home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / CONTRIB / HTTPD / HTTPD_SO.TAR / httpd_1.3 / src / http_config.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-07  |  33.4 KB  |  984 lines

  1. /*
  2.  * http_config.c: auxillary functions for reading httpd's config file
  3.  * and converting filenames into a namespace
  4.  *
  5.  * Rob McCool 
  6.  * 
  7.  */
  8.  
  9. #include "httpd.h"
  10.  
  11.  
  12. /* Server config globals */
  13. int standalone;
  14. int port;
  15. uid_t user_id;
  16. gid_t group_id;
  17. char server_root[MAX_STRING_LEN];
  18. char error_fname[MAX_STRING_LEN];
  19. char xfer_fname[MAX_STRING_LEN];
  20. char pid_fname[MAX_STRING_LEN];
  21. char server_admin[MAX_STRING_LEN];
  22. char *server_hostname;
  23. char srm_confname[MAX_STRING_LEN];
  24. char server_confname[MAX_STRING_LEN];
  25. char access_confname[MAX_STRING_LEN];
  26. char types_confname[MAX_STRING_LEN];
  27. int timeout;
  28. int do_rfc931;
  29. #ifdef PEM_AUTH
  30. char auth_pem_decrypt[MAX_STRING_LEN];
  31. char auth_pem_encrypt[MAX_STRING_LEN];
  32. char auth_pem_entity[MAX_STRING_LEN];
  33. char auth_pgp_decrypt[MAX_STRING_LEN];
  34. char auth_pgp_encrypt[MAX_STRING_LEN];
  35. char auth_pgp_entity[MAX_STRING_LEN];
  36. #endif
  37.  
  38. void process_server_config(FILE *errors) {
  39.     FILE *cfg;
  40.     char l[MAX_STRING_LEN],w[MAX_STRING_LEN];
  41.     int n=0;
  42.  
  43.     standalone = 1;
  44.     port = DEFAULT_PORT;
  45.     user_id = uname2id(DEFAULT_USER);
  46.     group_id = gname2id(DEFAULT_GROUP);
  47.     /* ServerRoot set in httpd.c */
  48.     make_full_path(server_root,DEFAULT_ERRORLOG,error_fname);
  49.     make_full_path(server_root,DEFAULT_XFERLOG,xfer_fname);
  50.     make_full_path(server_root,DEFAULT_PIDLOG,pid_fname);
  51.     strcpy(server_admin,DEFAULT_ADMIN);
  52.     server_hostname = NULL;
  53.     make_full_path(server_root,RESOURCE_CONFIG_FILE,srm_confname);
  54.     /* server_confname set in httpd.c */
  55.     make_full_path(server_root,ACCESS_CONFIG_FILE,access_confname);
  56.     make_full_path(server_root,TYPES_CONFIG_FILE,types_confname);
  57.  
  58.     timeout = DEFAULT_TIMEOUT;
  59.     do_rfc931 = DEFAULT_RFC931;
  60. #ifdef PEM_AUTH
  61.     auth_pem_encrypt[0] = '\0';
  62.     auth_pem_decrypt[0] = '\0';
  63.     auth_pem_entity[0] = '\0';
  64.     auth_pgp_encrypt[0] = '\0';
  65.     auth_pgp_decrypt[0] = '\0';
  66.     auth_pgp_entity[0] = '\0';
  67. #endif
  68.  
  69.     if(!(cfg = fopen(server_confname,"r"))) {
  70.         fprintf(errors,"httpd: could not open server config. file %s\n",server_confname);
  71.         perror("fopen");
  72.         exit(1);
  73.     }
  74.     /* Parse server config file. Remind me to learn yacc. */
  75.     while(!(cfg_getline(l,MAX_STRING_LEN,cfg))) {
  76.         ++n;
  77.         if((l[0] != '#') && (l[0] != '\0')) {
  78.             cfg_getword(w,l);
  79.             
  80.             if(!strcasecmp(w,"ServerType")) {
  81.                 if(!strcasecmp(l,"inetd")) standalone=0;
  82.                 else if(!strcasecmp(l,"standalone")) standalone=1;
  83.                 else {
  84.                     fprintf(errors,"Syntax error on line %d of %s:\n",n,server_confname);
  85.                     fprintf(errors,"ServerType is either inetd or standalone.\n");
  86.                     exit(1);
  87.                 }
  88.             }
  89.             else if(!strcasecmp(w,"Port")) {
  90.                 cfg_getword(w,l);
  91.                 port = atoi(w);
  92.             }
  93.             else if(!strcasecmp(w,"User")) {
  94.                 cfg_getword(w,l);
  95.                 user_id = uname2id(w);
  96.             } 
  97.             else if(!strcasecmp(w,"Group")) {
  98.                 cfg_getword(w,l);
  99.                 group_id = gname2id(w);
  100.             }
  101.             else if(!strcasecmp(w,"ServerAdmin")) {
  102.                 cfg_getword(w,l);
  103.                 strcpy(server_admin,w);
  104.             }
  105.             else if(!strcasecmp(w,"ServerName")) {
  106.                 cfg_getword(w,l);
  107.                 if(server_hostname)
  108.                     free(server_hostname);
  109.                 if(!(server_hostname = strdup(w)))
  110.                     die(NO_MEMORY,"process_resource_config",errors);
  111.             }
  112.             else if(!strcasecmp(w,"ServerRoot")) {
  113.                 cfg_getword(w,l);
  114.                 if(!is_directory(w)) {
  115.                     fprintf(errors,"Syntax error on line %d of %s:\n",n,server_confname);
  116.                     fprintf(errors,"%s is not a valid directory.\n",w);
  117.                     exit(1);
  118.                 }
  119.                 strcpy(server_root,w);
  120.           make_full_path(server_root,DEFAULT_ERRORLOG,error_fname);
  121.           make_full_path(server_root,DEFAULT_XFERLOG,xfer_fname);
  122.           make_full_path(server_root,DEFAULT_PIDLOG,pid_fname);
  123.           make_full_path(server_root,RESOURCE_CONFIG_FILE,srm_confname);
  124.           make_full_path(server_root,ACCESS_CONFIG_FILE,access_confname);
  125.           make_full_path(server_root,TYPES_CONFIG_FILE,types_confname);
  126.             }
  127.             else if(!strcasecmp(w,"ErrorLog")) {
  128.                 cfg_getword(w,l);
  129.                 if(w[0] != '/')
  130.                     make_full_path(server_root,w,error_fname);
  131.                 else 
  132.                     strcpy(error_fname,w);
  133.             } 
  134.             else if(!strcasecmp(w,"TransferLog")) {
  135.                 cfg_getword(w,l);
  136.                 if(w[0] != '/')
  137.                     make_full_path(server_root,w,xfer_fname);
  138.                 else strcpy(xfer_fname,w);
  139.             }
  140.             else if(!strcasecmp(w,"PidFile")) {
  141.                 cfg_getword(w,l);
  142.                 if(w[0] != '/')
  143.                     make_full_path(server_root,w,pid_fname);
  144.                 else strcpy(pid_fname,w);
  145.             }
  146.             else if(!strcasecmp(w,"AccessConfig")) {
  147.                 cfg_getword(w,l);
  148.                 if(w[0] != '/')
  149.                     make_full_path(server_root,w,access_confname);
  150.                 else strcpy(access_confname,w);
  151.             }
  152.             else if(!strcasecmp(w,"ResourceConfig")) {
  153.                 cfg_getword(w,l);
  154.                 if(w[0] != '/')
  155.                     make_full_path(server_root,w,srm_confname);
  156.                 else strcpy(srm_confname,w);
  157.             }
  158.             else if(!strcasecmp(w,"TypesConfig")) {
  159.                 cfg_getword(w,l);
  160.                 if(w[0] != '/')
  161.                     make_full_path(server_root,w,types_confname);
  162.                 else strcpy(types_confname,w);
  163.             }
  164.             else if(!strcasecmp(w,"Timeout"))
  165.                 timeout = atoi(l);
  166.             else if(!strcasecmp(w,"IdentityCheck")) {
  167.                 cfg_getword(w,l);
  168.                 if(!strcasecmp(w,"on"))
  169.                     do_rfc931 = 1;
  170.                 else if(!strcasecmp(w,"off"))
  171.                     do_rfc931 = 0;
  172.                 else {
  173.                     fprintf(errors,"Syntax error on line %d of %s:\n",n,
  174.                             srm_confname);
  175.                     fprintf(errors,"IdentityCheck must be on or off.\n");
  176.                 }
  177.             }
  178. #ifdef PEM_AUTH
  179.             else if(!strcasecmp(w,"PEMEncryptCmd")) {
  180.                 cfg_getword(w,l);
  181.                 strcpy(auth_pem_encrypt,w);
  182.             }
  183.             else if(!strcasecmp(w,"PEMDecryptCmd")) {
  184.                 cfg_getword(w,l);
  185.                 strcpy(auth_pem_decrypt,w);
  186.             }
  187.             else if(!strcasecmp(w,"PEMServerEntity")) {
  188.                 cfg_getword(w,l);
  189.                 strcpy(auth_pem_entity,w);
  190.             }
  191.             else if(!strcasecmp(w,"PGPEncryptCmd")) {
  192.                 cfg_getword(w,l);
  193.                 strcpy(auth_pgp_encrypt,w);
  194.             }
  195.             else if(!strcasecmp(w,"PGPDecryptCmd")) {
  196.                 cfg_getword(w,l);
  197.                 strcpy(auth_pgp_decrypt,w);
  198.             }
  199.             else if(!strcasecmp(w,"PGPServerEntity")) {
  200.                 cfg_getword(w,l);
  201.                 strcpy(auth_pgp_entity,w);
  202.             }
  203. #endif
  204.             else {
  205.                 fprintf(errors,"Syntax error on line %d of %s:\n",n,server_confname);
  206.                 fprintf(errors,"Unknown keyword %s.\n",w);
  207.                 exit(1);
  208.             }
  209.         }
  210.     }
  211.     fclose(cfg);
  212. }
  213.  
  214. /* Document config globals */
  215. char user_dir[MAX_STRING_LEN];
  216. char index_name[MAX_STRING_LEN];
  217. char access_name[MAX_STRING_LEN];
  218. char document_root[MAX_STRING_LEN];
  219. char default_type[MAX_STRING_LEN];
  220. char default_icon[MAX_STRING_LEN];
  221.  
  222. void process_resource_config(FILE *errors) {
  223.     FILE *cfg;
  224.     char l[MAX_STRING_LEN],w[MAX_STRING_LEN];
  225.     int n=0;
  226.  
  227.     strcpy(user_dir,DEFAULT_USER_DIR);
  228.     strcpy(index_name,DEFAULT_INDEX);
  229.     strcpy(access_name,DEFAULT_ACCESS_FNAME);
  230.     strcpy(document_root,DOCUMENT_LOCATION);
  231.     strcpy(default_type,DEFAULT_TYPE);
  232.     default_icon[0] = '\0';
  233.  
  234.     add_opts_int(0,"/",errors);
  235.  
  236.     if(!(cfg = fopen(srm_confname,"r"))) {
  237.         fprintf(errors,"httpd: could not open document config. file %s\n",
  238.                 srm_confname);
  239.         perror("fopen");
  240.         exit(1);
  241.     }
  242.  
  243.     while(!(cfg_getline(l,MAX_STRING_LEN,cfg))) {
  244.         ++n;
  245.         if((l[0] != '#') && (l[0] != '\0')) {
  246.             cfg_getword(w,l);
  247.             
  248.             if(!strcasecmp(w,"ScriptAlias")) {
  249.                 char w2[MAX_STRING_LEN];
  250.             
  251.                 cfg_getword(w,l);
  252.                 cfg_getword(w2,l);
  253.                 if((w[0] == '\0') || (w2[0] == '\0')) {
  254.                     fprintf(errors,"Syntax error on line %d of %s:\n",n,
  255.                             srm_confname);
  256.                     fprintf(errors,
  257. "ScriptAlias must be followed by a fakename, one space, then a realname.\n");
  258.                     exit(1);
  259.                 }                
  260.                 add_alias(w,w2,SCRIPT_CGI);
  261.             }
  262.             else if(!strcasecmp(w,"OldScriptAlias")) {
  263.                 char w2[MAX_STRING_LEN];
  264.             
  265.                 cfg_getword(w,l);
  266.                 cfg_getword(w2,l);
  267.                 if((w[0] == '\0') || (w2[0] == '\0')) {
  268.                     fprintf(errors,"Syntax error on line %d of %s:\n",n,
  269.                             srm_confname);
  270.                     fprintf(errors,
  271. "ScriptAlias must be followed by a fakename, one space, then a realname.\n");
  272.                     exit(1);
  273.                 }                
  274.                 add_alias(w,w2,SCRIPT_NCSA);
  275.             }
  276.             else if(!strcasecmp(w,"UserDir")) {
  277.                 cfg_getword(w,l);
  278.                 if(!strcmp(w,"DISABLED"))
  279.                     user_dir[0] = '\0';
  280.                 else
  281.                     strcpy(user_dir,w);
  282.             }
  283.             else if(!strcasecmp(w,"DirectoryIndex")) {
  284.                 cfg_getword(w,l);
  285.                 strcpy(index_name,w);
  286.             } 
  287.             else if(!strcasecmp(w,"DefaultType")) {
  288.                 cfg_getword(w,l);
  289.                 strcpy(default_type,w);
  290.             }
  291.             else if(!strcasecmp(w,"AccessFileName")) {
  292.                 cfg_getword(w,l);
  293.                 strcpy(access_name,w);
  294.             } 
  295.             else if(!strcasecmp(w,"DocumentRoot")) {
  296.                 cfg_getword(w,l);
  297.                 if(!is_directory(w)) {
  298.                     fprintf(errors,"Syntax error on line %d of %s:\n",n,
  299.                             srm_confname);
  300.                     fprintf(errors,"%s is not a valid directory.\n",w);
  301.                     exit(1);
  302.                 }
  303.                 strcpy(document_root,w);
  304.             } 
  305.             else if(!strcasecmp(w,"Alias")) {
  306.                 char w2[MAX_STRING_LEN];
  307.         
  308.                 cfg_getword(w,l);
  309.                 cfg_getword(w2,l);
  310.                 if((w[0] == '\0') || (w2[0] == '\0')) {
  311.                     fprintf(errors,"Syntax error on line %d of %s:\n",n,
  312.                             srm_confname);
  313.                     fprintf(errors,
  314. "Alias must be followed by a fakename, one space, then a realname.\n");
  315.                     exit(1);
  316.                 }                
  317.                 add_alias(w,w2,STD_DOCUMENT);
  318.             }
  319.             else if(!strcasecmp(w,"AddType")) {
  320.                 char w2[MAX_STRING_LEN];
  321.                 cfg_getword(w,l);
  322.                 cfg_getword(w2,l);
  323.                 if((w[0] == '\0') || (w2[0] == '\0')) {
  324.                     fprintf(errors,"Syntax error on line %d of %s:\n",n,
  325.                             srm_confname);
  326.                     fprintf(errors,
  327. "AddType must be followed by a type, one space, then a file or extension.\n");
  328.                     exit(1);
  329.                 }
  330.                 add_type(w2,w,errors);
  331.             }
  332.             else if(!strcasecmp(w,"AddEncoding")) {
  333.                 char w2[MAX_STRING_LEN];
  334.                 cfg_getword(w,l);
  335.                 cfg_getword(w2,l);
  336.                 if((w[0] == '\0') || (w2[0] == '\0')) {
  337.                     fprintf(errors,"Syntax error on line %d of %s:\n",n,
  338.                             srm_confname);
  339.                     fprintf(errors,
  340. "AddEncoding must be followed by a type, one space, then a file or extension.\n");
  341.                     exit(1);
  342.                 }
  343.                 add_encoding(w2,w,errors);
  344.             }
  345.             else if(!strcasecmp(w,"Redirect")) {
  346.                 char w2[MAX_STRING_LEN];
  347.                 cfg_getword(w,l);
  348.                 cfg_getword(w2,l);
  349.                 if((w[0] == '\0') || (w2[0] == '\0') || (!is_url(w2))) {
  350.                     fprintf(errors,"Syntax error on line %d of %s:\n",n,
  351.                             srm_confname);
  352.                     fprintf(errors,
  353. "Redirect must be followed by a document, one space, then a URL.\n");
  354.                     exit(1);
  355.                 }
  356.                 add_redirect(w,w2);
  357.             }
  358.             else if(!strcasecmp(w,"FancyIndexing")) {
  359.                 cfg_getword(w,l);
  360.                 if(!strcmp(w,"on"))
  361.                     add_opts_int(FANCY_INDEXING,"/",errors);
  362.                 else if(!strcmp(w,"off"))
  363.                     add_opts_int(0,"/",errors);
  364.                 else {
  365.                     fprintf(errors,"Syntax error on line %d of %s:\n",n,
  366.                             srm_confname);
  367.                     fprintf(errors,"FancyIndexing must be on or off.\n");
  368.                     exit(1);
  369.                 }
  370.             }
  371.             else if(!strcasecmp(w,"AddDescription")) {
  372.                 char desc[MAX_STRING_LEN];
  373.                 int fq;
  374.                 if((fq = ind(l,'\"')) == -1) {
  375.                     fprintf(errors,"Syntax error on line %d of %s:\n",n,
  376.                             srm_confname);
  377. fprintf(errors,"AddDescription must have quotes around the description.\n");
  378.                     exit(1);
  379.                 }
  380.                 else {
  381.                     getword(desc,&l[++fq],'\"');
  382.                     cfg_getword(w,&l[fq]);
  383.                     add_desc(BY_PATH,desc,w,"/",errors);
  384.                 }
  385.             }
  386.             else if(!strcasecmp(w,"IndexIgnore")) {
  387.                 while(l[0]) {
  388.                     cfg_getword(w,l);
  389.                     add_ignore(w,"/",errors);
  390.                 }
  391.             }
  392.             else if(!strcasecmp(w,"AddIcon")) {
  393.                 char w2[MAX_STRING_LEN];
  394.                 cfg_getword(w2,l);
  395.                 while(l[0]) {
  396.                     cfg_getword(w,l);
  397.                     add_icon(BY_PATH,w2,w,"/",errors);
  398.                 }
  399.             }
  400.             else if(!strcasecmp(w,"AddIconByType")) {
  401.                 char w2[MAX_STRING_LEN];
  402.                 cfg_getword(w2,l);
  403.                 while(l[0]) {
  404.                     cfg_getword(w,l);
  405.                     add_icon(BY_TYPE,w2,w,"/",errors);
  406.                 }
  407.             }
  408.             else if(!strcasecmp(w,"AddIconByEncoding")) {
  409.                 char w2[MAX_STRING_LEN];
  410.                 cfg_getword(w2,l);
  411.                 while(l[0]) {
  412.                     cfg_getword(w,l);
  413.                     add_icon(BY_ENCODING,w2,w,"/",errors);
  414.                 }
  415.             }
  416.             else if(!strcasecmp(w,"AddAlt")) {
  417.                 char w2[MAX_STRING_LEN];
  418.                 cfg_getword(w2,l);
  419.                 while(l[0]) {
  420.                     cfg_getword(w,l);
  421.                     add_alt(BY_PATH,w2,w,"/",errors);
  422.                 }
  423.             }
  424.             else if(!strcasecmp(w,"AddAltByType")) {
  425.                 char w2[MAX_STRING_LEN];
  426.                 cfg_getword(w2,l);
  427.                 while(l[0]) {
  428.                     cfg_getword(w,l);
  429.                     add_alt(BY_TYPE,w2,w,"/",errors);
  430.                 }
  431.             }
  432.             else if(!strcasecmp(w,"AddAltByEncoding")) {
  433.                 char w2[MAX_STRING_LEN];
  434.                 cfg_getword(w2,l);
  435.                 while(l[0]) {
  436.                     cfg_getword(w,l);
  437.                     add_alt(BY_ENCODING,w2,w,"/",errors);
  438.                 }
  439.             }
  440.             else if(!strcasecmp(w,"DefaultIcon")) {
  441.                 cfg_getword(w,l);
  442.                 strcpy(default_icon,w);
  443.             }
  444.             else if(!strcasecmp(w,"ReadmeName")) {
  445.                 cfg_getword(w,l);
  446.                 add_readme(w,"/",errors);
  447.             }
  448.             else if(!strcasecmp(w,"HeaderName")) {
  449.                 cfg_getword(w,l);
  450.                 add_header(w,"/",errors);
  451.             }
  452.             else if(!strcasecmp(w,"IndexOptions"))
  453.                 add_opts(l,"/",errors);
  454.             else {
  455.                 fprintf(errors,"Syntax error on line %d of %s:\n",n,
  456.                         srm_confname);
  457.                 fprintf(errors,"Unknown keyword %s.\n",w);
  458.                 exit(1);
  459.             }
  460.         }
  461.     }
  462.     fclose(cfg);
  463. }
  464.  
  465.  
  466. /* Auth Globals */
  467. char *auth_type;
  468. char *auth_name;
  469. char *auth_pwfile;
  470. char *auth_grpfile;
  471.  
  472. /* Access Globals*/
  473. int num_sec;
  474. security_data sec[MAX_SECURITY];
  475.  
  476. void access_syntax_error(int n, char *err, char *file, FILE *out) {
  477.     if(!file) {
  478.         fprintf(out,"Syntax error on line %d of access config. file.\n",n);
  479.         fprintf(out,"%s\n",err);
  480.         exit(1);
  481.     }
  482.     else {
  483.         char e[MAX_STRING_LEN];
  484.         sprintf(e,"httpd: syntax error or override violation in access control file %s, reason: %s",file,err);
  485.         die(SERVER_ERROR,e,out);
  486.     }
  487. }
  488.  
  489. int parse_access_dir(FILE *f, int line, char or, char *dir, 
  490.                      char *file, FILE *out) 
  491. {
  492.     char l[MAX_STRING_LEN];
  493.     char t[MAX_STRING_LEN];
  494.     char w[MAX_STRING_LEN];
  495.     char w2[MAX_STRING_LEN];
  496.     int n=line;
  497.     register int x,i;
  498.  
  499.     x = num_sec;
  500.  
  501.     sec[x].opts=OPT_UNSET;
  502.     sec[x].override = or;
  503.     if(!(sec[x].d = (char *)malloc((sizeof(char)) * (strlen(dir) + 2))))
  504.         die(NO_MEMORY,"parse_access_dir",out);
  505.     if(is_matchexp(dir))
  506.         strcpy(sec[x].d,dir);
  507.     else
  508.         strcpy_dir(sec[x].d,dir);
  509.  
  510.     sec[x].auth_type = NULL;
  511.     sec[x].auth_name = NULL;
  512.     sec[x].auth_pwfile = NULL;
  513.     sec[x].auth_grpfile = NULL;
  514.     for(i=0;i<METHODS;i++) {
  515.         sec[x].order[i] = DENY_THEN_ALLOW;
  516.         sec[x].num_allow[i]=0;
  517.         sec[x].num_deny[i]=0;
  518.         sec[x].num_auth[i] = 0;
  519.     }
  520.  
  521.     while(!(cfg_getline(l,MAX_STRING_LEN,f))) {
  522.         ++n;
  523.         if((l[0] == '#') || (!l[0])) continue;
  524.         cfg_getword(w,l);
  525.  
  526.         if(!strcasecmp(w,"AllowOverride")) {
  527.             if(file)
  528.                 access_syntax_error(n,"override violation",file,out);
  529.             sec[x].override = OR_NONE;
  530.             while(l[0]) {
  531.                 cfg_getword(w,l);
  532.                 if(!strcasecmp(w,"Limit"))
  533.                     sec[x].override |= OR_LIMIT;
  534.                 else if(!strcasecmp(w,"Options"))
  535.                     sec[x].override |= OR_OPTIONS;
  536.                 else if(!strcasecmp(w,"FileInfo"))
  537.                     sec[x].override |= OR_FILEINFO;
  538.                 else if(!strcasecmp(w,"AuthConfig"))
  539.                     sec[x].override |= OR_AUTHCFG;
  540.                 else if(!strcasecmp(w,"Indexes"))
  541.                     sec[x].override |= OR_INDEXES;
  542.                 else if(!strcasecmp(w,"None"))
  543.                     sec[x].override = OR_NONE;
  544.                 else if(!strcasecmp(w,"All")) 
  545.                     sec[x].override = OR_ALL;
  546.                 else {
  547.                     access_syntax_error(n,
  548. "Unknown keyword in AllowOverride directive.",file,out);
  549.                 }
  550.             }
  551.         } 
  552.         else if(!strcasecmp(w,"Options")) {
  553.             if(!(or & OR_OPTIONS))
  554.                 access_syntax_error(n,"override violation",file,out);
  555.             sec[x].opts = OPT_NONE;
  556.             while(l[0]) {
  557.                 cfg_getword(w,l);
  558.                 if(!strcasecmp(w,"Indexes"))
  559.                     sec[x].opts |= OPT_INDEXES;
  560.                 else if(!strcasecmp(w,"Includes"))
  561.                     sec[x].opts |= OPT_INCLUDES;
  562.                 else if(!strcasecmp(w,"IncludesNOEXEC"))
  563.                     sec[x].opts |= (OPT_INCLUDES | OPT_INCNOEXEC);
  564.                 else if(!strcasecmp(w,"FollowSymLinks"))
  565.                     sec[x].opts |= OPT_SYM_LINKS;
  566.                 else if(!strcasecmp(w,"SymLinksIfOwnerMatch"))
  567.                     sec[x].opts |= OPT_SYM_OWNER;
  568.                 else if(!strcasecmp(w,"execCGI"))
  569.                     sec[x].opts |= OPT_EXECCGI;
  570.                 else if(!strcasecmp(w,"None")) 
  571.                     sec[x].opts = OPT_NONE;
  572.                 else if(!strcasecmp(w,"All")) 
  573.                     sec[x].opts = OPT_ALL;
  574.                 else {
  575.                     access_syntax_error(n,
  576. "Unknown keyword in Options directive.",file,out);
  577.                 }
  578.             }
  579.         }
  580.         else if(!strcasecmp(w,"AuthName")) {
  581.             if(!(or & OR_AUTHCFG))
  582.                 access_syntax_error(n,"override violation",file,out);
  583.             if(sec[x].auth_name) 
  584.                 free(sec[x].auth_name);
  585.             if(!(sec[x].auth_name = strdup(l)))
  586.                 die(NO_MEMORY,"parse_access_dir",out);
  587.         }
  588.         else if(!strcasecmp(w,"AuthType")) {
  589.             if(!(or & OR_AUTHCFG))
  590.                 access_syntax_error(n,"override violation",file,out);
  591.             cfg_getword(w,l);
  592.             if(sec[x].auth_type) 
  593.                 free(sec[x].auth_type);
  594.             if(!(sec[x].auth_type = strdup(w)))
  595.                 die(NO_MEMORY,"parse_access_dir",out);
  596.         }
  597.         else if(!strcasecmp(w,"AuthUserFile")) {
  598.             if(!(or & OR_AUTHCFG))
  599.                 access_syntax_error(n,"override violation",file,out);
  600.             cfg_getword(w,l);
  601.             if(sec[x].auth_pwfile) 
  602.                 free(sec[x].auth_pwfile);
  603.             if(!(sec[x].auth_pwfile = strdup(w)))
  604.                 die(NO_MEMORY,"parse_access_dir",out);
  605.         }
  606.         else if(!strcasecmp(w,"AuthGroupFile")) {
  607.             if(!(or & OR_AUTHCFG))
  608.                 access_syntax_error(n,"override violation",file,out);
  609.             cfg_getword(w,l);
  610.             if(sec[x].auth_grpfile) 
  611.                 free(sec[x].auth_grpfile);
  612.             if(!(sec[x].auth_grpfile = strdup(w)))
  613.                 die(NO_MEMORY,"parse_access_dir",out);
  614.         }
  615.         else if(!strcasecmp(w,"AddType")) {
  616.             if(!(or & OR_FILEINFO))
  617.                 access_syntax_error(n,"override violation",file,out);
  618.             cfg_getword(w,l);
  619.             cfg_getword(w2,l);
  620.             if((w[0] == '\0') || (w2[0] == '\0')) {
  621.                 access_syntax_error(n,
  622. "AddType must be followed by a type, one space, then a file or extension.",
  623.                                     file,out);
  624.             }
  625.             add_type(w2,w,out);
  626.         }
  627.         else if(!strcasecmp(w,"DefaultType")) {
  628.             if(!(or & OR_FILEINFO))
  629.                 access_syntax_error(n,"override violation",file,out);
  630.             cfg_getword(w,l);
  631.             strcpy(default_type,w);
  632.         }
  633.         else if(!strcasecmp(w,"AddEncoding")) {
  634.             if(!(or & OR_FILEINFO))
  635.                 access_syntax_error(n,"override violation",file,out);
  636.             cfg_getword(w,l);
  637.             cfg_getword(w2,l);
  638.             if((w[0] == '\0') || (w2[0] == '\0')) {
  639.                 access_syntax_error(n,
  640. "AddEncoding must be followed by a type, one space, then a file or extension.",
  641.                                     file,out);
  642.             }
  643.             add_encoding(w2,w,out);
  644.         }
  645.         else if(!strcasecmp(w,"DefaultIcon")) {
  646.             if(!(or & OR_INDEXES))
  647.                 access_syntax_error(n,"override violation",file,out);
  648.             cfg_getword(w,l);
  649.             strcpy(default_icon,w);
  650.         }
  651.         else if(!strcasecmp(w,"AddDescription")) {
  652.             char desc[MAX_STRING_LEN];
  653.             int fq;
  654.             
  655.             if(!(or & OR_INDEXES))
  656.                 access_syntax_error(n,"override violation",file,out);
  657.             if((fq = ind(l,'\"')) == -1)
  658.                 access_syntax_error(n,"AddDescription must have quotes",
  659.                                     file,out);
  660.             else {
  661.                 getword(desc,&l[++fq],'\"');
  662.                 cfg_getword(w,&l[fq]);
  663.                 add_desc(BY_PATH,desc,w,sec[x].d,out);
  664.             }
  665.         }
  666.         else if(!strcasecmp(w,"IndexIgnore")) {
  667.             if(!(or & OR_INDEXES))
  668.                 access_syntax_error(n,"override violation",file,out);
  669.             while(l[0]) {
  670.                 cfg_getword(w,l);
  671.                 add_ignore(w,sec[x].d,out);
  672.             }
  673.         }
  674.         else if(!strcasecmp(w,"AddIcon")) {
  675.             char w2[MAX_STRING_LEN];
  676.             
  677.             if(!(or & OR_INDEXES))
  678.                 access_syntax_error(n,"override violation",file,out);
  679.             cfg_getword(w2,l);
  680.             while(l[0]) {
  681.                 cfg_getword(w,l);
  682.                 add_icon(BY_PATH,w2,w,sec[x].d,out);
  683.             }
  684.         }
  685.         else if(!strcasecmp(w,"AddIconByType")) {
  686.             char w2[MAX_STRING_LEN];
  687.             
  688.             if(!(or & OR_INDEXES))
  689.                 access_syntax_error(n,"override violation",file,out);
  690.             cfg_getword(w2,l);
  691.             while(l[0]) {
  692.                 cfg_getword(w,l);
  693.                 add_icon(BY_TYPE,w2,w,sec[x].d,out);
  694.             }
  695.         }
  696.         else if(!strcasecmp(w,"AddIconByEncoding")) {
  697.             char w2[MAX_STRING_LEN];
  698.             
  699.             if(!(or & OR_INDEXES))
  700.                 access_syntax_error(n,"override violation",file,out);
  701.             cfg_getword(w2,l);
  702.             while(l[0]) {
  703.                 cfg_getword(w,l);
  704.                 add_icon(BY_ENCODING,w2,w,sec[x].d,out);
  705.             }
  706.         }
  707.         else if(!strcasecmp(w,"ReadmeName")) {
  708.             if(!(or & OR_INDEXES))
  709.                 access_syntax_error(n,"override violation",file,out);
  710.             cfg_getword(w,l);
  711.             add_readme(w,sec[x].d,out);
  712.         }
  713.         else if(!strcasecmp(w,"HeaderName")) {
  714.             if(!(or & OR_INDEXES))
  715.                 access_syntax_error(n,"override violation",file,out);
  716.             cfg_getword(w,l);
  717.             add_header(w,sec[x].d,out);
  718.         }
  719.         else if(!strcasecmp(w,"IndexOptions")) {
  720.             if(!(or & OR_INDEXES))
  721.                 access_syntax_error(n,"override violation",file,out);
  722.             add_opts(l,sec[x].d,out);
  723.         }
  724.         else if(!strcasecmp(w,"Redirect")) {
  725.             if(!(or & OR_FILEINFO))
  726.                 access_syntax_error(n,"override violation",file,out);
  727.             cfg_getword(w,l);
  728.             cfg_getword(w2,l);
  729.             if((w[0] == '\0') || (w2[0] == '\0') || (!is_url(w2))) {
  730.                 access_syntax_error(n,
  731. "Redirect must be followed by a document, one space, then a URL.",file,out);
  732.             }
  733.             if(!file)
  734.                 add_redirect(w,w2);
  735.             else
  736.                 access_syntax_error(n,
  737. "Redirect no longer supported from .htaccess files.",file,out);
  738.         }
  739.         else if(!strcasecmp(w,"<Limit")) {
  740.             int m[METHODS];
  741.  
  742.             if(!(or & OR_LIMIT))
  743.                 access_syntax_error(n,"override violation",file,out);
  744.             for(i=0;i<METHODS;i++) m[i] = 0;
  745.             getword(w2,l,'>');
  746.             while(w2[0]) {
  747.                 cfg_getword(w,w2);
  748.                 if(!strcasecmp(w,"GET")) m[M_GET]=1;
  749.                 else if(!strcasecmp(w,"PUT")) m[M_PUT]=1;
  750.                 else if(!strcasecmp(w,"POST")) m[M_POST]=1;
  751.                 else if(!strcasecmp(w,"DELETE")) m[M_DELETE]=1;
  752.             }
  753.             while(1) {
  754.                 if(cfg_getline(l,MAX_STRING_LEN,f))
  755.                     access_syntax_error(n,"Limit missing /Limit",file,out);
  756.                 n++;
  757.                 if((l[0] == '#') || (!l[0])) continue;
  758.  
  759.                 if(!strcasecmp(l,"</Limit>"))
  760.                     break;
  761.                 cfg_getword(w,l);
  762.                 if(!strcasecmp(w,"order")) {
  763.                     if(!strcasecmp(l,"allow,deny")) {
  764.                         for(i=0;i<METHODS;i++)
  765.                             if(m[i])
  766.                                 sec[x].order[i] = ALLOW_THEN_DENY;
  767.                     }
  768.                     else if(!strcasecmp(l,"deny,allow")) {
  769.                         for(i=0;i<METHODS;i++)
  770.                             if(m[i]) 
  771.                                 sec[x].order[i] = DENY_THEN_ALLOW;
  772.                     }
  773.                     else if(!strcasecmp(l,"mutual-failure")) {
  774.                         for(i=0;i<METHODS;i++)
  775.                             if(m[i]) 
  776.                                 sec[x].order[i] = MUTUAL_FAILURE;
  777.                     }
  778.                     else
  779.                         access_syntax_error(n,"Unknown order.",file,out);
  780.                 } 
  781.                 else if((!strcasecmp(w,"allow"))) {
  782.                     cfg_getword(w,l);
  783.                     if(strcmp(w,"from"))
  784.                         access_syntax_error(n,
  785.                                             "allow must be followed by from.",
  786.                                             file,out);
  787.                     while(1) {
  788.                         cfg_getword(w,l);
  789.                         if(!w[0]) break;
  790.                         for(i=0;i<METHODS;i++)
  791.                             if(m[i]) {
  792.                                 int q=sec[x].num_allow[i]++;
  793.                                 if(!(sec[x].allow[i][q] = strdup(w)))
  794.                                     die(NO_MEMORY,"parse_access_dir",out);
  795.                             }
  796.                     }
  797.                 }
  798.                 else if(!strcasecmp(w,"require")) {
  799.                     for(i=0;i<METHODS;i++)
  800.                         if(m[i]) {
  801.                             int q=sec[x].num_auth[i]++;
  802.                             if(!(sec[x].auth[i][q] = strdup(l)))
  803.                                 die(NO_MEMORY,"parse_access_dir",out);
  804.                         }
  805.                 }
  806.                 else if((!strcasecmp(w,"deny"))) {
  807.                     cfg_getword(w,l);
  808.                     if(strcmp(w,"from"))
  809.                         access_syntax_error(n,
  810.                                             "deny must be followed by from.",
  811.                                             file,out);
  812.                     while(1) {
  813.                         cfg_getword(w,l);
  814.                         if(!w[0]) break;
  815.                         for(i=0;i<METHODS;i++)
  816.                             if(m[i]) {
  817.                                 int q=sec[x].num_deny[i]++;
  818.                                 if(!(sec[x].deny[i][q] = strdup(w)))
  819.                                     die(NO_MEMORY,"parse_access_dir",out);
  820.                             }
  821.                     }
  822.                 }
  823.                 else
  824.                     access_syntax_error(n,"Unknown keyword in Limit region.",
  825.                                         file,out);
  826.             }
  827.         }
  828.         else if(!strcasecmp(w,"</Directory>"))
  829.             break;
  830.         else {
  831.             char errstr[MAX_STRING_LEN];
  832.             sprintf(errstr,"Unknown method %s",w);
  833.             access_syntax_error(n,errstr,file,out);
  834.             return;
  835.         }
  836.     }
  837.     ++num_sec;
  838.     return n;
  839. }
  840.  
  841.  
  842. void parse_htaccess(char *path, char override, FILE *out) {
  843.     FILE *f;
  844.     char t[MAX_STRING_LEN];
  845.     char d[MAX_STRING_LEN];
  846.     int x;
  847.  
  848.     strcpy(d,path);
  849.     make_full_path(d,access_name,t);
  850.  
  851.     if((f=fopen(t,"r"))) {
  852.         parse_access_dir(f,-1,override,d,t,out);
  853.         fclose(f);
  854.     }
  855. }
  856.  
  857.  
  858. void process_access_config(FILE *errors) {
  859.     FILE *f;
  860.     char l[MAX_STRING_LEN];
  861.     char w[MAX_STRING_LEN];
  862.     int n;
  863.  
  864.     num_sec = 0;n=0;
  865.     if(!(f=fopen(access_confname,"r"))) {
  866.         fprintf(errors,"httpd: could not open access configuration file %s.\n",
  867.                 access_confname);
  868.         perror("fopen");
  869.         exit(1);
  870.     }
  871.     while(!(cfg_getline(l,MAX_STRING_LEN,f))) {
  872.         ++n;
  873.         if((l[0] == '#') || (!l[0])) continue;
  874.         cfg_getword(w,l);
  875.         if(strcasecmp(w,"<Directory")) {
  876.             fprintf(errors,
  877.                     "Syntax error on line %d of access config. file.\n",n);
  878.             fprintf(errors,"Unknown directive %s.\n",w);
  879.             exit(1);
  880.         }
  881.         getword(w,l,'>');
  882.         n=parse_access_dir(f,n,OR_ALL,w,NULL,errors);
  883.     }
  884.     fclose(f);
  885. }
  886.  
  887. int get_pw(char *user, char *pw, FILE *errors) {
  888.     FILE *f;
  889.     char errstr[MAX_STRING_LEN];
  890.     char l[MAX_STRING_LEN];
  891.     char w[MAX_STRING_LEN];
  892.  
  893.     if(!(f=fopen(auth_pwfile,"r"))) {
  894.         sprintf(errstr,"Could not open user file %s",auth_pwfile);
  895.         die(SERVER_ERROR,errstr,errors);
  896.     }
  897.     while(!(cfg_getline(l,MAX_STRING_LEN,f))) {
  898.         if((l[0] == '#') || (!l[0])) continue;
  899.         getword(w,l,':');
  900.  
  901.         if(!strcmp(user,w)) {
  902.             strcpy(pw,l);
  903.             fclose(f);
  904.             return 1;
  905.         }
  906.     }
  907.     fclose(f);
  908.     return 0;
  909. }
  910.  
  911.  
  912. struct ge {
  913.     char *name;
  914.     char *members;
  915.     struct ge *next;
  916. };
  917.  
  918. static struct ge *grps;
  919.  
  920. int init_group(char *grpfile, FILE *out) {
  921.     FILE *f;
  922.     struct ge *p;
  923.     char l[MAX_STRING_LEN],w[MAX_STRING_LEN];
  924.  
  925.     if(!(f=fopen(grpfile,"r")))
  926.         return 0;
  927.  
  928.     grps = NULL;
  929.     while(!(cfg_getline(l,MAX_STRING_LEN,f))) {
  930.         if((l[0] == '#') || (!l[0])) continue;
  931.         getword(w,l,':');
  932.         if(!(p = (struct ge *) malloc (sizeof(struct ge))))
  933.             die(NO_MEMORY,"init_group",out);
  934.         if(!(p->name = strdup(w)))
  935.             die(NO_MEMORY,"init_group",out);
  936.         if(!(p->members = strdup(l)))
  937.             die(NO_MEMORY,"init_group",out);
  938.         p->next = grps;
  939.         grps = p;
  940.     }
  941.     fclose(f);
  942.     return 1;
  943. }
  944.  
  945. int in_group(char *user, char *group) {
  946.     struct ge *p = grps;
  947.     char l[MAX_STRING_LEN],w[MAX_STRING_LEN];
  948.  
  949.     while(p) {
  950.         if(!strcmp(p->name,group)) {
  951.             strcpy(l,p->members);
  952.             while(l[0]) {
  953.                 getword(w,l,' ');
  954.                 if(!strcmp(w,user))
  955.                     return 1;
  956.             }
  957.         }
  958.         p=p->next;
  959.     }
  960.     return 0;
  961. }
  962.  
  963. void kill_group() {
  964.     struct ge *p = grps, *q;
  965.  
  966.     while(p) {
  967.         free(p->name);
  968.         free(p->members);
  969.         q=p;
  970.         p=p->next;
  971.         free(q);
  972.     }   
  973. }
  974.  
  975. void read_config(FILE *errors)
  976. {
  977.     reset_aliases();
  978.     process_server_config(errors);
  979.     init_mime(errors);
  980.     init_indexing();
  981.     process_resource_config(errors);
  982.     process_access_config(errors);
  983. }
  984.