Home | History | Annotate | Line # | Download | only in httpd
auth-bozo.c revision 1.11
      1 /*	$NetBSD: auth-bozo.c,v 1.11 2013/10/12 18:46:12 mbalmer 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 	free(request->hr_authuser);
    123 	free(request->hr_authpass);
    124 	free(request->hr_authrealm);
    125 }
    126 
    127 int
    128 bozo_auth_check_headers(bozo_httpreq_t *request, char *val, char *str, ssize_t len)
    129 {
    130 	bozohttpd_t *httpd = request->hr_httpd;
    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(bozo_httpreq_t *request,
    162 				const char *name)
    163 {
    164 	bozohttpd_t *httpd = request->hr_httpd;
    165 
    166 	if (strcmp(name, AUTH_FILE) == 0)
    167 		return bozo_http_error(httpd, 403, request,
    168 				"no permission to open authfile");
    169 	return 0;
    170 }
    171 
    172 void
    173 bozo_auth_check_401(bozo_httpreq_t *request, int code)
    174 {
    175 	bozohttpd_t *httpd = request->hr_httpd;
    176 
    177 	if (code == 401)
    178 		bozo_printf(httpd,
    179 			"WWW-Authenticate: Basic realm=\"%s\"\r\n",
    180 			(request && request->hr_authrealm) ?
    181 				request->hr_authrealm : "default realm");
    182 }
    183 
    184 #ifndef NO_CGIBIN_SUPPORT
    185 void
    186 bozo_auth_cgi_setenv(bozo_httpreq_t *request,
    187 			char ***curenvpp)
    188 {
    189 	bozohttpd_t *httpd = request->hr_httpd;
    190 
    191 	if (request->hr_authuser && *request->hr_authuser) {
    192 		bozo_setenv(httpd, "AUTH_TYPE", "Basic", (*curenvpp)++);
    193 		bozo_setenv(httpd, "REMOTE_USER", request->hr_authuser,
    194 				(*curenvpp)++);
    195 	}
    196 }
    197 
    198 int
    199 bozo_auth_cgi_count(bozo_httpreq_t *request)
    200 {
    201 	return (request->hr_authuser && *request->hr_authuser) ? 2 : 0;
    202 }
    203 #endif /* NO_CGIBIN_SUPPORT */
    204 
    205 /*
    206  * Decode len bytes starting at in using base64 encoding into out.
    207  * Result is *not* NUL terminated.
    208  * Written by Luke Mewburn <lukem (at) NetBSD.org>
    209  */
    210 const unsigned char decodetable[] = {
    211 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    212 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    213 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,  62, 255, 255, 255,  63,
    214 	 52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 255, 255, 255,   0, 255, 255,
    215 	255,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,
    216 	 15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25, 255, 255, 255, 255, 255,
    217 	255,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,
    218 	 41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51, 255, 255, 255, 255, 255,
    219 };
    220 
    221 static ssize_t
    222 base64_decode(const unsigned char *in, size_t ilen, unsigned char *out,
    223 	      size_t olen)
    224 {
    225 	unsigned char *cp;
    226 	size_t	 i;
    227 
    228 	cp = out;
    229 	for (i = 0; i < ilen; i += 4) {
    230 		if (cp + 3 > out + olen)
    231 			return (-1);
    232 #define IN_CHECK(x) \
    233 		if ((x) > sizeof(decodetable) || decodetable[(x)] == 255) \
    234 			    return(-1)
    235 
    236 		IN_CHECK(in[i + 0]);
    237 		/*LINTED*/
    238 		*(cp++) = decodetable[in[i + 0]] << 2
    239 			| decodetable[in[i + 1]] >> 4;
    240 		IN_CHECK(in[i + 1]);
    241 		/*LINTED*/
    242 		*(cp++) = decodetable[in[i + 1]] << 4
    243 			| decodetable[in[i + 2]] >> 2;
    244 		IN_CHECK(in[i + 2]);
    245 		*(cp++) = decodetable[in[i + 2]] << 6
    246 			| decodetable[in[i + 3]];
    247 #undef IN_CHECK
    248 	}
    249 	while (in[i - 1] == '=')
    250 		cp--,i--;
    251 	return (cp - out);
    252 }
    253 #endif /* DO_HTPASSWD */
    254