3 * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
4 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
7 * lutil_password(credentials, password)
9 * Returns true if user supplied credentials matches
10 * the stored password.
12 * Due to the use of the crypt(3) function
13 * this routine is NOT thread-safe.
19 #include <ac/stdlib.h>
21 #include <ac/string.h>
22 #include <ac/unistd.h>
27 #include "lutil_md5.h"
28 #include "lutil_sha1.h"
40 typedef int (*PASSWD_CHK_FUNC)(
41 const struct pw_scheme *scheme,
42 const struct berval *passwd,
43 const struct berval *cred );
45 typedef struct berval * (*PASSWD_GEN_FUNC) (
46 const struct pw_scheme *scheme,
47 const struct berval *passwd );
51 PASSWD_CHK_FUNC chk_fn;
52 PASSWD_GEN_FUNC gen_fn;
55 /* password check routines */
57 const struct pw_scheme *scheme,
58 const struct berval *passwd,
59 const struct berval *cred );
62 const struct pw_scheme *scheme,
63 const struct berval *passwd,
64 const struct berval *cred );
67 const struct pw_scheme *scheme,
68 const struct berval *passwd,
69 const struct berval *cred );
72 const struct pw_scheme *scheme,
73 const struct berval *passwd,
74 const struct berval *cred );
77 const struct pw_scheme *scheme,
78 const struct berval *passwd,
79 const struct berval *cred );
82 const struct pw_scheme *scheme,
83 const struct berval *passwd,
84 const struct berval *cred );
87 /* password generation routines */
88 static struct berval *gen_sha1(
89 const struct pw_scheme *scheme,
90 const struct berval *passwd );
92 static struct berval *gen_ssha1(
93 const struct pw_scheme *scheme,
94 const struct berval *passwd );
96 static struct berval *gen_smd5(
97 const struct pw_scheme *scheme,
98 const struct berval *passwd );
100 static struct berval *gen_md5(
101 const struct pw_scheme *scheme,
102 const struct berval *passwd );
104 static struct berval *gen_crypt(
105 const struct pw_scheme *scheme,
106 const struct berval *passwd );
109 static const struct pw_scheme pw_schemes[] =
111 { {sizeof("{SSHA}")-1, "{SSHA}"}, chk_ssha1, gen_ssha1 },
112 { {sizeof("{SHA}")-1, "{SHA}"}, chk_sha1, gen_sha1 },
114 { {sizeof("{SMD5}")-1, "{SMD5}"}, chk_smd5, gen_smd5 },
115 { {sizeof("{MD5}")-1, "{MD5}"}, chk_md5, gen_md5 },
118 { {sizeof("{CRYPT}")-1, "{CRYPT}"}, chk_crypt, gen_crypt },
120 # if defined( HAVE_GETSPNAM ) \
121 || ( defined( HAVE_GETPWNAM ) && defined( HAVE_PW_PASSWD ) )
122 { {sizeof("{UNIX}")-1, "{UNIX}"}, chk_unix, NULL },
125 #ifdef SLAPD_CLEARTEXT
127 { {0, "{CLEARTEXT}"}, NULL, NULL },
130 { {0, NULL}, NULL, NULL }
133 static const struct pw_scheme *get_scheme(
138 for( i=0; pw_schemes[i].name.bv_val; i++) {
139 if( pw_schemes[i].name.bv_len == 0 ) continue;
141 if( strncasecmp(scheme, pw_schemes[i].name.bv_val,
142 pw_schemes[i].name.bv_len) == 0 )
144 return &pw_schemes[i];
151 int lutil_passwd_scheme(
154 if( scheme == NULL ) {
158 return get_scheme(scheme) != NULL;
162 static int is_allowed_scheme(
164 const char** schemes )
168 if( schemes == NULL ) return 1;
170 for( i=0; schemes[i] != NULL; i++ ) {
171 if( strcasecmp( scheme, schemes[i] ) == 0 ) {
178 static struct berval *passwd_scheme(
179 const struct pw_scheme *scheme,
180 const struct berval * passwd,
181 const char** allowed )
183 if( !is_allowed_scheme( scheme->name.bv_val, allowed ) ) {
187 if( passwd->bv_len >= scheme->name.bv_len ) {
188 if( strncasecmp( passwd->bv_val, scheme->name.bv_val, scheme->name.bv_len ) == 0 ) {
189 struct berval *bv = ber_memalloc( sizeof(struct berval) );
191 if( bv == NULL ) return NULL;
193 bv->bv_val = &passwd->bv_val[scheme->name.bv_len];
194 bv->bv_len = passwd->bv_len - scheme->name.bv_len;
204 * Return 0 if creds are good.
208 const struct berval *passwd, /* stored passwd */
209 const struct berval *cred, /* user cred */
210 const char **schemes )
214 if (cred == NULL || cred->bv_len == 0 ||
215 passwd == NULL || passwd->bv_len == 0 )
220 for( i=0; pw_schemes[i].name.bv_val != NULL; i++ ) {
221 if( pw_schemes[i].chk_fn ) {
222 struct berval *p = passwd_scheme( &pw_schemes[i],
226 int rc = (pw_schemes[i].chk_fn)( &pw_schemes[i], p, cred );
228 /* only free the berval structure as the bv_val points
229 * into passwd->bv_val
238 #ifdef SLAPD_CLEARTEXT
239 if( is_allowed_scheme("{CLEARTEXT}", schemes ) ) {
240 return passwd->bv_len == cred->bv_len
241 ? memcmp( passwd->bv_val, cred->bv_val, passwd->bv_len )
250 struct berval * lutil_passwd_generate(
251 const struct berval * passwd,
252 const char * method )
254 const struct pw_scheme *sc = get_scheme( method );
256 if( sc == NULL ) return NULL;
257 if( ! sc->gen_fn ) return NULL;
259 return (sc->gen_fn)( sc, passwd );
262 static struct berval * pw_string(
263 const struct pw_scheme *sc,
264 const struct berval *passwd )
266 struct berval *pw = ber_memalloc( sizeof( struct berval ) );
267 if( pw == NULL ) return NULL;
269 pw->bv_len = sc->name.bv_len + passwd->bv_len;
270 pw->bv_val = ber_memalloc( pw->bv_len + 1 );
272 if( pw->bv_val == NULL ) {
277 memcpy( pw->bv_val, sc->name.bv_val, sc->name.bv_len );
278 memcpy( &pw->bv_val[sc->name.bv_len], passwd->bv_val, passwd->bv_len );
280 pw->bv_val[pw->bv_len] = '\0';
284 static struct berval * pw_string64(
285 const struct pw_scheme *sc,
286 const struct berval *hash,
287 const struct berval *salt )
290 struct berval string;
291 struct berval *b64 = ber_memalloc( sizeof(struct berval) );
294 if( b64 == NULL ) return NULL;
297 /* need to base64 combined string */
298 string.bv_len = hash->bv_len + salt->bv_len;
299 string.bv_val = ber_memalloc( string.bv_len + 1 );
301 if( string.bv_val == NULL ) {
306 memcpy( string.bv_val, hash->bv_val,
308 memcpy( &string.bv_val[hash->bv_len], salt->bv_val,
310 string.bv_val[string.bv_len] = '\0';
316 b64len = LUTIL_BASE64_ENCODE_LEN( string.bv_len ) + 1;
317 b64->bv_len = b64len + sc->name.bv_len;
318 b64->bv_val = ber_memalloc( b64->bv_len + 1 );
320 if( b64->bv_val == NULL ) {
321 if( salt ) ber_memfree( string.bv_val );
326 memcpy(b64->bv_val, sc->name.bv_val, sc->name.bv_len);
329 string.bv_val, string.bv_len,
330 &b64->bv_val[sc->name.bv_len], b64len );
332 b64->bv_val[b64->bv_len] = '\0';
334 if( salt ) ber_memfree( string.bv_val );
344 /* PASSWORD CHECK ROUTINES */
346 static int chk_ssha1(
347 const struct pw_scheme *sc,
348 const struct berval * passwd,
349 const struct berval * cred )
351 lutil_SHA1_CTX SHA1context;
352 unsigned char SHA1digest[LUTIL_SHA1_BYTES];
354 unsigned char *orig_pass = NULL;
356 /* base64 un-encode password */
357 orig_pass = (unsigned char *) ber_memalloc( (size_t) (
358 LUTIL_BASE64_DECODE_LEN(passwd->bv_len) + 1) );
360 if( orig_pass == NULL ) return -1;
362 rc = lutil_b64_pton(passwd->bv_val, orig_pass, passwd->bv_len);
365 ber_memfree(orig_pass);
369 /* hash credentials with salt */
370 lutil_SHA1Init(&SHA1context);
371 lutil_SHA1Update(&SHA1context,
372 (const unsigned char *) cred->bv_val, cred->bv_len);
373 lutil_SHA1Update(&SHA1context,
374 (const unsigned char *) &orig_pass[sizeof(SHA1digest)],
375 rc - sizeof(SHA1digest));
376 lutil_SHA1Final(SHA1digest, &SHA1context);
379 rc = memcmp((char *)orig_pass, (char *)SHA1digest, sizeof(SHA1digest));
380 ber_memfree(orig_pass);
385 const struct pw_scheme *sc,
386 const struct berval * passwd,
387 const struct berval * cred )
389 lutil_SHA1_CTX SHA1context;
390 unsigned char SHA1digest[LUTIL_SHA1_BYTES];
392 unsigned char *orig_pass = NULL;
394 /* base64 un-encode password */
395 orig_pass = (unsigned char *) ber_memalloc( (size_t) (
396 LUTIL_BASE64_DECODE_LEN(passwd->bv_len) + 1) );
398 if( orig_pass == NULL ) return -1;
400 rc = lutil_b64_pton(passwd->bv_val, orig_pass, passwd->bv_len);
402 if( rc != sizeof(SHA1digest) ) {
403 ber_memfree(orig_pass);
407 /* hash credentials with salt */
408 lutil_SHA1Init(&SHA1context);
409 lutil_SHA1Update(&SHA1context,
410 (const unsigned char *) cred->bv_val, cred->bv_len);
411 lutil_SHA1Final(SHA1digest, &SHA1context);
414 rc = memcmp((char *)orig_pass, (char *)SHA1digest, sizeof(SHA1digest));
415 ber_memfree(orig_pass);
420 const struct pw_scheme *sc,
421 const struct berval * passwd,
422 const struct berval * cred )
424 lutil_MD5_CTX MD5context;
425 unsigned char MD5digest[LUTIL_MD5_BYTES];
427 unsigned char *orig_pass = NULL;
429 /* base64 un-encode password */
430 orig_pass = (unsigned char *) ber_memalloc( (size_t) (
431 LUTIL_BASE64_DECODE_LEN(passwd->bv_len) + 1) );
433 if( orig_pass == NULL ) return -1;
435 rc = lutil_b64_pton(passwd->bv_val, orig_pass, passwd->bv_len);
437 ber_memfree(orig_pass);
441 /* hash credentials with salt */
442 lutil_MD5Init(&MD5context);
443 lutil_MD5Update(&MD5context,
444 (const unsigned char *) cred->bv_val, cred->bv_len );
445 lutil_MD5Update(&MD5context,
446 (const unsigned char *) &orig_pass[sizeof(MD5digest)],
447 rc - sizeof(MD5digest));
448 lutil_MD5Final(MD5digest, &MD5context);
451 rc = memcmp((char *)orig_pass, (char *)MD5digest, sizeof(MD5digest));
452 ber_memfree(orig_pass);
457 const struct pw_scheme *sc,
458 const struct berval * passwd,
459 const struct berval * cred )
461 lutil_MD5_CTX MD5context;
462 unsigned char MD5digest[LUTIL_MD5_BYTES];
464 unsigned char *orig_pass = NULL;
466 /* base64 un-encode password */
467 orig_pass = (unsigned char *) ber_memalloc( (size_t) (
468 LUTIL_BASE64_DECODE_LEN(passwd->bv_len) + 1) );
470 if( orig_pass == NULL ) return -1;
472 rc = lutil_b64_pton(passwd->bv_val, orig_pass, passwd->bv_len);
473 if ( rc != sizeof(MD5digest) ) {
474 ber_memfree(orig_pass);
478 /* hash credentials with salt */
479 lutil_MD5Init(&MD5context);
480 lutil_MD5Update(&MD5context,
481 (const unsigned char *) cred->bv_val, cred->bv_len );
482 lutil_MD5Final(MD5digest, &MD5context);
485 rc = memcmp((char *)orig_pass, (char *)MD5digest, sizeof(MD5digest));
486 ber_memfree(orig_pass);
491 static int chk_crypt(
492 const struct pw_scheme *sc,
493 const struct berval * passwd,
494 const struct berval * cred )
496 return strcmp(passwd, crypt(cred, passwd));
499 # if defined( HAVE_GETSPNAM ) \
500 || ( defined( HAVE_GETPWNAM ) && defined( HAVE_PW_PASSWD ) )
502 const struct pw_scheme *sc,
503 const struct berval * passwd,
504 const struct berval * cred )
509 for( i=0; i<cred->bv_len; i++) {
510 if(cred->bv_val[i] == '\0') {
511 return 1; /* NUL character in password */
514 if( cred->bv_val[i] != '\0' ) {
515 return 1; /* cred must behave like a string */
518 # ifdef HAVE_GETSPNAM
520 struct spwd *spwd = getspnam(p);
523 return 1; /* not found */
531 struct passwd *pwd = getpwnam(p);
534 return 1; /* not found */
541 if( pw == NULL || *pw == '\0' ) return 1;
543 return strcmp(pw, crypt(cred->bv_val, pw));
549 /* PASSWORD CHECK ROUTINES */
550 static struct berval *gen_ssha1(
551 const struct pw_scheme *scheme,
552 const struct berval *passwd )
554 lutil_SHA1_CTX SHA1context;
555 unsigned char SHA1digest[LUTIL_SHA1_BYTES];
556 unsigned char saltdata[4];
557 struct berval digest;
560 digest.bv_val = SHA1digest;
561 digest.bv_len = sizeof(SHA1digest);
562 salt.bv_val = saltdata;
563 salt.bv_len = sizeof(saltdata);
565 if( lutil_entropy( salt.bv_val, salt.bv_len) < 0 ) {
569 lutil_SHA1Init( &SHA1context );
570 lutil_SHA1Update( &SHA1context,
571 (const unsigned char *)passwd->bv_val, passwd->bv_len );
572 lutil_SHA1Update( &SHA1context,
573 (const unsigned char *)salt.bv_val, salt.bv_len );
574 lutil_SHA1Final( SHA1digest, &SHA1context );
576 return pw_string64( scheme, &digest, &salt);
579 static struct berval *gen_sha1(
580 const struct pw_scheme *scheme,
581 const struct berval *passwd )
583 lutil_SHA1_CTX SHA1context;
584 unsigned char SHA1digest[20];
585 struct berval digest;
586 digest.bv_val = SHA1digest;
587 digest.bv_len = sizeof(SHA1digest);
589 lutil_SHA1Init( &SHA1context );
590 lutil_SHA1Update( &SHA1context,
591 (const unsigned char *)passwd->bv_val, passwd->bv_len );
592 lutil_SHA1Final( SHA1digest, &SHA1context );
594 return pw_string64( scheme, &digest, NULL);
597 static struct berval *gen_smd5(
598 const struct pw_scheme *scheme,
599 const struct berval *passwd )
601 lutil_MD5_CTX MD5context;
602 unsigned char MD5digest[16];
603 unsigned char saltdata[4];
604 struct berval digest;
607 digest.bv_val = MD5digest;
608 digest.bv_len = sizeof(MD5digest);
609 salt.bv_val = saltdata;
610 salt.bv_len = sizeof(saltdata);
612 if( lutil_entropy( salt.bv_val, salt.bv_len) < 0 ) {
616 lutil_MD5Init( &MD5context );
617 lutil_MD5Update( &MD5context,
618 (const unsigned char *) passwd->bv_val, passwd->bv_len );
619 lutil_MD5Update( &MD5context,
620 (const unsigned char *) salt.bv_val, salt.bv_len );
621 lutil_MD5Final( MD5digest, &MD5context );
623 return pw_string64( scheme, &digest, &salt );
626 static struct berval *gen_md5(
627 const struct pw_scheme *scheme,
628 const struct berval *passwd )
630 lutil_MD5_CTX MD5context;
631 unsigned char MD5digest[16];
633 struct berval digest;
635 digest.bv_val = MD5digest;
636 digest.bv_len = sizeof(MD5digest);
638 lutil_MD5Init( &MD5context );
639 lutil_MD5Update( &MD5context,
640 (const unsigned char *) passwd->bv_val, passwd->bv_len );
641 lutil_MD5Final( MD5digest, &MD5context );
643 return pw_string64( scheme, &digest, NULL );
648 static struct berval *gen_crypt(
649 const struct pw_scheme *scheme,
650 const struct berval *passwd )
652 static const unsigned char crypt64[] =
653 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890./";
656 unsigned char salt[2];
658 if( lutil_entropy( salt, sizeof(salt)) < 0 ) {
662 salt[0] = crypt64[ salt[0] % (sizeof(crypt64)-1) ];
663 salt[1] = crypt64[ salt[1] % (sizeof(crypt64)-1) ];
665 hash = crypt( passwd, salt );
667 if( hash = NULL ) return NULL;
669 return pw_string( scheme, hash );