passwd.c 27.1 KB
Newer Older
1
/* $OpenLDAP$ */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
2
3
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
4
 * Copyright 1998-2005 The OpenLDAP Foundation.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
5
6
7
8
9
10
11
12
13
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
 *
 * A copy of this license is available in the file LICENSE in the
 * top-level directory of the distribution or, alternatively, at
 * <http://www.OpenLDAP.org/license.html>.
14
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
15

Kurt Zeilenga's avatar
Kurt Zeilenga committed
16
/*
Kurt Zeilenga's avatar
Kurt Zeilenga committed
17
18
19
20
 * int lutil_passwd(
 *	const struct berval *passwd,
 *	const struct berval *cred,
 *	const char **schemes )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
21
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
22
23
 * Returns true if user supplied credentials (cred) matches
 * the stored password (passwd). 
Kurt Zeilenga's avatar
Kurt Zeilenga committed
24
25
26
27
28
29
30
 *
 * Due to the use of the crypt(3) function 
 * this routine is NOT thread-safe.
 */

#include "portable.h"

31
#include <stdio.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
32
#include <ac/stdlib.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
33
#include <ac/string.h>
34
#include <ac/unistd.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
35

36
#ifdef SLAPD_SPASSWD
37
38
39
40
41
#	ifdef HAVE_SASL_SASL_H
#		include <sasl/sasl.h>
#	else
#		include <sasl.h>
#	endif
42
43
#endif

Kurt Zeilenga's avatar
Kurt Zeilenga committed
44
#if defined(SLAPD_LMHASH)
45
46
47
#	include <openssl/des.h>
#endif /* SLAPD_LMHASH */

48
49
#include <ac/param.h>

Kurt Zeilenga's avatar
Kurt Zeilenga committed
50
#ifdef SLAPD_CRYPT
Kurt Zeilenga's avatar
Kurt Zeilenga committed
51
# include <ac/crypt.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
52

Kurt Zeilenga's avatar
Kurt Zeilenga committed
53
54
# if defined( HAVE_GETPWNAM ) && defined( HAVE_PW_PASSWD )
#  ifdef HAVE_SHADOW_H
55
#	include <shadow.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
56
57
#  endif
#  ifdef HAVE_PWD_H
58
#	include <pwd.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
59
60
#  endif
#  ifdef HAVE_AIX_SECURITY
61
#	include <userpw.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
62
63
#  endif
# endif
64
#endif
65

66
67
#include <lber.h>

68
#include "ldap_pvt.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
69
#include "lber_pvt.h"
70

71
72
73
74
#include "lutil_md5.h"
#include "lutil_sha1.h"
#include "lutil.h"

75
76
77
static const unsigned char crypt64[] =
	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890./";

78
#ifdef SLAPD_CRYPT
Kurt Zeilenga's avatar
Kurt Zeilenga committed
79
static char *salt_format = NULL;
80
81
#endif

Howard Chu's avatar
Howard Chu committed
82
83
84
85
/* KLUDGE:
 *  chk_fn is NULL iff name is {CLEARTEXT}
 *     otherwise, things will break
 */
86
87
88
89
90
91
struct pw_scheme {
	struct berval name;
	LUTIL_PASSWD_CHK_FUNC *chk_fn;
	LUTIL_PASSWD_HASH_FUNC *hash_fn;
};

92
93
struct pw_slist {
	struct pw_slist *next;
94
	struct pw_scheme s;
95
96
97
98
};

/* password check routines */

Kurt Zeilenga's avatar
Kurt Zeilenga committed
99
100
#define	SALT_SIZE	4

101
102
103
104
static LUTIL_PASSWD_CHK_FUNC chk_md5;
static LUTIL_PASSWD_CHK_FUNC chk_smd5;
static LUTIL_PASSWD_HASH_FUNC hash_smd5;
static LUTIL_PASSWD_HASH_FUNC hash_md5;
105
106


107
108
109
110
111
#ifdef LUTIL_SHA1_BYTES
static LUTIL_PASSWD_CHK_FUNC chk_ssha1;
static LUTIL_PASSWD_CHK_FUNC chk_sha1;
static LUTIL_PASSWD_HASH_FUNC hash_sha1;
static LUTIL_PASSWD_HASH_FUNC hash_ssha1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
112
#endif
113

114
#ifdef SLAPD_LMHASH
115
116
static LUTIL_PASSWD_CHK_FUNC chk_lanman;
static LUTIL_PASSWD_HASH_FUNC hash_lanman;
117
118
#endif

