[comp.sources.x] v04i009: xlogin, Part01/01

argv@island.uu.net (Dan Heller) (05/30/89)

Submitted-by: Markus Stumpf <stumpf@lan.informatik.tu-muenchen.dbp.de>
Posting-number: Volume 4, Issue 9
Archive-name: xlogin/part01

This program does all the management stuff login does, but Xdm does not.
For a full description see the manual page. I only could test it on a
mVaxII with Qvss and X.V11R3 all 10 patches in, and it works right for me.
Please drop me a note, if something has to be changed to get it distributed.
Enjoy!

\Maex
+------------------------------------------------------------------------------+
|  Markus Stumpf                                                               |
|  TU Muenchen                        local: lan.informatik.tu-muenchen.dbp.de |
|  Inst. f. Informatik                  DFN: stumpf@{local}                    |
|  Arcisstrasse                        UUCP: stumpf%{local}@unido.uucp         |
|  D-8000 Muenchen                  ARPA/CS: stumpf%{local}@relay.cs.net       |
|  West Germany                      BITNET: infrza02@dm0tui1s.bitnet          |
+------------------------------------------------------------------------------+

--------------------------------- cut here ------------------------------
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  README Imakefile Makefile patchlevel.h xlogin.c xlogin.man
# Wrapped by stumpf@gshalle2 on Mon May 22 19:51:33 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(1538 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
XThis is the README file for Xlogin. 			22-05-1989
X
X	I would like to thank Elmar Bartel and Berni Schneck here at
Xthe TU for giving me some hints and helping me to make the code more
Xsecure and the people at MIT for helping me with a few questions and for
Xdoing the whole X stuff.
X
X	This program was written, to do some stuff, which is no longer
Xbe done, when using Xdm from X Windows Version 11 Release 3.
X	It handles /etc/motd, /etc/nologin, user quotas (EPROCLIM, EUSERS),
X/usr/adm/lastlog, /usr/adm/wtmp and $USER/.hushlogin.
XFor more information see the manual page.
X	I tried to write it as secure as possible (range checking in
Xstrings etc.), but any further security hints are welcome.
X	Further I don't know how good my try was, to use the X Toolkit.
XIt is my first program using this mechanism, so don't be too critical.
XBut here too, every improvements are welcome.
X
XEnjoy!
X
X\Maex
X
X+------------------------------------------------------------------------------+
X|  Markus Stumpf                                                               |
X|  TU Muenchen                        local: lan.informatik.tu-muenchen.dbp.de |
X|  Inst. f. Informatik                  DFN: stumpf@{local}                    |
X|  Arcisstrasse                        UUCP: stumpf%{local}@unido.uucp         |
X|  D-8000 Muenchen                  ARPA/CS: stumpf%{local}@relay.cs.net       |
X|  West Germany                      BITNET: infrza02@dm0tui1s.bitnet          |
X+------------------------------------------------------------------------------+
END_OF_FILE
if test 1538 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'Imakefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Imakefile'\"
else
echo shar: Extracting \"'Imakefile'\" \(142 characters\)
sed "s/^X//" >'Imakefile' <<'END_OF_FILE'
X           SRCS = xlogin.c
X           OBJS = xlogin.o
XLOCAL_LIBRARIES = $(XAWLIB) $(XMULIB) $(XTOOLLIB) $(XLIB)
X
XComplexProgramTarget(xlogin)
END_OF_FILE
if test 142 -ne `wc -c <'Imakefile'`; then
    echo shar: \"'Imakefile'\" unpacked with wrong size!
