run_as: adapt run_as implementation to support complex payloads
[lttng-tools.git] / src / common / runas.c
CommitLineData
60b6c79c
MD
1/*
2 * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
3 * Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
4 *
d14d33bf
AM
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License, version 2 only,
7 * as published by the Free Software Foundation.
60b6c79c
MD
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
d14d33bf 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
60b6c79c
MD
12 * more details.
13 *
d14d33bf
AM
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
60b6c79c
MD
17 */
18
6c1c0768 19#define _LGPL_SOURCE
60b6c79c
MD
20#include <errno.h>
21#include <limits.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <sys/wait.h>
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <unistd.h>
29#include <fcntl.h>
c2b75c49 30#include <sched.h>
0452bf08 31#include <signal.h>
749b7a0c 32#include <assert.h>
e1055edb 33#include <signal.h>
60b6c79c 34
90e535ef 35#include <common/common.h>
3fd15a74 36#include <common/utils.h>
e8fa9fb0 37#include <common/compat/getenv.h>
e1055edb 38#include <common/compat/prctl.h>
2038dd6c
JG
39#include <common/unix.h>
40#include <common/defaults.h>
60b6c79c 41
0857097f
DG
42#include "runas.h"
43
7567352f 44struct run_as_data;
fe9f7760
FD
45struct run_as_ret;
46typedef int (*run_as_fct)(struct run_as_data *data, struct run_as_ret *ret_value);
c2b75c49 47
e11d277b 48struct run_as_mkdir_data {
7567352f 49 char path[PATH_MAX];
60b6c79c
MD
50 mode_t mode;
51};
52
e11d277b 53struct run_as_open_data {
7567352f 54 char path[PATH_MAX];
60b6c79c
MD
55 int flags;
56 mode_t mode;
57};
58
4628484a 59struct run_as_unlink_data {
7567352f 60 char path[PATH_MAX];
4628484a
MD
61};
62
7567352f
MD
63struct run_as_rmdir_recursive_data {
64 char path[PATH_MAX];
65};
66
fe9f7760
FD
67struct run_as_mkdir_ret {
68 int ret;
69};
70
71struct run_as_open_ret {
72 int ret;
73};
74
75struct run_as_unlink_ret {
76 int ret;
77};
78
79struct run_as_rmdir_recursive_ret {
80 int ret;
81};
82
7567352f
MD
83enum run_as_cmd {
84 RUN_AS_MKDIR,
85 RUN_AS_OPEN,
86 RUN_AS_UNLINK,
87 RUN_AS_RMDIR_RECURSIVE,
88 RUN_AS_MKDIR_RECURSIVE,
89};
90
91struct run_as_data {
92 enum run_as_cmd cmd;
fe9f7760 93 int fd;
7567352f
MD
94 union {
95 struct run_as_mkdir_data mkdir;
96 struct run_as_open_data open;
97 struct run_as_unlink_data unlink;
98 struct run_as_rmdir_recursive_data rmdir_recursive;
99 } u;
100 uid_t uid;
101 gid_t gid;
4628484a
MD
102};
103
fe9f7760
FD
104/*
105 * The run_as_ret structure holds the returned value and status of the command.
106 *
107 * The `u` union field holds the return value of the command; in most cases it
108 * represents the success or the failure of the command. In more complex
109 * commands, it holds a computed value.
110 *
111 * The _errno field is the errno recorded after the execution of the command.
112 *
113 * The _error fields is used the signify that return status of the command. For
114 * simple commands returning `int` the _error field will be the same as the
115 * ret_int field. In complex commands, it signify the success or failure of the
116 * command.
117 *
118 */
df5b86c8 119struct run_as_ret {
fe9f7760
FD
120 int fd;
121 union {
122 struct run_as_mkdir_ret mkdir;
123 struct run_as_open_ret open;
124 struct run_as_unlink_ret unlink;
125 struct run_as_rmdir_recursive_ret rmdir_recursive;
126 } u;
df5b86c8 127 int _errno;
fe9f7760 128 bool _error;
df5b86c8
MD
129};
130
7567352f
MD
131struct run_as_worker {
132 pid_t pid; /* Worker PID. */
133 int sockpair[2];
134 char *procname;
135};
136
137/* Single global worker per process (for now). */
138static struct run_as_worker *global_worker;
139/* Lock protecting the worker. */
140static pthread_mutex_t worker_lock = PTHREAD_MUTEX_INITIALIZER;
141
8f0044bf
MD
142#ifdef VALGRIND
143static
144int use_clone(void)
145{
146 return 0;
147}
148#else
149static
150int use_clone(void)
151{
e8fa9fb0 152 return !lttng_secure_getenv("LTTNG_DEBUG_NOCLONE");
8f0044bf
MD
153}
154#endif
155
d77dded2
JG
156LTTNG_HIDDEN
157int _utils_mkdir_recursive_unsafe(const char *path, mode_t mode);
158
60b6c79c
MD
159/*
160 * Create recursively directory using the FULL path.
161 */
162static
fe9f7760 163int _mkdir_recursive(struct run_as_data *data, struct run_as_ret *ret_value)
60b6c79c 164{
60b6c79c 165 const char *path;
60b6c79c 166 mode_t mode;
60b6c79c 167
7567352f
MD
168 path = data->u.mkdir.path;
169 mode = data->u.mkdir.mode;
60b6c79c 170
d77dded2 171 /* Safe to call as we have transitioned to the requested uid/gid. */
fe9f7760
FD
172 ret_value->u.mkdir.ret = _utils_mkdir_recursive_unsafe(path, mode);
173 ret_value->_errno = errno;
174 ret_value->_error = (ret_value->u.mkdir.ret) ? true : false;
175 return ret_value->u.mkdir.ret;
60b6c79c
MD
176}
177
178static
fe9f7760 179int _mkdir(struct run_as_data *data, struct run_as_ret *ret_value)
60b6c79c 180{
fe9f7760
FD
181 ret_value->u.mkdir.ret = mkdir(data->u.mkdir.path, data->u.mkdir.mode);
182 ret_value->_errno = errno;
183 ret_value->_error = (ret_value->u.mkdir.ret) ? true : false;
184 return ret_value->u.mkdir.ret;
7567352f 185}
7ce36756 186
7567352f 187static
fe9f7760 188int _open(struct run_as_data *data, struct run_as_ret *ret_value)
7567352f 189{
fe9f7760
FD
190 ret_value->u.open.ret = open(data->u.open.path, data->u.open.flags, data->u.open.mode);
191 ret_value->fd = ret_value->u.open.ret;
192 ret_value->_errno = errno;
193 ret_value->_error = (ret_value->u.open.ret) ? true : false;
194 return ret_value->u.open.ret;
7567352f
MD
195}
196
197static
fe9f7760 198int _unlink(struct run_as_data *data, struct run_as_ret *ret_value)
7567352f 199{
fe9f7760
FD
200 ret_value->u.unlink.ret = unlink(data->u.unlink.path);
201 ret_value->_errno = errno;
202 ret_value->_error = (ret_value->u.unlink.ret) ? true : false;
203 return ret_value->u.unlink.ret;
60b6c79c
MD
204}
205
206static
fe9f7760 207int _rmdir_recursive(struct run_as_data *data, struct run_as_ret *ret_value)
60b6c79c 208{
fe9f7760
FD
209 ret_value->u.rmdir_recursive.ret = utils_recursive_rmdir(data->u.rmdir_recursive.path);
210 ret_value->_errno = errno;
211 ret_value->_error = (ret_value->u.rmdir_recursive.ret) ? true : false;
212 return ret_value->u.rmdir_recursive.ret;
7567352f 213}
df5b86c8 214
7567352f
MD
215static
216run_as_fct run_as_enum_to_fct(enum run_as_cmd cmd)
217{
218 switch (cmd) {
219 case RUN_AS_MKDIR:
220 return _mkdir;
221 case RUN_AS_OPEN:
222 return _open;
223 case RUN_AS_UNLINK:
224 return _unlink;
225 case RUN_AS_RMDIR_RECURSIVE:
226 return _rmdir_recursive;
227 case RUN_AS_MKDIR_RECURSIVE:
228 return _mkdir_recursive;
229 default:
62a7b8ed 230 ERR("Unknown command %d", (int) cmd);
7567352f
MD
231 return NULL;
232 }
60b6c79c
MD
233}
234
4628484a 235static
fe9f7760 236int do_send_fd(int sock, int fd)
4628484a 237{
7567352f 238 ssize_t len;
4628484a 239
7567352f 240 if (fd < 0) {
fe9f7760 241 ERR("Invalid file description");
7567352f
MD
242 return 0;
243 }
fe9f7760
FD
244
245 len = lttcomm_send_fds_unix_sock(sock, &fd, 1);
7567352f
MD
246 if (len < 0) {
247 PERROR("lttcomm_send_fds_unix_sock");
248 return -1;
249 }
7567352f 250 return 0;
4628484a
MD
251}
252
253static
fe9f7760 254int do_recv_fd(int sock, int *fd)
4628484a 255{
7567352f 256 ssize_t len;
4628484a 257
7567352f 258 if (*fd < 0) {
fe9f7760 259 ERR("Invalid file description");
7567352f
MD
260 return 0;
261 }
fe9f7760
FD
262
263 len = lttcomm_recv_fds_unix_sock(sock, fd, 1);
264
da9ee832
JG
265 if (!len) {
266 return -1;
267 } else if (len < 0) {
7567352f
MD
268 PERROR("lttcomm_recv_fds_unix_sock");
269 return -1;
270 }
271 return 0;
4628484a
MD
272}
273
fe9f7760
FD
274static
275int send_fd_to_worker(struct run_as_worker *worker, enum run_as_cmd cmd, int fd)
276{
277 int ret = 0;
278
279 switch (cmd) {
280 default:
281 return 0;
282 }
283
284 ret = do_send_fd(worker->sockpair[0], fd);
285 if (ret < 0) {
286 PERROR("do_send_fd");
287 ret = -1;
288 }
289
290 return ret;
291}
292
293static
294int send_fd_to_master(struct run_as_worker *worker, enum run_as_cmd cmd, int fd)
295{
296 int ret = 0, ret_close = 0;
297
298 switch (cmd) {
299 case RUN_AS_OPEN:
300 break;
301 default:
302 return 0;
303 }
304
305 ret = do_send_fd(worker->sockpair[1], fd);
306 if (ret < 0) {
307 PERROR("do_send_fd error");
308 ret = -1;
309 }
310
311 ret_close = close(fd);
312 if (ret_close < 0) {
313 PERROR("close");
314 }
315
316 return ret;
317}
318
319static
320int recv_fd_from_worker(struct run_as_worker *worker, enum run_as_cmd cmd, int *fd)
321{
322 int ret = 0;
323
324 switch (cmd) {
325 case RUN_AS_OPEN:
326 break;
327 default:
328 return 0;
329 }
330
331 ret = do_recv_fd(worker->sockpair[0], fd);
332 if (ret < 0) {
333 PERROR("do_recv_fd error");
334 ret = -1;
335 }
336
337 return ret;
338}
339
340static
341int recv_fd_from_master(struct run_as_worker *worker, enum run_as_cmd cmd, int *fd)
342{
343 int ret = 0;
344
345 switch (cmd) {
346 default:
347 return 0;
348 }
349
350 ret = do_recv_fd(worker->sockpair[1], fd);
351 if (ret < 0) {
352 PERROR("do_recv_fd error");
353 ret = -1;
354 }
355
356 return ret;
357}
358
359static
360int cleanup_received_fd(enum run_as_cmd cmd, int fd)
361{
362 int ret = 0;
363
364 switch (cmd) {
365 default:
366 return 0;
367 }
368
369 ret = close(fd);
370 if (ret < 0) {
371 PERROR("close error");
372 ret = -1;
373 }
374
375 return ret;
376}
7567352f
MD
377/*
378 * Return < 0 on error, 0 if OK, 1 on hangup.
379 */
c2b75c49 380static
7567352f 381int handle_one_cmd(struct run_as_worker *worker)
c2b75c49 382{
7567352f
MD
383 int ret = 0;
384 struct run_as_data data;
385 ssize_t readlen, writelen;
df5b86c8 386 struct run_as_ret sendret;
7567352f
MD
387 run_as_fct cmd;
388 uid_t prev_euid;
389
fe9f7760
FD
390 /*
391 * Stage 1: Receive run_as_data struct from the master.
392 * The structure contains the command type and all the parameters needed for
393 * its execution
394 */
7567352f
MD
395 readlen = lttcomm_recv_unix_sock(worker->sockpair[1], &data,
396 sizeof(data));
397 if (readlen == 0) {
398 /* hang up */
399 ret = 1;
400 goto end;
401 }
402 if (readlen < sizeof(data)) {
403 PERROR("lttcomm_recv_unix_sock error");
404 ret = -1;
405 goto end;
406 }
c2b75c49 407
7567352f
MD
408 cmd = run_as_enum_to_fct(data.cmd);
409 if (!cmd) {
410 ret = -1;
411 goto end;
412 }
413
fe9f7760
FD
414 /*
415 * Stage 2: Receive file descriptor from master.
416 * Some commands need a file descriptor as input so if it's needed we
417 * receive the fd using the Unix socket.
418 */
419 ret = recv_fd_from_master(worker, data.cmd, &data.fd);
420 if (ret < 0) {
421 PERROR("recv_fd_from_master error");
422 ret = -1;
423 goto end;
424 }
425
7567352f
MD
426 prev_euid = getuid();
427 if (data.gid != getegid()) {
428 ret = setegid(data.gid);
1576d582 429 if (ret < 0) {
4c462e79 430 PERROR("setegid");
6d73c4ef 431 goto write_return;
1576d582 432 }
c2b75c49 433 }
7567352f
MD
434 if (data.uid != prev_euid) {
435 ret = seteuid(data.uid);
1576d582 436 if (ret < 0) {
4c462e79 437 PERROR("seteuid");
6d73c4ef 438 goto write_return;
1576d582 439 }
c2b75c49 440 }
fe9f7760 441
c2b75c49
MD
442 /*
443 * Also set umask to 0 for mkdir executable bit.
444 */
445 umask(0);
fe9f7760
FD
446
447 /*
448 * Stage 3: Execute the command
449 */
450 ret = (*cmd)(&data, &sendret);
451 if (ret < 0) {
452 DBG("Execution of command returned an error");
453 }
6d73c4ef
MD
454
455write_return:
fe9f7760
FD
456 ret = cleanup_received_fd(data.cmd, data.fd);
457 if (ret < 0) {
458 ERR("Error cleaning up FD");
459 goto end;
460 }
461
462 /*
463 * Stage 4: Send run_as_ret structure to the master.
464 * This structure contain the return value of the command and the errno.
465 */
7567352f
MD
466 writelen = lttcomm_send_unix_sock(worker->sockpair[1], &sendret,
467 sizeof(sendret));
6cd525e8 468 if (writelen < sizeof(sendret)) {
7567352f
MD
469 PERROR("lttcomm_send_unix_sock error");
470 ret = -1;
471 goto end;
472 }
fe9f7760
FD
473
474 /*
475 * Stage 5: Send file descriptor to the master
476 * Some commands return a file descriptor so if it's needed we pass it back
477 * to the master using the Unix socket.
478 */
479 ret = send_fd_to_master(worker, data.cmd, sendret.fd);
480 if (ret < 0) {
481 DBG("Sending FD to master returned an error");
7567352f
MD
482 goto end;
483 }
fe9f7760 484
7567352f
MD
485 if (seteuid(prev_euid) < 0) {
486 PERROR("seteuid");
487 ret = -1;
488 goto end;
489 }
490 ret = 0;
491end:
492 return ret;
493}
494
495static
496int run_as_worker(struct run_as_worker *worker)
497{
498 int ret;
499 ssize_t writelen;
500 struct run_as_ret sendret;
501 size_t proc_orig_len;
502
503 /*
504 * Initialize worker. Set a different process cmdline.
505 */
506 proc_orig_len = strlen(worker->procname);
507 memset(worker->procname, 0, proc_orig_len);
508 strncpy(worker->procname, DEFAULT_RUN_AS_WORKER_NAME, proc_orig_len);
509
e1055edb
JG
510 ret = lttng_prctl(PR_SET_NAME,
511 (unsigned long) DEFAULT_RUN_AS_WORKER_NAME, 0, 0, 0);
512 if (ret && ret != -ENOSYS) {
b8090274
JG
513 /* Don't fail as this is not essential. */
514 PERROR("prctl PR_SET_NAME");
6cd525e8 515 }
7567352f 516
fe9f7760
FD
517 memset(&sendret, 0, sizeof(sendret));
518
7567352f
MD
519 writelen = lttcomm_send_unix_sock(worker->sockpair[1], &sendret,
520 sizeof(sendret));
521 if (writelen < sizeof(sendret)) {
522 PERROR("lttcomm_send_unix_sock error");
523 ret = EXIT_FAILURE;
524 goto end;
525 }
526
527 for (;;) {
528 ret = handle_one_cmd(worker);
529 if (ret < 0) {
530 ret = EXIT_FAILURE;
531 goto end;
532 } else if (ret > 0) {
533 break;
534 } else {
535 continue; /* Next command. */
536 }
537 }
538 ret = EXIT_SUCCESS;
539end:
540 return ret;
c2b75c49
MD
541}
542
60b6c79c 543static
7567352f
MD
544int run_as_cmd(struct run_as_worker *worker,
545 enum run_as_cmd cmd,
546 struct run_as_data *data,
fe9f7760 547 struct run_as_ret *ret_value,
7567352f 548 uid_t uid, gid_t gid)
60b6c79c 549{
fe9f7760 550 int ret = 0;
7567352f 551 ssize_t readlen, writelen;
60b6c79c
MD
552
553 /*
554 * If we are non-root, we can only deal with our own uid.
555 */
556 if (geteuid() != 0) {
557 if (uid != geteuid()) {
fe9f7760
FD
558 ret = -1;
559 ret_value->_errno = EPERM;
60b6c79c 560 ERR("Client (%d)/Server (%d) UID mismatch (and sessiond is not root)",
08797918 561 (int) uid, (int) geteuid());
df5b86c8 562 goto end;
60b6c79c 563 }
60b6c79c
MD
564 }
565
7567352f
MD
566 data->cmd = cmd;
567 data->uid = uid;
568 data->gid = gid;
569
fe9f7760
FD
570 /*
571 * Stage 1: Send the run_as_data struct to the worker process
572 */
7567352f
MD
573 writelen = lttcomm_send_unix_sock(worker->sockpair[0], data,
574 sizeof(*data));
575 if (writelen < sizeof(*data)) {
576 PERROR("Error writing message to run_as");
fe9f7760
FD
577 ret = -1;
578 ret_value->_errno = EIO;
60b6c79c 579 goto end;
c2b75c49 580 }
7567352f 581
fe9f7760
FD
582 /*
583 * Stage 2: Send file descriptor to the worker process if needed
584 */
585 ret = send_fd_to_worker(worker, data->cmd, data->fd);
586 if (ret) {
587 PERROR("do_send_fd error");
588 ret = -1;
589 ret_value->_errno = EIO;
590 goto end;
591 }
592
593 /*
594 * Stage 3: Wait for the execution of the command
595 */
596
597 /*
598 * Stage 4: Receive the run_as_ret struct containing the return value and
599 * errno
600 */
601 readlen = lttcomm_recv_unix_sock(worker->sockpair[0], ret_value,
602 sizeof(*ret_value));
da9ee832
JG
603 if (!readlen) {
604 ERR("Run-as worker has hung-up during run_as_cmd");
fe9f7760
FD
605 ret = -1;
606 ret_value->_errno = EIO;
da9ee832 607 goto end;
fe9f7760 608 } else if (readlen < sizeof(*ret_value)) {
7567352f 609 PERROR("Error reading response from run_as");
fe9f7760
FD
610 ret = -1;
611 ret_value->_errno = errno;
6cd525e8 612 }
fe9f7760
FD
613
614 /*
615 * Stage 5: Receive file descriptor if needed
616 */
617 ret = recv_fd_from_worker(worker, data->cmd, &ret_value->fd);
618 if (ret < 0) {
619 ERR("Error receiving fd");
620 ret = -1;
621 ret_value->_errno = EIO;
4c462e79 622 }
7567352f 623
60b6c79c 624end:
fe9f7760 625 return ret;
60b6c79c
MD
626}
627
2d85a600 628/*
7567352f 629 * This is for debugging ONLY and should not be considered secure.
2d85a600
MD
630 */
631static
fe9f7760
FD
632int run_as_noworker(enum run_as_cmd cmd,
633 struct run_as_data *data, struct run_as_ret *ret_value,
634 uid_t uid, gid_t gid)
2d85a600 635{
df5b86c8 636 int ret, saved_errno;
5b73926f 637 mode_t old_mask;
7567352f 638 run_as_fct fct;
5b73926f 639
7567352f
MD
640 fct = run_as_enum_to_fct(cmd);
641 if (!fct) {
642 errno = -ENOSYS;
643 ret = -1;
644 goto end;
645 }
5b73926f 646 old_mask = umask(0);
fe9f7760
FD
647 ret = fct(data, ret_value);
648 saved_errno = ret_value->_errno;
5b73926f 649 umask(old_mask);
df5b86c8 650 errno = saved_errno;
7567352f 651end:
5b73926f 652 return ret;
2d85a600
MD
653}
654
655static
fe9f7760 656int run_as_restart_worker(struct run_as_worker *worker)
2d85a600 657{
fe9f7760
FD
658 int ret = 0;
659 char *procname = NULL;
660
661 procname = worker->procname;
662
663 /* Close socket to run_as worker process and clean up the zombie process */
664 run_as_destroy_worker();
665
666 /* Create a new run_as worker process*/
667 ret = run_as_create_worker(procname);
668 if (ret < 0 ) {
669 ERR("Restarting the worker process failed");
670 ret = -1;
671 goto err;
672 }
673err:
674 return ret;
675}
676
677static
678int run_as(enum run_as_cmd cmd, struct run_as_data *data,
679 struct run_as_ret *ret_value, uid_t uid, gid_t gid)
680{
681 int ret, saved_errno;
7567352f 682
749b7a0c 683 if (use_clone()) {
7567352f 684 DBG("Using run_as worker");
749b7a0c
JG
685 pthread_mutex_lock(&worker_lock);
686 assert(global_worker);
749b7a0c 687
fe9f7760
FD
688 ret = run_as_cmd(global_worker, cmd, data, ret_value, uid, gid);
689 saved_errno = ret_value->_errno;
690
691 pthread_mutex_unlock(&worker_lock);
692 /*
693 * If the worker thread crashed the errno is set to EIO. we log
694 * the error and start a new worker process.
695 */
696 if (ret == -1 && saved_errno == EIO) {
697 DBG("Socket closed unexpectedly... "
698 "Restarting the worker process");
699 ret = run_as_restart_worker(global_worker);
700
701 if (ret == -1) {
702 ERR("Failed to restart worker process.");
703 goto err;
704 }
705 }
2d85a600 706 } else {
7567352f 707 DBG("Using run_as without worker");
fe9f7760 708 ret = run_as_noworker(cmd, data, ret_value, uid, gid);
2d85a600 709 }
fe9f7760 710err:
7567352f 711 return ret;
2d85a600
MD
712}
713
90e535ef 714LTTNG_HIDDEN
e11d277b 715int run_as_mkdir_recursive(const char *path, mode_t mode, uid_t uid, gid_t gid)
60b6c79c 716{
7567352f 717 struct run_as_data data;
fe9f7760 718 struct run_as_ret ret;
60b6c79c 719
8446e5eb 720 memset(&data, 0, sizeof(data));
fe9f7760 721 memset(&ret, 0, sizeof(ret));
60b6c79c 722 DBG3("mkdir() recursive %s with mode %d for uid %d and gid %d",
08797918 723 path, (int) mode, (int) uid, (int) gid);
7567352f
MD
724 strncpy(data.u.mkdir.path, path, PATH_MAX - 1);
725 data.u.mkdir.path[PATH_MAX - 1] = '\0';
726 data.u.mkdir.mode = mode;
fe9f7760
FD
727
728 run_as(RUN_AS_MKDIR_RECURSIVE, &data, &ret, uid, gid);
729 errno = ret._errno;
730 return ret.u.mkdir.ret;
60b6c79c
MD
731}
732
90e535ef 733LTTNG_HIDDEN
e11d277b 734int run_as_mkdir(const char *path, mode_t mode, uid_t uid, gid_t gid)
60b6c79c 735{
7567352f 736 struct run_as_data data;
fe9f7760 737 struct run_as_ret ret;
60b6c79c 738
8446e5eb 739 memset(&data, 0, sizeof(data));
fe9f7760
FD
740 memset(&ret, 0, sizeof(ret));
741
60b6c79c 742 DBG3("mkdir() %s with mode %d for uid %d and gid %d",
08797918 743 path, (int) mode, (int) uid, (int) gid);
7567352f
MD
744 strncpy(data.u.mkdir.path, path, PATH_MAX - 1);
745 data.u.mkdir.path[PATH_MAX - 1] = '\0';
746 data.u.mkdir.mode = mode;
fe9f7760
FD
747 run_as(RUN_AS_MKDIR, &data, &ret, uid, gid);
748 errno = ret._errno;
749 return ret.u.mkdir.ret;
60b6c79c
MD
750}
751
90e535ef 752LTTNG_HIDDEN
e11d277b 753int run_as_open(const char *path, int flags, mode_t mode, uid_t uid, gid_t gid)
60b6c79c 754{
7567352f 755 struct run_as_data data;
fe9f7760 756 struct run_as_ret ret;
c2b75c49 757
8446e5eb 758 memset(&data, 0, sizeof(data));
fe9f7760
FD
759 memset(&ret, 0, sizeof(ret));
760
47fb7563 761 DBG3("open() %s with flags %X mode %d for uid %d and gid %d",
08797918 762 path, flags, (int) mode, (int) uid, (int) gid);
7567352f
MD
763 strncpy(data.u.open.path, path, PATH_MAX - 1);
764 data.u.open.path[PATH_MAX - 1] = '\0';
765 data.u.open.flags = flags;
766 data.u.open.mode = mode;
fe9f7760
FD
767 run_as(RUN_AS_OPEN, &data, &ret, uid, gid);
768 errno = ret._errno;
769 ret.u.open.ret = ret.fd;
770 return ret.u.open.ret;
60b6c79c 771}
4628484a
MD
772
773LTTNG_HIDDEN
774int run_as_unlink(const char *path, uid_t uid, gid_t gid)
775{
7567352f 776 struct run_as_data data;
fe9f7760 777 struct run_as_ret ret;
4628484a 778
8446e5eb 779 memset(&data, 0, sizeof(data));
fe9f7760
FD
780 memset(&ret, 0, sizeof(ret));
781
4628484a 782 DBG3("unlink() %s with for uid %d and gid %d",
08797918 783 path, (int) uid, (int) gid);
7567352f
MD
784 strncpy(data.u.unlink.path, path, PATH_MAX - 1);
785 data.u.unlink.path[PATH_MAX - 1] = '\0';
fe9f7760
FD
786 run_as(RUN_AS_UNLINK, &data, &ret, uid, gid);
787 errno = ret._errno;
788 return ret.u.unlink.ret;
4628484a
MD
789}
790
791LTTNG_HIDDEN
7567352f 792int run_as_rmdir_recursive(const char *path, uid_t uid, gid_t gid)
4628484a 793{
7567352f 794 struct run_as_data data;
fe9f7760
FD
795 struct run_as_ret ret;
796
797 memset(&data, 0, sizeof(data));
798 memset(&ret, 0, sizeof(ret));
4628484a 799
7567352f 800 DBG3("rmdir_recursive() %s with for uid %d and gid %d",
08797918 801 path, (int) uid, (int) gid);
7567352f
MD
802 strncpy(data.u.rmdir_recursive.path, path, PATH_MAX - 1);
803 data.u.rmdir_recursive.path[PATH_MAX - 1] = '\0';
fe9f7760
FD
804 run_as(RUN_AS_RMDIR_RECURSIVE, &data, &ret, uid, gid);
805 errno = ret._errno;
806 return ret.u.rmdir_recursive.ret;
7567352f
MD
807}
808
f8f66d38 809static
a80ed305 810int reset_sighandler(void)
f8f66d38 811{
5b5bb8c8 812 int sig;
f8f66d38 813
978d5d79 814 DBG("Resetting run_as worker signal handlers to default");
5b5bb8c8
JG
815 for (sig = 1; sig <= 31; sig++) {
816 (void) signal(sig, SIG_DFL);
f8f66d38 817 }
5b5bb8c8 818 return 0;
a80ed305
JG
819}
820
821static
822void worker_sighandler(int sig)
823{
824 const char *signame;
825
826 /*
cd89f030
JG
827 * The worker will inherit its parent's signals since they are part of
828 * the same process group. However, in the case of SIGINT and SIGTERM,
829 * we want to give the worker a chance to teardown gracefully when its
830 * parent closes the command socket.
a80ed305
JG
831 */
832 switch (sig) {
833 case SIGINT:
834 signame = "SIGINT";
835 break;
836 case SIGTERM:
837 signame = "SIGTERM";
838 break;
839 default:
22d5e48e 840 signame = NULL;
a80ed305
JG
841 }
842
22d5e48e
JG
843 if (signame) {
844 DBG("run_as worker received signal %s", signame);
845 } else {
846 DBG("run_as_worker received signal %d", sig);
847 }
a80ed305
JG
848}
849
850static
851int set_worker_sighandlers(void)
852{
853 int ret = 0;
854 sigset_t sigset;
855 struct sigaction sa;
856
857 if ((ret = sigemptyset(&sigset)) < 0) {
858 PERROR("sigemptyset");
859 goto end;
860 }
861
862 sa.sa_handler = worker_sighandler;
863 sa.sa_mask = sigset;
864 sa.sa_flags = 0;
865 if ((ret = sigaction(SIGINT, &sa, NULL)) < 0) {
866 PERROR("sigaction SIGINT");
867 goto end;
868 }
869
870 if ((ret = sigaction(SIGTERM, &sa, NULL)) < 0) {
871 PERROR("sigaction SIGTERM");
872 goto end;
873 }
874
875 DBG("run_as signal handler set for SIGTERM and SIGINT");
876end:
877 return ret;
f8f66d38
JG
878}
879
7567352f
MD
880LTTNG_HIDDEN
881int run_as_create_worker(char *procname)
882{
883 pid_t pid;
884 int i, ret = 0;
885 ssize_t readlen;
886 struct run_as_ret recvret;
887 struct run_as_worker *worker;
888
749b7a0c
JG
889 pthread_mutex_lock(&worker_lock);
890 assert(!global_worker);
7567352f 891 if (!use_clone()) {
749b7a0c
JG
892 /*
893 * Don't initialize a worker, all run_as tasks will be performed
894 * in the current process.
895 */
7567352f
MD
896 ret = 0;
897 goto end;
898 }
899 worker = zmalloc(sizeof(*worker));
900 if (!worker) {
901 ret = -ENOMEM;
902 goto end;
903 }
904 worker->procname = procname;
905 /* Create unix socket. */
906 if (lttcomm_create_anon_unix_socketpair(worker->sockpair) < 0) {
907 ret = -1;
908 goto error_sock;
909 }
fe9f7760 910
7567352f
MD
911 /* Fork worker. */
912 pid = fork();
913 if (pid < 0) {
914 PERROR("fork");
915 ret = -1;
916 goto error_fork;
917 } else if (pid == 0) {
918 /* Child */
919
f8f66d38
JG
920 reset_sighandler();
921
a80ed305
JG
922 set_worker_sighandlers();
923
749b7a0c
JG
924 /* The child has no use for this lock. */
925 pthread_mutex_unlock(&worker_lock);
7567352f
MD
926 /* Just close, no shutdown. */
927 if (close(worker->sockpair[0])) {
928 PERROR("close");
929 exit(EXIT_FAILURE);
930 }
fe9f7760
FD
931
932 /*
933 * Close all FDs aside from STDIN, STDOUT, STDERR and sockpair[1]
934 * Sockpair[1] is used as a control channel with the master
935 */
936 for (i = 3; i < sysconf(_SC_OPEN_MAX); i++) {
937 if (i != worker->sockpair[1]) {
938 (void) close(i);
939 }
940 }
941
7567352f
MD
942 worker->sockpair[0] = -1;
943 ret = run_as_worker(worker);
944 if (lttcomm_close_unix_sock(worker->sockpair[1])) {
945 PERROR("close");
946 ret = -1;
947 }
948 worker->sockpair[1] = -1;
978d5d79 949 LOG(ret ? PRINT_ERR : PRINT_DBG, "run_as worker exiting (ret = %d)", ret);
7567352f
MD
950 exit(ret ? EXIT_FAILURE : EXIT_SUCCESS);
951 } else {
952 /* Parent */
953
954 /* Just close, no shutdown. */
955 if (close(worker->sockpair[1])) {
956 PERROR("close");
957 ret = -1;
958 goto error_fork;
959 }
960 worker->sockpair[1] = -1;
961 worker->pid = pid;
962 /* Wait for worker to become ready. */
963 readlen = lttcomm_recv_unix_sock(worker->sockpair[0],
964 &recvret, sizeof(recvret));
965 if (readlen < sizeof(recvret)) {
966 ERR("readlen: %zd", readlen);
967 PERROR("Error reading response from run_as at creation");
968 ret = -1;
969 goto error_fork;
970 }
971 global_worker = worker;
972 }
973end:
749b7a0c 974 pthread_mutex_unlock(&worker_lock);
7567352f
MD
975 return ret;
976
977 /* Error handling. */
978error_fork:
979 for (i = 0; i < 2; i++) {
980 if (worker->sockpair[i] < 0) {
981 continue;
982 }
983 if (lttcomm_close_unix_sock(worker->sockpair[i])) {
984 PERROR("close");
985 }
986 worker->sockpair[i] = -1;
987 }
988error_sock:
989 free(worker);
749b7a0c 990 pthread_mutex_unlock(&worker_lock);
7567352f
MD
991 return ret;
992}
993
994LTTNG_HIDDEN
995void run_as_destroy_worker(void)
996{
997 struct run_as_worker *worker = global_worker;
7567352f 998
978d5d79 999 DBG("Destroying run_as worker");
749b7a0c 1000 pthread_mutex_lock(&worker_lock);
7567352f 1001 if (!worker) {
749b7a0c 1002 goto end;
7567352f
MD
1003 }
1004 /* Close unix socket */
978d5d79 1005 DBG("Closing run_as worker socket");
7567352f
MD
1006 if (lttcomm_close_unix_sock(worker->sockpair[0])) {
1007 PERROR("close");
1008 }
1009 worker->sockpair[0] = -1;
1010 /* Wait for worker. */
f8f66d38
JG
1011 for (;;) {
1012 int status;
1013 pid_t wait_ret;
1014
1015 wait_ret = waitpid(worker->pid, &status, 0);
1016 if (wait_ret < 0) {
1017 if (errno == EINTR) {
1018 continue;
1019 }
1020 PERROR("waitpid");
1021 break;
1022 }
1023
1024 if (WIFEXITED(status)) {
1025 LOG(WEXITSTATUS(status) == 0 ? PRINT_DBG : PRINT_ERR,
1026 DEFAULT_RUN_AS_WORKER_NAME " terminated with status code %d",
1027 WEXITSTATUS(status));
1028 break;
1029 } else if (WIFSIGNALED(status)) {
1030 ERR(DEFAULT_RUN_AS_WORKER_NAME " was killed by signal %d",
1031 WTERMSIG(status));
1032 break;
1033 }
7567352f
MD
1034 }
1035 free(worker);
1036 global_worker = NULL;
749b7a0c
JG
1037end:
1038 pthread_mutex_unlock(&worker_lock);
4628484a 1039}
This page took 0.092016 seconds and 4 git commands to generate.