Annotation of embedaddon/strongswan/src/libcharon/plugins/vici/vici_message.c, revision 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>