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