Package: xtrlock
Version: 2.7-1
Severity: wishlist
Tags: patch
The attached patch adds an extra command-line option to xtrlock:
-p : prompt user for a custom passphrase (no echo)
This options overrides using the users' password/shadow to unlock the
screen and uses a custom passphrase instead.
Option works with the -b (blank) flag just fine.
Cheers,
-- tetris11
Kernel: 4.2.5-1
Arch: x86_64
/*
* xtrlock.c
*
* X Transparent Lock
*
* Copyright (C)1993,1994 Ian Jackson
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <X11/Xos.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <pwd.h>
#include <grp.h>
#include <limits.h>
#include <string.h>
#include <crypt.h>
#include <unistd.h>
#include <math.h>
#include <ctype.h>
#include <values.h>
/* required for custom passwd prompt --tetris11 */
#include <unistd.h>
#ifdef SHADOW_PWD
#include <shadow.h>
#endif
#include "lock.bitmap"
#include "mask.bitmap"
#include "patchlevel.h"
Display *display;
Window window, root;
#define TIMEOUTPERATTEMPT 30000
#define MAXGOODWILL (TIMEOUTPERATTEMPT*5)
#define INITIALGOODWILL MAXGOODWILL
#define GOODWILLPORTION 0.3
struct passwd *pw;
int c_pass = 0; /* custom_password flag */
int passwordok(const char *s) {
if ( c_pass == 1 ) {
return strcmp(s+1, pw->pw_passwd); /* skip first character to work --tetris11 */
}
#if 0
char key[3];
char *encr;
key[0] = *(pw->pw_passwd);
key[1] = (pw->pw_passwd)[1];
key[2] = 0;
encr = crypt(s, key);
return !strcmp(encr, pw->pw_passwd);
#else
/* simpler, and should work with crypt() algorithms using longer
salt strings (like the md5-based one on freebsd). --marekm */
return !strcmp(crypt(s, pw->pw_passwd), pw->pw_passwd);
#endif
}
int main(int argc, char **argv){
XEvent ev;
KeySym ks;
char cbuf[10], rbuf[128]; /* shadow appears to suggest 127 a good value here */
int clen, rlen=0;
long goodwill= INITIALGOODWILL, timeout= 0;
XSetWindowAttributes attrib;
Cursor cursor;
Pixmap csr_source,csr_mask;
XColor csr_fg, csr_bg, dummy, black;
int ret, screen, blank = 0;
char *custom_passwd = 0;
#define USAGE_EXIT \
fprintf(stderr,"xtrlock (version %s); usage: xtrlock [-b] [-p]\n", program_version); \
exit(1);
#define CUSTOM_PROMPT "custom passphrase: "
#ifdef SHADOW_PWD
struct spwd *sp;
#endif
struct timeval tv;
int tvt, gs;
if (argc == 2){
if (strcmp(argv[1], "-b") == 0 ) {
blank = 1;
}
else if (strcmp(argv[1],"-p") == 0 ) {
c_pass = 1;
custom_passwd = getpass(CUSTOM_PROMPT);
}
else {USAGE_EXIT}
}
else if (argc == 3) {
if (\
(strcmp(argv[1], "-b") == 0 ) && (strcmp(argv[2], "-p") == 0) || \
(strcmp(argv[1], "-p") == 0 ) && (strcmp(argv[2], "-b") == 0)\
) {
blank = c_pass = 1;
custom_passwd = getpass(CUSTOM_PROMPT);
}
else {USAGE_EXIT}
}
else if (argc > 1) {USAGE_EXIT}
errno=0; pw= getpwuid(getuid());
if (c_pass == 1) {
/* custom password bypasses gid uid checks, but still requires
a valid pw struct --tetris11 */
pw->pw_passwd = custom_passwd;
}
else {
if (!pw) { perror("password entry for uid not found"); exit(1); }
#ifdef SHADOW_PWD
sp = getspnam(pw->pw_name);
if (sp)
pw->pw_passwd = sp->sp_pwdp;
endspent();
#endif
/* logically, if we need to do the following then the same
applies to being installed setgid shadow.
we do this first, because of a bug in linux. --jdamery */
if (setgid(getgid())) { perror("setgid"); exit(1); }
/* we can be installed setuid root to support shadow passwords,
and we don't need root privileges any longer. --marekm */
if (setuid(getuid())) { perror("setuid"); exit(1); }
if (strlen(pw->pw_passwd) < 13) {
fputs("password entry has no pwd\n",stderr); exit(1);
}
}
display= XOpenDisplay(0);
if (display==NULL) {
fprintf(stderr,"xtrlock (version %s): cannot open display\n",
program_version);
exit(1);
}
attrib.override_redirect= True;
if (blank) {
screen = DefaultScreen(display);
attrib.background_pixel = BlackPixel(display, screen);
window= XCreateWindow(display,DefaultRootWindow(display),
0,0,DisplayWidth(display, screen),DisplayHeight(display, screen),
0,DefaultDepth(display, screen), CopyFromParent, DefaultVisual(display, screen),
CWOverrideRedirect|CWBackPixel,&attrib);
XAllocNamedColor(display, DefaultColormap(display, screen), "black", &black, &dummy);
} else {
window= XCreateWindow(display,DefaultRootWindow(display),
0,0,1,1,0,CopyFromParent,InputOnly,CopyFromParent,
CWOverrideRedirect,&attrib);
}
XSelectInput(display,window,KeyPressMask|KeyReleaseMask);
csr_source= XCreateBitmapFromData(display,window,lock_bits,lock_width,lock_height);
csr_mask= XCreateBitmapFromData(display,window,mask_bits,mask_width,mask_height);
ret = XAllocNamedColor(display,
DefaultColormap(display, DefaultScreen(display)),
"steelblue3",
&dummy, &csr_bg);
if (ret==0)
XAllocNamedColor(display,
DefaultColormap(display, DefaultScreen(display)),
"black",
&dummy, &csr_bg);
ret = XAllocNamedColor(display,
DefaultColormap(display,DefaultScreen(display)),
"grey25",
&dummy, &csr_fg);
if (ret==0)
XAllocNamedColor(display,
DefaultColormap(display, DefaultScreen(display)),
"white",
&dummy, &csr_bg);
cursor= XCreatePixmapCursor(display,csr_source,csr_mask,&csr_fg,&csr_bg,
lock_x_hot,lock_y_hot);
XMapWindow(display,window);
/*Sometimes the WM doesn't ungrab the keyboard quickly enough if
*launching xtrlock from a keystroke shortcut, meaning xtrlock fails
*to start We deal with this by waiting (up to 100 times) for 10,000
*microsecs and trying to grab each time. If we still fail
*(i.e. after 1s in total), then give up, and emit an error
*/
gs=0; /*gs==grab successful*/
for (tvt=0 ; tvt<100; tvt++) {
ret = XGrabKeyboard(display,window,False,GrabModeAsync,GrabModeAsync,
CurrentTime);
if (ret == GrabSuccess) {
gs=1;
break;
}
/*grab failed; wait .01s*/
tv.tv_sec=0;
tv.tv_usec=10000;
select(1,NULL,NULL,NULL,&tv);
}
if (gs==0){
fprintf(stderr,"xtrlock (version %s): cannot grab keyboard\n",
program_version);
exit(1);
}
if (XGrabPointer(display,window,False,(KeyPressMask|KeyReleaseMask)&0,
GrabModeAsync,GrabModeAsync,None,
cursor,CurrentTime)!=GrabSuccess) {
XUngrabKeyboard(display,CurrentTime);
fprintf(stderr,"xtrlock (version %s): cannot grab pointer\n",
program_version);
exit(1);
}
for (;;) {
XNextEvent(display,&ev);
switch (ev.type) {
case KeyPress:
if (ev.xkey.time < timeout) { XBell(display,0); break; }
clen= XLookupString(&ev.xkey,cbuf,9,&ks,0);
switch (ks) {
case XK_Escape: case XK_Clear:
rlen=0; break;
case XK_Delete: case XK_BackSpace:
if (rlen>0) rlen--;
break;
case XK_Linefeed: case XK_Return:
if (rlen==0) break;
rbuf[rlen]=0;
if (passwordok(rbuf)) goto loop_x;
XBell(display,0);
rlen= 0;
if (timeout) {
goodwill+= ev.xkey.time - timeout;
if (goodwill > MAXGOODWILL) {
goodwill= MAXGOODWILL;
}
}
timeout= -goodwill*GOODWILLPORTION;
goodwill+= timeout;
timeout+= ev.xkey.time + TIMEOUTPERATTEMPT;
break;
default:
if (clen != 1) break;
/* allow space for the trailing \0 */
if (rlen < (sizeof(rbuf) - 1)){
rbuf[rlen]=cbuf[0];
rlen++;
}
break;
}
break;
default:
break;
}
}
loop_x:
exit(0);
}
--- xtrlock.c 2014-01-07 14:20:33.000000000 +0000
+++ xtrlock.c.new 2015-11-27 16:20:42.148166109 +0000
@@ -37,6 +37,9 @@
#include <ctype.h>
#include <values.h>
+/* required for custom passwd prompt --tetris11 */
+#include <unistd.h>
+
#ifdef SHADOW_PWD
#include <shadow.h>
#endif
@@ -54,7 +57,15 @@
#define GOODWILLPORTION 0.3
struct passwd *pw;
+
+int c_pass = 0; /* custom_password flag */
+
int passwordok(const char *s) {
+
+ if ( c_pass == 1 ) {
+ return strcmp(s+1, pw->pw_passwd); /* skip first character to work --tetris11 */
+ }
+
#if 0
char key[3];
char *encr;
@@ -82,39 +93,71 @@
Pixmap csr_source,csr_mask;
XColor csr_fg, csr_bg, dummy, black;
int ret, screen, blank = 0;
+ char *custom_passwd = 0;
+
+#define USAGE_EXIT \
+ fprintf(stderr,"xtrlock (version %s); usage: xtrlock [-b] [-p]\n", program_version); \
+ exit(1);
+
+#define CUSTOM_PROMPT "custom passphrase: "
+
#ifdef SHADOW_PWD
struct spwd *sp;
#endif
struct timeval tv;
int tvt, gs;
- if ((argc == 2) && (strcmp(argv[1], "-b") == 0)) {
- blank = 1;
- } else if (argc > 1) {
- fprintf(stderr,"xtrlock (version %s); usage: xtrlock [-b]\n",
- program_version);
- exit(1);
+ if (argc == 2){
+ if (strcmp(argv[1], "-b") == 0 ) {
+ blank = 1;
+ }
+ else if (strcmp(argv[1],"-p") == 0 ) {
+ c_pass = 1;
+ custom_passwd = getpass(CUSTOM_PROMPT);
+ }
+ else {USAGE_EXIT}
}
-
+ else if (argc == 3) {
+ if (\
+ (strcmp(argv[1], "-b") == 0 ) && (strcmp(argv[2], "-p") == 0) || \
+ (strcmp(argv[1], "-p") == 0 ) && (strcmp(argv[2], "-b") == 0)\
+ ) {
+ blank = c_pass = 1;
+ custom_passwd = getpass(CUSTOM_PROMPT);
+ }
+ else {USAGE_EXIT}
+ }
+ else if (argc > 1) {USAGE_EXIT}
+
+
+
errno=0; pw= getpwuid(getuid());
- if (!pw) { perror("password entry for uid not found"); exit(1); }
+
+ if (c_pass == 1) {
+ /* custom password bypasses gid uid checks, but still requires
+ a valid pw struct --tetris11 */
+ pw->pw_passwd = custom_passwd;
+ }
+ else {
+ if (!pw) { perror("password entry for uid not found"); exit(1); }
#ifdef SHADOW_PWD
- sp = getspnam(pw->pw_name);
- if (sp)
- pw->pw_passwd = sp->sp_pwdp;
- endspent();
+ sp = getspnam(pw->pw_name);
+ if (sp)
+ pw->pw_passwd = sp->sp_pwdp;
+ endspent();
#endif
- /* logically, if we need to do the following then the same
- applies to being installed setgid shadow.
- we do this first, because of a bug in linux. --jdamery */
- if (setgid(getgid())) { perror("setgid"); exit(1); }
- /* we can be installed setuid root to support shadow passwords,
- and we don't need root privileges any longer. --marekm */
- if (setuid(getuid())) { perror("setuid"); exit(1); }
-
- if (strlen(pw->pw_passwd) < 13) {
- fputs("password entry has no pwd\n",stderr); exit(1);
+ /* logically, if we need to do the following then the same
+ applies to being installed setgid shadow.
+ we do this first, because of a bug in linux. --jdamery */
+ if (setgid(getgid())) { perror("setgid"); exit(1); }
+ /* we can be installed setuid root to support shadow passwords,
+ and we don't need root privileges any longer. --marekm */
+ if (setuid(getuid())) { perror("setuid"); exit(1); }
+
+ if (strlen(pw->pw_passwd) < 13) {
+ fputs("password entry has no pwd\n",stderr); exit(1);
+ }
}
display= XOpenDisplay(0);