home *** CD-ROM | disk | FTP | other *** search
- /*
- * Lockscreen for X windows
- * Tim Morgan 2/25/87
- *
- * Modified for X11 by Richard Johnson
- * Modified/Rewritten extensively afterwards.
- */
-
- #include <X11/Xlib.h>
- #include <stdio.h>
- #include <pwd.h>
- #include <signal.h>
- #include <X11/Xos.h>
-
- #define SLEEP_TIME 2 /* Seconds, of course */
- #define FONT "fixed" /* BORING! (but always there) */
- #define SEPARATION 2 /* ... between lines */
- #define DISPLAYNAME ""
- #define DELAYTIME 2 /* delay time for "-delay" option */
- #define FALSE 0
- #define TRUE 1
- #define UTMP "/etc/utmp" /* the utmp file */
- #define control(a) ((a) - ('@')) /* control characters */
-
- char DspMsg[1024]="X Gone"; /* Default message to display */
- char *Dsptime="Started: "; /* Time command was started */
- int fontheight; /* height of one line of text */
- Pixmap textpixmap; /* pixmap to hold text */
- int textwidth, textheight; /* sizes of whole text area */
- int Sleeptime=SLEEP_TIME; /* sleep time between updates */
- int Delay=FALSE; /* Delay startup (for twm) */
- int lastx=0, lasty=0; /* last coord's of text */
- fd_set select_mask, sel_mask; /* for select stuff */
- int select_bits; /* width of select_mask */
- struct timeval sleeptime; /* for selects */
- char *index(); /* from C lib. */
-
- main(argc, argv)
- int argc;
- char *argv[];
- {
- Display *dpy;
- XSetWindowAttributes xswa;
- Visual visual;
- Window w;
- GC gc;
- XGCValues gcvalues;
- XEvent in;
- XFontStruct *font;
- XColor blackcolor;
- XColor whitecolor;
- Pixmap pixmap;
- Cursor cursor;
- char buffer[100], inputbuf[80], *string, *user_name
- ,*getenv(), *ctime(), *rindex(), response[100];
- char *crypt(), *pw, root_pw[20], *user_passwd;
- int len, password_bad = 1, response_i, nbytes, i;
- struct passwd *u;
- char *myname, *dspptr;
- short *bits;
- int width, lenwidth;
- int timeout, interval,
- preference, allowexp;
- static char fontname[80]={FONT};
-
- if((myname = rindex(argv[0], '/')) == NULL)
- myname = argv[0];
- else
- myname++;
-
- if (! verify(getuid(), getenv("DISPLAY"))) {
- fprintf(stderr, "I can't open that display - sorry...\n");
- exit(1);
- }
-
- if ((dpy = XOpenDisplay(DISPLAYNAME)) == NULL) {
- fprintf(stderr, "%s: Can't open display '%s'\n",
- myname, XDisplayName(DISPLAYNAME));
- exit(1);
- }
- /*
- * Get the defaults
- */
- if((string = XGetDefault(dpy, myname, "Font")) != NULL)
- strcpy(fontname, string);
- if((string = XGetDefault(dpy, myname, "Text")) != NULL)
- strcpy(DspMsg, string);
- if((string = XGetDefault(dpy, myname, "Sleep")) != NULL)
- Sleeptime = atoi(string);
- if((string = XGetDefault(dpy, myname, "Update")) != NULL)
- Sleeptime = atoi(string);
- if((string = XGetDefault(dpy, myname, "Delay")) != NULL)
- if(strcmp(string, "off") == 0 || strcmp(string, "0") == 0
- || strcmp(string, "no") == 0)
- Delay = FALSE;
- else
- Delay = TRUE;
-
- /*
- * Parse arguments
- */
- for(--argc , ++argv ; *argv && **argv == '-' ; argv++ , argc--) {
- ++*argv;
- if(strcmp(*argv, "fn") == 0 || strncmp(*argv, "font", 1) == 0)
- strcpy(fontname, *++argv); /* save font name */
- else if(strncmp(*argv, "sleep", 1) == 0
- || strncmp(*argv, "update", 1) == 0)
- Sleeptime = atoi(*++argv);
- else if(strncmp(*argv, "delay", 1) == 0)
- Delay = TRUE;
- }
-
- /*
- * If we should delay startup, then fork and exit the parent right now.
- * (This way, "twm" changes the cursor back to the original one and lets
- * go of the mouse so that we can grab it.)
- */
- if(Delay)
- switch(fork()) {
- case 0: /* child - continue with program */
- sleep(DELAYTIME);
- break;
-
- case -1: /* error during fork - exit */
- fprintf(stderr, "Can't fork - ");
- perror("");
- exit(1);
-
- default: /* parent - exit */
- exit(0);
- }
-
- /*
- * Get the message
- */
- dspptr = DspMsg;
- if( *argv ) strcpy(dspptr, "\0");
- while( *argv ) {
- strcat(dspptr, *argv++);
- strcat(dspptr, " ");
- }
-
- /*
- * Set random number generator
- */
- srandom(time(0));
-
- /*
- * Make a big window to cover the screen
- */
- xswa.background_pixel = BlackPixel(dpy, DefaultScreen(dpy));
- xswa.override_redirect = True;
- visual.visualid = CopyFromParent;
- w = XCreateWindow(dpy, DefaultRootWindow(dpy), 0, 0, 9999, 9999,
- 0, DefaultDepth(dpy, DefaultScreen(dpy)), InputOutput,
- &visual, CWBackPixel | CWOverrideRedirect, &xswa);
-
- /*
- * Get their chosen font information
- */
- font = XLoadQueryFont(dpy, fontname);
- fontheight = font->max_bounds.ascent
- + font->max_bounds.descent + SEPARATION;
-
- /*
- * Make sure we get the events we want
- */
- i = ButtonPressMask | ExposureMask | KeyPressMask | VisibilityChangeMask;
- XSelectInput(dpy, w, i);
-
- /*
- * The infamous GC! (Oh no!! Not the *GC*!!! ARRRGGHHH!! :-) )
- */
- gcvalues.font = font->fid;
- gcvalues.fill_style = FillOpaqueStippled;
- gcvalues.foreground = WhitePixel(dpy, DefaultScreen(dpy));
- gcvalues.background = BlackPixel(dpy, DefaultScreen(dpy));
- gc = XCreateGC(dpy, w, GCFont|GCFillStyle|GCForeground|GCBackground
- , &gcvalues);
-
- XMapWindow(dpy, w); /* put it up on the screen */
-
- /*
- * Get rid of the cursor
- */
- pixmap = XCreatePixmap(dpy, w, 1, 1
- , DefaultDepth(dpy, DefaultScreen(dpy)));
- XSetForeground(dpy, gc, BlackPixel(dpy, DefaultScreen(dpy)));
- XFillRectangle(dpy, pixmap, gc, 0, 0, 1, 1);
- XSetForeground(dpy, gc, WhitePixel(dpy, DefaultScreen(dpy)));
- blackcolor.pixel = BlackPixel(dpy, DefaultScreen(dpy));
- whitecolor.pixel = WhitePixel(dpy, DefaultScreen(dpy));
- cursor = XCreatePixmapCursor(dpy, pixmap, None,
- &blackcolor, &whitecolor, 0, 0);
- XDefineCursor(dpy, w, cursor);
-
- /*
- * Grab mouse and keyboard at same time
- */
- if((i = XGrabPointer(dpy, w, False, ButtonPressMask, GrabModeAsync,
- GrabModeAsync,
- w, cursor, CurrentTime)) != GrabSuccess) {
- fprintf(stderr, "Can't grab mouse\n");
- XDestroyWindow(dpy, w);
- exit(1);
- }
-
- /*
- * Turn off the screen saver control to make sure they see our window
- * (But make sure you can turn it back on again in the right way!)
- */
- XGetScreenSaver(dpy, &timeout, &interval, &preference, &allowexp);
- XSetScreenSaver(dpy, 0, interval, preference, allowexp);
-
- u = getpwuid(0);
- if (u)
- strcpy(root_pw, u->pw_passwd);
- else
- root_pw[0] = '\0';
-
- u = getpwuid(getuid());
- if (u == NULL) {
- fprintf(stderr, "Who are you?\n");
- exit(1);
- }
- user_name = u->pw_name;
- user_passwd = u->pw_passwd;
-
- sprintf(buffer, "Enter password for user %s:", user_name);
- len = strlen(buffer);
- lenwidth = XTextWidth(font, buffer, len);
- /*
- * What time is it anyway? *That late*! It's time to go home!
- * (or start an FTP!)
- */
- time(&i);
- strcat(Dsptime, ctime(&i));
- Dsptime[strlen(Dsptime)-1] = '\0'; /* remove the '\n' on the end */
- /*
- * Now to save time (we all need to do *that*, right?) we create a pixmap
- * and put the text into it. That way we can simply do a CopyArea to the
- * right place later.
- */
- textheight = fontheight * 2 + SEPARATION;
- textwidth = XTextWidth(font, DspMsg, strlen(DspMsg));
- if(( i = XTextWidth(font, Dsptime, strlen(Dsptime))) > textwidth)
- textwidth = i;
- textpixmap = XCreatePixmap(dpy, w, textwidth, textheight
- , DefaultDepth(dpy, DefaultScreen(dpy)));
- XSetForeground(dpy, gc, BlackPixel(dpy, DefaultScreen(dpy)));
- XFillRectangle(dpy, textpixmap, gc, 0, 0, textwidth, textheight, 0);
- XSetBackground(dpy, gc, BlackPixel(dpy, DefaultScreen(dpy)));
- XSetForeground(dpy, gc, WhitePixel(dpy, DefaultScreen(dpy)));
- XDrawString(dpy, textpixmap, gc, 0, fontheight, DspMsg, strlen(DspMsg));
- XDrawString(dpy, textpixmap, gc, 0, fontheight*2, Dsptime
- , strlen(Dsptime));
-
- /*
- * Lost forever in the infinite loop...
- */
- do {
- entertain(dpy, w, gc);
- XNextEvent(dpy, &in);
- if (in.type != KeyPress && in.type != ButtonPress) continue;
- if (in.type == VisibilityNotify) continue;
- /*
- * Clear off the place where we drew the info. string last time
- */
- XClearArea(dpy, w, lastx, lasty, textwidth, textheight, 0);
-
- /*
- * Prompt them for the password
- */
- XDrawString(dpy, w, gc, 100, 100, buffer, len);
- XFlush(dpy);
- response_i = 1;
- response[0] = 'x'; /* filler */
- for(;;) {
- /* Gather password */
- if (in.type == KeyPress) {
- nbytes = XLookupString(&in, inputbuf, sizeof(inputbuf), 0, 0);
- for (i = 0 ; nbytes-- > 0 ; ) {
- if(inputbuf[i] == control('H') || inputbuf[i] == 0177)
- response_i--; /* delete */
- else if(inputbuf[i] == control('U'))
- response_i = 1; /* reset to first char */
- else {
- response[response_i] = inputbuf[i++];
- if(response[response_i++] == '\r') break;
- }
- }
- }
- if(response[response_i - 1] == '\r') break; /* finished */
- XNextEvent(dpy, &in);
- }
- response[response_i - 1] = '\0';
- pw = crypt(&response[1], user_passwd);
- password_bad = strcmp(pw, user_passwd);
- if (password_bad) {
- pw = crypt(&response[1], root_pw);
- password_bad = strcmp(pw, root_pw);
- if (password_bad) {
- width = XTextWidth(font, "Sorry", 5);
- XDrawString(dpy, w, gc, 100, 300, "Sorry", 5);
- XFlush(dpy);
- sleep(Sleeptime);
- XClearArea(dpy, w, 100, 300 - font->max_bounds.ascent, width
- , textheight, 0);
- XFlush(dpy);
- }
- }
- XClearArea(dpy, w, 100, 100 - font->max_bounds.ascent, lenwidth
- , textheight, 0);
- XFlush(dpy);
- } while (password_bad);
-
- XUngrabPointer(dpy, CurrentTime);
- XDestroyWindow(dpy, w); /* throw it away */
-
- /*
- * Set screen saver back the way it was
- */
- XSetScreenSaver(dpy, timeout, interval, preference, allowexp);
-
- XFlush(dpy); /* and make sure the server sees it */
-
- exit(0);
- }
-
- /* Do something entertaining on the screen */
- entertain(dpy, w, gc)
- Display *dpy;
- Window w;
- GC gc;
- {
- int x, y;
- int grpid;
- int starttime;
-
- x = 0; y = 0;
- while (XPending(dpy) == 0) {
- /* generate rand. numbers such that our text will be on the screen */
- x = rnd(DisplayWidth(dpy, DefaultScreen(dpy)) - textwidth);
- y = rnd(DisplayHeight(dpy, DefaultScreen(dpy)) - textheight);
- /* bye, bye, history! */
- XClearArea(dpy, w, lastx, lasty, textwidth, textheight, 0);
- /* I like being on top! */
- XRaiseWindow(dpy, w);
- /* ok, let's tell everyone what's happening */
- XCopyArea(dpy, textpixmap, w, gc, 0, 0, textwidth, textheight, x, y);
- lastx = x;
- lasty = y;
- /* NOW! */
- XFlush(dpy);
- /* You've done well, go to bed now. (With whom?) */
- sleep(Sleeptime);
- }
- }
-
- /*
- * Pick a number between 0 and n-1
- */
- int rnd(n) int n; {
-
- return(abs(random() % n));
- }
-
- /*
- * Small routine to return the official hostname for a display name
- */
- #include <netdb.h>
-
- char *displayhost(display) char *display; {
- char *cp;
- struct hostent *host;
- char savechar;
-
- /* Find the hostname in the display */
- if((cp = index(display, ':')) != NULL) {
- savechar = *cp;
- *cp = '\0';
- } else if((cp = index(display, '.')) != NULL) {
- savechar = *cp;
- *cp = '\0';
- } else {
- fprintf(stderr, "DISPLAY not in a standard form\n");
- return("\0"); /* return something that won't match */
- }
-
- /* Special case for "unix:0" */
- if(strcmp(display, "unix") == 0) {
- *cp = savechar;
- return("localhost");
- }
-
- /* Find official hostname */
- if((host = gethostbyname(display)) == 0) {
- fprintf(stderr, "Can't find your display hostname! (%s)\n", display);
- exit(1);
- }
- *cp = savechar; /* put it back again */
-
- return(host->h_name);
- }
-
- /*
- * Only allow the person to open the display they're running on
- * (Security, you understand, right? ... )
- *
- * Here's the situation:
- * We want to allow people to run xgone from any system and set the DISPLAY
- * to be their workstation/X_terminal, however we want to make sure that the
- * person who's running xgone is the person who's really using that DISPLAY!
- * The only way to TRY to verify this is to look for the oldest /etc/utmp
- * entry specifying that DISPLAY name and make sure that login name is the
- * same as the uid who's running the program. This makes it impossible for
- * people to run an xterm on the person's display and then run xgone because
- * their's wouldn't be oldest utmp entry.
- */
-
- #include <utmp.h>
- #include <lastlog.h>
-
- verify(uid, display) int uid; char *display; {
- FILE *utmp;
- struct utmp uent;
- struct passwd *pwd;
- static long oldest=0;
- char disphost[40];
- static char oldname[9]="\0";
- char *cp;
-
- if(uid == 0) return(TRUE); /* I guess we should allow root */
- if(display == (char *)NULL || *display == '\0') {
- fprintf(stderr, "You have no DISPLAY environment variable defined\n");
- exit(1);
- }
-
- /* Save away display official hostname */
- strcpy(disphost, displayhost(display));
-
- if((utmp = fopen(UTMP, "r")) == NULL) {
- fprintf(stderr, "Can't open %s for read - contact sys. manager\n"
- , UTMP);
- exit(1);
- }
-
- /*
- * Find user name of person running this program
- */
- if((pwd = getpwuid(uid)) == NULL) {
- /* Standard Unix ... ;^) */
- fprintf(stderr, "Intruder Alert!!!\n");
- exit(1);
- }
-
- /*
- * Read each entry in the utmp file
- */
- while(fread(&uent, sizeof(uent), 1, utmp) != NULL) {
- if(uent.ut_name[0] == '\0') continue;
-
- if(strncmp("console", uent.ut_line, 8) == 0
- && strcmp(uent.ut_name, pwd->pw_name, 0) == 0
- && strcmp(disphost, "localhost") == 0)
- /* they're on the console and they're opening unix:0, so go ahead */
- return(TRUE);
-
- if(uent.ut_host[0] == '\0') continue; /* normal terminal */
-
- if(strcmp(disphost, displayhost(uent.ut_host)) == 0) {
- if(oldest == 0 || uent.ut_time < oldest) {
- oldest = uent.ut_time;
- strncpy(oldname, uent.ut_name, 8);
- oldname[9] = '\0';
- }
- }
- }
-
- /*
- * Now then, (finally!) the username should match the name on the oldest
- * record for this host in the utmp file.
- */
- if(strncmp(oldname, pwd->pw_name, 8) == 0) return(TRUE);
- else if(oldname[0] == '\0') {
- fprintf(stderr, "I can't verify that you own display %s\n", display);
- return(FALSE);
- } else {
- fprintf(stderr, "It looks to me as if %s owns display %s\n", oldname
- , display);
- return(FALSE);
- }
- }
-