~ubuntu-branches/ubuntu/feisty/apache2/feisty

« back to all changes in this revision

Viewing changes to modules/generators/mod_cgid.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Barth
  • Date: 2006-12-09 21:05:45 UTC
  • mfrom: (0.6.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20061209210545-h70s0xaqc2v8vqr2
Tags: 2.2.3-3.2
* Non-maintainer upload.
* 043_ajp_connection_reuse: Patch from upstream Bugzilla, fixing a critical
  issue with regard to connection reuse in mod_proxy_ajp.
  Closes: #396265

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Licensed to the Apache Software Foundation (ASF) under one or more
 
2
 * contributor license agreements.  See the NOTICE file distributed with
 
3
 * this work for additional information regarding copyright ownership.
 
4
 * The ASF licenses this file to You under the Apache License, Version 2.0
 
5
 * (the "License"); you may not use this file except in compliance with
 
6
 * the License.  You may obtain a copy of the License at
 
7
 *
 
8
 *     http://www.apache.org/licenses/LICENSE-2.0
 
9
 *
 
10
 * Unless required by applicable law or agreed to in writing, software
 
11
 * distributed under the License is distributed on an "AS IS" BASIS,
 
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
13
 * See the License for the specific language governing permissions and
 
14
 * limitations under the License.
 
15
 */
 
16
 
 
17
/*
 
18
 * http_script: keeps all script-related ramblings together.
 
19
 *
 
20
 * Compliant to cgi/1.1 spec
 
21
 *
 
22
 * Adapted by rst from original NCSA code by Rob McCool
 
23
 *
 
24
 * Apache adds some new env vars; REDIRECT_URL and REDIRECT_QUERY_STRING for
 
25
 * custom error responses, and DOCUMENT_ROOT because we found it useful.
 
26
 * It also adds SERVER_ADMIN - useful for scripts to know who to mail when
 
27
 * they fail.
 
28
 */
 
29
 
 
30
#include "apr_lib.h"
 
31
#include "apr_strings.h"
 
32
#include "apr_general.h"
 
33
#include "apr_file_io.h"
 
34
#include "apr_portable.h"
 
35
#include "apr_buckets.h"
 
36
#include "apr_optional.h"
 
37
#include "apr_signal.h"
 
38
 
 
39
#define APR_WANT_STRFUNC
 
40
#include "apr_want.h"
 
41
 
 
42
#if APR_HAVE_SYS_SOCKET_H
 
43
#include <sys/socket.h>
 
44
#endif
 
45
#if APR_HAVE_UNISTD_H
 
46
#include <unistd.h>
 
47
#endif
 
48
#if APR_HAVE_SYS_TYPES_H
 
49
#include <sys/types.h>
 
50
#endif
 
51
 
 
52
#define CORE_PRIVATE
 
53
 
 
54
#include "util_filter.h"
 
55
#include "httpd.h"
 
56
#include "http_config.h"
 
57
#include "http_request.h"
 
58
#include "http_core.h"
 
59
#include "http_protocol.h"
 
60
#include "http_main.h"
 
61
#include "http_log.h"
 
62
#include "util_script.h"
 
63
#include "ap_mpm.h"
 
64
#include "unixd.h"
 
65
#include "mod_suexec.h"
 
66
#include "../filters/mod_include.h"
 
67
 
 
68
#include "mod_core.h"
 
69
 
 
70
 
 
71
/* ### should be tossed in favor of APR */
 
72
#include <sys/stat.h>
 
73
#include <sys/un.h> /* for sockaddr_un */
 
74
 
 
75
 
 
76
module AP_MODULE_DECLARE_DATA cgid_module;
 
77
 
 
78
static int cgid_start(apr_pool_t *p, server_rec *main_server, apr_proc_t *procnew);
 
79
static int cgid_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *main_server);
 
80
static int handle_exec(include_ctx_t *ctx, ap_filter_t *f, apr_bucket_brigade *bb);
 
81
 
 
82
static APR_OPTIONAL_FN_TYPE(ap_register_include_handler) *cgid_pfn_reg_with_ssi;
 
83
static APR_OPTIONAL_FN_TYPE(ap_ssi_get_tag_and_value) *cgid_pfn_gtv;
 
84
static APR_OPTIONAL_FN_TYPE(ap_ssi_parse_string) *cgid_pfn_ps;
 
85
 
 
86
static apr_pool_t *pcgi = NULL;
 
87
static int total_modules = 0;
 
88
static pid_t daemon_pid;
 
89
static int daemon_should_exit = 0;
 
90
static server_rec *root_server = NULL;
 
91
static apr_pool_t *root_pool = NULL;
 
92
static const char *sockname;
 
93
static pid_t parent_pid;
 
94
static ap_unix_identity_t empty_ugid = { (uid_t)-1, (gid_t)-1, -1 };
 
95
 
 
96
/* Read and discard the data in the brigade produced by a CGI script */
 
97
static void discard_script_output(apr_bucket_brigade *bb);
 
98
 
 
99
/* This doer will only ever be called when we are sure that we have
 
100
 * a valid ugid.
 
101
 */
 
102
static ap_unix_identity_t *cgid_suexec_id_doer(const request_rec *r)
 
103
{
 
104
    return (ap_unix_identity_t *)
 
105
                        ap_get_module_config(r->request_config, &cgid_module);
 
106
}
 
107
 
 
108
/* KLUDGE --- for back-combatibility, we don't have to check ExecCGI
 
109
 * in ScriptAliased directories, which means we need to know if this
 
110
 * request came through ScriptAlias or not... so the Alias module
 
111
 * leaves a note for us.
 
112
 */
 
113
 
 
114
static int is_scriptaliased(request_rec *r)
 
115
{
 
116
    const char *t = apr_table_get(r->notes, "alias-forced-type");
 
117
    return t && (!strcasecmp(t, "cgi-script"));
 
118
}
 
119
 
 
120
/* Configuration stuff */
 
121
 
 
122
#define DEFAULT_LOGBYTES 10385760
 
123
#define DEFAULT_BUFBYTES 1024
 
124
#define DEFAULT_SOCKET  DEFAULT_REL_RUNTIMEDIR "/cgisock"
 
125
 
 
126
#define CGI_REQ    1
 
127
#define SSI_REQ    2
 
128
#define GETPID_REQ 3 /* get the pid of script created for prior request */
 
129
 
 
130
#define ERRFN_USERDATA_KEY         "CGIDCHILDERRFN"
 
131
 
 
132
/* DEFAULT_CGID_LISTENBACKLOG controls the max depth on the unix socket's
 
133
 * pending connection queue.  If a bunch of cgi requests arrive at about
 
134
 * the same time, connections from httpd threads/processes will back up
 
135
 * in the queue while the cgid process slowly forks off a child to process
 
136
 * each connection on the unix socket.  If the queue is too short, the
 
137
 * httpd process will get ECONNREFUSED when trying to connect.
 
138
 */
 
139
#ifndef DEFAULT_CGID_LISTENBACKLOG
 
140
#define DEFAULT_CGID_LISTENBACKLOG 100
 
141
#endif
 
142
 
 
143
/* DEFAULT_CONNECT_ATTEMPTS controls how many times we'll try to connect
 
144
 * to the cgi daemon from the thread/process handling the cgi request.
 
145
 * Generally we want to retry when we get ECONNREFUSED since it is
 
146
 * probably because the listen queue is full.  We need to try harder so
 
147
 * the client doesn't see it as a 503 error.
 
148
 *
 
149
 * Set this to 0 to continually retry until the connect works or Apache
 
150
 * terminates.
 
151
 */
 
152
#ifndef DEFAULT_CONNECT_ATTEMPTS
 
153
#define DEFAULT_CONNECT_ATTEMPTS  15
 
154
#endif
 
155
 
 
156
typedef struct {
 
157
    const char *logname;
 
158
    long logbytes;
 
159
    int bufbytes;
 
160
} cgid_server_conf;
 
161
 
 
162
typedef struct {
 
163
    int req_type; /* request type (CGI_REQ, SSI_REQ, etc.) */
 
164
    unsigned long conn_id; /* connection id; daemon uses this as a hash value
 
165
                            * to find the script pid when it is time for that
 
166
                            * process to be cleaned up
 
167
                            */
 
168
    pid_t ppid;            /* sanity check for config problems leading to
 
169
                            * wrong cgid socket use
 
170
                            */
 
171
    int core_module_index;
 
172
    int env_count;
 
173
    ap_unix_identity_t ugid;
 
174
    apr_size_t filename_len;
 
175
    apr_size_t argv0_len;
 
176
    apr_size_t uri_len;
 
177
    apr_size_t args_len;
 
178
    int loglevel; /* to stuff in server_rec */
 
179
} cgid_req_t;
 
180
 
 
181
/* This routine is called to create the argument list to be passed
 
182
 * to the CGI script.  When suexec is enabled, the suexec path, user, and
 
183
 * group are the first three arguments to be passed; if not, all three
 
184
 * must be NULL.  The query info is split into separate arguments, where
 
185
 * "+" is the separator between keyword arguments.
 
186
 *
 
187
 * Do not process the args if they containing an '=' assignment.
 
188
 */
 
189
static char **create_argv(apr_pool_t *p, char *path, char *user, char *group,
 
190
                          char *av0, const char *args)
 
191
{
 
192
    int x, numwords;
 
193
    char **av;
 
194
    char *w;
 
195
    int idx = 0;
 
196
 
 
197
    if (ap_strchr_c(args, '=')) {
 
198
        numwords = 0;
 
199
    }
 
200
    else {
 
201
        /* count the number of keywords */
 
202
 
 
203
        for (x = 0, numwords = 1; args[x]; x++) {
 
204
            if (args[x] == '+') {
 
205
                ++numwords;
 
206
            }
 
207
        }
 
208
    }
 
209
 
 
210
    if (numwords > APACHE_ARG_MAX - 5) {
 
211
        numwords = APACHE_ARG_MAX - 5;  /* Truncate args to prevent overrun */
 
212
    }
 
213
    av = (char **) apr_pcalloc(p, (numwords + 5) * sizeof(char *));
 
214
 
 
215
    if (path) {
 
216
        av[idx++] = path;
 
217
    }
 
218
    if (user) {
 
219
        av[idx++] = user;
 
220
    }
 
221
    if (group) {
 
222
        av[idx++] = group;
 
223
    }
 
224
 
 
225
    av[idx++] = apr_pstrdup(p, av0);
 
226
 
 
227
    for (x = 1; x <= numwords; x++) {
 
228
        w = ap_getword_nulls(p, &args, '+');
 
229
        if (strcmp(w, "")) {
 
230
            ap_unescape_url(w);
 
231
            av[idx++] = ap_escape_shell_cmd(p, w);
 
232
        }
 
233
    }
 
234
    av[idx] = NULL;
 
235
    return av;
 
236
}
 
