Annotation of embedaddon/strongswan/src/libcharon/plugins/vici/vici_message.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2015 Tobias Brunner
3: * HSR Hochschule fuer Technik Rapperswil
4: *
5: * Copyright (C) 2014 Martin Willi
6: * Copyright (C) 2014 revosec AG
7: *
8: * This program is free software; you can redistribute it and/or modify it
9: * under the terms of the GNU General Public License as published by the
10: * Free Software Foundation; either version 2 of the License, or (at your
11: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12: *
13: * This program is distributed in the hope that it will be useful, but
14: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16: * for more details.
17: */
18:
19: #include "vici_message.h"
20: #include "vici_builder.h"
21:
22: #include <bio/bio_reader.h>
23: #include <bio/bio_writer.h>
24:
25: #include <errno.h>
26:
27: typedef struct private_vici_message_t private_vici_message_t;
28:
29: /**
30: * Private data of an vici_message_t object.
31: */
32: struct private_vici_message_t {
33:
34: /**
35: * Public vici_message_t interface.
36: */
37: vici_message_t public;
38:
39: /**
40: * Message encoding
41: */
42: chunk_t encoding;
43:
44: /**
45: * Free encoding during destruction?
46: */
47: bool cleanup;
48:
49: /**
50: * Allocated strings we maintain for get_str()
51: */
52: linked_list_t *strings;
53: };
54:
55: ENUM(vici_type_names, VICI_START, VICI_END,
56: "start",
57: "section-start",
58: "section-end",
59: "key-value",
60: "list-start",
61: "list-item",
62: "list-end",
63: "end"
64: );
65:
66: /**
67: * See header.
68: */
69: bool vici_stringify(chunk_t chunk, char *buf, size_t size)
70: {
71: if (!chunk_printable(chunk, NULL, 0))
72: {
73: return FALSE;
74: }
75: snprintf(buf, size, "%.*s", (int)chunk.len, chunk.ptr);
76: return TRUE;
77: }
78:
79: /**
80: * See header.
81: */
82: bool vici_verify_type(vici_type_t type, u_int section, bool list)
83: {
84: if (list)
85: {
86: if (type != VICI_LIST_END && type != VICI_LIST_ITEM)
87: {
88: DBG1(DBG_ENC, "'%N' within list", vici_type_names, type);
89: return FALSE;
90: }
91: }
92: else
93: {
94: if (type == VICI_LIST_ITEM || type == VICI_LIST_END)
95: {
96: DBG1(DBG_ENC, "'%N' outside list", vici_type_names, type);
97: return FALSE;
98: }
99: }
100: if (type == VICI_SECTION_END && section == 0)
101: {
102: DBG1(DBG_ENC, "'%N' outside of section", vici_type_names, type);
103: return FALSE;
104: }
105: if (type == VICI_END && section)
106: {
107: DBG1(DBG_ENC, "'%N' within section", vici_type_names, type);
108: return FALSE;
109: }
110: return TRUE;
111: }
112:
113: /**
114: * Enumerator parsing message
115: */
116: typedef struct {
117: /* implements enumerator */
118: enumerator_t public;
119: /** reader to parse from */
120: bio_reader_t *reader;
121: /** section nesting level */
122: int section;
123: /** currently parsing list? */
124: bool list;
125: /** string currently enumerating */
126: char name[257];
127: } parse_enumerator_t;
128:
129: METHOD(enumerator_t, parse_enumerate, bool,
130: parse_enumerator_t *this, va_list args)
131: {
132: vici_type_t *out;
133: chunk_t *value;
134: char **name;
135: uint8_t type;
136: chunk_t data;
137:
138: VA_ARGS_VGET(args, out, name, value);
139:
140: if (!this->reader->remaining(this->reader) ||
141: !this->reader->read_uint8(this->reader, &type))
142: {
143: *out = VICI_END;
144: return TRUE;
145: }
146: if (!vici_verify_type(type, this->section, this->list))
147: {
148: return FALSE;
149: }
150:
151: switch (type)
152: {
153: case VICI_SECTION_START:
154: if (!this->reader->read_data8(this->reader, &data) ||
155: !vici_stringify(data, this->name, sizeof(this->name)))
156: {
157: DBG1(DBG_ENC, "invalid '%N' encoding", vici_type_names, type);
158: return FALSE;
159: }
160: *name = this->name;
161: this->section++;
162: break;
163: case VICI_SECTION_END:
164: this->section--;
165: break;
166: case VICI_KEY_VALUE:
167: if (!this->reader->read_data8(this->reader, &data) ||
168: !vici_stringify(data, this->name, sizeof(this->name)) ||
169: !this->reader->read_data16(this->reader, value))
170: {
171: DBG1(DBG_ENC, "invalid '%N' encoding", vici_type_names, type);
172: return FALSE;
173: }
174: *name = this->name;
175: break;
176: case VICI_LIST_START:
177: if (!this->reader->read_data8(this->reader, &data) ||
178: !vici_stringify(data, this->name, sizeof(this->name)))
179: {
180: DBG1(DBG_ENC, "invalid '%N' encoding", vici_type_names, type);
181: return FALSE;
182: }
183: *name = this->name;
184: this->list = TRUE;
185: break;
186: case VICI_LIST_ITEM:
187: this->reader->read_data16(this->reader, value);
188: break;
189: case VICI_LIST_END:
190: this->list = FALSE;
191: break;
192: case VICI_END:
193: return TRUE;
194: default:
195: DBG1(DBG_ENC, "unknown encoding type: %u", type);
196: return FALSE;
197: }
198:
199: *out = type;
200:
201: return TRUE;
202: }
203:
204: METHOD(enumerator_t, parse_destroy, void,
205: parse_enumerator_t *this)
206: {
207: this->reader->destroy(this->reader);
208: free(this);
209: }
210:
211: METHOD(vici_message_t, create_enumerator, enumerator_t*,
212: private_vici_message_t *this)
213: {
214: parse_enumerator_t *enumerator;
215:
216: INIT(enumerator,
217: .public = {
218: .enumerate = enumerator_enumerate_default,
219: .venumerate = _parse_enumerate,
220: .destroy = _parse_destroy,
221: },
222: .reader = bio_reader_create(this->encoding),
223: );
224:
225: return &enumerator->public;
226: }
227:
228: /**
229: * Find a value for given vararg key
230: */
231: static bool find_value(private_vici_message_t *this, chunk_t *value,
232: char *fmt, va_list args)
233: {
234: enumerator_t *enumerator;
235: char buf[128], *name, *key, *dot, *next;
236: int section = 0, keysection = 0;
237: bool found = FALSE;
238: chunk_t current;
239: vici_type_t type;
240:
241: vsnprintf(buf, sizeof(buf), fmt, args);
242: next = buf;
243:
244: enumerator = create_enumerator(this);
245:
246: /* descent into section */
247: while (TRUE)
248: {
249: dot = strchr(next, '.');
250: if (!dot)
251: {
252: key = next;
253: break;
254: }
255: *dot = '\0';
256: key = next;
257: next = dot + 1;
258: keysection++;
259:
260: while (enumerator->enumerate(enumerator, &type, &name, ¤t))
261: {
262: switch (type)
263: {
264: case VICI_SECTION_START:
265: section++;
266: if (section == keysection && streq(name, key))
267: {
268: break;
269: }
270: continue;
271: case VICI_SECTION_END:
272: section--;
273: continue;
274: case VICI_END:
275: break;
276: default:
277: continue;
278: }
279: break;
280: }
281: }
282:
283: /* find key/value in current section */
284: while (enumerator->enumerate(enumerator, &type, &name, ¤t))
285: {
286: switch (type)
287: {
288: case VICI_KEY_VALUE:
289: if (section == keysection && streq(key, name))
290: {
291: *value = current;
292: found = TRUE;
293: break;
294: }
295: continue;
296: case VICI_SECTION_START:
297: section++;
298: continue;
299: case VICI_SECTION_END:
300: section--;
301: continue;
302: case VICI_END:
303: break;
304: default:
305: continue;
306: }
307: break;
308: }
309:
310: enumerator->destroy(enumerator);
311:
312: return found;
313: }
314:
315: METHOD(vici_message_t, vget_str, char*,
316: private_vici_message_t *this, char *def, char *fmt, va_list args)
317: {
318: chunk_t value;
319: bool found;
320: char *str;
321:
322: found = find_value(this, &value, fmt, args);
323: if (found)
324: {
325: if (chunk_printable(value, NULL, 0))
326: {
327: str = strndup(value.ptr, value.len);
328: /* keep a reference to string, so caller doesn't have to care */
329: this->strings->insert_last(this->strings, str);
330: return str;
331: }
332: }
333: return def;
334: }
335:
336: METHOD(vici_message_t, get_str, char*,
337: private_vici_message_t *this, char *def, char *fmt, ...)
338: {
339: va_list args;
340: char *str;
341:
342: va_start(args, fmt);
343: str = vget_str(this, def, fmt, args);
344: va_end(args);
345: return str;
346: }
347:
348: METHOD(vici_message_t, vget_int, int,
349: private_vici_message_t *this, int def, char *fmt, va_list args)
350: {
351: chunk_t value;
352: bool found;
353: char buf[32], *pos;
354: int ret;
355:
356: found = find_value(this, &value, fmt, args);
357: if (found)
358: {
359: if (value.len == 0)
360: {
361: return def;
362: }
363: if (chunk_printable(value, NULL, 0))
364: {
365: snprintf(buf, sizeof(buf), "%.*s", (int)value.len, value.ptr);
366: errno = 0;
367: ret = strtol(buf, &pos, 0);
368: if (errno == 0 && pos == buf + strlen(buf))
369: {
370: return ret;
371: }
372: }
373: }
374: return def;
375: }
376:
377: METHOD(vici_message_t, get_int, int,
378: private_vici_message_t *this, int def, char *fmt, ...)
379: {
380: va_list args;
381: int val;
382:
383: va_start(args, fmt);
384: val = vget_int(this, def, fmt, args);
385: va_end(args);
386: return val;
387: }
388:
389: METHOD(vici_message_t, vget_bool, bool,
390: private_vici_message_t *this, bool def, char *fmt, va_list args)
391: {
392: chunk_t value;
393: bool found;
394: char buf[16];
395:
396: found = find_value(this, &value, fmt, args);
397: if (found)
398: {
399: if (value.len == 0)
400: {
401: return def;
402: }
403: if (chunk_printable(value, NULL, 0))
404: {
405: snprintf(buf, sizeof(buf), "%.*s", (int)value.len, value.ptr);
406: return settings_value_as_bool(buf, def);
407: }
408: }
409: return def;
410: }
411:
412: METHOD(vici_message_t, get_bool, bool,
413: private_vici_message_t *this, bool def, char *fmt, ...)
414: {
415: va_list args;
416: bool val;
417:
418: va_start(args, fmt);
419: val = vget_bool(this, def, fmt, args);
420: va_end(args);
421: return val;
422: }
423:
424: METHOD(vici_message_t, vget_value, chunk_t,
425: private_vici_message_t *this, chunk_t def, char *fmt, va_list args)
426: {
427: chunk_t value;
428: bool found;
429:
430: found = find_value(this, &value, fmt, args);
431: if (found)
432: {
433: return value;
434: }
435: return def;
436: }
437:
438: METHOD(vici_message_t, get_value, chunk_t,
439: private_vici_message_t *this, chunk_t def, char *fmt, ...)
440: {
441: va_list args;
442: chunk_t value;
443:
444: va_start(args, fmt);
445: value = vget_value(this, def, fmt, args);
446: va_end(args);
447: return value;
448: }
449:
450: METHOD(vici_message_t, get_encoding, chunk_t,
451: private_vici_message_t *this)
452: {
453: return this->encoding;
454: }
455:
456: /**
457: * Private parse context data
458: */
459: struct vici_parse_context_t {
460: /** current section nesting level */
461: int level;
462: /** parse enumerator */
463: enumerator_t *e;
464: };
465:
466: METHOD(vici_message_t, parse, bool,
467: private_vici_message_t *this, vici_parse_context_t *ctx,
468: vici_section_cb_t section, vici_value_cb_t kv, vici_value_cb_t li,
469: void *user)
470: {
471: vici_parse_context_t root = {};
472: char *name, *list = NULL;
473: vici_type_t type;
474: chunk_t value;
475: int base;
476: bool ok = TRUE;
477:
478: if (!ctx)
479: {
480: ctx = &root;
481: root.e = create_enumerator(this);
482: }
483:
484: base = ctx->level;
485:
486: while (ok)
487: {
488: ok = ctx->e->enumerate(ctx->e, &type, &name, &value);
489: if (ok)
490: {
491: switch (type)
492: {
493: case VICI_START:
494: /* should never occur */
495: continue;
496: case VICI_KEY_VALUE:
497: if (ctx->level == base && kv)
498: {
499: name = strdup(name);
500: this->strings->insert_last(this->strings, name);
501: ok = kv(user, &this->public, name, value);
502: }
503: continue;
504: case VICI_LIST_START:
505: if (ctx->level == base)
506: {
507: list = strdup(name);
508: this->strings->insert_last(this->strings, list);
509: }
510: continue;
511: case VICI_LIST_ITEM:
512: if (list && li)
513: {
514: name = strdup(name);
515: this->strings->insert_last(this->strings, name);
516: ok = li(user, &this->public, list, value);
517: }
518: continue;
519: case VICI_LIST_END:
520: if (ctx->level == base)
521: {
522: list = NULL;
523: }
524: continue;
525: case VICI_SECTION_START:
526: if (ctx->level++ == base && section)
527: {
528: name = strdup(name);
529: this->strings->insert_last(this->strings, name);
530: ok = section(user, &this->public, ctx, name);
531: }
532: continue;
533: case VICI_SECTION_END:
534: if (ctx->level-- == base)
535: {
536: break;
537: }
538: continue;
539: case VICI_END:
540: break;
541: }
542: }
543: break;
544: }
545:
546: if (ctx == &root)
547: {
548: root.e->destroy(root.e);
549: }
550: return ok;
551: }
552:
553: METHOD(vici_message_t, dump, bool,
554: private_vici_message_t *this, char *label, bool pretty, FILE *out)
555: {
556: enumerator_t *enumerator;
557: int ident = 0, delta;
558: vici_type_t type, last_type = VICI_START;
559: char *name, *term, *sep, *separ, *assign;
560: chunk_t value;
561:
562: /* pretty print uses indentation on multiple lines */
563: if (pretty)
564: {
565: delta = 2;
566: term = "\n";
567: separ = "";
568: assign = " = ";
569: }
570: else
571: {
572: delta = 0;
573: term = "";
574: separ = " ";
575: assign = "=";
576: }
577:
578: fprintf(out, "%s {%s", label, term);
579: ident += delta;
580:
581: enumerator = create_enumerator(this);
582: while (enumerator->enumerate(enumerator, &type, &name, &value))
583: {
584: switch (type)
585: {
586: case VICI_START:
587: /* should never occur */
588: break;
589: case VICI_SECTION_START:
590: sep = (last_type != VICI_SECTION_START &&
591: last_type != VICI_START) ? separ : "";
592: fprintf(out, "%*s%s%s {%s", ident, "", sep, name, term);
593: ident += delta;
594: break;
595: case VICI_SECTION_END:
596: ident -= delta;
597: fprintf(out, "%*s}%s", ident, "", term);
598: break;
599: case VICI_KEY_VALUE:
600: sep = (last_type != VICI_SECTION_START &&
601: last_type != VICI_START) ? separ : "";
602: if (chunk_printable(value, NULL, ' '))
603: {
604: fprintf(out, "%*s%s%s%s%.*s%s", ident, "", sep, name,
605: assign, (int)value.len, value.ptr, term);
606: }
607: else
608: {
609: fprintf(out, "%*s%s%s%s0x%+#B%s", ident, "", sep, name,
610: assign, &value, term);
611: }
612: break;
613: case VICI_LIST_START:
614: sep = (last_type != VICI_SECTION_START &&
615: last_type != VICI_START) ? separ : "";
616: fprintf(out, "%*s%s%s%s[%s", ident, "", sep, name, assign, term);
617: ident += delta;
618: break;
619: case VICI_LIST_END:
620: ident -= delta;
621: fprintf(out, "%*s]%s", ident, "", term);
622: break;
623: case VICI_LIST_ITEM:
624: sep = (last_type != VICI_LIST_START) ? separ : "";
625: if (chunk_printable(value, NULL, ' '))
626: {
627: fprintf(out, "%*s%s%.*s%s", ident, "", sep,
628: (int)value.len, value.ptr, term);
629: }
630: else
631: {
632: fprintf(out, "%*s%s0x%+#B%s", ident, "", sep,
633: &value, term);
634: }
635: break;
636: case VICI_END:
637: fprintf(out, "}\n");
638: enumerator->destroy(enumerator);
639: return TRUE;
640: }
641: last_type = type;
642: }
643: enumerator->destroy(enumerator);
644: return FALSE;
645: }
646:
647: METHOD(vici_message_t, destroy, void,
648: private_vici_message_t *this)
649: {
650: if (this->cleanup)
651: {
652: chunk_clear(&this->encoding);
653: }
654: this->strings->destroy_function(this->strings, free);
655: free(this);
656: }
657:
658: /**
659: * See header
660: */
661: vici_message_t *vici_message_create_from_data(chunk_t data, bool cleanup)
662: {
663: private_vici_message_t *this;
664:
665: INIT(this,
666: .public = {
667: .create_enumerator = _create_enumerator,
668: .get_str = _get_str,
669: .vget_str = _vget_str,
670: .get_int = _get_int,
671: .vget_int = _vget_int,
672: .get_bool = _get_bool,
673: .vget_bool = _vget_bool,
674: .get_value = _get_value,
675: .vget_value = _vget_value,
676: .get_encoding = _get_encoding,
677: .parse = _parse,
678: .dump = _dump,
679: .destroy = _destroy,
680: },
681: .strings = linked_list_create(),
682: .encoding = data,
683: .cleanup = cleanup,
684: );
685:
686: return &this->public;
687: }
688:
689: /**
690: * See header
691: */
692: vici_message_t *vici_message_create_from_enumerator(enumerator_t *enumerator)
693: {
694: vici_builder_t *builder;
695: vici_type_t type;
696: char *name;
697: chunk_t value;
698:
699: builder = vici_builder_create();
700: while (enumerator->enumerate(enumerator, &type, &name, &value))
701: {
702: switch (type)
703: {
704: case VICI_SECTION_START:
705: case VICI_LIST_START:
706: builder->add(builder, type, name);
707: continue;
708: case VICI_KEY_VALUE:
709: builder->add(builder, type, name, value);
710: continue;
711: case VICI_LIST_ITEM:
712: builder->add(builder, type, value);
713: continue;
714: case VICI_SECTION_END:
715: case VICI_LIST_END:
716: default:
717: builder->add(builder, type);
718: continue;
719: case VICI_END:
720: break;
721: }
722: break;
723: }
724: enumerator->destroy(enumerator);
725:
726: return builder->finalize(builder);
727: }
728:
729: /**
730: * See header
731: */
732: vici_message_t *vici_message_create_from_args(vici_type_t type, ...)
733: {
734: vici_builder_t *builder;
735: va_list args;
736: char *name;
737: chunk_t value;
738:
739: builder = vici_builder_create();
740: va_start(args, type);
741: while (type != VICI_END)
742: {
743: switch (type)
744: {
745: case VICI_LIST_START:
746: case VICI_SECTION_START:
747: name = va_arg(args, char*);
748: builder->add(builder, type, name);
749: break;
750: case VICI_KEY_VALUE:
751: name = va_arg(args, char*);
752: value = va_arg(args, chunk_t);
753: builder->add(builder, type, name, value);
754: break;
755: case VICI_LIST_ITEM:
756: value = va_arg(args, chunk_t);
757: builder->add(builder, type, value);
758: break;
759: case VICI_SECTION_END:
760: case VICI_LIST_END:
761: default:
762: builder->add(builder, type);
763: break;
764: }
765: type = va_arg(args, vici_type_t);
766: }
767: va_end(args);
768: return builder->finalize(builder);
769: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>