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