119
#ifdef SLAPD_SPASSWD
120
static LUTIL_PASSWD_CHK_FUNC chk_sasl;
121
122
#endif

123
#ifdef SLAPD_CRYPT
124
125
static LUTIL_PASSWD_CHK_FUNC chk_crypt;
static LUTIL_PASSWD_HASH_FUNC hash_crypt;
126

Howard Chu's avatar
Howard Chu committed
127
#if defined( HAVE_GETPWNAM ) && defined( HAVE_PW_PASSWD )
128
static LUTIL_PASSWD_CHK_FUNC chk_unix;
129
130
#endif
#endif
131

132
/* password hash routines */
133

134
#ifdef SLAPD_CLEARTEXT
135
static LUTIL_PASSWD_HASH_FUNC hash_clear;
136
#endif
137

138
static struct pw_slist *pw_schemes;
Howard Chu's avatar
Howard Chu committed
139
static int pw_inited;
140

141
static const struct pw_scheme pw_schemes_default[] =
142
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
143
#ifdef LUTIL_SHA1_BYTES
Kurt Zeilenga's avatar
Kurt Zeilenga committed
144
145
	{ BER_BVC("{SSHA}"),		chk_ssha1, hash_ssha1 },
	{ BER_BVC("{SHA}"),			chk_sha1, hash_sha1 },
Kurt Zeilenga's avatar
Kurt Zeilenga committed
146
#endif
147

Kurt Zeilenga's avatar
Kurt Zeilenga committed
148
149
	{ BER_BVC("{SMD5}"),		chk_smd5, hash_smd5 },
	{ BER_BVC("{MD5}"),			chk_md5, hash_md5 },
150

151
#ifdef SLAPD_LMHASH
Kurt Zeilenga's avatar
Kurt Zeilenga committed
152
	{ BER_BVC("{LANMAN}"),		chk_lanman, hash_lanman },
153
154
#endif /* SLAPD_LMHASH */

155
#ifdef SLAPD_SPASSWD
Kurt Zeilenga's avatar
Kurt Zeilenga committed
156
	{ BER_BVC("{SASL}"),		chk_sasl, NULL },
157
158
#endif

159
#ifdef SLAPD_CRYPT
Kurt Zeilenga's avatar
Kurt Zeilenga committed
160
	{ BER_BVC("{CRYPT}"),		chk_crypt, hash_crypt },
161
# if defined( HAVE_GETPWNAM ) && defined( HAVE_PW_PASSWD )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
162
	{ BER_BVC("{UNIX}"),		chk_unix, NULL },
163
# endif
164
#endif
165

166
#ifdef SLAPD_CLEARTEXT
167
	/* pseudo scheme */
Howard Chu's avatar
Howard Chu committed
168
	{ BER_BVC("{CLEARTEXT}"),	NULL, hash_clear },
169
#endif
170

Kurt Zeilenga's avatar
Kurt Zeilenga committed
171
	{ BER_BVNULL, NULL, NULL }
172
173
};

174
175
176
177
int lutil_passwd_add(
	struct berval *scheme,
	LUTIL_PASSWD_CHK_FUNC *chk,
	LUTIL_PASSWD_HASH_FUNC *hash )
178
179
180
{
	struct pw_slist *ptr;

Howard Chu's avatar
Howard Chu committed
181
182
	if (!pw_inited) lutil_passwd_init();

183
184
185
	ptr = ber_memalloc( sizeof( struct pw_slist ));
	if (!ptr) return -1;
	ptr->next = pw_schemes;
186
187
188
	ptr->s.name = *scheme;
	ptr->s.chk_fn = chk;
	ptr->s.hash_fn = hash;
189
190
191
192
193
194
	pw_schemes = ptr;
	return 0;
}

void lutil_passwd_init()
{
195
	struct pw_scheme *s;
196

Howard Chu's avatar
Howard Chu committed
197
198
	pw_inited = 1;

199
	for( s=(struct pw_scheme *)pw_schemes_default; s->name.bv_val; s++) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
200
		if ( lutil_passwd_add( &s->name, s->chk_fn, s->hash_fn ) ) break;
201
202
203
204
205
206
207
208
209
210
211
212
213
	}
}

void lutil_passwd_destroy()
{
	struct pw_slist *ptr, *next;

	for( ptr=pw_schemes; ptr; ptr=next ) {
		next = ptr->next;
		ber_memfree( ptr );
	}
}

