2 * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 #include <sys/sysctl.h>
30 #ifdef INFO_OPEN_DIRECTORY
32 #include <CoreFoundation/CoreFoundation.h>
33 #include <OpenDirectory/OpenDirectory.h>
34 #include <OpenDirectory/OpenDirectoryPriv.h>
36 extern char* progname
;
40 cfprintf(FILE* file
, const char* format
, ...) {
44 va_start(args
, format
);
45 CFStringRef formatStr
= CFStringCreateWithCStringNoCopy(NULL
, format
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
47 CFStringRef str
= CFStringCreateWithFormatAndArguments(NULL
, NULL
, formatStr
, args
);
49 size_t size
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(str
), kCFStringEncodingUTF8
) + 1;
52 if (cstr
&& CFStringGetCString(str
, cstr
, size
, kCFStringEncodingUTF8
)) {
53 result
= fprintf(file
, "%s", cstr
);
64 show_error(CFErrorRef error
) {
66 CFStringRef desc
= CFErrorCopyDescription(error
);
68 cfprintf(stderr
, "%s: %@", progname
, desc
);
71 desc
= CFErrorCopyFailureReason(error
);
72 if (desc
) cfprintf(stderr
, " %@", desc
);
74 desc
= CFErrorCopyRecoverySuggestion(error
);
75 if (desc
) cfprintf(stderr
, " %@", desc
);
77 fprintf(stderr
, "\n");
82 od_passwd(char* uname
, char* locn
, char* aname
)
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
;
98 * If no explicit authorization name was specified (via -u)
99 * then default to the target user.
102 aname
= strdup(uname
);
105 master_mode
= (geteuid() == 0);
106 change_pass_on_self
= (strcmp(aname
, uname
) == 0);
109 location
= CFStringCreateWithCString(NULL
, locn
, kCFStringEncodingUTF8
);
113 authname
= CFStringCreateWithCString(NULL
, aname
, kCFStringEncodingUTF8
);
117 username
= CFStringCreateWithCString(NULL
, uname
, kCFStringEncodingUTF8
);
118 if (!username
) return -1;
122 * Copy the record from the specified node, or perform a search.
125 node
= ODNodeCreateWithName(NULL
, kODSessionDefault
, location
, &error
);
127 node
= ODNodeCreateWithNodeType(NULL
, kODSessionDefault
, kODNodeTypeAuthentication
, &error
);
131 rec
= ODNodeCopyRecord(node
, kODRecordTypeUsers
, username
, NULL
, &error
);
139 fprintf(stderr
, "%s: Unknown user name '%s'.\n", progname
, uname
);
145 * Get the actual location.
147 CFArrayRef values
= NULL
;
148 values
= ODRecordCopyValues(rec
, kODAttributeTypeMetaNodeLocation
, &error
);
149 location
= (values
&& CFArrayGetCount(values
) > 0) ? CFArrayGetValueAtIndex(values
, 0) : location
;
151 printf("Changing password for %s.\n", uname
);
153 bool isSecureToken
= false;
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
);
164 * Prompt for password if not super-user, or if changing a remote node, or if changing a record that uses SecureToken.
166 int needs_auth
= (!master_mode
|| CFStringCompareWithOptions(location
, CFSTR("/Local/"), CFRangeMake(0, 7), 0) != kCFCompareEqualTo
|| isSecureToken
);
170 if (change_pass_on_self
) {
171 strlcpy(prompt
, "Old password:", sizeof(prompt
));
173 snprintf(prompt
, sizeof(prompt
), "Password for %s:", aname
);
175 char *p
= getpass( prompt
);
177 oldpass
= CFStringCreateWithCString(NULL
, p
, kCFStringEncodingUTF8
);
178 memset(p
, 0, strlen(p
));
180 if (!change_pass_on_self
) {
181 if (!ODRecordSetNodeCredentials(rec
, authname
, oldpass
, &error
)) {
192 char *p
= getpass("New password:");
193 if (p
&& strlen(p
) > 0) {
194 newpass
= CFStringCreateWithCString(NULL
, p
, kCFStringEncodingUTF8
);
195 memset(p
, 0, strlen(p
));
197 printf("Password unchanged.\n");
201 p
= getpass("Retype new password:");
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");
214 ODRecordChangePassword(rec
, oldpass
, newpass
, &error
);
221 if (oldpass
) CFRelease(oldpass
);
222 if (newpass
) CFRelease(newpass
);
225 if ( status
!= eDSNoErr
) {
228 case eDSAuthPasswordTooShort
:
229 errMsgStr
= "The new password is too short.";
232 case eDSAuthPasswordTooLong
:
233 errMsgStr
= "The new password is too long.";
236 case eDSAuthPasswordNeedsLetter
:
237 errMsgStr
= "The new password must contain a letter.";
240 case eDSAuthPasswordNeedsDigit
:
241 errMsgStr
= "The new password must contain a number.";
247 fprintf(stderr
, "%s\n", errMsgStr
);
253 #endif /* INFO_OPEN_DIRECTORY */