diff options
author | 2023-12-04 09:11:08 -0500 | |
---|---|---|
committer | 2023-12-04 09:11:08 -0500 | |
commit | 2033e98e79721c82cb704dcc46b37cdb58afd986 (patch) | |
tree | dea825dcf577e7c178f2f4f9bf8d0741cab6f147 /src | |
parent | RELNOTES: add modif, bugfix, build and contrib items (diff) | |
parent | firecfg: add ignore command and docs (diff) | |
download | firejail-2033e98e79721c82cb704dcc46b37cdb58afd986.tar.gz firejail-2033e98e79721c82cb704dcc46b37cdb58afd986.tar.zst firejail-2033e98e79721c82cb704dcc46b37cdb58afd986.zip |
Merge pull request #5876 from kmk3/firecfg-add-confdir-ignore
feature: firecfg: add firecfg.d & add ignore command
Diffstat (limited to 'src')
-rw-r--r-- | src/firecfg/firecfg.h | 10 | ||||
-rw-r--r-- | src/firecfg/main.c | 145 | ||||
-rw-r--r-- | src/man/firecfg.1.in | 57 |
3 files changed, 159 insertions, 53 deletions
diff --git a/src/firecfg/firecfg.h b/src/firecfg/firecfg.h index 8f74a1198..11e3ebc67 100644 --- a/src/firecfg/firecfg.h +++ b/src/firecfg/firecfg.h | |||
@@ -37,6 +37,16 @@ | |||
37 | #include "../include/common.h" | 37 | #include "../include/common.h" |
38 | #define MAX_BUF 4096 | 38 | #define MAX_BUF 4096 |
39 | 39 | ||
40 | // config files | ||
41 | #define FIRECFG_CFGFILE SYSCONFDIR "/firecfg.config" | ||
42 | #define FIRECFG_CONF_GLOB SYSCONFDIR "/firecfg.d/*.conf" | ||
43 | |||
44 | // programs | ||
45 | #define FIREJAIL_EXEC PREFIX "/bin/firejail" | ||
46 | #define FIREJAIL_WELCOME_SH LIBDIR "/firejail/firejail-welcome.sh" | ||
47 | #define FZENITY_EXEC LIBDIR "/firejail/fzenity" | ||
48 | #define ZENITY_EXEC "/usr/bin/zenity" | ||
49 | #define SUDO_EXEC "sudo" | ||
40 | 50 | ||
41 | // main.c | 51 | // main.c |
42 | extern int arg_debug; | 52 | extern int arg_debug; |
diff --git a/src/firecfg/main.c b/src/firecfg/main.c index 4ec81c5b3..604b12633 100644 --- a/src/firecfg/main.c +++ b/src/firecfg/main.c | |||
@@ -20,6 +20,8 @@ | |||
20 | 20 | ||
21 | #include "firecfg.h" | 21 | #include "firecfg.h" |
22 | #include "../include/firejail_user.h" | 22 | #include "../include/firejail_user.h" |
23 | #include <glob.h> | ||
24 | |||
23 | int arg_debug = 0; | 25 | int arg_debug = 0; |
24 | char *arg_bindir = "/usr/local/bin"; | 26 | char *arg_bindir = "/usr/local/bin"; |
25 | int arg_guide = 0; | 27 | int arg_guide = 0; |
@@ -76,10 +78,6 @@ static void list(void) { | |||
76 | exit(1); | 78 | exit(1); |
77 | } | 79 | } |
78 | 80 | ||
79 | char *firejail_exec; | ||
80 | if (asprintf(&firejail_exec, "%s/bin/firejail", PREFIX) == -1) | ||
81 | errExit("asprintf"); | ||
82 | |||
83 | struct dirent *entry; | 81 | struct dirent *entry; |
84 | while ((entry = readdir(dir)) != NULL) { | 82 | while ((entry = readdir(dir)) != NULL) { |
85 | if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) | 83 | if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) |
@@ -92,7 +90,7 @@ static void list(void) { | |||
92 | if (is_link(fullname)) { | 90 | if (is_link(fullname)) { |
93 | char* fname = realpath(fullname, NULL); | 91 | char* fname = realpath(fullname, NULL); |
94 | if (fname) { | 92 | if (fname) { |
95 | if (strcmp(fname, firejail_exec) == 0) | 93 | if (strcmp(fname, FIREJAIL_EXEC) == 0) |
96 | printf("%s\n", fullname); | 94 | printf("%s\n", fullname); |
97 | free(fname); | 95 | free(fname); |
98 | } | 96 | } |
@@ -101,7 +99,6 @@ static void list(void) { | |||
101 | } | 99 | } |
102 | 100 | ||
103 | closedir(dir); | 101 | closedir(dir); |
104 | free(firejail_exec); | ||
105 | } | 102 | } |
106 | 103 | ||
107 | static void clean(void) { | 104 | static void clean(void) { |
@@ -114,10 +111,6 @@ static void clean(void) { | |||
114 | exit(1); | 111 | exit(1); |
115 | } | 112 | } |
116 | 113 | ||
117 | char *firejail_exec; | ||
118 | if (asprintf(&firejail_exec, "%s/bin/firejail", PREFIX) == -1) | ||
119 | errExit("asprintf"); | ||
120 | |||
121 | struct dirent *entry; | 114 | struct dirent *entry; |
122 | while ((entry = readdir(dir)) != NULL) { | 115 | while ((entry = readdir(dir)) != NULL) { |
123 | if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) | 116 | if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) |
@@ -130,7 +123,7 @@ static void clean(void) { | |||
130 | if (is_link(fullname)) { | 123 | if (is_link(fullname)) { |
131 | char* fname = realpath(fullname, NULL); | 124 | char* fname = realpath(fullname, NULL); |
132 | if (fname) { | 125 | if (fname) { |
133 | if (strcmp(fname, firejail_exec) == 0) { | 126 | if (strcmp(fname, FIREJAIL_EXEC) == 0) { |
134 | char *ptr = strrchr(fullname, '/'); | 127 | char *ptr = strrchr(fullname, '/'); |
135 | assert(ptr); | 128 | assert(ptr); |
136 | ptr++; | 129 | ptr++; |
@@ -147,10 +140,43 @@ static void clean(void) { | |||
147 | } | 140 | } |
148 | 141 | ||
149 | closedir(dir); | 142 | closedir(dir); |
150 | free(firejail_exec); | ||
151 | printf("\n"); | 143 | printf("\n"); |
152 | } | 144 | } |
153 | 145 | ||
146 | #define ignorelist_maxlen 2048 | ||
147 | static const char *ignorelist[ignorelist_maxlen]; | ||
148 | static int ignorelist_len = 0; | ||
149 | |||
150 | static int append_ignorelist(const char *const str) { | ||
151 | assert(str); | ||
152 | if (ignorelist_len >= ignorelist_maxlen) { | ||
153 | fprintf(stderr, "Warning: Ignore list is full (%d/%d), skipping %s\n", | ||
154 | ignorelist_len, ignorelist_maxlen, str); | ||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | printf(" ignoring '%s'\n", str); | ||
159 | const char *const dup = strdup(str); | ||
160 | if (!dup) | ||
161 | errExit("strdup"); | ||
162 | |||
163 | ignorelist[ignorelist_len] = dup; | ||
164 | ignorelist_len++; | ||
165 | |||
166 | return 1; | ||
167 | } | ||
168 | |||
169 | static int in_ignorelist(const char *const str) { | ||
170 | assert(str); | ||
171 | int i; | ||
172 | for (i = 0; i < ignorelist_len; i++) { | ||
173 | if (strcmp(str, ignorelist[i]) == 0) | ||
174 | return 1; | ||
175 | } | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
154 | static void set_file(const char *name, const char *firejail_exec) { | 180 | static void set_file(const char *name, const char *firejail_exec) { |
155 | if (which(name) == 0) | 181 | if (which(name) == 0) |
156 | return; | 182 | return; |
@@ -165,35 +191,26 @@ static void set_file(const char *name, const char *firejail_exec) { | |||
165 | if (rv) { | 191 | if (rv) { |
166 | fprintf(stderr, "Error: cannot create %s symbolic link\n", fname); | 192 | fprintf(stderr, "Error: cannot create %s symbolic link\n", fname); |
167 | perror("symlink"); | 193 | perror("symlink"); |
168 | } | 194 | } else { |
169 | else | ||
170 | printf(" %s created\n", name); | 195 | printf(" %s created\n", name); |
171 | } | 196 | } |
172 | else { | 197 | } else { |
173 | fprintf(stderr, "Warning: cannot create %s - already exists! Skipping...\n", fname); | 198 | fprintf(stderr, "Warning: cannot create %s - already exists! Skipping...\n", fname); |
174 | } | 199 | } |
175 | 200 | ||
176 | free(fname); | 201 | free(fname); |
177 | } | 202 | } |
178 | 203 | ||
179 | // parse /etc/firejail/firecfg.config file | 204 | // parse a single config file |
180 | static void set_links_firecfg(void) { | 205 | static void set_links_firecfg(const char *cfgfile) { |
181 | char *cfgfile; | 206 | printf("Configuring symlinks in %s based on %s\n", arg_bindir, cfgfile); |
182 | if (asprintf(&cfgfile, "%s/firecfg.config", SYSCONFDIR) == -1) | ||
183 | errExit("asprintf"); | ||
184 | |||
185 | char *firejail_exec; | ||
186 | if (asprintf(&firejail_exec, "%s/bin/firejail", PREFIX) == -1) | ||
187 | errExit("asprintf"); | ||
188 | 207 | ||
189 | // parse /etc/firejail/firecfg.config file | ||
190 | FILE *fp = fopen(cfgfile, "r"); | 208 | FILE *fp = fopen(cfgfile, "r"); |
191 | if (!fp) { | 209 | if (!fp) { |
192 | perror("fopen"); | 210 | perror("fopen"); |
193 | fprintf(stderr, "Error: cannot open %s\n", cfgfile); | 211 | fprintf(stderr, "Error: cannot open %s\n", cfgfile); |
194 | exit(1); | 212 | exit(1); |
195 | } | 213 | } |
196 | printf("Configuring symlinks in %s based on firecfg.config\n", arg_bindir); | ||
197 | 214 | ||
198 | char buf[MAX_BUF]; | 215 | char buf[MAX_BUF]; |
199 | int lineno = 0; | 216 | int lineno = 0; |
@@ -223,13 +240,43 @@ static void set_links_firecfg(void) { | |||
223 | if (*start == '\0') | 240 | if (*start == '\0') |
224 | continue; | 241 | continue; |
225 | 242 | ||
243 | // handle ignore command | ||
244 | if (*start == '!') { | ||
245 | append_ignorelist(start + 1); | ||
246 | continue; | ||
247 | } | ||
248 | |||
226 | // set link | 249 | // set link |
227 | set_file(start, firejail_exec); | 250 | if (!in_ignorelist(start)) |
251 | set_file(start, FIREJAIL_EXEC); | ||
252 | else | ||
253 | printf(" %s ignored\n", start); | ||
228 | } | 254 | } |
229 | 255 | ||
230 | fclose(fp); | 256 | fclose(fp); |
231 | free(cfgfile); | 257 | printf("\n"); |
232 | free(firejail_exec); | 258 | } |
259 | |||
260 | // parse all config files matching pattern | ||
261 | static void set_links_firecfg_glob(const char *pattern) { | ||
262 | printf("Looking for config files in %s\n", pattern); | ||
263 | |||
264 | glob_t globbuf; | ||
265 | int globerr = glob(pattern, 0, NULL, &globbuf); | ||
266 | if (globerr == GLOB_NOMATCH) { | ||
267 | fprintf(stderr, "No matches for glob pattern %s\n", pattern); | ||
268 | goto out; | ||
269 | } else if (globerr != 0) { | ||
270 | fprintf(stderr, "Warning: Failed to match glob pattern %s: %s\n", | ||
271 | pattern, strerror(errno)); | ||
272 | goto out; | ||
273 | } | ||
274 | |||
275 | size_t i; | ||
276 | for (i = 0; i < globbuf.gl_pathc; i++) | ||
277 | set_links_firecfg(globbuf.gl_pathv[i]); | ||
278 | out: | ||
279 | globfree(&globbuf); | ||
233 | } | 280 | } |
234 | 281 | ||
235 | // parse ~/.config/firejail/ directory | 282 | // parse ~/.config/firejail/ directory |
@@ -246,10 +293,6 @@ static void set_links_homedir(const char *homedir) { | |||
246 | return; | 293 | return; |
247 | } | 294 | } |
248 | 295 | ||
249 | char *firejail_exec; | ||
250 | if (asprintf(&firejail_exec, "%s/bin/firejail", PREFIX) == -1) | ||
251 | errExit("asprintf"); | ||
252 | |||
253 | // parse ~/.config/firejail/ directory | 296 | // parse ~/.config/firejail/ directory |
254 | printf("\nConfiguring symlinks in %s based on local firejail config directory\n", arg_bindir); | 297 | printf("\nConfiguring symlinks in %s based on local firejail config directory\n", arg_bindir); |
255 | 298 | ||
@@ -260,6 +303,7 @@ static void set_links_homedir(const char *homedir) { | |||
260 | free(dirname); | 303 | free(dirname); |
261 | return; | 304 | return; |
262 | } | 305 | } |
306 | free(dirname); | ||
263 | 307 | ||
264 | struct dirent *entry; | 308 | struct dirent *entry; |
265 | while ((entry = readdir(dir))) { | 309 | while ((entry = readdir(dir))) { |
@@ -280,12 +324,10 @@ static void set_links_homedir(const char *homedir) { | |||
280 | } | 324 | } |
281 | 325 | ||
282 | *ptr = '\0'; | 326 | *ptr = '\0'; |
283 | set_file(exec, firejail_exec); | 327 | set_file(exec, FIREJAIL_EXEC); |
284 | free(exec); | 328 | free(exec); |
285 | } | 329 | } |
286 | closedir(dir); | 330 | closedir(dir); |
287 | |||
288 | free(firejail_exec); | ||
289 | } | 331 | } |
290 | 332 | ||
291 | static const char *get_sudo_user(void) { | 333 | static const char *get_sudo_user(void) { |
@@ -449,18 +491,20 @@ int main(int argc, char **argv) { | |||
449 | } | 491 | } |
450 | 492 | ||
451 | if (arg_guide) { | 493 | if (arg_guide) { |
494 | const char *zenity_exec; | ||
495 | if (arg_debug) | ||
496 | zenity_exec = FZENITY_EXEC; | ||
497 | else | ||
498 | zenity_exec = ZENITY_EXEC; | ||
499 | |||
452 | char *cmd; | 500 | char *cmd; |
453 | if (arg_debug) { | 501 | if (asprintf(&cmd, "%s %s %s %s %s", |
454 | if (asprintf(&cmd, "sudo %s/firejail/firejail-welcome.sh /usr/lib/firejail/fzenity %s %s", LIBDIR, SYSCONFDIR, user) == -1) | 502 | SUDO_EXEC, FIREJAIL_WELCOME_SH, zenity_exec, SYSCONFDIR, user) == -1) |
455 | errExit("asprintf"); | 503 | errExit("asprintf"); |
456 | } | 504 | |
457 | else { | ||
458 | if (asprintf(&cmd, "sudo %s/firejail/firejail-welcome.sh /usr/bin/zenity %s %s", LIBDIR, SYSCONFDIR, user) == -1) | ||
459 | errExit("asprintf"); | ||
460 | } | ||
461 | int status = system(cmd); | 505 | int status = system(cmd); |
462 | if (status == -1) { | 506 | if (status == -1) { |
463 | fprintf(stderr, "Error: cannot run firejail-welcome.sh\n"); | 507 | fprintf(stderr, "Error: cannot run %s\n", FIREJAIL_WELCOME_SH); |
464 | exit(1); | 508 | exit(1); |
465 | } | 509 | } |
466 | free(cmd); | 510 | free(cmd); |
@@ -474,12 +518,15 @@ else { | |||
474 | // clear all symlinks | 518 | // clear all symlinks |
475 | clean(); | 519 | clean(); |
476 | 520 | ||
477 | // set new symlinks based on /etc/firejail/firecfg.config | 521 | // set new symlinks based on .conf files |
478 | set_links_firecfg(); | 522 | set_links_firecfg_glob(FIRECFG_CONF_GLOB); |
523 | |||
524 | // set new symlinks based on firecfg.config | ||
525 | set_links_firecfg(FIRECFG_CFGFILE); | ||
479 | 526 | ||
480 | if (getuid() == 0) { | 527 | if (getuid() == 0) { |
481 | // add user to firejail access database - only for root | 528 | // add user to firejail access database - only for root |
482 | printf("\nAdding user %s to Firejail access database in %s/firejail.users\n", user, SYSCONFDIR); | 529 | printf("Adding user %s to Firejail access database in %s/firejail.users\n", user, SYSCONFDIR); |
483 | // temporarily set the umask, access database must be world-readable | 530 | // temporarily set the umask, access database must be world-readable |
484 | mode_t orig_umask = umask(022); | 531 | mode_t orig_umask = umask(022); |
485 | firejail_user_add(user); | 532 | firejail_user_add(user); |
diff --git a/src/man/firecfg.1.in b/src/man/firecfg.1.in index a85fbc5da..e43a573de 100644 --- a/src/man/firecfg.1.in +++ b/src/man/firecfg.1.in | |||
@@ -29,9 +29,13 @@ Note: The examples use \fBsudo\fR, but \fBdoas\fR is also supported. | |||
29 | To set it up, run "sudo firecfg" after installing Firejail software. | 29 | To set it up, run "sudo firecfg" after installing Firejail software. |
30 | The same command should also be run after | 30 | The same command should also be run after |
31 | installing new programs. If the program is supported by Firejail, the symbolic link in /usr/local/bin | 31 | installing new programs. If the program is supported by Firejail, the symbolic link in /usr/local/bin |
32 | will be created. For a full list of programs supported by default run "cat /etc/firejail/firecfg.config". | 32 | will be created. |
33 | 33 | .PP | |
34 | For user-driven manual integration, see \fBDESKTOP INTEGRATION\fR section in \fBman 1 firejail\fR. | 34 | To configure the list of programs used by firecfg when creating symlinks, see |
35 | \fBFILES\fR and \fBSYNTAX\fR. | ||
36 | .PP | ||
37 | For user-driven manual integration, see \fBDESKTOP INTEGRATION\fR section in | ||
38 | \fBman 1 firejail\fR. | ||
35 | .SH DEFAULT ACTIONS | 39 | .SH DEFAULT ACTIONS |
36 | The following actions are implemented by default by running sudo firecfg: | 40 | The following actions are implemented by default by running sudo firecfg: |
37 | 41 | ||
@@ -135,8 +139,53 @@ $ sudo firecfg --clean | |||
135 | /usr/local/bin/vlc removed | 139 | /usr/local/bin/vlc removed |
136 | .br | 140 | .br |
137 | [...] | 141 | [...] |
142 | .SH FILES | ||
143 | .PP | ||
144 | Configuration files are searched for and parsed in the following paths: | ||
145 | .PP | ||
146 | .RS | ||
147 | 1. /etc/firejail/firecfg.d/*.conf (in alphabetical order) | ||
148 | .br | ||
149 | 2. /etc/firejail/firecfg.config | ||
150 | .RE | ||
151 | .PP | ||
152 | The programs that are supported by default are listed in | ||
153 | /etc/firejail/firecfg.config. | ||
154 | It is recommended to leave it as is and put all customizations inside | ||
155 | /etc/firejail/firecfg.d/. | ||
156 | .PP | ||
157 | Profile files are also searched in the user configuration directory: | ||
158 | .PP | ||
159 | .RS | ||
160 | 3. ~/.config/firejail/*.profile | ||
161 | .RE | ||
162 | .PP | ||
163 | For every \fBPROGRAM.profile\fR file found, firecfg attempts to create a | ||
164 | symlink for "PROGRAM", as if "PROGRAM" was listed in a configuration file. | ||
165 | .SH SYNTAX | ||
166 | Configuration file syntax: | ||
167 | .PP | ||
168 | A line that starts with \fB#\fR is considered a comment. | ||
169 | .br | ||
170 | A line that starts with \fB!PROGRAM\fR means to ignore "PROGRAM" when creating | ||
171 | symlinks. | ||
172 | .br | ||
173 | A line that starts with anything else is considered to be the name of an | ||
174 | executable and firecfg will attempt to create a symlink for it. | ||
175 | .PP | ||
176 | For example, to prevent firecfg from creating symlinks for "firefox" and | ||
177 | "patch" while attempting to create a symlink for "myprog", the following lines | ||
178 | could be added to /etc/firejail/firecfg.d/10-my.conf: | ||
179 | .PP | ||
180 | .RS | ||
181 | !firefox | ||
182 | .br | ||
183 | !patch | ||
184 | .br | ||
138 | 185 | ||
139 | 186 | .br | |
187 | myprog | ||
188 | .RE | ||
140 | .SH LICENSE | 189 | .SH LICENSE |
141 | This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. | 190 | This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. |
142 | .PP | 191 | .PP |