#include <securityd_client/ucsp.h>
#include "server.h"
#include "entropy.h"
#include "authority.h"
#include "session.h"
#include "pcscmonitor.h"
#include "self.h"
#include <security_utilities/daemon.h>
#include <security_utilities/machserver.h>
#include <security_utilities/logging.h>
#include <security_utilities/ktracecodes.h>
#include <security_cdsa_client/osxsigner.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <syslog.h>
#ifdef PERFORMANCE_MEASUREMENT
#include <mach/mach_time.h>
#endif
#include <security_cdsa_utilities/acl_any.h>
#include <security_cdsa_utilities/acl_password.h>
#include <security_cdsa_utilities/acl_prompted.h>
#include <security_cdsa_utilities/acl_protectedpw.h>
#include <security_cdsa_utilities/acl_threshold.h>
#include <security_cdsa_utilities/acl_codesigning.h>
#include <security_cdsa_utilities/acl_process.h>
#include <security_cdsa_utilities/acl_comment.h>
#include <security_cdsa_utilities/acl_preauth.h>
#include "acl_keychain.h"
static void usage(const char *me) __attribute__((noreturn));
static void handleSignals(int sig);
static PCSCMonitor::ServiceLevel scOptions(const char *optionString);
static Port gMainServerPort;
int main(int argc, char *argv[])
{
#ifdef PERFORMANCE_MEASUREMENT
uint64_t startTime = mach_absolute_time ();
#endif
Debug::trace (kSecTraceSecurityServerStart);
secdebug("SS", "starting umask was 0%o", ::umask(0));
::umask(0);
bool debugMode = false;
const char *bootstrapName = NULL;
bool doFork = false;
bool reExecute = false;
int workerTimeout = 0;
int maxThreads = 0;
const char *authorizationConfig = "/etc/authorization";
const char *tokenCacheDir = "/var/db/TokenCache";
const char *entropyFile = "/var/db/SystemEntropyCache";
const char *equivDbFile = EQUIVALENCEDBPATH;
const char *smartCardOptions = getenv("SMARTCARDS");
extern char *optarg;
extern int optind;
int arg;
while ((arg = getopt(argc, argv, "a:c:de:E:fN:s:t:T:X")) != -1) {
switch (arg) {
case 'a':
authorizationConfig = optarg;
break;
case 'c':
tokenCacheDir = optarg;
break;
case 'd':
debugMode = true;
break;
case 'e':
equivDbFile = optarg;
break;
case 'E':
entropyFile = optarg;
break;
case 'f':
fprintf(stderr, "%s: the -f option is obsolete\n", argv[0]);
break;
case 'N':
bootstrapName = optarg;
break;
case 's':
smartCardOptions = optarg;
break;
case 't':
if ((maxThreads = atoi(optarg)) < 0)
maxThreads = 0;
break;
case 'T':
if ((workerTimeout = atoi(optarg)) < 0)
workerTimeout = 0;
break;
case 'X':
doFork = true;
reExecute = true;
break;
default:
usage(argv[0]);
}
}
if (optind < argc)
usage(argv[0]);
if (!bootstrapName) {
bootstrapName = getenv(SECURITYSERVER_BOOTSTRAP_ENV);
if (!bootstrapName)
bootstrapName = SECURITYSERVER_BOOTSTRAP_NAME;
}
if (debugMode) {
Syslog::open(bootstrapName, LOG_AUTHPRIV, LOG_PERROR);
Syslog::notice("%s started in debug mode", argv[0]);
} else {
Syslog::open(bootstrapName, LOG_AUTHPRIV, LOG_CONS);
}
if (uid_t uid = getuid()) {
#if defined(NDEBUG)
Syslog::alert("Tried to run securityd as user %d: aborted", uid);
fprintf(stderr, "You are not allowed to run securityd\n");
exit(1);
#else
fprintf(stderr, "securityd is unprivileged; some features may not work.\n");
secdebug("SS", "Running as user %d (you have been warned)", uid);
#endif //NDEBUG
}
if (!debugMode && getppid() != 1) {
if (!Daemon::incarnate(doFork))
exit(1);
if (reExecute && !Daemon::executeSelf(argv))
exit(1); }
if (signal(SIGCHLD, handleSignals) == SIG_ERR)
secdebug("SS", "Cannot handle SIGCHLD: errno=%d", errno);
if (signal(SIGINT, handleSignals) == SIG_ERR)
secdebug("SS", "Cannot handle SIGINT: errno=%d", errno);
if (signal(SIGTERM, handleSignals) == SIG_ERR)
secdebug("SS", "Cannot handle SIGTERM: errno=%d", errno);
#if !defined(NDEBUG)
if (signal(SIGUSR1, handleSignals) == SIG_ERR)
secdebug("SS", "Cannot handle SIGHUP: errno=%d", errno);
#endif //NDEBUG
CodeSigning::OSXSigner signer;
Authority authority(authorizationConfig);
new AnyAclSubject::Maker();
new PasswordAclSubject::Maker();
new ProtectedPasswordAclSubject::Maker();
new PromptedAclSubject::Maker();
new ThresholdAclSubject::Maker();
new CommentAclSubject::Maker();
new ProcessAclSubject::Maker();
new CodeSignatureAclSubject::Maker(signer);
new KeychainPromptAclSubject::Maker();
new PreAuthorizationAcls::OriginMaker();
new PreAuthorizationAcls::SourceMaker();
CodeSignatures codeSignatures(equivDbFile);
Server server(authority, codeSignatures, bootstrapName);
gMainServerPort = server.primaryServicePort();
if (workerTimeout)
server.timeout(workerTimeout);
if (maxThreads)
server.maxThreads(maxThreads);
# if defined(NDEBUG)
EntropyManager entropy(server, entropyFile);
# else
if (getuid() == 0) new EntropyManager(server, entropyFile);
# endif
#if !defined(NDEBUG)
if (const char *s = getenv("TOKENCACHE"))
tokenCacheDir = s;
#endif //NDEBUG
PCSCMonitor secureCards(server, tokenCacheDir, scOptions(smartCardOptions));
RootSession rootSession(server,
debugMode ? (sessionHasGraphicAccess | sessionHasTTY) : 0);
server.loadCssm();
Syslog::notice("Entering service");
secdebug("SS", "%s initialized", bootstrapName);
Debug::trace (kSecTraceSecurityServerInitialized);
#ifdef PERFORMANCE_MEASUREMENT
uint64_t endTime = mach_absolute_time ();
uint64_t elapsedTime = endTime - startTime;
mach_timebase_info_data_t multiplier;
mach_timebase_info (&multiplier);
elapsedTime = elapsedTime * multiplier.numer / multiplier.denom;
FILE* f = fopen ("/var/log/startuptime.txt", "a");
if (f == NULL)
{
f = fopen ("/tmp/startuptime.txt", "a");
}
fprintf (f, "%lld\n", elapsedTime);
fclose (f);
#endif
server.run();
Syslog::alert("Aborting");
return 1;
}
static void usage(const char *me)
{
fprintf(stderr, "Usage: %s [-dX]"
"\n\t[-a authConfigFile] Authorization configuration file"
"\n\t[-c tokencache] smartcard token cache directory"
"\n\t[-e equivDatabase] path to code equivalence database"
"\n\t[-N serviceName] MACH service name"
"\n\t[-s off|on|conservative|aggressive] smartcard operation level"
"\n\t[-t maxthreads] [-T threadTimeout] server thread control"
"\n", me);
exit(2);
}
static PCSCMonitor::ServiceLevel scOptions(const char *optionString)
{
if (optionString)
if (!strcmp(optionString, "off"))
return PCSCMonitor::forcedOff;
else if (!strcmp(optionString, "on"))
return PCSCMonitor::forcedOn;
else if (!strcmp(optionString, "conservative"))
return PCSCMonitor::conservative;
else if (!strcmp(optionString, "aggressive"))
return PCSCMonitor::aggressive;
else if (!strcmp(optionString, "external"))
return PCSCMonitor::externalDaemon;
else
usage("securityd");
else
return PCSCMonitor::aggressive;
}
static void handleSignals(int sig)
{
if (kern_return_t rc = self_client_handleSignal(gMainServerPort, mach_task_self(), sig))
Syslog::error("self-send failed (mach error %d)", rc);
}