xref: /minix/libexec/httpd/auth-bozo.c (revision 340f5e56)
1*340f5e56SDavid van Moolenbroek /*	$NetBSD: auth-bozo.c,v 1.16 2014/12/26 19:52:00 mrg Exp $	*/
2*340f5e56SDavid van Moolenbroek 
3*340f5e56SDavid van Moolenbroek /*	$eterna: auth-bozo.c,v 1.17 2011/11/18 09:21:15 mrg Exp $	*/
4*340f5e56SDavid van Moolenbroek 
5*340f5e56SDavid van Moolenbroek /*
6*340f5e56SDavid van Moolenbroek  * Copyright (c) 1997-2014 Matthew R. Green
7*340f5e56SDavid van Moolenbroek  * All rights reserved.
8*340f5e56SDavid van Moolenbroek  *
9*340f5e56SDavid van Moolenbroek  * Redistribution and use in source and binary forms, with or without
10*340f5e56SDavid van Moolenbroek  * modification, are permitted provided that the following conditions
11*340f5e56SDavid van Moolenbroek  * are met:
12*340f5e56SDavid van Moolenbroek  * 1. Redistributions of source code must retain the above copyright
13*340f5e56SDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer.
14*340f5e56SDavid van Moolenbroek  * 2. Redistributions in binary form must reproduce the above copyright
15*340f5e56SDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer and
16*340f5e56SDavid van Moolenbroek  *    dedication in the documentation and/or other materials provided
17*340f5e56SDavid van Moolenbroek  *    with the distribution.
18*340f5e56SDavid van Moolenbroek  *
19*340f5e56SDavid van Moolenbroek  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20*340f5e56SDavid van Moolenbroek  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21*340f5e56SDavid van Moolenbroek  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22*340f5e56SDavid van Moolenbroek  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23*340f5e56SDavid van Moolenbroek  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24*340f5e56SDavid van Moolenbroek  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25*340f5e56SDavid van Moolenbroek  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26*340f5e56SDavid van Moolenbroek  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27*340f5e56SDavid van Moolenbroek  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28*340f5e56SDavid van Moolenbroek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29*340f5e56SDavid van Moolenbroek  * SUCH DAMAGE.
30*340f5e56SDavid van Moolenbroek  *
31*340f5e56SDavid van Moolenbroek  */
32*340f5e56SDavid van Moolenbroek 
33*340f5e56SDavid van Moolenbroek /* this code implements "http basic authorisation" for bozohttpd */
34*340f5e56SDavid van Moolenbroek 
35*340f5e56SDavid van Moolenbroek #ifdef DO_HTPASSWD
36*340f5e56SDavid van Moolenbroek 
37*340f5e56SDavid van Moolenbroek #include <sys/param.h>
38*340f5e56SDavid van Moolenbroek 
39*340f5e56SDavid van Moolenbroek #include <string.h>
40*340f5e56SDavid van Moolenbroek #include <stdlib.h>
41*340f5e56SDavid van Moolenbroek #include <unistd.h>
42*340f5e56SDavid van Moolenbroek 
43*340f5e56SDavid van Moolenbroek #include "bozohttpd.h"
44*340f5e56SDavid van Moolenbroek 
45*340f5e56SDavid van Moolenbroek #ifndef AUTH_FILE
46*340f5e56SDavid van Moolenbroek #define AUTH_FILE		".htpasswd"
47*340f5e56SDavid van Moolenbroek #endif
48*340f5e56SDavid van Moolenbroek 
49*340f5e56SDavid van Moolenbroek static	ssize_t	base64_decode(const unsigned char *, size_t,
50*340f5e56SDavid van Moolenbroek 			    unsigned char *, size_t);
51*340f5e56SDavid van Moolenbroek 
52*340f5e56SDavid van Moolenbroek /*
53*340f5e56SDavid van Moolenbroek  * Check if HTTP authentication is required
54*340f5e56SDavid van Moolenbroek  */
55*340f5e56SDavid van Moolenbroek int
bozo_auth_check(bozo_httpreq_t * request,const char * file)56*340f5e56SDavid van Moolenbroek bozo_auth_check(bozo_httpreq_t *request, const char *file)
57*340f5e56SDavid van Moolenbroek {
58*340f5e56SDavid van Moolenbroek 	bozohttpd_t *httpd = request->hr_httpd;
59*340f5e56SDavid van Moolenbroek 	struct stat sb;
60*340f5e56SDavid van Moolenbroek 	char dir[MAXPATHLEN], authfile[MAXPATHLEN], *basename;
61*340f5e56SDavid van Moolenbroek 	char user[BUFSIZ], *pass;
62*340f5e56SDavid van Moolenbroek 	FILE *fp;
63*340f5e56SDavid van Moolenbroek 	int len;
64*340f5e56SDavid van Moolenbroek 
65*340f5e56SDavid van Moolenbroek 			/* get dir=dirname(file) */
66*340f5e56SDavid van Moolenbroek 	snprintf(dir, sizeof(dir), "%s", file);
67*340f5e56SDavid van Moolenbroek 	if ((basename = strrchr(dir, '/')) == NULL)
68*340f5e56SDavid van Moolenbroek 		strcpy(dir, ".");
69*340f5e56SDavid van Moolenbroek 	else {
70*340f5e56SDavid van Moolenbroek 		*basename++ = '\0';
71*340f5e56SDavid van Moolenbroek 			/* ensure basename(file) != AUTH_FILE */
72*340f5e56SDavid van Moolenbroek 		if (bozo_check_special_files(request, basename))
73*340f5e56SDavid van Moolenbroek 			return 1;
74*340f5e56SDavid van Moolenbroek 	}
75*340f5e56SDavid van Moolenbroek 	request->hr_authrealm = bozostrdup(httpd, dir);
76*340f5e56SDavid van Moolenbroek 
77*340f5e56SDavid van Moolenbroek 	if ((size_t)snprintf(authfile, sizeof(authfile), "%s/%s", dir, AUTH_FILE) >=
78*340f5e56SDavid van Moolenbroek 	  sizeof(authfile)) {
79*340f5e56SDavid van Moolenbroek 		return bozo_http_error(httpd, 404, request,
80*340f5e56SDavid van Moolenbroek 			"authfile path too long");
81*340f5e56SDavid van Moolenbroek 	}
82*340f5e56SDavid van Moolenbroek 	if (stat(authfile, &sb) < 0) {
83*340f5e56SDavid van Moolenbroek 		debug((httpd, DEBUG_NORMAL,
84*340f5e56SDavid van Moolenbroek 		    "bozo_auth_check realm `%s' dir `%s' authfile `%s' missing",
85*340f5e56SDavid van Moolenbroek 		    dir, file, authfile));
86*340f5e56SDavid van Moolenbroek 		return 0;
87*340f5e56SDavid van Moolenbroek 	}
88*340f5e56SDavid van Moolenbroek 	if ((fp = fopen(authfile, "r")) == NULL)
89*340f5e56SDavid van Moolenbroek 		return bozo_http_error(httpd, 403, request,
90*340f5e56SDavid van Moolenbroek 			"no permission to open authfile");
91*340f5e56SDavid van Moolenbroek 	debug((httpd, DEBUG_NORMAL,
92*340f5e56SDavid van Moolenbroek 	    "bozo_auth_check realm `%s' dir `%s' authfile `%s' open",
93*340f5e56SDavid van Moolenbroek 	    dir, file, authfile));
94*340f5e56SDavid van Moolenbroek 	if (request->hr_authuser && request->hr_authpass) {
95*340f5e56SDavid van Moolenbroek 		while (fgets(user, sizeof(user), fp) != NULL) {
96*340f5e56SDavid van Moolenbroek 			len = strlen(user);
97*340f5e56SDavid van Moolenbroek 			if (len > 0 && user[len-1] == '\n')
98*340f5e56SDavid van Moolenbroek 				user[--len] = '\0';
99*340f5e56SDavid van Moolenbroek 			if ((pass = strchr(user, ':')) == NULL)
100*340f5e56SDavid van Moolenbroek 				continue;
101*340f5e56SDavid van Moolenbroek 			*pass++ = '\0';
102*340f5e56SDavid van Moolenbroek 			debug((httpd, DEBUG_NORMAL,
103*340f5e56SDavid van Moolenbroek 			    "bozo_auth_check authfile `%s':`%s' "
104*340f5e56SDavid van Moolenbroek 			    	"client `%s':`%s'",
105*340f5e56SDavid van Moolenbroek 			    user, pass, request->hr_authuser,
106*340f5e56SDavid van Moolenbroek 			    request->hr_authpass));
107*340f5e56SDavid van Moolenbroek 			if (strcmp(request->hr_authuser, user) != 0)
108*340f5e56SDavid van Moolenbroek 				continue;
109*340f5e56SDavid van Moolenbroek 			if (strcmp(crypt(request->hr_authpass, pass),
110*340f5e56SDavid van Moolenbroek 					pass) != 0)
111*340f5e56SDavid van Moolenbroek 				break;
112*340f5e56SDavid van Moolenbroek 			fclose(fp);
113*340f5e56SDavid van Moolenbroek 			return 0;
114*340f5e56SDavid van Moolenbroek 		}
115*340f5e56SDavid van Moolenbroek 	}
116*340f5e56SDavid van Moolenbroek 	fclose(fp);
117*340f5e56SDavid van Moolenbroek 	return bozo_http_error(httpd, 401, request, "bad auth");
118*340f5e56SDavid van Moolenbroek }
119*340f5e56SDavid van Moolenbroek 
120*340f5e56SDavid van Moolenbroek void
bozo_auth_init(bozo_httpreq_t * request)121*340f5e56SDavid van Moolenbroek bozo_auth_init(bozo_httpreq_t *request)
122*340f5e56SDavid van Moolenbroek {
123*340f5e56SDavid van Moolenbroek 	request->hr_authuser = NULL;
124*340f5e56SDavid van Moolenbroek 	request->hr_authpass = NULL;
125*340f5e56SDavid van Moolenbroek }
126*340f5e56SDavid van Moolenbroek 
127*340f5e56SDavid van Moolenbroek void
bozo_auth_cleanup(bozo_httpreq_t * request)128*340f5e56SDavid van Moolenbroek bozo_auth_cleanup(bozo_httpreq_t *request)
129*340f5e56SDavid van Moolenbroek {
130*340f5e56SDavid van Moolenbroek 
131*340f5e56SDavid van Moolenbroek 	if (request == NULL)
132*340f5e56SDavid van Moolenbroek 		return;
133*340f5e56SDavid van Moolenbroek 	free(request->hr_authuser);
134*340f5e56SDavid van Moolenbroek 	free(request->hr_authpass);
135*340f5e56SDavid van Moolenbroek 	free(request->hr_authrealm);
136*340f5e56SDavid van Moolenbroek }
137*340f5e56SDavid van Moolenbroek 
138*340f5e56SDavid van Moolenbroek int
bozo_auth_check_headers(bozo_httpreq_t * request,char * val,char * str,ssize_t len)139*340f5e56SDavid van Moolenbroek bozo_auth_check_headers(bozo_httpreq_t *request, char *val, char *str, ssize_t len)
140*340f5e56SDavid van Moolenbroek {
141*340f5e56SDavid van Moolenbroek 	bozohttpd_t *httpd = request->hr_httpd;
142*340f5e56SDavid van Moolenbroek 
143*340f5e56SDavid van Moolenbroek 	if (strcasecmp(val, "authorization") == 0 &&
144*340f5e56SDavid van Moolenbroek 	    strncasecmp(str, "Basic ", 6) == 0) {
145*340f5e56SDavid van Moolenbroek 		char	authbuf[BUFSIZ];
146*340f5e56SDavid van Moolenbroek 		char	*pass = NULL;
147*340f5e56SDavid van Moolenbroek 		ssize_t	alen;
148*340f5e56SDavid van Moolenbroek 
149*340f5e56SDavid van Moolenbroek 		alen = base64_decode((unsigned char *)str + 6,
150*340f5e56SDavid van Moolenbroek 					(size_t)(len - 6),
151*340f5e56SDavid van Moolenbroek 					(unsigned char *)authbuf,
152*340f5e56SDavid van Moolenbroek 					sizeof(authbuf) - 1);
153*340f5e56SDavid van Moolenbroek 		if (alen != -1)
154*340f5e56SDavid van Moolenbroek 			authbuf[alen] = '\0';
155*340f5e56SDavid van Moolenbroek 		if (alen == -1 ||
156*340f5e56SDavid van Moolenbroek 		    (pass = strchr(authbuf, ':')) == NULL)
157*340f5e56SDavid van Moolenbroek 			return bozo_http_error(httpd, 400, request,
158*340f5e56SDavid van Moolenbroek 			    "bad authorization field");
159*340f5e56SDavid van Moolenbroek 		*pass++ = '\0';
160*340f5e56SDavid van Moolenbroek 		free(request->hr_authuser);
161*340f5e56SDavid van Moolenbroek 		free(request->hr_authpass);
162*340f5e56SDavid van Moolenbroek 		request->hr_authuser = bozostrdup(httpd, authbuf);
163*340f5e56SDavid van Moolenbroek 		request->hr_authpass = bozostrdup(httpd, pass);
164*340f5e56SDavid van Moolenbroek 		debug((httpd, DEBUG_FAT,
165*340f5e56SDavid van Moolenbroek 		    "decoded authorization `%s' as `%s':`%s'",
166*340f5e56SDavid van Moolenbroek 		    str, request->hr_authuser, request->hr_authpass));
167*340f5e56SDavid van Moolenbroek 			/* don't store in request->headers */
168*340f5e56SDavid van Moolenbroek 		return 1;
169*340f5e56SDavid van Moolenbroek 	}
170*340f5e56SDavid van Moolenbroek 	return 0;
171*340f5e56SDavid van Moolenbroek }
172*340f5e56SDavid van Moolenbroek 
173*340f5e56SDavid van Moolenbroek int
bozo_auth_check_special_files(bozo_httpreq_t * request,const char * name)174*340f5e56SDavid van Moolenbroek bozo_auth_check_special_files(bozo_httpreq_t *request,
175*340f5e56SDavid van Moolenbroek 				const char *name)
176*340f5e56SDavid van Moolenbroek {
177*340f5e56SDavid van Moolenbroek 	bozohttpd_t *httpd = request->hr_httpd;
178*340f5e56SDavid van Moolenbroek 
179*340f5e56SDavid van Moolenbroek 	if (strcmp(name, AUTH_FILE) == 0)
180*340f5e56SDavid van Moolenbroek 		return bozo_http_error(httpd, 403, request,
181*340f5e56SDavid van Moolenbroek 				"no permission to open authfile");
182*340f5e56SDavid van Moolenbroek 	return 0;
183*340f5e56SDavid van Moolenbroek }
184*340f5e56SDavid van Moolenbroek 
185*340f5e56SDavid van Moolenbroek void
bozo_auth_check_401(bozo_httpreq_t * request,int code)186*340f5e56SDavid van Moolenbroek bozo_auth_check_401(bozo_httpreq_t *request, int code)
187*340f5e56SDavid van Moolenbroek {
188*340f5e56SDavid van Moolenbroek 	bozohttpd_t *httpd = request->hr_httpd;
189*340f5e56SDavid van Moolenbroek 
190*340f5e56SDavid van Moolenbroek 	if (code == 401)
191*340f5e56SDavid van Moolenbroek 		bozo_printf(httpd,
192*340f5e56SDavid van Moolenbroek 			"WWW-Authenticate: Basic realm=\"%s\"\r\n",
193*340f5e56SDavid van Moolenbroek 			(request && request->hr_authrealm) ?
194*340f5e56SDavid van Moolenbroek 				request->hr_authrealm : "default realm");
195*340f5e56SDavid van Moolenbroek }
196*340f5e56SDavid van Moolenbroek 
197*340f5e56SDavid van Moolenbroek #ifndef NO_CGIBIN_SUPPORT
198*340f5e56SDavid van Moolenbroek void
bozo_auth_cgi_setenv(bozo_httpreq_t * request,char *** curenvpp)199*340f5e56SDavid van Moolenbroek bozo_auth_cgi_setenv(bozo_httpreq_t *request,
200*340f5e56SDavid van Moolenbroek 			char ***curenvpp)
201*340f5e56SDavid van Moolenbroek {
202*340f5e56SDavid van Moolenbroek 	bozohttpd_t *httpd = request->hr_httpd;
203*340f5e56SDavid van Moolenbroek 
204*340f5e56SDavid van Moolenbroek 	if (request->hr_authuser && *request->hr_authuser) {
205*340f5e56SDavid van Moolenbroek 		bozo_setenv(httpd, "AUTH_TYPE", "Basic", (*curenvpp)++);
206*340f5e56SDavid van Moolenbroek 		bozo_setenv(httpd, "REMOTE_USER", request->hr_authuser,
207*340f5e56SDavid van Moolenbroek 				(*curenvpp)++);
208*340f5e56SDavid van Moolenbroek 	}
209*340f5e56SDavid van Moolenbroek }
210*340f5e56SDavid van Moolenbroek 
211*340f5e56SDavid van Moolenbroek int
bozo_auth_cgi_count(bozo_httpreq_t * request)212*340f5e56SDavid van Moolenbroek bozo_auth_cgi_count(bozo_httpreq_t *request)
213*340f5e56SDavid van Moolenbroek {
214*340f5e56SDavid van Moolenbroek 	return (request->hr_authuser && *request->hr_authuser) ? 2 : 0;
215*340f5e56SDavid van Moolenbroek }
216*340f5e56SDavid van Moolenbroek #endif /* NO_CGIBIN_SUPPORT */
217*340f5e56SDavid van Moolenbroek 
218*340f5e56SDavid van Moolenbroek /*
219*340f5e56SDavid van Moolenbroek  * Decode len bytes starting at in using base64 encoding into out.
220*340f5e56SDavid van Moolenbroek  * Result is *not* NUL terminated.
221*340f5e56SDavid van Moolenbroek  * Written by Luke Mewburn <lukem@NetBSD.org>
222*340f5e56SDavid van Moolenbroek  */
223*340f5e56SDavid van Moolenbroek const unsigned char decodetable[] = {
224*340f5e56SDavid van Moolenbroek 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
225*340f5e56SDavid van Moolenbroek 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
226*340f5e56SDavid van Moolenbroek 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,  62, 255, 255, 255,  63,
227*340f5e56SDavid van Moolenbroek 	 52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 255, 255, 255,   0, 255, 255,
228*340f5e56SDavid van Moolenbroek 	255,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,
229*340f5e56SDavid van Moolenbroek 	 15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25, 255, 255, 255, 255, 255,
230*340f5e56SDavid van Moolenbroek 	255,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,
231*340f5e56SDavid van Moolenbroek 	 41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51, 255, 255, 255, 255, 255,
232*340f5e56SDavid van Moolenbroek };
233*340f5e56SDavid van Moolenbroek 
234*340f5e56SDavid van Moolenbroek static ssize_t
base64_decode(const unsigned char * in,size_t ilen,unsigned char * out,size_t olen)235*340f5e56SDavid van Moolenbroek base64_decode(const unsigned char *in, size_t ilen, unsigned char *out,
236*340f5e56SDavid van Moolenbroek 	      size_t olen)
237*340f5e56SDavid van Moolenbroek {
238*340f5e56SDavid van Moolenbroek 	unsigned char *cp;
239*340f5e56SDavid van Moolenbroek 	size_t	 i;
240*340f5e56SDavid van Moolenbroek 
241*340f5e56SDavid van Moolenbroek 	if (ilen == 0) {
242*340f5e56SDavid van Moolenbroek 		if (olen)
243*340f5e56SDavid van Moolenbroek 			*out = '\0';
244*340f5e56SDavid van Moolenbroek 		return 0;
245*340f5e56SDavid van Moolenbroek 	}
246*340f5e56SDavid van Moolenbroek 
247*340f5e56SDavid van Moolenbroek 	cp = out;
248*340f5e56SDavid van Moolenbroek 	for (i = 0; i < ilen; i += 4) {
249*340f5e56SDavid van Moolenbroek 		if (cp + 3 > out + olen)
250*340f5e56SDavid van Moolenbroek 			return (-1);
251*340f5e56SDavid van Moolenbroek #define IN_CHECK(x) \
252*340f5e56SDavid van Moolenbroek 		if ((x) > sizeof(decodetable) || decodetable[(x)] == 255) \
253*340f5e56SDavid van Moolenbroek 			    return(-1)
254*340f5e56SDavid van Moolenbroek 
255*340f5e56SDavid van Moolenbroek 		IN_CHECK(in[i + 0]);
256*340f5e56SDavid van Moolenbroek 		/*LINTED*/
257*340f5e56SDavid van Moolenbroek 		*(cp++) = decodetable[in[i + 0]] << 2
258*340f5e56SDavid van Moolenbroek 			| decodetable[in[i + 1]] >> 4;
259*340f5e56SDavid van Moolenbroek 		IN_CHECK(in[i + 1]);
260*340f5e56SDavid van Moolenbroek 		/*LINTED*/
261*340f5e56SDavid van Moolenbroek 		*(cp++) = decodetable[in[i + 1]] << 4
262*340f5e56SDavid van Moolenbroek 			| decodetable[in[i + 2]] >> 2;
263*340f5e56SDavid van Moolenbroek 		IN_CHECK(in[i + 2]);
264*340f5e56SDavid van Moolenbroek 		*(cp++) = decodetable[in[i + 2]] << 6
265*340f5e56SDavid van Moolenbroek 			| decodetable[in[i + 3]];
266*340f5e56SDavid van Moolenbroek #undef IN_CHECK
267*340f5e56SDavid van Moolenbroek 	}
268*340f5e56SDavid van Moolenbroek 	while (i > 0 && in[i - 1] == '=')
269*340f5e56SDavid van Moolenbroek 		cp--,i--;
270*340f5e56SDavid van Moolenbroek 	return (cp - out);
271*340f5e56SDavid van Moolenbroek }
272*340f5e56SDavid van Moolenbroek #endif /* DO_HTPASSWD */
273