Use libutil and libypclnt for all passwd manipulation and NIS needs.

Sponsored by:	DARPA, NAI Labs
This commit is contained in:
Dag-Erling Smørgrav
2002-05-08 00:54:29 +00:00
parent 492da65ed7
commit f1d0592537
17 changed files with 407 additions and 1593 deletions
+12 -9
View File
@@ -1,5 +1,12 @@
# Copyright 1998 Juniper Networks, Inc.
# All rights reserved.
# Copyright (c) 2002 Networks Associates Technology, Inc.
# All rights reserved.
#
# Portions of this software was 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
@@ -9,6 +16,9 @@
# 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. The name of the author may not be used to endorse or promote
# products derived from this software without specific prior written
# permission.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -25,17 +35,10 @@
# $FreeBSD$
LIB= pam_unix
SRCS= pam_unix.c pw_copy.c pw_util.c
CFLAGS+= -DYP \
-I. \
-I${.CURDIR}/../../../../usr.sbin/vipw \
-I${.CURDIR}/../../../../usr.bin/chpass \
-I${.CURDIR}/../../../../lib/libc/gen
SRCS= pam_unix.c
CFLAGS+= -DYP
DPADD= ${LIBUTIL} ${LIBCRYPT} ${LIBYPCLNT}
LDADD= -lutil -lcrypt -lypclnt
MAN= pam_unix.8
.include <bsd.lib.mk>
.PATH: ${.CURDIR}/../../../../usr.bin/chpass
.PATH: ${.CURDIR}/../../../../usr.sbin/vipw
+29 -13
View File
@@ -52,8 +52,7 @@ __FBSDID("$FreeBSD$");
#include <syslog.h>
#include <unistd.h>
#include <pw_copy.h>
#include <pw_util.h>
#include <libutil.h>
#ifdef YP
#include <ypclnt.h>
@@ -289,7 +288,7 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags,
struct options options;
char salt[SALTSIZE + 1];
login_cap_t * lc;
struct passwd *pwd;
struct passwd *pwd, *old_pwd;
const char *user, *old_pass, *new_pass;
char *encrypted;
int pfd, tfd, retval;
@@ -307,6 +306,9 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags,
pwd = getpwnam(user);
}
if (pwd == NULL)
return (PAM_AUTHTOK_RECOVERY_ERR);
PAM_LOG("Got user: %s", user);
if (flags & PAM_PRELIM_CHECK) {
@@ -362,6 +364,9 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags,
return (retval);
}
if ((old_pwd = pw_dup(pwd)) == NULL)
return (PAM_BUF_ERR);
pwd->pw_change = 0;
lc = login_getclass(NULL);
if (login_setcryptfmt(lc, password_hash, NULL) == NULL)
@@ -370,16 +375,24 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags,
login_close(lc);
makesalt(salt);
pwd->pw_passwd = crypt(new_pass, salt);
retval = PAM_SUCCESS;
#ifdef YP
switch (pwd->pw_fields & _PWF_SOURCE) {
switch (old_pwd->pw_fields & _PWF_SOURCE) {
case _PWF_FILES:
#endif
pfd = pw_lock();
tfd = pw_tmp();
pw_copy(pfd, tfd, pwd, NULL);
if (!pw_mkdb(user))
retval = PAM_SERVICE_ERR;
retval = PAM_SERVICE_ERR;
if (pw_init(NULL, NULL))
openpam_log(PAM_LOG_ERROR, "pw_init() failed");
else if ((pfd = pw_lock()) == -1)
openpam_log(PAM_LOG_ERROR, "pw_lock() failed");
else if ((tfd = pw_tmp(-1)) == -1)
openpam_log(PAM_LOG_ERROR, "pw_tmp() failed");
else if (pw_copy(pfd, tfd, pwd, old_pwd) == -1)
openpam_log(PAM_LOG_ERROR, "pw_copy() failed");
else if (pw_mkdb(pwd->pw_name) == -1)
openpam_log(PAM_LOG_ERROR, "pw_mkdb() failed");
else
retval = PAM_SUCCESS;
pw_fini();
#ifdef YP
break;
case _PWF_NIS:
@@ -390,12 +403,14 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags,
"yp_server", (const void **)&yp_server);
ypclnt = ypclnt_new(yp_domain,
"passwd.byname", yp_server);
if (ypclnt == NULL)
return (PAM_BUF_ERR);
if (ypclnt_connect(ypclnt) == -1 ||
if (ypclnt == NULL) {
retval = PAM_BUF_ERR;
} else if (ypclnt_connect(ypclnt) == -1 ||
ypclnt_passwd(ypclnt, pwd, old_pass) == -1) {
openpam_log(PAM_LOG_ERROR, "%s", ypclnt->error);
retval = PAM_SERVICE_ERR;
} else {
retval = PAM_SUCCESS;
}
ypclnt_free(ypclnt);
break;
@@ -412,6 +427,7 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags,
PAM_LOG("Illegal 'flags'");
}
free(old_pwd);
return (retval);
}
+8 -40
View File
@@ -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
+128 -125
View File
@@ -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
yp_domain = optarg;
break;
case 'h':
yp_host = optarg;
break;
case 'l':
_use_yp = 0;
force_local = 1;
break;
case 'y':
_use_yp = force_yp = 1;
break;
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);
if (!pw_mkdb(username))
pw_error((char *)NULL, 0, 1);
#ifdef YP
password = "";
}
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);
}
+11 -5
View File
@@ -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 *);
+133 -113
View File
@@ -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);
}
+31 -24
View File
@@ -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);
}
-39
View File
@@ -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"
-177
View File
@@ -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);
}
-37
View File
@@ -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 *);
-530
View File
@@ -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 */
-126
View File
@@ -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 */
+7 -1
View File
@@ -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",
+2 -1
View File
@@ -3,7 +3,8 @@
PROG= vipw
MAN= vipw.8
SRCS= pw_util.c vipw.c
DPADD= ${LIBUTIL}
LDADD= -lutil
WARNS?= 4
.include <bsd.prog.mk>
-258
View File
@@ -1,258 +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.
*/
#ifndef lint
#if 0
static const char sccsid[] = "@(#)pw_util.c 8.3 (Berkeley) 4/2/94";
#endif
static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
/*
* This file is used by all the "password" programs; vipw(8), chpass(1),
* and passwd(1).
*/
#include <sys/param.h>
#include <sys/errno.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <err.h>
#include <fcntl.h>
#include <paths.h>
#include <pwd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "pw_util.h"
extern char *tempname;
static pid_t editpid = -1;
static int lockfd;
static char _default_editor[] = _PATH_VI;
static char _default_mppath[] = _PATH_PWD;
static char _default_masterpasswd[] = _PATH_MASTERPASSWD;
char *mppath = _default_mppath;
char *masterpasswd = _default_masterpasswd;
void pw_cont(int);
void
pw_cont(int sig)
{
if (editpid != -1)
kill(editpid, sig);
}
void
pw_init(void)
{
struct rlimit rlim;
/* Unlimited resource limits. */
rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
(void)setrlimit(RLIMIT_CPU, &rlim);
(void)setrlimit(RLIMIT_FSIZE, &rlim);
(void)setrlimit(RLIMIT_STACK, &rlim);
(void)setrlimit(RLIMIT_DATA, &rlim);
(void)setrlimit(RLIMIT_RSS, &rlim);
/* Don't drop core (not really necessary, but GP's). */
rlim.rlim_cur = rlim.rlim_max = 0;
(void)setrlimit(RLIMIT_CORE, &rlim);
/* Turn off signals. */
(void)signal(SIGALRM, SIG_IGN);
(void)signal(SIGHUP, SIG_IGN);
(void)signal(SIGINT, SIG_IGN);
(void)signal(SIGPIPE, SIG_IGN);
(void)signal(SIGQUIT, SIG_IGN);
(void)signal(SIGTERM, SIG_IGN);
(void)signal(SIGCONT, pw_cont);
/* Create with exact permissions. */
(void)umask(0);
}
int
pw_lock(void)
{
/*
* If the master password file doesn't exist, the system is hosed.
* Might as well try to build one. Set the close-on-exec bit so
* that users can't get at the encrypted passwords while editing.
* Open should allow flock'ing the file; see 4.4BSD. XXX
*/
for (;;) {
struct stat st;
lockfd = open(masterpasswd, O_RDONLY, 0);
if (lockfd < 0 || fcntl(lockfd, F_SETFD, 1) == -1)
err(1, "%s", masterpasswd);
if (flock(lockfd, LOCK_EX|LOCK_NB))
errx(1, "the password db file is busy");
/*
* If the password file was replaced while we were trying to
* get the lock, our hardlink count will be 0 and we have to
* close and retry.
*/
if (fstat(lockfd, &st) < 0)
errx(1, "fstat() failed");
if (st.st_nlink != 0)
break;
close(lockfd);
lockfd = -1;
}
return (lockfd);
}
int
pw_tmp(void)
{
static char path[MAXPATHLEN];
int fd;
char *p;
strncpy(path, masterpasswd, MAXPATHLEN - 1);
path[MAXPATHLEN] = '\0';
if ((p = strrchr(path, '/')))
++p;
else
p = path;
strcpy(p, "pw.XXXXXX");
if ((fd = mkstemp(path)) == -1)
err(1, "%s", path);
tempname = path;
return (fd);
}
int
pw_mkdb(const char *username)
{
int pstat;
pid_t pid;
(void)fflush(stderr);
if (!(pid = fork())) {
if(!username) {
warnx("rebuilding the database...");
execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p", "-d", mppath,
tempname, (char *)NULL);
} else {
warnx("updating the database...");
execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p", "-d", mppath,
"-u", username, tempname, (char *)NULL);
}
pw_error(_PATH_PWD_MKDB, 1, 1);
}
pid = waitpid(pid, &pstat, 0);
if (pid == -1 || !WIFEXITED(pstat) || WEXITSTATUS(pstat) != 0)
return (0);
warnx("done");
return (1);
}
void
pw_edit(int notsetuid)
{
int pstat;
char *p, *editor;
if (!(editor = getenv("EDITOR")))
editor = _default_editor;
if ((p = strrchr(editor, '/')))
++p;
else
p = editor;
if (!(editpid = fork())) {
if (notsetuid) {
(void)setgid(getgid());
(void)setuid(getuid());
}
errno = 0;
execlp(editor, p, tempname, (char *)NULL);
_exit(errno);
}
for (;;) {
editpid = waitpid(editpid, (int *)&pstat, WUNTRACED);
errno = WEXITSTATUS(pstat);
if (editpid == -1)
pw_error(editor, 1, 1);
else if (WIFSTOPPED(pstat))
raise(WSTOPSIG(pstat));
else if (WIFEXITED(pstat) && errno == 0)
break;
else
pw_error(editor, 1, 1);
}
editpid = -1;
}
void
pw_prompt(void)
{
int c, first;
(void)printf("re-edit the password file? [y]: ");
(void)fflush(stdout);
first = c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
if (first == 'n')
pw_error(NULL, 0, 0);
}
void
pw_error(const char *name, int error, int eval)
{
if (error) {
if (name != NULL)
warn("%s", name);
else
warn(NULL);
}
warnx("password information unchanged");
(void)unlink(tempname);
exit(eval);
}
-44
View File
@@ -1,44 +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_util.h 8.2 (Berkeley) 4/1/94
*
* $FreeBSD$
*/
void pw_edit(int);
void pw_error(const char *, int, int);
void pw_init(void);
int pw_lock(void);
int pw_mkdb(const char *);
void pw_prompt(void);
int pw_tmp(void);
+46 -51
View File
@@ -1,6 +1,13 @@
/*
* Copyright (c) 1987, 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
@@ -55,37 +62,22 @@ static const char rcsid[] =
#include <string.h>
#include <unistd.h>
#include "pw_util.h"
#include <libutil.h> /* must be after pwd.h */
extern char *mppath;
extern char *masterpasswd;
char *tempname;
static void copyfile(int, int);
static void usage(void);
int
main(int argc, char *argv[])
{
int pfd, tfd;
struct stat begin, end;
int ch;
const char *passwd_dir = NULL;
int ch, pfd, tfd;
char *line;
size_t len;
while ((ch = getopt(argc, argv, "d:")) != -1)
switch (ch) {
case 'd':
if ((masterpasswd = malloc(strlen(optarg) +
strlen(_MASTERPASSWD) + 2)) == NULL)
err(1, NULL);
strcpy(masterpasswd, optarg);
if (masterpasswd[strlen(masterpasswd) - 1] != '/')
strcat(masterpasswd, "/" _MASTERPASSWD);
else
strcat(masterpasswd, _MASTERPASSWD);
if ((mppath = strdup(optarg)) == NULL)
err(1, NULL);
if (mppath[strlen(mppath) - 1] == '/')
mppath[strlen(mppath) - 1] = '\0';
passwd_dir = optarg;
break;
case '?':
default:
@@ -98,49 +90,52 @@ main(int argc, char *argv[])
if (argc != 0)
usage();
pw_init();
pfd = pw_lock();
tfd = pw_tmp();
copyfile(pfd, tfd);
if (pw_init(passwd_dir, NULL) == -1)
err(1, "pw_init()");
if ((pfd = pw_lock()) == -1) {
pw_fini();
err(1, "pw_lock()");
}
if ((tfd = pw_tmp(pfd)) == -1) {
pw_fini();
err(1, "pw_tmp()");
}
(void)close(tfd);
/* Force umask for partial writes made in the edit phase */
(void)umask(077);
for (;;) {
if (stat(tempname, &begin))
pw_error(tempname, 1, 1);
pw_edit(0);
if (stat(tempname, &end))
pw_error(tempname, 1, 1);
if (begin.st_mtime == end.st_mtime) {
warnx("no changes made");
pw_error((char *)NULL, 0, 0);
}
if (pw_mkdb((char *)NULL))
switch (pw_edit(NULL)) {
case -1:
pw_fini();
err(1, "pw_edit()");
case 0:
pw_fini();
errx(0, "no changes made");
default:
break;
}
if (pw_mkdb(NULL) == 0) {
pw_fini();
errx(0, "password list updated");
}
printf("re-edit the password file? ");
fflush(stdout);
if ((line = fgetln(stdin, &len)) == NULL) {
pw_fini();
err(1, "fgetln()");
}
if (len > 0 && (*line == 'N' || *line == 'n'))
break;
pw_prompt();
}
pw_fini();
exit(0);
}
static void
copyfile(int from, int to)
{
int nr, nw, off;
char buf[8*1024];
while ((nr = read(from, buf, sizeof(buf))) > 0)
for (off = 0; off < nr; nr -= nw, off += nw)
if ((nw = write(to, buf + off, nr)) < 0)
pw_error(tempname, 1, 1);
if (nr < 0)
pw_error(masterpasswd, 1, 1);
}
static void
usage(void)
{
(void)fprintf(stderr, "usage: vipw [ -d directory ]\n");
(void)fprintf(stderr, "usage: vipw [-d directory]\n");
exit(1);
}