237
 
 
238
#if APR_HAS_OTHER_CHILD
 
239
static void cgid_maint(int reason, void *data, apr_wait_t status)
 
240
{
 
241
    apr_proc_t *proc = data;
 
242
    int mpm_state;
 
243
    int stopping;
 
244
 
 
245
    switch (reason) {
 
246
        case APR_OC_REASON_DEATH:
 
247
            apr_proc_other_child_unregister(data);
 
248
            /* If apache is not terminating or restarting,
 
249
             * restart the cgid daemon
 
250
             */
 
251
            stopping = 1; /* if MPM doesn't support query,
 
252
                           * assume we shouldn't restart daemon
 
253
                           */
 
254
            if (ap_mpm_query(AP_MPMQ_MPM_STATE, &mpm_state) == APR_SUCCESS &&
 
255
                mpm_state != AP_MPMQ_STOPPING) {
 
256
                stopping = 0;
 
257
            }
 
258
            if (!stopping) {
 
259
                ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
 
260
                             "cgid daemon process died, restarting");
 
261
                cgid_start(root_pool, root_server, proc);
 
262
            }
 
263
            break;
 
264
        case APR_OC_REASON_RESTART:
 
265
            /* don't do anything; server is stopping or restarting */
 
266
            apr_proc_other_child_unregister(data);
 
267
            break;
 
268
        case APR_OC_REASON_LOST:
 
269
            /* Restart the child cgid daemon process */
 
270
            apr_proc_other_child_unregister(data);
 
271
            cgid_start(root_pool, root_server, proc);
 
272
            break;
 
273
        case APR_OC_REASON_UNREGISTER:
 
274
            /* we get here when pcgi is cleaned up; pcgi gets cleaned
 
275
             * up when pconf gets cleaned up
 
276
             */
 
277
            kill(proc->pid, SIGHUP); /* send signal to daemon telling it to die */
 
278
 
 
279
            /* Remove the cgi socket, we must do it here in order to try and
 
280
             * guarantee the same permissions as when the socket was created.
 
281
             */
 
282
            if (unlink(sockname) < 0 && errno != ENOENT) {
 
283
                ap_log_error(APLOG_MARK, APLOG_ERR, errno, NULL,
 
284
                             "Couldn't unlink unix domain socket %s",
 
285
                             sockname);
 
286
            }
 
287
            break;
 
288
    }
 
289
}
 
290
#endif
 
291
 
 
292
/* deal with incomplete reads and signals
 
293
 * assume you really have to read buf_size bytes
 
294
 */
 
295
static apr_status_t sock_read(int fd, void *vbuf, size_t buf_size)
 
296
{
 
297
    char *buf = vbuf;
 
298
    int rc;
 
299
    size_t bytes_read = 0;
 
300
 
 
301
    do {
 
302
        do {
 
303
            rc = read(fd, buf + bytes_read, buf_size - bytes_read);
 
304
        } while (rc < 0 && errno == EINTR);
 
305
        switch(rc) {
 
306
        case -1:
 
307
            return errno;
 
308
        case 0: /* unexpected */
 
309
            return ECONNRESET;
 
310
        default:
 
311
            bytes_read += rc;
 
312
        }
 
313
    } while (bytes_read < buf_size);
 
314
 
 
315
    return APR_SUCCESS;
 
316
}
 
317
 
 
318
/* deal with signals
 
319
 */
 
320
static apr_status_t sock_write(int fd, const void *buf, size_t buf_size)
 
321
{
 
322
    int rc;
 
323
 
 
324
    do {
 
325
        rc = write(fd, buf, buf_size);
 
326
    } while (rc < 0 && errno == EINTR);
 
327
    if (rc < 0) {
 
328
        return errno;
 
329
    }
 
330
 
 
331
    return APR_SUCCESS;
 
332
}
 
333
 
 
334
static apr_status_t get_req(int fd, request_rec *r, char **argv0, char ***env,
 
335
                            cgid_req_t *req)
 
336
{
 
337
    int i;
 
338
    char **environ;
 
339
    core_request_config *temp_core;
 
340
    void **rconf;
 
341
    apr_status_t stat;
 
342
 
 
343
    r->server = apr_pcalloc(r->pool, sizeof(server_rec));
 
344
 
 
345
    /* read the request header */
 
346
    stat = sock_read(fd, req, sizeof(*req));
 
347
    if (stat != APR_SUCCESS) {
 
348
        return stat;
 
349
    }
 
350
    r->server->loglevel = req->loglevel;
 
351
    if (req->req_type == GETPID_REQ) {
 
352
        /* no more data sent for this request */
 
353
        return APR_SUCCESS;
 
354
    }
 
355
 
 
356
    /* handle module indexes and such */
 
357
    rconf = (void **) apr_pcalloc(r->pool, sizeof(void *) * (total_modules + DYNAMIC_MODULE_LIMIT));
 
358
 
 
359
    temp_core = (core_request_config *)apr_palloc(r->pool, sizeof(core_module));
 
360
    rconf[req->core_module_index] = (void *)temp_core;
 
361
    r->request_config = (ap_conf_vector_t *)rconf;
 
362
    ap_set_module_config(r->request_config, &cgid_module, (void *)&req->ugid);
 
363
 
 
364
    /* Read the filename, argv0, uri, and args */
 
365
    r->filename = apr_pcalloc(r->pool, req->filename_len + 1);
 
366
    *argv0 = apr_pcalloc(r->pool, req->argv0_len + 1);
 
367
    r->uri = apr_pcalloc(r->pool, req->uri_len + 1);
 
368
    if ((stat = sock_read(fd, r->filename, req->filename_len)) != APR_SUCCESS ||
 
369
        (stat = sock_read(fd, *argv0, req->argv0_len)) != APR_SUCCESS ||
 
370
        (stat = sock_read(fd, r->uri, req->uri_len)) != APR_SUCCESS) {
 
371
        return stat;
 
372
    }
 
373
 
 
374
    r->args = apr_pcalloc(r->pool, req->args_len + 1); /* empty string if no args */
 
375
    if (req->args_len) {
 
376
        if ((stat = sock_read(fd, r->args, req->args_len)) != APR_SUCCESS) {
 
377
            return stat;
 
378
        }
 
379
    }
 
380
 
 
381
    /* read the environment variables */
 
382
    environ = apr_pcalloc(r->pool, (req->env_count + 2) *sizeof(char *));
 
383
    for (i = 0; i < req->env_count; i++) {
 
384
        apr_size_t curlen;
 
385
 
 
386
        if ((stat = sock_read(fd, &curlen, sizeof(curlen))) != APR_SUCCESS) {
 
387
            return stat;
 
388
        }
 
389
        environ[i] = apr_pcalloc(r->pool, curlen + 1);
 
390
        if ((stat = sock_read(fd, environ[i], curlen)) != APR_SUCCESS) {
 
391
            return stat;
 
392
        }
 
393
    }
 
394
    *env = environ;
 
395
 
 
396
#if 0
 
397
#ifdef RLIMIT_CPU
 
398
    sock_read(fd, &j, sizeof(int));
 
399
    if (j) {
 
400
        temp_core->limit_cpu = (struct rlimit *)apr_palloc (sizeof(struct rlimit));
 
401
        sock_read(fd, temp_core->limit_cpu, sizeof(struct rlimit));
 
402
    }
 
403
    else {
 
404
        temp_core->limit_cpu = NULL;
 
405
    }
 
406
#endif
 
407
 
 
408
#if defined (RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS)
 
409
    sock_read(fd, &j, sizeof(int));
 
410
    if (j) {
 
411
        temp_core->limit_mem = (struct rlimit *)apr_palloc(r->pool, sizeof(struct rlimit));
 
412
        sock_read(fd, temp_core->limit_mem, sizeof(struct rlimit));
 
413
    }
 
414
    else {
 
415
        temp_core->limit_mem = NULL;
 
416
    }
 
417
#endif
 
418
 
 
419
#ifdef RLIMIT_NPROC
 
420
    sock_read(fd, &j, sizeof(int));
 
421
    if (j) {
 
422
        temp_core->limit_nproc = (struct rlimit *)apr_palloc(r->pool, sizeof(struct rlimit));
 
423
        sock_read(fd, temp_core->limit_nproc, sizeof(struct rlimit));
 
424
    }
 
425
    else {
 
426
        temp_core->limit_nproc = NULL;
 
427
    }
 
428
#endif
 
429
#endif
 
430
 
 
431
    return APR_SUCCESS;
 
432
}
 
433
 
 
434
static apr_status_t send_req(int fd, request_rec *r, char *argv0, char **env,
 
435
                             int req_type)
 
