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