r38706 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r38705‎ | r38706 | r38707 >
Date:11:58, 6 August 2008
Author:river
Status:old
Tags:
Comment:
swexec: fix indentation; need Solaris project support for stable toolserver
Modified paths:
  • /trunk/switchboard/Makefile (modified) (history)
  • /trunk/switchboard/Makefile.config.example (modified) (history)
  • /trunk/switchboard/swexec.c (modified) (history)

Diff [purge]

Index: trunk/switchboard/swexec.c
@@ -1,3 +1,5 @@
 2+/* Copyright 2008 The Apache Software Foundation. */
 3+/* Copyright 2008 River Tarnell <river@wikimedia.org */
24 /* Licensed to the Apache Software Foundation (ASF) under one or more
35 * contributor license agreements. See the NOTICE file distributed with
46 * this work for additional information regarding copyright ownership.
@@ -16,36 +18,34 @@
1719
1820 /*
1921 * suexec.c -- "Wrapper" support program for suEXEC behaviour for Apache
20 - *
21 - ***********************************************************************
22 - *
23 - * NOTE! : DO NOT edit this code!!! Unless you know what you are doing,
24 - * editing this code might open up your system in unexpected
25 - * ways to would-be crackers. Every precaution has been taken
26 - * to make this code as safe as possible; alter it at your own
27 - * risk.
28 - *
29 - ***********************************************************************
30 - *
31 - *
3222 */
3323
 24+#if defined(__sun) && defined(__svr4__)
 25+/* Solaris */
 26+# define USE_PROJECTS
 27+#endif
 28+
3429 #define SB_SUEXEC_UMASK 022
3530
36 -#include <sys/param.h>
37 -#include <sys/stat.h>
38 -#include <sys/types.h>
39 -#include <string.h>
40 -#include <time.h>
41 -#include <unistd.h>
42 -#include <stdio.h>
43 -#include <stdarg.h>
44 -#include <stdlib.h>
45 -#include <errno.h>
 31+#include <sys/param.h>
 32+#include <sys/stat.h>
 33+#include <sys/types.h>
 34+#include <string.h>
 35+#include <time.h>
 36+#include <unistd.h>
 37+#include <stdio.h>
 38+#include <stdarg.h>
 39+#include <stdlib.h>
 40+#include <errno.h>
4641
47 -#include <pwd.h>
48 -#include <grp.h>
 42+#ifdef USE_PROJECTS
 43+# include <sys/task.h>
 44+# include <project.h>
 45+#endif
4946
 47+#include <pwd.h>
 48+#include <grp.h>
 49+
5050 #if defined(PATH_MAX)
5151 #define SB_MAXPATH PATH_MAX
5252 #elif defined(MAXPATHLEN)
@@ -66,9 +66,9 @@
6767 };
6868
6969
70 -static void err_output(int is_error, const char *fmt, va_list ap)
 70+static void
 71+err_output(int is_error, const char *fmt, va_list ap)
7172 {
72 -#ifdef SB_LOG_EXEC
7373 time_t timevar;
7474 struct tm *lt;
7575
@@ -95,262 +95,274 @@
9696 vfprintf(log, fmt, ap);
9797
9898 fflush(log);
99 -#endif /* SB_LOG_EXEC */
100 - return;
10199 }
102100
103 -static void log_err(const char *fmt,...)
 101+static void
 102+log_err(const char *fmt,...)
104103 {
105 -#ifdef SB_LOG_EXEC
106104 va_list ap;
107105
108106 va_start(ap, fmt);
109107 err_output(1, fmt, ap); /* 1 == is_error */
110108 va_end(ap);
111 -#endif /* SB_LOG_EXEC */
112 - return;
113109 }
114110
115 -static void log_no_err(const char *fmt,...)
 111+static void
 112+log_no_err(const char *fmt,...)
