Coverage Report

Created: 2023-03-26 06:28

/src/httpd/srclib/apr/threadproc/unix/proc.c
Line
Count
Source (jump to first uncovered line)
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
#include "apr_arch_threadproc.h"
18
#include "apr_strings.h"
19
#include "apr_portable.h"
20
#include "apr_signal.h"
21
#include "apr_random.h"
22
#include "apr_crypto.h"
23
24
/* Heavy on no'ops, here's what we want to pass if there is APR_NO_FILE
25
 * requested for a specific child handle;
26
 */
27
static apr_file_t no_file = { NULL, -1, };
28
29
APR_DECLARE(apr_status_t) apr_procattr_create(apr_procattr_t **new,
30
                                              apr_pool_t *pool)
31
0
{
32
0
    (*new) = (apr_procattr_t *)apr_pcalloc(pool, sizeof(apr_procattr_t));
33
34
0
    if ((*new) == NULL) {
35
0
        return APR_ENOMEM;
36
0
    }
37
0
    (*new)->pool = pool;
38
0
    (*new)->cmdtype = APR_PROGRAM;
39
0
    (*new)->uid = (*new)->gid = -1;
40
0
    return APR_SUCCESS;
41
0
}
42
43
APR_DECLARE(apr_status_t) apr_procattr_io_set(apr_procattr_t *attr,
44
                                              apr_int32_t in,
45
                                              apr_int32_t out,
46
                                              apr_int32_t err)
47
0
{
48
0
    apr_status_t rv;
49
50
0
    if ((in != APR_NO_PIPE) && (in != APR_NO_FILE)) {
51
        /* APR_CHILD_BLOCK maps to APR_WRITE_BLOCK, while
52
         * APR_PARENT_BLOCK maps to APR_READ_BLOCK, so transpose
53
         * the CHILD/PARENT blocking flags for the stdin pipe.
54
         * stdout/stderr map to the correct mode by default.
55
         */
56
0
        if (in == APR_CHILD_BLOCK)
57
0
            in = APR_READ_BLOCK;
58
0
        else if (in == APR_PARENT_BLOCK)
59
0
            in = APR_WRITE_BLOCK;
60
61
0
        if ((rv = apr_file_pipe_create_ex(&attr->child_in, &attr->parent_in,
62
0
                                          in, attr->pool)) == APR_SUCCESS)
63
0
            rv = apr_file_inherit_unset(attr->parent_in);
64
0
        if (rv != APR_SUCCESS)
65
0
            return rv;
66
0
    }
67
0
    else if (in == APR_NO_FILE)
68
0
        attr->child_in = &no_file;
69
70
0
    if ((out != APR_NO_PIPE) && (out != APR_NO_FILE)) {
71
0
        if ((rv = apr_file_pipe_create_ex(&attr->parent_out, &attr->child_out,
72
0
                                          out, attr->pool)) == APR_SUCCESS)
73
0
            rv = apr_file_inherit_unset(attr->parent_out);
74
0
        if (rv != APR_SUCCESS)
75
0
            return rv;
76
0
    }
77
0
    else if (out == APR_NO_FILE)
78
0
        attr->child_out = &no_file;
79
80
0
    if ((err != APR_NO_PIPE) && (err != APR_NO_FILE)) {
81
0
        if ((rv = apr_file_pipe_create_ex(&attr->parent_err, &attr->child_err,
82
0
                                          err, attr->pool)) == APR_SUCCESS)
83
0
            rv = apr_file_inherit_unset(attr->parent_err);
84
0
        if (rv != APR_SUCCESS)
85
0
            return rv;
86
0
    }
87
0
    else if (err == APR_NO_FILE)
88
0
        attr->child_err = &no_file;
89
90
0
    return APR_SUCCESS;
91
0
}
92
93
94
APR_DECLARE(apr_status_t) apr_procattr_child_in_set(apr_procattr_t *attr,
95
                                                    apr_file_t *child_in,
96
                                                    apr_file_t *parent_in)
