]> git.saurik.com Git - apple/security.git/blob - SecurityTool/security.c
Security-57740.31.2.tar.gz
[apple/security.git] / SecurityTool / security.c
1 /*
2 * Copyright (c) 2003-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 * security.c
24 */
25
26 #include "security_tool.h"
27
28 #include "leaks.h"
29 #include "readline.h"
30
31 #include "cmsutil.h"
32 #include "db_commands.h"
33 #include "keychain_add.h"
34 #include "keychain_create.h"
35 #include "keychain_delete.h"
36 #include "keychain_list.h"
37 #include "keychain_lock.h"
38 #include "keychain_set_settings.h"
39 #include "keychain_show_info.h"
40 #include "keychain_unlock.h"
41 #include "keychain_recode.h"
42 #include "key_create.h"
43 #include "keychain_find.h"
44 #include "keychain_import.h"
45 #include "keychain_export.h"
46 #include "identity_find.h"
47 #include "identity_prefs.h"
48 #include "mds_install.h"
49 #include "trusted_cert_add.h"
50 #include "trusted_cert_dump.h"
51 #include "user_trust_enable.h"
52 #include "trust_settings_impexp.h"
53 #include "verify_cert.h"
54 #include "authz.h"
55 #include "smartcards.h"
56 #include "display_error_code.h"
57 #include "createFVMaster.h"
58 #include "smartcards.h"
59 #include "translocate.h"
60
61 #include <ctype.h>
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <string.h>
65 #include <unistd.h>
66 #include <dispatch/dispatch.h>
67
68 #include <CoreFoundation/CFRunLoop.h>
69 #include <Security/SecBasePriv.h>
70 #include <Security/SecKeychainPriv.h>
71 #include <security_asn1/secerr.h>
72
73 /* Maximum length of an input line in interactive mode. */
74 #define MAX_LINE_LEN 4096
75 /* Maximum number of arguments on an input line in interactive mode. */
76 #define MAX_ARGS 32
77
78 /* Entry in commands array for a command. */
79 typedef struct command
80 {
81 const char *c_name; /* name of the command. */
82 command_func c_func; /* function to execute the command. */
83 const char *c_usage; /* usage sting for command. */
84 const char *c_help; /* help string for (or description of) command. */
85 } command;
86
87 /* The default prompt. */
88 const char *prompt_string = "security> ";
89
90 /* The name of this program. */
91 const char *prog_name;
92
93
94 /* Forward declarations of static functions. */
95 static int help(int argc, char * const *argv);
96
97 /*
98 * The command array itself.
99 * Add commands here at will.
100 * Matching is done on a prefix basis. The first command in the array
101 * gets matched first.
102 */
103 const command commands[] =
104 {
105 { "help", help,
106 "[command ...]",
107 "Show all commands, or show usage for a command." },
108
109 { "list-keychains", keychain_list,
110 "[-d user|system|common|dynamic] [-s [keychain...]]\n"
111 " -d Use the specified preference domain\n"
112 " -s Set the search list to the specified keychains\n"
113 "With no parameters, display the search list.",
114 "Display or manipulate the keychain search list." },
115
116 { "list-smartcards", ctk_list,
117 "With no parameters, display IDs of available smartcards.",
118 "Display available smartcards." },
119
120 { "default-keychain", keychain_default,
121 "[-d user|system|common|dynamic] [-s [keychain]]\n"
122 " -d Use the specified preference domain\n"
123 " -s Set the default keychain to the specified keychain\n"
124 "With no parameters, display the default keychain.",
125 "Display or set the default keychain." },
126
127 { "login-keychain", keychain_login,
128 "[-d user|system|common|dynamic] [-s [keychain]]\n"
129 " -d Use the specified preference domain\n"
130 " -s Set the login keychain to the specified keychain\n"
131 "With no parameters, display the login keychain.",
132 "Display or set the login keychain." },
133
134 { "create-keychain", keychain_create,
135 "[-P] [-p password] [keychains...]\n"
136 " -p Use \"password\" as the password for the keychains being created\n"
137 " -P Prompt the user for a password using the SecurityAgent\n"
138 "Use of the -p option is insecure",
139 "Create keychains and add them to the search list.",
140 },
141
142 { "delete-keychain", keychain_delete,
143 "[keychains...]",
144 "Delete keychains and remove them from the search list." },
145
146 { "lock-keychain", keychain_lock,
147 "[-a | keychain]\n"
148 " -a Lock all keychains",
149 "Lock the specified keychain."},
150
151 { "unlock-keychain", keychain_unlock,
152 "[-u] [-p password] [keychain]\n"
153 " -p Use \"password\" as the password to unlock the keychain\n"
154 " -u Do not use the password\n"
155 "Use of the -p option is insecure",
156 "Unlock the specified keychain."},
157
158 { "set-keychain-settings", keychain_set_settings,
159 "[-lu] [-t timeout] [keychain]\n"
160 " -l Lock keychain when the system sleeps\n"
161 " -u Lock keychain after timeout interval\n"
162 " -t Timeout in seconds (omitting this option specifies \"no timeout\")\n",
163 "Set settings for a keychain."},
164
165 { "set-keychain-password", keychain_set_password,
166 "[-o oldPassword] [-p newPassword] [keychain]\n"
167 " -o Old keychain password (if not provided, will prompt)\n"
168 " -p New keychain password (if not provided, will prompt)\n"
169 "Use of either the -o or -p options is insecure\n",
170 "Set password for a keychain."},
171
172 { "show-keychain-info", keychain_show_info,
173 "[keychain]",
174 "Show the settings for keychain." },
175
176 { "dump-keychain", keychain_dump,
177 "[-adir] [keychain...]\n"
178 " -a Dump access control list of items\n"
179 " -d Dump (decrypted) data of items\n"
180 " -i Interactive access control list editing mode\n"
181 " -r Dump the raw (encrypted) data of items",
182 "Dump the contents of one or more keychains." },
183
184 #ifndef NDEBUG
185 { "recode-keychain", keychain_recode,
186 "keychain_to_recode keychain_to_get_secrets_from",
187 "Recode a keychain to use the secrets from another one."},
188 #endif
189
190 { "create-keypair", key_create_pair,
191 "[-a alg] [-s size] [-f date] [-t date] [-d days] [-k keychain] [-A|-T appPath] description\n"
192 " -a Use alg as the algorithm, can be rsa, dh, dsa or fee (default rsa)\n"
193 " -s Specify the keysize in bits (default 512)\n"
194 " -f Make a key valid from the specified date\n"
195 " -t Make a key valid to the specified date\n"
196 " -d Make a key valid for the number of days specified from today\n"
197 " -k Use the specified keychain rather than the default\n"
198 " -A Allow any application to access this key without warning (insecure, not recommended!)\n"
199 " -T Specify an application which may access this key (multiple -T options are allowed)\n"
200 "If no options are provided, ask the user interactively.",
201 "Create an asymmetric key pair." },
202
203 #if 0
204 /* this was added in mb's integration of PR-3420772, but this is an unimplemented command */
205 { "create-csr", csr_create,
206 "[-a alg] [-s size] [-f date] [-t date] [-d days] [-k keychain] [-A|-T appPath] description\n"
207 " -a Use alg as the algorithm, can be rsa, dh, dsa or fee (default rsa)\n"
208 " -s Specify the keysize in bits (default 512)\n"
209 " -f Make a key valid from the specified date\n"
210 " -t Make a key valid to the specified date\n"
211 " -d Make a key valid for the number of days specified from today\n"
212 " -k Use the specified keychain rather than the default\n"
213 " -A Allow any application to access this key without warning (insecure, not recommended!)\n"
214 " -T Specify an application which may access this key (multiple -T options are allowed)\n"
215 "If no options are provided, ask the user interactively.",
216 "Create a certificate signing request." },
217 #endif
218
219 { "add-generic-password", keychain_add_generic_password,
220 "[-a account] [-s service] [-w password] [options...] [-A|-T appPath] [keychain]\n"
221 " -a Specify account name (required)\n"
222 " -c Specify item creator (optional four-character code)\n"
223 " -C Specify item type (optional four-character code)\n"
224 " -D Specify kind (default is \"application password\")\n"
225 " -G Specify generic attribute (optional)\n"
226 " -j Specify comment string (optional)\n"
227 " -l Specify label (if omitted, service name is used as default label)\n"
228 " -s Specify service name (required)\n"
229 " -p Specify password to be added (legacy option, equivalent to -w)\n"
230 " -w Specify password to be added\n"
231 " -A Allow any application to access this item without warning (insecure, not recommended!)\n"
232 " -T Specify an application which may access this item (multiple -T options are allowed)\n"
233 " -U Update item if it already exists (if omitted, the item cannot already exist)\n"
234 "\n"
235 "By default, the application which creates an item is trusted to access its data without warning.\n"
236 "You can remove this default access by explicitly specifying an empty app pathname: -T \"\"\n"
237 "If no keychain is specified, the password is added to the default keychain.\n"
238 "Use of the -p or -w options is insecure. Specify -w as the last option to be prompted.\n",
239 "Add a generic password item."},
240
241 { "add-internet-password", keychain_add_internet_password,
242 "[-a account] [-s server] [-w password] [options...] [-A|-T appPath] [keychain]\n"
243 " -a Specify account name (required)\n"
244 " -c Specify item creator (optional four-character code)\n"
245 " -C Specify item type (optional four-character code)\n"
246 " -d Specify security domain string (optional)\n"
247 " -D Specify kind (default is \"Internet password\")\n"
248 " -j Specify comment string (optional)\n"
249 " -l Specify label (if omitted, server name is used as default label)\n"
250 " -p Specify path string (optional)\n"
251 " -P Specify port number (optional)\n"
252 " -r Specify protocol (optional four-character SecProtocolType, e.g. \"http\", \"ftp \")\n"
253 " -s Specify server name (required)\n"
254 " -t Specify authentication type (as a four-character SecAuthenticationType, default is \"dflt\")\n"
255 " -w Specify password to be added\n"
256 " -A Allow any application to access this item without warning (insecure, not recommended!)\n"
257 " -T Specify an application which may access this item (multiple -T options are allowed)\n"
258 " -U Update item if it already exists (if omitted, the item cannot already exist)\n"
259 "\n"
260 "By default, the application which creates an item is trusted to access its data without warning.\n"
261 "You can remove this default access by explicitly specifying an empty app pathname: -T \"\"\n"
262 "If no keychain is specified, the password is added to the default keychain.\n"
263 "Use of the -p or -w options is insecure. Specify -w as the last option to be prompted.\n",
264 "Add an internet password item."},
265
266 { "add-certificates", keychain_add_certificates,
267 "[-k keychain] file...\n"
268 "If no keychain is specified, the certificates are added to the default keychain.",
269 "Add certificates to a keychain."},
270
271 { "find-generic-password", keychain_find_generic_password,
272 "[-a account] [-s service] [options...] [-g] [keychain...]\n"
273 " -a Match \"account\" string\n"
274 " -c Match \"creator\" (four-character code)\n"
275 " -C Match \"type\" (four-character code)\n"
276 " -D Match \"kind\" string\n"
277 " -G Match \"value\" string (generic attribute)\n"
278 " -j Match \"comment\" string\n"
279 " -l Match \"label\" string\n"
280 " -s Match \"service\" string\n"
281 " -g Display the password for the item found\n"
282 " -w Display only the password on stdout\n"
283 "If no keychains are specified to search, the default search list is used.",
284 "Find a generic password item."},
285
286 { "delete-generic-password", keychain_delete_generic_password,
287 "[-a account] [-s service] [options...] [keychain...]\n"
288 " -a Match \"account\" string\n"
289 " -c Match \"creator\" (four-character code)\n"
290 " -C Match \"type\" (four-character code)\n"
291 " -D Match \"kind\" string\n"
292 " -G Match \"value\" string (generic attribute)\n"
293 " -j Match \"comment\" string\n"
294 " -l Match \"label\" string\n"
295 " -s Match \"service\" string\n"
296 "If no keychains are specified to search, the default search list is used.",
297 "Delete a generic password item."},
298
299 { "set-generic-password-partition-list", keychain_set_generic_password_partition_list,
300 "[-a account] [-s service] [-S partition-list] [-k keychain password] [options...] [keychain]\n"
301 " -a Match \"account\" string\n"
302 " -c Match \"creator\" (four-character code)\n"
303 " -C Match \"type\" (four-character code)\n"
304 " -D Match \"kind\" string\n"
305 " -G Match \"value\" string (generic attribute)\n"
306 " -j Match \"comment\" string\n"
307 " -l Match \"label\" string\n"
308 " -s Match \"service\" string\n"
309 " -S Comma-separated list of allowed partition IDs\n"
310 " -k The password for the keychain (required)\n"
311 "If no keychains are specified to search, the default search list is used.\n"
312 "Use of the -k option is insecure. Omit it to be prompted.\n",
313 "Set the partition list of a generic password item."},
314
315 { "find-internet-password", keychain_find_internet_password,
316 "[-a account] [-s server] [options...] [-g] [keychain...]\n"
317 " -a Match \"account\" string\n"
318 " -c Match \"creator\" (four-character code)\n"
319 " -C Match \"type\" (four-character code)\n"
320 " -d Match \"securityDomain\" string\n"
321 " -D Match \"kind\" string\n"
322 " -j Match \"comment\" string\n"
323 " -l Match \"label\" string\n"
324 " -p Match \"path\" string\n"
325 " -P Match port number\n"
326 " -r Match \"protocol\" (four-character code)\n"
327 " -s Match \"server\" string\n"
328 " -t Match \"authenticationType\" (four-character code)\n"
329 " -g Display the password for the item found\n"
330 " -w Display only the password on stdout\n"
331 "If no keychains are specified to search, the default search list is used.",
332 "Find an internet password item."},
333
334 { "delete-internet-password", keychain_delete_internet_password,
335 "[-a account] [-s server] [options...] [keychain...]\n"
336 " -a Match \"account\" string\n"
337 " -c Match \"creator\" (four-character code)\n"
338 " -C Match \"type\" (four-character code)\n"
339 " -d Match \"securityDomain\" string\n"
340 " -D Match \"kind\" string\n"
341 " -j Match \"comment\" string\n"
342 " -l Match \"label\" string\n"
343 " -p Match \"path\" string\n"
344 " -P Match port number\n"
345 " -r Match \"protocol\" (four-character code)\n"
346 " -s Match \"server\" string\n"
347 " -t Match \"authenticationType\" (four-character code)\n"
348 "If no keychains are specified to search, the default search list is used.",
349 "Delete an internet password item."},
350
351 { "set-internet-password-partition-list", keychain_set_internet_password_partition_list,
352 "[-a account] [-s service] [-S partition-list] [-k keychain password] [options...] [keychain]\n"
353 " -a Match \"account\" string\n"
354 " -c Match \"creator\" (four-character code)\n"
355 " -C Match \"type\" (four-character code)\n"
356 " -d Match \"securityDomain\" string\n"
357 " -D Match \"kind\" string\n"
358 " -j Match \"comment\" string\n"
359 " -l Match \"label\" string\n"
360 " -p Match \"path\" string\n"
361 " -P Match port number\n"
362 " -r Match \"protocol\" (four-character code)\n"
363 " -s Match \"server\" string\n"
364 " -t Match \"authenticationType\" (four-character code)\n"
365 " -S Comma-separated list of allowed partition IDs\n"
366 " -k password for keychain (required)\n"
367
368 "If no keychains are specified to search, the default search list is used.\n"
369 "Use of the -k option is insecure. Omit it to be prompted.\n",
370 "Set the partition list of a internet password item."},
371
372 { "find-key", keychain_find_key,
373 "[options...] [keychain...]\n"
374 " -a Match \"application label\" string\n"
375 " -c Match \"creator\" (four-character code)\n"
376 " -d Match keys that can decrypt\n"
377 " -D Match \"description\" string\n"
378 " -e Match keys that can encrypt\n"
379 " -j Match \"comment\" string\n"
380 " -l Match \"label\" string\n"
381 " -r Match keys that can derive\n"
382 " -s Match keys that can sign\n"
383 " -t Type of key to find: one of \"symmetric\", \"public\", or \"private\"\n"
384 " -u Match keys that can unwrap\n"
385 " -v Match keys that can verify\n"
386 " -w Match keys that can wrap\n"
387
388 "If no keychains are specified to search, the default search list is used.",
389 "Find keys in the keychain"},
390
391 { "set-key-partition-list", keychain_set_key_partition_list,
392 "[options...] [keychain]\n"
393 " -a Match \"application label\" string\n"
394 " -c Match \"creator\" (four-character code)\n"
395 " -d Match keys that can decrypt\n"
396 " -D Match \"description\" string\n"
397 " -e Match keys that can encrypt\n"
398 " -j Match \"comment\" string\n"
399 " -l Match \"label\" string\n"
400 " -r Match keys that can derive\n"
401 " -s Match keys that can sign\n"
402 " -t Type of key to find: one of \"symmetric\", \"public\", or \"private\"\n"
403 " -u Match keys that can unwrap\n"
404 " -v Match keys that can verify\n"
405 " -w Match keys that can wrap\n"
406 " -S Comma-separated list of allowed partition IDs\n"
407 " -k password for keychain (required)\n"
408
409 "If no keychains are specified to search, the default search list is used.",
410 "Set the partition list of a key."},
411
412 { "find-certificate", keychain_find_certificate,
413 "[-a] [-c name] [-e emailAddress] [-m] [-p] [-Z] [keychain...]\n"
414 " -a Find all matching certificates, not just the first one\n"
415 " -c Match on \"name\" when searching (optional)\n"
416 " -e Match on \"emailAddress\" when searching (optional)\n"
417 " -m Show the email addresses in the certificate\n"
418 " -p Output certificate in pem format\n"
419 " -Z Print SHA-1 hash of the certificate\n"
420 "If no keychains are specified to search, the default search list is used.",
421 "Find a certificate item."},
422
423 { "find-identity", keychain_find_identity,
424 "[-p policy] [-s string] [-v] [keychain...]\n"
425 " -p Specify policy to evaluate (multiple -p options are allowed)\n"
426 " Supported policies: basic, ssl-client, ssl-server, smime, eap,\n"
427 " ipsec, ichat, codesigning, sys-default, sys-kerberos-kdc, macappstore, appleID\n"
428 " -s Specify optional policy-specific string (e.g. DNS hostname for SSL,\n"
429 " or RFC822 email address for S/MIME)\n"
430 " -v Show valid identities only (default is to show all identities)\n"
431 "If no keychains are specified to search, the default search list is used.",
432 "Find an identity (certificate + private key)."},
433
434 { "delete-certificate", keychain_delete_certificate,
435 "[-c name] [-Z hash] [-t] [keychain...]\n"
436 " -c Specify certificate to delete by its common name\n"
437 " -Z Specify certificate to delete by its SHA-1 hash value\n"
438 " -t Also delete user trust settings for this certificate\n"
439 "The certificate to be deleted must be uniquely specified either by a\n"
440 "string found in its common name, or by its SHA-1 hash.\n"
441 "If no keychains are specified to search, the default search list is used.",
442 "Delete a certificate from a keychain."},
443
444 { "set-identity-preference", set_identity_preference,
445 "[-n] [-c identity] [-s service] [-u keyUsage] [-Z hash] [keychain...]\n"
446 " -n Specify no identity (clears existing preference for service)\n"
447 " -c Specify identity by common name of the certificate\n"
448 " -s Specify service (may be a URL, RFC822 email address, DNS host, or\n"
449 " other name) for which this identity is to be preferred\n"
450 " -u Specify key usage (optional) - see man page for values\n"
451 " -Z Specify identity by SHA-1 hash of certificate (optional)\n",
452 "Set the preferred identity to use for a service."},
453
454 { "get-identity-preference", get_identity_preference,
455 "[-s service] [-u keyUsage] [-p] [-c] [-Z] [keychain...]\n"
456 " -s Specify service (may be a URL, RFC822 email address, DNS host, or\n"
457 " other name)\n"
458 " -u Specify key usage (optional) - see man page for values\n"
459 " -p Output identity certificate in pem format\n"
460 " -c Print common name of the preferred identity certificate\n"
461 " -Z Print SHA-1 hash of the preferred identity certificate\n",
462 "Get the preferred identity to use for a service."},
463
464 { "create-db", db_create,
465 "[-ao0] [-g dl|cspdl] [-m mode] [name]\n"
466 " -a Turn off autocommit\n"
467 " -g Attach to \"guid\" rather than the AppleFileDL\n"
468 " -m Set the inital mode of the created db to \"mode\"\n"
469 " -o Force using openparams argument\n"
470 " -0 Force using version 0 openparams\n"
471 "If no name is provided, ask the user interactively.",
472 "Create a db using the DL." },
473
474 { "export" , keychain_export,
475 "[-k keychain] [-t type] [-f format] [-w] [-p] [-P passphrase] [-o outfile]\n"
476 " -k keychain to export items from\n"
477 " -t Type = certs|allKeys|pubKeys|privKeys|identities|all (Default: all)\n"
478 " -f Format = openssl|openssh1|openssh2|bsafe|pkcs7|pkcs8|pkcs12|pemseq|x509\n"
479 " ...default format is pemseq for aggregate, openssl for single\n"
480 " -w Private keys are wrapped\n"
481 " -p PEM encode the output\n"
482 " -P Specify wrapping passphrase immediately (default is secure passphrase via GUI)\n"
483 " -o Specify output file (default is stdout)\n"
484 "Use of the -P option is insecure\n",
485 "Export items from a keychain." },
486
487 { "import", keychain_import,
488 "inputfile [-k keychain] [-t type] [-f format] [-w] [-P passphrase] [options...]\n"
489 " -k Target keychain to import into\n"
490 " -t Type = pub|priv|session|cert|agg\n"
491 " -f Format = openssl|openssh1|openssh2|bsafe|raw|pkcs7|pkcs8|pkcs12|netscape|pemseq\n"
492 " -w Specify that private keys are wrapped and must be unwrapped on import\n"
493 " -x Specify that private keys are non-extractable after being imported\n"
494 " -P Specify wrapping passphrase immediately (default is secure passphrase via GUI)\n"
495 " -a Specify name and value of extended attribute (can be used multiple times)\n"
496 " -A Allow any application to access the imported key without warning (insecure, not recommended!)\n"
497 " -T Specify an application which may access the imported key (multiple -T options are allowed)\n"
498 "Use of the -P option is insecure\n",
499 "Import items into a keychain." },
500
501 { "export-smartcard" , ctk_export,
502 "[-i id] [-t type] \n"
503 " -i id of the smartcard to export (available IDs can be listed by list-smartcards\n"
504 " command, default: export all smartcards)\n"
505 " -t Type = certs|privKeys|identities|all (Default: all)\n",
506 "Export items from a smartcard." },
507
508 { "cms", cms_util,
509 "[-C|-D|-E|-S] [<options>]\n"
510 " -C create a CMS encrypted message\n"
511 " -D decode a CMS message\n"
512 " -E create a CMS enveloped message\n"
513 " -S create a CMS signed message\n"
514 "\n"
515 "Decoding options:\n"
516 " -c content use this detached content file\n"
517 " -h level generate email headers with info about CMS message\n"
518 " (output level >= 0)\n"
519 " -n suppress output of content\n"
520 "\n"
521 "Encoding options:\n"
522 " -r id,... create envelope for these recipients,\n"
523 " where id can be a certificate nickname or email address\n"
524 " -G include a signing time attribute\n"
525 " -H hash hash = MD2|MD4|MD5|SHA1|SHA256|SHA384|SHA512 (default: SHA1)\n"
526 " -N nick use certificate named \"nick\" for signing\n"
527 " -P include a SMIMECapabilities attribute\n"
528 " -T do not include content in CMS message\n"
529 " -Y nick include an EncryptionKeyPreference attribute with certificate\n"
530 " (use \"NONE\" to omit)\n"
531 " -Z hash find a certificate by subject key ID\n"
532 "\n"
533 "Common options:\n"
534 " -e envelope specify envelope file (valid with -D or -E)\n"
535 " -k keychain specify keychain to use\n"
536 " -i infile use infile as source of data (default: stdin)\n"
537 " -o outfile use outfile as destination of data (default: stdout)\n"
538 " -p password use password as key db password (default: prompt). Using -p is insecure\n"
539 " -s pass data a single byte at a time to CMS\n"
540 " -u certusage set type of certificate usage (default: certUsageEmailSigner)\n"
541 " -v print debugging information\n"
542 "\n"
543 "Cert usage codes:\n"
544 " 0 - certUsageSSLClient\n"
545 " 1 - certUsageSSLServer\n"
546 " 2 - certUsageSSLServerWithStepUp\n"
547 " 3 - certUsageSSLCA\n"
548 " 4 - certUsageEmailSigner\n"
549 " 5 - certUsageEmailRecipient\n"
550 " 6 - certUsageObjectSigner\n"
551 " 7 - certUsageUserCertImport\n"
552 " 8 - certUsageVerifyCA\n"
553 " 9 - certUsageProtectedObjectSigner\n"
554 " 10 - certUsageStatusResponder\n"
555 " 11 - certUsageAnyCA",
556 "Encode or decode CMS messages." },
557
558 { "install-mds" , mds_install,
559 "", /* no options */
560 "Install (or re-install) the MDS database." },
561
562 { "add-trusted-cert" , trusted_cert_add,
563 " [<options>] [certFile]\n"
564 " -d Add to admin cert store; default is user\n"
565 " -r resultType resultType = trustRoot|trustAsRoot|deny|unspecified;\n"
566 " default is trustRoot\n"
567 " -p policy Specify policy constraint (ssl, smime, codeSign, IPSec, iChat,\n"
568 " basic, swUpdate, pkgSign, pkinitClient, pkinitServer, eap)\n"
569 " -a appPath Specify application constraint\n"
570 " -s policyString Specify policy-specific string\n"
571 " -e allowedError Specify allowed error (certExpired, hostnameMismatch) or integer\n"
572 " -u keyUsage Specify key usage, an integer\n"
573 " -k keychain Specify keychain to which cert is added\n"
574 " -i settingsFileIn Input trust settings file; default is user domain\n"
575 " -o settingsFileOut Output trust settings file; default is user domain\n"
576 " -D Add default setting instead of per-cert setting\n"
577 " certFile Certificate(s)",
578 "Add trusted certificate(s)." },
579
580 { "remove-trusted-cert" , trusted_cert_remove,
581 " [-d] [-D] [certFile]\n"
582 " -d Remove from admin cert store (default is user)\n"
583 " -D Remove default setting instead of per-cert setting\n"
584 " certFile Certificate(s)",
585 "Remove trusted certificate(s)." },
586
587 { "dump-trust-settings" , trusted_cert_dump,
588 " [-s] [-d]\n"
589 " -s Display trusted system certs (default is user)\n"
590 " -d Display trusted admin certs (default is user)\n",
591 "Display contents of trust settings." },
592
593 { "user-trust-settings-enable", user_trust_enable,
594 "[-d] [-e]\n"
595 " -d Disable user-level trust Settings\n"
596 " -e Enable user-level trust Settings\n"
597 "With no parameters, show current enable state of user-level trust settings.",
598 "Display or manipulate user-level trust settings." },
599
600 { "trust-settings-export", trust_settings_export,
601 " [-s] [-d] settings_file\n"
602 " -s Export system trust settings (default is user)\n"
603 " -d Export admin trust settings (default is user)\n",
604 "Export trust settings." },
605
606 { "trust-settings-import", trust_settings_import,
607 " [-d] settings_file\n"
608 " -d Import admin trust settings (default is user)\n",
609 "Import trust settings." },
610
611 { "verify-cert" , verify_cert,
612 " [<options>]\n"
613 " -c certFile Certificate to verify. Can be specified multiple times, leaf first.\n"
614 " -r rootCertFile Root Certificate. Can be specified multiple times.\n"
615 " -p policy Verify Policy (basic, ssl, smime, codeSign, IPSec, swUpdate, pkgSign,\n"
616 " eap, appleID, macappstore, timestamping); default is basic.\n"
617 " -d date Set date and time to use when verifying certificate,\n"
618 " provided in the form of YYYY-MM-DD-hh:mm:ss (time optional) in GMT.\n"
619 " e.g: 2016-04-25-15:59:59 for April 25, 2016 at 3:59:59 pm in GMT\n"
620 " -k keychain Keychain. Can be called multiple times. Default is default search list.\n"
621 " -n No keychain search list.\n"
622 " -L Local certificates only (do not try to fetch missing CA certs from net).\n"
623 " -l Leaf cert is a CA (normally an error, unless this option is given).\n"
624 " -e emailAddress Email address for smime policy.\n"
625 " -s sslHost SSL host name for ssl policy.\n"
626 " -q Quiet.\n",
627 "Verify certificate(s)." },
628
629 { "authorize" , authorize,
630 "[<options>] <right(s)...>\n"
631 " -u Allow user interaction.\n"
632 " -c Use login name and prompt for password.\n"
633 " -C login Use given login name and prompt for password.\n"
634 " -x Do NOT share -c/-C explicit credentials\n"
635 #ifndef NDEBUG
636 " -E Don't extend rights.\n"
637 #endif
638 " -p Allow returning partial rights.\n"
639 " -d Destroy acquired rights.\n"
640 " -P Pre-authorize rights only.\n"
641 " -l Operate authorizations in least privileged mode.\n"
642 " -i Internalize authref passed on stdin.\n"
643 " -e Externalize authref to stdout.\n"
644 " -w Wait until stdout is closed (to allow reading authref from pipe).\n"
645 "Extend rights flag is passed per default.",
646 "Perform authorization operations." },
647
648 { "authorizationdb" , authorizationdb,
649 "read <right-name>\n"
650 " authorizationdb remove <right-name>\n"
651 " authorizationdb write <right-name> [allow|deny|<rulename>]\n"
652 "If no rulename is specified, write will read a plist from stdin.\n"
653 " authorizationdb merge source [destination]\n"
654 "If no destination path is specified, merge will merge to /etc/authorization.\n"
655 " authorizationdb smartcard <enable|disable|status>\n"
656 "Enables/disables smartcard login support or report current status.",
657 "Make changes to the authorization policy database." },
658
659 { "execute-with-privileges" , execute_with_privileges,
660 "<program> [args...]\n"
661 "On success, stdin will be read and forwarded to the tool.",
662 "Execute tool with privileges." },
663
664 { "leaks", leaks,
665 "[-cycles] [-nocontext] [-nostacks] [-exclude symbol]\n"
666 " -cycles Use a stricter algorithm (\"man leaks\" for details)\n"
667 " -nocontext Withhold hex dumps of the leaked memory\n"
668 " -nostacks Don't show stack traces of leaked memory\n"
669 " -exclude Ignore leaks called from \"symbol\"\n"
670 "(Set the environment variable MallocStackLogging to get symbolic traces.)",
671 "Run /usr/bin/leaks on this process." },
672
673 { "error", display_error_code,
674 "<error code(s)...>\n"
675 "Display an error string for the given security-related error code.\n"
676 "The error can be in decimal or hex, e.g. 1234 or 0x1234. Multiple "
677 "errors can be separated by spaces.",
678 "Display a descriptive message for the given error code(s)." },
679
680 { "create-filevaultmaster-keychain", keychain_createMFV,
681 "[-p password] [keychain name]\n"
682 " -p Use \"password\" as the password for the keychain being created\n"
683 " -s Specify the keysize in bits (default 2048; 1024 & 4096 are allowed)\n"
684 "By default the keychain will be created in ~/Library/Keychains/.\n"
685 "Use of the -p option is insecure. Omit it to be prompted.\n",
686 "Create a keychain containing a key pair for FileVault recovery use."
687 },
688
689 { "smartcards" , smartcards,
690 "token [-l] [-e token] [-d token]\n"
691 " -l List disabled smartcard tokens]\n"
692 " -e token Enable specified token\n"
693 " -d token Disable specified token\n",
694 "Enable, disable or list disabled smartcard tokens." },
695
696 { "translocate-create", translocate_create,
697 "<path to translocate>\n"
698 "Displays the created path or the error returned.",
699 "Create a translocation point for the provided path" },
700
701 { "translocate-policy-check", translocate_policy,
702 "<path to check>\n"
703 "Displays \"Would translocate\" or \"Would not translocate\"\n"
704 "based on the current state of the path and system policy.",
705 "Check whether a path would be translocated." },
706
707 { "translocate-status-check", translocate_check,
708 "<path to check>\n"
709 "Displays \"TRANSLOCATED\" or \"NOT TRANSLOCATED\"\n"
710 "for the given path.",
711 "Check whether a path is translocated." },
712
713 { "translocate-original-path", translocate_original_path,
714 "<path to check>\n"
715 "If the provided path is translocated, display the original path\n"
716 "If the provided path is not translocated, display the passed in path",
717 "Find the original path for a translocated path." },
718 {}
719 };
720
721 /* Global variables. */
722 int do_quiet = 0;
723 int do_verbose = 0;
724
725 /* Return 1 if name matches command. */
726 static int
727 match_command(const char *command, const char *name)
728 {
729 return !strncmp(command, name, strlen(name));
730 }
731
732 /* The help command. */
733 static int
734 help(int argc, char * const *argv)
735 {
736 const command *c;
737
738 if (argc > 1)
739 {
740 char * const *arg;
741 for (arg = argv + 1; *arg; ++arg)
742 {
743 int found = 0;
744
745 for (c = commands; c->c_name; ++c)
746 {
747 if (match_command(c->c_name, *arg))
748 {
749 found = 1;
750 break;
751 }
752 }
753
754 if (found)
755 printf("Usage: %s %s\n", c->c_name, c->c_usage);
756 else
757 {
758 sec_error("%s: no such command: %s", argv[0], *arg);
759 return 1;
760 }
761 }
762 }
763 else
764 {
765 for (c = commands; c->c_name; ++c)
766 printf(" %-36s %s\n", c->c_name, c->c_help);
767 }
768
769 return 0;
770 }
771
772 /* States for split_line parser. */
773 typedef enum
774 {
775 SKIP_WS,
776 READ_ARG,
777 READ_ARG_ESCAPED,
778 QUOTED_ARG,
779 QUOTED_ARG_ESCAPED
780 } parse_state;
781
782 /* Split a line into multiple arguments and return them in *pargc and *pargv. */
783 static void
784 split_line(char *line, int *pargc, char * const **pargv)
785 {
786 static char *argvec[MAX_ARGS + 1];
787 int argc = 0;
788 char *ptr = line;
789 char *dst = line;
790 parse_state state = SKIP_WS;
791 int quote_ch = 0;
792
793 for (ptr = line; *ptr; ++ptr)
794 {
795 if (state == SKIP_WS)
796 {
797 if (isspace(*ptr))
798 continue;
799
800 if (*ptr == '"' || *ptr == '\'')
801 {
802 quote_ch = *ptr;
803 state = QUOTED_ARG;
804 argvec[argc] = dst;
805 continue; /* Skip the quote. */
806 }
807 else
808 {
809 state = READ_ARG;
810 argvec[argc] = dst;
811 }
812 }
813
814 if (state == READ_ARG)
815 {
816 if (*ptr == '\\')
817 {
818 state = READ_ARG_ESCAPED;
819 continue;
820 }
821 else if (isspace(*ptr))
822 {
823 /* 0 terminate each arg. */
824 *dst++ = '\0';
825 argc++;
826 state = SKIP_WS;
827 if (argc >= MAX_ARGS)
828 break;
829 }
830 else
831 *dst++ = *ptr;
832 }
833
834 if (state == QUOTED_ARG)
835 {
836 if (*ptr == '\\')
837 {
838 state = QUOTED_ARG_ESCAPED;
839 continue;
840 }
841 if (*ptr == quote_ch)
842 {
843 /* 0 terminate each arg. */
844 *dst++ = '\0';
845 argc++;
846 state = SKIP_WS;
847 if (argc >= MAX_ARGS)
848 break;
849 }
850 else
851 *dst++ = *ptr;
852 }
853
854 if (state == READ_ARG_ESCAPED)
855 {
856 *dst++ = *ptr;
857 state = READ_ARG;
858 }
859
860 if (state == QUOTED_ARG_ESCAPED)
861 {
862 *dst++ = *ptr;
863 state = QUOTED_ARG;
864 }
865 }
866
867 if (state != SKIP_WS)
868 {
869 /* Terminate last arg. */
870 *dst++ = '\0';
871 argc++;
872 }
873
874 /* Teminate arg vector. */
875 argvec[argc] = NULL;
876
877 *pargv = argvec;
878 *pargc = argc;
879 }
880
881 /* Print a (hopefully) useful usage message. */
882 static int
883 usage(void)
884 {
885 printf(
886 "Usage: %s [-h] [-i] [-l] [-p prompt] [-q] [-v] [command] [opt ...]\n"
887 " -i Run in interactive mode.\n"
888 " -l Run /usr/bin/leaks -nocontext before exiting.\n"
889 " -p Set the prompt to \"prompt\" (implies -i).\n"
890 " -q Be less verbose.\n"
891 " -v Be more verbose about what's going on.\n"
892 "%s commands are:\n", prog_name, prog_name);
893 help(0, NULL);
894 return 2;
895 }
896
897 /* Execute a single command. */
898 static int
899 execute_command(int argc, char * const *argv)
900 {
901 const command *c;
902 int found = 0;
903
904 /* Nothing to do. */
905 if (argc == 0)
906 return 0;
907
908 for (c = commands; c->c_name; ++c)
909 {
910 if (match_command(c->c_name, argv[0]))
911 {
912 found = 1;
913 break;
914 }
915 }
916
917 if (found)
918 {
919 int result;
920
921 /* Reset getopt for command proc. */
922 optind = 1;
923 optreset = 1;
924
925 if (do_verbose)
926 {
927 int ix;
928
929 fprintf(stderr, "%s", c->c_name);
930 for (ix = 1; ix < argc; ++ix)
931 fprintf(stderr, " \"%s\"", argv[ix]);
932 fprintf(stderr, "\n");
933 }
934
935 result = c->c_func(argc, argv);
936 if (result == 2)
937 fprintf(stderr, "Usage: %s %s\n %s\n", c->c_name, c->c_usage, c->c_help);
938
939 return result;
940 }
941 else
942 {
943 sec_error("unknown command \"%s\"", argv[0]);
944 return 1;
945 }
946 }
947
948 static void
949 receive_notifications(void)
950 {
951 /* Run the CFRunloop to get any pending notifications. */
952 while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.0, TRUE) == kCFRunLoopRunHandledSource);
953 }
954
955
956 const char *
957 sec_errstr(int err)
958 {
959 const char *errString;
960 if (IS_SEC_ERROR(err))
961 errString = SECErrorString(err);
962 else
963 errString = cssmErrorString(err);
964 return errString;
965 }
966
967 void
968 sec_error(const char *msg, ...)
969 {
970 va_list args;
971
972 fprintf(stderr, "%s: ", prog_name);
973
974 va_start(args, msg);
975 vfprintf(stderr, msg, args);
976 va_end(args);
977
978 fprintf(stderr, "\n");
979 }
980
981 void
982 sec_perror(const char *msg, int err)
983 {
984 sec_error("%s: %s", msg, sec_errstr(err));
985 }
986
987 int
988 main(int argc, char * const *argv)
989 {
990 int result = 0;
991 int do_help = 0;
992 int do_interactive = 0;
993 int do_leaks = 0;
994 int ch;
995
996
997 /* Remember my name. */
998 prog_name = strrchr(argv[0], '/');
999 prog_name = prog_name ? prog_name + 1 : argv[0];
1000
1001 /* Do getopt stuff for global options. */
1002 optind = 1;
1003 optreset = 1;
1004 while ((ch = getopt(argc, argv, "hilp:qvR")) != -1)
1005 {
1006 switch (ch)
1007 {
1008 case 'h':
1009 do_help = 1;
1010 break;
1011 case 'i':
1012 do_interactive = 1;
1013 break;
1014 case 'l':
1015 do_leaks = 1;
1016 break;
1017 case 'p':
1018 do_interactive = 1;
1019 prompt_string = optarg;
1020 break;
1021 case 'q':
1022 do_quiet = 1;
1023 break;
1024 case 'v':
1025 do_verbose = 1;
1026 break;
1027 case 'R':
1028 // "Recovery mode", do NOT ask security-checksystem to run when using keychain APIs
1029 // NOTE: this is a hidden option (not in the usage message)
1030 SecKeychainSystemKeychainCheckWouldDeadlock();
1031 break;
1032 case '?':
1033 default:
1034 return usage();
1035 }
1036 }
1037
1038 argc -= optind;
1039 argv += optind;
1040
1041 if (do_help)
1042 {
1043 /* Munge argc/argv so that argv[0] is something. */
1044 return help(argc + 1, argv - 1);
1045 }
1046 else if (argc > 0)
1047 {
1048 receive_notifications();
1049 result = execute_command(argc, argv);
1050 receive_notifications();
1051 }
1052 else if (do_interactive)
1053 {
1054 /* In interactive mode we just read commands and run them until readline returns NULL. */
1055
1056 /* Only show prompt string if stdin is a tty. */
1057 int show_prompt = isatty(0);
1058
1059 for (;;)
1060 {
1061 static char buffer[MAX_LINE_LEN];
1062 char * const *av, *input;
1063 int ac;
1064
1065 if (show_prompt)
1066 fprintf(stderr, "%s", prompt_string);
1067
1068 input = readline(buffer, MAX_LINE_LEN);
1069 if (!input)
1070 break;
1071
1072 split_line(input, &ac, &av);
1073 receive_notifications();
1074 result = execute_command(ac, av);
1075 receive_notifications();
1076 if (result == -1)
1077 {
1078 result = 0;
1079 break;
1080 }
1081
1082 if (result && ! do_quiet)
1083 {
1084 fprintf(stderr, "%s: returned %d\n", av[0], result);
1085 }
1086 }
1087 }
1088 else
1089 result = usage();
1090
1091 if (do_leaks)
1092 {
1093 char *const argvec[3] = { "leaks", "-nocontext", NULL };
1094 leaks(2, argvec);
1095 }
1096
1097 return result;
1098 }