Code auditing weekend results and fixes committing.
[silc.git] / lib / silccore / silccommand.c
1 /*
2
3   silccommand.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1997 - 2000 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13   
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19 */
20 /* $Id$ */
21
22 #include "silcincludes.h"
23 #include "silccommand.h"
24
25 /******************************************************************************
26
27                               Command Payload
28
29 ******************************************************************************/
30
31 /* Command Payload structure. Contents of this structure is parsed
32    from SILC packets. */
33 struct SilcCommandPayloadStruct {
34   SilcCommand cmd;
35   unsigned short ident;
36   SilcArgumentPayload args;
37 };
38
39 /* Length of the command payload */
40 #define SILC_COMMAND_PAYLOAD_LEN 6
41
42 /* Parses command payload returning new command payload structure */
43
44 SilcCommandPayload silc_command_payload_parse(SilcBuffer buffer)
45 {
46   SilcCommandPayload new;
47   unsigned char args_num;
48   unsigned short payload_len;
49   int ret;
50
51   SILC_LOG_DEBUG(("Parsing command payload"));
52
53   new = silc_calloc(1, sizeof(*new));
54
55   /* Parse the Command Payload */
56   ret = silc_buffer_unformat(buffer, 
57                              SILC_STR_UI_SHORT(&payload_len),
58                              SILC_STR_UI_CHAR(&new->cmd),
59                              SILC_STR_UI_CHAR(&args_num),
60                              SILC_STR_UI_SHORT(&new->ident),
61                              SILC_STR_END);
62   if (ret == -1) {
63     silc_free(new);
64     return NULL;
65   }
66
67   if (payload_len != buffer->len) {
68     SILC_LOG_ERROR(("Incorrect command payload in packet, packet dropped"));
69     silc_free(new);
70     return NULL;
71   }
72
73   if (new->cmd == 0) {
74     silc_free(new);
75     return NULL;
76   }
77
78   silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN);
79   new->args = silc_argument_payload_parse(buffer, args_num);
80   if (!new->args) {
81     silc_free(new);
82     return NULL;
83   }
84   silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN);
85
86   return new;
87 }
88
89 /* Encodes Command Payload returning it to SilcBuffer. */
90
91 SilcBuffer silc_command_payload_encode(SilcCommand cmd,
92                                        unsigned int argc,
93                                        unsigned char **argv,
94                                        unsigned int *argv_lens,
95                                        unsigned int *argv_types,
96                                        unsigned short ident)
97 {
98   SilcBuffer buffer;
99   SilcBuffer args = NULL;
100   unsigned int len = 0;
101
102   SILC_LOG_DEBUG(("Encoding command payload"));
103
104   if (argc) {
105     args = silc_argument_payload_encode(argc, argv, argv_lens, argv_types);
106     len = args->len;
107   }
108
109   len += SILC_COMMAND_PAYLOAD_LEN;
110   buffer = silc_buffer_alloc(len);
111   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
112
113   /* Create Command payload */
114   silc_buffer_format(buffer,
115                      SILC_STR_UI_SHORT(len),
116                      SILC_STR_UI_CHAR(cmd),
117                      SILC_STR_UI_CHAR(argc),
118                      SILC_STR_UI_SHORT(ident),
119                      SILC_STR_END);
120
121   /* Add arguments */
122   if (argc) {
123     silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN);
124     silc_buffer_format(buffer,
125                        SILC_STR_UI_XNSTRING(args->data, args->len),
126                        SILC_STR_END);
127     silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN);
128     silc_free(args);
129   }
130
131   return buffer;
132 }
133
134 /* Same as above but encode the buffer from SilcCommandPayload structure
135    instead of raw data. */
136
137 SilcBuffer silc_command_payload_encode_payload(SilcCommandPayload payload)
138 {
139   SilcBuffer buffer;
140   SilcBuffer args = NULL;
141   unsigned int len = 0;
142   unsigned int argc = 0;
143
144   SILC_LOG_DEBUG(("Encoding command payload"));
145
146   if (payload->args) {
147     args = silc_argument_payload_encode_payload(payload->args);
148     len = args->len;
149     argc = silc_argument_get_arg_num(payload->args);
150   }
151
152   len += SILC_COMMAND_PAYLOAD_LEN;
153   buffer = silc_buffer_alloc(len);
154   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
155
156   /* Create Command payload */
157   silc_buffer_format(buffer,
158                      SILC_STR_UI_SHORT(len),
159                      SILC_STR_UI_CHAR(payload->cmd),
160                      SILC_STR_UI_CHAR(argc),
161                      SILC_STR_UI_SHORT(payload->ident),
162                      SILC_STR_END);
163
164   /* Add arguments */
165   if (args) {
166     silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN);
167     silc_buffer_format(buffer,
168                        SILC_STR_UI_XNSTRING(args->data, args->len),
169                        SILC_STR_END);
170     silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN);
171     silc_free(args);
172   }
173
174   return buffer;
175 }
176
177 /* Encodes Command payload with variable argument list. The arguments
178    must be: unsigned int, unsigned char *, unsigned int, ... One 
179    {unsigned int, unsigned char * and unsigned int} forms one argument, 
180    thus `argc' in case when sending one {unsigned int, unsigned char * 
181    and unsigned int} equals one (1) and when sending two of those it
182    equals two (2), and so on. This has to be preserved or bad things
183    will happen. The variable arguments is: {type, data, data_len}. */
184
185 SilcBuffer silc_command_payload_encode_va(SilcCommand cmd, 
186                                           unsigned short ident, 
187                                           unsigned int argc, ...)
188 {
189   va_list ap;
190   unsigned char **argv;
191   unsigned int *argv_lens = NULL, *argv_types = NULL;
192   unsigned char *x;
193   unsigned int x_len;
194   unsigned int x_type;
195   SilcBuffer buffer;
196   int i;
197
198   va_start(ap, argc);
199
200   argv = silc_calloc(argc, sizeof(unsigned char *));
201   argv_lens = silc_calloc(argc, sizeof(unsigned int));
202   argv_types = silc_calloc(argc, sizeof(unsigned int));
203
204   for (i = 0; i < argc; i++) {
205     x_type = va_arg(ap, unsigned int);
206     x = va_arg(ap, unsigned char *);
207     x_len = va_arg(ap, unsigned int);
208
209     argv[i] = silc_calloc(x_len + 1, sizeof(unsigned char));
210     memcpy(argv[i], x, x_len);
211     argv_lens[i] = x_len;
212     argv_types[i] = x_type;
213   }
214
215   buffer = silc_command_payload_encode(cmd, argc, argv, 
216                                        argv_lens, argv_types, ident);
217
218   for (i = 0; i < argc; i++)
219     silc_free(argv[i]);
220   silc_free(argv);
221   silc_free(argv_lens);
222   silc_free(argv_types);
223
224   return buffer;
225 }
226
227 /* Same as above but with va_list. */
228
229 SilcBuffer silc_command_payload_encode_vap(SilcCommand cmd, 
230                                            unsigned short ident, 
231                                            unsigned int argc, va_list ap)
232 {
233   unsigned char **argv;
234   unsigned int *argv_lens = NULL, *argv_types = NULL;
235   unsigned char *x;
236   unsigned int x_len;
237   unsigned int x_type;
238   SilcBuffer buffer;
239   int i;
240
241   argv = silc_calloc(argc, sizeof(unsigned char *));
242   argv_lens = silc_calloc(argc, sizeof(unsigned int));
243   argv_types = silc_calloc(argc, sizeof(unsigned int));
244
245   for (i = 0; i < argc; i++) {
246     x_type = va_arg(ap, unsigned int);
247     x = va_arg(ap, unsigned char *);
248     x_len = va_arg(ap, unsigned int);
249
250     argv[i] = silc_calloc(x_len + 1, sizeof(unsigned char));
251     memcpy(argv[i], x, x_len);
252     argv_lens[i] = x_len;
253     argv_types[i] = x_type;
254   }
255
256   buffer = silc_command_payload_encode(cmd, argc, argv, 
257                                        argv_lens, argv_types, ident);
258
259   for (i = 0; i < argc; i++)
260     silc_free(argv[i]);
261   silc_free(argv);
262   silc_free(argv_lens);
263   silc_free(argv_types);
264
265   return buffer;
266 }
267
268 /* Same as above except that this is used to encode strictly command
269    reply packets. The command status message to be returned is sent as
270    extra argument to this function. The `argc' must not count `status'
271    as on argument. */
272
273 SilcBuffer 
274 silc_command_reply_payload_encode_va(SilcCommand cmd, 
275                                      SilcCommandStatus status,
276                                      unsigned short ident,
277                                      unsigned int argc, ...)
278 {
279   va_list ap;
280   unsigned char **argv;
281   unsigned int *argv_lens = NULL, *argv_types = NULL;
282   unsigned char status_data[2];
283   unsigned char *x;
284   unsigned int x_len;
285   unsigned int x_type;
286   SilcBuffer buffer;
287   int i;
288
289   va_start(ap, argc);
290
291   argc++;
292   argv = silc_calloc(argc, sizeof(unsigned char *));
293   argv_lens = silc_calloc(argc, sizeof(unsigned int));
294   argv_types = silc_calloc(argc, sizeof(unsigned int));
295
296   SILC_PUT16_MSB(status, status_data);
297   argv[0] = silc_calloc(sizeof(status_data) + 1, sizeof(unsigned char));
298   memcpy(argv[0], status_data, sizeof(status_data));
299   argv_lens[0] = sizeof(status_data);
300   argv_types[0] = 1;
301
302   for (i = 1; i < argc; i++) {
303     x_type = va_arg(ap, unsigned int);
304     x = va_arg(ap, unsigned char *);
305     x_len = va_arg(ap, unsigned int);
306
307     argv[i] = silc_calloc(x_len + 1, sizeof(unsigned char));
308     memcpy(argv[i], x, x_len);
309     argv_lens[i] = x_len;
310     argv_types[i] = x_type;
311   }
312
313   buffer = silc_command_payload_encode(cmd, argc, argv, 
314                                        argv_lens, argv_types, ident);
315
316   for (i = 0; i < argc; i++)
317     silc_free(argv[i]);
318   silc_free(argv);
319   silc_free(argv_lens);
320   silc_free(argv_types);
321
322   return buffer;
323 }
324
325 /* Free's Command Payload */
326
327 void silc_command_free_payload(SilcCommandPayload payload)
328 {
329   if (payload) {
330     silc_argument_payload_free(payload->args);
331     silc_free(payload);
332   }
333 }
334
335 /* Returns command */
336
337 SilcCommand silc_command_get(SilcCommandPayload payload)
338 {
339   return payload->cmd;
340 }
341
342 /* Retuns arguments payload */
343
344 SilcArgumentPayload silc_command_get_args(SilcCommandPayload payload)
345 {
346   return payload->args;
347 }
348
349 /* Returns identifier */
350
351 unsigned short silc_command_get_ident(SilcCommandPayload payload)
352 {
353   return payload->ident;
354 }
355
356 /* Function to set identifier to already allocated Command Payload. Command
357    payloads are frequentlly resent in SILC and thusly this makes it easy
358    to set the identifier. */
359
360 void silc_command_set_ident(SilcCommandPayload payload, unsigned short ident)
361 {
362   payload->ident = ident;
363 }
364
365 /* Function to set the command to already allocated Command Payload. */
366
367 void silc_command_set_command(SilcCommandPayload payload, SilcCommand command)
368 {
369   payload->cmd = command;
370 }