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>