commit 841b726
Merge pull request 'strip_exif support for the OpenBSD sandbox' (#548) from oxzi/snac2:strip-metadata-openbsd into master Reviewed-on: https://codeberg.org/grunfink/snac2/pulls/548
M
data.c
+6,
-13
1@@ -100,19 +100,12 @@ int srv_open(const char *basedir, int auto_upgrade)
2
3 if (auto_upgrade)
4 ret = snac_upgrade(&error);
5- else {
6- if (xs_number_get(xs_dict_get(srv_config, "layout")) < disk_layout)
7- error = xs_fmt("ERROR: disk layout changed - execute 'snac upgrade' first");
8- else {
9- if (!check_strip_tool()) {
10- const char *mp = xs_dict_get(srv_config, "mogrify_path");
11- if (mp == NULL) mp = "mogrify";
12- error = xs_fmt("ERROR: strip_exif enabled but '%s' not found or not working (set 'mogrify_path' in server.json)", mp);
13- }
14- else
15- ret = 1;
16- }
17- }
18+ else if (xs_number_get(xs_dict_get(srv_config, "layout")) < disk_layout)
19+ error = xs_fmt("ERROR: disk layout changed - execute 'snac upgrade' first");
20+ else if (!check_strip_tool())
21+ error = xs_fmt("ERROR: strip_exif enabled but commands not found or working");
22+ else
23+ ret = 1;
24 }
25
26 }
+8,
-1
1@@ -13,6 +13,8 @@ void sbox_enter(const char *basedir)
2 return;
3 }
4
5+ const xs_val *strip_exif = xs_dict_get(srv_config, "strip_exif");
6+
7 int smail;
8 const char *url = xs_dict_get(srv_config, "smtp_url");
9
10@@ -33,6 +35,11 @@ void sbox_enter(const char *basedir)
11 if (*address == '/')
12 unveil(address, "rwc");
13
14+ if (strip_exif) {
15+ unveil(xs_dict_get(srv_config, "ffmpeg_path"), "x");
16+ unveil(xs_dict_get(srv_config, "mogrify_path"), "x");
17+ }
18+
19 if (smail)
20 unveil("/usr/sbin/sendmail", "x");
21
22@@ -45,7 +52,7 @@ void sbox_enter(const char *basedir)
23 if (*address == '/')
24 p = xs_str_cat(p, " unix");
25
26- if (smail)
27+ if (smail || strip_exif)
28 p = xs_str_cat(p, " exec");
29
30 pledge(p, NULL);
M
snac.c
+99,
-59
1@@ -35,7 +35,9 @@
2 #include <sys/stat.h>
3 #include <sys/wait.h>
4 #include <limits.h>
5+#include <stdio.h>
6 #include <stdlib.h>
7+#include <unistd.h>
8
9 xs_str *srv_basedir = NULL;
10 xs_dict *srv_config = NULL;
11@@ -177,6 +179,46 @@ int check_password(const char *uid, const char *passwd, const char *hash)
12 }
13
14
15+char* findprog(const char *prog)
16+/* find a prog in PATH and return the first match */
17+{
18+ char *path_env, *path, *dir, filename[PATH_MAX];
19+ int len;
20+ struct stat sbuf;
21+
22+ path_env = getenv("PATH");
23+ if (!prog || !path_env)
24+ return NULL;
25+
26+ path_env = strdup(path_env);
27+ if (!path_env)
28+ return NULL;
29+ path = path_env;
30+
31+ while ((dir = strsep(&path, ":")) != NULL) {
32+ /* empty entries as ./ instead of / */
33+ if (*dir == '\0')
34+ dir = ".";
35+
36+ /* strip trailing / */
37+ len = strlen(dir);
38+ while (len > 0 && dir[len-1] == '/')
39+ dir[--len] = '\0';
40+
41+ len = snprintf(filename, sizeof(filename), "%s/%s", dir, prog);
42+ if (len > 0 && len < (int) sizeof(filename) &&
43+ (stat(filename, &sbuf) == 0) && S_ISREG(sbuf.st_mode) &&
44+ access(filename, X_OK) == 0) {
45+ free(path_env);
46+ return strdup(filename);
47+ }
48+ }
49+
50+ free(path_env);
51+ return NULL;
52+}
53+
54+
55 int strip_media(const char *fn)
56 /* strips EXIF data from a file */
57 {
58@@ -207,23 +249,24 @@ int strip_media(const char *fn)
59 xs_endswith(l_fn, ".gif") || xs_endswith(l_fn, ".bmp")) {
60
61 const char *mp = xs_dict_get(srv_config, "mogrify_path");
62- if (mp == NULL)
63- mp = "mogrify";
64
65- xs *cmd = xs_fmt("cd \"%s\" && %s -auto-orient -strip \"%s\" 2>/dev/null", srv_basedir, mp, r_fn);
66-
67- ret = system(cmd);
68+ pid_t pid = fork();
69+ if (pid == -1) {
70+ srv_log(xs_fmt("strip_media: cannot fork()"));
71+ return -1;
72+ } else if (pid == 0) {
73+ chdir(srv_basedir);
74+ execl(mp, "-auto-orient", "-strip", r_fn, (char*) NULL);
75+ _exit(1);
76+ }
77
78- if (ret != 0) {
79- int code = 0;
80- if (WIFEXITED(ret))
81- code = WEXITSTATUS(ret);
82-
83- if (code == 127)
84- srv_log(xs_fmt("strip_media: error stripping %s. '%s' not found (exit 127). Set 'mogrify_path' in server.json.", r_fn, mp));
85- else
86- srv_log(xs_fmt("strip_media: error stripping %s %d", r_fn, ret));
87+ if (waitpid(pid, &ret, 0) == -1) {
88+ srv_log(xs_fmt("strip_media: cannot waitpid()"));
89+ return -1;
90 }
91+
92+ if (ret != 0)
93+ srv_log(xs_fmt("strip_media: error stripping %s %d", r_fn, ret));
94 else
95 srv_debug(1, xs_fmt("strip_media: stripped %s", r_fn));
96 }
97@@ -234,35 +277,33 @@ int strip_media(const char *fn)
98 xs_endswith(l_fn, ".mkv") || xs_endswith(l_fn, ".avi")) {
99
100 const char *fp = xs_dict_get(srv_config, "ffmpeg_path");
101- if (fp == NULL)
102- fp = "ffmpeg";
103
104 /* ffmpeg cannot modify in-place, so we need a temp file */
105 /* we must preserve valid extension for ffmpeg to guess the format */
106 const char *ext = strrchr(r_fn, '.');
107 if (ext == NULL) ext = "";
108 xs *tmp_fn = xs_fmt("%s.tmp%s", r_fn, ext);
109-
110- /* -map_metadata -1 strips all global metadata */
111- /* -c copy copies input streams without re-encoding */
112- /* we don't silence stderr so we can debug issues */
113- /* we explicitly cd to srv_basedir to ensure relative paths work */
114- xs *cmd = xs_fmt("cd \"%s\" && %s -y -i \"%s\" -map_metadata -1 -c copy \"%s\"", srv_basedir, fp, r_fn, tmp_fn);
115
116- ret = system(cmd);
117+ pid_t pid = fork();
118+ if (pid == -1) {
119+ srv_log(xs_fmt("strip_media: cannot fork()"));
120+ return -1;
121+ } else if (pid == 0) {
122+ chdir(srv_basedir);
123+ /* -map_metadata -1 strips all global metadata */
124+ /* -c copy copies input streams without re-encoding */
125+ execl(fp, "-y", "-i", r_fn, "-map_metadata", "-1", "-c", "copy", tmp_fn, (char*) NULL);
126+ _exit(1);
127+ }
128+
129+ if (waitpid(pid, &ret, 0) == -1) {
130+ srv_log(xs_fmt("strip_media: cannot waitpid()"));
131+ return -1;
132+ }
133
134 if (ret != 0) {
135- int code = 0;
136- if (WIFEXITED(ret))
137- code = WEXITSTATUS(ret);
138-
139- if (code == 127)
140- srv_log(xs_fmt("strip_media: error stripping %s. '%s' not found (exit 127). Set 'ffmpeg_path' in server.json.", r_fn, fp));
141- else {
142- srv_log(xs_fmt("strip_media: error stripping %s %d", r_fn, ret));
143- srv_log(xs_fmt("strip_media: command was: %s", cmd));
144- }
145-
146+ srv_log(xs_fmt("strip_media: error stripping %s %d", r_fn, ret));
147+
148 /* try to cleanup, just in case */
149 /* unlink needs full path too if we are not in basedir */
150 xs *full_tmp_fn = xs_fmt("%s/%s", srv_basedir, tmp_fn);
151@@ -286,38 +327,37 @@ int strip_media(const char *fn)
152
153
154 int check_strip_tool(void)
155+/* check if strip_exif tools do exist and fix their absolute path */
156 {
157 const xs_val *v = xs_dict_get(srv_config, "strip_exif");
158+ /* skip if unless strip_exif; return non-error */
159+ if (xs_type(v) != XSTYPE_TRUE)
160+ return 1;
161+
162 int ret = 1;
163+ const char *progs[] = { "ffmpeg", "mogrify" };
164
165- if (xs_type(v) == XSTYPE_TRUE) {
166- /* check mogrify */
167- {
168- const char *mp = xs_dict_get(srv_config, "mogrify_path");
169- if (mp == NULL)
170- mp = "mogrify";
171-
172- xs *cmd = xs_fmt("%s -version 2>/dev/null >/dev/null", mp);
173-
174- if (system(cmd) != 0) {
175- srv_log(xs_fmt("check_strip_tool: '%s' not working", mp));
176- ret = 0;
177- }
178+ for (int i = 0; i < (int)(sizeof(progs) / sizeof(progs[0])); i++) {
179+ xs_str *key = xs_fmt("%s_path", progs[i]);
180+
181+ const char *val = xs_dict_get(srv_config, key);
182+ if (val == NULL) {
183+ val = findprog(progs[i]);
184+ if (val != NULL)
185+ srv_debug(1, xs_fmt("check_strip_tool: found %s in PATH at %s", progs[i], val));
186 }
187
188- /* check ffmpeg */
189- if (ret) {
190- const char *fp = xs_dict_get(srv_config, "ffmpeg_path");
191- if (fp == NULL)
192- fp = "ffmpeg";
193-
194- xs *cmd = xs_fmt("%s -version 2>/dev/null >/dev/null", fp);
195-
196- if (system(cmd) != 0) {
197- srv_log(xs_fmt("check_strip_tool: '%s' not working", fp));
198- ret = 0;
199- }
200+ if (val == NULL) {
201+ srv_log(xs_fmt("check_strip_tool: %s not found in PATH", progs[i]));
202+ ret = 0;
203+ } else if (access(val, X_OK) != 0) {
204+ srv_log(xs_fmt("check_strip_tool: %s '%s' is not executable", progs[i], val));
205+ ret = 0;
206+ } else {
207+ srv_config = xs_dict_set(srv_config, key, val);
208 }
209+
210+ xs_free(key);
211 }
212
213 return ret;
M
snac.h
+1,
-0
1@@ -107,6 +107,7 @@ int validate_uid(const char *uid);
2 xs_str *hash_password(const char *uid, const char *passwd, const char *nonce);
3 int check_password(const char *uid, const char *passwd, const char *hash);
4
5+char* findprog(const char *prog);
6 int strip_media(const char *fn);
7 int check_strip_tool(void);
8