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