v08i051: xlogin, Part01/01

Markus Stumpf stumpf at lan.informatik.tu-muenchen.de
Wed Jul 11 06:32:48 AEST 1990


Submitted-by: Markus Stumpf <stumpf at lan.informatik.tu-muenchen.de>
Posting-number: Volume 8, Issue 51
Archive-name: xlogin/part01

Here is version 2.0 of my xlogin program.
+- Markus Stumpf                         Technische Universitaet Muenchen   -+
|                            Institut fuer Informatik, Rechnerbetriebsgruppe |
|  stumpf at informatik.tu-muenchen.de              Postfach 202420             |
+-   ...@{unido.uucp,relay.cs.net}        D-8000 Muenchen 2, West Germany   -+

------------------------------ cut here -----------------------------------
#!/bin/sh
# This is a shell archive (shar 3.24)
# made 07/09/1990 14:14 UTC by stumpf at dssystem1
# Source directory /usr/wiss/stumpf/src/X.V11R4/local/clients/xlogin
#
# existing files WILL be overwritten
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#   2453 -rw-r--r-- README
#   2511 -r--r--r-- INSTALL
#    292 -rw-r--r-- Imakefile
#   3040 -rw-r--r-- Makefile.std
#   1032 -rw-r--r-- xdm.patch01
#   2795 -rw-rw-r-- xdm.patch02
#  27614 -rw-r--r-- xlogin.c
#     21 -rw-rw-r-- patchlevel.h
#   1124 -rw-r--r-- Xlogin.ad
#   5798 -rw-r--r-- xlogin.man
#
if touch 2>&1 | fgrep '[-amc]' > /dev/null
 then TOUCH=touch
 else TOUCH=true
fi
# ============= README ==============
echo "x - extracting README (Text)"
sed 's/^X//' << 'SHAR_EOF' > README &&
X  This is the second release of xlogin! There has been a lot
Xof cleanup of the code and a few features have been added.
XPlease look at the manual page for more information.
X
XCREDITS:
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.
X  Lotta thanks to Tim Theisen (tim at cs.wisc.edu or uwvax!tim) from the
XDepartment of Computer Sciences at the University of Wisconsin-Madison,
Xfor doing the alpha and beta testing, supplying me with some code,
Xhelping me with some design decisions and making the man-page look more
Xtechnical and correcting my English grammer and spelling. (I'm German,
Xas u can see from the signature ;-) ) Thank you!
X
XABOUT:
X------
X  This program was written to do some stuff, which is no longer
Xdone, when using Xdm from X Windows Version 11 (and not using sessreg).
XIt handles /etc/motd, /etc/nologin, user quotas (EPROCLIM, EUSERS),
X/usr/adm/lastlog, /usr/adm/wtmp, /etc/utmp 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
XCOMPILING:
X----------
X  There are three compiler-flags: -DHOSTNAME -DQUOTA and -DLASTLOGIN.
Xo if you want the utmp host field to contain the hostname if the
X  display string starts with ":", compile with -DHOSTNAME. This code
X  is useful, if the utmp/wtmp is collected on a central machine.
Xo if you want lastlogin records to be written, use -DLASTLOGIN
Xo if you want to turn on the QUOTA code use -DQUOTA
X
XINSTALLING:
X-----------
XPlease read the file INSTALL! It contains urgent instructions for
Xinstalling xlogin !!
X
XThe program has been tested on the following machines:
X
X   mVax II,            Ultrix 3.1
X   DecStation 2100,    Ultrix 3.1
X   DecStation 3100,    Ultrix 3.1 and 4.0
X   VaxStation 3200,    Ultrix 3.1 and 4.0
X   IBM RT,             AOS 4.3
X   Sun 3/50,           SunOS 4.0.3
X   Sun 4/110,          SunOS 4.0.3 and 4.1
X   SunSparcStation 1,  SunOS 4.0.3c
X   Hp Bobcat,          BSD 4.3
X   Sequent symmetry,   Dynix 3.0.12
X
XEnjoy!
X
X\Maex
X
X+- Markus Stumpf                         Technische Universitaet Muenchen   -+
X|                            Institut fuer Informatik, Rechnerbetriebsgruppe |
X|  stumpf at informatik.tu-muenchen.de              Postfach 202420             |
X+-   ...@{unido.uucp,relay.cs.net}        D-8000 Muenchen 2, West Germany   -+
SHAR_EOF
$TOUCH -am 0709155890 README &&
chmod 0644 README ||
echo "restore of README failed"
set `wc -c README`;Wc_c=$1
if test "$Wc_c" != "2453"; then
	echo original size 2453, current size $Wc_c
fi
# ============= INSTALL ==============
echo "x - extracting INSTALL (Text)"
sed 's/^X//' << 'SHAR_EOF' > INSTALL &&
XA problem with xdm becomes apparent when installing xlogin!
X
XTypically xlogin should be called from the Xstartup and Xreset scripts
X(most of the time these can be found in the directory /usr/lib/X11/xdm).
XBut xdm is broken, because there is no authorization file
Xat the time the Xstartup-script is executed!
X
XThere are three possibilities:
X1) use X without authorization (not good I think).
X2) use xdm.patch01 to simply move the deletion of initial authorization
X   file until after the execution of Xstartup.
X3) use xdm.patch02 supplied by Tim Theisen to write an authorization
X   record for root to the file /.Xauthority.
X
Xin the latter two cases, you should set the environment variable
XXAUTHORITY so that it points to the authorization file.
XThus your Xstartup script might in the 2nd case look like:
X
X|> #!/bin/sh
X|>
X|> XAUTHORITY=/usr/lib/X11/xdm/auth-server
X|> export XAUTHORITY
X|>
X|> exec /usr/bin/X11/xlogin
X
Xor in the 3rd case like:
X
X|> #!/bin/sh
X|>
X|> XAUTHORITY=/.Xauthority
X|> export XAUTHORITY
X|>
X|> exec /usr/bin/X11/xlogin
X
XWhen executing xlogin in the Xreset script, there is no need for
Xan authorization file, cause xlogin doesn't open a connection to
Xthe X server! Thus it might look like:
X
X|> #!/bin/sh
X|> 
X|> exec /usr/bin/X11/xlogin -logout
X
X
XIf there is an entry for the X display in the /etc/ttys file,
Xxlogin will also write a record in utmp.  The ttyname is derived
Xfrom the display name.  If the display is local, the ttyname is
X"X" followed by the display number.  If the display is remote (i.e.
Xan X terminal), then ttyname is the hostname of the display.
XFor example, the display name ":0" maps to "X0", and the display
Xname "ncd1.cs.wisc.edu:0" maps to "ncd1".
X
XOne must take care when adding entries for the X displays in the
X/etc/ttys file.  The X displays should be placed at the end of
Xthe file.  Programs such as "talk" attempt to connect to the first
Xtty that it finds.  (Ideally, talk should connect to the least
Xidle tty for a particular user.)  To create an entry for an X
Xdisplay, simply copy the last network tty and set the ttyname
Xto the appropriate value.  It is also a good idea to place an
Xentry for the X display in /dev.  I think that a link to /dev/null
Xis the best solution.  Some programs check every tty listed in
Xutmp for activity to judge how idle the system is.
X
XAnother solution, (if u only have one display on that workstation)
Xand if u run e.g. xconsole in the background, is to link it to
X/dev/console and put the X0 on the first place in /etc/ttys!
X
SHAR_EOF
$TOUCH -am 0709155990 INSTALL &&
chmod 0444 INSTALL ||
echo "restore of INSTALL failed"
set `wc -c INSTALL`;Wc_c=$1
if test "$Wc_c" != "2511"; then
	echo original size 2511, current size $Wc_c
