]> git.saurik.com Git - apple/securityd.git/blob - src/main.cpp
d765ec855887ac03e0b1a32ff38e4084d130f60b
[apple/securityd.git] / src / main.cpp
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25
26
27 //
28 // securityd - Apple security services daemon.
29 //
30 #include <securityd_client/ucsp.h>
31
32 #include "securityserver.h"
33 #include "server.h"
34 #include "entropy.h"
35
36 #include <security_utilities/daemon.h>
37 #include <security_cdsa_client/osxsigner.h>
38 #include "authority.h"
39 #include "session.h"
40 #include "pcscmonitor.h"
41
42 #include <unistd.h>
43 #include <security_utilities/machserver.h>
44
45 #include <sys/types.h>
46 #include <signal.h>
47
48 #include <security_utilities/ktracecodes.h>
49
50 // #define PERFORMANCE_MEASUREMENT 1
51
52 #ifdef PERFORMANCE_MEASUREMENT
53 #include <mach/mach_time.h>
54 #endif
55
56 // ACL subject types (their makers are instantiated here)
57 #include <security_cdsa_utilities/acl_any.h>
58 #include <security_cdsa_utilities/acl_password.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 <syslog.h>
65 #include "acl_keychain.h"
66
67
68 namespace Security
69 {
70
71 //
72 // Program options (set by argument scan and environment)
73 //
74 uint32 debugMode = 0;
75 const char *bootstrapName = NULL;
76
77 } // end namespace Security
78
79
80 //
81 // Local functions of the main program driver
82 //
83 static void usage(const char *me);
84 static void handleSIGCHLD(int);
85 static void handleSIGOther(int);
86 IFDEBUG(static void handleSIGdebug(int));
87
88 static Port gMainServerPort;
89
90 //
91 // Main driver
92 //
93 int main(int argc, char *argv[])
94 {
95 #ifdef PERFORMANCE_MEASUREMENT
96 // needed for automated timing of securityd startup
97 uint64_t startTime = mach_absolute_time ();
98 #endif
99
100 Debug::trace (kSecTraceSecurityServerStart);
101
102 // program arguments (preset to defaults)
103 bool doFork = false;
104 bool forceCssmInit = false;
105 bool reExecute = false;
106 int workerTimeout = 0;
107 int maxThreads = 0;
108 const char *authorizationConfig = "/etc/authorization";
109 const char *entropyFile = "/var/db/SystemEntropyCache";
110 const char *equivDbFile = EQUIVALENCEDBPATH;
111
112 // parse command line arguments
113 extern char *optarg;
114 extern int optind;
115 int arg;
116 while ((arg = getopt(argc, argv, "a:de:E:fN:t:T:X")) != -1) {
117 switch (arg) {
118 case 'a':
119 authorizationConfig = optarg;
120 break;
121 case 'd':
122 debugMode++;
123 break;
124 case 'e':
125 equivDbFile = optarg;
126 break;
127 case 'E':
128 entropyFile = optarg;
129 break;
130 case 'f':
131 forceCssmInit = true;
132 break;
133 case 'N':
134 bootstrapName = optarg;
135 break;
136 case 't':
137 if ((maxThreads = atoi(optarg)) < 0)
138 maxThreads = 0;
139 break;
140 case 'T':
141 if ((workerTimeout = atoi(optarg)) < 0)
142 workerTimeout = 0;
143 break;
144 case 'X':
145 doFork = true;
146 reExecute = true;
147 break;
148 default:
149 usage(argv[0]);
150 }
151 }
152
153 // take no non-option arguments
154 if (optind < argc)
155 usage(argv[0]);
156
157 // figure out the bootstrap name
158 IFDEBUG(if (!bootstrapName) bootstrapName = getenv(SECURITYSERVER_BOOTSTRAP_ENV));
159
160 if (!bootstrapName) {
161 bootstrapName = SECURITYSERVER_BOOTSTRAP_NAME;
162 }
163
164 // configure logging first
165 if (debugMode) {
166 Syslog::open(bootstrapName, LOG_AUTHPRIV, LOG_PERROR);
167 Syslog::notice("SecurityServer started in debug mode");
168 } else {
169 Syslog::open(bootstrapName, LOG_AUTHPRIV, LOG_CONS);
170 }
171
172 // if we're not running as root in production mode, fail
173 // in debug mode, issue a warning
174 if (uid_t uid = getuid()) {
175 #if defined(NDEBUG)
176 Syslog::alert("Tried to run securityd as user %d: aborted", uid);
177 fprintf(stderr, "You are not allowed to run securityd\n");
178 exit(1);
179 #else
180 fprintf(stderr, "securityd is unprivileged; some features may not work.\n");
181 secdebug("SS", "Running as user %d (you have been warned)", uid);
182 #endif //NDEBUG
183 }
184
185 // turn into a properly diabolical daemon unless debugMode is on
186 if (!debugMode) {
187 if (!Daemon::incarnate(doFork))
188 exit(1); // can't daemonize
189
190 if (reExecute && !Daemon::executeSelf(argv))
191 exit(1); // can't self-execute
192 }
193
194 // create a code signing engine
195 CodeSigning::OSXSigner signer;
196
197 // create an Authorization engine
198 Authority authority(authorizationConfig);
199
200 // establish the ACL machinery
201 new AnyAclSubject::Maker();
202 new PasswordAclSubject::Maker();
203 new ProtectedPasswordAclSubject::Maker();
204 new ThresholdAclSubject::Maker();
205 new CommentAclSubject::Maker();
206 new ProcessAclSubject::Maker();
207 new CodeSignatureAclSubject::Maker(signer);
208 new KeychainPromptAclSubject::Maker();
209
210 // add a temporary registration for a subject type that went out in 10.2 seed 1
211 // this should probably be removed for the next major release >10.2
212 new KeychainPromptAclSubject::Maker(CSSM_WORDID__RESERVED_1);
213
214 // establish the code equivalents database
215 CodeSignatures codeSignatures(equivDbFile);
216
217 // create the main server object and register it
218 Server server(authority, codeSignatures, bootstrapName);
219
220 // Remember the primary service port to send signal events to.
221 gMainServerPort = server.primaryServicePort();
222
223 // set server configuration from arguments, if specified
224 if (workerTimeout)
225 server.timeout(workerTimeout);
226 if (maxThreads)
227 server.maxThreads(maxThreads);
228
229 // add the RNG seed timer to it
230 # if defined(NDEBUG)
231 EntropyManager entropy(server, entropyFile);
232 # else
233 if (!getuid()) new EntropyManager(server, entropyFile);
234 # endif
235
236 // create smartcard monitors to manage external token devices
237 PCSCMonitor secureCards(server);
238
239 // create the RootSession object (if -d, give it graphics and tty attributes)
240 RootSession rootSession(server.primaryServicePort(),
241 debugMode ? (sessionHasGraphicAccess | sessionHasTTY) : 0);
242
243 // set up signal handlers
244 if (signal(SIGCHLD, handleSIGCHLD) == SIG_ERR)
245 secdebug("SS", "Cannot handle SIGCHLD: errno=%d", errno);
246 if (signal(SIGINT, handleSIGOther) == SIG_ERR)
247 secdebug("SS", "Cannot handle SIGINT: errno=%d", errno);
248 if (signal(SIGTERM, handleSIGOther) == SIG_ERR)
249 secdebug("SS", "Cannot handle SIGTERM: errno=%d", errno);
250 #if !defined(NDEBUG)
251 if (signal(SIGUSR1, handleSIGdebug) == SIG_ERR)
252 secdebug("SS", "Cannot handle SIGHUP: errno=%d", errno);
253 #endif //NDEBUG
254
255 // initialize CSSM now if requested
256 if (forceCssmInit)
257 server.loadCssm();
258
259 Syslog::notice("Entering service");
260 secdebug("SS", "%s initialized", bootstrapName);
261
262 Debug::trace (kSecTraceSecurityServerInitialized);
263
264 #ifdef PERFORMANCE_MEASUREMENT
265 // needed for automated timing of securityd startup
266 uint64_t endTime = mach_absolute_time ();
267
268 // compute how long it took to initialize
269 uint64_t elapsedTime = endTime - startTime;
270 mach_timebase_info_data_t multiplier;
271 mach_timebase_info (&multiplier);
272
273 elapsedTime = elapsedTime * multiplier.numer / multiplier.denom;
274
275 FILE* f = fopen ("/var/log/startuptime.txt", "a");
276 if (f == NULL)
277 {
278 // probably not running as root.
279 f = fopen ("/tmp/startuptime.txt", "a");
280 }
281
282 fprintf (f, "%lld\n", elapsedTime);
283 fclose (f);
284 #endif
285
286 server.run();
287
288 // fell out of runloop (should not happen)
289 Syslog::alert("Aborting");
290 return 1;
291 }
292
293
294 //
295 // Issue usage message and die
296 //
297 static void usage(const char *me)
298 {
299 fprintf(stderr, "Usage: %s [-df] [-t maxthreads] [-T threadTimeout]"
300 "\t[-N bootstrapName] [-a authConfigFile]\n", me);
301 exit(2);
302 }
303
304
305 //
306 // Handle SIGCHLD signals to reap our children (zombie cleanup)
307 //
308 static void handleSIGCHLD(int signal_number)
309 {
310 kern_return_t kt = ucsp_client_handleSignal(gMainServerPort, mach_task_self(), signal_number);
311 if (kt)
312 syslog(LOG_ERR, "ucsp_client_handleSignal returned: %d", kt);
313 }
314
315
316 //
317 // Handle some other signals to shut down cleanly (and with logging)
318 //
319 static void handleSIGOther(int sig)
320 {
321 switch (sig) {
322 case SIGINT:
323 //secdebug("SS", "Interrupt signal; terminating");
324 Syslog::notice("received interrupt signal; terminating");
325 exit(0);
326 case SIGTERM:
327 //secdebug("SS", "Termination signal; terminating");
328 Syslog::notice("received termination signal; terminating");
329 exit(0);
330 }
331 }
332
333
334 #if !defined(NDEBUG)
335
336 static void handleSIGdebug(int)
337 {
338 NodeCore::dumpAll();
339 }
340
341 #endif //NDEBUG