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