214
static const struct pw_scheme *get_scheme(
215
216
	const char* scheme )
{
217
	struct pw_slist *pws;
218
	struct berval bv;
219

Howard Chu's avatar
Howard Chu committed
220
	if (!pw_inited) lutil_passwd_init();
221

222
223
224
225
226
227
228
	bv.bv_val = strchr( scheme, '}' );
	if ( !bv.bv_val )
		return NULL;

	bv.bv_len = bv.bv_val - scheme + 1;
	bv.bv_val = (char *) scheme;

229
	for( pws=pw_schemes; pws; pws=pws->next ) {
Howard Chu's avatar
Howard Chu committed
230
		if ( ber_bvstrcasecmp(&bv, &pws->s.name ) == 0 ) {
231
			return &(pws->s);
232
233
234
235
		}
	}

	return NULL;
236
237
}

238
239
240
241
242
243
244
245
246
247
int lutil_passwd_scheme(
	const char* scheme )
{
	if( scheme == NULL ) {
		return 0;
	}

	return get_scheme(scheme) != NULL;
}

248
249

static int is_allowed_scheme( 
250
251
	const char* scheme,
	const char** schemes )
252
{
253
	int i;
254

255
256
257
258
259
260
	if( schemes == NULL ) return 1;

	for( i=0; schemes[i] != NULL; i++ ) {
		if( strcasecmp( scheme, schemes[i] ) == 0 ) {
			return 1;
		}
261
	}
262
263
	return 0;
}
264

