1 #include "compat.h" 2 #include "libconfig.h" 3 #include "libconfig_private.h" 4 #include "conf_apache.h" 5 6 #ifdef HAVE_CTYPE_H 7 #include <ctype.h> 8 #endif 9 10 #ifdef HAVE_STDIO_H 11 #include <stdio.h> 12 #endif 13 14 #ifdef HAVE_STRING_H 15 #include <string.h> 16 #endif 17 18 #ifdef HAVE_SYS_TYPES_H 19 #include <sys/types.h> 20 #endif 21 22 #ifdef HAVE_SYS_STAT_H 23 #include <sys/stat.h> 24 #endif 25 26 #ifdef HAVE_UNISTD_H 27 #include <unistd.h> 28 #endif 29 30 #ifdef HAVE_DIRENT_H 31 #include <dirent.h> 32 #endif 33 34 static int lc_process_conf_apache_file(const char *configfile, const char *pathprefix); 35 36 static int lc_process_conf_apache_include(const char *pathname, const char *pathprefix) { 37 struct stat pathinfo; 38 struct dirent *dinfo = NULL; 39 char includepath[LC_LINEBUF_LEN] = {0}; 40 DIR *dh = NULL; 41 int statret = -1, lcpcafret = -1; 42 int retval = 0; 43 44 statret = stat(pathname, &pathinfo); 45 if (statret < 0) { 46 return(-1); 47 } 48 49 if (S_ISDIR(pathinfo.st_mode)) { 50 dh = opendir(pathname); 51 if (dh == NULL) { 52 return(-1); 53 } 54 55 while (1) { 56 dinfo = readdir(dh); 57 if (dinfo == NULL) { 58 break; 59 } 60 61 /* Skip files that begin with a dot ('.') */ 62 if (dinfo->d_name[0] == '.') continue; 63 64 snprintf(includepath, sizeof(includepath) - 1, "%s/%s", pathname, dinfo->d_name); 65 lcpcafret = lc_process_conf_apache_include(includepath, pathprefix); 66 if (lcpcafret < 0) { 67 retval = -1; 68 /* XXX: should we break here (abort further including of files from a directory if one fails ?) */ 69 break; 70 } 71 } 72 73 closedir(dh); 74 } else { 75 lcpcafret = lc_process_conf_apache_file(pathname, pathprefix); 76 if (lcpcafret < 0) { 77 retval = -1; 78 } 79 } 80 81 return(retval); 82 } 83 84 static int lc_process_conf_apache_file(const char *configfile, const char *pathprefix) { 85 LC_FILE *configfp = NULL; 86 const char *local_lc_errfile; 87 char linebuf[LC_LINEBUF_LEN] = {0}, *linebuf_ptr = NULL, *tmp_ptr = NULL; 88 char *lastsection = NULL; 89 char qualifbuf[LC_LINEBUF_LEN] = {0}; 90 char *cmd = NULL, *value = NULL, *sep = NULL, *cmdend = NULL; 91 char *fgetsret = NULL; 92 int lcpvret = -1, lpcafret = -1; 93 int invalid_section = 0, ignore_section = 0; 94 int local_lc_errline; 95 int retval = 0; 96 lc_err_t save_lc_errno = LC_ERR_NONE; 97 98 if (pathprefix != NULL) { 99 /* Copy the prefix, if specified. */ 100 strncpy(qualifbuf, pathprefix, sizeof(qualifbuf) - 1); 101 } 102 103 local_lc_errfile = configfile; 104 local_lc_errline = 0; 105 106 if (configfile == NULL) { 107 lc_errfile = local_lc_errfile; 108 lc_errline = local_lc_errline; 109 lc_errno = LC_ERR_INVDATA; 110 return(-1); 111 } 112 113 configfp = lc_fopen(configfile, "r"); 114 115 if (configfp == NULL) { 116 lc_errfile = local_lc_errfile; 117 lc_errline = local_lc_errline; 118 lc_errno = LC_ERR_CANTOPEN; 119 return(-1); 120 } 121 122 while (1) { 123 fgetsret = lc_fgets(linebuf, sizeof(linebuf) - 1, configfp); 124 if (fgetsret == NULL) { 125 break; 126 } 127 if (lc_feof(configfp)) { 128 break; 129 } 130 131 local_lc_errline++; 132 133 /* Remove trailing crap (but not spaces). */ 134 linebuf_ptr = &linebuf[strlen(linebuf) - 1]; 135 while (*linebuf_ptr < ' ' && linebuf_ptr >= linebuf) { 136 *linebuf_ptr = '\0'; 137 linebuf_ptr--; 138 } 139 140 /* Remove leading spaces. */ 141 linebuf_ptr = &linebuf[0]; 142 while ((*linebuf_ptr == ' ' || *linebuf_ptr == '\t') && linebuf_ptr < (linebuf + sizeof(linebuf))) { 143 linebuf_ptr++; 144 } 145 146 /* Handle section header. */ 147 if (linebuf_ptr[0] == '<' && linebuf_ptr[strlen(linebuf_ptr) - 1] == '>' && linebuf_ptr < (linebuf + sizeof(linebuf))) { 148 /* Remove < and > from around the data. */ 149 linebuf_ptr[strlen(linebuf_ptr) - 1] = '\0'; 150 linebuf_ptr++; 151 152 /* Lowercase the command part of the section. */ 153 tmp_ptr = linebuf_ptr; 154 while (*tmp_ptr != '\0' && *tmp_ptr != ' ' && tmp_ptr < (linebuf + sizeof(linebuf))) { 155 *tmp_ptr = tolower(*tmp_ptr); 156 tmp_ptr++; 157 } 158 159 /* If this is a close section command, handle it */ 160 if (linebuf_ptr[0] == '/') { 161 linebuf_ptr++; 162 cmd = linebuf_ptr; 163 164 /* Find the last section closed. */ 165 tmp_ptr = strrchr(qualifbuf, '.'); 166 if (tmp_ptr == NULL) { 167 lastsection = qualifbuf; 168 tmp_ptr = qualifbuf; 169 } else { 170 lastsection = tmp_ptr + 1; 171 } 172 173 if (strcmp(cmd, lastsection) != 0) { 174 #ifdef DEBUG 175 fprintf(stderr, "Section closing does not match last opened section.\n"); 176 fprintf(stderr, "Last opened = \"%s\", Closing = \"%s\"\n", lastsection, cmd); 177 #endif 178 retval = -1; 179 lc_errfile = local_lc_errfile; 180 lc_errline = local_lc_errline; 181 lc_errno = LC_ERR_BADFORMAT; 182 183 /* For this error, we abort immediately. */ 184 break; 185 } 186 187 lcpvret = lc_process_var(qualifbuf, NULL, NULL, LC_FLAGS_SECTIONEND); 188 if (lcpvret < 0) { 189 #ifdef DEBUG 190 fprintf(stderr, "Invalid section terminating: \"%s\"\n", qualifbuf); 191 #endif 192 } 193 194 /* Remove the "lastsection" part.. */ 195 *tmp_ptr = '\0'; 196 197 /* We just sucessfully closed the last section opened, 198 we must be in a valid section now since we only open 199 sections from within valid sections. */ 200 invalid_section = 0; 201 ignore_section = 0; 202 203 continue; 204 } 205 /* Otherwise, open a new section. */ 206 207 /* Don't open a section from an invalid section. */ 208 if (invalid_section == 1 || ignore_section == 1) { 209 continue; 210 } 211 212 /* Parse out any argument passed. */ 213 sep = strpbrk(linebuf_ptr, " \t"); 214 215 if (sep != NULL) { 216 cmdend = sep; 217 /* Delete space at the end of the command. */ 218 cmdend--; /* It currently derefs to the seperator.. */ 219 while (*cmdend <= ' ') { 220 *cmdend = '\0'; 221 cmdend--; 222 } 223 224 /* Delete the seperator char and any leading space. */ 225 *sep = '\0'; 226 sep++; 227 while (*sep == ' ' || *sep == '\t') { 228 sep++; 229 } 230 value = sep; 231 } else { 232 /* XXX: should this be "" or NULL ? */ 233 value = ""; 234 } 235 236 cmd = linebuf_ptr; 237 238 if (qualifbuf[0] != '\0') { 239 strncat(qualifbuf, ".", sizeof(qualifbuf) - strlen(qualifbuf) - 1); 240 } 241 strncat(qualifbuf, cmd, sizeof(qualifbuf) - strlen(qualifbuf) - 1); 242 243 lcpvret = lc_process_var(qualifbuf, value, NULL, LC_FLAGS_SECTIONSTART); 244 if (lcpvret < 0) { 245 #ifdef DEBUG 246 fprintf(stderr, "Invalid section: \"%s\"\n", qualifbuf); 247 #endif 248 invalid_section = 1; 249 lc_errfile = local_lc_errfile; 250 lc_errline = local_lc_errline; 251 lc_errno = LC_ERR_INVSECTION; 252 retval = -1; 253 } 254 if (lcpvret == LC_CBRET_IGNORESECTION) { 255 ignore_section = 1; 256 } 257 continue; 258 } 259 260 /* Drop comments and blank lines. */ 261 if (*linebuf_ptr == '#' || *linebuf_ptr == '\0') { 262 continue; 263 } 264 265 /* Don't handle things for a section that doesn't exist. */ 266 if (invalid_section == 1) { 267 #ifdef DEBUG 268 fprintf(stderr, "Ignoring line (because invalid section): %s\n", linebuf); 269 #endif 270 continue; 271 } 272 if (ignore_section == 1) { 273 #ifdef DEBUG 274 fprintf(stderr, "Ignoring line (because ignored section): %s\n", linebuf); 275 #endif 276 continue; 277 } 278 279 /* Find the command and the data in the line. */ 280 sep = strpbrk(linebuf_ptr, " \t"); 281 if (sep != NULL) { 282 cmdend = sep; 283 284 /* Delete space at the end of the command. */ 285 cmdend--; /* It currently derefs to the seperator.. */ 286 while (*cmdend <= ' ' && cmdend >= sep) { 287 *cmdend = '\0'; 288 cmdend--; 289 } 290 291 /* Delete the seperator char and any leading space. */ 292 *sep = '\0'; 293 sep++; 294 while (*sep == ' ' || *sep == '\t') { 295 sep++; 296 } 297 value = sep; 298 } else { 299 value = NULL; 300 } 301 302 cmd = linebuf_ptr; 303 304 /* Handle special commands. */ 305 if (strcasecmp(cmd, "include") == 0) { 306 if (value == NULL) { 307 lc_errfile = local_lc_errfile; 308 lc_errline = local_lc_errline; 309 lc_errno = LC_ERR_BADFORMAT; 310 retval = -1; 311 #ifdef DEBUG 312 fprintf(stderr, "Invalid include command.\n"); 313 #endif 314 continue; 315 } 316 317 lpcafret = lc_process_conf_apache_include(value, qualifbuf); 318 if (lpcafret < 0) { 319 #ifdef DEBUG 320 fprintf(stderr, "Error in included file.\n"); 321 #endif 322 retval = -1; 323 } 324 continue; 325 } 326 327 /* Create the fully qualified variable name. */ 328 if (qualifbuf[0] != '\0') { 329 strncat(qualifbuf, ".", sizeof(qualifbuf) - strlen(qualifbuf) - 1); 330 } 331 strncat(qualifbuf, cmd, sizeof(qualifbuf) - strlen(qualifbuf) - 1); 332 333 /* Call the parent and tell them we have data. */ 334 save_lc_errno = lc_errno; 335 lc_errno = LC_ERR_NONE; 336 lcpvret = lc_process_var(qualifbuf, NULL, value, LC_FLAGS_VAR); 337 if (lcpvret < 0) { 338 if (lc_errno == LC_ERR_NONE) { 339 #ifdef DEBUG 340 fprintf(stderr, "Invalid command: \"%s\"\n", cmd); 341 #endif 342 lc_errfile = local_lc_errfile; 343 lc_errline = local_lc_errline; 344 lc_errno = LC_ERR_INVCMD; 345 } else { 346 #ifdef DEBUG 347 fprintf(stderr, "Error processing command (command was valid, but an error occured, errno was set)\n"); 348 #endif 349 } 350 lc_errfile = local_lc_errfile; 351 lc_errline = local_lc_errline; 352 retval = -1; 353 break; 354 } else { 355 lc_errno = save_lc_errno; 356 } 357 358 /* Remove the "cmd" part of the buffer. */ 359 tmp_ptr = strrchr(qualifbuf, '.'); 360 if (tmp_ptr == NULL) { 361 tmp_ptr = qualifbuf; 362 } 363 *tmp_ptr = '\0'; 364 } 365 366 lc_fclose(configfp); 367 368 return(retval); 369 } 370 371 int lc_process_conf_apache(const char *appname, const char *configfile) { 372 return(lc_process_conf_apache_file(configfile, NULL)); 373 } |