]> git.saurik.com Git - apple/system_cmds.git/blame - passwd.tproj/od_passwd.c
system_cmds-805.200.21.tar.gz
[apple/system_cmds.git] / passwd.tproj / od_passwd.c
CommitLineData
34d340d7 1/*
cf37c299 2 * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
34d340d7
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
cf37c299 5 *
34d340d7
A
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.
cf37c299 12 *
34d340d7
A
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.
cf37c299 20 *
34d340d7
A
21 * @APPLE_LICENSE_HEADER_END@
22 */
23#include <stdio.h>
24#include <unistd.h>
25#include <pwd.h>
26#include <sys/sysctl.h>
27
aaff5f01
A
28#include "passwd.h"
29
30#ifdef INFO_OPEN_DIRECTORY
31
34d340d7
A
32#include <CoreFoundation/CoreFoundation.h>
33#include <OpenDirectory/OpenDirectory.h>
34#include <OpenDirectory/OpenDirectoryPriv.h>
34d340d7
A
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);
cf37c299 73
34d340d7
A
74 desc = CFErrorCopyRecoverySuggestion(error);
75 if (desc) cfprintf(stderr, " %@", desc);
cf37c299 76
34d340d7
A
77 fprintf(stderr, "\n");
78 }
79}
80
34d340d7
A
81int
82od_passwd(char* uname, char* locn, char* aname)
83{
8459d725
A
84 int change_pass_on_self;
85 CFErrorRef error = NULL;
34d340d7
A
86 CFStringRef username = NULL;
87 CFStringRef location = NULL;
88 CFStringRef authname = NULL;
8459d725 89 ODNodeRef node = NULL;
34d340d7
A
90 ODRecordRef rec = NULL;
91 CFStringRef oldpass = NULL;
92 CFStringRef newpass = NULL;
cf37c299 93
34d340d7
A
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
530d02b6 105 master_mode = (geteuid() == 0);
34d340d7
A
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
34d340d7
A
121 /*
122 * Copy the record from the specified node, or perform a search.
123 */
124 if (location) {
8459d725 125 node = ODNodeCreateWithName(NULL, kODSessionDefault, location, &error);
34d340d7 126 } else {
8459d725 127 node = ODNodeCreateWithNodeType(NULL, kODSessionDefault, kODNodeTypeAuthentication, &error);
34d340d7
A
128 }
129
34d340d7 130 if (node) {
ef8ad44b 131 rec = ODNodeCopyRecord(node, kODRecordTypeUsers, username, NULL, &error );
34d340d7
A
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;
ef8ad44b 148 values = ODRecordCopyValues(rec, kODAttributeTypeMetaNodeLocation, &error);
34d340d7 149 location = (values && CFArrayGetCount(values) > 0) ? CFArrayGetValueAtIndex(values, 0) : location;
cf37c299 150
34d340d7
A
151 printf("Changing password for %s.\n", uname);
152
530d02b6
A
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
34d340d7 163 /*
530d02b6 164 * Prompt for password if not super-user, or if changing a remote node, or if changing a record that uses SecureToken.
34d340d7 165 */
530d02b6 166 int needs_auth = (!master_mode || CFStringCompareWithOptions(location, CFSTR("/Local/"), CFRangeMake(0, 7), 0) != kCFCompareEqualTo || isSecureToken);
34d340d7
A
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));
530d02b6
A
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 }
34d340d7
A
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 }
cf37c299 200
34d340d7
A
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
8459d725 214 ODRecordChangePassword(rec, oldpass, newpass, &error);
34d340d7
A
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;
cf37c299 231
34d340d7
A
232 case eDSAuthPasswordTooLong:
233 errMsgStr = "The new password is too long.";
234 break;
cf37c299 235
34d340d7
A
236 case eDSAuthPasswordNeedsLetter:
237 errMsgStr = "The new password must contain a letter.";
238 break;
cf37c299 239
34d340d7
A
240 case eDSAuthPasswordNeedsDigit:
241 errMsgStr = "The new password must contain a number.";
242 break;
cf37c299 243
34d340d7
A
244 default:
245 errMsgStr = "Sorry";
246 }
247 fprintf(stderr, "%s\n", errMsgStr);
248 exit(1);
249#endif
250 return 0;
251}
aaff5f01
A
252
253#endif /* INFO_OPEN_DIRECTORY */