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