Sat Aug 27 15:33:59 2011 UTC ()
Don't check for __attribute__ being defined, it won't. Check for GCC 3.x
or compatible and define BOZO_PRINTFLIKE / BOZO_DEAD. Fix fallout.


(joerg)
diff -r1.27 -r1.28 src/libexec/httpd/bozohttpd.c
diff -r1.18 -r1.19 src/libexec/httpd/bozohttpd.h
diff -r1.13 -r1.14 src/libexec/httpd/daemon-bozo.c
diff -r1.2 -r1.3 src/libexec/httpd/main.c
diff -r1.11 -r1.12 src/libexec/httpd/ssl-bozo.c

cvs diff -r1.27 -r1.28 src/libexec/httpd/bozohttpd.c (switch to unified diff)

--- src/libexec/httpd/bozohttpd.c 2011/03/29 07:22:31 1.27
+++ src/libexec/httpd/bozohttpd.c 2011/08/27 15:33:59 1.28
@@ -1,2091 +1,2088 @@ @@ -1,2091 +1,2088 @@
1/* $NetBSD: bozohttpd.c,v 1.27 2011/03/29 07:22:31 jmmv Exp $ */ 1/* $NetBSD: bozohttpd.c,v 1.28 2011/08/27 15:33:59 joerg Exp $ */
2 2
3/* $eterna: bozohttpd.c,v 1.176 2010/09/20 22:26:28 mrg Exp $ */ 3/* $eterna: bozohttpd.c,v 1.176 2010/09/20 22:26:28 mrg Exp $ */
4 4
5/* 5/*
6 * Copyright (c) 1997-2010 Matthew R. Green 6 * Copyright (c) 1997-2010 Matthew R. Green
7 * All rights reserved. 7 * All rights reserved.
8 * 8 *
9 * Redistribution and use in source and binary forms, with or without 9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions 10 * modification, are permitted provided that the following conditions
11 * are met: 11 * are met:
12 * 1. Redistributions of source code must retain the above copyright 12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer. 13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright 14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer and 15 * notice, this list of conditions and the following disclaimer and
16 * dedication in the documentation and/or other materials provided 16 * dedication in the documentation and/or other materials provided
17 * with the distribution. 17 * with the distribution.
18 * 18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 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 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 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 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE. 29 * SUCH DAMAGE.
30 * 30 *
31 */ 31 */
32 32
33/* this program is dedicated to the Great God of Processed Cheese */ 33/* this program is dedicated to the Great God of Processed Cheese */
34 34
35/* 35/*
36 * bozohttpd.c: minimal httpd; provides only these features: 36 * bozohttpd.c: minimal httpd; provides only these features:
37 * - HTTP/0.9 (by virtue of ..) 37 * - HTTP/0.9 (by virtue of ..)
38 * - HTTP/1.0 38 * - HTTP/1.0
39 * - HTTP/1.1 39 * - HTTP/1.1
40 * - CGI/1.1 this will only be provided for "system" scripts 40 * - CGI/1.1 this will only be provided for "system" scripts
41 * - automatic "missing trailing slash" redirections 41 * - automatic "missing trailing slash" redirections
42 * - configurable translation of /~user/ to ~user/public_html, 42 * - configurable translation of /~user/ to ~user/public_html,
43 * however, this does not include cgi-bin support 43 * however, this does not include cgi-bin support
44 * - access lists via libwrap via inetd/tcpd 44 * - access lists via libwrap via inetd/tcpd
45 * - virtual hosting 45 * - virtual hosting
46 * - not that we do not even pretend to understand MIME, but 46 * - not that we do not even pretend to understand MIME, but
47 * rely only on the HTTP specification 47 * rely only on the HTTP specification
48 * - ipv6 support 48 * - ipv6 support
49 * - automatic `index.html' generation 49 * - automatic `index.html' generation
50 * - configurable server name 50 * - configurable server name
51 * - directory index generation 51 * - directory index generation
52 * - daemon mode (lacks libwrap support) 52 * - daemon mode (lacks libwrap support)
53 * - .htpasswd support 53 * - .htpasswd support
54 */ 54 */
55 55
56/* 56/*
57 * requirements for minimal http/1.1 (at least, as documented in 57 * requirements for minimal http/1.1 (at least, as documented in
58 * <draft-ietf-http-v11-spec-rev-06> which expired may 18, 1999): 58 * <draft-ietf-http-v11-spec-rev-06> which expired may 18, 1999):
59 * 59 *
60 * - 14.15: content-encoding handling. [1] 60 * - 14.15: content-encoding handling. [1]
61 * 61 *
62 * - 14.16: content-length handling. this is only a SHOULD header 62 * - 14.16: content-length handling. this is only a SHOULD header
63 * thus we could just not send it ever. [1] 63 * thus we could just not send it ever. [1]
64 * 64 *
65 * - 14.17: content-type handling. [1] 65 * - 14.17: content-type handling. [1]
66 * 66 *
67 * - 14.25/28: if-{,un}modified-since handling. maybe do this, but 67 * - 14.25/28: if-{,un}modified-since handling. maybe do this, but
68 * i really don't want to have to parse 3 differnet date formats 68 * i really don't want to have to parse 3 differnet date formats
69 * 69 *
70 * [1] need to revisit to ensure proper behaviour 70 * [1] need to revisit to ensure proper behaviour
71 * 71 *
72 * and the following is a list of features that we do not need 72 * and the following is a list of features that we do not need
73 * to have due to other limits, or are too lazy. there are more 73 * to have due to other limits, or are too lazy. there are more
74 * of these than are listed, but these are of particular note, 74 * of these than are listed, but these are of particular note,
75 * and could perhaps be implemented. 75 * and could perhaps be implemented.
76 * 76 *
77 * - 3.5/3.6: content/transfer codings. probably can ignore 77 * - 3.5/3.6: content/transfer codings. probably can ignore
78 * this? we "SHOULD"n't. but 4.4 says we should ignore a 78 * this? we "SHOULD"n't. but 4.4 says we should ignore a
79 * `content-length' header upon reciept of a `transfer-encoding' 79 * `content-length' header upon reciept of a `transfer-encoding'
80 * header. 80 * header.
81 * 81 *
82 * - 5.1.1: request methods. only MUST support GET and HEAD, 82 * - 5.1.1: request methods. only MUST support GET and HEAD,
83 * but there are new ones besides POST that are currently 83 * but there are new ones besides POST that are currently
84 * supported: OPTIONS PUT DELETE TRACE and CONNECT, plus 84 * supported: OPTIONS PUT DELETE TRACE and CONNECT, plus
85 * extensions not yet known? 85 * extensions not yet known?
86 * 86 *
87 * - 10.1: we can ignore informational status codes 87 * - 10.1: we can ignore informational status codes
88 * 88 *
89 * - 10.3.3/10.3.4/10.3.8: just use '302' codes always. 89 * - 10.3.3/10.3.4/10.3.8: just use '302' codes always.
90 * 90 *
91 * - 14.1/14.2/14.3/14.27: we do not support Accept: headers.. 91 * - 14.1/14.2/14.3/14.27: we do not support Accept: headers..
92 * just ignore them and send the request anyway. they are 92 * just ignore them and send the request anyway. they are
93 * only SHOULD. 93 * only SHOULD.
94 * 94 *
95 * - 14.5/14.16/14.35: we don't do ranges. from section 14.35.2 95 * - 14.5/14.16/14.35: we don't do ranges. from section 14.35.2
96 * `A server MAY ignore the Range header'. but it might be nice. 96 * `A server MAY ignore the Range header'. but it might be nice.
97 * since 20080301 we support simple range headers. 97 * since 20080301 we support simple range headers.
98 * 98 *
99 * - 14.9: we aren't a cache. 99 * - 14.9: we aren't a cache.
100 * 100 *
101 * - 14.15: content-md5 would be nice... 101 * - 14.15: content-md5 would be nice...
102 *  102 *
103 * - 14.24/14.26/14.27: be nice to support this... 103 * - 14.24/14.26/14.27: be nice to support this...
104 * 104 *
105 * - 14.44: not sure about this Vary: header. ignore it for now. 105 * - 14.44: not sure about this Vary: header. ignore it for now.
106 */ 106 */
107 107
108#ifndef INDEX_HTML 108#ifndef INDEX_HTML
109#define INDEX_HTML "index.html" 109#define INDEX_HTML "index.html"
110#endif 110#endif
111#ifndef SERVER_SOFTWARE 111#ifndef SERVER_SOFTWARE
112#define SERVER_SOFTWARE "bozohttpd/20100920" 112#define SERVER_SOFTWARE "bozohttpd/20100920"
113#endif 113#endif
114#ifndef DIRECT_ACCESS_FILE 114#ifndef DIRECT_ACCESS_FILE
115#define DIRECT_ACCESS_FILE ".bzdirect" 115#define DIRECT_ACCESS_FILE ".bzdirect"
116#endif 116#endif
117#ifndef REDIRECT_FILE 117#ifndef REDIRECT_FILE
118#define REDIRECT_FILE ".bzredirect" 118#define REDIRECT_FILE ".bzredirect"
119#endif 119#endif
120#ifndef ABSREDIRECT_FILE 120#ifndef ABSREDIRECT_FILE
121#define ABSREDIRECT_FILE ".bzabsredirect" 121#define ABSREDIRECT_FILE ".bzabsredirect"
122#endif 122#endif
123#ifndef PUBLIC_HTML 123#ifndef PUBLIC_HTML
124#define PUBLIC_HTML "public_html" 124#define PUBLIC_HTML "public_html"
125#endif 125#endif
126 126
127#ifndef USE_ARG 127#ifndef USE_ARG
128#define USE_ARG(x) /*LINTED*/(void)&(x) 128#define USE_ARG(x) /*LINTED*/(void)&(x)
129#endif 129#endif
130 130
131/* 131/*
132 * And so it begins .. 132 * And so it begins ..
133 */ 133 */
134 134
135#include <sys/param.h> 135#include <sys/param.h>
136#include <sys/socket.h> 136#include <sys/socket.h>
137#include <sys/time.h> 137#include <sys/time.h>
138#include <sys/mman.h> 138#include <sys/mman.h>
139 139
140#include <arpa/inet.h> 140#include <arpa/inet.h>
141 141
142#include <ctype.h> 142#include <ctype.h>
143#include <dirent.h> 143#include <dirent.h>
144#include <errno.h> 144#include <errno.h>
145#include <fcntl.h> 145#include <fcntl.h>
146#include <netdb.h> 146#include <netdb.h>
147#include <pwd.h> 147#include <pwd.h>
148#include <grp.h> 148#include <grp.h>
149#include <signal.h> 149#include <signal.h>
150#include <stdarg.h> 150#include <stdarg.h>
151#include <stdlib.h> 151#include <stdlib.h>
152#include <string.h> 152#include <string.h>
153#include <syslog.h> 153#include <syslog.h>
154#include <time.h> 154#include <time.h>
155#include <unistd.h> 155#include <unistd.h>
156 156
157#ifndef __attribute__ 
158#define __attribute__(x) 
159#endif /* __attribute__ */ 
160 
161#include "bozohttpd.h" 157#include "bozohttpd.h"
162 158
163#ifndef MAX_WAIT_TIME 159#ifndef MAX_WAIT_TIME
164#define MAX_WAIT_TIME 60 /* hang around for 60 seconds max */ 160#define MAX_WAIT_TIME 60 /* hang around for 60 seconds max */
165#endif 161#endif
166 162
167/* variables and functions */ 163/* variables and functions */
168#ifndef LOG_FTP 164#ifndef LOG_FTP
169#define LOG_FTP LOG_DAEMON 165#define LOG_FTP LOG_DAEMON
170#endif 166#endif
171 167
172volatile sig_atomic_t alarmhit; 168volatile sig_atomic_t alarmhit;
173 169
174/* 170/*
175 * check there's enough space in the prefs and names arrays. 171 * check there's enough space in the prefs and names arrays.
176 */ 172 */
177static int 173static int
178size_arrays(bozoprefs_t *bozoprefs, unsigned needed) 174size_arrays(bozoprefs_t *bozoprefs, unsigned needed)
179{ 175{
180 char **temp; 176 char **temp;
181 177
182 if (bozoprefs->size == 0) { 178 if (bozoprefs->size == 0) {
183 /* only get here first time around */ 179 /* only get here first time around */
184 bozoprefs->size = needed; 180 bozoprefs->size = needed;
185 if ((bozoprefs->name = calloc(sizeof(char *), needed)) == NULL) { 181 if ((bozoprefs->name = calloc(sizeof(char *), needed)) == NULL) {
186 (void) fprintf(stderr, "size_arrays: bad alloc\n"); 182 (void) fprintf(stderr, "size_arrays: bad alloc\n");
187 return 0; 183 return 0;
188 } 184 }
189 if ((bozoprefs->value = calloc(sizeof(char *), needed)) == NULL) { 185 if ((bozoprefs->value = calloc(sizeof(char *), needed)) == NULL) {
190 free(bozoprefs->name); 186 free(bozoprefs->name);
191 (void) fprintf(stderr, "size_arrays: bad alloc\n"); 187 (void) fprintf(stderr, "size_arrays: bad alloc\n");
192 return 0; 188 return 0;
193 } 189 }
194 } else if (bozoprefs->c == bozoprefs->size) { 190 } else if (bozoprefs->c == bozoprefs->size) {
195 /* only uses 'needed' when filled array */ 191 /* only uses 'needed' when filled array */
196 bozoprefs->size += needed; 192 bozoprefs->size += needed;
197 temp = realloc(bozoprefs->name, sizeof(char *) * needed); 193 temp = realloc(bozoprefs->name, sizeof(char *) * needed);
198 if (temp == NULL) { 194 if (temp == NULL) {
199 (void) fprintf(stderr, "size_arrays: bad alloc\n"); 195 (void) fprintf(stderr, "size_arrays: bad alloc\n");
200 return 0; 196 return 0;
201 } 197 }
202 bozoprefs->name = temp; 198 bozoprefs->name = temp;
203 temp = realloc(bozoprefs->value, sizeof(char *) * needed); 199 temp = realloc(bozoprefs->value, sizeof(char *) * needed);
204 if (temp == NULL) { 200 if (temp == NULL) {
205 (void) fprintf(stderr, "size_arrays: bad alloc\n"); 201 (void) fprintf(stderr, "size_arrays: bad alloc\n");
206 return 0; 202 return 0;
207 } 203 }
208 bozoprefs->value = temp; 204 bozoprefs->value = temp;
209 } 205 }
210 return 1; 206 return 1;
211} 207}
212 208
213static int 209static int
214findvar(bozoprefs_t *bozoprefs, const char *name) 210findvar(bozoprefs_t *bozoprefs, const char *name)
215{ 211{
216 unsigned i; 212 unsigned i;
217 213
218 for (i = 0 ; i < bozoprefs->c && strcmp(bozoprefs->name[i], name) != 0; i++) 214 for (i = 0 ; i < bozoprefs->c && strcmp(bozoprefs->name[i], name) != 0; i++)
219 ; 215 ;
220 return (i == bozoprefs->c) ? -1 : (int)i; 216 return (i == bozoprefs->c) ? -1 : (int)i;
221} 217}
222 218
223int 219int
224bozo_set_pref(bozoprefs_t *bozoprefs, const char *name, const char *value) 220bozo_set_pref(bozoprefs_t *bozoprefs, const char *name, const char *value)
225{ 221{
226 int i; 222 int i;
227 223
228 if ((i = findvar(bozoprefs, name)) < 0) { 224 if ((i = findvar(bozoprefs, name)) < 0) {
229 /* add the element to the array */ 225 /* add the element to the array */
230 if (size_arrays(bozoprefs, bozoprefs->size + 15)) { 226 if (size_arrays(bozoprefs, bozoprefs->size + 15)) {
231 bozoprefs->name[i = bozoprefs->c++] = strdup(name); 227 bozoprefs->name[i = bozoprefs->c++] = strdup(name);
232 } 228 }
233 } else { 229 } else {
234 /* replace the element in the array */ 230 /* replace the element in the array */
235 if (bozoprefs->value[i]) { 231 if (bozoprefs->value[i]) {
236 free(bozoprefs->value[i]); 232 free(bozoprefs->value[i]);
237 bozoprefs->value[i] = NULL; 233 bozoprefs->value[i] = NULL;
238 } 234 }
239 } 235 }
240 /* sanity checks for range of values go here */ 236 /* sanity checks for range of values go here */
241 bozoprefs->value[i] = strdup(value); 237 bozoprefs->value[i] = strdup(value);
242 return 1; 238 return 1;
243} 239}
244 240
245/* 241/*
246 * get a variable's value, or NULL 242 * get a variable's value, or NULL
247 */ 243 */
248char * 244char *
249bozo_get_pref(bozoprefs_t *bozoprefs, const char *name) 245bozo_get_pref(bozoprefs_t *bozoprefs, const char *name)
250{ 246{
251 int i; 247 int i;
252 248
253 return ((i = findvar(bozoprefs, name)) < 0) ? NULL : 249 return ((i = findvar(bozoprefs, name)) < 0) ? NULL :
254 bozoprefs->value[i]; 250 bozoprefs->value[i];
255} 251}
256 252
257char * 253char *
258bozo_http_date(char *date, size_t datelen) 254bozo_http_date(char *date, size_t datelen)
259{ 255{
260 struct tm *tm; 256 struct tm *tm;
261 time_t now; 257 time_t now;
262 258
263 /* Sun, 06 Nov 1994 08:49:37 GMT */ 259 /* Sun, 06 Nov 1994 08:49:37 GMT */
264 now = time(NULL); 260 now = time(NULL);
265 tm = gmtime(&now); /* HTTP/1.1 spec rev 06 sez GMT only */ 261 tm = gmtime(&now); /* HTTP/1.1 spec rev 06 sez GMT only */
266 strftime(date, datelen, "%a, %d %b %Y %H:%M:%S GMT", tm); 262 strftime(date, datelen, "%a, %d %b %Y %H:%M:%S GMT", tm);
267 return date; 263 return date;
268} 264}
269 265
270/* 266/*
271 * convert "in" into the three parts of a request (first line). 267 * convert "in" into the three parts of a request (first line).
272 * we allocate into file and query, but return pointers into 268 * we allocate into file and query, but return pointers into
273 * "in" for proto and method. 269 * "in" for proto and method.
274 */ 270 */
275static void 271static void
276parse_request(bozohttpd_t *httpd, char *in, char **method, char **file, 272parse_request(bozohttpd_t *httpd, char *in, char **method, char **file,
277 char **query, char **proto) 273 char **query, char **proto)
278{ 274{
279 ssize_t len; 275 ssize_t len;
280 char *val; 276 char *val;
281 277
282 USE_ARG(httpd); 278 USE_ARG(httpd);
283 debug((httpd, DEBUG_EXPLODING, "parse in: %s", in)); 279 debug((httpd, DEBUG_EXPLODING, "parse in: %s", in));
284 *method = *file = *query = *proto = NULL; 280 *method = *file = *query = *proto = NULL;
285 281
286 len = (ssize_t)strlen(in); 282 len = (ssize_t)strlen(in);
287 val = bozostrnsep(&in, " \t\n\r", &len); 283 val = bozostrnsep(&in, " \t\n\r", &len);
288 if (len < 1 || val == NULL) 284 if (len < 1 || val == NULL)
289 return; 285 return;
290 *method = val; 286 *method = val;
291 287
292 while (*in == ' ' || *in == '\t') 288 while (*in == ' ' || *in == '\t')
293 in++; 289 in++;
294 val = bozostrnsep(&in, " \t\n\r", &len); 290 val = bozostrnsep(&in, " \t\n\r", &len);
295 if (len < 1) { 291 if (len < 1) {
296 if (len == 0) 292 if (len == 0)
297 *file = val; 293 *file = val;
298 else 294 else
299 *file = in; 295 *file = in;
300 } else { 296 } else {
301 *file = val; 297 *file = val;
302 298
303 *query = strchr(*file, '?'); 299 *query = strchr(*file, '?');
304 if (*query) 300 if (*query)
305 *(*query)++ = '\0'; 301 *(*query)++ = '\0';
306 302
307 if (in) { 303 if (in) {
308 while (*in && (*in == ' ' || *in == '\t')) 304 while (*in && (*in == ' ' || *in == '\t'))
309 in++; 305 in++;
310 if (*in) 306 if (*in)
311 *proto = in; 307 *proto = in;
312 } 308 }
313 } 309 }
314 310
315 /* allocate private copies */ 311 /* allocate private copies */
316 *file = bozostrdup(httpd, *file); 312 *file = bozostrdup(httpd, *file);
317 if (*query) 313 if (*query)
318 *query = bozostrdup(httpd, *query); 314 *query = bozostrdup(httpd, *query);
319 315
320 debug((httpd, DEBUG_FAT, 316 debug((httpd, DEBUG_FAT,
321 "url: method: \"%s\" file: \"%s\" query: \"%s\" proto: \"%s\"", 317 "url: method: \"%s\" file: \"%s\" query: \"%s\" proto: \"%s\"",
322 *method, *file, *query, *proto)); 318 *method, *file, *query, *proto));
323} 319}
324 320
325/* 321/*
326 * cleanup a bozo_httpreq_t after use 322 * cleanup a bozo_httpreq_t after use
327 */ 323 */
328void 324void
329bozo_clean_request(bozo_httpreq_t *request) 325bozo_clean_request(bozo_httpreq_t *request)
330{ 326{
331 struct bozoheaders *hdr, *ohdr = NULL; 327 struct bozoheaders *hdr, *ohdr = NULL;
332 328
333 if (request == NULL) 329 if (request == NULL)
334 return; 330 return;
335 331
336 /* If SSL enabled cleanup SSL structure. */ 332 /* If SSL enabled cleanup SSL structure. */
337 bozo_ssl_destroy(request->hr_httpd); 333 bozo_ssl_destroy(request->hr_httpd);
338 334
339 /* clean up request */ 335 /* clean up request */
340#define MF(x) if (request->x) free(request->x) 336#define MF(x) if (request->x) free(request->x)
341 MF(hr_remotehost); 337 MF(hr_remotehost);
342 MF(hr_remoteaddr); 338 MF(hr_remoteaddr);
343 MF(hr_serverport); 339 MF(hr_serverport);
344 MF(hr_file); 340 MF(hr_file);
345 MF(hr_oldfile); 341 MF(hr_oldfile);
346 MF(hr_query); 342 MF(hr_query);
347#undef MF 343#undef MF
348 bozo_auth_cleanup(request); 344 bozo_auth_cleanup(request);
349 for (hdr = SIMPLEQ_FIRST(&request->hr_headers); hdr; 345 for (hdr = SIMPLEQ_FIRST(&request->hr_headers); hdr;
350 hdr = SIMPLEQ_NEXT(hdr, h_next)) { 346 hdr = SIMPLEQ_NEXT(hdr, h_next)) {
351 free(hdr->h_value); 347 free(hdr->h_value);
352 free(hdr->h_header); 348 free(hdr->h_header);
353 if (ohdr) 349 if (ohdr)
354 free(ohdr); 350 free(ohdr);
355 ohdr = hdr; 351 ohdr = hdr;
356 } 352 }
357 if (ohdr) 353 if (ohdr)
358 free(ohdr); 354 free(ohdr);
359 355
360 free(request); 356 free(request);
361} 357}
362 358
363/* 359/*
364 * send a HTTP/1.1 408 response if we timeout. 360 * send a HTTP/1.1 408 response if we timeout.
365 */ 361 */
366/* ARGSUSED */ 362/* ARGSUSED */
367static void 363static void
368alarmer(int sig) 364alarmer(int sig)
369{ 365{
370 alarmhit = 1; 366 alarmhit = 1;
371} 367}
372 368
373/* 369/*
374 * add or merge this header (val: str) into the requests list 370 * add or merge this header (val: str) into the requests list
375 */ 371 */
376static bozoheaders_t * 372static bozoheaders_t *
377addmerge_header(bozo_httpreq_t *request, char *val, 373addmerge_header(bozo_httpreq_t *request, char *val,
378 char *str, ssize_t len) 374 char *str, ssize_t len)
379{ 375{
380 struct bozoheaders *hdr; 376 struct bozoheaders *hdr;
381 377
382 USE_ARG(len); 378 USE_ARG(len);
383 /* do we exist already? */ 379 /* do we exist already? */
384 SIMPLEQ_FOREACH(hdr, &request->hr_headers, h_next) { 380 SIMPLEQ_FOREACH(hdr, &request->hr_headers, h_next) {
385 if (strcasecmp(val, hdr->h_header) == 0) 381 if (strcasecmp(val, hdr->h_header) == 0)
386 break; 382 break;
387 } 383 }
388 384
389 if (hdr) { 385 if (hdr) {
390 /* yup, merge it in */ 386 /* yup, merge it in */
391 char *nval; 387 char *nval;
392 388
393 if (asprintf(&nval, "%s, %s", hdr->h_value, str) == -1) { 389 if (asprintf(&nval, "%s, %s", hdr->h_value, str) == -1) {
394 (void)bozo_http_error(request->hr_httpd, 500, NULL, 390 (void)bozo_http_error(request->hr_httpd, 500, NULL,
395 "memory allocation failure"); 391 "memory allocation failure");
396 return NULL; 392 return NULL;
397 } 393 }
398 free(hdr->h_value); 394 free(hdr->h_value);
399 hdr->h_value = nval; 395 hdr->h_value = nval;
400 } else { 396 } else {
401 /* nope, create a new one */ 397 /* nope, create a new one */
402 398
403 hdr = bozomalloc(request->hr_httpd, sizeof *hdr); 399 hdr = bozomalloc(request->hr_httpd, sizeof *hdr);
404 hdr->h_header = bozostrdup(request->hr_httpd, val); 400 hdr->h_header = bozostrdup(request->hr_httpd, val);
405 if (str && *str) 401 if (str && *str)
406 hdr->h_value = bozostrdup(request->hr_httpd, str); 402 hdr->h_value = bozostrdup(request->hr_httpd, str);
407 else 403 else
408 hdr->h_value = bozostrdup(request->hr_httpd, " "); 404 hdr->h_value = bozostrdup(request->hr_httpd, " ");
409 405
410 SIMPLEQ_INSERT_TAIL(&request->hr_headers, hdr, h_next); 406 SIMPLEQ_INSERT_TAIL(&request->hr_headers, hdr, h_next);
411 request->hr_nheaders++; 407 request->hr_nheaders++;
412 } 408 }
413 409
414 return hdr; 410 return hdr;
415} 411}
416 412
417/* 413/*
418 * as the prototype string is not constant (eg, "HTTP/1.1" is equivalent 414 * as the prototype string is not constant (eg, "HTTP/1.1" is equivalent
419 * to "HTTP/001.01"), we MUST parse this. 415 * to "HTTP/001.01"), we MUST parse this.
420 */ 416 */
421static int 417static int
422process_proto(bozo_httpreq_t *request, const char *proto) 418process_proto(bozo_httpreq_t *request, const char *proto)
423{ 419{
424 char majorstr[16], *minorstr; 420 char majorstr[16], *minorstr;
425 int majorint, minorint; 421 int majorint, minorint;
426 422
427 if (proto == NULL) { 423 if (proto == NULL) {
428got_proto_09: 424got_proto_09:
429 request->hr_proto = request->hr_httpd->consts.http_09; 425 request->hr_proto = request->hr_httpd->consts.http_09;
430 debug((request->hr_httpd, DEBUG_FAT, "request %s is http/0.9", 426 debug((request->hr_httpd, DEBUG_FAT, "request %s is http/0.9",
431 request->hr_file)); 427 request->hr_file));
432 return 0; 428 return 0;
433 } 429 }
434 430
435 if (strncasecmp(proto, "HTTP/", 5) != 0) 431 if (strncasecmp(proto, "HTTP/", 5) != 0)
436 goto bad; 432 goto bad;
437 strncpy(majorstr, proto + 5, sizeof majorstr); 433 strncpy(majorstr, proto + 5, sizeof majorstr);
438 majorstr[sizeof(majorstr)-1] = 0; 434 majorstr[sizeof(majorstr)-1] = 0;
439 minorstr = strchr(majorstr, '.'); 435 minorstr = strchr(majorstr, '.');
440 if (minorstr == NULL) 436 if (minorstr == NULL)
441 goto bad; 437 goto bad;
442 *minorstr++ = 0; 438 *minorstr++ = 0;
443 439
444 majorint = atoi(majorstr); 440 majorint = atoi(majorstr);
445 minorint = atoi(minorstr); 441 minorint = atoi(minorstr);
446 442
447 switch (majorint) { 443 switch (majorint) {
448 case 0: 444 case 0:
449 if (minorint != 9) 445 if (minorint != 9)
450 break; 446 break;
451 goto got_proto_09; 447 goto got_proto_09;
452 case 1: 448 case 1:
453 if (minorint == 0) 449 if (minorint == 0)
454 request->hr_proto = request->hr_httpd->consts.http_10; 450 request->hr_proto = request->hr_httpd->consts.http_10;
455 else if (minorint == 1) 451 else if (minorint == 1)
456 request->hr_proto = request->hr_httpd->consts.http_11; 452 request->hr_proto = request->hr_httpd->consts.http_11;
457 else 453 else
458 break; 454 break;
459 455
460 debug((request->hr_httpd, DEBUG_FAT, "request %s is %s", 456 debug((request->hr_httpd, DEBUG_FAT, "request %s is %s",
461 request->hr_file, request->hr_proto)); 457 request->hr_file, request->hr_proto));
462 SIMPLEQ_INIT(&request->hr_headers); 458 SIMPLEQ_INIT(&request->hr_headers);
463 request->hr_nheaders = 0; 459 request->hr_nheaders = 0;
464 return 0; 460 return 0;
465 } 461 }
466bad: 462bad:
467 return bozo_http_error(request->hr_httpd, 404, NULL, "unknown prototype"); 463 return bozo_http_error(request->hr_httpd, 404, NULL, "unknown prototype");
468} 464}
469 465
470/* 466/*
471 * process each type of HTTP method, setting this HTTP requests 467 * process each type of HTTP method, setting this HTTP requests
472 # method type. 468 # method type.
473 */ 469 */
474static struct method_map { 470static struct method_map {
475 const char *name; 471 const char *name;
476 int type; 472 int type;
477} method_map[] = { 473} method_map[] = {
478 { "GET", HTTP_GET, }, 474 { "GET", HTTP_GET, },
479 { "POST", HTTP_POST, }, 475 { "POST", HTTP_POST, },
480 { "HEAD", HTTP_HEAD, }, 476 { "HEAD", HTTP_HEAD, },
481#if 0 /* other non-required http/1.1 methods */ 477#if 0 /* other non-required http/1.1 methods */
482 { "OPTIONS", HTTP_OPTIONS, }, 478 { "OPTIONS", HTTP_OPTIONS, },
483 { "PUT", HTTP_PUT, }, 479 { "PUT", HTTP_PUT, },
484 { "DELETE", HTTP_DELETE, }, 480 { "DELETE", HTTP_DELETE, },
485 { "TRACE", HTTP_TRACE, }, 481 { "TRACE", HTTP_TRACE, },
486 { "CONNECT", HTTP_CONNECT, }, 482 { "CONNECT", HTTP_CONNECT, },
487#endif 483#endif
488 { NULL, 0, }, 484 { NULL, 0, },
489}; 485};
490 486
491static int 487static int
492process_method(bozo_httpreq_t *request, const char *method) 488process_method(bozo_httpreq_t *request, const char *method)
493{ 489{
494 struct method_map *mmp; 490 struct method_map *mmp;
495 491
496 if (request->hr_proto == request->hr_httpd->consts.http_11) 492 if (request->hr_proto == request->hr_httpd->consts.http_11)
497 request->hr_allow = "GET, HEAD, POST"; 493 request->hr_allow = "GET, HEAD, POST";
498 494
499 for (mmp = method_map; mmp->name; mmp++) 495 for (mmp = method_map; mmp->name; mmp++)
500 if (strcasecmp(method, mmp->name) == 0) { 496 if (strcasecmp(method, mmp->name) == 0) {
501 request->hr_method = mmp->type; 497 request->hr_method = mmp->type;
502 request->hr_methodstr = mmp->name; 498 request->hr_methodstr = mmp->name;
503 return 0; 499 return 0;
504 } 500 }
505 501
506 return bozo_http_error(request->hr_httpd, 404, request, "unknown method"); 502 return bozo_http_error(request->hr_httpd, 404, request, "unknown method");
507} 503}
508 504
509/* 505/*
510 * This function reads a http request from stdin, returning a pointer to a 506 * This function reads a http request from stdin, returning a pointer to a
511 * bozo_httpreq_t structure, describing the request. 507 * bozo_httpreq_t structure, describing the request.
512 */ 508 */
513bozo_httpreq_t * 509bozo_httpreq_t *
514bozo_read_request(bozohttpd_t *httpd) 510bozo_read_request(bozohttpd_t *httpd)
515{ 511{
516 struct sigaction sa; 512 struct sigaction sa;
517 char *str, *val, *method, *file, *proto, *query; 513 char *str, *val, *method, *file, *proto, *query;
518 char *host, *addr, *port; 514 char *host, *addr, *port;
519 char bufport[10]; 515 char bufport[10];
520 char hbuf[NI_MAXHOST], abuf[NI_MAXHOST]; 516 char hbuf[NI_MAXHOST], abuf[NI_MAXHOST];
521 struct sockaddr_storage ss; 517 struct sockaddr_storage ss;
522 ssize_t len; 518 ssize_t len;
523 int line = 0; 519 int line = 0;
524 socklen_t slen; 520 socklen_t slen;
525 bozo_httpreq_t *request; 521 bozo_httpreq_t *request;
526 522
527 /* 523 /*
528 * if we're in daemon mode, bozo_daemon_fork() will return here twice 524 * if we're in daemon mode, bozo_daemon_fork() will return here twice
529 * for each call. once in the child, returning 0, and once in the 525 * for each call. once in the child, returning 0, and once in the
530 * parent, returning 1. for each child, then we can setup SSL, and 526 * parent, returning 1. for each child, then we can setup SSL, and
531 * the parent can signal the caller there was no request to process 527 * the parent can signal the caller there was no request to process
532 * and it will wait for another. 528 * and it will wait for another.
533 */ 529 */
534 if (bozo_daemon_fork(httpd)) 530 if (bozo_daemon_fork(httpd))
535 return NULL; 531 return NULL;
536 bozo_ssl_accept(httpd); 532 bozo_ssl_accept(httpd);
537 533
538 request = bozomalloc(httpd, sizeof(*request)); 534 request = bozomalloc(httpd, sizeof(*request));
539 memset(request, 0, sizeof(*request)); 535 memset(request, 0, sizeof(*request));
540 request->hr_httpd = httpd; 536 request->hr_httpd = httpd;
541 request->hr_allow = request->hr_host = NULL; 537 request->hr_allow = request->hr_host = NULL;
542 request->hr_content_type = request->hr_content_length = NULL; 538 request->hr_content_type = request->hr_content_length = NULL;
543 request->hr_range = NULL; 539 request->hr_range = NULL;
544 request->hr_last_byte_pos = -1; 540 request->hr_last_byte_pos = -1;
545 request->hr_if_modified_since = NULL; 541 request->hr_if_modified_since = NULL;
546 request->hr_file = NULL; 542 request->hr_file = NULL;
547 request->hr_oldfile = NULL; 543 request->hr_oldfile = NULL;
548 544
549 slen = sizeof(ss); 545 slen = sizeof(ss);
550 if (getpeername(0, (struct sockaddr *)(void *)&ss, &slen) < 0) 546 if (getpeername(0, (struct sockaddr *)(void *)&ss, &slen) < 0)
551 host = addr = NULL; 547 host = addr = NULL;
552 else { 548 else {
553 if (getnameinfo((struct sockaddr *)(void *)&ss, slen, 549 if (getnameinfo((struct sockaddr *)(void *)&ss, slen,
554 abuf, sizeof abuf, NULL, 0, NI_NUMERICHOST) == 0) 550 abuf, sizeof abuf, NULL, 0, NI_NUMERICHOST) == 0)
555 addr = abuf; 551 addr = abuf;
556 else 552 else
557 addr = NULL; 553 addr = NULL;
558 if (httpd->numeric == 0 && 554 if (httpd->numeric == 0 &&
559 getnameinfo((struct sockaddr *)(void *)&ss, slen, 555 getnameinfo((struct sockaddr *)(void *)&ss, slen,
560 hbuf, sizeof hbuf, NULL, 0, 0) == 0) 556 hbuf, sizeof hbuf, NULL, 0, 0) == 0)
561 host = hbuf; 557 host = hbuf;
562 else 558 else
563 host = NULL; 559 host = NULL;
564 } 560 }
565 if (host != NULL) 561 if (host != NULL)
566 request->hr_remotehost = bozostrdup(request->hr_httpd, host); 562 request->hr_remotehost = bozostrdup(request->hr_httpd, host);
567 if (addr != NULL) 563 if (addr != NULL)
568 request->hr_remoteaddr = bozostrdup(request->hr_httpd, addr); 564 request->hr_remoteaddr = bozostrdup(request->hr_httpd, addr);
569 slen = sizeof(ss); 565 slen = sizeof(ss);
570 if (getsockname(0, (struct sockaddr *)(void *)&ss, &slen) < 0) 566 if (getsockname(0, (struct sockaddr *)(void *)&ss, &slen) < 0)
571 port = NULL; 567 port = NULL;
572 else { 568 else {
573 if (getnameinfo((struct sockaddr *)(void *)&ss, slen, NULL, 0, 569 if (getnameinfo((struct sockaddr *)(void *)&ss, slen, NULL, 0,
574 bufport, sizeof bufport, NI_NUMERICSERV) == 0) 570 bufport, sizeof bufport, NI_NUMERICSERV) == 0)
575 port = bufport; 571 port = bufport;
576 else 572 else
577 port = NULL; 573 port = NULL;
578 } 574 }
579 if (port != NULL) 575 if (port != NULL)
580 request->hr_serverport = bozostrdup(request->hr_httpd, port); 576 request->hr_serverport = bozostrdup(request->hr_httpd, port);
581 577
582 /* 578 /*
583 * setup a timer to make sure the request is not hung 579 * setup a timer to make sure the request is not hung
584 */ 580 */
585 sa.sa_handler = alarmer; 581 sa.sa_handler = alarmer;
586 sigemptyset(&sa.sa_mask); 582 sigemptyset(&sa.sa_mask);
587 sigaddset(&sa.sa_mask, SIGALRM); 583 sigaddset(&sa.sa_mask, SIGALRM);
588 sa.sa_flags = 0; 584 sa.sa_flags = 0;
589 sigaction(SIGALRM, &sa, NULL); /* XXX */ 585 sigaction(SIGALRM, &sa, NULL); /* XXX */
590 586
591 alarm(MAX_WAIT_TIME); 587 alarm(MAX_WAIT_TIME);
592 while ((str = bozodgetln(httpd, STDIN_FILENO, &len, bozo_read)) != NULL) { 588 while ((str = bozodgetln(httpd, STDIN_FILENO, &len, bozo_read)) != NULL) {
593 alarm(0); 589 alarm(0);
594 if (alarmhit) { 590 if (alarmhit) {
595 (void)bozo_http_error(httpd, 408, NULL, 591 (void)bozo_http_error(httpd, 408, NULL,
596 "request timed out"); 592 "request timed out");
597 goto cleanup; 593 goto cleanup;
598 } 594 }
599 line++; 595 line++;
600 596
601 if (line == 1) { 597 if (line == 1) {
602 598
603 if (len < 1) { 599 if (len < 1) {
604 (void)bozo_http_error(httpd, 404, NULL, 600 (void)bozo_http_error(httpd, 404, NULL,
605 "null method"); 601 "null method");
606 goto cleanup; 602 goto cleanup;
607 } 603 }
608 604
609 bozo_warn(httpd, "got request ``%s'' from host %s to port %s", 605 bozo_warn(httpd, "got request ``%s'' from host %s to port %s",
610 str, 606 str,
611 host ? host : addr ? addr : "<local>", 607 host ? host : addr ? addr : "<local>",
612 port ? port : "<stdin>"); 608 port ? port : "<stdin>");
613 609
614 /* we allocate return space in file and query only */ 610 /* we allocate return space in file and query only */
615 parse_request(httpd, str, &method, &file, &query, &proto); 611 parse_request(httpd, str, &method, &file, &query, &proto);
616 request->hr_file = file; 612 request->hr_file = file;
617 request->hr_query = query; 613 request->hr_query = query;
618 if (method == NULL) { 614 if (method == NULL) {
619 (void)bozo_http_error(httpd, 404, NULL, 615 (void)bozo_http_error(httpd, 404, NULL,
620 "null method"); 616 "null method");
621 goto cleanup; 617 goto cleanup;
622 } 618 }
623 if (file == NULL) { 619 if (file == NULL) {
624 (void)bozo_http_error(httpd, 404, NULL, 620 (void)bozo_http_error(httpd, 404, NULL,
625 "null file"); 621 "null file");
626 goto cleanup; 622 goto cleanup;
627 } 623 }
628 624
629 /* 625 /*
630 * note that we parse the proto first, so that we 626 * note that we parse the proto first, so that we
631 * can more properly parse the method and the url. 627 * can more properly parse the method and the url.
632 */ 628 */
633 629
634 if (process_proto(request, proto) || 630 if (process_proto(request, proto) ||
635 process_method(request, method)) { 631 process_method(request, method)) {
636 goto cleanup; 632 goto cleanup;
637 } 633 }
638 634
639 debug((httpd, DEBUG_FAT, "got file \"%s\" query \"%s\"", 635 debug((httpd, DEBUG_FAT, "got file \"%s\" query \"%s\"",
640 request->hr_file, 636 request->hr_file,
641 request->hr_query ? request->hr_query : "<none>")); 637 request->hr_query ? request->hr_query : "<none>"));
642 638
643 /* http/0.9 has no header processing */ 639 /* http/0.9 has no header processing */
644 if (request->hr_proto == httpd->consts.http_09) 640 if (request->hr_proto == httpd->consts.http_09)
645 break; 641 break;
646 } else { /* incoming headers */ 642 } else { /* incoming headers */
647 bozoheaders_t *hdr; 643 bozoheaders_t *hdr;
648 644
649 if (*str == '\0') 645 if (*str == '\0')
650 break; 646 break;
651 647
652 val = bozostrnsep(&str, ":", &len); 648 val = bozostrnsep(&str, ":", &len);
653 debug((httpd, DEBUG_EXPLODING, 649 debug((httpd, DEBUG_EXPLODING,
654 "read_req2: after bozostrnsep: str ``%s'' val ``%s''", 650 "read_req2: after bozostrnsep: str ``%s'' val ``%s''",
655 str, val)); 651 str, val));
656 if (val == NULL || len == -1) { 652 if (val == NULL || len == -1) {
657 (void)bozo_http_error(httpd, 404, request, 653 (void)bozo_http_error(httpd, 404, request,
658 "no header"); 654 "no header");
659 goto cleanup; 655 goto cleanup;
660 } 656 }
661 while (*str == ' ' || *str == '\t') 657 while (*str == ' ' || *str == '\t')
662 len--, str++; 658 len--, str++;
663 while (*val == ' ' || *val == '\t') 659 while (*val == ' ' || *val == '\t')
664 val++; 660 val++;
665 661
666 if (bozo_auth_check_headers(request, val, str, len)) 662 if (bozo_auth_check_headers(request, val, str, len))
667 goto next_header; 663 goto next_header;
668 664
669 hdr = addmerge_header(request, val, str, len); 665 hdr = addmerge_header(request, val, str, len);
670 666
671 if (strcasecmp(hdr->h_header, "content-type") == 0) 667 if (strcasecmp(hdr->h_header, "content-type") == 0)
672 request->hr_content_type = hdr->h_value; 668 request->hr_content_type = hdr->h_value;
673 else if (strcasecmp(hdr->h_header, "content-length") == 0) 669 else if (strcasecmp(hdr->h_header, "content-length") == 0)
674 request->hr_content_length = hdr->h_value; 670 request->hr_content_length = hdr->h_value;
675 else if (strcasecmp(hdr->h_header, "host") == 0) 671 else if (strcasecmp(hdr->h_header, "host") == 0)
676 request->hr_host = hdr->h_value; 672 request->hr_host = hdr->h_value;
677 /* HTTP/1.1 rev06 draft spec: 14.20 */ 673 /* HTTP/1.1 rev06 draft spec: 14.20 */
678 else if (strcasecmp(hdr->h_header, "expect") == 0) { 674 else if (strcasecmp(hdr->h_header, "expect") == 0) {
679 (void)bozo_http_error(httpd, 417, request, 675 (void)bozo_http_error(httpd, 417, request,
680 "we don't support Expect:"); 676 "we don't support Expect:");
681 goto cleanup; 677 goto cleanup;
682 } 678 }
683 else if (strcasecmp(hdr->h_header, "referrer") == 0 || 679 else if (strcasecmp(hdr->h_header, "referrer") == 0 ||
684 strcasecmp(hdr->h_header, "referer") == 0) 680 strcasecmp(hdr->h_header, "referer") == 0)
685 request->hr_referrer = hdr->h_value; 681 request->hr_referrer = hdr->h_value;
686 else if (strcasecmp(hdr->h_header, "range") == 0) 682 else if (strcasecmp(hdr->h_header, "range") == 0)
687 request->hr_range = hdr->h_value; 683 request->hr_range = hdr->h_value;
688 else if (strcasecmp(hdr->h_header, 684 else if (strcasecmp(hdr->h_header,
689 "if-modified-since") == 0) 685 "if-modified-since") == 0)
690 request->hr_if_modified_since = hdr->h_value; 686 request->hr_if_modified_since = hdr->h_value;
691 687
692 debug((httpd, DEBUG_FAT, "adding header %s: %s", 688 debug((httpd, DEBUG_FAT, "adding header %s: %s",
693 hdr->h_header, hdr->h_value)); 689 hdr->h_header, hdr->h_value));
694 } 690 }
695next_header: 691next_header:
696 alarm(MAX_WAIT_TIME); 692 alarm(MAX_WAIT_TIME);
697 } 693 }
698 694
699 /* now, clear it all out */ 695 /* now, clear it all out */
700 alarm(0); 696 alarm(0);
701 signal(SIGALRM, SIG_DFL); 697 signal(SIGALRM, SIG_DFL);
702 698
703 /* RFC1945, 8.3 */ 699 /* RFC1945, 8.3 */
704 if (request->hr_method == HTTP_POST && 700 if (request->hr_method == HTTP_POST &&
705 request->hr_content_length == NULL) { 701 request->hr_content_length == NULL) {
706 (void)bozo_http_error(httpd, 400, request, 702 (void)bozo_http_error(httpd, 400, request,
707 "missing content length"); 703 "missing content length");
708 goto cleanup; 704 goto cleanup;
709 } 705 }
710 706
711 /* HTTP/1.1 draft rev-06, 14.23 & 19.6.1.1 */ 707 /* HTTP/1.1 draft rev-06, 14.23 & 19.6.1.1 */
712 if (request->hr_proto == httpd->consts.http_11 && 708 if (request->hr_proto == httpd->consts.http_11 &&
713 request->hr_host == NULL) { 709 request->hr_host == NULL) {
714 (void)bozo_http_error(httpd, 400, request, 710 (void)bozo_http_error(httpd, 400, request,
715 "missing Host header"); 711 "missing Host header");
716 goto cleanup; 712 goto cleanup;
717 } 713 }
718 714
719 if (request->hr_range != NULL) { 715 if (request->hr_range != NULL) {
720 debug((httpd, DEBUG_FAT, "hr_range: %s", request->hr_range)); 716 debug((httpd, DEBUG_FAT, "hr_range: %s", request->hr_range));
721 /* support only simple ranges %d- and %d-%d */ 717 /* support only simple ranges %d- and %d-%d */
722 if (strchr(request->hr_range, ',') == NULL) { 718 if (strchr(request->hr_range, ',') == NULL) {
723 const char *rstart, *dash; 719 const char *rstart, *dash;
724 720
725 rstart = strchr(request->hr_range, '='); 721 rstart = strchr(request->hr_range, '=');
726 if (rstart != NULL) { 722 if (rstart != NULL) {
727 rstart++; 723 rstart++;
728 dash = strchr(rstart, '-'); 724 dash = strchr(rstart, '-');
729 if (dash != NULL && dash != rstart) { 725 if (dash != NULL && dash != rstart) {
730 dash++; 726 dash++;
731 request->hr_have_range = 1; 727 request->hr_have_range = 1;
732 request->hr_first_byte_pos = 728 request->hr_first_byte_pos =
733 strtoll(rstart, NULL, 10); 729 strtoll(rstart, NULL, 10);
734 if (request->hr_first_byte_pos < 0) 730 if (request->hr_first_byte_pos < 0)
735 request->hr_first_byte_pos = 0; 731 request->hr_first_byte_pos = 0;
736 if (*dash != '\0') { 732 if (*dash != '\0') {
737 request->hr_last_byte_pos = 733 request->hr_last_byte_pos =
738 strtoll(dash, NULL, 10); 734 strtoll(dash, NULL, 10);
739 if (request->hr_last_byte_pos < 0) 735 if (request->hr_last_byte_pos < 0)
740 request->hr_last_byte_pos = -1; 736 request->hr_last_byte_pos = -1;
741 } 737 }
742 } 738 }
743 } 739 }
744 } 740 }
745 } 741 }
746 742
747 debug((httpd, DEBUG_FAT, "bozo_read_request returns url %s in request", 743 debug((httpd, DEBUG_FAT, "bozo_read_request returns url %s in request",
748 request->hr_file)); 744 request->hr_file));
749 return request; 745 return request;
750 746
751cleanup: 747cleanup:
752 bozo_clean_request(request); 748 bozo_clean_request(request);
753 749
754 return NULL; 750 return NULL;
755} 751}
756 752
757static int 753static int
758mmap_and_write_part(bozohttpd_t *httpd, int fd, off_t first_byte_pos, size_t sz) 754mmap_and_write_part(bozohttpd_t *httpd, int fd, off_t first_byte_pos, size_t sz)
759{ 755{
760 size_t mappedsz, wroffset; 756 size_t mappedsz, wroffset;
761 off_t mappedoffset; 757 off_t mappedoffset;
762 char *addr; 758 char *addr;
763 void *mappedaddr; 759 void *mappedaddr;
764 760
765 /* 761 /*
766 * we need to ensure that both the size *and* offset arguments to 762 * we need to ensure that both the size *and* offset arguments to
767 * mmap() are page-aligned. our formala for this is: 763 * mmap() are page-aligned. our formala for this is:
768 * 764 *
769 * input offset: first_byte_pos 765 * input offset: first_byte_pos
770 * input size: sz 766 * input size: sz
771 * 767 *
772 * mapped offset = page align truncate (input offset) 768 * mapped offset = page align truncate (input offset)
773 * mapped size = 769 * mapped size =
774 * page align extend (input offset - mapped offset + input size) 770 * page align extend (input offset - mapped offset + input size)
775 * write offset = input offset - mapped offset 771 * write offset = input offset - mapped offset
776 * 772 *
777 * we use the write offset in all writes 773 * we use the write offset in all writes
778 */ 774 */
779 mappedoffset = first_byte_pos & ~(httpd->page_size - 1); 775 mappedoffset = first_byte_pos & ~(httpd->page_size - 1);
780 mappedsz = (size_t) 776 mappedsz = (size_t)
781 (first_byte_pos - mappedoffset + sz + httpd->page_size - 1) & 777 (first_byte_pos - mappedoffset + sz + httpd->page_size - 1) &
782 ~(httpd->page_size - 1); 778 ~(httpd->page_size - 1);
783 wroffset = (size_t)(first_byte_pos - mappedoffset); 779 wroffset = (size_t)(first_byte_pos - mappedoffset);
784 780
785 addr = mmap(0, mappedsz, PROT_READ, MAP_SHARED, fd, mappedoffset); 781 addr = mmap(0, mappedsz, PROT_READ, MAP_SHARED, fd, mappedoffset);
786 if (addr == (char *)-1) { 782 if (addr == (char *)-1) {
787 bozo_warn(httpd, "mmap failed: %s", strerror(errno)); 783 bozo_warn(httpd, "mmap failed: %s", strerror(errno));
788 return -1; 784 return -1;
789 } 785 }
790 mappedaddr = addr; 786 mappedaddr = addr;
791 787
792#ifdef MADV_SEQUENTIAL 788#ifdef MADV_SEQUENTIAL
793 (void)madvise(addr, sz, MADV_SEQUENTIAL); 789 (void)madvise(addr, sz, MADV_SEQUENTIAL);
794#endif 790#endif
795 while (sz > BOZO_WRSZ) { 791 while (sz > BOZO_WRSZ) {
796 if (bozo_write(httpd, STDOUT_FILENO, addr + wroffset, 792 if (bozo_write(httpd, STDOUT_FILENO, addr + wroffset,
797 BOZO_WRSZ) != BOZO_WRSZ) { 793 BOZO_WRSZ) != BOZO_WRSZ) {
798 bozo_warn(httpd, "write failed: %s", strerror(errno)); 794 bozo_warn(httpd, "write failed: %s", strerror(errno));
799 goto out; 795 goto out;
800 } 796 }
801 debug((httpd, DEBUG_OBESE, "wrote %d bytes", BOZO_WRSZ)); 797 debug((httpd, DEBUG_OBESE, "wrote %d bytes", BOZO_WRSZ));
802 sz -= BOZO_WRSZ; 798 sz -= BOZO_WRSZ;
803 addr += BOZO_WRSZ; 799 addr += BOZO_WRSZ;
804 } 800 }
805 if (sz && (size_t)bozo_write(httpd, STDOUT_FILENO, addr + wroffset, 801 if (sz && (size_t)bozo_write(httpd, STDOUT_FILENO, addr + wroffset,
806 sz) != sz) { 802 sz) != sz) {
807 bozo_warn(httpd, "final write failed: %s", strerror(errno)); 803 bozo_warn(httpd, "final write failed: %s", strerror(errno));
808 goto out; 804 goto out;
809 } 805 }
810 debug((httpd, DEBUG_OBESE, "wrote %d bytes", (int)sz)); 806 debug((httpd, DEBUG_OBESE, "wrote %d bytes", (int)sz));
811 out: 807 out:
812 if (munmap(mappedaddr, mappedsz) < 0) { 808 if (munmap(mappedaddr, mappedsz) < 0) {
813 bozo_warn(httpd, "munmap failed"); 809 bozo_warn(httpd, "munmap failed");
814 return -1; 810 return -1;
815 } 811 }
816 812
817 return 0; 813 return 0;
818} 814}
819 815
820static int 816static int
821parse_http_date(const char *val, time_t *timestamp) 817parse_http_date(const char *val, time_t *timestamp)
822{ 818{
823 char *remainder; 819 char *remainder;
824 struct tm tm; 820 struct tm tm;
825 821
826 if ((remainder = strptime(val, "%a, %d %b %Y %T GMT", &tm)) == NULL && 822 if ((remainder = strptime(val, "%a, %d %b %Y %T GMT", &tm)) == NULL &&
827 (remainder = strptime(val, "%a, %d-%b-%y %T GMT", &tm)) == NULL && 823 (remainder = strptime(val, "%a, %d-%b-%y %T GMT", &tm)) == NULL &&
828 (remainder = strptime(val, "%a %b %d %T %Y", &tm)) == NULL) 824 (remainder = strptime(val, "%a %b %d %T %Y", &tm)) == NULL)
829 return 0; /* Invalid HTTP date format */ 825 return 0; /* Invalid HTTP date format */
830 826
831 if (*remainder) 827 if (*remainder)
832 return 0; /* No trailing garbage */ 828 return 0; /* No trailing garbage */
833 829
834 *timestamp = timegm(&tm); 830 *timestamp = timegm(&tm);
835 return 1; 831 return 1;
836} 832}
837 833
838/* 834/*
839 * checks to see if this request has a valid .bzdirect file. returns 835 * checks to see if this request has a valid .bzdirect file. returns
840 * 0 on failure and 1 on success. 836 * 0 on failure and 1 on success.
841 */ 837 */
842static int 838static int
843check_direct_access(bozo_httpreq_t *request) 839check_direct_access(bozo_httpreq_t *request)
844{ 840{
845 FILE *fp; 841 FILE *fp;
846 struct stat sb; 842 struct stat sb;
847 char dir[MAXPATHLEN], dirfile[MAXPATHLEN], *basename; 843 char dir[MAXPATHLEN], dirfile[MAXPATHLEN], *basename;
848 844
849 snprintf(dir, sizeof(dir), "%s", request->hr_file + 1); 845 snprintf(dir, sizeof(dir), "%s", request->hr_file + 1);
850 debug((request->hr_httpd, DEBUG_FAT, "check_bzredirect: dir %s", dir)); 846 debug((request->hr_httpd, DEBUG_FAT, "check_bzredirect: dir %s", dir));
851 basename = strrchr(dir, '/'); 847 basename = strrchr(dir, '/');
852 848
853 if ((!basename || basename[1] != '\0') && 849 if ((!basename || basename[1] != '\0') &&
854 lstat(dir, &sb) == 0 && S_ISDIR(sb.st_mode)) 850 lstat(dir, &sb) == 0 && S_ISDIR(sb.st_mode))
855 /* nothing */; 851 /* nothing */;
856 else if (basename == NULL) 852 else if (basename == NULL)
857 strcpy(dir, "."); 853 strcpy(dir, ".");
858 else { 854 else {
859 *basename++ = '\0'; 855 *basename++ = '\0';
860 bozo_check_special_files(request, basename); 856 bozo_check_special_files(request, basename);
861 } 857 }
862 858
863 snprintf(dirfile, sizeof(dirfile), "%s/%s", dir, DIRECT_ACCESS_FILE); 859 snprintf(dirfile, sizeof(dirfile), "%s/%s", dir, DIRECT_ACCESS_FILE);
864 if (stat(dirfile, &sb) < 0 || 860 if (stat(dirfile, &sb) < 0 ||
865 (fp = fopen(dirfile, "r")) == NULL) 861 (fp = fopen(dirfile, "r")) == NULL)
866 return 0; 862 return 0;
867 fclose(fp); 863 fclose(fp);
868 return 1; 864 return 1;
869} 865}
870 866
871/* 867/*
872 * do automatic redirection -- if there are query parameters for the URL 868 * do automatic redirection -- if there are query parameters for the URL
873 * we will tack these on to the new (redirected) URL. 869 * we will tack these on to the new (redirected) URL.
874 */ 870 */
875static void 871static void
876handle_redirect(bozo_httpreq_t *request, 872handle_redirect(bozo_httpreq_t *request,
877 const char *url, int absolute) 873 const char *url, int absolute)
878{ 874{
879 bozohttpd_t *httpd = request->hr_httpd; 875 bozohttpd_t *httpd = request->hr_httpd;
880 char *urlbuf; 876 char *urlbuf;
881 char portbuf[20]; 877 char portbuf[20];
882 int query = 0; 878 int query = 0;
883  879
884 if (url == NULL) { 880 if (url == NULL) {
885 if (asprintf(&urlbuf, "/%s/", request->hr_file) < 0) 881 if (asprintf(&urlbuf, "/%s/", request->hr_file) < 0)
886 bozo_err(httpd, 1, "asprintf"); 882 bozo_err(httpd, 1, "asprintf");
887 url = urlbuf; 883 url = urlbuf;
888 } else 884 } else
889 urlbuf = NULL; 885 urlbuf = NULL;
890 886
891 if (request->hr_query && strlen(request->hr_query)) { 887 if (request->hr_query && strlen(request->hr_query)) {
892 query = 1; 888 query = 1;
893 } 889 }
894 890
895 if (request->hr_serverport && strcmp(request->hr_serverport, "80") != 0) 891 if (request->hr_serverport && strcmp(request->hr_serverport, "80") != 0)
896 snprintf(portbuf, sizeof(portbuf), ":%s", 892 snprintf(portbuf, sizeof(portbuf), ":%s",
897 request->hr_serverport); 893 request->hr_serverport);
898 else 894 else
899 portbuf[0] = '\0'; 895 portbuf[0] = '\0';
900 bozo_warn(httpd, "redirecting %s%s%s", httpd->virthostname, portbuf, url); 896 bozo_warn(httpd, "redirecting %s%s%s", httpd->virthostname, portbuf, url);
901 debug((httpd, DEBUG_FAT, "redirecting %s", url)); 897 debug((httpd, DEBUG_FAT, "redirecting %s", url));
902 bozo_printf(httpd, "%s 301 Document Moved\r\n", request->hr_proto); 898 bozo_printf(httpd, "%s 301 Document Moved\r\n", request->hr_proto);
903 if (request->hr_proto != httpd->consts.http_09)  899 if (request->hr_proto != httpd->consts.http_09)
904 bozo_print_header(request, NULL, "text/html", NULL); 900 bozo_print_header(request, NULL, "text/html", NULL);
905 if (request->hr_proto != httpd->consts.http_09) { 901 if (request->hr_proto != httpd->consts.http_09) {
906 bozo_printf(httpd, "Location: http://"); 902 bozo_printf(httpd, "Location: http://");
907 if (absolute == 0) 903 if (absolute == 0)
908 bozo_printf(httpd, "%s%s", httpd->virthostname, portbuf); 904 bozo_printf(httpd, "%s%s", httpd->virthostname, portbuf);
909 if (query) { 905 if (query) {
910 bozo_printf(httpd, "%s?%s\r\n", url, request->hr_query); 906 bozo_printf(httpd, "%s?%s\r\n", url, request->hr_query);
911 } else { 907 } else {
912 bozo_printf(httpd, "%s\r\n", url); 908 bozo_printf(httpd, "%s\r\n", url);
913 } 909 }
914 } 910 }
915 bozo_printf(httpd, "\r\n"); 911 bozo_printf(httpd, "\r\n");
916 if (request->hr_method == HTTP_HEAD) 912 if (request->hr_method == HTTP_HEAD)
917 goto head; 913 goto head;
918 bozo_printf(httpd, "<html><head><title>Document Moved</title></head>\n"); 914 bozo_printf(httpd, "<html><head><title>Document Moved</title></head>\n");
919 bozo_printf(httpd, "<body><h1>Document Moved</h1>\n"); 915 bozo_printf(httpd, "<body><h1>Document Moved</h1>\n");
920 bozo_printf(httpd, "This document had moved <a href=\"http://"); 916 bozo_printf(httpd, "This document had moved <a href=\"http://");
921 if (query) { 917 if (query) {
922 if (absolute) 918 if (absolute)
923 bozo_printf(httpd, "%s?%s", url, request->hr_query); 919 bozo_printf(httpd, "%s?%s", url, request->hr_query);
924 else 920 else
925 bozo_printf(httpd, "%s%s%s?%s", httpd->virthostname, portbuf, url, 921 bozo_printf(httpd, "%s%s%s?%s", httpd->virthostname, portbuf, url,
926 request->hr_query); 922 request->hr_query);
927 } else { 923 } else {
928 if (absolute) 924 if (absolute)
929 bozo_printf(httpd, "%s", url); 925 bozo_printf(httpd, "%s", url);
930 else 926 else
931 bozo_printf(httpd, "%s%s%s", httpd->virthostname, portbuf, url); 927 bozo_printf(httpd, "%s%s%s", httpd->virthostname, portbuf, url);
932 } 928 }
933 bozo_printf(httpd, "\">here</a>\n"); 929 bozo_printf(httpd, "\">here</a>\n");
934 bozo_printf(httpd, "</body></html>\n"); 930 bozo_printf(httpd, "</body></html>\n");
935head: 931head:
936 bozo_flush(httpd, stdout); 932 bozo_flush(httpd, stdout);
937 if (urlbuf) 933 if (urlbuf)
938 free(urlbuf); 934 free(urlbuf);
939} 935}
940 936
941/* 937/*
942 * deal with virtual host names; we do this: 938 * deal with virtual host names; we do this:
943 * if we have a virtual path root (httpd->virtbase), and we are given a 939 * if we have a virtual path root (httpd->virtbase), and we are given a
944 * virtual host spec (Host: ho.st or http://ho.st/), see if this 940 * virtual host spec (Host: ho.st or http://ho.st/), see if this
945 * directory exists under httpd->virtbase. if it does, use this as the 941 * directory exists under httpd->virtbase. if it does, use this as the
946 # new slashdir. 942 # new slashdir.
947 */ 943 */
948static int 944static int
949check_virtual(bozo_httpreq_t *request) 945check_virtual(bozo_httpreq_t *request)
950{ 946{
951 bozohttpd_t *httpd = request->hr_httpd; 947 bozohttpd_t *httpd = request->hr_httpd;
952 char *file = request->hr_file, *s; 948 char *file = request->hr_file, *s;
953 size_t len; 949 size_t len;
954 950
955 if (!httpd->virtbase) 951 if (!httpd->virtbase)
956 goto use_slashdir; 952 goto use_slashdir;
957 953
958 /* 954 /*
959 * convert http://virtual.host/ to request->hr_host 955 * convert http://virtual.host/ to request->hr_host
960 */ 956 */
961 debug((httpd, DEBUG_OBESE, "checking for http:// virtual host in ``%s''", 957 debug((httpd, DEBUG_OBESE, "checking for http:// virtual host in ``%s''",
962 file)); 958 file));
963 if (strncasecmp(file, "http://", 7) == 0) { 959 if (strncasecmp(file, "http://", 7) == 0) {
964 /* we would do virtual hosting here? */ 960 /* we would do virtual hosting here? */
965 file += 7; 961 file += 7;
966 s = strchr(file, '/'); 962 s = strchr(file, '/');
967 /* HTTP/1.1 draft rev-06, 5.2: URI takes precedence over Host: */ 963 /* HTTP/1.1 draft rev-06, 5.2: URI takes precedence over Host: */
968 request->hr_host = file; 964 request->hr_host = file;
969 request->hr_file = bozostrdup(request->hr_httpd, s ? s : "/"); 965 request->hr_file = bozostrdup(request->hr_httpd, s ? s : "/");
970 debug((httpd, DEBUG_OBESE, "got host ``%s'' file is now ``%s''", 966 debug((httpd, DEBUG_OBESE, "got host ``%s'' file is now ``%s''",
971 request->hr_host, request->hr_file)); 967 request->hr_host, request->hr_file));
972 } else if (!request->hr_host) 968 } else if (!request->hr_host)
973 goto use_slashdir; 969 goto use_slashdir;
974 970
975 /* 971 /*
976 * ok, we have a virtual host, use scandir(3) to find a case 972 * ok, we have a virtual host, use scandir(3) to find a case
977 * insensitive match for the virtual host we are asked for. 973 * insensitive match for the virtual host we are asked for.
978 * note that if the virtual host is the same as the master, 974 * note that if the virtual host is the same as the master,
979 * we don't need to do anything special. 975 * we don't need to do anything special.
980 */ 976 */
981 len = strlen(request->hr_host); 977 len = strlen(request->hr_host);
982 debug((httpd, DEBUG_OBESE, 978 debug((httpd, DEBUG_OBESE,
983 "check_virtual: checking host `%s' under httpd->virtbase `%s' " 979 "check_virtual: checking host `%s' under httpd->virtbase `%s' "
984 "for file `%s'", 980 "for file `%s'",
985 request->hr_host, httpd->virtbase, request->hr_file)); 981 request->hr_host, httpd->virtbase, request->hr_file));
986 if (strncasecmp(httpd->virthostname, request->hr_host, len) != 0) { 982 if (strncasecmp(httpd->virthostname, request->hr_host, len) != 0) {
987 s = 0; 983 s = 0;
988 DIR *dirp; 984 DIR *dirp;
989 struct dirent *d; 985 struct dirent *d;
990 986
991 if ((dirp = opendir(httpd->virtbase)) != NULL) { 987 if ((dirp = opendir(httpd->virtbase)) != NULL) {
992 while ((d = readdir(dirp)) != NULL) { 988 while ((d = readdir(dirp)) != NULL) {
993 if (strcmp(d->d_name, ".") == 0 || 989 if (strcmp(d->d_name, ".") == 0 ||
994 strcmp(d->d_name, "..") == 0) { 990 strcmp(d->d_name, "..") == 0) {
995 continue; 991 continue;
996 } 992 }
997 debug((httpd, DEBUG_OBESE, "looking at dir``%s''", 993 debug((httpd, DEBUG_OBESE, "looking at dir``%s''",
998 d->d_name)); 994 d->d_name));
999 if (strncasecmp(d->d_name, request->hr_host, 995 if (strncasecmp(d->d_name, request->hr_host,
1000 len) == 0) { 996 len) == 0) {
1001 /* found it, punch it */ 997 /* found it, punch it */
1002 debug((httpd, DEBUG_OBESE, "found it punch it")); 998 debug((httpd, DEBUG_OBESE, "found it punch it"));
1003 httpd->virthostname = d->d_name; 999 httpd->virthostname = d->d_name;
1004 if (asprintf(&s, "%s/%s", httpd->virtbase, 1000 if (asprintf(&s, "%s/%s", httpd->virtbase,
1005 httpd->virthostname) < 0) 1001 httpd->virthostname) < 0)
1006 bozo_err(httpd, 1, "asprintf"); 1002 bozo_err(httpd, 1, "asprintf");
1007 break; 1003 break;
1008 } 1004 }
1009 } 1005 }
1010 closedir(dirp); 1006 closedir(dirp);
1011 } 1007 }
1012 else { 1008 else {
1013 debug((httpd, DEBUG_FAT, "opendir %s failed: %s", 1009 debug((httpd, DEBUG_FAT, "opendir %s failed: %s",
1014 httpd->virtbase, strerror(errno))); 1010 httpd->virtbase, strerror(errno)));
1015 } 1011 }
1016 if (s == 0) { 1012 if (s == 0) {
1017 if (httpd->unknown_slash) 1013 if (httpd->unknown_slash)
1018 goto use_slashdir; 1014 goto use_slashdir;
1019 return bozo_http_error(httpd, 404, request, 1015 return bozo_http_error(httpd, 404, request,
1020 "unknown URL"); 1016 "unknown URL");
1021 } 1017 }
1022 } else 1018 } else
1023use_slashdir: 1019use_slashdir:
1024 s = httpd->slashdir; 1020 s = httpd->slashdir;
1025 1021
1026 /* 1022 /*
1027 * ok, nailed the correct slashdir, chdir to it 1023 * ok, nailed the correct slashdir, chdir to it
1028 */ 1024 */
1029 if (chdir(s) < 0) 1025 if (chdir(s) < 0)
1030 return bozo_http_error(httpd, 404, request, 1026 return bozo_http_error(httpd, 404, request,
1031 "can't chdir to slashdir"); 1027 "can't chdir to slashdir");
1032 return 0; 1028 return 0;
1033} 1029}
1034 1030
1035/* 1031/*
1036 * checks to see if this request has a valid .bzredirect file. returns 1032 * checks to see if this request has a valid .bzredirect file. returns
1037 * 0 on failure and 1 on success. 1033 * 0 on failure and 1 on success.
1038 */ 1034 */
1039static void 1035static void
1040check_bzredirect(bozo_httpreq_t *request) 1036check_bzredirect(bozo_httpreq_t *request)
1041{ 1037{
1042 struct stat sb; 1038 struct stat sb;
1043 char dir[MAXPATHLEN], redir[MAXPATHLEN], redirpath[MAXPATHLEN + 1]; 1039 char dir[MAXPATHLEN], redir[MAXPATHLEN], redirpath[MAXPATHLEN + 1];
1044 char *basename, *finalredir; 1040 char *basename, *finalredir;
1045 int rv, absolute; 1041 int rv, absolute;
1046 1042
1047 /* 1043 /*
1048 * if this pathname is really a directory, but doesn't end in /, 1044 * if this pathname is really a directory, but doesn't end in /,
1049 * use it as the directory to look for the redir file. 1045 * use it as the directory to look for the redir file.
1050 */ 1046 */
1051 snprintf(dir, sizeof(dir), "%s", request->hr_file + 1); 1047 snprintf(dir, sizeof(dir), "%s", request->hr_file + 1);
1052 debug((request->hr_httpd, DEBUG_FAT, "check_bzredirect: dir %s", dir)); 1048 debug((request->hr_httpd, DEBUG_FAT, "check_bzredirect: dir %s", dir));
1053 basename = strrchr(dir, '/'); 1049 basename = strrchr(dir, '/');
1054 1050
1055 if ((!basename || basename[1] != '\0') && 1051 if ((!basename || basename[1] != '\0') &&
1056 lstat(dir, &sb) == 0 && S_ISDIR(sb.st_mode)) 1052 lstat(dir, &sb) == 0 && S_ISDIR(sb.st_mode))
1057 /* nothing */; 1053 /* nothing */;
1058 else if (basename == NULL) 1054 else if (basename == NULL)
1059 strcpy(dir, "."); 1055 strcpy(dir, ".");
1060 else { 1056 else {
1061 *basename++ = '\0'; 1057 *basename++ = '\0';
1062 bozo_check_special_files(request, basename); 1058 bozo_check_special_files(request, basename);
1063 } 1059 }
1064 1060
1065 snprintf(redir, sizeof(redir), "%s/%s", dir, REDIRECT_FILE); 1061 snprintf(redir, sizeof(redir), "%s/%s", dir, REDIRECT_FILE);
1066 if (lstat(redir, &sb) == 0) { 1062 if (lstat(redir, &sb) == 0) {
1067 if (!S_ISLNK(sb.st_mode)) 1063 if (!S_ISLNK(sb.st_mode))
1068 return; 1064 return;
1069 absolute = 0; 1065 absolute = 0;
1070 } else { 1066 } else {
1071 snprintf(redir, sizeof(redir), "%s/%s", dir, ABSREDIRECT_FILE); 1067 snprintf(redir, sizeof(redir), "%s/%s", dir, ABSREDIRECT_FILE);
1072 if (lstat(redir, &sb) < 0 || !S_ISLNK(sb.st_mode)) 1068 if (lstat(redir, &sb) < 0 || !S_ISLNK(sb.st_mode))
1073 return; 1069 return;
1074 absolute = 1; 1070 absolute = 1;
1075 } 1071 }
1076 debug((request->hr_httpd, DEBUG_FAT, 1072 debug((request->hr_httpd, DEBUG_FAT,
1077 "check_bzredirect: calling readlink")); 1073 "check_bzredirect: calling readlink"));
1078 rv = readlink(redir, redirpath, sizeof redirpath - 1); 1074 rv = readlink(redir, redirpath, sizeof redirpath - 1);
1079 if (rv == -1 || rv == 0) { 1075 if (rv == -1 || rv == 0) {
1080 debug((request->hr_httpd, DEBUG_FAT, "readlink failed")); 1076 debug((request->hr_httpd, DEBUG_FAT, "readlink failed"));
1081 return; 1077 return;
1082 } 1078 }
1083 redirpath[rv] = '\0'; 1079 redirpath[rv] = '\0';
1084 debug((request->hr_httpd, DEBUG_FAT, 1080 debug((request->hr_httpd, DEBUG_FAT,
1085 "readlink returned \"%s\"", redirpath)); 1081 "readlink returned \"%s\"", redirpath));
1086  1082
1087 /* now we have the link pointer, redirect to the real place */ 1083 /* now we have the link pointer, redirect to the real place */
1088 if (absolute) 1084 if (absolute)
1089 finalredir = redirpath; 1085 finalredir = redirpath;
1090 else 1086 else
1091 snprintf(finalredir = redir, sizeof(redir), "/%s/%s", dir, 1087 snprintf(finalredir = redir, sizeof(redir), "/%s/%s", dir,
1092 redirpath); 1088 redirpath);
1093 1089
1094 debug((request->hr_httpd, DEBUG_FAT, 1090 debug((request->hr_httpd, DEBUG_FAT,
1095 "check_bzredirect: new redir %s", finalredir)); 1091 "check_bzredirect: new redir %s", finalredir));
1096 handle_redirect(request, finalredir, absolute); 1092 handle_redirect(request, finalredir, absolute);
1097} 1093}
1098 1094
1099/* this fixes the %HH hack that RFC2396 requires. */ 1095/* this fixes the %HH hack that RFC2396 requires. */
1100static void 1096static void
1101fix_url_percent(bozo_httpreq_t *request) 1097fix_url_percent(bozo_httpreq_t *request)
1102{ 1098{
1103 bozohttpd_t *httpd = request->hr_httpd; 1099 bozohttpd_t *httpd = request->hr_httpd;
1104 char *s, *t, buf[3], *url; 1100 char *s, *t, buf[3], *url;
1105 char *end; /* if end is not-zero, we don't translate beyond that */ 1101 char *end; /* if end is not-zero, we don't translate beyond that */
1106 1102
1107 url = request->hr_file; 1103 url = request->hr_file;
1108 1104
1109 end = url + strlen(url); 1105 end = url + strlen(url);
1110 1106
1111 /* fast forward to the first % */ 1107 /* fast forward to the first % */
1112 if ((s = strchr(url, '%')) == NULL) 1108 if ((s = strchr(url, '%')) == NULL)
1113 return; 1109 return;
1114 1110
1115 t = s; 1111 t = s;
1116 do { 1112 do {
1117 if (end && s >= end) { 1113 if (end && s >= end) {
1118 debug((httpd, DEBUG_EXPLODING, 1114 debug((httpd, DEBUG_EXPLODING,
1119 "fu_%%: past end, filling out..")); 1115 "fu_%%: past end, filling out.."));
1120 while (*s) 1116 while (*s)
1121 *t++ = *s++; 1117 *t++ = *s++;
1122 break; 1118 break;
1123 } 1119 }
1124 debug((httpd, DEBUG_EXPLODING, 1120 debug((httpd, DEBUG_EXPLODING,
1125 "fu_%%: got s == %%, s[1]s[2] == %c%c", 1121 "fu_%%: got s == %%, s[1]s[2] == %c%c",
1126 s[1], s[2])); 1122 s[1], s[2]));
1127 if (s[1] == '\0' || s[2] == '\0') { 1123 if (s[1] == '\0' || s[2] == '\0') {
1128 (void)bozo_http_error(httpd, 400, request, 1124 (void)bozo_http_error(httpd, 400, request,
1129 "percent hack missing two chars afterwards"); 1125 "percent hack missing two chars afterwards");
1130 goto copy_rest; 1126 goto copy_rest;
1131 } 1127 }
1132 if (s[1] == '0' && s[2] == '0') { 1128 if (s[1] == '0' && s[2] == '0') {
1133 (void)bozo_http_error(httpd, 404, request, 1129 (void)bozo_http_error(httpd, 404, request,
1134 "percent hack was %00"); 1130 "percent hack was %00");
1135 goto copy_rest; 1131 goto copy_rest;
1136 } 1132 }
1137 if (s[1] == '2' && s[2] == 'f') { 1133 if (s[1] == '2' && s[2] == 'f') {
1138 (void)bozo_http_error(httpd, 404, request, 1134 (void)bozo_http_error(httpd, 404, request,
1139 "percent hack was %2f (/)"); 1135 "percent hack was %2f (/)");
1140 goto copy_rest; 1136 goto copy_rest;
1141 } 1137 }
1142  1138
1143 buf[0] = *++s; 1139 buf[0] = *++s;
1144 buf[1] = *++s; 1140 buf[1] = *++s;
1145 buf[2] = '\0'; 1141 buf[2] = '\0';
1146 s++; 1142 s++;
1147 *t = (char)strtol(buf, NULL, 16); 1143 *t = (char)strtol(buf, NULL, 16);
1148 debug((httpd, DEBUG_EXPLODING, 1144 debug((httpd, DEBUG_EXPLODING,
1149 "fu_%%: strtol put '%02x' into *t", *t)); 1145 "fu_%%: strtol put '%02x' into *t", *t));
1150 if (*t++ == '\0') { 1146 if (*t++ == '\0') {
1151 (void)bozo_http_error(httpd, 400, request, 1147 (void)bozo_http_error(httpd, 400, request,
1152 "percent hack got a 0 back"); 1148 "percent hack got a 0 back");
1153 goto copy_rest; 1149 goto copy_rest;
1154 } 1150 }
1155 1151
1156 while (*s && *s != '%') { 1152 while (*s && *s != '%') {
1157 if (end && s >= end) 1153 if (end && s >= end)
1158 break; 1154 break;
1159 *t++ = *s++; 1155 *t++ = *s++;
1160 } 1156 }
1161 } while (*s); 1157 } while (*s);
1162copy_rest: 1158copy_rest:
1163 while (*s) { 1159 while (*s) {
1164 if (s >= end) 1160 if (s >= end)
1165 break; 1161 break;
1166 *t++ = *s++; 1162 *t++ = *s++;
1167 } 1163 }
1168 *t = '\0'; 1164 *t = '\0';
1169 debug((httpd, DEBUG_FAT, "fix_url_percent returns %s in url", 1165 debug((httpd, DEBUG_FAT, "fix_url_percent returns %s in url",
1170 request->hr_file)); 1166 request->hr_file));
1171} 1167}
1172 1168
1173/* 1169/*
1174 * transform_request does this: 1170 * transform_request does this:
1175 * - ``expand'' %20 crapola 1171 * - ``expand'' %20 crapola
1176 * - punt if it doesn't start with / 1172 * - punt if it doesn't start with /
1177 * - check httpd->untrustedref / referrer 1173 * - check httpd->untrustedref / referrer
1178 * - look for "http://myname/" and deal with it. 1174 * - look for "http://myname/" and deal with it.
1179 * - maybe call bozo_process_cgi()  1175 * - maybe call bozo_process_cgi()
1180 * - check for ~user and call bozo_user_transform() if so 1176 * - check for ~user and call bozo_user_transform() if so
1181 * - if the length > 1, check for trailing slash. if so, 1177 * - if the length > 1, check for trailing slash. if so,
1182 * add the index.html file 1178 * add the index.html file
1183 * - if the length is 1, return the index.html file 1179 * - if the length is 1, return the index.html file
1184 * - disallow anything ending up with a file starting 1180 * - disallow anything ending up with a file starting
1185 * at "/" or having ".." in it. 1181 * at "/" or having ".." in it.
1186 * - anything else is a really weird internal error 1182 * - anything else is a really weird internal error
1187 * - returns malloced file to serve, if unhandled 1183 * - returns malloced file to serve, if unhandled
1188 */ 1184 */
1189static int 1185static int
1190transform_request(bozo_httpreq_t *request, int *isindex) 1186transform_request(bozo_httpreq_t *request, int *isindex)
1191{ 1187{
1192 bozohttpd_t *httpd = request->hr_httpd; 1188 bozohttpd_t *httpd = request->hr_httpd;
1193 char *file, *newfile = NULL; 1189 char *file, *newfile = NULL;
1194 size_t len; 1190 size_t len;
1195 1191
1196 file = NULL; 1192 file = NULL;
1197 *isindex = 0; 1193 *isindex = 0;
1198 debug((httpd, DEBUG_FAT, "tf_req: file %s", request->hr_file)); 1194 debug((httpd, DEBUG_FAT, "tf_req: file %s", request->hr_file));
1199 fix_url_percent(request); 1195 fix_url_percent(request);
1200 if (check_virtual(request)) { 1196 if (check_virtual(request)) {
1201 goto bad_done; 1197 goto bad_done;
1202 } 1198 }
1203 file = request->hr_file; 1199 file = request->hr_file;
1204 1200
1205 if (file[0] != '/') { 1201 if (file[0] != '/') {
1206 (void)bozo_http_error(httpd, 404, request, "unknown URL"); 1202 (void)bozo_http_error(httpd, 404, request, "unknown URL");
1207 goto bad_done; 1203 goto bad_done;
1208 } 1204 }
1209 1205
1210 check_bzredirect(request); 1206 check_bzredirect(request);
1211 1207
1212 if (httpd->untrustedref) { 1208 if (httpd->untrustedref) {
1213 int to_indexhtml = 0; 1209 int to_indexhtml = 0;
1214 1210
1215#define TOP_PAGE(x) (strcmp((x), "/") == 0 || \ 1211#define TOP_PAGE(x) (strcmp((x), "/") == 0 || \
1216 strcmp((x) + 1, httpd->index_html) == 0 || \ 1212 strcmp((x) + 1, httpd->index_html) == 0 || \
1217 strcmp((x) + 1, "favicon.ico") == 0)  1213 strcmp((x) + 1, "favicon.ico") == 0)
1218  1214
1219 debug((httpd, DEBUG_EXPLODING, "checking httpd->untrustedref")); 1215 debug((httpd, DEBUG_EXPLODING, "checking httpd->untrustedref"));
1220 /* 1216 /*
1221 * first check that this path isn't allowed via .bzdirect file, 1217 * first check that this path isn't allowed via .bzdirect file,
1222 * and then check referrer; make sure that people come via the 1218 * and then check referrer; make sure that people come via the
1223 * real name... otherwise if we aren't looking at / or 1219 * real name... otherwise if we aren't looking at / or
1224 * /index.html, redirect... we also special case favicon.ico. 1220 * /index.html, redirect... we also special case favicon.ico.
1225 */ 1221 */
1226 if (check_direct_access(request)) 1222 if (check_direct_access(request))
1227 /* nothing */; 1223 /* nothing */;
1228 else if (request->hr_referrer) { 1224 else if (request->hr_referrer) {
1229 const char *r = request->hr_referrer; 1225 const char *r = request->hr_referrer;
1230 1226
1231 debug((httpd, DEBUG_FAT, 1227 debug((httpd, DEBUG_FAT,
1232 "checking referrer \"%s\" vs virthostname %s", 1228 "checking referrer \"%s\" vs virthostname %s",
1233 r, httpd->virthostname)); 1229 r, httpd->virthostname));
1234 if (strncmp(r, "http://", 7) != 0 || 1230 if (strncmp(r, "http://", 7) != 0 ||
1235 (strncasecmp(r + 7, httpd->virthostname, 1231 (strncasecmp(r + 7, httpd->virthostname,
1236 strlen(httpd->virthostname)) != 0 && 1232 strlen(httpd->virthostname)) != 0 &&
1237 !TOP_PAGE(file))) 1233 !TOP_PAGE(file)))
1238 to_indexhtml = 1; 1234 to_indexhtml = 1;
1239 } else { 1235 } else {
1240 const char *h = request->hr_host; 1236 const char *h = request->hr_host;
1241 1237
1242 debug((httpd, DEBUG_FAT, "url has no referrer at all")); 1238 debug((httpd, DEBUG_FAT, "url has no referrer at all"));
1243 /* if there's no referrer, let / or /index.html past */ 1239 /* if there's no referrer, let / or /index.html past */
1244 if (!TOP_PAGE(file) || 1240 if (!TOP_PAGE(file) ||
1245 (h && strncasecmp(h, httpd->virthostname, 1241 (h && strncasecmp(h, httpd->virthostname,
1246 strlen(httpd->virthostname)) != 0)) 1242 strlen(httpd->virthostname)) != 0))
1247 to_indexhtml = 1; 1243 to_indexhtml = 1;
1248 } 1244 }
1249 1245
1250 if (to_indexhtml) { 1246 if (to_indexhtml) {
1251 char *slashindexhtml; 1247 char *slashindexhtml;
1252 1248
1253 if (asprintf(&slashindexhtml, "/%s", 1249 if (asprintf(&slashindexhtml, "/%s",
1254 httpd->index_html) < 0) 1250 httpd->index_html) < 0)
1255 bozo_err(httpd, 1, "asprintf"); 1251 bozo_err(httpd, 1, "asprintf");
1256 debug((httpd, DEBUG_FAT, 1252 debug((httpd, DEBUG_FAT,
1257 "httpd->untrustedref: redirecting %s to %s", 1253 "httpd->untrustedref: redirecting %s to %s",
1258 file, slashindexhtml)); 1254 file, slashindexhtml));
1259 handle_redirect(request, slashindexhtml, 0); 1255 handle_redirect(request, slashindexhtml, 0);
1260 free(slashindexhtml); 1256 free(slashindexhtml);
1261 return 0; 1257 return 0;
1262 } 1258 }
1263 } 1259 }
1264 1260
1265 len = strlen(file); 1261 len = strlen(file);
1266 if (/*CONSTCOND*/0) { 1262 if (/*CONSTCOND*/0) {
1267#ifndef NO_USER_SUPPORT 1263#ifndef NO_USER_SUPPORT
1268 } else if (len > 1 && httpd->enable_users && file[1] == '~') { 1264 } else if (len > 1 && httpd->enable_users && file[1] == '~') {
1269 if (file[2] == '\0') { 1265 if (file[2] == '\0') {
1270 (void)bozo_http_error(httpd, 404, request, 1266 (void)bozo_http_error(httpd, 404, request,
1271 "missing username"); 1267 "missing username");
1272 goto bad_done; 1268 goto bad_done;
1273 } 1269 }
1274 if (strchr(file + 2, '/') == NULL) { 1270 if (strchr(file + 2, '/') == NULL) {
1275 handle_redirect(request, NULL, 0); 1271 handle_redirect(request, NULL, 0);
1276 return 0; 1272 return 0;
1277 } 1273 }
1278 debug((httpd, DEBUG_FAT, "calling bozo_user_transform")); 1274 debug((httpd, DEBUG_FAT, "calling bozo_user_transform"));
1279 1275
1280 return bozo_user_transform(request, isindex); 1276 return bozo_user_transform(request, isindex);
1281#endif /* NO_USER_SUPPORT */ 1277#endif /* NO_USER_SUPPORT */
1282 } else if (len > 1) { 1278 } else if (len > 1) {
1283 debug((httpd, DEBUG_FAT, "file[len-1] == %c", file[len-1])); 1279 debug((httpd, DEBUG_FAT, "file[len-1] == %c", file[len-1]));
1284 if (file[len-1] == '/') { /* append index.html */ 1280 if (file[len-1] == '/') { /* append index.html */
1285 *isindex = 1; 1281 *isindex = 1;
1286 debug((httpd, DEBUG_FAT, "appending index.html")); 1282 debug((httpd, DEBUG_FAT, "appending index.html"));
1287 newfile = bozomalloc(httpd, 1283 newfile = bozomalloc(httpd,
1288 len + strlen(httpd->index_html) + 1); 1284 len + strlen(httpd->index_html) + 1);
1289 strcpy(newfile, file + 1); 1285 strcpy(newfile, file + 1);
1290 strcat(newfile, httpd->index_html); 1286 strcat(newfile, httpd->index_html);
1291 } else 1287 } else
1292 newfile = bozostrdup(request->hr_httpd, file + 1); 1288 newfile = bozostrdup(request->hr_httpd, file + 1);
1293 } else if (len == 1) { 1289 } else if (len == 1) {
1294 debug((httpd, DEBUG_EXPLODING, "tf_req: len == 1")); 1290 debug((httpd, DEBUG_EXPLODING, "tf_req: len == 1"));
1295 newfile = bozostrdup(request->hr_httpd, httpd->index_html); 1291 newfile = bozostrdup(request->hr_httpd, httpd->index_html);
1296 *isindex = 1; 1292 *isindex = 1;
1297 } else { /* len == 0 ? */ 1293 } else { /* len == 0 ? */
1298 (void)bozo_http_error(httpd, 500, request, 1294 (void)bozo_http_error(httpd, 500, request,
1299 "request->hr_file is nul?"); 1295 "request->hr_file is nul?");
1300 goto bad_done; 1296 goto bad_done;
1301 } 1297 }
1302 1298
1303 if (newfile == NULL) { 1299 if (newfile == NULL) {
1304 (void)bozo_http_error(httpd, 500, request, "internal failure"); 1300 (void)bozo_http_error(httpd, 500, request, "internal failure");
1305 goto bad_done; 1301 goto bad_done;
1306 } 1302 }
1307 1303
1308 /* 1304 /*
1309 * look for "http://myname/" and deal with it as necessary. 1305 * look for "http://myname/" and deal with it as necessary.
1310 */ 1306 */
1311 1307
1312 /* 1308 /*
1313 * stop traversing outside our domain  1309 * stop traversing outside our domain
1314 * 1310 *
1315 * XXX true security only comes from our parent using chroot(2) 1311 * XXX true security only comes from our parent using chroot(2)
1316 * before execve(2)'ing us. or our own built in chroot(2) support. 1312 * before execve(2)'ing us. or our own built in chroot(2) support.
1317 */ 1313 */
1318 if (*newfile == '/' || strcmp(newfile, "..") == 0 || 1314 if (*newfile == '/' || strcmp(newfile, "..") == 0 ||
1319 strstr(newfile, "/..") || strstr(newfile, "../")) { 1315 strstr(newfile, "/..") || strstr(newfile, "../")) {
1320 (void)bozo_http_error(httpd, 403, request, "illegal request"); 1316 (void)bozo_http_error(httpd, 403, request, "illegal request");
1321 goto bad_done; 1317 goto bad_done;
1322 } 1318 }
1323 1319
1324 if (bozo_auth_check(request, newfile)) 1320 if (bozo_auth_check(request, newfile))
1325 goto bad_done; 1321 goto bad_done;
1326 1322
1327 if (strlen(newfile)) { 1323 if (strlen(newfile)) {
1328 request->hr_oldfile = request->hr_file; 1324 request->hr_oldfile = request->hr_file;
1329 request->hr_file = newfile; 1325 request->hr_file = newfile;
1330 } 1326 }
1331 1327
1332 if (bozo_process_cgi(request)) 1328 if (bozo_process_cgi(request))
1333 return 0; 1329 return 0;
1334 1330
1335 debug((httpd, DEBUG_FAT, "transform_request set: %s", newfile)); 1331 debug((httpd, DEBUG_FAT, "transform_request set: %s", newfile));
1336 return 1; 1332 return 1;
1337bad_done: 1333bad_done:
1338 debug((httpd, DEBUG_FAT, "transform_request returning: 0")); 1334 debug((httpd, DEBUG_FAT, "transform_request returning: 0"));
1339 if (newfile) 1335 if (newfile)
1340 free(newfile); 1336 free(newfile);
1341 return 0; 1337 return 0;
1342} 1338}
1343 1339
1344/* 1340/*
1345 * bozo_process_request does the following: 1341 * bozo_process_request does the following:
1346 * - check the request is valid 1342 * - check the request is valid
1347 * - process cgi-bin if necessary 1343 * - process cgi-bin if necessary
1348 * - transform a filename if necesarry 1344 * - transform a filename if necesarry
1349 * - return the HTTP request 1345 * - return the HTTP request
1350 */ 1346 */
1351void 1347void
1352bozo_process_request(bozo_httpreq_t *request) 1348bozo_process_request(bozo_httpreq_t *request)
1353{ 1349{
1354 bozohttpd_t *httpd = request->hr_httpd; 1350 bozohttpd_t *httpd = request->hr_httpd;
1355 struct stat sb; 1351 struct stat sb;
1356 time_t timestamp; 1352 time_t timestamp;
1357 char *file; 1353 char *file;
1358 const char *type, *encoding; 1354 const char *type, *encoding;
1359 int fd, isindex; 1355 int fd, isindex;
1360 1356
1361 /* 1357 /*
1362 * note that transform_request chdir()'s if required. also note 1358 * note that transform_request chdir()'s if required. also note
1363 * that cgi is handed here. if transform_request() returns 0 1359 * that cgi is handed here. if transform_request() returns 0
1364 * then the request has been handled already. 1360 * then the request has been handled already.
1365 */ 1361 */
1366 if (transform_request(request, &isindex) == 0) 1362 if (transform_request(request, &isindex) == 0)
1367 return; 1363 return;
1368 1364
1369 file = request->hr_file; 1365 file = request->hr_file;
1370 1366
1371 fd = open(file, O_RDONLY); 1367 fd = open(file, O_RDONLY);
1372 if (fd < 0) { 1368 if (fd < 0) {
1373 debug((httpd, DEBUG_FAT, "open failed: %s", strerror(errno))); 1369 debug((httpd, DEBUG_FAT, "open failed: %s", strerror(errno)));
1374 if (errno == EPERM) 1370 if (errno == EPERM)
1375 (void)bozo_http_error(httpd, 403, request, 1371 (void)bozo_http_error(httpd, 403, request,
1376 "no permission to open file"); 1372 "no permission to open file");
1377 else if (errno == ENOENT) { 1373 else if (errno == ENOENT) {
1378 if (!bozo_dir_index(request, file, isindex))  1374 if (!bozo_dir_index(request, file, isindex))
1379 (void)bozo_http_error(httpd, 404, request, 1375 (void)bozo_http_error(httpd, 404, request,
1380 "no file"); 1376 "no file");
1381 } else 1377 } else
1382 (void)bozo_http_error(httpd, 500, request, "open file"); 1378 (void)bozo_http_error(httpd, 500, request, "open file");
1383 goto cleanup_nofd; 1379 goto cleanup_nofd;
1384 } 1380 }
1385 if (fstat(fd, &sb) < 0) { 1381 if (fstat(fd, &sb) < 0) {
1386 (void)bozo_http_error(httpd, 500, request, "can't fstat"); 1382 (void)bozo_http_error(httpd, 500, request, "can't fstat");
1387 goto cleanup; 1383 goto cleanup;
1388 } 1384 }
1389 if (S_ISDIR(sb.st_mode)) { 1385 if (S_ISDIR(sb.st_mode)) {
1390 handle_redirect(request, NULL, 0); 1386 handle_redirect(request, NULL, 0);
1391 goto cleanup; 1387 goto cleanup;
1392 } 1388 }
1393 1389
1394 if (request->hr_if_modified_since && 1390 if (request->hr_if_modified_since &&
1395 parse_http_date(request->hr_if_modified_since, &timestamp) && 1391 parse_http_date(request->hr_if_modified_since, &timestamp) &&
1396 timestamp >= sb.st_mtime) { 1392 timestamp >= sb.st_mtime) {
1397 /* XXX ignore subsecond of timestamp */ 1393 /* XXX ignore subsecond of timestamp */
1398 bozo_printf(httpd, "%s 304 Not Modified\r\n", 1394 bozo_printf(httpd, "%s 304 Not Modified\r\n",
1399 request->hr_proto); 1395 request->hr_proto);
1400 bozo_printf(httpd, "\r\n"); 1396 bozo_printf(httpd, "\r\n");
1401 bozo_flush(httpd, stdout); 1397 bozo_flush(httpd, stdout);
1402 goto cleanup; 1398 goto cleanup;
1403 } 1399 }
1404 1400
1405 /* validate requested range */ 1401 /* validate requested range */
1406 if (request->hr_last_byte_pos == -1 || 1402 if (request->hr_last_byte_pos == -1 ||
1407 request->hr_last_byte_pos >= sb.st_size) 1403 request->hr_last_byte_pos >= sb.st_size)
1408 request->hr_last_byte_pos = sb.st_size - 1; 1404 request->hr_last_byte_pos = sb.st_size - 1;
1409 if (request->hr_have_range && 1405 if (request->hr_have_range &&
1410 request->hr_first_byte_pos > request->hr_last_byte_pos) { 1406 request->hr_first_byte_pos > request->hr_last_byte_pos) {
1411 request->hr_have_range = 0; /* punt */ 1407 request->hr_have_range = 0; /* punt */
1412 request->hr_first_byte_pos = 0; 1408 request->hr_first_byte_pos = 0;
1413 request->hr_last_byte_pos = sb.st_size - 1; 1409 request->hr_last_byte_pos = sb.st_size - 1;
1414 } 1410 }
1415 debug((httpd, DEBUG_FAT, "have_range %d first_pos %qd last_pos %qd", 1411 debug((httpd, DEBUG_FAT, "have_range %d first_pos %lld last_pos %lld",
1416 request->hr_have_range, 1412 request->hr_have_range,
1417 request->hr_first_byte_pos, request->hr_last_byte_pos)); 1413 (long long)request->hr_first_byte_pos,
 1414 (long long)request->hr_last_byte_pos));
1418 if (request->hr_have_range) 1415 if (request->hr_have_range)
1419 bozo_printf(httpd, "%s 206 Partial Content\r\n", 1416 bozo_printf(httpd, "%s 206 Partial Content\r\n",
1420 request->hr_proto); 1417 request->hr_proto);
1421 else 1418 else
1422 bozo_printf(httpd, "%s 200 OK\r\n", request->hr_proto); 1419 bozo_printf(httpd, "%s 200 OK\r\n", request->hr_proto);
1423 1420
1424 if (request->hr_proto != httpd->consts.http_09) { 1421 if (request->hr_proto != httpd->consts.http_09) {
1425 type = bozo_content_type(request, file); 1422 type = bozo_content_type(request, file);
1426 encoding = bozo_content_encoding(request, file); 1423 encoding = bozo_content_encoding(request, file);
1427 1424
1428 bozo_print_header(request, &sb, type, encoding); 1425 bozo_print_header(request, &sb, type, encoding);
1429 bozo_printf(httpd, "\r\n"); 1426 bozo_printf(httpd, "\r\n");
1430 } 1427 }
1431 bozo_flush(httpd, stdout); 1428 bozo_flush(httpd, stdout);
1432 1429
1433 if (request->hr_method != HTTP_HEAD) { 1430 if (request->hr_method != HTTP_HEAD) {
1434 off_t szleft, cur_byte_pos; 1431 off_t szleft, cur_byte_pos;
1435 1432
1436 szleft = 1433 szleft =
1437 request->hr_last_byte_pos - request->hr_first_byte_pos + 1; 1434 request->hr_last_byte_pos - request->hr_first_byte_pos + 1;
1438 cur_byte_pos = request->hr_first_byte_pos; 1435 cur_byte_pos = request->hr_first_byte_pos;
1439 1436
1440 retry: 1437 retry:
1441 while (szleft) { 1438 while (szleft) {
1442 size_t sz; 1439 size_t sz;
1443 1440
1444 /* This should take care of the first unaligned chunk */ 1441 /* This should take care of the first unaligned chunk */
1445 if ((cur_byte_pos & (httpd->page_size - 1)) != 0) 1442 if ((cur_byte_pos & (httpd->page_size - 1)) != 0)
1446 sz = (size_t)(cur_byte_pos & ~httpd->page_size); 1443 sz = (size_t)(cur_byte_pos & ~httpd->page_size);
1447 if ((off_t)httpd->mmapsz < szleft) 1444 if ((off_t)httpd->mmapsz < szleft)
1448 sz = httpd->mmapsz; 1445 sz = httpd->mmapsz;
1449 else 1446 else
1450 sz = (size_t)szleft; 1447 sz = (size_t)szleft;
1451 if (mmap_and_write_part(httpd, fd, cur_byte_pos, sz)) { 1448 if (mmap_and_write_part(httpd, fd, cur_byte_pos, sz)) {
1452 if (errno == ENOMEM) { 1449 if (errno == ENOMEM) {
1453 httpd->mmapsz /= 2; 1450 httpd->mmapsz /= 2;
1454 if (httpd->mmapsz >= httpd->page_size) 1451 if (httpd->mmapsz >= httpd->page_size)
1455 goto retry; 1452 goto retry;
1456 } 1453 }
1457 goto cleanup; 1454 goto cleanup;
1458 } 1455 }
1459 cur_byte_pos += sz; 1456 cur_byte_pos += sz;
1460 szleft -= sz; 1457 szleft -= sz;
1461 } 1458 }
1462 } 1459 }
1463 cleanup: 1460 cleanup:
1464 close(fd); 1461 close(fd);
1465 cleanup_nofd: 1462 cleanup_nofd:
1466 close(STDIN_FILENO); 1463 close(STDIN_FILENO);
1467 close(STDOUT_FILENO); 1464 close(STDOUT_FILENO);
1468 /*close(STDERR_FILENO);*/ 1465 /*close(STDERR_FILENO);*/
1469} 1466}
1470 1467
1471/* make sure we're not trying to access special files */ 1468/* make sure we're not trying to access special files */
1472int 1469int
1473bozo_check_special_files(bozo_httpreq_t *request, const char *name) 1470bozo_check_special_files(bozo_httpreq_t *request, const char *name)
1474{ 1471{
1475 bozohttpd_t *httpd = request->hr_httpd; 1472 bozohttpd_t *httpd = request->hr_httpd;
1476 1473
1477 /* ensure basename(name) != special files */ 1474 /* ensure basename(name) != special files */
1478 if (strcmp(name, DIRECT_ACCESS_FILE) == 0) 1475 if (strcmp(name, DIRECT_ACCESS_FILE) == 0)
1479 return bozo_http_error(httpd, 403, request, 1476 return bozo_http_error(httpd, 403, request,
1480 "no permission to open direct access file"); 1477 "no permission to open direct access file");
1481 if (strcmp(name, REDIRECT_FILE) == 0) 1478 if (strcmp(name, REDIRECT_FILE) == 0)
1482 return bozo_http_error(httpd, 403, request, 1479 return bozo_http_error(httpd, 403, request,
1483 "no permission to open redirect file"); 1480 "no permission to open redirect file");
1484 if (strcmp(name, ABSREDIRECT_FILE) == 0) 1481 if (strcmp(name, ABSREDIRECT_FILE) == 0)
1485 return bozo_http_error(httpd, 403, request, 1482 return bozo_http_error(httpd, 403, request,
1486 "no permission to open redirect file"); 1483 "no permission to open redirect file");
1487 return bozo_auth_check_special_files(request, name); 1484 return bozo_auth_check_special_files(request, name);
1488} 1485}
1489 1486
1490/* generic header printing routine */ 1487/* generic header printing routine */
1491void 1488void
1492bozo_print_header(bozo_httpreq_t *request, 1489bozo_print_header(bozo_httpreq_t *request,
1493 struct stat *sbp, const char *type, const char *encoding) 1490 struct stat *sbp, const char *type, const char *encoding)
1494{ 1491{
1495 bozohttpd_t *httpd = request->hr_httpd; 1492 bozohttpd_t *httpd = request->hr_httpd;
1496 off_t len; 1493 off_t len;
1497 char date[40]; 1494 char date[40];
1498 1495
1499 bozo_printf(httpd, "Date: %s\r\n", bozo_http_date(date, sizeof(date))); 1496 bozo_printf(httpd, "Date: %s\r\n", bozo_http_date(date, sizeof(date)));
1500 bozo_printf(httpd, "Server: %s\r\n", httpd->server_software); 1497 bozo_printf(httpd, "Server: %s\r\n", httpd->server_software);
1501 bozo_printf(httpd, "Accept-Ranges: bytes\r\n"); 1498 bozo_printf(httpd, "Accept-Ranges: bytes\r\n");
1502 if (sbp) { 1499 if (sbp) {
1503 char filedate[40]; 1500 char filedate[40];
1504 struct tm *tm; 1501 struct tm *tm;
1505 1502
1506 tm = gmtime(&sbp->st_mtime); 1503 tm = gmtime(&sbp->st_mtime);
1507 strftime(filedate, sizeof filedate, 1504 strftime(filedate, sizeof filedate,
1508 "%a, %d %b %Y %H:%M:%S GMT", tm); 1505 "%a, %d %b %Y %H:%M:%S GMT", tm);
1509 bozo_printf(httpd, "Last-Modified: %s\r\n", filedate); 1506 bozo_printf(httpd, "Last-Modified: %s\r\n", filedate);
1510 } 1507 }
1511 if (type && *type) 1508 if (type && *type)
1512 bozo_printf(httpd, "Content-Type: %s\r\n", type); 1509 bozo_printf(httpd, "Content-Type: %s\r\n", type);
1513 if (encoding && *encoding) 1510 if (encoding && *encoding)
1514 bozo_printf(httpd, "Content-Encoding: %s\r\n", encoding); 1511 bozo_printf(httpd, "Content-Encoding: %s\r\n", encoding);
1515 if (sbp) { 1512 if (sbp) {
1516 if (request->hr_have_range) { 1513 if (request->hr_have_range) {
1517 len = request->hr_last_byte_pos - 1514 len = request->hr_last_byte_pos -
1518 request->hr_first_byte_pos +1; 1515 request->hr_first_byte_pos +1;
1519 bozo_printf(httpd, 1516 bozo_printf(httpd,
1520 "Content-Range: bytes %qd-%qd/%qd\r\n", 1517 "Content-Range: bytes %qd-%qd/%qd\r\n",
1521 (long long) request->hr_first_byte_pos, 1518 (long long) request->hr_first_byte_pos,
1522 (long long) request->hr_last_byte_pos, 1519 (long long) request->hr_last_byte_pos,
1523 (long long) sbp->st_size); 1520 (long long) sbp->st_size);
1524 } else 1521 } else
1525 len = sbp->st_size; 1522 len = sbp->st_size;
1526 bozo_printf(httpd, "Content-Length: %qd\r\n", (long long)len); 1523 bozo_printf(httpd, "Content-Length: %qd\r\n", (long long)len);
1527 } 1524 }
1528 if (request && request->hr_proto == httpd->consts.http_11) 1525 if (request && request->hr_proto == httpd->consts.http_11)
1529 bozo_printf(httpd, "Connection: close\r\n"); 1526 bozo_printf(httpd, "Connection: close\r\n");
1530 bozo_flush(httpd, stdout); 1527 bozo_flush(httpd, stdout);
1531} 1528}
1532 1529
1533#ifndef NO_DEBUG 1530#ifndef NO_DEBUG
1534void 1531void
1535debug__(bozohttpd_t *httpd, int level, const char *fmt, ...) 1532debug__(bozohttpd_t *httpd, int level, const char *fmt, ...)
1536{ 1533{
1537 va_list ap; 1534 va_list ap;
1538 int savederrno; 1535 int savederrno;
1539  1536
1540 /* only log if the level is low enough */ 1537 /* only log if the level is low enough */
1541 if (httpd->debug < level) 1538 if (httpd->debug < level)
1542 return; 1539 return;
1543 1540
1544 savederrno = errno; 1541 savederrno = errno;
1545 va_start(ap, fmt); 1542 va_start(ap, fmt);
1546 if (httpd->logstderr) { 1543 if (httpd->logstderr) {
1547 vfprintf(stderr, fmt, ap); 1544 vfprintf(stderr, fmt, ap);
1548 fputs("\n", stderr); 1545 fputs("\n", stderr);
1549 } else 1546 } else
1550 vsyslog(LOG_DEBUG, fmt, ap); 1547 vsyslog(LOG_DEBUG, fmt, ap);
1551 va_end(ap); 1548 va_end(ap);
1552 errno = savederrno; 1549 errno = savederrno;
1553} 1550}
1554#endif /* NO_DEBUG */ 1551#endif /* NO_DEBUG */
1555 1552
1556/* these are like warn() and err(), except for syslog not stderr */ 1553/* these are like warn() and err(), except for syslog not stderr */
1557void 1554void
1558bozo_warn(bozohttpd_t *httpd, const char *fmt, ...) 1555bozo_warn(bozohttpd_t *httpd, const char *fmt, ...)
1559{ 1556{
1560 va_list ap; 1557 va_list ap;
1561 1558
1562 va_start(ap, fmt); 1559 va_start(ap, fmt);
1563 if (httpd->logstderr || isatty(STDERR_FILENO)) { 1560 if (httpd->logstderr || isatty(STDERR_FILENO)) {
1564 //fputs("warning: ", stderr); 1561 //fputs("warning: ", stderr);
1565 vfprintf(stderr, fmt, ap); 1562 vfprintf(stderr, fmt, ap);
1566 fputs("\n", stderr); 1563 fputs("\n", stderr);
1567 } else 1564 } else
1568 vsyslog(LOG_INFO, fmt, ap); 1565 vsyslog(LOG_INFO, fmt, ap);
1569 va_end(ap); 1566 va_end(ap);
1570} 1567}
1571 1568
1572void 1569void
1573bozo_err(bozohttpd_t *httpd, int code, const char *fmt, ...) 1570bozo_err(bozohttpd_t *httpd, int code, const char *fmt, ...)
1574{ 1571{
1575 va_list ap; 1572 va_list ap;
1576 1573
1577 va_start(ap, fmt); 1574 va_start(ap, fmt);
1578 if (httpd->logstderr || isatty(STDERR_FILENO)) { 1575 if (httpd->logstderr || isatty(STDERR_FILENO)) {
1579 //fputs("error: ", stderr); 1576 //fputs("error: ", stderr);
1580 vfprintf(stderr, fmt, ap); 1577 vfprintf(stderr, fmt, ap);
1581 fputs("\n", stderr); 1578 fputs("\n", stderr);
1582 } else 1579 } else
1583 vsyslog(LOG_ERR, fmt, ap); 1580 vsyslog(LOG_ERR, fmt, ap);
1584 va_end(ap); 1581 va_end(ap);
1585 exit(code); 1582 exit(code);
1586} 1583}
1587 1584
1588/* this escape HTML tags */ 1585/* this escape HTML tags */
1589static void 1586static void
1590escape_html(bozo_httpreq_t *request) 1587escape_html(bozo_httpreq_t *request)
1591{ 1588{
1592 int i, j; 1589 int i, j;
1593 char *url = request->hr_file, *tmp; 1590 char *url = request->hr_file, *tmp;
1594 1591
1595 for (i = 0, j = 0; url[i]; i++) { 1592 for (i = 0, j = 0; url[i]; i++) {
1596 switch (url[i]) { 1593 switch (url[i]) {
1597 case '<': 1594 case '<':
1598 case '>': 1595 case '>':
1599 j += 4; 1596 j += 4;
1600 break; 1597 break;
1601 case '&': 1598 case '&':
1602 j += 5; 1599 j += 5;
1603 break; 1600 break;
1604 } 1601 }
1605 } 1602 }
1606 1603
1607 if (j == 0) 1604 if (j == 0)
1608 return; 1605 return;
1609 1606
1610 if ((tmp = (char *) malloc(strlen(url) + j)) == 0) 1607 if ((tmp = (char *) malloc(strlen(url) + j)) == 0)
1611 /* 1608 /*
1612 * ouch, but we are only called from an error context, and 1609 * ouch, but we are only called from an error context, and
1613 * most paths here come from malloc(3) failures anyway... 1610 * most paths here come from malloc(3) failures anyway...
1614 * we could completely punt and just exit, but isn't returning 1611 * we could completely punt and just exit, but isn't returning
1615 * an not-quite-correct error better than nothing at all? 1612 * an not-quite-correct error better than nothing at all?
1616 */ 1613 */
1617 return; 1614 return;
1618 1615
1619 for (i = 0, j = 0; url[i]; i++) { 1616 for (i = 0, j = 0; url[i]; i++) {
1620 switch (url[i]) { 1617 switch (url[i]) {
1621 case '<': 1618 case '<':
1622 memcpy(tmp + j, "&lt;", 4); 1619 memcpy(tmp + j, "&lt;", 4);
1623 j += 4; 1620 j += 4;
1624 break; 1621 break;
1625 case '>': 1622 case '>':
1626 memcpy(tmp + j, "&gt;", 4); 1623 memcpy(tmp + j, "&gt;", 4);
1627 j += 4; 1624 j += 4;
1628 break; 1625 break;
1629 case '&': 1626 case '&':
1630 memcpy(tmp + j, "&amp;", 5); 1627 memcpy(tmp + j, "&amp;", 5);
1631 j += 5; 1628 j += 5;
1632 break; 1629 break;
1633 default: 1630 default:
1634 tmp[j++] = url[i]; 1631 tmp[j++] = url[i];
1635 } 1632 }
1636 } 1633 }
1637 tmp[j] = 0; 1634 tmp[j] = 0;
1638 1635
1639 free(request->hr_file); 1636 free(request->hr_file);
1640 request->hr_file = tmp; 1637 request->hr_file = tmp;
1641} 1638}
1642 1639
1643/* short map between error code, and short/long messages */ 1640/* short map between error code, and short/long messages */
1644static struct errors_map { 1641static struct errors_map {
1645 int code; /* HTTP return code */ 1642 int code; /* HTTP return code */
1646 const char *shortmsg; /* short version of message */ 1643 const char *shortmsg; /* short version of message */
1647 const char *longmsg; /* long version of message */ 1644 const char *longmsg; /* long version of message */
1648} errors_map[] = { 1645} errors_map[] = {
1649 { 400, "400 Bad Request", "The request was not valid", }, 1646 { 400, "400 Bad Request", "The request was not valid", },
1650 { 401, "401 Unauthorized", "No authorization", }, 1647 { 401, "401 Unauthorized", "No authorization", },
1651 { 403, "403 Forbidden", "Access to this item has been denied",}, 1648 { 403, "403 Forbidden", "Access to this item has been denied",},
1652 { 404, "404 Not Found", "This item has not been found", }, 1649 { 404, "404 Not Found", "This item has not been found", },
1653 { 408, "408 Request Timeout", "This request took too long", }, 1650 { 408, "408 Request Timeout", "This request took too long", },
1654 { 417, "417 Expectation Failed","Expectations not available", }, 1651 { 417, "417 Expectation Failed","Expectations not available", },
1655 { 500, "500 Internal Error", "An error occured on the server", }, 1652 { 500, "500 Internal Error", "An error occured on the server", },
1656 { 501, "501 Not Implemented", "This request is not available", }, 1653 { 501, "501 Not Implemented", "This request is not available", },
1657 { 0, NULL, NULL, }, 1654 { 0, NULL, NULL, },
1658}; 1655};
1659 1656
1660static const char *help = "DANGER! WILL ROBINSON! DANGER!"; 1657static const char *help = "DANGER! WILL ROBINSON! DANGER!";
1661 1658
1662static const char * 1659static const char *
1663http_errors_short(int code) 1660http_errors_short(int code)
1664{ 1661{
1665 struct errors_map *ep; 1662 struct errors_map *ep;
1666 1663
1667 for (ep = errors_map; ep->code; ep++) 1664 for (ep = errors_map; ep->code; ep++)
1668 if (ep->code == code) 1665 if (ep->code == code)
1669 return (ep->shortmsg); 1666 return (ep->shortmsg);
1670 return (help); 1667 return (help);
1671} 1668}
1672 1669
1673static const char * 1670static const char *
1674http_errors_long(int code) 1671http_errors_long(int code)
1675{ 1672{
1676 struct errors_map *ep; 1673 struct errors_map *ep;
1677 1674
1678 for (ep = errors_map; ep->code; ep++) 1675 for (ep = errors_map; ep->code; ep++)
1679 if (ep->code == code) 1676 if (ep->code == code)
1680 return (ep->longmsg); 1677 return (ep->longmsg);
1681 return (help); 1678 return (help);
1682} 1679}
1683 1680
1684/* the follow functions and variables are used in handling HTTP errors */ 1681/* the follow functions and variables are used in handling HTTP errors */
1685/* ARGSUSED */ 1682/* ARGSUSED */
1686int 1683int
1687bozo_http_error(bozohttpd_t *httpd, int code, bozo_httpreq_t *request, 1684bozo_http_error(bozohttpd_t *httpd, int code, bozo_httpreq_t *request,
1688 const char *msg) 1685 const char *msg)
1689{ 1686{
1690 char portbuf[20]; 1687 char portbuf[20];
1691 const char *header = http_errors_short(code); 1688 const char *header = http_errors_short(code);
1692 const char *reason = http_errors_long(code); 1689 const char *reason = http_errors_long(code);
1693 const char *proto = (request && request->hr_proto) ? 1690 const char *proto = (request && request->hr_proto) ?
1694 request->hr_proto : httpd->consts.http_11; 1691 request->hr_proto : httpd->consts.http_11;
1695 int size; 1692 int size;
1696 1693
1697 debug((httpd, DEBUG_FAT, "bozo_http_error %d: %s", code, msg)); 1694 debug((httpd, DEBUG_FAT, "bozo_http_error %d: %s", code, msg));
1698 if (header == NULL || reason == NULL) { 1695 if (header == NULL || reason == NULL) {
1699 bozo_err(httpd, 1, 1696 bozo_err(httpd, 1,
1700 "bozo_http_error() failed (short = %p, long = %p)", 1697 "bozo_http_error() failed (short = %p, long = %p)",
1701 header, reason); 1698 header, reason);
1702 return code; 1699 return code;
1703 } 1700 }
1704 1701
1705 if (request && request->hr_serverport && 1702 if (request && request->hr_serverport &&
1706 strcmp(request->hr_serverport, "80") != 0) 1703 strcmp(request->hr_serverport, "80") != 0)
1707 snprintf(portbuf, sizeof(portbuf), ":%s", 1704 snprintf(portbuf, sizeof(portbuf), ":%s",
1708 request->hr_serverport); 1705 request->hr_serverport);
1709 else 1706 else
1710 portbuf[0] = '\0'; 1707 portbuf[0] = '\0';
1711 1708
1712 if (request && request->hr_file) { 1709 if (request && request->hr_file) {
1713 escape_html(request); 1710 escape_html(request);
1714 size = snprintf(httpd->errorbuf, BUFSIZ, 1711 size = snprintf(httpd->errorbuf, BUFSIZ,
1715 "<html><head><title>%s</title></head>\n" 1712 "<html><head><title>%s</title></head>\n"
1716 "<body><h1>%s</h1>\n" 1713 "<body><h1>%s</h1>\n"
1717 "%s: <pre>%s</pre>\n" 1714 "%s: <pre>%s</pre>\n"
1718 "<hr><address><a href=\"http://%s%s/\">%s%s</a></address>\n" 1715 "<hr><address><a href=\"http://%s%s/\">%s%s</a></address>\n"
1719 "</body></html>\n", 1716 "</body></html>\n",
1720 header, header, request->hr_file, reason, 1717 header, header, request->hr_file, reason,
1721 httpd->virthostname, portbuf, httpd->virthostname, portbuf); 1718 httpd->virthostname, portbuf, httpd->virthostname, portbuf);
1722 if (size >= (int)BUFSIZ) { 1719 if (size >= (int)BUFSIZ) {
1723 bozo_warn(httpd, 1720 bozo_warn(httpd,
1724 "bozo_http_error buffer too small, truncated"); 1721 "bozo_http_error buffer too small, truncated");
1725 size = (int)BUFSIZ; 1722 size = (int)BUFSIZ;
1726 } 1723 }
1727 } else 1724 } else
1728 size = 0; 1725 size = 0;
1729 1726
1730 bozo_printf(httpd, "%s %s\r\n", proto, header); 1727 bozo_printf(httpd, "%s %s\r\n", proto, header);
1731 if (request) 1728 if (request)
1732 bozo_auth_check_401(request, code); 1729 bozo_auth_check_401(request, code);
1733 1730
1734 bozo_printf(httpd, "Content-Type: text/html\r\n"); 1731 bozo_printf(httpd, "Content-Type: text/html\r\n");
1735 bozo_printf(httpd, "Content-Length: %d\r\n", size); 1732 bozo_printf(httpd, "Content-Length: %d\r\n", size);
1736 bozo_printf(httpd, "Server: %s\r\n", httpd->server_software); 1733 bozo_printf(httpd, "Server: %s\r\n", httpd->server_software);
1737 if (request && request->hr_allow) 1734 if (request && request->hr_allow)
1738 bozo_printf(httpd, "Allow: %s\r\n", request->hr_allow); 1735 bozo_printf(httpd, "Allow: %s\r\n", request->hr_allow);
1739 bozo_printf(httpd, "\r\n"); 1736 bozo_printf(httpd, "\r\n");
1740 if (size) 1737 if (size)
1741 bozo_printf(httpd, "%s", httpd->errorbuf); 1738 bozo_printf(httpd, "%s", httpd->errorbuf);
1742 bozo_flush(httpd, stdout); 1739 bozo_flush(httpd, stdout);
1743 1740
1744 return code; 1741 return code;
1745} 1742}
1746 1743
1747/* Below are various modified libc functions */ 1744/* Below are various modified libc functions */
1748 1745
1749/* 1746/*
1750 * returns -1 in lenp if the string ran out before finding a delimiter, 1747 * returns -1 in lenp if the string ran out before finding a delimiter,
1751 * but is otherwise the same as strsep. Note that the length must be 1748 * but is otherwise the same as strsep. Note that the length must be
1752 * correctly passed in. 1749 * correctly passed in.
1753 */ 1750 */
1754char * 1751char *
1755bozostrnsep(char **strp, const char *delim, ssize_t *lenp) 1752bozostrnsep(char **strp, const char *delim, ssize_t *lenp)
1756{ 1753{
1757 char *s; 1754 char *s;
1758 const char *spanp; 1755 const char *spanp;
1759 int c, sc; 1756 int c, sc;
1760 char *tok; 1757 char *tok;
1761 1758
1762 if ((s = *strp) == NULL) 1759 if ((s = *strp) == NULL)
1763 return (NULL); 1760 return (NULL);
1764 for (tok = s;;) { 1761 for (tok = s;;) {
1765 if (lenp && --(*lenp) == -1) 1762 if (lenp && --(*lenp) == -1)
1766 return (NULL); 1763 return (NULL);
1767 c = *s++; 1764 c = *s++;
1768 spanp = delim; 1765 spanp = delim;
1769 do { 1766 do {
1770 if ((sc = *spanp++) == c) { 1767 if ((sc = *spanp++) == c) {
1771 if (c == 0) 1768 if (c == 0)
1772 s = NULL; 1769 s = NULL;
1773 else 1770 else
1774 s[-1] = '\0'; 1771 s[-1] = '\0';
1775 *strp = s; 1772 *strp = s;
1776 return (tok); 1773 return (tok);
1777 } 1774 }
1778 } while (sc != 0); 1775 } while (sc != 0);
1779 } 1776 }
1780 /* NOTREACHED */ 1777 /* NOTREACHED */
1781} 1778}
1782 1779
1783/* 1780/*
1784 * inspired by fgetln(3), but works for fd's. should work identically 1781 * inspired by fgetln(3), but works for fd's. should work identically
1785 * except it, however, does *not* return the newline, and it does nul 1782 * except it, however, does *not* return the newline, and it does nul
1786 * terminate the string. 1783 * terminate the string.
1787 */ 1784 */
1788char * 1785char *
1789bozodgetln(bozohttpd_t *httpd, int fd, ssize_t *lenp, 1786bozodgetln(bozohttpd_t *httpd, int fd, ssize_t *lenp,
1790 ssize_t (*readfn)(bozohttpd_t *, int, void *, size_t)) 1787 ssize_t (*readfn)(bozohttpd_t *, int, void *, size_t))
1791{ 1788{
1792 ssize_t len; 1789 ssize_t len;
1793 int got_cr = 0; 1790 int got_cr = 0;
1794 char c, *nbuffer; 1791 char c, *nbuffer;
1795 1792
1796 /* initialise */ 1793 /* initialise */
1797 if (httpd->getln_buflen == 0) { 1794 if (httpd->getln_buflen == 0) {
1798 /* should be plenty for most requests */ 1795 /* should be plenty for most requests */
1799 httpd->getln_buflen = 128; 1796 httpd->getln_buflen = 128;
1800 httpd->getln_buffer = malloc((size_t)httpd->getln_buflen); 1797 httpd->getln_buffer = malloc((size_t)httpd->getln_buflen);
1801 if (httpd->getln_buffer == NULL) { 1798 if (httpd->getln_buffer == NULL) {
1802 httpd->getln_buflen = 0; 1799 httpd->getln_buflen = 0;
1803 return NULL; 1800 return NULL;
1804 } 1801 }
1805 } 1802 }
1806 len = 0; 1803 len = 0;
1807 1804
1808 /* 1805 /*
1809 * we *have* to read one byte at a time, to not break cgi 1806 * we *have* to read one byte at a time, to not break cgi
1810 * programs (for we pass stdin off to them). could fix this 1807 * programs (for we pass stdin off to them). could fix this
1811 * by becoming a fd-passing program instead of just exec'ing 1808 * by becoming a fd-passing program instead of just exec'ing
1812 * the program 1809 * the program
1813 * 1810 *
1814 * the above is no longer true, we are the fd-passing 1811 * the above is no longer true, we are the fd-passing
1815 * program already. 1812 * program already.
1816 */ 1813 */
1817 for (; readfn(httpd, fd, &c, 1) == 1; ) { 1814 for (; readfn(httpd, fd, &c, 1) == 1; ) {
1818 debug((httpd, DEBUG_EXPLODING, "bozodgetln read %c", c)); 1815 debug((httpd, DEBUG_EXPLODING, "bozodgetln read %c", c));
1819 1816
1820 if (len >= httpd->getln_buflen - 1) { 1817 if (len >= httpd->getln_buflen - 1) {
1821 httpd->getln_buflen *= 2; 1818 httpd->getln_buflen *= 2;
1822 debug((httpd, DEBUG_EXPLODING, "bozodgetln: " 1819 debug((httpd, DEBUG_EXPLODING, "bozodgetln: "
1823 "reallocating buffer to buflen %zu", 1820 "reallocating buffer to buflen %zu",
1824 httpd->getln_buflen)); 1821 httpd->getln_buflen));
1825 nbuffer = bozorealloc(httpd, httpd->getln_buffer, 1822 nbuffer = bozorealloc(httpd, httpd->getln_buffer,
1826 (size_t)httpd->getln_buflen); 1823 (size_t)httpd->getln_buflen);
1827 httpd->getln_buffer = nbuffer; 1824 httpd->getln_buffer = nbuffer;
1828 } 1825 }
1829 1826
1830 httpd->getln_buffer[len++] = c; 1827 httpd->getln_buffer[len++] = c;
1831 if (c == '\r') { 1828 if (c == '\r') {
1832 got_cr = 1; 1829 got_cr = 1;
1833 continue; 1830 continue;
1834 } else if (c == '\n') { 1831 } else if (c == '\n') {
1835 /* 1832 /*
1836 * HTTP/1.1 spec says to ignore CR and treat 1833 * HTTP/1.1 spec says to ignore CR and treat
1837 * LF as the real line terminator. even though 1834 * LF as the real line terminator. even though
1838 * the same spec defines CRLF as the line 1835 * the same spec defines CRLF as the line
1839 * terminator, it is recommended in section 19.3 1836 * terminator, it is recommended in section 19.3
1840 * to do the LF trick for tolerance. 1837 * to do the LF trick for tolerance.
1841 */ 1838 */
1842 if (got_cr) 1839 if (got_cr)
1843 len -= 2; 1840 len -= 2;
1844 else 1841 else
1845 len -= 1; 1842 len -= 1;
1846 break; 1843 break;
1847 } 1844 }
1848 1845
1849 } 1846 }
1850 httpd->getln_buffer[len] = '\0'; 1847 httpd->getln_buffer[len] = '\0';
1851 debug((httpd, DEBUG_OBESE, "bozodgetln returns: ``%s'' with len %d", 1848 debug((httpd, DEBUG_OBESE, "bozodgetln returns: ``%s'' with len %zd",
1852 httpd->getln_buffer, len)); 1849 httpd->getln_buffer, len));
1853 *lenp = len; 1850 *lenp = len;
1854 return httpd->getln_buffer; 1851 return httpd->getln_buffer;
1855} 1852}
1856 1853
1857void * 1854void *
1858bozorealloc(bozohttpd_t *httpd, void *ptr, size_t size) 1855bozorealloc(bozohttpd_t *httpd, void *ptr, size_t size)
1859{ 1856{
1860 void *p; 1857 void *p;
1861 1858
1862 p = realloc(ptr, size); 1859 p = realloc(ptr, size);
1863 if (p == NULL) { 1860 if (p == NULL) {
1864 (void)bozo_http_error(httpd, 500, NULL, 1861 (void)bozo_http_error(httpd, 500, NULL,
1865 "memory allocation failure"); 1862 "memory allocation failure");
1866 exit(1); 1863 exit(1);
1867 } 1864 }
1868 return (p); 1865 return (p);
1869} 1866}
1870 1867
1871void * 1868void *
1872bozomalloc(bozohttpd_t *httpd, size_t size) 1869bozomalloc(bozohttpd_t *httpd, size_t size)
1873{ 1870{
1874 void *p; 1871 void *p;
1875 1872
1876 p = malloc(size); 1873 p = malloc(size);
1877 if (p == NULL) { 1874 if (p == NULL) {
1878 (void)bozo_http_error(httpd, 500, NULL, 1875 (void)bozo_http_error(httpd, 500, NULL,
1879 "memory allocation failure"); 1876 "memory allocation failure");
1880 exit(1); 1877 exit(1);
1881 } 1878 }
1882 return (p); 1879 return (p);
1883} 1880}
1884 1881
1885char * 1882char *
1886bozostrdup(bozohttpd_t *httpd, const char *str) 1883bozostrdup(bozohttpd_t *httpd, const char *str)
1887{ 1884{
1888 char *p; 1885 char *p;
1889 1886
1890 p = strdup(str); 1887 p = strdup(str);
1891 if (p == NULL) { 1888 if (p == NULL) {
1892 (void)bozo_http_error(httpd, 500, NULL, 1889 (void)bozo_http_error(httpd, 500, NULL,
1893 "memory allocation failure"); 1890 "memory allocation failure");
1894 exit(1); 1891 exit(1);
1895 } 1892 }
1896 return (p); 1893 return (p);
1897} 1894}
1898 1895
1899/* set default values in bozohttpd_t struct */ 1896/* set default values in bozohttpd_t struct */
1900int 1897int
1901bozo_init_httpd(bozohttpd_t *httpd) 1898bozo_init_httpd(bozohttpd_t *httpd)
1902{ 1899{
1903 /* make sure everything is clean */ 1900 /* make sure everything is clean */
1904 (void) memset(httpd, 0x0, sizeof(*httpd)); 1901 (void) memset(httpd, 0x0, sizeof(*httpd));
1905 1902
1906 /* constants */ 1903 /* constants */
1907 httpd->consts.http_09 = "HTTP/0.9"; 1904 httpd->consts.http_09 = "HTTP/0.9";
1908 httpd->consts.http_10 = "HTTP/1.0"; 1905 httpd->consts.http_10 = "HTTP/1.0";
1909 httpd->consts.http_11 = "HTTP/1.1"; 1906 httpd->consts.http_11 = "HTTP/1.1";
1910 httpd->consts.text_plain = "text/plain"; 1907 httpd->consts.text_plain = "text/plain";
1911 1908
1912 /* mmap region size */ 1909 /* mmap region size */
1913 httpd->mmapsz = BOZO_MMAPSZ; 1910 httpd->mmapsz = BOZO_MMAPSZ;
1914 1911
1915 /* error buffer for bozo_http_error() */ 1912 /* error buffer for bozo_http_error() */
1916 if ((httpd->errorbuf = malloc(BUFSIZ)) == NULL) { 1913 if ((httpd->errorbuf = malloc(BUFSIZ)) == NULL) {
1917 (void) fprintf(stderr, 1914 (void) fprintf(stderr,
1918 "bozohttpd: memory_allocation failure\n"); 1915 "bozohttpd: memory_allocation failure\n");
1919 return 0; 1916 return 0;
1920 } 1917 }
1921 return 1; 1918 return 1;
1922} 1919}
1923 1920
1924/* set default values in bozoprefs_t struct */ 1921/* set default values in bozoprefs_t struct */
1925int 1922int
1926bozo_init_prefs(bozoprefs_t *prefs) 1923bozo_init_prefs(bozoprefs_t *prefs)
1927{ 1924{
1928 /* make sure everything is clean */ 1925 /* make sure everything is clean */
1929 (void) memset(prefs, 0x0, sizeof(*prefs)); 1926 (void) memset(prefs, 0x0, sizeof(*prefs));
1930 1927
1931 /* set up default values */ 1928 /* set up default values */
1932 bozo_set_pref(prefs, "server software", SERVER_SOFTWARE); 1929 bozo_set_pref(prefs, "server software", SERVER_SOFTWARE);
1933 bozo_set_pref(prefs, "index.html", INDEX_HTML); 1930 bozo_set_pref(prefs, "index.html", INDEX_HTML);
1934 bozo_set_pref(prefs, "public_html", PUBLIC_HTML); 1931 bozo_set_pref(prefs, "public_html", PUBLIC_HTML);
1935 1932
1936 return 1; 1933 return 1;
1937} 1934}
1938 1935
1939/* set default values */ 1936/* set default values */
1940int 1937int
1941bozo_set_defaults(bozohttpd_t *httpd, bozoprefs_t *prefs) 1938bozo_set_defaults(bozohttpd_t *httpd, bozoprefs_t *prefs)
1942{ 1939{
1943 return bozo_init_httpd(httpd) && bozo_init_prefs(prefs); 1940 return bozo_init_httpd(httpd) && bozo_init_prefs(prefs);
1944} 1941}
1945 1942
1946/* set the virtual host name, port and root */ 1943/* set the virtual host name, port and root */
1947int 1944int
1948bozo_setup(bozohttpd_t *httpd, bozoprefs_t *prefs, const char *vhost, 1945bozo_setup(bozohttpd_t *httpd, bozoprefs_t *prefs, const char *vhost,
1949 const char *root) 1946 const char *root)
1950{ 1947{
1951 struct passwd *pw; 1948 struct passwd *pw;
1952 extern char **environ; 1949 extern char **environ;
1953 static char *cleanenv[1] = { NULL }; 1950 static char *cleanenv[1] = { NULL };
1954 uid_t uid; 1951 uid_t uid;
1955 char *chrootdir; 1952 char *chrootdir;
1956 char *username; 1953 char *username;
1957 char *portnum; 1954 char *portnum;
1958 char *cp; 1955 char *cp;
1959 int dirtyenv; 1956 int dirtyenv;
1960 1957
1961 dirtyenv = 0; 1958 dirtyenv = 0;
1962 1959
1963 if (vhost == NULL) { 1960 if (vhost == NULL) {
1964 httpd->virthostname = bozomalloc(httpd, MAXHOSTNAMELEN+1); 1961 httpd->virthostname = bozomalloc(httpd, MAXHOSTNAMELEN+1);
1965 /* XXX we do not check for FQDN here */ 1962 /* XXX we do not check for FQDN here */
1966 if (gethostname(httpd->virthostname, MAXHOSTNAMELEN+1) < 0) 1963 if (gethostname(httpd->virthostname, MAXHOSTNAMELEN+1) < 0)
1967 bozo_err(httpd, 1, "gethostname"); 1964 bozo_err(httpd, 1, "gethostname");
1968 httpd->virthostname[MAXHOSTNAMELEN] = '\0'; 1965 httpd->virthostname[MAXHOSTNAMELEN] = '\0';
1969 } else { 1966 } else {
1970 httpd->virthostname = strdup(vhost); 1967 httpd->virthostname = strdup(vhost);
1971 } 1968 }
1972 httpd->slashdir = strdup(root); 1969 httpd->slashdir = strdup(root);
1973 if ((portnum = bozo_get_pref(prefs, "port number")) != NULL) { 1970 if ((portnum = bozo_get_pref(prefs, "port number")) != NULL) {
1974 httpd->bindport = strdup(portnum); 1971 httpd->bindport = strdup(portnum);
1975 } 1972 }
1976 1973
1977 /* go over preferences now */ 1974 /* go over preferences now */
1978 if ((cp = bozo_get_pref(prefs, "numeric")) != NULL && 1975 if ((cp = bozo_get_pref(prefs, "numeric")) != NULL &&
1979 strcmp(cp, "true") == 0) { 1976 strcmp(cp, "true") == 0) {
1980 httpd->numeric = 1; 1977 httpd->numeric = 1;
1981 } 1978 }
1982 if ((cp = bozo_get_pref(prefs, "trusted referal")) != NULL && 1979 if ((cp = bozo_get_pref(prefs, "trusted referal")) != NULL &&
1983 strcmp(cp, "true") == 0) { 1980 strcmp(cp, "true") == 0) {
1984 httpd->untrustedref = 1; 1981 httpd->untrustedref = 1;
1985 } 1982 }
1986 if ((cp = bozo_get_pref(prefs, "log to stderr")) != NULL && 1983 if ((cp = bozo_get_pref(prefs, "log to stderr")) != NULL &&
1987 strcmp(cp, "true") == 0) { 1984 strcmp(cp, "true") == 0) {
1988 httpd->logstderr = 1; 1985 httpd->logstderr = 1;
1989 } 1986 }
1990 if ((cp = bozo_get_pref(prefs, "bind address")) != NULL) { 1987 if ((cp = bozo_get_pref(prefs, "bind address")) != NULL) {
1991 httpd->bindaddress = strdup(cp); 1988 httpd->bindaddress = strdup(cp);
1992 } 1989 }
1993 if ((cp = bozo_get_pref(prefs, "background")) != NULL) { 1990 if ((cp = bozo_get_pref(prefs, "background")) != NULL) {
1994 httpd->background = atoi(cp); 1991 httpd->background = atoi(cp);
1995 } 1992 }
1996 if ((cp = bozo_get_pref(prefs, "foreground")) != NULL && 1993 if ((cp = bozo_get_pref(prefs, "foreground")) != NULL &&
1997 strcmp(cp, "true") == 0) { 1994 strcmp(cp, "true") == 0) {
1998 httpd->foreground = 1; 1995 httpd->foreground = 1;
1999 } 1996 }
2000 if ((cp = bozo_get_pref(prefs, "pid file")) != NULL) { 1997 if ((cp = bozo_get_pref(prefs, "pid file")) != NULL) {
2001 httpd->pidfile = strdup(cp); 1998 httpd->pidfile = strdup(cp);
2002 } 1999 }
2003 if ((cp = bozo_get_pref(prefs, "unknown slash")) != NULL && 2000 if ((cp = bozo_get_pref(prefs, "unknown slash")) != NULL &&
2004 strcmp(cp, "true") == 0) { 2001 strcmp(cp, "true") == 0) {
2005 httpd->unknown_slash = 1; 2002 httpd->unknown_slash = 1;
2006 } 2003 }
2007 if ((cp = bozo_get_pref(prefs, "virtual base")) != NULL) { 2004 if ((cp = bozo_get_pref(prefs, "virtual base")) != NULL) {
2008 httpd->virtbase = strdup(cp); 2005 httpd->virtbase = strdup(cp);
2009 } 2006 }
2010 if ((cp = bozo_get_pref(prefs, "enable users")) != NULL && 2007 if ((cp = bozo_get_pref(prefs, "enable users")) != NULL &&
2011 strcmp(cp, "true") == 0) { 2008 strcmp(cp, "true") == 0) {
2012 httpd->enable_users = 1; 2009 httpd->enable_users = 1;
2013 } 2010 }
2014 if ((cp = bozo_get_pref(prefs, "dirty environment")) != NULL && 2011 if ((cp = bozo_get_pref(prefs, "dirty environment")) != NULL &&
2015 strcmp(cp, "true") == 0) { 2012 strcmp(cp, "true") == 0) {
2016 dirtyenv = 1; 2013 dirtyenv = 1;
2017 } 2014 }
2018 if ((cp = bozo_get_pref(prefs, "hide dots")) != NULL && 2015 if ((cp = bozo_get_pref(prefs, "hide dots")) != NULL &&
2019 strcmp(cp, "true") == 0) { 2016 strcmp(cp, "true") == 0) {
2020 httpd->hide_dots = 1; 2017 httpd->hide_dots = 1;
2021 } 2018 }
2022 if ((cp = bozo_get_pref(prefs, "directory indexing")) != NULL && 2019 if ((cp = bozo_get_pref(prefs, "directory indexing")) != NULL &&
2023 strcmp(cp, "true") == 0) { 2020 strcmp(cp, "true") == 0) {
2024 httpd->dir_indexing = 1; 2021 httpd->dir_indexing = 1;
2025 } 2022 }
2026 if ((cp = bozo_get_pref(prefs, "public_html")) != NULL) { 2023 if ((cp = bozo_get_pref(prefs, "public_html")) != NULL) {
2027 httpd->public_html = strdup(cp); 2024 httpd->public_html = strdup(cp);
2028 } 2025 }
2029 httpd->server_software = 2026 httpd->server_software =
2030 strdup(bozo_get_pref(prefs, "server software")); 2027 strdup(bozo_get_pref(prefs, "server software"));
2031 httpd->index_html = strdup(bozo_get_pref(prefs, "index.html")); 2028 httpd->index_html = strdup(bozo_get_pref(prefs, "index.html"));
2032 2029
2033 /* 2030 /*
2034 * initialise ssl and daemon mode if necessary. 2031 * initialise ssl and daemon mode if necessary.
2035 */ 2032 */
2036 bozo_ssl_init(httpd); 2033 bozo_ssl_init(httpd);
2037 bozo_daemon_init(httpd); 2034 bozo_daemon_init(httpd);
2038 2035
2039 if ((username = bozo_get_pref(prefs, "username")) == NULL) { 2036 if ((username = bozo_get_pref(prefs, "username")) == NULL) {
2040 if ((pw = getpwuid(uid = 0)) == NULL) 2037 if ((pw = getpwuid(uid = 0)) == NULL)
2041 bozo_err(httpd, 1, "getpwuid(0): %s", strerror(errno)); 2038 bozo_err(httpd, 1, "getpwuid(0): %s", strerror(errno));
2042 httpd->username = strdup(pw->pw_name); 2039 httpd->username = strdup(pw->pw_name);
2043 } else { 2040 } else {
2044 httpd->username = strdup(username); 2041 httpd->username = strdup(username);
2045 if ((pw = getpwnam(httpd->username)) == NULL) 2042 if ((pw = getpwnam(httpd->username)) == NULL)
2046 bozo_err(httpd, 1, "getpwnam(%s): %s", httpd->username, 2043 bozo_err(httpd, 1, "getpwnam(%s): %s", httpd->username,
2047 strerror(errno)); 2044 strerror(errno));
2048 if (initgroups(pw->pw_name, pw->pw_gid) == -1) 2045 if (initgroups(pw->pw_name, pw->pw_gid) == -1)
2049 bozo_err(httpd, 1, "initgroups: %s", strerror(errno)); 2046 bozo_err(httpd, 1, "initgroups: %s", strerror(errno));
2050 if (setgid(pw->pw_gid) == -1) 2047 if (setgid(pw->pw_gid) == -1)
2051 bozo_err(httpd, 1, "setgid(%u): %s", pw->pw_gid, 2048 bozo_err(httpd, 1, "setgid(%u): %s", pw->pw_gid,
2052 strerror(errno)); 2049 strerror(errno));
2053 uid = pw->pw_uid; 2050 uid = pw->pw_uid;
2054 } 2051 }
2055 /* 2052 /*
2056 * handle chroot. 2053 * handle chroot.
2057 */ 2054 */
2058 if ((chrootdir = bozo_get_pref(prefs, "chroot dir")) != NULL) { 2055 if ((chrootdir = bozo_get_pref(prefs, "chroot dir")) != NULL) {
2059 httpd->rootdir = strdup(chrootdir); 2056 httpd->rootdir = strdup(chrootdir);
2060 if (chdir(httpd->rootdir) == -1) 2057 if (chdir(httpd->rootdir) == -1)
2061 bozo_err(httpd, 1, "chdir(%s): %s", httpd->rootdir, 2058 bozo_err(httpd, 1, "chdir(%s): %s", httpd->rootdir,
2062 strerror(errno)); 2059 strerror(errno));
2063 if (chroot(httpd->rootdir) == -1) 2060 if (chroot(httpd->rootdir) == -1)
2064 bozo_err(httpd, 1, "chroot(%s): %s", httpd->rootdir, 2061 bozo_err(httpd, 1, "chroot(%s): %s", httpd->rootdir,
2065 strerror(errno)); 2062 strerror(errno));
2066 } 2063 }
2067 2064
2068 if (username != NULL) 2065 if (username != NULL)
2069 if (setuid(uid) == -1) 2066 if (setuid(uid) == -1)
2070 bozo_err(httpd, 1, "setuid(%d): %s", uid, 2067 bozo_err(httpd, 1, "setuid(%d): %s", uid,
2071 strerror(errno)); 2068 strerror(errno));
2072 2069
2073 /* 2070 /*
2074 * prevent info leakage between different compartments. 2071 * prevent info leakage between different compartments.
2075 * some PATH values in the environment would be invalided 2072 * some PATH values in the environment would be invalided
2076 * by chroot. cross-user settings might result in undesirable 2073 * by chroot. cross-user settings might result in undesirable
2077 * effects. 2074 * effects.
2078 */ 2075 */
2079 if ((chrootdir != NULL || username != NULL) && !dirtyenv) 2076 if ((chrootdir != NULL || username != NULL) && !dirtyenv)
2080 environ = cleanenv; 2077 environ = cleanenv;
2081 2078
2082#ifdef _SC_PAGESIZE 2079#ifdef _SC_PAGESIZE
2083 httpd->page_size = (long)sysconf(_SC_PAGESIZE); 2080 httpd->page_size = (long)sysconf(_SC_PAGESIZE);
2084#else 2081#else
2085 httpd->page_size = 4096; 2082 httpd->page_size = 4096;
2086#endif 2083#endif
2087 debug((httpd, DEBUG_OBESE, "myname is %s, slashdir is %s", 2084 debug((httpd, DEBUG_OBESE, "myname is %s, slashdir is %s",
2088 httpd->virthostname, httpd->slashdir)); 2085 httpd->virthostname, httpd->slashdir));
2089 2086
2090 return 1; 2087 return 1;
2091} 2088}

