Shadow Login Suite, patch 5

John F Haugh II jfh at rpp386.cactus.org
Fri Jun 14 13:38:19 AEST 1991


The three new commands that were added in patch 4 had a few problems, and
this patch addresses them.  One important change is that the directory
copy, move, and delete functions are better supported now.  It is now
possible to rename someones home directory and have it copied to a completely
different device.

The most significant changes are for the support of "rlogin" on SCO Xenix.
These changes were made by Chip Rosenthal, as were many of the other
changes in this particular set of patches.

In the "Things to Come" catagory, the groupadd, groupdel, and groupmod
commands [ see your SVR4 documentation for more details ] have been
finished and will be part of patch 6, due out in a week or two.  Also
in "Things to Come" are changes to these 6 commands that will allow
you to utilize the code without being forced to have all of the other
strange modifications that I've made.  That is, you can stick with
just plain old /etc/passwd and /etc/group and still use the 6 more
recently added commands.  I think I went overboard making those commands
only usable with the extensions that I've added ...

A gentleman from Down Under is currently working on SunOS patches, and
swears to have it running on SunOS.  This is great news and I am
anxiously waiting those results.
--
Prereq: 4
*** rel3/patchlevel.h	Thu Jun 13 21:28:41 1991
--- patchlevel.h	Thu Jun 13 10:06:38 1991
***************
*** 10,13 ****
   */
  
  #define	RELEASE		3
! #define	PATCHLEVEL	4
--- 10,14 ----
   */
  
  #define	RELEASE		3
! #define	PATCHLEVEL	5
! #define	VERSION		"3.0.5"
*** rel3/Makefile	Thu Jun 13 21:28:42 1991
--- Makefile	Thu Jun 13 21:16:50 1991
***************
*** 8,16 ****
  # and conspicuously displayed on all copies of object code or
  # distribution media.
  #
! #	@(#)Makefile	3.11	11:11:42  - Shadow password system
  #
! #	@(#)Makefile	3.11	11:11:42	6/7/91
  #
  SHELL = /bin/sh
  
--- 8,16 ----
  # and conspicuously displayed on all copies of object code or
  # distribution media.
  #
! #	@(#)Makefile	3.15	20:52:45  - Shadow password system
  #
! #	@(#)Makefile	3.15	20:52:45	6/13/91
  #
  SHELL = /bin/sh
  
***************
*** 26,31 ****
--- 26,35 ----
  # LOGINDIR = /bin
  LOGINDIR = /etc
  
+ # Define any special libraries required to access the directory routines.
+ # NDIR = -lndir
+ NDIR = -lx
+ 
  # Pick your favorite C compiler and tags command
  CC = cc
  TAGS = ctags
***************
*** 39,44 ****
--- 43,57 ----
  RANLIB = ranlib
  # RANLIB = echo
  
+ # Configuration Flags
+ #
+ #	LIBS - system libraries
+ #		-lsocket - needed for TCP/IP and possibly SYSLOG
+ #		-ldbm or -lndbm - needed for DBM support
+ #		-lcrypt - needed for SCO crypt() functions
+ #	CFLAGS - C compiler flags
+ #		-DLAI_TCP - needed for SCO Xenix Lachman TCP/IP
+ 
  # Flags for SCO Xenix/386
  CFLAGS = -O -M3 -g $(OS)
  LIBS = -lcrypt -lndbm
***************
*** 128,134 ****
  	chfn.c chsh.c chage.c rad64.c encrypt.c chpasswd.c shadowio.c pwio.c \
  	newusers.c groupio.c fields.c pwdbm.c grpack.c grdbm.c sppack.c \
  	spdbm.c dpmain.c gshadow.c gsdbm.c gspack.c sgroupio.c useradd.c \
! 	userdel.c patchlevel.h usermod.c
  
  FILES1 = README newgrp.c Makefile config.h pwunconv.c obscure.c age.c id.c \
  	patchlevel.h
--- 141,147 ----
  	chfn.c chsh.c chage.c rad64.c encrypt.c chpasswd.c shadowio.c pwio.c \
  	newusers.c groupio.c fields.c pwdbm.c grpack.c grdbm.c sppack.c \
  	spdbm.c dpmain.c gshadow.c gsdbm.c gspack.c sgroupio.c useradd.c \
! 	userdel.c patchlevel.h usermod.c copydir.c mkrmdir.c
  
  FILES1 = README newgrp.c Makefile config.h pwunconv.c obscure.c age.c id.c \
  	patchlevel.h
***************
*** 149,155 ****
  
  FILES7 = groupio.c shadowio.c sgroupio.c
  
! FILES8 = useradd.c userdel.c usermod.c
  
  MAN_1 = chage.1 chfn.1 chsh.1 login.1 passwd.1 su.1
  MAN_3 = shadow.3
--- 162,168 ----
  
  FILES7 = groupio.c shadowio.c sgroupio.c
  
! FILES8 = useradd.c userdel.c usermod.c copydir.c mkrmdir.c
  
  MAN_1 = chage.1 chfn.1 chsh.1 login.1 passwd.1 su.1
  MAN_3 = shadow.3
***************
*** 333,355 ****
  id.lint: id.c
  	$(LINT) $(LINTFLAGS) id.c > id.lint
  
! useradd: useradd.o libshadow.a
! 	$(CC) -o useradd $(LDFLAGS) useradd.o libshadow.a $(LIBS)
  
! useradd.lint: useradd.c
! 	$(LINT) $(LINTFLAGS) useradd.c > useradd.lint
! 
! userdel: userdel.o libshadow.a
! 	$(CC) -o userdel $(LDFLAGS) userdel.o libshadow.a $(LIBS)
! 
! userdel.lint: userdel.c
! 	$(LINT) $(LINTFLAGS) userdel.c > userdel.lint
! 
! usermod: usermod.o libshadow.a
! 	$(CC) -o usermod $(LDFLAGS) usermod.o libshadow.a $(LIBS)
  
! usermod.lint: usermod.c
! 	$(LINT) $(LINTFLAGS) usermod.c > usermod.lint
  
  sulog.o: config.h
  
--- 346,371 ----
  id.lint: id.c
  	$(LINT) $(LINTFLAGS) id.c > id.lint
  
! useradd: useradd.o copydir.o mkrmdir.o libshadow.a
! 	$(CC) -o useradd $(LDFLAGS) useradd.o copydir.o mkrmdir.o \
! 		libshadow.a $(LIBS) $(NDIR)
  
! useradd.lint: useradd.c copydir.c mkrmdir.c
! 	$(LINT) $(LINTFLAGS) useradd.c copydir.c mkrmdir.c > useradd.lint
! 
! userdel: userdel.o copydir.o mkrmdir.o libshadow.a
! 	$(CC) -o userdel $(LDFLAGS) userdel.o copydir.o mkrmdir.o \
! 		libshadow.a $(LIBS) $(NDIR)
! 
! userdel.lint: userdel.c copydir.c mkrmdir.c
! 	$(LINT) $(LINTFLAGS) userdel.c copydir.c mkrmdir.c > userdel.lint
! 
! usermod: usermod.o copydir.o mkrmdir.o libshadow.a
! 	$(CC) -o usermod $(LDFLAGS) usermod.o copydir.o mkrmdir.o \
! 		libshadow.a $(LIBS) $(NDIR)
  
! usermod.lint: usermod.c copydir.c mkrmdir.c
! 	$(LINT) $(LINTFLAGS) usermod.c copydir.c mkrmdir.c > usermod.lint
  
  sulog.o: config.h
  
***************
*** 464,466 ****
--- 480,483 ----
  
  login.sh.9: $(DOCS) Makefile
  	shar -a $(DOCS) > login.sh.9
