Home | History | Annotate | Line # | Download | only in httpd
auth-bozo.c revision 1.22
      1 /*	$NetBSD: auth-bozo.c,v 1.22 2018/11/22 08:54:08 mrg Exp $	*/
      2 
      3 /*	$eterna: auth-bozo.c,v 1.17 2011/11/18 09:21:15 mrg Exp $	*/
      4 
      5 /*
      6  * Copyright (c) 1997-2018 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 static	ssize_t	base64_decode(const unsigned char *, size_t,
     46 			    unsigned char *, size_t);
     47 
     48 /*
     49  * Check if HTTP authentication is required
     50  */
     51 int
     52 bozo_auth_check(bozo_httpreq_t *request, const char *file)
     53 {
     54 	bozohttpd_t *httpd = request->hr_httpd;
     55 	struct stat sb;
     56 	char dir[MAXPATHLEN], authfile[MAXPATHLEN], *basename;
     57 	char user[BUFSIZ], *pass;
     58 	FILE *fp;
     59 	int len;
     60 
     61 			/* get dir=dirname(file) */
     62 	snprintf(dir, sizeof(dir), "%s", file);
     63 	if ((basename = strrchr(dir, '/')) == NULL)
     64 		strcpy(dir, ".");
     65 	else {
     66 		*basename++ = '\0';
     67 		if (bozo_check_special_files(request, basename))
     68 			return 1;
     69 	}
     70 	request->hr_authrealm = bozostrdup(httpd, request, dir);
     71 
     72 	if ((size_t)snprintf(authfile, sizeof(authfile), "%s/%s", dir,
     73 			     AUTH_FILE) >= sizeof(authfile)) {
     74 		return bozo_http_error(httpd, 404, request,
     75 			"authfile path too long");
     76 	}
     77 	if (stat(authfile, &sb) < 0) {
     78 		debug((httpd, DEBUG_NORMAL,
     79 		    "bozo_auth_check realm `%s' dir `%s' authfile `%s' missing",
     80 		    dir, file, authfile));
     81 		return 0;
     82 	}
     83 	if ((fp = fopen(authfile, "r")) == NULL)
     84 		return bozo_http_error(httpd, 403, request,
     85 			"no permission to open authfile");
     86 	debug((httpd, DEBUG_NORMAL,
     87 	    "bozo_auth_check realm `%s' dir `%s' authfile `%s' open",
     88 	    dir, file, authfile));
     89 	if (request->hr_authuser && request->hr_authpass) {
     90 		while (fgets(user, sizeof(user), fp) != NULL) {
     91 			len = strlen(user);
     92 			if (len > 0 && user[len-1] == '\n')
     93 				user[--len] = '\0';
     94 			if ((pass = strchr(user, ':')) == NULL)
     95 				continue;
     96 			*pass++ = '\0';
     97 			debug((httpd, DEBUG_NORMAL,
     98 			    "bozo_auth_check authfile `%s':`%s' "
     99 			    	"client `%s':`%s'",
    100 			    user, pass, request->hr_authuser,
    101 			    request->hr_authpass));
    102 			if (strcmp(request->hr_authuser, user) != 0)
    103 				continue;
    104 			if (strcmp(crypt(request->hr_authpass, pass),
    105 					pass) != 0)
    106 				break;
    107 			fclose(fp);
    108 			return 0;
    109 		}
    110 	}
    111 	fclose(fp);
    112 	return bozo_http_error(httpd, 401, request, "bad auth");
    113 }
    114 
    115 void
    116 bozo_auth_init(bozo_httpreq_t *request)
    117 {
    118 	request->hr_authuser = NULL;
    119 	request->hr_authpass = NULL;
    120 	request->hr_authrealm = NULL;
    121 }
    122 
    123 void
    124 bozo_auth_cleanup(bozo_httpreq_t *request)
    125 {
    126 
    127 	if (request == NULL)
    128 		return;
    129 	free(request->hr_authuser);
    130 	free(request->hr_authpass);
    131 	free(request->hr_authrealm);
    132 }
    133 
    134 int
    135 bozo_auth_check_headers(bozo_httpreq_t *request, char *val, char *str,
    136 			ssize_t len)
    137 {
    138 	bozohttpd_t *httpd = request->hr_httpd;
    139 
    140 	if (strcasecmp(val, "authorization") == 0 &&
    141 	    strncasecmp(str, "Basic ", 6) == 0) {
    142 		char	authbuf[BUFSIZ];
    143 		char	*pass = NULL;
    144 		ssize_t	alen;
    145 
    146 		/* free prior entries. */
    147 		free(request->hr_authuser);
    148 		free(request->hr_authpass);
    149 
    150 		alen = base64_decode((unsigned char *)str + 6,
    151 					(size_t)(len - 6),
    152 					(unsigned char *)authbuf,
    153 					sizeof(authbuf) - 1);
    154 		if (alen != -1)
    155 			authbuf[alen] = '\0';
    156 		if (alen == -1 ||
    157 		    (pass = strchr(authbuf, ':')) == NULL)
    158 			return bozo_http_error(httpd, 400, request,
    159 			    "bad authorization field");
    160 		*pass++ = '\0';
    161 		request->hr_authuser = bozostrdup(httpd, request, authbuf);
    162 		request->hr_authpass = bozostrdup(httpd, request, pass);
    163 		debug((httpd, DEBUG_FAT,
    164 		    "decoded authorization `%s' as `%s':`%s'",
    165 		    str, request->hr_authuser, request->hr_authpass));
    166 			/* don't store in request->headers */
    167 		return 1;
    168 	}
    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->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 	if (ilen == 0) {
    229 		if (olen)
    230 			*out = '\0';
    231 		return 0;
    232 	}
    233 
    234 	cp = out;
    235 	for (i = 0; i < ilen; i += 4) {
    236 		if (cp + 3 > out + olen)
    237 			return (-1);
    238 #define IN_CHECK(x) \
    239 		if ((x) > sizeof(decodetable) || decodetable[(x)] == 255) \
    240 			    return(-1)
    241 
    242 		IN_CHECK(in[i + 0]);
    243 		/*LINTED*/
    244 		*(cp++) = decodetable[in[i + 0]] << 2
    245 			| decodetable[in[i + 1]] >> 4;
    246 		IN_CHECK(in[i + 1]);
    247 		/*LINTED*/
    248 		*(cp++) = decodetable[in[i + 1]] << 4
    249 			| decodetable[in[i + 2]] >> 2;
    250 		IN_CHECK(in[i + 2]);
    251 		*(cp++) = decodetable[in[i + 2]] << 6
    252 			| decodetable[in[i + 3]];
    253 #undef IN_CHECK
    254 	}
    255 	while (i > 0 && in[i - 1] == '=')
    256 		cp--,i--;
    257 	return (cp - out);
    258 }
    259 #endif /* DO_HTPASSWD */
    260