]> git.saurik.com Git - apple/securityd.git/blob - src/main.cpp
securityd-36489.tar.gz
[apple/securityd.git] / src / main.cpp
1 /*
2 * Copyright (c) 2000-2007 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 //
26 // securityd - Apple security services daemon.
27 //
28 #include <securityd_client/ucsp.h>
29
30 #include "server.h"
31 #include "entropy.h"
32 #include "authority.h"
33 #include "session.h"
34 #include "notifications.h"
35 #include "pcscmonitor.h"
36 #include "self.h"
37
38 #include <security_utilities/daemon.h>
39 #include <security_utilities/machserver.h>
40 #include <security_utilities/logging.h>
41 #include <security_utilities/ktracecodes.h>
42
43 #include <Security/SecKeychainPriv.h>
44
45 #include <unistd.h>
46 #include <sys/types.h>
47 #include <signal.h>
48 #include <syslog.h>
49
50
51 // #define PERFORMANCE_MEASUREMENT 1
52
53 #ifdef PERFORMANCE_MEASUREMENT
54 #include <mach/mach_time.h>
55 #endif
56
57 // ACL subject types (their makers are instantiated here)
58 #include <security_cdsa_utilities/acl_any.h>
59 #include <security_cdsa_utilities/acl_password.h>
60 #include <security_cdsa_utilities/acl_prompted.h>
61 #include <security_cdsa_utilities/acl_protectedpw.h>
62 #include <security_cdsa_utilities/acl_threshold.h>
63 #include <security_cdsa_utilities/acl_codesigning.h>
64 #include <security_cdsa_utilities/acl_process.h>
65 #include <security_cdsa_utilities/acl_comment.h>
66 #include <security_cdsa_utilities/acl_preauth.h>
67 #include "acl_keychain.h"
68
69
70 //
71 // Local functions of the main program driver
72 //
73 static void usage(const char *me) __attribute__((noreturn));
74 static void handleSignals(int sig);
75 static PCSCMonitor::ServiceLevel scOptions(const char *optionString);
76
77
78 static Port gMainServerPort;
79 PCSCMonitor *gPCSC;
80
81
82 //
83 // Main driver
84 //
85 int main(int argc, char *argv[])
86 {
87 #ifdef PERFORMANCE_MEASUREMENT
88 // needed for automated timing of securityd startup
89 uint64_t startTime = mach_absolute_time ();
90 #endif
91
92 Debug::trace (kSecTraceSecurityServerStart);
93
94 // clear the umask - we know what we're doing
95 secdebug("SS", "starting umask was 0%o", ::umask(0));
96 ::umask(0);
97
98 // tell the keychain (client) layer to turn off the server interface
99 SecKeychainSetServerMode();
100
101 // program arguments (preset to defaults)
102 bool debugMode = false;
103 const char *bootstrapName = NULL;
104 const char* messagingName = SECURITY_MESSAGES_NAME;
105 bool doFork = false;
106 bool reExecute = false;
107 int workerTimeout = 0;
108 int maxThreads = 0;
109 bool waitForClients = false;
110 const char *authorizationConfig = "/etc/authorization";
111 const char *tokenCacheDir = "/var/db/TokenCache";
112 const char *entropyFile = "/var/db/SystemEntropyCache";
113 const char *equivDbFile = EQUIVALENCEDBPATH;
114 const char *smartCardOptions = getenv("SMARTCARDS");
115 uint32_t keychainAclDefault = CSSM_ACL_KEYCHAIN_PROMPT_INVALID | CSSM_ACL_KEYCHAIN_PROMPT_UNSIGNED;
116
117 // check for the Installation-DVD environment and modify some default arguments if found
118 if (access("/etc/rc.cdrom", F_OK) == 0) { // /etc/rc.cdrom exists
119 secdebug("SS", "configuring for installation");
120 smartCardOptions = "off"; // needs writable directories that aren't
121 }
122
123 // parse command line arguments
124 extern char *optarg;
125 extern int optind;
126 int arg;
127 while ((arg = getopt(argc, argv, "a:c:de:E:fiN:s:t:T:Xuw")) != -1) {
128 switch (arg) {
129 case 'a':
130 authorizationConfig = optarg;
131 break;
132 case 'c':
133 tokenCacheDir = optarg;
134 break;
135 case 'd':
136 debugMode = true;
137 break;
138 case 'e':
139 equivDbFile = optarg;
140 break;
141 case 'E':
142 entropyFile = optarg;
143 break;
144 case 'f':
145 fprintf(stderr, "%s: the -f option is obsolete\n", argv[0]);
146 break;
147 case 'i':
148 keychainAclDefault &= ~CSSM_ACL_KEYCHAIN_PROMPT_INVALID;
149 break;
150 case 'N':
151 bootstrapName = optarg;
152 break;
153 case 's':
154 smartCardOptions = optarg;
155 break;
156 case 't':
157 if ((maxThreads = atoi(optarg)) < 0)
158 maxThreads = 0;
159 break;
160 case 'T':
161 if ((workerTimeout = atoi(optarg)) < 0)
162 workerTimeout = 0;
163 break;
164 case 'w':
165 waitForClients = true;
166 break;
167 case 'u':
168 keychainAclDefault &= ~CSSM_ACL_KEYCHAIN_PROMPT_UNSIGNED;
169 break;
170 case 'X':
171 doFork = true;
172 reExecute = true;
173 break;
174 default:
175 usage(argv[0]);
176 }
177 }
178
179 // take no non-option arguments
180 if (optind < argc)
181 usage(argv[0]);
182
183 // figure out the bootstrap name
184 if (!bootstrapName) {
185 bootstrapName = getenv(SECURITYSERVER_BOOTSTRAP_ENV);
186 if (!bootstrapName)
187 {
188 bootstrapName = SECURITYSERVER_BOOTSTRAP_NAME;
189 }
190 else
191 {
192 messagingName = bootstrapName;
193 }
194 }
195 else
196 {
197 messagingName = bootstrapName;
198 }
199
200 // configure logging first
201 if (debugMode) {
202 Syslog::open(bootstrapName, LOG_AUTHPRIV, LOG_PERROR);
203 Syslog::notice("%s started in debug mode", argv[0]);
204 } else {
205 Syslog::open(bootstrapName, LOG_AUTHPRIV, LOG_CONS);
206 }
207
208 // if we're not running as root in production mode, fail
209 // in debug mode, issue a warning
210 if (uid_t uid = getuid()) {
211 #if defined(NDEBUG)
212 Syslog::alert("Tried to run securityd as user %d: aborted", uid);
213 fprintf(stderr, "You are not allowed to run securityd\n");
214 exit(1);
215 #else
216 fprintf(stderr, "securityd is unprivileged; some features may not work.\n");
217 secdebug("SS", "Running as user %d (you have been warned)", uid);
218 #endif //NDEBUG
219 }
220
221 // turn into a properly diabolical daemon unless debugMode is on
222 if (!debugMode && getppid() != 1) {
223 if (!Daemon::incarnate(doFork))
224 exit(1); // can't daemonize
225
226 if (reExecute && !Daemon::executeSelf(argv))
227 exit(1); // can't self-execute
228 }
229
230 // arm signal handlers; code below may generate signals we want to see
231 if (signal(SIGCHLD, handleSignals) == SIG_ERR)
232 secdebug("SS", "Cannot handle SIGCHLD: errno=%d", errno);
233 if (signal(SIGINT, handleSignals) == SIG_ERR)
234 secdebug("SS", "Cannot handle SIGINT: errno=%d", errno);
235 if (signal(SIGTERM, handleSignals) == SIG_ERR)
236 secdebug("SS", "Cannot handle SIGTERM: errno=%d", errno);
237 if (signal(SIGPIPE, handleSignals) == SIG_ERR)
238 secdebug("SS", "Cannot handle SIGPIPE: errno=%d", errno);
239 #if !defined(NDEBUG)
240 if (signal(SIGUSR1, handleSignals) == SIG_ERR)
241 secdebug("SS", "Cannot handle SIGUSR1: errno=%d", errno);
242 #endif //NDEBUG
243 if (signal(SIGUSR2, handleSignals) == SIG_ERR)
244 secdebug("SS", "Cannot handle SIGUSR2: errno=%d", errno);
245
246 // create an Authorization engine
247 Authority authority(authorizationConfig);
248
249 // introduce all supported ACL subject types
250 new AnyAclSubject::Maker();
251 new PasswordAclSubject::Maker();
252 new ProtectedPasswordAclSubject::Maker();
253 new PromptedAclSubject::Maker();
254 new ThresholdAclSubject::Maker();
255 new CommentAclSubject::Maker();
256 new ProcessAclSubject::Maker();
257 new CodeSignatureAclSubject::Maker();
258 new KeychainPromptAclSubject::Maker(keychainAclDefault);
259 new PreAuthorizationAcls::OriginMaker();
260 new PreAuthorizationAcls::SourceMaker();
261
262 // establish the code equivalents database
263 CodeSignatures codeSignatures(equivDbFile);
264
265 // create the main server object and register it
266 Server server(authority, codeSignatures, bootstrapName);
267
268 // Remember the primary service port to send signal events to
269 gMainServerPort = server.primaryServicePort();
270
271 // set server configuration from arguments, if specified
272 if (workerTimeout)
273 server.timeout(workerTimeout);
274 if (maxThreads)
275 server.maxThreads(maxThreads);
276 server.floatingThread(true);
277 server.waitForClients(waitForClients);
278
279 // add the RNG seed timer
280 # if defined(NDEBUG)
281 EntropyManager entropy(server, entropyFile);
282 # else
283 if (getuid() == 0) new EntropyManager(server, entropyFile);
284 # endif
285
286 // create a token-cache interface
287 #if !defined(NDEBUG)
288 if (const char *s = getenv("TOKENCACHE"))
289 tokenCacheDir = s;
290 #endif //NDEBUG
291
292 // create a smartcard monitor to manage external token devices
293 gPCSC = new PCSCMonitor(server, tokenCacheDir, scOptions(smartCardOptions));
294
295 // create the RootSession object (if -d, give it graphics and tty attributes)
296 RootSession rootSession(server,
297 debugMode ? (sessionHasGraphicAccess | sessionHasTTY) : 0);
298
299 // install MDS and initialize the local CSSM
300 server.loadCssm();
301
302 // create the shared memory notification hub
303 new SharedMemoryListener(messagingName, kSharedMemoryPoolSize);
304
305 // okay, we're ready to roll
306 Syslog::notice("Entering service");
307 secdebug("SS", "%s initialized", bootstrapName);
308 Debug::trace (kSecTraceSecurityServerInitialized);
309
310 #ifdef PERFORMANCE_MEASUREMENT
311 // needed for automated timing of securityd startup
312 uint64_t endTime = mach_absolute_time ();
313
314 // compute how long it took to initialize
315 uint64_t elapsedTime = endTime - startTime;
316 mach_timebase_info_data_t multiplier;
317 mach_timebase_info (&multiplier);
318
319 elapsedTime = elapsedTime * multiplier.numer / multiplier.denom;
320
321 FILE* f = fopen ("/var/log/startuptime.txt", "a");
322 if (f == NULL)
323 {
324 // probably not running as root.
325 f = fopen ("/tmp/startuptime.txt", "a");
326 }
327
328 fprintf (f, "%lld\n", elapsedTime);
329 fclose (f);
330 #endif
331
332 // go
333 server.run();
334
335 // fell out of runloop (should not happen)
336 Syslog::alert("Aborting");
337 return 1;
338 }
339
340
341 //
342 // Issue usage message and die
343 //
344 static void usage(const char *me)
345 {
346 fprintf(stderr, "Usage: %s [-dwX]"
347 "\n\t[-a authConfigFile] Authorization configuration file"
348 "\n\t[-c tokencache] smartcard token cache directory"
349 "\n\t[-e equivDatabase] path to code equivalence database"
350 "\n\t[-N serviceName] MACH service name"
351 "\n\t[-s off|on|conservative|aggressive] smartcard operation level"
352 "\n\t[-t maxthreads] [-T threadTimeout] server thread control"
353 "\n", me);
354 exit(2);
355 }
356
357
358 //
359 // Translate strings (e.g. "conservative") into PCSCMonitor service levels
360 //
361 static PCSCMonitor::ServiceLevel scOptions(const char *optionString)
362 {
363 if (optionString)
364 if (!strcmp(optionString, "off"))
365 return PCSCMonitor::forcedOff;
366 else if (!strcmp(optionString, "on"))
367 return PCSCMonitor::forcedOn;
368 else if (!strcmp(optionString, "conservative"))
369 return PCSCMonitor::conservative;
370 else if (!strcmp(optionString, "aggressive"))
371 return PCSCMonitor::aggressive;
372 else if (!strcmp(optionString, "external"))
373 return PCSCMonitor::externalDaemon;
374 else
375 usage("securityd");
376 else
377 return PCSCMonitor::aggressive;
378 }
379
380
381 //
382 // Handle signals.
383 // We send ourselves a message (through the "self" service), so actual
384 // actions happen on the normal event loop path. Note that another thread
385 // may be picking up the message immediately.
386 //
387 static void handleSignals(int sig)
388 {
389 if (kern_return_t rc = self_client_handleSignal(gMainServerPort, mach_task_self(), sig))
390 Syslog::error("self-send failed (mach error %d)", rc);
391 }