]> git.saurik.com Git - apple/securityd.git/blob - src/main.cpp
securityd-32661.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
80
81 //
82 // Main driver
83 //
84 int main(int argc, char *argv[])
85 {
86 #ifdef PERFORMANCE_MEASUREMENT
87 // needed for automated timing of securityd startup
88 uint64_t startTime = mach_absolute_time ();
89 #endif
90
91 Debug::trace (kSecTraceSecurityServerStart);
92
93 // clear the umask - we know what we're doing
94 secdebug("SS", "starting umask was 0%o", ::umask(0));
95 ::umask(0);
96
97 // tell the keychain (client) layer to turn off the server interface
98 SecKeychainSetServerMode();
99
100 // program arguments (preset to defaults)
101 bool debugMode = false;
102 const char *bootstrapName = NULL;
103 const char* messagingName = SECURITY_MESSAGES_NAME;
104 bool doFork = false;
105 bool reExecute = false;
106 int workerTimeout = 0;
107 int maxThreads = 0;
108 bool waitForClients = false;
109 const char *authorizationConfig = "/etc/authorization";
110 const char *tokenCacheDir = "/var/db/TokenCache";
111 const char *entropyFile = "/var/db/SystemEntropyCache";
112 const char *equivDbFile = EQUIVALENCEDBPATH;
113 const char *smartCardOptions = getenv("SMARTCARDS");
114 uint32_t keychainAclDefault = CSSM_ACL_KEYCHAIN_PROMPT_INVALID | CSSM_ACL_KEYCHAIN_PROMPT_UNSIGNED;
115
116 // check for the Installation-DVD environment and modify some default arguments if found
117 if (access("/etc/rc.cdrom", F_OK) == 0) { // /etc/rc.cdrom exists
118 secdebug("SS", "configuring for installation");
119 smartCardOptions = "off"; // needs writable directories that aren't
120 }
121
122 // parse command line arguments
123 extern char *optarg;
124 extern int optind;
125 int arg;
126 while ((arg = getopt(argc, argv, "a:c:de:E:fiN:s:t:T:Xuw")) != -1) {
127 switch (arg) {
128 case 'a':
129 authorizationConfig = optarg;
130 break;
131 case 'c':
132 tokenCacheDir = optarg;
133 break;
134 case 'd':
135 debugMode = true;
136 break;
137 case 'e':
138 equivDbFile = optarg;
139 break;
140 case 'E':
141 entropyFile = optarg;
142 break;
143 case 'f':
144 fprintf(stderr, "%s: the -f option is obsolete\n", argv[0]);
145 break;
146 case 'i':
147 keychainAclDefault &= ~CSSM_ACL_KEYCHAIN_PROMPT_INVALID;
148 break;
149 case 'N':
150 bootstrapName = optarg;
151 break;
152 case 's':
153 smartCardOptions = optarg;
154 break;
155 case 't':
156 if ((maxThreads = atoi(optarg)) < 0)
157 maxThreads = 0;
158 break;
159 case 'T':
160 if ((workerTimeout = atoi(optarg)) < 0)
161 workerTimeout = 0;
162 break;
163 case 'w':
164 waitForClients = true;
165 break;
166 case 'u':
167 keychainAclDefault &= ~CSSM_ACL_KEYCHAIN_PROMPT_UNSIGNED;
168 break;
169 case 'X':
170 doFork = true;
171 reExecute = true;
172 break;
173 default:
174 usage(argv[0]);
175 }
176 }
177
178 // take no non-option arguments
179 if (optind < argc)
180 usage(argv[0]);
181
182 // figure out the bootstrap name
183 if (!bootstrapName) {
184 bootstrapName = getenv(SECURITYSERVER_BOOTSTRAP_ENV);
185 if (!bootstrapName)
186 {
187 bootstrapName = SECURITYSERVER_BOOTSTRAP_NAME;
188 }
189 else
190 {
191 messagingName = bootstrapName;
192 }
193 }
194 else
195 {
196 messagingName = bootstrapName;
197 }
198
199 // configure logging first
200 if (debugMode) {
201 Syslog::open(bootstrapName, LOG_AUTHPRIV, LOG_PERROR);
202 Syslog::notice("%s started in debug mode", argv[0]);
203 } else {
204 Syslog::open(bootstrapName, LOG_AUTHPRIV, LOG_CONS);
205 }
206
207 // if we're not running as root in production mode, fail
208 // in debug mode, issue a warning
209 if (uid_t uid = getuid()) {
210 #if defined(NDEBUG)
211 Syslog::alert("Tried to run securityd as user %d: aborted", uid);
212 fprintf(stderr, "You are not allowed to run securityd\n");
213 exit(1);
214 #else
215 fprintf(stderr, "securityd is unprivileged; some features may not work.\n");
216 secdebug("SS", "Running as user %d (you have been warned)", uid);
217 #endif //NDEBUG
218 }
219
220 // turn into a properly diabolical daemon unless debugMode is on
221 if (!debugMode && getppid() != 1) {
222 if (!Daemon::incarnate(doFork))
223 exit(1); // can't daemonize
224
225 if (reExecute && !Daemon::executeSelf(argv))
226 exit(1); // can't self-execute
227 }
228
229 // arm signal handlers; code below may generate signals we want to see
230 if (signal(SIGCHLD, handleSignals) == SIG_ERR)
231 secdebug("SS", "Cannot handle SIGCHLD: errno=%d", errno);
232 if (signal(SIGINT, handleSignals) == SIG_ERR)
233 secdebug("SS", "Cannot handle SIGINT: errno=%d", errno);
234 if (signal(SIGTERM, handleSignals) == SIG_ERR)
235 secdebug("SS", "Cannot handle SIGTERM: errno=%d", errno);
236 if (signal(SIGPIPE, handleSignals) == SIG_ERR)
237 secdebug("SS", "Cannot handle SIGPIPE: errno=%d", errno);
238 #if !defined(NDEBUG)
239 if (signal(SIGUSR1, handleSignals) == SIG_ERR)
240 secdebug("SS", "Cannot handle SIGHUP: errno=%d", errno);
241 #endif //NDEBUG
242
243 // create the shared memory notification hub
244 new SharedMemoryListener(messagingName, kSharedMemoryPoolSize);
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 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 // okay, we're ready to roll
303 Syslog::notice("Entering service");
304 secdebug("SS", "%s initialized", bootstrapName);
305 Debug::trace (kSecTraceSecurityServerInitialized);
306
307 #ifdef PERFORMANCE_MEASUREMENT
308 // needed for automated timing of securityd startup
309 uint64_t endTime = mach_absolute_time ();
310
311 // compute how long it took to initialize
312 uint64_t elapsedTime = endTime - startTime;
313 mach_timebase_info_data_t multiplier;
314 mach_timebase_info (&multiplier);
315
316 elapsedTime = elapsedTime * multiplier.numer / multiplier.denom;
317
318 FILE* f = fopen ("/var/log/startuptime.txt", "a");
319 if (f == NULL)
320 {
321 // probably not running as root.
322 f = fopen ("/tmp/startuptime.txt", "a");
323 }
324
325 fprintf (f, "%lld\n", elapsedTime);
326 fclose (f);
327 #endif
328
329 // go
330 server.run();
331
332 // fell out of runloop (should not happen)
333 Syslog::alert("Aborting");
334 return 1;
335 }
336
337
338 //
339 // Issue usage message and die
340 //
341 static void usage(const char *me)
342 {
343 fprintf(stderr, "Usage: %s [-dwX]"
344 "\n\t[-a authConfigFile] Authorization configuration file"
345 "\n\t[-c tokencache] smartcard token cache directory"
346 "\n\t[-e equivDatabase] path to code equivalence database"
347 "\n\t[-N serviceName] MACH service name"
348 "\n\t[-s off|on|conservative|aggressive] smartcard operation level"
349 "\n\t[-t maxthreads] [-T threadTimeout] server thread control"
350 "\n", me);
351 exit(2);
352 }
353
354
355 //
356 // Translate strings (e.g. "conservative") into PCSCMonitor service levels
357 //
358 static PCSCMonitor::ServiceLevel scOptions(const char *optionString)
359 {
360 if (optionString)
361 if (!strcmp(optionString, "off"))
362 return PCSCMonitor::forcedOff;
363 else if (!strcmp(optionString, "on"))
364 return PCSCMonitor::forcedOn;
365 else if (!strcmp(optionString, "conservative"))
366 return PCSCMonitor::conservative;
367 else if (!strcmp(optionString, "aggressive"))
368 return PCSCMonitor::aggressive;
369 else if (!strcmp(optionString, "external"))
370 return PCSCMonitor::externalDaemon;
371 else
372 usage("securityd");
373 else
374 return PCSCMonitor::aggressive;
375 }
376
377
378 //
379 // Handle signals.
380 // We send ourselves a message (through the "self" service), so actual
381 // actions happen on the normal event loop path. Note that another thread
382 // may be picking up the message immediately.
383 //
384 static void handleSignals(int sig)
385 {
386 if (kern_return_t rc = self_client_handleSignal(gMainServerPort, mach_task_self(), sig))
387 Syslog::error("self-send failed (mach error %d)", rc);
388 }