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>
27 #ifdef HAVE_SYS_TYPES_H
28 #include <sys/types.h>
35 #define des_encrypt wingless_pigs_mostly_fail_to_fly
46 #if defined(KRB4) || defined(KRB5)
53 static char login
[16];
54 static char userprompt
[128];
56 static char name
[ANAME_SZ
];
57 static char inst
[INST_SZ
];
58 static char realm
[REALM_SZ
];
61 static krb5_context context
;
62 static krb5_principal client
;
65 #define font_height(font) (font->ascent + font->descent)
67 static char *SPACE_STRING
= " ";
68 static char STRING
[] = "****************";
70 #define STRING_LENGTH (sizeof(STRING))
71 #define MAX_PASSWD_LENGTH 256
72 /* (sizeof(STRING)) */
74 #define PROMPT "Password: "
75 #define FAIL_MSG "Sorry, try again"
84 #define XNLOCK_NOCTRL 0
86 static XtAppContext app
;
88 static unsigned short Width
, Height
;
91 static XtIntervalId timeout_id
;
94 static Pixel Black
, White
;
95 static XFontStruct
*font
;
96 static char root_cpass
[128];
97 static char user_cpass
[128];
98 static int time_left
, prompt_x
, prompt_y
, time_x
, time_y
;
99 static unsigned long interval
;
100 static Pixmap left0
, left1
, right0
, right1
, left_front
,
101 right_front
, front
, down
;
107 static int state
; /* indicates states: walking or getting passwd */
109 static int ALLOW_LOGOUT
= (60*10); /* Allow logout after nn seconds */
110 #define LOGOUT_PASSWD "enuHDmTo5Lq4g" /* when given password "LOGOUT" */
111 static time_t locked_at
;
117 Boolean ignore_passwd
;
120 char *text
, *text_prog
, *file
, *logoutPasswd
;
121 Boolean no_screensaver
;
122 Boolean destroytickets
;
125 static XtResource resources
[] = {
126 { XtNbackground
, XtCBackground
, XtRPixel
, sizeof(Pixel
),
127 XtOffsetOf(struct appres_t
, bg
), XtRString
, "black" },
129 { XtNforeground
, XtCForeground
, XtRPixel
, sizeof(Pixel
),
130 XtOffsetOf(struct appres_t
, fg
), XtRString
, "white" },
132 { XtNfont
, XtCFont
, XtRFontStruct
, sizeof (XFontStruct
*),
133 XtOffsetOf(struct appres_t
, font
),
134 XtRString
, "-*-new century schoolbook-*-*-*-18-*" },
136 { "ignorePasswd", "IgnorePasswd", XtRBoolean
, sizeof(Boolean
),
137 XtOffsetOf(struct appres_t
,ignore_passwd
),XtRImmediate
,(XtPointer
)False
},
139 { "acceptRootPasswd", "AcceptRootPasswd", XtRBoolean
, sizeof(Boolean
),
140 XtOffsetOf(struct appres_t
, accept_root
), XtRImmediate
, (XtPointer
)True
},
142 { "text", "Text", XtRString
, sizeof(String
),
143 XtOffsetOf(struct appres_t
, text
), XtRString
, "I'm out running around." },
145 { "program", "Program", XtRString
, sizeof(String
),
146 XtOffsetOf(struct appres_t
, text_prog
), XtRImmediate
, NULL
},
148 { "file", "File", XtRString
, sizeof(String
),
149 XtOffsetOf(struct appres_t
,file
), XtRImmediate
, NULL
},
151 { "logoutPasswd", "logoutPasswd", XtRString
, sizeof(String
),
152 XtOffsetOf(struct appres_t
, logoutPasswd
), XtRString
, LOGOUT_PASSWD
},
154 { "noScreenSaver", "NoScreenSaver", XtRBoolean
, sizeof(Boolean
),
155 XtOffsetOf(struct appres_t
,no_screensaver
), XtRImmediate
, (XtPointer
)True
},
157 { "destroyTickets", "DestroyTickets", XtRBoolean
, sizeof(Boolean
),
158 XtOffsetOf(struct appres_t
,destroytickets
), XtRImmediate
, (XtPointer
)True
},
161 static XrmOptionDescRec options
[] = {
162 { "-fg", ".foreground", XrmoptionSepArg
, NULL
},
163 { "-foreground", ".foreground", XrmoptionSepArg
, NULL
},
164 { "-fn", ".font", XrmoptionSepArg
, NULL
},
165 { "-font", ".font", XrmoptionSepArg
, NULL
},
166 { "-ip", ".ignorePasswd", XrmoptionNoArg
, "True" },
167 { "-noip", ".ignorePasswd", XrmoptionNoArg
, "False" },
168 { "-ar", ".acceptRootPasswd", XrmoptionNoArg
, "True" },
169 { "-noar", ".acceptRootPasswd", XrmoptionNoArg
, "False" },
170 { "-nonoscreensaver", ".noScreenSaver", XrmoptionNoArg
, "False" },
171 { "-nodestroytickets", ".destroyTickets", XrmoptionNoArg
, "False" },
178 static char buf
[512];
181 if (appres
.text_prog
) {
182 pp
= popen(appres
.text_prog
, "r");
184 warn("popen %s", appres
.text_prog
);
187 n
= fread(buf
, 1, sizeof(buf
) - 1, pp
);
193 pp
= fopen(appres
.file
, "r");
195 warn("fopen %s", appres
.file
);
198 n
= fread(buf
, 1, sizeof(buf
) - 1, pp
);
210 fprintf(stderr
, "usage: %s [options] [message]\n", getprogname());
211 fprintf(stderr
, "-fg color foreground color\n");
212 fprintf(stderr
, "-bg color background color\n");
213 fprintf(stderr
, "-rv reverse foreground/background colors\n");
214 fprintf(stderr
, "-nrv no reverse video\n");
215 fprintf(stderr
, "-ip ignore passwd\n");
216 fprintf(stderr
, "-nip don't ignore passwd\n");
217 fprintf(stderr
, "-ar accept root's passwd to unlock\n");
218 fprintf(stderr
, "-nar don't accept root's passwd\n");
219 fprintf(stderr
, "-f [file] message is read from file or ~/.msgfile\n");
220 fprintf(stderr
, "-prog program text is gotten from executing `program'\n");
221 fprintf(stderr
, "-nodestroytickets keep kerberos tickets\n");
226 init_words (int argc
, char **argv
)
231 if(strcmp(argv
[i
], "-p") == 0
232 || strcmp(argv
[i
], "-prog") == 0) {
235 appres
.text_prog
= argv
[i
];
238 warnx ("-p requires an argument");
241 } else if(strcmp(argv
[i
], "-f") == 0) {
244 appres
.file
= argv
[i
];
247 asprintf (&appres
.file
,
248 "%s/.msgfile", getenv("HOME"));
249 if (appres
.file
== NULL
)
250 errx (1, "cannot allocate memory for message");
252 } else if(strcmp(argv
[i
], "--version") == 0) {
258 for(j
= i
; argv
[j
]; j
++)
259 len
+= strlen(argv
[j
]) + 1;
260 appres
.text
= malloc(len
);
261 if (appres
.text
== NULL
)
262 errx (1, "cannot allocate memory for message");
265 strlcat(appres
.text
, argv
[i
], len
);
266 strlcat(appres
.text
, " ", len
);
273 ScreenSaver(int save
)
275 static int timeout
, interval
, prefer_blank
, allow_exp
;
276 if(!appres
.no_screensaver
){
278 XGetScreenSaver(dpy
, &timeout
, &interval
,
279 &prefer_blank
, &allow_exp
);
280 XSetScreenSaver(dpy
, 0, interval
, prefer_blank
, allow_exp
);
283 XSetScreenSaver(dpy
, timeout
, interval
, prefer_blank
, allow_exp
);
287 /* Forward decls necessary */
288 static void talk(int force_erase
);
289 static unsigned long look(void);
296 warn ("zrefresh: fork");
300 execlp("zrefresh", "zrefresh", 0);
301 execl(BINDIR
"/zrefresh", "zrefresh", 0);
313 XUngrabPointer(dpy
, CurrentTime
);
314 XUngrabKeyboard(dpy
, CurrentTime
);
329 XSetForeground(dpy
, gc
, White
);
330 XSetBackground(dpy
, gc
, Black
);
331 if (dir
& (LEFT
|RIGHT
)) { /* left/right movement (mabye up/down too) */
332 up
= -up
; /* bouncing effect (even if hit a wall) */
335 frame
= (up
< 0) ? left0
: left1
;
338 frame
= (up
< 0) ? right0
: right1
;
340 if ((lastdir
== FRONT
|| lastdir
== DOWN
) && dir
& UP
) {
341 /* workaround silly bug that leaves screen dust when
342 * guy is facing forward or down and moves up-left/right.
344 XCopyPlane(dpy
, frame
, XtWindow(widget
), gc
, 0, 0, 64,64, x
, y
, 1L);
347 /* note that maybe neither UP nor DOWN is set! */
348 if (dir
& UP
&& y
> Y_INCR
)
350 else if (dir
& DOWN
&& y
< (int)Height
- 64)
353 /* Explicit up/down movement only (no left/right) */
355 XCopyPlane(dpy
, front
, XtWindow(widget
), gc
,
356 0,0, 64,64, x
, y
-= Y_INCR
, 1L);
357 else if (dir
== DOWN
)
358 XCopyPlane(dpy
, down
, XtWindow(widget
), gc
,
359 0,0, 64,64, x
, y
+= Y_INCR
, 1L);
360 else if (dir
== FRONT
&& frame
!= front
) {
365 else if (lastdir
& RIGHT
)
369 XCopyPlane(dpy
, frame
, XtWindow(widget
), gc
, 0, 0, 64,64, x
, y
, 1L);
373 XCopyPlane(dpy
, frame
, XtWindow(widget
), gc
,
374 0,0, 64,64, --x
, y
+up
, 1L);
377 else if (dir
& RIGHT
)
379 XCopyPlane(dpy
, frame
, XtWindow(widget
), gc
,
380 0,0, 64,64, ++x
, y
+up
, 1L);
401 if (my_random() & 1) {
409 move(XtPointer _p
, XtIntervalId
*_id
)
411 static int length
, dir
;
416 if ((my_random() & 1) && think()) {
417 talk(0); /* sets timeout to itself */
420 if (!(my_random() % 3) && (interval
= look())) {
421 timeout_id
= XtAppAddTimeOut(app
, interval
, move
, NULL
);
424 interval
= 20 + my_random() % 100;
427 length
= Width
/100 + my_random() % 90, tries
= 8;
430 switch (my_random() % 8) {
432 if (x
- X_INCR
*length
>= 5)
435 if (x
+ X_INCR
*length
<= (int)Width
- 70)
438 if (y
- (Y_INCR
*length
) >= 5)
439 dir
= UP
, interval
= 40;
441 if (y
+ Y_INCR
*length
<= (int)Height
- 70)
442 dir
= DOWN
, interval
= 20;
444 if (x
- X_INCR
*length
>= 5 && y
- (Y_INCR
*length
) >= 5)
447 if (x
+ X_INCR
* length
<= (int)Width
- 70 &&
448 y
-Y_INCR
* length
>= 5)
451 if (x
- X_INCR
* length
>= 5 &&
452 y
+ Y_INCR
* length
<= (int)Height
- 70)
455 if (x
+ X_INCR
*length
<= (int)Width
- 70 &&
456 y
+ Y_INCR
*length
<= (int)Height
- 70)
463 timeout_id
= XtAppAddTimeOut(app
, interval
, move
, NULL
);
467 post_prompt_box(Window window
)
469 int width
= (Width
/ 3);
470 int height
= font_height(font
) * 6;
473 /* make sure the entire nose icon fits in the box */
477 if(width
< 105 + font
->max_bounds
.width
*STRING_LENGTH
)
478 width
= 105 + font
->max_bounds
.width
*STRING_LENGTH
;
479 box_x
= (Width
- width
) / 2;
480 time_x
= prompt_x
= box_x
+ 105;
482 time_y
= prompt_y
= Height
/ 2;
483 box_y
= prompt_y
- 3 * font_height(font
);
485 /* erase current guy -- text message may still exist */
486 XSetForeground(dpy
, gc
, Black
);
487 XFillRectangle(dpy
, window
, gc
, x
, y
, 64, 64);
488 talk(1); /* forcefully erase message if one is being displayed */
489 /* Clear area in middle of screen for prompt box */
490 XSetForeground(dpy
, gc
, White
);
491 XFillRectangle(dpy
, window
, gc
, box_x
, box_y
, width
, height
);
493 /* make a box that's 5 pixels thick. Then add a thin box inside it */
494 XSetForeground(dpy
, gc
, Black
);
495 XSetLineAttributes(dpy
, gc
, 5, 0, 0, 0);
496 XDrawRectangle(dpy
, window
, gc
, box_x
+5, box_y
+5, width
-10, height
-10);
497 XSetLineAttributes(dpy
, gc
, 0, 0, 0, 0);
498 XDrawRectangle(dpy
, window
, gc
, box_x
+12, box_y
+12, width
-23, height
-23);
500 XDrawString(dpy
, window
, gc
,
501 prompt_x
, prompt_y
-font_height(font
),
502 userprompt
, strlen(userprompt
));
503 XDrawString(dpy
, window
, gc
, prompt_x
, prompt_y
, PROMPT
, strlen(PROMPT
));
504 /* set background for copyplane and DrawImageString; need reverse video */
505 XSetBackground(dpy
, gc
, White
);
506 XCopyPlane(dpy
, right0
, window
, gc
, 0,0, 64,64,
507 box_x
+ 20, box_y
+ (height
- 64)/2, 1L);
508 prompt_x
+= XTextWidth(font
, PROMPT
, strlen(PROMPT
));
509 time_y
+= 2*font_height(font
);
513 RaiseWindow(Widget w
, XEvent
*ev
, String
*s
, Cardinal
*n
)
519 XRaiseWindow(dpy
, XtWindow(x
));
524 ClearWindow(Widget w
, XEvent
*_event
, String
*_s
, Cardinal
*_n
)
526 XExposeEvent
*event
= (XExposeEvent
*)_event
;
527 if (!XtIsRealized(w
))
529 XClearArea(dpy
, XtWindow(w
), event
->x
, event
->y
,
530 event
->width
, event
->height
, False
);
531 if (state
== GET_PASSWD
)
532 post_prompt_box(XtWindow(w
));
533 if (timeout_id
== 0 && event
->count
== 0) {
534 timeout_id
= XtAppAddTimeOut(app
, 1000L, move
, NULL
);
535 /* first grab the input focus */
536 XSetInputFocus(dpy
, XtWindow(w
), RevertToPointerRoot
, CurrentTime
);
537 /* now grab the pointer and keyboard and contrain to this window */
538 XGrabPointer(dpy
, XtWindow(w
), TRUE
, 0, GrabModeAsync
,
539 GrabModeAsync
, XtWindow(w
), None
, CurrentTime
);
544 countdown(XtPointer _t
, XtIntervalId
*_d
)
546 int *timeout
= (int *)_t
;
550 if (--(*timeout
) < 0) {
552 XtRemoveTimeOut(timeout_id
);
554 event
.x
= event
.y
= 0;
555 event
.width
= Width
, event
.height
= Height
;
556 ClearWindow(widget
, (XEvent
*)&event
, 0, 0);
557 timeout_id
= XtAppAddTimeOut(app
, 200L, move
, NULL
);
560 seconds
= time(0) - locked_at
;
562 snprintf(buf
, sizeof(buf
),
563 "Locked for %d:%02d:%02d ",
564 (int)seconds
/3600, (int)seconds
/60%60, (int)seconds
%60);
566 snprintf(buf
, sizeof(buf
),
567 "Locked for %2d:%02d ",
568 (int)seconds
/60, (int)seconds
%60);
570 XDrawImageString(dpy
, XtWindow(widget
), gc
,
571 time_x
, time_y
, buf
, strlen(buf
));
572 XtAppAddTimeOut(app
, 1000L, countdown
, timeout
);
578 verify_krb5(const char *password
)
582 krb5_boolean get_v4_tgt
;
584 krb5_cc_default(context
, &id
);
585 ret
= krb5_verify_user(context
,
593 krb5_appdefault_boolean(context
, "xnlock",
594 krb5_principal_get_realm(context
, client
),
595 "krb4_get_tickets", FALSE
, &get_v4_tgt
);
598 krb5_creds mcred
, cred
;
600 krb5_make_principal(context
, &mcred
.server
,
605 ret
= krb5_cc_retrieve_cred(context
, id
, 0, &mcred
, &cred
);
607 ret
= krb524_convert_creds_kdc_ccache(context
, id
, &cred
, &c
);
609 tf_setup(&c
, c
.pname
, c
.pinst
);
610 memset(&c
, 0, sizeof(c
));
611 krb5_free_creds_contents(context
, &cred
);
613 krb5_free_principal(context
, mcred
.server
);
617 krb5_afslog(context
, id
, NULL
, NULL
);
620 if (ret
!= KRB5KRB_AP_ERR_MODIFIED
)
621 krb5_warn(context
, ret
, "verify_krb5");
628 verify(char *password
)
631 * First try with root password, if allowed.
633 if ( appres
.accept_root
634 && strcmp(crypt(password
, root_cpass
), root_cpass
) == 0)
638 * Password that log out user
642 (time(0) - locked_at
) > ALLOW_LOGOUT
&&
643 strcmp(crypt(password
, appres
.logoutPasswd
), appres
.logoutPasswd
) == 0)
645 signal(SIGHUP
, SIG_IGN
);
648 /* If the X-server shut down then so will we, else
650 signal(SIGHUP
, SIG_DFL
);
654 * Try copy of users password.
656 if (strcmp(crypt(password
, user_cpass
), user_cpass
) == 0)
660 * Try to verify as user in case password change.
662 if (unix_verify_user(login
, password
) == 0)
667 * Try to verify as user with kerberos 5.
669 if(verify_krb5(password
) == 0)
677 * Try to verify as user with kerberos 4.
679 ret
= krb_verify_user(name
, inst
, realm
, password
,
680 KRB_VERIFY_NOT_SECURE
, NULL
);
681 if (ret
== KSUCCESS
){
683 krb_afslog(NULL
, NULL
);
686 if (ret
!= INTK_BADPW
)
687 warnx ("warning: %s",
688 (ret
< 0) ? strerror(ret
) : krb_get_err_text(ret
));
697 GetPasswd(Widget w
, XEvent
*_event
, String
*_s
, Cardinal
*_n
)
699 XKeyEvent
*event
= (XKeyEvent
*)_event
;
700 static char passwd
[MAX_PASSWD_LENGTH
];
702 static int is_ctrl
= XNLOCK_NOCTRL
;
706 int old_state
= state
;
708 if (event
->type
== ButtonPress
) {
709 x
= event
->x
, y
= event
->y
;
712 if (state
== IS_MOVING
) {
713 /* guy is running around--change to post prompt box. */
714 XtRemoveTimeOut(timeout_id
);
716 if (appres
.ignore_passwd
|| !strlen(user_cpass
))
718 post_prompt_box(XtWindow(w
));
721 countdown((XtPointer
)&time_left
, 0);
723 if (event
->type
== KeyRelease
) {
724 keysym
= XLookupKeysym(event
, 0);
725 if (keysym
== XK_Control_L
|| keysym
== XK_Control_R
) {
726 is_ctrl
= XNLOCK_NOCTRL
;
729 if (event
->type
!= KeyPress
)
734 keysym
= XLookupKeysym(event
, 0);
735 if (keysym
== XK_Control_L
|| keysym
== XK_Control_R
) {
736 is_ctrl
= XNLOCK_CTRL
;
739 if (!XLookupString(event
, &c
, 1, &keysym
, 0))
741 if (keysym
== XK_Return
|| keysym
== XK_Linefeed
) {
743 if(old_state
== IS_MOVING
)
745 XtRemoveTimeOut(timeout_id
);
747 if(verify(passwd
) == 0)
752 XDrawImageString(dpy
, XtWindow(widget
), gc
,
753 time_x
, time_y
, FAIL_MSG
, strlen(FAIL_MSG
));
755 timeout_id
= XtAppAddTimeOut(app
, 2000L, countdown
, &time_left
);
758 if (keysym
== XK_BackSpace
|| keysym
== XK_Delete
|| keysym
== XK_Left
) {
761 } else if (keysym
== XK_u
&& is_ctrl
== XNLOCK_CTRL
) {
764 echolen
= min(cnt
, STRING_LENGTH
);
765 XDrawImageString(dpy
, XtWindow(w
), gc
,
766 prompt_x
, prompt_y
, STRING
, echolen
);
767 XDrawImageString(dpy
, XtWindow(w
), gc
,
768 prompt_x
+ XTextWidth(font
, STRING
, echolen
),
769 prompt_y
, SPACE_STRING
, STRING_LENGTH
- echolen
+ 1);
771 } else if (isprint((unsigned char)c
)) {
772 if ((cnt
+ 1) >= MAX_PASSWD_LENGTH
)
778 echolen
= min(cnt
, STRING_LENGTH
);
779 XDrawImageString(dpy
, XtWindow(w
), gc
,
780 prompt_x
, prompt_y
, STRING
, echolen
);
781 XDrawImageString(dpy
, XtWindow(w
), gc
,
782 prompt_x
+ XTextWidth(font
, STRING
, echolen
),
783 prompt_y
, SPACE_STRING
, STRING_LENGTH
- echolen
+1);
786 #include "nose.0.left"
787 #include "nose.1.left"
788 #include "nose.0.right"
789 #include "nose.1.right"
790 #include "nose.left.front"
791 #include "nose.right.front"
792 #include "nose.front"
798 static Pixmap
*images
[] = {
799 &left0
, &left1
, &right0
, &right1
,
800 &left_front
, &right_front
, &front
, &down
802 static unsigned char *bits
[] = {
803 nose_0_left_bits
, nose_1_left_bits
, nose_0_right_bits
,
804 nose_1_right_bits
, nose_left_front_bits
, nose_right_front_bits
,
805 nose_front_bits
, nose_down_bits
809 for (i
= 0; i
< XtNumber(images
); i
++)
811 XCreatePixmapFromBitmapData(dpy
, DefaultRootWindow(dpy
),
812 (char*)(bits
[i
]), 64, 64, 1, 0, 1)))
813 XtError("Can't load nose images");
817 talk(int force_erase
)
819 int width
= 0, height
, Z
, total
= 0;
820 static int X
, Y
, talking
;
821 static struct { int x
, y
, width
, height
; } s_rect
;
823 char buf
[BUFSIZ
], args
[MAXLINES
][256];
825 /* clear what we've written */
826 if (talking
|| force_erase
) {
830 XSetForeground(dpy
, gc
, Black
);
831 XDrawString(dpy
, XtWindow(widget
), gc
, X
, Y
, words
, strlen(words
));
832 } else if (talking
== 1) {
833 XSetForeground(dpy
, gc
, Black
);
834 XFillRectangle(dpy
, XtWindow(widget
), gc
, s_rect
.x
-5, s_rect
.y
-5,
835 s_rect
.width
+10, s_rect
.height
+10);
839 timeout_id
= XtAppAddTimeOut(app
, 40L,
840 (XtTimerCallbackProc
)move
,
844 XSetForeground(dpy
, gc
, White
);
847 strlcpy (buf
, words
, sizeof(buf
));
850 /* possibly avoid a lot of work here
851 * if no CR or only one, then just print the line
853 if (!(p2
= strchr(p
, '\n')) || !p2
[1]) {
858 w
= XTextWidth(font
, words
, strlen(words
));
860 Y
= y
- 5 - font_height(font
);
861 /* give us a nice 5 pixel margin */
864 else if (X
+ w
+ 15 > (int)Width
+ 5)
867 Y
= y
+ 64 + 5 + font_height(font
);
868 XDrawString(dpy
, XtWindow(widget
), gc
, X
, Y
, words
, strlen(words
));
869 timeout_id
= XtAppAddTimeOut(app
, 5000L, (XtTimerCallbackProc
)talk
,
875 /* p2 now points to the first '\n' */
876 for (height
= 0; p
; height
++) {
879 if ((w
= XTextWidth(font
, p
, p2
- p
)) > width
)
881 total
+= p2
- p
; /* total chars; count to determine reading time */
882 strlcpy(args
[height
], p
, sizeof(args
[height
]));
883 if (height
== MAXLINES
- 1) {
884 puts("Message too long!");
888 if (!(p2
= strchr(p
, '\n')))
893 /* Figure out the height and width in pixels (height, width) extend
894 * the new box by 15 pixels on the sides (30 total) top and bottom.
896 s_rect
.width
= width
+ 30;
897 s_rect
.height
= height
* font_height(font
) + 30;
898 if (x
- s_rect
.width
- 10 < 5)
901 if ((s_rect
.x
= x
+32-(s_rect
.width
+15)/2)
902 + s_rect
.width
+15 > (int)Width
-5)
903 s_rect
.x
= Width
- 15 - s_rect
.width
;
904 if (y
- s_rect
.height
- 10 < 5)
905 s_rect
.y
= y
+ 64 + 5;
907 s_rect
.y
= y
- 5 - s_rect
.height
;
909 XSetForeground(dpy
, gc
, White
);
910 XFillRectangle(dpy
, XtWindow(widget
), gc
,
911 s_rect
.x
-5, s_rect
.y
-5, s_rect
.width
+10, s_rect
.height
+10);
913 /* make a box that's 5 pixels thick. Then add a thin box inside it */
914 XSetForeground(dpy
, gc
, Black
);
915 XSetLineAttributes(dpy
, gc
, 5, 0, 0, 0);
916 XDrawRectangle(dpy
, XtWindow(widget
), gc
,
917 s_rect
.x
, s_rect
.y
, s_rect
.width
-1, s_rect
.height
-1);
918 XSetLineAttributes(dpy
, gc
, 0, 0, 0, 0);
919 XDrawRectangle(dpy
, XtWindow(widget
), gc
,
920 s_rect
.x
+ 7, s_rect
.y
+ 7, s_rect
.width
- 15,
924 Y
= 15 + font_height(font
);
926 /* now print each string in reverse order (start at bottom of box) */
927 for (Z
= 0; Z
< height
; Z
++) {
928 XDrawString(dpy
, XtWindow(widget
), gc
, s_rect
.x
+X
, s_rect
.y
+Y
,
929 args
[Z
], strlen(args
[Z
]));
930 Y
+= font_height(font
);
932 timeout_id
= XtAppAddTimeOut(app
, (total
/15) * 1000,
933 (XtTimerCallbackProc
)talk
, NULL
);
939 XSetForeground(dpy
, gc
, White
);
940 XSetBackground(dpy
, gc
, Black
);
941 if (my_random() % 3) {
942 XCopyPlane(dpy
, (my_random() & 1)? down
: front
, XtWindow(widget
), gc
,
943 0, 0, 64,64, x
, y
, 1L);
946 if (!(my_random() % 5))
948 if (my_random() % 3) {
949 XCopyPlane(dpy
, (my_random() & 1)? left_front
: right_front
,
950 XtWindow(widget
), gc
, 0, 0, 64,64, x
, y
, 1L);
953 if (!(my_random() % 5))
955 XCopyPlane(dpy
, (my_random() & 1)? left0
: right0
, XtWindow(widget
), gc
,
956 0, 0, 64,64, x
, y
, 1L);
961 main (int argc
, char **argv
)
967 setprogname (argv
[0]);
970 * Must be setuid root to read /etc/shadow, copy encrypted
971 * passwords here and then switch to sane uid.
975 uid_t uid
= getuid();
976 if (!(pw
= k_getpwuid(0)))
977 errx (1, "can't get root's passwd!");
978 strlcpy(root_cpass
, pw
->pw_passwd
, sizeof(root_cpass
));
980 if (!(pw
= k_getpwuid(uid
)))
981 errx (1, "Can't get your password entry!");
982 strlcpy(user_cpass
, pw
->pw_passwd
, sizeof(user_cpass
));
984 if (uid
!= 0 && setuid(0) != -1) {
985 fprintf(stderr
, "Failed to drop privileges!\n");
988 /* Now we're no longer running setuid root. */
989 strlcpy(login
, pw
->pw_name
, sizeof(login
));
992 #if defined(HAVE_SRANDOMDEV)
994 #elif defined(HAVE_RANDOM)
999 for (i
= 0; i
< STRING_LENGTH
; i
++)
1000 STRING
[i
] = ((unsigned long)my_random() % ('~' - ' ')) + ' ';
1002 locked_at
= time(0);
1004 snprintf(userprompt
, sizeof(userprompt
), "User: %s", login
);
1006 krb_get_default_principal(name
, inst
, realm
);
1007 snprintf(userprompt
, sizeof(userprompt
), "User: %s",
1008 krb_unparse_name_long(name
, inst
, realm
));
1012 krb5_error_code ret
;
1015 ret
= krb5_init_context(&context
);
1017 errx (1, "krb5_init_context failed: %d", ret
);
1018 krb5_get_default_principal(context
, &client
);
1019 krb5_unparse_name(context
, client
, &str
);
1020 snprintf(userprompt
, sizeof(userprompt
), "User: %s", str
);
1025 override
= XtVaAppInitialize(&app
, "XNlock", options
, XtNumber(options
),
1026 (Cardinal
*)&argc
, argv
, NULL
,
1027 XtNoverrideRedirect
, True
,
1030 XtVaGetApplicationResources(override
,(XtPointer
)&appres
,
1031 resources
,XtNumber(resources
),
1033 /* the background is black and the little guy is white */
1037 if (appres
.destroytickets
) {
1041 dest_tkt(); /* Nuke old ticket file */
1042 /* but keep a place holder */
1043 fd
= open (TKT_FILE
, O_WRONLY
| O_CREAT
| O_EXCL
, 0600);
1049 dpy
= XtDisplay(override
);
1052 errx (1, "Error: Can't open display");
1054 Width
= DisplayWidth(dpy
, DefaultScreen(dpy
)) + 2;
1055 Height
= DisplayHeight(dpy
, DefaultScreen(dpy
)) + 2;
1057 for(i
= 0; i
< ScreenCount(dpy
); i
++){
1064 XtResource Res
[] = {
1065 { XtNbackground
, XtCBackground
, XtRPixel
, sizeof(Pixel
),
1066 XtOffsetOf(struct xxx
, bg
), XtRString
, "black" }
1069 if(i
== DefaultScreen(dpy
))
1072 shell
= XtVaAppCreateShell(NULL
,NULL
, applicationShellWidgetClass
, dpy
,
1073 XtNscreen
, ScreenOfDisplay(dpy
, i
),
1074 XtNoverrideRedirect
, True
,
1079 XtVaGetApplicationResources(shell
, (XtPointer
)&res
,
1083 core
= XtVaCreateManagedWidget("_foo", widgetClass
, shell
,
1084 XtNwidth
, DisplayWidth(dpy
, i
),
1085 XtNheight
, DisplayHeight(dpy
, i
),
1086 XtNbackground
, res
.bg
,
1088 XtRealizeWidget(shell
);
1091 widget
= XtVaCreateManagedWidget("_foo", widgetClass
, override
,
1094 XtNbackground
, Black
,
1097 init_words(--argc
, ++argv
);
1100 gcvalues
.foreground
= Black
;
1101 gcvalues
.background
= White
;
1105 gcvalues
.font
= font
->fid
;
1106 gcvalues
.graphics_exposures
= False
;
1107 gc
= XCreateGC(dpy
, DefaultRootWindow(dpy
),
1108 GCForeground
| GCBackground
| GCGraphicsExposures
| GCFont
,
1117 static XtActionsRec actions
[] = {
1118 { "ClearWindow", ClearWindow
},
1119 { "GetPasswd", GetPasswd
},
1120 { "RaiseWindow", RaiseWindow
},
1122 XtAppAddActions(app
, actions
, XtNumber(actions
));
1123 XtOverrideTranslations(widget
,
1124 XtParseTranslationTable(
1125 "<Expose>: ClearWindow() \n"
1126 "<BtnDown>: GetPasswd() \n"
1127 "<Visible>: RaiseWindow() \n"
1128 "<KeyRelease>: GetPasswd() \n"
1129 "<KeyPress>: GetPasswd()"));
1132 XtRealizeWidget(override
);
1133 if((i
= XGrabPointer(dpy
, XtWindow(widget
), True
, 0, GrabModeAsync
,
1134 GrabModeAsync
, XtWindow(widget
),
1135 None
, CurrentTime
)) != 0)
1136 errx(1, "Failed to grab pointer (%d)", i
);
1138 if((i
= XGrabKeyboard(dpy
, XtWindow(widget
), True
, GrabModeAsync
,
1139 GrabModeAsync
, CurrentTime
)) != 0)
1140 errx(1, "Failed to grab keyboard (%d)", i
);