initial import

--HG--
extra : convert_revision : svn%3Aeebe1cee-a9af-4fe4-bd26-ad572b19c5ab/trunk%401
This commit is contained in:
mathias 2005-04-30 00:35:03 +00:00
commit 620b251aaf
7 changed files with 744 additions and 0 deletions

7
CHANGELOG Normal file
View file

@ -0,0 +1,7 @@
Version 0.1
2005-04-28:
* first release (0.1)
* added pam-support (works ok with linux + freebsd so far)
* use scons for building the stuff

84
README Normal file
View file

@ -0,0 +1,84 @@
-+------------------------------------------------------------------+-
aklock - a slim screenlocker for X
-+------------------------------------------------------------------+-
1. about
2. installation
3. usage
4. todo
5. author
1. about
--------
'aklock' locks your current session in X. its not a fullfeatured
screensaver-distribution like 'xlockmore' or 'xscreensaver' but just a
tiny locker: "uh, i need coffee .. lock" .. speaking of size: binary takes
only 11kb. 'aklock' shows the content of the locked screen .. so you can
see whats going on, even when you are not able to modify what you see.
this is pretty usefull for public terminals where a demo should run which
shouldnt interupted (you know those little kids who press every button and
click everywhere ...).
an irc-friend of mine (izhirahider) is using 'xtrlock' and had some
problems with it .. no wonder, development stopped some years ago
and it doesnt support pam. since i like the minimalism of 'xtrlock'
but wanted to add some minor things to it i "forked" 'aklock' from
'xtrlock' and modified it a bit :)
2. installation
---------------
to install / compile 'aklock' you need 'scons':
http://www.scons.org
its a clever buildsystem which i prefer over make/autotools.
after installing 'scons' you just type:
$> scons
and it should build your personal version of 'aklock'
you can influence the build-process by some variables, check
$> scons -h
to finally install it to your system use:
$> scons install
and thats it.
tested platforms (so far):
gentoo-linux (pc and ppc with gcc3.4.3)
freebsd5.3 (pc gcc3.4.2)
3. usage
--------
aklock [-vh] [-blank]
-h displays a little help
-v displays version number
-blank hides the content of the screen with a big, black area
after locking 'aklock' will show a modified mousecursor. you have to
enter your password blindly. if its the correct password the screen will
unlock
4. todo
-------
- check on irix, sun, hp etc etc
- users wants to specify lockcursor + background for -blank
5. author
---------
2005 mathias gumz aka akira < akira at fluxbox dot org>
1993 - 1994 ian jackson (xtrlock)

79
SConstruct Normal file
View file

@ -0,0 +1,79 @@
#!/bin/env python
##########################################################
#
# scons - buildsystem for aklock
#
##########################################################
import sys
aklock_version = '0.1'
aklock_optfile = 'scons.opts'
aklock_distfiles = ['aklock.c',
'lock.bitmap', 'mask.bitmap',
'SConstruct', 'README', 'CHANGELOG' ]
aklock_sources = [ 'aklock.c' ]
aklock_target = 'aklock'
Default(aklock_target)
aklock_options = Options(aklock_optfile)
aklock_options.AddOptions(
BoolOption('debug', 'build debug version', 0),
BoolOption('shadow', 'support for shadowpasswords', 0),
BoolOption('pam', 'support for pam', 1),
PathOption('prefix', 'install-path base', '/usr/local')
)
aklock_env = Environment(options = aklock_options,
TARFLAGS = '-c -z',
TARSUFFIX = '.tgz')
Help(aklock_options.GenerateHelpText(aklock_env))
###########################################################
#
#
build = aklock_env.Copy()
if sys.platform == "linux2" or sys.platform == "linux-i386":
build.AppendUnique(
CPPDEFINES = [ 'LINUX' ])
build.AppendUnique(
CPPDEFINES = [ 'VERSION=\\"'+aklock_version+'\\"' ],
CPPFLAGS = [ '-Wall' ],
CPPPATH = [ '/usr/X11R6/include' ],
LIBPATH = ['/usr/X11R6/lib'],
LIBS = [ 'X11', 'crypt' ])
if build['debug']:
build.AppendUnique(
CPPDEFINES = [ 'DEBUG' ],
LINKFLAGS = [ '-g' ],
CPPFLAGS = [ '-g' ])
if build['pam']:
build.AppendUnique(
CPPDEFINES = [ 'PAM_PWD' ],
LIBS = [ 'pam' ])
if sys.platform == 'linux2' or sys.platform == 'linux-i386':
build.AppendUnique(LIBS = ['pam_misc'])
if build['shadow']:
build.AppendUnique(
CPPDEFINES = [ 'SHADOW_PWD' ])
aklock_program = build.Program(aklock_target, aklock_sources)
build.AddPostAction(aklock_program, Chmod(aklock_target, 0755))
aklock_env.Install(aklock_env['prefix']+'/bin', aklock_program)
aklock_env.Alias('install', aklock_env['prefix']+'/bin')
# TODO: add a "scons dist" command which builds a propper tarball
#aklock_env.Alias('dist', aklock_env.Tar(aklock_target + '-' + aklock_version,
# aklock_distfiles))
# vim:ft=python