116113 {
117 -#ifdef SB_LOG_EXEC
118114 va_list ap;
119115
120116 va_start(ap, fmt);
121117 err_output(0, fmt, ap); /* 0 == !is_error */
122118 va_end(ap);
123 -#endif /* SB_LOG_EXEC */
124 - return;
125119 }
126120
127 -static void clean_env(void)
 121+static void
 122+clean_env(void)
128123 {
129 - char envbuf[512];
130 - char **cleanenv;
131 - char **ep;
132 - int cidx = 0;
133 - int idx;
 124+ char envbuf[512];
 125+ char **cleanenv;
 126+ char **ep;
 127+ int cidx = 0;
 128+ int idx;
134129
135 - /* While cleaning the environment, the environment should be clean.
136 - * (e.g. malloc() may get the name of a file for writing debugging info.
137 - * Bad news if MALLOC_DEBUG_FILE is set to /etc/passwd. Sprintf() may be
138 - * susceptible to bad locale settings....)
139 - * (from PR 2790)
140 - */
141 - char **envp = environ;
142 - char *empty_ptr = NULL;
 130+ /* While cleaning the environment, the environment should be clean.
 131+ * (e.g. malloc() may get the name of a file for writing debugging info.
 132+ * Bad news if MALLOC_DEBUG_FILE is set to /etc/passwd. Sprintf() may be
 133+ * susceptible to bad locale settings....)
 134+ * (from PR 2790)
 135+ */
 136+ char **envp = environ;
 137+ char *empty_ptr = NULL;
143138
144 - environ = &empty_ptr; /* VERY safe environment */
 139+ environ = &empty_ptr; /* VERY safe environment */
145140
146 - if ((cleanenv = (char **) calloc(SB_ENVBUF, sizeof(char *))) == NULL) {
147 - log_err("failed to malloc memory for environment\n");
148 - exit(120);
149 - }
 141+ if ((cleanenv = (char **) calloc(SB_ENVBUF, sizeof(char *))) == NULL) {
 142+ log_err("failed to malloc memory for environment\n");
 143+ exit(120);
 144+ }
150145
151 - sprintf(envbuf, "PATH=%s", SB_SAFE_PATH);
152 - cleanenv[cidx] = strdup(envbuf);
153 - cidx++;
154 - sprintf(envbuf, "PHP_FCGI_MAX_REQUESTS=5000");
155 - cleanenv[cidx] = strdup(envbuf);
156 - cidx++;
 146+ sprintf(envbuf, "PATH=%s", SB_SAFE_PATH);
 147+ cleanenv[cidx] = strdup(envbuf);
 148+ cidx++;
 149+ sprintf(envbuf, "PHP_FCGI_MAX_REQUESTS=5000");
 150+ cleanenv[cidx] = strdup(envbuf);
 151+ cidx++;
157152
158 - for (ep = envp; *ep && cidx < SB_ENVBUF-1; ep++) {
159 - for (idx = 0; safe_env_lst[idx]; idx++) {
160 - if (!strncmp(*ep, safe_env_lst[idx],
161 - strlen(safe_env_lst[idx]))) {
162 - cleanenv[cidx] = *ep;
163 - cidx++;
164 - break;
165 - }
166 - }
167 - }
 153+ for (ep = envp; *ep && cidx < SB_ENVBUF-1; ep++) {
 154+ for (idx = 0; safe_env_lst[idx]; idx++) {
 155+ if (!strncmp(*ep, safe_env_lst[idx],
 156+ strlen(safe_env_lst[idx]))) {
 157+ cleanenv[cidx] = *ep;
 158+ cidx++;
 159+ break;
 160+ }
 161+ }
 162+ }
168163
169 - cleanenv[cidx] = NULL;
 164+ cleanenv[cidx] = NULL;
170165
171 - environ = cleanenv;
 166+ environ = cleanenv;
172167 }
173168
174 -int main(int argc, char *argv[])
 169+int
 170+main(int argc, char *argv[])
