|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T p
Length: 16110 (0x3eee)
Types: TextFile
Names: »pw_yp.c.orig«
└─⟦4f9d7c866⟧ Bits:30007245 EUUGD6: Sikkerheds distributionen
└─⟦123909933⟧ »./npasswd/npasswd.tar.Z«
└─⟦22a202e7d⟧
└─⟦this⟧ »npass-new/npasswd_jpl/pw_yp.c.orig«
/* -------------------------------------------------------------------- */
/* */
/* Author: Clyde Hoover */
/* Computation Center */
/* The University of Texas at Austin */
/* Austin, Texas 78712 */
/* clyde@emx.utexas.edu */
/* uunet!cs.utexas.edu!ut-emx!clyde */
/* */
/*This code may be distributed freely, provided this notice is retained. */
/* */
/* -------------------------------------------------------------------- */
/*
* pw_yp - Routines for dealing with SUN Yellow Pages password files
*
* This code can update local password file, can cause rebuilding of
* local YP maps and can use yppasswdd(8) to change YP passwords.
*
* Must be linked with -lrpcsvc
*/
#include <stdio.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <signal.h>
#include <errno.h>
#include <pwd.h>
#include <fcntl.h>
#include <rpc/rpc.h>
#include <rpcsvc/ypclnt.h>
#include <rpcsvc/yppasswd.h>
#include <sys/socket.h>
#ifdef SECURE_RPC
#include <rpc/key_prot.h>
#endif
#ifdef SYSV
#define index strchr
#endif
#ifdef SYSLOG
#include <syslog.h>
#endif
#ifndef lint
static char sccsid[] = "@(#)pw_yp.c 1.15 1/25/91 (cc.utexas.edu)";
#endif
#define NONE -1 /* YP not active */
#define NOT 0 /* YP active - we are not master */
#define IS 1 /* YP active - we have the password file */
#define SLOP 128 /* Size difference tolerated old <> new passwd file */
typedef struct passwd passwd;
typedef struct passwd *passwdp;
static passwd theUser, /* User being changed */
Me; /* User invoking passwd */
static int myuid, /* Uid of invoker */
mytempfile = 0; /* Does PASSWD_TEMP belong to me? */
static char *ypmaster, /* Name of the YP master */
*ypdomain; /* YP domain name */
#define PASSWD_MAP "passwd.byname" /* Name of YP passwd map */
/*
* File names
*/
#ifndef PASSWD_FILE
#define PASSWD_FILE "/etc/passwd"
#endif
#ifndef PASSWD_SAVE
#define PASSWD_SAVE "/etc/opasswd"
#endif
#ifndef PASSWD_TEMP
#define PASSWD_TEMP "/etc/ptmp"
#endif
#define PASSWD_MODE 0644
#ifdef DEBUG
static char *passwdtemp = "./etc_ptmp", /* Temp file */
*passwdfile = "./etc_passwd", /* Password file */
*savefile = "./etc_opasswd"; /* Save file */
#else
static char *passwdtemp = PASSWD_TEMP,
*passwdfile = PASSWD_FILE,
*savefile = PASSWD_SAVE;
#endif
static char auxlockfile[MAXPATHLEN]; /* Aux lock file */
extern int errno;
char *getlogin(),
*crypt();
/*
* pw_initialize - set up
*/
pw_initialize()
{
passwdp me; /* Passwd for invoker */
char *myname = getlogin(); /* Invoker login name */
#ifdef DEBUG
setpwfile(passwdfile);
#endif
myuid = getuid();
if (myname && *myname) {
if ((me = getpwnam(myname)) == NULL)
quit(1, "Cannot get user identification from name.\n");
} else {
if ((me = getpwuid(myuid)) == NULL)
quit(1, "Cannot get user identification from uid.\n");
}
_cppasswd(me, &Me);
return(1);
}
/*
* pw_getuserbyname - get password
*
* Returns 1 if passwd found for <name>
* 0 otherwise
*/
pw_getuserbyname(name, passwdb)
char *name, /* User name */
*passwdb; /* Where to stuff password */
{
passwdp p; /* Temp */
if ((p = getpwnam(name)) == NULL)
return(0);
_cppasswd(p, &theUser);
(void) strcpy(passwdb, p->pw_passwd);
return(1);
}
/*
* pw_permission - check password change permission
*
* Returns 1 if password can be changed
* 0 if not
*/
pw_permission()
{
/*
* Is this my password or someone elses?
*/
if (strcmp(Me.pw_name, theUser.pw_name) && myuid)
return(0);
/*
* If on a YP client, root cannot change another
* users' password via yppasswd(), since we can't
* get a plain text password to pass to yppasswdd().
*/
if (myuid == 0 && is_yp_master() == NOT) {
FILE *pf;
passwdp px, /* Password file traversal */
fgetpwent();
int rc = 0;
/* What if passwdfile != /etc/passwd? */
if ((pf = fopen(passwdfile, "r")) == NULL)
quit(1, "Cannot open password file \"%s\".\n", passwdfile);
/*
* Scan local password file, looking for user
* Cannot use getpwnam() because it will use YP - I want to know
* if the user's password file entry is >>local<<
*/
while ((px = fgetpwent(pf)) != NULL) {
if (strcmp(px->pw_name, theUser.pw_name) == 0) {
rc = 1;
break;
}
}
fclose(pf);
if (rc) {
if (strncmp(px->pw_passwd, "##", 2) == 0)
quit(0,
"Changing of adjunct passwords not supported.\n");
return(1);
}
else
quit(0, "Password for %s can only be changed on YP server %s.\n",
theUser.pw_name, ypmaster);
}
/* Check if passwd is '##username' - can't do that yet */
/*
* Other checks can be put here to determine if the invoker should
* be allowed to change this password.
*/
return(1);
}
/*
* pw_compare - compare old and new passwords
*
* Returns 1 if check = new, 0 if not
*/
pw_compare(current, new)
char *current, /* Current pw (encrypted) */
*new; /* check pw (plain) */
{
if (!*current) /* Is current password null? */
return(0);
/* Put other administrative checks here */
return(!strcmp(current, crypt(new, current)));
}
/*
* pw_check - sanity check password. Right now just calls
* the password check code
*
* Returns 1 if password is ok to use, 0 otherwise
*/
pw_check(pwd)
char *pwd;
{
int rc = checkpasswd(theUser.pw_uid, pwd);
#ifdef PASSWORD_HISTORY
if (rc)
return(rc);
/* Call password history checker to prevent password reuse */
rc = passwd_history(theUser.pw_uid, pwd);
#endif
return(rc);
}
/* Error message for when yppasswdd fails with error code 1. */
static char *yperrmsg =
"Password change failed: Problem with yppasswdd.\n\n\
This is probably because the YP maps are out of sync\n\
with the YP passwd file for %s on %s.\n\n\
Please try again later.\n";
/*
* pw_replace - replace password in passwd file
*/
pw_replace(newpwd, curpwd)
char *newpwd, /* New password (plain) */
*curpwd; /* Old password (plain) */
{
passwdp px, /* Password file traversal */
fgetpwent();
long oldsigs, /* Old signal mask */
blocksigs = sigmask(SIGINT) | /* Sigs to block */
sigmask(SIGQUIT) |
sigmask(SIGTSTP);
FILE *tf, /* New password file output */
*pf; /* Current password file input */
int fd, /* Temp file create fd */
islocal = 0; /* Is user in local password file */
struct stat oldstat, /* Old password file stat */
newstat; /* New password file stat */
if ((pf = fopen(passwdfile, "r")) == NULL)
quit(1, "Cannot open password file \"%s\".\n", passwdfile);
/*
* Scan local password file, looking for user
* Cannot use getpwnam() because it will use YP - I want to know
* if I have to change a >>local<< password file.
*/
while ((px = fgetpwent(pf)) != NULL) {
if (*px->pw_name == '+' || *px->pw_name == '-')
continue;
if (strcmp(px->pw_name, theUser.pw_name) == 0) {
if (strncmp(px->pw_passwd, "##", 2) == 0)
quit(0,
"Changing of adjunct passwords not supported.\n");
islocal++;
break;
}
}
rewind(pf);
/*
* If the user was not in the local password file, use RPC
* to update the Yellow Pages (NIS) password file.
*/
if (islocal == 0) {
if (is_yp_master() == NOT) {
int rc; /* Return code from ypasswdd */
int why; /* RPC call return code */
int ypport; /* Port for RPC call */
struct yppasswd yppasswd; /* YP passwd change block */
char salt[4]; /* Password encryption salt */
if (curpwd[0] == 0)
quit(0, "Cannot change YP password without old password.\n");
randomstring(salt, sizeof(salt));
theUser.pw_passwd = crypt(newpwd, salt);
yppasswd.oldpass = curpwd;
_cppasswd(&theUser, &yppasswd.newpw);
#ifdef DEBUG
printf("yppasswd(%s, %s)\n", curpwd, theUser.pw_passwd);
#else
if ((ypport = getrpcport(ypmaster, YPPASSWDPROG,
YPPASSWDPROC_UPDATE, IPPROTO_UDP)) == 0)
quit(1, "%s is not running ypassswdd.\n",
ypmaster);
if (ypport >= IPPORT_RESERVED)
quit(1, "yppasswdd on %s not privleged.\n",
ypmaster);
rc = callrpc(ypmaster, YPPASSWDPROG, YPPASSWDVERS,
YPPASSWDPROC_UPDATE, xdr_yppasswd, &yppasswd,
xdr_int, &why);
/* RPC call error */
if (rc)
#if NO_CLNT_SPERRNO
clnt_perrno(rc);
quit(1, "Password change failed (%s)\n",
ypmaster);
#else
quit(1, "Password change failed (%s): %s\n",
ypmaster, clnt_sperrno(rc));
#endif
/* Error returned from yppasswdd */
if (why) {
#ifdef SYSLOG
syslog(LOG_ERR,
"yppasswdd error %d on %s for %s",
why, ypmaster, theUser.pw_name);
#endif
if (why == 1)
quit(0, yperrmsg, ypdomain, ypmaster);
else
quit(1, "Password change failed.\n");
}
# ifdef SECURE_RPC
reset_secret_key(curpwd);
# endif /* SECURE_RPC */
#endif /* DEBUG */
return;
}
else /* User not in local passwd, and not in YP passwd */
quit(1, "User %s missing from password file.\n",
theUser.pw_name);
}
/*
* There is a local password file to change
*/
(void) umask(0);
(void) fstat(fileno(pf), &oldstat);
/*
* Use different temp file if on YP master.
* This deals with the SunOS 4.0.3 yppasswdd which creates temp files
* named "passwd-file.ptmp", rather than the traditional "/etc/ptmp".
* But there are still a lot of applications which use /etc/ptmp,
* so is it used as the passwd temp file and the 'auxlockfile' is
* also made --- >>>GROAN<<<.
*/
auxlockfile[0] = 0;
if (is_yp_master() == IS) {
(void) sprintf(auxlockfile, "%s.ptmp", passwdfile);
close(mklocktemp(auxlockfile));
}
mytempfile = 1;
fd = mklocktemp(passwdtemp);
if ((tf = fdopen(fd, "w")) == NULL)
quit(1, "Cannot fdopen temp file.\n");
oldsigs = sigblock(blocksigs);
while ((px = fgetpwent(pf)) != NULL) {
if (px->pw_name == 0 || px->pw_name[0] == 0) /* Sanity check */
continue;
if (strcmp(px->pw_name, theUser.pw_name) == 0) {
char salt[4]; /* Password encryption salt */
randomstring(salt, sizeof(salt));
theUser.pw_passwd = crypt(newpwd, salt);
px = &theUser;
}
(void) putpwent(px, tf);
}
(void) fflush(tf); /* Force buffers empty */
(void) fstat(fileno(tf), &newstat); /* Get size */
(void) fclose(tf);
(void) fclose(pf);
/*
* Check if the new password file is complete. Since the encrypted
* password is of a fixed length, the new file should be roughly
* the same size as the old one.
*
* This assumption will FAIL when this program does chfn and chsh!!! -
* use line counts.
*/
if (newstat.st_size < (oldstat.st_size - SLOP))
quit(1,
"New password file appears to be incomplete - aborting.\n");
if (rename(passwdfile, savefile) < 0) {
perror("Password file save");
(void) unlink(passwdtemp);
quit(1, "Can't save password file.\n");
}
if (rename(passwdtemp, passwdfile) < 0) {
perror("Password file replace");
(void) unlink(passwdtemp);
(void) link(savefile, passwdfile);
quit(1, "Can't replace password file.\n");
}
if (is_yp_master() == IS)
updateyp();
(void) sigsetmask(oldsigs);
}
/*
* pw_cleanup - clean up after myself
*/
pw_cleanup(code)
int code; /* 0 for normal, 1 for abort */ /*NOTUSED*/
{
if (mytempfile) {
(void) unlink(passwdtemp);
if (auxlockfile[0])
(void) unlink(auxlockfile);
}
}
/*
* _newstr - copy string into new storage
*/
static char *
_newstr(s)
char *s; /* String to copy */
{
register char *t; /* Temp */
char *malloc();
if (s == NULL)
return(0);
t = malloc(strlen(s) + 1);
if (t == NULL)
quit(1, "No memory.\n");
(void) strcpy(t, s);
return(t);
}
/*
* mklocktemp - Make temp file with exclusive use checking
*
* Returns file descriptor of created file, else exits with error
*/
static int
mklocktemp(name)
char *name;
{
int fd;
fd = open(name, O_WRONLY|O_CREAT|O_EXCL, PASSWD_MODE);
if (fd < 0) {
if (errno == EEXIST)
quit(0, "Password file busy - try again.\n");
perror("Tempfile create");
quit(1, "Cannot create temp file.\n");
}
return(fd);
}
/*
* _cppasswd - copy a passwd structure
*/
static
_cppasswd(f,t)
passwdp f, /* From */
t; /* To */
{
*t = *f;
t->pw_name = _newstr(f->pw_name);
t->pw_passwd = _newstr(f->pw_passwd);
t->pw_comment = _newstr(f->pw_comment);
t->pw_gecos = _newstr(f->pw_gecos);
t->pw_dir = _newstr(f->pw_dir);
t->pw_shell = _newstr(f->pw_shell);
}
/*
* is_yp_master - Figure out whether we are running on the Yellow Pages
* master for the password file maps.
*
* Returns:
* IS if we are the master
* NOT if we are not the master
* NONE if there is no master
*/
#include <netdb.h>
#ifndef MAXHOSTNAMLEN
#define MAXHOSTNAMLEN 32
#endif
is_yp_master()
{
static char known = 0, /* We've been here */
answer = NOT; /* ...and this is the answer */
char hostname[MAXHOSTNAMLEN]; /* Our host name */
char *index();
struct hostent *hinfo;
if (known)
return(answer);
(void) gethostname(hostname, sizeof(hostname));
if (yp_get_default_domain(&ypdomain)) {
/* quit(1, "Cannot get YP domain.\n"); */
known++;
return(answer = NONE); /* Assume no YP running */
}
if (yp_master(ypdomain, PASSWD_MAP, &ypmaster)) {
known++;
return(answer = NONE); /* Assume no YP running */
}
known++;
#ifdef FASTCHECK
/*
* Stupid (but fast) hostname check (first component only)
*/
{
char *p; /* Scratch */
if (p = index(ypmaster, '.')) *p = 0;
if (p = index(hostname, '.')) *p = 0;
}
#else
/*
* Compare my host name and the YP master's host name.
* Use gethostbyname() to return the fully qualified form so that
* a string compare can be done.
*/
if (index(hostname, '.') == 0) {
if ((hinfo = gethostbyname(hostname)) == 0)
quit(1, "Cannot get hostinfo for self.\n");
(void) strcpy(hostname, hinfo->h_name);
}
if (index(ypmaster, '.') == 0) {
static char ypmaster_f[MAXHOSTNAMLEN];
if ((hinfo = gethostbyname(ypmaster)) == 0)
quit(1, "Cannot get hostinfo for ypmaster.\n");
(void) strcpy(ypmaster_f, hinfo->h_name);
ypmaster = ypmaster_f;
}
#endif
if (strcmp(ypmaster, hostname) == 0)
return(answer = IS);
return(answer);
}
/*
* An example sh(1) script to update YP password map
*/
char *ypcmd =
"(PATH=/bin:/usr/bin; export PATH; ypdirs='/var/yp /etc/yp'\n\
for d in $ypdirs; do\n\
if [ -d $d ]; then\n\
cd $d; exec make passwd\n\
fi\n\
done\n\
echo 'passwd: Cannot rebuild YP maps!' 1>&2\n\
false) >/dev/null &\n";
/*
* updateyp - update local YP maps
*/
updateyp()
{
(void) setuid(geteuid()); /* Get all privs */
/* (This assumes that we are setuid root) */
/*
* This machine is the YP master for passwd - invoke something
* to update the YP maps.
* Super-user can override the default YP updater by setting
* env "YP_UPDATE_PROC" to a command to be run instead.
* The name of the user being changed is piped to stdin of the command.
*/
if (myuid == 0) {
char *getenv();
char *proc = getenv("YP_UPDATE_PROC");
if (proc && *proc) {
char cmdbuf[BUFSIZ];
(void) sprintf(cmdbuf, "/bin/echo '%s' | ( %s )",
theUser.pw_name, proc);
#ifdef DEBUG
printf("updateyp (proc): %s", cmdbuf);
#endif
(void) system(cmdbuf);
return;
}
}
#ifdef DEBUG
printf("updateyp: %s", ypcmd);
#endif
(void) system(ypcmd);
}
#ifdef SECURE_RPC
/*
* reset_secret_key - Reset secret key for secure RPC
*/
reset_secret_key(curpwd)
char *curpwd;
{
char mynet[MAXNETNAMELEN+1],
key[HEXKEYBYTES+1];
getnetname(mynet);
if (!getsecretkey(mynet, key, curpwd))
return; /* Secure RPC not running */
if (key[0] = 0)
return; /* No secret key */
fprintf(stderr, "Cannot change secure RPC key\n");
/*
* Actually I could, but I'd have to steal from Sun source
* code to do it. Sun wouldn't like that very much, so I won't.
*/
}
#endif
/* End pw_yp.c */