+ 
*** rel3/chpasswd.c	Thu Jun 13 21:27:57 1991
--- chpasswd.c	Mon Jun 10 10:14:05 1991
***************
*** 28,39 ****
  #endif
  
  #ifndef	lint
! static	char	sccsid[] = "@(#)chpasswd.c	3.3	09:07:09	5/28/91";
  #endif
  
  char	*Prog;
  
  extern	char	*pw_encrypt();
  
  /* 
   * If it weren't for the different structures and differences in how
--- 28,40 ----
  #endif
  
  #ifndef	lint
! static	char	sccsid[] = "@(#)chpasswd.c	3.4	08:57:30	6/10/91";
  #endif
  
  char	*Prog;
  
  extern	char	*pw_encrypt();
+ extern	char	*l64a();
  
  /* 
   * If it weren't for the different structures and differences in how
*** rel3/config.h	Thu Jun 13 21:28:42 1991
--- config.h	Thu Jun 13 10:06:41 1991
***************
*** 12,18 ****
  /*
   * Configuration file for login.
   *
!  *	@(#)config.h	3.8	11:11:17	6/7/91
   */
  
  /*
--- 12,18 ----
  /*
   * Configuration file for login.
   *
!  *	@(#)config.h	3.10	10:04:15	6/13/91
   */
  
  /*
***************
*** 223,228 ****
--- 223,236 ----
  #define	NDBM	/* */
  
  /*
+  * Enable RLOGIN to support the "-r" and "-h" options.
+  * If your /etc/utmp provides for a host name, enable UT_HOST.
+  */
+ 
+ #define RLOGIN
+ #undef UT_HOST
+ 
+ /*
   * Define file name for sulog.  If SULOG is not defined, there will be
   * no logging.  This is NOT a good idea ...  We also define other file
   * names.
***************
*** 238,243 ****
--- 246,253 ----
  #define	GRPFILE	"/etc/group"
  #define	OGRPFILE "/etc/group-"
  #define	NGRPFILE "/etc/ngroup"
+ #define	OGSHADOW "/etc/gshadow-"
+ #define	NGSHADOW "/etc/ngshadow"
  
  /*
   * Define PWDLOCK to be a locking semaphore for updating the password
***************
*** 247,252 ****
--- 257,263 ----
  #define	PWDLOCK	"/etc/passwd.lock"
  #define	GRPLOCK "/etc/group.lock"
  #define	SPWLOCK "/etc/shadow.lock"
+ #define	SGRPLOCK "/etc/gshadow.lock"
  
  /*
   * Define USE_SYSLOG if you want to have SYSLOG functions included
***************
*** 256,261 ****
--- 267,280 ----
  
  #define	USE_SYSLOG
  #undef	SULOGONLY
+ 
+ /*
+  * Select one of the following
+  */
+ 
+ #define DIR_XENIX	/* include <sys/ndir.h>, use (struct direct)	*/
+ /* #define DIR_BSD	/* include <ndir.h>, use (struct direct)	*/
+ /* #define DIR_SYSV	/* include <dirent.h>, use (struct dirent)	*/
  
  /*
   * Wierd stuff follows ...
*** /dev/null	Thu Jun 13 21:28:57 1991
--- copydir.c	Thu Jun 13 10:09:40 1991
***************
*** 0 ****
--- 1,372 ----
+ /*
+  * Copyright 1991, John F. Haugh II
+  * An unpublished work.
+  * All rights reserved.
+  *
+  * Permission is granted to copy and create derivative works for any
+  * non-commercial purpose, provided this copyright notice is preserved
+  * in all copies of source code, or included in human readable form
+  * and conspicuously displayed on all copies of object code or
+  * distribution media.
+  */
+ 
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include "config.h"
+ #ifdef DIR_XENIX
+ #include <sys/ndir.h>
+ #define DIRECT direct
+ #endif
+ #ifdef DIR_BSD
+ #include <ndir.h>
+ #define DIRECT direct
+ #endif
+ #ifdef DIR_SYSV
+ #include <dirent.h>
+ #define DIRECT dirent
+ #endif
+ #include <fcntl.h>
+ #include <stdio.h>
+ 
+ #ifndef lint
+ static	char	sccsid[] = "@(#)copydir.c	3.1	10:09:26	6/13/91";
+ #endif
+ 
+ #ifndef	S_ISDIR
+ #define	S_ISDIR(x)	(((x)&S_IFMT)==S_IFDIR)
+ #endif
+ #ifndef	S_ISREG
+ #define	S_ISREG(x)	(((x)&S_IFMT)==S_IFREG)
+ #endif
+ 
+ static	char	*src_orig;
+ static	char	*dst_orig;
+ 
+ struct	link_name {
+ 	int	ln_dev;
+ 	int	ln_ino;
+ 	int	ln_count;
+ 	char	*ln_name;
+ 	struct	link_name *ln_next;
+ };
+ static	struct	link_name *links;
+ 
+ /*
+  * remove_link - delete a link from the link list
+  */
+ 
+ void
+ remove_link (link)
+ struct	link_name *link;
+ {
+ 	struct link_name *lp;
+ 
+ 	if (links == link) {
+ 		links = link->ln_next;
+ 		free (link->ln_name);
+ 		free (link);
+ 		return;
+ 	}
+ 	for (lp = links;lp;lp = lp->ln_next)
+ 		if (lp->ln_next == link)
+ 			break;
+ 
+ 	if (! lp)
+ 		return;
+ 
+ 	lp->ln_next = lp->ln_next->ln_next;
+ 	free (link->ln_name);
+ 	free (link);
+ }
+ 
+ /*
+  * check_link - see if a file is really a link
+  */
+ 
+ struct link_name *
+ check_link (name, sb)
+ char	*name;
+ struct	stat	*sb;
+ {
+ 	struct	link_name *lp;
+ 	int	src_len;
+ 	int	dst_len;
+ 	int	name_len;
+ 	char	*malloc ();
+ 
+ 	for (lp = links;lp;lp = lp->ln_next)
+ 		if (lp->ln_dev == sb->st_dev && lp->ln_ino == sb->st_ino)
+ 			return lp;
+ 
+ 	if (sb->st_nlink == 1)
+ 		return 0;
+ 
+ 	lp = (struct link_name *) malloc (sizeof *lp);
+ 	src_len = strlen (src_orig);
+ 	dst_len = strlen (dst_orig);
+ 	name_len = strlen (name);
+ 	lp->ln_dev = sb->st_dev;
+ 	lp->ln_ino = sb->st_ino;
+ 	lp->ln_count = sb->st_nlink;
+ 	lp->ln_name = malloc (name_len - src_len + dst_len + 1);
+ 	sprintf (lp->ln_name, "%s%s", dst_orig, name + src_len);
+ 	lp->ln_next = links;
+ 	links = lp;
+ 
+ 	return 0;
+ }
+ 
+ /*
+  * copy_tree - copy files in a directory tree
+  *
+  *	copy_tree() walks a directory tree and copies ordinary files
+  *	as it goes.
+  */
+ 
+ int
+ copy_tree (src_root, dst_root, uid, gid)
+ char	*src_root;
+ char	*dst_root;
+ int	uid;
+ int	gid;
+ {
+ 	char	src_name[BUFSIZ];
+ 	char	dst_name[BUFSIZ];
+ 	char	buf[BUFSIZ];
+ 	int	ifd;
+ 	int	ofd;
+ 	int	err = 0;
+ 	int	cnt;
+ 	int	set_orig = 0;
+ 	struct	DIRECT	*ent;
+ 	struct	stat	sb;
+ 	struct	link_name *lp;
+ 	DIR	*dir;
+ 
+ 	/*
+ 	 * Make certain both directories exist.  This routine is called
+ 	 * after the home directory is created, or recursively after the
+ 	 * target is created.  It assumes the target directory exists.
+ 	 */
+ 
+ 	if (access (src_root, 0) != 0 || access (dst_root, 0) != 0)
+ 		return -1;
+ 
+ 	/*
+ 	 * Open the source directory and read each entry.  Every file
+ 	 * entry in the directory is copied with the UID and GID set
+ 	 * to the provided values.  As an added security feature only
+ 	 * regular files (and directories ...) are copied, and no file
+ 	 * is made set-ID.
+ 	 */
+ 
+ 	if (! (dir = opendir (src_root)))
+ 		return -1;
+ 
+ 	if (src_orig == 0) {
+ 		src_orig = src_root;
+ 		dst_orig = dst_root;
+ 		set_orig++;
+ 	}
+ 	while (ent = readdir (dir)) {
+ 
+ 		/*
+ 		 * Skip the "." and ".." entries
+ 		 */
+ 
+ 		if (strcmp (ent->d_name, ".") == 0 ||
+ 				strcmp (ent->d_name, "..") == 0)
+ 			continue;
+ 
+ 		/*
+ 		 * Make the filename for both the source and the
+ 		 * destination files.
+ 		 */
+ 
+ 		if (strlen (src_root) + strlen (ent->d_name) + 2 > BUFSIZ) {
+ 			err++;
+ 			break;
+ 		}
+ 		sprintf (src_name, "%s/%s", src_root, ent->d_name);
+ 
+ 		if (strlen (dst_root) + strlen (ent->d_name) + 2 > BUFSIZ) {
+ 			err++;
+ 			break;
+ 		}
+ 		sprintf (dst_name, "%s/%s", dst_root, ent->d_name);
+ 
+ 		if (stat (src_name, &sb) == -1)
+ 			continue;
+ 
+ 		if (S_ISDIR (sb.st_mode)) {
+ 
+ 			/*
+ 			 * Create a new target directory, make it owned by
+ 			 * the user and then recursively copy that directory.
+ 			 */
+ 
+ 			mkdir (dst_name, sb.st_mode & 0777);
+ 			chown (dst_name, uid == -1 ? sb.st_uid:uid,
+ 				gid == -1 ? sb.st_gid:gid);
+ 
+ 			if (copy_tree (src_name, dst_name, uid, gid)) {
+ 				err++;
+ 				break;
+ 			}
+ 			continue;
+ 		}
+ 
+ 		/*
+ 		 * See if this is a previously copied link
+ 		 */
+ 
+ 		if (lp = check_link (src_name, &sb)) {
+ 			if (link (lp->ln_name, dst_name)) {
+ 				err++;
+ 				break;
+ 			}
+ 			if (unlink (src_name)) {
+ 				err++;
+ 				break;
+ 			}
+ 			if (--lp->ln_count <= 0)
+ 				remove_link (lp);
+ 
+ 			continue;
+ 		}
+ 
+ 		/*
+ 		 * Deal with FIFOs and special files.  The user really
+ 		 * shouldn't have any of these, but it seems like it
+ 		 * would be nice to copy everything ...
+ 		 */
+ 
+ 		if (! S_ISREG (sb.st_mode)) {
+ 			if (mknod (dst_name, sb.st_mode & ~07777, sb.st_rdev) ||
+ 				chown (dst_name, uid == -1 ? sb.st_uid:uid,
+ 					gid == -1 ? sb.st_gid:gid) ||
+ 					chmod (dst_name, sb.st_mode & 07777)) {
+ 				err++;
+ 				break;
+ 			}
+ 			continue;
+ 		}
+ 
+ 		/*
+ 		 * Create the new file and copy the contents.  The new
+ 		 * file will be owned by the provided UID and GID values.
+ 		 */
+ 
+ 		if ((ifd = open (src_name, O_RDONLY)) < 0) {
+ 			err++;
+ 			break;
+ 		}
+ 		if ((ofd = open (dst_name, O_WRONLY|O_CREAT, 0)) < 0 ||
+ 			chown (dst_name, uid == -1 ? sb.st_uid:uid,
+ 					gid == -1 ? sb.st_gid:gid) ||
+ 				chmod (dst_name, sb.st_mode & 07777)) {
+ 			close (ifd);
+ 			err++;
+ 			break;
+ 		}
+ 		while ((cnt = read (ifd, buf, sizeof buf)) > 0) {
+ 			if (write (ofd, buf, cnt) != cnt) {
+ 				cnt = -1;
+ 				break;
+ 			}
+ 		}
+ 		close (ifd);
+ 		close (ofd);
+ 
+ 		if (cnt == -1) {
+ 			err++;
+ 			break;
+ 		}
+ 	}
+ 	closedir (dir);
+ 
+ 	if (set_orig) {
+ 		src_orig = 0;
+ 		dst_orig = 0;
+ 	}
+ 	return err ? -1:0;
+ }
+ 
+ /*
+  * remove_tree - remove files in a directory tree
+  *
+  *	remove_tree() walks a directory tree and deletes all the files
+  *	and directories.
+  */
+ 
+ int
+ remove_tree (root)
+ char	*root;
+ {
+ 	char	new_name[BUFSIZ];
+ 	int	err = 0;
+ 	struct	DIRECT	*ent;
+ 	struct	stat	sb;
+ 	DIR	*dir;
+ 
+ 	/*
+ 	 * Make certain the directory exists.
+ 	 */
+ 
+ 	if (access (root, 0) != 0)
+ 		return -1;
+ 
+ 	/*
+ 	 * Open the source directory and read each entry.  Every file
+ 	 * entry in the directory is copied with the UID and GID set
+ 	 * to the provided values.  As an added security feature only
+ 	 * regular files (and directories ...) are copied, and no file
+ 	 * is made set-ID.
+ 	 */
+ 
+ 	dir = opendir (root);
+ 
+ 	while (ent = readdir (dir)) {
+ 
+ 		/*
+ 		 * Skip the "." and ".." entries
+ 		 */
+ 
+ 		if (strcmp (ent->d_name, ".") == 0 ||
+ 				strcmp (ent->d_name, "..") == 0)
+ 			continue;
+ 
+ 		/*
+ 		 * Make the filename for the current entry.
+ 		 */
+ 
+ 		if (strlen (root) + strlen (ent->d_name) + 2 > BUFSIZ) {
+ 			err++;
+ 			break;
+ 		}
+ 		sprintf (new_name, "%s/%s", root, ent->d_name);
+ 		if (stat (new_name, &sb) == -1)
+ 			continue;
+ 
+ 		if (S_ISDIR (sb.st_mode)) {
+ 
+ 			/*
+ 			 * Recursively delete this directory.
+ 			 */
+ 
+ 			if (remove_tree (new_name)) {
+ 				err++;
+ 				break;
+ 			}
+ 			if (rmdir (new_name)) {
+ 				err++;
+ 				break;
+ 			}
+ 			continue;
+ 		}
+ 		unlink (new_name);
+ 	}
+ 	closedir (dir);
+ 
+ 	return err ? -1:0;
+ }
*** rel3/getpass.c	Thu Jun 13 21:27:59 1991
--- getpass.c	Mon Jun 10 10:02:54 1991
***************
*** 9,15 ****
   * distribution media.
   */
  
