From 330e74b7e9b50884742f157e67ecec1b7cf49142 Mon Sep 17 00:00:00 2001 From: gdr-ftp Date: Mon, 15 Feb 1999 00:22:11 +0000 Subject: [PATCH] Makefile, mklink.data, mkso.data, newuser.desc, newuser.rez: - initial checkin README: - updated installation notes installit, newuserv.c: - deleted (obsolete) newuser.1: - renamed to newuser.8 newuser.c, newuser.8: - account home directories are now made in /home rather than /user - made all the routines internal to this file to be class 'static' - fit sources into GNO base distribution builds - added checks for parsing NEWID_FILE - added various conchecks to prevent buffer overflow and similar problems - ensure the password is at least MIN_PASSWD_LEN characters long - don't set the terminal type; that is the responsibility of initd/getty. - instead of creating explicit files in the user's home directory, copy every file that is in the SKELETONS directory. - account creation is now logged via syslogd - added -g flag for selecting non-default group ids - check to ensure that the new uid returned by get_next_uid is not already in use; if it is, then log a warning via syslog, skip it, and get another uid --- usr.sbin/newuser/Makefile | 15 + usr.sbin/newuser/README | 24 +- usr.sbin/newuser/installit | 9 - usr.sbin/newuser/mklink.data | 9 + usr.sbin/newuser/mkso.data | 8 + usr.sbin/newuser/newuser.1 | 52 ---- usr.sbin/newuser/newuser.8 | 106 ++++--- usr.sbin/newuser/newuser.c | 552 +++++++++++++++++++++++----------- usr.sbin/newuser/newuser.desc | 23 ++ usr.sbin/newuser/newuser.rez | 18 ++ usr.sbin/newuser/newuserv.c | 16 - 11 files changed, 532 insertions(+), 300 deletions(-) create mode 100644 usr.sbin/newuser/Makefile delete mode 100644 usr.sbin/newuser/installit create mode 100644 usr.sbin/newuser/mklink.data create mode 100644 usr.sbin/newuser/mkso.data delete mode 100644 usr.sbin/newuser/newuser.1 create mode 100644 usr.sbin/newuser/newuser.desc create mode 100644 usr.sbin/newuser/newuser.rez delete mode 100644 usr.sbin/newuser/newuserv.c diff --git a/usr.sbin/newuser/Makefile b/usr.sbin/newuser/Makefile new file mode 100644 index 0000000..8f00ba3 --- /dev/null +++ b/usr.sbin/newuser/Makefile @@ -0,0 +1,15 @@ +# +# $Id: Makefile,v 1.1 1999/02/15 00:22:10 gdr-ftp Exp $ +# + +PROG = newuser +SRCS = newuser.c +LDADD = -lcrypt -lcontrib +DEBUG = 25 +OPTIMIZE= 0 +CFLAGS += -D__STACK_CHECK__ +STACK = 4096 # observed: 940 +BINDIR = /usr/sbin +CHAPTER = 8 + +.INCLUDE: /src/gno/prog.mk diff --git a/usr.sbin/newuser/README b/usr.sbin/newuser/README index fb81a88..11e2bc1 100644 --- a/usr.sbin/newuser/README +++ b/usr.sbin/newuser/README @@ -1,7 +1,17 @@ -After running the 'install' program, you need to create the files -/var/adm/newuser/newid and /var/adm/newuser/gshrc. The latter is simply -a template gshrc file that all new users will be given. The former is -a file with a single integer (1-5 digits) and *nothing else*. New users -will be assigned the userid found in this file each time newuser is run, -and the userid will be automatically incremented by newuser. So you only -have to set it up once. +$Id: README,v 1.2 1999/02/15 00:22:10 gdr-ftp Exp $ + +In order to run newuser/newuserv, the following files must exist. They +are installed as part of the GNO base distribution, but you may have to +install them manually if you received newuser/newuserv as a standalone +archive: + +/home + A directory. All user home directories will be created in this + directory. +/var/adm/newuser/newid: + A text file containing the next UID that newuser/newuserv + should assign. +/var/adm/newuser/skel: + A directory. All plain files in this directory will be copied + into a user's $HOME directory, when $HOME is created. It is normal + to have a skelton glogin and gshrc in here. diff --git a/usr.sbin/newuser/installit b/usr.sbin/newuser/installit deleted file mode 100644 index 5ab0c86..0000000 --- a/usr.sbin/newuser/installit +++ /dev/null @@ -1,9 +0,0 @@ -echo "Moving files to appropriate places..." -echo -mv -vi newuser /usr/sbin -mv -vi newuserv /usr/sbin -mv -vi newuser.1 /usr/man/man1/ -echo -echo "Make sure the directory /var/adm/newuser exists, and has as" -echo "template 'gshrc' file in it. Also required in that directory" -echo "is the 'newid' file, which holds the next available userid." diff --git a/usr.sbin/newuser/mklink.data b/usr.sbin/newuser/mklink.data new file mode 100644 index 0000000..38f2ee0 --- /dev/null +++ b/usr.sbin/newuser/mklink.data @@ -0,0 +1,9 @@ +# 0 +# 1 The first column is the "real" program; the second is what _should_ +# 2 be the symlink, but for now is a copy. +# 3 All paths should be relative to the root directory. This list +# 4 should be kept sorted. +# 5 +# 6 $Id: mklink.data,v 1.1 1999/02/15 00:22:10 gdr-ftp Exp $ +# 7 +usr/sbin/newuser usr/sbin/newuserv diff --git a/usr.sbin/newuser/mkso.data b/usr.sbin/newuser/mkso.data new file mode 100644 index 0000000..0cf9e09 --- /dev/null +++ b/usr.sbin/newuser/mkso.data @@ -0,0 +1,8 @@ +# 0 +# 1 The first column is the "real" man page; the second is the .so link. +# 2 All paths should be relative to the /usr/man directory. This list +# 3 should be kept sorted. +# 4 +# 5 $Id: mkso.data,v 1.1 1999/02/15 00:22:10 gdr-ftp Exp $ +# 6 +man8/newuser.8 man8/newuserv.8 diff --git a/usr.sbin/newuser/newuser.1 b/usr.sbin/newuser/newuser.1 deleted file mode 100644 index b15e7b1..0000000 --- a/usr.sbin/newuser/newuser.1 +++ /dev/null @@ -1,52 +0,0 @@ -.TH NEWUSER 8 -.SH NAME -.nf -newuser - add a new user to the system -newuserv - add a new user to the system, subject to validation -.fi -.LP -.SH DESCRIPTION -This is -.B newuser -for GNO/ME. Its basic intent is -to let people add themselves to the system without requiring the system -administrator to do it all manually. -.LP -.B newuser -will ask for real name, account name, terminal type and password (verifying -the password once) and then create the directory /user/(account name) and -copy a template -.B gshrc -into that directory. Then it will add the user to -.B /etc/passwd -and exit. -.PP -If the -.B -v -(verify) flag is selected, everything is done as normal, except -that the new entry is appended to -.B /var/adm/newuser/newusers -instead of being appended to -.BR /etc/passwd ". " -.LP -.SH FILES -.nf -.BR /var/adm/newuser/newid " -- This file holds the next available" -userID. newuser will increment it as necessary. -.BR /var/adm/newuser/gshrc " -- This is the 'template' gshrc file" -that all new users will get. In addition to this, newuser will append -'set' commands to set $home and $user. -.BR /etc/passwd " -- Not required if you use -v. But what's the point" -in newuser if you don't have it? :) -.BR /user/ " -- Has to exist. This is where the user's home directories" -go. -.fi -.LP -.B newuser -will time out after 60 seconds of operation. -.LP -.SH AUTHOR -.nf -James Brookes -jamesb@cscihp.ecst.csuchico.edu -.fi diff --git a/usr.sbin/newuser/newuser.8 b/usr.sbin/newuser/newuser.8 index b15e7b1..1b2e068 100644 --- a/usr.sbin/newuser/newuser.8 +++ b/usr.sbin/newuser/newuser.8 @@ -1,52 +1,88 @@ -.TH NEWUSER 8 +.TH NEWUSER 8 "14 February 1999" GNO "System Administration" .SH NAME -.nf -newuser - add a new user to the system -newuserv - add a new user to the system, subject to validation -.fi -.LP +.BR newuser , +.BR newuserv +\- add a new user to the system +.SH SYNOPSIS +.BR newuser +[ +.BR -v +] [ +.B -g +.I gid +] +.br +.BR newuserv +[ +.BR -v +] [ +.B -g +.I gid +] .SH DESCRIPTION -This is +This manual page documents .B newuser -for GNO/ME. Its basic intent is +and +.B newuserv +version 1.2 for GNO. Its basic intent is to let people add themselves to the system without requiring the system administrator to do it all manually. .LP .B newuser -will ask for real name, account name, terminal type and password (verifying -the password once) and then create the directory /user/(account name) and -copy a template -.B gshrc -into that directory. Then it will add the user to +will ask for a real name, account name, terminal type and password (verifying +the password once) and then create the directory \fB/home/\fIaccount_name\fR. +.BR newuser +will also copy all the regular files from the +.BR /var/adm/newuser/skel +directory into the \fB/home/\fIaccount_name\fR directory. +It will not recurse. +Finally, it will add the appropriate entry to .B /etc/passwd -and exit. +and then exit. .PP If the .B -v -(verify) flag is selected, everything is done as normal, except -that the new entry is appended to -.B /var/adm/newuser/newusers +(verify) flag is selected, or if invoked as +.BR newuserv , +everything is done as normal, except that the new entry is appended to +.B /var/adm/newuser/pending instead of being appended to -.BR /etc/passwd ". " +.BR /etc/passwd . .LP -.SH FILES -.nf -.BR /var/adm/newuser/newid " -- This file holds the next available" -userID. newuser will increment it as necessary. -.BR /var/adm/newuser/gshrc " -- This is the 'template' gshrc file" -that all new users will get. In addition to this, newuser will append -'set' commands to set $home and $user. -.BR /etc/passwd " -- Not required if you use -v. But what's the point" -in newuser if you don't have it? :) -.BR /user/ " -- Has to exist. This is where the user's home directories" -go. -.fi +Accounts are normally created with group ID 100. The +.B -g +flag overrides this group ID. +.LP +Both +.BR newuser +and +.BR newuserv +will log created accounts via +.BR syslogd (8) +using the auth.info facility. .LP .B newuser will time out after 60 seconds of operation. -.LP +.SH FILES +.IP \fB/home\fR +The directory where new user home directories will be placed. +.IP \fB/var/adm/newuser/newid\fR +The text file containing the next available user ID. It must consist +of exactly one line, containing only a decimal number. +.BR newuser +will update this file as required. +.IP \fB/var/adm/newuser/pending\fR +This file contains all of the +.BR /etc/passwd +entries that are waiting for approval before activation. +.IP \fB/var/adm/newuser/skel\fR +All regular files in this directory will be copied to the newly created +home directory. +.SH BUGS +.BR newuser +should create a lock file in +.BR /var/locks +to ensure that a race condition with multiple instantiations is avoided. +They are currently possible. .SH AUTHOR -.nf -James Brookes -jamesb@cscihp.ecst.csuchico.edu -.fi +James Brookes. Maintained by Devin Reade. diff --git a/usr.sbin/newuser/newuser.c b/usr.sbin/newuser/newuser.c index 814ccc2..42d7078 100644 --- a/usr.sbin/newuser/newuser.c +++ b/usr.sbin/newuser/newuser.c @@ -1,85 +1,114 @@ -/* */ -/* newuser - add a new user to the system, v1.1 -- James Brookes */ -/* */ -/* Changes from 1.0 */ -/* */ -/* * Removed code to add "set $home/$user" stuff to new user's gshrc */ -/* file, per request of Phil Vandry. */ -/* * Added restriction that the new password entered must be greater */ -/* than four characters. */ -/* * Newuser will now try multiple times to open up the /etc/passwd */ -/* file, just as passwd itself does. */ -/* */ -/* Some code borrowed from Eric Shepard's passwd source. */ -/* */ -/* files: /var/adm/newuser/newid */ -/* /var/adm/newuser/newusers */ -/* /var/adm/newuser/gshrc */ -/* /user/ */ -/* */ - -/*#pragma optimize -1 */ -#pragma stacksize 512 +/* + * newuser - add a new user to the system -- James Brookes + * + * $Id: newuser.c,v 1.3 1999/02/15 00:22:11 gdr-ftp Exp $ + * + * Changes for version 1.2 (Modifications by Devin Reade) + * - account home directories are now made in /home rather than /user + * - made all the routines internal to this file to be class 'static' + * - fit sources into GNO base distribution builds + * - added checks for parsing NEWID_FILE + * - added various conchecks to prevent buffer overflow and similar + * problems + * - ensure the password is at least MIN_PASSWD_LEN characters long + * - don't set the terminal type; that is the responsibility of + * initd/getty. + * - instead of creating explicit files in the user's home directory, + * copy every file that is in the SKELETONS directory. + * - account creation is now logged via syslogd + * - added -g flag for selecting non-default group ids + * - check to ensure that the new uid returned by get_next_uid is + * not already in use; if it is, then log a warning via syslog, + * skip it, and get another uid + * + * Changes for version 1.1 + * + * * Removed code to add "set $home/$user" stuff to new user's gshrc + * file, per request of Phil Vandry. + * * Added restriction that the new password entered must be greater + * than four characters. + * * Newuser will now try multiple times to open up the /etc/passwd + * file, just as passwd itself does. + * + * Original version 1.0: + * * Some code borrowed from Eric Shepard's passwd source. + * + * files: /var/adm/newuser/newid + * /var/adm/newuser/newusers + * /var/adm/newuser/gshrc + * /user/ + */ +#include +#include +#include +#include +#include +#include #include #include -#include #include #include #include -#include #include #include +#include +#include +#include +#include +#include -#pragma lint -1 +#define HOME "/home" +#define NEWID_FILE "/var/adm/newuser/newid" /* next ID to assign */ +#define NEWUSERS_FILE "/var/adm/newuser/pending" /* addtions "on hold */ +#define SKELETONS "/var/adm/newuser/skel" /* files to copy */ +#define DEFAULT_SHELL _PATH_GSHELL /* default shell */ -char *getpass(char *prompt); -char *crypt(char *key, char *salt); - -void time_out(void); -void makesalt(char *salt, long seed); -int get_next_uid(void); -void getpassword(char *password, char *salt, char *passstring); -int bad_name(char *acct_name); -void myfgets(char *string, int maxchar, FILE *FilePtr); -FILE *smartopen(char *file, char *mode); - -#define NEWID_FILE "/var/adm/newuser/newid" -#define NEWUSERS_FILE "/var/adm/newuser/newusers" -#define NEWGSHRC_FILE "/var/adm/newuser/gshrc" - -#define DEFAULT_GID 2 /* default group ID assigned to new user */ -#define ACCT_NAME_LEN 8 /* max # of chars in account name */ -#define REAL_NAME_LEN 30 /* max # of chars in real name */ -#define TERM_TYPE_LEN 8 /* max # of chars in terminal type */ -#define MAX_TRIES 3 /* max # of trials for opening passwd file */ +#define MIN_PASSWD_LEN 5 /* minimum length of cleartext password */ +#define DEFAULT_GID 100 /* default group ID assigned to new user */ +#define ACCT_NAME_LEN 32 /* max # of chars in account name, +1 */ + /* We later truncate the account name to */ + /* to no more than 8 chars. */ +#define REAL_NAME_LEN 31 /* max # of chars in real name, +1 */ +#define CRYPT_PASS_LEN 14 /* max # of chars in encrypted passwd +1 */ +#define MAX_TRIES 3 /* max # of trials for opening passwd file */ #ifndef FALSE #define FALSE 0 #define TRUE 1 #endif -static char acct_name[ACCT_NAME_LEN+1], - buffer[80], - name[REAL_NAME_LEN+1], - pass1[14], pass2[14], - salt[3], - scratch[256], - term_type[TERM_TYPE_LEN+1]; +static void time_out(void); +static void makesalt(char *salt, long seed); +static uid_t get_next_uid(void); +static int getpassword(char *, int, char *, char *); +static int bad_name(char *acct_name); +static void mygets(char *string, int maxchar); +static FILE * smartopen(char *file, char *mode); + +static char acct_name[ACCT_NAME_LEN]; +static char name[REAL_NAME_LEN]; +static char pass1[CRYPT_PASS_LEN]; +static char pass2[CRYPT_PASS_LEN]; +static char salt[3]; + +static char newhome[PATH_MAX]; static unsigned char salttab[] = /* table of chars for salt */ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; -void time_out(void) - - { - printf("\nnewuser timed out after 60 seconds.\n"); - exit(1); - } +#pragma databank 1 +static void +time_out(void) +{ + printf("\nnewuser timed out after 60 seconds.\n"); + exit(1); +} +#pragma databank 0 /* Borrowed from Eric's passwd.cc */ -void +static void makesalt(char *salt, long seed) { int num = 2; @@ -89,14 +118,27 @@ makesalt(char *salt, long seed) } } -int +/* + * get_next_uid() + * + * Return the next available user id from NEWID_FILE, and update the + * NEWID_FILE under the assumption that the returned id will be assigned + * in /etc/passwd. Abort on any errors. + */ + +static uid_t get_next_uid(void) { FILE *FPtr; - int uid; + uid_t uid; - FPtr = fopen(NEWID_FILE,"r+"); - fscanf(FPtr,"%d\n",&uid); + if ((FPtr = fopen(NEWID_FILE,"r+")) == NULL) { + err(1, "failed to id file %s", NEWID_FILE); + /*NOTREACHED*/ + } + if (fscanf(FPtr,"%d\n",&uid) != 1) { + errx(1, "scan of %s failed", NEWID_FILE); + } rewind(FPtr); fprintf(FPtr,"%d\n",uid+1); fclose(FPtr); @@ -104,56 +146,120 @@ get_next_uid(void) return(uid); } -void -getpassword(char *password, char *salt, char *passstring) +/* + * getpassword + * prompt for a password with . put the encrypted + * password into , aborting if it's length is greater + * than -1. Return the length of the plaintext password. + */ + +static int +getpassword(char *password, int passwdlen, char *salt, char *passstring) { char *pass, *passcode; - + int length_clear, length_crypt, quit_now; + pass = getpass(passstring); - passcode = crypt(pass,salt); + + if (*pass == '\0') { /* ^D */ + quit_now = 1; + } else { + quit_now = 0; + length_clear = strlen(pass); + passcode = crypt(pass,salt); + } + + /* zero out the cleartext password */ + for (length_crypt=0; length_crypt<_PASSWORD_LEN; length_crypt++) { + if (pass[length_crypt] == '\0') { + break; + } + pass[length_crypt] = '\0'; + } + + /* password not given? */ + if (quit_now) { + errx(1, "aborted"); + } + + if (length_crypt > passwdlen-1) { + errx(1, + "internal error: encrypted password length (%d) > buffer length (%d)", + length_crypt+1, passwdlen); + /*NOTREACHED*/ + } strcpy(password,passcode); + return length_clear; } -int +/* + * bad_name() + * + * return nonzero if is unsuitable as an account name. It must + * be between 2 and 8 characters long, start with a lower case letter, and + * contain only lower case letters or digits. + */ + +static int bad_name(char *acct_name) { - if (!isalpha(*acct_name++)) + int len; + + len = strlen(acct_name); + if ((len < 2) || (len > 8) || !islower(*acct_name)) { return(TRUE); + } + len = 1; + acct_name++; - while (*acct_name != '\0') - if (!isalnum(*acct_name++)) + while (*acct_name != '\0') { + len++; + if ((len > 8) || (!islower(*acct_name) && !isdigit(*acct_name))) { return(TRUE); + } + acct_name++; + } + /* it's a good account name */ return(FALSE); } -void -myfgets(char *string, int maxchar, FILE *FilePtr) +static void +mygets(char *string, int maxchar) { - int last_char; - char *tmp_buf; - - tmp_buf = (char *) malloc (256); - - maxchar++; - fgets(tmp_buf,maxchar,FilePtr); - if (*tmp_buf == 0x00) /* ^D */ - exit(1); - last_char = strlen(tmp_buf)-1; - - /* remove terminating \n if necessary */ - - if ((tmp_buf[last_char] == '\n') || (tmp_buf[last_char] == '\r')) - tmp_buf[last_char] = '\0'; - - strcpy(string,tmp_buf); - fflush(stdin); - free(tmp_buf); + int len; + + fgets(string, maxchar, stdin); + fflush(stdin); + if (*string == 0x00) { /* ^D */ + goto fail; + } + len = strlen(string); + if (len == 0) { + goto fail; + } + + /* remove terminating \n if necessary */ + if ((string[len-1] == '\r') || (string[len-1] == '\n')) { + string[len-1] = '\0'; + len--; + } + + /* check for empty string */ + if ((len == 0)) { + goto fail; + } + + return; + +fail: + errx(1, "aborted"); + /*NOTREACHED*/ } /* try multiple times to open /etc/passwd file */ -FILE * +static FILE * smartopen(char *file, char *mode) { FILE *FOutPtr; @@ -171,15 +277,54 @@ smartopen(char *file, char *mode) return(FOutPtr); } +static void +usage (void) +{ + printf("Usage: newuser [-v] [-g gid]\n"); + printf(" newuserv [-v] [-g gid]\n"); + exit(1); +} + int main (int argc, char **argv) { - int validate, uid; - FILE *FInPtr, *FOutPtr; - + int validate, ch; + uid_t uid; + gid_t gid; + FILE *FOutPtr; + DIR *dirp; + struct dirent *entp; struct sgttyb *s; - s = (struct sgttyb *) malloc (sizeof(struct sgttyb)); - + char *srcfile; + + __REPORT_STACK(); + + /* check usage */ + gid = DEFAULT_GID; + validate = (strcmp(basename(argv[0]), "newuserv") == 0) ? TRUE : FALSE; + while ((ch = getopt(argc, argv, "vg:")) != EOF) { + switch(ch) { + case 'g': + if ((gid = atoi(optarg)) == 0) { + gid = DEFAULT_GID; + } + break; + case 'v': + validate = TRUE; + break; + default: + usage(); + } + } + if (argc - optind > 0) { + usage(); + } + + /* set up for system logging */ + openlog(basename(argv[0]), LOG_PID | LOG_NDELAY, LOG_AUTH | LOG_INFO); + + + /* set up signal handlers */ signal(SIGINT,SIG_IGN); signal(SIGHUP,SIG_IGN); signal(SIGQUIT,SIG_IGN); @@ -187,40 +332,34 @@ main (int argc, char **argv) signal(SIGALRM,time_out); /* Set proper erase character */ - + s = malloc (sizeof(struct sgttyb)); gtty(STDIN_FILENO,s); s->sg_erase = 0x7f; stty(STDIN_FILENO,s); free(s); - validate = FALSE; - - if (argc == 2 && !strcmp(argv[1],"-v")) - validate = TRUE; - else if (argc == 1); - else - exit(1); - /* Make sure all required files exist before going any further */ - - if ((FInPtr = fopen(NEWID_FILE,"r+")) == NULL) { - fprintf(stderr,"unable to open %s; exiting.\n",NEWID_FILE); - exit(1); + if (access(NEWID_FILE, R_OK | W_OK) != 0) { + errx(1, "no read/write access for %s", NEWID_FILE); + } + if (access(HOME, R_OK | W_OK | X_OK) != 0) { + errx(1, "no read/write/execute access for %s", HOME); + } + if (access(SKELETONS, R_OK | X_OK) != 0) { + errx(1, "no read/execute access for %s", SKELETONS); } - fclose(FInPtr); - - if ((FInPtr = fopen(NEWGSHRC_FILE,"r+")) == NULL) { - fprintf(stderr,"unable to open %s; exiting.\n",NEWGSHRC_FILE); - exit(1); + printf("\n\tYou have requested a new account. You will be required\n"); + printf("\tto enter the account information, after which "); + if (validate) { + printf("your account\n\tWill be placed on hold until it is verified\n"); + } else { + printf("you will be\n\table to log into the system\n"); } - fclose(FInPtr); - - /* Get information */ - - printf("\nReal Name: "); - myfgets(name,REAL_NAME_LEN,stdin); + /* Get the user's "Real Name" for the GECOS field */ + printf("\nReal Name: "); + mygets(name, REAL_NAME_LEN); /* Get login name. If the login name is duplicate, prompt for */ /* a new login name. If the login name would call for the */ @@ -232,91 +371,142 @@ main (int argc, char **argv) while(1) { printf("Login Name: "); - myfgets(acct_name,ACCT_NAME_LEN,stdin); - printf("\n\n(login name: '%s')\n\n",acct_name); - if (getpwnam(acct_name) != NULL) { - printf("Duplicate username: please choose another.\n"); - } else if (bad_name(acct_name)) { - printf("\n** Invalid username: please choose a name comprised of\n"); - printf(" alphanumeric characters which starts with an alphabetic\n"); - printf(" character.\n"); + mygets(acct_name, ACCT_NAME_LEN); +#if 0 + printf("\n\n(login name: '%s')\n\n", acct_name); +#endif + + if (bad_name(acct_name)) { + puts("\nInvalid login name. Login names must be between 2 and 8"); + puts("characters long, must start with a lower case letter, and"); + puts("must consist of only digits and lower case letters.\n"); + } else if (getpwnam(acct_name) != NULL) { + printf("The login name \"%s\" is already in use.\n", acct_name); + printf("Please choose another.\n"); } else { - break; +#if 0 + /* bad_name ensures that strlen(acct_name) < 8 */ + if (sizeof(HOME) + strlen(acct_name) > PATH_MAX) { + /* what are the chances? */ + err(1, "buffer overflow at line %d", __LINE__); + } +#endif + sprintf(newhome, "%s/%s", HOME, acct_name); + if (access(newhome, X_OK) == 0) { + printf("The login name \"%s\" has already been requested by someone else\n", + acct_name); + printf("Please choose another.\n"); + } else { + break; + } } } - printf("Terminal Type: "); - myfgets(term_type,TERM_TYPE_LEN,stdin); - - /* Get password of > 4 chars, with verification */ + /* close the file descriptor we have open on /etc/passswd */ + endpwent(); + /* Get password of >= MIN_PASSWD_LEN chars, with verification */ makesalt(salt, rand()); while(1) { - getpassword(pass1,salt,"Password: "); - getpassword(pass2,salt,"Verify: "); - if (!strcmp(pass1,pass2) && (strlen(pass1) > 4)) { + if (getpassword(pass1, CRYPT_PASS_LEN, salt, "Password: ") + < MIN_PASSWD_LEN) { + printf("The password must be at least %d characters long.\nTry again.\n", + MIN_PASSWD_LEN); + continue; + } + getpassword(pass2, CRYPT_PASS_LEN, salt,"Verify: "); + if (strcmp(pass1,pass2) == 0) { break; } else { - printf("*** Failed verification.\n"); + printf("Passwords don't match. Try again.\n"); } } - uid = get_next_uid(); /* get and update next free ID# */ - - /* make home directory */ - - sprintf(scratch,"mkdir -s /user/%s",acct_name); - exec("/bin/mkdir",scratch); - sleep(2); - - /* and copy default gshrc to it */ - - sprintf(scratch,"/user/%s/gshrc",acct_name); - FOutPtr = fopen(scratch,"w"); - - FInPtr = fopen(NEWGSHRC_FILE,"r"); - - while(fgets(buffer,80,FInPtr) != NULL) { - fputs(buffer,FOutPtr); + /* + * Get the next free uid and update the NEWID_FILE. When we return from + * this routine, we are now past the point of no return; if we fail + * anything, then we have used up a user id. + */ + while(1) { + uid = get_next_uid(); + if (getpwuid(uid) == NULL) { + break; + } else { + syslog(LOG_WARNING, "uid %d is already in use; skipping", uid); + } } - fclose(FInPtr); - /* update default gshrc to have correct $home, $user, and $term */ - - /* Phil asked that this be removed, so... :) */ -#if 0 - fprintf(FOutPtr,"set home=/user/%s\n",acct_name); - fprintf(FOutPtr,"set user=%s\n",acct_name); -#endif - fprintf(FOutPtr,"set term=%s\n",term_type); + /* + * make the home directory + */ + if (mkdir(newhome) != 0) { + err(1, "failed to create directory %s", newhome); + } -#if 0 - fprintf(FOutPtr,"export home user term\n"); -#else - fprintf(FOutPtr,"export term\n"); -#endif - fclose(FOutPtr); + /* + * Copy each of the files in SKELETONS into the user's home directory. + * Initially change directory into SKELETONS so that we can use partial + * pathnames when copying the files into $HOME. + */ + putchar('\n'); + if (chdir(SKELETONS) != 0) { + err(1, "couldn't change directory into %s", SKELETONS); + /*NOTREACHED*/ + } + if ((dirp = opendir(SKELETONS)) == NULL) { + err(1, "read of directory %d failed", SKELETONS); + } + while ((entp = readdir(dirp)) != NULL) { + + /* only copy regular files, and don't recurse through subdirectories */ + if (entp->d_type == DT_DIR) { + continue; + } + + /* skip entries for current and parent directories */ + srcfile = entp->d_name; + if (((srcfile[0]=='.') && (srcfile[1]=='\0')) || + ((srcfile[0]=='.') && (srcfile[1]=='.') && (srcfile[2]=='\0'))) { + continue; + } + + /* do the copy */ + srcfile = LC_CopyFile(srcfile, newhome, LC_COPY_DATA | LC_COPY_REZ); + if (srcfile == NULL) { + err(1, "couldn't copy %s", entp->d_name); + } else { + printf("creating %s\n", srcfile); + } + } + closedir(dirp); + + /* Save the password information away. */ if (!validate) { /* no validation, so append new entry to /etc/passwd */ - FOutPtr = smartopen("/etc/passwd","a"); + FOutPtr = smartopen(_PATH_PASSWD, "a"); if (FOutPtr == NULL) { - fprintf(stderr,"Trouble opening /etc/passwd file.\nExiting\n"); - exit(1); + err(1, "couldn't open %s", _PATH_PASSWD); } - fprintf(FOutPtr,"%s:%s:%d:%d:%s:/user/%s:/bin/gsh\n",acct_name,pass1, - uid,DEFAULT_GID,name,acct_name); + fprintf(FOutPtr, "%s:%s:%d:%d:%s:%s/%s:%s\n", + acct_name, pass1, uid, gid, name, HOME, acct_name, DEFAULT_SHELL); fclose(FOutPtr); + syslog(LOG_INFO, "created account %s", acct_name); printf("You may now log in.\n"); } else { /* validation selected -- so append new entry to NEWUSERS_FILE */ - FOutPtr = fopen(NEWUSERS_FILE,"a"); - fprintf(FOutPtr,"%s:%s:%d:0:%s:/user/%s:/bin/gsh\n",acct_name,pass1, - uid,name,acct_name); + if ((FOutPtr = fopen(NEWUSERS_FILE, "a")) == NULL) { + err(1, "couldn't open %s", NEWUSERS_FILE); + } + fprintf(FOutPtr,"%s:%s:%d:%d:%s:%s/%s:%s\n", + acct_name, pass1, uid, gid, name, HOME, acct_name, DEFAULT_SHELL); fclose(FOutPtr); - printf("Try back in 24 hours.\n"); + syslog(LOG_INFO, "created account %s pending validation", acct_name); + printf("\nYour account will be available after the system administrator"); + printf("has had a\nchance to review it.\n"); } + closelog(); - exit(0); + return 0; } diff --git a/usr.sbin/newuser/newuser.desc b/usr.sbin/newuser/newuser.desc new file mode 100644 index 0000000..d1be9f3 --- /dev/null +++ b/usr.sbin/newuser/newuser.desc @@ -0,0 +1,23 @@ +Name: newuser +Version: 1.2 +Shell: GNO +Author: James Brookes. Maintained by Devin Reade. +Contact: gdr@trenco.gno.org +Where: /usr/sbin +FTP: ftp.gno.org + +Create a home directory in /home with a template $HOME/gshrc and $HOME/glogin +for a new user, and add the user's entry into the /etc/passwd file for +immediate access. See also newuserv. + +Name: newuserv +Version: 1.2 +Shell: GNO +Author: James Brookes. Maintained by Devin Reade. +Contact: gdr@trenco.gno.org +Where: /usr/sbin +FTP: ftp.gno.org + +Create a home directory in /home with a template $HOME/gshrc and $HOME/glogin +for a new user, and add the user's entry into the /var/adm/newuser/newusers +file for validation by the system operator. See also newuserv. diff --git a/usr.sbin/newuser/newuser.rez b/usr.sbin/newuser/newuser.rez new file mode 100644 index 0000000..9d9fcae --- /dev/null +++ b/usr.sbin/newuser/newuser.rez @@ -0,0 +1,18 @@ +/* + * $Id: newuser.rez,v 1.1 1999/02/15 00:22:11 gdr-ftp Exp $ + */ + +#include "Types.Rez" +#include "builddate.rez" + +resource rVersion (0x1, purgeable3, nocrossbank) { + + { 1, 2, 0, /* version */ + release, /* development|alpha|beta|final|release */ + 0 /* non-final release number */ + }, + verUS, + "newuser/newuserv", + "create new accounts\n" + BUILD_DATE +}; diff --git a/usr.sbin/newuser/newuserv.c b/usr.sbin/newuser/newuserv.c deleted file mode 100644 index ca0bb8d..0000000 --- a/usr.sbin/newuser/newuserv.c +++ /dev/null @@ -1,16 +0,0 @@ -#pragma optimize -1 -#pragma stacksize 256 - -/* */ -/* newverify.c - a simple program to launch newuser with the -v option */ -/* */ - -#include -#include -#include - -int main(int argc, char **argv) - - { - execve("/usr/sbin/newuser","newuser -v"); - }