436
{
 
437
    int i;
 
438
    cgid_req_t req = {0};
 
439
    apr_status_t stat;
 
440
    ap_unix_identity_t * ugid = ap_run_get_suexec_identity(r);
 
441
 
 
442
    if (ugid == NULL) {
 
443
        req.ugid = empty_ugid;
 
444
    } else {
 
445
        memcpy(&req.ugid, ugid, sizeof(ap_unix_identity_t));
 
446
    }
 
447
 
 
448
    req.req_type = req_type;
 
449
    req.ppid = parent_pid;
 
450
    req.conn_id = r->connection->id;
 
451
    req.core_module_index = core_module.module_index;
 
452
    for (req.env_count = 0; env[req.env_count]; req.env_count++) {
 
453
        continue;
 
454
    }
 
455
    req.filename_len = strlen(r->filename);
 
456
    req.argv0_len = strlen(argv0);
 
457
    req.uri_len = strlen(r->uri);
 
458
    req.args_len = r->args ? strlen(r->args) : 0;
 
459
    req.loglevel = r->server->loglevel;
 
460
 
 
461
    /* Write the request header */
 
462
    if ((stat = sock_write(fd, &req, sizeof(req))) != APR_SUCCESS) {
 
463
        return stat;
 
464
    }
 
465
 
 
466
    /* Write filename, argv0, uri, and args */
 
467
    if ((stat = sock_write(fd, r->filename, req.filename_len)) != APR_SUCCESS ||
 
468
        (stat = sock_write(fd, argv0, req.argv0_len)) != APR_SUCCESS ||
 
469
        (stat = sock_write(fd, r->uri, req.uri_len)) != APR_SUCCESS) {
 
470
        return stat;
 
471
    }
 
472
    if (req.args_len) {
 
473
        if ((stat = sock_write(fd, r->args, req.args_len)) != APR_SUCCESS) {
 
474
            return stat;
 
475
        }
 
476
    }
 
477
 
 
478
    /* write the environment variables */
 
479
    for (i = 0; i < req.env_count; i++) {
 
480
        apr_size_t curlen = strlen(env[i]);
 
481
 
 
482
        if ((stat = sock_write(fd, &curlen, sizeof(curlen))) != APR_SUCCESS) {
 
483
            return stat;
 
484
        }
 
485
 
 
486
        if ((stat = sock_write(fd, env[i], curlen)) != APR_SUCCESS) {
 
487
            return stat;
 
488
        }
 
489
    }
 
490
 
 
491
#if 0
 
492
#ifdef RLIMIT_CPU
 
493
    if (conf->limit_cpu) {
 
494
        len = 1;
 
495
        stat = sock_write(fd, &len, sizeof(int));
 
496
        stat = sock_write(fd, conf->limit_cpu, sizeof(struct rlimit));
 
497
    }
 
498
    else {
 
499
        len = 0;
 
500
        stat = sock_write(fd, &len, sizeof(int));
 
501
    }
 
502
#endif
 
503
 
 
504
#if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS)
 
505
    if (conf->limit_mem) {
 
506
        len = 1;
 
507
        stat = sock_write(fd, &len, sizeof(int));
 
508
        stat = sock_write(fd, conf->limit_mem, sizeof(struct rlimit));
 
509
    }
 
510
    else {
 
511
        len = 0;
 
512
        stat = sock_write(fd, &len, sizeof(int));
 
513
    }
 
514
#endif
 
515
 
 
516
#ifdef RLIMIT_NPROC
 
517
    if (conf->limit_nproc) {
 
518
        len = 1;
 
519
        stat = sock_write(fd, &len, sizeof(int));
 
520
        stat = sock_write(fd, conf->limit_nproc, sizeof(struct rlimit));
 
521
    }
 
522
    else {
 
523
        len = 0;
 
524
        stat = sock_write(fd, &len, sizeof(int));
 
525
    }
 
526
#endif
 
527
#endif
 
528
    return APR_SUCCESS;
 
529
}
 
530
 
 
531
static void daemon_signal_handler(int sig)
 
532
{
 
533
    if (sig == SIGHUP) {
 
534
        ++daemon_should_exit;
 
535
    }
 
536
}
 
537
 
 
538
static void cgid_child_errfn(apr_pool_t *pool, apr_status_t err,
 
539
                             const char *description)
 
540
{
 
541
    request_rec *r;
 
542
    void *vr;
 
543
 
 
544
    apr_pool_userdata_get(&vr, ERRFN_USERDATA_KEY, pool);
 
545
    r = vr;
 
546
 
 
547
    /* sure we got r, but don't call ap_log_rerror() because we don't
 
548
     * have r->headers_in and possibly other storage referenced by
 
549
     * ap_log_rerror()
 
550
     */
 
551
    ap_log_error(APLOG_MARK, APLOG_ERR, err, r->server, "%s", description);
 
552
}
 
553
 
 
554
static int cgid_server(void *data)
 
555
{
 
556
    struct sockaddr_un unix_addr;
 
557
    int sd, sd2, rc;
 
558
    mode_t omask;
 
559
    apr_socklen_t len;
 
560
    apr_pool_t *ptrans;
 
561
    server_rec *main_server = data;
 
562
    apr_hash_t *script_hash = apr_hash_make(pcgi);
 
563
 
 
564
    apr_pool_create(&ptrans, pcgi);
 
565
 
 
566
    apr_signal(SIGCHLD, SIG_IGN);
 
567
    apr_signal(SIGHUP, daemon_signal_handler);
 
568
 
 
569
    /* Close our copy of the listening sockets */
 
570
    ap_close_listeners();
 
571
 
 
572
    /* cgid should use its own suexec doer */
 
573
    ap_hook_get_suexec_identity(cgid_suexec_id_doer, NULL, NULL,
 
574
                                APR_HOOK_REALLY_FIRST);
 
575
    apr_hook_sort_all();
 
576
 
 
577
    if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
 
578
        ap_log_error(APLOG_MARK, APLOG_ERR, errno, main_server,
 
579
                     "Couldn't create unix domain socket");
 
580
        return errno;
 
581
    }
 
582
 
 
583
    memset(&unix_addr, 0, sizeof(unix_addr));
 
584
    unix_addr.sun_family = AF_UNIX;
 
585
    apr_cpystrn(unix_addr.sun_path, sockname, sizeof unix_addr.sun_path);
 
586
 
 
587
    omask = umask(0077); /* so that only Apache can use socket */
 
588
    rc = bind(sd, (struct sockaddr *)&unix_addr, sizeof(unix_addr));
 
589
    umask(omask); /* can't fail, so can't clobber errno */
 
590
    if (rc < 0) {
 
591
        ap_log_error(APLOG_MARK, APLOG_ERR, errno, main_server,
 
592
                     "Couldn't bind unix domain socket %s",
 
593
                     sockname);
 
594
        return errno;
 
595
    }
 
596
 
 
597
    if (listen(sd, DEFAULT_CGID_LISTENBACKLOG) < 0) {
 
598
        ap_log_error(APLOG_MARK, APLOG_ERR, errno, main_server,
 
599
                     "Couldn't listen on unix domain socket");
 
600
        return errno;
 
601
    }
 
602
 
 
603
    if (!geteuid()) {
 
604
        if (chown(sockname, unixd_config.user_id, -1) < 0) {
 
605
            ap_log_error(APLOG_MARK, APLOG_ERR, errno, main_server,
 
606
                         "Couldn't change owner of unix domain socket %s",
 
607
                         sockname);
 
608
            return errno;
 
609
        }
 
610
    }
 
611
 
 
612
    unixd_setup_child(); /* if running as root, switch to configured user/group */
 
