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