/*************************************************************************** * Copyright (C) 2013 - 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // 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.2"; static TDECmdLineOptions options[] = { { "immediate", I18N_NOOP("Force immediate update"), 0 }, TDECmdLineLastOption }; bool received_sighup = false; void signalHandler(int signum) { printf("[INFO] Got signal %d\n", signum); if (signum == SIGHUP) { received_sighup = true; } else if (signum == SIGTERM) { unlink(TDE_LDAP_CERT_UPDATER_PID_FILE); exit(0); } else if (signum == SIGINT) { unlink(TDE_LDAP_CERT_UPDATER_PID_FILE); exit(0); } } int get_certificate_from_server(TQString certificateName, TQString certificateFileName, LDAPRealmConfig realmcfg) { int retcode = 0; TQString errorstring; // Bind anonymously to LDAP LDAPCredentials* credentials = new LDAPCredentials; credentials->username = ""; credentials->password = ""; credentials->realm = realmcfg.name.upper(); credentials->use_tls = true; LDAPManager* ldap_mgr = new LDAPManager(realmcfg.name.upper(), TQString("ldaps://%1").arg(realmcfg.admin_server).ascii(), credentials); // Add the domain-wide computer local admin group to local sudoers ldap_mgr->writeSudoersConfFile(&errorstring); // Get and install the CA root certificate from LDAP printf("[INFO] Updating certificate %s from LDAP\n", certificateFileName.ascii()); if (ldap_mgr->getTDECertificate(certificateName, certificateFileName, &errorstring) != 0) { printf("[ERROR] Unable to obtain root certificate for realm %s: %s\n", realmcfg.name.upper().ascii(), errorstring.ascii()); retcode = 1; } delete ldap_mgr; delete credentials; return retcode; } int main(int argc, char *argv[]) { // Register signal handler for SIGHUP signal(SIGHUP, signalHandler); // Register signal handler for SIGINT signal(SIGINT, signalHandler); // Register signal handler for SIGTERM signal(SIGTERM, signalHandler); TQDir pidDir(TDE_LDAP_PID_DIR); if (!pidDir.exists()) { mkdir(TDE_LDAP_PID_DIR, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH); } TQFile pidFile(TDE_LDAP_CERT_UPDATER_PID_FILE); if (pidFile.open(IO_WriteOnly)) { TQTextStream stream(&pidFile); stream << getpid(); pidFile.close(); } // Seed random number generator struct timeval time; gettimeofday(&time,NULL); srand((time.tv_sec * 1000) + (time.tv_usec / 1000)); // Initialize TDE application libraries TDEAboutData aboutData( "tdeldapcertupdater", I18N_NOOP("Realm Certificate Updater"), version, description, TDEAboutData::License_GPL, "(c) 2013 - 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(); bool immediate = TDECmdLineArgs::parsedArgs()->isSet("immediate"); //====================================================================================================================================================== // // Updater code follows // //====================================================================================================================================================== KSimpleConfig* systemconfig = new KSimpleConfig( TQString::fromLatin1( KDE_CONFDIR "/ldap/ldapconfigrc" )); LDAPRealmConfigList realms = LDAPManager::readTDERealmList(systemconfig, false); TQString m_defaultRealm = systemconfig->readEntry("DefaultRealm"); int prevSecondsToExpiry = (7*24*60*60); while (1) { bool newCertDownloaded = false; bool allDownloadsOK = true; TQDateTime now = TQDateTime::currentDateTime(); TQDateTime earliestCertExpiry = now.addDays(14); // Recheck every 7 days regardless of last expiry check results LDAPRealmConfigList::Iterator it; for (it = realms.begin(); it != realms.end(); ++it) { LDAPRealmConfig realmcfg = it.data(); TQString certificateFileName = KERBEROS_PKI_PUBLICDIR + realmcfg.admin_server + ".ldap.crt"; TQString crlFileName = KERBEROS_PKI_PUBLICDIR + realmcfg.admin_server + ".ldap.crl"; TQDateTime certExpiry; TQDateTime soon = now.addDays(7); // Keep in sync with src/ldapcontroller.cpp if (TQFile::exists(certificateFileName)) { certExpiry = LDAPManager::getCertificateExpiration(certificateFileName); if (certExpiry >= now) { printf("[INFO] Certificate %s expires %s\n", certificateFileName.ascii(), certExpiry.toString().ascii()); fflush(stdout); } if (immediate || (certExpiry < now) || ((certExpiry >= now) && (certExpiry < soon))) { if (get_certificate_from_server("publicRootCertificate", certificateFileName, realmcfg) == 0) { newCertDownloaded = true; } else { allDownloadsOK = false; } } if (certExpiry < earliestCertExpiry) { earliestCertExpiry = certExpiry; } } else { mkdir(TDE_CERTIFICATE_DIR, 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); if (get_certificate_from_server("publicRootCertificate", certificateFileName, realmcfg) == 0) { newCertDownloaded = true; } else { allDownloadsOK = false; } } if (TQFile::exists(crlFileName)) { certExpiry = LDAPManager::getCertificateExpiration(crlFileName); if (certExpiry >= now) { printf("[INFO] CRL %s expires %s\n", crlFileName.ascii(), certExpiry.toString().ascii()); fflush(stdout); } if (immediate || (certExpiry < now) || ((certExpiry >= now) && (certExpiry < soon))) { if (get_certificate_from_server("publicRootCertificateRevocationList", crlFileName, realmcfg) == 0) { newCertDownloaded = true; } else { allDownloadsOK = false; } } if (certExpiry < earliestCertExpiry) { earliestCertExpiry = certExpiry; } } else { mkdir(TDE_CERTIFICATE_DIR, 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); if (get_certificate_from_server("publicRootCertificateRevocationList", crlFileName, realmcfg) == 0) { newCertDownloaded = true; } else { allDownloadsOK = false; } } if (newCertDownloaded) { if (LDAPManager::rehashClientPKCSCertificates() != 0) { printf("[WARNING] Unable to rehash client PKCS certificates\n"); fflush(stdout); } } } immediate = false; earliestCertExpiry = earliestCertExpiry.addDays(-7); // Keep in sync with now.addDays above (use negative of value given above) int secondsToExpiry = now.secsTo(earliestCertExpiry); secondsToExpiry = secondsToExpiry + (rand()%(5*60)); // Nothing worse than thousands of clients hammering the LDAP server all at once... if (secondsToExpiry < 1) { secondsToExpiry = 1; } if ((prevSecondsToExpiry == 1) && (allDownloadsOK)) { // The server has not yet updated its certificate, even though our copy is close to expiration // Therefore, do not hammer the server with useless requests! prevSecondsToExpiry = (15*60) + (rand()%(5*60)); } prevSecondsToExpiry = secondsToExpiry; printf("[INFO] Will recheck certificates in %d seconds (%d days)\n", secondsToExpiry, secondsToExpiry/60/60/24); fflush(stdout); if (sleep(secondsToExpiry) != 0) { // Signal caught if (!received_sighup) { break; } } } unlink(TDE_LDAP_CERT_UPDATER_PID_FILE); delete systemconfig; //====================================================================================================================================================== return 0; }