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