Annotation of embedaddon/thttpd/cgi-src/ssi.c, revision 1.1.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>