1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | #ifndef _CONFIG_H |
12 | #define _CONFIG_H |
13 | #include "config.h" |
14 | #endif |
15 | |
16 | #include <stdlib.h> |
17 | #include <stdio.h> |
18 | #include <unistd.h> |
19 | #include <string.h> |
20 | #include <sys/param.h> /* for PATH_MAX */ |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | #ifdef USE_LIBGLUSTERFS1 |
30 | #include "glusterfs.h" |
31 | #include "globals.h" |
32 | #endif |
33 | |
34 | #include "common-utils.h" |
35 | #include "run.h" |
36 | #include "procdiggy.h" |
37 | |
38 | #define _GLUSTERD_CALLED_"_GLUSTERD_CALLED_" "_GLUSTERD_CALLED_" |
39 | #define _GSYNCD_DISPATCHED_"_GSYNCD_DISPATCHED_" "_GSYNCD_DISPATCHED_" |
40 | #define GSYNCD_CONF"geo-replication/gsyncd.conf" "geo-replication/gsyncd.conf" |
41 | #define GSYNCD_PY"gsyncd.py" "gsyncd.py" |
42 | #define RSYNC"rsync" "rsync" |
43 | |
44 | int restricted = 0; |
45 | |
46 | static int |
47 | duplexpand (void **buf, size_t tsiz, size_t *len) |
48 | { |
49 | size_t osiz = tsiz * *len; |
50 | char *p = realloc (*buf, osiz << 1); |
51 | if (!p) { |
52 | free(*buf); |
53 | return -1; |
54 | } |
55 | |
56 | memset (p + osiz, 0, osiz); |
57 | *buf = p; |
58 | *len <<= 1; |
59 | |
60 | return 0; |
61 | } |
62 | |
63 | static int |
64 | str2argv (char *str, char ***argv) |
65 | { |
66 | char *p = NULL((void*)0); |
67 | char *savetok = NULL((void*)0); |
68 | int argc = 0; |
69 | size_t argv_len = 32; |
70 | int ret = 0; |
71 | |
72 | assert (str)((str) ? (void) (0) : __assert_fail ("str", "gsyncd.c", 72, __PRETTY_FUNCTION__ )); |
73 | str = strdup (str); |
74 | if (!str) |
75 | return -1; |
76 | |
77 | *argv = calloc (argv_len, sizeof (**argv)); |
78 | if (!*argv) |
79 | goto error; |
80 | |
81 | while ((p = strtok_r (str, " ", &savetok))) { |
82 | str = NULL((void*)0); |
83 | |
84 | argc++; |
85 | if (argc == argv_len) { |
86 | ret = duplexpand ((void *)argv, |
87 | sizeof (**argv), |
88 | &argv_len); |
89 | if (ret == -1) |
90 | goto error; |
91 | } |
92 | (*argv)[argc - 1] = p; |
93 | } |
94 | |
95 | return argc; |
96 | |
97 | error: |
98 | fprintf (stderrstderr, "out of memory\n"); |
99 | return -1; |
100 | } |
101 | |
102 | static int |
103 | invoke_gsyncd (int argc, char **argv) |
104 | { |
105 | char config_file[PATH_MAX4096] = {0,}; |
106 | size_t gluster_workdir_len = 0; |
107 | runner_t runner = {0,}; |
108 | int i = 0; |
109 | int j = 0; |
110 | char *nargv[argc + 4]; |
111 | char *python = NULL((void*)0); |
112 | |
113 | if (restricted) { |
114 | size_t len; |
115 | |
116 | runinit (&runner); |
117 | runner_add_args (&runner, SBIN_DIR"/usr/local/sbin""/gluster", |
118 | "--log-file=-", "system::", "getwd", |
119 | NULL((void*)0)); |
120 | runner_redir (&runner, STDOUT_FILENO1, RUN_PIPE-1); |
121 | if (runner_start (&runner) == 0 && |
122 | fgets (config_file, PATH_MAX4096, |
123 | runner_chio (&runner, STDOUT_FILENO1)) != NULL((void*)0) && |
124 | (len = strlen (config_file)) && |
125 | config_file[len - 1] == '\n' && |
126 | runner_end (&runner) == 0) |
127 | gluster_workdir_len = len - 1; |
128 | |
129 | if (gluster_workdir_len) { |
130 | if (gluster_workdir_len + 1 + strlen (GSYNCD_CONF"geo-replication/gsyncd.conf") + 1 > |
131 | PATH_MAX4096) |
132 | goto error; |
133 | config_file[gluster_workdir_len] = '/'; |
134 | strcat (config_file, GSYNCD_CONF"geo-replication/gsyncd.conf"); |
135 | } else |
136 | goto error; |
137 | |
138 | if (setenv ("_GSYNCD_RESTRICTED_", "1", 1) == -1) |
139 | goto error; |
140 | } |
141 | |
142 | if (chdir ("/") == -1) |
143 | goto error; |
144 | |
145 | j = 0; |
146 | python = getenv("PYTHON"); |
147 | if(!python) |
148 | python = PYTHON"/usr/bin/python"; |
149 | nargv[j++] = python; |
150 | nargv[j++] = GSYNCD_PREFIX"/usr/local/libexec/glusterfs""/python/syncdaemon/"GSYNCD_PY"gsyncd.py"; |
151 | for (i = 1; i < argc; i++) |
152 | nargv[j++] = argv[i]; |
153 | if (config_file[0]) { |
154 | nargv[j++] = "-c"; |
155 | nargv[j++] = config_file; |
156 | } |
157 | nargv[j++] = NULL((void*)0); |
158 | |
159 | execvp (python, nargv); |
160 | |
161 | fprintf (stderrstderr, "exec of '%s' failed\n", python); |
162 | return 127; |
163 | |
164 | error: |
165 | fprintf (stderrstderr, "gsyncd initializaion failed\n"); |
166 | return 1; |
167 | } |
168 | |
169 | |
170 | static int |
171 | find_gsyncd (pid_t pid, pid_t ppid, char *name, void *data) |
172 | { |
173 | char buf[NAME_MAX255 * 2] = {0,}; |
174 | char path[PATH_MAX4096] = {0,}; |
175 | char *p = NULL((void*)0); |
176 | int zeros = 0; |
177 | int ret = 0; |
178 | int fd = -1; |
179 | pid_t *pida = (pid_t *)data; |
180 | |
181 | if (ppid != pida[0]) |
182 | return 0; |
183 | |
184 | sprintf (path, PROC"/proc""/%d/cmdline", pid); |
185 | fd = open (path, O_RDONLY00); |
186 | if (fd == -1) |
187 | return 0; |
188 | ret = read (fd, buf, sizeof (buf)); |
189 | close (fd); |
190 | if (ret == -1) |
191 | return 0; |
192 | for (zeros = 0, p = buf; zeros < 2 && p < buf + ret; p++) |
193 | zeros += !*p; |
194 | |
195 | ret = 0; |
196 | switch (zeros) { |
197 | case 2: |
198 | if ((strcmp (basename (buf), basename (PYTHON"/usr/bin/python")) || |
199 | strcmp (basename (buf + strlen (buf) + 1), GSYNCD_PY"gsyncd.py")) == 0) { |
200 | ret = 1; |
201 | break; |
202 | } |
203 | |
204 | case 1: |
205 | if (strcmp (basename (buf), GSYNCD_PY"gsyncd.py") == 0) |
206 | ret = 1; |
207 | } |
208 | |
209 | if (ret == 1) { |
210 | if (pida[1] != -1) { |
211 | fprintf (stderrstderr, GSYNCD_PY"gsyncd.py"" sibling is not unique"); |
212 | return -1; |
213 | } |
214 | pida[1] = pid; |
215 | } |
216 | |
217 | return 0; |
218 | } |
219 | |
220 | static int |
221 | invoke_rsync (int argc, char **argv) |
222 | { |
223 | int i = 0; |
224 | char path[PATH_MAX4096] = {0,}; |
225 | pid_t pid = -1; |
226 | pid_t ppid = -1; |
227 | pid_t pida[] = {-1, -1}; |
228 | char *name = NULL((void*)0); |
229 | char buf[PATH_MAX4096 + 1] = {0,}; |
230 | int ret = 0; |
231 | |
232 | assert (argv[argc] == NULL)((argv[argc] == ((void*)0)) ? (void) (0) : __assert_fail ("argv[argc] == ((void*)0)" , "gsyncd.c", 232, __PRETTY_FUNCTION__)); |
233 | |
234 | if (argc < 2 || strcmp (argv[1], "--server") != 0) |
235 | goto error; |
236 | |
237 | for (i = 2; i < argc && argv[i][0] == '-'; i++); |
238 | |
239 | if (!(i == argc - 2 && strcmp (argv[i], ".") == 0 && argv[i + 1][0] == '/')) { |
240 | fprintf (stderrstderr, "need an rsync invocation without protected args\n"); |
241 | goto error; |
242 | } |
243 | |
244 | |
245 | for (pid = getpid () ;; pid = ppid) { |
246 | ppid = pidinfo (pid, &name); |
247 | if (ppid < 0) { |
248 | fprintf (stderrstderr, "sshd ancestor not found\n"); |
249 | goto error; |
250 | } |
251 | if (strcmp (name, "sshd") == 0) { |
252 | GF_FREE (name)__gf_free (name); |
253 | break; |
254 | } |
255 | GF_FREE (name)__gf_free (name); |
256 | } |
257 | |
258 | pida[0] = pid; |
259 | ret = prociter (find_gsyncd, pida); |
260 | if (ret == -1 || pida[1] == -1) { |
261 | fprintf (stderrstderr, "gsyncd sibling not found\n"); |
262 | goto error; |
263 | } |
264 | |
265 | sprintf (path, PROC"/proc""/%d/cwd", pida[1]); |
266 | ret = readlink (path, buf, sizeof (buf)); |
267 | if (ret == -1 || ret == sizeof (buf)) |
268 | goto error; |
269 | if (strcmp (argv[argc - 1], "/") == 0 || |
270 | (strcmp (argv[argc - 1], path) && |
271 | strcmp (argv[argc - 1], buf) ) != 0) { |
272 | fprintf (stderrstderr, "rsync target does not match "GEOREP"geo-replication"" session\n"); |
273 | goto error; |
274 | } |
275 | |
276 | argv[0] = RSYNC"rsync"; |
277 | |
278 | execvp (RSYNC"rsync", argv); |
279 | |
280 | fprintf (stderrstderr, "exec of "RSYNC"rsync"" failed\n"); |
281 | return 127; |
282 | |
283 | error: |
284 | fprintf (stderrstderr, "disallowed "RSYNC"rsync"" invocation\n"); |
285 | return 1; |
286 | } |
287 | |
288 | |
289 | struct invocable { |
290 | char *name; |
291 | int (*invoker) (int argc, char **argv); |
292 | }; |
293 | |
294 | struct invocable invocables[] = { |
295 | { "rsync", invoke_rsync }, |
296 | { "gsyncd", invoke_gsyncd }, |
297 | { NULL((void*)0), NULL((void*)0)} |
298 | }; |
299 | |
300 | int |
301 | main (int argc, char **argv) |
302 | { |
303 | char *evas = NULL((void*)0); |
304 | struct invocable *i = NULL((void*)0); |
305 | char *b = NULL((void*)0); |
306 | char *sargv = NULL((void*)0); |
307 | |
308 | #ifdef USE_LIBGLUSTERFS1 |
309 | glusterfs_ctx_t *ctx = NULL((void*)0); |
310 | |
311 | ctx = glusterfs_ctx_new (); |
312 | if (!ctx) |
| 1 | Assuming 'ctx' is non-null | |
|
| |
313 | return ENOMEM12; |
314 | |
315 | if (glusterfs_globals_init (ctx)) |
| |
316 | return 1; |
317 | |
318 | THIS(*__glusterfs_this_location())->ctx = ctx; |
319 | #endif |
320 | |
321 | evas = getenv (_GLUSTERD_CALLED_"_GLUSTERD_CALLED_"); |
322 | if (evas && strcmp (evas, "1") == 0) |
323 | |
324 | |
325 | |
326 | unsetenv (_GLUSTERD_CALLED_"_GLUSTERD_CALLED_"); |
327 | else { |
328 | |
329 | |
330 | |
331 | |
332 | restricted = 1; |
333 | |
334 | if (!getenv (_GSYNCD_DISPATCHED_"_GSYNCD_DISPATCHED_")) { |
| |
335 | evas = getenv ("SSH_ORIGINAL_COMMAND"); |
336 | if (evas) |
| |
| |
337 | sargv = evas; |
338 | else { |
339 | evas = getenv ("SHELL"); |
340 | if (evas && strcmp (basename (evas), "gsyncd") == 0 && |
| |
341 | argc == 3 && strcmp (argv[1], "-c") == 0) |
| 7 | | Assuming 'argc' is equal to 3 | |
|
342 | sargv = argv[2]; |
343 | } |
344 | } |
345 | |
346 | } |
347 | |
348 | if (!(sargv && restricted)) |
| |
349 | return invoke_gsyncd (argc, argv); |
350 | |
351 | argc = str2argv (sargv, &argv); |
352 | if (argc == -1 || setenv (_GSYNCD_DISPATCHED_"_GSYNCD_DISPATCHED_", "1", 1) == -1) { |
| |
353 | fprintf (stderrstderr, "internal error\n"); |
354 | return 1; |
355 | } |
356 | |
357 | b = basename (argv[0]); |
| 11 | | Null pointer passed as an argument to a 'nonnull' parameter |
|
358 | for (i = invocables; i->name; i++) { |
359 | if (strcmp (b, i->name) == 0) |
360 | return i->invoker (argc, argv); |
361 | } |
362 | |
363 | fprintf (stderrstderr, "invoking %s in restricted SSH session is not allowed\n", |
364 | b); |
365 | |
366 | return 1; |
367 | } |