Use libutil and libypclnt for all passwd manipulation and NIS needs.
Sponsored by: DARPA, NAI Labs
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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 *);
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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",
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user