265
static struct berval *passwd_scheme(
266
	const struct pw_scheme *scheme,
267
	const struct berval * passwd,
268
	struct berval *bv,
269
270
	const char** allowed )
{
271
	if( !is_allowed_scheme( scheme->name.bv_val, allowed ) ) {
272
273
		return NULL;
	}
274

275
276
277
278
279
280
281
	if( passwd->bv_len >= scheme->name.bv_len ) {
		if( strncasecmp( passwd->bv_val, scheme->name.bv_val, scheme->name.bv_len ) == 0 ) {
			bv->bv_val = &passwd->bv_val[scheme->name.bv_len];
			bv->bv_len = passwd->bv_len - scheme->name.bv_len;

			return bv;
		}
282
283
284
285
286
	}

	return NULL;
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
287
/*
288
 * Return 0 if creds are good.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
289
290
291
 */
int
lutil_passwd(
292
293
	const struct berval *passwd,	/* stored passwd */
	const struct berval *cred,		/* user cred */
294
295
	const char **schemes,
	const char **text )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
296
{
297
	struct pw_slist *pws;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
298

299
300
	if ( text ) *text = NULL;

301
302
303
	if (cred == NULL || cred->bv_len == 0 ||
		passwd == NULL || passwd->bv_len == 0 )
	{
304
		return -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
305
306
	}

Howard Chu's avatar
Howard Chu committed
307
	if (!pw_inited) lutil_passwd_init();
308
309
310

	for( pws=pw_schemes; pws; pws=pws->next ) {
		if( pws->s.chk_fn ) {
311
			struct berval x;
312
			struct berval *p = passwd_scheme( &(pws->s),
313
				passwd, &x, schemes );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
314

315
			if( p != NULL ) {
316
				return (pws->s.chk_fn)( &(pws->s.name), p, cred, text );
317
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
318
		}
319
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
320

321
#ifdef SLAPD_CLEARTEXT
Howard Chu's avatar
Howard Chu committed
322
323
324
325
326
327
328
329
	/* Do we think there is a scheme specifier here that we
	* didn't recognize? Assume a scheme name is at least 1 character.
	*/
	if (( passwd->bv_val[0] == '{' ) &&
		( strchr( passwd->bv_val, '}' ) > passwd->bv_val+1 ))
	{
		return 1;
	}
330
	if( is_allowed_scheme("{CLEARTEXT}", schemes ) ) {
Howard Chu's avatar
Howard Chu committed
331
332
		return ( passwd->bv_len == cred->bv_len ) ?
			memcmp( passwd->bv_val, cred->bv_val, passwd->bv_len )
333
			: 1;
334
335
	}
#endif
336
	return 1;
337
}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
338

Kurt Zeilenga's avatar
Kurt Zeilenga committed
339
int lutil_passwd_generate( struct berval *pw, ber_len_t len )
340
341
{

Kurt Zeilenga's avatar
Kurt Zeilenga committed
342
	if( len < 1 ) return -1;
343
344
345
346
347

	pw->bv_len = len;
	pw->bv_val = ber_memalloc( len + 1 );

	if( pw->bv_val == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
348
		return -1;
349
350
	}

351
	if( lutil_entropy( (unsigned char *) pw->bv_val, pw->bv_len) < 0 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
352
		return -1; 
353
354
355
356
357
358
359
360
361
	}

	for( len = 0; len < pw->bv_len; len++ ) {
		pw->bv_val[len] = crypt64[
			pw->bv_val[len] % (sizeof(crypt64)-1) ];
	}

	pw->bv_val[len] = '\0';
	
Kurt Zeilenga's avatar
Kurt Zeilenga committed
362
	return 0;
363
364
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
365
int lutil_passwd_hash(
366
	const struct berval * passwd,
367
	const char * method,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
368
	struct berval *hash,
369
	const char **text )
370
{
371
	const struct pw_scheme *sc = get_scheme( method );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
372

Kurt Zeilenga's avatar
Kurt Zeilenga committed
373
374
375
	hash->bv_val = NULL;
	hash->bv_len = 0;

376
377
	if( sc == NULL ) {
		if( text ) *text = "scheme not recognized";
Kurt Zeilenga's avatar
Kurt Zeilenga committed
378
		return -1;
379
380
381
382
	}

	if( ! sc->hash_fn ) {
		if( text ) *text = "scheme provided no hash function";
Kurt Zeilenga's avatar
Kurt Zeilenga committed
383
		return -1;
384
385
	}

386
	if( text ) *text = NULL;
387

Kurt Zeilenga's avatar
Kurt Zeilenga committed
388
	return (sc->hash_fn)( &sc->name, passwd, hash, text );
389
390
}

391
392
/* pw_string is only called when SLAPD_LMHASH or SLAPD_CRYPT is defined */
#if defined(SLAPD_LMHASH) || defined(SLAPD_CRYPT)
Kurt Zeilenga's avatar
Kurt Zeilenga committed
393
static int pw_string(
394
	const struct berval *sc,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
395
	struct berval *passwd )
396
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
397
	struct berval pw;
398

Kurt Zeilenga's avatar
Kurt Zeilenga committed
399
400
	pw.bv_len = sc->bv_len + passwd->bv_len;
	pw.bv_val = ber_memalloc( pw.bv_len + 1 );
401

Kurt Zeilenga's avatar
Kurt Zeilenga committed
402
403
	if( pw.bv_val == NULL ) {
		return LUTIL_PASSWD_ERR;
404
405
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
406
407
	AC_MEMCPY( pw.bv_val, sc->bv_val, sc->bv_len );
	AC_MEMCPY( &pw.bv_val[sc->bv_len], passwd->bv_val, passwd->bv_len );
408

Kurt Zeilenga's avatar
Kurt Zeilenga committed
409
410
411
412
	pw.bv_val[pw.bv_len] = '\0';
	*passwd = pw;

	return LUTIL_PASSWD_OK;
413
}
414
#endif /* SLAPD_LMHASH || SLAPD_CRYPT */
415

Kurt Zeilenga's avatar
Kurt Zeilenga committed
416
static int pw_string64(
417
	const struct berval *sc,
418
	const struct berval *hash,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
419
	struct berval *b64,
420
	const struct berval *salt )
421
422
{
	int rc;
423
	struct berval string;
424
425
	size_t b64len;

426
	if( salt ) {
427
		/* need to base64 combined string */
428
429
		string.bv_len = hash->bv_len + salt->bv_len;
		string.bv_val = ber_memalloc( string.bv_len + 1 );
430

431
		if( string.bv_val == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
432
			return LUTIL_PASSWD_ERR;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
433
434
		}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
435
		AC_MEMCPY( string.bv_val, hash->bv_val,
436
			hash->bv_len );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
437
		AC_MEMCPY( &string.bv_val[hash->bv_len], salt->bv_val,
438
439
			salt->bv_len );
		string.bv_val[string.bv_len] = '\0';
Kurt Zeilenga's avatar
Kurt Zeilenga committed
440

441
	} else {
442
		string = *hash;
443
444
	}

445
	b64len = LUTIL_BASE64_ENCODE_LEN( string.bv_len ) + 1;
446
	b64->bv_len = b64len + sc->bv_len;
447
	b64->bv_val = ber_memalloc( b64->bv_len + 1 );
448

449
450
	if( b64->bv_val == NULL ) {
		if( salt ) ber_memfree( string.bv_val );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
451
		return LUTIL_PASSWD_ERR;
452
	}
453

454
	AC_MEMCPY(b64->bv_val, sc->bv_val, sc->bv_len);
455
456

	rc = lutil_b64_ntop(
457
		(unsigned char *) string.bv_val, string.bv_len,
458
		&b64->bv_val[sc->bv_len], b64len );
459

460
	if( salt ) ber_memfree( string.bv_val );
461
	
462
	if( rc < 0 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
463
		return LUTIL_PASSWD_ERR;
464
465
	}

466
	/* recompute length */
467
	b64->bv_len = sc->bv_len + rc;
468
	assert( strlen(b64->bv_val) == b64->bv_len );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
469
	return LUTIL_PASSWD_OK;
470
471
472
473
}

/* PASSWORD CHECK ROUTINES */

Kurt Zeilenga's avatar
Kurt Zeilenga committed
474
#ifdef LUTIL_SHA1_BYTES
475
static int chk_ssha1(
476
	const struct berval *sc,
477
	const struct berval * passwd,
478
479
	const struct berval * cred,
	const char **text )
480
481
{
	lutil_SHA1_CTX SHA1context;
482
	unsigned char SHA1digest[LUTIL_SHA1_BYTES];
483
484
	int rc;
	unsigned char *orig_pass = NULL;
485

Kurt Zeilenga's avatar
Kurt Zeilenga committed
486
487
	/* safety check -- must have some salt */
	if (LUTIL_BASE64_DECODE_LEN(passwd->bv_len) <= sizeof(SHA1digest)) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
488
		return LUTIL_PASSWD_ERR;
489
490
	}

491
	/* decode base64 password */
492
	orig_pass = (unsigned char *) ber_memalloc( (size_t) (
493
		LUTIL_BASE64_DECODE_LEN(passwd->bv_len) + 1) );
494

Kurt Zeilenga's avatar
Kurt Zeilenga committed
495
	if( orig_pass == NULL ) return LUTIL_PASSWD_ERR;
496

497
498
	rc = lutil_b64_pton(passwd->bv_val, orig_pass, passwd->bv_len);

Kurt Zeilenga's avatar
Kurt Zeilenga committed
499
500
	/* safety check -- must have some salt */
	if (rc <= (int)(sizeof(SHA1digest))) {
501
		ber_memfree(orig_pass);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
502
		return LUTIL_PASSWD_ERR;
503
	}
504
 
505
506
507
	/* hash credentials with salt */
	lutil_SHA1Init(&SHA1context);
	lutil_SHA1Update(&SHA1context,
508
		(const unsigned char *) cred->bv_val, cred->bv_len);
509
510
511
512
	lutil_SHA1Update(&SHA1context,
		(const unsigned char *) &orig_pass[sizeof(SHA1digest)],
		rc - sizeof(SHA1digest));
	lutil_SHA1Final(SHA1digest, &SHA1context);
513
 
514
515
	/* compare */
	rc = memcmp((char *)orig_pass, (char *)SHA1digest, sizeof(SHA1digest));
516
	ber_memfree(orig_pass);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
517
	return rc ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK;
518
}
519

520
static int chk_sha1(
521
	const struct berval *sc,
522
	const struct berval * passwd,
523
524
	const struct berval * cred,
	const char **text )
525
526
{
	lutil_SHA1_CTX SHA1context;
527
	unsigned char SHA1digest[LUTIL_SHA1_BYTES];
528
529
530
	int rc;
	unsigned char *orig_pass = NULL;
 
Kurt Zeilenga's avatar
Kurt Zeilenga committed
531
532
	/* safety check */
	if (LUTIL_BASE64_DECODE_LEN(passwd->bv_len) < sizeof(SHA1digest)) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
533
		return LUTIL_PASSWD_ERR;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
534
535
	}

536
537
538
	/* base64 un-encode password */
	orig_pass = (unsigned char *) ber_memalloc( (size_t) (
		LUTIL_BASE64_DECODE_LEN(passwd->bv_len) + 1) );
539

Kurt Zeilenga's avatar
Kurt Zeilenga committed
540
	if( orig_pass == NULL ) return LUTIL_PASSWD_ERR;
541

542
543
544
545
	rc = lutil_b64_pton(passwd->bv_val, orig_pass, passwd->bv_len);

	if( rc != sizeof(SHA1digest) ) {
		ber_memfree(orig_pass);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
546
		return LUTIL_PASSWD_ERR;
547
	}
548
549
550
551
552
553
554
555
556
557
 
	/* hash credentials with salt */
	lutil_SHA1Init(&SHA1context);
	lutil_SHA1Update(&SHA1context,
		(const unsigned char *) cred->bv_val, cred->bv_len);
	lutil_SHA1Final(SHA1digest, &SHA1context);
 
	/* compare */
	rc = memcmp((char *)orig_pass, (char *)SHA1digest, sizeof(SHA1digest));
	ber_memfree(orig_pass);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
558
	return rc ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK;
559
}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
560
#endif
561
562

static int chk_smd5(
563
	const struct berval *sc,
564
	const struct berval * passwd,
565
566
	const struct berval * cred,
	const char **text )
567
568
{
	lutil_MD5_CTX MD5context;
569
	unsigned char MD5digest[LUTIL_MD5_BYTES];
570
571
572
	int rc;
	unsigned char *orig_pass = NULL;

573
	/* safety check */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
574
	if (LUTIL_BASE64_DECODE_LEN(passwd->bv_len) <= sizeof(MD5digest)) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
575
		return LUTIL_PASSWD_ERR;
576
577
	}

578
	/* base64 un-encode password */
579
	orig_pass = (unsigned char *) ber_memalloc( (size_t) (
580
		LUTIL_BASE64_DECODE_LEN(passwd->bv_len) + 1) );
581

Kurt Zeilenga's avatar
Kurt Zeilenga committed
582
	if( orig_pass == NULL ) return LUTIL_PASSWD_ERR;
583

584
	rc = lutil_b64_pton(passwd->bv_val, orig_pass, passwd->bv_len);
585

Kurt Zeilenga's avatar
Kurt Zeilenga committed
586
	if (rc <= (int)(sizeof(MD5digest))) {
587
		ber_memfree(orig_pass);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
588
		return LUTIL_PASSWD_ERR;
589
590
591
592
593
	}

	/* hash credentials with salt */
	lutil_MD5Init(&MD5context);
	lutil_MD5Update(&MD5context,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
594
595
		(const unsigned char *) cred->bv_val,
		cred->bv_len );
596
	lutil_MD5Update(&MD5context,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
597
		&orig_pass[sizeof(MD5digest)],
598
599
600
601
602
		rc - sizeof(MD5digest));
	lutil_MD5Final(MD5digest, &MD5context);

	/* compare */
	rc = memcmp((char *)orig_pass, (char *)MD5digest, sizeof(MD5digest));
603
	ber_memfree(orig_pass);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
604
	return rc ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK;
605
606
607
}

static int chk_md5(
608
	const struct berval *sc,
609
	const struct berval * passwd,
610
611
	const struct berval * cred,
	const char **text )
612
613
{
	lutil_MD5_CTX MD5context;
614
	unsigned char MD5digest[LUTIL_MD5_BYTES];
615
616
	int rc;
	unsigned char *orig_pass = NULL;
617

Kurt Zeilenga's avatar
Kurt Zeilenga committed
618
619
	/* safety check */
	if (LUTIL_BASE64_DECODE_LEN(passwd->bv_len) < sizeof(MD5digest)) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
620
		return LUTIL_PASSWD_ERR;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
621
622
	}

623
624
625
	/* base64 un-encode password */
	orig_pass = (unsigned char *) ber_memalloc( (size_t) (
		LUTIL_BASE64_DECODE_LEN(passwd->bv_len) + 1) );
626

Kurt Zeilenga's avatar
Kurt Zeilenga committed
627
	if( orig_pass == NULL ) return LUTIL_PASSWD_ERR;
628
629
630
631

	rc = lutil_b64_pton(passwd->bv_val, orig_pass, passwd->bv_len);
	if ( rc != sizeof(MD5digest) ) {
		ber_memfree(orig_pass);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
632
		return LUTIL_PASSWD_ERR;
633
634
	}

635
636
637
	/* hash credentials with salt */
	lutil_MD5Init(&MD5context);
	lutil_MD5Update(&MD5context,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
638
639
		(const unsigned char *) cred->bv_val,
		cred->bv_len );
640
641
642
643
644
	lutil_MD5Final(MD5digest, &MD5context);

	/* compare */
	rc = memcmp((char *)orig_pass, (char *)MD5digest, sizeof(MD5digest));
	ber_memfree(orig_pass);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
645
	return rc ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK;
646
}
647

