diff --git a/CHANGELOG b/CHANGELOG index 3bd242a..9425839 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,17 @@ -Version 0.2 +Version 0.5 + +2005-05-07: + + * big restructering + feature enhancements + + added auth_.c, each basic auth-method has now + its own implementation-file + + added -auth - flag: + - list - lists all available methods + - none - no auth, like -nolock + - passwd - standard login, possible shadowsupport + - pam - use pam for authentification + - md5:hash - provide a md5-hash for authentification + * support for 'shadow'-passwords is part of the passwd authmodule 2005-05-06: diff --git a/README b/README index d93bccc..99fd11e 100644 --- a/README +++ b/README @@ -59,22 +59,25 @@ 3. usage -------- - aklock [-vh] [-blank] + aklock [-vh] [-blank] [-cursor ] + [-auth list|] -h displays a little help -v displays version number -blank hides the content of the screen with a big, black area + -cursor choose between multiple cursors + -auth choose between different authmethods. after locking 'aklock' will show a modified mousecursor. you have to enter your password blindly. if its the correct password the screen will - unlock + unlock. 4. todo ------- + - better documentation, updated manpage - check on irix, sun, hp etc etc - - users wants to specify lockcursor + background for -blank 5. author --------- diff --git a/SConstruct b/SConstruct index 56f6f4d..c44df6c 100644 --- a/SConstruct +++ b/SConstruct @@ -18,8 +18,10 @@ Default(aklock_target) aklock_options = Options(aklock_optfile) aklock_options.AddOptions( BoolOption('debug', 'build debug version', 0), + BoolOption('passwd', 'support for classic passwd', 0), BoolOption('shadow', 'support for shadowpasswords', 0), BoolOption('pam', 'support for pam', 1), + BoolOption('md5', 'support for md5', 1), BoolOption('xcursor', 'support xcursor-themes', 1), @@ -45,7 +47,7 @@ aklock_env.AppendUnique( CPPFLAGS = [ '-Wall' ], CPPPATH = [ '/usr/X11R6/include' ], LIBPATH = ['/usr/X11R6/lib'], - LIBS = [ 'X11', 'crypt' ]) + LIBS = [ 'X11' ]) if aklock_env['debug']: aklock_env.AppendUnique( @@ -53,10 +55,15 @@ if aklock_env['debug']: LINKFLAGS = [ '-g' ], CPPFLAGS = [ '-g' ]) +if aklock_env['passwd']: + aklock_env.AppendUnique( + CPPDEFINES = [ 'PASSWD_PWD' ], + LIBS = [ 'crypt' ]) + if aklock_env['pam']: aklock_env.AppendUnique( CPPDEFINES = [ 'PAM_PWD' ], - LIBS = [ 'pam' ]) + LIBS = [ 'pam', 'crypt' ]) if sys.platform == 'linux2' or sys.platform == 'linux-i386': aklock_env.AppendUnique(LIBS = ['pam_misc']) @@ -66,6 +73,10 @@ if aklock_env['shadow']: aklock_env.AppendUnique( CPPDEFINES = [ 'SHADOW_PWD' ]) +if aklock_env['md5']: + aklock_env.AppendUnique( + CPPDEFINES = [ 'MD5_PWD' ]) + if aklock_env['xcursor']: conf = aklock_env.Configure() if conf.CheckLib('Xcursor', 'XcursorSupportsARGB', 1): diff --git a/src/SConscript b/src/SConscript index 41db0b0..e2fe61c 100644 --- a/src/SConscript +++ b/src/SConscript @@ -5,12 +5,19 @@ # ########################################################## -aklock_sources = [ 'aklock.c', 'akcursors.c' ] +aklock_sources = [ 'aklock.c', 'akcursors.c', 'auth_none.c' ] Import('aklock_env') build = aklock_env.Copy() +if build['passwd']: + aklock_sources += [ 'auth_passwd.c' ] +if build['md5']: + aklock_sources += [ 'auth_md5.c' ] +if build['pam']: + aklock_sources += [ 'auth_pam.c' ] + aklock = build.Program('aklock', aklock_sources) build.AddPostAction(aklock, Chmod(aklock, 0755)) diff --git a/src/aklock.c b/src/aklock.c index be2f021..36e797e 100644 --- a/src/aklock.c +++ b/src/aklock.c @@ -40,33 +40,25 @@ #include #include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include - -#ifdef SHADOW_PWD -# include -#endif /* SHADOW_PWD */ - -#ifdef PAM_PWD -# include -# ifdef LINUX -# include -# endif -#endif /* PAM_PWD */ /*----------------------------------------------*\ \*----------------------------------------------*/ #include "aklock.h" +struct akXInfo { + + Display* display; + Window root; + Window window; + Colormap colormap; + + Cursor cursor; + + int width; + int height; +}; /*------------------------------------------------------------------*\ globals \*------------------------------------------------------------------*/ @@ -82,186 +74,34 @@ # define DBGMSG #endif // DEBUG -struct passwd *pw; - - +static struct akAuth* ak_authmodules[] = { + &aklock_auth_none, +#ifdef MD5_PWD + &aklock_auth_md5, +#endif /* MD5_PWD */ +#ifdef PASSWD_PWD + &aklock_auth_passwd, +#endif /* PASSWD_PWD */ +#ifdef PAM_PWD + &aklock_auth_pam, +#endif + NULL +}; /*------------------------------------------------------------------*\ \*------------------------------------------------------------------*/ void displayUsage() { - printf("\naklock [-h] [-v] [-blank] [-nolock] [-cursor ]\n"); + printf("\naklock [-h] [-v] [-blank] [-cursor ]\n"); + printf(" [-auth list|]\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 */ - -} - - - -/*------------------------------------------------------------------*\ -\*------------------------------------------------------------------*/ - - /*------------------------------------------------------------------*\ \*------------------------------------------------------------------*/ void initOpts(struct akOpts* opts) { - opts->dont_lock = 0; + opts->auth = ak_authmodules[0]; opts->use_blank = 0; opts->cursor_name = "mini"; @@ -376,13 +216,47 @@ int main(int argc, char **argv) { initOpts(&opts); - // parse options + /* 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], "-nolock")) { - opts.dont_lock = 1; + } else if (!strcmp(argv[arg - 1], "-auth")) { + if (arg < argc) { + + char* char_tmp; + struct akAuth* auth_tmp = NULL; + struct akAuth** i; + if (!strcmp(argv[arg], "list")) { + for(i = ak_authmodules; *i; ++i) { + printf("%s\n", (*i)->name); + } + exit(0); + } + + for(i = ak_authmodules; *i; ++i) { + char_tmp = strstr(argv[arg], (*i)->name); + if(char_tmp && char_tmp == argv[arg]) { + auth_tmp = (*i); + if (!auth_tmp->init(argv[arg])) { + fprintf(stderr, "aklock: error, failed init of [%s].\n", auth_tmp->name); + exit(1); + } + opts.auth = auth_tmp; + break; + } + } + + if (!auth_tmp) { + fprintf(stderr, "aklock: error, couldnt find the auth module you specified.\n"); + exit(1); + } + + } else { + fprintf(stderr, "aklock, error, missing argument\n"); + displayUsage(); + exit(1); + } } else if (!strcmp(argv[arg - 1], "-cursor")) { if (arg < argc) opts.cursor_name = argv[arg]; @@ -401,12 +275,8 @@ int main(int argc, char **argv) { } } - if (!opts.dont_lock) - checkAuth(); - initXInfo(&xinfo, &opts); - /* create the windows */ xswa.override_redirect = True; xsmask |= CWOverrideRedirect; @@ -434,7 +304,7 @@ int main(int argc, char **argv) { XRaiseWindow(xinfo.display, xinfo.window); /* TODO: -bg */ - if (opts.use_blank) { + /* if (opts.use_blank) { XImage* ximage; ximage = XGetImage (xinfo.display, xinfo.root, 0, 0, @@ -456,7 +326,7 @@ int main(int argc, char **argv) { XDestroyImage(ximage); XFreeGC(xinfo.display, gc); } - } + } */ /* try to grab 2 times, another process (windowmanager) may have grabbed * the keyboard already */ if ((XGrabKeyboard(xinfo.display, xinfo.window, True, GrabModeAsync, GrabModeAsync, @@ -482,9 +352,6 @@ int main(int argc, char **argv) { switch (ev.type) { case KeyPress: - if (opts.dont_lock) - goto exit; - if (ev.xkey.time < timeout) { XBell(xinfo.display, 0); break; @@ -507,7 +374,7 @@ int main(int argc, char **argv) { break; rbuf[rlen] = 0; - if (passwordOk(rbuf)) + if (opts.auth->auth(rbuf)) goto exit; XSync(xinfo.display, True); /* discard pending events to start really fresh */ @@ -538,6 +405,9 @@ int main(int argc, char **argv) { } exit: + + opts.auth->deinit(); + XDestroyWindow(xinfo.display, xinfo.window); XFreeCursor(xinfo.display, xinfo.cursor); XCloseDisplay(xinfo.display); diff --git a/src/aklock.h b/src/aklock.h index 54cae1a..0a89201 100644 --- a/src/aklock.h +++ b/src/aklock.h @@ -22,6 +22,13 @@ /* ---------------------------------------------------------------- *\ \* ---------------------------------------------------------------- */ +struct akAuth { + const char* name; + int (*init)(const char* args); + int (*auth)(const char* pass); + int (*deinit)(); +}; + struct akCursor { const char* name; unsigned int width; @@ -33,22 +40,11 @@ struct akCursor { unsigned char* mask; }; -struct akXInfo { - - Display* display; - Window root; - Window window; - Colormap colormap; - Cursor cursor; - - int width; - int height; -}; struct akOpts { - char dont_lock; + struct akAuth* auth; char use_blank; char* cursor_name; @@ -62,6 +58,19 @@ struct akOpts { \*------------------------------------------------------------------*/ extern struct akCursor ak_cursors[]; + +/*------------------------------------------------------------------*\ +\*------------------------------------------------------------------*/ +extern struct akAuth aklock_auth_none; +#ifdef MD5_PWD +extern struct akAuth aklock_auth_md5; +#endif /* MD5_PWD */ +#ifdef PASSWD_PWD +extern struct akAuth aklock_auth_passwd; +#endif /* PASSWD_PWD */ +#ifdef PAM_PWD +extern struct akAuth aklock_auth_pam; +#endif /* PAM_PWD */ /* ---------------------------------------------------------------- *\ \* ---------------------------------------------------------------- */ #endif // _AKLOCK_H_ diff --git a/src/auth_md5.c b/src/auth_md5.c new file mode 100644 index 0000000..22ce04c --- /dev/null +++ b/src/auth_md5.c @@ -0,0 +1,396 @@ +/* ---------------------------------------------------------------- *\ + + file : auth_md5.c + author : m. gumz + copyr : copyright (c) 2005 by m. gumz + + license : based on: + + MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm + + Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All + rights reserved. + + License to copy and use this software is granted provided that it + is identified as the "RSA Data Security, Inc. MD5 Message-Digest + Algorithm" in all material mentioning or referencing this software + or this function. + + License is also granted to make and use derivative works provided + that such works are identified as "derived from the RSA Data + Security, Inc. MD5 Message-Digest Algorithm" in all material + mentioning or referencing the derived work. + + RSA Data Security, Inc. makes no representations concerning either + the merchantability of this software or the suitability of this + software for any particular purpose. It is provided "as is" + without express or implied warranty of any kind. + + These notices must be retained in any copies of any part of this + documentation and/or software. + + start : Sa 07 Mai 2005 13:21:45 CEST + +\* ---------------------------------------------------------------- */ +/* ---------------------------------------------------------------- *\ + + about : + +\* ---------------------------------------------------------------- */ + +/* ---------------------------------------------------------------- *\ + includes +\* ---------------------------------------------------------------- */ +#include +#include +#include +#include "aklock.h" +/*------------------------------------------------------------------*\ +\*------------------------------------------------------------------*/ + +enum { + S11 = 7, + S12 = 12, + S13 = 17, + S14 = 22, + S21 = 5, + S22 = 9, + S23 = 14, + S24 = 20, + S31 = 4, + S32 = 11, + S33 = 16, + S34 = 23, + S41 = 6, + S42 = 10, + S43 = 15, + S44 = 21 +}; + +typedef struct { + unsigned long int state[4]; /* state (ABCD) */ + unsigned long int count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ +} md5Context; + + +static void md5_transform(unsigned long int[4], unsigned char [64]); +static void md5_encode(unsigned char*, unsigned long int*, unsigned int); +static void md5_decode(unsigned long int*, unsigned char*, unsigned int); + +static void md5_init(md5Context*); +static void md5_update(md5Context*, unsigned char *, unsigned int); +static void md5_final(unsigned char[16], md5Context *); + +/*------------------------------------------------------------------*\ +\*------------------------------------------------------------------*/ +static unsigned char padding[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* F, G, H and I are basic MD5 functions. */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits. */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/*--------------------------------------------------------*\ + FF, GG, HH, and II transformations for rounds 1, 2, 3, + and 4. Rotation is separate from addition to prevent + recomputation. +\*--------------------------------------------------------*/ +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (unsigned long int)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ +} + +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (unsigned long int)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ +} + + +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (unsigned long int)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ +} + +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (unsigned long int)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ +} +/*------------------------------------------------------------------*\ +\*------------------------------------------------------------------*/ + +/*--------------------------------------------------------*\ + MD5 initialization. Begins an MD5 operation, writing + a new context. +\*--------------------------------------------------------*/ +static void md5_init(md5Context* context) { + context->count[0] = context->count[1] = 0; + /* Load magic initialization constants.*/ + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; +} + +/*--------------------------------------------------------*\ + MD5 block update operation. Continues an MD5 + message-digest operation, processing another message + block, and updating the context. +\*--------------------------------------------------------*/ + +static void md5_update(md5Context* context, unsigned char* input, unsigned int inputLen) { + + unsigned int i, index, partLen; + + /* Compute number of bytes mod 64 */ + index = (unsigned int)((context->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ((context->count[0] += ((unsigned long int)inputLen << 3)) < ((unsigned long int)inputLen << 3)) + context->count[1]++; + + context->count[1] += ((unsigned long int)inputLen >> 29); + + partLen = 64 - index; + + /* Transform as many times as possible. */ + if (inputLen >= partLen) { + memcpy((unsigned char*)&context->buffer[index], + (unsigned char*)input, + partLen); + md5_transform(context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + md5_transform(context->state, &input[i]); + + index = 0; + } + else + i = 0; + + /* Buffer remaining input */ + memcpy((unsigned char*)&context->buffer[index], + (unsigned char*)&input[i], + inputLen-i); +} + +/*--------------------------------------------------------*\ + MD5 finalization. Ends an MD5 message-digest operation, + writing the the message digest and zeroizing the context. +\*--------------------------------------------------------*/ +static void md5_final(unsigned char digest[16], md5Context* context) { + unsigned char bits[8]; + unsigned int index; + unsigned int padLen; + + /* Save number of bits */ + md5_encode(bits, context->count, 8); + + /* Pad out to 56 mod 64. */ + index = (unsigned int)((context->count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + md5_update(context, padding, padLen); + + /* Append length (before padding) */ + md5_update(context, bits, 8); + /* Store state in digest */ + md5_encode(digest, context->state, 16); + + /* Zeroize sensitive information. */ + memset((unsigned char*)context, 0, sizeof (*context)); +} +/* MD5 basic transformation. Transforms state based on block. + */ +static void md5_transform(unsigned long int state[4], unsigned char block[64]) { + unsigned long int a = state[0]; + unsigned long int b = state[1]; + unsigned long int c = state[2]; + unsigned long int d = state[3]; + unsigned long int x[16]; + + md5_decode(x, block, 64); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* Zeroize sensitive information. */ + memset((unsigned char*)x, 0, sizeof (x)); +} + +/*--------------------------------------------------------*\ + Encodes input into output. Assumes len is a multiple + of 4. +\*--------------------------------------------------------*/ +static void md5_encode(unsigned char* output, unsigned long int* input, unsigned int len) { + + unsigned int i, j; + for (i = 0, j = 0; j < len; i++, j += 4) { + output[j] = (unsigned char)(input[i] & 0xff); + output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); + output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); + output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); + } +} + +/*--------------------------------------------------------*\ + Decodes input into output. Assumes len is a multiple + of 4. +\*--------------------------------------------------------*/ +static void md5_decode(unsigned long int* output, unsigned char* input, unsigned int len) { + + unsigned int i, j; + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((unsigned long int)input[j]) | + (((unsigned long int)input[j+1]) << 8) | + (((unsigned long int)input[j+2]) << 16) | + (((unsigned long int)input[j+3]) << 24); +} + + +/* ---------------------------------------------------------------- *\ +\* ---------------------------------------------------------------- */ + +static const char* userhash = NULL; + +static int init(const char* args) { + if (args) { + char* check = strstr(args, "md5:"); + if (!check || check != args) { + fprintf(stderr, "aklock: error, missing arguments for [md5].\n"); + return 0; + } + + if (strlen(&args[4]) != 32) { + fprintf(stderr, "aklock: error, invalid md5-hash.\n"); + return 0; + } + + userhash = &args[4]; + return 1; + } + + return 0; +} + +static int deinit() { + return 1; +} + +static int auth(const char* pass) { + + unsigned char tmpdigest[16]; + unsigned char digest[32]; + unsigned int i; + md5Context md5; + + if (!pass || !userhash) + return 0; + + md5_init(&md5); + md5_update(&md5, (unsigned char*)pass, strlen(pass)); + md5_final(tmpdigest, &md5); + + for (i = 0; i < 16; i++) { + sprintf(&digest[i*2], "%02x", tmpdigest[i]); + } + + return !strcmp(digest, userhash); +} + +struct akAuth aklock_auth_md5 = { + "md5", + init, + auth, + deinit +}; + +/* ---------------------------------------------------------------- *\ +\* ---------------------------------------------------------------- */ + + diff --git a/src/auth_none.c b/src/auth_none.c new file mode 100644 index 0000000..c6d5aba --- /dev/null +++ b/src/auth_none.c @@ -0,0 +1,47 @@ +/* ---------------------------------------------------------------- *\ + + file : auth_none.c + author : m. gumz + copyr : copyright (c) 2005 by m. gumz + + license : see LICENSE + + start : Sa 07 Mai 2005 16:41:28 CEST + +\* ---------------------------------------------------------------- */ +/* ---------------------------------------------------------------- *\ + + about : this authmodule does absolutly nothing :) + +\* ---------------------------------------------------------------- */ + +/* ---------------------------------------------------------------- *\ + includes +\* ---------------------------------------------------------------- */ +#include "aklock.h" + +/* ---------------------------------------------------------------- *\ +\* ---------------------------------------------------------------- */ + +static int init(const unsigned char* args) { + return 1; +} + +static int deinit() { + return 1; +} + +static int auth(const unsigned char* passwd) { + return 1; +} + +struct akAuth aklock_auth_none = { + "none", + init, + deinit, + auth +}; + +/* ---------------------------------------------------------------- *\ +\* ---------------------------------------------------------------- */ + diff --git a/src/auth_pam.c b/src/auth_pam.c new file mode 100644 index 0000000..44299b1 --- /dev/null +++ b/src/auth_pam.c @@ -0,0 +1,181 @@ +/* ---------------------------------------------------------------- *\ + + file : auth_pam.c + author : m. gumz + copyr : copyright (c) 2005 by m. gumz + + license : see LICENSE + + start : Sa 07 Mai 2005 16:21:24 CEST + +\* ---------------------------------------------------------------- */ +/* ---------------------------------------------------------------- *\ + + about : + + pam-authentification for aklock + + taken from pure-ftpd's authstuff, but you can see similar stuff + in xlockmore, openssh and basicly all pam-related apps :) + +\* ---------------------------------------------------------------- */ + +/* ---------------------------------------------------------------- *\ + includes +\* ---------------------------------------------------------------- */ + +#include +#include +#include +#include +#include +#include + +#include +#ifdef LINUX +# include +#endif /* LINUX */ + +#include "aklock.h" + +/* ---------------------------------------------------------------- *\ +\* ---------------------------------------------------------------- */ + +#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 +}; + + +/*------------------------------------------------------------------*\ +\*------------------------------------------------------------------*/ + +static struct passwd* pwd_entry = NULL; + + +static int init(const char* args) { + errno = 0; + pwd_entry = getpwuid(getuid()); + if (!pwd_entry) { + perror("password entry for uid not found"); + return 0; + } + + /* we can be installed setuid root to support shadow passwords, + and we don't need root privileges any longer. --marekm */ + setuid(getuid()); + + return 1; +} + +static int deinit() { + + pwd_entry = NULL; + + return 0; +} + +static int auth(const char* pass) { + + pam_handle_t* pam_handle = NULL; + + if (!pass || !pwd_entry) + return 0; + + PAM_username = pwd_entry->pw_name; + PAM_password = pass; + 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; +} + +struct akAuth aklock_auth_pam = { + "pam", + init, + auth, + deinit +}; + +/* ---------------------------------------------------------------- *\ +\* ---------------------------------------------------------------- */ + + diff --git a/src/auth_passwd.c b/src/auth_passwd.c new file mode 100644 index 0000000..5799ade --- /dev/null +++ b/src/auth_passwd.c @@ -0,0 +1,111 @@ +/* ---------------------------------------------------------------- *\ + + file : auth_passwd.c + author : m. gumz + copyr : copyright (c) 2005 by m. gumz + + license : see LICENSE + + start : Sa 07 Mai 2005 16:40:01 CEST + +\* ---------------------------------------------------------------- */ +/* ---------------------------------------------------------------- *\ + + about : + +\* ---------------------------------------------------------------- */ + +/* ---------------------------------------------------------------- *\ + includes +\* ---------------------------------------------------------------- */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef SHADOW_PWD +# include +#endif /* SHADOW_PWD */ + +#include "aklock.h" + +/* ---------------------------------------------------------------- *\ +\* ---------------------------------------------------------------- */ + +static struct passwd* pwd_entry = NULL; + +static int init(const char* args) { + +#ifdef SHADOW_PWD + struct spwd* sp = NULL; +#endif + + errno = 0; + pwd_entry = getpwuid(getuid()); + if (!pwd_entry) { + perror("password entry for uid not found"); + return 0; + } + +#ifdef SHADOW_PWD + sp = getspnam(pwd_entry->pw_name); + if (sp) + pwd_entry->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()); + + if (strlen(pwd_entry->pw_passwd) < 13) { + perror("password entry has no pwd\n"); + return 0; + } + + return 1; +} + +static int deinit() { + return 1; +} + +static int auth(const char* pass) { +#if 0 + char key[3]; + char *encr; + + if (!pass || !pwd_entry) + return 0; + + key[0] = *(pwd_entry->pw_passwd); + key[1] = (pwd_entry->pw_passwd)[1]; + key[2] = 0; + encr = crypt(pass, key); + return !strcmp(encr, pw->pw_passwd); +#else + if (!pass || !pwd_entry) + return 0; + + /* simpler, and should work with crypt() algorithms using longer + salt strings (like the md5-based one on freebsd). --marekm */ + return !strcmp(crypt(pass, pwd_entry->pw_passwd), pwd_entry->pw_passwd); +#endif /* 0 */ +} + +struct akAuth aklock_auth_passwd = { + "passwd", + init, + auth, + deinit +}; + +/* ---------------------------------------------------------------- *\ +\* ---------------------------------------------------------------- */ + +