home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume3 / xgone / part01 / xgone.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-03-11  |  13.8 KB  |  494 lines

  1. /*
  2.  * Lockscreen for X windows
  3.  * Tim Morgan 2/25/87
  4.  * 
  5.  * Modified for X11 by Richard Johnson
  6.  * Modified/Rewritten extensively afterwards.
  7.  */
  8.  
  9. #include <X11/Xlib.h>
  10. #include <stdio.h>
  11. #include <pwd.h>
  12. #include <signal.h>
  13. #include <X11/Xos.h>
  14.  
  15. #define    SLEEP_TIME    2        /* Seconds, of course */
  16. #define FONT        "fixed"        /* BORING! (but always there) */
  17. #define SEPARATION    2        /* ... between lines */
  18. #define DISPLAYNAME    ""
  19. #define DELAYTIME    2        /* delay time for "-delay" option */
  20. #define FALSE        0
  21. #define TRUE        1
  22. #define UTMP        "/etc/utmp"    /* the utmp file */
  23. #define control(a)    ((a) - ('@'))    /* control characters */
  24.  
  25. char    DspMsg[1024]="X Gone";    /* Default message to display */
  26. char    *Dsptime="Started: ";        /* Time command was started */
  27. int    fontheight;            /* height of one line of text */
  28. Pixmap    textpixmap;            /* pixmap to hold text */
  29. int    textwidth, textheight;        /* sizes of whole text area */
  30. int    Sleeptime=SLEEP_TIME;        /* sleep time between updates */
  31. int    Delay=FALSE;            /* Delay startup (for twm) */
  32. int    lastx=0, lasty=0;        /* last coord's of text */
  33. fd_set    select_mask, sel_mask;        /* for select stuff */
  34. int    select_bits;            /* width of select_mask */
  35. struct timeval    sleeptime;        /* for selects */
  36. char    *index();            /* from C lib. */
  37.  
  38. main(argc, argv)
  39. int argc;
  40. char *argv[];
  41. {
  42.     Display            *dpy;
  43.     XSetWindowAttributes    xswa;
  44.     Visual            visual;
  45.     Window            w;
  46.     GC                gc;
  47.     XGCValues            gcvalues;
  48.     XEvent            in;
  49.     XFontStruct            *font;
  50.     XColor            blackcolor;
  51.     XColor            whitecolor;
  52.     Pixmap            pixmap;
  53.     Cursor            cursor;
  54.     char            buffer[100], inputbuf[80], *string, *user_name
  55.                 ,*getenv(), *ctime(), *rindex(), response[100];
  56.     char            *crypt(), *pw, root_pw[20], *user_passwd;
  57.     int                len, password_bad = 1, response_i, nbytes, i;
  58.     struct passwd        *u;
  59.     char            *myname, *dspptr;
  60.     short            *bits;
  61.     int                width, lenwidth;
  62.     int                timeout, interval,
  63.                 preference, allowexp;
  64.     static char            fontname[80]={FONT};
  65.  
  66.     if((myname = rindex(argv[0], '/')) == NULL)
  67.     myname = argv[0];
  68.     else
  69.     myname++;
  70.  
  71.     if (! verify(getuid(), getenv("DISPLAY"))) {
  72.     fprintf(stderr, "I can't open that display  -  sorry...\n");
  73.     exit(1);
  74.     } 
  75.     
  76.     if ((dpy = XOpenDisplay(DISPLAYNAME)) == NULL) {
  77.     fprintf(stderr, "%s: Can't open display '%s'\n",
  78.         myname, XDisplayName(DISPLAYNAME));
  79.     exit(1);
  80.     }
  81. /*
  82.  * Get the defaults
  83.  */
  84.     if((string = XGetDefault(dpy, myname, "Font")) != NULL)
  85.     strcpy(fontname, string);
  86.     if((string = XGetDefault(dpy, myname, "Text")) != NULL)
  87.     strcpy(DspMsg, string);
  88.     if((string = XGetDefault(dpy, myname, "Sleep")) != NULL)
  89.     Sleeptime = atoi(string);
  90.     if((string = XGetDefault(dpy, myname, "Update")) != NULL)
  91.     Sleeptime = atoi(string);
  92.     if((string = XGetDefault(dpy, myname, "Delay")) != NULL)
  93.     if(strcmp(string, "off") == 0 || strcmp(string, "0") == 0
  94.        || strcmp(string, "no") == 0)
  95.         Delay = FALSE;
  96.     else
  97.         Delay = TRUE;
  98.         
  99. /*
  100.  * Parse arguments
  101.  */
  102.     for(--argc , ++argv ; *argv && **argv == '-' ; argv++ , argc--) {
  103.     ++*argv;
  104.     if(strcmp(*argv, "fn") == 0 || strncmp(*argv, "font", 1) == 0)
  105.         strcpy(fontname, *++argv);    /* save font name */
  106.     else if(strncmp(*argv, "sleep", 1) == 0
  107.        || strncmp(*argv, "update", 1) == 0)
  108.         Sleeptime = atoi(*++argv);
  109.     else if(strncmp(*argv, "delay", 1) == 0)
  110.         Delay = TRUE;
  111.     }
  112.  
  113. /*
  114.  * If we should delay startup, then fork and exit the parent right now.
  115.  * (This way, "twm" changes the cursor back to the original one and lets
  116.  *  go of the mouse so that we can grab it.)
  117.  */
  118.     if(Delay)
  119.     switch(fork()) {
  120.     case 0:    /* child  -  continue with program */
  121.         sleep(DELAYTIME);
  122.         break;
  123.  
  124.     case -1:    /* error during fork  -  exit */
  125.         fprintf(stderr, "Can't fork - ");
  126.         perror("");
  127.         exit(1);
  128.  
  129.     default:    /* parent  -  exit */
  130.         exit(0);
  131.     }
  132.  
  133. /*
  134.  * Get the message
  135.  */
  136.     dspptr = DspMsg;
  137.     if( *argv ) strcpy(dspptr, "\0");
  138.     while( *argv ) {
  139.     strcat(dspptr, *argv++);
  140.     strcat(dspptr, " ");
  141.     }
  142.  
  143. /*
  144.  * Set random number generator
  145.  */
  146.     srandom(time(0));
  147.  
  148. /*
  149.  * Make a big window to cover the screen
  150.  */
  151.     xswa.background_pixel = BlackPixel(dpy, DefaultScreen(dpy));
  152.     xswa.override_redirect = True;
  153.     visual.visualid = CopyFromParent;
  154.     w = XCreateWindow(dpy, DefaultRootWindow(dpy), 0, 0, 9999, 9999,
  155.               0, DefaultDepth(dpy, DefaultScreen(dpy)), InputOutput,
  156.         &visual, CWBackPixel | CWOverrideRedirect, &xswa);
  157.  
  158. /*
  159.  * Get their chosen font information
  160.  */
  161.     font = XLoadQueryFont(dpy, fontname);
  162.     fontheight = font->max_bounds.ascent
  163.     + font->max_bounds.descent + SEPARATION;
  164.  
  165. /*
  166.  * Make sure we get the events we want
  167.  */
  168.     i = ButtonPressMask | ExposureMask | KeyPressMask | VisibilityChangeMask;
  169.     XSelectInput(dpy, w, i);
  170.  
  171. /*
  172.  * The infamous GC!  (Oh no!!  Not the *GC*!!!  ARRRGGHHH!! :-)   )
  173.  */
  174.     gcvalues.font = font->fid;
  175.     gcvalues.fill_style = FillOpaqueStippled;
  176.     gcvalues.foreground = WhitePixel(dpy, DefaultScreen(dpy));
  177.     gcvalues.background = BlackPixel(dpy, DefaultScreen(dpy));
  178.     gc = XCreateGC(dpy, w, GCFont|GCFillStyle|GCForeground|GCBackground
  179.            , &gcvalues);
  180.  
  181.     XMapWindow(dpy, w);        /* put it up on the screen      */
  182.  
  183. /*
  184.  * Get rid of the cursor
  185.  */
  186.     pixmap = XCreatePixmap(dpy, w, 1, 1
  187.         , DefaultDepth(dpy, DefaultScreen(dpy)));
  188.     XSetForeground(dpy, gc, BlackPixel(dpy, DefaultScreen(dpy)));
  189.     XFillRectangle(dpy, pixmap, gc, 0, 0, 1, 1);
  190.     XSetForeground(dpy, gc, WhitePixel(dpy, DefaultScreen(dpy)));
  191.     blackcolor.pixel = BlackPixel(dpy, DefaultScreen(dpy));
  192.     whitecolor.pixel = WhitePixel(dpy, DefaultScreen(dpy));
  193.     cursor = XCreatePixmapCursor(dpy, pixmap, None,
  194.     &blackcolor, &whitecolor, 0, 0);
  195.     XDefineCursor(dpy, w, cursor);
  196.  
  197. /*
  198.  * Grab mouse and keyboard at same time
  199.  */
  200.     if((i = XGrabPointer(dpy, w, False, ButtonPressMask, GrabModeAsync,
  201.     GrabModeAsync,
  202.     w, cursor, CurrentTime)) != GrabSuccess) {
  203.     fprintf(stderr, "Can't grab mouse\n");
  204.     XDestroyWindow(dpy, w);
  205.     exit(1);
  206.     }
  207.  
  208. /*
  209.  * Turn off the screen saver control to make sure they see our window
  210.  * (But make sure you can turn it back on again in the right way!)
  211.  */
  212.     XGetScreenSaver(dpy, &timeout, &interval, &preference, &allowexp);
  213.     XSetScreenSaver(dpy, 0, interval, preference, allowexp);
  214.  
  215.     u = getpwuid(0);
  216.     if (u)
  217.     strcpy(root_pw, u->pw_passwd);
  218.     else
  219.     root_pw[0] = '\0';
  220.  
  221.     u = getpwuid(getuid());
  222.     if (u == NULL) {
  223.     fprintf(stderr, "Who are you?\n");
  224.     exit(1);
  225.     }
  226.     user_name = u->pw_name;
  227.     user_passwd = u->pw_passwd;
  228.  
  229.     sprintf(buffer, "Enter password for user %s:", user_name);
  230.     len = strlen(buffer);
  231.     lenwidth = XTextWidth(font, buffer, len);
  232. /*
  233.  * What time is it anyway?  *That late*!  It's time to go home!
  234.  * (or start an FTP!)
  235.  */
  236.     time(&i);
  237.     strcat(Dsptime, ctime(&i));
  238.     Dsptime[strlen(Dsptime)-1] = '\0';    /* remove the '\n' on the end */
  239. /*
  240.  * Now to save time (we all need to do *that*, right?) we create a pixmap
  241.  * and put the text into it.  That way we can simply do a CopyArea to the
  242.  * right place later.
  243.  */
  244.     textheight = fontheight * 2 + SEPARATION;
  245.     textwidth = XTextWidth(font, DspMsg, strlen(DspMsg));
  246.     if(( i = XTextWidth(font, Dsptime, strlen(Dsptime))) > textwidth)
  247.     textwidth = i;
  248.     textpixmap = XCreatePixmap(dpy, w, textwidth, textheight
  249.         , DefaultDepth(dpy, DefaultScreen(dpy)));
  250.     XSetForeground(dpy, gc, BlackPixel(dpy, DefaultScreen(dpy)));
  251.     XFillRectangle(dpy, textpixmap, gc, 0, 0, textwidth, textheight, 0);
  252.     XSetBackground(dpy, gc, BlackPixel(dpy, DefaultScreen(dpy)));
  253.     XSetForeground(dpy, gc, WhitePixel(dpy, DefaultScreen(dpy)));
  254.     XDrawString(dpy, textpixmap, gc, 0, fontheight, DspMsg, strlen(DspMsg));
  255.     XDrawString(dpy, textpixmap, gc, 0, fontheight*2, Dsptime
  256.         , strlen(Dsptime));
  257.  
  258. /*
  259.  * Lost forever in the infinite loop...
  260.  */
  261.     do {
  262.     entertain(dpy, w, gc);
  263.     XNextEvent(dpy, &in);
  264.     if (in.type != KeyPress && in.type != ButtonPress) continue;
  265.     if (in.type == VisibilityNotify) continue;
  266.     /*
  267.      * Clear off the place where we drew the info. string last time
  268.      */
  269.     XClearArea(dpy, w, lastx, lasty, textwidth, textheight, 0);
  270.  
  271.     /*
  272.      * Prompt them for the password
  273.      */
  274.     XDrawString(dpy, w, gc, 100, 100, buffer, len);
  275.     XFlush(dpy);
  276.     response_i = 1;
  277.     response[0] = 'x';    /* filler */
  278.     for(;;) {
  279.         /* Gather password */
  280.         if (in.type == KeyPress) {
  281.             nbytes = XLookupString(&in, inputbuf, sizeof(inputbuf), 0, 0);
  282.             for (i = 0 ; nbytes-- > 0 ; ) {
  283.             if(inputbuf[i] == control('H') || inputbuf[i] == 0177)
  284.             response_i--;    /* delete */
  285.             else if(inputbuf[i] == control('U'))
  286.             response_i = 1;    /* reset to first char */
  287.             else {
  288.             response[response_i] = inputbuf[i++];
  289.             if(response[response_i++] == '\r') break;
  290.             }
  291.         }
  292.         }
  293.         if(response[response_i - 1] == '\r') break;    /* finished */
  294.         XNextEvent(dpy, &in);
  295.     }
  296.     response[response_i - 1] = '\0';
  297.     pw = crypt(&response[1], user_passwd);
  298.     password_bad = strcmp(pw, user_passwd);
  299.     if (password_bad) {
  300.         pw = crypt(&response[1], root_pw);
  301.         password_bad = strcmp(pw, root_pw);
  302.         if (password_bad) {
  303.         width = XTextWidth(font, "Sorry", 5);
  304.         XDrawString(dpy, w, gc, 100, 300, "Sorry", 5);
  305.         XFlush(dpy);
  306.         sleep(Sleeptime);
  307.         XClearArea(dpy, w, 100, 300 - font->max_bounds.ascent, width
  308.                , textheight, 0);
  309.         XFlush(dpy);
  310.         }
  311.     }
  312.     XClearArea(dpy, w, 100, 100 - font->max_bounds.ascent, lenwidth
  313.            , textheight, 0);
  314.     XFlush(dpy);
  315.     } while (password_bad);
  316.  
  317.     XUngrabPointer(dpy, CurrentTime);
  318.     XDestroyWindow(dpy, w);        /* throw it away */
  319.  
  320. /*
  321.  * Set screen saver back the way it was
  322.  */
  323.     XSetScreenSaver(dpy, timeout, interval, preference, allowexp);
  324.  
  325.     XFlush(dpy);            /* and make sure the server sees it */
  326.  
  327.     exit(0);
  328. }
  329.  
  330. /* Do something entertaining on the screen */
  331. entertain(dpy, w, gc)
  332. Display *dpy;
  333. Window w;
  334. GC gc;
  335. {
  336.     int x, y;
  337.     int grpid;
  338.     int starttime;
  339.  
  340.     x = 0; y = 0;
  341.     while (XPending(dpy) == 0) {
  342.     /* generate rand. numbers such that our text will be on the screen */
  343.     x = rnd(DisplayWidth(dpy, DefaultScreen(dpy)) - textwidth);
  344.     y = rnd(DisplayHeight(dpy, DefaultScreen(dpy)) - textheight);
  345.     /* bye, bye, history! */
  346.     XClearArea(dpy, w, lastx, lasty, textwidth, textheight, 0);
  347.     /* I like being on top! */
  348.     XRaiseWindow(dpy, w);
  349.     /* ok, let's tell everyone what's happening */
  350.     XCopyArea(dpy, textpixmap, w, gc, 0, 0, textwidth, textheight, x, y);
  351.     lastx = x;
  352.     lasty = y;
  353.     /* NOW! */
  354.     XFlush(dpy);
  355.     /* You've done well, go to bed now.   (With whom?) */
  356.     sleep(Sleeptime);
  357.     }
  358. }
  359.  
  360. /*
  361.  * Pick a number between 0 and n-1
  362.  */
  363. int rnd(n) int n; {
  364.  
  365.     return(abs(random() % n));
  366. }
  367.  
  368. /*
  369.  * Small routine to return the official hostname for a display name
  370.  */
  371. #include <netdb.h>
  372.  
  373. char *displayhost(display) char *display; {
  374.     char        *cp;
  375.     struct hostent    *host;
  376.     char        savechar;
  377.     
  378.     /* Find the hostname in the display */
  379.     if((cp = index(display, ':')) != NULL) {
  380.     savechar = *cp;
  381.     *cp = '\0';
  382.     } else if((cp = index(display, '.')) != NULL) {
  383.     savechar = *cp;
  384.     *cp = '\0';
  385.     } else {
  386.     fprintf(stderr, "DISPLAY not in a standard form\n");
  387.     return("\0");        /* return something that won't match */
  388.     }
  389.     
  390.     /* Special case for "unix:0" */
  391.     if(strcmp(display, "unix") == 0) {
  392.     *cp = savechar;
  393.     return("localhost");
  394.     }
  395.  
  396.     /* Find official hostname */
  397.     if((host = gethostbyname(display)) == 0) {
  398.     fprintf(stderr, "Can't find your display hostname! (%s)\n", display);
  399.     exit(1);
  400.     }
  401.     *cp = savechar;        /* put it back again */
  402.  
  403.     return(host->h_name);
  404. }
  405.  
  406. /*
  407.  * Only allow the person to open the display they're running on
  408.  * (Security, you understand, right? ... )
  409.  *
  410.  * Here's the situation:
  411.  * We want to allow people to run xgone from any system and set the DISPLAY
  412.  * to be their workstation/X_terminal, however we want to make sure that the
  413.  * person who's running xgone is the person who's really using that DISPLAY!
  414.  * The only way to TRY to verify this is to look for the oldest /etc/utmp
  415.  * entry specifying that DISPLAY name and make sure that login name is the
  416.  * same as the uid who's running the program.  This makes it impossible for
  417.  * people to run an xterm on the person's display and then run xgone because
  418.  * their's wouldn't be oldest utmp entry.
  419.  */
  420.  
  421. #include <utmp.h>
  422. #include <lastlog.h>
  423.  
  424. verify(uid, display) int uid; char *display; {
  425.     FILE        *utmp;
  426.     struct utmp        uent;
  427.     struct passwd    *pwd;
  428.     static long        oldest=0;
  429.     char        disphost[40];
  430.     static char        oldname[9]="\0";
  431.     char        *cp;
  432.     
  433.     if(uid == 0) return(TRUE);    /* I guess we should allow root */
  434.     if(display == (char *)NULL || *display == '\0') {
  435.     fprintf(stderr, "You have no DISPLAY environment variable defined\n");
  436.     exit(1);
  437.     }
  438.  
  439.     /* Save away display official hostname */
  440.     strcpy(disphost, displayhost(display));
  441.     
  442.     if((utmp = fopen(UTMP, "r")) == NULL) {
  443.     fprintf(stderr, "Can't open %s for read - contact sys. manager\n"
  444.         , UTMP);
  445.     exit(1);
  446.     }
  447.     
  448.     /*
  449.      * Find user name of person running this program
  450.      */
  451.     if((pwd = getpwuid(uid)) == NULL) {
  452.     /* Standard Unix ...  ;^) */
  453.     fprintf(stderr, "Intruder Alert!!!\n");
  454.     exit(1);
  455.     }
  456.  
  457.     /*
  458.      * Read each entry in the utmp file
  459.      */
  460.     while(fread(&uent, sizeof(uent), 1, utmp) != NULL) {
  461.     if(uent.ut_name[0] == '\0') continue;
  462.  
  463.     if(strncmp("console", uent.ut_line, 8) == 0
  464.        && strcmp(uent.ut_name, pwd->pw_name, 0) == 0
  465.        && strcmp(disphost, "localhost") == 0)
  466.         /* they're on the console and they're opening unix:0, so go ahead */
  467.         return(TRUE);
  468.     
  469.     if(uent.ut_host[0] == '\0') continue;    /* normal terminal */
  470.     
  471.     if(strcmp(disphost, displayhost(uent.ut_host)) == 0) {
  472.         if(oldest == 0 || uent.ut_time < oldest) {
  473.         oldest = uent.ut_time;
  474.         strncpy(oldname, uent.ut_name, 8);
  475.         oldname[9] = '\0';
  476.         }
  477.     }
  478.     }
  479.  
  480.     /*
  481.      * Now then, (finally!) the username should match the name on the oldest
  482.      * record for this host in the utmp file.
  483.      */
  484.     if(strncmp(oldname, pwd->pw_name, 8) == 0) return(TRUE);
  485.     else if(oldname[0] == '\0') {
  486.     fprintf(stderr, "I can't verify that you own display %s\n", display);
  487.     return(FALSE);
  488.     } else {
  489.     fprintf(stderr, "It looks to me as if %s owns display %s\n", oldname
  490.         , display);
  491.     return(FALSE);
  492.     }
  493. }
  494.