|
@@ -2433,6 +2433,7 @@ enum {
|
|
CGI_ENVIRONMENT,
|
|
CGI_ENVIRONMENT,
|
|
PUT_DELETE_PASSWORDS_FILE,
|
|
PUT_DELETE_PASSWORDS_FILE,
|
|
CGI_INTERPRETER,
|
|
CGI_INTERPRETER,
|
|
|
|
+ CGI_INTERPRETER_ARGS,
|
|
PROTECT_URI,
|
|
PROTECT_URI,
|
|
AUTHENTICATION_DOMAIN,
|
|
AUTHENTICATION_DOMAIN,
|
|
ENABLE_AUTH_DOMAIN_CHECK,
|
|
ENABLE_AUTH_DOMAIN_CHECK,
|
|
@@ -2540,6 +2541,7 @@ static const struct mg_option config_options[] = {
|
|
{"cgi_environment", MG_CONFIG_TYPE_STRING_LIST, NULL},
|
|
{"cgi_environment", MG_CONFIG_TYPE_STRING_LIST, NULL},
|
|
{"put_delete_auth_file", MG_CONFIG_TYPE_FILE, NULL},
|
|
{"put_delete_auth_file", MG_CONFIG_TYPE_FILE, NULL},
|
|
{"cgi_interpreter", MG_CONFIG_TYPE_FILE, NULL},
|
|
{"cgi_interpreter", MG_CONFIG_TYPE_FILE, NULL},
|
|
|
|
+ {"cgi_interpreter_args", MG_CONFIG_TYPE_STRING, NULL},
|
|
{"protect_uri", MG_CONFIG_TYPE_STRING_LIST, NULL},
|
|
{"protect_uri", MG_CONFIG_TYPE_STRING_LIST, NULL},
|
|
{"authentication_domain", MG_CONFIG_TYPE_STRING, "mydomain.com"},
|
|
{"authentication_domain", MG_CONFIG_TYPE_STRING, "mydomain.com"},
|
|
{"enable_auth_domain_check", MG_CONFIG_TYPE_BOOLEAN, "yes"},
|
|
{"enable_auth_domain_check", MG_CONFIG_TYPE_BOOLEAN, "yes"},
|
|
@@ -5789,8 +5791,10 @@ spawn_process(struct mg_connection *conn,
|
|
const char *dir)
|
|
const char *dir)
|
|
{
|
|
{
|
|
HANDLE me;
|
|
HANDLE me;
|
|
- char *p, *interp, full_interp[PATH_MAX], full_dir[PATH_MAX],
|
|
|
|
- cmdline[PATH_MAX], buf[PATH_MAX];
|
|
|
|
|
|
+ char *p, *interp;
|
|
|
|
+ char *interp_arg = 0;
|
|
|
|
+ char full_interp[PATH_MAX], full_dir[PATH_MAX], cmdline[PATH_MAX],
|
|
|
|
+ buf[PATH_MAX];
|
|
int truncated;
|
|
int truncated;
|
|
struct mg_file file = STRUCT_FILE_INITIALIZER;
|
|
struct mg_file file = STRUCT_FILE_INITIALIZER;
|
|
STARTUPINFOA si;
|
|
STARTUPINFOA si;
|
|
@@ -5840,12 +5844,19 @@ spawn_process(struct mg_connection *conn,
|
|
HANDLE_FLAG_INHERIT,
|
|
HANDLE_FLAG_INHERIT,
|
|
0);
|
|
0);
|
|
|
|
|
|
- /* If CGI file is a script, try to read the interpreter line */
|
|
|
|
|
|
+ /* First check, if there is a CGI interpreter configured for all CGI
|
|
|
|
+ * scripts. */
|
|
interp = conn->dom_ctx->config[CGI_INTERPRETER];
|
|
interp = conn->dom_ctx->config[CGI_INTERPRETER];
|
|
- if (interp == NULL) {
|
|
|
|
|
|
+ if (interp != NULL) {
|
|
|
|
+ /* If there is a configured interpreter, check for additional arguments
|
|
|
|
+ */
|
|
|
|
+ interp_arg = conn->domm_ctx->config[CGI_INTERPRETER_ARGS];
|
|
|
|
+ } else {
|
|
|
|
+ /* Otherwise, the interpreter must be stated in the first line of the
|
|
|
|
+ * CGI script file, after a #! (shebang) mark. */
|
|
buf[0] = buf[1] = '\0';
|
|
buf[0] = buf[1] = '\0';
|
|
|
|
|
|
- /* Read the first line of the script into the buffer */
|
|
|
|
|
|
+ /* Get the full script path */
|
|
mg_snprintf(
|
|
mg_snprintf(
|
|
conn, &truncated, cmdline, sizeof(cmdline), "%s/%s", dir, prog);
|
|
conn, &truncated, cmdline, sizeof(cmdline), "%s/%s", dir, prog);
|
|
|
|
|
|
@@ -5854,12 +5865,14 @@ spawn_process(struct mg_connection *conn,
|
|
goto spawn_cleanup;
|
|
goto spawn_cleanup;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /* Open the script file, to read the first line */
|
|
if (mg_fopen(conn, cmdline, MG_FOPEN_MODE_READ, &file)) {
|
|
if (mg_fopen(conn, cmdline, MG_FOPEN_MODE_READ, &file)) {
|
|
#if defined(MG_USE_OPEN_FILE)
|
|
#if defined(MG_USE_OPEN_FILE)
|
|
p = (char *)file.access.membuf;
|
|
p = (char *)file.access.membuf;
|
|
#else
|
|
#else
|
|
p = (char *)NULL;
|
|
p = (char *)NULL;
|
|
#endif
|
|
#endif
|
|
|
|
+ /* Read the first line of the script into the buffer */
|
|
mg_fgets(buf, sizeof(buf), &file, &p);
|
|
mg_fgets(buf, sizeof(buf), &file, &p);
|
|
(void)mg_fclose(&file.access); /* ignore error on read only file */
|
|
(void)mg_fclose(&file.access); /* ignore error on read only file */
|
|
buf[sizeof(buf) - 1] = '\0';
|
|
buf[sizeof(buf) - 1] = '\0';
|
|
@@ -5880,15 +5893,29 @@ spawn_process(struct mg_connection *conn,
|
|
GetFullPathNameA(dir, sizeof(full_dir), full_dir, NULL);
|
|
GetFullPathNameA(dir, sizeof(full_dir), full_dir, NULL);
|
|
|
|
|
|
if (interp[0] != '\0') {
|
|
if (interp[0] != '\0') {
|
|
- mg_snprintf(conn,
|
|
|
|
- &truncated,
|
|
|
|
- cmdline,
|
|
|
|
- sizeof(cmdline),
|
|
|
|
- "\"%s\" \"%s\\%s\"",
|
|
|
|
- interp,
|
|
|
|
- full_dir,
|
|
|
|
- prog);
|
|
|
|
|
|
+ /* This is an interpreted script file. We must call the interpreter. */
|
|
|
|
+ if ((interp_arg != 0) && (interp_arg[0] != 0)) {
|
|
|
|
+ mg_snprintf(conn,
|
|
|
|
+ &truncated,
|
|
|
|
+ cmdline,
|
|
|
|
+ sizeof(cmdline),
|
|
|
|
+ "\"%s\" %s \"%s\\%s\"",
|
|
|
|
+ interp,
|
|
|
|
+ interp_arg,
|
|
|
|
+ full_dir,
|
|
|
|
+ prog);
|
|
|
|
+ } else {
|
|
|
|
+ mg_snprintf(conn,
|
|
|
|
+ &truncated,
|
|
|
|
+ cmdline,
|
|
|
|
+ sizeof(cmdline),
|
|
|
|
+ "\"%s\" \"%s\\%s\"",
|
|
|
|
+ interp,
|
|
|
|
+ full_dir,
|
|
|
|
+ prog);
|
|
|
|
+ }
|
|
} else {
|
|
} else {
|
|
|
|
+ /* This is (probably) a compiled program. We call it directly. */
|
|
mg_snprintf(conn,
|
|
mg_snprintf(conn,
|
|
&truncated,
|
|
&truncated,
|
|
cmdline,
|
|
cmdline,
|
|
@@ -6152,6 +6179,7 @@ spawn_process(struct mg_connection *conn,
|
|
|
|
|
|
interp = conn->dom_ctx->config[CGI_INTERPRETER];
|
|
interp = conn->dom_ctx->config[CGI_INTERPRETER];
|
|
if (interp == NULL) {
|
|
if (interp == NULL) {
|
|
|
|
+ /* no interpreter configured, call the programm directly */
|
|
(void)execle(prog, prog, NULL, envp);
|
|
(void)execle(prog, prog, NULL, envp);
|
|
mg_cry_internal(conn,
|
|
mg_cry_internal(conn,
|
|
"%s: execle(%s): %s",
|
|
"%s: execle(%s): %s",
|
|
@@ -6159,7 +6187,15 @@ spawn_process(struct mg_connection *conn,
|
|
prog,
|
|
prog,
|
|
strerror(ERRNO));
|
|
strerror(ERRNO));
|
|
} else {
|
|
} else {
|
|
- (void)execle(interp, interp, prog, NULL, envp);
|
|
|
|
|
|
+ /* call the configured interpreter */
|
|
|
|
+ const char *interp_args =
|
|
|
|
+ conn->dom_ctx->config[CGI_INTERPRETER_ARGS];
|
|
|
|
+
|
|
|
|
+ if ((interp_args != NULL) && (interp_args[0] != 0)) {
|
|
|
|
+ (void)execle(interp, interp, interp_args, prog, NULL, envp);
|
|
|
|
+ } else {
|
|
|
|
+ (void)execle(interp, interp, prog, NULL, envp);
|
|
|
|
+ }
|
|
mg_cry_internal(conn,
|
|
mg_cry_internal(conn,
|
|
"%s: execle(%s %s): %s",
|
|
"%s: execle(%s %s): %s",
|
|
__func__,
|
|
__func__,
|