cvs diff -r1.18 -r1.19 src/libexec/httpd/bozohttpd.h (switch to unified diff)

--- src/libexec/httpd/bozohttpd.h 2011/03/29 07:22:31 1.18
+++ src/libexec/httpd/bozohttpd.h 2011/08/27 15:33:59 1.19
@@ -1,294 +1,299 @@ @@ -1,294 +1,299 @@
1/* $NetBSD: bozohttpd.h,v 1.18 2011/03/29 07:22:31 jmmv Exp $ */ 1/* $NetBSD: bozohttpd.h,v 1.19 2011/08/27 15:33:59 joerg Exp $ */
2 2
3/* $eterna: bozohttpd.h,v 1.37 2010/09/20 22:26:28 mrg Exp $ */ 3/* $eterna: bozohttpd.h,v 1.37 2010/09/20 22:26:28 mrg Exp $ */
4 4
5/* 5/*
6 * Copyright (c) 1997-2010 Matthew R. Green 6 * Copyright (c) 1997-2010 Matthew R. Green
7 * All rights reserved. 7 * All rights reserved.
8 * 8 *
9 * Redistribution and use in source and binary forms, with or without 9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions 10 * modification, are permitted provided that the following conditions
11 * are met: 11 * are met:
12 * 1. Redistributions of source code must retain the above copyright 12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer. 13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright 14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer and 15 * notice, this list of conditions and the following disclaimer and
16 * dedication in the documentation and/or other materials provided 16 * dedication in the documentation and/or other materials provided
17 * with the distribution. 17 * with the distribution.
18 * 18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 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 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 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 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE. 29 * SUCH DAMAGE.
30 * 30 *
31 */ 31 */
32 32
33#ifndef BOZOHTTOPD_H_ 33#ifndef BOZOHTTOPD_H_
34#define BOZOHTTOPD_H_ 1 34#define BOZOHTTOPD_H_ 1
35 35
36#include <sys/queue.h> 36#include <sys/queue.h>
37 37
38#include <sys/stat.h> 38#include <sys/stat.h>
39 39
40#include <stdio.h> 40#include <stdio.h>
41 41
42/* lots of "const" but gets free()'ed etc at times, sigh */ 42/* lots of "const" but gets free()'ed etc at times, sigh */
43 43
44/* headers */ 44/* headers */
45typedef struct bozoheaders { 45typedef struct bozoheaders {
46 /*const*/ char *h_header; 46 /*const*/ char *h_header;
47 /*const*/ char *h_value; /* this gets free()'ed etc at times */ 47 /*const*/ char *h_value; /* this gets free()'ed etc at times */
48 SIMPLEQ_ENTRY(bozoheaders) h_next; 48 SIMPLEQ_ENTRY(bozoheaders) h_next;
49} bozoheaders_t; 49} bozoheaders_t;
50 50
51typedef struct bozo_content_map_t { 51typedef struct bozo_content_map_t {
52 const char *name; /* postfix of file */ 52 const char *name; /* postfix of file */
53 size_t namelen; /* length of postfix */ 53 size_t namelen; /* length of postfix */
54 const char *type; /* matching content-type */ 54 const char *type; /* matching content-type */
55 const char *encoding; /* matching content-encoding */ 55 const char *encoding; /* matching content-encoding */
56 const char *encoding11; /* matching content-encoding (HTTP/1.1) */ 56 const char *encoding11; /* matching content-encoding (HTTP/1.1) */
57 const char *cgihandler; /* optional CGI handler */ 57 const char *cgihandler; /* optional CGI handler */
58} bozo_content_map_t; 58} bozo_content_map_t;
59 59
60/* this struct holds the bozo constants */ 60/* this struct holds the bozo constants */
61typedef struct bozo_consts_t { 61typedef struct bozo_consts_t {
62 const char *http_09; /* "HTTP/0.9" */ 62 const char *http_09; /* "HTTP/0.9" */
63 const char *http_10; /* "HTTP/1.0" */ 63 const char *http_10; /* "HTTP/1.0" */
64 const char *http_11; /* "HTTP/1.1" */ 64 const char *http_11; /* "HTTP/1.1" */
65 const char *text_plain; /* "text/plain" */ 65 const char *text_plain; /* "text/plain" */
66} bozo_consts_t; 66} bozo_consts_t;
67 67
68/* this structure encapsulates all the bozo flags and control vars */ 68/* this structure encapsulates all the bozo flags and control vars */
69typedef struct bozohttpd_t { 69typedef struct bozohttpd_t {
70 char *rootdir; /* root directory */ 70 char *rootdir; /* root directory */
71 char *username; /* username to switch to */ 71 char *username; /* username to switch to */
72 int numeric; /* avoid gethostby*() */ 72 int numeric; /* avoid gethostby*() */
73 char *virtbase; /* virtual directory base */ 73 char *virtbase; /* virtual directory base */
74 int unknown_slash; /* unknown vhosts go to normal slashdir */ 74 int unknown_slash; /* unknown vhosts go to normal slashdir */
75 int untrustedref; /* make sure referrer = me unless url = / */ 75 int untrustedref; /* make sure referrer = me unless url = / */
76 int logstderr; /* log to stderr (even if not tty) */ 76 int logstderr; /* log to stderr (even if not tty) */
77 int background; /* drop into daemon mode */ 77 int background; /* drop into daemon mode */
78 int foreground; /* keep daemon mode in foreground */ 78 int foreground; /* keep daemon mode in foreground */
79 char *pidfile; /* path to the pid file, if any */ 79 char *pidfile; /* path to the pid file, if any */
80 size_t page_size; /* page size */ 80 size_t page_size; /* page size */
81 char *slashdir; /* www slash directory */ 81 char *slashdir; /* www slash directory */
82 char *bindport; /* bind port; default "http" */ 82 char *bindport; /* bind port; default "http" */
83 char *bindaddress; /* address for binding - INADDR_ANY */ 83 char *bindaddress; /* address for binding - INADDR_ANY */
84 int debug; /* debugging level */ 84 int debug; /* debugging level */
85 char *virthostname; /* my name */ 85 char *virthostname; /* my name */
86 const char *server_software;/* our brand :-) */ 86 const char *server_software;/* our brand :-) */
87 const char *index_html; /* our home page */ 87 const char *index_html; /* our home page */
88 const char *public_html; /* ~user/public_html page */ 88 const char *public_html; /* ~user/public_html page */
89 int enable_users; /* enable public_html */ 89 int enable_users; /* enable public_html */
90 int *sock; /* bound sockets */ 90 int *sock; /* bound sockets */
91 int nsock; /* number of above */ 91 int nsock; /* number of above */
92 struct pollfd *fds; /* current poll fd set */ 92 struct pollfd *fds; /* current poll fd set */
93 int request_times; /* # times a request was processed */ 93 int request_times; /* # times a request was processed */
94 int dir_indexing; /* handle directories */ 94 int dir_indexing; /* handle directories */
95 int hide_dots; /* hide .* */ 95 int hide_dots; /* hide .* */
96 int process_cgi; /* use the cgi handler */ 96 int process_cgi; /* use the cgi handler */
97 char *cgibin; /* cgi-bin directory */ 97 char *cgibin; /* cgi-bin directory */
98 void *sslinfo; /* pointer to ssl struct */ 98 void *sslinfo; /* pointer to ssl struct */
99 int dynamic_content_map_size;/* size of dyn cont map */ 99 int dynamic_content_map_size;/* size of dyn cont map */
100 bozo_content_map_t *dynamic_content_map;/* dynamic content map */ 100 bozo_content_map_t *dynamic_content_map;/* dynamic content map */
101 size_t mmapsz; /* size of region to mmap */ 101 size_t mmapsz; /* size of region to mmap */
102 char *getln_buffer; /* space for getln buffer */ 102 char *getln_buffer; /* space for getln buffer */
103 ssize_t getln_buflen; /* length of allocated space */ 103 ssize_t getln_buflen; /* length of allocated space */
104 char *errorbuf; /* no dynamic allocation allowed */ 104 char *errorbuf; /* no dynamic allocation allowed */
105 bozo_consts_t consts; /* various constants */ 105 bozo_consts_t consts; /* various constants */
106} bozohttpd_t; 106} bozohttpd_t;
107 107
108/* bozo_httpreq_t */ 108/* bozo_httpreq_t */
109typedef struct bozo_httpreq_t { 109typedef struct bozo_httpreq_t {
110 bozohttpd_t *hr_httpd; 110 bozohttpd_t *hr_httpd;
111 int hr_method; 111 int hr_method;
112#define HTTP_GET 0x01 112#define HTTP_GET 0x01
113#define HTTP_POST 0x02 113#define HTTP_POST 0x02
114#define HTTP_HEAD 0x03 114#define HTTP_HEAD 0x03
115#define HTTP_OPTIONS 0x04 /* not supported */ 115#define HTTP_OPTIONS 0x04 /* not supported */
116#define HTTP_PUT 0x05 /* not supported */ 116#define HTTP_PUT 0x05 /* not supported */
117#define HTTP_DELETE 0x06 /* not supported */ 117#define HTTP_DELETE 0x06 /* not supported */
118#define HTTP_TRACE 0x07 /* not supported */ 118#define HTTP_TRACE 0x07 /* not supported */
119#define HTTP_CONNECT 0x08 /* not supported */ 119#define HTTP_CONNECT 0x08 /* not supported */
120 const char *hr_methodstr; 120 const char *hr_methodstr;
121 char *hr_file; 121 char *hr_file;
122 char *hr_oldfile; /* if we added an index_html */ 122 char *hr_oldfile; /* if we added an index_html */
123 char *hr_query;  123 char *hr_query;
124 const char *hr_proto; 124 const char *hr_proto;
125 const char *hr_content_type; 125 const char *hr_content_type;
126 const char *hr_content_length; 126 const char *hr_content_length;
127 const char *hr_allow; 127 const char *hr_allow;
128 const char *hr_host; /* HTTP/1.1 Host: */ 128 const char *hr_host; /* HTTP/1.1 Host: */
129 const char *hr_referrer; 129 const char *hr_referrer;
130 const char *hr_range; 130 const char *hr_range;
131 const char *hr_if_modified_since; 131 const char *hr_if_modified_since;
132 int hr_have_range; 132 int hr_have_range;
133 off_t hr_first_byte_pos; 133 off_t hr_first_byte_pos;
134 off_t hr_last_byte_pos; 134 off_t hr_last_byte_pos;
135 /*const*/ char *hr_remotehost; 135 /*const*/ char *hr_remotehost;
136 /*const*/ char *hr_remoteaddr; 136 /*const*/ char *hr_remoteaddr;
137 /*const*/ char *hr_serverport; 137 /*const*/ char *hr_serverport;
138#ifdef DO_HTPASSWD 138#ifdef DO_HTPASSWD
139 /*const*/ char *hr_authrealm; 139 /*const*/ char *hr_authrealm;
140 /*const*/ char *hr_authuser; 140 /*const*/ char *hr_authuser;
141 /*const*/ char *hr_authpass; 141 /*const*/ char *hr_authpass;
142#endif 142#endif
143 SIMPLEQ_HEAD(, bozoheaders) hr_headers; 143 SIMPLEQ_HEAD(, bozoheaders) hr_headers;
144 int hr_nheaders; 144 int hr_nheaders;
145} bozo_httpreq_t; 145} bozo_httpreq_t;
146 146
147/* structure to hold string based (name, value) pairs with preferences */ 147/* structure to hold string based (name, value) pairs with preferences */
148typedef struct bozoprefs_t { 148typedef struct bozoprefs_t {
149 unsigned size; /* size of the two arrays */ 149 unsigned size; /* size of the two arrays */
150 unsigned c; /* # of entries in arrays */ 150 unsigned c; /* # of entries in arrays */
151 char **name; /* names of each entry */ 151 char **name; /* names of each entry */
152 char **value; /* values for the name entries */ 152 char **value; /* values for the name entries */
153} bozoprefs_t; 153} bozoprefs_t;
154 154
155/* write in upto 64KiB chunks, and mmap in upto 64MiB chunks */ 155/* write in upto 64KiB chunks, and mmap in upto 64MiB chunks */
156#define BOZO_WRSZ (64 * 1024) 156#define BOZO_WRSZ (64 * 1024)
157#define BOZO_MMAPSZ (BOZO_WRSZ * 1024) 157#define BOZO_MMAPSZ (BOZO_WRSZ * 1024)
158 158
159/* debug flags */ 159/* debug flags */
160#define DEBUG_NORMAL 1 160#define DEBUG_NORMAL 1
161#define DEBUG_FAT 2 161#define DEBUG_FAT 2
162#define DEBUG_OBESE 3 162#define DEBUG_OBESE 3
163#define DEBUG_EXPLODING 4 163#define DEBUG_EXPLODING 4
164 164
165#define strornull(x) ((x) ? (x) : "<null>") 165#define strornull(x) ((x) ? (x) : "<null>")
166 166
167#ifndef NO_DEBUG 167#ifndef NO_DEBUG
168void debug__(bozohttpd_t *, int, const char *, ...) 168void debug__(bozohttpd_t *, int, const char *, ...)
169 __attribute__((__format__(__printf__, 3, 4))); 169 __attribute__((__format__(__printf__, 3, 4)));
170#define debug(x) debug__ x 170#define debug(x) debug__ x
171#else 171#else
172#define debug(x)  172#define debug(x)
173#endif /* NO_DEBUG */ 173#endif /* NO_DEBUG */
174 174
 175#if defined(__GNUC__) && __GNUC__ >= 3
 176#define BOZO_PRINTFLIKE(x,y) __attribute__((__format__(__printf__, x,y)))
 177#define BOZO_DEAD __attribute__((__noreturn__))
 178#endif
 179
