diff options
Diffstat (limited to 'usr.bin/chpass')
-rw-r--r-- | usr.bin/chpass/Makefile | 48 | ||||
-rw-r--r-- | usr.bin/chpass/chpass.c | 251 | ||||
-rw-r--r-- | usr.bin/chpass/chpass.h | 16 | ||||
-rw-r--r-- | usr.bin/chpass/edit.c | 246 | ||||
-rw-r--r-- | usr.bin/chpass/field.c | 55 | ||||
-rw-r--r-- | usr.bin/chpass/pathnames.h | 39 | ||||
-rw-r--r-- | usr.bin/chpass/pw_copy.c | 177 | ||||
-rw-r--r-- | usr.bin/chpass/pw_copy.h | 37 | ||||
-rw-r--r-- | usr.bin/chpass/pw_yp.c | 530 | ||||
-rw-r--r-- | usr.bin/chpass/pw_yp.h | 126 | ||||
-rw-r--r-- | usr.bin/chpass/util.c | 8 |
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", |