~ubuntu-branches/ubuntu/hardy/lighttpd/hardy-updates

« back to all changes in this revision

Viewing changes to src/http_auth.c

  • Committer: Bazaar Package Importer
  • Author(s): Soren Hansen
  • Date: 2006-12-08 14:40:42 UTC
  • mfrom: (1.1.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20061208144042-3z5kr9pe0kya5lgu
Tags: 1.4.13-6ubuntu1
* Merge from debian unstable, remaining changes:
  - Replace Depends: on perl with Depends: on libterm-readline-perl-perl

Show diffs side-by-side

added added

removed removed

Lines of Context:
79
79
        unsigned char *result;
80
80
        int ch, j = 0, k;
81
81
        size_t i;
82
 
        
 
82
 
83
83
        size_t in_len = strlen(in);
84
 
        
 
84
 
85
85
        buffer_prepare_copy(out, in_len);
86
 
        
 
86
 
87
87
        result = (unsigned char *)out->ptr;
88
 
        
 
88
 
89
89
        ch = in[0];
90
90
        /* run through the whole string, converting as we go */
91
91
        for (i = 0; i < in_len; i++) {
92
92
                ch = in[i];
93
 
                
 
93
 
94
94
                if (ch == '\0') break;
95
 
                
 
95
 
96
96
                if (ch == base64_pad) break;
97
 
                
 
97
 
98
98
                ch = base64_reverse_table[ch];
99
99
                if (ch < 0) continue;
100
 
                
 
100
 
101
101
                switch(i % 4) {
102
102
                case 0:
103
103
                        result[j] = ch << 2;
129
129
                }
130
130
        }
131
131
        result[k] = '\0';
132
 
        
 
132
 
133
133
        out->used = k;
134
 
        
 
134
 
135
135
        return result;
136
136
}
137
137
 
