131
131
result[k] = '\0';
138
138
static int http_auth_get_password(server *srv, mod_auth_plugin_data *p, buffer *username, buffer *realm, buffer *password) {
141
141
if (!username->used|| !realm->used) return -1;
143
143
if (p->conf.auth_backend == AUTH_BACKEND_HTDIGEST) {
147
147
if (buffer_is_empty(p->conf.auth_htdigest_userfile)) return -1;
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));
155
155
f_line = f.start;
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;
164
164
* htdigest format
166
* user:realm:md5(user:realm:password)
166
* user:realm:md5(user:realm:password)
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'");
174
174
stream_close(&f);
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'");
184
184
stream_close(&f);
189
189
/* get pointers to the fields */
190
u_len = f_realm - f_user;
190
u_len = f_realm - f_user;
192
192
r_len = f_pwd - f_realm;
195
195
if (NULL != (e = memchr(f_pwd, '\n', f.size - (f_pwd - f.start)))) {
196
196
pwd_len = e - f_pwd;
198
198
pwd_len = f.size - (f_pwd - f.start);
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))) {
207
207
buffer_copy_string_len(password, f_pwd, pwd_len);
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) {
226
226
auth_fn = (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) ? p->conf.auth_htpasswd_userfile : p->conf.auth_plain_userfile;
228
228
if (buffer_is_empty(auth_fn)) return -1;
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));
237
237
f_line = f.start;
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;
246
246
* htpasswd format
248
248
* user:crypted passwd
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'");
256
256
stream_close(&f);
261
261
/* get pointers to the fields */
262
u_len = f_pwd - f_user;
262
u_len = f_pwd - f_user;
265
265
if (NULL != (e = memchr(f_pwd, '\n', f.size - (f_pwd - f.start)))) {
266
266
pwd_len = e - f_pwd;
268
268
pwd_len = f.size - (f_pwd - f.start);
271
271
if (username->used - 1 == u_len &&
272
272
(0 == strncmp(username->ptr, f_user, u_len))) {
275
275
buffer_copy_string_len(password, f_pwd, pwd_len);
287
287
stream_close(&f);
288
288
} else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) {
321
321
req = ((data_array *)(p->conf.auth_require->data[i]))->value;
323
323
require = (data_string *)array_get_element(req, "require");
325
325
/* if we get here, the user we got a authed user */
326
326
if (0 == strcmp(require->value->ptr, "valid-user")) {
330
330
/* user=name1|group=name3|host=name4 */
332
332
/* seperate the string by | */
334
334
log_error_write(srv, __FILE__, __LINE__, "sb", "rules", require->value);
337
337
username_len = username ? strlen(username) : 0;
339
339
r = rules = require->value->ptr;
343
343
const char *k, *v, *e;
344
344
int k_len, v_len, r_len;
346
346
e = strchr(r, '|');
351
351
r_len = strlen(rules) - (r - rules);
354
354
/* from r to r + r_len is a rule */
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",
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",
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",
380
380
/* the part before the = is user|group|host */
385
385
v_len = r_len - k_len - 1;
387
387
if (k_len == 4) {
388
388
if (0 == strncmp(k, "user", k_len)) {
390
390
username_len == v_len &&
391
391
0 == strncmp(username, v, v_len)) {
703
703
char *attrs[] = { LDAP_NO_ATTRS, NULL };
706
706
/* for now we stay synchronous */
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
717
717
/* check username
719
719
* we have to protect us againt username which modifies out filter in
720
720
* a unpleasant way
723
723
for (i = 0; i < username->used - 1; i++) {
724
724
char c = username->ptr[i];
726
726
if (!isalpha(c) &&
729
log_error_write(srv, __FILE__, __LINE__, "sbd",
729
log_error_write(srv, __FILE__, __LINE__, "sbd",
730
730
"ldap: invalid character (a-zA-Z0-9 allowed) in username:", username, i);
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);
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))) {
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))) {
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);
758
758
if (NULL == (first = ldap_first_entry(p->conf.ldap, lm))) {
759
759
log_error_write(srv, __FILE__, __LINE__, "s", "ldap ...");
761
761
ldap_msgfree(lm);
766
766
if (NULL == (dn = ldap_get_dn(p->conf.ldap, first))) {
767
767
log_error_write(srv, __FILE__, __LINE__, "s", "ldap ...");
769
769
ldap_msgfree(lm);
774
774
ldap_msgfree(lm);
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));
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));
787
787
ldap_unbind_s(ldap);
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));
796
796
ldap_unbind_s(ldap);
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));
806
806
ldap_unbind_s(ldap);
812
812
ldap_unbind_s(ldap);
814
814
/* everything worked, good, access granted */
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;
826
826
data_string *realm;
828
828
realm = (data_string *)array_get_element(req, "realm");
830
830
username = buffer_init();
831
831
password = buffer_init();
833
833
base64_decode(username, realm_str);
835
835
/* r2 == user:password */
836
836
if (NULL == (pw = strchr(username->ptr, ':'))) {
837
837
buffer_free(username);
839
839
log_error_write(srv, __FILE__, __LINE__, "sb", ": is missing in", username);
846
846
username->used = pw - username->ptr;
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);
853
853
log_error_write(srv, __FILE__, __LINE__, "s", "get_password failed");
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);
862
862
buffer_free(username);
863
863
buffer_free(password);
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);
873
873
log_error_write(srv, __FILE__, __LINE__, "s", "rules didn't match");
878
878
/* remember the username */
879
879
buffer_copy_string_buffer(p->auth_user, username);
881
881
buffer_free(username);
882
882
buffer_free(password);
1003
1003
log_error_write(srv, __FILE__, __LINE__, "ss", "nc", nc);
1004
1004
log_error_write(srv, __FILE__, __LINE__, "ss", "response", respons);
1007
1007
/* check if everything is transmitted */
1012
1012
(qop && (!nc || !cnonce)) ||
1014
1014
/* missing field */
1016
log_error_write(srv, __FILE__, __LINE__, "s",
1016
log_error_write(srv, __FILE__, __LINE__, "s",
1017
1017
"digest: missing field");
1021
m = get_http_method_name(con->request.http_method);
1021
m = get_http_method_name(con->request.http_method);
1023
1023
/* password-string == HA1 */
1024
1024
password = buffer_init();
1100
1100
MD5_Update(&Md5Ctx, (unsigned char *)HA2Hex, HASHHEXLEN);
1101
1101
MD5_Final(RespHash, &Md5Ctx);
1102
1102
CvtHex(RespHash, a2);
1104
1104
if (0 != strcmp(a2, respons)) {
1105
1105
/* digest not ok */
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);
1112
log_error_write(srv, __FILE__, __LINE__, "sss",
1112
log_error_write(srv, __FILE__, __LINE__, "sss",
1113
1113
"digest: auth failed for", username, "wrong password");
1115
1115
buffer_free(b);
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);
1123
log_error_write(srv, __FILE__, __LINE__, "s",
1123
log_error_write(srv, __FILE__, __LINE__, "s",
1124
1124
"digest: rules did match");
1129
1129
/* remember the username */
1130
1130
buffer_copy_string(p->auth_user, username);
1132
1132
buffer_free(b);
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");