1/* 2 * Copyright (c) 2003-2009 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 * keychain_set_settings.c 24 */ 25 26#include "keychain_set_settings.h" 27#include "keychain_utilities.h" 28#include "readline.h" 29#include "security.h" 30 31#include <limits.h> 32#include <stdio.h> 33#include <stdlib.h> 34#include <string.h> 35#include <unistd.h> 36#include <Security/SecKeychain.h> 37#include <Security/SecKeychainPriv.h> 38 39#define PW_BUF_SIZE 512 /* size of buffer to alloc for password */ 40 41 42static int 43do_keychain_set_settings(const char *keychainName, SecKeychainSettings newKeychainSettings) 44{ 45 SecKeychainRef keychain = NULL; 46 OSStatus result; 47 48 if (keychainName) 49 { 50 keychain = keychain_open(keychainName); 51 if (!keychain) 52 { 53 result = 1; 54 goto cleanup; 55 } 56 } 57 result = SecKeychainSetSettings(keychain, &newKeychainSettings); 58 if (result) 59 { 60 sec_error("SecKeychainSetSettings %s: %s", keychainName ? keychainName : "<NULL>", sec_errstr(result)); 61 } 62 63cleanup: 64 if (keychain) 65 CFRelease(keychain); 66 67 return result; 68} 69 70 71static int 72do_keychain_set_password(const char *keychainName, const char* oldPassword, const char* newPassword) 73{ 74 SecKeychainRef keychain = NULL; 75 OSStatus result = 1; 76 UInt32 oldLen = (oldPassword) ? strlen(oldPassword) : 0; 77 UInt32 newLen = (newPassword) ? strlen(newPassword) : 0; 78 char *oldPass = (oldPassword) ? (char*)oldPassword : NULL; 79 char *newPass = (newPassword) ? (char*)newPassword : NULL; 80 char *oldBuf = NULL; 81 char *newBuf = NULL; 82 83 if (keychainName) 84 { 85 keychain = keychain_open(keychainName); 86 if (!keychain) 87 { 88 result = 1; 89 goto cleanup; 90 } 91 } 92 93 if (!oldPass) { 94 /* prompt for old password */ 95 char *pBuf = getpass("Old Password: "); 96 if (pBuf) { 97 oldBuf = (char*) calloc(PW_BUF_SIZE, 1); 98 oldLen = strlen(pBuf); 99 memcpy(oldBuf, pBuf, oldLen); 100 bzero(pBuf, oldLen); 101 oldPass = oldBuf; 102 } 103 } 104 105 if (!newPass) { 106 /* prompt for new password */ 107 char *pBuf = getpass("New Password: "); 108 if (pBuf) { 109 newBuf = (char*) calloc(PW_BUF_SIZE, 1); 110 newLen = strlen(pBuf); 111 memcpy(newBuf, pBuf, newLen); 112 bzero(pBuf, newLen); 113 } 114 /* confirm new password */ 115 pBuf = getpass("Retype New Password: "); 116 if (pBuf) { 117 UInt32 confirmLen = strlen(pBuf); 118 if (confirmLen == newLen && newBuf && 119 !memcmp(pBuf, newBuf, newLen)) { 120 newPass = newBuf; 121 } 122 bzero(pBuf, confirmLen); 123 } 124 } 125 126 if (!oldPass || !newPass) { 127 sec_error("try again"); 128 goto cleanup; 129 } 130 131 /* lock keychain first to remove existing credentials */ 132 (void)SecKeychainLock(keychain); 133 134 /* change the password */ 135 result = SecKeychainChangePassword(keychain, oldLen, oldPass, newLen, newPass); 136 if (result) 137 { 138 sec_error("error changing password for \"%s\": %s", 139 keychainName ? keychainName : "<NULL>", sec_errstr(result)); 140 } 141 142cleanup: 143 /* if we allocated password buffers, zero and free them */ 144 if (oldBuf) { 145 bzero(oldBuf, PW_BUF_SIZE); 146 free(oldBuf); 147 } 148 if (newBuf) { 149 bzero(newBuf, PW_BUF_SIZE); 150 free(newBuf); 151 } 152 if (keychain) { 153 CFRelease(keychain); 154 } 155 return result; 156} 157 158 159int 160keychain_set_settings(int argc, char * const *argv) 161{ 162 char *keychainName = NULL; 163 int ch, result = 0; 164 SecKeychainSettings newKeychainSettings = 165 { SEC_KEYCHAIN_SETTINGS_VERS1, FALSE, FALSE, INT_MAX }; 166 167 while ((ch = getopt(argc, argv, "hlt:u")) != -1) 168 { 169 switch (ch) 170 { 171 case 'l': 172 newKeychainSettings.lockOnSleep = TRUE; 173 break; 174 case 't': 175 newKeychainSettings.lockInterval = atoi(optarg); 176 break; 177 case 'u': 178 newKeychainSettings.useLockInterval = TRUE; 179 break; 180 case '?': 181 default: 182 result = 2; /* @@@ Return 2 triggers usage message. */ 183 goto cleanup; 184 } 185 } 186 187 if (newKeychainSettings.lockInterval != INT_MAX) { 188 // -t was specified, which implies -u 189 newKeychainSettings.useLockInterval = TRUE; 190 } else { 191 // -t was unspecified, so revert to no timeout 192 newKeychainSettings.useLockInterval = FALSE; 193 } 194 195 argc -= optind; 196 argv += optind; 197 198 if (argc == 1) 199 { 200 keychainName = argv[0]; 201 if (*keychainName == '\0') 202 { 203 result = 2; 204 goto cleanup; 205 } 206 } 207 else if (argc != 0) 208 { 209 result = 2; 210 goto cleanup; 211 } 212 213 result = do_keychain_set_settings(keychainName, newKeychainSettings); 214 215cleanup: 216 217 return result; 218} 219 220int 221keychain_set_password(int argc, char * const *argv) 222{ 223 char *keychainName = NULL; 224 char *oldPassword = NULL; 225 char *newPassword = NULL; 226 int ch, result = 0; 227 228 while ((ch = getopt(argc, argv, "ho:p:")) != -1) 229 { 230 switch (ch) 231 { 232 case 'o': 233 oldPassword = optarg; 234 break; 235 case 'p': 236 newPassword = optarg; 237 break; 238 case '?': 239 default: 240 result = 2; /* @@@ Return 2 triggers usage message. */ 241 goto cleanup; 242 } 243 } 244 245 argc -= optind; 246 argv += optind; 247 248 if (argc == 1) 249 { 250 keychainName = argv[0]; 251 if (*keychainName == '\0') 252 { 253 result = 2; 254 goto cleanup; 255 } 256 } 257 else if (argc != 0) 258 { 259 result = 2; 260 goto cleanup; 261 } 262 263 result = do_keychain_set_password(keychainName, oldPassword, newPassword); 264 265cleanup: 266 267 return result; 268} 269 270