Yet Another Last Login program (UNIXPC source; 16K)

Thad P Floryan thad at cup.portal.com
Fri Jan 5 01:55:08 AEST 1990


Yet Another Last Login Program!  :-)

Contrast this one with Greg Woods' recent posting to alt.sources of his
finger and lastlog program for SysV.

Read the README.

Thad Floryan [ thad at cup.portal.com (OR) ..!sun!portal!cup.portal.com!thad ]

------------------------------ cut here ------------------------------
#! /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
#	Makefile
#	lastlogin.1
#	lastlogin.c
# This archive created: Thu Jan  4 06:54:37 1990
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'README'" '(1221 characters)'
if test -f 'README'
then
	echo shar: "will not over-write existing file 'README'"
else
sed 's/^X//' << \SHAR_EOF > 'README'
XSort of in preparation for more-public access to some of my systems, I've
Xbeen poking though the system and verifying all is in accordance with some
Xgenerally accepted security guidelines when it dawned on me that one piece
Xof information was still missing: notification to a logging-in user of the
Xlast time the account was entered.
X
XSuch "last login" notification is available on ALL the systems I use, even
Xthe loathed VAX/VMS, except for my UNIX boxes.
X
XSo, during a few hours this holiday season I whipped up "lastlogin" which
Xis now installed on my systems and is presented here for your perusal and
Xenjoyment.
X
XImagine my chagrin when, just as I was posting, I saw Yet Another version
Xof this same idea posted to alt.sources by Greg A. Woods entitled:  "SysV
Xversions of finger and last, with lastlog."
X
XSheesh!  Another example of unrelated development occurring simultaneously.
X
XIn any event, you now have a choice!
X
XThe design assumptions of my "lastlogin" were for it to run non-privileged
Xand for it to illustrate (if you read the source code) some techniques and
Xother tidbits of programming UNIX systems.
X
XComments welcome!
X
XThad
X
XThad Floryan [ thad at cup.portal.com (OR) ..!sun!portal!cup.portal.com!thad ]
SHAR_EOF
if test 1221 -ne "`wc -c < 'README'`"
then
	echo shar: "error transmitting 'README'" '(should have been 1221 characters)'
fi
fi
echo shar: "extracting 'Makefile'" '(889 characters)'
if test -f 'Makefile'
then
	echo shar: "will not over-write existing file 'Makefile'"
else
sed 's/^X//' << \SHAR_EOF > 'Makefile'
X# Makefile for lastlogin, Thad Floryan, 3-Jan-1990
X#
X# To forestall the anticipated commentary, this Makefile is DELIBERATELY
X# verbose and specific to show the curious ALL the otherwise-hidden steps
X# assumed by the implicit rules in my home-consumption-only Makefiles.
X#
X# If you have the GNU ``C'' compiler, use it, and uncomment the line "CC=";
X# the executable program will be approx. 300 bytes smaller using GNU gcc.
X# The sizes on my system are 2128 bytes using "gcc" and 2424 using "cc".
X#
X#CC=		gcc
X
XCFLAGS=		-O
XLDFLAGS=	-s
XLIBS=		/lib/crt0s.o /lib/shlib.ifile
XDEST=		/usr/local/bin
X
Xlastlogin :	lastlogin.o
X		$(LD) $(LDFLAGS) -o lastlogin lastlogin.o $(LIBS) 
X		rm lastlogin.o
X
Xlastlogin.o :	lastlogin.c
X		$(CC) $(CFLAGS) -c lastlogin.c
X
Xinstall :	lastlogin $(DEST)
X		cp lastlogin ${DEST}
X		chown bin ${DEST}/lastlogin
X		chgrp bin ${DEST}/lastlogin
X		chmod 111 ${DEST}/lastlogin
SHAR_EOF
if test 889 -ne "`wc -c < 'Makefile'`"
then
	echo shar: "error transmitting 'Makefile'" '(should have been 889 characters)'
fi
fi
echo shar: "extracting 'lastlogin.1'" '(3226 characters)'
if test -f 'lastlogin.1'
then
	echo shar: "will not over-write existing file 'lastlogin.1'"
