Mercurial > dovecot > original-hg > dovecot-1.2
comparison src/auth/password-scheme.c @ 2367:203938a7f45e HEAD
Added dovecotpw utility. Patch by Joshua Goodall
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Mon, 26 Jul 2004 19:21:29 +0300 |
parents | d921b930abd7 |
children | 8f5be0be3199 |
comparison
equal
deleted
inserted
replaced
2366:33c584ef528a | 2367:203938a7f45e |
---|---|
6 #include "hex-binary.h" | 6 #include "hex-binary.h" |
7 #include "md5.h" | 7 #include "md5.h" |
8 #include "module-dir.h" | 8 #include "module-dir.h" |
9 #include "mycrypt.h" | 9 #include "mycrypt.h" |
10 #include "randgen.h" | 10 #include "randgen.h" |
11 #include "sha1.h" | |
11 #include "str.h" | 12 #include "str.h" |
12 #include "password-scheme.h" | 13 #include "password-scheme.h" |
13 | |
14 #ifdef HAVE_OPENSSL_SHA1 | |
15 # include <openssl/sha.h> | |
16 #endif | |
17 | 14 |
18 static const char salt_chars[] = | 15 static const char salt_chars[] = |
19 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; | 16 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; |
20 | 17 |
21 static buffer_t *schemes_buf; | 18 static buffer_t *schemes_buf; |
36 if (strcasecmp(s->name, scheme) == 0) | 33 if (strcasecmp(s->name, scheme) == 0) |
37 return s->password_verify(plaintext, password, user); | 34 return s->password_verify(plaintext, password, user); |
38 } | 35 } |
39 | 36 |
40 return -1; | 37 return -1; |
38 } | |
39 | |
40 const char *password_list_schemes(const struct password_scheme **listptr) | |
41 { | |
42 if (*listptr == NULL) | |
43 *listptr = schemes; | |
44 | |
45 if ((*listptr)->name == NULL) { | |
46 *listptr = NULL; | |
47 return NULL; | |
48 } | |
49 | |
50 return (*listptr)++->name; | |
41 } | 51 } |
42 | 52 |
43 const char *password_get_scheme(const char **password) | 53 const char *password_get_scheme(const char **password) |
44 { | 54 { |
45 const char *p, *scheme; | 55 const char *p, *scheme; |
66 if (p == NULL) | 76 if (p == NULL) |
67 return NULL; | 77 return NULL; |
68 | 78 |
69 scheme = t_strdup_until(*password + 1, p); | 79 scheme = t_strdup_until(*password + 1, p); |
70 *password = p + 1; | 80 *password = p + 1; |
81 | |
82 /* LDAP's RFC2307 specifies the MD5 scheme for what we call PLAIN-MD5, | |
83 only base64-encoded rather than hex-encoded. | |
84 We can detect this case - base64 doesn't use '$'. */ | |
85 if (strncasecmp(scheme, "MD5", 3) == 0 && | |
86 strncmp(*password, "$1$", 3) != 0) { | |
87 scheme = "LDAP-MD5"; | |
88 } | |
71 return scheme; | 89 return scheme; |
72 } | 90 } |
73 | 91 |
74 const char *password_generate(const char *plaintext, const char *user, | 92 const char *password_generate(const char *plaintext, const char *user, |
75 const char *scheme) | 93 const char *scheme) |
122 salt[i] = salt_chars[salt[i] % (sizeof(salt_chars)-1)]; | 140 salt[i] = salt_chars[salt[i] % (sizeof(salt_chars)-1)]; |
123 salt[8] = '\0'; | 141 salt[8] = '\0'; |
124 return password_generate_md5_crypt(plaintext, salt); | 142 return password_generate_md5_crypt(plaintext, salt); |
125 } | 143 } |
126 | 144 |
127 #ifdef HAVE_OPENSSL_SHA1 | 145 static const char *sha1_generate(const char *plaintext, |
128 static int sha_verify(const char *plaintext, const char *password, | 146 const char *user __attr_unused__) |
147 { | |
148 unsigned char digest[SHA1_RESULTLEN]; | |
149 string_t *str; | |
150 | |
151 sha1_get_digest(plaintext, strlen(plaintext), digest); | |
152 str = t_str_new(MAX_BASE64_ENCODED_SIZE(sizeof(digest)+1)); | |
153 base64_encode(digest, sizeof(digest), str); | |
154 return str_c(str); | |
155 } | |
156 | |
157 static int sha1_verify(const char *plaintext, const char *password, | |
129 const char *user __attr_unused__) | 158 const char *user __attr_unused__) |
130 { | 159 { |
131 unsigned char digest[SHA_DIGEST_LENGTH]; | 160 unsigned char sha1_digest[SHA1_RESULTLEN]; |
161 const char *data; | |
162 buffer_t *buf; | |
163 size_t size; | |
164 | |
165 sha1_get_digest(plaintext, strlen(plaintext), sha1_digest); | |
166 | |
167 buf = buffer_create_static(pool_datastack_create(), | |
168 MAX_BASE64_DECODED_SIZE(strlen(password)+1)); | |
169 | |
170 if (base64_decode(password, strlen(password), NULL, buf) <= 0) { | |
171 i_error("sha1_verify(%s): failed decoding SHA base64", user); | |
172 return 0; | |
173 } | |
174 | |
175 data = buffer_get_data(buf, &size); | |
176 if (size < SHA1_RESULTLEN) { | |
177 i_error("sha1_verify(%s): invalid SHA base64 decode", user); | |
178 return 0; | |
179 } | |
180 | |
181 return memcmp(sha1_digest, data, SHA1_RESULTLEN) == 0; | |
182 } | |
183 | |
184 static const char *ssha_generate(const char *plaintext, | |
185 const char *user __attr_unused__) | |
186 { | |
187 unsigned char ssha_digest[SHA1_RESULTLEN+4]; | |
188 unsigned char *salt = &ssha_digest[SHA1_RESULTLEN]; | |
189 struct sha1_ctxt ctx; | |
132 string_t *str; | 190 string_t *str; |
133 | 191 |
134 SHA1(plaintext, strlen(plaintext), digest); | 192 random_fill(salt, 4); |
135 | 193 |
136 str = t_str_new(64); | 194 sha1_init(&ctx); |
137 base64_encode(digest, sizeof(digest), str); | 195 sha1_loop(&ctx, plaintext, strlen(plaintext)); |
138 return strcasecmp(str_c(str), password) == 0; | 196 sha1_loop(&ctx, salt, 4); |
139 } | 197 sha1_result(&ctx, ssha_digest); |
140 #endif | 198 |
199 str = t_str_new(MAX_BASE64_ENCODED_SIZE(sizeof(ssha_digest))+1); | |
200 base64_encode(ssha_digest, sizeof(ssha_digest), str); | |
201 return str_c(str); | |
202 } | |
203 | |
204 static int ssha_verify(const char *plaintext, const char *password, | |
205 const char *user __attr_unused__) | |
206 { | |
207 unsigned char sha1_digest[SHA1_RESULTLEN]; | |
208 buffer_t *buf; | |
209 const char *data; | |
210 size_t size; | |
211 struct sha1_ctxt ctx; | |
212 | |
213 /* format: base64-encoded MD5 hash and salt */ | |
214 buf = buffer_create_static(pool_datastack_create(), | |
215 MAX_BASE64_DECODED_SIZE(strlen(password)+1)); | |
216 | |
217 if (base64_decode(password, strlen(password), NULL, buf) <= 0) { | |
218 i_error("ssha_verify(%s): failed decoding SSHA base64", user); | |
219 return 0; | |
220 } | |
221 | |
222 data = buffer_get_data(buf, &size); | |
223 if (size <= SHA1_RESULTLEN) { | |
224 i_error("ssha_verify(%s): invalid SSHA base64 decode", user); | |
225 return 0; | |
226 } | |
227 | |
228 sha1_init(&ctx); | |
229 sha1_loop(&ctx, plaintext, strlen(plaintext)); | |
230 sha1_loop(&ctx, &data[SHA1_RESULTLEN], size-SHA1_RESULTLEN); | |
231 sha1_result(&ctx, sha1_digest); | |
232 return memcmp(sha1_digest, data, SHA1_RESULTLEN) == 0; | |
233 } | |
234 | |
235 static const char *smd5_generate(const char *plaintext, | |
236 const char *user __attr_unused__) | |
237 { | |
238 unsigned char smd5_digest[20]; | |
239 unsigned char *salt = &smd5_digest[16]; | |
240 struct md5_context ctx; | |
241 string_t *str; | |
242 | |
243 random_fill(salt, 4); | |
244 | |
245 md5_init(&ctx); | |
246 md5_update(&ctx, plaintext, strlen(plaintext)); | |
247 md5_update(&ctx, salt, 4); | |
248 md5_final(&ctx, smd5_digest); | |
249 | |
250 str = t_str_new(MAX_BASE64_ENCODED_SIZE(sizeof(smd5_digest))+1); | |
251 base64_encode(smd5_digest, sizeof(smd5_digest), str); | |
252 return str_c(str); | |
253 } | |
254 | |
255 static int smd5_verify(const char *plaintext, const char *password, | |
256 const char *user __attr_unused__) | |
257 { | |
258 unsigned char md5_digest[16]; | |
259 buffer_t *buf; | |
260 const char *data; | |
261 size_t size; | |
262 struct md5_context ctx; | |
263 | |
264 /* format: base64-encoded MD5 hash and salt */ | |
265 buf = buffer_create_static(pool_datastack_create(), | |
266 MAX_BASE64_DECODED_SIZE(strlen(password)+1)); | |
267 | |
268 if (base64_decode(password, strlen(password), NULL, buf) <= 0) { | |
269 i_error("smd5_verify(%s): failed decoding SMD5 base64", user); | |
270 return 0; | |
271 } | |
272 | |
273 data = buffer_get_data(buf, &size); | |
274 if (size <= 16) { | |
275 i_error("smd5_verify(%s): invalid SMD5 base64 decode", user); | |
276 return 0; | |
277 } | |
278 | |
279 md5_init(&ctx); | |
280 md5_update(&ctx, plaintext, strlen(plaintext)); | |
281 md5_update(&ctx, &data[16], size-16); | |
282 md5_final(&ctx, md5_digest); | |
283 return memcmp(md5_digest, data, 16) == 0; | |
284 } | |
141 | 285 |
142 static int plain_verify(const char *plaintext, const char *password, | 286 static int plain_verify(const char *plaintext, const char *password, |
143 const char *user __attr_unused__) | 287 const char *user __attr_unused__) |
144 { | 288 { |
145 return strcmp(password, plaintext) == 0; | 289 return strcmp(password, plaintext) == 0; |
214 | 358 |
215 md5_get_digest(plaintext, strlen(plaintext), digest); | 359 md5_get_digest(plaintext, strlen(plaintext), digest); |
216 return binary_to_hex(digest, sizeof(digest)); | 360 return binary_to_hex(digest, sizeof(digest)); |
217 } | 361 } |
218 | 362 |
363 static const char *ldap_md5_generate(const char *plaintext, | |
364 const char *user __attr_unused__) | |
365 { | |
366 unsigned char digest[16]; | |
367 string_t *str; | |
368 | |
369 md5_get_digest(plaintext, strlen(plaintext), digest); | |
370 str = t_str_new(MAX_BASE64_ENCODED_SIZE(sizeof(digest)+1)); | |
371 base64_encode(digest, sizeof(digest), str); | |
372 return str_c(str); | |
373 } | |
374 | |
375 static int ldap_md5_verify(const char *plaintext, const char *password, | |
376 const char *user __attr_unused__) | |
377 { | |
378 unsigned char md5_digest[16]; | |
379 buffer_t *buf; | |
380 const char *data; | |
381 size_t size; | |
382 | |
383 md5_get_digest(plaintext, strlen(plaintext), md5_digest); | |
384 | |
385 buf = buffer_create_static(pool_datastack_create(), | |
386 MAX_BASE64_DECODED_SIZE(strlen(password)+1)); | |
387 | |
388 if (base64_decode(password, strlen(password), NULL, buf) <= 0) { | |
389 i_error("ldap_md5_verify(%s): failed decoding MD5 base64", | |
390 user); | |
391 return 0; | |
392 } | |
393 | |
394 data = buffer_get_data(buf, &size); | |
395 if (size != 16) { | |
396 i_error("ldap_md5_verify(%s): invalid MD5 base64 decode", user); | |
397 return 0; | |
398 } | |
399 | |
400 return memcmp(md5_digest, data, 16) == 0; | |
401 } | |
402 | |
219 static const struct password_scheme default_schemes[] = { | 403 static const struct password_scheme default_schemes[] = { |
220 { "CRYPT", crypt_verify, crypt_generate }, | 404 { "CRYPT", crypt_verify, crypt_generate }, |
221 { "MD5", md5_verify, md5_generate }, | 405 { "MD5", md5_verify, md5_generate }, |
222 #ifdef HAVE_OPENSSL_SHA1 | 406 { "SHA", sha1_verify, sha1_generate }, |
223 { "SHA", sha_verify, NULL }, | 407 { "SHA1", sha1_verify, sha1_generate }, |
224 { "SHA1", sha_verify, NULL }, | 408 { "SMD5", smd5_verify, smd5_generate }, |
225 #endif | 409 { "SSHA", ssha_verify, ssha_generate }, |
226 { "PLAIN", plain_verify, plain_generate }, | 410 { "PLAIN", plain_verify, plain_generate }, |
411 { "CLEARTEXT", plain_verify, plain_generate }, | |
227 { "HMAC-MD5", hmac_md5_verify, hmac_md5_generate }, | 412 { "HMAC-MD5", hmac_md5_verify, hmac_md5_generate }, |
228 { "DIGEST-MD5", digest_md5_verify, digest_md5_generate }, | 413 { "DIGEST-MD5", digest_md5_verify, digest_md5_generate }, |
229 { "PLAIN-MD5", plain_md5_verify, plain_md5_generate }, | 414 { "PLAIN-MD5", plain_md5_verify, plain_md5_generate }, |
415 { "LDAP-MD5", ldap_md5_verify, ldap_md5_generate }, | |
230 { NULL, NULL, NULL } | 416 { NULL, NULL, NULL } |
231 }; | 417 }; |
232 | 418 |
233 void password_schemes_init(void) | 419 void password_schemes_init(void) |
234 { | 420 { |