1447 lines
35 KiB
C
1447 lines
35 KiB
C
/*
|
|
* |-----------------------------------------------------------|
|
|
* | Copyright (c) 1990 MIPS Computer Systems, Inc. |
|
|
* | All Rights Reserved |
|
|
* |-----------------------------------------------------------|
|
|
* | Restricted Rights Legend |
|
|
* | Use, duplication, or disclosure by the Government is |
|
|
* | subject to restrictions as set forth in |
|
|
* | subparagraph (c)(1)(ii) of the Rights in Technical |
|
|
* | Data and Computer Software Clause of DFARS 52.227-7013. |
|
|
* | MIPS Computer Systems, Inc. |
|
|
* | 950 DeGuigne Drive |
|
|
* | Sunnyvale, CA 94086 |
|
|
* |-----------------------------------------------------------|
|
|
*/
|
|
#ident "$Revision: 1.9 $"
|
|
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
|
|
/* All Rights Reserved */
|
|
/* */
|
|
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
|
|
/* The copyright notice above does not evidence any */
|
|
/* actual or intended publication of such source code. */
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <sys/types.h>
|
|
#include <shadow.h>
|
|
#include <pwd.h>
|
|
#include <string.h>
|
|
#include <signal.h>
|
|
#include <sys/stat.h>
|
|
#include <errno.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#ifdef _SHAREII
|
|
#include <dlfcn.h>
|
|
#include <shareIIhooks.h>
|
|
SH_DECLARE_HOOK(SETMYNAME);
|
|
SH_DECLARE_HOOK(ISUSERADMIN);
|
|
SH_DECLARE_HOOK(BACKOUTUSER);
|
|
SH_DECLARE_HOOK(ENTERPASSWD);
|
|
SH_DECLARE_HOOK(ADDUSER);
|
|
SH_DECLARE_HOOK(MODUSER);
|
|
SH_DECLARE_HOOK(DELUSER);
|
|
SH_DECLARE_HOOK(COMMITUSER);
|
|
static int SHshareRunning = 0;
|
|
#endif /* _SHAREII */
|
|
|
|
#define CMT_SIZE (128+1) /* Argument sizes + 1 (for '\0') */
|
|
#define DIR_SIZE (256+1)
|
|
#define SHL_SIZE (256+1)
|
|
#define ENTRY_LENGTH BUFSIZ /* Max length of an /etc/passwd entry */
|
|
#define UID_MIN 100 /* Lower bound of default UID */
|
|
|
|
#define M_MASK 01 /* Masks for the optn_mask variable */
|
|
#define L_MASK 02 /* It keeps track of which options */
|
|
#define C_MASK 04 /* have been entered */
|
|
#define H_MASK 010
|
|
#define U_MASK 020
|
|
#define G_MASK 040
|
|
#define S_MASK 0100
|
|
#define O_MASK 0200
|
|
#define A_MASK 0400
|
|
#define D_MASK 01000
|
|
#define F_MASK 02000
|
|
#if DO_PWEXPIRE
|
|
#define E_MASK 04000
|
|
#endif
|
|
|
|
/* #define DEBUG 1 */
|
|
/* flags for info_mask */
|
|
#define LOGNAME_EXIST 01 /* logname exists */
|
|
#define BOTH_FILES 02 /* touch both password files */
|
|
#define WRITE_P_ENTRY 04 /* write out password entry */
|
|
#define WRITE_S_ENTRY 010 /* write out shadow entry */
|
|
#define NEED_DEF_UID 020 /* need default uid */
|
|
#define FOUND 040 /* found the entry in password file */
|
|
#define LOCKED 0100 /* did we lock the password file */
|
|
#define SHAD_FLAG 0200 /* running with shadow file flag */
|
|
|
|
char defdir[] = "/usr/people/"; /* default home directory for new user */
|
|
char defshell[] = "/bin/sh"; /* default shell of new entries */
|
|
char pwdflr[] = "x" ; /* password string for /etc/passwd */
|
|
char lkstring[] = "*LK*" ; /* lock string for shadow password */
|
|
char nullstr[] = "" ; /* null string */
|
|
|
|
#if DO_PWEXPIRE /* this file used only by -e (passwd expiration opt) code */
|
|
#define DATMSK "DATEMSK=/etc/datemsk"
|
|
char getdate_msg[9][80] = {
|
|
"? no error",
|
|
"environment variable DATEMSK null/undefined",
|
|
"cannot open DATEMSK template file",
|
|
"bad status for DATEMSK template file",
|
|
"DATEMSK template file is not a regular file",
|
|
"I/O error reading DATEMSK template file",
|
|
"memory allocation failure while processing DATEMSK template file",
|
|
"no match for input string in DATEMSK template file",
|
|
"invalid time/date input"
|
|
};
|
|
#endif
|
|
|
|
/* Declare all functions that do not return integers. This is here
|
|
to get rid of some lint messages */
|
|
|
|
void bad_perm(void), bad_usage(char *), bad_arg(char *),
|
|
bad_uid(void), bad_pasf(void), file_error(void), bad_news(void),
|
|
no_lock(void), add_uid(uid_t), rid_tmpf(void), ck_p_sz(struct passwd *),
|
|
ck_s_sz(struct spwd *), bad_name(char *) ;
|
|
int rec_pwd(void);
|
|
|
|
#define _SAFESTR(_SPTR) (_SPTR ? _SPTR : "<NULL>")
|
|
|
|
/* SGI: config file to see if system uses NIS */
|
|
#define YP_CONFIG_FILE "/etc/config/yp"
|
|
static int get_flag_state();
|
|
#define LINE_SIZE 80
|
|
|
|
#if DEBUG
|
|
static void dump_pwent(struct passwd *);
|
|
static void dump_spwent(struct spwd *);
|
|
/* SGI added these to allow unprivileged debugging */
|
|
static int xxlckpwdf();
|
|
static void xxulckpwdf();
|
|
#define lckpwdf() xxlckpwdf()
|
|
#define ulckpwdf() xxulckpwdf()
|
|
#undef PASSWD
|
|
#define PASSWD "/usr/tmp/passwd"
|
|
#undef SHADOW
|
|
#define SHADOW "/usr/tmp/shadow"
|
|
#undef OPASSWD
|
|
#define OPASSWD "/usr/tmp/opasswd"
|
|
#undef OSHADOW
|
|
#define OSHADOW "/usr/tmp/oshadow"
|
|
#undef PASSTEMP
|
|
#define PASSTEMP "/usr/tmp/ptmp"
|
|
#undef SHADTEMP
|
|
#define SHADTEMP "/usr/tmp/stmp"
|
|
#endif
|
|
|
|
static FILE *fp_ptemp, *fp_stemp ;
|
|
|
|
/* The uid_blk structure is used in the search for the default
|
|
uid. Each uid_blk represent a range of uid(s) that are currently
|
|
used on the system. */
|
|
|
|
struct uid_blk {
|
|
struct uid_blk *link ;
|
|
uid_t low ; /* low bound for this uid block */
|
|
uid_t high ; /* high bound for this uid block */
|
|
} ;
|
|
|
|
/* more forward decls, moved from above */
|
|
void uid_bcom(struct uid_blk *), add_ublk(uid_t, struct uid_blk *);
|
|
struct uid_blk *uid_sp ;
|
|
char *prognamp ; /* program name */
|
|
extern int errno ;
|
|
int optn_mask = 0, info_mask = 0 ;
|
|
extern int getdate_err;
|
|
int shadow_exist = 0;
|
|
/* SGI IRIX 5.1 getpwent merges in NIS transparently, i.e. you get
|
|
* the NIS yppasswd map entries back from getpwent. This behavior
|
|
* is turned off by setting _getpwent_no_yp to 1, which is what
|
|
* passmgmt needs.
|
|
*/
|
|
extern int _getpwent_no_yp;
|
|
|
|
/* SGI IRIX 5.1 getpwent handles shadow passwd file transparently for
|
|
* privileged users, i.e. getpwent returns encrypted pw if euid==0.
|
|
* This behavior is turned off by setting _getpwent_no_shadow to 1,
|
|
* which is what passmgmt needs.
|
|
*/
|
|
extern int _getpwent_no_shadow;
|
|
|
|
/* SGI: place to save +::... entry to preserve it at the end of the file */
|
|
struct passwd savedpwent;
|
|
|
|
/* SGI IRIX 6.2 getpwent merges in SSDI, which allows custom implementations
|
|
* of passwd database (and others as well). With SSDI, getpwent will
|
|
* return entries from these custom implemetations, whereas passmt
|
|
* only needs stuff from the "files". Setting _getpwent_no_ssdi to 1
|
|
* turns off this behavior which is what passmgmt needs.
|
|
*/
|
|
extern int _getpwent_no_ssdi;
|
|
|
|
main (argc, argv)
|
|
int argc ;
|
|
char **argv ;
|
|
{
|
|
int c, i ;
|
|
char *lognamp, *char_p ;
|
|
char *shadownamep; /* SGI: lognamep less the leading + for YP*/
|
|
int end_of_file = 0;
|
|
int error;
|
|
long date = 0;
|
|
|
|
extern char *optarg;
|
|
extern int optind ;
|
|
extern struct tm *getdate();
|
|
|
|
struct passwd *pw_ptr1p, passwd_st ;
|
|
struct spwd *sp_ptr1p, shadow_st ;
|
|
struct stat statbuf ;
|
|
int ypflag = 0;
|
|
int savedflag = 0; /* SGI: used for +::... entry */
|
|
struct tm *tm_ptr;
|
|
#ifdef _SHAREII
|
|
uid_t SHoriguid;
|
|
uid_t SHoriggid;
|
|
static const char *Myname = "passmgmt";
|
|
#endif /* _SHAREII */
|
|
#ifdef DEBUG
|
|
struct uid_blk *uid_ptr;
|
|
#endif
|
|
|
|
tzset();
|
|
/* Get program name */
|
|
prognamp = argv[0] ;
|
|
|
|
#ifndef DEBUG
|
|
#ifdef _SHAREII
|
|
/*
|
|
*
|
|
* The original identity check requires that the
|
|
* invoker's real UID == 0, i.e. the invoker is really the
|
|
* super-user.
|
|
*
|
|
* Share allows users other than the super-user to alter the
|
|
* password file, subject to careful restrictions. At this point
|
|
* we check the invoker's privilege. The function returns 1 if
|
|
* it is okay, 0 if the user is not allowed to add/mod/del users.
|
|
*/
|
|
if (sgidladd(SH_LIMITS_LIB, RTLD_LAZY))
|
|
{
|
|
SHshareRunning = 1;
|
|
SH_HOOK_SETMYNAME(Myname);
|
|
|
|
if (SH_HOOK_ISUSERADMIN() == 0)
|
|
bad_perm();
|
|
}
|
|
else
|
|
{
|
|
/* Check identity */
|
|
if ( getuid () != 0 )
|
|
bad_perm () ;
|
|
}
|
|
#else
|
|
/* Check identity */
|
|
if ( getuid () != 0 )
|
|
bad_perm () ;
|
|
#endif /* _SHAREII */
|
|
#endif
|
|
|
|
/* SGI: turn off NIS mapping for getpwent */
|
|
_getpwent_no_yp = 1;
|
|
/* SGI: turn off automatic fill from shadow */
|
|
_getpwent_no_shadow = 1;
|
|
/* SGI: turn off SSDI mapping for getpwent */
|
|
_getpwent_no_ssdi = 1;
|
|
|
|
/* Check for the existence of shadow password file */
|
|
if ( !access (SHADOW,0) ) /* if shadow is there */
|
|
{
|
|
shadow_exist ++;
|
|
info_mask |= SHAD_FLAG ;
|
|
}
|
|
|
|
|
|
/* Lock the password file(s) */
|
|
|
|
if ( lckpwdf() != 0 )
|
|
no_lock () ;
|
|
info_mask |= LOCKED ; /* remember we locked */
|
|
|
|
/* initialize the two structures */
|
|
|
|
passwd_st.pw_name = nullstr ; /* login name */
|
|
if ( SHAD_FLAG & info_mask ) /* if shadow is running */
|
|
passwd_st.pw_passwd = pwdflr ; /* bogus password */
|
|
else
|
|
passwd_st.pw_passwd = lkstring; /* bogus password */
|
|
passwd_st.pw_uid = -1 ; /* no uid */
|
|
passwd_st.pw_gid = 1 ; /* default gid */
|
|
passwd_st.pw_age = nullstr ; /* no aging info. */
|
|
passwd_st.pw_comment = nullstr ; /* no comments */
|
|
passwd_st.pw_gecos = nullstr ; /* no comments */
|
|
passwd_st.pw_dir = nullstr ; /* no default directory */
|
|
|
|
/*
|
|
* XXX: 5.1 doesn't work correctly with a NULL /etc/passwd
|
|
* shell field, so force passmgmt to specify /bin/sh when
|
|
* creating new entries, rather than defaulting to NULL.
|
|
*/
|
|
passwd_st.pw_shell = defshell ; /* explicit /bin/sh */
|
|
|
|
shadow_st.sp_namp = nullstr ; /* no name */
|
|
shadow_st.sp_pwdp = lkstring ; /* locked password */
|
|
shadow_st.sp_lstchg = -1 ; /* no lastchanged date */
|
|
shadow_st.sp_min = -1 ; /* no min */
|
|
shadow_st.sp_max = -1 ; /* no max */
|
|
shadow_st.sp_warn = -1 ; /* no warn */
|
|
shadow_st.sp_inact = -1 ; /* no inactive */
|
|
shadow_st.sp_expire = -1 ; /* no expire */
|
|
shadow_st.sp_flag = 0 ; /* no flag */
|
|
|
|
/* parse the command line */
|
|
|
|
#if DO_PWEXPIRE /* accept -e (passwd expiration) option */
|
|
while ( (c = getopt (argc, argv, "ml:c:h:u:g:s:f:e:k:oad")) != -1 )
|
|
#else
|
|
while ( (c = getopt (argc, argv, "ml:c:h:u:g:s:f:k:oad")) != -1 )
|
|
#endif
|
|
|
|
switch (c)
|
|
{
|
|
|
|
case 'm' :
|
|
/* Modify */
|
|
|
|
if ( (A_MASK|D_MASK|M_MASK) & optn_mask )
|
|
bad_usage ("Invalid combination of options") ;
|
|
|
|
optn_mask |= M_MASK ;
|
|
break ;
|
|
|
|
case 'l' :
|
|
/* Change logname */
|
|
|
|
if ( (A_MASK|D_MASK|L_MASK) & optn_mask )
|
|
bad_usage ("Invalid combination of options") ;
|
|
|
|
if ( strpbrk ( optarg, ":\n" ) ||
|
|
strlen (optarg) == 0 )
|
|
bad_arg ("Invalid argument to option -l") ;
|
|
|
|
optn_mask |= L_MASK ;
|
|
passwd_st.pw_name = optarg ;
|
|
shadow_st.sp_namp = optarg ;
|
|
break ;
|
|
|
|
case 'f' :
|
|
/* set inactive */
|
|
|
|
if ( (D_MASK|F_MASK) & optn_mask )
|
|
bad_usage ("Invalid combination of options") ;
|
|
if (((shadow_st.sp_inact = strtol (optarg,
|
|
&char_p,10)) < 0) || (*char_p != '\0')
|
|
|| strlen (optarg) < 0)
|
|
bad_arg ("Invalid argument to option -f") ;
|
|
if (shadow_st.sp_inact == 0 )
|
|
shadow_st.sp_inact = -1;
|
|
optn_mask |= F_MASK;
|
|
break;
|
|
|
|
#if DO_PWEXPIRE
|
|
case 'e' :
|
|
/* set expire date */
|
|
|
|
if ( (D_MASK|E_MASK) & optn_mask )
|
|
bad_usage ("Invalid combination of options") ;
|
|
|
|
if ( (strlen(optarg)) <2 )
|
|
shadow_st.sp_expire = -1;
|
|
else {
|
|
if (getenv("DATEMSK") == NULL)
|
|
putenv(DATMSK);
|
|
if ( (tm_ptr = getdate(optarg)) == NULL)
|
|
{
|
|
if( getdate_err < 0 || getdate_err > 8)
|
|
bad_arg("getdate internal error for -e opt");
|
|
else {
|
|
fprintf(stderr,"(%d) %s ",getdate_err,getdate_msg[getdate_err]);
|
|
bad_arg("Invalid argument to -e opt");
|
|
}
|
|
}
|
|
if ((date = mktime(tm_ptr)) < 0)
|
|
bad_arg ("Invalid argument to -e opt");
|
|
if ((shadow_st.sp_expire = (date/DAY))<=DAY_NOW)
|
|
bad_arg ("Invalid argument to -e opt, date must be > today");
|
|
}
|
|
|
|
optn_mask |= E_MASK;
|
|
break;
|
|
#endif /* DO_PWEXPIRE */
|
|
|
|
case 'c' :
|
|
/* The comment */
|
|
|
|
if ( (D_MASK|C_MASK) & optn_mask )
|
|
bad_usage ("Invalid combination of options");
|
|
|
|
if ( strlen (optarg) > CMT_SIZE ||
|
|
strpbrk ( optarg, ":\n" ) )
|
|
bad_arg ("Invalid argument to option -c") ;
|
|
|
|
optn_mask |= C_MASK ;
|
|
passwd_st.pw_comment = optarg ;
|
|
passwd_st.pw_gecos = optarg ;
|
|
break ;
|
|
|
|
case 'h' :
|
|
/* The home directory */
|
|
|
|
if ( (D_MASK|H_MASK) & optn_mask )
|
|
bad_usage ("Invalid combination of options") ;
|
|
|
|
if ( strlen (optarg) > DIR_SIZE ||
|
|
strpbrk ( optarg, ":\n" ) )
|
|
bad_arg ("Invalid argument to option -h") ;
|
|
|
|
optn_mask |= H_MASK ;
|
|
passwd_st.pw_dir = optarg ;
|
|
break ;
|
|
|
|
case 'u' :
|
|
/* The uid */
|
|
|
|
if ( (D_MASK|U_MASK) & optn_mask )
|
|
bad_usage ("Invalid combination of options") ;
|
|
|
|
optn_mask |= U_MASK ;
|
|
passwd_st.pw_uid = (uid_t)strtol(optarg,&char_p,10);
|
|
if ( (*char_p != '\0') ||
|
|
( passwd_st.pw_uid < 0 ) ||
|
|
( strlen (optarg) == 0 ) )
|
|
bad_arg ("Invalid argument to option -u") ;
|
|
|
|
break ;
|
|
|
|
case 'g' :
|
|
/* The gid */
|
|
|
|
if ( (D_MASK|G_MASK) & optn_mask )
|
|
bad_usage ("Invalid combination of options");
|
|
|
|
optn_mask |= G_MASK ;
|
|
passwd_st.pw_gid = (gid_t)strtol(optarg,&char_p,10);
|
|
|
|
if ( (*char_p != '\0') ||
|
|
( passwd_st.pw_gid < 0 ) ||
|
|
( strlen (optarg) == 0 ) )
|
|
bad_arg ("Invalid argument to option -g") ;
|
|
break ;
|
|
|
|
case 's' :
|
|
/* The shell */
|
|
|
|
if ( (D_MASK|S_MASK) & optn_mask )
|
|
bad_usage ("Invalid combination of options") ;
|
|
|
|
if ( strlen (optarg) > SHL_SIZE ||
|
|
strpbrk ( optarg, ":\n" ) )
|
|
bad_arg ("Invalid argument to option -s") ;
|
|
|
|
optn_mask |= S_MASK ;
|
|
passwd_st.pw_shell = optarg ;
|
|
break ;
|
|
|
|
case 'o' :
|
|
/* Override unique uid */
|
|
|
|
if ( (D_MASK|O_MASK) & optn_mask )
|
|
bad_usage ("Invalid combination of options") ;
|
|
|
|
optn_mask |= O_MASK ;
|
|
break ;
|
|
|
|
case 'a' :
|
|
/* Add */
|
|
|
|
if ( (A_MASK|M_MASK|D_MASK|L_MASK) & optn_mask )
|
|
bad_usage ("Invalid combination of options") ;
|
|
|
|
optn_mask |= A_MASK ;
|
|
break ;
|
|
|
|
case 'd' :
|
|
/* Delete */
|
|
|
|
if ( (D_MASK|M_MASK|L_MASK|C_MASK|
|
|
H_MASK|U_MASK|G_MASK|S_MASK|
|
|
O_MASK|A_MASK) & optn_mask )
|
|
bad_usage ("Invalid combination of options") ;
|
|
|
|
optn_mask |= D_MASK ;
|
|
break ;
|
|
|
|
case '?' :
|
|
|
|
bad_usage ("") ;
|
|
break ;
|
|
}
|
|
|
|
/* check command syntax for the following errors */
|
|
/* too few or too many arguments */
|
|
/* no -a -m or -d option */
|
|
/* -o without -u */
|
|
/* -m with no other option */
|
|
|
|
if ( optind == argc || argc > (optind+1) ||
|
|
!((A_MASK|M_MASK|D_MASK) & optn_mask) ||
|
|
((optn_mask & O_MASK) && !(optn_mask & U_MASK)) ||
|
|
((optn_mask & M_MASK) && !(optn_mask &
|
|
#if DO_PWEXPIRE
|
|
(L_MASK|C_MASK|H_MASK|U_MASK|G_MASK|S_MASK|F_MASK|E_MASK))) )
|
|
#else
|
|
(L_MASK|C_MASK|H_MASK|U_MASK|G_MASK|S_MASK|F_MASK))) )
|
|
#endif
|
|
|
|
bad_usage ("Invalid command syntax") ;
|
|
|
|
/* null string argument or bad characters ? */
|
|
if ( ( strlen ( argv[optind] ) == 0 ) ||
|
|
strpbrk ( argv[optind], ":\n" ) )
|
|
bad_arg ("Invalid name") ;
|
|
|
|
lognamp = argv [optind] ;
|
|
if (*lognamp == '+') {
|
|
ypflag = 1;
|
|
optn_mask &= ~U_MASK ;
|
|
optn_mask &= ~G_MASK ;
|
|
/* SGI: these were 0, but -1 requested by CSD */
|
|
passwd_st.pw_uid = -1 ;
|
|
passwd_st.pw_gid = -1 ;
|
|
shadownamep = lognamp+1;
|
|
}
|
|
else
|
|
{
|
|
shadownamep = lognamp;
|
|
}
|
|
|
|
/* if we are adding a new user or modifying an existing user
|
|
(not the logname), then copy logname into the two data
|
|
structures */
|
|
|
|
if ( (A_MASK & optn_mask) ||
|
|
((M_MASK & optn_mask) && !(optn_mask & L_MASK)) )
|
|
{
|
|
passwd_st.pw_name = argv [optind] ;
|
|
shadow_st.sp_namp = argv [optind] ;
|
|
}
|
|
|
|
/* SGI: shadow file can't have leading + in NIS entries */
|
|
if (*shadow_st.sp_namp == '+') shadow_st.sp_namp++;
|
|
|
|
/* Put in directory if we are adding and we need a default */
|
|
|
|
if ( !( optn_mask & H_MASK) && ( optn_mask & A_MASK ) ) {
|
|
if ((passwd_st.pw_dir = (char *)malloc((size_t)DIR_SIZE))==NULL)
|
|
file_error () ;
|
|
|
|
*passwd_st.pw_dir = '\0' ;
|
|
if (!ypflag) {
|
|
(void)strcat(passwd_st.pw_dir, defdir);
|
|
(void)strcat(passwd_st.pw_dir, lognamp);
|
|
}
|
|
}
|
|
|
|
/* Check the number of password files we are touching */
|
|
|
|
if ( (SHAD_FLAG & info_mask) && !( (M_MASK & optn_mask) &&
|
|
!(L_MASK & optn_mask) ) )
|
|
info_mask |= BOTH_FILES ;
|
|
|
|
if ((M_MASK & optn_mask) &&
|
|
#if DO_PWEXPIRE
|
|
((E_MASK & optn_mask) || (F_MASK & optn_mask))) {
|
|
#else
|
|
(F_MASK & optn_mask)) {
|
|
#endif
|
|
if (!(SHAD_FLAG & info_mask))
|
|
bad_arg (
|
|
"/etc/shadow file is not accessible for specified operation!"
|
|
);
|
|
info_mask |= BOTH_FILES ;
|
|
}
|
|
|
|
/* Open the temporary file(s) with appropriate permission mask */
|
|
/* and the appropriate owner */
|
|
|
|
if ( stat ( PASSWD, &statbuf ) < 0 )
|
|
file_error () ;
|
|
|
|
(void) umask ( ~( statbuf.st_mode & (S_IRUSR|S_IRGRP|S_IROTH) ) ) ;
|
|
|
|
if ( (fp_ptemp = fopen ( PASSTEMP , "w" )) == NULL )
|
|
file_error () ;
|
|
|
|
if ( chown ( PASSTEMP, statbuf.st_uid, statbuf.st_gid ) != NULL )
|
|
{
|
|
(void) fclose ( fp_ptemp ) ;
|
|
|
|
if ( unlink ( PASSTEMP ) )
|
|
(void)fprintf(stderr, "%s: warning: cannot unlink %s\n",
|
|
prognamp, PASSTEMP ) ;
|
|
|
|
file_error () ;
|
|
}
|
|
|
|
if ( info_mask & BOTH_FILES )
|
|
{
|
|
if ( stat ( SHADOW, &statbuf ) < 0 )
|
|
{
|
|
rid_tmpf () ;
|
|
file_error () ;
|
|
}
|
|
|
|
(void) umask ( ~( statbuf.st_mode & S_IRUSR ) ) ;
|
|
|
|
if ( (fp_stemp = fopen ( SHADTEMP , "w" )) == NULL )
|
|
{
|
|
rid_tmpf () ;
|
|
file_error () ;
|
|
}
|
|
|
|
if (chown(SHADTEMP, statbuf.st_uid, statbuf.st_gid ) != NULL)
|
|
{
|
|
rid_tmpf () ;
|
|
file_error () ;
|
|
}
|
|
}
|
|
|
|
/* Default uid needed ? */
|
|
|
|
if ( !( optn_mask & U_MASK ) && ( optn_mask & A_MASK ) && (!ypflag) )
|
|
{
|
|
/* mark it in the information mask */
|
|
info_mask |= NEED_DEF_UID ;
|
|
|
|
/* create the head of the uid number list */
|
|
if ((uid_sp = (struct uid_blk *)
|
|
malloc((size_t)sizeof(struct uid_blk))) == NULL)
|
|
{
|
|
rid_tmpf () ;
|
|
file_error () ;
|
|
}
|
|
|
|
uid_sp->link = NULL ;
|
|
uid_sp->low = (UID_MIN -1) ;
|
|
uid_sp->high = (UID_MIN -1) ;
|
|
}
|
|
|
|
|
|
error = errno = end_of_file = 0;
|
|
/* The while loop for reading PASSWD entries */
|
|
while (!end_of_file) {
|
|
if ( (pw_ptr1p = (struct passwd *) getpwent()) != NULL ) {
|
|
info_mask |= WRITE_P_ENTRY ;
|
|
/*
|
|
* if shadow is running, we must overwrite the actual
|
|
* encrypted passwd--fetched from /etc/shadow--with
|
|
* the bogus value, since this entry will be written
|
|
* to tmp file that then becomes /etc/passwd.
|
|
*/
|
|
if (SHAD_FLAG & info_mask)
|
|
pw_ptr1p->pw_passwd = pwdflr ;
|
|
#if DEBUG
|
|
if (errno)
|
|
fprintf(stderr, "!!!errno == %d: ", errno);
|
|
fprintf(stderr, "Processing ");
|
|
dump_pwent(pw_ptr1p);
|
|
#endif
|
|
|
|
/* Set up the uid usage blocks to find the first
|
|
available uid above UID_MIN, if needed */
|
|
|
|
if ( info_mask & NEED_DEF_UID )
|
|
add_uid ( pw_ptr1p->pw_uid ) ;
|
|
|
|
/* Check for unique UID */
|
|
|
|
if ( strcmp ( lognamp, pw_ptr1p->pw_name ) &&
|
|
( pw_ptr1p->pw_uid == passwd_st.pw_uid ) &&
|
|
( (optn_mask & U_MASK) && !(optn_mask & O_MASK) ) ) {
|
|
rid_tmpf () ; /* get rid of temp files */
|
|
bad_uid () ;
|
|
}
|
|
/* Check for unique new logname */
|
|
|
|
if (strcmp(lognamp, pw_ptr1p->pw_name) && (optn_mask&L_MASK) &&
|
|
!strcmp(pw_ptr1p->pw_name, passwd_st.pw_name)) {
|
|
rid_tmpf () ;
|
|
if ( (SHAD_FLAG & info_mask) &&
|
|
!getspnam ( pw_ptr1p->pw_name ))
|
|
bad_pasf () ;
|
|
else
|
|
bad_name ( "logname already exists" ) ;
|
|
}
|
|
|
|
#ifdef _SHAREII
|
|
/*
|
|
* Share builds a list of all the users in the password file
|
|
* for later checking whether the invoker has permission
|
|
* to be adding/modifying/deleting the user in question.
|
|
*/
|
|
if (SHshareRunning)
|
|
SH_HOOK_ENTERPASSWD(pw_ptr1p);
|
|
#endif /* _SHAREII */
|
|
|
|
if (!strcmp(lognamp, pw_ptr1p->pw_name) ||
|
|
(ypflag && !strcmp(lognamp+1, pw_ptr1p->pw_name)) ||
|
|
(*pw_ptr1p->pw_name == '+' &&
|
|
!strcmp(lognamp, pw_ptr1p->pw_name+1))) {
|
|
/* no good if we want to add an existing logname */
|
|
if ( optn_mask & A_MASK ) {
|
|
rid_tmpf () ;
|
|
if ((SHAD_FLAG&info_mask) && !getspnam(shadownamep))
|
|
bad_pasf();
|
|
else
|
|
bad_name("name already exists");
|
|
}
|
|
/* remember we found it */
|
|
info_mask |= FOUND ;
|
|
|
|
#ifdef _SHAREII
|
|
/*
|
|
* Share needs to keep track of the original
|
|
* UID of the user being deleted or modified,
|
|
* for later checking.
|
|
*/
|
|
SHoriguid = pw_ptr1p->pw_uid;
|
|
SHoriggid = pw_ptr1p->pw_gid;
|
|
#endif /* _SHAREII */
|
|
|
|
/* Do not write it out on the fly */
|
|
if ( optn_mask & D_MASK )
|
|
info_mask &= ~WRITE_P_ENTRY ;
|
|
|
|
if ( optn_mask & M_MASK ) {
|
|
if ((SHAD_FLAG & info_mask) &&
|
|
!getspnam(shadownamep)) {
|
|
rid_tmpf () ;
|
|
bad_pasf () ;
|
|
}
|
|
if ( optn_mask & L_MASK )
|
|
pw_ptr1p->pw_name = passwd_st.pw_name;
|
|
if ( optn_mask & U_MASK )
|
|
pw_ptr1p->pw_uid = passwd_st.pw_uid;
|
|
if ( optn_mask & G_MASK )
|
|
pw_ptr1p->pw_gid = passwd_st.pw_gid;
|
|
if ( optn_mask & C_MASK ) {
|
|
pw_ptr1p->pw_comment =
|
|
passwd_st.pw_comment;
|
|
pw_ptr1p->pw_gecos=passwd_st.pw_comment;
|
|
}
|
|
if ( optn_mask & H_MASK )
|
|
pw_ptr1p->pw_dir = passwd_st.pw_dir ;
|
|
if ( optn_mask & S_MASK )
|
|
pw_ptr1p->pw_shell = passwd_st.pw_shell;
|
|
ck_p_sz(pw_ptr1p); /* check entry size */
|
|
}
|
|
}
|
|
|
|
if ( (info_mask & WRITE_P_ENTRY) )
|
|
{
|
|
/* handle +::0:0::: et al, which must be/stay the last entry */
|
|
if( (pw_ptr1p->pw_name[0] == '+')
|
|
&& (pw_ptr1p->pw_name[1] == '\0'))
|
|
{
|
|
/* HUH? can't have two of these entries */
|
|
if (savedflag == 1 )
|
|
{
|
|
bad_pasf();
|
|
}
|
|
savedflag = 1;
|
|
(void)memcpy((void *)&savedpwent,
|
|
(void *)pw_ptr1p,
|
|
sizeof(struct passwd));
|
|
}
|
|
else
|
|
{
|
|
if ( putpwent ( pw_ptr1p, fp_ptemp ) ) {
|
|
rid_tmpf () ;
|
|
file_error () ;
|
|
}
|
|
}
|
|
}
|
|
|
|
} else { /* pw_ptr1p == NULL */
|
|
if (errno == 0) /* end of file */
|
|
end_of_file = 1;
|
|
else if (errno == EINVAL) { /* Bad entry found, skip it */
|
|
error++;
|
|
errno = 0;
|
|
#if DEBUG
|
|
fprintf(stderr, "Bad passwd entry (NULL pw_ptr1p)\n");
|
|
#endif
|
|
} else /* unexpected error found */
|
|
end_of_file = 1;
|
|
}
|
|
}
|
|
|
|
if (error >= 1)
|
|
fprintf(stderr,
|
|
"%s: Bad entry found in /etc/passwd. Run pwconv.\n",
|
|
prognamp);
|
|
|
|
/* Cannot find the target entry and we are deleting or modifying */
|
|
|
|
if ( !(info_mask & FOUND) && ( optn_mask & (D_MASK|M_MASK) ) )
|
|
{
|
|
rid_tmpf () ;
|
|
if ( (SHAD_FLAG & info_mask) && getspnam ( shadownamep ) )
|
|
bad_pasf () ;
|
|
else
|
|
bad_name ( "name does not exist" ) ;
|
|
}
|
|
|
|
/* First available uid above UID_MIN is ... */
|
|
|
|
if ( info_mask & NEED_DEF_UID )
|
|
passwd_st.pw_uid = uid_sp->high + 1 ;
|
|
#ifdef DEBUG1
|
|
for (uid_ptr = uid_sp; uid_ptr; uid_ptr = uid_ptr->link)
|
|
{
|
|
printf("UID Block: 0x%x hi: %d lo: %d\n",uid_ptr,uid_ptr->high, uid_ptr->low);
|
|
}
|
|
#endif
|
|
|
|
/* Write out the added entry now */
|
|
|
|
if ( optn_mask & A_MASK )
|
|
{
|
|
ck_p_sz ( &passwd_st ) ; /* Check entry size */
|
|
if ( putpwent ( &passwd_st, fp_ptemp ) )
|
|
{
|
|
rid_tmpf () ;
|
|
file_error () ;
|
|
}
|
|
}
|
|
/* SGI: put out saved +::0:0::: entry */
|
|
if (savedflag)
|
|
{
|
|
if ( putpwent ( &savedpwent, fp_ptemp) )
|
|
{
|
|
rid_tmpf ();
|
|
file_error ();
|
|
}
|
|
}
|
|
|
|
(void) fclose ( fp_ptemp ) ;
|
|
|
|
/* Now we are done with PASSWD */
|
|
|
|
#ifdef _SHAREII
|
|
/*
|
|
* Before committing to the operation, do a permission check
|
|
* that the invoker is allowed to do what they specified.
|
|
* If a normal user adds a new user, then a new lnode must
|
|
* be created and placed under the invoker's control.
|
|
* Normal users are not permitted to modify or delete the accounts
|
|
* of users who are not under their direct control.
|
|
*
|
|
* If permission is granted, then an lnode is created and/or deleted
|
|
* to keep the lnode file in line with the new state of the passwd
|
|
* file. If a new UID is added then a new lnode must be created.
|
|
* If a UID is no longer used, then its lnode must be deleted.
|
|
*
|
|
* Before passmgmt exits, it must call either SHbackoutuser()
|
|
* or SHcommituser() to finalise these lnode operations. If
|
|
* neither is called, then it will not spell disaster, but some
|
|
* lnodes may be left in existence with no password file entries.
|
|
* This may cause a few warning messages in the future, but no
|
|
* failures.
|
|
*/
|
|
if (SHshareRunning)
|
|
{
|
|
int error = 0;
|
|
|
|
if (optn_mask & A_MASK)
|
|
error = SH_HOOK_ADDUSER(passwd_st.pw_uid, passwd_st.pw_gid);
|
|
else if (optn_mask & M_MASK)
|
|
error = SH_HOOK_MODUSER
|
|
(
|
|
SHoriguid,
|
|
(optn_mask & U_MASK) ? passwd_st.pw_uid : SHoriguid,
|
|
SHoriggid,
|
|
(optn_mask & G_MASK) ? passwd_st.pw_gid : SHoriggid
|
|
);
|
|
else if (optn_mask & D_MASK)
|
|
error = SH_HOOK_DELUSER(SHoriguid);
|
|
|
|
switch (error)
|
|
{
|
|
case 0: break;
|
|
case 1: bad_perm();
|
|
break;
|
|
case 2: bad_uid();
|
|
break;
|
|
default:
|
|
file_error();
|
|
}
|
|
}
|
|
#endif /* _SHAREII */
|
|
|
|
/* Do this if we are touching both password files */
|
|
|
|
if ( info_mask & BOTH_FILES ) {
|
|
info_mask &= ~FOUND ; /* Reset FOUND flag */
|
|
|
|
/* The while loop for reading SHADOW entries */
|
|
info_mask |= WRITE_S_ENTRY ;
|
|
|
|
end_of_file = errno = error = 0;
|
|
|
|
while (!end_of_file) {
|
|
if ( (sp_ptr1p = (struct spwd *) getspent()) != NULL ) {
|
|
#if DEBUG
|
|
fprintf(stderr, "Processing ");
|
|
dump_spwent(sp_ptr1p);
|
|
#endif
|
|
/* See if the new logname already exist in the
|
|
shadow passwd file */
|
|
if ( ( optn_mask & M_MASK ) &&
|
|
strcmp ( shadownamep, shadow_st.sp_namp ) &&
|
|
( !strcmp ( sp_ptr1p->sp_namp,
|
|
shadow_st.sp_namp ) ) )
|
|
{
|
|
rid_tmpf () ;
|
|
bad_pasf () ;
|
|
}
|
|
|
|
if ( !strcmp ( shadownamep, sp_ptr1p->sp_namp ) )
|
|
{
|
|
info_mask |= FOUND ;
|
|
if ( optn_mask & A_MASK )
|
|
{
|
|
rid_tmpf () ;
|
|
bad_pasf () ; /* password file
|
|
inconsistent */
|
|
}
|
|
|
|
if ( optn_mask & M_MASK )
|
|
{
|
|
sp_ptr1p->sp_namp = shadow_st.sp_namp ;
|
|
if ( F_MASK & optn_mask)
|
|
sp_ptr1p->sp_inact =
|
|
shadow_st.sp_inact;
|
|
#if DO_PWEXPIRE
|
|
if ( E_MASK & optn_mask)
|
|
sp_ptr1p->sp_expire =
|
|
shadow_st.sp_expire;
|
|
#endif
|
|
ck_s_sz ( sp_ptr1p ) ;
|
|
}
|
|
|
|
if ( optn_mask & D_MASK )
|
|
info_mask &= ~WRITE_S_ENTRY ;
|
|
}
|
|
|
|
if ( info_mask & WRITE_S_ENTRY )
|
|
{
|
|
if ( putspent ( sp_ptr1p, fp_stemp ) )
|
|
{
|
|
rid_tmpf () ;
|
|
file_error () ;
|
|
}
|
|
}
|
|
else
|
|
info_mask |= WRITE_S_ENTRY ;
|
|
|
|
} else {
|
|
if (errno == 0)
|
|
end_of_file = 1;
|
|
else if (errno==EINVAL) { /*bad entry, skip it*/
|
|
error++;
|
|
errno = 0;
|
|
#if DEBUG
|
|
fprintf(stderr,
|
|
"Bad shadow ent (NULL sp_ptr1p)\n");
|
|
#endif
|
|
} else
|
|
/* unexpected error found */
|
|
end_of_file = 1;
|
|
}
|
|
}
|
|
|
|
if (error >= 1)
|
|
fprintf(stderr,
|
|
"%s: Bad entry found in /etc/shadow. Run pwconv.\n",
|
|
prognamp);
|
|
|
|
/* If we cannot find the entry and we are deleting or
|
|
modifying */
|
|
|
|
if ( !(info_mask & FOUND) && (optn_mask & (D_MASK|M_MASK)) )
|
|
{
|
|
rid_tmpf () ;
|
|
bad_pasf () ;
|
|
}
|
|
|
|
if ( optn_mask & A_MASK )
|
|
{
|
|
ck_s_sz ( &shadow_st ) ;
|
|
if ( putspent ( &shadow_st, fp_stemp ) )
|
|
{
|
|
rid_tmpf () ;
|
|
file_error () ;
|
|
}
|
|
}
|
|
|
|
(void) fclose (fp_stemp) ;
|
|
|
|
/* Done with SHADOW */
|
|
} /* End of if info_mask */
|
|
|
|
/* ignore all signals */
|
|
|
|
for ( i = 1 ; i < NSIG ; i++ )
|
|
(void ) sigset ( i, SIG_IGN ) ;
|
|
|
|
errno = 0 ; /* For correcting sigset to SIGKILL */
|
|
|
|
if (unlink (OPASSWD) && access (OPASSWD, 0) == 0)
|
|
file_error () ;
|
|
|
|
if (rename(PASSWD, OPASSWD) == -1)
|
|
file_error () ;
|
|
|
|
|
|
if (rename(PASSTEMP, PASSWD) == -1)
|
|
{
|
|
if (link (OPASSWD, PASSWD))
|
|
bad_news () ;
|
|
|
|
file_error () ;
|
|
}
|
|
|
|
|
|
if ( info_mask & BOTH_FILES )
|
|
{
|
|
|
|
if (unlink (OSHADOW) && access (OSHADOW, 0) == 0)
|
|
{
|
|
if ( rec_pwd() )
|
|
bad_news () ;
|
|
else
|
|
file_error () ;
|
|
}
|
|
|
|
if (rename(SHADOW, OSHADOW) == -1)
|
|
{
|
|
if ( rec_pwd() )
|
|
bad_news () ;
|
|
else
|
|
file_error () ;
|
|
}
|
|
|
|
|
|
if (rename(SHADTEMP, SHADOW) == -1)
|
|
{
|
|
if (rename(OSHADOW, SHADOW) == -1)
|
|
bad_news () ;
|
|
|
|
if ( rec_pwd() )
|
|
bad_news () ;
|
|
else
|
|
file_error () ;
|
|
}
|
|
|
|
}
|
|
|
|
ulckpwdf () ;
|
|
|
|
#ifdef _SHAREII
|
|
/*
|
|
* At this point, we know the password/shadow file operations have
|
|
* succeeded. We cn now finally commit to the lnode deletions
|
|
* that are required.
|
|
*/
|
|
if (SHshareRunning)
|
|
{
|
|
SH_HOOK_COMMITUSER();
|
|
}
|
|
#endif /* _SHAREII */
|
|
|
|
} /* end of main */
|
|
|
|
/* Try to recover the old password file */
|
|
|
|
int
|
|
rec_pwd ()
|
|
{
|
|
if ( unlink ( PASSWD ) || link ( OPASSWD, PASSWD ) )
|
|
return (-1) ;
|
|
|
|
return (0) ;
|
|
}
|
|
|
|
/* combine two uid_blk's */
|
|
|
|
void
|
|
uid_bcom ( uid_p )
|
|
struct uid_blk *uid_p ;
|
|
{
|
|
struct uid_blk *uid_tp ;
|
|
|
|
uid_tp = uid_p->link ;
|
|
uid_p->high = uid_tp->high ;
|
|
uid_p->link = uid_tp->link ;
|
|
|
|
free ( uid_tp ) ;
|
|
}
|
|
|
|
/* add a new uid_blk */
|
|
|
|
void
|
|
add_ublk ( num, uid_p )
|
|
uid_t num ;
|
|
struct uid_blk *uid_p ;
|
|
{
|
|
struct uid_blk *uid_tp ;
|
|
|
|
if ( (uid_tp = (struct uid_blk *) malloc((size_t)
|
|
sizeof(struct uid_blk)) ) == NULL )
|
|
{
|
|
rid_tmpf () ;
|
|
file_error () ;
|
|
}
|
|
|
|
uid_tp->high = uid_tp->low = num ;
|
|
uid_tp->link = uid_p->link ;
|
|
uid_p->link = uid_tp ;
|
|
}
|
|
|
|
/*
|
|
* Here we are using a linked list of uid_blk to keep track of all
|
|
* the used uids. Each uid_blk represents a range of used uid,
|
|
* with low represents the low inclusive end and high represents
|
|
* the high inclusive end. In the beginning, we initialize a linked
|
|
* list of one uid_blk with low = high = (UID_MIN-1). This was
|
|
* done in main().
|
|
* Each time we read in another used uid, we add it onto the linked
|
|
* list by either making a new uid_blk, decrementing the low of
|
|
* an existing uid_blk, incrementing the high of an existing
|
|
* uid_blk, or combining two existing uid_blks. After we finished
|
|
* building this linked list, the first available uid above or
|
|
* equal to UID_MIN is the high of the first uid_blk in the linked
|
|
* list + 1.
|
|
*/
|
|
|
|
/* add_uid() adds uid to the link list of used uids */
|
|
void
|
|
add_uid ( uid )
|
|
uid_t uid ;
|
|
{
|
|
struct uid_blk *uid_p ;
|
|
/* Only keep track of the ones above UID_MIN */
|
|
|
|
if ( uid >= UID_MIN )
|
|
{
|
|
uid_p = uid_sp ;
|
|
|
|
while ( uid_p != NULL )
|
|
{
|
|
|
|
if ( uid_p->link != NULL )
|
|
{
|
|
|
|
if ( uid >= uid_p->link->low )
|
|
uid_p = uid_p->link ;
|
|
|
|
else if ( uid >= uid_p->low &&
|
|
uid <= uid_p->high )
|
|
{
|
|
uid_p = NULL ;
|
|
}
|
|
|
|
else if (uid == (uid_p->high+1))
|
|
{
|
|
|
|
if ( ++uid_p->high == (uid_p->link->low - 1) )
|
|
{
|
|
uid_bcom (uid_p) ;
|
|
}
|
|
uid_p = NULL ;
|
|
}
|
|
|
|
else if ( uid == (uid_p->link->low - 1) )
|
|
{
|
|
uid_p->link->low -- ;
|
|
uid_p = NULL ;
|
|
}
|
|
|
|
else if ( uid < uid_p->link->low )
|
|
{
|
|
add_ublk ( uid, uid_p ) ;
|
|
uid_p = NULL ;
|
|
}
|
|
} /* if uid_p->link */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( uid == (uid_p->high + 1) )
|
|
{
|
|
uid_p->high++ ;
|
|
uid_p = NULL ;
|
|
}
|
|
|
|
else if ( uid >= uid_p->low &&
|
|
uid <= uid_p->high )
|
|
{
|
|
uid_p = NULL ;
|
|
}
|
|
|
|
else
|
|
{
|
|
add_ublk ( uid, uid_p ) ;
|
|
uid_p = NULL ;
|
|
}
|
|
|
|
} /* else */
|
|
|
|
} /* while uid_p */
|
|
|
|
} /* if uid */
|
|
}
|
|
|
|
void
|
|
bad_perm()
|
|
{
|
|
(void) fprintf (stderr, "%s: Permission denied\n", prognamp ) ;
|
|
#ifdef _SHAREII
|
|
if (SHshareRunning)
|
|
{
|
|
SH_HOOK_BACKOUTUSER();
|
|
}
|
|
#endif /* _SHAREII */
|
|
exit (1) ;
|
|
}
|
|
|
|
void
|
|
bad_usage(sp)
|
|
char *sp ;
|
|
{
|
|
if ( strlen (sp) != 0 )
|
|
(void) fprintf (stderr,"%s: %s\n", prognamp, sp) ;
|
|
(void) fprintf (stderr,"Usage:\n") ;
|
|
(void) fprintf (stderr,
|
|
"%s -a [-c comment] [-h homedir] [-u uid [-o]] [-g gid] \n",
|
|
prognamp ) ;
|
|
(void) fprintf (stderr,
|
|
#if DO_PWEXPIRE
|
|
" [-s shell] [-f inactive] [-e expire] name\n") ;
|
|
#else
|
|
" [-s shell] [-f inactive] name\n") ;
|
|
#endif
|
|
(void) fprintf (stderr,
|
|
"%s -m -c comment | -h homedir | -u uid [-o] | -g gid |\n",
|
|
prognamp ) ;
|
|
(void) fprintf (stderr,
|
|
#if DO_PWEXPIRE
|
|
" -s shell | -f inactive | -e expire | -l logname name\n") ;
|
|
#else
|
|
" -s shell | -f inactive | -l logname name\n") ;
|
|
#endif
|
|
(void) fprintf (stderr,"%s -d name\n", prognamp ) ;
|
|
if ( info_mask & LOCKED )
|
|
ulckpwdf () ;
|
|
exit (2) ;
|
|
}
|
|
|
|
void
|
|
bad_arg(s)
|
|
char *s ;
|
|
{
|
|
(void) fprintf (stderr, "%s: %s\n",prognamp, s) ;
|
|
|
|
if ( info_mask & LOCKED )
|
|
ulckpwdf () ;
|
|
exit (3) ;
|
|
}
|
|
|
|
void
|
|
bad_name(s)
|
|
char *s ;
|
|
{
|
|
(void) fprintf (stderr, "%s: %s\n",prognamp, s) ;
|
|
ulckpwdf () ;
|
|
exit (9) ;
|
|
}
|
|
|
|
void
|
|
bad_uid()
|
|
{
|
|
(void) fprintf (stderr, "%s: UID in use\n", prognamp ) ;
|
|
|
|
ulckpwdf () ;
|
|
exit (4) ;
|
|
}
|
|
|
|
void
|
|
bad_pasf()
|
|
{
|
|
(void) fprintf (stderr, "%s: Inconsistent password files\n", prognamp);
|
|
|
|
ulckpwdf () ;
|
|
#ifdef _SHAREII
|
|
if (SHshareRunning)
|
|
{
|
|
SH_HOOK_BACKOUTUSER();
|
|
}
|
|
#endif /* _SHAREII */
|
|
exit (5) ;
|
|
}
|
|
|
|
void
|
|
file_error()
|
|
{
|
|
(void) fprintf (stderr,
|
|
"%s: Unexpected failure. Password files unchanged\n",
|
|
prognamp ) ;
|
|
|
|
ulckpwdf () ;
|
|
#ifdef _SHAREII
|
|
if (SHshareRunning)
|
|
{
|
|
SH_HOOK_BACKOUTUSER();
|
|
}
|
|
#endif /* _SHAREII */
|
|
exit (6) ;
|
|
}
|
|
|
|
void
|
|
bad_news()
|
|
{
|
|
(void) fprintf (stderr,
|
|
"%s: Unexpected failure. Password file(s) missing\n",prognamp);
|
|
|
|
ulckpwdf () ;
|
|
#ifdef _SHAREII
|
|
if (SHshareRunning)
|
|
{
|
|
SH_HOOK_BACKOUTUSER();
|
|
}
|
|
#endif /* _SHAREII */
|
|
exit (7) ;
|
|
}
|
|
|
|
void
|
|
no_lock ()
|
|
{
|
|
(void) fprintf(stderr,"%s: Password file(s) busy. Try again later\n",
|
|
prognamp);
|
|
|
|
exit (8) ;
|
|
}
|
|
|
|
/* Check for the size of the whole passwd entry */
|
|
void
|
|
ck_p_sz ( pwp )
|
|
struct passwd *pwp ;
|
|
{
|
|
char ctp[128] ;
|
|
|
|
/* Ensure that the combined length of the individual */
|
|
/* fields will fit in a passwd entry. The 1 accounts for the */
|
|
/* newline and the 6 accounts for the colons (:'s) */
|
|
if ( ( strlen ( pwp->pw_name ) + 1 +
|
|
sprintf ( ctp, "%d", pwp->pw_uid ) +
|
|
sprintf ( ctp, "%d", pwp->pw_gid ) +
|
|
strlen ( pwp->pw_comment ) +
|
|
strlen ( pwp->pw_dir ) +
|
|
strlen ( pwp->pw_shell ) + 6) > (ENTRY_LENGTH-1) )
|
|
{
|
|
rid_tmpf () ;
|
|
bad_arg ("New password entry too long") ;
|
|
}
|
|
}
|
|
|
|
/* Check for the size of the whole passwd entry */
|
|
void
|
|
ck_s_sz ( ssp )
|
|
struct spwd *ssp ;
|
|
{
|
|
char ctp[128] ;
|
|
|
|
/* Ensure that the combined length of the individual */
|
|
/* fields will fit in a shadow entry. The 1 accounts for the */
|
|
/* newline and the 7 accounts for the colons (:'s) */
|
|
if ( ( strlen ( ssp->sp_namp ) + 1 +
|
|
strlen ( ssp->sp_pwdp ) +
|
|
sprintf ( ctp, "%d", ssp->sp_lstchg ) +
|
|
sprintf ( ctp, "%d", ssp->sp_min ) +
|
|
sprintf ( ctp, "%d", ssp->sp_max ) +
|
|
sprintf ( ctp, "%d", ssp->sp_warn ) +
|
|
sprintf ( ctp, "%d", ssp->sp_inact ) +
|
|
sprintf ( ctp, "%d", ssp->sp_expire ) + 7) > (ENTRY_LENGTH - 1))
|
|
{
|
|
rid_tmpf () ;
|
|
bad_arg ("New password entry too long") ;
|
|
}
|
|
}
|
|
|
|
/* Get rid of the temp files */
|
|
void
|
|
rid_tmpf ()
|
|
{
|
|
(void) fclose ( fp_ptemp ) ;
|
|
|
|
if ( unlink ( PASSTEMP ) )
|
|
(void) fprintf ( stderr, "%s: warning: cannot unlink %s\n",
|
|
prognamp, PASSTEMP ) ;
|
|
|
|
if ( info_mask & BOTH_FILES )
|
|
{
|
|
(void) fclose ( fp_stemp ) ;
|
|
|
|
if ( unlink ( SHADTEMP ) )
|
|
(void) fprintf ( stderr,
|
|
"%s: warning: cannot unlink %s\n",
|
|
prognamp, SHADTEMP ) ;
|
|
}
|
|
}
|
|
|
|
#if DEBUG
|
|
static void
|
|
dump_pwent(struct passwd *pwp)
|
|
{
|
|
fprintf(stderr,
|
|
"passwd entry: name \"%s\" pw \"%s\", %d.%d, dir \"%s\" shell \"%s\"\n",
|
|
_SAFESTR(pwp->pw_name), _SAFESTR(pwp->pw_passwd), pwp->pw_uid,
|
|
pwp->pw_gid, _SAFESTR(pwp->pw_dir), _SAFESTR(pwp->pw_shell));
|
|
}
|
|
|
|
static void
|
|
dump_spwent(struct spwd *spwp)
|
|
{
|
|
fprintf(stderr,
|
|
"shadow pwentry: name \"%s\", passwd \"%s\"\n",
|
|
_SAFESTR(spwp->sp_namp), _SAFESTR(spwp->sp_pwdp));
|
|
}
|
|
|
|
static int
|
|
xxlckpwdf()
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
static void
|
|
xxulckpwdf()
|
|
{
|
|
}
|
|
#endif /* DEBUG */
|