fi
# end of 'Imakefile'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(8014 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X# Makefile generated by imake - do not edit!
X# $XConsortium: imake.c,v 1.37 88/10/08 20:08:30 jim Exp $
X
X###########################################################################
X# X Window System Makefile generated from template file Imake.tmpl
X# $XConsortium: Imake.tmpl,v 1.91 88/10/23 22:37:10 jim Exp $
X#
X# Do not change the body of the imake template file.  Server-specific
X# parameters may be set in the appropriate .macros file; site-specific
X# parameters (but shared by all servers) may be set in site.def.  If you
X# make any changes, you'll need to rebuild the makefiles using
X# "make World" (at best) or "make Makefile; make Makefiles" (at least) in
X# the top level directory.
X#
X# If your C preprocessor doesn't define any unique symbols, you'll need
X# to set BOOTSTRAPCFLAGS when rebuilding imake (usually when doing
X# "make Makefile", "make Makefiles", or "make World").
X#
X# If you absolutely can't get imake to work, you'll need to set the
X# variables at the top of each Makefile as well as the dependencies at the
X# bottom (makedepend will do this automatically).
X#
X
X###########################################################################
X# platform-specific configuration parameters - edit Vax.macros to change
X
X# platform:  $XConsortium: Vax.macros,v 1.49 88/10/23 11:01:02 jim Exp $
X
XBOOTSTRAPCFLAGS =
X             AS = /usr/local/gas
X             CC = /usr/local/gcc
X            CPP = /lib/gcc-cpp
X             LD = /usr/local/gld
X           LINT = lint
X        INSTALL = install
X           TAGS = ctags
X             RM = rm -f
X             MV = mv
X             LN = ln -s
X         RANLIB = /usr/bin/ranlib
XRANLIBINSTFLAGS = -t
X             AR = ar clq
X             LS = ls
X       LINTOPTS = -axz
X    LINTLIBFLAG = -C
X           MAKE = make
XSTD_CPP_DEFINES =
X    STD_DEFINES = -traditional -fwritable-strings
X
X###########################################################################
X# site-specific configuration parameters - edit site.def to change
X
X# site:  $XConsortium: site.def,v 1.16 88/10/12 10:30:24 jim Exp $
X
X###########################################################################
X# definitions common to all Makefiles - do not edit
X
X          SHELL = 	/bin/sh
X
X        DESTDIR =
X      USRLIBDIR = $(DESTDIR)/usr/lib
X         BINDIR = $(DESTDIR)/usr/bin/X11
X         INCDIR = $(DESTDIR)/usr/include/X11
X         ADMDIR = $(DESTDIR)/usr/adm
X         LIBDIR = $(USRLIBDIR)/X11
X     LINTLIBDIR = $(USRLIBDIR)/lint
X        FONTDIR = $(LIBDIR)/fonts
X       XINITDIR = $(LIBDIR)/xinit
X         XDMDIR = $(LIBDIR)/xdm
X         UWMDIR = $(LIBDIR)/uwm
X         AWMDIR = $(LIBDIR)/awm
X         TWMDIR = $(LIBDIR)/twm
X        MANPATH = $(DESTDIR)/usr/man
X  MANSOURCEPATH = $(MANPATH)/man
X         MANDIR = $(MANSOURCEPATH)n
X      LIBMANDIR = $(MANSOURCEPATH)3
X    XAPPLOADDIR = $(LIBDIR)/app-defaults
X
X   INSTBINFLAGS = -m 0755
X   INSTUIDFLAGS = -m 4755
X   INSTLIBFLAGS = -m 0664
X   INSTINCFLAGS = -m 0444
X   INSTMANFLAGS = -m 0444
X   INSTAPPFLAGS = -m 0444
X  INSTKMEMFLAGS = -m 4755
X        FCFLAGS = -t
X    CDEBUGFLAGS = -O
X
X        PATHSEP = /
X         DEPEND = $(DEPENDSRC)/makedepend
X          IMAKE = $(IMAKESRC)/imake
X            RGB = $(RGBSRC)/rgb
X             FC = $(BDFTOSNFSRC)/bdftosnf
X      MKFONTDIR = $(MKFONTDIRSRC)/mkfontdir
X      MKDIRHIER = $(SCRIPTSSRC)/mkdirhier.sh
X
X         CFLAGS = $(CDEBUGFLAGS) $(INCLUDES) $(STD_DEFINES) $(DEFINES)
X      LINTFLAGS = $(LINTOPTS) $(INCLUDES) $(STD_DEFINES) $(DEFINES) -DLINT
X        LDFLAGS = $(CDEBUGFLAGS) $(SYS_LIBRARIES) $(SYSAUX_LIBRARIES)
X            TOP = ./../../..
X      CLIENTSRC = $(TOP)/clients
X        DEMOSRC = $(TOP)/demos
X         LIBSRC = $(TOP)/lib
X        FONTSRC = $(TOP)/fonts
X     INCLUDESRC = $(TOP)/X11
X      SERVERSRC = $(TOP)/server
X        UTILSRC = $(TOP)/util
X     SCRIPTSSRC = $(UTILSRC)/scripts
X     EXAMPLESRC = $(TOP)/examples
X     CONTRIBSRC = $(TOP)/contrib
X         DOCSRC = $(TOP)/doc
X         RGBSRC = $(TOP)/rgb
X      DEPENDSRC = $(UTILSRC)/makedepend
X       IMAKESRC = $(UTILSRC)/imake
X       IRULESRC = $(UTILSRC)/imake.includes
X        XLIBSRC = $(LIBSRC)/X
X         XMUSRC = $(LIBSRC)/Xmu
X     TOOLKITSRC = $(LIBSRC)/Xt
X     AWIDGETSRC = $(LIBSRC)/Xaw
X     OLDXLIBSRC = $(LIBSRC)/oldX
X    BDFTOSNFSRC = $(FONTSRC)/bdftosnf
X   MKFONTDIRSRC = $(FONTSRC)/mkfontdir
X   EXTENSIONSRC = $(TOP)/extensions
X   EXTENSIONLIB = $(EXTENSIONSRC)/lib/libXext.a
X           XLIB = $(XLIBSRC)/libX11.a
X         XMULIB = $(XMUSRC)/libXmu.a
X        OLDXLIB = $(OLDXLIBSRC)/liboldX.a
X       XTOOLLIB = $(TOOLKITSRC)/libXt.a
X         XAWLIB = $(AWIDGETSRC)/libXaw.a
X       LINTXLIB = $(XLIBSRC)/llib-lX11.ln
X        LINTXMU = $(XMUSRC)/llib-lXmu.ln
X      LINTXTOOL = $(TOOLKITSRC)/llib-lXt.ln
X        LINTXAW = $(AWIDGETSRC)/llib-lXaw.ln
X       INCLUDES = -I$(TOP)
X      MACROFILE = Vax.macros
X   ICONFIGFILES = $(IRULESRC)/Imake.tmpl \
X			$(IRULESRC)/$(MACROFILE) $(IRULESRC)/site.def
X  IMAKE_DEFINES =
X      IMAKE_CMD = $(NEWTOP)$(IMAKE) -TImake.tmpl -I$(NEWTOP)$(IRULESRC) \
X			-s Makefile $(IMAKE_DEFINES)
X         RM_CMD = $(RM) *.CKP *.ln *.BAK *.bak *.o core errs ,* *~ *.a \
X			.emacs_* tags TAGS make.log MakeOut
X
X###########################################################################
X# rules:  $XConsortium: Imake.rules,v 1.71 88/10/23 22:46:34 jim Exp $
X
X###########################################################################
X# start of Imakefile
X
X           SRCS = xlogin.c
X           OBJS = xlogin.o
XLOCAL_LIBRARIES = $(XAWLIB) $(XMULIB) $(XTOOLLIB) $(XLIB)
X
X        PROGRAM = xlogin
X
Xall:: xlogin
X
Xxlogin: $(OBJS) $(LOCAL_LIBRARIES)
X	$(RM) $@
X	$(CC) -o $@ $(OBJS) $(LOCAL_LIBRARIES) $(LDFLAGS) $(SYSLAST_LIBRARIES)
X
Xrelink::
X	$(RM) $(PROGRAM)
X	$(MAKE) $(MFLAGS) $(PROGRAM)
X
Xinstall:: xlogin
X	$(INSTALL) -c $(INSTALLFLAGS) xlogin $(BINDIR)
X
Xinstall.man:: xlogin.man
X	$(INSTALL) -c $(INSTMANFLAGS) xlogin.man $(MANDIR)/xlogin.n
X
Xdepend:: $(DEPEND)
X
Xdepend::
X	$(DEPEND) -s "# DO NOT DELETE" -- $(CFLAGS) -- $(SRCS)
X
X$(DEPEND):
X	@echo "making $@"; \
X	cd $(DEPENDSRC); $(MAKE)
X
Xclean::
X	$(RM) $(PROGRAM)
X
X###########################################################################
X# Imake.tmpl common rules for all Makefiles - do not edit
X
Xemptyrule::
X
Xclean::
X	$(RM_CMD) \#*
X
XMakefile:: $(IMAKE)
X
XMakefile:: Imakefile \
X	$(IRULESRC)/Imake.tmpl \
X	$(IRULESRC)/Imake.rules \
X	$(IRULESRC)/site.def \
X	$(IRULESRC)/$(MACROFILE)
X	-@if [ -f Makefile ]; then \
X		echo "$(RM) Makefile.bak; $(MV) Makefile Makefile.bak"; \
X		$(RM) Makefile.bak; $(MV) Makefile Makefile.bak; \
X	else exit 0; fi
X	$(IMAKE_CMD) -DTOPDIR=$(TOP)
X
X$(IMAKE):
X	@echo "making $@"; \
X	cd $(IMAKESRC); $(MAKE) BOOTSTRAPCFLAGS=$(BOOTSTRAPCFLAGS)
X
Xtags::
X	$(TAGS) -w *.[ch]
X	$(TAGS) -xw *.[ch] > TAGS
X
X###########################################################################
X# empty rules for directories that do not have SUBDIRS - do not edit
X
Xinstall::
X	@echo "install done"
X
Xinstall.man::
X	@echo "install.man done"
X
XMakefiles::
X
X###########################################################################
X# dependencies generated by makedepend
X
X# DO NOT DELETE
X
Xxlogin.o: /usr/include/sys/param.h /usr/include/machine/param.h
Xxlogin.o: /usr/include/sys/signal.h /usr/include/sys/types.h
Xxlogin.o: /usr/include/sys/quota.h /usr/include/sys/stat.h
Xxlogin.o: /usr/include/sys/time.h /usr/include/errno.h /usr/include/lastlog.h
Xxlogin.o: /usr/include/pwd.h /usr/include/utmp.h /usr/include/stdio.h
Xxlogin.o: ./../../../X11/StringDefs.h ./../../../X11/Intrinsic.h
Xxlogin.o: ./../../../X11/Xlib.h ./../../../X11/X.h ./../../../X11/Xutil.h
Xxlogin.o: ./../../../X11/Xresource.h ./../../../X11/Xos.h
Xxlogin.o: /usr/include/strings.h /usr/include/sys/file.h
Xxlogin.o: ./../../../X11/Core.h ./../../../X11/Composite.h
Xxlogin.o: ./../../../X11/Constraint.h ./../../../X11/Command.h
Xxlogin.o: ./../../../X11/Label.h ./../../../X11/Simple.h
Xxlogin.o: ./../../../X11/copyright.h ./../../../X11/Xmu.h
Xxlogin.o: ./../../../X11/Form.h ./../../../X11/Constraint.h
Xxlogin.o: ./../../../X11/AsciiText.h ./../../../X11/Text.h patchlevel.h
END_OF_FILE
if test 8014 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'patchlevel.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'patchlevel.h'\"
else
echo shar: Extracting \"'patchlevel.h'\" \(21 characters\)
sed "s/^X//" >'patchlevel.h' <<'END_OF_FILE'
X#define PATCHLEVEL	0
END_OF_FILE
if test 21 -ne `wc -c <'patchlevel.h'`; then
    echo shar: \"'patchlevel.h'\" unpacked with wrong size!