! #include <sys/signal.h>
  #include <stdio.h>
  #include "config.h"
  
--- 9,15 ----
   * distribution media.
   */
  
! #include <signal.h>
  #include <stdio.h>
  #include "config.h"
  
***************
*** 22,28 ****
  #endif
  
  #ifndef	lint
! static	char	sccsid[] = "@(#)getpass.c	3.3	09:09:36	5/28/91";
  #endif
  
  /*
--- 22,28 ----
  #endif
  
  #ifndef	lint
! static	char	sccsid[] = "@(#)getpass.c	3.4	08:59:38	6/10/91";
  #endif
  
  /*
*** rel3/lmain.c	Thu Jun 13 21:28:01 1991
--- lmain.c	Thu Jun 13 10:06:44 1991
***************
*** 44,52 ****
  #endif
  
  #ifndef	lint
! static	char	sccsid[] = "@(#)lmain.c	3.5	09:07:32	5/28/91";
  #endif
  
  #ifndef	ERASECHAR
  #define	ERASECHAR	'\b'		/* backspace */
  #endif
--- 44,55 ----
  #endif
  
  #ifndef	lint
! static	char	sccsid[] = "@(#)lmain.c	3.10	10:04:50	6/13/91";
  #endif
  
+ 					/* danger - side effects */
+ #define STRFCPY(A,B)	strncpy((A), (B), sizeof(A)), *((A)+sizeof(A)-1) = '\0'
+ 
  #ifndef	ERASECHAR
  #define	ERASECHAR	'\b'		/* backspace */
  #endif
