1 /*
2  * $Id: fcgi_config.c,v 1.54 2009/09/28 12:33:14 robs Exp $
3  */
4 
5 #define CORE_PRIVATE
6 #include "fcgi.h"
7 
8 #ifdef APACHE2
9 
10 #include <limits.h>
11 #include "mpm_common.h"     /* ap_uname2id, ap_gname2id */
12 
13 #ifdef WIN32
14 #include <direct.h>
15 #else
16 #include <unistd.h>
17 #include "unixd.h"
18 #endif
19 
20 #endif
21 
22 #ifdef WIN32
23 /* warning C4100: unreferenced formal parameter */
24 /* warning C4706: assignment within conditional expression */
25 #pragma warning( disable : 4100 4706 )
26 #endif
27 
28 /*******************************************************************************
29  * Get the next configuration directive argument, & return an in_addr and port.
30  * The arg must be in the form "host:port" where host can be an IP or hostname.
31  * The pool arg should be persistant storage.
32  */
get_host_n_port(pool * p,const char ** arg,const char ** host,u_short * port)33 static const char *get_host_n_port(pool *p, const char **arg,
34         const char **host, u_short *port)
35 {
36     char *cvptr, *portStr;
37     long tmp;
38 
39     *host = ap_getword_conf(p, arg);
40     if (**host == '\0')
41         return "\"\"";
42 
43     portStr = strchr(*host, ':');
44     if (portStr == NULL)
45         return "missing port specification";
46 
47     /* Split the host and port portions */
48     *portStr++ = '\0';
49 
50     /* Convert port number */
51     tmp = (u_short) strtol(portStr, &cvptr, 10);
52     if (*cvptr != '\0' || tmp < 1 || tmp > USHRT_MAX)
53         return ap_pstrcat(p, "bad port number \"", portStr, "\"", NULL);
54 
55     *port = (unsigned short) tmp;
56 
57     return NULL;
58 }
59 
60 /*******************************************************************************
61  * Get the next configuration directive argument, & return an u_short.
62  * The pool arg should be temporary storage.
63  */
get_u_short(pool * p,const char ** arg,u_short * num,u_short min)64 static const char *get_u_short(pool *p, const char **arg,
65         u_short *num, u_short min)
66 {
67     char *ptr;
68 	long tmp;
69     const char *txt = ap_getword_conf(p, arg);
70 
71     if (*txt == '\0') {
72 		return "\"\"";
73 	}
74 
75     tmp = strtol(txt, &ptr, 10);
76 
77     if (*ptr != '\0') {
78         return ap_pstrcat(p, "\"", txt, "\" must be a positive integer", NULL);
79 	}
80 
81 	if (tmp < min || tmp > USHRT_MAX) {
82         return ap_psprintf(p, "\"%u\" must be >= %u and < %u", *num, min, USHRT_MAX);
83 	}
84 
85 	*num = (u_short) tmp;
86 
87     return NULL;
88 }
89 
get_int(pool * p,const char ** arg,int * num,int min)90 static const char *get_int(pool *p, const char **arg, int *num, int min)
91 {
92     char *cp;
93     const char *val = ap_getword_conf(p, arg);
94 
95     if (*val == '\0')
96     {
97         return "\"\"";
98     }
99 
100     *num = (int) strtol(val, &cp, 10);
101 
102     if (*cp != '\0')
103     {
104         return ap_pstrcat(p, "can't parse ", "\"", val, "\"", NULL);
105     }
106     else if (*num < min)
107     {
108         return ap_psprintf(p, "\"%d\" must be >= %d", *num, min);
109     }
110 
111     return NULL;
112 }
113 
114 /*******************************************************************************
115  * Get the next configuration directive argument, & return an u_int.
116  * The pool arg should be temporary storage.
117  */
get_u_int(pool * p,const char ** arg,u_int * num,u_int min)118 static const char *get_u_int(pool *p, const char **arg,
119         u_int *num, u_int min)
120 {
121     char *ptr;
122     const char *val = ap_getword_conf(p, arg);
123 
124     if (*val == '\0')
125         return "\"\"";
126     *num = (u_int)strtol(val, &ptr, 10);
127 
128     if (*ptr != '\0')
129         return ap_pstrcat(p, "\"", val, "\" must be a positive integer", NULL);
130     else if (*num < min)
131         return ap_psprintf(p, "\"%u\" must be >= %u", *num, min);
132     return NULL;
133 }
134 
135 /*******************************************************************************
136  * Get the next configuration directive argument, & return a float.
137  * The pool arg should be temporary storage.
138  */
get_float(pool * p,const char ** arg,float * num,float min,float max)139 static const char *get_float(pool *p, const char **arg,
140         float *num, float min, float max)
141 {
142     char *ptr;
143     const char *val = ap_getword_conf(p, arg);
144 
145     if (*val == '\0')
146         return "\"\"";
147     *num = (float) strtod(val, &ptr);
148 
149     if (*ptr != '\0')
150         return ap_pstrcat(p, "\"", val, "\" is not a floating point number", NULL);
151     if (*num < min || *num > max)
152         return ap_psprintf(p, "\"%f\" is not between %f and %f", *num, min, max);
153     return NULL;
154 }
155 
fcgi_config_set_env_var(pool * p,char ** envp,unsigned int * envc,char * var)156 const char *fcgi_config_set_env_var(pool *p, char **envp, unsigned int *envc, char * var)
157 {
158     if (*envc >= MAX_INIT_ENV_VARS) {
159         return "too many variables, must be <= MAX_INIT_ENV_VARS";
160     }
161 
162     if (strchr(var, '=') == NULL) {
163         *(envp + *envc) = ap_pstrcat(p, var, "=", getenv(var), NULL);
164     }
165     else {
166         *(envp + *envc) = var;
167     }
168 
169     (*envc)++;
170 
171     return NULL;
172 }
173 
174 /*******************************************************************************
175  * Get the next configuration directive argument, & add it to an env array.
176  * The pool arg should be permanent storage.
177  */
get_env_var(pool * p,const char ** arg,char ** envp,unsigned int * envc)178 static const char *get_env_var(pool *p, const char **arg, char **envp, unsigned int *envc)
179 {
180     char * const val = ap_getword_conf(p, arg);
181 
182     if (*val == '\0') {
183         return "\"\"";
184     }
185 
186     return fcgi_config_set_env_var(p, envp, envc, val);
187 }
188 
get_pass_header(pool * p,const char ** arg,array_header ** array)189 static const char *get_pass_header(pool *p, const char **arg, array_header **array)
190 {
191     const char **header;
192 
193     if (!*array) {
194         *array = ap_make_array(p, 10, sizeof(char*));
195     }
196 
197     header = (const char **)ap_push_array(*array);
198     *header = ap_getword_conf(p, arg);
199 
200     return header ? NULL : "\"\"";
201 }
202 
203 /*******************************************************************************
204  * Return a "standard" message for common configuration errors.
205  */
invalid_value(pool * p,const char * cmd,const char * id,const char * opt,const char * err)206 static const char *invalid_value(pool *p, const char *cmd, const char *id,
207         const char *opt, const char *err)
208 {
209     return ap_psprintf(p, "%s%s%s: invalid value for %s: %s",
210                     cmd, id ? " " : "", id ? id : "",  opt, err);
211 }
212 
213 /*******************************************************************************
214  * Set/Reset the uid/gid that Apache and the PM will run as.  This is ap_user_id
215  * and ap_group_id if we're started as root, and euid/egid otherwise.  Also try
216  * to check that the config files don't set the User/Group after a FastCGI
217  * directive is used that depends on it.
218  */
219 /*@@@ To be complete, we should save a handle to the server each AppClass is
220  * configured in and at init() check that the user/group is still what we
221  * thought it was.  Also the other directives should only be allowed in the
222  * parent Apache server.
223  */
fcgi_config_set_fcgi_uid_n_gid(int set)224 const char *fcgi_config_set_fcgi_uid_n_gid(int set)
225 {
226     static int isSet = 0;
227 
228 #ifndef WIN32
229 
230     uid_t uid = geteuid();
231     gid_t gid = getegid();
232 
233     if (set == 0) {
234         isSet = 0;
235         fcgi_user_id = (uid_t)-1;
236         fcgi_group_id = (gid_t)-1;
237         return NULL;
238     }
239 
240     if (uid == 0) {
241         uid = ap_user_id;
242     }
243 
244     if (gid == 0) {
245         gid = ap_group_id;
246     }
247 
248     if (isSet && (uid != fcgi_user_id || gid != fcgi_group_id)) {
249         return "User/Group commands must preceed FastCGI server definitions";
250     }
251 
252     isSet = 1;
253     fcgi_user_id = uid;
254     fcgi_group_id = gid;
255 
256 #endif /* !WIN32 */
257 
258     return NULL;
259 }
260 
fcgi_config_reset_globals(void * dummy)261 apcb_t fcgi_config_reset_globals(void* dummy)
262 {
263     fcgi_config_pool = NULL;
264     fcgi_servers = NULL;
265     fcgi_config_set_fcgi_uid_n_gid(0);
266     fcgi_wrapper = NULL;
267     fcgi_socket_dir = NULL;
268 
269     fcgi_dynamic_total_proc_count = 0;
270     fcgi_dynamic_epoch = 0;
271     fcgi_dynamic_last_analyzed = 0;
272 
273     dynamicMaxProcs = FCGI_DEFAULT_MAX_PROCS;
274     dynamicMinProcs = FCGI_DEFAULT_MIN_PROCS;
275     dynamicMaxClassProcs = FCGI_DEFAULT_MAX_CLASS_PROCS;
276     dynamicKillInterval = FCGI_DEFAULT_KILL_INTERVAL;
277     dynamicUpdateInterval = FCGI_DEFAULT_UPDATE_INTERVAL;
278     dynamicGain = FCGI_DEFAULT_GAIN;
279     dynamicThreshold1 = FCGI_DEFAULT_THRESHOLD_1;
280     dynamicThresholdN = FCGI_DEFAULT_THRESHOLD_N;
281     dynamicPleaseStartDelay = FCGI_DEFAULT_START_PROCESS_DELAY;
282     dynamicAppConnectTimeout = FCGI_DEFAULT_APP_CONN_TIMEOUT;
283     dynamicEnvp = &fcgi_empty_env;
284     dynamicProcessSlack = FCGI_DEFAULT_PROCESS_SLACK;
285     dynamicAutoRestart = FCGI_DEFAULT_RESTART_DYNAMIC;
286     dynamicAutoUpdate = FCGI_DEFAULT_AUTOUPDATE;
287     dynamicListenQueueDepth = FCGI_DEFAULT_LISTEN_Q;
288     dynamicInitStartDelay = DEFAULT_INIT_START_DELAY;
289     dynamicRestartDelay = FCGI_DEFAULT_RESTART_DELAY;
290     dynamicMinServerLife = FCGI_DEFAULT_MIN_SERVER_LIFE;
291     dynamic_pass_headers = NULL;
292     dynamic_idle_timeout = FCGI_DEFAULT_IDLE_TIMEOUT;
293 	dynamicFlush = FCGI_FLUSH;
294 
295 #ifndef WIN32
296 	/* Close any old pipe (HUP/USR1) */
297 	if (fcgi_pm_pipe[0] != -1) {
298 		close(fcgi_pm_pipe[0]);
299 		fcgi_pm_pipe[0] = -1;
300 	}
301 	if (fcgi_pm_pipe[1] != -1) {
302 		close(fcgi_pm_pipe[1]);
303 		fcgi_pm_pipe[1] = -1;
304 	}
305 #endif
306 
307     return APCB_OK;
308 }
309 
310 /*******************************************************************************
311  * Create a directory to hold Unix/Domain sockets.
312  */
fcgi_config_make_dir(pool * tp,char * path)313 const char *fcgi_config_make_dir(pool *tp, char *path)
314 {
315     struct stat finfo;
316     const char *err = NULL;
317 
318     /* Is the directory spec'd correctly */
319     if (*path != '/') {
320         return "path is not absolute (it must start with a \"/\")";
321     }
322     else {
323         int i = strlen(path) - 1;
324 
325         /* Strip trailing "/"s */
326         while(i > 0 && path[i] == '/') path[i--] = '\0';
327     }
328 
329     /* Does it exist? */
330     if (stat(path, &finfo) != 0) {
331         /* No, but maybe we can create it */
332 #ifdef WIN32
333         if (mkdir(path) != 0)
334 #else
335         if (mkdir(path, S_IRWXU) != 0)
336 #endif
337         {
338             return ap_psprintf(tp,
339                 "doesn't exist and can't be created: %s",
340                 strerror(errno));
341         }
342 
343 #ifndef WIN32
344         /* If we're root, we're gonna setuid/setgid so we need to chown */
345         if (geteuid() == 0 && chown(path, ap_user_id, ap_group_id) != 0) {
346             return ap_psprintf(tp,
347                 "can't chown() to the server (uid %ld, gid %ld): %s",
348                 (long)ap_user_id, (long)ap_group_id, strerror(errno));
349         }
350 #endif
351     }
352     else {
353         /* Yes, is it a directory? */
354         if (!S_ISDIR(finfo.st_mode))
355             return "isn't a directory!";
356 
357         /* Can we RWX in there? */
358 #ifdef WIN32
359         err = fcgi_util_check_access(tp, NULL, &finfo, _S_IREAD | _S_IWRITE | _S_IEXEC, fcgi_user_id, fcgi_group_id);
360 #else
361         err = fcgi_util_check_access(tp, NULL, &finfo, R_OK | W_OK | X_OK,
362                           fcgi_user_id, fcgi_group_id);
363 #endif
364         if (err != NULL) {
365             return ap_psprintf(tp,
366                 "access for server (uid %ld, gid %ld) failed: %s",
367                 (long)fcgi_user_id, (long)fcgi_group_id, err);
368         }
369     }
370     return NULL;
371 }
372 
373 /*******************************************************************************
374  * Create a "dynamic" subdirectory.  If the directory
375  * already exists we don't mess with it unless 'wax' is set.
376  */
377 #ifndef WIN32
fcgi_config_make_dynamic_dir(pool * p,const int wax)378 const char *fcgi_config_make_dynamic_dir(pool *p, const int wax)
379 {
380     const char *err;
381     pool *tp;
382 
383     fcgi_dynamic_dir = ap_pstrcat(p, fcgi_socket_dir, "/dynamic", NULL);
384 
385     if ((err = fcgi_config_make_dir(p, fcgi_dynamic_dir)))
386         return ap_psprintf(p, "can't create dynamic directory \"%s\": %s", fcgi_dynamic_dir, err);
387 
388     /* Don't step on a running server unless its OK. */
389     if (!wax)
390         return NULL;
391 
392 #ifdef APACHE2
393     {
394         apr_dir_t * dir;
395         apr_finfo_t finfo;
396 
397         if (apr_pool_create(&tp, p))
398             return "apr_pool_create() failed";
399 
400         if (apr_dir_open(&dir, fcgi_dynamic_dir, tp))
401             return "apr_dir_open() failed";
402 
403         /* delete the contents */
404 
405         while (apr_dir_read(&finfo, APR_FINFO_NAME, dir) == APR_SUCCESS)
406         {
407             if (strcmp(finfo.name, ".") == 0 || strcmp(finfo.name, "..") == 0)
408                 continue;
409 
410             apr_file_remove(finfo.name, tp);
411         }
412     }
413 
414 #else /* !APACHE2 */
415     {
416         DIR *dp;
417         struct dirent *dirp = NULL;
418 
419         tp = ap_make_sub_pool(p);
420 
421         dp = ap_popendir(tp, fcgi_dynamic_dir);
422         if (dp == NULL) {
423             ap_destroy_pool(tp);
424             return ap_psprintf(p, "can't open dynamic directory \"%s\": %s",
425                 fcgi_dynamic_dir, strerror(errno));
426         }
427 
428         /* delete the contents */
429 
430         while ((dirp = readdir(dp)) != NULL)
431         {
432             if (strcmp(dirp->d_name, ".") == 0 || strcmp(dirp->d_name, "..") == 0)
433                 continue;
434 
435             unlink(ap_pstrcat(tp, fcgi_dynamic_dir, "/", dirp->d_name, NULL));
436         }
437     }
438 
439 #endif /* !APACHE2 */
440 
441     ap_destroy_pool(tp);
442 
443     return NULL;
444 }
445 #endif
446 
447 /*******************************************************************************
448  * Change the directory used for the Unix/Domain sockets from the default.
449  * Create the directory and the "dynamic" subdirectory.
450  */
fcgi_config_set_socket_dir(cmd_parms * cmd,void * dummy,const char * arg)451 const char *fcgi_config_set_socket_dir(cmd_parms *cmd, void *dummy, const char *arg)
452 {
453     pool * const tp = cmd->temp_pool;
454     const char * const name = cmd->cmd->name;
455     const char *err;
456     char * arg_nc;
457 
458     err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
459     if (err)
460     {
461         return err;
462     }
463 
464     if (fcgi_socket_dir) {
465         return ap_psprintf(tp, "%s %s: already defined as \"%s\"",
466                         name, arg, fcgi_socket_dir);
467     }
468 
469     err = fcgi_config_set_fcgi_uid_n_gid(1);
470     if (err != NULL)
471         return ap_psprintf(tp, "%s %s: %s", name, arg, err);
472 
473     if (fcgi_servers != NULL) {
474         return ap_psprintf(tp,
475             "The %s command must preceed static FastCGI server definitions",
476             name);
477     }
478 
479     arg_nc = ap_pstrdup(cmd->pool, arg);
480 
481 #ifndef WIN32
482 
483 #ifdef APACHE2
484     if (apr_filepath_merge(&arg_nc, "", arg, 0, cmd->pool))
485         return ap_psprintf(tp, "%s %s: invalid filepath", name, arg);
486 #else
487     arg_nc = ap_os_canonical_filename(cmd->pool, arg_nc);
488 #endif
489 
490     arg_nc = ap_server_root_relative(cmd->pool, arg_nc);
491 
492 #else /* WIN32 */
493 
494 	if (strncmp(arg_nc, "\\\\.\\pipe\\", 9) != 0)
495 		return ap_psprintf(tp, "%s %s is invalid format",name, arg_nc);
496 
497 #endif
498 
499     fcgi_socket_dir = arg_nc;
500 
501 #ifdef WIN32
502     fcgi_dynamic_dir = ap_pstrcat(cmd->pool, fcgi_socket_dir, "dynamic", NULL);
503 #else
504     err = fcgi_config_make_dir(tp, fcgi_socket_dir);
505     if (err != NULL)
506         return ap_psprintf(tp, "%s %s: %s", name, arg_nc, err);
507 
508     err = fcgi_config_make_dynamic_dir(cmd->pool, 0);
509     if (err != NULL)
510         return ap_psprintf(tp, "%s %s: %s", name, arg_nc, err);
511 #endif
512 
513     return NULL;
514 }
515 
516 /*******************************************************************************
517  * Enable, disable, or specify the path to a wrapper used to invoke all
518  * FastCGI applications.
519  */
fcgi_config_set_wrapper(cmd_parms * cmd,void * dummy,const char * arg)520 const char *fcgi_config_set_wrapper(cmd_parms *cmd, void *dummy, const char *arg)
521 {
522 #ifdef WIN32
523     return ap_psprintf(cmd->temp_pool,
524         "the %s directive is not supported on WIN", cmd->cmd->name);
525 #else
526 
527     const char *err = NULL;
528     const char * const name = cmd->cmd->name;
529     pool * const tp = cmd->temp_pool;
530     char * wrapper = NULL;
531 
532     err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
533     if (err)
534     {
535         return err;
536     }
537 
538     if (fcgi_wrapper)
539     {
540         return ap_psprintf(tp, "%s was already set to \"%s\"",
541                            name, fcgi_wrapper);
542     }
543 
544     err = fcgi_config_set_fcgi_uid_n_gid(1);
545     if (err != NULL)
546         return ap_psprintf(tp, "%s %s: %s", name, arg, err);
547 
548     if (fcgi_servers != NULL) {
549         return ap_psprintf(tp,
550             "The %s command must preceed static FastCGI server definitions", name);
551     }
552 
553     if (strcasecmp(arg, "Off") == 0) {
554         fcgi_wrapper = NULL;
555         return NULL;
556     }
557 
558     if (strcasecmp(arg, "On") == 0)
559     {
560         wrapper = SUEXEC_BIN;
561     }
562     else
563     {
564 #ifdef APACHE2
565         if (apr_filepath_merge(&wrapper, "", arg, 0, cmd->pool))
566             return ap_psprintf(tp, "%s %s: invalid filepath", name, arg);
567 #else
568         wrapper = ap_os_canonical_filename(cmd->pool, (char *) arg);
569 #endif
570 
571         wrapper = ap_server_root_relative(cmd->pool, wrapper);
572     }
573 
574     err = fcgi_util_check_access(tp, wrapper, NULL, X_OK, fcgi_user_id, fcgi_group_id);
575     if (err)
576     {
577         return ap_psprintf(tp, "%s: \"%s\" execute access for server "
578                            "(uid %ld, gid %ld) failed: %s", name, wrapper,
579                            (long) fcgi_user_id, (long) fcgi_group_id, err);
580     }
581 
582     fcgi_wrapper = wrapper;
583 
584     return NULL;
585 #endif /* !WIN32 */
586 }
587 
588 /*******************************************************************************
589  * Configure a static FastCGI server.
590  */
fcgi_config_new_static_server(cmd_parms * cmd,void * dummy,const char * arg)591 const char *fcgi_config_new_static_server(cmd_parms *cmd, void *dummy, const char *arg)
592 {
593     fcgi_server *s;
594     pool *p = cmd->pool, *tp = cmd->temp_pool;
595     const char *name = cmd->cmd->name;
596     char *fs_path = ap_getword_conf(p, &arg);
597     const char *option, *err;
598 
599     /* Allocate temp storage for the array of initial environment variables */
600     char **envp = ap_pcalloc(tp, sizeof(char *) * (MAX_INIT_ENV_VARS + 3));
601     unsigned int envc = 0;
602 
603 #ifdef WIN32
604     HANDLE mutex;
605 #endif
606 
607     err = ap_check_cmd_context(cmd, NOT_IN_LIMIT|NOT_IN_DIR_LOC_FILE);
608     if (err)
609     {
610         return err;
611     }
612 
613     if (*fs_path == '\0')
614         return "AppClass requires a pathname!?";
615 
616     if ((err = fcgi_config_set_fcgi_uid_n_gid(1)) != NULL)
617         return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
618 
619 #ifdef APACHE2
620     if (apr_filepath_merge(&fs_path, "", fs_path, 0, p))
621         return ap_psprintf(tp, "%s %s: invalid filepath", name, fs_path);
622 #else
623     fs_path = ap_os_canonical_filename(p, fs_path);
624 #endif
625     fs_path = ap_server_root_relative(p, fs_path);
626 
627     ap_getparents(fs_path);
628     ap_no2slash(fs_path);
629 
630     /* See if we've already got one of these configured */
631     s = fcgi_util_fs_get_by_id(fs_path, fcgi_util_get_server_uid(cmd->server),
632                                fcgi_util_get_server_gid(cmd->server));
633     if (s != NULL) {
634         if (fcgi_wrapper) {
635             return ap_psprintf(tp,
636                 "%s: redefinition of a previously defined FastCGI "
637                 "server \"%s\" with uid=%ld and gid=%ld",
638                 name, fs_path, (long) fcgi_util_get_server_uid(cmd->server),
639                 (long) fcgi_util_get_server_gid(cmd->server));
640         }
641         else {
642             return ap_psprintf(tp,
643                 "%s: redefinition of a previously defined FastCGI server \"%s\"",
644                 name, fs_path);
645         }
646     }
647 
648     err = fcgi_util_fs_is_path_ok(tp, fs_path, NULL);
649     if (err != NULL) {
650         return ap_psprintf(tp, "%s: \"%s\" %s", name, fs_path, err);
651     }
652 
653     s = fcgi_util_fs_new(p);
654     s->fs_path = fs_path;
655     s->directive = APP_CLASS_STANDARD;
656     s->restartOnExit = TRUE;
657     s->numProcesses = 1;
658 
659 #ifdef WIN32
660 
661     /* TCP FastCGI applications require SystemRoot be present in the environment
662      * Put it in both for consistency to the application */
663     fcgi_config_set_env_var(p, envp, &envc, "SystemRoot");
664 
665     mutex = CreateMutex(NULL, FALSE, fs_path);
666 
667     if (mutex == NULL)
668     {
669         ap_log_error(FCGI_LOG_ALERT, fcgi_apache_main_server,
670             "FastCGI: CreateMutex() failed");
671         return "failed to create FastCGI application accept mutex";
672     }
673 
674     SetHandleInformation(mutex, HANDLE_FLAG_INHERIT, TRUE);
675 
676     s->mutex_env_string = ap_psprintf(p, "_FCGI_MUTEX_=%ld", mutex);
677 
678 #endif
679 
680     /*  Parse directive arguments */
681     while (*arg) {
682         option = ap_getword_conf(tp, &arg);
683 
684         if (strcasecmp(option, "-processes") == 0) {
685             if ((err = get_u_int(tp, &arg, &s->numProcesses, 1)))
686                 return invalid_value(tp, name, fs_path, option, err);
687         }
688         else if (strcasecmp(option, "-restart-delay") == 0) {
689             if ((err = get_u_int(tp, &arg, &s->restartDelay, 0)))
690                 return invalid_value(tp, name, fs_path, option, err);
691         }
692         else if (strcasecmp(option, "-init-start-delay") == 0) {
693             if ((err = get_int(tp, &arg, &s->initStartDelay, 0)))
694                 return invalid_value(tp, name, fs_path, option, err);
695         }
696         else if (strcasecmp(option, "-min-server-life") == 0) {
697             if ((err = get_u_int(tp, &arg, &s->minServerLife, 0)))
698                 return invalid_value(tp, name, NULL, option, err);
699         }
700         else if (strcasecmp(option, "-priority") == 0) {
701             if ((err = get_u_int(tp, &arg, &s->processPriority, 0)))
702                 return invalid_value(tp, name, fs_path, option, err);
703         }
704         else if (strcasecmp(option, "-listen-queue-depth") == 0) {
705             if ((err = get_u_int(tp, &arg, &s->listenQueueDepth, 1)))
706                 return invalid_value(tp, name, fs_path, option, err);
707         }
708         else if (strcasecmp(option, "-appConnTimeout") == 0) {
709             if ((err = get_u_int(tp, &arg, &s->appConnectTimeout, 0)))
710                 return invalid_value(tp, name, fs_path, option, err);
711         }
712         else if (strcasecmp(option, "-idle-timeout") == 0) {
713             if ((err = get_u_int(tp, &arg, &s->idle_timeout, 1)))
714                 return invalid_value(tp, name, fs_path, option, err);
715         }
716         else if (strcasecmp(option, "-port") == 0) {
717             if ((err = get_u_short(tp, &arg, &s->port, 1)))
718                 return invalid_value(tp, name, fs_path, option, err);
719         }
720         else if (strcasecmp(option, "-socket") == 0) {
721             s->socket_path = ap_getword_conf(tp, &arg);
722             if (*s->socket_path == '\0')
723                 return invalid_value(tp, name, fs_path, option, "\"\"");
724         }
725         else if (strcasecmp(option, "-initial-env") == 0) {
726             if ((err = get_env_var(p, &arg, envp, &envc)))
727                 return invalid_value(tp, name, fs_path, option, err);
728         }
729         else if (strcasecmp(option, "-pass-header") == 0) {
730             if ((err = get_pass_header(p, &arg, &s->pass_headers)))
731                 return invalid_value(tp, name, fs_path, option, err);
732         }
733         else if (strcasecmp(option, "-flush") == 0) {
734             s->flush = 1;
735         }
736         else if (strcasecmp(option, "-nph") == 0) {
737             s->nph = 1;
738         }
739         else if (strcasecmp(option, "-user") == 0) {
740 #ifdef WIN32
741             return ap_psprintf(tp,
742                 "%s %s: the -user option isn't supported on WIN", name, fs_path);
743 #else
744             s->user = ap_getword_conf(tp, &arg);
745             if (*s->user == '\0')
746                 return invalid_value(tp, name, fs_path, option, "\"\"");
747 #endif
748         }
749         else if (strcasecmp(option, "-group") == 0) {
750 #ifdef WIN32
751             return ap_psprintf(tp,
752                 "%s %s: the -group option isn't supported on WIN", name, fs_path);
753 #else
754             s->group = ap_getword_conf(tp, &arg);
755             if (*s->group == '\0')
756                 return invalid_value(tp, name, fs_path, option, "\"\"");
757 #endif
758         }
759         else {
760             return ap_psprintf(tp, "%s %s: invalid option: %s", name, fs_path, option);
761         }
762     } /* while */
763 
764 #ifndef WIN32
765     if (fcgi_wrapper)
766     {
767         if (s->group == NULL)
768         {
769             s->group = ap_psprintf(tp, "#%ld", (long) fcgi_util_get_server_gid(cmd->server));
770         }
771 
772         if (s->user == NULL)
773         {
774             s->user = ap_psprintf(p, "#%ld", (long) fcgi_util_get_server_uid(cmd->server));
775         }
776 
777         s->uid = ap_uname2id(s->user);
778         s->gid = ap_gname2id(s->group);
779     }
780     else if (s->user || s->group)
781     {
782         ap_log_error(FCGI_LOG_WARN, cmd->server, "FastCGI: there is no "
783                      "fastcgi wrapper set, user/group options are ignored");
784     }
785 
786     if ((err = fcgi_util_fs_set_uid_n_gid(p, s, s->uid, s->gid)))
787     {
788         return ap_psprintf(tp,
789             "%s %s: invalid user or group: %s", name, fs_path, err);
790     }
791 #endif /* !WIN32 */
792 
793     if (s->socket_path != NULL && s->port != 0) {
794         return ap_psprintf(tp,
795                 "%s %s: -port and -socket are mutually exclusive options",
796                 name, fs_path);
797     }
798 
799     /* Move env array to a surviving pool */
800     s->envp = (char **)ap_pcalloc(p, sizeof(char *) * (envc + 4));
801     memcpy(s->envp, envp, sizeof(char *) * envc);
802 
803     /* Initialize process structs */
804     s->procs = fcgi_util_fs_create_procs(p, s->numProcesses);
805 
806     /* Build the appropriate sockaddr structure */
807     if (s->port != 0) {
808         err = fcgi_util_socket_make_inet_addr(p, (struct sockaddr_in **)&s->socket_addr,
809                                 &s->socket_addr_len, NULL, s->port);
810         if (err != NULL)
811             return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
812 #ifdef WIN32
813         err = fcgi_util_socket_make_inet_addr(p, (struct sockaddr_in **)&s->dest_addr,
814                                           &s->socket_addr_len, "localhost", s->port);
815         if (err != NULL)
816             return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
817 #endif
818     } else {
819         if (s->socket_path == NULL)
820              s->socket_path = fcgi_util_socket_hash_filename(tp, fs_path, s->user, s->group);
821 
822         if (fcgi_socket_dir == NULL)
823         {
824 #ifdef WIN32
825             fcgi_socket_dir = DEFAULT_SOCK_DIR;
826 #else
827             fcgi_socket_dir = ap_server_root_relative(p, DEFAULT_SOCK_DIR);
828 #endif
829         }
830 
831         s->socket_path = fcgi_util_socket_make_path_absolute(p, s->socket_path, 0);
832 #ifndef WIN32
833         err = fcgi_util_socket_make_domain_addr(p, (struct sockaddr_un **)&s->socket_addr,
834                                   &s->socket_addr_len, s->socket_path);
835         if (err != NULL)
836             return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
837 #endif
838     }
839 
840     /* Add it to the list of FastCGI servers */
841     fcgi_util_fs_add(s);
842 
843     return NULL;
844 }
845 
846 /*******************************************************************************
847  * Configure a static FastCGI server that is started/managed elsewhere.
848  */
fcgi_config_new_external_server(cmd_parms * cmd,void * dummy,const char * arg)849 const char *fcgi_config_new_external_server(cmd_parms *cmd, void *dummy, const char *arg)
850 {
851     fcgi_server *s;
852     pool * const p = cmd->pool, *tp = cmd->temp_pool;
853     const char * const name = cmd->cmd->name;
854     char *fs_path = ap_getword_conf(p, &arg);
855     const char *option, *err;
856 
857     err = ap_check_cmd_context(cmd, NOT_IN_LIMIT|NOT_IN_DIR_LOC_FILE);
858     if (err) {
859         return err;
860     }
861 
862     if (!*fs_path) {
863         return ap_pstrcat(tp, name, " requires a path and either a -socket or -host option", NULL);
864     }
865 
866 #ifdef APACHE2
867     if (apr_filepath_merge(&fs_path, "", fs_path, 0, p))
868         return ap_psprintf(tp, "%s %s: invalid filepath", name, fs_path);
869 #else
870     fs_path = ap_os_canonical_filename(p, fs_path);
871 #endif
872 
873     fs_path = ap_server_root_relative(p, fs_path);
874 
875     ap_getparents(fs_path);
876     ap_no2slash(fs_path);
877 
878     /* See if we've already got one of these bettys configured */
879     s = fcgi_util_fs_get_by_id(fs_path, fcgi_util_get_server_uid(cmd->server),
880                                fcgi_util_get_server_gid(cmd->server));
881     if (s != NULL) {
882         if (fcgi_wrapper) {
883             return ap_psprintf(tp,
884                 "%s: redefinition of a previously defined class \"%s\" "
885                 "with uid=%ld and gid=%ld",
886                 name, fs_path, (long) fcgi_util_get_server_uid(cmd->server),
887                 (long) fcgi_util_get_server_gid(cmd->server));
888         }
889         else
890         {
891             return ap_psprintf(tp,
892                 "%s: redefinition of previously defined class \"%s\"", name, fs_path);
893         }
894     }
895 
896     s = fcgi_util_fs_new(p);
897     s->fs_path = fs_path;
898     s->directive = APP_CLASS_EXTERNAL;
899 
900     /*  Parse directive arguments */
901     while (*arg != '\0') {
902         option = ap_getword_conf(tp, &arg);
903 
904         if (strcasecmp(option, "-host") == 0) {
905             if ((err = get_host_n_port(p, &arg, &s->host, &s->port)))
906                 return invalid_value(tp, name, fs_path, option, err);
907         }
908         else if (strcasecmp(option, "-socket") == 0) {
909             s->socket_path = ap_getword_conf(tp, &arg);
910             if (*s->socket_path == '\0')
911                 return invalid_value(tp, name, fs_path, option, "\"\"");
912         }
913         else if (strcasecmp(option, "-appConnTimeout") == 0) {
914             if ((err = get_u_int(tp, &arg, &s->appConnectTimeout, 0)))
915                 return invalid_value(tp, name, fs_path, option, err);
916         }
917         else if (strcasecmp(option, "-idle-timeout") == 0) {
918             if ((err = get_u_int(tp, &arg, &s->idle_timeout, 1)))
919                 return invalid_value(tp, name, fs_path, option, err);
920         }
921         else if (strcasecmp(option, "-nph") == 0) {
922             s->nph = 1;
923         }
924         else if (strcasecmp(option, "-pass-header") == 0) {
925             if ((err = get_pass_header(p, &arg, &s->pass_headers)))
926                 return invalid_value(tp, name, fs_path, option, err);
927         }
928         else if (strcasecmp(option, "-flush") == 0) {
929             s->flush = 1;
930         }
931         else if (strcasecmp(option, "-user") == 0) {
932 #ifdef WIN32
933             return ap_psprintf(tp,
934                 "%s %s: the -user option isn't supported on WIN", name, fs_path);
935 #else
936             s->user = ap_getword_conf(tp, &arg);
937             if (*s->user == '\0')
938                 return invalid_value(tp, name, fs_path, option, "\"\"");
939 #endif
940         }
941         else if (strcasecmp(option, "-group") == 0) {
942 #ifdef WIN32
943             return ap_psprintf(tp,
944                 "%s %s: the -group option isn't supported on WIN", name, fs_path);
945 #else
946             s->group = ap_getword_conf(tp, &arg);
947             if (*s->group == '\0')
948                 return invalid_value(tp, name, fs_path, option, "\"\"");
949 #endif
950         }
951         else {
952             return ap_psprintf(tp, "%s %s: invalid option: %s", name, fs_path, option);
953         }
954     } /* while */
955 
956 
957 #ifndef WIN32
958     if (fcgi_wrapper)
959     {
960         if (s->group == NULL)
961         {
962             s->group = ap_psprintf(tp, "#%ld", (long) fcgi_util_get_server_gid(cmd->server));
963         }
964 
965         if (s->user == NULL)
966         {
967             s->user = ap_psprintf(p, "#%ld", (long) fcgi_util_get_server_uid(cmd->server));
968         }
969 
970         s->uid = ap_uname2id(s->user);
971         s->gid = ap_gname2id(s->group);
972     }
973     else if (s->user || s->group)
974     {
975         ap_log_error(FCGI_LOG_WARN, cmd->server, "FastCGI: there is no "
976                      "fastcgi wrapper set, user/group options are ignored");
977     }
978 
979     if ((err = fcgi_util_fs_set_uid_n_gid(p, s, s->uid, s->gid)))
980     {
981         return ap_psprintf(tp,
982             "%s %s: invalid user or group: %s", name, fs_path, err);
983     }
984 #endif /* !WIN32 */
985 
986     /* Require one of -socket or -host, but not both */
987     if (s->socket_path != NULL && s->port != 0) {
988         return ap_psprintf(tp,
989             "%s %s: -host and -socket are mutually exclusive options",
990             name, fs_path);
991     }
992     if (s->socket_path == NULL && s->port == 0) {
993         return ap_psprintf(tp,
994             "%s %s: -socket or -host option missing", name, fs_path);
995     }
996 
997     /* Build the appropriate sockaddr structure */
998     if (s->port != 0) {
999         err = fcgi_util_socket_make_inet_addr(p, (struct sockaddr_in **)&s->socket_addr,
1000             &s->socket_addr_len, s->host, s->port);
1001         if (err != NULL)
1002             return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
1003     } else {
1004 
1005         if (fcgi_socket_dir == NULL)
1006         {
1007 #ifdef WIN32
1008             fcgi_socket_dir = DEFAULT_SOCK_DIR;
1009 #else
1010             fcgi_socket_dir = ap_server_root_relative(p, DEFAULT_SOCK_DIR);
1011 #endif
1012         }
1013 
1014         s->socket_path = fcgi_util_socket_make_path_absolute(p, s->socket_path, 0);
1015 #ifndef WIN32
1016         err = fcgi_util_socket_make_domain_addr(p, (struct sockaddr_un **)&s->socket_addr,
1017                                   &s->socket_addr_len, s->socket_path);
1018         if (err != NULL)
1019             return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
1020 #endif
1021     }
1022 
1023     /* Add it to the list of FastCGI servers */
1024     fcgi_util_fs_add(s);
1025 
1026     return NULL;
1027 }
1028 
1029 /*
1030  *----------------------------------------------------------------------
1031  *
1032  * fcgi_config_set_config --
1033  *
1034  *      Implements the FastCGI FCGIConfig configuration directive.
1035  *      This command adds routines to control the execution of the
1036  *      dynamic FastCGI processes.
1037  *
1038  *
1039  *----------------------------------------------------------------------
1040  */
fcgi_config_set_config(cmd_parms * cmd,void * dummy,const char * arg)1041 const char *fcgi_config_set_config(cmd_parms *cmd, void *dummy, const char *arg)
1042 {
1043     pool * const p = cmd->pool;
1044     pool * const tp = cmd->temp_pool;
1045     const char *err, *option;
1046     const char * const name = cmd->cmd->name;
1047 
1048     /* Allocate temp storage for an initial environment */
1049     unsigned int envc = 0;
1050     char **envp = (char **)ap_pcalloc(tp, sizeof(char *) * (MAX_INIT_ENV_VARS + 3));
1051 
1052     err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1053     if (err)
1054     {
1055         return err;
1056     }
1057 
1058     /* Parse the directive arguments */
1059     while (*arg) {
1060         option = ap_getword_conf(tp, &arg);
1061 
1062         if (strcasecmp(option, "-maxProcesses") == 0) {
1063             if ((err = get_u_int(tp, &arg, &dynamicMaxProcs, 1)))
1064                 return invalid_value(tp, name, NULL, option, err);
1065         }
1066         else if (strcasecmp(option, "-minProcesses") == 0) {
1067             if ((err = get_int(tp, &arg, &dynamicMinProcs, 0)))
1068                 return invalid_value(tp, name, NULL, option, err);
1069         }
1070         else if (strcasecmp(option, "-maxClassProcesses") == 0) {
1071             if ((err = get_int(tp, &arg, &dynamicMaxClassProcs, 1)))
1072                 return invalid_value(tp, name, NULL, option, err);
1073         }
1074         else if (strcasecmp(option, "-killInterval") == 0) {
1075             if ((err = get_u_int(tp, &arg, &dynamicKillInterval, 1)))
1076                 return invalid_value(tp, name, NULL, option, err);
1077         }
1078         else if (strcasecmp(option, "-updateInterval") == 0) {
1079             if ((err = get_u_int(tp, &arg, &dynamicUpdateInterval, 1)))
1080                 return invalid_value(tp, name, NULL, option, err);
1081         }
1082         else if (strcasecmp(option, "-gainValue") == 0) {
1083             if ((err = get_float(tp, &arg, &dynamicGain, 0.0, 1.0)))
1084                 return invalid_value(tp, name, NULL, option, err);
1085         }
1086         else if ((strcasecmp(option, "-singleThreshold") == 0)
1087 		    || (strcasecmp(option, "-singleThreshhold") == 0))
1088         {
1089             if ((err = get_int(tp, &arg, &dynamicThreshold1, 0)))
1090                 return invalid_value(tp, name, NULL, option, err);
1091         }
1092         else if ((strcasecmp(option, "-multiThreshold") == 0)
1093 		    || (strcasecmp(option, "-multiThreshhold") == 0))
1094         {
1095             if ((err = get_int(tp, &arg, &dynamicThresholdN, 0)))
1096                 return invalid_value(tp, name, NULL, option, err);
1097         }
1098         else if (strcasecmp(option, "-startDelay") == 0) {
1099             if ((err = get_u_int(tp, &arg, &dynamicPleaseStartDelay, 1)))
1100                 return invalid_value(tp, name, NULL, option, err);
1101         }
1102         else if (strcasecmp(option, "-initial-env") == 0) {
1103             if ((err = get_env_var(p, &arg, envp, &envc)))
1104                 return invalid_value(tp, name, NULL, option, err);
1105         }
1106         else if (strcasecmp(option, "-pass-header") == 0) {
1107             if ((err = get_pass_header(p, &arg, &dynamic_pass_headers)))
1108                 return invalid_value(tp, name, NULL, option, err);
1109         }
1110         else if (strcasecmp(option, "-appConnTimeout") == 0) {
1111             if ((err = get_u_int(tp, &arg, &dynamicAppConnectTimeout, 0)))
1112                 return invalid_value(tp, name, NULL, option, err);
1113         }
1114         else if (strcasecmp(option, "-idle-timeout") == 0) {
1115             if ((err = get_u_int(tp, &arg, &dynamic_idle_timeout, 1)))
1116                 return invalid_value(tp, name, NULL, option, err);
1117         }
1118         else if (strcasecmp(option, "-listen-queue-depth") == 0) {
1119             if ((err = get_u_int(tp, &arg, &dynamicListenQueueDepth, 1)))
1120                 return invalid_value(tp, name, NULL, option, err);
1121         }
1122         else if (strcasecmp(option, "-min-server-life") == 0) {
1123             if ((err = get_int(tp, &arg, &dynamicMinServerLife, 0)))
1124                 return invalid_value(tp, name, NULL, option, err);
1125         }
1126         else if (strcasecmp(option, "-restart-delay") == 0) {
1127             if ((err = get_u_int(tp, &arg, &dynamicRestartDelay, 0)))
1128                 return invalid_value(tp, name, NULL, option, err);
1129         }
1130         else if (strcasecmp(option, "-init-start-delay") == 0) {
1131             if ((err = get_u_int(tp, &arg, &dynamicInitStartDelay, 0)))
1132                 return invalid_value(tp, name, NULL, option, err);
1133         }
1134         else if (strcasecmp(option, "-processSlack") == 0) {
1135             if ((err = get_u_int(tp, &arg, &dynamicProcessSlack, 1)))
1136                 return invalid_value(tp, name, NULL, option, err);
1137         }
1138         else if (strcasecmp(option, "-restart") == 0) {
1139             dynamicAutoRestart = 1;
1140         }
1141         else if (strcasecmp(option, "-autoUpdate") == 0) {
1142             dynamicAutoUpdate = 1;
1143 		}
1144         else if (strcasecmp(option, "-flush") == 0) {
1145             dynamicFlush = TRUE;
1146         }
1147         else {
1148             return ap_psprintf(tp, "%s: invalid option: %s", name, option);
1149         }
1150     } /* while */
1151 
1152     if (dynamicProcessSlack >= dynamicMaxProcs + 1) {
1153 	    /* the kill policy would work unexpectedly */
1154     	return ap_psprintf(tp,
1155             "%s: processSlack (%u) must be less than maxProcesses (%u) + 1",
1156         	name, dynamicProcessSlack, dynamicMaxProcs);
1157     }
1158 
1159     /* Move env array to a surviving pool, leave 2 extra slots for
1160      * WIN32 _FCGI_MUTEX_ and _FCGI_SHUTDOWN_EVENT_ */
1161     dynamicEnvp = (char **)ap_pcalloc(p, sizeof(char *) * (envc + 4));
1162     memcpy(dynamicEnvp, envp, sizeof(char *) * envc);
1163 
1164     return NULL;
1165 }
1166 
fcgi_config_create_dir_config(pool * p,char * dummy)1167 void *fcgi_config_create_dir_config(pool *p, char *dummy)
1168 {
1169     fcgi_dir_config *dir_config = ap_pcalloc(p, sizeof(fcgi_dir_config));
1170 
1171     dir_config->authenticator_options = FCGI_AUTHORITATIVE;
1172     dir_config->authorizer_options = FCGI_AUTHORITATIVE;
1173     dir_config->access_checker_options = FCGI_AUTHORITATIVE;
1174 
1175     return dir_config;
1176 }
1177 
1178 
fcgi_config_new_auth_server(cmd_parms * cmd,void * dircfg,const char * fs_path,const char * compat)1179 const char *fcgi_config_new_auth_server(cmd_parms * cmd,
1180     void * dircfg, const char *fs_path, const char * compat)
1181 {
1182     fcgi_dir_config * dir_config = (fcgi_dir_config *) dircfg;
1183     pool * const tp = cmd->temp_pool;
1184     char * auth_server;
1185 
1186 #ifdef APACHE2
1187     if (apr_filepath_merge(&auth_server, "", fs_path, 0, cmd->pool))
1188         return ap_psprintf(tp, "%s %s: invalid filepath", cmd->cmd->name, fs_path);
1189 #else
1190     auth_server = (char *) ap_os_canonical_filename(cmd->pool, fs_path);
1191 #endif
1192 
1193     auth_server = ap_server_root_relative(cmd->pool, auth_server);
1194 
1195     /* Make sure its already configured or at least a candidate for dynamic */
1196     if (fcgi_util_fs_get_by_id(auth_server, fcgi_util_get_server_uid(cmd->server),
1197                                fcgi_util_get_server_gid(cmd->server)) == NULL)
1198     {
1199         const char *err = fcgi_util_fs_is_path_ok(tp, auth_server, NULL);
1200         if (err)
1201             return ap_psprintf(tp, "%s: \"%s\" %s", cmd->cmd->name, auth_server, err);
1202     }
1203 
1204     if (compat && strcasecmp(compat, "-compat"))
1205         return ap_psprintf(cmd->temp_pool, "%s: unknown option: \"%s\"", cmd->cmd->name, compat);
1206 
1207     switch((intptr_t)cmd->info) {
1208         case FCGI_AUTH_TYPE_AUTHENTICATOR:
1209             dir_config->authenticator = auth_server;
1210             dir_config->authenticator_options |= (compat) ? FCGI_COMPAT : 0;
1211             break;
1212         case FCGI_AUTH_TYPE_AUTHORIZER:
1213             dir_config->authorizer = auth_server;
1214             dir_config->authorizer_options |= (compat) ? FCGI_COMPAT : 0;
1215             break;
1216         case FCGI_AUTH_TYPE_ACCESS_CHECKER:
1217             dir_config->access_checker = auth_server;
1218             dir_config->access_checker_options |= (compat) ? FCGI_COMPAT : 0;
1219             break;
1220     }
1221 
1222     return NULL;
1223 }
1224 
fcgi_config_set_authoritative_slot(cmd_parms * cmd,void * dir_config,int arg)1225 const char *fcgi_config_set_authoritative_slot(cmd_parms * cmd,
1226     void * dir_config, int arg)
1227 {
1228     int offset = (int)(long)cmd->info;
1229 
1230     if (arg)
1231         *((u_char *)dir_config + offset) |= FCGI_AUTHORITATIVE;
1232     else
1233         *((u_char *)dir_config + offset) &= ~FCGI_AUTHORITATIVE;
1234 
1235     return NULL;
1236 }
1237