Apache HTTPD
mod_unixd.c
Go to the documentation of this file.
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 "ap_config.h"
18#include "httpd.h"
19#include "http_config.h"
20#include "http_main.h"
21#include "http_log.h"
22#include "http_core.h"
23#include "mpm_common.h"
24#include "os.h"
25#include "ap_mpm.h"
26#include "mod_unixd.h"
27#include "apr_thread_proc.h"
28#include "apr_strings.h"
29#include "apr_portable.h"
30#ifdef HAVE_PWD_H
31#include <pwd.h>
32#endif
33#ifdef HAVE_SYS_RESOURCE_H
34#include <sys/resource.h>
35#endif
36/* XXX */
37#include <sys/stat.h>
38#ifdef HAVE_UNISTD_H
39#include <unistd.h>
40#endif
41#ifdef HAVE_GRP_H
42#include <grp.h>
43#endif
44#ifdef HAVE_STRINGS_H
45#include <strings.h>
46#endif
47#ifdef HAVE_SYS_SEM_H
48#include <sys/sem.h>
49#endif
50#ifdef HAVE_SYS_PRCTL_H
51#include <sys/prctl.h>
52#endif
53
54#ifndef DEFAULT_USER
55#define DEFAULT_USER "#-1"
56#endif
57#ifndef DEFAULT_GROUP
58#define DEFAULT_GROUP "#-1"
59#endif
60
61#if 0
62typedef struct {
63 const char *user_name;
66 const char *chroot_dir;
68#else
69/*
70 * TODO: clean up the separation between this code
71 * and its data structures and unixd.c, as shown
72 * by the fact that we include unixd.h. Create
73 * mod_unixd.h which does what we need and
74 * clean up unixd.h for what it no longer needs
75 */
76#include "unixd.h"
77#endif
78
79
80/* Set group privileges.
81 *
82 * Note that we use the username as set in the config files, rather than
83 * the lookup of to uid --- the same uid may have multiple passwd entries,
84 * with different sets of groups for each.
85 */
86
87static int set_group_privs(void)
88{
89 if (!geteuid()) {
90 const char *name;
91
92 /* Get username if passed as a uid */
93
94 if (ap_unixd_config.user_name[0] == '#') {
95 struct passwd *ent;
96 uid_t uid = atol(&ap_unixd_config.user_name[1]);
97
98 if ((ent = getpwuid(uid)) == NULL) {
100 "getpwuid: couldn't determine user name from uid %ld, "
101 "you probably need to modify the User directive",
102 (long)uid);
103 return -1;
104 }
105
106 name = ent->pw_name;
107 }
108 else
109 name = ap_unixd_config.user_name;
110
111#if !defined(OS2)
112 /* OS/2 doesn't support groups. */
113 /*
114 * Set the GID before initgroups(), since on some platforms
115 * setgid() is known to zap the group list.
116 */
117 if (setgid(ap_unixd_config.group_id) == -1) {
119 "setgid: unable to set group id to Group %ld",
120 (long)ap_unixd_config.group_id);
121 return -1;
122 }
123
124 /* Reset `groups' attributes. */
125
126 if (initgroups(name, ap_unixd_config.group_id) == -1) {
128 "initgroups: unable to set groups for User %s "
129 "and Group %ld", name, (long)ap_unixd_config.group_id);
130 return -1;
131 }
132#endif /* !defined(OS2) */
133 }
134 return 0;
135}
136
137
138static int
140{
141 int rv = set_group_privs();
142
143 if (rv) {
144 return rv;
145 }
146
147 if (NULL != ap_unixd_config.chroot_dir) {
148 if (geteuid()) {
149 rv = errno;
151 "Cannot chroot when not started as root");
152 return rv;
153 }
154
155 if (chdir(ap_unixd_config.chroot_dir) != 0) {
156 rv = errno;
158 "Can't chdir to %s", ap_unixd_config.chroot_dir);
159 return rv;
160 }
161
162 if (chroot(ap_unixd_config.chroot_dir) != 0) {
163 rv = errno;
165 "Can't chroot to %s", ap_unixd_config.chroot_dir);
166 return rv;
167 }
168
169 if (chdir("/") != 0) {
170 rv = errno;
172 "Can't chdir to new root");
173 return rv;
174 }
175 }
176
177 /* Only try to switch if we're running as root */
178 if (!geteuid() && (
181#endif
182 setuid(ap_unixd_config.user_id) == -1)) {
183 rv = errno;
185 "setuid: unable to change to uid: %ld",
186 (long) ap_unixd_config.user_id);
187 return rv;
188 }
189#if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE)
190 /* this applies to Linux 2.4+ */
192 if (prctl(PR_SET_DUMPABLE, 1)) {
193 rv = errno;
195 "set dumpable failed - this child will not coredump"
196 " after software errors");
197 return rv;
198 }
199 }
200#endif
201
202 return OK;
203}
204
205
206static const char *
208 const char *arg)
209{
210 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
211 if (err != NULL) {
212 return err;
213 }
214
215 ap_unixd_config.user_name = arg;
217#if !defined (BIG_SECURITY_HOLE) && !defined (OS2)
218 if (ap_unixd_config.user_id == 0) {
219 return "Error:\tApache has not been designed to serve pages while\n"
220 "\trunning as root. There are known race conditions that\n"
221 "\twill allow any local user to read any file on the system.\n"
222 "\tIf you still desire to serve pages as root then\n"
223 "\tadd -DBIG_SECURITY_HOLE to the CFLAGS env variable\n"
224 "\tand then rebuild the server.\n"
225 "\tIt is strongly suggested that you instead modify the User\n"
226 "\tdirective in your httpd.conf file to list a non-root\n"
227 "\tuser.\n";
228 }
229#endif
230
231 return NULL;
232}
233
234static const char*
236 const char *arg)
237{
238 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
239 if (err != NULL) {
240 return err;
241 }
242
243 ap_unixd_config.group_name = arg;
244 ap_unixd_config.group_id = ap_gname2id(arg);
245
246 return NULL;
247}
248
249static const char*
251 const char *arg)
252{
253 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
254 if (err != NULL) {
255 return err;
256 }
257 if (!ap_is_directory(cmd->pool, arg)) {
258 return "ChrootDir must be a valid directory";
259 }
260
261 ap_unixd_config.chroot_dir = arg;
262 return NULL;
263}
264
265static const char *
267{
268 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
269
270 if (err != NULL) {
271 return err;
272 }
273
274 if (!ap_unixd_config.suexec_enabled && arg) {
275 return apr_pstrcat(cmd->pool, "suEXEC isn't supported: ",
276 ap_unixd_config.suexec_disabled_reason, NULL);
277 }
278
279 if (!arg) {
280 ap_unixd_config.suexec_disabled_reason = "Suexec directive is Off";
281 }
282
283 ap_unixd_config.suexec_enabled = arg;
284 return NULL;
285}
286
287#ifdef AP_SUEXEC_CAPABILITIES
288/* If suexec is using capabilities, don't test for the setuid bit. */
289#define SETUID_TEST(finfo) (1)
290#else
291#define SETUID_TEST(finfo) (finfo.protection & APR_USETID)
292#endif
293
294static int
296 apr_pool_t *ptemp)
297{
299 ap_unixd_config.user_name = DEFAULT_USER;
301 ap_unixd_config.group_name = DEFAULT_GROUP;
303
304 ap_unixd_config.chroot_dir = NULL; /* none */
305
306 /* Check for suexec */
307 ap_unixd_config.suexec_enabled = 0;
309 == APR_SUCCESS) {
310 if (SETUID_TEST(wrapper) && wrapper.user == 0
311 && (access(SUEXEC_BIN, R_OK|X_OK) == 0)) {
312 ap_unixd_config.suexec_enabled = 1;
313 ap_unixd_config.suexec_disabled_reason = "";
314 }
315 else {
316 ap_unixd_config.suexec_disabled_reason =
317 "Invalid owner or file mode for " SUEXEC_BIN;
318 }
319 }
320 else {
321 ap_unixd_config.suexec_disabled_reason =
322 "Missing suexec binary " SUEXEC_BIN;
323 }
324
326 return OK;
327}
328
330{
331 if (set_group_privs()) {
332 return -1;
333 }
334
335 if (NULL != ap_unixd_config.chroot_dir) {
336 if (geteuid()) {
338 "Cannot chroot when not started as root");
339 return -1;
340 }
341 if (chdir(ap_unixd_config.chroot_dir) != 0) {
343 "Can't chdir to %s", ap_unixd_config.chroot_dir);
344 return -1;
345 }
346 if (chroot(ap_unixd_config.chroot_dir) != 0) {
348 "Can't chroot to %s", ap_unixd_config.chroot_dir);
349 return -1;
350 }
351 if (chdir("/") != 0) {
353 "Can't chdir to new root");
354 return -1;
355 }
356 }
357
358 /* Only try to switch if we're running as root */
359 if (!geteuid() && (
362#endif
363 setuid(ap_unixd_config.user_id) == -1)) {
365 "setuid: unable to change to uid: %ld",
366 (long) ap_unixd_config.user_id);
367 return -1;
368 }
369#if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE)
370 /* this applies to Linux 2.4+ */
372 if (prctl(PR_SET_DUMPABLE, 1)) {
374 "set dumpable failed - this child will not coredump"
375 " after software errors");
376 }
377 }
378#endif
379 return 0;
380}
381
383{
385 apr_uid_t uid = ap_unixd_config.user_id;
386 apr_gid_t gid = ap_unixd_config.group_id;
387 char *no_root = "";
388 if (!ap_exists_config_define("DUMP_RUN_CFG"))
389 return;
390 if (geteuid() != 0)
391 no_root = " not_used";
393 apr_file_printf(out, "User: name=\"%s\" id=%lu%s\n",
394 ap_unixd_config.user_name, (unsigned long)uid, no_root);
395 apr_file_printf(out, "Group: name=\"%s\" id=%lu%s\n",
396 ap_unixd_config.group_name, (unsigned long)gid, no_root);
397 if (ap_unixd_config.chroot_dir)
398 apr_file_printf(out, "ChrootDir: \"%s\"%s\n",
399 ap_unixd_config.chroot_dir, no_root);
400}
401
411
412static const command_rec unixd_cmds[] = {
414 "Effective user id for this server"),
416 "Effective group id for this server"),
418 "The directory to chroot(2) into"),
420 "Enable or disable suEXEC support"),
421 {NULL}
422};
423
426 NULL,
427 NULL,
428 NULL,
429 NULL,
432};
433
Symbol export macros and hook functions.
#define AP_DECLARE(type)
Definition ap_config.h:67
Apache Multi-Processing Module library.
APR Portability Routines.
APR Strings library.
APR Thread and Process Library.
static apr_pool_t * pconf
Definition event.c:441
#define AP_INIT_TAKE1(directive, func, mconfig, where, help)
void ap_hook_test_config(ap_HOOK_test_config_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:100
#define AP_DECLARE_MODULE(foo)
#define AP_INIT_FLAG(directive, func, mconfig, where, help)
void ap_hook_pre_config(ap_HOOK_pre_config_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:91
#define OK
Definition httpd.h:456
#define SUEXEC_BIN
Definition httpd.h:156
int ap_exists_config_define(const char *name)
Definition core.c:2896
#define APLOGNO(n)
Definition http_log.h:117
#define ap_log_error
Definition http_log.h:370
#define APLOG_MARK
Definition http_log.h:283
#define APLOG_ALERT
Definition http_log.h:65
void * dummy
Definition http_vhost.h:62
void const char * arg
Definition http_vhost.h:63
int ap_sys_privileges_handlers(int inc)
Definition core.c:5062
int ap_coredumpdir_configured
Definition mpm_common.c:153
void ap_hook_drop_privileges(ap_HOOK_drop_privileges_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition mpm_common.c:94
int initgroups(const char *name, gid_t basegid)
Definition mpm_common.c:267
int ap_unixd_setup_child(void)
Definition mod_unixd.c:329
apr_fileperms_t apr_uid_t uid
apr_fileperms_t apr_uid_t apr_gid_t gid
#define APR_HOOK_FIRST
Definition apr_hooks.h:301
#define APR_HOOK_MIDDLE
Definition apr_hooks.h:303
#define RSRC_CONF
#define STANDARD20_MODULE_STUFF
int ap_is_directory(apr_pool_t *p, const char *name)
Definition util.c:2326
#define GLOBAL_ONLY
const char * ap_check_cmd_context(cmd_parms *cmd, unsigned forbidden)
Definition core.c:1301
apr_size_t size
const char int apr_pool_t * pool
Definition apr_cstr.h:84
#define APR_SUCCESS
Definition apr_errno.h:225
#define APR_FINFO_NORM
const char * s
Definition apr_strings.h:95
apr_int32_t apr_int32_t apr_int32_t err
apr_cmdtype_e cmd
gid_t apr_gid_t
Definition apr_user.h:54
uid_t apr_uid_t
Definition apr_user.h:45
Apache Configuration.
CORE HTTP Daemon.
Apache Logging library.
Command line options.
HTTP Daemon routines.
apr_pool_t * p
Definition md_event.c:32
static apr_file_t * out
Definition mod_info.c:85
return NULL
Definition mod_so.c:359
static const command_rec unixd_cmds[]
Definition mod_unixd.c:412
static const char * unixd_set_user(cmd_parms *cmd, void *dummy, const char *arg)
Definition mod_unixd.c:207
static int unixd_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp)
Definition mod_unixd.c:295
static int set_group_privs(void)
Definition mod_unixd.c:87
#define DEFAULT_GROUP
Definition mod_unixd.c:58
static int unixd_drop_privileges(apr_pool_t *pool, server_rec *s)
Definition mod_unixd.c:139
static const char * unixd_set_suexec(cmd_parms *cmd, void *dummy, int arg)
Definition mod_unixd.c:266
#define DEFAULT_USER
Definition mod_unixd.c:55
static void unixd_hooks(apr_pool_t *pool)
Definition mod_unixd.c:402
static const char * unixd_set_chroot_dir(cmd_parms *cmd, void *dummy, const char *arg)
Definition mod_unixd.c:250
static const char * unixd_set_group(cmd_parms *cmd, void *dummy, const char *arg)
Definition mod_unixd.c:235
#define SETUID_TEST(finfo)
Definition mod_unixd.c:291
static void unixd_dump_config(apr_pool_t *p, server_rec *s)
Definition mod_unixd.c:382
common stuff that unix MPMs will want
Multi-Processing Modules functions.
char * name
A structure to store information for each virtual server.
Definition httpd.h:1322