***************
*** 55,62 ****
  #define	KILLCHAR	'\025'		/* control U */
  #endif
  
! #ifdef	UT_HOST
! char	host[BUFSIZ];
  #endif
  #ifdef	HUSHLOGIN
  int	hushed;
--- 58,66 ----
  #define	KILLCHAR	'\025'		/* control U */
  #endif
  
! #ifdef	RLOGIN
! char	host[128];
! char	term[128] = "TERM=";
  #endif
  #ifdef	HUSHLOGIN
  int	hushed;
***************
*** 69,74 ****
--- 73,79 ----
  int	rflg;
  int	fflg;
  int	hflg;
+ int	preauth_flag;
  #ifndef	BSD
  struct	termio	termio;
  #endif
***************
*** 114,120 ****
  
  #ifdef	TZ
  FILE	*tzfile;
! char	tzbuf[32] = TZ;
  #endif
  
  #ifndef	ALARM
--- 119,125 ----
  
  #ifdef	TZ
  FILE	*tzfile;
! char	tzbuf[BUFSIZ] = TZ;
  #endif
  
  #ifndef	ALARM
***************
*** 153,172 ****
  
  /*
   * usage - print login command usage and exit
   */
  
  usage ()
  {
  	fprintf (stderr, "usage: login [ -p ] [ name ]\n");
! #ifdef	UT_HOST
! 	fprintf (stderr, "       login -r name\n");
! 	fprintf (stderr, "       login [ -p ] -f name [ -h host ]\n");
  #else
  	fprintf (stderr, "       login [ -p ] -f name\n");
! #endif
  	exit (1);
  }
  
  /*
   * login - create a new login session for a user
   *
--- 158,224 ----
  
  /*
   * usage - print login command usage and exit
+  *
+  * login [ name ]
+  * login -r hostname	(for rlogind)
+  * login -h hostname	(for telnetd, etc.)
+  * login -f name	(for pre-authenticated login: datakit, xterm, etc.)
   */
  
  usage ()
  {
  	fprintf (stderr, "usage: login [ -p ] [ name ]\n");
! #ifdef	RLOGIN
! #ifdef	LAI_TCP
! 	fprintf (stderr, "       login -r rem_host rem_name name\n");
  #else
+ 	fprintf (stderr, "       login [ -p ] -r name\n");
+ #endif	/* LAI_TCP */
+ 	fprintf (stderr, "       login [ -p ] [ -f name ] -h host\n");
+ #else
  	fprintf (stderr, "       login [ -p ] -f name\n");
! #endif	/* RLOGIN */
  	exit (1);
  }
  
+ #ifdef	RLOGIN
+ rlogin (host, name, namelen)
+ char	*host;
+ char	*name;
+ int	namelen;
+ {
+ 	struct	passwd	*pwd;
+ 	char	remote_name[32];
+ 	char	*cp;
+ 
+ 	get_remote_string (remote_name, sizeof remote_name);
+ 	get_remote_string (name, namelen);
+ 	get_remote_string (term + 5, sizeof term - 5);
+ 	if (cp = strchr (term, '/'))
+ 		*cp = '\0';
+ 
+ 	if (! (pwd = getpwnam (name)))
+ 		return 0;
+ 
+ 	return ruserok (host, pwd->pw_uid == 0, remote_name, name);
+ }
+ 
+ get_remote_string (buf, size)
+ char	*buf;
+ int	size;
+ {
+ 	for (;;) {
+ 		if (read (0, buf, 1) != 1)
+   			exit (1);
+ 		if (*buf == '\0')
+ 			return;
+ 		if (--size > 0)
+ 			++buf;
+ 	}
+ 	/*NOTREACHED*/
+ }
+ #endif
+ 
  /*
   * login - create a new login session for a user
   *
***************
*** 223,230 ****
  	 */
  
  	checkutmp (argc > 1 && argv[1][0] != '-');
! 	strncpy (tty, utent.ut_line, sizeof tty);
! 	tty[sizeof tty - 1] = '\0';
  
  	if (Prog = strrchr (argv[0], '/'))
  		Prog++;
--- 275,281 ----
  	 */
  
  	checkutmp (argc > 1 && argv[1][0] != '-');
! 	STRFCPY (tty, utent.ut_line);
  
  	if (Prog = strrchr (argv[0], '/'))
  		Prog++;
***************
*** 231,237 ****
  	else
  		Prog = argv[0];
  
! #ifdef	UT_HOST
  	while ((flag = getopt (argc, argv, "pr:f:h:")) != EOF)
  #else
  	while ((flag = getopt (argc, argv, "pf:")) != EOF)
--- 282,310 ----
  	else
  		Prog = argv[0];
  
! #ifdef LAI_TCP /*{*/
! 	/*
! 	 * SCO/Lachman rlogind calls:
! 	 *     /bin/login -r rem_host rem_name local_name"
! 	 */
! 	if ( argc == 5 && strcmp(argv[1], "-r") == 0 ) {
! 		char rem_name[16];
! 		int root_user;
! 
! 		STRFCPY(host, argv[2]);
! 		STRFCPY(rem_name, argv[3]);
! 		STRFCPY(name, argv[4]);
! 
! 		root_user = ((pwd = getpwnam(name)) && pwd->pw_uid == 0);
! 		preauth_flag = ! ruserok(host, root_user, rem_name, name);
! 		pflg++;		/* in case SCO ever fixes rlogind */
! 		rflg++;
! 		argc = 1;
! 		argv[1] = NULL;
! 	}
! #endif /*}LAI_TCP*/
! 
! #ifdef	RLOGIN
  	while ((flag = getopt (argc, argv, "pr:f:h:")) != EOF)
  #else
  	while ((flag = getopt (argc, argv, "pf:")) != EOF)
***************
*** 240,286 ****
  		switch (flag) {
  			case 'p': pflg++;
  				break;
! 			case 'f': fflg++;
! 				strncpy (name, optarg, sizeof name);
  				break;
  #ifdef	UT_HOST
! 			case 'r': rflg++;
! 				strncpy (name, optarg, sizeof name);
  				break;
! 			case 'h': hflg++;
! 				strncpy (host, optarg, sizeof host);
! 				strncpy (utmp.ut_host, host,
! 							sizeof utmp.ut_host);
  				break;
! #endif
  			default:
  				usage ();
  		}
  	}
  
  	/*
! 	 * The -r option is not valid with any other flags
  	 */
  
! 	if (rflg && (hflg || fflg || pflg))
  		usage ();
