1 --- lighttpd-1.4.12/src/http_auth.c 2006-09-26 11:35:18.617105290 +0300
2 +++ lighttpd-1.4.12/src/http_auth.c 2006-09-26 11:43:39.928372212 +0300
8 + * The apr_md5_encode() routine uses much code obtained from the FreeBSD 3.0
9 + * MD5 crypt() function, which is licenced as follows:
10 + * ----------------------------------------------------------------------------
11 + * "THE BEER-WARE LICENSE" (Revision 42):
12 + * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
13 + * can do whatever you want with this stuff. If we meet some day, and you think
14 + * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
15 + * ----------------------------------------------------------------------------
18 handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s);
20 static const char base64_pad = '=';
25 +#define APR_MD5_DIGESTSIZE 16
26 +#define APR1_ID "$apr1$"
29 + * The following MD5 password encryption code was largely borrowed from
30 + * the FreeBSD 3.0 /usr/src/lib/libcrypt/crypt.c file, which is
31 + * licenced as stated at the top of this file.
34 +static void to64(char *s, unsigned long v, int n)
36 + static unsigned char itoa64[] = /* 0 ... 63 => ASCII - 64 */
37 + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
40 + *s++ = itoa64[v&0x3f];
45 +static void apr_md5_encode(const char *pw, const char *salt, char *result, size_t nbytes) {
47 + * Minimum size is 8 bytes for salt, plus 1 for the trailing NUL,
48 + * plus 4 for the '$' separators, plus the password hash itself.
49 + * Let's leave a goodly amount of leeway.
52 + char passwd[120], *p;
53 + const char *sp, *ep;
54 + unsigned char final[APR_MD5_DIGESTSIZE];
60 + * Refine the salt first. It's possible we were given an already-hashed
61 + * string as the salt argument, so extract the actual salt value from it
62 + * if so. Otherwise just use the string up to the first '$' as the salt.
67 + * If it starts with the magic string, then skip that.
69 + if (!strncmp(sp, APR1_ID, strlen(APR1_ID))) {
70 + sp += strlen(APR1_ID);
74 + * It stops at the first '$' or 8 chars, whichever comes first
76 + for (ep = sp; (*ep != '\0') && (*ep != '$') && (ep < (sp + 8)); ep++) {
81 + * Get the length of the true salt
86 + * 'Time to make the doughnuts..'
91 + * The password first, since that is what is most unknown
93 + MD5_Update(&ctx, pw, strlen(pw));
96 + * Then our magic string
98 + MD5_Update(&ctx, APR1_ID, strlen(APR1_ID));
101 + * Then the raw salt
103 + MD5_Update(&ctx, sp, sl);
106 + * Then just as many characters of the MD5(pw, salt, pw)
109 + MD5_Update(&ctx1, pw, strlen(pw));
110 + MD5_Update(&ctx1, sp, sl);
111 + MD5_Update(&ctx1, pw, strlen(pw));
112 + MD5_Final(final, &ctx1);
113 + for (pl = strlen(pw); pl > 0; pl -= APR_MD5_DIGESTSIZE) {
114 + MD5_Update(&ctx, final,
115 + (pl > APR_MD5_DIGESTSIZE) ? APR_MD5_DIGESTSIZE : pl);
119 + * Don't leave anything around in vm they could use.
121 + memset(final, 0, sizeof(final));
124 + * Then something really weird...
126 + for (i = strlen(pw); i != 0; i >>= 1) {
128 + MD5_Update(&ctx, final, 1);
131 + MD5_Update(&ctx, pw, 1);
136 + * Now make the output string. We know our limitations, so we
137 + * can use the string routines without bounds checking.
139 + strcpy(passwd, APR1_ID);
140 + strncat(passwd, sp, sl);
141 + strcat(passwd, "$");
143 + MD5_Final(final, &ctx);
146 + * And now, just to make sure things don't run too fast..
147 + * On a 60 Mhz Pentium this takes 34 msec, so you would
148 + * need 30 seconds to build a 1000 entry dictionary...
150 + for (i = 0; i < 1000; i++) {
153 + MD5_Update(&ctx1, pw, strlen(pw));
156 + MD5_Update(&ctx1, final, APR_MD5_DIGESTSIZE);
159 + MD5_Update(&ctx1, sp, sl);
163 + MD5_Update(&ctx1, pw, strlen(pw));
167 + MD5_Update(&ctx1, final, APR_MD5_DIGESTSIZE);
170 + MD5_Update(&ctx1, pw, strlen(pw));
172 + MD5_Final(final,&ctx1);
175 + p = passwd + strlen(passwd);
177 + l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p, l, 4); p += 4;
178 + l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p, l, 4); p += 4;
179 + l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p, l, 4); p += 4;
180 + l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p, l, 4); p += 4;
181 + l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p, l, 4); p += 4;
182 + l = final[11] ; to64(p, l, 2); p += 2;
186 + * Don't leave anything around in vm they could use.
188 + memset(final, 0, sizeof(final));
192 +#define apr_cpystrn strncpy
193 + apr_cpystrn(result, passwd, nbytes - 1);
203 } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) {
205 + if (!strncmp(password->ptr, APR1_ID, strlen(APR1_ID))) {
207 + * The hash was created using $apr1$ custom algorithm.
209 + apr_md5_encode(pw, password->ptr, sample, sizeof(sample));
210 + return (strcmp(sample, password->ptr) == 0) ? 0 : 1;
220 } else if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
221 if (0 == strcmp(password->ptr, pw)) {