Home | History | Annotate | Line # | Download | only in httpd
auth-bozo.c revision 1.8
      1 /*	$NetBSD: auth-bozo.c,v 1.8 2010/05/10 03:37:45 mrg Exp $	*/
      2 
      3 /*	$eterna: auth-bozo.c,v 1.15 2010/05/10 02:51:28 mrg Exp $	*/
      4 
      5 /*
      6  * Copyright (c) 1997-2010 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(bozohttpd_t *httpd, bozo_httpreq_t *request, const char *file)
     57 {
     58 	struct stat sb;
     59 	char dir[MAXPATHLEN], authfile[MAXPATHLEN], *basename;
     60 	char user[BUFSIZ], *pass;
     61 	FILE *fp;
     62 	int len;
     63 
     64 			/* get dir=dirname(file) */
     65 	snprintf(dir, sizeof(dir), "%s", file);
     66 	if ((basename = strrchr(dir, '/')) == NULL)
     67 		strcpy(dir, ".");
     68 	else {
     69 		*basename++ = '\0';
     70 			/* ensure basename(file) != AUTH_FILE */
     71 		if (bozo_check_special_files(httpd, request, basename))
     72 			return 1;
     73 	}
     74 	request->hr_authrealm = bozostrdup(httpd, dir);
     75 
     76 	snprintf(authfile, sizeof(authfile), "%s/%s", dir, AUTH_FILE);
     77 	if (stat(authfile, &sb) < 0) {
     78 		debug((httpd, DEBUG_NORMAL,
     79 		    "bozo_auth_check realm `%s' dir `%s' authfile `%s' missing",
     80 		    dir, file, authfile));
     81 		return 0;
     82 	}
     83 	if ((fp = fopen(authfile, "r")) == NULL)
     84 		return bozo_http_error(httpd, 403, request,
     85 			"no permission to open authfile");
     86 	debug((httpd, DEBUG_NORMAL,
     87 	    "bozo_auth_check realm `%s' dir `%s' authfile `%s' open",
     88 	    dir, file, authfile));
     89 	if (request->hr_authuser && request->hr_authpass) {
     90 		while (fgets(user, sizeof(user), fp) != NULL) {
     91 			len = strlen(user);
     92 			if (len > 0 && user[len-1] == '\n')
     93 				user[--len] = '\0';
     94 			if ((pass = strchr(user, ':')) == NULL)
     95 				continue;
     96 			*pass++ = '\0';
     97 			debug((httpd, DEBUG_NORMAL,
     98 			    "bozo_auth_check authfile `%s':`%s' "
     99 			    	"client `%s':`%s'",
    100 			    user, pass, request->hr_authuser,
    101 			    request->hr_authpass));
    102 			if (strcmp(request->hr_authuser, user) != 0)
    103 				continue;
    104 			if (strcmp(crypt(request->hr_authpass, pass),
    105 					pass) != 0)
    106 				break;
    107 			fclose(fp);
    108 			return 0;
    109 		}
    110 	}
    111 	fclose(fp);
    112 	return bozo_http_error(httpd, 401, request, "bad auth");
    113 }
    114 
    115 void
    116 bozo_auth_cleanup(bozo_httpreq_t *request)
    117 {
    118 
    119 	if (request == NULL)
    120 		return;
    121 	if (request->hr_authuser)
    122 		free(request->hr_authuser);
    123 	if (request->hr_authpass)
    124 		free(request->hr_authpass);
    125 	if (request->hr_authrealm)
    126 		free(request->hr_authrealm);
    127 }
    128 
    129 int
    130 bozo_auth_check_headers(bozohttpd_t *httpd, bozo_httpreq_t *request, char *val, char *str, ssize_t len)
    131 {
    132 	if (strcasecmp(val, "authorization") == 0 &&
    133 	    strncasecmp(str, "Basic ", 6) == 0) {
    134 		char	authbuf[BUFSIZ];
    135 		char	*pass = NULL;
    136 		ssize_t	alen;
    137 
    138 		alen = base64_decode((unsigned char *)str + 6,
    139 					(size_t)(len - 6),
    140 					(unsigned char *)authbuf,
    141 					sizeof(authbuf) - 1);
    142 		if (alen != -1)
    143 			authbuf[alen] = '\0';
    144 		if (alen == -1 ||
    145 		    (pass = strchr(authbuf, ':')) == NULL)
    146 			return bozo_http_error(httpd, 400, request,
    147 			    "bad authorization field");
    148 		*pass++ = '\0';
    149 		request->hr_authuser = bozostrdup(httpd, authbuf);
    150 		request->hr_authpass = bozostrdup(httpd, pass);
    151 		debug((httpd, DEBUG_FAT,
    152 		    "decoded authorization `%s' as `%s':`%s'",
    153 		    str, request->hr_authuser, request->hr_authpass));
    154 			/* don't store in request->headers */
    155 		return 1;
    156 	}
    157 	return 0;
    158 }
    159 
    160 int
    161 bozo_auth_check_special_files(bozohttpd_t *httpd, bozo_httpreq_t *request,
    162 				const char *name)
    163 {
    164 	if (strcmp(name, AUTH_FILE) == 0)
    165 		return bozo_http_error(httpd, 403, request,
    166 				"no permission to open authfile");
    167 	return 0;
    168 }
    169 
    170 void
    171 bozo_auth_check_401(bozohttpd_t *httpd, bozo_httpreq_t *request, int code)
    172 {
    173 	if (code == 401)
    174 		bozo_printf(httpd,
    175 			"WWW-Authenticate: Basic realm=\"%s\"\r\n",
    176 			(request && request->hr_authrealm) ?
    177 				request->hr_authrealm : "default realm");
    178 }
    179 
    180 #ifndef NO_CGIBIN_SUPPORT
    181 void
    182 bozo_auth_cgi_setenv(bozohttpd_t *httpd, bozo_httpreq_t *request,
    183 			char ***curenvpp)
    184 {
    185 	if (request->hr_authuser && *request->hr_authuser) {
    186 		bozo_setenv(httpd, "AUTH_TYPE", "Basic", (*curenvpp)++);
    187 		bozo_setenv(httpd, "REMOTE_USER", request->hr_authuser,
    188 				(*curenvpp)++);
    189 	}
    190 }
    191 
    192 int
    193 bozo_auth_cgi_count(bozo_httpreq_t *request)
    194 {
    195 	return (request->hr_authuser && *request->hr_authuser) ? 2 : 0;
    196 }
    197 #endif /* NO_CGIBIN_SUPPORT */
    198 
    199 /*
    200  * Decode len bytes starting at in using base64 encoding into out.
    201  * Result is *not* NUL terminated.
    202  * Written by Luke Mewburn <lukem (at) NetBSD.org>
    203  */
    204 const unsigned char decodetable[] = {
    205 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    206 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    207 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,  62, 255, 255, 255,  63,
    208 	 52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 255, 255, 255,   0, 255, 255,
    209 	255,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,
    210 	 15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25, 255, 255, 255, 255, 255,
    211 	255,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,
    212 	 41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51, 255, 255, 255, 255, 255,
    213 };
    214 
    215 static ssize_t
    216 base64_decode(const unsigned char *in, size_t ilen, unsigned char *out,
    217 	      size_t olen)
    218 {
    219 	unsigned char *cp;
    220 	size_t	 i;
    221 
    222 	cp = out;
    223 	for (i = 0; i < ilen; i += 4) {
    224 		if (cp + 3 > out + olen)
    225 			return (-1);
    226 #define IN_CHECK(x) \
    227 		if ((x) > sizeof(decodetable) || decodetable[(x)] == 255) \
    228 			    return(-1)
    229 
    230 		IN_CHECK(in[i + 0]);
    231 		/*LINTED*/
    232 		*(cp++) = decodetable[in[i + 0]] << 2
    233 			| decodetable[in[i + 1]] >> 4;
    234 		IN_CHECK(in[i + 1]);
    235 		/*LINTED*/
    236 		*(cp++) = decodetable[in[i + 1]] << 4
    237 			| decodetable[in[i + 2]] >> 2;
    238 		IN_CHECK(in[i + 2]);
    239 		*(cp++) = decodetable[in[i + 2]] << 6
    240 			| decodetable[in[i + 3]];
    241 #undef IN_CHECK
    242 	}
    243 	while (in[i - 1] == '=')
    244 		cp--,i--;
    245 	return (cp - out);
    246 }
    247 #endif /* DO_HTPASSWD */
    248