|
|
|
/***************************************************************************
|
|
|
|
* Copyright (C) 2013 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.1";
|
|
|
|
|
|
|
|
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, 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 = false;
|
|
|
|
LDAPManager* ldap_mgr = new LDAPManager(realmcfg.name.upper(), TQString("ldap://%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", certificateName.ascii());
|
|
|
|
if (ldap_mgr->getTDECertificate("publicRootCertificate", certificateName, &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, Timothy Pearson");
|
|
|
|
aboutData.addAuthor("Timothy Pearson",0, "kb9vqf@pearsoncomputing.net");
|
|
|
|
TDECmdLineArgs::init( argc, argv, &aboutData );
|
|
|
|
TDEApplication::disableAutoDcopRegistration();
|
|
|
|
|
|
|
|
TDEApplication app(false, false);
|
|
|
|
|
|
|
|
TDEStartupInfo::appStarted();
|
|
|
|
|
|
|
|
//======================================================================================================================================================
|
|
|
|
//
|
|
|
|
// 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 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 certificateName = KERBEROS_PKI_PUBLICDIR + realmcfg.admin_server + ".ldap.crt";
|
|
|
|
|
|
|
|
TQDateTime certExpiry;
|
|
|
|
TQDateTime soon = now.addDays(7); // Keep in sync with src/ldapcontroller.cpp
|
|
|
|
|
|
|
|
if (TQFile::exists(certificateName)) {
|
|
|
|
certExpiry = LDAPManager::getCertificateExpiration(certificateName);
|
|
|
|
if (certExpiry >= now) {
|
|
|
|
printf("[INFO] Certificate %s expires %s\n", certificateName.ascii(), certExpiry.toString().ascii()); fflush(stdout);
|
|
|
|
}
|
|
|
|
if ((certExpiry < now) || ((certExpiry >= now) && (certExpiry < soon))) {
|
|
|
|
if (get_certificate_from_server(certificateName, realmcfg) != 0) {
|
|
|
|
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(certificateName, realmcfg) != 0) {
|
|
|
|
allDownloadsOK = 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);
|
|
|
|
|
|
|
|
//======================================================================================================================================================
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|