fi
# end of 'patchlevel.h'
fi
if test -f 'xlogin.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xlogin.c'\"
else
echo shar: Extracting \"'xlogin.c'\" \(13294 characters\)
sed "s/^X//" >'xlogin.c' <<'END_OF_FILE'
X/*
X * xlogin - X login manager
X *
X * $Header: gshalle2 xlogin.c,v 1.6 89/05/22 17:49:56 stumpf Exp $
X *
X * Copyright 1989 Technische Universitaet Muenchen (TUM), Germany
X *
X * Permission to use, copy, modify, and distribute this software and its
X * documentation for any purpose and without fee is hereby granted, provided
X * that the above copyright notice appear in all copies and that both that
X * copyright notice and this permission notice appear in supporting
X * documentation, and that the name of TUM not be used in advertising or
X * publicity pertaining to distribution of the software without specific,
X * written prior permission.  TUM makes no representations about the
X * suitability of this software for any purpose.  It is provided "as is"
X * without express or implied warranty.
X *
X *
X * Author:  Markus Stumpf, Technische Universitaet Muenchen
X *		(stumpf@lan.informatik.tu-muenchen.dbp.de)
X *
X * $Source: /usr/wiss/stumpf/work/xlogin/RCS/xlogin.c,v $
X *
X */
X
X#include <sys/param.h>
X#include <sys/quota.h>
X#include <sys/stat.h>
X#include <sys/time.h>
X#include <sys/types.h>
X
X#include <errno.h>
X#include <lastlog.h>
X#include <pwd.h>
X#include <utmp.h>
X#include <stdio.h>
X
X#include <X11/StringDefs.h>
X#include <X11/Intrinsic.h>
X#include <X11/Command.h>
X#include <X11/Form.h>
X#include <X11/AsciiText.h>
X
X#include "patchlevel.h"
X
X
X#define MAXLEN	1024
X
X#define STRCPY(a, b)	strncpy(a, b, sizeof(a))
X
Xstruct passwd	*pwd;
Xstruct utmp	wtmp;
X
Xchar	path_delimiter[]= "/";
Xchar	XTTYname[]	= "Xlogin";
Xchar	HushLog[]	= ".hushlogin";
Xchar	XLogFile[]	= ".Xlogin";
Xchar	HushLogin[MAXLEN];
Xchar	Lastlog[]	= "/usr/adm/lastlog";
Xchar	Wtmp[]		= "/usr/adm/wtmp";
Xchar	Motd[]		= "/etc/motd";
Xchar	NoLogin[]	= "/etc/nologin";
Xchar	lastltime[100];
Xchar	Myname[255];
Xchar	XLogin[MAXLEN];
X
Xint	do_login	= TRUE;
Xint	do_logout;
Xint	info_atall;
Xint	info_eproclim	= FALSE;
Xint	info_eusers	= FALSE;
Xint	info_lastlog	= FALSE;
Xint	info_motd	= FALSE;
Xint	info_nolog	= FALSE;
Xint	is_hushlogin;
X
Xchar	*strcat(), *getenv();
Xint	strlen();
X
Xextern int	errno;
Xextern int	lseek(), exit();
X
Xstatic void		ExitMotd();
Xstatic XtCallbackRec	callbacks[] =
X				{ {ExitMotd, NULL}, {NULL, NULL} };
X
X
X
X/*
X * This is the routine that is called on press of the
X * endbutton; exits program when login permitted
X */
Xstatic void ExitMotd()
X{
X	exit(!do_login);
X}
X
X
X
X/*
X * This procedure is called to initialize the passwd struct,
X * the paths to the various files and the utmp struct.
X */
Xvoid Init()
X{
X	char	*user, *home;
X	int	home_len;
X
X	/*
X	 * get the user from the environment
X	 */
X	if ((user = getenv("USER")) == NULL) {
X		fprintf(stderr,"%s: cannot getenv(\"USER\") \n", Myname);
X		exit(1);
X	}
X	/*
X	 * get the passwd entry of the user
X	 */
X	if ((pwd = getpwnam(user)) == NULL) {
X		endpwent();
X		fprintf(stderr,"%s: cannot getpwnam(%s) \n", Myname, user);
X		exit(1);
X	}
X	endpwent();
X	/*
X	 * set the path to the users home directory
X	 */
X	if ((home = getenv("HOME")) == NULL) {
X		home = pwd->pw_dir;
X	}
X	/*
X	 * build up the variables pointing to the files we want
X	 * to use and check, whether we reserved enough space 
X	 * otherwise exit
X	 */
X	home_len = strlen(home) + 1;	/* pathname + delimiter */
X	if (home_len >= MAXLEN) {
X		fprintf(stderr, "%s: pathname length overflow \n");
X		exit(1);
X	}
X	STRCPY(HushLogin, home); strcat(HushLogin, path_delimiter);
X	STRCPY(XLogin, home); strcat(XLogin, path_delimiter);
X	if (home_len + strlen(HushLog) > MAXLEN) {
X		fprintf(stderr, "%s: pathname length overflow \n");
X		exit(1);
X	}
X	if (home_len + strlen(XLogFile) > MAXLEN) {
X		fprintf(stderr, "%s: pathname length overflow \n");
X		exit(1);
X	}
X	strncat(HushLogin, HushLog, MAXLEN-strlen(HushLogin));
X	strncat(XLogin, XLogFile, MAXLEN-strlen(XLogFile));
X
X	/*
X	 * set up the utmp struct for the wtmp file
X	 */
X	STRCPY(wtmp.ut_name, pwd->pw_name);
X	STRCPY(wtmp.ut_host, EMPTY);
X	STRCPY(wtmp.ut_line, XTTYname);
X	time((long *) &wtmp.ut_time);
X
X	/*
X	 * check if $HOME/.hushlogin exists and set the
X	 * appropriate flag
X	 */
X	is_hushlogin = (access(HushLogin, F_OK) == 0);
X}
X
X
X
X/*
X * this procedure checks, whether logins are permitted
X * and sets the appropriate flags
X */
Xvoid CheckNologin()
X{
X	if (access(NoLogin, F_OK) == 0) {
X		/*
X		 * deny login only, if user not root
X		 */
X		do_login = FALSE | (pwd->pw_uid == 0);
X		info_nolog = TRUE;
X	}
X}
X
X
X
X/*
X * deny login because of bad quota ?
X */
Xvoid CheckQuota()
X{
X	if ((quota(Q_SETUID, pwd->pw_uid, 0, (caddr_t) 0) < 0)
X	  && (errno != EINVAL)) {
X		if (errno == EUSERS) {
X			do_login = FALSE;
X			info_eusers = TRUE;
X		} else {
X			if (errno = EPROCLIM) {
X				do_login = FALSE;
X				info_eproclim = TRUE;
X			}
X		}
X	}
X}
X
X
X
X/*
X * check if motd file exists and whether it is newer than
X * a eventually existing file $HOME/.Xlogin
X */
Xvoid CheckMotd()
X{
X	struct stat	buf;
X	time_t		xlast;
X
X	info_motd	= TRUE;
X	if (stat(XLogin, &buf) == 0) {
X		xlast = buf.st_mtime;
X		utime(XLogin, NULL);
X	} else xlast = (time_t) 0;
X
X	if (stat(Motd, &buf) == 0)
X		info_motd = (xlast < buf.st_mtime);
X	else info_motd = FALSE;
X
X	/*
X	 * display motd only if no .hushlogin exists
X	 */
X	info_motd = info_motd && !is_hushlogin;
X}
X
X
X
X/*
X * this procedure writes the wtmp entry
X */
Xvoid WriteWtmp()
X{
X	int	wtmpfd;
X
X	/*
X	 * write only if file exists, don't create it
X	 */
X	if ((wtmpfd = open(Wtmp, O_WRONLY|O_APPEND)) >= 0) {
X		write(wtmpfd, (char *) &wtmp, sizeof(wtmp));
X		close(wtmpfd);
X	}
X}
X
X
X
X/*
X * this procedure reads from and writes to the
X * lastlogin file. If none exists, it will not be created.
X */
Xvoid DoLastLogin()
X{
X	struct lastlog	rll, wll;
X	int		llfd;		/* Lastlog file descriptor */
X
X	STRCPY(lastltime, "Last Login: ");
X	if ((llfd = open(Lastlog, O_RDWR)) >= 0) {
X		/*
X		 *  get time of last login, if any
X		 */
X		lseek(llfd, (long) pwd->pw_uid * sizeof(struct lastlog), 0);
X		if (read(llfd, (char *) &rll, sizeof(rll)) == sizeof(rll)
X		&& (rll.ll_time != 0)) {
X			strncat(lastltime, ctime((long *) &rll.ll_time), 24);
X			if (strcmp(rll.ll_host, "") != 0) {
X				strcat(lastltime, " from ");
X				strcat(lastltime, rll.ll_host);
X			}
X			info_lastlog = !is_hushlogin;
X		}
X		/*
X		 * write new last login time
X		 */
X		lseek(llfd, (long) pwd->pw_uid * sizeof(struct lastlog), 0);
X		wll.ll_time = wtmp.ut_time;
X		STRCPY(wll.ll_line, XTTYname);
X		STRCPY(wll.ll_host, wtmp.ut_host);
X		write(llfd, (char *) &wll, sizeof(wll));
X		close(llfd);
X	}
X}
X
X
X
X/*
X * this procedure does all the display stuff:
X *   defining, creating and starting widgets
X */
Xvoid DoXDisplay(argc, argv)
X	int	argc;
X	char	*argv[];
X{
X#define LABELLEN	255
X	Widget	toplevel, form, endbutton, lastlogin, motd,
X		eproclim, eusers, motd_label, nologin_label;
X	Widget	queue;
X	Arg	args[11];
X	int	width, height,
X		dpywidth, dpyheight,
X		formwidth, formheight;
X	char	motd_label_text[LABELLEN], nolog_label_text[LABELLEN];
X
X	/*
X	 * THIS IS UGLY, but don't how to do it better in the moment.
X	 * I assume a 6x13 font and set width and height to
X	 * 12 lines and 80 columns
X	 */
X	width = 80 * 6;
X	height = 12 * 13;
X
X	toplevel = XtInitialize(NULL, "XLogin", NULL, 0, &argc, argv);
X
X	form = XtCreateWidget("form", formWidgetClass, toplevel,
X		(ArgList) NULL, 0);
X	XtManageChild(form);
X
X	queue = (Widget) NULL;
X
X	if (info_lastlog) {
X		XtSetArg(args[0], XtNresize, True);
X		XtSetArg(args[1], XtNjustify, XtJustifyCenter);
X		XtSetArg(args[2], XtNlabel, lastltime);
X		XtSetArg(args[3], XtNborderWidth, (Dimension) 0);
X		XtSetArg(args[4], XtNwidth, (Dimension) width);
X		lastlogin = XtCreateWidget("lastlogin", labelWidgetClass, form,
X				args, 5);
X		XtManageChild(lastlogin);
X		queue = lastlogin;
X	}
X
X	if (do_login) {
X		if (info_motd) {
X			strcpy(motd_label_text,"Message Of The Day follows:");
X		} else {
X			STRCPY(motd_label_text, "Nothing changed in ");
X			strncat(motd_label_text, Motd,
X				LABELLEN-strlen(motd_label_text));
X			strncat(motd_label_text, " since your last login",
X				LABELLEN-strlen(motd_label_text));
X		}
X	} else {
X		STRCPY(motd_label_text, "Sorry, no login permitted");
X	}
X
X	XtSetArg(args[0], XtNresize, True);
X	XtSetArg(args[1], XtNjustify, XtJustifyCenter);
X	XtSetArg(args[2], XtNlabel, motd_label_text);
X	XtSetArg(args[3], XtNborderWidth, (Dimension) 0);
X	XtSetArg(args[4], XtNfromVert, queue);
X	XtSetArg(args[5], XtNwidth, (Dimension) width);
X	motd_label = XtCreateWidget("motd_label", labelWidgetClass, form,
X			(ArgList) args, 6);
X	XtManageChild(motd_label);
X	queue = motd_label;
X
X	if (info_eusers) {
X		XtSetArg(args[0], XtNresize, True);
X		XtSetArg(args[1], XtNjustify, XtJustifyCenter);
X		XtSetArg(args[2], XtNlabel,	
X			"Too many users already logged in. Try again later");
X		XtSetArg(args[3], XtNborderWidth, (Dimension) 0);
X		XtSetArg(args[4], XtNfromVert, queue);
X		XtSetArg(args[5], XtNwidth, (Dimension) width);
X		eusers = XtCreateWidget("eusers", labelWidgetClass, form,
X			(ArgList) args, 6);
X		XtManageChild(eusers);
X		queue = eusers;
X	}
X
X
X	if (info_eproclim) {
X		XtSetArg(args[0], XtNresize, True);
X		XtSetArg(args[1], XtNjustify, XtJustifyCenter);
X		XtSetArg(args[2], XtNlabel,	
X			"You have too many processes running.");
X		XtSetArg(args[3], XtNborderWidth, (Dimension) 0);
X		XtSetArg(args[4], XtNfromVert, queue);
X		XtSetArg(args[5], XtNwidth, (Dimension) width);
X		eproclim = XtCreateWidget("eproclim", labelWidgetClass, form,
X			(ArgList) args, 6);
X		XtManageChild(eproclim);
X		queue = eproclim;
X	}
X
X	if (info_nolog) {
X		STRCPY(nolog_label_text, "Text in file ");
X		strncat(nolog_label_text, NoLogin,
X			LABELLEN-strlen(nolog_label_text));
X		strncat(nolog_label_text, " follows:",
X			LABELLEN-strlen(nolog_label_text));
X		XtSetArg(args[0], XtNresize, True);
X		XtSetArg(args[1], XtNjustify, XtJustifyCenter);
X		XtSetArg(args[2], XtNlabel, nolog_label_text);
X		XtSetArg(args[3], XtNborderWidth, (Dimension) 0);
X		XtSetArg(args[4], XtNfromVert, queue);
X		XtSetArg(args[5], XtNwidth, (Dimension) width);
X		nologin_label = XtCreateWidget("nologin_label", labelWidgetClass, form,
X				(ArgList) args, 6);
X		XtManageChild(nologin_label);
X		queue = nologin_label;
X
X		XtSetArg(args[0], XtNfile, NoLogin);
X		XtSetArg(args[1], XtNtextOptions, resizeWidth|resizeHeight|
X					scrollVertical|scrollHorizontal);
X		XtSetArg(args[2], XtNeditType, XttextRead);
X		XtSetArg(args[3], XtNfromVert, queue);
X		XtSetArg(args[4], XtNheight, (Dimension) height);
X		XtSetArg(args[5], XtNwidth, (Dimension) width);
X		motd = XtCreateWidget("motd", asciiDiskWidgetClass, form,
X				(ArgList) args, 6);
X		XtManageChild(motd);
X		queue = motd;
X	} else {
X		if (info_motd) {
X			XtSetArg(args[0], XtNfile, Motd);
X			XtSetArg(args[1], XtNtextOptions, resizeWidth|resizeHeight|
X						scrollVertical|scrollHorizontal);
X			XtSetArg(args[2], XtNeditType, XttextRead);
X			XtSetArg(args[3], XtNfromVert, queue);
X			XtSetArg(args[4], XtNheight, (Dimension) height);
X			XtSetArg(args[5], XtNwidth, (Dimension) width);
X			motd = XtCreateWidget("motd", asciiDiskWidgetClass, form,
X					(ArgList) args, 6);
X			XtManageChild(motd);
X			queue = motd;
X		}
X	}
X	
X	XtSetArg(args[0], XtNcallback, callbacks);
X	XtSetArg(args[1], XtNjustify, XtJustifyCenter);
X	XtSetArg(args[2], XtNresize, True);
X	XtSetArg(args[3], XtNresizable,	False);
X	XtSetArg(args[4], XtNwidth, (Dimension) width);
X	XtSetArg(args[5], XtNfromVert, queue);
X	XtSetArg(args[6], XtNborderWidth, (Dimension) 2);
X	XtSetArg(args[7], XtNhighlightThickness, (Dimension) 2);
X	XtSetArg(args[8], XtNinternalHeight, (Dimension) 3);
X	XtSetArg(args[9], XtNinternalWidth, (Dimension) 3);
X	XtSetArg(args[10],XtNlabel, "Click here to continue");
X	endbutton = XtCreateWidget("endbutton", commandWidgetClass, form,
X			(ArgList) args, 11);
X	XtManageChild(endbutton);
X	queue = endbutton;
X
X	/*
X	 * Get the size of the screen.
X	 * Want the window to be centered.
X	 */
X	dpywidth = DisplayWidth(XtDisplay(form), DefaultScreen(XtDisplay(form)));
X	dpyheight = DisplayHeight(XtDisplay(form), DefaultScreen(XtDisplay(form)));
X
X	/*
X	 * Don't map, but realize it, to get the size of the window
X	 */
X	XtSetMappedWhenManaged(toplevel, False);
X	XtRealizeWidget(toplevel);
X
X	while (!XtIsRealized(form))
X		formwidth=2;
X
X	/*
X	 * Get the size of the window
X	 */
X	args[0].name = XtNwidth;
X	args[0].value = (XtArgVal) &formwidth;
X	args[1].name = XtNheight;
X	args[1].value = (XtArgVal) &formheight;
X	XtGetValues(form, args, 2);
X
X	/*
X	 * Place the window centered on the screen.
X	 */
X	XtMoveWidget(toplevel, (Position) (dpywidth - formwidth) / 2,
X			(Position) (dpyheight - formheight) / 2);
X
X	/*
X	 * Now map the window to get it visible
X	 */
X	XtSetMappedWhenManaged(toplevel, True);
X	XtMapWidget(toplevel);
X	/*
X	 * Warp the pointer in the button-click window
X	 */
X	XWarpPointer(XtDisplay(toplevel), (Window) NULL, XtWindow(endbutton),
X		0, 0, 0, 0, width/2, 3);
X	XtMainLoop();
X}
X
X
X
Xmain(argc, argv)
X	int	argc;
X	char	*argv[];
X{
X	STRCPY(Myname, argv[0]);
X
X	do_logout = FALSE;
X	if (argc > 1) {
X		do_logout = (strcmp(argv[1], "-logout") == 0);
X		if (!do_logout) {
X			fprintf(stderr,"%s: unknown option %s \n",Myname,
X				argv[1]);
X			fprintf(stderr,"Usage:\n	%s [-logout] \n",Myname);
X			exit(1);
X		}
X	}
X	do_login  = !do_logout;
X
X	Init();
X
X	if (do_logout) {
X		STRCPY(wtmp.ut_name, EMPTY);
X		WriteWtmp();
X		exit(0);
X	}
X
X	CheckNologin();
X	CheckQuota();
X
X	if (do_login) {
X		WriteWtmp();
X		DoLastLogin();
X		CheckMotd();
X	}
X
X	info_atall = info_lastlog | info_motd | info_eusers
X			| info_eproclim | info_nolog;
X	if (info_atall) {
X		DoXDisplay(argc, argv);
X	}
X}
END_OF_FILE
if test 13294 -ne `wc -c <'xlogin.c'`; then
    echo shar: \"'xlogin.c'\" unpacked with wrong size!
