2 * xnlock -- Dan Heller, 1990
3 * "nlock" is a "new lockscreen" type program... something that prevents
4 * screen burnout by making most of it "black" while providing something
5 * of interest to be displayed in case anyone is watching.
6 * "xnlock" is the X11 version of the program.
7 * Original sunview version written by Dan Heller 1985 (not included here).
18 #include <X11/StringDefs.h>
19 #include <X11/Intrinsic.h>
20 #include <X11/keysym.h>
21 #include <X11/Shell.h>
23 #ifdef HAVE_SYS_TYPES_H
24 #include <sys/types.h>
31 #define des_encrypt wingless_pigs_mostly_fail_to_fly
44 static char login
[16];
45 static char userprompt
[128];
47 static krb5_context context
;
48 static krb5_principal client
;
51 #define font_height(font) (font->ascent + font->descent)
53 static char *SPACE_STRING
= " ";
54 static char STRING
[] = "****************";
56 #define STRING_LENGTH (sizeof(STRING))
57 #define MAX_PASSWD_LENGTH 256
58 /* (sizeof(STRING)) */
60 #define PROMPT "Password: "
61 #define FAIL_MSG "Sorry, try again"
70 #define XNLOCK_NOCTRL 0
72 static XtAppContext app
;
74 static unsigned short Width
, Height
;
77 static XtIntervalId timeout_id
;
80 static Pixel Black
, White
;
81 static XFontStruct
*font
;
82 static char root_cpass
[128];
83 static char user_cpass
[128];
84 static int time_left
, prompt_x
, prompt_y
, time_x
, time_y
;
85 static unsigned long interval
;
86 static Pixmap left0
, left1
, right0
, right1
, left_front
,
87 right_front
, front
, down
;
93 static int state
; /* indicates states: walking or getting passwd */
95 static int ALLOW_LOGOUT
= (60*10); /* Allow logout after nn seconds */
96 #define LOGOUT_PASSWD "enuHDmTo5Lq4g" /* when given password "LOGOUT" */
97 static time_t locked_at
;
103 Boolean ignore_passwd
;
106 char *text
, *text_prog
, *file
, *logoutPasswd
;
107 Boolean no_screensaver
;
108 Boolean destroytickets
;
111 static XtResource resources
[] = {
112 { XtNbackground
, XtCBackground
, XtRPixel
, sizeof(Pixel
),
113 XtOffsetOf(struct appres_t
, bg
), XtRString
, "black" },
115 { XtNforeground
, XtCForeground
, XtRPixel
, sizeof(Pixel
),
116 XtOffsetOf(struct appres_t
, fg
), XtRString
, "white" },
118 { XtNfont
, XtCFont
, XtRFontStruct
, sizeof (XFontStruct
*),
119 XtOffsetOf(struct appres_t
, font
),
120 XtRString
, "-*-new century schoolbook-*-*-*-18-*" },
122 { "ignorePasswd", "IgnorePasswd", XtRBoolean
, sizeof(Boolean
),
123 XtOffsetOf(struct appres_t
,ignore_passwd
),XtRImmediate
,(XtPointer
)False
},
125 { "acceptRootPasswd", "AcceptRootPasswd", XtRBoolean
, sizeof(Boolean
),
126 XtOffsetOf(struct appres_t
, accept_root
), XtRImmediate
, (XtPointer
)True
},
128 { "text", "Text", XtRString
, sizeof(String
),
129 XtOffsetOf(struct appres_t
, text
), XtRString
, "I'm out running around." },
131 { "program", "Program", XtRString
, sizeof(String
),
132 XtOffsetOf(struct appres_t
, text_prog
), XtRImmediate
, NULL
},
134 { "file", "File", XtRString
, sizeof(String
),
135 XtOffsetOf(struct appres_t
,file
), XtRImmediate
, NULL
},
137 { "logoutPasswd", "logoutPasswd", XtRString
, sizeof(String
),
138 XtOffsetOf(struct appres_t
, logoutPasswd
), XtRString
, LOGOUT_PASSWD
},
140 { "noScreenSaver", "NoScreenSaver", XtRBoolean
, sizeof(Boolean
),
141 XtOffsetOf(struct appres_t
,no_screensaver
), XtRImmediate
, (XtPointer
)True
},
143 { "destroyTickets", "DestroyTickets", XtRBoolean
, sizeof(Boolean
),
144 XtOffsetOf(struct appres_t
,destroytickets
), XtRImmediate
, (XtPointer
)True
},
147 static XrmOptionDescRec options
[] = {
148 { "-fg", ".foreground", XrmoptionSepArg
, NULL
},
149 { "-foreground", ".foreground", XrmoptionSepArg
, NULL
},
150 { "-fn", ".font", XrmoptionSepArg
, NULL
},
151 { "-font", ".font", XrmoptionSepArg
, NULL
},
152 { "-ip", ".ignorePasswd", XrmoptionNoArg
, "True" },
153 { "-noip", ".ignorePasswd", XrmoptionNoArg
, "False" },
154 { "-ar", ".acceptRootPasswd", XrmoptionNoArg
, "True" },
155 { "-noar", ".acceptRootPasswd", XrmoptionNoArg
, "False" },
156 { "-nonoscreensaver", ".noScreenSaver", XrmoptionNoArg
, "False" },
157 { "-nodestroytickets", ".destroyTickets", XrmoptionNoArg
, "False" },
164 static char buf
[512];
167 if (appres
.text_prog
) {
168 pp
= popen(appres
.text_prog
, "r");
170 warn("popen %s", appres
.text_prog
);
173 n
= fread(buf
, 1, sizeof(buf
) - 1, pp
);
179 pp
= fopen(appres
.file
, "r");
181 warn("fopen %s", appres
.file
);
184 n
= fread(buf
, 1, sizeof(buf
) - 1, pp
);
196 fprintf(stderr
, "usage: %s [options] [message]\n", getprogname());
197 fprintf(stderr
, "-fg color foreground color\n");
198 fprintf(stderr
, "-bg color background color\n");
199 fprintf(stderr
, "-rv reverse foreground/background colors\n");
200 fprintf(stderr
, "-nrv no reverse video\n");
201 fprintf(stderr
, "-ip ignore passwd\n");
202 fprintf(stderr
, "-nip don't ignore passwd\n");
203 fprintf(stderr
, "-ar accept root's passwd to unlock\n");
204 fprintf(stderr
, "-nar don't accept root's passwd\n");
205 fprintf(stderr
, "-f [file] message is read from file or ~/.msgfile\n");
206 fprintf(stderr
, "-prog program text is gotten from executing `program'\n");
207 fprintf(stderr
, "-nodestroytickets keep kerberos tickets\n");
208 fprintf(stderr
, "--version\n");
209 fprintf(stderr
, "--help\n");
214 init_words (int argc
, char **argv
)
219 if(strcmp(argv
[i
], "-p") == 0
220 || strcmp(argv
[i
], "-prog") == 0) {
223 appres
.text_prog
= argv
[i
];
226 warnx ("-p requires an argument");
229 } else if(strcmp(argv
[i
], "-f") == 0) {
232 appres
.file
= argv
[i
];
236 ret
= asprintf (&appres
.file
,
237 "%s/.msgfile", getenv("HOME"));
239 errx (1, "cannot allocate memory for message");
241 } else if(strcmp(argv
[i
], "--version") == 0) {
244 } else if(strcmp(argv
[i
], "--help") == 0) {
249 for(j
= i
; argv
[j
]; j
++)
250 len
+= strlen(argv
[j
]) + 1;
251 appres
.text
= malloc(len
);
252 if (appres
.text
== NULL
)
253 errx (1, "cannot allocate memory for message");
256 strlcat(appres
.text
, argv
[i
], len
);
257 strlcat(appres
.text
, " ", len
);
264 ScreenSaver(int save
)
266 static int timeout
, interval
, prefer_blank
, allow_exp
;
267 if(!appres
.no_screensaver
){
269 XGetScreenSaver(dpy
, &timeout
, &interval
,
270 &prefer_blank
, &allow_exp
);
271 XSetScreenSaver(dpy
, 0, interval
, prefer_blank
, allow_exp
);
274 XSetScreenSaver(dpy
, timeout
, interval
, prefer_blank
, allow_exp
);
278 /* Forward decls necessary */
279 static void talk(int force_erase
);
280 static unsigned long look(void);
287 warn ("zrefresh: fork");
291 execlp("zrefresh", "zrefresh", NULL
);
292 execl(BINDIR
"/zrefresh", "zrefresh", NULL
);
304 XUngrabPointer(dpy
, CurrentTime
);
305 XUngrabKeyboard(dpy
, CurrentTime
);
320 XSetForeground(dpy
, gc
, White
);
321 XSetBackground(dpy
, gc
, Black
);
322 if (dir
& (LEFT
|RIGHT
)) { /* left/right movement (mabye up/down too) */
323 up
= -up
; /* bouncing effect (even if hit a wall) */
326 frame
= (up
< 0) ? left0
: left1
;
329 frame
= (up
< 0) ? right0
: right1
;
331 if ((lastdir
== FRONT
|| lastdir
== DOWN
) && dir
& UP
) {
332 /* workaround silly bug that leaves screen dust when
333 * guy is facing forward or down and moves up-left/right.
335 XCopyPlane(dpy
, frame
, XtWindow(widget
), gc
, 0, 0, 64,64, x
, y
, 1L);
338 /* note that maybe neither UP nor DOWN is set! */
339 if (dir
& UP
&& y
> Y_INCR
)
341 else if (dir
& DOWN
&& y
< (int)Height
- 64)
344 /* Explicit up/down movement only (no left/right) */
346 XCopyPlane(dpy
, front
, XtWindow(widget
), gc
,
347 0,0, 64,64, x
, y
-= Y_INCR
, 1L);
348 else if (dir
== DOWN
)
349 XCopyPlane(dpy
, down
, XtWindow(widget
), gc
,
350 0,0, 64,64, x
, y
+= Y_INCR
, 1L);
351 else if (dir
== FRONT
&& frame
!= front
) {
356 else if (lastdir
& RIGHT
)
360 XCopyPlane(dpy
, frame
, XtWindow(widget
), gc
, 0, 0, 64,64, x
, y
, 1L);
364 XCopyPlane(dpy
, frame
, XtWindow(widget
), gc
,
365 0,0, 64,64, --x
, y
+up
, 1L);
368 else if (dir
& RIGHT
)
370 XCopyPlane(dpy
, frame
, XtWindow(widget
), gc
,
371 0,0, 64,64, ++x
, y
+up
, 1L);
392 if (my_random() & 1) {
400 move(XtPointer _p
, XtIntervalId
*_id
)
403 static unsigned int length
;
408 if ((my_random() & 1) && think()) {
409 talk(0); /* sets timeout to itself */
412 if (!(my_random() % 3) && (interval
= look())) {
413 timeout_id
= XtAppAddTimeOut(app
, interval
, move
, NULL
);
416 interval
= 20 + my_random() % 100;
419 length
= Width
/100 + my_random() % 90, tries
= 8;
422 switch (my_random() % 8) {
424 if (x
- X_INCR
*length
>= 5)
427 if (x
+ X_INCR
*length
<= (int)Width
- 70)
430 if (y
- (Y_INCR
*length
) >= 5)
431 dir
= UP
, interval
= 40;
433 if (y
+ Y_INCR
*length
<= (int)Height
- 70)
434 dir
= DOWN
, interval
= 20;
436 if (x
- X_INCR
*length
>= 5 && y
- (Y_INCR
*length
) >= 5)
439 if (x
+ X_INCR
* length
<= (int)Width
- 70 &&
440 y
-Y_INCR
* length
>= 5)
443 if (x
- X_INCR
* length
>= 5 &&
444 y
+ Y_INCR
* length
<= (int)Height
- 70)
447 if (x
+ X_INCR
*length
<= (int)Width
- 70 &&
448 y
+ Y_INCR
*length
<= (int)Height
- 70)
455 timeout_id
= XtAppAddTimeOut(app
, interval
, move
, NULL
);
459 post_prompt_box(Window window
)
461 int width
= (Width
/ 3);
462 int height
= font_height(font
) * 6;
465 /* make sure the entire nose icon fits in the box */
469 if(width
< 105 + font
->max_bounds
.width
*STRING_LENGTH
)
470 width
= 105 + font
->max_bounds
.width
*STRING_LENGTH
;
471 box_x
= (Width
- width
) / 2;
472 time_x
= prompt_x
= box_x
+ 105;
474 time_y
= prompt_y
= Height
/ 2;
475 box_y
= prompt_y
- 3 * font_height(font
);
477 /* erase current guy -- text message may still exist */
478 XSetForeground(dpy
, gc
, Black
);
479 XFillRectangle(dpy
, window
, gc
, x
, y
, 64, 64);
480 talk(1); /* forcefully erase message if one is being displayed */
481 /* Clear area in middle of screen for prompt box */
482 XSetForeground(dpy
, gc
, White
);
483 XFillRectangle(dpy
, window
, gc
, box_x
, box_y
, width
, height
);
485 /* make a box that's 5 pixels thick. Then add a thin box inside it */
486 XSetForeground(dpy
, gc
, Black
);
487 XSetLineAttributes(dpy
, gc
, 5, 0, 0, 0);
488 XDrawRectangle(dpy
, window
, gc
, box_x
+5, box_y
+5, width
-10, height
-10);
489 XSetLineAttributes(dpy
, gc
, 0, 0, 0, 0);
490 XDrawRectangle(dpy
, window
, gc
, box_x
+12, box_y
+12, width
-23, height
-23);
492 XDrawString(dpy
, window
, gc
,
493 prompt_x
, prompt_y
-font_height(font
),
494 userprompt
, strlen(userprompt
));
495 XDrawString(dpy
, window
, gc
, prompt_x
, prompt_y
, PROMPT
, strlen(PROMPT
));
496 /* set background for copyplane and DrawImageString; need reverse video */
497 XSetBackground(dpy
, gc
, White
);
498 XCopyPlane(dpy
, right0
, window
, gc
, 0,0, 64,64,
499 box_x
+ 20, box_y
+ (height
- 64)/2, 1L);
500 prompt_x
+= XTextWidth(font
, PROMPT
, strlen(PROMPT
));
501 time_y
+= 2*font_height(font
);
505 RaiseWindow(Widget w
, XEvent
*ev
, String
*s
, Cardinal
*n
)
511 XRaiseWindow(dpy
, XtWindow(x
));
516 ClearWindow(Widget w
, XEvent
*_event
, String
*_s
, Cardinal
*_n
)
518 XExposeEvent
*event
= (XExposeEvent
*)_event
;
519 if (!XtIsRealized(w
))
521 XClearArea(dpy
, XtWindow(w
), event
->x
, event
->y
,
522 event
->width
, event
->height
, False
);
523 if (state
== GET_PASSWD
)
524 post_prompt_box(XtWindow(w
));
525 if (timeout_id
== 0 && event
->count
== 0) {
526 timeout_id
= XtAppAddTimeOut(app
, 1000L, move
, NULL
);
527 /* first grab the input focus */
528 XSetInputFocus(dpy
, XtWindow(w
), RevertToPointerRoot
, CurrentTime
);
529 /* now grab the pointer and keyboard and contrain to this window */
530 XGrabPointer(dpy
, XtWindow(w
), TRUE
, 0, GrabModeAsync
,
531 GrabModeAsync
, XtWindow(w
), None
, CurrentTime
);
536 countdown(XtPointer _t
, XtIntervalId
*_d
)
538 int *timeout
= (int *)_t
;
542 if (--(*timeout
) < 0) {
544 XtRemoveTimeOut(timeout_id
);
546 event
.x
= event
.y
= 0;
547 event
.width
= Width
, event
.height
= Height
;
548 ClearWindow(widget
, (XEvent
*)&event
, 0, 0);
549 timeout_id
= XtAppAddTimeOut(app
, 200L, move
, NULL
);
552 seconds
= time(0) - locked_at
;
554 snprintf(buf
, sizeof(buf
),
555 "Locked for %d:%02d:%02d ",
556 (int)seconds
/3600, (int)seconds
/60%60, (int)seconds
%60);
558 snprintf(buf
, sizeof(buf
),
559 "Locked for %2d:%02d ",
560 (int)seconds
/60, (int)seconds
%60);
562 XDrawImageString(dpy
, XtWindow(widget
), gc
,
563 time_x
, time_y
, buf
, strlen(buf
));
564 XtAppAddTimeOut(app
, 1000L, countdown
, timeout
);
570 verify_krb5(const char *password
)
575 krb5_cc_default(context
, &id
);
576 ret
= krb5_verify_user(context
,
584 krb5_afslog(context
, id
, NULL
, NULL
);
587 if (ret
!= KRB5KRB_AP_ERR_MODIFIED
)
588 krb5_warn(context
, ret
, "verify_krb5");
595 verify(char *password
)
598 * First try with root password, if allowed.
600 if ( appres
.accept_root
601 && strcmp(crypt(password
, root_cpass
), root_cpass
) == 0)
605 * Password that log out user
609 (time(0) - locked_at
) > ALLOW_LOGOUT
&&
610 strcmp(crypt(password
, appres
.logoutPasswd
), appres
.logoutPasswd
) == 0)
612 signal(SIGHUP
, SIG_IGN
);
615 /* If the X-server shut down then so will we, else
617 signal(SIGHUP
, SIG_DFL
);
621 * Try copy of users password.
623 if (strcmp(crypt(password
, user_cpass
), user_cpass
) == 0)
627 * Try to verify as user in case password change.
629 if (unix_verify_user(login
, password
) == 0)
634 * Try to verify as user with kerberos 5.
636 if(verify_krb5(password
) == 0)
645 GetPasswd(Widget w
, XEvent
*_event
, String
*_s
, Cardinal
*_n
)
647 XKeyEvent
*event
= (XKeyEvent
*)_event
;
648 static char passwd
[MAX_PASSWD_LENGTH
];
649 static unsigned int cnt
;
650 static int is_ctrl
= XNLOCK_NOCTRL
;
654 int old_state
= state
;
656 if (event
->type
== ButtonPress
) {
657 x
= event
->x
, y
= event
->y
;
660 if (state
== IS_MOVING
) {
661 /* guy is running around--change to post prompt box. */
662 XtRemoveTimeOut(timeout_id
);
664 if (appres
.ignore_passwd
|| !strlen(user_cpass
))
666 post_prompt_box(XtWindow(w
));
669 countdown((XtPointer
)&time_left
, 0);
671 if (event
->type
== KeyRelease
) {
672 keysym
= XLookupKeysym(event
, 0);
673 if (keysym
== XK_Control_L
|| keysym
== XK_Control_R
) {
674 is_ctrl
= XNLOCK_NOCTRL
;
677 if (event
->type
!= KeyPress
)
682 keysym
= XLookupKeysym(event
, 0);
683 if (keysym
== XK_Control_L
|| keysym
== XK_Control_R
) {
684 is_ctrl
= XNLOCK_CTRL
;
687 if (!XLookupString(event
, &c
, 1, &keysym
, 0))
689 if (keysym
== XK_Return
|| keysym
== XK_Linefeed
) {
691 if(old_state
== IS_MOVING
)
693 XtRemoveTimeOut(timeout_id
);
695 if(verify(passwd
) == 0)
700 XDrawImageString(dpy
, XtWindow(widget
), gc
,
701 time_x
, time_y
, FAIL_MSG
, strlen(FAIL_MSG
));
703 timeout_id
= XtAppAddTimeOut(app
, 2000L, countdown
, &time_left
);
706 if (keysym
== XK_BackSpace
|| keysym
== XK_Delete
|| keysym
== XK_Left
) {
709 } else if (keysym
== XK_u
&& is_ctrl
== XNLOCK_CTRL
) {
712 echolen
= min(cnt
, STRING_LENGTH
);
713 XDrawImageString(dpy
, XtWindow(w
), gc
,
714 prompt_x
, prompt_y
, STRING
, echolen
);
715 XDrawImageString(dpy
, XtWindow(w
), gc
,
716 prompt_x
+ XTextWidth(font
, STRING
, echolen
),
717 prompt_y
, SPACE_STRING
, STRING_LENGTH
- echolen
+ 1);
719 } else if (isprint((unsigned char)c
)) {
720 if ((cnt
+ 1) >= MAX_PASSWD_LENGTH
)
726 echolen
= min(cnt
, STRING_LENGTH
);
727 XDrawImageString(dpy
, XtWindow(w
), gc
,
728 prompt_x
, prompt_y
, STRING
, echolen
);
729 XDrawImageString(dpy
, XtWindow(w
), gc
,
730 prompt_x
+ XTextWidth(font
, STRING
, echolen
),
731 prompt_y
, SPACE_STRING
, STRING_LENGTH
- echolen
+1);
734 #include "nose.0.left"
735 #include "nose.1.left"
736 #include "nose.0.right"
737 #include "nose.1.right"
738 #include "nose.left.front"
739 #include "nose.right.front"
740 #include "nose.front"
746 static Pixmap
*images
[] = {
747 &left0
, &left1
, &right0
, &right1
,
748 &left_front
, &right_front
, &front
, &down
750 static unsigned char *bits
[] = {
751 nose_0_left_bits
, nose_1_left_bits
, nose_0_right_bits
,
752 nose_1_right_bits
, nose_left_front_bits
, nose_right_front_bits
,
753 nose_front_bits
, nose_down_bits
757 for (i
= 0; i
< XtNumber(images
); i
++)
759 XCreatePixmapFromBitmapData(dpy
, DefaultRootWindow(dpy
),
760 (char*)(bits
[i
]), 64, 64, 1, 0, 1)))
761 XtError("Can't load nose images");
765 talk(int force_erase
)
767 unsigned int width
= 0, height
, Z
, total
= 0;
768 static unsigned int X
, Y
;
770 static struct { int x
, y
, width
, height
; } s_rect
;
772 char buf
[BUFSIZ
], args
[MAXLINES
][256];
774 /* clear what we've written */
775 if (talking
|| force_erase
) {
779 XSetForeground(dpy
, gc
, Black
);
780 XDrawString(dpy
, XtWindow(widget
), gc
, X
, Y
, words
, strlen(words
));
781 } else if (talking
== 1) {
782 XSetForeground(dpy
, gc
, Black
);
783 XFillRectangle(dpy
, XtWindow(widget
), gc
, s_rect
.x
-5, s_rect
.y
-5,
784 s_rect
.width
+10, s_rect
.height
+10);
788 timeout_id
= XtAppAddTimeOut(app
, 40L,
789 (XtTimerCallbackProc
)move
,
793 XSetForeground(dpy
, gc
, White
);
796 strlcpy (buf
, words
, sizeof(buf
));
799 /* possibly avoid a lot of work here
800 * if no CR or only one, then just print the line
802 if (!(p2
= strchr(p
, '\n')) || !p2
[1]) {
807 w
= XTextWidth(font
, words
, strlen(words
));
809 Y
= y
- 5 - font_height(font
);
810 /* give us a nice 5 pixel margin */
813 else if (X
+ w
+ 15 > (int)Width
+ 5)
816 Y
= y
+ 64 + 5 + font_height(font
);
817 XDrawString(dpy
, XtWindow(widget
), gc
, X
, Y
, words
, strlen(words
));
818 timeout_id
= XtAppAddTimeOut(app
, 5000L, (XtTimerCallbackProc
)talk
,
824 /* p2 now points to the first '\n' */
825 for (height
= 0; p
[0]; height
++) {
828 if ((w
= XTextWidth(font
, p
, p2
- p
)) > width
)
830 total
+= p2
- p
; /* total chars; count to determine reading time */
831 strlcpy(args
[height
], p
, sizeof(args
[height
]));
832 if (height
== MAXLINES
- 1) {
833 puts("Message too long!");
837 if (!(p2
= strchr(p
, '\n')))
842 /* Figure out the height and width in pixels (height, width) extend
843 * the new box by 15 pixels on the sides (30 total) top and bottom.
845 s_rect
.width
= width
+ 30;
846 s_rect
.height
= height
* font_height(font
) + 30;
847 if (x
- s_rect
.width
- 10 < 5)
850 if ((s_rect
.x
= x
+32-(s_rect
.width
+15)/2)
851 + s_rect
.width
+15 > (int)Width
-5)
852 s_rect
.x
= Width
- 15 - s_rect
.width
;
853 if (y
- s_rect
.height
- 10 < 5)
854 s_rect
.y
= y
+ 64 + 5;
856 s_rect
.y
= y
- 5 - s_rect
.height
;
858 XSetForeground(dpy
, gc
, White
);
859 XFillRectangle(dpy
, XtWindow(widget
), gc
,
860 s_rect
.x
-5, s_rect
.y
-5, s_rect
.width
+10, s_rect
.height
+10);
862 /* make a box that's 5 pixels thick. Then add a thin box inside it */
863 XSetForeground(dpy
, gc
, Black
);
864 XSetLineAttributes(dpy
, gc
, 5, 0, 0, 0);
865 XDrawRectangle(dpy
, XtWindow(widget
), gc
,
866 s_rect
.x
, s_rect
.y
, s_rect
.width
-1, s_rect
.height
-1);
867 XSetLineAttributes(dpy
, gc
, 0, 0, 0, 0);
868 XDrawRectangle(dpy
, XtWindow(widget
), gc
,
869 s_rect
.x
+ 7, s_rect
.y
+ 7, s_rect
.width
- 15,
873 Y
= 15 + font_height(font
);
875 /* now print each string in reverse order (start at bottom of box) */
876 for (Z
= 0; Z
< height
; Z
++) {
877 XDrawString(dpy
, XtWindow(widget
), gc
, s_rect
.x
+X
, s_rect
.y
+Y
,
878 args
[Z
], strlen(args
[Z
]));
879 Y
+= font_height(font
);
881 timeout_id
= XtAppAddTimeOut(app
, (total
/15) * 1000,
882 (XtTimerCallbackProc
)talk
, NULL
);
888 XSetForeground(dpy
, gc
, White
);
889 XSetBackground(dpy
, gc
, Black
);
890 if (my_random() % 3) {
891 XCopyPlane(dpy
, (my_random() & 1)? down
: front
, XtWindow(widget
), gc
,
892 0, 0, 64,64, x
, y
, 1L);
895 if (!(my_random() % 5))
897 if (my_random() % 3) {
898 XCopyPlane(dpy
, (my_random() & 1)? left_front
: right_front
,
899 XtWindow(widget
), gc
, 0, 0, 64,64, x
, y
, 1L);
902 if (!(my_random() % 5))
904 XCopyPlane(dpy
, (my_random() & 1)? left0
: right0
, XtWindow(widget
), gc
,
905 0, 0, 64,64, x
, y
, 1L);
910 main (int argc
, char **argv
)
916 setprogname (argv
[0]);
919 * Must be setuid root to read /etc/shadow, copy encrypted
920 * passwords here and then switch to sane uid.
924 uid_t uid
= getuid();
925 if (!(pw
= k_getpwuid(0)))
926 errx (1, "can't get root's passwd!");
927 strlcpy(root_cpass
, pw
->pw_passwd
, sizeof(root_cpass
));
929 if (!(pw
= k_getpwuid(uid
)))
930 errx (1, "Can't get your password entry!");
931 strlcpy(user_cpass
, pw
->pw_passwd
, sizeof(user_cpass
));
933 if (uid
!= 0 && setuid(0) != -1) {
934 fprintf(stderr
, "Failed to drop privileges!\n");
937 /* Now we're no longer running setuid root. */
938 strlcpy(login
, pw
->pw_name
, sizeof(login
));
941 #if defined(HAVE_SRANDOMDEV)
943 #elif defined(HAVE_RANDOM)
948 for (i
= 0; i
< STRING_LENGTH
; i
++)
949 STRING
[i
] = ((unsigned long)my_random() % ('~' - ' ')) + ' ';
953 snprintf(userprompt
, sizeof(userprompt
), "User: %s", login
);
959 ret
= krb5_init_context(&context
);
961 errx (1, "krb5_init_context failed: %d", ret
);
962 krb5_get_default_principal(context
, &client
);
963 krb5_unparse_name(context
, client
, &str
);
964 snprintf(userprompt
, sizeof(userprompt
), "User: %s", str
);
969 override
= XtVaAppInitialize(&app
, "XNlock", options
, XtNumber(options
),
971 XtNoverrideRedirect
, True
,
974 XtVaGetApplicationResources(override
,(XtPointer
)&appres
,
975 resources
,XtNumber(resources
),
977 /* the background is black and the little guy is white */
981 if (appres
.destroytickets
) {
983 /*XXX add krb4 code here */
987 dpy
= XtDisplay(override
);
990 errx (1, "Error: Can't open display");
992 Width
= DisplayWidth(dpy
, DefaultScreen(dpy
)) + 2;
993 Height
= DisplayHeight(dpy
, DefaultScreen(dpy
)) + 2;
995 for(i
= 0; i
< ScreenCount(dpy
); i
++){
1002 XtResource Res
[] = {
1003 { XtNbackground
, XtCBackground
, XtRPixel
, sizeof(Pixel
),
1004 XtOffsetOf(struct xxx
, bg
), XtRString
, "black" }
1007 if(i
== DefaultScreen(dpy
))
1010 shell
= XtVaAppCreateShell(NULL
,NULL
, applicationShellWidgetClass
, dpy
,
1011 XtNscreen
, ScreenOfDisplay(dpy
, i
),
1012 XtNoverrideRedirect
, True
,
1017 XtVaGetApplicationResources(shell
, (XtPointer
)&res
,
1021 core
= XtVaCreateManagedWidget("_foo", widgetClass
, shell
,
1022 XtNwidth
, DisplayWidth(dpy
, i
),
1023 XtNheight
, DisplayHeight(dpy
, i
),
1024 XtNbackground
, res
.bg
,
1026 XtRealizeWidget(shell
);
1029 widget
= XtVaCreateManagedWidget("_foo", widgetClass
, override
,
1032 XtNbackground
, Black
,
1035 init_words(--argc
, ++argv
);
1038 gcvalues
.foreground
= Black
;
1039 gcvalues
.background
= White
;
1043 gcvalues
.font
= font
->fid
;
1044 gcvalues
.graphics_exposures
= False
;
1045 gc
= XCreateGC(dpy
, DefaultRootWindow(dpy
),
1046 GCForeground
| GCBackground
| GCGraphicsExposures
| GCFont
,
1055 static XtActionsRec actions
[] = {
1056 { "ClearWindow", ClearWindow
},
1057 { "GetPasswd", GetPasswd
},
1058 { "RaiseWindow", RaiseWindow
},
1060 XtAppAddActions(app
, actions
, XtNumber(actions
));
1061 XtOverrideTranslations(widget
,
1062 XtParseTranslationTable(
1063 "<Expose>: ClearWindow() \n"
1064 "<BtnDown>: GetPasswd() \n"
1065 "<Visible>: RaiseWindow() \n"
1066 "<KeyRelease>: GetPasswd() \n"
1067 "<KeyPress>: GetPasswd()"));
1070 XtRealizeWidget(override
);
1071 if((i
= XGrabPointer(dpy
, XtWindow(widget
), True
, 0, GrabModeAsync
,
1072 GrabModeAsync
, XtWindow(widget
),
1073 None
, CurrentTime
)) != 0)
1074 errx(1, "Failed to grab pointer (%d)", i
);
1076 if((i
= XGrabKeyboard(dpy
, XtWindow(widget
), True
, GrabModeAsync
,
1077 GrabModeAsync
, CurrentTime
)) != 0)
1078 errx(1, "Failed to grab keyboard (%d)", i
);