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