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