/[hydra]/hydra/src/alias.c
ViewVC logotype

Contents of /hydra/src/alias.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.6 - (show annotations)
Wed Sep 25 20:39:04 2002 UTC (21 years, 6 months ago) by nmav
Branch: MAIN
CVS Tags: hydra_0_0_2
Changes since 1.5: +2 -2 lines
File MIME type: text/plain
Cleanups

1 /*
2 * Boa, an http server
3 * Copyright (C) 1995 Paul Phillips <paulp@go2net.com>
4 * Some changes Copyright (C) 1996 Larry Doolittle <ldoolitt@boa.org>
5 * Some changes Copyright (C) 1996 Russ Nelson <nelson@crynwr.com>
6 * Some changes Copyright (C) 1996-2002 Jon Nelson <jnelson@boa.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 1, or (at your option)
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 */
23
24 /* $Id: alias.c,v 1.5 2002/09/25 06:42:34 nmav Exp $ */
25
26 #include "boa.h"
27
28 int get_alias_hash_value(char *file);
29
30 /*
31 * Name: get_alias_hash_value
32 *
33 * Description: adds the ASCII values of the file letters
34 * and mods by the hashtable size to get the hash value
35 * Note: stops at first '/' (or '\0')
36 */
37
38 int get_alias_hash_value(char *file)
39 {
40 unsigned int hash = 0;
41 unsigned int index = 0;
42 unsigned char c;
43
44 hash = file[index++];
45 while ((c = file[index++]) && c != '/')
46 hash += (unsigned int) c;
47
48 return hash % ALIAS_HASHTABLE_SIZE;
49 }
50
51 /*
52 * Name: add_alias
53 *
54 * Description: add an Alias, Redirect, or ScriptAlias to the
55 * alias hash table.
56 */
57
58 void add_alias(char* hostname, char *fakename, char *realname, int type)
59 {
60 int hash;
61 alias *old, *new;
62 int fakelen, reallen, hostlen;
63 virthost* vhost;
64
65 /* sanity checking */
66 if (hostname == NULL || fakename == NULL || realname == NULL) {
67 DIE("NULL values sent to add_alias");
68 }
69
70 hostlen = strlen(hostname);
71
72 vhost = find_virthost( hostname, hostlen);
73 if (vhost == NULL) {
74 log_error_time();
75 fprintf(stderr, "Tried to add Alias for host %s, which does not exist.\n", hostname);
76 exit(1);
77 }
78
79 fakelen = strlen(fakename);
80 reallen = strlen(realname);
81 if (fakelen == 0 || reallen == 0) {
82 DIE("empty values sent to add_alias");
83 }
84
85 hash = get_alias_hash_value(fakename);
86
87 old = vhost->alias_hashtable[hash];
88
89 if (old) {
90 while (old->next) {
91 if (!strcmp(fakename, old->fakename)) /* don't add twice */
92 return;
93 old = old->next;
94 }
95 }
96
97 new = (alias *) malloc(sizeof (alias));
98 if (!new) {
99 DIE("out of memory adding alias to hash");
100 }
101
102 if (old)
103 old->next = new;
104 else
105 vhost->alias_hashtable[hash] = new;
106
107 new->fakename = strdup(fakename);
108 if (!new->fakename) {
109 DIE("failed strdup");
110 }
111 new->fake_len = fakelen;
112 /* check for "here" */
113 if (realname[0] == '.' && realname[1] == '/') {
114 new->realname = normalize_path(realname+2);
115 if (!new->realname) {
116 /* superfluous - normalize_path checks for NULL return values. */
117 DIE("normalize_path returned NULL");
118 }
119 reallen = strlen(new->realname);
120 } else {
121 new->realname = strdup(realname);
122 if (!new->realname) {
123 DIE("strdup of realname failed");
124 }
125 }
126 new->real_len = reallen;
127
128 new->type = type;
129 new->next = NULL;
130 }
131
132 /*
133 * Name: find_alias
134 *
135 * Description: Locates uri in the alias hashtable if it exists.
136 *
137 * Returns:
138 *
139 * alias structure or NULL if not found
140 */
141
142 alias *find_alias(char* hostname, char *uri, int urilen)
143 {
144 alias *current;
145 int hash;
146 virthost* vhost;
147
148 /* Find ScriptAlias, Alias, or Redirect */
149
150 vhost = find_virthost( hostname, 0);
151 if (vhost == NULL) {
152 return NULL;
153 }
154
155 if (urilen == 0)
156 urilen = strlen(uri);
157 hash = get_alias_hash_value(uri);
158
159 current = vhost->alias_hashtable[hash];
160 while (current) {
161 #ifdef FASCIST_LOGGING
162 fprintf(stderr,
163 "%s:%d - comparing \"%s\" (request) to \"%s\" (alias): ",
164 __FILE__, __LINE__, uri, current->fakename);
165 #endif
166 /* current->fake_len must always be:
167 * shorter or equal to the uri
168 */
169 /*
170 * when performing matches:
171 * If the virtual part of the url ends in '/', and
172 * we get a match, stop there.
173 * Otherwise, we require '/' or '\0' at the end of the url.
174 * We only check if the virtual path does *not* end in '/'
175 */
176 if (current->fake_len <= urilen &&
177 !memcmp(uri, current->fakename, current->fake_len) &&
178 (current->fakename[current->fake_len - 1] == '/' ||
179 (current->fakename[current->fake_len - 1] != '/' &&
180 (uri[current->fake_len] == '\0' ||
181 uri[current->fake_len] == '/')))) {
182 #ifdef FASCIST_LOGGING
183 fprintf(stderr, "Got it!\n");
184 #endif
185 return current;
186 }
187 #ifdef FASCIST_LOGGING
188 else
189 fprintf(stderr, "Don't Got it!\n");
190 #endif
191 current = current->next;
192 }
193 return current;
194 }
195
196 /*
197 * Name: translate_uri
198 *
199 * Description: Parse a request's virtual path.
200 * Sets query_string, pathname directly.
201 * Also sets path_info, path_translated, and script_name via
202 * init_script_alias
203 *
204 * Note: NPH in user dir is currently broken
205 *
206 * Note -- this should be broken up.
207 *
208 * Return values:
209 * 0: failure, close it down
210 * 1: success, continue
211 */
212
213 int translate_uri(request * req)
214 {
215 char buffer[MAX_HEADER_LENGTH + 1];
216 char *req_urip;
217 alias *current;
218 char *p;
219 int uri_len;
220
221 req_urip = req->request_uri;
222 if (req_urip[0] != '/') {
223 send_r_bad_request(req);
224 return 0;
225 }
226
227 uri_len = strlen(req->request_uri);
228
229 current = find_alias( req->hostname, req->request_uri, uri_len);
230 if (current) {
231
232 if (current->type == SCRIPTALIAS) /* Script */
233 return init_script_alias(req, current, uri_len);
234
235 /* not a script alias, therefore begin filling in data */
236
237 {
238 int len;
239 len = current->real_len;
240 len += uri_len - current->fake_len;
241 if (len > MAX_HEADER_LENGTH) {
242 log_error_doc(req);
243 fputs("uri too long!\n", stderr);
244 send_r_bad_request(req);
245 return 0;
246 }
247 memcpy(buffer, current->realname, current->real_len);
248 memcpy(buffer + current->real_len,
249 req->request_uri + current->fake_len,
250 uri_len - current->fake_len + 1);
251 }
252
253 if (current->type == REDIRECT) { /* Redirect */
254 if (req->method == M_POST) { /* POST to non-script */
255 /* it's not a cgi, but we try to POST??? */
256 send_r_bad_request(req);
257 return 0; /* not a script alias, therefore begin filling in data */
258 }
259 send_r_moved_temp(req, buffer, "");
260 return 0;
261 } else { /* Alias */
262 req->pathname = strdup(buffer);
263 if (!req->pathname) {
264 send_r_error(req);
265 WARN("unable to strdup buffer onto req->pathname");
266 return 0;
267 }
268 return 1;
269 }
270 }
271
272 /*
273 The reason why this is *not* an 'else if' is that,
274 after aliasing, we still have to check for '~' expansion
275 */
276
277 if (req->user_dir[0]!=0 && req->request_uri[1] == '~') {
278 char *user_homedir;
279
280 req_urip = req->request_uri + 2;
281
282 /* since we have uri_len which is from strlen(req->request_uri) */
283 p = memchr(req_urip, '/', uri_len - 2);
284 if (p)
285 *p = '\0';
286
287 user_homedir = get_home_dir(req_urip);
288 if (p) /* have to restore request_uri in case of error */
289 *p = '/';
290
291 if (!user_homedir) { /*no such user */
292 send_r_not_found(req);
293 return 0;
294 }
295 {
296 int l1 = strlen(user_homedir);
297 int l2 = strlen(req->user_dir);
298 int l3 = (p ? strlen(p) : 0);
299
300 if (l1 + l2 + l3 + 1 > MAX_HEADER_LENGTH) {
301 log_error_doc(req);
302 fputs("uri too long!\n", stderr);
303 send_r_bad_request(req);
304 return 0;
305 }
306
307 memcpy(buffer, user_homedir, l1);
308 buffer[l1] = '/';
309 memcpy(buffer + l1 + 1, req->user_dir, l2 + 1);
310 if (p)
311 memcpy(buffer + l1 + 1 + l2, p, l3 + 1);
312 }
313 } else if (req->document_root[0]!=0) {
314 /* no aliasing, no userdir... */
315 int l1, l2;
316
317 l1 = strlen(req->document_root);
318 l2 = strlen(req->request_uri);
319
320 if (l1 + l2 + 1 > MAX_HEADER_LENGTH) {
321 log_error_doc(req);
322 fputs("uri too long!\n", stderr);
323 send_r_bad_request(req);
324 return 0;
325 }
326
327 /* the 'l2 + 1' is there so we copy the '\0' as well */
328 memcpy(buffer, req->document_root, l1);
329 memcpy(buffer + l1, req->request_uri, l2 + 1);
330 } else {
331 /* not aliased. not userdir. not part of document_root. BAIL */
332 send_r_bad_request(req);
333 return 0;
334 }
335
336 /* if here,
337 * o it may be aliased but it's not a redirect or a script...
338 * o it may be a homedir
339 * o it may be a document_root resource (with or without virtual host)
340 */
341
342 req->pathname = strdup(buffer);
343 if (!req->pathname) {
344 WARN("Could not strdup buffer for req->pathname!");
345 send_r_error(req);
346 return 0;
347 }
348
349 /* below we support cgis outside of a ScriptAlias */
350 if (strcmp(CGI_MIME_TYPE, get_mime_type(buffer)) == 0) { /* cgi */
351 #ifdef FASCIST_LOGGING
352 log_error_time();
353 fprintf(stderr, "%s:%d - buffer is: \"%s\"\n",
354 __FILE__, __LINE__, buffer);
355 #endif
356 /* FIXME */
357 /* script_name could end up as /cgi-bin/bob/extra_path */
358 req->script_name = strdup(req->request_uri);
359 if (!req->script_name) {
360 WARN("Could not strdup req->request_uri for req->script_name");
361 send_r_error(req);
362 return 0;
363 }
364 if (req->simple)
365 req->is_cgi = NPH;
366 else
367 req->is_cgi = CGI;
368 return 1;
369 } else if (req->method == M_POST) { /* POST to non-script */
370 /* it's not a cgi, but we try to POST??? */
371 send_r_bad_request(req);
372 return 0;
373 } else /* we are done!! */
374 return 1;
375 }
376
377 /*
378 * Name: init_script_alias
379 *
380 * Description: Performs full parsing on a ScriptAlias request
381 * Sets path_info and script_name
382 *
383 * Return values:
384 *
385 * 0: failure, shut down
386 * 1: success, continue
387 */
388
389 int init_script_alias(request * req, alias * current1, int uri_len)
390 {
391 static char pathname[MAX_HEADER_LENGTH + 1];
392 struct stat statbuf;
393 static char buffer[MAX_HEADER_LENGTH + 1];
394
395 int index = 0;
396 char c;
397 int err;
398 virthost* vhost;
399
400 vhost = find_virthost( req->hostname, 0);
401 if (vhost == NULL) {
402 send_r_not_found(req);
403 return 0;
404 }
405
406 /* copies the "real" path + the non-alias portion of the
407 uri to pathname.
408 */
409
410 if (uri_len - current1->fake_len + current1->real_len >
411 MAX_HEADER_LENGTH) {
412 log_error_doc(req);
413 fputs("uri too long!\n", stderr);
414 send_r_bad_request(req);
415 return 0;
416 }
417
418 memcpy(pathname, current1->realname, current1->real_len);
419 memcpy(pathname + current1->real_len,
420 &req->request_uri[current1->fake_len],
421 uri_len - current1->fake_len + 1); /* the +1 copies the NUL */
422 #ifdef FASCIST_LOGGING
423 log_error_time();
424 fprintf(stderr,
425 "%s:%d - pathname in init_script_alias is: \"%s\" (\"%s\")\n",
426 __FILE__, __LINE__, pathname, pathname + current1->real_len);
427 #endif
428 if (strncmp("nph-", pathname + current1->real_len, 4) == 0
429 || req->simple) req->is_cgi = NPH;
430 else
431 req->is_cgi = CGI;
432
433
434 /* start at the beginning of the actual uri...
435 (in /cgi-bin/bob, start at the 'b' in bob */
436 index = current1->real_len;
437
438 /* go to first and successive '/' and keep checking
439 * if it is a full pathname
440 * on success (stat (not lstat) of file is a *regular file*)
441 */
442 do {
443 c = pathname[++index];
444 if (c == '/') {
445 pathname[index] = '\0';
446 err = stat(pathname, &statbuf);
447 pathname[index] = '/';
448 if (err == -1) {
449 send_r_not_found(req);
450 return 0;
451 }
452
453 /* is it a dir? */
454 if (!S_ISDIR(statbuf.st_mode)) {
455 /* check access */
456 if (!(statbuf.st_mode &
457 (S_IFREG | /* regular file */
458 (S_IRUSR | S_IXUSR) | /* u+rx */
459 (S_IRGRP | S_IXGRP) | /* g+rx */
460 (S_IROTH | S_IXOTH)))) { /* o+rx */
461 send_r_forbidden(req);
462 return 0;
463 }
464 /* stop here */
465 break;
466 }
467 }
468 } while (c != '\0');
469
470 req->script_name = strdup(req->request_uri);
471 if (!req->script_name) {
472 send_r_error(req);
473 WARN("unable to strdup req->request_uri for req->script_name");
474 return 0;
475 }
476
477 if (c == '\0') {
478 err = stat(pathname, &statbuf);
479 if (err == -1) {
480 send_r_not_found(req);
481 return 0;
482 }
483
484 /* is it a dir? */
485 if (!S_ISDIR(statbuf.st_mode)) {
486 /* check access */
487 if (!(statbuf.st_mode &
488 (S_IFREG | /* regular file */
489 (S_IRUSR | S_IXUSR) | /* u+rx */
490 (S_IRGRP | S_IXGRP) | /* g+rx */
491 (S_IROTH | S_IXOTH)))) { /* o+rx */
492 send_r_forbidden(req);
493 return 0;
494 }
495 /* stop here */
496 } else {
497 send_r_forbidden(req);
498 return 0;
499 }
500 }
501
502 /* we have path_info if c == '/'... still have to check for query */
503 else if (c == '/') {
504 int hash;
505 alias *current;
506 int path_len;
507
508 req->path_info = strdup(pathname + index);
509 if (!req->path_info) {
510 send_r_error(req);
511 WARN("unable to strdup pathname + index for req->path_info");
512 return 0;
513 }
514 pathname[index] = '\0'; /* strip path_info from path */
515 path_len = strlen(req->path_info);
516 /* we need to fix script_name here */
517 /* index points into pathname, which is
518 * realname/cginame/foo
519 * and index points to the '/foo' part
520 */
521 req->script_name[strlen(req->script_name) - path_len] = '\0'; /* zap off the /foo part */
522
523 /* now, we have to re-alias the extra path info....
524 this sucks.
525 */
526 hash = get_alias_hash_value(req->path_info);
527 current = vhost->alias_hashtable[hash];
528 while (current && !req->path_translated) {
529 if (!strncmp(req->path_info, current->fakename,
530 current->fake_len)) {
531
532 if (current->real_len +
533 path_len - current->fake_len > MAX_HEADER_LENGTH) {
534 log_error_doc(req);
535 fputs("uri too long!\n", stderr);
536 send_r_bad_request(req);
537 return 0;
538 }
539
540 memcpy(buffer, current->realname, current->real_len);
541 strcpy(buffer + current->real_len,
542 &req->path_info[current->fake_len]);
543 req->path_translated = strdup(buffer);
544 if (!req->path_translated) {
545 send_r_error(req);
546 WARN("unable to strdup buffer for req->path_translated");
547 return 0;
548 }
549 }
550 current = current->next;
551 }
552 /* no alias... try userdir */
553 if (!req->path_translated && req->user_dir[0]!=0 && req->path_info[1] == '~') {
554 char *user_homedir;
555 char *p;
556
557 p = strchr(pathname + index + 1, '/');
558 if (p)
559 *p = '\0';
560
561 user_homedir = get_home_dir(pathname + index + 2);
562 if (p)
563 *p = '/';
564
565 if (!user_homedir) { /* no such user */
566 send_r_not_found(req);
567 return 0;
568 }
569 {
570 int l1 = strlen(user_homedir);
571 int l2 = strlen(req->user_dir);
572 int l3;
573 if (p)
574 l3 = strlen(p);
575 else
576 l3 = 0;
577
578 req->path_translated = malloc(l1 + l2 + l3 + 2);
579 if (req->path_translated == NULL) {
580 send_r_error(req);
581 WARN("unable to malloc memory for req->path_translated");
582 return 0;
583 }
584 memcpy(req->path_translated, user_homedir, l1);
585 req->path_translated[l1] = '/';
586 memcpy(req->path_translated + l1 + 1, req->user_dir, l2 + 1);
587 if (p)
588 memcpy(req->path_translated + l1 + 1 + l2, p, l3 + 1);
589 }
590 }
591 if (!req->path_translated && req->document_root[0]!=0) {
592 /* no userdir, no aliasing... try document root */
593 int l1, l2;
594 l1 = strlen(req->document_root);
595 l2 = path_len;
596
597 req->path_translated = malloc(l1 + l2 + 1);
598 if (req->path_translated == NULL) {
599 send_r_error(req);
600 WARN("unable to malloc memory for req->path_translated");
601 return 0;
602 }
603 memcpy(req->path_translated, req->document_root, l1);
604 memcpy(req->path_translated + l1, req->path_info, l2 + 1);
605 }
606 }
607
608 req->pathname = strdup(pathname);
609 if (!req->pathname) {
610 send_r_error(req);
611 WARN("unable to strdup pathname for req->pathname");
612 return 0;
613 }
614
615 return 1;
616 }
617
618 /*
619 * Empties the alias hashtable, deallocating any allocated memory.
620 */
621
622 void dump_alias( virthost* vhost)
623 {
624 int i;
625 alias *temp;
626
627 for (i = 0; i < ALIAS_HASHTABLE_SIZE; ++i) { /* these limits OK? */
628 if (vhost->alias_hashtable[i]) {
629 temp = vhost->alias_hashtable[i];
630 while (temp) {
631 alias *temp_next;
632
633 if (temp->fakename)
634 free(temp->fakename);
635 if (temp->realname)
636 free(temp->realname);
637 temp_next = temp->next;
638 free(temp);
639 temp = temp_next;
640 }
641 vhost->alias_hashtable[i] = NULL;
642 }
643 }
644 }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26