Add ssl generation and storage

pull/1/head
Timothy Pearson 13 years ago
parent bf4dbda968
commit 75044dd48a

@ -14,3 +14,6 @@ ldapldifskel_DATA = openldap/ldif/*
saslskeldir = $(confskeldir)/sasl
saslskel_DATA = sasl/*
sslskeldir = $(confskeldir)/openssl
sslskel_DATA = openssl/*

@ -1,8 +1,8 @@
[kdc]
logging = FILE:/var/log/heimdal-kdc.log
enable-pkinit = yes
pkinit_identity = FILE:/etc/trinity/ldap/tde-ca/public/@@@KDCSERVER@@@.pki.crt,/etc/trinity/ldap/tde-ca/private/@@@KDCSERVER@@@.pki.key
pkinit_anchors = FILE:/etc/trinity/ldap/tde-ca/anchors/tdeca.pem
pkinit_identity = FILE:@@@KRBKDCPEMFILE@@@,@@@KRBKDCPEMKEYFILE@@@
pkinit_anchors = FILE:@@@KRBPKIPEMFILE@@@
pkinit_allow-proxy-certificate = false
acl_file = /etc/heimdal-kdc/kadmind.acl

@ -3,7 +3,7 @@
default_realm = @@@REALM_UCNAME@@@
[appdefaults]
pkinit_anchors = FILE:/etc/trinity/ldap/tde-ca/anchors/tdeca.pem
pkinit_anchors = FILE:@@@KRBPKIPEMFILE@@@
[realms]
@@@REALM_UCNAME@@@ = {

@ -72,8 +72,8 @@ index gidNumber eq
lastmod on
unique_attributes mail uid uidNumber
TLSCertificateFile /etc/trinity/ldap/tde-ca/public/@@@ADMINSERVER@@@.crt
TLSCertificateKeyFile /etc/trinity/ldap/tde-ca/private/@@@ADMINSERVER@@@.key
TLSCertificateFile @@@LDAPPEMFILE@@@
TLSCertificateKeyFile @@@LDAPPEMKEYFILE@@@
sasl-realm @@@REALM_UCNAME@@@
sasl-host @@@ADMINSERVER@@@

@ -28,8 +28,8 @@ olcSaslSecProps: noplain,noanonymous
olcSockbufMaxIncoming: 262143
olcSockbufMaxIncomingAuth: 16777215
olcThreads: 16
#olcTLSCertificateFile: /etc/trinity/ldap/tde-ca/public/@@@ADMINSERVER@@@.crt
#olcTLSCertificateKeyFile: /etc/trinity/ldap/tde-ca/private/@@@ADMINSERVER@@@.key
olcTLSCertificateFile: @@@LDAPPEMFILE@@@
olcTLSCertificateKeyFile: @@@LDAPPEMKEYFILE@@@
olcTLSVerifyClient: never
olcToolThreads: 1
olcWriteTimeout: 0

@ -15,6 +15,9 @@ olcAttributeTypes: {9} ( 1.3.6.1.4.1.99999.1.1.10 NAME 'badPwdCount' DESC 'Bad p
olcAttributeTypes: {10} ( 1.3.6.1.4.1.99999.1.1.11 NAME 'badPasswordTime' DESC 'Time of the last bad password attempt' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
olcAttributeTypes: {11} ( 1.3.6.1.4.1.99999.1.1.12 NAME 'lastLogon' DESC 'Timestamp of last logon' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
olcAttributeTypes: {12} ( 1.3.6.1.4.1.99999.1.1.13 NAME 'lastLogoff' DESC 'Timestamp of last logoff' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
# Used for storing sharable certificates and keys
olcAttributeTypes: {13} ( 1.3.6.1.4.1.99999.1.1.14 NAME 'publicRootCertificate' DESC 'Certificate authority root certificate' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 SINGLE-VALUE )
olcObjectClasses: {0} ( 1.3.6.1.4.1.99999.1.2.1 NAME 'tdeExtendedUserData' SUP top AUXILIARY MAY ( website
URL $ managerName $ secretaryName $ teletexId $ preferredDelivery $ locallyUniqueID $ notes $ pwdLastSet $ badPwdCount $ badPasswordTime $ lastLogon $ lastLogoff ) )
olcObjectClasses: {1} ( 1.3.6.1.4.1.99999.1.2.2 NAME 'tdeAccountObject' SUP top AUXILIARY MAY tdeBuiltinAccount )
olcObjectClasses: {2} ( 1.3.6.1.4.1.99999.1.2.3 NAME 'tdeCertificateStore' SUP top AUXILIARY MAY ( tdeBuiltinAccount $ publicRootCertificate ) )

@ -88,6 +88,16 @@ entryCSN: @@@TIMESTAMP@@@.000000Z#000000#000#000000
modifiersName: cn=@@@ROOTUSER@@@,@@@REALM_DCNAME@@@
modifyTimestamp: @@@TIMESTAMP@@@Z
dn: cn=tde realm data,ou=master services,ou=core,ou=realm,@@@REALM_DCNAME@@@
objectClass: namedObject
cn: TDE Realm Data
structuralObjectClass: namedObject
creatorsName: cn=@@@ROOTUSER@@@,@@@REALM_DCNAME@@@
createTimestamp: @@@TIMESTAMP@@@Z
entryCSN: @@@TIMESTAMP@@@.000000Z#000000#000#000000
modifiersName: cn=@@@ROOTUSER@@@,@@@REALM_DCNAME@@@
modifyTimestamp: @@@TIMESTAMP@@@Z
dn: o=kerberos,cn=kerberos control,ou=master services,ou=core,ou=realm,@@@REALM_DCNAME@@@
cn: kerberos
emsdescription: Kerberos Registry
@ -104,6 +114,22 @@ entryCSN: @@@TIMESTAMP@@@.000000Z#000000#000#000000
modifiersName: cn=@@@ROOTUSER@@@,@@@REALM_DCNAME@@@
modifyTimestamp: @@@TIMESTAMP@@@Z
dn: o=tde,cn=tde realm data,ou=master services,ou=core,ou=realm,@@@REALM_DCNAME@@@
cn: tde
emsdescription: TDE Realm Data
emsmodelclass: EMSSecurityObject
emstype: ServicePlugin
o: tde
objectClass: organization
objectClass: emsSecurityObject
objectClass: emsIgnore
structuralObjectClass: organization
creatorsName: cn=@@@ROOTUSER@@@,@@@REALM_DCNAME@@@
createTimestamp: @@@TIMESTAMP@@@Z
entryCSN: @@@TIMESTAMP@@@.000000Z#000000#000#000000
modifiersName: cn=@@@ROOTUSER@@@,@@@REALM_DCNAME@@@
modifyTimestamp: @@@TIMESTAMP@@@Z
dn: ou=groups,ou=core,ou=realm,@@@REALM_DCNAME@@@
emscontainertype: EGroupContainer
emsdescription: EMS Group Container
@ -227,3 +253,16 @@ krb5EncryptionType: 23
entryCSN: @@@TIMESTAMP@@@.000000Z#000000#000#000000
modifiersName: cn=@@@ROOTUSER@@@,@@@REALM_DCNAME@@@
modifyTimestamp: @@@TIMESTAMP@@@Z
dn: cn=certificate store,o=tde,cn=tde realm data,ou=master services,ou=core,ou=realm,@@@REALM_DCNAME@@@
cn: certificate store
description: TDE Certificate Store
objectClass: tdeCertificateStore
objectClass: applicationProcess
tdeBuiltinAccount: TRUE
structuralObjectClass: applicationProcess
creatorsName: cn=@@@ROOTUSER@@@,@@@REALM_DCNAME@@@
createTimestamp: @@@TIMESTAMP@@@Z
entryCSN: @@@TIMESTAMP@@@.000000Z#000000#000#000000
modifiersName: cn=@@@ROOTUSER@@@,@@@REALM_DCNAME@@@
modifyTimestamp: @@@TIMESTAMP@@@Z

@ -0,0 +1,61 @@
[ kdc_cert ]
basicConstraints=CA:FALSE
# Here are some examples of the usage of nsCertType. If it is omitted
keyUsage = nonRepudiation, digitalSignature, keyEncipherment, keyAgreement
#Pkinit EKU
extendedKeyUsage = 1.3.6.1.5.2.3.5
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
# Copy subject details
issuerAltName=issuer:copy
# Add id-pkinit-san (pkinit subjectAlternativeName)
subjectAltName=otherName:1.3.6.1.5.2.2;SEQUENCE:kdc_princ_name
[kdc_princ_name]
realm = EXP:0, GeneralString:@@@REALM_UCNAME@@@
principal_name = EXP:1, SEQUENCE:kdc_principal_seq
[kdc_principal_seq]
name_type = EXP:0, INTEGER:1
name_string = EXP:1, SEQUENCE:kdc_principals
[kdc_principals]
princ1 = GeneralString:krbtgt
princ2 = GeneralString:@@@REALM_UCNAME@@@
[ client_cert ]
# These extensions are added when 'ca' signs a request.
basicConstraints=CA:FALSE
keyUsage = digitalSignature, keyEncipherment, keyAgreement
extendedKeyUsage = 1.3.6.1.5.2.3.4
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
subjectAltName=otherName:1.3.6.1.5.2.2;SEQUENCE:princ_name
# Copy subject details
issuerAltName=issuer:copy
[princ_name]
realm = EXP:0, GeneralString:@@@REALM_UCNAME@@@
principal_name = EXP:1, SEQUENCE:principal_seq
[principal_seq]
name_type = EXP:0, INTEGER:1
name_string = EXP:1, SEQUENCE:principals
[principals]
princ1 = GeneralString:@@@KDCSERVER@@@

@ -48,11 +48,20 @@ CertConfigPage::CertConfigPage(TQWidget *parent, const char *name ) : CertConfig
connect(generateKeysDisabled, TQT_SIGNAL(stateChanged(int)), this, TQT_SLOT(setUseProvidedKeys(int)));
connect(kerberosPEM, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(validateEntries()));
connect(kerberosPEMKEY, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(validateEntries()));
connect(kerberosCRT, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(validateEntries()));
connect(kerberosKEY, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(validateEntries()));
connect(ldapCRT, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(validateEntries()));
connect(ldapKEY, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(validateEntries()));
connect(organizationName, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(validateEntries()));
connect(orgUnitName, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(validateEntries()));
connect(commonName, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(validateEntries()));
connect(localityName, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(validateEntries()));
connect(stateOrProvinceName, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(validateEntries()));
connect(countryName, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(validateEntries()));
connect(emailAddress, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(validateEntries()));
m_parentWizard = dynamic_cast<KWizard*>(parent);
m_parentDialog = dynamic_cast<KDialogBase*>(parent);
}
@ -81,19 +90,33 @@ void CertConfigPage::setUseProvidedKeys(int state) {
void CertConfigPage::processLockouts() {
kerberosPEM->setEnabled(generateKeysDisabled->isOn());
kerberosPEMKEY->setEnabled(generateKeysDisabled->isOn());
kerberosCRT->setEnabled(generateKeysDisabled->isOn());
kerberosKEY->setEnabled(generateKeysDisabled->isOn());
ldapCRT->setEnabled(generateKeysDisabled->isOn());
ldapKEY->setEnabled(generateKeysDisabled->isOn());
organizationName->setEnabled(generateKeysEnabled->isOn());
orgUnitName->setEnabled(generateKeysEnabled->isOn());
commonName->setEnabled(generateKeysEnabled->isOn());
localityName->setEnabled(generateKeysEnabled->isOn());
stateOrProvinceName->setEnabled(generateKeysEnabled->isOn());
countryName->setEnabled(generateKeysEnabled->isOn());
emailAddress->setEnabled(generateKeysEnabled->isOn());
}
void CertConfigPage::validateEntries() {
if (m_parentWizard) {
if (generateKeysEnabled->isOn()) {
m_parentWizard->nextButton()->setEnabled(true);
if ((organizationName->text() != "") && (orgUnitName->text() != "") && (commonName->text() != "") && (localityName->text() != "") && (stateOrProvinceName->text() != "") && (countryName->text() != "") && (emailAddress->text() != "")) {
m_parentWizard->nextButton()->setEnabled(true);
}
else {
m_parentWizard->nextButton()->setEnabled(false);
}
}
else {
if ((kerberosPEM->url() != "") && (kerberosCRT->url() != "") && (kerberosKEY->url() != "") && (ldapCRT->url() != "") && (ldapKEY->url() != "")) {
if ((kerberosPEM->url() != "") && (kerberosPEMKEY->url() != "") && (kerberosCRT->url() != "") && (kerberosKEY->url() != "") && (ldapCRT->url() != "") && (ldapKEY->url() != "")) {
m_parentWizard->nextButton()->setEnabled(true);
}
else {
@ -103,10 +126,15 @@ void CertConfigPage::validateEntries() {
}
if (m_parentDialog) {
if (generateKeysEnabled->isOn()) {
m_parentDialog->enableButton(KDialogBase::Ok, true);
if ((organizationName->text() != "") && (orgUnitName->text() != "") && (commonName->text() != "") && (localityName->text() != "") && (stateOrProvinceName->text() != "") && (countryName->text() != "") && (emailAddress->text() != "")) {
m_parentDialog->enableButton(KDialogBase::Ok, true);
}
else {
m_parentDialog->enableButton(KDialogBase::Ok, false);
}
}
else {
if ((kerberosPEM->url() != "") && (kerberosCRT->url() != "") && (kerberosKEY->url() != "") && (ldapCRT->url() != "") && (ldapKEY->url() != "")) {
if ((kerberosPEM->url() != "") && (kerberosPEMKEY->url() != "") && (kerberosCRT->url() != "") && (kerberosKEY->url() != "") && (ldapCRT->url() != "") && (ldapKEY->url() != "")) {
m_parentDialog->enableButton(KDialogBase::Ok, true);
}
else {

@ -66,7 +66,101 @@
<string>Generate New Certificates and Keys</string>
</property>
</widget>
<widget class="TQRadioButton" row="1" column="0">
<widget class="TQLabel" row="1" column="0">
<property name="name">
<cstring>unnamed</cstring>
</property>
<property name="text">
<string>Organization</string>
</property>
</widget>
<widget class="TQLineEdit" row="1" column="1" colspan="3">
<property name="name">
<cstring>organizationName</cstring>
</property>
</widget>
<widget class="TQLabel" row="2" column="0">
<property name="name">
<cstring>unnamed</cstring>
</property>
<property name="text">
<string>Division/Unit</string>
</property>
</widget>
<widget class="TQLineEdit" row="2" column="1" colspan="3">
<property name="name">
<cstring>orgUnitName</cstring>
</property>
</widget>
<widget class="TQLabel" row="3" column="0">
<property name="name">
<cstring>unnamed</cstring>
</property>
<property name="text">
<string>Certificate Owner</string>
</property>
</widget>
<widget class="TQLineEdit" row="3" column="1" colspan="3">
<property name="name">
<cstring>commonName</cstring>
</property>
</widget>
<widget class="TQLabel" row="4" column="0">
<property name="name">
<cstring>unnamed</cstring>
</property>
<property name="text">
<string>City/Locality</string>
</property>
</widget>
<widget class="TQLineEdit" row="4" column="1" colspan="3">
<property name="name">
<cstring>localityName</cstring>
</property>
</widget>
<widget class="TQLabel" row="5" column="0">
<property name="name">
<cstring>unnamed</cstring>
</property>
<property name="text">
<string>State/Province</string>
</property>
</widget>
<widget class="TQLineEdit" row="5" column="1" colspan="1">
<property name="name">
<cstring>stateOrProvinceName</cstring>
</property>
</widget>
<widget class="TQLabel" row="5" column="2">
<property name="name">
<cstring>unnamed</cstring>
</property>
<property name="text">
<string>Country</string>
</property>
</widget>
<widget class="TQLineEdit" row="5" column="3" colspan="1">
<property name="name">
<cstring>countryName</cstring>
</property>
<property name="maxLength">
<number>2</number>
</property>
</widget>
<widget class="TQLabel" row="6" column="0">
<property name="name">
<cstring>unnamed</cstring>
</property>
<property name="text">
<string>Administrative Email</string>
</property>
</widget>
<widget class="TQLineEdit" row="6" column="1" colspan="3">
<property name="name">
<cstring>emailAddress</cstring>
</property>
</widget>
<widget class="TQRadioButton" row="10" column="0">
<property name="name">
<cstring>generateKeysDisabled</cstring>
</property>
@ -74,15 +168,15 @@
<string>Install Provided Certificates and Keys</string>
</property>
</widget>
<widget class="TQLabel" row="2" column="0">
<widget class="TQLabel" row="11" column="0">
<property name="name">
<cstring>unnamed</cstring>
</property>
<property name="text">
<string>Kerberos PKI Anchor</string>
<string>Kerberos PKI CA Public Certificate</string>
</property>
</widget>
<widget class="KURLRequester" row="2" column="1" colspan="1">
<widget class="KURLRequester" row="11" column="1" colspan="3">
<property name="name">
<cstring>kerberosPEM</cstring>
</property>
@ -93,7 +187,26 @@
<cstring>*.pem|PKI Anchor Files (*.pem)</cstring>
</property>
</widget>
<widget class="TQLabel" row="3" column="0">
<widget class="TQLabel" row="12" column="0">
<property name="name">
<cstring>unnamed</cstring>
</property>
<property name="text">
<string>Kerberos PKI CA Private Key</string>
</property>
</widget>
<widget class="KURLRequester" row="12" column="1" colspan="3">
<property name="name">
<cstring>kerberosPEMKEY</cstring>
</property>
<property name="mode">
<number>25</number>
</property>
<property name="filter">
<cstring>*.key|Private Key (*.key)</cstring>
</property>
</widget>
<widget class="TQLabel" row="13" column="0">
<property name="name">
<cstring>unnamed</cstring>
</property>
@ -101,7 +214,7 @@
<string>Kerberos Public Certificate</string>
</property>
</widget>
<widget class="KURLRequester" row="3" column="1" colspan="1">
<widget class="KURLRequester" row="13" column="1" colspan="3">
<property name="name">
<cstring>kerberosCRT</cstring>
</property>
@ -112,7 +225,7 @@
<cstring>*.crt|Public Certificate (*.crt)</cstring>
</property>
</widget>
<widget class="TQLabel" row="4" column="0">
<widget class="TQLabel" row="14" column="0">
<property name="name">
<cstring>unnamed</cstring>
</property>
@ -120,7 +233,7 @@
<string>Kerberos Private Key</string>
</property>
</widget>
<widget class="KURLRequester" row="4" column="1" colspan="1">
<widget class="KURLRequester" row="14" column="1" colspan="3">
<property name="name">
<cstring>kerberosKEY</cstring>
</property>
@ -131,7 +244,7 @@
<cstring>*.key|Private Key (*.key)</cstring>
</property>
</widget>
<widget class="TQLabel" row="5" column="0">
<widget class="TQLabel" row="15" column="0">
<property name="name">
<cstring>unnamed</cstring>
</property>
@ -139,7 +252,7 @@
<string>LDAP TLS Public Certificate</string>
</property>
</widget>
<widget class="KURLRequester" row="5" column="1" colspan="1">
<widget class="KURLRequester" row="15" column="1" colspan="3">
<property name="name">
<cstring>ldapCRT</cstring>
</property>
@ -150,7 +263,7 @@
<cstring>*.crt|Public Certificate (*.crt)</cstring>
</property>
</widget>
<widget class="TQLabel" row="6" column="0">
<widget class="TQLabel" row="16" column="0">
<property name="name">
<cstring>unnamed</cstring>
</property>
@ -158,7 +271,7 @@
<string>LDAP TLS Private Key</string>
</property>
</widget>
<widget class="KURLRequester" row="6" column="1" colspan="1">
<widget class="KURLRequester" row="16" column="1" colspan="3">
<property name="name">
<cstring>ldapKEY</cstring>
</property>

@ -63,13 +63,35 @@
// RedHat would be "/etc/sysconfig/ldap"
#define LDAP_DEFAULT_FILE "/etc/default/slapd"
#define HEIMDAL_DEFAULT_FILE "/etc/default/heimdal-kdc"
#define HEIMDAL_ACL_FILE "/etc/heimdal-kdc/kadmind.acl"
#define SASL_DEFAULT_FILE "/etc/default/saslauthd"
#define SASL_CONTROL_FILE "/etc/ldap/sasl2/slapd.conf"
#define HEIMDAL_ACL_FILE "/etc/heimdal-kdc/kadmind.acl"
#define TDE_CERTIFICATE_DIR "/etc/trinity/ldap/tde-ca/"
#define KERBEROS_PKI_ANCHORDIR "/etc/trinity/ldap/tde-ca/anchors/"
#define KERBEROS_PKI_PRIVATEDIR "/etc/trinity/ldap/tde-ca/private/"
#define KERBEROS_PKI_PUBLICDIR "/etc/trinity/ldap/tde-ca/public/"
#define KERBEROS_PKI_PEM_FILE KERBEROS_PKI_ANCHORDIR "tdeca.pem"
#define KERBEROS_PKI_PEMKEY_FILE KERBEROS_PKI_ANCHORDIR "tdeca.key.pem"
#define KERBEROS_PKI_KDC_FILE KERBEROS_PKI_PUBLICDIR "@@@KDCSERVER@@@.pki.crt"
#define KERBEROS_PKI_KDCKEY_FILE KERBEROS_PKI_PRIVATEDIR "@@@KDCSERVER@@@.pki.key"
#define KERBEROS_PKI_KDCREQ_FILE KERBEROS_PKI_PRIVATEDIR "@@@KDCSERVER@@@.pki.req"
#define LDAP_CERT_FILE KERBEROS_PKI_PUBLICDIR "@@@ADMINSERVER@@@.ldap.crt"
#define LDAP_CERTKEY_FILE KERBEROS_PKI_PRIVATEDIR "@@@ADMINSERVER@@@.ldap.key"
#define LDAP_CERTREQ_FILE KERBEROS_PKI_PRIVATEDIR "@@@ADMINSERVER@@@.ldap.req"
#define OPENSSL_EXTENSIONS_FILE TDE_CERTIFICATE_DIR "pki_extensions"
#define ROLE_WORKSTATION 0
#define ROLE_REALM_CONTROLLER 1
#define KEY_STRENGTH 2048
// RAJA FIXME
// Provide a way to change the LDAP root password
// in the olcDatabase (field olcRootPW) after installation!
typedef KGenericFactory<LDAPController, TQWidget> ldapFactory;
K_EXPORT_COMPONENT_FACTORY( kcm_ldapcontroller, ldapFactory("kcmldapcontroller"))
@ -145,7 +167,7 @@ void LDAPController::systemRoleChanged() {
// Something will probably change
save();
RealmWizard realmwizard(this, m_fqdn, this);
RealmWizard realmwizard(this, m_fqdn, m_certconfig, this);
if (realmwizard.exec() < 0) {
// Wizard was cancelled
// Back out all changes!
@ -191,6 +213,18 @@ void LDAPController::load() {
m_base->systemRole->setCurrentItem(ROLE_WORKSTATION);
}
m_prevRole = m_base->systemRole->currentItem();
// Load cert config
m_systemconfig->setGroup("Certificates");
m_certconfig.countryName = m_systemconfig->readEntry("countryName");
m_certconfig.stateOrProvinceName = m_systemconfig->readEntry("stateOrProvinceName");
m_certconfig.localityName = m_systemconfig->readEntry("localityName");
m_certconfig.organizationName = m_systemconfig->readEntry("organizationName");
m_certconfig.orgUnitName = m_systemconfig->readEntry("orgUnitName");
m_certconfig.commonName = m_systemconfig->readEntry("commonName");
m_certconfig.emailAddress = m_systemconfig->readEntry("emailAddress");
m_systemconfig->setGroup(NULL);
}
void LDAPController::defaults() {
@ -202,6 +236,18 @@ void LDAPController::save() {
m_systemconfig->writeEntry("EnableLDAP", m_base->systemEnableSupport->isChecked());
m_systemconfig->writeEntry("LDAPRole", m_base->systemRole->currentText());
// Write cert config
m_systemconfig->setGroup("Certificates");
m_systemconfig->writeEntry("countryName", m_certconfig.countryName);
m_systemconfig->writeEntry("stateOrProvinceName", m_certconfig.stateOrProvinceName);
m_systemconfig->writeEntry("localityName", m_certconfig.localityName);
m_systemconfig->writeEntry("organizationName", m_certconfig.organizationName);
m_systemconfig->writeEntry("orgUnitName", m_certconfig.orgUnitName);
m_systemconfig->writeEntry("commonName", m_certconfig.commonName);
m_systemconfig->writeEntry("emailAddress", m_certconfig.emailAddress);
m_systemconfig->setGroup(NULL);
m_systemconfig->sync();
if (m_base->systemEnableSupport->isChecked()) {
@ -228,8 +274,6 @@ void replacePlaceholdersInFile(TQString infile, TQString outfile, LDAPRealmConfi
sha.process(adminPassword, strlen(rootPassword));
TQString adminpw_hash = sha.base64Hash();
// RAJA FIXME
// Created needed strings
TQStringList domainChunks = TQStringList::split(".", realmconfig.name.lower());
TQString basedcname = "dc=" + domainChunks.join(",dc=");
@ -241,6 +285,15 @@ void replacePlaceholdersInFile(TQString infile, TQString outfile, LDAPRealmConfi
timestamp.replace(":", "");
timestamp.replace("T", "");
TQString kdc_certfile = KERBEROS_PKI_KDC_FILE;
TQString kdc_keyfile = KERBEROS_PKI_KDCKEY_FILE;
TQString ldap_certfile = LDAP_CERT_FILE;
TQString ldap_keyfile = LDAP_CERTKEY_FILE;
kdc_certfile.replace("@@@KDCSERVER@@@", realmconfig.kdc);
kdc_keyfile.replace("@@@KDCSERVER@@@", realmconfig.kdc);
ldap_certfile.replace("@@@ADMINSERVER@@@", realmconfig.admin_server);
ldap_keyfile.replace("@@@ADMINSERVER@@@", realmconfig.admin_server);
TQFile ifile(infile);
TQFile ofile(outfile);
if (ifile.open(IO_ReadOnly)) {
@ -275,6 +328,12 @@ void replacePlaceholdersInFile(TQString infile, TQString outfile, LDAPRealmConfi
line.replace("@@@LDAP_GROUP_NAME@@@", ldapgroupname);
line.replace("@@@TDELIBDIR@@@", TDE_LIBDIR);
line.replace("@@@HEIMDALACLFILE@@@", HEIMDAL_ACL_FILE);
line.replace("@@@KRBPKIPEMFILE@@@", KERBEROS_PKI_PEM_FILE);
line.replace("@@@KRBPKIPEMKEYFILE@@@", KERBEROS_PKI_PEMKEY_FILE);
line.replace("@@@KRBKDCPEMFILE@@@", kdc_certfile);
line.replace("@@@KRBKDCPEMKEYFILE@@@", kdc_keyfile);
line.replace("@@@LDAPPEMFILE@@@", ldap_certfile);
line.replace("@@@LDAPPEMKEYFILE@@@", ldap_keyfile);
if (ldifSchemaNumber >= 0) {
line.replace("@@@LDIFSCHEMANUMBER@@@", TQString("%1").arg(ldifSchemaNumber));
}
@ -683,7 +742,64 @@ int LDAPController::setKerberosPasswordForUser(LDAPCredentials user, TQString *e
return 1; // Failure
}
int LDAPController::createNewLDAPRealm(TQWidget* dialogparent, LDAPRealmConfig realmconfig, TQString adminUserName, TQString adminGroupName, TQString machineAdminGroupName, const char * adminPassword, TQString rootUserName, const char * rootPassword, TQString adminRealm, TQString *errstr) {
int LDAPController::createRealmCertificates(LDAPCertConfig certinfo, LDAPRealmConfig realmconfig, uid_t ldap_uid, gid_t ldap_gid) {
// Certificate authority certificate
TQString command;
command = TQString("openssl genrsa -out %1 %2").arg(KERBEROS_PKI_PEMKEY_FILE).arg(KEY_STRENGTH);
system(command);
chmod(KERBEROS_PKI_PEMKEY_FILE, S_IRUSR|S_IWUSR);
chown(KERBEROS_PKI_PEMKEY_FILE, 0, 0);
command = TQString("openssl req -key %1 -new -x509 -out %2 -subj \"/C=%3/ST=%4/L=%5/O=%6/OU=%7/CN=%8/emailAddress=%9\"").arg(KERBEROS_PKI_PEMKEY_FILE).arg(KERBEROS_PKI_PEM_FILE).arg(certinfo.countryName).arg(certinfo.stateOrProvinceName).arg(certinfo.localityName).arg(certinfo.organizationName).arg(certinfo.orgUnitName).arg(certinfo.commonName).arg(certinfo.emailAddress);
system(command);
chmod(KERBEROS_PKI_PEM_FILE, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
chown(KERBEROS_PKI_PEM_FILE, 0, 0);
// KDC certificate
TQString kdc_certfile = KERBEROS_PKI_KDC_FILE;
TQString kdc_keyfile = KERBEROS_PKI_KDCKEY_FILE;
TQString kdc_reqfile = KERBEROS_PKI_KDCREQ_FILE;
kdc_certfile.replace("@@@KDCSERVER@@@", realmconfig.kdc);
kdc_keyfile.replace("@@@KDCSERVER@@@", realmconfig.kdc);
kdc_reqfile.replace("@@@KDCSERVER@@@", realmconfig.kdc);
command = TQString("openssl genrsa -out %1 %2").arg(kdc_keyfile).arg(KEY_STRENGTH);
system(command);
chmod(kdc_keyfile.ascii(), S_IRUSR|S_IWUSR);
chown(kdc_keyfile.ascii(), 0, 0);
command = TQString("openssl req -new -out %1 -key %2 -subj \"/C=%3/ST=%4/L=%5/O=%6/OU=%7/CN=%8/emailAddress=%9\"").arg(kdc_reqfile).arg(kdc_keyfile).arg(certinfo.countryName).arg(certinfo.stateOrProvinceName).arg(certinfo.localityName).arg(certinfo.organizationName).arg(certinfo.orgUnitName).arg(certinfo.commonName).arg(certinfo.emailAddress);
system(command);
command = TQString("openssl x509 -req -in %1 -CAkey %2 -CA %3 -out %4 -extfile %5 -extensions kdc_cert -CAcreateserial").arg(kdc_reqfile).arg(KERBEROS_PKI_PEMKEY_FILE).arg(KERBEROS_PKI_PEM_FILE).arg(kdc_certfile).arg(OPENSSL_EXTENSIONS_FILE);
system(command);
chmod(kdc_certfile.ascii(), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
chown(kdc_certfile.ascii(), 0, 0);
unlink(kdc_reqfile.ascii());
unlink(OPENSSL_EXTENSIONS_FILE);
// LDAP certificate
TQString ldap_certfile = LDAP_CERT_FILE;
TQString ldap_keyfile = LDAP_CERTKEY_FILE;
TQString ldap_reqfile = LDAP_CERTREQ_FILE;
ldap_certfile.replace("@@@ADMINSERVER@@@", realmconfig.admin_server);
ldap_keyfile.replace("@@@ADMINSERVER@@@", realmconfig.admin_server);
ldap_reqfile.replace("@@@ADMINSERVER@@@", realmconfig.admin_server);
command = TQString("openssl genrsa -out %1 %2").arg(ldap_keyfile).arg(KEY_STRENGTH);
system(command);
chmod(ldap_keyfile.ascii(), S_IRUSR|S_IWUSR);
chown(ldap_keyfile.ascii(), ldap_uid, ldap_gid);
command = TQString("openssl req -new -out %1 -key %2 -subj \"/C=%3/ST=%4/L=%5/O=%6/OU=%7/CN=%8/emailAddress=%9\"").arg(ldap_reqfile).arg(ldap_keyfile).arg(certinfo.countryName).arg(certinfo.stateOrProvinceName).arg(certinfo.localityName).arg(certinfo.organizationName).arg(certinfo.orgUnitName).arg(realmconfig.admin_server).arg(certinfo.emailAddress);
system(command);
command = TQString("openssl x509 -req -in %1 -CAkey %2 -CA %3 -out %4 -CAcreateserial").arg(ldap_reqfile).arg(KERBEROS_PKI_PEMKEY_FILE).arg(KERBEROS_PKI_PEM_FILE).arg(ldap_certfile);
system(command);
chmod(ldap_certfile.ascii(), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
chown(ldap_certfile.ascii(), ldap_uid, ldap_gid);
unlink(ldap_reqfile.ascii());
return 0;
}
int LDAPController::createNewLDAPRealm(TQWidget* dialogparent, LDAPRealmConfig realmconfig, TQString adminUserName, TQString adminGroupName, TQString machineAdminGroupName, const char * adminPassword, TQString rootUserName, const char * rootPassword, TQString adminRealm, LDAPCertConfig certinfo, TQString *errstr) {
int ldifSchemaNumber;
ProcessingDialog pdialog(dialogparent);
@ -747,19 +863,17 @@ configTempDir.setAutoDelete(false); // RAJA DEBUG ONLY FIXME
mkdir(TQString(destDir + "ldap/slapd.d/cn=config").ascii(), S_IRUSR|S_IWUSR|S_IXUSR);
mkdir(TQString(destDir + "ldap/slapd.d/cn=config/cn=schema").ascii(), S_IRUSR|S_IWUSR|S_IXUSR);
mkdir(TDE_CERTIFICATE_DIR, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
mkdir(KERBEROS_PKI_ANCHORDIR, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
mkdir(KERBEROS_PKI_PRIVATEDIR, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
mkdir(KERBEROS_PKI_PUBLICDIR, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
// Heimdal
replacePlaceholdersInFile(templateDir + "heimdal/heimdal.defaults", HEIMDAL_DEFAULT_FILE, realmconfig, adminUserName, adminGroupName, machineAdminGroupName, adminPassword, rootUserName, rootPassword);
replacePlaceholdersInFile(templateDir + "heimdal/kadmind.acl", HEIMDAL_ACL_FILE, realmconfig, adminUserName, adminGroupName, machineAdminGroupName, adminPassword, rootUserName, rootPassword);
replacePlaceholdersInFile(templateDir + "heimdal/kdc.conf", destDir + "heimdal-kdc/kdc.conf", realmconfig, adminUserName, adminGroupName, machineAdminGroupName, adminPassword, rootUserName, rootPassword);
replacePlaceholdersInFile(templateDir + "heimdal/krb5.conf", destDir + "krb5.conf", realmconfig, adminUserName, adminGroupName, machineAdminGroupName, adminPassword, rootUserName, rootPassword);
// RAJA DEBUG
// if (system("kstash --random-key") != 0) {
// if (errstr) *errstr = i18n("Unable to create Kerberos foundational key");
// pdialog.closeDialog();
// return -1;
// }
// OpenLDAP
replacePlaceholdersInFile(templateDir + "openldap/skel.ldif", configTempDir.name() + "skel.ldif", realmconfig, adminUserName, adminGroupName, machineAdminGroupName, adminPassword, rootUserName, rootPassword);
// replacePlaceholdersInFile(templateDir + "openldap/ldap/slapd.conf", destDir + "ldap/slapd.conf", realmconfig, adminUserName, adminGroupName, machineAdminGroupName, adminPassword, rootUserName, rootPassword);
@ -769,6 +883,9 @@ configTempDir.setAutoDelete(false); // RAJA DEBUG ONLY FIXME
replacePlaceholdersInFile(templateDir + "sasl/saslauthd.defaults", SASL_DEFAULT_FILE, realmconfig, adminUserName, adminGroupName, machineAdminGroupName, adminPassword, rootUserName, rootPassword);
replacePlaceholdersInFile(templateDir + "sasl/slapd.conf", SASL_CONTROL_FILE, realmconfig, adminUserName, adminGroupName, machineAdminGroupName, adminPassword, rootUserName, rootPassword);
// OpenSSL
replacePlaceholdersInFile(templateDir + "openssl/pki_extensions", OPENSSL_EXTENSIONS_FILE, realmconfig, adminUserName, adminGroupName, machineAdminGroupName, adminPassword, rootUserName, rootPassword);
// FIXME
// This assumes Debian!
// Grant LDAP access to SASL mux pipe
@ -839,7 +956,62 @@ configTempDir.setAutoDelete(false); // RAJA DEBUG ONLY FIXME
chmod(TQString(LDAP_DEFAULT_FILE).ascii(), S_IRUSR|S_IWUSR|S_IRGRP);
chmod(TQString(SASL_DEFAULT_FILE).ascii(), S_IRUSR|S_IWUSR|S_IRGRP);
chmod(TQString(SASL_CONTROL_FILE).ascii(), S_IRUSR|S_IWUSR|S_IRGRP);
chmod(TQString(SASL_CONTROL_FILE).ascii(), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
pdialog.setStatusMessage(i18n("Installing realm certificates..."));
tqApp->processEvents();
if (certinfo.generate_certs) {
// Generate certificates
if (createRealmCertificates(certinfo, realmconfig, slapd_uid, slapd_gid) != 0) {
if (errstr) *errstr = i18n("Unable to install realm certificates");
pdialog.closeDialog();
return -1;
}
m_certconfig = certinfo;
}
else {
// Copy certificates
TQString kdc_certfile = KERBEROS_PKI_KDC_FILE;
TQString kdc_keyfile = KERBEROS_PKI_KDCKEY_FILE;
kdc_certfile.replace("@@@KDCSERVER@@@", realmconfig.kdc);
kdc_keyfile.replace("@@@KDCSERVER@@@", realmconfig.kdc);
TQString ldap_certfile = LDAP_CERT_FILE;
TQString ldap_keyfile = LDAP_CERTKEY_FILE;
ldap_certfile.replace("@@@ADMINSERVER@@@", realmconfig.admin_server);
ldap_keyfile.replace("@@@ADMINSERVER@@@", realmconfig.admin_server);
// Copy files
// FIXME
// There has GOT to be a better way to do this than system()!!!
TQString command;
command = TQString("cp %1 %2").arg(certinfo.provided_kerberos_pem).arg(KERBEROS_PKI_PEMKEY_FILE);
system(command);
command = TQString("cp %1 %2").arg(certinfo.provided_kerberos_pemkey).arg(KERBEROS_PKI_PEM_FILE);
system(command);
command = TQString("cp %1 %2").arg(certinfo.provided_kerberos_crt).arg(kdc_certfile);
system(command);
command = TQString("cp %1 %2").arg(certinfo.provided_kerberos_key).arg(kdc_keyfile);
system(command);
command = TQString("cp %1 %2").arg(certinfo.provided_ldap_crt).arg(ldap_certfile);
system(command);
command = TQString("cp %1 %2").arg(certinfo.provided_ldap_key).arg(ldap_keyfile);
system(command);
// Set permissions
chmod(KERBEROS_PKI_PEMKEY_FILE, S_IRUSR|S_IWUSR);
chown(KERBEROS_PKI_PEMKEY_FILE, 0, 0);
chmod(KERBEROS_PKI_PEM_FILE, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
chown(KERBEROS_PKI_PEM_FILE, 0, 0);
chmod(kdc_keyfile.ascii(), S_IRUSR|S_IWUSR);
chown(kdc_keyfile.ascii(), 0, 0);
chmod(kdc_certfile.ascii(), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
chown(kdc_certfile.ascii(), 0, 0);
chmod(ldap_keyfile.ascii(), S_IRUSR|S_IWUSR);
chown(ldap_keyfile.ascii(), slapd_uid, slapd_gid);
chmod(ldap_certfile.ascii(), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
chown(ldap_certfile.ascii(), slapd_uid, slapd_gid);
}
pdialog.setStatusMessage(i18n("Loading initial database into LDAP..."));
tqApp->processEvents();
@ -920,6 +1092,20 @@ configTempDir.setAutoDelete(false); // RAJA DEBUG ONLY FIXME
pdialog.closeDialog();
return -1;
}
// Upload the contents of KERBEROS_PKI_PEM_FILE to the LDAP server
TQFile cafile(KERBEROS_PKI_PEM_FILE);
if (cafile.open(IO_ReadOnly)) {
TQByteArray cafiledata = cafile.readAll();
if (ldap_mgr->writeCertificateFileIntoDirectory(cafiledata, "publicRootCertificate", &errorstring) != 0) {
delete ldap_mgr;
delete credentials;
if (errstr) *errstr = errorstring;
pdialog.closeDialog();
return -1;
}
}
delete ldap_mgr;
delete credentials;

@ -42,6 +42,27 @@ enum sc_command {
SC_SETDBPERMS
};
// PRIVATE
class LDAPCertConfig
{
public:
bool generate_certs;
TQString provided_kerberos_pem;
TQString provided_kerberos_pemkey;
TQString provided_kerberos_crt;
TQString provided_kerberos_key;
TQString provided_ldap_crt;
TQString provided_ldap_key;
TQString countryName;
TQString stateOrProvinceName;
TQString localityName;
TQString organizationName;
TQString orgUnitName;
TQString commonName;
TQString emailAddress;
};
class LDAPController: public KCModule
{
Q_OBJECT
@ -58,7 +79,7 @@ class LDAPController: public KCModule
virtual const KAboutData *aboutData() const { return myAboutData; };
public:
int createNewLDAPRealm(TQWidget* dialogparent, LDAPRealmConfig realmconfig, TQString adminUserName, TQString adminGroupName, TQString machineAdminGroupName, const char * adminPassword, TQString rootUserName, const char * rootPassword, TQString adminRealm, TQString *errstr);
int createNewLDAPRealm(TQWidget* dialogparent, LDAPRealmConfig realmconfig, TQString adminUserName, TQString adminGroupName, TQString machineAdminGroupName, const char * adminPassword, TQString rootUserName, const char * rootPassword, TQString adminRealm, LDAPCertConfig certinfo, TQString *errstr);
private slots:
void systemRoleChanged();
@ -73,6 +94,7 @@ class LDAPController: public KCModule
int addLDAPEntryToKerberosRealm(TQString ldapProcessOwnerName, TQString ldapHost, TQString *errstr);
int addHostEntryToKerberosRealm(TQString kerberosHost, TQString *errstr);
int setKerberosPasswordForUser(LDAPCredentials user, TQString *errstr);
int createRealmCertificates(LDAPCertConfig certinfo, LDAPRealmConfig realmconfig, uid_t ldap_uid, gid_t ldap_gid);
private:
KAboutData *myAboutData;
@ -84,6 +106,8 @@ class LDAPController: public KCModule
int m_prevRole;
TQString m_ldapUserName;
TQString m_ldapGroupName;
LDAPCertConfig m_certconfig;
};
#endif // _LDAPCONTROLLER_H_

@ -45,6 +45,7 @@
#include <klineedit.h>
#include <ktextedit.h>
#include <kpassdlg.h>
#include <kurlrequester.h>
#include <stdlib.h>
@ -58,8 +59,8 @@
#include "realmwizard.h"
#include "realmwizard.moc"
RealmWizard::RealmWizard(LDAPController* controller, TQString fqdn, TQWidget *parent, const char *name)
: KWizard(parent, name, true), m_controller(controller), m_fqdn(fqdn) {
RealmWizard::RealmWizard(LDAPController* controller, TQString fqdn, LDAPCertConfig certinfo, TQWidget *parent, const char *name)
: KWizard(parent, name, true), m_controller(controller), m_fqdn(fqdn), m_certconfig(certinfo) {
setCaption(i18n("LDAP Realm Wizard"));
@ -98,6 +99,15 @@ RealmWizard::RealmWizard(LDAPController* controller, TQString fqdn, TQWidget *pa
finishpage->ldapAdminGroupname->setText("realmadmins");
finishpage->ldapMachineAdminGroupname->setText("machineadmins");
// Load certificate info
certpage->organizationName->setText(m_certconfig.organizationName);
certpage->orgUnitName->setText(m_certconfig.orgUnitName);
certpage->commonName->setText(m_certconfig.commonName);
certpage->localityName->setText(m_certconfig.localityName);
certpage->stateOrProvinceName->setText(m_certconfig.stateOrProvinceName);
certpage->countryName->setText(m_certconfig.countryName);
certpage->emailAddress->setText(m_certconfig.emailAddress);
// Other setup
finishpage->ldapAdminRealm->setEnabled(false);
@ -140,8 +150,21 @@ void RealmWizard::next() {
certpage->validateEntries();
}
else if (currentPage()==certpage) {
// RAJA FIXME
// What to do with the certificate information?
// Save certificate information
m_certconfig.generate_certs = certpage->generateKeysEnabled->isOn();
m_certconfig.provided_kerberos_pem = certpage->kerberosPEM->url();
m_certconfig.provided_kerberos_pemkey = certpage->kerberosPEMKEY->url();
m_certconfig.provided_kerberos_crt = certpage->kerberosCRT->url();
m_certconfig.provided_kerberos_key = certpage->kerberosKEY->url();
m_certconfig.provided_ldap_crt = certpage->ldapCRT->url();
m_certconfig.provided_ldap_key = certpage->ldapKEY->url();
m_certconfig.organizationName = certpage->organizationName->text();
m_certconfig.orgUnitName = certpage->orgUnitName->text();
m_certconfig.commonName = certpage->commonName->text();
m_certconfig.localityName = certpage->localityName->text();
m_certconfig.stateOrProvinceName = certpage->stateOrProvinceName->text();
m_certconfig.countryName = certpage->countryName->text();
m_certconfig.emailAddress = certpage->emailAddress->text();
TQWizard::next();
finishpage->validateEntries();
@ -221,7 +244,7 @@ void RealmWizard::accept() {
nextButton()->setEnabled(false);
finishButton()->setEnabled(false);
cancelButton()->setEnabled(false);
if (m_controller->createNewLDAPRealm(this, m_realmconfig, finishpage->ldapAdminUsername->text(), finishpage->ldapAdminGroupname->text(), finishpage->ldapMachineAdminGroupname->text(), finishpage->ldapAdminPassword->password(), "admin", finishpage->ldapAdminPassword->password(), finishpage->ldapAdminRealm->text(), &errorString) == 0) {
if (m_controller->createNewLDAPRealm(this, m_realmconfig, finishpage->ldapAdminUsername->text(), finishpage->ldapAdminGroupname->text(), finishpage->ldapMachineAdminGroupname->text(), finishpage->ldapAdminPassword->password(), "admin", finishpage->ldapAdminPassword->password(), finishpage->ldapAdminRealm->text(), m_certconfig, &errorString) == 0) {
done(0);
}
else {

@ -42,7 +42,7 @@ class RealmWizard : public KWizard {
Q_OBJECT
public:
/** construtor */
RealmWizard(LDAPController* controller, TQString fqdn, TQWidget* parent=0, const char *name=0);
RealmWizard(LDAPController* controller, TQString fqdn, LDAPCertConfig certinfo, TQWidget* parent=0, const char *name=0);
/** destructor */
~RealmWizard();
@ -76,6 +76,7 @@ private:
LDAPController* m_controller;
LDAPRealmConfig m_realmconfig;
TQString m_fqdn;
LDAPCertConfig m_certconfig;
protected: // Protected methods
// the close button on the titlebar sets e->accept() which we don't want.

Loading…
Cancel
Save