summaryrefslogtreecommitdiffstats
path: root/usr.bin/chpass
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/chpass')
-rw-r--r--usr.bin/chpass/Makefile48
-rw-r--r--usr.bin/chpass/chpass.c251
-rw-r--r--usr.bin/chpass/chpass.h16
-rw-r--r--usr.bin/chpass/edit.c246
-rw-r--r--usr.bin/chpass/field.c55
-rw-r--r--usr.bin/chpass/pathnames.h39
-rw-r--r--usr.bin/chpass/pw_copy.c177
-rw-r--r--usr.bin/chpass/pw_copy.h37
-rw-r--r--usr.bin/chpass/pw_yp.c530
-rw-r--r--usr.bin/chpass/pw_yp.h126
-rw-r--r--usr.bin/chpass/util.c8
11 files changed, 317 insertions, 1216 deletions
diff --git a/usr.bin/chpass/Makefile b/usr.bin/chpass/Makefile
index a84cebc..5c807ee 100644
--- a/usr.bin/chpass/Makefile
+++ b/usr.bin/chpass/Makefile
@@ -2,17 +2,14 @@
# $FreeBSD$
PROG= chpass
-SRCS= chpass.c edit.c field.c pw_copy.c pw_scan.c pw_util.c pw_yp.c \
- table.c util.c ypxfr_misc.c ${GENSRCS}
-GENSRCS=yp.h yp_clnt.c yppasswd.h yppasswd_clnt.c yppasswd_private.h \
- yppasswd_private_clnt.c yppasswd_private_xdr.c
+SRCS= chpass.c edit.c field.c pw_scan.c table.c util.c
BINOWN= root
BINMODE=4555
-.PATH: ${.CURDIR}/../../usr.sbin/pwd_mkdb ${.CURDIR}/../../usr.sbin/vipw \
- ${.CURDIR}/../../libexec/ypxfr \
- ${.CURDIR}/../../usr.sbin/rpc.yppasswdd \
+.PATH: ${.CURDIR}/../../usr.sbin/pwd_mkdb \
${.CURDIR}/../../lib/libc/gen
-CFLAGS+=-I${.CURDIR}/../../usr.sbin/pwd_mkdb -I${.CURDIR}/../../usr.sbin/vipw -I${.CURDIR}/../../lib/libc/gen
+CFLAGS+=-I${.CURDIR}/../../usr.sbin/pwd_mkdb -I${.CURDIR}/../../lib/libc/gen
+WARNS?= 4
+NO_WERROR=yes
LINKS= ${BINDIR}/chpass ${BINDIR}/chfn
LINKS+= ${BINDIR}/chpass ${BINDIR}/chsh
LINKS+= ${BINDIR}/chpass ${BINDIR}/ypchpass
@@ -22,42 +19,13 @@ LINKS+= ${BINDIR}/chpass ${BINDIR}/ypchsh
MLINKS= chpass.1 chfn.1 chpass.1 chsh.1
MLINKS+= chpass.1 ypchpass.1 chpass.1 ypchfn.1 chpass.1 ypchsh.1
-CFLAGS+=-DYP -I. -I${.CURDIR}/../../libexec/ypxfr \
- -I${.CURDIR}/../../usr.sbin/rpc.yppasswdd -Dyp_error=warnx
+CFLAGS+=-DYP -I.
#Some people need this, uncomment to activate
#CFLAGS+=-DRESTRICT_FULLNAME_CHANGE
-DPADD= ${LIBRPCSVC} ${LIBCRYPT} ${LIBMD}
-LDADD+= -lrpcsvc -lcrypt -lmd
-
-CLEANFILES= ${GENSRCS}
-
-RPCGEN= rpcgen -C
-RPCSRC= ${DESTDIR}/usr/include/rpcsvc/yp.x
-RPCSRC_PW= ${DESTDIR}/usr/include/rpcsvc/yppasswd.x
-RPCSRC_PRIV= ${.CURDIR}/../../usr.sbin/rpc.yppasswdd/yppasswd_private.x
-
-yp.h: ${RPCSRC}
- ${RPCGEN} -h -o ${.TARGET} ${RPCSRC}
-
-yp_clnt.c: ${RPCSRC}
- ${RPCGEN} -l -o ${.TARGET} ${RPCSRC}
-
-yppasswd.h: ${RPCSRC_PW}
- ${RPCGEN} -h -o ${.TARGET} ${RPCSRC_PW}
-
-yppasswd_clnt.c: ${RPCSRC_PW}
- ${RPCGEN} -l -o ${.TARGET} ${RPCSRC_PW}
-
-yppasswd_private.h: ${RPCSRC_PRIV}
- ${RPCGEN} -h -o ${.TARGET} ${RPCSRC_PRIV}
-
-yppasswd_private_xdr.c: ${RPCSRC_PRIV}
- ${RPCGEN} -c -o ${.TARGET} ${RPCSRC_PRIV}
-
-yppasswd_private_clnt.c: ${RPCSRC_PRIV}
- ${RPCGEN} -l -o ${.TARGET} ${RPCSRC_PRIV}
+DPADD= ${LIBCRYPT} ${LIBUTIL} ${LIBYPCLNT}
+LDADD+= -lcrypt -lutil -lypclnt
beforeinstall:
.for i in chpass chfn chsh ypchpass ypchfn ypchsh
diff --git a/usr.bin/chpass/chpass.c b/usr.bin/chpass/chpass.c
index 2fe205f..22ca2ac 100644
--- a/usr.bin/chpass/chpass.c
+++ b/usr.bin/chpass/chpass.c
@@ -1,6 +1,13 @@
/*-
* Copyright (c) 1988, 1993, 1994
* The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -61,24 +68,19 @@ __FBSDID("$FreeBSD$");
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-
-#include <pw_scan.h>
-#include <pw_util.h>
-#include "pw_copy.h"
#ifdef YP
-#include <rpcsvc/yp.h>
-int yp_errno = YP_TRUE;
-#include "pw_yp.h"
+#include <ypclnt.h>
#endif
+#include <pw_scan.h>
+#include <libutil.h>
+
#include "chpass.h"
-#include "pathnames.h"
-char *tempname;
-uid_t uid;
+int master_mode;
-void baduser(void);
-void usage(void);
+static void baduser(void);
+static void usage(void);
char localhost[] = "localhost";
@@ -86,22 +88,23 @@ int
main(int argc, char *argv[])
{
enum { NEWSH, LOADENTRY, EDITENTRY, NEWPW, NEWEXP } op;
- struct passwd *pw = NULL, lpw, old_pw;
- char *username = NULL;
+ struct passwd *pw = NULL, lpw, *old_pw;
int ch, pfd, tfd;
+ const char *password;
char *arg = NULL;
+ uid_t uid;
#ifdef YP
- int force_local = 0;
- int force_yp = 0;
+ struct ypclnt *ypclnt;
+ const char *yp_domain = NULL, *yp_host = NULL;
#endif
op = EDITENTRY;
#ifdef YP
- while ((ch = getopt(argc, argv, "a:p:s:e:d:h:oly")) != -1)
+ while ((ch = getopt(argc, argv, "a:p:s:e:d:h:loy")) != -1)
#else
while ((ch = getopt(argc, argv, "a:p:s:e:")) != -1)
#endif
- switch(ch) {
+ switch (ch) {
case 'a':
op = LOADENTRY;
arg = optarg;
@@ -119,184 +122,184 @@ main(int argc, char *argv[])
arg = optarg;
break;
#ifdef YP
- case 'h':
-#ifdef PARANOID
- if (getuid()) {
- warnx("Only the superuser can use the -h flag");
- } else {
-#endif
- yp_server = optarg;
-#ifdef PARANOID
- }
-#endif
- break;
case 'd':
-#ifdef PARANOID
- if (getuid()) {
- warnx("Only the superuser can use the -d flag");
- } else {
-#endif
- yp_domain = optarg;
- if (yp_server == NULL)
- yp_server = localhost;
-#ifdef PARANOID
- }
-#endif
- break;
- case 'l':
- _use_yp = 0;
- force_local = 1;
+ yp_domain = optarg;
break;
- case 'y':
- _use_yp = force_yp = 1;
+ case 'h':
+ yp_host = optarg;
break;
+ case 'l':
case 'o':
- force_old++;
+ case 'y':
+ /* compatibility */
break;
#endif
case '?':
default:
usage();
}
+
argc -= optind;
argv += optind;
+ if (argc > 1)
+ usage();
+
uid = getuid();
if (op == EDITENTRY || op == NEWSH || op == NEWPW || op == NEWEXP) {
- switch(argc) {
-#ifdef YP
- case 0:
- GETPWUID(uid)
- get_yp_master(1); /* XXX just to set the suser flag */
- break;
- case 1:
- GETPWNAM(*argv)
- get_yp_master(1); /* XXX just to set the suser flag */
-#else
- case 0:
- if (!(pw = getpwuid(uid)))
+ if (argc == 0) {
+ if ((pw = getpwuid(uid)) == NULL)
errx(1, "unknown user: uid %lu",
(unsigned long)uid);
- break;
- case 1:
- if (!(pw = getpwnam(*argv)))
+ } else {
+ if ((pw = getpwnam(*argv)) == NULL)
errx(1, "unknown user: %s", *argv);
-#endif
- if (uid && uid != pw->pw_uid)
+ if (uid != 0 && uid != pw->pw_uid)
baduser();
- break;
- default:
- usage();
}
/* Make a copy for later verification */
- old_pw = *pw;
- old_pw.pw_gecos = strdup(old_pw.pw_gecos);
+ if ((pw = pw_dup(pw)) == NULL ||
+ (old_pw = pw_dup(pw)) == NULL)
+ err(1, "pw_dup");
}
+#ifdef YP
+ if ((pw->pw_fields & _PWF_SOURCE) == _PWF_NIS) {
+ ypclnt = ypclnt_new(yp_domain, "passwd.byname", yp_host);
+ master_mode = (ypclnt != NULL &&
+ ypclnt_connect(ypclnt) != -1 &&
+ ypclnt_havepasswdd(ypclnt) == 1);
+ ypclnt_free(ypclnt);
+ } else
+#endif
+ master_mode = (uid == 0);
+
if (op == NEWSH) {
/* protect p_shell -- it thinks NULL is /bin/sh */
if (!arg[0])
usage();
- if (p_shell(arg, pw, (ENTRY *)NULL))
- pw_error((char *)NULL, 0, 1);
+ if (p_shell(arg, pw, (ENTRY *)NULL) == -1)
+ exit(1);
}
if (op == NEWEXP) {
if (uid) /* only root can change expire */
baduser();
- if (p_expire(arg, pw, (ENTRY *)NULL))
- pw_error((char *)NULL, 0, 1);
+ if (p_expire(arg, pw, (ENTRY *)NULL) == -1)
+ exit(1);
}
if (op == LOADENTRY) {
if (uid)
baduser();
pw = &lpw;
+ old_pw = NULL;
if (!__pw_scan(arg, pw, _PWSCAN_WARN|_PWSCAN_MASTER))
exit(1);
}
- username = pw->pw_name;
if (op == NEWPW) {
if (uid)
baduser();
- if(strchr(arg, ':')) {
+ if (strchr(arg, ':'))
errx(1, "invalid format for password");
- }
pw->pw_passwd = arg;
}
- /*
- * The temporary file/file descriptor usage is a little tricky here.
- * 1: Create a temporary file called tempname, get descriptor tfd.
- * 2: Display() gets an fp for the temporary file, and copies the
- * user's information into it. It then gives the temporary file
- * to the user and closes the fp, closing the underlying fd.
- * 3: The user edits the temporary file some number of times.
- * The results are stored in pw by edit().
- * 4: Delete the temporary file.
- * 5: Make a new temporary file, descriptor tfd.
- * 6: Get a descriptor for the master.passwd file, pfd, and
- * lock master.passwd.
- * 7: Pw_copy() gets descriptors for master.passwd and the
- * temporary file and copies the master password file into it,
- * replacing the modified user's record with a new one. We can't
- * use the first temporary file for this because it was owned
- * by the user. Pass the new and old user info. Check the
- * entry for our user has not been changed by someone else by
- * while the user was editing by comparing the old info to
- * the entry freshly read from master.passwd. Pw_copy() closes
- * its fp, flushing the data and closing the underlying file
- * descriptor. We can't close the master password fp, or we'd
- * lose the lock.
- * 8: Call pw_mkdb() (which renames the temporary file) and exit.
- * The exit closes the master passwd fp/fd.
- */
- pw_init();
- tfd = pw_tmp();
-
if (op == EDITENTRY) {
- display(tfd, pw);
- edit(pw);
- (void)unlink(tempname);
- tfd = pw_tmp();
+ /*
+ * We don't really need pw_*() here, but pw_edit() (used
+ * by edit()) is just too useful...
+ */
+ if (pw_init(NULL, NULL))
+ err(1, "pw_init()");
+ if ((tfd = pw_tmp(-1)) == -1) {
+ pw_fini();
+ err(1, "pw_tmp()");
+ }
+ free(pw);
+ pw = edit(pw_tempname(), old_pw);
+ pw_fini();
+ if (pw == NULL)
+ err(1, "edit()");
+ if (pw_equal(old_pw, pw))
+ errx(0, "user information unchanged");
}
-#ifdef YP
- if (_use_yp) {
- yp_submit(pw);
- (void)unlink(tempname);
+ if (old_pw && !master_mode) {
+ password = getpass("Password: ");
+ if (strcmp(crypt(password, old_pw->pw_passwd),
+ old_pw->pw_passwd) != 0)
+ baduser();
} else {
-#endif /* YP */
- pfd = pw_lock();
- pw_copy(pfd, tfd, pw, (op == LOADENTRY) ? NULL : &old_pw);
+ password = "";
+ }
- if (!pw_mkdb(username))
- pw_error((char *)NULL, 0, 1);
+ if (old_pw != NULL)
+ pw->pw_fields |= (old_pw->pw_fields & _PWF_SOURCE);
+ switch (pw->pw_fields & _PWF_SOURCE) {
#ifdef YP
- }
+ case _PWF_NIS:
+ ypclnt = ypclnt_new(yp_domain, "passwd.byname", yp_host);
+ if (ypclnt == NULL ||
+ ypclnt_connect(ypclnt) == -1 ||
+ ypclnt_passwd(ypclnt, pw, password) == -1) {
+ warnx("%s", ypclnt->error);
+ ypclnt_free(ypclnt);
+ exit(1);
+ }
+ ypclnt_free(ypclnt);
+ errx(0, "NIS user information updated");
#endif /* YP */
- exit(0);
+ case 0:
+ case _PWF_FILES:
+ if (pw_init(NULL, NULL))
+ err(1, "pw_init()");
+ if ((pfd = pw_lock()) == -1) {
+ pw_fini();
+ err(1, "pw_lock()");
+ }
+ if ((tfd = pw_tmp(-1)) == -1) {
+ pw_fini();
+ err(1, "pw_tmp()");
+ }
+ if (pw_copy(pfd, tfd, pw, old_pw) == -1) {
+ pw_fini();
+ err(1, "pw_copy");
+ }
+ if (pw_mkdb(pw->pw_name) == -1) {
+ pw_fini();
+ err(1, "pw_mkdb()");
+ }
+ pw_fini();
+ errx(0, "user information updated");
+ break;
+ default:
+ errx(1, "unsupported passwd source");
+ }
}
-void
+static void
baduser(void)
{
+
errx(1, "%s", strerror(EACCES));
}
-void
+static void
usage(void)
{
(void)fprintf(stderr,
+ "Usage: chpass%s %s [user]\n",
#ifdef YP
- "usage: chpass [-o] [-l] [-y] [-d domain] [-h host] [-a list] [-p encpass] [-s shell] [-e mmm dd yy] [user]\n");
+ " [-d domain] [-h host]",
#else
- "usage: chpass [-a list] [-p encpass] [-s shell] [-e mmm dd yy] [user]\n");
+ "",
#endif
+ "[-a list] [-p encpass] [-s shell] [-e mmm dd yy]");
exit(1);
}
diff --git a/usr.bin/chpass/chpass.h b/usr.bin/chpass/chpass.h
index ef0c708..b78b85e 100644
--- a/usr.bin/chpass/chpass.h
+++ b/usr.bin/chpass/chpass.h
@@ -1,6 +1,13 @@
/*
* Copyright (c) 1988, 1993, 1994
* The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -39,7 +46,8 @@ struct passwd;
typedef struct _entry {
const char *prompt;
int (*func)(char *, struct passwd *, struct _entry *);
- int restricted, len;
+ int restricted;
+ size_t len;
char *except, *save;
} ENTRY;
@@ -52,11 +60,10 @@ typedef struct _entry {
#define E_SHELL 13
extern ENTRY list[];
-extern uid_t uid;
+extern int master_mode;
int atot(char *, time_t *);
-void display(int, struct passwd *);
-void edit(struct passwd *);
+struct passwd *edit(const char *, struct passwd *);
char *ok_shell(char *);
int p_change(char *, struct passwd *, ENTRY *);
int p_class(char *, struct passwd *, ENTRY *);
@@ -70,4 +77,3 @@ int p_passwd(char *, struct passwd *, ENTRY *);
int p_shell(char *, struct passwd *, ENTRY *);
int p_uid(char *, struct passwd *, ENTRY *);
char *ttoa(time_t);
-int verify(struct passwd *);
diff --git a/usr.bin/chpass/edit.c b/usr.bin/chpass/edit.c
index 0ec0f10..59646f0 100644
--- a/usr.bin/chpass/edit.c
+++ b/usr.bin/chpass/edit.c
@@ -1,6 +1,13 @@
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -46,7 +53,6 @@ __FBSDID("$FreeBSD$");
#include <ctype.h>
#include <err.h>
#include <errno.h>
-#include <md5.h>
#include <paths.h>
#include <pwd.h>
#include <stdio.h>
@@ -55,39 +61,42 @@ __FBSDID("$FreeBSD$");
#include <unistd.h>
#include <pw_scan.h>
-#include <pw_util.h>
+#include <libutil.h>
#include "chpass.h"
-#ifdef YP
-#include "pw_yp.h"
-#endif /* YP */
-extern char *tempname;
+static int display(const char *tfn, struct passwd *pw);
+static struct passwd *verify(const char *tfn, struct passwd *pw);
-void
-edit(struct passwd *pw)
+struct passwd *
+edit(const char *tfn, struct passwd *pw)
{
- struct stat begin, end;
- char *begin_sum, *end_sum;
+ struct passwd *npw;
+ char *line;
+ size_t len;
+ if (display(tfn, pw) == -1)
+ return (NULL);
for (;;) {
- if (stat(tempname, &begin))
- pw_error(tempname, 1, 1);
- begin_sum = MD5File(tempname, (char *)NULL);
- pw_edit(1);
- if (stat(tempname, &end))
- pw_error(tempname, 1, 1);
- end_sum = MD5File(tempname, (char *)NULL);
- if ((begin.st_mtime == end.st_mtime) &&
- (strcmp(begin_sum, end_sum) == 0)) {
- warnx("no changes made");
- pw_error(NULL, 0, 0);
- }
- free(begin_sum);
- free(end_sum);
- if (verify(pw))
+ switch (pw_edit(1)) {
+ case -1:
+ return (NULL);
+ case 0:
+ return (pw_dup(pw));
+ default:
break;
- pw_prompt();
+ }
+ if ((npw = verify(tfn, pw)) != NULL)
+ return (npw);
+ free(npw);
+ printf("re-edit the password file? ");
+ fflush(stdout);
+ if ((line = fgetln(stdin, &len)) == NULL) {
+ warn("fgetln()");
+ return (NULL);
+ }
+ if (len > 0 && (*line == 'N' || *line == 'n'))
+ return (NULL);
}
}
@@ -96,23 +105,20 @@ edit(struct passwd *pw)
* print out the file for the user to edit; strange side-effect:
* set conditional flag if the user gets to edit the shell.
*/
-void
-display(int fd, struct passwd *pw)
+static int
+display(const char *tfn, struct passwd *pw)
{
FILE *fp;
char *bp, *p;
- if (!(fp = fdopen(fd, "w")))
- pw_error(tempname, 1, 1);
+ if ((fp = fopen(tfn, "w")) == NULL) {
+ warn("%s", tfn);
+ return (-1);
+ }
(void)fprintf(fp,
-#ifdef YP
- "#Changing %s information for %s.\n", _use_yp ? "NIS" : "user database", pw->pw_name);
- if (!uid && (!_use_yp || suser_override)) {
-#else
- "#Changing user database information for %s.\n", pw->pw_name);
- if (!uid) {
-#endif /* YP */
+ "#Changing user information for %s.\n", pw->pw_name);
+ if (master_mode) {
(void)fprintf(fp, "Login: %s\n", pw->pw_name);
(void)fprintf(fp, "Password: %s\n", pw->pw_passwd);
(void)fprintf(fp, "Uid [#]: %lu\n", (unsigned long)pw->pw_uid);
@@ -135,7 +141,8 @@ display(int fd, struct passwd *pw)
* necklace, but there's not much else to do.
*/
#else
- else if ((!list[E_SHELL].restricted && ok_shell(pw->pw_shell)) || !uid)
+ else if ((!list[E_SHELL].restricted && ok_shell(pw->pw_shell)) ||
+ master_mode)
/*
* If change not restrict (table.c) and standard shell
* OR if root, then allow editing of shell.
@@ -150,120 +157,133 @@ display(int fd, struct passwd *pw)
p = strsep(&bp, ",");
p = strdup(p ? p : "");
list[E_NAME].save = p;
- if (!list[E_NAME].restricted || !uid)
+ if (!list[E_NAME].restricted || master_mode)
(void)fprintf(fp, "Full Name: %s\n", p);
- p = strsep(&bp, ",");
+ p = strsep(&bp, ",");
p = strdup(p ? p : "");
list[E_LOCATE].save = p;
- if (!list[E_LOCATE].restricted || !uid)
+ if (!list[E_LOCATE].restricted || master_mode)
(void)fprintf(fp, "Office Location: %s\n", p);
- p = strsep(&bp, ",");
+ p = strsep(&bp, ",");
p = strdup(p ? p : "");
list[E_BPHONE].save = p;
- if (!list[E_BPHONE].restricted || !uid)
+ if (!list[E_BPHONE].restricted || master_mode)
(void)fprintf(fp, "Office Phone: %s\n", p);
- p = strsep(&bp, ",");
+ p = strsep(&bp, ",");
p = strdup(p ? p : "");
list[E_HPHONE].save = p;
- if (!list[E_HPHONE].restricted || !uid)
+ if (!list[E_HPHONE].restricted || master_mode)
(void)fprintf(fp, "Home Phone: %s\n", p);
bp = strdup(bp ? bp : "");
list[E_OTHER].save = bp;
- if (!list[E_OTHER].restricted || !uid)
+ if (!list[E_OTHER].restricted || master_mode)
(void)fprintf(fp, "Other information: %s\n", bp);
- (void)fchown(fd, getuid(), getgid());
+ (void)fchown(fileno(fp), getuid(), getgid());
(void)fclose(fp);
+ return (0);
}
-int
-verify(struct passwd *pw)
+static struct passwd *
+verify(const char *tfn, struct passwd *pw)
{
+ struct passwd *npw;
ENTRY *ep;
- char *p;
+ char *buf, *p, *val;
struct stat sb;
FILE *fp;
- int len, line;
- static char buf[LINE_MAX];
+ int line;
+ size_t len;
- if (!(fp = fopen(tempname, "r")))
- pw_error(tempname, 1, 1);
- if (fstat(fileno(fp), &sb))
- pw_error(tempname, 1, 1);
+ if ((pw = pw_dup(pw)) == NULL)
+ return (NULL);
+ if ((fp = fopen(tfn, "r")) == NULL ||
+ fstat(fileno(fp), &sb) == -1) {
+ warn("%s", tfn);
+ free(pw);
+ return (NULL);
+ }
if (sb.st_size == 0) {
warnx("corrupted temporary file");
- goto bad;
+ fclose(fp);
+ free(pw);
+ return (NULL);
}
- line = 0;
- while (fgets(buf, sizeof(buf), fp)) {
- line++;
- if (!buf[0] || buf[0] == '#')
+ val = NULL;
+ for (line = 1; (buf = fgetln(fp, &len)) != NULL; ++line) {
+ if (*buf == '\0' || *buf == '#')
continue;
- if (!(p = strchr(buf, '\n'))) {
- warnx("line %d too long", line);
- goto bad;
- }
- *p = '\0';
+ while (len > 0 && isspace(buf[len - 1]))
+ --len;
for (ep = list;; ++ep) {
if (!ep->prompt) {
- warnx("unrecognized field on line %d", line);
+ warnx("%s: unrecognized field on line %d",
+ tfn, line);
goto bad;
}
- if (!strncasecmp(buf, ep->prompt, ep->len)) {
- if (ep->restricted && uid) {
- warnx(
- "you may not change the %s field",
- ep->prompt);
- goto bad;
- }
- if (!(p = strchr(buf, ':'))) {
- warnx("line %d corrupted", line);
- goto bad;
- }
- while (isspace(*++p));
- if (ep->except && strpbrk(p, ep->except)) {
- warnx(
- "illegal character in the \"%s\" field",
- ep->prompt);
- goto bad;
- }
- if ((ep->func)(p, pw, ep)) {
-bad: (void)fclose(fp);
- return (0);
- }
- break;
+ if (ep->len > len)
+ continue;
+ if (strncasecmp(buf, ep->prompt, ep->len) != 0)
+ continue;
+ if (ep->restricted && !master_mode) {
+ warnx("%s: you may not change the %s field",
+ tfn, ep->prompt);
+ goto bad;
}
+ for (p = buf; p < buf + len && *p != ':'; ++p)
+ /* nothing */ ;
+ if (*p != ':') {
+ warnx("%s: line %d corrupted", tfn, line);
+ goto bad;
+ }
+ while (++p < buf + len && isspace(*p))
+ /* nothing */ ;
+ free(val);
+ asprintf(&val, "%.*s", (int)(buf + len - p), p);
+ if (val == NULL)
+ goto bad;
+ if (ep->except && strpbrk(val, ep->except)) {
+ warnx("%s: invalid character in \"%s\" field '%s'",
+ tfn, ep->prompt, val);
+ goto bad;
+ }
+ if ((ep->func)(val, pw, ep))
+ goto bad;
+ break;
}
}
- (void)fclose(fp);
+ free(val);
+ fclose(fp);
/* Build the gecos field. */
- len = strlen(list[E_NAME].save) + strlen(list[E_BPHONE].save) +
- strlen(list[E_HPHONE].save) + strlen(list[E_LOCATE].save) +
- strlen(list[E_OTHER].save) + 5;
- if (!(p = malloc(len)))
- err(1, NULL);
- (void)sprintf(pw->pw_gecos = p, "%s,%s,%s,%s,%s", list[E_NAME].save,
- list[E_LOCATE].save, list[E_BPHONE].save, list[E_HPHONE].save,
- list[E_OTHER].save);
-
- while ((len = strlen(pw->pw_gecos)) && pw->pw_gecos[len - 1] == ',')
- pw->pw_gecos[len - 1] = '\0';
-
- if ((size_t)snprintf(buf, sizeof(buf),
- "%s:%s:%lu:%lu:%s:%ld:%ld:%s:%s:%s",
- pw->pw_name, pw->pw_passwd, (unsigned long)pw->pw_uid,
- (unsigned long)pw->pw_gid, pw->pw_class, (long)pw->pw_change,
- (long)pw->pw_expire, pw->pw_gecos, pw->pw_dir,
- pw->pw_shell) >= sizeof(buf)) {
- warnx("entries too long");
- free(p);
- return (0);
+ len = asprintf(&p, "%s,%s,%s,%s,%s", list[E_NAME].save,
+ list[E_LOCATE].save, list[E_BPHONE].save,
+ list[E_HPHONE].save, list[E_OTHER].save);
+ if (p == NULL) {
+ warn("asprintf()");
+ free(pw);
+ return (NULL);
}
+ while (len > 0 && p[len - 1] == ',')
+ p[--len] = '\0';
+ pw->pw_gecos = p;
+ buf = pw_make(pw);
+ free(pw);
free(p);
- return (__pw_scan(buf, pw, _PWSCAN_WARN|_PWSCAN_MASTER));
+ if (buf == NULL) {
+ warn("pw_make()");
+ return (NULL);
+ }
+ npw = pw_scan(buf, PWSCAN_WARN|PWSCAN_MASTER);
+ free(buf);
+ return (npw);
+bad:
+ free(pw);
+ free(val);
+ fclose(fp);
+ return (NULL);
}
diff --git a/usr.bin/chpass/field.c b/usr.bin/chpass/field.c
index 0e2770b..ffa79fa 100644
--- a/usr.bin/chpass/field.c
+++ b/usr.bin/chpass/field.c
@@ -1,6 +1,13 @@
/*
* Copyright (c) 1988, 1993, 1994
* The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -47,6 +54,7 @@ __FBSDID("$FreeBSD$");
#include <err.h>
#include <errno.h>
#include <grp.h>
+#include <paths.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
@@ -54,7 +62,6 @@ __FBSDID("$FreeBSD$");
#include <unistd.h>
#include "chpass.h"
-#include "pathnames.h"
/* ARGSUSED */
int
@@ -62,15 +69,15 @@ p_login(char *p, struct passwd *pw, ENTRY *ep __unused)
{
if (!*p) {
warnx("empty login field");
- return (1);
+ return (-1);
}
if (*p == '-') {
warnx("login names may not begin with a hyphen");
- return (1);
+ return (-1);
}
if (!(pw->pw_name = strdup(p))) {
warnx("can't save entry");
- return (1);
+ return (-1);
}
if (strchr(p, '.'))
warnx("\'.\' is dangerous in a login name");
@@ -88,7 +95,7 @@ p_passwd(char *p, struct passwd *pw, ENTRY *ep __unused)
{
if (!(pw->pw_passwd = strdup(p))) {
warnx("can't save password entry");
- return (1);
+ return (-1);
}
return (0);
@@ -103,17 +110,17 @@ p_uid(char *p, struct passwd *pw, ENTRY *ep __unused)
if (!*p) {
warnx("empty uid field");
- return (1);
+ return (-1);
}
if (!isdigit(*p)) {
warnx("illegal uid");
- return (1);
+ return (-1);
}
errno = 0;
id = strtoul(p, &np, 10);
if (*np || (id == ULONG_MAX && errno == ERANGE)) {
warnx("illegal uid");
- return (1);
+ return (-1);
}
pw->pw_uid = id;
return (0);
@@ -129,12 +136,12 @@ p_gid(char *p, struct passwd *pw, ENTRY *ep __unused)
if (!*p) {
warnx("empty gid field");
- return (1);
+ return (-1);
}
if (!isdigit(*p)) {
if (!(gr = getgrnam(p))) {
warnx("unknown group %s", p);
- return (1);
+ return (-1);
}
pw->pw_gid = gr->gr_gid;
return (0);
@@ -143,7 +150,7 @@ p_gid(char *p, struct passwd *pw, ENTRY *ep __unused)
id = strtoul(p, &np, 10);
if (*np || (id == ULONG_MAX && errno == ERANGE)) {
warnx("illegal gid");
- return (1);
+ return (-1);
}
pw->pw_gid = id;
return (0);
@@ -155,7 +162,7 @@ p_class(char *p, struct passwd *pw, ENTRY *ep __unused)
{
if (!(pw->pw_class = strdup(p))) {
warnx("can't save entry");
- return (1);
+ return (-1);
}
return (0);
@@ -168,7 +175,7 @@ p_change(char *p, struct passwd *pw, ENTRY *ep __unused)
if (!atot(p, &pw->pw_change))
return (0);
warnx("illegal date for change field");
- return (1);
+ return (-1);
}
/* ARGSUSED */
@@ -178,16 +185,16 @@ p_expire(char *p, struct passwd *pw, ENTRY *ep __unused)
if (!atot(p, &pw->pw_expire))
return (0);
warnx("illegal date for expire field");
- return (1);
+ return (-1);
}
/* ARGSUSED */
int
-p_gecos(char *p, struct passwd *pw __unused, ENTRY *ep __unused)
+p_gecos(char *p, struct passwd *pw __unused, ENTRY *ep)
{
if (!(ep->save = strdup(p))) {
warnx("can't save entry");
- return (1);
+ return (-1);
}
return (0);
}
@@ -198,11 +205,11 @@ p_hdir(char *p, struct passwd *pw, ENTRY *ep __unused)
{
if (!*p) {
warnx("empty home directory field");
- return (1);
+ return (-1);
}
if (!(pw->pw_dir = strdup(p))) {
warnx("can't save entry");
- return (1);
+ return (-1);
}
return (0);
}
@@ -219,21 +226,21 @@ p_shell(char *p, struct passwd *pw, ENTRY *ep __unused)
return (0);
}
/* only admin can change from or to "restricted" shells */
- if (uid && pw->pw_shell && !ok_shell(pw->pw_shell)) {
+ if (!master_mode && pw->pw_shell && !ok_shell(pw->pw_shell)) {
warnx("%s: current shell non-standard", pw->pw_shell);
- return (1);
+ return (-1);
}
if (!(t = ok_shell(p))) {
- if (uid) {
+ if (!master_mode) {
warnx("%s: non-standard shell", p);
- return (1);
+ return (-1);
}
}
else
p = t;
if (!(pw->pw_shell = strdup(p))) {
warnx("can't save entry");
- return (1);
+ return (-1);
}
if (stat(pw->pw_shell, &sbuf) < 0) {
if (errno == ENOENT)
@@ -244,7 +251,7 @@ p_shell(char *p, struct passwd *pw, ENTRY *ep __unused)
return (0);
}
if (!S_ISREG(sbuf.st_mode)) {
- warnx("WARNING: shell '%s' is not a regular file",
+ warnx("WARNING: shell '%s' is not a regular file",
pw->pw_shell);
return (0);
}
diff --git a/usr.bin/chpass/pathnames.h b/usr.bin/chpass/pathnames.h
deleted file mode 100644
index 30f3c0d..0000000
--- a/usr.bin/chpass/pathnames.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 1989, 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.
- *
- * @(#)pathnames.h 8.1 (Berkeley) 6/6/93
- */
-
-#include <paths.h>
-
-#undef _PATH_TMP
-#define _PATH_TMP "/tmp/chpass.XXXXXX"
diff --git a/usr.bin/chpass/pw_copy.c b/usr.bin/chpass/pw_copy.c
deleted file mode 100644
index daebd20..0000000
--- a/usr.bin/chpass/pw_copy.c
+++ /dev/null
@@ -1,177 +0,0 @@
-/*-
- * Copyright (c) 1990, 1993, 1994
- * 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.
- *
- * $FreeBSD$
- */
-
-#ifndef lint
-static const char sccsid[] = "@(#)pw_copy.c 8.4 (Berkeley) 4/2/94";
-#endif /* not lint */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-/*
- * This module is used to copy the master password file, replacing a single
- * record, by chpass(1) and passwd(1).
- */
-
-#include <err.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <pw_scan.h>
-#include <pw_util.h>
-
-#include "pw_copy.h"
-
-extern char *tempname;
-
-/* for use in pw_copy(). Compare a pw entry to a pw struct. */
-static int
-pw_equal(char *buf, struct passwd *pw)
-{
- struct passwd buf_pw;
- int len;
-
- len = strlen (buf);
- if (buf[len-1] == '\n')
- buf[len-1] = '\0';
- if (!__pw_scan(buf, &buf_pw, _PWSCAN_MASTER))
- return 0;
- return (strcmp(pw->pw_name, buf_pw.pw_name) == 0
- && pw->pw_uid == buf_pw.pw_uid
- && pw->pw_gid == buf_pw.pw_gid
- && strcmp(pw->pw_class, buf_pw.pw_class) == 0
- && (long)pw->pw_change == (long)buf_pw.pw_change
- && (long)pw->pw_expire == (long)buf_pw.pw_expire
- && strcmp(pw->pw_gecos, buf_pw.pw_gecos) == 0
- && strcmp(pw->pw_dir, buf_pw.pw_dir) == 0
- && strcmp(pw->pw_shell, buf_pw.pw_shell) == 0);
-}
-
-void
-pw_copy(int ffd, int tfd, struct passwd *pw, struct passwd *old_pw)
-{
- FILE *from, *to;
- int done;
- char *p, buf[8192];
- char uidstr[20];
- char gidstr[20];
- char chgstr[20];
- char expstr[20];
-
- snprintf(uidstr, sizeof(uidstr), "%lu", (unsigned long)pw->pw_uid);
- snprintf(gidstr, sizeof(gidstr), "%lu", (unsigned long)pw->pw_gid);
- snprintf(chgstr, sizeof(chgstr), "%ld", (long)pw->pw_change);
- snprintf(expstr, sizeof(expstr), "%ld", (long)pw->pw_expire);
-
- if (!(from = fdopen(ffd, "r")))
- pw_error(_PATH_MASTERPASSWD, 1, 1);
- if (!(to = fdopen(tfd, "w")))
- pw_error(tempname, 1, 1);
-
- for (done = 0; fgets(buf, sizeof(buf), from);) {
- if (!strchr(buf, '\n')) {
- warnx("%s: line too long", _PATH_MASTERPASSWD);
- pw_error(NULL, 0, 1);
- }
- if (done) {
- (void)fprintf(to, "%s", buf);
- if (ferror(to))
- goto err;
- continue;
- }
- for (p = buf; *p != '\n'; p++)
- if (*p != ' ' && *p != '\t')
- break;
- if (*p == '#' || *p == '\n') {
- (void)fprintf(to, "%s", buf);
- if (ferror(to))
- goto err;
- continue;
- }
- if (!(p = strchr(buf, ':'))) {
- warnx("%s: corrupted entry", _PATH_MASTERPASSWD);
- pw_error(NULL, 0, 1);
- }
- *p = '\0';
- if (strcmp(buf, pw->pw_name)) {
- *p = ':';
- (void)fprintf(to, "%s", buf);
- if (ferror(to))
- goto err;
- continue;
- }
- *p = ':';
- if (old_pw && !pw_equal(buf, old_pw)) {
- warnx("%s: entry for %s has changed",
- _PATH_MASTERPASSWD, pw->pw_name);
- pw_error(NULL, 0, 1);
- }
- (void)fprintf(to, "%s:%s:%s:%s:%s:%s:%s:%s:%s:%s\n",
- pw->pw_name, pw->pw_passwd,
- pw->pw_fields & _PWF_UID ? uidstr : "",
- pw->pw_fields & _PWF_GID ? gidstr : "",
- pw->pw_class,
- pw->pw_fields & _PWF_CHANGE ? chgstr : "",
- pw->pw_fields & _PWF_EXPIRE ? expstr : "",
- pw->pw_gecos, pw->pw_dir, pw->pw_shell);
- done = 1;
- if (ferror(to))
- goto err;
- }
- if (!done) {
-#ifdef YP
- /* Ultra paranoid: shouldn't happen. */
- if (getuid()) {
- warnx("%s: not found in %s -- permission denied",
- pw->pw_name, _PATH_MASTERPASSWD);
- pw_error(NULL, 0, 1);
- } else
-#endif /* YP */
- (void)fprintf(to, "%s:%s:%s:%s:%s:%s:%s:%s:%s:%s\n",
- pw->pw_name, pw->pw_passwd,
- pw->pw_fields & _PWF_UID ? uidstr : "",
- pw->pw_fields & _PWF_GID ? gidstr : "",
- pw->pw_class,
- pw->pw_fields & _PWF_CHANGE ? chgstr : "",
- pw->pw_fields & _PWF_EXPIRE ? expstr : "",
- pw->pw_gecos, pw->pw_dir, pw->pw_shell);
- }
-
- if (ferror(to))
-err: pw_error(NULL, 1, 1);
- (void)fclose(to);
-}
diff --git a/usr.bin/chpass/pw_copy.h b/usr.bin/chpass/pw_copy.h
deleted file mode 100644
index 6e34e57..0000000
--- a/usr.bin/chpass/pw_copy.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 1994
- * 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.
- *
- * @(#)pw_copy.h 8.1 (Berkeley) 4/2/94
- * $FreeBSD$
- */
-
-void pw_copy(int, int, struct passwd *, struct passwd *);
diff --git a/usr.bin/chpass/pw_yp.c b/usr.bin/chpass/pw_yp.c
deleted file mode 100644
index df8a082..0000000
--- a/usr.bin/chpass/pw_yp.c
+++ /dev/null
@@ -1,530 +0,0 @@
-/*
- * Copyright (c) 1995
- * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
- * 4. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul 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.
- *
- * NIS interface routines for chpass
- *
- * Written by Bill Paul <wpaul@ctr.columbia.edu>
- * Center for Telecommunications Research
- * Columbia University, New York City
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#ifdef YP
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <rpc/rpc.h>
-#include <rpcsvc/yp.h>
-#include <rpcsvc/ypclnt.h>
-#include <rpcsvc/yppasswd.h>
-
-#include <db.h>
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <netdb.h>
-#include <pw_util.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <utmp.h>
-
-#include "pw_yp.h"
-#include "ypxfr_extern.h"
-#include "yppasswd_private.h"
-
-#define PERM_SECURE (S_IRUSR|S_IWUSR)
-static HASHINFO openinfo = {
- 4096, /* bsize */
- 32, /* ffactor */
- 256, /* nelem */
- 2048 * 1024, /* cachesize */
- NULL, /* hash */
- 0, /* lorder */
-};
-
-static char passwdbyname[] = "passwd.byname";
-static char localhost[] = "localhost";
-
-int force_old = 0;
-int _use_yp = 0;
-int suser_override = 0;
-int yp_in_pw_file = 0;
-char *yp_domain = NULL;
-char *yp_server = NULL;
-
-extern char *tempname;
-
-/* Save the local and NIS password information */
-struct passwd local_password;
-struct passwd yp_password;
-
-void
-copy_yp_pass(char *p, int x, int m)
-{
- register char *t, *s = p;
- static char *buf;
-
- yp_password.pw_fields = 0;
-
- buf = (char *)realloc(buf, m + 10);
- bzero(buf, m + 10);
-
- /* Turn all colons into NULLs */
- while (strchr(s, ':')) {
- s = (strchr(s, ':') + 1);
- *(s - 1)= '\0';
- }
-
- t = buf;
-#define EXPAND(e) e = t; while ((*t++ = *p++));
- EXPAND(yp_password.pw_name);
- yp_password.pw_fields |= _PWF_NAME;
- EXPAND(yp_password.pw_passwd);
- yp_password.pw_fields |= _PWF_PASSWD;
- yp_password.pw_uid = atoi(p);
- p += (strlen(p) + 1);
- yp_password.pw_fields |= _PWF_UID;
- yp_password.pw_gid = atoi(p);
- p += (strlen(p) + 1);
- yp_password.pw_fields |= _PWF_GID;
- if (x) {
- EXPAND(yp_password.pw_class);
- yp_password.pw_fields |= _PWF_CLASS;
- yp_password.pw_change = atol(p);
- p += (strlen(p) + 1);
- yp_password.pw_fields |= _PWF_CHANGE;
- yp_password.pw_expire = atol(p);
- p += (strlen(p) + 1);
- yp_password.pw_fields |= _PWF_EXPIRE;
- }
- EXPAND(yp_password.pw_gecos);
- yp_password.pw_fields |= _PWF_GECOS;
- EXPAND(yp_password.pw_dir);
- yp_password.pw_fields |= _PWF_DIR;
- EXPAND(yp_password.pw_shell);
- yp_password.pw_fields |= _PWF_SHELL;
-
- return;
-}
-
-static void
-copy_local_pass(char *p, int m)
-{
- register char *t;
- static char *buf;
-
- buf = (char *)realloc(buf, m + 10);
- bzero(buf, m + 10);
-
- t = buf;
- EXPAND(local_password.pw_name);
- EXPAND(local_password.pw_passwd);
- bcopy(p, (char *)&local_password.pw_uid, sizeof(int));
- p += sizeof(int);
- bcopy(p, (char *)&local_password.pw_gid, sizeof(int));
- p += sizeof(int);
- bcopy(p, (char *)&local_password.pw_change, sizeof(time_t));
- p += sizeof(time_t);
- EXPAND(local_password.pw_class);
- EXPAND(local_password.pw_gecos);
- EXPAND(local_password.pw_dir);
- EXPAND(local_password.pw_shell);
- bcopy(p, (char *)&local_password.pw_expire, sizeof(time_t));
- p += sizeof(time_t);
- bcopy(p, (char *)&local_password.pw_fields, sizeof local_password.pw_fields);
- p += sizeof local_password.pw_fields;
-
- return;
-}
-
-/*
- * It is not mandatory that an NIS master server also be a client.
- * However, if the NIS master is not configured as a client, then the
- * domain name will not be set and ypbind will not be running, so we
- * will be unable to use the ypclnt routines inside libc. We therefore
- * need our own magic version of yp_match() which we can use in any
- * environment.
- */
-static int
-my_yp_match(char *server, char *domain, const char *map, char *key,
- unsigned long keylen, char **result, unsigned long *resultlen)
-{
- ypreq_key ypkey;
- ypresp_val *ypval;
- CLIENT *clnt;
- static char buf[YPMAXRECORD + 2];
-
- bzero((char *)buf, sizeof(buf));
-
- /*
- * Don't make this a fatal error. The inability to contact
- * a server is, for our purposes, equivalent to not finding
- * the record we were looking for. Letting use_yp() know
- * that the lookup failed is sufficient.
- */
- if ((clnt = clnt_create(server, YPPROG,YPVERS,"udp")) == NULL)
- return(1);
-
- ypkey.domain = domain;
- ypkey.map = strdup(map);
- ypkey.key.keydat_len = keylen;
- ypkey.key.keydat_val = key;
-
- if ((ypval = ypproc_match_2(&ypkey, clnt)) == NULL) {
- clnt_destroy(clnt);
- return(1);
- }
-
- clnt_destroy(clnt);
-
- if (ypval->stat != YP_TRUE) {
- xdr_free(xdr_ypresp_val, (char *)ypval);
- return(1);
- }
-
-
- strncpy((char *)&buf, ypval->val.valdat_val, ypval->val.valdat_len);
-
- *result = (char *)&buf;
- *resultlen = ypval->val.valdat_len;
-
- xdr_free(xdr_ypresp_val, (char *)ypval);
-
- return(0);
-}
-
-/*
- * Check if the user we're working with is local or in NIS.
- */
-int
-use_yp(char *user, uid_t uid, int which /* 0 = use username, 1 = use uid */)
-{
- int user_local = 0, user_yp = 0, user_exists = 0;
- DB *dbp;
- DBT key,data;
- char bf[UT_NAMESIZE + 2];
- char *result;
- char *server;
- long resultlen;
- char ubuf[UT_NAMESIZE + 2];
-
- if (which) {
- snprintf(ubuf, sizeof(ubuf), "%lu", (unsigned long)uid);
- user = (char *)&ubuf;
- }
-
- /* Grope around for the user in the usual way */
- if (which) {
- if (getpwuid(uid) != NULL)
- user_exists = 1;
- } else {
- if (getpwnam(user) != NULL)
- user_exists = 1;
- }
-
- /* Now grope directly through the user database */
- if ((dbp = dbopen(_PATH_SMP_DB, O_RDONLY, PERM_SECURE,
- DB_HASH, &openinfo)) == NULL) {
- warn("error opening database: %s.", _PATH_MP_DB);
- pw_error(tempname, 0, 1);
- }
-
- /* Is NIS turned on */
- bf[0] = _PW_KEYYPENABLED;
- key.data = (u_char *)bf;
- key.size = 1;
- yp_in_pw_file = !(dbp->get)(dbp,&key,&data,0);
- if (_yp_check(NULL) || (yp_domain && yp_server)) {
- server = get_yp_master(0);
-
- /* Is the user in the NIS passwd map */
- if (!my_yp_match(server, yp_domain, which ? "passwd.byuid" :
- "passwd.byname", user, strlen(user),
- &result, &resultlen)) {
- user_yp = user_exists = 1;
- *(char *)(result + resultlen) = '\0';
- copy_yp_pass(result, 0, resultlen);
- }
- /* Is the user in the NIS master.passwd map */
- if (user_yp && !my_yp_match(server, yp_domain, which ?
- "master.passwd.byuid" : "master.passwd.byname",
- user, strlen(user),
- &result, &resultlen)) {
- *(char *)(result + resultlen) = '\0';
- copy_yp_pass(result, 1, resultlen);
- }
- }
-
- /* Is the user in the local password database */
-
- bf[0] = which ? _PW_KEYBYUID : _PW_KEYBYNAME;
- if (which)
- bcopy((char *)&uid, bf + 1, sizeof(uid));
- else
- bcopy((char *)user, bf + 1, MIN(strlen(user), UT_NAMESIZE));
- key.data = (u_char *)bf;
- key.size = which ? sizeof(uid) + 1 : strlen(user) + 1;
- if (!(dbp->get)(dbp,&key,&data,0)) {
- user_local = 1;
- copy_local_pass(data.data, data.size);
- }
-
- (dbp->close)(dbp);
-
- if (user_local && user_yp && user_exists)
- return(USER_YP_AND_LOCAL);
- else if (!user_local && user_yp && user_exists)
- return(USER_YP_ONLY);
- else if (user_local && !user_yp && user_exists)
- return(USER_LOCAL_ONLY);
- else if (!user_exists)
- return(USER_UNKNOWN);
-
- return(-1);
-}
-
-/*
- * Find the name of the NIS master server for this domain
- * and make sure it's running yppasswdd.
- */
-char *
-get_yp_master(int getserver)
-{
- char *mastername;
- int rval, localport;
-
- /*
- * Sometimes we are called just to probe for rpc.yppasswdd and
- * set the suser_override flag. Just return NULL and leave
- * suser_override at 0 if _use_yp doesn't indicate that NIS is
- * in use and we weren't called from use_yp() itself.
- * Without this check, we might try probing and fail with an NIS
- * error in non-NIS environments.
- */
- if ((_use_yp == USER_UNKNOWN || _use_yp == USER_LOCAL_ONLY) &&
- getserver)
- return(NULL);
-
- /* Get default NIS domain. */
-
- if (yp_domain == NULL && (rval = yp_get_default_domain(&yp_domain))) {
- warnx("can't get local NIS domain name: %s",yperr_string(rval));
- pw_error(tempname, 0, 1);
- }
-
- /* Get master server of passwd map. */
-
- if ((mastername = ypxfr_get_master(yp_domain, passwdbyname,
- yp_server, yp_server ? 0 : 1)) == NULL) {
- warnx("can't get name of master NIS server");
- pw_error(tempname, 0, 1);
- }
-
- if (!getserver)
- return(mastername);
-
- /* Check if yppasswdd is out there. */
-
- if ((rval = getrpcport(mastername, YPPASSWDPROG, YPPASSWDPROC_UPDATE,
- IPPROTO_UDP)) == 0) {
- warnx("rpc.yppasswdd is not running on the NIS master server");
- pw_error(tempname, 0, 1);
- }
-
- /*
- * Make sure it's on a reserved port.
- * XXX Might break with yppasswdd servers running on Solaris 2.x.
- */
-
- if (rval >= IPPORT_RESERVED) {
- warnx("rpc.yppasswdd server not running on reserved port");
- pw_error(tempname, 0, 1);
- }
-
- /* See if _we_ are the master server. */
- if (!force_old && !getuid() && (localport = getrpcport(localhost,
- YPPASSWDPROG, YPPASSWDPROC_UPDATE, IPPROTO_UDP)) != 0) {
- if (localport == rval) {
- suser_override = 1;
- mastername = localhost;
- }
- }
-
- /* Everything checks out: return the name of the server. */
-
- return (mastername);
-}
-
-/*
- * Ask the user for his NIS password and submit the new information
- * to yppasswdd. Note that rpc.yppasswdd requires password authentication
- * and only allows changes to existing records rather than the addition
- * of new records. (To do actual updates we would need something like
- * secure RPC and ypupdated, which FreeBSD doesn't have yet.) The FreeBSD
- * rpc.yppasswdd has some special hooks to allow the superuser update
- * information without specifying a password, however this only works
- * for the superuser on the NIS master server.
- */
-void
-yp_submit(struct passwd *pw)
-{
- struct yppasswd yppwd;
- struct master_yppasswd master_yppwd;
- struct netconfig *nconf;
- void *localhandle;
- CLIENT *clnt;
- char *master, *password;
- int *status = NULL;
- struct rpc_err lerr;
-
- nconf = NULL;
- _use_yp = 1;
-
- /* Get NIS master server name */
-
- master = get_yp_master(1);
-
- /* Populate the yppasswd structure that gets handed to yppasswdd. */
-
- if (suser_override) {
- master_yppwd.newpw.pw_passwd = strdup(pw->pw_passwd);
- master_yppwd.newpw.pw_name = strdup(pw->pw_name);
- master_yppwd.newpw.pw_uid = pw->pw_uid;
- master_yppwd.newpw.pw_gid = pw->pw_gid;
- master_yppwd.newpw.pw_expire = pw->pw_expire;
- master_yppwd.newpw.pw_change = pw->pw_change;
- master_yppwd.newpw.pw_fields = pw->pw_fields;
- master_yppwd.newpw.pw_gecos = strdup(pw->pw_gecos);
- master_yppwd.newpw.pw_dir = strdup(pw->pw_dir);
- master_yppwd.newpw.pw_shell = strdup(pw->pw_shell);
- master_yppwd.newpw.pw_class = pw->pw_class != NULL
- ? strdup(pw->pw_class)
- : strdup("");
- master_yppwd.oldpass = strdup(""); /* not really needed */
- master_yppwd.domain = yp_domain;
- } else {
- yppwd.newpw.pw_passwd = strdup(pw->pw_passwd);
- yppwd.newpw.pw_name = strdup(pw->pw_name);
- yppwd.newpw.pw_uid = pw->pw_uid;
- yppwd.newpw.pw_gid = pw->pw_gid;
- yppwd.newpw.pw_gecos = strdup(pw->pw_gecos);
- yppwd.newpw.pw_dir = strdup(pw->pw_dir);
- yppwd.newpw.pw_shell = strdup(pw->pw_shell);
- yppwd.oldpass = strdup("");
- }
-
- /* Get the user's password for authentication purposes. */
-
- printf ("Changing NIS information for %s on %s\n",
- pw->pw_name, master);
-
- if (pw->pw_passwd[0] && !suser_override) {
- password = getpass("Please enter password: ");
- if (strncmp(crypt(password,pw->pw_passwd),
- pw->pw_passwd,strlen(pw->pw_passwd))) {
- warnx("Password incorrect.");
- pw_error(tempname, 0, 1);
- }
- yppwd.oldpass = password; /* XXX */
- }
-
- if (suser_override) {
- /* Talk to server via AF_UNIX socket. */
- localhandle = setnetconfig();
- while ((nconf = getnetconfig(localhandle)) != NULL) {
- if (nconf->nc_protofmly != NULL &&
- strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0)
- break;
- }
- if (nconf == NULL) {
- warnx("getnetconfig: %s", nc_sperror());
- pw_error(tempname, 0, 1);
- }
-
- clnt = clnt_tp_create(NULL, MASTER_YPPASSWDPROG,
- MASTER_YPPASSWDVERS, nconf);
- if (clnt == NULL) {
- warnx("failed to contact rpc.yppasswdd: %s",
- clnt_spcreateerror(master));
- endnetconfig(localhandle);
- pw_error(tempname, 0, 1);
- }
- endnetconfig(localhandle);
- } else {
- /* Create a handle to yppasswdd. */
-
- if ((clnt = clnt_create(master, YPPASSWDPROG,
- YPPASSWDVERS, "udp")) == NULL) {
- warnx("failed to contact rpc.yppasswdd: %s",
- clnt_spcreateerror(master));
- pw_error(tempname, 0, 1);
- }
- }
-
- clnt->cl_auth = authunix_create_default();
-
- if (suser_override)
- status = yppasswdproc_update_master_1(&master_yppwd, clnt);
- else
- status = yppasswdproc_update_1(&yppwd, clnt);
-
- clnt_geterr(clnt, &lerr);
-
- auth_destroy(clnt->cl_auth);
- clnt_destroy(clnt);
-
- /* Call failed: signal the error. */
-
- if (lerr.re_status != RPC_SUCCESS || status == NULL || *status) {
- warnx("NIS update failed: %s", clnt_sperrno(lerr.re_status));
- pw_error(NULL, 0, 1);
- }
-
- /* Success. */
-
- if (suser_override)
- warnx("NIS information changed on host %s, domain %s",
- master, yp_domain);
- else
- warnx("NIS information changed on host %s", master);
-
- return;
-}
-#endif /* YP */
diff --git a/usr.bin/chpass/pw_yp.h b/usr.bin/chpass/pw_yp.h
deleted file mode 100644
index 774722e..0000000
--- a/usr.bin/chpass/pw_yp.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (c) 1995
- * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
- * 4. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Bill Paul 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.
- *
- * NIS interface routines for chpass
- *
- * Written by Bill Paul <wpaul@ctr.columbia.edu>
- * Center for Telecommunications Research
- * Columbia University, New York City
- *
- * $FreeBSD$
- */
-
-#ifdef YP
-#include <sys/types.h>
-#include <rpc/rpc.h>
-#include <rpc/auth.h>
-#include <rpc/auth_unix.h>
-/* Four possible return codes from use_yp() */
-#define USER_UNKNOWN 0
-#define USER_YP_ONLY 1
-#define USER_LOCAL_ONLY 2
-#define USER_YP_AND_LOCAL 3
-
-extern int force_old;
-extern int _use_yp;
-extern int suser_override;
-extern struct passwd local_password;
-extern struct passwd yp_password;
-extern void copy_yp_pass(char *, int, int);
-extern char *yp_domain;
-extern char *yp_server;
-extern void yp_submit(struct passwd *);
-extern int use_yp(char *, uid_t, int);
-extern char *get_yp_master(int);
-extern int yp_in_pw_file;
-
-/*
- * Yucky.
- */
-#define GETPWUID(X) \
- _use_yp = use_yp(NULL, X, 1); \
- \
- if (_use_yp == USER_UNKNOWN) { \
- errx(1, "unknown user: uid %u", X); \
- } \
- \
- if (_use_yp == USER_YP_ONLY) { \
- if (!force_local) { \
- _use_yp = 1; \
- pw = (struct passwd *)&yp_password; \
- } else \
- errx(1, "unknown local user: uid %u", X); \
- } else if (_use_yp == USER_LOCAL_ONLY) { \
- if (!force_yp) { \
- _use_yp = 0; \
- pw = (struct passwd *)&local_password; \
- } else \
- errx(1, "unknown NIS user: uid %u", X); \
- } else if (_use_yp == USER_YP_AND_LOCAL) { \
- if (!force_local && (force_yp || yp_in_pw_file)) { \
- _use_yp = 1; \
- pw = (struct passwd *)&yp_password; \
- } else { \
- _use_yp = 0; \
- pw = (struct passwd *)&local_password; \
- } \
- }
-
-#define GETPWNAM(X) \
- _use_yp = use_yp(X, 0, 0); \
- \
- if (_use_yp == USER_UNKNOWN) { \
- errx(1, "unknown user: %s", X); \
- } \
- \
- if (_use_yp == USER_YP_ONLY) { \
- if (!force_local) { \
- _use_yp = 1; \
- pw = (struct passwd *)&yp_password; \
- } else \
- errx(1, "unknown local user: %s.", X); \
- } else if (_use_yp == USER_LOCAL_ONLY) { \
- if (!force_yp) { \
- _use_yp = 0; \
- pw = (struct passwd *)&local_password; \
- } else \
- errx(1, "unknown NIS user: %s.", X); \
- } else if (_use_yp == USER_YP_AND_LOCAL) { \
- if (!force_local && (force_yp || yp_in_pw_file)) { \
- _use_yp = 1; \
- pw = (struct passwd *)&yp_password; \
- } else { \
- _use_yp = 0; \
- pw = (struct passwd *)&local_password; \
- } \
- }
-
-#endif /* YP */
diff --git a/usr.bin/chpass/util.c b/usr.bin/chpass/util.c
index 8703aeb..8460576 100644
--- a/usr.bin/chpass/util.c
+++ b/usr.bin/chpass/util.c
@@ -1,6 +1,13 @@
/*-
* Copyright (c) 1988, 1993, 1994
* The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -49,7 +56,6 @@ __FBSDID("$FreeBSD$");
#include <unistd.h>
#include "chpass.h"
-#include "pathnames.h"
static const char *months[] =
{ "January", "February", "March", "April", "May", "June",
OpenPOWER on IntegriCloud