2 * $Id: fcgi_config.c,v 1.50 2004/01/07 01:56:00 robs Exp $
11 #include "mpm_common.h" /* ap_uname2id, ap_gname2id */
23 /* warning C4100: unreferenced formal parameter */
24 /* warning C4706: assignment within conditional expression */
25 #pragma warning( disable : 4100 4706 )
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.
33 static const char *get_host_n_port(pool
*p
, const char **arg
,
34 const char **host
, u_short
*port
)
36 char *cvptr
, *portStr
;
39 *host
= ap_getword_conf(p
, arg
);
43 portStr
= strchr(*host
, ':');
45 return "missing port specification";
47 /* Split the host and port portions */
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
);
55 *port
= (unsigned short) tmp
;
60 /*******************************************************************************
61 * Get the next configuration directive argument, & return an u_short.
62 * The pool arg should be temporary storage.
64 static const char *get_u_short(pool
*p
, const char **arg
,
65 u_short
*num
, u_short min
)
69 const char *txt
= ap_getword_conf(p
, arg
);
75 tmp
= strtol(txt
, &ptr
, 10);
78 return ap_pstrcat(p
, "\"", txt
, "\" must be a positive integer", NULL
);
81 if (tmp
< min
|| tmp
> USHRT_MAX
) {
82 return ap_psprintf(p
, "\"%u\" must be >= %u and < %u", *num
, min
, USHRT_MAX
);
90 static const char *get_int(pool
*p
, const char **arg
, int *num
, int min
)
93 const char *val
= ap_getword_conf(p
, arg
);
100 *num
= (int) strtol(val
, &cp
, 10);
104 return ap_pstrcat(p
, "can't parse ", "\"", val
, "\"", NULL
);
108 return ap_psprintf(p
, "\"%d\" must be >= %d", *num
, min
);
114 /*******************************************************************************
115 * Get the next configuration directive argument, & return an u_int.
116 * The pool arg should be temporary storage.
118 static const char *get_u_int(pool
*p
, const char **arg
,
119 u_int
*num
, u_int min
)
122 const char *val
= ap_getword_conf(p
, arg
);
126 *num
= (u_int
)strtol(val
, &ptr
, 10);
129 return ap_pstrcat(p
, "\"", val
, "\" must be a positive integer", NULL
);
131 return ap_psprintf(p
, "\"%u\" must be >= %u", *num
, min
);
135 /*******************************************************************************
136 * Get the next configuration directive argument, & return a float.
137 * The pool arg should be temporary storage.
139 static const char *get_float(pool
*p
, const char **arg
,
140 float *num
, float min
, float max
)
143 const char *val
= ap_getword_conf(p
, arg
);
147 *num
= (float) strtod(val
, &ptr
);
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
);
156 const char *fcgi_config_set_env_var(pool
*p
, char **envp
, unsigned int *envc
, char * var
)
158 if (*envc
>= MAX_INIT_ENV_VARS
) {
159 return "too many variables, must be <= MAX_INIT_ENV_VARS";
162 if (strchr(var
, '=') == NULL
) {
163 *(envp
+ *envc
) = ap_pstrcat(p
, var
, "=", getenv(var
), NULL
);
166 *(envp
+ *envc
) = var
;
174 /*******************************************************************************
175 * Get the next configuration directive argument, & add it to an env array.
176 * The pool arg should be permanent storage.
178 static const char *get_env_var(pool
*p
, const char **arg
, char **envp
, unsigned int *envc
)
180 char * const val
= ap_getword_conf(p
, arg
);
186 return fcgi_config_set_env_var(p
, envp
, envc
, val
);
189 static const char *get_pass_header(pool
*p
, const char **arg
, array_header
**array
)
194 *array
= ap_make_array(p
, 10, sizeof(char*));
197 header
= (const char **)ap_push_array(*array
);
198 *header
= ap_getword_conf(p
, arg
);
200 return header
? NULL
: "\"\"";
203 /*******************************************************************************
204 * Return a "standard" message for common configuration errors.
206 static const char *invalid_value(pool
*p
, const char *cmd
, const char *id
,
207 const char *opt
, const char *err
)
209 return ap_psprintf(p
, "%s%s%s: invalid value for %s: %s",
210 cmd
, id
? " " : "", id
? id
: "", opt
, err
);
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.
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.
224 const char *fcgi_config_set_fcgi_uid_n_gid(int set
)
226 static int isSet
= 0;
230 uid_t uid
= geteuid();
231 gid_t gid
= getegid();
235 fcgi_user_id
= (uid_t
)-1;
236 fcgi_group_id
= (gid_t
)-1;
248 if (isSet
&& (uid
!= fcgi_user_id
|| gid
!= fcgi_group_id
)) {
249 return "User/Group commands must preceed FastCGI server definitions";
261 apcb_t
fcgi_config_reset_globals(void* dummy
)
263 fcgi_config_pool
= NULL
;
265 fcgi_config_set_fcgi_uid_n_gid(0);
267 fcgi_socket_dir
= NULL
;
269 fcgi_dynamic_total_proc_count
= 0;
270 fcgi_dynamic_epoch
= 0;
271 fcgi_dynamic_last_analyzed
= 0;
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
;
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;
301 if (fcgi_pm_pipe
[1] != -1) {
302 close(fcgi_pm_pipe
[1]);
303 fcgi_pm_pipe
[1] = -1;
310 /*******************************************************************************
311 * Create a directory to hold Unix/Domain sockets.
313 const char *fcgi_config_make_dir(pool
*tp
, char *path
)
316 const char *err
= NULL
;
318 /* Is the directory spec'd correctly */
320 return "path is not absolute (it must start with a \"/\")";
323 int i
= strlen(path
) - 1;
325 /* Strip trailing "/"s */
326 while(i
> 0 && path
[i
] == '/') path
[i
--] = '\0';
330 if (stat(path
, &finfo
) != 0) {
331 /* No, but maybe we can create it */
333 if (mkdir(path
) != 0)
335 if (mkdir(path
, S_IRWXU
) != 0)
338 return ap_psprintf(tp
,
339 "doesn't exist and can't be created: %s",
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
));
353 /* Yes, is it a directory? */
354 if (!S_ISDIR(finfo
.st_mode
))
355 return "isn't a directory!";
357 /* Can we RWX in there? */
359 err
= fcgi_util_check_access(tp
, NULL
, &finfo
, _S_IREAD
| _S_IWRITE
| _S_IEXEC
, fcgi_user_id
, fcgi_group_id
);
361 err
= fcgi_util_check_access(tp
, NULL
, &finfo
, R_OK
| W_OK
| X_OK
,
362 fcgi_user_id
, fcgi_group_id
);
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
);
373 /*******************************************************************************
374 * Create a "dynamic" subdirectory. If the directory
375 * already exists we don't mess with it unless 'wax' is set.
378 const char *fcgi_config_make_dynamic_dir(pool
*p
, const int wax
)
383 fcgi_dynamic_dir
= ap_pstrcat(p
, fcgi_socket_dir
, "/dynamic", NULL
);
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
);
388 /* Don't step on a running server unless its OK. */
397 if (apr_pool_create(&tp
, p
))
398 return "apr_pool_create() failed";
400 if (apr_dir_open(&dir
, fcgi_dynamic_dir
, tp
))
401 return "apr_dir_open() failed";
403 /* delete the contents */
405 while (apr_dir_read(&finfo
, APR_FINFO_NAME
, dir
) == APR_SUCCESS
)
407 if (strcmp(finfo
.name
, ".") == 0 || strcmp(finfo
.name
, "..") == 0)
410 apr_file_remove(finfo
.name
, tp
);
417 struct dirent
*dirp
= NULL
;
419 tp
= ap_make_sub_pool(p
);
421 dp
= ap_popendir(tp
, fcgi_dynamic_dir
);
424 return ap_psprintf(p
, "can't open dynamic directory \"%s\": %s",
425 fcgi_dynamic_dir
, strerror(errno
));
428 /* delete the contents */
430 while ((dirp
= readdir(dp
)) != NULL
)
432 if (strcmp(dirp
->d_name
, ".") == 0 || strcmp(dirp
->d_name
, "..") == 0)
435 unlink(ap_pstrcat(tp
, fcgi_dynamic_dir
, "/", dirp
->d_name
, NULL
));
439 #endif /* !APACHE2 */
447 /*******************************************************************************
448 * Change the directory used for the Unix/Domain sockets from the default.
449 * Create the directory and the "dynamic" subdirectory.
451 const char *fcgi_config_set_socket_dir(cmd_parms
*cmd
, void *dummy
, const char *arg
)
453 pool
* const tp
= cmd
->temp_pool
;
454 const char * const name
= cmd
->cmd
->name
;
458 err
= ap_check_cmd_context(cmd
, GLOBAL_ONLY
);
464 if (fcgi_socket_dir
) {
465 return ap_psprintf(tp
, "%s %s: already defined as \"%s\"",
466 name
, arg
, fcgi_socket_dir
);
469 err
= fcgi_config_set_fcgi_uid_n_gid(1);
471 return ap_psprintf(tp
, "%s %s: %s", name
, arg
, err
);
473 if (fcgi_servers
!= NULL
) {
474 return ap_psprintf(tp
,
475 "The %s command must preceed static FastCGI server definitions",
479 arg_nc
= ap_pstrdup(cmd
->pool
, arg
);
484 if (apr_filepath_merge(&arg_nc
, "", arg
, 0, cmd
->pool
))
485 return ap_psprintf(tp
, "%s %s: invalid filepath", name
, arg
);
487 arg_nc
= ap_os_canonical_filename(cmd
->pool
, arg_nc
);
490 arg_nc
= ap_server_root_relative(cmd
->pool
, arg_nc
);
494 if (strncmp(arg_nc
, "\\\\.\\pipe\\", 9) != 0)
495 return ap_psprintf(tp
, "%s %s is invalid format",name
, arg_nc
);
499 fcgi_socket_dir
= arg_nc
;
502 fcgi_dynamic_dir
= ap_pstrcat(cmd
->pool
, fcgi_socket_dir
, "dynamic", NULL
);
504 err
= fcgi_config_make_dir(tp
, fcgi_socket_dir
);
506 return ap_psprintf(tp
, "%s %s: %s", name
, arg_nc
, err
);
508 err
= fcgi_config_make_dynamic_dir(cmd
->pool
, 0);
510 return ap_psprintf(tp
, "%s %s: %s", name
, arg_nc
, err
);
516 /*******************************************************************************
517 * Enable, disable, or specify the path to a wrapper used to invoke all
518 * FastCGI applications.
520 const char *fcgi_config_set_wrapper(cmd_parms
*cmd
, void *dummy
, const char *arg
)
523 return ap_psprintf(cmd
->temp_pool
,
524 "the %s directive is not supported on WIN", cmd
->cmd
->name
);
527 const char *err
= NULL
;
528 const char * const name
= cmd
->cmd
->name
;
529 pool
* const tp
= cmd
->temp_pool
;
530 char * wrapper
= NULL
;
532 err
= ap_check_cmd_context(cmd
, GLOBAL_ONLY
);
540 return ap_psprintf(tp
, "%s was already set to \"%s\"",
544 err
= fcgi_config_set_fcgi_uid_n_gid(1);
546 return ap_psprintf(tp
, "%s %s: %s", name
, arg
, err
);
548 if (fcgi_servers
!= NULL
) {
549 return ap_psprintf(tp
,
550 "The %s command must preceed static FastCGI server definitions", name
);
553 if (strcasecmp(arg
, "Off") == 0) {
558 if (strcasecmp(arg
, "On") == 0)
560 wrapper
= SUEXEC_BIN
;
565 if (apr_filepath_merge(&wrapper
, "", arg
, 0, cmd
->pool
))
566 return ap_psprintf(tp
, "%s %s: invalid filepath", name
, arg
);
568 wrapper
= ap_os_canonical_filename(cmd
->pool
, (char *) arg
);
571 wrapper
= ap_server_root_relative(cmd
->pool
, wrapper
);
574 err
= fcgi_util_check_access(tp
, wrapper
, NULL
, X_OK
, fcgi_user_id
, fcgi_group_id
);
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
);
582 fcgi_wrapper
= wrapper
;
588 /*******************************************************************************
589 * Configure a static FastCGI server.
591 const char *fcgi_config_new_static_server(cmd_parms
*cmd
, void *dummy
, const char *arg
)
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
;
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;
607 err
= ap_check_cmd_context(cmd
, GLOBAL_ONLY
);
613 if (*fs_path
== '\0')
614 return "AppClass requires a pathname!?";
616 if ((err
= fcgi_config_set_fcgi_uid_n_gid(1)) != NULL
)
617 return ap_psprintf(tp
, "%s %s: %s", name
, fs_path
, err
);
620 if (apr_filepath_merge(&fs_path
, "", fs_path
, 0, p
))
621 return ap_psprintf(tp
, "%s %s: invalid filepath", name
, fs_path
);
623 fs_path
= ap_os_canonical_filename(p
, fs_path
);
625 fs_path
= ap_server_root_relative(p
, fs_path
);
627 ap_getparents(fs_path
);
628 ap_no2slash(fs_path
);
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
));
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
));
642 return ap_psprintf(tp
,
643 "%s: redefinition of a previously defined FastCGI server \"%s\"",
648 err
= fcgi_util_fs_is_path_ok(tp
, fs_path
, NULL
);
650 return ap_psprintf(tp
, "%s: \"%s\" %s", name
, fs_path
, err
);
653 s
= fcgi_util_fs_new(p
);
654 s
->fs_path
= fs_path
;
655 s
->directive
= APP_CLASS_STANDARD
;
656 s
->restartOnExit
= TRUE
;
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");
665 mutex
= CreateMutex(NULL
, FALSE
, fs_path
);
669 ap_log_error(FCGI_LOG_ALERT
, fcgi_apache_main_server
,
670 "FastCGI: CreateMutex() failed");
671 return "failed to create FastCGI application accept mutex";
674 SetHandleInformation(mutex
, HANDLE_FLAG_INHERIT
, TRUE
);
676 s
->mutex_env_string
= ap_psprintf(p
, "_FCGI_MUTEX_=%ld", mutex
);
680 /* Parse directive arguments */
682 option
= ap_getword_conf(tp
, &arg
);
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
);
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
);
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
);
696 else if (strcasecmp(option
, "-min-server-life") == 0) {
697 if ((err
= get_int(tp
, &arg
, &s
->minServerLife
, 0)))
698 return invalid_value(tp
, name
, NULL
, option
, err
);
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
);
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
);
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
);
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
);
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
);
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
, "\"\"");
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
);
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
);
733 else if (strcasecmp(option
, "-flush") == 0) {
736 else if (strcasecmp(option
, "-user") == 0) {
738 return ap_psprintf(tp
,
739 "%s %s: the -user option isn't supported on WIN", name
, fs_path
);
741 s
->user
= ap_getword_conf(tp
, &arg
);
742 if (*s
->user
== '\0')
743 return invalid_value(tp
, name
, fs_path
, option
, "\"\"");
746 else if (strcasecmp(option
, "-group") == 0) {
748 return ap_psprintf(tp
,
749 "%s %s: the -group option isn't supported on WIN", name
, fs_path
);
751 s
->group
= ap_getword_conf(tp
, &arg
);
752 if (*s
->group
== '\0')
753 return invalid_value(tp
, name
, fs_path
, option
, "\"\"");
757 return ap_psprintf(tp
, "%s %s: invalid option: %s", name
, fs_path
, option
);
764 if (s
->group
== NULL
)
766 s
->group
= ap_psprintf(tp
, "#%ld", fcgi_util_get_server_gid(cmd
->server
));
771 s
->user
= ap_psprintf(p
, "#%ld", fcgi_util_get_server_uid(cmd
->server
));
774 s
->uid
= ap_uname2id(s
->user
);
775 s
->gid
= ap_gname2id(s
->group
);
777 else if (s
->user
|| s
->group
)
779 ap_log_error(FCGI_LOG_WARN
, cmd
->server
, "FastCGI: there is no "
780 "fastcgi wrapper set, user/group options are ignored");
783 if ((err
= fcgi_util_fs_set_uid_n_gid(p
, s
, s
->uid
, s
->gid
)))
785 return ap_psprintf(tp
,
786 "%s %s: invalid user or group: %s", name
, fs_path
, err
);
790 if (s
->socket_path
!= NULL
&& s
->port
!= 0) {
791 return ap_psprintf(tp
,
792 "%s %s: -port and -socket are mutually exclusive options",
796 /* Move env array to a surviving pool */
797 s
->envp
= (char **)ap_pcalloc(p
, sizeof(char *) * (envc
+ 4));
798 memcpy(s
->envp
, envp
, sizeof(char *) * envc
);
800 /* Initialize process structs */
801 s
->procs
= fcgi_util_fs_create_procs(p
, s
->numProcesses
);
803 /* Build the appropriate sockaddr structure */
805 err
= fcgi_util_socket_make_inet_addr(p
, (struct sockaddr_in
**)&s
->socket_addr
,
806 &s
->socket_addr_len
, NULL
, s
->port
);
808 return ap_psprintf(tp
, "%s %s: %s", name
, fs_path
, err
);
810 err
= fcgi_util_socket_make_inet_addr(p
, (struct sockaddr_in
**)&s
->dest_addr
,
811 &s
->socket_addr_len
, "localhost", s
->port
);
813 return ap_psprintf(tp
, "%s %s: %s", name
, fs_path
, err
);
816 if (s
->socket_path
== NULL
)
817 s
->socket_path
= fcgi_util_socket_hash_filename(tp
, fs_path
, s
->user
, s
->group
);
819 if (fcgi_socket_dir
== NULL
)
822 fcgi_socket_dir
= DEFAULT_SOCK_DIR
;
824 fcgi_socket_dir
= ap_server_root_relative(p
, DEFAULT_SOCK_DIR
);
828 s
->socket_path
= fcgi_util_socket_make_path_absolute(p
, s
->socket_path
, 0);
830 err
= fcgi_util_socket_make_domain_addr(p
, (struct sockaddr_un
**)&s
->socket_addr
,
831 &s
->socket_addr_len
, s
->socket_path
);
833 return ap_psprintf(tp
, "%s %s: %s", name
, fs_path
, err
);
837 /* Add it to the list of FastCGI servers */
843 /*******************************************************************************
844 * Configure a static FastCGI server that is started/managed elsewhere.
846 const char *fcgi_config_new_external_server(cmd_parms
*cmd
, void *dummy
, const char *arg
)
849 pool
* const p
= cmd
->pool
, *tp
= cmd
->temp_pool
;
850 const char * const name
= cmd
->cmd
->name
;
851 char *fs_path
= ap_getword_conf(p
, &arg
);
852 const char *option
, *err
;
854 err
= ap_check_cmd_context(cmd
, GLOBAL_ONLY
);
861 return ap_pstrcat(tp
, name
, " requires a path and either a -socket or -host option", NULL
);
865 if (apr_filepath_merge(&fs_path
, "", fs_path
, 0, p
))
866 return ap_psprintf(tp
, "%s %s: invalid filepath", name
, fs_path
);
868 fs_path
= ap_os_canonical_filename(p
, fs_path
);
871 fs_path
= ap_server_root_relative(p
, fs_path
);
873 ap_getparents(fs_path
);
874 ap_no2slash(fs_path
);
876 /* See if we've already got one of these bettys configured */
877 s
= fcgi_util_fs_get_by_id(fs_path
, fcgi_util_get_server_uid(cmd
->server
),
878 fcgi_util_get_server_gid(cmd
->server
));
881 return ap_psprintf(tp
,
882 "%s: redefinition of a previously defined class \"%s\" "
883 "with uid=%ld and gid=%ld",
884 name
, fs_path
, (long) fcgi_util_get_server_uid(cmd
->server
),
885 (long) fcgi_util_get_server_gid(cmd
->server
));
889 return ap_psprintf(tp
,
890 "%s: redefinition of previously defined class \"%s\"", name
, fs_path
);
894 s
= fcgi_util_fs_new(p
);
895 s
->fs_path
= fs_path
;
896 s
->directive
= APP_CLASS_EXTERNAL
;
898 /* Parse directive arguments */
899 while (*arg
!= '\0') {
900 option
= ap_getword_conf(tp
, &arg
);
902 if (strcasecmp(option
, "-host") == 0) {
903 if ((err
= get_host_n_port(p
, &arg
, &s
->host
, &s
->port
)))
904 return invalid_value(tp
, name
, fs_path
, option
, err
);
906 else if (strcasecmp(option
, "-socket") == 0) {
907 s
->socket_path
= ap_getword_conf(tp
, &arg
);
908 if (*s
->socket_path
== '\0')
909 return invalid_value(tp
, name
, fs_path
, option
, "\"\"");
911 else if (strcasecmp(option
, "-appConnTimeout") == 0) {
912 if ((err
= get_u_int(tp
, &arg
, &s
->appConnectTimeout
, 0)))
913 return invalid_value(tp
, name
, fs_path
, option
, err
);
915 else if (strcasecmp(option
, "-idle-timeout") == 0) {
916 if ((err
= get_u_int(tp
, &arg
, &s
->idle_timeout
, 1)))
917 return invalid_value(tp
, name
, fs_path
, option
, err
);
919 else if (strcasecmp(option
, "-pass-header") == 0) {
920 if ((err
= get_pass_header(p
, &arg
, &s
->pass_headers
)))
921 return invalid_value(tp
, name
, fs_path
, option
, err
);
923 else if (strcasecmp(option
, "-flush") == 0) {
926 else if (strcasecmp(option
, "-user") == 0) {
928 return ap_psprintf(tp
,
929 "%s %s: the -user option isn't supported on WIN", name
, fs_path
);
931 s
->user
= ap_getword_conf(tp
, &arg
);
932 if (*s
->user
== '\0')
933 return invalid_value(tp
, name
, fs_path
, option
, "\"\"");
936 else if (strcasecmp(option
, "-group") == 0) {
938 return ap_psprintf(tp
,
939 "%s %s: the -group option isn't supported on WIN", name
, fs_path
);
941 s
->group
= ap_getword_conf(tp
, &arg
);
942 if (*s
->group
== '\0')
943 return invalid_value(tp
, name
, fs_path
, option
, "\"\"");
947 return ap_psprintf(tp
, "%s %s: invalid option: %s", name
, fs_path
, option
);
955 if (s
->group
== NULL
)
957 s
->group
= ap_psprintf(tp
, "#%ld", fcgi_util_get_server_gid(cmd
->server
));
962 s
->user
= ap_psprintf(p
, "#%ld", fcgi_util_get_server_uid(cmd
->server
));
965 s
->uid
= ap_uname2id(s
->user
);
966 s
->gid
= ap_gname2id(s
->group
);
968 else if (s
->user
|| s
->group
)
970 ap_log_error(FCGI_LOG_WARN
, cmd
->server
, "FastCGI: there is no "
971 "fastcgi wrapper set, user/group options are ignored");
974 if ((err
= fcgi_util_fs_set_uid_n_gid(p
, s
, s
->uid
, s
->gid
)))
976 return ap_psprintf(tp
,
977 "%s %s: invalid user or group: %s", name
, fs_path
, err
);
981 /* Require one of -socket or -host, but not both */
982 if (s
->socket_path
!= NULL
&& s
->port
!= 0) {
983 return ap_psprintf(tp
,
984 "%s %s: -host and -socket are mutually exclusive options",
987 if (s
->socket_path
== NULL
&& s
->port
== 0) {
988 return ap_psprintf(tp
,
989 "%s %s: -socket or -host option missing", name
, fs_path
);
992 /* Build the appropriate sockaddr structure */
994 err
= fcgi_util_socket_make_inet_addr(p
, (struct sockaddr_in
**)&s
->socket_addr
,
995 &s
->socket_addr_len
, s
->host
, s
->port
);
997 return ap_psprintf(tp
, "%s %s: %s", name
, fs_path
, err
);
1000 if (fcgi_socket_dir
== NULL
)
1003 fcgi_socket_dir
= DEFAULT_SOCK_DIR
;
1005 fcgi_socket_dir
= ap_server_root_relative(p
, DEFAULT_SOCK_DIR
);
1009 s
->socket_path
= fcgi_util_socket_make_path_absolute(p
, s
->socket_path
, 0);
1011 err
= fcgi_util_socket_make_domain_addr(p
, (struct sockaddr_un
**)&s
->socket_addr
,
1012 &s
->socket_addr_len
, s
->socket_path
);
1014 return ap_psprintf(tp
, "%s %s: %s", name
, fs_path
, err
);
1018 /* Add it to the list of FastCGI servers */
1019 fcgi_util_fs_add(s
);
1025 *----------------------------------------------------------------------
1027 * fcgi_config_set_config --
1029 * Implements the FastCGI FCGIConfig configuration directive.
1030 * This command adds routines to control the execution of the
1031 * dynamic FastCGI processes.
1034 *----------------------------------------------------------------------
1036 const char *fcgi_config_set_config(cmd_parms
*cmd
, void *dummy
, const char *arg
)
1038 pool
* const p
= cmd
->pool
;
1039 pool
* const tp
= cmd
->temp_pool
;
1040 const char *err
, *option
;
1041 const char * const name
= cmd
->cmd
->name
;
1043 /* Allocate temp storage for an initial environment */
1044 unsigned int envc
= 0;
1045 char **envp
= (char **)ap_pcalloc(tp
, sizeof(char *) * (MAX_INIT_ENV_VARS
+ 3));
1047 err
= ap_check_cmd_context(cmd
, GLOBAL_ONLY
);
1053 /* Parse the directive arguments */
1055 option
= ap_getword_conf(tp
, &arg
);
1057 if (strcasecmp(option
, "-maxProcesses") == 0) {
1058 if ((err
= get_u_int(tp
, &arg
, &dynamicMaxProcs
, 1)))
1059 return invalid_value(tp
, name
, NULL
, option
, err
);
1061 else if (strcasecmp(option
, "-minProcesses") == 0) {
1062 if ((err
= get_int(tp
, &arg
, &dynamicMinProcs
, 0)))
1063 return invalid_value(tp
, name
, NULL
, option
, err
);
1065 else if (strcasecmp(option
, "-maxClassProcesses") == 0) {
1066 if ((err
= get_int(tp
, &arg
, &dynamicMaxClassProcs
, 1)))
1067 return invalid_value(tp
, name
, NULL
, option
, err
);
1069 else if (strcasecmp(option
, "-killInterval") == 0) {
1070 if ((err
= get_u_int(tp
, &arg
, &dynamicKillInterval
, 1)))
1071 return invalid_value(tp
, name
, NULL
, option
, err
);
1073 else if (strcasecmp(option
, "-updateInterval") == 0) {
1074 if ((err
= get_u_int(tp
, &arg
, &dynamicUpdateInterval
, 1)))
1075 return invalid_value(tp
, name
, NULL
, option
, err
);
1077 else if (strcasecmp(option
, "-gainValue") == 0) {
1078 if ((err
= get_float(tp
, &arg
, &dynamicGain
, 0.0, 1.0)))
1079 return invalid_value(tp
, name
, NULL
, option
, err
);
1081 else if ((strcasecmp(option
, "-singleThreshold") == 0)
1082 || (strcasecmp(option
, "-singleThreshhold") == 0))
1084 if ((err
= get_int(tp
, &arg
, &dynamicThreshold1
, 0)))
1085 return invalid_value(tp
, name
, NULL
, option
, err
);
1087 else if ((strcasecmp(option
, "-multiThreshold") == 0)
1088 || (strcasecmp(option
, "-multiThreshhold") == 0))
1090 if ((err
= get_int(tp
, &arg
, &dynamicThresholdN
, 0)))
1091 return invalid_value(tp
, name
, NULL
, option
, err
);
1093 else if (strcasecmp(option
, "-startDelay") == 0) {
1094 if ((err
= get_u_int(tp
, &arg
, &dynamicPleaseStartDelay
, 1)))
1095 return invalid_value(tp
, name
, NULL
, option
, err
);
1097 else if (strcasecmp(option
, "-initial-env") == 0) {
1098 if ((err
= get_env_var(p
, &arg
, envp
, &envc
)))
1099 return invalid_value(tp
, name
, NULL
, option
, err
);
1101 else if (strcasecmp(option
, "-pass-header") == 0) {
1102 if ((err
= get_pass_header(p
, &arg
, &dynamic_pass_headers
)))
1103 return invalid_value(tp
, name
, NULL
, option
, err
);
1105 else if (strcasecmp(option
, "-appConnTimeout") == 0) {
1106 if ((err
= get_u_int(tp
, &arg
, &dynamicAppConnectTimeout
, 0)))
1107 return invalid_value(tp
, name
, NULL
, option
, err
);
1109 else if (strcasecmp(option
, "-idle-timeout") == 0) {
1110 if ((err
= get_u_int(tp
, &arg
, &dynamic_idle_timeout
, 1)))
1111 return invalid_value(tp
, name
, NULL
, option
, err
);
1113 else if (strcasecmp(option
, "-listen-queue-depth") == 0) {
1114 if ((err
= get_u_int(tp
, &arg
, &dynamicListenQueueDepth
, 1)))
1115 return invalid_value(tp
, name
, NULL
, option
, err
);
1117 else if (strcasecmp(option
, "-min-server-life") == 0) {
1118 if ((err
= get_int(tp
, &arg
, &dynamicMinServerLife
, 0)))
1119 return invalid_value(tp
, name
, NULL
, option
, err
);
1121 else if (strcasecmp(option
, "-restart-delay") == 0) {
1122 if ((err
= get_u_int(tp
, &arg
, &dynamicRestartDelay
, 0)))
1123 return invalid_value(tp
, name
, NULL
, option
, err
);
1125 else if (strcasecmp(option
, "-init-start-delay") == 0) {
1126 if ((err
= get_u_int(tp
, &arg
, &dynamicInitStartDelay
, 0)))
1127 return invalid_value(tp
, name
, NULL
, option
, err
);
1129 else if (strcasecmp(option
, "-processSlack") == 0) {
1130 if ((err
= get_u_int(tp
, &arg
, &dynamicProcessSlack
, 1)))
1131 return invalid_value(tp
, name
, NULL
, option
, err
);
1133 else if (strcasecmp(option
, "-restart") == 0) {
1134 dynamicAutoRestart
= 1;
1136 else if (strcasecmp(option
, "-autoUpdate") == 0) {
1137 dynamicAutoUpdate
= 1;
1139 else if (strcasecmp(option
, "-flush") == 0) {
1140 dynamicFlush
= TRUE
;
1143 return ap_psprintf(tp
, "%s: invalid option: %s", name
, option
);
1147 if (dynamicProcessSlack
>= dynamicMaxProcs
+ 1) {
1148 /* the kill policy would work unexpectedly */
1149 return ap_psprintf(tp
,
1150 "%s: processSlack (%u) must be less than maxProcesses (%u) + 1",
1151 name
, dynamicProcessSlack
, dynamicMaxProcs
);
1154 /* Move env array to a surviving pool, leave 2 extra slots for
1155 * WIN32 _FCGI_MUTEX_ and _FCGI_SHUTDOWN_EVENT_ */
1156 dynamicEnvp
= (char **)ap_pcalloc(p
, sizeof(char *) * (envc
+ 4));
1157 memcpy(dynamicEnvp
, envp
, sizeof(char *) * envc
);
1162 void *fcgi_config_create_dir_config(pool
*p
, char *dummy
)
1164 fcgi_dir_config
*dir_config
= ap_pcalloc(p
, sizeof(fcgi_dir_config
));
1166 dir_config
->authenticator_options
= FCGI_AUTHORITATIVE
;
1167 dir_config
->authorizer_options
= FCGI_AUTHORITATIVE
;
1168 dir_config
->access_checker_options
= FCGI_AUTHORITATIVE
;
1174 const char *fcgi_config_new_auth_server(cmd_parms
* cmd
,
1175 void * dircfg
, const char *fs_path
, const char * compat
)
1177 fcgi_dir_config
* dir_config
= (fcgi_dir_config
*) dircfg
;
1178 pool
* const tp
= cmd
->temp_pool
;
1182 if (apr_filepath_merge(&auth_server
, "", fs_path
, 0, cmd
->pool
))
1183 return ap_psprintf(tp
, "%s %s: invalid filepath", cmd
->cmd
->name
, fs_path
);
1185 auth_server
= (char *) ap_os_canonical_filename(cmd
->pool
, fs_path
);
1188 auth_server
= ap_server_root_relative(cmd
->pool
, auth_server
);
1190 /* Make sure its already configured or at least a candidate for dynamic */
1191 if (fcgi_util_fs_get_by_id(auth_server
, fcgi_util_get_server_uid(cmd
->server
),
1192 fcgi_util_get_server_gid(cmd
->server
)) == NULL
)
1194 const char *err
= fcgi_util_fs_is_path_ok(tp
, auth_server
, NULL
);
1196 return ap_psprintf(tp
, "%s: \"%s\" %s", cmd
->cmd
->name
, auth_server
, err
);
1199 if (compat
&& strcasecmp(compat
, "-compat"))
1200 return ap_psprintf(cmd
->temp_pool
, "%s: unknown option: \"%s\"", cmd
->cmd
->name
, compat
);
1202 switch((int)cmd
->info
) {
1203 case FCGI_AUTH_TYPE_AUTHENTICATOR
:
1204 dir_config
->authenticator
= auth_server
;
1205 dir_config
->authenticator_options
|= (compat
) ? FCGI_COMPAT
: 0;
1207 case FCGI_AUTH_TYPE_AUTHORIZER
:
1208 dir_config
->authorizer
= auth_server
;
1209 dir_config
->authorizer_options
|= (compat
) ? FCGI_COMPAT
: 0;
1211 case FCGI_AUTH_TYPE_ACCESS_CHECKER
:
1212 dir_config
->access_checker
= auth_server
;
1213 dir_config
->access_checker_options
|= (compat
) ? FCGI_COMPAT
: 0;
1220 const char *fcgi_config_set_authoritative_slot(cmd_parms
* cmd
,
1221 void * dir_config
, int arg
)
1223 int offset
= (int)(long)cmd
->info
;
1226 *((u_char
*)dir_config
+ offset
) |= FCGI_AUTHORITATIVE
;
1228 *((u_char
*)dir_config
+ offset
) &= ~FCGI_AUTHORITATIVE
;