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