aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--RELNOTES1
-rw-r--r--src/firecfg/desktop_files.c265
-rw-r--r--src/firecfg/firecfg.h51
-rw-r--r--src/firecfg/main.c342
-rw-r--r--src/firecfg/sound.c65
-rw-r--r--src/firecfg/util.c86
6 files changed, 470 insertions, 340 deletions
diff --git a/RELNOTES b/RELNOTES
index 5bc07f000..4c272ccee 100644
--- a/RELNOTES
+++ b/RELNOTES
@@ -1,6 +1,7 @@
1firejail (0.9.51) baseline; urgency=low 1firejail (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
24static 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
71void 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
40extern int arg_debug;
41
42// util.c
43int which(const char *program);
44int is_link(const char *fname);
45
46// sound.c
47void sound(void);
48
49// desktop_files.c
50void 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> 22int 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"
37static int arg_debug = 0;
38#define MAX_BUF 1024
39 23
40static void usage(void) { 24static 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
74static 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
112errexit:
113 fprintf(stderr, "Error: cannot configure sound file\n");
114 exit(1);
115}
116
117// return 1 if the program is found
118static 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
138static 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
168static 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
182static void list(void) { 59static 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
392static 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
431static 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
607int main(int argc, char **argv) { 269int 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
23void 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
61errexit:
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
24static 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
44int 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
74int 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}