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 saver_screen_info *prompt_screen;
79 int previous_mouse_x, previous_mouse_y;
81 enum passwd_state state;
82 char typed_passwd [80];
90 Dimension border_width;
100 XFontStruct *heading_font;
101 XFontStruct *body_font;
102 XFontStruct *label_font;
103 XFontStruct *passwd_font;
104 XFontStruct *date_font;
108 Pixel passwd_foreground;
109 Pixel passwd_background;
110 Pixel thermo_foreground;
111 Pixel thermo_background;
115 Dimension logo_width;
116 Dimension logo_height;
117 Dimension thermo_width;
118 Dimension internal_border;
119 Dimension shadow_width;
121 Dimension passwd_field_x, passwd_field_y;
122 Dimension passwd_field_width, passwd_field_height;
124 Dimension thermo_field_x, thermo_field_y;
125 Dimension thermo_field_height;
129 unsigned long *logo_pixels;
134 static void draw_passwd_window (saver_info *si);
135 static void update_passwd_window (saver_info *si, const char *printed_passwd,
137 static void destroy_passwd_window (saver_info *si);
138 static void undo_vp_motion (saver_info *si);
142 make_passwd_window (saver_info *si)
144 struct passwd *p = getpwuid (getuid ());
145 XSetWindowAttributes attrs;
146 unsigned long attrmask = 0;
147 passwd_dialog_data *pw = (passwd_dialog_data *) calloc (1, sizeof(*pw));
152 pw->prompt_screen = &si->screens [mouse_screen (si)];
153 if (si->prefs.verbose_p)
154 fprintf (stderr, "%s: %d: creating password dialog.\n",
155 blurb(), pw->prompt_screen->number);
157 screen = pw->prompt_screen->screen;
158 cmap = DefaultColormapOfScreen (screen);
162 pw->heading_label = get_string_resource ("passwd.heading.label",
163 "Dialog.Label.Label");
164 pw->body_label = get_string_resource ("passwd.body.label",
165 "Dialog.Label.Label");
166 pw->user_label = get_string_resource ("passwd.user.label",
167 "Dialog.Label.Label");
168 pw->passwd_label = get_string_resource ("passwd.passwd.label",
169 "Dialog.Label.Label");
170 pw->date_label = get_string_resource ("dateFormat", "DateFormat");
172 if (!pw->heading_label)
173 pw->heading_label = strdup("ERROR: REESOURCES NOT INSTALLED CORRECTLY");
175 pw->body_label = strdup("ERROR: REESOURCES NOT INSTALLED CORRECTLY");
176 if (!pw->user_label) pw->user_label = strdup("ERROR");
177 if (!pw->passwd_label) pw->passwd_label = strdup("ERROR");
178 if (!pw->date_label) pw->date_label = strdup("ERROR");
180 /* Put the version number in the label. */
182 char *s = (char *) malloc (strlen(pw->heading_label) + 20);
183 sprintf(s, pw->heading_label, si->version);
184 free (pw->heading_label);
185 pw->heading_label = s;
188 pw->user_string = (p && p->pw_name ? p->pw_name : "???");
189 pw->passwd_string = strdup("");
191 f = get_string_resource ("passwd.headingFont", "Dialog.Font");
192 pw->heading_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
193 if (!pw->heading_font) pw->heading_font = XLoadQueryFont (si->dpy, "fixed");
196 f = get_string_resource("passwd.bodyFont", "Dialog.Font");
197 pw->body_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
198 if (!pw->body_font) pw->body_font = XLoadQueryFont (si->dpy, "fixed");
201 f = get_string_resource("passwd.labelFont", "Dialog.Font");
202 pw->label_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
203 if (!pw->label_font) pw->label_font = XLoadQueryFont (si->dpy, "fixed");
206 f = get_string_resource("passwd.passwdFont", "Dialog.Font");
207 pw->passwd_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
208 if (!pw->passwd_font) pw->passwd_font = XLoadQueryFont (si->dpy, "fixed");
211 f = get_string_resource("passwd.dateFont", "Dialog.Font");
212 pw->date_font = XLoadQueryFont (si->dpy, (f ? f : "fixed"));
213 if (!pw->date_font) pw->date_font = XLoadQueryFont (si->dpy, "fixed");
216 pw->foreground = get_pixel_resource ("passwd.foreground",
219 pw->background = get_pixel_resource ("passwd.background",
223 if (pw->foreground == pw->background)
225 /* Make sure the error messages show up. */
226 pw->foreground = BlackPixelOfScreen (screen);
227 pw->background = WhitePixelOfScreen (screen);
230 pw->passwd_foreground = get_pixel_resource ("passwd.text.foreground",
231 "Dialog.Text.Foreground",
233 pw->passwd_background = get_pixel_resource ("passwd.text.background",
234 "Dialog.Text.Background",
236 pw->thermo_foreground = get_pixel_resource ("passwd.thermometer.foreground",
237 "Dialog.Thermometer.Foreground",
239 pw->thermo_background = get_pixel_resource ("passwd.thermometer.background",
240 "Dialog.Thermometer.Background",
242 pw->shadow_top = get_pixel_resource ("passwd.topShadowColor",
245 pw->shadow_bottom = get_pixel_resource ("passwd.bottomShadowColor",
249 pw->logo_width = get_integer_resource ("passwd.logo.width",
250 "Dialog.Logo.Width");
251 pw->logo_height = get_integer_resource ("passwd.logo.height",
252 "Dialog.Logo.Height");
253 pw->thermo_width = get_integer_resource ("passwd.thermometer.width",
254 "Dialog.Thermometer.Width");
255 pw->internal_border = get_integer_resource ("passwd.internalBorderWidth",
256 "Dialog.InternalBorderWidth");
257 pw->shadow_width = get_integer_resource ("passwd.shadowThickness",
258 "Dialog.ShadowThickness");
260 if (pw->logo_width == 0) pw->logo_width = 150;
261 if (pw->logo_height == 0) pw->logo_height = 150;
262 if (pw->internal_border == 0) pw->internal_border = 15;
263 if (pw->shadow_width == 0) pw->shadow_width = 4;
264 if (pw->thermo_width == 0) pw->thermo_width = pw->shadow_width;
267 int direction, ascent, descent;
273 /* Measure the heading_label. */
274 XTextExtents (pw->heading_font,
275 pw->heading_label, strlen(pw->heading_label),
276 &direction, &ascent, &descent, &overall);
277 if (overall.width > pw->width) pw->width = overall.width;
278 pw->height += ascent + descent;
280 /* Measure the body_label. */
281 XTextExtents (pw->body_font,
282 pw->body_label, strlen(pw->body_label),
283 &direction, &ascent, &descent, &overall);
284 if (overall.width > pw->width) pw->width = overall.width;
285 pw->height += ascent + descent;
288 Dimension w2 = 0, w3 = 0;
289 Dimension h2 = 0, h3 = 0;
290 const char *passwd_string = "MMMMMMMMMMMM";
292 /* Measure the user_label. */
293 XTextExtents (pw->label_font,
294 pw->user_label, strlen(pw->user_label),
295 &direction, &ascent, &descent, &overall);
296 if (overall.width > w2) w2 = overall.width;
297 h2 += ascent + descent;
299 /* Measure the passwd_label. */
300 XTextExtents (pw->label_font,
301 pw->passwd_label, strlen(pw->passwd_label),
302 &direction, &ascent, &descent, &overall);
303 if (overall.width > w2) w2 = overall.width;
304 h2 += ascent + descent;
306 /* Measure the user_string. */
307 XTextExtents (pw->passwd_font,
308 pw->user_string, strlen(pw->user_string),
309 &direction, &ascent, &descent, &overall);
310 overall.width += (pw->shadow_width * 4);
311 ascent += (pw->shadow_width * 4);
312 if (overall.width > w3) w3 = overall.width;
313 h3 += ascent + descent;
315 /* Measure the (maximally-sized, dummy) passwd_string. */
316 XTextExtents (pw->passwd_font,
317 passwd_string, strlen(passwd_string),
318 &direction, &ascent, &descent, &overall);
319 overall.width += (pw->shadow_width * 4);
320 ascent += (pw->shadow_width * 4);
321 if (overall.width > w3) w3 = overall.width;
322 h3 += ascent + descent;
324 w2 = w2 + w3 + (pw->shadow_width * 2);
327 if (w2 > pw->width) pw->width = w2;
331 pw->width += (pw->internal_border * 2);
332 pw->height += (pw->internal_border * 4);
334 pw->width += pw->thermo_width + (pw->shadow_width * 3);
336 if (pw->logo_height > pw->height)
337 pw->height = pw->logo_height;
338 else if (pw->height > pw->logo_height)
339 pw->logo_height = pw->height;
341 pw->logo_width = pw->logo_height;
343 pw->width += pw->logo_width;
346 attrmask |= CWOverrideRedirect; attrs.override_redirect = True;
347 attrmask |= CWEventMask; attrs.event_mask = ExposureMask|KeyPressMask;
349 /* We need to remember the mouse position and restore it afterward, or
350 sometimes (perhaps only with Xinerama?) the mouse gets warped to
351 inside the bounds of the lock dialog window.
354 Window pointer_root, pointer_child;
355 int root_x, root_y, win_x, win_y;
357 pw->previous_mouse_x = 0;
358 pw->previous_mouse_y = 0;
359 if (XQueryPointer (si->dpy, RootWindowOfScreen (pw->prompt_screen->screen),
360 &pointer_root, &pointer_child,
361 &root_x, &root_y, &win_x, &win_y, &mask))
363 pw->previous_mouse_x = root_x;
364 pw->previous_mouse_y = root_y;
365 if (si->prefs.verbose_p)
366 fprintf (stderr, "%s: %d: mouse is at %d,%d.\n",
367 blurb(), pw->prompt_screen->number,
368 pw->previous_mouse_x, pw->previous_mouse_y);
370 else if (si->prefs.verbose_p)
371 fprintf (stderr, "%s: %d: unable to determine mouse position?\n",
372 blurb(), pw->prompt_screen->number);
375 /* Figure out where on the desktop to place the window so that it will
376 actually be visible; this takes into account virtual viewports as
380 get_screen_viewport (pw->prompt_screen, &x, &y, &w, &h,
381 pw->previous_mouse_x, pw->previous_mouse_y,
382 si->prefs.verbose_p);
383 if (si->prefs.debug_p) w /= 2;
384 pw->x = x + ((w + pw->width) / 2) - pw->width;
385 pw->y = y + ((h + pw->height) / 2) - pw->height;
386 if (pw->x < x) pw->x = x;
387 if (pw->y < y) pw->y = y;
390 pw->border_width = get_integer_resource ("passwd.borderWidth",
391 "Dialog.BorderWidth");
394 XCreateWindow (si->dpy,
395 RootWindowOfScreen(screen),
396 pw->x, pw->y, pw->width, pw->height, pw->border_width,
397 DefaultDepthOfScreen (screen), InputOutput,
398 DefaultVisualOfScreen(screen),
400 XSetWindowBackground (si->dpy, si->passwd_dialog, pw->background);
402 pw->logo_pixmap = xscreensaver_logo (si->dpy, si->passwd_dialog, cmap,
404 &pw->logo_pixels, &pw->logo_npixels,
407 /* Before mapping the window, save the bits that are underneath the
408 rectangle the window will occlude. When we lower the window, we
409 restore these bits. This works, because the running screenhack
410 has already been sent SIGSTOP, so we know nothing else is drawing
415 pw->save_under = XCreatePixmap (si->dpy,
416 pw->prompt_screen->screensaver_window,
417 pw->width + (pw->border_width*2) + 1,
418 pw->height + (pw->border_width*2) + 1,
419 pw->prompt_screen->current_depth);
420 gcv.function = GXcopy;
421 gc = XCreateGC (si->dpy, pw->save_under, GCFunction, &gcv);
422 XCopyArea (si->dpy, pw->prompt_screen->screensaver_window,
424 pw->x - pw->border_width, pw->y - pw->border_width,
425 pw->width + (pw->border_width*2) + 1,
426 pw->height + (pw->border_width*2) + 1,
428 XFreeGC (si->dpy, gc);
431 XMapRaised (si->dpy, si->passwd_dialog);
432 XSync (si->dpy, False);
434 move_mouse_grab (si, si->passwd_dialog,
435 pw->prompt_screen->cursor,
436 pw->prompt_screen->number);
442 XInstallColormap (si->dpy, cmap);
443 draw_passwd_window (si);
444 XSync (si->dpy, False);
449 draw_passwd_window (saver_info *si)
451 passwd_dialog_data *pw = si->pw_data;
455 int x1, x2, x3, y1, y2;
459 height = (pw->heading_font->ascent + pw->heading_font->descent +
460 pw->body_font->ascent + pw->body_font->descent +
461 (2 * MAX ((pw->label_font->ascent + pw->label_font->descent),
462 (pw->passwd_font->ascent + pw->passwd_font->descent +
463 (pw->shadow_width * 4)))) +
464 pw->date_font->ascent + pw->date_font->descent
466 spacing = ((pw->height - (2 * pw->shadow_width) -
467 pw->internal_border - height)) / 8;
468 if (spacing < 0) spacing = 0;
470 gcv.foreground = pw->foreground;
471 gc1 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
472 gc2 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
473 x1 = pw->logo_width + pw->thermo_width + (pw->shadow_width * 3);
474 x3 = pw->width - (pw->shadow_width * 2);
475 y1 = (pw->shadow_width * 2) + spacing + spacing;
479 XSetFont (si->dpy, gc1, pw->heading_font->fid);
480 sw = string_width (pw->heading_font, pw->heading_label);
481 x2 = (x1 + ((x3 - x1 - sw) / 2));
482 y1 += spacing + pw->heading_font->ascent + pw->heading_font->descent;
483 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
484 pw->heading_label, strlen(pw->heading_label));
486 /* text below top heading
488 XSetFont (si->dpy, gc1, pw->body_font->fid);
489 y1 += spacing + pw->body_font->ascent + pw->body_font->descent;
490 sw = string_width (pw->body_font, pw->body_label);
491 x2 = (x1 + ((x3 - x1 - sw) / 2));
492 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
493 pw->body_label, strlen(pw->body_label));
496 tb_height = (pw->passwd_font->ascent + pw->passwd_font->descent +
497 (pw->shadow_width * 4));
499 /* the "User:" prompt
503 XSetForeground (si->dpy, gc1, pw->foreground);
504 XSetFont (si->dpy, gc1, pw->label_font->fid);
505 y1 += (spacing + tb_height);
506 x2 = (x1 + pw->internal_border +
507 MAX(string_width (pw->label_font, pw->user_label),
508 string_width (pw->label_font, pw->passwd_label)));
509 XDrawString (si->dpy, si->passwd_dialog, gc1,
510 x2 - string_width (pw->label_font, pw->user_label),
512 pw->user_label, strlen(pw->user_label));
514 /* the "Password:" prompt
516 y1 += (spacing + tb_height);
517 XDrawString (si->dpy, si->passwd_dialog, gc1,
518 x2 - string_width (pw->label_font, pw->passwd_label),
520 pw->passwd_label, strlen(pw->passwd_label));
523 XSetForeground (si->dpy, gc2, pw->passwd_background);
525 /* the "user name" text field
528 XSetForeground (si->dpy, gc1, pw->passwd_foreground);
529 XSetFont (si->dpy, gc1, pw->passwd_font->fid);
530 y1 += (spacing + tb_height);
531 x2 += (pw->shadow_width * 4);
533 pw->passwd_field_width = x3 - x2 - pw->internal_border;
534 pw->passwd_field_height = (pw->passwd_font->ascent +
535 pw->passwd_font->descent +
538 XFillRectangle (si->dpy, si->passwd_dialog, gc2,
539 x2 - pw->shadow_width,
540 y1 - (pw->passwd_font->ascent + pw->passwd_font->descent),
541 pw->passwd_field_width, pw->passwd_field_height);
542 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1,
543 pw->user_string, strlen(pw->user_string));
545 /* the "password" text field
547 y1 += (spacing + tb_height);
549 pw->passwd_field_x = x2 - pw->shadow_width;
550 pw->passwd_field_y = y1 - (pw->passwd_font->ascent +
551 pw->passwd_font->descent);
553 /* The shadow around the text fields
556 y1 += (spacing + (pw->shadow_width * 3));
557 x1 = x2 - (pw->shadow_width * 2);
558 x2 = pw->passwd_field_width + (pw->shadow_width * 2);
559 y2 = pw->passwd_field_height + (pw->shadow_width * 2);
561 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
564 pw->shadow_bottom, pw->shadow_top);
566 y1 += (spacing + pw->passwd_font->ascent + pw->passwd_font->descent +
567 (pw->shadow_width * 4));
568 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
571 pw->shadow_bottom, pw->shadow_top);
574 /* The date, below the text fields
578 time_t now = time ((time_t *) 0);
579 struct tm *tm = localtime (&now);
580 memset (buf, 0, sizeof(buf));
581 strftime (buf, sizeof(buf)-1, pw->date_label, tm);
583 XSetFont (si->dpy, gc1, pw->date_font->fid);
584 y1 += pw->shadow_width;
585 y1 += (spacing + tb_height);
587 sw = string_width (pw->date_font, buf);
589 XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1, buf, strlen(buf));
595 x1 = pw->shadow_width * 6;
596 y1 = pw->shadow_width * 6;
597 x2 = pw->logo_width - (pw->shadow_width * 12);
598 y2 = pw->logo_height - (pw->shadow_width * 12);
604 unsigned int w, h, bw, d;
605 XGetGeometry (si->dpy, pw->logo_pixmap, &root, &x, &y, &w, &h, &bw, &d);
606 XSetForeground (si->dpy, gc1, pw->foreground);
607 XSetBackground (si->dpy, gc1, pw->background);
609 XCopyPlane (si->dpy, pw->logo_pixmap, si->passwd_dialog, gc1,
611 x1 + ((x2 - (int)w) / 2),
612 y1 + ((y2 - (int)h) / 2),
615 XCopyArea (si->dpy, pw->logo_pixmap, si->passwd_dialog, gc1,
617 x1 + ((x2 - (int)w) / 2),
618 y1 + ((y2 - (int)h) / 2));
623 XSetForeground (si->dpy, gc1, pw->thermo_foreground);
624 XSetForeground (si->dpy, gc2, pw->thermo_background);
626 pw->thermo_field_x = pw->logo_width + pw->shadow_width;
627 pw->thermo_field_y = pw->shadow_width * 5;
628 pw->thermo_field_height = pw->height - (pw->shadow_width * 10);
631 /* Solid border inside the logo box. */
632 XSetForeground (si->dpy, gc1, pw->foreground);
633 XDrawRectangle (si->dpy, si->passwd_dialog, gc1, x1, y1, x2-1, y2-1);
636 /* The shadow around the logo
638 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
639 pw->shadow_width * 4,
640 pw->shadow_width * 4,
641 pw->logo_width - (pw->shadow_width * 8),
642 pw->logo_height - (pw->shadow_width * 8),
644 pw->shadow_bottom, pw->shadow_top);
646 /* The shadow around the thermometer
648 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
650 pw->shadow_width * 4,
651 pw->thermo_width + (pw->shadow_width * 2),
652 pw->height - (pw->shadow_width * 8),
654 pw->shadow_bottom, pw->shadow_top);
657 /* Solid border inside the thermometer. */
658 XSetForeground (si->dpy, gc1, pw->foreground);
659 XDrawRectangle (si->dpy, si->passwd_dialog, gc1,
660 pw->thermo_field_x, pw->thermo_field_y,
661 pw->thermo_width - 1, pw->thermo_field_height - 1);
664 /* The shadow around the whole window
666 draw_shaded_rectangle (si->dpy, si->passwd_dialog,
667 0, 0, pw->width, pw->height, pw->shadow_width,
668 pw->shadow_top, pw->shadow_bottom);
670 XFreeGC (si->dpy, gc1);
671 XFreeGC (si->dpy, gc2);
673 update_passwd_window (si, pw->passwd_string, pw->ratio);
678 update_passwd_window (saver_info *si, const char *printed_passwd, float ratio)
680 passwd_dialog_data *pw = si->pw_data;
687 gcv.foreground = pw->passwd_foreground;
688 gcv.font = pw->passwd_font->fid;
689 gc1 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground|GCFont, &gcv);
690 gcv.foreground = pw->passwd_background;
691 gc2 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv);
695 char *s = strdup (printed_passwd);
696 if (pw->passwd_string) free (pw->passwd_string);
697 pw->passwd_string = s;
700 /* the "password" text field
702 rects[0].x = pw->passwd_field_x;
703 rects[0].y = pw->passwd_field_y;
704 rects[0].width = pw->passwd_field_width;
705 rects[0].height = pw->passwd_field_height;
707 XFillRectangle (si->dpy, si->passwd_dialog, gc2,
708 rects[0].x, rects[0].y, rects[0].width, rects[0].height);
710 XSetClipRectangles (si->dpy, gc1, 0, 0, rects, 1, Unsorted);
712 XDrawString (si->dpy, si->passwd_dialog, gc1,
713 rects[0].x + pw->shadow_width,
714 rects[0].y + (pw->passwd_font->ascent +
715 pw->passwd_font->descent),
716 pw->passwd_string, strlen(pw->passwd_string));
718 XSetClipMask (si->dpy, gc1, None);
724 x = (rects[0].x + pw->shadow_width +
725 string_width (pw->passwd_font, pw->passwd_string));
726 y = rects[0].y + pw->shadow_width;
728 if (x > rects[0].x + rects[0].width - 1)
729 x = rects[0].x + rects[0].width - 1;
730 XDrawLine (si->dpy, si->passwd_dialog, gc1,
731 x, y, x, y + pw->passwd_font->ascent);
734 pw->i_beam = (pw->i_beam + 1) % 4;
739 y = (pw->thermo_field_height - 2) * (1.0 - pw->ratio);
742 XFillRectangle (si->dpy, si->passwd_dialog, gc2,
743 pw->thermo_field_x + 1,
744 pw->thermo_field_y + 1,
747 XSetForeground (si->dpy, gc1, pw->thermo_foreground);
748 XFillRectangle (si->dpy, si->passwd_dialog, gc1,
749 pw->thermo_field_x + 1,
750 pw->thermo_field_y + 1 + y,
752 MAX (0, pw->thermo_field_height - y - 2));
755 XFreeGC (si->dpy, gc1);
756 XFreeGC (si->dpy, gc2);
757 XSync (si->dpy, False);
762 destroy_passwd_window (saver_info *si)
764 saver_preferences *p = &si->prefs;
765 passwd_dialog_data *pw = si->pw_data;
766 saver_screen_info *ssi = pw->prompt_screen;
767 Colormap cmap = DefaultColormapOfScreen (ssi->screen);
768 Pixel black = BlackPixelOfScreen (ssi->screen);
769 Pixel white = WhitePixelOfScreen (ssi->screen);
773 XtRemoveTimeOut (pw->timer);
775 move_mouse_grab (si, RootWindowOfScreen (ssi->screen),
776 ssi->cursor, ssi->number);
779 fprintf (stderr, "%s: %d: moving mouse back to %d,%d.\n",
780 blurb(), ssi->number,
781 pw->previous_mouse_x, pw->previous_mouse_y);
783 XWarpPointer (si->dpy, None, RootWindowOfScreen (ssi->screen),
785 pw->previous_mouse_x, pw->previous_mouse_y);
787 XSync (si->dpy, False);
788 while (XCheckMaskEvent (si->dpy, PointerMotionMask, &event))
790 fprintf (stderr, "%s: discarding MotionNotify event.\n", blurb());
792 if (si->passwd_dialog)
794 XDestroyWindow (si->dpy, si->passwd_dialog);
795 si->passwd_dialog = 0;
802 gcv.function = GXcopy;
803 gc = XCreateGC (si->dpy, ssi->screensaver_window, GCFunction, &gcv);
804 XCopyArea (si->dpy, pw->save_under,
805 ssi->screensaver_window, gc,
807 pw->width + (pw->border_width*2) + 1,
808 pw->height + (pw->border_width*2) + 1,
809 pw->x - pw->border_width, pw->y - pw->border_width);
810 XFreePixmap (si->dpy, pw->save_under);
812 XFreeGC (si->dpy, gc);
815 if (pw->heading_label) free (pw->heading_label);
816 if (pw->body_label) free (pw->body_label);
817 if (pw->user_label) free (pw->user_label);
818 if (pw->passwd_label) free (pw->passwd_label);
820 if (pw->heading_font) XFreeFont (si->dpy, pw->heading_font);
821 if (pw->body_font) XFreeFont (si->dpy, pw->body_font);
822 if (pw->label_font) XFreeFont (si->dpy, pw->label_font);
823 if (pw->passwd_font) XFreeFont (si->dpy, pw->passwd_font);
825 if (pw->foreground != black && pw->foreground != white)
826 XFreeColors (si->dpy, cmap, &pw->foreground, 1, 0L);
827 if (pw->background != black && pw->background != white)
828 XFreeColors (si->dpy, cmap, &pw->background, 1, 0L);
829 if (pw->passwd_foreground != black && pw->passwd_foreground != white)
830 XFreeColors (si->dpy, cmap, &pw->passwd_foreground, 1, 0L);
831 if (pw->passwd_background != black && pw->passwd_background != white)
832 XFreeColors (si->dpy, cmap, &pw->passwd_background, 1, 0L);
833 if (pw->thermo_foreground != black && pw->thermo_foreground != white)
834 XFreeColors (si->dpy, cmap, &pw->thermo_foreground, 1, 0L);
835 if (pw->thermo_background != black && pw->thermo_background != white)
836 XFreeColors (si->dpy, cmap, &pw->thermo_background, 1, 0L);
837 if (pw->shadow_top != black && pw->shadow_top != white)
838 XFreeColors (si->dpy, cmap, &pw->shadow_top, 1, 0L);
839 if (pw->shadow_bottom != black && pw->shadow_bottom != white)
840 XFreeColors (si->dpy, cmap, &pw->shadow_bottom, 1, 0L);
843 XFreePixmap (si->dpy, pw->logo_pixmap);
844 if (pw->logo_npixels && pw->logo_pixels)
845 XFreeColors (si->dpy, cmap, pw->logo_pixels, pw->logo_npixels, 0L);
847 free (pw->logo_pixels);
849 memset (pw, 0, sizeof(*pw));
853 XInstallColormap (si->dpy, cmap);
859 #ifdef HAVE_XHPDISABLERESET
860 /* This function enables and disables the C-Sh-Reset hot-key, which
861 normally resets the X server (logging out the logged-in user.)
862 We don't want random people to be able to do that while the
866 hp_lock_reset (saver_info *si, Bool lock_p)
868 static Bool hp_locked_p = False;
870 /* Calls to XHPDisableReset and XHPEnableReset must be balanced,
871 or BadAccess errors occur. (It's ok for this to be global,
872 since it affects the whole machine, not just the current screen.)
874 if (hp_locked_p == lock_p)
878 XHPDisableReset (si->dpy);
880 XHPEnableReset (si->dpy);
881 hp_locked_p = lock_p;
883 #endif /* HAVE_XHPDISABLERESET */
887 /* This function enables and disables the C-Sh-F1 ... F12 hot-keys,
888 which, on Linux systems, switches to another virtual console.
889 We'd like the whole screen/keyboard to be locked, not just one
890 virtual console, so this function disables that while the X
893 Unfortunately, this doesn't work -- this ioctl only works when
894 called by root, and we have disavowed our privileges long ago.
896 #ifdef HAVE_VT_LOCKSWITCH
898 linux_lock_vt_switch (saver_info *si, Bool lock_p)
900 saver_preferences *p = &si->prefs;
901 static Bool vt_locked_p = False;
902 const char *dev_console = "/dev/console";
905 if (lock_p == vt_locked_p)
908 if (lock_p && !p->lock_vt_p)
911 fd = open (dev_console, O_RDWR);
915 sprintf (buf, "%s: couldn't %s VTs: %s", blurb(),
916 (lock_p ? "lock" : "unlock"),
918 #if 1 /* #### doesn't work yet, so don't bother complaining */
924 if (ioctl (fd, (lock_p ? VT_LOCKSWITCH : VT_UNLOCKSWITCH)) == 0)
926 vt_locked_p = lock_p;
929 fprintf (stderr, "%s: %s VTs\n", blurb(),
930 (lock_p ? "locked" : "unlocked"));
935 sprintf (buf, "%s: couldn't %s VTs: ioctl", blurb(),
936 (lock_p ? "lock" : "unlock"));
937 #if 0 /* #### doesn't work yet, so don't bother complaining */
944 #endif /* HAVE_VT_LOCKSWITCH */
947 /* This function enables and disables the C-Alt-Plus and C-Alt-Minus
948 hot-keys, which normally change the resolution of the X server.
949 We don't want people to be able to switch the server resolution
950 while the screen is locked, because if they switch to a higher
951 resolution, it could cause part of the underlying desktop to become
954 #ifdef HAVE_XF86VMODE
956 static int ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error);
957 static Bool vp_got_error = False;
960 xfree_lock_mode_switch (saver_info *si, Bool lock_p)
962 static Bool any_mode_locked_p = False;
963 saver_preferences *p = &si->prefs;
967 XErrorHandler old_handler;
969 if (any_mode_locked_p == lock_p)
971 if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
974 for (screen = 0; screen < si->nscreens; screen++)
976 XSync (si->dpy, False);
977 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
978 status = XF86VidModeLockModeSwitch (si->dpy, screen, lock_p);
979 XSync (si->dpy, False);
980 XSetErrorHandler (old_handler);
981 if (vp_got_error) status = False;
984 any_mode_locked_p = lock_p;
986 if (!status && (p->verbose_p || !lock_p))
987 /* Only print this when verbose, or when we locked but can't unlock.
988 I tried printing this message whenever it comes up, but
989 mode-locking always fails if DontZoom is set in XF86Config. */
990 fprintf (stderr, "%s: %d: unable to %s mode switching!\n",
991 blurb(), screen, (lock_p ? "lock" : "unlock"));
992 else if (p->verbose_p)
993 fprintf (stderr, "%s: %d: %s mode switching.\n",
994 blurb(), screen, (lock_p ? "locked" : "unlocked"));
999 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
1001 vp_got_error = True;
1005 #endif /* HAVE_XF86VMODE */
1008 /* If the viewport has been scrolled since the screen was blanked,
1009 then scroll it back to where it belongs. This function only exists
1010 to patch over a very brief race condition.
1013 undo_vp_motion (saver_info *si)
1015 #ifdef HAVE_XF86VMODE
1016 saver_preferences *p = &si->prefs;
1020 if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
1023 for (screen = 0; screen < si->nscreens; screen++)
1025 saver_screen_info *ssi = &si->screens[screen];
1029 if (ssi->blank_vp_x == -1 && ssi->blank_vp_y == -1)
1031 if (!XF86VidModeGetViewPort (si->dpy, screen, &x, &y))
1033 if (ssi->blank_vp_x == x && ssi->blank_vp_y == y)
1036 /* We're going to move the viewport. The mouse has just been grabbed on
1037 (and constrained to, thus warped to) the password window, so it is no
1038 longer near the edge of the screen. However, wait a bit anyway, just
1039 to make sure the server drains its last motion event, so that the
1040 screen doesn't continue to scroll after we've reset the viewport.
1042 XSync (si->dpy, False);
1043 usleep (250000); /* 1/4 second */
1044 XSync (si->dpy, False);
1046 status = XF86VidModeSetViewPort (si->dpy, screen,
1047 ssi->blank_vp_x, ssi->blank_vp_y);
1051 "%s: %d: unable to move vp from (%d,%d) back to (%d,%d)!\n",
1052 blurb(), screen, x, y, ssi->blank_vp_x, ssi->blank_vp_y);
1053 else if (p->verbose_p)
1055 "%s: %d: vp moved to (%d,%d); moved it back to (%d,%d).\n",
1056 blurb(), screen, x, y, ssi->blank_vp_x, ssi->blank_vp_y);
1058 #endif /* HAVE_XF86VMODE */
1067 passwd_animate_timer (XtPointer closure, XtIntervalId *id)
1069 saver_info *si = (saver_info *) closure;
1071 passwd_dialog_data *pw = si->pw_data;
1075 pw->ratio -= (1.0 / ((double) si->prefs.passwd_timeout / (double) tick));
1079 if (pw->state == pw_read)
1080 pw->state = pw_time;
1083 update_passwd_window (si, 0, pw->ratio);
1085 if (pw->state == pw_read)
1086 pw->timer = XtAppAddTimeOut (si->app, tick, passwd_animate_timer,
1091 idle_timer ((XtPointer) si, id);
1095 static XComposeStatus *compose_status;
1098 handle_passwd_key (saver_info *si, XKeyEvent *event)
1100 saver_preferences *p = &si->prefs;
1101 passwd_dialog_data *pw = si->pw_data;
1102 int pw_size = sizeof (pw->typed_passwd) - 1;
1103 char *typed_passwd = pw->typed_passwd;
1107 int size = XLookupString (event, s, 1, 0, compose_status);
1109 if (size != 1) return;
1115 case '\010': case '\177': /* Backspace */
1119 typed_passwd [strlen(typed_passwd)-1] = 0;
1122 case '\025': case '\030': /* Erase line */
1123 memset (typed_passwd, 0, pw_size);
1126 case '\012': case '\015': /* Enter */
1127 if (pw->state != pw_read)
1128 ; /* already done? */
1129 else if (typed_passwd[0] == 0)
1130 pw->state = pw_null;
1133 update_passwd_window (si, "Checking...", pw->ratio);
1134 XSync (si->dpy, False);
1135 if (passwd_valid_p (typed_passwd, p->verbose_p))
1138 pw->state = pw_fail;
1139 update_passwd_window (si, "", pw->ratio);
1144 i = strlen (typed_passwd);
1149 typed_passwd [i] = *s;
1150 typed_passwd [i+1] = 0;
1155 i = strlen(typed_passwd);
1156 stars = (char *) malloc(i+1);
1157 memset (stars, '*', i);
1159 update_passwd_window (si, stars, pw->ratio);
1165 passwd_event_loop (saver_info *si)
1167 saver_preferences *p = &si->prefs;
1170 passwd_animate_timer ((XtPointer) si, 0);
1172 while (si->pw_data && si->pw_data->state == pw_read)
1174 XtAppNextEvent (si->app, &event);
1175 if (event.xany.window == si->passwd_dialog && event.xany.type == Expose)
1176 draw_passwd_window (si);
1177 else if (event.xany.type == KeyPress)
1178 handle_passwd_key (si, &event.xkey);
1180 XtDispatchEvent (&event);
1183 switch (si->pw_data->state)
1185 case pw_ok: msg = 0; break;
1186 case pw_null: msg = ""; break;
1187 case pw_time: msg = "Timed out!"; break;
1188 default: msg = "Sorry!"; break;
1191 if (si->pw_data->state == pw_fail)
1192 si->unlock_failures++;
1195 switch (si->pw_data->state)
1198 fprintf (stderr, "%s: password correct.\n", blurb()); break;
1200 fprintf (stderr, "%s: password incorrect!\n", blurb()); break;
1203 fprintf (stderr, "%s: password entry cancelled.\n", blurb()); break;
1205 fprintf (stderr, "%s: password entry timed out.\n", blurb()); break;
1210 if (si->pw_data->state == pw_fail)
1212 /* If they typed a password (as opposed to just hitting return) and
1213 the password was invalid, log it.
1215 struct passwd *pw = getpwuid (getuid ());
1216 char *d = DisplayString (si->dpy);
1217 char *u = (pw->pw_name ? pw->pw_name : "???");
1225 # if defined(LOG_AUTHPRIV)
1227 # elif defined(LOG_AUTH)
1234 openlog (progname, opt, fac);
1235 syslog (LOG_NOTICE, "FAILED LOGIN %d ON DISPLAY \"%s\", FOR \"%s\"",
1236 si->unlock_failures, d, u);
1239 #endif /* HAVE_SYSLOG */
1241 if (si->pw_data->state == pw_fail)
1242 XBell (si->dpy, False);
1244 if (si->pw_data->state == pw_ok && si->unlock_failures != 0)
1246 if (si->unlock_failures == 1)
1247 fprintf (real_stderr,
1248 "%s: WARNING: 1 failed attempt to unlock the screen.\n",
1251 fprintf (real_stderr,
1252 "%s: WARNING: %d failed attempts to unlock the screen.\n",
1253 blurb(), si->unlock_failures);
1254 fflush (real_stderr);
1256 si->unlock_failures = 0;
1261 si->pw_data->i_beam = 0;
1262 update_passwd_window (si, msg, 0.0);
1263 XSync (si->dpy, False);
1266 /* Swallow all pending KeyPress/KeyRelease events. */
1269 while (XCheckMaskEvent (si->dpy, KeyPressMask|KeyReleaseMask, &e))
1277 handle_typeahead (saver_info *si)
1279 passwd_dialog_data *pw = si->pw_data;
1281 if (!si->unlock_typeahead)
1284 i = strlen (si->unlock_typeahead);
1285 if (i >= sizeof(pw->typed_passwd) - 1)
1286 i = sizeof(pw->typed_passwd) - 1;
1288 memcpy (pw->typed_passwd, si->unlock_typeahead, i);
1289 pw->typed_passwd [i] = 0;
1291 memset (si->unlock_typeahead, '*', strlen(si->unlock_typeahead));
1292 si->unlock_typeahead[i] = 0;
1293 update_passwd_window (si, si->unlock_typeahead, pw->ratio);
1295 free (si->unlock_typeahead);
1296 si->unlock_typeahead = 0;
1301 unlock_p (saver_info *si)
1303 saver_preferences *p = &si->prefs;
1306 raise_window (si, True, True, True);
1309 fprintf (stderr, "%s: prompting for password.\n", blurb());
1311 if (si->pw_data || si->passwd_dialog)
1312 destroy_passwd_window (si);
1314 make_passwd_window (si);
1316 compose_status = calloc (1, sizeof (*compose_status));
1318 handle_typeahead (si);
1319 passwd_event_loop (si);
1321 status = (si->pw_data->state == pw_ok);
1322 destroy_passwd_window (si);
1324 free (compose_status);
1332 set_locked_p (saver_info *si, Bool locked_p)
1334 si->locked_p = locked_p;
1336 #ifdef HAVE_XHPDISABLERESET
1337 hp_lock_reset (si, locked_p); /* turn off/on C-Sh-Reset */
1339 #ifdef HAVE_VT_LOCKSWITCH
1340 linux_lock_vt_switch (si, locked_p); /* turn off/on C-Alt-F1 */
1342 #ifdef HAVE_XF86VMODE
1343 xfree_lock_mode_switch (si, locked_p); /* turn off/on C-Alt-Plus */
1346 store_saver_status (si); /* store locked-p */
1350 #else /* NO_LOCKING -- whole file */
1353 set_locked_p (saver_info *si, Bool locked_p)
1355 if (locked_p) abort();
1358 #endif /* !NO_LOCKING */