97
0
{
98
0
    apr_status_t rv = APR_SUCCESS;
99
100
0
    if (attr->child_in == NULL && attr->parent_in == NULL
101
0
           && child_in == NULL && parent_in == NULL)
102
0
        if ((rv = apr_file_pipe_create(&attr->child_in, &attr->parent_in,
103
0
                                       attr->pool)) == APR_SUCCESS)
104
0
            rv = apr_file_inherit_unset(attr->parent_in);
105
106
0
    if (child_in != NULL && rv == APR_SUCCESS) {
107
0
        if (attr->child_in && (attr->child_in->filedes != -1))
108
0
            rv = apr_file_dup2(attr->child_in, child_in, attr->pool);
109
0
        else {
110
0
            attr->child_in = NULL;
111
0
            if ((rv = apr_file_dup(&attr->child_in, child_in, attr->pool))
112
0
                    == APR_SUCCESS)
113
0
                rv = apr_file_inherit_set(attr->child_in);
114
0
        }
115
0
    }
116
117
0
    if (parent_in != NULL && rv == APR_SUCCESS) {
118
0
        if (attr->parent_in)
119
0
            rv = apr_file_dup2(attr->parent_in, parent_in, attr->pool);
120
0
        else
121
0
            rv = apr_file_dup(&attr->parent_in, parent_in, attr->pool);
122
0
    }
123
124
0
    return rv;
125
0
}
126
127
128
APR_DECLARE(apr_status_t) apr_procattr_child_out_set(apr_procattr_t *attr,
129
                                                     apr_file_t *child_out,
130
                                                     apr_file_t *parent_out)
131
0
{
132
0
    apr_status_t rv = APR_SUCCESS;
133
134
0
    if (attr->child_out == NULL && attr->parent_out == NULL
135
0
           && child_out == NULL && parent_out == NULL)
136
0
        if ((rv = apr_file_pipe_create(&attr->parent_out, &attr->child_out,
137
0
                                       attr->pool)) == APR_SUCCESS)
138
0
            rv = apr_file_inherit_unset(attr->parent_out);
139
140
0
    if (child_out != NULL && rv == APR_SUCCESS) {
141
0
        if (attr->child_out && (attr->child_out->filedes != -1))
142
0
            rv = apr_file_dup2(attr->child_out, child_out, attr->pool);
143
0
        else {
144
0
            attr->child_out = NULL;
145
0
            if ((rv = apr_file_dup(&attr->child_out, child_out, attr->pool))
146
0
                    == APR_SUCCESS)
147
0
                rv = apr_file_inherit_set(attr->child_out);
148
0
        }
149
0
    }
150
151
0
    if (parent_out != NULL && rv == APR_SUCCESS) {
152
0
        if (attr->parent_out)
153
0
            rv = apr_file_dup2(attr->parent_out, parent_out, attr->pool);
154
0
        else
155
0
            rv = apr_file_dup(&attr->parent_out, parent_out, attr->pool);
156
0
    }
157
158
0
    return rv;
159
0
}
160
161
162
APR_DECLARE(apr_status_t) apr_procattr_child_err_set(apr_procattr_t *attr,
163
                                                     apr_file_t *child_err,
164
                                                     apr_file_t *parent_err)
165
0
{
166
0
    apr_status_t rv = APR_SUCCESS;
167
168
0
    if (attr->child_err == NULL && attr->parent_err == NULL
169
0
           && child_err == NULL && parent_err == NULL)
170
0
        if ((rv = apr_file_pipe_create(&attr->parent_err, &attr->child_err,
171
0
                                      attr->pool)) == APR_SUCCESS)
172
0
            rv = apr_file_inherit_unset(attr->parent_err);
173
174
0
    if (child_err != NULL && rv == APR_SUCCESS) {
175
0
        if (attr->child_err && (attr->child_err->filedes != -1))
176
0
            rv = apr_file_dup2(attr->child_err, child_err, attr->pool);
177
0
        else {
178
0
            attr->child_err = NULL;
179
0
            if ((rv = apr_file_dup(&attr->child_err, child_err, attr->pool))
180
0
                    == APR_SUCCESS)
181
0
                rv = apr_file_inherit_set(attr->child_err);
182
0
        }
183
0
    }
184
0
    if (parent_err != NULL && rv == APR_SUCCESS) {
185
0
        if (attr->parent_err)
186
0
            rv = apr_file_dup2(attr->parent_err, parent_err, attr->pool);
187
0
        else
188
0
            rv = apr_file_dup(&attr->parent_err, parent_err, attr->pool);
189
0
    }
190
191
0
    return rv;
192
0
}
193
194
195
APR_DECLARE(apr_status_t) apr_procattr_dir_set(apr_procattr_t *attr,
196
                                               const char *dir)
