tony%ajfcal@cpsc.ucalgary.ca (Tony Field) (04/01/91)
Submitted-by: Tony Field <tony%ajfcal@cpsc.ucalgary.ca> Posting-number: Volume 17, Issue 76 Archive-name: login/part01 Login.c is a replacement for AT&T SysV/386 (or Interactive Unix) /bin/login. Most of the features of standard /bin/login are provided as well as a non-standard "user access control" that may be used to restrict user access based on dates, times, days of the weeek and tty line. Tony ------ #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: Readme login.1 login.4 Makefile login.c # Wrapped by ajf@ajfcal on Fri Mar 29 00:18:32 1991 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'Readme' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Readme'\" else echo shar: Extracting \"'Readme'\" \(2846 characters\) sed "s/^X//" >'Readme' <<'END_OF_FILE' X login.c X X/bin/login replacement for AT&T SysV/386 3.2 and Interactive Unix. X XAt present, this login cannot be used as a replacement for XInteractive's /etc/netlogin: rlogin fails (however telnet works). X((( can anybody help!!! ))) X XThis version of login replicates most of the actions of the standard Xlogin provided with AT&T SysV/386 unix. The standard man page apply, or Xthe provided man pages may be used. X XAT&T and Interactive Unix man pages do not document the /etc/dialups & X/etc/d_passwd files, however the dialup feature does indeed exist in the Xdistribution login programme. This and the non-standard "user access Xsecurity" extension are documented in login.4. X XThis version of login supports "user access security". If file X/etc/usrtime exits, it is processed to restrict the tty line, day of Xweek, and time of user access. Additional options allow all users, uucp Xusers and interactive users to be controlled on a global basis. The Xformat of this file is: X X <user>:<enable>:<tty>:<weekday>:<time>:<comment> X Xfor example: X X ajf:LOGIN:/dev/tty01:Mon,Tue:0800-1700:Temp employee X X XSUPPORTED: X 1. /etc/passwd, /etc/shadow X 2. /etc/default/login X 3. /etc/dialups, /etc/d_passwd X 4. /etc/utmp, /etc/wtmp X 5. /usr/adm/loginlog X 6. /etc/ttytype X 7 .lastlogin X 8. /etc/usrtime (non-standard feature) X XNOT IMPLEMENTED: X 1. what are /usr/lib/uucp/uucico, sublogin, syscon, stty used for? X these files are text strings in the original AT&T binary for login X but are not implemented in this login routine. X 2. internationalization as in Interactive unix. X 3. tcp/ip network rlogin support. X XDIFFERENCES: X 1. TIMEOUT= in /etc/default/login is the total elapsed time required X for a successful user name and password. The AT&T manuals X indicate that this really should be the number of seconds X between receipt of a userid and the receipt of a password. X 2. This login assumes a sane tty condition. X 3. CONSOLE= in /etc/default/login accepts colon-separated devices X as well as "?" wildcard specifications. X CONSOLE=/dev/console:/dev/vt?? X 4. User access security (/etc/usrtime) is not standard. X 5. Change of the root directory is implemented as per AT&T man X pages, however, I cannot figure out why the functionality X exits! No "useful" results could be found. X 6. The -p (preserve environment) is not standard for interactive X login (however is a standard feature for tcp/ip login). X 7. Of course, other differences exist..... X X XINSTALL: X======== XCheck the Makefile before compilation to define your OS and compiler. X X X----------------------------------------------------------------------------- Xtony field X X uucp: tony@ajfcal.uucp X ..uunet!watmath!calgary!ajfcal!tony X Xinternet: tony%ajfcal@cpsc.ucalgary.ca (I hope!) END_OF_FILE if test 2846 -ne `wc -c <'Readme'`; then echo shar: \"'Readme'\" unpacked with wrong size! fi # end of 'Readme' fi if test -f 'login.1' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'login.1'\" else echo shar: Extracting \"'login.1'\" \(4951 characters\) sed "s/^X//" >'login.1' <<'END_OF_FILE' X.TH LOGIN 1 "" X.SH NAME Xlogin \- sign on user X X.SH SYNOPSIS X X.B login X[ X.B -p X] X[ X.B name X[ X.B env-var ... X]] X X where -p = perserve environment X name = user login name X env-var = environment variable X.fi X X.SH DESCRIPTION X XThe X.B login Xcommand allows the user to identify himself to the system. XIt may be invoked as a command or by the system (usually by X.B getty X) when the user first logs in. X XIf X.B login Xis invoked as a command, it must replace the initial Xcommand interpreter by typing: X X.nf X exec login X.fi X Xfrom the initial (lowest level) shell. X XIf a user name is not supplied as a command line argument, X.B login Xprompts the user for a user name. If passwords are required Xfor the user, then a password is requested. Echoing is turned Xoff (if possible) during the entry of the password to ensure that Xthe password is not displayed on the terminal. X XIf five unsuccessful user name and password combinations are Xattempted, the the erroneous attempts are recorded in X.B \/usr\/adm\/loginlog X(if it exits). Null entries to the login id are not recorded. XThe terminal is disabled for a period of time Xafter the unsuccessful attempts. X XIf a successful login is not received within 120 seconds, X.B login Xsilently disconnects the terminal and returns control to X.B getty. X XAfter successful login, the user\'s user ID, group ID, and login directory Xare initialized. The user is informed of the date and time of Xhis last login (as set in file X.B \.lastlogin X). If the X.B \.lastlogin Xfile has been modified by some process other than X.B login, Xthe user is warned of a possible breach of his account security. X XSubsequently, the user\'s shell (possibly sh(1) or csh(1)) Xis invoked. As part of the shell startup script ( X.B \.profile Xor X.B \.login X), the message of the day (if any) is printed. X XThe basic environment is initialized to include: X X.nf X X HOME=user login directory X PATH=:/bin:/usr/bin X SHELL=shell from /etc/passwd X MAIL=/usr/mail/name X TZ=timezone spec X LOGNAME=usr login name X TERM=terminal type X.fi X XAdditional environment entries may be automatically provided by Xthe shell startup scripts or, if login is executed from the Xcommand line, by command line options. X XCommand line environment options may be of the form: X X.nf X xxxx X or X var=yyy X.fi X XIf the option contains an equal sign, then variable and value Xis placed into the environment as specified. If the variable Xis LOGNAME, CDPATH, HOME, PATH, SHELL, MAIL, TZ, HZ or IFS, Xit is are silently ignored for security reasons. X XIf the option does not contain an equal sign, then the option Xis placed in the environment with the format: X X.nf X Ln=xxx X.fi X Xwhere n is a number starting from 0 and is incremented each time Xa new variable is required. X X.SH OPTIONS X X.TP X.B -p X XIf this option is not provided, X.B login Xinitializes the environment to an empty condition before Xconstruction of the new users environment. X XIf this option is provided, then the existing environment Xis preserved. Environment values generated during Xthe login process replace existing values, however other values Xremain as set in the original environment. X X.SH SUBSYSTEM LOGINS X XIf the user's shell as specified in X.B /etc/passwd Xis "*", then the directory specified as the user's login directory Xbecomes the root directory (i.e. search paths starting with "/" will Xstart from this directory), and login is re-executed. The new Xroot directory must have it's own X.B /etc/passwd, /bin/login Xand X.B /dev Xfiles. X XThe user is informed that a "Subsystem login" is being performed. X X.SH LOGIN DEFAULTS X XVarious login default conditions are described in X.B /etc/default/login. X X X.SH DIALUP PASSWORDS X XAuxiliary passwords may be set up for users on selected tty Xlines to provide additional security with Xfiles X.B /etc/dialups Xand X.B /etc/d_passwd. X X.SH USER ACCESS RESTRICTIONS X XIf file X.B /etc/usrtime Xexits, it is processed to allow restrictions on Xaccess for different times of the day, days of Xthe week, or terminal lines for selected users. X X.SH FILES X.nf X /etc/utmp accounting X /etc/wtmp accounting X /usr/mail/name user mailbox X /usr/adm/loginlog record of failed login attempts X /etc/passwd password file X /etc/shadow optional shadow password file X /etc/group group file X /etc/profile system profile (/bin/sh only) X /etc/dialups list of dialup tty lines X /etc/d_passwd passwords for shells on dialup lines X /etc/ttytype default terminal type on tty line X /etc/default/login default parameters for login X /etc/usrtime time/tty restrictions for user X \.lastlogin date of last login X.fi X X.SH SEE ALSO X Xlogin(4), mail(1), sh(1), csh(1), bash(1), newgrp(1M), su(1M). Xloginlog(4), passwd(4), profile(4), environ(5) END_OF_FILE if test 4951 -ne `wc -c <'login.1'`; then echo shar: \"'login.1'\" unpacked with wrong size! fi # end of 'login.1' fi if test -f 'login.4' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'login.4'\" else echo shar: Extracting \"'login.4'\" \(8995 characters\) sed "s/^X//" >'login.4' <<'END_OF_FILE' X.TH LOGIN 4 "" X.SH NAME Xlogin: /etc/default/passwd, /etc/usrtime, /etc/d_passwd, /etc/dialups \- login files X X.SH DESCRIPTION X XA number of files besides X.B /etc/passwd Xand X.B /etc/shadow Xare used by the login process to set default user conditions and Xprovide additional access security. X XThe X.B /etc/default/passwd Xfile provides default values for the user environment. X XThe X.B /etc/usertime Xfile provides time, day, and terminal line control on a per-user basis. X XThe X.B /etc/d_passwd Xand X.B /etc/dialups Xfiles allow additional passwords to be associated with tty lines Xand specific shells. X X.SH LOGIN DEFAULT VALUES X XVarious X.B login Xstartup options may be set in the default control file. XThese options are of the form: X X.nf X OPTION=value X.fi X Xand may be placed in X.B \/etc\/default\/login Xin any order. (Comment lines begin with #.) X X.TP X.B TIMEOUT= Xspecified the total elapsed time in seconds before login silently Xterminates and returns control to the X.B getty Xprocess. The user is allowed five attempts within this time period Xto enter a valid login and password sequence. The default Xvalue is 120 seconds. X X.TP X.B ULIMIT= Xspecifies the maximum size (in 512 byte blocks) of file the user Xis allowed to create. No default value is provided. X X.TP X.B TZ= Xdefines the current time zone, for example, MST7MDT. The Xdefault value is EST5EDT. X X.TP X.B HZ= Xdefines the computers clock tick frequency in Hertz. No default Xvalue is provided. X X.TP X.B CONSOLE= Xsets the allowable terminal devices (from /dev) for a superuser Xlogin. If this parameter is not specified, the superuser may Xlogin from any terminal. If multiple devices are permitted, they Xmust be separated by a colon: X X.nf X CONSOLE=/dev/console:/dev/tty02:/dev/vt01 X.fi X XA wild-card match character of "?" is permitted for the Xdevice names. The specification of: X X.nf X /dev/tty?? X.fi X Xwill match any tty number with two symbols following the "tty". X X.TP X.B PASSREQ= Xmay be set to YES to force all users to have passwords or may be Xset to NO if accounts without passwords are permitted. The default Xvalue is YES. X X.TP X.B ALTSHELL= Xmay be set to YES if the login shell\'s name is to be recorded in Xthe enviornment, or to NO if it is not to be recorded in then Xenvironment. The default value is YES. X X.TP X.B PATH= Xmay be set to the default user path. If this is not provided, Xthe default path is set to \/bin:\/usr\/bin. X X.TP X.B SUPATH= Xmay be set to the default path for superuser logins. If this is Xnot provided, the default superuser path is \/bin:\/etc:\/usr\/bin. X X.TP X.B UMASK= Xmay be set to the desired default octal value for umask. No default Xvalue is provided. X X.TP X.B IDLEWEEKS= Xmay be set to the number of weeks before a login is disabled Xfor lack of use. By default, this value is not set. X X X.SH DIALUP PASSWORDS X XAuxiliary passwords may be set up for users on selected tty Xlines to provide additional security. The specific tty lines Xrequiring the additional passwords are defined in X.B \/etc\/dialups Xwith one device name per line, eg: X X.nf X /dev/tty01 X /dev/vt07 X.fi X XThe actual passwords are recorded in X.B \/etc\/d_passwd Xwhich has a format similar to that of X.B \/etc\/passwd. XEach password is associated with a specific shell. XThe format of the entries is: X X.nf X <shellname>:<encrypted password>:<comment> X.fi X XIf the shellname is missing, then the line containing the Xentry is the default for all shells not listed in other Xlines of the file. If the password is missing, no password is Xrequired from users of the shell. X XA reasonable example would be: X X.nf X :<encrypted password>:default dialup password X /usr/lib/uucp/uucico::UUCP logins don't have extra password X /bin/sh:<encrypted password>:normal dialup extra password X /bin/csh:<encrypted password>:normal dialup extra password X.fi X XOne useful application of these features is to reserve Xselected dialin ports for UUCP usage only. This is done Xby providing a list of UUCP-only tty lines in X.B /etc/dialups Xand setting a password for all shells except uucico. XThe interactive users calling on the UUCP-only lines Xwill not know the password. Since no password is assigned Xto the uucico shell, the UUCP users have normal access. X XNormal password services do not allow construction of the X.B \/etc\/d_passwd Xfile. One way to do so is to create a temporary user Xwith the desired password. With an editor (vi), manually Xcopy the password from X.B \/etc\/passwd Xor X.B \/etc\/shadow Xinto the working copy of X.B \/etc\/d_passwd. X XSubsequently, permissions should be set to: X X.nf X chmod 644 /etc/d_passwd /etc/dialups X chown bin /etc/d_passwd /etc/dialups X chgrp other /etc/d_passwd /etc/dialups X.fi X X X.SH USER ACCESS RESTRICTIONS X XIf file X.B /etc/usrtime Xexits, it is processed to allow restrictions on Xaccess for different times of the day, days of Xthe week, or terminal lines for selected users. X XComment lines may be in the file: such lines start Xwith a #. X XThe format of this file is X X.nf X <user>:<enable>:<tty>:<weekday>:<time>:<comment> X Xfor example: X X ajf:LOGIN:/dev/tty01:Mon,Tue:0800-1700:Temp employee X.fi X X X.TP X.B user Xis a comma-separated list of user names that is to be restricted. XThe names should be present in X.B /etc/passwd. X X.nf XFor example: ajf,guest,bill: X.fi X XIf the X.B user Xfield is empty, then the line becomes a default for all users Xnot specifically mentioned in the remaining part of the file. X XThree special values ("ALL", "UUCP", Xor "INTERACTIVE") may be optionally used in the X.B Xuser Xfield. The restrictions defined in Xthese lines apply in a global sense. Not only is a user restricted to Xlog in as defined by his private line entry, he is further restricted Xby the definitions in the "ALL" and/or "INTERACTIVE" line. X.B UUCP Xusers (i.e. those users with a login shell of X.B /usr/lib/uucp/uucico X) are also restricted by the parameters in the "UUCP" and "ALL" lines. XSuch lines are normally placed at the beginning of the file. X XThe root user is never restricted. If other Xusers need guaranteed access (e.g. other administrative Xaccounts), they should be described in the file Xbefore the "ALL", "UUCP" and "INTERACTIVE" users. Such users Xare normally unrestricted: X X.nf X sys,bin,adm,powerdown,sysadm::::: X.fi X XIf a user is not mentioned in X.B /etc/usrtime, Xthen the user is not subject to time restrictions unless Xa default user, "ALL", "INTERACTIVE" or "UUCP" entries Xare defined. X X.TP X.B enable Xdetermines if the user's login is enabled or disabled. XA login is disabled with "NOLOGIN". Login may be enabled with "LOGIN" Xor an empty field. X XIf the X.B enable Xfield contains date ranges of the form: X X.nf X yyyymmdd-yyyymmdd X Xfor example: :19901201-19910308: X.fi X Xthen user logins are accepted only over the stipulated date range or Xcomma-separted date ranges. X XIf the key word "NOLOGIN" Xis present for "ALL", "UUCP", or "INTERACTIVE" users, then Xlogin is disabled appropriately without further processing Xof user names. X X.TP X.B tty Xis a list of permitted devices the user may access. More than Xone device must be separated by commas. If X.B tty Xis empty, then the user may log in on all devices. X X.nf XFor example: :/dev/tty01,/dev/tty02: X.fi X XA wild-card match character of "?" is permitted for the Xdevice names. The specification of: X X.nf X :/dev/tty??: X.fi X Xwill match any tty number with two symbols following the "tty". X X.TP X.B weekday Xis a list of days that the user is permitted to log in. The list Xof days is comma-separated and chosen from: X X.nf X Mon, Tue, Wed, Thu, Fri, Sat, Sun X Xfor example: :Mon,Wed,Fri: X.fi X XIf the X.B weekday Xfield is empty, then no day restrictions are imposed. X X.TP X.B time Xis a list of comma-separated time ranges that the user is permitted Xto log in. A time range is of the form: X X.nf X hhmm-hhmm X Xfor example: :0800-1200,1300-1700: X.fi X XIf the X.B time Xfield is empty, then no time restrictions are imposed. X X.TP X.B comment Xis arbitrary commentary that is ignored. X X.SH NOTES XFor security reasons, the permissions on X.B /etc/usrtime Xshould be set to: X X.nf X chown root /etc/usrtime X chgrp sys /etc/usrtime X chmod 400 /etc/usrtime X.fi X XAn example of a X.B usrtime Xfile is: X X.nf X # <user>:<enable>:<tty>:<weekday>:<time>:<comment> X sys,bin,adm,powerdown,sysadm::::: X operator::::: X ALL::::0400-2200:midnite shift for backups only X INTERACTIVE:::Mon,Tue,Wed,Thu,Fri:0630-1830: X UUCP::::: X ::::0800-1700:default for anybody not mentioned below X bill,loris:LOGIN:/dev/ttyi1a::0830-1630:accounting X anil,byron:LOGIN:/dev/tty???:::engineering X harry:NOLOGIN:/dev/tty???:::on holidays X aubry:19910401-19910431::::contract programmer X.fi X X.SH LIMITS XLines in X.B /etc/usrtime Xare limited to 500 characters in length. Unpredictable Xresults may be expected if this limit is exceeded. X X.SH SEE ALSO X Xlogin(1), passwd(4), loginlog(4), utmp(4) END_OF_FILE if test 8995 -ne `wc -c <'login.4'`; then echo shar: \"'login.4'\" unpacked with wrong size! fi # end of 'login.4' fi if test -f 'Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Makefile'\" else echo shar: Extracting \"'Makefile'\" \(1371 characters\) sed "s/^X//" >'Makefile' <<'END_OF_FILE' X# login -- for AT&T unix SysV / 3.2.2 X X# Set operating system. X# X# -DATT for AT&T unix 3.2.2 X# -DIAC for Interactive 2.2 X X# OS=-DATT XOS=-DIAC X X# Set UA=-DUSRACCESS if user access time feature is used (see login.4) X# UA= if not X XUA=-DUSRACCESS X# UA= X X# Set -DNOISY if you want unsuccessful login attempts to be X# reported to the user. Otherwise, login is silent X# about failures. Standard login reports unsuccessful attempts. X X# QUIET=-DNOISY XQUIET= X X# Set PG=-DPOSIX_GROUPS if supplimentary groups are used (not for AT&T) X# Set LIBS to ensure that initgroups() and alloca() are available X# TCP/IP connection on Interactive need -linet X# Usually, initgroups() in -lcposix (ATT unix does not have this) X# alloca() in -lPW (if GCC is used, don't define -lPW) X XPG=-DPOSIX_GROUPS X# LIBS=-lPW XLIBS=-lcposix -linet X# PG= X# LIBS=-lPW X X# Set compiler X XCC=gcc -traditional X# CC=cc X XCFLAGS= -O $(OS) $(QUIET) $(PG) $(UA) XSRC= login.c X X Xall: login X Xlogin: login.c X ${CC} $(CFLAGS) -o $@ $@.c $(LIBS) X Xtar: X tar cvf login.tar Readme login.1 login.4 Makefile $(SRC) X Xshar: X shar Readme login.1 login.4 Makefile $(SRC) > login.shar X Xclean: X rm -f ${OBJS} core login udump *.B *~ X Xinstall: X install -f /bin -u root -g bin -m 4755 login X X# install -f /usr/man/man.1 -u bin -g bin -m 644 login.1 X# install -f /usr/man/man.4 -u bin -g bin -m 644 login.4 END_OF_FILE if test 1371 -ne `wc -c <'Makefile'`; then echo shar: \"'Makefile'\" unpacked with wrong size! fi # end of 'Makefile' fi if test -f 'login.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'login.c'\" else echo shar: Extracting \"'login.c'\" \(30942 characters\) sed "s/^X//" >'login.c' <<'END_OF_FILE' X/* ta=4 tabs are set to 4. vi: "set ts=4" */ X/**************************************************************************** X* l o g i n . c * X* * X* tony field * X* uucp: tony@ajfcal.uucp * X* ..uunet!watmath!calgary!ajfcal!tony * X* internet: tony%ajfcal@cpsc.ucalgary.ca * X****************************************************************************/ X X/* login replacement for AT&T SysV/386 3.2 and Interactive Unix. X X Replicate most (at least many) of the actions of the standard X /bin/login provided with AT&T unix. User access security is added. X The standard man pages apply except for /etc/usrtime. X XInteractive & AT&T /etc/utmp entries are different! (why??) X Interactive contains devices as: X root console X LOGIN /dev/vt02 <--- X ajf ttyp0 X AT&T contains devices as: X root console X LOGIN vt02 <--- X ajf ttyp0 X X The device comparison for Interactive must be able to X handle /dev/xxx or xxx format in utmp - seems to be X related only to /dev/vt?? devices. X XNOTE: does not yet work as a replacement for /etc/netlogin. X It seems to work for telnet access but not rlogin access. X X called by telnet: login -p X called by rlogin: login -r <systemid> X called by getty: login <username> X X -p = preserve environment X -r = invoked by rlogind X XREVISIONS: X========== X 1991-Mar-06: Interactive V 2.2 conversion. X 1. add posix group support - initgroups() X 2. correct /etc/utmp differences AT&T vs. Interactive X*/ X X#include <stdio.h> X#include <sys/types.h> X#ifdef IAC X#include <utime.h> X#endif X#include <sys/stat.h> X#include <unistd.h> X#include <signal.h> X X#include <termio.h> X X#include <sys/ioctl.h> X#include <fcntl.h> X#include <string.h> X#include <time.h> X#include <utmp.h> X#include <pwd.h> X X#ifdef __GNUC__ X#define alloca __builtin_alloca X#else /* not __GNUC__ */ Xchar *alloca (); X#endif X X#define TIMEOUT 120 /* seconds before login aborted*/ X#define MAXBAD 5 /* max allowed login attempts */ X#define BADLOGINTIME 200 /* wait time before allowing new logins */ X#define MAXUSERNAME 25 /* size of user name */ X X#define DEFAULTSHELL "/bin/sh" X#define USERPATH "/bin:/usr/bin" X#define ROOTPATH "/bin:/etc:/usr/bin" X#define MAIL "/usr/mail" X#define DEFAULTTZ "EST5EDT" X X#define BINPASSWD "/bin/passwd" X X#define DIALUPTTY "/etc/dialups" X#define DIALUPPWD "/etc/d_passwd" X#define SHADOW "/etc/shadow" X#define LASTLOGIN ".lastlogin" X#define DEFAULTFILE "/etc/default/login" X#define LOGINLOG "/usr/adm/loginlog" X#define TTYTYPE "/etc/ttytype" X#define WTMP "/etc/wtmp" X#define USRTIME "/etc/usrtime" X X#define ROOT 0 X X/* user is forbidden to modify these with login command line options */ Xchar *forbidden[] = {"HOME=", "PATH=", "SHELL=", "MAIL=", "IFS=", X "HZ=", "CDPATH=", "LOGNAME=", NULL }; X X#define MAXPATHLEN 300 X#define LONGLINE 500 X#define SHORTLINE 100 X X#ifdef ATT Xstruct utimbuf /* missing from /usr/include */ X{ time_t actime; /* access time */ X time_t modtime; /* modification time */ X} ; X#endif X X#ifdef USRACCESS Xstruct usrtime /* fields within /etc/usrtime */ X{ char *enable; X char *ttyline; X char *days; X char *timerange; X} ; X#endif X Xlong shadow_lstchg, shadow_min, shadow_max; X X#ifdef __STDC__ Xint main(int argc, char **argv); Xint dialup_pwd(char *ttyfname, char *pwdfname, char *tty_name, struct passwd *pwd); X#ifdef USRACCESS Xint get_usrtime(char *fname, char *user, char *shell, char *tty); Xint check_user(long *now, char *tty, struct usrtime *usr); Xint check_tty(char *tty, char *list); Xint check_day(long now, char *list); Xint check_time(long now, char *list, int timerange); X#endif Xvoid setenv(char *this, char *val); Xvoid check_putenv(char *val); Xchar *get_shadow(char *fname, char *user, int allow); Xchar *search_ttytype(char *tty); Xint get_defaults(char *fname, char *tz, char *hz, char **console, long *ulim, int *passreq, int *altshell, char **path, char **supath, long *timeout, int *cmask, int *idleweeks); Xvoid trim(char *s); Xint atoo(char *s); Xvoid user_timeout(void); Xint tscan(char s[], char t[]); Xint qtscan(char s[], char t[]); X#else Xint main(); Xint dialup_pwd(); X#ifdef USRACCESS Xint get_usrtime(); Xint check_user(); Xint check_tty(); Xint check_day(); Xint check_time(); X#endif Xvoid setenv(); Xvoid check_putenv(); Xchar *get_shadow(); Xchar *search_ttytype(); Xint get_defaults(); Xvoid trim(); Xint atoo(); Xvoid user_timeout(); Xint tscan(); Xint qtscan(); X#endif X X Xextern char *getpass(), *crypt(), *malloc(); Xlong timeout; /* TIMEOUT from /etc/default/login */ Xlong atol(); Xint atoi(); X Xmain (argc, argv) Xint argc; Xchar **argv; X{ X char *login_name; /* user login id */ X char user_name[SHORTLINE+1]; X char *tty_name, *tty_n, *ttyname(); /* tty name for user */ X int i; X struct passwd *getnam(); X struct passwd *pwd; X char shell[MAXPATHLEN + 1]; X char term[SHORTLINE + 1]; X char buffer[MAXPATHLEN+1], *p; X char *shadow, *my_pass; X char *ctime(); X long ulimit_blocks; /* ULIMIT from /etc/default/login */ X char tz[50]; /* TZ " */ X char hz[50]; /* HZ " */ X char *console; /* CONSOLE " */ X int passreq; /* PASSREQ " */ X int altshell; /* ALTSHELL " */ X char *path; /* PATH " */ X char *supath; /* SUPATH " */ X int cmask; /* UMASK " */ X int idleweeks; /* IDLEWEEKS " */ X int passwd_needed = 0; X int null_user_count; X int lcreate; X char bad_user[MAXBAD][MAXUSERNAME+1]; X extern char **environ, *optarg; X extern int optind; X int c; X char *domain, *hostname, *environ_init[1]; X int preserve = 0; X X X#ifndef NETWORK X /* this is valid only for /bin/login. */ X if (getppid () != 1) X { fprintf (stderr, "login must be 'exec'ed from lowest level shell.\n"); X exit (1); X } X#endif X X#if defined (IAC) && defined (NETWORK) X gethostname(buffer, sizeof(buffer)); X domain = strchr (buffer, '.'); X hostname = NULL; X#endif X X while ((c = getopt(argc, argv, "pr:")) != -1) X { X switch (c) X { X case 'p': /* preserve environment */ X preserve = 1; X break; X#if defined (IAC) && defined (NETWORK) X case 'r': /* rlogind initiated this call, remote host name */ X if (getuid()) X { fprintf (stderr, "%s: -r for superuser only\n", argv[0]); X exit (1); X } X if (domain && (p = strchr (optarg, '.')) && X strcasecmp(p, domain) == 0) X *p = 0; X hostname = optarg; X break; X#endif X default: break; X } X } X X console = path = supath = NULL; X *tz = *hz = '\0'; X idleweeks = timeout = cmask = -1; X ulimit_blocks = 0; X passreq = 1; X altshell = 1; X shadow_lstchg = -1; X X signal (SIGALRM, user_timeout); X alarm (TIMEOUT); X signal (SIGQUIT, SIG_IGN); X signal (SIGINT, SIG_IGN); X X if (optind < argc) X login_name = argv[optind++]; X else X login_name = NULL; X X tty_name = ttyname (0); X if (tty_name == NULL || *tty_name == '\0') X tty_name = "/dev/tty??"; X if ((tty_n = strrchr (tty_name, '/'))) X tty_n++; X else X tty_n = tty_name; X X /* get defaults from /etc/default/login */ X X get_defaults (DEFAULTFILE, tz, hz, &console, &ulimit_blocks, &passreq, X &altshell, &path, &supath, &timeout, &cmask, &idleweeks); X if (timeout != -1) X alarm (timeout); X else X timeout = TIMEOUT; X if (path == NULL) X path = USERPATH; X if (supath == NULL) X supath = ROOTPATH; X if (*tz == '\0') X strcpy (tz, DEFAULTTZ); X X /* accept a user's login user name and password */ X X for (null_user_count = i = 0; i < MAXBAD; i++) X { char *salt, *pass, *pass_crypt; X if (login_name) X { strcpy (user_name, login_name); X login_name = NULL; X } X else X { fprintf (stdout, "login: "); X fgets (user_name, SHORTLINE, stdin); X user_name[SHORTLINE] = 0; X trim (user_name); X user_name[MAXUSERNAME] = '\0'; X strcpy (bad_user[i], user_name); X if (*user_name == '\0') X { null_user_count++; X continue; X } X } X if ((pwd = getpwnam (user_name))) X { if (*(pwd->pw_shell) == '*') X { /* see 'real' man page for login for * in shell field. X must change the root directory, then rerun login X with the new root looking at new password file... X HOWEVER, this does not work as I expected. X */ X if (chroot (pwd->pw_dir)) X { perror ("Could not change to your root directory: "); X exit (1); X } X fprintf (stderr, "Subsystem root = %s\n", pwd->pw_dir); X execlp ("login", "login", 0); X perror ("No login on subsystem: "); X exit (1); X } X X /* valid user. shadow file may or may not exist */ X if ((strcmp (pwd->pw_passwd, "x") == 0) && (shadow = get_shadow (SHADOW, user_name, 0))) X { salt = shadow; X my_pass = shadow; X } X else X my_pass = salt = pwd->pw_passwd; X } X else /* invalid user */ X my_pass = salt = "xx"; X X if (*my_pass == '\0') X { /* bypass prompting if zero length */ X if (passreq) X passwd_needed = 1; /* ask user later */ X#ifdef USRACCESS X if (get_usrtime (USRTIME, user_name, pwd->pw_shell, tty_name)) X exit (1); X#endif X break; X } X X pass = getpass ("password: "); X if (pwd) X { /* get regular + dialup password + restrict time access */ X pass_crypt = crypt (pass, salt); X if ( !strcmp (pass_crypt, my_pass) X && !dialup_pwd (DIALUPTTY, DIALUPPWD, tty_name, pwd) X#ifdef USRACCESS X && !get_usrtime (USRTIME, user_name, pwd->pw_shell, tty_name) X#endif X ) X break; X } X#ifdef NOISY X if (i > 1) X sleep (i); X fprintf (stdout, "Login incorrect: try again.\n"); X#endif X } X alarm (0); /* turn of pending alarm */ X X if (i == MAXBAD) X { /* write the bad attempt to /usr/adm/loginlog. */ X FILE *fp; X time_t now; X X if (null_user_count < 3) X { if ((fp = fopen (LOGINLOG, "a"))) X { now = time (0L); X for (i = 0; i < MAXBAD; i++) X { if (*bad_user[i]) X fprintf (fp, "%s:%s: %s", bad_user[i], tty_name, ctime (&now)); X } X fclose (fp); X } X sleep (BADLOGINTIME); /* discourage further abuse */ X } X exit (1); X } X X /* if CONSOLE= is defined in /etc/default/login, then root may X root may log in only on the CONSOLE=device X */ X if (pwd->pw_uid == ROOT && console && *console) X { strcpy (buffer, tty_name); X strcat (buffer, ":"); X if (qtscan (console, buffer) < 0) X { fprintf (stderr, "Superuser must be on %s\n", console); X exit (1); X } X } X X if (*(pwd->pw_shell) == '\0') X strcpy (shell, DEFAULTSHELL); X else X strcpy (shell, pwd->pw_shell); X X if (chdir (pwd->pw_dir) < 0) X { perror ("Could not locate login directory"); X exit (1); X } X X { /* update utmp and wtmp (if wtmp exists) X For an original tty login, utmp will contain: X LOGIN /dev/vt01 X For exec login: X ajf vt01 X Must scan for either getutline() form. X */ X struct utmp *utmp; X struct utmp line, id; X struct utmp *getutline(); X X#ifdef IAC X /* first check for /dev/tty?? format */ X X memset ((char *)&line, '\0', sizeof(line)); X strncpy (line.ut_line, tty_name, sizeof(line.ut_line)); X if ((utmp = getutline (&line)) == NULL) X { X /* for tty?? format */ X setutent(); X memset ((char *)&line, '\0', sizeof(line)); X strncpy (line.ut_line, tty_n, sizeof(line.ut_line)); X if ((utmp = getutline (&line)) == NULL) X { fprintf (stderr, "No utmp entry.\n"); X exit (1); X } X } X#else X memset ((char *)&line, '\0', sizeof(line)); X strncpy (line.ut_line, tty_n, sizeof(line.ut_line)); X if ((utmp = getutline (&line)) == NULL) X { X fprintf (stderr, "No utmp entry.\n"); X exit (1); X } X#endif X memset ((char *)&id, '\0', sizeof(id)); X strncpy (id.ut_id, utmp->ut_id, sizeof(id.ut_id)); X (void) time (&id.ut_time); X strncpy (id.ut_name, user_name, sizeof(id.ut_name)); X strncpy (id.ut_line, tty_n, sizeof(id.ut_line)); X id.ut_pid = getpid(); X id.ut_type = USER_PROCESS; X pututline (&id); X X if (access (WTMP, W_OK) == 0) X { FILE *wtmp; X if ((wtmp = fopen (WTMP, "a"))) X { fwrite (&id, sizeof(id), 1, wtmp); X fclose (wtmp); X } X } X } X X if (pwd->pw_uid != ROOT && ulimit_blocks) X { if (ulimit (2, ulimit_blocks) == -1) X fprintf (stderr, "Could not set ULIMIT=%ld\n", ulimit_blocks); X } X X /* set user context: uid/gid and environment */ X X if (setgid (pwd->pw_gid)) X { perror ("Could not set gid=%d\n", pwd->pw_gid); X exit (1); X } X#ifdef POSIX_GROUPS X initgroups (user_name, pwd->pw_gid); /* posix supplimentary groups */ X#endif X if (setuid (pwd->pw_uid)) X { perror ("Could not set uid=%d\n", pwd->pw_uid); X exit (1); X } X X if (passwd_needed) X { fprintf (stdout, "A password is needed to log into this system. Choose one.\n"); X if (system (BINPASSWD)) X exit (1); X } X else if (shadow_lstchg >= 0) X { if ((time(NULL) / (24L*60*60) - shadow_lstchg) > shadow_max) X { fprintf (stdout, "Your password has expired. Choose a new one.\n"); X if (system (BINPASSWD)) X exit (1); X } X } X X /* lastlogin magic seems to use a 2 second difference in X the modified and access times of the .lastlogin file. X This is a guess....but it seems to work. X */ X sprintf (buffer, "%s/%s", pwd->pw_dir, LASTLOGIN); X if (access (buffer, 0)) X { FILE *fp; X fprintf (stdout, "Warning: creating .lastlogin\n"); X lcreate = 1; X if (fp = fopen (buffer, "w")) X { fclose (fp); X chmod (buffer, 0400); X } X } X else X lcreate = 0; X if (access (buffer, 0) == 0) X { struct stat sb; X struct utimbuf timset; X time_t now; X X if (stat (buffer, &sb) == 0) X { if (lcreate == 0) X { if (sb.st_mtime - sb.st_atime < 2) X fprintf (stdout, "Warning: .lastlogin has been modified since your previous login.\n"); X fprintf (stdout, "last login: %s", ctime (&sb.st_mtime)); X } X now = time (0L); X if (idleweeks > 0 && pwd->pw_uid != ROOT X && ((now - sb.st_atime) / (24L * 60 * 60 * 7 * (long) idleweeks)) >= idleweeks) X { fprintf (stderr, "Login disabled due to lack of usage.\n"); X exit (1); X } X timset.actime = now - 2; X timset.modtime = now; X utime (buffer, &timset); X } X } X else X fprintf (stderr, "Warning: could not find .lastlogin\n"); X X if (cmask != -1) X umask (cmask); X X if (!preserve) X { environ_init[0] = NULL; X environ = environ_init; X strncpy(term, search_ttytype(tty_n), sizeof(term)); X term[sizeof(term) - 1] = 0; X setenv ("TERM", term); X } X sprintf (buffer, "%s/%s", MAIL, user_name); X setenv ("MAIL", buffer); X setenv ("HOME", pwd->pw_dir); X setenv ("LOGNAME", user_name); X if (altshell) X setenv ("SHELL", shell); X if (pwd->pw_uid == ROOT) X setenv ("PATH", supath); X else X setenv ("PATH", path); X if (*tz) X setenv ("TZ", tz); X X for (i = optind; i < argc; i++) /* environment from command line */ X check_putenv (argv[i]); X X signal (SIGALRM, SIG_DFL); X signal (SIGQUIT, SIG_DFL); X signal (SIGINT, SIG_DFL); X#ifdef SIGTSTP X /* Interactive has job control signals, AT&T does not */ X signal (SIGTSTP, SIG_IGN); X#endif X X /* exec the desired shell */ X X buffer[0] = '-'; X strcpy (buffer + 1, (p = strrchr (shell, '/')) ? p + 1 : shell); X execlp (shell, buffer, 0); X fprintf (stderr, "login: no shell: "); X perror (shell); X exit (1); X} X X/**************************************************************************** X* read /etc/dialups & /etc/d_passwd, if they exist * X* Return 0 if user has access, 1 if no access * X****************************************************************************/ X Xint dialup_pwd (ttyfname, pwdfname, tty_name, pwd) Xchar *ttyfname; /* /etc/dialups */ Xchar *pwdfname; /* /etc/d_passwd */ Xchar *tty_name; /* user's tty line */ Xstruct passwd *pwd; /* user;s /etc/passwd file entry */ X{ FILE *fp; X char dtty[SHORTLINE+1]; X char *dpass, *dcrypt, *salt, *shell, *dialpass, *crypt(); X X if (pwd == NULL) X return (0); X X if (*(pwd->pw_shell)) X shell = pwd->pw_shell; X else X shell = DEFAULTSHELL; X if (access (ttyfname, 0)) X return (0); X if (fp = fopen (ttyfname, "r")) X { while (fgets (dtty, SHORTLINE, fp)) X { dtty[SHORTLINE] = 0; X trim (dtty); X if (strcmp (dtty, tty_name) == 0) X { fclose (fp); X if (dialpass = get_shadow (DIALUPPWD, shell, 1)) X { if (*dialpass == '\0') /* no password needed */ X return (0); X salt = dialpass; X } X else X return (1); X dpass = getpass ("dialup password: "); X dcrypt = crypt (dpass, salt); X if (strcmp (dcrypt, dialpass)) X return (1); X else X return (0); X } X } X fclose (fp); X } X return (0); X} X X#ifdef USRACCESS X/**************************************************************************** X* process /etc/usrtime, if it exists * X* Return 0 if user has access, 1 if no access * X****************************************************************************/ X Xint get_usrtime (fname, user, shell, tty) Xchar *fname; /* /etc/usrtime */ Xchar *user; /* user login name */ Xchar *shell; /* user's shell (from /etc/passwd) */ Xchar *tty; /* user's login tty line */ X{ X struct usrtime all, uucp, interact, genuser, thisuser, *which; X char line[LONGLINE+1]; X FILE *fp; X char *var[5], *colon; X char *uname, save_letter; X int failure, i; X long now; X char *uucico; X X if (strcmp (user, "root") == 0) X return (0); X X uucico = "uucico"; X all.enable = uucp.enable = interact.enable X = thisuser.enable = genuser.enable = NULL; X failure = 0; X uname = alloca (strlen (user) + 3); X strcpy (uname, user); X strcat (uname, ","); X if ((fp = fopen (fname, "r"))) X { X while (fgets (line, LONGLINE, fp)) X { line[LONGLINE] = '\0'; X if (*line == '#') X continue; X trim (line); X for (colon = line, i = 0; i < 5; i++) X { var[i] = colon; X colon = strchr (colon, ':'); X if (colon == NULL) X break; X *colon++ = '\0'; X } X if (colon == NULL) /* need min of 5 colons */ X continue; X which = NULL; X X /* select first instance of ALL, UUCP, INTERACTIVE or default */ X if (strcmp (var[0], "ALL") == 0) X { if (strcmp (var[1], "NOLOGIN") == 0) X { failure = 1; X break; X } X if (all.enable) X continue; X which = &all; X } X else if (strcmp (var[0], "UUCP") == 0) X { if (strcmp (var[1], "NOLOGIN") == 0 && tscan (shell, uucico) >= 0) X { failure = 1; X break; X } X if (uucp.enable) X continue; X which = &uucp; X } X else if (strcmp (var[0], "INTERACTIVE") == 0) X { if (strcmp (var[1], "NOLOGIN") == 0 && tscan (shell, uucico) < 0) X { failure = 1; X break; X } X if (interact.enable) X continue; X which = &interact; X } X else if (var[0][0] == '\0') X { /* general default user setup */ X if (genuser.enable) X continue; X which = &genuser; X } X X if (which) X { /* process ALL, UUCP, INTERACTIVE or default user lines */ X which->enable = alloca (strlen (var[1]) + 2); X which->ttyline = alloca (strlen (var[2]) + 2); X which->days = alloca (strlen (var[3]) + 2); X which->timerange = alloca (strlen (var[4]) + 2); X strcpy (which->enable, var[1]); X strcpy (which->ttyline, var[2]); X strcpy (which->days, var[3]); X strcpy (which->timerange, var[4]); X } X else X { /* standard user line */ X i = strlen (var[0]); X save_letter = var[1][0]; X strcat (var[0], ","); X if (tscan (var[0], uname) >= 0) X { var[0][i] = '\0'; /* undo comma */ X var[1][0] = save_letter; X thisuser.enable = var[1]; X thisuser.ttyline = var[2]; X thisuser.days = var[3]; X thisuser.timerange = var[4]; X if (strcmp (var[1], "NOLOGIN") == 0) X failure = 1; X break; X } X } X } X fclose (fp); X if (failure || (genuser.enable && thisuser.enable == NULL && strcmp (genuser.enable, "NOLOGIN") == 0)) X { fprintf (stderr, "Logins are temporarily disabled.\n"); X return (2); X } X now = time (NULL); X if ( (all.enable && check_user (now, tty, &all)) X || (uucp.enable && tscan (shell, uucico) >= 0 && check_user (now, tty, &uucp)) X || (interact.enable && tscan (tty, uucico) < 0 && check_user (now, tty, &interact)) X || (genuser.enable && thisuser.enable == NULL && check_user (now, tty, &genuser)) X || (thisuser.enable && check_user (now, tty, &thisuser))) X return (1); X } X return (0); X} X X/**************************************************************************** X* usrtime: check fields in sequence to see if user has access permission * X****************************************************************************/ X Xcheck_user (now, tty, usr) Xchar *tty; /* user's tty line */ Xlong *now; /* current time of day (now=time(NULL)) */ Xstruct usrtime *usr; /* various values from /etc/usrtime */ X{ X return ( check_time (now, usr->enable, 0) X || check_tty (tty, usr->ttyline) X || check_day (now, usr->days) X || check_time (now, usr->timerange, 1)); X} X X/**************************************************************************** X* usrtime: ensure usr is on acceptable tty line * X****************************************************************************/ X Xcheck_tty (tty, list) Xchar *tty; /* user's tty line */ Xchar *list; /* list of valid tty lines */ X{ X char *tt, *ls; X int t; X X if (*list == '\0') X return (0); X tt = alloca (strlen (tty) + 2); X strcpy (tt, tty); X strcat (tt, ","); X ls = alloca (strlen (list) + 2); X strcpy (ls, list); X strcat (ls, ","); X if ((t = qtscan (ls, tty)) >= 0) X { X if (ls[t + strlen (tt) - 1] == ',') X return (0); X } X fprintf (stderr, "Login is permitted on %s only.\n", list); X return (1); X} X X/**************************************************************************** X* usrtime: ensure usr is on acceptable week day * X****************************************************************************/ X Xcheck_day (now, list) Xlong now; /* current time = time(NULL) */ Xchar *list; /* list of days (Mon, Tue...) */ X{ X char weekday[50]; X X if (*list == '\0') X return (0); X cftime (weekday, "%a", &now); X if (tscan (list, weekday) >= 0) X return (0); X fprintf (stderr, "Login is permitted on %s only.\n", list); X return (1); X} X X/**************************************************************************** X* usrtime: ensure usr is on acceptable time or date range * X****************************************************************************/ X Xcheck_time (now, list, timerange) Xlong now; /* current time = time(NULL) */ Xchar *list; /* hhmm-hhmm or yymmdd-yymmdd list */ Xint timerange; /* 0 = check yyyymmdd, 1 = check hhmm */ X{ X char clock[50]; X char *begin, *end; X char *ls; X long present, first, last; X X if (*list < '0' || *list > '9' || strchr (list, '-') == NULL) X return (0); X ls = end = alloca (strlen (list) + 2); X strcpy (end, list); X if (timerange) X cftime (clock, "%H%M", &now); X else X cftime (clock, "%Y%m%d", &now); X present = atol (clock); X while (*end) X { begin = end; X if ((end = strchr (begin, '-')) == NULL) X break; X *end++ = '\0'; X first = atol (begin); X last = atol (end); X if (first <= present && present <= last) X return (0); X if ((end = strchr (end, ',')) == NULL) X break; X end++; X } X if (timerange) X fprintf (stderr, "Login is permitted between %s hours only.\n", list); X else X fprintf (stderr, "This login has been disabled.\n"); X return (1); X} X X#endif X X/**************************************************************************** X* set the users environment with values. * X****************************************************************************/ X Xvoid setenv (this, val) Xchar *this; Xchar *val; X{ X char s[MAXPATHLEN+1]; X char *ss; X X sprintf (s, "%s=%s", this, val); X ss = malloc (strlen(s) + 1); X strcpy (ss, s); X putenv (ss); X} X X/**************************************************************************** X* user-provided environment variables must be checked * X****************************************************************************/ X Xvoid check_putenv (val) Xchar *val; X{ static count = 0; X char *env; X char **forbid; X X /* check forbidden environment variables */ X for (forbid = forbidden; *forbid; forbid++) X { if (strncmp (*forbid, val, strlen (*forbid)) == 0) X return; X } X X /* variables without an '=' sign assume the form of "Lnn=val" */ X if (strchr (val, '=') == NULL) X { env = malloc (strlen (val)+ 6); X sprintf (env, "L%d=%s", count++, val); X val = env; X } X putenv (val); X} X X/**************************************************************************** X* get the encrypted password from /etc/shadow or /etc/d_passwd * X* allow "null" user for /etc/d_passwd general shell password. * X* Return encrypted password if found, else null. * X****************************************************************************/ X X/* could have used getspnam(user) except for /etc/d_passwd */ X Xchar *get_shadow (fname, user, allow) Xchar *fname; /* /etc/shadow or /etc/d_passwd */ Xchar *user; /* user's login name */ Xint allow; /* 0 =must have pwr entry, 1 =success even if no entry */ X{ FILE *shadow; X char line[SHORTLINE+1]; X char *pwd, *colon; X static char pass[50]; X X *pass = '\0'; X if (shadow = fopen (fname, "r")) X { while (fgets (line, SHORTLINE, shadow)) X { line[SHORTLINE] = '\0'; X if (pwd = strchr (line, ':')) X { *pwd++ = '\0'; X if (colon = strchr (pwd, ':')) X { *colon++ = '\0'; X if (*line) X { if (strcmp (user, line) == 0) X { fclose (shadow); X strcpy (pass, pwd); X if (allow == 0 && colon) X { shadow_lstchg = atol (colon); X colon = strchr (colon, ':') + 1; X shadow_min = atol (colon); X colon = strchr (colon, ':') + 1; X shadow_max = atol (colon); X } X return (pass); X } X } X else if (allow) X strcpy (pass, pwd); X } X } X } X } X fclose (shadow); X if (allow && *pass) X return (pass); X return (NULL); X} X X/**************************************************************************** X* search for tty type in /etc/ttytype * X****************************************************************************/ X Xchar *search_ttytype (tty) Xchar *tty; /* user's tty line */ X{ FILE *fp; X char line[SHORTLINE+1]; X static char *tname; X char *dev; X X if (fp = fopen (TTYTYPE, "r")) X { while (fgets (line, SHORTLINE, fp)) X { line[SHORTLINE] = '\0'; X trim (line); X dev = line; X while (*dev) /* skip tty name */ X { if (*dev <= ' ') X break; X dev++; X } X while (*dev) /* locate device */ X { if (*dev > ' ') X break; X *dev++ = '\0'; X } X if (strcmp (dev, tty) == 0) X { fclose (fp); X tname = malloc (strlen(line)+1); X strcpy (tname, line); X return (tname); X } X } X } X fclose (fp); X return ("UNKNOWN"); X} X X X/**************************************************************************** X* read /etc/default/login file * X****************************************************************************/ X Xint get_defaults (fname, tz, hz, console, ulim, passreq, altshell, X path, supath, timeout, cmask, idleweeks) Xchar *fname; /* /etc/default/login */ Xchar *tz; /* TIMEZONE=xxx should be same as in /etc/TIMEZONE */ Xchar *hz; /* HZ=nn */ Xchar **console; /* CONSOLE=xxx root must be on this device if given*/ Xlong *ulim; /* ULIMIT=xxx default ulimit for users */ Xint *passreq; /* PASSREQ=YES/NO is password required */ Xint *altshell; /* ALTSHELL=YES/NO YES==set shell name in environment */ Xchar **path; /* PATH=xxx default user path */ Xchar **supath; /* SUPATH=xxx defaut root path */ Xlong *timeout; /* TIMEOUT=nn login abort timeout in seconds */ Xint *cmask; /* UMASK=ooo default umask for users */ Xint *idleweeks; /* IDLEWEEKS=nn idle weeks */ X{ X FILE *fp; X char line[LONGLINE+1]; X char *equal; X X if ((fp = fopen (fname, "r")) == NULL) X return (2); X while ((fgets (line, LONGLINE, fp))) X { if (*line == '#') /* must be first character */ X continue; X line[LONGLINE] = '\0'; X trim (line); X if (equal = strchr (line, '=')) X { *equal++ = '\0'; X if (strcmp (line, "TIMEZONE") == 0) X strcpy (tz, equal); X else if (strcmp (line, "HZ") == 0) X strcpy (hz, equal); X else if (strcmp (line, "CONSOLE") == 0) X { if (*console == NULL) X { *console = malloc (strlen (equal) + 2); X strcpy (*console, equal); X if (*console[strlen(*console) - 1] != ':') X strcat (*console, ":"); X } X } X else if (strcmp (line, "ULIMIT") == 0) X *ulim = atol (equal); X else if (strcmp (line, "PATH") == 0) X { if (*path == NULL) X { *path = malloc (strlen (equal) + 1); X strcpy (*path, equal); X } X } X else if (strcmp (line, "SUPATH") == 0) X { if (*supath == NULL) X { *supath = malloc (strlen (equal) + 1); X strcpy (*supath, equal); X } X } X else if (strcmp (line, "TIMEOUT") == 0) X *timeout = atol (equal); X else if (strcmp (line, "UMASK") == 0) X *cmask = atoo (equal); X else if (strcmp (line, "PASSREQ") == 0) X { if (toupper (*equal) == 'Y') X *passreq = 1; X else X *passreq = 0; X } X else if (strcmp (line, "ALTSHELL") == 0) X { if (toupper (*equal) == 'Y') X *altshell = 1; X else X *altshell = 0; X } X else if (strcmp (line, "IDLEWEEKS") == 0) X *idleweeks = atoi (equal); X } X } X fclose (fp); X return (0); X} X X/**************************************************************************** X* trim line at end * X****************************************************************************/ X Xvoid trim (s) Xchar *s; X{ char *t; X X t = s + strlen (s); X do X { if (*t > ' ') X break; X *t = '\0'; X } while (t-- != s); X} X X/**************************************************************************** X* ascii to octal * X****************************************************************************/ X Xint atoo (s) Xchar *s; X{ X unsigned int v; X X v = 0; X while (*s) X v = v * 8 + (*s++ - '0'); X return (v); X} X X/**************************************************************************** X* timeout error message if user takes too long to log in. * X****************************************************************************/ X Xvoid user_timeout() X{ X fprintf (stderr, "login timed out after %d seconds\n", timeout); X exit(0); X} X X X/**************************************************************************** X* search for string t in string s. return -1 if it does not exist * X* otherwise return an integer, the first byte of s that matches t. * X****************************************************************************/ X Xint tscan (s, t) Xchar s[], t[]; X{ X int i, j, k; X for (i = 0; s[i] != '\0'; i++) X { for (j = i, k=0; t[k] != '\0' && s[j] == t[k]; j++, k++) X ; X if (t[k] == '\0') X return (i); X } X return (-1); X} X X/**************************************************************************** X* search for string t in string s. return -1 if it does not exist * X* otherwise return an integer, the first byte of s that matches t. * X* Any '?' in s is a wild card match for t * X****************************************************************************/ X Xint qtscan (s, t) Xchar s[], t[]; X{ X int i, j, k; X for (i = 0; s[i] != '\0'; i++) X { for (j = i, k=0; t[k] != '\0' && ((s[j] == t[k]) || (s[j] == '?')) ; j++, k++) X ; X if (t[k] == '\0') X return (i); X } X return (-1); X} X END_OF_FILE if test 30942 -ne `wc -c <'login.c'`; then echo shar: \"'login.c'\" unpacked with wrong size! fi # end of 'login.c' fi echo shar: End of shell archive. exit 0 exit 0 # Just in case... -- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM Sterling Software, IMD UUCP: uunet!sparky!kent Phone: (402) 291-8300 FAX: (402) 291-4362 Please send comp.sources.misc-related mail to kent@uunet.uu.net.