fi
# ============= Imakefile ==============
echo "x - extracting Imakefile (Text)"
sed 's/^X//' << 'SHAR_EOF' > Imakefile &&
X#
X# $Id: Imakefile,v 1.2 90/07/09 15:42:26 stumpf Exp Locker: stumpf $
X#
X
X        DEFINES = -DQUOTA -DLASTLOGIN -DHOSTNAME
X           SRCS = xlogin.c
X           OBJS = xlogin.o
XLOCAL_LIBRARIES = $(XAWLIB) $(XMULIB) $(XTOOLLIB) $(XLIB)
X
XComplexProgramTarget(xlogin)
XInstallAppDefaults(Xlogin)
SHAR_EOF
$TOUCH -am 0709154290 Imakefile &&
chmod 0644 Imakefile ||
echo "restore of Imakefile failed"
set `wc -c Imakefile`;Wc_c=$1
if test "$Wc_c" != "292"; then
	echo original size 292, current size $Wc_c
fi
# ============= Makefile.std ==============
echo "x - extracting Makefile.std (Text)"
sed 's/^X//' << 'SHAR_EOF' > Makefile.std &&
X#
X# Makefile for non-imake users
X#
X# WARNING   WARNING   WARNING
X#
X# if you don't have QUOTA and/or LASTLOGIN remove -DQUOTA and/or
X#    -DLASTLOGIN from the definition of STD_DEFINES.
X#    In this case you also have to check the dependencies on the
X#    end of this file!
X# you may wish to remove -DHOSTNAME, if you don't want hostname
X#    information for displays in the utmp/wtmp files (see README)
X# check the definition of the various variables
X#
X# $Id: Makefile.std,v 1.3 90/07/09 15:42:54 stumpf Exp Locker: stumpf $
X#
X
X          DEFINES = -DQUOTA -DLASTLOGIN -DHOSTNAME
X          DESTDIR = 
X        USRLIBDIR = $(DESTDIR)/usr/lib
X       APPLDEFDIR = $(USRLIBDIR)/app-defaults
X           BINDIR = $(DESTDIR)/usr/bin/X11
X           MANDIR = $(DESTDIR)/usr/man/man1
X          INCROOT = $(DESTDIR)/usr/include
X     EXTENSIONLIB = $(USRLIBDIR)/libXext.a
X             XLIB = $(USRLIBDIR)/libX11.a
X         XAUTHLIB = $(USRLIBDIR)/libXau.a
X           XMULIB = $(USRLIBDIR)/libXmu.a
X          OLDXLIB = $(USRLIBDIR)/liboldX.a
X         XTOOLLIB = $(USRLIBDIR)/libXt.a
X           XAWLIB = $(USRLIBDIR)/libXaw.a
X          DEPLIBS = $(XAWLIB) $(XMULIB) $(XTOOLLIB) $(EXTENSIONLIB) $(XLIB)
X           LDLIBS = $(DEPLIBS)
X           CFLAGS = $(DEFINES)
X
X        PROGRAM = xlogin
X           SRCS = xlogin.c
X           OBJS = xlogin.o
X
Xall: xlogin
X
Xxlogin: $(OBJS) $(DEPLIBS)
X	rm -f $@
X	$(CC) -o $@ $(OBJS) $(LDLIBS)
X
Xinstall: xlogin
X	install -c -m 0755 xlogin $(BINDIR)
X	install -c -m 0644 Xlogin.ad $(APPLDEFDIR)/Xlogin
X
Xinstall.man: xlogin.man
X	install -c -m 0644 xlogin.man $(MANDIR)/xlogin.l
X
Xclean:
X	rm -f $(PROGRAM) *.CKP *.ln *.BAK *.bak *.o core errs ,* *~ \
X	*.a .emacs_* tags TAGS make.log MakeOut
X
X
X# DO NOT DELETE THIS LINE -- make depend depends on it.
X
Xxlogin.o: /usr/include/sys/quota.h /usr/include/lastlog.h
X
Xxlogin.o: /usr/include/sys/param.h /usr/include/machine/param.h
Xxlogin.o: /usr/include/errno.h /usr/include/pwd.h /usr/include/sys/stat.h
Xxlogin.o: /usr/include/sys/signal.h /usr/include/sys/types.h
Xxlogin.o: /usr/include/utmp.h /usr/include/stdio.h /usr/include/ttyent.h
Xxlogin.o: /usr/include/X11/Xos.h /usr/include/strings.h
Xxlogin.o: /usr/include/sys/file.h /usr/include/sys/time.h
Xxlogin.o: /usr/include/X11/StringDefs.h /usr/include/X11/Intrinsic.h
Xxlogin.o: /usr/include/X11/Xlib.h /usr/include/X11/X.h
Xxlogin.o: /usr/include/X11/Xutil.h /usr/include/X11/Xresource.h
Xxlogin.o: /usr/include/X11/Core.h /usr/include/X11/Composite.h
Xxlogin.o: /usr/include/X11/Constraint.h /usr/include/X11/Object.h
Xxlogin.o: /usr/include/X11/RectObj.h /usr/include/X11/Shell.h
Xxlogin.o: /usr/include/X11/Xaw/Command.h /usr/include/X11/Xaw/Label.h
Xxlogin.o: /usr/include/X11/Xaw/Simple.h /usr/include/X11/Xmu/Converters.h
Xxlogin.o: /usr/include/X11/Xaw/Form.h /usr/include/X11/Xaw/AsciiText.h
Xxlogin.o: /usr/include/X11/Xaw/Text.h /usr/include/X11/Xaw/TextSink.h
Xxlogin.o: /usr/include/X11/Xaw/TextSrc.h /usr/include/X11/Xaw/AsciiSrc.h
Xxlogin.o: /usr/include/X11/Xaw/AsciiSink.h /usr/include/X11/Xmu/CharSet.h
Xxlogin.o: patchlevel.h
SHAR_EOF
$TOUCH -am 0709154390 Makefile.std &&
chmod 0644 Makefile.std ||
echo "restore of Makefile.std failed"
set `wc -c Makefile.std`;Wc_c=$1
if test "$Wc_c" != "3040"; then
	echo original size 3040, current size $Wc_c
