freebsd-dev/gnu/usr.sbin/yppasswdd/update.c
Bill Paul 6c394ac5f9 Obtained from: The NYS project
This is a ported/modified version of yppasswd from the NYS yppasswd-0.5
package. This package has code in it from both Olaf Kirch and Theo
de Raadt. There are GPL references and BSD-style copyright all over the
place... hopefully I won't get flamed into oblivion for commiting this.

This program has been modified from the original in the following ways:

- Changed the ALLOW_CHFN and ALLOW_CHSH compile-time options into
  run-time options.

- Demolished the password update functions and replaced them with
  routines to handle FreeBSD-style passwordd databases. It is expected
  that a seperate master.passwd file will be maintained for use with
  the NIS maps. yppasswd will have to be told where it is:

  % yppasswdd -m /var/yp/master.passwd

  A /var/yp/passwd file will be generated from /var/yp/master.passwd by
  /var/yp/Makefile. When yppasswdd has finished modifying the master.passwd
  file, it will invoke /usr/libexec/yppwupdate, which is a script that
  will run /var/yp/Makefile to generate new maps and push them.

Note that there are copies if pw_util.c and pw_copy.c here. This is
deliberate: they are *not* identical to the originals. Very similar, yes,
but not identical. *sigh*
1995-01-31 09:12:52 +00:00

157 lines
4.2 KiB
C

/*
* yppasswdd
* Copyright 1994 Olaf Kirch, <okir@monad.swb.de>
*
* This program is covered by the GNU General Public License, version 2.
* It is provided in the hope that it is useful. However, the author
* disclaims ALL WARRANTIES, expressed or implied. See the GPL for details.
*/
#include <sys/types.h>
#include <sys/errno.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <ctype.h>
#include <time.h>
#include <pwd.h>
#include <syslog.h>
#include <stdio.h>
#include <string.h>
#include <rpc/rpc.h>
#include <rpc/pmap_clnt.h>
#include "yppasswd.h"
char *tempname;
extern char *passfile, *opassfile;
extern int *allow_chfn, *allow_chsh;
#define xprt_addr(xprt) (svc_getcaller(xprt)->sin_addr)
#define xprt_port(xprt) ntohs(svc_getcaller(xprt)->sin_port)
void reaper( int sig );
/*===============================================================*
* Argument validation. Avoid \n... (ouch).
* We can't use isprint, because people may use 8bit chars which
* aren't recognized as printable in the default locale.
*===============================================================*/
static int
validate_string(char *str)
{
while (*str && !iscntrl(*str)) str++;
return (*str == '\0');
}
static int
validate_args(struct xpasswd *pw)
{
return validate_string(pw->pw_passwd)
&& validate_string(pw->pw_shell)
&& validate_string(pw->pw_gecos);
}
/*===============================================================*
* The passwd update handler
*===============================================================*/
int *
yppasswdproc_pwupdate_1(yppasswd *yppw, struct svc_req *rqstp)
{
struct xpasswd *newpw; /* passwd struct passed by the client */
struct passwd *pw; /* passwd struct obtained from getpwent() */
int chsh = 0, chfn = 0;
static int res;
char logbuf[255];
int pfd, tfd, c;
newpw = &yppw->newpw;
res = 1;
sprintf( logbuf, "update %.12s (uid=%d) from host %s",
yppw->newpw.pw_name,
yppw->newpw.pw_uid,
inet_ntoa(xprt_addr(rqstp->rq_xprt)));
if (!validate_args(newpw)) {
syslog ( LOG_ALERT, "%s failed", logbuf );
syslog ( LOG_ALERT, "Invalid characters in argument. "
"Possible spoof attempt?" );
return &res;
}
pw_init();
pfd = pw_lock();
tfd = pw_tmp();
/* Check if the user exists
*/
if (!(pw = getpwnam(yppw->newpw.pw_name))) {
syslog ( LOG_WARNING, "%s failed", logbuf );
syslog ( LOG_WARNING, "User not in password file." );
return (&res);
}
/* Check the password.
*/
if (strcmp(crypt(yppw->oldpass, pw->pw_passwd), pw->pw_passwd)) {
syslog ( LOG_WARNING, "%s rejected", logbuf );
syslog ( LOG_WARNING, "Invalid password." );
sleep(1);
return(&res);
}
/* set the new passwd, shell, and full name
*/
pw->pw_passwd = newpw->pw_passwd;
if (allow_chsh) {
chsh = (strcmp(pw->pw_shell, newpw->pw_shell) != 0);
pw->pw_shell = newpw->pw_shell;
}
if (allow_chfn) {
chfn = (strcmp(pw->pw_gecos, newpw->pw_gecos) != 0);
pw->pw_gecos = newpw->pw_gecos;
}
pw->pw_change = 0;
pw_copy(pfd, tfd, pw);
if (strcmp(passfile, _PATH_MASTERPASSWD)) {
close(pfd);
close(tfd);
rename(tempname,passfile);
}
else
if (pw_mkdb()) {
syslog ( LOG_WARNING, "%s failed to rebuild password database", logbuf );
return(&res);
}
/* Fork off process to rebuild NIS passwd.* maps. If the fork
* fails, restore old passwd file and return an error.
*/
if ((c = fork()) < 0) {
syslog( LOG_ERR, "%s failed", logbuf );
syslog( LOG_ERR, "Couldn't fork map update process: %m" );
return (&res);
}
if (c == 0) {
execlp(MAP_UPDATE_PATH, MAP_UPDATE, NULL);
syslog( LOG_ERR, "Error: couldn't exec map update process: %m" );
exit(1);
}
syslog ( LOG_INFO, "%s successful. Password changed.", logbuf );
if (chsh || chfn) {
syslog ( LOG_INFO, "Shell %schanged (%s), GECOS %schanged (%s).",
chsh? "" : "un", newpw->pw_shell,
chfn? "" : "un", newpw->pw_gecos );
}
res = 0;
return (&res);
}