]> git.saurik.com Git - apple/system_cmds.git/blob - passwd.tproj/od_passwd.c
system_cmds-880.100.5.tar.gz
[apple/system_cmds.git] / passwd.tproj / od_passwd.c
1 /*
2 * Copyright (c) 1999-2016 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 #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
36 extern char* progname;
37 int master_mode;
38
39 static int
40 cfprintf(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
63 static void
64 show_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
81 int
82 od_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 = (geteuid() == 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 bool isSecureToken = false;
154 if (master_mode) {
155 CFArrayRef authorityValues = NULL;
156 authorityValues = ODRecordCopyValues(rec, kODAttributeTypeAuthenticationAuthority, &error);
157 if (authorityValues != NULL) {
158 isSecureToken = CFArrayContainsValue(authorityValues, CFRangeMake(0, CFArrayGetCount(authorityValues)), (const void *)CFSTR(";SecureToken;"));
159 CFRelease(authorityValues);
160 }
161 }
162
163 /*
164 * Prompt for password if not super-user, or if changing a remote node, or if changing a record that uses SecureToken.
165 */
166 int needs_auth = (!master_mode || CFStringCompareWithOptions(location, CFSTR("/Local/"), CFRangeMake(0, 7), 0) != kCFCompareEqualTo || isSecureToken);
167
168 if (needs_auth) {
169 char prompt[BUFSIZ];
170 if (change_pass_on_self) {
171 strlcpy(prompt, "Old password:", sizeof(prompt));
172 } else {
173 snprintf(prompt, sizeof(prompt), "Password for %s:", aname);
174 }
175 char *p = getpass( prompt );
176 if (p) {
177 oldpass = CFStringCreateWithCString(NULL, p, kCFStringEncodingUTF8);
178 memset(p, 0, strlen(p));
179
180 if (!change_pass_on_self) {
181 if (!ODRecordSetNodeCredentials(rec, authname, oldpass, &error)) {
182 show_error(error);
183 exit(1);
184 }
185 CFRelease(oldpass);
186 oldpass = NULL;
187 }
188 }
189 }
190
191 for (;;) {
192 char *p = getpass("New password:");
193 if (p && strlen(p) > 0) {
194 newpass = CFStringCreateWithCString(NULL, p, kCFStringEncodingUTF8);
195 memset(p, 0, strlen(p));
196 } else {
197 printf("Password unchanged.\n");
198 exit(0);
199 }
200
201 p = getpass("Retype new password:");
202 if (p) {
203 CFStringRef verify = CFStringCreateWithCString(NULL, p, kCFStringEncodingUTF8);
204 if (!verify || !CFEqual(newpass, verify)) {
205 if (verify) CFRelease(verify);
206 printf("Mismatch; try again, EOF to quit.\n");
207 } else {
208 CFRelease(verify);
209 break;
210 }
211 }
212 }
213
214 ODRecordChangePassword(rec, oldpass, newpass, &error);
215
216 if (error) {
217 show_error(error);
218 exit(1);
219 }
220
221 if (oldpass) CFRelease(oldpass);
222 if (newpass) CFRelease(newpass);
223
224 #if 0
225 if ( status != eDSNoErr ) {
226 switch( status )
227 {
228 case eDSAuthPasswordTooShort:
229 errMsgStr = "The new password is too short.";
230 break;
231
232 case eDSAuthPasswordTooLong:
233 errMsgStr = "The new password is too long.";
234 break;
235
236 case eDSAuthPasswordNeedsLetter:
237 errMsgStr = "The new password must contain a letter.";
238 break;
239
240 case eDSAuthPasswordNeedsDigit:
241 errMsgStr = "The new password must contain a number.";
242 break;
243
244 default:
245 errMsgStr = "Sorry";
246 }
247 fprintf(stderr, "%s\n", errMsgStr);
248 exit(1);
249 #endif
250 return 0;
251 }
252
253 #endif /* INFO_OPEN_DIRECTORY */