613
 
 
614
    while (!daemon_should_exit) {
 
615
        int errfileno = STDERR_FILENO;
 
616
        char *argv0;
 
617
        char **env;
 
618
        const char * const *argv;
 
619
        apr_int32_t in_pipe;
 
620
        apr_int32_t out_pipe;
 
621
        apr_int32_t err_pipe;
 
622
        apr_cmdtype_e cmd_type;
 
623
        request_rec *r;
 
624
        apr_procattr_t *procattr = NULL;
 
625
        apr_proc_t *procnew = NULL;
 
626
        apr_file_t *inout;
 
627
        cgid_req_t cgid_req;
 
628
        apr_status_t stat;
 
629
 
 
630
        apr_pool_clear(ptrans);
 
631
 
 
632
        len = sizeof(unix_addr);
 
633
        sd2 = accept(sd, (struct sockaddr *)&unix_addr, &len);
 
634
        if (sd2 < 0) {
 
635
#if defined(ENETDOWN)
 
636
            if (errno == ENETDOWN) {
 
637
                /* The network has been shut down, no need to continue. Die gracefully */
 
638
                ++daemon_should_exit;
 
639
            }
 
640
#endif
 
641
            if (errno != EINTR) {
 
642
                ap_log_error(APLOG_MARK, APLOG_ERR, errno,
 
643
                             (server_rec *)data,
 
644
                             "Error accepting on cgid socket");
 
645
            }
 
646
            continue;
 
647
        }
 
648
 
 
649
        r = apr_pcalloc(ptrans, sizeof(request_rec));
 
650
        procnew = apr_pcalloc(ptrans, sizeof(*procnew));
 
651
        r->pool = ptrans;
 
652
        stat = get_req(sd2, r, &argv0, &env, &cgid_req);
 
653
        if (stat != APR_SUCCESS) {
 
654
            ap_log_error(APLOG_MARK, APLOG_ERR, stat,
 
655
                         main_server,
 
656
                         "Error reading request on cgid socket");
 
657
            close(sd2);
 
658
            continue;
 
659
        }
 
660
 
 
661
        if (cgid_req.ppid != parent_pid) {
 
662
            ap_log_error(APLOG_MARK, APLOG_CRIT, 0, main_server,
 
663
                         "CGI request received from wrong server instance; "
 
664
                         "see ScriptSock directive");
 
665
            close(sd2);
 
666
            continue;
 
667
        }
 
668
 
 
669
        if (cgid_req.req_type == GETPID_REQ) {
 
670
            pid_t pid;
 
671
 
 
672
            pid = (pid_t)((long)apr_hash_get(script_hash, &cgid_req.conn_id, sizeof(cgid_req.conn_id)));
 
673
            if (write(sd2, &pid, sizeof(pid)) != sizeof(pid)) {
 
674
                ap_log_error(APLOG_MARK, APLOG_ERR, 0,
 
675
                             main_server,
 
676
                             "Error writing pid %" APR_PID_T_FMT " to handler", pid);
 
677
            }
 
678
            close(sd2);
 
679
            continue;
 
680
        }
 
681
 
 
682
        apr_os_file_put(&r->server->error_log, &errfileno, 0, r->pool);
 
683
        apr_os_file_put(&inout, &sd2, 0, r->pool);
 
684
 
 
685
        if (cgid_req.req_type == SSI_REQ) {
 
686
            in_pipe  = APR_NO_PIPE;
 
687
            out_pipe = APR_FULL_BLOCK;
 
688
            err_pipe = APR_NO_PIPE;
 
689
            cmd_type = APR_SHELLCMD;
 
690
        }
 
691
        else {
 
692
            in_pipe  = APR_CHILD_BLOCK;
 
693
            out_pipe = APR_CHILD_BLOCK;
 
694
            err_pipe = APR_CHILD_BLOCK;
 
695
            cmd_type = APR_PROGRAM;
 
696
        }
 
697
 
 
698
        if (((rc = apr_procattr_create(&procattr, ptrans)) != APR_SUCCESS) ||
 
699
            ((cgid_req.req_type == CGI_REQ) &&
 
700
             (((rc = apr_procattr_io_set(procattr,
 
701
                                        in_pipe,
 
702
                                        out_pipe,
 
703
                                        err_pipe)) != APR_SUCCESS) ||
 
704
              /* XXX apr_procattr_child_*_set() is creating an unnecessary
 
705
               * pipe between this process and the child being created...
 
706
               * It is cleaned up with the temporary pool for this request.
 
707
               */
 
708
              ((rc = apr_procattr_child_err_set(procattr, r->server->error_log, NULL)) != APR_SUCCESS) ||
 
709
              ((rc = apr_procattr_child_in_set(procattr, inout, NULL)) != APR_SUCCESS))) ||
 
710
            ((rc = apr_procattr_child_out_set(procattr, inout, NULL)) != APR_SUCCESS) ||
 
711
            ((rc = apr_procattr_dir_set(procattr,
 
712
                                  ap_make_dirstr_parent(r->pool, r->filename))) != APR_SUCCESS) ||
 
713
            ((rc = apr_procattr_cmdtype_set(procattr, cmd_type)) != APR_SUCCESS) ||
 
714
            ((rc = apr_procattr_child_errfn_set(procattr, cgid_child_errfn)) != APR_SUCCESS)) {
 
715
            /* Something bad happened, tell the world.
 
716
             * ap_log_rerror() won't work because the header table used by
 
717
             * ap_log_rerror() hasn't been replicated in the phony r
 
718
             */
 
719
            ap_log_error(APLOG_MARK, APLOG_ERR, rc, r->server,
 
720
                         "couldn't set child process attributes: %s", r->filename);
 
721
        }
 
722
        else {
 
723
            apr_pool_userdata_set(r, ERRFN_USERDATA_KEY, apr_pool_cleanup_null, ptrans);
 
724
 
 
725
            argv = (const char * const *)create_argv(r->pool, NULL, NULL, NULL, argv0, r->args);
 
726
 
 
727
           /* We want to close sd2 for the new CGI process too.
 
728
            * If it is left open it'll make ap_pass_brigade() block
 
729
            * waiting for EOF if CGI forked something running long.
 
730
            * close(sd2) here should be okay, as CGI channel
 
731
            * is already dup()ed by apr_procattr_child_{in,out}_set()
 
732
            * above.
 
733
            */
 
734
            close(sd2);
 
735
 
 
736
            if (memcmp(&empty_ugid, &cgid_req.ugid, sizeof(empty_ugid))) {
 
737
                /* We have a valid identity, and can be sure that
 
738
                 * cgid_suexec_id_doer will return a valid ugid
 
739
                 */
 
740
                rc = ap_os_create_privileged_process(r, procnew, argv0, argv,
 
741
                                                     (const char * const *)env,
 
742
                                                     procattr, ptrans);
 
743
            } else {
 
744
                rc = apr_proc_create(procnew, argv0, argv,
 
745
                                     (const char * const *)env,
 
746
                                     procattr, ptrans);
 
747
            }
 
748
 
 
749
            if (rc != APR_SUCCESS) {
 
750
                /* Bad things happened. Everyone should have cleaned up.
 
751
                 * ap_log_rerror() won't work because the header table used by
 
752
                 * ap_log_rerror() hasn't been replicated in the phony r
 
753
                 */
 
754
                ap_log_error(APLOG_MARK, APLOG_ERR, rc, r->server,
 
755
                             "couldn't create child process: %d: %s", rc,
 
756
                             apr_filepath_name_get(r->filename));
 
757
            }
 
758
            else {
 
759
                /* We don't want to leak storage for the key, so only allocate
 
760
                 * a key if the key doesn't exist yet in the hash; there are
 
761
                 * only a limited number of possible keys (one for each
 
762
                 * possible thread in the server), so we can allocate a copy
 
763
                 * of the key the first time a thread has a cgid request.
 
764
                 * Note that apr_hash_set() only uses the storage passed in
 
765
                 * for the key if it is adding the key to the hash for the
 
766
                 * first time; new key storage isn't needed for replacing the
 
767
                 * existing value of a key.
 
768
                 */
 
769
                void *key;
 
770
 
 
771
                if (apr_hash_get(script_hash, &cgid_req.conn_id, sizeof(cgid_req.conn_id))) {
 
772
                    key = &cgid_req.conn_id;
 
773
                }
 
774
                else {
 
775
                    key = apr_pcalloc(pcgi, sizeof(cgid_req.conn_id));
 
776
                    memcpy(key, &cgid_req.conn_id, sizeof(cgid_req.conn_id));
 
777
                }
 
778
                apr_hash_set(script_hash, key, sizeof(cgid_req.conn_id),
 
779
                             (void *)((long)procnew->pid));
 
780
            }
 
781
        }
 
782
    }
 
783
    return -1;
 
784
}
 
785
 
 
786
static int cgid_start(apr_pool_t *p, server_rec *main_server,
 
787
                      apr_proc_t *procnew)
 
788
{
 
789
 
 
790
    daemon_should_exit = 0; /* clear setting from previous generation */
 
791
    if ((daemon_pid = fork()) < 0) {
 
792
        ap_log_error(APLOG_MARK, APLOG_ERR, errno, main_server,
 
793
                     "mod_cgid: Couldn't spawn cgid daemon process");
 
794
        return DECLINED;
 
795
    }
 
796
    else if (daemon_pid == 0) {
 
797
        if (pcgi == NULL) {
 
798
            apr_pool_create(&pcgi, p);
 
799
        }
 
800
        cgid_server(main_server);
 
801
        exit(-1);
 
802
    }
 
803
    procnew->pid = daemon_pid;
 
804
    procnew->err = procnew->in = procnew->out = NULL;
 
805
    apr_pool_note_subprocess(p, procnew, APR_KILL_AFTER_TIMEOUT);
 
806
#if APR_HAS_OTHER_CHILD
 
807
    apr_proc_other_child_register(procnew, cgid_maint, procnew, NULL, p);
 
808
#endif
 
809
    return OK;
 
810
}
 
811
 
 
812
static int cgid_pre_config(apr_pool_t *pconf, apr_pool_t *plog,
 
813
                           apr_pool_t *ptemp)
 
814
{
 
815
    sockname = ap_append_pid(pconf, DEFAULT_SOCKET, ".");
 
816
    return OK;
 
817
}
 
818
 
 
819
static int cgid_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp,
 
820
                     server_rec *main_server)
 
821
{
 
822
    apr_proc_t *procnew = NULL;
 
823
    int first_time = 0;
 
824
    const char *userdata_key = "cgid_init";
 
825
    module **m;
 
826
    int ret = OK;
 
827
    void *data;
 
828
 
 
829
    root_server = main_server;
 
830
    root_pool = p;
 
831
 
 
832
    apr_pool_userdata_get(&data, userdata_key, main_server->process->pool);
 
833
    if (!data) {
 
834
        first_time = 1;
 
835
        procnew = apr_pcalloc(main_server->process->pool, sizeof(*procnew));
 
836
        procnew->pid = -1;
 
837
        procnew->err = procnew->in = procnew->out = NULL;
 
838
        apr_pool_userdata_set((const void *)procnew, userdata_key,
 
839
                     apr_pool_cleanup_null, main_server->process->pool);
 
840
    }
 
841
    else {
 
842
        procnew = data;
 
843
    }
 
844
 
 
845
    if (!first_time) {
 
846
        total_modules = 0;
 
847
        for (m = ap_preloaded_modules; *m != NULL; m++)
 
848
            total_modules++;
 
849
 
 
850
        parent_pid = getpid();
 
851
        sockname = ap_server_root_relative(p, sockname);
 
852
        ret = cgid_start(p, main_server, procnew);
 
853
        if (ret != OK ) {
 
854
            return ret;
 
855
        }
 
856
        cgid_pfn_reg_with_ssi = APR_RETRIEVE_OPTIONAL_FN(ap_register_include_handler);
 
857
        cgid_pfn_gtv          = APR_RETRIEVE_OPTIONAL_FN(ap_ssi_get_tag_and_value);
 
858
        cgid_pfn_ps           = APR_RETRIEVE_OPTIONAL_FN(ap_ssi_parse_string);
 
859
 
 
860
        if ((cgid_pfn_reg_with_ssi) && (cgid_pfn_gtv) && (cgid_pfn_ps)) {
 
861
            /* Required by mod_include filter. This is how mod_cgid registers
 
862
             *   with mod_include to provide processing of the exec directive.
 
863
             */
 
864
            cgid_pfn_reg_with_ssi("exec", handle_exec);
 
865
        }
 
866
    }
 
867
    return ret;
 
868
}
 
869
 
 
870
static void *create_cgid_config(apr_pool_t *p, server_rec *s)
 
871
{
 
872
    cgid_server_conf *c =
 
873
    (cgid_server_conf *) apr_pcalloc(p, sizeof(cgid_server_conf));
 
874
 
 
875
    c->logname = NULL;
 
876
    c->logbytes = DEFAULT_LOGBYTES;
 
877
    c->bufbytes = DEFAULT_BUFBYTES;
 
878
    return c;
 
879
}
 
880
 
 
881
static void *merge_cgid_config(apr_pool_t *p, void *basev, void *overridesv)
 
882
{
 
883
    cgid_server_conf *base = (cgid_server_conf *) basev, *overrides = (cgid_server_conf *) overridesv;
 
884
 
 
885
    return overrides->logname ? overrides : base;
 
886
}
 
