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 x1 = pw->shadow_width * 3;
542 y1 = pw->shadow_width * 3;
543 x2 = pw->logo_width - (pw->shadow_width * 6);
544 y2 = pw->logo_height - (pw->shadow_width * 6);
546 draw_logo (si, si->passwd_dialog, x1, y1, x2, y2, True);
550 pw->thermo_field_x = pw->logo_width + pw->shadow_width;
551 pw->thermo_field_y = pw->shadow_width * 3;
552 pw->thermo_field_height = pw->height - (pw->shadow_width * 6);
554 /* Solid border inside the logo box. */
555 XSetForeground (si->dpy, gc1, pw->foreground);
556 XDrawRectangle (si->dpy, si->passwd_dialog, gc1, x1, y1, x2-1, y2-1);
558 /* The shadow around the logo
560 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
561 pw->shadow_width * 2,
562 pw->shadow_width * 2,
563 pw->logo_width - (pw->shadow_width * 4),
564 pw->logo_height - (pw->shadow_width * 4),
566 pw->shadow_bottom, pw->shadow_top);
568 /* The shadow around the thermometer
570 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
572 pw->shadow_width * 2,
573 pw->thermo_width + (pw->shadow_width * 2),
574 pw->height - (pw->shadow_width * 4),
576 pw->shadow_bottom, pw->shadow_top);
578 /* Solid border inside the thermometer. */
579 XSetForeground (si->dpy, gc1, pw->foreground);
580 XDrawRectangle (si->dpy, si->passwd_dialog, gc1,
581 pw->logo_width + pw->shadow_width,
582 pw->shadow_width * 3,
583 pw->thermo_width - 1,
584 pw->height - (pw->shadow_width * 6) - 1);
586 /* The shadow around the whole window
588 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
589 0, 0, pw->width, pw->height, pw->shadow_width,
590 pw->shadow_top, pw->shadow_bottom);
592 XFreeGC (si->dpy, gc1);
593 XFreeGC (si->dpy, gc2);
595 update_passwd_window (si, pw->passwd_string, pw->ratio);
600 update_passwd_window (saver_info *si, const char *printed_passwd, float ratio)
602 passwd_dialog_data *pw = si->pw_data;
609 gcv.foreground = pw->passwd_foreground;
610 gcv.font = pw->passwd_font->fid;
611 gc1 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground|GCFont, &gcv);
612 gcv.foreground = pw->passwd_background;
613 gc2 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
617 char *s = strdup (printed_passwd);
618 if (pw->passwd_string) free (pw->passwd_string);
619 pw->passwd_string = s;
622 /* the "password" text field
624 rects[0].x = pw->passwd_field_x;
625 rects[0].y = pw->passwd_field_y;
626 rects[0].width = pw->passwd_field_width;
627 rects[0].height = pw->passwd_field_height;
629 XFillRectangle (si->dpy, si->passwd_dialog, gc2,
630 rects[0].x, rects[0].y, rects[0].width, rects[0].height);
632 XSetClipRectangles (si->dpy, gc1, 0, 0, rects, 1, Unsorted);
634 XDrawString (si->dpy, si->passwd_dialog, gc1,
635 rects[0].x + pw->shadow_width,
636 rects[0].y + (pw->passwd_font->ascent +
637 pw->passwd_font->descent),
638 pw->passwd_string, strlen(pw->passwd_string));
640 XSetClipMask (si->dpy, gc1, None);
646 x = (rects[0].x + pw->shadow_width +
647 string_width (pw->passwd_font, pw->passwd_string));
648 y = rects[0].y + pw->shadow_width;
650 if (x > rects[0].x + rects[0].width - 1)
651 x = rects[0].x + rects[0].width - 1;
652 XDrawLine (si->dpy, si->passwd_dialog, gc1,
653 x, y, x, y + pw->passwd_font->ascent);
656 pw->i_beam = (pw->i_beam + 1) % 4;
661 y = pw->thermo_field_height * (1.0 - pw->ratio);
664 XFillRectangle (si->dpy, si->passwd_dialog, gc2,
665 pw->thermo_field_x + 1,
666 pw->thermo_field_y + 1,
669 XSetForeground (si->dpy, gc1, pw->logo_foreground);
670 XFillRectangle (si->dpy, si->passwd_dialog, gc1,
671 pw->thermo_field_x + 1,
672 pw->thermo_field_y + 1 + y,
674 MAX (0, pw->thermo_field_height - y - 2));
681 x1 = pw->shadow_width * 3;
682 y1 = pw->shadow_width * 3;
683 x2 = pw->logo_width - (pw->shadow_width * 6);
684 y2 = pw->logo_height - (pw->shadow_width * 6);
686 draw_logo (si, si->passwd_dialog, x1, y1, x2, y2, False);
689 XFreeGC (si->dpy, gc1);
690 XFreeGC (si->dpy, gc2);
691 XSync (si->dpy, False);
696 destroy_passwd_window (saver_info *si)
698 passwd_dialog_data *pw = si->pw_data;
699 Screen *screen = si->default_screen->screen;
700 Colormap cmap = DefaultColormapOfScreen (screen);
701 Pixel black = BlackPixelOfScreen (screen);
702 Pixel white = WhitePixelOfScreen (screen);
705 XtRemoveTimeOut (pw->timer);
707 move_mouse_grab (si, RootWindowOfScreen(si->screens[0].screen),
708 si->screens[0].cursor);
710 if (si->passwd_dialog)
712 XDestroyWindow (si->dpy, si->passwd_dialog);
713 si->passwd_dialog = 0;
720 gcv.function = GXcopy;
721 gc = XCreateGC (si->dpy, si->default_screen->screensaver_window,
723 XCopyArea (si->dpy, pw->save_under,
724 si->default_screen->screensaver_window, gc,
726 pw->width + (pw->border_width*2) + 1,
727 pw->height + (pw->border_width*2) + 1,
728 pw->x - pw->border_width, pw->y - pw->border_width);
729 XFreePixmap (si->dpy, pw->save_under);
731 XFreeGC (si->dpy, gc);
734 if (pw->heading_label) free (pw->heading_label);
735 if (pw->body_label) free (pw->body_label);
736 if (pw->user_label) free (pw->user_label);
737 if (pw->passwd_label) free (pw->passwd_label);
739 if (pw->heading_font) XFreeFont (si->dpy, pw->heading_font);
740 if (pw->body_font) XFreeFont (si->dpy, pw->body_font);
741 if (pw->label_font) XFreeFont (si->dpy, pw->label_font);
742 if (pw->passwd_font) XFreeFont (si->dpy, pw->passwd_font);
744 if (pw->foreground != black && pw->foreground != white)
745 XFreeColors (si->dpy, cmap, &pw->foreground, 1, 0L);
746 if (pw->background != black && pw->background != white)
747 XFreeColors (si->dpy, cmap, &pw->background, 1, 0L);
748 if (pw->passwd_foreground != black && pw->passwd_foreground != white)
749 XFreeColors (si->dpy, cmap, &pw->passwd_foreground, 1, 0L);
750 if (pw->passwd_background != black && pw->passwd_background != white)
751 XFreeColors (si->dpy, cmap, &pw->passwd_background, 1, 0L);
752 if (pw->logo_foreground != black && pw->logo_foreground != white)
753 XFreeColors (si->dpy, cmap, &pw->logo_foreground, 1, 0L);
754 if (pw->logo_background != black && pw->logo_background != white)
755 XFreeColors (si->dpy, cmap, &pw->logo_background, 1, 0L);
756 if (pw->shadow_top != black && pw->shadow_top != white)
757 XFreeColors (si->dpy, cmap, &pw->shadow_top, 1, 0L);
758 if (pw->shadow_bottom != black && pw->shadow_bottom != white)
759 XFreeColors (si->dpy, cmap, &pw->shadow_bottom, 1, 0L);
761 memset (pw, 0, sizeof(*pw));
768 #ifdef HAVE_XHPDISABLERESET
769 /* This function enables and disables the C-Sh-Reset hot-key, which
770 normally resets the X server (logging out the logged-in user.)
771 We don't want random people to be able to do that while the
775 hp_lock_reset (saver_info *si, Bool lock_p)
777 static Bool hp_locked_p = False;
779 /* Calls to XHPDisableReset and XHPEnableReset must be balanced,
780 or BadAccess errors occur. (It's ok for this to be global,
781 since it affects the whole machine, not just the current screen.)
783 if (hp_locked_p == lock_p)
787 XHPDisableReset (si->dpy);
789 XHPEnableReset (si->dpy);
790 hp_locked_p = lock_p;
792 #endif /* HAVE_XHPDISABLERESET */
796 /* This function enables and disables the C-Sh-F1 ... F12 hot-keys,
797 which, on Linux systems, switches to another virtual console.
798 We'd like the whole screen/keyboard to be locked, not just one
799 virtual console, so this function disables that while the X
802 Unfortunately, this doesn't work -- this ioctl only works when
803 called by root, and we have disavowed our privileges long ago.
805 #ifdef HAVE_VT_LOCKSWITCH
807 linux_lock_vt_switch (saver_info *si, Bool lock_p)
809 saver_preferences *p = &si->prefs;
810 static Bool vt_locked_p = False;
811 const char *dev_console = "/dev/console";
814 if (lock_p == vt_locked_p)
817 if (lock_p && !p->lock_vt_p)
820 fd = open (dev_console, O_RDWR);
824 sprintf (buf, "%s: couldn't %s VTs: %s", blurb(),
825 (lock_p ? "lock" : "unlock"),
827 #if 1 /* #### doesn't work yet, so don't bother complaining */
833 if (ioctl (fd, (lock_p ? VT_LOCKSWITCH : VT_UNLOCKSWITCH)) == 0)
835 vt_locked_p = lock_p;
838 fprintf (stderr, "%s: %s VTs\n", blurb(),
839 (lock_p ? "locked" : "unlocked"));
844 sprintf (buf, "%s: couldn't %s VTs: ioctl", blurb(),
845 (lock_p ? "lock" : "unlock"));
846 #if 0 /* #### doesn't work yet, so don't bother complaining */
853 #endif /* HAVE_VT_LOCKSWITCH */
856 /* This function enables and disables the C-Alt-Plus and C-Alt-Minus
857 hot-keys, which normally change the resolution of the X server.
858 We don't want people to be able to switch the server resolution
859 while the screen is locked, because if they switch to a higher
860 resolution, it could cause part of the underlying desktop to become
863 #ifdef HAVE_XF86VMODE
865 static int ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error);
866 static Bool vp_got_error = False;
869 xfree_lock_mode_switch (saver_info *si, Bool lock_p)
871 static Bool mode_locked_p = False;
872 saver_preferences *p = &si->prefs;
873 int screen = 0; /* always screen 0 */
876 XErrorHandler old_handler;
878 if (mode_locked_p == lock_p)
880 if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
883 XSync (si->dpy, False);
884 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
885 status = XF86VidModeLockModeSwitch (si->dpy, screen, lock_p);
886 XSync (si->dpy, False);
887 XSetErrorHandler (old_handler);
888 if (vp_got_error) status = False;
891 mode_locked_p = lock_p;
893 if (!status && (p->verbose_p || !lock_p))
894 /* Only print this when verbose, or when we locked but can't unlock.
895 I tried printing this message whenever it comes up, but
896 mode-locking always fails if DontZoom is set in XF86Config. */
897 fprintf (stderr, "%s: unable to %s mode switching!\n",
898 blurb(), (lock_p ? "lock" : "unlock"));
899 else if (p->verbose_p)
900 fprintf (stderr, "%s: %s mode switching.\n",
901 blurb(), (lock_p ? "locked" : "unlocked"));
905 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
911 #endif /* HAVE_XF86VMODE */
914 /* If the viewport has been scrolled since the screen was blanked,
915 then scroll it back to where it belongs. This function only exists
916 to patch over a very brief race condition.
919 undo_vp_motion (saver_info *si)
921 #ifdef HAVE_XF86VMODE
922 saver_preferences *p = &si->prefs;
923 int screen = 0; /* always screen 0 */
924 saver_screen_info *ssi = &si->screens[screen];
925 int event, error, x, y;
928 if (ssi->blank_vp_x == -1 && ssi->blank_vp_y == -1)
930 if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
932 if (!XF86VidModeGetViewPort (si->dpy, 0, &x, &y))
934 if (ssi->blank_vp_x == x && ssi->blank_vp_y == y)
937 /* We're going to move the viewport. The mouse has just been grabbed on
938 (and constrained to, thus warped to) the password window, so it is no
939 longer near the edge of the screen. However, wait a bit anyway, just
940 to make sure the server drains its last motion event, so that the
941 screen doesn't continue to scroll after we've reset the viewport.
943 XSync (si->dpy, False);
944 usleep (250000); /* 1/4 second */
945 XSync (si->dpy, False);
947 status = XF86VidModeSetViewPort (si->dpy, screen,
948 ssi->blank_vp_x, ssi->blank_vp_y);
951 fprintf (stderr, "%s: unable to move vp from (%d,%d) back to (%d,%d)!\n",
952 blurb(), x, y, ssi->blank_vp_x, ssi->blank_vp_y);
953 else if (p->verbose_p)
954 fprintf (stderr, "%s: vp moved to (%d,%d); moved it back to (%d,%d).\n",
955 blurb(), x, y, ssi->blank_vp_x, ssi->blank_vp_y);
957 #endif /* HAVE_XF86VMODE */
966 passwd_animate_timer (XtPointer closure, XtIntervalId *id)
968 saver_info *si = (saver_info *) closure;
970 passwd_dialog_data *pw = si->pw_data;
974 pw->ratio -= (1.0 / ((double) si->prefs.passwd_timeout / (double) tick));
978 if (pw->state == pw_read)
982 update_passwd_window (si, 0, pw->ratio);
984 if (pw->state == pw_read)
985 pw->timer = XtAppAddTimeOut (si->app, tick, passwd_animate_timer,
990 idle_timer ((XtPointer) si, id);
994 static XComposeStatus *compose_status;
997 handle_passwd_key (saver_info *si, XKeyEvent *event)
999 saver_preferences *p = &si->prefs;
1000 passwd_dialog_data *pw = si->pw_data;
1001 int pw_size = sizeof (pw->typed_passwd) - 1;
1002 char *typed_passwd = pw->typed_passwd;
1006 int size = XLookupString (event, s, 1, 0, compose_status);
1008 if (size != 1) return;
1014 case '\010': case '\177': /* Backspace */
1018 typed_passwd [strlen(typed_passwd)-1] = 0;
1021 case '\025': case '\030': /* Erase line */
1022 memset (typed_passwd, 0, pw_size);
1025 case '\012': case '\015': /* Enter */
1026 if (pw->state != pw_read)
1027 ; /* already done? */
1028 else if (typed_passwd[0] == 0)
1029 pw->state = pw_null;
1032 update_passwd_window (si, "Checking...", pw->ratio);
1033 XSync (si->dpy, False);
1034 if (passwd_valid_p (typed_passwd, p->verbose_p))
1037 pw->state = pw_fail;
1038 update_passwd_window (si, "", pw->ratio);
1043 i = strlen (typed_passwd);
1048 typed_passwd [i] = *s;
1049 typed_passwd [i+1] = 0;
1054 i = strlen(typed_passwd);
1055 stars = (char *) malloc(i+1);
1056 memset (stars, '*', i);
1058 update_passwd_window (si, stars, pw->ratio);
1064 passwd_event_loop (saver_info *si)
1066 saver_preferences *p = &si->prefs;
1069 passwd_animate_timer ((XtPointer) si, 0);
1071 while (si->pw_data && si->pw_data->state == pw_read)
1073 XtAppNextEvent (si->app, &event);
1074 if (event.xany.window == si->passwd_dialog && event.xany.type == Expose)
1075 draw_passwd_window (si);
1076 else if (event.xany.type == KeyPress)
1077 handle_passwd_key (si, &event.xkey);
1079 XtDispatchEvent (&event);
1082 switch (si->pw_data->state)
1084 case pw_ok: msg = 0; break;
1085 case pw_null: msg = ""; break;
1086 case pw_time: msg = "Timed out!"; break;
1087 default: msg = "Sorry!"; break;
1090 if (si->pw_data->state == pw_fail)
1091 si->unlock_failures++;
1094 switch (si->pw_data->state)
1097 fprintf (stderr, "%s: password correct.\n", blurb()); break;
1099 fprintf (stderr, "%s: password incorrect!\n", blurb()); break;
1102 fprintf (stderr, "%s: password entry cancelled.\n", blurb()); break;
1104 fprintf (stderr, "%s: password entry timed out.\n", blurb()); break;
1109 if (si->pw_data->state == pw_fail)
1111 /* If they typed a password (as opposed to just hitting return) and
1112 the password was invalid, log it.
1114 struct passwd *pw = getpwuid (getuid ());
1115 char *d = DisplayString (si->dpy);
1116 char *u = (pw->pw_name ? pw->pw_name : "???");
1124 # if defined(LOG_AUTHPRIV)
1126 # elif defined(LOG_AUTH)
1133 openlog (progname, opt, fac);
1134 syslog (LOG_NOTICE, "FAILED LOGIN %d ON DISPLAY \"%s\", FOR \"%s\"",
1135 si->unlock_failures, d, u);
1138 #endif /* HAVE_SYSLOG */
1140 if (si->pw_data->state == pw_fail)
1141 XBell (si->dpy, False);
1143 if (si->pw_data->state == pw_ok && si->unlock_failures != 0)
1145 if (si->unlock_failures == 1)
1146 fprintf (real_stderr,
1147 "%s: WARNING: 1 failed attempt to unlock the screen.\n",
1150 fprintf (real_stderr,
1151 "%s: WARNING: %d failed attempts to unlock the screen.\n",
1152 blurb(), si->unlock_failures);
1153 fflush (real_stderr);
1155 si->unlock_failures = 0;
1160 si->pw_data->i_beam = 0;
1161 update_passwd_window (si, msg, 0.0);
1162 XSync (si->dpy, False);
1165 /* Swallow all pending KeyPress/KeyRelease events. */
1168 while (XCheckMaskEvent (si->dpy, KeyPressMask|KeyReleaseMask, &e))
1176 handle_typeahead (saver_info *si)
1178 passwd_dialog_data *pw = si->pw_data;
1180 if (!si->unlock_typeahead)
1183 i = strlen (si->unlock_typeahead);
1184 if (i >= sizeof(pw->typed_passwd) - 1)
1185 i = sizeof(pw->typed_passwd) - 1;
1187 memcpy (pw->typed_passwd, si->unlock_typeahead, i);
1188 pw->typed_passwd [i] = 0;
1190 memset (si->unlock_typeahead, '*', strlen(si->unlock_typeahead));
1191 si->unlock_typeahead[i] = 0;
1192 update_passwd_window (si, si->unlock_typeahead, pw->ratio);
1194 free (si->unlock_typeahead);
1195 si->unlock_typeahead = 0;
1200 unlock_p (saver_info *si)
1202 saver_preferences *p = &si->prefs;
1203 Screen *screen = si->default_screen->screen;
1204 Colormap cmap = DefaultColormapOfScreen (screen);
1207 raise_window (si, True, True, True);
1210 fprintf (stderr, "%s: prompting for password.\n", blurb());
1212 if (si->pw_data || si->passwd_dialog)
1213 destroy_passwd_window (si);
1215 make_passwd_window (si);
1216 if (cmap) XInstallColormap (si->dpy, cmap);
1218 compose_status = calloc (1, sizeof (*compose_status));
1220 handle_typeahead (si);
1221 passwd_event_loop (si);
1223 status = (si->pw_data->state == pw_ok);
1224 destroy_passwd_window (si);
1226 free (compose_status);
1229 cmap = si->default_screen->cmap;
1230 if (cmap) XInstallColormap (si->dpy, cmap);
1237 set_locked_p (saver_info *si, Bool locked_p)
1239 si->locked_p = locked_p;
1241 #ifdef HAVE_XHPDISABLERESET
1242 hp_lock_reset (si, locked_p); /* turn off/on C-Sh-Reset */
1244 #ifdef HAVE_VT_LOCKSWITCH
1245 linux_lock_vt_switch (si, locked_p); /* turn off/on C-Alt-F1 */
1247 #ifdef HAVE_XF86VMODE
1248 xfree_lock_mode_switch (si, locked_p); /* turn off/on C-Alt-Plus */
1251 store_saver_status (si); /* store locked-p */
1255 #else /* NO_LOCKING -- whole file */
1258 set_locked_p (saver_info *si, Bool locked_p)
1260 if (locked_p) abort();
1263 #endif /* !NO_LOCKING */