]> git.saurik.com Git - apple/security.git/blob - securityd/src/main.cpp
Security-59306.11.20.tar.gz
[apple/security.git] / securityd / src / main.cpp
1 /*
2 * Copyright (c) 2000-2009,2014 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 "session.h"
32 #include "notifications.h"
33 #include "pcscmonitor.h"
34 #include "auditevents.h"
35 #include "self.h"
36 #include "util.h"
37
38 #include <security_utilities/daemon.h>
39 #include <security_utilities/machserver.h>
40 #include <security_utilities/logging.h>
41
42 #include <Security/SecKeychainPriv.h>
43
44 #include <unistd.h>
45 #include <sys/types.h>
46 #include <signal.h>
47 #include <syslog.h>
48
49 // ACL subject types (their makers are instantiated here)
50 #include <security_cdsa_utilities/acl_any.h>
51 #include <security_cdsa_utilities/acl_password.h>
52 #include <security_cdsa_utilities/acl_prompted.h>
53 #include <security_cdsa_utilities/acl_protectedpw.h>
54 #include <security_cdsa_utilities/acl_threshold.h>
55 #include <security_cdsa_utilities/acl_codesigning.h>
56 #include <security_cdsa_utilities/acl_process.h>
57 #include <security_cdsa_utilities/acl_comment.h>
58 #include <security_cdsa_utilities/acl_preauth.h>
59 #include "acl_keychain.h"
60 #include "acl_partition.h"
61
62 #include <sandbox.h>
63
64 //
65 // Local functions of the main program driver
66 //
67 static void usage(const char *me) __attribute__((noreturn));
68 static void handleSignals(int sig);
69 static PCSCMonitor::ServiceLevel scOptions(const char *optionString);
70 static bool legacyTokensEnabled(void);
71
72 static Port gMainServerPort;
73 PCSCMonitor *gPCSC;
74
75
76 //
77 // Main driver
78 //
79 int main(int argc, char *argv[])
80 {
81 DisableLocalization();
82
83 // clear the umask - we know what we're doing
84 secnotice("SecServer", "starting umask was 0%o", ::umask(0));
85 ::umask(0);
86
87 // tell the keychain (client) layer to turn off the server interface
88 SecKeychainSetServerMode();
89
90 const char *params[] = {"LEGACY_TOKENS_ENABLED", legacyTokensEnabled() ? "YES" : "NO", NULL};
91 char* errorbuf = NULL;
92 if (sandbox_init_with_parameters("com.apple.securityd", SANDBOX_NAMED, params, &errorbuf)) {
93 seccritical("SecServer: unable to enter sandbox: %{public}s", errorbuf);
94 if (errorbuf) {
95 sandbox_free_error(errorbuf);
96 }
97 exit(1);
98 } else {
99 secnotice("SecServer", "entered sandbox");
100 }
101
102 // program arguments (preset to defaults)
103 bool debugMode = false;
104 const char *bootstrapName = NULL;
105 const char* messagingName = SharedMemoryCommon::kDefaultSecurityMessagesName;
106 bool doFork = false;
107 bool reExecute = false;
108 int workerTimeout = 0;
109 int maxThreads = 0;
110 bool waitForClients = true;
111 bool mdsIsInstalled = false;
112 const char *tokenCacheDir = "/var/db/TokenCache";
113 const char *smartCardOptions = getenv("SMARTCARDS");
114 uint32_t keychainAclDefault = CSSM_ACL_KEYCHAIN_PROMPT_INVALID | CSSM_ACL_KEYCHAIN_PROMPT_UNSIGNED;
115 unsigned int verbose = 0;
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 secnotice("SecServer", "starting in installmode");
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, "c:dE:imN:s:t:T:uvWX")) != -1) {
128 switch (arg) {
129 case 'c':
130 tokenCacheDir = optarg;
131 break;
132 case 'd':
133 debugMode = true;
134 break;
135 case 'E':
136 /* was entropyFile, kept to preserve ABI */
137 break;
138 case 'i':
139 keychainAclDefault &= ~CSSM_ACL_KEYCHAIN_PROMPT_INVALID;
140 break;
141 case 'm':
142 mdsIsInstalled = true;
143 break;
144 case 'N':
145 bootstrapName = optarg;
146 break;
147 case 's':
148 smartCardOptions = optarg;
149 break;
150 case 't':
151 if ((maxThreads = atoi(optarg)) < 0)
152 maxThreads = 0;
153 break;
154 case 'T':
155 if ((workerTimeout = atoi(optarg)) < 0)
156 workerTimeout = 0;
157 break;
158 case 'W':
159 waitForClients = false;
160 break;
161 case 'u':
162 keychainAclDefault &= ~CSSM_ACL_KEYCHAIN_PROMPT_UNSIGNED;
163 break;
164 case 'v':
165 verbose++;
166 break;
167 case 'X':
168 doFork = true;
169 reExecute = true;
170 break;
171 default:
172 usage(argv[0]);
173 }
174 }
175
176 // take no non-option arguments
177 if (optind < argc)
178 usage(argv[0]);
179
180 // figure out the bootstrap name
181 if (!bootstrapName) {
182 bootstrapName = getenv(SECURITYSERVER_BOOTSTRAP_ENV);
183 if (!bootstrapName)
184 {
185 bootstrapName = SECURITYSERVER_BOOTSTRAP_NAME;
186 }
187 else
188 {
189 #ifndef __clang_analyzer__
190 messagingName = bootstrapName;
191 #endif
192 }
193 }
194 else
195 {
196 #ifndef __clang_analyzer__
197 messagingName = bootstrapName;
198 #endif
199 }
200
201 // configure logging first
202 if (debugMode) {
203 Syslog::open(bootstrapName, LOG_AUTHPRIV, LOG_PERROR);
204 Syslog::notice("%s started in debug mode", argv[0]);
205 } else {
206 Syslog::open(bootstrapName, LOG_AUTHPRIV, LOG_CONS);
207 }
208
209 // if we're not running as root in production mode, fail
210 // in debug mode, issue a warning
211 if (uid_t uid = getuid()) {
212 #if defined(NDEBUG)
213 Syslog::alert("Tried to run securityd as user %d: aborted", uid);
214 fprintf(stderr, "You are not allowed to run securityd\n");
215 exit(1);
216 #else
217 fprintf(stderr, "securityd is unprivileged (uid=%d); some features may not work.\n", 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 || signal(SIGINT, handleSignals) == SIG_ERR
233 || signal(SIGTERM, handleSignals) == SIG_ERR
234 || signal(SIGPIPE, handleSignals) == SIG_ERR
235 #if !defined(NDEBUG)
236 || signal(SIGUSR1, handleSignals) == SIG_ERR
237 #endif //NDEBUG
238 || signal(SIGUSR2, handleSignals) == SIG_ERR) {
239 perror("signal");
240 exit(1);
241 }
242
243 // The clang static analyzer isn't a big fan of our "object creation hooks object into global pointer graph" model.
244 // Tell it not to worry.
245 #ifndef __clang_analyzer__
246 // introduce all supported ACL subject types
247 new AnyAclSubject::Maker();
248 new PasswordAclSubject::Maker();
249 new ProtectedPasswordAclSubject::Maker();
250 new PromptedAclSubject::Maker();
251 new ThresholdAclSubject::Maker();
252 new CommentAclSubject::Maker();
253 new ProcessAclSubject::Maker();
254 new CodeSignatureAclSubject::Maker();
255 new KeychainPromptAclSubject::Maker(keychainAclDefault);
256 new PartitionAclSubject::Maker();
257 new PreAuthorizationAcls::OriginMaker();
258 new PreAuthorizationAcls::SourceMaker();
259 #endif
260 // establish the code equivalents database
261 CodeSignatures codeSignatures;
262
263
264 // create the main server object and register it
265 Server server(codeSignatures, bootstrapName);
266
267 // Remember the primary service port to send signal events to
268 gMainServerPort = server.primaryServicePort();
269
270 // set server configuration from arguments, if specified
271 if (workerTimeout)
272 server.timeout(workerTimeout);
273 if (maxThreads)
274 server.maxThreads(maxThreads);
275 server.floatingThread(true);
276 server.waitForClients(waitForClients);
277 server.verbosity(verbose);
278
279 // create a smartcard monitor to manage external token devices
280 gPCSC = new PCSCMonitor(server, tokenCacheDir, scOptions(smartCardOptions));
281
282 // create the RootSession object (if -d, give it graphics and tty attributes)
283 RootSession rootSession(debugMode ? (sessionHasGraphicAccess | sessionHasTTY) : 0, server);
284
285 // create a monitor thread to watch for audit session events
286 AuditMonitor audits(gMainServerPort);
287 audits.run();
288
289 // install MDS (if needed) and initialize the local CSSM
290 server.loadCssm(mdsIsInstalled);
291
292 #ifndef __clang_analyzer__
293 // create the shared memory notification hub
294 new SharedMemoryListener(messagingName, kSharedMemoryPoolSize);
295 #endif
296
297
298 // okay, we're ready to roll
299 secnotice("SecServer", "Entering service as %s", (char*)bootstrapName);
300 Syslog::notice("Entering service");
301
302 // go
303 server.run();
304
305 // fell out of runloop (should not happen)
306 Syslog::alert("Aborting");
307 return 1;
308 }
309
310
311 //
312 // Issue usage message and die
313 //
314 static void usage(const char *me)
315 {
316 fprintf(stderr, "Usage: %s [-dwX]"
317 "\n\t[-c tokencache] smartcard token cache directory"
318 "\n\t[-e equivDatabase] path to code equivalence database"
319 "\n\t[-N serviceName] MACH service name"
320 "\n\t[-s off|on|conservative|aggressive] smartcard operation level"
321 "\n\t[-t maxthreads] [-T threadTimeout] server thread control"
322 "\n", me);
323 exit(2);
324 }
325
326 const CFStringRef kTKSmartCardPreferencesDomain = CFSTR("com.apple.security.smartcard");
327 const CFStringRef kTKLegacyTokendPreferencesKey = CFSTR("Legacy");
328
329 static bool legacyTokensEnabled() {
330 bool result = false;
331 CFPropertyListRef value = CFPreferencesCopyValue(kTKLegacyTokendPreferencesKey, kTKSmartCardPreferencesDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
332 if (value) {
333 if (CFEqual(value, kCFBooleanTrue)) {
334 result = true;
335 }
336 CFRelease(value);
337 }
338 return result;
339 }
340
341 //
342 // Translate strings (e.g. "conservative") into PCSCMonitor service levels
343 //
344 static PCSCMonitor::ServiceLevel scOptions(const char *optionString)
345 {
346 if (!legacyTokensEnabled())
347 return PCSCMonitor::forcedOff;
348
349 if (optionString)
350 if (!strcmp(optionString, "off"))
351 return PCSCMonitor::forcedOff;
352 else if (!strcmp(optionString, "on"))
353 return PCSCMonitor::externalDaemon;
354 else if (!strcmp(optionString, "conservative"))
355 return PCSCMonitor::externalDaemon;
356 else if (!strcmp(optionString, "aggressive"))
357 return PCSCMonitor::externalDaemon;
358 else if (!strcmp(optionString, "external"))
359 return PCSCMonitor::externalDaemon;
360 else
361 usage("securityd");
362 else
363 return PCSCMonitor::externalDaemon;
364 }
365
366
367 //
368 // Handle signals.
369 // We send ourselves a message (through the "self" service), so actual
370 // actions happen on the normal event loop path. Note that another thread
371 // may be picking up the message immediately.
372 //
373 static void handleSignals(int sig)
374 {
375 (void)self_client_handleSignal(gMainServerPort, mach_task_self(), sig);
376 }