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