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