175void bozo_warn(bozohttpd_t *, const char *, ...) 180void bozo_warn(bozohttpd_t *, const char *, ...)
176 __attribute__((__format__(__printf__, 2, 3))); 181 BOZO_PRINTFLIKE(2, 3);
177void bozo_err(bozohttpd_t *, int, const char *, ...) 182void bozo_err(bozohttpd_t *, int, const char *, ...)
178 __attribute__((__format__(__printf__, 3, 4))) 183 BOZO_PRINTFLIKE(3, 4)
179 __attribute__((__noreturn__)); 184 BOZO_DEAD;
180int bozo_http_error(bozohttpd_t *, int, bozo_httpreq_t *, const char *); 185int bozo_http_error(bozohttpd_t *, int, bozo_httpreq_t *, const char *);
181 186
182int bozo_check_special_files(bozo_httpreq_t *, const char *); 187int bozo_check_special_files(bozo_httpreq_t *, const char *);
183char *bozo_http_date(char *, size_t); 188char *bozo_http_date(char *, size_t);
184void bozo_print_header(bozo_httpreq_t *, struct stat *, const char *, const char *); 189void bozo_print_header(bozo_httpreq_t *, struct stat *, const char *, const char *);
185 190
186char *bozodgetln(bozohttpd_t *, int, ssize_t *, ssize_t (*)(bozohttpd_t *, int, void *, size_t)); 191char *bozodgetln(bozohttpd_t *, int, ssize_t *, ssize_t (*)(bozohttpd_t *, int, void *, size_t));
187char *bozostrnsep(char **, const char *, ssize_t *); 192char *bozostrnsep(char **, const char *, ssize_t *);
188 193
189void *bozomalloc(bozohttpd_t *, size_t); 194void *bozomalloc(bozohttpd_t *, size_t);
190void *bozorealloc(bozohttpd_t *, void *, size_t); 195void *bozorealloc(bozohttpd_t *, void *, size_t);
191char *bozostrdup(bozohttpd_t *, const char *); 196char *bozostrdup(bozohttpd_t *, const char *);
192 197
193/* ssl-bozo.c */ 198/* ssl-bozo.c */
194#ifdef NO_SSL_SUPPORT 199#ifdef NO_SSL_SUPPORT
195#define bozo_ssl_set_opts(w, x, y) /* nothing */ 200#define bozo_ssl_set_opts(w, x, y) /* nothing */
196#define bozo_ssl_init(x) /* nothing */ 201#define bozo_ssl_init(x) /* nothing */
197#define bozo_ssl_accept(x) /* nothing */ 202#define bozo_ssl_accept(x) /* nothing */
198#define bozo_ssl_destroy(x) /* nothing */ 203#define bozo_ssl_destroy(x) /* nothing */
199#else 204#else
200void bozo_ssl_set_opts(bozohttpd_t *, const char *, const char *); 205void bozo_ssl_set_opts(bozohttpd_t *, const char *, const char *);
201void bozo_ssl_init(bozohttpd_t *); 206void bozo_ssl_init(bozohttpd_t *);
202void bozo_ssl_accept(bozohttpd_t *); 207void bozo_ssl_accept(bozohttpd_t *);
203void bozo_ssl_destroy(bozohttpd_t *); 208void bozo_ssl_destroy(bozohttpd_t *);
204#endif 209#endif
205 210
206 211
207/* auth-bozo.c */ 212/* auth-bozo.c */
208#ifdef DO_HTPASSWD 213#ifdef DO_HTPASSWD
209int bozo_auth_check(bozo_httpreq_t *, const char *); 214int bozo_auth_check(bozo_httpreq_t *, const char *);
210void bozo_auth_cleanup(bozo_httpreq_t *); 215void bozo_auth_cleanup(bozo_httpreq_t *);
211int bozo_auth_check_headers(bozo_httpreq_t *, char *, char *, ssize_t); 216int bozo_auth_check_headers(bozo_httpreq_t *, char *, char *, ssize_t);
212int bozo_auth_check_special_files(bozo_httpreq_t *, const char *); 217int bozo_auth_check_special_files(bozo_httpreq_t *, const char *);
213void bozo_auth_check_401(bozo_httpreq_t *, int); 218void bozo_auth_check_401(bozo_httpreq_t *, int);
214void bozo_auth_cgi_setenv(bozo_httpreq_t *, char ***); 219void bozo_auth_cgi_setenv(bozo_httpreq_t *, char ***);
215int bozo_auth_cgi_count(bozo_httpreq_t *); 220int bozo_auth_cgi_count(bozo_httpreq_t *);
216#else 221#else
217#define bozo_auth_check(x, y) 0 222#define bozo_auth_check(x, y) 0
218#define bozo_auth_cleanup(x) /* nothing */ 223#define bozo_auth_cleanup(x) /* nothing */
219#define bozo_auth_check_headers(y, z, a, b) 0 224#define bozo_auth_check_headers(y, z, a, b) 0
220#define bozo_auth_check_special_files(x, y) 0 225#define bozo_auth_check_special_files(x, y) 0
221#define bozo_auth_check_401(x, y) /* nothing */ 226#define bozo_auth_check_401(x, y) /* nothing */
222#define bozo_auth_cgi_setenv(x, y) /* nothing */ 227#define bozo_auth_cgi_setenv(x, y) /* nothing */
223#define bozo_auth_cgi_count(x) 0 228#define bozo_auth_cgi_count(x) 0
224#endif /* DO_HTPASSWD */ 229#endif /* DO_HTPASSWD */
225 230
226 231
227/* cgi-bozo.c */ 232/* cgi-bozo.c */
228#ifdef NO_CGIBIN_SUPPORT 233#ifdef NO_CGIBIN_SUPPORT
229#define bozo_process_cgi(h) 0 234#define bozo_process_cgi(h) 0
230#else 235#else
231void bozo_cgi_setbin(bozohttpd_t *, const char *); 236void bozo_cgi_setbin(bozohttpd_t *, const char *);
232void bozo_setenv(bozohttpd_t *, const char *, const char *, char **); 237void bozo_setenv(bozohttpd_t *, const char *, const char *, char **);
233int bozo_process_cgi(bozo_httpreq_t *); 238int bozo_process_cgi(bozo_httpreq_t *);
234void bozo_add_content_map_cgi(bozohttpd_t *, const char *, const char *); 239void bozo_add_content_map_cgi(bozohttpd_t *, const char *, const char *);
235#endif /* NO_CGIBIN_SUPPORT */ 240#endif /* NO_CGIBIN_SUPPORT */
236 241
237 242
238/* daemon-bozo.c */ 243/* daemon-bozo.c */
239#ifdef NO_DAEMON_MODE 244#ifdef NO_DAEMON_MODE
240#define bozo_daemon_init(x) /* nothing */ 245#define bozo_daemon_init(x) /* nothing */
241#define bozo_daemon_fork(x) 0 246#define bozo_daemon_fork(x) 0
242#define bozo_daemon_closefds(x) /* nothing */ 247#define bozo_daemon_closefds(x) /* nothing */
243#else 248#else
244void bozo_daemon_init(bozohttpd_t *); 249void bozo_daemon_init(bozohttpd_t *);
245int bozo_daemon_fork(bozohttpd_t *); 250int bozo_daemon_fork(bozohttpd_t *);
246void bozo_daemon_closefds(bozohttpd_t *); 251void bozo_daemon_closefds(bozohttpd_t *);
247#endif /* NO_DAEMON_MODE */ 252#endif /* NO_DAEMON_MODE */
248 253
249 254
250/* tilde-luzah-bozo.c */ 255/* tilde-luzah-bozo.c */
251#ifdef NO_USER_SUPPORT 256#ifdef NO_USER_SUPPORT
252#define bozo_user_transform(a, c) 0 257#define bozo_user_transform(a, c) 0
253#else 258#else
254int bozo_user_transform(bozo_httpreq_t *, int *); 259int bozo_user_transform(bozo_httpreq_t *, int *);
255#endif /* NO_USER_SUPPORT */ 260#endif /* NO_USER_SUPPORT */
256 261
257 262
258/* dir-index-bozo.c */ 263/* dir-index-bozo.c */
259#ifdef NO_DIRINDEX_SUPPORT 264#ifdef NO_DIRINDEX_SUPPORT
260#define bozo_dir_index(a, b, c) 0 265#define bozo_dir_index(a, b, c) 0
261#else 266#else
262int bozo_dir_index(bozo_httpreq_t *, const char *, int); 267int bozo_dir_index(bozo_httpreq_t *, const char *, int);
263#endif /* NO_DIRINDEX_SUPPORT */ 268#endif /* NO_DIRINDEX_SUPPORT */
264 269
265 270
266/* content-bozo.c */ 271/* content-bozo.c */
267const char *bozo_content_type(bozo_httpreq_t *, const char *); 272const char *bozo_content_type(bozo_httpreq_t *, const char *);
268const char *bozo_content_encoding(bozo_httpreq_t *, const char *); 273const char *bozo_content_encoding(bozo_httpreq_t *, const char *);
269bozo_content_map_t *bozo_match_content_map(bozohttpd_t *, const char *, int); 274bozo_content_map_t *bozo_match_content_map(bozohttpd_t *, const char *, int);
270bozo_content_map_t *bozo_get_content_map(bozohttpd_t *, const char *); 275bozo_content_map_t *bozo_get_content_map(bozohttpd_t *, const char *);
271#ifndef NO_DYNAMIC_CONTENT 276#ifndef NO_DYNAMIC_CONTENT
272void bozo_add_content_map_mime(bozohttpd_t *, const char *, const char *, const char *, const char *); 277void bozo_add_content_map_mime(bozohttpd_t *, const char *, const char *, const char *, const char *);
273#endif 278#endif
274 279
275/* I/O */ 280/* I/O */
276int bozo_printf(bozohttpd_t *, const char *, ...); 281int bozo_printf(bozohttpd_t *, const char *, ...);
277ssize_t bozo_read(bozohttpd_t *, int, void *, size_t); 282ssize_t bozo_read(bozohttpd_t *, int, void *, size_t);
278ssize_t bozo_write(bozohttpd_t *, int, const void *, size_t); 283ssize_t bozo_write(bozohttpd_t *, int, const void *, size_t);
279int bozo_flush(bozohttpd_t *, FILE *); 284int bozo_flush(bozohttpd_t *, FILE *);
280 285
281/* misc */ 286/* misc */
282int bozo_init_httpd(bozohttpd_t *); 287int bozo_init_httpd(bozohttpd_t *);
283int bozo_init_prefs(bozoprefs_t *); 288int bozo_init_prefs(bozoprefs_t *);
284int bozo_set_defaults(bozohttpd_t *, bozoprefs_t *); 289int bozo_set_defaults(bozohttpd_t *, bozoprefs_t *);
285int bozo_setup(bozohttpd_t *, bozoprefs_t *, const char *, const char *); 290int bozo_setup(bozohttpd_t *, bozoprefs_t *, const char *, const char *);
286bozo_httpreq_t *bozo_read_request(bozohttpd_t *); 291bozo_httpreq_t *bozo_read_request(bozohttpd_t *);
287void bozo_process_request(bozo_httpreq_t *); 292void bozo_process_request(bozo_httpreq_t *);
288void bozo_clean_request(bozo_httpreq_t *); 293void bozo_clean_request(bozo_httpreq_t *);
289 294
290/* variables */ 295/* variables */
291int bozo_set_pref(bozoprefs_t *, const char *, const char *); 296int bozo_set_pref(bozoprefs_t *, const char *, const char *);
292char *bozo_get_pref(bozoprefs_t *, const char *); 297char *bozo_get_pref(bozoprefs_t *, const char *);
293 298
294#endif /* BOZOHTTOPD_H_ */ 299#endif /* BOZOHTTOPD_H_ */

