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