home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume8 / xlogin / part01 / xlogin.c < prev    next >
C/C++ Source or Header  |  1990-07-11  |  28KB  |  1,077 lines

  1. /*
  2.  * xlogin - X login manager
  3.  *
  4.  * $Id: xlogin.c,v 2.2 90/07/09 15:41:54 stumpf Exp Locker: stumpf $
  5.  *
  6.  * Copyright 1989, 1990 Technische Universitaet Muenchen (TUM), Germany
  7.  *
  8.  * Permission to use, copy, modify, and distribute this software and its
  9.  * documentation for any purpose and without fee is hereby granted, provided
  10.  * that the above copyright notice appear in all copies and that both that
  11.  * copyright notice and this permission notice appear in supporting
  12.  * documentation, and that the name of TUM not be used in advertising or
  13.  * publicity pertaining to distribution of the software without specific,
  14.  * written prior permission.  TUM makes no representations about the
  15.  * suitability of this software for any purpose.  It is provided "as is"
  16.  * without express or implied warranty.
  17.  *
  18.  *
  19.  * Author:  Markus Stumpf, Technische Universitaet Muenchen
  20.  *        (stumpf@lan.informatik.tu-muenchen.de)
  21.  *
  22.  * $Source: /usr/wiss/stumpf/src/X.V11R4/local/clients/xlogin/RCS/xlogin.c,v $
  23.  *
  24.  */
  25.  
  26. #include <sys/param.h>
  27. #ifdef QUOTA
  28. #include <sys/quota.h>
  29. #endif
  30. #include <sys/stat.h>
  31.  
  32. #include <errno.h>
  33. #ifdef LASTLOGIN
  34. #    include <lastlog.h>
  35. #endif /* LASTLOGIN */
  36. #include <pwd.h>
  37. #include <utmp.h>
  38. /* EMPTY is defined in most <utmp.h> */
  39. #ifndef EMPTY
  40. #    define EMPTY ""
  41. #endif
  42. #include <stdio.h>
  43. #ifndef sequent
  44. #    include <ttyent.h>
  45. #endif
  46.  
  47. #include <X11/Xos.h>
  48. #include <X11/StringDefs.h>
  49. #include <X11/Intrinsic.h>
  50. #include <X11/Shell.h>
  51. #include <X11/Xaw/Command.h>
  52. #include <X11/Xaw/Form.h>
  53. #include <X11/Xaw/AsciiText.h>
  54. #include <X11/Xmu/CharSet.h>
  55.  
  56. #include "patchlevel.h"
  57.  
  58. #define    XLOGIN_NAME    "xlogin"
  59. #define    XLOGIN_CLASS    "Xlogin"
  60.  
  61. #define MAXLEN    1024
  62.  
  63. #define STRCPY(a, b)    strncpy(a, b, sizeof(a))
  64.  
  65. struct passwd    *pwd;
  66. struct utmp    wtmp;
  67. #ifdef LASTLOGIN
  68.     struct lastlog    rll;
  69. #endif /* LASTLOGIN */
  70.  
  71. char    path_delimiter[]= "/";
  72. char    XTTYname[100];
  73. char    HushLog[]    = ".hushlogin";
  74. char    XLogFile[]    = ".Xlogin";
  75. char    HushLogin[MAXLEN];
  76. char    Lastlog[]    = "/usr/adm/lastlog";
  77. #ifndef UTMP_FILE
  78.     char    Utmp[]        = "/etc/utmp";
  79. #else
  80.     char    Utmp[]        = UTMP_FILE;
  81. #endif    /* UTMP_FILE */
  82. #ifndef WTMP_FILE
  83.     char    Wtmp[]        = "/usr/adm/wtmp";
  84. #else
  85.     char    Wtmp[]        = WTMP_FILE;
  86. #endif    /* WTMP_FILE */
  87. char    Motd[]        = "/etc/motd";
  88. char    NoLogin[]    = "/etc/nologin";
  89. char    lastltime[100];
  90. char    hostname[100];
  91. char    dpyname[100];
  92. char    versionname[100];
  93. char    Myname[255];
  94. char    MyRevision[]    = "$Revision: 2.2 $";
  95. char    MyVersion[]    = "2.0";
  96. char    DEVname[MAXLEN];
  97. char    XLogin[MAXLEN];
  98.  
  99. int    do_login    = TRUE;
  100. int    do_logout;
  101. int    info_atall;
  102. int    info_eproclim    = FALSE;
  103. int    info_eusers    = FALSE;
  104. int    info_lastlog    = FALSE;
  105. int    info_motd    = FALSE;
  106. int    lines_motd    = 0;
  107. int    lines_nologin    = 0;
  108. int    info_nolog    = FALSE;
  109. int    is_hushlogin;
  110. int    have_display    = TRUE;
  111.  
  112. extern char    *getenv();
  113.  
  114. extern int    errno;
  115. extern int    lseek(), exit();
  116.  
  117. static void        ExitMotd();
  118.  
  119. XtAppContext        app_ctxt;
  120. Display            *gDisplay;
  121. String            display;
  122. Widget            toplevel;
  123.  
  124. XrmOptionDescRec    pre_options[] = {
  125.     {"-debug",    "*debug",    XrmoptionNoArg,        "True"},
  126.     {"-display",    "*display",    XrmoptionSepArg,    ""},
  127.     {"-logout",    ".logout",    XrmoptionNoArg,        "True"},
  128.     {"-timeOutAction",".timeOutAction",XrmoptionSepArg,    "logout"},
  129.     {"-version",    ".versionOnly",    XrmoptionNoArg,        "True"}
  130.     };
  131. XrmOptionDescRec    options[] = {
  132.     {"-lines",    "lines",        XrmoptionSepArg,NULL},
  133.     {"-showMOTD",    "showMOTD",        XrmoptionSepArg,NULL},
  134.     {"-showVersion","showVersion",        XrmoptionNoArg,    "True"},
  135.     {"-motdFont",    "motdFont",        XrmoptionSepArg,NULL}
  136.     };
  137.  
  138. typedef struct {
  139.     int        lines;
  140.     Boolean        show_version;
  141.     char        *show_MOTD;
  142.     XFontStruct    *motd_font;
  143. } xlog_resourceRec, *xlog_resourcePtr; 
  144.  
  145. typedef struct {
  146.     Boolean        debug;
  147.     String        display;
  148.     Boolean        logout;
  149.     Boolean        time_out_exit;
  150.     Boolean        version_only;
  151. } xlog_preresourceRec;
  152.  
  153. xlog_resourceRec        app_resources;
  154. xlog_preresourceRec        pre_app_resources;
  155. XtResource        resources[] = {
  156.     {"lines",    "Lines", XtRInt,    sizeof(int),
  157.         XtOffset(xlog_resourcePtr, lines), XtRString, "0"},
  158.     {"showMOTD",    "ShowMOTD", XtRString,    sizeof(String),
  159.         XtOffset(xlog_resourcePtr, show_MOTD), XtRString, (caddr_t) "IfChanged"},
  160.     {"showVersion",    "ShowVersion", XtRBoolean,    sizeof(Boolean),
  161.         XtOffset(xlog_resourcePtr, show_version), XtRImmediate, (caddr_t)False},
  162.     {"motdFont",    XtCFont, XtRFontStruct,    sizeof(XFontStruct *),
  163.         XtOffset(xlog_resourcePtr, motd_font), XtRString,
  164.         "-misc-fixed-medium-r-normal--*-120-*-*-c-*-iso8859-1"}
  165.     };
  166. XtCallbackRec        callbacks[] =
  167.                 { {ExitMotd, NULL}, {NULL, NULL} };
  168.  
  169.  
  170.  
  171. Debug (fmt, arg1, arg2, arg3, arg4, arg5)
  172. char    *fmt;
  173. int    arg1, arg2, arg3, arg4, arg5;
  174. {
  175.     if (pre_app_resources.debug) {
  176.         fprintf(stderr,"Debug: ");
  177.         fprintf (stderr,fmt, arg1, arg2, arg3, arg4, arg5);
  178.         fprintf(stderr,"\n");
  179.         fflush(stderr);
  180.     }
  181. }
  182.  
  183.                          
  184. /*
  185.  * This routine is called before exit; it closes the display
  186.  * and frees all resources
  187.  */
  188. void CloseXDisplay()
  189. {
  190.     Debug("Closing X Display");
  191.     XtDestroyWidget(toplevel);
  192.     XtDestroyApplicationContext(app_ctxt);
  193. }
  194.  
  195.  
  196. /*
  197.  * This is the routine that is called on press of the
  198.  * endbutton; exits program with status 0, if login permitted,
  199.  * with status 1 otherwise
  200.  */
  201. static void ExitMotd()
  202. {
  203.     CloseXDisplay();
  204.     Debug("ExitMotd(): status=%d ", !do_login);
  205.     exit(!do_login);
  206. }
  207.  
  208.  
  209. /*
  210.  * This is the routine that's called when the timeout has
  211.  * expired.
  212.  */
  213.  
  214. static void motdTimeOver(c_data, id)
  215.     XtPointer    c_data;
  216.     XtIntervalId    *id;
  217. {
  218.     Debug("Timeout has expired");
  219.     do_login = !pre_app_resources.time_out_exit;
  220.     ExitMotd();
  221. }
  222.  
  223.  
  224. /*
  225.  * This procedure is called to initialize the passwd struct,
  226.  * the paths to the various files and the utmp struct.
  227.  */
  228. void Init()
  229. {
  230.     char    *user, *home;
  231.     char    *number, *tmp;
  232.     int    home_len;
  233.  
  234.     Debug("Init()");
  235.     /*
  236.      * get the user from the environment
  237.      */
  238.     if ((user = getenv("USER")) == NULL) {
  239.         fprintf(stderr,"%s: cannot getenv(\"USER\") \n", Myname);
  240.         exit(1);
  241.     }
  242.     Debug("Init(): user=%s ", user);
  243.     /*
  244.      * get the display from the environment,
  245.      * if we hadn't it yet from the options
  246.      */
  247.     if (pre_app_resources.display == (String) NULL) {
  248.         if ((display = getenv("DISPLAY")) == NULL) {
  249.             fprintf(stderr,"%s: cannot getenv(\"DISPLAY\") \n",
  250.                 Myname);
  251.             exit(1);
  252.         }
  253.     } else    display = pre_app_resources.display;
  254.     Debug("Init(): display=%s ", display);
  255.     /*
  256.      * get the passwd entry of the user
  257.      */
  258.     if ((pwd = getpwnam(user)) == NULL) {
  259.         endpwent();
  260.         fprintf(stderr,"%s: cannot getpwnam(%s) \n", Myname, user);
  261.         exit(1);
  262.     }
  263.     endpwent();
  264.     /*
  265.      * set the path to the users home directory
  266.      */
  267.     if ((home = getenv("HOME")) == NULL) {
  268.         home = pwd->pw_dir;
  269.     }
  270.     Debug("Init(): home=%s ", home);
  271.     /*
  272.      * build up the variables pointing to the files we want
  273.      * to use and check, whether we reserved enough space 
  274.      * otherwise exit
  275.      */
  276.     home_len = strlen(home) + 1;    /* pathname + delimiter */
  277.     if (home_len >= MAXLEN) {
  278.         fprintf(stderr, "%s: pathname length overflow \n", Myname);
  279.         exit(1);
  280.     }
  281.     STRCPY(HushLogin, home); strcat(HushLogin, path_delimiter);
  282.     STRCPY(XLogin, home); strcat(XLogin, path_delimiter);
  283.     if (home_len + strlen(HushLog) > MAXLEN) {
  284.         fprintf(stderr, "%s: pathname length overflow \n", Myname);
  285.         exit(1);
  286.     }
  287.     if (home_len + strlen(XLogFile) > MAXLEN) {
  288.         fprintf(stderr, "%s: pathname length overflow \n", Myname);
  289.         exit(1);
  290.     }
  291.     strncat(HushLogin, HushLog, MAXLEN-strlen(HushLogin));
  292.     strncat(XLogin, XLogFile, MAXLEN-strlen(XLogFile));
  293.  
  294.     /*
  295.      * set up XTTYname from display information
  296.      */
  297.     STRCPY(dpyname, display);
  298.     if (number = index(dpyname, ':')) {
  299.         *number++ = '\0';
  300.         if (tmp = index(dpyname, '.')) *tmp = '\0';
  301.         gethostname(hostname, sizeof(hostname));
  302.         if (tmp = index(hostname, '.')) *tmp = '\0';
  303.         if (strcmp(dpyname, hostname) == 0 ||
  304.             strcmp(dpyname, "localhost") == 0 ||
  305.             strcmp(dpyname, "unix") == 0 ||
  306.             strcmp(dpyname, "") == 0 ) {
  307.             if (tmp = index(number, '.')) *tmp = '\0';
  308.             STRCPY(XTTYname, "X");
  309.             strncat(XTTYname, number,
  310.                 sizeof(XTTYname)-strlen(XTTYname));
  311.         }
  312.         else
  313.             STRCPY(XTTYname, dpyname);
  314.     }
  315.     else
  316.         STRCPY(XTTYname, "Xlogin");
  317.  
  318.     if (*display == ':') {
  319. #ifdef HOSTNAME
  320.         STRCPY(dpyname, hostname);
  321.         strncat(dpyname, display, sizeof(dpyname)-strlen(dpyname));
  322. #else
  323.         *dpyname = '\0';
  324. #endif
  325.     } else {
  326.         STRCPY(dpyname, display);
  327.     }
  328.  
  329.     Debug("Init(): XTTYName=%s, display=%s ", XTTYname, dpyname);
  330.     /*
  331.      * set up the utmp struct for the wtmp file
  332.      */
  333.     STRCPY(wtmp.ut_name, pwd->pw_name);
  334.     STRCPY(wtmp.ut_host, dpyname);
  335.     STRCPY(wtmp.ut_line, XTTYname);
  336.     time((long *) &wtmp.ut_time);
  337.  
  338.     /*
  339.      * check if $HOME/.hushlogin exists and set the
  340.      * appropriate flag
  341.      */
  342.     is_hushlogin = (access(HushLogin, F_OK) == 0);
  343. }
  344.  
  345.  
  346.  
  347. /*
  348.  * this procedure checks, whether logins are permitted
  349.  * and sets the appropriate flags
  350.  */
  351. void CheckNologin()
  352. {
  353.     int        c;
  354.     FILE        *fp;
  355.  
  356.     Debug("CheckNologin()");
  357.     if (access(NoLogin, F_OK) == 0) {
  358.         Debug("CheckNologin(): file %s found. ", NoLogin);
  359.         /*
  360.          * deny login only, if user not root
  361.          */
  362.         do_login = FALSE | (pwd->pw_uid == 0);
  363.         info_nolog = TRUE;
  364.         /*
  365.          * count lines in nologin to determine size of Text widget
  366.          */
  367.         lines_nologin = 0;
  368.         if ((fp=fopen(NoLogin, "r")) == NULL) {
  369.             return;
  370.         }
  371.  
  372.         while ((c = getc(fp)) != EOF)
  373.             if (c == '\n')
  374.                 ++lines_nologin;
  375.         fclose(fp);
  376.         Debug("CheckNologin(): %s has %d lines. ", NoLogin, lines_nologin);
  377.     } else {
  378.         Debug("CheckNologin(): file %s not found. ", NoLogin);
  379.     }    
  380. }
  381.  
  382.  
  383. #ifdef QUOTA
  384. /*
  385.  * deny login because of bad quota ?
  386.  */
  387. void CheckQuota()
  388. {
  389.     int    retcode;
  390.  
  391.     Debug("CheckQuota()");
  392.     Debug("CheckQuota(): userid=%d ", pwd->pw_uid);
  393.     errno = 0;
  394.     quota(Q_SETUID, 0, 0, (caddr_t) 0);
  395.     if ((retcode=quota(Q_SETUID, pwd->pw_uid, 0, (caddr_t) 0) < 0)
  396.       && (errno != EINVAL)) {
  397.         if (errno == EUSERS) {
  398.             do_login = FALSE;
  399.             info_eusers = TRUE;
  400.         } else {
  401.             if (errno = EPROCLIM) {
  402.                 do_login = FALSE;
  403.                 info_eproclim = TRUE;
  404.             }
  405.         }
  406.     }
  407.     Debug("CheckQuota(): quota returned %d, errno=%d", retcode, errno);
  408. }
  409. #endif
  410.  
  411.  
  412.  
  413. /*
  414.  * check if motd file exists and whether it is newer than
  415.  * the lastlogin-time or if that is 0, if it is newer than
  416.  * a possibly existing file $HOME/.Xlogin
  417.  * Then check it with the "showMOTD" resource
  418.  */
  419. void CheckMotd()
  420. {
  421.     struct stat    buf1, buf2;
  422.     int        c;
  423.     FILE        *fp;
  424.  
  425.     info_motd    = TRUE;
  426.     lines_motd    = 0;
  427.  
  428.     Debug("CheckMotd()");
  429.     if (stat(Motd, &buf1) != 0) {
  430.         info_motd = FALSE;
  431.         Debug("CheckMotd(): No %s file found", Motd);
  432.         return;
  433.     } else {
  434.         /*
  435.          * count lines in motd to determine size of Text widget
  436.          */
  437.         if ((fp=fopen(Motd, "r")) == NULL) {
  438.             Debug("CheckMotd(): %s is unreadable", Motd);
  439.             info_motd = FALSE;
  440.             return;
  441.         }
  442.         while ((c = getc(fp)) != EOF)
  443.             if (c == '\n')
  444.                 ++lines_motd;
  445.         fclose(fp);
  446.  
  447.         Debug("CheckMotd(): %s has %d lines.", Motd, lines_motd);
  448.     }
  449.  
  450. #ifdef LASTLOGIN
  451.     if (rll.ll_time != 0) {
  452.         Debug("CheckMotd(): lastlogin time found");
  453.         info_motd = (rll.ll_time < buf1.st_mtime);
  454.     } else
  455. #endif /* LASTLOGIN */
  456.     {
  457.         if (stat(XLogin, &buf2) == 0) {
  458.             Debug("CheckMotd(): file %s found", XLogin);
  459.             utime(XLogin, NULL);
  460.             info_motd = (buf2.st_mtime < buf1.st_mtime);
  461.         } else {
  462.             Debug("CheckMotd(): no %s file found", XLogin);
  463.             info_motd = TRUE;
  464.         }
  465.     }
  466.  
  467. }
  468.  
  469.  
  470.  
  471. /*
  472.  * Return the number of the slot in the utmp file
  473.  * Definition is the line number in the /etc/ttys file.
  474.  */
  475. #ifndef sequent
  476. int xttyslot()
  477. {
  478.     register struct ttyent *ty;
  479.     register int s;
  480.  
  481.     setttyent();
  482.     s = 0;
  483.     while ((ty = getttyent()) != NULL) {
  484.         s++;
  485.         if (strcmp(ty->ty_name, XTTYname) == 0) {
  486.             endttyent();
  487.             return (s);
  488.         }
  489.     }
  490.     endttyent();
  491.     return (0);
  492. }
  493. #else
  494. char    *getttys();
  495. static    char    ttys[]    = "/etc/ttys";
  496. static    char    *_b, *_p;
  497. static    int    _c;
  498. int xttyslot()
  499. {
  500.     register int s, tf;
  501.     register char *tp;
  502.     char b[1024];
  503.  
  504.     if ((tf = open(ttys, 0)) < 0)
  505.         return(0);
  506.     _p = _b = b;
  507.     _c = 0;
  508.     s = 0;
  509.     while (tp = getttys(tf)) {
  510.         s++;
  511.         if (strcmp(XTTYname, tp)==0) {
  512.             close(tf);
  513.             return(s);
  514.         }
  515.     }
  516.     close(tf);
  517.     return(0);
  518. }
  519.  
  520. static char *
  521. getttys(f) {
  522.     static char line[32];
  523.     register char *lp;
  524.  
  525.     lp = line;
  526.     for (;;) {
  527.         if (--_c < 0)
  528.             if ((_c = read(f, _p = _b, 1024)) <= 0)
  529.                 return(NULL);
  530.             else
  531.                 --_c;
  532.         *lp = *_p++;
  533.         if (*lp =='\n') {
  534.             *lp = '\0';
  535.             return(line + 2);
  536.         }
  537.         if (lp >= &line[sizeof line])
  538.             return(line + 2);
  539.         lp++;
  540.     }
  541. }
  542. #endif
  543.  
  544.  
  545.  
  546. /*
  547.  * this procedure writes the wtmp entry
  548.  */
  549. void WriteWtmp()
  550. {
  551.  
  552.     struct stat    buf;
  553.     int        wtmpfd, utmpfd;
  554.     int        xtty;
  555.  
  556.     Debug("WriteWtmp()");
  557.     xtty = xttyslot();
  558.     Debug("WriteWtmp(): xttyslot=%d", xtty);
  559.     if (xtty > 0 && (utmpfd = open(Utmp, O_WRONLY)) >= 0) {
  560.         Debug("WriteWtmp(): reading utmp file");
  561.         lseek(utmpfd, (long)(xtty*sizeof(wtmp)), 0);
  562.         write(utmpfd, (char *)&wtmp, sizeof(wtmp));
  563.         close(utmpfd);
  564.         if (strcmp(wtmp.ut_name, EMPTY) != 0) {
  565.             STRCPY(DEVname, "/dev/");
  566.             strncat(DEVname, XTTYname,
  567.                 sizeof(DEVname)-strlen(DEVname));
  568.             if (stat(DEVname, &buf) == 0) {
  569.                 Debug("WriteWtmp(): uptiming %s", DEVname);
  570.                 utime(DEVname, NULL);
  571.             }
  572.         }
  573.     }
  574.     /*
  575.      * write only if file exists, don't create it
  576.      */
  577.     if ((wtmpfd = open(Wtmp, O_WRONLY|O_APPEND)) >= 0) {
  578.         Debug("WriteWtmp(): writing wtmp file");
  579.         write(wtmpfd, (char *) &wtmp, sizeof(wtmp));
  580.         close(wtmpfd);
  581.     }
  582.     Debug("WriteWtmp(): leaving ...");
  583. }
  584.  
  585.  
  586.  
  587. #ifdef LASTLOGIN
  588. /*
  589.  * this procedure reads from and writes to the
  590.  * lastlogin file. If none exists, it will not be created.
  591.  */
  592. void DoLastLogin()
  593. {
  594.     struct lastlog    wll;
  595.     int        llfd;        /* Lastlog file descriptor */
  596.  
  597.     Debug("DoLastLogin()");
  598.     rll.ll_time = 0;
  599.     STRCPY(lastltime, "Last Login: ");
  600.     if ((llfd = open(Lastlog, O_RDONLY)) >= 0) {
  601.         /*
  602.          *  get time of last login, if any
  603.          */
  604.         Debug("DoLastLogin(): reading lastlog file");
  605.         lseek(llfd, (long) pwd->pw_uid * sizeof(struct lastlog), 0);
  606.         if (read(llfd, (char *) &rll, sizeof(rll)) == sizeof(rll)
  607.         && (rll.ll_time != 0)) {
  608.             strncat(lastltime, ctime((long *) &rll.ll_time), 24);
  609.             if (strcmp(rll.ll_host, "") != 0) {
  610.                 strcat(lastltime, " from ");
  611.                 strncat(lastltime, rll.ll_host, 16);
  612.             }
  613.             info_lastlog = !is_hushlogin;
  614.         }
  615.         close(llfd);
  616.         /*
  617.          * write new last login time
  618.          */
  619.         if ((llfd = open(Lastlog, O_WRONLY)) >= 0) {
  620.             Debug("DoLastLogin(): writing lastlog file");
  621.             lseek(llfd, (long) pwd->pw_uid * sizeof(struct lastlog), 0);
  622.             wll.ll_time = wtmp.ut_time;
  623.             STRCPY(wll.ll_line, XTTYname);
  624.             STRCPY(wll.ll_host, wtmp.ut_host);
  625.             write(llfd, (char *) &wll, sizeof(wll));
  626.             close(llfd);
  627.         }
  628.     }
  629.     Debug("DoLastLogin(): leaving ...");
  630. }
  631. #endif /* LASTLOGIN */
  632.  
  633.  
  634. /*
  635.  * in this procedure I do a kind of a prescan of some commandline options,
  636.  * to avoid connecting to the X server, if not necessary at all.
  637.  */
  638. LoadPreResources(argc, argv)
  639.     int    *argc;
  640.     char    *argv[];
  641. #define    RESLEN        255
  642. {
  643.     char            *str_type;
  644.     XrmValue        xrm_value;
  645.     XrmDatabase        PreResDB;
  646.     char            res[RESLEN];
  647.  
  648.     XrmInitialize();
  649.     /*
  650.      * Need an empty database; that's a good trick
  651.      */
  652.     PreResDB = XrmGetStringDatabase("");
  653.  
  654.     XrmParseCommand(&PreResDB, pre_options, XtNumber(pre_options),
  655.         XLOGIN_NAME, argc, argv);
  656.     
  657.     STRCPY(res, XLOGIN_NAME); strncat(res, ".debug", RESLEN-strlen(res));
  658.     if (XrmGetResource(PreResDB, res, "", &str_type, &xrm_value)) {
  659.         pre_app_resources.debug =
  660.             (XmuCompareISOLatin1(xrm_value.addr, "true") == 0);
  661.     } else    pre_app_resources.debug = False;
  662.  
  663.     STRCPY(res, XLOGIN_NAME); strncat(res, ".display", RESLEN-strlen(res));
  664.     if (XrmGetResource(PreResDB, res, "", &str_type, &xrm_value)) {
  665.         pre_app_resources.display = XtNewString(xrm_value.addr);
  666.     } else    pre_app_resources.display = (String) NULL;
  667.  
  668.     STRCPY(res, XLOGIN_NAME); strncat(res, ".logout", RESLEN-strlen(res));
  669.     if (XrmGetResource(PreResDB, res, "", &str_type, &xrm_value)) {
  670.         pre_app_resources.logout =
  671.             (XmuCompareISOLatin1(xrm_value.addr, "true") ==0);
  672.     } else    pre_app_resources.logout = False;
  673.  
  674.     STRCPY(res, XLOGIN_NAME); strncat(res, ".timeOutAction", RESLEN-strlen(res));
  675.     if (XrmGetResource(PreResDB, res, "", &str_type, &xrm_value)) {
  676.         pre_app_resources.time_out_exit =
  677.             (XmuCompareISOLatin1(xrm_value.addr, "logout") == 0);
  678.                 /* set to True equiv. to logout */
  679.     } else    pre_app_resources.time_out_exit = True;
  680.  
  681.     STRCPY(res, XLOGIN_NAME); strncat(res, ".versionOnly", RESLEN-strlen(res));
  682.     if (XrmGetResource(PreResDB, res, "", &str_type, &xrm_value)) {
  683.         pre_app_resources.version_only =
  684.             (XmuCompareISOLatin1(xrm_value.addr, "true") ==0);
  685.     } else    pre_app_resources.version_only = False;
  686.  
  687.  
  688.     XrmDestroyDatabase(PreResDB);
  689.     Debug("LoadPreResources(): display=%s", pre_app_resources.display);
  690.     Debug("LoadPreResources(): logout=%d", pre_app_resources.logout);
  691.     Debug("LoadPreResources(): timeOutAction=%d", pre_app_resources.time_out_exit);
  692.     Debug("LoadPreResources(): versionOnly=%d", pre_app_resources.version_only);
  693.     Debug("LoadPreResources(): leaving ...");
  694. }
  695.  
  696.  
  697. /*
  698.  * this procedure initializes the display and parses
  699.  * the command line options
  700.  */
  701. void InitXDisplay(argc, argv)
  702.     int    *argc;
  703.     char    *argv[];
  704. {
  705.     Debug("InitXDisplay()");
  706.     Debug("InitXDisplay(): argc=%d", *argc);
  707.     XtToolkitInitialize();
  708.     app_ctxt = XtCreateApplicationContext();
  709.     gDisplay = XtOpenDisplay(app_ctxt, display, XLOGIN_NAME, XLOGIN_CLASS,
  710.         options, XtNumber(options), argc, argv);
  711.     if (gDisplay == (Display *) NULL) {
  712.         fprintf(stderr, "%s: WARNING! Cannot open display \"%s\" \n",
  713.             Myname, display);
  714.         XtDestroyApplicationContext(app_ctxt);
  715.         have_display = FALSE;
  716.         return;
  717.     }
  718.     toplevel = XtAppCreateShell(XLOGIN_NAME, XLOGIN_CLASS,
  719.         applicationShellWidgetClass, gDisplay, NULL, 0);
  720.     XtGetApplicationResources(toplevel, &app_resources, resources,
  721.         XtNumber(resources), NULL, 0);
  722.     Debug("InitXDisplay(): showVersion=%d",app_resources.show_version);
  723. }
  724.  
  725.  
  726. /*
  727.  * this procedure does all the display stuff:
  728.  *   defining, creating and starting widgets
  729.  */
  730. void DoXDisplay()
  731. {
  732. #define LABELLEN    255
  733.     Widget        form, endbutton, logininfo, motd, version_w,
  734.             quota_w, motd_label;
  735.     Widget        queue;
  736.     Arg        args[20];
  737.     Dimension    width, motd_height, nolog_height,
  738.             formwidth, formheight,
  739.             fnt_width, fnt_height;
  740.     Position    dpywidth, dpyheight;
  741.     char        motd_label_text[LABELLEN],
  742.             nolog_info_text[LABELLEN],
  743.             nolog_label_text[LABELLEN];
  744.     int        timeout_mult;
  745.     static Arg label_args[] = {
  746.         {XtNresize,        (XtArgVal) True},
  747.         {XtNjustify,        (XtArgVal) XtJustifyCenter},
  748.         {XtNborderWidth,    (XtArgVal) 0},
  749.         {XtNwidth,        (XtArgVal) 0},
  750.         {XtNfromVert,        (XtArgVal) NULL},
  751.         {XtNlabel,        (XtArgVal) NULL}
  752.         };
  753.  
  754.     static Arg text_args[] = {
  755.         {XtNstring,        (XtArgVal) NULL},
  756.         {XtNfromVert,        (XtArgVal) NULL},
  757.         {XtNwidth,        (XtArgVal) 0},
  758.         {XtNheight,        (XtArgVal) 0},
  759.         {XtNfont,        (XtArgVal) NULL},
  760.         {XtNscrollHorizontal,    (XtArgVal) XawtextScrollWhenNeeded},
  761.         {XtNscrollVertical,    (XtArgVal) XawtextScrollWhenNeeded},
  762.         {XtNeditType,        (XtArgVal) XawtextRead},
  763.         {XtNtype,        (XtArgVal) XawAsciiFile},
  764.         {XtNdisplayCaret,    (XtArgVal) False}
  765.         };
  766.  
  767.     Debug("DoXDisplay()");
  768.  
  769.     timeout_mult = 0;
  770.     motd = (Widget) NULL;
  771.  
  772.     XtSetArg(args[0], XtNresizable, True);
  773.     XtSetArg(args[1], XtNresize, True);
  774.     form = XtCreateManagedWidget("form", formWidgetClass, toplevel,
  775.         (ArgList) args, 2);
  776.  
  777.     XtSetArg(args[0], XtNresize,        True);
  778.     XtSetArg(args[1], XtNallowShellResize,    True);
  779.     XtSetValues(toplevel, args, 2);
  780.  
  781.     /* find the max width and height of the font */
  782.  
  783.     fnt_width = app_resources.motd_font->max_bounds.width;
  784.     fnt_height = app_resources.motd_font->ascent + app_resources.motd_font->descent;
  785.     Debug("DoXDisplay(): Fontinfo: width=%d, height=%d", fnt_width, fnt_height);
  786.  
  787.     /*
  788.      * plan for 80 columns and match the number of lines in motd
  789.      * allow for default border width of 1 at both edges
  790.      * allow 1 line for sometimes wrong font infos
  791.      * add 20 pxl to width for scrollbar if lines_motd > app_resources.lines
  792.      */
  793.     Debug("DoXDisplay(): lines set from resources=%d", app_resources.lines);
  794.     if ((app_resources.lines == 0) | (app_resources.lines > lines_motd+1))
  795.         motd_height = fnt_height * (lines_motd + 1);
  796.     else    motd_height = fnt_height * (app_resources.lines + 1);
  797.     if ((app_resources.lines == 0) | (app_resources.lines > lines_nologin+1))
  798.         nolog_height = fnt_height * (lines_nologin + 1);
  799.     else    nolog_height = fnt_height * (app_resources.lines + 1);
  800.     width = fnt_width * 80 + 2;
  801.     label_args[3].value = (XtArgVal) width;
  802.  
  803.     text_args[2].value = (XtArgVal) width;
  804.     text_args[4].value = (XtArgVal) app_resources.motd_font;
  805.     queue = (Widget) NULL;
  806.  
  807.     if (app_resources.show_version) {
  808.         label_args[5].value = (XtArgVal) versionname;
  809.         queue=version_w = XtCreateManagedWidget("version", labelWidgetClass,
  810.                 form, label_args, XtNumber(label_args));
  811.     }
  812.     label_args[4].value = (XtArgVal) queue;
  813. #ifdef LASTLOGIN
  814.     if (info_lastlog) {
  815.         label_args[5].value = (XtArgVal) lastltime;
  816.     } else
  817. #endif /* LASTLOGIN */
  818.         if (do_login) {
  819.             STRCPY(nolog_info_text,
  820.                 "No information available on time of last login");
  821.             label_args[5].value = (XtArgVal) nolog_info_text;
  822.         } else {
  823.             STRCPY(nolog_info_text,
  824.                 "Sorry, no login permitted");
  825.             label_args[5].value = (XtArgVal) nolog_info_text;
  826.         }
  827.     queue=logininfo = XtCreateManagedWidget("loginInfo", labelWidgetClass,
  828.                 form, label_args, XtNumber(label_args));
  829.  
  830.     if (do_login | info_nolog) {
  831.         if (info_motd) {
  832.             STRCPY(motd_label_text,"Message Of The Day follows:");
  833.             label_args[5].value = (XtArgVal) motd_label_text;
  834.         } else if (info_nolog) {
  835.             STRCPY(nolog_label_text, "Text in file ");
  836.             strncat(nolog_label_text, NoLogin,
  837.                 LABELLEN-strlen(nolog_label_text));
  838.             strncat(nolog_label_text, " follows:",
  839.                 LABELLEN-strlen(nolog_label_text));
  840.             label_args[5].value = (XtArgVal) nolog_label_text;
  841.         } else {
  842.             STRCPY(motd_label_text, "Nothing changed in ");
  843.             strncat(motd_label_text, Motd,
  844.                 LABELLEN-strlen(motd_label_text));
  845.             strncat(motd_label_text, " since your last login",
  846.                 LABELLEN-strlen(motd_label_text));
  847.             label_args[5].value = (XtArgVal) motd_label_text;
  848.         }
  849.  
  850.         label_args[4].value = (XtArgVal) queue;
  851.         queue=motd_label = XtCreateManagedWidget("motdLabel", labelWidgetClass,
  852.                 form, (ArgList) label_args, 6);
  853.     }
  854.  
  855. #ifdef QUOTA
  856.     if (info_eusers | info_eproclim) {
  857.         if (info_eproclim) {
  858.             label_args[5].value = (XtArgVal) 
  859.                 "You have too many processes running.";
  860.         } else {
  861.             label_args[5].value = (XtArgVal) 
  862.                 "Too many users already logged in. Try again later";
  863.         }
  864.         label_args[4].value = (XtArgVal) queue;
  865.         queue=quota_w = XtCreateManagedWidget("quotaInfo", labelWidgetClass,
  866.                     form, (ArgList) label_args, 6);
  867.     }
  868.  
  869. #endif /* QUOTA */
  870.  
  871.     if (info_nolog) {
  872.         timeout_mult = lines_nologin;
  873.         XtSetArg(text_args[0], XtNstring, NoLogin);
  874.         XtSetArg(text_args[1], XtNfromVert, queue);
  875.         XtSetArg(text_args[3], XtNheight, nolog_height);
  876.         queue=motd = XtCreateManagedWidget("motd", asciiTextWidgetClass,
  877.                 form, (ArgList) text_args, XtNumber(text_args));
  878.         Debug("Uninstalling Translations for motd widget ...");
  879.         XtUninstallTranslations(motd);
  880.     } else {
  881.         if (info_motd) {
  882.             timeout_mult = lines_motd;
  883.             XtSetArg(text_args[0], XtNstring, Motd);
  884.             XtSetArg(text_args[1], XtNfromVert, queue);
  885.             XtSetArg(text_args[3], XtNheight, motd_height);
  886.             queue=motd = XtCreateManagedWidget("motd", asciiTextWidgetClass,
  887.                     form, (ArgList) text_args, XtNumber(text_args));
  888.             Debug("Uninstalling Translations for motd widget ...");
  889.             XtUninstallTranslations(motd);
  890.         }
  891.     }
  892.     
  893.     XtSetArg(args[0], XtNcallback, callbacks);
  894.     XtSetArg(args[1], XtNjustify, XtJustifyCenter);
  895.     XtSetArg(args[2], XtNresize, True);
  896.     XtSetArg(args[3], XtNresizable,    False);
  897.     XtSetArg(args[4], XtNwidth, width);
  898.     XtSetArg(args[5], XtNfromVert, queue);
  899.     XtSetArg(args[6], XtNborderWidth, (Dimension) 2);
  900.     XtSetArg(args[7], XtNhighlightThickness, (Dimension) 2);
  901.     XtSetArg(args[8], XtNinternalHeight, (Dimension) 3);
  902.     XtSetArg(args[9], XtNinternalWidth, (Dimension) 3);
  903.     XtSetArg(args[10],XtNlabel, "Click here to continue");
  904.     endbutton = XtCreateManagedWidget("endbutton", commandWidgetClass,
  905.             form, (ArgList) args, 11);
  906.  
  907.     Debug("Installing Accelerators for form widget");
  908.     XtInstallAccelerators(form, endbutton);
  909.  
  910.     /*
  911.      * Get the size of the screen.
  912.      * Want the window to be centered.
  913.      */
  914.     dpywidth = DisplayWidth(XtDisplay(form), DefaultScreen(XtDisplay(form)));
  915.     dpyheight = DisplayHeight(XtDisplay(form), DefaultScreen(XtDisplay(form)));
  916.  
  917.     /*
  918.      * Don't map, but realize it, to get the size of the window
  919.      */
  920.     XtSetMappedWhenManaged(toplevel, False);
  921.     XtRealizeWidget(toplevel);
  922.  
  923.     while (!XtIsRealized(form))
  924.         formwidth=2;
  925.  
  926.     /*
  927.      * Get the size of the window
  928.      */
  929.     XtSetArg(args[0], XtNwidth,    &formwidth);
  930.     XtSetArg(args[1], XtNheight,    &formheight);
  931.     XtGetValues(form, args, 2);
  932.  
  933.     /*
  934.      * Place the window centered on the screen.
  935.      * allow 5 pixels distance to top and bottom
  936.      */
  937.     if ((dpyheight < formheight) && (motd != NULL)) {
  938.         int        dpy_offest = 5;
  939.         Dimension    motd_width;
  940.  
  941.         Debug("DoXDisplay(): New layout for motd ...");
  942.  
  943.         dpyheight -= 2*dpy_offest;
  944.         Debug("DoXDislay(): motd_height was %d", motd_height);
  945.         XtSetArg(args[0], XtNheight,    &motd_height);
  946.         XtSetArg(args[1], XtNwidth,    &motd_width);
  947.         XtGetValues(motd, args, 2);
  948.  
  949.         motd_height -= (formheight - dpyheight);
  950.         /*
  951.          * set new height of motd-widget and allow
  952.          * 20 pixels for scrollbar
  953.          */
  954.         XtSetArg(args[0], XtNheight,    motd_height);
  955.         XtSetArg(args[1], XtNwidth,    motd_width + 20);
  956.         XtSetValues(motd, args, 2);
  957.  
  958.         XtSetArg(args[0], XtNheight,    dpyheight);
  959.         XtSetValues(form, args, 1);
  960.  
  961.         XawFormDoLayout(form, True);
  962.  
  963.         XtMoveWidget(toplevel, (Position) (dpywidth-formwidth)/2,
  964.                 (Position) dpy_offest);
  965.     } else {
  966.         XtMoveWidget(toplevel, (Position) (dpywidth-formwidth)/2,
  967.                 (Position) (dpyheight-formheight)/2);
  968.     }
  969.  
  970.     /*
  971.      * Now map the window to get it visible
  972.      */
  973.     XtSetMappedWhenManaged(toplevel, True);
  974.     XtMapWidget(toplevel);
  975.     /*
  976.      * Warp the pointer into the button-click window
  977.      */
  978.     XWarpPointer(XtDisplay(toplevel), (Window) NULL, XtWindow(endbutton),
  979.         0, 0, 0, 0, width/2, 3);
  980.     Debug("DoXDisplay(): timeout multiplicator=%d", timeout_mult);
  981.  
  982.     /*
  983.      * add timeout, so user get's kicked off, if he's not
  984.      * behind the the display
  985.      */
  986.     if (!info_motd || pre_app_resources.time_out_exit) {
  987.         XtAppAddTimeOut(app_ctxt,
  988.             (unsigned long) (timeout_mult+30)*1000, 
  989.             motdTimeOver, (XtPointer) NULL);
  990.         Debug("DoXDisplay(): TimeOut added.");
  991.     }
  992.     Debug("DoXDisplay(): starting XtAppMainLoop()");
  993.     XtAppMainLoop(app_ctxt);
  994. }
  995.  
  996.  
  997.  
  998. main(argc, argv)
  999.     int    argc;
  1000.     char    *argv[];
  1001. {
  1002.     STRCPY(Myname, argv[0]);
  1003.     MyRevision[0] = ' ';
  1004.     MyRevision[strlen(MyRevision)-1] = '\0';
  1005.  
  1006.     sprintf(versionname,"%s- version %s patchlevel %d \0",
  1007.         MyRevision, MyVersion, PATCHLEVEL);
  1008.  
  1009.     LoadPreResources(&argc, argv);
  1010.     if (pre_app_resources.version_only) {
  1011.         fprintf(stderr,"%s:%s \n", Myname, versionname);
  1012.         exit(1);
  1013.     }
  1014.  
  1015.     do_logout = pre_app_resources.logout;
  1016.  
  1017.     if ((argc > 1) && do_logout) {
  1018.         fprintf(stderr,"%s: unknown option %s \n", Myname,
  1019.             argv[1]);
  1020.         exit(1);
  1021.     }
  1022.  
  1023.     Init();
  1024.     Debug("main(): after Init()");
  1025.  
  1026.     if (do_logout) {
  1027.         Debug("main(): logging out ...");
  1028.         STRCPY(wtmp.ut_name, EMPTY);
  1029.         WriteWtmp();
  1030.         exit(0);
  1031.     }
  1032.  
  1033.     InitXDisplay(&argc, argv);
  1034.     Debug("main(): after InitXDisplay()");
  1035.  
  1036.     if ((argc > 1) & have_display) {
  1037.         fprintf(stderr,"%s: unknown option %s \n", Myname,
  1038.             argv[1]);
  1039.         CloseXDisplay();
  1040.         exit(1);
  1041.         }
  1042.     do_login  = !do_logout;
  1043.  
  1044.     CheckNologin();
  1045. #ifdef QUOTA
  1046.     CheckQuota();
  1047. #endif
  1048.  
  1049.     if (do_login) {
  1050.         WriteWtmp();
  1051. #ifdef LASTLOGIN
  1052.         DoLastLogin();
  1053. #endif /* LASTLOGIN */
  1054.         CheckMotd();
  1055.     }
  1056.  
  1057.     if (have_display) {
  1058.         Debug("main(): showMOTD=%s", app_resources.show_MOTD);
  1059.         info_motd |= (XmuCompareISOLatin1(app_resources.show_MOTD,
  1060.                 "always") == 0);
  1061.     }
  1062.     /*
  1063.  
  1064.      * display motd only if no .hushlogin exists
  1065.      * and /etc/motd has more than 0 lines!
  1066.      */
  1067.     info_motd = info_motd && !is_hushlogin && (lines_motd != 0);
  1068.  
  1069.     info_atall = info_lastlog | info_motd | info_eusers
  1070.             | info_eproclim | info_nolog;
  1071.  
  1072.  
  1073.     if (info_atall & have_display) {
  1074.         DoXDisplay();
  1075.     }
  1076. }
  1077.