/* Copy no more than N characters of SRC to DEST, returning the address of the terminating '\0' in DEST, if any, or else DEST + N. */ char * __stpncpy_chk (char *dest, const char *src, size_t n, size_t destlen) { if (__builtin_expect (destlen < n, 0)) __chk_fail (); return __stpncpy (dest, src, n); }
static int internal_function attribute_compat_text_section getttyname_r (char *buf, size_t buflen, dev_t mydev, ino64_t myino, int save, int *dostat) { struct stat64 st; DIR *dirstream; struct dirent64 *d; size_t devlen = strlen (buf); dirstream = __opendir (buf); if (dirstream == NULL) { *dostat = -1; return errno; } while ((d = __readdir64 (dirstream)) != NULL) if ((d->d_fileno == myino || *dostat) && strcmp (d->d_name, "stdin") && strcmp (d->d_name, "stdout") && strcmp (d->d_name, "stderr")) { char *cp; size_t needed = _D_EXACT_NAMLEN (d) + 1; if (needed > buflen) { *dostat = -1; (void) __closedir (dirstream); __set_errno (ERANGE); return ERANGE; } cp = __stpncpy (buf + devlen, d->d_name, needed); cp[0] = '\0'; if (__xstat64 (_STAT_VER, buf, &st) == 0 #ifdef _STATBUF_ST_RDEV && S_ISCHR (st.st_mode) && st.st_rdev == mydev #else && d->d_fileno == myino && st.st_dev == mydev #endif ) { (void) __closedir (dirstream); __set_errno (save); return 0; } } (void) __closedir (dirstream); __set_errno (save); /* It is not clear what to return in this case. `isatty' says FD refers to a TTY but no entry in /dev has this inode. */ return ENOTTY; }
static int _nss_nisplus_parse_etherent (nis_result *result, struct etherent *ether, char *buffer, size_t buflen, int *errnop) { char *p = buffer; size_t room_left = buflen; if (result == NULL) return 0; if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) || NIS_RES_NUMOBJ (result) != 1 || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ || strcmp (NIS_RES_OBJECT (result)->EN_data.en_type, "ethers_tbl") != 0 || NIS_RES_OBJECT (result)->EN_data.en_cols.en_cols_len < 2) return 0; /* Generate the ether entry format and use the normal parser */ if (NISENTRYLEN (0, 0, result) + 1 > room_left) { *errnop = ERANGE; return -1; } char *cp = __stpncpy (p, NISENTRYVAL (0, 0, result), NISENTRYLEN (0, 0, result)); *cp = '\0'; room_left -= NISENTRYLEN (0, 0, result) + 1; ether->e_name = p; struct ether_addr *ea = ether_aton (NISENTRYVAL (0, 1, result)); if (ea == NULL) { *errnop = EINVAL; return -2; } ether->e_addr = *ea; return 1; }
kern_return_t _S_msg_describe_ports (mach_port_t msgport, mach_port_t refport, mach_port_t *ports, mach_msg_type_number_t nports, char **desc, mach_msg_type_number_t *desclen) { char *p, *end; if (__USEPORT (AUTH, msgport != port)) return EPERM; end = *desc + *desclen; p = *desc; while (nports-- > 0) { char this[200]; describe_port (this, *ports++); p = __stpncpy (p, this, end - p); if (p == end && p[-1] != '\0') return ENOMEM; } *desclen = p - *desc; return 0; }
char * __sha512_crypt_r (const char *key, const char *salt, char *buffer, int buflen) { unsigned char alt_result[64] __attribute__ ((__aligned__ (__alignof__ (uint64_t)))); unsigned char temp_result[64] __attribute__ ((__aligned__ (__alignof__ (uint64_t)))); 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; size_t alloca_used = 0; char *free_key = NULL; char *free_pbytes = NULL; /* 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; } } salt_len = MIN (strcspn (salt, "$"), SALT_LEN_MAX); key_len = strlen (key); if ((key - (char *) 0) % __alignof__ (uint64_t) != 0) { char *tmp; if (__libc_use_alloca (alloca_used + key_len + __alignof__ (uint64_t))) tmp = alloca_account (key_len + __alignof__ (uint64_t), alloca_used); else { free_key = tmp = (char *) malloc (key_len + __alignof__ (uint64_t)); if (tmp == NULL) return NULL; } key = copied_key = memcpy (tmp + __alignof__ (uint64_t) - (tmp - (char *) 0) % __alignof__ (uint64_t), key, key_len); assert ((key - (char *) 0) % __alignof__ (uint64_t) == 0); } 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); assert ((salt - (char *) 0) % __alignof__ (uint64_t) == 0); } #ifdef USE_NSS /* Initialize libfreebl3. */ NSSLOWInitContext *nss_ictx = NSSLOW_Init (); if (nss_ictx == NULL) { free (free_key); return NULL; } NSSLOWHASHContext *nss_ctx = NULL; NSSLOWHASHContext *nss_alt_ctx = NULL; #else struct sha512_ctx ctx; struct sha512_ctx alt_ctx; #endif /* Prepare for the real work. */ sha512_init_ctx (&ctx, nss_ctx); /* Add the key string. */ sha512_process_bytes (key, key_len, &ctx, nss_ctx); /* The last part is the salt string. This must be at most 16 characters and it ends at the first `$' character. */ sha512_process_bytes (salt, salt_len, &ctx, nss_ctx); /* Compute alternate SHA512 sum with input KEY, SALT, and KEY. The final result will be added to the first context. */ sha512_init_ctx (&alt_ctx, nss_alt_ctx); /* Add key. */ sha512_process_bytes (key, key_len, &alt_ctx, nss_alt_ctx); /* Add salt. */ sha512_process_bytes (salt, salt_len, &alt_ctx, nss_alt_ctx); /* Add key again. */ sha512_process_bytes (key, key_len, &alt_ctx, nss_alt_ctx); /* Now get result of this (64 bytes) and add it to the other context. */ sha512_finish_ctx (&alt_ctx, nss_alt_ctx, alt_result); /* Add for any character in the key one byte of the alternate sum. */ for (cnt = key_len; cnt > 64; cnt -= 64) sha512_process_bytes (alt_result, 64, &ctx, nss_ctx); sha512_process_bytes (alt_result, cnt, &ctx, nss_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) sha512_process_bytes (alt_result, 64, &ctx, nss_ctx); else sha512_process_bytes (key, key_len, &ctx, nss_ctx); /* Create intermediate result. */ sha512_finish_ctx (&ctx, nss_ctx, alt_result); /* Start computation of P byte sequence. */ sha512_init_ctx (&alt_ctx, nss_alt_ctx); /* For every character in the password add the entire password. */ for (cnt = 0; cnt < key_len; ++cnt) sha512_process_bytes (key, key_len, &alt_ctx, nss_alt_ctx); /* Finish the digest. */ sha512_finish_ctx (&alt_ctx, nss_alt_ctx, temp_result); /* Create byte sequence P. */ if (__libc_use_alloca (alloca_used + key_len)) cp = p_bytes = (char *) alloca (key_len); else { free_pbytes = cp = p_bytes = (char *)malloc (key_len); if (free_pbytes == NULL) { free (free_key); return NULL; } } for (cnt = key_len; cnt >= 64; cnt -= 64) cp = mempcpy (cp, temp_result, 64); memcpy (cp, temp_result, cnt); /* Start computation of S byte sequence. */ sha512_init_ctx (&alt_ctx, nss_alt_ctx); /* For every character in the password add the entire password. */ for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt) sha512_process_bytes (salt, salt_len, &alt_ctx, nss_alt_ctx); /* Finish the digest. */ sha512_finish_ctx (&alt_ctx, nss_alt_ctx, temp_result); /* 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. */ sha512_init_ctx (&ctx, nss_ctx); /* Add key or last result. */ if ((cnt & 1) != 0) sha512_process_bytes (p_bytes, key_len, &ctx, nss_ctx); else sha512_process_bytes (alt_result, 64, &ctx, nss_ctx); /* Add salt for numbers not divisible by 3. */ if (cnt % 3 != 0) sha512_process_bytes (s_bytes, salt_len, &ctx, nss_ctx); /* Add key for numbers not divisible by 7. */ if (cnt % 7 != 0) sha512_process_bytes (p_bytes, key_len, &ctx, nss_ctx); /* Add key or last result. */ if ((cnt & 1) != 0) sha512_process_bytes (alt_result, 64, &ctx, nss_ctx); else sha512_process_bytes (p_bytes, key_len, &ctx, nss_ctx); /* Create intermediate result. */ sha512_finish_ctx (&ctx, nss_ctx, alt_result); } #ifdef USE_NSS /* Free libfreebl3 resources. */ NSSLOW_Shutdown (nss_ictx); #endif /* 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; } cp = __stpncpy (cp, salt, MIN ((size_t) MAX (0, buflen), salt_len)); buflen -= MIN ((size_t) MAX (0, buflen), salt_len); if (buflen > 0) { *cp++ = '$'; --buflen; } __b64_from_24bit (&cp, &buflen, alt_result[0], alt_result[21], alt_result[42], 4); __b64_from_24bit (&cp, &buflen, alt_result[22], alt_result[43], alt_result[1], 4); __b64_from_24bit (&cp, &buflen, alt_result[44], alt_result[2], alt_result[23], 4); __b64_from_24bit (&cp, &buflen, alt_result[3], alt_result[24], alt_result[45], 4); __b64_from_24bit (&cp, &buflen, alt_result[25], alt_result[46], alt_result[4], 4); __b64_from_24bit (&cp, &buflen, alt_result[47], alt_result[5], alt_result[26], 4); __b64_from_24bit (&cp, &buflen, alt_result[6], alt_result[27], alt_result[48], 4); __b64_from_24bit (&cp, &buflen, alt_result[28], alt_result[49], alt_result[7], 4); __b64_from_24bit (&cp, &buflen, alt_result[50], alt_result[8], alt_result[29], 4); __b64_from_24bit (&cp, &buflen, alt_result[9], alt_result[30], alt_result[51], 4); __b64_from_24bit (&cp, &buflen, alt_result[31], alt_result[52], alt_result[10], 4); __b64_from_24bit (&cp, &buflen, alt_result[53], alt_result[11], alt_result[32], 4); __b64_from_24bit (&cp, &buflen, alt_result[12], alt_result[33], alt_result[54], 4); __b64_from_24bit (&cp, &buflen, alt_result[34], alt_result[55], alt_result[13], 4); __b64_from_24bit (&cp, &buflen, alt_result[56], alt_result[14], alt_result[35], 4); __b64_from_24bit (&cp, &buflen, alt_result[15], alt_result[36], alt_result[57], 4); __b64_from_24bit (&cp, &buflen, alt_result[37], alt_result[58], alt_result[16], 4); __b64_from_24bit (&cp, &buflen, alt_result[59], alt_result[17], alt_result[38], 4); __b64_from_24bit (&cp, &buflen, alt_result[18], alt_result[39], alt_result[60], 4); __b64_from_24bit (&cp, &buflen, alt_result[40], alt_result[61], alt_result[19], 4); __b64_from_24bit (&cp, &buflen, alt_result[62], alt_result[20], alt_result[41], 4); __b64_from_24bit (&cp, &buflen, 0, 0, alt_result[63], 2); if (buflen <= 0) { __set_errno (ERANGE); buffer = NULL; } 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. */ #ifndef USE_NSS __sha512_init_ctx (&ctx); __sha512_finish_ctx (&ctx, alt_result); memset (&ctx, '\0', sizeof (ctx)); memset (&alt_ctx, '\0', sizeof (alt_ctx)); #endif memset (temp_result, '\0', sizeof (temp_result)); memset (p_bytes, '\0', key_len); memset (s_bytes, '\0', salt_len); if (copied_key != NULL) memset (copied_key, '\0', key_len); if (copied_salt != NULL) memset (copied_salt, '\0', salt_len); free (free_key); free (free_pbytes); return buffer; }
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 (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 ((PTR_2_INT(key) % ALIGN64) != 0) { tmp = (char *)alloca(key_len + ALIGN64); key = copied_key = memcpy(tmp + ALIGN64 - PTR_2_INT(tmp) % ALIGN64, key, key_len); } if (PTR_2_INT(salt) % ALIGN64 != 0) { tmp = (char *)alloca(salt_len + ALIGN64); salt = copied_salt = memcpy(tmp + ALIGN64 - PTR_2_INT(tmp) % ALIGN64, salt, salt_len); } ret = nspr_nss_init(); if (ret != EOK) { ret = EIO; goto done; } ctx = HASH_Create(HASH_AlgSHA512); if (!ctx) { ret = EIO; goto done; } alt_ctx = HASH_Create(HASH_AlgSHA512); if (!alt_ctx) { ret = EIO; goto done; } /* Prepare for the real work. */ HASH_Begin(ctx); /* 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); /* Add salt. */ HASH_Update(alt_ctx, (const unsigned char *)salt, salt_len); /* Add key again. */ HASH_Update(alt_ctx, (const unsigned char *)key, key_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 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); } /* Finish the digest. */ HASH_End(alt_ctx, temp_result, &part, HASH_ResultLenContext(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); /* Start computation of S byte sequence. */ HASH_Begin(alt_ctx); /* 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); } /* 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++) { 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)); } /* Now we can construct the result string. * It consists of three parts. */ if (buflen <= SALT_PREF_SIZE) { ret = ERANGE; goto done; } 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; } if (buflen <= salt_len + 1) { ret = ERANGE; goto done; } 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 * __md5_crypt_r (const char *key, const char *salt, char *buffer, int buflen) { unsigned char alt_result[16] __attribute__ ((__aligned__ (__alignof__ (md5_uint32)))); size_t salt_len; size_t key_len; size_t cnt; char *cp; char *copied_key = NULL; char *copied_salt = NULL; char *free_key = NULL; size_t alloca_used = 0; /* Find beginning of salt string. The prefix should normally always be present. Just in case it is not. */ if (strncmp (md5_salt_prefix, salt, sizeof (md5_salt_prefix) - 1) == 0) /* Skip salt prefix. */ salt += sizeof (md5_salt_prefix) - 1; salt_len = MIN (strcspn (salt, "$"), 8); key_len = strlen (key); if ((key - (char *) 0) % __alignof__ (md5_uint32) != 0) { char *tmp; if (__libc_use_alloca (alloca_used + key_len + __alignof__ (md5_uint32))) tmp = (char *) alloca (key_len + __alignof__ (md5_uint32)); else { free_key = tmp = (char *) malloc (key_len + __alignof__ (md5_uint32)); if (tmp == NULL) return NULL; } key = copied_key = memcpy (tmp + __alignof__ (md5_uint32) - (tmp - (char *) 0) % __alignof__ (md5_uint32), key, key_len); assert ((key - (char *) 0) % __alignof__ (md5_uint32) == 0); } if ((salt - (char *) 0) % __alignof__ (md5_uint32) != 0) { char *tmp = (char *) alloca (salt_len + __alignof__ (md5_uint32)); salt = copied_salt = memcpy (tmp + __alignof__ (md5_uint32) - (tmp - (char *) 0) % __alignof__ (md5_uint32), salt, salt_len); assert ((salt - (char *) 0) % __alignof__ (md5_uint32) == 0); } #ifdef USE_NSS /* Initialize libfreebl3. */ NSSLOWInitContext *nss_ictx = NSSLOW_Init (); if (nss_ictx == NULL) { free (free_key); return NULL; } NSSLOWHASHContext *nss_ctx = NULL; NSSLOWHASHContext *nss_alt_ctx = NULL; #else struct md5_ctx ctx; struct md5_ctx alt_ctx; #endif /* Prepare for the real work. */ md5_init_ctx (&ctx, nss_ctx); /* Add the key string. */ md5_process_bytes (key, key_len, &ctx, nss_ctx); /* Because the SALT argument need not always have the salt prefix we add it separately. */ md5_process_bytes (md5_salt_prefix, sizeof (md5_salt_prefix) - 1, &ctx, nss_ctx); /* The last part is the salt string. This must be at most 8 characters and it ends at the first `$' character (for compatibility with existing implementations). */ md5_process_bytes (salt, salt_len, &ctx, nss_ctx); /* Compute alternate MD5 sum with input KEY, SALT, and KEY. The final result will be added to the first context. */ md5_init_ctx (&alt_ctx, nss_alt_ctx); /* Add key. */ md5_process_bytes (key, key_len, &alt_ctx, nss_alt_ctx); /* Add salt. */ md5_process_bytes (salt, salt_len, &alt_ctx, nss_alt_ctx); /* Add key again. */ md5_process_bytes (key, key_len, &alt_ctx, nss_alt_ctx); /* Now get result of this (16 bytes) and add it to the other context. */ md5_finish_ctx (&alt_ctx, nss_alt_ctx, alt_result); /* Add for any character in the key one byte of the alternate sum. */ for (cnt = key_len; cnt > 16; cnt -= 16) md5_process_bytes (alt_result, 16, &ctx, nss_ctx); md5_process_bytes (alt_result, cnt, &ctx, nss_ctx); /* For the following code we need a NUL byte. */ *alt_result = '\0'; /* The original implementation now does something weird: for every 1 bit in the key the first 0 is added to the buffer, for every 0 bit the first character of the key. This does not seem to be what was intended but we have to follow this to be compatible. */ for (cnt = key_len; cnt > 0; cnt >>= 1) md5_process_bytes ((cnt & 1) != 0 ? (const void *) alt_result : (const void *) key, 1, &ctx, nss_ctx); /* Create intermediate result. */ md5_finish_ctx (&ctx, nss_ctx, alt_result); /* Now comes another weirdness. In fear of password crackers here comes a quite long loop which just processes the output of the previous round again. We cannot ignore this here. */ for (cnt = 0; cnt < 1000; ++cnt) { /* New context. */ md5_init_ctx (&ctx, nss_ctx); /* Add key or last result. */ if ((cnt & 1) != 0) md5_process_bytes (key, key_len, &ctx, nss_ctx); else md5_process_bytes (alt_result, 16, &ctx, nss_ctx); /* Add salt for numbers not divisible by 3. */ if (cnt % 3 != 0) md5_process_bytes (salt, salt_len, &ctx, nss_ctx); /* Add key for numbers not divisible by 7. */ if (cnt % 7 != 0) md5_process_bytes (key, key_len, &ctx, nss_ctx); /* Add key or last result. */ if ((cnt & 1) != 0) md5_process_bytes (alt_result, 16, &ctx, nss_ctx); else md5_process_bytes (key, key_len, &ctx, nss_ctx); /* Create intermediate result. */ md5_finish_ctx (&ctx, nss_ctx, alt_result); } #ifdef USE_NSS /* Free libfreebl3 resources. */ NSSLOW_Shutdown (nss_ictx); #endif /* Now we can construct the result string. It consists of three parts. */ cp = __stpncpy (buffer, md5_salt_prefix, MAX (0, buflen)); buflen -= sizeof (md5_salt_prefix) - 1; cp = __stpncpy (cp, salt, MIN ((size_t) MAX (0, buflen), salt_len)); buflen -= MIN ((size_t) MAX (0, buflen), salt_len); if (buflen > 0) { *cp++ = '$'; --buflen; } __b64_from_24bit (&cp, &buflen, alt_result[0], alt_result[6], alt_result[12], 4); __b64_from_24bit (&cp, &buflen, alt_result[1], alt_result[7], alt_result[13], 4); __b64_from_24bit (&cp, &buflen, alt_result[2], alt_result[8], alt_result[14], 4); __b64_from_24bit (&cp, &buflen, alt_result[3], alt_result[9], alt_result[15], 4); __b64_from_24bit (&cp, &buflen, alt_result[4], alt_result[10], alt_result[5], 4); __b64_from_24bit (&cp, &buflen, 0, 0, alt_result[11], 2); if (buflen <= 0) { __set_errno (ERANGE); buffer = NULL; } 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 MD5 implementation as well. */ #ifndef USE_NSS __md5_init_ctx (&ctx); __md5_finish_ctx (&ctx, alt_result); explicit_bzero (&ctx, sizeof (ctx)); explicit_bzero (&alt_ctx, sizeof (alt_ctx)); #endif if (copied_key != NULL) explicit_bzero (copied_key, key_len); if (copied_salt != NULL) explicit_bzero (copied_salt, salt_len); free (free_key); return buffer; }
enum nss_status _nss_nisplus_getnetgrent_r (struct __netgrent *result, char *buffer, size_t buflen, int *errnop) { enum nss_status status; /* Some sanity checks. */ if (result->data == NULL || result->data_size == 0) return NSS_STATUS_NOTFOUND; if (result->position == result->data_size) return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN; unsigned int entrylen = NISENTRYLEN (result->position, 1, (nis_result *) result->data); if (entrylen > 0) { /* We have a list of other netgroups. */ result->type = group_val; if (entrylen >= buflen) { *errnop = ERANGE; return NSS_STATUS_TRYAGAIN; } strncpy (buffer, NISENTRYVAL (result->position, 1, (nis_result *) result->data), entrylen); buffer[entrylen] = '\0'; result->val.group = buffer; ++result->position; result->first = 0; return NSS_STATUS_SUCCESS; } /* Before we can copy the entry to the private buffer we have to make sure it is big enough. */ unsigned int hostlen = NISENTRYLEN (result->position, 2, (nis_result *) result->data); unsigned int userlen = NISENTRYLEN (result->position, 3, (nis_result *) result->data); unsigned int domainlen = NISENTRYLEN (result->position, 4, (nis_result *) result->data); if (hostlen + userlen + domainlen + 6 > buflen) { *errnop = ERANGE; status = NSS_STATUS_TRYAGAIN; } else { char *cp = buffer; result->type = triple_val; if (hostlen == 0 || NISENTRYVAL (result->position, 2, (nis_result *) result->data)[0] == '\0') result->val.triple.host = NULL; else { result->val.triple.host = cp; cp = __stpncpy (cp, NISENTRYVAL (result->position, 2, (nis_result *) result->data), hostlen); *cp++ = '\0'; } if (userlen == 0 || NISENTRYVAL (result->position, 3, (nis_result *) result->data)[0] == '\0') result->val.triple.user = NULL; else { result->val.triple.user = cp; cp = __stpncpy (cp, NISENTRYVAL (result->position, 3, (nis_result *) result->data), userlen); *cp++ = '\0'; } if (domainlen == 0 || NISENTRYVAL (result->position, 4, (nis_result *) result->data)[0] == '\0') result->val.triple.domain = NULL; else { result->val.triple.domain = cp; cp = __stpncpy (cp, NISENTRYVAL (result->position, 4, (nis_result *) result->data), domainlen); *cp = '\0'; } status = NSS_STATUS_SUCCESS; /* Remember where we stopped reading. */ ++result->position; result->first = 0; } return status; }