Annotation of embedaddon/thttpd/cgi-src/ssi.c, revision 1.1
1.1 ! misho 1: /* ssi - server-side-includes CGI program
! 2: **
! 3: ** Copyright © 1995 by Jef Poskanzer <jef@mail.acme.com>.
! 4: ** All rights reserved.
! 5: **
! 6: ** Redistribution and use in source and binary forms, with or without
! 7: ** modification, are permitted provided that the following conditions
! 8: ** are met:
! 9: ** 1. Redistributions of source code must retain the above copyright
! 10: ** notice, this list of conditions and the following disclaimer.
! 11: ** 2. Redistributions in binary form must reproduce the above copyright
! 12: ** notice, this list of conditions and the following disclaimer in the
! 13: ** documentation and/or other materials provided with the distribution.
! 14: **
! 15: ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
! 16: ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 17: ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 18: ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
! 19: ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 20: ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 21: ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 22: ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 23: ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 24: ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 25: ** SUCH DAMAGE.
! 26: */
! 27:
! 28: #include <stdio.h>
! 29: #include <stdlib.h>
! 30: #include <string.h>
! 31: #include <time.h>
! 32: #include <sys/types.h>
! 33: #include <sys/stat.h>
! 34:
! 35: #include "config.h"
! 36: #include "match.h"
! 37:
! 38:
! 39: #define ST_GROUND 0
! 40: #define ST_LESSTHAN 1
! 41: #define ST_BANG 2
! 42: #define ST_MINUS1 3
! 43: #define ST_MINUS2 4
! 44:
! 45:
! 46: static void read_file( char* vfilename, char* filename, FILE* fp );
! 47:
! 48:
! 49: static char* argv0;
! 50: static char* url;
! 51:
! 52: static char timefmt[100];
! 53: static int sizefmt;
! 54: #define SF_BYTES 0
! 55: #define SF_ABBREV 1
! 56: static struct stat sb;
! 57:
! 58:
! 59: static void
! 60: internal_error( char* reason )
! 61: {
! 62: char* title = "500 Internal Error";
! 63:
! 64: (void) printf( "\
! 65: <HTML><HEAD><TITLE>%s</TITLE></HEAD>\n\
! 66: <BODY><H2>%s</H2>\n\
! 67: Something unusual went wrong during a server-side-includes request:\n\
! 68: <BLOCKQUOTE>\n\
! 69: %s\n\
! 70: </BLOCKQUOTE>\n\
! 71: </BODY></HTML>\n", title, title, reason );
! 72: }
! 73:
! 74:
! 75: static void
! 76: not_found( char* filename )
! 77: {
! 78: char* title = "404 Not Found";
! 79:
! 80: (void) printf( "\
! 81: <HTML><HEAD><TITLE>%s</TITLE></HEAD>\n\
! 82: <BODY><H2>%s</H2>\n\
! 83: The requested server-side-includes filename, %s,\n\
! 84: does not seem to exist.\n\
! 85: </BODY></HTML>\n", title, title, filename );
! 86: }
! 87:
! 88:
! 89: static void
! 90: not_found2( char* directive, char* tag, char* filename2 )
! 91: {
! 92: char* title = "Not Found";
! 93:
! 94: (void) printf( "\
! 95: <HR><H2>%s</H2>\n\
! 96: The filename requested in a %s %s directive, %s,\n\
! 97: does not seem to exist.\n\
! 98: <HR>\n", title, directive, tag, filename2 );
! 99: }
! 100:
! 101:
! 102: static void
! 103: not_permitted( char* directive, char* tag, char* val )
! 104: {
! 105: char* title = "Not Permitted";
! 106:
! 107: (void) printf( "\
! 108: <HR><H2>%s</H2>\n\
! 109: The filename requested in the %s %s=%s directive\n\
! 110: may not be fetched.\n\
! 111: <HR>\n", title, directive, tag, val );
! 112: }
! 113:
! 114:
! 115: static void
! 116: unknown_directive( char* filename, char* directive )
! 117: {
! 118: char* title = "Unknown Directive";
! 119:
! 120: (void) printf( "\
! 121: <HR><H2>%s</H2>\n\
! 122: The requested server-side-includes filename, %s,\n\
! 123: tried to use an unknown directive, %s.\n\
! 124: <HR>\n", title, filename, directive );
! 125: }
! 126:
! 127:
! 128: static void
! 129: unknown_tag( char* filename, char* directive, char* tag )
! 130: {
! 131: char* title = "Unknown Tag";
! 132:
! 133: (void) printf( "\
! 134: <HR><H2>%s</H2>\n\
! 135: The requested server-side-includes filename, %s,\n\
! 136: tried to use the directive %s with an unknown tag, %s.\n\
! 137: <HR>\n", title, filename, directive, tag );
! 138: }
! 139:
! 140:
! 141: static void
! 142: unknown_value( char* filename, char* directive, char* tag, char* val )
! 143: {
! 144: char* title = "Unknown Value";
! 145:
! 146: (void) printf( "\
! 147: <HR><H2>%s</H2>\n\
! 148: The requested server-side-includes filename, %s,\n\
! 149: tried to use the directive %s %s with an unknown value, %s.\n\
! 150: <HR>\n", title, filename, directive, tag, val );
! 151: }
! 152:
! 153:
! 154: static int
! 155: get_filename( char* vfilename, char* filename, char* directive, char* tag, char* val, char* fn, int fnsize )
! 156: {
! 157: int vl, fl;
! 158: char* cp;
! 159:
! 160: /* Used for the various commands that accept a file name.
! 161: ** These commands accept two tags:
! 162: ** virtual
! 163: ** Gives a virtual path to a document on the server.
! 164: ** file
! 165: ** Gives a pathname relative to the current directory. ../ cannot
! 166: ** be used in this pathname, nor can absolute paths be used.
! 167: */
! 168: vl = strlen( vfilename );
! 169: fl = strlen( filename );
! 170: if ( strcmp( tag, "virtual" ) == 0 )
! 171: {
! 172: if ( strstr( val, "../" ) != (char*) 0 )
! 173: {
! 174: not_permitted( directive, tag, val );
! 175: return -1;
! 176: }
! 177: /* Figure out root using difference between vfilename and filename. */
! 178: if ( vl > fl ||
! 179: strcmp( vfilename, &filename[fl - vl] ) != 0 )
! 180: return -1;
! 181: if ( fl - vl + strlen( val ) >= fnsize )
! 182: return -1;
! 183: (void) strncpy( fn, filename, fl - vl );
! 184: (void) strcpy( &fn[fl - vl], val );
! 185: }
! 186: else if ( strcmp( tag, "file" ) == 0 )
! 187: {
! 188: if ( val[0] == '/' || strstr( val, "../" ) != (char*) 0 )
! 189: {
! 190: not_permitted( directive, tag, val );
! 191: return -1;
! 192: }
! 193: if ( fl + 1 + strlen( val ) >= fnsize )
! 194: return -1;
! 195: (void) strcpy( fn, filename );
! 196: cp = strrchr( fn, '/' );
! 197: if ( cp == (char*) 0 )
! 198: {
! 199: cp = &fn[strlen( fn )];
! 200: *cp = '/';
! 201: }
! 202: (void) strcpy( ++cp, val );
! 203: }
! 204: else
! 205: {
! 206: unknown_tag( filename, directive, tag );
! 207: return -1;
! 208: }
! 209: return 0;
! 210: }
! 211:
! 212:
! 213: static int
! 214: check_filename( char* filename )
! 215: {
! 216: static int inited = 0;
! 217: static char* cgi_pattern;
! 218: int fnl;
! 219: char* cp;
! 220: char* dirname;
! 221: char* authname;
! 222: struct stat sb;
! 223: int r;
! 224:
! 225: if ( ! inited )
! 226: {
! 227: /* Get the cgi pattern. */
! 228: cgi_pattern = getenv( "CGI_PATTERN" );
! 229: #ifdef CGI_PATTERN
! 230: if ( cgi_pattern == (char*) 0 )
! 231: cgi_pattern = CGI_PATTERN;
! 232: #endif /* CGI_PATTERN */
! 233: inited = 1;
! 234: }
! 235:
! 236: /* ../ is not permitted. */
! 237: if ( strstr( filename, "../" ) != (char*) 0 )
! 238: return 0;
! 239:
! 240: #ifdef AUTH_FILE
! 241: /* Ensure that we are not reading a basic auth password file. */
! 242: fnl = strlen(filename);
! 243: if ( strcmp( filename, AUTH_FILE ) == 0 ||
! 244: ( fnl >= sizeof(AUTH_FILE) &&
! 245: strcmp( &filename[fnl - sizeof(AUTH_FILE) + 1], AUTH_FILE ) == 0 &&
! 246: filename[fnl - sizeof(AUTH_FILE)] == '/' ) )
! 247: return 0;
! 248:
! 249: /* Check for an auth file in the same directory. We can't do an actual
! 250: ** auth password check here because CGI programs are not given the
! 251: ** authorization header, for security reasons. So instead we just
! 252: ** prohibit access to all auth-protected files.
! 253: */
! 254: dirname = strdup( filename );
! 255: if ( dirname == (char*) 0 )
! 256: return 0; /* out of memory */
! 257: cp = strrchr( dirname, '/' );
! 258: if ( cp == (char*) 0 )
! 259: (void) strcpy( dirname, "." );
! 260: else
! 261: *cp = '\0';
! 262: authname = malloc( strlen( dirname ) + 1 + sizeof(AUTH_FILE) );
! 263: if ( authname == (char*) 0 )
! 264: return 0; /* out of memory */
! 265: (void) sprintf( authname, "%s/%s", dirname, AUTH_FILE );
! 266: r = stat( authname, &sb );
! 267: free( dirname );
! 268: free( authname );
! 269: if ( r == 0 )
! 270: return 0;
! 271: #endif /* AUTH_FILE */
! 272:
! 273: /* Ensure that we are not reading a CGI file. */
! 274: if ( cgi_pattern != (char*) 0 && match( cgi_pattern, filename ) )
! 275: return 0;
! 276:
! 277: return 1;
! 278: }
! 279:
! 280:
! 281: static void
! 282: show_time( time_t t, int gmt )
! 283: {
! 284: struct tm* tmP;
! 285: char tbuf[500];
! 286:
! 287: if ( gmt )
! 288: tmP = gmtime( &t );
! 289: else
! 290: tmP = localtime( &t );
! 291: if ( strftime( tbuf, sizeof(tbuf), timefmt, tmP ) > 0 )
! 292: (void) fputs( tbuf, stdout );
! 293: }
! 294:
! 295:
! 296: static void
! 297: show_size( off_t size )
! 298: {
! 299: switch ( sizefmt )
! 300: {
! 301: case SF_BYTES:
! 302: (void) printf( "%ld", (long) size ); /* spec says should have commas */
! 303: break;
! 304: case SF_ABBREV:
! 305: if ( size < 1024 )
! 306: (void) printf( "%ld", (long) size );
! 307: else if ( size < 1024 )
! 308: (void) printf( "%ldK", (long) size / 1024L );
! 309: else if ( size < 1024*1024 )
! 310: (void) printf( "%ldM", (long) size / (1024L*1024L) );
! 311: else
! 312: (void) printf( "%ldG", (long) size / (1024L*1024L*1024L) );
! 313: break;
! 314: }
! 315: }
! 316:
! 317:
! 318: static void
! 319: do_config( char* vfilename, char* filename, FILE* fp, char* directive, char* tag, char* val )
! 320: {
! 321: /* The config directive controls various aspects of the file parsing.
! 322: ** There are two valid tags:
! 323: ** timefmt
! 324: ** Gives the server a new format to use when providing dates. This
! 325: ** is a string compatible with the strftime library call.
! 326: ** sizefmt
! 327: ** Determines the formatting to be used when displaying the size of
! 328: ** a file. Valid choices are bytes, for a formatted byte count
! 329: ** (formatted as 1,234,567), or abbrev for an abbreviated version
! 330: ** displaying the number of kilobytes or megabytes the file occupies.
! 331: */
! 332:
! 333: if ( strcmp( tag, "timefmt" ) == 0 )
! 334: {
! 335: (void) strncpy( timefmt, val, sizeof(timefmt) - 1 );
! 336: timefmt[sizeof(timefmt) - 1] = '\0';
! 337: }
! 338: else if ( strcmp( tag, "sizefmt" ) == 0 )
! 339: {
! 340: if ( strcmp( val, "bytes" ) == 0 )
! 341: sizefmt = SF_BYTES;
! 342: else if ( strcmp( val, "abbrev" ) == 0 )
! 343: sizefmt = SF_ABBREV;
! 344: else
! 345: unknown_value( filename, directive, tag, val );
! 346: }
! 347: else
! 348: unknown_tag( filename, directive, tag );
! 349: }
! 350:
! 351:
! 352: static void
! 353: do_include( char* vfilename, char* filename, FILE* fp, char* directive, char* tag, char* val )
! 354: {
! 355: char vfilename2[1000];
! 356: char filename2[1000];
! 357: FILE* fp2;
! 358:
! 359: /* Inserts the text of another document into the parsed document. */
! 360:
! 361: if ( get_filename(
! 362: vfilename, filename, directive, tag, val, filename2,
! 363: sizeof(filename2) ) < 0 )
! 364: return;
! 365:
! 366: if ( ! check_filename( filename2 ) )
! 367: {
! 368: not_permitted( directive, tag, filename2 );
! 369: return;
! 370: }
! 371:
! 372: fp2 = fopen( filename2, "r" );
! 373: if ( fp2 == (FILE*) 0 )
! 374: {
! 375: not_found2( directive, tag, filename2 );
! 376: return;
! 377: }
! 378:
! 379: if ( strcmp( tag, "virtual" ) == 0 )
! 380: {
! 381: if ( strlen( val ) < sizeof( vfilename2 ) )
! 382: (void) strcpy( vfilename2, val );
! 383: else
! 384: (void) strcpy( vfilename2, filename2 ); /* same size, has to fit */
! 385: }
! 386: else
! 387: {
! 388: if ( strlen( vfilename ) + 1 + strlen( val ) < sizeof(vfilename2) )
! 389: {
! 390: char* cp;
! 391: (void) strcpy( vfilename2, vfilename );
! 392: cp = strrchr( vfilename2, '/' );
! 393: if ( cp == (char*) 0 )
! 394: {
! 395: cp = &vfilename2[strlen( vfilename2 )];
! 396: *cp = '/';
! 397: }
! 398: (void) strcpy( ++cp, val );
! 399: }
! 400: else
! 401: (void) strcpy( vfilename2, filename2 ); /* same size, has to fit */
! 402: }
! 403:
! 404: read_file( vfilename2, filename2, fp2 );
! 405: (void) fclose( fp2 );
! 406: }
! 407:
! 408:
! 409: static void
! 410: do_echo( char* vfilename, char* filename, FILE* fp, char* directive, char* tag, char* val )
! 411: {
! 412: char* cp;
! 413: time_t t;
! 414:
! 415: /* Prints the value of one of the include variables. Any dates are
! 416: ** printed subject to the currently configured timefmt. The only valid
! 417: ** tag is var, whose value is the name of the variable you wish to echo.
! 418: */
! 419:
! 420: if ( strcmp( tag, "var" ) != 0 )
! 421: unknown_tag( filename, directive, tag );
! 422: else
! 423: {
! 424: if ( strcmp( val, "DOCUMENT_NAME" ) == 0 )
! 425: {
! 426: /* The current filename. */
! 427: (void) fputs( filename, stdout );
! 428: }
! 429: else if ( strcmp( val, "DOCUMENT_URI" ) == 0 )
! 430: {
! 431: /* The virtual path to this file (such as /~robm/foo.shtml). */
! 432: (void) fputs( vfilename, stdout );
! 433: }
! 434: else if ( strcmp( val, "QUERY_STRING_UNESCAPED" ) == 0 )
! 435: {
! 436: /* The unescaped version of any search query the client sent. */
! 437: cp = getenv( "QUERY_STRING" );
! 438: if ( cp != (char*) 0 )
! 439: (void) fputs( cp, stdout );
! 440: }
! 441: else if ( strcmp( val, "DATE_LOCAL" ) == 0 )
! 442: {
! 443: /* The current date, local time zone. */
! 444: t = time( (time_t*) 0 );
! 445: show_time( t, 0 );
! 446: }
! 447: else if ( strcmp( val, "DATE_GMT" ) == 0 )
! 448: {
! 449: /* Same as DATE_LOCAL but in Greenwich mean time. */
! 450: t = time( (time_t*) 0 );
! 451: show_time( t, 1 );
! 452: }
! 453: else if ( strcmp( val, "LAST_MODIFIED" ) == 0 )
! 454: {
! 455: /* The last modification date of the current document. */
! 456: if ( fstat( fileno( fp ), &sb ) >= 0 )
! 457: show_time( sb.st_mtime, 0 );
! 458: }
! 459: else
! 460: {
! 461: /* Try an environment variable. */
! 462: cp = getenv( val );
! 463: if ( cp == (char*) 0 )
! 464: unknown_value( filename, directive, tag, val );
! 465: else
! 466: (void) fputs( cp, stdout );
! 467: }
! 468: }
! 469: }
! 470:
! 471:
! 472: static void
! 473: do_fsize( char* vfilename, char* filename, FILE* fp, char* directive, char* tag, char* val )
! 474: {
! 475: char filename2[1000];
! 476:
! 477: /* Prints the size of the specified file. */
! 478:
! 479: if ( get_filename(
! 480: vfilename, filename, directive, tag, val, filename2,
! 481: sizeof(filename2) ) < 0 )
! 482: return;
! 483: if ( stat( filename2, &sb ) < 0 )
! 484: {
! 485: not_found2( directive, tag, filename2 );
! 486: return;
! 487: }
! 488: show_size( sb.st_size );
! 489: }
! 490:
! 491:
! 492: static void
! 493: do_flastmod( char* vfilename, char* filename, FILE* fp, char* directive, char* tag, char* val )
! 494: {
! 495: char filename2[1000];
! 496:
! 497: /* Prints the last modification date of the specified file. */
! 498:
! 499: if ( get_filename(
! 500: vfilename, filename, directive, tag, val, filename2,
! 501: sizeof(filename2) ) < 0 )
! 502: return;
! 503: if ( stat( filename2, &sb ) < 0 )
! 504: {
! 505: not_found2( directive, tag, filename2 );
! 506: return;
! 507: }
! 508: show_time( sb.st_mtime, 0 );
! 509: }
! 510:
! 511:
! 512: static void
! 513: parse( char* vfilename, char* filename, FILE* fp, char* str )
! 514: {
! 515: char* directive;
! 516: char* cp;
! 517: int ntags;
! 518: char* tags[200];
! 519: int dirn;
! 520: #define DI_CONFIG 0
! 521: #define DI_INCLUDE 1
! 522: #define DI_ECHO 2
! 523: #define DI_FSIZE 3
! 524: #define DI_FLASTMOD 4
! 525: int i;
! 526: char* val;
! 527:
! 528: directive = str;
! 529: directive += strspn( directive, " \t\n\r" );
! 530:
! 531: ntags = 0;
! 532: cp = directive;
! 533: for (;;)
! 534: {
! 535: cp = strpbrk( cp, " \t\n\r\"" );
! 536: if ( cp == (char*) 0 )
! 537: break;
! 538: if ( *cp == '"' )
! 539: {
! 540: cp = strpbrk( cp + 1, "\"" );
! 541: ++cp;
! 542: if ( *cp == '\0' )
! 543: break;
! 544: }
! 545: *cp++ = '\0';
! 546: cp += strspn( cp, " \t\n\r" );
! 547: if ( *cp == '\0' )
! 548: break;
! 549: if ( ntags < sizeof(tags)/sizeof(*tags) )
! 550: tags[ntags++] = cp;
! 551: }
! 552:
! 553: if ( strcmp( directive, "config" ) == 0 )
! 554: dirn = DI_CONFIG;
! 555: else if ( strcmp( directive, "include" ) == 0 )
! 556: dirn = DI_INCLUDE;
! 557: else if ( strcmp( directive, "echo" ) == 0 )
! 558: dirn = DI_ECHO;
! 559: else if ( strcmp( directive, "fsize" ) == 0 )
! 560: dirn = DI_FSIZE;
! 561: else if ( strcmp( directive, "flastmod" ) == 0 )
! 562: dirn = DI_FLASTMOD;
! 563: else
! 564: {
! 565: unknown_directive( filename, directive );
! 566: return;
! 567: }
! 568:
! 569: for ( i = 0; i < ntags; ++i )
! 570: {
! 571: if ( i > 0 )
! 572: putchar( ' ' );
! 573: val = strchr( tags[i], '=' );
! 574: if ( val == (char*) 0 )
! 575: val = "";
! 576: else
! 577: *val++ = '\0';
! 578: if ( *val == '"' && val[strlen( val ) - 1] == '"' )
! 579: {
! 580: val[strlen( val ) - 1] = '\0';
! 581: ++val;
! 582: }
! 583: switch( dirn )
! 584: {
! 585: case DI_CONFIG:
! 586: do_config( vfilename, filename, fp, directive, tags[i], val );
! 587: break;
! 588: case DI_INCLUDE:
! 589: do_include( vfilename, filename, fp, directive, tags[i], val );
! 590: break;
! 591: case DI_ECHO:
! 592: do_echo( vfilename, filename, fp, directive, tags[i], val );
! 593: break;
! 594: case DI_FSIZE:
! 595: do_fsize( vfilename, filename, fp, directive, tags[i], val );
! 596: break;
! 597: case DI_FLASTMOD:
! 598: do_flastmod( vfilename, filename, fp, directive, tags[i], val );
! 599: break;
! 600: }
! 601: }
! 602: }
! 603:
! 604:
! 605: static void
! 606: slurp( char* vfilename, char* filename, FILE* fp )
! 607: {
! 608: char buf[1000];
! 609: int i;
! 610: int state;
! 611: int ich;
! 612:
! 613: /* Now slurp in the rest of the comment from the input file. */
! 614: i = 0;
! 615: state = ST_GROUND;
! 616: while ( ( ich = getc( fp ) ) != EOF )
! 617: {
! 618: switch ( state )
! 619: {
! 620: case ST_GROUND:
! 621: if ( ich == '-' )
! 622: state = ST_MINUS1;
! 623: break;
! 624: case ST_MINUS1:
! 625: if ( ich == '-' )
! 626: state = ST_MINUS2;
! 627: else
! 628: state = ST_GROUND;
! 629: break;
! 630: case ST_MINUS2:
! 631: if ( ich == '>' )
! 632: {
! 633: buf[i - 2] = '\0';
! 634: parse( vfilename, filename, fp, buf );
! 635: return;
! 636: }
! 637: else if ( ich != '-' )
! 638: state = ST_GROUND;
! 639: break;
! 640: }
! 641: if ( i < sizeof(buf) - 1 )
! 642: buf[i++] = (char) ich;
! 643: }
! 644: }
! 645:
! 646:
! 647: static void
! 648: read_file( char* vfilename, char* filename, FILE* fp )
! 649: {
! 650: int ich;
! 651: int state;
! 652:
! 653: /* Copy it to output, while running a state-machine to look for
! 654: ** SSI directives.
! 655: */
! 656: state = ST_GROUND;
! 657: while ( ( ich = getc( fp ) ) != EOF )
! 658: {
! 659: switch ( state )
! 660: {
! 661: case ST_GROUND:
! 662: if ( ich == '<' )
! 663: { state = ST_LESSTHAN; continue; }
! 664: break;
! 665: case ST_LESSTHAN:
! 666: if ( ich == '!' )
! 667: { state = ST_BANG; continue; }
! 668: else
! 669: { state = ST_GROUND; putchar( '<' ); }
! 670: break;
! 671: case ST_BANG:
! 672: if ( ich == '-' )
! 673: { state = ST_MINUS1; continue; }
! 674: else
! 675: { state = ST_GROUND; (void) fputs ( "<!", stdout ); }
! 676: break;
! 677: case ST_MINUS1:
! 678: if ( ich == '-' )
! 679: { state = ST_MINUS2; continue; }
! 680: else
! 681: { state = ST_GROUND; (void) fputs ( "<!-", stdout ); }
! 682: break;
! 683: case ST_MINUS2:
! 684: if ( ich == '#' )
! 685: {
! 686: slurp( vfilename, filename, fp );
! 687: state = ST_GROUND;
! 688: continue;
! 689: }
! 690: else
! 691: { state = ST_GROUND; (void) fputs ( "<!--", stdout ); }
! 692: break;
! 693: }
! 694: putchar( (char) ich );
! 695: }
! 696: }
! 697:
! 698:
! 699: int
! 700: main( int argc, char** argv )
! 701: {
! 702: char* script_name;
! 703: char* path_info;
! 704: char* path_translated;
! 705: FILE* fp;
! 706:
! 707: argv0 = argv[0];
! 708:
! 709: /* Default formats. */
! 710: (void) strcpy( timefmt, "%a %b %e %T %Z %Y" );
! 711: sizefmt = SF_BYTES;
! 712:
! 713: /* The MIME type has to be text/html. */
! 714: (void) fputs( "Content-type: text/html\n\n", stdout );
! 715:
! 716: /* Get the name that we were run as. */
! 717: script_name = getenv( "SCRIPT_NAME" );
! 718: if ( script_name == (char*) 0 )
! 719: {
! 720: internal_error( "Couldn't get SCRIPT_NAME environment variable." );
! 721: exit( 1 );
! 722: }
! 723:
! 724: /* Append the PATH_INFO, if any, to get the full URL. */
! 725: path_info = getenv( "PATH_INFO" );
! 726: if ( path_info == (char*) 0 )
! 727: path_info = "";
! 728: url = (char*) malloc( strlen( script_name ) + strlen( path_info ) + 1 );
! 729: if ( url == (char*) 0 )
! 730: {
! 731: internal_error( "Out of memory." );
! 732: exit( 1 );
! 733: }
! 734: (void) sprintf( url, "%s%s", script_name, path_info );
! 735:
! 736: /* Get the name of the file to parse. */
! 737: path_translated = getenv( "PATH_TRANSLATED" );
! 738: if ( path_translated == (char*) 0 )
! 739: {
! 740: internal_error( "Couldn't get PATH_TRANSLATED environment variable." );
! 741: exit( 1 );
! 742: }
! 743:
! 744: if ( ! check_filename( path_translated ) )
! 745: {
! 746: not_permitted( "initial", "PATH_TRANSLATED", path_translated );
! 747: exit( 1 );
! 748: }
! 749:
! 750: /* Open it. */
! 751: fp = fopen( path_translated, "r" );
! 752: if ( fp == (FILE*) 0 )
! 753: {
! 754: not_found( path_translated );
! 755: exit( 1 );
! 756: }
! 757:
! 758: /* Read and handle the file. */
! 759: read_file( path_info, path_translated, fp );
! 760:
! 761: (void) fclose( fp );
! 762: exit( 0 );
! 763: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>