|
|
|
/***************************************************************************
|
|
|
|
* Copyright (C) 2012 - 2015 by Timothy Pearson *
|
|
|
|
* kb9vqf@pearsoncomputing.net *
|
|
|
|
* *
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU General Public License as published by *
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
|
|
* (at your option) any later version. *
|
|
|
|
* *
|
|
|
|
* This program is distributed in the hope that it will be useful, *
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
|
|
* GNU General Public License for more details. *
|
|
|
|
* *
|
|
|
|
* You should have received a copy of the GNU General Public License *
|
|
|
|
* along with this program; if not, write to the *
|
|
|
|
* Free Software Foundation, Inc., *
|
|
|
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <netdb.h>
|
|
|
|
#include <pwd.h>
|
|
|
|
|
|
|
|
#include <tdeapplication.h>
|
|
|
|
#include <tdestartupinfo.h>
|
|
|
|
#include <tdecmdlineargs.h>
|
|
|
|
#include <tdeaboutdata.h>
|
|
|
|
|
|
|
|
#include <ksimpleconfig.h>
|
|
|
|
|
|
|
|
#include <tqdatetime.h>
|
|
|
|
#include <tqfile.h>
|
|
|
|
|
|
|
|
#include <libtdeldap.h>
|
|
|
|
|
|
|
|
// FIXME
|
|
|
|
// Connect this to CMake/Automake
|
|
|
|
#define KDE_CONFDIR "/etc/trinity"
|
|
|
|
|
|
|
|
static const char description[] =
|
|
|
|
I18N_NOOP("TDE utility for updating realm certificates");
|
|
|
|
|
|
|
|
static const char version[] = "v0.0.1";
|
|
|
|
|
|
|
|
static const TDECmdLineOptions options[] =
|
|
|
|
{
|
|
|
|
{ "force", I18N_NOOP("Force certificate update"), 0 },
|
|
|
|
TDECmdLineLastOption // End of options.
|
|
|
|
};
|
|
|
|
|
|
|
|
void chown_safe(const char * file, uid_t user, gid_t group) {
|
|
|
|
if (chown(file, user, group) < 0) {
|
|
|
|
printf("[ERROR] Chown call to '%s' for %d:%d failed!\n\r", file, user, group);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int uploadKerberosCAFileToLDAP(LDAPManager* ldap_mgr, TQString* errstr) {
|
|
|
|
// 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", errstr) != 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
TDEAboutData aboutData( "primaryrccertupdater", I18N_NOOP("Realm Certificate Updater"),
|
|
|
|
version, description, TDEAboutData::License_GPL,
|
|
|
|
"(c) 2012-2015, Timothy Pearson");
|
|
|
|
aboutData.addAuthor("Timothy Pearson",0, "kb9vqf@pearsoncomputing.net");
|
|
|
|
TDECmdLineArgs::init( argc, argv, &aboutData );
|
|
|
|
TDECmdLineArgs::addCmdLineOptions(options);
|
|
|
|
TDEApplication::disableAutoDcopRegistration();
|
|
|
|
|
|
|
|
TDEApplication app(false, false);
|
|
|
|
|
|
|
|
TDEStartupInfo::appStarted();
|
|
|
|
|
|
|
|
TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs();
|
|
|
|
|
|
|
|
bool force_update = false;
|
|
|
|
if (args->isSet("force")) {
|
|
|
|
force_update = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ca_modified = false;
|
|
|
|
|
|
|
|
//======================================================================================================================================================
|
|
|
|
//
|
|
|
|
// Updater code follows
|
|
|
|
//
|
|
|
|
//======================================================================================================================================================
|
|
|
|
|
|
|
|
// FIXME
|
|
|
|
// This assumes Debian!
|
|
|
|
TQString m_ldapUserName = "openldap";
|
|
|
|
TQString m_ldapGroupName = "openldap";
|
|
|
|
|
|
|
|
KSimpleConfig* m_systemconfig = new KSimpleConfig( TQString::fromLatin1( KDE_CONFDIR "/ldap/ldapconfigrc" ));
|
|
|
|
LDAPRealmConfigList m_realmconfig = LDAPManager::readTDERealmList(m_systemconfig, false);
|
|
|
|
// Load cert config
|
|
|
|
m_systemconfig->setGroup("Certificates");
|
|
|
|
LDAPCertConfig m_certconfig;
|
|
|
|
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");
|
|
|
|
// Load other defaults
|
|
|
|
m_systemconfig->setGroup(NULL);
|
|
|
|
TQString m_defaultRealm = m_systemconfig->readEntry("DefaultRealm");
|
|
|
|
|
|
|
|
TQDateTime certExpiry;
|
|
|
|
TQDateTime now = TQDateTime::currentDateTime();
|
|
|
|
TQDateTime soon = now.addDays(7); // Keep in sync with src/ldapcontroller.cpp
|
|
|
|
|
|
|
|
TQString kdc_certfile = KERBEROS_PKI_KDC_FILE;
|
|
|
|
kdc_certfile.replace("@@@KDCSERVER@@@", m_realmconfig[m_defaultRealm].name.lower());
|
|
|
|
TQString ldap_certfile = LDAP_CERT_FILE;
|
|
|
|
ldap_certfile.replace("@@@ADMINSERVER@@@", m_realmconfig[m_defaultRealm].name.lower());
|
|
|
|
|
|
|
|
// Certificate Authority
|
|
|
|
TQString fqdn = LDAPManager::getMachineFQDN();
|
|
|
|
TQString defaultRealm = m_systemconfig->readEntry("DefaultRealm");
|
|
|
|
|
|
|
|
// Connect to LDAP
|
|
|
|
TQString realmname = defaultRealm.upper();
|
|
|
|
LDAPCredentials* credentials = new LDAPCredentials;
|
|
|
|
credentials->username = "";
|
|
|
|
credentials->password = "";
|
|
|
|
credentials->realm = realmname;
|
|
|
|
LDAPManager* ldap_mgr = new LDAPManager(realmname, "ldapi://", credentials);
|
|
|
|
TQString errorstring;
|
|
|
|
|
|
|
|
TQString basedn = ldap_mgr->basedn();
|
|
|
|
|
|
|
|
// Get certificate settings from LDAP
|
|
|
|
TQString realmCAMaster = ldap_mgr->getRealmCAMaster(&errorstring);
|
|
|
|
|
|
|
|
delete ldap_mgr;
|
|
|
|
delete credentials;
|
|
|
|
|
|
|
|
if (realmCAMaster == "") {
|
|
|
|
printf("[WARNING] Unable to determine the realm CA master! CA will not be updated\n"); fflush(stdout);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (realmCAMaster == fqdn) {
|
|
|
|
printf("This server is the realm CA master\n"); fflush(stdout);
|
|
|
|
|
|
|
|
TQString realmname = m_defaultRealm.upper();
|
|
|
|
LDAPCredentials* credentials = new LDAPCredentials;
|
|
|
|
credentials->username = "";
|
|
|
|
credentials->password = "";
|
|
|
|
credentials->realm = realmname;
|
|
|
|
LDAPManager* ldap_mgr = new LDAPManager(realmname, "ldapi://", credentials);
|
|
|
|
|
|
|
|
if (TQFile::exists(KERBEROS_PKI_PEM_FILE)) {
|
|
|
|
certExpiry = LDAPManager::getCertificateExpiration(KERBEROS_PKI_PEM_FILE);
|
|
|
|
if (certExpiry >= now) {
|
|
|
|
printf("Certificate %s expires %s\n", TQString(KERBEROS_PKI_PEM_FILE).ascii(), certExpiry.toString().ascii()); fflush(stdout);
|
|
|
|
}
|
|
|
|
if (force_update || (certExpiry < now) || ((certExpiry >= now) && (certExpiry < soon))) {
|
|
|
|
printf("Regenerating certificate %s...\n", TQString(KERBEROS_PKI_PEM_FILE).ascii()); fflush(stdout);
|
|
|
|
LDAPManager::generatePublicKerberosCACertificate(m_certconfig, m_realmconfig[m_defaultRealm]);
|
|
|
|
|
|
|
|
// Upload the contents of KERBEROS_PKI_PEM_FILE to the LDAP server
|
|
|
|
TQString errorstring;
|
|
|
|
if (uploadKerberosCAFileToLDAP(ldap_mgr, &errorstring) != 0) {
|
|
|
|
printf("[ERROR] Unable to upload new certificate to LDAP server!\n%s\n", errorstring.ascii()); fflush(stdout);
|
|
|
|
}
|
|
|
|
|
|
|
|
ca_modified = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set permissions
|
|
|
|
chmod(KERBEROS_PKI_PEMKEY_FILE, S_IRUSR|S_IWUSR);
|
|
|
|
chown_safe(KERBEROS_PKI_PEMKEY_FILE, 0, 0);
|
|
|
|
chmod(KERBEROS_PKI_PEM_FILE, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
|
|
|
|
chown_safe(KERBEROS_PKI_PEM_FILE, 0, 0);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
printf("[WARNING] Certificate file %s not found!\n", TQString(KERBEROS_PKI_PEM_FILE).ascii()); fflush(stdout);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check CRL expiry
|
|
|
|
TQByteArray certificateContents;
|
|
|
|
if (ldap_mgr->getTDECertificate("publicRootCertificateRevocationList", &certificateContents, NULL) == 0) {
|
|
|
|
certExpiry = LDAPManager::getCertificateExpiration(certificateContents);
|
|
|
|
if (certExpiry >= now) {
|
|
|
|
printf("CRL expires %s\n", certExpiry.toString().ascii()); fflush(stdout);
|
|
|
|
}
|
|
|
|
if (force_update || (certExpiry < now) || ((certExpiry >= now) && (certExpiry < soon))) {
|
|
|
|
printf("Regenerating CRL...\n"); fflush(stdout);
|
|
|
|
LDAPManager::generatePublicKerberosCACertificate(m_certconfig, m_realmconfig[m_defaultRealm]);
|
|
|
|
|
|
|
|
// Upload the new CRL to the LDAP server
|
|
|
|
if (ldap_mgr->generatePKICRL(m_certconfig.caCrlExpiryDays, m_realmconfig[m_defaultRealm], KERBEROS_PKI_CRL_FILE, KERBEROS_PKI_PEMKEY_FILE, KERBEROS_PKI_CRLDB_FILE, &errorstring) != 0) {
|
|
|
|
printf("[ERROR] Unable to generate CRL!\n%s\n", errorstring.ascii()); fflush(stdout);
|
|
|
|
}
|
|
|
|
|
|
|
|
ca_modified = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
delete ldap_mgr;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
printf("This server is a realm CA slave\n"); fflush(stdout);
|
|
|
|
|
|
|
|
// Connect to LDAP
|
|
|
|
TQString realmname = defaultRealm.upper();
|
|
|
|
LDAPCredentials* credentials = new LDAPCredentials;
|
|
|
|
credentials->username = "cn=admin," + basedn;
|
|
|
|
m_systemconfig->setGroup("Replication");
|
|
|
|
credentials->password = m_systemconfig->readEntry("Password");
|
|
|
|
m_systemconfig->setGroup(NULL);
|
|
|
|
credentials->realm = realmname;
|
|
|
|
LDAPManager* ldap_mgr = new LDAPManager(realmname, TQString("ldaps://%1/").arg(realmCAMaster), credentials);
|
|
|
|
TQString errorstring;
|
|
|
|
|
|
|
|
if (ldap_mgr->getTDECertificate("privateRootCertificateKey", KERBEROS_PKI_PEMKEY_FILE ".tmp", &errorstring) != 0) {
|
|
|
|
printf("[ERROR] Unable to get private CA certificate key from LDAP server!\n%s\n", errorstring.ascii()); fflush(stdout);
|
|
|
|
}
|
|
|
|
if (ldap_mgr->getTDECertificate("publicRootCertificate", KERBEROS_PKI_PEM_FILE ".tmp", &errorstring) != 0) {
|
|
|
|
printf("[ERROR] Unable to get public CA certificate from LDAP server!\n%s\n", errorstring.ascii()); fflush(stdout);
|
|
|
|
}
|
|
|
|
|
|
|
|
delete ldap_mgr;
|
|
|
|
delete credentials;
|
|
|
|
|
|
|
|
TQByteArray originalPemKeyFile;
|
|
|
|
TQByteArray originalPemFile;
|
|
|
|
TQByteArray newPemKeyFile;
|
|
|
|
TQByteArray newPemFile;
|
|
|
|
|
|
|
|
TQFile* cafile;
|
|
|
|
cafile = new TQFile(KERBEROS_PKI_PEMKEY_FILE);
|
|
|
|
if (cafile->open(IO_ReadOnly)) {
|
|
|
|
originalPemKeyFile = cafile->readAll();
|
|
|
|
}
|
|
|
|
delete cafile;
|
|
|
|
cafile = new TQFile(KERBEROS_PKI_PEM_FILE);
|
|
|
|
if (cafile->open(IO_ReadOnly)) {
|
|
|
|
originalPemFile = cafile->readAll();
|
|
|
|
}
|
|
|
|
delete cafile;
|
|
|
|
cafile = new TQFile(KERBEROS_PKI_PEMKEY_FILE ".tmp");
|
|
|
|
if (cafile->open(IO_ReadOnly)) {
|
|
|
|
newPemKeyFile = cafile->readAll();
|
|
|
|
}
|
|
|
|
delete cafile;
|
|
|
|
cafile = new TQFile(KERBEROS_PKI_PEM_FILE ".tmp");
|
|
|
|
if (cafile->open(IO_ReadOnly)) {
|
|
|
|
newPemFile = cafile->readAll();
|
|
|
|
}
|
|
|
|
delete cafile;
|
|
|
|
|
|
|
|
if ((originalPemKeyFile == newPemKeyFile) && (originalPemFile == newPemFile)) {
|
|
|
|
unlink(KERBEROS_PKI_PEMKEY_FILE ".tmp");
|
|
|
|
unlink(KERBEROS_PKI_PEM_FILE ".tmp");
|
|
|
|
printf("Certificates have not changed since last update\n");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
unlink(KERBEROS_PKI_PEMKEY_FILE);
|
|
|
|
unlink(KERBEROS_PKI_PEM_FILE);
|
|
|
|
rename(KERBEROS_PKI_PEMKEY_FILE ".tmp", KERBEROS_PKI_PEMKEY_FILE);
|
|
|
|
rename(KERBEROS_PKI_PEM_FILE ".tmp", KERBEROS_PKI_PEM_FILE);
|
|
|
|
force_update = true;
|
|
|
|
printf("Certificates have changed, forcing certificate regeneration\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set permissions
|
|
|
|
chmod(KERBEROS_PKI_PEMKEY_FILE, S_IRUSR|S_IWUSR);
|
|
|
|
chown_safe(KERBEROS_PKI_PEMKEY_FILE, 0, 0);
|
|
|
|
chmod(KERBEROS_PKI_PEM_FILE, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
|
|
|
|
chown_safe(KERBEROS_PKI_PEM_FILE, 0, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ca_modified) {
|
|
|
|
force_update = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Kerberos
|
|
|
|
if (TQFile::exists(kdc_certfile)) {
|
|
|
|
certExpiry = LDAPManager::getCertificateExpiration(kdc_certfile);
|
|
|
|
if (certExpiry >= now) {
|
|
|
|
printf("Certificate %s expires %s\n", kdc_certfile.ascii(), certExpiry.toString().ascii()); fflush(stdout);
|
|
|
|
}
|
|
|
|
if (force_update || (certExpiry < now) || ((certExpiry >= now) && (certExpiry < soon))) {
|
|
|
|
printf("Regenerating certificate %s...\n", kdc_certfile.ascii()); fflush(stdout);
|
|
|
|
LDAPManager::generatePublicKerberosCertificate(m_certconfig, m_realmconfig[m_defaultRealm]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
printf("[WARNING] Certificate file %s not found!\n", kdc_certfile.ascii()); fflush(stdout);
|
|
|
|
}
|
|
|
|
|
|
|
|
// LDAP
|
|
|
|
if (TQFile::exists(ldap_certfile)) {
|
|
|
|
certExpiry = LDAPManager::getCertificateExpiration(ldap_certfile);
|
|
|
|
if (certExpiry >= now) {
|
|
|
|
printf("Certificate %s expires %s\n", ldap_certfile.ascii(), certExpiry.toString().ascii()); fflush(stdout);
|
|
|
|
}
|
|
|
|
if (force_update || (certExpiry < now) || ((certExpiry >= now) && (certExpiry < soon))) {
|
|
|
|
printf("Regenerating certificate %s...\n", ldap_certfile.ascii()); fflush(stdout);
|
|
|
|
uid_t slapd_uid = 0;
|
|
|
|
gid_t slapd_gid = 0;
|
|
|
|
|
|
|
|
// Get LDAP user uid/gid
|
|
|
|
struct passwd *pwd;
|
|
|
|
pwd = getpwnam(m_ldapUserName);
|
|
|
|
slapd_uid = pwd->pw_uid;
|
|
|
|
slapd_gid = pwd->pw_gid;
|
|
|
|
|
|
|
|
LDAPManager::generatePublicLDAPCertificate(m_certconfig, m_realmconfig[m_defaultRealm], slapd_uid, slapd_gid);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
printf("[WARNING] Certificate file %s not found!\n", ldap_certfile.ascii()); fflush(stdout);
|
|
|
|
}
|
|
|
|
|
|
|
|
delete m_systemconfig;
|
|
|
|
|
|
|
|
//======================================================================================================================================================
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|