else
sed 's/^X//' << \SHAR_EOF > 'lastlogin.1'
X.TH LASTLOGIN 1L "UNIXPC Local Utilities"
X.UC 4
X.SH NAME
Xlastlogin \- reports user's last login date and time
X.SH SYNOPSIS
X.I lastlogin
X.LP
X.SH NOMENCLATURE
X.TP 15
X$HOME
Xis the environment variable defining the user's login default directory.
X.TP 15
X_LOGFNAM
Xis a compiled-in filename constant used by
X.I lastlogin
Xas its record of a prior login.
X.TP 15
X$PATH
Xis the environment variable defining the order-specific list of file
Xdirectories to be searched by the shell seeking a program to be executed.
X.SH DESCRIPTION
X.PP
X.I  Lastlogin
Xgets the last modified time of $HOME/_LOGFNAM and reports that as
Xthe date and time of last login, then locates the /etc/pwcntl entry for
Xthe user and updates the modification time of $HOME/_LOGFNAM to the
X"time_t laston" value from the /etc/pwcntl record entry.
X.PP
XNote that if $HOME is
X.I not
Xdefined in the environment,
X.I lastlogin
Xwill derive a ``$HOME'' value from the user's entry in /etc/passwd.
X.PP
XNote also that if $HOME/_LOGFNAM doesn't exist, the user is assumed to be
Xlogging in for the first time and
X.I lastlogin
Xwill automatically create $HOME/_LOGFNAM.
X.PP
X.I Lastlogin
Xis intended to be invoked from $HOME/.profile by
Xincluding its name on a line by itself, assuming $PATH includes
Xthe directory containing
X.I lastlogin.
XSome sites may wish to place the
X.I lastlogin
Xinvocation in their /etc/profile or /etc/localprofile
Xcausing it to execute for
X.I all
Xuser logins.
X.PP
X.I Lastlogin
Xmay also be used to set an environment variable in one's
Xshell for other purposes per:
X.PP
X.RS
X$ LASTLOGIN=`/usr/local/bin/lastlogin`
X.RE
X.RS
X$ echo $LASTLOGIN
X.RE
X.RS
XLast login Wed  3-Jan-90 16:53:15
X.RE
X.RS
X$
X.RE
X.PP
XIt would have been desirable for /bin/login itself to report a user's last
Xlogin time, but, alas, one needs the source
Xcode for /bin/login to do this, hence
X.I lastlogin's
Xgenesis.
X.PP
X.I Lastlogin
Xis a user-mode program and, as such, does not require any special
Xprivileges or capabilities to operate.  If presented with command line
Xarguments, it acknowledges them by displaying its version and a
Xusage line.
X.SH AUTHOR
XThad Floryan
X.RS 0
XUUCP email address: ..!sun!portal!cup.portal.com!thad
X.RE
X.SH VERSION
XThe present version of
X.I lastlogin
Xis 1.0, dated 3-Jan-1990.
X.SH CREDITS
XThe portion of the code reading /etc/pwcntl is based on look_pwcntl.c
Xby Lenny Tropiano, ICUS Software Systems, 13-Dec-1988.
X.SH CAVEATS
X.PP
X.I Lastlogin
Xassumes the presence of /etc/pwcntl; this assumption may be valid
X.I ONLY
Xfor the 3B1/UNIXPC/PC7300 systems.
X.PP
XIf
X.I lastlogin
Xis invoked by /etc/profile or /etc/localprofile, causing
Xit to execute for
X.I all
Xuser logins, its output could be potentially
Xtroublesome if one's system has special server logins (such as a public
Xaccess time-of-day server), so verify
X.I lastlogin's
Xoperation on your system before inflicting it on
X.I your
Xusers.
X.SH FILES
X.RS 0
X$HOME/_LOGFNAM\ \ (typically ~/.lastlogin)
X.RE
X.RS 0
X$HOME/.profile
X.RE
X.RS 0
X/etc/localprofile
X.RE
X.RS 0
X/etc/passwd
X.RE
X.RS 0
X/etc/profile
X.RE
X.RS 0
X/etc/pwcntl
X.RE
X.SH BUGS
X.PP
XErrors during the execution of some system calls are passively ignored
Xsince there is really no adequate recovery strategy imaginable.  At worse,
X.I lastlogin
Xwill simply exit quietly.
SHAR_EOF
if test 3226 -ne "`wc -c < 'lastlogin.1'`"
then
	echo shar: "error transmitting 'lastlogin.1'" '(should have been 3226 characte
rs)'
fi
fi
echo shar: "extracting 'lastlogin.c'" '(8394 characters)'
if test -f 'lastlogin.c'
then
	echo shar: "will not over-write existing file 'lastlogin.c'"