197
0
{
198
0
    attr->currdir = apr_pstrdup(attr->pool, dir);
199
0
    if (attr->currdir) {
200
0
        return APR_SUCCESS;
201
0
    }
202
203
0
    return APR_ENOMEM;
204
0
}
205
206
APR_DECLARE(apr_status_t) apr_procattr_cmdtype_set(apr_procattr_t *attr,
207
                                                   apr_cmdtype_e cmd)
208
0
{
209
0
    attr->cmdtype = cmd;
210
0
    return APR_SUCCESS;
211
0
}
212
213
APR_DECLARE(apr_status_t) apr_procattr_detach_set(apr_procattr_t *attr,
214
                                                  apr_int32_t detach)
215
0
{
216
0
    attr->detached = detach;
217
0
    return APR_SUCCESS;
218
0
}
219
220
APR_DECLARE(apr_status_t) apr_proc_fork(apr_proc_t *proc, apr_pool_t *pool)
221
0
{
222
0
    int pid;
223
224
0
    memset(proc, 0, sizeof(apr_proc_t));
225
226
    /* Rekey PRNG(s) to clear buffer(s) and make sure that the
227
     * state(s) change between fork()s in any case.
228
     */
229
#if APU_HAVE_CRYPTO_PRNG
230
    apr_crypto_prng_rekey(NULL);
231
#endif
232
233
0
    if ((pid = fork()) < 0) {
234
0
        return errno;
235
0
    }
236
0
    else if (pid == 0) {
237
0
#if APR_HAS_THREAD_LOCAL
238
0
        apr_thread_current_after_fork();
239
0
#endif
240
0
        proc->pid = getpid();
241
242
        /* Do the work needed for children PRNG(s). */
243
#if APU_HAVE_CRYPTO_PRNG
244
        apr_crypto_prng_after_fork(NULL, APR_CRYPTO_FORK_INCHILD);
245
#endif
246
0
        apr_random_after_fork(proc);
247
248
0
        return APR_INCHILD;
249
0
    }
250
251
0
    proc->pid = pid;
252
253
    /* Do the work needed for parent PRNG(s). */
254
#if APU_HAVE_CRYPTO_PRNG
255
    apr_crypto_prng_after_fork(NULL, APR_CRYPTO_FORK_INPARENT);
256
#endif
257
258
0
    return APR_INPARENT;
259
0
}
260
261
static apr_status_t limit_proc(apr_procattr_t *attr)
262
0
{
263
0
#if APR_HAVE_STRUCT_RLIMIT && APR_HAVE_SETRLIMIT
264
0
#ifdef RLIMIT_CPU
265
0
    if (attr->limit_cpu != NULL) {
266
0
        if ((setrlimit(RLIMIT_CPU, attr->limit_cpu)) != 0) {
267
0
            return errno;
268
0
        }
269
0
    }
270
0
#endif
271
0
#ifdef RLIMIT_NPROC
272
0
    if (attr->limit_nproc != NULL) {
273
0
        if ((setrlimit(RLIMIT_NPROC, attr->limit_nproc)) != 0) {
274
0
            return errno;
275
0
        }
276
0
    }
277
0
#endif
278
0
#ifdef RLIMIT_NOFILE
279
0
    if (attr->limit_nofile != NULL) {
280
0
        if ((setrlimit(RLIMIT_NOFILE, attr->limit_nofile)) != 0) {
281
0
            return errno;
282
0
        }
283
0
    }
284
0
#endif
285
0
#if defined(RLIMIT_AS)
286
0
    if (attr->limit_mem != NULL) {
287
0
        if ((setrlimit(RLIMIT_AS, attr->limit_mem)) != 0) {
288
0
            return errno;
289
0
        }
290
0
    }
291
#elif defined(RLIMIT_DATA)
292
    if (attr->limit_mem != NULL) {
293
        if ((setrlimit(RLIMIT_DATA, attr->limit_mem)) != 0) {
294
            return errno;
295
        }
296
    }
297
#elif defined(RLIMIT_VMEM)
298
    if (attr->limit_mem != NULL) {
299
        if ((setrlimit(RLIMIT_VMEM, attr->limit_mem)) != 0) {
300
            return errno;
301
        }
302
    }
303
#endif
304
#else
305
    /*
306
     * Maybe make a note in error_log that setrlimit isn't supported??
307
     */
308
309
#endif
310
0
    return APR_SUCCESS;
311
0
}
312
313
APR_DECLARE(apr_status_t) apr_procattr_child_errfn_set(apr_procattr_t *attr,
314
                                                       apr_child_errfn_t *errfn)
