]> git.saurik.com Git - apple/security.git/blob - securityd/src/main.cpp
Security-57740.1.18.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 "session.h"
33 #include "notifications.h"
34 #include "pcscmonitor.h"
35 #include "auditevents.h"
36 #include "self.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
63 //
64 // Local functions of the main program driver
65 //
66 static void usage(const char *me) __attribute__((noreturn));
67 static void handleSignals(int sig);
68 static PCSCMonitor::ServiceLevel scOptions(const char *optionString);
69
70
71 static Port gMainServerPort;
72 PCSCMonitor *gPCSC;
73
74
75 //
76 // Main driver
77 //
78 int main(int argc, char *argv[])
79 {
80 // clear the umask - we know what we're doing
81 secnotice("SS", "starting umask was 0%o", ::umask(0));
82 ::umask(0);
83
84 // tell the keychain (client) layer to turn off the server interface
85 SecKeychainSetServerMode();
86
87 // program arguments (preset to defaults)
88 bool debugMode = false;
89 const char *bootstrapName = NULL;
90 const char* messagingName = SECURITY_MESSAGES_NAME;
91 bool doFork = false;
92 bool reExecute = false;
93 int workerTimeout = 0;
94 int maxThreads = 0;
95 bool waitForClients = true;
96 bool mdsIsInstalled = false;
97 const char *tokenCacheDir = "/var/db/TokenCache";
98 const char *entropyFile = "/var/db/SystemEntropyCache";
99 const char *smartCardOptions = getenv("SMARTCARDS");
100 uint32_t keychainAclDefault = CSSM_ACL_KEYCHAIN_PROMPT_INVALID | CSSM_ACL_KEYCHAIN_PROMPT_UNSIGNED;
101 unsigned int verbose = 0;
102
103 // check for the Installation-DVD environment and modify some default arguments if found
104 if (access("/etc/rc.cdrom", F_OK) == 0) { // /etc/rc.cdrom exists
105 secnotice("SS", "starting in installmode");
106 smartCardOptions = "off"; // needs writable directories that aren't
107 }
108
109 // parse command line arguments
110 extern char *optarg;
111 extern int optind;
112 int arg;
113 while ((arg = getopt(argc, argv, "c:dE:imN:s:t:T:uvWX")) != -1) {
114 switch (arg) {
115 case 'c':
116 tokenCacheDir = optarg;
117 break;
118 case 'd':
119 debugMode = true;
120 break;
121 case 'E':
122 entropyFile = optarg;
123 break;
124 case 'i':
125 keychainAclDefault &= ~CSSM_ACL_KEYCHAIN_PROMPT_INVALID;
126 break;
127 case 'm':
128 mdsIsInstalled = true;
129 break;
130 case 'N':
131 bootstrapName = optarg;
132 break;
133 case 's':
134 smartCardOptions = 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 'W':
145 waitForClients = false;
146 break;
147 case 'u':
148 keychainAclDefault &= ~CSSM_ACL_KEYCHAIN_PROMPT_UNSIGNED;
149 break;
150 case 'v':
151 verbose++;
152 break;
153 case 'X':
154 doFork = true;
155 reExecute = true;
156 break;
157 default:
158 usage(argv[0]);
159 }
160 }
161
162 // take no non-option arguments
163 if (optind < argc)
164 usage(argv[0]);
165
166 // figure out the bootstrap name
167 if (!bootstrapName) {
168 bootstrapName = getenv(SECURITYSERVER_BOOTSTRAP_ENV);
169 if (!bootstrapName)
170 {
171 bootstrapName = SECURITYSERVER_BOOTSTRAP_NAME;
172 }
173 else
174 {
175 messagingName = bootstrapName;
176 }
177 }
178 else
179 {
180 messagingName = bootstrapName;
181 }
182
183 // configure logging first
184 if (debugMode) {
185 Syslog::open(bootstrapName, LOG_AUTHPRIV, LOG_PERROR);
186 Syslog::notice("%s started in debug mode", argv[0]);
187 } else {
188 Syslog::open(bootstrapName, LOG_AUTHPRIV, LOG_CONS);
189 }
190
191 // if we're not running as root in production mode, fail
192 // in debug mode, issue a warning
193 if (uid_t uid = getuid()) {
194 #if defined(NDEBUG)
195 Syslog::alert("Tried to run securityd as user %d: aborted", uid);
196 fprintf(stderr, "You are not allowed to run securityd\n");
197 exit(1);
198 #else
199 fprintf(stderr, "securityd is unprivileged (uid=%d); some features may not work.\n", uid);
200 #endif //NDEBUG
201 }
202
203 // turn into a properly diabolical daemon unless debugMode is on
204 if (!debugMode && getppid() != 1) {
205 if (!Daemon::incarnate(doFork))
206 exit(1); // can't daemonize
207
208 if (reExecute && !Daemon::executeSelf(argv))
209 exit(1); // can't self-execute
210 }
211
212 // arm signal handlers; code below may generate signals we want to see
213 if (signal(SIGCHLD, handleSignals) == SIG_ERR
214 || signal(SIGINT, handleSignals) == SIG_ERR
215 || signal(SIGTERM, handleSignals) == SIG_ERR
216 || signal(SIGPIPE, handleSignals) == SIG_ERR
217 #if !defined(NDEBUG)
218 || signal(SIGUSR1, handleSignals) == SIG_ERR
219 #endif //NDEBUG
220 || signal(SIGUSR2, handleSignals) == SIG_ERR) {
221 perror("signal");
222 exit(1);
223 }
224
225 // introduce all supported ACL subject types
226 new AnyAclSubject::Maker();
227 new PasswordAclSubject::Maker();
228 new ProtectedPasswordAclSubject::Maker();
229 new PromptedAclSubject::Maker();
230 new ThresholdAclSubject::Maker();
231 new CommentAclSubject::Maker();
232 new ProcessAclSubject::Maker();
233 new CodeSignatureAclSubject::Maker();
234 new KeychainPromptAclSubject::Maker(keychainAclDefault);
235 new PartitionAclSubject::Maker();
236 new PreAuthorizationAcls::OriginMaker();
237 new PreAuthorizationAcls::SourceMaker();
238
239 // establish the code equivalents database
240 CodeSignatures codeSignatures;
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 // add the RNG seed timer
258 # if defined(NDEBUG)
259 EntropyManager entropy(server, entropyFile);
260 # else
261 if (getuid() == 0) new EntropyManager(server, entropyFile);
262 # endif
263
264 // create a smartcard monitor to manage external token devices
265 gPCSC = new PCSCMonitor(server, tokenCacheDir, scOptions(smartCardOptions));
266
267 // create the RootSession object (if -d, give it graphics and tty attributes)
268 RootSession rootSession(debugMode ? (sessionHasGraphicAccess | sessionHasTTY) : 0, server);
269
270 // create a monitor thread to watch for audit session events
271 AuditMonitor audits(gMainServerPort);
272 audits.run();
273
274 // install MDS (if needed) and initialize the local CSSM
275 server.loadCssm(mdsIsInstalled);
276
277 // create the shared memory notification hub
278 new SharedMemoryListener(messagingName, kSharedMemoryPoolSize);
279
280 // okay, we're ready to roll
281 secnotice("SS", "Entering service as %s", (char*)bootstrapName);
282 Syslog::notice("Entering service");
283
284 // go
285 server.run();
286
287 // fell out of runloop (should not happen)
288 Syslog::alert("Aborting");
289 return 1;
290 }
291
292
293 //
294 // Issue usage message and die
295 //
296 static void usage(const char *me)
297 {
298 fprintf(stderr, "Usage: %s [-dwX]"
299 "\n\t[-c tokencache] smartcard token cache directory"
300 "\n\t[-e equivDatabase] path to code equivalence database"
301 "\n\t[-N serviceName] MACH service name"
302 "\n\t[-s off|on|conservative|aggressive] smartcard operation level"
303 "\n\t[-t maxthreads] [-T threadTimeout] server thread control"
304 "\n", me);
305 exit(2);
306 }
307
308
309 //
310 // Translate strings (e.g. "conservative") into PCSCMonitor service levels
311 //
312 static PCSCMonitor::ServiceLevel scOptions(const char *optionString)
313 {
314 if (optionString)
315 if (!strcmp(optionString, "off"))
316 return PCSCMonitor::forcedOff;
317 else if (!strcmp(optionString, "on"))
318 return PCSCMonitor::externalDaemon;
319 else if (!strcmp(optionString, "conservative"))
320 return PCSCMonitor::externalDaemon;
321 else if (!strcmp(optionString, "aggressive"))
322 return PCSCMonitor::externalDaemon;
323 else if (!strcmp(optionString, "external"))
324 return PCSCMonitor::externalDaemon;
325 else
326 usage("securityd");
327 else
328 return PCSCMonitor::externalDaemon;
329 }
330
331
332 //
333 // Handle signals.
334 // We send ourselves a message (through the "self" service), so actual
335 // actions happen on the normal event loop path. Note that another thread
336 // may be picking up the message immediately.
337 //
338 static void handleSignals(int sig)
339 {
340 secnotice("SS", "signal received: %d", sig);
341 if (kern_return_t rc = self_client_handleSignal(gMainServerPort, mach_task_self(), sig))
342 Syslog::error("self-send failed (mach error %d)", rc);
343 }