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