648
#ifdef SLAPD_LMHASH
Kurt Zeilenga's avatar
Kurt Zeilenga committed
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
/* pseudocode from RFC2433
 * A.2 LmPasswordHash()
 * 
 *    LmPasswordHash(
 *    IN  0-to-14-oem-char Password,
 *    OUT 16-octet         PasswordHash )
 *    {
 *       Set UcasePassword to the uppercased Password
 *       Zero pad UcasePassword to 14 characters
 * 
 *       DesHash( 1st 7-octets of UcasePassword,
 *                giving 1st 8-octets of PasswordHash )
 * 
 *       DesHash( 2nd 7-octets of UcasePassword,
 *                giving 2nd 8-octets of PasswordHash )
 *    }
 * 
 * 
 * A.3 DesHash()
 * 
 *    DesHash(
 *    IN  7-octet Clear,
 *    OUT 8-octet Cypher )
 *    {
 *        *
 *        * Make Cypher an irreversibly encrypted form of Clear by
 *        * encrypting known text using Clear as the secret key.
 *        * The known text consists of the string
 *        *
 *        *              KGS!@#$%
 *        *
 * 
 *       Set StdText to "KGS!@#$%"
 *       DesEncrypt( StdText, Clear, giving Cypher )
 *    }
 * 
 * 
 * A.4 DesEncrypt()
 * 
 *    DesEncrypt(
 *    IN  8-octet Clear,
 *    IN  7-octet Key,
 *    OUT 8-octet Cypher )
 *    {
 *        *
 *        * Use the DES encryption algorithm [4] in ECB mode [9]
 *        * to encrypt Clear into Cypher such that Cypher can
 *        * only be decrypted back to Clear by providing Key.
 *        * Note that the DES algorithm takes as input a 64-bit
 *        * stream where the 8th, 16th, 24th, etc.  bits are
 *        * parity bits ignored by the encrypting algorithm.
 *        * Unless you write your own DES to accept 56-bit input
 *        * without parity, you will need to insert the parity bits
 *        * yourself.
 *        *
 *    }
 */

