summaryrefslogtreecommitdiffstats
path: root/system_cmds/passwd.tproj
diff options
context:
space:
mode:
Diffstat (limited to 'system_cmds/passwd.tproj')
-rw-r--r--system_cmds/passwd.tproj/file_passwd.c237
-rw-r--r--system_cmds/passwd.tproj/nis_passwd.c265
-rw-r--r--system_cmds/passwd.tproj/od_passwd.c253
-rw-r--r--system_cmds/passwd.tproj/pam_passwd.c80
-rw-r--r--system_cmds/passwd.tproj/passwd.1134
-rw-r--r--system_cmds/passwd.tproj/passwd.c302
-rw-r--r--system_cmds/passwd.tproj/passwd.entitlements12
-rw-r--r--system_cmds/passwd.tproj/passwd.h47
-rw-r--r--system_cmds/passwd.tproj/passwd.pam5
9 files changed, 1335 insertions, 0 deletions
diff --git a/system_cmds/passwd.tproj/file_passwd.c b/system_cmds/passwd.tproj/file_passwd.c
new file mode 100644
index 0000000..62d27f3
--- /dev/null
+++ b/system_cmds/passwd.tproj/file_passwd.c
@@ -0,0 +1,237 @@
+/*
+ * 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,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * 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 <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include "passwd.h"
+
+#define _PASSWD_FILE "/etc/master.passwd"
+#define _COMPAT_FILE "/etc/passwd"
+#define _PASSWD_FIELDS 10
+#define BUFSIZE 8192
+
+void getpasswd(char *, int, int, int, int, char *, char **, char**, char **);
+
+static struct passwd *
+parse_user(char *line, size_t len)
+{
+ static struct passwd pw;
+ int i,j;
+ char *tokens[_PASSWD_FIELDS];
+ char *token = NULL;
+ bool comment = true;
+
+ free(pw.pw_name);
+ free(pw.pw_passwd);
+ free(pw.pw_class);
+ free(pw.pw_gecos);
+ free(pw.pw_dir);
+ free(pw.pw_shell);
+ memset(&pw, 0, sizeof(pw));
+
+ if (line == NULL) return NULL;
+
+ memset(&tokens, 0, sizeof(char *) * _PASSWD_FIELDS);
+
+ for (i = 0, j = 0; i < len && j < _PASSWD_FIELDS; ++i) {
+ int c = line[i];
+ if (!isspace(c) && c != '#') {
+ comment = false;
+ }
+ if (!comment && token == NULL) {
+ // start a new token
+ token = &line[i];
+ } else if (token && (c == ':' || c == '\n')) {
+ // end the current token
+ // special case for empty token
+ while (token[0] == ':' && token < &line[i]) {
+ tokens[j++] = strdup("");
+ ++token;
+ }
+ tokens[j++] = strndup(token, &line[i] - token);
+ token = NULL;
+ }
+ }
+
+ if (comment || j != _PASSWD_FIELDS) return NULL;
+
+ j = 0;
+ pw.pw_name = tokens[j++];
+ pw.pw_passwd = tokens[j++];
+ pw.pw_uid = atoi(tokens[j]);
+ free(tokens[j++]);
+ pw.pw_gid = atoi(tokens[j]);
+ free(tokens[j++]);
+ pw.pw_class = tokens[j++];
+ pw.pw_change = atoi(tokens[j]);
+ free(tokens[j++]);
+ pw.pw_expire = atoi(tokens[j]);
+ free(tokens[j++]);
+ pw.pw_gecos = tokens[j++];
+ pw.pw_dir = tokens[j++];
+ pw.pw_shell = tokens[j++];
+
+ return &pw;
+}
+
+static struct passwd *
+find_user(FILE *fp, char *uname)
+{
+ size_t len;
+ char *line;
+
+ rewind(fp);
+
+ while ((line = fgetln(fp, &len)) != NULL) {
+ struct passwd *pw = parse_user(line, len);
+ if (pw && strcmp(uname, pw->pw_name) == 0) {
+ return pw;
+ }
+ }
+ return NULL;
+}
+
+static void
+rewrite_file(char *path, FILE *fp, struct passwd *newpw)
+{
+ int fd;
+ char *line;
+ size_t len;
+ FILE *tfp = NULL;
+ char *tempname = NULL; // temporary master.passwd file
+
+ asprintf(&tempname, "%s.XXXXXX", path);
+
+ fd = mkstemp(tempname);
+ if (fd == -1) {
+ err(EXIT_FAILURE, "%s", tempname);
+ }
+ tfp = fdopen(fd, "w+");
+ if (tfp == NULL || fchmod(fd, S_IRUSR | S_IWUSR) != 0) {
+ int save = errno;
+ unlink(tempname);
+ errno = save;
+ err(EXIT_FAILURE, "%s", tempname);
+ }
+
+ while ((line = fgetln(fp, &len)) != NULL) {
+ struct passwd *pw = parse_user(line, len);
+
+ // if this is not the entry we're looking for or if parsing
+ // failed (likely a comment) then print the entry as is.
+ if (pw == NULL || strcmp(newpw->pw_name, pw->pw_name) != 0) {
+ fwrite(line, sizeof(char), len, tfp);
+ } else {
+ fprintf(tfp, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n",
+ newpw->pw_name,
+ newpw->pw_passwd,
+ newpw->pw_uid,
+ newpw->pw_gid,
+ newpw->pw_class,
+ newpw->pw_change,
+ newpw->pw_expire,
+ newpw->pw_gecos,
+ newpw->pw_dir,
+ newpw->pw_shell);
+ }
+ }
+
+ // Move the temporary file into place.
+ if (fclose(tfp) != 0 || rename(tempname, path) != 0) {
+ int save = errno;
+ unlink(tempname);
+ errno = save;
+ err(EXIT_FAILURE, "%s", tempname);
+ }
+
+ free(tempname);
+}
+
+int
+file_passwd(char *uname, char *locn)
+{
+ char *ne, *oc, *nc;
+ int fd;
+ FILE *fp;
+ uid_t uid;
+ char *fname;
+ struct passwd *pw;
+ struct passwd newpw;
+
+ fname = _PASSWD_FILE;
+ if (locn != NULL) fname = locn;
+
+ fd = open(fname, O_RDONLY | O_EXLOCK);
+ if (fd == -1) {
+ err(EXIT_FAILURE, "%s", fname);
+ }
+
+ fp = fdopen(fd, "r");
+ if (fp == NULL) {
+ err(EXIT_FAILURE, "%s", fname);
+ }
+
+ pw = find_user(fp, uname);
+ if (pw == NULL) {
+ errx(EXIT_FAILURE, "user %s not found in %s", uname, fname);
+ }
+
+ uid = getuid();
+ if (uid != 0 && uid != pw->pw_uid) {
+ errno = EACCES;
+ err(EXIT_FAILURE, "%s", uname);
+ }
+
+ // Get the password
+ getpasswd(uname, (uid == 0), 5, 0, 0, pw->pw_passwd, &ne, &oc, &nc);
+
+ newpw.pw_name = strdup(pw->pw_name);
+ newpw.pw_passwd = strdup(ne);
+ newpw.pw_uid = pw->pw_uid;
+ newpw.pw_gid = pw->pw_gid;
+ newpw.pw_class = strdup(pw->pw_class);
+ newpw.pw_change = pw->pw_change;
+ newpw.pw_expire = pw->pw_expire;
+ newpw.pw_gecos = strdup(pw->pw_gecos);
+ newpw.pw_dir = strdup(pw->pw_dir);
+ newpw.pw_shell = strdup(pw->pw_shell);
+
+ // Rewrite the file
+ rewind(fp);
+ rewrite_file(fname, fp, &newpw);
+
+ fclose(fp);
+
+ return 0;
+}
diff --git a/system_cmds/passwd.tproj/nis_passwd.c b/system_cmds/passwd.tproj/nis_passwd.c
new file mode 100644
index 0000000..1525096
--- /dev/null
+++ b/system_cmds/passwd.tproj/nis_passwd.c
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. 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 1.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.apple.com/publicsource 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,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Portions Copyright (c) 1998 by Apple Computer, Inc.
+ * Portions Copyright (c) 1988 by Sun Microsystems, Inc.
+ * Portions Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "passwd.h"
+
+#ifdef INFO_NIS
+
+/* update a user's password in NIS. This was based on the Sun implementation
+ * we used in NEXTSTEP, although I've added some stuff from OpenBSD. And
+ * it uses the API to support Rhapsody's proprietry infosystem switch.
+ * lukeh
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <pwd.h>
+#include <netinet/in.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/rpc.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#include <rpcsvc/yppasswd.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <errno.h>
+
+extern int getrpcport(char *, int, int, int);
+extern void getpasswd(char *, int, int, int, int, char *, char **, char**, char **);
+
+static struct passwd *ypgetpwnam(char *name, char *domain);
+static struct passwd *interpret(struct passwd *pwent, char *line);
+
+int nis_passwd(char *uname, char *domain)
+{
+ int ans, port, ok = -1;
+ char *master;
+ char *ne; /* new encrypted password */
+ char *oc; /* old cleartext password */
+ char *nc; /* new cleartext password */
+ static struct yppasswd yppasswd;
+ struct passwd *pwd;
+ int uid;
+ struct timeval tv;
+ CLIENT *cl;
+
+ if (domain == NULL)
+ {
+ if (yp_get_default_domain(&domain) != 0)
+ {
+ (void)fprintf(stderr, "can't get domain\n");
+ exit(1);
+ }
+ }
+
+ if (yp_master(domain, "passwd.byname", &master) != 0)
+ {
+ (void)fprintf(stderr, "can't get master for passwd file\n");
+ exit(1);
+ }
+
+ port = getrpcport(master, YPPASSWDPROG, YPPASSWDPROC_UPDATE,
+ IPPROTO_UDP);
+ if (port == 0)
+ {
+ (void)fprintf(stderr, "%s is not running yppasswd daemon\n",
+ master);
+ exit(1);
+ }
+ if (port >= IPPORT_RESERVED)
+ {
+ (void)fprintf(stderr,
+ "yppasswd daemon is not running on privileged port\n");
+ exit(1);
+ }
+
+ pwd = ypgetpwnam(uname, domain);
+ if (pwd == NULL)
+ {
+ (void)fprintf(stderr, "user %s not found\n", uname);
+ exit(1);
+ }
+
+ uid = getuid();
+ if (uid != 0 && uid != pwd->pw_uid)
+ {
+ (void)fprintf(stderr, "you may only change your own password\n");
+ exit(1);
+ }
+
+ getpasswd(uname, 0, 5, 0, 0, pwd->pw_passwd, &ne, &oc, &nc);
+
+ yppasswd.oldpass = oc;
+ yppasswd.newpw.pw_name = pwd->pw_name;
+ yppasswd.newpw.pw_passwd = ne;
+ yppasswd.newpw.pw_uid = pwd->pw_uid;
+ yppasswd.newpw.pw_gid = pwd->pw_gid;
+ yppasswd.newpw.pw_gecos = pwd->pw_gecos;
+ yppasswd.newpw.pw_dir = pwd->pw_dir;
+ yppasswd.newpw.pw_shell = pwd->pw_shell;
+
+ cl = clnt_create(master, YPPASSWDPROG, YPPASSWDVERS, "udp");
+ if (cl == NULL)
+ {
+ (void)fprintf(stderr, "could not contact yppasswdd on %s\n", master);
+ exit(1);
+ }
+ cl->cl_auth = authunix_create_default();
+ tv.tv_sec = 2;
+ tv.tv_usec = 0;
+ ans = clnt_call(cl, YPPASSWDPROC_UPDATE,
+ (xdrproc_t)xdr_yppasswd, &yppasswd, (xdrproc_t)xdr_int, &ok, tv);
+
+ if (ans != 0)
+ {
+ clnt_perrno(ans);
+ (void)fprintf(stderr, "\n");
+ (void)fprintf(stderr, "couldn't change passwd\n");
+ exit(1);
+ }
+ if (ok != 0)
+ {
+ (void)fprintf(stderr, "couldn't change passwd\n");
+ exit(1);
+ }
+ return(0);
+}
+
+static char *
+pwskip(register char *p)
+{
+ while (*p && *p != ':' && *p != '\n')
+ ++p;
+ if (*p)
+ *p++ = 0;
+ return (p);
+}
+
+static struct passwd *
+interpret(struct passwd *pwent, char *line)
+{
+ register char *p = line;
+
+ pwent->pw_passwd = "*";
+ pwent->pw_uid = 0;
+ pwent->pw_gid = 0;
+ pwent->pw_gecos = "";
+ pwent->pw_dir = "";
+ pwent->pw_shell = "";
+#ifndef __SLICK__
+ pwent->pw_change = 0;
+ pwent->pw_expire = 0;
+ pwent->pw_class = "";
+#endif
+
+ /* line without colon separators is no good, so ignore it */
+ if(!strchr(p, ':'))
+ return(NULL);
+
+ pwent->pw_name = p;
+ p = pwskip(p);
+ pwent->pw_passwd = p;
+ p = pwskip(p);
+ pwent->pw_uid = (uid_t)strtoul(p, NULL, 10);
+ p = pwskip(p);
+ pwent->pw_gid = (gid_t)strtoul(p, NULL, 10);
+ p = pwskip(p);
+ pwent->pw_gecos = p;
+ p = pwskip(p);
+ pwent->pw_dir = p;
+ p = pwskip(p);
+ pwent->pw_shell = p;
+ while (*p && *p != '\n')
+ p++;
+ *p = '\0';
+ return (pwent);
+}
+
+
+static struct passwd *
+ypgetpwnam(char *nam, char *domain)
+{
+ static struct passwd pwent;
+ char *val;
+ int reason, vallen;
+ static char *__yplin = NULL;
+
+ reason = yp_match(domain, "passwd.byname", nam, (int)strlen(nam),
+ &val, &vallen);
+ switch(reason) {
+ case 0:
+ break;
+ default:
+ return (NULL);
+ break;
+ }
+ val[vallen] = '\0';
+ if (__yplin)
+ free(__yplin);
+ __yplin = (char *)malloc(vallen + 1);
+ strcpy(__yplin, val);
+ free(val);
+
+ return(interpret(&pwent, __yplin));
+}
+
+#endif /* INFO_NIS */
diff --git a/system_cmds/passwd.tproj/od_passwd.c b/system_cmds/passwd.tproj/od_passwd.c
new file mode 100644
index 0000000..f24883a
--- /dev/null
+++ b/system_cmds/passwd.tproj/od_passwd.c
@@ -0,0 +1,253 @@
+/*
+ * 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,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * 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 <unistd.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>
+
+extern char* progname;
+int master_mode;
+
+static int
+cfprintf(FILE* file, const char* format, ...) {
+ char* cstr;
+ int result = 0;
+ va_list args;
+ va_start(args, format);
+ CFStringRef formatStr = CFStringCreateWithCStringNoCopy(NULL, format, kCFStringEncodingUTF8, kCFAllocatorNull);
+ if (formatStr) {
+ CFStringRef str = CFStringCreateWithFormatAndArguments(NULL, NULL, formatStr, args);
+ if (str) {
+ size_t size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), kCFStringEncodingUTF8) + 1;
+ va_end(args);
+ cstr = malloc(size);
+ if (cstr && CFStringGetCString(str, cstr, size, kCFStringEncodingUTF8)) {
+ result = fprintf(file, "%s", cstr);
+ free(cstr);
+ }
+ CFRelease(str);
+ }
+ CFRelease(formatStr);
+ }
+ return result;
+}
+
+static void
+show_error(CFErrorRef error) {
+ if (error) {
+ CFStringRef desc = CFErrorCopyDescription(error);
+ if (desc) {
+ cfprintf(stderr, "%s: %@", progname, desc);
+ CFRelease(desc);
+ }
+ desc = CFErrorCopyFailureReason(error);
+ if (desc) cfprintf(stderr, " %@", desc);
+
+ desc = CFErrorCopyRecoverySuggestion(error);
+ if (desc) cfprintf(stderr, " %@", desc);
+
+ fprintf(stderr, "\n");
+ }
+}
+
+int
+od_passwd(char* uname, char* locn, char* aname)
+{
+ int change_pass_on_self;
+ CFErrorRef error = NULL;
+ CFStringRef username = NULL;
+ CFStringRef location = NULL;
+ CFStringRef authname = NULL;
+ ODNodeRef node = NULL;
+ ODRecordRef rec = NULL;
+ CFStringRef oldpass = NULL;
+ CFStringRef newpass = NULL;
+
+ if (uname == NULL)
+ return -1;
+
+ /*
+ * If no explicit authorization name was specified (via -u)
+ * then default to the target user.
+ */
+ if (!aname) {
+ aname = strdup(uname);
+ }
+
+ master_mode = (geteuid() == 0);
+ change_pass_on_self = (strcmp(aname, uname) == 0);
+
+ if (locn) {
+ location = CFStringCreateWithCString(NULL, locn, kCFStringEncodingUTF8);
+ }
+
+ if (aname) {
+ authname = CFStringCreateWithCString(NULL, aname, kCFStringEncodingUTF8);
+ }
+
+ if (uname) {
+ username = CFStringCreateWithCString(NULL, uname, kCFStringEncodingUTF8);
+ if (!username) return -1;
+ }
+
+ /*
+ * Copy the record from the specified node, or perform a search.
+ */
+ if (location) {
+ node = ODNodeCreateWithName(NULL, kODSessionDefault, location, &error);
+ } else {
+ node = ODNodeCreateWithNodeType(NULL, kODSessionDefault, kODNodeTypeAuthentication, &error);
+ }
+
+ if (node) {
+ rec = ODNodeCopyRecord(node, kODRecordTypeUsers, username, NULL, &error );
+ CFRelease(node);
+ }
+
+ if (!rec) {
+ if (error) {
+ show_error(error);
+ } else {
+ fprintf(stderr, "%s: Unknown user name '%s'.\n", progname, uname);
+ }
+ return -1;
+ }
+
+ /*
+ * Get the actual location.
+ */
+ CFArrayRef values = NULL;
+ 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, or if changing a record that uses SecureToken.
+ */
+ int needs_auth = (!master_mode || CFStringCompareWithOptions(location, CFSTR("/Local/"), CFRangeMake(0, 7), 0) != kCFCompareEqualTo || isSecureToken);
+
+ if (needs_auth) {
+ char prompt[BUFSIZ];
+ if (change_pass_on_self) {
+ strlcpy(prompt, "Old password:", sizeof(prompt));
+ } else {
+ snprintf(prompt, sizeof(prompt), "Password for %s:", aname);
+ }
+ char *p = getpass( prompt );
+ 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;
+ }
+ }
+ }
+
+ for (;;) {
+ char *p = getpass("New password:");
+ if (p && strlen(p) > 0) {
+ newpass = CFStringCreateWithCString(NULL, p, kCFStringEncodingUTF8);
+ memset(p, 0, strlen(p));
+ } else {
+ printf("Password unchanged.\n");
+ exit(0);
+ }
+
+ p = getpass("Retype new password:");
+ if (p) {
+ CFStringRef verify = CFStringCreateWithCString(NULL, p, kCFStringEncodingUTF8);
+ if (!verify || !CFEqual(newpass, verify)) {
+ if (verify) CFRelease(verify);
+ printf("Mismatch; try again, EOF to quit.\n");
+ } else {
+ CFRelease(verify);
+ break;
+ }
+ }
+ }
+
+ ODRecordChangePassword(rec, oldpass, newpass, &error);
+
+ if (error) {
+ show_error(error);
+ exit(1);
+ }
+
+ if (oldpass) CFRelease(oldpass);
+ if (newpass) CFRelease(newpass);
+
+#if 0
+ if ( status != eDSNoErr ) {
+ switch( status )
+ {
+ 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";
+ }
+ fprintf(stderr, "%s\n", errMsgStr);
+ exit(1);
+#endif
+ return 0;
+}
+
+#endif /* INFO_OPEN_DIRECTORY */
diff --git a/system_cmds/passwd.tproj/pam_passwd.c b/system_cmds/passwd.tproj/pam_passwd.c
new file mode 100644
index 0000000..aabf2f1
--- /dev/null
+++ b/system_cmds/passwd.tproj/pam_passwd.c
@@ -0,0 +1,80 @@
+/*
+ * 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,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * 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 "passwd.h"
+
+#ifdef INFO_PAM
+
+#include <security/pam_appl.h>
+#include <security/openpam.h> /* for openpam_ttyconv() */
+
+extern char* progname;
+static pam_handle_t *pamh;
+static struct pam_conv pamc;
+
+int
+pam_passwd(char* uname)
+{
+ int retval = PAM_SUCCESS;
+
+ /* Initialize PAM. */
+ pamc.conv = &openpam_ttyconv;
+ pam_start(progname, uname, &pamc, &pamh);
+
+ /* Authenticate. */
+ if (PAM_SUCCESS != (retval = pam_authenticate(pamh, 0)))
+ goto pamerr;
+
+ /* Authorize. */
+ if (PAM_SUCCESS != (retval = pam_acct_mgmt(pamh, 0)) && PAM_NEW_AUTHTOK_REQD != retval)
+ goto pamerr;
+
+ printf("Changing password for %s.\n", uname);
+
+ /* Change the password. */
+ if (PAM_SUCCESS != (retval = pam_chauthtok(pamh, 0)))
+ goto pamerr;
+
+ /* Set the credentials. */
+ if (PAM_SUCCESS != (retval = pam_setcred(pamh, PAM_ESTABLISH_CRED)))
+ goto pamerr;
+
+ /* Open the session. */
+ if (PAM_SUCCESS != (retval = pam_open_session(pamh, 0)))
+ goto pamerr;
+
+ /* Close the session. */
+ if (PAM_SUCCESS != (retval = pam_close_session(pamh, 0)))
+ goto pamerr;
+
+pamerr:
+ /* Print an error, if needed. */
+ if (PAM_SUCCESS != retval)
+ fprintf(stderr, "%s: %s\n", progname, pam_strerror(pamh, retval));
+
+ /* Terminate PAM. */
+ pam_end(pamh, retval);
+ return retval;
+}
+
+#endif /* INFO_PAM */
diff --git a/system_cmds/passwd.tproj/passwd.1 b/system_cmds/passwd.tproj/passwd.1
new file mode 100644
index 0000000..fd1cef1
--- /dev/null
+++ b/system_cmds/passwd.tproj/passwd.1
@@ -0,0 +1,134 @@
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)passwd.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd August 18, 2008
+.Dt PASSWD 1
+.Os "Mac OS X"
+.Sh NAME
+.Nm passwd
+.Nd modify a user's password
+.Sh SYNOPSIS
+.Nm passwd
+.Op Fl i Ar infosystem Op Fl l Ar location
+.Op Fl u Ar authname
+.Op Ar user
+.Sh DESCRIPTION
+The
+.Nm
+utility changes the user's password.
+If the user is not the super-user,
+.Nm
+first prompts for the current password and will not continue unless the correct
+password is entered.
+.Pp
+When entering the new password, the characters entered do not echo, in order to
+avoid the password being seen by a passer-by.
+The
+.Nm
+utility prompts for the new password twice in order to detect typing errors.
+.Pp
+The new password should be at least six characters long
+and not purely alphabetic.
+Its total length should be less than
+.Dv _PASSWORD_LEN
+(currently 128 characters),
+although some directory systems allow longer passwords.
+Numbers, upper
+case letters, and meta characters are encouraged.
+.Pp
+Once the password has been verified,
+.Nm
+communicates the new password to the directory system.
+.Bl -tag -width flag
+.It Fl i Ar infosystem
+This option specifies where the password update should be applied.
+Under Mac OS X 10.5 and later, supported directory systems are:
+.Bl -tag -width flag
+.It Ar PAM
+(default) Pluggable Authentication Modules.
+.It Ar opendirectory
+A system conforming to Open Directory APIs and supporting updates
+(including LDAP, etc).
+If no -l option is specified, the search node is used.
+.It Ar file
+The local flat-files (included for legacy configurations).
+.It Ar nis
+A remote NIS server containing the user's password.
+.El
+.It Fl l Ar location
+This option causes the password to be updated in the given location
+of the chosen directory system.
+.Bl -tag -width flag
+.It for file,
+location may be a file name (/etc/master.passwd is the default)
+.It for nis,
+location may be a NIS domainname
+.It for opendirectory,
+location may be a directory node name
+.It for PAM,
+location is not used
+.El
+.It Fl u Ar authname
+This option specifies the user name to use when authenticating to
+the directory node.
+.It Ar user
+This optional argument specifies the user account whose password will be
+changed. This account's current password may be required, even when run as the
+super-user, depending on the directory system.
+.El
+.Sh FILES
+.Bl -tag -width /etc/master.passwd -compact
+.It Pa /etc/master.passwd
+The user database
+.It Pa /etc/passwd
+A Version 7 format password file
+.It Pa /etc/passwd.XXXXXX
+Temporary copy of the password file
+.El
+.Sh SEE ALSO
+.Xr chpass 1 ,
+.Xr login 1 ,
+.Xr dscl 1 ,
+.Xr passwd 5 ,
+.Xr pwd_mkdb 8 ,
+.Xr vipw 8
+.Rs
+.%A Robert Morris
+.%A Ken Thompson
+.%T "UNIX password security"
+.Re
+.Sh HISTORY
+A
+.Nm passwd
+command appeared in
+.At v6 .
diff --git a/system_cmds/passwd.tproj/passwd.c b/system_cmds/passwd.tproj/passwd.c
new file mode 100644
index 0000000..877036e
--- /dev/null
+++ b/system_cmds/passwd.tproj/passwd.c
@@ -0,0 +1,302 @@
+/*
+ * 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,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * 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 <TargetConditionals.h>
+
+#define _PASSWD_FILE "/etc/master.passwd"
+
+#include <stdio.h>
+#include <errno.h>
+#include <pwd.h>
+#include <libc.h>
+#include <ctype.h>
+#include <string.h>
+#include "passwd.h"
+
+#ifdef __SLICK__
+#define _PASSWORD_LEN 8
+#endif
+
+char* progname = "passwd";
+
+static char *saltchars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
+
+void
+getpasswd(char *name, int isroot, int minlen, int mixcase, int nonalpha,
+ char *old_pw, char **new_pw, char **old_clear, char **new_clear)
+{
+ int i, tries, pw_ok, upper, lower, alpha, notalpha;
+ size_t len;
+ int isNull;
+ char *p;
+ static char obuf[_PASSWORD_LEN+1];
+ static char nbuf[_PASSWORD_LEN+1];
+ char salt[9];
+
+ printf("Changing password for %s.\n", name);
+
+ p = "";
+ isNull = 0;
+ if (old_pw == NULL) isNull = 1;
+ if ((isNull == 0) && (old_pw[0] == '\0')) isNull = 1;
+ if ((isroot == 0) && (isNull == 0))
+ {
+ p = getpass("Old password:");
+ if (strcmp(crypt(p, old_pw), old_pw))
+ {
+ errno = EACCES;
+ fprintf(stderr, "Sorry\n");
+ exit(1);
+ }
+ }
+ //strcpy(obuf, p);
+ snprintf( obuf, sizeof(obuf), "%s", p );
+
+ tries = 0;
+ nbuf[0] = '\0';
+ for (;;)
+ {
+ p = getpass("New password:");
+ if (!*p)
+ {
+ printf("Password unchanged.\n");
+ exit(0);
+ }
+
+ tries++;
+ len = strlen(p);
+ upper = 0;
+ lower = 0;
+ alpha = 0;
+ notalpha = 0;
+ for (i = 0; i < len; i++)
+ {
+ if (isupper(p[i])) upper++;
+ if (islower(p[i])) lower++;
+ if (isalpha(p[i])) alpha++;
+ else notalpha++;
+ }
+
+
+ pw_ok = 1;
+ if (len < minlen) pw_ok = 0;
+ if ((mixcase == 1) && ((upper == 0) || (lower == 0))) pw_ok = 0;
+ if ((nonalpha == 1) && (notalpha == 0)) pw_ok = 0;
+
+ /*
+ * An insistent root may override security options.
+ */
+ if ((isroot == 1) && (tries > 2)) pw_ok = 1;
+
+ /*
+ * A very insistent user may override security options.
+ */
+ if (tries > 4) pw_ok = 1;
+
+ if (pw_ok == 0)
+ {
+ if (len < minlen)
+ printf("Password must be at least %d characters long.\n", minlen);
+ if ((mixcase == 1) && ((upper == 0) || (lower == 0)))
+ printf("Password must contain both upper and lower case characters.\n");
+ if ((nonalpha == 1) && (notalpha == 0))
+ printf("Password must contain non-alphabetic characters.\n");
+ continue;
+ }
+
+ //strcpy(nbuf, p);
+ snprintf( nbuf, sizeof(nbuf), "%s", p );
+
+ if (!strcmp(nbuf, getpass("Retype new password:"))) break;
+
+ printf("Mismatch; try again, EOF to quit.\n");
+ }
+
+ /*
+ * Create a random salt
+ */
+ srandom((int)time((time_t *)NULL));
+ salt[0] = saltchars[random() % strlen(saltchars)];
+ salt[1] = saltchars[random() % strlen(saltchars)];
+ salt[2] = '\0';
+ *new_pw = crypt(nbuf, salt);
+
+ *old_clear = obuf;
+ *new_clear = nbuf;
+ return;
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: %s [-i infosystem] -l location]] [-u authname] [name]\n", progname);
+ fprintf(stderr, " infosystem:\n");
+ fprintf(stderr, " file\n");
+ fprintf(stderr, " NIS\n");
+ fprintf(stderr, " OpenDirectory\n");
+ fprintf(stderr, " PAM\n");
+ fprintf(stderr, " location (for infosystem):\n");
+ fprintf(stderr, " file location is path to file (default is %s)\n", _PASSWD_FILE);
+ fprintf(stderr, " NIS location is NIS domain name\n");
+ fprintf(stderr, " OpenDirectory location is directory node name\n");
+ fprintf(stderr, " PAM location is not used\n");
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ char* user = NULL;
+ char* locn = NULL;
+ char* auth = NULL;
+ int infosystem, ch;
+ int free_user = 0;
+ int res = -1;
+
+#ifdef INFO_PAM
+ infosystem = INFO_PAM;
+#else
+#ifdef INFO_OPEN_DIRECTORY
+ infosystem = INFO_OPEN_DIRECTORY;
+#else
+ infosystem = INFO_FILE;
+#endif
+#endif
+
+#ifdef INFO_OPEN_DIRECTORY
+ /* PAM is the default infosystem, but we still want to use OpenDirectory directly when run by root */
+ if (0 == getuid())
+ infosystem = INFO_OPEN_DIRECTORY;
+#endif
+
+ while ((ch = getopt(argc, argv, "i:l:u:")) != -1)
+ switch(ch) {
+ case 'i':
+ if (!strcasecmp(optarg, "file")) {
+ infosystem = INFO_FILE;
+#ifdef INFO_NIS
+ } else if (!strcasecmp(optarg, "NIS")) {
+ infosystem = INFO_NIS;
+ } else if (!strcasecmp(optarg, "YP")) {
+ infosystem = INFO_NIS;
+#endif
+#ifdef INFO_OPEN_DIRECTORY
+ } else if (!strcasecmp(optarg, "opendirectory")) {
+ infosystem = INFO_OPEN_DIRECTORY;
+#endif
+#ifdef INFO_PAM
+ } else if (!strcasecmp(optarg, "PAM")) {
+ infosystem = INFO_PAM;
+#endif
+ } else {
+ fprintf(stderr, "%s: Unknown info system \'%s\'.\n",
+ progname, optarg);
+ usage();
+ }
+ break;
+ case 'l':
+ locn = optarg;
+ break;
+ case 'u':
+ auth = optarg;
+ break;
+ case '?':
+ default:
+ usage();
+ break;
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 1) {
+ usage();
+ } else if (argc == 1) {
+ user = argv[0];
+ }
+
+#ifdef INFO_PAM
+ if (INFO_PAM == infosystem && NULL != locn)
+ usage();
+#endif
+
+ if (user == NULL)
+ {
+ /*
+ * Verify that the login name exists.
+ * lukeh 24 Dec 1997
+ */
+
+ /* getlogin() is the wrong thing to use here because it returns the wrong user after su */
+ /* sns 5 Jan 2005 */
+
+ struct passwd * userRec = getpwuid(getuid());
+ if (userRec != NULL && userRec->pw_name != NULL) {
+ /* global static mem is volatile; must strdup */
+ user = strdup(userRec->pw_name);
+ free_user = 1;
+ }
+
+ if (user == NULL)
+ {
+ fprintf(stderr, "you don't have a login name\n");
+ exit(1);
+ }
+ }
+
+ switch (infosystem)
+ {
+ case INFO_FILE:
+ res = file_passwd(user, locn);
+ break;
+#ifdef INFO_NIS
+ case INFO_NIS:
+ res = nis_passwd(user, locn);
+ break;
+#endif
+#ifdef INFO_OPEN_DIRECTORY
+ case INFO_OPEN_DIRECTORY:
+ res = od_passwd(user, locn, auth);
+ break;
+#endif
+#ifdef INFO_PAM
+ case INFO_PAM:
+ res = pam_passwd(user);
+ break;
+#endif
+ }
+
+ if (res == 0)
+ {
+ printf("\n");
+ printf("################################### WARNING ###################################\n");
+ printf("# This tool does not update the login keychain password. #\n");
+ printf("# To update it, run `security set-keychain-password` as the user in question, #\n");
+ printf("# or as root providing a path to such user's login keychain. #\n");
+ printf("###############################################################################\n");
+ printf("\n");
+ }
+
+ if (free_user == 1)
+ free(user);
+
+ exit(0);
+}
diff --git a/system_cmds/passwd.tproj/passwd.entitlements b/system_cmds/passwd.tproj/passwd.entitlements
new file mode 100644
index 0000000..a63c168
--- /dev/null
+++ b/system_cmds/passwd.tproj/passwd.entitlements
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.keystore.console</key>
+ <true/>
+ <key>com.apple.private.opendirectoryd.identity</key>
+ <true/>
+ <key>com.apple.private.security.clear-library-validation</key>
+ <true/>
+</dict>
+</plist>
diff --git a/system_cmds/passwd.tproj/passwd.h b/system_cmds/passwd.tproj/passwd.h
new file mode 100644
index 0000000..60109db
--- /dev/null
+++ b/system_cmds/passwd.tproj/passwd.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2011-2019 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. 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 1.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.apple.com/publicsource 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,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <TargetConditionals.h>
+
+#define INFO_FILE 1
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+#define INFO_NIS 2
+#define INFO_OPEN_DIRECTORY 3
+#define INFO_PAM 4
+#endif
+
+extern int file_passwd(char *, char *);
+#ifdef INFO_NIS
+extern int nis_passwd(char *, char *);
+#endif
+#ifdef INFO_OPEN_DIRECTORY
+extern int od_passwd(char *, char *, char*);
+#endif
+#ifdef INFO_PAM
+extern int pam_passwd(char *);
+#endif
+
+void
+getpasswd(char *name, int isroot, int minlen, int mixcase, int nonalpha,
+ char *old_pw, char **new_pw, char **old_clear, char **new_clear);
diff --git a/system_cmds/passwd.tproj/passwd.pam b/system_cmds/passwd.tproj/passwd.pam
new file mode 100644
index 0000000..9ac660f
--- /dev/null
+++ b/system_cmds/passwd.tproj/passwd.pam
@@ -0,0 +1,5 @@
+# passwd: auth account
+auth required pam_permit.so
+account required pam_opendirectory.so
+password required pam_opendirectory.so
+session required pam_permit.so