315
0
{
316
0
    attr->errfn = errfn;
317
0
    return APR_SUCCESS;
318
0
}
319
320
APR_DECLARE(apr_status_t) apr_procattr_error_check_set(apr_procattr_t *attr,
321
                                                       apr_int32_t chk)
322
0
{
323
0
    attr->errchk = chk;
324
0
    return APR_SUCCESS;
325
0
}
326
327
APR_DECLARE(apr_status_t) apr_procattr_addrspace_set(apr_procattr_t *attr,
328
                                                       apr_int32_t addrspace)
329
0
{
330
    /* won't ever be used on this platform, so don't save the flag */
331
0
    return APR_SUCCESS;
332
0
}
333
334
APR_DECLARE(apr_status_t) apr_procattr_user_set(apr_procattr_t *attr,
335
                                                const char *username,
336
                                                const char *password)
337
0
{
338
0
    apr_status_t rv;
339
0
    apr_gid_t    gid;
340
341
0
    if ((rv = apr_uid_get(&attr->uid, &gid, username,
342
0
                          attr->pool)) != APR_SUCCESS) {
343
0
        attr->uid = -1;
344
0
        return rv;
345
0
    }
346
347
    /* Use default user group if not already set */
348
0
    if (attr->gid == -1) {
349
0
        attr->gid = gid;
350
0
    }
351
0
    return APR_SUCCESS;
352
0
}
353
354
APR_DECLARE(apr_status_t) apr_procattr_group_set(apr_procattr_t *attr,
355
                                                 const char *groupname)
356
0
{
357
0
    apr_status_t rv;
358
359
0
    if ((rv = apr_gid_get(&attr->gid, groupname, attr->pool)) != APR_SUCCESS)
360
0
        attr->gid = -1;
361
0
    return rv;
362
0
}
363
364
APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *new,
365
                                          const char *progname,
366
                                          const char * const *args,
367
                                          const char * const *env,
368
                                          apr_procattr_t *attr,
369
                                          apr_pool_t *pool)
