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