aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar smitsohu <smitsohu@gmail.com>2018-08-01 15:39:15 +0200
committerLibravatar smitsohu <smitsohu@gmail.com>2018-08-01 15:39:15 +0200
commitfaff9d14de30763b991bd5d0665891e6d8ad2733 (patch)
tree2f503b78e63ce4948439711695d7f744d6b96fa5
parentenhance safe_fd function so it can digest arbitrary pathnames (diff)
parentFixed Documents handling (consume trailing /) and hide XDG warnings unless --... (diff)
downloadfirejail-faff9d14de30763b991bd5d0665891e6d8ad2733.tar.gz
firejail-faff9d14de30763b991bd5d0665891e6d8ad2733.tar.zst
firejail-faff9d14de30763b991bd5d0665891e6d8ad2733.zip
Merge branch 'master' of https://github.com/netblue30/firejail
-rw-r--r--etc/Viber.profile2
-rw-r--r--etc/amarok.profile2
-rw-r--r--etc/ardour5.profile2
-rw-r--r--etc/cmus.profile2
-rw-r--r--etc/gnome-music.profile2
-rw-r--r--etc/goobox.profile2
-rw-r--r--etc/minetest.profile2
-rw-r--r--etc/musixmatch.profile2
-rw-r--r--etc/parole.profile2
-rw-r--r--etc/ppsspp.profile2
-rw-r--r--etc/qupzilla.profile2
-rw-r--r--etc/seamonkey.profile2
-rw-r--r--etc/slack.profile2
-rw-r--r--etc/totem.profile2
-rw-r--r--etc/xonotic.profile2
-rw-r--r--etc/xplayer.profile2
-rw-r--r--src/firejail/firejail.h9
-rw-r--r--src/firejail/fs_whitelist.c269
-rw-r--r--src/firejail/util.c279
19 files changed, 369 insertions, 220 deletions
diff --git a/etc/Viber.profile b/etc/Viber.profile
index 6a58da8c9..cb9d01e03 100644
--- a/etc/Viber.profile
+++ b/etc/Viber.profile
@@ -32,7 +32,7 @@ shell none
32 32
33disable-mnt 33disable-mnt
34private-bin sh,bash,dig,awk,Viber 34private-bin sh,bash,dig,awk,Viber
35private-etc hosts,fonts,mailcap,resolv.conf,X11,pulse,alternatives,localtime,nsswitch.conf,ssl,proxychains.conf,pki,ca-certificates,crypto-policies 35private-etc hosts,fonts,mailcap,resolv.conf,X11,pulse,alternatives,localtime,nsswitch.conf,ssl,proxychains.conf,pki,ca-certificates,crypto-policies,machine-id,asound.conf
36private-tmp 36private-tmp
37 37
38noexec ${HOME} 38noexec ${HOME}
diff --git a/etc/amarok.profile b/etc/amarok.profile
index aff78e210..dab23c218 100644
--- a/etc/amarok.profile
+++ b/etc/amarok.profile
@@ -29,5 +29,5 @@ shell none
29 29
30# private-bin amarok 30# private-bin amarok
31private-dev 31private-dev
32# private-etc none 32# private-etc none,machine-id,pulse,asound.conf
33private-tmp 33private-tmp
diff --git a/etc/ardour5.profile b/etc/ardour5.profile
index aaac62bc8..99649cc3f 100644
--- a/etc/ardour5.profile
+++ b/etc/ardour5.profile
@@ -35,7 +35,7 @@ shell none
35#private-bin sh,ardour4,ardour5,ardour5-copy-mixer,ardour5-export,ardour5-fix_bbtppq,grep,sed,ldd,nm 35#private-bin sh,ardour4,ardour5,ardour5-copy-mixer,ardour5-export,ardour5-fix_bbtppq,grep,sed,ldd,nm
36private-cache 36private-cache
37private-dev 37private-dev
38#private-etc pulse,X11,alternatives,ardour4,ardour5,fonts 38#private-etc pulse,X11,alternatives,ardour4,ardour5,fonts,machine-id,asound.conf
39private-tmp 39private-tmp
40 40
41noexec ${HOME} 41noexec ${HOME}
diff --git a/etc/cmus.profile b/etc/cmus.profile
index 3331bde22..36478ef85 100644
--- a/etc/cmus.profile
+++ b/etc/cmus.profile
@@ -26,4 +26,4 @@ seccomp
26shell none 26shell none
27 27
28private-bin cmus 28private-bin cmus
29private-etc group 29private-etc group,machine-id,pulse,asound.conf
diff --git a/etc/gnome-music.profile b/etc/gnome-music.profile
index 90fb9814f..15710b363 100644
--- a/etc/gnome-music.profile
+++ b/etc/gnome-music.profile
@@ -38,7 +38,7 @@ tracelog
38 38
39private-bin gnome-music,python* 39private-bin gnome-music,python*
40private-dev 40private-dev
41# private-etc fonts 41# private-etc fonts,machine-id,pulse,asound.conf
42private-tmp 42private-tmp
43 43
44noexec ${HOME} 44noexec ${HOME}
diff --git a/etc/goobox.profile b/etc/goobox.profile
index 5e5aad95b..680e14a49 100644
--- a/etc/goobox.profile
+++ b/etc/goobox.profile
@@ -29,5 +29,5 @@ tracelog
29 29
30# private-bin goobox 30# private-bin goobox
31private-dev 31private-dev
32# private-etc fonts 32# private-etc fonts,machine-id,pulse,asound.conf
33# private-tmp 33# private-tmp
diff --git a/etc/minetest.profile b/etc/minetest.profile
index cdbf21935..6497fa9ba 100644
--- a/etc/minetest.profile
+++ b/etc/minetest.profile
@@ -34,7 +34,7 @@ disable-mnt
34private-bin minetest 34private-bin minetest
35private-dev 35private-dev
36# private-etc needs to be updated, see #1702 36# private-etc needs to be updated, see #1702
37#private-etc asound.conf,ca-certificates,drirc,fonts,group,host.conf,hostname,hosts,ld.so.cache,ld.so.preload,localtime,nsswitch.conf,passwd,pulse,resolv.conf,ssl,pki,crypto-policies 37#private-etc asound.conf,ca-certificates,drirc,fonts,group,host.conf,hostname,hosts,ld.so.cache,ld.so.preload,localtime,nsswitch.conf,passwd,pulse,resolv.conf,ssl,pki,crypto-policies,machine-id
38private-tmp 38private-tmp
39 39
40noexec ${HOME} 40noexec ${HOME}
diff --git a/etc/musixmatch.profile b/etc/musixmatch.profile
index bc8965431..b572f13d2 100644
--- a/etc/musixmatch.profile
+++ b/etc/musixmatch.profile
@@ -30,7 +30,7 @@ seccomp
30 30
31disable-mnt 31disable-mnt
32private-dev 32private-dev
33private-etc none 33private-etc none,machine-id,pulse,asound.conf
34 34
35noexec ${HOME} 35noexec ${HOME}
36noexec /tmp 36noexec /tmp
diff --git a/etc/parole.profile b/etc/parole.profile
index f98703bd6..17d31af15 100644
--- a/etc/parole.profile
+++ b/etc/parole.profile
@@ -26,4 +26,4 @@ shell none
26 26
27private-bin parole,dbus-launch 27private-bin parole,dbus-launch
28private-cache 28private-cache
29private-etc passwd,group,fonts 29private-etc passwd,group,fonts,machine-id,pulse,asound.conf
diff --git a/etc/ppsspp.profile b/etc/ppsspp.profile
index 073108464..3a40b6260 100644
--- a/etc/ppsspp.profile
+++ b/etc/ppsspp.profile
@@ -36,7 +36,7 @@ shell none
36 36
37# private-dev is disabled to allow controller support 37# private-dev is disabled to allow controller support
38#private-dev 38#private-dev
39private-etc asound.conf,ca-certificates,drirc,fonts,group,host.conf,hostname,hosts,ld.so.cache,ld.so.preload,localtime,nsswitch.conf,passwd,pulse,resolv.conf,ssl,pki,crypto-policies 39private-etc asound.conf,ca-certificates,drirc,fonts,group,host.conf,hostname,hosts,ld.so.cache,ld.so.preload,localtime,nsswitch.conf,passwd,pulse,resolv.conf,ssl,pki,crypto-policies,machine-id
40private-opt ppsspp 40private-opt ppsspp
41private-tmp 41private-tmp
42 42
diff --git a/etc/qupzilla.profile b/etc/qupzilla.profile
index 947689d96..da1ca2281 100644
--- a/etc/qupzilla.profile
+++ b/etc/qupzilla.profile
@@ -33,7 +33,7 @@ seccomp.drop @clock,@cpu-emulation,@debug,@module,@obsolete,@raw-io,@reboot,@res
33# tracelog 33# tracelog
34 34
35private-dev 35private-dev
36# private-etc passwd,group,hostname,hosts,localtime,nsswitch.conf,resolv.conf,gtk-2.0,pango,fonts,adobe,mime.types,mailcap,asound.conf,pulse 36# private-etc passwd,group,hostname,hosts,localtime,nsswitch.conf,resolv.conf,gtk-2.0,pango,fonts,adobe,mime.types,mailcap,asound.conf,pulse,machine-id
37# private-tmp - interferes with the opening of downloaded files 37# private-tmp - interferes with the opening of downloaded files
38 38
39noexec ${HOME} 39noexec ${HOME}
diff --git a/etc/seamonkey.profile b/etc/seamonkey.profile
index 423863cc2..dc2fd8e30 100644
--- a/etc/seamonkey.profile
+++ b/etc/seamonkey.profile
@@ -47,4 +47,4 @@ seccomp
47tracelog 47tracelog
48 48
49disable-mnt 49disable-mnt
50# private-etc passwd,group,hostname,hosts,localtime,nsswitch.conf,resolv.conf,gtk-2.0,pango,fonts,iceweasel,firefox,adobe,mime.types,mailcap,asound.conf,pulse 50# private-etc passwd,group,hostname,hosts,localtime,nsswitch.conf,resolv.conf,gtk-2.0,pango,fonts,iceweasel,firefox,adobe,mime.types,mailcap,asound.conf,pulse,machine-id
diff --git a/etc/slack.profile b/etc/slack.profile
index 13106255b..91bf0a722 100644
--- a/etc/slack.profile
+++ b/etc/slack.profile
@@ -37,5 +37,5 @@ shell none
37disable-mnt 37disable-mnt
38private-bin slack,locale 38private-bin slack,locale
39private-dev 39private-dev
40private-etc asound.conf,ca-certificates,fonts,group,passwd,pulse,resolv.conf,ssl,ld.so.conf,ld.so.cache,localtime,pki,crypto-policies 40private-etc asound.conf,ca-certificates,fonts,group,passwd,pulse,resolv.conf,ssl,ld.so.conf,ld.so.cache,localtime,pki,crypto-policies,machine-id
41private-tmp 41private-tmp
diff --git a/etc/totem.profile b/etc/totem.profile
index 3ac25440b..911999665 100644
--- a/etc/totem.profile
+++ b/etc/totem.profile
@@ -33,7 +33,7 @@ shell none
33private-bin totem 33private-bin totem
34private-cache 34private-cache
35private-dev 35private-dev
36# private-etc fonts 36# private-etc fonts,machine-id,pulse,asound.conf
37private-tmp 37private-tmp
38 38
39noexec ${HOME} 39noexec ${HOME}
diff --git a/etc/xonotic.profile b/etc/xonotic.profile
index 1d2493f36..30f5c735d 100644
--- a/etc/xonotic.profile
+++ b/etc/xonotic.profile
@@ -34,7 +34,7 @@ disable-mnt
34private-bin bash,blind-id,darkplaces-glx,darkplaces-sdl,dirname,grep,ldd,netstat,ps,readlink,sh,uname,xonotic,xonotic-glx,xonotic-linux32-dedicated,xonotic-linux32-glx,xonotic-linux32-sdl,xonotic-linux64-dedicated,xonotic-linux64-glx,xonotic-linux64-sdl,xonotic-sdl 34private-bin bash,blind-id,darkplaces-glx,darkplaces-sdl,dirname,grep,ldd,netstat,ps,readlink,sh,uname,xonotic,xonotic-glx,xonotic-linux32-dedicated,xonotic-linux32-glx,xonotic-linux32-sdl,xonotic-linux64-dedicated,xonotic-linux64-glx,xonotic-linux64-sdl,xonotic-sdl
35private-dev 35private-dev
36# private-etc breaks audio on some distros 36# private-etc breaks audio on some distros
37#private-etc asound.conf,ca-certificates,drirc,fonts,group,host.conf,hostname,hosts,ld.so.cache,ld.so.preload,localtime,nsswitch.conf,passwd,pulse,resolv.conf,ssl,pki,crypto-policies 37#private-etc asound.conf,ca-certificates,drirc,fonts,group,host.conf,hostname,hosts,ld.so.cache,ld.so.preload,localtime,nsswitch.conf,passwd,pulse,resolv.conf,ssl,pki,crypto-policies,machine-id
38private-tmp 38private-tmp
39 39
40noexec ${HOME} 40noexec ${HOME}
diff --git a/etc/xplayer.profile b/etc/xplayer.profile
index 46579ead8..5873e2436 100644
--- a/etc/xplayer.profile
+++ b/etc/xplayer.profile
@@ -39,7 +39,7 @@ tracelog
39 39
40private-bin xplayer,xplayer-audio-preview,xplayer-video-thumbnailer 40private-bin xplayer,xplayer-audio-preview,xplayer-video-thumbnailer
41private-dev 41private-dev
42# private-etc fonts 42# private-etc fonts,machine-id,pulse,asound.conf
43private-tmp 43private-tmp
44 44
45noexec ${HOME} 45noexec ${HOME}
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index 0faf10340..9f7936174 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -491,6 +491,15 @@ int arp_check(const char *dev, uint32_t destaddr);
491uint32_t arp_assign(const char *dev, Bridge *br); 491uint32_t arp_assign(const char *dev, Bridge *br);
492 492
493// util.c 493// util.c
494extern char *dentry[];
495extern char *mentry[];
496extern char *ventry[];
497extern char *pentry[];
498extern char *deentry[];
499extern char *doentry[];
500
501char *resolve_xdg(int flags, const char *var, size_t length, const char *prnt);
502char *resolve_hardcoded(int flags, char *entries[], const char *prnt);
494void errLogExit(char* fmt, ...); 503void errLogExit(char* fmt, ...);
495void fwarning(char* fmt, ...); 504void fwarning(char* fmt, ...);
496void fmessage(char* fmt, ...); 505void fmessage(char* fmt, ...);
diff --git a/src/firejail/fs_whitelist.c b/src/firejail/fs_whitelist.c
index bf839b524..0178e3c5b 100644
--- a/src/firejail/fs_whitelist.c
+++ b/src/firejail/fs_whitelist.c
@@ -33,159 +33,20 @@
33// 3. run firejail --debug --whitelist=/tmp/etc 33// 3. run firejail --debug --whitelist=/tmp/etc
34//#define TEST_MOUNTINFO 34//#define TEST_MOUNTINFO
35 35
36static char *dentry[] = {
37 "Downloads",
38 "Загрузки",
39 "Téléchargement",
40 NULL
41};
42
43static char *mentry[] = {
44 "Music",
45 "Музыка",
46 "Musique",
47 NULL
48};
49
50static char *ventry[] = {
51 "Videos",
52 "Видео",
53 "Vidéos",
54 NULL
55};
56
57static char *pentry[] = {
58 "Pictures",
59 "Изображения",
60 "Photos",
61 NULL
62};
63
64static char *deentry[] = {
65 "Desktop",
66 "Рабочий стол",
67 "Bureau",
68 NULL
69};
70
71static char *doentry[] = {
72 "Documents",
73 "Документы",
74 "Documents",
75 NULL
76};
77
78#define EMPTY_STRING ("") 36#define EMPTY_STRING ("")
79#define MAXBUF 4098 37#define MAXBUF 4098
80 38
81static char *resolve_xdg(int nowhitelist_flag, const char *var, size_t length, const char *prnt) { 39char *parse_nowhitelist(int nowhitelist_flag, char *ptr1) {
82 EUID_ASSERT(); 40 char *rv;
83 char *fname; 41 if (nowhitelist_flag) {
84 struct stat s; 42 if (asprintf(&rv, "nowhitelist ~/%s", ptr1) == -1)
85 43 errExit("asprintf");
86 if (asprintf(&fname, "%s/.config/user-dirs.dirs", cfg.homedir) == -1)
87 errExit("asprintf");
88 FILE *fp = fopen(fname, "r");
89 if (!fp) {
90 free(fname);
91 return NULL;
92 }
93 free(fname);
94
95 char buf[MAXBUF];
96 while (fgets(buf, MAXBUF, fp)) {
97 char *ptr = buf;
98
99 // skip blanks
100 while (*ptr == ' ' || *ptr == '\t')
101 ptr++;
102 if (*ptr == '\0' || *ptr == '\n' || *ptr == '#')
103 continue;
104
105 if (strncmp(ptr, var, length) == 0) {
106 char *ptr1 = ptr + length;
107 char *ptr2 = strchr(ptr1, '"');
108 if (ptr2) {
109 fclose(fp);
110 *ptr2 = '\0';
111 if (arg_debug || arg_debug_whitelists)
112 printf("extracted %s from ~/.config/user-dirs.dirs\n", ptr1);
113 if (strlen(ptr1) != 0) {
114 if (arg_debug || arg_debug_whitelists)
115 printf("%s ",prnt);
116 printf("directory resolved as \"%s\"\n", ptr1);
117
118 if (asprintf(&fname, "%s/%s", cfg.homedir, ptr1) == -1)
119 errExit("asprintf");
120
121 if (stat(fname, &s) == -1) {
122 free(fname);
123 goto errout;
124 }
125
126 char *rv;
127 if (nowhitelist_flag) {
128 if (asprintf(&rv, "nowhitelist ~/%s", ptr + length) == -1)
129 errExit("asprintf");
130 }
131 else {
132 if (asprintf(&rv, "whitelist ~/%s", ptr + length) == -1)
133 errExit("asprintf");
134 }
135 return rv;
136 }
137 else
138 goto errout;
139 }
140 }
141 }
142
143 fclose(fp);
144 return NULL;
145
146 errout:
147 if (!arg_private) {
148 fprintf(stderr, "***\n");
149 fprintf(stderr, "*** Error: %s directory was not found in user home.\n",prnt);
150 fprintf(stderr, "*** \tAny files saved by the program, will be lost when the sandbox is closed.\n");
151 fprintf(stderr, "***\n");
152 } 44 }
153 return NULL; 45 else {
154} 46 if (asprintf(&rv, "whitelist ~/%s", ptr1) == -1)
155
156static char *resolve_hardcoded(int nowhitelist_flag, char *entries[], const char *prnt) {
157 EUID_ASSERT();
158 char *fname;
159 struct stat s;
160
161 int i = 0;
162 while (entries[i] != NULL) {
163 if (asprintf(&fname, "%s/%s", cfg.homedir, entries[i]) == -1)
164 errExit("asprintf"); 47 errExit("asprintf");
165
166 if (stat(fname, &s) == 0) {
167 if (arg_debug || arg_debug_whitelists) {
168 printf("%s ", prnt);
169 printf("directory resolved as \"%s\"\n", fname);
170 }
171
172 char *rv;
173 if (nowhitelist_flag) {
174 if (asprintf(&rv, "nowhitelist ~/%s", entries[i]) == -1)
175 errExit("asprintf");
176 }
177 else {
178 if (asprintf(&rv, "whitelist ~/%s", entries[i]) == -1)
179 errExit("asprintf");
180 }
181 free(fname);
182 return rv;
183 }
184 free(fname);
185 i++;
186 } 48 }
187 49 return rv;
188 return NULL;
189} 50}
190 51
191static int mkpath(const char* path, mode_t mode) { 52static int mkpath(const char* path, mode_t mode) {
@@ -467,39 +328,43 @@ void fs_whitelist(void) {
467 328
468 // resolve ${DOWNLOADS} 329 // resolve ${DOWNLOADS}
469 if (strcmp(dataptr, "${DOWNLOADS}") == 0) { 330 if (strcmp(dataptr, "${DOWNLOADS}") == 0) {
470 char *tmp = resolve_xdg(nowhitelist_flag, "XDG_DOWNLOAD_DIR=\"$HOME/", 24, "Downloads"); 331 char *tmp1 = resolve_xdg(arg_debug || arg_debug_whitelists, "XDG_DOWNLOAD_DIR=\"$HOME/", 24, "Downloads");
471 char *tmp2 = resolve_hardcoded(nowhitelist_flag, dentry, "Downloads"); 332 char *tmpw1 = parse_nowhitelist(nowhitelist_flag, tmp1);
472 if (tmp) { 333 char *tmp2 = resolve_hardcoded(arg_debug || arg_debug_whitelists, dentry, "Downloads");
473 entry->data = tmp; 334 char *tmpw2 = parse_nowhitelist(nowhitelist_flag, tmp2);
474 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10; 335 if (tmp1 && tmpw1) {
475 } 336 entry->data = tmpw1;
476 else if (tmp2) { 337 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10;
477 entry->data = tmp2; 338 }
478 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10; 339 else if (tmp2 && tmpw2) {
479 } 340 entry->data = tmpw2;
480 else { 341 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10;
481 if (!nowhitelist_flag && !arg_quiet && !arg_private) { 342 }
482 fprintf(stderr, "***\n"); 343 else {
483 fprintf(stderr, "*** Warning: cannot whitelist Downloads directory\n"); 344 if (!nowhitelist_flag && !arg_quiet && !arg_private) {
484 fprintf(stderr, "*** \tAny file saved will be lost when the sandbox is closed.\n"); 345 fprintf(stderr, "***\n");
485 fprintf(stderr, "*** \tPlease create a proper Downloads directory for your application.\n"); 346 fprintf(stderr, "*** Warning: cannot whitelist Downloads directory\n");
486 fprintf(stderr, "***\n"); 347 fprintf(stderr, "*** \tAny file saved will be lost when the sandbox is closed.\n");
487 } 348 fprintf(stderr, "*** \tPlease create a proper Downloads directory for your application.\n");
488 entry->data = EMPTY_STRING; 349 fprintf(stderr, "***\n");
489 continue; 350 }
490 } 351 entry->data = EMPTY_STRING;
352 continue;
353 }
491 } 354 }
492 355
493 // resolve ${MUSIC} 356 // resolve ${MUSIC}
494 if (strcmp(dataptr, "${MUSIC}") == 0) { 357 if (strcmp(dataptr, "${MUSIC}") == 0) {
495 char *tmp = resolve_xdg(nowhitelist_flag, "XDG_MUSIC_DIR=\"$HOME/", 21, "Music"); 358 char *tmp1 = resolve_xdg(arg_debug || arg_debug_whitelists, "XDG_MUSIC_DIR=\"$HOME/", 21, "Music");
496 char *tmp2 = resolve_hardcoded(nowhitelist_flag, mentry, "Music"); 359 char *tmpw1 = parse_nowhitelist(nowhitelist_flag, tmp1);
497 if (tmp) { 360 char *tmp2 = resolve_hardcoded(arg_debug || arg_debug_whitelists, mentry, "Music");
498 entry->data = tmp; 361 char *tmpw2 = parse_nowhitelist(nowhitelist_flag, tmp2);
362 if (tmp1 && tmpw1) {
363 entry->data = tmpw1;
499 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10; 364 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10;
500 } 365 }
501 else if (tmp2) { 366 else if (tmp2 && tmpw2) {
502 entry->data = tmp2; 367 entry->data = tmpw2;
503 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10; 368 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10;
504 } 369 }
505 else { 370 else {
@@ -517,14 +382,16 @@ void fs_whitelist(void) {
517 382
518 // resolve ${VIDEOS} 383 // resolve ${VIDEOS}
519 if (strcmp(dataptr, "${VIDEOS}") == 0) { 384 if (strcmp(dataptr, "${VIDEOS}") == 0) {
520 char *tmp = resolve_xdg(nowhitelist_flag, "XDG_VIDEOS_DIR=\"$HOME/", 22, "Videos"); 385 char *tmp1 = resolve_xdg(arg_debug || arg_debug_whitelists, "XDG_VIDEOS_DIR=\"$HOME/", 22, "Videos");
521 char *tmp2 = resolve_hardcoded(nowhitelist_flag, ventry, "Videos"); 386 char *tmpw1 = parse_nowhitelist(nowhitelist_flag, tmp1);
522 if (tmp) { 387 char *tmp2 = resolve_hardcoded(arg_debug || arg_debug_whitelists, ventry, "Videos");
523 entry->data = tmp; 388 char *tmpw2 = parse_nowhitelist(nowhitelist_flag, tmp2);
389 if (tmp1 && tmpw1) {
390 entry->data = tmpw1;
524 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10; 391 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10;
525 } 392 }
526 else if (tmp2) { 393 else if (tmp2 && tmpw2) {
527 entry->data = tmp2; 394 entry->data = tmpw2;
528 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10; 395 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10;
529 } 396 }
530 else { 397 else {
@@ -542,14 +409,16 @@ void fs_whitelist(void) {
542 409
543 // resolve ${PICTURES} 410 // resolve ${PICTURES}
544 if (strcmp(dataptr, "${PICTURES}") == 0) { 411 if (strcmp(dataptr, "${PICTURES}") == 0) {
545 char *tmp = resolve_xdg(nowhitelist_flag, "XDG_PICTURES_DIR=\"$HOME/", 24, "Pictures"); 412 char *tmp1 = resolve_xdg(arg_debug || arg_debug_whitelists, "XDG_PICTURES_DIR=\"$HOME/", 24, "Pictures");
546 char *tmp2 = resolve_hardcoded(nowhitelist_flag, pentry, "Pictures"); 413 char *tmpw1 = parse_nowhitelist(nowhitelist_flag, tmp1);
547 if (tmp) { 414 char *tmp2 = resolve_hardcoded(arg_debug || arg_debug_whitelists, pentry, "Pictures");
548 entry->data = tmp; 415 char *tmpw2 = parse_nowhitelist(nowhitelist_flag, tmp2);
416 if (tmp1 && tmpw1) {
417 entry->data = tmpw1;
549 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10; 418 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10;
550 } 419 }
551 else if (tmp2) { 420 else if (tmp2 && tmpw2) {
552 entry->data = tmp2; 421 entry->data = tmpw2;
553 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10; 422 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10;
554 } 423 }
555 else { 424 else {
@@ -567,14 +436,16 @@ void fs_whitelist(void) {
567 436
568 // resolve ${DESKTOP} 437 // resolve ${DESKTOP}
569 if (strcmp(dataptr, "${DESKTOP}") == 0) { 438 if (strcmp(dataptr, "${DESKTOP}") == 0) {
570 char *tmp = resolve_xdg(nowhitelist_flag, "XDG_DESKTOP_DIR=\"$HOME/", 24, "Desktop"); 439 char *tmp1 = resolve_xdg(arg_debug || arg_debug_whitelists, "XDG_DESKTOP_DIR=\"$HOME/", 24, "Desktop");
571 char *tmp2 = resolve_hardcoded(nowhitelist_flag, deentry, "Desktop"); 440 char *tmpw1 = parse_nowhitelist(nowhitelist_flag, tmp1);
572 if (tmp) { 441 char *tmp2 = resolve_hardcoded(arg_debug || arg_debug_whitelists, deentry, "Desktop");
573 entry->data = tmp; 442 char *tmpw2 = parse_nowhitelist(nowhitelist_flag, tmp2);
443 if (tmp1 && tmpw1) {
444 entry->data = tmpw1;
574 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10; 445 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10;
575 } 446 }
576 else if (tmp2) { 447 else if (tmp2 && tmpw2) {
577 entry->data = tmp2; 448 entry->data = tmpw2;
578 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10; 449 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10;
579 } 450 }
580 else { 451 else {
@@ -592,14 +463,16 @@ void fs_whitelist(void) {
592 463
593 // resolve ${DOCUMENTS} 464 // resolve ${DOCUMENTS}
594 if (strcmp(dataptr, "${DOCUMENTS}") == 0) { 465 if (strcmp(dataptr, "${DOCUMENTS}") == 0) {
595 char *tmp = resolve_xdg(nowhitelist_flag, "XDG_DOCUMENTS_DIR=\"$HOME/", 25, "Documents"); 466 char *tmp1 = resolve_xdg(arg_debug || arg_debug_whitelists, "XDG_DOCUMENTS_DIR=\"$HOME/", 25, "Documents");
596 char *tmp2 = resolve_hardcoded(nowhitelist_flag, doentry, "Documents"); 467 char *tmpw1 = parse_nowhitelist(nowhitelist_flag, tmp1);
597 if (tmp) { 468 char *tmp2 = resolve_hardcoded(arg_debug || arg_debug_whitelists, doentry, "Documents");
598 entry->data = tmp; 469 char *tmpw2 = parse_nowhitelist(nowhitelist_flag, tmp2);
470 if (tmp1 && tmpw1) {
471 entry->data = tmpw1;
599 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10; 472 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10;
600 } 473 }
601 else if (tmp2) { 474 else if (tmp2 && tmpw2) {
602 entry->data = tmp2; 475 entry->data = tmpw2;
603 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10; 476 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10;
604 } 477 }
605 else { 478 else {
diff --git a/src/firejail/util.c b/src/firejail/util.c
index 18f837d7e..d79e955a7 100644
--- a/src/firejail/util.c
+++ b/src/firejail/util.c
@@ -32,6 +32,138 @@
32#include <fcntl.h> 32#include <fcntl.h>
33 33
34#define MAX_GROUPS 1024 34#define MAX_GROUPS 1024
35#define MAXBUF 4098
36
37char *dentry[] = {
38 "Downloads",
39 "Загрузки",
40 "Téléchargement",
41 NULL
42};
43
44char *mentry[] = {
45 "Music",
46 "Музыка",
47 "Musique",
48 NULL
49};
50
51char *ventry[] = {
52 "Videos",
53 "Видео",
54 "Vidéos",
55 NULL
56};
57
58char *pentry[] = {
59 "Pictures",
60 "Изображения",
61 "Photos",
62 NULL
63};
64
65char *deentry[] = {
66 "Desktop",
67 "Рабочий стол",
68 "Bureau",
69 NULL
70};
71
72char *doentry[] = {
73 "Documents",
74 "Документы",
75 "Documents",
76 NULL
77};
78
79char *resolve_xdg(int flags, const char *var, size_t length, const char *prnt) {
80 char *fname;
81 struct stat s;
82
83 if (asprintf(&fname, "%s/.config/user-dirs.dirs", cfg.homedir) == -1)
84 errExit("asprintf");
85 FILE *fp = fopen(fname, "r");
86 if (!fp) {
87 free(fname);
88 return NULL;
89 }
90 free(fname);
91
92 char buf[MAXBUF];
93 while (fgets(buf, MAXBUF, fp)) {
94 char *ptr = buf;
95
96 // skip blanks
97 while (*ptr == ' ' || *ptr == '\t')
98 ptr++;
99 if (*ptr == '\0' || *ptr == '\n' || *ptr == '#')
100 continue;
101
102 if (strncmp(ptr, var, length) == 0) {
103 char *ptr1 = ptr + length;
104 char *ptr2 = strchr(ptr1, '"');
105 if (ptr2) {
106 fclose(fp);
107 *ptr2 = '\0';
108 if (flags)
109 printf("extracted %s from ~/.config/user-dirs.dirs\n", ptr1);
110 if (strlen(ptr1) != 0) {
111 if (flags)
112 printf("%s ",prnt);
113 printf("directory resolved as \"%s\"\n", ptr1);
114
115 if (asprintf(&fname, "%s/%s", cfg.homedir, ptr1) == -1)
116 errExit("asprintf");
117
118 if (stat(fname, &s) == -1) {
119 free(fname);
120 goto errout;
121 }
122 free(fname);
123 return ptr1;
124 }
125 else
126 goto errout;
127 }
128 }
129 }
130
131 fclose(fp);
132 return NULL;
133
134 errout:
135 if (!arg_private && arg_debug) {
136 fprintf(stderr, "***\n");
137 fprintf(stderr, "*** Error: %s directory was not found in user home.\n",prnt);
138 fprintf(stderr, "*** \tAny files saved by the program, will be lost when the sandbox is closed.\n");
139 fprintf(stderr, "***\n");
140 }
141 return NULL;
142}
143
144char *resolve_hardcoded(int flags, char *entries[], const char *prnt) {
145 char *fname;
146 struct stat s;
147
148 int i = 0;
149 while (entries[i] != NULL) {
150 if (asprintf(&fname, "%s/%s", cfg.homedir, entries[i]) == -1)
151 errExit("asprintf");
152
153 if (stat(fname, &s) == 0) {
154 if (flags) {
155 printf("%s ", prnt);
156 printf("directory resolved as \"%s\"\n", fname);
157 }
158 free(fname);
159 return entries[i];
160 }
161 free(fname);
162 i++;
163 }
164
165 return NULL;
166}
35 167
36// send the error to /var/log/auth.log and exit after a small delay 168// send the error to /var/log/auth.log and exit after a small delay
37void errLogExit(char* fmt, ...) { 169void errLogExit(char* fmt, ...) {
@@ -732,27 +864,162 @@ char *expand_home(const char *path, const char* homedir) {
732 assert(path); 864 assert(path);
733 assert(homedir); 865 assert(homedir);
734 866
867 int called_as_root = 0;
868
869 if(geteuid() == 0)
870 called_as_root = 1;
871
872 if(called_as_root) {
873 EUID_USER();
874 }
875
876 EUID_ASSERT();
877
735 // Replace home macro 878 // Replace home macro
736 char *new_name = NULL; 879 char *new_name = NULL;
737 if (strncmp(path, "${HOME}", 7) == 0) { 880 if (strncmp(path, "${HOME}", 7) == 0) {
738 if (asprintf(&new_name, "%s%s", homedir, path + 7) == -1) 881 if (asprintf(&new_name, "%s%s", homedir, path + 7) == -1)
739 errExit("asprintf"); 882 errExit("asprintf");
883 if(called_as_root)
884 EUID_ROOT();
740 return new_name; 885 return new_name;
741 } 886 }
742 else if (*path == '~') { 887 else if (*path == '~') {
743 if (asprintf(&new_name, "%s%s", homedir, path + 1) == -1) 888 if (asprintf(&new_name, "%s%s", homedir, path + 1) == -1)
744 errExit("asprintf"); 889 errExit("asprintf");
745 return new_name; 890 if(called_as_root)
891 EUID_ROOT();
892 return new_name;
746 } 893 }
747 else if (strncmp(path, "${CFG}", 6) == 0) { 894 else if (strncmp(path, "${CFG}", 6) == 0) {
748 if (asprintf(&new_name, "%s%s", SYSCONFDIR, path + 6) == -1) 895 if (asprintf(&new_name, "%s%s", SYSCONFDIR, path + 6) == -1)
749 errExit("asprintf"); 896 errExit("asprintf");
750 return new_name; 897 if(called_as_root)
898 EUID_ROOT();
899 return new_name;
900 }
901
902 else if (strncmp(path, "${DOWNLOADS}", 12) == 0) {
903 char *tmp = resolve_xdg(arg_debug, "XDG_DOWNLOAD_DIR=\"$HOME/", 24, "Downloads");
904 char *tmp2 = resolve_hardcoded(arg_debug, dentry, "Downloads");
905 if(tmp) {
906 if (asprintf(&new_name, "%s/%s%s", homedir, tmp, path + 12) == -1)
907 errExit("asprintf");
908 if(called_as_root)
909 EUID_ROOT();
910 return new_name;
911 }
912 else if(tmp2) {
913 if (asprintf(&new_name, "%s/%s%s", homedir, tmp2, path + 12) == -1)
914 errExit("asprintf");
915 if(called_as_root)
916 EUID_ROOT();
917 return new_name;
918 }
919 }
920
921 else if (strncmp(path, "${MUSIC}", 8) == 0) {
922 char *tmp = resolve_xdg(arg_debug, "XDG_MUSIC_DIR=\"$HOME/", 21, "Music");
923 char *tmp2 = resolve_hardcoded(arg_debug, mentry, "Music");
924 if(tmp) {
925 if (asprintf(&new_name, "%s/%s%s", homedir, tmp, path + 8) == -1)
926 errExit("asprintf");
927 if(called_as_root)
928 EUID_ROOT();
929 return new_name;
930 }
931 else if(tmp2) {
932 if (asprintf(&new_name, "%s/%s%s", homedir, tmp2, path + 8) == -1)
933 errExit("asprintf");
934 if(called_as_root)
935 EUID_ROOT();
936 return new_name;
937 }
938 }
939
940 else if (strncmp(path, "${VIDEOS}", 9) == 0) {
941 char *tmp = resolve_xdg(arg_debug, "XDG_VIDEOS_DIR=\"$HOME/", 22, "Videos");
942 char *tmp2 = resolve_hardcoded(arg_debug, ventry, "Videos");
943 if(tmp) {
944 if (asprintf(&new_name, "%s/%s%s", homedir, tmp, path + 9) == -1)
945 errExit("asprintf");
946 if(called_as_root)
947 EUID_ROOT();
948 return new_name;
949 }
950 else if(tmp2) {
951 if (asprintf(&new_name, "%s/%s%s", homedir, tmp2, path + 9) == -1)
952 errExit("asprintf");
953 if(called_as_root)
954 EUID_ROOT();
955 return new_name;
956 }
957 }
958
959 else if (strncmp(path, "${PICTURES}", 11) == 0) {
960 char *tmp = resolve_xdg(arg_debug, "XDG_PICTURES_DIR=\"$HOME/", 24, "Pictures");
961 char *tmp2 = resolve_hardcoded(arg_debug, pentry, "Pictures");
962 if(tmp) {
963 if (asprintf(&new_name, "%s/%s%s", homedir, tmp, path + 11) == -1)
964 errExit("asprintf");
965 if(called_as_root)
966 EUID_ROOT();
967 return new_name;
968 }
969 else if(tmp2) {
970 if (asprintf(&new_name, "%s/%s%s", homedir, tmp2, path + 11) == -1)
971 errExit("asprintf");
972 if(called_as_root)
973 EUID_ROOT();
974 return new_name;
975 }
976 }
977
978 else if (strncmp(path, "${DESKTOP}", 10) == 0) {
979 char *tmp = resolve_xdg(arg_debug, "XDG_DESKTOP_DIR=\"$HOME/", 24, "Desktop");
980 char *tmp2 = resolve_hardcoded(arg_debug, deentry, "Desktop");
981 if(tmp) {
982 if (asprintf(&new_name, "%s/%s%s", homedir, tmp, path + 10) == -1)
983 errExit("asprintf");
984 if(called_as_root)
985 EUID_ROOT();
986 return new_name;
987 }
988 else if(tmp2) {
989 if (asprintf(&new_name, "%s/%s%s", homedir, tmp2, path + 10) == -1)
990 errExit("asprintf");
991 if(called_as_root)
992 EUID_ROOT();
993 return new_name;
994 }
995 }
996
997 else if (strncmp(path, "${DOCUMENTS}", 12) == 0) {
998 char *tmp = resolve_xdg(arg_debug, "XDG_DOCUMENTS_DIR=\"$HOME/", 25, "Documents");
999 char *tmp2 = resolve_hardcoded(arg_debug, doentry, "Documents");
1000 if(tmp) {
1001 if (asprintf(&new_name, "%s/%s%s", homedir, tmp, path + 12) == -1)
1002 errExit("asprintf");
1003 if(called_as_root)
1004 EUID_ROOT();
1005 return new_name;
1006 }
1007 else if(tmp2) {
1008 if (asprintf(&new_name, "%s/%s%s", homedir, tmp2, path + 12) == -1)
1009 errExit("asprintf");
1010 if(called_as_root)
1011 EUID_ROOT();
1012 return new_name;
1013 }
751 } 1014 }
752 1015
753 char *rv = strdup(path); 1016 char *rv = strdup(path);
754 if (!rv) 1017 if (!rv)
755 errExit("strdup"); 1018 errExit("strdup");
1019
1020 if(called_as_root)
1021 EUID_ROOT();
1022
756 return rv; 1023 return rv;
757} 1024}
758 1025