138
138
static int http_auth_get_password(server *srv, mod_auth_plugin_data *p, buffer *username, buffer *realm, buffer *password) {
139
139
        int ret = -1;
140
 
        
 
140
 
141
141
        if (!username->used|| !realm->used) return -1;
142
 
        
 
142
 
143
143
        if (p->conf.auth_backend == AUTH_BACKEND_HTDIGEST) {
144
144
                stream f;
145
145
                char * f_line;
146
 
                
 
146
 
147
147
                if (buffer_is_empty(p->conf.auth_htdigest_userfile)) return -1;
148
 
                
 
148
 
149
149
                if (0 != stream_open(&f, p->conf.auth_htdigest_userfile)) {
150
150
                        log_error_write(srv, __FILE__, __LINE__, "sbss", "opening digest-userfile", p->conf.auth_htdigest_userfile, "failed:", strerror(errno));
151
 
                        
 
151
 
152
152
                        return -1;
153
153
                }
154
 
                
 
154
 
155
155
                f_line = f.start;
156
 
                
 
156
 
157
157
                while (f_line - f.start != f.size) {
158
158
                        char *f_user, *f_pwd, *e, *f_realm;
159
159
                        size_t u_len, pwd_len, r_len;
160
 
                        
 
160
 
161
161
                        f_user = f_line;
162
 
                        
163
 
                        /* 
 
162
 
 
163
                        /*
164
164
                         * htdigest format
165
 
                         * 
166
 
                         * user:realm:md5(user:realm:password) 
 
165
                         *
 
166
                         * user:realm:md5(user:realm:password)
167
167
                         */
168
 
                        
 
168
 
169
169
                        if (NULL == (f_realm = memchr(f_user, ':', f.size - (f_user - f.start) ))) {
170
 
                                log_error_write(srv, __FILE__, __LINE__, "sbs", 
171
 
                                                "parsed error in", p->conf.auth_htdigest_userfile, 
 
170
                                log_error_write(srv, __FILE__, __LINE__, "sbs",
 
171
                                                "parsed error in", p->conf.auth_htdigest_userfile,
172
172
                                                "expected 'username:realm:hashed password'");
173
 
                                
 
173
 
174
174
                                stream_close(&f);
175
 
                                
 
175
 
176
176
                                return -1;
177
177
                        }
178
 
                        
 
178
 
179
179
                        if (NULL == (f_pwd = memchr(f_realm + 1, ':', f.size - (f_realm + 1 - f.start)))) {
180
 
                                log_error_write(srv, __FILE__, __LINE__, "sbs", 
181
 
                                                "parsed error in", p->conf.auth_plain_userfile, 
 
180
                                log_error_write(srv, __FILE__, __LINE__, "sbs",
 
181
                                                "parsed error in", p->conf.auth_plain_userfile,
182
182
                                                "expected 'username:realm:hashed password'");
183
 
                                
 
183
 
184
184
                                stream_close(&f);
185
 
                                
 
185
 
186
186
                                return -1;
187
187
                        }
188
 
                        
 
188
 
189
189
                        /* get pointers to the fields */
190
 
                        u_len = f_realm - f_user; 
 
190
                        u_len = f_realm - f_user;
191
191
                        f_realm++;
192
192
                        r_len = f_pwd - f_realm;
193
193
                        f_pwd++;
194
 
                        
 
194
 
195
195
                        if (NULL != (e = memchr(f_pwd, '\n', f.size - (f_pwd - f.start)))) {
196
196
                                pwd_len = e - f_pwd;
197
197
                        } else {
198
198
                                pwd_len = f.size - (f_pwd - f.start);
199
199
                        }
200
 
                        
 
200
 
201
201
                        if (username->used - 1 == u_len &&
202
202
                            (realm->used - 1 == r_len) &&
203
203
                            (0 == strncmp(username->ptr, f_user, u_len)) &&
204
204
                            (0 == strncmp(realm->ptr, f_realm, r_len))) {
205
205
                                /* found */
206
 
                                
 
206
 
207
207
                                buffer_copy_string_len(password, f_pwd, pwd_len);
208
 
                                
 
208
 
209
209
                                ret = 0;
210
210
                                break;
211
211
                        }
212
 
                        
 
212
 
213
213
                        /* EOL */
214
214
                        if (!e) break;
215
 
                        
 
215
 
216
216
                        f_line = e + 1;
217
217
                }
218
 
                
 
218
 
219
219
                stream_close(&f);
220
220
        } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD ||
221
221
                   p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
222
222
                stream f;
223
223
                char * f_line;
224
224
                buffer *auth_fn;
225
 
                
 
225
 
226
226
                auth_fn = (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) ? p->conf.auth_htpasswd_userfile : p->conf.auth_plain_userfile;
227
 
                
 
227
 
228
228
                if (buffer_is_empty(auth_fn)) return -1;
229
 
                
 
229
 
230
230
                if (0 != stream_open(&f, auth_fn)) {
231
 
                        log_error_write(srv, __FILE__, __LINE__, "sbss", 
 
231
                        log_error_write(srv, __FILE__, __LINE__, "sbss",
232
232
                                        "opening plain-userfile", auth_fn, "failed:", strerror(errno));
233
 
                        
 
233
 
234
234
                        return -1;
235
235
                }
236
 
                
 
236
 
237
237
                f_line = f.start;
238
 
                
 
238
 
239
239
                while (f_line - f.start != f.size) {
240
240
                        char *f_user, *f_pwd, *e;
241
241
                        size_t u_len, pwd_len;
242
 
                        
 
242
 
243
243
                        f_user = f_line;
244
 
                        
245
 
                        /* 
 
244
 
 
245
                        /*
246
246
                         * htpasswd format
247
 
                         * 
 
247
                         *
248
248
                         * user:crypted passwd
249
249
                         */
250
 
                        
 
250
 
251
251
                        if (NULL == (f_pwd = memchr(f_user, ':', f.size - (f_user - f.start) ))) {
252
 
                                log_error_write(srv, __FILE__, __LINE__, "sbs", 
253
 
                                                "parsed error in", auth_fn, 
 
252
                                log_error_write(srv, __FILE__, __LINE__, "sbs",
 
253
                                                "parsed error in", auth_fn,
254
254
                                                "expected 'username:hashed password'");
255
 
                                
 
255
 
256
256
                                stream_close(&f);
257
 
                                
 
257
 
258
258
                                return -1;
259
259
                        }
260
 
                        
 
260
 
261
261
                        /* get pointers to the fields */
262
 
                        u_len = f_pwd - f_user; 
 
262
                        u_len = f_pwd - f_user;
263
263
                        f_pwd++;
264
 
                        
 
264
 
265
265
                        if (NULL != (e = memchr(f_pwd, '\n', f.size - (f_pwd - f.start)))) {
266
266
                                pwd_len = e - f_pwd;
267
267
                        } else {
268
268
                                pwd_len = f.size - (f_pwd - f.start);
269
269
                        }
270
 
                        
 
270
 
271
271
                        if (username->used - 1 == u_len &&
272
272
                            (0 == strncmp(username->ptr, f_user, u_len))) {
273
273
                                /* found */
274
 
                                
 
274
 
275
275
                                buffer_copy_string_len(password, f_pwd, pwd_len);
276
 
                                
 
276
 
277
277
                                ret = 0;
278
278
                                break;
279
279
                        }
280
 
                        
 
280
 
281
281
                        /* EOL */
282
282
                        if (!e) break;
283
 
                        
 
283
 
284
284
                        f_line = e + 1;
285
285
                }
286
 
                
 
286
 
287
287
                stream_close(&f);
288
288
        } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) {
289
289
                ret = 0;
290
290
        } else {
291
291
                return -1;
292
292
        }
293
 
        
 
293
 
294
294
        return ret;
295
295
}
296
296
 
300
300
        int username_len;
301
301
        data_string *require;
302
302
        array *req;
303
 
        
 
303
 
304
304
        UNUSED(group);
305
305
        UNUSED(host);
306
306
 
308
308
        /* search auth-directives for path */
309
309
        for (i = 0; i < p->conf.auth_require->used; i++) {
310
310
                if (p->conf.auth_require->data[i]->key->used == 0) continue;
311
 
                
 
311
 
312
312
                if (0 == strncmp(url, p->conf.auth_require->data[i]->key->ptr, p->conf.auth_require->data[i]->key->used - 1)) {
313
313
                        break;
314
314
                }
315
315
        }
316
 
        
 
316
 
317
317
        if (i == p->conf.auth_require->used) {
318
318
                return -1;
319
319
        }
321
321
        req = ((data_array *)(p->conf.auth_require->data[i]))->value;
322
322
 
323
323
        require = (data_string *)array_get_element(req, "require");
324
 
        
 
324
 
325
325
        /* if we get here, the user we got a authed user */
326
326
        if (0 == strcmp(require->value->ptr, "valid-user")) {
327
327
                return 0;
328
328
        }
329
 
        
 
329
 
330
330
        /* user=name1|group=name3|host=name4 */
331
 
        
 
331
 
332
332
        /* seperate the string by | */
333
333
#if 0
334
334
        log_error_write(srv, __FILE__, __LINE__, "sb", "rules", require->value);
335
 
#endif  
336
 
        
 
335
#endif
 
336
 
337
337
        username_len = username ? strlen(username) : 0;
338
 
        
 
338
 
339
339
        r = rules = require->value->ptr;
340
 
        
 
340
 
341
341
        while (1) {
342
342
                const char *eq;
343
343
                const char *k, *v, *e;
344
344
                int k_len, v_len, r_len;
345
 
                
 
345
 
346
346
                e = strchr(r, '|');
347
 
                
 
347
 
348
348
                if (e) {
349
349
                        r_len = e - r;
350
350
                } else {
351
351
                        r_len = strlen(rules) - (r - rules);
352
352
                }
353
 
                
 
353
 
354
354
                /* from r to r + r_len is a rule */
355
 
                
 
355
 
356
356
                if (0 == strncmp(r, "valid-user", r_len)) {
357
 
                        log_error_write(srv, __FILE__, __LINE__, "sb", 
 
357
                        log_error_write(srv, __FILE__, __LINE__, "sb",
358
358
                                        "parsing the 'require' section in 'auth.require' failed: valid-user cannot be combined with other require rules",
359
359
                                        require->value);
360
360
                        return -1;
361
361
                }
362
 
                
 
362
 
363
363
                /* search for = in the rules */
364
364
                if (NULL == (eq = strchr(r, '='))) {
365
 
                        log_error_write(srv, __FILE__, __LINE__, "sb", 
366
 
                                        "parsing the 'require' section in 'auth.require' failed: a = is missing", 
 
365
                        log_error_write(srv, __FILE__, __LINE__, "sb",
 
366
                                        "parsing the 'require' section in 'auth.require' failed: a = is missing",
367
367
                                        require->value);
368
368
                        return -1;
369
369
                }
370
 
                
 
370
 
371
371
                /* = out of range */
372
372
                if (eq > r + r_len) {
373
 
                        log_error_write(srv, __FILE__, __LINE__, "sb", 
 
373
                        log_error_write(srv, __FILE__, __LINE__, "sb",
374
374
                                        "parsing the 'require' section in 'auth.require' failed: = out of range",
375
375
                                        require->value);
376
 
                        
 
376
 
377
377
                        return -1;
378
378
                }
379
 
                
 
379
 
380
380
                /* the part before the = is user|group|host */
381
 
                
 
381
 
382
382
                k = r;
383
383
                k_len = eq - r;
384
384
                v = eq + 1;
385
385
                v_len = r_len - k_len - 1;
386
 
                
 
386
 
387
387
                if (k_len == 4) {
388
388
                        if (0 == strncmp(k, "user", k_len)) {
389
 
                                if (username && 
 
389
                                if (username &&
390
390
                                    username_len == v_len &&
391
391
                                    0 == strncmp(username, v, v_len)) {
392
392
                                        return 0;
408
408
                        log_error_write(srv, __FILE__, __LINE__, "s", "unknown  key");
409
409
                        return -1;
410
410
                }
411
 
                
 
411
 
412
412
                if (!e) break;
413
413
                r = e + 1;
414
414
        }
415
 
        
 
415
 
416
416
        log_error_write(srv, __FILE__, __LINE__, "s", "nothing matched");
417
 
        
 
417
 
418
418
        return -1;
419
419
}
420
420
 
452
452
    MD5_CTX ctx, ctx1;
453
453
    unsigned long l;
454
454
 
455
 
    /* 
 
455
    /*
456
456
     * Refine the salt first.  It's possible we were given an already-hashed
457
457
     * string as the salt argument, so extract the actual salt value from it
458
458
     * if so.  Otherwise just use the string up to the first '$' as the salt.
482
482
     * 'Time to make the doughnuts..'
483
483
     */
484
484
    MD5_Init(&ctx);
485
 
    
 
485
 
486
486
    /*
487
487
     * The password first, since that is what is most unknown
488
488
     */
507
507
    MD5_Update(&ctx1, pw, strlen(pw));
508
508
    MD5_Final(final, &ctx1);
509
509
    for (pl = strlen(pw); pl > 0; pl -= APR_MD5_DIGESTSIZE) {
510
 
        MD5_Update(&ctx, final, 
 
510
        MD5_Update(&ctx, final,
511
511
                      (pl > APR_MD5_DIGESTSIZE) ? APR_MD5_DIGESTSIZE : pl);
512
512
    }
513
513
 
591
591
 
592
592
 
593
593
/**
594
 
 * 
595
 
 * 
 
594
 *
 
595
 *
596
596
 * @param password password-string from the auth-backend
597
597
 * @param pw       password-string from the client
598
598
 */
602
602
        UNUSED(req);
603
603
 
604
604
        if (p->conf.auth_backend == AUTH_BACKEND_HTDIGEST) {
605
 
                /* 
 
605
                /*
606
606
                 * htdigest format
607
 
                 * 
608
 
                 * user:realm:md5(user:realm:password) 
 
607
                 *
 
608
                 * user:realm:md5(user:realm:password)
609
609
                 */
610
 
                
 
610
 
611
611
                MD5_CTX Md5Ctx;
612
612
                HASH HA1;
613
613
                char a1[256];
614
 
                
 
614
 
615
615
                MD5_Init(&Md5Ctx);
616
616
                MD5_Update(&Md5Ctx, (unsigned char *)username->ptr, username->used - 1);
617
617
                MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
619
619
                MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
620
620
                MD5_Update(&Md5Ctx, (unsigned char *)pw, strlen(pw));
621
621
                MD5_Final(HA1, &Md5Ctx);
622
 
                
 
622
 
623
623
                CvtHex(HA1, a1);
624
 
                
 
624
 
625
625
                if (0 == strcmp(password->ptr, a1)) {
626
626
                        return 0;
627
627
                }
628
 
        } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) { 
 
628
        } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) {
629
629
                char sample[120];
630
630
                if (!strncmp(password->ptr, APR1_ID, strlen(APR1_ID))) {
631
631
                        /*
634
634
                        apr_md5_encode(pw, password->ptr, sample, sizeof(sample));
635
635
                        return (strcmp(sample, password->ptr) == 0) ? 0 : 1;
636
636
                } else {
637
 
#ifdef HAVE_CRYPT       
 
637
#ifdef HAVE_CRYPT
638
638
                char salt[32];
639
639
                char *crypted;
640
640
                size_t salt_len = 0;
641
 
                /* 
 
641
                /*
642
642
                 * htpasswd format
643
 
                 * 
 
643
                 *
644
644
                 * user:crypted password
645
645
                 */
646
646
 
647
 
                /* 
 
647
                /*
648
648
                 *  Algorithm      Salt
649
649
                 *  CRYPT_STD_DES   2-character (Default)
650
650
                 *  CRYPT_EXT_DES   9-character
662
662
                        salt_len = 2;
663
663
                } else if (password->ptr[0] == '$' && password->ptr[2] == '$') {
664
664
                        char *dollar = NULL;
665
 
                
 
665
 
666
666
                        if (NULL == (dollar = strchr(password->ptr + 3, '$'))) {
667
667
                                fprintf(stderr, "%s.%d\n", __FILE__, __LINE__);
668
668
                                return -1;
679
679
                strncpy(salt, password->ptr, salt_len);
680
680
 
681
681
                salt[salt_len] = '\0';
682
 
                
 
682
 
683
683
                crypted = crypt(pw, salt);
684
684
 
685
685
                if (0 == strcmp(password->ptr, crypted)) {
687
687
                } else {
688
688
                        fprintf(stderr, "%s.%d\n", __FILE__, __LINE__);
689
689
                }
690
 
        
691
 
#endif  
 
690
 
 
691
#endif
692
692
        }
693
 
        } else if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) { 
 
693
        } else if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
694
694
                if (0 == strcmp(password->ptr, pw)) {
695
695
                        return 0;
696
696
                }
697
 
        } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) { 
 
697
        } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) {
698
698
#ifdef USE_LDAP
699
699
                LDAP *ldap;
700
700
                LDAPMessage *lm, *first;
702
702
                int ret;
703
703
                char *attrs[] = { LDAP_NO_ATTRS, NULL };
704
704
                size_t i;
705
 
                
 
705
 
706
706
                /* for now we stay synchronous */
707
 
                
708
 
                /* 
 
707
 
 
708
                /*
709
709
                 * 1. connect anonymously (done in plugin init)
710
710
                 * 2. get DN for uid = username
711
711
                 * 3. auth against ldap server
712
712
                 * 4. (optional) check a field
713
713
                 * 5. disconnect
714
 
                 * 
 
714
                 *
715
715
                 */
716
 
                
 
716
 
717
717
                /* check username
718
 
                 * 
 
718
                 *
719
719
                 * we have to protect us againt username which modifies out filter in
720
720
                 * a unpleasant way
721
721
                 */
722
 
                
 
722
 
723
723
                for (i = 0; i < username->used - 1; i++) {
724
724
                        char c = username->ptr[i];
725
 
                        
 
725
 
726
726
                        if (!isalpha(c) &&
727
727
                            !isdigit(c)) {
728
 
                                
729
 
                                log_error_write(srv, __FILE__, __LINE__, "sbd", 
 
728
 
 
729
                                log_error_write(srv, __FILE__, __LINE__, "sbd",
730
730
                                        "ldap: invalid character (a-zA-Z0-9 allowed) in username:", username, i);
731
 
                                
 
731
 
732
732
                                return -1;
733
733
                        }
734
734
                }
735
 
                
736
 
                
737
 
                
 
735
 
 
736
 
 
737
 
738
738
                /* build filter */
739
739
                buffer_copy_string_buffer(p->ldap_filter, p->conf.ldap_filter_pre);
740
740
                buffer_append_string_buffer(p->ldap_filter, username);
741
741
                buffer_append_string_buffer(p->ldap_filter, p->conf.ldap_filter_post);
742
 
                
743
 
                
 
742
 
 
743
 
744
744
                /* 2. */
745
745
                if (p->conf.ldap == NULL ||
746
746
                    LDAP_SUCCESS != (ret = ldap_search_s(p->conf.ldap, p->conf.auth_ldap_basedn->ptr, LDAP_SCOPE_SUBTREE, p->ldap_filter->ptr, attrs, 0, &lm))) {
748
748
                                return -1;
749
749
                        if (LDAP_SUCCESS != (ret = ldap_search_s(p->conf.ldap, p->conf.auth_ldap_basedn->ptr, LDAP_SCOPE_SUBTREE, p->ldap_filter->ptr, attrs, 0, &lm))) {
750
750
 
751
 
                        log_error_write(srv, __FILE__, __LINE__, "sssb", 
 
751
                        log_error_write(srv, __FILE__, __LINE__, "sssb",
752
752
                                        "ldap:", ldap_err2string(ret), "filter:", p->ldap_filter);
753
 
                        
 
753
 
754
754
                        return -1;
755
755
                        }
756
756
                }
757
 
                
 
757
 
758
758
                if (NULL == (first = ldap_first_entry(p->conf.ldap, lm))) {
759
759
                        log_error_write(srv, __FILE__, __LINE__, "s", "ldap ...");
760
 
                        
 
760
 
761
761
                        ldap_msgfree(lm);
762
 
                        
 
762
 
763
763
                        return -1;
764
764
                }
765
 
                
 
765
 
766
766
                if (NULL == (dn = ldap_get_dn(p->conf.ldap, first))) {
767
767
                        log_error_write(srv, __FILE__, __LINE__, "s", "ldap ...");
768
 
                        
 
768
 
769
769
                        ldap_msgfree(lm);
770
 
                        
 
770
 
771
771
                        return -1;
772
772
                }
773
 
                
 
773
 
774
774
                ldap_msgfree(lm);
775
 
                
776
 
                
 
775
 
 
776
 
777
777
                /* 3. */
778
778
                if (NULL == (ldap = ldap_init(p->conf.auth_ldap_hostname->ptr, LDAP_PORT))) {
779
779
                        log_error_write(srv, __FILE__, __LINE__, "ss", "ldap ...", strerror(errno));
780
780
                        return -1;
781
781
                }
782
 
                
 
782
 
783
783
                ret = LDAP_VERSION3;
784
784
                if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &ret))) {
785
785
                        log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
786
 
                        
 
786
 
787
787
                        ldap_unbind_s(ldap);
788
 
                        
 
788
 
789
789
                        return -1;
790
790
                }
791
 
                
 
791
 
792
792
                if (p->conf.auth_ldap_starttls == 1) {
793
793
                        if (LDAP_OPT_SUCCESS != (ret = ldap_start_tls_s(ldap, NULL,  NULL))) {
794
794
                                log_error_write(srv, __FILE__, __LINE__, "ss", "ldap startTLS failed:", ldap_err2string(ret));
795
 
                
 
795
 
796
796
                                ldap_unbind_s(ldap);
797
 
                                
 
797
 
798
798
                                return -1;
799
799
                        }
800
800
                }
801
801
 
802
 
                
 
802
 
803
803
                if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(ldap, dn, pw))) {
804
804
                        log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
805
 
                        
 
805
 
806
806
                        ldap_unbind_s(ldap);
807
 
                        
 
807
 
808
808
                        return -1;
809
809
                }
810
 
                
 
810
 
811
811
                /* 5. */
812
812
                ldap_unbind_s(ldap);
813
 
                
 
813
 
814
814
                /* everything worked, good, access granted */
815
 
                
 
815
 
816
816
                return 0;
817
817
#endif
818
818
        }
822
822
int http_auth_basic_check(server *srv, connection *con, mod_auth_plugin_data *p, array *req, buffer *url, const char *realm_str) {
823
823
        buffer *username, *password;
824
824
        char *pw;
825
 
        
 
825
 
826
826
        data_string *realm;
827
 
        
 
827
 
828
828
        realm = (data_string *)array_get_element(req, "realm");
829
 
        
 
829
 
830
830
        username = buffer_init();
831
831
        password = buffer_init();
832
 
        
 
832
 
833
833
        base64_decode(username, realm_str);
834
 
        
 
834
 
835
835
        /* r2 == user:password */
836
836
        if (NULL == (pw = strchr(username->ptr, ':'))) {
837
837
                buffer_free(username);
838
 
                
 
838
 
839
839
                log_error_write(srv, __FILE__, __LINE__, "sb", ": is missing in", username);
840
 
                
 
840
 
841
841
                return 0;
842
842
        }
843
 
        
 
843
 
844
844
        *pw++ = '\0';
845
 
        
 
845
 
846
846
        username->used = pw - username->ptr;
847
 
        
 
847
 
848
848
        /* copy password to r1 */
849
849
        if (http_auth_get_password(srv, p, username, realm->value, password)) {
850
850
                buffer_free(username);
851
851
                buffer_free(password);
852
 
                
 
852
 
853
853
                log_error_write(srv, __FILE__, __LINE__, "s", "get_password failed");
854
 
                
 
854
 
855
855
                return 0;
856
856
        }
857
 
        
 
857
 
858
858
        /* password doesn't match */
859
859
        if (http_auth_basic_password_compare(srv, p, req, username, realm->value, password, pw)) {
860
860
                log_error_write(srv, __FILE__, __LINE__, "sbb", "password doesn't match for", con->uri.path, username);
861
 
                
 
861
 
862
862
                buffer_free(username);
863
863
                buffer_free(password);
864
 
                
 
864
 
865
865
                return 0;
866
866
        }
867
 
        
 
867
 
868
868
        /* value is our allow-rules */
869
869
        if (http_auth_match_rules(srv, p, url->ptr, username->ptr, NULL, NULL)) {
870
870
                buffer_free(username);
871
871
                buffer_free(password);
872
 
                
 
872
 
873
873
                log_error_write(srv, __FILE__, __LINE__, "s", "rules didn't match");
874
 
                
 
874
 
875
875
                return 0;
876
876
        }
877
 
        
 
877
 
878
878
        /* remember the username */
879
879
        buffer_copy_string_buffer(p->auth_user, username);
880
 
        
 
880
 
881
881
        buffer_free(username);
882
882
        buffer_free(password);
883
 
        
 
883
 
884
884
        return 1;
885
885
}
886
886
 
893
893
int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p, array *req, buffer *url, const char *realm_str) {
894
894
        char a1[256];
895
895
        char a2[256];
896
 
        
 
896
 
897
897
        char *username;
898
898
        char *realm;
899
899
        char *nonce;
903
903
        char *cnonce;
904
904
        char *nc;
905
905
        char *respons;
906
 
        
 
906
 
907
907
        char *e, *c;
908
908
        const char *m = NULL;
909
909
        int i;
910
910
        buffer *password, *b, *username_buf, *realm_buf;
911
 
        
 
911
 
912
912
        MD5_CTX Md5Ctx;
913
913
        HASH HA1;
914
914
        HASH HA2;
915
915
        HASH RespHash;
916
916
        HASHHEX HA2Hex;
917
 
        
 
917
 
918
918
 
919
919
        /* init pointers */
920
920
#define S(x) \
929
929
                { S("cnonce=") },
930
930
                { S("nc=") },
931
931
                { S("response=") },
932
 
                
 
932
 
933
933
                { NULL, 0, NULL }
934
934
        };
935
935
#undef S
936
 
        
 
936
 
937
937
        dkv[0].ptr = &username;
938
938
        dkv[1].ptr = &realm;
939
939
        dkv[2].ptr = &nonce;
944
944
        dkv[7].ptr = &nc;
945
945
        dkv[8].ptr = &respons;
946
946
        dkv[9].ptr = NULL;
947
 
        
 
947
 
948
948
        UNUSED(req);
949
 
        
 
949
 
950
950
        for (i = 0; dkv[i].key; i++) {
951
951
                *(dkv[i].ptr) = NULL;
952
952
        }
953
 
        
954
 
        
 
953
 
 
954
 
955
955
        if (p->conf.auth_backend != AUTH_BACKEND_HTDIGEST &&
956
956
            p->conf.auth_backend != AUTH_BACKEND_PLAIN) {
957
 
                log_error_write(srv, __FILE__, __LINE__, "s", 
 
957
                log_error_write(srv, __FILE__, __LINE__, "s",
958
958
                                "digest: unsupported backend (only htdigest or plain)");
959
 
                
 
959
 
960
960
                return -1;
961
961
        }
962
 
        
 
962
 
963
963
        b = buffer_init_string(realm_str);
964
 
        
 
964
 
965
965
        /* parse credentials from client */
966
966
        for (c = b->ptr; *c; c++) {
967
967
                /* skip whitespaces */
970
970
 
971
971
                for (i = 0; dkv[i].key; i++) {
972
972
                        if ((0 == strncmp(c, dkv[i].key, dkv[i].key_len))) {
973
 
                                if ((c[dkv[i].key_len] == '"') && 
 
973
                                if ((c[dkv[i].key_len] == '"') &&
974
974
                                    (NULL != (e = strchr(c + dkv[i].key_len + 1, '"')))) {
975
975
                                        /* value with "..." */
976
976
                                        *(dkv[i].ptr) = c + dkv[i].key_len + 1;
977
977
                                        c = e;
978
 
        
 
978
 
979
979
                                        *e = '\0';
980
980
                                } else if (NULL != (e = strchr(c + dkv[i].key_len, ','))) {
981
981
                                        /* value without "...", terminated by ',' */
982
982
                                        *(dkv[i].ptr) = c + dkv[i].key_len;
983
983
                                        c = e;
984
 
                                        
 
984
 
985
985
                                        *e = '\0';
986
986
                                } else {
987
987
                                        /* value without "...", terminated by EOL */
991
991
                        }
992
992
                }
993
993
        }
994
 
        
 
994
 
995
995
        if (p->conf.auth_debug > 1) {
996
996
                log_error_write(srv, __FILE__, __LINE__, "ss", "username", username);
997
997
                log_error_write(srv, __FILE__, __LINE__, "ss", "realm", realm);
1003
1003
                log_error_write(srv, __FILE__, __LINE__, "ss", "nc", nc);
1004
1004
                log_error_write(srv, __FILE__, __LINE__, "ss", "response", respons);
1005
1005
        }
1006
 
        
 
1006
 
1007
1007
        /* check if everything is transmitted */
1008
 
        if (!username || 
 
1008
        if (!username ||
1009
1009
            !realm ||
1010
1010
            !nonce ||
1011
1011
            !uri ||
1012
1012
            (qop && (!nc || !cnonce)) ||
1013
1013
            !respons ) {
1014
1014
                /* missing field */
1015
 
                
1016
 
                log_error_write(srv, __FILE__, __LINE__, "s", 
 
1015
 
 
1016
                log_error_write(srv, __FILE__, __LINE__, "s",
1017
1017
                                "digest: missing field");
1018
1018
                return -1;
1019
1019
        }
1020
1020
 
1021
 
        m = get_http_method_name(con->request.http_method);     
 
1021
        m = get_http_method_name(con->request.http_method);
1022
1022
 
1023
1023
        /* password-string == HA1 */
1024
1024
        password = buffer_init();
1031
1031
                buffer_free(realm_buf);
1032
1032
                return 0;
1033
1033
        }
1034
 
        
 
1034
 
1035
1035
        buffer_free(username_buf);
1036
1036
        buffer_free(realm_buf);
1037
 
        
 
1037
 
1038
1038
        if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
1039
1039
                /* generate password from plain-text */
1040
1040
                MD5_Init(&Md5Ctx);
1048
1048
                /* HA1 */
1049
1049
                /* transform the 32-byte-hex-md5 to a 16-byte-md5 */
1050
1050
                for (i = 0; i < HASHLEN; i++) {
1051
 
                        HA1[i] = hex2int(password->ptr[i*2]) << 4; 
1052
 
                        HA1[i] |= hex2int(password->ptr[i*2+1]); 
 
1051
                        HA1[i] = hex2int(password->ptr[i*2]) << 4;
 
1052
                        HA1[i] |= hex2int(password->ptr[i*2+1]);
1053
1053
                }
1054
1054
        } else {
1055
1055
                /* we already check that above */
1056
1056
                SEGFAULT();
1057
1057
        }
1058
 
        
 
1058
 
1059
1059
        buffer_free(password);
1060
 
        
 
1060
 
1061
1061
        if (algorithm &&
1062
1062
            strcasecmp(algorithm, "md5-sess") == 0) {
1063
1063
                MD5_Init(&Md5Ctx);
1068
1068
                MD5_Update(&Md5Ctx, (unsigned char *)cnonce, strlen(cnonce));
1069
1069
                MD5_Final(HA1, &Md5Ctx);
1070
1070
        }
1071
 
        
 
1071
 
1072
1072
        CvtHex(HA1, a1);
1073
 
        
 
1073
 
1074
1074
        /* calculate H(A2) */
1075
1075
        MD5_Init(&Md5Ctx);
1076
1076
        MD5_Update(&Md5Ctx, (unsigned char *)m, strlen(m));
1082
1082
        }
1083
1083
        MD5_Final(HA2, &Md5Ctx);
1084
1084
        CvtHex(HA2, HA2Hex);
1085
 
        
 
1085
 
1086
1086
        /* calculate response */
1087
1087
        MD5_Init(&Md5Ctx);
1088
1088
        MD5_Update(&Md5Ctx, (unsigned char *)a1, HASHHEXLEN);
1100
1100
        MD5_Update(&Md5Ctx, (unsigned char *)HA2Hex, HASHHEXLEN);
1101
1101
        MD5_Final(RespHash, &Md5Ctx);
1102
1102
        CvtHex(RespHash, a2);
1103
 
        
 
1103
 
1104
1104
        if (0 != strcmp(a2, respons)) {
1105
1105
                /* digest not ok */
1106
 
                
 
1106
 
1107
1107
                if (p->conf.auth_debug) {
1108
 
                        log_error_write(srv, __FILE__, __LINE__, "sss", 
 
1108
                        log_error_write(srv, __FILE__, __LINE__, "sss",
1109
1109
                                "digest: digest mismatch", a2, respons);
1110
1110
                }
1111
 
                
1112
 
                log_error_write(srv, __FILE__, __LINE__, "sss", 
 
1111
 
 
1112
                log_error_write(srv, __FILE__, __LINE__, "sss",
1113
1113
                                "digest: auth failed for", username, "wrong password");
1114
 
                
 
1114
 
1115
1115
                buffer_free(b);
1116
1116
                return 0;
1117
1117
        }
1118
 
        
 
1118
 
1119
1119
        /* value is our allow-rules */
1120
1120
        if (http_auth_match_rules(srv, p, url->ptr, username, NULL, NULL)) {
1121
1121
                buffer_free(b);
1122
 
                
1123
 
                log_error_write(srv, __FILE__, __LINE__, "s", 
 
1122
 
 
1123
                log_error_write(srv, __FILE__, __LINE__, "s",
1124
1124
                                "digest: rules did match");
1125
 
                
 
1125
 
1126
1126
                return 0;
1127
1127
        }
1128
 
        
 
1128
 
1129
1129
        /* remember the username */
1130
1130
        buffer_copy_string(p->auth_user, username);
1131
 
        
 
1131
 
1132
1132
        buffer_free(b);
1133
 
        
 
1133
 
1134
1134
        if (p->conf.auth_debug) {
1135
 
                log_error_write(srv, __FILE__, __LINE__, "s", 
 
1135
                log_error_write(srv, __FILE__, __LINE__, "s",
1136
1136
                                "digest: auth ok");
1137
1137
        }
1138
1138
        return 1;
1143
1143
        HASH h;
1144
1144
        MD5_CTX Md5Ctx;
1145
1145
        char hh[32];
1146
 
        
 
1146
 
1147
1147
        UNUSED(p);
1148
1148
 
1149
1149
        /* generate shared-secret */
1150
1150
        MD5_Init(&Md5Ctx);
1151
1151
        MD5_Update(&Md5Ctx, (unsigned char *)fn->ptr, fn->used - 1);
1152
1152
        MD5_Update(&Md5Ctx, (unsigned char *)"+", 1);
1153
 
        
 
1153
 
1154
1154
        /* we assume sizeof(time_t) == 4 here, but if not it ain't a problem at all */
1155
1155
        ltostr(hh, srv->cur_ts);
1156
1156
        MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
1157
1157
        ltostr(hh, rand());
1158
1158
        MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
1159
 
        
 
1159
 
1160
1160
        MD5_Final(h, &Md5Ctx);
1161
 
        
 
1161
 
1162
1162
        CvtHex(h, out);
1163
 
        
 
1163
 
1164
1164
        return 0;
1165
1165
}