887
 
 
888
static const char *set_scriptlog(cmd_parms *cmd, void *dummy, const char *arg)
 
889
{
 
890
    server_rec *s = cmd->server;
 
891
    cgid_server_conf *conf = ap_get_module_config(s->module_config,
 
892
                                                  &cgid_module);
 
893
 
 
894
    conf->logname = ap_server_root_relative(cmd->pool, arg);
 
895
 
 
896
    if (!conf->logname) {
 
897
        return apr_pstrcat(cmd->pool, "Invalid ScriptLog path ",
 
898
                           arg, NULL);
 
899
    }
 
900
    return NULL;
 
901
}
 
902
 
 
903
static const char *set_scriptlog_length(cmd_parms *cmd, void *dummy, const char *arg)
 
904
{
 
905
    server_rec *s = cmd->server;
 
906
    cgid_server_conf *conf = ap_get_module_config(s->module_config,
 
907
                                                  &cgid_module);
 
908
 
 
909
    conf->logbytes = atol(arg);
 
910
    return NULL;
 
911
}
 
912
 
 
913
static const char *set_scriptlog_buffer(cmd_parms *cmd, void *dummy, const char *arg)
 
914
{
 
915
    server_rec *s = cmd->server;
 
916
    cgid_server_conf *conf = ap_get_module_config(s->module_config,
 
917
                                                  &cgid_module);
 
918
 
 
919
    conf->bufbytes = atoi(arg);
 
920
    return NULL;
 
921
}
 
922
 
 
923
static const char *set_script_socket(cmd_parms *cmd, void *dummy, const char *arg)
 
924
{
 
925
    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
 
926
    if (err != NULL) {
 
927
        return err;
 
928
    }
 
929
 
 
930
    /* Make sure the pid is appended to the sockname */
 
931
    sockname = ap_append_pid(cmd->pool, arg, ".");
 
932
    sockname = ap_server_root_relative(cmd->pool, sockname);
 
933
 
 
934
    if (!sockname) {
 
935
        return apr_pstrcat(cmd->pool, "Invalid ScriptSock path",
 
936
                           arg, NULL);
 
937
    }
 
938
 
 
939
    return NULL;
 
940
}
 
941
 
 
942
static const command_rec cgid_cmds[] =
 
943
{
 
944
    AP_INIT_TAKE1("ScriptLog", set_scriptlog, NULL, RSRC_CONF,
 
945
                  "the name of a log for script debugging info"),
 
946
    AP_INIT_TAKE1("ScriptLogLength", set_scriptlog_length, NULL, RSRC_CONF,
 
947
                  "the maximum length (in bytes) of the script debug log"),
 
948
    AP_INIT_TAKE1("ScriptLogBuffer", set_scriptlog_buffer, NULL, RSRC_CONF,
 
949
                  "the maximum size (in bytes) to record of a POST request"),
 
950
    AP_INIT_TAKE1("ScriptSock", set_script_socket, NULL, RSRC_CONF,
 
951
                  "the name of the socket to use for communication with "
 
952
                  "the cgi daemon."),
 
953
    {NULL}
 
954
};
 
955
 
 
956
static int log_scripterror(request_rec *r, cgid_server_conf * conf, int ret,
 
957
                           apr_status_t rv, char *error)
 
958
{
 
959
    apr_file_t *f = NULL;
 
960
    struct stat finfo;
 
961
    char time_str[APR_CTIME_LEN];
 
962
    int log_flags = rv ? APLOG_ERR : APLOG_ERR;
 
963
 
 
964
    ap_log_rerror(APLOG_MARK, log_flags, rv, r,
 
965
                "%s: %s", error, r->filename);
 
966
 
 
967
    /* XXX Very expensive mainline case! Open, then getfileinfo! */
 
968
    if (!conf->logname ||
 
969
        ((stat(conf->logname, &finfo) == 0)
 
970
         && (finfo.st_size > conf->logbytes)) ||
 
971
         (apr_file_open(&f, conf->logname,
 
972
                  APR_APPEND|APR_WRITE|APR_CREATE, APR_OS_DEFAULT, r->pool) != APR_SUCCESS)) {
 
973
        return ret;
 
974
    }
 
975
 
 
976
    /* "%% [Wed Jun 19 10:53:21 1996] GET /cgid-bin/printenv HTTP/1.0" */
 
977
    apr_ctime(time_str, apr_time_now());
 
978
    apr_file_printf(f, "%%%% [%s] %s %s%s%s %s\n", time_str, r->method, r->uri,
 
979
            r->args ? "?" : "", r->args ? r->args : "", r->protocol);
 
980
    /* "%% 500 /usr/local/apache/cgid-bin */
 
981
    apr_file_printf(f, "%%%% %d %s\n", ret, r->filename);
 
982
 
 
983
    apr_file_printf(f, "%%error\n%s\n", error);
 
984
 
 
985
    apr_file_close(f);
 
986
    return ret;
 
987
}
 
988
 
 
989
static int log_script(request_rec *r, cgid_server_conf * conf, int ret,
 
990
                      char *dbuf, const char *sbuf, apr_bucket_brigade *bb,
 
991
                      apr_file_t *script_err)
 
992
{
 
993
    const apr_array_header_t *hdrs_arr = apr_table_elts(r->headers_in);
 
994
    const apr_table_entry_t *hdrs = (apr_table_entry_t *) hdrs_arr->elts;
 
995
    char argsbuffer[HUGE_STRING_LEN];
 
996
    apr_file_t *f = NULL;
 
997
    apr_bucket *e;
 
998
    const char *buf;
 
999
    apr_size_t len;
 
1000
    apr_status_t rv;
 
1001
    int first;
 
1002
    int i;
 
1003
    struct stat finfo;
 
1004
    char time_str[APR_CTIME_LEN];
 
1005
 
 
1006
    /* XXX Very expensive mainline case! Open, then getfileinfo! */
 
1007
    if (!conf->logname ||
 
1008
        ((stat(conf->logname, &finfo) == 0)
 
1009
         && (finfo.st_size > conf->logbytes)) ||
 
1010
         (apr_file_open(&f, conf->logname,
 
1011
                  APR_APPEND|APR_WRITE|APR_CREATE, APR_OS_DEFAULT, r->pool) != APR_SUCCESS)) {
 
1012
        /* Soak up script output */
 
1013
        discard_script_output(bb);
 
1014
        if (script_err) {
 
1015
            while (apr_file_gets(argsbuffer, HUGE_STRING_LEN,
 
1016
                                 script_err) == APR_SUCCESS)
 
1017
                continue;
 
1018
        }
 
1019
        return ret;
 
1020
    }
 
1021
 
 
1022
    /* "%% [Wed Jun 19 10:53:21 1996] GET /cgid-bin/printenv HTTP/1.0" */
 
1023
    apr_ctime(time_str, apr_time_now());
 
1024
    apr_file_printf(f, "%%%% [%s] %s %s%s%s %s\n", time_str, r->method, r->uri,
 
1025
            r->args ? "?" : "", r->args ? r->args : "", r->protocol);
 
1026
    /* "%% 500 /usr/local/apache/cgid-bin" */
 
1027
    apr_file_printf(f, "%%%% %d %s\n", ret, r->filename);
 
1028
 
 
1029
    apr_file_puts("%request\n", f);
 
1030
    for (i = 0; i < hdrs_arr->nelts; ++i) {
 
1031
        if (!hdrs[i].key)
 
1032
            continue;
 
1033
        apr_file_printf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val);
 
1034
    }
 
1035
    if ((r->method_number == M_POST || r->method_number == M_PUT)
 
1036
        && *dbuf) {
 
1037
        apr_file_printf(f, "\n%s\n", dbuf);
 
1038
    }
 
1039
 
 
1040
    apr_file_puts("%response\n", f);
 
1041
    hdrs_arr = apr_table_elts(r->err_headers_out);
 
1042
    hdrs = (const apr_table_entry_t *) hdrs_arr->elts;
 
1043
 
 
1044
    for (i = 0; i < hdrs_arr->nelts; ++i) {
 
1045
        if (!hdrs[i].key)
 
1046
            continue;
 
1047
        apr_file_printf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val);
 
1048
    }
 
1049
 
 
1050
    if (sbuf && *sbuf)
 
1051
        apr_file_printf(f, "%s\n", sbuf);
 
1052
 
 
1053
    first = 1;
 
1054
 
 
1055
    for (e = APR_BRIGADE_FIRST(bb);
 
1056
         e != APR_BRIGADE_SENTINEL(bb);
 
1057
         e = APR_BUCKET_NEXT(e))
 
1058
    {
 
1059
        if (APR_BUCKET_IS_EOS(e)) {
 
1060
            break;
 
1061
        }
 
1062
        rv = apr_bucket_read(e, &buf, &len, APR_BLOCK_READ);
 
1063
        if (rv != APR_SUCCESS || (len == 0)) {
 
1064
            break;
 
1065
        }
 
1066
        if (first) {
 
1067
            apr_file_puts("%stdout\n", f);
 
1068
            first = 0;
 
1069
        }
 
1070
        apr_file_write(f, buf, &len);
 
1071
        apr_file_puts("\n", f);
 
1072
    }
 
1073
 
 
1074
    if (script_err) {
 
1075
        if (apr_file_gets(argsbuffer, HUGE_STRING_LEN,
 
1076
                          script_err) == APR_SUCCESS) {
 
1077
            apr_file_puts("%stderr\n", f);
 
1078
            apr_file_puts(argsbuffer, f);
 
1079
            while (apr_file_gets(argsbuffer, HUGE_STRING_LEN,
 
1080
                                 script_err) == APR_SUCCESS)
 
1081
                apr_file_puts(argsbuffer, f);
 
1082
            apr_file_puts("\n", f);
 
1083
        }
 
1084
    }
 
1085
 
 
1086
    if (script_err) {
 
1087
        apr_file_close(script_err);
 
1088
    }
 
1089
 
 
1090
    apr_file_close(f);
 
1091
    return ret;
 
1092
}
 
1093
 
 
1094
static apr_status_t close_unix_socket(void *thefd)
 
