#include "securityserver.h"
#include "server.h"
#include "entropy.h"
#include <Security/daemon.h>
#include <Security/osxsigner.h>
#include "authority.h"
#include "session.h"
#include <unistd.h>
#include <Security/machserver.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include "ktracecodes.h"
#include <Security/acl_any.h>
#include <Security/acl_password.h>
#include <Security/acl_protectedpw.h>
#include <Security/acl_threshold.h>
#include <Security/acl_codesigning.h>
#include <Security/acl_process.h>
#include <Security/acl_comment.h>
#include "acl_keychain.h"
namespace Security
{
uint32 debugMode = 0;
const char *bootstrapName = NULL;
}
static void usage(const char *me);
static void handleSIGCHLD(int);
static void handleSIGOther(int);
int main(int argc, char *argv[])
{
Debug::trace (kSecTraceSecurityServerStart);
bool forceCssmInit = false;
bool reExecute = false;
int workerTimeout = 0;
int maxThreads = 0;
const char *authorizationConfig = "/etc/authorization";
const char *entropyFile = "/var/db/SystemEntropyCache";
const char *equivDbFile = EQUIVALENCEDBPATH;
extern char *optarg;
extern int optind;
int arg;
while ((arg = getopt(argc, argv, "a:de:E:fN:t:T:X")) != -1) {
switch (arg) {
case 'a':
authorizationConfig = optarg;
break;
case 'd':
debugMode++;
break;
case 'e':
equivDbFile = optarg;
break;
case 'E':
entropyFile = optarg;
break;
case 'f':
forceCssmInit = true;
break;
case 'N':
bootstrapName = optarg;
break;
case 't':
if ((maxThreads = atoi(optarg)) < 0)
maxThreads = 0;
break;
case 'T':
if ((workerTimeout = atoi(optarg)) < 0)
workerTimeout = 0;
break;
case 'X':
reExecute = true;
break;
default:
usage(argv[0]);
}
}
if (optind < argc)
usage(argv[0]);
IFDEBUG(if (!bootstrapName) bootstrapName = getenv(SECURITYSERVER_BOOTSTRAP_ENV));
if (!bootstrapName) {
bootstrapName = SECURITYSERVER_BOOTSTRAP_NAME;
}
if (debugMode) {
Syslog::open(bootstrapName, LOG_AUTHPRIV, LOG_PERROR);
Syslog::notice("SecurityServer started in debug mode");
} else {
Syslog::open(bootstrapName, LOG_AUTHPRIV, LOG_CONS);
}
if (uid_t uid = getuid()) {
#if defined(NDEBUG)
Syslog::alert("Tried to run SecurityServer as user %d: aborted", uid);
fprintf(stderr, "You are not allowed to run SecurityServer\n");
exit(1);
#else
fprintf(stderr, "SecurityServer is unprivileged; some features may not work.\n");
secdebug("SS", "Running as user %d (you have been warned)", uid);
#endif //NDEBUG
}
if (!debugMode) {
if (!Daemon::incarnate())
exit(1);
if (reExecute && !Daemon::executeSelf(argv))
exit(1); }
CodeSigning::OSXSigner signer;
Authority authority(authorizationConfig);
new AnyAclSubject::Maker();
new PasswordAclSubject::Maker();
new ProtectedPasswordAclSubject::Maker();
new ThresholdAclSubject::Maker();
new CommentAclSubject::Maker();
new ProcessAclSubject::Maker();
new CodeSignatureAclSubject::Maker(signer);
new KeychainPromptAclSubject::Maker();
new KeychainPromptAclSubject::Maker(CSSM_WORDID__RESERVED_1);
CodeSignatures codeSignatures(equivDbFile);
Server server(authority, codeSignatures, bootstrapName);
if (workerTimeout)
server.timeout(workerTimeout);
if (maxThreads)
server.maxThreads(maxThreads);
# if defined(NDEBUG)
EntropyManager entropy(server, entropyFile);
# else
if (!getuid()) new EntropyManager(server, entropyFile);
# endif
RootSession rootSession(server.primaryServicePort(),
debugMode ? (sessionHasGraphicAccess | sessionHasTTY) : 0);
if (signal(SIGCHLD, handleSIGCHLD) == SIG_ERR)
secdebug("SS", "Cannot ignore SIGCHLD: errno=%d", errno);
if (signal(SIGINT, handleSIGOther) == SIG_ERR)
secdebug("SS", "Cannot handle SIGINT: errno=%d", errno);
if (signal(SIGTERM, handleSIGOther) == SIG_ERR)
secdebug("SS", "Cannot handle SIGTERM: errno=%d", errno);
if (forceCssmInit)
server.loadCssm();
Syslog::notice("Entering service");
secdebug("SS", "%s initialized", bootstrapName);
Debug::trace (kSecTraceSecurityServerStart);
server.run();
Syslog::alert("Aborting");
return 1;
}
static void usage(const char *me)
{
fprintf(stderr, "Usage: %s [-df] [-t maxthreads] [-T threadTimeout]"
"\t[-N bootstrapName] [-a authConfigFile]\n", me);
exit(2);
}
static void handleSIGCHLD(int)
{
int status;
pid_t pid = waitpid(-1, &status, WNOHANG);
switch (pid) {
case 0:
return;
case -1:
return;
default:
return;
}
}
static void handleSIGOther(int sig)
{
switch (sig) {
case SIGINT:
Syslog::notice("received interrupt signal; terminating");
exit(0);
case SIGTERM:
Syslog::notice("received termination signal; terminating");
exit(0);
}
}