Friday, February 26, 2010

Step into a fast-moving industry with a Radiology Technician degree

The following set of patches is not strictly related but they are somewhat interdependent. Feel free to ack/nack and comment individually. 0001 Fix the crypt functions. - make them *not* use static buffers, that's just plain wrong - fix indentation where possible - fix naming so that exported functions do not have too generic names that may conflict (name space) 0002 Prevents accepting a blank password - I think we can all agree that allowing blank passwords is not a good idea, however if someone feels strongly about allowing no password logins we should probably make a patch that looks up the individual user record and read an attribute where the specific user is allowed toi use blank passwords (IMHO) 0003 Split ldap backend - mostly so that each single file is easily digestible but also so that in theory you can mix and match (ldap user + krb pwd or local user + ldap pwd, etc...) 0004 Move password caching decision into backends - this is so that backends can have better control (per user caching/other more complex stuff) Simo. -- Simo Sorce * Red Hat, Inc * New York From c010163830365332654a79647929e0458912abee Mon Sep 17 00:00:00 2001 From: Simo Sorce < sso ... @redhat > Date: Fri, 1 May 2009 20:09:44 -0400 Subject: [PATCH 1/4] Fix crypt functions to not use static buffers. Also fix style, clarify, and simplify some logic. --- server/responder/pam/pam_LOCAL_domain.c | 18 +- server/responder/pam/pamsrv_cache.c | 16 +- server/util/nss_sha512crypt.c | 633 +++++++++++++++---------------- server/util/nss_sha512crypt.h | 5 +- 4 files changed, 334 insertions(+), 338 deletions(-) diff --git a/server/responder/pam/pam_LOCAL_domain.c b/server/responder/pam/pam_LOCAL_domain.c index dc394ab..1287c7d 100644 --- a/server/responder/pam/pam_LOCAL_domain.c +++ b/server/responder/pam/pam_LOCAL_domain.c @@ -230,14 +230,14 @@ static void do_pam_chauthtok(struct LOCAL_request *lreq) lreq->error, ret, done); memset(pd->newauthtok, 0, pd->newauthtok_size); - salt = gen_salt(); - NULL_CHECK_OR_JUMP(salt, ("Salt generation failed.\n"), - lreq->error, EFAULT, done); + ret = s3crypt_gen_salt(lreq, &salt); + NEQ_CHECK_OR_JUMP(ret, EOK, ("Salt generation failed.\n"), + lreq->error, ret, done); DEBUG(4, ("Using salt [%s]\n", salt)); - new_hash = nss_sha512_crypt(newauthtok, salt); - NULL_CHECK_OR_JUMP(new_hash, ("Hash generation failed.\n"), - lreq->error, EFAULT, done); + ret = s3crypt_sha512(lreq, newauthtok, salt, &new_hash); + NEQ_CHECK_OR_JUMP(ret, EOK, ("Hash generation failed.\n"), + lreq->error, ret, done); DEBUG(4, ("New hash [%s]\n", new_hash)); memset(newauthtok, 0, pd->newauthtok_size); @@ -323,10 +323,10 @@ static void local_handler_callback(void *pvt, int ldb_status, lreq->error, ret, done); DEBUG(4, ("user: [%s], password hash: [%s]\n", username, password)); - new_hash = nss_sha512_crypt(authtok, password); + ret = s3crypt_sha512(lreq, authtok, password, &new_hash); memset(authtok, 0, pd->authtok_size); - NULL_CHECK_OR_JUMP(new_hash, ("nss_sha512_crypt failed.\n"), - lreq->error, EFAULT, done); + NEQ_CHECK_OR_JUMP(ret, EOK, ("nss_sha512_crypt failed.\n"), + lreq->error, ret, done); DEBUG(4, ("user: [%s], new hash: [%s]\n", username, new_hash)); diff --git a/server/responder/pam/pamsrv_cache.c b/server/responder/pam/pamsrv_cache.c index f98be79..ed18f6a 100644 --- a/server/responder/pam/pamsrv_cache.c +++ b/server/responder/pam/pamsrv_cache.c @@ -122,17 +122,15 @@ int pam_cache_credentials(struct pam_auth_req *preq) goto done; } - salt = gen_salt(); - if (!salt) { + ret = s3crypt_gen_salt(preq, &salt); + if (ret) { DEBUG(4, ("Failed to generate random salt.\n")); - ret = EFAULT; goto done; } - comphash = nss_sha512_crypt(password, salt); - if (!comphash) { + ret = s3crypt_sha512(preq, password, salt, &comphash); + if (ret) { DEBUG(4, ("Failed to create password hash.\n")); - ret = EFAULT; goto done; } @@ -181,7 +179,7 @@ static void pam_cache_auth_callback(void *pvt, int ldb_status, struct pam_auth_req *preq; struct pam_data *pd; const char *userhash; - const char *comphash; + char *comphash; char *password = NULL; int i, ret; @@ -226,8 +224,8 @@ static void pam_cache_auth_callback(void *pvt, int ldb_status, goto done; } - comphash = nss_sha512_crypt(password, userhash); - if (!comphash) { + ret = s3crypt_sha512(preq, password, userhash, &comphash); + if (ret) { DEBUG(4, ("Failed to create password hash.\n")); ret = PAM_SYSTEM_ERR; goto done; diff --git a/server/util/nss_sha512crypt.c b/server/util/nss_sha512crypt.c index cb60610..f02dbef 100644 --- a/server/util/nss_sha512crypt.c +++ b/server/util/nss_sha512crypt.c @@ -20,400 +20,397 @@ #include #include +#include "util/util.h" + #include #include #include #include - static int nspr_nss_init_done = 0; -/* according to - * :// .mozilla /projects/security/pki/nss/ref/ssl/sslfnc.html#1234224 - * PR_Init must be called, but at least for the HASH_* calls it seems to work - * quite well without. */ static int nspr_nss_init(void) { - int ret; - PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); - ret = NSS_NoDB_Init(NULL); - if (ret != SECSuccess) { - return ret; - } - nspr_nss_init_done = 1; - return 0; + int ret; + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + ret = NSS_NoDB_Init(NULL); + if (ret != SECSuccess) { + return ret; + } + nspr_nss_init_done = 1; + return 0; } /* added for completness, so far not used */ static int nspr_nss_cleanup(void) { - int ret; - ret=NSS_Shutdown(); - if (ret != SECSuccess ) { - return ret; - } - PR_Cleanup(); - nspr_nss_init_done = 0; - return 0; + int ret; + ret = NSS_Shutdown(); + if (ret != SECSuccess) { + return ret; + } + PR_Cleanup(); + nspr_nss_init_done = 0; + return 0; } -/* Define our magic string to mark salt for SHA512 "encryption" - replacement. */ -static const char sha512_salt_prefix[] = "$6$"; +/* Define our magic string to mark salt for SHA512 "encryption" replacement. */ +const char sha512_salt_prefix[] = "$6$"; +#define SALT_PREF_SIZE (sizeof(sha512_salt_prefix) - 1) -/* Prefix for optional rounds specification. */ -static const char sha512_rounds_prefix[] = "rounds="; +/* Prefix for optional rounds specification. */ +const char sha512_rounds_prefix[] = "rounds="; +#define ROUNDS_SIZE (sizeof(sha512_rounds_prefix) - 1) -/* Maximum salt string length. */ #define SALT_LEN_MAX 16 -/* Default number of rounds if not explicitly specified. */ #define ROUNDS_DEFAULT 5000 -/* Minimum number of rounds. */ #define ROUNDS_MIN 1000 -/* Maximum number of rounds. */ #define ROUNDS_MAX 999999999 /* Table with characters for base64 transformation. */ -static const char b64t[64] = -"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; +const char b64t[64] = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - -static char * -sha512_crypt_r (const char *key, const char *salt, char *buffer, int buflen) +/* base64 conversion function */ +static inline void b64_from_24bit(char **dest, size_t *len, size_t n, + uint8_t b2, uint8_t b1, uint8_t b0) { - unsigned char alt_result[64] - __attribute__ ((__aligned__ (__alignof__ (uint64_t)))); - unsigned char temp_result[64] - __attribute__ ((__aligned__ (__alignof__ (uint64_t)))); - HASHContext *ctx; - HASHContext *alt_ctx; - size_t salt_len; - size_t key_len; - size_t cnt; - char *cp; - char *copied_key = NULL; - char *copied_salt = NULL; - char *p_bytes; - char *s_bytes; - /* Default number of rounds. */ - size_t rounds = ROUNDS_DEFAULT; - bool rounds_custom = false; - - int ret; - unsigned int part; - - /* Find beginning of salt string. The prefix should normally always - be present. Just in case it is not. */ - if (strncmp (sha512_salt_prefix, salt, sizeof (sha512_salt_prefix) - 1) == 0) - /* Skip salt prefix. */ - salt += sizeof (sha512_salt_prefix) - 1; - - if (strncmp (salt, sha512_rounds_prefix, sizeof (sha512_rounds_prefix) - 1) - == 0) - { - const char *num = salt + sizeof (sha512_rounds_prefix) - 1; - char *endp; - unsigned long int srounds = strtoul (num, &endp, 10); - if (*endp == '$') - { - salt = endp + 1; - rounds = MAX (ROUNDS_MIN, MIN (srounds, ROUNDS_MAX)); - rounds_custom = true; - } + uint32_t w; + size_t i; + + if (*len < n) n = *len; + + w = (b2 << 16) | (b1 << 8) | b0; + for (i = 0; i < n; i++) { + (*dest)[i] = b64t[w & 0x3f]; + w >>= 6; } - salt_len = MIN (strcspn (salt, "$"), SALT_LEN_MAX); - key_len = strlen (key); + *len -= i; + *dest += i; +} + +#define ALIGN64 __alignof__(uint64_t) - if ((key - (char *) 0) % __alignof__ (uint64_t) != 0) - { - char *tmp = (char *) alloca (key_len + __alignof__ (uint64_t)); - key = copied_key = - memcpy (tmp + __alignof__ (uint64_t) - - (tmp - (char *) 0) % __alignof__ (uint64_t), - key, key_len); +static int sha512_crypt_r(const char *key, + const char *salt, + char *buffer, size_t buflen) +{ + unsigned char temp_result[64] __attribute__((__aligned__(ALIGN64))); + unsigned char alt_result[64] __attribute__((__aligned__(ALIGN64))); + size_t rounds = ROUNDS_DEFAULT; + bool rounds_custom = false; + HASHContext *alt_ctx = NULL; + HASHContext *ctx = NULL; + size_t salt_len; + size_t key_len; + size_t cnt; + char *copied_salt = NULL; + char *copied_key = NULL; + char *p_bytes = NULL; + char *s_bytes = NULL; + int p1, p2, p3, pt, n; + unsigned int part; + char *cp, *tmp; + int ret; + + /* Find beginning of salt string. The prefix should normally always be + * present. Just in case it is not. */ + if (strncmp(salt, sha512_salt_prefix, SALT_PREF_SIZE) == 0) { + /* Skip salt prefix. */ + salt += SALT_PREF_SIZE; } - if ((salt - (char *) 0) % __alignof__ (uint64_t) != 0) - { - char *tmp = (char *) alloca (salt_len + __alignof__ (uint64_t)); - salt = copied_salt = - memcpy (tmp + __alignof__ (uint64_t) - - (tmp - (char *) 0) % __alignof__ (uint64_t), - salt, salt_len); + if (strncmp(salt, sha512_rounds_prefix, ROUNDS_SIZE) == 0) { + unsigned long int srounds; + const char *num; + char *endp; + + num = salt + ROUNDS_SIZE; + srounds = strtoul(num, &endp, 10); + if (*endp == '$') { + salt = endp + 1; + if (srounds < ROUNDS_MIN) srounds = ROUNDS_MIN; + if (srounds > ROUNDS_MAX) srounds = ROUNDS_MAX; + rounds = srounds; + rounds_custom = true; + } } + salt_len = MIN(strcspn(salt, "$"), SALT_LEN_MAX); + key_len = strlen(key); - if (!nspr_nss_init_done) { - ret = nspr_nss_init(); - if (ret != SECSuccess) return NULL; - } + if ((((uint64_t)key) % ALIGN64) != 0) { + tmp = (char *)alloca(key_len + ALIGN64); + key = copied_key = memcpy(tmp + ALIGN64 - (((uint64_t)tmp) % ALIGN64), key, key_len); + } - ctx = HASH_Create(HASH_AlgSHA512); - if ( ctx == NULL ) { - return NULL; - } + if (((uint64_t)salt) % ALIGN64 != 0) { + tmp = (char *)alloca(salt_len + ALIGN64); + salt = copied_salt = memcpy(tmp + ALIGN64 - ((uint64_t)tmp) % ALIGN64, salt, salt_len); + } - alt_ctx = HASH_Create(HASH_AlgSHA512); - if ( alt_ctx == NULL ) { - return NULL; - } + if (!nspr_nss_init_done) { + ret = nspr_nss_init(); + if (ret != SECSuccess) { + ret = EIO; + goto done; + } + } + ctx = HASH_Create(HASH_AlgSHA512); + if (!ctx) { + ret = EIO; + goto done; + } - /* Prepare for the real work. */ - HASH_Begin(ctx); + alt_ctx = HASH_Create(HASH_AlgSHA512); + if (!alt_ctx) { + ret = EIO; + goto done; + } - /* Add the key string. */ - HASH_Update(ctx, (const unsigned char *)key, key_len); + /* Prepare for the real work. */ + HASH_Begin(ctx); - /* The last part is the salt string. This must be at most 16 - characters and it ends at the first `$' character (for - compatibility with existing implementations). */ - HASH_Update(ctx, (const unsigned char *)salt, salt_len); + /* Add the key string. */ + HASH_Update(ctx, (const unsigned char *)key, key_len); + /* The last part is the salt string. This must be at most 16 + * characters and it ends at the first `$' character (for + * compatibility with existing implementations). */ + HASH_Update(ctx, (const unsigned char *)salt, salt_len); - /* Compute alternate SHA512 sum with input KEY, SALT, and KEY. The - final result will be added to the first context. */ - HASH_Begin(alt_ctx); - /* Add key. */ - HASH_Update(alt_ctx, (const unsigned char *)key, key_len); + /* Compute alternate SHA512 sum with input KEY, SALT, and KEY. + * The final result will be added to the first context. */ + HASH_Begin(alt_ctx); - /* Add salt. */ - HASH_Update(alt_ctx, (const unsigned char *)salt, salt_len); + /* Add key. */ + HASH_Update(alt_ctx, (const unsigned char *)key, key_len); - /* Add key again. */ - HASH_Update(alt_ctx, (const unsigned char *)key, key_len); + /* Add salt. */ + HASH_Update(alt_ctx, (const unsigned char *)salt, salt_len); - /* Now get result of this (64 bytes) and add it to the other - context. */ - HASH_End(alt_ctx, alt_result, &part, HASH_ResultLenContext(alt_ctx)); + /* Add key again. */ + HASH_Update(alt_ctx, (const unsigned char *)key, key_len); - /* Add for any character in the key one byte of the alternate sum. */ - for (cnt = key_len; cnt > 64; cnt -= 64) { - HASH_Update(ctx, alt_result, 64); - } - HASH_Update(ctx, alt_result, cnt); + /* Now get result of this (64 bytes) and add it to the other context. */ + HASH_End(alt_ctx, alt_result, &part, HASH_ResultLenContext(alt_ctx)); - /* Take the binary representation of the length of the key and for every - 1 add the alternate sum, for every 0 the key. */ - for (cnt = key_len; cnt > 0; cnt >>= 1) - if ((cnt & 1) != 0) { - HASH_Update(ctx, alt_result, 64); - } else { - HASH_Update(ctx, (const unsigned char *)key, key_len); + /* Add for any character in the key one byte of the alternate sum. */ + for (cnt = key_len; cnt > 64; cnt -= 64) { + HASH_Update(ctx, alt_result, 64); + } + HASH_Update(ctx, alt_result, cnt); + + /* Take the binary representation of the length of the key and for every + * 1 add the alternate sum, for every 0 the key. */ + for (cnt = key_len; cnt > 0; cnt >>= 1) { + if ((cnt & 1) != 0) { + HASH_Update(ctx, alt_result, 64); + } else { + HASH_Update(ctx, (const unsigned char *)key, key_len); + } } - /* Create intermediate result. */ - HASH_End(ctx, alt_result, &part, HASH_ResultLenContext(ctx)); - - /* Start computation of P byte sequence. */ - HASH_Begin(alt_ctx); - - /* For every character in the password add the entire password. */ - for (cnt = 0; cnt < key_len; ++cnt) { - HASH_Update(alt_ctx, (const unsigned char *)key, key_len); - } + /* Create intermediate result. */ + HASH_End(ctx, alt_result, &part, HASH_ResultLenContext(ctx)); - /* Finish the digest. */ - HASH_End(alt_ctx, temp_result, &part, HASH_ResultLenContext(alt_ctx)); + /* Start computation of P byte sequence. */ + HASH_Begin(alt_ctx); - /* Create byte sequence P. */ - cp = p_bytes = alloca (key_len); - for (cnt = key_len; cnt >= 64; cnt -= 64) - cp = mempcpy (cp, temp_result, 64); - memcpy (cp, temp_result, cnt); + /* For every character in the password add the entire password. */ + for (cnt = 0; cnt < key_len; cnt++) { + HASH_Update(alt_ctx, (const unsigned char *)key, key_len); + } - /* Start computation of S byte sequence. */ - HASH_Begin(alt_ctx); + /* Finish the digest. */ + HASH_End(alt_ctx, temp_result, &part, HASH_ResultLenContext(alt_ctx)); - /* For every character in the password add the entire password. */ - for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt) { - HASH_Update(alt_ctx, (const unsigned char *)salt, salt_len); - } - - /* Finish the digest. */ - HASH_End(alt_ctx, temp_result, &part, HASH_ResultLenContext(alt_ctx)); - - /* Create byte sequence S. */ - cp = s_bytes = alloca (salt_len); - for (cnt = salt_len; cnt >= 64; cnt -= 64) - cp = mempcpy (cp, temp_result, 64); - memcpy (cp, temp_result, cnt); - - /* Repeatedly run the collected hash value through SHA512 to burn - CPU cycles. */ - for (cnt = 0; cnt < rounds; ++cnt) - { - /* New context. */ - HASH_Begin(ctx); - - /* Add key or last result. */ - if ((cnt & 1) != 0) { - HASH_Update(ctx, (const unsigned char *)p_bytes, key_len); - } else { - HASH_Update(ctx, alt_result, 64); - } + /* Create byte sequence P. */ + cp = p_bytes = alloca(key_len); + for (cnt = key_len; cnt >= 64; cnt -= 64) { + cp = mempcpy(cp, temp_result, 64); + } + memcpy(cp, temp_result, cnt); - /* Add salt for numbers not divisible by 3. */ - if (cnt % 3 != 0) { - HASH_Update(ctx, (const unsigned char *)s_bytes, salt_len); - } + /* Start computation of S byte sequence. */ + HASH_Begin(alt_ctx); - /* Add key for numbers not divisible by 7. */ - if (cnt % 7 != 0) { - HASH_Update(ctx, (const unsigned char *)p_bytes, key_len); - } + /* For every character in the password add the entire salt. */ + for (cnt = 0; cnt < 16 + alt_result[0]; cnt++) { + HASH_Update(alt_ctx, (const unsigned char *)salt, salt_len); + } - /* Add key or last result. */ - if ((cnt & 1) != 0) { - HASH_Update(ctx, alt_result, 64); - } else { - HASH_Update(ctx, (const unsigned char *)p_bytes, key_len); - } + /* Finish the digest. */ + HASH_End(alt_ctx, temp_result, &part, HASH_ResultLenContext(alt_ctx)); - /* Create intermediate result. */ - HASH_End(ctx, alt_result, &part, HASH_ResultLenContext(ctx)); + /* Create byte sequence S. */ + cp = s_bytes = alloca(salt_len); + for (cnt = salt_len; cnt >= 64; cnt -= 64) { + cp = mempcpy(cp, temp_result, 64); } - - /* Now we can construct the result string. It consists of three - parts. */ - cp = __stpncpy (buffer, sha512_salt_prefix, MAX (0, buflen)); - buflen -= sizeof (sha512_salt_prefix) - 1; - - if (rounds_custom) - { - int n = snprintf (cp, MAX (0, buflen), "%s%zu$", - sha512_rounds_prefix, rounds); - cp += n; - buflen -= n; + memcpy(cp, temp_result, cnt); + + /* Repeatedly run the collected hash value through SHA512 to burn CPU cycles. */ + for (cnt = 0; cnt < rounds; cnt++) { + + HASH_Begin(ctx); + + /* Add key or last result. */ + if ((cnt & 1) != 0) { + HASH_Update(ctx, (const unsigned char *)p_bytes, key_len); + } else { + HASH_Update(ctx, alt_result, 64); + } + + /* Add salt for numbers not divisible by 3. */ + if (cnt % 3 != 0) { + HASH_Update(ctx, (const unsigned char *)s_bytes, salt_len); + } + + /* Add key for numbers not divisible by 7. */ + if (cnt % 7 != 0) { + HASH_Update(ctx, (const unsigned char *)p_bytes, key_len); + } + + /* Add key or last result. */ + if ((cnt & 1) != 0) { + HASH_Update(ctx, alt_result, 64); + } else { + HASH_Update(ctx, (const unsigned char *)p_bytes, key_len); + } + + /* Create intermediate result. */ + HASH_End(ctx, alt_result, &part, HASH_ResultLenContext(ctx)); } - cp = __stpncpy (cp, salt, MIN ((size_t) MAX (0, buflen), salt_len)); - buflen -= MIN ((size_t) MAX (0, buflen), salt_len); + /* Now we can construct the result string. + * It consists of three parts. */ + if (buflen <= SALT_PREF_SIZE) { + ret = ERANGE; + goto done; + } - if (buflen > 0) - { - *cp++ = '$'; - --buflen; + cp = __stpncpy(buffer, sha512_salt_prefix, SALT_PREF_SIZE); + buflen -= SALT_PREF_SIZE; + + if (rounds_custom) { + n = snprintf(cp, buflen, "%s%zu$", + sha512_rounds_prefix, rounds); + if (n < 0 || n >= buflen) { + ret = ERANGE; + goto done; + } + cp += n; + buflen -= n; } -#define b64_from_24bit(B2, B1, B0, N) \ - do { \ - unsigned int w = ((B2) << 16) | ((B1) << 8) | (B0); \ - int n = (N); \ - while (n-- > 0 && buflen > 0) \ - { \ - *cp++ = b64t[w & 0x3f]; \ - --buflen; \ - w >>= 6; \ - } \ - } while (0) - - b64_from_24bit (alt_result[0], alt_result[21], alt_result[42], 4); - b64_from_24bit (alt_result[22], alt_result[43], alt_result[1], 4); - b64_from_24bit (alt_result[44], alt_result[2], alt_result[23], 4); - b64_from_24bit (alt_result[3], alt_result[24], alt_result[45], 4); - b64_from_24bit (alt_result[25], alt_result[46], alt_result[4], 4); - b64_from_24bit (alt_result[47], alt_result[5], alt_result[26], 4); - b64_from_24bit (alt_result[6], alt_result[27], alt_result[48], 4); - b64_from_24bit (alt_result[28], alt_result[49], alt_result[7], 4); - b64_from_24bit (alt_result[50], alt_result[8], alt_result[29], 4); - b64_from_24bit (alt_result[9], alt_result[30], alt_result[51], 4); - b64_from_24bit (alt_result[31], alt_result[52], alt_result[10], 4); - b64_from_24bit (alt_result[53], alt_result[11], alt_result[32], 4); - b64_from_24bit (alt_result[12], alt_result[33], alt_result[54], 4); - b64_from_24bit (alt_result[34], alt_result[55], alt_result[13], 4); - b64_from_24bit (alt_result[56], alt_result[14], alt_result[35], 4); - b64_from_24bit (alt_result[15], alt_result[36], alt_result[57], 4); - b64_from_24bit (alt_result[37], alt_result[58], alt_result[16], 4); - b64_from_24bit (alt_result[59], alt_result[17], alt_result[38], 4); - b64_from_24bit (alt_result[18], alt_result[39], alt_result[60], 4); - b64_from_24bit (alt_result[40], alt_result[61], alt_result[19], 4); - b64_from_24bit (alt_result[62], alt_result[20], alt_result[41], 4); - b64_from_24bit (0, 0, alt_result[63], 2); - - if (buflen <= 0) - { - errno = ERANGE; - buffer = NULL; + if (buflen <= salt_len + 1) { + ret = ERANGE; + goto done; } - else - *cp = '\0'; /* Terminate the string. */ - - /* Clear the buffer for the intermediate result so that people - attaching to processes or reading core dumps cannot get any - information. We do it in this way to clear correct_words[] - inside the SHA512 implementation as well. */ - HASH_Destroy(ctx); - HASH_Destroy(alt_ctx); - - memset (temp_result, '\0', sizeof (temp_result)); - memset (p_bytes, '\0', key_len); - memset (s_bytes, '\0', salt_len); - memset (&ctx, '\0', sizeof (ctx)); - memset (&alt_ctx, '\0', sizeof (alt_ctx)); - if (copied_key != NULL) - memset (copied_key, '\0', key_len); - if (copied_salt != NULL) - memset (copied_salt, '\0', salt_len); - - return buffer; -} + cp = __stpncpy(cp, salt, salt_len); + *cp++ = '$'; + buflen -= salt_len + 1; + + /* fuzzyfill the base 64 string */ + p1 = 0; + p2 = 21; + p3 = 42; + for (n = 0; n < 21; n++) { + b64_from_24bit(&cp, &buflen, 4, alt_result[p1], alt_result[p2], alt_result[p3]); + if (buflen == 0) { + ret = ERANGE; + goto done; + } + pt = p1; + p1 = p2 + 1; + p2 = p3 + 1; + p3 = pt + 1; + } + /* 64th and last byte */ + b64_from_24bit(&cp, &buflen, 2, 0, 0, alt_result[p3]); + if (buflen == 0) { + ret = ERANGE; + goto done; + } + + *cp = '\0'; + ret = EOK; + +done: + /* Clear the buffer for the intermediate result so that people attaching + * to processes or reading core dumps cannot get any information. We do it + * in this way to clear correct_words[] inside the SHA512 implementation + * as well. */ + if (ctx) HASH_Destroy(ctx); + if (alt_ctx) HASH_Destroy(alt_ctx); + if (p_bytes) memset(p_bytes, '\0', key_len); + if (s_bytes) memset(s_bytes, '\0', salt_len); + if (copied_key) memset(copied_key, '\0', key_len); + if (copied_salt) memset(copied_salt, '\0', salt_len); + memset(temp_result, '\0', sizeof(temp_result)); + return ret; +} -/* This entry point is equivalent to the `crypt' function in Unix - libcs. */ -char * -nss_sha512_crypt (const char *key, const char *salt) +int s3crypt_sha512(TALLOC_CTX *memctx, + const char *key, const char *salt, char **_hash) { - /* We don't want to have an arbitrary limit in the size of the - password. We can compute an upper bound for the size of the - result in advance and so we can prepare the buffer we pass to - `sha512_crypt_r'. */ - static char *buffer; - static int buflen; - int needed = (sizeof (sha512_salt_prefix) - 1 - + sizeof (sha512_rounds_prefix) + 9 + 1 - + strlen (salt) + 1 + 86 + 1); - - if (buflen < needed) - { - char *new_buffer = (char *) realloc (buffer, needed); - if (new_buffer == NULL) - return NULL; - - buffer = new_buffer; - buflen = needed; - } + char *hash; + int hlen = (sizeof (sha512_salt_prefix) - 1 + + sizeof (sha512_rounds_prefix) + 9 + 1 + + strlen (salt) + 1 + 86 + 1); + int ret; + + hash = talloc_size(memctx, hlen); + if (!hash) return ENOMEM; - return sha512_crypt_r (key, salt, buffer, buflen); + ret = sha512_crypt_r(key, salt, hash, hlen); + if (ret) return ret; + + *_hash = hash; + return ret; } -char *gen_salt(void) +#define SALT_RAND_LEN 12 + +int s3crypt_gen_salt(TALLOC_CTX *memctx, char **_salt) { - int ret; - unsigned char bin_rand[12]; - static char b64_rand[17]; - char *cp; - int buflen; + uint8_t rb[SALT_RAND_LEN]; + char *salt, *cp; + size_t slen; + int ret; + + if (!nspr_nss_init_done) { + ret = nspr_nss_init(); + if (ret != SECSuccess) { + return EIO; + } + } - if (!nspr_nss_init_done) { - ret = nspr_nss_init(); - if (ret != SECSuccess) return NULL; - } + salt = talloc_size(memctx, SALT_LEN_MAX + 1); + if (!salt) { + return ENOMEM; + } - ret = PK11_GenerateRandom(bin_rand, sizeof(bin_rand)-1); - cp = b64_rand; - buflen = 16; - b64_from_24bit (bin_rand[0], bin_rand[1], bin_rand[2], 4); - b64_from_24bit (bin_rand[3], bin_rand[4], bin_rand[5], 4); - b64_from_24bit (bin_rand[6], bin_rand[7], bin_rand[8], 4); - b64_from_24bit (bin_rand[9], bin_rand[10], bin_rand[11], 4); + ret = PK11_GenerateRandom(rb, SALT_RAND_LEN); + if (ret != SECSuccess) { + return EIO; + } - *cp++ = '\0'; + slen = SALT_LEN_MAX; + cp = salt; + b64_from_24bit(&cp, &slen, 4, rb[0], rb[1], rb[2]); + b64_from_24bit(&cp, &slen, 4, rb[3], rb[4], rb[5]); + b64_from_24bit(&cp, &slen, 4, rb[6], rb[7], rb[8]); + b64_from_24bit(&cp, &slen, 4, rb[9], rb[10], rb[11]); + *cp = '\0'; - return b64_rand; + *_salt = salt; + return EOK; } diff --git a/server/util/nss_sha512crypt.h b/server/util/nss_sha512crypt.h index 0d06321..5512c5d 100644 --- a/server/util/nss_sha512crypt.h +++ b/server/util/nss_sha512crypt.h @@ -1,3 +1,4 @@ -char * nss_sha512_crypt (const char *key, const char *salt); -char *gen_salt(void); +int s3crypt_sha512(TALLOC_CTX *mmectx, + const char *key, const char *salt, char **_hash); +int s3crypt_gen_salt(TALLOC_CTX *memctx, char **_salt); -- 1.6.2.2 From aeffcf788e2b87946cff7f71ac21033272a72ad6 Mon Sep 17 00:00:00 2001 From: Simo Sorce < sso ... @redhat > Date: Wed, 6 May 2009 18:12:26 -0400 Subject: [PATCH 2/4] Prevent accepting blank passwords --- server/responder/pam/pam_LOCAL_domain.c | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/server/responder/pam/pam_LOCAL_domain.c b/server/responder/pam/pam_LOCAL_domain.c index 1287c7d..614d640 100644 --- a/server/responder/pam/pam_LOCAL_domain.c +++ b/server/responder/pam/pam_LOCAL_domain.c @@ -230,6 +230,13 @@ static void do_pam_chauthtok(struct LOCAL_request *lreq) lreq->error, ret, done); memset(pd->newauthtok, 0, pd->newauthtok_size); + if (strlen(newauthtok) == 0) { + /* TODO: should we allow null passwords via a config option ? */ + DEBUG(1, ("Empty passwords are not allowed!")); + ret = EINVAL; + goto done; + } + ret = s3crypt_gen_salt(lreq, &salt); NEQ_CHECK_OR_JUMP(ret, EOK, ("Salt generation failed.\n"), lreq->error, ret, done); -- 1.6.2.2 From 770fd235cb96c0c782279ae9c6836003a767354c Mon Sep 17 00:00:00 2001 From: Simo Sorce < sso ... @redhat > Date: Fri, 10 Apr 2009 17:33:30 -0400 Subject: [PATCH 3/4] Split ldap backend into auth and identity files --- server/providers/ldap/ldap_auth.c | 705 +++++++++++++++++++++++++++++++++ server/providers/ldap/ldap_id.c | 786 +++++++++++++++++++++++++++++++++++++ server/providers/ldap_be.c | 773 ------------------------------------ server/server.mk | 3 +- 4 files changed, 1493 insertions(+), 774 deletions(-) create mode 100644 server/providers/ldap/ldap_auth.c create mode 100644 server/providers/ldap/ldap_id.c delete mode 100644 server/providers/ldap_be.c diff --git a/server/providers/ldap/ldap_auth.c b/server/providers/ldap/ldap_auth.c new file mode 100644 index 0000000..18b39d8 --- /dev/null +++ b/server/providers/ldap/ldap_auth.c @@ -0,0 +1,705 @@ +/* + SSSD + + LDAP Backend Module + + Authors: + Sumit Bose < sbo ... @redhat > + + Copyright (C) 2008 Red Hat + + This program 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 3 of the License, or + (at your option) any later version. + + 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. + + You should have received a copy of the GNU General Public License + along with this program. If not, see < :// .gnu /licenses/ >. +*/ + +#ifdef WITH_MOZLDAP +#define LDAP_OPT_SUCCESS LDAP_SUCCESS +#define LDAP_TAG_EXOP_MODIFY_PASSWD_ID ((ber_tag_t) 0x80U) +#define LDAP_TAG_EXOP_MODIFY_PASSWD_OLD ((ber_tag_t) 0x81U) +#define LDAP_TAG_EXOP_MODIFY_PASSWD_NEW ((ber_tag_t) 0x82U) + <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'> <span class='post-author vcard'> <span class='fn' itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://www.blogger.com/profile/02122685172386752211' itemprop='url'/> <a href='https://www.blogger.com/profile/02122685172386752211' rel='author' title='author profile'> <span itemprop='name'>Cadet Boardash</span> </a> </span> </span> <span class='post-timestamp'> at <meta content='http://boardash.blogspot.com/2010/02/step-into-fast-moving-industry-with.html' itemprop='url'/> <a class='timestamp-link' href='https://boardash.blogspot.com/2010/02/step-into-fast-moving-industry-with.html?m=1' rel='bookmark' title='permanent link'><abbr class='published' itemprop='datePublished' title='2010-02-26T15:43:00-08:00'>3:43 PM</abbr></a> </span> <span class='post-comment-link'> </span> </div> <div class='post-footer-line post-footer-line-2'> </div> </div> </div> <div class='comments' id='comments'> <a name='comments'></a> </div> </div> </div> </div> </div> <div class='blog-pager' id='blog-pager'> <div class='mobile-link-button' id='blog-pager-newer-link'> <a class='blog-pager-newer-link' href='https://boardash.blogspot.com/2010/02/arbcombo-greenhouse-gas-and-mandatory.html?m=1' id='Blog1_blog-pager-newer-link' title='Newer Post'>‹</a> </div> <div class='mobile-link-button' id='blog-pager-older-link'> <a class='blog-pager-older-link' href='https://boardash.blogspot.com/2010/02/reading-to-english-speaking-kids-must.html?m=1' id='Blog1_blog-pager-older-link' title='Older Post'>›</a> </div> <div class='mobile-link-button' id='blog-pager-home-link'> <a class='home-link' href='https://boardash.blogspot.com/?m=1'>Home</a> </div> <div class='mobile-desktop-link'> <a class='home-link' href='https://boardash.blogspot.com/2010/02/step-into-fast-moving-industry-with.html?m=0'>View web version</a> </div> </div> <div class='clear'></div> </div></div> </div> </div> <div class='column-left-outer'> <div class='column-left-inner'> <aside> </aside> </div> </div> <div class='column-right-outer'> <div class='column-right-inner'> <aside> </aside> </div> </div> </div> <div style='clear: both'></div> <!-- columns --> </div> <!-- main --> </div> </div> <div class='main-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> <footer> <div class='footer-outer'> <div class='footer-cap-top cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left footer-fauxborder-left'> <div class='fauxborder-right footer-fauxborder-right'></div> <div class='region-inner footer-inner'> <div class='foot no-items section' id='footer-1'></div> <!-- outside of the include in order to lock Attribution widget --> <div class='foot section' id='footer-3' name='Footer'><div class='widget Profile' data-version='1' id='Profile1'> <h2>About Me</h2> <div class='widget-content'> <dl class='profile-datablock'> <dt class='profile-data'> <a class='profile-name-link g-profile' href='https://www.blogger.com/profile/02122685172386752211' rel='author' style='background-image: url(//www.blogger.com/img/logo-16.png);'> Cadet Boardash </a> </dt> </dl> <a class='profile-link' href='https://www.blogger.com/profile/02122685172386752211' rel='author'>View my complete profile</a> <div class='clear'></div> </div> </div><div class='widget Attribution' data-version='1' id='Attribution1'> <div class='widget-content' style='text-align: center;'> Powered by <a href='https://www.blogger.com' target='_blank'>Blogger</a>. </div> <div class='clear'></div> </div></div> </div> </div> <div class='footer-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> </footer> <!-- content --> </div> </div> <div class='content-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> </div> <script type='text/javascript'> window.setTimeout(function() { document.body.className = document.body.className.replace('loading', ''); }, 10); </script> <script type="text/javascript" src="https://www.blogger.com/static/v1/widgets/382300504-widgets.js"></script> <script type='text/javascript'> var BLOG_BASE_IMAGE_URL = 'https://resources.blogblog.com/img';var BLOG_LANG_DIR = 'ltr';window['__wavt'] = 'AOuZoY6NamBVdguLbiv1PTnXpOaRvI7lZw:1765911746600';_WidgetManager._Init('//www.blogger.com/rearrange?blogID\x3d294348864327444061','//boardash.blogspot.com/2010/02/step-into-fast-moving-industry-with.html?m\x3d1','294348864327444061'); _WidgetManager._SetDataContext([{'name': 'blog', 'data': {'blogId': '294348864327444061', 'title': 'Boardash', 'url': 'https://boardash.blogspot.com/2010/02/step-into-fast-moving-industry-with.html?m\x3d1', 'canonicalUrl': 'http://boardash.blogspot.com/2010/02/step-into-fast-moving-industry-with.html', 'homepageUrl': 'https://boardash.blogspot.com/?m\x3d1', 'searchUrl': 'https://boardash.blogspot.com/search', 'canonicalHomepageUrl': 'http://boardash.blogspot.com/', 'blogspotFaviconUrl': 'https://boardash.blogspot.com/favicon.ico', 'bloggerUrl': 'https://www.blogger.com', 'hasCustomDomain': false, 'httpsEnabled': true, 'enabledCommentProfileImages': true, 'gPlusViewType': 'FILTERED_POSTMOD', 'adultContent': false, 'analyticsAccountNumber': '', 'encoding': 'UTF-8', 'locale': 'en', 'localeUnderscoreDelimited': 'en', 'languageDirection': 'ltr', 'isPrivate': false, 'isMobile': true, 'isMobileRequest': true, 'mobileClass': ' mobile', 'isPrivateBlog': false, 'isDynamicViewsAvailable': true, 'feedLinks': '\x3clink rel\x3d\x22alternate\x22 type\x3d\x22application/atom+xml\x22 title\x3d\x22Boardash - Atom\x22 href\x3d\x22https://boardash.blogspot.com/feeds/posts/default\x22 /\x3e\n\x3clink rel\x3d\x22alternate\x22 type\x3d\x22application/rss+xml\x22 title\x3d\x22Boardash - RSS\x22 href\x3d\x22https://boardash.blogspot.com/feeds/posts/default?alt\x3drss\x22 /\x3e\n\x3clink rel\x3d\x22service.post\x22 type\x3d\x22application/atom+xml\x22 title\x3d\x22Boardash - Atom\x22 href\x3d\x22https://www.blogger.com/feeds/294348864327444061/posts/default\x22 /\x3e\n\n\x3clink rel\x3d\x22alternate\x22 type\x3d\x22application/atom+xml\x22 title\x3d\x22Boardash - Atom\x22 href\x3d\x22https://boardash.blogspot.com/feeds/4634540108722859727/comments/default\x22 /\x3e\n', 'meTag': '', 'adsenseHostId': 'ca-host-pub-1556223355139109', 'adsenseHasAds': false, 'adsenseAutoAds': false, 'boqCommentIframeForm': true, 'loginRedirectParam': '', 'view': '', 'dynamicViewsCommentsSrc': '//www.blogblog.com/dynamicviews/4224c15c4e7c9321/js/comments.js', 'dynamicViewsScriptSrc': '//www.blogblog.com/dynamicviews/91113183d353c15a', 'plusOneApiSrc': 'https://apis.google.com/js/platform.js', 'disableGComments': true, 'interstitialAccepted': false, 'sharing': {'platforms': [{'name': 'Get link', 'key': 'link', 'shareMessage': 'Get link', 'target': ''}, {'name': 'Facebook', 'key': 'facebook', 'shareMessage': 'Share to Facebook', 'target': 'facebook'}, {'name': 'BlogThis!', 'key': 'blogThis', 'shareMessage': 'BlogThis!', 'target': 'blog'}, {'name': 'X', 'key': 'twitter', 'shareMessage': 'Share to X', 'target': 'twitter'}, {'name': 'Pinterest', 'key': 'pinterest', 'shareMessage': 'Share to Pinterest', 'target': 'pinterest'}, {'name': 'Email', 'key': 'email', 'shareMessage': 'Email', 'target': 'email'}], 'disableGooglePlus': true, 'googlePlusShareButtonWidth': 0, 'googlePlusBootstrap': '\x3cscript type\x3d\x22text/javascript\x22\x3ewindow.___gcfg \x3d {\x27lang\x27: \x27en\x27};\x3c/script\x3e'}, 'hasCustomJumpLinkMessage': false, 'jumpLinkMessage': 'Read more', 'pageType': 'item', 'postId': '4634540108722859727', 'pageName': 'Step into a fast-moving industry with a Radiology Technician degree', 'pageTitle': 'Boardash: Step into a fast-moving industry with a Radiology Technician degree'}}, {'name': 'features', 'data': {}}, {'name': 'messages', 'data': {'edit': 'Edit', 'linkCopiedToClipboard': 'Link copied to clipboard!', 'ok': 'Ok', 'postLink': 'Post Link'}}, {'name': 'template', 'data': {'name': 'Simple', 'localizedName': 'Simple', 'isResponsive': false, 'isAlternateRendering': true, 'isCustom': false, 'variant': 'simplysimple', 'variantId': 'simplysimple'}}, {'name': 'view', 'data': {'classic': {'name': 'classic', 'url': '?view\x3dclassic'}, 'flipcard': {'name': 'flipcard', 'url': '?view\x3dflipcard'}, 'magazine': {'name': 'magazine', 'url': '?view\x3dmagazine'}, 'mosaic': {'name': 'mosaic', 'url': '?view\x3dmosaic'}, 'sidebar': {'name': 'sidebar', 'url': '?view\x3dsidebar'}, 'snapshot': {'name': 'snapshot', 'url': '?view\x3dsnapshot'}, 'timeslide': {'name': 'timeslide', 'url': '?view\x3dtimeslide'}, 'isMobile': true, 'title': 'Step into a fast-moving industry with a Radiology Technician degree', 'description': ' The following set of patches is not strictly related but they are somewhat interdependent. Feel free to ack/nack and comment individu...', 'url': 'https://boardash.blogspot.com/2010/02/step-into-fast-moving-industry-with.html?m\x3d1', 'type': 'item', 'isSingleItem': true, 'isMultipleItems': false, 'isError': false, 'isPage': false, 'isPost': true, 'isHomepage': false, 'isArchive': false, 'isLabelSearch': false, 'postId': 4634540108722859727}}]); _WidgetManager._RegisterWidget('_HeaderView', new _WidgetInfo('Header1', 'header', document.getElementById('Header1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_BlogView', new _WidgetInfo('Blog1', 'main', document.getElementById('Blog1'), {'cmtInteractionsEnabled': false, 'mobile': true}, 'displayModeFull')); _WidgetManager._RegisterWidget('_ProfileView', new _WidgetInfo('Profile1', 'footer-3', document.getElementById('Profile1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_AttributionView', new _WidgetInfo('Attribution1', 'footer-3', document.getElementById('Attribution1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_NavbarView', new _WidgetInfo('Navbar1', 'navbar', document.getElementById('Navbar1'), {}, 'displayModeFull')); </script> </body> </html>