diff options
Diffstat (limited to 'modules/pam_unix')
-rw-r--r-- | modules/pam_unix/Makefile | 2 | ||||
-rw-r--r-- | modules/pam_unix/md5.c | 158 | ||||
-rw-r--r-- | modules/pam_unix/md5.h | 7 | ||||
-rw-r--r-- | modules/pam_unix/pam_unix.c | 57 |
4 files changed, 167 insertions, 57 deletions
diff --git a/modules/pam_unix/Makefile b/modules/pam_unix/Makefile index 34ed3f0..0b05143 100644 --- a/modules/pam_unix/Makefile +++ b/modules/pam_unix/Makefile @@ -17,7 +17,7 @@ MANMODE = 644 PROJ = $(LIBSHARED) -OBJS = pam_unix.o +OBJS = pam_unix.o md5.o all: case "`uname -s`" in \ diff --git a/modules/pam_unix/md5.c b/modules/pam_unix/md5.c index a9377f1..94d3dd4 100644 --- a/modules/pam_unix/md5.c +++ b/modules/pam_unix/md5.c @@ -17,6 +17,8 @@ #include <sys/types.h> #include <string.h> +#include <stdio.h> +#include <stdlib.h> #include "md5.h" #define PUT_64BIT_LE(cp, value) do { \ @@ -35,6 +37,10 @@ (cp)[1] = (value) >> 8; \ (cp)[0] = (value); } while (0) + +static void to64(char* , long , int ); + + static u_int8_t PADDING[MD5_BLOCK_LENGTH] = { 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, @@ -244,20 +250,158 @@ MD5Transform(u_int32_t state[4], const u_int8_t block[MD5_BLOCK_LENGTH]) state[2] += c; state[3] += d; } + + /* * MD5String: takes a string as an argument and returns the * digest for this string. */ -char * MD5String(const char * string) { +char * MD5Hash(const char * string, const char * salt) { + + int i,j,passl,saltl,pl; + unsigned long l; + MD5_CTX mdContext, mdContext2; + unsigned char digest[16]; + const char *magic = "$1$"; + const char *sp , *tsp; /*sp: salt pointer / tsp : true salt pointer*/ + char * md5hash, *passwd; + + md5hash = (char *) malloc (sizeof(char)*120); + passwd = md5hash; + sp = salt; + + /* skip magic string if it's in salt -- + * this can't happen here, since we create the + * salt without a magic string but someone may use + * this for something else one day */ + if (!strncmp(sp, magic, strlen(magic))) + sp += strlen(magic); + + /* stop salt at '$' or after 8 chars */ + for (tsp = sp; *tsp && *tsp != '$' && tsp < (sp + 8); tsp++) + continue; + /* Define salt and pass length */ + saltl = tsp - sp ; + passl = strlen(string); + + /* Init the condext */ + MD5Init(&mdContext); + /* Update with the password first */ + MD5Update(&mdContext, (unsigned const char *)string, passl); + /* Then use the magic string */ + MD5Update(&mdContext, (unsigned const char *)magic, strlen(magic)); + /* Then use the salt */ + MD5Update(&mdContext, (unsigned const char *)salt, saltl); + + /* Update original using characters from MD5Hash of pwd,salt,pwd */ + MD5Init(&mdContext2); + MD5Update(&mdContext2, (unsigned const char *)string, passl); + MD5Update(&mdContext2, (unsigned const char *)salt, saltl); + MD5Update(&mdContext2, (unsigned const char *)string, passl); + MD5Final (digest, &mdContext2); + + /* Cool, huh? */ + for (pl = passl; pl > 0; pl -= 16) + MD5Update(&mdContext,(unsigned const char *)digest,pl>16 ? 16 : pl); + + /* Don't leave behind sensitive data */ + memset(digest, 0, sizeof digest); + + /* Weird stuff... */ + for (j = 0, i = passl; i; i >>= 1) { + if (i & 1) + MD5Update(&mdContext,(unsigned const char *)digest+j,1); + else + MD5Update(&mdContext,(unsigned const char *)string+j,1); + } + + /* Update hash with magic + salt + $ */ + strcpy(passwd, magic); + strncat(passwd, salt, saltl); + strcat(passwd,"$"); + passwd += strlen(md5hash); + + MD5Final(digest,&mdContext); + + /* Ensure that it can't go too fast (not sure why we need this) */ + for (i = 0; i < 1000; i++) { + MD5Init(&mdContext2); + if (i & 1) + MD5Update(&mdContext2,(unsigned const char *)string,passl); + else + MD5Update(&mdContext2,(unsigned const char *)digest,16); + if (i % 3) + MD5Update(&mdContext2,(unsigned const char *)salt,saltl); + + if (i % 7) + MD5Update(&mdContext2,(unsigned const char *)string,passl); + + if (i & 1) + MD5Update(&mdContext2,(unsigned const char *)digest,16); + else + MD5Update(&mdContext2,(unsigned const char *)string,passl); + + MD5Final(digest,&mdContext2); + + } + + /* Do some binary permutations */ + l = (digest[0] << 16) | (digest[6] << 8) | digest[12]; + to64(passwd, l, 4); + passwd += 4; + l = (digest[1] << 16) | (digest[7] << 8) | digest[13]; + to64(passwd, l, 4); + passwd += 4; + l = (digest[2] << 16) | (digest[8] << 8) | digest[14]; + to64(passwd, l, 4); + passwd += 4; + l = (digest[3] << 16) | (digest[9] << 8) | digest[15]; + to64(passwd, l, 4); + passwd += 4; + l = (digest[4] << 16) | (digest[10] << 8) | digest[5]; + to64(passwd, l, 4); + passwd += 4; + l = digest[11]; + to64(passwd, l, 2); + passwd += 2; + *passwd = '\0'; + + /* Don't leave behind sensitive data */ + memset(digest, 0, sizeof digest); + puts(md5hash); + return (md5hash); +} - MD5_CTX mdContext; - unsigned int length = strlen(string); - MD5Init(&mdContext); - MD5Update(&mdContext, string, length); - MD5Final (&mdContext); - return (mdContext->digest); +/* + * Mostly stolen from freebsd-lib's pam_unix module which was mostly + * stolen from passwd(1)'s local_passwd.c + * + * Good ideas are meant to be reused ;) + */ + +static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */ + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +static void to64(char *s, long v, int n) { + while (--n >= 0) { + *s++ = itoa64[v&0x3f]; + v >>= 6; + } +} +/* Salt suitable for traditional DES and MD5 */ +void makesalt(char salt[SALTSIZE]) { + int i; + /* These are not really random numbers, they are just + * numbers that change to thwart construction of a + * dictionary. This is exposed to the public. + */ + + for (i = 0; i < SALTSIZE; i += 4) + to64(&salt[i], random(), 4); + + salt[SALTSIZE] = '\0'; } diff --git a/modules/pam_unix/md5.h b/modules/pam_unix/md5.h index df431b6..51dcb7b 100644 --- a/modules/pam_unix/md5.h +++ b/modules/pam_unix/md5.h @@ -13,8 +13,9 @@ #ifndef _MD5_H_ #define _MD5_H_ +#define SALTSIZE 32 #define MD5_BLOCK_LENGTH 64 -#define MD5_DIGEST_LENGTH 16 +#define MD5_DIGEST_LENGTH 16 #define MD5_DIGEST_STRING_LENGTH (MD5_DIGEST_LENGTH * 2 + 1) typedef struct MD5Context { @@ -33,5 +34,7 @@ char *MD5End(MD5_CTX *, char *); char *MD5File(const char *, char *); char *MD5FileChunk(const char *, char *, off_t, off_t); char *MD5Data(const u_int8_t *, size_t, char *); -char *MD5String(const char *); +char *MD5Hash(const char *, const char * salt); +void makesalt(char *); + #endif /* _MD5_H_ */ diff --git a/modules/pam_unix/pam_unix.c b/modules/pam_unix/pam_unix.c index e7c058b..fd5d06d 100644 --- a/modules/pam_unix/pam_unix.c +++ b/modules/pam_unix/pam_unix.c @@ -8,20 +8,15 @@ #include <time.h> #include <string.h> #include <shadow.h> - -#ifndef MAXHOSTNAMELEN -# define MAXHOSTNAMELEN 256 -#endif +#include "md5.h" #define PAM_SM_AUTH #define PAM_SM_ACCOUNT #define PAM_SM_PASSWORD #define PAM_SM_SESSION -#define PASSWORD_HASH "md5" #define MAX_RETRIES 3 #define DEFAULT_WARN (2L * 7L * 86400L) /* two weeks */ -#define SALTSIZE 32 #include <security/pam_modules.h> @@ -164,7 +159,6 @@ pam_sm_acct_mgmt(pam_handle_t *pamh, int flags , /* Check for account expiration */ if (pwd->sp_expire > 0) { - fprintf(stdout, "Account expiration data value is %ld\n", pwd->sp_expire); if ( (curtime > pwd->sp_expire ) && ( pwd->sp_expire != -1 ) ) { PAM_ERROR("Account has expired!"); return (PAM_ACCT_EXPIRED); @@ -218,8 +212,6 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char *argv[]) { - fprintf(stdout, "flags :%d\n" , flags); - fprintf(stdout, "flags :0x%x\n" , flags); /* * NIS support will be left for future implementation. * This is standard unix passwd changing function. @@ -341,12 +333,16 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags, !openpam_get_option(pamh, PAM_OPT_NULLOK)) return (PAM_PERM_DENIED); + + makesalt(salt); /* Update shadow/passwd entries for Linux */ - if ( openpam_get_option (pamh, PAM_OPT_MD5) ) - pam_err = update_shadow( pamh ,user, MD5String(new_pass)) ; - else { - makesalt(salt); - pam_err = update_shadow( pamh ,user,crypt(new_pass, salt)); + if ( openpam_get_option (pamh, PAM_OPT_MD5) ) { + pam_err = update_shadow( pamh ,user, + MD5Hash(new_pass, salt)) ; + } else { + + pam_err = update_shadow( pamh ,user, + crypt(new_pass, salt)); } if ( pam_err != PAM_SUCCESS) return (pam_err); @@ -629,37 +625,4 @@ static char * read_shadow(const char * user) { return (pwd->sp_pwdp); } - - -/* - * Mostly stolen from freebsd-lib's pam_unix module which was mostly - * stolen from passwd(1)'s local_passwd.c - * - * Good ideas are meant to be reused ;) - */ - -static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */ - "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - -static void to64(char *s, long v, int n) { - while (--n >= 0) { - *s++ = itoa64[v&0x3f]; - v >>= 6; - } -} - -/* Salt suitable for traditional DES and MD5 */ -void -makesalt(char salt[SALTSIZE]) { - int i; - /* These are not really random numbers, they are just - * numbers that change to thwart construction of a - * dictionary. This is exposed to the public. - */ - - for (i = 0; i < SALTSIZE; i += 4) - to64(&salt[i], random(), 4); - - salt[SALTSIZE] = '\0'; -} PAM_MODULE_ENTRY("pam_unix") |