]> granicus.if.org Git - apache/blob - os/unix/unixd.c
detach, set_group_privs, and such... these will be common amongst the
[apache] / os / unix / unixd.c
1 /* ====================================================================
2  * Copyright (c) 1998-1999 The Apache Group.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer. 
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in
13  *    the documentation and/or other materials provided with the
14  *    distribution.
15  *
16  * 3. All advertising materials mentioning features or use of this
17  *    software must display the following acknowledgment:
18  *    "This product includes software developed by the Apache Group
19  *    for use in the Apache HTTP server project (http://www.apache.org/)."
20  *
21  * 4. The names "Apache Server" and "Apache Group" must not be used to
22  *    endorse or promote products derived from this software without
23  *    prior written permission. For written permission, please contact
24  *    apache@apache.org.
25  *
26  * 5. Products derived from this software may not be called "Apache"
27  *    nor may "Apache" appear in their names without prior written
28  *    permission of the Apache Group.
29  *
30  * 6. Redistributions of any form whatsoever must retain the following
31  *    acknowledgment:
32  *    "This product includes software developed by the Apache Group
33  *    for use in the Apache HTTP server project (http://www.apache.org/)."
34  *
35  * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
36  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
38  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
39  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
41  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
42  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
44  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
45  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
46  * OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Apache Group and was originally based
51  * on public domain software written at the National Center for
52  * Supercomputing Applications, University of Illinois, Urbana-Champaign.
53  * For more information on the Apache Group and the Apache HTTP server
54  * project, please see <http://www.apache.org/>.
55  *
56  */
57
58 #include "httpd.h"
59 #include "http_config.h"
60 #include "http_main.h"
61 #include "http_log.h"
62 #include "unixd.h"
63
64 unixd_config_rec unixd_config;
65
66 void unixd_detach(void)
67 {
68     int x;
69     pid_t pgrp;
70
71     chdir("/");
72 #if !defined(MPE) && !defined(OS2) && !defined(TPF)
73 /* Don't detach for MPE because child processes can't survive the death of
74    the parent. */
75     if ((x = fork()) > 0)
76         exit(0);
77     else if (x == -1) {
78         perror("fork");
79         fprintf(stderr, "%s: unable to fork new process\n", ap_server_argv0);
80         exit(1);
81     }
82     RAISE_SIGSTOP(DETACH);
83 #endif
84 #ifndef NO_SETSID
85     if ((pgrp = setsid()) == -1) {
86         perror("setsid");
87         fprintf(stderr, "%s: setsid failed\n", ap_server_argv0);
88         exit(1);
89     }
90 #elif defined(NEXT) || defined(NEWSOS)
91     if (setpgrp(0, getpid()) == -1 || (pgrp = getpgrp(0)) == -1) {
92         perror("setpgrp");
93         fprintf(stderr, "%s: setpgrp or getpgrp failed\n", ap_server_argv0);
94         exit(1);
95     }
96 #elif defined(OS2) || defined(TPF)
97     /* OS/2 and TPF don't support process group IDs */
98     pgrp = getpid();
99 #elif defined(MPE)
100     /* MPE uses negative pid for process group */
101     pgrp = -getpid();
102 #else
103     if ((pgrp = setpgrp(getpid(), 0)) == -1) {
104         perror("setpgrp");
105         fprintf(stderr, "%s: setpgrp failed\n", ap_server_argv0);
106         exit(1);
107     }
108 #endif
109
110     /* close out the standard file descriptors */
111     if (freopen("/dev/null", "r", stdin) == NULL) {
112         fprintf(stderr, "%s: unable to replace stdin with /dev/null: %s\n",
113                 ap_server_argv0, strerror(errno));
114         /* continue anyhow -- note we can't close out descriptor 0 because we
115          * have nothing to replace it with, and if we didn't have a descriptor
116          * 0 the next file would be created with that value ... leading to
117          * havoc.
118          */
119     }
120     if (freopen("/dev/null", "w", stdout) == NULL) {
121         fprintf(stderr, "%s: unable to replace stdout with /dev/null: %s\n",
122                 ap_server_argv0, strerror(errno));
123     }
124     /* stderr is a tricky one, we really want it to be the error_log,
125      * but we haven't opened that yet.  So leave it alone for now and it'll
126      * be reopened moments later.
127      */
128 }
129
130 /* Set group privileges.
131  *
132  * Note that we use the username as set in the config files, rather than
133  * the lookup of to uid --- the same uid may have multiple passwd entries,
134  * with different sets of groups for each.
135  */
136
137 static int set_group_privs(void)
138 {
139     if (!geteuid()) {
140         char *name;
141
142         /* Get username if passed as a uid */
143
144         if (unixd_config.user_name[0] == '#') {
145             struct passwd *ent;
146             uid_t uid = atoi(&unixd_config.user_name[1]);
147
148             if ((ent = getpwuid(uid)) == NULL) {
149                 ap_log_error(APLOG_MARK, APLOG_ALERT, NULL,
150                          "getpwuid: couldn't determine user name from uid %u, "
151                          "you probably need to modify the User directive",
152                          (unsigned)uid);
153                 return -1;
154             }
155
156             name = ent->pw_name;
157         }
158         else
159             name = unixd_config.user_name;
160
161 #if !defined(OS2) && !defined(TPF)
162         /* OS/2 and TPF don't support groups. */
163
164         /*
165          * Set the GID before initgroups(), since on some platforms
166          * setgid() is known to zap the group list.
167          */
168         if (setgid(unixd_config.group_id) == -1) {
169             ap_log_error(APLOG_MARK, APLOG_ALERT, NULL,
170                         "setgid: unable to set group id to Group %u",
171                         (unsigned)unixd_config.group_id);
172             return -1;
173         }
174
175         /* Reset `groups' attributes. */
176
177         if (initgroups(name, unixd_config.group_id) == -1) {
178             ap_log_error(APLOG_MARK, APLOG_ALERT, NULL,
179                         "initgroups: unable to set groups for User %s "
180                         "and Group %u", name, (unsigned)unixd_config.group_id);
181             return -1;
182         }
183 #endif /* !defined(OS2) && !defined(TPF) */
184     }
185     return 0;
186 }
187
188
189 int unixd_setup_child(void)
190 {
191     if (set_group_privs()) {
192         return -1;
193     }
194 #ifdef MPE
195     /* Only try to switch if we're running as MANAGER.SYS */
196     if (geteuid() == 1 && unixd_config.user_id > 1) {
197         GETPRIVMODE();
198         if (setuid(unixd_config.user_id) == -1) {
199             GETUSERMODE();
200             ap_log_error(APLOG_MARK, APLOG_ALERT, NULL,
201                         "setuid: unable to change uid");
202             exit(1);
203         }
204         GETUSERMODE();
205     }
206 #else
207     /* Only try to switch if we're running as root */
208     if (!geteuid() && (
209 #ifdef _OSD_POSIX
210         os_init_job_environment(server_conf, unixd_config.user_name, one_process) != 0 || 
211 #endif
212         setuid(unixd_config.user_id) == -1)) {
213         ap_log_error(APLOG_MARK, APLOG_ALERT, NULL,
214                     "setuid: unable to change uid");
215         return -1;
216     }
217 #endif
218     return 0;
219 }
220
221
222 const char *unixd_set_user(cmd_parms *cmd, void *dummy, char *arg)
223 {
224     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
225     if (err != NULL) {
226         return err;
227     }
228
229     unixd_config.user_name = arg;
230     unixd_config.user_id = ap_uname2id(arg);
231 #if !defined (BIG_SECURITY_HOLE) && !defined (OS2)
232     if (unixd_config.user_id == 0) {
233         return "Error:\tApache has not been designed to serve pages while\n"
234                 "\trunning as root.  There are known race conditions that\n"
235                 "\twill allow any local user to read any file on the system.\n"
236                 "\tIf you still desire to serve pages as root then\n"
237                 "\tadd -DBIG_SECURITY_HOLE to the EXTRA_CFLAGS line in your\n"
238                 "\tsrc/Configuration file and rebuild the server.  It is\n"
239                 "\tstrongly suggested that you instead modify the User\n"
240                 "\tdirective in your httpd.conf file to list a non-root\n"
241                 "\tuser.\n";
242     }
243 #endif
244
245     return NULL;
246 }
247
248 const char *unixd_set_group(cmd_parms *cmd, void *dummy, char *arg)
249 {
250     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
251     if (err != NULL) {
252         return err;
253     }
254
255     unixd_config.group_id = ap_gname2id(arg);
256
257     return NULL;
258 }
259
260 void unixd_pre_config(void)
261 {
262     unixd_config.user_name = DEFAULT_USER;
263     unixd_config.user_id = ap_uname2id(DEFAULT_USER);
264     unixd_config.group_id = ap_gname2id(DEFAULT_GROUP);
265 }