cvs diff -r1.13 -r1.14 src/libexec/httpd/daemon-bozo.c (switch to unified diff)

--- src/libexec/httpd/daemon-bozo.c 2011/03/29 07:22:31 1.13
+++ src/libexec/httpd/daemon-bozo.c 2011/08/27 15:33:59 1.14
@@ -1,339 +1,339 @@ @@ -1,339 +1,339 @@
1/* $NetBSD: daemon-bozo.c,v 1.13 2011/03/29 07:22:31 jmmv Exp $ */ 1/* $NetBSD: daemon-bozo.c,v 1.14 2011/08/27 15:33:59 joerg Exp $ */
2 2
3/* $eterna: daemon-bozo.c,v 1.22 2010/06/21 06:45:45 mrg Exp $ */ 3/* $eterna: daemon-bozo.c,v 1.22 2010/06/21 06:45:45 mrg Exp $ */
4 4
5/* 5/*
6 * Copyright (c) 1997-2010 Matthew R. Green 6 * Copyright (c) 1997-2010 Matthew R. Green
7 * All rights reserved. 7 * All rights reserved.
8 * 8 *
9 * Redistribution and use in source and binary forms, with or without 9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions 10 * modification, are permitted provided that the following conditions
11 * are met: 11 * are met:
12 * 1. Redistributions of source code must retain the above copyright 12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer. 13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright 14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer and 15 * notice, this list of conditions and the following disclaimer and
16 * dedication in the documentation and/or other materials provided 16 * dedication in the documentation and/or other materials provided
17 * with the distribution. 17 * with the distribution.
18 * 18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 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 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 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 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE. 29 * SUCH DAMAGE.
30 * 30 *
31 */ 31 */
32 32
33/* this code implements daemon mode for bozohttpd */ 33/* this code implements daemon mode for bozohttpd */
34 34
35#ifndef NO_DAEMON_MODE 35#ifndef NO_DAEMON_MODE
36 36
37#include <sys/param.h> 37#include <sys/param.h>
38#include <sys/socket.h> 38#include <sys/socket.h>
39#include <sys/wait.h> 39#include <sys/wait.h>
40 40
41#include <netinet/in.h> 41#include <netinet/in.h>
42 42
43#include <assert.h> 43#include <assert.h>
44#include <errno.h> 44#include <errno.h>
45#include <netdb.h> 45#include <netdb.h>
46#include <poll.h> 46#include <poll.h>
47#include <stdio.h> 47#include <stdio.h>
48#include <stdlib.h> 48#include <stdlib.h>
49#include <string.h> 49#include <string.h>
50#include <unistd.h> 50#include <unistd.h>
51 51
52#include "bozohttpd.h" 52#include "bozohttpd.h"
53 53
54static void sigchild(int); /* SIGCHLD handler */ 54static void sigchild(int); /* SIGCHLD handler */
55 55
56#ifndef POLLRDNORM 56#ifndef POLLRDNORM
57#define POLLRDNORM 0 57#define POLLRDNORM 0
58#endif 58#endif
59#ifndef POLLRDBAND 59#ifndef POLLRDBAND
60#define POLLRDBAND 0 60#define POLLRDBAND 0
61#endif 61#endif
62#ifndef INFTIM 62#ifndef INFTIM
63#define INFTIM -1 63#define INFTIM -1
64#endif 64#endif
65 65
66static const char* pidfile_path = NULL; 66static const char* pidfile_path = NULL;
67static pid_t pidfile_pid = 0; 67static pid_t pidfile_pid = 0;
68 68
69/* ARGSUSED */ 69/* ARGSUSED */
70static void 70static void
71sigchild(int signo) 71sigchild(int signo)
72{ 72{
73 while (waitpid(-1, NULL, WNOHANG) > 0) { 73 while (waitpid(-1, NULL, WNOHANG) > 0) {
74 } 74 }
75} 75}
76 76
77/* Signal handler to exit in a controlled manner. This ensures that 77/* Signal handler to exit in a controlled manner. This ensures that
78 * any atexit(3) handlers are properly executed. */ 78 * any atexit(3) handlers are properly executed. */
79/* ARGSUSED */ 79/* ARGSUSED */
80static void 80BOZO_DEAD static void
81controlled_exit(int signo) 81controlled_exit(int signo)
82{ 82{
83 83
84 exit(EXIT_SUCCESS); 84 exit(EXIT_SUCCESS);
85} 85}
86 86
87static void 87static void
88remove_pidfile(void) 88remove_pidfile(void)
89{ 89{
90 90
91 if (pidfile_path != NULL && pidfile_pid == getpid()) { 91 if (pidfile_path != NULL && pidfile_pid == getpid()) {
92 (void)unlink(pidfile_path); 92 (void)unlink(pidfile_path);
93 pidfile_path = NULL; 93 pidfile_path = NULL;
94 } 94 }
95} 95}
96 96
97static void 97static void
98create_pidfile(bozohttpd_t *httpd) 98create_pidfile(bozohttpd_t *httpd)
99{ 99{
100 FILE *file; 100 FILE *file;
101 101
102 assert(pidfile_path == NULL); 102 assert(pidfile_path == NULL);
103 103
104 if (httpd->pidfile == NULL) 104 if (httpd->pidfile == NULL)
105 return; 105 return;
106 106
107 if (atexit(remove_pidfile) == -1) 107 if (atexit(remove_pidfile) == -1)
108 bozo_err(httpd, 1, "Failed to install pidfile handler"); 108 bozo_err(httpd, 1, "Failed to install pidfile handler");
109 109
110 if ((file = fopen(httpd->pidfile, "w")) == NULL) 110 if ((file = fopen(httpd->pidfile, "w")) == NULL)
111 bozo_err(httpd, 1, "Failed to create pidfile '%s'", 111 bozo_err(httpd, 1, "Failed to create pidfile '%s'",
112 httpd->pidfile); 112 httpd->pidfile);
113 (void)fprintf(file, "%d\n", getpid()); 113 (void)fprintf(file, "%d\n", getpid());
114 (void)fclose(file); 114 (void)fclose(file);
115 115
116 pidfile_path = httpd->pidfile; 116 pidfile_path = httpd->pidfile;
117 pidfile_pid = getpid(); 117 pidfile_pid = getpid();
118 118
119 debug((httpd, DEBUG_FAT, "Created pid file '%s' for pid %d", 119 debug((httpd, DEBUG_FAT, "Created pid file '%s' for pid %d",
120 pidfile_path, pidfile_pid)); 120 pidfile_path, pidfile_pid));
121} 121}
122 122
123void 123void
124bozo_daemon_init(bozohttpd_t *httpd) 124bozo_daemon_init(bozohttpd_t *httpd)
125{ 125{
126 struct addrinfo h, *r, *r0; 126 struct addrinfo h, *r, *r0;
127 const char *portnum; 127 const char *portnum;
128 int e, i, on = 1; 128 int e, i, on = 1;
129 129
130 if (!httpd->background) 130 if (!httpd->background)
131 return; 131 return;
132 132
133 portnum = (httpd->bindport) ? httpd->bindport : "http"; 133 portnum = (httpd->bindport) ? httpd->bindport : "http";
134  134
135 memset(&h, 0, sizeof(h)); 135 memset(&h, 0, sizeof(h));
136 h.ai_family = PF_UNSPEC; 136 h.ai_family = PF_UNSPEC;
137 h.ai_socktype = SOCK_STREAM; 137 h.ai_socktype = SOCK_STREAM;
138 h.ai_flags = AI_PASSIVE; 138 h.ai_flags = AI_PASSIVE;
139 e = getaddrinfo(httpd->bindaddress, portnum, &h, &r0); 139 e = getaddrinfo(httpd->bindaddress, portnum, &h, &r0);
140 if (e) 140 if (e)
141 bozo_err(httpd, 1, "getaddrinfo([%s]:%s): %s", 141 bozo_err(httpd, 1, "getaddrinfo([%s]:%s): %s",
142 httpd->bindaddress ? httpd->bindaddress : "*", 142 httpd->bindaddress ? httpd->bindaddress : "*",
143 portnum, gai_strerror(e)); 143 portnum, gai_strerror(e));
144 for (r = r0; r != NULL; r = r->ai_next) 144 for (r = r0; r != NULL; r = r->ai_next)
145 httpd->nsock++; 145 httpd->nsock++;
146 httpd->sock = bozomalloc(httpd, httpd->nsock * sizeof(*httpd->sock)); 146 httpd->sock = bozomalloc(httpd, httpd->nsock * sizeof(*httpd->sock));
147 httpd->fds = bozomalloc(httpd, httpd->nsock * sizeof(*httpd->fds)); 147 httpd->fds = bozomalloc(httpd, httpd->nsock * sizeof(*httpd->fds));
148 for (i = 0, r = r0; r != NULL; r = r->ai_next) { 148 for (i = 0, r = r0; r != NULL; r = r->ai_next) {
149 httpd->sock[i] = socket(r->ai_family, SOCK_STREAM, 0); 149 httpd->sock[i] = socket(r->ai_family, SOCK_STREAM, 0);
150 if (httpd->sock[i] == -1) 150 if (httpd->sock[i] == -1)
151 continue; 151 continue;
152 if (setsockopt(httpd->sock[i], SOL_SOCKET, SO_REUSEADDR, &on, 152 if (setsockopt(httpd->sock[i], SOL_SOCKET, SO_REUSEADDR, &on,
153 sizeof(on)) == -1) 153 sizeof(on)) == -1)
154 bozo_warn(httpd, "setsockopt SO_REUSEADDR: %s", 154 bozo_warn(httpd, "setsockopt SO_REUSEADDR: %s",
155 strerror(errno)); 155 strerror(errno));
156 if (bind(httpd->sock[i], r->ai_addr, r->ai_addrlen) == -1) 156 if (bind(httpd->sock[i], r->ai_addr, r->ai_addrlen) == -1)
157 continue; 157 continue;
158 if (listen(httpd->sock[i], SOMAXCONN) == -1) 158 if (listen(httpd->sock[i], SOMAXCONN) == -1)
159 continue; 159 continue;
160 httpd->fds[i].events = POLLIN | POLLPRI | POLLRDNORM | 160 httpd->fds[i].events = POLLIN | POLLPRI | POLLRDNORM |
161 POLLRDBAND | POLLERR; 161 POLLRDBAND | POLLERR;
162 httpd->fds[i].fd = httpd->sock[i]; 162 httpd->fds[i].fd = httpd->sock[i];
163 i++; 163 i++;
164 } 164 }
165 if (i == 0) 165 if (i == 0)
166 bozo_err(httpd, 1, "could not find any addresses to bind"); 166 bozo_err(httpd, 1, "could not find any addresses to bind");
167 httpd->nsock = i; 167 httpd->nsock = i;
168 freeaddrinfo(r0); 168 freeaddrinfo(r0);
169 169
170 if (httpd->foreground == 0) 170 if (httpd->foreground == 0)
171 daemon(1, 0); 171 daemon(1, 0);
172 172
173 create_pidfile(httpd); 173 create_pidfile(httpd);
174 174
175 bozo_warn(httpd, "started in daemon mode as `%s' port `%s' root `%s'", 175 bozo_warn(httpd, "started in daemon mode as `%s' port `%s' root `%s'",
176 httpd->virthostname, portnum, httpd->slashdir); 176 httpd->virthostname, portnum, httpd->slashdir);
177 177
178 signal(SIGHUP, controlled_exit); 178 signal(SIGHUP, controlled_exit);
179 signal(SIGINT, controlled_exit); 179 signal(SIGINT, controlled_exit);
180 signal(SIGTERM, controlled_exit); 180 signal(SIGTERM, controlled_exit);
181 181
182 signal(SIGCHLD, sigchild); 182 signal(SIGCHLD, sigchild);
183} 183}
184 184
185void 185void
186bozo_daemon_closefds(bozohttpd_t *httpd) 186bozo_daemon_closefds(bozohttpd_t *httpd)
187{ 187{
188 int i; 188 int i;
189 189
190 for (i = 0; i < httpd->nsock; i++) 190 for (i = 0; i < httpd->nsock; i++)
191 close(httpd->sock[i]); 191 close(httpd->sock[i]);
192} 192}
193 193
194static void 194static void
195daemon_runchild(bozohttpd_t *httpd, int fd) 195daemon_runchild(bozohttpd_t *httpd, int fd)
196{ 196{
197 httpd->request_times++; 197 httpd->request_times++;
198 198
199 /* setup stdin/stdout/stderr */ 199 /* setup stdin/stdout/stderr */
200 dup2(fd, 0); 200 dup2(fd, 0);
201 dup2(fd, 1); 201 dup2(fd, 1);
202 /*dup2(fd, 2);*/ 202 /*dup2(fd, 2);*/
203 close(fd); 203 close(fd);
204} 204}
205 205
206static int 206static int
207daemon_poll_err(bozohttpd_t *httpd, int fd, int idx) 207daemon_poll_err(bozohttpd_t *httpd, int fd, int idx)
208{ 208{
209 if ((httpd->fds[idx].revents & (POLLNVAL|POLLERR|POLLHUP)) == 0) 209 if ((httpd->fds[idx].revents & (POLLNVAL|POLLERR|POLLHUP)) == 0)
210 return 0; 210 return 0;
211 211
212 bozo_warn(httpd, "poll on fd %d pid %d revents %d: %s", 212 bozo_warn(httpd, "poll on fd %d pid %d revents %d: %s",
213 httpd->fds[idx].fd, getpid(), httpd->fds[idx].revents, 213 httpd->fds[idx].fd, getpid(), httpd->fds[idx].revents,
214 strerror(errno)); 214 strerror(errno));
215 bozo_warn(httpd, "nsock = %d", httpd->nsock); 215 bozo_warn(httpd, "nsock = %d", httpd->nsock);
216 close(httpd->sock[idx]); 216 close(httpd->sock[idx]);
217 httpd->nsock--; 217 httpd->nsock--;
218 bozo_warn(httpd, "nsock now = %d", httpd->nsock); 218 bozo_warn(httpd, "nsock now = %d", httpd->nsock);
219 /* no sockets left */ 219 /* no sockets left */
220 if (httpd->nsock == 0) 220 if (httpd->nsock == 0)
221 exit(0); 221 exit(0);
222 /* last socket closed is the easy case */ 222 /* last socket closed is the easy case */
223 if (httpd->nsock != idx) { 223 if (httpd->nsock != idx) {
224 memmove(&httpd->fds[idx], &httpd->fds[idx+1], 224 memmove(&httpd->fds[idx], &httpd->fds[idx+1],
225 (httpd->nsock - idx) * sizeof(*httpd->fds)); 225 (httpd->nsock - idx) * sizeof(*httpd->fds));
226 memmove(&httpd->sock[idx], &httpd->sock[idx+1], 226 memmove(&httpd->sock[idx], &httpd->sock[idx+1],
227 (httpd->nsock - idx) * sizeof(*httpd->sock)); 227 (httpd->nsock - idx) * sizeof(*httpd->sock));
228 } 228 }
229 229
230 return 1; 230 return 1;
231} 231}
232 232
233/* 233/*
234 * the parent never returns from this function, only children that 234 * the parent never returns from this function, only children that
235 * are ready to run... XXXMRG - still true in fork-lesser bozo? 235 * are ready to run... XXXMRG - still true in fork-lesser bozo?
236 */ 236 */
237int 237int
238bozo_daemon_fork(bozohttpd_t *httpd) 238bozo_daemon_fork(bozohttpd_t *httpd)
239{ 239{
240 int i; 240 int i;
241 241
242 debug((httpd, DEBUG_FAT, "%s: pid %u request_times %d", 242 debug((httpd, DEBUG_FAT, "%s: pid %u request_times %d",
243 __func__, getpid(), 243 __func__, getpid(),
244 httpd->request_times)); 244 httpd->request_times));
245 /* if we've handled 5 files, exit and let someone else work */ 245 /* if we've handled 5 files, exit and let someone else work */
246 if (httpd->request_times > 5 || 246 if (httpd->request_times > 5 ||
247 (httpd->background == 2 && httpd->request_times > 0)) 247 (httpd->background == 2 && httpd->request_times > 0))
248 _exit(0); 248 _exit(0);
249 249
250#if 1 250#if 1
251 if (httpd->request_times > 0) 251 if (httpd->request_times > 0)
252 _exit(0); 252 _exit(0);
253#endif 253#endif
254 254
255 while (httpd->background) { 255 while (httpd->background) {
256 struct sockaddr_storage ss; 256 struct sockaddr_storage ss;
257 socklen_t slen; 257 socklen_t slen;
258 int fd; 258 int fd;
259 259
260 if (httpd->nsock == 0) 260 if (httpd->nsock == 0)
261 exit(0); 261 exit(0);
262 262
263 /* 263 /*
264 * wait for a connection, then fork() and return NULL in 264 * wait for a connection, then fork() and return NULL in
265 * the parent, who will come back here waiting for another 265 * the parent, who will come back here waiting for another
266 * connection. read the request in in the child, and return 266 * connection. read the request in in the child, and return
267 * it, for processing. 267 * it, for processing.
268 */ 268 */
269again: 269again:
270 if (poll(httpd->fds, (unsigned)httpd->nsock, INFTIM) == -1) { 270 if (poll(httpd->fds, (unsigned)httpd->nsock, INFTIM) == -1) {
271 /* fail on programmer errors */ 271 /* fail on programmer errors */
272 if (errno == EFAULT || 272 if (errno == EFAULT ||
273 errno == EINVAL) 273 errno == EINVAL)
274 bozo_err(httpd, 1, "poll: %s", 274 bozo_err(httpd, 1, "poll: %s",
275 strerror(errno)); 275 strerror(errno));
276 276
277 /* sleep on some temporary kernel failures */ 277 /* sleep on some temporary kernel failures */
278 if (errno == ENOMEM || 278 if (errno == ENOMEM ||
279 errno == EAGAIN) 279 errno == EAGAIN)
280 sleep(1); 280 sleep(1);
281 281
282 goto again; 282 goto again;
283 } 283 }
284 284
285 for (i = 0; i < httpd->nsock; i++) { 285 for (i = 0; i < httpd->nsock; i++) {
286 if (daemon_poll_err(httpd, fd, i)) 286 if (daemon_poll_err(httpd, fd, i))
287 break; 287 break;
288 if (httpd->fds[i].revents == 0) 288 if (httpd->fds[i].revents == 0)
289 continue; 289 continue;
290 290
291 slen = sizeof(ss); 291 slen = sizeof(ss);
292 fd = accept(httpd->fds[i].fd, 292 fd = accept(httpd->fds[i].fd,
293 (struct sockaddr *)(void *)&ss, &slen); 293 (struct sockaddr *)(void *)&ss, &slen);
294 if (fd == -1) { 294 if (fd == -1) {
295 if (errno == EFAULT || 295 if (errno == EFAULT ||
296 errno == EINVAL) 296 errno == EINVAL)
297 bozo_err(httpd, 1, "accept: %s", 297 bozo_err(httpd, 1, "accept: %s",
298 strerror(errno)); 298 strerror(errno));
299 299
300 if (errno == ENOMEM || 300 if (errno == ENOMEM ||
301 errno == EAGAIN) 301 errno == EAGAIN)
302 sleep(1); 302 sleep(1);
303 303
304 continue; 304 continue;
305 } 305 }
306 306
307#if 0 307#if 0
308 /* 308 /*
309 * This code doesn't work. It interacts very poorly 309 * This code doesn't work. It interacts very poorly
310 * with ~user translation and needs to be fixed. 310 * with ~user translation and needs to be fixed.
311 */ 311 */
312 if (httpd->request_times > 0) { 312 if (httpd->request_times > 0) {
313 daemon_runchild(httpd, fd); 313 daemon_runchild(httpd, fd);
314 return 0; 314 return 0;
315 } 315 }
316#endif 316#endif
317 317
318 switch (fork()) { 318 switch (fork()) {
319 case -1: /* eep, failure */ 319 case -1: /* eep, failure */
320 bozo_warn(httpd, "fork() failed, sleeping for " 320 bozo_warn(httpd, "fork() failed, sleeping for "
321 "10 seconds: %s", strerror(errno)); 321 "10 seconds: %s", strerror(errno));
322 close(fd); 322 close(fd);
323 sleep(10); 323 sleep(10);
324 break; 324 break;
325 325
326 case 0: /* child */ 326 case 0: /* child */
327 daemon_runchild(httpd, fd); 327 daemon_runchild(httpd, fd);
328 return 0; 328 return 0;
329 329
330 default: /* parent */ 330 default: /* parent */
331 close(fd); 331 close(fd);
332 break; 332 break;
333 } 333 }
334 } 334 }
335 } 335 }
336 return 0; 336 return 0;
337} 337}
338 338
339#endif /* NO_DAEMON_MODE */ 339#endif /* NO_DAEMON_MODE */