1095
{
 
1096
    int fd = (int)((long)thefd);
 
1097
 
 
1098
    return close(fd);
 
1099
}
 
1100
 
 
1101
static int connect_to_daemon(int *sdptr, request_rec *r,
 
1102
                             cgid_server_conf *conf)
 
1103
{
 
1104
    struct sockaddr_un unix_addr;
 
1105
    int sd;
 
1106
    int connect_tries;
 
1107
    apr_interval_time_t sliding_timer;
 
1108
 
 
1109
    memset(&unix_addr, 0, sizeof(unix_addr));
 
1110
    unix_addr.sun_family = AF_UNIX;
 
1111
    apr_cpystrn(unix_addr.sun_path, sockname, sizeof unix_addr.sun_path);
 
1112
 
 
1113
    connect_tries = 0;
 
1114
    sliding_timer = 100000; /* 100 milliseconds */
 
1115
    while (1) {
 
1116
        ++connect_tries;
 
1117
        if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
 
1118
            return log_scripterror(r, conf, HTTP_INTERNAL_SERVER_ERROR, errno,
 
1119
                                   "unable to create socket to cgi daemon");
 
1120
        }
 
1121
        if (connect(sd, (struct sockaddr *)&unix_addr, sizeof(unix_addr)) < 0) {
 
1122
            if (errno == ECONNREFUSED && connect_tries < DEFAULT_CONNECT_ATTEMPTS) {
 
1123
                ap_log_rerror(APLOG_MARK, APLOG_DEBUG, errno, r,
 
1124
                              "connect #%d to cgi daemon failed, sleeping before retry",
 
1125
                              connect_tries);
 
1126
                close(sd);
 
1127
                apr_sleep(sliding_timer);
 
1128
                if (sliding_timer < apr_time_from_sec(2)) {
 
1129
                    sliding_timer *= 2;
 
1130
                }
 
1131
            }
 
1132
            else {
 
1133
                close(sd);
 
1134
                return log_scripterror(r, conf, HTTP_SERVICE_UNAVAILABLE, errno,
 
1135
                                       "unable to connect to cgi daemon after multiple tries");
 
1136
            }
 
1137
        }
 
1138
        else {
 
1139
            apr_pool_cleanup_register(r->pool, (void *)((long)sd),
 
1140
                                      close_unix_socket, apr_pool_cleanup_null);
 
1141
            break; /* we got connected! */
 
1142
        }
 
1143
        /* gotta try again, but make sure the cgid daemon is still around */
 
1144
        if (kill(daemon_pid, 0) != 0) {
 
1145
            return log_scripterror(r, conf, HTTP_SERVICE_UNAVAILABLE, errno,
 
1146
                                   "cgid daemon is gone; is Apache terminating?");
 
1147
        }
 
1148
    }
 
1149
    *sdptr = sd;
 
1150
    return OK;
 
1151
}
 
1152
 
 
1153
static void discard_script_output(apr_bucket_brigade *bb)
 
1154
{
 
1155
    apr_bucket *e;
 
1156
    const char *buf;
 
1157
    apr_size_t len;
 
1158
    apr_status_t rv;
 
1159
 
 
1160
    for (e = APR_BRIGADE_FIRST(bb);
 
1161
         e != APR_BRIGADE_SENTINEL(bb);
 
1162
         e = APR_BUCKET_NEXT(e))
 
1163
    {
 
1164
        if (APR_BUCKET_IS_EOS(e)) {
 
1165
            break;
 
1166
        }
 
1167
        rv = apr_bucket_read(e, &buf, &len, APR_BLOCK_READ);
 
1168
        if (rv != APR_SUCCESS) {
 
1169
            break;
 
1170
        }
 
1171
    }
 
1172
}
 
1173
 
 
1174
/****************************************************************
 
1175
 *
 
1176
 * Actual cgid handling...
 
1177
 */
 
1178
 
 
1179
struct cleanup_script_info {
 
1180
    request_rec *r;
 
1181
    unsigned long conn_id;
 
1182
    cgid_server_conf *conf;
 
1183
};
 
1184
 
 
1185
static apr_status_t dead_yet(pid_t pid, apr_interval_time_t max_wait)
 
1186
{
 
1187
    apr_interval_time_t interval = 10000; /* 10 ms */
 
1188
    apr_interval_time_t total = 0;
 
1189
 
 
1190
    do {
 
1191
#ifdef _AIX
 
1192
        /* On AIX, for processes like mod_cgid's script children where
 
1193
         * SIGCHLD is ignored, kill(pid,0) returns success for up to
 
1194
         * one second after the script child exits, based on when a
 
1195
         * daemon runs to clean up unnecessary process table entries.
 
1196
         * getpgid() can report the proper info (-1/ESRCH) immediately.
 
1197
         */
 
1198
        if (getpgid(pid) < 0) {
 
1199
#else
 
1200
        if (kill(pid, 0) < 0) {
 
1201
#endif
 
1202
            return APR_SUCCESS;
 
1203
        }
 
1204
        apr_sleep(interval);
 
1205
        total = total + interval;
 
1206
        if (interval < 500000) {
 
1207
            interval *= 2;
 
1208
        }
 
1209
    } while (total < max_wait);
 
1210
    return APR_EGENERAL;
 
1211
}
 
1212
 
 
1213
static apr_status_t cleanup_nonchild_process(request_rec *r, pid_t pid)
 
1214
{
 
1215
    kill(pid, SIGTERM); /* in case it isn't dead yet */
 
1216
    if (dead_yet(pid, apr_time_from_sec(3)) == APR_SUCCESS) {
 
1217
        return APR_SUCCESS;
 
1218
    }
 
1219
    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
 
1220
                  "CGI process %" APR_PID_T_FMT " didn't exit, sending SIGKILL",
 
1221
                  pid);
 
1222
    kill(pid, SIGKILL);
 
1223
    if (dead_yet(pid, apr_time_from_sec(3)) == APR_SUCCESS) {
 
1224
        return APR_SUCCESS;
 
1225
    }
 
1226
    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
 
1227
                  "CGI process %" APR_PID_T_FMT " didn't exit, sending SIGKILL again",
 
1228
                  pid);
 
1229
    kill(pid, SIGKILL);
 
1230
 
 
1231
    return APR_EGENERAL;
 
1232
}
 
1233
 
 
1234
static apr_status_t cleanup_script(void *vptr)
 
1235
{
 
1236
    struct cleanup_script_info *info = vptr;
 
1237
    int sd;
 
1238
    int rc;
 
1239
    cgid_req_t req = {0};
 
1240
    pid_t pid;
 
1241
    apr_status_t stat;
 
1242
 
 
1243
    rc = connect_to_daemon(&sd, info->r, info->conf);
 
1244
    if (rc != OK) {
 
1245
        return APR_EGENERAL;
 
1246
    }
 
1247
 
 
1248
    /* we got a socket, and there is already a cleanup registered for it */
 
1249
 
 
1250
    req.req_type = GETPID_REQ;
 
1251
    req.ppid = parent_pid;
 
1252
    req.conn_id = info->r->connection->id;
 
1253
 
 
1254
    stat = sock_write(sd, &req, sizeof(req));
 
1255
    if (stat != APR_SUCCESS) {
 
1256
        return stat;
 
1257
    }
 
1258
 
 
1259
    /* wait for pid of script */
 
1260
    stat = sock_read(sd, &pid, sizeof(pid));
 
1261
    if (stat != APR_SUCCESS) {
 
1262
        return stat;
 
1263
    }
 
1264
 
 
1265
    if (pid == 0) {
 
1266
        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, info->r,
 
1267
                      "daemon couldn't find CGI process for connection %lu",
 
1268
                      info->conn_id);
 
1269
        return APR_EGENERAL;
 
1270
    }
 
1271
    return cleanup_nonchild_process(info->r, pid);
 
1272
}
 
1273
 
 
1274
static int cgid_handler(request_rec *r)
 
1275
{
 
1276
    conn_rec *c = r->connection;
 
1277
    int retval, nph, dbpos = 0;
 
1278
    char *argv0, *dbuf = NULL;
 
1279
    apr_bucket_brigade *bb;
 
1280
    apr_bucket *b;
 
1281
    cgid_server_conf *conf;
 
1282
    int is_included;
 
1283
    int seen_eos, child_stopped_reading;
 
1284
    int sd;
 
1285
    char **env;
 
1286
    apr_file_t *tempsock;
 
1287
    struct cleanup_script_info *info;
 
1288
    apr_status_t rv;
 
1289
 
 
1290
    if (strcmp(r->handler,CGI_MAGIC_TYPE) && strcmp(r->handler,"cgi-script"))
 
1291
        return DECLINED;
 
1292
 
 
1293
    conf = ap_get_module_config(r->server->module_config, &cgid_module);
 
1294
    is_included = !strcmp(r->protocol, "INCLUDED");
 
1295
 
 
1296
    if ((argv0 = strrchr(r->filename, '/')) != NULL)
 
1297
        argv0++;
 
1298
    else
 
1299
        argv0 = r->filename;
 
1300
 
 
1301
    nph = !(strncmp(argv0, "nph-", 4));
 
1302
 
 
1303
    argv0 = r->filename;
 
1304
 
 
1305
    if (!(ap_allow_options(r) & OPT_EXECCGI) && !is_scriptaliased(r))
 
1306
        return log_scripterror(r, conf, HTTP_FORBIDDEN, 0,
 
1307
                               "Options ExecCGI is off in this directory");
 
1308
    if (nph && is_included)
 
1309
        return log_scripterror(r, conf, HTTP_FORBIDDEN, 0,
 
1310
                               "attempt to include NPH CGI script");
 
1311
 
 
1312
#if defined(OS2) || defined(WIN32)
 
1313
#error mod_cgid does not work on this platform.  If you teach it to, look
 
1314
#error at mod_cgi.c for required code in this path.
 
1315
#else
 
1316
    if (r->finfo.filetype == 0)
 
1317
        return log_scripterror(r, conf, HTTP_NOT_FOUND, 0,
 
1318
                               "script not found or unable to stat");
 
1319
#endif
 
1320
    if (r->finfo.filetype == APR_DIR)
 
1321
        return log_scripterror(r, conf, HTTP_FORBIDDEN, 0,
 
1322
                               "attempt to invoke directory as script");
 
1323
 
 
1324
    if ((r->used_path_info == AP_REQ_REJECT_PATH_INFO) &&
 
1325
        r->path_info && *r->path_info)
 
1326
    {
 
1327
        /* default to accept */
 
1328
        return log_scripterror(r, conf, HTTP_NOT_FOUND, 0,
 
1329
                               "AcceptPathInfo off disallows user's path");
 
1330
    }
 
1331
/*
 
1332
    if (!ap_suexec_enabled) {
 
1333
        if (!ap_can_exec(&r->finfo))
 
1334
            return log_scripterror(r, conf, HTTP_FORBIDDEN, 0,
 
1335
                                   "file permissions deny server execution");
 
1336
    }
 
1337
*/
 
1338
    ap_add_common_vars(r);
 
1339
    ap_add_cgi_vars(r);
 
1340
    env = ap_create_environment(r->pool, r->subprocess_env);
 
1341
 
 
1342
    if ((retval = connect_to_daemon(&sd, r, conf)) != OK) {
 
1343
        return retval;
 
1344
    }
 
1345
 
 
1346
    rv = send_req(sd, r, argv0, env, CGI_REQ);
 
1347
    if (rv != APR_SUCCESS) {
 
1348
        ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
 
1349
                     "write to cgi daemon process");
 
1350
    }
 
