2 * $Id: fcgi_config.c,v 1.31 2002/02/04 19:39:32 robs Exp $
8 #pragma warning( disable : 4100 4706 )
11 /*******************************************************************************
12 * Get the next configuration directive argument, & return an in_addr and port.
13 * The arg must be in the form "host:port" where host can be an IP or hostname.
14 * The pool arg should be persistant storage.
16 static const char *get_host_n_port(pool
*p
, const char **arg
,
17 const char **host
, u_short
*port
)
19 char *cvptr
, *portStr
;
22 *host
= ap_getword_conf(p
, arg
);
26 portStr
= strchr(*host
, ':');
28 return "missing port specification";
30 /* Split the host and port portions */
33 /* Convert port number */
34 tmp
= (u_short
) strtol(portStr
, &cvptr
, 10);
35 if (*cvptr
!= '\0' || tmp
< 1 || tmp
> USHRT_MAX
)
36 return ap_pstrcat(p
, "bad port number \"", portStr
, "\"", NULL
);
38 *port
= (unsigned short) tmp
;
43 /*******************************************************************************
44 * Get the next configuration directive argument, & return an u_short.
45 * The pool arg should be temporary storage.
47 static const char *get_u_short(pool
*p
, const char **arg
,
48 u_short
*num
, u_short min
)
52 const char *txt
= ap_getword_conf(p
, arg
);
58 tmp
= strtol(txt
, &ptr
, 10);
61 return ap_pstrcat(p
, "\"", txt
, "\" must be a positive integer", NULL
);
64 if (tmp
< min
|| tmp
> USHRT_MAX
) {
65 return ap_psprintf(p
, "\"%u\" must be >= %u and < %u", *num
, min
, USHRT_MAX
);
73 static const char *get_int(pool
*p
, const char **arg
, int *num
, int min
)
76 const char *val
= ap_getword_conf(p
, arg
);
83 *num
= (int) strtol(val
, &cp
, 10);
87 return ap_pstrcat(p
, "can't parse ", "\"", val
, "\"", NULL
);
91 return ap_psprintf(p
, "\"%d\" must be >= %d", *num
, min
);
97 /*******************************************************************************
98 * Get the next configuration directive argument, & return an u_int.
99 * The pool arg should be temporary storage.
101 static const char *get_u_int(pool
*p
, const char **arg
,
102 u_int
*num
, u_int min
)
105 const char *val
= ap_getword_conf(p
, arg
);
109 *num
= (u_int
)strtol(val
, &ptr
, 10);
112 return ap_pstrcat(p
, "\"", val
, "\" must be a positive integer", NULL
);
114 return ap_psprintf(p
, "\"%u\" must be >= %u", *num
, min
);
118 /*******************************************************************************
119 * Get the next configuration directive argument, & return a float.
120 * The pool arg should be temporary storage.
122 static const char *get_float(pool
*p
, const char **arg
,
123 float *num
, float min
, float max
)
126 const char *val
= ap_getword_conf(p
, arg
);
130 *num
= (float) strtod(val
, &ptr
);
133 return ap_pstrcat(p
, "\"", val
, "\" is not a floating point number", NULL
);
134 if (*num
< min
|| *num
> max
)
135 return ap_psprintf(p
, "\"%f\" is not between %f and %f", *num
, min
, max
);
139 const char *fcgi_config_set_env_var(pool
*p
, char **envp
, unsigned int *envc
, char * var
)
141 if (*envc
>= MAX_INIT_ENV_VARS
) {
142 return "too many variables, must be <= MAX_INIT_ENV_VARS";
145 if (strchr(var
, '=') == NULL
) {
146 *(envp
+ *envc
) = ap_pstrcat(p
, var
, "=", getenv(var
), NULL
);
149 *(envp
+ *envc
) = var
;
157 /*******************************************************************************
158 * Get the next configuration directive argument, & add it to an env array.
159 * The pool arg should be permanent storage.
161 static const char *get_env_var(pool
*p
, const char **arg
, char **envp
, unsigned int *envc
)
163 char * const val
= ap_getword_conf(p
, arg
);
169 return fcgi_config_set_env_var(p
, envp
, envc
, val
);
172 static const char *get_pass_header(pool
*p
, const char **arg
, array_header
**array
)
177 *array
= ap_make_array(p
, 10, sizeof(char*));
180 header
= (const char **)ap_push_array(*array
);
181 *header
= ap_getword_conf(p
, arg
);
183 return header
? NULL
: "\"\"";
186 /*******************************************************************************
187 * Return a "standard" message for common configuration errors.
189 static const char *invalid_value(pool
*p
, const char *cmd
, const char *id
,
190 const char *opt
, const char *err
)
192 return ap_psprintf(p
, "%s%s%s: invalid value for %s: %s",
193 cmd
, id
? " " : "", id
? id
: "", opt
, err
);
196 /*******************************************************************************
197 * Set/Reset the uid/gid that Apache and the PM will run as. This is ap_user_id
198 * and ap_group_id if we're started as root, and euid/egid otherwise. Also try
199 * to check that the config files don't set the User/Group after a FastCGI
200 * directive is used that depends on it.
202 /*@@@ To be complete, we should save a handle to the server each AppClass is
203 * configured in and at init() check that the user/group is still what we
204 * thought it was. Also the other directives should only be allowed in the
205 * parent Apache server.
207 const char *fcgi_config_set_fcgi_uid_n_gid(int set
)
209 static int isSet
= 0;
211 uid_t uid
= geteuid();
212 gid_t gid
= getegid();
216 fcgi_user_id
= (uid_t
)-1;
217 fcgi_group_id
= (gid_t
)-1;
221 uid
= uid
? uid
: ap_user_id
;
222 gid
= gid
? gid
: ap_group_id
;
224 if (isSet
&& (uid
!= fcgi_user_id
|| gid
!= fcgi_group_id
)) {
225 return "User/Group commands must preceed FastCGI server definitions";
235 void fcgi_config_reset_globals(void* dummy
)
237 fcgi_config_pool
= NULL
;
239 fcgi_config_set_fcgi_uid_n_gid(0);
241 fcgi_socket_dir
= DEFAULT_SOCK_DIR
;
243 fcgi_dynamic_total_proc_count
= 0;
244 fcgi_dynamic_epoch
= 0;
245 fcgi_dynamic_last_analyzed
= 0;
247 dynamicMaxProcs
= FCGI_DEFAULT_MAX_PROCS
;
248 dynamicMinProcs
= FCGI_DEFAULT_MIN_PROCS
;
249 dynamicMaxClassProcs
= FCGI_DEFAULT_MAX_CLASS_PROCS
;
250 dynamicKillInterval
= FCGI_DEFAULT_KILL_INTERVAL
;
251 dynamicUpdateInterval
= FCGI_DEFAULT_UPDATE_INTERVAL
;
252 dynamicGain
= FCGI_DEFAULT_GAIN
;
253 dynamicThreshold1
= FCGI_DEFAULT_THRESHOLD_1
;
254 dynamicThresholdN
= FCGI_DEFAULT_THRESHOLD_N
;
255 dynamicPleaseStartDelay
= FCGI_DEFAULT_START_PROCESS_DELAY
;
256 dynamicAppConnectTimeout
= FCGI_DEFAULT_APP_CONN_TIMEOUT
;
257 dynamicEnvp
= &fcgi_empty_env
;
258 dynamicProcessSlack
= FCGI_DEFAULT_PROCESS_SLACK
;
259 dynamicAutoRestart
= FCGI_DEFAULT_RESTART_DYNAMIC
;
260 dynamicAutoUpdate
= FCGI_DEFAULT_AUTOUPDATE
;
261 dynamicListenQueueDepth
= FCGI_DEFAULT_LISTEN_Q
;
262 dynamicInitStartDelay
= DEFAULT_INIT_START_DELAY
;
263 dynamicRestartDelay
= FCGI_DEFAULT_RESTART_DELAY
;
264 dynamic_pass_headers
= NULL
;
265 dynamic_idle_timeout
= FCGI_DEFAULT_IDLE_TIMEOUT
;
266 dynamicFlush
= FCGI_FLUSH
;
269 /* Close any old pipe (HUP/USR1) */
270 if (fcgi_pm_pipe
[0] != -1) {
271 close(fcgi_pm_pipe
[0]);
272 fcgi_pm_pipe
[0] = -1;
274 if (fcgi_pm_pipe
[1] != -1) {
275 close(fcgi_pm_pipe
[1]);
276 fcgi_pm_pipe
[1] = -1;
281 /*******************************************************************************
282 * Create a directory to hold Unix/Domain sockets.
284 const char *fcgi_config_make_dir(pool
*tp
, char *path
)
287 const char *err
= NULL
;
289 /* Is the directory spec'd correctly */
291 return "path is not absolute (it must start with a \"/\")";
294 int i
= strlen(path
) - 1;
296 /* Strip trailing "/"s */
297 while(i
> 0 && path
[i
] == '/') path
[i
--] = '\0';
301 if (stat(path
, &finfo
) != 0) {
302 /* No, but maybe we can create it */
304 if (mkdir(path
) != 0)
306 if (mkdir(path
, S_IRWXU
) != 0)
309 return ap_psprintf(tp
,
310 "doesn't exist and can't be created: %s",
315 /* If we're root, we're gonna setuid/setgid so we need to chown */
316 if (geteuid() == 0 && chown(path
, ap_user_id
, ap_group_id
) != 0) {
317 return ap_psprintf(tp
,
318 "can't chown() to the server (uid %ld, gid %ld): %s",
319 (long)ap_user_id
, (long)ap_group_id
, strerror(errno
));
324 /* Yes, is it a directory? */
325 if (!S_ISDIR(finfo
.st_mode
))
326 return "isn't a directory!";
328 /* Can we RWX in there? */
330 err
= fcgi_util_check_access(tp
, NULL
, &finfo
, _S_IREAD
| _S_IWRITE
| _S_IEXEC
, fcgi_user_id
, fcgi_group_id
);
332 err
= fcgi_util_check_access(tp
, NULL
, &finfo
, R_OK
| W_OK
| X_OK
,
333 fcgi_user_id
, fcgi_group_id
);
336 return ap_psprintf(tp
,
337 "access for server (uid %ld, gid %ld) failed: %s",
338 (long)fcgi_user_id
, (long)fcgi_group_id
, err
);
344 /*******************************************************************************
345 * Create a "dynamic" subdirectory. If the directory
346 * already exists we don't mess with it unless 'wax' is set.
348 const char *fcgi_config_make_dynamic_dir(pool
*p
, const int wax
)
352 struct dirent
*dirp
= NULL
;
356 fcgi_dynamic_dir
= ap_pstrcat(p
, fcgi_socket_dir
, "/dynamic", NULL
);
358 if ((err
= fcgi_config_make_dir(p
, fcgi_dynamic_dir
)))
359 return ap_psprintf(p
, "can't create dynamic directory \"%s\": %s", fcgi_dynamic_dir
, err
);
361 /* Don't step on a running server unless its OK. */
365 /* Create a subpool for the directory operations */
366 tp
= ap_make_sub_pool(p
);
368 dp
= ap_popendir(tp
, fcgi_dynamic_dir
);
371 return ap_psprintf(p
, "can't open dynamic directory \"%s\": %s",
372 fcgi_dynamic_dir
, strerror(errno
));
375 /* Delete everything in the directory, its all FCGI specific */
376 while ((dirp
= readdir(dp
)) != NULL
) {
377 if (strcmp(dirp
->d_name
, ".") == 0
378 || strcmp(dirp
->d_name
, "..") == 0) {
382 unlink(ap_pstrcat(tp
, fcgi_dynamic_dir
, "/", dirp
->d_name
, NULL
));
388 fcgi_dynamic_dir
= ap_pstrcat(p
, fcgi_socket_dir
, "dynamic", NULL
);
394 /*******************************************************************************
395 * Change the directory used for the Unix/Domain sockets from the default.
396 * Create the directory and the "dynamic" subdirectory.
398 const char *fcgi_config_set_socket_dir(cmd_parms
*cmd
, void *dummy
, char *arg
)
400 pool
* const tp
= cmd
->temp_pool
;
401 const char * const name
= cmd
->cmd
->name
;
404 if (strcmp(fcgi_socket_dir
, DEFAULT_SOCK_DIR
) != 0) {
405 return ap_psprintf(tp
, "%s %s: already defined as \"%s\"",
406 name
, arg
, fcgi_socket_dir
);
409 err
= fcgi_config_set_fcgi_uid_n_gid(1);
411 return ap_psprintf(tp
, "%s %s: %s", name
, arg
, err
);
413 if (fcgi_servers
!= NULL
) {
414 return ap_psprintf(tp
,
415 "The %s command must preceed static FastCGI server definitions",
420 arg
= ap_os_canonical_filename(cmd
->pool
, arg
);
421 arg
= ap_server_root_relative(cmd
->pool
, arg
);
423 if (strncmp(arg
, "\\\\.\\pipe\\", 9) != 0)
424 return ap_psprintf(tp
, "%s %s is invalid format",name
, arg
);
427 fcgi_socket_dir
= arg
;
430 err
= fcgi_config_make_dir(tp
, fcgi_socket_dir
);
432 return ap_psprintf(tp
, "%s %s: %s", name
, arg
, err
);
434 err
= fcgi_config_make_dynamic_dir(cmd
->pool
, 0);
436 return ap_psprintf(tp
, "%s %s: %s", name
, arg
, err
);
442 /*******************************************************************************
443 * Enable, disable, or specify the path to a wrapper used to invoke all
444 * FastCGI applications.
446 const char *fcgi_config_set_wrapper(cmd_parms
*cmd
, void *dummy
, const char *arg
)
448 const char *err
= NULL
;
449 const char * const name
= cmd
->cmd
->name
;
450 pool
* const tp
= cmd
->temp_pool
;
453 if (!ap_suexec_enabled
&& strcasecmp(arg
, "On") == 0) {
454 fprintf(stderr
, "Warning: \"%s On\" requires SUEXEC be enabled in Apache", name
);
458 err
= fcgi_config_set_fcgi_uid_n_gid(1);
460 return ap_psprintf(tp
, "%s %s: %s", name
, arg
, err
);
462 if (fcgi_servers
!= NULL
) {
463 return ap_psprintf(tp
,
464 "The %s command must preceed static FastCGI server definitions", name
);
467 if (strcasecmp(arg
, "On") == 0) {
468 fcgi_wrapper
= SUEXEC_BIN
;
470 else if (strcasecmp(arg
, "Off") == 0) {
474 wrapper
= (char *) ap_os_canonical_filename(cmd
->pool
, arg
);
475 wrapper
= ap_server_root_relative(cmd
->pool
, wrapper
);
478 err
= fcgi_util_check_access(tp
, wrapper
, NULL
, _S_IEXEC
, fcgi_user_id
, fcgi_group_id
);
480 err
= fcgi_util_check_access(tp
, wrapper
, NULL
, X_OK
, fcgi_user_id
, fcgi_group_id
);
484 return ap_psprintf(tp
,
485 "%s: \"%s\" access for server (uid %ld, gid %ld) failed: %s",
486 name
, wrapper
, (long)fcgi_user_id
, (long)fcgi_group_id
, err
);
489 fcgi_wrapper
= wrapper
;
494 /*******************************************************************************
495 * Configure a static FastCGI server.
497 const char *fcgi_config_new_static_server(cmd_parms
*cmd
, void *dummy
, const char *arg
)
500 pool
*p
= cmd
->pool
, *tp
= cmd
->temp_pool
;
501 const char *name
= cmd
->cmd
->name
;
502 char *fs_path
= ap_getword_conf(p
, &arg
);
503 const char *option
, *err
;
505 /* Allocate temp storage for the array of initial environment variables */
506 char **envp
= ap_pcalloc(tp
, sizeof(char *) * (MAX_INIT_ENV_VARS
+ 3));
507 unsigned int envc
= 0;
513 if (*fs_path
== '\0')
514 return "AppClass requires a pathname!?";
516 if ((err
= fcgi_config_set_fcgi_uid_n_gid(1)) != NULL
)
517 return ap_psprintf(tp
, "%s %s: %s", name
, fs_path
, err
);
519 fs_path
= ap_os_canonical_filename(p
, fs_path
);
520 fs_path
= ap_server_root_relative(p
, fs_path
);
522 ap_getparents(fs_path
);
523 ap_no2slash(fs_path
);
525 /* See if we've already got one of these configured */
526 s
= fcgi_util_fs_get_by_id(fs_path
, cmd
->server
->server_uid
,
527 cmd
->server
->server_gid
);
530 return ap_psprintf(tp
,
531 "%s: redefinition of a previously defined FastCGI server \"%s\" with uid=%ld and gid=%ld",
532 name
, fs_path
, (long)cmd
->server
->server_uid
,
533 (long)cmd
->server
->server_gid
);
536 return ap_psprintf(tp
,
537 "%s: redefinition of a previously defined FastCGI server \"%s\"",
542 err
= fcgi_util_fs_is_path_ok(tp
, fs_path
, NULL
);
544 return ap_psprintf(tp
, "%s: \"%s\" %s", name
, fs_path
, err
);
547 s
= fcgi_util_fs_new(p
);
548 s
->fs_path
= fs_path
;
549 s
->directive
= APP_CLASS_STANDARD
;
550 s
->restartOnExit
= TRUE
;
554 // TCP FastCGI applications require SystemRoot be present in the environment
555 // Put it in both for consistency to the application
556 fcgi_config_set_env_var(tp
, envp
, &envc
, "SystemRoot");
558 mutex
= CreateMutex(NULL
, FALSE
, fs_path
);
562 ap_log_error(FCGI_LOG_ALERT
, fcgi_apache_main_server
,
563 "FastCGI: CreateMutex() failed");
564 return "failed to create FastCGI application accept mutex";
567 SetHandleInformation(mutex
, HANDLE_FLAG_INHERIT
, TRUE
);
569 s
->mutex_env_string
= ap_psprintf(p
, "_FCGI_MUTEX_=%ld", mutex
);;
575 s
->uid
= cmd
->server
->server_uid
;
576 pw
= getpwuid(s
->uid
);
578 return ap_psprintf(tp
, "mod_fastcgi: "
579 "getpwuid() couldn't determine the username for uid '%ld', "
580 "you probably need to modify the User directive: %s",
581 (long)s
->uid
, strerror(errno
));
583 s
->user
= ap_pstrdup(p
, pw
->pw_name
);
584 s
->username
= s
->user
;
586 s
->gid
= cmd
->server
->server_gid
;
587 gr
= getgrgid(s
->gid
);
589 return ap_psprintf(tp
, "mod_fastcgi: "
590 "getgrgid() couldn't determine the group name for gid '%ld', "
591 "you probably need to modify the Group directive: %s\n",
592 (long)s
->gid
, strerror(errno
));
594 s
->group
= ap_pstrdup(p
, gr
->gr_name
);
598 /* Parse directive arguments */
600 option
= ap_getword_conf(tp
, &arg
);
602 if (strcasecmp(option
, "-processes") == 0) {
603 if ((err
= get_u_int(tp
, &arg
, &s
->numProcesses
, 1)))
604 return invalid_value(tp
, name
, fs_path
, option
, err
);
606 else if (strcasecmp(option
, "-restart-delay") == 0) {
607 if ((err
= get_u_int(tp
, &arg
, &s
->restartDelay
, 0)))
608 return invalid_value(tp
, name
, fs_path
, option
, err
);
610 else if (strcasecmp(option
, "-init-start-delay") == 0) {
611 if ((err
= get_int(tp
, &arg
, &s
->initStartDelay
, 0)))
612 return invalid_value(tp
, name
, fs_path
, option
, err
);
614 else if (strcasecmp(option
, "-priority") == 0) {
615 if ((err
= get_u_int(tp
, &arg
, &s
->processPriority
, 0)))
616 return invalid_value(tp
, name
, fs_path
, option
, err
);
618 else if (strcasecmp(option
, "-listen-queue-depth") == 0) {
619 if ((err
= get_u_int(tp
, &arg
, &s
->listenQueueDepth
, 1)))
620 return invalid_value(tp
, name
, fs_path
, option
, err
);
622 else if (strcasecmp(option
, "-appConnTimeout") == 0) {
623 if ((err
= get_u_int(tp
, &arg
, &s
->appConnectTimeout
, 0)))
624 return invalid_value(tp
, name
, fs_path
, option
, err
);
626 else if (strcasecmp(option
, "-idle-timeout") == 0) {
627 if ((err
= get_u_int(tp
, &arg
, &s
->idle_timeout
, 1)))
628 return invalid_value(tp
, name
, fs_path
, option
, err
);
630 else if (strcasecmp(option
, "-port") == 0) {
631 if ((err
= get_u_short(tp
, &arg
, &s
->port
, 1)))
632 return invalid_value(tp
, name
, fs_path
, option
, err
);
634 else if (strcasecmp(option
, "-socket") == 0) {
635 s
->socket_path
= ap_getword_conf(tp
, &arg
);
636 if (*s
->socket_path
== '\0')
637 return invalid_value(tp
, name
, fs_path
, option
, "\"\"");
639 else if (strcasecmp(option
, "-initial-env") == 0) {
640 if ((err
= get_env_var(p
, &arg
, envp
, &envc
)))
641 return invalid_value(tp
, name
, fs_path
, option
, err
);
643 else if (strcasecmp(option
, "-pass-header") == 0) {
644 if ((err
= get_pass_header(p
, &arg
, &s
->pass_headers
)))
645 return invalid_value(tp
, name
, fs_path
, option
, err
);
647 else if (strcasecmp(option
, "-flush") == 0) {
651 return ap_psprintf(tp
, "%s %s: invalid option: %s", name
, fs_path
, option
);
655 if (s
->socket_path
!= NULL
&& s
->port
!= 0) {
656 return ap_psprintf(tp
,
657 "%s %s: -port and -socket are mutually exclusive options",
661 /* Move env array to a surviving pool */
663 s
->envp
= (char **)ap_palloc(p
, sizeof(char *) * ++envc
);
664 memcpy(s
->envp
, envp
, sizeof(char *) * envc
);
666 /* Initialize process structs */
667 s
->procs
= fcgi_util_fs_create_procs(p
, s
->numProcesses
);
669 /* Build the appropriate sockaddr structure */
671 err
= fcgi_util_socket_make_inet_addr(p
, (struct sockaddr_in
**)&s
->socket_addr
,
672 &s
->socket_addr_len
, NULL
, s
->port
);
674 return ap_psprintf(tp
, "%s %s: %s", name
, fs_path
, err
);
676 err
= fcgi_util_socket_make_inet_addr(p
, (struct sockaddr_in
**)&s
->dest_addr
,
677 &s
->socket_addr_len
, "localhost", s
->port
);
679 return ap_psprintf(tp
, "%s %s: %s", name
, fs_path
, err
);
682 if (s
->socket_path
== NULL
)
683 s
->socket_path
= fcgi_util_socket_hash_filename(tp
, fs_path
, s
->user
, s
->group
);
684 s
->socket_path
= fcgi_util_socket_make_path_absolute(p
, s
->socket_path
, 0);
686 err
= fcgi_util_socket_make_domain_addr(p
, (struct sockaddr_un
**)&s
->socket_addr
,
687 &s
->socket_addr_len
, s
->socket_path
);
689 return ap_psprintf(tp
, "%s %s: %s", name
, fs_path
, err
);
693 /* Add it to the list of FastCGI servers */
699 /*******************************************************************************
700 * Configure a static FastCGI server that is started/managed elsewhere.
702 const char *fcgi_config_new_external_server(cmd_parms
*cmd
, void *dummy
, const char *arg
)
705 pool
* const p
= cmd
->pool
, *tp
= cmd
->temp_pool
;
706 const char * const name
= cmd
->cmd
->name
;
707 char *fs_path
= ap_getword_conf(p
, &arg
);
708 const char *option
, *err
;
711 return ap_pstrcat(tp
, name
, " requires a path and either a -socket or -host option", NULL
);
714 fs_path
= ap_os_canonical_filename(p
, fs_path
);
715 fs_path
= ap_server_root_relative(p
, fs_path
);
717 ap_getparents(fs_path
);
718 ap_no2slash(fs_path
);
720 /* See if we've already got one of these bettys configured */
721 s
= fcgi_util_fs_get_by_id(fs_path
, cmd
->server
->server_uid
,
722 cmd
->server
->server_gid
);
725 return ap_psprintf(tp
,
726 "%s: redefinition of a previously defined class \"%s\" with uid=%ld and gid=%ld",
727 name
, fs_path
, (long)cmd
->server
->server_uid
,
728 (long)cmd
->server
->server_gid
);
731 return ap_psprintf(tp
,
732 "%s: redefinition of previously defined class \"%s\"", name
, fs_path
);
736 s
= fcgi_util_fs_new(p
);
737 s
->fs_path
= fs_path
;
738 s
->directive
= APP_CLASS_EXTERNAL
;
740 err
= fcgi_util_fs_set_uid_n_gid(p
, s
, cmd
->server
->server_uid
, cmd
->server
->server_gid
);
742 return ap_psprintf(tp
, "%s %s: %s", name
, fs_path
, err
);
744 /* Parse directive arguments */
745 while (*arg
!= '\0') {
746 option
= ap_getword_conf(tp
, &arg
);
748 if (strcasecmp(option
, "-host") == 0) {
749 if ((err
= get_host_n_port(p
, &arg
, &s
->host
, &s
->port
)))
750 return invalid_value(tp
, name
, fs_path
, option
, err
);
752 else if (strcasecmp(option
, "-socket") == 0) {
753 s
->socket_path
= ap_getword_conf(tp
, &arg
);
754 if (*s
->socket_path
== '\0')
755 return invalid_value(tp
, name
, fs_path
, option
, "\"\"");
757 else if (strcasecmp(option
, "-appConnTimeout") == 0) {
758 if ((err
= get_u_int(tp
, &arg
, &s
->appConnectTimeout
, 0)))
759 return invalid_value(tp
, name
, fs_path
, option
, err
);
761 else if (strcasecmp(option
, "-idle-timeout") == 0) {
762 if ((err
= get_u_int(tp
, &arg
, &s
->idle_timeout
, 1)))
763 return invalid_value(tp
, name
, fs_path
, option
, err
);
765 else if (strcasecmp(option
, "-pass-header") == 0) {
766 if ((err
= get_pass_header(p
, &arg
, &s
->pass_headers
)))
767 return invalid_value(tp
, name
, fs_path
, option
, err
);
769 else if (strcasecmp(option
, "-flush") == 0) {
773 return ap_psprintf(tp
, "%s %s: invalid option: %s", name
, fs_path
, option
);
777 /* Require one of -socket or -host, but not both */
778 if (s
->socket_path
!= NULL
&& s
->port
!= 0) {
779 return ap_psprintf(tp
,
780 "%s %s: -host and -socket are mutually exclusive options",
783 if (s
->socket_path
== NULL
&& s
->port
== 0) {
784 return ap_psprintf(tp
,
785 "%s %s: -socket or -host option missing", name
, fs_path
);
788 /* Build the appropriate sockaddr structure */
790 err
= fcgi_util_socket_make_inet_addr(p
, (struct sockaddr_in
**)&s
->socket_addr
,
791 &s
->socket_addr_len
, s
->host
, s
->port
);
793 return ap_psprintf(tp
, "%s %s: %s", name
, fs_path
, err
);
795 s
->socket_path
= fcgi_util_socket_make_path_absolute(p
, s
->socket_path
, 0);
797 err
= fcgi_util_socket_make_domain_addr(p
, (struct sockaddr_un
**)&s
->socket_addr
,
798 &s
->socket_addr_len
, s
->socket_path
);
800 return ap_psprintf(tp
, "%s %s: %s", name
, fs_path
, err
);
804 /* Add it to the list of FastCGI servers */
811 *----------------------------------------------------------------------
813 * fcgi_config_set_config --
815 * Implements the FastCGI FCGIConfig configuration directive.
816 * This command adds routines to control the execution of the
817 * dynamic FastCGI processes.
820 *----------------------------------------------------------------------
822 const char *fcgi_config_set_config(cmd_parms
*cmd
, void *dummy
, const char *arg
)
824 pool
* const p
= cmd
->pool
;
825 pool
* const tp
= cmd
->temp_pool
;
826 const char *err
, *option
;
827 const char * const name
= cmd
->cmd
->name
;
829 /* Allocate temp storage for an initial environment */
830 unsigned int envc
= 0;
831 char **envp
= (char **)ap_pcalloc(tp
, sizeof(char *) * (MAX_INIT_ENV_VARS
+ 3));
833 /* Parse the directive arguments */
835 option
= ap_getword_conf(tp
, &arg
);
837 if (strcasecmp(option
, "-maxProcesses") == 0) {
838 if ((err
= get_u_int(tp
, &arg
, &dynamicMaxProcs
, 1)))
839 return invalid_value(tp
, name
, NULL
, option
, err
);
841 else if (strcasecmp(option
, "-minProcesses") == 0) {
842 if ((err
= get_int(tp
, &arg
, &dynamicMinProcs
, 0)))
843 return invalid_value(tp
, name
, NULL
, option
, err
);
845 else if (strcasecmp(option
, "-maxClassProcesses") == 0) {
846 if ((err
= get_int(tp
, &arg
, &dynamicMaxClassProcs
, 1)))
847 return invalid_value(tp
, name
, NULL
, option
, err
);
849 else if (strcasecmp(option
, "-killInterval") == 0) {
850 if ((err
= get_u_int(tp
, &arg
, &dynamicKillInterval
, 1)))
851 return invalid_value(tp
, name
, NULL
, option
, err
);
853 else if (strcasecmp(option
, "-updateInterval") == 0) {
854 if ((err
= get_u_int(tp
, &arg
, &dynamicUpdateInterval
, 1)))
855 return invalid_value(tp
, name
, NULL
, option
, err
);
857 else if (strcasecmp(option
, "-gainValue") == 0) {
858 if ((err
= get_float(tp
, &arg
, &dynamicGain
, 0.0, 1.0)))
859 return invalid_value(tp
, name
, NULL
, option
, err
);
861 else if ((strcasecmp(option
, "-singleThreshold") == 0)
862 || (strcasecmp(option
, "-singleThreshhold") == 0))
864 if ((err
= get_int(tp
, &arg
, &dynamicThreshold1
, 0)))
865 return invalid_value(tp
, name
, NULL
, option
, err
);
867 else if ((strcasecmp(option
, "-multiThreshold") == 0)
868 || (strcasecmp(option
, "-multiThreshhold") == 0))
870 if ((err
= get_int(tp
, &arg
, &dynamicThresholdN
, 0)))
871 return invalid_value(tp
, name
, NULL
, option
, err
);
873 else if (strcasecmp(option
, "-startDelay") == 0) {
874 if ((err
= get_u_int(tp
, &arg
, &dynamicPleaseStartDelay
, 1)))
875 return invalid_value(tp
, name
, NULL
, option
, err
);
877 else if (strcasecmp(option
, "-initial-env") == 0) {
878 if ((err
= get_env_var(p
, &arg
, envp
, &envc
)))
879 return invalid_value(tp
, name
, NULL
, option
, err
);
881 else if (strcasecmp(option
, "-pass-header") == 0) {
882 if ((err
= get_pass_header(p
, &arg
, &dynamic_pass_headers
)))
883 return invalid_value(tp
, name
, NULL
, option
, err
);
885 else if (strcasecmp(option
, "-appConnTimeout") == 0) {
886 if ((err
= get_u_int(tp
, &arg
, &dynamicAppConnectTimeout
, 0)))
887 return invalid_value(tp
, name
, NULL
, option
, err
);
889 else if (strcasecmp(option
, "-idle-timeout") == 0) {
890 if ((err
= get_u_int(tp
, &arg
, &dynamic_idle_timeout
, 1)))
891 return invalid_value(tp
, name
, NULL
, option
, err
);
893 else if (strcasecmp(option
, "-listen-queue-depth") == 0) {
894 if ((err
= get_u_int(tp
, &arg
, &dynamicListenQueueDepth
, 1)))
895 return invalid_value(tp
, name
, NULL
, option
, err
);
897 else if (strcasecmp(option
, "-restart-delay") == 0) {
898 if ((err
= get_u_int(tp
, &arg
, &dynamicRestartDelay
, 0)))
899 return invalid_value(tp
, name
, NULL
, option
, err
);
901 else if (strcasecmp(option
, "-init-start-delay") == 0) {
902 if ((err
= get_u_int(tp
, &arg
, &dynamicInitStartDelay
, 0)))
903 return invalid_value(tp
, name
, NULL
, option
, err
);
905 else if (strcasecmp(option
, "-processSlack") == 0) {
906 if ((err
= get_u_int(tp
, &arg
, &dynamicProcessSlack
, 1)))
907 return invalid_value(tp
, name
, NULL
, option
, err
);
909 else if (strcasecmp(option
, "-restart") == 0) {
910 dynamicAutoRestart
= 1;
912 else if (strcasecmp(option
, "-autoUpdate") == 0) {
913 dynamicAutoUpdate
= 1;
915 else if (strcasecmp(option
, "-flush") == 0) {
919 return ap_psprintf(tp
, "%s: invalid option: %s", name
, option
);
923 if (dynamicProcessSlack
>= dynamicMaxProcs
+ 1) {
924 /* the kill policy would work unexpectedly */
925 return ap_psprintf(tp
,
926 "%s: processSlack (%u) must be less than maxProcesses (%u) + 1",
927 name
, dynamicProcessSlack
, dynamicMaxProcs
);
930 /* Move env array to a surviving pool, leave an extra slot for WIN32 _FCGI_MUTEX_ */
932 dynamicEnvp
= (char **)ap_palloc(p
, sizeof(char *) * ++envc
);
933 memcpy(dynamicEnvp
, envp
, sizeof(char *) * envc
);
938 void *fcgi_config_create_dir_config(pool
*p
, char *dummy
)
940 fcgi_dir_config
*dir_config
= ap_pcalloc(p
, sizeof(fcgi_dir_config
));
942 dir_config
->authenticator_options
= FCGI_AUTHORITATIVE
;
943 dir_config
->authorizer_options
= FCGI_AUTHORITATIVE
;
944 dir_config
->access_checker_options
= FCGI_AUTHORITATIVE
;
950 const char *fcgi_config_new_auth_server(cmd_parms
* const cmd
,
951 fcgi_dir_config
*dir_config
, const char *fs_path
, const char * const compat
)
953 pool
* const tp
= cmd
->temp_pool
;
954 const uid_t uid
= cmd
->server
->server_uid
;
955 const gid_t gid
= cmd
->server
->server_gid
;
958 auth_server
= (char *) ap_os_canonical_filename(cmd
->pool
, fs_path
);
959 auth_server
= ap_server_root_relative(cmd
->pool
, auth_server
);
961 /* Make sure its already configured or at least a candidate for dynamic */
962 if (fcgi_util_fs_get_by_id(auth_server
, uid
, gid
) == NULL
) {
963 const char *err
= fcgi_util_fs_is_path_ok(tp
, auth_server
, NULL
);
965 return ap_psprintf(tp
, "%s: \"%s\" %s", cmd
->cmd
->name
, auth_server
, err
);
968 if (compat
&& strcasecmp(compat
, "-compat"))
969 return ap_psprintf(cmd
->temp_pool
, "%s: unknown option: \"%s\"", cmd
->cmd
->name
, compat
);
971 switch((int)cmd
->info
) {
972 case FCGI_AUTH_TYPE_AUTHENTICATOR
:
973 dir_config
->authenticator
= auth_server
;
974 dir_config
->authenticator_options
|= (compat
) ? FCGI_COMPAT
: 0;
976 case FCGI_AUTH_TYPE_AUTHORIZER
:
977 dir_config
->authorizer
= auth_server
;
978 dir_config
->authorizer_options
|= (compat
) ? FCGI_COMPAT
: 0;
980 case FCGI_AUTH_TYPE_ACCESS_CHECKER
:
981 dir_config
->access_checker
= auth_server
;
982 dir_config
->access_checker_options
|= (compat
) ? FCGI_COMPAT
: 0;
989 const char *fcgi_config_set_authoritative_slot(const cmd_parms
* const cmd
,
990 fcgi_dir_config
* const dir_config
, int arg
)
992 int offset
= (int)(long)cmd
->info
;
995 *((u_char
*)dir_config
+ offset
) |= FCGI_AUTHORITATIVE
;
997 *((u_char
*)dir_config
+ offset
) &= ~FCGI_AUTHORITATIVE
;