home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / clients / xdm / session.c.orig < prev    next >
Encoding:
Text File  |  1993-07-21  |  13.5 KB  |  618 lines

  1. /*
  2.  * xdm - display manager daemon
  3.  *
  4.  * $XConsortium: session.c,v 1.55 91/09/19 16:25:56 keith Exp $
  5.  *
  6.  * Copyright 1988 Massachusetts Institute of Technology
  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 M.I.T. not be used in advertising or
  13.  * publicity pertaining to distribution of the software without specific,
  14.  * written prior permission.  M.I.T. 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.  * Author:  Keith Packard, MIT X Consortium
  19.  */
  20.  
  21. /*
  22.  * session.c
  23.  */
  24.  
  25. # include "dm.h"
  26. # include <X11/Xlib.h>
  27. # include <signal.h>
  28. # include <X11/Xatom.h>
  29. # include <errno.h>
  30. # include <stdio.h>
  31. # include <ctype.h>
  32. #ifdef SECURE_RPC
  33. # include <rpc/rpc.h>
  34. # include <rpc/key_prot.h>
  35. #endif
  36.  
  37. extern int  errno;
  38.  
  39. static int            clientPid;
  40. static struct greet_info    greet;
  41. static struct verify_info    verify;
  42.  
  43. static Jmp_buf    abortSession;
  44.  
  45. /* ARGSUSED */
  46. static SIGVAL
  47. catchTerm (n)
  48.     int n;
  49. {
  50.     Longjmp (abortSession, 1);
  51. }
  52.  
  53. static Jmp_buf    pingTime;
  54.  
  55. /* ARGSUSED */
  56. static SIGVAL
  57. catchAlrm (n)
  58.     int n;
  59. {
  60.     Longjmp (pingTime, 1);
  61. }
  62.  
  63. SessionPingFailed (d)
  64.     struct display  *d;
  65. {
  66.     if (clientPid > 1)
  67.     {
  68.         AbortClient (clientPid);
  69.     source (verify.systemEnviron, d->reset);
  70.     }
  71.     SessionExit (d, RESERVER_DISPLAY, TRUE);
  72. }
  73.  
  74. /*
  75.  * We need our own error handlers because we can't be sure what exit code Xlib
  76.  * will use, and our Xlib does exit(1) which matches REMANAGE_DISPLAY, which
  77.  * can cause a race condition leaving the display wedged.  We need to use
  78.  * RESERVER_DISPLAY for IO errors, to ensure that the manager waits for the
  79.  * server to terminate.  For other X errors, we should give up.
  80.  */
  81.  
  82. /*ARGSUSED*/
  83. static
  84. IOErrorHandler (dpy)
  85.     Display *dpy;
  86. {
  87.     extern char *sys_errlist[];
  88.     extern int sys_nerr;
  89.     char *s = ((errno >= 0 && errno < sys_nerr) ? sys_errlist[errno]
  90.                         : "unknown error");
  91.  
  92.     LogError("fatal IO error %d (%s)\n", errno, s);
  93.     exit(RESERVER_DISPLAY);
  94. }
  95.  
  96. static int
  97. ErrorHandler(dpy, event)
  98.     Display *dpy;
  99.     XErrorEvent *event;
  100. {
  101.     LogError("X error\n");
  102.     if (XmuPrintDefaultErrorMessage (dpy, event, stderr) == 0) return 0;
  103.     exit(UNMANAGE_DISPLAY);
  104.     /*NOTREACHED*/
  105. }
  106.  
  107. ManageSession (d)
  108. struct display    *d;
  109. {
  110.     int            pid, code, i;
  111.     Display        *dpy, *InitGreet ();
  112.  
  113.     Debug ("ManageSession %s\n", d->name);
  114.     (void)XSetIOErrorHandler(IOErrorHandler);
  115.     (void)XSetErrorHandler(ErrorHandler);
  116.     SetTitle(d->name, (char *) 0);
  117.     /*
  118.      * Load system default Resources
  119.      */
  120.     LoadXloginResources (d);
  121.     dpy = InitGreet (d);
  122.     /*
  123.      * Run the setup script - note this usually will not work when
  124.      * the server is grabbed, so we don't even bother trying.
  125.      */
  126.     if (!d->grabServer)
  127.     SetupDisplay (d);
  128.     if (!dpy) {
  129.     LogError ("Cannot reopen display %s for greet window\n", d->name);
  130.     exit (RESERVER_DISPLAY);
  131.     }
  132.     for (;;) {
  133.     /*
  134.      * Greet user, requesting name/password
  135.      */
  136.     code = Greet (d, &greet);
  137.     if (code != 0)
  138.     {
  139.         CloseGreet (d);
  140.         SessionExit (d, code, FALSE);
  141.     }
  142.     /*
  143.      * Verify user
  144.      */
  145.     if (Verify (d, &greet, &verify))
  146.         break;
  147.     else
  148.         FailedLogin (d, &greet);
  149.     }
  150.     DeleteXloginResources (d, dpy);
  151. #ifdef SECURE_RPC
  152.     for (i = 0; i < d->authNum; i++)
  153.     {
  154.     if (d->authorizations[i]->name_length == 9 &&
  155.         bcmp (d->authorizations[i]->name, "SUN-DES-1", 9) == 0)
  156.     {
  157.         XHostAddress    addr;
  158.         char        netname[MAXNETNAMELEN+1];
  159.         char        domainname[MAXNETNAMELEN+1];
  160.     
  161.         getdomainname(domainname, sizeof domainname);
  162.         user2netname (netname, verify.uid, domainname);
  163.         addr.family = FamilyNetname;
  164.         addr.length = strlen (netname);
  165.         addr.address = netname;
  166.         XAddHost (dpy, &addr);
  167.         break;
  168.     }
  169.     }
  170. #endif
  171.     CloseGreet (d);
  172.     Debug ("Greet loop finished\n");
  173.     /*
  174.      * Run system-wide initialization file
  175.      */
  176.     if (source (verify.systemEnviron, d->startup) != 0)
  177.     {
  178.     Debug ("Startup program %s exited with non-zero status\n",
  179.         d->startup);
  180.     SessionExit (d, OBEYSESS_DISPLAY, FALSE);
  181.     }
  182.     clientPid = 0;
  183.     if (!Setjmp (abortSession)) {
  184.     (void) Signal (SIGTERM, catchTerm);
  185.     /*
  186.      * Start the clients, changing uid/groups
  187.      *       setting up environment and running the session
  188.      */
  189.     if (StartClient (&verify, d, &clientPid, greet.password)) {
  190.         Debug ("Client Started\n");
  191.         /*
  192.          * Wait for session to end,
  193.          */
  194.         for (;;) {
  195.         if (d->pingInterval)
  196.         {
  197.             if (!Setjmp (pingTime))
  198.             {
  199.             (void) Signal (SIGALRM, catchAlrm);
  200.             (void) alarm (d->pingInterval * 60);
  201.             pid = wait ((waitType *) 0);
  202.             (void) alarm (0);
  203.             }
  204.             else
  205.             {
  206.             (void) alarm (0);
  207.                 if (!PingServer (d, (Display *) NULL))
  208.                 SessionPingFailed (d);
  209.             }
  210.         }
  211.         else
  212.         {
  213.             pid = wait ((waitType *) 0);
  214.         }
  215.         if (pid == clientPid)
  216.             break;
  217.         }
  218.     } else {
  219.         LogError ("session start failed\n");
  220.     }
  221.     } else {
  222.     /*
  223.      * when terminating the session, nuke
  224.      * the child and then run the reset script
  225.      */
  226.     AbortClient (clientPid);
  227.     }
  228.     /*
  229.      * run system-wide reset file
  230.      */
  231.     Debug ("Source reset program %s\n", d->reset);
  232.     source (verify.systemEnviron, d->reset);
  233.     SessionExit (d, OBEYSESS_DISPLAY, TRUE);
  234. }
  235.  
  236. LoadXloginResources (d)
  237. struct display    *d;
  238. {
  239.     char    **args, **parseArgs();
  240.     char    **env = 0, **setEnv(), **systemEnv();
  241.  
  242.     if (d->resources[0] && access (d->resources, 4) == 0) {
  243.     env = systemEnv (d, (char *) 0, (char *) 0);
  244.     args = parseArgs ((char **) 0, d->xrdb);
  245.     args = parseArgs (args, d->resources);
  246.     Debug ("Loading resource file: %s\n", d->resources);
  247.     (void) runAndWait (args, env);
  248.     freeArgs (args);
  249.     freeEnv (env);
  250.     }
  251. }
  252.  
  253. SetupDisplay (d)
  254. struct display    *d;
  255. {
  256.     char    **env = 0, **setEnv(), **systemEnv();
  257.  
  258.     if (d->setup && d->setup[0])
  259.     {
  260.         env = systemEnv (d, (char *) 0, (char *) 0);
  261.         (void) source (env, d->setup);
  262.         freeEnv (env);
  263.     }
  264. }
  265.  
  266. /*ARGSUSED*/
  267. DeleteXloginResources (d, dpy)
  268. struct display    *d;
  269. Display        *dpy;
  270. {
  271.     int i;
  272.     Atom prop = XInternAtom(dpy, "SCREEN_RESOURCES", True);
  273.  
  274.     XDeleteProperty(dpy, RootWindow (dpy, 0), XA_RESOURCE_MANAGER);
  275.     if (prop) {
  276.     for (i = ScreenCount(dpy); --i >= 0; )
  277.         XDeleteProperty(dpy, RootWindow (dpy, i), prop);
  278.     }
  279. }
  280.  
  281. static Jmp_buf syncJump;
  282.  
  283. /* ARGSUSED */
  284. static SIGVAL
  285. syncTimeout (n)
  286.     int n;
  287. {
  288.     Longjmp (syncJump, 1);
  289. }
  290.  
  291. SecureDisplay (d, dpy)
  292. struct display    *d;
  293. Display        *dpy;
  294. {
  295.     Debug ("SecureDisplay %s\n", d->name);
  296.     (void) Signal (SIGALRM, syncTimeout);
  297.     if (Setjmp (syncJump)) {
  298.     LogError ("WARNING: display %s could not be secured\n",
  299.            d->name);
  300.     SessionExit (d, RESERVER_DISPLAY, FALSE);
  301.     }
  302.     (void) alarm ((unsigned) d->grabTimeout);
  303.     Debug ("Before XGrabServer %s\n", d->name);
  304.     XGrabServer (dpy);
  305.     if (XGrabKeyboard (dpy, DefaultRootWindow (dpy), True, GrabModeAsync,
  306.                GrabModeAsync, CurrentTime) != GrabSuccess)
  307.     {
  308.     (void) alarm (0);
  309.     (void) Signal (SIGALRM, SIG_DFL);
  310.     LogError ("WARNING: keyboard on display %s could not be secured\n",
  311.           d->name);
  312.     SessionExit (d, RESERVER_DISPLAY, FALSE);
  313.     }
  314.     Debug ("XGrabKeyboard succeeded %s\n", d->name);
  315.     (void) alarm (0);
  316.     (void) Signal (SIGALRM, SIG_DFL);
  317.     pseudoReset (dpy);
  318.     if (!d->grabServer)
  319.     {
  320.     XUngrabServer (dpy);
  321.     XSync (dpy, 0);
  322.     }
  323.     Debug ("done secure %s\n", d->name);
  324. }
  325.  
  326. UnsecureDisplay (d, dpy)
  327. struct display    *d;
  328. Display        *dpy;
  329. {
  330.     Debug ("Unsecure display %s\n", d->name);
  331.     if (d->grabServer)
  332.     {
  333.     XUngrabServer (dpy);
  334.     XSync (dpy, 0);
  335.     }
  336. }
  337.  
  338. SessionExit (d, status, removeAuth)
  339.     struct display  *d;
  340. {
  341.     /* make sure the server gets reset after the session is over */
  342.     if (d->serverPid >= 2 && d->resetSignal)
  343.     kill (d->serverPid, d->resetSignal);
  344.     else
  345.     ResetServer (d);
  346.     if (removeAuth)
  347.     {
  348. #ifdef NGROUPS_MAX
  349.     setgid (verify.groups[0]);
  350. #else
  351.     setgid (verify.gid);
  352. #endif
  353.     setuid (verify.uid);
  354.     RemoveUserAuthorization (d, &verify);
  355.     }
  356.     Debug ("Display %s exiting with status %d\n", d->name, status);
  357.     exit (status);
  358. }
  359.  
  360. StartClient (verify, d, pidp, passwd)
  361. struct verify_info    *verify;
  362. struct display        *d;
  363. int            *pidp;
  364. char            *passwd;
  365. {
  366.     char    **f, *home, *getEnv ();
  367.     char    *failsafeArgv[2];
  368.     int    pid;
  369.  
  370.     if (verify->argv) {
  371.     Debug ("StartSession %s: ", verify->argv[0]);
  372.     for (f = verify->argv; *f; f++)
  373.         Debug ("%s ", *f);
  374.     Debug ("; ");
  375.     }
  376.     if (verify->userEnviron) {
  377.     for (f = verify->userEnviron; *f; f++)
  378.         Debug ("%s ", *f);
  379.     Debug ("\n");
  380.     }
  381.     switch (pid = fork ()) {
  382.     case 0:
  383.     CleanUpChild ();
  384. #ifdef NGROUPS_MAX
  385.  
  386.     setgid (verify->groups[0]);
  387.     setgroups (verify->ngroups, verify->groups);
  388. #else
  389.     setgid (verify->gid);
  390. #endif
  391.     setuid (verify->uid);
  392. #ifdef SECURE_RPC
  393.     {
  394.         char    netname[MAXNETNAMELEN+1], secretkey[HEXKEYBYTES+1];
  395.         int        ret;
  396.         int        len;
  397.  
  398.         getnetname (netname);
  399.         Debug ("User netname: %s\n", netname);
  400.         len = strlen (passwd);
  401.         if (len > 8)
  402.         bzero (passwd + 8, len - 8);
  403.         ret = getsecretkey(netname,secretkey,passwd);
  404.         Debug ("getsecretkey returns %d, key length %d\n",
  405.             ret, strlen (secretkey));
  406.         ret = key_setsecret(secretkey);
  407.         Debug ("key_setsecret returns %d\n", ret);
  408.     }
  409. #endif
  410.     bzero(passwd, strlen(passwd));
  411.     SetUserAuthorization (d, verify);
  412.     home = getEnv (verify->userEnviron, "HOME");
  413.     if (home)
  414.         if (chdir (home) == -1) {
  415.             LogError ("No home directory %s for user %s, using /\n",
  416.                   home, getEnv (verify->userEnviron, "USER"));
  417.             chdir ("/");
  418.         }
  419.     if (verify->argv) {
  420.         Debug ("executing session %s\n", verify->argv[0]);
  421.         execute (verify->argv, verify->userEnviron);
  422.         LogError ("Session execution failed %s\n", verify->argv[0]);
  423.     } else {
  424.         LogError ("Session has no command/arguments\n");
  425.     }
  426.     failsafeArgv[0] = d->failsafeClient;
  427.     failsafeArgv[1] = 0;
  428.     execute (failsafeArgv, verify->userEnviron);
  429.     exit (1);
  430.     case -1:
  431.     bzero(passwd, strlen(passwd));
  432.     Debug ("StartSession, fork failed\n");
  433.     LogError ("can't start session for %d, fork failed\n", d->name);
  434.     return 0;
  435.     default:
  436.     bzero(passwd, strlen(passwd));
  437.     Debug ("StartSession, fork suceeded %d\n", pid);
  438.     *pidp = pid;
  439.     return 1;
  440.     }
  441. }
  442.  
  443. static Jmp_buf    tenaciousClient;
  444.  
  445. /* ARGSUSED */
  446. static SIGVAL
  447. waitAbort (n)
  448.     int n;
  449. {
  450.     Longjmp (tenaciousClient, 1);
  451. }
  452.  
  453. #if defined(_POSIX_SOURCE) || defined(SYSV) || defined(SVR4)
  454. #define killpg(pgrp, sig) kill(-(pgrp), sig)
  455. #endif
  456.  
  457. AbortClient (pid)
  458. int    pid;
  459. {
  460.     int    sig = SIGTERM;
  461. #if __STDC__
  462.     volatile int    i;
  463. #else
  464.     int    i;
  465. #endif
  466.     int    retId;
  467.     for (i = 0; i < 4; i++) {
  468.     if (killpg (pid, sig) == -1) {
  469.         switch (errno) {
  470.         case EPERM:
  471.         LogError ("xdm can't kill client\n");
  472.         case EINVAL:
  473.         case ESRCH:
  474.         return;
  475.         }
  476.     }
  477.     if (!Setjmp (tenaciousClient)) {
  478.         (void) Signal (SIGALRM, waitAbort);
  479.         (void) alarm ((unsigned) 10);
  480.         retId = wait ((waitType *) 0);
  481.         (void) alarm ((unsigned) 0);
  482.         (void) Signal (SIGALRM, SIG_DFL);
  483.         if (retId == pid)
  484.         break;
  485.     } else
  486.         (void) Signal (SIGALRM, SIG_DFL);
  487.     sig = SIGKILL;
  488.     }
  489. }
  490.  
  491. int
  492. source (environ, file)
  493. char            **environ;
  494. char            *file;
  495. {
  496.     char    **args, *args_safe[2];
  497.     extern char    **parseArgs ();
  498.     int        ret;
  499.  
  500.     if (file && file[0]) {
  501.     Debug ("source %s\n", file);
  502.     args = parseArgs ((char **) 0, file);
  503.     if (!args)
  504.     {
  505.         args = args_safe;
  506.         args[0] = file;
  507.         args[1] = NULL;
  508.     }
  509.     ret = runAndWait (args, environ);
  510.     freeArgs (args);
  511.     return ret;
  512.     }
  513.     return 0;
  514. }
  515.  
  516. int
  517. runAndWait (args, environ)
  518.     char    **args;
  519.     char    **environ;
  520. {
  521.     int    pid;
  522.     extern int    errno;
  523.     waitType    result;
  524.  
  525.     switch (pid = fork ()) {
  526.     case 0:
  527.     CleanUpChild ();
  528.     execute (args, environ);
  529.     LogError ("can't execute %s\n", args[0]);
  530.     exit (1);
  531.     case -1:
  532.     Debug ("fork failed\n");
  533.     LogError ("can't fork to execute %s\n", args[0]);
  534.     return 1;
  535.     default:
  536.     while (wait (&result) != pid)
  537.         /* SUPPRESS 530 */
  538.         ;
  539.     break;
  540.     }
  541.     return waitVal (result);
  542. }
  543.  
  544. execute (argv, environ)
  545. char    **argv;
  546. char    **environ;
  547. {
  548.     /* make stdout follow stderr to the log file */
  549.     dup2 (2,1);
  550.     execve (argv[0], argv, environ);
  551.     /*
  552.      * In case this is a shell script which hasn't been
  553.      * made executable (or this is a SYSV box), do
  554.      * a reasonable thing
  555.      */
  556.     if (errno != ENOENT) {
  557.     char    program[1024], *e, *p, *optarg;
  558.     FILE    *f;
  559.     char    **newargv, **av;
  560.     int    argc;
  561.  
  562.     /*
  563.      * emulate BSD kernel behaviour -- read
  564.      * the first line; check if it starts
  565.      * with "#!", in which case it uses
  566.      * the rest of the line as the name of
  567.      * program to run.  Else use "/bin/sh".
  568.      */
  569.     f = fopen (argv[0], "r");
  570.     if (!f)
  571.         return;
  572.     if (fgets (program, sizeof (program) - 1, f) == NULL)
  573.      {
  574.         fclose (f);
  575.         return;
  576.     }
  577.     fclose (f);
  578.     e = program + strlen (program) - 1;
  579.     if (*e == '\n')
  580.         *e = '\0';
  581.     if (!strncmp (program, "#!", 2)) {
  582.         p = program + 2;
  583.         while (*p && isspace (*p))
  584.         ++p;
  585.         optarg = p;
  586.         while (*optarg && !isspace (*optarg))
  587.         ++optarg;
  588.         if (*optarg) {
  589.         *optarg = '\0';
  590.         do
  591.             ++optarg;
  592.         while (*optarg && isspace (*optarg));
  593.         } else
  594.         optarg = 0;
  595.     } else {
  596.         p = "/bin/sh";
  597.         optarg = 0;
  598.     }
  599.     Debug ("Shell script execution: %s (optarg %s)\n",
  600.         p, optarg ? optarg : "(null)");
  601.     for (av = argv, argc = 0; *av; av++, argc++)
  602.         /* SUPPRESS 530 */
  603.         ;
  604.     newargv = (char **) malloc ((argc + (optarg ? 3 : 2)) * sizeof (char *));
  605.     if (!newargv)
  606.         return;
  607.     av = newargv;
  608.     *av++ = p;
  609.     if (optarg)
  610.         *av++ = optarg;
  611.     /* SUPPRESS 560 */
  612.     while (*av++ = *argv++)
  613.         /* SUPPRESS 530 */
  614.         ;
  615.     execve (newargv[0], newargv, environ);
  616.     }
  617. }
  618.