1351
 
 
1352
    info = apr_palloc(r->pool, sizeof(struct cleanup_script_info));
 
1353
    info->r = r;
 
1354
    info->conn_id = r->connection->id;
 
1355
    info->conf = conf;
 
1356
    apr_pool_cleanup_register(r->pool, info,
 
1357
                              cleanup_script,
 
1358
                              apr_pool_cleanup_null);
 
1359
    /* We are putting the socket discriptor into an apr_file_t so that we can
 
1360
     * use a pipe bucket to send the data to the client.  APR will create
 
1361
     * a cleanup for the apr_file_t which will close the socket, so we'll
 
1362
     * get rid of the cleanup we registered when we created the socket.
 
1363
     */
 
1364
 
 
1365
    apr_os_pipe_put_ex(&tempsock, &sd, 1, r->pool);
 
1366
    apr_pool_cleanup_kill(r->pool, (void *)((long)sd), close_unix_socket);
 
1367
 
 
1368
    if ((argv0 = strrchr(r->filename, '/')) != NULL)
 
1369
        argv0++;
 
1370
    else
 
1371
        argv0 = r->filename;
 
1372
 
 
1373
    /* Transfer any put/post args, CERN style...
 
1374
     * Note that we already ignore SIGPIPE in the core server.
 
1375
     */
 
1376
    bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
 
1377
    seen_eos = 0;
 
1378
    child_stopped_reading = 0;
 
1379
    if (conf->logname) {
 
1380
        dbuf = apr_palloc(r->pool, conf->bufbytes + 1);
 
1381
        dbpos = 0;
 
1382
    }
 
1383
    do {
 
1384
        apr_bucket *bucket;
 
1385
 
 
1386
        rv = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES,
 
1387
                            APR_BLOCK_READ, HUGE_STRING_LEN);
 
1388
 
 
1389
        if (rv != APR_SUCCESS) {
 
1390
            return rv;
 
1391
        }
 
1392
 
 
1393
        for (bucket = APR_BRIGADE_FIRST(bb);
 
1394
             bucket != APR_BRIGADE_SENTINEL(bb);
 
1395
             bucket = APR_BUCKET_NEXT(bucket))
 
1396
        {
 
1397
            const char *data;
 
1398
            apr_size_t len;
 
1399
 
 
1400
            if (APR_BUCKET_IS_EOS(bucket)) {
 
1401
                seen_eos = 1;
 
1402
                break;
 
1403
            }
 
1404
 
 
1405
            /* We can't do much with this. */
 
1406
            if (APR_BUCKET_IS_FLUSH(bucket)) {
 
1407
                continue;
 
1408
            }
 
1409
 
 
1410
            /* If the child stopped, we still must read to EOS. */
 
1411
            if (child_stopped_reading) {
 
1412
                continue;
 
1413
            }
 
1414
 
 
1415
            /* read */
 
1416
            apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
 
1417
 
 
1418
            if (conf->logname && dbpos < conf->bufbytes) {
 
1419
                int cursize;
 
1420
 
 
1421
                if ((dbpos + len) > conf->bufbytes) {
 
1422
                    cursize = conf->bufbytes - dbpos;
 
1423
                }
 
1424
                else {
 
1425
                    cursize = len;
 
1426
                }
 
1427
                memcpy(dbuf + dbpos, data, cursize);
 
1428
                dbpos += cursize;
 
1429
            }
 
1430
 
 
1431
            /* Keep writing data to the child until done or too much time
 
1432
             * elapses with no progress or an error occurs.
 
1433
             */
 
1434
            rv = apr_file_write_full(tempsock, data, len, NULL);
 
1435
 
 
1436
            if (rv != APR_SUCCESS) {
 
1437
                /* silly script stopped reading, soak up remaining message */
 
1438
                child_stopped_reading = 1;
 
1439
            }
 
1440
        }
 
1441
        apr_brigade_cleanup(bb);
 
1442
    }
 
1443
    while (!seen_eos);
 
1444
 
 
1445
    if (conf->logname) {
 
1446
        dbuf[dbpos] = '\0';
 
1447
    }
 
1448
 
 
1449
    /* we're done writing, or maybe we didn't write at all;
 
1450
     * force EOF on child's stdin so that the cgi detects end (or
 
1451
     * absence) of data
 
1452
     */
 
1453
    shutdown(sd, 1);
 
1454
 
 
1455
    /* Handle script return... */
 
1456
    if (!nph) {
 
1457
        const char *location;
 
1458
        char sbuf[MAX_STRING_LEN];
 
1459
        int ret;
 
1460
 
 
1461
        bb = apr_brigade_create(r->pool, c->bucket_alloc);
 
1462
        b = apr_bucket_pipe_create(tempsock, c->bucket_alloc);
 
1463
        APR_BRIGADE_INSERT_TAIL(bb, b);
 
1464
        b = apr_bucket_eos_create(c->bucket_alloc);
 
1465
        APR_BRIGADE_INSERT_TAIL(bb, b);
 
1466
 
 
1467
        if ((ret = ap_scan_script_header_err_brigade(r, bb, sbuf))) {
 
1468
            return log_script(r, conf, ret, dbuf, sbuf, bb, NULL);
 
1469
        }
 
1470
 
 
1471
        location = apr_table_get(r->headers_out, "Location");
 
1472
 
 
1473
        if (location && location[0] == '/' && r->status == 200) {
 
1474
 
 
1475
            /* Soak up all the script output */
 
1476
            discard_script_output(bb);
 
1477
            apr_brigade_destroy(bb);
 
1478
            /* This redirect needs to be a GET no matter what the original
 
1479
             * method was.
 
1480
             */
 
1481
            r->method = apr_pstrdup(r->pool, "GET");
 
1482
            r->method_number = M_GET;
 
1483
 
 
1484
            /* We already read the message body (if any), so don't allow
 
1485
             * the redirected request to think it has one. We can ignore
 
1486
             * Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR.
 
1487
             */
 
1488
            apr_table_unset(r->headers_in, "Content-Length");
 
1489
 
 
1490
            ap_internal_redirect_handler(location, r);
 
1491
            return OK;
 
1492
        }
 
1493
        else if (location && r->status == 200) {
 
1494
            /* XX Note that if a script wants to produce its own Redirect
 
1495
             * body, it now has to explicitly *say* "Status: 302"
 
1496
             */
 
1497
            discard_script_output(bb);
 
1498
            apr_brigade_destroy(bb);
 
1499
            return HTTP_MOVED_TEMPORARILY;
 
1500
        }
 
1501
 
 
1502
        ap_pass_brigade(r->output_filters, bb);
 
1503
    }
 
1504
 
 
1505
    if (nph) {
 
1506
        struct ap_filter_t *cur;
 
1507
 
 
1508
        /* get rid of all filters up through protocol...  since we
 
1509
         * haven't parsed off the headers, there is no way they can
 
1510
         * work
 
1511
         */
 
1512
 
 
1513
        cur = r->proto_output_filters;
 
1514
        while (cur && cur->frec->ftype < AP_FTYPE_CONNECTION) {
 
1515
            cur = cur->next;
 
1516
        }
 
1517
        r->output_filters = r->proto_output_filters = cur;
 
1518
 
 
1519
        bb = apr_brigade_create(r->pool, c->bucket_alloc);
 
1520
        b = apr_bucket_pipe_create(tempsock, c->bucket_alloc);
 
1521
        APR_BRIGADE_INSERT_TAIL(bb, b);
 
1522
        b = apr_bucket_eos_create(c->bucket_alloc);
 
1523
        APR_BRIGADE_INSERT_TAIL(bb, b);
 
1524
        ap_pass_brigade(r->output_filters, bb);
 
1525
    }
 
1526
 
 
1527
    return OK; /* NOT r->status, even if it has changed. */
 
1528
}
 
1529
 
 
1530
 
 
1531
 
 
1532
 
 
1533
/*============================================================================
 
1534
 *============================================================================
 
1535
 * This is the beginning of the cgi filter code moved from mod_include. This
 
1536
 *   is the code required to handle the "exec" SSI directive.
 
1537
 *============================================================================
 
1538
 *============================================================================*/
 
1539
static apr_status_t include_cgi(include_ctx_t *ctx, ap_filter_t *f,
 
1540
                                apr_bucket_brigade *bb, char *s)
 