static void lmPasswd_to_key(
708
	const char *lmPasswd,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
709
710
	des_cblock *key)
{
711
712
713
	const unsigned char *lpw = (const unsigned char *) lmPasswd;
	unsigned char *k = (unsigned char *) key;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
714
	/* make room for parity bits */
715
716
717
718
719
720
721
722
	k[0] = lpw[0];
	k[1] = ((lpw[0] & 0x01) << 7) | (lpw[1] >> 1);
	k[2] = ((lpw[1] & 0x03) << 6) | (lpw[2] >> 2);
	k[3] = ((lpw[2] & 0x07) << 5) | (lpw[3] >> 3);
	k[4] = ((lpw[3] & 0x0F) << 4) | (lpw[4] >> 4);
	k[5] = ((lpw[4] & 0x1F) << 3) | (lpw[5] >> 5);
	k[6] = ((lpw[5] & 0x3F) << 2) | (lpw[6] >> 6);
	k[7] = ((lpw[6] & 0x7F) << 1);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
723
724
725
726
		
	des_set_odd_parity( key );
}	

727
static int chk_lanman(
728
	const struct berval *scheme,
729
	const struct berval *passwd,
730
731
	const struct berval *cred,
	const char **text )
732
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
733
734
735
736
737
738
739
740
741
742
	int i;
	char UcasePassword[15];
	des_cblock key;
	des_key_schedule schedule;
	des_cblock StdText = "KGS!@#$%";
	des_cblock PasswordHash1, PasswordHash2;
	char PasswordHash[33], storedPasswordHash[33];
	
	for( i=0; i<cred->bv_len; i++) {
		if(cred->bv_val[i] == '\0') {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
743
			return LUTIL_PASSWD_ERR;	/* NUL character in password */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
744
745
746
747
		}
	}
	
	if( cred->bv_val[i] != '\0' ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
748
		return LUTIL_PASSWD_ERR;	/* passwd must behave like a string */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
	}
	
	strncpy( UcasePassword, cred->bv_val, 14 );
	UcasePassword[14] = '\0';
	ldap_pvt_str2upper( UcasePassword );
	
	lmPasswd_to_key( UcasePassword, &key );
	des_set_key_unchecked( &key, schedule );
	des_ecb_encrypt( &StdText, &PasswordHash1, schedule , DES_ENCRYPT );
	
	lmPasswd_to_key( &UcasePassword[7], &key );
	des_set_key_unchecked( &key, schedule );
	des_ecb_encrypt( &StdText, &PasswordHash2, schedule , DES_ENCRYPT );
	
	sprintf( PasswordHash, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", 
		PasswordHash1[0],PasswordHash1[1],PasswordHash1[2],PasswordHash1[3],
		PasswordHash1[4],PasswordHash1[5],PasswordHash1[6],PasswordHash1[7],
		PasswordHash2[0],PasswordHash2[1],PasswordHash2[2],PasswordHash2[3],
		PasswordHash2[4],PasswordHash2[5],PasswordHash2[6],PasswordHash2[7] );
	
	/* as a precaution convert stored password hash to lower case */
	strncpy( storedPasswordHash, passwd->bv_val, 32 );
	storedPasswordHash[32] = '\0';
	ldap_pvt_str2lower( storedPasswordHash );
	
