]> granicus.if.org Git - apache/blob - os/bs2000/bs2login.c
Update our copyright for this year.
[apache] / os / bs2000 / bs2login.c
1 /* ====================================================================
2  * The Apache Software License, Version 1.1
3  *
4  * Copyright (c) 2000-2002 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 #ifdef _OSD_POSIX
60 #include "httpd.h"
61 #include "http_config.h"
62 #include "http_log.h"
63 #include <ctype.h>
64 #include <sys/utsname.h>
65
66 #define ACCT_LEN 8
67 #define USER_LEN 8
68
69 static const char *bs2000_account = NULL;
70 typedef enum
71 {
72     bs2_unknown,     /* not initialized yet. */
73     bs2_noFORK,      /* no fork() because -X flag was specified */
74     bs2_FORK,        /* only fork() because uid != 0 */
75     bs2_FORK_RINI,   /* prior to A17, regular fork() and _rini() was used. */
76     bs2_RFORK_RINI,  /* for A17, use of _rfork() and _rini() was required */
77     bs2_UFORK        /* As of A18, the new ufork() is used. */
78 } bs2_ForkType;
79
80 static bs2_ForkType forktype = bs2_unknown;
81
82 #if !defined(_POSIX_SOURCE) && !defined(_XOPEN_SOURCE)
83 typedef struct {           
84     char    *username;     
85     char    *account;      
86     char    *processor_name;
87 }  _rini_struct;           
88
89 extern int _rini(_rini_struct *);
90 #endif /* !defined(_POSIX_SOURCE) && !defined(_XOPEN_SOURCE) */
91
92
93 static void ap_pad(char *dest, size_t size, char ch)
94 {
95     int i = strlen(dest); /* Leave space for trailing '\0' */
96     
97     while (i < size-1)
98         dest[i++] = ch;
99
100     dest[size-1] = '\0';        /* Guarantee for trailing '\0' */
101 }
102
103 static void ap_str_toupper(char *str)
104 {
105     while (*str) {
106         *str = apr_toupper(*str);
107         ++str;
108     }
109 }
110
111 /* Determine the method for forking off a child in such a way as to
112  * set both the POSIX and BS2000 user id's to the unprivileged user.
113  */
114 static bs2_ForkType os_forktype(void)
115 {
116     struct utsname os_version;
117
118     /* have we checked the OS version before? If yes return the previous
119      * result - the OS release isn't going to change suddenly!
120      */
121     if (forktype != bs2_unknown) {
122         return forktype;
123     }
124
125     /* If the user is unprivileged, use the normal fork() only. */
126     if (getuid() != 0) {
127         return forktype = bs2_FORK;
128     }
129
130     if (uname(&os_version) < 0)
131     {
132         ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
133                      "uname() failed - aborting.");
134         exit(APEXIT_CHILDFATAL);
135     }
136
137     /*
138      * Old BS2000/OSD versions (before XPG4 SPEC1170) don't work with Apache.
139      * Anyway, simply return a fork().
140      */
141     if (strcmp(os_version.release, "01.0A") == 0 ||
142         strcmp(os_version.release, "02.0A") == 0 ||
143         strcmp(os_version.release, "02.1A") == 0)
144     {
145         ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, NULL,
146                      "Error: unsupported OS version. "
147                      "You may encounter problems.");
148         forktype = bs2_FORK;
149     }
150
151     /* The following versions are special:
152      * OS versions before A17 needs regular fork() and _rini().
153      * A17 requires _rfork() and _rini(),
154      * and later versions need ufork().
155      */
156     else if (strcmp(os_version.release, "01.1A") == 0 ||
157              strcmp(os_version.release, "03.0A") == 0 ||
158              strcmp(os_version.release, "03.1A") == 0 ||
159              strcmp(os_version.release, "04.0A") == 0)
160     {
161         if (strcmp (os_version.version, "A18") >= 0)
162             forktype = bs2_UFORK;
163
164         else if (strcmp (os_version.version, "A17") < 0)
165             forktype = bs2_FORK_RINI;
166
167         else
168             forktype = bs2_RFORK_RINI;
169     }
170
171     /* All later OS versions will hopefully use ufork() only  ;-) */
172     else
173         forktype = bs2_UFORK;
174
175     return forktype;
176 }
177
178
179
180 /* This routine is called by http_core for the BS2000Account directive */
181 /* It stores the account name for later use */
182 const char *os_set_account(apr_pool_t *p, const char *account)
183 {
184     char account_temp[ACCT_LEN+1];
185
186     apr_cpystrn(account_temp, account, sizeof account_temp);
187
188     /* Make account all upper case */
189     ap_str_toupper(account_temp);
190
191     /* Pad to length 8 */
192     ap_pad(account_temp, sizeof account_temp, ' ');
193
194     bs2000_account = apr_pstrdup(p, account_temp);
195     return NULL;
196 }
197
198 /* This routine complements the setuid() call: it causes the BS2000 job
199  * environment to be switched to the target user's user id.
200  * That is important if CGI scripts try to execute native BS2000 commands.
201  */
202 int os_init_job_environment(server_rec *server, const char *user_name, int one_process)
203 {
204     _rini_struct            inittask; 
205     char                    username[USER_LEN+1];
206     int                     save_errno;
207     bs2_ForkType            type = os_forktype();
208
209     /* We can be sure that no change to uid==0 is possible because of
210      * the checks in http_core.c:set_user()
211      */
212
213     /* The _rini() function works only after a prior _rfork().
214      * In the case of one_process, it would fail.
215      */
216     if (one_process) {
217
218         type = forktype = bs2_noFORK;
219
220         ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, server,
221                      "The debug mode of Apache should only "
222                      "be started by an unprivileged user!");
223         return 0;
224     }
225
226     /* If no _rini() is required, then return quickly. */
227     if (type != bs2_RFORK_RINI && type != bs2_FORK_RINI)
228         return 0;
229
230     /* An Account is required for _rini() */
231     if (bs2000_account == NULL)
232     {
233         ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_NOERRNO, 0, server,
234                      "No BS2000Account configured - cannot switch to User %s",
235                      user_name);
236         exit(APEXIT_CHILDFATAL);
237     }
238
239     apr_cpystrn(username, user_name, sizeof username);
240
241     /* Make user name all upper case */
242     ap_str_toupper(username);
243
244     /* Pad to length 8 */
245     ap_pad(username, sizeof username, ' ');
246
247     inittask.username       = username;
248     inittask.account        = bs2000_account;
249     inittask.processor_name = "        ";
250
251     /* Switch to the new logon user (setuid() and setgid() are done later) */
252     /* Only the super user can switch identities. */
253     if (_rini(&inittask) != 0) {
254
255         ap_log_error(APLOG_MARK, APLOG_ALERT, errno, server,
256                      "_rini: BS2000 auth failed for user \"%s\" acct \"%s\"",
257                      inittask.username, inittask.account);
258
259         exit(APEXIT_CHILDFATAL);
260     }
261
262     return 0;
263 }
264
265 /* BS2000 requires a "special" version of fork() before a setuid()/_rini() call */
266 pid_t os_fork(const char *user)
267 {
268     pid_t pid;
269     char  username[USER_LEN+1];
270
271     switch (os_forktype()) {
272       case bs2_FORK:
273       case bs2_FORK_RINI:
274         pid = fork();
275         break;
276
277       case bs2_RFORK_RINI:
278         pid = _rfork();
279         break;
280
281       case bs2_UFORK:
282         apr_cpystrn(username, user, sizeof username);
283
284         /* Make user name all upper case - for some versions of ufork() */
285         ap_str_toupper(username);
286
287         pid = ufork(username);
288         if (pid == -1 && errno == EPERM) {
289             ap_log_error(APLOG_MARK, APLOG_EMERG, errno,
290                          NULL, "ufork: Possible mis-configuration "
291                          "for user %s - Aborting.", user);
292             exit(1);
293         }
294         break;
295
296       default:
297         pid = 0;
298         break;
299     }
300
301     return pid;
302 }
303
304 #else /* _OSD_POSIX */
305 void bs2login_is_not_here()
306 {
307 }
308 #endif /* _OSD_POSIX */