Home | History | Annotate | Line # | Download | only in httpd
auth-bozo.c revision 1.2
      1 /*	$eterna: auth-bozo.c,v 1.7 2006/05/17 08:19:10 mrg Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1997-2006 Matthew R. Green
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer and
     14  *    dedication in the documentation and/or other materials provided
     15  *    with the distribution.
     16  * 3. The name of the author may not be used to endorse or promote products
     17  *    derived from this software without specific prior written permission.
     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 void
     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 		check_special_files(request, basename);
     71 	}
     72 	request->hr_authrealm = dir;
     73 
     74 	snprintf(authfile, sizeof(authfile), "%s/%s", dir, AUTH_FILE);
     75 	if (stat(authfile, &sb) < 0) {
     76 		debug((DEBUG_NORMAL,
     77 		    "auth_check realm `%s' dir `%s' authfile `%s' missing",
     78 		    dir, file, authfile));
     79 		return;
     80 	}
     81 	if ((fp = fopen(authfile, "r")) == NULL)
     82 		http_error(403, request, "no permission to open authfile");
     83 	debug((DEBUG_NORMAL,
     84 	    "auth_check realm `%s' dir `%s' authfile `%s' open",
     85 	    dir, file, authfile));
     86 	if (request->hr_authuser && request->hr_authpass) {
     87 		while (fgets(user, sizeof(user), fp) != NULL) {
     88 			len = strlen(user);
     89 			if (len > 0 && user[len-1] == '\n')
     90 				user[--len] = '\0';
     91 			if ((pass = strchr(user, ':')) == NULL)
     92 				continue;
     93 			*pass++ = '\0';
     94 			debug((DEBUG_NORMAL,
     95 			    "auth_check authfile `%s':`%s' client `%s':`%s'",
     96 			    user, pass, request->hr_authuser,
     97 			    request->hr_authpass));
     98 			if (strcmp(request->hr_authuser, user) != 0)
     99 				continue;
    100 			if (strcmp(crypt(request->hr_authpass, pass), pass))
    101 				break;
    102 			fclose(fp);
    103 			return;
    104 		}
    105 	}
    106 	fclose(fp);
    107 	http_error(401, request, "bad auth");
    108 }
    109 
    110 int
    111 auth_check_headers(http_req *request, char *val, char *str, ssize_t len)
    112 {
    113 	if (strcasecmp(val, "authorization") == 0 &&
    114 	    strncasecmp(str, "Basic ", 6) == 0) {
    115 		char	authbuf[BUFSIZ];
    116 		char	*pass = NULL;
    117 		ssize_t	alen;
    118 
    119 		alen = base64_decode((unsigned char *)str + 6, len - 6,
    120 		    (unsigned char *)authbuf, sizeof(authbuf) - 1);
    121 		if (alen != -1)
    122 			authbuf[alen] = '\0';
    123 		if (alen == -1 ||
    124 		    (pass = strchr(authbuf, ':')) == NULL)
    125 			http_error(400, request,
    126 			    "bad authorization field");
    127 		*pass++ = '\0';
    128 		request->hr_authuser = bozostrdup(authbuf);
    129 		request->hr_authpass = bozostrdup(pass);
    130 		debug((DEBUG_FAT,
    131 		    "decoded authorization `%s' as `%s':`%s'",
    132 		    str, request->hr_authuser, request->hr_authpass));
    133 			/* don't store in request->headers */
    134 		return 1;
    135 	}
    136 	return 0;
    137 }
    138 
    139 void
    140 auth_check_special_files(http_req *request, const char *name)
    141 {
    142 	if (strcmp(name, AUTH_FILE) == 0)
    143 		http_error(403, request, "no permission to open authfile");
    144 }
    145 
    146 void
    147 auth_check_401(http_req *request, int code)
    148 {
    149 	if (code == 401)
    150 		bozoprintf("WWW-Authenticate: Basic realm=\"%s\"\r\n",
    151 		    request && request->hr_authrealm ? request->hr_authrealm :
    152 		    "default realm");
    153 }
    154 
    155 #ifndef NO_CGIBIN_SUPPORT
    156 void
    157 auth_cgi_setenv(http_req *request, char ***curenvpp)
    158 {
    159 	if (request->hr_authuser && *request->hr_authuser) {
    160 		spsetenv("AUTH_TYPE", "Basic", (*curenvpp)++);
    161 		spsetenv("REMOTEUSER", request->hr_authuser, (*curenvpp)++);
    162 	}
    163 }
    164 
    165 int
    166 auth_cgi_count(http_req *request)
    167 {
    168 	return (request->hr_authuser && *request->hr_authuser) ? 2 : 0;
    169 }
    170 #endif /* NO_CGIBIN_SUPPORT */
    171 
    172 /*
    173  * Decode len bytes starting at in using base64 encoding into out.
    174  * Result is *not* NUL terminated.
    175  * Written by Luke Mewburn <lukem (at) NetBSD.org>
    176  */
    177 const unsigned char decodetable[] = {
    178 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    179 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    180 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,  62, 255, 255, 255,  63,
    181 	 52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 255, 255, 255,   0, 255, 255,
    182 	255,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,
    183 	 15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25, 255, 255, 255, 255, 255,
    184 	255,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,
    185 	 41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51, 255, 255, 255, 255, 255,
    186 };
    187 
    188 static ssize_t
    189 base64_decode(const unsigned char *in, size_t ilen, unsigned char *out,
    190 	      size_t olen)
    191 {
    192 	unsigned char *cp;
    193 	size_t	 i;
    194 
    195 	cp = out;
    196 	for (i = 0; i < ilen; i += 4) {
    197 		if (cp + 3 > out + olen)
    198 			return (-1);
    199 #define IN_CHECK(x) \
    200 		if ((x) > sizeof(decodetable) || decodetable[(x)] == 255) \
    201 			    return(-1)
    202 
    203 		IN_CHECK(in[i + 0]);
    204 		*(cp++) = decodetable[in[i + 0]] << 2
    205 			| decodetable[in[i + 1]] >> 4;
    206 		IN_CHECK(in[i + 1]);
    207 		*(cp++) = decodetable[in[i + 1]] << 4
    208 			| decodetable[in[i + 2]] >> 2;
    209 		IN_CHECK(in[i + 2]);
    210 		*(cp++) = decodetable[in[i + 2]] << 6
    211 			| decodetable[in[i + 3]];
    212 #undef IN_CHECK
    213 	}
    214 	while (in[i - 1] == '=')
    215 		cp--,i--;
    216 	return (cp - out);
    217 }
    218 #endif /* DO_HTPASSWD */
    219