fi
# ============= xdm.patch01 ==============
echo "x - extracting xdm.patch01 (Text)"
sed 's/^X//' << 'SHAR_EOF' > xdm.patch01 &&
X*** session.c.mit	Mon Feb 12 21:44:13 1990
X--- session.c	Thu Mar 15 10:55:13 1990
X***************
X*** 112,122 ****
X      LoadXloginResources (d);
X      Debug ("name now %s\n", d->name);
X      dpy = InitGreet (d);
X-     if (d->authorization && d->authFile)
X-     {
X- 	Debug ("Done with authorization file %s, removing\n", d->authFile);
X- 	(void) unlink (d->authFile);
X-     }
X      for (;;) {
X  	/*
X  	 * Greet user, requesting name/password
X--- 112,117 ----
X***************
X*** 141,147 ****
X--- 136,152 ----
X      {
X  	Debug ("Startup program %s exited with non-zero status\n",
X  		d->startup);
X+       if (d->authorization && d->authFile)
X+       {
X+ 	  Debug ("Done with authorization file %s, removing\n", d->authFile);
X+ 	  (void) unlink (d->authFile);
X+       }
X  	SessionExit (d, OBEYSESS_DISPLAY);
X+     }
X+     if (d->authorization && d->authFile)
X+     {
X+ 	Debug ("Done with authorization file %s, removing\n", d->authFile);
X+ 	(void) unlink (d->authFile);
X      }
X      clientPid = 0;
X      if (!setjmp (abortSession)) {
SHAR_EOF
$TOUCH -am 0705191490 xdm.patch01 &&
chmod 0644 xdm.patch01 ||
echo "restore of xdm.patch01 failed"
set `wc -c xdm.patch01`;Wc_c=$1
if test "$Wc_c" != "1032"; then
	echo original size 1032, current size $Wc_c
fi
# ============= xdm.patch02 ==============
echo "x - extracting xdm.patch02 (Text)"
sed 's/^X//' << 'SHAR_EOF' > xdm.patch02 &&
XAlso, I thought that I would share my changes to xdm.  I have changed
Xxdm to write an authorization record for root.  I feel that this does
Xnot compromise security at all.  root could also setuid to the user
Xto gain access to the display.  I have written a daemon that catches
Xconsole message and displays them in a window.  Also, we have a system
Xthat submits jobs on idle workstations.  This system can connect to
Xthe X display to check the idle time.  Anyway, here is my patch to xdm:
X 
X 
X*** /tmp/,RCSt1a23628	Sun Jul  8 14:39:22 1990
X--- auth.c	Wed Jun 13 14:03:25 1990
X***************
X*** 201,206 ****
X--- 201,207 ----
X  	    ret = TRUE;
X  	fclose (auth_file);
X      }
X+     SetRootAuthorization (d, auth);
X      return ret;
X  }
X  
X***************
X*** 778,781 ****
X--- 779,849 ----
X  	}
X      }
X      Debug ("done SetUserAuthorization\n");
X+ }
X+ 
X+ SetRootAuthorization (d, auth)
X+ struct display	*d;
X+ Xauth		*auth;
X+ {
X+     FILE	*old, *new;
X+     char	*home_name;
X+     char	new_name[1024];
X+     int	lockStatus;
X+     Xauth	*entry;
X+     struct stat	statb;
X+ 
X+     Debug ("SetRootAuthorization\n");
X+     if (auth) {
X+ 	lockStatus = LOCK_ERROR;
X+ 	home_name = "/.Xauthority";
X+ 	Debug ("XauLockAuth %s\n", home_name);
X+ 	lockStatus = XauLockAuth (home_name, 1, 2, 10);
X+ 	Debug ("Lock is %d\n", lockStatus);
X+ 	if (lockStatus == LOCK_SUCCESS) {
X+ 	    if (!openFiles (home_name, new_name, &old, &new)) {
X+ 		Debug ("openFiles failed\n");
X+ 		XauUnlockAuth (home_name);
X+ 		lockStatus = LOCK_ERROR;
X+ 	    }	
X+ 	}
X+ 	if (lockStatus != LOCK_SUCCESS) {
X+ 	    Debug ("can't lock auth file %s\n", home_name);
X+ 	    LogError ("can't lock authorization file %s\n", home_name);
X+ 	    return;
X+ 	}
X+ 	initAddrs ();
X+ 	if (d->displayType.location == Local)
X+ 	    writeLocalAuth (new, auth, d->name);
X+ 	else
X+ 	    writeRemoteAuth (new, auth, d->peer, d->peerlen, d->name);
X+ 	if (old) {
X+ 	    if (fstat (fileno (old), &statb) != -1)
X+ 		chmod (new_name, (int) (statb.st_mode & 0777));
X+ 	    while (entry = XauReadAuth (old)) {
X+ 		if (!checkAddr (entry->family,
X+ 			       entry->address_length, entry->address,
X+ 			       entry->number_length, entry->number))
X+ 		{
X+ 		    Debug ("Saving an entry\n");
X+ 		    dumpAuth (entry);
X+ 		    writeAuth (new, entry);
X+ 		}
X+ 		XauDisposeAuth (entry);
X+ 	    }
X+ 	    fclose (old);
X+ 	}
X+ 	doneAddrs ();
X+ 	fclose (new);
X+ 	if (unlink (home_name) == -1)
X+ 	    Debug ("unlink %s failed\n", home_name);
X+ 	if (link (new_name, home_name) == -1) {
X+ 	    Debug ("link failed %s %s\n", new_name, home_name);
X+ 	    LogError ("Can't move authorization into place\n");
X+ 	} else {
X+ 	    Debug ("new is in place, go for it!\n");
X+ 	    unlink (new_name);
X+ 	}
X+ 	XauUnlockAuth (home_name);
X+     }
X+     Debug ("done SetRootAuthorization\n");
X  }
SHAR_EOF
$TOUCH -am 0709153390 xdm.patch02 &&
chmod 0664 xdm.patch02 ||
echo "restore of xdm.patch02 failed"
set `wc -c xdm.patch02`;Wc_c=$1
if test "$Wc_c" != "2795"; then
	echo original size 2795, current size $Wc_c
fi
# ============= xlogin.c ==============
echo "x - extracting xlogin.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > xlogin.c &&
X/*
X * xlogin - X login manager
X *
X * $Id: xlogin.c,v 2.2 90/07/09 15:41:54 stumpf Exp Locker: stumpf $
X *
X * Copyright 1989, 1990 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 at lan.informatik.tu-muenchen.de)
X *
X * $Source: /usr/wiss/stumpf/src/X.V11R4/local/clients/xlogin/RCS/xlogin.c,v $
X *
X */
X
X#include <sys/param.h>
X#ifdef QUOTA
X#include <sys/quota.h>
X#endif
X#include <sys/stat.h>
X
X#include <errno.h>
X#ifdef LASTLOGIN
X#	include <lastlog.h>
X#endif /* LASTLOGIN */
X#include <pwd.h>
X#include <utmp.h>
X/* EMPTY is defined in most <utmp.h> */
X#ifndef EMPTY
X#	define EMPTY ""
X#endif
X#include <stdio.h>
X#ifndef sequent
X#	include <ttyent.h>
X#endif
X
X#include <X11/Xos.h>
X#include <X11/StringDefs.h>
X#include <X11/Intrinsic.h>
X#include <X11/Shell.h>
X#include <X11/Xaw/Command.h>
X#include <X11/Xaw/Form.h>
X#include <X11/Xaw/AsciiText.h>
X#include <X11/Xmu/CharSet.h>
X
X#include "patchlevel.h"
X
X#define	XLOGIN_NAME	"xlogin"
X#define	XLOGIN_CLASS	"Xlogin"
X
X#define MAXLEN	1024
X
X#define STRCPY(a, b)	strncpy(a, b, sizeof(a))
X
Xstruct passwd	*pwd;
Xstruct utmp	wtmp;
X#ifdef LASTLOGIN
X	struct lastlog	rll;
X#endif /* LASTLOGIN */
X
Xchar	path_delimiter[]= "/";
Xchar	XTTYname[100];
Xchar	HushLog[]	= ".hushlogin";
Xchar	XLogFile[]	= ".Xlogin";
Xchar	HushLogin[MAXLEN];
Xchar	Lastlog[]	= "/usr/adm/lastlog";
X#ifndef UTMP_FILE
X	char	Utmp[]		= "/etc/utmp";
X#else
X	char	Utmp[]		= UTMP_FILE;
X#endif	/* UTMP_FILE */
X#ifndef WTMP_FILE
X	char	Wtmp[]		= "/usr/adm/wtmp";
X#else
X	char	Wtmp[]		= WTMP_FILE;
X#endif	/* WTMP_FILE */
Xchar	Motd[]		= "/etc/motd";
Xchar	NoLogin[]	= "/etc/nologin";
Xchar	lastltime[100];
Xchar	hostname[100];
Xchar	dpyname[100];
Xchar	versionname[100];
Xchar	Myname[255];
Xchar	MyRevision[]	= "$Revision: 2.2 $";
Xchar	MyVersion[]	= "2.0";
Xchar	DEVname[MAXLEN];
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	lines_motd	= 0;
Xint	lines_nologin	= 0;
Xint	info_nolog	= FALSE;
Xint	is_hushlogin;
Xint	have_display	= TRUE;
X
Xextern char	*getenv();
X
Xextern int	errno;
Xextern int	lseek(), exit();
X
Xstatic void		ExitMotd();
X
XXtAppContext		app_ctxt;
XDisplay			*gDisplay;
XString			display;
XWidget			toplevel;
X
XXrmOptionDescRec	pre_options[] = {
X	{"-debug",	"*debug",	XrmoptionNoArg,		"True"},
X	{"-display",	"*display",	XrmoptionSepArg,	""},
X	{"-logout",	".logout",	XrmoptionNoArg,		"True"},
X	{"-timeOutAction",".timeOutAction",XrmoptionSepArg,	"logout"},
X	{"-version",	".versionOnly",	XrmoptionNoArg,		"True"}
X	};
XXrmOptionDescRec	options[] = {
X	{"-lines",	"lines",		XrmoptionSepArg,NULL},
X	{"-showMOTD",	"showMOTD",		XrmoptionSepArg,NULL},
X	{"-showVersion","showVersion",		XrmoptionNoArg,	"True"},
X	{"-motdFont",	"motdFont",		XrmoptionSepArg,NULL}
X	};
X
Xtypedef struct {
X	int		lines;
X	Boolean		show_version;
X	char		*show_MOTD;
X	XFontStruct	*motd_font;
X} xlog_resourceRec, *xlog_resourcePtr; 
X
Xtypedef struct {
X	Boolean		debug;
X	String		display;
X	Boolean		logout;
X	Boolean		time_out_exit;
X	Boolean		version_only;
X} xlog_preresourceRec;
X
Xxlog_resourceRec		app_resources;
Xxlog_preresourceRec		pre_app_resources;
XXtResource		resources[] = {
X	{"lines",	"Lines", XtRInt,	sizeof(int),
X		XtOffset(xlog_resourcePtr, lines), XtRString, "0"},
X	{"showMOTD",	"ShowMOTD", XtRString,	sizeof(String),
X		XtOffset(xlog_resourcePtr, show_MOTD), XtRString, (caddr_t) "IfChanged"},
X	{"showVersion",	"ShowVersion", XtRBoolean,	sizeof(Boolean),
X		XtOffset(xlog_resourcePtr, show_version), XtRImmediate, (caddr_t)False},
X	{"motdFont",	XtCFont, XtRFontStruct,	sizeof(XFontStruct *),
X		XtOffset(xlog_resourcePtr, motd_font), XtRString,
X		"-misc-fixed-medium-r-normal--*-120-*-*-c-*-iso8859-1"}
X	};
XXtCallbackRec		callbacks[] =
X				{ {ExitMotd, NULL}, {NULL, NULL} };
X
X
X
XDebug (fmt, arg1, arg2, arg3, arg4, arg5)
Xchar	*fmt;
Xint	arg1, arg2, arg3, arg4, arg5;
X{
X	if (pre_app_resources.debug) {
X		fprintf(stderr,"Debug: ");
X		fprintf (stderr,fmt, arg1, arg2, arg3, arg4, arg5);
X		fprintf(stderr,"\n");
X		fflush(stderr);
X	}
X}
X
X						 
X/*
X * This routine is called before exit; it closes the display
X * and frees all resources
X */
Xvoid CloseXDisplay()
X{
X	Debug("Closing X Display");
X	XtDestroyWidget(toplevel);
X	XtDestroyApplicationContext(app_ctxt);
X}
X
X
X/*
X * This is the routine that is called on press of the
X * endbutton; exits program with status 0, if login permitted,
X * with status 1 otherwise
X */
Xstatic void ExitMotd()
X{
X	CloseXDisplay();
X	Debug("ExitMotd(): status=%d ", !do_login);
X	exit(!do_login);
X}
X
X
X/*
X * This is the routine that's called when the timeout has
X * expired.
X */
X
Xstatic void motdTimeOver(c_data, id)
X	XtPointer	c_data;
X	XtIntervalId	*id;
X{
X	Debug("Timeout has expired");
X	do_login = !pre_app_resources.time_out_exit;
X	ExitMotd();
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	char	*number, *tmp;
X	int	home_len;
X
X	Debug("Init()");
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	Debug("Init(): user=%s ", user);
X	/*
X	 * get the display from the environment,
X	 * if we hadn't it yet from the options
X	 */
X	if (pre_app_resources.display == (String) NULL) {
X		if ((display = getenv("DISPLAY")) == NULL) {
X			fprintf(stderr,"%s: cannot getenv(\"DISPLAY\") \n",
X				Myname);
X			exit(1);
X		}
X	} else	display = pre_app_resources.display;
X	Debug("Init(): display=%s ", display);
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	Debug("Init(): home=%s ", home);
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", Myname);
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", Myname);
X		exit(1);
X	}
X	if (home_len + strlen(XLogFile) > MAXLEN) {
X		fprintf(stderr, "%s: pathname length overflow \n", Myname);
X		exit(1);
X	}
X	strncat(HushLogin, HushLog, MAXLEN-strlen(HushLogin));
X	strncat(XLogin, XLogFile, MAXLEN-strlen(XLogFile));
X
X	/*
X	 * set up XTTYname from display information
X	 */
X	STRCPY(dpyname, display);
X	if (number = index(dpyname, ':')) {
X		*number++ = '\0';
X		if (tmp = index(dpyname, '.')) *tmp = '\0';
X		gethostname(hostname, sizeof(hostname));
X		if (tmp = index(hostname, '.')) *tmp = '\0';
X		if (strcmp(dpyname, hostname) == 0 ||
X		    strcmp(dpyname, "localhost") == 0 ||
X		    strcmp(dpyname, "unix") == 0 ||
X		    strcmp(dpyname, "") == 0 ) {
X			if (tmp = index(number, '.')) *tmp = '\0';
X			STRCPY(XTTYname, "X");
X			strncat(XTTYname, number,
X				sizeof(XTTYname)-strlen(XTTYname));
X		}
X		else
X			STRCPY(XTTYname, dpyname);
X	}
X	else
X		STRCPY(XTTYname, "Xlogin");
X
X	if (*display == ':') {
X#ifdef HOSTNAME
X		STRCPY(dpyname, hostname);
X		strncat(dpyname, display, sizeof(dpyname)-strlen(dpyname));
X#else
X		*dpyname = '\0';
X#endif
X	} else {
X		STRCPY(dpyname, display);
X	}
X
X	Debug("Init(): XTTYName=%s, display=%s ", XTTYname, dpyname);
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, dpyname);
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	int		c;
X	FILE		*fp;
X
X	Debug("CheckNologin()");
X	if (access(NoLogin, F_OK) == 0) {
X		Debug("CheckNologin(): file %s found. ", NoLogin);
X		/*
X		 * deny login only, if user not root
X		 */
X		do_login = FALSE | (pwd->pw_uid == 0);
X		info_nolog = TRUE;
X		/*
X		 * count lines in nologin to determine size of Text widget
X		 */
X		lines_nologin = 0;
X		if ((fp=fopen(NoLogin, "r")) == NULL) {
X			return;
X		}
X
X		while ((c = getc(fp)) != EOF)
X			if (c == '\n')
X				++lines_nologin;
X		fclose(fp);
X		Debug("CheckNologin(): %s has %d lines. ", NoLogin, lines_nologin);
X	} else {
X		Debug("CheckNologin(): file %s not found. ", NoLogin);
X	}	
X}
X
X
X#ifdef QUOTA
X/*
X * deny login because of bad quota ?
X */
Xvoid CheckQuota()
X{
X	int	retcode;
X
X	Debug("CheckQuota()");
X	Debug("CheckQuota(): userid=%d ", pwd->pw_uid);
X	errno = 0;
X	quota(Q_SETUID, 0, 0, (caddr_t) 0);
X	if ((retcode=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	Debug("CheckQuota(): quota returned %d, errno=%d", retcode, errno);
X}
X#endif
X
X
X
X/*
X * check if motd file exists and whether it is newer than
X * the lastlogin-time or if that is 0, if it is newer than
X * a possibly existing file $HOME/.Xlogin
X * Then check it with the "showMOTD" resource
X */
Xvoid CheckMotd()
X{
X	struct stat	buf1, buf2;
X	int		c;
X	FILE		*fp;
X
X	info_motd	= TRUE;
X	lines_motd	= 0;
X
X	Debug("CheckMotd()");
X	if (stat(Motd, &buf1) != 0) {
X		info_motd = FALSE;
X		Debug("CheckMotd(): No %s file found", Motd);
X		return;
X	} else {
X		/*
X		 * count lines in motd to determine size of Text widget
X		 */
X		if ((fp=fopen(Motd, "r")) == NULL) {
X			Debug("CheckMotd(): %s is unreadable", Motd);
X			info_motd = FALSE;
X			return;
X		}
X		while ((c = getc(fp)) != EOF)
X			if (c == '\n')
X				++lines_motd;
X		fclose(fp);
X
X		Debug("CheckMotd(): %s has %d lines.", Motd, lines_motd);
X	}
X
X#ifdef LASTLOGIN
X	if (rll.ll_time != 0) {
X		Debug("CheckMotd(): lastlogin time found");
X		info_motd = (rll.ll_time < buf1.st_mtime);
X	} else
X#endif /* LASTLOGIN */
X	{
X		if (stat(XLogin, &buf2) == 0) {
X			Debug("CheckMotd(): file %s found", XLogin);
X			utime(XLogin, NULL);
X			info_motd = (buf2.st_mtime < buf1.st_mtime);
X		} else {
X			Debug("CheckMotd(): no %s file found", XLogin);
X			info_motd = TRUE;
X		}
X	}
X
X}
X
X
X
X/*
X * Return the number of the slot in the utmp file
X * Definition is the line number in the /etc/ttys file.
X */
X#ifndef sequent
Xint xttyslot()
X{
X	register struct ttyent *ty;
X	register int s;
X
X	setttyent();
X	s = 0;
X	while ((ty = getttyent()) != NULL) {
X		s++;
X		if (strcmp(ty->ty_name, XTTYname) == 0) {
X			endttyent();
X			return (s);
X		}
X	}
X	endttyent();
X	return (0);
X}
X#else
Xchar	*getttys();
Xstatic	char	ttys[]	= "/etc/ttys";
Xstatic	char	*_b, *_p;
Xstatic	int	_c;
Xint xttyslot()
X{
X	register int s, tf;
X	register char *tp;
X	char b[1024];
X
X	if ((tf = open(ttys, 0)) < 0)
X		return(0);
X	_p = _b = b;
X	_c = 0;
X	s = 0;
X	while (tp = getttys(tf)) {
X		s++;
X		if (strcmp(XTTYname, tp)==0) {
X			close(tf);
X			return(s);
X		}
X	}
X	close(tf);
X	return(0);
X}
X
Xstatic char *
Xgetttys(f) {
X	static char line[32];
X	register char *lp;
X
X	lp = line;
X	for (;;) {
X		if (--_c < 0)
X			if ((_c = read(f, _p = _b, 1024)) <= 0)
X				return(NULL);
X			else
X				--_c;
X		*lp = *_p++;
X		if (*lp =='\n') {
X			*lp = '\0';
X			return(line + 2);
X		}
X		if (lp >= &line[sizeof line])
X			return(line + 2);
X		lp++;
X	}
X}
X#endif
X
X
X
X/*
X * this procedure writes the wtmp entry
X */
Xvoid WriteWtmp()
X{
X
X	struct stat	buf;
X	int		wtmpfd, utmpfd;
X	int		xtty;
X
X	Debug("WriteWtmp()");
X	xtty = xttyslot();
X	Debug("WriteWtmp(): xttyslot=%d", xtty);
X	if (xtty > 0 && (utmpfd = open(Utmp, O_WRONLY)) >= 0) {
X		Debug("WriteWtmp(): reading utmp file");
X		lseek(utmpfd, (long)(xtty*sizeof(wtmp)), 0);
X		write(utmpfd, (char *)&wtmp, sizeof(wtmp));
X		close(utmpfd);
X		if (strcmp(wtmp.ut_name, EMPTY) != 0) {
X			STRCPY(DEVname, "/dev/");
X			strncat(DEVname, XTTYname,
X				sizeof(DEVname)-strlen(DEVname));
X			if (stat(DEVname, &buf) == 0) {
X				Debug("WriteWtmp(): uptiming %s", DEVname);
X				utime(DEVname, NULL);
X			}
X		}
X	}
X	/*
X	 * write only if file exists, don't create it
X	 */
X	if ((wtmpfd = open(Wtmp, O_WRONLY|O_APPEND)) >= 0) {
X		Debug("WriteWtmp(): writing wtmp file");
X		write(wtmpfd, (char *) &wtmp, sizeof(wtmp));
X		close(wtmpfd);
X	}
X	Debug("WriteWtmp(): leaving ...");
X}
X
X
X
X#ifdef LASTLOGIN
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	wll;
X	int		llfd;		/* Lastlog file descriptor */
X
X	Debug("DoLastLogin()");
X	rll.ll_time = 0;
X	STRCPY(lastltime, "Last Login: ");
X	if ((llfd = open(Lastlog, O_RDONLY)) >= 0) {
X		/*
X		 *  get time of last login, if any
X		 */
X		Debug("DoLastLogin(): reading lastlog file");
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				strncat(lastltime, rll.ll_host, 16);
X			}
X			info_lastlog = !is_hushlogin;
X		}
X		close(llfd);
X		/*
X		 * write new last login time
X		 */
X		if ((llfd = open(Lastlog, O_WRONLY)) >= 0) {
X			Debug("DoLastLogin(): writing lastlog file");
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	Debug("DoLastLogin(): leaving ...");
X}
X#endif /* LASTLOGIN */
X
X
X/*
X * in this procedure I do a kind of a prescan of some commandline options,
X * to avoid connecting to the X server, if not necessary at all.
X */
XLoadPreResources(argc, argv)
X	int	*argc;
X	char	*argv[];
X#define	RESLEN		255
X{
X	char			*str_type;
X	XrmValue		xrm_value;
X	XrmDatabase		PreResDB;
X	char			res[RESLEN];
X
X	XrmInitialize();
X	/*
X	 * Need an empty database; that's a good trick
X	 */
X	PreResDB = XrmGetStringDatabase("");
X
X	XrmParseCommand(&PreResDB, pre_options, XtNumber(pre_options),
X		XLOGIN_NAME, argc, argv);
X	
X	STRCPY(res, XLOGIN_NAME); strncat(res, ".debug", RESLEN-strlen(res));
X	if (XrmGetResource(PreResDB, res, "", &str_type, &xrm_value)) {
X		pre_app_resources.debug =
X			(XmuCompareISOLatin1(xrm_value.addr, "true") == 0);
X	} else	pre_app_resources.debug = False;
X
X	STRCPY(res, XLOGIN_NAME); strncat(res, ".display", RESLEN-strlen(res));
X	if (XrmGetResource(PreResDB, res, "", &str_type, &xrm_value)) {
X		pre_app_resources.display = XtNewString(xrm_value.addr);
X	} else	pre_app_resources.display = (String) NULL;
X
X	STRCPY(res, XLOGIN_NAME); strncat(res, ".logout", RESLEN-strlen(res));
X	if (XrmGetResource(PreResDB, res, "", &str_type, &xrm_value)) {
X		pre_app_resources.logout =
X			(XmuCompareISOLatin1(xrm_value.addr, "true") ==0);
X	} else	pre_app_resources.logout = False;
X
X	STRCPY(res, XLOGIN_NAME); strncat(res, ".timeOutAction", RESLEN-strlen(res));
X	if (XrmGetResource(PreResDB, res, "", &str_type, &xrm_value)) {
X		pre_app_resources.time_out_exit =
X			(XmuCompareISOLatin1(xrm_value.addr, "logout") == 0);
X				/* set to True equiv. to logout */
X	} else	pre_app_resources.time_out_exit = True;
X
X	STRCPY(res, XLOGIN_NAME); strncat(res, ".versionOnly", RESLEN-strlen(res));
X	if (XrmGetResource(PreResDB, res, "", &str_type, &xrm_value)) {
X		pre_app_resources.version_only =
X			(XmuCompareISOLatin1(xrm_value.addr, "true") ==0);
X	} else	pre_app_resources.version_only = False;
X
X
X	XrmDestroyDatabase(PreResDB);
X	Debug("LoadPreResources(): display=%s", pre_app_resources.display);
X	Debug("LoadPreResources(): logout=%d", pre_app_resources.logout);
X	Debug("LoadPreResources(): timeOutAction=%d", pre_app_resources.time_out_exit);
X	Debug("LoadPreResources(): versionOnly=%d", pre_app_resources.version_only);
X	Debug("LoadPreResources(): leaving ...");
X}
X
X
X/*
X * this procedure initializes the display and parses
X * the command line options
X */
Xvoid InitXDisplay(argc, argv)
X	int	*argc;
X	char	*argv[];
X{
X	Debug("InitXDisplay()");
X	Debug("InitXDisplay(): argc=%d", *argc);
X	XtToolkitInitialize();
X	app_ctxt = XtCreateApplicationContext();
X	gDisplay = XtOpenDisplay(app_ctxt, display, XLOGIN_NAME, XLOGIN_CLASS,
X		options, XtNumber(options), argc, argv);
X	if (gDisplay == (Display *) NULL) {
X		fprintf(stderr, "%s: WARNING! Cannot open display \"%s\" \n",
X			Myname, display);
X		XtDestroyApplicationContext(app_ctxt);
X		have_display = FALSE;
X		return;
X	}
X	toplevel = XtAppCreateShell(XLOGIN_NAME, XLOGIN_CLASS,
X		applicationShellWidgetClass, gDisplay, NULL, 0);
X	XtGetApplicationResources(toplevel, &app_resources, resources,
X		XtNumber(resources), NULL, 0);
X	Debug("InitXDisplay(): showVersion=%d",app_resources.show_version);
X}
X
X
X/*
X * this procedure does all the display stuff:
X *   defining, creating and starting widgets
X */
Xvoid DoXDisplay()
X{
X#define LABELLEN	255
X	Widget		form, endbutton, logininfo, motd, version_w,
X			quota_w, motd_label;
X	Widget		queue;
X	Arg		args[20];
X	Dimension	width, motd_height, nolog_height,
X			formwidth, formheight,
X			fnt_width, fnt_height;
X	Position	dpywidth, dpyheight;
X	char		motd_label_text[LABELLEN],
X			nolog_info_text[LABELLEN],
X			nolog_label_text[LABELLEN];
X	int		timeout_mult;
X	static Arg label_args[] = {
X		{XtNresize,		(XtArgVal) True},
X		{XtNjustify,		(XtArgVal) XtJustifyCenter},
X		{XtNborderWidth,	(XtArgVal) 0},
X		{XtNwidth,		(XtArgVal) 0},
X		{XtNfromVert,		(XtArgVal) NULL},
X		{XtNlabel,		(XtArgVal) NULL}
X		};
X
X	static Arg text_args[] = {
X		{XtNstring,		(XtArgVal) NULL},
X		{XtNfromVert,		(XtArgVal) NULL},
X		{XtNwidth,		(XtArgVal) 0},
X		{XtNheight,		(XtArgVal) 0},
X		{XtNfont,		(XtArgVal) NULL},
X		{XtNscrollHorizontal,	(XtArgVal) XawtextScrollWhenNeeded},
X		{XtNscrollVertical,	(XtArgVal) XawtextScrollWhenNeeded},
X		{XtNeditType,		(XtArgVal) XawtextRead},
X		{XtNtype,		(XtArgVal) XawAsciiFile},
X		{XtNdisplayCaret,	(XtArgVal) False}
X		};
X
X	Debug("DoXDisplay()");
X
X	timeout_mult = 0;
X	motd = (Widget) NULL;
X
X	XtSetArg(args[0], XtNresizable, True);
X	XtSetArg(args[1], XtNresize, True);
X	form = XtCreateManagedWidget("form", formWidgetClass, toplevel,
X		(ArgList) args, 2);
X
X	XtSetArg(args[0], XtNresize,		True);
X	XtSetArg(args[1], XtNallowShellResize,	True);
X	XtSetValues(toplevel, args, 2);
X
X	/* find the max width and height of the font */
X
X	fnt_width = app_resources.motd_font->max_bounds.width;
X	fnt_height = app_resources.motd_font->ascent + app_resources.motd_font->descent;
X	Debug("DoXDisplay(): Fontinfo: width=%d, height=%d", fnt_width, fnt_height);
X
X	/*
X	 * plan for 80 columns and match the number of lines in motd
X	 * allow for default border width of 1 at both edges
X	 * allow 1 line for sometimes wrong font infos
X	 * add 20 pxl to width for scrollbar if lines_motd > app_resources.lines
X	 */
X	Debug("DoXDisplay(): lines set from resources=%d", app_resources.lines);
X	if ((app_resources.lines == 0) | (app_resources.lines > lines_motd+1))
X		motd_height = fnt_height * (lines_motd + 1);
X	else	motd_height = fnt_height * (app_resources.lines + 1);
X	if ((app_resources.lines == 0) | (app_resources.lines > lines_nologin+1))
X		nolog_height = fnt_height * (lines_nologin + 1);
X	else	nolog_height = fnt_height * (app_resources.lines + 1);
X	width = fnt_width * 80 + 2;
X	label_args[3].value = (XtArgVal) width;
X
X	text_args[2].value = (XtArgVal) width;
X	text_args[4].value = (XtArgVal) app_resources.motd_font;
X	queue = (Widget) NULL;
X
X	if (app_resources.show_version) {
X		label_args[5].value = (XtArgVal) versionname;
X		queue=version_w = XtCreateManagedWidget("version", labelWidgetClass,
X				form, label_args, XtNumber(label_args));
X	}
X	label_args[4].value = (XtArgVal) queue;
X#ifdef LASTLOGIN
X	if (info_lastlog) {
X		label_args[5].value = (XtArgVal) lastltime;
X	} else
X#endif /* LASTLOGIN */
X		if (do_login) {
X			STRCPY(nolog_info_text,
X				"No information available on time of last login");
X			label_args[5].value = (XtArgVal) nolog_info_text;
X		} else {
X			STRCPY(nolog_info_text,
X				"Sorry, no login permitted");
X			label_args[5].value = (XtArgVal) nolog_info_text;
X		}
X	queue=logininfo = XtCreateManagedWidget("loginInfo", labelWidgetClass,
X				form, label_args, XtNumber(label_args));
X
X	if (do_login | info_nolog) {
X		if (info_motd) {
X			STRCPY(motd_label_text,"Message Of The Day follows:");
X			label_args[5].value = (XtArgVal) motd_label_text;
X		} else 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			label_args[5].value = (XtArgVal) nolog_label_text;
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			label_args[5].value = (XtArgVal) motd_label_text;
X		}
X
X		label_args[4].value = (XtArgVal) queue;
X		queue=motd_label = XtCreateManagedWidget("motdLabel", labelWidgetClass,
X				form, (ArgList) label_args, 6);
X	}
X
X#ifdef QUOTA
X	if (info_eusers | info_eproclim) {
X		if (info_eproclim) {
X			label_args[5].value = (XtArgVal) 
X				"You have too many processes running.";
X		} else {
X			label_args[5].value = (XtArgVal) 
X				"Too many users already logged in. Try again later";
X		}
X		label_args[4].value = (XtArgVal) queue;
X		queue=quota_w = XtCreateManagedWidget("quotaInfo", labelWidgetClass,
X					form, (ArgList) label_args, 6);
X	}
X
X#endif /* QUOTA */
X
X	if (info_nolog) {
X		timeout_mult = lines_nologin;
X		XtSetArg(text_args[0], XtNstring, NoLogin);
X		XtSetArg(text_args[1], XtNfromVert, queue);
X		XtSetArg(text_args[3], XtNheight, nolog_height);
X		queue=motd = XtCreateManagedWidget("motd", asciiTextWidgetClass,
X				form, (ArgList) text_args, XtNumber(text_args));
X		Debug("Uninstalling Translations for motd widget ...");
X		XtUninstallTranslations(motd);
X	} else {
X		if (info_motd) {
X			timeout_mult = lines_motd;
X			XtSetArg(text_args[0], XtNstring, Motd);
X			XtSetArg(text_args[1], XtNfromVert, queue);
X			XtSetArg(text_args[3], XtNheight, motd_height);
X			queue=motd = XtCreateManagedWidget("motd", asciiTextWidgetClass,
X					form, (ArgList) text_args, XtNumber(text_args));
X			Debug("Uninstalling Translations for motd widget ...");
X			XtUninstallTranslations(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, 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 = XtCreateManagedWidget("endbutton", commandWidgetClass,
X			form, (ArgList) args, 11);
X
X	Debug("Installing Accelerators for form widget");
X	XtInstallAccelerators(form, 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	XtSetArg(args[0], XtNwidth,	&formwidth);
X	XtSetArg(args[1], XtNheight,	&formheight);
X	XtGetValues(form, args, 2);
X
X	/*
X	 * Place the window centered on the screen.
X	 * allow 5 pixels distance to top and bottom
X	 */
X	if ((dpyheight < formheight) && (motd != NULL)) {
X		int		dpy_offest = 5;
X		Dimension	motd_width;
X
X		Debug("DoXDisplay(): New layout for motd ...");
X
X		dpyheight -= 2*dpy_offest;
X		Debug("DoXDislay(): motd_height was %d", motd_height);
X		XtSetArg(args[0], XtNheight,	&motd_height);
X		XtSetArg(args[1], XtNwidth,	&motd_width);
X		XtGetValues(motd, args, 2);
X
X		motd_height -= (formheight - dpyheight);
X		/*
X		 * set new height of motd-widget and allow
X		 * 20 pixels for scrollbar
X		 */
X		XtSetArg(args[0], XtNheight,	motd_height);
X		XtSetArg(args[1], XtNwidth,	motd_width + 20);
X		XtSetValues(motd, args, 2);
X
X		XtSetArg(args[0], XtNheight,	dpyheight);
X		XtSetValues(form, args, 1);
X
X		XawFormDoLayout(form, True);
X
X		XtMoveWidget(toplevel, (Position) (dpywidth-formwidth)/2,
X				(Position) dpy_offest);
X	} else {
X		XtMoveWidget(toplevel, (Position) (dpywidth-formwidth)/2,
X				(Position) (dpyheight-formheight)/2);
X	}
X
X	/*
X	 * Now map the window to get it visible
X	 */
X	XtSetMappedWhenManaged(toplevel, True);
X	XtMapWidget(toplevel);
X	/*
X	 * Warp the pointer into the button-click window
X	 */
X	XWarpPointer(XtDisplay(toplevel), (Window) NULL, XtWindow(endbutton),
X		0, 0, 0, 0, width/2, 3);
X	Debug("DoXDisplay(): timeout multiplicator=%d", timeout_mult);
X
X	/*
X	 * add timeout, so user get's kicked off, if he's not
X	 * behind the the display
X	 */
X	if (!info_motd || pre_app_resources.time_out_exit) {
X		XtAppAddTimeOut(app_ctxt,
X			(unsigned long) (timeout_mult+30)*1000, 
X			motdTimeOver, (XtPointer) NULL);
X		Debug("DoXDisplay(): TimeOut added.");
X	}
X	Debug("DoXDisplay(): starting XtAppMainLoop()");
X	XtAppMainLoop(app_ctxt);
X}
X
X
X
Xmain(argc, argv)
X	int	argc;
X	char	*argv[];
X{
X	STRCPY(Myname, argv[0]);
X	MyRevision[0] = ' ';
X	MyRevision[strlen(MyRevision)-1] = '\0';
X
X	sprintf(versionname,"%s- version %s patchlevel %d \0",
X		MyRevision, MyVersion, PATCHLEVEL);
X
X	LoadPreResources(&argc, argv);
X	if (pre_app_resources.version_only) {
X		fprintf(stderr,"%s:%s \n", Myname, versionname);
X		exit(1);
X	}
X
X	do_logout = pre_app_resources.logout;
X
X	if ((argc > 1) && do_logout) {
X		fprintf(stderr,"%s: unknown option %s \n", Myname,
X			argv[1]);
X		exit(1);
X	}
X
X	Init();
X	Debug("main(): after Init()");
X
X	if (do_logout) {
X		Debug("main(): logging out ...");
X		STRCPY(wtmp.ut_name, EMPTY);
X		WriteWtmp();
X		exit(0);
X	}
X
X	InitXDisplay(&argc, argv);
X	Debug("main(): after InitXDisplay()");
X
X	if ((argc > 1) & have_display) {
X		fprintf(stderr,"%s: unknown option %s \n", Myname,
X			argv[1]);
X		CloseXDisplay();
X		exit(1);
X		}
X	do_login  = !do_logout;
X
X	CheckNologin();
X#ifdef QUOTA
X	CheckQuota();
X#endif
X
X	if (do_login) {
X		WriteWtmp();
X#ifdef LASTLOGIN
X		DoLastLogin();
X#endif /* LASTLOGIN */
X		CheckMotd();
X	}
X
X	if (have_display) {
X		Debug("main(): showMOTD=%s", app_resources.show_MOTD);
X		info_motd |= (XmuCompareISOLatin1(app_resources.show_MOTD,
X				"always") == 0);
X	}
X	/*
X
X	 * display motd only if no .hushlogin exists
X	 * and /etc/motd has more than 0 lines!
X	 */
X	info_motd = info_motd && !is_hushlogin && (lines_motd != 0);
X
X	info_atall = info_lastlog | info_motd | info_eusers
X			| info_eproclim | info_nolog;
X
X
X	if (info_atall & have_display) {
X		DoXDisplay();
X	}
X}
SHAR_EOF
$TOUCH -am 0709154290 xlogin.c &&
chmod 0644 xlogin.c ||
echo "restore of xlogin.c failed"
set `wc -c xlogin.c`;Wc_c=$1
if test "$Wc_c" != "27614"; then
	echo original size 27614, current size $Wc_c
fi
# ============= patchlevel.h ==============
echo "x - extracting patchlevel.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > patchlevel.h &&
X#define PATCHLEVEL	0
SHAR_EOF
$TOUCH -am 0421000390 patchlevel.h &&
chmod 0664 patchlevel.h ||
echo "restore of patchlevel.h failed"
set `wc -c patchlevel.h`;Wc_c=$1
if test "$Wc_c" != "21"; then
	echo original size 21, current size $Wc_c
fi
# ============= Xlogin.ad ==============
echo "x - extracting Xlogin.ad (Text)"
sed 's/^X//' << 'SHAR_EOF' > Xlogin.ad &&
X!
X! $Id: Xlogin.ad,v 1.1 90/07/09 15:44:52 stumpf Exp Locker: stumpf $
X!
X
XXlogin*loginInfo*font:	-adobe-times-medium-r-normal--*-180-*-*-p-*-iso8859-1
XXlogin*motdLabel*font:	-b&h-lucida-bold-i-normal-sans--*-140-*-*-p-*-iso8859-1
XXlogin*motdFont:	-misc-fixed-medium-r-normal--*-120-*-*-c-*-iso8859-1
XXlogin*showMOTD:	IfChanged
XXlogin*Accelerators:	#override\n\
X	<Btn1Down>:	set() notify()	\n\
X	<Btn2Down>:	set() notify()	\n\
X	<Btn3Down>:	set() notify()	\n\
X	<Key>0x20:	set() notify()	\n\
X	<Key>Return:	set() notify()	\n\
X	<Key>F1:	set() notify()
XXlogin*Command*Translations:	#override\n\
X	<Btn1Down>:	set() notify()	\n\
X	<Btn2Down>:	set() notify()	\n\
X	<Btn3Down>:	set() notify()	\n\
X	<Key>0x20:	set() notify()	\n\
X	<Key>Return:	set() notify()	\n\
X	<Key>F1:	set() notify()
X!
X! NOTE: this ifdef has no meaning unless this file is loaded
X!       with xrdb!
X!
X#ifdef COLOR
XXlogin*loginInfo*foreground:	DeepPink
XXlogin*motdLabel*foreground:	red
XXlogin*motd.background:		white
XXlogin*motd*Foreground:		maroon
XXlogin*Command*background:	lightcyan
XXlogin.Form.Background:		LemonChiffon
XXlogin*Label.Background:	LemonChiffon
X#endif
SHAR_EOF
$TOUCH -am 0709154590 Xlogin.ad &&
chmod 0644 Xlogin.ad ||
echo "restore of Xlogin.ad failed"
set `wc -c Xlogin.ad`;Wc_c=$1
if test "$Wc_c" != "1124"; then
	echo original size 1124, current size $Wc_c
fi
# ============= xlogin.man ==============
echo "x - extracting xlogin.man (Text)"
sed 's/^X//' << 'SHAR_EOF' > xlogin.man &&
X.TH XLOGIN 1 "5 July 1990" "X Version 11"
X.SH NAME
Xxlogin - login for X
X.SH SYNOPSIS
X.B "xlogin"
X[-debug]
X[-lines \fInum\fP]
X[-logout]
X[-motdFont \fIfont\fP]
X[-showMOTD Always|IfChanged]
X[-showVersion]
X[-timeOutAction login|logout]
X[-version]
X.SH SUMMARY
X.PP
XThe
X.I xlogin
Xutility provides most of the functionality of the \fIlogin(1)\fP program
Xthat is not provided by \fIxdm(1)\fP. It supports motd, wtmp, utmp,
Xlastlog, nologin and quota handling.
X.SH OPTIONS
X.PP
X.TP 8
X.B "-debug"
X(command line only) writes debugging information to stderr.
X.TP 8
X.B "-lines"
Xspecifies the number of lines of /etc/motd or /etc/nologin
Xthat are to be displayed.
X.TP 8
X.B "-logout"
X(command line only) only writes a logout entry to the wtmp file
X.TP 8
X.B "-motdFont"
Xspecifies the font to be used when displaying /etc/motd or /etc/nologin.
X.TP 8
X.B "-showMOTD"
X\fIAlways\fP causes /etc/motd to be displayed every time.
X\fIIfChanged\fP causes /etc/motd to be displayed only if something
Xchanged since your last login.
XThe default is \fIIfChanged\fP.
X.TP 8
X.B "-showVersion"
Xdisplays a line containing version-number, revision and patchlevel
Xin the window.
X.TP 8
X.B "-timeOutAction"
X(command line only) determines whether to \fIlogin\fP or \fIlogout\fP when the
Xtimeout has expired.
XThe default is \fIlogout\fP.
X.TP 8
X.B "-version"
X(command line only) displays version-number, revision and patchlevel. Nothing else is
Xperformed if this option is specified.
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 provides most of the functionality of the \fIlogin(1)\fP program
Xthat is not provided by \fIxdm(1)\fP.
X.ta \w'.\ \ 'u
X.br
X.PP
X\-	it checks whether the file /etc/nologin 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 utmp and wtmp
Xfile. If the file does not exist, none is created.
X.br
X.PP
X\-	if login is permitted, it writes an entry to /usr/adm/lastlog.
XIf the file does not exist, none 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 displayed in this case.
X.br
X.PP
X\-	if showMOTD (or the corresponding resource) is set to \fIIfChanged\fP,
Xxlogin compares the last login time against the last change time of /etc/motd.
X/etc/motd is displayed only if it has been changed since the last login.
XIf no last login file exists,
Xit checks whether a $HOME/.Xlogin file exists and compares its
Xlast change time against that of the /etc/motd file. Xlogin displays the
Xmotd if the motd is newer and then touches the .Xlogin file. If no .Xlogin
Xfile exists /etc/motd is displayed every time.
X.br
X.PP
XNormally, the user clicks a button after reading the message of the day.
XThe user is given 20 seconds plus 1 second per motd line to respond.
XIf the user does not respond, he is logged out.
XIf the \fItimeOutAction\fP is set to \fIlogin\fP the behavior is
Xdifferent:
Xif nothing is to be displayed (i.e. no /etc/motd or /etc/nologin) the user
Xis granted login automatically after 20 seconds. If there is something
Xto display \fIxlogin\fP waits for a button click before proceeding.
X.br
X.PP
XIf there is an entry for the X display in the /etc/ttys file,
Xxlogin will also write a record in utmp.  The ttyname is
Xderived from the display name.  If the display is local,
Xthe ttyname is "X" followed by the display number.  If
Xthe display is remote (i.e. an X terminal), then ttyname is
Xthe hostname of the display.  For example, the display name
X":0" maps to "X0", and the display name "ncd1.cs.wisc.edu:0"
Xmaps to "ncd1".
X.SH RETURN VALUE
X.PP
XIf login is permitted \fIxlogin\fP returns 0 otherwise 1
Xis returned.
X.SH ENVIRONMENT
X.PP
X.TP 8
X.B DISPLAY
XTo get the name of the display.
X.TP 8
X.B USER
XTo get the name of the user. (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 RESOURCES
X.PP
X.TP 8
X.B motdFont
XSpecifies which font to use when displaying /etc/motd or /etc/nologin.
X.TP 8
X.B showVersion (boolean)
XIf true, causes xlogin to display version-number, revision and patchlevel
Xas the first line in the window.
X.TP 8
X.B showMOTD
XCan have the values Always or IfChanged. See explanation for the corresponding
Xoption.
X.TP 8
X.B lines
XSpecified the number of lines of /etc/motd that should be displayed.
X.PP
X.SH EXAMPLES
X.PP
Xin the file Xstartup:
X.PP
X	/usr/bin/X11/xlogin
X.PP
X.PP
Xin the file Xreset:
X.PP
X	/usr/bin/X11/xlogin -logout
X.SH FILES
X.ta \w'/usr/adm/lastlog\ \ 'u
X/etc/utmp	login records
X.br
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.../lib/X11/app-defaults/Xlogin	system resource file
X.br
X\&.hushlogin	makes xlogin much quieter
X.br
X\&.Xlogin	makes xlogin a bit quieter
X.br
X\&.Xdefaults	users resource file
X.SH WINDOW
XTo display the contents of /etc/motd or /etc/nologin, a widget
Xthat is 80 characters wide is created.
XAll other messages are boxes up to 80 characters in width.
X.SH BUGS
XThe size of the motd window is based on the font metrics.
XHowever, the window is much too wide when using a proportionally spaced font.
X.SH SEE ALSO
XX(1), xdm(1), login(1)
X.SH COPYRIGHT
XCopyright 1989, 1990, Technische Universit\(aet M\(uenchen (TUM).
X.SH AUTHOR
XMarkus Stumpf, TU M\(uenchen
X  (stumpf at informatik.tu-muenchen.de)
X.SH CREDITS
XTim Theisen
X  (tim at cs.wisc.edu, ...!uwvax!tim)
SHAR_EOF
$TOUCH -am 0705214690 xlogin.man &&
chmod 0644 xlogin.man ||
echo "restore of xlogin.man failed"
set `wc -c xlogin.man`;Wc_c=$1
if test "$Wc_c" != "5798"; then
	echo original size 5798, current size $Wc_c
fi
exit 0

dan
----------------------------------------------------
O'Reilly && Associates   argv at sun.com / argv at ora.com
Opinions expressed reflect those of the author only.



More information about the Comp.sources.x mailing list