You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kcmldap/cert-updater/main.cpp

264 lines
9.4 KiB

/***************************************************************************
* 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 <stdlib.h>
#include <csignal>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.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 <tqdir.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.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", 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;
}