]> git.saurik.com Git - apple/security.git/blob - securityd/src/main.cpp
Security-59306.140.5.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 bool doFork = false;
105 bool reExecute = false;
106 int workerTimeout = 0;
107 int maxThreads = 0;
108 bool waitForClients = true;
109 bool mdsIsInstalled = false;
110 const char *tokenCacheDir = "/var/db/TokenCache";
111 const char *smartCardOptions = getenv("SMARTCARDS");
112 uint32_t keychainAclDefault = CSSM_ACL_KEYCHAIN_PROMPT_INVALID | CSSM_ACL_KEYCHAIN_PROMPT_UNSIGNED;
113 unsigned int verbose = 0;
114
115 // check for the Installation-DVD environment and modify some default arguments if found
116 if (access("/etc/rc.cdrom", F_OK) == 0) { // /etc/rc.cdrom exists
117 secnotice("SecServer", "starting in installmode");
118 smartCardOptions = "off"; // needs writable directories that aren't
119 }
120
121 // parse command line arguments
122 extern char *optarg;
123 extern int optind;
124 int arg;
125 while ((arg = getopt(argc, argv, "c:dE:ims:t:T:uvWX")) != -1) {
126 switch (arg) {
127 case 'c':
128 tokenCacheDir = optarg;
129 break;
130 case 'd':
131 debugMode = true;
132 break;
133 case 'E':
134 /* was entropyFile, kept to preserve ABI */
135 break;
136 case 'i':
137 keychainAclDefault &= ~CSSM_ACL_KEYCHAIN_PROMPT_INVALID;
138 break;
139 case 'm':
140 mdsIsInstalled = true;
141 break;
142 case 's':
143 smartCardOptions = optarg;
144 break;
145 case 't':
146 if ((maxThreads = atoi(optarg)) < 0)
147 maxThreads = 0;
148 break;
149 case 'T':
150 if ((workerTimeout = atoi(optarg)) < 0)
151 workerTimeout = 0;
152 break;
153 case 'W':
154 waitForClients = false;
155 break;
156 case 'u':
157 keychainAclDefault &= ~CSSM_ACL_KEYCHAIN_PROMPT_UNSIGNED;
158 break;
159 case 'v':
160 verbose++;
161 break;
162 case 'X':
163 doFork = true;
164 reExecute = true;
165 break;
166 default:
167 usage(argv[0]);
168 }
169 }
170
171 // take no non-option arguments
172 if (optind < argc) {
173 usage(argv[0]);
174 }
175
176 const char *bootstrapName = SECURITYSERVER_BOOTSTRAP_NAME;
177 const char* messagingName = SharedMemoryCommon::kDefaultSecurityMessagesName;
178
179 // configure logging first
180 if (debugMode) {
181 Syslog::open(bootstrapName, LOG_AUTHPRIV, LOG_PERROR);
182 Syslog::notice("%s started in debug mode", argv[0]);
183 } else {
184 Syslog::open(bootstrapName, LOG_AUTHPRIV, LOG_CONS);
185 }
186
187 // if we're not running as root in production mode, fail
188 // in debug mode, issue a warning
189 if (uid_t uid = getuid()) {
190 #if defined(NDEBUG)
191 Syslog::alert("Tried to run securityd as user %d: aborted", uid);
192 fprintf(stderr, "You are not allowed to run securityd\n");
193 exit(1);
194 #else
195 fprintf(stderr, "securityd is unprivileged (uid=%d); some features may not work.\n", uid);
196 #endif //NDEBUG
197 }
198
199 // turn into a properly diabolical daemon unless debugMode is on
200 if (!debugMode && getppid() != 1) {
201 if (!Daemon::incarnate(doFork))
202 exit(1); // can't daemonize
203
204 if (reExecute && !Daemon::executeSelf(argv))
205 exit(1); // can't self-execute
206 }
207
208 // arm signal handlers; code below may generate signals we want to see
209 if (signal(SIGCHLD, handleSignals) == SIG_ERR
210 || signal(SIGINT, handleSignals) == SIG_ERR
211 || signal(SIGTERM, handleSignals) == SIG_ERR
212 || signal(SIGPIPE, handleSignals) == SIG_ERR
213 #if !defined(NDEBUG)
214 || signal(SIGUSR1, handleSignals) == SIG_ERR
215 #endif //NDEBUG
216 || signal(SIGUSR2, handleSignals) == SIG_ERR) {
217 perror("signal");
218 exit(1);
219 }
220
221 // The clang static analyzer isn't a big fan of our "object creation hooks object into global pointer graph" model.
222 // Tell it not to worry.
223 #ifndef __clang_analyzer__
224 // introduce all supported ACL subject types
225 new AnyAclSubject::Maker();
226 new PasswordAclSubject::Maker();
227 new ProtectedPasswordAclSubject::Maker();
228 new PromptedAclSubject::Maker();
229 new ThresholdAclSubject::Maker();
230 new CommentAclSubject::Maker();
231 new ProcessAclSubject::Maker();
232 new CodeSignatureAclSubject::Maker();
233 new KeychainPromptAclSubject::Maker(keychainAclDefault);
234 new PartitionAclSubject::Maker();
235 new PreAuthorizationAcls::OriginMaker();
236 new PreAuthorizationAcls::SourceMaker();
237 #endif
238 // establish the code equivalents database
239 CodeSignatures codeSignatures;
240
241
242 // create the main server object and register it
243 Server server(codeSignatures, bootstrapName);
244
245 // Remember the primary service port to send signal events to
246 gMainServerPort = server.primaryServicePort();
247
248 // set server configuration from arguments, if specified
249 if (workerTimeout)
250 server.timeout(workerTimeout);
251 if (maxThreads)
252 server.maxThreads(maxThreads);
253 server.floatingThread(true);
254 server.waitForClients(waitForClients);
255 server.verbosity(verbose);
256
257 // create a smartcard monitor to manage external token devices
258 gPCSC = new PCSCMonitor(server, tokenCacheDir, scOptions(smartCardOptions));
259
260 // create the RootSession object (if -d, give it graphics and tty attributes)
261 RootSession rootSession(debugMode ? (sessionHasGraphicAccess | sessionHasTTY) : 0, server);
262
263 // create a monitor thread to watch for audit session events
264 AuditMonitor audits(gMainServerPort);
265 audits.run();
266
267 // install MDS (if needed) and initialize the local CSSM
268 server.loadCssm(mdsIsInstalled);
269
270 #ifndef __clang_analyzer__
271 // create the shared memory notification hub
272 new SharedMemoryListener(messagingName, kSharedMemoryPoolSize);
273 #endif
274
275
276 // okay, we're ready to roll
277 secnotice("SecServer", "Entering service as %s", (char*)bootstrapName);
278 Syslog::notice("Entering service");
279
280 // go
281 server.run();
282
283 // fell out of runloop (should not happen)
284 Syslog::alert("Aborting");
285 return 1;
286 }
287
288
289 //
290 // Issue usage message and die
291 //
292 static void usage(const char *me)
293 {
294 fprintf(stderr, "Usage: %s [-dwX]"
295 "\n\t[-c tokencache] smartcard token cache directory"
296 "\n\t[-e equivDatabase] path to code equivalence database"
297 "\n\t[-s off|on|conservative|aggressive] smartcard operation level"
298 "\n\t[-t maxthreads] [-T threadTimeout] server thread control"
299 "\n", me);
300 exit(2);
301 }
302
303 const CFStringRef kTKSmartCardPreferencesDomain = CFSTR("com.apple.security.smartcard");
304 const CFStringRef kTKLegacyTokendPreferencesKey = CFSTR("Legacy");
305
306 static bool legacyTokensEnabled() {
307 bool result = false;
308 CFPropertyListRef value = CFPreferencesCopyValue(kTKLegacyTokendPreferencesKey, kTKSmartCardPreferencesDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
309 if (value) {
310 if (CFEqual(value, kCFBooleanTrue)) {
311 result = true;
312 }
313 CFRelease(value);
314 }
315 return result;
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 (!legacyTokensEnabled())
324 return PCSCMonitor::forcedOff;
325
326 if (optionString)
327 if (!strcmp(optionString, "off"))
328 return PCSCMonitor::forcedOff;
329 else if (!strcmp(optionString, "on"))
330 return PCSCMonitor::externalDaemon;
331 else if (!strcmp(optionString, "conservative"))
332 return PCSCMonitor::externalDaemon;
333 else if (!strcmp(optionString, "aggressive"))
334 return PCSCMonitor::externalDaemon;
335 else if (!strcmp(optionString, "external"))
336 return PCSCMonitor::externalDaemon;
337 else
338 usage("securityd");
339 else
340 return PCSCMonitor::externalDaemon;
341 }
342
343
344 //
345 // Handle signals.
346 // We send ourselves a message (through the "self" service), so actual
347 // actions happen on the normal event loop path. Note that another thread
348 // may be picking up the message immediately.
349 //
350 static void handleSignals(int sig)
351 {
352 (void)self_client_handleSignal(gMainServerPort, mach_task_self(), sig);
353 }