- 
- #ifdef	USE_SYSLOG
- 	openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
  #endif
  
  	/*
! 	 * The -r and -f flags both require the real UID to be
! 	 * zero.  No authentication may be required for these
! 	 * flags, so the user must already be root.
  	 */
  
  	if ((rflg || fflg) && getuid () != 0) {
  #ifdef	USE_SYSLOG
! 		closelog ();
  #endif
! 		exit (1);		/* only root can use -r or -f */
! 	}
  	if (! isatty (0) || ! isatty (1) || ! isatty (2)) {
  #ifdef	USE_SYSLOG
  		closelog ();
--- 313,369 ----
  		switch (flag) {
  			case 'p': pflg++;
  				break;
! 			case 'f':
! 				fflg++;
! 				preauth_flag++;
! 				STRFCPY (name, optarg);
  				break;
+ #ifdef	RLOGIN
+ 			case 'r':
+ 				rflg++;
+ 				STRFCPY (host, optarg);
  #ifdef	UT_HOST
! 				STRFCPY (utent.ut_host, optarg);
! #endif	/*UT_HOST*/
! 				if (rlogin (host, name, sizeof name))
! 					preauth_flag++;
! 
  				break;
! 			case 'h':
! 				hflg++;
! 				STRFCPY (host, optarg);
! #ifdef	UT_HOST
! 				STRFCPY (utent.ut_host, optarg);
! #endif	/*UT_HOST*/
  				break;
! #endif	/*RLOGIN*/
  			default:
  				usage ();
  		}
  	}
  
+ #ifdef	RLOGIN
  	/*
! 	 * Neither -h nor -f should be combined with -r.
  	 */
  
! 	if (rflg && (hflg || fflg))
  		usage ();
  #endif
  
  	/*
! 	 * Allow authentication bypass only if real UID is zero.
  	 */
  
  	if ((rflg || fflg) && getuid () != 0) {
+ 		fprintf(stderr, "%s: permission denied\n", Prog);
+ 		exit (1);
+ 	}
+ 
  #ifdef	USE_SYSLOG
! 	openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
  #endif
