Path: utzoo!attcan!uunet!shelby!agate!ucbvax!tut.cis.ohio-state.edu!cs.utexas.edu!execu!sequoia!rpp386!jfh From: jfh@rpp386.Dallas.TX.US (John F. Haugh II) Newsgroups: alt.sources Subject: Shadow login release 2 (part 1 of 3) Message-ID: <16678@rpp386.Dallas.TX.US> Date: 20 Jun 89 06:48:40 GMT Followup-To: alt.sources.d Distribution: alt Organization: River Parishes Programming, Plano TX Lines: 2141 X-Archive-Name: shadow2/part1 Part 1 of second USENET release -- #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # README # log.c # mail.c # shadow.h # sulog.c # Makefile # entry.c # obscure.c # setup.c # sub.c # config.h # pmain.c # sulogin.c # dialup.h # ttytype.c # This archive created: Tue Jun 20 01:28:03 1989 # By: John F. Haugh II (River Parishes Programming, Plano TX) export PATH; PATH=/bin:/usr/bin:$PATH if test -f 'README' then echo shar: "will not over-write existing file 'README'" else cat << \SHAR_EOF > 'README' This is the explanatory document for John F. Haugh II's login replacement. This software is copyright 1989, John F. Haugh II. All rights reserved. Use, duplication and disclosure is permitted according to the guidelines listed below. At some point in the future this licence will be modified to conform to the GNU General Public License. This software is being provided as a freely redistributable login clone. You may distribute this software provided you do not charge for other than transmission costs. You are free to transfer this software provided you do not restrict the rights of the recipients to further transfer this software. This software is being distributed AS-IS. The author disclaims all liability for any consequences of use. The user is solely responsible for the maintenance of this software package. The author is under no obligation to provide modifications or improvements. Begin by reading and editing the config.h file. All options are selected by using #define's. A brief description for each available option appears below. You may want to print this file out as it is LONG and you will need to refer to it while editting config.h. You will also have to edit the Makefile. The possible differences are documented there. Pay close attention to the install: rule. DO NOT MAIL ME DIFFERENCES FOR VARIOUS INSTALLATION PROBLEMS. If you must share your experiences, do so on the net. Login now runs on about 15 different varieties of UNIX that I have been made aware of. Note that there are MANY options. As distributed most options are turned on, which produces a really nice package. This is the system as used on the authors machine. [ The one exception is NOBLANK, that is turned off because of anonymous UUCP logins. ] Dialup Password Files - This option permits individual ports to have an additional password prompted for on a by-shell basis. /etc/dialups contains a list of dialup ports, d_passwd contains the password for each shell requiring a dialup password. Select this option by defining the DIALUP macro. Shadow [ unreadable ] Password Files - This option utilizes an alternate, non-readable file to contain the actual encrypted passwords. This is presumed to increase system security by increasing the difficulty with which system crackers obtain encrypted passwords. Select this option by defining the SHADOWPWD macro. Double Length Passwords - This option extends the maximum length of a user password to 16 characters from eight. Select this option by defining the DOUBLESIZE macro. Credit for this option is due Jonathan Bayer. Obscure Password Testing - This option includes code to test user passwords for complexity. The programmer is encouraged to edit the file obscure.c to add additional methods for detecting simplistic passwords. Select this option by defining the OBSCURE macro. Additionally, the PASSLENGTH macro must be defined to control the minimum length for a legal password. Mandatory Password Prompting - This option requires all passwords, including null ones, to be prompted for. Traditionally an account with a password field of '::' does not require prompting for. This option modifies this behavior to require even null passwords be prompted for. Select this option by defining the NOBLANK macro. Password Aging Defaults - You may select the default number of days during which a password is valid. The pwconv command adds aging information to accounts which do not include it already. The MINDAYS macro must be defined to be the minimum number of days which must pass before a password may be changed. The MAXDAYS macro must be defined to be the maximum number of days which a password will remain valid during. HZ Environmental Variable - This option pre-defines the HZ environmental variable. Certain systems require this variable be defined for system time reporting functions to work properly. Select this option by defining the HZ macro to have the desired environmental variable value. TZ Environmental Variable - This option pre-defines the TZ environmental variable. This provides a default timezone variable for use by various utilities. Select this option by defining the TZ macro to have the desired environmental variable value, or the name of the file containing the desired value. Password Aging - This option includes code to perform password aging. Password aging is presumed to increase system security by forcing users to change passwords on a regular basis. The resolution on password age is in weeks for non-shadow password systems and in days otherwise. Select this option by defining the AGING macro. Mailbox Checking - This option includes code to check the status of the user's mailbox. One of three messages are produced depending on the status of the user's mailbox. Select this option by defining the MAILCHECK macro. Console Restricted Root Logins - This option restricts the port which root may legally login on. This option presumably increases system security by preventing outside attacks against the root account. Select this option by defining the CONSOLE macro to have the desired port name. If this file is a regular file, it is considered to contain a list of legal port names, one per line. Note that the port names DO NOT begin with "/dev/" and that a file name would have to be fully qualified. See config.h for a pair of examples. Restricted User Logins - This option permits you to specify a file which disables user logins. This options permits you to keep normal users off of the system while performing maintenance functions. Select this option by defining NOLOGINS to be the name of the file to use. Restricted Use Accounts - This option permits certain accounts to be used for identification purposes only. This options associates login ID's with UID's, such as for disk space accounting or anonymous FTP accounts. Passwords for these accounts may only be changed by root. Select this option by defining NOUSE to be the string to include in the password file in place of the user's shell. Message of the Day Printing - This option causes the message of the day to be printed at login time. Select this option by defining the MOTD macro. If you wish this feature to be overriden on a per-user basis, define the macro HUSHLOGIN and users may then turn off the /etc/motd message by creating a file '.hushlogin' in their home directories. Last Login Time Logging - This option causes a record to be made of successful logins in /usr/adm/lastlog. The format of the structure is defined in lastlog.h. Select this option by defining the LASTLOG macro. You will need to determine if you system already has a lastlog.h file and use that file if present. Failed Login Logging - This option causes a record to be kept of the most recent login failure by date and port. A cummulative count of failures is maintained and compared against an allowable limit. Select this option by defining the FAILLOG macro. See the file faillog.h for more details. Terminal Permissions - This option allows the terminal modes to be set at login time. This is particularly useful to disable messages on user's terminals. Select this option by defining the TTYPERM macro as having the desired mode. Terminal Type Setup - This option allows the terminal type to be set at login time. The environmental variable TERM will be set from the specified terminal to port mapping file. Select this option by defining the TTYTYPE macro as having the value of the name of the type to port mapping file. Credit for this option is due Chip Rosenthal. File Size Setting - This option includes code to set the user's ulimit at login time. Additional code to set the umask and nice value is also included. Select this option by defining the QUOTAS macro. Switch-User Logging - This option causes su(1) to log attempts to switch users. Su(1) will log all attempt, giving the old and new user ID's, tty port, and time. It also indicates if the attempt was successful. Select this option by defining the SULOG macro to have the value of the name of the file you want attempts logged to. Configurable Editing Keys - This options allows the erase and kill characters to be selected. A default value is provided. By default ERASE will be ^H and KILL will be ^U. Select this option by defining the ERASECHAR macro to be the desired erase character and the KILLCHAR macro to be the desired KILL character. Default ulimit and umask Values - This option allows you to select the default values for ulimit and umask, allowing you to avoid regenerating your system kernel. These values may be overriden with appropriate entries in the GECOS field. Select the default ulimit by defining the ULIMIT macro, and the default umask by defining the UMASK macro. Warning: These values will not apply to processes executed by /etc/cron or any of their children. BSD Notes: Steve Simmons scs@iti.org The full port of the shadow package to BSD is not complete; but some of the issues have been worked out. These notes describe the current state of things: In order to make use of password aging under BSD, minor changes to /usr/include/pwd.h and getpwent() are needed. These changes are to keep the password age from messing up the encrypted password when not using shadow passwords, and involve placing a new field in the password data structure. To use this, you should apply the following two patches: pwd.h.patch getpwent.c.patch to the BSD /usr/include/pwd.h and /usr/src/lib/libc/gen/getpwent.c, respectively. After applying the patches, rebuild your standard C library with the new getpwent. Programs which use the old getpwent will fail on password checking if they do a strcmp rather than a strncmp. These changes are based on BSD4.3, not Tahoe ToDo BSD: I'm working on this in my copious spare time (hah!); any help would be appreciated. If you decide to help, do these independantly rather than rework BSD code! Keep it redistributable! No dbm functions have been put in place. Dbm functionality is needed for both /etc/password and /etc/shadow management. The BSD GECOS field gets used for lots more stuff than the USG. At a minimum this functionality should be duplicated under BSD; better is to put it into USG as well; still better would be to make the chfn command for both systems; best would be site-configurable data to be put into GECOS/chfn. SHAR_EOF fi if test -f 'log.c' then echo shar: "will not over-write existing file 'log.c'" else cat << \SHAR_EOF > 'log.c' #include #include #include #include #include #ifndef BSD #include #include #else #include #define strchr index #define strrchr rindex #endif #include "config.h" #ifndef lint static char _sccsid[] = "@(#)log.c 2.1 01:23:21 6/20/89"; #endif #ifdef LASTLOG #include "lastlog.h" extern struct utmp utent; extern struct passwd pwent; extern struct lastlog lastlog; extern char **environ; long lseek (); time_t time (); void log () { int fd; off_t offset; struct lastlog newlog; if ((fd = open ("/usr/adm/lastlog", O_RDWR)) == -1) return; offset = pwent.pw_uid * sizeof lastlog; if (lseek (fd, offset, 0) != offset) { (void) close (fd); return; } if (read (fd, (char *) &lastlog, sizeof lastlog) != sizeof lastlog) #ifndef BSD memset ((char *) &lastlog, sizeof lastlog, 0); #else bzero ((char *) &lastlog, sizeof lastlog); #endif newlog = lastlog; (void) time (&newlog.ll_time); (void) strncpy (newlog.ll_line, utent.ut_line, sizeof newlog.ll_line); (void) lseek (fd, offset, 0); (void) write (fd, (char *) &newlog, sizeof newlog); (void) close (fd); } #endif SHAR_EOF fi if test -f 'mail.c' then echo shar: "will not over-write existing file 'mail.c'" else cat << \SHAR_EOF > 'mail.c' #include #include #ifndef BSD #include #include #else #include #define strchr index #define strrchr rindex #endif #include "config.h" #ifndef lint static char _sccsid[] = "@(#)mail.c 2.1 01:23:26 6/20/89"; #endif extern char mail[]; #ifdef HUSHLOGIN extern int hushed; #endif #ifdef MAILCHECK void mailcheck () { struct stat statbuf; char *mailbox; #ifdef HUSHLOGIN if (hushed) return; #endif if (mailbox = strchr (mail, '=')) mailbox++; else return; if (stat (mailbox, &statbuf) == -1 || statbuf.st_size == 0) puts ("No mail."); else if (statbuf.st_atime > statbuf.st_mtime) puts ("You have mail."); else puts ("You have new mail."); } #endif SHAR_EOF fi if test -f 'shadow.h' then echo shar: "will not over-write existing file 'shadow.h'" else cat << \SHAR_EOF > 'shadow.h' /* * This information is not derived from AT&T licensed sources. Posted * to the USENET 11/88. * * @(#)shadow.h 2.1 01:23:51 6/20/89 */ /* * Shadow password security file structure. */ struct spwd { char *sp_namp; /* login name */ char *sp_pwdp; /* encrypted password */ long sp_lstchg; /* date of last change */ long sp_max; /* maximum number of days between changes */ long sp_min; /* minimum number of days between changes */ }; /* * Shadow password security file functions. */ struct spwd *getspent (); struct spwd *getspnam (); void setspent (); void endspent (); struct spwd *fgetspent (); int putspent (); #define SHADOW "/etc/shadow" SHAR_EOF fi if test -f 'sulog.c' then echo shar: "will not over-write existing file 'sulog.c'" else cat << \SHAR_EOF > 'sulog.c' #include #include #include #ifndef BSD #include #include #else #include #define strchr index #define strrchr rindex #endif #include "config.h" extern char name[]; extern char oldname[]; time_t time (); void sulog (success) int success; { #ifdef SULOG char *tty; char *cp; char *ttyname (); time_t clock; struct tm *tm; struct tm *localtime (); FILE *fp; if ((fp = fopen (SULOG, "a+")) == (FILE *) 0) return; /* can't open or create logfile */ (void) time (&clock); tm = localtime (&clock); if (isatty (0) && (cp = ttyname (0))) { if (tty = strrchr (cp, '/')) tty++; else tty = cp; } else tty = "???"; (void) fprintf (fp, "SU %.02d/%0.2d %.02d:%.02d %c %.6s %s-%s\n", tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, success ? '+':'-', tty, oldname, name); fflush (fp); fclose (fp); #endif } SHAR_EOF fi if test -f 'Makefile' then echo shar: "will not over-write existing file 'Makefile'" else cat << \SHAR_EOF > 'Makefile' # # %W% %U% - System V shadow password system # # %W% %U% %G% # SHELL = /bin/sh # Define the directory login is copied to. BE VERY CAREFUL!!! # LOGINDIR = /bin LOGINDIR = /etc # Pick your favorite C compiler and tags command CC = cc TAGS = ctags # OS. Currently only BSD and USG are defined. If you don't use BSD, # USG (System V) is assumed. # OS = -DBSD # Do you have to do ranlib? Sorry to hear that ... RANLIB = ranlib # RANLIB = echo # Flags for SCO Xenix/386 CFLAGS = -O -M3 -g $(PWDEF) $(AL64DEF) $(OS) LIBS = -lcrypt LDFLAGS = -M3 -g LTFLAGS = # This should be Slibsec.a for small model, or Llibsec.a for # large model or whatever. MUST AGREE WITH CFLAGS!!! LIBSEC = Slibsec.a # Flags for normal machines # CFLAGS = -O -g $(PWDEF) $(AL64DEF) $(OS) # LIBS = # LDFLAGS = -g # LIBSEC = libsec.a LOBJS = lmain.o login.o env.o password.o entry.o valid.o setup.o shell.o age.o \ pwent.o utmp.o sub.o mail.o motd.o log.o shadow.o dialup.o dialchk.o \ ttytype.o failure.o LSRCS = lmain.c login.c env.c password.c entry.c valid.c setup.c shell.c age.c \ pwent.c utmp.c sub.c mail.c motd.c log.c shadow.c dialup.c dialchk.c \ ttytype.c failure.c SOBJS = smain.o env.o password.o entry.o valid.o susetup.o sushell.o \ pwent.o susub.o mail.o motd.o sulog.o shadow.o age.o SSRCS = smain.c env.c password.c entry.c valid.c setup.c shell.c \ pwent.c sub.c mail.c motd.c sulog.c shadow.c age.c POBJS = pmain.o password.o entry.o valid.o pwage.o pwent.o obscure.o shadow.o PSRCS = pmain.c password.c entry.c valid.c age.c pwent.c obscure.c shadow.c PWOBJS = pwconv.o pwent.o shadow.o pwage.o PWSRCS = pwconv.c pwent.c shadow.c age.c PWUNOBJS = pwunconv.o pwent.o shadow.o pwage.o PWUNSRCS = pwunconv.c pwent.c shadow.c age.c SULOGOBJS = sulogin.o entry.o env.o password.o pwage.o pwent.o setup.o \ shadow.o shell.o valid.o SULOGSRCS = sulogin.c entry.c env.c password.c age.c pwent.c setup.c \ shadow.c shell.c valid.c ALLSRCS = age.c dialchk.c dialup.c entry.c env.c lmain.c log.c login.c mail.c \ motd.c obscure.c password.c pmain.c pwconv.c pwent.c pwunconv.c \ setup.c shadow.c shell.c smain.c sub.c sulog.c sulogin.c ttytype.c \ utmp.c valid.c FILES1 = README log.c mail.c shadow.h sulog.c Makefile entry.c obscure.c \ setup.c sub.c config.h pmain.c sulogin.c dialup.h ttytype.c FILES2 = lastlog.h login.c motd.c password.c shell.c utmp.c age.c env.c \ pwent.c shadow.c valid.c lmain.c smain.c pwconv.c dialup.c dialchk.c \ pwunconv.c failure.c faillog.h faillog.c DOCS = login.1 passwd.1 passwd.4 shadow.3 shadow.4 su.1 sulogin.8 pwconv.8 \ pwunconv.8 faillog.8 faillog.4 all: su login pwconv pwunconv passwd sulogin faillog libsec: shadow.o ar rv $(LIBSEC) shadow.o $(RANLIB) $(LIBSEC) install: all cp login $(LOGINDIR)/login cp pwconv pwunconv sulogin /etc cp su passwd faillog /bin chown root $(LOGINDIR)/login /etc/pwconv /etc/pwunconv /etc/sulogin \ /bin/su /bin/passwd chgrp root $(LOGINDIR)/login /etc/pwconv /etc/pwunconv /etc/sulogin \ /bin/su /bin/passwd chown bin /bin/faillog chgrp bin /bin/faillog chmod 700 /etc/pwconv /etc/pwunconv /etc/sulogin chmod 4711 $(LOGINDIR)/login /bin/su /bin/passwd chmod 711 /bin/faillog lint: su.L login.L pwconv.L pwunconv.L passwd.L sulogin.L faillog.L tags: $(ALLSRCS) $(TAGS) $(ALLSRCS) login: $(LOBJS) $(CC) -o login $(LDFLAGS) $(LOBJS) $(LIBS) login.L: $(LSRCS) lint $(LSRCS) > login.L su: $(SOBJS) $(CC) -o su $(LDFLAGS) $(SOBJS) $(LIBS) su.L: $(SSRCS) lint -DSU $(SSRCS) > su.L passwd: $(POBJS) $(CC) -o passwd $(LDFLAGS) $(POBJS) $(LIBS) passwd.L: $(PSRCS) lint -DPASSWD $(PSRCS) > passwd.L pwconv: $(PWOBJS) $(CC) -o pwconv $(LDFLAGS) $(PWOBJS) $(LIBS) pwconv.L: $(PWSRCS) lint -DPASSWD $(PWSRCS) > pwconv.L pwunconv: $(PWUNOBJS) $(CC) -o pwunconv $(LDFLAGS) $(PWUNOBJS) $(LIBS) pwunconv.L: $(PWUNSRCS) lint -DPASSWD $(PWUNSRCS) > pwunconv.L sulogin: $(SULOGOBJS) $(CC) -o sulogin $(LDFLAGS) $(SULOGOBJS) $(LIBS) sulogin.L: $(SULOGSRCS) lint $(SULOGSRCS) > sulogin.L faillog: faillog.o $(CC) -o faillog $(LDFLAGS) faillog.o $(LIBS) faillog.L: faillog.c faillog.h config.h lint faillog.c > faillog.L sushell.o: config.h shell.c $(CC) -c $(CFLAGS) -DSU shell.c mv shell.o sushell.o susub.o: config.h sub.c $(CC) -c $(CFLAGS) -DSU sub.c mv sub.o susub.o sulog.o: config.h susetup.o: config.h setup.c $(CC) -c $(CFLAGS) -DSU setup.c mv setup.o susetup.o pmain.o: config.h lastlog.h shadow.h pwage.o: age.c config.h cp age.c pwage.c $(CC) -c $(CFLAGS) -DPASSWD pwage.c rm pwage.c lmain.o: config.h lastlog.h smain.o: config.h lastlog.h setup.o: config.h utmp.o: config.h mail.o: config.h motd.o: config.h age.o: config.h log.o: config.h lastlog.h shell.o: config.h entry.o: config.h shadow.h shadow.o: shadow.h dialup.o: dialup.h dialchk.o: dialup.h config.h valid.o: config.h failure.o: faillog.h config.h faillog.o: faillog.h config.h pwent.o: config.h clean: -rm -f *.o a.out core npasswd nshadow clobber: clean -rm -f su login passwd pwconv pwunconv sulogin faillog *.L shar: login.sh.1 login.sh.2 login.sh.3 login.sh.1: $(FILES1) shar $(FILES1) > login.sh.1 login.sh.2: $(FILES2) shar $(FILES2) > login.sh.2 login.sh.3: $(DOCS) shar $(DOCS) > login.sh.3 SHAR_EOF fi if test -f 'entry.c' then echo shar: "will not over-write existing file 'entry.c'" else cat << \SHAR_EOF > 'entry.c' #include #include #ifndef BSD #include #else #include #define strchr index #define strrchr rindex #endif #include "config.h" #ifdef SHADOWPWD #include "shadow.h" #endif #ifndef lint static char _sccsid[] = "@(#)entry.c 2.1 01:23:09 6/20/89"; #endif struct passwd *fgetpwent (); char *malloc (); char *strdup (s) char *s; { char *cp; if (s == (char *) 0) return ((char *) 0); if (! (cp = malloc ((unsigned) strlen (s) + 1))) return ((char *) 0); return (strcpy (cp, s)); } void entry (name, pwent) char *name; struct passwd *pwent; { FILE *pwd; struct passwd *passwd; #ifdef SHADOWPWD struct spwd *spwd; char *l64a (); #endif char *cp; if ((pwd = fopen (PWDFILE, "r")) == (FILE *) 0) { pwent->pw_passwd = (char *) 0; return; } while (passwd = fgetpwent (pwd)) { if (strcmp (name, passwd->pw_name) == 0) break; } fclose (pwd); if (passwd == (struct passwd *) 0) { pwent->pw_name = (char *) 0; pwent->pw_passwd = (char *) 0; } else { pwent->pw_name = strdup (passwd->pw_name); pwent->pw_uid = passwd->pw_uid; pwent->pw_gid = passwd->pw_gid; pwent->pw_comment = (char *) 0; pwent->pw_gecos = strdup (passwd->pw_gecos); pwent->pw_dir = strdup (passwd->pw_dir); pwent->pw_shell = strdup (passwd->pw_shell); #ifdef SHADOWPWD setspent (); if (spwd = getspnam (name)) { pwent->pw_passwd = strdup (spwd->sp_pwdp); if (spwd->sp_lstchg != 0) { pwent->pw_age = (char *) 0; } else { pwent->pw_age = malloc (5); pwent->pw_age[0] = i64c (spwd->sp_max / 7); pwent->pw_age[1] = i64c (spwd->sp_min / 7); cp = l64a (spwd->sp_lstchg / 7); pwent->pw_age[2] = cp[0]; pwent->pw_age[3] = cp[1]; pwent->pw_age[4] = '\0'; } endspent (); return; } endspent (); passwd->pw_age = pwent->pw_age = (char *) 0; #endif if (passwd->pw_passwd) pwent->pw_passwd = strdup (passwd->pw_passwd); else pwent->pw_passwd = (char *) 0; if (passwd->pw_age) { pwent->pw_age = malloc (5); /* longest legal time */ (void) strncpy (pwent->pw_age, passwd->pw_age, 5); } else pwent->pw_age = (char *) 0; } } SHAR_EOF fi if test -f 'obscure.c' then echo shar: "will not over-write existing file 'obscure.c'" else cat << \SHAR_EOF > 'obscure.c' #include #ifndef BSD #include #include #else #include #define strchr index #define strrchr rindex #endif #include "config.h" #ifndef lint static char _sccsid[] = "@(#)obscure.c 2.1 01:23:29 6/20/89"; #endif /* * Obscure - see if password is obscure enough. * * The programmer is encouraged to add as much complexity to this * routine as desired. Included are some of my favorite ways to * check passwords. */ extern char pass[]; /* the new password */ extern char orig[]; /* the original password */ #ifdef OBSCURE char mono[32]; /* a monocase version of pass */ #endif int obscure () { #ifdef OBSCURE int i; #endif if (orig[0] == '\0') return (1); if (strlen (pass) < PASSLENGTH) { /* too short */ printf ("Too short. "); return (0); } #ifdef OBSCURE for (i = 0;pass[i];i++) mono[i] = tolower (pass[i]); if (strcmp (pass, orig) == 0) /* the same */ return (0); if (palindrome ()) /* a palindrome */ return (0); if (caseshift ()) /* upper/lower case changes only */ return (0); if (similiar ()) /* jumbled version of original */ return (0); #endif return (1); } #ifdef OBSCURE /* * can't be a palindrome - like `R A D A R' or `M A D A M' */ int palindrome () { int i, j; i = strlen (pass); for (j = 0;j < i;j++) if (pass[i - j - 1] != pass[j]) return (0); printf ("No palindromes. "); return (1); } /* * may not be a shifted version of original */ int caseshift () { int i; for (i = 0;pass[i] && orig[i];i++) { if (tolower (pass[i]) == tolower (orig[i])) continue; else return (0); } printf ("May not be case-shifted. "); return (1); } /* * more than half of the characters are different ones. */ int similiar () { int i, j; char *strchr (); for (i = j = 0;pass[i] && orig[i];i++) if (strchr (mono, tolower (orig[i]))) j++; if (i - j > 2) return (0); printf ("Too similiar. "); return (1); } #endif SHAR_EOF fi if test -f 'setup.c' then echo shar: "will not over-write existing file 'setup.c'" else cat << \SHAR_EOF > 'setup.c' #include #include #include #ifndef BSD #include #include #else #include #define strchr index #define strrchr rindex #endif #include "config.h" #ifndef lint static char _sccsid[] = "@(#)setup.c 2.1 01:23:45 6/20/89"; #endif extern char home[]; extern char prog[]; extern char name[]; extern char mail[]; #ifndef PATH #define PATH ":/bin:/usr/bin" #endif #ifndef SUPATH #define SUPATH ":/bin:/usr/bin:/etc" #endif #ifndef MAILDIR #define MAILDIR "/usr/spool/mail" #endif #ifndef TTYPERM #define TTYPERM 0622 #endif #ifndef SU extern struct utmp utent; #endif #ifdef QUOTAS long strtol (); #ifdef ULIMIT long ulimit (); #endif #endif void addenv (); void setup (info) struct passwd *info; { extern int errno; char logname[30]; #ifndef SU char tty[30]; #endif char *cp; int i; long l; #ifndef SU (void) strcat (strcpy (tty, "/dev/"), utent.ut_line); if (chown (tty, info->pw_uid, info->pw_gid) || chmod (tty, TTYPERM)) perror (tty); #endif if (chdir (info->pw_dir) == -1) { (void) printf ("Unable to change directory to \"%s\"\n", info->pw_dir); exit (errno); } #ifdef QUOTAS for (cp = info->pw_gecos;cp != (char *) 0;cp = strchr (cp, ',')) { if (*cp == ',') cp++; if (strncmp (cp, "pri=", 4) == 0) { i = atoi (cp + 4); if (i >= -20 && i <= 20) (void) nice (i); continue; } #ifdef ULIMIT if (strncmp (cp, "ulimit=", 7) == 0) { l = strtol (cp + 7, (char **) 0, 10); (void) ulimit (2, l); continue; } #endif if (strncmp (cp, "umask=", 6) == 0) { i = strtol (cp + 6, (char **) 0, 8) & 0777; (void) umask (i); continue; } } #endif if (setgid (info->pw_gid) == -1) { puts ("Bad group id"); exit (errno); } #ifndef BSD if (setuid (info->pw_uid)) #else if (setreuid (info->pw_uid, info->pw_uid)) #endif { puts ("Bad user id"); exit (errno); } (void) strcat (strcpy (home, "HOME="), info->pw_dir); addenv (home); if (info->pw_shell == (char *) 0) info->pw_shell = "/bin/sh"; (void) strcat (strcpy (prog, "SHELL="), info->pw_shell); addenv (prog); if (info->pw_uid == 0) addenv (SUPATH); else addenv (PATH); (void) strcat (strcpy (logname, "LOGNAME="), name); addenv (logname); (void) strcat (strcat (strcpy (mail, "MAIL="), MAILDIR), name); addenv (mail); } SHAR_EOF fi if test -f 'sub.c' then echo shar: "will not over-write existing file 'sub.c'" else cat << \SHAR_EOF > 'sub.c' #include #include #include #ifndef BSD #include #include #else #include #define strchr index #define strrchr rindex #endif #ifndef lint static char _sccsid[] = "@(#)sub.c 2.1 01:23:58 6/20/89"; #endif extern struct passwd pwent; #ifndef SU extern struct utmp utent; #endif void setutmp (); /* * I have heard of two different types of behavior with subsystem roots. * One has you execute login no matter what. The other has you execute * the command [ if one exists ] after the '*' in the shell name. The * macro SUBLOGIN says to execute /bin/login [ followed by /etc/login ] * regardless. Otherwise, pwent.pw_shell is fixed up and that command * is executed [ by returning to the caller ]. I prefer the latter since * it doesn't require having a "login" on the new root filesystem. */ void subsystem () { char *strdup (); if (pwent.pw_dir[0] != '/') exit (1); if (chdir (pwent.pw_dir) || chroot (pwent.pw_dir)) { printf ("Can't change to \"%s\"\n", pwent.pw_dir); exit (1); } #ifndef SU (void) strcpy (utent.ut_line, ""); setutmp (); #endif #ifdef SUBLOGIN execl ("/bin/login", "login", name, (char *) 0); execl ("/etc/login", "login", name, (char *) 0); puts ("No /bin/login or /etc/login on root"); exit (1); #else if (! pwent.pw_shell || strlen (pwent.pw_shell) == 1) pwent.pw_shell = "/bin/sh"; /* default shell */ else pwent.pw_shell++; /* skip over '*' */ #endif } SHAR_EOF fi if test -f 'config.h' then echo shar: "will not over-write existing file 'config.h'" else cat << \SHAR_EOF > 'config.h' /* * Configuration file for login. * * @(#)config.h 2.1 01:23:03 6/20/89 */ /* * Define DIALUP to use dialup password files */ #define DIALUP /* * Define SHADOWPWD to use shadow [ unreadable ] password file */ #define SHADOWPWD /* * Define DOUBLESIZE to use 16 character passwords */ #define DOUBLESIZE /* * Define OBSCURE to include hard password testing code. */ #define OBSCURE /* * Define PASSLENGTH to be shortest legal password */ #define PASSLENGTH 5 /* * Define NOBLANK if you want all passwords prompted for, including * empty ones. #undef NOBLANK /* * Define MAXDAYS to be the default maximum number of days a password * is valid for when converting to shadow passwords. Define MINDAYS * to be the minimum number of days before a password may be changed. * See pwconv.c for more details. */ #define MAXDAYS 10000 #define MINDAYS 0 /* * Define NDEBUG for production versions */ #define NDEBUG /* * Define HZ if login must set HZ value */ #define HZ "HZ=50" /* * Define TZ if login must set timezone * * The first example sets the variable directly. The * second example names a file which is read to determine * the proper value. The file consists of a single line * of the form 'TZ=zone-name' */ /* #define TZ "TZ=CST6CDT" */ #define TZ "/etc/tzname" /* * Define the default PATH and SUPATH here. PATH is for non-privileged * users, SUPATH is for root. The first pair are for real trusting * systems, the second pair are for the paranoid ... */ /* #define PATH "PATH=:/bin:/usr/bin" */ /* #define SUPATH "PATH=:/bin:/usr/bin:/etc" */ #define PATH "PATH=/bin:/usr/bin" #define SUPATH "PATH=/bin:/usr/bin:/etc" /* * Define the mailbox directory */ #define MAILDIR "/usr/spool/mail/" /* * Define AGING if you want the password aging checks made. */ #define AGING /* * Define MAILCHECK if you want the mailbox checked for new mail * * One of two messages are printed - `You have new mail.' or * `You have mail.'. */ #define MAILCHECK /* * Define CONSOLE if you want ROOT restricted to a particular terminal. * * Use the name of the tty line if you only want a single line, or use * the name of the file containing the permissible ports if you wish to * allow root logins on more than one port. */ /* #define CONSOLE "console" /* root on /dev/console only */ #define CONSOLE "/etc/consoles" /* check /etc/consoles for a list */ /* * Define NOLOGINS if you want to be able to deny non-root users logins. * Logins will not be permitted if this file exists. */ #define NOLOGINS "/etc/nologin" /* * Define NOUSE if you want to be able to declare accounts which can't * be logged into. */ #define NOUSE "NOUSE" /* * Define MOTD if you want the message of the day (/etc/motd) printed * at login time. */ #define MOTD /* * Define HUSHLOGIN if you want the code added to avoid printing the * motd if a file $HOME/.hushlogin exists. This obviously only matters * if any of MOTD, MAILCHECK or LASTLOG are #define'd. */ #define HUSHLOGIN /* * Define LASTLOG if you want a record made of logins in /usr/adm/lastlog. */ #define LASTLOG /* * Define FAILLOG if you want a record make of failed logins in * /usr/adm/faillog. See faillog.h for more details. See fail(1L) * for even still more details ... */ #define FAILLOG /* * Define TTYPERM to be the initial terminal permissions. Defining * as 0600 will not allow messages, 0622 will. */ #define TTYPERM 0600 /* * Define TTYTYPE to the be name of the port to terminal type * mapping file. This is used to set the environmental variable * "TERM" to the correct terminal type. */ #define TTYTYPE "/etc/ttytype" /* * Define QUOTAS if you want the code added in setup.c to support * file ulimit and nice [ and umask as well ] setting from the password * file. */ #define QUOTAS /* * Define file name for sulog. If SULOG is not defined, there will be * no logging. This is NOT a good idea ... We also define other file * names. */ #define SULOG "/usr/adm/sulog" #define PWDFILE "/etc/passwd" #define OPWDFILE "/etc/-passwd" #define NPWDFILE "/etc/npasswd" #define OSHADOW "/etc/-shadow" #define NSHADOW "/etc/nshadow" /* * Define PWDLOCK to be a locking semaphore for updating the password * file. */ #define PWDLOCK "/etc/.pwdlock" /* * Wierd stuff follows ... * * The following macros exist solely to override stuff ... * You will probably want to change their values to suit your * fancy. */ #define ERASECHAR '\b' #define KILLCHAR '\025' #define UMASK 022 #define ULIMIT (1L<<20) /* Define if your UNIX supports ulimit() */ #define FGETPWENT /* Define if library does not include FGETPWENT */ #define NEED_AL64 /* Define if library does not include a64l() */ SHAR_EOF fi if test -f 'pmain.c' then echo shar: "will not over-write existing file 'pmain.c'" else cat << \SHAR_EOF > 'pmain.c' #include #include #include #include #include #include #ifndef BSD #include #include #include #else #include #include #define strchr index #define strrchr rindex #endif #include "config.h" #include "lastlog.h" #include "shadow.h" #ifndef PASSLENGTH #define PASSLENGTH 5 #endif #ifndef lint static char _sccsid[] = "@(#)pmain.c 2.1 01:23:35 6/20/89"; #endif char name[BUFSIZ]; char orig[BUFSIZ]; char pass[BUFSIZ]; char pass2[BUFSIZ]; struct passwd pwent; #ifndef RETRIES #define RETRIES 3 #endif char *l64a (); char *crypt (); extern int errno; long a64l (); void entry (); time_t time (); int main (argc, argv) int argc; char **argv; { void die (); char *cp; char *getlogin (); int amroot; int lockfd = -1; #ifdef OBSCURE int force = 0; #endif int retries; #ifdef AGING long week; long lastweek; #endif long salttime; struct passwd *pw; struct passwd *getpwuid (); struct passwd *sgetpwent (); FILE *npwd; #ifdef SHADOWPWD struct spwd *spwd; struct spwd tspwd; #else FILE *pwd; char buf[BUFSIZ]; #endif char tmp[BUFSIZ]; argc--; argv++; /* shift ... */ if (! isatty (0) || ! isatty (1)) exit (1); die (0); /* save tty modes */ signal (SIGHUP, die); /* exit if SIGHUP */ signal (SIGINT, die); /* exit if SIGINT */ signal (SIGQUIT, die); /* exit if SIGQUIT */ signal (SIGTERM, die); /* exit if SIGTERM */ if (! (pw = getpwuid (getuid ()))) goto failure; /* can't get my name ... */ #ifdef OBSCURE if (argc > 0 && strcmp (argv[0], "-f") == 0) { force = 1; argc--; argv++; /* shift ... */ } #endif if (argc > 0) (void) strcpy (name, argv[0]); else if (cp = getlogin ()) /* need user name */ (void) strcpy (name, cp); else /* can't find user name! */ goto failure; printf ("Changing password for %s\n", name); amroot = getuid () == 0; /* currently am super user */ #ifdef OBSCURE if (! amroot) force = 0; #endif if (! amroot && strcmp (name, pw->pw_name) != 0) goto failure; entry (name, &pwent); /* get password file entry */ if (! pwent.pw_name) /* no entry for user??? */ goto failure; if (! amroot) { if (! password ("Old Password:", orig)) exit (1); if (! valid (orig, &pwent)) { puts ("Sorry."); exit (1); } } #ifdef AGING if (! amroot && pwent.pw_age) { /* check out the age */ #ifdef SHADOWPWD (void) time (&week); week /= (24L * 60L * 60L); /* days since epoch */ if (spwd = getspnam (name)) { /* use entries in shadow */ if (spwd->sp_min > spwd->sp_max) { puts ("You may not change this password"); exit (1); } if (spwd->sp_lstchg + spwd->sp_min > week) { printf ("Sorry, less than %d days since the last change\n", spwd->sp_min); exit (1); } } else { #endif /* SHADOWPWD */ (void) time (&week); week /= (7L * 24L * 60L * 60L); /* weeks since epoch */ lastweek = a64l (&pwent.pw_age[2]); if (c64i (pwent.pw_age[0]) < c64i (pwent.pw_age[1])) { puts ("You may not change this password"); exit (1); } if (c64i (pwent.pw_age[1]) + lastweek > week) { printf ("Sorry, less than %d weeks since the last change\n", c64i (pwent.pw_age[1])); exit (1); } #ifdef SHADOWPWD } #endif } #endif printf ("Enter new password (minimum of %d characters)\n", PASSLENGTH); #ifdef OBSCURE puts ("Please use a combination of upper and lowercase letters and numbers"); #endif retries = RETRIES; retry: if (! password ("New Password:", pass)) exit (1); #ifndef OBSCURE if (! obscure ()) { puts ("Password not changed."); exit (1); } #else if (! force && ! obscure ()) { if (retries-- > 0) { puts ("Please try again."); goto retry; } else goto toomany; } #endif if (! password ("Re-enter new password:", pass2)) exit (1); if (strcmp (pass, pass2) != 0) { puts ("They don't match; try again"); if (retries-- > 0) goto retry; else goto toomany; } #ifdef AGING if (pwent.pw_age) { cp = l64a (week); pwent.pw_age[2] = cp[0]; pwent.pw_age[3] = cp[1]; pwent.pw_age[4] = '\0'; } #endif (void) time (&salttime); salttime = ((salttime & 07777) ^ ((salttime >> 14) & 07777)) & 07777; pwent.pw_passwd = tmp; strcpy (pwent.pw_passwd, crypt (pass, l64a (salttime))); #ifdef DOUBLESIZE if (strlen (pass) > 8) { strcpy (pwent.pw_passwd + 13, crypt (pass + 8, l64a (salttime)) + 2); } #endif /* * Now we get to race the bad guy. I don't think he can get us. * * Ignore most reasonable signals. * Maybe we should ignore more? He can't hurt us until the end. * * Get a lock file. * * Copy first part of password file to new file. * Illegal lines are copied verbatim. * File permissions are r--r--r--, owner root, group root. * * Output the new entry. * Only fields in struct passwd are output. * * Copy the rest of the file verbatim. * * Rename (link, unlink) password file to backup. * Kill me now and nothing changes or no one gets in. * * Rename (link, unlink) temporary file to password file. * Kill me now and no one gets in or lock is left. * * Remove locking file. * * That's all folks ... */ signal (SIGHUP, SIG_IGN); signal (SIGINT, SIG_IGN); signal (SIGQUIT, SIG_IGN); signal (SIGTERM, SIG_IGN); umask (0); /* get new files modes correct */ #ifndef NDEBUG if ((lockfd = open (".pwdlock", O_RDONLY|O_CREAT|O_EXCL), 0444) == -1) #else if ((lockfd = open (PWDLOCK, O_RDONLY|O_CREAT|O_EXCL), 0444) == -1) #endif /* NDEBUG */ { puts ("Can't get lock"); exit (1); } umask (077); /* close security holes to come ... */ #ifdef SHADOWPWD if (access (NSHADOW, 0) == 0 && unlink (NSHADOW) == -1) goto failure; if ((npwd = fopen (NSHADOW, "w")) == (FILE *) 0) goto failure; if (chmod (NSHADOW, 0400) || chown (NSHADOW, 0, 0)) goto failure; setspent (); while (spwd = getspent ()) { if (strcmp (spwd->sp_namp, name) == 0) break; if (putspent (spwd, npwd)) goto failure; } if (spwd == (struct spwd *) 0) { /* didn't find a match */ spwd = &tspwd; /* use a local structure instead */ spwd->sp_namp = pwent.pw_name; spwd->sp_max = 10000; /* about as big as possible */ spwd->sp_min = 0; /* about as small as possible */ } spwd->sp_pwdp = pwent.pw_passwd; /* fixup the password */ (void) time (&lastweek); /* get the current time ... */ lastweek /= (24L*60L*60L); /* ... turn it into days. */ spwd->sp_lstchg = lastweek; /* save it as date of last change */ (void) putspent (spwd, npwd); /* add the new entry */ while (spwd = getspent ()) /* finish the other ones off */ (void) putspent (spwd, npwd); endspent (); if (ferror (npwd)) { perror (NSHADOW); if (unlink (NPWDFILE) || unlink (PWDLOCK)) fputs ("Help!\n", stderr); exit (1); } fflush (npwd); fclose (npwd); if (access (OSHADOW, 0) == 0) { if (unlink (OSHADOW)) { puts ("Can't remove backup file"); goto unlock; } } if (link (SHADOW, OSHADOW) || unlink (SHADOW)) { puts ("Can't save backup file"); goto unlock; } #ifndef BSD if (link (NSHADOW, SHADOW) || unlink (NSHADOW)) #else if (rename (NSHADOW, SHADOW)) #endif { (void) unlink (OSHADOW); puts ("Can't rename new file"); goto unlock; } if (unlink (OSHADOW)) { puts ("Can't remove backup file"); goto unlock; } #else /* ! SHADOWPWD */ if (access (NPWDFILE, 0) == 0 && unlink (NPWDFILE) == -1) goto failure; #ifndef NDEBUG if ((npwd = fopen ("npasswd", "w")) == (FILE *) 0) #else umask (077); /* no permissions for non-roots */ if ((npwd = fopen (NPWDFILE, "w")) == (FILE *) 0) #endif /* NDEBUG */ goto failure; #ifndef NDEBUG chmod (NPWDFILE, 0444); /* lets have some security here ... */ chown (NPWDFILE, 0, 0); /* ... and keep the bad guy away */ #endif /* NDEBUG */ if ((pwd = fopen (PWDFILE, "r")) == (FILE *) 0) goto failure; while (fgets (buf, BUFSIZ, pwd) != (char *) 0) { if (buf[0] == '#' || ! (pw = sgetpwent (buf))) { fputs (buf, npwd); } else if (strcmp (pw->pw_name, pwent.pw_name) != 0) fputs (buf, npwd); else break; } (void) fprintf (npwd, "%s:", pw->pw_name); if (pwent.pw_age) (void) fprintf (npwd, "%s,%s:", pwent.pw_passwd, pwent.pw_age); else (void) fprintf (npwd, "%s:", pwent.pw_passwd); (void) fprintf (npwd, "%d:%d:%s:%s:%s\n", pwent.pw_uid, pwent.pw_gid, pwent.pw_gecos, pwent.pw_dir, pwent.pw_shell ? pwent.pw_shell:""); while (fgets (buf, BUFSIZ, pwd) != (char *) 0) fputs (buf, npwd); if (ferror (npwd)) { perror (NPWDFILE); if (unlink (NPWDFILE) || unlink (PWDLOCK)) fputs ("Help!\n", stderr); exit (1); } fflush (npwd); fclose (npwd); #ifdef NDEBUG chmod (NPWDFILE, 0644); if (unlink (OPWDFILE) == -1) { if (errno != ENOENT) { puts ("Can't unlink backup file"); goto unlock; } } if (link (PWDFILE, OPWDFILE) || unlink (PWDFILE)) { puts ("Can't save backup file"); goto unlock; } #ifndef BSD if (link (NPWDFILE, PWDFILE) || unlink (NPWDFILE)) #else if (rename (NPWDFILE, PWDFILE)) #endif { puts ("Can't rename new file"); goto unlock; } #endif /* NDEBUG */ #endif /* SHADOW */ #ifndef NDEBUG (void) unlink (".pwdlock"); #else (void) unlink (PWDLOCK); #endif exit (0); /*NOTREACHED*/ failure: puts ("Permission denied."); unlock: if (lockfd >= 0) (void) unlink (PWDLOCK); (void) unlink (NPWDFILE); exit (1); /*NOTREACHED*/ toomany: puts ("Too many tries; try again later."); exit (1); /*NOTREACHED*/ } /* * die - set or reset termio modes. * * die() is called before processing begins. signal() is then * called with die() as the signal handler. If signal later * calls die() with a signal number, the terminal modes are * then reset. */ void die (killed) int killed; { #ifdef BSD static struct sgtty sgtty; if (killed) stty (0, &sgtty); else gtty (0, &sgtty); #else struct termio sgtty; if (killed) ioctl (0, TCSETA, &sgtty); else ioctl (0, TCGETA, &sgtty); #endif if (killed) exit (killed); } SHAR_EOF fi if test -f 'sulogin.c' then echo shar: "will not over-write existing file 'sulogin.c'" else cat << \SHAR_EOF > 'sulogin.c' #include #include #include #include #ifndef BSD #include #include #else #include #define strchr index #define strrchr rindex #endif #include "config.h" #ifndef lint static char _sccsid[] = "@(#)sulogin.c 2.1 01:24:02 6/20/89"; #endif char name[BUFSIZ]; char pass[BUFSIZ]; char home[BUFSIZ]; char prog[BUFSIZ]; char mail[BUFSIZ]; struct passwd pwent; struct utmp utent; #ifdef TZ FILE *tzfile; char tzbuf[16] = TZ; #endif #ifndef MAXENV #define MAXENV 64 #endif char *newenvp[MAXENV]; int newenvc = 0; int maxenv = MAXENV; extern char **environ; #ifndef ALARM #define ALARM 60 #endif #ifndef RETRIES #define RETRIES 3 #endif int main (argc, argv, envp) int argc; char **argv; char **envp; { char *getenv (); char *ttyname (); char *cp; if (access (PWDFILE, 0) == -1) { /* must be a password file! */ printf ("No password file\n"); exit (1); } #ifndef DEBUG if (getppid () != 1) /* parent must be INIT */ exit (1); #endif if (! isatty (0)) /* must be a terminal */ exit (1); while (*envp) /* add inherited environment, */ addenv (*envp++); /* some variables change later */ #ifdef TZ if (tzbuf[0] == '/') { if ((tzfile = fopen (tzbuf, "r")) != (FILE *) 0) { if (fgets (tzbuf, sizeof tzbuf, tzfile)) { tzbuf[strlen (tzbuf) - 1] = '\0'; addenv (tzbuf); } fclose (tzfile); } } else { addenv (tzbuf); } #endif #ifdef HZ addenv (HZ); /* set the default $HZ, if one */ #endif (void) strcpy (name, "root"); /* KLUDGE!!! */ while (1) { /* repeatedly get login/password pairs */ entry (name, &pwent); /* get entry from password file */ if (pwent.pw_name == (char *) 0) { printf ("No password entry for 'root'\n"); exit (1); } /* * Here we prompt for the root password, or if no password is * given we just exit. */ /* get a password for root */ if (! password ("Type control-d for normal startup,\n(or give root password for system maintenance):", pass)) exit (0); if (valid (pass, &pwent)) /* check encrypted passwords ... */ break; /* ... encrypted passwords matched */ puts ("Login incorrect"); } environ = newenvp; /* make new environment active */ puts ("Entering System Maintenance Mode"); /* * Normally there would be a utmp entry for login to mung on * to get the tty name, date, etc. from. We don't need all that * stuff because we won't update the utmp or wtmp files. BUT!, * we do need the tty name so we can set the permissions and * ownership. */ if (cp = ttyname (0)) { /* found entry in /dev/ */ if (strrchr (cp, '/') != (char *) 0) strcpy (utent.ut_line, strrchr (cp, '/') + 1); else strcpy (utent.ut_line, cp); } if (getenv ("IFS")) /* don't export user IFS ... */ addenv ("IFS= \t\n"); /* ... instead, set a safe IFS */ setup (&pwent); /* set UID, GID, HOME, etc ... */ shell (pwent.pw_shell); /* exec the shell finally. */ /*NOTREACHED*/ } SHAR_EOF fi if test -f 'dialup.h' then echo shar: "will not over-write existing file 'dialup.h'" else cat << \SHAR_EOF > 'dialup.h' /* * Structure of d_passwd file * * The d_passwd file contains the names of login shells which require * dialup passwords. Each line contains the fully qualified path name * for the shell, followed by an optional password. Each field is * separated by a ':'. * * Structure of the dialups file * * The dialups file contains the names of ports which may be dialup * lines. Each line consists of the last component of the path * name. Any leading directory names are removed. * * @(#)dialup.h 2.1 01:23:08 6/20/89 */ struct dialup { char *du_shell; char *du_passwd; }; void setduent (); void endduent (); struct dialup *getduent (); struct dialup *getdushell (); #define DIALPWD "/etc/d_passwd" #define DIALUPS "/etc/dialups" SHAR_EOF fi if test -f 'ttytype.c' then echo shar: "will not over-write existing file 'ttytype.c'" else cat << \SHAR_EOF > 'ttytype.c' #include #ifndef BSD #include #include #else #include #define strchr index #define strrchr rindex #endif #include "config.h" #ifdef TTYTYPE #ifndef lint static char _sccsid[] = "@(#)ttytype.c 2.1 01:24:04 6/20/89"; #endif /* * ttytype - set ttytype from port to terminal type mapping database */ void ttytype (line) char *line; { FILE *fp; char buf[BUFSIZ]; char termvar[BUFSIZ]; char *cp; char *type; char *port; char *getenv (); if (getenv ("TERM")) return; if (! (fp = fopen (TTYTYPE, "r"))) return; while (fgets (buf, BUFSIZ, fp)) { if (buf[0] == '#') continue; if (cp = strchr (buf, '\n')) *cp = '\0'; if ((type = strtok (buf, " \t")) && (port = strtok ((char *) 0, " \t"))) { if (strcmp (line, port) == 0) break; } } if (! feof (fp) && ! ferror (fp)) { strcat (strcpy (termvar, "TERM="), type); addenv (termvar); } fclose (fp); } #endif SHAR_EOF fi exit 0 # End of shell archive -- John F. Haugh II +-Button of the Week Club:------------- VoiceNet: (512) 832-8832 Data: -8835 | "AIX is a three letter word, InterNet: jfh@rpp386.Cactus.Org | and it's BLUE." UucpNet : !bigtex!rpp386!jfh +--------------------------------------