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