2 * Copyright (c) 2000-2009,2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 // securityd - Apple security services daemon.
28 #include <securityd_client/ucsp.h>
32 #include "notifications.h"
33 #include "pcscmonitor.h"
34 #include "auditevents.h"
38 #include <security_utilities/daemon.h>
39 #include <security_utilities/machserver.h>
40 #include <security_utilities/logging.h>
42 #include <Security/SecKeychainPriv.h>
45 #include <sys/types.h>
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"
65 // Local functions of the main program driver
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);
72 static Port gMainServerPort
;
79 int main(int argc
, char *argv
[])
81 DisableLocalization();
83 // clear the umask - we know what we're doing
84 secnotice("SecServer", "starting umask was 0%o", ::umask(0));
87 // tell the keychain (client) layer to turn off the server interface
88 SecKeychainSetServerMode();
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
);
95 sandbox_free_error(errorbuf
);
99 secnotice("SecServer", "entered sandbox");
102 // program arguments (preset to defaults)
103 bool debugMode
= false;
104 const char *bootstrapName
= NULL
;
105 const char* messagingName
= SharedMemoryCommon::kDefaultSecurityMessagesName
;
107 bool reExecute
= false;
108 int workerTimeout
= 0;
110 bool waitForClients
= true;
111 bool mdsIsInstalled
= false;
112 const char *tokenCacheDir
= "/var/db/TokenCache";
113 const char *smartCardOptions
= getenv("SMARTCARDS");
114 uint32_t keychainAclDefault
= CSSM_ACL_KEYCHAIN_PROMPT_INVALID
| CSSM_ACL_KEYCHAIN_PROMPT_UNSIGNED
;
115 unsigned int verbose
= 0;
117 // check for the Installation-DVD environment and modify some default arguments if found
118 if (access("/etc/rc.cdrom", F_OK
) == 0) { // /etc/rc.cdrom exists
119 secnotice("SecServer", "starting in installmode");
120 smartCardOptions
= "off"; // needs writable directories that aren't
123 // parse command line arguments
127 while ((arg
= getopt(argc
, argv
, "c:dE:imN:s:t:T:uvWX")) != -1) {
130 tokenCacheDir
= optarg
;
136 /* was entropyFile, kept to preserve ABI */
139 keychainAclDefault
&= ~CSSM_ACL_KEYCHAIN_PROMPT_INVALID
;
142 mdsIsInstalled
= true;
145 bootstrapName
= optarg
;
148 smartCardOptions
= optarg
;
151 if ((maxThreads
= atoi(optarg
)) < 0)
155 if ((workerTimeout
= atoi(optarg
)) < 0)
159 waitForClients
= false;
162 keychainAclDefault
&= ~CSSM_ACL_KEYCHAIN_PROMPT_UNSIGNED
;
176 // take no non-option arguments
180 // figure out the bootstrap name
181 if (!bootstrapName
) {
182 bootstrapName
= getenv(SECURITYSERVER_BOOTSTRAP_ENV
);
185 bootstrapName
= SECURITYSERVER_BOOTSTRAP_NAME
;
189 #ifndef __clang_analyzer__
190 messagingName
= bootstrapName
;
196 #ifndef __clang_analyzer__
197 messagingName
= bootstrapName
;
201 // configure logging first
203 Syslog::open(bootstrapName
, LOG_AUTHPRIV
, LOG_PERROR
);
204 Syslog::notice("%s started in debug mode", argv
[0]);
206 Syslog::open(bootstrapName
, LOG_AUTHPRIV
, LOG_CONS
);
209 // if we're not running as root in production mode, fail
210 // in debug mode, issue a warning
211 if (uid_t uid
= getuid()) {
213 Syslog::alert("Tried to run securityd as user %d: aborted", uid
);
214 fprintf(stderr
, "You are not allowed to run securityd\n");
217 fprintf(stderr
, "securityd is unprivileged (uid=%d); some features may not work.\n", uid
);
221 // turn into a properly diabolical daemon unless debugMode is on
222 if (!debugMode
&& getppid() != 1) {
223 if (!Daemon::incarnate(doFork
))
224 exit(1); // can't daemonize
226 if (reExecute
&& !Daemon::executeSelf(argv
))
227 exit(1); // can't self-execute
230 // arm signal handlers; code below may generate signals we want to see
231 if (signal(SIGCHLD
, handleSignals
) == SIG_ERR
232 || signal(SIGINT
, handleSignals
) == SIG_ERR
233 || signal(SIGTERM
, handleSignals
) == SIG_ERR
234 || signal(SIGPIPE
, handleSignals
) == SIG_ERR
236 || signal(SIGUSR1
, handleSignals
) == SIG_ERR
238 || signal(SIGUSR2
, handleSignals
) == SIG_ERR
) {
243 // The clang static analyzer isn't a big fan of our "object creation hooks object into global pointer graph" model.
244 // Tell it not to worry.
245 #ifndef __clang_analyzer__
246 // introduce all supported ACL subject types
247 new AnyAclSubject::Maker();
248 new PasswordAclSubject::Maker();
249 new ProtectedPasswordAclSubject::Maker();
250 new PromptedAclSubject::Maker();
251 new ThresholdAclSubject::Maker();
252 new CommentAclSubject::Maker();
253 new ProcessAclSubject::Maker();
254 new CodeSignatureAclSubject::Maker();
255 new KeychainPromptAclSubject::Maker(keychainAclDefault
);
256 new PartitionAclSubject::Maker();
257 new PreAuthorizationAcls::OriginMaker();
258 new PreAuthorizationAcls::SourceMaker();
260 // establish the code equivalents database
261 CodeSignatures codeSignatures
;
264 // create the main server object and register it
265 Server
server(codeSignatures
, bootstrapName
);
267 // Remember the primary service port to send signal events to
268 gMainServerPort
= server
.primaryServicePort();
270 // set server configuration from arguments, if specified
272 server
.timeout(workerTimeout
);
274 server
.maxThreads(maxThreads
);
275 server
.floatingThread(true);
276 server
.waitForClients(waitForClients
);
277 server
.verbosity(verbose
);
279 // create a smartcard monitor to manage external token devices
280 gPCSC
= new PCSCMonitor(server
, tokenCacheDir
, scOptions(smartCardOptions
));
282 // create the RootSession object (if -d, give it graphics and tty attributes)
283 RootSession
rootSession(debugMode
? (sessionHasGraphicAccess
| sessionHasTTY
) : 0, server
);
285 // create a monitor thread to watch for audit session events
286 AuditMonitor
audits(gMainServerPort
);
289 // install MDS (if needed) and initialize the local CSSM
290 server
.loadCssm(mdsIsInstalled
);
292 #ifndef __clang_analyzer__
293 // create the shared memory notification hub
294 new SharedMemoryListener(messagingName
, kSharedMemoryPoolSize
);
298 // okay, we're ready to roll
299 secnotice("SecServer", "Entering service as %s", (char*)bootstrapName
);
300 Syslog::notice("Entering service");
305 // fell out of runloop (should not happen)
306 Syslog::alert("Aborting");
312 // Issue usage message and die
314 static void usage(const char *me
)
316 fprintf(stderr
, "Usage: %s [-dwX]"
317 "\n\t[-c tokencache] smartcard token cache directory"
318 "\n\t[-e equivDatabase] path to code equivalence database"
319 "\n\t[-N serviceName] MACH service name"
320 "\n\t[-s off|on|conservative|aggressive] smartcard operation level"
321 "\n\t[-t maxthreads] [-T threadTimeout] server thread control"
326 const CFStringRef kTKSmartCardPreferencesDomain
= CFSTR("com.apple.security.smartcard");
327 const CFStringRef kTKLegacyTokendPreferencesKey
= CFSTR("Legacy");
329 static bool legacyTokensEnabled() {
331 CFPropertyListRef value
= CFPreferencesCopyValue(kTKLegacyTokendPreferencesKey
, kTKSmartCardPreferencesDomain
, kCFPreferencesAnyUser
, kCFPreferencesCurrentHost
);
333 if (CFEqual(value
, kCFBooleanTrue
)) {
342 // Translate strings (e.g. "conservative") into PCSCMonitor service levels
344 static PCSCMonitor::ServiceLevel
scOptions(const char *optionString
)
346 if (!legacyTokensEnabled())
347 return PCSCMonitor::forcedOff
;
350 if (!strcmp(optionString
, "off"))
351 return PCSCMonitor::forcedOff
;
352 else if (!strcmp(optionString
, "on"))
353 return PCSCMonitor::externalDaemon
;
354 else if (!strcmp(optionString
, "conservative"))
355 return PCSCMonitor::externalDaemon
;
356 else if (!strcmp(optionString
, "aggressive"))
357 return PCSCMonitor::externalDaemon
;
358 else if (!strcmp(optionString
, "external"))
359 return PCSCMonitor::externalDaemon
;
363 return PCSCMonitor::externalDaemon
;
369 // We send ourselves a message (through the "self" service), so actual
370 // actions happen on the normal event loop path. Note that another thread
371 // may be picking up the message immediately.
373 static void handleSignals(int sig
)
375 (void)self_client_handleSignal(gMainServerPort
, mach_task_self(), sig
);