]>
Commit | Line | Data |
---|---|---|
332e71e1 ER |
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 | |
1bd1c0e4 ER |
3 | @@ -39,6 +39,17 @@ |
4 | # include "md5.h" | |
5 | #endif | |
6 | ||
7 | +/* | |
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 | + * ---------------------------------------------------------------------------- | |
16 | + */ | |
17 | + | |
18 | handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s); | |
19 | ||
20 | static const char base64_pad = '='; | |
332e71e1 | 21 | @@ -405,6 +416,178 @@ |
1bd1c0e4 ER |
22 | return -1; |
23 | } | |
24 | ||
25 | +#define APR_MD5_DIGESTSIZE 16 | |
26 | +#define APR1_ID "$apr1$" | |
27 | + | |
28 | +/* | |
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. | |
32 | + */ | |
33 | + | |
34 | +static void to64(char *s, unsigned long v, int n) | |
35 | +{ | |
36 | + static unsigned char itoa64[] = /* 0 ... 63 => ASCII - 64 */ | |
37 | + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; | |
38 | + | |
39 | + while (--n >= 0) { | |
40 | + *s++ = itoa64[v&0x3f]; | |
41 | + v >>= 6; | |
42 | + } | |
43 | +} | |
44 | + | |
45 | +static void apr_md5_encode(const char *pw, const char *salt, char *result, size_t nbytes) { | |
46 | + /* | |
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. | |
50 | + */ | |
51 | + | |
52 | + char passwd[120], *p; | |
53 | + const char *sp, *ep; | |
54 | + unsigned char final[APR_MD5_DIGESTSIZE]; | |
55 | + ssize_t sl, pl, i; | |
56 | + MD5_CTX ctx, ctx1; | |
57 | + unsigned long l; | |
58 | + | |
59 | + /* | |
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. | |
63 | + */ | |
64 | + sp = salt; | |
65 | + | |
66 | + /* | |
67 | + * If it starts with the magic string, then skip that. | |
68 | + */ | |
69 | + if (!strncmp(sp, APR1_ID, strlen(APR1_ID))) { | |
70 | + sp += strlen(APR1_ID); | |
71 | + } | |
72 | + | |
73 | + /* | |
74 | + * It stops at the first '$' or 8 chars, whichever comes first | |
75 | + */ | |
76 | + for (ep = sp; (*ep != '\0') && (*ep != '$') && (ep < (sp + 8)); ep++) { | |
77 | + continue; | |
78 | + } | |
79 | + | |
80 | + /* | |
81 | + * Get the length of the true salt | |
82 | + */ | |
83 | + sl = ep - sp; | |
84 | + | |
85 | + /* | |
86 | + * 'Time to make the doughnuts..' | |
87 | + */ | |
88 | + MD5_Init(&ctx); | |
89 | + | |
90 | + /* | |
91 | + * The password first, since that is what is most unknown | |
92 | + */ | |
93 | + MD5_Update(&ctx, pw, strlen(pw)); | |
94 | + | |
95 | + /* | |
96 | + * Then our magic string | |
97 | + */ | |
98 | + MD5_Update(&ctx, APR1_ID, strlen(APR1_ID)); | |
99 | + | |
100 | + /* | |
101 | + * Then the raw salt | |
102 | + */ | |
103 | + MD5_Update(&ctx, sp, sl); | |
104 | + | |
105 | + /* | |
106 | + * Then just as many characters of the MD5(pw, salt, pw) | |
107 | + */ | |
108 | + MD5_Init(&ctx1); | |
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); | |
116 | + } | |
117 | + | |
118 | + /* | |
119 | + * Don't leave anything around in vm they could use. | |
120 | + */ | |
121 | + memset(final, 0, sizeof(final)); | |
122 | + | |
123 | + /* | |
124 | + * Then something really weird... | |
125 | + */ | |
126 | + for (i = strlen(pw); i != 0; i >>= 1) { | |
127 | + if (i & 1) { | |
128 | + MD5_Update(&ctx, final, 1); | |
129 | + } | |
130 | + else { | |
131 | + MD5_Update(&ctx, pw, 1); | |
132 | + } | |
133 | + } | |
134 | + | |
135 | + /* | |
136 | + * Now make the output string. We know our limitations, so we | |
137 | + * can use the string routines without bounds checking. | |
138 | + */ | |
139 | + strcpy(passwd, APR1_ID); | |
140 | + strncat(passwd, sp, sl); | |
141 | + strcat(passwd, "$"); | |
142 | + | |
143 | + MD5_Final(final, &ctx); | |
144 | + | |
145 | + /* | |
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... | |
149 | + */ | |
150 | + for (i = 0; i < 1000; i++) { | |
151 | + MD5_Init(&ctx1); | |
152 | + if (i & 1) { | |
153 | + MD5_Update(&ctx1, pw, strlen(pw)); | |
154 | + } | |
155 | + else { | |
156 | + MD5_Update(&ctx1, final, APR_MD5_DIGESTSIZE); | |
157 | + } | |
158 | + if (i % 3) { | |
159 | + MD5_Update(&ctx1, sp, sl); | |
160 | + } | |
161 | + | |
162 | + if (i % 7) { | |
163 | + MD5_Update(&ctx1, pw, strlen(pw)); | |
164 | + } | |
165 | + | |
166 | + if (i & 1) { | |
167 | + MD5_Update(&ctx1, final, APR_MD5_DIGESTSIZE); | |
168 | + } | |
169 | + else { | |
170 | + MD5_Update(&ctx1, pw, strlen(pw)); | |
171 | + } | |
172 | + MD5_Final(final,&ctx1); | |
173 | + } | |
174 | + | |
175 | + p = passwd + strlen(passwd); | |
176 | + | |
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; | |
183 | + *p = '\0'; | |
184 | + | |
185 | + /* | |
186 | + * Don't leave anything around in vm they could use. | |
187 | + */ | |
188 | + memset(final, 0, sizeof(final)); | |
189 | + | |
332e71e1 ER |
190 | + /* FIXME |
191 | + */ | |
1bd1c0e4 ER |
192 | +#define apr_cpystrn strncpy |
193 | + apr_cpystrn(result, passwd, nbytes - 1); | |
194 | +} | |
195 | + | |
196 | + | |
197 | /** | |
198 | * | |
199 | * | |
332e71e1 | 200 | @@ -439,6 +622,14 @@ |
1bd1c0e4 ER |
201 | return 0; |
202 | } | |
9794508f | 203 | } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) { |
1bd1c0e4 ER |
204 | + char sample[120]; |
205 | + if (!strncmp(password->ptr, APR1_ID, strlen(APR1_ID))) { | |
206 | + /* | |
207 | + * The hash was created using $apr1$ custom algorithm. | |
208 | + */ | |
209 | + apr_md5_encode(pw, password->ptr, sample, sizeof(sample)); | |
210 | + return (strcmp(sample, password->ptr) == 0) ? 0 : 1; | |
211 | + } else { | |
9794508f | 212 | #ifdef HAVE_CRYPT |
1bd1c0e4 ER |
213 | char salt[32]; |
214 | char *crypted; | |
332e71e1 | 215 | @@ -493,6 +684,7 @@ |
1bd1c0e4 | 216 | } |
332e71e1 ER |
217 | |
218 | #endif | |
219 | + } | |
220 | } else if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) { | |
221 | if (0 == strcmp(password->ptr, pw)) { | |
222 | return 0; |