1 /* $NetBSD: auth-bozo.c,v 1.16 2014/12/26 19:52:00 mrg Exp $ */
3 /* $eterna: auth-bozo.c,v 1.17 2011/11/18 09:21:15 mrg Exp $ */
6 * Copyright (c) 1997-2014 Matthew R. Green
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
33 /* this code implements "http basic authorisation" for bozohttpd */
37 #include <sys/param.h>
43 #include "bozohttpd.h"
46 #define AUTH_FILE ".htpasswd"
49 static ssize_t
base64_decode(const unsigned char *, size_t,
50 unsigned char *, size_t);
53 * Check if HTTP authentication is required
56 bozo_auth_check(bozo_httpreq_t
*request
, const char *file
)
58 bozohttpd_t
*httpd
= request
->hr_httpd
;
60 char dir
[MAXPATHLEN
], authfile
[MAXPATHLEN
], *basename
;
61 char user
[BUFSIZ
], *pass
;
65 /* get dir=dirname(file) */
66 snprintf(dir
, sizeof(dir
), "%s", file
);
67 if ((basename
= strrchr(dir
, '/')) == NULL
)
71 /* ensure basename(file) != AUTH_FILE */
72 if (bozo_check_special_files(request
, basename
))
75 request
->hr_authrealm
= bozostrdup(httpd
, dir
);
77 if ((size_t)snprintf(authfile
, sizeof(authfile
), "%s/%s", dir
, AUTH_FILE
) >=
79 return bozo_http_error(httpd
, 404, request
,
80 "authfile path too long");
82 if (stat(authfile
, &sb
) < 0) {
83 debug((httpd
, DEBUG_NORMAL
,
84 "bozo_auth_check realm `%s' dir `%s' authfile `%s' missing",
85 dir
, file
, authfile
));
88 if ((fp
= fopen(authfile
, "r")) == NULL
)
89 return bozo_http_error(httpd
, 403, request
,
90 "no permission to open authfile");
91 debug((httpd
, DEBUG_NORMAL
,
92 "bozo_auth_check realm `%s' dir `%s' authfile `%s' open",
93 dir
, file
, authfile
));
94 if (request
->hr_authuser
&& request
->hr_authpass
) {
95 while (fgets(user
, sizeof(user
), fp
) != NULL
) {
97 if (len
> 0 && user
[len
-1] == '\n')
99 if ((pass
= strchr(user
, ':')) == NULL
)
102 debug((httpd
, DEBUG_NORMAL
,
103 "bozo_auth_check authfile `%s':`%s' "
105 user
, pass
, request
->hr_authuser
,
106 request
->hr_authpass
));
107 if (strcmp(request
->hr_authuser
, user
) != 0)
109 if (strcmp(crypt(request
->hr_authpass
, pass
),
117 return bozo_http_error(httpd
, 401, request
, "bad auth");
121 bozo_auth_init(bozo_httpreq_t
*request
)
123 request
->hr_authuser
= NULL
;
124 request
->hr_authpass
= NULL
;
128 bozo_auth_cleanup(bozo_httpreq_t
*request
)
133 free(request
->hr_authuser
);
134 free(request
->hr_authpass
);
135 free(request
->hr_authrealm
);
139 bozo_auth_check_headers(bozo_httpreq_t
*request
, char *val
, char *str
, ssize_t len
)
141 bozohttpd_t
*httpd
= request
->hr_httpd
;
143 if (strcasecmp(val
, "authorization") == 0 &&
144 strncasecmp(str
, "Basic ", 6) == 0) {
145 char authbuf
[BUFSIZ
];
149 alen
= base64_decode((unsigned char *)str
+ 6,
151 (unsigned char *)authbuf
,
152 sizeof(authbuf
) - 1);
154 authbuf
[alen
] = '\0';
156 (pass
= strchr(authbuf
, ':')) == NULL
)
157 return bozo_http_error(httpd
, 400, request
,
158 "bad authorization field");
160 free(request
->hr_authuser
);
161 free(request
->hr_authpass
);
162 request
->hr_authuser
= bozostrdup(httpd
, authbuf
);
163 request
->hr_authpass
= bozostrdup(httpd
, pass
);
164 debug((httpd
, DEBUG_FAT
,
165 "decoded authorization `%s' as `%s':`%s'",
166 str
, request
->hr_authuser
, request
->hr_authpass
));
167 /* don't store in request->headers */
174 bozo_auth_check_special_files(bozo_httpreq_t
*request
,
177 bozohttpd_t
*httpd
= request
->hr_httpd
;
179 if (strcmp(name
, AUTH_FILE
) == 0)
180 return bozo_http_error(httpd
, 403, request
,
181 "no permission to open authfile");
186 bozo_auth_check_401(bozo_httpreq_t
*request
, int code
)
188 bozohttpd_t
*httpd
= request
->hr_httpd
;
192 "WWW-Authenticate: Basic realm=\"%s\"\r\n",
193 (request
&& request
->hr_authrealm
) ?
194 request
->hr_authrealm
: "default realm");
197 #ifndef NO_CGIBIN_SUPPORT
199 bozo_auth_cgi_setenv(bozo_httpreq_t
*request
,
202 bozohttpd_t
*httpd
= request
->hr_httpd
;
204 if (request
->hr_authuser
&& *request
->hr_authuser
) {
205 bozo_setenv(httpd
, "AUTH_TYPE", "Basic", (*curenvpp
)++);
206 bozo_setenv(httpd
, "REMOTE_USER", request
->hr_authuser
,
212 bozo_auth_cgi_count(bozo_httpreq_t
*request
)
214 return (request
->hr_authuser
&& *request
->hr_authuser
) ? 2 : 0;
216 #endif /* NO_CGIBIN_SUPPORT */
219 * Decode len bytes starting at in using base64 encoding into out.
220 * Result is *not* NUL terminated.
221 * Written by Luke Mewburn <lukem@NetBSD.org>
223 const unsigned char decodetable
[] = {
224 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
225 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
226 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
227 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 0, 255, 255,
228 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
229 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
230 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
231 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255,
235 base64_decode(const unsigned char *in
, size_t ilen
, unsigned char *out
,
248 for (i
= 0; i
< ilen
; i
+= 4) {
249 if (cp
+ 3 > out
+ olen
)
251 #define IN_CHECK(x) \
252 if ((x) > sizeof(decodetable) || decodetable[(x)] == 255) \
257 *(cp
++) = decodetable
[in
[i
+ 0]] << 2
258 | decodetable
[in
[i
+ 1]] >> 4;
261 *(cp
++) = decodetable
[in
[i
+ 1]] << 4
262 | decodetable
[in
[i
+ 2]] >> 2;
264 *(cp
++) = decodetable
[in
[i
+ 2]] << 6
265 | decodetable
[in
[i
+ 3]];
268 while (i
> 0 && in
[i
- 1] == '=')
272 #endif /* DO_HTPASSWD */