else
sed 's/^X//' << \SHAR_EOF > 'lastlogin.c'
X/* lastlogin					by Thad Floryan, 3-Jan-1990
X *
X * Gets the time of last modification of $HOME/_LOGFNAM and reports that as
X * the date&time of last login, then locates the /etc/pwcntl entry for "us"
X * and updates the modification time of $HOME/_LOGFNAM to the "time_t laston"
X * value from the /etc/pwcntl record entry.
X *
X * Note that if $HOME is NOT defined in the environment, this program will
X * derive a ``$HOME'' value from the user's entry in /etc/passwd.
X *
X * Note also that if $HOME/_LOGFNAM doesn't exist, the user is assumed to be
X * logging in for the first time and this program will create $HOME/_LOGFNAM.
X *
X * This program is intended to be invoked from one's $HOME/.profile simply by
X * including the program name on a line by itself (assuming the $PATH includes
X * the directory in which this program resides on one's system).  If one is
X * using the UA (User Agent), it appears the $HOME/.profile is not executed,
X * so one could instead place the lastlogin invocation in /etc/localprofile
X * which causes it to execute for ALL user logins (this could be potentially
X * clumsy if one's system has special server logins, so check it out first
X * before inflicting it on YOUR users).
X *
X * This program may also be used to set an enviromental variable in one's
X * shell for other purposes per:
X *
X *	$ LASTLOGIN=`/usr/local/bin/lastlogin`
X *	$ echo $LASTLOGIN
X *	Last login Wed  3-Jan-90 16:53:15
X *	$
X *
X * The portion of the code reading /etc/pwcntl is based on look_pwcntl.c
X * by Lenny Tropiano, ICUS Software Systems, 13-Dec-88.  Note that the file
X * /etc/pwcntl seems to only exist on 3B1/UNIXPC/PC7300 systems and doesn't
X * appear to be a general feature of SysV.
X *
X * The only "#define" that should be altered to suit one's preferences is
X * _LOGFNAM, the name of the "recording" file in one's home directory.
X *
X * As regards installation on one's system, it is advisable to "chmod 111"
X * for "---x--x--x" to prevent casual use of the strings or the { od | hd }
X * programs on it to discover the name of the _LOGFNAM.
X *
X * It would be "nice" if /bin/login would itself report the user's last
X * login time before altering /etc/pwctnl, but, alas, one needs the source
X * code for /bin/login to do this (unless, hmmmm, one writes a new login
X * program that forks-off to /bin/login or sumtin').
X *
X */
X
X#include <stdio.h>
X#include <fcntl.h>
X#include <pwd.h>
X#include <sys/stat.h>
X#include <sys/types.h>
X#include <time.h>
X
X#define _LOGFNAM ".lastlogin"	/* name of file used as login indicator	     */
X
X#define _PATHMAX 128		/* assumed max path string length; couldn't  */
X				/* find anything other than "#define FILEMAX */
X				/* 512" in lp.h, so don't know what any real */
X				/* limitation might be.			     */
X
X#define _GUDEXIT 0
X#define _ERREXIT 1
X
X/*
X *	Structure of the /etc/pwcntl file (3B1/UNIXPC/PC7300 systems only).
X */
Xstruct pwcntl {
X	char	login[8];	/* login name (matches name in /etc/passwd) */
X	int	uid;		/* login username's UID			    */
X	char	expert;		/* set non-zero for "expert" users	    */
X	char	pad;		/* filler				    */
X	time_t	laston;		/* time of this login; set by /bin/login    */
X	time_t	tcreat;		/* time of first login (record creation)    */
X	long	space;		/* filler				    */
X};
X
X/*
X *	Structure for use by utime(); doesn't appear to be in any *.h file.
X */
Xstruct utimbuf {
X	time_t	actime;		/* time of last access			    */
X	time_t	modtime;	/* time of last modification		    */
X};
X
Xstatic char *version = "Version 1.0, Thad Floryan, 3-Jan-1990";
X
Xstatic char *month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
X		        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
X
Xstatic char *weekday[]={"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
X
Xmain(argc, argv)
X	int	 argc;
X	char	*argv[];
X{
X	extern int		 close();
X	extern int		 creat();
X	extern void		 endpwent();
X	extern void		 free();
X	extern char		*getenv();
X	extern struct passwd	*getpwuid();
X	extern int		 getuid();
X	extern struct tm	*localtime();
X	extern void		*malloc();
X	extern int		 open();
X	extern int		 fprintf();
X	extern int		 read();
X	extern int		 stat();
X	extern char		*strcat();
X	extern char		*strcpy();
X	extern int		 umask();
X	extern int		 utime();
X
X	int		 exists;	/* 0 if $HOME/_LOGFNAM exists	*/
X	int		 fd;		/* file descr. for /etc/pwcntl	*/
X	char		*homeptr;	/* ptr to environmental $HOME	*/
X	char		*logfptr;	/* ptr to $HOME/_LOGFNAM	*/
X	struct tm	*loglast;	/* mod time of $HOME/_LOGFNAM	*/
X	int		 myuid;		/* UID of this process		*/
X	struct passwd	*pwdentry;	/* curr /etc/passwd entry ptr	*/
X	struct pwcntl	 pwrec;		/* read buffer for /etc/pwcntl	*/
X	int		 setmask;	/* process' $UMASK value	*/
X	struct stat	 statbuf;	/* $HOME/_LOGFNAM stat() buffer	*/
X	struct utimbuf	 utimebuf;	/* data buffer for utime()	*/
X
X/*
X *	If user called us with any argument(s), report the usage and version.
X */
X	if (argc > 1) {
X		fprintf(stderr, "usage: %s\n%s\n", argv[0], version);
X		fprintf(stderr, "Reports date and time of your last login.\n");
X		exit(_GUDEXIT);
X	}
X/*
X *	Allocate memory for use constructing a path to _LOGFNAM
X */
X	if ((logfptr = (char *) malloc(_PATHMAX)) == NULL) {
X		fprintf(stderr, "%s: cannot allocate memory\n", argv[0]);
X		exit(_ERREXIT);
X	}
X/*
X *	Get the user's UID for use several places in the following code.
X */
X	myuid = getuid();
X/*
X *	Get value of $HOME environmental variable; the pointer will be NULL
X *	if $HOME hasn't been defined (not very likely! :-)
X */
X	if ((homeptr = getenv("HOME")) == NULL) {
X/*
X *	For some reason, $HOME is NOT defined, so derive a path to the
X *	user's true home directory from the /etc/passwd directory entry
X *	and copy its definition to the path buffer.
X */
X		pwdentry = getpwuid(myuid);
X		strcpy(logfptr, pwdentry->pw_dir);
X	}
X	else {
X/*
X *	$HOME was defined, so copy its definition to the path buffer.
X */
X		strcpy(logfptr, homeptr);
X	}
X/*
X *	Append a "/" to the path buffer, and
X *	Append the name of the last-login file (_LOGFNAM) to the path buffer.
X */
X	strcat(logfptr, "/");
X	strcat(logfptr, _LOGFNAM);
X/*
X *	Check if the last-login file exists; if not, assume the user is
X *	logging in for the first time NOW and so inform him.
X */
X	if ((exists = stat(logfptr, &statbuf)) < 0) {
X		fprintf(stdout, "Never logged on before.\n");
X	}
X	else {
X/*
X *	The last-login file exists, so stat() it and report its modification
X *	time as the user's last login date and time; this assumption is based
X *	on the fact that ONLY this program will have changed the modification
X *	time on the file (yeah, sure, famous last words! :-)
X *
X *	Note the date and time printing format differs from that which is
X *	available using asctime() due to my preferences for this application.
X */
X		loglast = localtime(&statbuf.st_mtime);
X		fprintf(stdout, "Last login %s %2d-%s-%02d %2d:%02d:%02d\n",
X			weekday[loglast->tm_wday],
X			loglast->tm_mday,
X			month[loglast->tm_mon],
X			loglast->tm_year,
X			loglast->tm_hour,
X			loglast->tm_min,
X			loglast->tm_sec);
X	}
X/*
X *	Now open the /etc/pwcntl file for read-only processing.
X */
X	if ((fd = open("/etc/pwcntl", O_RDONLY)) < 0) {
X/*
X *	Couldn't open /etc/pwcntl, so fake the login date to "nothing."
X */
X		pwrec.laston = 0;
X	}
X	else {
X/*
X *	Otherwise read /etc/pwcntl looking for a matching UID value; when
X *	found, leave the present record in memory and close the file.  The
X *	record will contain THIS session's login date&time as set by the
X *	/bin/login program.  This file and its record format is undocumented
X *	by AT&T and its purpose and structure were ascertained by Lenny.
X */
X		while (read(fd, &pwrec, sizeof(pwrec)) == sizeof(pwrec))
X			if (myuid == pwrec.uid)
X				break;
X		close(fd);
X	}
X/*
X *	Create the $HOME/_LOGFNAM file if it doesn't exist (ignoring any
X *	errors since there's nothing we can do about them), and set the
X *	file's mode to whatever the $UMASK permits (typically "-rw-r--r--"
X *	for non-executable files).
X */
X	if (exists != 0) {
X		umask(setmask = umask(0));	/* get & restore orig. value */
X		close(creat(logfptr, (0666 & ~setmask)));
X	}
X/*
X *	Preserve the original access time of $HOME/_LOGFNAM and set the modify
X *	time from the last login time in /etc/pwcntl (ignoring any error(s)
X *	because we won't be able to do anything about it(them) anyway).
X */
X	utimebuf.actime  = (exists == 0) ? statbuf.st_atime : 0;
X	utimebuf.modtime = pwrec.laston;
X
X	utime(logfptr, &utimebuf);
X/*
X *	Free-up the memory acquired earlier using malloc().
X */
X	free(logfptr);
X}
SHAR_EOF
if test 8394 -ne "`wc -c < 'lastlogin.c'`"
then
	echo shar: "error transmitting 'lastlogin.c'" '(should have been 8394 characte
rs)'
fi
fi
exit 0
#	End of shell archive



More information about the Comp.sys.att mailing list