1 /*
2
3 silcargument.c
4
5 Author: Pekka Riikonen <priikone@silcnet.org>
6
7 Copyright (C) 2001 - 2007 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; version 2 of the License.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 */
19 /* Implementation of Argument Payload routines */
20 /* $Id: silcargument.c,v 1.19 2007/07/01 16:42:02 priikone Exp $ */
21
22 #include "silc.h"
23 #include "silcargument.h"
24
25 /*************************** Argument Payload *******************************/
26
27 struct SilcArgumentPayloadStruct {
28 SilcUInt32 argc;
29 unsigned char **argv;
30 SilcUInt32 *argv_lens;
31 SilcUInt32 *argv_types;
32 SilcUInt32 pos;
33 };
34
35 /* Parses arguments and returns them into Argument Payload structure. */
36
37 SilcArgumentPayload silc_argument_payload_parse(const unsigned char *payload,
38 SilcUInt32 payload_len,
39 SilcUInt32 argc)
40 {
41 SilcBufferStruct buffer;
42 SilcArgumentPayload newp;
43 SilcUInt16 p_len = 0;
44 unsigned char arg_num = 0;
45 unsigned char arg_type = 0;
46 SilcUInt32 pull_len = 0;
47 int i = 0, ret;
48
49 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
50 newp = silc_calloc(1, sizeof(*newp));
51 if (!newp)
52 return NULL;
53 newp->argv = silc_calloc(argc, sizeof(unsigned char *));
54 if (!newp->argv)
55 goto err;
56 newp->argv_lens = silc_calloc(argc, sizeof(SilcUInt32));
57 if (!newp->argv_lens)
58 goto err;
59 newp->argv_types = silc_calloc(argc, sizeof(SilcUInt32));
60 if (!newp->argv_types)
61 goto err;
62
63 /* Get arguments */
64 arg_num = 1;
65 for (i = 0; i < argc; i++) {
66 ret = silc_buffer_unformat(&buffer,
67 SILC_STR_UI_SHORT(&p_len),
68 SILC_STR_UI_CHAR(&arg_type),
69 SILC_STR_END);
70 if (ret == -1 || p_len > silc_buffer_len(&buffer) - 3) {
71 SILC_LOG_DEBUG(("Malformed argument payload"));
72 goto err;
73 }
74
75 newp->argv_lens[i] = p_len;
76 newp->argv_types[i] = arg_type;
77
78 /* Get argument data */
79 silc_buffer_pull(&buffer, 3);
80 ret = silc_buffer_unformat(&buffer,
81 SILC_STR_UI_XNSTRING_ALLOC(&newp->argv[i],
82 p_len),
83 SILC_STR_END);
84 if (ret == -1) {
85 SILC_LOG_DEBUG(("Malformed argument payload"));
86 goto err;
87 }
88
89 silc_buffer_pull(&buffer, p_len);
90 pull_len += 3 + p_len;
91 }
92
93 if (silc_buffer_len(&buffer) != 0) {
94 SILC_LOG_DEBUG(("Malformed argument payload"));
95 goto err;
96 }
97
98 newp->argc = argc;
99 newp->pos = 0;
100
101 silc_buffer_push(&buffer, pull_len);
102
103 return newp;
104
105 err:
106 SILC_LOG_DEBUG(("Error parsing argument payload"));
107 if (i)
108 for (ret = 0; ret < i; ret++)
109 silc_free(newp->argv[ret]);
110
111 silc_free(newp->argv);
112 silc_free(newp->argv_lens);
113 silc_free(newp->argv_types);
114 silc_free(newp);
115
116 return NULL;
117 }
118
119 /* Encodes arguments in to Argument Paylods returning them to SilcBuffer. */
120
121 SilcBuffer silc_argument_payload_encode(SilcUInt32 argc,
122 unsigned char **argv,
123 SilcUInt32 *argv_lens,
124 SilcUInt32 *argv_types)
125 {
126 SilcBuffer buffer;
127 SilcUInt32 len;
128 int i;
129
130 len = 0;
131 for (i = 0; i < argc; i++)
132 len += 3 + (SilcUInt16)argv_lens[i];
133
134 buffer = silc_buffer_alloc_size(len);
135 if (!buffer)
136 return NULL;
137
138 /* Put arguments */
139 for (i = 0; i < argc; i++) {
140 silc_buffer_format(buffer,
141 SILC_STR_UI_SHORT(argv_lens[i]),
142 SILC_STR_UI_CHAR(argv_types[i]),
143 SILC_STR_UI_XNSTRING(argv[i], (SilcUInt16)argv_lens[i]),
144 SILC_STR_END);
145 silc_buffer_pull(buffer, 3 + (SilcUInt16)argv_lens[i]);
146 }
147
148 silc_buffer_push(buffer, len);
149
150 return buffer;
151 }
152
153 /* Encode one argument to buffer */
154
155 SilcBuffer silc_argument_payload_encode_one(SilcBuffer args,
156 unsigned char *arg,
157 SilcUInt32 arg_len,
158 SilcUInt32 arg_type)
159 {
160 SilcBuffer buffer = args;
161 SilcUInt32 len;
162
163 len = 3 + (SilcUInt16)arg_len;
164 buffer = silc_buffer_realloc(buffer,
165 (buffer ? silc_buffer_truelen(buffer) +
166 len : len));
167 if (!buffer)
168 return NULL;
169 silc_buffer_pull(buffer, silc_buffer_len(buffer));
170 silc_buffer_pull_tail(buffer, len);
171 silc_buffer_format(buffer,
172 SILC_STR_UI_SHORT(arg_len),
173 SILC_STR_UI_CHAR(arg_type),
174 SILC_STR_UI_XNSTRING(arg, (SilcUInt16)arg_len),
175 SILC_STR_END);
176 silc_buffer_push(buffer, buffer->data - buffer->head);
177
178 return buffer;
179 }
180
181 /* Same as above but encode the buffer from SilcArgumentPayload structure
182 instead of raw data. */
183
184 SilcBuffer silc_argument_payload_encode_payload(SilcArgumentPayload payload)
185 {
186 SilcBuffer buffer;
187 SilcUInt32 len;
188 int i;
189
190 len = 0;
191 for (i = 0; i < payload->argc; i++)
192 len += 3 + payload->argv_lens[i];
193
194 buffer = silc_buffer_alloc_size(len);
195 if (!buffer)
196 return NULL;
197
198 /* Put arguments */
199 for (i = 0; i < payload->argc; i++) {
200 silc_buffer_format(buffer,
201 SILC_STR_UI_SHORT(payload->argv_lens[i]),
202 SILC_STR_UI_CHAR(payload->argv_types[i]),
203 SILC_STR_UI_XNSTRING(payload->argv[i],
204 payload->argv_lens[i]),
205 SILC_STR_END);
206 silc_buffer_pull(buffer, 3 + payload->argv_lens[i]);
207 }
208
209 silc_buffer_push(buffer, len);
210
211 return buffer;
212 }
213
214 /* Frees Argument Payload */
215
216 void silc_argument_payload_free(SilcArgumentPayload payload)
217 {
218 int i;
219
220 if (payload) {
221 for (i = 0; i < payload->argc; i++)
222 silc_free(payload->argv[i]);
223
224 silc_free(payload->argv);
225 silc_free(payload->argv_lens);
226 silc_free(payload->argv_types);
227 silc_free(payload);
228 }
229 }
230
231 /* Returns number of arguments in payload */
232
233 SilcUInt32 silc_argument_get_arg_num(SilcArgumentPayload payload)
234 {
235 return payload ? payload->argc : 0;
236 }
237
238 /* Returns first argument from payload. */
239
240 unsigned char *silc_argument_get_first_arg(SilcArgumentPayload payload,
241 SilcUInt32 *type,
242 SilcUInt32 *ret_len)
243 {
244 if (!payload)
245 return NULL;
246
247 payload->pos = 0;
248
249 if (type)
250 *type = payload->argv_types[payload->pos];
251 if (ret_len)
252 *ret_len = payload->argv_lens[payload->pos];
253
254 return payload->argv[payload->pos++];
255 }
256
257 /* Returns next argument from payload or NULL if no more arguments. */
258
259 unsigned char *silc_argument_get_next_arg(SilcArgumentPayload payload,
260 SilcUInt32 *type,
261 SilcUInt32 *ret_len)
262 {
263 if (!payload)
264 return NULL;
265
266 if (payload->pos >= payload->argc)
267 return NULL;
268
269 if (type)
270 *type = payload->argv_types[payload->pos];
271 if (ret_len)
272 *ret_len = payload->argv_lens[payload->pos];
273
274 return payload->argv[payload->pos++];
275 }
276
277 /* Returns argument which type is `type'. */
278
279 unsigned char *silc_argument_get_arg_type(SilcArgumentPayload payload,
280 SilcUInt32 type,
281 SilcUInt32 *ret_len)
282 {
283 int i;
284
285 if (!payload)
286 return NULL;
287
288 for (i = 0; i < payload->argc; i++)
289 if (payload->argv_types[i] == type)
290 break;
291
292 if (i >= payload->argc)
293 return NULL;
294
295 if (ret_len)
296 *ret_len = payload->argv_lens[i];
297
298 return payload->argv[i];
299 }
300
301 /* Return argument already decoded */
302
303 static SilcBool silc_argument_decode(unsigned char *data,
304 SilcUInt32 data_len,
305 SilcArgumentDecodeType dec_type,
306 void *ret_arg,
307 void **ret_arg_alloc)
308 {
309 switch (dec_type) {
310
311 case SILC_ARGUMENT_ID:
312 if (ret_arg)
313 if (!silc_id_payload_parse_id(data, data_len, (SilcID *)ret_arg))
314 return FALSE;
315
316 if (ret_arg_alloc) {
317 SilcID id;
318 if (!silc_id_payload_parse_id(data, data_len, &id))
319 return FALSE;
320 *ret_arg_alloc = silc_memdup(&id, sizeof(id));
321 }
322 break;
323
324 case SILC_ARGUMENT_PUBLIC_KEY:
325 {
326 SilcPublicKey public_key;
327
328 if (!ret_arg_alloc)
329 return FALSE;
330
331 if (!silc_public_key_payload_decode(data, data_len, &public_key))
332 return FALSE;
333
334 *ret_arg_alloc = public_key;
335 }
336 break;
337
338 case SILC_ARGUMENT_ATTRIBUTES:
339 if (!ret_arg_alloc)
340 return FALSE;
341
342 *ret_arg_alloc = silc_attribute_payload_parse(data, data_len);
343 break;
344
345 case SILC_ARGUMENT_UINT32:
346 if (data_len != 4)
347 return FALSE;
348
349 if (ret_arg) {
350 SilcUInt32 *i = ret_arg;
351 SILC_GET32_MSB(*i, data);
352 }
353
354 if (ret_arg_alloc) {
355 SilcUInt32 i;
356 SILC_GET32_MSB(i, data);
357 *ret_arg_alloc = silc_memdup(&i, sizeof(i));
358 }
359 break;
360
361 case SILC_ARGUMENT_BOOL:
362 if (data_len != sizeof(SilcBool))
363 return FALSE;
364
365 if (ret_arg) {
366 SilcBool *b = ret_arg;
367 *b = (data[0] == 0x01 ? TRUE : FALSE);
368 }
369
370 if (ret_arg_alloc) {
371 SilcBool b;
372 b = (data[0] == 0x01 ? TRUE : FALSE);
373 *ret_arg_alloc = silc_memdup(&b, sizeof(b));
374 }
375 break;
376
377 default:
378 return FALSE;
379 }
380
381 return TRUE;
382 }
383
384 /* Return argument already decoded */
385
386 SilcBool silc_argument_get_decoded(SilcArgumentPayload payload,
387 SilcUInt32 type,
388 SilcArgumentDecodeType dec_type,
389 void *ret_arg,
390 void **ret_arg_alloc)
391 {
392 unsigned char *tmp;
393 SilcUInt32 tmp_len;
394
395 tmp = silc_argument_get_arg_type(payload, type, &tmp_len);
396 if (!tmp)
397 return FALSE;
398
399 return silc_argument_decode(tmp, tmp_len, dec_type, ret_arg, ret_arg_alloc);
400 }
401
402 /************************* Argument List Payload ****************************/
403
404 /* Parses argument payload list */
405
406 SilcArgumentPayload
407 silc_argument_list_parse(const unsigned char *payload,
408 SilcUInt32 payload_len)
409 {
410 SilcArgumentPayload arg;
411 SilcUInt16 argc;
412
413 if (payload_len < 5)
414 return NULL;
415
416 SILC_GET16_MSB(argc, payload);
417
418 arg = silc_argument_payload_parse(payload + 2, payload_len - 2, argc);
419
420 return arg;
421 }
422
423 /* Parses argument payload list of specific argument types */
424
425 SilcDList
426 silc_argument_list_parse_decoded(const unsigned char *payload,
427 SilcUInt32 payload_len,
428 SilcArgumentDecodeType dec_type)
429 {
430 SilcArgumentPayload arg;
431 SilcArgumentDecodedList dec;
432 unsigned char *data;
433 SilcUInt32 data_len, type;
434 SilcDList list;
435
436 arg = silc_argument_list_parse(payload, payload_len);
437 if (!arg)
438 return NULL;
439
440 list = silc_dlist_init();
441 if (!list) {
442 silc_argument_payload_free(arg);
443 return NULL;
444 }
445
446 data = silc_argument_get_first_arg(arg, &type, &data_len);
447 while (data) {
448 dec = silc_calloc(1, sizeof(*dec));
449 if (!dec)
450 continue;
451 dec->arg_type = type;
452 if (silc_argument_decode(data, data_len, dec_type, NULL, &dec->argument))
453 silc_dlist_add(list, dec);
454 else
455 silc_free(dec);
456 data = silc_argument_get_next_arg(arg, &type, &data_len);
457 }
458
459 silc_argument_payload_free(arg);
460
461 silc_dlist_start(list);
462
463 return list;
464 }
465
466 /* Free decoded argument payload list */
467
468 void silc_argument_list_free(SilcDList list, SilcArgumentDecodeType dec_type)
469 {
470 SilcArgumentDecodedList dec;
471
472 if (!list)
473 return;
474
475 silc_dlist_start(list);
476 while ((dec = silc_dlist_get(list))) {
477 switch (dec_type) {
478
479 case SILC_ARGUMENT_ID:
480 case SILC_ARGUMENT_UINT32:
481 case SILC_ARGUMENT_BOOL:
482 silc_free(dec->argument);
483 break;
484
485 case SILC_ARGUMENT_PUBLIC_KEY:
486 silc_pkcs_public_key_free(dec->argument);
487 break;
488
489 case SILC_ARGUMENT_ATTRIBUTES:
490 silc_attribute_payload_free(dec->argument);
491 break;
492
493 default:
494 break;
495 }
496
497 silc_free(dec);
498 }
499
500 silc_dlist_uninit(list);
501 }
502
This page was automatically generated by the LXR engine.
Free-text search provided by Glimpse