1/* 2 * Copyright (c) 1999-2006 Apple Computer, 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#include <stdio.h> 24#include <unistd.h> 25#include <pwd.h> 26#include <sys/sysctl.h> 27 28#include "passwd.h" 29 30#ifdef INFO_OPEN_DIRECTORY 31 32#include <CoreFoundation/CoreFoundation.h> 33#include <OpenDirectory/OpenDirectory.h> 34#include <OpenDirectory/OpenDirectoryPriv.h> 35 36extern char* progname; 37int master_mode; 38 39static int 40cfprintf(FILE* file, const char* format, ...) { 41 char* cstr; 42 int result = 0; 43 va_list args; 44 va_start(args, format); 45 CFStringRef formatStr = CFStringCreateWithCStringNoCopy(NULL, format, kCFStringEncodingUTF8, kCFAllocatorNull); 46 if (formatStr) { 47 CFStringRef str = CFStringCreateWithFormatAndArguments(NULL, NULL, formatStr, args); 48 if (str) { 49 size_t size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), kCFStringEncodingUTF8) + 1; 50 va_end(args); 51 cstr = malloc(size); 52 if (cstr && CFStringGetCString(str, cstr, size, kCFStringEncodingUTF8)) { 53 result = fprintf(file, "%s", cstr); 54 free(cstr); 55 } 56 CFRelease(str); 57 } 58 CFRelease(formatStr); 59 } 60 return result; 61} 62 63static void 64show_error(CFErrorRef error) { 65 if (error) { 66 CFStringRef desc = CFErrorCopyDescription(error); 67 if (desc) { 68 cfprintf(stderr, "%s: %@", progname, desc); 69 CFRelease(desc); 70 } 71 desc = CFErrorCopyFailureReason(error); 72 if (desc) cfprintf(stderr, " %@", desc); 73 74 desc = CFErrorCopyRecoverySuggestion(error); 75 if (desc) cfprintf(stderr, " %@", desc); 76 77 fprintf(stderr, "\n"); 78 } 79} 80 81int 82od_passwd(char* uname, char* locn, char* aname) 83{ 84 int change_pass_on_self; 85 CFErrorRef error = NULL; 86 CFStringRef username = NULL; 87 CFStringRef location = NULL; 88 CFStringRef authname = NULL; 89 ODNodeRef node = NULL; 90 ODRecordRef rec = NULL; 91 CFStringRef oldpass = NULL; 92 CFStringRef newpass = NULL; 93 94 if (uname == NULL) 95 return -1; 96 97 /* 98 * If no explicit authorization name was specified (via -u) 99 * then default to the target user. 100 */ 101 if (!aname) { 102 aname = strdup(uname); 103 } 104 105 master_mode = (getuid() == 0); 106 change_pass_on_self = (strcmp(aname, uname) == 0); 107 108 if (locn) { 109 location = CFStringCreateWithCString(NULL, locn, kCFStringEncodingUTF8); 110 } 111 112 if (aname) { 113 authname = CFStringCreateWithCString(NULL, aname, kCFStringEncodingUTF8); 114 } 115 116 if (uname) { 117 username = CFStringCreateWithCString(NULL, uname, kCFStringEncodingUTF8); 118 if (!username) return -1; 119 } 120 121 /* 122 * Copy the record from the specified node, or perform a search. 123 */ 124 if (location) { 125 node = ODNodeCreateWithName(NULL, kODSessionDefault, location, &error); 126 } else { 127 node = ODNodeCreateWithNodeType(NULL, kODSessionDefault, kODNodeTypeAuthentication, &error); 128 } 129 130 if (node) { 131 rec = ODNodeCopyRecord(node, kODRecordTypeUsers, username, NULL, &error ); 132 CFRelease(node); 133 } 134 135 if (!rec) { 136 if (error) { 137 show_error(error); 138 } else { 139 fprintf(stderr, "%s: Unknown user name '%s'.\n", progname, uname); 140 } 141 return -1; 142 } 143 144 /* 145 * Get the actual location. 146 */ 147 CFArrayRef values = NULL; 148 values = ODRecordCopyValues(rec, kODAttributeTypeMetaNodeLocation, &error); 149 location = (values && CFArrayGetCount(values) > 0) ? CFArrayGetValueAtIndex(values, 0) : location; 150 151 printf("Changing password for %s.\n", uname); 152 153 /* 154 * Prompt for password if not super-user, or if changing a remote node. 155 */ 156 int needs_auth = (!master_mode || CFStringCompareWithOptions(location, CFSTR("/Local/"), CFRangeMake(0, 7), 0) != kCFCompareEqualTo); 157 158 if (needs_auth) { 159 char prompt[BUFSIZ]; 160 if (change_pass_on_self) { 161 strlcpy(prompt, "Old password:", sizeof(prompt)); 162 } else { 163 snprintf(prompt, sizeof(prompt), "Password for %s:", aname); 164 } 165 char *p = getpass( prompt ); 166 if (p) { 167 oldpass = CFStringCreateWithCString(NULL, p, kCFStringEncodingUTF8); 168 memset(p, 0, strlen(p)); 169 } 170 } 171 172 for (;;) { 173 char *p = getpass("New password:"); 174 if (p && strlen(p) > 0) { 175 newpass = CFStringCreateWithCString(NULL, p, kCFStringEncodingUTF8); 176 memset(p, 0, strlen(p)); 177 } else { 178 printf("Password unchanged.\n"); 179 exit(0); 180 } 181 182 p = getpass("Retype new password:"); 183 if (p) { 184 CFStringRef verify = CFStringCreateWithCString(NULL, p, kCFStringEncodingUTF8); 185 if (!verify || !CFEqual(newpass, verify)) { 186 if (verify) CFRelease(verify); 187 printf("Mismatch; try again, EOF to quit.\n"); 188 } else { 189 CFRelease(verify); 190 break; 191 } 192 } 193 } 194 195 ODRecordChangePassword(rec, oldpass, newpass, &error); 196 197 if (error) { 198 show_error(error); 199 exit(1); 200 } 201 202 if (oldpass) CFRelease(oldpass); 203 if (newpass) CFRelease(newpass); 204 205#if 0 206 if ( status != eDSNoErr ) { 207 switch( status ) 208 { 209 case eDSAuthPasswordTooShort: 210 errMsgStr = "The new password is too short."; 211 break; 212 213 case eDSAuthPasswordTooLong: 214 errMsgStr = "The new password is too long."; 215 break; 216 217 case eDSAuthPasswordNeedsLetter: 218 errMsgStr = "The new password must contain a letter."; 219 break; 220 221 case eDSAuthPasswordNeedsDigit: 222 errMsgStr = "The new password must contain a number."; 223 break; 224 225 default: 226 errMsgStr = "Sorry"; 227 } 228 fprintf(stderr, "%s\n", errMsgStr); 229 exit(1); 230#endif 231 return 0; 232} 233 234#endif /* INFO_OPEN_DIRECTORY */ 235