aboutsummaryrefslogtreecommitdiffstats
path: root/src/firejail/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/firejail/util.c')
-rw-r--r--src/firejail/util.c180
1 files changed, 46 insertions, 134 deletions
diff --git a/src/firejail/util.c b/src/firejail/util.c
index 094a68c60..55dcdc246 100644
--- a/src/firejail/util.c
+++ b/src/firejail/util.c
@@ -20,8 +20,6 @@
20#define _XOPEN_SOURCE 500 20#define _XOPEN_SOURCE 500
21#include "firejail.h" 21#include "firejail.h"
22#include "../include/gcov_wrapper.h" 22#include "../include/gcov_wrapper.h"
23#include <ftw.h>
24#include <sys/stat.h>
25#include <sys/mount.h> 23#include <sys/mount.h>
26#include <syslog.h> 24#include <syslog.h>
27#include <errno.h> 25#include <errno.h>
@@ -32,9 +30,6 @@
32#include <sys/wait.h> 30#include <sys/wait.h>
33#include <limits.h> 31#include <limits.h>
34 32
35#include <string.h>
36#include <ctype.h>
37
38#include <fcntl.h> 33#include <fcntl.h>
39#ifndef O_PATH 34#ifndef O_PATH
40#define O_PATH 010000000 35#define O_PATH 010000000
@@ -459,31 +454,21 @@ int is_dir(const char *fname) {
459 if (*fname == '\0') 454 if (*fname == '\0')
460 return 0; 455 return 0;
461 456
462 int called_as_root = 0;
463 if (geteuid() == 0)
464 called_as_root = 1;
465
466 if (called_as_root)
467 EUID_USER();
468
469 // if fname doesn't end in '/', add one 457 // if fname doesn't end in '/', add one
470 int rv; 458 int rv;
471 struct stat s; 459 struct stat s;
472 if (fname[strlen(fname) - 1] == '/') 460 if (fname[strlen(fname) - 1] == '/')
473 rv = stat(fname, &s); 461 rv = stat_as_user(fname, &s);
474 else { 462 else {
475 char *tmp; 463 char *tmp;
476 if (asprintf(&tmp, "%s/", fname) == -1) { 464 if (asprintf(&tmp, "%s/", fname) == -1) {
477 fprintf(stderr, "Error: cannot allocate memory, %s:%d\n", __FILE__, __LINE__); 465 fprintf(stderr, "Error: cannot allocate memory, %s:%d\n", __FILE__, __LINE__);
478 errExit("asprintf"); 466 errExit("asprintf");
479 } 467 }
480 rv = stat(tmp, &s); 468 rv = stat_as_user(tmp, &s);
481 free(tmp); 469 free(tmp);
482 } 470 }
483 471
484 if (called_as_root)
485 EUID_ROOT();
486
487 if (rv == -1) 472 if (rv == -1)
488 return 0; 473 return 0;
489 474
@@ -499,13 +484,6 @@ int is_link(const char *fname) {
499 if (*fname == '\0') 484 if (*fname == '\0')
500 return 0; 485 return 0;
501 486
502 int called_as_root = 0;
503 if (geteuid() == 0)
504 called_as_root = 1;
505
506 if (called_as_root)
507 EUID_USER();
508
509 // remove trailing '/' if any 487 // remove trailing '/' if any
510 char *tmp = strdup(fname); 488 char *tmp = strdup(fname);
511 if (!tmp) 489 if (!tmp)
@@ -513,12 +491,9 @@ int is_link(const char *fname) {
513 trim_trailing_slash_or_dot(tmp); 491 trim_trailing_slash_or_dot(tmp);
514 492
515 char c; 493 char c;
516 ssize_t rv = readlink(tmp, &c, 1); 494 ssize_t rv = readlink_as_user(tmp, &c, 1);
517 free(tmp); 495 free(tmp);
518 496
519 if (called_as_root)
520 EUID_ROOT();
521
522 return (rv != -1); 497 return (rv != -1);
523} 498}
524 499
@@ -540,6 +515,24 @@ char *realpath_as_user(const char *fname) {
540 return rv; 515 return rv;
541} 516}
542 517
518ssize_t readlink_as_user(const char *fname, char *buf, size_t sz) {
519 assert(fname && buf && sz);
520
521 int called_as_root = 0;
522 if (geteuid() == 0)
523 called_as_root = 1;
524
525 if (called_as_root)
526 EUID_USER();
527
528 ssize_t rv = readlink(fname, buf, sz);
529
530 if (called_as_root)
531 EUID_ROOT();
532
533 return rv;
534}
535
543int stat_as_user(const char *fname, struct stat *s) { 536int stat_as_user(const char *fname, struct stat *s) {
544 assert(fname); 537 assert(fname);
545 538
@@ -974,12 +967,9 @@ uid_t pid_get_uid(pid_t pid) {
974} 967}
975 968
976 969
977 970gid_t get_group_id(const char *groupname) {
978
979uid_t get_group_id(const char *group) {
980 // find tty group id
981 gid_t gid = 0; 971 gid_t gid = 0;
982 struct group *g = getgrnam(group); 972 struct group *g = getgrnam(groupname);
983 if (g) 973 if (g)
984 gid = g->gr_gid; 974 gid = g->gr_gid;
985 975
@@ -987,86 +977,6 @@ uid_t get_group_id(const char *group) {
987} 977}
988 978
989 979
990static int remove_callback(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) {
991 (void) sb;
992 (void) typeflag;
993 (void) ftwbuf;
994 assert(fpath);
995
996 if (strcmp(fpath, ".") == 0)
997 return 0;
998
999 if (remove(fpath)) { // removes the link not the actual file
1000 perror("remove");
1001 fprintf(stderr, "Error: cannot remove file from user .firejail directory: %s\n", fpath);
1002 exit(1);
1003 }
1004
1005 return 0;
1006}
1007
1008
1009int remove_overlay_directory(void) {
1010 EUID_ASSERT();
1011 sleep(1);
1012
1013 char *path;
1014 if (asprintf(&path, "%s/.firejail", cfg.homedir) == -1)
1015 errExit("asprintf");
1016
1017 if (access(path, F_OK) == 0) {
1018 pid_t child = fork();
1019 if (child < 0)
1020 errExit("fork");
1021 if (child == 0) {
1022 // open ~/.firejail
1023 int fd = safer_openat(-1, path, O_PATH|O_NOFOLLOW|O_CLOEXEC);
1024 if (fd == -1) {
1025 fprintf(stderr, "Error: cannot open %s\n", path);
1026 exit(1);
1027 }
1028 struct stat s;
1029 if (fstat(fd, &s) == -1)
1030 errExit("fstat");
1031 if (!S_ISDIR(s.st_mode)) {
1032 if (S_ISLNK(s.st_mode))
1033 fprintf(stderr, "Error: %s is a symbolic link\n", path);
1034 else
1035 fprintf(stderr, "Error: %s is not a directory\n", path);
1036 exit(1);
1037 }
1038 if (s.st_uid != getuid()) {
1039 fprintf(stderr, "Error: %s is not owned by the current user\n", path);
1040 exit(1);
1041 }
1042 // chdir to ~/.firejail
1043 if (fchdir(fd) == -1)
1044 errExit("fchdir");
1045 close(fd);
1046
1047 EUID_ROOT();
1048 // FTW_PHYS - do not follow symbolic links
1049 if (nftw(".", remove_callback, 64, FTW_DEPTH | FTW_PHYS) == -1)
1050 errExit("nftw");
1051
1052 EUID_USER();
1053 // remove ~/.firejail
1054 if (rmdir(path) == -1)
1055 errExit("rmdir");
1056
1057 __gcov_flush();
1058
1059 _exit(0);
1060 }
1061 // wait for the child to finish
1062 waitpid(child, NULL, 0);
1063 // check if ~/.firejail was deleted
1064 if (access(path, F_OK) == 0)
1065 return 1;
1066 }
1067 return 0;
1068}
1069
1070// flush stdin if it is connected to a tty and has input 980// flush stdin if it is connected to a tty and has input
1071void flush_stdin(void) { 981void flush_stdin(void) {
1072 if (!isatty(STDIN_FILENO)) 982 if (!isatty(STDIN_FILENO))
@@ -1095,31 +1005,33 @@ int create_empty_dir_as_user(const char *dir, mode_t mode) {
1095 assert(dir); 1005 assert(dir);
1096 mode &= 07777; 1006 mode &= 07777;
1097 1007
1098 if (access(dir, F_OK) != 0) { 1008 if (access(dir, F_OK) == 0)
1009 return 0;
1010
1011 pid_t child = fork();
1012 if (child < 0)
1013 errExit("fork");
1014 if (child == 0) {
1015 // drop privileges
1016 drop_privs(0);
1017
1099 if (arg_debug) 1018 if (arg_debug)
1100 printf("Creating empty %s directory\n", dir); 1019 printf("Creating empty %s directory\n", dir);
1101 pid_t child = fork(); 1020 if (mkdir(dir, mode) == 0) {
1102 if (child < 0) 1021 int err = chmod(dir, mode);
1103 errExit("fork"); 1022 (void) err;
1104 if (child == 0) { 1023 }
1105 // drop privileges 1024 else if (arg_debug)
1106 drop_privs(0); 1025 printf("Directory %s not created: %s\n", dir, strerror(errno));
1107
1108 if (mkdir(dir, mode) == 0) {
1109 int err = chmod(dir, mode);
1110 (void) err;
1111 }
1112 else if (arg_debug)
1113 printf("Directory %s not created: %s\n", dir, strerror(errno));
1114 1026
1115 __gcov_flush(); 1027 __gcov_flush();
1116 1028
1117 _exit(0); 1029 _exit(0);
1118 }
1119 waitpid(child, NULL, 0);
1120 if (access(dir, F_OK) == 0)
1121 return 1;
1122 } 1030 }
1031 waitpid(child, NULL, 0);
1032
1033 if (access(dir, F_OK) == 0)
1034 return 1;
1123 return 0; 1035 return 0;
1124} 1036}
1125 1037
@@ -1509,7 +1421,7 @@ static int has_link(const char *dir) {
1509void check_homedir(const char *dir) { 1421void check_homedir(const char *dir) {
1510 assert(dir); 1422 assert(dir);
1511 if (dir[0] != '/') { 1423 if (dir[0] != '/') {
1512 fprintf(stderr, "Error: invalid user directory \"%s\"\n", cfg.homedir); 1424 fprintf(stderr, "Error: invalid user directory \"%s\"\n", dir);
1513 exit(1); 1425 exit(1);
1514 } 1426 }
1515 // symlinks are rejected in many places 1427 // symlinks are rejected in many places