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