/* # Copyright (c) 2009 - OpenSLX Project, Computer Center University of Freiburg # # This program is free software distributed under the GPL version 2. # See http://openslx.org/COPYING # # If you have any feedback please consult http://openslx.org/feedback and # send your suggestions, praise, or complaints to feedback@openslx.org # # General information about OpenSLX can be found at http://openslx.org/ # -------------------------------------------------------------------------- # pvsprivinputd.cpp: # - Handle privileged input events - daemon # -------------------------------------------------------------------------- */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pvsCheckPrivileges.h" #include "pvsPrivInputSocket.h" #include "pvsPrivInputHandler.h" #include "pvsPrivInputSignalHandler.h" using namespace std; #ifndef UNIX_PATH_MAX # define UNIX_PATH_MAX 108 /* according to unix(7) */ #endif QByteArray socketPath; int signalFds[2]; static void unlinkSocket() { if(!socketPath.isNull()) { unlink(socketPath.constData()); } } static void onCaughtSignal(int signum) { pvsPrivInputSendMessage(signalFds[0], &signum, sizeof(signum), 0); } int main(int argc, char** argv) { QCoreApplication app(argc, argv); app.setApplicationName("pvsprivinputd"); app.setOrganizationName("openslx"); bool no_fork = app.arguments().contains("--no-fork", Qt::CaseInsensitive); if(!no_fork) { pid_t pid; pid_t sid; pid = fork(); if(pid < 0) { qCritical("Could not fork: %s", strerror(errno)); exit(EXIT_FAILURE); } if(pid > 0) { exit(EXIT_SUCCESS); } // We are now inside a child process. // Detach from parent: sid = setsid(); if(sid < 0) { qCritical("Could not detach from parent process: %s", strerror(errno)); exit(EXIT_FAILURE); } // Change to some benign directory: if(chdir("/") < 0) { qCritical("Could not change directory: %s", strerror(errno)); exit(EXIT_FAILURE); } } // Okay, we are running as a daemon. Defer reopening standard file descriptors // so we can report errors. // Set the file creation mask to allow all processes to connect to // the socket (access control is handled differently): umask(0); // Store the socket path before the signal handler is installed so it does not risk segfaulting // due to bad timing. socketPath = pvsPrivInputGetSocketAddress().toLocal8Bit(); // Ignore SIGPIPE. Connection errors are handled internally. // According to signal(2), the only error is that the signal number // is invalid. This cannot happen. signal(SIGPIPE, SIG_IGN); // Create our socket: int sock = pvsPrivInputMakeServerSocket(); if(sock < 0) { exit(EXIT_FAILURE); } // set up signal handling: if(socketpair(AF_UNIX, SOCK_DGRAM, 0, signalFds) < 0) { qCritical("Could not set up signal handling. Giving up."); exit(EXIT_FAILURE); } PVSPrivInputSignalHandler sigHandler; QSocketNotifier sigintWatcher(signalFds[1], QSocketNotifier::Read); sigHandler.allowUnauthenticatedKilling(!pvsPrivInputEnableReceiveCredentials(signalFds[1])); QObject::connect(&sigintWatcher, SIGNAL(activated(int)), &sigHandler, SLOT(signalReceived(int))); QObject::connect(&sigHandler, SIGNAL(terminate()), &app, SLOT(quit())); QObject::connect(&sigHandler, SIGNAL(reloadConfiguration()), PVSCheckPrivileges::instance(), SLOT(updateCachedUserDatabase())); QObject::connect(&sigHandler, SIGNAL(reloadConfiguration()), PVSCheckPrivileges::instance(), SLOT(rereadConfiguration())); signal(SIGINT, onCaughtSignal); signal(SIGTERM, onCaughtSignal); signal(SIGHUP, onCaughtSignal); // Our setup is complete. if(!no_fork) { // Reopen standard file descriptors: freopen("/dev/null", "r", stdin); freopen("/dev/null", "w", stderr); freopen("/dev/null", "w", stdout); } // Install our main object PVSPrivInputHandler handler(sock); atexit(unlinkSocket); // and run the main loop. int ret = app.exec(); PVSCheckPrivileges::deleteInstance(); return ret; }