! 
  	if (! isatty (0) || ! isatty (1) || ! isatty (2)) {
  #ifdef	USE_SYSLOG
  		closelog ();
***************
*** 312,319 ****
  		while (*envp)		/* add inherited environment, */
  			addenv (*envp++); /* some variables change later */
  
  #ifdef	TZ
! 	if (! pflg) {
  		if (tzbuf[0] == '/') {
  			if ((tzfile = fopen (tzbuf, "r")) != (FILE *) 0) {
  				if (fgets (tzbuf, sizeof tzbuf, tzfile)) {
--- 395,406 ----
  		while (*envp)		/* add inherited environment, */
  			addenv (*envp++); /* some variables change later */
  
+ #ifdef	RLOGIN
+ 	if (term[5] != '\0')		/* see if anything after "TERM=" */
+ 		addenv (term);
+ #endif
  #ifdef	TZ
! 	if (! pflg || ! getenv("TZ")) {
  		if (tzbuf[0] == '/') {
  			if ((tzfile = fopen (tzbuf, "r")) != (FILE *) 0) {
  				if (fgets (tzbuf, sizeof tzbuf, tzfile)) {
***************
*** 328,342 ****
  	}
  #endif	/* TZ */
  #ifdef	HZ
! 	if (! pflg)
  		addenv (HZ);		/* set the default $HZ, if one */
  #endif	/* HZ */
- 	if (optind < argc) {	/* now set command line variables */
- 		if (optind + 1 < argc)
- 			setenv (argc - optind - 1, &argv[optind + 1]);
  
! 		(void) strncpy (name, argv[optind], sizeof name);
  	}
  top:
  	(void) alarm (ALARM);		/* only allow ALARM sec. for login */
  
--- 415,434 ----
  	}
  #endif	/* TZ */
  #ifdef	HZ
! 	if (! pflg || ! getenv("HZ"))
  		addenv (HZ);		/* set the default $HZ, if one */
  #endif	/* HZ */
  
! 	if (optind < argc) {		/* get the user name */
! 		if (rflg || fflg)
! 			usage ();
! 
! 		STRFCPY (name, argv[optind]);
! 		++optind;
  	}
+ 	if (optind < argc)		/* now set command line variables */
+ 		    setenv (argc - optind, &argv[optind]);
+ 
  top:
  	(void) alarm (ALARM);		/* only allow ALARM sec. for login */
  
***************
*** 351,357 ****
  #endif
  				exit (1);
  			}
! 			rflg = fflg = 0;
  			login (name);
  			continue;
  		}
--- 443,451 ----
  #endif
  				exit (1);
  			}
! #ifdef	RLOGIN
! 			preauth_flag = 0;
! #endif
  			login (name);
  			continue;
  		}
***************
*** 373,385 ****
  		} else
  			failed = 1;	/* will never pass validation */
  
  		/*
  		 * The -r and -f flags provide a name which has already
  		 * been authenticated by some server.
  		 */
  
! 		if (pwent.pw_name && (rflg || fflg))
  			goto have_name;
  
  	/*
  	 * Get the user's password.  One will only be prompted for
--- 467,481 ----
  		} else
  			failed = 1;	/* will never pass validation */
  
+ #ifdef	RLOGIN
  		/*
  		 * The -r and -f flags provide a name which has already
  		 * been authenticated by some server.
  		 */
  
! 		if (pwent.pw_name && preauth_flag)
  			goto have_name;
+ #endif	/*RLOGIN*/
  
  	/*
  	 * Get the user's password.  One will only be prompted for
***************
*** 393,399 ****
  			continue;
  
  		if (cp)
! 			strncpy (pass, cp, sizeof pass);
  
  		if (! valid (pass, &pwent)) { /* check encrypted passwords */
  #ifdef	USE_SYSLOG
--- 489,495 ----
  			continue;
  
  		if (cp)
! 			STRFCPY (pass, cp);
  
  		if (! valid (pass, &pwent)) { /* check encrypted passwords */
  #ifdef	USE_SYSLOG
***************
*** 467,472 ****
--- 563,569 ----
  			break;
  
  		puts ("Login incorrect");
+ #ifdef	RLOGIN
  		if (rflg || fflg) {
  #ifdef	USE_SYSLOG
  			closelog ();
***************
*** 473,478 ****
--- 570,576 ----
  #endif
  			exit (1);
  		}
+ #endif	/*RLOGIN*/
  #ifdef	FAILLOG
  		if (pwent.pw_name)	/* don't log non-existent users */
  			failure (pwent.pw_uid, tty, &faillog);
***************
*** 481,493 ****
  		failent = utent;
  
  		if (pwent.pw_name)
! 			strncpy (failent.ut_name,
! 				pwent.pw_name, sizeof failent.ut_name);
  		else
  #ifdef	UNKNOWNS
! 			strcpy (failent.ut_name, name);
  #else	/* !UNKNOWNS */
! 			strcpy (failent.ut_name, "UNKNOWN");
  #endif	/* UNKNOWNS */
  		time (&failent.ut_time);
  		failent.ut_type = USER_PROCESS;
--- 579,590 ----
  		failent = utent;
  
  		if (pwent.pw_name)
! 			STRFCPY (failent.ut_name, pwent.pw_name);
  		else
  #ifdef	UNKNOWNS
! 			STRFCPY (failent.ut_name, name);
  #else	/* !UNKNOWNS */
! 			STRFCPY (failent.ut_name, "UNKNOWN");
  #endif	/* UNKNOWNS */
  		time (&failent.ut_time);
  		failent.ut_type = USER_PROCESS;
***************
*** 575,581 ****
--- 672,680 ----
  	hushed = access (hush, 0) == 0;
  #endif	/* HUSHLOGIN */
  #ifdef	MOTD
+ #ifdef	HUSHLOGIN
  	if (! hushed)
+ #endif
  		motd ();		/* print the message of the day */
  #endif
  #ifdef	FAILLOG
***************
*** 583,603 ****
  		failprint (pwent.pw_uid, &faillog);
  #endif	/* FAILLOG */
  #ifdef	LASTLOG
! 	if (lastlog.ll_time != 0 && ! hushed)
! 		printf ("Last login: %.19s on %s\n",
! 			ctime (&lastlog.ll_time), lastlog.ll_line);
  #endif	/* LASTLOG */
  #ifdef	AGING
  	if (! hushed)
  		agecheck (&pwent, spwd);
  #endif	/* AGING */
  #ifdef	MAILCHECK
  	if (! hushed)
  		mailcheck ();		/* report on the status of mail */
  #endif	/* MAILCHECK */
  #ifdef	TTYTYPE
! 	if (! pflg)
! 		ttytype (tty);
  #endif	/* TTYTYPE */
  	signal (SIGINT, SIG_DFL);	/* default interrupt signal */
  	signal (SIGQUIT, SIG_DFL);	/* default quit signal */
--- 682,709 ----
  		failprint (pwent.pw_uid, &faillog);
  #endif	/* FAILLOG */
  #ifdef	LASTLOG
! #ifdef	HUSHLOGIN
! 	if (! hushed)
! #endif
! 		if (lastlog.ll_time != 0)
! 			printf ("Last login: %.19s on %s\n",
! 				ctime (&lastlog.ll_time), lastlog.ll_line);
  #endif	/* LASTLOG */
  #ifdef	AGING
+ #ifdef	HUSHLOGIN
  	if (! hushed)
+ #endif
  		agecheck (&pwent, spwd);
  #endif	/* AGING */
  #ifdef	MAILCHECK
+ #ifdef	HUSHLOGIN
  	if (! hushed)
+ #endif
  		mailcheck ();		/* report on the status of mail */
  #endif	/* MAILCHECK */
  #ifdef	TTYTYPE
! 	if (! getenv("TERM"))
!   		ttytype (tty);
  #endif	/* TTYTYPE */
  	signal (SIGINT, SIG_DFL);	/* default interrupt signal */
  	signal (SIGQUIT, SIG_DFL);	/* default quit signal */
*** /dev/null	Thu Jun 13 21:28:57 1991
--- mkrmdir.c	Thu Jun 13 10:09:40 1991
***************
*** 0 ****
--- 1,76 ----
+ /*
+  * Copyright 1991, John F. Haugh II
+  * An unpublished work.
+  * All rights reserved.
+  *
+  * Permission is granted to copy and create derivative works for any
+  * non-commercial purpose, provided this copyright notice is preserved
+  * in all copies of source code, or included in human readable form
+  * and conspicuously displayed on all copies of object code or
+  * distribution media.
+  */
+ 
+ #include <fcntl.h>
+ #include "config.h"
+ 
+ #ifndef lint
+ static	char	sccsid[] = "@(#)mkrmdir.c	3.1	10:09:21	6/13/91";
+ #endif
+ 
+ #ifdef	NEED_MKDIR
+ /*
+  * mkdir - create a directory
+  *
+  *	mkdir is provided for systems which do not include the mkdir()
+  *	system call.
+  */
+ 
+ int
+ mkdir (dir, mode)
+ char	*dir;
+ int	mode;
+ {
+ 	int	status;
+ 
+ 	if (fork ()) {
+ 		while (wait (&status) != -1)
+ 			;
+ 
+ 		return status >> 8;
+ 	}
+ #ifdef	USE_SYSLOG
+ 	closelog ();
+ #endif
+ 	close (2);
+ 	open ("/dev/null", O_WRONLY);
+ 	umask (0777 & ~ mode);
+ 	execl ("/bin/mkdir", "mkdir", dir, 0);
+ 	_exit (128);
+ }
+ #endif
+ #ifdef	NEED_RMDIR
+ /*
+  * rmdir - remove a directory
+  *
+  *	rmdir is provided for systems which do not include the rmdir()
+  *	system call.
+  */
+ 
+ int
+ rmdir (dir)
+ char	*dir;
+ {
+ 	int	status;
+ 
+ 	if (fork ()) {
+ 		while (wait (&status) != -1)
+ 			;
+ 
+ 		return status >> 8;
+ 	}
+ 	close (2);
+ 	open ("/dev/null", O_WRONLY);
+ 	execl ("/bin/rmdir", "rmdir", dir, 0);
+ 	_exit (128);
+ }
+ #endif
*** rel3/useradd.c	Thu Jun 13 21:28:44 1991
--- useradd.c	Thu Jun 13 10:06:45 1991
***************
*** 10,16 ****
   */
  
  #ifndef lint
! static	char	sccsid[] = "@(#)useradd.c	3.1	11:08:18	6/7/91";
  #endif
  
  #include <sys/types.h>
--- 10,16 ----
   */
  
  #ifndef lint
! static	char	sccsid[] = "@(#)useradd.c	3.2	20:15:10	6/11/91";
  #endif
  
  #include <sys/types.h>
***************
*** 43,48 ****
--- 43,49 ----
  gid_t	def_group;
  char	def_home[BUFSIZ];
  char	def_shell[BUFSIZ];
+ char	def_template[BUFSIZ] = "/etc/skel";
  long	def_inactive;
  long	def_expire;
  char	def_file[] = "/etc/default/useradd";
***************
*** 51,56 ****
--- 52,59 ----
  #define	NGROUPS_MAX	64
  #endif
  
+ #define	VALID(s)	(strcspn (s, ":\n") == strlen (s))
+ 
  char	user_name[BUFSIZ];
  uid_t	user_id;
  gid_t	user_gid;
***************
*** 141,177 ****
  	0,	31,	59,	90,	120,	151,	/* JAN - JUN */
  	181,	212,	243,	273,	304,	334 };	/* JUL - DEC */
  
- #ifdef	NEED_MKDIR
- /*
-  * mkdir - create a directory
-  *
-  *	mkdir is provided for systems which do not include the mkdir()
-  *	system call.
-  */
- 
- int
- mkdir (dir, mode)
- char	*dir;
- int	mode;
- {
- 	int	status;
- 
- 	if (fork ()) {
- 		while (wait (&status) != -1)
- 			;
- 
- 		return status >> 8;
- 	}
- #ifdef	USE_SYSLOG
- 	closelog ();
- #endif
- 	close (2);
- 	open ("/dev/null", O_WRONLY);
- 	umask (0777 & ~ mode);
- 	execl ("/bin/mkdir", "mkdir", dir, 0);
- 	_exit (128);
- }
- #endif
  #ifdef	NEED_RENAME
  /*
   * rename - rename a file to another name
--- 144,149 ----
***************
*** 927,932 ****
--- 899,910 ----
  	while ((arg = getopt (argc, argv, "Du:og:G:d:s:c:mk:f:e:b:")) != EOF) {
  		switch (arg) {
  			case 'b':
+ 				if (! VALID (optarg)) {
+ 					fprintf (stderr,
+ 						"%s: invalid field `%s'\n",
+ 						Prog, optarg);
+ 					exit (3);
+ 				}
  				bflg++;
  				if (! Dflg)
  					usage ();
***************
*** 934,943 ****
--- 912,933 ----
  				strncpy (def_home, optarg, BUFSIZ);
  				break;
  			case 'c':
+ 				if (! VALID (optarg)) {
+ 					fprintf (stderr,
+ 						"%s: invalid field `%s'\n",
+ 						Prog, optarg);
+ 					exit (3);
+ 				}
  				cflg++;
  				strncpy (user_comment, optarg, BUFSIZ);
  				break;
  			case 'd':
+ 				if (! VALID (optarg)) {
+ 					fprintf (stderr,
+ 						"%s: invalid field `%s'\n",
+ 						Prog, optarg);
+ 					exit (3);
+ 				}
  				dflg++;
  				strncpy (user_home, optarg, BUFSIZ);
  				break;
***************
*** 987,992 ****
--- 977,983 ----
  				if (! mflg)
  					usage ();
  
+ 				strncpy (def_template, optarg, BUFSIZ);
  				kflg++;
  				break;
  			case 'm':
***************
*** 999,1004 ****
--- 990,1001 ----
  				oflg++;
  				break;
  			case 's':
+ 				if (! VALID (optarg)) {
+ 					fprintf (stderr,
+ 						"%s: invalid field `%s'\n",
+ 						Prog, optarg);
+ 					exit (3);
+ 				}
  				sflg++;
  				strncpy (user_shell, optarg, BUFSIZ);
  				break;
***************
*** 1086,1096 ****
  		exit (1);
  	}
  	if (! spw_lock ()) {
! 		fprintf ("%s: cannot lock shadow password file\n", Prog);
  		exit (1);
  	}
  	if (! spw_open (O_RDWR)) {
! 		fprintf ("%s: cannot open shadow password file\n", Prog);
  		exit (1);
  	}
  }
--- 1083,1093 ----
  		exit (1);
  	}
  	if (! spw_lock ()) {
! 		fprintf (stderr, "%s: cannot lock shadow password file\n", Prog);
  		exit (1);
  	}
  	if (! spw_open (O_RDWR)) {
! 		fprintf (stderr, "%s: cannot open shadow password file\n", Prog);
  		exit (1);
  	}
  }
***************
*** 1236,1244 ****
  
  	usr_update ();
  
! 	if (mflg)
  		create_home ();
! 
  	close_files ();
  	exit (0);
  	/*NOTREACHED*/
--- 1233,1242 ----
  
  	usr_update ();
  
! 	if (mflg) {
  		create_home ();
! 		copy_tree (def_template, user_home, user_id, user_gid);
! 	}
  	close_files ();
  	exit (0);
  	/*NOTREACHED*/
*** rel3/userdel.c	Thu Jun 13 21:28:45 1991
--- userdel.c	Thu Jun 13 21:16:54 1991
***************
*** 10,16 ****
   */
  
  #ifndef lint
! static	char	sccsid[] = "@(#)userdel.c	3.1	11:08:47	6/7/91";
  #endif
  
  #include <sys/types.h>
--- 10,16 ----
   */
  
  #ifndef lint
! static	char	sccsid[] = "@(#)userdel.c	3.5	20:53:04	6/13/91";
  #endif
  
  #include <sys/types.h>
***************
*** 90,123 ****
  
  extern	char	*malloc();
  
- #ifdef	NEED_RMDIR
  /*
-  * rmdir - remove a directory
-  *
-  *	rmdir is provided for systems which do not include the rmdir()
-  *	system call.
-  */
- 
- int
- rmdir (dir)
- char	*dir;
- {
- 	int	status;
- 
- 	if (fork ()) {
- 		while (wait (&status) != -1)
- 			;
- 
- 		return status >> 8;
- 	}
- 	close (2);
- 	open ("/dev/null", O_WRONLY);
- 	execl ("/bin/rmdir", "rmdir", dir, 0);
- 	_exit (128);
- }
- #endif
- 
- /*
   * del_list - delete a member from a list of group members
   *
   *	the array of member names is searched for the old member
--- 90,96 ----
***************
*** 175,181 ****
  usage ()
  {
  	fprintf (stderr, "usage: userdel [-r] name\n");
! 	exit (1);
  }
  
  /*
--- 148,154 ----
  usage ()
  {
  	fprintf (stderr, "usage: userdel [-r] name\n");
! 	exit (2);
  }
  
  /*
***************
*** 224,239 ****
  				Prog);
  			exit (1);
  		}
- #ifdef	NDBM
  		/*
  		 * Update the DBM group file with the new entry as well.
  		 */
  
  		if (! gr_dbm_update (grp)) {
  			fprintf (stderr, "%s: cannot update dbm group entry\n",
  				Prog);
  			exit (1);
  		}
  #endif
  	}
  
--- 197,216 ----
  				Prog);
  			exit (1);
  		}
  		/*
  		 * Update the DBM group file with the new entry as well.
  		 */
  
