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