1541
{
 
1542
    request_rec *r = f->r;
 
1543
    request_rec *rr = ap_sub_req_lookup_uri(s, r, f->next);
 
1544
    int rr_status;
 
1545
 
 
1546
    if (rr->status != HTTP_OK) {
 
1547
        ap_destroy_sub_req(rr);
 
1548
        return APR_EGENERAL;
 
1549
    }
 
1550
 
 
1551
    /* No hardwired path info or query allowed */
 
1552
    if ((rr->path_info && rr->path_info[0]) || rr->args) {
 
1553
        ap_destroy_sub_req(rr);
 
1554
        return APR_EGENERAL;
 
1555
    }
 
1556
    if (rr->finfo.filetype != APR_REG) {
 
1557
        ap_destroy_sub_req(rr);
 
1558
        return APR_EGENERAL;
 
1559
    }
 
1560
 
 
1561
    /* Script gets parameters of the *document*, for back compatibility */
 
1562
    rr->path_info = r->path_info;       /* hard to get right; see mod_cgi.c */
 
1563
    rr->args = r->args;
 
1564
 
 
1565
    /* Force sub_req to be treated as a CGI request, even if ordinary
 
1566
     * typing rules would have called it something else.
 
1567
     */
 
1568
    ap_set_content_type(rr, CGI_MAGIC_TYPE);
 
1569
 
 
1570
    /* Run it. */
 
1571
    rr_status = ap_run_sub_req(rr);
 
1572
    if (ap_is_HTTP_REDIRECT(rr_status)) {
 
1573
        const char *location = apr_table_get(rr->headers_out, "Location");
 
1574
 
 
1575
        if (location) {
 
1576
            char *buffer;
 
1577
 
 
1578
            location = ap_escape_html(rr->pool, location);
 
1579
            buffer = apr_pstrcat(ctx->pool, "<a href=\"", location, "\">",
 
1580
                                 location, "</a>", NULL);
 
1581
 
 
1582
            APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_pool_create(buffer,
 
1583
                                    strlen(buffer), ctx->pool,
 
1584
                                    f->c->bucket_alloc));
 
1585
        }
 
1586
    }
 
1587
 
 
1588
    ap_destroy_sub_req(rr);
 
1589
 
 
1590
    return APR_SUCCESS;
 
1591
}
 
1592
 
 
1593
/* This is the special environment used for running the "exec cmd="
 
1594
 *   variety of SSI directives.
 
1595
 */
 
1596
static void add_ssi_vars(request_rec *r)
 
1597
{
 
1598
    apr_table_t *e = r->subprocess_env;
 
1599
 
 
1600
    if (r->path_info && r->path_info[0] != '\0') {
 
1601
        request_rec *pa_req;
 
1602
 
 
1603
        apr_table_setn(e, "PATH_INFO", ap_escape_shell_cmd(r->pool, r->path_info));
 
1604
 
 
1605
        pa_req = ap_sub_req_lookup_uri(ap_escape_uri(r->pool, r->path_info), r, NULL);
 
1606
        if (pa_req->filename) {
 
1607
            apr_table_setn(e, "PATH_TRANSLATED",
 
1608
                           apr_pstrcat(r->pool, pa_req->filename, pa_req->path_info, NULL));
 
1609
        }
 
1610
        ap_destroy_sub_req(pa_req);
 
1611
    }
 
1612
 
 
1613
    if (r->args) {
 
1614
        char *arg_copy = apr_pstrdup(r->pool, r->args);
 
1615
 
 
1616
        apr_table_setn(e, "QUERY_STRING", r->args);
 
1617
        ap_unescape_url(arg_copy);
 
1618
        apr_table_setn(e, "QUERY_STRING_UNESCAPED", ap_escape_shell_cmd(r->pool, arg_copy));
 
1619
    }
 
1620
}
 
1621
 
 
1622
static int include_cmd(include_ctx_t *ctx, ap_filter_t *f,
 
1623
                       apr_bucket_brigade *bb, char *command)
 
1624
{
 
1625
    char **env;
 
1626
    int sd;
 
1627
    int retval;
 
1628
    apr_file_t *tempsock = NULL;
 
1629
    request_rec *r = f->r;
 
1630
    cgid_server_conf *conf = ap_get_module_config(r->server->module_config,
 
1631
                                                  &cgid_module);
 
1632
    struct cleanup_script_info *info;
 
1633
 
 
1634
    add_ssi_vars(r);
 
1635
    env = ap_create_environment(r->pool, r->subprocess_env);
 
1636
 
 
1637
    if ((retval = connect_to_daemon(&sd, r, conf)) != OK) {
 
1638
        return retval;
 
1639
    }
 
1640
 
 
1641
    send_req(sd, r, command, env, SSI_REQ);
 
1642
 
 
1643
    info = apr_palloc(r->pool, sizeof(struct cleanup_script_info));
 
1644
    info->r = r;
 
1645
    info->conn_id = r->connection->id;
 
1646
    info->conf = conf;
 
1647
    /* for this type of request, the script is invoked through an
 
1648
     * intermediate shell process...  cleanup_script is only able
 
1649
     * to knock out the shell process, not the actual script
 
1650
     */
 
1651
    apr_pool_cleanup_register(r->pool, info,
 
1652
                              cleanup_script,
 
1653
                              apr_pool_cleanup_null);
 
1654
 
 
1655
    /* We are putting the socket discriptor into an apr_file_t so that we can
 
1656
     * use a pipe bucket to send the data to the client.  APR will create
 
1657
     * a cleanup for the apr_file_t which will close the socket, so we'll
 
1658
     * get rid of the cleanup we registered when we created the socket.
 
1659
     */
 
1660
    apr_os_pipe_put_ex(&tempsock, &sd, 1, r->pool);
 
1661
    apr_pool_cleanup_kill(r->pool, (void *)((long)sd), close_unix_socket);
 
1662
 
 
1663
    APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_pipe_create(tempsock,
 
1664
                            f->c->bucket_alloc));
 
1665
    ctx->flush_now = 1;
 
1666
 
 
1667
    return APR_SUCCESS;
 
1668
}
 
1669
 
 
1670
static apr_status_t handle_exec(include_ctx_t *ctx, ap_filter_t *f,
 
1671
                                apr_bucket_brigade *bb)
 
1672
{
 
1673
    char *tag     = NULL;
 
1674
    char *tag_val = NULL;
 
1675
    request_rec *r = f->r;
 
1676
    char *file = r->filename;
 
1677
    char parsed_string[MAX_STRING_LEN];
 
1678
 
 
1679
    if (!ctx->argc) {
 
1680
        ap_log_rerror(APLOG_MARK,
 
1681
                      (ctx->flags & SSI_FLAG_PRINTING)
 
1682
                          ? APLOG_ERR : APLOG_WARNING,
 
1683
                      0, r, "missing argument for exec element in %s",
 
1684
                      r->filename);
 
1685
    }
 
1686
 
 
1687
    if (!(ctx->flags & SSI_FLAG_PRINTING)) {
 
1688
        return APR_SUCCESS;
 
1689
    }
 
1690
 
 
1691
    if (!ctx->argc) {
 
1692
        SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
 
1693
        return APR_SUCCESS;
 
1694
    }
 
1695
 
 
1696
    if (ctx->flags & SSI_FLAG_NO_EXEC) {
 
1697
        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "exec used but not allowed "
 
1698
                      "in %s", r->filename);
 
1699
        SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
 
1700
        return APR_SUCCESS;
 
1701
    }
 
1702
 
 
1703
    while (1) {
 
1704
        cgid_pfn_gtv(ctx, &tag, &tag_val, SSI_VALUE_DECODED);
 
1705
        if (!tag || !tag_val) {
 
1706
            break;
 
1707
        }
 
1708
 
 
1709
        if (!strcmp(tag, "cmd")) {
 
1710
            apr_status_t rv;
 
1711
 
 
1712
            cgid_pfn_ps(ctx, tag_val, parsed_string, sizeof(parsed_string),
 
1713
                        SSI_EXPAND_LEAVE_NAME);
 
1714
 
 
1715
            rv = include_cmd(ctx, f, bb, parsed_string);
 
1716
            if (rv != APR_SUCCESS) {
 
1717
                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
 
1718
                              "execution failure for parameter \"%s\" "
 
1719
                              "to tag exec in file %s", tag, r->filename);
 
1720
                SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
 
1721
                break;
 
1722
            }
 
1723
        }
 
1724
        else if (!strcmp(tag, "cgi")) {
 
1725
            apr_status_t rv;
 
1726
 
 
1727
            cgid_pfn_ps(ctx, tag_val, parsed_string, sizeof(parsed_string),
 
1728
                        SSI_EXPAND_DROP_NAME);
 
1729
 
 
1730
            rv = include_cgi(ctx, f, bb, parsed_string);
 
1731
            if (rv != APR_SUCCESS) {
 
1732
                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "invalid CGI ref "
 
1733
                              "\"%s\" in %s", tag_val, file);
 
1734
                SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
 
1735
                break;
 
1736
            }
 
1737
        }
 
1738
        else {
 
1739
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "unknown parameter "
 
1740
                          "\"%s\" to tag exec in %s", tag, file);
 
1741
            SSI_CREATE_ERROR_BUCKET(ctx, f, bb);
 
1742
            break;
 
1743
        }
 
1744
    }
 
1745
 
 
1746
    return APR_SUCCESS;
 
1747
}
 
1748
/*============================================================================
 
1749
 *============================================================================
 
1750
 * This is the end of the cgi filter code moved from mod_include.
 
1751
 *============================================================================
 
1752
 *============================================================================*/
 
1753
 
 
1754
 
 
1755
static void register_hook(apr_pool_t *p)
 
1756
{
 
1757
    static const char * const aszPre[] = { "mod_include.c", NULL };
 
1758
 
 
1759
    ap_hook_pre_config(cgid_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
 
1760
    ap_hook_post_config(cgid_init, aszPre, NULL, APR_HOOK_MIDDLE);
 
1761
    ap_hook_handler(cgid_handler, NULL, NULL, APR_HOOK_MIDDLE);
 
1762
}
 
1763
 
 
1764
module AP_MODULE_DECLARE_DATA cgid_module = {
 
1765
    STANDARD20_MODULE_STUFF,
 
1766
    NULL, /* dir config creater */
 
1767
    NULL, /* dir merger --- default is to override */
 
1768
    create_cgid_config, /* server config */
 
1769
    merge_cgid_config, /* merge server config */
 
1770
    cgid_cmds, /* command table */
 
1771
    register_hook /* register_handlers */
 
1772
};
 
1773