175171 {
176 - int userdir = 0; /* ~userdir flag */
177 - uid_t uid; /* user information */
178 - gid_t gid; /* target group placeholder */
179 - char *target_uname; /* target user name */
180 - char *target_gname; /* target group name */
181 - char *target_homedir; /* target home directory */
182 - char *actual_uname; /* actual user name */
183 - char *actual_gname; /* actual group name */
184 - char *prog; /* name of this program */
185 - struct passwd *pw; /* password entry holder */
186 - struct group *gr; /* group entry holder */
 172+ int userdir = 0; /* ~userdir flag */
 173+ uid_t uid; /* user information */
 174+ gid_t gid; /* target group placeholder */
 175+ char *target_uname; /* target user name */
 176+ char *target_gname; /* target group name */
 177+ char *target_homedir; /* target home directory */
 178+ char *actual_uname; /* actual user name */
 179+ char *actual_gname; /* actual group name */
 180+ char *prog; /* name of this program */
 181+ struct passwd *pw; /* password entry holder */
 182+ struct group *gr; /* group entry holder */
 183+#ifdef USE_PROJECTS
 184+ struct project proj;
 185+ char nssbuf[PROJECT_BUFSZ];
 186+#endif
187187
188 - /*
189 - * Start with a "clean" environment
190 - */
191 - clean_env();
 188+ /*
 189+ * Start with a "clean" environment
 190+ */
 191+ clean_env();
192192
193 - prog = argv[0];
194 - /*
195 - * Check existence/validity of the UID of the user
196 - * running this program. Error out if invalid.
197 - */
198 - uid = getuid();
199 - if ((pw = getpwuid(uid)) == NULL) {
200 - log_err("crit: invalid uid: (%ld)\n", uid);
201 - exit(102);
202 - }
 193+ prog = argv[0];
 194+ /*
 195+ * Check existence/validity of the UID of the user
 196+ * running this program. Error out if invalid.
 197+ */
 198+ uid = getuid();
 199+ if ((pw = getpwuid(uid)) == NULL) {
 200+ log_err("crit: invalid uid: (%ld)\n", (long) uid);
 201+ exit(102);
 202+ }
203203
204 - /*
205 - * If there are a proper number of arguments, set
206 - * all of them to variables. Otherwise, error out.
207 - */
208 - if (argc < 3) {
209 - log_err("too few arguments\n");
210 - exit(101);
211 - }
212 - target_uname = argv[1];
213 - target_gname = argv[2];
 204+ /*
 205+ * If there are a proper number of arguments, set
 206+ * all of them to variables. Otherwise, error out.
 207+ */
 208+ if (argc < 3) {
 209+ log_err("too few arguments\n");
 210+ exit(101);
 211+ }
 212+ target_uname = argv[1];
 213+ target_gname = argv[2];
214214
215 - /*
216 - * Check to see if the user running this program
217 - * is the user allowed to do so as defined in
218 - * suexec.h. If not the allowed user, error out.
219 - */
220 - if (strcmp(SB_USER, pw->pw_name)) {
221 - log_err("user mismatch (%s instead of %s)\n", pw->pw_name, SB_USER);
222 - exit(103);
223 - }
 215+ /*
 216+ * Check to see if the user running this program
 217+ * is the user allowed to do so as defined in
 218+ * suexec.h. If not the allowed user, error out.
 219+ */
 220+ if (strcmp(SB_USER, pw->pw_name)) {
 221+ log_err("user mismatch (%s instead of %s)\n", pw->pw_name, SB_USER);
 222+ exit(103);
 223+ }
224224
225 - /*
226 - * Error out if the target username is invalid.
227 - */
228 - if (strspn(target_uname, "1234567890") != strlen(target_uname)) {
229 - if ((pw = getpwnam(target_uname)) == NULL) {
230 - log_err("invalid target user name: (%s)\n", target_uname);
231 - exit(105);
232 - }
233 - }
234 - else {
235 - if ((pw = getpwuid(atoi(target_uname))) == NULL) {
236 - log_err("invalid target user id: (%s)\n", target_uname);
237 - exit(121);
238 - }
239 - }
 225+ /*
 226+ * Error out if the target username is invalid.
 227+ */
 228+ if (strspn(target_uname, "1234567890") != strlen(target_uname)) {
 229+ if ((pw = getpwnam(target_uname)) == NULL) {
 230+ log_err("invalid target user name: (%s)\n", target_uname);
 231+ exit(105);
 232+ }
 233+ } else {
 234+ if ((pw = getpwuid(atoi(target_uname))) == NULL) {
 235+ log_err("invalid target user id: (%s)\n", target_uname);
 236+ exit(121);
 237+ }
 238+ }
240239
241 - /*
242 - * Error out if the target group name is invalid.
243 - */
244 - if (strspn(target_gname, "1234567890") != strlen(target_gname)) {
245 - if ((gr = getgrnam(target_gname)) == NULL) {
246 - log_err("invalid target group name: (%s)\n", target_gname);
247 - exit(106);
248 - }
249 - }
250 - else {
251 - if ((gr = getgrgid(atoi(target_gname))) == NULL) {
252 - log_err("invalid target group id: (%s)\n", target_gname);
253 - exit(106);
254 - }
255 - }
256 - gid = gr->gr_gid;
257 - actual_gname = strdup(gr->gr_name);
 240+ /*
 241+ * Error out if the target group name is invalid.
 242+ */
 243+ if (strspn(target_gname, "1234567890") != strlen(target_gname)) {
 244+ if ((gr = getgrnam(target_gname)) == NULL) {
 245+ log_err("invalid target group name: (%s)\n", target_gname);
 246+ exit(106);
 247+ }
 248+ } else {
 249+ if ((gr = getgrgid(atoi(target_gname))) == NULL) {
 250+ log_err("invalid target group id: (%s)\n", target_gname);
 251+ exit(106);
 252+ }
 253+ }
 254+ gid = gr->gr_gid;
 255+ actual_gname = strdup(gr->gr_name);
258256
259 - /*
260 - * Save these for later since initgroups will hose the struct
261 - */
262 - uid = pw->pw_uid;
263 - actual_uname = strdup(pw->pw_name);
264 - target_homedir = strdup(pw->pw_dir);
 257+ /*
 258+ * Save these for later since initgroups will hose the struct
 259+ */
 260+ uid = pw->pw_uid;
 261+ actual_uname = strdup(pw->pw_name);
 262+ target_homedir = strdup(pw->pw_dir);
265263
266 - /*
267 - * Log the transaction here to be sure we have an open log
268 - * before we setuid().
269 - */
270 - log_no_err("uid: (%s/%s) gid: (%s/%s) cmd: %s\n",
271 - target_uname, actual_uname,
272 - target_gname, actual_gname,
273 - PHP_BIN);
 264+ /*
 265+ * Log the transaction here to be sure we have an open log
 266+ * before we setuid().
 267+ */
 268+ log_no_err("uid: (%s/%s) gid: (%s/%s) cmd: %s\n",
 269+ target_uname, actual_uname,
 270+ target_gname, actual_gname,
 271+ PHP_BIN);
274272
275 - /*
276 - * Error out if attempt is made to execute as root or as
277 - * a UID less than SB_UID_MIN. Tsk tsk.
278 - */
279 - if ((uid == 0) || (uid < SB_UID_MIN)) {
280 - log_err("cannot run as forbidden uid (%d/%s)\n", uid, PHP_BIN);
281 - exit(107);
282 - }
 273+ /*
 274+ * Error out if attempt is made to execute as root or as
 275+ * a UID less than SB_UID_MIN. Tsk tsk.
 276+ */
 277+ if ((uid == 0) || (uid < SB_UID_MIN)) {
 278+ log_err("cannot run as forbidden uid (%d/%s)\n", uid, PHP_BIN);
 279+ exit(107);
 280+ }
283281
284 - /*
285 - * Error out if attempt is made to execute as root group
286 - * or as a GID less than SB_GID_MIN. Tsk tsk.
287 - */
288 - if ((gid == 0) || (gid < SB_GID_MIN)) {
289 - log_err("cannot run as forbidden gid (%d/%s)\n", gid, PHP_BIN);
290 - exit(108);
291 - }
 282+ /*
 283+ * Error out if attempt is made to execute as root group
 284+ * or as a GID less than SB_GID_MIN. Tsk tsk.
 285+ */
 286+ if ((gid == 0) || (gid < SB_GID_MIN)) {
 287+ log_err("cannot run as forbidden gid (%d/%s)\n", gid, PHP_BIN);
 288+ exit(108);
 289+ }
292290
293 - /*
294 - * Change UID/GID here so that the following tests work over NFS.
295 - *
296 - * Initialize the group access list for the target user,
297 - * and setgid() to the target group. If unsuccessful, error out.
298 - */
299 - if (((setgid(gid)) != 0) || (initgroups(actual_uname, gid) != 0)) {
300 - log_err("failed to setgid (%ld: %s)\n", gid, PHP_BIN);
301 - exit(109);
302 - }
 291+#ifdef USE_PROJECTS
 292+ if (getdefaultproj(actual_uname, &proj, nssbuf, sizeof(nssbuf)) == NULL) {
 293+ log_err("failed to get default project (%s: %s)",
 294+ actual_uname, strerror(errno));
 295+ exit(113);
 296+ }
303297
304 - /*
305 - * setuid() to the target user. Error out on fail.
306 - */
307 - if ((setuid(uid)) != 0) {
308 - log_err("failed to setuid (%ld: %s)\n", uid, PHP_BIN);
309 - exit(110);
310 - }
 298+ if (setproject(proj.pj_name, actual_uname, TASK_FINAL) != 0) {
 299+ log_err("failed to set project (%s: %s)",
 300+ actual_uname, strerror(errno));
 301+ exit(114);
 302+ }
 303+#endif
 304+
 305+ /*
 306+ * Change UID/GID here so that the following tests work over NFS.
 307+ *
 308+ * Initialize the group access list for the target user,
 309+ * and setgid() to the target group. If unsuccessful, error out.
 310+ */
 311+ if (((setgid(gid)) != 0) || (initgroups(actual_uname, gid) != 0)) {
 312+ log_err("failed to setgid (%ld: %s)\n", (long) gid, PHP_BIN);
 313+ exit(109);
 314+ }
311315
312 - if (chdir(target_homedir) != 0) {
313 - log_err("cannot chdir to home directory (%s)\n", target_homedir);
314 - exit(112);
315 - }
 316+ /*
 317+ * setuid() to the target user. Error out on fail.
 318+ */
 319+ if ((setuid(uid)) != 0) {
 320+ log_err("failed to setuid (%ld: %s)\n", (long) uid, PHP_BIN);
 321+ exit(110);
 322+ }
316323
 324+ if (chdir(target_homedir) != 0) {
 325+ log_err("cannot chdir to home directory (%s)\n", target_homedir);
 326+ exit(112);
 327+ }
 328+
317329 #ifdef SB_SUEXEC_UMASK
318 - /*
319 - * umask() uses inverse logic; bits are CLEAR for allowed access.
320 - */
321 - if ((~SB_SUEXEC_UMASK) & 0022) {
322 - log_err("notice: SB_SUEXEC_UMASK of %03o allows "
323 - "write permission to group and/or other\n", SB_SUEXEC_UMASK);
324 - }
325 - umask(SB_SUEXEC_UMASK);
 330+ /*
 331+ * umask() uses inverse logic; bits are CLEAR for allowed access.
 332+ */
 333+ if ((~SB_SUEXEC_UMASK) & 0022) {
 334+ log_err("notice: SB_SUEXEC_UMASK of %03o allows "
 335+ "write permission to group and/or other\n", SB_SUEXEC_UMASK);
 336+ }
 337+ umask(SB_SUEXEC_UMASK);
326338 #endif /* SB_SUEXEC_UMASK */
327339
328 - /*
329 - * Be sure to close the log file so the CGI can't
330 - * mess with it. If the exec fails, it will be reopened
331 - * automatically when log_err is called. Note that the log
332 - * might not actually be open if SB_LOG_EXEC isn't defined.
333 - * However, the "log" cell isn't ifdef'd so let's be defensive
334 - * and assume someone might have done something with it
335 - * outside an ifdef'd SB_LOG_EXEC block.
336 - */
337 - if (log != NULL) {
338 - fclose(log);
339 - log = NULL;
340 - }
 340+ /*
 341+ * Be sure to close the log file so the CGI can't
 342+ * mess with it. If the exec fails, it will be reopened
 343+ * automatically when log_err is called. Note that the log
 344+ * might not actually be open if SB_LOG_EXEC isn't defined.
 345+ * However, the "log" call isn't ifdef'd so let's be defensive
 346+ * and assume someone might have done something with it
 347+ * outside an ifdef'd SB_LOG_EXEC block.
 348+ */
 349+ if (log != NULL) {
 350+ fclose(log);
 351+ log = NULL;
 352+ }
341353
342 - /*
343 - * Execute the command, replacing our image with its own.
344 - */
345 - execl(PHP_BIN, PHP_BIN, NULL);
 354+ /*
 355+ * Execute the command, replacing our image with its own.
 356+ */
 357+ execl(PHP_BIN, PHP_BIN, NULL);
346358
347 - /*
348 - * (I can't help myself...sorry.)
349 - *
350 - * Uh oh. Still here. Where's the kaboom? There was supposed to be an
351 - * EARTH-shattering kaboom!
352 - *
353 - * Oh well, log the failure and error out.
354 - */
355 - log_err("(%d)%s: exec failed (%s)\n", errno, strerror(errno), PHP_BIN);
356 - exit(255);
 359+ /*
 360+ * (I can't help myself...sorry.)
 361+ *
 362+ * Uh oh. Still here. Where's the kaboom? There was supposed to be an
 363+ * EARTH-shattering kaboom!
 364+ *
 365+ * Oh well, log the failure and error out.
 366+ */
 367+ log_err("(%d)%s: exec failed (%s)\n", errno, strerror(errno), PHP_BIN);
 368+ exit(255);
357369 }
Index: trunk/switchboard/Makefile.config.example
@@ -31,8 +31,11 @@
3232 EXTRA_LIBS=
3333
3434 # For Solaris:
35 -EXTRA_LIBS+=-lsocket -lnsl
 35+EXTRA_LIBS+=-lsocket -lnsl -lproject
3636
 37+# swexec needs this for project support on solaris
 38+SWEXEC_EXTRA_LIBS = -lproject
 39+
3740 # install program, /usr/ucb/install for Solaris, otherwise /usr/bin/install
3841 INSTALL=/usr/ucb/install
3942
Index: trunk/switchboard/Makefile
@@ -49,7 +49,7 @@
5050 $(CXX) $(CFLAGS) $(CXXFLAGS) $(LDFLAGS) $(OBJS) -o $(PROG) $(LIBS)
5151
5252 $(SWEXEC): swexec.o
53 - $(CC) $(CFLAGS) $(LDFLAGS) swexec.o -o $(SWEXEC)
 53+ $(CC) $(CFLAGS) $(LDFLAGS) swexec.o -o $(SWEXEC) $(SWEXEC_EXTRA_LIBS)
5454
5555 $(SWKILL): swkill.o
5656 $(CC) $(CFLAGS) $(LDFLAGS) swkill.o -o $(SWKILL)

Status & tagging log