diff -u -r --new-file ypserv-1.3.8/ChangeLog ypserv-1.3.9/ChangeLog --- ypserv-1.3.8/ChangeLog Wed Oct 13 14:00:44 1999 +++ ypserv-1.3.9/ChangeLog Mon Oct 18 17:09:58 1999 @@ -1,3 +1,18 @@ +1999-10-18 Thorsten Kukuk + + * release version 1.3.9 + + * server.c (ypproc_xfr_2_svc): By default, don't allow new maps. + + * update.c: Complete rewrite to fix a lot of bugs. + + * yppush_xdr.c (xdr_ypresp_xfr): New function. + +1999-10-16 Thorsten Kukuk + + * ypMakefile.in (shadow.byname): Don't build this map if + MERGE_PASSWD=true + 1999-10-13 Thorsten Kukuk * release version 1.3.8 diff -u -r --new-file ypserv-1.3.8/HOWTO.SuSE ypserv-1.3.9/HOWTO.SuSE --- ypserv-1.3.8/HOWTO.SuSE Sat Jan 10 15:51:29 1998 +++ ypserv-1.3.9/HOWTO.SuSE Sat Oct 16 16:52:41 1999 @@ -14,6 +14,9 @@ "portmap". If your portmapper has the tcp-wrapper builtin, make sure /etc/hosts.allow and /etc/hosts.deny are setup correctly. +The rc.config variables for YP could be find in /etc/rc.config and +/etc/rc.config.d/ypserv.rc.config + Installing a client machine: ============================ diff -u -r --new-file ypserv-1.3.8/NEWS ypserv-1.3.9/NEWS --- ypserv-1.3.8/NEWS Sun Oct 10 22:17:36 1999 +++ ypserv-1.3.9/NEWS Mon Oct 18 17:30:27 1999 @@ -5,6 +5,10 @@ Please send bug reports, questions and suggestions to . +Version 1.3.9 +* rpc.yppasswdd: Fix some security problems +* ypserv: Don't fetch new maps by default + Version 1.3.8 * yppush fix for ndbm support * yppush fix for Irix 6.5.x NIS slave servers diff -u -r --new-file ypserv-1.3.8/server.c ypserv-1.3.9/server.c --- ypserv-1.3.8/server.c Sun Aug 22 12:46:53 1999 +++ ypserv-1.3.9/server.c Mon Oct 18 17:16:59 1999 @@ -756,6 +756,9 @@ { if (debug_flag) yp_msg ("\t-> Ignored (not a valid source host)\n"); + else + yp_msg ("ypproc_xfr: refuse to transfer map from %s", + inet_ntoa (rqhost->sin_addr)); result.xfrstat = YPXFR_REFUSED; return &result; @@ -765,7 +768,9 @@ { if (debug_flag) yp_msg ("\t-> Ignored (not a valid domain)\n"); - + else + yp_msg ("ypproc_xfr: refuse to transfer map from %s, no valid domain", + inet_ntoa (rqhost->sin_addr)); result.xfrstat = YPXFR_NODOM; return &result; } @@ -774,7 +779,9 @@ { if (debug_flag) yp_msg ("\t-> Ignored (map contains \"/\"!)\n"); - + else + yp_msg ("ypproc_xfr: refuse to transfer map from %s, no valid mapname", + inet_ntoa (rqhost->sin_addr)); result.xfrstat = YPXFR_REFUSED; return &result; } @@ -785,6 +792,9 @@ { if (debug_flag) yp_msg ("\t-> Ignored (no reserved port!)\n"); + else + yp_msg ("ypproc_xfr: refuse to transfer %s from %s, no valid port", + xfr->map_parms.map, inet_ntoa (rqhost->sin_addr)); result.xfrstat = YPXFR_REFUSED; return &result; @@ -792,7 +802,7 @@ } /* If we have the map, check, if the master name is the same as in - the ypreq_xfr struct. If we doesn't have the map, trust the host. */ + the ypreq_xfr struct. If we doesn't have the map, refuse. */ dbp = ypdb_open(xfr->map_parms.domain, xfr->map_parms.map); if (dbp != NULL) { @@ -810,6 +820,9 @@ if (debug_flag) yp_msg ("\t->Ignored (%s is not the master!)\n", xfr->map_parms.peer); + else + yp_msg ("ypproc_xfr: refuse to transfer %s from %s, not master", + xfr->map_parms.map, inet_ntoa (rqhost->sin_addr)); result.xfrstat = YPXFR_NODOM; return &result; @@ -827,14 +840,18 @@ } ypdb_close(dbp); } - /* If you wish to refuse the transfer of new maps, change the next - #if 0 statement to #if 1 */ -#if 0 + /* If you wish to allow the transfer of new maps, change the next + #if 1 statement to #if 0 */ +#if 1 else { /* We doesn't have the map, refuse the transfer */ if (debug_flag) yp_msg ("\t->Ignored (I don't have this map)\n"); + else + yp_msg ("ypproc_xfr: refuse to transfer %s from %s, map doesn't exist", + xfr->map_parms.map, inet_ntoa (rqhost->sin_addr)); + result.xfrstat = YPXFR_REFUSED; return &result; } diff -u -r --new-file ypserv-1.3.8/update.c ypserv-1.3.9/update.c --- ypserv-1.3.8/update.c Sun Oct 10 22:16:24 1999 +++ ypserv-1.3.9/update.c Mon Oct 18 16:01:55 1999 @@ -1,24 +1,21 @@ -/* update.c Common update routines for normal and shadow passwd file +/* Copyright (c) 1999 Thorsten Kukuk + This file is part of the NYS YP Server. + Author: Thorsten Kukuk - Copyright 1997, 1998, 1999 Thorsten Kukuk, - Complete rewritten for better shadow support. - - Copyright 1994, 1995 Olaf Kirch, - - This program are free software; you can redistribute it and/or + The NYS YP Server is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - This program is distributed in the hope that it will be useful, + The NYS YP Server is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public - License along with this program; see the file COPYING. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ + License along with the NYS YP Server; see the file COPYING. If + not, write to the Free Software Foundation, Inc., 675 Mass Ave, + Cambridge, MA 02139, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -27,18 +24,11 @@ #include "system.h" #include -#include -#include -#include +#include #include -#include #include -#include #include -#include -#include #include -#include #include #include #include @@ -57,20 +47,21 @@ #endif #ifndef CHECKROOT -/* Set to 1 if you want to chack against the root password. */ -#define CHECKROOT 0 +/* Set to 0 if you don't want to check against the root password + of the NIS master server. */ +#define CHECKROOT 1 #endif #ifndef _PATH_PASSWD -#define _PATH_PASSWD "/etc/passwd" +#define _PATH_PASSWD "/etc/passwd" #endif #ifdef HAVE_GETSPNAM #ifndef _PATH_SHADOW -#define _PATH_SHADOW "/etc/shadow" +#define _PATH_SHADOW "/etc/shadow" #endif #endif #ifndef _PATH_SHELLS -#define _PATH_SHELLS "/etc/shells" +#define _PATH_SHELLS "/etc/shells" #endif /* How often to retry locking the passwd file... */ @@ -85,36 +76,34 @@ char *path_shadow_old = NULL; #endif +/* Will be set by the main function */ char *external_update_program = NULL; -#ifndef svc_getcaller -/* This is a cheat. */ -#define svc_getcaller(x) ((struct sockaddr_in *) (x)->xp_rtaddr.buf) -#endif -#define xprt_addr(xprt) (svc_getcaller(xprt)->sin_addr) -#define xprt_port(xprt) ntohs(svc_getcaller(xprt)->sin_port) -void reaper (int sig); - static int external_update_env (yppasswd *yppw); static int external_update_pipe (yppasswd *yppw); +static int update_files (yppasswd *yppw, char *logbuf, int *shadow_changed, + int *passwd_changed, int *chfn, int *chsh); -/*===============================================================* - * 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. - *===============================================================*/ +/* 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 *what, char *str) { while (*str && *str != ':' && (unsigned char)*str >= 32) - str++; + ++str + ; if (*str == '\0') return 1; + yp_msg ("Invalid characters in %s argument: \"%s\"", what, str); + return 0; } -static int +/* Check that nobody tries to change special NIS entries beginning + with +/- and that all chracters are allowed. */ +static inline int validate_args (struct xpasswd *pw) { if (pw->pw_name[0] == '-' || pw->pw_name[0] == '+') @@ -131,7 +120,7 @@ static int shell_ok (char *shell) { - char buffer[256]; + char buffer[1024]; FILE *fp; if ((fp = fopen (_PATH_SHELLS, "r")) == NULL) @@ -139,20 +128,36 @@ yp_msg ("can't open %s", _PATH_SHELLS); return 0; } - while (fgets (buffer, 255, fp) != NULL) + while (fgets (buffer, sizeof (buffer), fp) != NULL) { - buffer[255] = '\0'; + buffer[sizeof (buffer) - 1] = '\0'; if (!strncmp (buffer, shell, strcspn (buffer, " \t\n"))) - { - fclose (fp); - return 1; - } + { + fclose (fp); + return 1; + } } fclose (fp); return 0; } +/* Check if the password the user supplied matches the old one */ +static int +password_ok (char *plain, char *crypted, char *root) +{ + if (crypted[0] == '\0') + return 1; + if (strcmp (crypt (plain, crypted), crypted) == 0) + return 1; +#if CHECKROOT + if (strcmp (crypt (plain, root), root) == 0) + return 1; +#endif + + return 0; +} + #ifdef HAVE_GETSPNAM static inline int is_allowed_to_change (const struct spwd *sp) @@ -176,83 +181,39 @@ } #endif -#if CHECKROOT -static int -password_ok (char *plain, char *crypted, char *root) -{ - if (crypted[0] == '\0') - return 1; - if (strcmp (crypt (plain, crypted), crypted) == 0) - return 1; - if (strcmp (crypt (plain, root), root) == 0) - return 1; +/********************************************************************* + * The Update Handler * + *********************************************************************/ - return 0; -} -#endif - -/*===============================================================* - * The /etc/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 fgetpwent() */ -#ifdef HAVE_GETSPNAM - struct spwd *spw; - int have_shadow = 0, shadow_changed = 0; - FILE *oldsf, *newsf; -#endif - int retries, gotit, c; - int chsh = 0, chfn = 0; - FILE *oldpf, *newpf; - static int res; + int shadow_changed = 0, passwd_changed = 0, chsh = 0, chfn = 0; + int retries; + static int res; /* I hate static variables */ char *logbuf; - struct stat passwd_stat, shadow_stat; -#if CHECKROOT - char *rootpass; - - res = 1; - if ((pw = getpwnam ("root")) != NULL) - { -#ifdef HAVE_GETSPNAM - if (strcmp (pw->pw_passwd, "x") == 0) - { - if ((spw = getspnam ("root")) != NULL) - { - rootpass = alloca (strlen (spw->sp_pwdp) + 1); - strcpy (rootpass, spw->sp_pwdp); - } - else - rootpass = "x"; - } - else -#endif /* HAVE_GETSPNAM */ - { - rootpass = alloca (strlen (pw->pw_passwd) + 1); - strcpy (rootpass, pw->pw_passwd); - } - } - else - rootpass = "x"; -#else /* !CHECKROOT */ - res = 1; -#endif + struct sockaddr_in *rqhost = svc_getcaller (rqstp->rq_xprt); + /* Be careful here with the debug option. You can see the old + and new password in clear text !! */ if (debug_flag) { - struct sockaddr_in *rqhost = svc_getcaller (rqstp->rq_xprt); yp_msg ("yppasswdproc_pwupdate(\"%s\") [From: %s:%d]\n", - yppw->newpw.pw_name, - inet_ntoa (rqhost->sin_addr), - ntohs (rqhost->sin_port)); + yppw->newpw.pw_name, + inet_ntoa (rqhost->sin_addr), + ntohs (rqhost->sin_port)); + yp_msg ("\toldpass..: %s\n", yppw->oldpass); + yp_msg ("\tpw_name..: %s\n", yppw->newpw.pw_name); + yp_msg ("\tpw_passwd: %s\n", yppw->newpw.pw_passwd); + yp_msg ("\tpw_gecos.: %s\n", yppw->newpw.pw_gecos); + yp_msg ("\tpw_dir...: %s\n", yppw->newpw.pw_dir); + yp_msg ("\tpw_shell.: %s\n", yppw->newpw.pw_shell); } - newpw = &yppw->newpw; + res = 1; /* res = 1 means no success */ logbuf = alloca (60 + strlen (yppw->newpw.pw_name) + - strlen (inet_ntoa (xprt_addr (rqstp->rq_xprt)))); + strlen (inet_ntoa (rqhost->sin_addr))); if (logbuf == NULL) { yp_msg ("rpc.yppasswdd: out of memory\n"); @@ -260,35 +221,67 @@ } sprintf (logbuf, "update %.12s (uid=%d) from host %s", - yppw->newpw.pw_name, yppw->newpw.pw_uid, - inet_ntoa (xprt_addr (rqstp->rq_xprt))); + yppw->newpw.pw_name, yppw->newpw.pw_uid, + inet_ntoa (rqhost->sin_addr)); - if (!validate_args (newpw)) + /* Check if somebody tries to make trouble with not allowed characters */ + if (!validate_args (&yppw->newpw)) { yp_msg ("%s failed", logbuf); return &res; } - res = 0; + /* ATTENTION: The external program needs to do the password checking! */ if (external_update_program) { - if (x_flag) + struct passwd *pw; + + pw = getpwnam (yppw->newpw.pw_name); + /* Do we need to update the GECOS information and are we allowed + to do it ? */ + chfn = (strcmp (pw->pw_gecos, yppw->newpw.pw_gecos) != 0); + if (chfn && !allow_chfn) { - res = external_update_pipe (yppw); + yp_msg ("%s rejected", logbuf); + yp_msg ("chfn not permitted"); return &res; } - else + + /* Do we need to update the shell adn are we allowed to do it ? */ + chsh = (strcmp (pw->pw_shell, yppw->newpw.pw_shell) != 0); + if (chsh) { - res = external_update_env (yppw); - if (res >= 2) - return &res; + if (!allow_chsh) + { + yp_msg ("%s rejected", logbuf); + yp_msg ("chsh not permitted"); + return &res; + } + if (!shell_ok (yppw->newpw.pw_shell)) + { + yp_msg ("%s rejected", logbuf); + yp_msg ("invalid shell: %s", yppw->newpw.pw_shell); + return &res; + } } + + if (x_flag) + { + res = external_update_pipe (yppw); + return &res; + } + else + { + res = external_update_env (yppw); + if (res >= 2) + return &res; + } + passwd_changed = 1; /* We don't know exactly what was changed. */ + shadow_changed = 1; /* So build everything new. */ } else { - /* Lock the passwd file. We retry several times. Maybe it would - be better to just return an error condition and have the client - reattempt instead? This procedure is already slow enough... */ + /* Lock the passwd file. We retry several times. */ retries = 0; while (lckpwdf () && retries < MAX_RETRIES) { @@ -300,313 +293,333 @@ { yp_msg ("%s failed", logbuf); yp_msg ("password file locked"); - goto error2; + return &res; } - /* Open the passwd file for reading. We can't use getpwent and - friends here, because they go through the YP maps, too. */ - if ((oldpf = fopen (path_passwd, "r")) == NULL) + res = update_files (yppw, logbuf, &shadow_changed, &passwd_changed, + &chfn, &chsh); + + ulckpwdf (); + } + + /* Fork off process to rebuild NIS passwd.* maps. */ + if (res == 0) + /* The child (-E program) may exit(1), which means success, but + don't run pwupdate. Bad, we tell the user that there was an + error. Needs to be fixed later. */ + { + int c; + + if ((c = fork ()) < 0) + { + /* Do NOT restore old password file. Someone else may already + * be using the new one. */ + yp_msg ("%s failed", logbuf); + yp_msg ("Couldn't fork map update process: %s", strerror (errno)); + return &res; + } + + if (c == 0) /* We are the child */ + { + if (shadow_changed) + execlp (MAP_UPDATE_PATH, MAP_UPDATE, "shadow", NULL); + else + execlp (MAP_UPDATE_PATH, MAP_UPDATE, "passwd", NULL); + yp_msg ("Error: couldn't exec map update process: %s", + strerror (errno)); + exit (1); + } + + yp_msg ("%s successful.", logbuf); + if (chsh || chfn) { - yp_msg ("%s failed", logbuf); - yp_msg ("Can't open %s: %m", path_passwd); - goto error2; + yp_msg ("Shell %schanged (%s), GECOS %schanged (%s).", + chsh ? "" : "un", yppw->newpw.pw_shell, + chfn ? "" : "un", yppw->newpw.pw_gecos); } + } + + return &res; +} - if (fstat (fileno (oldpf), &passwd_stat) < 0) +/* + return code: + 0: success + 1: error +*/ +static int +update_files (yppasswd *yppw, char *logbuf, int *shadow_changed, + int *passwd_changed, int *chfn, int *chsh) +{ + struct passwd *pw; + struct spwd *spw = NULL; + int gotit = 0; + FILE *oldpf = NULL, *newpf = NULL, *oldsf = NULL, *newsf = NULL; + struct stat passwd_stat, shadow_stat; + char *rootpass = "x"; + +#if CHECKROOT + if ((pw = getpwnam ("root")) != NULL) + { + if (strcmp (pw->pw_passwd, "x") == 0) + { + struct spwd *spw; + + if ((spw = getspnam ("root")) != NULL) + { + rootpass = alloca (strlen (spw->sp_pwdp) + 1); + strcpy (rootpass, spw->sp_pwdp); + } + } + else + { + rootpass = alloca (strlen (pw->pw_passwd) + 1); + strcpy (rootpass, pw->pw_passwd); + } + } +#endif + + /* Open the passwd file for reading. We can't use getpwent and + friends here. */ + if ((oldpf = fopen (path_passwd, "r")) == NULL) + { + yp_msg ("%s failed", logbuf); + yp_msg ("Can't open %s: %m", path_passwd); + return 1; + } + + if (fstat (fileno (oldpf), &passwd_stat) < 0) + { + yp_msg ("%s failed", logbuf); + yp_msg ("Can't stat %s: %m", path_passwd); + fclose (oldpf); + return 1; + } + + /* Open a temp passwd file */ + if ((newpf = fopen (path_passwd_tmp, "w+")) == NULL) + { + yp_msg ("%s failed", logbuf); + yp_msg ("Can't open %s: %m", path_passwd_tmp); + fclose (oldpf); + return 1; + } + chmod (path_passwd_tmp, passwd_stat.st_mode); + chown (path_passwd_tmp, passwd_stat.st_uid, passwd_stat.st_gid); + + /* Open the shadow file for reading. */ + if ((oldsf = fopen (path_shadow, "r")) != NULL) + { + if (fstat (fileno (oldsf), &shadow_stat) < 0) { yp_msg ("%s failed", logbuf); - yp_msg ("Can't stat %s: %m", path_passwd); + yp_msg ("Can't stat %s: %m", path_shadow); fclose (oldpf); - oldpf = 0; - goto error2; + fclose (oldsf); + return 1; } - /* Open a temp passwd file */ - if ((newpf = fopen (path_passwd_tmp, "w+")) == NULL) + if ((newsf = fopen (path_shadow_tmp, "w+")) == NULL) { yp_msg ("%s failed", logbuf); - yp_msg ("Can't open %s: %m", path_passwd_tmp); + yp_msg ("Can't open %s.tmp: %m", path_passwd); + fclose (oldsf); + fclose (newpf); fclose (oldpf); - oldpf = 0; - goto error2; + return 1; } - chmod (path_passwd_tmp, passwd_stat.st_mode); - chown (path_passwd_tmp, passwd_stat.st_uid, passwd_stat.st_gid); + chmod (path_shadow_tmp, shadow_stat.st_mode); + chown (path_shadow_tmp, shadow_stat.st_uid, shadow_stat.st_gid); + } -#ifdef HAVE_GETSPNAM - /* Open the shadow file for reading. */ - if ((oldsf = fopen (path_shadow, "r")) != NULL) + /* Loop over all passwd entries */ + while ((pw = fgetpwent (oldpf)) != NULL) + { + /* check if this is the uid we want to change. A few + sanity checks added for consistency. */ + if ((uid_t)yppw->newpw.pw_uid == pw->pw_uid && + (uid_t)yppw->newpw.pw_gid == pw->pw_gid && + !strcmp (yppw->newpw.pw_name, pw->pw_name) && !gotit) { - if (fstat (fileno (oldsf), &shadow_stat) < 0) + ++gotit; + + /* Check the password. At first check for a shadow password. */ + if (oldsf != NULL && + pw->pw_passwd[0] == 'x' && pw->pw_passwd[1] == '\0') { - yp_msg ("%s failed", logbuf); - yp_msg ("Can't stat %s: %m", path_shadow); - fclose (oldpf); - fclose (oldsf); - oldpf = oldsf = 0; - goto error2; + /* Search for the shadow entry of this user */ + while ((spw = fgetspent (oldsf)) != NULL) + { + if (strcmp (yppw->newpw.pw_name, spw->sp_namp) == 0) + { + if (!password_ok (yppw->oldpass, spw->sp_pwdp, rootpass)) + { + yp_msg ("%s rejected", logbuf); + yp_msg ("Invalid password."); + goto error; + } + /* Password is ok, leave while loop */ + break; + } + else if (putspent (spw, newsf) < 0) + { + yp_msg ("%s failed", logbuf); + yp_msg ("Error while writing new shadow file: %m"); + goto error; + } + } } - /* We have a shadow file */ - have_shadow = 1; - shadow_changed = 0; - - if ((newsf = fopen (path_shadow_tmp, "w+")) == NULL) + /* We don't have a shadow password file or we don't find the + user in it. */ + if (spw == NULL && + !password_ok (yppw->oldpass, pw->pw_passwd, rootpass)) { - yp_msg ("%s failed", logbuf); - yp_msg ("Can't open %s.tmp: %m", path_passwd); - fclose (oldsf); - fclose (newpf); - fclose (oldpf); - oldsf=newpf=oldpf=0; - goto error2; + yp_msg ("%s rejected", logbuf); + yp_msg ("Invalid password."); + goto error; } - chmod (path_shadow_tmp, shadow_stat.st_mode); - chown (path_shadow_tmp, shadow_stat.st_uid, shadow_stat.st_gid); - } - else - { - have_shadow = 0; - shadow_changed = 0; - newsf = NULL; - } -#endif - gotit = 0; - - /* Loop over all passwd entries */ - while ((pw = fgetpwent (oldpf)) != NULL) - { - /* check if this is the uid we want to change. A few - sanity checks added for consistency. */ - if ((uid_t)newpw->pw_uid == pw->pw_uid && - (uid_t)newpw->pw_gid == pw->pw_gid && - !strcmp (newpw->pw_name, pw->pw_name) && !gotit) + /*If the new password is not valid, + ignore it. User wishes to change GECOS or SHELL in this case. */ + if (yppw->newpw.pw_passwd != NULL && + !((yppw->newpw.pw_passwd[0] == 'x' || + yppw->newpw.pw_passwd[0] == '*') && + yppw->newpw.pw_passwd[1] == '\0') && + yppw->newpw.pw_passwd[0] != '\0') { - /* Check the password. */ - if (newpw->pw_passwd[0] != 'x' && newpw->pw_passwd[0] != '*') + if (spw) { -#ifdef HAVE_GETSPNAM - if (have_shadow && pw->pw_passwd[0] == 'x' && - pw->pw_passwd[1] == '\0') + /* test if password is expired */ + if (spw->sp_pwdp[0] != '!') { - while ((spw = fgetspent (oldsf)) != NULL) + if (is_allowed_to_change (spw)) { - if (strcmp (newpw->pw_name, spw->sp_namp) == 0) - { -#if CHECKROOT - if (!password_ok(yppw->oldpass, spw->sp_pwdp, - rootpass)) -#else - if (spw->sp_namp[0] != '\0' && - strcmp (crypt (yppw->oldpass,spw->sp_pwdp), - spw->sp_pwdp)) -#endif - { - yp_msg ("%s rejected",logbuf); - yp_msg ("Invalid password."); - goto error; - } - /* test if password is expired */ - if (spw->sp_pwdp[0] != '!') - { - if (is_allowed_to_change (spw)) - { - time_t now; - - time(&now); - /* set the new passwd */ - spw->sp_pwdp = newpw->pw_passwd; - spw->sp_lstchg = (long int)now / - (24L*3600L); - shadow_changed = 1; - } - else - { - yp_msg ("%s rejected", logbuf); - yp_msg ("now < minimum age for `%s'", - spw->sp_namp); - goto error; - } - } - else - { - yp_msg ("%s rejected", logbuf); - yp_msg ("password for `%s' is locked", - spw->sp_namp); - goto error; - } - } - if (putspent (spw, newsf) < 0) - { - yp_msg ("%s failed", logbuf); - yp_msg ("Error while writing new shadow file: %m"); - shadow_changed = 0; - goto error; - } + time_t now; + + time(&now); + /* set the new passwd */ + spw->sp_pwdp = yppw->newpw.pw_passwd; + spw->sp_lstchg = (long int)now / (24L*3600L); + *shadow_changed = 1; } - fclose (newsf); - fclose (oldsf); - newsf=oldsf=0; - if (shadow_changed) + else { - unlink (path_shadow_old); - link (path_shadow, path_shadow_old); - rename (path_shadow_tmp, path_shadow); + yp_msg ("%s rejected", logbuf); + yp_msg ("now < minimum age for `%s'", + spw->sp_namp); + goto error; } - else - unlink (path_shadow_tmp); } - else -#endif + if (putspent (spw, newsf) < 0) { - /* This user doesn't have shadow files */ -#if CHECKROOT - if (!password_ok(yppw->oldpass, pw->pw_passwd, - rootpass)) -#else - if (pw->pw_passwd[0] != '\0' && - strcmp (crypt (yppw->oldpass, pw->pw_passwd), - pw->pw_passwd)) -#endif - { - yp_msg ("%s rejected", logbuf); - yp_msg ("Invalid password."); - break; - } - /* set the new passwd */ - pw->pw_passwd = newpw->pw_passwd; + yp_msg ("%s failed", logbuf); + yp_msg ("Error while writing new shadow file: %m"); + *shadow_changed = 0; + goto error; } + + /* Copy all missing entries */ + while ((spw = fgetspent (oldsf)) != NULL) + if (putspent (spw, newsf) < 0) + { + yp_msg ("%s failed", logbuf); + yp_msg ("Error while writing new shadow file: %m"); + *shadow_changed = 0; + goto error; + } } - /* set the new shell, and full name */ - chsh = (strcmp (pw->pw_shell, newpw->pw_shell) != 0); - if (chsh) + else /* No shadow entry */ { - if (!allow_chsh) - { - yp_msg ("%s rejected", logbuf); - yp_msg ("chsh not permitted"); - break; - } - if (!shell_ok (newpw->pw_shell)) - { - yp_msg ("%s rejected", logbuf); - yp_msg ("invalid shell: %s", newpw->pw_shell); - break; - } - pw->pw_shell = newpw->pw_shell; + /* set the new passwd */ + pw->pw_passwd = yppw->newpw.pw_passwd; + *passwd_changed = 1; } - chfn = (strcmp (pw->pw_gecos, newpw->pw_gecos) != 0); - if (chfn) + } /* end changing password */ + else if (spw) + spw = NULL; + + /* Handle chsh and chfn here*/ + + /* Do we need to update the GECOS information and are we allowed + to do it ? */ + if (strcmp (pw->pw_gecos, yppw->newpw.pw_gecos) != 0) + { + if (!allow_chfn) { - if (!allow_chfn) - { - yp_msg ("%s rejected", logbuf); - yp_msg ("chfn not permitted"); - break; - } - pw->pw_gecos = newpw->pw_gecos; + yp_msg ("%s rejected", logbuf); + yp_msg ("chfn not permitted"); + *passwd_changed = 0; + goto error; } - ++gotit; + pw->pw_gecos = yppw->newpw.pw_gecos; + *chfn = 1; + *passwd_changed = 1; } - /* write the passwd entry to tmp file */ - if (putpwent (pw, newpf) < 0) + /* Do we need to update the shell adn are we allowed to do it ? */ + if (strcmp (pw->pw_shell, yppw->newpw.pw_shell) != 0) { - yp_msg ("%s failed", logbuf); - yp_msg ("Error while writing new password file: %m"); - break; + if (!allow_chsh) + { + yp_msg ("%s rejected", logbuf); + yp_msg ("chsh not permitted"); + *passwd_changed = 0; + goto error; + } + if (!shell_ok (yppw->newpw.pw_shell)) + { + yp_msg ("%s rejected", logbuf); + yp_msg ("invalid shell: %s", yppw->newpw.pw_shell); + *passwd_changed = 0; + goto error; + } + pw->pw_shell = yppw->newpw.pw_shell; + *chsh = 1; + *passwd_changed = 1; } - /* fflush (newpf); */ - } - error: - if(newpf) fclose (newpf); - if(oldpf) fclose (oldpf); -#ifdef HAVE_GETSPNAM - if (have_shadow && !shadow_changed) - { - if(newsf) fclose (newsf); - if(oldsf) fclose (oldsf); - } -#endif - - /* Check if we dropped out of the loop because of an error. - * If so, return an error to the client. - */ - if (pw != NULL) - { - unlink (path_passwd_tmp); -#ifdef HAVE_GETSPNAM - if (have_shadow) - unlink (path_shadow_tmp); -#endif - error2: - ulckpwdf (); - return (&res); - } - - /* Check whether we actually changed anything - */ - if (!gotit) + } /* Found the entry */ + /* write the passwd entry to tmp file */ + if (putpwent (pw, newpf) < 0) { yp_msg ("%s failed", logbuf); - yp_msg ("User not in password file."); - unlink (path_passwd_tmp); -#ifdef HAVE_GETSPNAM - if (have_shadow) - unlink (path_shadow_tmp); -#endif /* HAVE_GETSPNAM */ - ulckpwdf (); - return &res; - } - - unlink (path_passwd_old); - link (path_passwd, path_passwd_old); - rename (path_passwd_tmp, path_passwd); /* atomic */ -#ifdef HAVE_GETSPNAM - if (have_shadow && !shadow_changed) - unlink (path_shadow_tmp); -#endif /* HAVE_GETSPNAM */ - ulckpwdf (); + yp_msg ("Error while writing new password file: %m"); + *passwd_changed = 0; + break; + } + /* fflush (newpf); */ + } /* while */ + error: + if (newpf) fclose (newpf); + if (oldpf) fclose (oldpf); + if (newsf) fclose (newsf); + if (oldsf) fclose (oldsf); + /* If one of them is non-NULL, an error ocured. */ + if (pw || spw) + { + unlink (path_passwd_tmp); + unlink (path_shadow_tmp); + return 1; + } + if (*shadow_changed) + { + unlink (path_shadow_old); + link (path_shadow, path_shadow_old); + rename (path_shadow_tmp, path_shadow); } + else + unlink (path_shadow_tmp); - /* Fork off process to rebuild NIS passwd.* maps. */ - if (!res) - /* The child (-E program) may exit(1), which means success, but - don't run pwupdate */ + if (*passwd_changed) { - if ((c = fork ()) < 0) - { - /* Do NOT restore old password file. Someone else may already - * be using the new one. */ - yp_msg ("%s failed", logbuf); - yp_msg ("Couldn't fork map update process: %s", strerror (errno)); - return &res; - } - if (c == 0) - { -#ifdef HAVE_GETSPNAM - if (shadow_changed) - execlp (MAP_UPDATE_PATH, MAP_UPDATE, "shadow", NULL); - else -#endif /* HAVE_GETSPNAM */ - execlp (MAP_UPDATE_PATH, MAP_UPDATE, "passwd", NULL); - yp_msg ("Error: couldn't exec map update process: %s", - strerror (errno)); - exit (1); - } - - yp_msg ("%s successful. Password changed.", logbuf); - if (chsh || chfn) - { - yp_msg ("Shell %schanged (%s), GECOS %schanged (%s).", - chsh ? "" : "un", newpw->pw_shell, - chfn ? "" : "un", newpw->pw_gecos); - } - res = 0; + unlink (path_passwd_old); + link (path_passwd, path_passwd_old); + rename (path_passwd_tmp, path_passwd); } + else + unlink (path_passwd_tmp); - return &res; + return !(*shadow_changed || *passwd_changed); } static int @@ -620,9 +633,9 @@ itmp = waitpid (itmp, &res, 0); if (itmp < 0) - res = 2; + res = 2; else - res = WEXITSTATUS(res); + res = WEXITSTATUS(res); } else { /* Child - run external update program */ @@ -777,7 +790,7 @@ if (toparentpipe[1] != 1) { - close(1); + close(1); dup2(toparentpipe[1], 1); } @@ -818,7 +831,7 @@ if (shell) { if (password) - strncat (parentmsg, " ", sizeof parentmsg); + strncat (parentmsg, " ", sizeof parentmsg); strncat (parentmsg, "s:", sizeof parentmsg); strncat (parentmsg, shell, sizeof parentmsg); @@ -827,7 +840,7 @@ if (gcos) { if (password || shell) - strncat(parentmsg, " ", sizeof parentmsg); + strncat(parentmsg, " ", sizeof parentmsg); strncat(parentmsg, "g:", sizeof parentmsg); strncat(parentmsg, gcos, sizeof parentmsg); diff -u -r --new-file ypserv-1.3.8/version.h ypserv-1.3.9/version.h --- ypserv-1.3.8/version.h Sat Oct 9 10:39:45 1999 +++ ypserv-1.3.9/version.h Mon Oct 18 17:21:23 1999 @@ -1,4 +1,4 @@ #ifndef __VERSION_H__ #define __VERSION_H__ -static char version[] = "1.3.8"; +static char version[] = "1.3.9"; #endif diff -u -r --new-file ypserv-1.3.8/ypMakefile.in ypserv-1.3.9/ypMakefile.in --- ypserv-1.3.8/ypMakefile.in Wed Oct 13 18:47:33 1999 +++ ypserv-1.3.9/ypMakefile.in Sat Oct 16 16:55:40 1999 @@ -274,7 +274,13 @@ print $$3"\t"$$0 }' | $(DBLOAD) -i $(PASSWD) \ -o $(YPMAPDIR)/$@ - $@ -@$(NOPUSH) || $(YPPUSH) -d $(DOMAIN) $@ + +# Don't build a shadow map ! +shadow.byname: + @echo "Updating $@... Ignored -> merged with passwd" + else + passwd.byname: $(PASSWD) $(YPDIR)/Makefile @echo "Updating $@..." @$(UMASK); \ @@ -290,7 +296,6 @@ print $$3"\t"$$0 }' $(PASSWD) | $(DBLOAD) -i $(PASSWD) \ -o $(YPMAPDIR)/$@ - $@ -@$(NOPUSH) || $(YPPUSH) -d $(DOMAIN) $@ -endif shadow.byname: $(SHADOW) $(YPDIR)/Makefile @echo "Updating $@..." @@ -298,6 +303,7 @@ $(AWK) -F: '!/^[-+#]/ { if ($$1 != "" ) print $$1"\t"$$0 }' \ $(SHADOW) | $(DBLOAD) -s -i $(SHADOW) -o $(YPMAPDIR)/$@ - $@ -@$(NOPUSH) || $(YPPUSH) -d $(DOMAIN) $@ +endif passwd.adjunct.byname: $(ADJUNCT) $(YPDIR)/Makefile @echo "Updating $@..." @@ -310,6 +316,7 @@ ifeq (x$(MERGE_GROUP),xtrue) group.byname: $(GROUP) $(GSHADOW) $(YPDIR)/Makefile @echo "Updating $@..." + @$(UMASK); \ $(MERGER) -g $(GROUP) $(GSHADOW) | \ $(AWK) -F: '!/^[-+#]/ { if ($$1 != "" && $$3 >= $(MINGID) ) \ print $$1"\t"$$0 }' | $(DBLOAD) -i $(GROUP) -o $(YPMAPDIR)/$@ - $@ @@ -317,6 +324,7 @@ group.bygid: $(GROUP) $(GSHADOW) $(YPDIR)/Makefile @echo "Updating $@..." + @$(UMASK); \ $(MERGER) -g $(GROUP) $(GSHADOW) | \ $(AWK) -F: '!/^[-+#]/ { if ($$1 != "" && $$3 >= $(MINGID) ) \ print $$3"\t"$$0 }' | $(DBLOAD) -i $(GROUP) -o $(YPMAPDIR)/$@ - $@ @@ -325,6 +333,7 @@ group.byname: $(GROUP) $(YPDIR)/Makefile @echo "Updating $@..." + @$(UMASK); \ @$(AWK) -F: '!/^[-+#]/ { if ($$1 != "" && $$3 >= $(MINGID) ) \ print $$1"\t"$$0 }' $(GROUP) \ | $(DBLOAD) -i $(GROUP) -o $(YPMAPDIR)/$@ - $@ @@ -332,6 +341,7 @@ group.bygid: $(GROUP) $(YPDIR)/Makefile @echo "Updating $@..." + @$(UMASK); \ @$(AWK) -F: '!/^[-+#]/ { if ($$1 != "" && $$3 >= $(MINGID) ) \ print $$3"\t"$$0 }' $(GROUP) \ | $(DBLOAD) -i $(GROUP) -o $(YPMAPDIR)/$@ - $@ diff -u -r --new-file ypserv-1.3.8/yppasswdd.c ypserv-1.3.9/yppasswdd.c --- ypserv-1.3.8/yppasswdd.c Tue Jun 1 21:30:28 1999 +++ ypserv-1.3.9/yppasswdd.c Sat Oct 16 18:17:30 1999 @@ -106,7 +106,7 @@ return; } memset ((char *) &argument, 0, sizeof (argument)); - if (!svc_getargs (transp, xdr_argument, (caddr_t) & argument)) + if (!svc_getargs (transp, xdr_argument, (caddr_t) &argument)) { svcerr_decode (transp); return; diff -u -r --new-file ypserv-1.3.8/yppush_xdr.c ypserv-1.3.9/yppush_xdr.c --- ypserv-1.3.8/yppush_xdr.c Sat Aug 21 09:22:20 1999 +++ ypserv-1.3.9/yppush_xdr.c Mon Oct 18 16:42:23 1999 @@ -39,14 +39,14 @@ #include "yp_msg.h" #include "yppush.h" -/* -** If we use our own version under SunOS 4.x, we will get -** problems with gethostname, etc. -** But under Linux, we need this since the xdr_* stuff under -** libc 4.x, 5.x is really broken. GNU libc 6 does not have -** the xdr_* functions -*/ -#if !defined(__sun__) && !defined(sun) +static bool_t +xdr_ypxfrstat(XDR *xdrs, ypxfrstat *objp) +{ + if (!xdr_enum(xdrs, (enum_t *)objp)) + return FALSE; + + return TRUE; +} bool_t xdr_domainname(XDR *xdrs, domainname *objp) { @@ -95,6 +95,18 @@ return (TRUE); } +bool_t +xdr_ypresp_xfr(XDR *xdrs, ypresp_xfr *objp) +{ + if (!xdr_u_int(xdrs, &objp->transid)) + return FALSE; + + if (!xdr_ypxfrstat(xdrs, &objp->xfrstat)) + return FALSE; + + return TRUE; +} + bool_t xdr_yppush_status(XDR *xdrs, yppush_status *objp) { if (!xdr_enum(xdrs, (enum_t *)objp)) @@ -110,5 +122,3 @@ return (FALSE); return (TRUE); } - -#endif