diff options
author | 2018-07-23 19:16:23 -0400 | |
---|---|---|
committer | 2018-07-23 19:16:23 -0400 | |
commit | fff306c991ff1f33ccb56313e4c166a169555656 (patch) | |
tree | aca84d4befea348bb7fd50c8c7639ace8157f39f /src | |
parent | Fix #1638 (diff) | |
download | firejail-fff306c991ff1f33ccb56313e4c166a169555656.tar.gz firejail-fff306c991ff1f33ccb56313e4c166a169555656.tar.zst firejail-fff306c991ff1f33ccb56313e4c166a169555656.zip |
Add ${MUSIC}, ${VIDEOS}, ${PICTURES}, ${DOCUMENTS}, and ${DESKTOP} (Fixes #259)
Diffstat (limited to 'src')
-rw-r--r-- | src/firejail/fs_whitelist.c | 371 | ||||
-rw-r--r-- | src/firejail/util.c | 10 |
2 files changed, 282 insertions, 99 deletions
diff --git a/src/firejail/fs_whitelist.c b/src/firejail/fs_whitelist.c index cddfaa017..bf839b524 100644 --- a/src/firejail/fs_whitelist.c +++ b/src/firejail/fs_whitelist.c | |||
@@ -34,115 +34,158 @@ | |||
34 | //#define TEST_MOUNTINFO | 34 | //#define TEST_MOUNTINFO |
35 | 35 | ||
36 | static char *dentry[] = { | 36 | static char *dentry[] = { |
37 | "Downloads", | 37 | "Downloads", |
38 | "Загрузки", | 38 | "Загрузки", |
39 | "Téléchargement", | 39 | "Téléchargement", |
40 | NULL | 40 | NULL |
41 | }; | 41 | }; |
42 | 42 | ||
43 | #define EMPTY_STRING ("") | 43 | static char *mentry[] = { |
44 | #define MAXBUF 4098 | 44 | "Music", |
45 | static char *resolve_downloads(int nowhitelist_flag) { | 45 | "Музыка", |
46 | EUID_ASSERT(); | 46 | "Musique", |
47 | char *fname; | 47 | NULL |
48 | struct stat s; | 48 | }; |
49 | |||
50 | // try a name from ~/.config/user-dirs.dirs | ||
51 | if (asprintf(&fname, "%s/.config/user-dirs.dirs", cfg.homedir) == -1) | ||
52 | errExit("asprintf"); | ||
53 | FILE *fp = fopen(fname, "r"); | ||
54 | if (!fp) { | ||
55 | free(fname); | ||
56 | return NULL; | ||
57 | } | ||
58 | free(fname); | ||
59 | |||
60 | // extract downloads directory | ||
61 | char buf[MAXBUF]; | ||
62 | while (fgets(buf, MAXBUF, fp)) { | ||
63 | char *ptr = buf; | ||
64 | 49 | ||
65 | // skip blanks | 50 | static char *ventry[] = { |
66 | while (*ptr == ' ' || *ptr == '\t') | 51 | "Videos", |
67 | ptr++; | 52 | "Видео", |
68 | if (*ptr == '\0' || *ptr == '\n' || *ptr == '#') | 53 | "Vidéos", |
69 | continue; | 54 | NULL |
55 | }; | ||
70 | 56 | ||
71 | if (strncmp(ptr, "XDG_DOWNLOAD_DIR=\"$HOME/", 24) == 0) { | 57 | static char *pentry[] = { |
72 | char *ptr1 = ptr + 24; | 58 | "Pictures", |
73 | char *ptr2 = strchr(ptr1, '"'); | 59 | "Изображения", |
74 | if (ptr2) { | 60 | "Photos", |
75 | fclose(fp); | 61 | NULL |
76 | *ptr2 = '\0'; | 62 | }; |
77 | if (arg_debug || arg_debug_whitelists) | ||
78 | printf("extracted %s from ~/.config/user-dirs.dirs\n", ptr1); | ||
79 | if (strlen(ptr1) != 0) { | ||
80 | if (arg_debug || arg_debug_whitelists) | ||
81 | printf("Downloads directory resolved as \"%s\"\n", ptr1); | ||
82 | |||
83 | if (asprintf(&fname, "%s/%s", cfg.homedir, ptr1) == -1) | ||
84 | errExit("asprintf"); | ||
85 | |||
86 | if (stat(fname, &s) == -1) { | ||
87 | free(fname); | ||
88 | goto errout; | ||
89 | } | ||
90 | |||
91 | char *rv; | ||
92 | if (nowhitelist_flag) { | ||
93 | if (asprintf(&rv, "nowhitelist ~/%s", ptr + 24) == -1) | ||
94 | errExit("asprintf"); | ||
95 | } | ||
96 | else { | ||
97 | if (asprintf(&rv, "whitelist ~/%s", ptr + 24) == -1) | ||
98 | errExit("asprintf"); | ||
99 | } | ||
100 | return rv; | ||
101 | } | ||
102 | else | ||
103 | goto errout; | ||
104 | } | ||
105 | } | ||
106 | } | ||
107 | 63 | ||
108 | // try a well known download directory name | 64 | static char *deentry[] = { |
109 | int i = 0; | 65 | "Desktop", |
110 | while (dentry[i] != NULL) { | 66 | "Рабочий стол", |
111 | if (asprintf(&fname, "%s/%s", cfg.homedir, dentry[i]) == -1) | 67 | "Bureau", |
112 | errExit("asprintf"); | 68 | NULL |
69 | }; | ||
113 | 70 | ||
114 | if (stat(fname, &s) == 0) { | 71 | static char *doentry[] = { |
115 | if (arg_debug || arg_debug_whitelists) | 72 | "Documents", |
116 | printf("Downloads directory resolved as \"%s\"\n", fname); | 73 | "Документы", |
74 | "Documents", | ||
75 | NULL | ||
76 | }; | ||
117 | 77 | ||
118 | char *rv; | 78 | #define EMPTY_STRING ("") |
119 | if (nowhitelist_flag) { | 79 | #define MAXBUF 4098 |
120 | if (asprintf(&rv, "nowhitelist ~/%s", dentry[i]) == -1) | ||
121 | errExit("asprintf"); | ||
122 | } | ||
123 | else { | ||
124 | if (asprintf(&rv, "whitelist ~/%s", dentry[i]) == -1) | ||
125 | errExit("asprintf"); | ||
126 | } | ||
127 | free(fname); | ||
128 | return rv; | ||
129 | } | ||
130 | free(fname); | ||
131 | i++; | ||
132 | } | ||
133 | 80 | ||
81 | static char *resolve_xdg(int nowhitelist_flag, const char *var, size_t length, const char *prnt) { | ||
82 | EUID_ASSERT(); | ||
83 | char *fname; | ||
84 | struct stat s; | ||
85 | |||
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) { | ||
134 | fclose(fp); | 109 | fclose(fp); |
135 | return NULL; | 110 | *ptr2 = '\0'; |
136 | 111 | if (arg_debug || arg_debug_whitelists) | |
137 | errout: | 112 | printf("extracted %s from ~/.config/user-dirs.dirs\n", ptr1); |
138 | if (!arg_private) { | 113 | if (strlen(ptr1) != 0) { |
139 | fprintf(stderr, "***\n"); | 114 | if (arg_debug || arg_debug_whitelists) |
140 | fprintf(stderr, "*** Error: Downloads directory was not found in user home.\n"); | 115 | printf("%s ",prnt); |
141 | fprintf(stderr, "*** \tAny files saved by the program, will be lost when the sandbox is closed.\n"); | 116 | printf("directory resolved as \"%s\"\n", ptr1); |
142 | fprintf(stderr, "***\n"); | 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; | ||
143 | } | 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 | } | ||
153 | return NULL; | ||
154 | } | ||
144 | 155 | ||
145 | return NULL; | 156 | static 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"); | ||
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 | } | ||
187 | |||
188 | return NULL; | ||
146 | } | 189 | } |
147 | 190 | ||
148 | static int mkpath(const char* path, mode_t mode) { | 191 | static int mkpath(const char* path, mode_t mode) { |
@@ -424,11 +467,16 @@ void fs_whitelist(void) { | |||
424 | 467 | ||
425 | // resolve ${DOWNLOADS} | 468 | // resolve ${DOWNLOADS} |
426 | if (strcmp(dataptr, "${DOWNLOADS}") == 0) { | 469 | if (strcmp(dataptr, "${DOWNLOADS}") == 0) { |
427 | char *tmp = resolve_downloads(nowhitelist_flag); | 470 | char *tmp = resolve_xdg(nowhitelist_flag, "XDG_DOWNLOAD_DIR=\"$HOME/", 24, "Downloads"); |
471 | char *tmp2 = resolve_hardcoded(nowhitelist_flag, dentry, "Downloads"); | ||
428 | if (tmp) { | 472 | if (tmp) { |
429 | entry->data = tmp; | 473 | entry->data = tmp; |
430 | dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10; | 474 | dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10; |
431 | } | 475 | } |
476 | else if (tmp2) { | ||
477 | entry->data = tmp2; | ||
478 | dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10; | ||
479 | } | ||
432 | else { | 480 | else { |
433 | if (!nowhitelist_flag && !arg_quiet && !arg_private) { | 481 | if (!nowhitelist_flag && !arg_quiet && !arg_private) { |
434 | fprintf(stderr, "***\n"); | 482 | fprintf(stderr, "***\n"); |
@@ -442,6 +490,131 @@ void fs_whitelist(void) { | |||
442 | } | 490 | } |
443 | } | 491 | } |
444 | 492 | ||
493 | // resolve ${MUSIC} | ||
494 | if (strcmp(dataptr, "${MUSIC}") == 0) { | ||
495 | char *tmp = resolve_xdg(nowhitelist_flag, "XDG_MUSIC_DIR=\"$HOME/", 21, "Music"); | ||
496 | char *tmp2 = resolve_hardcoded(nowhitelist_flag, mentry, "Music"); | ||
497 | if (tmp) { | ||
498 | entry->data = tmp; | ||
499 | dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10; | ||
500 | } | ||
501 | else if (tmp2) { | ||
502 | entry->data = tmp2; | ||
503 | dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10; | ||
504 | } | ||
505 | else { | ||
506 | if (!nowhitelist_flag && !arg_quiet && !arg_private) { | ||
507 | fprintf(stderr, "***\n"); | ||
508 | fprintf(stderr, "*** Warning: cannot whitelist Music directory\n"); | ||
509 | fprintf(stderr, "*** \tAny file saved will be lost when the sandbox is closed.\n"); | ||
510 | fprintf(stderr, "*** \tPlease create a proper Music directory for your application.\n"); | ||
511 | fprintf(stderr, "***\n"); | ||
512 | } | ||
513 | entry->data = EMPTY_STRING; | ||
514 | continue; | ||
515 | } | ||
516 | } | ||
517 | |||
518 | // resolve ${VIDEOS} | ||
519 | if (strcmp(dataptr, "${VIDEOS}") == 0) { | ||
520 | char *tmp = resolve_xdg(nowhitelist_flag, "XDG_VIDEOS_DIR=\"$HOME/", 22, "Videos"); | ||
521 | char *tmp2 = resolve_hardcoded(nowhitelist_flag, ventry, "Videos"); | ||
522 | if (tmp) { | ||
523 | entry->data = tmp; | ||
524 | dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10; | ||
525 | } | ||
526 | else if (tmp2) { | ||
527 | entry->data = tmp2; | ||
528 | dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10; | ||
529 | } | ||
530 | else { | ||
531 | if (!nowhitelist_flag && !arg_quiet && !arg_private) { | ||
532 | fprintf(stderr, "***\n"); | ||
533 | fprintf(stderr, "*** Warning: cannot whitelist Videos directory\n"); | ||
534 | fprintf(stderr, "*** \tAny file saved will be lost when the sandbox is closed.\n"); | ||
535 | fprintf(stderr, "*** \tPlease create a proper Videos directory for your application.\n"); | ||
536 | fprintf(stderr, "***\n"); | ||
537 | } | ||
538 | entry->data = EMPTY_STRING; | ||
539 | continue; | ||
540 | } | ||
541 | } | ||
542 | |||
543 | // resolve ${PICTURES} | ||
544 | if (strcmp(dataptr, "${PICTURES}") == 0) { | ||
545 | char *tmp = resolve_xdg(nowhitelist_flag, "XDG_PICTURES_DIR=\"$HOME/", 24, "Pictures"); | ||
546 | char *tmp2 = resolve_hardcoded(nowhitelist_flag, pentry, "Pictures"); | ||
547 | if (tmp) { | ||
548 | entry->data = tmp; | ||
549 | dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10; | ||
550 | } | ||
551 | else if (tmp2) { | ||
552 | entry->data = tmp2; | ||
553 | dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10; | ||
554 | } | ||
555 | else { | ||
556 | if (!nowhitelist_flag && !arg_quiet && !arg_private) { | ||
557 | fprintf(stderr, "***\n"); | ||
558 | fprintf(stderr, "*** Warning: cannot whitelist Pictures directory\n"); | ||
559 | fprintf(stderr, "*** \tAny file saved will be lost when the sandbox is closed.\n"); | ||
560 | fprintf(stderr, "*** \tPlease create a proper Pictures directory for your application.\n"); | ||
561 | fprintf(stderr, "***\n"); | ||
562 | } | ||
563 | entry->data = EMPTY_STRING; | ||
564 | continue; | ||
565 | } | ||
566 | } | ||
567 | |||
568 | // resolve ${DESKTOP} | ||
569 | if (strcmp(dataptr, "${DESKTOP}") == 0) { | ||
570 | char *tmp = resolve_xdg(nowhitelist_flag, "XDG_DESKTOP_DIR=\"$HOME/", 24, "Desktop"); | ||
571 | char *tmp2 = resolve_hardcoded(nowhitelist_flag, deentry, "Desktop"); | ||
572 | if (tmp) { | ||
573 | entry->data = tmp; | ||
574 | dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10; | ||
575 | } | ||
576 | else if (tmp2) { | ||
577 | entry->data = tmp2; | ||
578 | dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10; | ||
579 | } | ||
580 | else { | ||
581 | if (!nowhitelist_flag && !arg_quiet && !arg_private) { | ||
582 | fprintf(stderr, "***\n"); | ||
583 | fprintf(stderr, "*** Warning: cannot whitelist Desktop directory\n"); | ||
584 | fprintf(stderr, "*** \tAny file saved will be lost when the sandbox is closed.\n"); | ||
585 | fprintf(stderr, "*** \tPlease create a proper Desktop directory for your application.\n"); | ||
586 | fprintf(stderr, "***\n"); | ||
587 | } | ||
588 | entry->data = EMPTY_STRING; | ||
589 | continue; | ||
590 | } | ||
591 | } | ||
592 | |||
593 | // resolve ${DOCUMENTS} | ||
594 | if (strcmp(dataptr, "${DOCUMENTS}") == 0) { | ||
595 | char *tmp = resolve_xdg(nowhitelist_flag, "XDG_DOCUMENTS_DIR=\"$HOME/", 25, "Documents"); | ||
596 | char *tmp2 = resolve_hardcoded(nowhitelist_flag, doentry, "Documents"); | ||
597 | if (tmp) { | ||
598 | entry->data = tmp; | ||
599 | dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10; | ||
600 | } | ||
601 | else if (tmp2) { | ||
602 | entry->data = tmp2; | ||
603 | dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10; | ||
604 | } | ||
605 | else { | ||
606 | if (!nowhitelist_flag && !arg_quiet && !arg_private) { | ||
607 | fprintf(stderr, "***\n"); | ||
608 | fprintf(stderr, "*** Warning: cannot whitelist Documents directory\n"); | ||
609 | fprintf(stderr, "*** \tAny file saved will be lost when the sandbox is closed.\n"); | ||
610 | fprintf(stderr, "*** \tPlease create a proper Documents directory for your application.\n"); | ||
611 | fprintf(stderr, "***\n"); | ||
612 | } | ||
613 | entry->data = EMPTY_STRING; | ||
614 | continue; | ||
615 | } | ||
616 | } | ||
617 | |||
445 | // replace ~/ or ${HOME} into /home/username | 618 | // replace ~/ or ${HOME} into /home/username |
446 | new_name = expand_home(dataptr, cfg.homedir); | 619 | new_name = expand_home(dataptr, cfg.homedir); |
447 | assert(new_name); | 620 | assert(new_name); |
diff --git a/src/firejail/util.c b/src/firejail/util.c index f634ff700..fa32ffcc8 100644 --- a/src/firejail/util.c +++ b/src/firejail/util.c | |||
@@ -826,6 +826,16 @@ void invalid_filename(const char *fname, int globbing) { | |||
826 | ptr = fname + 7; | 826 | ptr = fname + 7; |
827 | else if (strcmp(fname, "${DOWNLOADS}") == 0) | 827 | else if (strcmp(fname, "${DOWNLOADS}") == 0) |
828 | return; | 828 | return; |
829 | else if (strcmp(fname, "${MUSIC}") == 0) | ||
830 | return; | ||
831 | else if (strcmp(fname, "${VIDEOS}") == 0) | ||
832 | return; | ||
833 | else if (strcmp(fname, "${PICTURES}") == 0) | ||
834 | return; | ||
835 | else if (strcmp(fname, "${DESKTOP}") == 0) | ||
836 | return; | ||
837 | else if (strcmp(fname, "${DOCUMENTS}") == 0) | ||
838 | return; | ||
829 | 839 | ||
830 | int len = strlen(ptr); | 840 | int len = strlen(ptr); |
831 | 841 | ||