370
0
{
371
0
    int i;
372
0
    const char * const empty_envp[] = {NULL};
373
374
0
    if (!env) { /* Specs require an empty array instead of NULL;
375
                 * Purify will trigger a failure, even if many
376
                 * implementations don't.
377
                 */
378
0
        env = empty_envp;
379
0
    }
380
381
0
    new->in = attr->parent_in;
382
0
    new->err = attr->parent_err;
383
0
    new->out = attr->parent_out;
384
385
0
    if (attr->errchk) {
386
0
        if (attr->currdir) {
387
0
            if (access(attr->currdir, X_OK) == -1) {
388
                /* chdir() in child wouldn't have worked */
389
0
                return errno;
390
0
            }
391
0
        }
392
393
0
        if (attr->cmdtype == APR_PROGRAM ||
394
0
            attr->cmdtype == APR_PROGRAM_ENV ||
395
0
            *progname == '/') {
396
            /* for both of these values of cmdtype, caller must pass
397
             * full path, so it is easy to check;
398
             * caller can choose to pass full path for other
399
             * values of cmdtype
400
             */
401
0
            if (access(progname, X_OK) == -1) {
402
                /* exec*() in child wouldn't have worked */
403
0
                return errno;
404
0
            }
405
0
        }
406
0
        else {
407
            /* todo: search PATH for progname then try to access it */
408
0
        }
409
0
    }
410
411
0
    if ((new->pid = fork()) < 0) {
412
0
        return errno;
413
0
    }
414
0
    else if (new->pid == 0) {
415
        /* child process */
416
417
        /*
418
         * If we do exec cleanup before the dup2() calls to set up pipes
419
         * on 0-2, we accidentally close the pipes used by programs like
420
         * mod_cgid.
421
         *
422
         * If we do exec cleanup after the dup2() calls, cleanup can accidentally
423
         * close our pipes which replaced any files which previously had
424
         * descriptors 0-2.
425
         *
426
         * The solution is to kill the cleanup for the pipes, then do
427
         * exec cleanup, then do the dup2() calls.
428
         */
429
430
0
        if (attr->child_in) {
431
0
            apr_pool_cleanup_kill(apr_file_pool_get(attr->child_in),
432
0
                                  attr->child_in, apr_unix_file_cleanup);
433
0
        }
434
435
0
        if (attr->child_out) {
436
0
            apr_pool_cleanup_kill(apr_file_pool_get(attr->child_out),
437
0
                                  attr->child_out, apr_unix_file_cleanup);
438
0
        }
439
440
0
        if (attr->child_err) {
441
0
            apr_pool_cleanup_kill(apr_file_pool_get(attr->child_err),
442
0
                                  attr->child_err, apr_unix_file_cleanup);
443
0
        }
444
445
0
        apr_pool_cleanup_for_exec();
446
447
0
        if ((attr->child_in) && (attr->child_in->filedes == -1)) {
448
0
            close(STDIN_FILENO);
449
0
        }
450
0
        else if (attr->child_in &&
451
0
                 attr->child_in->filedes != STDIN_FILENO) {
452
0
            dup2(attr->child_in->filedes, STDIN_FILENO);
453
0
            apr_file_close(attr->child_in);
454
0
        }
455
456
0
        if ((attr->child_out) && (attr->child_out->filedes == -1)) {
457
0
            close(STDOUT_FILENO);
458
0
        }
459
0
        else if (attr->child_out &&
460
0
                 attr->child_out->filedes != STDOUT_FILENO) {
461
0
            dup2(attr->child_out->filedes, STDOUT_FILENO);
462
0
            apr_file_close(attr->child_out);
463
0
        }
464
465
0
        if ((attr->child_err) && (attr->child_err->filedes == -1)) {
466
0
            close(STDERR_FILENO);
467
0
        }
468
0
        else if (attr->child_err &&
469
0
                 attr->child_err->filedes != STDERR_FILENO) {
470
0
            dup2(attr->child_err->filedes, STDERR_FILENO);
471
0
            apr_file_close(attr->child_err);
472
0
        }
473
474
0
        apr_signal(SIGCHLD, SIG_DFL); /* not sure if this is needed or not */
475
476
0
        if (attr->currdir != NULL) {
477
0
            if (chdir(attr->currdir) == -1) {
478
0
                if (attr->errfn) {
479
0
                    attr->errfn(pool, errno, "change of working directory failed");
480
0
                }
481
0
                _exit(-1);   /* We have big problems, the child should exit. */
482
0
            }
483
0
        }
484
0
        if (!geteuid()) {
485
0
            apr_procattr_pscb_t *c = attr->perms_set_callbacks;
486
487
0
            while (c) {
488
0
                apr_status_t r;
489
0
                r = (*c->perms_set_fn)((void *)c->data, c->perms,
490
0
                                       attr->uid, attr->gid);
491
0
                if (r != APR_SUCCESS && r != APR_ENOTIMPL) {
492
0
                    _exit(-1);
493
0
                }
494
0
                c = c->next;
495
0
            }
496
0
        }
497
        /* Only try to switch if we are running as root */
498
0
        if (attr->gid != -1 && !geteuid()) {
499
0
            if (setgid(attr->gid)) {
500
0
                if (attr->errfn) {
501
0
                    attr->errfn(pool, errno, "setting of group failed");
502
0
                }
503
0
                _exit(-1);   /* We have big problems, the child should exit. */
504
0
            }
505
0
        }
506
507
0
        if (attr->uid != -1 && !geteuid()) {
508
0
            if (setuid(attr->uid)) {
509
0
                if (attr->errfn) {
510
0
                    attr->errfn(pool, errno, "setting of user failed");
511
0
                }
512
0
                _exit(-1);   /* We have big problems, the child should exit. */
513
0
            }
514
0
        }
515
516
0
        if (limit_proc(attr) != APR_SUCCESS) {
517
0
            if (attr->errfn) {
518
0
                attr->errfn(pool, errno, "setting of resource limits failed");
519
0
            }
520
0
            _exit(-1);   /* We have big problems, the child should exit. */
521
0
        }
522
523
0
        if (attr->cmdtype == APR_SHELLCMD ||
524
0
            attr->cmdtype == APR_SHELLCMD_ENV) {
525
0
            int onearg_len = 0;
526
0
            const char *newargs[4];
527
528
0
            newargs[0] = SHELL_PATH;
529
0
            newargs[1] = "-c";
530
531
0
            i = 0;
532
0
            while (args[i]) {
533
0
                onearg_len += strlen(args[i]);
534
0
                onearg_len++; /* for space delimiter */
535
0
                i++;
536
0
            }
537
538
0
            switch(i) {
539
0
            case 0:
540
                /* bad parameters; we're doomed */
541
0
                break;
542
0
            case 1:
543
                /* no args, or caller already built a single string from
544
                 * progname and args
545
                 */
546
0
                newargs[2] = args[0];
547
0
                break;
548
0
            default:
549
0
            {
550
0
                char *ch, *onearg;
551
552
0
                ch = onearg = apr_palloc(pool, onearg_len);
553
0
                i = 0;
554
0
                while (args[i]) {
555
0
                    size_t len = strlen(args[i]);
556
557
0
                    memcpy(ch, args[i], len);
558
0
                    ch += len;
559
0
                    *ch = ' ';
560
0
                    ++ch;
561
0
                    ++i;
562
0
                }
563
0
                --ch; /* back up to trailing blank */
564
0
                *ch = '\0';
565
0
                newargs[2] = onearg;
566
0
            }
567
0
            }
568
569
0
            newargs[3] = NULL;
570
571
0
            if (attr->detached) {
572
0
                apr_proc_detach(APR_PROC_DETACH_DAEMONIZE);
573
0
            }
574
575
0
            if (attr->cmdtype == APR_SHELLCMD) {
576
0
                execve(SHELL_PATH, (char * const *) newargs, (char * const *)env);
577
0
            }
578
0
            else {
579
0
                execv(SHELL_PATH, (char * const *)newargs);
580
0
            }
581
0
        }
582
0
        else if (attr->cmdtype == APR_PROGRAM) {
583
0
            if (attr->detached) {
584
0
                apr_proc_detach(APR_PROC_DETACH_DAEMONIZE);
585
0
            }
586
587
0
            execve(progname, (char * const *)args, (char * const *)env);
588
0
        }
589
0
        else if (attr->cmdtype == APR_PROGRAM_ENV) {
590
0
            if (attr->detached) {
591
0
                apr_proc_detach(APR_PROC_DETACH_DAEMONIZE);
592
0
            }
593
594
0
            execv(progname, (char * const *)args);
595
0
        }
596
0
        else {
597
            /* APR_PROGRAM_PATH */
598
0
            if (attr->detached) {
599
0
                apr_proc_detach(APR_PROC_DETACH_DAEMONIZE);
600
0
            }
601
602
0
            execvp(progname, (char * const *)args);
603
0
        }
604
0
        if (attr->errfn) {
605
0
            char *desc;
606
607
0
            desc = apr_psprintf(pool, "exec of '%s' failed",
608
0
                                progname);
609
0
            attr->errfn(pool, errno, desc);
610
0
        }
611
612
0
        _exit(-1);  /* if we get here, there is a problem, so exit with an
613
                     * error code. */
614
0
    }
615
616
    /* Parent process */
617
0
    if (attr->child_in && (attr->child_in->filedes != -1)) {
618
0
        apr_file_close(attr->child_in);
619
0
    }
620
621
0
    if (attr->child_out && (attr->child_out->filedes != -1)) {
622
0
        apr_file_close(attr->child_out);
623
0
    }
624
625
0
    if (attr->child_err && (attr->child_err->filedes != -1)) {
626
0
        apr_file_close(attr->child_err);
627
0
    }
628
629
0
    return APR_SUCCESS;
630
0
}
631
632
APR_DECLARE(apr_status_t) apr_proc_wait_all_procs(apr_proc_t *proc,
633
                                                  int *exitcode,
634
                                                  apr_exit_why_e *exitwhy,
635
                                                  apr_wait_how_e waithow,
636
                                                  apr_pool_t *p)
