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