fi
# end of 'xlogin.c'
fi
if test -f 'xlogin.man' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xlogin.man'\"
else
echo shar: Extracting \"'xlogin.man'\" \(2955 characters\)
sed "s/^X//" >'xlogin.man' <<'END_OF_FILE'
X.TH XLOGIN 1 "25 April 1989" "X Version 11"
X.SH NAME
Xxlogin - login for X
X.SH SYNOPSIS
X.B "xlogin"
X[-logout] 
X.SH SUMMARY
X.PP
XThe
X.I xlogin
Xutility is for logging in from \fIxdm(1)\fB . It supports motd, wtmp,
Xlastlog, nologin and quota handling.
X.SH OPTIONS
X.PP
X.TP 8
X.B "-logout"
Xonly writes an logout entry to the wtmp file
X.SH DESCRIPTION
X.PP
XThe \fIxlogin\fP 
Xcommand is used, after \fIxdm(1)\fP has validated the password and
Xlet the user log in. It should be called from within the Xstartup file
X(run setuid root) and again with the \-logout option from within
Xthe Xreset file. (see \fIxdm(1)\fP for more information on these files)
X.PP
X\fIXlogin\fP does all the login stuff \fIxdm(1)\fP does not:
X.ta \w'.\ \ 'u
X.br
X.PP
X\-	it checks, whether the file /etc/nolog exists and displays its contents
Xin a window.
X.br
X.PP
X\-	it checks the users quota and displays appropriate messages, if exceeded.
XNo login is permitted in this case.
X.br
X.PP
X\-	if login is permitted, it writes an entry to the /usr/adm/wtmp
Xfile indicating Xlogin as the user's tty. If the file does not exist,
Xnone is created.
X.br
X.PP
X\-	if login is permitted, it writes an entry to /usr/adm/lastlog
Xindicating Xlogin as the user's tty. If the file does not exist,
Xnone is created.
X.br
X.PP
X\-	it checks, whether a $HOME/.hushlogin file exists. No message-of-the-day
Xand no last login message is diplayed in this case.
X.br
X.PP
X\-	it checks, whether a $HOME/.Xlogin file exists, compares its
Xlast change time against those of the /etc/motd file, displays the
Xmotd if this file is newer and touches the .Xlogin file. If no .Xlogin
Xfile exists /etc/motd is displayed every time.
X.br
X.PP
XIf anything is to be displayed, \fIxlogin\fP
Xcreates a window and waits for a button click to exit.
X.SH RETURN VALUE
X.PP
XIf login is permitted \fIxlogin\fP returns 0 otherwise the value 1
Xis returned.
X.SH ENVIRONMENT
X.PP
X.TP 8
X.B DISPLAY
XTo get default display.
X.TP 8
X.B USER
XTo get the name of the user to log in. (normally set by \fIxdm(1)\fP
Xcorrectly.)
X.TP 8
X.B HOME
XTo get the user's home directory. If not set, it is obtained from /etc/passwd.
X.PP
X.SH EXAMPLES
X.PP
Xin the file Xstartup:
X.PP
X	/usr/local/dist/xlogin
X.PP
X.PP
Xin the file Xstartup:
X.PP
X	/usr/local/dist/xlogin -logout
X.SH FILES
X.ta \w'/usr/adm/lastlog\ \ 'u
X/usr/adm/wtmp	accounting
X.br
X/usr/adm/lastlog	last logins
X.br
X/etc/motd	message-of-the-day
X.br
X/etc/nologin	stops login
X.br
X/etc/passwd	passwd file
X.br
X\&.hushlogin	makes xlogin much quieter
X.br
X\&.Xlogin	makes xlogin a bit quieter
X.SH WINDOW
XTo display the contents of /etc/motd or /etc/nologin, a widget
Xof 12x80 characters is created.
XAll other messages are boxes up to 80 characters in width.
X.SH BUGS
XA font of 6x13 is assumed, to set the width and height of the
Xvarious widgets.
X.SH SEE ALSO
XX(1), xdm(1), login(1)
X.SH COPYRIGHT
XCopyright 1989, Technische Universitaet Muenchen (TUM).
X.SH AUTHOR
XMarkus Stumpf, TU Muenchen
X  (stumpf@lan.informatik.tu-muenchen.dbp.de)
END_OF_FILE
if test 2955 -ne `wc -c <'xlogin.man'`; then
    echo shar: \"'xlogin.man'\" unpacked with wrong size!
fi
# end of 'xlogin.man'
fi
echo shar: End of shell archive.
exit 0