]> git.sur5r.net Git - openldap/blob - libraries/liblutil/passwd.c
Need to adjust len by saltlen
[openldap] / libraries / liblutil / passwd.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6 /*
7  * lutil_password(credentials, password)
8  *
9  * Returns true if user supplied credentials matches
10  * the stored password. 
11  *
12  * Due to the use of the crypt(3) function 
13  * this routine is NOT thread-safe.
14  */
15
16 #include "portable.h"
17
18 #include <stdio.h>
19 #include <ac/stdlib.h>
20
21 #include <ac/string.h>
22 #include <ac/unistd.h>
23 #include <ac/crypt.h>
24
25 #include <lber.h>
26
27 #include "lutil_md5.h"
28 #include "lutil_sha1.h"
29 #include "lutil.h"
30
31 #ifdef HAVE_SHADOW_H
32 #       include <shadow.h>
33 #endif
34 #ifdef HAVE_PWD_H
35 #       include <pwd.h>
36 #endif
37
38 struct pw_scheme;
39
40 typedef int (*PASSWD_CHK_FUNC)(
41         const struct pw_scheme *scheme,
42         const char *passwd,
43         const char *cred );
44
45 typedef char * (*PASSWD_GEN_FUNC) (
46         const struct pw_scheme *scheme,
47         const char *passwd );
48
49 struct pw_scheme {
50         char *name;
51         size_t namelen;
52         PASSWD_CHK_FUNC chk_fn;
53         PASSWD_GEN_FUNC gen_fn;
54 };
55
56 /* password check routines */
57 static int chk_md5(
58         const struct pw_scheme *scheme,
59         const char *passwd,
60         const char *cred );
61
62 static int chk_smd5(
63         const struct pw_scheme *scheme,
64         const char *passwd,
65         const char *cred );
66
67 static int chk_ssha1(
68         const struct pw_scheme *scheme,
69         const char *passwd,
70         const char *cred );
71
72 static int chk_sha1(
73         const struct pw_scheme *scheme,
74         const char *passwd,
75         const char *cred );
76
77 static int chk_crypt(
78         const struct pw_scheme *scheme,
79         const char *passwd,
80         const char *cred );
81
82 static int chk_unix(
83         const struct pw_scheme *scheme,
84         const char *passwd,
85         const char *cred );
86
87
88 /* password generation routines */
89 static char *gen_sha1(
90         const struct pw_scheme *scheme,
91         const char *passwd );
92
93 static char *gen_ssha1(
94         const struct pw_scheme *scheme,
95         const char *passwd );
96
97 static char *gen_smd5(
98         const struct pw_scheme *scheme,
99         const char *passwd );
100
101 static char *gen_md5(
102         const struct pw_scheme *scheme,
103         const char *passwd );
104
105 static char *gen_crypt(
106         const struct pw_scheme *scheme,
107         const char *passwd );
108
109
110 static const struct pw_scheme pw_schemes[] =
111 {
112         { "{SSHA}", sizeof("{SSHA}")-1, chk_ssha1, gen_ssha1 },
113         { "{SHA}", sizeof("{SHA}")-1, chk_sha1, gen_sha1 },
114
115         { "{SMD5}", sizeof("{SMD5}")-1, chk_smd5, gen_smd5 },
116         { "{MD5}", sizeof("{MD5}")-1, chk_md5, gen_md5 },
117
118 #ifdef SLAPD_CRYPT
119         { "{CRYPT}", sizeof("{CRYPT}")-1, chk_crypt, gen_crypt },
120 #endif
121 # if defined( HAVE_GETSPNAM ) \
122   || ( defined( HAVE_GETPWNAM ) && defined( HAVE_PW_PASSWD ) )
123         { "{UNIX}",     sizeof("{UNIX}")-1, chk_unix, NULL },
124 #endif
125
126 #ifdef SLAPD_CLEARTEXT
127         /* psuedo scheme */
128         { "{CLEARTEXT}", 0, NULL, NULL },
129 #endif
130
131         NULL,
132 };
133
134 static const struct pw_scheme *get_scheme(
135         const char* scheme )
136 {
137         int i;
138
139         for( i=0; pw_schemes[i].name != NULL; i++) {
140                 if( pw_schemes[i].namelen == 0 ) continue;
141
142                 if( strncasecmp(scheme, pw_schemes[i].name,
143                         pw_schemes[i].namelen) == 0 )
144                 {
145                         return &pw_schemes[i];
146                 }
147         }
148
149         return NULL;
150 }
151
152
153 static int is_allowed_scheme( 
154         const char* scheme,
155         const char** schemes )
156 {
157         int i;
158
159         if( schemes == NULL ) return 1;
160
161         for( i=0; schemes[i] != NULL; i++ ) {
162                 if( strcasecmp( scheme, schemes[i] ) == 0 ) {
163                         return 1;
164                 }
165         }
166         return 0;
167 }
168
169 static const char *passwd_scheme(
170         const struct pw_scheme *scheme,
171         const char* passwd,
172         const char** allowed )
173 {
174         if( !is_allowed_scheme( scheme->name, allowed ) ) {
175                 return NULL;
176         }
177
178         if( strncasecmp( passwd, scheme->name, scheme->namelen ) == 0 ) {
179                 return &passwd[scheme->namelen];
180         }
181
182         return NULL;
183 }
184
185 /*
186  * Return 0 if creds are good.
187  */
188 int
189 lutil_passwd(
190         const char *passwd,     /* stored passwd */
191         const char *cred,       /* user cred */
192         const char **schemes )
193 {
194         int i;
195
196         if (cred == NULL || passwd == NULL) {
197                 return -1;
198         }
199
200         for( i=0; pw_schemes[i].name != NULL; i++ ) {
201                 if( pw_schemes[i].chk_fn ) {
202                         const char *p = passwd_scheme( &pw_schemes[i],
203                                 passwd, schemes );
204
205                         if( p != NULL ) {
206                                 return (pw_schemes[i].chk_fn)( &pw_schemes[i], p, cred );
207                         }
208                 }
209         }
210
211 #ifdef SLAPD_CLEARTEXT
212         if( is_allowed_scheme("{CLEARTEXT}", schemes ) ) {
213                 return strcmp( cred, passwd );
214         }
215 #else
216         return 1;
217 #endif
218
219 }
220
221 char * lutil_passwd_generate(
222         const char * passwd,
223         const char * method )
224 {
225         const struct pw_scheme *sc = get_scheme( method );
226
227         if( sc == NULL ) return NULL;
228         if( ! sc->gen_fn ) return NULL;
229
230         return (sc->gen_fn)( sc, passwd );
231 }
232
233 static char * pw_string(
234         const struct pw_scheme *sc,
235         const char *passwd)
236 {
237         size_t pwlen = strlen( passwd );
238         char *pw = ber_memalloc( sc->namelen + pwlen + 1 );
239
240         if( pw == NULL ) return NULL;
241
242         memcpy( pw, sc->name, sc->namelen );
243         memcpy( &pw[sc->namelen], passwd, pwlen );
244         pw[sc->namelen + pwlen] = '\0';
245
246         return pw;
247 }
248
249 static char * pw_string64(
250         const struct pw_scheme *sc,
251         const unsigned char *hash, size_t hashlen,
252         const unsigned char *salt, size_t saltlen )
253 {
254         int rc;
255         char *string;
256         size_t b64len;
257         size_t len = hashlen + saltlen;
258         char *b64;
259
260         if( saltlen ) {
261                 /* need to base64 combined string */
262                 string = ber_memalloc( hashlen + saltlen );
263
264                 if( string == NULL ) {
265                         return NULL;
266                 }
267
268                 memcpy( string, hash, len );
269                 memcpy( &string[len], salt, saltlen );
270
271                 len += saltlen;
272
273         } else {
274                 string = (char *) hash;
275         }
276
277         b64len = LUTIL_BASE64_ENCODE_LEN( len ) + 1;
278         b64 = ber_memalloc( b64len + sc->namelen );
279
280         if( b64 == NULL ) {
281                 if( saltlen ) ber_memfree( string );
282                 return NULL;
283         }
284
285         memcpy(b64, sc->name, sc->namelen);
286
287         rc = lutil_b64_ntop( string, len, &b64[sc->namelen], b64len );
288
289         if( saltlen ) ber_memfree( string );
290
291         if( rc < 0 ) {
292                 free( b64 );
293                 return NULL;
294         }
295
296         return b64;
297 }
298
299 /* PASSWORD CHECK ROUTINES */
300
301 static int chk_ssha1(
302         const struct pw_scheme *sc,
303         const char* passwd,
304         const char* cred )
305 {
306         lutil_SHA1_CTX SHA1context;
307         unsigned char SHA1digest[LUTIL_SHA1_BYTES];
308         int pw_len = strlen(passwd);
309         int rc;
310         unsigned char *orig_pass = NULL;
311  
312         /* base64 un-encode password */
313         orig_pass = (unsigned char *) ber_memalloc( (size_t) (
314                 LUTIL_BASE64_DECODE_LEN(pw_len) + 1) );
315
316         if( orig_pass == NULL ) return -1;
317
318         if ((rc = lutil_b64_pton(passwd, orig_pass, pw_len)) < 0) {
319                 ber_memfree(orig_pass);
320                 return 1;
321         }
322  
323         /* hash credentials with salt */
324         lutil_SHA1Init(&SHA1context);
325         lutil_SHA1Update(&SHA1context,
326                 (const unsigned char *) cred, strlen(cred));
327         lutil_SHA1Update(&SHA1context,
328                 (const unsigned char *) &orig_pass[sizeof(SHA1digest)],
329                 rc - sizeof(SHA1digest));
330         lutil_SHA1Final(SHA1digest, &SHA1context);
331  
332         /* compare */
333         rc = memcmp((char *)orig_pass, (char *)SHA1digest, sizeof(SHA1digest));
334         ber_memfree(orig_pass);
335         return rc;
336 }
337
338 static int chk_sha1(
339         const struct pw_scheme *sc,
340         const char* passwd,
341         const char* cred )
342 {
343         lutil_SHA1_CTX SHA1context;
344         unsigned char SHA1digest[LUTIL_SHA1_BYTES];
345         char base64digest[LUTIL_BASE64_ENCODE_LEN(sizeof(SHA1digest))+1]; 
346
347         lutil_SHA1Init(&SHA1context);
348         lutil_SHA1Update(&SHA1context,
349                 (const unsigned char *) cred, strlen(cred));
350         lutil_SHA1Final(SHA1digest, &SHA1context);
351
352         if (lutil_b64_ntop(SHA1digest, sizeof(SHA1digest),
353                 base64digest, sizeof(base64digest)) < 0)
354         {
355                 return 1;
356         }
357
358         return strcmp(passwd, base64digest);
359 }
360
361 static int chk_smd5(
362         const struct pw_scheme *sc,
363         const char* passwd,
364         const char* cred )
365 {
366         lutil_MD5_CTX MD5context;
367         unsigned char MD5digest[LUTIL_MD5_BYTES];
368         int pw_len = strlen(passwd);
369         int rc;
370         unsigned char *orig_pass = NULL;
371
372         /* base64 un-encode password */
373         orig_pass = (unsigned char *) ber_memalloc( (size_t) (
374                 LUTIL_BASE64_DECODE_LEN(pw_len) + 1) );
375
376         if( orig_pass == NULL ) return -1;
377
378         if ((rc = lutil_b64_pton(passwd, orig_pass, pw_len)) < 0) {
379                 ber_memfree(orig_pass);
380                 return 1;
381         }
382
383         /* hash credentials with salt */
384         lutil_MD5Init(&MD5context);
385         lutil_MD5Update(&MD5context,
386                 (const unsigned char *) cred, strlen(cred));
387         lutil_MD5Update(&MD5context,
388                 (const unsigned char *) &orig_pass[sizeof(MD5digest)],
389                 rc - sizeof(MD5digest));
390         lutil_MD5Final(MD5digest, &MD5context);
391
392         /* compare */
393         rc = memcmp((char *)orig_pass, (char *)MD5digest, sizeof(MD5digest));
394         ber_memfree(orig_pass);
395         return rc;
396 }
397
398 static int chk_md5(
399         const struct pw_scheme *sc,
400         const char* passwd,
401         const char* cred )
402 {
403         lutil_MD5_CTX MD5context;
404         unsigned char MD5digest[LUTIL_MD5_BYTES];
405         char base64digest[LUTIL_BASE64_ENCODE_LEN(sizeof(MD5digest))+1]; 
406
407         lutil_MD5Init(&MD5context);
408         lutil_MD5Update(&MD5context,
409                 (const unsigned char *)cred, strlen(cred));
410         lutil_MD5Final(MD5digest, &MD5context);
411
412         if ( lutil_b64_ntop(MD5digest, sizeof(MD5digest),
413                 base64digest, sizeof(base64digest)) < 0 )
414         {
415                 return 1;
416         }
417
418         return strcmp(passwd, base64digest);
419 }
420
421 #ifdef SLAPD_CRYPT
422 static int chk_crypt(
423         const struct pw_scheme *sc,
424         const char* passwd,
425         const char* cred )
426 {
427         return strcmp(passwd, crypt(cred, passwd));
428 }
429
430 # if defined( HAVE_GETSPNAM ) \
431   || ( defined( HAVE_GETPWNAM ) && defined( HAVE_PW_PASSWD ) )
432 static int chk_unix(
433         const struct pw_scheme *sc,
434         const char* cred,
435         const char* p )
436 {
437 #  ifdef HAVE_GETSPNAM
438         struct spwd *spwd = getspnam(p);
439
440         if(spwd == NULL) {
441                 return 1;       /* not found */
442         }
443
444         return strcmp(spwd->sp_pwdp, crypt(cred, spwd->sp_pwdp));
445 #  else
446         struct passwd *pwd = getpwnam(p);
447
448         if(pwd == NULL) {
449                 return 1;       /* not found */
450         }
451
452         return strcmp(pwd->pw_passwd, crypt(cred, pwd->pw_passwd));
453 #  endif
454 # endif
455 }
456 #endif
457
458 /* PASSWORD CHECK ROUTINES */
459 static char *gen_ssha1(
460         const struct pw_scheme *scheme,
461         const char *passwd )
462 {
463         lutil_SHA1_CTX  SHA1context;
464         unsigned char   SHA1digest[LUTIL_SHA1_BYTES];
465         unsigned char   salt[4];
466
467         if( lutil_entropy( salt, sizeof(salt)) < 0 ) {
468                 return NULL; 
469         }
470
471         lutil_SHA1Init( &SHA1context );
472         lutil_SHA1Update( &SHA1context,
473                 (const unsigned char *)passwd, strlen(passwd) );
474         lutil_SHA1Update( &SHA1context,
475                 (const unsigned char *)salt, sizeof(salt) );
476         lutil_SHA1Final( SHA1digest, &SHA1context );
477
478         return pw_string64( scheme,
479                 SHA1digest, sizeof(SHA1digest),
480                 salt, sizeof(salt));
481 }
482
483 static char *gen_sha1(
484         const struct pw_scheme *scheme,
485         const char *passwd )
486 {
487         lutil_SHA1_CTX  SHA1context;
488         unsigned char   SHA1digest[20];
489      
490         lutil_SHA1Init( &SHA1context );
491         lutil_SHA1Update( &SHA1context,
492                 (const unsigned char *)passwd, strlen(passwd) );
493         lutil_SHA1Final( SHA1digest, &SHA1context );
494             
495         return pw_string64( scheme,
496                 SHA1digest, sizeof(SHA1digest),
497                 NULL, 0);
498 }
499
500 static char *gen_smd5(
501         const struct pw_scheme *scheme,
502         const char *passwd )
503 {
504         lutil_MD5_CTX   MD5context;
505         unsigned char   MD5digest[16];
506         unsigned char   salt[4];
507
508         if( lutil_entropy( salt, sizeof(salt)) < 0 ) {
509                 return NULL; 
510         }
511
512         lutil_MD5Init( &MD5context );
513         lutil_MD5Update( &MD5context,
514                 (const unsigned char *) passwd, strlen(passwd) );
515         lutil_MD5Update( &MD5context,
516                 (const unsigned char *) salt, sizeof(salt) );
517         lutil_MD5Final( MD5digest, &MD5context );
518
519         return pw_string64( scheme,
520                 MD5digest, sizeof(MD5digest),
521                 salt, sizeof(salt) );
522 }
523
524 static char *gen_md5(
525         const struct pw_scheme *scheme,
526         const char *passwd )
527 {
528         lutil_MD5_CTX   MD5context;
529         unsigned char   MD5digest[16];
530
531         lutil_MD5Init( &MD5context );
532         lutil_MD5Update( &MD5context,
533                 (const unsigned char *) passwd, strlen(passwd) );
534
535         lutil_MD5Final( MD5digest, &MD5context );
536
537         return pw_string64( scheme,
538                 MD5digest, sizeof(MD5digest),
539                 NULL, 0 );
540 }
541
542 #ifdef SLAPD_CRYPT
543 static char *gen_crypt(
544         const struct pw_scheme *scheme,
545         const char *passwd )
546 {
547         static const unsigned char crypt64[] =
548                 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890./";
549
550         char *hash = NULL;
551         unsigned char salt[2];
552
553         if( lutil_entropy( salt, sizeof(salt)) < 0 ) {
554                 return NULL; 
555         }
556
557         salt[0] = crypt64[ salt[0] % (sizeof(crypt64)-1) ];
558         salt[1] = crypt64[ salt[1] % (sizeof(crypt64)-1) ];
559
560         hash = crypt( passwd, salt );
561
562         if( hash = NULL ) return NULL;
563
564         return pw_string( scheme, hash );
565 }
566 #endif