sha_pwd.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  3. * Copyright (C) 2005 Red Hat, Inc.
  4. * All rights reserved.
  5. * END COPYRIGHT BLOCK **/
  6. /*
  7. * slapd hashed password routines
  8. *
  9. */
  10. #include <stdio.h>
  11. #include <string.h>
  12. #include <sys/types.h>
  13. #include "pwdstorage.h"
  14. #if defined(NET_SSL)
  15. #include <sechash.h>
  16. #endif /* NET_SSL */
  17. #define SHA1_SALT_LENGTH 8 /* number of bytes of data in salt */
  18. #define NOT_FIRST_TIME (time_t)1 /* not the first logon */
  19. static char *hasherrmsg = "pw_cmp: %s userPassword \"%s\" is the wrong length or is not properly encoded BASE64\n";
  20. static char *plugin_name = "NSPwdStoragePlugin";
  21. #define DS40B1_SALTED_SHA_LENGTH 18
  22. /* Directory Server 4.0 Beta 1 implemented a scheme that stored
  23. * 8 bytes of salt plus the first 10 bytes of the SHA-1 digest.
  24. * It's obsolescent now, but we still handle such stored values.
  25. */
  26. int
  27. sha1_pw_cmp (char *userpwd, char *dbpwd )
  28. {
  29. /*
  30. * SHA1 passwords are stored in the database as SHA1_LENGTH bytes of
  31. * hash, followed by zero or more bytes of salt, all BASE64 encoded.
  32. */
  33. int result = 1; /* failure */
  34. unsigned char userhash[SHA1_LENGTH];
  35. unsigned char quick_dbhash[SHA1_LENGTH + SHA1_SALT_LENGTH + 3];
  36. unsigned char *dbhash = quick_dbhash;
  37. struct berval salt;
  38. int hash_len; /* must be a signed valued -- see below */
  39. /*
  40. * Decode hash stored in database.
  41. *
  42. * Note that ldif_base64_decode() returns a value less than zero to
  43. * indicate that a decoding error occurred, so it is critical that
  44. * hash_len be a signed value.
  45. */
  46. hash_len = (((strlen(dbpwd) + 3) / 4) * 3); /* maybe less */
  47. if ( hash_len > sizeof(quick_dbhash) ) { /* get more space: */
  48. dbhash = (unsigned char*) slapi_ch_malloc( hash_len );
  49. if ( dbhash == NULL ) goto loser;
  50. }
  51. hash_len = ldif_base64_decode( dbpwd, dbhash );
  52. if ( hash_len >= SHA1_LENGTH ) {
  53. salt.bv_val = (void*)(dbhash + SHA1_LENGTH);
  54. salt.bv_len = hash_len - SHA1_LENGTH;
  55. } else if ( hash_len == DS40B1_SALTED_SHA_LENGTH ) {
  56. salt.bv_val = (void*)dbhash;
  57. salt.bv_len = 8;
  58. } else { /* unsupported, invalid BASE64 (hash_len < 0), or similar */
  59. slapi_log_error( SLAPI_LOG_PLUGIN, plugin_name, hasherrmsg, SHA1_SCHEME_NAME, dbpwd );
  60. goto loser;
  61. }
  62. /* SHA1 hash the user's key */
  63. if ( sha1_salted_hash( userhash, userpwd, &salt ) != SECSuccess ) {
  64. slapi_log_error( SLAPI_LOG_PLUGIN, plugin_name, "sha1_pw_cmp: SHA1_Hash() failed\n");
  65. goto loser;
  66. }
  67. /* the proof is in the comparison... */
  68. result = ( hash_len == DS40B1_SALTED_SHA_LENGTH ) ?
  69. ( memcmp( userhash, dbhash + 8, hash_len - 8 )) :
  70. ( memcmp( userhash, dbhash, SHA1_LENGTH ));
  71. loser:
  72. if ( dbhash && dbhash != quick_dbhash ) slapi_ch_free( (void**)&dbhash );
  73. return result;
  74. }
  75. char *
  76. sha1_pw_enc( char *pwd )
  77. {
  78. unsigned char hash[ SHA1_LENGTH ];
  79. char *enc;
  80. /* SHA1 hash the user's key */
  81. if ( sha1_salted_hash( hash, pwd, NULL ) != SECSuccess ) {
  82. return( NULL );
  83. }
  84. if (( enc = slapi_ch_malloc( 3 + SHA1_NAME_LEN +
  85. LDIF_BASE64_LEN( SHA1_LENGTH ))) == NULL ) {
  86. return( NULL );
  87. }
  88. sprintf( enc, "%c%s%c", PWD_HASH_PREFIX_START, SHA1_SCHEME_NAME,
  89. PWD_HASH_PREFIX_END );
  90. (void)ldif_base64_encode( hash, enc + 2 + SHA1_NAME_LEN,
  91. SHA1_LENGTH, -1 );
  92. return( enc );
  93. }