]> git.saurik.com Git - apple/system_cmds.git/blob - passwd.tproj/od_passwd.c
system_cmds-735.20.1.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 = (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 */