/*
- * Copyright (c) 1999-2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
- *
+ *
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
- *
+ *
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
- *
+ *
* @APPLE_LICENSE_HEADER_END@
*/
#include <stdio.h>
#include <pwd.h>
#include <sys/sysctl.h>
+#include "passwd.h"
+
+#ifdef INFO_OPEN_DIRECTORY
+
#include <CoreFoundation/CoreFoundation.h>
#include <OpenDirectory/OpenDirectory.h>
#include <OpenDirectory/OpenDirectoryPriv.h>
-#include <DirectoryService/DirServicesTypes.h>
extern char* progname;
int master_mode;
}
desc = CFErrorCopyFailureReason(error);
if (desc) cfprintf(stderr, " %@", desc);
-
+
desc = CFErrorCopyRecoverySuggestion(error);
if (desc) cfprintf(stderr, " %@", desc);
-
- fprintf(stderr, "\n");
- }
-}
-static int
-is_singleuser(void) {
- uint32_t su = 0;
- size_t susz = sizeof(su);
- if (sysctlbyname("kern.singleuser", &su, &susz, NULL, 0) != 0) {
- return 0;
- } else {
- return (int)su;
- }
-}
-
-static int
-load_DirectoryServicesLocal() {
- const char* launchctl = "/bin/launchctl";
- const char* plist = "/System/Library/LaunchDaemons/com.apple.DirectoryServicesLocal.plist";
-
- pid_t pid = fork();
- int status, res;
- switch (pid) {
- case -1: // ERROR
- perror("launchctl");
- return 0;
- case 0: // CHILD
- execl(launchctl, launchctl, "load", plist, NULL);
- /* NOT REACHED */
- perror("launchctl");
- exit(1);
- break;
- default: // PARENT
- do {
- res = waitpid(pid, &status, 0);
- } while (res == -1 && errno == EINTR);
- if (res == -1) {
- perror("launchctl");
- return 0;
- }
- break;
+ fprintf(stderr, "\n");
}
- return (WIFEXITED(status) && (WEXITSTATUS(status) == EXIT_SUCCESS));
}
int
od_passwd(char* uname, char* locn, char* aname)
{
- int change_pass_on_self;
- CFErrorRef error = NULL;
+ int change_pass_on_self;
+ CFErrorRef error = NULL;
CFStringRef username = NULL;
CFStringRef location = NULL;
CFStringRef authname = NULL;
- ODSessionRef session = NULL;
- ODNodeRef node = NULL;
+ ODNodeRef node = NULL;
ODRecordRef rec = NULL;
CFStringRef oldpass = NULL;
CFStringRef newpass = NULL;
-
+
if (uname == NULL)
return -1;
aname = strdup(uname);
}
- master_mode = (getuid() == 0);
+ master_mode = (geteuid() == 0);
change_pass_on_self = (strcmp(aname, uname) == 0);
if (locn) {
if (!username) return -1;
}
- /*
- * Connect to DS server
- */
- session = ODSessionCreate(NULL, NULL, &error);
- if ( !session && error && CFErrorGetCode(error) == eServerNotRunning ) {
- /*
- * In single-user mode, attempt to load the local DS daemon.
- */
- if (is_singleuser() && load_DirectoryServicesLocal()) {
- CFTypeRef keys[] = { kODSessionLocalPath };
- CFTypeRef vals[] = { CFSTR("/var/db/dslocal") };
- CFDictionaryRef opts = CFDictionaryCreate(NULL, keys, vals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- if (opts) {
- session = ODSessionCreate(NULL, opts, &error);
- CFRelease(opts);
- }
-
- if (!location) {
- location = CFRetain(CFSTR("/Local/Default"));
- }
- } else {
- show_error(error);
- return -1;
- }
- }
-
-
/*
* Copy the record from the specified node, or perform a search.
*/
if (location) {
- node = ODNodeCreateWithName(NULL, session, location, &error);
+ node = ODNodeCreateWithName(NULL, kODSessionDefault, location, &error);
} else {
- node = ODNodeCreateWithNodeType(NULL, session, kODTypeAuthenticationSearchNode, &error);
+ node = ODNodeCreateWithNodeType(NULL, kODSessionDefault, kODNodeTypeAuthentication, &error);
}
- if (session) CFRelease(session);
-
if (node) {
- rec = ODNodeCopyRecord(node, CFSTR(kDSStdRecordTypeUsers), username, NULL, &error );
+ rec = ODNodeCopyRecord(node, kODRecordTypeUsers, username, NULL, &error );
CFRelease(node);
}
* Get the actual location.
*/
CFArrayRef values = NULL;
- values = ODRecordCopyValues(rec, CFSTR(kDSNAttrMetaNodeLocation), &error);
+ values = ODRecordCopyValues(rec, kODAttributeTypeMetaNodeLocation, &error);
location = (values && CFArrayGetCount(values) > 0) ? CFArrayGetValueAtIndex(values, 0) : location;
-
+
printf("Changing password for %s.\n", uname);
+ bool isSecureToken = false;
+ if (master_mode) {
+ CFArrayRef authorityValues = NULL;
+ authorityValues = ODRecordCopyValues(rec, kODAttributeTypeAuthenticationAuthority, &error);
+ if (authorityValues != NULL) {
+ isSecureToken = CFArrayContainsValue(authorityValues, CFRangeMake(0, CFArrayGetCount(authorityValues)), (const void *)CFSTR(";SecureToken;"));
+ CFRelease(authorityValues);
+ }
+ }
+
/*
- * Prompt for password if not super-user, or if changing a remote node.
+ * Prompt for password if not super-user, or if changing a remote node, or if changing a record that uses SecureToken.
*/
- int needs_auth = (!master_mode || CFStringCompareWithOptions(location, CFSTR("/Local/"), CFRangeMake(0, 7), 0) != kCFCompareEqualTo);
+ int needs_auth = (!master_mode || CFStringCompareWithOptions(location, CFSTR("/Local/"), CFRangeMake(0, 7), 0) != kCFCompareEqualTo || isSecureToken);
if (needs_auth) {
char prompt[BUFSIZ];
if (p) {
oldpass = CFStringCreateWithCString(NULL, p, kCFStringEncodingUTF8);
memset(p, 0, strlen(p));
+
+ if (!change_pass_on_self) {
+ if (!ODRecordSetNodeCredentials(rec, authname, oldpass, &error)) {
+ show_error(error);
+ exit(1);
+ }
+ CFRelease(oldpass);
+ oldpass = NULL;
+ }
}
}
printf("Password unchanged.\n");
exit(0);
}
-
+
p = getpass("Retype new password:");
if (p) {
CFStringRef verify = CFStringCreateWithCString(NULL, p, kCFStringEncodingUTF8);
}
}
- if (needs_auth) {
- CFTypeRef values[] = { username, newpass, authname, oldpass };
- CFArrayRef authItems = CFArrayCreate(NULL, values, 4, &kCFTypeArrayCallBacks);
-
- ODRecordSetNodeCredentialsExtended(rec,
- CFSTR(kDSStdRecordTypeUsers),
- CFSTR(kDSStdAuthSetPasswd),
- authItems,
- NULL,
- NULL,
- &error);
-
- CFRelease(authItems);
- } else {
- ODRecordChangePassword(rec, oldpass, newpass, &error);
- }
+ ODRecordChangePassword(rec, oldpass, newpass, &error);
if (error) {
show_error(error);
case eDSAuthPasswordTooShort:
errMsgStr = "The new password is too short.";
break;
-
+
case eDSAuthPasswordTooLong:
errMsgStr = "The new password is too long.";
break;
-
+
case eDSAuthPasswordNeedsLetter:
errMsgStr = "The new password must contain a letter.";
break;
-
+
case eDSAuthPasswordNeedsDigit:
errMsgStr = "The new password must contain a number.";
break;
-
+
default:
errMsgStr = "Sorry";
}
#endif
return 0;
}
+
+#endif /* INFO_OPEN_DIRECTORY */