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