1 /* lock.c --- handling the password dialog for locking-mode.
2 * xscreensaver, Copyright (c) 1993-1998 Jamie Zawinski <jwz@jwz.org>
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
13 /* Athena locking code contributed by Jon A. Christopher <jac8782@tamu.edu> */
14 /* Copyright 1997, with the same permissions as above. */
20 #include <X11/Intrinsic.h>
21 #include <X11/Xos.h> /* for time() */
22 #include "xscreensaver.h"
23 #include "resources.h"
25 #ifndef NO_LOCKING /* (mostly) whole file */
29 #endif /* HAVE_SYSLOG */
31 #ifdef HAVE_XHPDISABLERESET
32 # include <X11/XHPlib.h>
33 static void hp_lock_reset (saver_info *si, Bool lock_p);
34 #endif /* HAVE_XHPDISABLERESET */
36 #ifdef HAVE_VT_LOCKSWITCH
38 # include <sys/ioctl.h>
40 static void linux_lock_vt_switch (saver_info *si, Bool lock_p);
41 #endif /* HAVE_VT_LOCKSWITCH */
44 # include <X11/extensions/xf86vmode.h>
45 static void xfree_lock_mode_switch (saver_info *si, Bool lock_p);
46 #endif /* HAVE_XF86VMODE */
50 ERROR! You must not include vroot.h in this file.
57 extern char *getenv(const char *name);
58 extern int validate_user(char *name, char *password);
61 vms_passwd_valid_p(char *pw, Bool verbose_p)
63 return (validate_user (getenv("USER"), typed_passwd) == 1);
65 # undef passwd_valid_p
66 # define passwd_valid_p vms_passwd_valid_p
72 #define MAX(a,b) ((a)>(b)?(a):(b))
74 enum passwd_state { pw_read, pw_ok, pw_null, pw_fail, pw_cancel, pw_time };
76 struct passwd_dialog_data {
78 enum passwd_state state;
79 char typed_passwd [80];
87 Dimension border_width;
97 XFontStruct *heading_font;
98 XFontStruct *body_font;
99 XFontStruct *label_font;
100 XFontStruct *passwd_font;
101 XFontStruct *date_font;
105 Pixel passwd_foreground;
106 Pixel passwd_background;
107 Pixel logo_foreground;
108 Pixel logo_background;
112 Dimension logo_width;
113 Dimension logo_height;
114 Dimension thermo_width;
115 Dimension internal_border;
116 Dimension shadow_width;
118 Dimension passwd_field_x, passwd_field_y;
119 Dimension passwd_field_width, passwd_field_height;
121 Dimension thermo_field_x, thermo_field_y;
122 Dimension thermo_field_height;
127 static void draw_passwd_window (saver_info *si);
128 static void update_passwd_window (saver_info *si, const char *printed_passwd,
130 static void destroy_passwd_window (saver_info *si);
131 static void undo_vp_motion (saver_info *si);
135 make_passwd_window (saver_info *si)
137 struct passwd *p = getpwuid (getuid ());
138 XSetWindowAttributes attrs;
139 unsigned long attrmask = 0;
140 Screen *screen = si->default_screen->screen;
141 passwd_dialog_data *pw = (passwd_dialog_data *) calloc (1, sizeof(*pw));
142 Colormap cmap = DefaultColormapOfScreen (screen);
147 pw->heading_label = get_string_resource ("passwd.heading.label",
148 "Dialog.Label.Label");
149 pw->body_label = get_string_resource ("passwd.body.label",
150 "Dialog.Label.Label");
151 pw->user_label = get_string_resource ("passwd.user.label",
152 "Dialog.Label.Label");
153 pw->passwd_label = get_string_resource ("passwd.passwd.label",
154 "Dialog.Label.Label");
155 pw->date_label = get_string_resource ("dateFormat", "DateFormat");
157 if (!pw->heading_label)
158 pw->heading_label = strdup("ERROR: REESOURCES NOT INSTALLED CORRECTLY");
160 pw->body_label = strdup("ERROR: REESOURCES NOT INSTALLED CORRECTLY");
161 if (!pw->user_label) pw->user_label = strdup("ERROR");
162 if (!pw->passwd_label) pw->passwd_label = strdup("ERROR");
163 if (!pw->date_label) pw->date_label = strdup("ERROR");
165 /* Put the version number in the label. */
167 char *s = (char *) malloc (strlen(pw->heading_label) + 20);
168 sprintf(s, pw->heading_label, si->version);
169 free (pw->heading_label);
170 pw->heading_label = s;
173 pw->user_string = (p && p->pw_name ? p->pw_name : "???");
174 pw->passwd_string = strdup("");
176 f = get_string_resource ("passwd.headingFont", "Dialog.Font");
177 pw->heading_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
178 if (!pw->heading_font) pw->heading_font = XLoadQueryFont (si->dpy, "fixed");
181 f = get_string_resource("passwd.bodyFont", "Dialog.Font");
182 pw->body_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
183 if (!pw->body_font) pw->body_font = XLoadQueryFont (si->dpy, "fixed");
186 f = get_string_resource("passwd.labelFont", "Dialog.Font");
187 pw->label_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
188 if (!pw->label_font) pw->label_font = XLoadQueryFont (si->dpy, "fixed");
191 f = get_string_resource("passwd.passwdFont", "Dialog.Font");
192 pw->passwd_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
193 if (!pw->passwd_font) pw->passwd_font = XLoadQueryFont (si->dpy, "fixed");
196 f = get_string_resource("passwd.dateFont", "Dialog.Font");
197 pw->date_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
198 if (!pw->date_font) pw->date_font = XLoadQueryFont (si->dpy, "fixed");
201 pw->foreground = get_pixel_resource ("passwd.foreground",
204 pw->background = get_pixel_resource ("passwd.background",
208 if (pw->foreground == pw->background)
210 /* Make sure the error messages show up. */
211 pw->foreground = BlackPixelOfScreen (screen);
212 pw->background = WhitePixelOfScreen (screen);
215 pw->passwd_foreground = get_pixel_resource ("passwd.text.foreground",
216 "Dialog.Text.Foreground",
218 pw->passwd_background = get_pixel_resource ("passwd.text.background",
219 "Dialog.Text.Background",
221 pw->logo_foreground = get_pixel_resource ("passwd.logo.foreground",
222 "Dialog.Logo.Foreground",
224 pw->logo_background = get_pixel_resource ("passwd.logo.background",
225 "Dialog.Logo.Background",
227 pw->shadow_top = get_pixel_resource ("passwd.topShadowColor",
230 pw->shadow_bottom = get_pixel_resource ("passwd.bottomShadowColor",
234 pw->logo_width = get_integer_resource ("passwd.logo.width",
235 "Dialog.Logo.Width");
236 pw->logo_height = get_integer_resource ("passwd.logo.height",
237 "Dialog.Logo.Height");
238 pw->thermo_width = get_integer_resource ("passwd.thermometer.width",
239 "Dialog.Thermometer.Width");
240 pw->internal_border = get_integer_resource ("passwd.internalBorderWidth",
241 "Dialog.InternalBorderWidth");
242 pw->shadow_width = get_integer_resource ("passwd.shadowThickness",
243 "Dialog.ShadowThickness");
245 if (pw->logo_width == 0) pw->logo_width = 150;
246 if (pw->logo_height == 0) pw->logo_height = 150;
247 if (pw->internal_border == 0) pw->internal_border = 15;
248 if (pw->shadow_width == 0) pw->shadow_width = 4;
249 if (pw->thermo_width == 0) pw->thermo_width = pw->shadow_width;
252 int direction, ascent, descent;
258 /* Measure the heading_label. */
259 XTextExtents (pw->heading_font,
260 pw->heading_label, strlen(pw->heading_label),
261 &direction, &ascent, &descent, &overall);
262 if (overall.width > pw->width) pw->width = overall.width;
263 pw->height += ascent + descent;
265 /* Measure the body_label. */
266 XTextExtents (pw->body_font,
267 pw->body_label, strlen(pw->body_label),
268 &direction, &ascent, &descent, &overall);
269 if (overall.width > pw->width) pw->width = overall.width;
270 pw->height += ascent + descent;
273 Dimension w2 = 0, w3 = 0;
274 Dimension h2 = 0, h3 = 0;
275 const char *passwd_string = "MMMMMMMMMMMM";
277 /* Measure the user_label. */
278 XTextExtents (pw->label_font,
279 pw->user_label, strlen(pw->user_label),
280 &direction, &ascent, &descent, &overall);
281 if (overall.width > w2) w2 = overall.width;
282 h2 += ascent + descent;
284 /* Measure the passwd_label. */
285 XTextExtents (pw->label_font,
286 pw->passwd_label, strlen(pw->passwd_label),
287 &direction, &ascent, &descent, &overall);
288 if (overall.width > w2) w2 = overall.width;
289 h2 += ascent + descent;
291 /* Measure the user_string. */
292 XTextExtents (pw->passwd_font,
293 pw->user_string, strlen(pw->user_string),
294 &direction, &ascent, &descent, &overall);
295 overall.width += (pw->shadow_width * 4);
296 ascent += (pw->shadow_width * 4);
297 if (overall.width > w3) w3 = overall.width;
298 h3 += ascent + descent;
300 /* Measure the (maximally-sized, dummy) passwd_string. */
301 XTextExtents (pw->passwd_font,
302 passwd_string, strlen(passwd_string),
303 &direction, &ascent, &descent, &overall);
304 overall.width += (pw->shadow_width * 4);
305 ascent += (pw->shadow_width * 4);
306 if (overall.width > w3) w3 = overall.width;
307 h3 += ascent + descent;
309 w2 = w2 + w3 + (pw->shadow_width * 2);
312 if (w2 > pw->width) pw->width = w2;
316 pw->width += (pw->internal_border * 2);
317 pw->height += (pw->internal_border * 4);
319 pw->width += pw->thermo_width + (pw->shadow_width * 3);
321 if (pw->logo_height > pw->height)
322 pw->height = pw->logo_height;
323 else if (pw->height > pw->logo_height)
324 pw->logo_height = pw->height;
326 pw->logo_width = pw->logo_height;
328 pw->width += pw->logo_width;
331 attrmask |= CWOverrideRedirect; attrs.override_redirect = True;
332 attrmask |= CWEventMask; attrs.event_mask = ExposureMask|KeyPressMask;
336 get_screen_viewport (si->default_screen, &x, &y, &w, &h, False);
337 if (si->prefs.debug_p) w /= 2;
338 pw->x = x + ((w + pw->width) / 2) - pw->width;
339 pw->y = y + ((h + pw->height) / 2) - pw->height;
340 if (pw->x < x) pw->x = x;
341 if (pw->y < y) pw->y = y;
344 pw->border_width = get_integer_resource ("passwd.borderWidth",
345 "Dialog.BorderWidth");
348 XCreateWindow (si->dpy,
349 RootWindowOfScreen(screen),
350 pw->x, pw->y, pw->width, pw->height, pw->border_width,
351 DefaultDepthOfScreen (screen), InputOutput,
352 DefaultVisualOfScreen(screen),
354 XSetWindowBackground (si->dpy, si->passwd_dialog, pw->background);
357 /* Before mapping the window, save the bits that are underneath the
358 rectangle the window will occlude. When we lower the window, we
359 restore these bits. This works, because the running screenhack
360 has already been sent SIGSTOP, so we know nothing else is drawing
365 pw->save_under = XCreatePixmap (si->dpy,
366 si->default_screen->screensaver_window,
367 pw->width + (pw->border_width*2) + 1,
368 pw->height + (pw->border_width*2) + 1,
369 si->default_screen->current_depth);
370 gcv.function = GXcopy;
371 gc = XCreateGC (si->dpy, pw->save_under, GCFunction, &gcv);
372 XCopyArea (si->dpy, si->default_screen->screensaver_window,
374 pw->x - pw->border_width, pw->y - pw->border_width,
375 pw->width + (pw->border_width*2) + 1,
376 pw->height + (pw->border_width*2) + 1,
378 XFreeGC (si->dpy, gc);
381 XMapRaised (si->dpy, si->passwd_dialog);
382 XSync (si->dpy, False);
384 move_mouse_grab (si, si->passwd_dialog, si->screens[0].cursor);
389 draw_passwd_window (si);
390 XSync (si->dpy, False);
395 draw_passwd_window (saver_info *si)
397 passwd_dialog_data *pw = si->pw_data;
401 int x1, x2, x3, y1, y2;
405 height = (pw->heading_font->ascent + pw->heading_font->descent +
406 pw->body_font->ascent + pw->body_font->descent +
407 (2 * MAX ((pw->label_font->ascent + pw->label_font->descent),
408 (pw->passwd_font->ascent + pw->passwd_font->descent +
409 (pw->shadow_width * 4)))) +
410 pw->date_font->ascent + pw->date_font->descent
412 spacing = ((pw->height - (2 * pw->shadow_width) -
413 pw->internal_border - height)) / 8;
414 if (spacing < 0) spacing = 0;
416 gcv.foreground = pw->foreground;
417 gc1 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
418 gc2 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
419 x1 = pw->logo_width + pw->thermo_width + (pw->shadow_width * 3);
420 x3 = pw->width - (pw->shadow_width * 2);
421 y1 = (pw->shadow_width * 2) + spacing + spacing;
425 XSetFont (si->dpy, gc1, pw->heading_font->fid);
426 sw = string_width (pw->heading_font, pw->heading_label);
427 x2 = (x1 + ((x3 - x1 - sw) / 2));
428 y1 += spacing + pw->heading_font->ascent + pw->heading_font->descent;
429 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
430 pw->heading_label, strlen(pw->heading_label));
432 /* text below top heading
434 XSetFont (si->dpy, gc1, pw->body_font->fid);
435 y1 += spacing + pw->body_font->ascent + pw->body_font->descent;
436 sw = string_width (pw->body_font, pw->body_label);
437 x2 = (x1 + ((x3 - x1 - sw) / 2));
438 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
439 pw->body_label, strlen(pw->body_label));
442 tb_height = (pw->passwd_font->ascent + pw->passwd_font->descent +
443 (pw->shadow_width * 4));
445 /* the "User:" prompt
449 XSetForeground (si->dpy, gc1, pw->foreground);
450 XSetFont (si->dpy, gc1, pw->label_font->fid);
451 y1 += (spacing + tb_height);
452 x2 = (x1 + pw->internal_border +
453 MAX(string_width (pw->label_font, pw->user_label),
454 string_width (pw->label_font, pw->passwd_label)));
455 XDrawString (si->dpy, si->passwd_dialog, gc1,
456 x2 - string_width (pw->label_font, pw->user_label),
458 pw->user_label, strlen(pw->user_label));
460 /* the "Password:" prompt
462 y1 += (spacing + tb_height);
463 XDrawString (si->dpy, si->passwd_dialog, gc1,
464 x2 - string_width (pw->label_font, pw->passwd_label),
466 pw->passwd_label, strlen(pw->passwd_label));
469 XSetForeground (si->dpy, gc2, pw->passwd_background);
471 /* the "user name" text field
474 XSetForeground (si->dpy, gc1, pw->passwd_foreground);
475 XSetFont (si->dpy, gc1, pw->passwd_font->fid);
476 y1 += (spacing + tb_height);
477 x2 += (pw->shadow_width * 4);
479 pw->passwd_field_width = x3 - x2 - pw->internal_border;
480 pw->passwd_field_height = (pw->passwd_font->ascent +
481 pw->passwd_font->descent +
484 XFillRectangle (si->dpy, si->passwd_dialog, gc2,
485 x2 - pw->shadow_width,
486 y1 - (pw->passwd_font->ascent + pw->passwd_font->descent),
487 pw->passwd_field_width, pw->passwd_field_height);
488 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
489 pw->user_string, strlen(pw->user_string));
491 /* the "password" text field
493 y1 += (spacing + tb_height);
495 pw->passwd_field_x = x2 - pw->shadow_width;
496 pw->passwd_field_y = y1 - (pw->passwd_font->ascent +
497 pw->passwd_font->descent);
499 /* The shadow around the text fields
502 y1 += (spacing + (pw->shadow_width * 3));
503 x1 = x2 - (pw->shadow_width * 2);
504 x2 = pw->passwd_field_width + (pw->shadow_width * 2);
505 y2 = pw->passwd_field_height + (pw->shadow_width * 2);
507 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
510 pw->shadow_bottom, pw->shadow_top);
512 y1 += (spacing + pw->passwd_font->ascent + pw->passwd_font->descent +
513 (pw->shadow_width * 4));
514 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
517 pw->shadow_bottom, pw->shadow_top);
520 /* The date, below the text fields
524 time_t now = time ((time_t *) 0);
525 struct tm *tm = localtime (&now);
526 memset (buf, 0, sizeof(buf));
527 strftime (buf, sizeof(buf)-1, pw->date_label, tm);
529 XSetFont (si->dpy, gc1, pw->date_font->fid);
530 y1 += pw->shadow_width;
531 y1 += (spacing + tb_height);
533 sw = string_width (pw->date_font, buf);
535 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1, buf, strlen(buf));
541 XSetForeground (si->dpy, gc1, pw->logo_foreground);
542 XSetForeground (si->dpy, gc2, pw->logo_background);
544 x1 = pw->shadow_width * 3;
545 y1 = pw->shadow_width * 3;
546 x2 = pw->logo_width - (pw->shadow_width * 6);
547 y2 = pw->logo_height - (pw->shadow_width * 6);
549 XFillRectangle (si->dpy, si->passwd_dialog, gc2, x1, y1, x2, y2);
550 skull (si->dpy, si->passwd_dialog, gc1, gc2,
551 x1 + pw->shadow_width, y1 + pw->shadow_width,
552 x2 - (pw->shadow_width * 2), y2 - (pw->shadow_width * 2));
556 pw->thermo_field_x = pw->logo_width + pw->shadow_width;
557 pw->thermo_field_y = pw->shadow_width * 3;
558 pw->thermo_field_height = pw->height - (pw->shadow_width * 6);
560 /* Solid border inside the logo box. */
561 XSetForeground (si->dpy, gc1, pw->foreground);
562 XDrawRectangle (si->dpy, si->passwd_dialog, gc1, x1, y1, x2-1, y2-1);
564 /* The shadow around the logo
566 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
567 pw->shadow_width * 2,
568 pw->shadow_width * 2,
569 pw->logo_width - (pw->shadow_width * 4),
570 pw->logo_height - (pw->shadow_width * 4),
572 pw->shadow_bottom, pw->shadow_top);
574 /* The shadow around the thermometer
576 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
578 pw->shadow_width * 2,
579 pw->thermo_width + (pw->shadow_width * 2),
580 pw->height - (pw->shadow_width * 4),
582 pw->shadow_bottom, pw->shadow_top);
584 /* Solid border inside the thermometer. */
585 XSetForeground (si->dpy, gc1, pw->foreground);
586 XDrawRectangle (si->dpy, si->passwd_dialog, gc1,
587 pw->logo_width + pw->shadow_width,
588 pw->shadow_width * 3,
589 pw->thermo_width - 1,
590 pw->height - (pw->shadow_width * 6) - 1);
592 /* The shadow around the whole window
594 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
595 0, 0, pw->width, pw->height, pw->shadow_width,
596 pw->shadow_top, pw->shadow_bottom);
598 XFreeGC (si->dpy, gc1);
599 XFreeGC (si->dpy, gc2);
601 update_passwd_window (si, pw->passwd_string, pw->ratio);
606 update_passwd_window (saver_info *si, const char *printed_passwd, float ratio)
608 passwd_dialog_data *pw = si->pw_data;
615 gcv.foreground = pw->passwd_foreground;
616 gcv.font = pw->passwd_font->fid;
617 gc1 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground|GCFont, &gcv);
618 gcv.foreground = pw->passwd_background;
619 gc2 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
623 char *s = strdup (printed_passwd);
624 if (pw->passwd_string) free (pw->passwd_string);
625 pw->passwd_string = s;
628 /* the "password" text field
630 rects[0].x = pw->passwd_field_x;
631 rects[0].y = pw->passwd_field_y;
632 rects[0].width = pw->passwd_field_width;
633 rects[0].height = pw->passwd_field_height;
635 XFillRectangle (si->dpy, si->passwd_dialog, gc2,
636 rects[0].x, rects[0].y, rects[0].width, rects[0].height);
638 XSetClipRectangles (si->dpy, gc1, 0, 0, rects, 1, Unsorted);
640 XDrawString (si->dpy, si->passwd_dialog, gc1,
641 rects[0].x + pw->shadow_width,
642 rects[0].y + (pw->passwd_font->ascent +
643 pw->passwd_font->descent),
644 pw->passwd_string, strlen(pw->passwd_string));
646 XSetClipMask (si->dpy, gc1, None);
652 x = (rects[0].x + pw->shadow_width +
653 string_width (pw->passwd_font, pw->passwd_string));
654 y = rects[0].y + pw->shadow_width;
656 if (x > rects[0].x + rects[0].width - 1)
657 x = rects[0].x + rects[0].width - 1;
658 XDrawLine (si->dpy, si->passwd_dialog, gc1,
659 x, y, x, y + pw->passwd_font->ascent);
662 pw->i_beam = (pw->i_beam + 1) % 4;
667 y = pw->thermo_field_height * (1.0 - pw->ratio);
670 XFillRectangle (si->dpy, si->passwd_dialog, gc2,
671 pw->thermo_field_x + 1,
672 pw->thermo_field_y + 1,
675 XSetForeground (si->dpy, gc1, pw->logo_foreground);
676 XFillRectangle (si->dpy, si->passwd_dialog, gc1,
677 pw->thermo_field_x + 1,
678 pw->thermo_field_y + 1 + y,
680 MAX (0, pw->thermo_field_height - y - 2));
683 XFreeGC (si->dpy, gc1);
684 XFreeGC (si->dpy, gc2);
685 XSync (si->dpy, False);
690 destroy_passwd_window (saver_info *si)
692 passwd_dialog_data *pw = si->pw_data;
693 Screen *screen = si->default_screen->screen;
694 Colormap cmap = DefaultColormapOfScreen (screen);
695 Pixel black = BlackPixelOfScreen (screen);
696 Pixel white = WhitePixelOfScreen (screen);
699 XtRemoveTimeOut (pw->timer);
701 move_mouse_grab (si, RootWindowOfScreen(si->screens[0].screen),
702 si->screens[0].cursor);
704 if (si->passwd_dialog)
706 XDestroyWindow (si->dpy, si->passwd_dialog);
707 si->passwd_dialog = 0;
714 gcv.function = GXcopy;
715 gc = XCreateGC (si->dpy, si->default_screen->screensaver_window,
717 XCopyArea (si->dpy, pw->save_under,
718 si->default_screen->screensaver_window, gc,
720 pw->width + (pw->border_width*2) + 1,
721 pw->height + (pw->border_width*2) + 1,
722 pw->x - pw->border_width, pw->y - pw->border_width);
723 XFreePixmap (si->dpy, pw->save_under);
725 XFreeGC (si->dpy, gc);
728 if (pw->heading_label) free (pw->heading_label);
729 if (pw->body_label) free (pw->body_label);
730 if (pw->user_label) free (pw->user_label);
731 if (pw->passwd_label) free (pw->passwd_label);
733 if (pw->heading_font) XFreeFont (si->dpy, pw->heading_font);
734 if (pw->body_font) XFreeFont (si->dpy, pw->body_font);
735 if (pw->label_font) XFreeFont (si->dpy, pw->label_font);
736 if (pw->passwd_font) XFreeFont (si->dpy, pw->passwd_font);
738 if (pw->foreground != black && pw->foreground != white)
739 XFreeColors (si->dpy, cmap, &pw->foreground, 1, 0L);
740 if (pw->background != black && pw->background != white)
741 XFreeColors (si->dpy, cmap, &pw->background, 1, 0L);
742 if (pw->passwd_foreground != black && pw->passwd_foreground != white)
743 XFreeColors (si->dpy, cmap, &pw->passwd_foreground, 1, 0L);
744 if (pw->passwd_background != black && pw->passwd_background != white)
745 XFreeColors (si->dpy, cmap, &pw->passwd_background, 1, 0L);
746 if (pw->logo_foreground != black && pw->logo_foreground != white)
747 XFreeColors (si->dpy, cmap, &pw->logo_foreground, 1, 0L);
748 if (pw->logo_background != black && pw->logo_background != white)
749 XFreeColors (si->dpy, cmap, &pw->logo_background, 1, 0L);
750 if (pw->shadow_top != black && pw->shadow_top != white)
751 XFreeColors (si->dpy, cmap, &pw->shadow_top, 1, 0L);
752 if (pw->shadow_bottom != black && pw->shadow_bottom != white)
753 XFreeColors (si->dpy, cmap, &pw->shadow_bottom, 1, 0L);
755 memset (pw, 0, sizeof(*pw));
762 #ifdef HAVE_XHPDISABLERESET
763 /* This function enables and disables the C-Sh-Reset hot-key, which
764 normally resets the X server (logging out the logged-in user.)
765 We don't want random people to be able to do that while the
769 hp_lock_reset (saver_info *si, Bool lock_p)
771 static Bool hp_locked_p = False;
773 /* Calls to XHPDisableReset and XHPEnableReset must be balanced,
774 or BadAccess errors occur. (It's ok for this to be global,
775 since it affects the whole machine, not just the current screen.)
777 if (hp_locked_p == lock_p)
781 XHPDisableReset (si->dpy);
783 XHPEnableReset (si->dpy);
784 hp_locked_p = lock_p;
786 #endif /* HAVE_XHPDISABLERESET */
790 /* This function enables and disables the C-Sh-F1 ... F12 hot-keys,
791 which, on Linux systems, switches to another virtual console.
792 We'd like the whole screen/keyboard to be locked, not just one
793 virtual console, so this function disables that while the X
796 Unfortunately, this doesn't work -- this ioctl only works when
797 called by root, and we have disavowed our privileges long ago.
799 #ifdef HAVE_VT_LOCKSWITCH
801 linux_lock_vt_switch (saver_info *si, Bool lock_p)
803 saver_preferences *p = &si->prefs;
804 static Bool vt_locked_p = False;
805 const char *dev_console = "/dev/console";
808 if (lock_p == vt_locked_p)
811 if (lock_p && !p->lock_vt_p)
814 fd = open (dev_console, O_RDWR);
818 sprintf (buf, "%s: couldn't %s VTs: %s", blurb(),
819 (lock_p ? "lock" : "unlock"),
821 #if 1 /* #### doesn't work yet, so don't bother complaining */
827 if (ioctl (fd, (lock_p ? VT_LOCKSWITCH : VT_UNLOCKSWITCH)) == 0)
829 vt_locked_p = lock_p;
832 fprintf (stderr, "%s: %s VTs\n", blurb(),
833 (lock_p ? "locked" : "unlocked"));
838 sprintf (buf, "%s: couldn't %s VTs: ioctl", blurb(),
839 (lock_p ? "lock" : "unlock"));
840 #if 0 /* #### doesn't work yet, so don't bother complaining */
847 #endif /* HAVE_VT_LOCKSWITCH */
850 /* This function enables and disables the C-Alt-Plus and C-Alt-Minus
851 hot-keys, which normally change the resolution of the X server.
852 We don't want people to be able to switch the server resolution
853 while the screen is locked, because if they switch to a higher
854 resolution, it could cause part of the underlying desktop to become
857 #ifdef HAVE_XF86VMODE
859 static int ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error);
860 static Bool vp_got_error = False;
863 xfree_lock_mode_switch (saver_info *si, Bool lock_p)
865 static Bool mode_locked_p = False;
866 saver_preferences *p = &si->prefs;
867 int screen = 0; /* always screen 0 */
870 XErrorHandler old_handler;
872 if (mode_locked_p == lock_p)
874 if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
877 XSync (si->dpy, False);
878 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
879 status = XF86VidModeLockModeSwitch (si->dpy, screen, lock_p);
880 XSync (si->dpy, False);
881 XSetErrorHandler (old_handler);
882 if (vp_got_error) status = False;
885 mode_locked_p = lock_p;
887 if (!status && (p->verbose_p || !lock_p))
888 /* Only print this when verbose, or when we locked but can't unlock.
889 I tried printing this message whenever it comes up, but
890 mode-locking always fails if DontZoom is set in XF86Config. */
891 fprintf (stderr, "%s: unable to %s mode switching!\n",
892 blurb(), (lock_p ? "lock" : "unlock"));
893 else if (p->verbose_p)
894 fprintf (stderr, "%s: %s mode switching.\n",
895 blurb(), (lock_p ? "locked" : "unlocked"));
899 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
905 #endif /* HAVE_XF86VMODE */
908 /* If the viewport has been scrolled since the screen was blanked,
909 then scroll it back to where it belongs. This function only exists
910 to patch over a very brief race condition.
913 undo_vp_motion (saver_info *si)
915 #ifdef HAVE_XF86VMODE
916 saver_preferences *p = &si->prefs;
917 int screen = 0; /* always screen 0 */
918 saver_screen_info *ssi = &si->screens[screen];
919 int event, error, x, y;
922 if (ssi->blank_vp_x == -1 && ssi->blank_vp_y == -1)
924 if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
926 if (!XF86VidModeGetViewPort (si->dpy, 0, &x, &y))
928 if (ssi->blank_vp_x == x && ssi->blank_vp_y == y)
931 /* We're going to move the viewport. The mouse has just been grabbed on
932 (and constrained to, thus warped to) the password window, so it is no
933 longer near the edge of the screen. However, wait a bit anyway, just
934 to make sure the server drains its last motion event, so that the
935 screen doesn't continue to scroll after we've reset the viewport.
937 XSync (si->dpy, False);
938 usleep (250000); /* 1/4 second */
939 XSync (si->dpy, False);
941 status = XF86VidModeSetViewPort (si->dpy, screen,
942 ssi->blank_vp_x, ssi->blank_vp_y);
945 fprintf (stderr, "%s: unable to move vp from (%d,%d) back to (%d,%d)!\n",
946 blurb(), x, y, ssi->blank_vp_x, ssi->blank_vp_y);
947 else if (p->verbose_p)
948 fprintf (stderr, "%s: vp moved to (%d,%d); moved it back to (%d,%d).\n",
949 blurb(), x, y, ssi->blank_vp_x, ssi->blank_vp_y);
951 #endif /* HAVE_XF86VMODE */
960 passwd_animate_timer (XtPointer closure, XtIntervalId *id)
962 saver_info *si = (saver_info *) closure;
964 passwd_dialog_data *pw = si->pw_data;
968 pw->ratio -= (1.0 / ((double) si->prefs.passwd_timeout / (double) tick));
972 if (pw->state == pw_read)
976 update_passwd_window (si, 0, pw->ratio);
978 if (pw->state == pw_read)
979 pw->timer = XtAppAddTimeOut (si->app, tick, passwd_animate_timer,
984 idle_timer ((XtPointer) si, id);
989 handle_passwd_key (saver_info *si, XKeyEvent *event)
991 saver_preferences *p = &si->prefs;
992 passwd_dialog_data *pw = si->pw_data;
993 int pw_size = sizeof (pw->typed_passwd) - 1;
994 char *typed_passwd = pw->typed_passwd;
998 int size = XLookupString (event, s, 1, 0, 0);
1000 if (size != 1) return;
1006 case '\010': case '\177': /* Backspace */
1010 typed_passwd [strlen(typed_passwd)-1] = 0;
1013 case '\025': case '\030': /* Erase line */
1014 memset (typed_passwd, 0, pw_size);
1017 case '\012': case '\015': /* Enter */
1018 if (pw->state != pw_read)
1019 ; /* already done? */
1020 else if (typed_passwd[0] == 0)
1021 pw->state = pw_null;
1024 update_passwd_window (si, "Checking...", pw->ratio);
1025 XSync (si->dpy, False);
1026 if (passwd_valid_p (typed_passwd, p->verbose_p))
1029 pw->state = pw_fail;
1030 update_passwd_window (si, "", pw->ratio);
1035 i = strlen (typed_passwd);
1040 typed_passwd [i] = *s;
1041 typed_passwd [i+1] = 0;
1046 i = strlen(typed_passwd);
1047 stars = (char *) malloc(i+1);
1048 memset (stars, '*', i);
1050 update_passwd_window (si, stars, pw->ratio);
1056 passwd_event_loop (saver_info *si)
1058 saver_preferences *p = &si->prefs;
1061 passwd_animate_timer ((XtPointer) si, 0);
1063 while (si->pw_data && si->pw_data->state == pw_read)
1065 XtAppNextEvent (si->app, &event);
1066 if (event.xany.window == si->passwd_dialog && event.xany.type == Expose)
1067 draw_passwd_window (si);
1068 else if (event.xany.type == KeyPress)
1069 handle_passwd_key (si, &event.xkey);
1071 XtDispatchEvent (&event);
1074 switch (si->pw_data->state)
1076 case pw_ok: msg = 0; break;
1077 case pw_null: msg = ""; break;
1078 case pw_time: msg = "Timed out!"; break;
1079 default: msg = "Sorry!"; break;
1082 if (si->pw_data->state == pw_fail)
1083 si->unlock_failures++;
1086 switch (si->pw_data->state)
1089 fprintf (stderr, "%s: password correct.\n", blurb()); break;
1091 fprintf (stderr, "%s: password incorrect!\n", blurb()); break;
1094 fprintf (stderr, "%s: password entry cancelled.\n", blurb()); break;
1096 fprintf (stderr, "%s: password entry timed out.\n", blurb()); break;
1101 if (si->pw_data->state == pw_fail)
1103 /* If they typed a password (as opposed to just hitting return) and
1104 the password was invalid, log it.
1106 struct passwd *pw = getpwuid (getuid ());
1107 char *d = DisplayString (si->dpy);
1108 char *u = (pw->pw_name ? pw->pw_name : "???");
1116 # if defined(LOG_AUTHPRIV)
1118 # elif defined(LOG_AUTH)
1125 openlog (progname, opt, fac);
1126 syslog (LOG_NOTICE, "FAILED LOGIN %d ON DISPLAY \"%s\", FOR \"%s\"",
1127 si->unlock_failures, d, u);
1130 #endif /* HAVE_SYSLOG */
1132 if (si->pw_data->state == pw_fail)
1133 XBell (si->dpy, False);
1135 if (si->pw_data->state == pw_ok && si->unlock_failures != 0)
1137 if (si->unlock_failures == 1)
1138 fprintf (real_stderr,
1139 "%s: WARNING: 1 failed attempt to unlock the screen.\n",
1142 fprintf (real_stderr,
1143 "%s: WARNING: %d failed attempts to unlock the screen.\n",
1144 blurb(), si->unlock_failures);
1145 fflush (real_stderr);
1147 si->unlock_failures = 0;
1152 si->pw_data->i_beam = 0;
1153 update_passwd_window (si, msg, 0.0);
1154 XSync (si->dpy, False);
1157 /* Swallow all pending KeyPress/KeyRelease events. */
1160 while (XCheckMaskEvent (si->dpy, KeyPressMask|KeyReleaseMask, &e))
1168 handle_typeahead (saver_info *si)
1170 passwd_dialog_data *pw = si->pw_data;
1172 if (!si->unlock_typeahead)
1175 i = strlen (si->unlock_typeahead);
1176 if (i >= sizeof(pw->typed_passwd) - 1)
1177 i = sizeof(pw->typed_passwd) - 1;
1179 memcpy (pw->typed_passwd, si->unlock_typeahead, i);
1180 pw->typed_passwd [i] = 0;
1182 memset (si->unlock_typeahead, '*', strlen(si->unlock_typeahead));
1183 si->unlock_typeahead[i] = 0;
1184 update_passwd_window (si, si->unlock_typeahead, pw->ratio);
1186 free (si->unlock_typeahead);
1187 si->unlock_typeahead = 0;
1192 unlock_p (saver_info *si)
1194 saver_preferences *p = &si->prefs;
1195 Screen *screen = si->default_screen->screen;
1196 Colormap cmap = DefaultColormapOfScreen (screen);
1199 raise_window (si, True, True, True);
1202 fprintf (stderr, "%s: prompting for password.\n", blurb());
1204 if (si->pw_data || si->passwd_dialog)
1205 destroy_passwd_window (si);
1207 make_passwd_window (si);
1208 if (cmap) XInstallColormap (si->dpy, cmap);
1210 handle_typeahead (si);
1211 passwd_event_loop (si);
1213 status = (si->pw_data->state == pw_ok);
1214 destroy_passwd_window (si);
1216 cmap = si->default_screen->cmap;
1217 if (cmap) XInstallColormap (si->dpy, cmap);
1224 set_locked_p (saver_info *si, Bool locked_p)
1226 si->locked_p = locked_p;
1228 #ifdef HAVE_XHPDISABLERESET
1229 hp_lock_reset (si, locked_p); /* turn off/on C-Sh-Reset */
1231 #ifdef HAVE_VT_LOCKSWITCH
1232 linux_lock_vt_switch (si, locked_p); /* turn off/on C-Alt-F1 */
1234 #ifdef HAVE_XF86VMODE
1235 xfree_lock_mode_switch (si, locked_p); /* turn off/on C-Alt-Plus */
1238 store_saver_status (si); /* store locked-p */
1242 #else /* NO_LOCKING -- whole file */
1245 set_locked_p (saver_info *si, Bool locked_p)
1247 if (locked_p) abort();
1250 #endif /* !NO_LOCKING */