Kurt Zeilenga's avatar
Kurt Zeilenga committed
774
	return memcmp( PasswordHash, storedPasswordHash, 32) ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK;
775
776
777
}
#endif /* SLAPD_LMHASH */

778
779
780
781
782
783
#ifdef SLAPD_SPASSWD
#ifdef HAVE_CYRUS_SASL
sasl_conn_t *lutil_passwd_sasl_conn = NULL;
#endif

static int chk_sasl(
784
	const struct berval *sc,
785
	const struct berval * passwd,
786
787
	const struct berval * cred,
	const char **text )
788
{
Howard Chu's avatar
Howard Chu committed
789
	unsigned int i;
790
791
792
793
	int rtn;

	for( i=0; i<cred->bv_len; i++) {
		if(cred->bv_val[i] == '\0') {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
794
			return LUTIL_PASSWD_ERR;	/* NUL character in password */
795
796
797
798
		}
	}

	if( cred->bv_val[i] != '\0' ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
799
		return LUTIL_PASSWD_ERR;	/* cred must behave like a string */
800
801
802
803
	}

	for( i=0; i<passwd->bv_len; i++) {
		if(passwd->bv_val[i] == '\0') {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
804
			return LUTIL_PASSWD_ERR;	/* NUL character in password */
805
806
807
808
		}
	}

	if( passwd->bv_val[i] != '\0' ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
809
		return LUTIL_PASSWD_ERR;	/* passwd must behave like a string */
810
811
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
812
	rtn = LUTIL_PASSWD_ERR;
813
814
815
816

#ifdef HAVE_CYRUS_SASL
	if( lutil_passwd_sasl_conn != NULL ) {
		int sc;
817
# if SASL_VERSION_MAJOR < 2
818
819
820
		sc = sasl_checkpass( lutil_passwd_sasl_conn,
			passwd->bv_val, passwd->bv_len,
			cred->bv_val, cred->bv_len,
821
			text );
822
823
824
825
826
# else
		sc = sasl_checkpass( lutil_passwd_sasl_conn,
			passwd->bv_val, passwd->bv_len,
			cred->bv_val, cred->bv_len );
# endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
827
		rtn = ( sc != SASL_OK ) ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK;
828
829
830
831
832
833
834
	}
#endif

	return rtn;
}
#endif

835
#ifdef SLAPD_CRYPT
836
static int chk_crypt(
837
	const struct berval *sc,
838
	const struct berval * passwd,
839
840
	const struct berval * cred,
	const char **text )
841
{
Howard Chu's avatar
Howard Chu committed
842
	unsigned int i;
843
	char *cr;
844
845
846

	for( i=0; i<cred->bv_len; i++) {
		if(cred->bv_val[i] == '\0') {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
847
			return LUTIL_PASSWD_ERR;	/* NUL character in password */
848
849
850
851
		}
	}

	if( cred->bv_val[i] != '\0' ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
852
		return LUTIL_PASSWD_ERR;	/* cred must behave like a string */
853
854
	}

855
	if( passwd->bv_len < 2 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
856
		return LUTIL_PASSWD_ERR;	/* passwd must be at least two characters long */
857
858
	}

859
860
	for( i=0; i<passwd->bv_len; i++) {
		if(passwd->bv_val[i] == '\0') {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
861
			return LUTIL_PASSWD_ERR;	/* NUL character in password */
862
863
864
865
		}
	}

	if( passwd->bv_val[i] != '\0' ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
866
		return LUTIL_PASSWD_ERR;	/* passwd must behave like a string */
867
868
	}

869
870
871
872
	cr = crypt( cred->bv_val, passwd->bv_val );

	if( cr == NULL || cr[0] == '\0' ) {
		/* salt must have been invalid */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
873
		return LUTIL_PASSWD_ERR;
874
875
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
876
	return strcmp( passwd->bv_val, cr ) ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK;
877
}
878

879
# if defined( HAVE_GETPWNAM ) && defined( HAVE_PW_PASSWD )
880
static int chk_unix(
881
	const struct berval *sc,
882
	const struct berval * passwd,
883
884
	const struct berval * cred,
	const char **text )
885
{
Howard Chu's avatar
Howard Chu committed
886
	unsigned int i;
887
	char *pw, *cr;
888
889
890

	for( i=0; i<cred->bv_len; i++) {
		if(cred->bv_val[i] == '\0') {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
891
			return LUTIL_PASSWD_ERR;	/* NUL character in password */
892
893
894
		}
	}
	if( cred->bv_val[i] != '\0' ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
895
		return LUTIL_PASSWD_ERR;	/* cred must behave like a string */
896
897
	}

898
899