cvs diff -r1.2 -r1.3 src/libexec/httpd/main.c (switch to unified diff)

--- src/libexec/httpd/main.c 2011/03/29 07:22:31 1.2
+++ src/libexec/httpd/main.c 2011/08/27 15:33:59 1.3
@@ -1,345 +1,341 @@ @@ -1,345 +1,341 @@
1/* $NetBSD: main.c,v 1.2 2011/03/29 07:22:31 jmmv Exp $ */ 1/* $NetBSD: main.c,v 1.3 2011/08/27 15:33:59 joerg Exp $ */
2 2
3/* $eterna: main.c,v 1.4 2010/07/11 00:34:28 mrg Exp $ */ 3/* $eterna: main.c,v 1.4 2010/07/11 00:34:28 mrg Exp $ */
4/* from: eterna: bozohttpd.c,v 1.159 2009/05/23 02:14:30 mrg Exp */ 4/* from: eterna: bozohttpd.c,v 1.159 2009/05/23 02:14:30 mrg Exp */
5 5
6/* 6/*
7 * Copyright (c) 1997-2010 Matthew R. Green 7 * Copyright (c) 1997-2010 Matthew R. Green
8 * All rights reserved. 8 * All rights reserved.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright 15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer and 16 * notice, this list of conditions and the following disclaimer and
17 * dedication in the documentation and/or other materials provided 17 * dedication in the documentation and/or other materials provided
18 * with the distribution. 18 * with the distribution.
19 * 19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE. 30 * SUCH DAMAGE.
31 * 31 *
32 */ 32 */
33 33
34/* this program is dedicated to the Great God of Processed Cheese */ 34/* this program is dedicated to the Great God of Processed Cheese */
35 35
36/* 36/*
37 * main.c: C front end to bozohttpd 37 * main.c: C front end to bozohttpd
38 */ 38 */
39 39
40#include <sys/types.h> 40#include <sys/types.h>
41#include <sys/param.h> 41#include <sys/param.h>
42 42
43#include <errno.h> 43#include <errno.h>
44#include <stdlib.h> 44#include <stdlib.h>
45#include <string.h> 45#include <string.h>
46#include <syslog.h> 46#include <syslog.h>
47#include <time.h> 47#include <time.h>
48#include <unistd.h> 48#include <unistd.h>
49 49
50#ifndef __attribute__ 
51#define __attribute__(x) 
52#endif /* __attribute__ */ 
53 
54#include "bozohttpd.h" 50#include "bozohttpd.h"
55 51
56/* variables and functions */ 52/* variables and functions */
57#ifndef LOG_FTP 53#ifndef LOG_FTP
58#define LOG_FTP LOG_DAEMON 54#define LOG_FTP LOG_DAEMON
59#endif 55#endif
60 56
61/* print a usage message, and then exit */ 57/* print a usage message, and then exit */
62static void 58BOZO_DEAD static void
63usage(bozohttpd_t *httpd, char *progname) 59usage(bozohttpd_t *httpd, char *progname)
64{ 60{
65 bozo_warn(httpd, "usage: %s [options] slashdir [virtualhostname]", 61 bozo_warn(httpd, "usage: %s [options] slashdir [virtualhostname]",
66 progname); 62 progname);
67 bozo_warn(httpd, "options:"); 63 bozo_warn(httpd, "options:");
68#ifndef NO_DEBUG 64#ifndef NO_DEBUG
69 bozo_warn(httpd, " -d\t\t\tenable debug support"); 65 bozo_warn(httpd, " -d\t\t\tenable debug support");
70#endif 66#endif
71 bozo_warn(httpd, " -s\t\t\talways log to stderr"); 67 bozo_warn(httpd, " -s\t\t\talways log to stderr");
72#ifndef NO_USER_SUPPORT 68#ifndef NO_USER_SUPPORT
73 bozo_warn(httpd, " -u\t\t\tenable ~user/public_html support"); 69 bozo_warn(httpd, " -u\t\t\tenable ~user/public_html support");
74 bozo_warn(httpd, " -p dir\t\tchange `public_html' directory name]"); 70 bozo_warn(httpd, " -p dir\t\tchange `public_html' directory name]");
75#endif 71#endif
76#ifndef NO_DYNAMIC_CONTENT 72#ifndef NO_DYNAMIC_CONTENT
77 bozo_warn(httpd, " -M arg t c c11\tadd this mime extenstion"); 73 bozo_warn(httpd, " -M arg t c c11\tadd this mime extenstion");
78#endif 74#endif
79#ifndef NO_CGIBIN_SUPPORT 75#ifndef NO_CGIBIN_SUPPORT
80#ifndef NO_DYNAMIC_CONTENT 76#ifndef NO_DYNAMIC_CONTENT
81 bozo_warn(httpd, " -C arg prog\t\tadd this CGI handler"); 77 bozo_warn(httpd, " -C arg prog\t\tadd this CGI handler");
82#endif 78#endif
83 bozo_warn(httpd, 79 bozo_warn(httpd,
84 " -c cgibin\t\tenable cgi-bin support in this directory"); 80 " -c cgibin\t\tenable cgi-bin support in this directory");
85#endif 81#endif
86#ifndef NO_DAEMON_MODE 82#ifndef NO_DAEMON_MODE
87 bozo_warn(httpd, " -b\t\t\tbackground and go into daemon mode"); 83 bozo_warn(httpd, " -b\t\t\tbackground and go into daemon mode");
88 bozo_warn(httpd, " -f\t\t\tkeep daemon mode in the foreground"); 84 bozo_warn(httpd, " -f\t\t\tkeep daemon mode in the foreground");
89 bozo_warn(httpd, 85 bozo_warn(httpd,
90 " -i address\t\tbind on this address (daemon mode only)"); 86 " -i address\t\tbind on this address (daemon mode only)");
91 bozo_warn(httpd, " -I port\t\tbind on this port (daemon mode only)"); 87 bozo_warn(httpd, " -I port\t\tbind on this port (daemon mode only)");
92 bozo_warn(httpd, " -P pidfile\t\tpath to the pid file to create"); 88 bozo_warn(httpd, " -P pidfile\t\tpath to the pid file to create");
93#endif 89#endif
94 bozo_warn(httpd, " -S version\t\tset server version string"); 90 bozo_warn(httpd, " -S version\t\tset server version string");
95 bozo_warn(httpd, " -t dir\t\tchroot to `dir'"); 91 bozo_warn(httpd, " -t dir\t\tchroot to `dir'");
96 bozo_warn(httpd, " -U username\t\tchange user to `user'"); 92 bozo_warn(httpd, " -U username\t\tchange user to `user'");
97 bozo_warn(httpd, 93 bozo_warn(httpd,
98 " -e\t\t\tdon't clean the environment (-t and -U only)"); 94 " -e\t\t\tdon't clean the environment (-t and -U only)");
99 bozo_warn(httpd, 95 bozo_warn(httpd,
100 " -v virtualroot\tenable virtual host support " 96 " -v virtualroot\tenable virtual host support "
101 "in this directory"); 97 "in this directory");
102 bozo_warn(httpd, 98 bozo_warn(httpd,
103 " -r\t\t\tmake sure sub-pages come from " 99 " -r\t\t\tmake sure sub-pages come from "
104 "this host via referrer"); 100 "this host via referrer");
105#ifndef NO_DIRINDEX_SUPPORT 101#ifndef NO_DIRINDEX_SUPPORT
106 bozo_warn(httpd, 102 bozo_warn(httpd,
107 " -X\t\t\tenable automatic directory index support"); 103 " -X\t\t\tenable automatic directory index support");
108 bozo_warn(httpd, 104 bozo_warn(httpd,
109 " -H\t\t\thide files starting with a period (.)" 105 " -H\t\t\thide files starting with a period (.)"
110 " in index mode"); 106 " in index mode");
111#endif 107#endif
112 bozo_warn(httpd, 108 bozo_warn(httpd,
113 " -x index\t\tchange default `index.html' file name"); 109 " -x index\t\tchange default `index.html' file name");
114#ifndef NO_SSL_SUPPORT 110#ifndef NO_SSL_SUPPORT
115 bozo_warn(httpd, 111 bozo_warn(httpd,
116 " -Z cert privkey\tspecify path to server certificate" 112 " -Z cert privkey\tspecify path to server certificate"
117 " and private key file\n" 113 " and private key file\n"
118 "\t\t\tin pem format and enable bozohttpd in SSL mode"); 114 "\t\t\tin pem format and enable bozohttpd in SSL mode");
119#endif /* NO_SSL_SUPPORT */ 115#endif /* NO_SSL_SUPPORT */
120 bozo_err(httpd, 1, "%s failed to start", progname); 116 bozo_err(httpd, 1, "%s failed to start", progname);
121} 117}
122 118
123int 119int
124main(int argc, char **argv) 120main(int argc, char **argv)
125{ 121{
126 bozo_httpreq_t *request; 122 bozo_httpreq_t *request;
127 bozohttpd_t httpd; 123 bozohttpd_t httpd;
128 bozoprefs_t prefs; 124 bozoprefs_t prefs;
129 char *progname; 125 char *progname;
130 int c; 126 int c;
131 127
132 (void) memset(&httpd, 0x0, sizeof(httpd)); 128 (void) memset(&httpd, 0x0, sizeof(httpd));
133 (void) memset(&prefs, 0x0, sizeof(prefs)); 129 (void) memset(&prefs, 0x0, sizeof(prefs));
134 130
135 if ((progname = strrchr(argv[0], '/')) == NULL) 131 if ((progname = strrchr(argv[0], '/')) == NULL)
136 progname = argv[0]; 132 progname = argv[0];
137 else 133 else
138 progname++; 134 progname++;
139 135
140 openlog(progname, LOG_PID|LOG_NDELAY, LOG_FTP); 136 openlog(progname, LOG_PID|LOG_NDELAY, LOG_FTP);
141 137
142 bozo_set_defaults(&httpd, &prefs); 138 bozo_set_defaults(&httpd, &prefs);
143 139
144 while ((c = getopt(argc, argv, 140 while ((c = getopt(argc, argv,
145 "C:HI:M:P:S:U:VXZ:bc:defhi:np:rst:uv:x:z:")) != -1) { 141 "C:HI:M:P:S:U:VXZ:bc:defhi:np:rst:uv:x:z:")) != -1) {
146 switch(c) { 142 switch(c) {
147 143
148 case 'M': 144 case 'M':
149#ifdef NO_DYNAMIC_CONTENT 145#ifdef NO_DYNAMIC_CONTENT
150 bozo_err(&httpd, 1, 146 bozo_err(&httpd, 1,
151 "dynamic mime content support is not enabled"); 147 "dynamic mime content support is not enabled");
152 /* NOTREACHED */ 148 /* NOTREACHED */
153#else 149#else
154 /* make sure there's four arguments */ 150 /* make sure there's four arguments */
155 if (argc - optind < 3) 151 if (argc - optind < 3)
156 usage(&httpd, progname); 152 usage(&httpd, progname);
157 bozo_add_content_map_mime(&httpd, optarg, argv[optind], 153 bozo_add_content_map_mime(&httpd, optarg, argv[optind],
158 argv[optind+1], argv[optind+2]); 154 argv[optind+1], argv[optind+2]);
159 optind += 3; 155 optind += 3;
160 break; 156 break;
161#endif /* NO_DYNAMIC_CONTENT */ 157#endif /* NO_DYNAMIC_CONTENT */
162 158
163 case 'n': 159 case 'n':
164 bozo_set_pref(&prefs, "numeric", "true"); 160 bozo_set_pref(&prefs, "numeric", "true");
165 break; 161 break;
166 162
167 case 'r': 163 case 'r':
168 bozo_set_pref(&prefs, "trusted referal", "true"); 164 bozo_set_pref(&prefs, "trusted referal", "true");
169 break; 165 break;
170 166
171 case 's': 167 case 's':
172 bozo_set_pref(&prefs, "log to stderr", "true"); 168 bozo_set_pref(&prefs, "log to stderr", "true");
173 break; 169 break;
174 170
175 case 'S': 171 case 'S':
176 bozo_set_pref(&prefs, "server software", optarg); 172 bozo_set_pref(&prefs, "server software", optarg);
177 break; 173 break;
178 case 'Z': 174 case 'Z':
179#ifdef NO_SSL_SUPPORT 175#ifdef NO_SSL_SUPPORT
180 bozo_err(&httpd, 1, "ssl support is not enabled"); 176 bozo_err(&httpd, 1, "ssl support is not enabled");
181 /* NOT REACHED */ 177 /* NOT REACHED */
182#else 178#else
183 /* make sure there's two arguments */ 179 /* make sure there's two arguments */
184 if (argc - optind < 1) 180 if (argc - optind < 1)
185 usage(&httpd, progname); 181 usage(&httpd, progname);
186 bozo_ssl_set_opts(&httpd, optarg, argv[optind++]); 182 bozo_ssl_set_opts(&httpd, optarg, argv[optind++]);
187 break; 183 break;
188#endif /* NO_SSL_SUPPORT */ 184#endif /* NO_SSL_SUPPORT */
189 case 'U': 185 case 'U':
190 bozo_set_pref(&prefs, "username", optarg); 186 bozo_set_pref(&prefs, "username", optarg);
191 break; 187 break;
192 188
193 case 'V': 189 case 'V':
194 bozo_set_pref(&prefs, "unknown slash", "true"); 190 bozo_set_pref(&prefs, "unknown slash", "true");
195 break; 191 break;
196 192
197 case 'v': 193 case 'v':
198 bozo_set_pref(&prefs, "virtual base", optarg); 194 bozo_set_pref(&prefs, "virtual base", optarg);
199 break; 195 break;
200 196
201 case 'x': 197 case 'x':
202 bozo_set_pref(&prefs, "index.html", optarg); 198 bozo_set_pref(&prefs, "index.html", optarg);
203 break; 199 break;
204 200
205#ifdef NO_DAEMON_MODE 201#ifdef NO_DAEMON_MODE
206 case 'b': 202 case 'b':
207 case 'e': 203 case 'e':
208 case 'f': 204 case 'f':
209 case 'i': 205 case 'i':
210 case 'I': 206 case 'I':
211 case 'P': 207 case 'P':
212 bozo_err(&httpd, 1, "Daemon mode is not enabled"); 208 bozo_err(&httpd, 1, "Daemon mode is not enabled");
213 /* NOTREACHED */ 209 /* NOTREACHED */
214#else 210#else
215 case 'b': 211 case 'b':
216 /* 212 /*
217 * test suite support - undocumented 213 * test suite support - undocumented
218 * background == 2 (aka, -b -b) means to 214 * background == 2 (aka, -b -b) means to
219 * only process 1 per kid 215 * only process 1 per kid
220 */ 216 */
221 if (bozo_get_pref(&prefs, "background") == NULL) { 217 if (bozo_get_pref(&prefs, "background") == NULL) {
222 bozo_set_pref(&prefs, "background", "1"); 218 bozo_set_pref(&prefs, "background", "1");
223 } else { 219 } else {
224 bozo_set_pref(&prefs, "background", "2"); 220 bozo_set_pref(&prefs, "background", "2");
225 } 221 }
226 break; 222 break;
227 223
228 case 'e': 224 case 'e':
229 bozo_set_pref(&prefs, "dirty environment", "true"); 225 bozo_set_pref(&prefs, "dirty environment", "true");
230 break; 226 break;
231 227
232 case 'f': 228 case 'f':
233 bozo_set_pref(&prefs, "foreground", "true"); 229 bozo_set_pref(&prefs, "foreground", "true");
234 break; 230 break;
235 231
236 case 'i': 232 case 'i':
237 bozo_set_pref(&prefs, "bind address", optarg); 233 bozo_set_pref(&prefs, "bind address", optarg);
238 break; 234 break;
239 235
240 case 'I': 236 case 'I':
241 bozo_set_pref(&prefs, "port number", optarg); 237 bozo_set_pref(&prefs, "port number", optarg);
242 break; 238 break;
243 case 'P': 239 case 'P':
244 bozo_set_pref(&prefs, "pid file", optarg); 240 bozo_set_pref(&prefs, "pid file", optarg);
245 break; 241 break;
246#endif /* NO_DAEMON_MODE */ 242#endif /* NO_DAEMON_MODE */
247 243
248#ifdef NO_CGIBIN_SUPPORT 244#ifdef NO_CGIBIN_SUPPORT
249 case 'c': 245 case 'c':
250 case 'C': 246 case 'C':
251 bozo_err(&httpd, 1, "CGI is not enabled"); 247 bozo_err(&httpd, 1, "CGI is not enabled");
252 /* NOTREACHED */ 248 /* NOTREACHED */
253#else 249#else
254 case 'c': 250 case 'c':
255 bozo_cgi_setbin(&httpd, optarg); 251 bozo_cgi_setbin(&httpd, optarg);
256 break; 252 break;
257 253
258 case 'C': 254 case 'C':
259# ifdef NO_DYNAMIC_CONTENT 255# ifdef NO_DYNAMIC_CONTENT
260 bozo_err(&httpd, 1, 256 bozo_err(&httpd, 1,
261 "dynamic CGI handler support is not enabled"); 257 "dynamic CGI handler support is not enabled");
262 /* NOTREACHED */ 258 /* NOTREACHED */
263# else 259# else
264 /* make sure there's two arguments */ 260 /* make sure there's two arguments */
265 if (argc - optind < 1) 261 if (argc - optind < 1)
266 usage(&httpd, progname); 262 usage(&httpd, progname);
267 bozo_add_content_map_cgi(&httpd, optarg, 263 bozo_add_content_map_cgi(&httpd, optarg,
268 argv[optind++]); 264 argv[optind++]);
269 break; 265 break;
270# endif /* NO_DYNAMIC_CONTENT */ 266# endif /* NO_DYNAMIC_CONTENT */
271#endif /* NO_CGIBIN_SUPPORT */ 267#endif /* NO_CGIBIN_SUPPORT */
272 268
273 case 'd': 269 case 'd':
274 httpd.debug++; 270 httpd.debug++;
275#ifdef NO_DEBUG 271#ifdef NO_DEBUG
276 if (httpd.debug == 1) 272 if (httpd.debug == 1)
277 bozo_warn(&httpd, "Debugging is not enabled"); 273 bozo_warn(&httpd, "Debugging is not enabled");
278#endif /* NO_DEBUG */ 274#endif /* NO_DEBUG */
279 break; 275 break;
280 276
281#ifdef NO_USER_SUPPORT 277#ifdef NO_USER_SUPPORT
282 case 'p': 278 case 'p':
283 case 't': 279 case 't':
284 case 'u': 280 case 'u':
285 bozo_err(&httpd, 1, "User support is not enabled"); 281 bozo_err(&httpd, 1, "User support is not enabled");
286 /* NOTREACHED */ 282 /* NOTREACHED */
287#else 283#else
288 case 'p': 284 case 'p':
289 bozo_set_pref(&prefs, "public_html", optarg); 285 bozo_set_pref(&prefs, "public_html", optarg);
290 break; 286 break;
291 287
292 case 't': 288 case 't':
293 bozo_set_pref(&prefs, "chroot dir", optarg); 289 bozo_set_pref(&prefs, "chroot dir", optarg);
294 break; 290 break;
295 291
296 case 'u': 292 case 'u':
297 bozo_set_pref(&prefs, "enable users", "true"); 293 bozo_set_pref(&prefs, "enable users", "true");
298 break; 294 break;
299#endif /* NO_USER_SUPPORT */ 295#endif /* NO_USER_SUPPORT */
300 296
301#ifdef NO_DIRINDEX_SUPPORT 297#ifdef NO_DIRINDEX_SUPPORT
302 case 'H': 298 case 'H':
303 case 'X': 299 case 'X':
304 bozo_err(&httpd, 1, 300 bozo_err(&httpd, 1,
305 "directory indexing is not enabled"); 301 "directory indexing is not enabled");
306 /* NOTREACHED */ 302 /* NOTREACHED */
307#else 303#else
308 case 'H': 304 case 'H':
309 bozo_set_pref(&prefs, "hide dots", "true"); 305 bozo_set_pref(&prefs, "hide dots", "true");
310 break; 306 break;
311 307
312 case 'X': 308 case 'X':
313 bozo_set_pref(&prefs, "directory indexing", "true"); 309 bozo_set_pref(&prefs, "directory indexing", "true");
314 break; 310 break;
315 311
316#endif /* NO_DIRINDEX_SUPPORT */ 312#endif /* NO_DIRINDEX_SUPPORT */
317 313
318 default: 314 default:
319 usage(&httpd, progname); 315 usage(&httpd, progname);
320 /* NOTREACHED */ 316 /* NOTREACHED */
321 } 317 }
322 } 318 }
323 319
324 argc -= optind; 320 argc -= optind;
325 argv += optind; 321 argv += optind;
326 322
327 if (argc == 0 || argc > 2) { 323 if (argc == 0 || argc > 2) {
328 usage(&httpd, progname); 324 usage(&httpd, progname);
329 } 325 }
330 326
331 /* virtual host, and root of tree to serve */ 327 /* virtual host, and root of tree to serve */
332 bozo_setup(&httpd, &prefs, argv[1], argv[0]); 328 bozo_setup(&httpd, &prefs, argv[1], argv[0]);
333 329
334 /* 330 /*
335 * read and process the HTTP request. 331 * read and process the HTTP request.
336 */ 332 */
337 do { 333 do {
338 if ((request = bozo_read_request(&httpd)) != NULL) { 334 if ((request = bozo_read_request(&httpd)) != NULL) {
339 bozo_process_request(request); 335 bozo_process_request(request);
340 bozo_clean_request(request); 336 bozo_clean_request(request);
341 } 337 }
342 } while (httpd.background); 338 } while (httpd.background);
343 339
344 return (0); 340 return (0);
345} 341}