637
0
{
638
0
    proc->pid = -1;
639
0
    return apr_proc_wait(proc, exitcode, exitwhy, waithow);
640
0
}
641
642
APR_DECLARE(apr_status_t) apr_proc_wait(apr_proc_t *proc,
643
                                        int *exitcode, apr_exit_why_e *exitwhy,
644
                                        apr_wait_how_e waithow)
645
0
{
646
0
    pid_t pstatus;
647
0
    int waitpid_options = WUNTRACED;
648
0
    int exit_int;
649
0
    int ignore;
650
0
    apr_exit_why_e ignorewhy;
651
652
0
    if (exitcode == NULL) {
653
0
        exitcode = &ignore;
654
0
    }
655
656
0
    if (exitwhy == NULL) {
657
0
        exitwhy = &ignorewhy;
658
0
    }
659
660
0
    if (waithow != APR_WAIT) {
661
0
        waitpid_options |= WNOHANG;
662
0
    }
663
664
0
    do {
665
0
        pstatus = waitpid(proc->pid, &exit_int, waitpid_options);
666
0
    } while (pstatus < 0 && errno == EINTR);
667
668
0
    if (pstatus > 0) {
669
0
        proc->pid = pstatus;
670
671
0
        if (WIFEXITED(exit_int)) {
672
0
            *exitwhy = APR_PROC_EXIT;
673
0
            *exitcode = WEXITSTATUS(exit_int);
674
0
        }
675
0
        else if (WIFSIGNALED(exit_int)) {
676
0
            *exitwhy = APR_PROC_SIGNAL;
677
678
0
#ifdef WCOREDUMP
679
0
            if (WCOREDUMP(exit_int)) {
680
0
                *exitwhy |= APR_PROC_SIGNAL_CORE;
681
0
            }
682
0
#endif
683
684
0
            *exitcode = WTERMSIG(exit_int);
685
0
        }
686
0
        else {
687
            /* unexpected condition */
688
0
            return APR_EGENERAL;
689
0
        }
690
691
0
        return APR_CHILD_DONE;
692
0
    }
693
0
    else if (pstatus == 0) {
694
0
        return APR_CHILD_NOTDONE;
695
0
    }
696
697
0
    return errno;
698
0
}
699
700
#if APR_HAVE_STRUCT_RLIMIT
701
APR_DECLARE(apr_status_t) apr_procattr_limit_set(apr_procattr_t *attr,
702
                                                 apr_int32_t what,
703
                                                 struct rlimit *limit)
