stumpf@lan.informatik.tu-muenchen.de (Markus Stumpf) (07/11/90)
Submitted-by: Markus Stumpf <stumpf@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@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@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@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@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@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@informatik.tu-muenchen.de) X.SH CREDITS XTim Theisen X (tim@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@sun.com / argv@ora.com Opinions expressed reflect those of the author only.