1 |
From: Russ Allbery <rra@stanford.edu> |
2 |
Subject: [PATCH] Handle the rsync v3 -e option for protocol information |
3 |
|
4 |
As of rsync 3, rsync reused the -e option to pass protocol information |
5 |
from the client to the server. We therefore cannot reject all -e |
6 |
options to rsync, only ones not sent with --server or containing |
7 |
something other than protocol information as an argument. |
8 |
|
9 |
Also scan the rsync command line for any --rsh option and reject it as |
10 |
well. This replaces and improves the upstream strategy for rejecting |
11 |
that command-line option, taking advantage of the parsing added to |
12 |
check the -e option. |
13 |
|
14 |
Based on work by Robert Hardy. |
15 |
|
16 |
Debian Bug#471803 |
17 |
|
18 |
Signed-off-by: Russ Allbery <rra@stanford.edu> |
19 |
|
20 |
--- |
21 |
util.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- |
22 |
1 file changed, 72 insertions(+), 8 deletions(-) |
23 |
|
24 |
diff --git a/util.c b/util.c |
25 |
index f98d2bc..a257b06 100644 |
26 |
--- a/util.c |
27 |
+++ b/util.c |
28 |
@@ -56,6 +56,7 @@ |
29 |
#ifdef HAVE_LIBGEN_H |
30 |
#include <libgen.h> |
31 |
#endif /* HAVE_LIBGEN_H */ |
32 |
+#include <regex.h> |
33 |
|
34 |
/* LOCAL INCLUDES */ |
35 |
#include "pathnames.h" |
36 |
@@ -198,6 +199,73 @@ bool check_command( char *cl, ShellOptions_t *opts, char *cmd, int cmdflag ) |
37 |
|
38 |
|
39 |
/* |
40 |
+ * rsync_e_okay() - take the command line passed to rssh and look for an -e |
41 |
+ * option. If one is found, make sure --server is provided |
42 |
+ * and the option contains only the protocol information. |
43 |
+ * Also check for and reject any --rsh option. Returns FALSE |
44 |
+ * if the command line should not be allowed, TRUE if it is |
45 |
+ * okay. |
46 |
+ */ |
47 |
+static int rsync_e_okay( char **vec ) |
48 |
+{ |
49 |
+ regex_t re; |
50 |
+ int server = FALSE; |
51 |
+ int e_found = FALSE; |
52 |
+ |
53 |
+ /* |
54 |
+ * rsync will send -e, followed by either just "." (meaning no special |
55 |
+ * protocol) or "N.N" (meaning a pre-release protocol version), |
56 |
+ * followed by some number of alphabetic flags indicating various |
57 |
+ * supported options. There may be other options between - and the e, |
58 |
+ * but -e will always be the last option in the string. A typical |
59 |
+ * option passed by the client is "-ltpre.iL". |
60 |
+ * |
61 |
+ * Note that if --server is given, this should never be parsed as a |
62 |
+ * shell, but we'll tightly verify it anyway, just in case. |
63 |
+ * |
64 |
+ * This regex matches the acceptable flags containing -e, so if it |
65 |
+ * does not match, the command line should be rejected. |
66 |
+ */ |
67 |
+ static const char pattern[] |
68 |
+ = "^-[a-df-zA-Z]*e[0-9]*\\.[0-9]*[a-zA-Z]*$"; |
69 |
+ |
70 |
+ /* |
71 |
+ * Only recognize --server if it's the first option. rsync itself |
72 |
+ * always passes it that way, and if it's not the first argument, it |
73 |
+ * could be hidden from the server as an argument to some other |
74 |
+ * option. |
75 |
+ */ |
76 |
+ if ( vec && vec[0] && vec[1] && strcmp(vec[1], "--server") == 0 ){ |
77 |
+ server = TRUE; |
78 |
+ } |
79 |
+ |
80 |
+ /* Check the remaining options for -e or --rsh. */ |
81 |
+ if ( regcomp(&re, pattern, REG_EXTENDED | REG_NOSUB) != 0 ){ |
82 |
+ return FALSE; |
83 |
+ } |
84 |
+ while (vec && *vec){ |
85 |
+ if ( strcmp(*vec, "--") == 0 ) break; |
86 |
+ if ( strcmp(*vec, "--rsh") == 0 |
87 |
+ || strncmp(*vec, "--rsh=", strlen("--rsh=")) == 0 ){ |
88 |
+ regfree(&re); |
89 |
+ return FALSE; |
90 |
+ } |
91 |
+ if ( strncmp(*vec, "--", 2) != 0 && opt_exist(*vec, 'e') ){ |
92 |
+ e_found = TRUE; |
93 |
+ if ( regexec(&re, *vec, 0, NULL, 0) != 0 ){ |
94 |
+ regfree(&re); |
95 |
+ return FALSE; |
96 |
+ } |
97 |
+ } |
98 |
+ vec++; |
99 |
+ } |
100 |
+ regfree(&re); |
101 |
+ if ( e_found && !server ) return FALSE; |
102 |
+ return TRUE; |
103 |
+} |
104 |
+ |
105 |
+ |
106 |
+/* |
107 |
* check_command_line() - take the command line passed to rssh, and verify |
108 |
* that the specified command is one the user is |
109 |
* allowed to run and validate the arguments. Return the |
110 |
@@ -230,14 +298,10 @@ char *check_command_line( char **cl, ShellOptions_t *opts ) |
111 |
|
112 |
if ( check_command(*cl, opts, PATH_RSYNC, RSSH_ALLOW_RSYNC) ){ |
113 |
/* filter -e option */ |
114 |
- if ( opt_filter(cl, 'e') ) return NULL; |
115 |
- while (cl && *cl){ |
116 |
- if ( strstr(*cl, "--rsh" ) ){ |
117 |
- fprintf(stderr, "\ninsecure --rsh= not allowed."); |
118 |
- log_msg("insecure --rsh option in rsync command line!"); |
119 |
- return NULL; |
120 |
- } |
121 |
- cl++; |
122 |
+ if ( !rsync_e_okay(cl) ){ |
123 |
+ fprintf(stderr, "\ninsecure -e or --rsh option not allowed."); |
124 |
+ log_msg("insecure -e or --rsh option in rsync command line!"); |
125 |
+ return NULL; |
126 |
} |
127 |
return PATH_RSYNC; |
128 |
} |
129 |
-- |
130 |
tg: (f8b36e2..) fixes/rsync-protocol (depends on: upstream) |