jfh@rpp386.cactus.org (John F Haugh II) (05/16/91)
The next 8 postings are the shadow login suite that I first posted to the net about 3 years ago, only much bigger and with lots of really useless features that you'll probably want to use anyway ;-) What you get is - login, passwd, su, newgrp, chsh, chfn, chage, gpasswd, etc Too many programs to name. You also get a library that knows about password files and how to dork around with them in just about every conceivable manner. This is the initial beta version of the code. Please don't bother to archive it if you aren't interested in working on it - I hope to get plenty of bug reports and fix plenty of bugs, and I'd hate for you to have a bad version spinning on your disk. I'll post some patches as bugs get reported. Then, some time after the reports die down, I'll repost the entire thing with to here then comp.sources.misc. -- John F. Haugh II | Distribution to | UUCP: ...!cs.utexas.edu!rpp386!jfh Ma Bell: (512) 255-8251 | GEnie PROHIBITED :-) | Domain: jfh@rpp386.cactus.org "If liberals interpreted the 2nd Amendment the same way they interpret the rest of the Constitution, gun ownership would be mandatory."
jfh@rpp386.cactus.org (John F Haugh II) (05/16/91)
#! /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 # newgrp.c # Makefile # config.h # pwunconv.c # obscure.c # age.c # This archive created: Sun Mar 3 13:27:13 1991 # By: John F Haugh II (River Parishes Programming, Austin TX) export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'README'" '(12725 characters)' if test -f 'README' then echo shar: "will not over-write existing file 'README'" else sed 's/^X//' << \SHAR_EOF > 'README' XThis is the explanatory document for John F. Haugh II's login replacement, Xrelease 3. This document was last updated 11/21/90. X XThis software is copyright 1988, 1989, 1990, John F. Haugh II. All rights Xreserved. Use, duplication and disclosure is permitted according to the Xguidelines listed below. X XThis software is being provided as a freely redistributable login clone. XYou may distribute this software provided you do not charge for other than Xtransmission costs. You are free to copy this software provided you Xdo not restrict the rights of the recipients to further copy this software. X XTHIS SOFTWARE IS BEING DISTRIBUTED AS-IS. THE AUTHORS DISCLAIM ALL XLIABILITY FOR ANY CONSEQUENCES OF USE. THE USER IS SOLELY RESPONSIBLE XFOR THE MAINTENANCE OF THIS SOFTWARE PACKAGE. THE AUTHORS ARE UNDER NO XOBLIGATION TO PROVIDE MODIFICATIONS OR IMPROVEMENTS. THE USER IS XENCOURAGE TO TAKE ANY AND ALL STEPS NEEDED TO PROTECT AGAINST ACCIDENTAL XLOSS OF INFORMATION OR MACHINE RESOURCES. X XSpecial thanks are due to Chip Rosenthal for his fine testing efforts; Xto Steve Simmons for his work in porting this code to BSD; and to Bill XKennedy for his contributions of LaserJet printer time and energies. XAlso, thanks for Dennis L. Mumaugh for the initial shadow password Xinformation and to Tony Walton (olapw@olgb1.oliv.co.uk) for the System XV Release 4 changes. X XNew for Release 3: X The objects are being combined into libraries to make maintenance X easier and to encourage developers to use the modules as the X basis for new tools. X X New lint rules have been added to make the code easier to lint. X XBegin by reading and editing the config.h file. All options are selected Xby using #define's. A brief description for each available option appears Xbelow. You may want to print this file out as it is LONG and you will Xneed to refer to it while editting config.h. You will also have to edit Xthe Makefile. The possible differences are documented there. Pay close Xattention to the install: rule. DO NOT MAIL ME DIFFERENCES FOR VARIOUS XINSTALLATION PROBLEMS. If you must share your experiences, do so on the Xnet. Login now runs on about 30 different varieties of UNIX that I have Xbeen made aware of. X XNote that there are MANY options. As distributed most options are turned Xon, which produces a really nice package. This is the system as used on Xsome of the authors' machines. X XDialup Password Files - X This option permits individual ports to have an additional X password prompted for on a by-shell basis. /etc/dialups X contains a list of dialup ports, d_passwd contains the X password for each shell requiring a dialup password. X X Select this option by defining the DIALUP macro. X XPort Access Times File - X This option permits individual ports to have restrictions X based on user name and time of day and week. X X Select this option by defining the PORTTIME macro. X XShadow [ unreadable ] Password Files - X This option utilizes an alternate, non-readable file to X contain the actual encrypted passwords. This is presumed X to increase system security by increasing the difficulty X with which system crackers obtain encrypted passwords. X X Select this option by defining the SHADOWPWD macro. X XDBM Password Files - X This option utilizes the DBM database access routines to X increase the performance of user name and ID lookups in the X password file. X X Select this option by defining both the DBM and GETPWENT X macros. The FGETPWENT macro must also be defined or the X fgetpwent() library routine must be present. X XDouble Length Passwords - X This option extends the maximum length of a user password X to 16 characters from eight. X X Select this option by defining the DOUBLESIZE macro. X Credit for this option is due Jonathan Bayer. X XObscure Password Testing - X This option includes code to test user passwords for X complexity. The programmer is encouraged to edit the X file obscure.c to add additional methods for detecting X simplistic passwords. X X Select this option by defining the OBSCURE macro. X X Additionally, the PASSLENGTH macro must be defined to X control the minimum length for a legal password. X XMandatory Password Prompting - X This option requires all passwords, including null ones, X to be prompted for. Traditionally an account with a X password field of '::' does not require prompting for. X This option modifies this behavior to require even X null passwords be prompted for. X X Select this option by defining the NOBLANK macro. X XPassword Aging Defaults - X You may select the default number of days during which a X password is valid. The pwconv command adds aging X information to accounts which do not include it already. X X The MINDAYS macro must be defined to be the minimum X number of days which must pass before a password may be X changed. The MAXDAYS macro must be defined to be the X maximum number of days which a password will remain X valid during. X X The WARNDAYS macro controls how many days warning a user X is given that their password is about to expire. The X default is 10. X XHZ Environmental Variable - X This option pre-defines the HZ environmental variable. X Certain systems require this variable be defined for X system time reporting functions to work properly. X X Select this option by defining the HZ macro to have X the desired environmental variable value. X XTZ Environmental Variable - X This option pre-defines the TZ environmental variable. X This provides a default timezone variable for use by X various utilities. X X Select this option by defining the TZ macro to have X the desired environmental variable value, or the name X of the file containing the desired value. X XPassword Aging - X This option includes code to perform password aging. X Password aging is presumed to increase system security X by forcing users to change passwords on a regular X basis. The resolution on password age is in weeks for X non-shadow password systems and in days otherwise. X X Select this option by defining the AGING macro. X XMailbox Checking - X This option includes code to check the status of the X user's mailbox. One of three messages are produced X depending on the status of the user's mailbox. X X Select this option by defining the MAILCHECK macro. X XConsole Restricted Root Logins - X This option restricts the port which root may legally X login on. This option presumably increases system X security by preventing outside attacks against the root X account. X X Select this option by defining the CONSOLE macro to X have the desired port name. If this file is a regular X file, it is considered to contain a list of legal port X names, one per line. Note that the port names DO NOT X begin with "/dev/" and that a file name would have to X be fully qualified. See config.h for a pair of X examples. X XRestricted User Logins - X This option permits you to specify a file which disables X user logins. This options permits you to keep normal X users off of the system while performing maintenance X functions. X X Select this option by defining NOLOGINS to be the name X of the file to use. X XRestricted Use Accounts - X This option permits certain accounts to be used for X identification purposes only. This options associates X login ID's with UID's, such as for disk space accounting X or anonymous FTP accounts. Passwords for these accounts X may only be changed by root. X X Select this option by defining NOUSE to be the string X to include in the password file in place of the user's X shell. X XMessage of the Day Printing - X This option causes the message of the day to be X printed at login time. X X Select this option by defining the MOTD macro. X X If you wish this feature to be overriden on a per-user X basis, define the macro HUSHLOGIN and users may then X turn off the /etc/motd message by creating a file X '.hushlogin' in their home directories. X XLast Login Time Logging - X This option causes a record to be made of successful X logins in /usr/adm/lastlog. The format of the X structure is defined in lastlog.h. X X Select this option by defining the LASTLOG macro. X X You will need to determine if you system already has X a lastlog.h file and use that file if present. X XFailed Login Logging - X This option causes a record to be kept of the most X recent login failure by date and port. A cummulative X count of failures is maintained and compared against X an allowable limit. X X Select this option by defining the FAILLOG macro. X X An additional option is provided which will create X utmp-like entries for each failed login. Because of X security concerns, only valid account names will be X logged. X X Select this option by defining the FTMP macro to be X the name of a utmp-like file. You may control the X recording of unknown login names by defining the X UNKNOWNS macro. This prevents possible passwords from X being entered into the FTMP file. X X See the file faillog.h and config.h for more details. X XTerminal Permissions - X This option allows the terminal modes to be set at X login time. This is particularly useful to disable X messages on user's terminals. X X Select this option by defining the TTYPERM macro as X having the desired mode. X XTerminal Type Setup - X This option allows the terminal type to be set at X login time. The environmental variable TERM will be X set from the specified terminal to port mapping X file. X X Select this option by defining the TTYTYPE macro as X having the value of the name of the type to port X mapping file. Credit for this option is due Chip X Rosenthal. X XFile Size Setting - X This option includes code to set the user's ulimit X at login time. Additional code to set the umask and X nice value is also included. X X Select this option by defining the QUOTAS macro. X XSwitch-User Logging - X This option causes su(1) to log attempts to switch X users. Su(1) will log all attempt, giving the old X and new user ID's, tty port, and time. It also X indicates if the attempt was successful. X X Select this option by defining the SULOG macro to X have the value of the name of the file you want X attempts logged to. X XConfigurable Editing Keys - X This options allows the erase and kill characters to X be selected. A default value is provided. By default X ERASE will be ^H and KILL will be ^U. X X Select this option by defining the ERASECHAR macro X to be the desired erase character and the KILLCHAR X macro to be the desired KILL character. X XDefault ulimit and umask Values - X This option allows you to select the default values X for ulimit and umask, allowing you to avoid X regenerating your system kernel. These values may be X overriden with appropriate entries in the GECOS field. X X Select the default ulimit by defining the ULIMIT X macro, and the default umask by defining the UMASK X macro. X X Warning: These values will not apply to processes X executed by /etc/cron or any of their children. X XBSD Notes: Steve Simmons scs@iti.org X XThe full port of the shadow package to BSD is not complete; but some Xof the issues have been worked out. These notes describe the current Xstate of things: X XIn order to make use of password aging under BSD, minor changes to X/usr/include/pwd.h and getpwent() are needed. These changes are to Xkeep the password age from messing up the encrypted password when not Xusing shadow passwords, and involve placing a new field in the password Xdata structure. To use this, you should apply the following two patches: X pwd.h.patch X getpwent.c.patch Xto the BSD /usr/include/pwd.h and /usr/src/lib/libc/gen/getpwent.c, Xrespectively. After applying the patches, rebuild your standard C Xlibrary with the new getpwent. Programs which use the old getpwent Xwill fail on password checking if they do a strcmp rather than a strncmp. X[ I do not seem to have these two patches. I have provided an entire Xgetpwent collection of code which may be useful instead. This code Xdoes not support Sun Yellow Pages(tm?), which is a shame. -jfh ] X XThese changes are based on BSD4.3, not Tahoe X XToDo BSD: X XI'm working on this in my copious spare time (hah!); any help would Xbe appreciated. If you decide to help, do these independantly rather Xthan rework BSD code! Keep it redistributable! X XNo dbm functions have been put in place. Dbm functionality is needed Xfor both /etc/password and /etc/shadow management. [ It is now possible Xto create /etc/passwd.dir and /etc/passwd.pag using the new mkpasswd Xcommand. getpwuid and getpwnam both use these files. Also, the Xcommands chfn, chsh, and chage all update the DBM files. -jfh ] X XThe BSD GECOS field gets used for lots more stuff than the USG. At a Xminimum this functionality should be duplicated under BSD; better is to put Xit into USG as well; still better would be to make the chfn command for Xboth systems; best would be site-configurable data to be put into GECOS/chfn. X[ this is now possible using chfn and the -o option. - jfh ] SHAR_EOF if test 12725 -ne "`wc -c < 'README'`" then echo shar: "error transmitting 'README'" '(should have been 12725 characters)' fi fi echo shar: "extracting 'newgrp.c'" '(8576 characters)' if test -f 'newgrp.c' then echo shar: "will not over-write existing file 'newgrp.c'" else sed 's/^X//' << \SHAR_EOF > 'newgrp.c' X/* X * Copyright 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include <sys/types.h> X#include <string.h> X#include <stdio.h> X#include <grp.h> X#include "pwd.h" X#include <termio.h> X#ifdef SYS3 X#include <sys/ioctl.h> X#endif X#include "config.h" X X#ifndef lint Xstatic char sccsid[] = "@(#)newgrp.c 3.3 12:30:58 12/12/90"; X#endif X X#ifdef NGROUPS Xint ngroups; Xgid_t groups[NGROUPS]; X#endif X Xstruct passwd *pwd; Xstruct passwd *getpwuid(); Xstruct passwd *getpwnam(); X X#ifdef SHADOWPWD X#include "shadow.h" Xstruct spwd *spwd; Xstruct spwd *getspnam(); X#endif Xstruct group *grp; Xstruct group *getgrgid(); Xstruct group *getgrnam(); X Xchar *getlogin(); Xchar *crypt(); Xvoid shell(); X Xchar *name; Xchar *group; Xint gid; X Xchar *Prog; Xchar prog[BUFSIZ]; Xchar base[BUFSIZ]; Xchar passwd[BUFSIZ]; Xchar *cpasswd; Xchar *salt; X X#ifndef MAXENV X#define MAXENV 64 X#endif X Xchar *newenvp[MAXENV]; Xint newenvc = 0; Xint maxenv = MAXENV; X X/* X * usage - print command usage message X */ X Xusage () X{ X fprintf (stderr, "usage: newgrp [ - ] [ group ]\n"); X exit (1); X} X X/* X * newgrp - change the invokers current real and effective group id X */ X Xmain (argc, argv, envp) Xint argc; Xchar **argv; Xchar **envp; X{ X int initflag = 0; X int needspasswd = 0; X int i; X char *cp; X#ifdef DOUBLESIZE X int longpass; X#endif X X /* X * let me parse the command line first. the only legal flag X * is a "-", which indicates the shell is to perform the same X * initialization it does at login time. the remaining X * optional argument is the name of a new group. if it isn't X * present i just use the login group id of this user. X */ X X if (argc > 1 && strcmp (argv[1], "-") == 0) { X initflag = 1; X argc--; argv++; X } X if (argc > 2) X usage (); X X#ifdef NGROUPS X X /* X * get the current users groupset. the new group will be X * added to the concurrent groupset if there is room, otherwise X * you get a nasty message but at least your real and effective X * group id's are set. X */ X X ngroups = getgroups (groups); X#endif X X /* X * save my name for error messages and save my real gid incase X * of errors. if there is an error i have to exec a new login X * shell for the user since her old shell won't have fork'd to X * create the process. X */ X X Prog = argv[0]; X gid = getgid (); X X /* X * now i get to determine my current name. i do this to validate X * my access to the requested group. the validation works like X * this - X * 1) get the name associated with my current user id X * 2) get my login name, as told by getlogin(). X * 3) if they match, my name is the login name X * 4) if they don't match, my name is the name in the X * password file. X * X * this isn't perfect, but it works more often then not. X */ X X pwd = getpwuid (getuid ()); X X if (! (name = getlogin ()) || strcmp (name, pwd->pw_name) != 0) X name = pwd->pw_name; X X if (! (pwd = getpwnam (name))) { X fprintf (stderr, "unknown user: %s\n", name); X exit (1); X } X X /* X * now we determine the name of the new group which she wishes X * to become a member of. the password file entry for her X * current user id has been gotten. if there is no optional X * group argument she will have her real and effective group id X * set to the value from her password file entry. otherwise X * we validate her access to the specified group. X */ X X if (argv[1] != (char *) 0) { X X /* X * start by getting the entry for the requested group. X */ X X if (! (grp = getgrnam (group = argv[1]))) { X fprintf (stderr, "unknown group: %s\n", group); X goto failure; X } X X /* X * see if she is a member of this group. X */ X X for (i = 0;grp->gr_mem[i];i++) X if (strcmp (name, grp->gr_mem[i]) == 0) X break; X X /* X * if she isn't a member, she needs to provide the X * group password. if there is no group password, she X * will be denied access anyway. X */ X X if (grp->gr_mem[i] == (char *) 0) X needspasswd = 1; X#ifdef SHADOWPWD X X /* X * if she does not have either a shadowed password, X * or a regular password, and the group has a password, X * she needs to give the group password. X */ X X if (spwd = getspnam (name)) { X if (spwd->sp_pwdp[0] == '\0' && grp->gr_passwd[0]) X needspasswd = 1; X } else { X if (pwd->pw_passwd[0] == '\0' && grp->gr_passwd[0]) X needspasswd = 1; X } X#else X X /* X * if she does not have a regular password she will have X * to give the group password, if one exists. X */ X X if (pwd->pw_passwd[0] == '\0' && grp->gr_passwd[0]) X needspasswd = 1; X#endif X } else { X X /* X * get the group file entry for her login group id. X * the entry must exist, simply to be annoying. X */ X X if (! (grp = getgrgid (pwd->pw_gid))) { X fprintf (stderr, "unknown gid: %d\n", pwd->pw_gid); X goto failure; X } X } X X /* X * now i see about letting her into the group she requested. X * if she is the root user, i'll let her in without having to X * prompt for the password. otherwise i ask for a password X * if she flunked one of the tests above. note that she X * won't have to provide the password to her login group even X * if she isn't listed as a member. X */ X X if (getuid () != 0 && needspasswd) { X passwd[0] = '\0'; X X if (grp->gr_passwd[0]) { X X /* X * get the password from her, and set the salt for X * the decryption from the group file. X */ X X if (! (cp = getpass ("Password:"))) X goto failure; X X strcpy (passwd, cp); X salt = grp->gr_passwd; X } else { X X /* X * there is no password, print out "Sorry" and give up X */ X X fputs ("Sorry\n", stderr); X goto failure; X } X X /* X * encrypt the key she gave us using the salt from X * the password in the group file. the result of X * this encryption must match the previously X * encrypted value in the file. X */ X X cpasswd = pw_encrypt (passwd, salt); X X if (strcmp (cpasswd, grp->gr_passwd) != 0) { X fputs ("Sorry\n", stderr); X goto failure; X } X } X X /* X * all successful validations pass through this point. the X * group id will be set, and the group added to the concurrent X * groupset. X */ X X gid = grp->gr_gid; X#ifdef NGROUPS X X /* X * i am going to try to add her new group id to her concurrent X * group set. if the group id is already present i'll just X * skip this part. if the group doesn't fit, i'll complain X * loudly and skip this part ... X */ X X for (i = 0;i < ngroups;i++) { X if (gid == groups[i]) X break; X } X if (i == ngroups) { X if (ngroups == NGROUPS) { X fprintf (stderr, "too many groups\n"); X } else { X groups[ngroups++] = gid; X if (setgroups (ngroups, groups)) { X fprintf (stderr, "%s: ", Prog); X perror ("unable to set groups"); X } X } X } X#endif X X /* X * this is where all failures land. the group id will not X * have been set, so the setgid() below will set me to the X * original group id i had when i was invoked. X */ X Xfailure: X X /* X * i set her group id either to the value she requested, or X * to the original value. i have to go back to the original X * because she no longer has a shell running. X */ X X if (setgid (gid)) X perror ("setgid"); X X if (setuid (getuid ())) X perror ("setuid"); X X /* X * i have to get the pathname of her login shell. as a favor X * i'll try her environment for a $SHELL value first, and X * then try the password file entry. X */ X X if (! initflag && (cp = getenv ("SHELL"))) X strncpy (prog, cp, sizeof prog); X else if (pwd->pw_shell && pwd->pw_shell[0]) X strncpy (prog, pwd->pw_shell, sizeof prog); X else X strcpy (prog, "/bin/sh"); X X /* X * now i try to find the basename of the login shell. this X * will become argv[0] of the spawned command. X */ X X if (cp = strrchr (prog, '/')) X cp++; X else X cp = prog; X X /* X * to have the shell perform login processing i will set the X * first character in the first argument to a "-". X */ X X if (initflag) X strcat (strcpy (base, "-"), cp); X else X strcpy (base, cp); X X#ifdef SHADOWPWD X endspent (); X#endif X endpwent (); X endgrent (); X X /* X * switch back to her home directory if i am doing login X * initialization. X */ X X if (initflag) { X chdir (pwd->pw_dir); X while (*envp) { X if (strncmp (*envp, "PATH=", 5) == 0 || X strncmp (*envp, "HOME=", 5) == 0 || X strncmp (*envp, "SHELL=", 6) == 0) X addenv (*envp); X X envp++; X } X } else { X while (*envp) X addenv (*envp++); X } X X /* X * exec the login shell and go away. X */ X X shell (prog, base); X /*NOTREACHED*/ X} SHAR_EOF if test 8576 -ne "`wc -c < 'newgrp.c'`" then echo shar: "error transmitting 'newgrp.c'" '(should have been 8576 characters)' fi fi echo shar: "extracting 'Makefile'" '(11315 characters)' if test -f 'Makefile' then echo shar: "will not over-write existing file 'Makefile'" else sed 's/^X//' << \SHAR_EOF > 'Makefile' X# X# Copyright 1988,1989,1990, John F. Haugh II X# All rights reserved. X# X# Permission is granted to copy and create derivative works for any X# non-commercial purpose, provided this copyright notice is preserved X# in all copies of source code, or included in human readable form X# and conspicuously displayed on all copies of object code or X# distribution media. X# X# %W% %U% - Shadow password system X# X# %W% %U% %G% X# XSHELL = /bin/sh X X# X# Set this flag to decide what level of code "get" returns. X# The base USENET release was release 1. It is no longer supported. X# The version with the utilities added was release 2. X# The unreleased version with database-like file access is release 3. XRELEASE = 3 XGFLAGS = -t -r$(RELEASE) X X# Define the directory login is copied to. BE VERY CAREFUL!!! X# LOGINDIR = /bin XLOGINDIR = /etc X X# Pick your favorite C compiler and tags command XCC = cc XTAGS = ctags X X# OS. Currently only BSD and USG are defined. If you don't use BSD, X# USG (System V) is assumed. XOS = -DUSG X# OS = -DBSD X X# Do you have to do ranlib? Sorry to hear that ... XRANLIB = ranlib X# RANLIB = echo X X# Flags for SCO Xenix/386 XCFLAGS = -O -M3 -g $(OS) XLIBS = -lcrypt -lndbm X# LIBS = -lcrypt -ldbm XLDFLAGS = -M3 -g XLTFLAGS = X# This should be Slibsec.a for small model, or Llibsec.a for X# large model or whatever. MUST AGREE WITH CFLAGS!!! XLIBSEC = Slibsec.a X X# Flags for normal machines X# CFLAGS = -O -g $(OS) X# LIBS = X# LDFLAGS = -g X# LIBSEC = libsec.a X X# Names for root user and group, and bin user and group XRUID = root XRGID = root XBUID = bin XBGID = bin X X# Rules for .L (lint) files. X.SUFFIXES: .L XLINT = lint XLINTFLAGS = $(OS) -Dlint X X.c.L: X $(LINT) -u $(LINTFLAGS) $*.c > $*.L X XLOBJS = lmain.o login.o env.o valid.o setup.o shell.o age.o \ X utmp.o sub.o mail.o motd.o log.o ttytype.o failure.o X XLSRCS = lmain.c login.c env.c valid.c setup.c shell.c age.c \ X utmp.c sub.c mail.c motd.c log.c ttytype.c failure.c X XSOBJS = smain.o env.o entry.o susetup.o shell.o \ X sub.o mail.o motd.o sulog.o age.o X XSSRCS = smain.c env.c entry.c setup.c shell.c \ X pwent.c sub.c mail.c motd.c sulog.c shadow.c age.c pwpack.c rad64.c X XPOBJS = passwd.o obscure.o XPSRCS = passwd.c obscure.c X XGPSRCS = gpmain.c X XGPOBJS = gpmain.o X XPWOBJS = pwconv.o X XPWSRCS = pwconv.c pwent.c shadow.c pwpack.c rad64.c X XPWUNOBJS = pwunconv.o X XPWUNSRCS = pwunconv.c pwent.c shadow.c pwpack.c rad64.c X XSULOGOBJS = sulogin.o entry.o env.o age.o setup.o \ X valid.o shell.o X XSULOGSRCS = sulogin.c entry.c env.c age.c pwent.c setup.c \ X shadow.c shell.c valid.c pwpack.c X XMKPWDOBJS = mkpasswd.o X XMKPWDSRCS = mkpasswd.c X XNGSRCS = newgrp.c env.c shell.c X XNGOBJS = newgrp.o env.o shell.o X XCHFNSRCS = chfn.c fields.c XCHFNOBJS = chfn.o fields.o XCHSHSRCS = chsh.c fields.c XCHSHOBJS = chsh.o fields.o XCHAGEOBJS = chage.o fields.o XCHAGESRCS = chage.c fields.c XCHPASSOBJS = chpasswd.o XCHPASSSRCS = chpasswd.c XDPSRCS = dpmain.c XDPOBJS = dpmain.o X XALLSRCS = age.c dialchk.c dialup.c entry.c env.c lmain.c log.c login.c mail.c \ X motd.c obscure.c passwd.c pwconv.c pwent.c pwunconv.c getpass.c \ X setup.c shadow.c shell.c smain.c sub.c sulog.c sulogin.c ttytype.c \ X utmp.c valid.c port.c newgrp.c gpmain.c grent.c mkpasswd.c pwpack.c \ X chfn.c chsh.c chage.c rad64.c encrypt.c chpasswd.c shadowio.c pwio.c \ X newusers.c groupio.c fields.c pwdbm.c grpack.c grdbm.c sppack.c \ X spdbm.c dpmain.c gshadow.c gsdbm.c gspack.c sgroupio.c X XFILES1 = README newgrp.c Makefile config.h pwunconv.c obscure.c age.c X XFILES2 = passwd.c port.c lmain.c mkpasswd.c sulogin.c pwpack.c dialup.c \ X sulog.c getpass.c X XFILES3 = chfn.c chsh.c smain.c faillog.c pwconv.c failure.c utmp.c shadow.c X XFILES4 = gpmain.c chage.c pwent.c valid.c setup.c entry.c ttytype.c port.h X XFILES5 = pwio.c encrypt.c chpasswd.c newusers.c rad64.c dialchk.c faillog.h \ X pwdbm.c grdbm.c gshadow.c sppack.c X XFILES6 = gspack.c spdbm.c lastlog.h shell.c login.c sub.c dpmain.c mail.c \ X env.c pwd.h grpack.c shadow.h log.c grent.c motd.c dialup.h fields.c \ X gsdbm.c X XFILES7 = groupio.c shadowio.c sgroupio.c X XMAN_1 = chage.1 chfn.1 chsh.1 login.1 passwd.1 su.1 XMAN_3 = shadow.3 XMAN_4 = faillog.4 passwd.4 porttime.4 shadow.4 XMAN_8 = faillog.8 pwconv.8 pwunconv.8 sulogin.8 X XDOCS = $(MAN_1) $(MAN_3) $(MAN_4) $(MAN_8) X XBINS = su login pwconv pwunconv passwd sulogin faillog newgrp gpasswd \ X mkpasswd chfn chsh chage chpasswd newusers dpasswd id X Xall: $(BINS) $(DOCS) X X.PRECIOUS: libshadow.a Xlibshadow.a: \ X libshadow.a(dialchk.o) \ X libshadow.a(dialup.o) \ X libshadow.a(encrypt.o) \ X libshadow.a(getpass.o) \ X libshadow.a(grdbm.o) \ X libshadow.a(grent.o) \ X libshadow.a(groupio.o) \ X libshadow.a(grpack.o) \ X libshadow.a(gshadow.o) \ X libshadow.a(gsdbm.o) \ X libshadow.a(gspack.o) \ X libshadow.a(sgroupio.o) \ X libshadow.a(port.o) \ X libshadow.a(pwdbm.o) \ X libshadow.a(pwent.o) \ X libshadow.a(pwio.o) \ X libshadow.a(pwpack.o) \ X libshadow.a(rad64.o) \ X libshadow.a(spdbm.o) \ X libshadow.a(shadow.o) \ X libshadow.a(shadowio.o) \ X libshadow.a(sppack.o) X $(RANLIB) libshadow.a X Xlibsec: $(LIBSEC)(shadow.o) X $(RANLIB) $(LIBSEC) X Xinstall: all X strip $(BINS) X cp login $(LOGINDIR)/login X cp mkpasswd pwconv pwunconv sulogin chpasswd newusers /etc X cp su passwd gpasswd dpasswd faillog newgrp chfn chsh id /bin X cp dialup.h shadow.h pwd.h /usr/include X chown $(RUID) $(LOGINDIR)/login /etc/pwconv /etc/pwunconv /etc/sulogin \ X /bin/su /bin/passwd /bin/gpasswd /bin/newgrp /etc/mkpasswd \ X /bin/dpasswd /bin/chsh /bin/chfn /bin/chage X chgrp $(RGID) $(LOGINDIR)/login /etc/pwconv /etc/pwunconv /etc/sulogin \ X /bin/su /bin/passwd /bin/gpasswd /bin/newgrp /etc/mkpasswd \ X /bin/dpasswd /bin/chsh /bin/chfn /bin/chage X chown $(BUID) /bin/faillog /bin/id /usr/include/shadow.h \ X /usr/include/dialup.h /usr/include/pwd.h X chgrp $(BGID) /bin/faillog /bin/id /usr/include/shadow.h \ X /usr/include/dialup.h /usr/include/pwd.h X chmod 700 /etc/pwconv /etc/pwunconv /etc/sulogin /etc/mkpasswd \ X /etc/chpasswd /etc/newusers /bin/dpasswd /bin/chage X chmod 4711 $(LOGINDIR)/login /bin/su /bin/passwd /bin/gpasswd \ X /bin/newgrp /bin/chfn /bin/chsh X chmod 711 /bin/faillog /bin/id X chmod 444 /usr/include/shadow.h /usr/include/dialup.h \ X /usr/include/pwd.h X Xlint: su.lint login.lint pwconv.lint pwunconv.lint passwd.lint sulogin.lint \ X faillog.lint newgrp.lint gpasswd.lint mkpasswd.lint chfn.lint \ X chsh.lint chage.lint dpasswd.lint $(ALLSRCS:.c=.L) X Xtags: $(ALLSRCS) X $(TAGS) $(ALLSRCS) X XREADME: s.README X get -t -r$(RELEASE) s.README X X$(DOCS): X get -t -r$(RELEASE) s.$@ X Xlogin: $(LOBJS) libshadow.a X $(CC) -o login $(LDFLAGS) $(LOBJS) libshadow.a $(LIBS) X Xlogin.lint: $(LSRCS) X $(LINT) $(LINTFLAGS) $(LSRCS) > login.lint X Xsu: $(SOBJS) libshadow.a X $(CC) -o su $(LDFLAGS) $(SOBJS) libshadow.a $(LIBS) X Xsu.lint: $(SSRCS) X $(LINT) $(LINTFLAGS) -DSU $(SSRCS) > su.lint X Xpasswd: $(POBJS) libshadow.a X $(CC) -o passwd $(LDFLAGS) $(POBJS) libshadow.a $(LIBS) X Xpasswd.lint: $(PSRCS) X $(LINT) $(LINTFLAGS) -DPASSWD $(PSRCS) > passwd.lint X Xgpasswd: $(GPOBJS) libshadow.a X $(CC) -o gpasswd $(LDFLAGS) $(GPOBJS) libshadow.a $(LIBS) X Xgpasswd.lint: $(GPSRCS) X $(LINT) $(LINTFLAGS) $(GPSRCS) > gpasswd.lint X Xdpasswd: $(DPOBJS) libshadow.a X $(CC) -o dpasswd $(LDFLAGS) $(DPOBJS) libshadow.a $(LIBS) X Xdpasswd.lint: $(DPSRCS) X $(LINT) $(LINTFLAGS) $(DPSRCS) > dpasswd.lint X Xpwconv: $(PWOBJS) libshadow.a config.h X $(CC) -o pwconv $(LDFLAGS) $(PWOBJS) libshadow.a $(LIBS) X Xpwconv.lint: $(PWSRCS) config.h X $(LINT) $(LINTFLAGS) -DPASSWD $(PWSRCS) > pwconv.lint X Xpwunconv: $(PWUNOBJS) libshadow.a config.h X $(CC) -o pwunconv $(LDFLAGS) $(PWUNOBJS) libshadow.a $(LIBS) X Xpwunconv.lint: $(PWUNSRCS) X $(LINT) $(LINTFLAGS) -DPASSWD $(PWUNSRCS) > pwunconv.lint X Xsulogin: $(SULOGOBJS) libshadow.a X $(CC) -o sulogin $(LDFLAGS) $(SULOGOBJS) libshadow.a $(LIBS) X Xsulogin.lint: $(SULOGSRCS) X $(LINT) $(LINTFLAGS) $(SULOGSRCS) > sulogin.lint X Xfaillog: faillog.o X $(CC) -o faillog $(LDFLAGS) faillog.o $(LIBS) X Xfaillog.lint: faillog.c faillog.h config.h X $(LINT) $(LINTFLAGS) faillog.c > faillog.lint X Xmkpasswd: $(MKPWDOBJS) libshadow.a X $(CC) -o mkpasswd $(LDFLAGS) $(MKPWDOBJS) libshadow.a $(LIBS) X Xmkpasswd.lint: $(MKPWDSRCS) X $(LINT) $(LINTFLAGS) $(MKPWDSRCS) > mkpasswd.lint X Xnewgrp: $(NGOBJS) libshadow.a X $(CC) -o newgrp $(LDFLAGS) $(NGOBJS) libshadow.a $(LIBS) X Xnewgrp.lint: $(NGSRCS) X $(LINT) $(LINTFLAGS) $(NGSRCS) > newgrp.lint X Xchfn: $(CHFNOBJS) libshadow.a X $(CC) -o chfn $(LDFLAGS) $(CHFNOBJS) libshadow.a $(LIBS) X Xchfn.lint: $(CHFNSRCS) X $(LINT) $(LINTFLAGS) $(CHFNSRCS) > chfn.lint X Xchsh: $(CHSHOBJS) libshadow.a X $(CC) -o chsh $(LDFLAGS) $(CHSHOBJS) libshadow.a $(LIBS) X Xchsh.lint: $(CHSHSRCS) X $(LINT) $(LINTFLAGS) $(CHSHSRCS) > chsh.lint X Xchage: $(CHAGEOBJS) libshadow.a X $(CC) -o chage $(LDFLAGS) $(CHAGEOBJS) libshadow.a $(LIBS) X Xchage.lint: $(CHAGESRCS) X $(LINT) $(LINTFLAGS) -DPASSWD $(CHAGESRCS) > chage.lint X Xchpasswd: $(CHPASSOBJS) libshadow.a X $(CC) -o chpasswd $(LDFLAGS) $(CHPASSOBJS) libshadow.a $(LIBS) X Xchpasswd.lint: $(CHPASSSRCS) X $(LINT) $(LINTFLAGS) $(CHPASSSRCS) > chpasswd.lint X Xnewusers: newusers.o libshadow.a X $(CC) -o newusers $(LDFLAGS) newusers.o libshadow.a $(LIBS) X Xnewusers.lint: newusers.c X $(LINT) $(LINTFLAGS) newusers.c > newusers.lint X Xid: id.o libshadow.a X $(CC) -o id $(LDFLAGS) id.o libshadow.a $(LIBS) X Xid.lint: id.c X $(LINT) $(LINTFLAGS) id.c > id.lint X Xsulog.o: config.h X Xsusetup.c: setup.c X cp setup.c susetup.c X Xsusetup.o: config.h setup.c pwd.h X $(CC) -c $(CFLAGS) -DSU susetup.c X Xpasswd.o: config.h shadow.h pwd.h Xlmain.o: config.h lastlog.h faillog.h pwd.h Xsmain.o: config.h lastlog.h pwd.h shadow.h Xsub.o: pwd.h Xsetup.o: config.h pwd.h X Xutmp.o: config.h X Xmail.o: config.h X Xmotd.o: config.h X Xage.o: config.h pwd.h X Xlog.o: config.h lastlog.h pwd.h X Xshell.o: config.h X Xentry.o: config.h shadow.h pwd.h X Xshadow.o: shadow.h config.h Xshadowio.o: shadow.h Xgrent.o: config.h shadow.h Xsgroupio.o: shadow.h Xdialup.o: dialup.h Xdialchk.o: dialup.h config.h Xpwdbm.o: config.h pwd.h Xpwpack.o: config.h pwd.h Xpwent.o: config.h pwd.h Xpwio.o: pwd.h Xgetpass.o: config.h Xencrypt.o: config.h Xport.o: port.h X Xvalid.o: config.h pwd.h X Xfailure.o: faillog.h config.h X Xfaillog.o: faillog.h config.h pwd.h X Xnewgrp.o: config.h shadow.h pwd.h X Xmkpasswd.o: config.h shadow.h pwd.h X Xgpmain.o: config.h pwd.h X Xchfn.o: config.h pwd.h X Xchsh.o: config.h pwd.h X Xchage.o: config.h shadow.h pwd.h X Xpwconv.o: config.h shadow.h X Xpwunconv.o: config.h shadow.h pwd.h X Xchpasswd.o: config.h shadow.h pwd.h Xid.o: pwd.h Xnewusers.o: config.h shadow.h pwd.h Xdpmain.o: dialup.h X Xclean: X -rm -f *.o a.out core npasswd nshadow *.pag *.dir X Xclobber: clean X -rm -f $(BINS) *.lint *.L susetup.c libshadow.a X Xnuke: clobber X -for file in * ; do \ X if [ -f s.$$file -a ! -f p.$$file ] ; then \ X rm -f $$file ;\ X fi ;\ X done X Xshar: login.sh.1 login.sh.2 login.sh.3 login.sh.4 login.sh.5 login.sh.6 \ X login.sh.7 login.sh.8 X Xlogin.sh.1: $(FILES1) Makefile X shar -a $(FILES1) > login.sh.1 X Xlogin.sh.2: $(FILES2) Makefile X shar -a $(FILES2) > login.sh.2 X Xlogin.sh.3: $(FILES3) Makefile X shar -a $(FILES3) > login.sh.3 X Xlogin.sh.4: $(FILES4) Makefile X shar -a $(FILES4) > login.sh.4 X Xlogin.sh.5: $(FILES5) Makefile X shar -a $(FILES5) > login.sh.5 X Xlogin.sh.6: $(FILES6) Makefile X shar -a $(FILES6) > login.sh.6 X Xlogin.sh.7: $(FILES7) Makefile X shar -a $(FILES7) > login.sh.7 X Xlogin.sh.8: $(DOCS) Makefile X shar -a $(DOCS) > login.sh.8 SHAR_EOF if test 11315 -ne "`wc -c < 'Makefile'`" then echo shar: "error transmitting 'Makefile'" '(should have been 11315 characters)' fi fi echo shar: "extracting 'config.h'" '(6820 characters)' if test -f 'config.h' then echo shar: "will not over-write existing file 'config.h'" else sed 's/^X//' << \SHAR_EOF > 'config.h' X/* X * Copyright 1989, 1990, John F. Haugh II X * All rights reserved. X * X * Use, duplication, and disclosure prohibited without X * the express written permission of the author. X */ X X/* X * Configuration file for login. X * X * @(#)config.h 3.4 14:43:20 12/18/90 X */ X X/* X * Define DIALUP to use dialup password files. Define PORTTIME X * to use the port time restriction file, see port.h for more X * information. X */ X X#define DIALUP X#define PORTTIME X X/* X * Define SHADOWPWD to use shadow [ unreadable ] password file. X * Release 3 has a requirement that SHADOWPWD always be defined. X * Define AUTOSHADOW to have root always copy sp_pwdp to pw_passwd X * for getpwuid() and getpwnam(). This provides compatibility for X * privileged applications which are shadow-ignorant. YOU ARE X * ENCOURAGED TO NOT USE THIS OPTION UNLESS ABSOLUTELY NECESSARY. X */ X X#define SHADOWPWD X#undef AUTOSHADOW X X/* X * Define DOUBLESIZE to use 16 character passwords X */ X X#define DOUBLESIZE X X/* X * Define OBSCURE to include hard password testing code. X */ X X#define OBSCURE X X/* X * Define PASSLENGTH to be shortest legal password X */ X X#define PASSLENGTH 5 X X/* X * Define NOBLANK if you want all passwords prompted for, including X * empty ones. X X#undef NOBLANK X X/* X * Define MAXDAYS to be the default maximum number of days a password X * is valid for when converting to shadow passwords. Define MINDAYS X * to be the minimum number of days before a password may be changed. X * See pwconv.c for more details. X */ X X#define MAXDAYS 10000 X#define MINDAYS 0 X X/* X * Define NDEBUG for production versions X */ X X#define NDEBUG X X/* X * Define HZ if login must set HZ value X */ X X#define HZ "HZ=50" X X/* X * Define TZ if login must set timezone X * X * The first example sets the variable directly. The X * second example names a file which is read to determine X * the proper value. The file consists of a single line X * of the form 'TZ=zone-name' X */ X X/* #define TZ "TZ=CST6CDT" */ X#define TZ "/etc/tzname" X X/* X * Define the default PATH and SUPATH here. PATH is for non-privileged X * users, SUPATH is for root. The first pair are for real trusting X * systems, the second pair are for the paranoid ... X */ X X/* #define PATH "PATH=:/bin:/usr/bin" */ X/* #define SUPATH "PATH=:/bin:/usr/bin:/etc" */ X#define PATH "PATH=/bin:/usr/bin" X#define SUPATH "PATH=/bin:/usr/bin:/etc" X X/* X * Define the mailbox directory X */ X X#define MAILDIR "/usr/spool/mail/" X X/* X * Define AGING if you want the password aging checks made. X * Define WARNAGE to be the number of days notice a user receives X * of a soon to expire password. Release 3 has a requirement that X * AGING always be defined. X */ X X#define AGING X#define WARNAGE 10 X X/* X * Define MAILCHECK if you want the mailbox checked for new mail X * X * One of two messages are printed - `You have new mail.' or X * `You have mail.'. X */ X X#define MAILCHECK X X/* X * Define CONSOLE if you want ROOT restricted to a particular terminal. X * X * Use the name of the tty line if you only want a single line, or use X * the name of the file containing the permissible ports if you wish to X * allow root logins on more than one port. X */ X X/* #define CONSOLE "console" /* root on /dev/console only */ X#define CONSOLE "/etc/consoles" /* check /etc/consoles for a list */ X X/* X * Define NOLOGINS if you want to be able to deny non-root users logins. X * Logins will not be permitted if this file exists. X */ X X#define NOLOGINS "/etc/nologin" X X/* X * Define NOUSE if you want to be able to declare accounts which can't X * be logged into. Define NOLOGIN if you want it to be an su-only account. X */ X X#define NOUSE "NOUSE" X#define NOLOGIN "NOLOGIN" X X/* X * Define MOTD if you want the message of the day (/etc/motd) printed X * at login time. X */ X X#define MOTD X X/* X * Define HUSHLOGIN if you want the code added to avoid printing the X * motd if a file $HOME/.hushlogin exists. This obviously only matters X * if any of MOTD, MAILCHECK or LASTLOG are #define'd. X */ X X#define HUSHLOGIN X X/* X * Define LASTLOG if you want a record made of logins in /usr/adm/lastlog. X */ X X#define LASTLOG X X/* X * Define FAILLOG if you want a record make of failed logins in X * /usr/adm/faillog. See faillog.h for more details. See fail(1L) X * for even still more details ... Also, define FTMP to record utmp X * style records for failed logins. FTMP is the name of a utmp-like X * file. You can use who(1) instead of faillog(L), which is an X * advantage. Define UNKNOWNS if you do want unknown user names X * recorded. This can be a security hole since passwords are often X * entered mistakenly as user names. X */ X X#define FAILLOG X#define FTMP "/etc/ftmp" X#define UNKNOWNS X X/* X * Define TTYPERM to be the initial terminal permissions. Defining X * as 0600 will not allow messages, 0622 will. X */ X X#define TTYPERM 0600 X X/* X * Define TTYTYPE to the be name of the port to terminal type X * mapping file. This is used to set the environmental variable X * "TERM" to the correct terminal type. X */ X X#define TTYTYPE "/etc/ttytype" X X/* X * Define QUOTAS if you want the code added in setup.c to support X * file ulimit and nice [ and umask as well ] setting from the password X * file. X */ X X#define QUOTAS X X/* X * Pick your version of DBM. If you define either DBM or NDBM, you X * must define GETPWENT. If you define NDBM you must define GETGRENT X * as well. X */ X X/* #define DBM /* */ X#define NDBM /* */ X X/* X * Define file name for sulog. If SULOG is not defined, there will be X * no logging. This is NOT a good idea ... We also define other file X * names. X */ X X#define SULOG "/usr/adm/sulog" X#define SUCON "/dev/console" X#define PWDFILE "/etc/passwd" X#define OPWDFILE "/etc/passwd-" X#define NPWDFILE "/etc/npasswd" X#define OSHADOW "/etc/shadow-" X#define NSHADOW "/etc/nshadow" X#define GRPFILE "/etc/group" X#define OGRPFILE "/etc/group-" X#define NGRPFILE "/etc/ngroup" X X/* X * Define PWDLOCK to be a locking semaphore for updating the password X * file. GRPLOCK is the same for the group file. X */ X X#define PWDLOCK "/etc/passwd.lock" X#define GRPLOCK "/etc/group.lock" X#define SPWLOCK "/etc/shadow.lock" X X/* X * Wierd stuff follows ... X * X * The following macros exist solely to override stuff ... X * You will probably want to change their values to suit your X * fancy. X */ X X#define ERASECHAR '\b' X#define KILLCHAR '\025' X#define UMASK 022 X X#define ULIMIT (1L<<20) /* Define if your UNIX supports ulimit() */ X#define FGETPWENT /* Define if library does not include FGETPWENT */ X#define GETPWENT /* Define if you want my GETPWENT(3) routines */ X#define GETGRENT /* Define if you want my GETGRENT(3) routines */ X#define NEED_AL64 /* Define if library does not include a64l() */ X X/* X * These macros control the contents of <pwd.h>. X */ X X#define ATT_AGE /* the pw_age field exists */ X#define ATT_COMMENT /* the pw_comment field exists */ X#undef BSD_QUOTA /* the pw_quota field exists */ SHAR_EOF if test 6820 -ne "`wc -c < 'config.h'`" then echo shar: "error transmitting 'config.h'" '(should have been 6820 characters)' fi fi echo shar: "extracting 'pwunconv.c'" '(3162 characters)' if test -f 'pwunconv.c' then echo shar: "will not over-write existing file 'pwunconv.c'" else sed 's/^X//' << \SHAR_EOF > 'pwunconv.c' X/* X * Copyright 1989, 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X * X * pwunconv - restore old password file from shadow password file. X * X * Pwunconv copies the password file information from the shadow X * password file, merging entries from an optional existing shadow X * file. X * X * The new password file is left in npasswd. There is no new X * shadow file. Password aging information is translated where X * possible. X */ X X#include <sys/types.h> X#include <stdio.h> X#include <fcntl.h> X#include "pwd.h" X#include "config.h" X#include "shadow.h" X X#ifndef lint Xstatic char sccsid[] = "@(#)pwunconv.c 3.2 12:31:26 12/12/90"; X#endif X X#ifdef ITI_AGING X#define WEEK (7L*24L*3600L) X#else X#define WEEK (7) X#endif X Xchar buf[BUFSIZ]; Xchar *l64a (); X Xint main () X{ X struct passwd *pw; X struct passwd *sgetpwent (); X FILE *pwd; X FILE *npwd; X struct spwd *spwd; X int fd; X char newage[5]; X X if (! (pwd = fopen (PWDFILE, "r"))) { X perror (PWDFILE); X return (1); X } X unlink ("npasswd"); X if ((fd = open ("npasswd", O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0 || X ! (npwd = fdopen (fd, "w"))) { X perror ("npasswd"); X return (1); X } X while (fgets (buf, BUFSIZ, pwd) == buf) { X buf[strlen (buf) - 1] = '\0'; /* remove '\n' character */ X X if (buf[0] == '#') { /* comment line */ X (void) fprintf (npwd, "%s\n", buf); X continue; X } X if (! (pw = sgetpwent (buf))) { /* copy bad lines verbatim */ X (void) fprintf (npwd, "%s\n", buf); X continue; X } X setspent (); /* rewind shadow file */ X X if (! (spwd = getspnam (pw->pw_name))) { X (void) fprintf (npwd, "%s\n", buf); X continue; X } X pw->pw_passwd = spwd->sp_pwdp; X X /* X * Password aging works differently in the two different systems. X * With shadow password files you apparently must have some aging X * information. The maxweeks or minweeks may not map exactly. X * In pwconv we set max == 10000, which is about 30 years. Here X * we have to undo that kludge. So, if maxdays == 10000, no aging X * information is put into the new file. Otherwise, the days are X * converted to weeks and so on. X */ X X#ifdef ATT_AGE X if (spwd->sp_max > (63*WEEK) && spwd->sp_max < 10000) X spwd->sp_max = (63*WEEK); /* 10000 is infinity */ X X if (spwd->sp_min >= 0 && spwd->sp_min <= 63*7 && X spwd->sp_max >= 0 && spwd->sp_max <= 63*7) { X if (spwd->sp_lstchg == -1) X spwd->sp_lstchg = 0; X X spwd->sp_max /= WEEK; /* turn it into weeks */ X spwd->sp_min /= WEEK; X spwd->sp_lstchg /= WEEK; X X strncpy (newage, l64a (spwd->sp_lstchg * (64L*64L) + X spwd->sp_min * (64L) + spwd->sp_max), 5); X pw->pw_age = newage; X } else X pw->pw_age = ""; X#endif /* ATT_AGE */ X if (putpwent (pw, npwd)) { X perror (stderr, "pwunconv: write error"); X exit (1); X } X } X endspent (); X X if (ferror (npwd)) { X perror ("pwunconv"); X (void) unlink ("npasswd"); X } X (void) fclose (npwd); X (void) fclose (pwd); X return (0); X} SHAR_EOF if test 3162 -ne "`wc -c < 'pwunconv.c'`" then echo shar: "error transmitting 'pwunconv.c'" '(should have been 3162 characters)' fi fi echo shar: "extracting 'obscure.c'" '(3031 characters)' if test -f 'obscure.c' then echo shar: "will not over-write existing file 'obscure.c'" else sed 's/^X//' << \SHAR_EOF > 'obscure.c' X/* X * Copyright 1989, 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include <ctype.h> X#ifndef BSD X#include <string.h> X#include <memory.h> X#else X#include <strings.h> X#define strchr index X#define strrchr rindex X#endif X#include "config.h" X X#ifndef lint Xstatic char sccsid[] = "@(#)obscure.c 3.1 11:31:35 12/19/90"; X#endif X X/* X * Obscure - see if password is obscure enough. X * X * The programmer is encouraged to add as much complexity to this X * routine as desired. Included are some of my favorite ways to X * check passwords. X */ X Xint obscure (old, new) Xchar *old; Xchar *new; X{ X#ifdef OBSCURE X int i; X char oldmono[32]; X char newmono[32]; X char wrapped[64]; X#endif X if (old[0] == '\0') X return (1); X X if (strlen (new) < PASSLENGTH) { /* too short */ X printf ("Too short. "); X return (0); X } X#ifdef OBSCURE X for (i = 0;new[i];i++) X newmono[i] = tolower (new[i]); X X for (i = 0;old[i];i++) X oldmono[i] = tolower (old[i]); X X if (strcmp (new, old) == 0) { /* the same */ X printf ("No Change. "); X return (0); X } X if (palindrome (newmono, oldmono)) /* a palindrome */ X return (0); X X if (strcmp (newmono, oldmono) == 0) { /* case shifted */ X printf ("Case changes only. "); X return (0); X } X if (similiar (newmono, oldmono)) /* jumbled version */ X return (0); X X if (simple (new, old)) /* keyspace size */ X return (0); X X strcpy (wrapped, oldmono); X strcat (wrapped, oldmono); X if (strstr (wrapped, newmono)) { X printf ("Rotated. "); X return (0); X } X#endif X return (1); X} X X#ifdef OBSCURE X X/* X * can't be a palindrome - like `R A D A R' or `M A D A M' X */ X Xint palindrome (old, new) Xchar *old; Xchar *new; X{ X int i, j; X X i = strlen (new); X X for (j = 0;j < i;j++) X if (new[i - j - 1] != new[j]) X return (0); X X printf ("A palindrome. "); X return (1); X} X X/* X * more than half of the characters are different ones. X */ X Xint similiar (old, new) Xchar *old; Xchar *new; X{ X int i, j; X char *strchr (); X X for (i = j = 0;new[i] && old[i];i++) X if (strchr (new, tolower (old[i]))) X j++; X X if (i >= j * 2) X return (0); X X printf ("Too similiar. "); X return (1); X} X X/* X * a nice mix of characters. X */ X Xint simple (old, new) Xchar *old; Xchar *new; X{ X int digits = 0; X int uppers = 0; X int lowers = 0; X int others = 0; X int size; X int i; X double complexity; X X for (i = 0;new[i];i++) { X if (isdigit (new[i])) X digits++; X else if (isupper (new[i])) X uppers++; X else if (islower (new[i])) X lowers++; X else X others++; X } X X /* X * The scam is this - a password of only one character type X * must be 8 letters long. Two types, 7, and so on. X */ X X size = 9; X if (digits) size--; X if (uppers) size--; X if (lowers) size--; X if (others) size--; X X if (size <= i) X return 0; X X printf ("Too Simple. "); X return 1; X} X#endif SHAR_EOF if test 3031 -ne "`wc -c < 'obscure.c'`" then echo shar: "error transmitting 'obscure.c'" '(should have been 3031 characters)' fi fi echo shar: "extracting 'age.c'" '(6179 characters)' if test -f 'age.c' then echo shar: "will not over-write existing file 'age.c'" else sed 's/^X//' << \SHAR_EOF > 'age.c' X/* X * Copyright 1989, 1990, 1991, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include <sys/types.h> X#include <stdio.h> X#include <errno.h> X#include "config.h" X#include "pwd.h" X#include "shadow.h" X X#ifndef lint Xstatic char sccsid[] = "@(#)age.c 3.3 07:52:49 1/30/91"; X#endif X X#define DAY (24L*3600L) X#ifdef ITI_AGING X#define SCALE (DAY) X#else X#define SCALE (1) X#endif X X#ifndef WARNAGE X#define WARNAGE 10 X#endif X Xextern time_t time (); Xextern char *strdup(); X X/* X * pwd_to_spwd - create entries for new spwd structure X * X * pwd_to_spwd() creates a new (struct spwd) containing the X * information in the pointed-to (struct passwd). X */ X Xstatic struct spwd * Xpwd_to_spwd (pw) Xstruct passwd *pw; X{ X static struct spwd tspwd; X struct spwd *sp = &tspwd; X time_t t; X X /* X * Nice, easy parts first. The name and passwd map directly X * from the old password structure to the new one. X */ X X sp->sp_namp = strdup (pw->pw_name); X sp->sp_pwdp = strdup (pw->pw_passwd); X#ifdef ATT_AGE X X /* X * AT&T-style password aging maps the sp_min, sp_max, and X * sp_lstchg information from the pw_age field, which appears X * after the encrypted password. X */ X X if (pw->pw_age[0]) { X t = (c64i (pw->pw_age[0]) * 7) * SCALE; X sp->sp_max = t; X X if (pw->pw_age[1]) { X t = (c64i (pw->pw_age[1]) * 7) * SCALE; X sp->sp_min = t; X } else X sp->sp_min = (10000L) * SCALE; X X if (pw->pw_age[1] && pw->pw_age[2]) { X t = (a64l (pw->pw_age + 2) * 7) * SCALE; X sp->sp_lstchg = t; X } else X sp->sp_lstchg = time ((time_t *) 0) / (DAY/SCALE); X } else { X sp->sp_min = 0; X sp->sp_max = (10000L * SCALE); X sp->sp_lstchg = time ((time_t *) 0) / (DAY/SCALE); X } X#else /* !ATT_AGE */ X /* X * BSD does not use the pw_age field and has no aging information X * anywheres. The default values are used to initialize the X * fields which are in the missing pw_age field; X */ X X sp->sp_min = 0; X sp->sp_max = (10000L * SCALE); X sp->sp_lstchg = time ((time_t *) 0) / (DAY/SCALE); X#endif /* ATT_AGE */ X X /* X * These fields have no corresponding information in the password X * file. They are set to uninitialized values. X */ X X sp->sp_warn = -1; X sp->sp_inact = -1; X sp->sp_expire = -1; X sp->sp_flag = -1; X} X X/* X * isexpired - determine if account is expired yet X * X * isexpired calculates the expiration date based on the X * password expiration criteria. X */ X Xint Xisexpired (pw, sp) Xstruct passwd *pw; Xstruct spwd *sp; X{ X long clock; X X clock = time ((time_t *) 0) / (DAY/SCALE); X X /* X * Quick and easy - there is an expired account field X * along with an inactive account field. Do the expired X * one first since it is worse. X */ X X if (sp->sp_expire > 0 && sp->sp_expire < clock) X return 3; X X if (sp->sp_inact > 0 && sp->sp_lstchg > 0 && sp->sp_max > 0 && X sp->sp_inact + sp->sp_lstchg + sp->sp_max < clock) X return 2; X X /* X * The last and max fields must be present for an account X * to have an expired password. A maximum of >10000 days X * is considered to be infinite. X */ X X if (sp->sp_lstchg == -1 || X sp->sp_max == -1 || sp->sp_max >= (10000L*SCALE)) X return 0; X X /* X * Calculate today's day and the day on which the password X * is going to expire. If that date has already passed, X * the password has expired. X */ X X if (sp->sp_lstchg + sp->sp_max < clock) X return 1; X X return 0; X} X X/* X * expire - force password change if password expired X * X * expire() calls /bin/passwd to change the user's password X * if it has expired. X */ X Xint Xexpire (pw, sp) Xstruct passwd *pw; Xstruct spwd *sp; X{ X int status; X int child; X int pid; X X if (! sp) X sp = pwd_to_spwd (pw); X X /* X * See if the user's password has expired, and if so X * force them to change their password. X */ X X switch (status = isexpired (pw, sp)) { X case 0: X return 0; X case 1: X printf ("Your password has expired."); X break; X case 2: X printf ("Your password is inactive."); X break; X case 3: X printf ("Your login has expired."); X break; X } X X /* X * Setting the maximum valid period to less than the minimum X * valid period means that the minimum period will never X * occur while the password is valid, so the user can never X * change that password. X */ X X if (status > 1 || sp->sp_max < sp->sp_min) { X puts (" Contact the system administrator.\n"); X exit (1); X } X puts (" Choose a new one.\n"); X fflush (stdout); X X /* X * Close all the files so that unauthorized access won't X * occur. This needs to be done anyway because those files X * might become stale after "passwd" is executed. X */ X X endspent (); X endpwent (); X endsgent (); X endgrent (); X X /* X * Execute the /bin/passwd command. The exit status will be X * examined to see what the result is. If there are any X * errors the routine will exit. This forces the user to X * change their password before being able to use the account. X */ X X if ((pid = fork ()) == 0) { X execl ("/bin/passwd", "passwd", pw->pw_name, (char *) 0); X puts ("Can't execute /bin/passwd"); X exit (errno); X } else if (pid == -1) { X perror ("passwd"); X exit (errno); X } X while ((child = wait (&status)) != pid && child != -1) X ; X X if (child == pid && status == 0) X return 1; X X exit (1); X} X X/* X * agecheck - see if warning is needed for password expiration X * X * agecheck sees how many days until the user's password is going X * to expire and warns the user of the pending password expiration. X */ X Xvoid Xagecheck (pw, sp) Xstruct passwd *pw; Xstruct spwd *sp; X{ X long clock = time ((long *) 0) / (DAY/SCALE); X long remain; X X if (! sp) X sp = pwd_to_spwd (pw); X X /* X * The last, max, and warn fields must be supported or the X * warning period cannot be calculated. X */ X X if (sp->sp_lstchg == -1 || sp->sp_max == -1 || sp->sp_warn == -1) X return; X X if ((remain = (sp->sp_lstchg + sp->sp_max) - clock) <= sp->sp_warn) { X remain /= SCALE; X if (remain >= 0) X printf ("Your password will expire in %d %s.\n", X remain, remain == 1 ? "day":"days"); X } X} SHAR_EOF if test 6179 -ne "`wc -c < 'age.c'`" then echo shar: "error transmitting 'age.c'" '(should have been 6179 characters)' fi fi exit 0 # End of shell archive -- John F. Haugh II | Distribution to | UUCP: ...!cs.utexas.edu!rpp386!jfh Ma Bell: (512) 255-8251 | GEnie PROHIBITED :-) | Domain: jfh@rpp386.cactus.org "If liberals interpreted the 2nd Amendment the same way they interpret the rest of the Constitution, gun ownership would be mandatory."
jfh@rpp386.cactus.org (John F Haugh II) (05/16/91)
#! /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: # passwd.c # port.c # lmain.c # mkpasswd.c # sulogin.c # pwpack.c # dialup.c # sulog.c # getpass.c # This archive created: Sun Mar 3 13:27:16 1991 # By: John F Haugh II (River Parishes Programming, Austin TX) export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'passwd.c'" '(17138 characters)' if test -f 'passwd.c' then echo shar: "will not over-write existing file 'passwd.c'" else sed 's/^X//' << \SHAR_EOF > 'passwd.c' X/* X * Copyright 1989, 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include <sys/types.h> X#include <time.h> X#include <stdio.h> X#include <fcntl.h> X#include <signal.h> X#include <syslog.h> X X#ifndef lint Xstatic char sccsid[] = "@(#)passwd.c 3.1 09:00:47 2/8/91"; X#endif X X/* X * Set up some BSD defines so that all the BSD ifdef's are X * kept right here X */ X X#ifndef BSD X#include <string.h> X#include <memory.h> X#define bzero(a,n) memset(a, 0, n) X#else X#include <strings.h> X#define strchr index X#define strrchr rindex X#endif X X#include "config.h" X#include "pwd.h" X#include "lastlog.h" X#include "shadow.h" X X/* X * Password aging constants X * X * DAY - seconds in a day X * WEEK - seconds in a week X * SCALE - convert from clock to aging units X */ X X#define DAY (24L*3600L) X#define WEEK (7L*DAY) X X#ifdef ITI_AGING X#define SCALE (1) X#else X#define SCALE DAY X#endif X X/* X * Global variables X */ X Xchar name[32]; /* The user's name */ Xchar *Prog; /* Program name */ Xint amroot; /* The real UID was 0 */ X X/* X * External identifiers X */ X Xextern char *getpass(); Xextern char *pw_encrypt(); Xextern char *getlogin(); Xextern int optind; /* Index into argv[] for current option */ Xextern char *optarg; /* Pointer to current option value */ X#ifdef NDBM Xextern int sp_dbm_mode; Xextern int pw_dbm_mode; X#endif X X/* X * #defines for messages. This facilities foreign language conversion X * since all messages are defined right here. X */ X X#define USAGE "usage: %s [ -f | -s ] [ name ]\n" X#define ADMUSAGE \ X " %s [ -x max ] [ -n min ] [ -w warn ] [ -i inact ] name\n" X#define ADMUSAGE2 \ X " %s { -l | -d | -S } name\n" X#define OLDPASS "Old Password:" X#define NEWPASSMSG \ X"Enter the new password (minimum of 5 characters)\n\ XPlease use a combination of upper and lower case letters and numbers.\n" X#define NEWPASS "New Password:" X#define NEWPASS2 "Re-enter new password:" X#define WRONGPWD "Incorrect password for %s.\n" X#define WRONGPWD2 "incorrect password for `%s'\n" X#define NOMATCH "They don't match; try again.\n" X#define CANTCHANGE "The password for %s cannot be changed.\n" X#define CANTCHANGE2 "password locked for `%s'\n" X#define TOOSOON "Sorry, the password for %s cannot be changed yet.\n" X#define TOOSOON2 "now < sp_min for `%s'\n" X#define EXECFAILED "%s: Cannot execute %s" X#define EXECFAILED2 "cannot execute %s\n" X#define WHOAREYOU "%s: Cannot determine you user name.\n" X#define UNKUSER "%s: Unknown user %s\n" X#define NOPERM "You may not change the password for %s.\n" X#define NOPERM2 "can't change pwd for `%s'\n" X#define UNCHANGED "The password for %s is unchanged.\n" X#define SPWDBUSY "Cannot lock the password file; try again later.\n" X#define SPWDBUSY2 "can't lock /etc/shadow\n" X#define OPNERROR "Cannot open the password file.\n" X#define OPNERROR2 "can't open /etc/shadow\n" X#define UPDERROR "Error updating the password entry.\n" X#define UPDERROR2 "error updating shadow entry\n" X#define DBMERROR "Error updating the DBM password entry.\n" X#define DBMERROR2 "error updating DBM shadow entry.\n" X#define NOTROOT "Cannot change ID to root.\n" X#define NOTROOT2 "can't setuid(0).\n" X#define CLSERROR "Cannot commit shadow file changes.\n" X#define CLSERROR2 "can't rewrite /etc/shadow.\n" X#define UNLKERROR "Cannot unlock the shadow file.\n" X#define UNLKERROR2 "can't unlock /etc/shadow.\n" X#define TRYAGAIN "Try again.\n" X#define CHGPASSWD "changed password for `%s'\n" X X/* X * usage - print command usage and exit X */ X Xvoid Xusage () X{ X fprintf (stderr, USAGE, Prog); X if (amroot) { X fprintf (stderr, ADMUSAGE, Prog); X fprintf (stderr, ADMUSAGE2, Prog); X } X exit (1); X} X X/* X * new_password - validate old password and replace with new X */ X Xint Xnew_password (pw, sp) Xstruct passwd *pw; Xstruct spwd *sp; X{ X char *clear; /* Pointer to clear text */ X char *cipher; /* Pointer to cipher text */ X char *cp; /* Pointer to getpass() response */ X char orig[BUFSIZ]; /* Original password */ X char pass[BUFSIZ]; /* New password */ X int i; /* Counter for retries */ X X /* X * Authenticate the user. The user will be prompted for their X * own password. X */ X X if (! amroot && sp->sp_pwdp[0]) { X bzero (orig, sizeof orig); X X if (! (clear = getpass (OLDPASS))) X return -1; X X cipher = pw_encrypt (clear, sp->sp_pwdp); X if (strcmp (cipher, sp->sp_pwdp) != 0) { X sleep (1); X fprintf (stderr, WRONGPWD, sp->sp_namp); X syslog (LOG_WARN, WRONGPWD2, sp->sp_namp); X return -1; X } X strcpy (orig, clear); X } X X /* X * Get the new password. The user is prompted for the new password X * and has three tries to get it right. The password will be tested X * for strength, unless it is the root user. This provides an escape X * for initial login passwords. X */ X X printf (NEWPASSMSG); X for (i = 0;i < 3;i++) { X if (! (cp = getpass (NEWPASS))) X return -1; X else X strcpy (pass, cp); X X if (! amroot && ! obscure (orig, pass)) { X printf (TRYAGAIN); X continue; X } X if (! (cp = getpass (NEWPASS2))) X return -1; X X if (strcmp (cp, pass)) X fprintf (stderr, NOMATCH); X else X break; X } X if (i == 3) X return -1; X X /* X * Encrypt the password. The new password is encrypted and X * the shadow password structure updated to reflect the change. X */ X X sp->sp_pwdp = pw_encrypt (pass, (char *) 0); X sp->sp_lstchg = time ((time_t *) 0) / SCALE; X X return 0; X} X X/* X * check_password - test a password to see if it can be changed X * X * check_password() sees if the invoker has permission to change the X * password for the given user. X */ X Xvoid Xcheck_password (pw, sp) Xstruct passwd *pw; Xstruct spwd *sp; X{ X time_t now = time ((time_t *) 0) / SCALE; X X /* X * Root can change any password any time. X */ X X if (amroot) X return; X X /* X * Expired accounts cannot be changed ever. Passwords X * which are locked may not be changed. Passwords where X * min > max may not be changed. Passwords which have X * been inactive too long cannot be changed. X */ X X if ((sp->sp_expire > 0 && now >= sp->sp_expire) || X (sp->sp_inact >= 0 && sp->sp_max >= 0 && X now >= (sp->sp_lstchg + sp->sp_inact + sp->sp_max)) || X strcmp (sp->sp_pwdp, "!") == 0 || X sp->sp_min > sp->sp_max) { X fprintf (stderr, CANTCHANGE, sp->sp_namp); X syslog (LOG_WARN, CANTCHANGE2, sp->sp_namp); X exit (1); X } X X /* X * Passwords may only be changed after sp_min time is up. X */ X X if (sp->sp_min >= 0 && now < (sp->sp_lstchg + sp->sp_min)) { X fprintf (stderr, TOOSOON, sp->sp_namp); X syslog (LOG_WARN, TOOSOON2, sp->sp_namp); X exit (1); X } X} X X/* X * pwd_to_spwd - create entries for new spwd structure X * X * pwd_to_spwd() creates a new (struct spwd) containing the X * information in the pointed-to (struct passwd). X */ X Xvoid Xpwd_to_spwd (pw, sp) Xstruct passwd *pw; Xstruct spwd *sp; X{ X time_t t; X X /* X * Nice, easy parts first. The name and passwd map directly X * from the old password structure to the new one. X */ X X sp->sp_namp = strdup (pw->pw_name); X sp->sp_pwdp = strdup (pw->pw_passwd); X#ifdef ATT_AGE X X /* X * AT&T-style password aging maps the sp_min, sp_max, and X * sp_lstchg information from the pw_age field, which appears X * after the encrypted password. X */ X X if (pw->pw_age[0]) { X t = (c64i (pw->pw_age[0]) * WEEK) / SCALE; X sp->sp_max = t; X X if (pw->pw_age[1]) { X t = (c64i (pw->pw_age[1]) * WEEK) / SCALE; X sp->sp_min = t; X } else X sp->sp_min = (10000L * DAY) / SCALE; X X if (pw->pw_age[1] && pw->pw_age[2]) { X t = (a64l (pw->pw_age + 2) * WEEK) / SCALE; X sp->sp_lstchg = t; X } else X sp->sp_lstchg = time ((time_t *) 0) / SCALE; X } else { X sp->sp_min = 0; X sp->sp_max = (10000L * DAY) / SCALE; X sp->sp_lstchg = time ((time_t *) 0) / SCALE; X } X#else X /* X * BSD does not use the pw_age field and has no aging information X * anywheres. The default values are used to initialize the X * fields which are in the missing pw_age field; X */ X X sp->sp_min = 0; X sp->sp_max = (10000L * DAY) / SCALE; X sp->sp_lstchg = time ((time_t *) 0) / SCALE; X#endif X X /* X * These fields have no corresponding information in the password X * file. They are set to uninitialized values. X */ X X sp->sp_warn = -1; X sp->sp_inact = -1; X sp->sp_expire = -1; X sp->sp_flag = -1; X} X X/* X * print_status - print current password status X */ X Xvoid Xprint_status (sp) Xstruct spwd *sp; X{ X struct tm *tm; X time_t time; X X time = sp->sp_lstchg * SCALE; X tm = gmtime (&time); X X printf ("%s ", sp->sp_namp); X printf ("%s ", X sp->sp_pwdp[0] ? (sp->sp_pwdp[0] == '!' ? "L":"P"):"NP"); X printf ("%02.2d/%02.2d/%02.2d ", X tm->tm_mon + 1, tm->tm_mday, tm->tm_year % 100); X printf ("%d %d %d %d\n", X (sp->sp_min * SCALE) / DAY, (sp->sp_max * SCALE) / DAY, X (sp->sp_warn * SCALE) / DAY, (sp->sp_inact * SCALE) / DAY); X} X X/* X * passwd - change a user's password file information X * X * This command controls the password file and commands which are X * used to modify it. X * X * The valid options are X * X * -l lock the named account (*) X * -d delete the password for the named account (*) X * -x # set sp_max to # days (*) X * -n # set sp_min to # days (*) X * -w # set sp_warn to # days (*) X * -i # set sp_inact to # days (*) X * -S show password status of named account (*) X * -g execute gpasswd command to interpret flags X * -f execute chfn command to interpret flags X * -s execute chsh command to interpret flags X * X * (*) requires root permission to execute. X * X * All of the time fields are entered in days and converted to the X * appropriate internal format. For finer resolute the chage X * command must be used. X */ X Xint Xmain (argc, argv) Xint argc; Xchar **argv; X{ X char buf[BUFSIZ]; /* I/O buffer for messages, etc. */ X char *cp; /* Miscellaneous character pointing */ X time_t min; /* Minimum days before change */ X time_t max; /* Maximum days until change */ X time_t warn; /* Warning days before change */ X time_t inact; /* Days without change before locked */ X int i; /* Loop control variable */ X int flag; /* Current option to process */ X int lflg = 0; /* -l - lock account option */ X int dflg = 0; /* -d - delete password option */ X int xflg = 0; /* -x - set maximum days */ X int nflg = 0; /* -n - set minimum days */ X int wflg = 0; /* -w - set warning days */ X int iflg = 0; /* -i - set inactive days */ X int Sflg = 0; /* -S - show password status */ X struct passwd *pw; /* Password file entry for user */ X struct spwd *sp; /* Shadow file entry for user */ X struct spwd tspwd; /* New shadow file entry if none */ X X /* X * The program behaves differently when executed by root X * than when executed by a normal user. X */ X X amroot = getuid () == 0; X#ifdef NDBM X sp_dbm_mode = O_RDWR; X pw_dbm_mode = O_RDWR; X#endif X X /* X * Get the program name. The program name is used as a X * prefix to most error messages. It is also used as input X * to the openlog() function for error logging. X */ X X if (Prog = strrchr (argv[0], '/')) X Prog++; X else X Prog = argv[0]; X X openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH); X X /* X * Start with the flags which cause another command to be X * executed. The effective UID will be set back to the X * real UID and the new command executed with the flags X */ X X if (argc > 1 && argv[1][0] == '-' && strchr ("gfs", argv[1][1])) { X setuid (getuid ()); X switch (argv[1][1]) { X case 'g': X argv[1] = "gpasswd"; X execv ("/bin/gpasswd", &argv[1]); X break; X case 'f': X argv[1] = "chfn"; X execv ("/bin/chfn", &argv[1]); X break; X case 's': X argv[1] = "chsh"; X execv ("/bin/chsh", &argv[1]); X break; X default: X usage (); X } X sprintf (buf, EXECFAILED, Prog, argv[1]); X perror (buf); X syslog (LOG_CRIT, EXECFAILED2, argv[1]); X exit (1); X } X X /* X * The remaining arguments will be processed one by one and X * executed by this command. The name is the last argument X * if it does not begin with a "-", otherwise the name is X * determined from the environment and must agree with the X * real UID. Also, the UID will be checked for any commands X * which are restricted to root only. X */ X X while ((flag = getopt (argc, argv, "ldx:n:w:i:S")) != EOF) { X switch (flag) { X case 'x': X max = strtol (optarg, &cp, 10); X if (*cp || getuid ()) X usage (); X X xflg++; X break; X case 'n': X min = strtol (optarg, &cp, 10); X if (*cp || getuid ()) X usage (); X X nflg++; X break; X case 'w': X warn = strtol (optarg, &cp, 10); X if (*cp || getuid ()) X usage (); X X wflg++; X break; X case 'i': X inact = strtol (optarg, &cp, 10); X if (*cp || getuid ()) X usage (); X X iflg++; X break; X case 'S': X if (getuid ()) X usage (); X X Sflg++; X break; X case 'd': X dflg++; X break; X case 'l': X lflg++; X break; X default: X usage (); X } X } X X /* X * If any of the flags were given, a user name must be supplied X * on the command line. Only an unadorned command line doesn't X * require the user's name be given. Also, on -x, -n, -m, and X * -i may appear with each other. -d, -l and -S must appear alone. X */ X X if ((dflg || lflg || xflg || nflg || X wflg || iflg || Sflg) && optind >= argc) X usage (); X X if ((dflg + lflg + (xflg || nflg || wflg || iflg) + Sflg) > 1) X usage (); X X /* X * Now I have to get the user name. The name will be gotten X * from the command line if possible. Otherwise it is figured X * out from the environment. X */ X X if (optind < argc) { X strncpy (name, argv[optind], sizeof name); X name[sizeof name - 1] = '\0'; X } else if (cp = getlogin ()) { X strncpy (name, cp, sizeof name); X name[sizeof name - 1] = '\0'; X } else { X fprintf (stderr, WHOAREYOU, Prog); X exit (1); X } X X /* X * Now I have a name, let's see if the UID for the name X * matches the current real UID. X */ X X if (! (pw = getpwnam (name))) { X fprintf (stderr, UNKUSER, Prog, name); X exit (1); X } X if (! amroot && pw->pw_uid != getuid ()) { X fprintf (stderr, NOPERM, name); X syslog (LOG_WARN, NOPERM2, name); X exit (1); X } X X /* X * The user name is valid, so let's get the shadow file X * entry. X */ X X if (! (sp = getspnam (name))) X pwd_to_spwd (pw, sp = &tspwd); X X /* X * Save the shadow entry off to the side so it doesn't X * get changed by any of the following code. X */ X X if (sp != &tspwd) { X tspwd = *sp; X sp = &tspwd; X } X tspwd.sp_namp = strdup (sp->sp_namp); X tspwd.sp_pwdp = strdup (sp->sp_pwdp); X X if (Sflg) { X print_status (sp); X exit (0); X } X X /* X * If there are no other flags, just change the password. X */ X X if (! (dflg || lflg || xflg || nflg || wflg || iflg)) { X X /* X * See if the user is permitted to change the password. X * Otherwise, go ahead and set a new password. X */ X X check_password (pw, sp); X X if (new_password (pw, sp)) { X fprintf (stderr, UNCHANGED, name); X exit (1); X } X } X X /* X * The other options are incredibly simple. Just modify the X * field in the shadow file entry. X */ X X if (dflg) /* Set password to blank */ X sp->sp_pwdp = ""; X X if (lflg) /* Set password to "locked" value */ X sp->sp_pwdp = "!"; X X if (xflg) X sp->sp_max = (max * DAY) / SCALE; X X if (nflg) X sp->sp_min = (min * DAY) / SCALE; X X if (wflg) X sp->sp_warn = (warn * DAY) / SCALE; X X if (iflg) X sp->sp_inact = (inact * DAY) / SCALE; X X /* X * Before going any further, raise the ulimit to prevent X * colliding into a lowered ulimit, and set the real UID X * to root to protect against unexpected signals. Any X * keyboard signals are set to be ignored. X */ X X ulimit (2, 30000); X if (setuid (0)) { X fprintf (stderr, NOTROOT); X syslog (LOG_ERR, NOTROOT2); X exit (1); X } X signal (SIGHUP, SIG_IGN); X signal (SIGINT, SIG_IGN); X signal (SIGQUIT, SIG_IGN); X#ifdef SIGTSTP X signal (SIGTSTP, SIG_IGN); X#endif X X /* X * The shadow entry is now ready to be committed back to X * the shadow file. Get a lock on the file and open it. X */ X X for (i = 0;i < 30;i++) X if (spw_lock ()) X break; X X if (i == 30) { X fprintf (stderr, SPWDBUSY); X syslog (LOG_WARN, SPWDBUSY2); X exit (1); X } X if (! spw_open (O_RDWR)) { X fprintf (stderr, OPNERROR); X syslog (LOG_ERR, OPNERROR2); X (void) spw_unlock (); X exit (1); X } X X /* X * Update the shadow file entry. If there is a DBM file, X * update that entry as well. X */ X X if (! spw_update (sp)) { X fprintf (stderr, UPDERROR); X syslog (LOG_ERR, UPDERROR2); X (void) spw_unlock (); X exit (1); X } X#ifdef NDBM X if (access ("/etc/shadow.pag", 0) == 0 && ! sp_dbm_update (sp)) { X fprintf (stderr, DBMERROR); X syslog (LOG_ERR, DBMERROR2); X (void) spw_unlock (); X exit (1); X } X#endif X X /* X * Changes have all been made, so commit them and unlock the X * file. X */ X X if (! spw_close ()) { X fprintf (stderr, CLSERROR); X syslog (LOG_ERR, CLSERROR2); X (void) spw_unlock (); X exit (1); X } X if (! spw_unlock ()) { X fprintf (stderr, UNLKERROR); X syslog (LOG_ERR, UNLKERROR2); X exit (1); X } X syslog (LOG_INFO, CHGPASSWD, name); X exit (0); X} SHAR_EOF if test 17138 -ne "`wc -c < 'passwd.c'`" then echo shar: "error transmitting 'passwd.c'" '(should have been 17138 characters)' fi fi echo shar: "extracting 'port.c'" '(8978 characters)' if test -f 'port.c' then echo shar: "will not over-write existing file 'port.c'" else sed 's/^X//' << \SHAR_EOF > 'port.c' X/* X * Copyright 1989, 1990, 1991, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include <stdio.h> X#include <time.h> X#include <sys/types.h> X#include <ctype.h> X#include <errno.h> X#ifndef BSD X#include <string.h> X#else X#include <strings.h> X#define strchr index X#define strrchr rindex X#endif X#include "port.h" X X#ifndef lint Xstatic char _sccsid[] = "@(#)port.c 3.1 08:59:32 2/8/91"; X#endif X Xextern int errno; X Xstatic FILE *ports; X X/* X * setttyent - open /etc/porttime file or rewind X * X * the /etc/porttime file is rewound if already open, or X * opened for reading. X */ X Xvoid Xsetttyent () X{ X if (ports) X rewind (ports); X else X ports = fopen (PORTS, "r"); X} X X/* X * endttyent - close the /etc/porttime file X * X * the /etc/porttime file is closed and the ports variable set X * to NULL to indicate that the /etc/porttime file is no longer X * open. X */ X Xvoid Xendttyent () X{ X if (ports) X fclose (ports); X X ports = (FILE *) 0; X} X X/* X * getttyent - read a single entry from /etc/porttime X * X * the next line in /etc/porttime is converted to a (struct port) X * and a pointer to a static (struct port) is returned to the X * invoker. NULL is returned on either EOF or error. errno is X * set to EINVAL on error to distinguish the two conditions. X */ X Xstruct port * Xgetttyent () X{ X static struct port port; /* static struct to point to */ X static char buf[BUFSIZ]; /* some space for stuff */ X static char *ttys[PORT_TTY+1]; /* some pointers to tty names */ X static char *users[PORT_IDS+1]; /* some pointers to user ids */ X static struct pt_time times[PORT_TIMES+1]; /* time ranges */ X char *cp; /* pointer into line */ X int time; /* scratch time of day */ X int i, j; X int saveerr = errno; /* errno value on entry */ X X /* X * If the ports file is not open, open the file. Do not rewind X * since we want to search from the beginning each time. X */ X X if (! ports) X setttyent (); X X if (! ports) { X errno = saveerr; X return 0; X } X X /* X * Common point for beginning a new line - X * X * - read a line, and NUL terminate X * - skip lines which begin with '#' X * - parse off the tty names X * - parse off a list of user names X * - parse off a list of days and times X */ X Xagain: X X /* X * Get the next line and remove the last character, which X * is a '\n'. Lines which begin with '#' are all ignored. X */ X X if (fgets (buf, BUFSIZ, ports) == 0) { X errno = saveerr; X return 0; X } X if (buf[0] == '#') X goto again; X X /* X * Get the name of the TTY device. It is the first colon X * separated field, and is the name of the TTY with no X * leading "/dev". The entry '*' is used to specify all X * TTY devices. X */ X X buf[strlen (buf) - 1] = 0; X X port.pt_names = ttys; X for (cp = buf, j = 0;j < PORT_TTY;j++) { X port.pt_names[j] = cp; X while (*cp && *cp != ':' && *cp != ',') X cp++; X X if (! *cp) X goto again; /* line format error */ X X if (*cp == ':') /* end of tty name list */ X break; X X if (*cp == ',') /* end of current tty name */ X *cp++ = '\0'; X } X *cp++ = 0; X port.pt_names[j + 1] = (char *) 0; X X /* X * Get the list of user names. It is the second colon X * separated field, and is a comma separated list of user X * names. The entry '*' is used to specify all usernames. X * The last entry in the list is a (char *) 0 pointer. X */ X X if (*cp != ':') { X port.pt_users = users; X port.pt_users[0] = cp; X X for (j = 1;*cp != ':';cp++) { X if (*cp == ',' && j < PORT_IDS) { X *cp++ = 0; X port.pt_users[j++] = cp; X } X } X port.pt_users[j] = 0; X } else X port.pt_users = 0; X X if (*cp != ':') X goto again; X X *cp++ = 0; X X /* X * Get the list of valid times. The times field is the third X * colon separated field and is a list of days of the week and X * times during which this port may be used by this user. The X * valid days are 'Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', and 'Sa'. X * X * In addition, the value 'Al' represents all 7 days, and 'Wk' X * represents the 5 weekdays. X * X * Times are given as HHMM-HHMM. The ending time may be before X * the starting time. Days are presumed to wrap at 0000. X */ X X if (*cp == '\0') { X port.pt_times = 0; X return &port; X } X X port.pt_times = times; X X /* X * Get the next comma separated entry X */ X X for (j = 0;*cp && j < PORT_TIMES;j++) { X X /* X * Start off with no days of the week X */ X X port.pt_times[j].t_days = 0; X X /* X * Check each two letter sequence to see if it is X * one of the abbreviations for the days of the X * week or the other two values. X */ X X for (i = 0;cp[i] && cp[i + 1] && isalpha (cp[i]);i += 2) { X switch ((cp[i] << 8) | (cp[i + 1])) { X case ('S' << 8) | 'u': X port.pt_times[j].t_days |= 01; X break; X case ('M' << 8) | 'o': X port.pt_times[j].t_days |= 02; X break; X case ('T' << 8) | 'u': X port.pt_times[j].t_days |= 04; X break; X case ('W' << 8) | 'e': X port.pt_times[j].t_days |= 010; X break; X case ('T' << 8) | 'h': X port.pt_times[j].t_days |= 020; X break; X case ('F' << 8) | 'r': X port.pt_times[j].t_days |= 040; X break; X case ('S' << 8) | 'a': X port.pt_times[j].t_days |= 0100; X break; X case ('W' << 8) | 'k': X port.pt_times[j].t_days |= 076; X break; X case ('A' << 8) | 'l': X port.pt_times[j].t_days |= 0177; X break; X default: X errno = EINVAL; X return 0; X } X } X X /* X * The default is 'Al' if no days were seen. X */ X X if (i == 0) X port.pt_times[j].t_days = 0177; X X /* X * The start and end times are separated from each X * other by a '-'. The times are four digit numbers X * representing the times of day. X */ X X for (time = 0;cp[i] && isdigit (cp[i]);i++) X time = time * 10 + cp[i] - '0'; X X if (cp[i] != '-' || time > 2400 || time % 100 > 59) X goto again; X port.pt_times[j].t_start = time; X cp = cp + i + 1; X X for (time = i = 0;cp[i] && isdigit (cp[i]);i++) X time = time * 10 + cp[i] - '0'; X X if ((cp[i] != ',' && cp[i]) || time > 2400 || time % 100 > 59) X goto again; X X port.pt_times[j].t_end = time; X cp = cp + i + 1; X } X X /* X * The end of the list is indicated by a pair of -1's for the X * start and end times. X */ X X port.pt_times[j].t_start = port.pt_times[j].t_end = -1; X X return &port; X} X X/* X * getttyuser - get ports information for user and tty X * X * getttyuser() searches the ports file for an entry with a TTY X * and user field both of which match the supplied TTY and X * user name. The file is searched from the beginning, so the X * entries are treated as an ordered list. X */ X Xstruct port * Xgetttyuser (tty, user) Xchar *tty; Xchar *user; X{ X int i, j; X struct port *port; X X setttyent (); X X while (port = getttyent ()) { X if (port->pt_names == 0 || port->pt_users == 0) X continue; X X for (i = 0;port->pt_names[i];i++) X if (strcmp (port->pt_names[i], tty) == 0 || X strcmp (port->pt_names[i], "*") == 0) X break; X X if (port->pt_names[i] == 0) X continue; X X for (j = 0;port->pt_users[j];j++) X if (strcmp (user, port->pt_users[j]) == 0 || X strcmp (port->pt_users[j], "*") == 0) X break; X X if (port->pt_users[j] != 0) X break; X } X endttyent (); X return port; X} X X/* X * isttytime - tell if a given user may login at a particular time X * X * isttytime searches the ports file for an entry which matches X * the user name and TTY given. X */ X Xint Xisttytime (id, port, clock) Xchar *id; Xchar *port; Xlong clock; X{ X int i; X int time; X struct port *pp; X struct tm *tm, X *localtime(); X X /* X * Try to find a matching entry for this user. Default to X * letting the user in - there are pleny of ways to have an X * entry to match all users. X */ X X if (! (pp = getttyuser (port, id))) X return 1; X X /* X * The entry is there, but has not time entries - don't X * ever let them login. X */ X X if (pp->pt_times == 0) X return 0; X X /* X * The current time is converted to HHMM format for X * comparision against the time values in the TTY entry. X */ X X tm = localtime (&clock); X time = tm->tm_hour * 100 + tm->tm_min; X X /* X * Each time entry is compared against the current X * time. For entries with the start after the end time, X * the comparision is made so that the time is between X * midnight and either the start or end time. X */ X X for (i = 0;pp->pt_times[i].t_start != -1;i++) { X if (! (pp->pt_times[i].t_days & PORT_DAY(tm->tm_wday))) X continue; X X if (pp->pt_times[i].t_start <= pp->pt_times[i].t_end) { X if (time >= pp->pt_times[i].t_start && X time <= pp->pt_times[i].t_end) X return 1; X } else { X if (time >= pp->pt_times[i].t_start || X time <= pp->pt_times[i].t_end) X return 1; X } X } X X /* X * No matching time entry was found, user shouldn't X * be let in right now. X */ X X return 0; X} SHAR_EOF if test 8978 -ne "`wc -c < 'port.c'`" then echo shar: "error transmitting 'port.c'" '(should have been 8978 characters)' fi fi echo shar: "extracting 'lmain.c'" '(13146 characters)' if test -f 'lmain.c' then echo shar: "will not over-write existing file 'lmain.c'" else sed 's/^X//' << \SHAR_EOF > 'lmain.c' X/* X * Copyright 1989, 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include <sys/types.h> X#include <sys/stat.h> X#include <stdio.h> X#include "pwd.h" X#include <utmp.h> X#include <time.h> X#include <signal.h> X#include <syslog.h> X#ifndef BSD X#include <string.h> X#include <memory.h> X#define bzero(a,n) memset(a, 0, n); X#else X#include <strings.h> X#define strchr index X#define strrchr rindex X#endif X#ifndef BSD X#include <termio.h> X#else X#include <sgtty.h> X#endif X#include "config.h" X#include "lastlog.h" X#include "faillog.h" X#include "shadow.h" X X#ifndef lint Xstatic char sccsid[] = "%W% %U% %G%"; X#endif X X#ifndef ERASECHAR X#define ERASECHAR '\b' /* backspace */ X#endif X X#ifndef KILLCHAR X#define KILLCHAR '\025' /* control U */ X#endif X X#ifdef UT_HOST Xchar host[BUFSIZ]; X#endif X#ifdef HUSHLOGIN Xint hushed; X#endif X Xstruct passwd pwent; Xstruct utmp utent; Xstruct lastlog lastlog; Xint pflg; Xint rflg; Xint fflg; Xint hflg; X#ifndef BSD Xstruct termio termio; X#endif X X#ifndef MAXENV X#define MAXENV 64 X#endif X X/* X * Global variables. X */ X Xchar *newenvp[MAXENV]; Xchar *Prog; Xint newenvc = 0; Xint maxenv = MAXENV; X X/* X * External identifiers. X */ X Xextern char *getenv (); Xextern char *getpass (); Xextern void checkutmp (); Xextern void addenv (); Xextern void setenv (); Xextern unsigned alarm (); Xextern void login (); Xextern void entry (); Xextern void setutmp (); Xextern void subsystem (); Xextern void log (); Xextern void setup (); Xextern int expire (); Xextern void motd (); Xextern void mailcheck (); Xextern void shell (); Xextern long a64l (); Xextern int c64i (); Xextern int optind; Xextern char *optarg; Xextern char **environ; X X#ifdef TZ XFILE *tzfile; Xchar tzbuf[32] = TZ; X#endif X X#ifndef ALARM X#define ALARM 60 X#endif X X#ifndef RETRIES X#define RETRIES 3 X#endif X X#ifdef FAILLOG Xstruct faillog faillog; X#endif X X#ifdef FTMP Xstruct utmp failent; X#endif X X#ifndef UMASK X#define UMASK 0 X#endif X X#ifndef ULIMIT X#define ULIMIT (1L<<21) X#endif X X#define NO_SHADOW "no shadow password for `%s' on `%s'\n" X#define BAD_PASSWD "invalid password for `%s' on `%s'\n" X#define BAD_DIALUP "invalid dialup password for `%s' on `%s'\n" X#define BAD_TIME "invalid login time for `%s' on `%s'\n" X#define BAD_ROOT_LOGIN "ILLEGAL ROOT LOGIN ON TTY `%s'\n" X#define ROOT_LOGIN "ROOT LOGIN ON TTY `%s'\n" X#define FAILURE_CNT "exceeded failure limit for `%s' on `%s'\n" X#define NOT_A_TTY "not a tty\n" X#define NOT_ROOT "-r or -f flag and not ROOT on `%s'\n" X X/* X * usage - print login command usage and exit X */ X Xusage () X{ X fprintf (stderr, "usage: login [ -p ] [ name ]\n"); X#ifdef UT_HOST X fprintf (stderr, " login -r name\n"); X fprintf (stderr, " login [ -p ] -f name [ -h host ]\n"); X#else X fprintf (stderr, " login [ -p ] -f name\n"); X#endif X exit (1); X} X X/* X * login - create a new login session for a user X * X * login is typically called by getty as the second step of a X * new user session. getty is responsible for setting the line X * characteristics to a reasonable set of values and getting X * the name of the user to be logged in. login may also be X * called to create a new user session on a pty for a variety X * of reasons, such as X servers or network logins. X * X * the flags which login supports are X * X * -p - preserve the environment X * -r - perform autologin protocol for rlogin X * -f - do not perform authentication, user is preauthenticated X * -h - the name of the remote host X */ X Xint Xmain (argc, argv, envp) Xint argc; Xchar **argv; Xchar **envp; X{ X char name[32]; X char pass[32]; X char hush[BUFSIZ]; X char tty[BUFSIZ]; X int retries; X int failed; X int flag; X int subroot = 0; X char *cp; X struct passwd *pwd; X struct spwd *spwd; X struct spwd *getspnam(); X#ifdef CONSOLE X int conflag; X char console[BUFSIZ]; X FILE *fp; X struct stat statbuf; X#endif /* CONSOLE */ X X /* X * Some quick initialization. X */ X X name[0] = '\0'; X X /* X * Get the utmp file entry and get the tty name from it. The X * current process ID must match the process ID in the utmp X * file if there are no additional flags on the command line. X */ X X checkutmp (argc > 1 && argv[1][0] != '-'); X strncpy (tty, utent.ut_line, sizeof tty); X tty[sizeof tty - 1] = '\0'; X X if (Prog = strrchr (argv[0], '/')) X Prog++; X else X Prog = argv[0]; X X#ifdef UT_HOST X while ((flag = getopt (argc, argv, "pr:f:h:")) != EOF) X#else X while ((flag = getopt (argc, argv, "pf:")) != EOF) X#endif X { X switch (flag) { X case 'p': pflg++; X break; X case 'f': fflg++; X strncpy (name, optarg, sizeof name); X break; X#ifdef UT_HOST X case 'r': rflg++; X strncpy (name, optarg, sizeof name); X break; X case 'h': hflg++; X strncpy (host, optarg, sizeof host); X strncpy (utmp.ut_host, host, X sizeof utmp.ut_host); X break; X#endif X default: X usage (); X } X } X X /* X * The -r option is not valid with any other flags X */ X X if (rflg && (hflg || fflg || pflg)) X usage (); X X openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH); X X /* X * The -r and -f flags both require the real UID to be X * zero. No authentication may be required for these X * flags, so the user must already be root. X */ X X if ((rflg || fflg) && getuid () != 0) X exit (1); /* only root can use -r or -f */ X X if (! isatty (0) || ! isatty (1) || ! isatty (2)) X exit (1); /* must be a terminal */ X X#ifndef BSD X (void) ioctl (0, TCGETA, &termio); /* get terminal characteristics */ X X /* X * Add your favorite terminal modes here ... X */ X X termio.c_lflag |= ISIG; X X termio.c_cc[VERASE] = ERASECHAR; X termio.c_cc[VKILL] = KILLCHAR; X (void) ioctl (0, TCSETAF, &termio); /* set erase and kill characters */ X#endif /* !BSD */ X umask (UMASK); /* set the default umask */ X ulimit (2, (long) ULIMIT); /* set the default ulimit */ X X /* X * The entire environment will be preserved if the -p flag X * is used. X */ X X if (pflg) X while (*envp) /* add inherited environment, */ X addenv (*envp++); /* some variables change later */ X X#ifdef TZ X if (! pflg) { X if (tzbuf[0] == '/') { X if ((tzfile = fopen (tzbuf, "r")) != (FILE *) 0) { X if (fgets (tzbuf, sizeof tzbuf, tzfile)) { X tzbuf[strlen (tzbuf) - 1] = '\0'; X addenv (tzbuf); X } X fclose (tzfile); X } X } else { X addenv (tzbuf); X } X } X#endif /* TZ */ X#ifdef HZ X if (! pflg) X addenv (HZ); /* set the default $HZ, if one */ X#endif /* HZ */ X if (optind < argc) { /* now set command line variables */ X if (optind + 1 < argc) X setenv (argc - optind - 1, &argv[optind + 1]); X X (void) strncpy (name, argv[optind], sizeof name); X } Xtop: X (void) alarm (ALARM); /* only allow ALARM sec. for login */ X X retries = RETRIES; X while (1) { /* repeatedly get login/password pairs */ X pass[0] = '\0'; X X if (! name[0]) { /* need to get a login id */ X if (subroot) X exit (1); X X rflg = fflg = 0; X login (name); X continue; X } X if (! (pwd = getpwnam (name))) X pwent.pw_name = (char *) 0; X else X pwent = *pwd; X X if (pwent.pw_name) { X if (! (spwd = getspnam (name))) X syslog (LOG_WARN, NO_SHADOW, name, tty); X else X pwent.pw_passwd = spwd->sp_pwdp; X failed = 0; /* hasn't failed validation yet */ X } else X failed = 1; /* will never pass validation */ X X /* X * The -r and -f flags provide a name which has already X * been authenticated by some server. X */ X X if (pwent.pw_name && (rflg || fflg)) X goto have_name; X X /* X * Get the user's password. One will only be prompted for X * if the pw_passwd (or sp_passwd) field is non-blank. It X * will then be checked against the password entry, along X * with other options which prevent logins. X */ X cp = 0; X if ((! pwent.pw_name || (strlen (pwent.pw_passwd) > 0)) X && ! (cp = getpass ("Password:"))) X continue; X X if (cp) X strncpy (pass, cp, sizeof pass); X X if (! valid (pass, &pwent)) { /* check encrypted passwords */ X syslog (LOG_WARN, BAD_PASSWD, name, tty); X failed = 1; X } X bzero (pass, sizeof pass); X X /* X * This is the point where password-authenticated users X * wind up. If you reach this far, your password has X * been authenticated and so on. X */ X Xhave_name: X#ifdef DIALUP X alarm (30); X if (pwent.pw_name && ! dialcheck (tty, X pwent.pw_shell[0] ? pwent.pw_shell:"/bin/sh")) { X syslog (LOG_WARN, BAD_DIALUP, name, tty); X failed = 1; X } X#endif /* DIALUP */ X#ifdef PORTTIME X if (pwent.pw_name && X ! isttytime (pwent.pw_name, tty, time ((time_t *) 0))) { X syslog (LOG_WARN, BAD_TIME, name, tty); X failed = 1; X } X#endif /* PORTTIME */ X#ifdef CONSOLE X if (! failed && pwent.pw_name && X pwent.pw_uid == 0 && stat (CONSOLE, &statbuf) == 0) { X if ((statbuf.st_mode & S_IFMT) == S_IFREG) { X fp = fopen (CONSOLE, "r"); X while (fp && fgets (console, BUFSIZ, fp) X == console) { X console[strlen (console) - 1] = '\0'; X if (! strcmp (console, tty)) X break; X } X if (! fp || feof (fp)) X failed = 1; X X fclose (fp); X } else { X if (strcmp (CONSOLE, tty)) X failed = 1; X } X if (failed) X syslog (LOG_CRIT, BAD_ROOT_LOGIN, tty); X } X#endif /* CONSOLE */ X#ifdef FAILLOG X if (pwent.pw_name && X ! failcheck (pwent.pw_uid, &faillog, failed)) { X syslog (LOG_CRIT, FAILURE_CNT, name, tty); X failed = 1; X } X#endif /* FAILLOG */ X if (! failed) X break; X X puts ("Login incorrect"); X if (rflg || fflg) X exit (1); X#ifdef FAILLOG X if (pwent.pw_name) /* don't log non-existent users */ X failure (pwent.pw_uid, tty, &faillog); X#endif /* FAILLOG */ X#ifdef FTMP X failent = utent; X X if (pwent.pw_name) X strncpy (failent.ut_name, X pwent.pw_name, sizeof failent.ut_name); X else X#ifdef UNKNOWNS X strcpy (failent.ut_name, name); X#else /* !UNKNOWNS */ X strcpy (failent.ut_name, "UNKNOWN"); X#endif /* UNKNOWNS */ X time (&failent.ut_time); X failent.ut_type = USER_PROCESS; X X failtmp (&failent); X#endif /* FTMP */ X if (--retries <= 0) /* only allow so many failures */ X exit (1); X X bzero (name, sizeof name); X bzero (pass, sizeof pass); X } X (void) alarm (0); /* turn off alarm clock */ X#ifdef NOLOGINS X /* X * Check to see if system is turned off for non-root users. X * This would be useful to prevent users from logging in X * during system maintenance. X */ X X if (pwent.pw_uid != 0 && access (NOLOGINS, 0) == 0) { X FILE *fp; X int c; X X if (fp = fopen (NOLOGINS, "r")) { X while ((c = getc (fp)) != EOF) { X if (c == '\n') X putchar ('\r'); X X putchar (c); X } X fflush (stdout); X fclose (fp); X } else X printf ("\r\nSystem closed for routine maintenance\n"); X X exit (0); X } X#endif /* NOLOGINS */ X environ = newenvp; /* make new environment active */ X X if (getenv ("IFS")) /* don't export user IFS ... */ X addenv ("IFS= \t\n"); /* ... instead, set a safe IFS */ X X setutmp (name, tty); /* make entry in utmp & wtmp files */ X if (pwent.pw_shell[0] == '*') { /* subsystem root */ X subsystem (&pwent); /* figure out what to execute */ X subroot++; /* say i was here again */ X endpwent (); /* close all of the file which were */ X endgrent (); /* open in the original rooted file */ X endspent (); /* system. they will be re-opened */ X endsgent (); /* in the new rooted file system */ X goto top; /* go do all this all over again */ X } X X#ifdef LASTLOG X log (); /* give last login and log this one */ X#endif /* LASTLOG */ X setup (&pwent); /* set UID, GID, HOME, etc ... */ X#ifdef AGING X if (spwd) { /* check for age of password */ X if (expire (&pwent, spwd)) { X spwd = getspnam (name); X pwd = getpwnam (name); X pwent = *pwd; X } X } X#ifdef ATT_AGE X else if (pwent.pw_age && pwent.pw_age[0]) { X if (expire (&pwent, (void *) 0)) { X pwd = getpwnam (name); X pwent = *pwd; X } X } X#endif /* ATT_AGE */ X#endif /* AGING */ X#ifdef HUSHLOGIN X sprintf (hush, "%s/.hushlogin", pwent.pw_dir, 0); X hushed = access (hush, 0) == 0; X#endif /* HUSHLOGIN */ X#ifdef MOTD X if (! hushed) X motd (); /* print the message of the day */ X#endif X#ifdef FAILLOG X if (faillog.fail_cnt != 0) X failprint (pwent.pw_uid, &faillog); X#endif /* FAILLOG */ X#ifdef LASTLOG X if (lastlog.ll_time != 0 && ! hushed) X printf ("Last login: %.19s on %s\n", X ctime (&lastlog.ll_time), lastlog.ll_line); X#endif /* LASTLOG */ X#ifdef AGING X if (! hushed) X agecheck (&pwent, spwd); X#endif /* AGING */ X#ifdef MAILCHECK X if (! hushed) X mailcheck (); /* report on the status of mail */ X#endif /* MAILCHECK */ X#ifdef TTYTYPE X if (! pflg) X ttytype (tty); X#endif /* TTYTYPE */ X signal (SIGINT, SIG_DFL); /* default interrupt signal */ X signal (SIGQUIT, SIG_DFL); /* default quit signal */ X signal (SIGTERM, SIG_DFL); /* default terminate signal */ X signal (SIGALRM, SIG_DFL); /* default alarm signal */ X X endpwent (); /* stop access to password file */ X endgrent (); /* stop access to group file */ X endspent (); /* stop access to shadow passwd file */ X endsgent (); /* stop access to shadow group file */ X X if (pwent.pw_uid == 0) X syslog (LOG_INFO, ROOT_LOGIN, tty); X X shell (pwent.pw_shell, (char *) 0); /* exec the shell finally. */ X /*NOTREACHED*/ X} SHAR_EOF if test 13146 -ne "`wc -c < 'lmain.c'`" then echo shar: "error transmitting 'lmain.c'" '(should have been 13146 characters)' fi fi echo shar: "extracting 'mkpasswd.c'" '(8207 characters)' if test -f 'mkpasswd.c' then echo shar: "will not over-write existing file 'mkpasswd.c'" else sed 's/^X//' << \SHAR_EOF > 'mkpasswd.c' X/* X * Copyright 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include "config.h" X#include <stdio.h> X#include <fcntl.h> X#include "pwd.h" X#ifdef BSD X#include <strings.h> X#define strchr index X#define strrchr rindex X#else X#include <string.h> X#endif X X#if !defined(DBM) && !defined(NDBM) XWhat you are trying to do? You have to have a DBM of some kind ... X#endif X X#ifdef DBM X#include <dbm.h> X#endif X#ifdef NDBM X#include <ndbm.h> X#include <grp.h> X#include "shadow.h" X XDBM *pw_dbm; XDBM *gr_dbm; XDBM *sp_dbm; XDBM *sgr_dbm; X#endif X X#ifndef lint Xstatic char sccsid[] = "@(#)mkpasswd.c 3.4 11:29:08 12/19/90"; Xstatic char copyright[] = "Copyright 1990, John F. Haugh II"; X#endif X Xchar *CANT_OPEN = "%s: cannot open file %s\n"; Xchar *CANT_OVERWRITE = "%s: cannot overwrite file %s\n"; Xchar *CANT_CREATE = "%s: cannot create %s\n"; Xchar *DBM_OPEN_ERR = "%s: cannot open DBM files for %s\n"; Xchar *PARSE_ERR = "%s: error parsing line\n\"%s\"\n"; Xchar *LINE_TOO_LONG = "%s: the beginning with \"%.16s ...\" is too long\n"; Xchar *ADD_REC = "adding record for name \"%s\"\n"; Xchar *ADD_REC_ERR = "%s: error adding record for \"%s\"\n"; Xchar *INFO = "added %d entries, longest was %d\n"; X#ifdef NDBM Xchar *USAGE = "Usage: %s [ -vf ] [ -p|g|sp|sg ] file\n"; X#else Xchar *USAGE = "Usage: %s [ -vf ] file\n"; X#endif X Xchar *Progname; Xint vflg = 0; Xint fflg = 0; X#ifdef NDBM Xint gflg = 0; Xint sflg = 0; Xint pflg = 0; X#endif X Xvoid usage(); X Xextern char *malloc(); Xextern struct passwd *sgetpwent(); X#ifdef NDBM Xextern struct group *sgetgrent(); Xextern struct spwd *sgetspent(); Xextern struct sgrp *sgetsgent(); X#endif X X/* X * mkpasswd - create DBM files for /etc/passwd-like input file X * X * mkpasswd takes an an argument the name of a file in /etc/passwd format X * and creates a DBM file keyed by user ID and name. The output files have X * the same name as the input file, with .dir and .pag appended. X * X * if NDBM is defined this command will also create look-aside files for X * /etc/group, /etc/shadow, and /etc/gshadow. X */ X Xint Xmain (argc, argv) Xint argc; Xchar **argv; X{ X extern int optind; X extern char *optarg; X FILE *fp; /* File pointer for input file */ X char *file; /* Name of input file */ X char *dir; /* Name of .dir file */ X char *pag; /* Name of .pag file */ X char *cp; /* Temporary character pointer */ X int flag; /* Flag for command line option */ X int fd; /* File descriptor of open DBM file */ X int cnt = 0; /* Number of entries in database */ X int longest = 0; /* Longest entry in database */ X int len; /* Length of input line */ X int errors = 0; /* Count of errors processing file */ X char buf[BUFSIZ*8]; /* Input line from file */ X struct passwd *passwd; /* Pointer to password file entry */ X#ifdef NDBM X struct group *group; /* Pointer to group file entry */ X struct spwd *shadow; /* Pointer to shadow passwd entry */ X struct sgrp *gshadow; /* Pointer to shadow group entry */ X DBM *dbm; /* Pointer to new NDBM files */ X#endif X X /* X * Figure out what my name is. I will use this later ... X */ X X if (Progname = strrchr (argv[0], '/')) X Progname++; X else X Progname = argv[0]; X X /* X * Figure out what the flags might be ... X */ X X#ifdef NDBM X while ((flag = getopt (argc, argv, "fvpgs")) != EOF) X#else X while ((flag = getopt (argc, argv, "fv")) != EOF) X#endif X { X switch (flag) { X case 'v': X vflg++; X break; X case 'f': X fflg++; X break; X#ifdef NDBM X case 'g': X gflg++; X if (pflg) X usage (); X X break; X case 's': X sflg++; X break; X case 'p': X pflg++; X if (gflg) X usage (); X X break; X#endif X default: X usage (); X } X } X X /* X * Backwards compatibility fix for -p flag ... X */ X X if (! sflg && ! gflg) X pflg++; X X /* X * The last and only remaining argument must be the file name X */ X X if (argc - 1 != optind) X usage (); X X file = argv[optind]; X X if (! (fp = fopen (file, "r"))) { X fprintf (stderr, CANT_OPEN, Progname, file); X exit (1); X } X X /* X * Make the filenames for the two DBM files. X */ X X dir = malloc (strlen (file) + 5); /* space for .dir file */ X strcat (strcpy (dir, file), ".dir"); X X pag = malloc (strlen (file) + 5); /* space for .pag file */ X strcat (strcpy (pag, file), ".pag"); X X /* X * Remove existing files if requested. X */ X X if (fflg) { X (void) unlink (dir); X (void) unlink (pag); X } X X /* X * Create the two DBM files - it is an error for these files X * to have existed already. X */ X X if (access (dir, 0) == 0) { X fprintf (stderr, CANT_OVERWRITE, Progname, dir); X exit (1); X } X if (access (pag, 0) == 0) { X fprintf (stderr, CANT_OVERWRITE, Progname, pag); X exit (1); X } X X#ifdef NDBM X if (sflg) X umask (077); X else X#endif X umask (0); X#ifdef DBM X if ((fd = open (dir, O_RDWR|O_CREAT|O_EXCL, 0644)) == -1) { X fprintf (stderr, CANT_CREATE, Progname, dir); X exit (1); X } else X close (fd); X X if ((fd = open (pag, O_RDWR|O_CREAT|O_EXCL, 0644)) == -1) { X fprintf (stderr, CANT_CREATE, Progname, pag); X unlink (dir); X exit (1); X } else X close (fd); X#endif X X /* X * Now the DBM database gets initialized X */ X X#ifdef DBM X if (dbminit (file) == -1) { X fprintf (stderr, DBM_OPEN_ERR, Progname, file); X exit (1); X } X#endif X#ifdef NDBM X if (! (dbm = dbm_open (file, O_RDWR|O_CREAT, 0644))) { X fprintf (stderr, DBM_OPEN_ERR, Progname, file); X exit (1); X } X if (gflg) { X if (sflg) X sgr_dbm = dbm; X else X gr_dbm = dbm; X } else { X if (sflg) X sp_dbm = dbm; X else X pw_dbm = dbm; X } X#endif X X /* X * Read every line in the password file and convert it into a X * data structure to be put in the DBM database files. X */ X X#ifdef NDBM X while (fgetsx (buf, BUFSIZ, fp) != NULL) X#else X while (fgets (buf, BUFSIZ, fp) != NULL) X#endif X { X X /* X * Get the next line and strip off the trailing newline X * character. X */ X X buf[sizeof buf - 1] = '\0'; X if (! (cp = strchr (buf, '\n'))) { X fprintf (stderr, LINE_TOO_LONG, Progname, buf); X exit (1); X } X *cp = '\0'; X len = strlen (buf); X X /* X * Parse the password file line into a (struct passwd). X * Erroneous lines cause error messages, but that's X * all. YP lines are ignored completely. X */ X X if (buf[0] == '-' || buf[0] == '+') X continue; X X#ifdef DBM X if (! (passwd = sgetpwent (buf))) X#endif X#ifdef NDBM X if (! (((! sflg && pflg) && (passwd = sgetpwent (buf))) X || ((sflg && pflg) && (shadow = sgetspent (buf))) X || ((! sflg && gflg) && (group = sgetgrent (buf))) X || ((sflg && gflg) && (gshadow = sgetsgent (buf))))) X#endif X { X fprintf (stderr, PARSE_ERR, Progname, buf); X errors++; X continue; X } X#ifdef DBM X if (vflg) X printf (ADD_REC, passwd->pw_name); X X if (! pw_dbm_update (passwd)) X fprintf (stderr, ADD_REC_ERR, X Progname, passwd->pw_name); X#endif X#ifdef NDBM X if (vflg) { X if (!sflg && pflg) printf (ADD_REC, passwd->pw_name); X if (sflg && pflg) printf (ADD_REC, shadow->sp_namp); X if (!sflg && gflg) printf (ADD_REC, group->gr_name); X if (sflg && gflg) printf (ADD_REC, gshadow->sg_name); X } X if (! sflg && pflg && ! pw_dbm_update (passwd)) X fprintf (stderr, ADD_REC_ERR, X Progname, passwd->pw_name); X X if (sflg && pflg && ! sp_dbm_update (shadow)) X fprintf (stderr, ADD_REC_ERR, X Progname, shadow->sp_namp); X X if (! sflg && gflg && ! gr_dbm_update (group)) X fprintf (stderr, ADD_REC_ERR, X Progname, group->gr_name); X X if (sflg && gflg && ! sgr_dbm_update (gshadow)) X fprintf (stderr, ADD_REC_ERR, X Progname, gshadow->sg_name); X#endif X X /* X * Update the longest record and record count X */ X X if (len > longest) X longest = len; X cnt++; X } X X /* X * Tell the user how things went ... X */ X X if (vflg) X printf (INFO, cnt, longest); X X exit (errors); X /*NOTREACHED*/ X} X X/* X * usage - print error message and exit X */ X Xvoid Xusage () X{ X fprintf (stderr, USAGE, Progname); X exit (1); X /*NOTREACHED*/ X} SHAR_EOF if test 8207 -ne "`wc -c < 'mkpasswd.c'`" then echo shar: "error transmitting 'mkpasswd.c'" '(should have been 8207 characters)' fi fi echo shar: "extracting 'sulogin.c'" '(3501 characters)' if test -f 'sulogin.c' then echo shar: "will not over-write existing file 'sulogin.c'" else sed 's/^X//' << \SHAR_EOF > 'sulogin.c' X/* X * Copyright 1989, 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include <sys/types.h> X#include <stdio.h> X#include "pwd.h" X#include <utmp.h> X#ifdef BSD X#include <strings.h> X#define strchr index X#define strrchr rindex X#else X#include <string.h> X#include <memory.h> X#endif X#include "config.h" X X#ifndef lint Xstatic char sccsid[] = "@(#)sulogin.c 3.3 12:31:35 12/12/90"; X#endif X Xchar name[BUFSIZ]; Xchar pass[BUFSIZ]; Xchar home[BUFSIZ]; Xchar prog[BUFSIZ]; Xchar mail[BUFSIZ]; X Xstruct passwd pwent; Xstruct utmp utent; X X#ifdef TZ XFILE *tzfile; Xchar tzbuf[BUFSIZ] = TZ; X#endif X X#ifndef MAXENV X#define MAXENV 64 X#endif X Xchar *newenvp[MAXENV]; Xint newenvc = 0; Xint maxenv = MAXENV; Xextern char **environ; X X#ifndef ALARM X#define ALARM 60 X#endif X X#ifndef RETRIES X#define RETRIES 3 X#endif X Xint main (argc, argv, envp) Xint argc; Xchar **argv; Xchar **envp; X{ X char *getenv (); X char *ttyname (); X char *cp; X X if (access (PWDFILE, 0) == -1) { /* must be a password file! */ X printf ("No password file\n"); X exit (1); X } X#ifdef NDEBUG X if (getppid () != 1) /* parent must be INIT */ X exit (1); X#endif X if (! isatty (0) || ! isatty (1) || ! isatty (2)) X exit (1); /* must be a terminal */ X X while (*envp) /* add inherited environment, */ X addenv (*envp++); /* some variables change later */ X X#ifdef TZ X if (tzbuf[0] == '/') { X if ((tzfile = fopen (tzbuf, "r")) != (FILE *) 0) { X if (fgets (tzbuf, sizeof tzbuf, tzfile)) { X tzbuf[strlen (tzbuf) - 1] = '\0'; X addenv (tzbuf); X } X fclose (tzfile); X } X } else { X addenv (tzbuf); X } X#endif /* TZ */ X#ifdef HZ X addenv (HZ); /* set the default $HZ, if one */ X#endif /* HZ */ X (void) strcpy (name, "root"); /* KLUDGE!!! */ X X alarm (ALARM); /* only wait so long ... */ X while (1) { /* repeatedly get login/password pairs */ X entry (name, &pwent); /* get entry from password file */ X if (pwent.pw_name == (char *) 0) { X printf ("No password entry for 'root'\n"); X exit (1); X } X X /* X * Here we prompt for the root password, or if no password is X * given we just exit. X */ X X /* get a password for root */ X if (! (cp = getpass ("Type control-d for normal startup,\n\ X(or give root password for system maintenance):"))) X exit (0); X else X strcpy (pass, cp); X X if (valid (pass, &pwent)) /* check encrypted passwords ... */ X break; /* ... encrypted passwords matched */ X X puts ("Login incorrect"); X } X alarm (0); X environ = newenvp; /* make new environment active */ X X puts ("Entering System Maintenance Mode"); X X /* X * Normally there would be a utmp entry for login to mung on X * to get the tty name, date, etc. from. We don't need all that X * stuff because we won't update the utmp or wtmp files. BUT!, X * we do need the tty name so we can set the permissions and X * ownership. X */ X X if (cp = ttyname (0)) { /* found entry in /dev/ */ X if (strrchr (cp, '/') != (char *) 0) X strcpy (utent.ut_line, strrchr (cp, '/') + 1); X else X strcpy (utent.ut_line, cp); X } X if (getenv ("IFS")) /* don't export user IFS ... */ X addenv ("IFS= \t\n"); /* ... instead, set a safe IFS */ X X setup (&pwent); /* set UID, GID, HOME, etc ... */ X X shell (pwent.pw_shell, (char *) 0); /* exec the shell finally. */ X /*NOTREACHED*/ X} SHAR_EOF if test 3501 -ne "`wc -c < 'sulogin.c'`" then echo shar: "error transmitting 'sulogin.c'" '(should have been 3501 characters)' fi fi echo shar: "extracting 'pwpack.c'" '(2994 characters)' if test -f 'pwpack.c' then echo shar: "will not over-write existing file 'pwpack.c'" else sed 's/^X//' << \SHAR_EOF > 'pwpack.c' X/* X * Copyright 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include <stdio.h> X#include "pwd.h" X#ifdef BSD X#include <strings.h> X#define strchr index X#define strrchr rindex X#else X#include <string.h> X#endif X#include "config.h" X X#ifndef lint Xstatic char sccsid[] = "@(#)pwpack.c 3.3 12:31:23 12/12/90"; X#endif X X/* X * pw_pack - convert a (struct pwd) to a packed record X */ X Xint Xpw_pack (passwd, buf) Xstruct passwd *passwd; Xchar *buf; X{ X char *cp; X X cp = buf; X strcpy (cp, passwd->pw_name); X cp += strlen (cp) + 1; X X strcpy (cp, passwd->pw_passwd); X#ifdef ATT_AGE X if (passwd->pw_age[0]) { X *cp++ = ','; X strcat (cp, passwd->pw_age); X } X#endif X cp += strlen (cp) + 1; X X memcpy (cp, (void *) &passwd->pw_uid, sizeof passwd->pw_uid); X cp += sizeof passwd->pw_uid; X X memcpy (cp, (void *) &passwd->pw_gid, sizeof passwd->pw_gid); X cp += sizeof passwd->pw_gid; X#ifdef BSD_QUOTAS X memcpy (cp, (void *) &passwd->pw_quota, sizeof passwd->pw_quota); X cp += sizeof passwd->pw_quota; X#endif X#ifdef ATT_COMMENT X if (passwd->pw_comment) { X strcpy (cp, passwd->pw_comment); X cp += strlen (cp) + 1; X } else X *cp++ = '\0'; X#endif X strcpy (cp, passwd->pw_gecos); X cp += strlen (cp) + 1; X X strcpy (cp, passwd->pw_dir); X cp += strlen (cp) + 1; X X strcpy (cp, passwd->pw_shell); X cp += strlen (cp) + 1; X X return cp - buf; X} X X/* X * pw_unpack - convert a packed (struct pwd) record to a (struct pwd) X */ X Xint Xpw_unpack (buf, len, passwd) Xchar *buf; Xint len; Xstruct passwd *passwd; X{ X char *org = buf; X char *cp; X X memset ((void *) passwd, 0, sizeof *passwd); X X passwd->pw_name = buf; X buf += strlen (buf) + 1; X if (buf - org > len) X return -1; X X passwd->pw_passwd = buf; X buf += strlen (buf) + 1; X if (buf - org > len) X return -1; X X#ifdef ATT_AGE X if (cp = strchr (passwd->pw_passwd, ',')) { X *cp++ = '\0'; X passwd->pw_age = cp; X } else X passwd->pw_age = ""; X#endif X X memcpy ((void *) &passwd->pw_uid, (void *) buf, sizeof passwd->pw_uid); X buf += sizeof passwd->pw_uid; X if (buf - org > len) X return -1; X X memcpy ((void *) &passwd->pw_gid, (void *) buf, sizeof passwd->pw_gid); X buf += sizeof passwd->pw_gid; X if (buf - org > len) X return -1; X X#ifdef BSD_QUOTAS X memcpy ((void *) &passwd->pw_quota, (void *) buf, X sizeof passwd->pw_quota); X buf += sizeof passwd->pw_quota; X if (buf - org > len) X return -1; X#endif X#ifdef ATT_COMMENT X passwd->pw_comment = buf; X buf += strlen (buf) + 1; X if (buf - org > len) X return -1; X#endif X passwd->pw_gecos = buf; X buf += strlen (buf) + 1; X if (buf - org > len) X return -1; X X passwd->pw_dir = buf; X buf += strlen (buf) + 1; X if (buf - org > len) X return -1; X X passwd->pw_shell = buf; X buf += strlen (buf) + 1; X if (buf - org > len) X return -1; X X return 0; X} SHAR_EOF if test 2994 -ne "`wc -c < 'pwpack.c'`" then echo shar: "error transmitting 'pwpack.c'" '(should have been 2994 characters)' fi fi echo shar: "extracting 'dialup.c'" '(2631 characters)' if test -f 'dialup.c' then echo shar: "will not over-write existing file 'dialup.c'" else sed 's/^X//' << \SHAR_EOF > 'dialup.c' X/* X * Copyright 1989, 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include <stdio.h> X#ifndef BSD X#include <string.h> X#else X#include <strings.h> X#define strchr index X#define strrchr rindex X#endif X#include "dialup.h" X X#ifndef lint Xstatic char sccsid[] = "@(#)dialup.c 3.3 19:44:20 12/10/90"; X#endif X Xstatic FILE *dialpwd; X Xvoid Xsetduent () X{ X if (dialpwd) X rewind (dialpwd); X else X dialpwd = fopen (DIALPWD, "r"); X} X Xvoid Xendduent () X{ X if (dialpwd) X fclose (dialpwd); X X dialpwd = (FILE *) 0; X} X Xstruct dialup * Xfgetduent (fp) XFILE *fp; X{ X static struct dialup dialup; /* static structure to point to */ X static char shell[64]; /* some space for a login shell */ X static char passwd[16]; /* some space for dialup password */ X char buf[BUFSIZ]; X char *cp; X X if (! fp) X return 0; X X if (! fp || feof (fp)) X return ((struct dialup *) 0); X X while (fgets (buf, BUFSIZ, fp) == buf && buf[0] == '#') X ; X X if (feof (fp)) X return ((struct dialup *) 0); X X cp = strchr (buf, ':'); X if (cp - buf > sizeof shell) /* something is fishy ... */ X return ((struct dialup *) 0); X X (void) strncpy (shell, buf, cp - buf); X shell[cp - buf] = '\0'; X X if (strlen (cp + 1) > sizeof passwd) /* something is REALLY fishy */ X return ((struct dialup *) 0); X X (void) strcpy (passwd, cp + 1); X passwd[strlen (passwd) - 1] = '\0'; X if (cp = strchr (passwd, ':')) X *cp = '\0'; X X dialup.du_shell = shell; X dialup.du_passwd = passwd; X X return (&dialup); X} X Xstruct dialup * Xgetduent () X{ X if (! dialpwd) X setduent (); X X return fgetduent (dialpwd); X} X Xstruct dialup *getdushell (shell) Xchar *shell; X{ X struct dialup *dialup; X X while (dialup = getduent ()) { X if (strcmp (shell, dialup->du_shell) == 0) X return (dialup); X X if (strcmp (dialup->du_shell, "*") == 0) X return (dialup); X } X return ((struct dialup *) 0); X} X Xint isadialup (tty) Xchar *tty; X{ X FILE *fp; X char buf[BUFSIZ]; X int dialup = 0; X X if (! (fp = fopen (DIALUPS, "r"))) X return (0); X X while (fgets (buf, BUFSIZ, fp) == buf) { X if (buf[0] == '#') X continue; X X buf[strlen (buf) - 1] = '\0'; X X if (strcmp (buf, tty) == 0) { X dialup = 1; X break; X } X } X fclose (fp); X X return (dialup); X} X Xint Xputduent (dial, fp) Xstruct dialup *dial; XFILE *fp; X{ X if (! fp || ! dial) X return -1; X X if (fprintf (fp, "%s:%s\n", dial->du_shell, dial->du_passwd) == EOF) X return -1; X X return 0; X} SHAR_EOF if test 2631 -ne "`wc -c < 'dialup.c'`" then echo shar: "error transmitting 'dialup.c'" '(should have been 2631 characters)' fi fi echo shar: "extracting 'sulog.c'" '(1168 characters)' if test -f 'sulog.c' then echo shar: "will not over-write existing file 'sulog.c'" else sed 's/^X//' << \SHAR_EOF > 'sulog.c' X/* X * Copyright 1989, 1990, John F. Haugh II X * All rights reserved. X * X * Use, duplication, and disclosure prohibited without X * the express written permission of the author. X */ X X#include <sys/types.h> X#include <stdio.h> X#include <time.h> X#ifndef BSD X#include <string.h> X#include <memory.h> X#else X#include <strings.h> X#define strchr index X#define strrchr rindex X#endif X#include "config.h" X X#ifndef lint Xstatic char sccsid[] = "@(#)sulog.c 3.1 09:22:38 11/21/90"; X#endif X Xextern char name[]; Xextern char oldname[]; X Xtime_t time (); X Xvoid sulog (success) Xint success; X{ X#ifdef SULOG X char *tty; X char *cp; X char *ttyname (); X time_t clock; X struct tm *tm; X struct tm *localtime (); X FILE *fp; X X if ((fp = fopen (SULOG, "a+")) == (FILE *) 0) X return; /* can't open or create logfile */ X X (void) time (&clock); X tm = localtime (&clock); X X if (isatty (0) && (cp = ttyname (0))) { X if (tty = strrchr (cp, '/')) X tty++; X else X tty = cp; X } else X tty = "???"; X X (void) fprintf (fp, "SU %.02d/%0.2d %.02d:%.02d %c %.6s %s-%s\n", X tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, X success ? '+':'-', tty, oldname, name); X X fflush (fp); X fclose (fp); X#endif X} SHAR_EOF if test 1168 -ne "`wc -c < 'sulog.c'`" then echo shar: "error transmitting 'sulog.c'" '(should have been 1168 characters)' fi fi echo shar: "extracting 'getpass.c'" '(3390 characters)' if test -f 'getpass.c' then echo shar: "will not over-write existing file 'getpass.c'" else sed 's/^X//' << \SHAR_EOF > 'getpass.c' X/* X * Copyright 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include <sys/signal.h> X#include <stdio.h> X#include "config.h" X X#ifdef BSD X#include <sgtty.h> X#include <strings.h> X#else X#include <termio.h> X#include <string.h> X#endif X X#ifndef lint Xstatic char sccsid[] = "@(#)getpass.c 3.2 08:19:03 2/5/91"; X#endif X X/* X * limits.h may be kind enough to specify the length of a prompted X * for password. X */ X X#if defined(__STDC__) || defined(_POSIX_SOURCE) X#include <limits.h> X#endif X X/* X * This is really a giant mess. On the one hand, it would be nice X * if PASS_MAX were real big so that DOUBLESIZE isn't needed. But X * if it is defined we must honor it because some idiot might use X * this in a routine expecting some standard behavior. X */ X X#ifndef PASS_MAX X#ifdef DOUBLESIZE X#define PASS_MAX 16 X#else X#define PASS_MAX 8 X#endif X#endif X X#ifdef BSD X#define STTY(fd,termio) stty(fd, termio) X#define GTTY(fd,termio) gtty(fd, termio) X#define TERMIO struct sgttyb X#define INDEX index X#else X#define STTY(fd,termio) ioctl(fd, TCSETA, termio) X#define GTTY(fd,termio) ioctl(fd, TCGETA, termio) X#define TERMIO struct termio X#define INDEX strchr X#endif X Xstatic int sig_caught; X Xstatic void Xsig_catch () X{ X sig_caught = 1; X} X Xchar * Xgetpass (prompt) Xchar *prompt; X{ X static char input[PASS_MAX+1]; X char *return_value = 0; X char *cp; X FILE *fp; X int tty_opened = 0; X void (*old_signal)(); X TERMIO new_modes; X TERMIO old_modes; X X /* X * set a flag so the SIGINT signal can be re-sent if it X * is caught X */ X X sig_caught = 0; X X /* X * if /dev/tty can't be opened, getpass() needs to read X * from stdin instead. X */ X X if ((fp = fopen ("/dev/tty", "r")) == 0) { X fp = stdin; X setbuf (fp, (char *) 0); X } else { X tty_opened = 1; X } X X /* X * the current tty modes must be saved so they can be X * restored later on. echo will be turned off, except X * for the newline character (BSD has to punt on this) X */ X X if (GTTY (fileno (fp), &new_modes)) X return 0; X X old_modes = new_modes; X old_signal = signal (SIGINT, sig_catch); X X#ifdef BSD X new_modes.sg_flags &= ~ECHO ; X#else X new_modes.c_lflag &= ~(ECHO|ECHOE|ECHOK); X new_modes.c_lflag |= ECHONL; X#endif X X if (STTY (fileno (fp), &new_modes)) X goto out; X X /* X * the prompt is output, and the response read without X * echoing. the trailing newline must be removed. if X * the fgets() returns an error, a NULL pointer is X * returned. X */ X X if (fputs (prompt, stdout) == EOF) X goto out; X X if (fgets (input, sizeof input, fp) == input) { X if (cp = INDEX (input, '\n')) X *cp = '\0'; X else X input[sizeof input - 1] = '\0'; X X return_value = input; X#ifdef BSD X putc ('\n', stdout); X#endif X } Xout: X /* X * the old SIGINT handler is restored after the tty X * modes. then /dev/tty is closed if it was opened in X * the beginning. finally, if a signal was caught it X * is sent to this process for normal processing. X */ X X if (STTY (fileno (fp), &old_modes)) X return_value = 0; X X signal (SIGINT, old_signal); X X if (tty_opened) X fclose (fp); X X if (sig_caught) { X kill (getpid (), SIGINT); X return_value = 0; X } X return return_value; X} SHAR_EOF if test 3390 -ne "`wc -c < 'getpass.c'`" then echo shar: "error transmitting 'getpass.c'" '(should have been 3390 characters)' fi fi exit 0 # End of shell archive -- John F. Haugh II | Distribution to | UUCP: ...!cs.utexas.edu!rpp386!jfh Ma Bell: (512) 255-8251 | GEnie PROHIBITED :-) | Domain: jfh@rpp386.cactus.org "If liberals interpreted the 2nd Amendment the same way they interpret the rest of the Constitution, gun ownership would be mandatory."
jfh@rpp386.cactus.org (John F Haugh II) (05/16/91)
#! /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: # chfn.c # chsh.c # smain.c # faillog.c # pwconv.c # failure.c # utmp.c # shadow.c # This archive created: Sun Mar 3 13:27:20 1991 # By: John F Haugh II (River Parishes Programming, Austin TX) export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'chfn.c'" '(11610 characters)' if test -f 'chfn.c' then echo shar: "will not over-write existing file 'chfn.c'" else sed 's/^X//' << \SHAR_EOF > 'chfn.c' X/* X * Copyright 1989, 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include <sys/types.h> X#include <syslog.h> X#include <stdio.h> X#include <fcntl.h> X#include <signal.h> X X#ifndef lint Xstatic char sccsid[] = "@(#)chfn.c 3.4 11:23:40 12/19/90"; X#endif X X/* X * Set up some BSD defines so that all the BSD ifdef's are X * kept right here X */ X X#ifndef BSD X#include <string.h> X#include <memory.h> X#else X#include <strings.h> X#define strchr index X#define strrchr rindex X#endif X X#include "config.h" X#include "pwd.h" X X/* X * Global variables. X */ X Xchar *Progname; Xchar user[BUFSIZ]; Xchar fullnm[BUFSIZ]; Xchar roomno[BUFSIZ]; Xchar workph[BUFSIZ]; Xchar homeph[BUFSIZ]; Xchar slop[BUFSIZ]; Xint amroot; X X/* X * External identifiers X */ X Xextern int optind; Xextern char *optarg; Xextern struct passwd *getpwuid (); Xextern struct passwd *getpwnam (); Xextern char *getlogin (); X#ifdef NDBM Xextern int pw_dbm_mode; X#endif X X/* X * #defines for messages. This facilities foreign language conversion X * since all messages are defined right here. X */ X X#define USAGE \ X"Usage: %s [ -f full_name ] [ -r room_no ] [ -w work_ph ] [ -h home_ph ]\n" X#define ADMUSAGE \ X"Usage: %s [ -f full_name ] [ -r room_no ] [ -w work_ph ]\n\ X [ -h home_ph ] [ -o other ] [ user ]\n" X#define NOPERM "%s: Permission denied.\n" X#define WHOAREYOU "%s: Cannot determine you user name.\n" X#define INVALID_NAME "%s: invalid name: \"%s\"\n" X#define INVALID_ROOM "%s: invalid room number: \"%s\"\n" X#define INVALID_WORKPH "%s: invalid work phone: \"%s\"\n" X#define INVALID_HOMEPH "%s: invalid home phone: \"%s\"\n" X#define INVALID_OTHER "%s: \"%s\" contains illegal characters\n" X#define INVALID_FIELDS "%s: fields too long\n" X#define NEWFIELDSMSG "Changing the user information for %s\n" X#define NEWFIELDSMSG2 \ X"Enter the new value, or press return for the default\n\n" X#define NEWNAME "Full Name" X#define NEWROOM "Room Number" X#define NEWWORKPHONE "Work Phone" X#define NEWHOMEPHONE "Home Phone" X#define NEWSLOP "Other" X#define UNKUSER "%s: Unknown user %s\n" X#define PWDBUSY "Cannot lock the password file; try again later.\n" X#define PWDBUSY2 "can't lock /etc/passwd\n" X#define OPNERROR "Cannot open the password file.\n" X#define OPNERROR2 "can't open /etc/passwd\n" X#define UPDERROR "Error updating the password entry.\n" X#define UPDERROR2 "error updating passwd entry\n" X#define DBMERROR "Error updating the DBM password entry.\n" X#define DBMERROR2 "error updating DBM passwd entry.\n" X#define NOTROOT "Cannot change ID to root.\n" X#define NOTROOT2 "can't setuid(0).\n" X#define CLSERROR "Cannot commit password file changes.\n" X#define CLSERROR2 "can't rewrite /etc/passwd.\n" X#define UNLKERROR "Cannot unlock the password file.\n" X#define UNLKERROR2 "can't unlock /etc/passwd.\n" X#define CHGGECOS "changed user `%s' information.\n" X X/* X * usage - print command line syntax and exit X */ X Xvoid Xusage () X{ X fprintf (stderr, amroot ? USAGE:ADMUSAGE, Progname); X exit (1); X} X X/* X * new_fields - change the user's GECOS information interactively X * X * prompt the user for each of the four fields and fill in the fields X * from the user's response, or leave alone if nothing was entered. X */ X Xnew_fields () X{ X printf (NEWFIELDSMSG2); X X change_field (fullnm, NEWNAME); X change_field (roomno, NEWROOM); X change_field (workph, NEWWORKPHONE); X change_field (homeph, NEWHOMEPHONE); X X if (amroot) X change_field (slop, NEWSLOP); X} X X/* X * copy_field - get the next field from the gecos field X * X * copy_field copies the next field from the gecos field, returning a X * pointer to the field which follows, or NULL if there are no more X * fields. X */ X Xchar * Xcopy_field (in, out, extra) Xchar *in; /* the current GECOS field */ Xchar *out; /* where to copy the field to */ Xchar *extra; /* fields with '=' get copied here */ X{ X char *cp; X X while (in) { X if (cp = strchr (in, ',')) X *cp++ = '\0'; X X if (! strchr (in, '=')) X break; X X if (extra) { X if (extra[0]) X strcat (extra, ","); X X strcat (extra, in); X } X in = cp; X } X if (in && out) X strcpy (out, in); X X return cp; X} X X/* X * chfn - change a user's password file information X * X * This command controls the GECOS field information in the X * password file entry. X * X * The valid options are X * X * -f full name X * -r room number X * -w work phone number X * -h home phone number X * -o other information (*) X * X * (*) requires root permission to execute. X */ X Xint Xmain (argc, argv) Xint argc; Xchar **argv; X{ X char *cp; /* temporary character pointer */ X struct passwd *pw; /* password file entry */ X struct passwd pwent; /* modified password file entry */ X char old_gecos[BUFSIZ]; /* buffer for old GECOS fields */ X char new_gecos[BUFSIZ]; /* buffer for new GECOS fields */ X int flag; /* flag currently being processed */ X int fflg = 0; /* -f - set full name */ X int rflg = 0; /* -r - set room number */ X int wflg = 0; /* -w - set work phone number */ X int hflg = 0; /* -h - set home phone number */ X int oflg = 0; /* -o - set other information */ X int i; /* loop control variable */ X X /* X * This command behaves different for root and non-root X * users. X */ X X amroot = getuid () == 0; X#ifdef NDBM X pw_dbm_mode = O_RDWR; X#endif X X /* X * Get the program name. The program name is used as a X * prefix to most error messages. It is also used as input X * to the openlog() function for error logging. X */ X X if (Progname = strrchr (argv[0], '/')) X Progname++; X else X Progname = argv[0]; X X openlog (Progname, LOG_PID, LOG_AUTH); X X /* X * The remaining arguments will be processed one by one and X * executed by this command. The name is the last argument X * if it does not begin with a "-", otherwise the name is X * determined from the environment and must agree with the X * real UID. Also, the UID will be checked for any commands X * which are restricted to root only. X */ X X while ((flag = getopt (argc, argv, "f:r:w:h:o:")) != EOF) { X switch (flag) { X case 'f': X fflg++; X strcpy (fullnm, optarg); X break; X case 'r': X rflg++; X strcpy (roomno, optarg); X break; X case 'w': X wflg++; X strcpy (workph, optarg); X break; X case 'h': X hflg++; X strcpy (homeph, optarg); X break; X case 'o': X if (amroot) { X oflg++; X strcpy (slop, optarg); X break; X } X fprintf (stderr, NOPERM, Progname); X exit (1); X default: X usage (); X } X } X X /* X * Get the name of the user to check. It is either X * the command line name, or the name getlogin() X * returns. X */ X X if (optind < argc) { X strncpy (user, argv[optind], sizeof user); X pw = getpwnam (user); X } else if (cp = getlogin ()) { X strncpy (user, cp, sizeof user); X pw = getpwnam (user); X } else { X fprintf (stderr, WHOAREYOU, Progname); X exit (1); X } X X /* X * Make certain there was a password entry for the X * user. X */ X X if (! pw) { X fprintf (stderr, UNKUSER, Progname, user); X exit (1); X } X X /* X * Non-privileged users are only allowed to change the X * shell if the UID of the user matches the current X * real UID. X */ X X if (! amroot && pw->pw_uid != getuid ()) { X fprintf (stderr, NOPERM, Progname); X exit (1); X } X X /* X * Make a copy of the user's password file entry so it X * can be modified without worrying about it be modified X * elsewhere. X */ X X pwent = *pw; X pwent.pw_name = strdup (pw->pw_name); X pwent.pw_passwd = strdup (pw->pw_passwd); X#ifdef ATT_AGE X pwent.pw_age = strdup (pw->pw_age); X#endif X#ifdef ATT_COMMENT X pwent.pw_comment = strdup (pw->pw_comment); X#endif X pwent.pw_dir = strdup (pw->pw_dir); X pwent.pw_shell = strdup (pw->pw_shell); X X /* X * Now get the full name. It is the first comma separated field X * in the GECOS field. X */ X X strcpy (old_gecos, pw->pw_gecos); X cp = copy_field (old_gecos, fflg ? (char *) 0:fullnm, slop); X X /* X * Now get the room number. It is the next comma separated field, X * if there is indeed one. X */ X X if (cp) X cp = copy_field (cp, rflg ? (char *) 0:roomno, slop); X X /* X * Now get the work phone number. It is the third field. X */ X X if (cp) X cp = copy_field (cp, wflg ? (char *) 0:workph, slop); X X /* X * Now get the home phone number. It is the fourth field. X */ X X if (cp) X cp = copy_field (cp, hflg ? (char *) 0:homeph, slop); X X /* X * Anything left over is "slop". X */ X X if (cp) { X if (slop[0]) X strcat (slop, ","); X X strcat (slop, cp); X } X X /* X * If none of the fields were changed from the command line, X * let the user interactively change them. X */ X X if (! fflg && ! rflg && ! wflg && ! hflg && ! oflg) { X printf (NEWFIELDSMSG, user); X new_fields (); X } X X /* X * Check all of the fields for valid information X */ X X if (valid_field (fullnm, ":,=")) { X fprintf (stderr, INVALID_NAME, Progname, fullnm); X exit (1); X } X if (valid_field (roomno, ":,=")) { X fprintf (stderr, INVALID_ROOM, Progname, roomno); X exit (1); X } X if (valid_field (workph, ":,=")) { X fprintf (stderr, INVALID_WORKPH, Progname, workph); X exit (1); X } X if (valid_field (homeph, ":,=")) { X fprintf (stderr, INVALID_HOMEPH, Progname, homeph); X exit (1); X } X if (valid_field (slop, ":")) { X fprintf (stderr, INVALID_OTHER, Progname, slop); X exit (1); X } X X /* X * Build the new GECOS field by plastering all the pieces together, X * if they will fit ... X */ X X if (strlen (fullnm) + strlen (roomno) + strlen (workph) + X strlen (homeph) + strlen (slop) > 80) { X fprintf (stderr, INVALID_FIELDS, Progname); X exit (1); X } X sprintf (new_gecos, "%s,%s,%s,%s", fullnm, roomno, workph, homeph); X if (slop[0]) { X strcat (new_gecos, ","); X strcat (new_gecos, slop); X } X pwent.pw_gecos = new_gecos; X pw = &pwent; X X /* X * Before going any further, raise the ulimit to prevent X * colliding into a lowered ulimit, and set the real UID X * to root to protect against unexpected signals. Any X * keyboard signals are set to be ignored. X */ X X ulimit (2, 30000); X if (setuid (0)) { X fprintf (stderr, NOTROOT); X syslog (LOG_ERR, NOTROOT2); X exit (1); X } X signal (SIGHUP, SIG_IGN); X signal (SIGINT, SIG_IGN); X signal (SIGQUIT, SIG_IGN); X#ifdef SIGTSTP X signal (SIGTSTP, SIG_IGN); X#endif X X /* X * The passwd entry is now ready to be committed back to X * the password file. Get a lock on the file and open it. X */ X X for (i = 0;i < 30;i++) X if (pw_lock ()) X break; X X if (i == 30) { X fprintf (stderr, PWDBUSY); X syslog (LOG_WARN, PWDBUSY2); X exit (1); X } X if (! pw_open (O_RDWR)) { X fprintf (stderr, OPNERROR); X syslog (LOG_ERR, OPNERROR2); X (void) pw_unlock (); X exit (1); X } X X /* X * Update the passwd file entry. If there is a DBM file, X * update that entry as well. X */ X X if (! pw_update (pw)) { X fprintf (stderr, UPDERROR); X syslog (LOG_ERR, UPDERROR2); X (void) pw_unlock (); X exit (1); X } X#if defined(DBM) || defined(NDBM) X if (access ("/etc/passwd.pag", 0) == 0 && ! pw_dbm_update (pw)) { X fprintf (stderr, DBMERROR); X syslog (LOG_ERR, DBMERROR2); X (void) pw_unlock (); X exit (1); X } X#endif X X /* X * Changes have all been made, so commit them and unlock the X * file. X */ X X if (! pw_close ()) { X fprintf (stderr, CLSERROR); X syslog (LOG_ERR, CLSERROR2); X (void) pw_unlock (); X exit (1); X } X if (! pw_unlock ()) { X fprintf (stderr, UNLKERROR); X syslog (LOG_ERR, UNLKERROR2); X exit (1); X } X syslog (LOG_INFO, CHGGECOS, user); X closelog (); X exit (0); X} SHAR_EOF if test 11610 -ne "`wc -c < 'chfn.c'`" then echo shar: "error transmitting 'chfn.c'" '(should have been 11610 characters)' fi fi echo shar: "extracting 'chsh.c'" '(9361 characters)' if test -f 'chsh.c' then echo shar: "will not over-write existing file 'chsh.c'" else sed 's/^X//' << \SHAR_EOF > 'chsh.c' X/* X * Copyright 1989, 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include <sys/types.h> X#include <syslog.h> X#include <stdio.h> X#include <fcntl.h> X#include <signal.h> X X#ifndef lint Xstatic char sccsid[] = "@(#)chsh.c 3.3 11:23:29 12/19/90"; X#endif X X/* X * Set up some BSD defines so that all the BSD ifdef's are X * kept right here X */ X X#ifndef BSD X#include <string.h> X#include <memory.h> X#else X#include <strings.h> X#define strchr index X#define strrchr rindex X#endif X X#include "config.h" X#include "pwd.h" X X/* X * Global variables. X */ X Xchar *Progname; /* Program name */ Xint amroot; /* Real UID is root */ Xchar loginsh[BUFSIZ]; /* Name of new login shell */ X X/* X * External identifiers X */ X Xextern struct passwd *getpwuid (); Xextern struct passwd *getpwnam (); Xextern int optind; Xextern char *optarg; Xextern char *getlogin (); X#ifdef NDBM Xextern int pw_dbm_mode; X#endif X X/* X * #defines for messages. This facilities foreign language conversion X * since all messages are defined right here. X */ X X#define USAGE "Usage: %s [ -s shell ] [ name ]\n" X#define WHOAREYOU "%s: Cannot determine you user name.\n" X#define UNKUSER "%s: Unknown user %s\n" X#define NOPERM "You may not change the shell for %s.\n" X#define NOPERM2 "can't change shell for `%s'\n" X#define NEWSHELLMSG "Changing the login shell for %s\n" X#define NEWSHELL "Login Shell" X#define NEWSHELLMSG2 \ X "Enter the new value, or press return for the default\n\n" X#define BADSHELL "%s is an invalid shell.\n" X#define BADFIELD "%s: Invalid entry: %s\n" X#define PWDBUSY "Cannot lock the password file; try again later.\n" X#define PWDBUSY2 "can't lock /etc/passwd\n" X#define OPNERROR "Cannot open the password file.\n" X#define OPNERROR2 "can't open /etc/passwd\n" X#define UPDERROR "Error updating the password entry.\n" X#define UPDERROR2 "error updating passwd entry\n" X#define DBMERROR "Error updating the DBM password entry.\n" X#define DBMERROR2 "error updating DBM passwd entry.\n" X#define NOTROOT "Cannot change ID to root.\n" X#define NOTROOT2 "can't setuid(0).\n" X#define CLSERROR "Cannot commit password file changes.\n" X#define CLSERROR2 "can't rewrite /etc/passwd.\n" X#define UNLKERROR "Cannot unlock the password file.\n" X#define UNLKERROR2 "can't unlock /etc/passwd.\n" X#define CHGSHELL "changed user `%s' shell to `%s'\n" X X/* X * usage - print command line syntax and exit X */ X Xvoid Xusage () X{ X fprintf (stderr, USAGE, Progname); X exit (1); X} X X/* X * new_fields - change the user's login shell information interactively X * X * prompt the user for the login shell and change it according to the X * response, or leave it alone if nothing was entered. X */ X Xnew_fields () X{ X printf (NEWSHELLMSG2); X change_field (loginsh, NEWSHELL); X} X X/* X * check_shell - see if the user's login shell is listed in /etc/shells X * X * The /etc/shells file is read for valid names of login shells. If the X * /etc/shells file does not exist the user cannot set any shell unless X * they are root. X */ X Xcheck_shell (shell) Xchar *shell; X{ X char buf[BUFSIZ]; X char *cp; X int found = 0; X FILE *fp; X X if (amroot) X return 1; X X if ((fp = fopen ("/etc/shells", "r")) == (FILE *) 0) X return 0; X X while (fgets (buf, BUFSIZ, fp) && ! found) { X if (cp = strrchr (buf, '\n')) X *cp = '\0'; X X if (strcmp (buf, shell) == 0) X found = 1; X } X fclose (fp); X X return found; X} X X/* X * restricted_shell - return true if the named shell begins with 'r' or 'R' X * X * If the first letter of the filename is 'r' or 'R', the shell is X * considered to be restricted. X */ X Xint Xrestricted_shell (shell) Xchar *shell; X{ X char *cp; X X if (cp = strrchr (shell, '/')) X cp++; X else X cp = shell; X X return *cp == 'r' || *cp == 'R'; X} X X/* X * chsh - this command controls changes to the user's shell X * X * The only suppoerted option is -s which permits the X * the login shell to be set from the command line. X */ X Xint Xmain (argc, argv) Xint argc; Xchar **argv; X{ X char user[BUFSIZ]; /* User name */ X int flag; /* Current command line flag */ X int sflg = 0; /* -s - set shell from command line */ X int i; /* Loop control variable */ X char *cp; /* Miscellaneous character pointer */ X struct passwd *pw; /* Password entry from /etc/passwd */ X struct passwd pwent; /* New password entry */ X X /* X * This command behaves different for root and non-root X * users. X */ X X amroot = getuid () == 0; X#ifdef NDBM X pw_dbm_mode = O_RDWR; X#endif X X /* X * Get the program name. The program name is used as a X * prefix to most error messages. It is also used as input X * to the openlog() function for error logging. X */ X X if (Progname = strrchr (argv[0], '/')) X Progname++; X else X Progname = argv[0]; X X openlog (Progname, LOG_PID, LOG_AUTH); X X /* X * There is only one option, but use getopt() anyway to X * keep things consistent. X */ X X while ((flag = getopt (argc, argv, "s:")) != EOF) { X switch (flag) { X case 's': X sflg++; X strcpy (loginsh, optarg); X break; X default: X usage (); X } X } X X /* X * There should be only one remaining argument at most X * and it should be the user's name. X */ X X if (argc > optind + 1) X usage (); X X /* X * Get the name of the user to check. It is either X * the command line name, or the name getlogin() X * returns. X */ X X if (optind < argc) { X strncpy (user, argv[optind], sizeof user); X pw = getpwnam (user); X } else if (cp = getlogin ()) { X strncpy (user, cp, sizeof user); X pw = getpwnam (user); X } else { X fprintf (stderr, WHOAREYOU, Progname); X exit (1); X } X X /* X * Make certain there was a password entry for the X * user. X */ X X if (! pw) { X fprintf (stderr, UNKUSER, Progname, user); X exit (1); X } X X /* X * Non-privileged users are only allowed to change the X * shell if the UID of the user matches the current X * real UID. X */ X X if (! amroot && pw->pw_uid != getuid ()) { X fprintf (stderr, NOPERM, user); X syslog (LOG_WARN, NOPERM2, user); X exit (1); X } X X /* X * Non-privileged users are only allowed to change the X * shell if it is not a restricted one. X */ X X if (! amroot && restricted_shell (pw->pw_shell)) { X fprintf (stderr, NOPERM, user); X syslog (LOG_WARN, NOPERM2, user); X exit (1); X } X X /* X * Make a copy of the user's password file entry so it X * can be modified without worrying about it be modified X * elsewhere. X */ X X pwent = *pw; X pwent.pw_name = strdup (pw->pw_name); X pwent.pw_passwd = strdup (pw->pw_passwd); X#ifdef ATT_AGE X pwent.pw_age = strdup (pw->pw_age); X#endif X#ifdef ATT_COMMENT X pwent.pw_comment = strdup (pw->pw_comment); X#endif X pwent.pw_dir = strdup (pw->pw_dir); X pwent.pw_gecos = strdup (pw->pw_gecos); X X /* X * Now get the login shell. Either get it from the password X * file, or use the value from the command line. X */ X X if (! sflg) X strcpy (loginsh, pw->pw_shell); X X /* X * If the login shell was not set on the command line, X * let the user interactively change it. X */ X X if (! sflg) { X printf (NEWSHELLMSG, user); X new_fields (); X } X X /* X * Check all of the fields for valid information. The shell X * field may not contain any illegal characters. Non-privileged X * users are restricted to using the shells in /etc/shells. X */ X X if (valid_field (loginsh, ":,=")) { X fprintf (stderr, BADFIELD, Progname, loginsh); X exit (1); X } X if (! check_shell (loginsh)) { X fprintf (stderr, BADSHELL, loginsh); X exit (1); X } X pwent.pw_shell = loginsh; X pw = &pwent; X X /* X * Before going any further, raise the ulimit to prevent X * colliding into a lowered ulimit, and set the real UID X * to root to protect against unexpected signals. Any X * keyboard signals are set to be ignored. X */ X X ulimit (2, 30000); X if (setuid (0)) { X fprintf (stderr, NOTROOT); X syslog (LOG_ERR, NOTROOT2); X exit (1); X } X signal (SIGHUP, SIG_IGN); X signal (SIGINT, SIG_IGN); X signal (SIGQUIT, SIG_IGN); X#ifdef SIGTSTP X signal (SIGTSTP, SIG_IGN); X#endif X X /* X * The passwd entry is now ready to be committed back to X * the password file. Get a lock on the file and open it. X */ X X for (i = 0;i < 30;i++) X if (pw_lock ()) X break; X X if (i == 30) { X fprintf (stderr, PWDBUSY); X syslog (LOG_WARN, PWDBUSY2); X exit (1); X } X if (! pw_open (O_RDWR)) { X fprintf (stderr, OPNERROR); X syslog (LOG_ERR, OPNERROR2); X (void) pw_unlock (); X exit (1); X } X X /* X * Update the passwd file entry. If there is a DBM file, X * update that entry as well. X */ X X if (! pw_update (pw)) { X fprintf (stderr, UPDERROR); X syslog (LOG_ERR, UPDERROR2); X (void) pw_unlock (); X exit (1); X } X#if defined(DBM) || defined(NDBM) X if (access ("/etc/passwd.pag", 0) == 0 && ! pw_dbm_update (pw)) { X fprintf (stderr, DBMERROR); X syslog (LOG_ERR, DBMERROR2); X (void) pw_unlock (); X exit (1); X } X#endif X X /* X * Changes have all been made, so commit them and unlock the X * file. X */ X X if (! pw_close ()) { X fprintf (stderr, CLSERROR); X syslog (LOG_ERR, CLSERROR2); X (void) pw_unlock (); X exit (1); X } X if (! pw_unlock ()) { X fprintf (stderr, UNLKERROR); X syslog (LOG_ERR, UNLKERROR2); X exit (1); X } X syslog (LOG_INFO, CHGSHELL, user, pwent.pw_shell); X closelog (); X exit (0); X} SHAR_EOF if test 9361 -ne "`wc -c < 'chsh.c'`" then echo shar: "error transmitting 'chsh.c'" '(should have been 9361 characters)' fi fi echo shar: "extracting 'smain.c'" '(9944 characters)' if test -f 'smain.c' then echo shar: "will not over-write existing file 'smain.c'" else sed 's/^X//' << \SHAR_EOF > 'smain.c' X/* X * Copyright 1989, 1990, 1991, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include <sys/types.h> X#include <stdio.h> X X#ifndef lint Xstatic char sccsid[] = "%W% %U% %G%"; X#endif X X/* X * Set up some BSD defines so that all the BSD ifdef's are X * kept right here X */ X X#ifndef BSD X#include <string.h> X#include <memory.h> X#define bzero(a,n) memset(a, 0, n) X#include <termio.h> X#else X#include <strings.h> X#include <sgtty.h> X#define strchr index X#define strrchr rindex X#endif X X#include <signal.h> X#include <syslog.h> X#include "config.h" X#include "lastlog.h" X#include "pwd.h" X#include "shadow.h" X X/* X * Password aging constants X * X * DAY - seconds in a day X * WEEK - seconds in a week X * SCALE - convert from clock to aging units X */ X X#define DAY (24L*3600L) X#define WEEK (7L*DAY) X X#ifdef ITI_AGING X#define SCALE (1) X#else X#define SCALE DAY X#endif X X/* X * Assorted #defines to control su's behavior X */ X X#ifndef MAXENV X#define MAXENV 128 X#endif X X#ifndef PATH X#define PATH ":/bin:/usr/bin" X#endif X X#ifndef SUPATH X#define SUPATH ":/bin:/usr/bin:/etc" X#endif X X/* X * Global variables X */ X X#ifdef HUSHLOGIN Xchar hush[BUFSIZ]; Xint hushed; X#endif X Xchar name[BUFSIZ]; Xchar pass[BUFSIZ]; Xchar home[BUFSIZ]; Xchar prog[BUFSIZ]; Xchar mail[BUFSIZ]; Xchar oldname[BUFSIZ]; Xchar *newenvp[MAXENV]; Xchar *Prog; Xint newenvc = 0; Xint maxenv = MAXENV; Xstruct passwd pwent; X X#ifdef TZ XFILE *tzfile; Xchar tzbuf[16] = TZ; X#endif X X/* X * External identifiers X */ X Xextern void addenv (); Xextern void entry (); Xextern void sulog (); Xextern void subsystem (); Xextern void setup (); Xextern void motd (); Xextern void mailcheck (); Xextern void shell (); Xextern char *ttyname (); Xextern char *getenv (); Xextern char *getpass (); Xextern struct passwd *getpwuid (); Xextern struct passwd *getpwnam (); Xextern struct spwd *getspnam (); Xextern char **environ; X X/* X * die - set or reset termio modes. X * X * die() is called before processing begins. signal() is then X * called with die() as the signal handler. If signal later X * calls die() with a signal number, the terminal modes are X * then reset. X */ X Xvoid die (killed) Xint killed; X{ X#ifdef BSD X static struct sgtty sgtty; X X if (killed) X stty (0, &sgtty); X else X gtty (0, &sgtty); X#else X static struct termio sgtty; X X if (killed) X ioctl (0, TCSETA, &sgtty); X else X ioctl (0, TCGETA, &sgtty); X#endif X if (killed) { X closelog (); X exit (killed); X } X} X X/* X * su - switch user id X * X * su changes the user's ids to the values for the specified user. X * if no new user name is specified, "root" is used by default. X * X * The only valid option is a "-" character, which is interpreted X * as requiring a new login session to be simulated. X * X * Any additional arguments are passed to the user's shell. In X * particular, the argument "-c" will cause the next argument to X * be interpreted as a command by the common shell programs. X */ X Xint main (argc, argv, envp) Xint argc; Xchar **argv; Xchar **envp; X{ X void (*oldsig)(); X char *cp; X char *tty = 0; /* Name of tty SU is run from */ X int doshell = 0; X int fakelogin = 0; X int amroot = 0; X struct passwd *pw = 0; X struct spwd *spwd = 0; X X /* X * Get the program name. The program name is used as a X * prefix to most error messages. It is also used as input X * to the openlog() function for error logging. X */ X X if (Prog = strrchr (argv[0], '/')) X Prog++; X else X Prog = argv[0]; X X openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH); X X /* X * Get the tty name. Entries will be logged indicating that X * the user tried to change to the named new user from the X * current terminal. X */ X X if (isatty (0) && (cp = ttyname (0))) { X if (strncmp (cp, "/dev/", 5) == 0) X tty = cp + 5; X else X tty = cp; X } else X tty = "???"; X X /* X * Process the command line arguments. X */ X X argc--; argv++; /* shift out command name */ X X if (argc > 0 && argv[0][0] == '-' && argv[0][1] == '\0') { X fakelogin = 1; X argc--; argv++; /* shift ... */ X } X X /* X * If a new login is being set up, the old environment will X * be ignored and a new one created later on. X */ X X if (! fakelogin) X while (*envp) X addenv (*envp++); X X#ifdef TZ X X /* X * The timezone will be reset to the login value if required. X */ X X if (fakelogin) { X if (tzbuf[0] == '/') { X if ((tzfile = fopen (tzbuf, "r")) != (FILE *) 0) { X if (fgets (tzbuf, sizeof tzbuf, tzfile)) { X tzbuf[strlen (tzbuf) - 1] = '\0'; X addenv (tzbuf); X } X fclose (tzfile); X } X } else { X addenv (tzbuf); X } X } X#endif /* TZ */ X#ifdef HZ X X /* X * The clock frequency will be reset to the login value if required X */ X X if (fakelogin) X addenv (HZ); /* set the default $HZ, if one */ X#endif /* HZ */ X X /* X * The next argument must be either a user ID, or some flag to X * a subshell. Pretty sticky since you can't have an argument X * which doesn't start with a "-" unless you specify the new user X * name. Any remaining arguments will be passed to the user's X * login shell. X */ X X if (argc > 0 && argv[0][0] != '-') { X (void) strcpy (name, argv[0]); /* use this login id */ X argc--; argv++; /* shift ... */ X } X if (! name[0]) /* use default user ID */ X (void) strcpy (name, "root"); X X doshell = argc == 0; /* any arguments remaining? */ X X /* X * Get the user's real name. The current UID is used to determine X * who has executed su. That user ID must exist. X */ X X if (pw = getpwuid (getuid ())) /* need old user name */ X (void) strcpy (oldname, pw->pw_name); X else { /* user ID MUST exist */ X syslog (LOG_CRIT, "Unknown UID: %d\n", getuid ()); X goto failure; X } X amroot = getuid () == 0; /* currently am super user */ X Xtop: X /* X * This is the common point for validating a user whose name X * is known. It will be reached either by normal processing, X * or if the user is to be logged into a subsystem root. X * X * The password file entries for the user is gotten and the X * accont validated. X */ X X if (pw = getpwnam (name)) { X if (spwd = getspnam (name)) X pw->pw_passwd = spwd->sp_pwdp; X } else { X (void) fprintf (stderr, "Unknown id: %s\n", name); X closelog (); X exit (1); X } X pwent = *pw; X X#ifdef NOLOGIN X X /* X * See if the account is usable for anything but login. X */ X X if (strcmp (pwent.pw_shell, NOLOGIN) == 0) X pwent.pw_shell = getenv ("SHELL"); X#endif /* NOLOGIN */ X X /* X * Set the default shell. X */ X X if (pwent.pw_shell == 0 || pwent.pw_shell[0] == '\0') X pwent.pw_shell = "/bin/sh"; X X /* X * Set up a signal handler in case the user types QUIT. X */ X X die (0); X oldsig = signal (SIGQUIT, die); X X /* X * Get the password from the invoker X */ X X if (! amroot && pwent.pw_passwd[0]) { X if (! (cp = getpass ("Password:"))) { X syslog (pwent.pw_uid ? LOG_WARN:LOG_CRIT, X "Unable to get password for %s\n", name); X goto failure; X } else X strncpy (pass, cp, sizeof pass); X } else X bzero (pass, sizeof pass); X X /* X * check encrypted passwords ... X */ X X if (! amroot && ((pass[0] != '\0' || pwent.pw_passwd[0] != '\0') && X strcmp (pwent.pw_passwd, X pw_encrypt (pass, pwent.pw_passwd)) != 0)) { X syslog (pwent.pw_uid ? LOG_WARN:LOG_CRIT, X "Invalid password for %s\n", name); Xfailure: sulog (0); /* log failed attempt */ X syslog (pwent.pw_uid ? LOG_INFO:LOG_CRIT, X "- %s %s-%s\n", tty ? tty:"???", X oldname[0] ? oldname:"???", name[0] ? name:"???"); X puts ("Sorry."); X closelog (); X exit (1); X } X signal (SIGQUIT, oldsig); X X /* X * Check to see if the account is expired. root gets to X * ignore any expired accounts, but normal users can't become X * a user with an expired password. X */ X X if (! amroot) { X if (spwd) { X if (isexpired (&pwent, spwd)) { X syslog (pwent.pw_uid ? LOG_WARN:LOG_CRIT, X "Expired account %s\n", name); X goto failure; X } X } X#ifdef ATT_AGE X else if (pwent.pw_age[0] && X isexpired (&pwent, (struct spwd *) 0)) { X syslog (pwent.pw_uid ? LOG_WARN:LOG_CRIT, X "Expired account %s\n", name); X goto failure; X } X#endif /* ATT_AGE */ X } X if (pwent.pw_uid == 0) X addenv (SUPATH); X else X addenv (PATH); X X environ = newenvp; /* make new environment active */ X X if (getenv ("IFS")) /* don't export user IFS ... */ X addenv ("IFS= \t\n"); /* ... instead, set a safe IFS */ X X if (doshell && pwent.pw_shell[0] == '*') { /* subsystem root required */ X subsystem (&pwent); /* figure out what to execute */ X endpwent (); X endspent (); X goto top; X } X X sulog (1); /* save SU information */ X syslog (LOG_INFO, "+ %s %s-%s\n", tty ? tty:"???", X oldname[0] ? oldname:"???", name[0] ? name:"???"); X X if (fakelogin) X setup (&pwent); /* set UID, GID, HOME, etc ... */ X else { X if (setgid (pwent.pw_gid) || setuid (pwent.pw_uid)) { X perror ("Can't set ID"); X syslog (LOG_CRIT, "Unable to set uid = %d, gid = %d\n", X pwent.pw_uid, pwent.pw_gid); X closelog (); X exit (1); X } X } X if (! doshell) { /* execute arguments as command */ X if (cp = getenv ("SHELL")) X pwent.pw_shell = cp; X argv[-1] = pwent.pw_shell; X (void) execv (pwent.pw_shell, &argv[-1]); X (void) fprintf (stderr, "No shell\n"); X syslog (LOG_WARN, "Cannot execute %s\n", pwent.pw_shell); X closelog (); X exit (1); X } X if (fakelogin) { X#ifdef HUSHLOGIN X sprintf (hush, "%s/.hushlogin", pwent.pw_dir); X hushed = access (hush, 0) != -1; X#endif /* HUSHLOGIN */ X#ifdef MOTD X motd (); /* print the message of the day */ X#endif /* MOTD */ X#ifdef MAILCHECK X if (! hushed) X mailcheck (); /* report on the status of mail */ X#endif /* MAILCHECK */ X shell (pwent.pw_shell, "-su"); /* exec the shell finally. */ X } else { X if (cp = strrchr (pwent.pw_shell, '/')) X cp++; X else X cp = pwent.pw_shell; X X shell (pwent.pw_shell, cp); X } X syslog (LOG_WARN, "Cannot execute %s\n", pwent.pw_shell); X X /*NOTREACHED*/ X} SHAR_EOF if test 9944 -ne "`wc -c < 'smain.c'`" then echo shar: "error transmitting 'smain.c'" '(should have been 9944 characters)' fi fi echo shar: "extracting 'faillog.c'" '(5024 characters)' if test -f 'faillog.c' then echo shar: "will not over-write existing file 'faillog.c'" else sed 's/^X//' << \SHAR_EOF > 'faillog.c' X/* X * Copyright 1989, 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include <sys/types.h> X#include <sys/stat.h> X#include <stdio.h> X#include "pwd.h" X#include <time.h> X#ifndef BSD X#include <string.h> X#include <memory.h> X#else X#include <strings.h> X#define strchr index X#define strrchr rindex X#endif X#include "config.h" X#include "faillog.h" X X#ifndef lint Xstatic char _sccsid[] = "@(#)faillog.c 3.1 12:30:41 12/12/90"; X#endif X XFILE *fail; /* failure file stream */ Xoff_t user; /* one single user, specified on command line */ Xint days; /* number of days to consider for print command */ Xtime_t seconds; /* that number of days in seconds */ Xint max; /* maximum failure count for fail_max */ X Xint mflg; /* set fail_max for a given user */ Xint rflg; /* reset fail_cnt for user or all user's */ Xint uflg; /* set if user is a valid user id */ Xint tflg; /* print is restricted to most recent days */ Xstruct faillog faillog; /* scratch structure to play with ... */ Xstruct stat statbuf; /* fstat buffer for file size */ X Xextern int optind; Xextern char *optarg; Xextern char *asctime (); Xextern struct passwd *getpwuid (); Xextern struct passwd *getpwnam (); Xextern struct passwd *getpwent (); Xextern struct tm *localtime (); X X#define DAY (24L*3600L) X#define NOW (time ((time_t *) 0)) X Xmain (argc, argv) Xint argc; Xchar **argv; X{ X char *mode; X int uid = 0; X int c; X struct passwd *pwent; X X if (getuid () == 0) /* only root can update anything */ X mode = "r+"; X else /* all others can only look */ X mode = "r"; X X if ((fail = fopen (FAILFILE, mode)) == (FILE *) 0) { X perror (FAILFILE); X exit (1); X } X while ((c = getopt (argc, argv, "m:pru:t:")) != EOF) { X switch (c) { X case 'm': X max = atoi (optarg); X setmax (); X break; X case 'p': X print (); X break; X case 'r': X reset (); X break; X case 'u': X pwent = getpwnam (optarg); X if (! pwent) { X fprintf (stderr, "Unknown User: %s\n", optarg); X exit (1); X } X uflg++; X user = pwent->pw_uid; X break; X case 't': X days = atoi (optarg); X seconds = days * DAY; X tflg++; X break; X } X } X fclose (fail); X exit (0); X} X Xprint () X{ X int uid; X off_t offset; X X if (uflg) { X offset = user * sizeof faillog; X fstat (fileno (fail), &statbuf); X if (offset >= statbuf.st_size) X return; X X fseek (fail, (off_t) user * sizeof faillog, 0); X if (fread ((char *) &faillog, sizeof faillog, 1, fail) == 1) X print_one (&faillog, user); X else X perror (FAILFILE); X } else { X for (uid = 0; X fread ((char *) &faillog, sizeof faillog, 1, fail) == 1; X uid++) { X X if (faillog.fail_cnt == 0) X continue; X X if (tflg && NOW - faillog.fail_time > seconds) X continue; X X print_one (&faillog, uid); X } X } X} X Xprint_one (faillog, uid) Xstruct faillog *faillog; X{ X static int once; X char *cp; X struct tm *tm; X struct passwd *pwent; X X if (! once) { X printf ("Username Failures Maximum Latest\n"); X once++; X } X pwent = getpwuid (uid); X tm = localtime (&faillog->fail_time); X cp = asctime (tm); X cp[24] = '\0'; X X if (pwent) { X printf ("%-16s %4d %4d", X pwent->pw_name, faillog->fail_cnt, faillog->fail_max); X if (faillog->fail_time) X printf (" %s on %s\n", cp, faillog->fail_line); X else X putchar ('\n'); X } X} X Xreset () X{ X int uid = 0; X X if (uflg) X reset_one (user); X else X for (uid = 0;reset_one (uid);uid++) X ; X} X Xreset_one (uid) Xint uid; X{ X off_t offset; X X offset = uid * sizeof faillog; X fstat (fileno (fail), &statbuf); X if (offset >= statbuf.st_size) X return (0); X X if (fseek (fail, offset, 0) != 0) { X perror (FAILFILE); X return (0); X } X if (fread ((char *) &faillog, sizeof faillog, 1, fail) != 1) { X if (! feof (fail)) X perror (FAILFILE); X X return (0); X } X if (faillog.fail_cnt == 0) X return (1); /* don't fill in no holes ... */ X X faillog.fail_cnt = 0; X X if (fseek (fail, offset, 0) == 0 X && fwrite ((char *) &faillog, sizeof faillog, 1, fail) == 1) { X fflush (fail); X return (1); X } else { X perror (FAILFILE); X } X return (0); X} X Xsetmax () X{ X int uid = 0; X struct passwd *pwent; X X if (uflg) { X setmax_one (user); X } else { X setpwent (); X while (pwent = getpwent ()) X setmax_one (pwent->pw_uid); X } X} X Xsetmax_one (uid) Xint uid; X{ X off_t offset; X X offset = uid * sizeof faillog; X X if (fseek (fail, offset, 0) != 0) { X perror (FAILFILE); X return; X } X if (fread ((char *) &faillog, sizeof faillog, 1, fail) != 1) { X if (! feof (fail)) X perror (FAILFILE); X } else { X#ifndef BSD X memset ((char *) &faillog, '\0', sizeof faillog); X#else X bzero ((char *) &faillog, sizeof faillog); X#endif X } X faillog.fail_max = max; X X if (fseek (fail, offset, 0) == 0 X && fwrite ((char *) &faillog, sizeof faillog, 1, fail) == 1) X fflush (fail); X else X perror (FAILFILE); X} SHAR_EOF if test 5024 -ne "`wc -c < 'faillog.c'`" then echo shar: "error transmitting 'faillog.c'" '(should have been 5024 characters)' fi fi echo shar: "extracting 'pwconv.c'" '(4442 characters)' if test -f 'pwconv.c' then echo shar: "will not over-write existing file 'pwconv.c'" else sed 's/^X//' << \SHAR_EOF > 'pwconv.c' X/* X * Copyright 1989, 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X * X * pwconv - convert and update shadow password files X * X * Pwconv copies the old password file information to a new shadow X * password file, merging entries from an optional existing shadow X * file. X * X * The new password file is left in npasswd, the new shadow file is X * left in nshadow. Existing shadow entries are copied as is. X * New entries are created with passwords which expire in MAXDAYS days, X * with a last changed date of today, unless password aging X * information was already present. Likewise, the minimum number of X * days before which the password may be changed is controlled by X * MINDAYS. The number of warning days is set to WARNAGE if that X * macro exists. Entries with blank passwordsare not copied to the X * shadow file at all. X */ X X#include <sys/types.h> X#include <stdio.h> X#include <fcntl.h> X#include "pwd.h" X#ifndef BSD X#include <string.h> X#else X#define strchr index X#define strrchr rindex X#include <strings.h> X#endif X#include "config.h" X#include "shadow.h" X X#ifndef lint Xstatic char _sccsid[] = "@(#)pwconv.c 3.2 12:31:11 12/12/90"; X#endif X Xchar buf[BUFSIZ]; X Xlong time (); Xlong a64l (); X Xint main () X{ X long today; X struct passwd *pw; X struct passwd *sgetpwent (); X FILE *pwd; X FILE *npwd; X FILE *shadow; X struct spwd *spwd; X struct spwd tspwd; X int fd; X char *cp; X X if (! (pwd = fopen (PWDFILE, "r"))) { X perror (PWDFILE); X exit (1); X } X unlink ("npasswd"); X if ((fd = open ("npasswd", O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0 || X ! (npwd = fdopen (fd, "w"))) { X perror ("npasswd"); X exit (1); X } X unlink ("nshadow"); X if ((fd = open ("nshadow", O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0 || X ! (shadow = fdopen (fd, "w"))) { X perror ("nshadow"); X (void) unlink ("npasswd"); X (void) unlink ("nshadow"); X exit (1); X } X X (void) time (&today); X today /= (24L * 60L * 60L); X X while (fgets (buf, BUFSIZ, pwd) == buf) { X if (cp = strrchr (buf, '\n')) X *cp = '\0'; X X if (buf[0] == '#') { /* comment line */ X (void) fprintf (npwd, "%s\n", buf); X continue; X } X if (! (pw = sgetpwent (buf))) { /* copy bad lines verbatim */ X (void) fprintf (npwd, "%s\n", buf); X continue; X } X if (pw->pw_passwd[0] == '\0') { /* no password, skip */ X (void) fprintf (npwd, "%s\n", buf); X continue; X } X setspent (); /* rewind old shadow file */ X X if (spwd = getspnam (pw->pw_name)) { X if (putspent (spwd, shadow)) { /* copy old entry */ X perror ("nshadow"); X goto error; X } X } else { /* need a new entry. */ X tspwd.sp_namp = pw->pw_name; X tspwd.sp_pwdp = pw->pw_passwd; X pw->pw_passwd = "x"; X#ifdef ATT_AGE X if (pw->pw_age) { /* copy old password age stuff */ X if (strlen (pw->pw_age) >= 2) { X tspwd.sp_min = c64i (pw->pw_age[1]); X tspwd.sp_max = c64i (pw->pw_age[0]); X } else { X tspwd.sp_min = tspwd.sp_max = -1; X } X if (strlen (pw->pw_age) == 4) X tspwd.sp_lstchg = a64l (&pw->pw_age[2]); X else X tspwd.sp_lstchg = -1; X X /* X * Convert weeks to days X */ X X if (tspwd.sp_min != -1) X tspwd.sp_min *= 7; X X if (tspwd.sp_max != -1) X tspwd.sp_max *= 7; X X if (tspwd.sp_lstchg != -1) X tspwd.sp_lstchg *= 7; X } else X#endif /* ATT_AGE */ X { /* fake up new password age stuff */ X tspwd.sp_max = MAXDAYS; X tspwd.sp_min = MINDAYS; X tspwd.sp_lstchg = today; X } X#ifdef WARNAGE X tspwd.sp_warn = WARNAGE; X tspwd.sp_inact = tspwd.sp_expire = tspwd.sp_flag = -1; X#else X tspwd.sp_warn = tspwd.sp_inact = tspwd.sp_expire = X tspwd.sp_flag = -1; X#endif X if (putspent (&tspwd, shadow)) { /* output entry */ X perror ("nshadow"); X goto error; X } X } X (void) fprintf (npwd, "%s:%s:%d:%d:%s:%s:", X pw->pw_name, pw->pw_passwd, X pw->pw_uid, pw->pw_gid, X pw->pw_gecos, pw->pw_dir); X X if (fprintf (npwd, "%s\n", X pw->pw_shell ? pw->pw_shell:"") == EOF) { X perror ("npasswd"); X goto error; X } X } X endspent (); X X if (ferror (npwd) || ferror (shadow)) { X perror ("pwconv"); Xerror: X (void) unlink ("npasswd"); X (void) unlink ("nshadow"); X exit (1); X } X (void) fclose (pwd); X (void) fclose (npwd); X (void) fclose (shadow); X X exit (0); X} SHAR_EOF if test 4442 -ne "`wc -c < 'pwconv.c'`" then echo shar: "error transmitting 'pwconv.c'" '(should have been 4442 characters)' fi fi echo shar: "extracting 'failure.c'" '(2948 characters)' if test -f 'failure.c' then echo shar: "will not over-write existing file 'failure.c'" else sed 's/^X//' << \SHAR_EOF > 'failure.c' X/* X * Copyright 1989, 1990, John F. Haugh II X * All rights reserved. X * X * Use, duplication, and disclosure prohibited without X * the express written permission of the author. X */ X X#include <sys/types.h> X#include <fcntl.h> X#include <time.h> X#ifndef BSD X#include <string.h> X#include <memory.h> X#else X#include <strings.h> X#define strchr index X#define strrchr rindex X#endif X#include "faillog.h" X#include "config.h" X X#ifdef FTMP X#include <utmp.h> X#endif X X#ifndef lint Xstatic char _sccsid[] = "@(#)failure.c 2.3 19:23:48 7/29/90"; X#endif X X#ifdef FAILLOG X X#define DAY (24L*3600L) X#define YEAR (365L*DAY) X#define NOW (time ((time_t *) 0)) X Xextern struct tm *localtime (); Xextern char *asctime (); Xextern void failprint (); X X/* X * failure - make failure entry X */ X Xvoid Xfailure (uid, tty, faillog) Xint uid; Xchar *tty; Xstruct faillog *faillog; X{ X int fd; X X if ((fd = open (FAILFILE, O_RDWR)) < 0) X return; X X lseek (fd, (off_t) (sizeof *faillog) * uid, 0); X if (read (fd, (char *) faillog, sizeof *faillog) X != sizeof *faillog) X#ifndef BSD X memset ((void *) faillog, '\0', sizeof *faillog); X#else X bzero ((char *) faillog, sizeof *faillog); X#endif X X if (faillog->fail_max == 0 || faillog->fail_cnt < faillog->fail_max) X faillog->fail_cnt++; X X strncpy (faillog->fail_line, tty, sizeof faillog->fail_line); X faillog->fail_time = time ((time_t *) 0); X X lseek (fd, (off_t) (sizeof *faillog) * uid, 0); X write (fd, (char *) faillog, sizeof *faillog); X close (fd); X} X X/* X * failcheck - check for failures > allowable X * X * failcheck() is called AFTER the password has been validated. X */ X Xint Xfailcheck (uid, faillog, failed) Xint uid; Xstruct faillog *faillog; X{ X int fd; X int okay = 1; X struct faillog fail; X X if ((fd = open (FAILFILE, O_RDWR)) < 0) X return (1); X X lseek (fd, (off_t) (sizeof *faillog) * uid, 0); X if (read (fd, (char *) faillog, sizeof *faillog) == sizeof *faillog) { X if (faillog->fail_max != 0 X && faillog->fail_cnt >= faillog->fail_max) X okay = 0; X } X if (!failed && okay) { X fail = *faillog; X fail.fail_cnt = 0; X X lseek (fd, (off_t) sizeof fail * uid, 0); X write (fd, (char *) &fail, sizeof fail); X } X close (fd); X X return (okay); X} X X/* X * failprint - print line of failure information X */ X Xvoid Xfailprint (uid, fail) Xstruct faillog *fail; X{ X int fd; X struct tm *tp; X char *lasttime; X X if (fail->fail_cnt == 0) X return; X X tp = localtime (&fail->fail_time); X lasttime = asctime (tp); X lasttime[24] = '\0'; X X if (NOW - fail->fail_time < YEAR) X lasttime[19] = '\0'; X if (NOW - fail->fail_time < DAY) X lasttime = lasttime + 11; X X if (*lasttime == ' ') X lasttime++; X X printf ("%d %s since last login. Last was %s on %s.\n", X fail->fail_cnt, fail->fail_cnt > 1 ? "failures":"failure", X lasttime, fail->fail_line); X} X#endif X X#ifdef FTMP X Xvoid Xfailtmp (failent) Xstruct utmp *failent; X{ X int fd; X X if ((fd = open (FTMP, O_WRONLY|O_APPEND)) == -1) X return; X X write (fd, (char *) failent, sizeof *failent); X close (fd); X} X#endif SHAR_EOF if test 2948 -ne "`wc -c < 'failure.c'`" then echo shar: "error transmitting 'failure.c'" '(should have been 2948 characters)' fi fi echo shar: "extracting 'utmp.c'" '(2985 characters)' if test -f 'utmp.c' then echo shar: "will not over-write existing file 'utmp.c'" else sed 's/^X//' << \SHAR_EOF > 'utmp.c' X/* X * Copyright 1989, 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include <sys/types.h> X#include <utmp.h> X#include <fcntl.h> X#ifndef BSD X#include <string.h> X#include <memory.h> X#define bzero(a,n) memset(a, 0, n) X#else X#include <strings.h> X#define strchr index X#define strrchr rindex X#endif X#include <stdio.h> X#include "config.h" X X#ifndef lint Xstatic char sccsid[] = "%W% %U% %G%"; X#endif X Xextern struct utmp utent; Xextern char name[]; X Xextern struct utmp *getutent(); Xextern void setutent(); Xextern void endutent(); Xextern time_t time(); Xextern char *ttyname(); X X#define NO_UTENT \ X "No utmp entry. You must exec \"login\" from the lowest level \"sh\"" X X/* X * checkutmp - see if utmp file is correct for this process X * X * System V is very picky about the contents of the utmp file X * and requires that a slot for the current process exist. X * The utmp file is scanned for an entry with the same process X * ID. If no entry exists the process exits with a message. X */ X Xvoid Xcheckutmp (picky) Xint picky; X{ X struct utmp *ut; X char *line; X#ifndef NDEBUG X int pid = getppid (); X#else X int pid = getpid (); X#endif X setutent (); X X#ifndef BSD X if (picky) { X while (ut = getutent ()) X if (ut->ut_pid == pid) X break; X X if (ut) X utent = *ut; X X endutent (); X X if (ut && utent.ut_pid == pid) X return; X X puts (NO_UTENT); X exit (1); X } else { X line = ttyname (0); X if (strncmp (line, "/dev/", 5) == 0) X line += 5; X X strncpy (utent.ut_line, line, sizeof utent.ut_line); X if (ut = getutline (&utent)) X strncpy (utent.ut_id, ut->ut_id, sizeof ut->ut_id); X X strcpy (utent.ut_user, "LOGIN"); X utent.ut_pid = getpid (); X utent.ut_type = LOGIN_PROCESS; X time (&utent.ut_time); X } X#endif X} X X/* X * setutmp - put a USER_PROCESS entry in the utmp file X * X * setutmp changes the type of the current utmp entry to X * USER_PROCESS. the wtmp file will be updated as well. X */ X Xvoid Xsetutmp (name, line) Xchar *name; Xchar *line; X{ X FILE *wtmp; X struct utmp utent; X int fd; X int i; X int found = 0; X X if (! (fd = open ("/etc/utmp", O_RDWR))) X return; X X while (! found && read (fd, &utent, sizeof utent) == sizeof utent) { X if (! strncmp (line, utent.ut_line, sizeof utent.ut_line)) X found++; X } X if (! found) { X bzero (&utent, sizeof utent); X strncpy (utent.ut_line, line, sizeof utent.ut_line); X } X (void) strncpy (utent.ut_user, name, sizeof utent.ut_user); X#ifndef BSD X utent.ut_type = USER_PROCESS; X utent.ut_pid = getpid (); X#endif X (void) time (&utent.ut_time); X X if (found) X lseek (fd, (long) - sizeof utent, 1); X X write (fd, &utent, sizeof utent); X close (fd); X X if ((wtmp = fopen (WTMP_FILE, "a+"))) { X fwrite (&utent, sizeof utent, 1, wtmp); X fclose (wtmp); X } X} SHAR_EOF if test 2985 -ne "`wc -c < 'utmp.c'`" then echo shar: "error transmitting 'utmp.c'" '(should have been 2985 characters)' fi fi echo shar: "extracting 'shadow.c'" '(5862 characters)' if test -f 'shadow.c' then echo shar: "will not over-write existing file 'shadow.c'" else sed 's/^X//' << \SHAR_EOF > 'shadow.c' X/* X * Copyright 1989, 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include "shadow.h" X#include "config.h" X#include <stdio.h> X X#ifndef BSD X#include <string.h> X#include <memory.h> X#else X#include <strings.h> X#define strchr index X#define strrchr rindex X#endif X X#ifdef NDBM X#include <ndbm.h> X#include <fcntl.h> XDBM *sp_dbm; Xint sp_dbm_mode = -1; Xstatic int dbmopened; Xstatic int dbmerror; X#endif X X X#ifndef lint Xstatic char sccsid[] = "@(#)shadow.c 3.8 07:57:47 2/8/91"; X#endif X Xstatic FILE *shadow; Xstatic char spwbuf[BUFSIZ]; Xstatic struct spwd spwd; X X#define FIELDS 9 X#define OFIELDS 5 X Xvoid Xsetspent () X{ X int mode; X X if (shadow) X rewind (shadow); X else X shadow = fopen (SHADOW, "r"); X X /* X * Attempt to open the DBM files if they have never been opened X * and an error has never been returned. X */ X X#ifdef NDBM X if (! dbmerror && ! dbmopened) { X int mode; X char dbmfiles[BUFSIZ]; X X strcpy (dbmfiles, SHADOW); X strcat (dbmfiles, ".pag"); X X if (sp_dbm_mode == -1) X mode = O_RDWR; X else X mode = (sp_dbm_mode == O_RDWR) ? O_RDWR:O_RDONLY; X X if (! (sp_dbm = dbm_open (SHADOW, mode, 0))) X dbmerror = 1; X else X dbmopened = 1; X } X#endif X} X Xvoid Xendspent () X{ X if (shadow) X (void) fclose (shadow); X X shadow = (FILE *) 0; X#ifdef NDBM X if (dbmopened && sp_dbm) { X dbm_close (sp_dbm); X sp_dbm = 0; X } X dbmopened = 0; X dbmerror = 0; X#endif X} X Xstruct spwd * Xsgetspent (string) Xchar *string; X{ X char *fields[FIELDS]; X char *cp; X char *cpp; X int atoi (); X long atol (); X int i; X X strncpy (spwbuf, string, BUFSIZ-1); X spwbuf[BUFSIZ-1] = '\0'; X X if (cp = strrchr (spwbuf, '\n')) X *cp = '\0'; X X for (cp = spwbuf, i = 0;*cp && i < FIELDS;i++) { X fields[i] = cp; X while (*cp && *cp != ':') X cp++; X X if (*cp) X *cp++ = '\0'; X } X if (i == (FIELDS-1)) X fields[i++] = cp; X X if (*cp || (i != FIELDS && i != OFIELDS)) X return 0; X X spwd.sp_namp = fields[0]; X spwd.sp_pwdp = fields[1]; X X if ((spwd.sp_lstchg = strtol (fields[2], &cpp, 10)) == 0 && *cpp) X return 0; X else if (fields[2][0] == '\0') X spwd.sp_lstchg = -1; X X if ((spwd.sp_min = strtol (fields[3], &cpp, 10)) == 0 && *cpp) X return 0; X else if (fields[3][0] == '\0') X spwd.sp_min = -1; X X if ((spwd.sp_max = strtol (fields[4], &cpp, 10)) == 0 && *cpp) X return 0; X else if (fields[4][0] == '\0') X spwd.sp_max = -1; X X if (i == OFIELDS) { X spwd.sp_warn = spwd.sp_inact = spwd.sp_expire = X spwd.sp_flag = -1; X X return &spwd; X } X if ((spwd.sp_warn = strtol (fields[5], &cpp, 10)) == 0 && *cpp) X return 0; X else if (fields[5][0] == '\0') X spwd.sp_warn = -1; X X if ((spwd.sp_inact = strtol (fields[6], &cpp, 10)) == 0 && *cpp) X return 0; X else if (fields[6][0] == '\0') X spwd.sp_inact = -1; X X if ((spwd.sp_expire = strtol (fields[7], &cpp, 10)) == 0 && *cpp) X return 0; X else if (fields[7][0] == '\0') X spwd.sp_expire = -1; X X if ((spwd.sp_flag = strtol (fields[8], &cpp, 10)) == 0 && *cpp) X return 0; X else if (fields[8][0] == '\0') X spwd.sp_flag = -1; X X return (&spwd); X} X Xstruct spwd X*fgetspent (fp) XFILE *fp; X{ X char buf[BUFSIZ]; X X if (! fp) X return (0); X X if (fgets (buf, BUFSIZ, fp) == (char *) 0) X return (0); X X return sgetspent (buf); X} X Xstruct spwd X*getspent () X{ X if (! shadow) X setspent (); X X return (fgetspent (shadow)); X} X Xstruct spwd X*getspnam (name) Xchar *name; X{ X struct spwd *sp; X#ifdef NDBM X datum key; X datum content; X#endif X X setspent (); X X#ifdef NDBM X X /* X * If the DBM file are now open, create a key for this UID and X * try to fetch the entry from the database. A matching record X * will be unpacked into a static structure and returned to X * the user. X */ X X if (dbmopened) { X key.dsize = strlen (name); X key.dptr = name; X X content = dbm_fetch (sp_dbm, key); X if (content.dptr != 0) { X memcpy (spwbuf, content.dptr, content.dsize); X spw_unpack (spwbuf, content.dsize, &spwd); X return &spwd; X } X } X#endif X while ((sp = getspent ()) != (struct spwd *) 0) { X if (strcmp (name, sp->sp_namp) == 0) X return (sp); X } X return (0); X} X Xint Xputspent (sp, fp) Xstruct spwd *sp; XFILE *fp; X{ X int errors = 0; X X if (! fp || ! sp) X return -1; X X if (fprintf (fp, "%s:%s:", sp->sp_namp, sp->sp_pwdp) < 0) X errors++; X X if (sp->sp_lstchg != -1) { X if (fprintf (fp, "%ld:", sp->sp_lstchg) < 0) X errors++; X } else if (putc (':', fp) == EOF) X errors++; X X if (sp->sp_min != -1) { X if (fprintf (fp, "%ld:", sp->sp_min) < 0) X errors++; X } else if (putc (':', fp) == EOF) X errors++; X X if (sp->sp_max != -1) { X if (fprintf (fp, "%ld", sp->sp_max) < 0) X errors++; X } X X /* X * See if the structure has any of the SVR4 fields in X * it. If none of those fields have any data there is X * no reason to write them out since they will be filled X * in the same way when they are read back in. Otherwise X * there is at least one SVR4 field that must be output. X */ X X if (sp->sp_warn == -1 && sp->sp_inact == -1 && X sp->sp_expire == -1 && sp->sp_flag == -1) { X if (putc ('\n', fp) == EOF || errors) X return -1; X else X return 0; X } else if (putc (':', fp) == EOF) X errors++; X X if (sp->sp_warn != -1) { X if (fprintf (fp, "%ld:", sp->sp_warn) < 0) X errors++; X } else if (putc (':', fp) == EOF) X errors++; X X if (sp->sp_inact != -1) { X if (fprintf (fp, "%ld:", sp->sp_inact) < 0) X errors++; X } else if (putc (':', fp) == EOF) X errors++; X X if (sp->sp_expire != -1) { X if (fprintf (fp, "%ld:", sp->sp_expire) < 0) X errors++; X } else if (putc (':', fp) == EOF) X errors++; X X if (sp->sp_flag != -1) { X if (fprintf (fp, "%ld", sp->sp_flag) < 0) X errors++; X } X if (putc ('\n', fp) == EOF) X errors++; X X if (errors) X return -1; X else X return 0; X} SHAR_EOF if test 5862 -ne "`wc -c < 'shadow.c'`" then echo shar: "error transmitting 'shadow.c'" '(should have been 5862 characters)' fi fi exit 0 # End of shell archive -- John F. Haugh II | Distribution to | UUCP: ...!cs.utexas.edu!rpp386!jfh Ma Bell: (512) 255-8251 | GEnie PROHIBITED :-) | Domain: jfh@rpp386.cactus.org "If liberals interpreted the 2nd Amendment the same way they interpret the rest of the Constitution, gun ownership would be mandatory."
jfh@rpp386.cactus.org (John F Haugh II) (05/16/91)
#! /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: # gpmain.c # chage.c # pwent.c # valid.c # setup.c # entry.c # ttytype.c # port.h # This archive created: Sun Mar 3 13:27:23 1991 # By: John F Haugh II (River Parishes Programming, Austin TX) export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'gpmain.c'" '(9448 characters)' if test -f 'gpmain.c' then echo shar: "will not over-write existing file 'gpmain.c'" else sed 's/^X//' << \SHAR_EOF > 'gpmain.c' X/* X * Copyright 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include <sys/types.h> X#include <stdio.h> X#include "pwd.h" X#include <grp.h> X#include <fcntl.h> X#include <signal.h> X#include <errno.h> X#ifndef BSD X#include <termio.h> X#ifdef SYS3 X#include <sys/ioctl.h> X#endif X#include <string.h> X#ifndef SYS3 X#include <memory.h> X#endif X#else X#include <sgtty.h> X#include <strings.h> X#define strchr index X#define strrchr rindex X#endif X#include "config.h" X X#ifndef PASSLENGTH X#define PASSLENGTH 5 X#endif X X#ifndef lint Xstatic char _sccsid[] = "@(#)gpmain.c 3.4 12:30:43 12/12/90"; X#endif X Xchar name[BUFSIZ]; Xchar pass[BUFSIZ]; Xchar pass2[BUFSIZ]; X Xstruct group grent; X Xchar *Prog; Xchar *user; Xchar *group; Xint aflg; Xint dflg; Xint rflg; Xint Rflg; X X#ifndef RETRIES X#define RETRIES 3 X#endif X Xextern char *l64a (); Xextern char *crypt (); Xextern char *pw_encrypt (); Xextern int errno; Xextern long a64l (); Xextern void entry (); Xextern time_t time (); X X/* X * usage - display usage message X */ X Xvoid Xusage () X{ X fprintf (stderr, "usage: %s [ -r|R ] group\n", Prog); X fprintf (stderr, " %s [ -a user ] group\n", Prog); X fprintf (stderr, " %s [ -d user ] group\n", Prog); X exit (1); X} X X/* X * add_list - add a member to a list of group members X * X * the array of member names is searched for the new member X * name, and if not present it is added to a freshly allocated X * list of users. X */ X Xchar ** Xadd_list (list, member) Xchar **list; Xchar *member; X{ X int i; X int found = 0; X char **tmp; X X for (i = 0;!found && list[i] != (char *) 0;i++) X if (strcmp (list[i], member) == 0) X found++; X X tmp = (char **) malloc ((i + 2) * sizeof member); X X for (i = 0;list[i] != (char *) 0;i++) X tmp[i] = list[i]; X X if (! found) X tmp[i++] = strdup (member); X X tmp[i] = (char *) 0; X return tmp; X} X X/* X * del_list - delete a group member from a list of members X * X * del_list searches a list of group members, copying the X * members which do not match "member" to a newly allocated X * list. X */ X Xchar ** Xdel_list (list, member) Xchar **list; Xchar *member; X{ X int i, j; X char **tmp; X X for (j = i = 0;list[i] != (char *) 0;i++) X if (strcmp (list[i], member)) X j++; X X tmp = (char **) malloc ((j + 1) * sizeof member); X X for (j = i = 0;list[i] != (char *) 0;i++) X if (strcmp (list[i], member) != 0) X tmp[j++] = list[i]; X X tmp[j] = (char *) 0; X X return tmp; X} X Xint Xmain (argc, argv) Xint argc; Xchar **argv; X{ X extern int optind; X extern char *optarg; X int flag; X int i; X void die (); X char *cp; X char *getlogin (); X int amroot; X int retries; X int ruid = getuid(); X struct group *gr; X struct group *getgrnam (); X struct group *sgetgrent (); X struct passwd *pw; X struct passwd *getpwuid (); X struct passwd *getpwnam (); X X /* X * Make a note of whether or not this command was invoked X * by root. This will be used to bypass certain checks X * later on. Also, set the real user ID to match the X * effective user ID. This will prevent the invoker from X * issuing signals which would interfer with this command. X */ X X amroot = getuid () == 0; X setuid (geteuid ()); X Prog = argv[0]; X setbuf (stdout, (char *) 0); X setbuf (stderr, (char *) 0); X X while ((flag = getopt (argc, argv, "a:d:grR")) != EOF) { X switch (flag) { X case 'a': /* add a user */ X aflg++; X user = optarg; X break; X case 'd': /* delete a user */ X dflg++; X user = optarg; X break; X case 'g': /* no-op from normal password */ X break; X case 'r': /* remove group password */ X rflg++; X break; X case 'R': /* restrict group password */ X Rflg++; X break; X default: X usage (); X } X } X X /* X * Make sure exclusive flags are exclusive X */ X X if (aflg + dflg + rflg + Rflg > 1) X usage (); X X /* X * Unless the mode is -a, -d or -r, the input and output must X * both be a tty. The typical keyboard signals are caught X * so the termio modes can be restored. X */ X X if (! aflg && ! dflg && ! rflg && ! Rflg) { X if (! isatty (0) || ! isatty (1)) X exit (1); X X die (0); /* save tty modes */ X X signal (SIGHUP, die); X signal (SIGINT, die); X signal (SIGQUIT, die); X signal (SIGTERM, die); X } X X /* X * Determine the name of the user that invoked this command. X * This is really hit or miss because there are so many ways X * that command can be executed and so many ways to trip up X * the routines that report the user name. X */ X X if ((cp = getlogin ()) && (pw = getpwnam (cp)) && pw->pw_uid == ruid) { X /* need user name */ X (void) strcpy (name, cp); X } else if (pw = getpwuid (ruid)) /* get it from password file */ X strcpy (name, pw->pw_name); X else { /* can't find user name! */ X fprintf (stderr, "Who are you?\n"); X exit (1); X } X if (! (pw = getpwnam (name))) X goto failure; /* can't get my name ... */ X X /* X * Get the name of the group that is being affected. The group X * entry will be completely replicated so it may be modified X * later on. X */ X X if (! (group = argv[optind])) X usage (); X X if (! (gr = getgrnam (group))) { X fprintf (stderr, "unknown group: %s\n", group); X exit (1); X } X grent = *gr; X grent.gr_name = strdup (gr->gr_name); X grent.gr_passwd = strdup (gr->gr_passwd); X X for (i = 0;gr->gr_mem[i];i++) X ; X grent.gr_mem = (char **) malloc ((i + 1) * sizeof (char *)); X for (i = 0;gr->gr_mem[i];i++) X grent.gr_mem[i] = strdup (gr->gr_mem[i]); X grent.gr_mem[i] = (char *) 0; X X /* X * The policy for changing a group is that 1) you must be root X * or 2) you must be the first listed member of the group. The X * first listed member of a group can do anything to that group X * that the root user can. X */ X X if (! amroot) { X if (grent.gr_mem[0] == (char *) 0) X goto failure; X X if (strcmp (grent.gr_mem[0], name) != 0) X goto failure; X } X X /* X * Removing a password is straight forward. Just set the X * password field to a "". X */ X X if (rflg) { X grent.gr_passwd = ""; X goto output; X } else if (Rflg) { X grent.gr_passwd = "!"; X goto output; X } X X /* X * Adding a member to a member list is pretty straightforward X * as well. Call the appropriate routine and split. X */ X X if (aflg) { X if (getpwnam (user) == (struct passwd *) 0) { X fprintf (stderr, "%s: unknown user %s\n", Prog, user); X exit (1); X } X printf ("Adding user %s to group %s\n", user, group); X grent.gr_mem = add_list (grent.gr_mem, user); X goto output; X } X X /* X * Removing a member from the member list is the same deal X * as adding one, except the routine is different. X */ X X if (dflg) { X for (i = 0;grent.gr_mem[i];i++) X if (strcmp (user, grent.gr_mem[i]) == 0) X break; X X if (grent.gr_mem[i] == (char *) 0) { X fprintf (stderr, "%s: unknown member %s\n", Prog, user); X exit (1); X } X printf ("Removing user %s from group %s\n", user, group); X grent.gr_mem = del_list (grent.gr_mem, user); X goto output; X } X X /* X * A new password is to be entered and it must be encrypted, X * etc. The password will be prompted for twice, and both X * entries must be identical. There is no need to validate X * the old password since the invoker is either the group X * owner, or root. X */ X X printf ("Changing the password for group %s\n", group); X X for (retries = 0;retries < RETRIES;retries++) { X if (! (cp = getpass ("New Password:"))) X exit (1); X else X strcpy (pass, cp); X X if (! (cp = getpass ("Re-enter new password:"))) X exit (1); X else X strcpy (pass2, cp); X X if (strcmp (pass, pass2) == 0) X break; X X if (retries + 1 < RETRIES) X puts ("They don't match; try again"); X } X if (retries == RETRIES) { X fprintf (stderr, "%s: Try again later\n", Prog); X exit (1); X } X grent.gr_passwd = pw_encrypt (pass, (char *) 0); X X /* X * This is the common arrival point to output the new group X * file. The freshly crafted entry is in allocated space. X * The group file will be locked and opened for writing. The X * new entry will be output, etc. X */ X Xoutput: X signal (SIGHUP, SIG_IGN); X signal (SIGINT, SIG_IGN); X signal (SIGQUIT, SIG_IGN); X X if (! gr_lock ()) { X fprintf (stderr, "%s: can't get lock\n", Prog); X exit (1); X } X if (! gr_open (O_RDWR)) { X fprintf (stderr, "%s: can't open file\n", Prog); X exit (1); X } X if (! gr_update (&grent)) { X fprintf (stderr, "%s: can't update entry\n", Prog); X exit (1); X } X if (! gr_close ()) { X fprintf (stderr, "%s: can't re-write file\n", Prog); X exit (1); X } X if (! gr_unlock ()) { X fprintf (stderr, "%s: can't unlock file\n", Prog); X exit (1); X } X#ifdef NDBM X if (! gr_dbm_update (&grent)) { X fprintf (stderr, "%s: can't update DBM files\n", Prog); X exit (1); X } X#endif X exit (0); X /*NOTREACHED*/ X Xfailure: X fprintf (stderr, "Permission denied.\n"); X exit (1); X /*NOTREACHED*/ X} X X/* X * die - set or reset termio modes. X * X * die() is called before processing begins. signal() is then X * called with die() as the signal handler. If signal later X * calls die() with a signal number, the terminal modes are X * then reset. X */ X Xvoid die (killed) Xint killed; X{ X#ifdef BSD X static struct sgtty sgtty; X X if (killed) X stty (0, &sgtty); X else X gtty (0, &sgtty); X#else X static struct termio sgtty; X X if (killed) X ioctl (0, TCSETA, &sgtty); X else X ioctl (0, TCGETA, &sgtty); X#endif X if (killed) { X putchar ('\n'); X fflush (stdout); X exit (killed); X } X} SHAR_EOF if test 9448 -ne "`wc -c < 'gpmain.c'`" then echo shar: "error transmitting 'gpmain.c'" '(should have been 9448 characters)' fi fi echo shar: "extracting 'chage.c'" '(15243 characters)' if test -f 'chage.c' then echo shar: "will not over-write existing file 'chage.c'" else sed 's/^X//' << \SHAR_EOF > 'chage.c' X/* X * Copyright 1989, 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include <sys/types.h> X#include <syslog.h> X#include <stdio.h> X#include <fcntl.h> X#include <signal.h> X#include <ctype.h> X#include <time.h> X X#ifndef lint Xstatic char sccsid[] = "%W% %U% %G%"; X#endif X X/* X * Set up some BSD defines so that all the BSD ifdef's are X * kept right here X */ X X#ifndef BSD X#include <string.h> X#include <memory.h> X#define bzero(a,n) memset(a, 0, n) X#else X#include <strings.h> X#define strchr index X#define strrchr rindex X#endif X X#include "config.h" X#include "pwd.h" X#include "shadow.h" X X/* X * Global variables X */ X Xchar *Prog; Xlong mindays; Xlong maxdays; Xlong lastday; Xlong warndays; Xlong inactdays; Xlong expdays; Xvoid cleanup(); X X/* X * External identifiers X */ X Xextern long a64l(); Xextern int pw_lock(), pw_open(), X pw_unlock(), pw_close(), X pw_update(); Xextern struct passwd *pw_locate(); Xextern int spw_lock(), spw_open(), X spw_unlock(), spw_close(), X spw_update(); Xextern struct spwd *spw_locate(); Xextern int optind; Xextern char *optarg; Xextern char *getlogin (); X#ifdef NDBM Xextern int pw_dbm_mode; Xextern int sp_dbm_mode; X#endif X X/* X * Password aging constants X * X * DAY - seconds in a day X * WEEK - seconds in a week X * SCALE - convert from clock to aging units X */ X X#define DAY (24L*3600L) X#define WEEK (7*DAY) X X#ifdef ITI_AGING X#define SCALE (1) X#else X#define SCALE (DAY) X#endif X X/* X * days and juldays are used to compute the number of days in the X * current month, and the cummulative number of days in the preceding X * months. they are declared so that january is 1, not 0. X */ X Xstatic short days[13] = { 0, X 31, 28, 31, 30, 31, 30, /* JAN - JUN */ X 31, 31, 30, 31, 30, 31 }; /* JUL - DEC */ X Xstatic short juldays[13] = { 0, X 0, 31, 59, 90, 120, 151, /* JAN - JUN */ X 181, 212, 243, 273, 304, 334 }; /* JUL - DEC */ X X/* X * #defines for messages. This facilities foreign language conversion X * since all messages are defined right here. X */ X X#define USAGE \ X"Usage: %s [ -l ] [ -m min_days ] [ -M max_days ] [ -W warn ]\n\ X [ -I inactive ] [ -E expire ] [ -d last_day ] user\n" X#define DBMERROR "Error updating the DBM password entry.\n" X#define DBMERROR2 "error updating DBM shadow entry.\n" X X/* X * usage - print command line syntax and exit X */ X Xvoid Xusage () X{ X fprintf (stderr, USAGE, Prog); X exit (1); X} X X/* X * strtoday - compute the number of days since 1970. X * X * the total number of days prior to the current date is X * computed. january 1, 1970 is used as the origin with X * it having a day number of 0. the gmtime() routine is X * used to prevent confusion regarding time zones. X */ X Xlong Xstrtoday (str) Xchar *str; X{ X char slop[2]; X int month; X int day; X int year; X long total; X X /* X * start by separating the month, day and year. this is X * a chauvanistic program - it only takes date input in X * the standard USA format. X */ X X if (sscanf (str, "%d/%d/%d%c", &month, &day, &year, slop) != 3) X return -1; X X /* X * the month, day of the month, and year are checked for X * correctness and the year adjusted so it falls between X * 1970 and 2069. X */ X X if (month < 1 || month > 12) X return -1; X X if (day < 1) X return -1; X X if ((month != 2 || (year % 4) != 0) && day > days[month]) X return -1; X else if ((month == 2 && (year % 4) == 0) && day > 29) X return -1; X X if (year < 0) X return -1; X else if (year < 69) X year += 2000; X else if (year < 99) X year += 1900; X X if (year < 1970 || year > 2069) X return -1; X X /* X * the total number of days is the total number of days in all X * the whole years, plus the number of leap days, plus the X * number of days in the whole months preceding, plus the number X * of days so far in the month. X */ X X total = ((year - 1970) * 365) + (((year + 1) - 1970) / 4); X total += juldays[month] + (month > 2 && (year % 4) == 0 ? 1:0); X total += day - 1; X X return total; X} X X/* X * new_fields - change the user's password aging information interactively. X * X * prompt the user for all of the password age values. set the fields X * from the user's response, or leave alone if nothing was entered. the X * value (-1) is used to indicate the field should be removed if possible. X * any other negative value is an error. very large positive values will X * be handled elsewhere. X */ X Xint Xnew_fields () X{ X char buf[BUFSIZ]; X char *cp; X long value; X struct tm *tp; X X printf ("Enter the new value, or press return for the default\n\n"); X X sprintf (buf, "%ld", mindays); X change_field (buf, "Minimum Password Age"); X if (((mindays = strtol (buf, &cp, 10)) == 0 && *cp) || mindays < -1) X return 0; X X sprintf (buf, "%ld", maxdays); X change_field (buf, "Maximum Password Age"); X if (((maxdays = strtol (buf, &cp, 10)) == 0 && *cp) || maxdays < -1) X return 0; X X value = lastday * SCALE; X tp = gmtime (&value); X sprintf (buf, "%02d/%02d/%02d", X tp->tm_mon + 1, tp->tm_mday, tp->tm_year); X change_field (buf, "Last Password Change (MM/DD/YY)"); X if (strcmp (buf, "12/31/69") == 0) X lastday = -1; X else if ((lastday = strtoday (buf)) == -1) X return 0; X X sprintf (buf, "%ld", warndays); X change_field (buf, "Password Expiration Warning"); X if (((warndays = strtol (buf, &cp, 10)) == 0 && *cp) || warndays < -1) X return 0; X X sprintf (buf, "%ld", inactdays); X change_field (buf, "Password Inactive"); X if (((inactdays = strtol (buf, &cp, 10)) == 0 && *cp) || inactdays < -1) X return 0; X X value = expdays * SCALE; X tp = gmtime (&value); X sprintf (buf, "%02d/%02d/%02d", X tp->tm_mon + 1, tp->tm_mday, tp->tm_year); X change_field (buf, "Account Expiration Date (MM/DD/YY)"); X if (strcmp (buf, "12/31/69") == 0) X expdays = -1; X else if ((expdays = strtoday (buf)) == -1) X return 0; X X return 1; X} X X/* X * list_fields - display the current values of the expiration fields X * X * display the password age information from the password fields. date X * values will be displayed as a calendar date, or the word "Never" if X * the date is 1/1/70, which is day number 0. X */ X Xvoid Xlist_fields () X{ X struct tm *tp; X char *cp; X long changed; X long expires; X X /* X * Start with the easy numbers - the number of days before the X * password can be changed, the number of days after which the X * password must be chaged, the number of days before the X * password expires that the user is told, and the number of X * days after the password expires that the account becomes X * unusable. X */ X X printf ("Minimum:\t%d\n", mindays); X printf ("Maximum:\t%d\n", maxdays); X printf ("Warning:\t%d\n", warndays); X printf ("Inactive:\t%d\n", inactdays); X X /* X * The "last change" date is either "Never" or the date the X * password was last modified. The date is the number of X * days since 1/1/1970. X */ X X printf ("Last Change:\t\t"); X if (changed <= 0) { X printf ("Never\n"); X } else { X changed = lastday * SCALE; X tp = gmtime (&changed); X cp = asctime (tp); X printf ("%6.6s, %4.4s\n", cp + 4, cp + 20); X } X X /* X * The password expiration date is determined from the last X * change date plus the number of days the password is valid X * for. X */ X X printf ("Password Expires:\t"); X if (changed <= 0 || maxdays >= 10000*(DAY/SCALE) || maxdays <= 0) { X printf ("Never\n"); X } else { X expires = changed + maxdays * SCALE; X tp = gmtime (&expires); X cp = asctime (tp); X printf ("%6.6s, %4.4s\n", cp + 4, cp + 20); X } X X /* X * The account becomes inactive if the password is expired X * for more than "inactdays". The expiration date is calculated X * and the number of inactive days is added. The resulting date X * is when the active will be disabled. X */ X X printf ("Password Inactive:\t"); X if (changed <= 0 || inactdays <= 0 || X maxdays >= 10000*(DAY/SCALE) || maxdays <= 0) { X printf ("Never\n"); X } else { X expires = changed + (maxdays + inactdays) * SCALE; X tp = gmtime (&expires); X cp = asctime (tp); X printf ("%6.6s, %4.4s\n", cp + 4, cp + 20); X } X X /* X * The account will expire on the given date regardless of the X * password expiring or not. X */ X X printf ("Account Expires:\t"); X if (expdays <= 0) { X printf ("Never\n"); X } else { X expires = expdays * SCALE; X tp = gmtime (&expires); X cp = asctime (tp); X printf ("%6.6s, %4.4s\n", cp + 4, cp + 20); X } X} X X/* X * chage - change a user's password aging information X * X * This command controls the password aging information. X * X * The valid options are X * X * -m minimum number of days before password change (*) X * -M maximim number of days before password change (*) X * -d last password change date (*) X * -l last password change date X * -W expiration warning days (*) X * -I password inactive after expiration (*) X * -E account expiration date (*) X * X * (*) requires root permission to execute. X * X * All of the time fields are entered in the internal format X * which is either seconds or days. X */ X Xint Xmain (argc, argv) Xint argc; Xchar **argv; X{ X int flag; X int lflg; X int mflg; X int Mflg; X int dflg; X int Wflg; X int Iflg; X int Eflg; X int ruid = getuid (); X struct passwd *pw; X struct passwd pwent; X struct spwd *sp; X struct spwd spwd; X char name[BUFSIZ]; X X /* X * Get the program name so that error messages can use it. X */ X X if (Prog = strrchr (argv[0], '/')) X Prog++; X else X Prog = argv[0]; X X openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH); X#ifdef NDBM X sp_dbm_mode = O_RDWR; X pw_dbm_mode = O_RDWR; X#endif X X /* X * Parse the flags. The difference between password file X * formats includes the number of fields, and whether the X * dates are entered as days or weeks. Shadow password X * file info =must= be entered in days, while regular X * password file info =must= be entered in weeks. X */ X X while ((flag = getopt (argc, argv, "lm:M:W:I:E:d:")) != EOF) { X switch (flag) { X case 'l': X lflg++; X break; X case 'm': X mflg++; X mindays = strtol (optarg, 0, 10); X break; X case 'M': X Mflg++; X maxdays = strtol (optarg, 0, 10); X break; X case 'd': X dflg++; X lastday = strtol (optarg, 0, 10); X break; X case 'W': X Wflg++; X warndays = strtol (optarg, 0, 10); X break; X case 'I': X Iflg++; X inactdays = strtol (optarg, 0, 10); X break; X case 'E': X Eflg++; X expdays = strtol (optarg, 0, 10); X break; X default: X usage (); X } X } X X /* X * Make certain the flags do not conflict and that there is X * a user name on the command line. X */ X X if (argc != optind + 1) X usage (); X X if (lflg && (mflg || Mflg || dflg || Wflg || Iflg || Eflg)) { X fprintf (stderr, "%s: do not include \"l\" with other flags\n", X Prog); X usage (); X } X X /* X * An unprivileged user can ask for their own aging information, X * but only root can change it, or list another user's aging X * information. X */ X X if (ruid != 0 && ! lflg) { X fprintf (stderr, "%s: permission denied\n", Prog); X exit (1); X } X X /* X * Lock and open the password file. This loads all of the X * password file entries into memory. Then we get a pointer X * to the password file entry for the requested user. X */ X X if (! pw_lock ()) { X fprintf (stderr, "%s: can't lock password file\n", Prog); X exit (1); X } X if (! pw_open (ruid != 0 || lflg ? O_RDONLY:O_RDWR)) { X fprintf (stderr, "%s: can't open password file\n", Prog); X cleanup (1); X exit (1); X } X if (! (pw = pw_locate (argv[optind]))) { X fprintf (stderr, "%s: unknown user: %s\n", Prog, argv[optind]); X cleanup (1); X exit (1); X } X X /* X * For shadow password files we have to lock the file and X * read in the entries as was done for the password file. X * The user entries does not have to exist in this case; X * a new entry will be created for this user if one does X * not exist already. X */ X X if (! spw_lock ()) { X fprintf (stderr, "%s: can't lock shadow file\n", Prog); X cleanup (1); X exit (1); X } X if (! spw_open ((ruid != 0 || lflg) ? O_RDONLY:O_RDWR)) { X fprintf (stderr, "%s: can't open shadow file\n", Prog); X cleanup (2); X exit (1); X } X if (sp = spw_locate (argv[optind])) X spwd = *sp; X X strcpy (name, pw->pw_name); X pwent = *pw; X X /* X * Set the fields that aren't being set from the command line X * from the password file. X */ X X if (sp) { X if (! Mflg) X maxdays = spwd.sp_max; X if (! mflg) X mindays = spwd.sp_min; X if (! dflg) X lastday = spwd.sp_lstchg; X if (! Wflg) X warndays = spwd.sp_warn; X if (! Iflg) X inactdays = spwd.sp_inact; X if (! Eflg) X expdays = spwd.sp_expire; X } else X#ifdef ATT_AGE X { X if (pwent.pw_age && strlen (pwent.pw_age) >= 2) { X if (! Mflg) X maxdays = c64i (pwent.pw_age[0]) * (WEEK/SCALE); X if (! mflg) X mindays = c64i (pwent.pw_age[1]) * (WEEK/SCALE); X if (! dflg && strlen (pwent.pw_age) == 4) X lastday = a64l (pwent.pw_age+2) * (WEEK/SCALE); X } else { X mindays = 0; X maxdays = 10000L * (DAY/SCALE); X lastday = -1; X } X warndays = inactdays = expdays = -1; X } X#endif X X /* X * Print out the expiration fields if the user has X * requested the list option. X */ X X if (lflg) { X if (ruid != 0 && ruid != pw->pw_uid) { X fprintf (stderr, "%s: permission denied\n", Prog); X exit (1); X } X list_fields (); X cleanup (2); X exit (0); X } X X /* X * If none of the fields were changed from the command line, X * let the user interactively change them. X */ X X if (! mflg && ! Mflg && ! dflg && ! Wflg && ! Iflg && ! Eflg) { X printf ("Changing the aging information for %s\n", name); X if (! new_fields ()) { X fprintf (stderr, "%s: error changing fields\n", Prog); X cleanup (2); X exit (1); X } X } X X /* X * There was no shadow entry. The new entry will have the X * encrypted password transferred from the normal password X * file along with the aging information. X */ X X if (sp == 0) { X sp = &spwd; X bzero (&spwd, sizeof spwd); X X sp->sp_namp = pw->pw_name; X sp->sp_pwdp = pw->pw_passwd; X sp->sp_flag = -1; X X pwent.pw_passwd = "!"; X#ifdef ATT_AGE X pwent.pw_age = ""; X#endif X if (! pw_update (&pwent)) { X fprintf (stderr, "%s: can't update password file\n", X Prog); X cleanup (2); X exit (1); X } X#if defined(DBM) || defined(NDBM) X (void) pw_dbm_update (&pwent); X#endif X } X X /* X * Copy the fields back to the shadow file entry and X * write the modified entry back to the shadow file. X * Closing the shadow and password files will commit X * any changes that have been made. X */ X X sp->sp_max = maxdays; X sp->sp_min = mindays; X sp->sp_lstchg = lastday; X sp->sp_warn = warndays; X sp->sp_inact = inactdays; X sp->sp_expire = expdays; X X if (! spw_update (sp)) { X fprintf (stderr, "%s: can't update shadow file\n", Prog); X cleanup (2); X exit (1); X } X#ifdef NDBM X if (access ("/etc/shadow.pag", 0) == 0 && ! sp_dbm_update (sp)) { X fprintf (stderr, DBMERROR); X syslog (LOG_ERR, DBMERROR2); X (void) spw_unlock (); X exit (1); X } X#endif /* NDBM */ X if (! spw_close ()) { X fprintf (stderr, "%s: can't rewrite shadow file\n", Prog); X cleanup (2); X exit (1); X } X (void) pw_close (); X cleanup (2); X exit (0); X /*NOTREACHED*/ X} X X/* X * cleanup - unlock any locked password files X */ X Xvoid Xcleanup (state) Xint state; X{ X switch (state) { X case 2: X spw_unlock (); X case 1: X pw_unlock (); X case 0: X break; X } X} SHAR_EOF if test 15243 -ne "`wc -c < 'chage.c'`" then echo shar: "error transmitting 'chage.c'" '(should have been 15243 characters)' fi fi echo shar: "extracting 'pwent.c'" '(9715 characters)' if test -f 'pwent.c' then echo shar: "will not over-write existing file 'pwent.c'" else sed 's/^X//' << \SHAR_EOF > 'pwent.c' X/* X * Copyright 1989, 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include <stdio.h> X#include "pwd.h" X#ifdef BSD X#include <strings.h> X#define strchr index X#define strrchr rindex X#else X#include <string.h> X#endif X#include "config.h" X X/* X * If AUTOSHADOW is enable, the getpwnam and getpwuid calls will X * fill in the pw_passwd and pw_age fields from the passwd and X * shadow files. X */ X X#if defined(AUTOSHADOW) && !defined(SHADOWPWD) X#undef AUTOSHADOW X#endif X#ifdef AUTOSHADOW X#include "shadow.h" X#endif X X/* X * If DBM or NDBM is enabled, the getpwnam and getpwuid calls will X * go to the database files to look for the requested entries. X */ X X#ifdef DBM X#include <dbm.h> X#endif X#ifdef NDBM X#include <ndbm.h> X#include <fcntl.h> XDBM *pw_dbm; Xint pw_dbm_mode = -1; X#endif X X/* X * ITI-style aging uses time_t's as the time fields, while X * AT&T-style aging uses long numbers of days. X */ X X#ifdef ITI_AGING X#define WEEK (7L*24L*3600L) X#else X#define WEEK 7 X#endif X X#ifndef lint Xstatic char sccsid[] = "@(#)pwent.c 3.5 12:53:57 12/19/90"; X#endif X X#define SBUFSIZ 64 X#define NFIELDS 7 X Xstatic FILE *pwdfp; Xstatic char pwdbuf[BUFSIZ]; Xstatic char *pwdfile = PWDFILE; X#if defined(DBM) || defined(NDBM) Xstatic int dbmopened; Xstatic int dbmerror; X#endif Xstatic char *pwdfields[NFIELDS]; Xstatic struct passwd pwent; X X#if defined(AUTOSHADOW) && defined(ATT_AGE) X/* X * sptopwage - convert shadow ages to AT&T-style pw_age ages X * X * sptopwage() converts the values in the shadow password X * entry to the format used in the old-style password X * entry. X */ X Xstatic char * Xsptopwage (spwd) Xstruct spwd *spwd; X{ X static char age[5]; X long min; X long max; X long last; X X if ((min = (spwd->sp_min / WEEK)) < 0) X min = 0; X else if (min >= 64) X min = 63; X X if ((max = (spwd->sp_max / WEEK)) < 0) X max = 0; X else if (max >= 64) X max = 63; X X if ((last = (spwd->sp_lstchg / WEEK)) < 0) X last = 0; X else if (last >= 4096) X last = 4095; X X age[0] = i64c (max); X age[1] = i64c (min); X age[2] = i64c (last % 64); X age[3] = i64c (last / 64); X age[4] = '\0'; X return age; X} X#endif X X/* X * sgetpwent - convert a string to a (struct passwd) X * X * sgetpwent() parses a string into the parts required for a password X * structure. Strict checking is made for the UID and GID fields and X * presence of the correct number of colons. Any failing tests result X * in a NULL pointer being returned. X */ X Xstruct passwd * Xsgetpwent (buf) Xchar *buf; X{ X int i; X char *cp; X X /* X * Copy the string to a static buffer so the pointers into X * the password structure remain valid. X */ X X strncpy (pwdbuf, buf, BUFSIZ); X pwdbuf[BUFSIZ-1] = '\0'; X X /* X * Save a pointer to the start of each colon separated X * field. The fields are converted into NUL terminated strings. X */ X X for (cp = pwdbuf, i = 0;i < NFIELDS && cp;i++) { X pwdfields[i] = cp; X if (cp = strchr (cp, ':')) X *cp++ = 0; X } X X /* X * There must be exactly NFIELDS colon separated fields or X * the entry is invalid. Also, the UID and GID must be non-blank. X */ X X if (i != NFIELDS || *pwdfields[2] == '\0' || *pwdfields[3] == '\0') X return 0; X X /* X * Each of the fields is converted the appropriate data type X * and the result assigned to the password structure. If the X * UID or GID does not convert to an integer value, a NULL X * pointer is returned. X */ X X pwent.pw_name = pwdfields[0]; X pwent.pw_passwd = pwdfields[1]; X if ((pwent.pw_uid = strtol (pwdfields[2], &cp, 10)) == 0 && *cp) X return 0; X X if ((pwent.pw_gid = strtol (pwdfields[3], &cp, 10)) == 0 && *cp) X return 0; X#ifdef ATT_AGE X if (cp = strchr (pwent.pw_passwd, ',')) { X pwent.pw_age = cp + 1; X *cp = '\0'; X } else X pwent.pw_age = ""; X#endif X pwent.pw_gecos = pwdfields[4]; X#ifdef ATT_COMMENT X pwent.pw_comment = ""; X#endif X pwent.pw_dir = pwdfields[5]; X pwent.pw_shell = pwdfields[6]; X X return (&pwent); X} X X/* X * fgetpwent - get a password file entry from a stream X * X * fgetpwent() reads the next line from a password file formatted stream X * and returns a pointer to the password structure for that line. X */ X Xstruct passwd * Xfgetpwent (fp) XFILE *fp; X{ X char buf[BUFSIZ]; X X while (fgets (buf, BUFSIZ, fp) != (char *) 0) { X buf[strlen (buf) - 1] = '\0'; X return (sgetpwent (buf)); X } X return 0; X} X X/* X * endpwent - close a password file X * X * endpwent() closes the password file if open. if autoshadowing is X * enabled the system must also end access to the shadow files since X * the user is probably unaware it was ever accessed. X */ X Xint Xendpwent () X{ X if (pwdfp) X if (fclose (pwdfp)) X return -1; X X pwdfp = 0; X#ifdef NDBM X if (dbmopened && pw_dbm) { X dbm_close (pw_dbm); X dbmopened = 0; X dbmerror = 0; X pw_dbm = 0; X } X#endif X#ifdef AUTOSHADOW X endspent (); X#endif X return 0; X} X X/* X * getpwent - get a password entry from the password file X * X * getpwent() opens the password file, if not already opened, and reads X * a single entry. NULL is returned if any errors are encountered reading X * the password file. X */ X Xstruct passwd * Xgetpwent () X{ X if (! pwdfp && setpwent ()) X return 0; X X return fgetpwent (pwdfp); X} X X/* X * getpwuid - locate the password entry for a given UID X * X * getpwuid() locates the first password file entry for the given UID. X * If there is a valid DBM file, the DBM files are queried first for X * the entry. Otherwise, a linear search is begun of the password file X * searching for an entry which matches the provided UID. X */ X Xstruct passwd * Xgetpwuid (uid) Xint uid; X{ X struct passwd *pwd; X#if defined(DBM) || defined(NDBM) X datum key; X datum content; X#endif X#ifdef AUTOSHADOW X struct spwd *spwd; X#endif X X if (setpwent ()) X return 0; X X#if defined(DBM) || defined(NDBM) X X /* X * If the DBM file are now open, create a key for this UID and X * try to fetch the entry from the database. A matching record X * will be unpacked into a static structure and returned to X * the user. X */ X X if (dbmopened) { X pwent.pw_uid = uid; X key.dsize = sizeof pwent.pw_uid; X key.dptr = (char *) &pwent.pw_uid; X#ifdef DBM X content = fetch (key); X#endif X#ifdef NDBM X content = dbm_fetch (pw_dbm, key); X#endif X if (content.dptr != 0) { X memcpy (pwdbuf, content.dptr, content.dsize); X pw_unpack (pwdbuf, content.dsize, &pwent); X#ifdef AUTOSHADOW X if (spwd = getspnam (pwent.pw_name)) { X pwent.pw_passwd = spwd->sp_pwdp; X#ifdef ATT_AGE X pwent.pw_age = sptopwage (spwd); X#endif X } X#endif X return &pwent; X } X } X#endif X /* X * Search for an entry which matches the UID. Return the X * entry when a match is found. X */ X X while (pwd = getpwent ()) X if (pwd->pw_uid == uid) X break; X X#ifdef AUTOSHADOW X if (pwd && (spwd = getspnam (pwd->pw_name))) { X pwd->pw_passwd = spwd->sp_pwdp; X#ifdef ATT_AGE X pwd->pw_age = sptopwage (spwd); X#endif X } X#endif X return pwd; X} X X/* X * getpwnam - locate the password entry for a given name X * X * getpwnam() locates the first password file entry for the given name. X * If there is a valid DBM file, the DBM files are queried first for X * the entry. Otherwise, a linear search is begun of the password file X * searching for an entry which matches the provided name. X */ X Xstruct passwd * Xgetpwnam (name) Xchar *name; X{ X struct passwd *pwd; X#if defined(DBM) || defined(NDBM) X datum key; X datum content; X#endif X#ifdef AUTOSHADOW X struct spwd *spwd; X#endif X X if (setpwent ()) X return 0; X X#if defined(DBM) || defined(NDBM) X X /* X * If the DBM file are now open, create a key for this UID and X * try to fetch the entry from the database. A matching record X * will be unpacked into a static structure and returned to X * the user. X */ X X if (dbmopened) { X key.dsize = strlen (name); X key.dptr = name; X#ifdef DBM X content = fetch (key); X#endif X#ifdef NDBM X content = dbm_fetch (pw_dbm, key); X#endif X if (content.dptr != 0) { X memcpy (pwdbuf, content.dptr, content.dsize); X pw_unpack (pwdbuf, content.dsize, &pwent); X#ifdef AUTOSHADOW X if (spwd = getspnam (pwent.pw_name)) { X pwent.pw_passwd = spwd->sp_pwdp; X#ifdef ATT_AGE X pwent.pw_age = sptopwage (spwd); X#endif X } X#endif X return &pwent; X } X } X#endif X /* X * Search for an entry which matches the name. Return the X * entry when a match is found. X */ X X while (pwd = getpwent ()) X if (strcmp (pwd->pw_name, name) == 0) X break; X X#ifdef AUTOSHADOW X if (pwd && (spwd = getspnam (pwd->pw_name))) { X pwd->pw_passwd = spwd->sp_pwdp; X#ifdef ATT_AGE X pwd->pw_age = sptopwage (spwd); X#endif X } X#endif X return pwd; X} X X/* X * setpwent - open the password file X * X * setpwent() opens the system password file, and the DBM password files X * if they are present. The system password file is rewound if it was X * open already. X */ X Xint Xsetpwent () X{ X#ifdef NDBM X int mode; X#endif X X if (! pwdfp) { X if (! (pwdfp = fopen (pwdfile, "r"))) X return -1; X } else { X if (fseek (pwdfp, 0L, 0) != 0) X return -1; X } X X /* X * Attempt to open the DBM files if they have never been opened X * and an error has never been returned. X */ X X#if defined (DBM) || defined (NDBM) X if (! dbmerror && ! dbmopened) { X char dbmfiles[BUFSIZ]; X X strcpy (dbmfiles, pwdfile); X strcat (dbmfiles, ".pag"); X#ifdef NDBM X if (pw_dbm_mode == -1) X mode = O_RDONLY; X else X mode = (pw_dbm_mode == O_RDONLY || X pw_dbm_mode == O_RDWR) ? pw_dbm_mode:O_RDONLY; X#endif X#ifdef DBM X if (access (dbmfiles, 0) || dbminit (pwdfile)) X#endif X#ifdef NDBM X if (access (dbmfiles, 0) || X (! (pw_dbm = dbm_open (pwdfile, mode, 0)))) X#endif X dbmerror = 1; X else X dbmopened = 1; X } X#endif X return 0; X} SHAR_EOF if test 9715 -ne "`wc -c < 'pwent.c'`" then echo shar: "error transmitting 'pwent.c'" '(should have been 9715 characters)' fi fi echo shar: "extracting 'valid.c'" '(2336 characters)' if test -f 'valid.c' then echo shar: "will not over-write existing file 'valid.c'" else sed 's/^X//' << \SHAR_EOF > 'valid.c' X/* X * Copyright 1989, 1990, 1991, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include <stdio.h> X#include "pwd.h" X#ifdef BSD X#include <strings.h> X#define strchr index X#define strrchr rindex X#else X#include <string.h> X#include <memory.h> X#endif X#include "config.h" X X#ifndef lint Xstatic char _sccsid[] = "@(#)valid.c 3.3 08:00:20 2/6/91"; X#endif X X/* X * valid - compare encrypted passwords X * X * Valid() compares the DES encrypted password from the password file X * against the password which the user has entered after it has been X * encrypted using the same salt as the original. Entries which do X * not have a password file entry have a NULL pw_name field and this X * is used to indicate that a dummy salt must be used to encrypt the X * password anyway. X */ X Xint valid (password, entry) Xchar *password; Xstruct passwd *entry; X{ X char *encrypt; X char *salt; X char *pw_encrypt (); X char *shell; X X /* X * Start with blank or empty password entries. Always encrypt X * a password if no such user exists. Only if the ID exists and X * the password is really empty do you return quickly. This X * routine is meant to waste CPU time. X */ X X if (entry->pw_name && ! entry->pw_passwd[0]) { X if (! password[0]) X return (1); /* user entered nothing */ X else X return (0); /* user entered something! */ X } X X /* X * If there is no entry then we need a salt to use. X */ X X if (entry->pw_name == (char *) 0 || entry->pw_passwd[0] == '\0') X salt = "xx"; X else X salt = entry->pw_passwd; X X /* X * Now, perform the encryption using the salt from before on X * the users input. Since we always encrypt the string, it X * should be very difficult to determine if the user exists by X * looking at execution time. X */ X X encrypt = pw_encrypt (password, salt); X X /* X * One last time we must deal with there being no password file X * entry for the user. We use the pw_passwd == NULL idiom to X * cause non-existent users to not be validated. X */ X X if (entry->pw_name && strcmp (encrypt, entry->pw_passwd) == 0) X return (1); X else X return (0); X} SHAR_EOF if test 2336 -ne "`wc -c < 'valid.c'`" then echo shar: "error transmitting 'valid.c'" '(should have been 2336 characters)' fi fi echo shar: "extracting 'setup.c'" '(3560 characters)' if test -f 'setup.c' then echo shar: "will not over-write existing file 'setup.c'" else sed 's/^X//' << \SHAR_EOF > 'setup.c' X/* X * Copyright 1989, 1990, 1991, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include <sys/types.h> X#include <stdio.h> X#include <utmp.h> X#include <syslog.h> X X#ifdef BSD X#include <strings.h> X#define strchr index X#else X#include <string.h> X#include <memory.h> X#endif X X#include "config.h" X#include "pwd.h" X X#ifndef lint Xstatic char sccsid[] = "@(#)setup.c 3.3 07:46:41 2/6/91"; X#endif X X#ifndef PATH X#define PATH "PATH=/bin:/usr/bin" X#endif X X#ifndef SUPATH X#define SUPATH "PATH=/bin:/usr/bin:/etc" X#endif X X#ifndef MAILDIR X#define MAILDIR "/usr/spool/mail" X#endif X X#ifndef TTYPERM X#define TTYPERM 0622 X#endif X X#ifndef SU Xextern struct utmp utent; X#endif X X#ifdef QUOTAS Xlong strtol (); X#ifdef ULIMIT Xlong ulimit (); X#endif X#endif X Xvoid addenv (); X X/* X * setup - initialize login environment X * X * setup() performs the following steps - X * X * set the login tty to be owned by the new user ID with TTYPERM modes X * change to the user's home directory X * set the process nice, ulimit, and umask from the password file entry X * set the group ID to the value from the password file entry X * set the user ID to the value from the password file entry X * set the HOME, SHELL, MAIL, PATH, and LOGNAME environmental variables X */ X Xvoid setup (info) Xstruct passwd *info; X{ X extern int errno; X char buf[BUFSIZ]; X#ifndef SU X char tty[30]; X#endif X char *cp; X int i; X long l; X X#ifndef SU X (void) strcat (strcpy (tty, "/dev/"), utent.ut_line); X if (chown (tty, info->pw_uid, info->pw_gid) || chmod (tty, TTYPERM)) { X (void) sprintf (buf, "Unable to change tty %s", tty); X syslog (LOG_WARN, "unable to change tty `%s' for user `%s'", X tty, info->pw_name); X perror (buf); X exit (errno); X } X#endif X if (chdir (info->pw_dir) == -1) { X (void) sprintf (buf, "Unable to cd to \"%s\"", info->pw_dir); X syslog (LOG_WARN, "unable to cd to `%s' for user `%s'", X info->pw_dir, info->pw_name); X perror (buf); X exit (errno); X } X#ifdef QUOTAS X for (cp = info->pw_gecos;cp != (char *) 0;cp = strchr (cp, ',')) { X if (*cp == ',') X cp++; X X if (strncmp (cp, "pri=", 4) == 0) { X i = atoi (cp + 4); X if (i >= -20 && i <= 20) X (void) nice (i); X X continue; X } X#ifdef ULIMIT X if (strncmp (cp, "ulimit=", 7) == 0) { X l = strtol (cp + 7, (char **) 0, 10); X (void) ulimit (2, l); X X continue; X } X#endif X if (strncmp (cp, "umask=", 6) == 0) { X i = strtol (cp + 6, (char **) 0, 8) & 0777; X (void) umask (i); X X continue; X } X } X#endif X if (setgid (info->pw_gid) == -1) { X puts ("Bad group id"); X syslog (LOG_WARN, "bad group ID `%d' for user `%s'", X info->pw_gid, info->pw_name); X exit (errno); X } X#ifndef BSD X if (setuid (info->pw_uid)) X#else X if (setreuid (info->pw_uid, info->pw_uid)) X#endif X { X puts ("Bad user id"); X syslog (LOG_WARN, "bad user ID `%d' for user `%s'", X info->pw_uid, info->pw_name); X exit (errno); X } X (void) strcat (strcpy (buf, "HOME="), info->pw_dir); X addenv (buf); X X if (info->pw_shell == (char *) 0) X info->pw_shell = "/bin/sh"; X X (void) strcat (strcpy (buf, "SHELL="), info->pw_shell); X addenv (buf); X X if (info->pw_uid == 0) X addenv (SUPATH); X else X addenv (PATH); X X (void) strcat (strcpy (buf, "LOGNAME="), info->pw_name); X addenv (buf); X X (void) strcat (strcat (strcpy (buf, "MAIL="), MAILDIR), info->pw_name); X addenv (buf); X} SHAR_EOF if test 3560 -ne "`wc -c < 'setup.c'`" then echo shar: "error transmitting 'setup.c'" '(should have been 3560 characters)' fi fi echo shar: "extracting 'entry.c'" '(1946 characters)' if test -f 'entry.c' then echo shar: "will not over-write existing file 'entry.c'" else sed 's/^X//' << \SHAR_EOF > 'entry.c' X/* X * Copyright 1989, 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include "pwd.h" X#ifndef BSD X#include <string.h> X#else X#include <strings.h> X#define strchr index X#define strrchr rindex X#endif X#include "config.h" X#ifdef SHADOWPWD X#include "shadow.h" X#endif X X#ifndef lint Xstatic char sccsid[] = "@(#)entry.c 3.2 12:30:39 12/12/90"; X#endif X Xstruct passwd *fgetpwent (); X Xvoid entry (name, pwent) Xchar *name; Xstruct passwd *pwent; X{ X struct passwd *passwd; X#ifdef SHADOWPWD X struct spwd *spwd; X char *l64a (); X#endif X char *cp; X X if (! (passwd = getpwnam (name))) { X pwent->pw_name = (char *) 0; X return; X } else { X pwent->pw_name = strdup (passwd->pw_name); X pwent->pw_uid = passwd->pw_uid; X pwent->pw_gid = passwd->pw_gid; X#ifdef ATT_COMMENT X pwent->pw_comment = strdup (passwd->pw_comment); X#endif X pwent->pw_gecos = strdup (passwd->pw_gecos); X pwent->pw_dir = strdup (passwd->pw_dir); X pwent->pw_shell = strdup (passwd->pw_shell); X#if defined(SHADOWPWD) && !defined(AUTOSHADOW) X setspent (); X if (spwd = getspnam (name)) { X pwent->pw_passwd = strdup (spwd->sp_pwdp); X#ifdef ATT_AGE X pwent->pw_age = malloc (5); X X if (spwd->sp_max > (63*7)) X spwd->sp_max = (63*7); X if (spwd->sp_min > (63*7)) X spwd->sp_min = (63*7); X X pwent->pw_age[0] = i64c (spwd->sp_max / 7); X pwent->pw_age[1] = i64c (spwd->sp_min / 7); X X cp = l64a (spwd->sp_lstchg / 7); X pwent->pw_age[2] = cp[0]; X pwent->pw_age[3] = cp[1]; X X pwent->pw_age[4] = '\0'; X#endif X endspent (); X return; X } X endspent (); X#endif X pwent->pw_passwd = strdup (passwd->pw_passwd); X#ifdef ATT_AGE X pwent->pw_age = strdup (passwd->pw_age); X#endif X } X} SHAR_EOF if test 1946 -ne "`wc -c < 'entry.c'`" then echo shar: "error transmitting 'entry.c'" '(should have been 1946 characters)' fi fi echo shar: "extracting 'ttytype.c'" '(1125 characters)' if test -f 'ttytype.c' then echo shar: "will not over-write existing file 'ttytype.c'" else sed 's/^X//' << \SHAR_EOF > 'ttytype.c' X/* X * Copyright 1989, 1990, John F. Haugh II X * All rights reserved. X * X * Use, duplication, and disclosure prohibited without X * the express written permission of the author. X */ X X#include <stdio.h> X#ifndef BSD X#include <string.h> X#include <memory.h> X#else X#include <strings.h> X#define strchr index X#define strrchr rindex X#endif X#include "config.h" X X#ifdef TTYTYPE X#ifndef lint Xstatic char _sccsid[] = "@(#)ttytype.c 2.2 19:24:24 7/29/90"; X#endif X X/* X * ttytype - set ttytype from port to terminal type mapping database X */ X Xvoid ttytype (line) Xchar *line; X{ X FILE *fp; X char buf[BUFSIZ]; X char termvar[BUFSIZ]; X char *cp; X char *type; X char *port; X char *getenv (); X X if (getenv ("TERM")) X return; X X if (! (fp = fopen (TTYTYPE, "r"))) X return; X X while (fgets (buf, BUFSIZ, fp)) { X if (buf[0] == '#') X continue; X X if (cp = strchr (buf, '\n')) X *cp = '\0'; X X if ((type = strtok (buf, " \t")) X && (port = strtok ((char *) 0, " \t"))) { X if (strcmp (line, port) == 0) X break; X } X } X if (! feof (fp) && ! ferror (fp)) { X strcat (strcpy (termvar, "TERM="), type); X addenv (termvar); X } X fclose (fp); X} X#endif SHAR_EOF if test 1125 -ne "`wc -c < 'ttytype.c'`" then echo shar: "error transmitting 'ttytype.c'" '(should have been 1125 characters)' fi fi echo shar: "extracting 'port.h'" '(1743 characters)' if test -f 'port.h' then echo shar: "will not over-write existing file 'port.h'" else sed 's/^X//' << \SHAR_EOF > 'port.h' X/* X * Copyright 1989, 1990, 1991, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X/* X * port.h - structure of /etc/porttime X * X * @(#)port.h 3.1 08:59:36 2/8/91 X * X * Each entry in /etc/porttime consists of a TTY device X * name or "*" to indicate all TTY devices, followed by X * a list of 1 or more user IDs or "*" to indicate all X * user names, followed by a list of zero or more valid X * login times. Login time entries consist of zero or X * more day names (Su, Mo, Tu, We, Th, Fr, Sa, Wk, Al) X * followed by a pair of time values in HHMM format X * separated by a "-". X */ X X/* X * PORTS - Name of system port access time file. X * PORT_IDS - Allowable number of IDs per entry. X * PORT_TTY - Allowable number of TTYs per entry. X * PORT_TIMES - Allowable number of time entries per entry. X * PORT_DAY - Day of the week to a bit value (0 = Sunday). X */ X X#define PORTS "/etc/porttime" X#define PORT_IDS 64 X#define PORT_TTY 64 X#define PORT_TIMES 24 X#define PORT_DAY(day) (1<<(day)) X X/* X * pt_names - pointer to array of device names in /dev/ X * pt_users - pointer to array of applicable user IDs. X * pt_times - pointer to list of allowable time periods. X */ X Xstruct port { X char **pt_names; X char **pt_users; X struct pt_time *pt_times; X}; X X/* X * t_days - bit array for each day of the week (0 = Sunday) X * t_start - starting time for this entry X * t_end - ending time for this entry X */ X Xstruct pt_time { X short t_days; X short t_start; X short t_end; X}; SHAR_EOF if test 1743 -ne "`wc -c < 'port.h'`" then echo shar: "error transmitting 'port.h'" '(should have been 1743 characters)' fi fi exit 0 # End of shell archive -- John F. Haugh II | Distribution to | UUCP: ...!cs.utexas.edu!rpp386!jfh Ma Bell: (512) 255-8251 | GEnie PROHIBITED :-) | Domain: jfh@rpp386.cactus.org "If liberals interpreted the 2nd Amendment the same way they interpret the rest of the Constitution, gun ownership would be mandatory."
jfh@rpp386.cactus.org (John F Haugh II) (05/16/91)
#! /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: # pwio.c # encrypt.c # chpasswd.c # newusers.c # rad64.c # dialchk.c # faillog.h # pwdbm.c # grdbm.c # gshadow.c # sppack.c # This archive created: Sun Mar 3 13:27:28 1991 # By: John F Haugh II (River Parishes Programming, Austin TX) export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'pwio.c'" '(11009 characters)' if test -f 'pwio.c' then echo shar: "will not over-write existing file 'pwio.c'" else sed 's/^X//' << \SHAR_EOF > 'pwio.c' X/* X * Copyright 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X * X * This file implements a transaction oriented password database X * library. The password file is updated one entry at a time. X * After each transaction the file must be logically closed and X * transferred to the existing password file. The sequence of X * events is X * X * pw_lock -- lock password file X * pw_open -- logically open password file X * while transaction to process X * pw_(locate,update,remove) -- perform transaction X * done X * pw_close -- commit transactions X * pw_unlock -- remove password lock X */ X X#include <sys/stat.h> X#include <fcntl.h> X#include <errno.h> X#include "pwd.h" X#include <stdio.h> X X#ifndef lint Xstatic char sccsid[] = "@(#)pwio.c 3.6 12:31:19 12/12/90"; X#endif X Xstatic int islocked; Xstatic int isopen; Xstatic int open_modes; Xstatic FILE *pwfp; X Xstruct pw_file_entry { X char *pwf_line; X int pwf_changed; X struct passwd *pwf_entry; X struct pw_file_entry *pwf_next; X}; X Xstatic struct pw_file_entry *pwf_head; Xstatic struct pw_file_entry *pwf_tail; Xstatic struct pw_file_entry *pwf_cursor; Xstatic int pw_changed; Xstatic int lock_pid; X X#define PW_LOCK "/etc/passwd.lock" X#define PW_TEMP "/etc/pwd.%d" X#define PASSWD "/etc/passwd" X Xstatic char pw_filename[BUFSIZ] = PASSWD; X Xextern char *strdup(); Xextern struct passwd *sgetpwent(); X X/* X * pw_dup - duplicate a password file entry X * X * pw_dup() accepts a pointer to a password file entry and X * returns a pointer to a password file entry in allocated X * memory. X */ X Xstatic struct passwd * Xpw_dup (pwent) Xstruct passwd *pwent; X{ X struct passwd *pw; X X if (! (pw = (struct passwd *) malloc (sizeof *pw))) X return 0; X X if ((pw->pw_name = strdup (pwent->pw_name)) == 0 || X (pw->pw_passwd = strdup (pwent->pw_passwd)) == 0 || X#ifdef ATT_AGE X (pw->pw_age = strdup (pwent->pw_age)) == 0 || X#endif /* ATT_AGE */ X#ifdef ATT_COMMENT X (pw->pw_comment = strdup (pwent->pw_comment)) == 0 || X#endif /* ATT_COMMENT */ X (pw->pw_gecos = strdup (pwent->pw_gecos)) == 0 || X (pw->pw_dir = strdup (pwent->pw_dir)) == 0 || X (pw->pw_shell = strdup (pwent->pw_shell)) == 0) X return 0; X X pw->pw_uid = pwent->pw_uid; X pw->pw_gid = pwent->pw_gid; X X return pw; X} X X/* X * pw_free - free a dynamically allocated password file entry X * X * pw_free() frees up the memory which was allocated for the X * pointed to entry. X */ X Xstatic void Xpw_free (pwent) Xstruct passwd *pwent; X{ X free (pwent->pw_name); X free (pwent->pw_passwd); X free (pwent->pw_gecos); X free (pwent->pw_dir); X free (pwent->pw_shell); X} X X/* X * pw_name - change the name of the password file X */ X Xint Xpw_name (name) Xchar *name; X{ X if (isopen || strlen (name) > (BUFSIZ-10)) X return -1; X X strcpy (pw_filename, name); X return 0; X} X X/* X * pw_lock - lock a password file X * X * pw_lock() encapsulates the lock operation. it returns X * TRUE or FALSE depending on the password file being X * properly locked. the lock is set by creating a semaphore X * file, PW_LOCK. X */ X Xint Xpw_lock () X{ X int fd; X int pid; X int len; X char file[BUFSIZ]; X char buf[32]; X struct stat sb; X X if (islocked) X return 1; X X if (strcmp (pw_filename, PASSWD) != 0) X return 0; X X /* X * Create a lock file which can be switched into place X */ X X sprintf (file, PW_TEMP, lock_pid = getpid ()); X if ((fd = open (file, O_CREAT|O_EXCL|O_WRONLY, 0600)) == -1) X return 0; X X sprintf (buf, "%d", lock_pid); X if (write (fd, buf, strlen (buf) + 1) != strlen (buf) + 1) { X (void) close (fd); X (void) unlink (file); X return 0; X } X close (fd); X X /* X * Simple case first - X * Link fails (in a sane environment ...) if the target X * exists already. So we try to switch in a new lock X * file. If that succeeds, we assume we have the only X * valid lock. Needs work for NFS where this assumption X * may not hold. The simple hack is to check the link X * count on the source file, which should be 2 iff the X * link =really= worked. X */ X X if (link (file, PW_LOCK) == 0) { X if (stat (file, &sb) != 0) X return 0; X X if (sb.st_nlink != 2) X return 0; X X (void) unlink (file); X islocked = 1; X return 1; X } X X /* X * Invalid lock test - X * Open the lock file and see if the lock is valid. X * The PID of the lock file is checked, and if the PID X * is not valid, the lock file is removed. If the unlink X * of the lock file fails, it should mean that someone X * else is executing this code. They will get success, X * and we will fail. X */ X X if ((fd = open (PW_LOCK, O_RDWR)) == -1 || X (len = read (fd, buf, BUFSIZ)) <= 0) { X errno = EINVAL; X return 0; X } X buf[len] = '\0'; X if ((pid = strtol (buf, (char **) 0, 10)) == 0) { X errno = EINVAL; X return 0; X } X if (kill (pid, 0) == 0) { X errno = EEXIST; X return 0; X } X if (unlink (PW_LOCK)) { X (void) close (fd); X (void) unlink (file); X X return 0; X } X X /* X * Re-try lock - X * The invalid lock has now been removed and I should X * be able to acquire a lock for myself just fine. If X * this fails there will be no retry. The link count X * test here makes certain someone executing the previous X * block of code didn't just remove the lock we just X * linked to. X */ X X if (link (file, PW_LOCK) == 0) { X if (stat (file, &sb) != 0) X return 0; X X if (sb.st_nlink != 2) X return 0; X X (void) unlink (file); X islocked = 1; X return 1; X } X (void) unlink (file); X return 0; X} X X/* X * pw_unlock - logically unlock a password file X * X * pw_unlock() removes the lock which was set by an earlier X * invocation of pw_lock(). X */ X Xint Xpw_unlock () X{ X if (isopen) { X open_modes = O_RDONLY; X if (! pw_close ()) X return 0; X } X if (islocked) { X islocked = 0; X if (lock_pid != getpid ()) X return 0; X X (void) unlink (PW_LOCK); X return 1; X } X return 0; X} X X/* X * pw_open - open a password file X * X * pw_open() encapsulates the open operation. it returns X * TRUE or FALSE depending on the password file being X * properly opened. X */ X Xint Xpw_open (mode) Xint mode; X{ X char buf[8192]; X char *cp; X struct pw_file_entry *pwf; X struct passwd *pwent; X X if (isopen || (mode != O_RDONLY && mode != O_RDWR)) X return 0; X X if (mode != O_RDONLY && ! islocked && X strcmp (pw_filename, PASSWD) == 0) X return 0; X X if ((pwfp = fopen (pw_filename, mode == O_RDONLY ? "r":"r+")) == 0) X return 0; X X pwf_head = pwf_tail = pwf_cursor = 0; X pw_changed = 0; X X while (fgets (buf, sizeof buf, pwfp) != (char *) 0) { X if (cp = strrchr (buf, '\n')) X *cp = '\0'; X X if (! (pwf = (struct pw_file_entry *) malloc (sizeof *pwf))) X return 0; X X pwf->pwf_changed = 0; X pwf->pwf_line = strdup (buf); X if ((pwent = sgetpwent (buf)) && ! (pwent = pw_dup (pwent))) X return 0; X X pwf->pwf_entry = pwent; X X if (pwf_head == 0) { X pwf_head = pwf_tail = pwf; X pwf->pwf_next = 0; X } else { X pwf_tail->pwf_next = pwf; X pwf->pwf_next = 0; X pwf_tail = pwf; X } X } X isopen++; X open_modes = mode; X X return 1; X} X X/* X * pw_close - close the password file X * X * pw_close() outputs any modified password file entries and X * frees any allocated memory. X */ X Xint Xpw_close () X{ X char backup[BUFSIZ]; X int fd; X int mask; X int c; X int i; X int errors = 0; X FILE *bkfp; X struct pw_file_entry *pwf; X struct pw_file_entry *opwf; X X if (! isopen) { X errno = EINVAL; X return 0; X } X if (islocked && lock_pid != getpid ()) { X isopen = 0; X islocked = 0; X errno = EACCES; X return 0; X } X strcpy (backup, pw_filename); X strcat (backup, "-"); X X if (open_modes == O_RDWR && pw_changed) { X mask = umask (022); X if ((bkfp = fopen (backup, "w")) == 0) { X umask (mask); X return 0; X } X umask (mask); X X rewind (pwfp); X while ((c = getc (pwfp)) != EOF) { X if (putc (c, bkfp) == EOF) { X fclose (bkfp); X return 0; X } X } X if (fclose (bkfp)) X return 0; X X isopen = 0; X (void) fclose (pwfp); X X mask = umask (022); X if (! (pwfp = fopen (pw_filename, "w"))) { X umask (mask); X return 0; X } X umask (mask); X X for (pwf = pwf_head;errors == 0 && pwf;pwf = pwf->pwf_next) { X if (pwf->pwf_changed) { X if (putpwent (pwf->pwf_entry, pwfp)) X errors++; X } else { X if (fputs (pwf->pwf_line, pwfp) == EOF) X errors++; X if (putc ('\n', pwfp) == EOF) X errors++; X } X } X if (fflush (pwfp)) X errors++; X X if (errors) { X unlink (pw_filename); X link (backup, pw_filename); X unlink (backup); X return 0; X } X } X if (fclose (pwfp)) X return 0; X X pwfp = 0; X X while (pwf_head != 0) { X pwf = pwf_head; X pwf_head = pwf->pwf_next; X X if (pwf->pwf_entry) { X pw_free (pwf->pwf_entry); X free (pwf->pwf_entry); X } X if (pwf->pwf_line) X free (pwf->pwf_line); X X free (pwf); X } X pwf_tail = 0; X return 1; X} X Xint Xpw_update (pwent) Xstruct passwd *pwent; X{ X struct pw_file_entry *pwf; X struct passwd *npw; X X if (! isopen || open_modes == O_RDONLY) { X errno = EINVAL; X return 0; X } X for (pwf = pwf_head;pwf != 0;pwf = pwf->pwf_next) { X if (pwf->pwf_entry == 0) X continue; X X if (strcmp (pwent->pw_name, pwf->pwf_entry->pw_name) != 0) X continue; X X if (! (npw = pw_dup (pwent))) X return 0; X else { X pw_free (pwf->pwf_entry); X *(pwf->pwf_entry) = *npw; X } X pwf->pwf_changed = 1; X pwf_cursor = pwf; X return pw_changed = 1; X } X pwf = (struct pw_file_entry *) malloc (sizeof *pwf); X if (! (pwf->pwf_entry = pw_dup (pwent))) X return 0; X X pwf->pwf_changed = 1; X pwf->pwf_next = 0; X pwf->pwf_line = 0; X X if (pwf_tail) X pwf_tail->pwf_next = pwf; X X if (! pwf_head) X pwf_head = pwf; X X pwf_tail = pwf; X X return pw_changed = 1; X} X Xint Xpw_remove (name) Xchar *name; X{ X struct pw_file_entry *pwf; X struct pw_file_entry *opwf; X X if (! isopen || open_modes == O_RDONLY) { X errno = EINVAL; X return 0; X } X for (opwf = 0, pwf = pwf_head;pwf != 0; X opwf = pwf, pwf = pwf->pwf_next) { X if (! pwf->pwf_entry) X continue; X X if (strcmp (name, pwf->pwf_entry->pw_name) != 0) X continue; X X if (pwf == pwf_cursor) X pwf_cursor = opwf; X X if (opwf != 0) X opwf->pwf_next = pwf->pwf_next; X else X pwf_head = pwf->pwf_next; X X if (pwf == pwf_tail) X pwf_tail = opwf; X X return pw_changed = 1; X } X errno = ENOENT; X return 0; X} X Xstruct passwd * Xpw_locate (name) Xchar *name; X{ X struct pw_file_entry *pwf; X X if (! isopen) { X errno = EINVAL; X return 0; X } X for (pwf = pwf_head;pwf != 0;pwf = pwf->pwf_next) { X if (pwf->pwf_entry == 0) X continue; X X if (strcmp (name, pwf->pwf_entry->pw_name) == 0) { X pwf_cursor = pwf; X return pwf->pwf_entry; X } X } X errno = ENOENT; X return 0; X} X Xint Xpw_rewind () X{ X if (! isopen) { X errno = EINVAL; X return 0; X } X pwf_cursor = 0; X return 1; X} X Xstruct passwd * Xpw_next () X{ X if (! isopen) { X errno = EINVAL; X return 0; X } X if (pwf_cursor == 0) X pwf_cursor = pwf_head; X else X pwf_cursor = pwf_cursor->pwf_next; X X while (pwf_cursor) { X if (pwf_cursor->pwf_entry) X return pwf_cursor->pwf_entry; X X pwf_cursor = pwf_cursor->pwf_next; X } X return 0; X} SHAR_EOF if test 11009 -ne "`wc -c < 'pwio.c'`" then echo shar: "error transmitting 'pwio.c'" '(should have been 11009 characters)' fi fi echo shar: "extracting 'encrypt.c'" '(1287 characters)' if test -f 'encrypt.c' then echo shar: "will not over-write existing file 'encrypt.c'" else sed 's/^X//' << \SHAR_EOF > 'encrypt.c' X/* X * Copyright 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include <string.h> X#include "config.h" X X#ifndef lint Xstatic char sccsid[] = "@(#)encrypt.c 3.4 19:44:23 12/10/90"; X#endif X Xextern char *crypt(); X Xchar * Xpw_encrypt (clear, salt) Xchar *clear; Xchar *salt; X{ X static char cipher[32]; X static int count; X char newsalt[2]; X char *cp; X long now; X X /* X * See if a new salt is needed and get a few random X * bits of information. The amount of randomness is X * probably not all that crucial since the salt only X * serves to thwart a dictionary attack. X */ X X if (salt == (char *) 0) { X now = time ((long *) 0) + count++; X now ^= clock (); X now ^= getpid (); X now = ((now >> 12) ^ (now)) & 07777; X newsalt[0] = i64c ((now >> 6) & 077); X newsalt[1] = i64c (now & 077); X salt = newsalt; X } X cp = crypt (clear, salt); X strcpy (cipher, cp); X X#ifdef DOUBLESIZE X if (strlen (clear) > 8) { X cp = crypt (clear + 8, salt); X strcat (cipher, cp + 2); X } X#endif X return cipher; X} SHAR_EOF if test 1287 -ne "`wc -c < 'encrypt.c'`" then echo shar: "error transmitting 'encrypt.c'" '(should have been 1287 characters)' fi fi echo shar: "extracting 'chpasswd.c'" '(5114 characters)' if test -f 'chpasswd.c' then echo shar: "will not over-write existing file 'chpasswd.c'" else sed 's/^X//' << \SHAR_EOF > 'chpasswd.c' X/* X * Copyright 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X * X * chpass - update passwords in batch X * X * chpass reads standard input for a list of colon separated X * user names and new passwords. the appropriate password X * files are updated to reflect the changes. because the X * changes are made in a batch fashion, the user must run X * the mkpasswd command after this command terminates since X * no password updates occur until the very end. X */ X X#include <stdio.h> X#include "pwd.h" X#include <fcntl.h> X#include <string.h> X#include "config.h" X#ifdef SHADOWPWD X#include "shadow.h" X#endif X X#ifndef lint Xstatic char sccsid[] = "@(#)chpasswd.c 3.2 12:30:30 12/12/90"; X#endif X Xchar *Prog; X Xextern char *pw_encrypt(); X X/* X * If it weren't for the different structures and differences in how X * certain fields were manipulated, I could just use macros to replace X * the function calls for the different file formats. So I make the X * best of things and just use macros to replace a few of the calls. X */ X X#ifdef SHADOWPWD X#define pw_lock spw_lock X#define pw_open spw_open X#define pw_close spw_close X#define pw_unlock spw_unlock X#endif X X/* X * usage - display usage message and exit X */ X Xusage () X{ X fprintf (stderr, "usage: %s\n", Prog); X exit (1); X} X Xmain (argc, argv) Xint argc; Xchar **argv; X{ X char buf[BUFSIZ]; X char *name; X char *newpwd; X char *cp; X#ifdef SHADOWPWD X struct spwd *sp; X struct spwd newsp; X struct spwd *spw_locate(); X#else X struct passwd *pw; X struct passwd newpw; X struct passwd *pw_locate(); X char newage[5]; X#endif X int errors = 0; X int line = 0; X long now = time ((long *) 0) / (24L*3600L); X X if (Prog = strrchr (argv[0], '/')) X Prog++; X else X Prog = argv[0]; X X if (argc != 1) X usage (); X X /* X * Lock the password file and open it for reading. This will X * bring all of the entries into memory where they may be X * updated. X */ X X if (! pw_lock ()) { X fprintf (stderr, "%s: can't lock password file\n", Prog); X exit (1); X } X if (! pw_open (O_RDWR)) { X fprintf (stderr, "%s: can't open password file\n", Prog); X exit (1); X } X X /* X * Read each line, separating the user name from the password. X * The password entry for each user will be looked up in the X * appropriate file (shadow or passwd) and the password changed. X * For shadow files the last change date is set directly, for X * passwd files the last change date is set in the age only if X * aging information is present. X */ X X while (fgets (buf, sizeof buf, stdin) != (char *) 0) { X line++; X if (cp = strrchr (buf, '\n')) { X *cp = '\0'; X } else { X fprintf (stderr, "%s: line %d: line too long\n", X Prog, line); X errors++; X continue; X } X X /* X * The username is the first field. It is separated X * from the password with a ":" character which is X * replaced with a NUL to give the new password. The X * new password will then be encrypted in the normal X * fashion with a new salt generated. X */ X X name = buf; X if (cp = strchr (name, ':')) { X *cp++ = '\0'; X } else { X fprintf (stderr, "%s: line %d: missing new password\n", X Prog, line); X errors++; X continue; X } X newpwd = cp; X cp = pw_encrypt (newpwd, (char *) 0); X X /* X * Get the password file entry for this user. The user X * must already exist. X */ X X#ifdef SHADOWPWD X if (! (sp = spw_locate (name))) X#else X if (! (pw = pw_locate (name))) X#endif X { X fprintf (stderr, "%s: line %d: unknown user %s\n", X Prog, line, name); X errors++; X continue; X } X X /* X * The freshly encrypted new password is merged into X * the user's password file entry and the last password X * change date is set to the current date. X */ X X#ifdef SHADOWPWD X newsp = *sp; X newsp.sp_pwdp = cp; X newsp.sp_lstchg = now; X#else X newpw = *pw; X newpw.pw_passwd = cp; X#ifdef ATT_AGE X if (newpw.pw_age[0]) { X strcpy (newage, newpw.pw_age); X strcpy (newage + 2, l64a (now / 7)); X newpw.pw_age = newage; X } X#endif X#endif X X /* X * The updated password file entry is then put back X * and will be written to the password file later, after X * all the other entries have been updated as well. X */ X X#ifdef SHADOWPWD X if (! spw_update (&newsp)) X#else X if (! pw_update (&newpw)) X#endif X { X fprintf (stderr, "%s: line %d: cannot update password entry\n", X Prog, line); X errors++; X continue; X } X } X X /* X * Any detected errors will cause the entire set of changes X * to be aborted. Unlocking the password file will cause X * all of the changes to be ignored. Otherwise the file is X * closed, causing the changes to be written out all at X * once, and then unlocked afterwards. X */ X X if (errors) { X fprintf ("%s: error detected, changes ignored\n", Prog); X pw_unlock (); X exit (1); X } X if (! pw_close ()) { X fprintf ("%s: error updating password file\n", Prog); X exit (1); X } X (void) pw_unlock (); X} SHAR_EOF if test 5114 -ne "`wc -c < 'chpasswd.c'`" then echo shar: "error transmitting 'chpasswd.c'" '(should have been 5114 characters)' fi fi echo shar: "extracting 'newusers.c'" '(13360 characters)' if test -f 'newusers.c' then echo shar: "will not over-write existing file 'newusers.c'" else sed 's/^X//' << \SHAR_EOF > 'newusers.c' X/* X * Copyright 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X * X * newusers - create users from a batch file X * X * newusers creates a collection of entries in /etc/passwd X * and related files by reading a passwd-format file and X * adding entries in the related directories. X */ X X#include <stdio.h> X#include "pwd.h" X#include <grp.h> X#include <fcntl.h> X#include <string.h> X#include "config.h" X#ifdef SHADOWPWD X#include "shadow.h" X#endif X X#ifndef lint Xstatic char sccsid[] = "@(#)newusers.c 3.2 12:31:02 12/12/90"; X#endif X Xchar *Prog; X Xextern char *pw_encrypt(); X Xint pw_lock(), gr_lock(); Xint pw_open(), gr_open(); Xstruct passwd *pw_locate(), *pw_next(); Xstruct group *gr_locate(), *gr_next(); Xint pw_update(), gr_update(); Xint pw_close(), gr_close(); Xint pw_unlock(), gr_unlock(); X X#ifdef SHADOWPWD Xint spw_lock(), spw_open(), spw_update(), spw_close(), spw_unlock(); Xstruct spwd *spw_locate(), *spw_next(); X#endif X X#ifndef MKDIR X X/* X * mkdir - for those of us with no mkdir() system call. X */ X Xmkdir (dir, mode) Xchar *dir; Xint mode; X{ X int mask; X int status; X int pid; X int i; X char buf[BUFSIZ]; X X mode = (~mode & 0777); X mask = umask (mode); X if ((pid = fork ()) == 0) { X execl ("/bin/mkdir", "mkdir", dir, (char *) 0); X perror ("/bin/mkdir"); X _exit (1); X } else { X while ((i = wait (&status)) != pid && i != -1) X ; X } X umask (mask); X return status; X} X#endif X X/* X * usage - display usage message and exit X */ X Xusage () X{ X fprintf (stderr, "Usage: %s [ input ]\n", Prog); X exit (1); X} X X/* X * add_group - create a new group or add a user to an existing group X */ X Xint Xadd_group (name, uid, gid, ngid) Xchar *name; Xchar *uid; Xchar *gid; Xint *ngid; X{ X struct passwd *pwd; X struct group *grp; X struct group grent; X char *members[2]; X int i; X X /* X * Start by seeing if the named group already exists. This X * will be very easy to deal with if it does. X */ X X if (grp = gr_locate (gid)) { Xadd_member: X grent = *grp; X *ngid = grent.gr_gid; X for (i = 0;grent.gr_mem[i] != (char *) 0;i++) X if (strcmp (grent.gr_mem[i], name) == 0) X return 0; X X if (! (grent.gr_mem = (char **) X malloc (sizeof (char *) * (i + 2)))) { X fprintf (stderr, "%s: Out of Memory\n", Prog); X return -1; X } X memcpy (grent.gr_mem, grp->gr_mem, sizeof (char *) * (i + 2)); X grent.gr_mem[i] = strdup (name); X grent.gr_mem[i + 1] = (char *) 0; X X return ! gr_update (&grent); X } X X /* X * The group did not exist, so I try to figure out what the X * GID is going to be. The gid parameter is probably "", meaning X * I figure out the GID from the password file. I want the UID X * and GID to match, unless the GID is already used. X */ X X if (gid[0] == '\0') { X i = 100; X for (pw_rewind ();pwd = pw_next ();) { X if (pwd->pw_uid >= i) X i = pwd->pw_uid + 1; X } X for (gr_rewind ();grp = gr_next ();) { X if (grp->gr_gid == i) { X i = -1; X break; X } X } X } else if (gid[0] >= '0' && gid[0] <= '9') { X X /* X * The GID is a number, which means either this is a brand new X * group, or an existing group. For existing groups I just add X * myself as a member, just like I did earlier. X */ X X i = atoi (gid); X for (gr_rewind ();grp = gr_next ();) X if (grp->gr_gid == i) X goto add_member; X } else X X /* X * The last alternative is that the GID is a name which is not X * already the name of an existing group, and I need to figure X * out what group ID that group name is going to have. X */ X X i = -1; X X /* X * If I don't have a group ID by now, I'll go get the X * next one. X */ X X if (i == -1) { X for (i = 100, gr_rewind;grp = gr_next ();) X if (grp->gr_gid >= i) X i = grp->gr_gid + 1; X } X X /* X * Now I have all of the fields required to create the new X * group. X */ X X if (gid[0] && (gid[0] <= '0' || gid[0] >= '9')) X grent.gr_name = gid; X else X grent.gr_name = name; X X grent.gr_passwd = "!"; X grent.gr_gid = i; X members[0] = name; X members[1] = (char *) 0; X grent.gr_mem = members; X X *ngid = grent.gr_gid; X return ! gr_update (&grent); X} X X/* X * add_user - create a new user ID X */ X Xadd_user (name, uid, nuid, gid) Xchar *name; Xchar *uid; Xint *nuid; Xint gid; X{ X struct passwd *pwd; X struct passwd pwent; X int i; X X /* X * The first guess for the UID is either the numerical UID X * that the caller provided, or the next available UID. X */ X X if (uid[0] >= '0' && uid[0] <= '9') { X i = atoi (uid); X } if (uid[0] && (pwd = pw_locate (uid))) { X i = pwd->pw_uid; X } else { X i = 100; X for (pw_rewind ();pwd = pw_next ();) X if (pwd->pw_uid >= i) X i = pwd->pw_uid + 1; X } X X /* X * I don't want to fill in the entire password structure X * members JUST YET, since there is still more data to be X * added. So, I fill in the parts that I have. X */ X X pwent.pw_name = name; X pwent.pw_passwd = "!"; X#ifdef ATT_AGE X pwent.pw_age = ""; X#endif X#ifdef ATT_COMMENT X pwent.pw_comment = ""; X#endif X#ifdef BSD_QUOTAS X pwent.pw_quota = 0; X#endif X pwent.pw_uid = i; X pwent.pw_gid = gid; X pwent.pw_gecos = ""; X pwent.pw_dir = ""; X pwent.pw_shell = ""; X X *nuid = i; X return ! pw_update (&pwent); X} X X/* X * add_passwd - add or update the encrypted password X */ X Xadd_passwd (pwd, passwd) Xstruct passwd *pwd; Xchar *passwd; X{ X#ifdef SHADOWPWD X struct spwd *sp; X struct spwd spent; X#endif X struct passwd *pw; X struct passwd pwent; X static char newage[5]; X X /* X * In the case of regular password files, this is real X * easy - pwd points to the entry in the password file. X * Shadow files are harder since there are zillions of X * things to do ... X */ X X#ifndef SHADOWPWD X pwd->pw_passwd = pw_encrypt (passwd, (char *) 0); X#ifdef ATT_AGE X if (strlen (pwd->pw_age) == 4) { X strcpy (newage, pwd->pw_age); X strcpy (newage + 2, X l64a (time ((long *) 0) / (7L*24L*3600L))); X pwd->pw_age = newage; X } X#endif /* ATT_AGE */ X return 0; X#else X X /* X * Do the first and easiest shadow file case. The user X * already exists in the shadow password file. X */ X X if (sp = spw_locate (pwd->pw_name)) { X spent = *sp; X spent.sp_pwdp = pw_encrypt (passwd, (char *) 0); X return ! spw_update (sp); X } X X /* X * Pick the next easiest case - the user has an encrypted X * password which isn't equal to "!". The password was set X * to "!" earlier when the entry was created, so this user X * would have to have had the password set someplace else. X */ X X if (strcmp (pwd->pw_passwd, "!") != 0) { X pwd->pw_passwd = pw_encrypt (passwd, (char *) 0); X#ifdef ATT_AGE X if (strlen (pwd->pw_age) == 4) { X strcpy (newage, pwd->pw_age); X strcpy (newage + 2, X l64a (time ((long *) 0) / (7L*24L*3600L))); X pwd->pw_age = newage; X } X#endif /* ATT_AGE */ X return 0; X } X X /* X * Now the really hard case - I need to create an entirely X * shadow password file entry. X */ X X spent.sp_namp = pwd->pw_name; X spent.sp_pwdp = pw_encrypt (passwd, (char *) 0); X spent.sp_lstchg = time ((long *) 0) / (24L*3600L); X#ifdef MINDAYS X spent.sp_min = MINDAYS; X#else X spent.sp_min = 0; X#endif X#ifdef MAXDAYS X spent.sp_max = MAXDAYS; X#else X spent.sp_max = 10000; /* 10000 is infinity this week */ X#endif X#ifdef WARNAGE X spent.sp_warn = WARNAGE; X#else X spent.sp_warn = -1; X#endif X spent.sp_inact = -1; X spent.sp_expire = -1; X spent.sp_flag = -1; X X return ! spw_update (&spent); X#endif X} X Xmain (argc, argv) Xint argc; Xchar **argv; X{ X char buf[BUFSIZ]; X char *fields[8]; X int nfields; X char *name; X char *newpwd; X char *cp; X#ifdef SHADOWPWD X struct spwd *sp; X struct spwd newsp; X struct spwd *spw_locate(); X#endif X struct passwd *pw; X struct passwd newpw; X struct passwd *pw_locate(); X char newage[5]; X int errors = 0; X int line = 0; X long now = time ((long *) 0) / (24L*3600L); X int uid; X int gid; X int i; X X if (Prog = strrchr (argv[0], '/')) X Prog++; X else X Prog = argv[0]; X X if (argc > 1 && argv[1][0] == '-') X usage (); X X if (argc == 2) { X if (! freopen (argv[1], "r", stdin)) { X sprintf (buf, "%s: %s", Prog, argv[1]); X perror (buf); X exit (1); X } X } X X /* X * Lock the password files and open them for update. This will X * bring all of the entries into memory where they may be X * searched for an modified, or new entries added. The password X * file is the key - if it gets locked, assume the others can X * be locked right away. X */ X X for (i = 0;i < 30;i++) { X if (pw_lock ()) X break; X } X if (i == 30) { X fprintf (stderr, "%s: can't lock /etc/passwd.\n", Prog); X exit (1); X } X#ifdef SHADOWPWD X if (! spw_lock () || ! gr_lock ()) X#else X if (! gr_lock ()) X#endif X { X fprintf (stderr, "%s: can't lock files, try again later\n", X Prog); X (void) pw_unlock (); X#ifdef SHADOWPWD X (void) spw_unlock (); X#endif X exit (1); X } X#ifdef SHADOWPWD X if (! pw_open (O_RDWR) || ! spw_open (O_RDWR) || ! gr_open (O_RDWR)) X#else X if (! pw_open (O_RDWR) || ! gr_open (O_RDWR)) X#endif X { X fprintf (stderr, "%s: can't open files\n", Prog); X (void) pw_unlock (); X#ifdef SHADOWPWD X (void) spw_unlock (); X#endif X (void) gr_unlock (); X exit (1); X } X X /* X * Read each line. The line has the same format as a password X * file entry, except that certain fields are not contrained to X * be numerical values. If a group ID is entered which does X * not already exist, an attempt is made to allocate the same X * group ID as the numerical user ID. Should that fail, the X * next available group ID over 100 is allocated. The pw_gid X * field will be updated with that value. X */ X X while (fgets (buf, sizeof buf, stdin) != (char *) 0) { X line++; X if (cp = strrchr (buf, '\n')) { X *cp = '\0'; X } else { X fprintf (stderr, "%s: line %d: line too long\n", X Prog, line); X errors++; X continue; X } X X /* X * Break the string into fields and screw around with X * them. There MUST be 7 colon separated fields, X * although the values aren't that particular. X */ X X for (cp = buf, nfields = 0;nfields < 7;nfields++) { X fields[nfields] = cp; X if (cp = strchr (cp, ':')) X *cp++ = '\0'; X else X break; X } X if (*cp || nfields != 6) { X fprintf (stderr, "%s: line %d: invalid line\n", X Prog, line); X continue; X } X X /* X * Now the fields are processed one by one. The first X * field to be processed is the group name. A new X * group will be created if the group name is non-numeric X * and does not already exist. The named user will be X * the only member. If there is no named group to be a X * member of, the UID will be figured out and that value X * will be a candidate for a new group, if that group ID X * exists, a whole new group ID will be made up. X */ X X if (! (pw = pw_locate (fields[0])) && X add_group (fields[0], fields[2], fields[3], &gid)) { X fprintf (stderr, "%s: %d: can't create GID\n", X Prog, line); X errors++; X continue; X } X X /* X * Now we work on the user ID. It has to be specified X * either as a numerical value, or left blank. If it X * is a numerical value, that value will be used, otherwise X * the next available user ID is computed and used. After X * this there will at least be a (struct passwd) for the X * user. X */ X X if (! pw && add_user (fields[0], fields[2], &uid, gid)) { X fprintf (stderr, "%s: line %d: can't create UID\n", X Prog, line); X errors++; X continue; X } X X /* X * The password, gecos field, directory, and shell fields X * all come next. X */ X X if (! (pw = pw_locate (fields[0]))) { X fprintf (stderr, "%s: line %d: cannot find user %s\n", X Prog, line, fields[0]); X errors++; X continue; X } X newpw = *pw; X X if (add_passwd (&newpw, fields[1])) { X fprintf (stderr, "%s: line %d: can't update password\n", X Prog, line); X errors++; X continue; X } X if (fields[4][0]) X newpw.pw_gecos = fields[4]; X X if (fields[5][0]) X newpw.pw_dir = fields[5]; X X if (fields[6][0]) X newpw.pw_shell = fields[6]; X X if (newpw.pw_dir[0] && access (newpw.pw_dir, 0)) { X#ifdef UMASK X if (mkdir (newpw.pw_dir, 0777 & (~UMASK))) X#else X if (mkdir (newpw.pw_dir, 0777)) X#endif X fprintf (stderr, "%s: line %d: mkdir failed\n", X Prog, line); X else if (chown (newpw.pw_dir, X newpw.pw_uid, newpw.pw_gid)) X fprintf (stderr, "%s: line %d: chown failed\n", X Prog, line); X } X X /* X * Update the password entry with the new changes made. X */ X X if (! pw_update (&newpw)) { X fprintf (stderr, "%s: line %d: can't update entry\n", X Prog, line); X errors++; X continue; X } X } X X /* X * Any detected errors will cause the entire set of changes X * to be aborted. Unlocking the password file will cause X * all of the changes to be ignored. Otherwise the file is X * closed, causing the changes to be written out all at X * once, and then unlocked afterwards. X */ X X if (errors) { X fprintf ("%s: error detected, changes ignored\n", Prog); X (void) gr_unlock (); X#ifdef SHADOWPWD X (void) spw_unlock (); X#endif X (void) pw_unlock (); X exit (1); X } X#ifdef SHADOWPWD X if (! pw_close () || ! spw_close () || ! gr_close ()) X#else X if (! pw_close () || ! gr_close ()) X#endif X { X fprintf ("%s: error updating files\n", Prog); X (void) gr_unlock (); X#ifdef SHADOWPWD X (void) spw_unlock (); X#endif X (void) pw_unlock (); X exit (1); X } X (void) gr_unlock (); X#ifdef SHADOWPWD X (void) spw_unlock (); X#endif X (void) pw_unlock (); X X exit (0); X} SHAR_EOF if test 13360 -ne "`wc -c < 'newusers.c'`" then echo shar: "error transmitting 'newusers.c'" '(should have been 13360 characters)' fi fi echo shar: "extracting 'rad64.c'" '(1670 characters)' if test -f 'rad64.c' then echo shar: "will not over-write existing file 'rad64.c'" else sed 's/^X//' << \SHAR_EOF > 'rad64.c' X/* X * Copyright 1989, 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#ifndef lint Xstatic char sccsid[] = "@(#)rad64.c 3.2 19:44:25 12/10/90"; X#endif X X/* X * c64i - convert a radix 64 character to an integer X */ X Xint c64i (c) Xchar c; X{ X if (c == '.') X return (0); X X if (c == '/') X return (1); X X if (c >= '0' && c <= '9') X return (c - '0' + 2); X X if (c >= 'A' && c <= 'Z') X return (c - 'A' + 12); X X if (c >= 'a' && c <= 'z') X return (c - 'a' + 38); X else X return (-1); X} X X/* X * i64c - convert an integer to a radix 64 character X */ X Xint i64c (i) Xint i; X{ X if (i < 0) X return ('.'); X else if (i > 63) X return ('z'); X X if (i == 0) X return ('.'); X X if (i == 1) X return ('/'); X X if (i >= 2 && i <= 11) X return ('0' - 2 + i); X X if (i >= 12 && i <= 37) X return ('A' - 12 + i); X X if (i >= 38 && i <= 63) X return ('a' - 38 + i); X X return ('\0'); X} X X/* X * l64a - convert a long to a string of radix 64 characters X */ X Xchar *l64a (l) Xlong l; X{ X static char buf[8]; X int i = 0; X X if (i < 0L) X return ((char *) 0); X X do { X buf[i++] = i64c ((int) (l % 64)); X buf[i] = '\0'; X } while (l /= 64L, l > 0 && i < 6); X X return (buf); X} X X/* X * a64l - convert a radix 64 string to a long integer X */ X Xlong a64l (s) Xchar *s; X{ X int i; X long value; X long shift = 0; X X for (i = 0, value = 0L;i < 6 && *s;s++) { X value += (c64i (*s) << shift); X shift += 6; X } X return (value); X} SHAR_EOF if test 1670 -ne "`wc -c < 'rad64.c'`" then echo shar: "error transmitting 'rad64.c'" '(should have been 1670 characters)' fi fi echo shar: "extracting 'dialchk.c'" '(1328 characters)' if test -f 'dialchk.c' then echo shar: "will not over-write existing file 'dialchk.c'" else sed 's/^X//' << \SHAR_EOF > 'dialchk.c' X/* X * Copyright 1989, 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include <stdio.h> X#ifdef BSD X#include <strings.h> X#else X#include <string.h> X#endif X#include "config.h" X#include "dialup.h" X X#ifndef lint Xstatic char sccsid[] = "@(#)dialchk.c 3.2 19:44:18 12/10/90"; X#endif X Xextern char *pw_encrypt(); X X/* X * Check for dialup password X * X * dialcheck tests to see if tty is listed as being a dialup X * line. If so, a dialup password may be required if the shell X * is listed as one which requires a second password. X */ X Xint dialcheck (tty, shell) Xchar *tty; Xchar *shell; X{ X char *crypt (); X char *getpass (); X struct dialup *dialup; X char *pass; X char *cp; X X setduent (); X X if (! isadialup (tty)) { X endduent (); X return (1); X } X if (! (dialup = getdushell (shell))) { X endduent (); X return (1); X } X endduent (); X X if (dialup->du_passwd[0] == '\0') X return (1); X X if (! (pass = getpass ("Dialup Password:"))) X return (0); X X cp = pw_encrypt (pass, dialup->du_passwd); X return (strcmp (cp, dialup->du_passwd) == 0); X} SHAR_EOF if test 1328 -ne "`wc -c < 'dialchk.c'`" then echo shar: "error transmitting 'dialchk.c'" '(should have been 1328 characters)' fi fi echo shar: "extracting 'faillog.h'" '(715 characters)' if test -f 'faillog.h' then echo shar: "will not over-write existing file 'faillog.h'" else sed 's/^X//' << \SHAR_EOF > 'faillog.h' X/* X * Copyright 1989, 1990, John F. Haugh II X * All rights reserved. X * X * Use, duplication, and disclosure prohibited without X * the express written permission of the author. X */ X X/* X * faillog.h - login failure logging file format X * X * @(#)faillog.h 2.2 19:23:46 7/29/90 X * X * The login failure file is maintained by login(1) and fail(1L) X * Each record in the file represents a separate UID and the file X * is indexed in that fashion. X */ X X#define FAILFILE "/usr/adm/faillog" X Xstruct faillog { X short fail_cnt; /* failures since last success */ X short fail_max; /* failures before turning account off */ X char fail_line[12]; /* last failure occured here */ X time_t fail_time; /* last failure occured then */ X}; SHAR_EOF if test 715 -ne "`wc -c < 'faillog.h'`" then echo shar: "error transmitting 'faillog.h'" '(should have been 715 characters)' fi fi echo shar: "extracting 'pwdbm.c'" '(1637 characters)' if test -f 'pwdbm.c' then echo shar: "will not over-write existing file 'pwdbm.c'" else sed 's/^X//' << \SHAR_EOF > 'pwdbm.c' X/* X * Copyright 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#ifndef lint Xstatic char sccsid[] = "@(#)pwdbm.c 3.3 12:31:13 12/12/90"; X#endif X X#ifdef BSD X#include <strings.h> X#define strchr index X#define strrchr rindex X#else X#include <string.h> X#endif X#include <stdio.h> X#include "pwd.h" X#include "config.h" X X#ifdef DBM X#include <dbm.h> X#endif X#ifdef NDBM X#include <ndbm.h> XDBM *pw_dbm; X#endif X X/* X * pw_dbm_update X * X * Updates the DBM password files, if they exist. X */ X Xint Xpw_dbm_update (pw) Xstruct passwd *pw; X{ X datum key; X datum content; X char data[BUFSIZ]; X int len; X static int once; X X if (! once) { X#ifdef NDBM X if (! pw_dbm) X setpwent (); X#else X setpwent (); X#endif X once++; X } X#ifdef DBM X strcpy (data, PWDFILE); X strcat (data, ".pag"); X if (access (data, 0)) X return 0; X#endif X#ifdef NDBM X if (! pw_dbm) X return 0; X#endif X len = pw_pack (pw, data); X content.dsize = len; X content.dptr = data; X X key.dsize = strlen (pw->pw_name); X key.dptr = pw->pw_name; X#ifdef DBM X if (store (key, content)) X return 0; X#endif X#ifdef NDBM X if (dbm_store (pw_dbm, key, content, DBM_REPLACE)) X return 0; X#endif X X key.dsize = sizeof pw->pw_uid; X key.dptr = (char *) &pw->pw_uid; X#ifdef DBM X if (store (key, content)) X return 0; X#endif X#ifdef NDBM X if (dbm_store (pw_dbm, key, content, DBM_REPLACE)) X return 0; X#endif X return 1; X} SHAR_EOF if test 1637 -ne "`wc -c < 'pwdbm.c'`" then echo shar: "error transmitting 'pwdbm.c'" '(should have been 1637 characters)' fi fi echo shar: "extracting 'grdbm.c'" '(2117 characters)' if test -f 'grdbm.c' then echo shar: "will not over-write existing file 'grdbm.c'" else sed 's/^X//' << \SHAR_EOF > 'grdbm.c' X/* X * Copyright 1990, John F. Haugh II X * All rights reserved. X * X * Use, duplication, and disclosure prohibited without X * the express written permission of the author. X */ X X#ifndef lint Xstatic char sccsid[] = "@(#)grdbm.c 3.1 08:11:52 11/21/90"; X#endif X X#include <string.h> X#include <stdio.h> X#include <grp.h> X#include "config.h" X X#ifdef NDBM X#include <ndbm.h> XDBM *gr_dbm; X X#define GRP_FRAG 256 X X/* X * gr_dbm_update X * X * Updates the DBM password files, if they exist. X */ X Xint Xgr_dbm_update (gr) Xstruct group *gr; X{ X datum key; X datum content; X char data[BUFSIZ*8]; X char grpkey[60]; X char *cp; X int len; X int i; X int cnt; X static int once; X X if (! once) { X if (! gr_dbm) X setgrent (); X X once++; X } X if (! gr_dbm) X return 0; X X len = gr_pack (gr, data); X X if (len <= GRP_FRAG) { X content.dsize = len; X content.dptr = data; X X key.dsize = strlen (gr->gr_name); X key.dptr = gr->gr_name; X if (dbm_store (gr_dbm, key, content, DBM_REPLACE)) X return 0; X X key.dsize = sizeof gr->gr_gid; X key.dptr = (char *) &gr->gr_gid; X if (dbm_store (gr_dbm, key, content, DBM_REPLACE)) X return 0; X X } else { X content.dsize = sizeof cnt; X content.dptr = (char *) &cnt; X cnt = (len + (GRP_FRAG-1)) / GRP_FRAG; X X key.dsize = strlen (gr->gr_name); X key.dptr = gr->gr_name; X if (dbm_store (gr_dbm, key, content, DBM_REPLACE)) X return 0; X X key.dsize = sizeof gr->gr_gid; X key.dptr = (char *) &gr->gr_gid; X if (dbm_store (gr_dbm, key, content, DBM_REPLACE)) X return 0; X X for (cp = data, i = 0;i < cnt;i++) { X content.dsize = len > GRP_FRAG ? GRP_FRAG:len; X len -= content.dsize; X content.dptr = cp; X cp += content.dsize; X X key.dsize = sizeof i + strlen (gr->gr_name); X key.dptr = grpkey; X memcpy (grpkey, &i, sizeof i); X strcpy (grpkey + sizeof i, gr->gr_name); X if (dbm_store (gr_dbm, key, content, DBM_REPLACE)) X return 0; X X key.dsize = sizeof i + sizeof gr->gr_gid; X key.dptr = grpkey; X memcpy (grpkey, &i, sizeof i); X memcpy (grpkey + sizeof i, &gr->gr_gid, X sizeof gr->gr_gid); X if (dbm_store (gr_dbm, key, content, DBM_REPLACE)) X return 0; X } X } X return 1; X} X#endif SHAR_EOF if test 2117 -ne "`wc -c < 'grdbm.c'`" then echo shar: "error transmitting 'grdbm.c'" '(should have been 2117 characters)' fi fi echo shar: "extracting 'gshadow.c'" '(4652 characters)' if test -f 'gshadow.c' then echo shar: "will not over-write existing file 'gshadow.c'" else sed 's/^X//' << \SHAR_EOF > 'gshadow.c' X/* X * Copyright 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include "shadow.h" X#include "config.h" X#include <stdio.h> X#ifndef BSD X#include <string.h> X#include <memory.h> X#else X#include <strings.h> X#define strchr index X#define strrchr rindex X#endif X X#ifdef NDBM X#include <ndbm.h> X#include <fcntl.h> XDBM *sg_dbm; Xint sg_dbm_mode; Xstatic int dbmopened; Xstatic int dbmerror; X#endif X X X#ifndef lint Xstatic char sccsid[] = "@(#)gshadow.c 3.3 11:25:55 12/19/90"; X#endif X X#define MAXMEM 1024 X Xstatic FILE *shadow; Xstatic char *sgrpfile = "/etc/gshadow"; Xstatic char sgrbuf[BUFSIZ*4]; Xstatic char *members[MAXMEM+1]; Xstatic char *admins[MAXMEM+1]; Xstatic struct sgrp sgroup; X Xextern char *fgetsx(); Xextern int fputsx(); X X#define FIELDS 4 X Xstatic char ** Xlist (s, l) Xchar *s; Xchar **l; X{ X int nmembers = 0; X X while (*s) { X l[nmembers++] = s; X if (s = strchr (s, ',')) X *s++ = '\0'; X } X l[nmembers] = (char *) 0; X return l; X} X Xvoid Xsetsgent () X{ X#ifdef NDBM X int mode; X#endif /* NDBM */ X X if (shadow) X rewind (shadow); X else X shadow = fopen (GSHADOW, "r"); X X /* X * Attempt to open the DBM files if they have never been opened X * and an error has never been returned. X */ X X#ifdef NDBM X if (! dbmerror && ! dbmopened) { X char dbmfiles[BUFSIZ]; X X strcpy (dbmfiles, sgrpfile); X strcat (dbmfiles, ".pag"); X if (sg_dbm_mode != -1) X mode = O_RDONLY; X else X mode = (sg_dbm_mode == O_RDONLY || X sg_dbm_mode == O_RDWR) ? sg_dbm_mode:O_RDONLY; X X if (access (dbmfiles, 0) || X (! (sg_dbm = dbm_open (sgrpfile, mode, 0)))) X dbmerror = 1; X else X dbmopened = 1; X } X#endif /* NDBM */ X} X Xvoid Xendsgent () X{ X if (shadow) X (void) fclose (shadow); X X shadow = (FILE *) 0; X#ifdef NDBM X if (dbmopened && sg_dbm) { X dbm_close (sg_dbm); X dbmopened = 0; X sg_dbm = 0; X } X#endif X} X Xstruct sgrp * Xsgetsgent (string) Xchar *string; X{ X char *fields[FIELDS]; X char *cp; X char *cpp; X int atoi (); X long atol (); X int i; X X strncpy (sgrbuf, string, sizeof sgrbuf - 1); X sgrbuf[sizeof sgrbuf - 1] = '\0'; X X if (cp = strrchr (sgrbuf, '\n')) X *cp = '\0'; X X for (cp = sgrbuf, i = 0;*cp && i < FIELDS;i++) { X fields[i] = cp; X while (*cp && *cp != ':') X cp++; X X if (*cp) X *cp++ = '\0'; X } X if (*cp || i != FIELDS) X return 0; X X sgroup.sg_name = fields[0]; X sgroup.sg_passwd = fields[1]; X sgroup.sg_adm = list (fields[2], admins); X sgroup.sg_mem = list (fields[3], members); X X return &sgroup; X} X Xstruct sgrp X*fgetsgent (fp) XFILE *fp; X{ X char buf[sizeof sgrbuf]; X X if (! fp) X return (0); X X if (fgetsx (buf, sizeof buf, fp) == (char *) 0) X return (0); X X return sgetsgent (buf); X} X Xstruct sgrp X*getsgent () X{ X if (! shadow) X setsgent (); X X return (fgetsgent (shadow)); X} X Xstruct sgrp * Xgetsgnam (name) Xchar *name; X{ X struct sgrp *sgrp; X#ifdef NDBM X datum key; X datum content; X#endif X X setsgent (); X X#ifdef NDBM X X /* X * If the DBM file are now open, create a key for this group and X * try to fetch the entry from the database. A matching record X * will be unpacked into a static structure and returned to X * the user. X */ X X if (dbmopened) { X key.dsize = strlen (name); X key.dptr = name; X X content = dbm_fetch (sg_dbm, key); X if (content.dptr != 0) { X memcpy (sgrbuf, content.dptr, content.dsize); X sgroup.sg_mem = members; X sgroup.sg_adm = admins; X sgr_unpack (sgrbuf, content.dsize, &sgroup); X return &sgroup; X } X } X#endif X while ((sgrp = getsgent ()) != (struct sgrp *) 0) { X if (strcmp (name, sgrp->sg_name) == 0) X return (sgrp); X } X return (0); X} X Xint Xputsgent (sgrp, fp) Xstruct sgrp *sgrp; XFILE *fp; X{ X char buf[sizeof sgrbuf]; X char *cp = buf; X int errors = 0; X int i; X X if (! fp || ! sgrp) X return -1; X X /* X * Copy the group name and passwd. X */ X X strcpy (cp, sgrp->sg_name); X cp += strlen (cp); X *cp++ = ':'; X X strcpy (cp, sgrp->sg_passwd); X cp += strlen (cp); X *cp++ = ':'; X X /* X * Copy the administrators, separating each from the other X * with a ",". X */ X X for (i = 0;sgrp->sg_adm[i];i++) { X if (i > 0) X *cp++ = ','; X X strcpy (cp, sgrp->sg_adm[i]); X cp += strlen (cp); X } X *cp++ = ':'; X X /* X * Now do likewise with the group members. X */ X X for (i = 0;sgrp->sg_mem[i];i++) { X if (i > 0) X *cp++ = ','; X X strcpy (cp, sgrp->sg_mem[i]); X cp += strlen (cp); X } X *cp++ = '\n'; X *cp = '\0'; X X /* X * Output using the function which understands the line X * continuation conventions. X */ X X return fputsx (buf, fp); X} SHAR_EOF if test 4652 -ne "`wc -c < 'gshadow.c'`" then echo shar: "error transmitting 'gshadow.c'" '(should have been 4652 characters)' fi fi echo shar: "extracting 'sppack.c'" '(2142 characters)' if test -f 'sppack.c' then echo shar: "will not over-write existing file 'sppack.c'" else sed 's/^X//' << \SHAR_EOF > 'sppack.c' X/* X * Copyright 1990, John F. Haugh II X * All rights reserved. X * X * Use, duplication, and disclosure prohibited without X * the express written permission of the author. X * X * Duplication is permitted for non-commercial [ profit making ] X * purposes provided this and other copyright notices remain X * intact. X */ X X#include <stdio.h> X#ifdef BSD X#include <strings.h> X#else X#include <string.h> X#endif X X#include "shadow.h" X X#ifndef lint Xstatic char sccsid[] = "@(#)sppack.c 3.1 08:16:27 11/21/90"; X#endif X Xint spw_pack (spwd, buf) Xstruct spwd *spwd; Xchar *buf; X{ X char *cp; X X cp = buf; X strcpy (cp, spwd->sp_namp); X cp += strlen (cp) + 1; X X strcpy (cp, spwd->sp_pwdp); X cp += strlen (cp) + 1; X X memcpy (cp, &spwd->sp_min, sizeof spwd->sp_min); X cp += sizeof spwd->sp_min; X X memcpy (cp, &spwd->sp_max, sizeof spwd->sp_max); X cp += sizeof spwd->sp_max; X X memcpy (cp, &spwd->sp_lstchg, sizeof spwd->sp_lstchg); X cp += sizeof spwd->sp_lstchg; X X memcpy (cp, &spwd->sp_warn, sizeof spwd->sp_warn); X cp += sizeof spwd->sp_warn; X X memcpy (cp, &spwd->sp_inact, sizeof spwd->sp_inact); X cp += sizeof spwd->sp_inact; X X memcpy (cp, &spwd->sp_expire, sizeof spwd->sp_expire); X cp += sizeof spwd->sp_expire; X X memcpy (cp, &spwd->sp_flag, sizeof spwd->sp_flag); X cp += sizeof spwd->sp_flag; X X return cp - buf; X} X Xint spw_unpack (buf, len, spwd) Xchar *buf; Xint len; Xstruct spwd *spwd; X{ X char *org = buf; X char *cp; X X spwd->sp_namp = buf; X buf += strlen (buf) + 1; X X spwd->sp_pwdp = buf; X buf += strlen (buf) + 1; X X memcpy (&spwd->sp_min, buf, sizeof spwd->sp_min); X buf += sizeof spwd->sp_min; X X memcpy (&spwd->sp_max, buf, sizeof spwd->sp_max); X buf += sizeof spwd->sp_max; X X memcpy (&spwd->sp_lstchg, buf, sizeof spwd->sp_lstchg); X buf += sizeof spwd->sp_lstchg; X X memcpy (&spwd->sp_warn, buf, sizeof spwd->sp_warn); X buf += sizeof spwd->sp_warn; X X memcpy (&spwd->sp_inact, buf, sizeof spwd->sp_inact); X buf += sizeof spwd->sp_inact; X X memcpy (&spwd->sp_expire, buf, sizeof spwd->sp_expire); X buf += sizeof spwd->sp_expire; X X memcpy (&spwd->sp_flag, buf, sizeof spwd->sp_flag); X buf += sizeof spwd->sp_flag; X X if (buf - org > len) X return -1; X X return 0; X} SHAR_EOF if test 2142 -ne "`wc -c < 'sppack.c'`" then echo shar: "error transmitting 'sppack.c'" '(should have been 2142 characters)' fi fi exit 0 # End of shell archive -- John F. Haugh II | Distribution to | UUCP: ...!cs.utexas.edu!rpp386!jfh Ma Bell: (512) 255-8251 | GEnie PROHIBITED :-) | Domain: jfh@rpp386.cactus.org "If liberals interpreted the 2nd Amendment the same way they interpret the rest of the Constitution, gun ownership would be mandatory."
jfh@rpp386.cactus.org (John F Haugh II) (05/16/91)
#! /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: # gspack.c # spdbm.c # lastlog.h # shell.c # login.c # sub.c # dpmain.c # mail.c # env.c # pwd.h # grpack.c # shadow.h # log.c # grent.c # motd.c # dialup.h # fields.c # gsdbm.c # This archive created: Sun Mar 3 13:27:34 1991 # By: John F Haugh II (River Parishes Programming, Austin TX) export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'gspack.c'" '(2890 characters)' if test -f 'gspack.c' then echo shar: "will not over-write existing file 'gspack.c'" else sed 's/^X//' << \SHAR_EOF > 'gspack.c' X/* X * Copyright 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include <stdio.h> X#include "shadow.h" X#ifdef BSD X#include <strings.h> X#else X#include <string.h> X#endif X X#ifndef lint Xstatic char sccsid[] = "@(#)gspack.c 3.1 09:13:50 12/13/90"; X#endif X X/* X * sgr_pack - convert a shadow group structure to a packed X * shadow group record X * X * sgr_pack takes the shadow group structure and packs X * the components in a record. this record will be X * unpacked later by sgr_unpack. X */ X Xint Xsgr_pack (sgrp, buf) Xstruct sgrp *sgrp; Xchar *buf; X{ X char *cp; X int i; X X /* X * The name and password are both easy - append each string X * to the buffer. These are always the first two strings X * in a record. X */ X X cp = buf; X strcpy (cp, sgrp->sg_name); X cp += strlen (cp) + 1; X X strcpy (cp, sgrp->sg_passwd); X cp += strlen (cp) + 1; X X /* X * The arrays of administrators and members are slightly X * harder. Each element is appended as a string, with a X * final '\0' appended to serve as a blank string. The X * number of elements is not known in advance, so the X * entire collection of administrators must be scanned to X * find the start of the members. X */ X X for (i = 0;sgrp->sg_adm[i];i++) { X strcpy (cp, sgrp->sg_adm[i]); X cp += strlen (cp) + 1; X } X *cp++ = '\0'; X X for (i = 0;sgrp->sg_mem[i];i++) { X strcpy (cp, sgrp->sg_mem[i]); X cp += strlen (cp) + 1; X } X *cp++ = '\0'; X X return cp - buf; X} X X/* X * sgr_unpack - convert a packed shadow group record to an X * unpacked record X * X * sgr_unpack converts a record which was packed by sgr_pack X * into the normal shadow group structure format. X */ X Xint Xsgr_unpack (buf, len, sgrp) Xchar *buf; Xint len; Xstruct sgrp *sgrp; X{ X char *org = buf; X int i; X X /* X * The name and password are both easy - they are the first X * two strings in the record. X */ X X sgrp->sg_name = buf; X buf += strlen (buf) + 1; X if (buf - org > len) X return -1; X X sgrp->sg_passwd = buf; X buf += strlen (buf) + 1; X if (buf - org > len) X return -1; X X /* X * The administrators and members are slightly more difficult. X * The arrays are lists of strings. Each list is terminated X * by a string of length zero. This string is detected by X * looking for an initial character of '\0'. X */ X X for (i = 0;*buf && i < 1024;i++) { X sgrp->sg_adm[i] = buf; X buf += strlen (buf) + 1; X X if (buf - org > len) X return -1; X } X sgrp->sg_adm[i] = (char *) 0; X if (! *buf) X buf++; X X for (i = 0;*buf && i < 1024;i++) { X sgrp->sg_mem[i] = buf; X buf += strlen (buf) + 1; X X if (buf - org > len) X return -1; X } X sgrp->sg_mem[i] = (char *) 0; X X return 0; X} SHAR_EOF if test 2890 -ne "`wc -c < 'gspack.c'`" then echo shar: "error transmitting 'gspack.c'" '(should have been 2890 characters)' fi fi echo shar: "extracting 'spdbm.c'" '(933 characters)' if test -f 'spdbm.c' then echo shar: "will not over-write existing file 'spdbm.c'" else sed 's/^X//' << \SHAR_EOF > 'spdbm.c' X/* X * Copyright 1990, John F. Haugh II X * All rights reserved. X * X * Use, duplication, and disclosure prohibited without X * the express written permission of the author. X */ X X#ifndef lint Xstatic char sccsid[] = "@(#)spdbm.c 3.1 08:16:16 11/21/90"; X#endif X X#include <string.h> X#include <stdio.h> X#include "config.h" X#include "shadow.h" X X#ifdef NDBM X#include <ndbm.h> XDBM *sp_dbm; X X/* X * sp_dbm_update X * X * Updates the DBM password files, if they exist. X */ X Xint Xsp_dbm_update (sp) Xstruct spwd *sp; X{ X datum key; X datum content; X char data[BUFSIZ]; X char spwdkey[60]; X char *cp; X int len; X int i; X int cnt; X static int once; X X if (! once) { X if (! sp_dbm) X setspent (); X X once++; X } X if (! sp_dbm) X return 0; X X len = spw_pack (sp, data); X X content.dsize = len; X content.dptr = data; X X key.dsize = strlen (sp->sp_namp); X key.dptr = sp->sp_namp; X if (dbm_store (sp_dbm, key, content, DBM_REPLACE)) X return 0; X X return 1; X} X#endif SHAR_EOF if test 933 -ne "`wc -c < 'spdbm.c'`" then echo shar: "error transmitting 'spdbm.c'" '(should have been 933 characters)' fi fi echo shar: "extracting 'lastlog.h'" '(511 characters)' if test -f 'lastlog.h' then echo shar: "will not over-write existing file 'lastlog.h'" else sed 's/^X//' << \SHAR_EOF > 'lastlog.h' X/* X * Copyright 1989, 1990, John F. Haugh II X * All rights reserved. X * X * Use, duplication, and disclosure prohibited without X * the express written permission of the author. X */ X X/* X * lastlog.h - structure of lastlog file X * X * @(#)lastlog.h 2.3 19:23:49 7/29/90 X * X * This file defines a lastlog file structure which should be sufficient X * to hold the information required by login. It should only be used if X * there is no real lastlog.h file. X */ X Xstruct lastlog { X time_t ll_time; X char ll_line[8]; X}; SHAR_EOF if test 511 -ne "`wc -c < 'lastlog.h'`" then echo shar: "error transmitting 'lastlog.h'" '(should have been 511 characters)' fi fi echo shar: "extracting 'shell.c'" '(2527 characters)' if test -f 'shell.c' then echo shar: "will not over-write existing file 'shell.c'" else sed 's/^X//' << \SHAR_EOF > 'shell.c' X/* X * Copyright 1989, 1990, 1991, John F. Haugh II X * All rights reserved. X * X * Use, duplication, and disclosure prohibited without X * the express written permission of the author. X */ X X#include <stdio.h> X#include <errno.h> X#ifndef BSD X#include <string.h> X#include <memory.h> X#else X#include <strings.h> X#define strchr index X#define strrchr rindex X#endif X#include "config.h" X X#ifndef lint Xstatic char _sccsid[] = "@(#)shell.c 3.2 07:55:08 2/6/91"; X#endif X Xextern char *newenvp[]; X X/* X * shell - execute the named program X * X * shell begins by trying to figure out what argv[0] is going to X * be for the named process. The user may pass in that argument, X * or it will be the last pathname component of the file with a X * '-' prepended. The first attempt is to just execute the named X * file. If the errno comes back "ENOEXEC", the file is assumed X * at first glance to be a shell script. The first two characters X * must be "#!", in which case "/bin/sh" is executed to process X * the file. If all that fails, give up in disgust ... X */ X Xvoid shell (file, arg) Xchar *file; Xchar *arg; X{ X char arg0[BUFSIZ]; X FILE *fp; X char *path; X int err; X X if (file == (char *) 0) X exit (1); X X /* X * The argv[0]'th entry is usually the path name, but X * for various reasons the invoker may want to override X * that. So, we determine the 0'th entry only if they X * don't want to tell us what it is themselves. X */ X X if (arg == (char *) 0) { X if (path = strrchr (file, '/')) X path++; X else X path = file; X X (void) strcpy (arg0 + 1, path); X arg0[0] = '-'; X arg = arg0; X } X#ifndef NDEBUG X printf ("Executing shell %s\n", file); X#endif X X /* X * First we try the direct approach. The system should be X * able to figure out what we are up to without too much X * grief. X */ X X execle (file, arg, (char *) 0, newenvp); X err = errno; X X /* X * It is perfectly OK to have a shell script for a login X * shell, and this code attempts to support that. It X * relies on the standard shell being able to make sense X * of the "#!" magic number. X */ X X if (err == ENOEXEC) { X if (fp = fopen (file, "r")) { X if (getc (fp) == '#' && getc (fp) == '!') { X fclose (fp); X execle ("/bin/sh", "sh", X file, (char *) 0, newenvp); X err = errno; X } else { X fclose (fp); X } X } X } X X /* X * Obviously something is really wrong - I can't figure out X * how to execute this stupid shell, so I might as well give X * up in disgust ... X */ X X sprintf (arg0, "Cannot execute %s", file); X errno = err; X perror (arg0); X exit (err); X} SHAR_EOF if test 2527 -ne "`wc -c < 'shell.c'`" then echo shar: "error transmitting 'shell.c'" '(should have been 2527 characters)' fi fi echo shar: "extracting 'login.c'" '(1164 characters)' if test -f 'login.c' then echo shar: "will not over-write existing file 'login.c'" else sed 's/^X//' << \SHAR_EOF > 'login.c' X/* X * Copyright 1989, 1990, John F. Haugh II X * All rights reserved. X * X * Use, duplication, and disclosure prohibited without X * the express written permission of the author. X */ X X#include <stdio.h> X#include <ctype.h> X#ifndef BSD X#include <string.h> X#include <memory.h> X#else X#include <strings.h> X#define strchr index X#define strrchr rindex X#endif X X#ifndef lint Xstatic char sccsid[] = "@(#)login.c 2.3 19:23:55 7/29/90"; X#endif X Xvoid setenv (); X Xvoid login (name) Xchar *name; X{ X char buf[BUFSIZ]; X char *envp[32]; X int envc; X char *cp; X int i; X X#ifndef BSD X (void) memset (buf, '\0', sizeof buf); X#else X bzero (buf, sizeof buf); X#endif X fputs ("login: ", stdout); X X if (fgets (buf, BUFSIZ, stdin) != buf) X exit (1); X X buf[strlen (buf) - 1] = '\0'; /* remove \n [ must be there ] */ X X for (cp = buf;*cp == ' ' || *cp == '\t';cp++) X ; X X for (i = 0;i < BUFSIZ - 1 && isgraph (*cp);name[i++] = *cp++) X ; X X if (*cp) X cp++; X X name[i] = '\0'; X X if (*cp != '\0') { /* process new variables */ X for (envc = 0;envc < 32;envc++) { X envp[envc] = strtok (envc == 0 ? cp:(char *) 0, " \t,"); X X if (envp[envc] == (char *) 0) X break; X } X setenv (envc, envp); X } X} SHAR_EOF if test 1164 -ne "`wc -c < 'login.c'`" then echo shar: "error transmitting 'login.c'" '(should have been 1164 characters)' fi fi echo shar: "extracting 'sub.c'" '(1538 characters)' if test -f 'sub.c' then echo shar: "will not over-write existing file 'sub.c'" else sed 's/^X//' << \SHAR_EOF > 'sub.c' X/* X * Copyright 1989, 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include <sys/types.h> X#include <syslog.h> X X#include "pwd.h" X X#ifndef lint Xstatic char sccsid[] = "@(#)sub.c 3.2 08:22:12 1/30/91"; X#endif X X#define BAD_SUBROOT "Invalid root directory \"%s\"\n" X#define BAD_SUBROOT2 "invalid root `%s' for user `%s'\n" X#define NO_SUBROOT "Can't change root directory to \"%s\"\n" X#define NO_SUBROOT2 "no subsystem root `%s' for user `%s'\n" X X/* X * subsystem - change to subsystem root X * X * A subsystem login is indicated by the presense of a "*" as X * the first character of the login shell. The given home X * directory will be used as the root of a new filesystem which X * the user is actually logged into. X */ X Xvoid subsystem (pw) Xstruct passwd *pw; X{ X /* X * The new root directory must begin with a "/" character. X */ X X if (pw->pw_dir[0] != '/') { X printf (BAD_SUBROOT, pw->pw_dir); X syslog (LOG_WARN, BAD_SUBROOT2, pw->pw_dir, pw->pw_name); X exit (1); X } X X /* X * The directory must be accessible and the current process X * must be able to change into it. X */ X X if (chdir (pw->pw_dir) || chroot (pw->pw_dir)) { X printf (NO_SUBROOT, pw->pw_dir); X syslog (LOG_WARN, NO_SUBROOT2, pw->pw_dir, pw->pw_name); X exit (1); X } X} SHAR_EOF if test 1538 -ne "`wc -c < 'sub.c'`" then echo shar: "error transmitting 'sub.c'" '(should have been 1538 characters)' fi fi echo shar: "extracting 'dpmain.c'" '(2895 characters)' if test -f 'dpmain.c' then echo shar: "will not over-write existing file 'dpmain.c'" else sed 's/^X//' << \SHAR_EOF > 'dpmain.c' X/* X * Copyright 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include <sys/types.h> X#include <sys/stat.h> X#include <stdio.h> X#include <fcntl.h> X#ifdef BSD X#include <strings.h> X#else X#include <string.h> X#endif X#include "dialup.h" X X#ifndef lint Xstatic char sccsid[] = "@(#)dpmain.c 3.2 12:30:37 12/12/90"; X#endif X X#define DTMP "/etc/d_passwd.tmp" X X/* X * Prompts and messages go here. X */ X X#define PASS1 "Shell password:" X#define PASS2 "re-enter Shell password:" X#define NOMATCH "%s: Passwords do not match, try again.\n" X#define NOFOUND "%s: Shell %s not found.\n" X Xint aflg; Xint dflg; Xchar *Prog; X Xextern char *pw_encrypt(); Xextern char *getpass(); X Xusage () X{ X fprintf (stderr, "Usage: %s -a|c|d shell\n", Prog); X exit (1); X} X Xmain (argc, argv) Xint argc; Xchar **argv; X{ X struct dialup *dial; X struct dialup dent; X struct stat sb; X FILE *fp; X char *shell; X char *cp; X char pass[BUFSIZ]; X int fd; X int found = 0; X int opt; X extern int optind; X extern char *optarg; X X if (Prog = strrchr (argv[0], '/')) X Prog++; X else X Prog = argv[0]; X X while ((opt = getopt (argc, argv, "a:d:")) != EOF) { X switch (opt) { X case 'a': X aflg++; X shell = optarg; X break; X case 'd': X dflg++; X shell = optarg; X break; X default: X usage (); X } X } X if (aflg + dflg != 1) X usage (); X X if (aflg) { X dent.du_shell = shell; X dent.du_passwd = ""; X X if (! (cp = getpass (PASS1))) { X unlink (DTMP); X exit (1); X } X strcpy (pass, cp); X if (! (cp = getpass (PASS2))) { X unlink (DTMP); X exit (1); X } X if (strcmp (pass, cp)) { X fprintf (stderr, NOMATCH, Prog); X unlink (DTMP); X exit (1); X } X dent.du_passwd = pw_encrypt (pass, (char *) 0); X } X if ((fd = open (DTMP, O_CREAT|O_EXCL|O_RDWR, 0600)) < 0) { X sprintf (pass, "%s: can't create %s", Prog, DTMP); X perror (pass); X exit (1); X } X if (! (fp = fdopen (fd, "r+"))) { X sprintf (pass, "%s: can't open %s", Prog, DTMP); X perror (pass); X exit (1); X } X while (dial = getduent ()) { X if (strcmp (dial->du_shell, shell) == 0) { X found = 1; X break; X } X if (putduent (dial, fp)) X goto failure; X } X if (dflg && ! found) { X fprintf (stderr, NOMATCH, Prog, shell); X exit (1); X } X if (aflg) X if (putduent (&dent, fp)) X goto failure; X X while (dial = getduent ()) X if (putduent (dial, fp)) X goto failure; X X if (fflush (fp)) X goto failure; X X if (! stat (DIALPWD, &sb)) { X chown (DTMP, sb.st_uid, sb.st_gid); X chmod (DTMP, sb.st_mode); X unlink (DIALPWD); X } else { X chown (DTMP, 0, 0); X chmod (DTMP, 0400); X } X link (DTMP, DIALPWD); X unlink (DTMP); X X sync (); X exit (0); X Xfailure: X unlink (DTMP); X exit (1); X} SHAR_EOF if test 2895 -ne "`wc -c < 'dpmain.c'`" then echo shar: "error transmitting 'dpmain.c'" '(should have been 2895 characters)' fi fi echo shar: "extracting 'mail.c'" '(998 characters)' if test -f 'mail.c' then echo shar: "will not over-write existing file 'mail.c'" else sed 's/^X//' << \SHAR_EOF > 'mail.c' X/* X * Copyright 1989, 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include <sys/types.h> X#include <sys/stat.h> X X#ifndef BSD X#include <string.h> X#include <memory.h> X#else X#include <strings.h> X#define strchr index X#define strrchr rindex X#endif X X#include "config.h" X#ifdef MAILCHECK X X#ifndef lint Xstatic char sccsid[] = "@(#)mail.c 3.2 13:28:27 12/19/90"; X#endif X Xextern char *getenv(); X Xvoid mailcheck () X{ X struct stat statbuf; X char *mailbox; X X if (! (mailbox = getenv ("MAIL"))) X return; X X if (stat (mailbox, &statbuf) == -1 || statbuf.st_size == 0) X puts ("No mail."); X else if (statbuf.st_atime > statbuf.st_mtime) X puts ("You have mail."); X else X puts ("You have new mail."); X} X#endif SHAR_EOF if test 998 -ne "`wc -c < 'mail.c'`" then echo shar: "error transmitting 'mail.c'" '(should have been 998 characters)' fi fi echo shar: "extracting 'env.c'" '(1788 characters)' if test -f 'env.c' then echo shar: "will not over-write existing file 'env.c'" else sed 's/^X//' << \SHAR_EOF > 'env.c' X/* X * Copyright 1989, 1990, John F. Haugh II X * All rights reserved. X * X * Use, duplication, and disclosure prohibited without X * the express written permission of the author. X */ X X#include <stdio.h> X#ifndef BSD X#include <string.h> X#else X#define strchr index X#define strrchr rindex X#include <strings.h> X#endif X X#ifndef lint Xstatic char _sccsid[] = "@(#)env.c 2.2 19:23:43 7/29/90"; X#endif X Xextern char **environ; Xextern char *newenvp[]; Xextern int newenvc; Xextern int maxenv; X Xchar *strdup (); Xvoid free (); X Xstatic char *forbid[] = { X "HOME", X "IFS", X "PATH", X "SHELL", X (char *) 0 X}; X Xvoid addenv (entry) Xchar *entry; X{ X char *cp; X int i; X int len; X X if (cp = strchr (entry, '=')) X len = cp - entry; X else X return; X X for (i = 0;i < newenvc;i++) X if (strncmp (entry, newenvp[i], len) == 0 && X (newenvp[i][len] == '=' || newenvp[i][len] == '\0')) X break; X X if (i == maxenv) { X puts ("Environment overflow"); X return; X } X if (i == newenvc) { X newenvp[newenvc++] = strdup (entry); X } else { X free (newenvp[i]); X newenvp[i] = strdup (entry); X } X} X Xvoid setenv (argc, argv) Xint argc; Xchar **argv; X{ X int i; X int n; X int noname = 1; X char variable[BUFSIZ]; X char *cp; X X for (i = 0;i < argc;i++) { X if ((n = strlen (argv[i])) >= BUFSIZ) X continue; /* ignore long entries */ X X if (! (cp = strchr (argv[i], '='))) { X (void) strcpy (variable, argv[i]); X } else { X (void) strncpy (variable, argv[i], cp - argv[i]); X variable[cp - argv[i]] = '\0'; X } X for (n = 0;forbid[n] != (char *) 0;n++) X if (strcmp (variable, forbid[n]) == 0) X break; X X if (forbid[n] != (char *) 0) { X printf ("You may not change $%s\n", forbid[n]); X continue; X } X if (cp) { X addenv (argv[i]); X } else { X sprintf (variable, "L%d=%s", noname++, argv[i]); X addenv (variable); X } X } X} SHAR_EOF if test 1788 -ne "`wc -c < 'env.c'`" then echo shar: "error transmitting 'env.c'" '(should have been 1788 characters)' fi fi echo shar: "extracting 'pwd.h'" '(2383 characters)' if test -f 'pwd.h' then echo shar: "will not over-write existing file 'pwd.h'" else sed 's/^X//' << \SHAR_EOF > 'pwd.h' X/* X * Copyright 1990, John F. Haugh II and Steve Simmons X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X/* X * Standard definitions for password files. This is an independant X * reimplementation of the definitions used by AT&T, BSD, and POSIX. X * It is not derived from any of those sources. Note that it can be X * site-defined to have non-POSIX features as well. X * X * $RCSfile$ $Revision$ X * X * $Author$ $Date$ X * X * $State$ $Locker$ X * X * $Log$ X */ X X#ifndef PWD_H X#define PWD_H X X#include <sys/types.h> X X/* X * For now these are defined here. Later they should be moved to X * the configuration file or this file should be generated by X * a configurator. X */ X X#undef BSD_QUOTAS X#define ATT_AGE X#define ATT_COMMENT X X/* X * This is the data structure returned by the getpw* functions. The X * names of the elements and the structure are taken from traditional X * usage. X */ X Xstruct passwd { X char *pw_name ; /* User login name */ X char *pw_passwd ; /* Encrypted passwd or dummy field */ X uid_t pw_uid ; /* User uid number */ X gid_t pw_gid ; /* User group id number */ X#ifdef BSD_QUOTAS X /* Most BSD systems have quotas, most USG ones don't */ X int pw_quota ; /* The BSD magic doodah */ X#endif X#ifdef ATT_AGE X /* Use ATT-style password aging */ X char *pw_age ; /* ATT radix-64 encoded data */ X#endif X#ifdef ATT_COMMENT X /* Provide the unused comment field */ X char *pw_comment; /* Unused comment field */ X#endif X char *pw_gecos ; /* ASCII user name, other data */ X char *pw_dir ; /* User home directory */ X char *pw_shell ; /* User startup shell */ X} ; X X#ifdef ATT_COMMENT X/* Provide the unused comment structure */ Xstruct comment { X char *c_dept; X char *c_name; X char *c_acct; X char *c_bin; X}; X#endif X X#ifdef __STDC__ X Xextern struct passwd *getpwent( void ) ; Xextern struct passwd *getpwuid( uid_t user_uid ) ; Xextern struct passwd *getpwnam( char *name ) ; Xint setpwent( void ); Xint endpwent( void ); X X#else X Xextern struct passwd *getpwent(); Xextern struct passwd *getpwuid(); Xextern struct passwd *getpwnam(); Xint setpwent(); Xint endpwent(); X X#endif /* of ifdef __STDC__ */ X X#endif /* of ifdef PWD_H */ SHAR_EOF if test 2383 -ne "`wc -c < 'pwd.h'`" then echo shar: "error transmitting 'pwd.h'" '(should have been 2383 characters)' fi fi echo shar: "extracting 'grpack.c'" '(1512 characters)' if test -f 'grpack.c' then echo shar: "will not over-write existing file 'grpack.c'" else sed 's/^X//' << \SHAR_EOF > 'grpack.c' X/* X * Copyright 1990, John F. Haugh II X * All rights reserved. X * X * Use, duplication, and disclosure prohibited without X * the express written permission of the author. X * X * Duplication is permitted for non-commercial [ profit making ] X * purposes provided this and other copyright notices remain X * intact. X */ X X#include <stdio.h> X#include <grp.h> X#ifdef BSD X#include <strings.h> X#else X#include <string.h> X#endif X X#ifndef lint Xstatic char sccsid[] = "@(#)grpack.c 3.2 08:11:20 11/21/90"; X#endif X Xint gr_pack (group, buf) Xstruct group *group; Xchar *buf; X{ X char *cp; X int i; X X cp = buf; X strcpy (cp, group->gr_name); X cp += strlen (cp) + 1; X X strcpy (cp, group->gr_passwd); X cp += strlen (cp) + 1; X X memcpy (cp, (void *) &group->gr_gid, sizeof group->gr_gid); X cp += sizeof group->gr_gid; X X for (i = 0;group->gr_mem[i];i++) { X strcpy (cp, group->gr_mem[i]); X cp += strlen (cp) + 1; X } X *cp++ = '\0'; X X return cp - buf; X} X Xint gr_unpack (buf, len, group) Xchar *buf; Xint len; Xstruct group *group; X{ X char *org = buf; X int i; X X group->gr_name = buf; X buf += strlen (buf) + 1; X if (buf - org > len) X return -1; X X group->gr_passwd = buf; X buf += strlen (buf) + 1; X if (buf - org > len) X return -1; X X memcpy ((void *) &group->gr_gid, (void *) buf, sizeof group->gr_gid); X buf += sizeof group->gr_gid; X if (buf - org > len) X return -1; X X for (i = 0;*buf && i < 1024;i++) { X group->gr_mem[i] = buf; X buf += strlen (buf) + 1; X X if (buf - org > len) X return -1; X } X group->gr_mem[i] = (char *) 0; X return 0; X} SHAR_EOF if test 1512 -ne "`wc -c < 'grpack.c'`" then echo shar: "error transmitting 'grpack.c'" '(should have been 1512 characters)' fi fi echo shar: "extracting 'shadow.h'" '(1823 characters)' if test -f 'shadow.h' then echo shar: "will not over-write existing file 'shadow.h'" else sed 's/^X//' << \SHAR_EOF > 'shadow.h' X/* X * Copyright 1988, 1989, 1990, John F. Haugh II X * All rights reserved. X * X * Use, duplication, and disclosure prohibited without X * the express written permission of the author. X */ X X#ifndef _H_SHADOW X#define _H_SHADOW X X/* X * This information is not derived from AT&T licensed sources. Posted X * to the USENET 11/88, and updated 11/90 with information from SVR4. X * X * @(#)shadow.h 3.3 09:06:50 12/7/90 X */ X X#ifdef ITI_AGING Xtypedef time_t sptime; X#else Xtypedef long sptime; X#endif X X/* X * Shadow password security file structure. X */ X Xstruct spwd { X char *sp_namp; /* login name */ X char *sp_pwdp; /* encrypted password */ X sptime sp_lstchg; /* date of last change */ X sptime sp_min; /* minimum number of days between changes */ X sptime sp_max; /* maximum number of days between changes */ X sptime sp_warn; /* number of days of warning before password X expires */ X sptime sp_inact; /* number of days after password expires X until the account becomes unusable. */ X sptime sp_expire; /* days since 1/1/70 until account expires */ X unsigned long sp_flag; /* reserved for future use */ X}; X X/* X * Shadow password security file functions. X */ X Xstruct spwd *getspent (); Xstruct spwd *getspnam (); Xstruct spwd *sgetspent (); Xstruct spwd *fgetspent (); Xvoid setspent (); Xvoid endspent (); Xint putspent (); X X#define SHADOW "/etc/shadow" X X/* X * Shadow group security file structure X */ X Xstruct sgrp { X char *sg_name; /* group name */ X char *sg_passwd; /* group password */ X char **sg_adm; /* group administator list */ X char **sg_mem; /* group membership list */ X}; X X/* X * Shadow group security file functions. X */ X Xstruct sgrp *getsgent (); Xstruct sgrp *getsgnam (); Xstruct sgrp *sgetsgent (); Xstruct sgrp *fgetsgent (); Xvoid setsgent (); Xvoid endsgent (); Xint putsgent (); X X#define GSHADOW "/etc/gshadow" X#endif SHAR_EOF if test 1823 -ne "`wc -c < 'shadow.h'`" then echo shar: "error transmitting 'shadow.h'" '(should have been 1823 characters)' fi fi echo shar: "extracting 'log.c'" '(1543 characters)' if test -f 'log.c' then echo shar: "will not over-write existing file 'log.c'" else sed 's/^X//' << \SHAR_EOF > 'log.c' X/* X * Copyright 1989, 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include <sys/types.h> X#include <utmp.h> X#include "pwd.h" X#include <fcntl.h> X#include <time.h> X#ifndef BSD X#include <string.h> X#include <memory.h> X#else X#include <strings.h> X#define strchr index X#define strrchr rindex X#endif X#include "config.h" X X#ifndef lint Xstatic char sccsid[] = "@(#)log.c 3.1 12:30:53 12/12/90"; X#endif X X#ifdef LASTLOG X X#include "lastlog.h" X Xextern struct utmp utent; Xextern struct passwd pwent; Xextern struct lastlog lastlog; Xextern char **environ; X Xlong lseek (); Xtime_t time (); X Xvoid log () X{ X int fd; X off_t offset; X struct lastlog newlog; X X if ((fd = open ("/usr/adm/lastlog", O_RDWR)) == -1) X return; X X offset = pwent.pw_uid * sizeof lastlog; X X if (lseek (fd, offset, 0) != offset) { X (void) close (fd); X return; X } X if (read (fd, (char *) &lastlog, sizeof lastlog) != sizeof lastlog) X#ifndef BSD X memset ((char *) &lastlog, sizeof lastlog, 0); X#else X bzero ((char *) &lastlog, sizeof lastlog); X#endif X newlog = lastlog; X X (void) time (&newlog.ll_time); X (void) strncpy (newlog.ll_line, utent.ut_line, sizeof newlog.ll_line); X (void) lseek (fd, offset, 0); X (void) write (fd, (char *) &newlog, sizeof newlog); X (void) close (fd); X} X#endif SHAR_EOF if test 1543 -ne "`wc -c < 'log.c'`" then echo shar: "error transmitting 'log.c'" '(should have been 1543 characters)' fi fi echo shar: "extracting 'grent.c'" '(9437 characters)' if test -f 'grent.c' then echo shar: "will not over-write existing file 'grent.c'" else sed 's/^X//' << \SHAR_EOF > 'grent.c' X/* X * Copyright 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#include <stdio.h> X#include <grp.h> X#ifdef BSD X#include <strings.h> X#define strchr index X#define strrchr rindex X#else /* !BSD */ X#include <string.h> X#endif /* BSD */ X#include "config.h" X X#ifdef AUTOSHADOW X#include "shadow.h" X#endif /* AUTOSHADOW */ X X#ifdef NDBM X#include <ndbm.h> X#include <fcntl.h> XDBM *gr_dbm; Xint gr_dbm_mode = -1; X#endif /* NDBM */ X X#ifndef lint Xstatic char sccsid[] = "@(#)grent.c 3.7 08:03:08 12/20/90"; X#endif /* !lint */ X X#define NFIELDS 4 X#define MAXMEM 1024 X Xstatic char grpbuf[4*BUFSIZ]; Xstatic char *grpfields[NFIELDS]; Xstatic char *members[MAXMEM+1]; Xstatic struct group grent; X Xstatic FILE *grpfp; Xstatic char *grpfile = GRPFILE; X#ifdef NDBM Xstatic int dbmopened; Xstatic int dbmerror; X#endif /* NDBM */ X Xchar * Xfgetsx (buf, cnt, f) Xchar *buf; Xint cnt; XFILE *f; X{ X int c; X char *cp = buf; X char *ep; X X while (cnt > 0) { X if (fgets (cp, cnt, f) == 0) X if (cp == buf) X return 0; X else X break; X X if ((ep = strrchr (cp, '\\')) && *(ep + 1) == '\n') { X if ((cnt -= ep - cp) > 0) X *(cp = ep) = '\0'; X } else X break; X } X return buf; X} X Xint Xfputsx (s, stream) Xchar *s; XFILE *stream; X{ X int i; X X for (i = 0;*s;i++, s++) { X if (putc (*s, stream) == EOF) X return EOF; X X if (i > (BUFSIZ/2)) { X if (putc ('\\', stream) == EOF || X putc ('\n', stream) == EOF) X return EOF; X X i = 0; X } X } X return 0; X} X Xstatic char ** Xlist (s) Xchar *s; X{ X int nmembers = 0; X X while (*s) { X members[nmembers++] = s; X if (s = strchr (s, ',')) X *s++ = '\0'; X } X members[nmembers] = (char *) 0; X return members; X} X Xstruct group *sgetgrent (buf) Xchar *buf; X{ X int i; X char *cp; X X strncpy (grpbuf, buf, sizeof grpbuf); X grpbuf[sizeof grpbuf - 1] = '\0'; X if (cp = strrchr (grpbuf, '\n')) X *cp = '\0'; X X for (cp = grpbuf, i = 0;i < NFIELDS && cp;i++) { X grpfields[i] = cp; X if (cp = strchr (cp, ':')) X *cp++ = 0; X } X if (i < (NFIELDS-1) || *grpfields[2] == '\0') X return ((struct group *) 0); X X grent.gr_name = grpfields[0]; X grent.gr_passwd = grpfields[1]; X grent.gr_gid = atoi (grpfields[2]); X grent.gr_mem = list (grpfields[3]); X X return (&grent); X} X Xint Xputgrent (g, f) Xstruct group *g; XFILE *f; X{ X int i; X char *cp; X char buf[BUFSIZ*4]; X X if (! g || ! f) X return -1; X X sprintf (buf, "%s:%s:%d:", g->gr_name, g->gr_passwd, g->gr_gid); X if (g->gr_mem) { X cp = strchr (buf, '\0'); X for (i = 0;g->gr_mem[i];i++) { X if ((cp - buf) + strlen (g->gr_mem[i]) + 2 X >= sizeof buf) X return -1; X X if (i > 0) { X strcpy (cp, ","); X cp++; X } X strcpy (cp, g->gr_mem[i]); X cp = strchr (cp, '\0'); X } X strcat (cp, "\n"); X } else X strcat (buf, "\n"); X X if (fputsx (buf, f) == EOF || ferror (f)) X return -1; X X return 0; X} X X/* X * fgetgrent - get a group file entry from a stream X * X * fgetgrent() reads the next line from a group file formatted stream X * and returns a pointer to the group structure for that line. X */ X Xstruct group *fgetgrent (fp) XFILE *fp; X{ X char buf[BUFSIZ*4]; X char *cp; X X if (fgetsx (buf, sizeof buf, fp) != (char *) 0) { X if (cp = strchr (buf, '\n')) X *cp = '\0'; X X return (sgetgrent (buf)); X } X return 0; X} X X/* X * endgrent - close a group file X * X * endgrent() closes the group file if open. X */ X Xint endgrent () X{ X if (grpfp) X if (fclose (grpfp)) X return -1; X X grpfp = 0; X#ifdef NDBM X if (dbmopened && gr_dbm) { X dbm_close (gr_dbm); X gr_dbm = 0; X } X dbmopened = 0; X dbmerror = 0; X#endif /* NDBM */ X return 0; X} X X/* X * getgrent - get a group entry from the group file X * X * getgrent() opens the group file, if not already opened, and reads X * a single entry. NULL is returned if any errors are encountered reading X * the group file. X */ X Xstruct group *getgrent () X{ X if (! grpfp && setgrent ()) X return 0; X X return fgetgrent (grpfp); X} X X/* X * getgrgid - locate the group entry for a given GID X * X * getgrgid() locates the first group file entry for the given GID. X * If there is a valid DBM file, the DBM files are queried first for X * the entry. Otherwise, a linear search is begun of the group file X * searching for an entry which matches the provided GID. X */ X Xstruct group *getgrgid (gid) Xint gid; X{ X struct group *grp; X#ifdef NDBM X datum key; X datum content; X int cnt; X int i; X char *cp; X char grpkey[64]; X#endif /* NDBM */ X#ifdef AUTOSHADOW X struct sgrp *sgrp; X#endif /* AUTOSHADOW */ X X if (setgrent ()) X return 0; X X#ifdef NDBM X X /* X * If the DBM file are now open, create a key for this GID and X * try to fetch the entry from the database. A matching record X * will be unpacked into a static structure and returned to X * the user. X */ X X if (dbmopened) { X grent.gr_gid = gid; X key.dsize = sizeof grent.gr_gid; X key.dptr = (char *) &grent.gr_gid; X content = dbm_fetch (gr_dbm, key); X if (content.dptr == 0) X return 0; X X if (content.dsize == sizeof (int)) { X memcpy (&cnt, content.dptr, content.dsize); X for (cp = grpbuf, i = 0;i < cnt;i++) { X memcpy (grpkey, &i, sizeof i); X memcpy (grpkey + sizeof i, &grent.gr_gid, X sizeof grent.gr_gid); X X key.dsize = sizeof i + sizeof grent.gr_gid; X key.dptr = grpkey; X X content = dbm_fetch (gr_dbm, key); X if (content.dptr == 0) X return 0; X X memcpy (cp, content.dptr, content.dsize); X cp += content.dsize; X } X grent.gr_mem = members; X gr_unpack (grpbuf, cp - grpbuf, &grent); X#ifdef AUTOSHADOW X if (sgrp = getsgnam (grent.gr_name)) { X grent.gr_passwd = sgrp->sg_passwd; X grent.gr_mem = sgrp->sg_mem; X } X#endif /* AUTOSHADOW */ X return &grent; X } else { X grent.gr_mem = members; X memcpy (grpbuf, content.dptr, content.dsize); X gr_unpack (grpbuf, content.dsize, &grent); X#ifdef AUTOSHADOW X if (sgrp = getsgnam (grent.gr_name)) { X grent.gr_passwd = sgrp->sg_passwd; X grent.gr_mem = sgrp->sg_mem; X } X#endif /* AUTOSHADOW */ X return &grent; X } X } X#endif /* NDBM */ X /* X * Search for an entry which matches the GID. Return the X * entry when a match is found. X */ X X while (grp = getgrent ()) X if (grp->gr_gid == gid) X break; X X#ifdef AUTOSHADOW X if (grp) { X if (sgrp = getsgnam (grent.gr_name)) { X grp->gr_passwd = sgrp->sg_passwd; X grp->gr_mem = sgrp->sg_mem; X } X } X#endif /* AUTOSHADOW */ X return grp; X} X Xstruct group *getgrnam (name) Xchar *name; X{ X struct group *grp; X#ifdef NDBM X datum key; X datum content; X int cnt; X int i; X char *cp; X char grpkey[64]; X#endif /* NDBM */ X#ifdef AUTOSHADOW X struct sgrp *sgrp; X#endif /* AUTOSHADOW */ X X if (setgrent ()) X return 0; X X#ifdef NDBM X X /* X * If the DBM file are now open, create a key for this GID and X * try to fetch the entry from the database. A matching record X * will be unpacked into a static structure and returned to X * the user. X */ X X if (dbmopened) { X key.dsize = strlen (name); X key.dptr = name; X content = dbm_fetch (gr_dbm, key); X if (content.dptr == 0) X return 0; X X if (content.dsize == sizeof (int)) { X memcpy (&cnt, content.dptr, content.dsize); X for (cp = grpbuf, i = 0;i < cnt;i++) { X memcpy (grpkey, &i, sizeof i); X strcpy (grpkey + sizeof i, name); X X key.dsize = sizeof i + strlen (name); X key.dptr = grpkey; X X content = dbm_fetch (gr_dbm, key); X if (content.dptr == 0) X return 0; X X memcpy (cp, content.dptr, content.dsize); X cp += content.dsize; X } X grent.gr_mem = members; X gr_unpack (grpbuf, cp - grpbuf, &grent); X#ifdef AUTOSHADOW X if (sgrp = getsgnam (grent.gr_name)) { X grent.gr_passwd = sgrp->sg_passwd; X grent.gr_mem = sgrp->sg_mem; X } X#endif /* AUTOSHADOW */ X return &grent; X } else { X grent.gr_mem = members; X memcpy (grpbuf, content.dptr, content.dsize); X gr_unpack (grpbuf, content.dsize, &grent); X#ifdef AUTOSHADOW X if (sgrp = getsgnam (grent.gr_name)) { X grent.gr_passwd = sgrp->sg_passwd; X grent.gr_mem = sgrp->sg_mem; X } X#endif /* AUTOSHADOW */ X return &grent; X } X } X#endif /* NDBM */ X /* X * Search for an entry which matches the name. Return the X * entry when a match is found. X */ X X while (grp = getgrent ()) X if (strcmp (grp->gr_name, name) == 0) X break; X X#ifdef AUTOSHADOW X if (grp) { X if (sgrp = getsgnam (grent.gr_name)) { X grp->gr_passwd = sgrp->sg_passwd; X grp->gr_mem = sgrp->sg_mem; X } X } X#endif /* AUTOSHADOW */ X return 0; X} X X/* X * setgrent - open the group file X * X * setgrent() opens the system group file, and the DBM group files X * if they are present. The system group file is rewound if it was X * open already. X */ X Xint Xsetgrent () X{ X#ifdef NDBM X int mode; X#endif /* NDBM */ X X if (! grpfp) { X if (! (grpfp = fopen (grpfile, "r"))) X return -1; X } else { X if (fseek (grpfp, 0L, 0) != 0) X return -1; X } X X /* X * Attempt to open the DBM files if they have never been opened X * and an error has never been returned. X */ X X#ifdef NDBM X if (! dbmerror && ! dbmopened) { X char dbmfiles[BUFSIZ]; X X strcpy (dbmfiles, grpfile); X strcat (dbmfiles, ".pag"); X if (gr_dbm_mode == -1) X mode = O_RDONLY; X else X mode = (gr_dbm_mode == O_RDONLY || X gr_dbm_mode == O_RDWR) ? gr_dbm_mode:O_RDONLY; X X if (access (dbmfiles, 0) || X (! (gr_dbm = dbm_open (grpfile, mode, 0)))) X dbmerror = 1; X else X dbmopened = 1; X } X#endif /* NDBM */ X return 0; X} SHAR_EOF if test 9437 -ne "`wc -c < 'grent.c'`" then echo shar: "error transmitting 'grent.c'" '(should have been 9437 characters)' fi fi echo shar: "extracting 'motd.c'" '(750 characters)' if test -f 'motd.c' then echo shar: "will not over-write existing file 'motd.c'" else sed 's/^X//' << \SHAR_EOF > 'motd.c' X/* X * Copyright 1989, 1990, John F. Haugh II X * All rights reserved. X * X * Use, duplication, and disclosure prohibited without X * the express written permission of the author. X */ X X#include <stdio.h> X#ifndef BSD X#include <string.h> X#include <memory.h> X#else X#include <strings.h> X#define strchr index X#define strrchr rindex X#endif X#include "config.h" X X#ifndef lint Xstatic char _sccsid[] = "@(#)motd.c 2.2 19:23:58 7/29/90"; X#endif X Xextern char home[]; X#ifdef HUSHLOGIN Xextern int hushed; X#endif X X#ifdef MOTD Xvoid motd () X{ X FILE *fp; X register int c; X X#ifdef HUSHLOGIN X if (hushed) X return; X#endif X if ((fp = fopen ("/etc/motd", "r")) == (FILE *) 0) X return; X X while ((c = getc (fp)) != EOF) X putchar (c); X X fclose (fp); X fflush (stdout); X} X#endif SHAR_EOF if test 750 -ne "`wc -c < 'motd.c'`" then echo shar: "error transmitting 'motd.c'" '(should have been 750 characters)' fi fi echo shar: "extracting 'dialup.h'" '(1598 characters)' if test -f 'dialup.h' then echo shar: "will not over-write existing file 'dialup.h'" else sed 's/^X//' << \SHAR_EOF > 'dialup.h' X/* X * Copyright 1989, 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X/* X * Structure of the /etc/d_passwd file X * X * The d_passwd file contains the names of login shells which require X * dialup passwords. Each line contains the fully qualified path name X * for the shell, followed by an optional password. Each field is X * separated by a ':'. X * X * Structure of the /etc/dialups file X * X * The dialups file contains the names of ports which may be dialup X * lines. Each line consists of the last component of the path X * name. The leading "/dev/" string is removed. X * X * @(#)dialup.h 3.1 19:44:22 12/10/90 X */ X X#ifndef _DIALUP_H X#define _DIALUP_H X X#include <stdio.h> X Xstruct dialup { X char *du_shell; X char *du_passwd; X}; X X#ifdef __STDC__ Xextern void setduent (); Xextern void endduent (); Xextern struct dialup *fgetduent (); Xextern struct dialup *getduent (); Xextern struct dialup *getdushell (); Xextern int putduent (); Xextern int isadialup (); X#else Xextern void setduent (void); Xextern void endduent (void); Xextern struct dialup *fgetduent (FILE *); Xextern struct dialup *getduent (void); Xextern struct dialup *getdushell (char *); Xextern int putduent (struct dialup *, FILE *); Xextern int isadialup (char *); X#endif X X#define DIALPWD "/etc/d_passwd" X#define DIALUPS "/etc/dialups" X X#endif SHAR_EOF if test 1598 -ne "`wc -c < 'dialup.h'`" then echo shar: "error transmitting 'dialup.h'" '(should have been 1598 characters)' fi fi echo shar: "extracting 'fields.c'" '(1230 characters)' if test -f 'fields.c' then echo shar: "will not over-write existing file 'fields.c'" else sed 's/^X//' << \SHAR_EOF > 'fields.c' X/* X * Copyright 1990, John F. Haugh II X * All rights reserved. X * X * Use, duplication, and disclosure prohibited without X * the express written permission of the author. X */ X X#include <ctype.h> X#include <string.h> X#include <stdio.h> X X#ifndef lint Xstatic char sccsid[] = "@(#)fields.c 3.2 08:26:23 11/26/90"; X#endif X Xextern char *Progname; X X/* X * valid_field - insure that a field contains all legal characters X * X * The supplied field is scanned for non-printing and other illegal X * characters. If any illegal characters are found, valid_field X * returns -1. Zero is returned for success. X */ X Xint Xvalid_field (field, illegal) Xchar *field; Xchar *illegal; X{ X char *cp; X X for (cp = field;*cp && isprint (*cp) && ! strchr (illegal, *cp);cp++) X ; X X if (*cp) X return -1; X else X return 0; X} X X/* X * change_field - change a single field if a new value is given. X * X * prompt the user with the name of the field being changed and the X * current value. X */ X Xvoid Xchange_field (buf, prompt) Xchar *buf; Xchar *prompt; X{ X char new[BUFSIZ]; X char *cp; X X printf ("\t%s [%s]: ", prompt, buf); X if (fgets (new, BUFSIZ, stdin) != new) X return; X X if (cp = strchr (new, '\n')) X *cp = '\0'; X else X return; X X if (new[0]) X strcpy (buf, new); X} SHAR_EOF if test 1230 -ne "`wc -c < 'fields.c'`" then echo shar: "error transmitting 'fields.c'" '(should have been 1230 characters)' fi fi echo shar: "extracting 'gsdbm.c'" '(1823 characters)' if test -f 'gsdbm.c' then echo shar: "will not over-write existing file 'gsdbm.c'" else sed 's/^X//' << \SHAR_EOF > 'gsdbm.c' X/* X * Copyright 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X */ X X#ifndef lint Xstatic char sccsid[] = "@(#)gsdbm.c 3.3 11:25:29 12/19/90"; X#endif X X#include <string.h> X#include <stdio.h> X#include "shadow.h" X#include "config.h" X X#ifdef NDBM X#include <ndbm.h> XDBM *sgr_dbm; X X#define GRP_FRAG 256 X X/* X * sgr_dbm_update X * X * Updates the DBM password files, if they exist. X */ X Xint Xsgr_dbm_update (sgr) Xstruct sgrp *sgr; X{ X datum key; X datum content; X char data[BUFSIZ*8]; X char sgrpkey[60]; X char *cp; X int len; X int i; X int cnt; X static int once; X X if (! once) { X if (! sgr_dbm) X setsgent (); X X once++; X } X if (! sgr_dbm) X return 0; X X len = sgr_pack (sgr, data); X X if (len <= GRP_FRAG) { X content.dsize = len; X content.dptr = data; X X key.dsize = strlen (sgr->sg_name); X key.dptr = sgr->sg_name; X if (dbm_store (sgr_dbm, key, content, DBM_REPLACE)) X return 0; X } else { X content.dsize = sizeof cnt; X content.dptr = (char *) &cnt; X cnt = (len + (GRP_FRAG-1)) / GRP_FRAG; X X key.dsize = strlen (sgr->sg_name); X key.dptr = sgr->sg_name; X if (dbm_store (sgr_dbm, key, content, DBM_REPLACE)) X return 0; X X for (cp = data, i = 0;i < cnt;i++) { X content.dsize = len > GRP_FRAG ? GRP_FRAG:len; X len -= content.dsize; X content.dptr = cp; X cp += content.dsize; X X key.dsize = sizeof i + strlen (sgr->sg_name); X key.dptr = sgrpkey; X memcpy (sgrpkey, &i, sizeof i); X strcpy (sgrpkey + sizeof i, sgr->sg_name); X if (dbm_store (sgr_dbm, key, content, DBM_REPLACE)) X return 0; X } X } X return 1; X} X#endif SHAR_EOF if test 1823 -ne "`wc -c < 'gsdbm.c'`" then echo shar: "error transmitting 'gsdbm.c'" '(should have been 1823 characters)' fi fi exit 0 # End of shell archive -- John F. Haugh II | Distribution to | UUCP: ...!cs.utexas.edu!rpp386!jfh Ma Bell: (512) 255-8251 | GEnie PROHIBITED :-) | Domain: jfh@rpp386.cactus.org "If liberals interpreted the 2nd Amendment the same way they interpret the rest of the Constitution, gun ownership would be mandatory."
jfh@rpp386.cactus.org (John F Haugh II) (05/16/91)
#! /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: # groupio.c # shadowio.c # sgroupio.c # This archive created: Sun Mar 3 13:27:37 1991 # By: John F Haugh II (River Parishes Programming, Austin TX) export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'groupio.c'" '(10707 characters)' if test -f 'groupio.c' then echo shar: "will not over-write existing file 'groupio.c'" else sed 's/^X//' << \SHAR_EOF > 'groupio.c' X/* X * Copyright 1990, John F. Haugh II X * An unpublished work. X * All rights reserved. X * X * Use, duplication, and disclosure prohibited without X * the express written permission of the author. X * X * This file implements a transaction oriented group database X * library. The group file is updated one entry at a time. X * After each transaction the file must be logically closed and X * transferred to the existing group file. The sequence of X * events is X * X * gr_lock -- lock group file X * gr_open -- logically open group file X * while transaction to process X * gr_(locate,update,remove) -- perform transaction X * done X * gr_close -- commit transactions X * gr_unlock -- remove group lock X */ X X#include <sys/stat.h> X#include <fcntl.h> X#include <errno.h> X#include <grp.h> X#include <stdio.h> X#ifdef BSD X#include <strings.h> X#else X#include <string.h> X#endif X X#ifndef lint Xstatic char sccsid[] = "@(#)groupio.c 3.6 15:59:12 12/9/90"; X#endif X Xstatic int islocked; Xstatic int isopen; Xstatic int open_modes; Xstatic FILE *grfp; X Xstruct gr_file_entry { X char *grf_line; X int grf_changed; X struct group *grf_entry; X struct gr_file_entry *grf_next; X}; X Xstatic struct gr_file_entry *grf_head; Xstatic struct gr_file_entry *grf_tail; Xstatic struct gr_file_entry *grf_cursor; Xstatic int gr_changed; Xstatic int lock_pid; X X#define GR_LOCK "/etc/group.lock" X#define GR_TEMP "/etc/grp.%d" X#define GROUP "/etc/group" X Xstatic char gr_filename[BUFSIZ] = GROUP; X Xextern char *strdup(); Xextern struct group *sgetgrent(); X X/* X * gr_dup - duplicate a group file entry X * X * gr_dup() accepts a pointer to a group file entry and X * returns a pointer to a group file entry in allocated X * memory. X */ X Xstatic struct group * Xgr_dup (grent) Xstruct group *grent; X{ X struct group *gr; X int i; X X if (! (gr = (struct group *) malloc (sizeof *gr))) X return 0; X X if ((gr->gr_name = strdup (grent->gr_name)) == 0 || X (gr->gr_passwd = strdup (grent->gr_passwd)) == 0) X return 0; X X for (i = 0;grent->gr_mem[i];i++) X ; X X gr->gr_mem = (char **) malloc (sizeof (char *) * (i + 1)); X for (i = 0;grent->gr_mem[i];i++) X if (! (gr->gr_mem[i] = strdup (grent->gr_mem[i]))) X return 0; X X gr->gr_mem[i] = 0; X gr->gr_gid = grent->gr_gid; X X return gr; X} X X/* X * gr_free - free a dynamically allocated group file entry X * X * gr_free() frees up the memory which was allocated for the X * pointed to entry. X */ X Xstatic void Xgr_free (grent) Xstruct group *grent; X{ X int i; X X free (grent->gr_name); X free (grent->gr_passwd); X X for (i = 0;grent->gr_mem[i];i++) X free (grent->gr_mem[i]); X X free (grent->gr_mem); X} X X/* X * gr_name - change the name of the group file X */ X Xint Xgr_name (name) Xchar *name; X{ X if (isopen || strlen (name) > (BUFSIZ-10)) X return -1; X X strcpy (gr_filename, name); X return 0; X} X X/* X * gr_lock - lock a group file X * X * gr_lock() encapsulates the lock operation. it returns X * TRUE or FALSE depending on the group file being X * properly locked. the lock is set by creating a semaphore X * file, GR_LOCK. X */ X Xint Xgr_lock () X{ X int fd; X int pid; X int len; X char file[BUFSIZ]; X char buf[32]; X struct stat sb; X X if (islocked) X return 1; X X if (strcmp (gr_filename, GROUP) != 0) X return 0; X X /* X * Create a lock file which can be switched into place X */ X X sprintf (file, GR_TEMP, lock_pid = getpid ()); X if ((fd = open (file, O_CREAT|O_EXCL|O_WRONLY, 0600)) == -1) X return 0; X X sprintf (buf, "%d", lock_pid); X if (write (fd, buf, strlen (buf) + 1) != strlen (buf) + 1) { X (void) close (fd); X (void) unlink (file); X return 0; X } X close (fd); X X /* X * Simple case first - X * Link fails (in a sane environment ...) if the target X * exists already. So we try to switch in a new lock X * file. If that succeeds, we assume we have the only X * valid lock. Needs work for NFS where this assumption X * may not hold. The simple hack is to check the link X * count on the source file, which should be 2 iff the X * link =really= worked. X */ X X if (link (file, GR_LOCK) == 0) { X if (stat (file, &sb) != 0) X return 0; X X if (sb.st_nlink != 2) X return 0; X X (void) unlink (file); X islocked = 1; X return 1; X } X X /* X * Invalid lock test - X * Open the lock file and see if the lock is valid. X * The PID of the lock file is checked, and if the PID X * is not valid, the lock file is removed. If the unlink X * of the lock file fails, it should mean that someone X * else is executing this code. They will get success, X * and we will fail. X */ X X if ((fd = open (GR_LOCK, O_RDWR)) == -1 || X (len = read (fd, buf, BUFSIZ)) <= 0) { X errno = EINVAL; X return 0; X } X buf[len] = '\0'; X if ((pid = strtol (buf, (char **) 0, 10)) == 0) { X errno = EINVAL; X return 0; X } X if (kill (pid, 0) == 0) { X errno = EEXIST; X return 0; X } X if (unlink (GR_LOCK)) { X (void) close (fd); X (void) unlink (file); X X return 0; X } X X /* X * Re-try lock - X * The invalid lock has now been removed and I should X * be able to acquire a lock for myself just fine. If X * this fails there will be no retry. The link count X * test here makes certain someone executing the previous X * block of code didn't just remove the lock we just X * linked to. X */ X X if (link (file, GR_LOCK) == 0) { X if (stat (file, &sb) != 0) X return 0; X X if (sb.st_nlink != 2) X return 0; X X (void) unlink (file); X islocked = 1; X return 1; X } X (void) unlink (file); X return 0; X} X X/* X * gr_unlock - logically unlock a group file X * X * gr_unlock() removes the lock which was set by an earlier X * invocation of gr_lock(). X */ X Xint Xgr_unlock () X{ X if (isopen) { X open_modes = O_RDONLY; X if (! gr_close ()) X return 0; X } X if (islocked) { X islocked = 0; X if (lock_pid != getpid ()) X return 0; X X (void) unlink (GR_LOCK); X return 1; X } X return 0; X} X X/* X * gr_open - open a group file X * X * gr_open() encapsulates the open operation. it returns X * TRUE or FALSE depending on the group file being X * properly opened. X */ X Xint Xgr_open (mode) Xint mode; X{ X char buf[8192]; X char *cp; X struct gr_file_entry *grf; X struct group *grent; X X if (isopen || (mode != O_RDONLY && mode != O_RDWR)) X return 0; X X if (mode != O_RDONLY && ! islocked && X strcmp (gr_filename, GROUP) == 0) X return 0; X X if ((grfp = fopen (gr_filename, mode == O_RDONLY ? "r":"r+")) == 0) X return 0; X X grf_head = grf_tail = grf_cursor = 0; X gr_changed = 0; X X while (fgetsx (buf, sizeof buf, grfp) != (char *) 0) { X if (cp = strrchr (buf, '\n')) X *cp = '\0'; X X if (! (grf = (struct gr_file_entry *) malloc (sizeof *grf))) X return 0; X X grf->grf_changed = 0; X grf->grf_line = strdup (buf); X if ((grent = sgetgrent (buf)) && ! (grent = gr_dup (grent))) X return 0; X X grf->grf_entry = grent; X X if (grf_head == 0) { X grf_head = grf_tail = grf; X grf->grf_next = 0; X } else { X grf_tail->grf_next = grf; X grf->grf_next = 0; X grf_tail = grf; X } X } X isopen++; X open_modes = mode; X X return 1; X} X X/* X * gr_close - close the group file X * X * gr_close() outputs any modified group file entries and X * frees any allocated memory. X */ X Xint Xgr_close () X{ X char backup[BUFSIZ]; X int fd; X int mask; X int c; X int i; X int errors = 0; X FILE *bkfp; X struct gr_file_entry *grf; X struct gr_file_entry *ogrf; X X if (! isopen) { X errno = EINVAL; X return 0; X } X if (islocked && lock_pid != getpid ()) { X isopen = 0; X islocked = 0; X errno = EACCES; X return 0; X } X strcpy (backup, gr_filename); X strcat (backup, "-"); X X if (open_modes == O_RDWR && gr_changed) { X mask = umask (0222); X if ((bkfp = fopen (backup, "w")) == 0) { X umask (mask); X return 0; X } X umask (mask); X X rewind (grfp); X while ((c = getc (grfp)) != EOF) { X if (putc (c, bkfp) == EOF) { X fclose (bkfp); X return 0; X } X } X if (fclose (bkfp)) X return 0; X X isopen = 0; X (void) fclose (grfp); X X mask = umask (0222); X if (! (grfp = fopen (gr_filename, "w"))) { X umask (mask); X return 0; X } X umask (mask); X X for (grf = grf_head;! errors && grf;grf = grf->grf_next) { X if (grf->grf_changed) { X if (putgrent (grf->grf_entry, grfp)) X errors++; X } else { X if (fputsx (grf->grf_line, grfp)) X errors++; X X if (putc ('\n', grfp) == EOF) X errors++; X } X } X if (fflush (grfp)) X errors++; X X if (errors) { X unlink (gr_filename); X link (backup, gr_filename); X unlink (backup); X return 0; X } X } X if (fclose (grfp)) X return 0; X X grfp = 0; X X while (grf_head != 0) { X grf = grf_head; X grf_head = grf->grf_next; X X if (grf->grf_entry) { X gr_free (grf->grf_entry); X free (grf->grf_entry); X } X if (grf->grf_line) X free (grf->grf_line); X X free (grf); X } X grf_tail = 0; X return 1; X} X Xint Xgr_update (grent) Xstruct group *grent; X{ X struct gr_file_entry *grf; X struct group *ngr; X X if (! isopen || open_modes == O_RDONLY) { X errno = EINVAL; X return 0; X } X for (grf = grf_head;grf != 0;grf = grf->grf_next) { X if (grf->grf_entry == 0) X continue; X X if (strcmp (grent->gr_name, grf->grf_entry->gr_name) != 0) X continue; X X if (! (ngr = gr_dup (grent))) X return 0; X else { X gr_free (grf->grf_entry); X *(grf->grf_entry) = *ngr; X } X grf->grf_changed = 1; X grf_cursor = grf; X return gr_changed = 1; X } X grf = (struct gr_file_entry *) malloc (sizeof *grf); X if (! (grf->grf_entry = gr_dup (grent))) X return 0; X X grf->grf_changed = 1; X grf->grf_next = 0; X grf->grf_line = 0; X X if (grf_tail) X grf_tail->grf_next = grf; X X if (! grf_head) X grf_head = grf; X X grf_tail = grf; X X return gr_changed = 1; X} X Xint Xgr_remove (name) Xchar *name; X{ X struct gr_file_entry *grf; X struct gr_file_entry *ogrf; X X if (! isopen || open_modes == O_RDONLY) { X errno = EINVAL; X return 0; X } X for (ogrf = 0, grf = grf_head;grf != 0; X ogrf = grf, grf = grf->grf_next) { X if (! grf->grf_entry) X continue; X X if (strcmp (name, grf->grf_entry->gr_name) != 0) X continue; X X if (grf == grf_cursor) X grf_cursor = ogrf; X X if (ogrf != 0) X ogrf->grf_next = grf->grf_next; X else X grf_head = grf->grf_next; X X if (grf == grf_tail) X grf_tail = ogrf; X X return gr_changed = 1; X } X errno = ENOENT; X return 0; X} X Xstruct group * Xgr_locate (name) Xchar *name; X{ X struct gr_file_entry *grf; X X if (! isopen) { X errno = EINVAL; X return 0; X } X for (grf = grf_head;grf != 0;grf = grf->grf_next) { X if (grf->grf_entry == 0) X continue; X X if (strcmp (name, grf->grf_entry->gr_name) == 0) { X grf_cursor = grf; X return grf->grf_entry; X } X } X errno = ENOENT; X return 0; X} X Xint Xgr_rewind () X{ X if (! isopen) { X errno = EINVAL; X return 0; X } X grf_cursor = 0; X return 1; X} X Xstruct group * Xgr_next () X{ X if (! isopen) { X errno = EINVAL; X return 0; X } X if (grf_cursor == 0) X grf_cursor = grf_head; X else X grf_cursor = grf_cursor->grf_next; X X while (grf_cursor) { X if (grf_cursor->grf_entry) X return grf_cursor->grf_entry; X X grf_cursor = grf_cursor->grf_next; X } X return 0; X} SHAR_EOF if test 10707 -ne "`wc -c < 'groupio.c'`" then echo shar: "error transmitting 'groupio.c'" '(should have been 10707 characters)' fi fi echo shar: "extracting 'shadowio.c'" '(10637 characters)' if test -f 'shadowio.c' then echo shar: "will not over-write existing file 'shadowio.c'" else sed 's/^X//' << \SHAR_EOF > 'shadowio.c' X/* X * Copyright 1990, John F. Haugh II X * All rights reserved. X * X * Use, duplication, and disclosure prohibited without X * the express written permission of the author. X * X * This file implements a transaction oriented password database X * library. The password file is updated one entry at a time. X * After each transaction the file must be logically closed and X * transferred to the existing password file. The sequence of X * events is X * X * spw_lock -- lock shadow file X * spw_open -- logically open shadow file X * while transaction to process X * spw_(locate,update,remove) -- perform transaction X * done X * spw_close -- commit transactions X * spw_unlock -- remove shadow lock X */ X X#ifndef lint Xstatic char sccsid[] = "@(#)shadowio.c 3.4 07:54:20 12/1/90"; X#endif X X#include <sys/stat.h> X#include <fcntl.h> X#include <errno.h> X#include <stdio.h> X#ifdef BSD X#include <strings.h> X#else X#include <string.h> X#endif X#include "shadow.h" X Xstatic int islocked; Xstatic int isopen; Xstatic int open_modes; Xstatic FILE *spwfp; X Xstruct spw_file_entry { X char *spwf_line; X int spwf_changed; X struct spwd *spwf_entry; X struct spw_file_entry *spwf_next; X}; X Xstatic struct spw_file_entry *spwf_head; Xstatic struct spw_file_entry *spwf_tail; Xstatic struct spw_file_entry *spwf_cursor; Xstatic int sp_changed; Xstatic int lock_pid; X X#define SPW_LOCK "/etc/shadow.lock" X#define SPW_TEMP "/etc/spwd.%d" X#define SHADOW "/etc/shadow" X Xstatic char spw_filename[BUFSIZ] = SHADOW; X Xextern char *strdup(); Xextern struct spwd *sgetspent(); X X/* X * spw_dup - duplicate a shadow file entry X * X * spw_dup() accepts a pointer to a shadow file entry and X * returns a pointer to a shadow file entry in allocated X * memory. X */ X Xstatic struct spwd * Xspw_dup (spwd) Xstruct spwd *spwd; X{ X struct spwd *spw; X X if (! (spw = (struct spwd *) malloc (sizeof *spw))) X return 0; X X *spw = *spwd; X if ((spw->sp_namp = strdup (spwd->sp_namp)) == 0 || X (spw->sp_pwdp = strdup (spwd->sp_pwdp)) == 0) X return 0; X X return spw; X} X X/* X * spw_free - free a dynamically allocated shadow file entry X * X * spw_free() frees up the memory which was allocated for the X * pointed to entry. X */ X Xstatic void Xspw_free (spwd) Xstruct spwd *spwd; X{ X free (spwd->sp_namp); X free (spwd->sp_pwdp); X} X X/* X * spw_name - change the name of the shadow password file X */ X Xint Xspw_name (name) Xchar *name; X{ X if (isopen || strlen (name) > (BUFSIZ-10)) X return -1; X X strcpy (spw_filename, name); X return 0; X} X X/* X * spw_lock - lock a password file X * X * spw_lock() encapsulates the lock operation. it returns X * TRUE or FALSE depending on the password file being X * properly locked. the lock is set by creating a semaphore X * file, SPW_LOCK. X */ X Xint Xspw_lock () X{ X int fd; X int pid; X int len; X char file[BUFSIZ]; X char buf[32]; X struct stat sb; X X if (islocked) X return 1; X X if (strcmp (spw_filename, SHADOW) != 0) X return 0; X X /* X * Create a lock file which can be switched into place X */ X X sprintf (file, SPW_TEMP, lock_pid = getpid ()); X if ((fd = open (file, O_CREAT|O_EXCL|O_WRONLY, 0600)) == -1) X return 0; X X sprintf (buf, "%d", lock_pid); X if (write (fd, buf, strlen (buf) + 1) != strlen (buf) + 1) { X (void) close (fd); X (void) unlink (file); X return 0; X } X close (fd); X X /* X * Simple case first - X * Link fails (in a sane environment ...) if the target X * exists already. So we try to switch in a new lock X * file. If that succeeds, we assume we have the only X * valid lock. Needs work for NFS where this assumption X * may not hold. The simple hack is to check the link X * count on the source file, which should be 2 iff the X * link =really= worked. X */ X X if (link (file, SPW_LOCK) == 0) { X if (stat (file, &sb) != 0) X return 0; X X if (sb.st_nlink != 2) X return 0; X X (void) unlink (file); X islocked = 1; X return 1; X } X X /* X * Invalid lock test - X * Open the lock file and see if the lock is valid. X * The PID of the lock file is checked, and if the PID X * is not valid, the lock file is removed. If the unlink X * of the lock file fails, it should mean that someone X * else is executing this code. They will get success, X * and we will fail. X */ X X if ((fd = open (SPW_LOCK, O_RDWR)) == -1 || X (len = read (fd, buf, BUFSIZ)) <= 0) { X errno = EINVAL; X return 0; X } X buf[len] = '\0'; X if ((pid = strtol (buf, (char **) 0, 10)) == 0) { X errno = EINVAL; X return 0; X } X if (kill (pid, 0) == 0) { X errno = EEXIST; X return 0; X } X if (unlink (SPW_LOCK)) { X (void) close (fd); X (void) unlink (file); X X return 0; X } X X /* X * Re-try lock - X * The invalid lock has now been removed and I should X * be able to acquire a lock for myself just fine. If X * this fails there will be no retry. The link count X * test here makes certain someone executing the previous X * block of code didn't just remove the lock we just X * linked to. X */ X X if (link (file, SPW_LOCK) == 0) { X if (stat (file, &sb) != 0) X return 0; X X if (sb.st_nlink != 2) X return 0; X X (void) unlink (file); X islocked = 1; X return 1; X } X (void) unlink (file); X return 0; X} X X/* X * spw_unlock - logically unlock a shadow file X * X * spw_unlock() removes the lock which was set by an earlier X * invocation of spw_lock(). X */ X Xint Xspw_unlock () X{ X if (isopen) { X open_modes = O_RDONLY; X if (! spw_close ()) X return 0; X } X if (islocked) { X islocked = 0; X if (lock_pid != getpid ()) X return 0; X X (void) unlink (SPW_LOCK); X return 1; X } X return 0; X} X X/* X * spw_open - open a password file X * X * spw_open() encapsulates the open operation. it returns X * TRUE or FALSE depending on the shadow file being X * properly opened. X */ X Xint Xspw_open (mode) Xint mode; X{ X char buf[BUFSIZ]; X char *cp; X struct spw_file_entry *spwf; X struct spwd *spwd; X X if (isopen || (mode != O_RDONLY && mode != O_RDWR)) X return 0; X X if (mode != O_RDONLY && ! islocked && X strcmp (spw_filename, SHADOW) == 0) X return 0; X X if ((spwfp = fopen (spw_filename, mode == O_RDONLY ? "r":"r+")) == 0) X return 0; X X spwf_head = spwf_tail = spwf_cursor = 0; X sp_changed = 0; X X while (fgets (buf, sizeof buf, spwfp) != (char *) 0) { X if (cp = strrchr (buf, '\n')) X *cp = '\0'; X X if (! (spwf = (struct spw_file_entry *) malloc (sizeof *spwf))) X return 0; X X spwf->spwf_changed = 0; X spwf->spwf_line = strdup (buf); X if ((spwd = sgetspent (buf)) && ! (spwd = spw_dup (spwd))) X return 0; X X spwf->spwf_entry = spwd; X X if (spwf_head == 0) { X spwf_head = spwf_tail = spwf; X spwf->spwf_next = 0; X } else { X spwf_tail->spwf_next = spwf; X spwf->spwf_next = 0; X spwf_tail = spwf; X } X } X isopen++; X open_modes = mode; X X return 1; X} X X/* X * spw_close - close the password file X * X * spw_close() outputs any modified password file entries and X * frees any allocated memory. X */ X Xint Xspw_close () X{ X char backup[BUFSIZ]; X int fd; X int mask; X int c; X int i; X int errors = 0; X FILE *bkfp; X struct spw_file_entry *spwf; X struct spw_file_entry *ospwf; X X if (! isopen) { X errno = EINVAL; X return 0; X } X if (islocked && lock_pid != getpid ()) { X isopen = 0; X islocked = 0; X errno = EACCES; X return 0; X } X strcpy (backup, spw_filename); X strcat (backup, "-"); X X if (open_modes == O_RDWR && sp_changed) { X mask = umask (077); X if ((bkfp = fopen (backup, "w")) == 0) { X umask (mask); X return 0; X } X umask (mask); X X rewind (spwfp); X while ((c = getc (spwfp)) != EOF) { X if (putc (c, bkfp) == EOF) { X fclose (bkfp); X return 0; X } X } X if (fclose (bkfp)) X return 0; X X isopen = 0; X (void) fclose (spwfp); X X mask = umask (077); X if (! (spwfp = fopen (spw_filename, "w"))) { X umask (mask); X return 0; X } X umask (mask); X X for (spwf = spwf_head;errors == 0 && spwf; X spwf = spwf->spwf_next) { X if (spwf->spwf_changed) { X if (putspent (spwf->spwf_entry, spwfp)) X errors++; X } else { X if (fputs (spwf->spwf_line, spwfp) == EOF) X errors++; X if (putc ('\n', spwfp) == EOF) X errors++; X } X } X if (fflush (spwfp)) X errors++; X X if (errors) { X unlink (spw_filename); X link (backup, spw_filename); X unlink (backup); X return 0; X } X } X if (fclose (spwfp)) X return 0; X X spwfp = 0; X X while (spwf_head != 0) { X spwf = spwf_head; X spwf_head = spwf->spwf_next; X X if (spwf->spwf_entry) { X spw_free (spwf->spwf_entry); X free (spwf->spwf_entry); X } X if (spwf->spwf_line) X free (spwf->spwf_line); X X free (spwf); X } X spwf_tail = 0; X return 1; X} X Xint Xspw_update (spwd) Xstruct spwd *spwd; X{ X struct spw_file_entry *spwf; X struct spwd *nspwd; X X if (! isopen || open_modes == O_RDONLY) { X errno = EINVAL; X return 0; X } X for (spwf = spwf_head;spwf != 0;spwf = spwf->spwf_next) { X if (spwf->spwf_entry == 0) X continue; X X if (strcmp (spwd->sp_namp, spwf->spwf_entry->sp_namp) != 0) X continue; X X if (! (nspwd = spw_dup (spwd))) X return 0; X else { X spw_free (spwf->spwf_entry); X *(spwf->spwf_entry) = *nspwd; X } X spwf->spwf_changed = 1; X spwf_cursor = spwf; X return sp_changed = 1; X } X spwf = (struct spw_file_entry *) malloc (sizeof *spwf); X if (! (spwf->spwf_entry = spw_dup (spwd))) X return 0; X X spwf->spwf_changed = 1; X spwf->spwf_next = 0; X spwf->spwf_line = 0; X X if (spwf_tail) X spwf_tail->spwf_next = spwf; X X if (! spwf_head) X spwf_head = spwf; X X spwf_tail = spwf; X X return sp_changed = 1; X} X Xint Xspw_remove (name) Xchar *name; X{ X struct spw_file_entry *spwf; X struct spw_file_entry *ospwf; X X if (! isopen || open_modes == O_RDONLY) { X errno = EINVAL; X return 0; X } X for (ospwf = 0, spwf = spwf_head;spwf != 0; X ospwf = spwf, spwf = spwf->spwf_next) { X if (! spwf->spwf_entry) X continue; X X if (strcmp (name, spwf->spwf_entry->sp_namp) != 0) X continue; X X if (spwf == spwf_cursor) X spwf_cursor = ospwf; X X if (ospwf != 0) X ospwf->spwf_next = spwf->spwf_next; X else X spwf_head = spwf->spwf_next; X X if (spwf == spwf_tail) X spwf_tail = ospwf; X X return sp_changed = 1; X } X errno = ENOENT; X return 0; X} X Xstruct spwd * Xspw_locate (name) Xchar *name; X{ X struct spw_file_entry *spwf; X X if (! isopen) { X errno = EINVAL; X return 0; X } X for (spwf = spwf_head;spwf != 0;spwf = spwf->spwf_next) { X if (spwf->spwf_entry == 0) X continue; X X if (strcmp (name, spwf->spwf_entry->sp_namp) == 0) { X spwf_cursor = spwf; X return spwf->spwf_entry; X } X } X errno = ENOENT; X return 0; X} X Xint Xspw_rewind () X{ X if (! isopen) { X errno = EINVAL; X return 0; X } X spwf_cursor = 0; X return 1; X} X Xstruct spwd * Xspw_next () X{ X if (! isopen) { X errno = EINVAL; X return 0; X } X if (spwf_cursor == 0) X spwf_cursor = spwf_head; X else X spwf_cursor = spwf_cursor->spwf_next; X X while (spwf_cursor) { X if (spwf_cursor->spwf_entry) X return spwf_cursor->spwf_entry; X X spwf_cursor = spwf_cursor->spwf_next; X } X return 0; X} SHAR_EOF if test 10637 -ne "`wc -c < 'shadowio.c'`" then echo shar: "error transmitting 'shadowio.c'" '(should have been 10637 characters)' fi fi echo shar: "extracting 'sgroupio.c'" '(11482 characters)' if test -f 'sgroupio.c' then echo shar: "will not over-write existing file 'sgroupio.c'" else sed 's/^X//' << \SHAR_EOF > 'sgroupio.c' X/* X * Copyright 1990, John F. Haugh II X * All rights reserved. X * X * Permission is granted to copy and create derivative works for any X * non-commercial purpose, provided this copyright notice is preserved X * in all copies of source code, or included in human readable form X * and conspicuously displayed on all copies of object code or X * distribution media. X * X * This file implements a transaction oriented shadow group X * database library. The shadow group file is updated one X * entry at a time. After each transaction the file must be X * logically closed and transferred to the existing shadow X * group file. The sequence of events is X * X * sgr_lock -- lock shadow group file X * sgr_open -- logically open shadow group file X * while transaction to process X * sgr_(locate,update,remove) -- perform transaction X * done X * sgr_close -- commit transactions X * sgr_unlock -- remove shadow group lock X */ X X#include <sys/stat.h> X#include <fcntl.h> X#include <errno.h> X#include <stdio.h> X#ifdef BSD X#include <strings.h> X#define strchr index X#define strrchr rindex X#else X#include <string.h> X#endif X#include "shadow.h" X X#ifndef lint Xstatic char sccsid[] = "@(#)sgroupio.c 3.1 08:13:51 12/14/90"; X#endif X Xstatic int islocked; Xstatic int isopen; Xstatic int open_modes; Xstatic FILE *sgrfp; X Xstruct sg_file_entry { X char *sgr_line; X int sgr_changed; X struct sgrp *sgr_entry; X struct sg_file_entry *sgr_next; X}; X Xstatic struct sg_file_entry *sgr_head; Xstatic struct sg_file_entry *sgr_tail; Xstatic struct sg_file_entry *sgr_cursor; Xstatic int sgr_changed; Xstatic int lock_pid; X X#define SG_LOCK "/etc/gshadow.lock" X#define GR_TEMP "/etc/gshadow.%d" X#define SGROUP "/etc/gshadow" X Xstatic char sg_filename[BUFSIZ] = SGROUP; X Xextern char *strdup(); Xextern struct sgrp *sgetgsent(); Xextern char *fgetsx(); X X/* X * sgr_dup - duplicate a shadow group file entry X * X * sgr_dup() accepts a pointer to a shadow group file entry and X * returns a pointer to a shadow group file entry in allocated memory. X */ X Xstatic struct sgrp * Xsgr_dup (sgrent) Xstruct sgrp *sgrent; X{ X struct sgrp *sgr; X int i; X X if (! (sgr = (struct sgrp *) malloc (sizeof *sgr))) X return 0; X X if ((sgr->sg_name = strdup (sgrent->sg_name)) == 0 || X (sgr->sg_passwd = strdup (sgrent->sg_passwd)) == 0) X return 0; X X for (i = 0;sgrent->sg_mem[i];i++) X ; X X sgr->sg_mem = (char **) malloc (sizeof (char *) * (i + 1)); X for (i = 0;sgrent->sg_mem[i];i++) X if (! (sgr->sg_mem[i] = strdup (sgrent->sg_mem[i]))) X return 0; X X sgr->sg_mem[i] = 0; X X sgr->sg_adm = (char **) malloc (sizeof (char *) * (i + 1)); X for (i = 0;sgrent->sg_adm[i];i++) X if (! (sgr->sg_adm[i] = strdup (sgrent->sg_adm[i]))) X return 0; X X sgr->sg_adm[i] = 0; X X return sgr; X} X X/* X * sgr_free - free a dynamically allocated shadow group file entry X * X * sgr_free() frees up the memory which was allocated for the X * pointed to entry. X */ X Xstatic void Xsgr_free (sgrent) Xstruct sgrp *sgrent; X{ X int i; X X free (sgrent->sg_name); X free (sgrent->sg_passwd); X X for (i = 0;sgrent->sg_mem[i];i++) X free (sgrent->sg_mem[i]); X X free (sgrent->sg_mem); X X for (i = 0;sgrent->sg_adm[i];i++) X free (sgrent->sg_adm[i]); X X free (sgrent->sg_adm); X} X X/* X * sgr_name - change the name of the shadow group file X */ X Xint Xsgr_name (name) Xchar *name; X{ X if (isopen || strlen (name) > (BUFSIZ-10)) X return -1; X X strcpy (sg_filename, name); X return 0; X} X X/* X * sgr_lock - lock a shadow group file X * X * sgr_lock() encapsulates the lock operation. it returns X * TRUE or FALSE depending on the shadow group file being X * properly locked. the lock is set by creating a semaphore X * file, SG_LOCK. X */ X Xint Xsgr_lock () X{ X int fd; X int pid; X int len; X char file[BUFSIZ]; X char buf[32]; X struct stat sb; X X if (islocked) X return 1; X X if (strcmp (sg_filename, SGROUP) != 0) X return 0; X X /* X * Create a lock file which can be switched into place X */ X X sprintf (file, GR_TEMP, lock_pid = getpid ()); X if ((fd = open (file, O_CREAT|O_EXCL|O_WRONLY, 0600)) == -1) X return 0; X X sprintf (buf, "%d", lock_pid); X if (write (fd, buf, strlen (buf) + 1) != strlen (buf) + 1) { X (void) close (fd); X (void) unlink (file); X return 0; X } X close (fd); X X /* X * Simple case first - X * Link fails (in a sane environment ...) if the target X * exists already. So we try to switch in a new lock X * file. If that succeeds, we assume we have the only X * valid lock. Needs work for NFS where this assumption X * may not hold. The simple hack is to check the link X * count on the source file, which should be 2 iff the X * link =really= worked. X */ X X if (link (file, SG_LOCK) == 0) { X if (stat (file, &sb) != 0) X return 0; X X if (sb.st_nlink != 2) X return 0; X X (void) unlink (file); X islocked = 1; X return 1; X } X X /* X * Invalid lock test - X * Open the lock file and see if the lock is valid. X * The PID of the lock file is checked, and if the PID X * is not valid, the lock file is removed. If the unlink X * of the lock file fails, it should mean that someone X * else is executing this code. They will get success, X * and we will fail. X */ X X if ((fd = open (SG_LOCK, O_RDWR)) == -1 || X (len = read (fd, buf, BUFSIZ)) <= 0) { X errno = EINVAL; X return 0; X } X buf[len] = '\0'; X if ((pid = strtol (buf, (char **) 0, 10)) == 0) { X errno = EINVAL; X return 0; X } X if (kill (pid, 0) == 0) { X errno = EEXIST; X return 0; X } X if (unlink (SG_LOCK)) { X (void) close (fd); X (void) unlink (file); X X return 0; X } X X /* X * Re-try lock - X * The invalid lock has now been removed and I should X * be able to acquire a lock for myself just fine. If X * this fails there will be no retry. The link count X * test here makes certain someone executing the previous X * block of code didn't just remove the lock we just X * linked to. X */ X X if (link (file, SG_LOCK) == 0) { X if (stat (file, &sb) != 0) X return 0; X X if (sb.st_nlink != 2) X return 0; X X (void) unlink (file); X islocked = 1; X return 1; X } X (void) unlink (file); X return 0; X} X X/* X * sgr_unlock - logically unlock a shadow group file X * X * sgr_unlock() removes the lock which was set by an earlier X * invocation of sgr_lock(). X */ X Xint Xsgr_unlock () X{ X if (isopen) { X open_modes = O_RDONLY; X if (! sgr_close ()) X return 0; X } X if (islocked) { X islocked = 0; X if (lock_pid != getpid ()) X return 0; X X (void) unlink (SG_LOCK); X return 1; X } X return 0; X} X X/* X * sgr_open - open a shadow group file X * X * sgr_open() encapsulates the open operation. it returns X * TRUE or FALSE depending on the shadow group file being X * properly opened. X */ X Xint Xsgr_open (mode) Xint mode; X{ X char buf[8192]; X char *cp; X struct sg_file_entry *sgrf; X struct sgrp *sgrent; X X if (isopen || (mode != O_RDONLY && mode != O_RDWR)) X return 0; X X if (mode != O_RDONLY && ! islocked && X strcmp (sg_filename, SGROUP) == 0) X return 0; X X if ((sgrfp = fopen (sg_filename, mode == O_RDONLY ? "r":"r+")) == 0) X return 0; X X sgr_head = sgr_tail = sgr_cursor = 0; X sgr_changed = 0; X X while (fgetsx (buf, sizeof buf, sgrfp) != (char *) 0) { X if (cp = strrchr (buf, '\n')) X *cp = '\0'; X X if (! (sgrf = (struct sg_file_entry *) malloc (sizeof *sgrf))) X return 0; X X sgrf->sgr_changed = 0; X sgrf->sgr_line = strdup (buf); X if ((sgrent = sgetgsent (buf)) && ! (sgrent = sgr_dup (sgrent))) X return 0; X X sgrf->sgr_entry = sgrent; X X if (sgr_head == 0) { X sgr_head = sgr_tail = sgrf; X sgrf->sgr_next = 0; X } else { X sgr_tail->sgr_next = sgrf; X sgrf->sgr_next = 0; X sgr_tail = sgrf; X } X } X isopen++; X open_modes = mode; X X return 1; X} X X/* X * sgr_close - close the shadow group file X * X * sgr_close() outputs any modified shadow group file entries and X * frees any allocated memory. X */ X Xint Xsgr_close () X{ X char backup[BUFSIZ]; X int fd; X int mask; X int c; X int i; X int errors = 0; X FILE *bkfp; X struct sg_file_entry *sgrf; X struct sg_file_entry *osgrf; X X if (! isopen) { X errno = EINVAL; X return 0; X } X if (islocked && lock_pid != getpid ()) { X isopen = 0; X islocked = 0; X errno = EACCES; X return 0; X } X strcpy (backup, sg_filename); X strcat (backup, "-"); X X if (open_modes == O_RDWR && sgr_changed) { X mask = umask (0222); X if ((bkfp = fopen (backup, "w")) == 0) { X umask (mask); X return 0; X } X umask (mask); X X rewind (sgrfp); X while ((c = getc (sgrfp)) != EOF) { X if (putc (c, bkfp) == EOF) { X fclose (bkfp); X return 0; X } X } X if (fclose (bkfp)) X return 0; X X isopen = 0; X (void) fclose (sgrfp); X X mask = umask (0222); X if (! (sgrfp = fopen (sg_filename, "w"))) { X umask (mask); X return 0; X } X umask (mask); X X for (sgrf = sgr_head;! errors && sgrf;sgrf = sgrf->sgr_next) { X if (sgrf->sgr_changed) { X if (putgsent (sgrf->sgr_entry, sgrfp)) X errors++; X } else { X if (fputsx (sgrf->sgr_line, sgrfp)) X errors++; X X if (putc ('\n', sgrfp) == EOF) X errors++; X } X } X if (fflush (sgrfp)) X errors++; X X if (errors) { X unlink (sg_filename); X link (backup, sg_filename); X unlink (backup); X return 0; X } X } X if (fclose (sgrfp)) X return 0; X X sgrfp = 0; X X while (sgr_head != 0) { X sgrf = sgr_head; X sgr_head = sgrf->sgr_next; X X if (sgrf->sgr_entry) { X sgr_free (sgrf->sgr_entry); X free (sgrf->sgr_entry); X } X if (sgrf->sgr_line) X free (sgrf->sgr_line); X X free (sgrf); X } X sgr_tail = 0; X return 1; X} X Xint Xsgr_update (sgrent) Xstruct sgrp *sgrent; X{ X struct sg_file_entry *sgrf; X struct sgrp *nsgr; X X if (! isopen || open_modes == O_RDONLY) { X errno = EINVAL; X return 0; X } X for (sgrf = sgr_head;sgrf != 0;sgrf = sgrf->sgr_next) { X if (sgrf->sgr_entry == 0) X continue; X X if (strcmp (sgrent->sg_name, sgrf->sgr_entry->sg_name) != 0) X continue; X X if (! (nsgr = sgr_dup (sgrent))) X return 0; X else { X sgr_free (sgrf->sgr_entry); X *(sgrf->sgr_entry) = *nsgr; X } X sgrf->sgr_changed = 1; X sgr_cursor = sgrf; X return sgr_changed = 1; X } X sgrf = (struct sg_file_entry *) malloc (sizeof *sgrf); X if (! (sgrf->sgr_entry = sgr_dup (sgrent))) X return 0; X X sgrf->sgr_changed = 1; X sgrf->sgr_next = 0; X sgrf->sgr_line = 0; X X if (sgr_tail) X sgr_tail->sgr_next = sgrf; X X if (! sgr_head) X sgr_head = sgrf; X X sgr_tail = sgrf; X X return sgr_changed = 1; X} X Xint Xsgr_remove (name) Xchar *name; X{ X struct sg_file_entry *sgrf; X struct sg_file_entry *osgrf; X X if (! isopen || open_modes == O_RDONLY) { X errno = EINVAL; X return 0; X } X for (osgrf = 0, sgrf = sgr_head;sgrf != 0; X osgrf = sgrf, sgrf = sgrf->sgr_next) { X if (! sgrf->sgr_entry) X continue; X X if (strcmp (name, sgrf->sgr_entry->sg_name) != 0) X continue; X X if (sgrf == sgr_cursor) X sgr_cursor = osgrf; X X if (osgrf != 0) X osgrf->sgr_next = sgrf->sgr_next; X else X sgr_head = sgrf->sgr_next; X X if (sgrf == sgr_tail) X sgr_tail = osgrf; X X return sgr_changed = 1; X } X errno = ENOENT; X return 0; X} X Xstruct sgrp * Xsgr_locate (name) Xchar *name; X{ X struct sg_file_entry *sgrf; X X if (! isopen) { X errno = EINVAL; X return 0; X } X for (sgrf = sgr_head;sgrf != 0;sgrf = sgrf->sgr_next) { X if (sgrf->sgr_entry == 0) X continue; X X if (strcmp (name, sgrf->sgr_entry->sg_name) == 0) { X sgr_cursor = sgrf; X return sgrf->sgr_entry; X } X } X errno = ENOENT; X return 0; X} X Xint Xsgr_rewind () X{ X if (! isopen) { X errno = EINVAL; X return 0; X } X sgr_cursor = 0; X return 1; X} X Xstruct sgrp * Xsgr_next () X{ X if (! isopen) { X errno = EINVAL; X return 0; X } X if (sgr_cursor == 0) X sgr_cursor = sgr_head; X else X sgr_cursor = sgr_cursor->sgr_next; X X while (sgr_cursor) { X if (sgr_cursor->sgr_entry) X return sgr_cursor->sgr_entry; X X sgr_cursor = sgr_cursor->sgr_next; X } X return 0; X} SHAR_EOF if test 11482 -ne "`wc -c < 'sgroupio.c'`" then echo shar: "error transmitting 'sgroupio.c'" '(should have been 11482 characters)' fi fi exit 0 # End of shell archive -- John F. Haugh II | Distribution to | UUCP: ...!cs.utexas.edu!rpp386!jfh Ma Bell: (512) 255-8251 | GEnie PROHIBITED :-) | Domain: jfh@rpp386.cactus.org "If liberals interpreted the 2nd Amendment the same way they interpret the rest of the Constitution, gun ownership would be mandatory."
jfh@rpp386.cactus.org (John F Haugh II) (05/16/91)
#! /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: # chage.1 # chfn.1 # chsh.1 # login.1 # passwd.1 # su.1 # shadow.3 # faillog.4 # passwd.4 # porttime.4 # shadow.4 # faillog.8 # pwconv.8 # pwunconv.8 # sulogin.8 # This archive created: Sun Mar 3 13:27:41 1991 # By: John F Haugh II (River Parishes Programming, Austin TX) export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'chage.1'" '(1875 characters)' if test -f 'chage.1' then echo shar: "will not over-write existing file 'chage.1'" else sed 's/^X//' << \SHAR_EOF > 'chage.1' X.\" Copyright 1990, John F. Haugh II X.\" All rights reserved. X.\" X.\" Use, duplication, and disclosure prohibited without X.\" the express written permission of the author. X.\" X.\" @(#)chage.1 3.1 09:34:14 11/21/90 X.\" X.TH CHAGE 1 X.SH NAME Xchage \- change user password expirate information X.SH SYNOPSIS X\fBchage\fR [ \fB-m \fImindays\fR ] [ \fB-M \fImaxdays\fR ] [ \fB-d \fIlastday\fR ] \fIuser\fR X.SH DESCRIPTION X\fIchage\f changes the number of days between password changes and the Xdate of the last password change. XThis information is used by the system to determine when a user must Xchange their password. XThe \fIchage\f command is restricted to the root user. X.PP XThe value of \fImindays\f is the minimum number of days between Xpassword changes. XA value of zero for this field indicates that the user may change Xher password at any time. X.PP XThe value of \fImaxdays\f is the maximum number of days during Xwhich a password is valid. XWhen \fImaxdays\f plus \fIlastday\f is less than the current day, Xthe user will be required to change her password before being Xable to use her account. X.PP XThe value of \fIlastday\f is the number of days since January 1st, X1970 when the password was last changed. X.PP XAll of the above values are stored exactly as days when the shadow Xpassword file is used, but are converted to and from weeks when the Xstandard password file is used. XBecause of this conversion, rounding errors may result. X.PP XIf none of the options are selected, \fIchage\f operates in an interactive Xfashion, prompting the user with the current values for all of the fields. XEnter the new value to change the field, or leave the line blank to use Xthe current value. XThe current value is displayed between a pair of \fB[ ]\f marks. X.SH Files X/etc/passwd \- user account information X.br X/etc/shadow \- shadow user account information X.SH See Also Xpasswd(4), Xshadow(4) SHAR_EOF if test 1875 -ne "`wc -c < 'chage.1'`" then echo shar: "error transmitting 'chage.1'" '(should have been 1875 characters)' fi fi echo shar: "extracting 'chfn.1'" '(1598 characters)' if test -f 'chfn.1' then echo shar: "will not over-write existing file 'chfn.1'" else sed 's/^X//' << \SHAR_EOF > 'chfn.1' X.\" Copyright 1990, John F. Haugh II X.\" All rights reserved. X.\" X.\" Use, duplication, and disclosure prohibited without X.\" the express written permission of the author. X.\" X.\" @(#)chfn.1 3.1 09:34:16 11/21/90 X.\" X.TH CHFN 1 X.SH NAME Xchfn \- change user name and information X.SH SYNOPSIS X\fBchfn\fR [ \fB-f \fIfull_name\fR ] [ \fB-r \fIroom_no\fR ] X.br X[ \fB-w \fIwork_ph\fR ] [ \fB-h \fIhome_ph\fR ] [ \fB-o \fIother\fR ] X[ \fIuser\fR ] X.SH DESCRIPTION X\fIchfn\f changes user fullname, office number, office extension, and home Xphone number information for a user's account. XThis information is typically printed by \fIfinger(1)\f and similiar Xprograms. XA normal user may only change the fields for their own account, Xthe super user may change the fields for any account. XAlso, only the super user may use the \fB-o\f option to change the Xundefined portions of the GCOS field. X.PP XThe only restrictions placed on the contents of the fields is that no Xcontrol characters may be present, nor any of comma, colon, or equal sign. XThe \fIother\f field does not have this restriction, and is used to Xstore accounting information used by other applications. X.PP XIf none of the options are selected, \fIchfn\f operates in an interactive Xfashion, prompting the user with the current values for all of the fields. XEnter the new value to change the field, or leave the line blank to use Xthe current value. XThe current value is displayed between a pair of \fB[ ]\f marks. XWithout options, chfn prompts for the current user account. X.SH Files X/etc/passwd \- user account information X.SH See Also Xpasswd(4) SHAR_EOF if test 1598 -ne "`wc -c < 'chfn.1'`" then echo shar: "error transmitting 'chfn.1'" '(should have been 1598 characters)' fi fi echo shar: "extracting 'chsh.1'" '(1475 characters)' if test -f 'chsh.1' then echo shar: "will not over-write existing file 'chsh.1'" else sed 's/^X//' << \SHAR_EOF > 'chsh.1' X.\" Copyright 1990, John F. Haugh II X.\" All rights reserved. X.\" X.\" Use, duplication, and disclosure prohibited without X.\" the express written permission of the author. X.\" X.\" @(#)chsh.1 3.1 09:34:17 11/21/90 X.\" X.TH CHSH 1 X.SH NAME Xchsh \- change login shell X.SH SYNOPSIS X\fBchsh\fR [ \fB-s \fIlogin_shell\fR ] [ \fIuser\fR ] X.SH DESCRIPTION X\fIchsh\f changes the user login shell. XThis determines the name of the user's initial login command. XA normal user may only change the login shell for their own account, Xthe super user may change the login shell for any account. X.PP XThe only restrictions placed on the login shell is that the Xcommand name must be listed in \fB/etc/shells\fR, unless the Xinvoker is the super-user, and then any value may be added. XAn account with a restricted login shell may not change Xtheir login shell. XFor this reason, placing \fB/bin/rsh\fR in \fB/etc/shells\fR Xis discouraged since accidentally changing to a restricted Xshell would prevent the user from every changing their login Xshell back to its original value. X.PP XIf the \fB-s\fR option is not selected, \fIchsh\f operates in an interactive Xfashion, prompting the user with the current login shell. XEnter the new value to change the field, or leave the line blank to use Xthe current value. XThe current value is displayed between a pair of \fB[ ]\f marks. X.SH Files X/etc/passwd \- user account information X.br X/etc/shells \- list of valid login shells X.SH See Also Xchfn(1), Xpasswd(4) SHAR_EOF if test 1475 -ne "`wc -c < 'chsh.1'`" then echo shar: "error transmitting 'chsh.1'" '(should have been 1475 characters)' fi fi echo shar: "extracting 'login.1'" '(3344 characters)' if test -f 'login.1' then echo shar: "will not over-write existing file 'login.1'" else sed 's/^X//' << \SHAR_EOF > 'login.1' X.\" Copyright 1989, 1990, John F. Haugh II X.\" All rights reserved. X.\" X.\" Use, duplication, and disclosure prohibited without X.\" the express written permission of the author. X.\" X.\" @(#)login.1 3.1 09:34:21 11/21/90 X.\" X.TH LOGIN 1 X.SH NAME Xlogin \- Begin session on the system X.SH SYNOPSIS X.B login X[ username [ environmental-variables ] ] X.SH DESCRIPTION X.I login Xis used to establish a new session with the system. XIt is normally invoked automatically by responding to the X.B login: Xprompt on the user\'s terminal. X.I login Xmay be special to the shell and may not be invoked as a sub-process. XTypically, X.I login Xis treated by the shell as \fBexec login\fR which causes the user Xto exit from the current shell. XAttempting to execute \fIlogin\fR from any shell but the login shell Xwill produce an error message. X.PP XWhen invoked from the \fBlogin:\fR prompt, the user may enter Xenvironmental variables after the username. XThese variables are entered in the form \fBNAME=VALUE\fR. XNot all variables may be set in the fashion, notably \fBPATH\fR, X\fBHOME\fR and \fBSHELL\fR. XAdditionally, \fBIFS\fR may be inhibited if the user\'s login Xshell is \fB/bin/sh\fR. X.PP XThe user is then prompted for a password, where appropriate. XEchoing is disabled to prevent revealing the password. XOnly a small number of password failures are permitted before X\fIlogin\fR exits and the communications link is severed. X.PP XIf password aging has been enabled for your account, you may be Xprompted for a new password before proceeding. XYou will be forced to provide your old password and the new Xpassword before continuing. XPlease refer to \fIpasswd(1)\fR for more information. X.PP XAfter a successful login, Xyou will be informed of any system messages and the presence Xof mail. XYou may turn off the printing of the system message file, X\fI/etc/motd\fR, by creating a zero-length file \fI.hushlogin\fR Xin your login directory. XThe mail message will be one of "\fIYou have new mail.\fR", X"\fIYou have mail.\fR", or "\fINo Mail.\fR" according to Xthe condition of your mailbox. X.PP XYour user and group ID will be set according to their values in Xthe \fI/etc/passwd\fR file. XThe value for \fB$HOME\fR, \fB$SHELL\fR, \fB$PATH\fR, \fB$LOGNAME\fR, Xand \fB$MAIL\fR are set according to the appropriate fields in the Xpassword entry. XUlimit, umask and nice values may also be set according to Xentries in the GECOS field. X.PP XOn some installations, the environmental variable \fB$TERM\fR will be Xinitialize to the terminal type on your tty line, as specified in X\fI/etc/ttytype\fR. X.PP XAn initialization script for your command interpreter may also be Xexecuted. XPlease see the appropriate manual section for more information on Xthis function. X.SH CAVEATS X.PP XThis version of \fIlogin\fR has many compilation options, only some of which Xmay be in use at any particular site. X.SH Files X/etc/utmp \- list of current login sessions X.br X/etc/wtmp \- list of previous login sessions X.br X/etc/passwd \- user account information X.br X/etc/shadow \- encrypted passwords and age information X.br X/etc/motd \- system message file X.br X/etc/ttytype \- list of terminal types X.br X$HOME/.profile \- initialization script for default shell X.br X$HOME/.hushlogin \- suppress printing of system messages X.br X.SH See Also X.PP Xgetty(1M), Xmail(1), Xpasswd(1), Xsh(1), Xsu(1), Xd_passwd(4), Xpasswd(4) SHAR_EOF if test 3344 -ne "`wc -c < 'login.1'`" then echo shar: "error transmitting 'login.1'" '(should have been 3344 characters)' fi fi echo shar: "extracting 'passwd.1'" '(4116 characters)' if test -f 'passwd.1' then echo shar: "will not over-write existing file 'passwd.1'" else sed 's/^X//' << \SHAR_EOF > 'passwd.1' X.\" Copyright 1989, 1990, John F. Haugh II X.\" All rights reserved. X.\" X.\" Use, duplication, and disclosure prohibited without X.\" the express written permission of the author. X.\" X.\" @(#)passwd.1 3.1 09:34:23 11/21/90 X.\" X.TH PASSWD 1 X.SH NAME Xpasswd \- change user password X.SH SYNOPSIS X\fBpasswd\fR [ \fB-f\fR ] [ \fIname\fR ] X.br X\fBpasswd\fR [ \fB-g\fR ] [ \fB-r\fR ] \fIgroup\fR X.SH DESCRIPTION X\fIpasswd\f changes passwords for user accounts. XA normal user may only change the password for their own account, Xthe super user may change the password for any account. X.PP XThe user is first prompted for their old password, Xif one is present. XThis password is then encrypted and compared against the Xstored password. XThe user has only one chance to enter the correct password. XThe super user is permitted to bypass this step so that forgotten Xpasswords may be changed. X.PP XAfter the password has been entered password aging information Xis checked to see if the user is permitted to change their password Xat this time. XIf not, \fIpasswd\fR refuses to change the password and exits. X.PP XThe user is then prompted for a replacement password. XThis password is tested for complexity. XAs a general guideline, Xpasswords should consist of 6 to 8 characters including Xone or more from each of following sets: X.IP "" .5i XLower case alphabetics X.IP "" .5i XUpper case alphabetics X.IP "" .5i XDigits 0 thru 9 X.IP "" .5i XPunctuation marks X.PP XCare must be taken not to include the system default erase Xor kill characters. X\fIpasswd\fR will reject any password which is not suitably Xcomplex. X.PP XIf the password is accepted, X\fIpasswd\fR will prompt again and compare the second entry Xagainst the first. XBoth entries are require to match in order for the password Xto be changed. X.PP XWhen the \fB-g\f option is used, the password for the named Xgroup is changed. XThe user must either be the super user, or the first group Xmember listed for the named group. XThe current group password is not prompted for. XThe \fB-r\f option is used with the \fB-g\f option to remove Xthe current password from the named group. X.SH Hints for user passwords XThe security of a password depends upon the strength of the Xencryption algorithm and the size of the key space. XThe \fB\s-2UNIX\s+2\fR System encryption method is based on Xthe NBS DES algorithm and is very secure. XThe size of the key space depends upon the randomness of the Xpassword which is selected. X.PP XCompromises in password security normally result from careless Xpassword selection or handling. XFor this reason, you should select a password which does not Xappear in a dictionary or which must be written down. XThe password should also not be a proper name, your license Xnumber, birth date, or street address. XAny of these may be used as guesses to violate system security. X.PP XYour password must easily remembered so that you will not Xbe forced to write it on a piece of paper. XThis can be accomplished by appending two small words together Xand separating each with a special character or digit. XFor example, Pass%word. X.PP XOther methods of construction involve selecting an easily Xremembered phrase from literature and selecting the first Xor last letter from each. XAn example of this is X.IP "" .5i XAsk not for whom the bell tolls. X.PP Xwhich produces X.IP "" .5i XAn4wtbt. X.PP XYou may be reasonably sure few crackers will have Xincluded this in their dictionary. X.SH Notes about group passwords XGroup passwords are an inherent security problem since more Xthan one person is permitted to know the password. XHowever, groups are a useful tool for permitting co-operation Xbetween different users. X.SH CAVEATS XNot all options may be supported. XPassword complexity checking may vary from site to site. XThe user is urged to select as complex a password as they Xfeel comfortable with. XA \fB-f\fR option exists to permit the superuser to override Xany password complexity testing; Xnormal users must create passwords which pass the complexity Xtest. X.SH Files X/etc/passwd \- user account information X.br X/etc/shadow \- encrypted user passwords X.SH See Also Xpasswd(3), Xshadow(3), Xgroup(4), Xpasswd(4) SHAR_EOF if test 4116 -ne "`wc -c < 'passwd.1'`" then echo shar: "error transmitting 'passwd.1'" '(should have been 4116 characters)' fi fi echo shar: "extracting 'su.1'" '(1697 characters)' if test -f 'su.1' then echo shar: "will not over-write existing file 'su.1'" else sed 's/^X//' << \SHAR_EOF > 'su.1' X.\" Copyright 1989, 1990, John F. Haugh II X.\" All rights reserved. X.\" X.\" Use, duplication, and disclosure prohibited without X.\" the express written permission of the author. X.\" X.\" @(#)su.1 3.1 09:34:28 11/21/90 X.\" X.TH SU 1 X.SH NAME Xsu \- Change user ID or become super-user X.SH SYNOPSIS X.B su X[ - ] [ username [ args ] ] X.SH DESCRIPTION X.I su Xis used to become another user during a login session. XInvoked without a username, \fIsu\fR defaults to becoming Xthe super user. XThe optional argument \fB\-\fR may be used to provide an Xenvironment similiar to what the user would expect had Xthe user logged in directly. X.PP XAdditional arguments may be provided after the username, Xin which case they are supplied to the user\'s login shell. XIn particular, an argument of \fB-c\fR will cause the Xnext argument to be treated as a command by most command Xinterpreters. XThe command will be executed under the shell specified by X\fB$SHELL\fR, or if undefined, by the one specified in X\fI/etc/passwd\fR. X.PP XThe user will be prompted for a password, if appropriate. XInvalid passwords will produce an error message. XAll attempts, both valid and invalid, are logged to detect Xabuses of the system. X.PP XThe current environment is passed to the new shell. XThe value of \fB$PATH\fR is reset to \fB/bin:/usr/bin\fR Xfor normal users, or \fB/bin:/usr/bin:/etc\fR for the super user. X.SH CAVEATS X.PP XThis version of \fIsu\fR has many compilation options, only some of which Xmay be in use at any particular site. X.SH Files X/etc/passwd \- user account information X.br X/etc/shadow \- encrypted passwords and age information X.br X$HOME/.profile \- initialization script for default shell X.SH See Also Xlogin(1), Xsh(1) SHAR_EOF if test 1697 -ne "`wc -c < 'su.1'`" then echo shar: "error transmitting 'su.1'" '(should have been 1697 characters)' fi fi echo shar: "extracting 'shadow.3'" '(2801 characters)' if test -f 'shadow.3' then echo shar: "will not over-write existing file 'shadow.3'" else sed 's/^X//' << \SHAR_EOF > 'shadow.3' X.\" Copyright 1989, 1990, John F. Haugh II X.\" All rights reserved. X.\" X.\" Use, duplication, and disclosure prohibited without X.\" the express written permission of the author. X.\" X.\" @(#)shadow.3 3.1 23:49:42 11/11/90 X.\" X.TH SHADOW 3 X.SH NAME Xshadow \- encrypted password file routines X.SH Syntax X.IP "" .5i X#include <shadow.h> X.IP "" .5i Xstruct spwd *getspent(); X.br Xstruct spwd *getspnam(char * name); X.br Xvoid setspent(); X.br Xvoid endspent(); X.br Xstruct spwd *fgetspent(FILE *fp); X.br Xstruct spwd *sgetspent(char *cp); X.br Xint putspent(struct spwd *p,FILE *fp); X.SH DESCRIPTION X.I shadow Xmanipulates the contents of the shadow password file, X\fB/etc/shadow\fR. XThe structure in the \fI#include\fR file is X.IP "" .5i Xstruct spwd { X.br X char *sp_namp; /* user login name */ X.br X char *sp_pwdp; /* encrypted password */ X.br X long sp_lstchg; /* last password change */ X.br X int sp_min; /* days until change allowed. */ X.br X int sp_max; /* days before change required */ X.br X int sp_warn; /* days warning for expiration */ X.br X int sp_inact; /* days before account inactive */ X.br X int sp_expire; /* date when account expires */ X.br X int sp_flag; /* reserved for future use */ X.br X} X.PP XThe meanings of each field are X.IP "" .5i Xsp_namp \- pointer to null-terminated user name. X.IP "" .5i Xsp_pwdp \- pointer to null-terminated password. X.IP "" .5i Xsp_lstchg \- days since Jan 1, 1970 password was last changed. X.IP "" .5i Xsp_min \- days before which password may not be changed. X.IP "" .5i Xsp_max \- days after which password must be changed. X.IP "" .5i Xsp_warn \- days before password is to expire that user is warned Xof pending password expiration. X.IP "" .5i Xsp_inact \- days after password expires that account is considered Xinactive and disabled. X.IP "" .5i Xsp_expire \- days since Jan 1, 1970 that account will be disabled. X.IP "" .5i Xsp_flag \- reserved for future use. X.SH Description X\fIgetspent\fR, \fIgetspname\fR, \fIfgetspent\fR, and \fIsgetspent\fR Xeach return a pointer to a \fBstruct spwd\fR. X\fIgetspent\fR returns the Xnext entry from the file, and \fIfgetspent\fR returns the next Xentry from the given stream, which is assumed to be a file of Xthe proper format. X\fIsgetspent\fR returns a pointer to a \fBstruct spwd\fR using the Xprovided string as input. X\fIgetspnam\fR searches from the current position in the file for Xan entry matching \fIname\fR. X.PP X\fIsetspent\fR and \fIendspent\fR may be used to begin and end, Xrespectively, access to the shadow password file. X.SH Diagnostics XRoutines return NULL if no more entries are available or if an Xerror occurs during processing. X.SH Caveats XThese routines may only be used by the super user as access to Xthe shadow password file is restricted. X.SH Files X/etc/shadow \- encrypted user passwords X.SH See Also Xgetpwent(3), Xshadow(4) SHAR_EOF if test 2801 -ne "`wc -c < 'shadow.3'`" then echo shar: "error transmitting 'shadow.3'" '(should have been 2801 characters)' fi fi echo shar: "extracting 'faillog.4'" '(969 characters)' if test -f 'faillog.4' then echo shar: "will not over-write existing file 'faillog.4'" else sed 's/^X//' << \SHAR_EOF > 'faillog.4' X.\" Copyright 1989, 1990, John F. Haugh II X.\" All rights reserved. X.\" X.\" Use, duplication, and disclosure prohibited without X.\" the express written permission of the author. X.\" X.\" @(#)faillog.4 3.1 09:34:18 11/21/90 X.\" X.TH FAILLOG 4 X.SH NAME Xfaillog \- Login failure logging file X.SH DESCRIPTION X.I faillog Xmaintains a count of login failures and the limits for each account. XThe file is fixed length record, indexed by numerical UID. XEach record contains the count of login failures since the last Xsuccessful login; Xthe maximum number of failures before the account is disabled; Xthe line the last login failure occured on; Xand the date the last login failure occured. X.PP XThe structure of the file is X.DS X X struct faillog { X short fail_cnt; X short fail_max; X char fail_line[12]; X time_t fail_time; X }; X X.DE X.SH Files X/usr/adm/faillog \- login failure log X.SH See Also Xfaillog(8) SHAR_EOF if test 969 -ne "`wc -c < 'faillog.4'`" then echo shar: "error transmitting 'faillog.4'" '(should have been 969 characters)' fi fi echo shar: "extracting 'passwd.4'" '(2520 characters)' if test -f 'passwd.4' then echo shar: "will not over-write existing file 'passwd.4'" else sed 's/^X//' << \SHAR_EOF > 'passwd.4' X.\" Copyright 1989, 1990, John F. Haugh II X.\" All rights reserved. X.\" X.\" Use, duplication, and disclosure prohibited without X.\" the express written permission of the author. X.\" X.\" @(#)passwd.4 3.1 09:34:24 11/21/90 X.\" X.TH PASSWD 4 X.SH NAME Xpasswd \- The password file X.SH DESCRIPTION X.I passwd Xcontains various pieces of information for each user account. XIncluded is X.IP "" .5i XLogin name X.IP "" .5i XOptional encrypted password X.IP "" .5i XNumerical user ID X.IP "" .5i XNumerical group ID X.IP "" .5i XUser name or comment field X.IP "" .5i XUser home directory X.IP "" .5i XUser command interpreter X.PP XThe password field may not be filled if shadow passwords Xhave been enabled. XIf shadow passwords are being used, the encrypted password will Xbe found in \fB/etc/shadow\fR. XThe encryped password consists of 13 characters from the X64 character alphabet Xa thru z, A thru Z, 0 thru 9, \. and /. XRefer to \fIcrypt(3)\fR for details on how this string is Xinterpreted. X.PP XAn optional password age string may follow the encrypted Xpassword, separated by a comma, from the same alphabet Xas the password itself. XThe first character gives the number of weeks during which the Xpassword is valid. XThe second character gives the number of weeks which must pass Xbefore the user is permitted to change the password. XThe last two characters give the week since Jan 1970 when the Xpassword was last changed. XWhen the number of weeks during which the password is valid Xhave passed, the user will be required to provide a new Xpassword. X.PP XThe comment field is used by various system utilities, such as X\fIfinger(1)\fR. XThree additional values may be present in the comment field. XThey are X.IP "" .5i Xpri= \- set initial value of nice X.IP "" .5i Xumask= \- set initial value of umask X.IP "" .5i Xulimit= \- set initial value of ulimit X.PP XThese fields are separated from each other and from any other Xcomment field by a comma. X.PP XThe home directory field provides the name of the initial Xworking directory. X\fILogin\fR uses this information to set the value of Xthe \fBHOME\fR environmental variable. X.PP XThe command interpreter field provides the name of the user's Xcommand language interpreter, or the name of the initial program Xto execute. X\fILogin\fR uses this information to set the value of the X\fBSHELL\fR environmental variable. XIf this field is empty, it defaults to the value \fB/bin/sh\fR. X.SH Files X/etc/passwd \- user account information X.SH See Also Xlogin(1), Xpasswd(1), Xsu(1), Xsulogin(1M), Xshadow(4), Xpwconv(8), Xpwunconv(8) SHAR_EOF if test 2520 -ne "`wc -c < 'passwd.4'`" then echo shar: "error transmitting 'passwd.4'" '(should have been 2520 characters)' fi fi echo shar: "extracting 'porttime.4'" '(1872 characters)' if test -f 'porttime.4' then echo shar: "will not over-write existing file 'porttime.4'" else sed 's/^X//' << \SHAR_EOF > 'porttime.4' X.\" Copyright 1989, 1990, John F. Haugh II X.\" All rights reserved. X.\" X.\" Use, duplication, and disclosure prohibited without X.\" the express written permission of the author. X.\" X.\" @(#)porttime.4 3.2 08:36:07 2/8/91 X.\" X.TH PORTTIME 4 X.SH NAME Xporttime \- port access time file X.SH DESCRIPTION X.I porttime Xcontains a list of tty devices, user names, and permitted login times. X.PP XEach entry consists of three colon separated fields. XThe first field is a comma separated list of tty devices, Xor an asterisk to indicate that all tty devices are matched by this entry. XThe second field is a comma separated list of user names, or an Xasterisk to indicated that all user names are matched by this entry. XThe third field is a comma separated list of permitted access times. X.PP XEach access time entry consists of zero or more days of the week, Xabbreviated \fBSu\fR, \fBMo\fR, \fBTu\fR, \fBWe\fR, \fBTh\fR, X\fBFr\fR, and \fBSa\fR, followed by a pair of times separated by Xa hyphen. XThe abbreviation \fBWk\fR may be used to represent Monday thru Friday, Xand \fBAl\fR may be used to indicate every day. XIf no days are given, \fBAl\fR is assumed. X.SH Examples XThe following entry allows access to user \fBjfh\fR on every port Xduring weekdays from 9am to 5pm. X.br X.sp 1 X*:jfh:Wk0900-1700 X.br X.sp 1 XThe following entries allow access only to the users \fBroot\fR and X\fBoper\fR on /dev/console at any time. XThis illustrates how the X\fB/etc/porttime\fR file is an ordered list of access times. XAny other user would match the second entry which does not permit Xaccess at any time. X.br X.sp 1 Xconsole:root,oper:Al0000-2400 X.br Xconsole:*: X.br X.sp 1 XThe following entry allows access for the user \fBgames\fR on any Xport during non-working hours. X.br X.sp 1 X*:games:Wk1700-0900,SaSu0000-2400 X.br X.sp 1 X.SH Files X/etc/porttime \- file containing port access times X.SH See Also Xlogin(1) SHAR_EOF if test 1872 -ne "`wc -c < 'porttime.4'`" then echo shar: "error transmitting 'porttime.4'" '(should have been 1872 characters)' fi fi echo shar: "extracting 'shadow.4'" '(2122 characters)' if test -f 'shadow.4' then echo shar: "will not over-write existing file 'shadow.4'" else sed 's/^X//' << \SHAR_EOF > 'shadow.4' X.\" Copyright 1989, 1990, John F. Haugh II X.\" All rights reserved. X.\" X.\" Use, duplication, and disclosure prohibited without X.\" the express written permission of the author. X.\" X.\" @(#)shadow.4 3.1 23:49:44 11/11/90 X.\" X.TH SHADOW 4 X.SH NAME Xshadow \- encrypted password file X.SH DESCRIPTION X.I shadow Xcontains the encrypted password information for user's accounts Xand optional the password aging information. XIncluded is X.IP "" .5i XLogin name X.IP "" .5i XEncrypted password X.IP "" .5i XDays since Jan 1, 1970 that password was last changed X.IP "" .5i XDays before password may be changed X.IP "" .5i XDays after which password must be changed X.IP "" .5i XDays before password is to expire that user is warned X.IP "" .5i XDays after password expires that account is disabled X.IP "" .5i XDays since Jan 1, 1970 that account is disabled X.IP "" .5i XA reserved field X.PP XThe password field must be filled. XThe encryped password consists of 13 to 24 characters from the X64 character alphabet Xa thru z, A thru Z, 0 thru 9, \. and /. XRefer to \fIcrypt(3)\fR for details on how this string is Xinterpreted. X.PP XThe date of the last password change is given as the number Xof days since Jan 1, 1970. XThe password may not be changed again until the proper number Xof days have passed, and must be changed after the maximum Xnumber of days. XIf the minimum number of days required is greater than the Xmaximum number of day allowed, this password may not be Xchanged by the user. X.PP XAn account is considered to be inactive and is disabled if Xthe password is not changed within the specified number of Xdays after the password expires. XAn account will also be disabled on the specified day Xregardless of other password expiration information. X.PP XThis information supercedes any password or password age Xinformation present in \fB/etc/passwd\fR. X.PP XThis file must not be readable by regular users if password Xsecurity is to be maintained. X.SH Files X/etc/passwd \- user account information X.br X/etc/shadow \- encrypted user passwords X.SH See Also Xchage(1), Xlogin(1), Xpasswd(1), Xsu(1), Xsulogin(1M), Xshadow(3), Xpasswd(4), Xpwconv(8), Xpwunconv(8) SHAR_EOF if test 2122 -ne "`wc -c < 'shadow.4'`" then echo shar: "error transmitting 'shadow.4'" '(should have been 2122 characters)' fi fi echo shar: "extracting 'faillog.8'" '(2030 characters)' if test -f 'faillog.8' then echo shar: "will not over-write existing file 'faillog.8'" else sed 's/^X//' << \SHAR_EOF > 'faillog.8' X.\" Copyright 1989, 1990, John F. Haugh II X.\" All rights reserved. X.\" X.\" Use, duplication, and disclosure prohibited without X.\" the express written permission of the author. X.\" X.\" @(#)faillog.8 3.1 09:34:20 11/21/90 X.\" X.TH FAILLOG 8 X.SH NAME Xfaillog \- examine faillog and set login failure limits X.SH SYNOPSIS X/etc/faillog [ -u uid ] [ -t days ] [ -m max ] [ -pr ] X.SH DESCRIPTION X\fIPlastlog\fR formats the contents of the failure log, X\fI/usr/adm/faillog\fR, and maintains failure counts and Xlimits. XThe order of the arguments to \fIfaillog\fR is significant. XEach argument is processed immediately in the order given. X.PP XThe \fB-p\fR flag causes failure entries to be printed in UID Xorder. XEntering \fB-u login-name\fR flag will Xcause the failure record for \fBlogin-name\fR only to be printed. XEntering \fB-t days\fR will cause only the Xfailures more recent than \fBdays\fR to be printed. XThe \fB-t\fR flag overrides the use of \fB-u\fR. X.PP XThe \fB-r\fR flag is used to reset the count of login failures. XWrite access to \fI/usr/adm/faillog\fR is required for Xthis option. XEntering \fB-u login-name\fR will cause only the failure count Xfor \fBlogin-name\fR to be reset. X.PP XThe \fB-m\fR flag is used to set the maximum number of login Xfailures before the account is disabled. XWrite access to \fB/usr/adm/faillog\fR is required for this Xoption. XEntering \fB-m max\fR will cause all accounts to be disabled Xafter \fBmax\fR failed logins occur. XThis may be modified with \fB-u login-name\fR to limit this Xfunction to \fBlogin-name\fR only. XSelecting a \fBmax\fR value of 0 has the effect of not placing Xa limit on the number of failed logins. XThe maximum failure count Xshould always be 0 for \fBroot\fR to prevent Xa denial of services attack against the system. X.PP XOptions may be combined in virtually any fashion. XEach \fB-p\fR, \fB-r\fR, and \fB-m\fR option will cause Ximmediate execution using any \fB-u\fR or \fB-t\fR modifier. X.SH Files X/usr/adm/faillog \- failure logging file X.SH See Also Xlogin(1), Xfaillog(4) SHAR_EOF if test 2030 -ne "`wc -c < 'faillog.8'`" then echo shar: "error transmitting 'faillog.8'" '(should have been 2030 characters)' fi fi echo shar: "extracting 'pwconv.8'" '(1396 characters)' if test -f 'pwconv.8' then echo shar: "will not over-write existing file 'pwconv.8'" else sed 's/^X//' << \SHAR_EOF > 'pwconv.8' X.\" Copyright 1989, 1990, John F. Haugh II X.\" All rights reserved. X.\" X.\" Use, duplication, and disclosure prohibited without X.\" the express written permission of the author. X.\" X.\" @(#)pwconv.8 3.1 23:51:34 11/11/90 X.\" X.TH PWCONV 8 X.SH NAME Xpwconv \- convert and update shadow password files X.SH SYNOPSIS X/etc/pwconv X.SH DESCRIPTION X\fIPwconv\fR copies the old password file information to a new shadow Xpassword file, Xmerging entries from an optional existing shadow file. XThe new password file is left in \fBnpasswd\fR, Xthe new shadow file is left in \fBnshadow\fR. XBoth of these are files are created with modes which only permit Xread access to the owner. XExisting shadow entries are copied as is. XShadow entries in the old format will be silently converted to the Xnew format on output. XAny entries which are missing fields will have those fields Xfilled in with default values where appropriate. XNew entries are created with passwords which expire in 10000 days, Xwith a last changed date of today, Xunless password aging information was already present. XEntries with blank passwords are not copied to the shadow file at all. X.SH Files X/etc/passwd \- old encrypted passwords and password aging X.br X/etc/shadow \- previously converted shadow password file X.br X./npasswd \- new password file X.br X./nshadow \- new shadow password file X.SH See Also Xpasswd(1), Xpasswd(4), Xshadow(4), Xpwunconv(8) SHAR_EOF if test 1396 -ne "`wc -c < 'pwconv.8'`" then echo shar: "error transmitting 'pwconv.8'" '(should have been 1396 characters)' fi fi echo shar: "extracting 'pwunconv.8'" '(926 characters)' if test -f 'pwunconv.8' then echo shar: "will not over-write existing file 'pwunconv.8'" else sed 's/^X//' << \SHAR_EOF > 'pwunconv.8' X.\" Copyright 1989, 1990, John F. Haugh II X.\" All rights reserved. X.\" X.\" Use, duplication, and disclosure prohibited without X.\" the express written permission of the author. X.\" X.\" @(#)pwunconv.8 3.1 09:34:27 11/21/90 X.\" X.TH PWUNCONV 8 X.SH NAME Xpwunconv \- restore old password file from shadow password file X.SH SYNOPSIS X/etc/pwunconv X.SH DESCRIPTION X\fIPwunconv\fR copies the password file information from the shadow Xpassword file, Xmerging entries from an optional existing shadow file. XThe new password file is left in \fBnpasswd\fR. XThis file is created with modes which allow read access for Xthe owner only. XThere is no new shadow file. XPassword aging information is translated where possible. X.SH Files X/etc/passwd \- old encrypted passwords and password aging X.br X/etc/shadow \- previously converted shadow password file X.br X./npasswd \- new password file X.SH See Also Xpasswd(1), Xpasswd(4), Xshadow(4), Xpwconv(8) SHAR_EOF if test 926 -ne "`wc -c < 'pwunconv.8'`" then echo shar: "error transmitting 'pwunconv.8'" '(should have been 926 characters)' fi fi echo shar: "extracting 'sulogin.8'" '(1611 characters)' if test -f 'sulogin.8' then echo shar: "will not over-write existing file 'sulogin.8'" else sed 's/^X//' << \SHAR_EOF > 'sulogin.8' X.\" Copyright 1989, 1990, John F. Haugh II X.\" All rights reserved. X.\" X.\" Use, duplication, and disclosure prohibited without X.\" the express written permission of the author. X.\" X.\" @(#)sulogin.8 3.1 09:34:30 11/21/90 X.\" X.TH SULOGIN 8 X.SH NAME Xsulogin \- Single-user login X.SH DESCRIPTION X.I sulogin Xis invoked by \fB/etc/init\fR prior to allowing the user Xaccess to the system when in single user mode. XThis feature may only be available on certain systems where X\fIinit\fR has been modified accordingly, or where the X\fB/etc/inittab\fR has an entry for a single user login. X.PP XThe user is prompted X.IP "" .5i XType control-d for normal startup, X.br X(or give root password for system maintenance): X.PP XIf the user enters the correct root password, a login session Xis initiated. XWhen \fBEOF\fR is pressed instead, the system enters multi-user Xmode. X.PP XAfter the user exits the single-user shell, or presses \fBEOF\fR, Xthe system begins the initialization process required to enter Xmulti-user mode. X.SH CAVEATS X.PP XThis command can only be used if \fIinit\fR has been modified to call X\fB/etc/sulogin\fR instead of \fB/bin/sh\fR, Xor if the user has set the \fIinittab\fR to support a single user Xlogin. X.PP XAs complete an environment as possible is created. XHowever, various devices may be unmounted or uninitialized and many Xof the user commands may be unavailable or nonfunctional as a result. X.SH Files X/etc/passwd \- user account information X.br X/etc/shadow \- encrypted passwords and age information X.br X/.profile \- initialization script for single user shell X.SH See Also Xlogin(1), Xinit(1M), Xsh(1) SHAR_EOF if test 1611 -ne "`wc -c < 'sulogin.8'`" then echo shar: "error transmitting 'sulogin.8'" '(should have been 1611 characters)' fi fi exit 0 # End of shell archive -- John F. Haugh II | Distribution to | UUCP: ...!cs.utexas.edu!rpp386!jfh Ma Bell: (512) 255-8251 | GEnie PROHIBITED :-) | Domain: jfh@rpp386.cactus.org "If liberals interpreted the 2nd Amendment the same way they interpret the rest of the Constitution, gun ownership would be mandatory."