+ #ifdef	NDBM
  		if (! gr_dbm_update (grp)) {
  			fprintf (stderr, "%s: cannot update dbm group entry\n",
  				Prog);
  			exit (1);
  		}
+ #endif	/* NDBM */
+ #ifdef	USE_SYSLOG
+ 		syslog (LOG_INFO, "delete `%s' from group `%s'\n",
+ 			user_name, grp->gr_name);
  #endif
  	}
  
***************
*** 287,292 ****
--- 264,273 ----
  			exit (1);
  		}
  #endif
+ #ifdef	USE_SYSLOG
+ 		syslog (LOG_INFO, "delete `%s' from shadow group `%s'\n",
+ 			user_name, grp->gr_name);
+ #endif
  	}
  #endif
  }
***************
*** 312,318 ****
  	if (! gr_close ()) {
  		fprintf (stderr, "%s: cannot rewrite group file\n",
  			Prog);
! 		exit (1);
  	}
  	(void) gr_unlock ();
  #ifdef	SHADOWGRP
--- 293,299 ----
  	if (! gr_close ()) {
  		fprintf (stderr, "%s: cannot rewrite group file\n",
  			Prog);
! 		exit (10);
  	}
  	(void) gr_unlock ();
  #ifdef	SHADOWGRP
***************
*** 319,325 ****
  	if (! sgr_close ()) {
  		fprintf (stderr, "%s: cannot rewrite shadow group file\n",
  			Prog);
! 		exit (1);
  	}
  	(void) sgr_unlock ();
  #endif
--- 300,306 ----
  	if (! sgr_close ()) {
  		fprintf (stderr, "%s: cannot rewrite shadow group file\n",
  			Prog);
! 		exit (10);
  	}
  	(void) sgr_unlock ();
  #endif
***************
*** 343,353 ****
  		exit (1);
  	}
  	if (! spw_lock ()) {
! 		fprintf ("%s: cannot lock shadow password file\n", Prog);
  		exit (1);
  	}
  	if (! spw_open (O_RDWR)) {
! 		fprintf ("%s: cannot open shadow password file\n", Prog);
  		exit (1);
  	}
  	if (! gr_lock ()) {
--- 324,334 ----
  		exit (1);
  	}
  	if (! spw_lock ()) {
! 		fprintf (stderr, "%s: cannot lock shadow password file\n", Prog);
  		exit (1);
  	}
  	if (! spw_open (O_RDWR)) {
! 		fprintf (stderr, "%s: cannot open shadow password file\n", Prog);
  		exit (1);
  	}
  	if (! gr_lock ()) {
***************
*** 414,419 ****
--- 395,403 ----
  		fprintf (stderr, "%s: error deleting shadow passwd dbm entry\n",
  			Prog);
  #endif
+ #ifdef	USE_SYSLOG
+ 	syslog (LOG_INFO, "delete user `%s'\n", user_name);
+ #endif
  }
  
  /*
***************
*** 426,431 ****
--- 410,416 ----
  {
  	struct	passwd	*pwd;
  	int	arg;
+ 	int	errors = 0;
  	extern	int	optind;
  	extern	char	*optarg;
  
***************
*** 475,481 ****
  	if (! (pwd = getpwnam (user_name))) {
  		fprintf (stderr, "%s: user %s does not exist\n",
  			Prog, user_name);
! 		exit (1);
  	}
  	user_id = pwd->pw_uid;
  	strcpy (user_home, pwd->pw_dir);
--- 460,466 ----
  	if (! (pwd = getpwnam (user_name))) {
  		fprintf (stderr, "%s: user %s does not exist\n",
  			Prog, user_name);
! 		exit (6);
  	}
  	user_id = pwd->pw_uid;
  	strcpy (user_home, pwd->pw_dir);
***************
*** 490,499 ****
  	update_user ();
  	update_groups ();
  
! 	if (rflg)
! 		rmdir (user_home);
! 
  	close_files ();
! 	exit (0);
  	/*NOTREACHED*/
  }
