xref: /lighttpd1.4/src/mod_auth.c (revision 4a6ce4ae)
1bcdc6a3bSJan Kneschke #include <sys/types.h>
2bcdc6a3bSJan Kneschke #include <sys/stat.h>
3bcdc6a3bSJan Kneschke 
4bcdc6a3bSJan Kneschke #include <stdlib.h>
5bcdc6a3bSJan Kneschke #include <string.h>
6bcdc6a3bSJan Kneschke #include <errno.h>
7bcdc6a3bSJan Kneschke #include <fcntl.h>
8bcdc6a3bSJan Kneschke #include <unistd.h>
9bcdc6a3bSJan Kneschke 
10bcdc6a3bSJan Kneschke #include "plugin.h"
11bcdc6a3bSJan Kneschke #include "http_auth.h"
12bcdc6a3bSJan Kneschke #include "log.h"
13bcdc6a3bSJan Kneschke #include "response.h"
14bcdc6a3bSJan Kneschke 
15bcdc6a3bSJan Kneschke 
16bcdc6a3bSJan Kneschke /**
17bcdc6a3bSJan Kneschke  * the basic and digest auth framework
18bcdc6a3bSJan Kneschke  *
19bcdc6a3bSJan Kneschke  * - config handling
20bcdc6a3bSJan Kneschke  * - protocol handling
21bcdc6a3bSJan Kneschke  *
22bcdc6a3bSJan Kneschke  * http_auth.c
23bcdc6a3bSJan Kneschke  * http_auth_digest.c
24bcdc6a3bSJan Kneschke  *
25bcdc6a3bSJan Kneschke  * do the real work
26bcdc6a3bSJan Kneschke  */
27bcdc6a3bSJan Kneschke 
28bcdc6a3bSJan Kneschke INIT_FUNC(mod_auth_init) {
29bcdc6a3bSJan Kneschke 	mod_auth_plugin_data *p;
30bcdc6a3bSJan Kneschke 
31bcdc6a3bSJan Kneschke 	p = calloc(1, sizeof(*p));
32bcdc6a3bSJan Kneschke 
33bcdc6a3bSJan Kneschke 	p->tmp_buf = buffer_init();
34bcdc6a3bSJan Kneschke 
35bcdc6a3bSJan Kneschke 	p->auth_user = buffer_init();
36bcdc6a3bSJan Kneschke #ifdef USE_LDAP
37bcdc6a3bSJan Kneschke 	p->ldap_filter = buffer_init();
38bcdc6a3bSJan Kneschke #endif
39bcdc6a3bSJan Kneschke 
40bcdc6a3bSJan Kneschke 	return p;
41bcdc6a3bSJan Kneschke }
42bcdc6a3bSJan Kneschke 
43bcdc6a3bSJan Kneschke FREE_FUNC(mod_auth_free) {
44bcdc6a3bSJan Kneschke 	mod_auth_plugin_data *p = p_d;
45bcdc6a3bSJan Kneschke 
46bcdc6a3bSJan Kneschke 	UNUSED(srv);
47bcdc6a3bSJan Kneschke 
48bcdc6a3bSJan Kneschke 	if (!p) return HANDLER_GO_ON;
49bcdc6a3bSJan Kneschke 
50bcdc6a3bSJan Kneschke 	buffer_free(p->tmp_buf);
51bcdc6a3bSJan Kneschke 	buffer_free(p->auth_user);
52bcdc6a3bSJan Kneschke #ifdef USE_LDAP
53bcdc6a3bSJan Kneschke 	buffer_free(p->ldap_filter);
54bcdc6a3bSJan Kneschke #endif
55bcdc6a3bSJan Kneschke 
56bcdc6a3bSJan Kneschke 	if (p->config_storage) {
57bcdc6a3bSJan Kneschke 		size_t i;
58bcdc6a3bSJan Kneschke 		for (i = 0; i < srv->config_context->used; i++) {
59bcdc6a3bSJan Kneschke 			mod_auth_plugin_config *s = p->config_storage[i];
60bcdc6a3bSJan Kneschke 
61*4a6ce4aeSJan Kneschke 			if (!s) continue;
62*4a6ce4aeSJan Kneschke 
63bcdc6a3bSJan Kneschke 			array_free(s->auth_require);
64bcdc6a3bSJan Kneschke 			buffer_free(s->auth_plain_groupfile);
65bcdc6a3bSJan Kneschke 			buffer_free(s->auth_plain_userfile);
66bcdc6a3bSJan Kneschke 			buffer_free(s->auth_htdigest_userfile);
67bcdc6a3bSJan Kneschke 			buffer_free(s->auth_htpasswd_userfile);
68bcdc6a3bSJan Kneschke 			buffer_free(s->auth_backend_conf);
69bcdc6a3bSJan Kneschke 
70bcdc6a3bSJan Kneschke 			buffer_free(s->auth_ldap_hostname);
71bcdc6a3bSJan Kneschke 			buffer_free(s->auth_ldap_basedn);
72bcdc6a3bSJan Kneschke 			buffer_free(s->auth_ldap_filter);
73*4a6ce4aeSJan Kneschke 			buffer_free(s->auth_ldap_cafile);
74bcdc6a3bSJan Kneschke 
75bcdc6a3bSJan Kneschke #ifdef USE_LDAP
76bcdc6a3bSJan Kneschke 			buffer_free(s->ldap_filter_pre);
77bcdc6a3bSJan Kneschke 			buffer_free(s->ldap_filter_post);
78bcdc6a3bSJan Kneschke 
79bcdc6a3bSJan Kneschke 			if (s->ldap) ldap_unbind_s(s->ldap);
80bcdc6a3bSJan Kneschke #endif
81bcdc6a3bSJan Kneschke 
82bcdc6a3bSJan Kneschke 			free(s);
83bcdc6a3bSJan Kneschke 		}
84bcdc6a3bSJan Kneschke 		free(p->config_storage);
85bcdc6a3bSJan Kneschke 	}
86bcdc6a3bSJan Kneschke 
87bcdc6a3bSJan Kneschke 	free(p);
88bcdc6a3bSJan Kneschke 
89bcdc6a3bSJan Kneschke 	return HANDLER_GO_ON;
90bcdc6a3bSJan Kneschke }
91bcdc6a3bSJan Kneschke 
92bcdc6a3bSJan Kneschke #define PATCH(x) \
93bcdc6a3bSJan Kneschke 	p->conf.x = s->x;
94*4a6ce4aeSJan Kneschke static int mod_auth_patch_connection(server *srv, connection *con, mod_auth_plugin_data *p) {
95bcdc6a3bSJan Kneschke 	size_t i, j;
96*4a6ce4aeSJan Kneschke 	mod_auth_plugin_config *s = p->config_storage[0];
97*4a6ce4aeSJan Kneschke 
98*4a6ce4aeSJan Kneschke 	PATCH(auth_backend);
99*4a6ce4aeSJan Kneschke 	PATCH(auth_plain_groupfile);
100*4a6ce4aeSJan Kneschke 	PATCH(auth_plain_userfile);
101*4a6ce4aeSJan Kneschke 	PATCH(auth_htdigest_userfile);
102*4a6ce4aeSJan Kneschke 	PATCH(auth_htpasswd_userfile);
103*4a6ce4aeSJan Kneschke 	PATCH(auth_require);
104*4a6ce4aeSJan Kneschke 	PATCH(auth_debug);
105*4a6ce4aeSJan Kneschke 	PATCH(auth_ldap_hostname);
106*4a6ce4aeSJan Kneschke 	PATCH(auth_ldap_basedn);
107*4a6ce4aeSJan Kneschke 	PATCH(auth_ldap_filter);
108*4a6ce4aeSJan Kneschke 	PATCH(auth_ldap_cafile);
109*4a6ce4aeSJan Kneschke 	PATCH(auth_ldap_starttls);
110*4a6ce4aeSJan Kneschke #ifdef USE_LDAP
111*4a6ce4aeSJan Kneschke 	PATCH(ldap);
112*4a6ce4aeSJan Kneschke 	PATCH(ldap_filter_pre);
113*4a6ce4aeSJan Kneschke 	PATCH(ldap_filter_post);
114*4a6ce4aeSJan Kneschke #endif
115bcdc6a3bSJan Kneschke 
116bcdc6a3bSJan Kneschke 	/* skip the first, the global context */
117bcdc6a3bSJan Kneschke 	for (i = 1; i < srv->config_context->used; i++) {
118bcdc6a3bSJan Kneschke 		data_config *dc = (data_config *)srv->config_context->data[i];
119*4a6ce4aeSJan Kneschke 		s = p->config_storage[i];
120bcdc6a3bSJan Kneschke 
121bcdc6a3bSJan Kneschke 		/* condition didn't match */
122bcdc6a3bSJan Kneschke 		if (!config_check_cond(srv, con, dc)) continue;
123bcdc6a3bSJan Kneschke 
124bcdc6a3bSJan Kneschke 		/* merge config */
125bcdc6a3bSJan Kneschke 		for (j = 0; j < dc->value->used; j++) {
126bcdc6a3bSJan Kneschke 			data_unset *du = dc->value->data[j];
127bcdc6a3bSJan Kneschke 
128bcdc6a3bSJan Kneschke 			if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend"))) {
129bcdc6a3bSJan Kneschke 				PATCH(auth_backend);
130bcdc6a3bSJan Kneschke 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.plain.groupfile"))) {
131bcdc6a3bSJan Kneschke 				PATCH(auth_plain_groupfile);
132bcdc6a3bSJan Kneschke 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.plain.userfile"))) {
133bcdc6a3bSJan Kneschke 				PATCH(auth_plain_userfile);
134bcdc6a3bSJan Kneschke 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.htdigest.userfile"))) {
135bcdc6a3bSJan Kneschke 				PATCH(auth_htdigest_userfile);
136bcdc6a3bSJan Kneschke 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.htpasswd.userfile"))) {
137bcdc6a3bSJan Kneschke 				PATCH(auth_htpasswd_userfile);
138bcdc6a3bSJan Kneschke 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.require"))) {
139bcdc6a3bSJan Kneschke 				PATCH(auth_require);
140bcdc6a3bSJan Kneschke 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.debug"))) {
141bcdc6a3bSJan Kneschke 				PATCH(auth_debug);
142bcdc6a3bSJan Kneschke 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.hostname"))) {
143bcdc6a3bSJan Kneschke 				PATCH(auth_ldap_hostname);
144bcdc6a3bSJan Kneschke #ifdef USE_LDAP
145bcdc6a3bSJan Kneschke 				PATCH(ldap);
146bcdc6a3bSJan Kneschke 				PATCH(ldap_filter_pre);
147bcdc6a3bSJan Kneschke 				PATCH(ldap_filter_post);
148bcdc6a3bSJan Kneschke #endif
149bcdc6a3bSJan Kneschke 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.base-dn"))) {
150bcdc6a3bSJan Kneschke 				PATCH(auth_ldap_basedn);
151bcdc6a3bSJan Kneschke 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.filter"))) {
152bcdc6a3bSJan Kneschke 				PATCH(auth_ldap_filter);
153*4a6ce4aeSJan Kneschke 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.ca-file"))) {
154*4a6ce4aeSJan Kneschke 				PATCH(auth_ldap_cafile);
155*4a6ce4aeSJan Kneschke 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.starttls"))) {
156*4a6ce4aeSJan Kneschke 				PATCH(auth_ldap_starttls);
157bcdc6a3bSJan Kneschke 			}
158bcdc6a3bSJan Kneschke 		}
159bcdc6a3bSJan Kneschke 	}
160bcdc6a3bSJan Kneschke 
161bcdc6a3bSJan Kneschke 	return 0;
162bcdc6a3bSJan Kneschke }
163bcdc6a3bSJan Kneschke #undef PATCH
164bcdc6a3bSJan Kneschke 
165bcdc6a3bSJan Kneschke static handler_t mod_auth_uri_handler(server *srv, connection *con, void *p_d) {
166bcdc6a3bSJan Kneschke 	size_t k;
167bcdc6a3bSJan Kneschke 	int auth_required = 0, auth_satisfied = 0;
168bcdc6a3bSJan Kneschke 	char *http_authorization = NULL;
169bcdc6a3bSJan Kneschke 	data_string *ds;
170bcdc6a3bSJan Kneschke 	mod_auth_plugin_data *p = p_d;
171bcdc6a3bSJan Kneschke 	array *req;
172bcdc6a3bSJan Kneschke 	size_t i;
173bcdc6a3bSJan Kneschke 
174bcdc6a3bSJan Kneschke 	/* select the right config */
175*4a6ce4aeSJan Kneschke 	mod_auth_patch_connection(srv, con, p);
176bcdc6a3bSJan Kneschke 
177bcdc6a3bSJan Kneschke 	if (p->conf.auth_require == NULL) return HANDLER_GO_ON;
178bcdc6a3bSJan Kneschke 
179bcdc6a3bSJan Kneschke 	/*
180bcdc6a3bSJan Kneschke 	 * AUTH
181bcdc6a3bSJan Kneschke 	 *
182bcdc6a3bSJan Kneschke 	 */
183bcdc6a3bSJan Kneschke 
184bcdc6a3bSJan Kneschke 	/* do we have to ask for auth ? */
185bcdc6a3bSJan Kneschke 
186bcdc6a3bSJan Kneschke 	auth_required = 0;
187bcdc6a3bSJan Kneschke 	auth_satisfied = 0;
188bcdc6a3bSJan Kneschke 
189bcdc6a3bSJan Kneschke 	/* search auth-directives for path */
190bcdc6a3bSJan Kneschke 	for (k = 0; k < p->conf.auth_require->used; k++) {
191bcdc6a3bSJan Kneschke 		if (p->conf.auth_require->data[k]->key->used == 0) continue;
192bcdc6a3bSJan Kneschke 
193bcdc6a3bSJan Kneschke 		if (0 == strncmp(con->uri.path->ptr, p->conf.auth_require->data[k]->key->ptr, p->conf.auth_require->data[k]->key->used - 1)) {
194bcdc6a3bSJan Kneschke 			auth_required = 1;
195bcdc6a3bSJan Kneschke 			break;
196bcdc6a3bSJan Kneschke 		}
197bcdc6a3bSJan Kneschke 	}
198bcdc6a3bSJan Kneschke 
199bcdc6a3bSJan Kneschke 	/* nothing to do for us */
200bcdc6a3bSJan Kneschke 	if (auth_required == 0) return HANDLER_GO_ON;
201bcdc6a3bSJan Kneschke 
202bcdc6a3bSJan Kneschke 	req = ((data_array *)(p->conf.auth_require->data[k]))->value;
203bcdc6a3bSJan Kneschke 
204bcdc6a3bSJan Kneschke 	/* try to get Authorization-header */
205bcdc6a3bSJan Kneschke 
206bcdc6a3bSJan Kneschke 	if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Authorization"))) {
207bcdc6a3bSJan Kneschke 		http_authorization = ds->value->ptr;
208bcdc6a3bSJan Kneschke 	}
209bcdc6a3bSJan Kneschke 
210bcdc6a3bSJan Kneschke 	if (ds && ds->value && ds->value->used) {
211bcdc6a3bSJan Kneschke 		char *auth_realm;
212bcdc6a3bSJan Kneschke 		data_string *method;
213bcdc6a3bSJan Kneschke 
214bcdc6a3bSJan Kneschke 		method = (data_string *)array_get_element(req, "method");
215bcdc6a3bSJan Kneschke 
216bcdc6a3bSJan Kneschke 		/* parse auth-header */
217bcdc6a3bSJan Kneschke 		if (NULL != (auth_realm = strchr(http_authorization, ' '))) {
218bcdc6a3bSJan Kneschke 			int auth_type_len = auth_realm - http_authorization;
219bcdc6a3bSJan Kneschke 
220bcdc6a3bSJan Kneschke 			if ((auth_type_len == 5) &&
221bcdc6a3bSJan Kneschke 			    (0 == strncmp(http_authorization, "Basic", auth_type_len))) {
222bcdc6a3bSJan Kneschke 
223bcdc6a3bSJan Kneschke 				if (0 == strcmp(method->value->ptr, "basic")) {
224bcdc6a3bSJan Kneschke 					auth_satisfied = http_auth_basic_check(srv, con, p, req, con->uri.path, auth_realm+1);
225bcdc6a3bSJan Kneschke 				}
226bcdc6a3bSJan Kneschke 			} else if ((auth_type_len == 6) &&
227bcdc6a3bSJan Kneschke 				   (0 == strncmp(http_authorization, "Digest", auth_type_len))) {
228bcdc6a3bSJan Kneschke 				if (0 == strcmp(method->value->ptr, "digest")) {
229bcdc6a3bSJan Kneschke 					if (-1 == (auth_satisfied = http_auth_digest_check(srv, con, p, req, con->uri.path, auth_realm+1))) {
230bcdc6a3bSJan Kneschke 						con->http_status = 400;
231bcdc6a3bSJan Kneschke 
232bcdc6a3bSJan Kneschke 						/* a field was missing */
233bcdc6a3bSJan Kneschke 
234bcdc6a3bSJan Kneschke 						return HANDLER_FINISHED;
235bcdc6a3bSJan Kneschke 					}
236bcdc6a3bSJan Kneschke 				}
237bcdc6a3bSJan Kneschke 			} else {
238bcdc6a3bSJan Kneschke 				log_error_write(srv, __FILE__, __LINE__, "ss",
239bcdc6a3bSJan Kneschke 						"unknown authentification type:",
240bcdc6a3bSJan Kneschke 						http_authorization);
241bcdc6a3bSJan Kneschke 			}
242bcdc6a3bSJan Kneschke 		}
243bcdc6a3bSJan Kneschke 	}
244bcdc6a3bSJan Kneschke 
245bcdc6a3bSJan Kneschke 	if (!auth_satisfied) {
246bcdc6a3bSJan Kneschke 		data_string *method, *realm;
247bcdc6a3bSJan Kneschke 		method = (data_string *)array_get_element(req, "method");
248bcdc6a3bSJan Kneschke 		realm = (data_string *)array_get_element(req, "realm");
249bcdc6a3bSJan Kneschke 
250bcdc6a3bSJan Kneschke 		con->http_status = 401;
251bcdc6a3bSJan Kneschke 
252bcdc6a3bSJan Kneschke 		if (0 == strcmp(method->value->ptr, "basic")) {
253bcdc6a3bSJan Kneschke 			buffer_copy_string(p->tmp_buf, "Basic realm=\"");
254bcdc6a3bSJan Kneschke 			buffer_append_string_buffer(p->tmp_buf, realm->value);
255bcdc6a3bSJan Kneschke 			buffer_append_string(p->tmp_buf, "\"");
256bcdc6a3bSJan Kneschke 
257bcdc6a3bSJan Kneschke 			response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(p->tmp_buf));
258bcdc6a3bSJan Kneschke 		} else if (0 == strcmp(method->value->ptr, "digest")) {
259bcdc6a3bSJan Kneschke 			char hh[33];
260bcdc6a3bSJan Kneschke 			http_auth_digest_generate_nonce(srv, p, srv->tmp_buf, hh);
261bcdc6a3bSJan Kneschke 
262bcdc6a3bSJan Kneschke 			buffer_copy_string(p->tmp_buf, "Digest realm=\"");
263bcdc6a3bSJan Kneschke 			buffer_append_string_buffer(p->tmp_buf, realm->value);
264bcdc6a3bSJan Kneschke 			buffer_append_string(p->tmp_buf, "\", nonce=\"");
265bcdc6a3bSJan Kneschke 			buffer_append_string(p->tmp_buf, hh);
266bcdc6a3bSJan Kneschke 			buffer_append_string(p->tmp_buf, "\", qop=\"auth\"");
267bcdc6a3bSJan Kneschke 
268bcdc6a3bSJan Kneschke 			response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(p->tmp_buf));
269bcdc6a3bSJan Kneschke 		} else {
270bcdc6a3bSJan Kneschke 			/* evil */
271bcdc6a3bSJan Kneschke 		}
272bcdc6a3bSJan Kneschke 		return HANDLER_FINISHED;
273bcdc6a3bSJan Kneschke 	} else {
274bcdc6a3bSJan Kneschke 		/* the REMOTE_USER header */
275bcdc6a3bSJan Kneschke 
276bcdc6a3bSJan Kneschke 		buffer_copy_string_buffer(con->authed_user, p->auth_user);
277bcdc6a3bSJan Kneschke 	}
278bcdc6a3bSJan Kneschke 
279bcdc6a3bSJan Kneschke 	return HANDLER_GO_ON;
280bcdc6a3bSJan Kneschke }
281bcdc6a3bSJan Kneschke 
282bcdc6a3bSJan Kneschke SETDEFAULTS_FUNC(mod_auth_set_defaults) {
283bcdc6a3bSJan Kneschke 	mod_auth_plugin_data *p = p_d;
284bcdc6a3bSJan Kneschke 	size_t i;
285bcdc6a3bSJan Kneschke 
286bcdc6a3bSJan Kneschke 	config_values_t cv[] = {
287bcdc6a3bSJan Kneschke 		{ "auth.backend",                   NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
288bcdc6a3bSJan Kneschke 		{ "auth.backend.plain.groupfile",   NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
289bcdc6a3bSJan Kneschke 		{ "auth.backend.plain.userfile",    NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
290bcdc6a3bSJan Kneschke 		{ "auth.require",                   NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },
291bcdc6a3bSJan Kneschke 		{ "auth.backend.ldap.hostname",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
292bcdc6a3bSJan Kneschke 		{ "auth.backend.ldap.base-dn",      NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
293bcdc6a3bSJan Kneschke 		{ "auth.backend.ldap.filter",       NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
294*4a6ce4aeSJan Kneschke 		{ "auth.backend.ldap.ca-file",       NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
295*4a6ce4aeSJan Kneschke 		{ "auth.backend.ldap.starttls",     NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
296bcdc6a3bSJan Kneschke 		{ "auth.backend.htdigest.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
297bcdc6a3bSJan Kneschke 		{ "auth.backend.htpasswd.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
298*4a6ce4aeSJan Kneschke 		{ "auth.debug",                     NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 11 */
299bcdc6a3bSJan Kneschke 		{ NULL,                             NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
300bcdc6a3bSJan Kneschke 	};
301bcdc6a3bSJan Kneschke 
302bcdc6a3bSJan Kneschke 	p->config_storage = malloc(srv->config_context->used * sizeof(specific_config *));
303bcdc6a3bSJan Kneschke 
304bcdc6a3bSJan Kneschke 	for (i = 0; i < srv->config_context->used; i++) {
305bcdc6a3bSJan Kneschke 		mod_auth_plugin_config *s;
306bcdc6a3bSJan Kneschke 		size_t n;
307bcdc6a3bSJan Kneschke 		data_array *da;
308bcdc6a3bSJan Kneschke 		array *ca;
309bcdc6a3bSJan Kneschke 
310bcdc6a3bSJan Kneschke 		s = malloc(sizeof(mod_auth_plugin_config));
311bcdc6a3bSJan Kneschke 		s->auth_plain_groupfile = buffer_init();
312bcdc6a3bSJan Kneschke 		s->auth_plain_userfile = buffer_init();
313bcdc6a3bSJan Kneschke 		s->auth_htdigest_userfile = buffer_init();
314bcdc6a3bSJan Kneschke 		s->auth_htpasswd_userfile = buffer_init();
315bcdc6a3bSJan Kneschke 		s->auth_backend_conf = buffer_init();
316bcdc6a3bSJan Kneschke 
317bcdc6a3bSJan Kneschke 		s->auth_ldap_hostname = buffer_init();
318bcdc6a3bSJan Kneschke 		s->auth_ldap_basedn = buffer_init();
319bcdc6a3bSJan Kneschke 		s->auth_ldap_filter = buffer_init();
320*4a6ce4aeSJan Kneschke 		s->auth_ldap_cafile = buffer_init();
321*4a6ce4aeSJan Kneschke 		s->auth_ldap_starttls = 0;
322bcdc6a3bSJan Kneschke 		s->auth_debug = 0;
323bcdc6a3bSJan Kneschke 
324bcdc6a3bSJan Kneschke 		s->auth_require = array_init();
325bcdc6a3bSJan Kneschke 
326bcdc6a3bSJan Kneschke #ifdef USE_LDAP
327bcdc6a3bSJan Kneschke 		s->ldap_filter_pre = buffer_init();
328bcdc6a3bSJan Kneschke 		s->ldap_filter_post = buffer_init();
329bcdc6a3bSJan Kneschke 		s->ldap = NULL;
330bcdc6a3bSJan Kneschke #endif
331bcdc6a3bSJan Kneschke 
332bcdc6a3bSJan Kneschke 		cv[0].destination = s->auth_backend_conf;
333bcdc6a3bSJan Kneschke 		cv[1].destination = s->auth_plain_groupfile;
334bcdc6a3bSJan Kneschke 		cv[2].destination = s->auth_plain_userfile;
335bcdc6a3bSJan Kneschke 		cv[3].destination = s->auth_require;
336bcdc6a3bSJan Kneschke 		cv[4].destination = s->auth_ldap_hostname;
337bcdc6a3bSJan Kneschke 		cv[5].destination = s->auth_ldap_basedn;
338bcdc6a3bSJan Kneschke 		cv[6].destination = s->auth_ldap_filter;
339*4a6ce4aeSJan Kneschke 		cv[7].destination = s->auth_ldap_cafile;
340*4a6ce4aeSJan Kneschke 		cv[8].destination = &(s->auth_ldap_starttls);
341*4a6ce4aeSJan Kneschke 		cv[9].destination = s->auth_htdigest_userfile;
342*4a6ce4aeSJan Kneschke 		cv[10].destination = s->auth_htpasswd_userfile;
343*4a6ce4aeSJan Kneschke 		cv[11].destination = &(s->auth_debug);
344bcdc6a3bSJan Kneschke 
345bcdc6a3bSJan Kneschke 		p->config_storage[i] = s;
346bcdc6a3bSJan Kneschke 		ca = ((data_config *)srv->config_context->data[i])->value;
347bcdc6a3bSJan Kneschke 
348bcdc6a3bSJan Kneschke 		if (0 != config_insert_values_global(srv, ca, cv)) {
349bcdc6a3bSJan Kneschke 			return HANDLER_ERROR;
350bcdc6a3bSJan Kneschke 		}
351bcdc6a3bSJan Kneschke 
352bcdc6a3bSJan Kneschke 		if (s->auth_backend_conf->used) {
353bcdc6a3bSJan Kneschke 			if (0 == strcmp(s->auth_backend_conf->ptr, "htpasswd")) {
354bcdc6a3bSJan Kneschke 				s->auth_backend = AUTH_BACKEND_HTPASSWD;
355bcdc6a3bSJan Kneschke 			} else if (0 == strcmp(s->auth_backend_conf->ptr, "htdigest")) {
356bcdc6a3bSJan Kneschke 				s->auth_backend = AUTH_BACKEND_HTDIGEST;
357bcdc6a3bSJan Kneschke 			} else if (0 == strcmp(s->auth_backend_conf->ptr, "plain")) {
358bcdc6a3bSJan Kneschke 				s->auth_backend = AUTH_BACKEND_PLAIN;
359bcdc6a3bSJan Kneschke 			} else if (0 == strcmp(s->auth_backend_conf->ptr, "ldap")) {
360bcdc6a3bSJan Kneschke 				s->auth_backend = AUTH_BACKEND_LDAP;
361bcdc6a3bSJan Kneschke 			} else {
362bcdc6a3bSJan Kneschke 				log_error_write(srv, __FILE__, __LINE__, "sb", "auth.backend not supported:", s->auth_backend_conf);
363bcdc6a3bSJan Kneschke 
364bcdc6a3bSJan Kneschke 				return HANDLER_ERROR;
365bcdc6a3bSJan Kneschke 			}
366bcdc6a3bSJan Kneschke 		}
367bcdc6a3bSJan Kneschke 
368bcdc6a3bSJan Kneschke 		/* no auth.require for this section */
369bcdc6a3bSJan Kneschke 		if (NULL == (da = (data_array *)array_get_element(ca, "auth.require"))) continue;
370bcdc6a3bSJan Kneschke 
371bcdc6a3bSJan Kneschke 		if (da->type != TYPE_ARRAY) continue;
372bcdc6a3bSJan Kneschke 
373bcdc6a3bSJan Kneschke 		for (n = 0; n < da->value->used; n++) {
374bcdc6a3bSJan Kneschke 			size_t m;
375bcdc6a3bSJan Kneschke 			data_array *da_file = (data_array *)da->value->data[n];
376bcdc6a3bSJan Kneschke 			const char *method, *realm, *require;
377bcdc6a3bSJan Kneschke 
378bcdc6a3bSJan Kneschke 			if (da->value->data[n]->type != TYPE_ARRAY) {
379bcdc6a3bSJan Kneschke 				log_error_write(srv, __FILE__, __LINE__, "sssbs",
380bcdc6a3bSJan Kneschke 						"unexpected type for key: ", "auth.require", "[", da->value->data[n]->key, "](string)");
381bcdc6a3bSJan Kneschke 
382bcdc6a3bSJan Kneschke 				return HANDLER_ERROR;
383bcdc6a3bSJan Kneschke 			}
384bcdc6a3bSJan Kneschke 
385bcdc6a3bSJan Kneschke 			method = realm = require = NULL;
386bcdc6a3bSJan Kneschke 
387bcdc6a3bSJan Kneschke 			for (m = 0; m < da_file->value->used; m++) {
388bcdc6a3bSJan Kneschke 				if (da_file->value->data[m]->type == TYPE_STRING) {
389bcdc6a3bSJan Kneschke 					if (0 == strcmp(da_file->value->data[m]->key->ptr, "method")) {
390bcdc6a3bSJan Kneschke 						method = ((data_string *)(da_file->value->data[m]))->value->ptr;
391bcdc6a3bSJan Kneschke 					} else if (0 == strcmp(da_file->value->data[m]->key->ptr, "realm")) {
392bcdc6a3bSJan Kneschke 						realm = ((data_string *)(da_file->value->data[m]))->value->ptr;
393bcdc6a3bSJan Kneschke 					} else if (0 == strcmp(da_file->value->data[m]->key->ptr, "require")) {
394bcdc6a3bSJan Kneschke 						require = ((data_string *)(da_file->value->data[m]))->value->ptr;
395bcdc6a3bSJan Kneschke 					} else {
396bcdc6a3bSJan Kneschke 						log_error_write(srv, __FILE__, __LINE__, "sssbs", "unexpected type for key: ", "auth.require", "[", da_file->value->data[m]->key, "](string)");
397bcdc6a3bSJan Kneschke 						return HANDLER_ERROR;
398bcdc6a3bSJan Kneschke 					}
399bcdc6a3bSJan Kneschke 				} else {
400bcdc6a3bSJan Kneschke 					log_error_write(srv, __FILE__, __LINE__, "sssbs", "unexpected type for key: ", "auth.require", "[", da_file->value->data[m]->key, "](string)");
401bcdc6a3bSJan Kneschke 
402bcdc6a3bSJan Kneschke 					return HANDLER_ERROR;
403bcdc6a3bSJan Kneschke 				}
404bcdc6a3bSJan Kneschke 			}
405bcdc6a3bSJan Kneschke 
406bcdc6a3bSJan Kneschke 			if (method == NULL) {
407bcdc6a3bSJan Kneschke 				log_error_write(srv, __FILE__, __LINE__, "sssss", "missing entry for key: ", "auth.require", "[", "method", "](string)");
408bcdc6a3bSJan Kneschke 				return HANDLER_ERROR;
409*4a6ce4aeSJan Kneschke 			} else {
410*4a6ce4aeSJan Kneschke 				if (0 != strcmp(method, "basic") &&
411*4a6ce4aeSJan Kneschke 				    0 != strcmp(method, "digest")) {
412*4a6ce4aeSJan Kneschke 					log_error_write(srv, __FILE__, __LINE__, "sssss", "auth.require->method has to be either 'basic' or 'digest'");
413*4a6ce4aeSJan Kneschke 					return HANDLER_ERROR;
414*4a6ce4aeSJan Kneschke 				}
415bcdc6a3bSJan Kneschke 			}
416bcdc6a3bSJan Kneschke 
417bcdc6a3bSJan Kneschke 			if (realm == NULL) {
418bcdc6a3bSJan Kneschke 				log_error_write(srv, __FILE__, __LINE__, "sssss", "missing entry for key: ", "auth.require", "[", "realm", "](string)");
419bcdc6a3bSJan Kneschke 				return HANDLER_ERROR;
420bcdc6a3bSJan Kneschke 			}
421bcdc6a3bSJan Kneschke 
422bcdc6a3bSJan Kneschke 			if (require == NULL) {
423bcdc6a3bSJan Kneschke 				log_error_write(srv, __FILE__, __LINE__, "sssss", "missing entry for key: ", "auth.require", "[", "require", "](string)");
424bcdc6a3bSJan Kneschke 				return HANDLER_ERROR;
425bcdc6a3bSJan Kneschke 			}
426bcdc6a3bSJan Kneschke 
427bcdc6a3bSJan Kneschke 			if (method && realm && require) {
428bcdc6a3bSJan Kneschke 				data_string *ds;
429bcdc6a3bSJan Kneschke 				data_array *a;
430bcdc6a3bSJan Kneschke 
431bcdc6a3bSJan Kneschke 				a = data_array_init();
432bcdc6a3bSJan Kneschke 				buffer_copy_string_buffer(a->key, da_file->key);
433bcdc6a3bSJan Kneschke 
434bcdc6a3bSJan Kneschke 				ds = data_string_init();
435bcdc6a3bSJan Kneschke 
436bcdc6a3bSJan Kneschke 				buffer_copy_string(ds->key, "method");
437bcdc6a3bSJan Kneschke 				buffer_copy_string(ds->value, method);
438bcdc6a3bSJan Kneschke 
439bcdc6a3bSJan Kneschke 				array_insert_unique(a->value, (data_unset *)ds);
440bcdc6a3bSJan Kneschke 
441bcdc6a3bSJan Kneschke 				ds = data_string_init();
442bcdc6a3bSJan Kneschke 
443bcdc6a3bSJan Kneschke 				buffer_copy_string(ds->key, "realm");
444bcdc6a3bSJan Kneschke 				buffer_copy_string(ds->value, realm);
445bcdc6a3bSJan Kneschke 
446bcdc6a3bSJan Kneschke 				array_insert_unique(a->value, (data_unset *)ds);
447bcdc6a3bSJan Kneschke 
448bcdc6a3bSJan Kneschke 				ds = data_string_init();
449bcdc6a3bSJan Kneschke 
450bcdc6a3bSJan Kneschke 				buffer_copy_string(ds->key, "require");
451bcdc6a3bSJan Kneschke 				buffer_copy_string(ds->value, require);
452bcdc6a3bSJan Kneschke 
453bcdc6a3bSJan Kneschke 				array_insert_unique(a->value, (data_unset *)ds);
454bcdc6a3bSJan Kneschke 
455bcdc6a3bSJan Kneschke 				array_insert_unique(s->auth_require, (data_unset *)a);
456bcdc6a3bSJan Kneschke 			}
457bcdc6a3bSJan Kneschke 		}
458bcdc6a3bSJan Kneschke 
459bcdc6a3bSJan Kneschke 		switch(s->auth_backend) {
460bcdc6a3bSJan Kneschke 		case AUTH_BACKEND_PLAIN:
461bcdc6a3bSJan Kneschke 			if (s->auth_plain_userfile->used) {
462bcdc6a3bSJan Kneschke 				int fd;
463bcdc6a3bSJan Kneschke 				/* try to read */
464bcdc6a3bSJan Kneschke 				if (-1 == (fd = open(s->auth_plain_userfile->ptr, O_RDONLY))) {
465bcdc6a3bSJan Kneschke 					log_error_write(srv, __FILE__, __LINE__, "sbss",
466bcdc6a3bSJan Kneschke 							"opening auth.backend.plain.userfile:", s->auth_plain_userfile,
467bcdc6a3bSJan Kneschke 							"failed:", strerror(errno));
468bcdc6a3bSJan Kneschke 					return HANDLER_ERROR;
469bcdc6a3bSJan Kneschke 				}
470bcdc6a3bSJan Kneschke 				close(fd);
471bcdc6a3bSJan Kneschke 			}
472bcdc6a3bSJan Kneschke 			break;
473bcdc6a3bSJan Kneschke 		case AUTH_BACKEND_HTPASSWD:
474bcdc6a3bSJan Kneschke 			if (s->auth_htpasswd_userfile->used) {
475bcdc6a3bSJan Kneschke 				int fd;
476bcdc6a3bSJan Kneschke 				/* try to read */
477bcdc6a3bSJan Kneschke 				if (-1 == (fd = open(s->auth_htpasswd_userfile->ptr, O_RDONLY))) {
478bcdc6a3bSJan Kneschke 					log_error_write(srv, __FILE__, __LINE__, "sbss",
479bcdc6a3bSJan Kneschke 							"opening auth.backend.htpasswd.userfile:", s->auth_htpasswd_userfile,
480bcdc6a3bSJan Kneschke 							"failed:", strerror(errno));
481bcdc6a3bSJan Kneschke 					return HANDLER_ERROR;
482bcdc6a3bSJan Kneschke 				}
483bcdc6a3bSJan Kneschke 				close(fd);
484bcdc6a3bSJan Kneschke 			}
485bcdc6a3bSJan Kneschke 			break;
486bcdc6a3bSJan Kneschke 		case AUTH_BACKEND_HTDIGEST:
487bcdc6a3bSJan Kneschke 			if (s->auth_htdigest_userfile->used) {
488bcdc6a3bSJan Kneschke 				int fd;
489bcdc6a3bSJan Kneschke 				/* try to read */
490bcdc6a3bSJan Kneschke 				if (-1 == (fd = open(s->auth_htdigest_userfile->ptr, O_RDONLY))) {
491bcdc6a3bSJan Kneschke 					log_error_write(srv, __FILE__, __LINE__, "sbss",
492bcdc6a3bSJan Kneschke 							"opening auth.backend.htdigest.userfile:", s->auth_htdigest_userfile,
493bcdc6a3bSJan Kneschke 							"failed:", strerror(errno));
494bcdc6a3bSJan Kneschke 					return HANDLER_ERROR;
495bcdc6a3bSJan Kneschke 				}
496bcdc6a3bSJan Kneschke 				close(fd);
497bcdc6a3bSJan Kneschke 			}
498bcdc6a3bSJan Kneschke 			break;
499bcdc6a3bSJan Kneschke 		case AUTH_BACKEND_LDAP:
500bcdc6a3bSJan Kneschke #ifdef USE_LDAP
501bcdc6a3bSJan Kneschke #if 0
502bcdc6a3bSJan Kneschke 			if (s->auth_ldap_basedn->used == 0) {
503bcdc6a3bSJan Kneschke 				log_error_write(srv, __FILE__, __LINE__, "s", "ldap: auth.backend.ldap.base-dn has to be set");
504bcdc6a3bSJan Kneschke 
505bcdc6a3bSJan Kneschke 				return HANDLER_ERROR;
506bcdc6a3bSJan Kneschke 			}
507bcdc6a3bSJan Kneschke #endif
508bcdc6a3bSJan Kneschke 
509bcdc6a3bSJan Kneschke 			if (s->auth_ldap_filter->used) {
510bcdc6a3bSJan Kneschke 				char *dollar;
511bcdc6a3bSJan Kneschke 
512bcdc6a3bSJan Kneschke 				/* parse filter */
513bcdc6a3bSJan Kneschke 
514bcdc6a3bSJan Kneschke 				if (NULL == (dollar = strchr(s->auth_ldap_filter->ptr, '$'))) {
515bcdc6a3bSJan Kneschke 					log_error_write(srv, __FILE__, __LINE__, "s", "ldap: auth.backend.ldap.filter is missing a replace-operator '$'");
516bcdc6a3bSJan Kneschke 
517bcdc6a3bSJan Kneschke 					return HANDLER_ERROR;
518bcdc6a3bSJan Kneschke 				}
519bcdc6a3bSJan Kneschke 
520bcdc6a3bSJan Kneschke 				buffer_copy_string_len(s->ldap_filter_pre, s->auth_ldap_filter->ptr, dollar - s->auth_ldap_filter->ptr);
521bcdc6a3bSJan Kneschke 				buffer_copy_string(s->ldap_filter_post, dollar+1);
522bcdc6a3bSJan Kneschke 			}
523bcdc6a3bSJan Kneschke 
524bcdc6a3bSJan Kneschke 			if (s->auth_ldap_hostname->used) {
525bcdc6a3bSJan Kneschke 				int ret;
526bcdc6a3bSJan Kneschke 				if (NULL == (s->ldap = ldap_init(s->auth_ldap_hostname->ptr, LDAP_PORT))) {
527bcdc6a3bSJan Kneschke 					log_error_write(srv, __FILE__, __LINE__, "ss", "ldap ...", strerror(errno));
528bcdc6a3bSJan Kneschke 
529bcdc6a3bSJan Kneschke 					return HANDLER_ERROR;
530bcdc6a3bSJan Kneschke 				}
531bcdc6a3bSJan Kneschke 
532bcdc6a3bSJan Kneschke 				ret = LDAP_VERSION3;
533bcdc6a3bSJan Kneschke 				if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(s->ldap, LDAP_OPT_PROTOCOL_VERSION, &ret))) {
534bcdc6a3bSJan Kneschke 					log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
535bcdc6a3bSJan Kneschke 
536bcdc6a3bSJan Kneschke 					return HANDLER_ERROR;
537bcdc6a3bSJan Kneschke 				}
538bcdc6a3bSJan Kneschke 
539*4a6ce4aeSJan Kneschke 				if (s->auth_ldap_starttls) {
540*4a6ce4aeSJan Kneschke 					if (buffer_is_empty(s->auth_ldap_cafile)) {
541*4a6ce4aeSJan Kneschke 						log_error_write(srv, __FILE__, __LINE__, "s", "CA file has to be set");
542*4a6ce4aeSJan Kneschke 
543*4a6ce4aeSJan Kneschke 						return HANDLER_ERROR;
544*4a6ce4aeSJan Kneschke 
545*4a6ce4aeSJan Kneschke 					}
546*4a6ce4aeSJan Kneschke 
547*4a6ce4aeSJan Kneschke 					if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, s->auth_ldap_cafile->ptr))) {
548*4a6ce4aeSJan Kneschke 						log_error_write(srv, __FILE__, __LINE__, "ss", "Loading CA certificate failed:", ldap_err2string(ret));
549*4a6ce4aeSJan Kneschke 
550*4a6ce4aeSJan Kneschke 						return HANDLER_ERROR;
551*4a6ce4aeSJan Kneschke 					}
552*4a6ce4aeSJan Kneschke 
553*4a6ce4aeSJan Kneschke 					if (LDAP_OPT_SUCCESS != (ret = ldap_start_tls_s(s->ldap, NULL,  NULL))) {
554*4a6ce4aeSJan Kneschke 						log_error_write(srv, __FILE__, __LINE__, "ss", "ldap startTLS failed:", ldap_err2string(ret));
555*4a6ce4aeSJan Kneschke 
556*4a6ce4aeSJan Kneschke 						return HANDLER_ERROR;
557*4a6ce4aeSJan Kneschke 					}
558*4a6ce4aeSJan Kneschke 				}
559*4a6ce4aeSJan Kneschke 
560bcdc6a3bSJan Kneschke 
561bcdc6a3bSJan Kneschke 				/* 1. */
562bcdc6a3bSJan Kneschke 				if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(s->ldap, NULL, NULL))) {
563bcdc6a3bSJan Kneschke 					log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
564bcdc6a3bSJan Kneschke 
565bcdc6a3bSJan Kneschke 					return HANDLER_ERROR;
566bcdc6a3bSJan Kneschke 				}
567bcdc6a3bSJan Kneschke 			}
568bcdc6a3bSJan Kneschke #else
569bcdc6a3bSJan Kneschke 			log_error_write(srv, __FILE__, __LINE__, "s", "no ldap support available");
570bcdc6a3bSJan Kneschke 			return HANDLER_ERROR;
571bcdc6a3bSJan Kneschke #endif
572bcdc6a3bSJan Kneschke 			break;
573bcdc6a3bSJan Kneschke 		default:
574bcdc6a3bSJan Kneschke 			break;
575bcdc6a3bSJan Kneschke 		}
576bcdc6a3bSJan Kneschke 	}
577bcdc6a3bSJan Kneschke 
578bcdc6a3bSJan Kneschke 	return HANDLER_GO_ON;
579bcdc6a3bSJan Kneschke }
580bcdc6a3bSJan Kneschke 
581bcdc6a3bSJan Kneschke int mod_auth_plugin_init(plugin *p) {
582bcdc6a3bSJan Kneschke 	p->version     = LIGHTTPD_VERSION_ID;
583bcdc6a3bSJan Kneschke 	p->name        = buffer_init_string("auth");
584bcdc6a3bSJan Kneschke 	p->init        = mod_auth_init;
585bcdc6a3bSJan Kneschke 	p->set_defaults = mod_auth_set_defaults;
586bcdc6a3bSJan Kneschke 	p->handle_uri_clean = mod_auth_uri_handler;
587bcdc6a3bSJan Kneschke 	p->cleanup     = mod_auth_free;
588bcdc6a3bSJan Kneschke 
589bcdc6a3bSJan Kneschke 	p->data        = NULL;
590bcdc6a3bSJan Kneschke 
591bcdc6a3bSJan Kneschke 	return 0;
592bcdc6a3bSJan Kneschke }
593