aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--RELNOTES4
-rw-r--r--etc/Viber.profile2
-rw-r--r--etc/apktool.profile2
-rw-r--r--etc/arm.profile2
-rw-r--r--etc/atril.profile7
-rw-r--r--etc/bless.profile2
-rw-r--r--etc/catfish.profile2
-rw-r--r--etc/deluge.profile2
-rw-r--r--etc/dex2jar.profile2
-rw-r--r--etc/disable-common.inc5
-rw-r--r--etc/display.profile2
-rw-r--r--etc/filezilla.profile2
-rw-r--r--etc/gajim.profile2
-rw-r--r--etc/gnome-music.profile2
-rw-r--r--etc/google-earth.profile2
-rw-r--r--etc/hexchat.profile6
-rw-r--r--etc/jd-gui.profile2
-rw-r--r--etc/macrofusion.profile2
-rw-r--r--etc/meld.profile2
-rw-r--r--etc/mpv.profile2
-rw-r--r--etc/multimc5.profile2
-rw-r--r--etc/pdfsam.profile2
-rw-r--r--etc/pithos.profile2
-rw-r--r--etc/sdat2img.profile2
-rw-r--r--etc/silentarmy.profile2
-rw-r--r--etc/spotify.profile2
-rw-r--r--etc/start-tor-browser.profile2
-rw-r--r--etc/surf.profile2
-rw-r--r--etc/tar.profile2
-rw-r--r--etc/torbrowser-launcher.profile2
-rw-r--r--etc/waterfox.profile2
-rw-r--r--etc/xchat.profile2
-rw-r--r--etc/xonotic.profile2
-rw-r--r--etc/xpra.profile2
-rw-r--r--src/fcopy/main.c16
-rw-r--r--src/firejail/appimage.c2
-rw-r--r--src/firejail/cgroup.c2
-rw-r--r--src/firejail/firejail.h2
-rw-r--r--src/firejail/fs_bin.c55
-rw-r--r--src/firejail/fs_etc.c2
-rw-r--r--src/firejail/fs_home.c4
-rw-r--r--src/firejail/fs_hostname.c2
-rw-r--r--src/firejail/fs_mkdir.c4
-rw-r--r--src/firejail/main.c16
-rw-r--r--src/firejail/netfilter.c2
-rw-r--r--src/firejail/netns.c2
-rw-r--r--src/firejail/output.c2
-rw-r--r--src/firejail/profile.c10
-rw-r--r--src/firejail/util.c19
49 files changed, 151 insertions, 71 deletions
diff --git a/RELNOTES b/RELNOTES
index aba2e7dee..026c67f9b 100644
--- a/RELNOTES
+++ b/RELNOTES
@@ -3,11 +3,11 @@ firejail (0.9.51) baseline; urgency=low
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 * enhancement: disable DBus activation in firecfg
5 * enhancement; enumerate root directories in apparmor profile 5 * enhancement; enumerate root directories in apparmor profile
6 * feature: systemd-resolvd integration 6 * feature: systemd-resolved integration
7 * feature: whitelisting /var directory in most profiles 7 * feature: whitelisting /var directory in most profiles
8 * feature: GTK2, GTK3 and Qt4 private-lib support 8 * feature: GTK2, GTK3 and Qt4 private-lib support
9 * feature: test deployment of private-lib for the following 9 * feature: test deployment of private-lib for the following
10 applications: evince, galculator, gnome-calculator, hexchat, 10 applications: evince, galculator, gnome-calculator,
11 leafpad, mousepad, transmission-gtk, xcalc, xmr-stak-cpu, 11 leafpad, mousepad, transmission-gtk, xcalc, xmr-stak-cpu,
12 atril, mate-color-select 12 atril, mate-color-select
13 * feature: --writable-run-user 13 * feature: --writable-run-user
diff --git a/etc/Viber.profile b/etc/Viber.profile
index 03e5f1086..f5843bfd4 100644
--- a/etc/Viber.profile
+++ b/etc/Viber.profile
@@ -30,7 +30,7 @@ seccomp
30shell none 30shell none
31 31
32disable-mnt 32disable-mnt
33private-bin sh,bash,dash,dig,awk,Viber 33private-bin sh,bash,dig,awk,Viber
34private-etc hosts,fonts,mailcap,resolv.conf,X11,pulse,alternatives,localtime,nsswitch.conf,ssl,proxychains.conf 34private-etc hosts,fonts,mailcap,resolv.conf,X11,pulse,alternatives,localtime,nsswitch.conf,ssl,proxychains.conf
35private-tmp 35private-tmp
36 36
diff --git a/etc/apktool.profile b/etc/apktool.profile
index 650c20de7..13c8f3311 100644
--- a/etc/apktool.profile
+++ b/etc/apktool.profile
@@ -25,7 +25,7 @@ protocol unix
25seccomp 25seccomp
26shell none 26shell none
27 27
28private-bin apktool,bash,dash,java,dirname,basename,expr,sh 28private-bin apktool,bash,java,dirname,basename,expr,sh
29private-dev 29private-dev
30 30
31noexec ${HOME} 31noexec ${HOME}
diff --git a/etc/arm.profile b/etc/arm.profile
index afb6d465a..8b41d787e 100644
--- a/etc/arm.profile
+++ b/etc/arm.profile
@@ -33,7 +33,7 @@ shell none
33tracelog 33tracelog
34 34
35disable-mnt 35disable-mnt
36# private-bin arm,tor,sh,bash,dash,python2,python2.7,ps,lsof,ldconfig 36private-bin arm,tor,sh,bash,python*,ps,lsof,ldconfig
37private-dev 37private-dev
38private-etc tor,passwd 38private-etc tor,passwd
39private-tmp 39private-tmp
diff --git a/etc/atril.profile b/etc/atril.profile
index 4d7ac5244..8c5bdc6fb 100644
--- a/etc/atril.profile
+++ b/etc/atril.profile
@@ -32,10 +32,13 @@ tracelog
32private-bin atril, atril-previewer, atril-thumbnailer 32private-bin atril, atril-previewer, atril-thumbnailer
33private-dev 33private-dev
34private-etc fonts,ld.so.cache 34private-etc fonts,ld.so.cache
35private-lib 35# atril uses webkit gtk to display epub files
36# waiting for globbing support in private-lib; for now hardcoding it to webkit2gtk-4.0
37private-lib webkit2gtk-4.0
36# atril needs access to /tmp/mozilla* to work in firefox 38# atril needs access to /tmp/mozilla* to work in firefox
37# private-tmp 39# private-tmp
38 40
39memory-deny-write-execute 41# webkit gtk killed by memory-deny-write-execute
42#memory-deny-write-execute
40noexec ${HOME} 43noexec ${HOME}
41noexec /tmp 44noexec /tmp
diff --git a/etc/bless.profile b/etc/bless.profile
index 27557d9af..e4d2f0730 100644
--- a/etc/bless.profile
+++ b/etc/bless.profile
@@ -26,7 +26,7 @@ protocol unix
26seccomp 26seccomp
27shell none 27shell none
28 28
29# private-bin bless,dash,sh,bash,mono 29# private-bin bless,sh,bash,mono
30private-dev 30private-dev
31private-etc fonts,mono 31private-etc fonts,mono
32private-tmp 32private-tmp
diff --git a/etc/catfish.profile b/etc/catfish.profile
index 5fc585d90..45aa6c35c 100644
--- a/etc/catfish.profile
+++ b/etc/catfish.profile
@@ -33,6 +33,6 @@ tracelog
33 33
34# These options work but are disabled in case 34# These options work but are disabled in case
35# a users wants to search in these directories. 35# a users wants to search in these directories.
36# private-bin bash,catfish,env,locate,ls,mlocate,python,python2,python2.7,python3,python3.5,python3.5m,python3m 36# private-bin bash,catfish,env,locate,ls,mlocate,python*
37# private-dev 37# private-dev
38# private-tmp 38# private-tmp
diff --git a/etc/deluge.profile b/etc/deluge.profile
index c311d2fa7..e18e39b1a 100644
--- a/etc/deluge.profile
+++ b/etc/deluge.profile
@@ -30,6 +30,6 @@ seccomp
30shell none 30shell none
31 31
32# deluge is using python on Debian 32# deluge is using python on Debian
33# private-bin deluge,sh,python,uname 33private-bin deluge,sh,python*,uname
34private-dev 34private-dev
35private-tmp 35private-tmp
diff --git a/etc/dex2jar.profile b/etc/dex2jar.profile
index bdbb10b12..5261bb865 100644
--- a/etc/dex2jar.profile
+++ b/etc/dex2jar.profile
@@ -26,7 +26,7 @@ protocol unix
26seccomp 26seccomp
27shell none 27shell none
28 28
29private-bin dex2jar,dash,java,sh,bash,expr,dirname,ls,uname,grep 29private-bin dex2jar,java,sh,bash,expr,dirname,ls,uname,grep
30private-dev 30private-dev
31 31
32noexec ${HOME} 32noexec ${HOME}
diff --git a/etc/disable-common.inc b/etc/disable-common.inc
index 021e6349e..f01953ed4 100644
--- a/etc/disable-common.inc
+++ b/etc/disable-common.inc
@@ -76,6 +76,11 @@ read-only ${HOME}/.kde4/share/kde4/services
76read-only ${HOME}/.kde4/share/config/kdeglobals 76read-only ${HOME}/.kde4/share/config/kdeglobals
77read-only ${HOME}/.local/share/kservices5 77read-only ${HOME}/.local/share/kservices5
78 78
79# kdeinit sockets
80blacklist /run/user/*/kdeinit*
81blacklist /run/user/*/ksocket-*/kdeinit*
82blacklist /tmp/ksocket-*/kdeinit*
83
79# systemd 84# systemd
80blacklist ${HOME}/.config/systemd 85blacklist ${HOME}/.config/systemd
81blacklist ${HOME}/.local/share/systemd 86blacklist ${HOME}/.local/share/systemd
diff --git a/etc/display.profile b/etc/display.profile
index eca749cec..d44733e30 100644
--- a/etc/display.profile
+++ b/etc/display.profile
@@ -26,7 +26,7 @@ seccomp
26shell none 26shell none
27# x11 xorg - problems on kubuntu 17.04 27# x11 xorg - problems on kubuntu 17.04
28 28
29# private-bin display - requires python 29private-bin display,python*
30private-dev 30private-dev
31# private-etc none - on Debian-based systems display is a symlink in /etc/alternatives 31# private-etc none - on Debian-based systems display is a symlink in /etc/alternatives
32private-tmp 32private-tmp
diff --git a/etc/filezilla.profile b/etc/filezilla.profile
index 866aaabca..544c724bc 100644
--- a/etc/filezilla.profile
+++ b/etc/filezilla.profile
@@ -24,6 +24,6 @@ protocol unix,inet,inet6
24seccomp 24seccomp
25shell none 25shell none
26 26
27private-bin filezilla,uname,sh,bash,dash,python,lsb_release,fzputtygen,fzsftp 27private-bin filezilla,uname,sh,bash,python*,lsb_release,fzputtygen,fzsftp
28private-dev 28private-dev
29private-tmp 29private-tmp
diff --git a/etc/gajim.profile b/etc/gajim.profile
index f1929c015..9171b93af 100644
--- a/etc/gajim.profile
+++ b/etc/gajim.profile
@@ -38,7 +38,7 @@ seccomp
38shell none 38shell none
39 39
40disable-mnt 40disable-mnt
41# private-bin python2.7 gajim 41private-bin python2.7,gajim
42private-dev 42private-dev
43# private-etc fonts 43# private-etc fonts
44# private-tmp 44# private-tmp
diff --git a/etc/gnome-music.profile b/etc/gnome-music.profile
index d1ef20e6b..17288d500 100644
--- a/etc/gnome-music.profile
+++ b/etc/gnome-music.profile
@@ -27,7 +27,7 @@ seccomp
27shell none 27shell none
28tracelog 28tracelog
29 29
30# private-bin gnome-music,python3 30private-bin gnome-music,python*
31private-dev 31private-dev
32# private-etc fonts 32# private-etc fonts
33private-tmp 33private-tmp
diff --git a/etc/google-earth.profile b/etc/google-earth.profile
index b60f5b3a5..2e0d11897 100644
--- a/etc/google-earth.profile
+++ b/etc/google-earth.profile
@@ -41,7 +41,7 @@ protocol unix,inet,inet6
41seccomp 41seccomp
42shell none 42shell none
43 43
44private-bin google-earth,sh,bash,dash,grep,sed,ls,dirname 44private-bin google-earth,sh,bash,grep,sed,ls,dirname
45private-dev 45private-dev
46 46
47noexec ${HOME} 47noexec ${HOME}
diff --git a/etc/hexchat.profile b/etc/hexchat.profile
index 46ddee61d..5945665cc 100644
--- a/etc/hexchat.profile
+++ b/etc/hexchat.profile
@@ -36,11 +36,11 @@ tracelog
36 36
37disable-mnt 37disable-mnt
38# debug note: private-bin requires perl, python, etc on some systems 38# debug note: private-bin requires perl, python, etc on some systems
39private-bin hexchat 39private-bin hexchat,python*
40private-dev 40private-dev
41private-lib 41#private-lib - python problems
42private-tmp 42private-tmp
43 43
44memory-deny-write-execute 44# memory-deny-write-execute - breaks python
45noexec ${HOME} 45noexec ${HOME}
46noexec /tmp 46noexec /tmp
diff --git a/etc/jd-gui.profile b/etc/jd-gui.profile
index 0f59b5721..5cb1e1828 100644
--- a/etc/jd-gui.profile
+++ b/etc/jd-gui.profile
@@ -27,7 +27,7 @@ protocol unix
27seccomp 27seccomp
28shell none 28shell none
29 29
30private-bin jd-gui,dash,sh,bash 30private-bin jd-gui,sh,bash
31private-dev 31private-dev
32private-tmp 32private-tmp
33 33
diff --git a/etc/macrofusion.profile b/etc/macrofusion.profile
index be66cf6ee..506fdd549 100644
--- a/etc/macrofusion.profile
+++ b/etc/macrofusion.profile
@@ -27,7 +27,7 @@ protocol unix
27seccomp 27seccomp
28shell none 28shell none
29 29
30#private-bin python3,macrofusion,env,enfuse,exiftool,align_image_stack 30private-bin python*,macrofusion,env,enfuse,exiftool,align_image_stack
31private-dev 31private-dev
32private-tmp 32private-tmp
33 33
diff --git a/etc/meld.profile b/etc/meld.profile
index f1910d0f4..5043f2496 100644
--- a/etc/meld.profile
+++ b/etc/meld.profile
@@ -26,7 +26,7 @@ protocol unix
26seccomp 26seccomp
27shell none 27shell none
28 28
29# private-bin meld,python2,python2.7 29private-bin meld,python*
30private-dev 30private-dev
31private-tmp 31private-tmp
32 32
diff --git a/etc/mpv.profile b/etc/mpv.profile
index eb8a88a4b..2e632eef2 100644
--- a/etc/mpv.profile
+++ b/etc/mpv.profile
@@ -25,5 +25,5 @@ seccomp
25shell none 25shell none
26tracelog 26tracelog
27 27
28private-bin mpv,youtube-dl,python,python2.7,python3,python3.5,python3.6,env 28private-bin mpv,youtube-dl,python*,env
29private-dev 29private-dev
diff --git a/etc/multimc5.profile b/etc/multimc5.profile
index 3423c2a88..8a70d9d36 100644
--- a/etc/multimc5.profile
+++ b/etc/multimc5.profile
@@ -35,7 +35,7 @@ shell none
35 35
36disable-mnt 36disable-mnt
37# private-bin works, but causes weirdness 37# private-bin works, but causes weirdness
38# private-bin multimc5,dash,bash,mkdir,which,zenity,kdialog,ldd,chmod,valgrind,apt-file,pkgfile,dnf,yum,zypper,pfl,java,grep,sort,awk,readlink,dirname 38# private-bin multimc5,bash,mkdir,which,zenity,kdialog,ldd,chmod,valgrind,apt-file,pkgfile,dnf,yum,zypper,pfl,java,grep,sort,awk,readlink,dirname
39private-dev 39private-dev
40private-tmp 40private-tmp
41 41
diff --git a/etc/pdfsam.profile b/etc/pdfsam.profile
index f1c3377d9..fd52fb9ee 100644
--- a/etc/pdfsam.profile
+++ b/etc/pdfsam.profile
@@ -26,7 +26,7 @@ protocol unix
26seccomp 26seccomp
27shell none 27shell none
28 28
29private-bin pdfsam,dash,sh,bash,java,archlinux-java,grep,awk,dirname,uname,which,sort,find,readlink,expr,ls,java-config 29private-bin pdfsam,sh,bash,java,archlinux-java,grep,awk,dirname,uname,which,sort,find,readlink,expr,ls,java-config
30private-dev 30private-dev
31private-tmp 31private-tmp
32 32
diff --git a/etc/pithos.profile b/etc/pithos.profile
index b81e0b634..f3949d3f1 100644
--- a/etc/pithos.profile
+++ b/etc/pithos.profile
@@ -26,7 +26,7 @@ seccomp
26shell none 26shell none
27 27
28disable-mnt 28disable-mnt
29# private-bin pithos,python,python3,python3.6 29private-bin pithos,env,python*
30private-dev 30private-dev
31private-tmp 31private-tmp
32 32
diff --git a/etc/sdat2img.profile b/etc/sdat2img.profile
index ce4c4d416..62a056a30 100644
--- a/etc/sdat2img.profile
+++ b/etc/sdat2img.profile
@@ -26,7 +26,7 @@ protocol unix
26seccomp 26seccomp
27shell none 27shell none
28 28
29# private-bin sdat2img,env,python,python3,python3.6 29private-bin sdat2img,env,python*
30private-dev 30private-dev
31 31
32noexec ${HOME} 32noexec ${HOME}
diff --git a/etc/silentarmy.profile b/etc/silentarmy.profile
index 977cfea99..88bf23158 100644
--- a/etc/silentarmy.profile
+++ b/etc/silentarmy.profile
@@ -28,7 +28,7 @@ shell none
28 28
29disable-mnt 29disable-mnt
30private 30private
31# private-bin silentarmy,sa-solver,python3 31private-bin silentarmy,sa-solver,python*
32private-dev 32private-dev
33private-opt none 33private-opt none
34private-tmp 34private-tmp
diff --git a/etc/spotify.profile b/etc/spotify.profile
index 3506b793b..586934ec3 100644
--- a/etc/spotify.profile
+++ b/etc/spotify.profile
@@ -40,7 +40,7 @@ seccomp
40shell none 40shell none
41 41
42disable-mnt 42disable-mnt
43private-bin spotify,bash,sh,dash 43private-bin spotify,bash,sh
44private-dev 44private-dev
45private-etc fonts,machine-id,pulse,resolv.conf 45private-etc fonts,machine-id,pulse,resolv.conf
46private-opt spotify 46private-opt spotify
diff --git a/etc/start-tor-browser.profile b/etc/start-tor-browser.profile
index e12a38164..57a5c20e3 100644
--- a/etc/start-tor-browser.profile
+++ b/etc/start-tor-browser.profile
@@ -24,7 +24,7 @@ seccomp
24shell none 24shell none
25tracelog 25tracelog
26 26
27private-bin bash,dash,sh,grep,tail,env,gpg,id,readlink,dirname,test,mkdir,ln,sed,cp,rm,getconf 27private-bin bash,sh,grep,tail,env,gpg,id,readlink,dirname,test,mkdir,ln,sed,cp,rm,getconf
28private-dev 28private-dev
29private-etc fonts 29private-etc fonts
30private-tmp 30private-tmp
diff --git a/etc/surf.profile b/etc/surf.profile
index 251331902..a12212f16 100644
--- a/etc/surf.profile
+++ b/etc/surf.profile
@@ -26,7 +26,7 @@ seccomp
26shell none 26shell none
27tracelog 27tracelog
28 28
29private-bin ls,surf,sh,dash,bash,curl,dmenu,printf,sed,sleep,st,stterm,xargs,xprop 29private-bin ls,surf,sh,bash,curl,dmenu,printf,sed,sleep,st,stterm,xargs,xprop
30private-dev 30private-dev
31private-etc passwd,group,hosts,resolv.conf,fonts,ssl 31private-etc passwd,group,hosts,resolv.conf,fonts,ssl
32private-tmp 32private-tmp
diff --git a/etc/tar.profile b/etc/tar.profile
index f14894c25..c8c0b2cae 100644
--- a/etc/tar.profile
+++ b/etc/tar.profile
@@ -20,7 +20,7 @@ shell none
20tracelog 20tracelog
21 21
22# support compressed archives 22# support compressed archives
23private-bin sh,bash,dash,tar,gtar,compress,gzip,lzma,xz,bzip2,lbzip2,lzip,lzop 23private-bin sh,bash,tar,gtar,compress,gzip,lzma,xz,bzip2,lbzip2,lzip,lzop
24private-dev 24private-dev
25private-etc passwd,group,localtime 25private-etc passwd,group,localtime
26 26
diff --git a/etc/torbrowser-launcher.profile b/etc/torbrowser-launcher.profile
index 3b6b65bec..85af86068 100644
--- a/etc/torbrowser-launcher.profile
+++ b/etc/torbrowser-launcher.profile
@@ -32,7 +32,7 @@ seccomp
32shell none 32shell none
33tracelog 33tracelog
34 34
35private-bin bash,cp,dash,dirname,env,expr,file,getconf,gpg,grep,id,ln,mkdir,python,python2.7,readlink,rm,sed,sh,tail,test,tor-browser-en,torbrowser-launcher 35private-bin bash,cp,dirname,env,expr,file,getconf,gpg,grep,id,ln,mkdir,python*,readlink,rm,sed,sh,tail,test,tor-browser-en,torbrowser-launcher
36private-dev 36private-dev
37private-etc fonts 37private-etc fonts
38private-tmp 38private-tmp
diff --git a/etc/waterfox.profile b/etc/waterfox.profile
index 67995f345..9626c17aa 100644
--- a/etc/waterfox.profile
+++ b/etc/waterfox.profile
@@ -80,7 +80,7 @@ shell none
80tracelog 80tracelog
81 81
82# waterfox requires a shell to launch on Arch. We can possibly remove sh though. 82# waterfox requires a shell to launch on Arch. We can possibly remove sh though.
83# private-bin waterfox,which,sh,dbus-launch,dbus-send,env,dash,bash 83# private-bin waterfox,which,sh,dbus-launch,dbus-send,env,bash
84private-dev 84private-dev
85# private-etc passwd,group,hostname,hosts,localtime,nsswitch.conf,resolv.conf,xdg,gtk-2.0,gtk-3.0,X11,pango,fonts,waterfox,mime.types,mailcap,asound.conf,pulse 85# private-etc passwd,group,hostname,hosts,localtime,nsswitch.conf,resolv.conf,xdg,gtk-2.0,gtk-3.0,X11,pango,fonts,waterfox,mime.types,mailcap,asound.conf,pulse
86private-tmp 86private-tmp
diff --git a/etc/xchat.profile b/etc/xchat.profile
index ab62160b5..bab108c0a 100644
--- a/etc/xchat.profile
+++ b/etc/xchat.profile
@@ -19,4 +19,4 @@ notv
19protocol unix,inet,inet6 19protocol unix,inet,inet6
20seccomp 20seccomp
21 21
22# private-bin requires perl, python, etc. 22# private-bin requires perl, python*, etc.
diff --git a/etc/xonotic.profile b/etc/xonotic.profile
index 6dc62c33b..b3d45dc71 100644
--- a/etc/xonotic.profile
+++ b/etc/xonotic.profile
@@ -29,7 +29,7 @@ seccomp
29shell none 29shell none
30 30
31disable-mnt 31disable-mnt
32private-bin bash,blind-id,darkplaces-glx,darkplaces-sdl,dash,dirname,grep,ldd,netstat,ps,readlink,sh,uname,xonotic,xonotic-glx,xonotic-linux32-dedicated,xonotic-linux32-glx,xonotic-linux32-sdl,xonotic-linux64-dedicated,xonotic-linux64-glx,xonotic-linux64-sdl,xonotic-sdl 32private-bin bash,blind-id,darkplaces-glx,darkplaces-sdl,dirname,grep,ldd,netstat,ps,readlink,sh,uname,xonotic,xonotic-glx,xonotic-linux32-dedicated,xonotic-linux32-glx,xonotic-linux32-sdl,xonotic-linux64-dedicated,xonotic-linux64-glx,xonotic-linux64-sdl,xonotic-sdl
33private-dev 33private-dev
34# private-etc breaks audio on some distros 34# private-etc breaks audio on some distros
35#private-etc asound.conf,ca-certificates,drirc,fonts,group,host.conf,hostname,hosts,ld.so.cache,ld.so.preload,localtime,nsswitch.conf,passwd,pulse,resolv.conf,ssl 35#private-etc asound.conf,ca-certificates,drirc,fonts,group,host.conf,hostname,hosts,ld.so.cache,ld.so.preload,localtime,nsswitch.conf,passwd,pulse,resolv.conf,ssl
diff --git a/etc/xpra.profile b/etc/xpra.profile
index 2bd91e8b5..849bb9868 100644
--- a/etc/xpra.profile
+++ b/etc/xpra.profile
@@ -41,7 +41,7 @@ shell none
41# private home directory doesn't work on some distros, so we go for a regular home 41# private home directory doesn't work on some distros, so we go for a regular home
42# private 42# private
43# older Xpra versions also use Xvfb 43# older Xpra versions also use Xvfb
44# private-bin xpra,python,Xvfb,Xorg,sh,xkbcomp,xauth,dbus-launch,pactl,ldconfig,which,strace,bash,cat,ls 44# private-bin xpra,python*,Xvfb,Xorg,sh,xkbcomp,xauth,dbus-launch,pactl,ldconfig,which,strace,bash,cat,ls
45private-dev 45private-dev
46# private-etc ld.so.conf,ld.so.cache,resolv.conf,host.conf,nsswitch.conf,gai.conf,hosts,hostname,machine-id,xpra,X11 46# private-etc ld.so.conf,ld.so.cache,resolv.conf,host.conf,nsswitch.conf,gai.conf,hosts,hostname,machine-id,xpra,X11
47private-tmp 47private-tmp
diff --git a/src/fcopy/main.c b/src/fcopy/main.c
index e7b4ffa8a..cbb551125 100644
--- a/src/fcopy/main.c
+++ b/src/fcopy/main.c
@@ -41,6 +41,11 @@ static void copy_file(const char *srcname, const char *destname, mode_t mode, ui
41 assert(destname); 41 assert(destname);
42 mode &= 07777; 42 mode &= 07777;
43 43
44 // don't copy the file if it is already there
45 struct stat s;
46 if (stat(destname, &s) == 0)
47 return;
48
44 // open source 49 // open source
45 int src = open(srcname, O_RDONLY); 50 int src = open(srcname, O_RDONLY);
46 if (src < 0) { 51 if (src < 0) {
@@ -113,10 +118,18 @@ void copy_link(const char *target, const char *linkpath, mode_t mode, uid_t uid,
113 (void) mode; 118 (void) mode;
114 (void) uid; 119 (void) uid;
115 (void) gid; 120 (void) gid;
121
122 // if the link is already there, don't create it
123 struct stat s;
124 if (stat(linkpath, &s) == 0)
125 return;
126
116 char *rp = realpath(target, NULL); 127 char *rp = realpath(target, NULL);
117 if (rp) { 128 if (rp) {
118 if (symlink(rp, linkpath) == -1) 129 if (symlink(rp, linkpath) == -1) {
130 free(rp);
119 goto errout; 131 goto errout;
132 }
120 free(rp); 133 free(rp);
121 } 134 }
122 else 135 else
@@ -129,6 +142,7 @@ errout:
129} 142}
130 143
131 144
145
132static int first = 1; 146static int first = 1;
133static int fs_copydir(const char *infname, const struct stat *st, int ftype, struct FTW *sftw) { 147static int fs_copydir(const char *infname, const struct stat *st, int ftype, struct FTW *sftw) {
134 (void) st; 148 (void) st;
diff --git a/src/firejail/appimage.c b/src/firejail/appimage.c
index 0f7ab40ff..2a045f628 100644
--- a/src/firejail/appimage.c
+++ b/src/firejail/appimage.c
@@ -45,7 +45,7 @@ void appimage_set(const char *appimage) {
45 45
46#ifdef LOOP_CTL_GET_FREE 46#ifdef LOOP_CTL_GET_FREE
47 // check appimage file 47 // check appimage file
48 invalid_filename(appimage); 48 invalid_filename(appimage, 0); // no globbing
49 if (access(appimage, R_OK) == -1) { 49 if (access(appimage, R_OK) == -1) {
50 fprintf(stderr, "Error: cannot access AppImage file\n"); 50 fprintf(stderr, "Error: cannot access AppImage file\n");
51 exit(1); 51 exit(1);
diff --git a/src/firejail/cgroup.c b/src/firejail/cgroup.c
index 70f07dd23..8d6496aab 100644
--- a/src/firejail/cgroup.c
+++ b/src/firejail/cgroup.c
@@ -72,7 +72,7 @@ errout:
72void set_cgroup(const char *path) { 72void set_cgroup(const char *path) {
73 EUID_ASSERT(); 73 EUID_ASSERT();
74 74
75 invalid_filename(path); 75 invalid_filename(path, 0); // no globbing
76 76
77 // path starts with /sys/fs/cgroup 77 // path starts with /sys/fs/cgroup
78 if (strncmp(path, "/sys/fs/cgroup", 14) != 0) 78 if (strncmp(path, "/sys/fs/cgroup", 14) != 0)
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index b9eb68fb0..e10a5d346 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -499,7 +499,7 @@ void notify_other(int fd);
499char *expand_home(const char *path, const char* homedir); 499char *expand_home(const char *path, const char* homedir);
500const char *gnu_basename(const char *path); 500const char *gnu_basename(const char *path);
501uid_t pid_get_uid(pid_t pid); 501uid_t pid_get_uid(pid_t pid);
502void invalid_filename(const char *fname); 502void invalid_filename(const char *fname, int globbing);
503uid_t get_group_id(const char *group); 503uid_t get_group_id(const char *group);
504int remove_directory(const char *path); 504int remove_directory(const char *path);
505void flush_stdin(void); 505void flush_stdin(void);
diff --git a/src/firejail/fs_bin.c b/src/firejail/fs_bin.c
index 9aa227caf..6bd7ecd17 100644
--- a/src/firejail/fs_bin.c
+++ b/src/firejail/fs_bin.c
@@ -23,6 +23,7 @@
23#include <sys/types.h> 23#include <sys/types.h>
24#include <sys/wait.h> 24#include <sys/wait.h>
25#include <unistd.h> 25#include <unistd.h>
26#include <glob.h>
26 27
27static char *paths[] = { 28static char *paths[] = {
28 "/usr/local/bin", 29 "/usr/local/bin",
@@ -146,11 +147,13 @@ errexit:
146} 147}
147 148
148static void duplicate(char *fname, FILE *fplist) { 149static void duplicate(char *fname, FILE *fplist) {
150 assert(fname);
151
149 if (*fname == '~' || strstr(fname, "..")) { 152 if (*fname == '~' || strstr(fname, "..")) {
150 fprintf(stderr, "Error: \"%s\" is an invalid filename\n", fname); 153 fprintf(stderr, "Error: \"%s\" is an invalid filename\n", fname);
151 exit(1); 154 exit(1);
152 } 155 }
153 invalid_filename(fname); 156 invalid_filename(fname, 0); // no globbing
154 157
155 char *full_path; 158 char *full_path;
156 if (*fname == '/') { 159 if (*fname == '/') {
@@ -203,6 +206,52 @@ static void duplicate(char *fname, FILE *fplist) {
203 free(full_path); 206 free(full_path);
204} 207}
205 208
209static void globbing(char *fname, FILE *fplist) {
210 assert(fname);
211
212 // go directly to duplicate() if no globbing char is present - see man 7 glob
213 if (strrchr(fname, '*') == NULL &&
214 strrchr(fname, '[') == NULL &&
215 strrchr(fname, '?') == NULL)
216 return duplicate(fname, fplist);
217
218 // loop through paths[]
219 int i = 0;
220 while (paths[i]) {
221 // private-bin-no-local can be disabled in /etc/firejail/firejail.config
222 if (checkcfg(CFG_PRIVATE_BIN_NO_LOCAL) && strstr(paths[i], "local/")) {
223 i++;
224 continue;
225 }
226
227 // check file
228 char *pattern;
229 if (asprintf(&pattern, "%s/%s", paths[i], fname) == -1)
230 errExit("asprintf");
231
232 // globbing
233 glob_t globbuf;
234 int globerr = glob(pattern, GLOB_NOCHECK | GLOB_NOSORT | GLOB_PERIOD, NULL, &globbuf);
235 if (globerr) {
236 fprintf(stderr, "Error: failed to glob private-bin pattern %s\n", pattern);
237 exit(1);
238 }
239
240 size_t j;
241 for (j = 0; j < globbuf.gl_pathc; j++) {
242 assert(globbuf.gl_pathv[j]);
243 // testing for GLOB_NOCHECK - no pattern matched returns the original pattern
244 if (strcmp(globbuf.gl_pathv[j], pattern) == 0)
245 continue;
246
247 duplicate(globbuf.gl_pathv[j], fplist);
248 }
249
250 globfree(&globbuf);
251 free(pattern);
252 i++;
253 }
254}
206 255
207void fs_private_bin_list(void) { 256void fs_private_bin_list(void) {
208 char *private_list = cfg.bin_private_keep; 257 char *private_list = cfg.bin_private_keep;
@@ -228,9 +277,9 @@ void fs_private_bin_list(void) {
228 } 277 }
229 278
230 char *ptr = strtok(dlist, ","); 279 char *ptr = strtok(dlist, ",");
231 duplicate(ptr, fplist); 280 globbing(ptr, fplist);
232 while ((ptr = strtok(NULL, ",")) != NULL) 281 while ((ptr = strtok(NULL, ",")) != NULL)
233 duplicate(ptr, fplist); 282 globbing(ptr, fplist);
234 free(dlist); 283 free(dlist);
235 fs_logger_print(); 284 fs_logger_print();
236 if (fplist) 285 if (fplist)
diff --git a/src/firejail/fs_etc.c b/src/firejail/fs_etc.c
index b0835d50b..9502844b2 100644
--- a/src/firejail/fs_etc.c
+++ b/src/firejail/fs_etc.c
@@ -103,7 +103,7 @@ static void duplicate(const char *fname, const char *private_dir, const char *pr
103 fprintf(stderr, "Error: \"%s\" is an invalid filename\n", fname); 103 fprintf(stderr, "Error: \"%s\" is an invalid filename\n", fname);
104 exit(1); 104 exit(1);
105 } 105 }
106 invalid_filename(fname); 106 invalid_filename(fname, 0); // no globbing
107 107
108 char *src; 108 char *src;
109 if (asprintf(&src, "%s/%s", private_dir, fname) == -1) 109 if (asprintf(&src, "%s/%s", private_dir, fname) == -1)
diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c
index 9e3678c33..0de003e58 100644
--- a/src/firejail/fs_home.c
+++ b/src/firejail/fs_home.c
@@ -325,7 +325,7 @@ void fs_private(void) {
325// check new private home directory (--private= option) - exit if it fails 325// check new private home directory (--private= option) - exit if it fails
326void fs_check_private_dir(void) { 326void fs_check_private_dir(void) {
327 EUID_ASSERT(); 327 EUID_ASSERT();
328 invalid_filename(cfg.home_private); 328 invalid_filename(cfg.home_private, 0); // no globbing
329 329
330 // Expand the home directory 330 // Expand the home directory
331 char *tmp = expand_home(cfg.home_private, cfg.homedir); 331 char *tmp = expand_home(cfg.home_private, cfg.homedir);
@@ -367,7 +367,7 @@ static char *check_dir_or_file(const char *name) {
367 assert(name); 367 assert(name);
368 368
369 // basic checks 369 // basic checks
370 invalid_filename(name); 370 invalid_filename(name, 0); // no globbing
371 if (arg_debug) 371 if (arg_debug)
372 printf("Private home: checking %s\n", name); 372 printf("Private home: checking %s\n", name);
373 373
diff --git a/src/firejail/fs_hostname.c b/src/firejail/fs_hostname.c
index 42255070c..0cf715fe2 100644
--- a/src/firejail/fs_hostname.c
+++ b/src/firejail/fs_hostname.c
@@ -129,7 +129,7 @@ void fs_resolvconf(void) {
129 129
130char *fs_check_hosts_file(const char *fname) { 130char *fs_check_hosts_file(const char *fname) {
131 assert(fname); 131 assert(fname);
132 invalid_filename(fname); 132 invalid_filename(fname, 0); // no globbing
133 char *rv = expand_home(fname, cfg.homedir); 133 char *rv = expand_home(fname, cfg.homedir);
134 134
135 // no a link 135 // no a link
diff --git a/src/firejail/fs_mkdir.c b/src/firejail/fs_mkdir.c
index 20ffe825a..7975ae323 100644
--- a/src/firejail/fs_mkdir.c
+++ b/src/firejail/fs_mkdir.c
@@ -59,7 +59,7 @@ void fs_mkdir(const char *name) {
59 EUID_ASSERT(); 59 EUID_ASSERT();
60 60
61 // check directory name 61 // check directory name
62 invalid_filename(name); 62 invalid_filename(name, 0); // no globbing
63 char *expanded = expand_home(name, cfg.homedir); 63 char *expanded = expand_home(name, cfg.homedir);
64 if (strncmp(expanded, cfg.homedir, strlen(cfg.homedir)) != 0 && 64 if (strncmp(expanded, cfg.homedir, strlen(cfg.homedir)) != 0 &&
65 strncmp(expanded, "/tmp", 4) != 0) { 65 strncmp(expanded, "/tmp", 4) != 0) {
@@ -99,7 +99,7 @@ void fs_mkfile(const char *name) {
99 EUID_ASSERT(); 99 EUID_ASSERT();
100 100
101 // check file name 101 // check file name
102 invalid_filename(name); 102 invalid_filename(name, 0); // no globbing
103 char *expanded = expand_home(name, cfg.homedir); 103 char *expanded = expand_home(name, cfg.homedir);
104 if (strncmp(expanded, cfg.homedir, strlen(cfg.homedir)) != 0 && 104 if (strncmp(expanded, cfg.homedir, strlen(cfg.homedir)) != 0 &&
105 strncmp(expanded, "/tmp", 4) != 0) { 105 strncmp(expanded, "/tmp", 4) != 0) {
diff --git a/src/firejail/main.c b/src/firejail/main.c
index 54cbf1526..458bba6f6 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -572,7 +572,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
572 exit(1); 572 exit(1);
573 } 573 }
574 char *path = argv[i + 1]; 574 char *path = argv[i + 1];
575 invalid_filename(path); 575 invalid_filename(path, 0); // no globbing
576 if (strstr(path, "..")) { 576 if (strstr(path, "..")) {
577 fprintf(stderr, "Error: invalid file name %s\n", path); 577 fprintf(stderr, "Error: invalid file name %s\n", path);
578 exit(1); 578 exit(1);
@@ -596,13 +596,13 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
596 exit(1); 596 exit(1);
597 } 597 }
598 char *path1 = argv[i + 1]; 598 char *path1 = argv[i + 1];
599 invalid_filename(path1); 599 invalid_filename(path1, 0); // no globbing
600 if (strstr(path1, "..")) { 600 if (strstr(path1, "..")) {
601 fprintf(stderr, "Error: invalid file name %s\n", path1); 601 fprintf(stderr, "Error: invalid file name %s\n", path1);
602 exit(1); 602 exit(1);
603 } 603 }
604 char *path2 = argv[i + 2]; 604 char *path2 = argv[i + 2];
605 invalid_filename(path2); 605 invalid_filename(path2, 0); // no globbing
606 if (strstr(path2, "..")) { 606 if (strstr(path2, "..")) {
607 fprintf(stderr, "Error: invalid file name %s\n", path2); 607 fprintf(stderr, "Error: invalid file name %s\n", path2);
608 exit(1); 608 exit(1);
@@ -626,7 +626,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
626 exit(1); 626 exit(1);
627 } 627 }
628 char *path = argv[i + 1]; 628 char *path = argv[i + 1];
629 invalid_filename(path); 629 invalid_filename(path, 0); // no globbing
630 if (strstr(path, "..")) { 630 if (strstr(path, "..")) {
631 fprintf(stderr, "Error: invalid file name %s\n", path); 631 fprintf(stderr, "Error: invalid file name %s\n", path);
632 exit(1); 632 exit(1);
@@ -1434,7 +1434,7 @@ int main(int argc, char **argv) {
1434 } 1434 }
1435 1435
1436 // check name 1436 // check name
1437 invalid_filename(subdirname); 1437 invalid_filename(subdirname, 0); // no globbing
1438 if (strstr(subdirname, "..") || strstr(subdirname, "/")) { 1438 if (strstr(subdirname, "..") || strstr(subdirname, "/")) {
1439 fprintf(stderr, "Error: invalid overlay name\n"); 1439 fprintf(stderr, "Error: invalid overlay name\n");
1440 exit(1); 1440 exit(1);
@@ -1483,7 +1483,7 @@ int main(int argc, char **argv) {
1483 exit(1); 1483 exit(1);
1484 } 1484 }
1485 custom_profile_dir = expand_home(argv[i] + 15, cfg.homedir); 1485 custom_profile_dir = expand_home(argv[i] + 15, cfg.homedir);
1486 invalid_filename(custom_profile_dir); 1486 invalid_filename(custom_profile_dir, 0); // no globbing
1487 if (!is_dir(custom_profile_dir) || is_link(custom_profile_dir) || strstr(custom_profile_dir, "..")) { 1487 if (!is_dir(custom_profile_dir) || is_link(custom_profile_dir) || strstr(custom_profile_dir, "..")) {
1488 fprintf(stderr, "Error: invalid profile path\n"); 1488 fprintf(stderr, "Error: invalid profile path\n");
1489 exit(1); 1489 exit(1);
@@ -1542,7 +1542,7 @@ int main(int argc, char **argv) {
1542 } 1542 }
1543 1543
1544 1544
1545 invalid_filename(argv[i] + 9); 1545 invalid_filename(argv[i] + 9, 0); // no globbing
1546 1546
1547 // extract chroot dirname 1547 // extract chroot dirname
1548 cfg.chrootdir = argv[i] + 9; 1548 cfg.chrootdir = argv[i] + 9;
@@ -2193,7 +2193,7 @@ int main(int argc, char **argv) {
2193 fprintf(stderr, "Error: --shell=none was already specified.\n"); 2193 fprintf(stderr, "Error: --shell=none was already specified.\n");
2194 return 1; 2194 return 1;
2195 } 2195 }
2196 invalid_filename(argv[i] + 8); 2196 invalid_filename(argv[i] + 8, 0); // no globbing
2197 2197
2198 if (cfg.shell) { 2198 if (cfg.shell) {
2199 fprintf(stderr, "Error: only one user shell can be specified\n"); 2199 fprintf(stderr, "Error: only one user shell can be specified\n");
diff --git a/src/firejail/netfilter.c b/src/firejail/netfilter.c
index 14b3b54a6..cb0d9d7af 100644
--- a/src/firejail/netfilter.c
+++ b/src/firejail/netfilter.c
@@ -45,7 +45,7 @@ static char *client_filter =
45 45
46void check_netfilter_file(const char *fname) { 46void check_netfilter_file(const char *fname) {
47 EUID_ASSERT(); 47 EUID_ASSERT();
48 invalid_filename(fname); 48 invalid_filename(fname, 0); // no globbing
49 49
50 if (is_dir(fname) || is_link(fname) || strstr(fname, "..") || access(fname, R_OK )) { 50 if (is_dir(fname) || is_link(fname) || strstr(fname, "..") || access(fname, R_OK )) {
51 fprintf(stderr, "Error: invalid network filter file %s\n", fname); 51 fprintf(stderr, "Error: invalid network filter file %s\n", fname);
diff --git a/src/firejail/netns.c b/src/firejail/netns.c
index fdd108652..f52613490 100644
--- a/src/firejail/netns.c
+++ b/src/firejail/netns.c
@@ -49,7 +49,7 @@ void check_netns(const char *nsname) {
49 fprintf(stderr, "Error: invalid netns name %s\n", nsname); 49 fprintf(stderr, "Error: invalid netns name %s\n", nsname);
50 exit(1); 50 exit(1);
51 } 51 }
52 invalid_filename(nsname); 52 invalid_filename(nsname, 0); // no globbing
53 char *control_file = netns_control_file(nsname); 53 char *control_file = netns_control_file(nsname);
54 54
55 EUID_ASSERT(); 55 EUID_ASSERT();
diff --git a/src/firejail/output.c b/src/firejail/output.c
index b99604ec4..4f68b8ca3 100644
--- a/src/firejail/output.c
+++ b/src/firejail/output.c
@@ -48,7 +48,7 @@ void check_output(int argc, char **argv) {
48 drop_privs(0); 48 drop_privs(0);
49 char *outfile = argv[outindex]; 49 char *outfile = argv[outindex];
50 outfile += (enable_stderr)? 16:9; 50 outfile += (enable_stderr)? 16:9;
51 invalid_filename(outfile); 51 invalid_filename(outfile, 0); // no globbing
52 52
53 // do not accept directories, links, and files with ".." 53 // do not accept directories, links, and files with ".."
54 if (strstr(outfile, "..") || is_link(outfile) || is_dir(outfile)) { 54 if (strstr(outfile, "..") || is_link(outfile) || is_dir(outfile)) {
diff --git a/src/firejail/profile.c b/src/firejail/profile.c
index 789a8b060..a1c94579c 100644
--- a/src/firejail/profile.c
+++ b/src/firejail/profile.c
@@ -925,7 +925,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
925 } 925 }
926 926
927 // check name 927 // check name
928 invalid_filename(subdirname); 928 invalid_filename(subdirname, 0); // no globbing
929 if (strstr(subdirname, "..") || strstr(subdirname, "/")) { 929 if (strstr(subdirname, "..") || strstr(subdirname, "/")) {
930 fprintf(stderr, "Error: invalid overlay name\n"); 930 fprintf(stderr, "Error: invalid overlay name\n");
931 exit(1); 931 exit(1);
@@ -993,8 +993,8 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
993 } 993 }
994 994
995 // check directories 995 // check directories
996 invalid_filename(dname1); 996 invalid_filename(dname1, 0); // no globbing
997 invalid_filename(dname2); 997 invalid_filename(dname2, 0); // no globbing
998 if (strstr(dname1, "..") || strstr(dname2, "..")) { 998 if (strstr(dname1, "..") || strstr(dname2, "..")) {
999 fprintf(stderr, "Error: invalid file name.\n"); 999 fprintf(stderr, "Error: invalid file name.\n");
1000 exit(1); 1000 exit(1);
@@ -1123,7 +1123,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
1123 } 1123 }
1124 1124
1125 // some characters just don't belong in filenames 1125 // some characters just don't belong in filenames
1126 invalid_filename(ptr); 1126 invalid_filename(ptr, 1); // globbing
1127 if (strstr(ptr, "..")) { 1127 if (strstr(ptr, "..")) {
1128 if (lineno == 0) 1128 if (lineno == 0)
1129 fprintf(stderr, "Error: \"%s\" is an invalid filename\n", ptr); 1129 fprintf(stderr, "Error: \"%s\" is an invalid filename\n", ptr);
@@ -1170,7 +1170,7 @@ void profile_read(const char *fname) {
1170 } 1170 }
1171 1171
1172 // check file 1172 // check file
1173 invalid_filename(fname); 1173 invalid_filename(fname, 0); // no globbing
1174 if (strlen(fname) == 0 || is_dir(fname)) { 1174 if (strlen(fname) == 0 || is_dir(fname)) {
1175 fprintf(stderr, "Error: invalid profile file\n"); 1175 fprintf(stderr, "Error: invalid profile file\n");
1176 exit(1); 1176 exit(1);
diff --git a/src/firejail/util.c b/src/firejail/util.c
index 4d1c94c25..559f7ee48 100644
--- a/src/firejail/util.c
+++ b/src/firejail/util.c
@@ -747,7 +747,7 @@ uid_t pid_get_uid(pid_t pid) {
747} 747}
748 748
749 749
750void invalid_filename(const char *fname) { 750void invalid_filename(const char *fname, int globbing) {
751// EUID_ASSERT(); 751// EUID_ASSERT();
752 assert(fname); 752 assert(fname);
753 const char *ptr = fname; 753 const char *ptr = fname;
@@ -763,10 +763,19 @@ void invalid_filename(const char *fname) {
763 return; 763 return;
764 764
765 int len = strlen(ptr); 765 int len = strlen(ptr);
766 // file globbing ('*') is allowed 766
767 if (strcspn(ptr, "\\&!?\"'<>%^(){}[];,") != (size_t)len) { 767 if (globbing) {
768 fprintf(stderr, "Error: \"%s\" is an invalid filename\n", ptr); 768 // file globbing ('*?[]') is allowed
769 exit(1); 769 if (strcspn(ptr, "\\&!\"'<>%^(){};,") != (size_t)len) {
770 fprintf(stderr, "Error: \"%s\" is an invalid filename\n", ptr);
771 exit(1);
772 }
773 }
774 else {
775 if (strcspn(ptr, "\\&!?\"'<>%^(){};,*[]") != (size_t)len) {
776 fprintf(stderr, "Error: \"%s\" is an invalid filename\n", ptr);
777 exit(1);
778 }
770 } 779 }
771} 780}
772 781