482
aklock.c Normal file
View file

@ -0,0 +1,482 @@
/*------------------------------------------------------------------*\
file: aklock.c
X Transparent Lock
copyright:
Copyright (C)1993,1994 Ian Jackson (xtrlock)
Copyright (C)2005 Mathias Gumz (forked aklock)
license:
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 <unistd.h>
#include <math.h>
#include <ctype.h>
#ifdef SHADOW_PWD
# include <shadow.h>
#endif /* SHADOW_PWD */
#ifdef PAM_PWD
# include <security/pam_appl.h>
# ifdef LINUX
# include <security/pam_misc.h>
# endif
#endif /* PAM_PWD */
/*----------------------------------------------*\
\*----------------------------------------------*/
#include "lock.bitmap"
#include "mask.bitmap"
/*------------------------------------------------------------------*\
globals
\*------------------------------------------------------------------*/
#define TIMEOUTPERATTEMPT 30000
#define MAXGOODWILL (TIMEOUTPERATTEMPT*5)
#define INITIALGOODWILL MAXGOODWILL
#define GOODWILLPORTION 0.3
#ifdef DEBUG
# define DBGMSG fprintf(stderr, "%s : %d\n", __FUNCTION__, __LINE__); fflush(stderr)
#else
# define DBGMSG
#endif // DEBUG
struct passwd *pw;
/*------------------------------------------------------------------*\
\*------------------------------------------------------------------*/
void displayUsage() {
printf("\naklock [-hv] [-blank]\n\n"
" -h shows this little help\n"
" -v shows the version number\n"
" -blank hides the content of the screen\n"
"\n"
"when the screen is locked, just enter your password.\n");
}
/*------------------------------------------------------------------*\
pam-related stuff
taken from pure-ftpd's authstuff, but you can see similar stuff
in xlockmore, openssh and basicly all pam-related apps :)
\*------------------------------------------------------------------*/
#ifdef PAM_PWD
# define PAM_YN { \
if (PAM_error != 0 || pam_error != PAM_SUCCESS) { \
fprintf(stderr, "pam error:%s\n", pam_strerror(pam_handle, pam_error)); \
pam_end(pam_handle, pam_error); \
PAM_username = NULL; \
PAM_password = NULL; \
return 0;\
} \
}
# define GET_MEM \
size += sizeof(struct pam_response); \
if ((reply = realloc(reply, size)) == NULL) { \
PAM_error = 1; \
return PAM_CONV_ERR; \
}
static const char* PAM_username = NULL;
static const char* PAM_password = NULL;
static int PAM_error = 0;
static int pam_error = PAM_SUCCESS;
static int PAM_conv(int num_msg, const struct pam_message **msgs,
struct pam_response **resp, void *appdata_ptr) {
int count = 0;
unsigned int replies = 0U;
struct pam_response *reply = NULL;
size_t size = (size_t) 0U;
(void) appdata_ptr;
*resp = NULL;
for (count = 0; count < num_msg; count++) {
switch (msgs[count]->msg_style) {
case PAM_PROMPT_ECHO_ON:
GET_MEM;
memset(&reply[replies], 0, sizeof reply[replies]);
if ((reply[replies].resp = strdup(PAM_username)) == NULL) {
# ifdef PAM_BUF_ERR
reply[replies].resp_retcode = PAM_BUF_ERR;
# endif
PAM_error = 1;
return PAM_CONV_ERR;
}
reply[replies++].resp_retcode = PAM_SUCCESS;
/* PAM frees resp */
break;
case PAM_PROMPT_ECHO_OFF:
GET_MEM;
memset(&reply[replies], 0, sizeof reply[replies]);
if ((reply[replies].resp = strdup(PAM_password)) == NULL) {
# ifdef PAM_BUF_ERR
reply[replies].resp_retcode = PAM_BUF_ERR;
# endif
PAM_error = 1;
return PAM_CONV_ERR;
}
reply[replies++].resp_retcode = PAM_SUCCESS;
/* PAM frees resp */
break;
case PAM_TEXT_INFO:
/* ignore it... */
break;
case PAM_ERROR_MSG:
default:
/* Must be an error of some sort... */
free(reply);
PAM_error = 1;
return PAM_CONV_ERR;
}
}
*resp = reply;
return PAM_SUCCESS;
}
static struct pam_conv PAM_conversation = {
&PAM_conv, NULL
};
#endif /* PAM_PWD */
/*------------------------------------------------------------------*\
\*------------------------------------------------------------------*/
int passwordOk(const char *s) {
#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 */
#ifdef PAM_PWD
pam_handle_t* pam_handle = NULL;
PAM_username = pw->pw_name;
PAM_password = s;
pam_error = pam_start("login", PAM_username, &PAM_conversation, &pam_handle);
PAM_YN;
pam_error = pam_authenticate(pam_handle, 0);
PAM_YN;
pam_error = pam_end(pam_handle, pam_error);
PAM_YN;
return 1;
#else
return !strcmp(crypt(s, pw->pw_passwd), pw->pw_passwd);
#endif /* PAM_PWD */
#endif /* 0 */
}
/*------------------------------------------------------------------*\
check if the system would be able to authentificate the user
\*------------------------------------------------------------------*/
void checkAuth() {
#ifdef SHADOW_PWD
struct spwd *sp;
#endif
errno = 0;
pw = getpwuid(getuid());
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
/* we can be installed setuid root to support shadow passwords,
and we don't need root privileges any longer. --marekm */
setuid(getuid());
#ifndef PAM_PWD
if (strlen(pw->pw_passwd) < 13) {
perror("aklock: password entry has no pwd\n");
exit(1);
}
#endif /* PAM_PWD */
}
/*------------------------------------------------------------------*\
\*------------------------------------------------------------------*/
struct XInfo {
Display* display;
Window root;
Window window;
Cursor cursor;
int width;
int height;
};
struct Opts {
char use_blank;
char* color_fg;
char* color_bg;
};
/*------------------------------------------------------------------*\
\*------------------------------------------------------------------*/
void initOpts(struct Opts* opts) {
opts->use_blank = 0;
opts->color_bg = "steelblue3";
opts->color_fg = "grey25";
}
void initXInfo(struct XInfo* xinfo, struct Opts* opts) {
Display* dpy = XOpenDisplay(NULL);
XColor color_fg;
XColor color_bg;
XColor tmp_color;
Colormap color_map;
Pixmap pixmap_cursor;
Pixmap pixmap_cursor_mask;
XWindowAttributes xgwa;
if (!dpy) {
perror("aklock: error, can't open connection to X");
exit(1);
}
xinfo->display = dpy;
xinfo->window = 0;
xinfo->root = DefaultRootWindow(dpy);
color_map = DefaultColormap(dpy, DefaultScreen(dpy));
XGetWindowAttributes(dpy, xinfo->root, &xgwa);
xinfo->width = xgwa.width;
xinfo->height = xgwa.height;
pixmap_cursor = XCreateBitmapFromData(dpy, xinfo->root, lock_bits, lock_width, lock_height);
pixmap_cursor_mask = XCreateBitmapFromData(dpy, xinfo->root, mask_bits, mask_width, mask_height);
if((XAllocNamedColor(dpy, color_map, opts->color_bg, &tmp_color, &color_bg)) == 0)
XAllocNamedColor(dpy, color_map, "black", &tmp_color, &color_bg);
if((XAllocNamedColor(dpy, color_map, opts->color_fg, &tmp_color, &color_fg)) == 0)
XAllocNamedColor(dpy, color_map, "white", &tmp_color, &color_fg);
xinfo->cursor = XCreatePixmapCursor(dpy,
pixmap_cursor, pixmap_cursor_mask,
&color_fg, &color_bg,
lock_x_hot, lock_y_hot);
}
int main(int argc, char **argv) {
XEvent ev;
KeySym ks;
char cbuf[10], rbuf[50];
int clen, rlen = 0;
long goodwill = INITIALGOODWILL, timeout = 0;
XSetWindowAttributes xswa;
long xsmask = 0;
struct XInfo xinfo;
struct Opts opts;
int arg = 0;
initOpts(&opts);
// parse options
if (argc != 1) {
for(arg = 1; arg <= argc; arg++) {
if (!strcmp(argv[arg - 1], "-blank")) {
opts.use_blank = 1;
} else if (!strcmp(argv[arg - 1], "-h")) {
displayUsage();
exit(0);
} else if (!strcmp(argv[arg - 1], "-v")) {
printf("aklock-%s by m.gumz 2005\n", VERSION);
exit(0);
}
}
}
checkAuth();
initXInfo(&xinfo, &opts);
/* create the windows */
xswa.override_redirect = True;
xsmask |= CWOverrideRedirect;
if (opts.use_blank) {
xswa.background_pixel = BlackPixel(xinfo.display, DefaultScreen(xinfo.display));
xsmask |= CWBackPixel;
xinfo.window = XCreateWindow(xinfo.display, xinfo.root,
0, 0, xinfo.width, xinfo.height,
0, /* borderwidth */
CopyFromParent, /* depth */
InputOutput, /* class */
CopyFromParent, /* visual */
xsmask, &xswa);
} else {
xinfo.window = XCreateWindow(xinfo.display, xinfo.root,
0, 0, 1, 1,
0, /* borderwidth */
CopyFromParent, /* depth */
InputOnly, /* class */
CopyFromParent, /* visual */
xsmask, &xswa);
}
XSelectInput(xinfo.display, xinfo.window, KeyPressMask|KeyReleaseMask);
XMapWindow(xinfo.display, xinfo.window);
XRaiseWindow(xinfo.display, xinfo.window);
/* try to grab 2 times, another process (windowmanager) may have grabbed
* the keyboard already */
if ((XGrabKeyboard(xinfo.display, xinfo.window, True, GrabModeAsync, GrabModeAsync,
CurrentTime)) != GrabSuccess) {
sleep(1);
if ((XGrabKeyboard(xinfo.display, xinfo.window, True, GrabModeAsync, GrabModeAsync,
CurrentTime)) != GrabSuccess) {
perror("aklock: couldnt grab the keyboard.\n");
exit(1);
}
}
if (XGrabPointer(xinfo.display, xinfo.window, False, (KeyPressMask|KeyReleaseMask) & 0,
GrabModeAsync, GrabModeAsync, None, xinfo.cursor, CurrentTime) != GrabSuccess) {
XUngrabKeyboard(xinfo.display, CurrentTime);
perror("aklock: couldnt grab the pointer.\n");
exit(1);
}
/* eventhandling */
for(;;) {
XNextEvent(xinfo.display, &ev);
switch (ev.type) {
case KeyPress:
if (ev.xkey.time < timeout) {
XBell(xinfo.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 exit;
XBell(xinfo.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;
if (rlen < sizeof(rbuf))
rbuf[rlen] = cbuf[0];
rlen++;
break;
}
break;
default:
break;
}
}
exit:
XDestroyWindow(xinfo.display, xinfo.window);
XCloseDisplay(xinfo.display);
return 0;
}

54
aklock.man Normal file
View file

@ -0,0 +1,54 @@
.TH AKLOCK 1
.SH NAME
aklock \- Lock X display until password supplied
.SH SYNOPSIS
.B aklock
.SH DESCRIPTION
.B aklock
locks the X server till the user enters their password at the keyboard.
While
.B aklock
is running, the mouse and keyboard are grabbed and the mouse cursor
becomes a padlock. Output displayed by X programs, and windows put up
by new X clients, continue to be visible, and any new output is
displayed normally, except you run in -blank mode. Then the content
of the Screen is hidden behind a black Window.
The mouse and keyboard are returned when the user types their
password, followed by Enter or Newline. If an incorrect password is
entered the bell is sounded. Pressing Backspace or Delete erases one
character of a password partially typed; pressing Escape or Clear
clears anything that has been entered.
If too many attempts are made in too short a time further keystrokes
generate bells and are otherwise ignored until a timeout has expired.
The X server screen saver continues to operate normally; if it comes
into operation the display may be restored by the usual means of
touching a key (Shift, for example) or the mouse.
.SH OPTIONS, X RESOURCES, CONFIGURATION
None.
.SH BUGS
Additional input devices other than the keyboard and mouse are not
disabled.
The timeouts, bitmaps and mouse cursor colour cannot be modifed.
.SH SEE ALSO
.BR X "(1), " xlock "(1), Xlib Documentation."
.SH AUTHOR
Mathias Gumz <akira at gmail dot com>
Ian Jackson <ijackson@nyx.cs.du.edu>
.SH COPYRIGHT
Copyright (C) 2005 Mathias Gumz
Copyright (C) 1993, 1994 by Ian Jackson.
Permission to use, copy, modify and distribute this software and its
documentation is granted under the terms of the GNU General Public
Licence, version 2 or later, as published by the Free Software
Foundation.
This program 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.

19
lock.bitmap Normal file
View file

@ -0,0 +1,19 @@
#define lock_width 28
#define lock_height 40
#define lock_x_hot 14
#define lock_y_hot 21
static char lock_bits[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0xf8, 0xff, 0x7f, 0x00, 0xe0, 0xff,
0x3f, 0x00, 0xc0, 0xff, 0x1f, 0x00, 0x80, 0xff, 0x0f, 0xfc, 0x03, 0xff,
0x0f, 0xfe, 0x07, 0xff, 0x0f, 0xff, 0x0f, 0xff, 0x07, 0xff, 0x0f, 0xfe,
0x87, 0xff, 0x1f, 0xfe, 0x87, 0xff, 0x1f, 0xfe, 0x87, 0xff, 0x1f, 0xfe,
0x87, 0xff, 0x1f, 0xfe, 0x87, 0xff, 0x1f, 0xfe, 0x87, 0xff, 0x1f, 0xfe,
0x87, 0xff, 0x1f, 0xfe, 0x87, 0xff, 0x1f, 0xfe, 0x87, 0xff, 0x1f, 0xfe,
0x87, 0xff, 0x1f, 0xfe, 0x01, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0xf8,
0x01, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0xf8, 0x01, 0xf0, 0x00, 0xf8,
0x01, 0xf8, 0x01, 0xf8, 0x01, 0xf8, 0x01, 0xf8, 0x01, 0xf8, 0x01, 0xf8,
0x01, 0xf8, 0x01, 0xf8, 0x01, 0xf0, 0x00, 0xf8, 0x01, 0x60, 0x00, 0xf8,
0x01, 0x60, 0x00, 0xf8, 0x01, 0x60, 0x00, 0xf8, 0x01, 0x60, 0x00, 0xf8,
0x01, 0x60, 0x00, 0xf8, 0x01, 0x60, 0x00, 0xf8, 0x01, 0x00, 0x00, 0xf8,
0x01, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0xf8,
0xff, 0xff, 0xff, 0xff};

19
mask.bitmap Normal file
View file

@ -0,0 +1,19 @@
#define mask_width 28
#define mask_height 40
#define mask_x_hot 14
#define mask_y_hot 21
static char mask_bits[] = {
0x00, 0xfe, 0x07, 0x00, 0x80, 0xff, 0x1f, 0x00, 0xc0, 0xff, 0x3f, 0x00,
0xe0, 0xff, 0x7f, 0x00, 0xf0, 0xff, 0xff, 0x00, 0xf8, 0xff, 0xff, 0x01,
0xf8, 0x03, 0xfc, 0x01, 0xf8, 0x01, 0xf8, 0x01, 0xfc, 0x01, 0xf8, 0x03,
0xfc, 0x00, 0xf0, 0x03, 0xfc, 0x00, 0xf0, 0x03, 0xfc, 0x00, 0xf0, 0x03,
0xfc, 0x00, 0xf0, 0x03, 0xfc, 0x00, 0xf0, 0x03, 0xfc, 0x00, 0xf0, 0x03,
0xfc, 0x00, 0xf0, 0x03, 0xfc, 0x00, 0xf0, 0x03, 0xfc, 0x00, 0xf0, 0x03,
0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
0xff, 0xff, 0xff, 0x0f};