704
0
{
705
0
    switch(what) {
706
0
        case APR_LIMIT_CPU:
707
0
#ifdef RLIMIT_CPU
708
0
            attr->limit_cpu = limit;
709
0
            break;
710
#else
711
            return APR_ENOTIMPL;
712
#endif
713
714
0
        case APR_LIMIT_MEM:
715
0
#if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS)
716
0
            attr->limit_mem = limit;
717
0
            break;
718
#else
719
            return APR_ENOTIMPL;
720
#endif
721
722
0
        case APR_LIMIT_NPROC:
723
0
#ifdef RLIMIT_NPROC
724
0
            attr->limit_nproc = limit;
725
0
            break;
726
#else
727
            return APR_ENOTIMPL;
728
#endif
729
730
0
        case APR_LIMIT_NOFILE:
731
0
#ifdef RLIMIT_NOFILE
732
0
            attr->limit_nofile = limit;
733
0
            break;
734
#else
735
            return APR_ENOTIMPL;
736
#endif
737
738
0
    }
739
740
0
    return APR_SUCCESS;
741
0
}
742
#endif /* APR_HAVE_STRUCT_RLIMIT */
743
744
APR_DECLARE(apr_status_t) apr_procattr_perms_set_register(apr_procattr_t *attr,
745
                                                 apr_perms_setfn_t *perms_set_fn,
746
                                                 void *data,
747
                                                 apr_fileperms_t perms)
748
0
{
749
0
    apr_procattr_pscb_t *c;
750
751
0
    c = apr_palloc(attr->pool, sizeof(apr_procattr_pscb_t));
752
0
    c->data = data;
753
0
    c->perms = perms;
754
0
    c->perms_set_fn = perms_set_fn;
755
0
    c->next = attr->perms_set_callbacks;
756
0
    attr->perms_set_callbacks = c;
757
758
0
    return APR_SUCCESS;
759
0
}