"Fossies" - the Fresh Open Source Software Archive 
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
See also the latest
Fossies "Diffs" side-by-side code changes report for "fcgi_config.c":
2.4.6_vs_2.4.7-0910052141.
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 */
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 */
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
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 */
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 */
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
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 */
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
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 */
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 */
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
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 */
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
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 */
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 */
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 */
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 */
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 */
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
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
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((int)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
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 }