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