auth-bozo.c revision 1.1 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;
117 ssize_t alen;
118
119 alen = base64_decode(str + 6, len - 6,
120 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