2 * Copyright (c) 2000-2004 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
26 // securityd - Apple security services daemon.
28 #include <securityd_client/ucsp.h>
32 #include "authority.h"
34 #include "pcscmonitor.h"
37 #include <security_utilities/daemon.h>
38 #include <security_utilities/machserver.h>
39 #include <security_utilities/logging.h>
40 #include <security_utilities/ktracecodes.h>
41 #include <security_cdsa_client/osxsigner.h>
44 #include <sys/types.h>
49 // #define PERFORMANCE_MEASUREMENT 1
51 #ifdef PERFORMANCE_MEASUREMENT
52 #include <mach/mach_time.h>
55 // ACL subject types (their makers are instantiated here)
56 #include <security_cdsa_utilities/acl_any.h>
57 #include <security_cdsa_utilities/acl_password.h>
58 #include <security_cdsa_utilities/acl_prompted.h>
59 #include <security_cdsa_utilities/acl_protectedpw.h>
60 #include <security_cdsa_utilities/acl_threshold.h>
61 #include <security_cdsa_utilities/acl_codesigning.h>
62 #include <security_cdsa_utilities/acl_process.h>
63 #include <security_cdsa_utilities/acl_comment.h>
64 #include <security_cdsa_utilities/acl_preauth.h>
65 #include "acl_keychain.h"
68 // Local functions of the main program driver
70 static void usage(const char *me
) __attribute__((noreturn
));
71 static void handleSignals(int sig
);
72 static PCSCMonitor::ServiceLevel
scOptions(const char *optionString
);
75 static Port gMainServerPort
;
81 int main(int argc
, char *argv
[])
83 #ifdef PERFORMANCE_MEASUREMENT
84 // needed for automated timing of securityd startup
85 uint64_t startTime
= mach_absolute_time ();
88 Debug::trace (kSecTraceSecurityServerStart
);
90 // clear the umask - we know what we're doing
91 secdebug("SS", "starting umask was 0%o", ::umask(0));
94 // program arguments (preset to defaults)
95 bool debugMode
= false;
96 const char *bootstrapName
= NULL
;
98 bool reExecute
= false;
99 int workerTimeout
= 0;
101 const char *authorizationConfig
= "/etc/authorization";
102 const char *tokenCacheDir
= "/var/db/TokenCache";
103 const char *entropyFile
= "/var/db/SystemEntropyCache";
104 const char *equivDbFile
= EQUIVALENCEDBPATH
;
105 const char *smartCardOptions
= getenv("SMARTCARDS");
107 // parse command line arguments
111 while ((arg
= getopt(argc
, argv
, "a:c:de:E:fN:s:t:T:X")) != -1) {
114 authorizationConfig
= optarg
;
117 tokenCacheDir
= optarg
;
123 equivDbFile
= optarg
;
126 entropyFile
= optarg
;
129 fprintf(stderr
, "%s: the -f option is obsolete\n", argv
[0]);
132 bootstrapName
= optarg
;
135 smartCardOptions
= optarg
;
138 if ((maxThreads
= atoi(optarg
)) < 0)
142 if ((workerTimeout
= atoi(optarg
)) < 0)
154 // take no non-option arguments
158 // figure out the bootstrap name
159 if (!bootstrapName
) {
160 bootstrapName
= getenv(SECURITYSERVER_BOOTSTRAP_ENV
);
162 bootstrapName
= SECURITYSERVER_BOOTSTRAP_NAME
;
165 // configure logging first
167 Syslog::open(bootstrapName
, LOG_AUTHPRIV
, LOG_PERROR
);
168 Syslog::notice("%s started in debug mode", argv
[0]);
170 Syslog::open(bootstrapName
, LOG_AUTHPRIV
, LOG_CONS
);
173 // if we're not running as root in production mode, fail
174 // in debug mode, issue a warning
175 if (uid_t uid
= getuid()) {
177 Syslog::alert("Tried to run securityd as user %d: aborted", uid
);
178 fprintf(stderr
, "You are not allowed to run securityd\n");
181 fprintf(stderr
, "securityd is unprivileged; some features may not work.\n");
182 secdebug("SS", "Running as user %d (you have been warned)", uid
);
186 // turn into a properly diabolical daemon unless debugMode is on
187 if (!debugMode
&& getppid() != 1) {
188 if (!Daemon::incarnate(doFork
))
189 exit(1); // can't daemonize
191 if (reExecute
&& !Daemon::executeSelf(argv
))
192 exit(1); // can't self-execute
195 // arm signal handlers; code below may generate signals we want to see
196 if (signal(SIGCHLD
, handleSignals
) == SIG_ERR
)
197 secdebug("SS", "Cannot handle SIGCHLD: errno=%d", errno
);
198 if (signal(SIGINT
, handleSignals
) == SIG_ERR
)
199 secdebug("SS", "Cannot handle SIGINT: errno=%d", errno
);
200 if (signal(SIGTERM
, handleSignals
) == SIG_ERR
)
201 secdebug("SS", "Cannot handle SIGTERM: errno=%d", errno
);
203 if (signal(SIGUSR1
, handleSignals
) == SIG_ERR
)
204 secdebug("SS", "Cannot handle SIGHUP: errno=%d", errno
);
207 // create a code signing engine
208 CodeSigning::OSXSigner signer
;
210 // create an Authorization engine
211 Authority
authority(authorizationConfig
);
213 // establish the ACL machinery
214 new AnyAclSubject::Maker();
215 new PasswordAclSubject::Maker();
216 new ProtectedPasswordAclSubject::Maker();
217 new PromptedAclSubject::Maker();
218 new ThresholdAclSubject::Maker();
219 new CommentAclSubject::Maker();
220 new ProcessAclSubject::Maker();
221 new CodeSignatureAclSubject::Maker(signer
);
222 new KeychainPromptAclSubject::Maker();
223 new PreAuthorizationAcls::OriginMaker();
224 new PreAuthorizationAcls::SourceMaker();
226 // establish the code equivalents database
227 CodeSignatures
codeSignatures(equivDbFile
);
229 // create the main server object and register it
230 Server
server(authority
, codeSignatures
, bootstrapName
);
232 // Remember the primary service port to send signal events to
233 gMainServerPort
= server
.primaryServicePort();
235 // set server configuration from arguments, if specified
237 server
.timeout(workerTimeout
);
239 server
.maxThreads(maxThreads
);
241 // add the RNG seed timer
243 EntropyManager
entropy(server
, entropyFile
);
245 if (getuid() == 0) new EntropyManager(server
, entropyFile
);
248 // create a token-cache interface
250 if (const char *s
= getenv("TOKENCACHE"))
254 // create a smartcard monitor to manage external token devices
255 PCSCMonitor
secureCards(server
, tokenCacheDir
, scOptions(smartCardOptions
));
257 // create the RootSession object (if -d, give it graphics and tty attributes)
258 RootSession
rootSession(server
,
259 debugMode
? (sessionHasGraphicAccess
| sessionHasTTY
) : 0);
261 // install MDS and initialize the local CSSM
264 // okay, we're ready to roll
265 Syslog::notice("Entering service");
266 secdebug("SS", "%s initialized", bootstrapName
);
267 Debug::trace (kSecTraceSecurityServerInitialized
);
269 #ifdef PERFORMANCE_MEASUREMENT
270 // needed for automated timing of securityd startup
271 uint64_t endTime
= mach_absolute_time ();
273 // compute how long it took to initialize
274 uint64_t elapsedTime
= endTime
- startTime
;
275 mach_timebase_info_data_t multiplier
;
276 mach_timebase_info (&multiplier
);
278 elapsedTime
= elapsedTime
* multiplier
.numer
/ multiplier
.denom
;
280 FILE* f
= fopen ("/var/log/startuptime.txt", "a");
283 // probably not running as root.
284 f
= fopen ("/tmp/startuptime.txt", "a");
287 fprintf (f
, "%lld\n", elapsedTime
);
294 // fell out of runloop (should not happen)
295 Syslog::alert("Aborting");
301 // Issue usage message and die
303 static void usage(const char *me
)
305 fprintf(stderr
, "Usage: %s [-dX]"
306 "\n\t[-a authConfigFile] Authorization configuration file"
307 "\n\t[-c tokencache] smartcard token cache directory"
308 "\n\t[-e equivDatabase] path to code equivalence database"
309 "\n\t[-N serviceName] MACH service name"
310 "\n\t[-s off|on|conservative|aggressive] smartcard operation level"
311 "\n\t[-t maxthreads] [-T threadTimeout] server thread control"
318 // Translate strings (e.g. "conservative") into PCSCMonitor service levels
320 static PCSCMonitor::ServiceLevel
scOptions(const char *optionString
)
323 if (!strcmp(optionString
, "off"))
324 return PCSCMonitor::forcedOff
;
325 else if (!strcmp(optionString
, "on"))
326 return PCSCMonitor::forcedOn
;
327 else if (!strcmp(optionString
, "conservative"))
328 return PCSCMonitor::conservative
;
329 else if (!strcmp(optionString
, "aggressive"))
330 return PCSCMonitor::aggressive
;
331 else if (!strcmp(optionString
, "external"))
332 return PCSCMonitor::externalDaemon
;
336 return PCSCMonitor::aggressive
;
342 // We send ourselves a message (through the "self" service), so actual
343 // actions happen on the normal event loop path. Note that another thread
344 // may be picking up the message immediately.
346 static void handleSignals(int sig
)
348 if (kern_return_t rc
= self_client_handleSignal(gMainServerPort
, mach_task_self(), sig
))
349 Syslog::error("self-send failed (mach error %d)", rc
);