Home | History | Annotate | Line # | Download | only in httpd
auth-bozo.c revision 1.5
      1 /*	$NetBSD: auth-bozo.c,v 1.5 2009/04/18 07:28:24 mrg Exp $	*/
      2 
      3 /*	$eterna: auth-bozo.c,v 1.12 2009/04/17 22:52:19 mrg Exp $	*/
      4 
      5 /*
      6  * Copyright (c) 1997-2009 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 <unistd.h>
     41 
     42 #include "bozohttpd.h"
     43 
     44 #ifndef AUTH_FILE
     45 #define AUTH_FILE		".htpasswd"
     46 #endif
     47 
     48 static	ssize_t	base64_decode(const unsigned char *, size_t,
     49 			    unsigned char *, size_t);
     50 
     51 /*
     52  * Check if HTTP authentication is required
     53  */
     54 int
     55 auth_check(http_req *request, const char *file)
     56 {
     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 (check_special_files(request, basename))
     71 			return 1;
     72 	}
     73 	request->hr_authrealm = bozostrdup(dir);
     74 
     75 	snprintf(authfile, sizeof(authfile), "%s/%s", dir, AUTH_FILE);
     76 	if (stat(authfile, &sb) < 0) {
     77 		debug((DEBUG_NORMAL,
     78 		    "auth_check realm `%s' dir `%s' authfile `%s' missing",
     79 		    dir, file, authfile));
     80 		return;
     81 	}
     82 	if ((fp = fopen(authfile, "r")) == NULL)
     83 		return http_error(403, request, "no permission to open "
     84 						"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 	return http_error(401, request, "bad auth");
    110 }
    111 
    112 void
    113 auth_cleanup(http_req *request)
    114 {
    115 
    116 	if (request == NULL)
    117 		return;
    118 	if (request->hr_authuser)
    119 		free(request->hr_authuser);
    120 	if (request->hr_authpass)
    121 		free(request->hr_authpass);
    122 	if (request->hr_authrealm)
    123 		free(request->hr_authrealm);
    124 }
    125 
    126 int
    127 auth_check_headers(http_req *request, char *val, char *str, ssize_t len)
    128 {
    129 	if (strcasecmp(val, "authorization") == 0 &&
    130 	    strncasecmp(str, "Basic ", 6) == 0) {
    131 		char	authbuf[BUFSIZ];
    132 		char	*pass = NULL;
    133 		ssize_t	alen;
    134 
    135 		alen = base64_decode((unsigned char *)str + 6, len - 6,
    136 		    (unsigned char *)authbuf, sizeof(authbuf) - 1);
    137 		if (alen != -1)
    138 			authbuf[alen] = '\0';
    139 		if (alen == -1 ||
    140 		    (pass = strchr(authbuf, ':')) == NULL)
    141 			return http_error(400, request,
    142 			    "bad authorization field");
    143 		*pass++ = '\0';
    144 		request->hr_authuser = bozostrdup(authbuf);
    145 		request->hr_authpass = bozostrdup(pass);
    146 		debug((DEBUG_FAT,
    147 		    "decoded authorization `%s' as `%s':`%s'",
    148 		    str, request->hr_authuser, request->hr_authpass));
    149 			/* don't store in request->headers */
    150 		return 1;
    151 	}
    152 	return 0;
    153 }
    154 
    155 int
    156 auth_check_special_files(http_req *request, const char *name)
    157 {
    158 	if (strcmp(name, AUTH_FILE) == 0)
    159 		return http_error(403, request, "no permission to open authfile");
    160 	return 0;
    161 }
    162 
    163 void
    164 auth_check_401(http_req *request, int code)
    165 {
    166 	if (code == 401)
    167 		bozoprintf("WWW-Authenticate: Basic realm=\"%s\"\r\n",
    168 		    request && request->hr_authrealm ? request->hr_authrealm :
    169 		    "default realm");
    170 }
    171 
    172 #ifndef NO_CGIBIN_SUPPORT
    173 void
    174 auth_cgi_setenv(http_req *request, char ***curenvpp)
    175 {
    176 	if (request->hr_authuser && *request->hr_authuser) {
    177 		spsetenv("AUTH_TYPE", "Basic", (*curenvpp)++);
    178 		spsetenv("REMOTE_USER", request->hr_authuser, (*curenvpp)++);
    179 	}
    180 }
    181 
    182 int
    183 auth_cgi_count(http_req *request)
    184 {
    185 	return (request->hr_authuser && *request->hr_authuser) ? 2 : 0;
    186 }
    187 #endif /* NO_CGIBIN_SUPPORT */
    188 
    189 /*
    190  * Decode len bytes starting at in using base64 encoding into out.
    191  * Result is *not* NUL terminated.
    192  * Written by Luke Mewburn <lukem (at) NetBSD.org>
    193  */
    194 const unsigned char decodetable[] = {
    195 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    196 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    197 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,  62, 255, 255, 255,  63,
    198 	 52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 255, 255, 255,   0, 255, 255,
    199 	255,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,
    200 	 15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25, 255, 255, 255, 255, 255,
    201 	255,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,
    202 	 41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51, 255, 255, 255, 255, 255,
    203 };
    204 
    205 static ssize_t
    206 base64_decode(const unsigned char *in, size_t ilen, unsigned char *out,
    207 	      size_t olen)
    208 {
    209 	unsigned char *cp;
    210 	size_t	 i;
    211 
    212 	cp = out;
    213 	for (i = 0; i < ilen; i += 4) {
    214 		if (cp + 3 > out + olen)
    215 			return (-1);
    216 #define IN_CHECK(x) \
    217 		if ((x) > sizeof(decodetable) || decodetable[(x)] == 255) \
    218 			    return(-1)
    219 
    220 		IN_CHECK(in[i + 0]);
    221 		*(cp++) = decodetable[in[i + 0]] << 2
    222 			| decodetable[in[i + 1]] >> 4;
    223 		IN_CHECK(in[i + 1]);
    224 		*(cp++) = decodetable[in[i + 1]] << 4
    225 			| decodetable[in[i + 2]] >> 2;
    226 		IN_CHECK(in[i + 2]);
    227 		*(cp++) = decodetable[in[i + 2]] << 6
    228 			| decodetable[in[i + 3]];
    229 #undef IN_CHECK
    230 	}
    231 	while (in[i - 1] == '=')
    232 		cp--,i--;
    233 	return (cp - out);
    234 }
    235 #endif /* DO_HTPASSWD */
    236