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