]> granicus.if.org Git - apache/blob - os/unix/unixd.c
Renamed all MODULE_EXPORT symbols to AP_MODULE_DECLARE and all symbols
[apache] / os / unix / unixd.c
1 /* ====================================================================
2  * The Apache Software License, Version 1.1
3  *
4  * Copyright (c) 2000 The Apache Software Foundation.  All rights
5  * reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in
16  *    the documentation and/or other materials provided with the
17  *    distribution.
18  *
19  * 3. The end-user documentation included with the redistribution,
20  *    if any, must include the following acknowledgment:
21  *       "This product includes software developed by the
22  *        Apache Software Foundation (http://www.apache.org/)."
23  *    Alternately, this acknowledgment may appear in the software itself,
24  *    if and wherever such third-party acknowledgments normally appear.
25  *
26  * 4. The names "Apache" and "Apache Software Foundation" must
27  *    not be used to endorse or promote products derived from this
28  *    software without prior written permission. For written
29  *    permission, please contact apache@apache.org.
30  *
31  * 5. Products derived from this software may not be called "Apache",
32  *    nor may "Apache" appear in their name, without prior written
33  *    permission of the Apache Software Foundation.
34  *
35  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46  * SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Apache Software Foundation.  For more
51  * information on the Apache Software Foundation, please see
52  * <http://www.apache.org/>.
53  *
54  * Portions of this software are based upon public domain software
55  * originally written at the National Center for Supercomputing Applications,
56  * University of Illinois, Urbana-Champaign.
57  */
58
59 #include "ap_config.h"
60 #include "httpd.h"
61 #include "http_config.h"
62 #include "http_main.h"
63 #include "http_log.h"
64 #include "unixd.h"
65 #ifdef HAVE_PWD_H
66 #include <pwd.h>
67 #endif
68 #ifdef HAVE_SYS_RESOURCE_H
69 #include <sys/resource.h>
70 #endif
71 #ifdef HAVE_UNISTD_H
72 #include <unistd.h>
73 #endif
74 #ifdef HAVE_GRP_H
75 #include <grp.h>
76 #endif
77 #ifdef HAVE_STRINGS_H
78 #include <strings.h>
79 #endif
80
81 unixd_config_rec unixd_config;
82
83 /* Set group privileges.
84  *
85  * Note that we use the username as set in the config files, rather than
86  * the lookup of to uid --- the same uid may have multiple passwd entries,
87  * with different sets of groups for each.
88  */
89
90 static int set_group_privs(void)
91 {
92     if (!geteuid()) {
93         const char *name;
94
95         /* Get username if passed as a uid */
96
97         if (unixd_config.user_name[0] == '#') {
98             struct passwd *ent;
99             uid_t uid = atoi(&unixd_config.user_name[1]);
100
101             if ((ent = getpwuid(uid)) == NULL) {
102                 ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
103                          "getpwuid: couldn't determine user name from uid %u, "
104                          "you probably need to modify the User directive",
105                          (unsigned)uid);
106                 return -1;
107             }
108
109             name = ent->pw_name;
110         }
111         else
112             name = unixd_config.user_name;
113
114 #if !defined(OS2) && !defined(TPF)
115         /* OS/2 and TPF don't support groups. */
116
117         /*
118          * Set the GID before initgroups(), since on some platforms
119          * setgid() is known to zap the group list.
120          */
121         if (setgid(unixd_config.group_id) == -1) {
122             ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
123                         "setgid: unable to set group id to Group %u",
124                         (unsigned)unixd_config.group_id);
125             return -1;
126         }
127
128         /* Reset `groups' attributes. */
129
130         if (initgroups(name, unixd_config.group_id) == -1) {
131             ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
132                         "initgroups: unable to set groups for User %s "
133                         "and Group %u", name, (unsigned)unixd_config.group_id);
134             return -1;
135         }
136 #endif /* !defined(OS2) && !defined(TPF) */
137     }
138     return 0;
139 }
140
141
142 int unixd_setup_child(void)
143 {
144     if (set_group_privs()) {
145         return -1;
146     }
147 #ifdef MPE
148     /* Only try to switch if we're running as MANAGER.SYS */
149     if (geteuid() == 1 && unixd_config.user_id > 1) {
150         GETPRIVMODE();
151         if (setuid(unixd_config.user_id) == -1) {
152             GETUSERMODE();
153             ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
154                         "setuid: unable to change to uid: %ld",
155                         (long) unixd_config.user_id);
156             exit(1);
157         }
158         GETUSERMODE();
159     }
160 #else
161     /* Only try to switch if we're running as root */
162     if (!geteuid() && (
163 #ifdef _OSD_POSIX
164         os_init_job_environment(server_conf, unixd_config.user_name, one_process) != 0 || 
165 #endif
166         setuid(unixd_config.user_id) == -1)) {
167         ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
168                     "setuid: unable to change to uid: %ld",
169                     (long) unixd_config.user_id);
170         return -1;
171     }
172 #endif
173     return 0;
174 }
175
176
177 const char *unixd_set_user(cmd_parms *cmd, void *dummy, const char *arg)
178 {
179     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
180     if (err != NULL) {
181         return err;
182     }
183
184     unixd_config.user_name = arg;
185     unixd_config.user_id = ap_uname2id(arg);
186 #if !defined (BIG_SECURITY_HOLE) && !defined (OS2)
187     if (unixd_config.user_id == 0) {
188         return "Error:\tApache has not been designed to serve pages while\n"
189                 "\trunning as root.  There are known race conditions that\n"
190                 "\twill allow any local user to read any file on the system.\n"
191                 "\tIf you still desire to serve pages as root then\n"
192                 "\tadd -DBIG_SECURITY_HOLE to the EXTRA_CFLAGS line in your\n"
193                 "\tsrc/Configuration file and rebuild the server.  It is\n"
194                 "\tstrongly suggested that you instead modify the User\n"
195                 "\tdirective in your httpd.conf file to list a non-root\n"
196                 "\tuser.\n";
197     }
198 #endif
199
200     return NULL;
201 }
202
203 const char *unixd_set_group(cmd_parms *cmd, void *dummy, const char *arg)
204 {
205     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
206     if (err != NULL) {
207         return err;
208     }
209
210     unixd_config.group_id = ap_gname2id(arg);
211
212     return NULL;
213 }
214
215 void unixd_pre_config(void)
216 {
217     unixd_config.user_name = DEFAULT_USER;
218     unixd_config.user_id = ap_uname2id(DEFAULT_USER);
219     unixd_config.group_id = ap_gname2id(DEFAULT_GROUP);
220 }
221
222 #ifdef NEED_AP_SYS_SIGLIST
223
224 const char *ap_sys_siglist[NumSIG];
225
226 #define store_str(array,index,string) \
227 (ap_assert(index < (sizeof(array)/sizeof(array[0]))),array[index]=string)
228
229 void unixd_siglist_init(void)
230 {
231     int sig;
232
233     ap_sys_siglist[0] = "Signal 0";
234 #ifdef SIGHUP
235     store_str(ap_sys_siglist,SIGHUP,"Hangup");
236 #endif
237 #ifdef SIGINT
238     store_str(ap_sys_siglist,SIGINT,"Interrupt");
239 #endif
240 #ifdef SIGQUIT
241     store_str(ap_sys_siglist,SIGQUIT,"Quit");
242 #endif
243 #ifdef SIGILL
244     store_str(ap_sys_siglist,SIGILL,"Illegal instruction");
245 #endif
246 #ifdef SIGTRAP
247     store_str(ap_sys_siglist,SIGTRAP,"Trace/BPT trap");
248 #endif
249 #ifdef SIGIOT
250     store_str(ap_sys_siglist,SIGIOT,"IOT instruction");
251 #endif
252 #ifdef SIGABRT
253     store_str(ap_sys_siglist,SIGABRT,"Abort");
254 #endif
255 #ifdef SIGEMT
256     store_str(ap_sys_siglist,SIGEMT,"Emulator trap");
257 #endif
258 #ifdef SIGFPE
259     store_str(ap_sys_siglist,SIGFPE,"Arithmetic exception");
260 #endif
261 #ifdef SIGKILL
262     store_str(ap_sys_siglist,SIGKILL,"Killed");
263 #endif
264 #ifdef SIGBUS
265     store_str(ap_sys_siglist,SIGBUS,"Bus error");
266 #endif
267 #ifdef SIGSEGV
268     store_str(ap_sys_siglist,SIGSEGV,"Segmentation fault");
269 #endif
270 #ifdef SIGSYS
271     store_str(ap_sys_siglist,SIGSYS,"Bad system call");
272 #endif
273 #ifdef SIGPIPE
274     store_str(ap_sys_siglist,SIGPIPE,"Broken pipe");
275 #endif
276 #ifdef SIGALRM
277     store_str(ap_sys_siglist,SIGALRM,"Alarm clock");
278 #endif
279 #ifdef SIGTERM
280     store_str(ap_sys_siglist,SIGTERM,"Terminated");
281 #endif
282 #ifdef SIGUSR1
283     store_str(ap_sys_siglist,SIGUSR1,"User defined signal 1");
284 #endif
285 #ifdef SIGUSR2
286     store_str(ap_sys_siglist,SIGUSR2,"User defined signal 2");
287 #endif
288 #ifdef SIGCLD
289     store_str(ap_sys_siglist,SIGCLD,"Child status change");
290 #endif
291 #ifdef SIGCHLD
292     store_str(ap_sys_siglist,SIGCHLD,"Child status change");
293 #endif
294 #ifdef SIGPWR
295     store_str(ap_sys_siglist,SIGPWR,"Power-fail restart");
296 #endif
297 #ifdef SIGWINCH
298     store_str(ap_sys_siglist,SIGWINCH,"Window changed");
299 #endif
300 #ifdef SIGURG
301     store_str(ap_sys_siglist,SIGURG,"urgent socket condition");
302 #endif
303 #ifdef SIGPOLL
304     store_str(ap_sys_siglist,SIGPOLL,"Pollable event occurred");
305 #endif
306 #ifdef SIGIO
307     store_str(ap_sys_siglist,SIGIO,"socket I/O possible");
308 #endif
309 #ifdef SIGSTOP
310     store_str(ap_sys_siglist,SIGSTOP,"Stopped (signal)");
311 #endif
312 #ifdef SIGTSTP
313     store_str(ap_sys_siglist,SIGTSTP,"Stopped");
314 #endif
315 #ifdef SIGCONT
316     store_str(ap_sys_siglist,SIGCONT,"Continued");
317 #endif
318 #ifdef SIGTTIN
319     store_str(ap_sys_siglist,SIGTTIN,"Stopped (tty input)");
320 #endif
321 #ifdef SIGTTOU
322     store_str(ap_sys_siglist,SIGTTOU,"Stopped (tty output)");
323 #endif
324 #ifdef SIGVTALRM
325     store_str(ap_sys_siglist,SIGVTALRM,"virtual timer expired");
326 #endif
327 #ifdef SIGPROF
328     store_str(ap_sys_siglist,SIGPROF,"profiling timer expired");
329 #endif
330 #ifdef SIGXCPU
331     store_str(ap_sys_siglist,SIGXCPU,"exceeded cpu limit");
332 #endif
333 #ifdef SIGXFSZ
334     store_str(ap_sys_siglist,SIGXFSZ,"exceeded file size limit");
335 #endif
336     for (sig=0; sig < sizeof(ap_sys_siglist)/sizeof(ap_sys_siglist[0]); ++sig)
337         if (ap_sys_siglist[sig] == NULL)
338             ap_sys_siglist[sig] = "";
339 }
340 #endif /* NEED_AP_SYS_SIGLIST */
341
342 AP_DECLARE(void) unixd_set_rlimit(cmd_parms *cmd, struct rlimit **plimit, 
343                            const char *arg, const char * arg2, int type)
344 {
345 #if (defined(RLIMIT_CPU) || defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_NPROC) || defined(RLIMIT_AS)) && APR_HAVE_STRUCT_RLIMIT && APR_HAVE_GETRLIMIT
346     char *str;
347     struct rlimit *limit;
348     /* If your platform doesn't define rlim_t then typedef it in ap_config.h */
349     rlim_t cur = 0;
350     rlim_t max = 0;
351
352     *plimit = (struct rlimit *)apr_pcalloc(cmd->pool, sizeof(**plimit));
353     limit = *plimit;
354     if ((getrlimit(type, limit)) != 0)  {
355         *plimit = NULL;
356         ap_log_error(APLOG_MARK, APLOG_ERR, errno, cmd->server,
357                      "%s: getrlimit failed", cmd->cmd->name);
358         return;
359     }
360
361     if ((str = ap_getword_conf(cmd->pool, &arg))) {
362         if (!strcasecmp(str, "max")) {
363             cur = limit->rlim_max;
364         }
365         else {
366             cur = atol(str);
367         }
368     }
369     else {
370         ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, cmd->server,
371                      "Invalid parameters for %s", cmd->cmd->name);
372         return;
373     }
374
375     if (arg2 && (str = ap_getword_conf(cmd->pool, &arg2))) {
376         max = atol(str);
377     }
378
379     /* if we aren't running as root, cannot increase max */
380     if (geteuid()) {
381         limit->rlim_cur = cur;
382         if (max) {
383             ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, cmd->server,
384                          "Must be uid 0 to raise maximum %s", cmd->cmd->name);
385         }
386     }
387     else {
388         if (cur) {
389             limit->rlim_cur = cur;
390         }
391         if (max) {
392             limit->rlim_max = max;
393         }
394     }
395 #else
396
397     ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, cmd->server,
398                  "Platform does not support rlimit for %s", cmd->cmd->name);
399 #endif
400 }
401