home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / clients / xdm / session.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-21  |  14.2 KB  |  646 lines

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