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