Browse code

Reject new commands sent as new-style commands to avoid confusion. This means that IDSESSION/INSTREAM must be sent as nIDSESSION\n or zIDSESSION\0, ditto for INSTREAM. Adjust testcases accordingly. Old commands are still accepted when sent without delimiter.

git-svn: trunk@4811

Török Edvin authored on 2009/02/18 03:04:48
Showing 5 changed files
... ...
@@ -1,3 +1,12 @@
1
+Tue Feb 17 20:35:21 EET 2009 (edwin)
2
+------------------------------------
3
+ * clamd/server-th.c, clamd/session.c, clamd/session.h,
4
+ unit_tests/check_clamd.c: Reject new commands sent as new-style
5
+ commands to avoid confusion.  This means that IDSESSION/INSTREAM
6
+ must be sent as nIDSESSION\n or zIDSESSION\0, ditto for INSTREAM.
7
+ Adjust testcases accordingly.  Old commands are still accepted when
8
+ sent without delimiter.
9
+
1 10
 Tue Feb 17 20:06:02 EET 2009 (edwin)
2 11
 ------------------------------------
3 12
  * clamd/others.c, libclamunrar_iface/unrar_iface.h, shared/misc.c,
... ...
@@ -243,7 +243,7 @@ static struct cl_engine *reload_db(struct cl_engine *engine, unsigned int dbopti
243 243
  * Old-style non-prefixed commands are one packet, optionally delimited by \n,
244 244
  * with trailing \r|\n ignored
245 245
  */
246
-static const char *get_cmd(struct fd_buf *buf, size_t off, size_t *len, char *term)
246
+static const char *get_cmd(struct fd_buf *buf, size_t off, size_t *len, char *term, int *oldstyle)
247 247
 {
248 248
     unsigned char *pos;
249 249
     if (!buf->off || off >= buf->off) {
... ...
@@ -269,6 +269,7 @@ static const char *get_cmd(struct fd_buf *buf, size_t off, size_t *len, char *te
269 269
 	    } else {
270 270
 		*len = pos - buf->buffer - off;
271 271
 	    }
272
+	    *oldstyle = 0;
272 273
 	    return buf->buffer + off + 1;
273 274
 	default:
274 275
 	    /* one packet = one command */
... ...
@@ -283,6 +284,7 @@ static const char *get_cmd(struct fd_buf *buf, size_t off, size_t *len, char *te
283 283
 		buf->buffer[buf->off] = '\0';
284 284
 	    }
285 285
 	    cli_chomp(buf->buffer);
286
+	    *oldstyle = 1;
286 287
 	    return buf->buffer;
287 288
     }
288 289
 }
... ...
@@ -876,6 +878,7 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi
876 876
 		const unsigned char *cmd = NULL;
877 877
 		size_t cmdlen = 0;
878 878
 		char term = '\n';
879
+		int oldstyle = 0;
879 880
 		int rc;
880 881
 		/* New data available to read on socket. */
881 882
 
... ...
@@ -895,9 +898,16 @@ int recvloop_th(int *socketds, unsigned nsockets, struct cl_engine *engine, unsi
895 895
 		conn.term = buf->term;
896 896
 		/* Parse & dispatch commands */
897 897
 		while ((conn.mode == MODE_COMMAND) &&
898
-		       (cmd = get_cmd(buf, pos, &cmdlen, &term)) != NULL) {
898
+		       (cmd = get_cmd(buf, pos, &cmdlen, &term, &oldstyle)) != NULL) {
899 899
 		    const char *argument;
900
-		    enum commands cmdtype = parse_command(cmd, &argument);
900
+		    enum commands cmdtype;
901
+		    if (conn.group && oldstyle) {
902
+			logg("$Received oldstyle command inside IDSESSION: %s\n", cmd);
903
+			conn_reply_error(&conn, "Only nCMDS\\n and zCMDS\\0 are accepted inside IDSESSION.");
904
+			error = 1;
905
+			break;
906
+		    }
907
+		    cmdtype = parse_command(cmd, &argument, oldstyle);
901 908
 		    logg("$got command %s (%u, %u), argument: %s\n",
902 909
 			 cmd, (unsigned)cmdlen, (unsigned)cmdtype, argument ? argument : "");
903 910
 		    if (cmdtype == COMMAND_FILDES) {
... ...
@@ -70,25 +70,26 @@ static struct {
70 70
     const size_t len;
71 71
     enum commands cmdtype;
72 72
     int need_arg;
73
+    int support_old;
73 74
 } commands[] = {
74
-    {CMD1,  sizeof(CMD1)-1,	COMMAND_SCAN,	    1},
75
-    {CMD3,  sizeof(CMD3)-1,	COMMAND_SHUTDOWN,   0},
76
-    {CMD4,  sizeof(CMD4)-1,	COMMAND_RELOAD,	    0},
77
-    {CMD5,  sizeof(CMD5)-1,	COMMAND_PING,	    0},
78
-    {CMD6,  sizeof(CMD6)-1,	COMMAND_CONTSCAN,   1},
79
-    {CMD7,  sizeof(CMD7)-1,	COMMAND_VERSION,    0},
80
-    {CMD8,  sizeof(CMD8)-1,	COMMAND_STREAM,	    0},
81
-    {CMD10, sizeof(CMD10)-1,	COMMAND_END,	    0},
82
-    {CMD11, sizeof(CMD11)-1,	COMMAND_SHUTDOWN,   0},
83
-    {CMD13, sizeof(CMD13)-1,	COMMAND_MULTISCAN,  1},
84
-    {CMD14, sizeof(CMD14)-1,	COMMAND_FILDES,	    0},
85
-    {CMD15, sizeof(CMD15)-1,	COMMAND_STATS,	    0},
86
-    {CMD16, sizeof(CMD16)-1,	COMMAND_IDSESSION,  0},
87
-    {CMD17, sizeof(CMD17)-1,	COMMAND_INSTREAM,   0}
75
+    {CMD1,  sizeof(CMD1)-1,	COMMAND_SCAN,	    1,	1},
76
+    {CMD3,  sizeof(CMD3)-1,	COMMAND_SHUTDOWN,   0,	1},
77
+    {CMD4,  sizeof(CMD4)-1,	COMMAND_RELOAD,	    0,	1},
78
+    {CMD5,  sizeof(CMD5)-1,	COMMAND_PING,	    0,	1},
79
+    {CMD6,  sizeof(CMD6)-1,	COMMAND_CONTSCAN,   1,	1},
80
+    {CMD7,  sizeof(CMD7)-1,	COMMAND_VERSION,    0,	1},
81
+    {CMD8,  sizeof(CMD8)-1,	COMMAND_STREAM,	    0,	1},
82
+    {CMD10, sizeof(CMD10)-1,	COMMAND_END,	    0,	0},
83
+    {CMD11, sizeof(CMD11)-1,	COMMAND_SHUTDOWN,   0,	1},
84
+    {CMD13, sizeof(CMD13)-1,	COMMAND_MULTISCAN,  1,	1},
85
+    {CMD14, sizeof(CMD14)-1,	COMMAND_FILDES,	    0,	1},
86
+    {CMD15, sizeof(CMD15)-1,	COMMAND_STATS,	    0,	0},
87
+    {CMD16, sizeof(CMD16)-1,	COMMAND_IDSESSION,  0,	0},
88
+    {CMD17, sizeof(CMD17)-1,	COMMAND_INSTREAM,   0,	0}
88 89
 };
89 90
 
90 91
 
91
-enum commands parse_command(const char *cmd, const char **argument)
92
+enum commands parse_command(const char *cmd, const char **argument, int oldstyle)
92 93
 {
93 94
     size_t i;
94 95
     *argument = NULL;
... ...
@@ -109,6 +110,10 @@ enum commands parse_command(const char *cmd, const char **argument)
109 109
 		}
110 110
 		*argument = NULL;
111 111
 	    }
112
+	    if (oldstyle && !commands[i].support_old) {
113
+		logg("$Command sent as old-style when not supported: %s\n", commands[i].cmd);
114
+		return COMMAND_UNKNOWN;
115
+	    }
112 116
 	    return commands[i].cmdtype;
113 117
 	}
114 118
     }
... ...
@@ -85,7 +85,7 @@ typedef struct client_conn_tag {
85 85
 } client_conn_t;
86 86
 
87 87
 int command(client_conn_t *conn, int *virus);
88
-enum commands parse_command(const char *cmd, const char **argument);
88
+enum commands parse_command(const char *cmd, const char **argument, int oldstyle);
89 89
 int execute_or_dispatch_command(client_conn_t *conn, enum commands command, const char *argument);
90 90
 
91 91
 int conn_reply(const client_conn_t *conn, const char *path, const char *msg, const char *status);
... ...
@@ -124,35 +124,36 @@ static struct basic_test {
124 124
     const char *command;
125 125
     const char *extra;
126 126
     const char *reply;
127
+    int support_old;
127 128
 } basic_tests[] = {
128
-    {"PING", NULL, "PONG"},
129
-    {"RELOAD", NULL, "RELOADING"},
130
-    {"VERSION", NULL, VERSION_REPLY},
131
-    {"SCAN "SCANFILE, NULL, FOUNDREPLY},
132
-    {"SCAN "CLEANFILE, NULL, CLEANREPLY},
133
-    {"CONTSCAN "SCANFILE, NULL, FOUNDREPLY},
134
-    {"CONTSCAN "CLEANFILE, NULL, CLEANREPLY},
135
-    {"MULTISCAN "SCANFILE, NULL, FOUNDREPLY},
136
-    {"MULTISCAN "CLEANFILE, NULL, CLEANREPLY},
129
+    {"PING", NULL, "PONG", 1},
130
+    {"RELOAD", NULL, "RELOADING", 1},
131
+    {"VERSION", NULL, VERSION_REPLY, 1},
132
+    {"SCAN "SCANFILE, NULL, FOUNDREPLY, 1},
133
+    {"SCAN "CLEANFILE, NULL, CLEANREPLY, 1},
134
+    {"CONTSCAN "SCANFILE, NULL, FOUNDREPLY, 1},
135
+    {"CONTSCAN "CLEANFILE, NULL, CLEANREPLY, 1},
136
+    {"MULTISCAN "SCANFILE, NULL, FOUNDREPLY, 1},
137
+    {"MULTISCAN "CLEANFILE, NULL, CLEANREPLY, 1},
137 138
     /* unknown commnads */
138
-    {"RANDOM", NULL, UNKNOWN_REPLY},
139
+    {"RANDOM", NULL, UNKNOWN_REPLY, 1},
139 140
     /* commands invalid as first */
140
-    {"END", NULL, UNKNOWN_REPLY},
141
+    {"END", NULL, UNKNOWN_REPLY, 1},
141 142
     /* commands for nonexistent files */
142
-    {"SCAN "NONEXISTENT, NULL, NONEXISTENT_REPLY},
143
-    {"CONTSCAN "NONEXISTENT, NULL, NONEXISTENT_REPLY},
144
-    {"MULTISCAN "NONEXISTENT, NULL, NONEXISTENT_REPLY},
143
+    {"SCAN "NONEXISTENT, NULL, NONEXISTENT_REPLY, 1},
144
+    {"CONTSCAN "NONEXISTENT, NULL, NONEXISTENT_REPLY, 1},
145
+    {"MULTISCAN "NONEXISTENT, NULL, NONEXISTENT_REPLY, 1},
145 146
     /* commands for access denied files */
146
-    {"SCAN "ACCDENIED, NULL, ACCDENIED_REPLY},
147
-    {"CONTSCAN "ACCDENIED, NULL, ACCDENIED_REPLY},
148
-    {"MULTISCAN "ACCDENIED, NULL, ACCDENIED_REPLY},
147
+    {"SCAN "ACCDENIED, NULL, ACCDENIED_REPLY, 1},
148
+    {"CONTSCAN "ACCDENIED, NULL, ACCDENIED_REPLY, 1},
149
+    {"MULTISCAN "ACCDENIED, NULL, ACCDENIED_REPLY, 1},
149 150
     /* commands with invalid/missing arguments */
150
-    {"SCAN", NULL, UNKNOWN_REPLY},
151
-    {"CONTSCAN", NULL, UNKNOWN_REPLY},
152
-    {"MULTISCAN", NULL, UNKNOWN_REPLY},
151
+    {"SCAN", NULL, UNKNOWN_REPLY, 1},
152
+    {"CONTSCAN", NULL, UNKNOWN_REPLY, 1},
153
+    {"MULTISCAN", NULL, UNKNOWN_REPLY, 1},
153 154
     /* commands with invalid data */
154
-    {"INSTREAM", "\xff\xff\xff\xff", "INSTREAM size limit exceeded. ERROR"}, /* too big chunksize */
155
-    {"FILDES", "X", "No file descriptor received. ERROR"}, /* FILDES w/o ancillary data */
155
+    {"INSTREAM", "\xff\xff\xff\xff", "INSTREAM size limit exceeded. ERROR", 0}, /* too big chunksize */
156
+    {"FILDES", "X", "No file descriptor received. ERROR", 1}, /* FILDES w/o ancillary data */
156 157
 };
157 158
 
158 159
 static void *recvpartial(int sd, size_t *len, int partial)
... ...
@@ -231,9 +232,13 @@ START_TEST (test_compat_commands)
231 231
     struct basic_test *test = &basic_tests[_i];
232 232
     char nsend[BUFSIZ], nreply[BUFSIZ];
233 233
 
234
-    snprintf(nreply, sizeof(nreply), "%s\n", test->reply);
234
+    if (!test->support_old) {
235
+	snprintf(nreply, sizeof(nreply), "UNKNOWN COMMAND\n");
236
+    } else {
237
+	snprintf(nreply, sizeof(nreply), "%s\n", test->reply);
238
+    }
239
+    /* one command = one packet, no delimiter */
235 240
     if (!test->extra) {
236
-	/* one command = one packet, no delimiter */
237 241
 	conn_setup();
238 242
 	test_command(test->command, strlen(test->command), test->extra, nreply, strlen(nreply));
239 243
 	conn_teardown();