1 |
// $Id: rpm-fake.c,v 1.30 2005/03/23 02:08:45 ensc Exp $ --*- c++ -*-- |
2 |
|
3 |
// Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de> |
4 |
// |
5 |
// This program is free software; you can redistribute it and/or modify |
6 |
// it under the terms of the GNU General Public License as published by |
7 |
// the Free Software Foundation; version 2 of the License. |
8 |
// |
9 |
// This program is distributed in the hope that it will be useful, |
10 |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 |
// GNU General Public License for more details. |
13 |
// |
14 |
// You should have received a copy of the GNU General Public License |
15 |
// along with this program; if not, write to the Free Software |
16 |
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
17 |
// |
18 |
|
19 |
#ifdef HAVE_CONFIG_H |
20 |
# include <config.h> |
21 |
#endif |
22 |
|
23 |
#include "pathconfig.h" |
24 |
#include "util.h" |
25 |
|
26 |
#include <lib/vserver.h> |
27 |
#include <lib/internal.h> |
28 |
#include <lib_internal/sys_clone.h> |
29 |
|
30 |
#include <sys/socket.h> |
31 |
#include <dlfcn.h> |
32 |
#include <stdlib.h> |
33 |
#include <stdint.h> |
34 |
#include <stdio.h> |
35 |
#include <unistd.h> |
36 |
#include <asm/unistd.h> |
37 |
#include <string.h> |
38 |
#include <stdbool.h> |
39 |
#include <errno.h> |
40 |
#include <fcntl.h> |
41 |
#include <stdarg.h> |
42 |
#include <sys/mount.h> |
43 |
#include <linux/fs.h> |
44 |
#include <sched.h> |
45 |
#include <signal.h> |
46 |
#include <sys/types.h> |
47 |
#include <sys/wait.h> |
48 |
#include <sys/un.h> |
49 |
#include <fcntl.h> |
50 |
#include <pwd.h> |
51 |
#include <grp.h> |
52 |
|
53 |
|
54 |
// from selinux.h |
55 |
// FIXME: add configure autodetection and include <selinux.h> directly |
56 |
int rpm_execcon(unsigned int verified, |
57 |
const char *filename, |
58 |
char *const argv[], char *const envp[]); |
59 |
|
60 |
|
61 |
#define ENSC_WRAPPERS_PREFIX "rpm-fake.so: " |
62 |
#define ENSC_WRAPPERS_VSERVER 1 |
63 |
#define ENSC_WRAPPERS_UNISTD 1 |
64 |
#include <wrappers.h> |
65 |
|
66 |
#undef _POSIX_SOURCE |
67 |
#include "capability-compat.h" |
68 |
|
69 |
#ifndef CLONE_NEWNS |
70 |
# define CLONE_NEWNS 0x00020000 |
71 |
#endif |
72 |
|
73 |
#define LIBNAME "rpm-fake.so" |
74 |
#define PLATFORM_FILE "/etc/rpm/platform" |
75 |
|
76 |
#define INIT(FILE,FUNC) FUNC##_func = ((__typeof__(FUNC) *) (xdlsym(FILE, #FUNC))) |
77 |
#define DECLARE(FUNC) static __typeof__(FUNC) * FUNC##_func = 0 |
78 |
|
79 |
#define DEBUG 1 |
80 |
|
81 |
#define DBG_INIT 0x0001 |
82 |
#define DBG_VARIABLES 0x0002 |
83 |
#define DBG_RESOLVER 0x0004 |
84 |
#define DBG_EXECV 0x0008 |
85 |
#define DBG_ENV 0x0010 |
86 |
#define DBG_VERBOSE0 0x8000 |
87 |
#define DBG_VERBOSE1 (0x4000 | DBG_VERBOSE0) |
88 |
#define DBG_VERBOSE2 (0x2000 | DBG_VERBOSE1) |
89 |
|
90 |
int wrapper_exit_code = 255; |
91 |
|
92 |
static xid_t ctx = VC_NOCTX; |
93 |
static uint32_t caps = ~0; |
94 |
static int flags = 0; |
95 |
static char const * mnts = 0; |
96 |
static char const * root = 0; |
97 |
static int pw_sock = -1; |
98 |
static int sync_sock = -1; |
99 |
static unsigned int debug_level = 0; |
100 |
|
101 |
static bool is_initialized = false; |
102 |
|
103 |
//DECLARE(rpm_execcon); |
104 |
//DECLARE(execv); |
105 |
DECLARE(getpwnam); |
106 |
DECLARE(getgrnam); |
107 |
DECLARE(endpwent); |
108 |
DECLARE(endgrent); |
109 |
|
110 |
static void initRPMFake() __attribute__((__constructor__)); |
111 |
static void exitRPMFake() __attribute__((__destructor__)); |
112 |
|
113 |
static inline bool |
114 |
isDbgLevel(unsigned int level) |
115 |
{ |
116 |
return ((debug_level&level)==level); |
117 |
} |
118 |
|
119 |
static void * |
120 |
xdlsym(void *handle, const char *symbol) |
121 |
{ |
122 |
void *res = dlsym(handle, symbol); |
123 |
if (res==0) { |
124 |
char const *error = dlerror(); |
125 |
Vwrite(2, symbol, strlen(symbol)); |
126 |
Vwrite(2, ": ", 2); |
127 |
Vwrite(2, error, strlen(error)); |
128 |
Vwrite(2, "\n", 2); |
129 |
|
130 |
_exit(255); |
131 |
} |
132 |
|
133 |
return res; |
134 |
} |
135 |
|
136 |
static void |
137 |
showHelp() |
138 |
{ |
139 |
WRITE_MSG(1, |
140 |
"Usage: LD_PRELOAD=" LIBNAME " <executable> <args>*\n\n" |
141 |
LIBNAME " unterstands the following environment variables:\n" |
142 |
" $RPM_FAKE_RESOLVER ... program which does the NSS resolving (defaults\n" |
143 |
" to " RESOLVER_PROG ")\n" |
144 |
" $RPM_FAKE_RESOLVER_UID ... uid of the resolver program\n" |
145 |
" $RPM_FAKE_RESOLVER_GID ... gid of the resolver program\n" |
146 |
" $RPM_FAKE_CTX ... vserver context which shall be used for resolver\n" |
147 |
" and scriptlets\n" |
148 |
" $RPM_FAKE_CAP ... linux capability remove-mask for the context\n" |
149 |
" $RPM_FAKE_FLAGS ... vserver flags of the context\n" |
150 |
" $RPM_FAKE_CHROOT ... directory of the chroot environment\n" |
151 |
" $RPM_FAKE_NAMESPACE_MOUNTS\n" |
152 |
" ... colon separated list of directories which will\n" |
153 |
" umounted before scriptlet execution\n\n" |
154 |
" $RPM_FAKE_HELP ... shows this message\n" |
155 |
" $RPM_FAKE_VERSION ... shows the version of this program\n\n" |
156 |
" $RPM_FAKE_DEBUG ... sets the debuglevel bitmask\n\n" |
157 |
"Please report bugs to " PACKAGE_BUGREPORT "\n"); |
158 |
exit(0); |
159 |
} |
160 |
|
161 |
static void |
162 |
showVersion() |
163 |
{ |
164 |
WRITE_MSG(1, |
165 |
LIBNAME " " VERSION " -- wrapper around rpm\n" |
166 |
"This program is part of " PACKAGE_STRING "\n\n" |
167 |
"Copyright (C) 2003 Enrico Scholz\n" |
168 |
VERSION_COPYRIGHT_DISCLAIMER); |
169 |
exit(0); |
170 |
} |
171 |
|
172 |
static void |
173 |
unsetPreloadEnv() |
174 |
{ |
175 |
char *env = getenv("LD_PRELOAD"); |
176 |
char *pos; |
177 |
|
178 |
// the const <-> non-const assignment is not an issue since the following |
179 |
// modifying operations will not be executed in the const-case |
180 |
env = env ? env : ""; |
181 |
pos = strstr(env, LIBNAME); |
182 |
|
183 |
if (pos!=0) { |
184 |
char *end_pos = pos + sizeof(LIBNAME); |
185 |
bool is_end = (end_pos[-1]=='\0'); |
186 |
char *start_pos; |
187 |
|
188 |
end_pos[-1] = '\0'; |
189 |
start_pos = strrchr(env, ':'); |
190 |
if (start_pos==0) start_pos = env; |
191 |
else if (!is_end) ++start_pos; |
192 |
|
193 |
if (is_end) *start_pos = '\0'; |
194 |
else memmove(start_pos, end_pos, strlen(end_pos)+1); |
195 |
} |
196 |
|
197 |
#ifdef DEBUG |
198 |
if (isDbgLevel(DBG_VERBOSE1|DBG_VARIABLES)) { |
199 |
WRITE_MSG(2, "env='"); |
200 |
WRITE_STR(2, env); |
201 |
WRITE_MSG(2, "'\n"); |
202 |
} |
203 |
#endif |
204 |
|
205 |
if (*env=='\0') unsetenv("LD_PRELOAD"); |
206 |
} |
207 |
|
208 |
static void |
209 |
clearEnv() |
210 |
{ |
211 |
if (isDbgLevel(DBG_ENV)) WRITE_MSG(2, "clearEnv()\n"); |
212 |
|
213 |
unsetenv("RPM_FAKE_S_CONTEXT_REV"); |
214 |
unsetenv("RPM_FAKE_S_CONTEXT_NR"); |
215 |
unsetenv("RPM_FAKE_CTX"); |
216 |
unsetenv("RPM_FAKE_FLAGS"); |
217 |
unsetenv("RPM_FAKE_CHROOT"); |
218 |
unsetenv("RPM_FAKE_NAMESPACE_MOUNTS"); |
219 |
|
220 |
unsetenv("RPM_FAKE_RESOLVER_GID"); |
221 |
unsetenv("RPM_FAKE_RESOLVER_UID"); |
222 |
unsetenv("RPM_FAKE_RESOLVER"); |
223 |
unsetenv("RPM_FAKE_PWSOCKET"); |
224 |
|
225 |
unsetenv("RPM_FAKE_DEBUG"); |
226 |
|
227 |
unsetPreloadEnv(); |
228 |
} |
229 |
|
230 |
static int |
231 |
getDefaultEnv(char const *key, int dflt) |
232 |
{ |
233 |
char *env = getenv(key); |
234 |
int res; |
235 |
|
236 |
if (env==0 || env[0]=='\0') res = dflt; |
237 |
else res = atoi(env); |
238 |
|
239 |
return res; |
240 |
} |
241 |
|
242 |
/// \returns true iff we are in ctx after leaving this function |
243 |
static bool |
244 |
setupContext(xid_t xid, char const **xid_str) |
245 |
{ |
246 |
bool res = false; |
247 |
|
248 |
if (vc_isSupported(vcFEATURE_MIGRATE)) { |
249 |
xid_t rc=VC_NOCTX; |
250 |
|
251 |
if ((xid==VC_DYNAMIC_XID || !vc_is_dynamic_xid(xid)) && |
252 |
(rc=vc_ctx_create(xid))==VC_NOCTX && |
253 |
errno!=EEXIST) { |
254 |
perror(ENSC_WRAPPERS_PREFIX "vc_create_context()"); |
255 |
exit(255); |
256 |
} |
257 |
|
258 |
if (rc!=VC_NOCTX) { |
259 |
char buf[sizeof(xid_t)*3 + 128]; |
260 |
size_t l; |
261 |
struct vc_ctx_caps caps; |
262 |
|
263 |
strcpy(buf, "rpm-fake.so #"); |
264 |
l = utilvserver_fmt_uint(buf+sizeof("rpm-fake.so #")-1, getppid()); |
265 |
Evc_set_vhi_name(rc, vcVHI_CONTEXT, buf, sizeof("rpm-fake.so #")+l-1); |
266 |
|
267 |
caps.ccaps = 0ull; |
268 |
caps.cmask = ~0ull; |
269 |
caps.bcaps = ~vc_get_insecurebcaps(); |
270 |
caps.bmask = ~0ull; |
271 |
Evc_set_ccaps(rc, &caps); |
272 |
|
273 |
// context will be activated later... |
274 |
|
275 |
xid = rc; |
276 |
res = true; |
277 |
} |
278 |
} |
279 |
|
280 |
if (xid==VC_DYNAMIC_XID) |
281 |
*xid_str = 0; |
282 |
else { |
283 |
char buf[sizeof(xid_t)*3 + 2]; |
284 |
size_t l; |
285 |
|
286 |
l = utilvserver_fmt_uint(buf, xid); buf[l] = '\0'; |
287 |
*xid_str = strdup(buf); |
288 |
} |
289 |
|
290 |
Ewrite(3, &xid, sizeof xid); |
291 |
return res; |
292 |
} |
293 |
|
294 |
#if 0 |
295 |
static void |
296 |
initPwSocket() |
297 |
{ |
298 |
char const * sock_name = getenv("RPM_FAKE_PWSOCKET"); |
299 |
if (sock_name!=0) { |
300 |
int flag; |
301 |
struct sockaddr_un addr = { |
302 |
.sun_family = AF_UNIX, |
303 |
}; |
304 |
|
305 |
strncpy(addr.sun_path, sock_name, sizeof(addr.sun_path)-1); |
306 |
addr.sun_path[sizeof(addr.sun_path)-1]='\0'; |
307 |
|
308 |
if ((pw_sock=socket(AF_UNIX, SOCK_STREAM, 0))==-1 || |
309 |
connect(pw_sock, (struct sockaddr *)(&addr), sizeof addr)==-1 || |
310 |
(flag=fcntl(pw_sock, F_GETFD))==-1 || |
311 |
fcntl(pw_sock, F_SETFD, flag | FD_CLOEXEC)==-1) { |
312 |
perror(ENSC_WRAPPERS_PREFIX "error while initializing pw-socket"); |
313 |
exit(255); |
314 |
} |
315 |
} |
316 |
} |
317 |
#else |
318 |
static void |
319 |
initPwSocket() |
320 |
{ |
321 |
char const * resolver = getenv("RPM_FAKE_RESOLVER"); |
322 |
if (resolver==0) resolver=RESOLVER_PROG; |
323 |
|
324 |
if (resolver!=0 && *resolver!='\0') { |
325 |
int res_sock[2]; |
326 |
int sync_pipe[2]; |
327 |
pid_t pid; |
328 |
char const * uid=0; |
329 |
char const * gid=0; |
330 |
|
331 |
uid=getenv("RPM_FAKE_RESOLVER_UID"); |
332 |
gid=getenv("RPM_FAKE_RESOLVER_GID"); |
333 |
|
334 |
if (socketpair(AF_UNIX, SOCK_STREAM, 0, res_sock)==-1 || |
335 |
pipe(sync_pipe)==-1 || |
336 |
fcntl(res_sock[0], F_SETFD, FD_CLOEXEC)==-1 || |
337 |
fcntl(sync_pipe[0], F_SETFD, FD_CLOEXEC)==-1) { |
338 |
perror(ENSC_WRAPPERS_PREFIX "failed to create/initialize resolver-socket or pipe"); |
339 |
exit(255); |
340 |
} |
341 |
|
342 |
pid = fork(); |
343 |
if (pid==-1) { |
344 |
perror(ENSC_WRAPPERS_PREFIX "fork()"); |
345 |
exit(255); |
346 |
} |
347 |
|
348 |
if (pid==0) { |
349 |
char const *args[20]; |
350 |
char const **ptr = args; |
351 |
char const *env[] = { "HOME=/", "PATH=/bin:/usr/bin", 0 }; |
352 |
char const *xid_str; |
353 |
char flag_str[ sizeof(flags)*3 + 2]; |
354 |
char caps_str[ sizeof(caps)*3 + 2]; |
355 |
|
356 |
clearEnv(); |
357 |
|
358 |
setsid(); |
359 |
dup2(res_sock[1], 0); |
360 |
dup2(res_sock[1], 1); |
361 |
if (sync_pipe[1]!=3) { |
362 |
close(3); |
363 |
dup2(sync_pipe[1], 3); |
364 |
close(sync_pipe[1]); |
365 |
} |
366 |
close(res_sock[1]); |
367 |
/* ... *socket[0] are marked as close-on-exec ...*/ |
368 |
|
369 |
flag_str[utilvserver_fmt_uint(flag_str, flags)] = '\0'; |
370 |
caps_str[utilvserver_fmt_uint(caps_str, caps)] = '\0'; |
371 |
|
372 |
*ptr++ = resolver; |
373 |
*ptr++ = "-F"; *ptr++ = flag_str; |
374 |
*ptr++ = "-C"; *ptr++ = caps_str; |
375 |
if (root) { *ptr++ = "-r"; *ptr++ = "."; } |
376 |
if (uid) { *ptr++ = "-u"; *ptr++ = uid; } |
377 |
if (gid) { *ptr++ = "-g"; *ptr++ = gid; } |
378 |
|
379 |
if (root) Echdir(root); |
380 |
|
381 |
if (setupContext(ctx, &xid_str)) { *ptr++ = "-s"; } |
382 |
else if (xid_str) { *ptr++ = "-c"; *ptr++ = xid_str; } |
383 |
|
384 |
*ptr++ = 0; |
385 |
execve(resolver, (char **)args, (char **)env); |
386 |
perror(ENSC_WRAPPERS_PREFIX "failed to exec resolver"); |
387 |
exit(255); |
388 |
} |
389 |
else { |
390 |
uint8_t c; |
391 |
|
392 |
close(res_sock[1]); |
393 |
close(sync_pipe[1]); |
394 |
pw_sock = res_sock[0]; |
395 |
sync_sock = sync_pipe[0]; |
396 |
|
397 |
if (read(sync_sock, &ctx, sizeof ctx)!=sizeof(ctx) || |
398 |
read(sync_sock, &c, 1)!=1 || |
399 |
write(pw_sock, ".", 1)!=1 || |
400 |
read(pw_sock, &c, 1)!=1 || |
401 |
c!='.') { |
402 |
WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "failed to initialize communication with resolver\n"); |
403 |
exit(255); |
404 |
} |
405 |
|
406 |
if (wait4(pid, 0, WNOHANG,0)==-1) { |
407 |
WRITE_MSG(2, ENSC_WRAPPERS_PREFIX" unexpected initialization-error of resolver\n"); |
408 |
exit(255); |
409 |
} |
410 |
} |
411 |
} |
412 |
} |
413 |
#endif |
414 |
|
415 |
static void |
416 |
reduceCapabilities() |
417 |
{ |
418 |
struct __user_cap_header_struct header; |
419 |
struct __user_cap_data_struct user; |
420 |
|
421 |
header.version = _LINUX_CAPABILITY_VERSION; |
422 |
header.pid = 0; |
423 |
|
424 |
if (capget(&header, &user)==-1) { |
425 |
perror("capget()"); |
426 |
exit(wrapper_exit_code); |
427 |
} |
428 |
|
429 |
user.effective &= ~(1<<CAP_MKNOD); |
430 |
user.permitted &= ~(1<<CAP_MKNOD); |
431 |
user.inheritable &= ~(1<<CAP_MKNOD); |
432 |
|
433 |
if (capset(&header, &user)==-1) { |
434 |
perror("capset()"); |
435 |
exit(wrapper_exit_code); |
436 |
} |
437 |
} |
438 |
|
439 |
static void |
440 |
initEnvironment() |
441 |
{ |
442 |
int syscall_rev; |
443 |
int syscall_nr; |
444 |
|
445 |
if (is_initialized) return; |
446 |
|
447 |
syscall_rev = getDefaultEnv("RPM_FAKE_S_CONTEXT_REV", 0); |
448 |
syscall_nr = getDefaultEnv("RPM_FAKE_S_CONTEXT_NR", 273); |
449 |
|
450 |
#ifdef VC_ENABLE_API_LEGACY |
451 |
{ |
452 |
extern void vc_init_internal_legacy(int ctx_rev, int ctx_number, |
453 |
int ipv4_rev, int ipv4_number); |
454 |
|
455 |
vc_init_internal_legacy(syscall_rev, syscall_nr, 3, 274); |
456 |
} |
457 |
#endif |
458 |
|
459 |
ctx = getDefaultEnv("RPM_FAKE_CTX", VC_DYNAMIC_XID); |
460 |
caps = getDefaultEnv("RPM_FAKE_CAP", ~0x3404040f); |
461 |
flags = getDefaultEnv("RPM_FAKE_FLAGS", 0); |
462 |
root = getenv("RPM_FAKE_CHROOT"); |
463 |
mnts = getenv("RPM_FAKE_NAMESPACE_MOUNTS"); |
464 |
if (mnts && *mnts) mnts = strdup(mnts); |
465 |
else mnts = 0; |
466 |
|
467 |
#if DEBUG |
468 |
if (isDbgLevel(DBG_VERBOSE1)) |
469 |
dprintf(2, "ctx=%u, caps=%016x, flags=%016x,\nroot='%s',\nmnts='%s'\n", |
470 |
ctx, caps, flags, root, mnts); |
471 |
#endif |
472 |
|
473 |
is_initialized = true; |
474 |
} |
475 |
|
476 |
static void |
477 |
initSymbols() |
478 |
{ |
479 |
//INIT(RTLD_NEXT, rpm_execcon); |
480 |
//INIT(RTLD_NEXT, execv); |
481 |
INIT(RTLD_NEXT, getgrnam); |
482 |
INIT(RTLD_NEXT, getpwnam); |
483 |
INIT(RTLD_NEXT, endpwent); |
484 |
INIT(RTLD_NEXT, endgrent); |
485 |
} |
486 |
|
487 |
void |
488 |
initRPMFake() |
489 |
{ |
490 |
if (getenv("RPM_FAKE_VERSION")) showVersion(); |
491 |
if (getenv("RPM_FAKE_HELP")) showHelp(); |
492 |
|
493 |
debug_level = getDefaultEnv("RPM_FAKE_DEBUG", 0); |
494 |
|
495 |
if (isDbgLevel(DBG_INIT)) WRITE_MSG(2, ">>>>> initRPMFake <<<<<\n"); |
496 |
|
497 |
reduceCapabilities(); |
498 |
initSymbols(); |
499 |
initEnvironment(); |
500 |
initPwSocket(); |
501 |
|
502 |
#if 0 |
503 |
if (isDbgLevel(DBG_VARIABLES|DBG_VERBOSE2)) { |
504 |
|
505 |
} |
506 |
#endif |
507 |
} |
508 |
|
509 |
void |
510 |
exitRPMFake() |
511 |
{ |
512 |
if (isDbgLevel(DBG_INIT)) WRITE_MSG(2, ">>>>> exitRPMFake <<<<<\n"); |
513 |
if (pw_sock!=-1) { |
514 |
uint8_t c; |
515 |
if (read(sync_sock, &c, 1)!=1) { /*...*/ } |
516 |
if (write(pw_sock, "Q", 1)!=1) { /*...*/ } |
517 |
} |
518 |
} |
519 |
|
520 |
|
521 |
//============ the worker part =========== |
522 |
|
523 |
|
524 |
static bool |
525 |
doPwStringRequest(uint32_t *result, char style, char const *name) |
526 |
{ |
527 |
size_t len = strlen(name); |
528 |
uint8_t code; |
529 |
uint8_t c; |
530 |
|
531 |
return (TEMP_FAILURE_RETRY(read (sync_sock, &c, 1))==1 && |
532 |
|
533 |
TEMP_FAILURE_RETRY(write(pw_sock, &style, 1))==1 && |
534 |
TEMP_FAILURE_RETRY(write(pw_sock, &len, sizeof len))==sizeof(len) && |
535 |
TEMP_FAILURE_RETRY(write(pw_sock, name, len))==(ssize_t)(len) && |
536 |
TEMP_FAILURE_RETRY(read (pw_sock, &code, sizeof code))==sizeof(code) && |
537 |
TEMP_FAILURE_RETRY(read (pw_sock, result, sizeof *result))==sizeof(*result) && |
538 |
code!=0); |
539 |
} |
540 |
|
541 |
struct passwd * |
542 |
getpwnam(const char * name) |
543 |
{ |
544 |
if (pw_sock==-1) return getpwnam_func(name); |
545 |
else { |
546 |
static struct passwd res = { |
547 |
.pw_passwd = "*", |
548 |
.pw_gid = -1, |
549 |
.pw_gecos = "", |
550 |
.pw_dir = "/", |
551 |
.pw_shell = "/bin/false" |
552 |
}; |
553 |
|
554 |
res.pw_name = (char *)(name); |
555 |
if (!doPwStringRequest(&res.pw_uid, 'P', name)) return 0; |
556 |
|
557 |
return &res; |
558 |
} |
559 |
} |
560 |
|
561 |
struct group * |
562 |
getgrnam(const char * name) |
563 |
{ |
564 |
if (pw_sock==-1) return getgrnam_func(name); |
565 |
else { |
566 |
static struct group res = { |
567 |
.gr_passwd = "*", |
568 |
.gr_mem = 0 |
569 |
}; |
570 |
|
571 |
res.gr_name = (char *)(name); |
572 |
if (!doPwStringRequest(&res.gr_gid, 'G', name)) return 0; |
573 |
|
574 |
return &res; |
575 |
} |
576 |
} |
577 |
|
578 |
void |
579 |
endgrent() |
580 |
{ |
581 |
if (pw_sock==-1) endgrent_func(); |
582 |
TEMP_FAILURE_RETRY(write(pw_sock, "Cg", 2)); |
583 |
} |
584 |
|
585 |
void |
586 |
endpwent() |
587 |
{ |
588 |
if (pw_sock==-1) endpwent_func(); |
589 |
TEMP_FAILURE_RETRY(write(pw_sock, "Cp", 2)); |
590 |
} |
591 |
|
592 |
|
593 |
static int |
594 |
execvWorker(char const *path, char * const argv[], char * const envp[]) |
595 |
{ |
596 |
int res = -1; |
597 |
|
598 |
if (vc_isSupported(vcFEATURE_MIGRATE)) |
599 |
res = vc_ctx_migrate(ctx); |
600 |
else { |
601 |
#ifdef VC_ENABLE_API_COMPAT |
602 |
res = vc_new_s_context(ctx,caps,flags); |
603 |
#else |
604 |
WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "can not change context: migrate kernel feature missing and 'compat' API disabled\n"); |
605 |
#endif |
606 |
} |
607 |
|
608 |
clearEnv(); |
609 |
|
610 |
if (res!=-1) |
611 |
res=execve(path, argv, envp); |
612 |
|
613 |
return res; |
614 |
} |
615 |
|
616 |
struct ExecvParams |
617 |
{ |
618 |
char const * path; |
619 |
char * const * argv; |
620 |
char * const * envp; |
621 |
char const * mnts; |
622 |
}; |
623 |
|
624 |
static int |
625 |
removeNamespaceMountsChild(struct ExecvParams const *params) |
626 |
{ |
627 |
char buf[strlen(params->mnts)+1], *ptr; |
628 |
|
629 |
strcpy(buf, params->mnts); |
630 |
ptr = strtok(buf, ":"); |
631 |
while (ptr) { |
632 |
if (umount2(ptr, 0)==-1) { |
633 |
// FIXME: What is the semantic for CLONE_NEWNS? Is it ok that mounts in |
634 |
// chroots are visible only, when chroot is on /dev/root? |
635 |
// |
636 |
// For now, ignore any errors, but future versions should handle them. |
637 |
|
638 |
//return -1; |
639 |
} |
640 |
ptr = strtok(0, ":"); |
641 |
} |
642 |
|
643 |
return execvWorker(params->path, params->argv, params->envp); |
644 |
} |
645 |
|
646 |
static int |
647 |
removeNamespaceMounts(char const *path, |
648 |
char * const argv[], char * const envp[]) |
649 |
{ |
650 |
if (mnts==0) return execvWorker(path, argv, envp); |
651 |
|
652 |
{ |
653 |
int status; |
654 |
pid_t p, pid; |
655 |
struct ExecvParams params; |
656 |
|
657 |
params.path = path; |
658 |
params.argv = argv; |
659 |
params.envp = envp; |
660 |
params.mnts = mnts; |
661 |
|
662 |
// the rpmlib signal-handler is still active; use the default one to |
663 |
// make wait4() working... |
664 |
signal(SIGCHLD, SIG_DFL); |
665 |
|
666 |
#ifdef NDEBUG |
667 |
pid = sys_clone(CLONE_NEWNS|SIGCHLD|CLONE_VFORK, 0); |
668 |
#else |
669 |
pid = sys_clone(CLONE_NEWNS|SIGCHLD, 0); |
670 |
#endif |
671 |
|
672 |
switch (pid) { |
673 |
case -1 : return -1; |
674 |
case 0 : _exit(removeNamespaceMountsChild(¶ms)); |
675 |
default : break; |
676 |
} |
677 |
|
678 |
while ((p=wait4(pid, &status, 0,0))==-1 && |
679 |
(errno==EINTR || errno==EAGAIN)) ; |
680 |
|
681 |
if (p==-1) return -1; |
682 |
|
683 |
if (WIFEXITED(status)) _exit(WEXITSTATUS(status)); |
684 |
if (WIFSIGNALED(status)) kill(getpid(), WTERMSIG(status)); |
685 |
|
686 |
return -1; |
687 |
} |
688 |
} |
689 |
|
690 |
|
691 |
int |
692 |
execv(char const *path, char * const argv[]) |
693 |
{ |
694 |
extern char **environ; |
695 |
|
696 |
if (isDbgLevel(DBG_EXECV)) { |
697 |
WRITE_MSG(2, "execv('"); |
698 |
WRITE_STR(2, path); |
699 |
WRITE_MSG(2, "', ...)\n"); |
700 |
} |
701 |
|
702 |
return removeNamespaceMounts(path, argv, environ); |
703 |
} |
704 |
|
705 |
int |
706 |
rpm_execcon(unsigned int UNUSED verified, |
707 |
const char *filename, |
708 |
char *const argv[], char *const envp[]) |
709 |
{ |
710 |
if (isDbgLevel(DBG_EXECV)) { |
711 |
WRITE_MSG(2, "rpm_execcon(..., '"); |
712 |
WRITE_STR(2, filename); |
713 |
WRITE_MSG(2, "', ...)\n"); |
714 |
} |
715 |
|
716 |
return removeNamespaceMounts(filename, argv, envp); |
717 |
} |
718 |
|
719 |
int |
720 |
is_selinux_enabled() |
721 |
{ |
722 |
return 0; |
723 |
} |