home *** CD-ROM | disk | FTP | other *** search
- From: jfh@rpp386.cactus.org (John F Haugh II)
- Newsgroups: alt.sources
- Subject: Shadow Login Suite, patch 4
- Message-ID: <19372@rpp386.cactus.org>
- Date: 11 Jun 91 11:27:15 GMT
-
- [ Either this didn't make it off this site or I'm in really bad shape. ]
-
- This is patch #4 for the current beta test release of the shadow login
- suite. It adds three new commands, useradd, userdel and usermod. The
- documentation that I promised in patch #3 hasn't been written. I've been
- busy planning a wedding (mine) and I've not had the time. You may refer
- either to the source code or your nearest SVR4 documentation for the
- behavior of these commands.
-
- It is known that there are bugs in these three new commands. Since they
- are the newest code in the entire suite, that's to be expected. Have
- patience and I'll get it fixed. Some of the bugs have been fixed already,
- and other fixes are due out in patch #6 (patch #5 is currently being
- verified by Chip).
-
- Also added was a "patchlevel.h" file. So many of you asked for it, so
- I've provided it ...
- --
- *** /dev/null Fri Jun 7 11:02:59 1991
- --- patchlevel.h Fri Jun 7 11:13:28 1991
- ***************
- *** 0 ****
- --- 1,13 ----
- + /*
- + * Copyright 1991, John F. Haugh II
- + * 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.
- + */
- +
- + #define RELEASE 3
- + #define PATCHLEVEL 4
- *** rel3/config.h Thu Jun 6 09:35:02 1991
- --- config.h Fri Jun 7 11:11:26 1991
- ***************
- *** 12,18 ****
- /*
- * Configuration file for login.
- *
- ! * @(#)config.h 3.7 08:57:09 5/30/91
- */
-
- /*
- --- 12,18 ----
- /*
- * Configuration file for login.
- *
- ! * @(#)config.h 3.8 11:11:17 6/7/91
- */
-
- /*
- ***************
- *** 31,40 ****
- --- 31,44 ----
- * for getpwuid() and getpwnam(). This provides compatibility for
- * privileged applications which are shadow-ignorant. YOU ARE
- * ENCOURAGED TO NOT USE THIS OPTION UNLESS ABSOLUTELY NECESSARY.
- + *
- + * Define SHADOWGRP to user shadowed group files. This feature adds
- + * the concept of a group administrator.
- */
-
- #define SHADOWPWD
- #undef AUTOSHADOW
- + #define SHADOWGRP
-
- /*
- * Define DOUBLESIZE to use 16 character passwords
- ***************
- *** 270,275 ****
- --- 274,282 ----
- #define GETPWENT /* Define if you want my GETPWENT(3) routines */
- #define GETGRENT /* Define if you want my GETGRENT(3) routines */
- #define NEED_AL64 /* Define if library does not include a64l() */
- + #define NEED_MKDIR /* Define if system does not have mkdir() */
- + #define NEED_RMDIR /* Define if system does not have rmdir() */
- + #define NEED_RENAME /* Define if system does not have rename() */
- #undef NO_STRSTR /* Define if library does not include strstr() */
-
- /*
- *** rel3/Makefile Thu Jun 6 09:35:02 1991
- --- Makefile Fri Jun 7 11:12:38 1991
- ***************
- *** 8,16 ****
- # and conspicuously displayed on all copies of object code or
- # distribution media.
- #
- ! # @(#)Makefile 3.10 09:05:50 - Shadow password system
- #
- ! # @(#)Makefile 3.10 09:05:50 5/30/91
- #
- SHELL = /bin/sh
-
- --- 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
-
- ***************
- *** 127,135 ****
- utmp.c valid.c port.c newgrp.c gpmain.c grent.c mkpasswd.c pwpack.c \
- 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
-
- ! FILES1 = README newgrp.c Makefile config.h pwunconv.c obscure.c age.c id.c
-
- FILES2 = passwd.c port.c lmain.c mkpasswd.c sulogin.c pwpack.c dialup.c \
- sulog.c getpass.c
- --- 127,137 ----
- utmp.c valid.c port.c newgrp.c gpmain.c grent.c mkpasswd.c pwpack.c \
- 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
-
- FILES2 = passwd.c port.c lmain.c mkpasswd.c sulogin.c pwpack.c dialup.c \
- sulog.c getpass.c
- ***************
- *** 147,152 ****
- --- 149,156 ----
-
- 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
- MAN_4 = faillog.4 passwd.4 porttime.4 shadow.4
- ***************
- *** 155,161 ****
- DOCS = $(MAN_1) $(MAN_3) $(MAN_4) $(MAN_8)
-
- BINS = su login pwconv pwunconv passwd sulogin faillog newgrp gpasswd \
- ! mkpasswd chfn chsh chage chpasswd newusers dpasswd id
-
- all: $(BINS) $(DOCS)
-
- --- 159,166 ----
- DOCS = $(MAN_1) $(MAN_3) $(MAN_4) $(MAN_8)
-
- BINS = su login pwconv pwunconv passwd sulogin faillog newgrp gpasswd \
- ! mkpasswd chfn chsh chage chpasswd newusers dpasswd id useradd \
- ! userdel usermod
-
- all: $(BINS) $(DOCS)
-
- ***************
- *** 214,220 ****
-
- lint: su.lint login.lint pwconv.lint pwunconv.lint passwd.lint sulogin.lint \
- faillog.lint newgrp.lint gpasswd.lint mkpasswd.lint chfn.lint \
- ! chsh.lint chage.lint dpasswd.lint $(ALLSRCS:.c=.L)
-
- tags: $(ALLSRCS)
- $(TAGS) $(ALLSRCS)
- --- 219,226 ----
-
- lint: su.lint login.lint pwconv.lint pwunconv.lint passwd.lint sulogin.lint \
- faillog.lint newgrp.lint gpasswd.lint mkpasswd.lint chfn.lint \
- ! chsh.lint chage.lint dpasswd.lint id.lint useradd.lint userdel.lint \
- ! usermod.lint $(ALLSRCS:.c=.L)
-
- tags: $(ALLSRCS)
- $(TAGS) $(ALLSRCS)
- ***************
- *** 327,332 ****
- --- 333,356 ----
- 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
-
- susetup.c: setup.c
- ***************
- *** 395,400 ****
- --- 419,426 ----
- id.o: pwd.h
- newusers.o: config.h shadow.h pwd.h
- dpmain.o: dialup.h
- + useradd.o: config.h shadow.h pwd.h
- + userdel.o: config.h shadow.h pwd.h
-
- clean:
- -rm -f *.o a.out core npasswd nshadow *.pag *.dir
- ***************
- *** 410,416 ****
- done
-
- shar: login.sh.1 login.sh.2 login.sh.3 login.sh.4 login.sh.5 login.sh.6 \
- ! login.sh.7 login.sh.8
-
- login.sh.1: $(FILES1) Makefile
- shar -a $(FILES1) > login.sh.1
- --- 436,442 ----
- done
-
- shar: login.sh.1 login.sh.2 login.sh.3 login.sh.4 login.sh.5 login.sh.6 \
- ! login.sh.7 login.sh.8 login.sh.9
-
- login.sh.1: $(FILES1) Makefile
- shar -a $(FILES1) > login.sh.1
- ***************
- *** 433,437 ****
- login.sh.7: $(FILES7) Makefile
- shar -a $(FILES7) > login.sh.7
-
- ! login.sh.8: $(DOCS) Makefile
- ! shar -a $(DOCS) > login.sh.8
- --- 459,466 ----
- login.sh.7: $(FILES7) Makefile
- shar -a $(FILES7) > login.sh.7
-
- ! login.sh.8: $(FILES8) Makefile
- ! shar -a $(FILES8) > login.sh.8
- !
- ! login.sh.9: $(DOCS) Makefile
- ! shar -a $(DOCS) > login.sh.9
- *** /dev/null Fri Jun 7 11:02:59 1991
- --- useradd.c Fri Jun 7 11:10:07 1991
- ***************
- *** 0 ****
- --- 1,1245 ----
- + /*
- + * Copyright 1991, John F. Haugh II
- + * 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.
- + */
- +
- + #ifndef lint
- + static char sccsid[] = "@(#)useradd.c 3.1 11:08:18 6/7/91";
- + #endif
- +
- + #include <sys/types.h>
- + #include <sys/stat.h>
- + #include <stdio.h>
- + #include <errno.h>
- + #include <pwd.h>
- + #include <grp.h>
- + #include <ctype.h>
- + #include <fcntl.h>
- + #include <time.h>
- +
- + #ifdef BSD
- + #include <strings.h>
- + #else
- + #include <string.h>
- + #endif
- +
- + #include "config.h"
- + #include "shadow.h"
- +
- + #ifdef USE_SYSLOG
- + #include <syslog.h>
- +
- + #ifndef LOG_WARN
- + #define LOG_WARN LOG_WARNING
- + #endif
- + #endif
- +
- + gid_t def_group;
- + char def_home[BUFSIZ];
- + char def_shell[BUFSIZ];
- + long def_inactive;
- + long def_expire;
- + char def_file[] = "/etc/default/useradd";
- +
- + #ifndef NGROUPS_MAX
- + #define NGROUPS_MAX 64
- + #endif
- +
- + char user_name[BUFSIZ];
- + uid_t user_id;
- + gid_t user_gid;
- + char user_comment[BUFSIZ];
- + char user_home[BUFSIZ];
- + char user_shell[BUFSIZ];
- + long user_expire;
- + int user_ngroups;
- + gid_t user_groups[NGROUPS_MAX];
- +
- + char *Prog;
- +
- + int uflg; /* specify user ID for new account */
- + int oflg; /* permit non-unique user ID to be specified with -u */
- + int gflg; /* primary group ID for new account */
- + int Gflg; /* secondary group set for new account */
- + int dflg; /* home directory for new account */
- + int bflg; /* new default root of home directory */
- + int sflg; /* shell program for new account */
- + int cflg; /* comment (GECOS) field for new account */
- + int mflg; /* create user's home directory if it doesn't exist */
- + int kflg; /* specify a directory to fill new user directory */
- + int fflg; /* days until account with expired password is locked */
- + int eflg; /* days after password changed before it becomes expired */
- + int Dflg; /* set/show new user default values */
- +
- + #if defined(DBM) || defined(NDBM)
- + extern int pw_dbm_mode;
- + #endif
- + #ifdef NDBM
- + extern int sp_dbm_mode;
- + extern int gr_dbm_mode;
- + extern int sg_dbm_mode;
- + #endif
- + extern FILE *fopen();
- + extern int fclose();
- + extern char *malloc();
- + extern char *mktemp();
- +
- + extern struct group *getgrnam();
- + extern struct group *getgrgid();
- + extern struct group *gr_next();
- + extern struct group *gr_locate();
- + extern int gr_lock();
- + extern int gr_unlock();
- + extern int gr_rewind();
- + extern int gr_open();
- +
- + #ifdef SHADOWGRP
- + extern struct sgrp *sgr_next();
- + extern int sgr_lock();
- + extern int sgr_unlock();
- + extern int sgr_rewind();
- + extern int sgr_open();
- + #endif
- +
- + extern struct passwd *getpwnam();
- + extern struct passwd *pw_next();
- + extern int pw_lock();
- + extern int pw_unlock();
- + extern int pw_rewind();
- + extern int pw_open();
- +
- + extern int spw_lock();
- + extern int spw_unlock();
- + extern int spw_open();
- +
- + #define DAY (24L*3600L)
- + #define WEEK (7*DAY)
- +
- + #ifdef ITI_AGING
- + #define SCALE (1)
- + #else
- + #define SCALE (DAY)
- + #endif
- +
- + /*
- + * days and juldays are used to compute the number of days in the
- + * current month, and the cummulative number of days in the preceding
- + * months. they are declared so that january is 1, not 0.
- + */
- +
- + static short days[13] = { 0,
- + 31, 28, 31, 30, 31, 30, /* JAN - JUN */
- + 31, 31, 30, 31, 30, 31 }; /* JUL - DEC */
- +
- + static short juldays[13] = { 0,
- + 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
- + *
- + * rename is provided for systems which do not include the rename()
- + * system call.
- + */
- +
- + int
- + rename (begin, end)
- + char *begin;
- + char *end;
- + {
- + struct stat s1, s2;
- + extern int errno;
- + int orig_err = errno;
- +
- + if (stat (begin, &s1))
- + return -1;
- +
- + if (stat (end, &s2)) {
- + errno = orig_err;
- + } else {
- +
- + /*
- + * See if this is a cross-device link. We do this to
- + * insure that the link below has a chance of working.
- + */
- +
- + if (s1.st_dev != s2.st_dev) {
- + errno = EXDEV;
- + return -1;
- + }
- +
- + /*
- + * See if we can unlink the existing destination
- + * file. If the unlink works the directory is writable,
- + * so there is no need here to figure that out.
- + */
- +
- + if (unlink (end))
- + return -1;
- + }
- +
- + /*
- + * Now just link the original name to the final name. If there
- + * was no file previously, this link will fail if the target
- + * directory isn't writable. The unlink will fail if the source
- + * directory isn't writable, but life stinks ...
- + */
- +
- + if (link (begin, end) || unlink (begin))
- + return -1;
- +
- + return 0;
- + }
- + #endif
- +
- + /*
- + * strtoday - compute the number of days since 1970.
- + *
- + * the total number of days prior to the current date is
- + * computed. january 1, 1970 is used as the origin with
- + * it having a day number of 0.
- + */
- +
- + long
- + strtoday (str)
- + char *str;
- + {
- + char slop[2];
- + int month;
- + int day;
- + int year;
- + long total;
- +
- + /*
- + * start by separating the month, day and year. this is
- + * a chauvanistic program - it only takes date input in
- + * the standard USA format.
- + */
- +
- + if (sscanf (str, "%d/%d/%d%c", &month, &day, &year, slop) != 3)
- + return -1;
- +
- + /*
- + * the month, day of the month, and year are checked for
- + * correctness and the year adjusted so it falls between
- + * 1970 and 2069.
- + */
- +
- + if (month < 1 || month > 12)
- + return -1;
- +
- + if (day < 1)
- + return -1;
- +
- + if ((month != 2 || (year % 4) != 0) && day > days[month])
- + return -1;
- + else if ((month == 2 && (year % 4) == 0) && day > 29)
- + return -1;
- +
- + if (year < 0)
- + return -1;
- + else if (year < 69)
- + year += 2000;
- + else if (year < 99)
- + year += 1900;
- +
- + if (year < 1970 || year > 2069)
- + return -1;
- +
- + /*
- + * the total number of days is the total number of days in all
- + * the whole years, plus the number of leap days, plus the
- + * number of days in the whole months preceding, plus the number
- + * of days so far in the month.
- + */
- +
- + total = (long) ((year - 1970) * 365L) + (((year + 1) - 1970) / 4);
- + total += (long) juldays[month] + (month > 2 && (year % 4) == 0 ? 1:0);
- + total += (long) day - 1;
- +
- + return total;
- + }
- +
- + /*
- + * add_list - add a member to a list of group members
- + *
- + * the array of member names is searched for the new member
- + * name, and if not present it is added to a freshly allocated
- + * list of users.
- + */
- +
- + char **
- + add_list (list, member)
- + char **list;
- + char *member;
- + {
- + int i;
- + char **tmp;
- +
- + /*
- + * Scan the list for the new name. Return the original list
- + * pointer if it is present.
- + */
- +
- + for (i = 0;list[i] != (char *) 0;i++)
- + if (strcmp (list[i], member) == 0)
- + return list;
- +
- + /*
- + * Allocate a new list pointer large enough to hold all the
- + * old entries, and the new entries as well.
- + */
- +
- + if (! (tmp = (char **) malloc ((i + 2) * sizeof member)))
- + return 0;
- +
- + /*
- + * Copy the original list to the new list, then append the
- + * new member and NULL terminate the result. This new list
- + * is returned to the invoker.
- + */
- +
- + for (i = 0;list[i] != (char *) 0;i++)
- + tmp[i] = list[i];
- +
- + tmp[i++] = strdup (member);
- + tmp[i] = (char *) 0;
- +
- + return tmp;
- + }
- +
- + /*
- + * get_defaults - read the defaults file
- + *
- + * get_defaults() reads the defaults file for this command. It sets
- + * the various values from the file, or uses built-in default values
- + * if the file does not exist.
- + */
- +
- + void
- + get_defaults ()
- + {
- + FILE *fp;
- + char buf[BUFSIZ];
- + char *cp;
- + struct group *grp;
- +
- + /*
- + * Open the defaults file for reading.
- + */
- +
- + if (! (fp = fopen (def_file, "r"))) {
- +
- + /*
- + * No defaults file - set up the defaults that are given
- + * in the documentation.
- + */
- +
- + def_group = 1;
- + strcpy (def_home, "/home");
- + def_inactive = 0;
- + def_expire = 0;
- + return;
- + }
- +
- + /*
- + * Read the file a line at a time. Only the lines that have
- + * relevant values are used, everything else can be ignored.
- + */
- +
- + while (fgets (buf, BUFSIZ, fp)) {
- + if (cp = strrchr (buf, '\n'))
- + *cp = '\0';
- +
- + /*
- + * Primary GROUP identifier
- + */
- +
- + if (strncmp ("GROUP=", buf, 6) == 0) {
- + cp = buf + 6;
- + if (isdigit (*cp))
- + def_group = atoi (cp);
- + else if (grp = getgrnam (cp))
- + def_group = grp->gr_gid;
- + else
- + fprintf (stderr, "%s: unknown group %s\n", cp);
- + }
- +
- + /*
- + * Default HOME filesystem
- + */
- +
- + else if (strncmp ("HOME=", buf, 5) == 0) {
- + strncpy (def_home, buf + 5, BUFSIZ);
- + }
- +
- + /*
- + * Default Login Shell command
- + */
- +
- + else if (strncmp ("SHELL=", buf, 6) == 0) {
- + strncpy (def_shell, buf + 6, BUFSIZ);
- + }
- +
- + /*
- + * Default Password Inactive value
- + */
- +
- + else if (strncmp ("INACTIVE=", buf, 9) == 0) {
- + def_inactive = atoi (buf + 9);
- + }
- +
- + /*
- + * Default Password Expiration value
- + */
- +
- + else if (strncmp ("EXPIRE=", buf, 7) == 0) {
- + def_expire = atoi (buf + 7);
- + }
- + }
- + }
- +
- + /*
- + * show_defaults - show the contents of the defaults file
- + *
- + * show_defaults() displays the values that are used from the default
- + * file and the built-in values.
- + */
- +
- + void
- + show_defaults ()
- + {
- + printf ("GROUP=%d\n", def_group);
- + printf ("HOME=%s\n", def_home);
- + printf ("INACTIVE=%d\n", def_inactive);
- + printf ("EXPIRE=%d\n", def_expire);
- + }
- +
- + /*
- + * set_defaults - write new defaults file
- + *
- + * set_defaults() re-writes the defaults file using the values that
- + * are currently set. Duplicated lines are pruned, missing lines are
- + * added, and unrecognized lines are copied as is.
- + */
- +
- + int
- + set_defaults ()
- + {
- + FILE *ifp;
- + FILE *ofp;
- + char buf[BUFSIZ];
- + static char new_file[] = "/etc/default/nuaddXXXXXX";
- + char *cp;
- + int out_group = 0;
- + int out_home = 0;
- + int out_inactive = 0;
- + int out_expire = 0;
- +
- + /*
- + * Create a temporary file to copy the new output to.
- + */
- +
- + mktemp (new_file);
- + if (! (ofp = fopen (new_file, "w"))) {
- + fprintf (stderr, "%s: cannot create new defaults file\n", Prog);
- + return -1;
- + }
- +
- + /*
- + * Open the existing defaults file and copy the lines to the
- + * temporary files, using any new values. Each line is checked
- + * to insure that it is not output more than once.
- + */
- +
- + if (ifp = fopen (def_file, "r")) {
- + while (fgets (buf, BUFSIZ, ifp)) {
- + if (cp = strrchr (buf, '\n'))
- + *cp = '\0';
- +
- + if (strncmp ("GROUP=", buf, 6) == 0) {
- + if (! out_group)
- + fprintf (ofp, "GROUP=%d\n", def_group);
- +
- + out_group++;
- + } else if (strncmp ("HOME=", buf, 5) == 0) {
- + if (! out_home)
- + fprintf (ofp, "HOME=%s\n", def_home);
- +
- + out_home++;
- + } else if (strncmp ("INACTIVE=", buf, 9) == 0) {
- + if (! out_inactive)
- + fprintf (ofp, "INACTIVE=%d\n",
- + def_inactive);
- +
- + out_inactive++;
- + } else if (strncmp ("EXPIRE=", buf, 7) == 0) {
- + if (! out_expire)
- + fprintf (ofp, "EXPIRE=%d\n",
- + def_expire);
- +
- + out_expire++;
- + } else
- + fprintf (ofp, "%s\n", buf);
- + }
- + fclose ((FILE *) ifp);
- + }
- +
- + /*
- + * Check each line to insure that every line was output. This
- + * causes new values to be added to a file which did not previously
- + * have an entry for that value.
- + */
- +
- + if (! out_group)
- + fprintf (ofp, "GROUP=%d\n", def_group);
- +
- + if (! out_home)
- + fprintf (ofp, "HOME=%s\n", def_home);
- +
- + if (! out_inactive)
- + fprintf (ofp, "INACTIVE=%d\n", def_inactive);
- +
- + if (! out_expire)
- + fprintf (ofp, "EXPIRE=%d\n", def_expire);
- +
- + /*
- + * Flush and close the file. Check for errors to make certain
- + * the new file is intact.
- + */
- +
- + (void) fflush (ofp);
- + if (ferror (ofp) || fclose ((FILE *) ofp)) {
- + unlink (new_file);
- + return -1;
- + }
- +
- + /*
- + * Rename the current default file to its backup name.
- + */
- +
- + sprintf (buf, "%s-", def_file);
- + if (rename (def_file, buf) && errno != ENOENT) {
- + sprintf (buf, "%s: rename: %s", Prog, def_file);
- + perror (buf);
- + unlink (new_file);
- + return -1;
- + }
- +
- + /*
- + * Rename the new default file to its correct name.
- + */
- +
- + if (rename (new_file, def_file)) {
- + sprintf (buf, "%s: rename: %s", Prog, new_file);
- + perror (buf);
- + return -1;
- + }
- + #ifdef USE_SYSLOG
- + syslog (LOG_INFO, "defaults: group=%d, home=%s, inactive=%d, expire=%d",
- + def_group, def_home, def_inactive, def_expire);
- + #endif
- + return 0;
- + }
- +
- + /*
- + * get_groups - convert a list of group names to an array of group IDs
- + *
- + * get_groups() takes a comma-separated list of group names and
- + * converts it to an array of group ID values. Any unknown group
- + * names are reported as errors.
- + */
- +
- + int
- + get_groups (list)
- + char *list;
- + {
- + char *cp;
- + struct group *grp;
- + int errors = 0;
- +
- + /*
- + * Initialize the list to be empty
- + */
- +
- + user_ngroups = 0;
- +
- + if (! *list)
- + return 0;
- +
- + /*
- + * So long as there is some data to be converted, strip off
- + * each name and look it up. A mix of numerical and string
- + * values for group identifiers is permitted.
- + */
- +
- + do {
- + /*
- + * Strip off a single name from the list
- + */
- +
- + if (cp = strchr (list, ','))
- + *cp++ = '\0';
- +
- + /*
- + * Names starting with digits are treated as numerical
- + * GID values, otherwise the string is looked up as is.
- + */
- +
- + if (isdigit (*list))
- + grp = getgrgid (atoi (list));
- + else
- + grp = getgrnam (list);
- +
- + /*
- + * There must be a match, either by GID value or by
- + * string name.
- + */
- +
- + if (! grp) {
- + fprintf (stderr, "%s: unknown group %s\n", Prog, list);
- + errors++;
- + }
- +
- + /*
- + * Add the GID value from the group file to the user's
- + * list of groups.
- + */
- +
- + user_groups[user_ngroups++] = grp->gr_gid;
- +
- + list = cp;
- + } while (list);
- +
- + /*
- + * Any errors in finding group names are fatal
- + */
- +
- + if (errors)
- + return -1;
- +
- + return 0;
- + }
- +
- + /*
- + * usage - display usage message and exit
- + */
- +
- + usage ()
- + {
- + fprintf (stderr,
- + "usage:\tuseradd [-u uid [-o]] [-g group] [-G group,...] \n");
- + fprintf (stderr,
- + "\t\t[-d home] [-s shell] [-c comment] [-m [-k template]]\n");
- + fprintf (stderr,
- + "\t\t[-f inactive] [-e expire] name\n");
- +
- + fprintf (stderr,
- + "\tuseradd -D [-g group] [-b base] [-f inactive] [-e expire]\n");
- +
- + exit (1);
- + }
- +
- + /*
- + * new_pwent - initialize the values in a password file entry
- + *
- + * new_pwent() takes all of the values that have been entered and
- + * fills in a (struct passwd) with them.
- + */
- +
- + void
- + new_pwent (pwent)
- + struct passwd *pwent;
- + {
- + memset (pwent, 0, sizeof *pwent);
- + pwent->pw_name = user_name;
- + pwent->pw_passwd = "*";
- + pwent->pw_age = "";
- + pwent->pw_uid = user_id;
- + pwent->pw_gid = user_gid;
- + pwent->pw_gecos = user_comment;
- + pwent->pw_comment = "";
- + pwent->pw_dir = user_home;
- + pwent->pw_shell = user_shell;
- + }
- +
- + /*
- + * new_spent - initialize the values in a shadow password file entry
- + *
- + * new_spent() takes all of the values that have been entered and
- + * fills in a (struct spwd) with them.
- + */
- +
- + void
- + new_spent (spent)
- + struct spwd *spent;
- + {
- + memset (spent, 0, sizeof *spent);
- + spent->sp_namp = user_name;
- + spent->sp_pwdp = "!";
- + spent->sp_lstchg = 0;
- + spent->sp_min = 0;
- + spent->sp_max = def_expire;
- + spent->sp_warn = 0;
- + spent->sp_inact = def_inactive;
- + spent->sp_expire = user_expire;
- + }
- +
- + /*
- + * grp_update - add user to secondary group set
- + *
- + * grp_update() takes the secondary group set given in user_groups
- + * and adds the user to each group given by that set.
- + */
- +
- + void
- + grp_update ()
- + {
- + int i;
- + struct group *grp;
- + struct sgrp *sgrp;
- +
- + /*
- + * Lock and open the group file. This will load all of the group
- + * entries.
- + */
- +
- + if (! gr_lock ()) {
- + fprintf (stderr, "%s: error locking group file\n", Prog);
- + exit (1);
- + }
- + if (! gr_open (O_RDWR)) {
- + fprintf (stderr, "%s: error opening group file\n", Prog);
- + exit (1);
- + }
- + #ifdef SHADOWGRP
- + if (! sgr_lock ()) {
- + fprintf (stderr, "%s: error locking shadow group file\n", Prog);
- + exit (1);
- + }
- + if (! sgr_open (O_RDWR)) {
- + fprintf (stderr, "%s: error opening shadow group file\n", Prog);
- + exit (1);
- + }
- + #endif
- +
- + /*
- + * Scan through the entire group file looking for the groups that
- + * the user is a member of.
- + */
- +
- + for (gr_rewind (), grp = gr_next ();grp;grp = gr_next ()) {
- +
- + /*
- + * See if the user specified this group as one of their
- + * concurrent groups.
- + */
- +
- + for (i = 0;i < user_ngroups;i++)
- + if (grp->gr_gid == user_groups[i])
- + break;
- +
- + if (i == user_ngroups)
- + continue;
- +
- + /*
- + * Add the username to the list of group members and
- + * update the group entry to reflect the change.
- + */
- +
- + grp->gr_mem = add_list (grp->gr_mem, user_name);
- + if (! gr_update (grp)) {
- + fprintf (stderr, "%s: error adding new group entry\n",
- + 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 add new dbm group entry\n",
- + Prog);
- + exit (1);
- + }
- + #endif
- + #ifdef USE_SYSLOG
- + syslog (LOG_INFO, "add `%s' to group `%s'\n",
- + user_name, grp->gr_name);
- + #endif
- + }
- +
- + #ifdef SHADOWGRP
- + /*
- + * Scan through the entire shadow group file looking for the groups
- + * that the user is a member of. The administrative list isn't
- + * modified.
- + */
- +
- + for (sgr_rewind (), sgrp = sgr_next ();sgrp;sgrp = sgr_next ()) {
- +
- + /*
- + * See if the user specified this group as one of their
- + * concurrent groups.
- + */
- +
- + for (i = 0;i < user_ngroups;i++) {
- + if (! (grp = gr_locate (sgrp->sg_name)))
- + continue;
- +
- + if (grp->gr_gid == user_groups[i])
- + break;
- + }
- + if (i == user_ngroups)
- + continue;
- +
- + /*
- + * Add the username to the list of group members and
- + * update the group entry to reflect the change.
- + */
- +
- + sgrp->sg_mem = add_list (sgrp->sg_mem, user_name);
- + if (! sgr_update (sgrp)) {
- + fprintf (stderr, "%s: error adding new group entry\n",
- + Prog);
- + exit (1);
- + }
- + #ifdef NDBM
- + /*
- + * Update the DBM group file with the new entry as well.
- + */
- +
- + if (! sgr_dbm_update (sgrp)) {
- + fprintf (stderr, "%s: cannot add new dbm group entry\n",
- + Prog);
- + exit (1);
- + }
- + #endif
- + #ifdef USE_SYSLOG
- + syslog (LOG_INFO, "add `%s' to shadow group `%s'\n",
- + user_name, sgrp->sg_name);
- + #endif
- + }
- + #endif
- + }
- +
- + /*
- + * find_new_uid - find the next available UID
- + *
- + * find_new_uid() locates the next highest unused UID in the password
- + * file, or checks the given user ID against the existing ones for
- + * uniqueness.
- + */
- +
- + int
- + find_new_uid ()
- + {
- + struct passwd *pwd;
- +
- + /*
- + * Start with some UID value if the user didn't provide us with
- + * one already.
- + */
- +
- + if (! uflg)
- + user_id = 100;
- +
- + /*
- + * Search the entire password file, either looking for this
- + * UID (if the user specified one with -u) or looking for the
- + * largest unused value.
- + */
- +
- + for (pw_rewind (), pwd = pw_next ();pwd;pwd = pw_next ()) {
- + if (strcmp (user_name, pwd->pw_name) == 0) {
- + fprintf (stderr, "%s: name %s is not unique\n",
- + Prog, user_name);
- + exit (1);
- + }
- + if (uflg && user_id == pwd->pw_uid) {
- + fprintf (stderr, "%s: uid %d is not unique\n",
- + Prog, user_id);
- + exit (1);
- + }
- + if (! uflg && pwd->pw_uid >= user_id)
- + user_id = pwd->pw_uid + 1;
- + }
- + }
- +
- + /*
- + * process_flags - perform command line argument setting
- + *
- + * process_flags() interprets the command line arguments and sets
- + * the values that the user will be created with accordingly. The
- + * values are checked for sanity.
- + */
- +
- + void
- + process_flags (argc, argv)
- + int argc;
- + char **argv;
- + {
- + extern int optind;
- + extern char *optarg;
- + struct group *grp;
- + int anyflag = 0;
- + int arg;
- +
- + while ((arg = getopt (argc, argv, "Du:og:G:d:s:c:mk:f:e:b:")) != EOF) {
- + switch (arg) {
- + case 'b':
- + bflg++;
- + if (! Dflg)
- + usage ();
- +
- + strncpy (def_home, optarg, BUFSIZ);
- + break;
- + case 'c':
- + cflg++;
- + strncpy (user_comment, optarg, BUFSIZ);
- + break;
- + case 'd':
- + dflg++;
- + strncpy (user_home, optarg, BUFSIZ);
- + break;
- + case 'D':
- + if (anyflag)
- + usage ();
- +
- + Dflg++;
- + break;
- + case 'e':
- + eflg++;
- + if (Dflg)
- + def_expire = atoi (optarg);
- + else {
- + user_expire = strtoday (optarg);
- + #ifdef ITI_AGING
- + user_expire *= DAY;
- + #endif
- + }
- + break;
- + case 'f':
- + fflg++;
- + def_inactive = atoi (optarg);
- + break;
- + case 'g':
- + gflg++;
- + if (isdigit (optarg[0]))
- + grp = getgrgid (atoi (optarg));
- + else
- + grp = getgrnam (optarg);
- +
- + if (! grp) {
- + fprintf (stderr,
- + "%s: unknown group %s\n",
- + optarg);
- + exit (1);
- + }
- + def_group = grp->gr_gid;
- + break;
- + case 'G':
- + Gflg++;
- + if (get_groups (optarg))
- + exit (1);
- +
- + break;
- + case 'k':
- + if (! mflg)
- + usage ();
- +
- + kflg++;
- + break;
- + case 'm':
- + mflg++;
- + break;
- + case 'o':
- + if (! uflg)
- + usage ();
- +
- + oflg++;
- + break;
- + case 's':
- + sflg++;
- + strncpy (user_shell, optarg, BUFSIZ);
- + break;
- + case 'u':
- + uflg++;
- + user_id = atoi (optarg);
- + break;
- + default:
- + usage ();
- + }
- + anyflag++;
- + }
- + if (! Dflg && optind == argc - 1)
- + strcpy (user_name, argv[argc - 1]);
- +
- + if (! dflg)
- + sprintf (user_home, "%s/%s", def_home, user_name);
- +
- + if (! gflg)
- + user_gid = def_group;
- +
- + if (Dflg) {
- + if (optind != argc)
- + usage ();
- +
- + if (uflg || oflg || Gflg || dflg ||
- + sflg || cflg || mflg || kflg)
- + usage ();
- + } else {
- + if (optind != argc - 1)
- + usage ();
- + }
- + }
- +
- + /*
- + * close_files - close all of the files that were opened
- + *
- + * close_files() closes all of the files that were opened for this
- + * new user. This causes any modified entries to be written out.
- + */
- +
- + close_files ()
- + {
- + if (! pw_close ()) {
- + fprintf (stderr, "%s: cannot rewrite password file\n", Prog);
- + exit (1);
- + }
- + if (! spw_close ()) {
- + fprintf (stderr, "%s: cannot rewrite shadow password file\n",
- + Prog);
- + exit (1);
- + }
- + if (user_ngroups > 0) {
- + if (! gr_close ()) {
- + fprintf (stderr, "%s: cannot rewrite group file\n",
- + Prog);
- + exit (1);
- + }
- + (void) gr_unlock ();
- + #ifdef SHADOWGRP
- + if (! sgr_close ()) {
- + fprintf (stderr, "%s: cannot rewrite shadow group file\n",
- + Prog);
- + exit (1);
- + }
- + #endif
- + }
- + (void) pw_unlock ();
- + }
- +
- + /*
- + * open_files - lock and open the password files
- + *
- + * open_files() opens the two password files.
- + */
- +
- + open_files ()
- + {
- + if (! pw_lock ()) {
- + fprintf (stderr, "%s: unable to lock password file\n", Prog);
- + exit (1);
- + }
- + if (! pw_open (O_RDWR)) {
- + fprintf (stderr, "%s: unable to open password file\n", Prog);
- + 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);
- + }
- + }
- +
- + /*
- + * usr_update - create the user entries
- + *
- + * usr_update() creates the password file entries for this user
- + * and will update the group entries if required.
- + */
- +
- + usr_update ()
- + {
- + struct passwd pwent;
- + struct spwd spent;
- +
- + if (! oflg)
- + find_new_uid ();
- +
- + new_pwent (&pwent);
- + if (! pw_update (&pwent)) {
- + fprintf (stderr, "%s: error adding new password entry\n", Prog);
- + exit (1);
- + }
- + new_spent (&spent);
- + if (! spw_update (&spent)) {
- + fprintf (stderr, "%s: error adding new shadow password entry\n",
- + Prog);
- + exit (1);
- + }
- + #if defined(DBM) || defined(NDBM)
- + if (access ("/etc/passwd.pag", 0) == 0 && ! pw_dbm_update (&pwent)) {
- + fprintf (stderr, "%s: error updating password dbm entry\n",
- + Prog);
- + exit (1);
- + }
- + #endif
- + #ifdef NDBM
- + if (access ("/etc/shadow.pag", 0) == 0 && ! sp_dbm_update (&spent)) {
- + fprintf (stderr, "%s: error updating shadow passwd dbm entry\n",
- + Prog);
- + exit (1);
- + }
- + #endif
- + #ifdef USE_SYSLOG
- + syslog (LOG_INFO,
- + "new user: name=%s, uid=%d, gid=%d, home=%s, shell=%s\n",
- + user_name, user_id, user_gid, user_home, user_shell);
- + #endif
- + if (user_ngroups > 0)
- + grp_update ();
- + }
- +
- + /*
- + * create_home - create the user's home directory
- + *
- + * create_home() creates the user's home directory if it does not
- + * already exist. It will be created mode 755 owned by the user
- + * with the user's default group.
- + */
- +
- + create_home ()
- + {
- + if (access (user_home, 0)) {
- + if (mkdir (user_home, 0755)) {
- + fprintf (stderr, "%s: cannot create directory %s\n",
- + Prog, user_home);
- + exit (1);
- + }
- + chown (user_home, user_id, user_gid);
- + chmod (user_home, 0755);
- + }
- + }
- +
- + /*
- + * main - useradd command
- + */
- +
- + main (argc, argv)
- + int argc;
- + char **argv;
- + {
- + /*
- + * Get my name so that I can use it to report errors.
- + */
- +
- + if (Prog = strrchr (argv[0], '/'))
- + Prog++;
- + else
- + Prog = argv[0];
- +
- + #ifdef USE_SYSLOG
- + openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
- + #endif
- +
- + /*
- + * The open routines for the DBM files don't use read-write
- + * as the mode, so we have to clue them in.
- + */
- +
- + #if defined(DBM) || defined(NDBM)
- + pw_dbm_mode = O_RDWR;
- + #endif
- + #ifdef NDBM
- + sp_dbm_mode = O_RDWR;
- + gr_dbm_mode = O_RDWR;
- + #ifdef SHADOWGRP
- + sg_dbm_mode = O_RDWR;
- + #endif
- + #endif
- + get_defaults ();
- +
- + process_flags (argc, argv);
- +
- + /*
- + * See if we are messing with the defaults file, or creating
- + * a new user.
- + */
- +
- + if (Dflg) {
- + if (gflg || bflg || fflg || eflg)
- + exit (set_defaults () ? 1:0);
- +
- + show_defaults ();
- + exit (0);
- + }
- +
- + /*
- + * Start with a quick check to see if the user exists.
- + */
- +
- + if (getpwnam (user_name)) {
- + fprintf (stderr, "%s: user %s exists\n", Prog, user_name);
- + exit (1);
- + }
- +
- + /*
- + * Do the hard stuff - open the files, create the user entries,
- + * create the home directory, then close and update the files.
- + */
- +
- + open_files ();
- +
- + usr_update ();
- +
- + if (mflg)
- + create_home ();
- +
- + close_files ();
- + exit (0);
- + /*NOTREACHED*/
- + }
- *** /dev/null Fri Jun 7 11:02:59 1991
- --- userdel.c Fri Jun 7 11:10:08 1991
- ***************
- *** 0 ****
- --- 1,499 ----
- + /*
- + * Copyright 1991, John F. Haugh II
- + * 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.
- + */
- +
- + #ifndef lint
- + static char sccsid[] = "@(#)userdel.c 3.1 11:08:47 6/7/91";
- + #endif
- +
- + #include <sys/types.h>
- + #include <sys/stat.h>
- + #include <stdio.h>
- + #include <errno.h>
- + #include <pwd.h>
- + #include <grp.h>
- + #include <ctype.h>
- + #include <fcntl.h>
- + #include <time.h>
- +
- + #ifdef BSD
- + #include <strings.h>
- + #else
- + #include <string.h>
- + #endif
- +
- + #include "config.h"
- + #include "shadow.h"
- +
- + #ifdef USE_SYSLOG
- + #include <syslog.h>
- +
- + #ifndef LOG_WARN
- + #define LOG_WARN LOG_WARNING
- + #endif
- + #endif
- +
- + gid_t default_group;
- + char default_home[BUFSIZ];
- + char default_shell[BUFSIZ];
- + long default_inactive;
- + long default_expire;
- + char default_file[] = "/etc/default/useradd";
- +
- + #ifndef NGROUPS_MAX
- + #define NGROUPS_MAX 64
- + #endif
- +
- + char user_name[BUFSIZ];
- + uid_t user_id;
- + gid_t user_group;
- + char user_comment[BUFSIZ];
- + char user_home[BUFSIZ];
- + char user_shell[BUFSIZ];
- + int user_ngroups;
- + int user_expire;
- + gid_t user_groups[NGROUPS_MAX];
- +
- + char *Prog;
- + int rflg;
- +
- + #if defined(DBM) || defined(NDBM)
- + extern int pw_dbm_mode;
- + #endif
- + #ifdef NDBM
- + extern int sp_dbm_mode;
- + extern int gr_dbm_mode;
- + #ifdef SHADOWGRP
- + extern int sg_dbm_mode;
- + #endif
- + #endif
- + extern struct group *getgrnam();
- + extern struct group *getgrgid();
- + extern struct group *gr_next();
- + extern struct passwd *getpwnam();
- + extern struct passwd *pw_next();
- +
- + #ifdef SHADOWGRP
- + extern int sgr_lock();
- + extern int sgr_unlock();
- + extern int sgr_open();
- + extern int sgr_close();
- + extern struct sgrp *sgr_next();
- + #endif
- +
- + 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
- + * name, and if present it is deleted from a freshly allocated
- + * list of users.
- + */
- +
- + char **
- + del_list (list, member)
- + char **list;
- + char *member;
- + {
- + int i, j;
- + char **tmp;
- +
- + /*
- + * Scan the list for the new name. Return the original list
- + * pointer if it is present.
- + */
- +
- + for (i = j = 0;list[i] != (char *) 0;i++)
- + if (strcmp (list[i], member))
- + j++;
- +
- + if (j == i)
- + return list;
- +
- + /*
- + * Allocate a new list pointer large enough to hold all the
- + * old entries, and the new entries as well.
- + */
- +
- + if (! (tmp = (char **) malloc ((j + 2) * sizeof member)))
- + return 0;
- +
- + /*
- + * Copy the original list to the new list, then append the
- + * new member and NULL terminate the result. This new list
- + * is returned to the invoker.
- + */
- +
- + for (i = j = 0;list[i] != (char *) 0;i++)
- + if (strcmp (list[i], member))
- + tmp[j++] = list[i];
- +
- + tmp[j] = (char *) 0;
- +
- + return tmp;
- + }
- +
- + /*
- + * usage - display usage message and exit
- + */
- +
- + usage ()
- + {
- + fprintf (stderr, "usage: userdel [-r] name\n");
- + exit (1);
- + }
- +
- + /*
- + * update_groups - delete user from secondary group set
- + *
- + * update_groups() takes the user name that was given and searches
- + * the group files for membership in any group.
- + */
- +
- + void
- + update_groups ()
- + {
- + int i;
- + struct group *grp;
- + #ifdef SHADOWGRP
- + struct sgrp *sgrp;
- + #endif
- +
- + /*
- + * Scan through the entire group file looking for the groups that
- + * the user is a member of.
- + */
- +
- + for (gr_rewind (), grp = gr_next ();grp;grp = gr_next ()) {
- +
- + /*
- + * See if the user specified this group as one of their
- + * concurrent groups.
- + */
- +
- + for (i = 0;grp->gr_mem[i];i++)
- + if (strcmp (grp->gr_mem[i], user_name) == 0)
- + break;
- +
- + if (grp->gr_mem[i] == (char *) 0)
- + continue;
- +
- + /*
- + * Delete the username from the list of group members and
- + * update the group entry to reflect the change.
- + */
- +
- + grp->gr_mem = del_list (grp->gr_mem, user_name);
- + if (! gr_update (grp)) {
- + fprintf (stderr, "%s: error updating group entry\n",
- + 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
- + }
- +
- + #ifdef SHADOWGRP
- + /*
- + * Scan through the entire shadow group file looking for the groups
- + * that the user is a member of. Both the administrative list and
- + * the ordinary membership list is checked.
- + */
- +
- + for (sgr_rewind (), sgrp = sgr_next ();sgrp;sgrp = sgr_next ()) {
- + int group_changed = 0;
- +
- + /*
- + * See if the user specified this group as one of their
- + * concurrent groups.
- + */
- +
- + for (i = 0;sgrp->sg_mem[i];i++)
- + if (strcmp (sgrp->sg_mem[i], user_name) == 0)
- + break;
- +
- + if (sgrp->sg_mem[i]) {
- + sgrp->sg_mem = del_list (sgrp->sg_mem, user_name);
- + group_changed = 1;
- + }
- + for (i = 0;sgrp->sg_adm[i];i++)
- + if (strcmp (sgrp->sg_adm[i], user_name) == 0)
- + break;
- +
- + if (sgrp->sg_adm[i]) {
- + sgrp->sg_adm = del_list (sgrp->sg_adm, user_name);
- + group_changed = 1;
- + }
- + if (! group_changed)
- + continue;
- +
- + if (! sgr_update (sgrp)) {
- + fprintf (stderr, "%s: error updating group entry\n",
- + Prog);
- + exit (1);
- + }
- + #ifdef NDBM
- + /*
- + * Update the DBM group file with the new entry as well.
- + */
- +
- + if (! sgr_dbm_update (sgrp)) {
- + fprintf (stderr, "%s: cannot update dbm group entry\n",
- + Prog);
- + exit (1);
- + }
- + #endif
- + }
- + #endif
- + }
- +
- + /*
- + * close_files - close all of the files that were opened
- + *
- + * close_files() closes all of the files that were opened for this
- + * new user. This causes any modified entries to be written out.
- + */
- +
- + close_files ()
- + {
- + if (! pw_close ()) {
- + fprintf (stderr, "%s: cannot rewrite password file\n", Prog);
- + exit (1);
- + }
- + if (! spw_close ()) {
- + fprintf (stderr, "%s: cannot rewrite shadow password file\n",
- + Prog);
- + exit (1);
- + }
- + if (! gr_close ()) {
- + fprintf (stderr, "%s: cannot rewrite group file\n",
- + Prog);
- + exit (1);
- + }
- + (void) gr_unlock ();
- + #ifdef SHADOWGRP
- + if (! sgr_close ()) {
- + fprintf (stderr, "%s: cannot rewrite shadow group file\n",
- + Prog);
- + exit (1);
- + }
- + (void) sgr_unlock ();
- + #endif
- + (void) pw_unlock ();
- + }
- +
- + /*
- + * open_files - lock and open the password files
- + *
- + * open_files() opens the two password files.
- + */
- +
- + open_files ()
- + {
- + if (! pw_lock ()) {
- + fprintf (stderr, "%s: unable to lock password file\n", Prog);
- + exit (1);
- + }
- + if (! pw_open (O_RDWR)) {
- + fprintf (stderr, "%s: unable to open password file\n", Prog);
- + 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 ()) {
- + fprintf (stderr, "%s: unable to lock group file\n", Prog);
- + exit (1);
- + }
- + if (! gr_open (O_RDWR)) {
- + fprintf (stderr, "%s: cannot open group file\n", Prog);
- + exit (1);
- + }
- + #ifdef SHADOWGRP
- + if (! sgr_lock ()) {
- + fprintf (stderr, "%s: unable to lock shadow group file\n", Prog);
- + exit (1);
- + }
- + if (! sgr_open (O_RDWR)) {
- + fprintf (stderr, "%s: cannot open shadow group file\n", Prog);
- + exit (1);
- + }
- + #endif
- + }
- +
- + /*
- + * update_user - delete the user entries
- + *
- + * update_user() deletes the password file entries for this user
- + * and will update the group entries as required.
- + */
- +
- + update_user ()
- + {
- + struct passwd *pwd;
- +
- + if (! pw_remove (user_name))
- + fprintf (stderr, "%s: error deleting password entry\n", Prog);
- +
- + if (! spw_remove (user_name))
- + fprintf (stderr, "%s: error deleting shadow password entry\n",
- + Prog);
- +
- + #if defined(DBM) || defined(NDBM)
- + if (access ("/etc/passwd.pag", 0) == 0) {
- + if ((pwd = getpwnam (user_name)) && ! pw_dbm_remove (pwd))
- + fprintf (stderr,
- + "%s: error deleting password dbm entry\n",
- + Prog);
- + }
- +
- + /*
- + * If the user's UID is a duplicate the duplicated entry needs
- + * to be updated so that a UID match can be found in the DBM
- + * files.
- + */
- +
- + for (pw_rewind (), pwd = pw_next ();pwd;pwd = pw_next ()) {
- + if (pwd->pw_uid == user_id) {
- + pw_dbm_update (pwd);
- + break;
- + }
- + }
- + #endif
- + #ifdef NDBM
- + if (access ("/etc/shadow.pag", 0) == 0 && ! sp_dbm_remove (user_name))
- + fprintf (stderr, "%s: error deleting shadow passwd dbm entry\n",
- + Prog);
- + #endif
- + }
- +
- + /*
- + * main - useradd command
- + */
- +
- + main (argc, argv)
- + int argc;
- + char **argv;
- + {
- + struct passwd *pwd;
- + int arg;
- + extern int optind;
- + extern char *optarg;
- +
- + /*
- + * Get my name so that I can use it to report errors.
- + */
- +
- + if (Prog = strrchr (argv[0], '/'))
- + Prog++;
- + else
- + Prog = argv[0];
- +
- + #ifdef USE_SYSLOG
- + openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
- + #endif
- +
- + /*
- + * The open routines for the DBM files don't use read-write
- + * as the mode, so we have to clue them in.
- + */
- +
- + #if defined(DBM) || defined(NDBM)
- + pw_dbm_mode = O_RDWR;
- + #endif
- + #ifdef NDBM
- + sp_dbm_mode = O_RDWR;
- + gr_dbm_mode = O_RDWR;
- + #ifdef SHADOWGRP
- + sg_dbm_mode = O_RDWR;
- + #endif
- + #endif
- + while ((arg = getopt (argc, argv, "r")) != EOF)
- + if (arg != 'r')
- + usage ();
- + else
- + rflg++;
- +
- + if (optind == argc)
- + usage ();
- +
- + /*
- + * Start with a quick check to see if the user exists.
- + */
- +
- + strncpy (user_name, argv[argc - 1], BUFSIZ);
- +
- + 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);
- +
- + /*
- + * Do the hard stuff - open the files, create the user entries,
- + * create the home directory, then close and update the files.
- + */
- +
- + open_files ();
- +
- + update_user ();
- + update_groups ();
- +
- + if (rflg)
- + rmdir (user_home);
- +
- + close_files ();
- + exit (0);
- + /*NOTREACHED*/
- + }
- *** /dev/null Fri Jun 7 11:02:59 1991
- --- usermod.c Fri Jun 7 11:10:08 1991
- ***************
- *** 0 ****
- --- 1,1149 ----
- + /*
- + * Copyright 1991, John F. Haugh II
- + * 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.
- + */
- +
- + #ifndef lint
- + static char sccsid[] = "@(#)usermod.c 3.1 11:08:35 6/7/91";
- + #endif
- +
- + #include <sys/types.h>
- + #include <sys/stat.h>
- + #include <stdio.h>
- + #include <errno.h>
- + #include <pwd.h>
- + #include <grp.h>
- + #include <ctype.h>
- + #include <fcntl.h>
- + #include <time.h>
- +
- + #ifdef BSD
- + #include <strings.h>
- + #else
- + #include <string.h>
- + #endif
- +
- + #include "config.h"
- + #include "shadow.h"
- +
- + #ifdef USE_SYSLOG
- + #include <syslog.h>
- +
- + #ifndef LOG_WARN
- + #define LOG_WARN LOG_WARNING
- + #endif
- + #endif
- +
- + #ifndef NGROUPS_MAX
- + #define NGROUPS_MAX 64
- + #endif
- +
- + char user_name[BUFSIZ];
- + char user_newname[BUFSIZ];
- + uid_t user_id;
- + uid_t user_newid;
- + gid_t user_gid;
- + char user_comment[BUFSIZ];
- + char user_home[BUFSIZ];
- + char user_newhome[BUFSIZ];
- + char user_shell[BUFSIZ];
- + long user_expire;
- + long user_inactive;
- + int user_ngroups;
- + gid_t user_groups[NGROUPS_MAX];
- + struct passwd user_pwd;
- + struct spwd user_spwd;
- +
- + char *Prog;
- +
- + int uflg; /* specify user ID for new account */
- + int oflg; /* permit non-unique user ID to be specified with -u */
- + int gflg; /* primary group ID for new account */
- + int Gflg; /* secondary group set for new account */
- + int dflg; /* home directory for new account */
- + int sflg; /* shell program for new account */
- + int cflg; /* comment (GECOS) field for new account */
- + int mflg; /* create user's home directory if it doesn't exist */
- + int fflg; /* days until account with expired password is locked */
- + int eflg; /* days after password changed before it becomes expired */
- + int lflg; /* new user name for user */
- +
- + #if defined(DBM) || defined(NDBM)
- + extern int pw_dbm_mode;
- + #endif
- + #ifdef NDBM
- + extern int sp_dbm_mode;
- + extern int gr_dbm_mode;
- + extern int sg_dbm_mode;
- + #endif
- + extern FILE *fopen();
- + extern int fclose();
- + extern char *malloc();
- + extern char *mktemp();
- +
- + extern struct group *getgrnam();
- + extern struct group *getgrgid();
- + extern struct group *gr_next();
- + extern struct group *gr_locate();
- + extern int gr_lock();
- + extern int gr_unlock();
- + extern int gr_rewind();
- + extern int gr_open();
- +
- + #ifdef SHADOWGRP
- + extern struct sgrp *sgr_next();
- + extern int sgr_lock();
- + extern int sgr_unlock();
- + extern int sgr_rewind();
- + extern int sgr_open();
- + #endif
- +
- + extern struct passwd *getpwnam();
- + extern struct passwd *pw_next();
- + extern struct passwd *pw_locate();
- + extern int pw_lock();
- + extern int pw_unlock();
- + extern int pw_rewind();
- + extern int pw_open();
- +
- + extern int spw_lock();
- + extern int spw_unlock();
- + extern int spw_open();
- + extern int spw_locate();
- +
- + #define DAY (24L*3600L)
- + #define WEEK (7*DAY)
- +
- + #ifdef ITI_AGING
- + #define SCALE (1)
- + #else
- + #define SCALE (DAY)
- + #endif
- +
- + /*
- + * days and juldays are used to compute the number of days in the
- + * current month, and the cummulative number of days in the preceding
- + * months. they are declared so that january is 1, not 0.
- + */
- +
- + static short days[13] = { 0,
- + 31, 28, 31, 30, 31, 30, /* JAN - JUN */
- + 31, 31, 30, 31, 30, 31 }; /* JUL - DEC */
- +
- + static short juldays[13] = { 0,
- + 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
- + *
- + * rename is provided for systems which do not include the rename()
- + * system call.
- + */
- +
- + int
- + rename (begin, end)
- + char *begin;
- + char *end;
- + {
- + struct stat s1, s2;
- + extern int errno;
- + int orig_err = errno;
- +
- + if (stat (begin, &s1))
- + return -1;
- +
- + if (stat (end, &s2)) {
- + errno = orig_err;
- + } else {
- +
- + /*
- + * See if this is a cross-device link. We do this to
- + * insure that the link below has a chance of working.
- + */
- +
- + if (s1.st_dev != s2.st_dev) {
- + errno = EXDEV;
- + return -1;
- + }
- +
- + /*
- + * See if we can unlink the existing destination
- + * file. If the unlink works the directory is writable,
- + * so there is no need here to figure that out.
- + */
- +
- + if (unlink (end))
- + return -1;
- + }
- +
- + /*
- + * Now just link the original name to the final name. If there
- + * was no file previously, this link will fail if the target
- + * directory isn't writable. The unlink will fail if the source
- + * directory isn't writable, but life stinks ...
- + */
- +
- + if (link (begin, end) || unlink (begin))
- + return -1;
- +
- + return 0;
- + }
- + #endif
- +
- + /*
- + * strtoday - compute the number of days since 1970.
- + *
- + * the total number of days prior to the current date is
- + * computed. january 1, 1970 is used as the origin with
- + * it having a day number of 0.
- + */
- +
- + long
- + strtoday (str)
- + char *str;
- + {
- + char slop[2];
- + int month;
- + int day;
- + int year;
- + long total;
- +
- + /*
- + * start by separating the month, day and year. this is
- + * a chauvanistic program - it only takes date input in
- + * the standard USA format.
- + */
- +
- + if (sscanf (str, "%d/%d/%d%c", &month, &day, &year, slop) != 3)
- + return -1;
- +
- + /*
- + * the month, day of the month, and year are checked for
- + * correctness and the year adjusted so it falls between
- + * 1970 and 2069.
- + */
- +
- + if (month < 1 || month > 12)
- + return -1;
- +
- + if (day < 1)
- + return -1;
- +
- + if ((month != 2 || (year % 4) != 0) && day > days[month])
- + return -1;
- + else if ((month == 2 && (year % 4) == 0) && day > 29)
- + return -1;
- +
- + if (year < 0)
- + return -1;
- + else if (year < 69)
- + year += 2000;
- + else if (year < 99)
- + year += 1900;
- +
- + if (year < 1970 || year > 2069)
- + return -1;
- +
- + /*
- + * the total number of days is the total number of days in all
- + * the whole years, plus the number of leap days, plus the
- + * number of days in the whole months preceding, plus the number
- + * of days so far in the month.
- + */
- +
- + total = (long) ((year - 1970) * 365L) + (((year + 1) - 1970) / 4);
- + total += (long) juldays[month] + (month > 2 && (year % 4) == 0 ? 1:0);
- + total += (long) day - 1;
- +
- + return total;
- + }
- +
- + /*
- + * add_list - add a member to a list of group members
- + *
- + * the array of member names is searched for the new member
- + * name, and if not present it is added to a freshly allocated
- + * list of users.
- + */
- +
- + char **
- + add_list (list, member)
- + char **list;
- + char *member;
- + {
- + int i;
- + char **tmp;
- +
- + /*
- + * Scan the list for the new name. Return the original list
- + * pointer if it is present.
- + */
- +
- + for (i = 0;list[i] != (char *) 0;i++)
- + if (strcmp (list[i], member) == 0)
- + return list;
- +
- + /*
- + * Allocate a new list pointer large enough to hold all the
- + * old entries, and the new entries as well.
- + */
- +
- + if (! (tmp = (char **) malloc ((i + 2) * sizeof member)))
- + return 0;
- +
- + /*
- + * Copy the original list to the new list, then append the
- + * new member and NULL terminate the result. This new list
- + * is returned to the invoker.
- + */
- +
- + for (i = 0;list[i] != (char *) 0;i++)
- + tmp[i] = list[i];
- +
- + tmp[i++] = strdup (member);
- + tmp[i] = (char *) 0;
- +
- + return tmp;
- + }
- +
- + /*
- + * del_list - delete a member from a list of group members
- + *
- + * the array of member names is searched for the old member
- + * name, and if present it is deleted from a freshly allocated
- + * list of users.
- + */
- +
- + char **
- + del_list (list, member)
- + char **list;
- + char *member;
- + {
- + int i, j;
- + char **tmp;
- +
- + /*
- + * Scan the list for the new name. Return the original list
- + * pointer if it is present.
- + */
- +
- + for (i = j = 0;list[i] != (char *) 0;i++)
- + if (strcmp (list[i], member))
- + j++;
- +
- + if (j == i)
- + return list;
- +
- + /*
- + * Allocate a new list pointer large enough to hold all the
- + * old entries, and the new entries as well.
- + */
- +
- + if (! (tmp = (char **) malloc ((j + 2) * sizeof member)))
- + return 0;
- +
- + /*
- + * Copy the original list to the new list, then append the
- + * new member and NULL terminate the result. This new list
- + * is returned to the invoker.
- + */
- +
- + for (i = j = 0;list[i] != (char *) 0;i++)
- + if (strcmp (list[i], member))
- + tmp[j++] = list[i];
- +
- + tmp[j] = (char *) 0;
- +
- + return tmp;
- + }
- +
- + /*
- + * get_groups - convert a list of group names to an array of group IDs
- + *
- + * get_groups() takes a comma-separated list of group names and
- + * converts it to an array of group ID values. Any unknown group
- + * names are reported as errors.
- + */
- +
- + int
- + get_groups (list)
- + char *list;
- + {
- + char *cp;
- + struct group *grp;
- + int errors = 0;
- +
- + /*
- + * Initialize the list to be empty
- + */
- +
- + user_ngroups = 0;
- +
- + if (! *list)
- + return 0;
- +
- + /*
- + * So long as there is some data to be converted, strip off
- + * each name and look it up. A mix of numerical and string
- + * values for group identifiers is permitted.
- + */
- +
- + do {
- + /*
- + * Strip off a single name from the list
- + */
- +
- + if (cp = strchr (list, ','))
- + *cp++ = '\0';
- +
- + /*
- + * Names starting with digits are treated as numerical
- + * GID values, otherwise the string is looked up as is.
- + */
- +
- + if (isdigit (*list))
- + grp = getgrgid (atoi (list));
- + else
- + grp = getgrnam (list);
- +
- + /*
- + * There must be a match, either by GID value or by
- + * string name.
- + */
- +
- + if (! grp) {
- + fprintf (stderr, "%s: unknown group %s\n", Prog, list);
- + errors++;
- + }
- +
- + /*
- + * Add the GID value from the group file to the user's
- + * list of groups.
- + */
- +
- + user_groups[user_ngroups++] = grp->gr_gid;
- +
- + list = cp;
- + } while (list);
- +
- + /*
- + * Any errors in finding group names are fatal
- + */
- +
- + if (errors)
- + return -1;
- +
- + return 0;
- + }
- +
- + /*
- + * usage - display usage message and exit
- + */
- +
- + usage ()
- + {
- + fprintf (stderr,
- + "usage: %s [-u uid [-o]] [-g group] [-G group,...] \n", Prog);
- + fprintf (stderr,
- + "\t\t[-d home [-m]] [-s shell] [-c comment] [-l new_name]\n");
- + fprintf (stderr,
- + "\t\t[-f inactive] [-e expire] name\n");
- +
- + exit (2);
- + }
- +
- + /*
- + * new_pwent - initialize the values in a password file entry
- + *
- + * new_pwent() takes all of the values that have been entered and
- + * fills in a (struct passwd) with them.
- + */
- +
- + void
- + new_pwent (pwent)
- + struct passwd *pwent;
- + {
- + if (lflg)
- + pwent->pw_name = strdup (user_newname);
- +
- + if (uflg)
- + pwent->pw_uid = user_newid;
- +
- + if (gflg)
- + pwent->pw_gid = user_gid;
- +
- + if (cflg)
- + pwent->pw_gecos = strdup (user_comment);
- +
- + if (dflg)
- + pwent->pw_dir = strdup (user_newhome);
- +
- + if (sflg)
- + pwent->pw_shell = strdup (user_shell);
- + }
- +
- + /*
- + * new_spent - initialize the values in a shadow password file entry
- + *
- + * new_spent() takes all of the values that have been entered and
- + * fills in a (struct spwd) with them.
- + */
- +
- + void
- + new_spent (spent)
- + struct spwd *spent;
- + {
- + if (lflg)
- + spent->sp_namp = strdup (user_newname);
- +
- + spent->sp_inact = user_inactive;
- + spent->sp_expire = user_expire;
- + }
- +
- + /*
- + * grp_update - add user to secondary group set
- + *
- + * grp_update() takes the secondary group set given in user_groups
- + * and adds the user to each group given by that set.
- + */
- +
- + void
- + grp_update ()
- + {
- + int i;
- + int is_member;
- + int was_member;
- + int was_admin;
- + struct group *grp;
- + struct sgrp *sgrp;
- +
- + /*
- + * Lock and open the group file. This will load all of the group
- + * entries.
- + */
- +
- + if (! gr_lock ()) {
- + fprintf (stderr, "%s: error locking group file\n", Prog);
- + exit (1);
- + }
- + if (! gr_open (O_RDWR)) {
- + fprintf (stderr, "%s: error opening group file\n", Prog);
- + exit (1);
- + }
- + #ifdef SHADOWGRP
- + if (! sgr_lock ()) {
- + fprintf (stderr, "%s: error locking shadow group file\n", Prog);
- + exit (1);
- + }
- + if (! sgr_open (O_RDWR)) {
- + fprintf (stderr, "%s: error opening shadow group file\n", Prog);
- + exit (1);
- + }
- + #endif
- +
- + /*
- + * Scan through the entire group file looking for the groups that
- + * the user is a member of.
- + */
- +
- + for (gr_rewind (), grp = gr_next ();grp;grp = gr_next ()) {
- +
- + /*
- + * See if the user specified this group as one of their
- + * concurrent groups.
- + */
- +
- + for (i = 0;i < user_ngroups;i++)
- + if (grp->gr_gid == user_groups[i])
- + break;
- +
- + is_member = i == user_ngroups ? -1:i;
- +
- + for (i = 0;grp->gr_mem[i];i++)
- + if (strcmp (user_name, grp->gr_mem[i]) == 0)
- + break;
- +
- + was_member = grp->gr_mem[i] ? i:-1;
- +
- + if (is_member == -1 && was_member == -1)
- + continue;
- +
- + if (was_member >= 0 && (! Gflg || is_member >= 0)) {
- + if (lflg) {
- + grp->gr_mem = del_list (grp->gr_mem,
- + user_name);
- + grp->gr_mem = add_list (grp->gr_mem,
- + user_newname);
- + #ifdef USE_SYSLOG
- + syslog (LOG_INFO,
- + "change `%s' to `%s' in group `%s'\n",
- + user_name, user_newname, grp->gr_name);
- + #endif
- + }
- + } else if (was_member >= 0 && Gflg && is_member < 0) {
- + grp->gr_mem = del_list (grp->gr_mem, user_name);
- + #ifdef USE_SYSLOG
- + syslog (LOG_INFO, "delete `%s' from group `%s'\n",
- + user_name, grp->gr_name);
- + #endif
- + } else if (was_member < 0 && Gflg && is_member >= 0) {
- + grp->gr_mem = add_list (grp->gr_mem,
- + lflg ? user_newname:user_name);
- + #ifdef USE_SYSLOG
- + syslog (LOG_INFO, "add `%s' to group `%s'\n",
- + lflg ? user_newname:user_name, grp->gr_name);
- + #endif
- + } else
- + continue;
- +
- + if (! gr_update (grp)) {
- + fprintf (stderr, "%s: error adding new group entry\n",
- + 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 add new dbm group entry\n",
- + Prog);
- + exit (1);
- + }
- + #endif
- + }
- +
- + #ifdef SHADOWGRP
- + /*
- + * Scan through the entire shadow group file looking for the groups
- + * that the user is a member of.
- + */
- +
- + for (sgr_rewind (), sgrp = sgr_next ();sgrp;sgrp = sgr_next ()) {
- +
- + /*
- + * See if the user was a member of this group
- + */
- +
- + for (i = 0;sgrp->sg_mem[i];i++)
- + if (strcmp (sgrp->sg_mem[i], user_name) == 0)
- + break;
- +
- + was_member = sgrp->sg_mem[i] ? i:-1;
- +
- + /*
- + * See if the user was an administrator of this group
- + */
- +
- + for (i = 0;sgrp->sg_adm[i];i++)
- + if (strcmp (sgrp->sg_adm[i], user_name) == 0)
- + break;
- +
- + was_admin = sgrp->sg_adm[i] ? i:-1;
- +
- + /*
- + * See if the user specified this group as one of their
- + * concurrent groups.
- + */
- +
- + for (i = 0;i < user_ngroups;i++) {
- + if (! (grp = gr_locate (sgrp->sg_name)))
- + continue;
- +
- + if (grp->gr_gid == user_groups[i])
- + break;
- + }
- + is_member = i == user_ngroups ? -1:i;
- +
- + if (is_member == -1 && was_admin == -1 && was_member == -1)
- + continue;
- +
- + if (was_admin >= 0 && lflg) {
- + sgrp->sg_adm = del_list (sgrp->sg_adm, user_name);
- + sgrp->sg_adm = add_list (sgrp->sg_adm, user_newname);
- + #ifdef USE_SYSLOG
- + syslog (LOG_INFO, "change admin `%s' to `%s' in shadow group `%s'\n",
- + user_name, user_newname, sgrp->sg_name);
- + #endif
- + }
- + if (was_member >= 0 && (! Gflg || is_member >= 0)) {
- + if (lflg) {
- + sgrp->sg_mem = del_list (sgrp->sg_mem,
- + user_name);
- + sgrp->sg_mem = add_list (sgrp->sg_mem,
- + user_newname);
- + #ifdef USE_SYSLOG
- + syslog (LOG_INFO, "change `%s' to `%s' in shadow group `%s'\n",
- + user_name, user_newname, sgrp->sg_name);
- + #endif
- + }
- + } else if (was_member >= 0 && Gflg && is_member < 0) {
- + sgrp->sg_mem = del_list (sgrp->sg_mem, user_name);
- + #ifdef USE_SYSLOG
- + syslog (LOG_INFO, "delete `%s' from shadow group `%s'\n",
- + user_name, sgrp->sg_name);
- + #endif
- + } else if (was_member < 0 && Gflg && is_member >= 0) {
- + sgrp->sg_mem = add_list (sgrp->sg_mem,
- + lflg ? user_newname:user_name);
- + #ifdef USE_SYSLOG
- + syslog (LOG_INFO, "add `%s' to shadow group `%s'\n",
- + lflg ? user_newname:user_name, grp->gr_name);
- + #endif
- + } else
- + continue;
- +
- + /*
- + * Update the group entry to reflect the changes.
- + */
- +
- + if (! sgr_update (sgrp)) {
- + fprintf (stderr, "%s: error adding new group entry\n",
- + Prog);
- + exit (1);
- + }
- + #ifdef NDBM
- + /*
- + * Update the DBM group file with the new entry as well.
- + */
- +
- + if (! sgr_dbm_update (sgrp)) {
- + fprintf (stderr, "%s: cannot add new dbm group entry\n",
- + Prog);
- + exit (1);
- + }
- + #endif
- + }
- + #endif
- + }
- +
- + /*
- + * check_new_id - verify the new UID for uniqueness
- + *
- + * check_new_id() insures that the new UID does not exist already.
- + * It does this by checking that the UID has changed and that there
- + * is no current entry for this user ID.
- + */
- +
- + int
- + check_new_id ()
- + {
- + /*
- + * First, the easy stuff. If the ID can be duplicated, or if
- + * the ID didn't really change, just return. If the ID didn't
- + * change, turn off those flags. No sense doing needless work.
- + */
- +
- + if (oflg)
- + return 0;
- +
- + if (user_id == user_newid) {
- + uflg = lflg = 0;
- + return 0;
- + }
- + if (getpwuid (user_newid))
- + return -1;
- +
- + return 0;
- + }
- +
- + /*
- + * process_flags - perform command line argument setting
- + *
- + * process_flags() interprets the command line arguments and sets
- + * the values that the user will be created with accordingly. The
- + * values are checked for sanity.
- + */
- +
- + void
- + process_flags (argc, argv)
- + int argc;
- + char **argv;
- + {
- + extern int optind;
- + extern char *optarg;
- + struct group *grp;
- + struct passwd *pwd;
- + struct spwd *spwd;
- + long l;
- + int anyflag = 0;
- + int arg;
- +
- + if (argc == 1 || argv[argc - 1][0] == '-')
- + usage ();
- +
- + if (! (pwd = getpwnam (argv[argc - 1]))) {
- + fprintf (stderr, "%s: user %s does not exist\n",
- + Prog, argv[argc - 1]);
- + exit (6);
- + }
- + strcpy (user_name, pwd->pw_name);
- + user_id = pwd->pw_uid;
- + user_gid = pwd->pw_gid;
- + strcpy (user_comment, pwd->pw_gecos);
- + strcpy (user_home, pwd->pw_dir);
- + strcpy (user_shell, pwd->pw_shell);
- +
- + if (spwd = getspnam (user_name)) {
- + user_expire = spwd->sp_expire;
- + user_inactive = spwd->sp_inact;
- + }
- + while ((arg = getopt (argc, argv, "u:og:G:d:s:c:mf:e:l:")) != EOF) {
- + switch (arg) {
- + case 'c':
- + if (strcmp (optarg, user_comment)) {
- + cflg++;
- + strncpy (user_comment, optarg, BUFSIZ);
- + }
- + break;
- + case 'd':
- + dflg++;
- + strncpy (user_newhome, optarg, BUFSIZ);
- + break;
- + case 'e':
- + l = strtoday (optarg);
- + #ifdef ITI_AGING
- + l *= DAY;
- + #endif
- + if (l != user_expire) {
- + eflg++;
- + user_expire = l;
- + }
- + break;
- + case 'f':
- + if (user_inactive != atoi (optarg)) {
- + fflg++;
- + user_inactive = atoi (optarg);
- + }
- + break;
- + case 'g':
- + if (isdigit (optarg[0]))
- + grp = getgrgid (atoi (optarg));
- + else
- + grp = getgrnam (optarg);
- +
- + if (! grp) {
- + fprintf (stderr,
- + "%s: unknown group %s\n",
- + optarg);
- + exit (1);
- + }
- + if (grp->gr_gid != user_gid) {
- + gflg++;
- + user_gid = grp->gr_gid;
- + }
- + break;
- + case 'G':
- + Gflg++;
- + if (get_groups (optarg))
- + exit (1);
- +
- + break;
- + case 'l':
- + if (strcmp (user_name, optarg)) {
- + lflg++;
- + strcpy (user_newname, optarg);
- + }
- + break;
- + case 'm':
- + if (! dflg)
- + usage ();
- +
- + mflg++;
- + break;
- + case 'o':
- + if (! uflg)
- + usage ();
- +
- + oflg++;
- + break;
- + case 's':
- + if (strcmp (user_shell, optarg)) {
- + strncpy (user_shell, optarg, BUFSIZ);
- + sflg++;
- + }
- + break;
- + case 'u':
- + uflg++;
- + user_newid = atoi (optarg);
- + break;
- + default:
- + usage ();
- + }
- + anyflag++;
- + }
- + if (optind != argc - 1)
- + usage ();
- +
- + if (dflg && strcmp (user_home, user_newhome) == 0)
- + dflg = mflg = 0;
- +
- + if (uflg && user_id == user_newid)
- + uflg = oflg = 0;
- +
- + if (lflg && getpwnam (user_newname)) {
- + fprintf (stderr, "%s: user %s exists\n", user_newname);
- + exit (9);
- + }
- + }
- +
- + /*
- + * close_files - close all of the files that were opened
- + *
- + * close_files() closes all of the files that were opened for this
- + * new user. This causes any modified entries to be written out.
- + */
- +
- + close_files ()
- + {
- + if (! pw_close ()) {
- + fprintf (stderr, "%s: cannot rewrite password file\n", Prog);
- + exit (1);
- + }
- + if (! spw_close ()) {
- + fprintf (stderr, "%s: cannot rewrite shadow password file\n",
- + Prog);
- + exit (1);
- + }
- + if (user_ngroups > 0) {
- + if (! gr_close ()) {
- + fprintf (stderr, "%s: cannot rewrite group file\n",
- + Prog);
- + exit (1);
- + }
- + (void) gr_unlock ();
- + #ifdef SHADOWGRP
- + if (! sgr_close ()) {
- + fprintf (stderr, "%s: cannot rewrite shadow group file\n",
- + Prog);
- + exit (1);
- + }
- + #endif
- + }
- + (void) pw_unlock ();
- + }
- +
- + /*
- + * open_files - lock and open the password files
- + *
- + * open_files() opens the two password files.
- + */
- +
- + open_files ()
- + {
- + if (! pw_lock ()) {
- + fprintf (stderr, "%s: unable to lock password file\n", Prog);
- + exit (1);
- + }
- + if (! pw_open (O_RDWR)) {
- + fprintf (stderr, "%s: unable to open password file\n", Prog);
- + 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);
- + }
- + }
- +
- + /*
- + * usr_update - create the user entries
- + *
- + * usr_update() creates the password file entries for this user
- + * and will update the group entries if required.
- + */
- +
- + usr_update ()
- + {
- + struct passwd pwent;
- + struct spwd spent;
- + struct passwd *pwd;
- + struct spwd *spwd;
- +
- + pwd = pw_locate (user_name);
- + pwent = *pwd;
- +
- + spwd = spw_locate (user_name);
- + spent = *spwd;
- +
- + new_pwent (&pwent);
- + new_spent (&spent);
- +
- + if (lflg || uflg || gflg || cflg || dflg || sflg) {
- + if (! pw_update (&pwent)) {
- + fprintf (stderr, "%s: error changing password entry\n");
- + exit (1);
- + }
- + if (lflg && ! pw_remove (user_name)) {
- + fprintf (stderr, "%s: error removing password entry\n");
- + exit (1);
- + }
- + #if defined(DBM) || defined(NDBM)
- + if (access ("/etc/passwd.pag", 0) == 0) {
- + if (! pw_dbm_update (&pwent)) {
- + fprintf (stderr, "%s: error adding password dbm entry\n",
- + Prog);
- + exit (1);
- + }
- + if (lflg && (pwd = getpwnam (user_name)) && ! pw_dbm_remove (pwd)) {
- + fprintf (stderr, "%s: error removing passwd dbm entry\n",
- + Prog);
- + exit (1);
- + }
- + }
- + #endif
- + }
- + if (lflg || eflg || fflg) {
- + if (! spw_update (&spent)) {
- + fprintf (stderr, "%s: error adding new shadow password entry\n",
- + Prog);
- + exit (1);
- + }
- + if (lflg && ! spw_remove (user_name)) {
- + fprintf (stderr, "%s: error removing shadow password entry\n",
- + Prog);
- + exit (1);
- + }
- + }
- + #ifdef NDBM
- + if (access ("/etc/shadow.pag", 0) == 0) {
- + if (! sp_dbm_update (&spent)) {
- + fprintf (stderr, "%s: error updating shadow passwd dbm entry\n",
- + Prog);
- + exit (1);
- + }
- + if (lflg && ! sp_dbm_remove (user_name)) {
- + fprintf (stderr, "%s: error removing shadow passwd db entry\n",
- + Prog);
- + exit (1);
- + }
- + }
- + #endif
- + if (Gflg || lflg)
- + grp_update ();
- + }
- +
- + /*
- + * move_home - move the user's home directory
- + *
- + * move_home() creates the user's home directory if it does not
- + * already exist. It will be created mode 755 owned by the user
- + * with the user's default group.
- + */
- +
- + 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);
- + exit (12);
- + }
- + }
- + if (uflg || gflg)
- + chown (dflg ? user_newhome:user_home, user_id, user_gid);
- + }
- +
- + /*
- + * main - useradd command
- + */
- +
- + main (argc, argv)
- + int argc;
- + char **argv;
- + {
- + /*
- + * Get my name so that I can use it to report errors.
- + */
- +
- + if (Prog = strrchr (argv[0], '/'))
- + Prog++;
- + else
- + Prog = argv[0];
- +
- + #ifdef USE_SYSLOG
- + openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
- + #endif
- +
- + /*
- + * The open routines for the DBM files don't use read-write
- + * as the mode, so we have to clue them in.
- + */
- +
- + #if defined(DBM) || defined(NDBM)
- + pw_dbm_mode = O_RDWR;
- + #endif
- + #ifdef NDBM
- + sp_dbm_mode = O_RDWR;
- + gr_dbm_mode = O_RDWR;
- + #ifdef SHADOWGRP
- + sg_dbm_mode = O_RDWR;
- + #endif
- + #endif
- + process_flags (argc, argv);
- +
- + /*
- + * Do the hard stuff - open the files, change the user entries,
- + * change the home directory, then close and update the files.
- + */
- +
- + open_files ();
- +
- + usr_update ();
- +
- + close_files ();
- +
- + if (mflg)
- + move_home ();
- +
- + exit (0);
- + /*NOTREACHED*/
- + }
- --
- John F. Haugh II | Distribution to | UUCP: ...!cs.utexas.edu!rpp386!jfh
- Ma Bell: (512) 255-8251 | GEnie PROHIBITED :-) | Domain: jfh@rpp386.cactus.org
- "If liberals interpreted the 2nd Amendment the same way they interpret the
- rest of the Constitution, gun ownership would be mandatory."
-