Skip to content

Commit

Permalink
Merge pull request #5876 from kmk3/firecfg-add-confdir-ignore
Browse files Browse the repository at this point in the history
feature: firecfg: add firecfg.d & add ignore command
  • Loading branch information
netblue30 authored Dec 4, 2023
2 parents 8f55f6c + ef6cfb8 commit 2033e98
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 53 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ endif
install -m 0644 -t $(DESTDIR)$(docdir) COPYING README RELNOTES etc/templates/*
# profiles and settings
install -m 0755 -d $(DESTDIR)$(sysconfdir)/firejail
install -m 0755 -d $(DESTDIR)$(sysconfdir)/firejail/firecfg.d
install -m 0644 -t $(DESTDIR)$(sysconfdir)/firejail src/firecfg/firecfg.config
install -m 0644 -t $(DESTDIR)$(sysconfdir)/firejail etc/profile-a-l/*.profile etc/profile-m-z/*.profile etc/inc/*.inc etc/net/*.net etc/firejail.config
sh -c "if [ ! -f $(DESTDIR)/$(sysconfdir)/firejail/login.users ]; then install -c -m 0644 etc/login.users $(DESTDIR)/$(sysconfdir)/firejail/.; fi;"
Expand Down
10 changes: 10 additions & 0 deletions src/firecfg/firecfg.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@
#include "../include/common.h"
#define MAX_BUF 4096

// config files
#define FIRECFG_CFGFILE SYSCONFDIR "/firecfg.config"
#define FIRECFG_CONF_GLOB SYSCONFDIR "/firecfg.d/*.conf"

// programs
#define FIREJAIL_EXEC PREFIX "/bin/firejail"
#define FIREJAIL_WELCOME_SH LIBDIR "/firejail/firejail-welcome.sh"
#define FZENITY_EXEC LIBDIR "/firejail/fzenity"
#define ZENITY_EXEC "/usr/bin/zenity"
#define SUDO_EXEC "sudo"

// main.c
extern int arg_debug;
Expand Down
145 changes: 96 additions & 49 deletions src/firecfg/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

#include "firecfg.h"
#include "../include/firejail_user.h"
#include <glob.h>

int arg_debug = 0;
char *arg_bindir = "/usr/local/bin";
int arg_guide = 0;
Expand Down Expand Up @@ -76,10 +78,6 @@ static void list(void) {
exit(1);
}

char *firejail_exec;
if (asprintf(&firejail_exec, "%s/bin/firejail", PREFIX) == -1)
errExit("asprintf");

struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
Expand All @@ -92,7 +90,7 @@ static void list(void) {
if (is_link(fullname)) {
char* fname = realpath(fullname, NULL);
if (fname) {
if (strcmp(fname, firejail_exec) == 0)
if (strcmp(fname, FIREJAIL_EXEC) == 0)
printf("%s\n", fullname);
free(fname);
}
Expand All @@ -101,7 +99,6 @@ static void list(void) {
}

closedir(dir);
free(firejail_exec);
}

static void clean(void) {
Expand All @@ -114,10 +111,6 @@ static void clean(void) {
exit(1);
}

char *firejail_exec;
if (asprintf(&firejail_exec, "%s/bin/firejail", PREFIX) == -1)
errExit("asprintf");

struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
Expand All @@ -130,7 +123,7 @@ static void clean(void) {
if (is_link(fullname)) {
char* fname = realpath(fullname, NULL);
if (fname) {
if (strcmp(fname, firejail_exec) == 0) {
if (strcmp(fname, FIREJAIL_EXEC) == 0) {
char *ptr = strrchr(fullname, '/');
assert(ptr);
ptr++;
Expand All @@ -147,10 +140,43 @@ static void clean(void) {
}

closedir(dir);
free(firejail_exec);
printf("\n");
}

#define ignorelist_maxlen 2048
static const char *ignorelist[ignorelist_maxlen];
static int ignorelist_len = 0;

static int append_ignorelist(const char *const str) {
assert(str);
if (ignorelist_len >= ignorelist_maxlen) {
fprintf(stderr, "Warning: Ignore list is full (%d/%d), skipping %s\n",
ignorelist_len, ignorelist_maxlen, str);
return 0;
}

printf(" ignoring '%s'\n", str);
const char *const dup = strdup(str);
if (!dup)
errExit("strdup");

ignorelist[ignorelist_len] = dup;
ignorelist_len++;

return 1;
}

static int in_ignorelist(const char *const str) {
assert(str);
int i;
for (i = 0; i < ignorelist_len; i++) {
if (strcmp(str, ignorelist[i]) == 0)
return 1;
}

return 0;
}

static void set_file(const char *name, const char *firejail_exec) {
if (which(name) == 0)
return;
Expand All @@ -165,35 +191,26 @@ static void set_file(const char *name, const char *firejail_exec) {
if (rv) {
fprintf(stderr, "Error: cannot create %s symbolic link\n", fname);
perror("symlink");
}
else
} else {
printf(" %s created\n", name);
}
else {
fprintf(stderr, "Warning: cannot create %s - already exists! Skipping...\n", fname);
}
} else {
fprintf(stderr, "Warning: cannot create %s - already exists! Skipping...\n", fname);
}

free(fname);
}

// parse /etc/firejail/firecfg.config file
static void set_links_firecfg(void) {
char *cfgfile;
if (asprintf(&cfgfile, "%s/firecfg.config", SYSCONFDIR) == -1)
errExit("asprintf");

char *firejail_exec;
if (asprintf(&firejail_exec, "%s/bin/firejail", PREFIX) == -1)
errExit("asprintf");
// parse a single config file
static void set_links_firecfg(const char *cfgfile) {
printf("Configuring symlinks in %s based on %s\n", arg_bindir, cfgfile);

// parse /etc/firejail/firecfg.config file
FILE *fp = fopen(cfgfile, "r");
if (!fp) {
perror("fopen");
fprintf(stderr, "Error: cannot open %s\n", cfgfile);
exit(1);
}
printf("Configuring symlinks in %s based on firecfg.config\n", arg_bindir);

char buf[MAX_BUF];
int lineno = 0;
Expand Down Expand Up @@ -223,13 +240,43 @@ static void set_links_firecfg(void) {
if (*start == '\0')
continue;

// handle ignore command
if (*start == '!') {
append_ignorelist(start + 1);
continue;
}

// set link
set_file(start, firejail_exec);
if (!in_ignorelist(start))
set_file(start, FIREJAIL_EXEC);
else
printf(" %s ignored\n", start);
}

fclose(fp);
free(cfgfile);
free(firejail_exec);
printf("\n");
}

// parse all config files matching pattern
static void set_links_firecfg_glob(const char *pattern) {
printf("Looking for config files in %s\n", pattern);

glob_t globbuf;
int globerr = glob(pattern, 0, NULL, &globbuf);
if (globerr == GLOB_NOMATCH) {
fprintf(stderr, "No matches for glob pattern %s\n", pattern);
goto out;
} else if (globerr != 0) {
fprintf(stderr, "Warning: Failed to match glob pattern %s: %s\n",
pattern, strerror(errno));
goto out;
}

size_t i;
for (i = 0; i < globbuf.gl_pathc; i++)
set_links_firecfg(globbuf.gl_pathv[i]);
out:
globfree(&globbuf);
}

// parse ~/.config/firejail/ directory
Expand All @@ -246,10 +293,6 @@ static void set_links_homedir(const char *homedir) {
return;
}

char *firejail_exec;
if (asprintf(&firejail_exec, "%s/bin/firejail", PREFIX) == -1)
errExit("asprintf");

// parse ~/.config/firejail/ directory
printf("\nConfiguring symlinks in %s based on local firejail config directory\n", arg_bindir);

Expand All @@ -260,6 +303,7 @@ static void set_links_homedir(const char *homedir) {
free(dirname);
return;
}
free(dirname);

struct dirent *entry;
while ((entry = readdir(dir))) {
Expand All @@ -280,12 +324,10 @@ static void set_links_homedir(const char *homedir) {
}

*ptr = '\0';
set_file(exec, firejail_exec);
set_file(exec, FIREJAIL_EXEC);
free(exec);
}
closedir(dir);

free(firejail_exec);
}

static const char *get_sudo_user(void) {
Expand Down Expand Up @@ -449,18 +491,20 @@ int main(int argc, char **argv) {
}

if (arg_guide) {
const char *zenity_exec;
if (arg_debug)
zenity_exec = FZENITY_EXEC;
else
zenity_exec = ZENITY_EXEC;

char *cmd;
if (arg_debug) {
if (asprintf(&cmd, "sudo %s/firejail/firejail-welcome.sh /usr/lib/firejail/fzenity %s %s", LIBDIR, SYSCONFDIR, user) == -1)
if (asprintf(&cmd, "%s %s %s %s %s",
SUDO_EXEC, FIREJAIL_WELCOME_SH, zenity_exec, SYSCONFDIR, user) == -1)
errExit("asprintf");
}
else {
if (asprintf(&cmd, "sudo %s/firejail/firejail-welcome.sh /usr/bin/zenity %s %s", LIBDIR, SYSCONFDIR, user) == -1)
errExit("asprintf");
}

int status = system(cmd);
if (status == -1) {
fprintf(stderr, "Error: cannot run firejail-welcome.sh\n");
fprintf(stderr, "Error: cannot run %s\n", FIREJAIL_WELCOME_SH);
exit(1);
}
free(cmd);
Expand All @@ -474,12 +518,15 @@ else {
// clear all symlinks
clean();

// set new symlinks based on /etc/firejail/firecfg.config
set_links_firecfg();
// set new symlinks based on .conf files
set_links_firecfg_glob(FIRECFG_CONF_GLOB);

// set new symlinks based on firecfg.config
set_links_firecfg(FIRECFG_CFGFILE);

if (getuid() == 0) {
// add user to firejail access database - only for root
printf("\nAdding user %s to Firejail access database in %s/firejail.users\n", user, SYSCONFDIR);
printf("Adding user %s to Firejail access database in %s/firejail.users\n", user, SYSCONFDIR);
// temporarily set the umask, access database must be world-readable
mode_t orig_umask = umask(022);
firejail_user_add(user);
Expand Down
57 changes: 53 additions & 4 deletions src/man/firecfg.1.in
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,13 @@ Note: The examples use \fBsudo\fR, but \fBdoas\fR is also supported.
To set it up, run "sudo firecfg" after installing Firejail software.
The same command should also be run after
installing new programs. If the program is supported by Firejail, the symbolic link in /usr/local/bin
will be created. For a full list of programs supported by default run "cat /etc/firejail/firecfg.config".

For user-driven manual integration, see \fBDESKTOP INTEGRATION\fR section in \fBman 1 firejail\fR.
will be created.
.PP
To configure the list of programs used by firecfg when creating symlinks, see
\fBFILES\fR and \fBSYNTAX\fR.
.PP
For user-driven manual integration, see \fBDESKTOP INTEGRATION\fR section in
\fBman 1 firejail\fR.
.SH DEFAULT ACTIONS
The following actions are implemented by default by running sudo firecfg:

Expand Down Expand Up @@ -135,8 +139,53 @@ $ sudo firecfg --clean
/usr/local/bin/vlc removed
.br
[...]
.SH FILES
.PP
Configuration files are searched for and parsed in the following paths:
.PP
.RS
1. /etc/firejail/firecfg.d/*.conf (in alphabetical order)
.br
2. /etc/firejail/firecfg.config
.RE
.PP
The programs that are supported by default are listed in
/etc/firejail/firecfg.config.
It is recommended to leave it as is and put all customizations inside
/etc/firejail/firecfg.d/.
.PP
Profile files are also searched in the user configuration directory:
.PP
.RS
3. ~/.config/firejail/*.profile
.RE
.PP
For every \fBPROGRAM.profile\fR file found, firecfg attempts to create a
symlink for "PROGRAM", as if "PROGRAM" was listed in a configuration file.
.SH SYNTAX
Configuration file syntax:
.PP
A line that starts with \fB#\fR is considered a comment.
.br
A line that starts with \fB!PROGRAM\fR means to ignore "PROGRAM" when creating
symlinks.
.br
A line that starts with anything else is considered to be the name of an
executable and firecfg will attempt to create a symlink for it.
.PP
For example, to prevent firecfg from creating symlinks for "firefox" and
"patch" while attempting to create a symlink for "myprog", the following lines
could be added to /etc/firejail/firecfg.d/10-my.conf:
.PP
.RS
!firefox
.br
!patch
.br


.br
myprog
.RE
.SH LICENSE
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.
.PP
Expand Down

0 comments on commit 2033e98

Please sign in to comment.