]> git.saurik.com Git - apple/security.git/blob - securityd/src/main.cpp
Security-57337.40.85.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 "entropy.h"
32 #include "authority.h"
33 #include "session.h"
34 #include "notifications.h"
35 #include "pcscmonitor.h"
36 #include "auditevents.h"
37 #include "self.h"
38
39 #include <security_utilities/daemon.h>
40 #include <security_utilities/machserver.h>
41 #include <security_utilities/logging.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 // ACL subject types (their makers are instantiated here)
51 #include <security_cdsa_utilities/acl_any.h>
52 #include <security_cdsa_utilities/acl_password.h>
53 #include <security_cdsa_utilities/acl_prompted.h>
54 #include <security_cdsa_utilities/acl_protectedpw.h>
55 #include <security_cdsa_utilities/acl_threshold.h>
56 #include <security_cdsa_utilities/acl_codesigning.h>
57 #include <security_cdsa_utilities/acl_process.h>
58 #include <security_cdsa_utilities/acl_comment.h>
59 #include <security_cdsa_utilities/acl_preauth.h>
60 #include "acl_keychain.h"
61 #include "acl_partition.h"
62
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
71
72 static Port gMainServerPort;
73 PCSCMonitor *gPCSC;
74
75
76 //
77 // Main driver
78 //
79 int main(int argc, char *argv[])
80 {
81 // clear the umask - we know what we're doing
82 secdebug("SS", "starting umask was 0%o", ::umask(0));
83 ::umask(0);
84
85 // tell the keychain (client) layer to turn off the server interface
86 SecKeychainSetServerMode();
87
88 // program arguments (preset to defaults)
89 bool debugMode = false;
90 const char *bootstrapName = NULL;
91 const char* messagingName = SECURITY_MESSAGES_NAME;
92 bool doFork = false;
93 bool reExecute = false;
94 int workerTimeout = 0;
95 int maxThreads = 0;
96 bool waitForClients = true;
97 bool mdsIsInstalled = false;
98 const char *authorizationConfig = "/etc/authorization";
99 const char *tokenCacheDir = "/var/db/TokenCache";
100 const char *entropyFile = "/var/db/SystemEntropyCache";
101 const char *smartCardOptions = getenv("SMARTCARDS");
102 uint32_t keychainAclDefault = CSSM_ACL_KEYCHAIN_PROMPT_INVALID | CSSM_ACL_KEYCHAIN_PROMPT_UNSIGNED;
103 unsigned int verbose = 0;
104
105 // check for the Installation-DVD environment and modify some default arguments if found
106 if (access("/etc/rc.cdrom", F_OK) == 0) { // /etc/rc.cdrom exists
107 SECURITYD_INSTALLMODE();
108 smartCardOptions = "off"; // needs writable directories that aren't
109 }
110
111 // parse command line arguments
112 extern char *optarg;
113 extern int optind;
114 int arg;
115 while ((arg = getopt(argc, argv, "a:c:dE:imN:s:t:T:uvWX")) != -1) {
116 switch (arg) {
117 case 'a':
118 authorizationConfig = optarg;
119 break;
120 case 'c':
121 tokenCacheDir = optarg;
122 break;
123 case 'd':
124 debugMode = true;
125 break;
126 case 'E':
127 entropyFile = optarg;
128 break;
129 case 'i':
130 keychainAclDefault &= ~CSSM_ACL_KEYCHAIN_PROMPT_INVALID;
131 break;
132 case 'm':
133 mdsIsInstalled = true;
134 break;
135 case 'N':
136 bootstrapName = optarg;
137 break;
138 case 's':
139 smartCardOptions = optarg;
140 break;
141 case 't':
142 if ((maxThreads = atoi(optarg)) < 0)
143 maxThreads = 0;
144 break;
145 case 'T':
146 if ((workerTimeout = atoi(optarg)) < 0)
147 workerTimeout = 0;
148 break;
149 case 'W':
150 waitForClients = false;
151 break;
152 case 'u':
153 keychainAclDefault &= ~CSSM_ACL_KEYCHAIN_PROMPT_UNSIGNED;
154 break;
155 case 'v':
156 verbose++;
157 break;
158 case 'X':
159 doFork = true;
160 reExecute = true;
161 break;
162 default:
163 usage(argv[0]);
164 }
165 }
166
167 // take no non-option arguments
168 if (optind < argc)
169 usage(argv[0]);
170
171 // figure out the bootstrap name
172 if (!bootstrapName) {
173 bootstrapName = getenv(SECURITYSERVER_BOOTSTRAP_ENV);
174 if (!bootstrapName)
175 {
176 bootstrapName = SECURITYSERVER_BOOTSTRAP_NAME;
177 }
178 else
179 {
180 messagingName = bootstrapName;
181 }
182 }
183 else
184 {
185 messagingName = bootstrapName;
186 }
187
188 // configure logging first
189 if (debugMode) {
190 Syslog::open(bootstrapName, LOG_AUTHPRIV, LOG_PERROR);
191 Syslog::notice("%s started in debug mode", argv[0]);
192 } else {
193 Syslog::open(bootstrapName, LOG_AUTHPRIV, LOG_CONS);
194 }
195
196 // if we're not running as root in production mode, fail
197 // in debug mode, issue a warning
198 if (uid_t uid = getuid()) {
199 #if defined(NDEBUG)
200 Syslog::alert("Tried to run securityd as user %d: aborted", uid);
201 fprintf(stderr, "You are not allowed to run securityd\n");
202 exit(1);
203 #else
204 fprintf(stderr, "securityd is unprivileged (uid=%d); some features may not work.\n", uid);
205 #endif //NDEBUG
206 }
207
208 // turn into a properly diabolical daemon unless debugMode is on
209 if (!debugMode && getppid() != 1) {
210 if (!Daemon::incarnate(doFork))
211 exit(1); // can't daemonize
212
213 if (reExecute && !Daemon::executeSelf(argv))
214 exit(1); // can't self-execute
215 }
216
217 // arm signal handlers; code below may generate signals we want to see
218 if (signal(SIGCHLD, handleSignals) == SIG_ERR
219 || signal(SIGINT, handleSignals) == SIG_ERR
220 || signal(SIGTERM, handleSignals) == SIG_ERR
221 || signal(SIGPIPE, handleSignals) == SIG_ERR
222 #if !defined(NDEBUG)
223 || signal(SIGUSR1, handleSignals) == SIG_ERR
224 #endif //NDEBUG
225 || signal(SIGUSR2, handleSignals) == SIG_ERR) {
226 perror("signal");
227 exit(1);
228 }
229
230 // create an Authorization engine
231 Authority authority(authorizationConfig);
232
233 // introduce all supported ACL subject types
234 new AnyAclSubject::Maker();
235 new PasswordAclSubject::Maker();
236 new ProtectedPasswordAclSubject::Maker();
237 new PromptedAclSubject::Maker();
238 new ThresholdAclSubject::Maker();
239 new CommentAclSubject::Maker();
240 new ProcessAclSubject::Maker();
241 new CodeSignatureAclSubject::Maker();
242 new KeychainPromptAclSubject::Maker(keychainAclDefault);
243 new PartitionAclSubject::Maker();
244 new PreAuthorizationAcls::OriginMaker();
245 new PreAuthorizationAcls::SourceMaker();
246
247 // establish the code equivalents database
248 CodeSignatures codeSignatures;
249
250 // create the main server object and register it
251 Server server(authority, codeSignatures, bootstrapName);
252
253 // Remember the primary service port to send signal events to
254 gMainServerPort = server.primaryServicePort();
255
256 // set server configuration from arguments, if specified
257 if (workerTimeout)
258 server.timeout(workerTimeout);
259 if (maxThreads)
260 server.maxThreads(maxThreads);
261 server.floatingThread(true);
262 server.waitForClients(waitForClients);
263 server.verbosity(verbose);
264
265 // add the RNG seed timer
266 # if defined(NDEBUG)
267 EntropyManager entropy(server, entropyFile);
268 # else
269 if (getuid() == 0) new EntropyManager(server, entropyFile);
270 # endif
271
272 // create a smartcard monitor to manage external token devices
273 gPCSC = new PCSCMonitor(server, tokenCacheDir, scOptions(smartCardOptions));
274
275 // create the RootSession object (if -d, give it graphics and tty attributes)
276 RootSession rootSession(debugMode ? (sessionHasGraphicAccess | sessionHasTTY) : 0, server);
277
278 // create a monitor thread to watch for audit session events
279 AuditMonitor audits(gMainServerPort);
280 audits.run();
281
282 // install MDS (if needed) and initialize the local CSSM
283 server.loadCssm(mdsIsInstalled);
284
285 // create the shared memory notification hub
286 new SharedMemoryListener(messagingName, kSharedMemoryPoolSize);
287
288 // okay, we're ready to roll
289 SECURITYD_INITIALIZED((char*)bootstrapName);
290 Syslog::notice("Entering service");
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 [-dwX]"
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::externalDaemon;
328 else if (!strcmp(optionString, "conservative"))
329 return PCSCMonitor::externalDaemon;
330 else if (!strcmp(optionString, "aggressive"))
331 return PCSCMonitor::externalDaemon;
332 else if (!strcmp(optionString, "external"))
333 return PCSCMonitor::externalDaemon;
334 else
335 usage("securityd");
336 else
337 return PCSCMonitor::externalDaemon;
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 SECURITYD_SIGNAL_RECEIVED(sig);
350 if (kern_return_t rc = self_client_handleSignal(gMainServerPort, mach_task_self(), sig))
351 Syslog::error("self-send failed (mach error %d)", rc);
352 }