--- 475,485 ----
  	update_user ();
  	update_groups ();
  
! 	if (rflg) {
! 		if (remove_tree (user_home) || rmdir (user_home))
! 			errors++;
! 	}
  	close_files ();
! 	exit (errors ? 12:0);
  	/*NOTREACHED*/
  }
*** rel3/usermod.c	Thu Jun 13 21:28:46 1991
--- usermod.c	Thu Jun 13 10:06:47 1991
***************
*** 10,16 ****
   */
  
  #ifndef lint
! static	char	sccsid[] = "@(#)usermod.c	3.1	11:08:35	6/7/91";
  #endif
  
  #include <sys/types.h>
--- 10,16 ----
   */
  
  #ifndef lint
! static	char	sccsid[] = "@(#)usermod.c	3.2	20:26:57	6/11/91";
  #endif
  
  #include <sys/types.h>
***************
*** 44,49 ****
--- 44,51 ----
  #define	NGROUPS_MAX	64
  #endif
  
+ #define	VALID(s)	(strcspn (s, ":\n") == strlen (s))
+ 
  char	user_name[BUFSIZ];
  char	user_newname[BUFSIZ];
  uid_t	user_id;
***************
*** 115,121 ****
  extern	int	spw_lock();
  extern	int	spw_unlock();
  extern	int	spw_open();
! extern	int	spw_locate();
  
  #define	DAY	(24L*3600L)
  #define	WEEK	(7*DAY)
--- 117,123 ----
  extern	int	spw_lock();
  extern	int	spw_unlock();
  extern	int	spw_open();
! extern	struct	spwd	*spw_locate();
  
  #define	DAY	(24L*3600L)
  #define	WEEK	(7*DAY)
***************
*** 140,176 ****
  	0,	31,	59,	90,	120,	151,	/* JAN - JUN */
  	181,	212,	243,	273,	304,	334 };	/* JUL - DEC */
  
- #ifdef	NEED_MKDIR
- /*
-  * mkdir - create a directory
-  *
-  *	mkdir is provided for systems which do not include the mkdir()
-  *	system call.
-  */
- 
- int
- mkdir (dir, mode)
- char	*dir;
- int	mode;
- {
- 	int	status;
- 
- 	if (fork ()) {
- 		while (wait (&status) != -1)
- 			;
- 
- 		return status >> 8;
- 	}
- #ifdef	USE_SYSLOG
- 	closelog ();
- #endif
- 	close (2);
- 	open ("/dev/null", O_WRONLY);
- 	umask (0777 & ~ mode);
- 	execl ("/bin/mkdir", "mkdir", dir, 0);
- 	_exit (128);
- }
- #endif
  #ifdef	NEED_RENAME
  /*
   * rename - rename a file to another name
--- 142,147 ----
***************
*** 831,836 ****
--- 802,813 ----
  	while ((arg = getopt (argc, argv, "u:og:G:d:s:c:mf:e:l:")) != EOF) {
  		switch (arg) {
  			case 'c':
+ 				if (! VALID (optarg)) {
+ 					fprintf (stderr,
+ 						"%s: invalid field `%s'\n",
+ 						Prog, optarg);
+ 					exit (3);
+ 				}
  				if (strcmp (optarg, user_comment)) {
  					cflg++;
  					strncpy (user_comment, optarg, BUFSIZ);
***************
*** 837,842 ****
--- 814,825 ----
  				}
  				break;
  			case 'd':
+ 				if (! VALID (optarg)) {
+ 					fprintf (stderr,
+ 						"%s: invalid field `%s'\n",
+ 						Prog, optarg);
+ 					exit (3);
+ 				}
  				dflg++;
  				strncpy (user_newhome, optarg, BUFSIZ);
  				break;
***************
*** 880,885 ****
--- 863,874 ----
  
  				break;
  			case 'l':
+ 				if (! VALID (optarg)) {
+ 					fprintf (stderr,
+ 						"%s: invalid field `%s'\n",
+ 						Prog, optarg);
+ 					exit (3);
+ 				}
  				if (strcmp (user_name, optarg)) {
  					lflg++;
  					strcpy (user_newname, optarg);
***************
*** 898,903 ****
--- 887,898 ----
  				oflg++;
  				break;
  			case 's':
+ 				if (! VALID (optarg)) {
+ 					fprintf (stderr,
+ 						"%s: invalid field `%s'\n",
+ 						Prog, optarg);
+ 					exit (3);
+ 				}
  				if (strcmp (user_shell, optarg)) {
  					strncpy (user_shell, optarg, BUFSIZ);
  					sflg++;
***************
*** 980,990 ****
  		exit (1);
  	}
  	if (! spw_lock ()) {
! 		fprintf ("%s: cannot lock shadow password file\n", Prog);
  		exit (1);
  	}
  	if (! spw_open (O_RDWR)) {
! 		fprintf ("%s: cannot open shadow password file\n", Prog);
  		exit (1);
  	}
  }
--- 975,985 ----
  		exit (1);
  	}
  	if (! spw_lock ()) {
! 		fprintf (stderr, "%s: cannot lock shadow password file\n", Prog);
  		exit (1);
  	}
  	if (! spw_open (O_RDWR)) {
! 		fprintf (stderr, "%s: cannot open shadow password file\n", Prog);
  		exit (1);
  	}
  }
***************
*** 1076,1087 ****
  
  move_home ()
  {
! 	if (mflg && access (user_home, 0) == 0) {
  		if (access (user_newhome, 0) == 0) {
  			fprintf (stderr, "%s: directory %s exists\n",
  				Prog, user_newhome);
  			exit (12);
  		} else if (rename (user_home, user_newhome)) {
  			fprintf (stderr,
  				"%s: cannot rename directory %s to %s\n",
  				Prog, user_home, user_newhome);
--- 1071,1100 ----
  
  move_home ()
  {
! 	struct	stat	sb;
! 
! 	if (mflg && stat (user_home, &sb) == 0) {
  		if (access (user_newhome, 0) == 0) {
  			fprintf (stderr, "%s: directory %s exists\n",
  				Prog, user_newhome);
  			exit (12);
  		} else if (rename (user_home, user_newhome)) {
+ 			if (errno == EXDEV) {
+ 				if (mkdir (user_newhome, sb.st_mode & 0777)) {
+ 					fprintf (stderr,
+ 						"%s: can't create %s\n",
+ 						Prog, user_newhome);
+ 				}
+ 				chown (user_newhome, sb.st_uid, sb.st_gid);
+ 				if (copy_tree (user_home, user_newhome,
+ 						-1, -1) == 0 &&
+ 					remove_tree (user_home) == 0 &&
+ 						rmdir (user_home) == 0)
+ 					return;
+ 
+ 				remove_tree (user_newhome);
+ 				rmdir (user_newhome);
+ 			}
  			fprintf (stderr,
  				"%s: cannot rename directory %s to %s\n",
  				Prog, user_home, user_newhome);
-- 
John F. Haugh II        | Distribution to  | UUCP: ...!cs.utexas.edu!rpp386!jfh
Ma Bell: (512) 255-8251 | GEnie PROHIBITED :-) |  Domain: jfh at rpp386.cactus.org
"I carry a lot of weight, and I carry it well."
		-- Rush Limbaugh



More information about the Alt.sources mailing list