ignatz@chinet.chi.il.us (Dave Ihnat) (12/19/88)
As I said in the group unix-pc.general, I goofed. Last minute upgrades == last minute goofs. Anyway, it's for the better--this has some extensions and modifications that improve it (in my view.) It's small, so it's a total repost; just discard the last version, if my cancel didn't get to it before you saved it. -Dave Ihnat ===================== Hier Schneiden ============================ #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: Ifile.sh Makefile pwcntl.1 pwcntl.4 pwcntl.c pwcntl.h # pwcntl.notes # Wrapped by ignatz@chinet on Sun Dec 18 13:33:11 1988 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f Ifile.sh -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"Ifile.sh\" else echo shar: Extracting \"Ifile.sh\" \(705 characters\) sed "s/^X//" >Ifile.sh <<'END_OF_Ifile.sh' Xex - $1 << EOF X1,\$s/^PC/xPC/ X1,\$s/^BC/xBC/ X1,\$s/^UP/xUP/ X1,\$s/^ospeed/xospeed/ X1,\$s/^LINES/xLINES/ X1,\$s/^COLS/xCOLS/ X1,\$s/^tgetflag/xtgetflag/ X1,\$s/^tgetent/xtgetent/ X1,\$s/^tgetstr/xtgetstr/ X1,\$s/^tgetnum/xtgetnum/ X1,\$s/^tgoto/xtgoto/ X1,\$s/^tputs/xtputs/ X1,\$s/^wrefresh/xwrefresh/ X1,\$s/^initscr/xinitscr/ X1,\$s/^cbreak/xcbreak/ X1,\$s/^nl/xnl/ X1,\$s/^flushinp/xflushinp/ X1,\$s/^noecho/xnoecho/ X1,\$s/^savetty/xsavetty/ X1,\$s/^resetty/xresetty/ X1,\$s/^echo/xecho/ X1,\$s/^nocbreak/xnocbreak/ X1,\$s/^nonl/xnonl/ X1,\$s/^keypad/xkeypad/ X1,\$s/^endwin/xendwin/ X1,\$s/^printw/xprintw/ X1,\$s/^fixterm/xfixterm/ X1,\$s/^resetterm/xresetterm/ X1,\$s/^setterm/xsetterm/ X1,\$s/^baudrate/xbaudrate/ Xw Xq XEOF END_OF_Ifile.sh if test 705 -ne `wc -c <Ifile.sh`; then echo shar: \"Ifile.sh\" unpacked with wrong size! fi # end of overwriting check fi if test -f Makefile -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"Makefile\" else echo shar: Extracting \"Makefile\" \(636 characters\) sed "s/^X//" >Makefile <<'END_OF_Makefile' X# @(#)Makefile 1.1 12/18/88 X X# Normal distribution XCFLAGS = -O XLDFLAGS = -s XCRT= /lib/crt0s.o XLIBC= ./shlib_c.ifile X X# Debug version X#CFLAGS = -g -DSHELL X#LDFLAGS = -lg X#CRT=/lib/crt0.o X#LIBC= /lib/libc.a X XOBJECTS = pwcntl.o \ X setvbuf.o \ X doprnt.o X Xpwcntl: $(OBJECTS) shlib_c.ifile X $(LD) $(LDFLAGS) -o pwcntl $(OBJECTS) -lcurses $(CRT) $(LIBC) X Xsetvbuf.o : /lib/libc.a X ar xv /lib/libc.a setvbuf.o X Xdoprnt.o : /lib/libc.a X ar xv /lib/libc.a doprnt.o X X# Thanks to Emmet Gray for his ifile shellscript and scheme Xshlib_c.ifile: X cp /lib/shlib.ifile shlib_c.ifile X sh Ifile.sh shlib_c.ifile X Xclean: X - rm -f pwcntl shlib_c.ifile *.o END_OF_Makefile if test 636 -ne `wc -c <Makefile`; then echo shar: \"Makefile\" unpacked with wrong size! fi # end of overwriting check fi if test -f pwcntl.1 -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"pwcntl.1\" else echo shar: Extracting \"pwcntl.1\" \(8024 characters\) sed "s/^X//" >pwcntl.1 <<'END_OF_pwcntl.1' X.\" @(#)pwcntl.1 1.3 12/18/88 X.TH PWCNTL 1 " Public Domain Utilities" X.SH NAME Xpwcntl \- dump and administer the Unix PC/7300/3B1 /etc/pwcntl file X.SH SYNOPSIS X\fBpwcntl -d\fP [ \fB-i\fP][ \fB-s\fP [\fBname\fP|\fBlast\fP]] [ \fB-c\fP][ \fB-v\fP][ \fB-f\fP filename] X.br X\fBpwcntl\fP [ \fB-e\fP | \fB-u\fP][ \fB-c\fP][ \fB-v\fP][\fB-f\fP filename] X.SH DESCRIPTION XThere is a file on the AT&T Unix PC, or 7300, or 3B1--take your pick--which Xis maintained by the normal system login (and/or user administration) Xprograms which provides certain information about login attempts. This Xprogram provides a means of examining and maintaining this file--a Xcapability not provided by AT&T (which isn't surprising, as they didn't Xdocument it, either.) X.PP XThe program has two main modes of operation. One mode provides for a Xnon-interactive line-oriented dump of the information in the file, suitable Xfor printing (or framing, I suppose, if you're so inclined.) Of course, Xit has several modifying options to tailor the output. XThe second mode provides for an interactive perusal of the file, with a Xfull-screen display. When in this mode with the update option Xspecified, the user may perform file maintenance functions, including Xthe deletion of records (presumably to clean up dead users or bogus Xlogin information), correction of the space indication, etc. X.PP XWith either mode, or simply by itself, there is an option to force Xrecalculation of space usage for every valid login recorded. (Note that Xspace calculations are only for the login's home directory; any directory Xstructures or files that belong to that login, but are resident elsewhere, Xwill not enter into the calculation.) The provision exists at program Xgeneration to exempt certain logins from the space calculation--for Xinstance, \fIroot\fP would appear to own the whole system, since its home Xdirectory is usually recorded as \fB/\fP. Similarly, uucp access logins Xcommonly have the directory \fB/usr/spool/uucppublic\fP as the home directory; Xcalculating the space used would be meaningless. X.PP XA number of checks are made to assure and indicate validity of the login Xinformation in the file. As all login attempts--including those for Xnon-existent logins--are logged, there can be a potentially large number of Xthese records. Normally they only indicate mistyped valid login attempts, Xbut this does provide some intruder detection. X.SS Options XThe space calculation and file options are valid for either the dump or Xinteractive modes of operation; all others are valid with only one or the Xother, as indicated. Options may be provided in any order. X.TP X\fB-d\fP X.br XDump. 80-column output is to stdout. X.TP X\fB-e\fP X.br XExamine. Allows interactive examination on a per-record full-screen basis. X.TP X\fB-u\fP X.br XUpdate. Allows changes to the file data as indicated on the screen. Valid only Xwith interactive mode (i.e., no \fB-d\fP option.) X.TP X\fB-i\fP X.br XInvalid logins only (Only with 'd' option). Only those file records identified as bad logins (\fBL\fP flag at the end of the line), or with User ID values that Xdon't match the current value in the password file (\fBI\fP flag) are dumped. X.TP X\fB-c\fP X.br XCalculate space. Either standalone, or before further processing for either Xdumps or interactive sessions, it scans the file and performs space calculations Xfor only the valid records, updating the file upon completion of the scan. X(This can take some time.) X.TP X\fB-v\fP X.br XVerbose mode. Provides more detailed informative messages, particularly when Xperforming long background tasks such as global space recalculate. X.TP X\fB-s\fP X X.br XSort. Must have either X=name, for by Name order, or X=last, for Lastlog order. X(Only with 'd' option.) Actually, the flags may be shortened to only \fIn\fP Xor \fIl\fP. X.TP X\fB-f\fP filename X.br XUse alternate filename; default is /etc/pwcntl. It may be preferable, while Xlearning how to use the program, to copy /etc/pwcntl to another file and test Xon that. X.SS Screen XThe interactive screen is quite self-explanatory. The commands that perform Xmodifications on the file are not honored unless the update option is selected; Xthis is indicated by offering them on the menu. X.PP XCommands always honored are: X.TP X\fBN\fP XNext record X.TP X\fBP\fP XPrevious record X.TP X\fBT\fP XTop of file X.TP X\fBB\fP XBottom of file X.TP X\fBR\fP XRefresh screen X.TP X\fBQ\fP XQuit. Any changes will be recorded in the file. To abort changes, send an Xinterrupt or quit signal. X.PP XModification commands are: X.TP X\fBD\fP XDelete. Flagged only; takes effect on exit. X.TP X\fBU XUndelete. Restores record for rewrite on close. X.TP X\fP\fBE\fP XExpert toggle. Toggles the state of the Expert flag. X.TP X\fBS\fP XSpace calculation. Calculates space used in the home directory of this user Xonly. X.TP X\fBI\fP XUser ID correction. If the user ID in the password file has changed since this Xrecord was logged, the recorded ID will be incorrect. This command updates the Xrecorded user ID from the password file information. X.SS Output XThe output from the dump option is fairly self-explanatory; it is simply a Xformatted dump of the information contained in the /etc/pwcntl file. One Xexception is the flag field. If the record is abnormal--either a bad login Xattempt, or a mismatched user ID--then a one-character flag will be appended to Xthe end of the line. An \fBL\fP indicates a bad login attempt, i.e., the login Xname recorded doesn't exist in the password file. An \fBI\fP indicates a bad Xuser id for a valid login. X.PP XOutput was designed to fit on an 80-column page. However, two conditions may Xcause this to overwrap. First, a user may type anything at the login prompt; Xthus, an excessively long name, or a name containing control characters, may Xcause the output to exceed, or fall short, of its intended format length. XSecondly, an excessive amount of disk space allocation--for instance, if root Xowns a disproportionately large number of files, or you've a very large source Xdatabase owned by a caretaker--may cause the space allocation field to expand Xpast its bounds. These effects are, however, purely cosmetic, and are the Xexception rather than the norm. X.SH FILES X/etc/pwcntl X.SH SEE ALSO Xpwcntl(4) X.SH WARNINGS XThis program should \fBnot\fP be run setuid or setgid. Only execute from an Xaccount with appropriate permissions. Normal users should not be permitted to Xeven peruse the file, since often passwords may be mistyped instead of logins. X.PP XNotice that the program has the same name as the file it is supposed to manage. XThis is deliberate--it's easy to remember, and if you just bury this in /etc, Xyou stand a chance of losing it whenever you have to move to a new upgrade, or Xhave to recover your disk. If you don't like that, feel free to rename it Xlocally. Whatever--\fBdon't\fP blindly copy this into /etc! X.SH DIAGNOSTICS XA number of informative text messages are emitted in case of exceptions. X.SH CAVEATS XChanges during an update or space calculation session may be aborted by an Xinterrupt or quit signal, and file integrity is assured. Once the normal Xprogram exit is taken, however, the changes are permanent. No backup is Xtaken of the file by the program. X.PP XWhile running the program for update or space calculation, normal logging is Xprohibited. X.PP XI deliberately didn't allow creation of records. This will happen with the Xfirst login of an unknown valid user, anyway. In a similar manner, I didn't Xallow unrestricted editing of information in the file--it's logging information, Xand shouldn't be fudged. X.PP XThis program hasn't yet undergone extensive testing-by-use. Please notify me Xat ignatz@homebru.chi.il.us of any bugs (and fixes, if you have them), Xenhancements, etc. (Attaboys are always welcome, too...) X.SH CREDITS XThanks to Mike Ditto and Dave Wexelblat (and anyone else I may Xforget--sorry) for responding to my initial query as to the structure of Xthe /etc/pwcntl file. This saved me a couple of hours of poking about Xthat I didn't really want to spend. END_OF_pwcntl.1 if test 8024 -ne `wc -c <pwcntl.1`; then echo shar: \"pwcntl.1\" unpacked with wrong size! fi # end of overwriting check fi if test -f pwcntl.4 -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"pwcntl.4\" else echo shar: Extracting \"pwcntl.4\" \(1129 characters\) sed "s/^X//" >pwcntl.4 <<'END_OF_pwcntl.4' X.\" @(#)pwcntl.4 1.1 12/18/88 X.TH PWCNTL 4 "#Public Domain Utilities" X.SH NAME Xpwcntl \- Unix PC/7300/3B1 /etc/pwcntl file format X.SH SYNOPSIS X\fB#include <sys/pwcntl.h>\fP X.SH DESCRIPTION XThe file \fB/etc/pwcntl\fP holds login information gleaned by \fIlogin\fP, Xand maintained by the UA utility \fIUlogin\fP. The structure, as defined by Xthe file \fIpwcntl.h\fP, is as follows: X.nf X X struct pwrec { X char logon[8]; /* user name from login arg1 */ X int uid; /* uid from /etc/passwd */ X char expert; /* Y/N flag for expert mode */ X char flg; /* unused (pad) */ X time_t timeon; /* time of most recent login */ X time_t timecr; /* time of first login */ X long space; /* disk space used in blocks, X * only used in Ulogin after Compute Space X * has been selected. X */ X }; X X.fi X.SH FILES X/etc/pwcntl X.SH SEE ALSO Xpwcntl(1) X.SH CAVEATS XThis file is not distributed with the Unix PC/7300/3B1 software, but rather Xis derived from perusal of the file itself. X.SH CREDITS XThanks to Mike Ditto and Dave Wexelblat (and anyone else I may Xforget--sorry) for responding to my initial query as to the structure of Xthis file. END_OF_pwcntl.4 if test 1129 -ne `wc -c <pwcntl.4`; then echo shar: \"pwcntl.4\" unpacked with wrong size! fi # end of overwriting check fi if test -f pwcntl.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"pwcntl.c\" else echo shar: Extracting \"pwcntl.c\" \(23716 characters\) sed "s/^X//" >pwcntl.c <<'END_OF_pwcntl.c' X/* @(#)pwcntl.c 1.2 12/18/88 */ X/* X * pwcntl - AT&T 7300/3B1 /etc/pwcntl file manager utilty X * X * Author: David M. Ihnat X * ignatz@homebru.chi.il.us X * (312) 784-4544 X * X * December 11, 1988 X * X * This is a work donated to the Public Domain. As such, it may be used in any X * way desired. I do request that you at least allow the credit (or blame) to X * remain mine. X * X * See the manual page for detailed discussion of the features and modes of X * operation; important assumptions and design approach information should X * be kept here in the source file. X * X * The major assumption made is that the file will always be small enough X * to be kept in memory. This is not unreasonable, since each record in X * the file is only 26 bytes in length, and on the 7300/3B1--a small box-- X * even, say, 1000 records--an outrageous number!--would only take 26000 X * bytes to hold in memory. Even a 2000 record file would be much less X * than 64K. However, the first draft of the program was implemented using X * tempfiles, and the conversion to a memory-based model took 30 minutes. X * Going the other way would be similarly easy, with the exception of the X * dump sorting. X * X * Protection from unauthorized modification of the file is provided only X * by normal Unix file permissions; the program must be run by an X * appropriately privileged user. DON'T run it setuid/setgid; that would X * be tantamount to leaving /etc/pwcntl 666. X * X * When enabled for update or space calculation, the file is locked. This X * effectively prevents update during execution, and maintains a consistent X * view of the file from the maintainer's point of view, but it will X * interfere with normal logging of user access attempts during the program X * execution. X * X * The information returned from getpwnam is assumed to always be correct, X * and is used to indicate bad login attempts or user IDs. X * X * It is assumed that a time of last login of 0L indicates NEVER LOGGED IN. X * should this be false, please correct it and notify me by email. X * X * The ifile provided is for 3.51. If you're running 3.50, it should work; X * if it doesn't, the changes are fairly simple--it's the old curses thing. X * Just compare your /lib/shlib.ifile with this one, and make the changes X * for your system. (Even though the program is only for the 3B1--so X * portability isn't an issue--I decided I didn't want to play with TAM X * directly.) X * X * Outside of the above, the program is quite straightforward. Please mail any X * bug reports, comments, or corrections to me, and I'll attempt to keep a X * current version. X * X * CREDITS X * Thanks to Mike Ditto and Dave Wexelblat (and anyone else I may X * forget--sorry) for responding to my initial query as to the structure of X * the /etc/pwcntl file. This saved me a couple of hours of poking about X * that I didn't really want to spend. X */ X X#define PATCHLEVEL 0 X X#include <sys/types.h> X#include <string.h> X#include <stdio.h> X#include <fcntl.h> X#include <sys/stat.h> X#include <time.h> X#include <curses.h> X#include <sys/signal.h> X#include <memory.h> X#include <pwd.h> X#include <errno.h> X#include "pwcntl.h" X X/* Some system calls and functions used in multiple places */ Xextern void exit(); Xextern void perror(); Xextern unsigned sleep(); X Xtypedef struct { X int y; X int x; X char *label; X} SCRFRM; X Xtypedef struct { X int y; X int x; X char *fmt; X} SCRDATA; X X/* Following are the fixed screen form definitions */ X#define UPDCMDS 9 X XSCRFRM sform[] = { X { 0, 0, "** pwcntl data ** Total records: " }, X { 1, 0, "Current record: " }, X { 2, 0, "logon: " }, X { 2, 40,"Uid: "}, X { 2, 60,"Expert: " }, X { 4, 0, "Login created: " }, X { 4, 40,"Last Login: " }, X { 6, 0, "Space Used (blocks): " }, X { 8, 0, "Commands: (N)ext, (P)revious, (T)op, (B)ottom, (R)efresh, (Q)uit" }, X { 9, 0, " (D)elete, (U)ndelete, (E)xpert toggle, (S)pace calculate, (I)uId fix" }, X { 21, 0, "Status: " }, X { 23, 0, "Command: " }, X { -1, -1,(char *)NULL } X}; X X#define CURREC 0 X#define LOGIN CURREC+1 X#define RECCNT LOGIN+1 X#define UID RECCNT+1 X#define EXPERT UID+1 X#define CREATE EXPERT+1 X#define LASTLOG CREATE+1 X#define SPACE_USED LASTLOG+1 X#define DELETED SPACE_USED+1 X X#define BAD_LOGIN DELETED+1 X#define BAD_UID BAD_LOGIN+1 X X/* Some positions we need... */ X#define CMDIN_Y 23 X#define CMDIN_X 9 X X#define STATUS_Y 21 X#define STATUS_X 8 X X#define RECSTAT_Y 3 X#define RECSTAT_X 0 X X#define CURREC_Y 1 X#define CURREC_X 16 X X/* Data Elements */ XSCRDATA data[] = { X { 1, 16, "%5.5d" }, X { 2, 7, "%-20.20s" }, /* Login ID (recorded) */ X { 0, 40, "%5.5d" }, /* Record count (permanent) */ X { 2, 45, "%3.3d" }, /* UID (recorded) */ X { 2, 68, "%c" }, /* Expert Flag */ X { 4, 15, "%24.24s" }, /* Creation Date */ X { 4, 52, "%24.24s" }, /* Last login date */ X { 6, 21, "%6.6ld" }, /* Space Used */ X { 7, 0, "%7.7s" }, /* DELETED flag */ X X /* OPTIONAL DATA FIELDS */ X { 3, 0, "**BAD LOGON**" }, X { 3, 40, "**BAD UID (should be %d)**" } X}; X X/* Sort information */ Xint (*comp_routine)() = NULL; X X/* File access status indicators and data */ X#define F_NORM 0 X#define F_TOP 1 X#define F_EOF 2 X X/* Data disposition on termination or dump to file */ X#define KEEP 0 X#define FREE 1 X Xint fstatus; /* This is the current status of the 'tempfile' */ Xchar *f_statext[] = { X " ", X "File at TOP", X "File at EOF", X}; X X/* Used for record validation, and space calculation */ Xstruct passwd *passwdrec; Xstruct passwd *getpwnam(); X X/* X * Exception list. On a per-site basis, there may be some users or login X * name conventions for which it makes no sense to do a space calculation. X * In this event, include either the full login name, or the initial unique X * portion of the name, in this list at compile time. Their space usage will X * be set to zero on any space recalculation. X */ Xchar *nospace_list[] = { X "root", /* Owns everything */ X (char *)NULL /* TERMINATOR -- ALWAYS LAST */ X}; X X/* To mark deleted entries, a rather unlikely size */ X#define DELREC 0x696969L X X/* The star of the show */ X#define PWCNTL "/etc/pwcntl" Xchar *pw_fname = PWCNTL; X X#define VERSION "1.2 12/18/88" X Xstatic int updateflag = 0; Xstatic int spaceflag = 0; Xstatic int dumpflag = 0; Xstatic int examflag = 0; Xstatic int invflag = 0; Xstatic int verbflag = 0; Xstatic int errflag = 0; X Xstatic char interactive= 0; /* Set as byproduct of update, or no dumpflag */ X XFILE *oldfdes = (FILE *)NULL; X X/* File statistic and manipulation routines. */ Xint reccnt; /* Count of valid records */ Xint currec; /* Current record in file (index into datarec) */ X Xstruct pwrec *data_recs; /* Data structure holding the file data */ X Xmain(argc,argv) Xint argc; Xchar **argv; X{ X register int ch; X extern char *optarg; X X void dospace(); X extern int by_name(); X extern int by_login(); X X while((ch = getopt(argc,argv,"eicduvs:f:")) != EOF) X switch(ch) X { X case 'd': /* Dump */ X dumpflag = 1; X break; X X case 'e': /* Examine interactively */ X examflag++; X break; X X case 's': /* Sorting */ X if(*optarg == 'n' || *optarg == 'N') X comp_routine = by_name; X X else X if(*optarg == 'l' || *optarg == 'L') X comp_routine = by_login; X X else X errflag++; X X break; X X case 'i': /* Invalid list only */ X invflag++; X break; X X case 'c': /* Calculate space for all */ X spaceflag++; X break; X X case 'u': /* Update */ X updateflag = 1; X break; X X case 'v': /* Verbose (non-interactive */ X verbflag++; X break; X X case 'f': /* Alternate file */ X pw_fname = optarg; X break; X X case '?': /* Huh? */ X errflag++; X } X X /* A series of consistency checks */ X if(updateflag) X examflag++; X X if(!dumpflag && !examflag && !spaceflag) X errflag++; X X if(updateflag && dumpflag) X errflag++; X X if((comp_routine != NULL) && !dumpflag) X errflag++; X X if(interactive && invflag) X errflag++; X X X if(errflag) X usage(); X X if((!dumpflag && !updateflag && !spaceflag) || updateflag ) X interactive++; X X /* Only show update commands if in update mode */ X if(!updateflag) X sform[UPDCMDS].label = ""; X X (void)printf("pwcntl Version %s\n",VERSION); X X if(spaceflag) X { X dospace(); X spaceflag = 0; /* For exit processing */ X } X X if(dumpflag) X dumpit(); X X if(examflag) X screenit(); X X return(0); X} X/**/ Xvoid Xdospace() X{ X struct pwrec *pw; X register int index; X X struct pwrec *getrec(); X long spacerec(); X void purge_data(); X void load_file(); X extern int end_proc(); X extern int (*signal())(); X X if(verbflag) X printf("Doing space recalculation for all valid recorded logins.\n"); X /* X * As for the normal startup code. Notice that we neither save, nor X * restore, the signal values, even though they might get reset later X * if this is in conjunction with an update. No problem--no settings X * are needful of being saved or restored in any case. X */ X for(index = 1; index <= SIGUSR2; index++) X (void)signal(index,end_proc); X X updateflag +=2; /* If in update, just increments; if not, are now */ X load_file(); /* Will fail horribly and not return, if necessary */ X X pw = getrec(); X while(fstatus == F_NORM || fstatus == F_TOP) X { X if(verbflag) X { X printf("%s...",pw->logon); X fflush(stdout); X } X X passwdrec = getpwnam(pw->logon); X X if(passwdrec == (struct passwd *)NULL) X { X if(verbflag) X printf("INVALID LOGIN. Skipping.\n"); X X continue; /* Don't process bad records */ X }else X if(passwdrec->pw_uid != pw->uid) X if(verbflag) X { X printf("WARNING: UID MISMATCH. Processing..."); X fflush(stdout); X } X X X pw->space = spacerec(); X if(pw->space < 0L) X { X if(verbflag) X printf("EXEMPTED USER. Set to zero.\n"); X X pw->space = 0L; X }else X if(verbflag) X printf("%ld blocks.\n",pw->space); X X pw = getrec(); X X } X X if(fstatus != F_EOF) X { X (void)fprintf(stderr,"FATAL ERROR: Failure on space calculate(%d)\n", X fstatus); X (void)fprintf(stderr,"Updates lost; file intact.\n"); X exit(-1); X } X X /* If not in update, will close & release all; else, will hold file */ X updateflag -= 2; X if(updateflag == 1) X purge_data(KEEP); X else X purge_data(FREE); X X if(verbflag) X printf("\n**Done with recalculation.**\n"); X X return; X} X/**/ Xdumpit() X{ X struct pwrec *pw; X register int rec_sts; X X void qsort(); X void load_file(); X X load_file(); X X if((comp_routine != NULL)) X qsort((char *)data_recs,reccnt,sizeof(struct pwrec),comp_routine); X X (void)printf("User Uid Exp. First Last Disk\n"); X (void)printf(" Flg Login Logged in Used\n"); X (void)printf("------------------------------------------------------------------------------\n"); X X pw = getrec(); X while(fstatus == F_NORM || fstatus == F_TOP) X { X rec_sts = ' '; X X passwdrec = getpwnam(pw->logon); X if(passwdrec == (struct passwd *)NULL) X rec_sts = 'L'; X else X X if((passwdrec->pw_uid != pw->uid) && rec_sts == ' ') X rec_sts = 'U'; X X if(rec_sts == ' ' && invflag) X continue; X X (void)printf("%-8.8s %4.4d %c %24.24s %24.24s %5.5ld %c\n", X pw->logon,pw->uid,pw->expert, X ctime(&pw->timecr), X ((pw->timecr!=pw->timeon)?ctime(&pw->timeon):"** NEVER LOGGED ON **"), X pw->space,rec_sts); X X pw = getrec(); X } X X (void)printf("\nTotal: %d users recorded.\n",reccnt); X X return(0); X} X/**/ Xscreenit() X{ X struct pwrec *pw; X register int cmd_ch; X register int index; X register int readit = 0; X X struct pwrec *getrec(); X long atol(); X long spacerec(); X void load_data(); X void purge_data(); X void startup(); X X /* Ok, let's see how startup works. We won't return on fatal errors. */ X startup(); X X /* Display the initial record count (set in startup) */ X mvprintw(STATUS_Y,STATUS_X,"%d records",reccnt); X refresh(); X X /* Wow--it all worked! Now enter the record loop */ X for(readit++;;) X { X if(readit) X pw = getrec(); X X readit = 0; X X if((fstatus != F_EOF)||(fstatus == F_NORM)||(fstatus == F_TOP)) X load_data(pw); /* Stuff the data into the data areas */ X else X { X move(STATUS_Y,STATUS_X); X clrtoeol(); X X mvprintw(STATUS_Y,STATUS_X,"%s",f_statext[fstatus]); X refresh(); X }; X X cmd_ch = getch(); X X switch(cmd_ch) X { X case 't': /* Top of file */ X fstatus = F_TOP; X currec = -1; X readit++; X break; X X case 'b': /* Bottom of file */ X X currec = reccnt - 2; X fstatus = F_NORM; X readit++; X break; X X case 'p': /* Previous record */ X if(currec <= 0) X { X fstatus = F_TOP; X break; X }; X X readit++; X currec -= 2; X X break; X X case 'n': /* Next record */ X case '\n': X readit++; X break; X X case 'q': X purge_data(FREE); X X end_proc(0); X break; X X case 'r': /* Screen refresh */ X clear(); X for(index = 0; sform[index].x >= 0;index++) X mvprintw(sform[index].y,sform[index].x,"%s",sform[index].label); X refresh(); X break; X X#ifdef SHELL X /* Diagnostic, and not all that clean. */ X case '!': /* Shell */ X if(!fork()) X { X (void)setuid(getuid()); X (void)setgid(getgid()); X X noraw(); X echo(); X clear(); X refresh(); X X /* Don't care what happens... */ X (void)system("/bin/ksh"); X X raw(); X noecho(); X clear(); X for(index = 0; sform[index].x >= 0;index++) X mvprintw(sform[index].y,sform[index].x,"%s",sform[index].label); X refresh(); X }else X (void)wait((int *)0); X X break; X#endif X X case 'd': /* Delete current record */ X if(!updateflag) X break; X X pw->space = DELREC; X updateflag++; X X break; X X case 'u': /* Undelete current record */ X X if(!updateflag || (pw->space != DELREC)) X break; X X pw->space = 0L; X updateflag++; X X break; X X case 'e': /* Expert toggle */ X if(!updateflag) X break; X X pw->expert = (pw->expert=='Y'?'N':'Y'); X updateflag++; X X break; X X case 'i': /* Uid fix */ X if(!updateflag) X break; X X pw->uid = passwdrec->pw_uid; X updateflag++; X X break; X X case 's': /* Space calculate */ X if(!updateflag) X break; X X mvprintw(STATUS_Y,STATUS_X,"Be patient..."); X refresh(); X pw->space = spacerec(); X if(pw->space < 0L) X { X X mvprintw(STATUS_Y,STATUS_X,"Exempted user."); X pw->space = 0L; X }else X mvprintw(STATUS_Y,STATUS_X,"Space recalculation done!"); X X refresh(); X (void)sleep(1); X X updateflag++; X X break; X } X } X} X/**/ Xlong Xspacerec() X{ X /* X * The routine assumes that the passwd record contains the X * valid password field for the current record. X */ X FILE *pipfdes; X char *cmdbuf; X register char *tmpptr; X char **listptr; X long space_ret; X X extern char *malloc(); X extern void free(); X X /* See if the user is an exception. If so, return negative flag. */ X for(listptr = nospace_list;*listptr != (char *)NULL;listptr++) X if(!strncmp(*listptr,passwdrec->pw_name,strlen(*listptr))) X return(-1L); X X /* '/bin/du -s ' + user's dirpath + null */ X cmdbuf = malloc((unsigned)(11+strlen(passwdrec->pw_dir)+1)); X if(cmdbuf == (char *)NULL) X { X perror("spacerec (malloc)"); /* Not fatal */ X return(0L); X } X X (void)strcpy(cmdbuf,"/bin/du -s "); X (void)strcat(cmdbuf,passwdrec->pw_dir); X pipfdes = popen(cmdbuf,"r"); X X /* It'll fit here, and we know it's at least this long */ X (void)fgets(cmdbuf,12,pipfdes); X X for(tmpptr = cmdbuf; X ((*tmpptr >= '0')&&(*tmpptr <= '9')); X tmpptr++); X X *tmpptr = '\0'; X X space_ret = atol(cmdbuf); X X (void)pclose(pipfdes); X (void)free(cmdbuf); X X return(space_ret); X} Xvoid Xload_data(recptr) Xstruct pwrec *recptr; X{ X /* X * Load the data into the screen and force an update. X * Notice that there is an actual check for the login ID and the X * UID in the system password file for each entry passed! X */ X register SCRDATA *curelt; X X /* Data is highlighted */ X standout(); X X /* Always clear out the error status line. */ X move(RECSTAT_Y,RECSTAT_X); X clrtoeol(); X X /* Load the current record number (one-based) */ X curelt = &data[CURREC]; X mvprintw(curelt->y,curelt->x,curelt->fmt,(currec+1)); X X /* Load the login name. */ X curelt = &data[LOGIN]; X mvprintw(curelt->y,curelt->x,curelt->fmt,recptr->logon); X X /* On to the UID */ X curelt = &data[UID]; X mvprintw(curelt->y,curelt->x,curelt->fmt,recptr->uid); X X /* Are the UID and the logon name good? */ X passwdrec = getpwnam(recptr->logon); X X if(passwdrec == (struct passwd *)NULL) X mvprintw(data[BAD_LOGIN].y,data[BAD_LOGIN].x,data[BAD_LOGIN].fmt); X else X X if(passwdrec->pw_uid != recptr->uid) X mvprintw(data[BAD_UID].y,data[BAD_UID].x,data[BAD_UID].fmt,passwdrec->pw_uid); X X /* Next, the Expert flag */ X curelt = &data[EXPERT]; X mvprintw(curelt->y,curelt->x,curelt->fmt,recptr->expert); X X /* And the Creation and Last Login Dates */ X curelt = &data[CREATE]; X mvprintw(curelt->y,curelt->x,curelt->fmt,ctime(&recptr->timecr)); X X curelt = &data[LASTLOG]; X if(recptr->timeon != 0L) X mvprintw(curelt->y,curelt->x,curelt->fmt,ctime(&recptr->timeon)); X else X mvprintw(curelt->y,curelt->x,curelt->fmt,"** NEVER LOGGED IN **"); X X /* Current space used value, or deleted */ X if(recptr->space == DELREC) X { X curelt = &data[SPACE_USED]; X mvprintw(curelt->y,curelt->x,curelt->fmt,0L); X curelt = &data[DELETED]; X mvprintw(curelt->y,curelt->x,curelt->fmt,"DELETED"); X X }else X { X curelt = &data[SPACE_USED]; X mvprintw(curelt->y,curelt->x,curelt->fmt,recptr->space); X curelt = &data[DELETED]; X standend(); X mvprintw(curelt->y,curelt->x,curelt->fmt," "); X } X X /* End the highlight mode, if not done above */ X standend(); X X /* Load the status data, after clearing it */ X move(STATUS_Y,STATUS_X); X clrtoeol(); X X mvprintw(STATUS_Y,STATUS_X,"%s",f_statext[fstatus]); X X /* Go to get ready for the input */ X move(CMDIN_Y,CMDIN_X); X X refresh(); X} X/**/ Xvoid Xstartup() X{ X register int index; X X void load_file(); X extern int end_proc(); X extern int (*signal())(); X X /* Get the file data */ X X load_file(); X /* X * Ok, grab all signals that could zonk us. We know that X * there are some signals in this range we can't catch, but X * running through them won't hurt, and simplifies the code. X */ X for(index = 1; index <= SIGUSR2; index++) X (void)signal(index,end_proc); X X /* Initialize screen handling */ X initscr(); X raw(); X noecho(); X clear(); X refresh(); X X /* Display the initial screen form */ X for(index = 0; sform[index].x >= 0;index++) X mvprintw(sform[index].y,sform[index].x,"%s",sform[index].label); X X /* Load the record count */ X mvprintw(data[RECCNT].y,data[RECCNT].x,data[RECCNT].fmt,reccnt); X refresh(); X X return; X} X/**/ Xvoid Xload_file() X{ X struct stat statbuf; X X extern char *calloc(); X X /* X * If the file is already loaded, no allocation work--just go to X * the "top". X */ X if(oldfdes != (FILE *)NULL) X { X currec = -1; X fstatus = F_TOP; X return; X } X X /* Can we get the file? The philosophy here is to lock the X * file to prevent others from accessing it--this should block X * logins for the time that we're operative, but it shouldn't X * be prohibitive. If so, you figure out how to handle changed file X * records... of course, locks are only applied for update mode. X */ X if((oldfdes = fopen(pw_fname,"r")) == (FILE *)NULL) X { X perror(pw_fname); X exit(-1); X }else X if(updateflag) X { X /* Let them know now, if it's not writable */ X if(access(pw_fname,02)) X { X (void)fprintf(stderr,"No write permission on %s.\n",pw_fname); X (void)fprintf(stderr,"ABORT\n"); X exit(-1); X } X X if(locking(fileno(oldfdes),1,0L) < 0) X { X perror(pw_fname); X exit(errno); X } X } X X /* Good, have it open. Figure out how big an array to allocate. X * As mentioned elsewhere, the assumption is that, with each record X * only 26 bytes, the file will always easily fit in memory. X * This makes later manipulation--sorting, etc--trivial. The X * structure, however, will be easy to convert to using a tempfile, X * if anyone really wants to...the first cut of this program did so. X */ X if(fstat(fileno(oldfdes),&statbuf) < 0) X { X perror(pw_fname); X exit(errno); X } X X reccnt = (int)statbuf.st_size / sizeof(struct pwrec); X X /* Size sanity check */ X if((off_t)(reccnt * sizeof(struct pwrec)) != statbuf.st_size) X { X (void)fprintf(stderr, X "CORRUPTED %s! File size not an integral number of records!\n",pw_fname); X exit(-1); X } X X data_recs = (struct pwrec *)calloc((unsigned)reccnt,(unsigned)sizeof(struct pwrec)); X X if(data_recs == (struct pwrec *)NULL) X { X (void)fprintf(stderr,"Couldn't get memory!\n"); X exit(-1); X } X X /* X * Load the array with the actual file data. Check the X * record count, too. Note that, while this keeps our view of the X * file consistent, the real file may change if we're just viewing it. X */ X for(currec = 0; currec < reccnt;currec++) X if(fread(&data_recs[currec],sizeof(struct pwrec),1,oldfdes) != 1) X { X if(feof(oldfdes)) X (void)fprintf(stderr, X "Unexpected early EOF on %s!\n",pw_fname); X else X (void)fprintf(stderr, X "Unknown error on %s read!\n",pw_fname); X X exit(-1); X } X X /* Just another sanity check */ X { X struct pwrec pw; X if((fread(&pw,sizeof(struct pwrec),1,oldfdes) == 1) || X !feof(oldfdes)) X { X (void)fprintf(stderr,"Unexpected extra data in %s!\n",pw_fname); X exit(-1); X } X } X X /* All data loaded; leave input file ready for update */ X if(updateflag) X rewind(oldfdes); X else X (void)fclose(oldfdes); X X X /* Initialize the current record number and status */ X currec = -1; X fstatus = F_TOP; X} X/**/ Xstruct pwrec * Xgetrec() X{ X /* "Get" a record from the array. */ X X fstatus = F_NORM; X X X if(currec == (reccnt-1)) X fstatus = F_EOF; X else X currec++; X X if(currec == 0) X fstatus = F_TOP; X X return(&data_recs[currec]); X} X/**/ Xvoid Xpurge_data(disp) Xint disp; X{ X /* X * If it's been determined that the data was modified. X * Truncate the data file, and then transfer ONLY valid X * (undeleted) records. In all cases, release the array memory. X */ X extern void free(); X X if(updateflag <= 1) X { X free(data_recs); X return; X } X X currec = 0; /* Start at the array first element */ X X if((oldfdes = freopen(pw_fname,"w",oldfdes)) == (FILE *)NULL) X { X (void)fprintf(stderr,"COULDN'T TRUNCATE %s\n",pw_fname); X (void)fprintf(stderr,"ALL UPDATES LOST!"); X X end_proc(0); X }; X X /* Move those records, but ignore deleted ones */ X for(currec = 0; currec < reccnt;currec++) X if(data_recs[currec].space != DELREC) X if(fwrite(&data_recs[currec],sizeof(struct pwrec),1,oldfdes) != 1) X { X perror("real file write"); X exit(errno); X } X X if(disp == FREE) X { X (void)fclose(oldfdes); X free(data_recs); X } X} X/**/ Xend_proc(sig) Xint sig; X{ X X if(!spaceflag) X { X noraw(); X echo(); X clear(); X endwin(); X }; X X if(sig != 0) X { X (void)fprintf(stderr,"Caught signal %d\n",sig); X if(updateflag) X (void)fprintf(stderr,"Changes lost!\n"); X X (void)sleep(2); X } X X exit(sig); X} X/**/ Xint Xby_name(n1,n2) Xchar *n1,*n2; X{ X return(strcmp(n1,n2)); X} X/**/ Xby_login(l1,l2) Xlong l1,l2; X{ X return((int)l1 - l2); X} X/**/ Xusage() X{ X (void)fprintf(stderr,"Usage: pwcntl -d [ -i][ -s [n|l]] [ -c][ -v][ -f filename]\n"); X (void)fprintf(stderr," pwcntl [-e | -u][ -c][ -v][-f filename]\n"); X (void)fprintf(stderr," where:\n"); X (void)fprintf(stderr," -u : Update. Interactive only.\n\n"); X (void)fprintf(stderr," -d : Dump mode.\n\n"); X (void)fprintf(stderr," -e : Examine interactively.\n\n"); X (void)fprintf(stderr," -i : Invalid logins only (Only with 'd' option)\n\n"); X (void)fprintf(stderr," -c : Calculate space. Either standalone, or before further processing.\n\n"); X (void)fprintf(stderr," -s X: Sort. Must have either X=n, for by Name order, or X=l, for Lastlog\n"); X (void)fprintf(stderr," order. (Only with 'd' option)\n\n"); X (void)fprintf(stderr," -v : Verbose mode.\n\n"); X (void)fprintf(stderr," -f : Use alternate filename; default /etc/pwcntl\n\n"); X X exit(1); X}; END_OF_pwcntl.c if test 23716 -ne `wc -c <pwcntl.c`; then echo shar: \"pwcntl.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f pwcntl.h -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"pwcntl.h\" else echo shar: Extracting \"pwcntl.h\" \(470 characters\) sed "s/^X//" >pwcntl.h <<'END_OF_pwcntl.h' X/* @(#)pwcntl.h 1.1 12/18/88 */ X/* X * pwcntl.h - /etc/pwcntl file structure X */ Xstruct pwrec { X char logon[8]; /* user name from login arg1 */ X int uid; /* uid from /etc/passwd */ X char expert; /* Y/N flag for expert mode */ X char flg; /* unused (pad) */ X time_t timeon; /* time of most recent login */ X time_t timecr; /* time of first login */ X long space; /* disk space used in blocks, X * only used in Ulogin after Compute Space X * has been selected. X */ X}; END_OF_pwcntl.h if test 470 -ne `wc -c <pwcntl.h`; then echo shar: \"pwcntl.h\" unpacked with wrong size! fi # end of overwriting check fi if test -f pwcntl.notes -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"pwcntl.notes\" else echo shar: Extracting \"pwcntl.notes\" \(7919 characters\) sed "s/^X//" >pwcntl.notes <<'END_OF_pwcntl.notes' XFrom uucp Sun Dec 11 00:50 CST 1988 X>From ignatz Sun Dec 11 00:50:33 1988 remote from chinet XReceived: by homebru.UUCP (smail2.5) X id AA13442; 11 Dec 88 00:50:33 CST (Sun) XReceived: by chinet.chi.il.us (smail2.5) X id AA09165; 10 Dec 88 23:47:16 CST (Sat) XSubject: pwcntl.update XTo: homebru!ignatz XDate: Sat, 10 Dec 88 23:47:12 CST XFrom: Dave Ihnat <ignatz@chinet.chi.il.us> XX-Mailer: Elm [version 2.1 PL1] XMessage-Id: <8812102347.AA09165@chinet.chi.il.us> X XArticle 3509 of unix-pc.general: XPath: chinet!mcdchg!ethos!att!mtuxo!mtgzy!mtgzz!dwex XFrom: dwex@mtgzz.att.com (d.e.wexelblat) XNewsgroups: unix-pc.general XSubject: Re: /etc/pwcntl on the 3B1 (3.51), anyone? XKeywords: pwcntl login lastlog XMessage-ID: <4736@mtgzz.att.com> XDate: 7 Dec 88 13:29:49 GMT XReferences: <7059@chinet.chi.il.us> <5439@cbmvax.UUCP> XReply-To: dwex@mtgzz.UUCP (d.e.wexelblat) XOrganization: AT&T, Middletown NJ XLines: 57 X XIn article <5439@cbmvax.UUCP> ditto@cbmvax.UUCP (Michael "Ford" Ditto) writes: X>In article <7059@chinet.chi.il.us> ignatz@chinet.chi.il.us (Dave Ihnat) writes: X>>Before I waste my time re-inventing the wheel, I guess I'll ask here. X> [ ... ] X>>Has someone else taken this file apart? If not, it shouldn't be too X>>outrageous, but I'd prefer not to duplicate effort. X> X [ ... ] X> X> struct pwcntl X> { X> char name[8]; /* name entered at login: */ X> int uid; /* seems to be garbage for failed logins */ X> char flag; /* always 'Y' or 'N', what does it mean? */ X> /* char pad; */ X> long last_login; /* last login attempt */ X> long first_login; /* time when this entry was created */ X> long unknown; /* always zero, what does it mean? */ X> }; /* 26 bytes total */ X> X>Has anyone ever seen this file on anything other than a Unix PC? X>Anyone with further observations/conclusions, please post! X>-- X> -=] Ford [=- X> X>"The number of Unix installations (In Real Life: Mike Ditto) X>has grown to 10, with more expected." ford@kenobi.cts.com X>- The Unix Programmer's Manual, ...!sdcsvax!crash!elgar!ford X> 2nd Edition, June, 1972. ditto@cbmvax.commodore.com X X XThis file is used by the 'install' user's 'add user' (or whatever it's Xcalled) command. The flag field is for the 'EXPERT' flag (shows up on Xthe menu. The first_login field will be zero if the user is created through Xthe menu, and gets set when the user first logs in. The unknown field Xis (I think) the disk space used by that user, and gets filled in when you Xtell UA to run whatever to find disk usage (this also shows up on the Xadd user menu). I decoded this file a while ago, since I needed to write Xa script to create a bunch of users, but still have things look OK to UA. XIf UA isn't used, I don't think this file is necessary, or relevant. X X X--David Wexelblat dwex@mtgzz.att.com X AT&T Bell Laboratories ...!att!mtgzz!dwex X 200 Laurel Ave - 4B-421 X Middletown, NJ 07748 X X Xstupid Xinews Xfodder Xstupid Xinews Xfodder Xstupid Xinews Xfodder X X XArticle 3516 of unix-pc.general: XPath: chinet!att!ucbvax!ucsd!rutgers!tut.cis.ohio-state.edu!unmvax!pprg.unm.edu!hc!lll-winken!lll-tis!pacbell!ctnews!mitisft!bms XFrom: bms@mitisft.Convergent.COM (Bruce Schlobohm) XNewsgroups: unix-pc.general XSubject: Re: /etc/pwcntl on the 3B1 (3.51) XKeywords: pwcntl login Ulogin XMessage-ID: <531@mitisft.Convergent.COM> XDate: 9 Dec 88 05:42:06 GMT XReferences: <7059@chinet.chi.il.us> <5439@cbmvax.UUCP> XOrganization: Convergent Technologies, San Jose, CA XLines: 46 X XIn article <5439@cbmvax.UUCP>, ditto@cbmvax.UUCP (Michael "Ford" Ditto) writes: X> X> When I first looked at this file a long time ago, I was under the X> impression that it only recorded failed login attempts, but since it X> was definately modified when I logged in just now, I guess I was X> wrong. It definitely does record unsuccessful attempts, though; X> even unknown login names. X> [...] X> Has anyone ever seen this file on anything other than a Unix PC? X> Anyone with further observations/conclusions, please post! X XInfo on pwcntl as I see it: X Xstruct pwrec { X char logon[8]; /* user name from login arg1 */ X int uid; /* uid from /etc/passwd */ X char expert; /* Y/N flag for expert mode */ X char flg; /* unused (pad) */ X time_t timeon; /* time of most recent login */ X time_t timecr; /* time of first login */ X long space; /* disk space used in blocks, X * only used in Ulogin after Compute Space X * has been selected. X */ X}; X Xlogin writes records, Ulogin reads them and updates the expert flag, Xupon request, but never writes the disk space info back to the file. XThe information you see in the menu "User Login Interface" (Ulogin), Xcomes from pwcntl. In my brief search, I didn't find any other programs Xwhich use of the file, and this is definitely not a feature from CTIX. X XThe purpose of the file seems to be the groundwork for the ua to control Xwho can be an "expert", but this feature doesn't seem to be fully implemented, Xat least not on my UNIXPC. (Changing Expert= in ~/Environment seems to be Xall that ua needs to turn on/off Expert Mode.) X XAs far as failed logins, this seems to be more of a quirk than an feature. XIf you type a nonexistent login name at getty, hit return for the password, Xthen log in with a valid login name/passwd, a record is written with Xthe nonexistent login name, as though it were a valid (new) user. However, Xif you fail the login completely, and let login timeout (60 seconds), Xno record is written to pwcntl. So this isn't a reliable way of tracking Xfailed login attempts. X-- XBruce Schlobohm Xbms@Convergent.COM -or- {pyramid,sri-unix,pacbell}!ctnews!bms X X X XFrom uucp Wed Dec 7 12:20 CST 1988 X>From ignatz Wed Dec 7 12:20:47 1988 remote from chinet XReceived: by homebru.UUCP (smail2.5) X id AA00697; 7 Dec 88 12:20:47 CST (Wed) XReceived: by chinet.chi.il.us (smail2.5) X id AA20892; 7 Dec 88 11:07:56 CST (Wed) XSubject: pwdctl.note XTo: homebru!ignatz XDate: Wed, 7 Dec 88 11:07:55 CST XFrom: Dave Ihnat <ignatz@chinet.chi.il.us> XX-Mailer: Elm [version 2.1 PL1] XMessage-Id: <8812071107.AA20892@chinet.chi.il.us> X XArticle 3483 of unix-pc.general: XPath: chinet!att!rutgers!cbmvax!ditto XFrom: ditto@cbmvax.UUCP (Michael "Ford" Ditto) XNewsgroups: unix-pc.general XSubject: Re: /etc/pwcntl on the 3B1 (3.51), anyone? XSummary: priliminary guess at format XKeywords: pwcntl login lastlog XMessage-ID: <5439@cbmvax.UUCP> XDate: 6 Dec 88 00:41:18 GMT XReferences: <7059@chinet.chi.il.us> XReply-To: ditto@cbmvax.UUCP (Michael "Ford" Ditto) XOrganization: Commodore Technology, West Chester, PA XLines: 34 X XIn article <7059@chinet.chi.il.us> ignatz@chinet.chi.il.us (Dave Ihnat) writes: X>Before I waste my time re-inventing the wheel, I guess I'll ask here. X [ ... ] X>Has someone else taken this file apart? If not, it shouldn't be too X>outrageous, but I'd prefer not to duplicate effort. X XWhen I first looked at this file a long time ago, I was under the Ximpression that it only recorded failed login attempts, but since it Xwas definately modified when I logged in just now, I guess I was Xwrong. It definitely does record unsuccessful attempts, though; Xeven unknown login names. X XHere's what I've been able to figure out from the file itself: X X struct pwcntl X { X char name[8]; /* name entered at login: */ X int uid; /* seems to be garbage for failed logins */ X char flag; /* always 'Y' or 'N', what does it mean? */ X /* char pad; */ X long last_login; /* last login attempt */ X long first_login; /* time when this entry was created */ X long unknown; /* always zero, what does it mean? */ X }; /* 26 bytes total */ X XHas anyone ever seen this file on anything other than a Unix PC? XAnyone with further observations/conclusions, please post! X-- X -=] Ford [=- X X"The number of Unix installations (In Real Life: Mike Ditto) Xhas grown to 10, with more expected." ford@kenobi.cts.com X- The Unix Programmer's Manual, ...!sdcsvax!crash!elgar!ford X 2nd Edition, June, 1972. ditto@cbmvax.commodore.com X X X END_OF_pwcntl.notes if test 7919 -ne `wc -c <pwcntl.notes`; then echo shar: \"pwcntl.notes\" unpacked with wrong size! fi # end of overwriting check fi echo shar: End of shell archive. exit 0