diff options
author | netblue30 <netblue30@yahoo.com> | 2017-09-25 07:38:01 -0400 |
---|---|---|
committer | netblue30 <netblue30@yahoo.com> | 2017-09-25 07:38:01 -0400 |
commit | a6341b904c08b1feb51e264ab487d1f125222a10 (patch) | |
tree | 35ea50b8c8e561b710272a0e8ae9418541a32925 | |
parent | Remove whitelist from pinta (diff) | |
download | firejail-a6341b904c08b1feb51e264ab487d1f125222a10.tar.gz firejail-a6341b904c08b1feb51e264ab487d1f125222a10.tar.zst firejail-a6341b904c08b1feb51e264ab487d1f125222a10.zip |
disable DBus activation in firecfg
-rw-r--r-- | RELNOTES | 1 | ||||
-rw-r--r-- | src/firecfg/desktop_files.c | 265 | ||||
-rw-r--r-- | src/firecfg/firecfg.h | 51 | ||||
-rw-r--r-- | src/firecfg/main.c | 342 | ||||
-rw-r--r-- | src/firecfg/sound.c | 65 | ||||
-rw-r--r-- | src/firecfg/util.c | 86 |
6 files changed, 470 insertions, 340 deletions
@@ -1,6 +1,7 @@ | |||
1 | firejail (0.9.51) baseline; urgency=low | 1 | firejail (0.9.51) baseline; urgency=low |
2 | * work in progress! | 2 | * work in progress! |
3 | * enhancement: support Firejail user config directory in firecfg | 3 | * enhancement: support Firejail user config directory in firecfg |
4 | * enhancement: disable DBus activation in firecfg | ||
4 | * feature: --writable-run-user | 5 | * feature: --writable-run-user |
5 | * feature: profile build tool (--build) | 6 | * feature: profile build tool (--build) |
6 | -- netblue30 <netblue30@yahoo.com> Thu, 14 Sep 2017 20:00:00 -0500 | 7 | -- netblue30 <netblue30@yahoo.com> Thu, 14 Sep 2017 20:00:00 -0500 |
diff --git a/src/firecfg/desktop_files.c b/src/firecfg/desktop_files.c new file mode 100644 index 000000000..eaedc4b64 --- /dev/null +++ b/src/firecfg/desktop_files.c | |||
@@ -0,0 +1,265 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2017 Firejail Authors | ||
3 | * | ||
4 | * This file is part of firejail project | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #include "firecfg.h" | ||
22 | |||
23 | // look for a profile file in /etc/firejail diectory and in homedir/.config/firejail directory | ||
24 | static int have_profile(const char *filename, const char *homedir) { | ||
25 | assert(filename); | ||
26 | assert(homedir); | ||
27 | |||
28 | if (arg_debug) | ||
29 | printf("checking profile for %s\n", filename); | ||
30 | |||
31 | // remove .desktop extension; if file name starts with org.gnome... remove it | ||
32 | char *f1; | ||
33 | if (strncmp(filename, "org.gnome.", 10) == 0) | ||
34 | f1 = strdup(filename + 10); | ||
35 | else | ||
36 | f1 = strdup(filename); | ||
37 | if (!f1) | ||
38 | errExit("strdup"); | ||
39 | f1[strlen(f1) - 8] = '\0'; | ||
40 | if (arg_debug) | ||
41 | printf("looking for a profile for %s - %s\n", filename, f1); | ||
42 | |||
43 | // build profile name | ||
44 | char *profname1; | ||
45 | char *profname2; | ||
46 | if (asprintf(&profname1, "%s/%s.profile", SYSCONFDIR, f1) == -1) | ||
47 | errExit("asprintf"); | ||
48 | if (asprintf(&profname2, "%s/.config/firejail/%s.profile", homedir, f1) == -1) | ||
49 | errExit("asprintf"); | ||
50 | |||
51 | int rv = 0; | ||
52 | if (access(profname1, R_OK) == 0) { | ||
53 | if (arg_debug) | ||
54 | printf("found %s\n", profname1); | ||
55 | rv = 1; | ||
56 | } | ||
57 | else if (access(profname2, R_OK) == 0) { | ||
58 | if (arg_debug) | ||
59 | printf("found %s\n", profname2); | ||
60 | rv = 1; | ||
61 | } | ||
62 | |||
63 | if (arg_debug) | ||
64 | printf("Profile for %s %s\n", f1, (rv)? "found": "not found"); | ||
65 | free(f1); | ||
66 | free(profname1); | ||
67 | free(profname2); | ||
68 | return rv; | ||
69 | } | ||
70 | |||
71 | void fix_desktop_files(char *homedir) { | ||
72 | assert(homedir); | ||
73 | struct stat sb; | ||
74 | |||
75 | // check user | ||
76 | if (getuid() == 0) { | ||
77 | fprintf(stderr, "Error: this option is not supported for root user; please run as a regular user.\n"); | ||
78 | exit(1); | ||
79 | } | ||
80 | |||
81 | // destination | ||
82 | // create ~/.local/share/applications directory if necessary | ||
83 | char *user_apps_dir; | ||
84 | if (asprintf(&user_apps_dir, "%s/.local/share/applications", homedir) == -1) | ||
85 | errExit("asprintf"); | ||
86 | if (stat(user_apps_dir, &sb) == -1) { | ||
87 | int rv = mkdir(user_apps_dir, 0700); | ||
88 | if (rv) { | ||
89 | fprintf(stderr, "Error: cannot create ~/.local/application directory\n"); | ||
90 | perror("mkdir"); | ||
91 | exit(1); | ||
92 | } | ||
93 | rv = chmod(user_apps_dir, 0700); | ||
94 | (void) rv; | ||
95 | } | ||
96 | |||
97 | // source | ||
98 | DIR *dir = opendir("/usr/share/applications"); | ||
99 | if (!dir) { | ||
100 | perror("Error: cannot open /usr/share/applications directory"); | ||
101 | exit(1); | ||
102 | } | ||
103 | if (chdir("/usr/share/applications")) { | ||
104 | perror("Error: cannot chdir to /usr/share/applications"); | ||
105 | exit(1); | ||
106 | } | ||
107 | |||
108 | printf("\nFixing desktop files in %s\n", user_apps_dir); | ||
109 | // copy | ||
110 | struct dirent *entry; | ||
111 | while ((entry = readdir(dir)) != NULL) { | ||
112 | if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) | ||
113 | continue; | ||
114 | |||
115 | // skip if not regular file or link | ||
116 | // d_type is not available on some file systems | ||
117 | if (entry->d_type != DT_REG && entry->d_type != DT_LNK && entry->d_type != DT_UNKNOWN) | ||
118 | continue; | ||
119 | |||
120 | // skip if not .desktop file | ||
121 | if (strstr(entry->d_name,".desktop") != (entry->d_name+strlen(entry->d_name)-8)) | ||
122 | continue; | ||
123 | |||
124 | char *filename = entry->d_name; | ||
125 | |||
126 | // skip links | ||
127 | if (is_link(filename)) | ||
128 | continue; | ||
129 | if (stat(filename, &sb) == -1) | ||
130 | errExit("stat"); | ||
131 | |||
132 | // no profile in /etc/firejail, no desktop file fixing | ||
133 | if (!have_profile(filename, homedir)) | ||
134 | continue; | ||
135 | |||
136 | //**************************************************** | ||
137 | // load the file in memory and do some basic checking | ||
138 | //**************************************************** | ||
139 | /* coverity[toctou] */ | ||
140 | int fd = open(filename, O_RDONLY); | ||
141 | if (fd == -1) { | ||
142 | fprintf(stderr, "Error: cannot open /usr/share/applications/%s\n", filename); | ||
143 | continue; | ||
144 | } | ||
145 | |||
146 | char *buf = mmap(NULL, sb.st_size + 1, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); | ||
147 | if (buf == MAP_FAILED) | ||
148 | errExit("mmap"); | ||
149 | close(fd); | ||
150 | |||
151 | // check format | ||
152 | if (strstr(buf, "[Desktop Entry]\n") == NULL) { | ||
153 | if (arg_debug) | ||
154 | printf(" %s - skipped: wrong format?\n", filename); | ||
155 | munmap(buf, sb.st_size + 1); | ||
156 | continue; | ||
157 | } | ||
158 | |||
159 | // get executable name | ||
160 | char *ptr = strstr(buf,"\nExec="); | ||
161 | if (!ptr || strlen(ptr) < 7) { | ||
162 | if (arg_debug) | ||
163 | printf(" %s - skipped: wrong format?\n", filename); | ||
164 | munmap(buf, sb.st_size + 1); | ||
165 | continue; | ||
166 | } | ||
167 | |||
168 | char *execname = ptr + 6; | ||
169 | // executable name can be quoted, this is rare and currently unsupported, TODO | ||
170 | if (execname[0] == '"') { | ||
171 | if (arg_debug) | ||
172 | printf(" %s - skipped: path quoting unsupported\n", filename); | ||
173 | munmap(buf, sb.st_size + 1); | ||
174 | continue; | ||
175 | } | ||
176 | |||
177 | |||
178 | // try to decide if we need to covert this file | ||
179 | char *change_exec = NULL; | ||
180 | int change_dbus = 0; | ||
181 | |||
182 | // https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s06.html | ||
183 | // The executable program can either be specified with its full path | ||
184 | // or with the name of the executable only | ||
185 | if (execname[0] == '/') { | ||
186 | char *end_name = strchr(execname, ' '); | ||
187 | if (end_name) { | ||
188 | *end_name = '\0'; | ||
189 | char *start_name = strrchr(execname, '/'); | ||
190 | if (start_name) { | ||
191 | start_name++; | ||
192 | // check if we have the executable on the regular path | ||
193 | if (which(start_name)) { | ||
194 | change_exec = strdup(start_name); | ||
195 | if (!change_exec) | ||
196 | errExit("strdup"); | ||
197 | } | ||
198 | } | ||
199 | } | ||
200 | } | ||
201 | |||
202 | if (strstr(buf, "\nDBusActivatable=true")) | ||
203 | change_dbus = 1; | ||
204 | |||
205 | if (change_exec == NULL && change_dbus == 0) { | ||
206 | munmap(buf, sb.st_size + 1); | ||
207 | continue; | ||
208 | } | ||
209 | |||
210 | munmap(buf, sb.st_size + 1); | ||
211 | |||
212 | //**************************************************** | ||
213 | // generate output file | ||
214 | //**************************************************** | ||
215 | char *outname; | ||
216 | if (asprintf(&outname ,"%s/%s", user_apps_dir, filename) == -1) | ||
217 | errExit("asprintf"); | ||
218 | |||
219 | if (stat(outname, &sb) == 0) { | ||
220 | printf(" %s skipped: file exists\n", filename); | ||
221 | continue; | ||
222 | } | ||
223 | |||
224 | FILE *fpin = fopen(filename, "r"); | ||
225 | if (!fpin) { | ||
226 | fprintf(stderr, "Error: cannot open /usr/share/applications/%s\n", filename); | ||
227 | continue; | ||
228 | } | ||
229 | |||
230 | FILE *fpout = fopen(outname, "w"); | ||
231 | if (!fpout) { | ||
232 | fprintf(stderr, "Error: cannot open ~/.local/share/applications/%s\n", outname); | ||
233 | fclose(fpin); | ||
234 | continue; | ||
235 | } | ||
236 | fprintf(fpout, "# converted by firecfg\n"); | ||
237 | free(outname); | ||
238 | |||
239 | char fbuf[MAX_BUF]; | ||
240 | while (fgets(fbuf, MAX_BUF, fpin)) { | ||
241 | if (change_dbus && strcmp(fbuf, "DBusActivatable=true\n") == 0) | ||
242 | fprintf(fpout, "DBusActivatable=false\n"); | ||
243 | else if (change_exec && strncmp(fbuf, "Exec=", 5) == 0) { | ||
244 | char *start_params = strchr(fbuf + 5, ' '); | ||
245 | assert(start_params); | ||
246 | start_params++; | ||
247 | fprintf(fpout, "Exec=%s %s", change_exec, start_params); | ||
248 | } | ||
249 | else | ||
250 | fprintf(fpout, "%s", fbuf); | ||
251 | } | ||
252 | |||
253 | if (change_exec) | ||
254 | free(change_exec); | ||
255 | fclose(fpin); | ||
256 | fclose(fpout); | ||
257 | printf(" %s created\n", filename); | ||
258 | |||
259 | } | ||
260 | |||
261 | closedir(dir); | ||
262 | free(user_apps_dir); | ||
263 | } | ||
264 | |||
265 | |||
diff --git a/src/firecfg/firecfg.h b/src/firecfg/firecfg.h new file mode 100644 index 000000000..c4640feb8 --- /dev/null +++ b/src/firecfg/firecfg.h | |||
@@ -0,0 +1,51 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2017 Firejail Authors | ||
3 | * | ||
4 | * This file is part of firejail project | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | #define _GNU_SOURCE | ||
21 | #include <stdio.h> | ||
22 | #include <sys/types.h> | ||
23 | #include <dirent.h> | ||
24 | #include <sys/types.h> | ||
25 | #include <sys/stat.h> | ||
26 | #include <fcntl.h> | ||
27 | #include <unistd.h> | ||
28 | #include <grp.h> | ||
29 | #include <string.h> | ||
30 | #include <errno.h> | ||
31 | #include <sys/mman.h> | ||
32 | #include <pwd.h> | ||
33 | #include <dirent.h> | ||
34 | |||
35 | #include "../include/common.h" | ||
36 | #define MAX_BUF 4096 | ||
37 | |||
38 | |||
39 | // main.c | ||
40 | extern int arg_debug; | ||
41 | |||
42 | // util.c | ||
43 | int which(const char *program); | ||
44 | int is_link(const char *fname); | ||
45 | |||
46 | // sound.c | ||
47 | void sound(void); | ||
48 | |||
49 | // desktop_files.c | ||
50 | void fix_desktop_files(char *homedir); | ||
51 | |||
diff --git a/src/firecfg/main.c b/src/firecfg/main.c index 5928b9ae5..1cdd39c1f 100644 --- a/src/firecfg/main.c +++ b/src/firecfg/main.c | |||
@@ -18,24 +18,8 @@ | |||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #define _GNU_SOURCE | 21 | #include "firecfg.h" |
22 | #include <stdio.h> | 22 | int arg_debug = 0; |
23 | #include <sys/types.h> | ||
24 | #include <dirent.h> | ||
25 | #include <sys/types.h> | ||
26 | #include <sys/stat.h> | ||
27 | #include <fcntl.h> | ||
28 | #include <unistd.h> | ||
29 | #include <grp.h> | ||
30 | #include <string.h> | ||
31 | #include <errno.h> | ||
32 | #include <sys/mman.h> | ||
33 | #include <pwd.h> | ||
34 | #include <dirent.h> | ||
35 | |||
36 | #include "../include/common.h" | ||
37 | static int arg_debug = 0; | ||
38 | #define MAX_BUF 1024 | ||
39 | 23 | ||
40 | static void usage(void) { | 24 | static void usage(void) { |
41 | printf("firecfg - version %s\n\n", VERSION); | 25 | printf("firecfg - version %s\n\n", VERSION); |
@@ -71,113 +55,6 @@ static void usage(void) { | |||
71 | printf("Homepage: http://firejail.wordpress.com\n\n"); | 55 | printf("Homepage: http://firejail.wordpress.com\n\n"); |
72 | } | 56 | } |
73 | 57 | ||
74 | static void sound(void) { | ||
75 | struct passwd *pw = getpwuid(getuid()); | ||
76 | if (!pw) { | ||
77 | goto errexit; | ||
78 | } | ||
79 | char *home = pw->pw_dir; | ||
80 | if (!home) { | ||
81 | goto errexit; | ||
82 | } | ||
83 | |||
84 | // the input file is /etc/pulse/client.conf | ||
85 | FILE *fpin = fopen("/etc/pulse/client.conf", "r"); | ||
86 | if (!fpin) { | ||
87 | fprintf(stderr, "PulseAudio is not available on this platform, there is nothing to fix...\n"); | ||
88 | return; | ||
89 | } | ||
90 | |||
91 | // the dest is PulseAudio user config file | ||
92 | char *fname; | ||
93 | if (asprintf(&fname, "%s/.config/pulse/client.conf", home) == -1) | ||
94 | errExit("asprintf"); | ||
95 | FILE *fpout = fopen(fname, "w"); | ||
96 | free(fname); | ||
97 | if (!fpout) | ||
98 | goto errexit; | ||
99 | |||
100 | // copy default config | ||
101 | char buf[MAX_BUF]; | ||
102 | while (fgets(buf, MAX_BUF, fpin)) | ||
103 | fputs(buf, fpout); | ||
104 | |||
105 | // disable shm | ||
106 | fprintf(fpout, "\nenable-shm = no\n"); | ||
107 | fclose(fpin); | ||
108 | fclose(fpout); | ||
109 | printf("PulseAudio configured, please logout and login back again\n"); | ||
110 | return; | ||
111 | |||
112 | errexit: | ||
113 | fprintf(stderr, "Error: cannot configure sound file\n"); | ||
114 | exit(1); | ||
115 | } | ||
116 | |||
117 | // return 1 if the program is found | ||
118 | static int find(const char *program, const char *directory) { | ||
119 | int retval = 0; | ||
120 | |||
121 | char *fname; | ||
122 | if (asprintf(&fname, "/%s/%s", directory, program) == -1) | ||
123 | errExit("asprintf"); | ||
124 | |||
125 | struct stat s; | ||
126 | if (stat(fname, &s) == 0) { | ||
127 | if (arg_debug) | ||
128 | printf("found %s in directory %s\n", program, directory); | ||
129 | retval = 1; | ||
130 | } | ||
131 | |||
132 | free(fname); | ||
133 | return retval; | ||
134 | } | ||
135 | |||
136 | |||
137 | // return 1 if program is installed on the system | ||
138 | static int which(const char *program) { | ||
139 | // check some well-known paths | ||
140 | if (find(program, "/bin") || find(program, "/usr/bin") || | ||
141 | find(program, "/sbin") || find(program, "/usr/sbin") || | ||
142 | find(program, "/usr/games")) | ||
143 | return 1; | ||
144 | |||
145 | // check environment | ||
146 | char *path1 = getenv("PATH"); | ||
147 | if (path1) { | ||
148 | char *path2 = strdup(path1); | ||
149 | if (!path2) | ||
150 | errExit("strdup"); | ||
151 | |||
152 | // use path2 to count the entries | ||
153 | char *ptr = strtok(path2, ":"); | ||
154 | while (ptr) { | ||
155 | if (find(program, ptr)) { | ||
156 | free(path2); | ||
157 | return 1; | ||
158 | } | ||
159 | ptr = strtok(NULL, ":"); | ||
160 | } | ||
161 | free(path2); | ||
162 | } | ||
163 | |||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | // return 1 if the file is a link | ||
168 | static int is_link(const char *fname) { | ||
169 | assert(fname); | ||
170 | if (*fname == '\0') | ||
171 | return 0; | ||
172 | |||
173 | struct stat s; | ||
174 | if (lstat(fname, &s) == 0) { | ||
175 | if (S_ISLNK(s.st_mode)) | ||
176 | return 1; | ||
177 | } | ||
178 | |||
179 | return 0; | ||
180 | } | ||
181 | 58 | ||
182 | static void list(void) { | 59 | static void list(void) { |
183 | DIR *dir = opendir("/usr/local/bin"); | 60 | DIR *dir = opendir("/usr/local/bin"); |
@@ -388,221 +265,6 @@ static void set_links_homedir(const char *homedir) { | |||
388 | free(firejail_exec); | 265 | free(firejail_exec); |
389 | } | 266 | } |
390 | 267 | ||
391 | // look for a profile file in /etc/firejail diectory and in homedir/.config/firejail directory | ||
392 | static int have_profile(const char *filename, const char *homedir) { | ||
393 | assert(filename); | ||
394 | assert(homedir); | ||
395 | |||
396 | if (arg_debug) | ||
397 | printf("checking profile for %s\n", filename); | ||
398 | |||
399 | // remove .desktop extension | ||
400 | char *f1 = strdup(filename); | ||
401 | if (!f1) | ||
402 | errExit("strdup"); | ||
403 | f1[strlen(filename) - 8] = '\0'; | ||
404 | |||
405 | // build profile name | ||
406 | char *profname1; | ||
407 | char *profname2; | ||
408 | if (asprintf(&profname1, "%s/%s.profile", SYSCONFDIR, f1) == -1) | ||
409 | errExit("asprintf"); | ||
410 | if (asprintf(&profname2, "%s/.config/firejail/%s.profile", homedir, f1) == -1) | ||
411 | errExit("asprintf"); | ||
412 | |||
413 | int rv = 0; | ||
414 | if (access(profname1, R_OK) == 0) { | ||
415 | if (arg_debug) | ||
416 | printf("found %s\n", profname1); | ||
417 | rv = 1; | ||
418 | } | ||
419 | else if (access(profname2, R_OK) == 0) { | ||
420 | if (arg_debug) | ||
421 | printf("found %s\n", profname2); | ||
422 | rv = 1; | ||
423 | } | ||
424 | |||
425 | free(f1); | ||
426 | free(profname1); | ||
427 | free(profname2); | ||
428 | return rv; | ||
429 | } | ||
430 | |||
431 | static void fix_desktop_files(char *homedir) { | ||
432 | assert(homedir); | ||
433 | struct stat sb; | ||
434 | |||
435 | // check user | ||
436 | if (getuid() == 0) { | ||
437 | fprintf(stderr, "Error: this option is not supported for root user; please run as a regular user.\n"); | ||
438 | exit(1); | ||
439 | } | ||
440 | |||
441 | // destination | ||
442 | // create ~/.local/share/applications directory if necessary | ||
443 | char *user_apps_dir; | ||
444 | if (asprintf(&user_apps_dir, "%s/.local/share/applications", homedir) == -1) | ||
445 | errExit("asprintf"); | ||
446 | if (stat(user_apps_dir, &sb) == -1) { | ||
447 | int rv = mkdir(user_apps_dir, 0700); | ||
448 | if (rv) { | ||
449 | fprintf(stderr, "Error: cannot create ~/.local/application directory\n"); | ||
450 | perror("mkdir"); | ||
451 | exit(1); | ||
452 | } | ||
453 | rv = chmod(user_apps_dir, 0700); | ||
454 | (void) rv; | ||
455 | } | ||
456 | |||
457 | // source | ||
458 | DIR *dir = opendir("/usr/share/applications"); | ||
459 | if (!dir) { | ||
460 | perror("Error: cannot open /usr/share/applications directory"); | ||
461 | exit(1); | ||
462 | } | ||
463 | if (chdir("/usr/share/applications")) { | ||
464 | perror("Error: cannot chdir to /usr/share/applications"); | ||
465 | exit(1); | ||
466 | } | ||
467 | |||
468 | printf("\nFixing desktop files in %s\n", user_apps_dir); | ||
469 | // copy | ||
470 | struct dirent *entry; | ||
471 | while ((entry = readdir(dir)) != NULL) { | ||
472 | if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) | ||
473 | continue; | ||
474 | |||
475 | // skip if not regular file or link | ||
476 | // d_type is not available on some file systems | ||
477 | if (entry->d_type != DT_REG && entry->d_type != DT_LNK && entry->d_type != DT_UNKNOWN) | ||
478 | continue; | ||
479 | |||
480 | // skip if not .desktop file | ||
481 | if (strstr(entry->d_name,".desktop") != (entry->d_name+strlen(entry->d_name)-8)) | ||
482 | continue; | ||
483 | |||
484 | char *filename = entry->d_name; | ||
485 | |||
486 | // skip links | ||
487 | if (is_link(filename)) | ||
488 | continue; | ||
489 | if (stat(filename, &sb) == -1) | ||
490 | errExit("stat"); | ||
491 | |||
492 | // no profile in /etc/firejail, no desktop file fixing | ||
493 | if (!have_profile(filename, homedir)) | ||
494 | continue; | ||
495 | |||
496 | /* coverity[toctou] */ | ||
497 | int fd = open(filename, O_RDONLY); | ||
498 | if (fd == -1) | ||
499 | errExit("open"); | ||
500 | |||
501 | char *buf = mmap(NULL, sb.st_size + 1, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); | ||
502 | if (buf == MAP_FAILED) | ||
503 | errExit("mmap"); | ||
504 | |||
505 | close(fd); | ||
506 | |||
507 | // check format | ||
508 | if (strstr(buf, "[Desktop Entry]\n") == NULL) { | ||
509 | if (arg_debug) | ||
510 | printf(" %s - SKIPPED: wrong format?\n", filename); | ||
511 | munmap(buf, sb.st_size + 1); | ||
512 | continue; | ||
513 | } | ||
514 | |||
515 | // get executable name | ||
516 | char *ptr1 = strstr(buf,"\nExec="); | ||
517 | if (!ptr1 || strlen(ptr1) < 7) { | ||
518 | if (arg_debug) | ||
519 | printf(" %s - SKIPPED: wrong format?\n", filename); | ||
520 | munmap(buf, sb.st_size + 1); | ||
521 | continue; | ||
522 | } | ||
523 | |||
524 | char *execname = ptr1 + 6; | ||
525 | // https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s06.html | ||
526 | // The executable program can either be specified with its full path | ||
527 | // or with the name of the executable only | ||
528 | if (execname[0] != '/') { | ||
529 | if (arg_debug) | ||
530 | printf(" %s - already OK\n", filename); | ||
531 | continue; | ||
532 | } | ||
533 | // executable name can be quoted, this is rare and currently unsupported, TODO | ||
534 | if (execname[0] == '"') { | ||
535 | if (arg_debug) | ||
536 | printf(" %s - skipped: path quoting unsupported\n", filename); | ||
537 | continue; | ||
538 | } | ||
539 | |||
540 | // put '\0' at end of filename | ||
541 | char *tail = NULL; | ||
542 | char endchar = ' '; | ||
543 | if (execname[0] == '/') { | ||
544 | char *ptr2 = index(execname, ' '); | ||
545 | char *ptr3 = index(execname, '\n'); | ||
546 | if (ptr2 && (!ptr3 || (ptr2 < ptr3))) { | ||
547 | endchar = ptr2[0]; | ||
548 | ptr2[0] = '\0'; | ||
549 | tail = ptr2 + 1; | ||
550 | } else if (ptr3 && (!ptr2 || (ptr3 < ptr2))) { | ||
551 | endchar = ptr3[0]; | ||
552 | ptr3[0] = '\0'; | ||
553 | tail = ptr3 + 1; | ||
554 | } | ||
555 | ptr1[5] = '\0'; | ||
556 | } | ||
557 | |||
558 | char *bname = basename(execname); | ||
559 | assert(bname); | ||
560 | |||
561 | // check if basename in PATH | ||
562 | if (!which(bname)) { | ||
563 | printf(" %s - skipped, %s not in PATH\n", filename, bname); | ||
564 | continue; | ||
565 | } | ||
566 | |||
567 | char *outname; | ||
568 | if (asprintf(&outname ,"%s/%s", user_apps_dir, filename) == -1) | ||
569 | errExit("asprintf"); | ||
570 | |||
571 | int fd1 = open(outname, O_CREAT | O_WRONLY | O_EXCL, S_IRUSR | S_IWUSR); | ||
572 | free(outname); | ||
573 | |||
574 | if (fd1 == -1) { | ||
575 | printf(" %s skipped: %s\n", filename, strerror(errno)); | ||
576 | munmap(buf, sb.st_size + 1); | ||
577 | continue; | ||
578 | } | ||
579 | |||
580 | FILE *outfile = fdopen(fd1, "w"); | ||
581 | if (!outfile) { | ||
582 | printf(" %s skipped: %s\n", filename, strerror(errno)); | ||
583 | munmap(buf, sb.st_size + 1); | ||
584 | close(fd1); | ||
585 | continue; | ||
586 | } | ||
587 | |||
588 | if (fprintf(outfile,\ | ||
589 | "# Converted by firecfg --fix from /usr/share/applications/%s\n\n%s=%s%c%s",\ | ||
590 | filename, buf, bname, endchar, tail) < 0) { | ||
591 | fprintf(stderr, "Unable to write %s/%s: %s\n", user_apps_dir, filename, strerror(errno)); | ||
592 | munmap(buf, sb.st_size + 1); | ||
593 | fclose(outfile); | ||
594 | continue; | ||
595 | } | ||
596 | |||
597 | fclose(outfile); | ||
598 | munmap(buf, sb.st_size + 1); | ||
599 | |||
600 | printf(" %s created\n", filename); | ||
601 | } | ||
602 | |||
603 | closedir(dir); | ||
604 | free(user_apps_dir); | ||
605 | } | ||
606 | 268 | ||
607 | int main(int argc, char **argv) { | 269 | int main(int argc, char **argv) { |
608 | int i; | 270 | int i; |
diff --git a/src/firecfg/sound.c b/src/firecfg/sound.c new file mode 100644 index 000000000..9dfb305cd --- /dev/null +++ b/src/firecfg/sound.c | |||
@@ -0,0 +1,65 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2017 Firejail Authors | ||
3 | * | ||
4 | * This file is part of firejail project | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #include "firecfg.h" | ||
22 | |||
23 | void sound(void) { | ||
24 | struct passwd *pw = getpwuid(getuid()); | ||
25 | if (!pw) { | ||
26 | goto errexit; | ||
27 | } | ||
28 | char *home = pw->pw_dir; | ||
29 | if (!home) { | ||
30 | goto errexit; | ||
31 | } | ||
32 | |||
33 | // the input file is /etc/pulse/client.conf | ||
34 | FILE *fpin = fopen("/etc/pulse/client.conf", "r"); | ||
35 | if (!fpin) { | ||
36 | fprintf(stderr, "PulseAudio is not available on this platform, there is nothing to fix...\n"); | ||
37 | return; | ||
38 | } | ||
39 | |||
40 | // the dest is PulseAudio user config file | ||
41 | char *fname; | ||
42 | if (asprintf(&fname, "%s/.config/pulse/client.conf", home) == -1) | ||
43 | errExit("asprintf"); | ||
44 | FILE *fpout = fopen(fname, "w"); | ||
45 | free(fname); | ||
46 | if (!fpout) | ||
47 | goto errexit; | ||
48 | |||
49 | // copy default config | ||
50 | char buf[MAX_BUF]; | ||
51 | while (fgets(buf, MAX_BUF, fpin)) | ||
52 | fputs(buf, fpout); | ||
53 | |||
54 | // disable shm | ||
55 | fprintf(fpout, "\nenable-shm = no\n"); | ||
56 | fclose(fpin); | ||
57 | fclose(fpout); | ||
58 | printf("PulseAudio configured, please logout and login back again\n"); | ||
59 | return; | ||
60 | |||
61 | errexit: | ||
62 | fprintf(stderr, "Error: cannot configure sound file\n"); | ||
63 | exit(1); | ||
64 | } | ||
65 | |||
diff --git a/src/firecfg/util.c b/src/firecfg/util.c new file mode 100644 index 000000000..4520e75e8 --- /dev/null +++ b/src/firecfg/util.c | |||
@@ -0,0 +1,86 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2017 Firejail Authors | ||
3 | * | ||
4 | * This file is part of firejail project | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #include "firecfg.h" | ||
22 | |||
23 | // return 1 if the program is found | ||
24 | static int find(const char *program, const char *directory) { | ||
25 | int retval = 0; | ||
26 | |||
27 | char *fname; | ||
28 | if (asprintf(&fname, "/%s/%s", directory, program) == -1) | ||
29 | errExit("asprintf"); | ||
30 | |||
31 | struct stat s; | ||
32 | if (stat(fname, &s) == 0) { | ||
33 | if (arg_debug) | ||
34 | printf("found %s in directory %s\n", program, directory); | ||
35 | retval = 1; | ||
36 | } | ||
37 | |||
38 | free(fname); | ||
39 | return retval; | ||
40 | } | ||
41 | |||
42 | |||
43 | // return 1 if program is installed on the system | ||
44 | int which(const char *program) { | ||
45 | // check some well-known paths | ||
46 | if (find(program, "/bin") || find(program, "/usr/bin") || | ||
47 | find(program, "/sbin") || find(program, "/usr/sbin") || | ||
48 | find(program, "/usr/games")) | ||
49 | return 1; | ||
50 | |||
51 | // check environment | ||
52 | char *path1 = getenv("PATH"); | ||
53 | if (path1) { | ||
54 | char *path2 = strdup(path1); | ||
55 | if (!path2) | ||
56 | errExit("strdup"); | ||
57 | |||
58 | // use path2 to count the entries | ||
59 | char *ptr = strtok(path2, ":"); | ||
60 | while (ptr) { | ||
61 | if (find(program, ptr)) { | ||
62 | free(path2); | ||
63 | return 1; | ||
64 | } | ||
65 | ptr = strtok(NULL, ":"); | ||
66 | } | ||
67 | free(path2); | ||
68 | } | ||
69 | |||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | // return 1 if the file is a link | ||
74 | int is_link(const char *fname) { | ||
75 | assert(fname); | ||
76 | if (*fname == '\0') | ||
77 | return 0; | ||
78 | |||
79 | struct stat s; | ||
80 | if (lstat(fname, &s) == 0) { | ||
81 | if (S_ISLNK(s.st_mode)) | ||
82 | return 1; | ||
83 | } | ||
84 | |||
85 | return 0; | ||
86 | } | ||