cvs diff -r1.11 -r1.12 src/libexec/httpd/ssl-bozo.c (switch to unified diff)

--- src/libexec/httpd/ssl-bozo.c 2011/08/21 10:45:33 1.11
+++ src/libexec/httpd/ssl-bozo.c 2011/08/27 15:33:59 1.12
@@ -1,295 +1,295 @@ @@ -1,295 +1,295 @@
1/* $NetBSD: ssl-bozo.c,v 1.11 2011/08/21 10:45:33 hannken Exp $ */ 1/* $NetBSD: ssl-bozo.c,v 1.12 2011/08/27 15:33:59 joerg Exp $ */
2 2
3/* $eterna: ssl-bozo.c,v 1.13 2010/05/12 12:24:58 rtr Exp $ */ 3/* $eterna: ssl-bozo.c,v 1.13 2010/05/12 12:24:58 rtr Exp $ */
4 4
5/* 5/*
6 * Copyright (c) 1997-2010 Matthew R. Green 6 * Copyright (c) 1997-2010 Matthew R. Green
7 * All rights reserved. 7 * All rights reserved.
8 * 8 *
9 * Redistribution and use in source and binary forms, with or without 9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions 10 * modification, are permitted provided that the following conditions
11 * are met: 11 * are met:
12 * 1. Redistributions of source code must retain the above copyright 12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer. 13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright 14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer and 15 * notice, this list of conditions and the following disclaimer and
16 * dedication in the documentation and/or other materials provided 16 * dedication in the documentation and/or other materials provided
17 * with the distribution. 17 * with the distribution.
18 * 18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 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 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 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 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE. 29 * SUCH DAMAGE.
30 * 30 *
31 */ 31 */
32 32
33/* this code implements SSL for bozohttpd */ 33/* this code implements SSL for bozohttpd */
34 34
35#include <stdarg.h> 35#include <stdarg.h>
36#include <stdio.h> 36#include <stdio.h>
37#include <syslog.h> 37#include <syslog.h>
38#include <unistd.h> 38#include <unistd.h>
39 39
40#include "bozohttpd.h" 40#include "bozohttpd.h"
41 41
42#ifndef NO_SSL_SUPPORT 42#ifndef NO_SSL_SUPPORT
43 43
44#include <openssl/ssl.h> 44#include <openssl/ssl.h>
45#include <openssl/err.h> 45#include <openssl/err.h>
46 46
47#ifndef USE_ARG 47#ifndef USE_ARG
48#define USE_ARG(x) /*LINTED*/(void)&(x) 48#define USE_ARG(x) /*LINTED*/(void)&(x)
49#endif 49#endif
50 50
51/* this structure encapsulates the ssl info */ 51/* this structure encapsulates the ssl info */
52typedef struct sslinfo_t { 52typedef struct sslinfo_t {
53 SSL_CTX *ssl_context; 53 SSL_CTX *ssl_context;
54 const SSL_METHOD *ssl_method; 54 const SSL_METHOD *ssl_method;
55 SSL *bozossl; 55 SSL *bozossl;
56 char *certificate_file; 56 char *certificate_file;
57 char *privatekey_file; 57 char *privatekey_file;
58} sslinfo_t; 58} sslinfo_t;
59 59
60/* 60/*
61 * bozo_ssl_err 61 * bozo_ssl_err
62 * 62 *
63 * bozo_ssl_err works just like bozo_err except in addition to printing 63 * bozo_ssl_err works just like bozo_err except in addition to printing
64 * the error provided by the caller at the point of error it pops and 64 * the error provided by the caller at the point of error it pops and
65 * prints all errors from the SSL error queue. 65 * prints all errors from the SSL error queue.
66 */ 66 */
67static void 67BOZO_DEAD static void
68bozo_ssl_err(bozohttpd_t *httpd, int code, const char *fmt, ...) 68bozo_ssl_err(bozohttpd_t *httpd, int code, const char *fmt, ...)
69{ 69{
70 va_list ap; 70 va_list ap;
71 71
72 va_start(ap, fmt); 72 va_start(ap, fmt);
73 if (httpd->logstderr || isatty(STDERR_FILENO)) { 73 if (httpd->logstderr || isatty(STDERR_FILENO)) {
74 vfprintf(stderr, fmt, ap); 74 vfprintf(stderr, fmt, ap);
75 fputs("\n", stderr); 75 fputs("\n", stderr);
76 } else 76 } else
77 vsyslog(LOG_ERR, fmt, ap); 77 vsyslog(LOG_ERR, fmt, ap);
78 va_end(ap); 78 va_end(ap);
79 79
80 unsigned int sslcode = ERR_get_error(); 80 unsigned int sslcode = ERR_get_error();
81 do { 81 do {
82 static const char sslfmt[] = "SSL Error: %s:%s:%s"; 82 static const char sslfmt[] = "SSL Error: %s:%s:%s";
83 83
84 if (httpd->logstderr || isatty(STDERR_FILENO)) { 84 if (httpd->logstderr || isatty(STDERR_FILENO)) {
85 fprintf(stderr, sslfmt, 85 fprintf(stderr, sslfmt,
86 ERR_lib_error_string(sslcode), 86 ERR_lib_error_string(sslcode),
87 ERR_func_error_string(sslcode), 87 ERR_func_error_string(sslcode),
88 ERR_reason_error_string(sslcode)); 88 ERR_reason_error_string(sslcode));
89 } else { 89 } else {
90 syslog(LOG_ERR, sslfmt, 90 syslog(LOG_ERR, sslfmt,
91 ERR_lib_error_string(sslcode), 91 ERR_lib_error_string(sslcode),
92 ERR_func_error_string(sslcode), 92 ERR_func_error_string(sslcode),
93 ERR_reason_error_string(sslcode)); 93 ERR_reason_error_string(sslcode));
94 } 94 }
95 } while (0 != (sslcode = ERR_get_error())); 95 } while (0 != (sslcode = ERR_get_error()));
96 exit(code); 96 exit(code);
97} 97}
98 98
99static int 99static int
100bozo_ssl_printf(bozohttpd_t *httpd, const char * fmt, va_list ap) 100bozo_ssl_printf(bozohttpd_t *httpd, const char * fmt, va_list ap)
101{ 101{
102 sslinfo_t *sslinfo; 102 sslinfo_t *sslinfo;
103 char *buf; 103 char *buf;
104 int nbytes; 104 int nbytes;
105 105
106 sslinfo = httpd->sslinfo; 106 sslinfo = httpd->sslinfo;
107 /* XXX we need more elegant/proper handling of SSL_write return */ 107 /* XXX we need more elegant/proper handling of SSL_write return */
108 if ((nbytes = vasprintf(&buf, fmt, ap)) != -1)  108 if ((nbytes = vasprintf(&buf, fmt, ap)) != -1)
109 SSL_write(sslinfo->bozossl, buf, nbytes); 109 SSL_write(sslinfo->bozossl, buf, nbytes);
110 110
111 free(buf); 111 free(buf);
112 112
113 return nbytes; 113 return nbytes;
114} 114}
115 115
116static ssize_t 116static ssize_t
117bozo_ssl_read(bozohttpd_t *httpd, int fd, void *buf, size_t nbytes) 117bozo_ssl_read(bozohttpd_t *httpd, int fd, void *buf, size_t nbytes)
118{ 118{
119 sslinfo_t *sslinfo; 119 sslinfo_t *sslinfo;
120 ssize_t rbytes; 120 ssize_t rbytes;
121 121
122 USE_ARG(fd); 122 USE_ARG(fd);
123 sslinfo = httpd->sslinfo; 123 sslinfo = httpd->sslinfo;
124 /* XXX we need elegant/proper handling of SSL_read return */ 124 /* XXX we need elegant/proper handling of SSL_read return */
125 rbytes = (ssize_t)SSL_read(sslinfo->bozossl, buf, (int)nbytes); 125 rbytes = (ssize_t)SSL_read(sslinfo->bozossl, buf, (int)nbytes);
126 if (rbytes < 1) { 126 if (rbytes < 1) {
127 if (SSL_get_error(sslinfo->bozossl, rbytes) == 127 if (SSL_get_error(sslinfo->bozossl, rbytes) ==
128 SSL_ERROR_WANT_READ) 128 SSL_ERROR_WANT_READ)
129 bozo_warn(httpd, "SSL_ERROR_WANT_READ"); 129 bozo_warn(httpd, "SSL_ERROR_WANT_READ");
130 else 130 else
131 bozo_warn(httpd, "SSL_ERROR OTHER"); 131 bozo_warn(httpd, "SSL_ERROR OTHER");
132 } 132 }
133 133
134 return rbytes; 134 return rbytes;
135} 135}
136 136
137static ssize_t 137static ssize_t
138bozo_ssl_write(bozohttpd_t *httpd, int fd, const void *buf, size_t nbytes) 138bozo_ssl_write(bozohttpd_t *httpd, int fd, const void *buf, size_t nbytes)
139{ 139{
140 sslinfo_t *sslinfo; 140 sslinfo_t *sslinfo;
141 ssize_t wbytes; 141 ssize_t wbytes;
142 142
143 USE_ARG(fd); 143 USE_ARG(fd);
144 sslinfo = httpd->sslinfo; 144 sslinfo = httpd->sslinfo;
145 /* XXX we need elegant/proper handling of SSL_write return */ 145 /* XXX we need elegant/proper handling of SSL_write return */
146 wbytes = (ssize_t)SSL_write(sslinfo->bozossl, buf, (int)nbytes); 146 wbytes = (ssize_t)SSL_write(sslinfo->bozossl, buf, (int)nbytes);
147 147
148 return wbytes; 148 return wbytes;
149} 149}
150 150
151static int 151static int
152bozo_ssl_flush(bozohttpd_t *httpd, FILE *fp) 152bozo_ssl_flush(bozohttpd_t *httpd, FILE *fp)
153{ 153{
154 USE_ARG(httpd); 154 USE_ARG(httpd);
155 USE_ARG(fp); 155 USE_ARG(fp);
156 /* nothing to see here, move right along */ 156 /* nothing to see here, move right along */
157 return 0; 157 return 0;
158} 158}
159 159
160void 160void
161bozo_ssl_init(bozohttpd_t *httpd) 161bozo_ssl_init(bozohttpd_t *httpd)
162{ 162{
163 sslinfo_t *sslinfo; 163 sslinfo_t *sslinfo;
164 164
165 sslinfo = httpd->sslinfo; 165 sslinfo = httpd->sslinfo;
166 if (sslinfo == NULL || !sslinfo->certificate_file) 166 if (sslinfo == NULL || !sslinfo->certificate_file)
167 return; 167 return;
168 SSL_library_init(); 168 SSL_library_init();
169 SSL_load_error_strings(); 169 SSL_load_error_strings();
170 170
171 sslinfo->ssl_method = SSLv23_server_method(); 171 sslinfo->ssl_method = SSLv23_server_method();
172 sslinfo->ssl_context = SSL_CTX_new(sslinfo->ssl_method); 172 sslinfo->ssl_context = SSL_CTX_new(sslinfo->ssl_method);
173 173
174 /* XXX we need to learn how to check the SSL stack for more info */ 174 /* XXX we need to learn how to check the SSL stack for more info */
175 if (NULL == sslinfo->ssl_context) 175 if (NULL == sslinfo->ssl_context)
176 bozo_ssl_err(httpd, EXIT_FAILURE, 176 bozo_ssl_err(httpd, EXIT_FAILURE,
177 "SSL context creation failed"); 177 "SSL context creation failed");
178 178
179 if (1 != SSL_CTX_use_certificate_file(sslinfo->ssl_context, 179 if (1 != SSL_CTX_use_certificate_file(sslinfo->ssl_context,
180 sslinfo->certificate_file, SSL_FILETYPE_PEM)) 180 sslinfo->certificate_file, SSL_FILETYPE_PEM))
181 bozo_ssl_err(httpd, EXIT_FAILURE, 181 bozo_ssl_err(httpd, EXIT_FAILURE,
182 "Unable to use certificate file '%s'", 182 "Unable to use certificate file '%s'",
183 sslinfo->certificate_file); 183 sslinfo->certificate_file);
184 184
185 if (1 != SSL_CTX_use_PrivateKey_file(sslinfo->ssl_context, 185 if (1 != SSL_CTX_use_PrivateKey_file(sslinfo->ssl_context,
186 sslinfo->privatekey_file, SSL_FILETYPE_PEM)) 186 sslinfo->privatekey_file, SSL_FILETYPE_PEM))
187 bozo_ssl_err(httpd, EXIT_FAILURE, 187 bozo_ssl_err(httpd, EXIT_FAILURE,
188 "Unable to use private key file '%s'", 188 "Unable to use private key file '%s'",
189 sslinfo->privatekey_file); 189 sslinfo->privatekey_file);
190 190
191 /* check consistency of key vs certificate */ 191 /* check consistency of key vs certificate */
192 if (!SSL_CTX_check_private_key(sslinfo->ssl_context)) 192 if (!SSL_CTX_check_private_key(sslinfo->ssl_context))
193 bozo_ssl_err(httpd, EXIT_FAILURE, 193 bozo_ssl_err(httpd, EXIT_FAILURE,
194 "Check private key failed"); 194 "Check private key failed");
195} 195}
196 196
197void 197void
198bozo_ssl_accept(bozohttpd_t *httpd) 198bozo_ssl_accept(bozohttpd_t *httpd)
199{ 199{
200 sslinfo_t *sslinfo; 200 sslinfo_t *sslinfo;
201 201
202 sslinfo = httpd->sslinfo; 202 sslinfo = httpd->sslinfo;
203 if (sslinfo != NULL && sslinfo->ssl_context) { 203 if (sslinfo != NULL && sslinfo->ssl_context) {
204 sslinfo->bozossl = SSL_new(sslinfo->ssl_context); 204 sslinfo->bozossl = SSL_new(sslinfo->ssl_context);
205 SSL_set_rfd(sslinfo->bozossl, 0); 205 SSL_set_rfd(sslinfo->bozossl, 0);
206 SSL_set_wfd(sslinfo->bozossl, 1); 206 SSL_set_wfd(sslinfo->bozossl, 1);
207 SSL_accept(sslinfo->bozossl); 207 SSL_accept(sslinfo->bozossl);
208 } 208 }
209} 209}
210 210
211void 211void
212bozo_ssl_destroy(bozohttpd_t *httpd) 212bozo_ssl_destroy(bozohttpd_t *httpd)
213{ 213{
214 sslinfo_t *sslinfo; 214 sslinfo_t *sslinfo;
215 215
216 sslinfo = httpd->sslinfo; 216 sslinfo = httpd->sslinfo;
217 if (sslinfo && sslinfo->bozossl) 217 if (sslinfo && sslinfo->bozossl)
218 SSL_free(sslinfo->bozossl); 218 SSL_free(sslinfo->bozossl);
219} 219}
220 220
221void 221void
222bozo_ssl_set_opts(bozohttpd_t *httpd, const char *cert, const char *priv) 222bozo_ssl_set_opts(bozohttpd_t *httpd, const char *cert, const char *priv)
223{ 223{
224 sslinfo_t *sslinfo; 224 sslinfo_t *sslinfo;
225 225
226 if ((sslinfo = httpd->sslinfo) == NULL) { 226 if ((sslinfo = httpd->sslinfo) == NULL) {
227 sslinfo = bozomalloc(httpd, sizeof(*sslinfo)); 227 sslinfo = bozomalloc(httpd, sizeof(*sslinfo));
228 if (sslinfo == NULL) { 228 if (sslinfo == NULL) {
229 bozo_err(httpd, 1, "sslinfo allocation failed"); 229 bozo_err(httpd, 1, "sslinfo allocation failed");
230 } 230 }
231 httpd->sslinfo = sslinfo; 231 httpd->sslinfo = sslinfo;
232 } 232 }
233 sslinfo->certificate_file = strdup(cert); 233 sslinfo->certificate_file = strdup(cert);
234 sslinfo->privatekey_file = strdup(priv); 234 sslinfo->privatekey_file = strdup(priv);
235 debug((httpd, DEBUG_NORMAL, "using cert/priv files: %s & %s", 235 debug((httpd, DEBUG_NORMAL, "using cert/priv files: %s & %s",
236 sslinfo->certificate_file, 236 sslinfo->certificate_file,
237 sslinfo->privatekey_file)); 237 sslinfo->privatekey_file));
238 if (!httpd->bindport) { 238 if (!httpd->bindport) {
239 httpd->bindport = strdup("https"); 239 httpd->bindport = strdup("https");
240 } 240 }
241} 241}
242 242
243#endif /* NO_SSL_SUPPORT */ 243#endif /* NO_SSL_SUPPORT */
244 244
245int 245int
246bozo_printf(bozohttpd_t *httpd, const char *fmt, ...) 246bozo_printf(bozohttpd_t *httpd, const char *fmt, ...)
247{ 247{
248 va_list args; 248 va_list args;
249 int cc; 249 int cc;
250 250
251 va_start(args, fmt); 251 va_start(args, fmt);
252#ifndef NO_SSL_SUPPORT 252#ifndef NO_SSL_SUPPORT
253 if (httpd->sslinfo) { 253 if (httpd->sslinfo) {
254 cc = bozo_ssl_printf(httpd, fmt, args); 254 cc = bozo_ssl_printf(httpd, fmt, args);
255 va_end(args); 255 va_end(args);
256 return cc; 256 return cc;
257 } 257 }
258#endif 258#endif
259 cc = vprintf(fmt, args); 259 cc = vprintf(fmt, args);
260 va_end(args); 260 va_end(args);
261 return cc; 261 return cc;
262} 262}
263 263
264ssize_t 264ssize_t
265bozo_read(bozohttpd_t *httpd, int fd, void *buf, size_t len) 265bozo_read(bozohttpd_t *httpd, int fd, void *buf, size_t len)
266{ 266{
267#ifndef NO_SSL_SUPPORT 267#ifndef NO_SSL_SUPPORT
268 if (httpd->sslinfo) { 268 if (httpd->sslinfo) {
269 return bozo_ssl_read(httpd, fd, buf, len); 269 return bozo_ssl_read(httpd, fd, buf, len);
270 } 270 }
271#endif 271#endif
272 return read(fd, buf, len); 272 return read(fd, buf, len);
273} 273}
274 274
275ssize_t 275ssize_t
276bozo_write(bozohttpd_t *httpd, int fd, const void *buf, size_t len) 276bozo_write(bozohttpd_t *httpd, int fd, const void *buf, size_t len)
277{ 277{
278#ifndef NO_SSL_SUPPORT 278#ifndef NO_SSL_SUPPORT
279 if (httpd->sslinfo) { 279 if (httpd->sslinfo) {
280 return bozo_ssl_write(httpd, fd, buf, len); 280 return bozo_ssl_write(httpd, fd, buf, len);
281 } 281 }
282#endif 282#endif
283 return write(fd, buf, len); 283 return write(fd, buf, len);
284} 284}
285 285
286int 286int
287bozo_flush(bozohttpd_t *httpd, FILE *fp) 287bozo_flush(bozohttpd_t *httpd, FILE *fp)
288{ 288{
289#ifndef NO_SSL_SUPPORT 289#ifndef NO_SSL_SUPPORT
290 if (httpd->sslinfo) { 290 if (httpd->sslinfo) {
291 return bozo_ssl_flush(httpd, fp); 291 return bozo_ssl_flush(httpd, fp);
292 } 292 }
293#endif 293#endif
294 return fflush(fp); 294 return fflush(fp);
295} 295}