/* * Copyright (C) 2014 Tobias Brunner * Copyright (C) 2006 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. See . * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include #include #include "confread.h" #include "args.h" /* argument types */ typedef enum { ARG_NONE, ARG_ENUM, ARG_UINT, ARG_TIME, ARG_ULNG, ARG_ULLI, ARG_UBIN, ARG_PCNT, ARG_STR, ARG_MISC } arg_t; /* various keyword lists */ static const char *LST_bool[] = { "no", "yes", NULL }; static const char *LST_sendcert[] = { "always", "ifasked", "never", "yes", "no", NULL }; static const char *LST_unique[] = { "no", "yes", "replace", "keep", "never", NULL }; static const char *LST_strict[] = { "no", "yes", "ifuri", NULL }; static const char *LST_dpd_action[] = { "none", "clear", "hold", "restart", NULL }; static const char *LST_startup[] = { "ignore", "add", "route", "start", NULL }; static const char *LST_keyexchange[] = { "ike", "ikev1", "ikev2", NULL }; static const char *LST_authby[] = { "psk", "secret", "pubkey", "rsa", "rsasig", "ecdsa", "ecdsasig", "xauthpsk", "xauthrsasig", "never", NULL }; static const char *LST_fragmentation[] = { "no", "accept", "yes", "force", NULL }; typedef struct { arg_t type; size_t offset; const char **list; } token_info_t; static const token_info_t token_info[] = { /* config setup keywords */ { ARG_STR, offsetof(starter_config_t, setup.charondebug), NULL }, { ARG_ENUM, offsetof(starter_config_t, setup.uniqueids), LST_unique }, { ARG_ENUM, offsetof(starter_config_t, setup.cachecrls), LST_bool }, { ARG_ENUM, offsetof(starter_config_t, setup.strictcrlpolicy), LST_strict }, { ARG_MISC, 0, NULL /* KW_PKCS11_DEPRECATED */ }, { ARG_MISC, 0, NULL /* KW_SETUP_DEPRECATED */ }, /* conn section keywords */ { ARG_STR, offsetof(starter_conn_t, name), NULL }, { ARG_ENUM, offsetof(starter_conn_t, startup), LST_startup }, { ARG_ENUM, offsetof(starter_conn_t, keyexchange), LST_keyexchange }, { ARG_MISC, 0, NULL /* KW_TYPE */ }, { ARG_MISC, 0, NULL /* KW_COMPRESS */ }, { ARG_ENUM, offsetof(starter_conn_t, install_policy), LST_bool }, { ARG_ENUM, offsetof(starter_conn_t, aggressive), LST_bool }, { ARG_STR, offsetof(starter_conn_t, authby), LST_authby }, { ARG_STR, offsetof(starter_conn_t, eap_identity), NULL }, { ARG_STR, offsetof(starter_conn_t, aaa_identity), NULL }, { ARG_MISC, 0, NULL /* KW_MOBIKE */ }, { ARG_MISC, 0, NULL /* KW_FORCEENCAPS */ }, { ARG_ENUM, offsetof(starter_conn_t, fragmentation), LST_fragmentation }, { ARG_UBIN, offsetof(starter_conn_t, ikedscp), NULL }, { ARG_TIME, offsetof(starter_conn_t, sa_ike_life_seconds), NULL }, { ARG_TIME, offsetof(starter_conn_t, sa_ipsec_life_seconds), NULL }, { ARG_TIME, offsetof(starter_conn_t, sa_rekey_margin), NULL }, { ARG_ULLI, offsetof(starter_conn_t, sa_ipsec_life_bytes), NULL }, { ARG_ULLI, offsetof(starter_conn_t, sa_ipsec_margin_bytes), NULL }, { ARG_ULLI, offsetof(starter_conn_t, sa_ipsec_life_packets), NULL }, { ARG_ULLI, offsetof(starter_conn_t, sa_ipsec_margin_packets), NULL }, { ARG_MISC, 0, NULL /* KW_KEYINGTRIES */ }, { ARG_PCNT, offsetof(starter_conn_t, sa_rekey_fuzz), NULL }, { ARG_MISC, 0, NULL /* KW_REKEY */ }, { ARG_MISC, 0, NULL /* KW_REAUTH */ }, { ARG_STR, offsetof(starter_conn_t, ike), NULL }, { ARG_STR, offsetof(starter_conn_t, esp), NULL }, { ARG_STR, offsetof(starter_conn_t, ah), NULL }, { ARG_TIME, offsetof(starter_conn_t, dpd_delay), NULL }, { ARG_TIME, offsetof(starter_conn_t, dpd_timeout), NULL }, { ARG_ENUM, offsetof(starter_conn_t, dpd_action), LST_dpd_action }, { ARG_ENUM, offsetof(starter_conn_t, close_action), LST_dpd_action }, { ARG_ENUM, offsetof(starter_conn_t, sha256_96), LST_bool }, { ARG_TIME, offsetof(starter_conn_t, inactivity), NULL }, { ARG_MISC, 0, NULL /* KW_MODECONFIG */ }, { ARG_MISC, 0, NULL /* KW_XAUTH */ }, { ARG_STR, offsetof(starter_conn_t, xauth_identity), NULL }, { ARG_ENUM, offsetof(starter_conn_t, me_mediation), LST_bool }, { ARG_STR, offsetof(starter_conn_t, me_mediated_by), NULL }, { ARG_STR, offsetof(starter_conn_t, me_peerid), NULL }, { ARG_UINT, offsetof(starter_conn_t, reqid), NULL }, { ARG_UINT, offsetof(starter_conn_t, replay_window), NULL }, { ARG_MISC, 0, NULL /* KW_MARK */ }, { ARG_MISC, 0, NULL /* KW_MARK_IN */ }, { ARG_MISC, 0, NULL /* KW_MARK_OUT */ }, { ARG_MISC, 0, NULL /* KW_TFC */ }, { ARG_MISC, 0, NULL /* KW_PFS_DEPRECATED */ }, { ARG_MISC, 0, NULL /* KW_CONN_DEPRECATED */ }, /* ca section keywords */ { ARG_STR, offsetof(starter_ca_t, name), NULL }, { ARG_ENUM, offsetof(starter_ca_t, startup), LST_startup }, { ARG_STR, offsetof(starter_ca_t, cacert), NULL }, { ARG_STR, offsetof(starter_ca_t, crluri), NULL }, { ARG_STR, offsetof(starter_ca_t, crluri2), NULL }, { ARG_STR, offsetof(starter_ca_t, ocspuri), NULL }, { ARG_STR, offsetof(starter_ca_t, ocspuri2), NULL }, { ARG_STR, offsetof(starter_ca_t, certuribase), NULL }, { ARG_MISC, 0, NULL /* KW_CA_DEPRECATED */ }, /* end keywords */ { ARG_STR, offsetof(starter_end_t, host), NULL }, { ARG_UINT, offsetof(starter_end_t, ikeport), NULL }, { ARG_STR, offsetof(starter_end_t, subnet), NULL }, { ARG_MISC, 0, NULL /* KW_PROTOPORT */ }, { ARG_STR, offsetof(starter_end_t, sourceip), NULL }, { ARG_STR, offsetof(starter_end_t, dns), NULL }, { ARG_ENUM, offsetof(starter_end_t, firewall), LST_bool }, { ARG_ENUM, offsetof(starter_end_t, hostaccess), LST_bool }, { ARG_ENUM, offsetof(starter_end_t, allow_any), LST_bool }, { ARG_STR, offsetof(starter_end_t, updown), NULL }, { ARG_STR, offsetof(starter_end_t, auth), NULL }, { ARG_STR, offsetof(starter_end_t, auth2), NULL }, { ARG_STR, offsetof(starter_end_t, id), NULL }, { ARG_STR, offsetof(starter_end_t, id2), NULL }, { ARG_STR, offsetof(starter_end_t, rsakey), NULL }, { ARG_STR, offsetof(starter_end_t, cert), NULL }, { ARG_STR, offsetof(starter_end_t, cert2), NULL }, { ARG_STR, offsetof(starter_end_t, cert_policy), NULL }, { ARG_ENUM, offsetof(starter_end_t, sendcert), LST_sendcert }, { ARG_STR, offsetof(starter_end_t, ca), NULL }, { ARG_STR, offsetof(starter_end_t, ca2), NULL }, { ARG_STR, offsetof(starter_end_t, groups), NULL }, { ARG_STR, offsetof(starter_end_t, groups2), NULL }, { ARG_MISC, 0, NULL /* KW_END_DEPRECATED */ }, }; /* * assigns an argument value to a struct field */ bool assign_arg(kw_token_t token, kw_token_t first, char *key, char *value, void *base, bool *assigned) { char *p = (char*)base + token_info[token].offset; const char **list = token_info[token].list; int index = -1; /* used for enumeration arguments */ *assigned = FALSE; DBG3(DBG_APP, " %s=%s", key, value); /* is there a keyword list? */ if (list != NULL) { bool match = FALSE; while (*list != NULL && !match) { index++; match = streq(value, *list++); } if (!match) { DBG1(DBG_APP, "# bad value: %s=%s", key, value); return FALSE; } } switch (token_info[token].type) { case ARG_NONE: DBG1(DBG_APP, "# option '%s' not supported yet", key); return FALSE; case ARG_ENUM: { if (index < 0) { DBG1(DBG_APP, "# bad enumeration value: %s=%s (%d)", key, value, index); return FALSE; } if (token_info[token].list == LST_bool) { bool *b = (bool *)p; *b = (index > 0); } else { /* FIXME: this is not entirely correct as the args are enums */ int *i = (int *)p; *i = index; } break; } case ARG_UINT: { char *endptr; u_int *u = (u_int *)p; *u = strtoul(value, &endptr, 10); if (*endptr != '\0') { DBG1(DBG_APP, "# bad integer value: %s=%s", key, value); return FALSE; } break; } case ARG_ULNG: case ARG_PCNT: { char *endptr; unsigned long *l = (unsigned long *)p; *l = strtoul(value, &endptr, 10); if (token_info[token].type == ARG_ULNG) { if (*endptr != '\0') { DBG1(DBG_APP, "# bad integer value: %s=%s", key, value); return FALSE; } } else { if ((*endptr != '%') || (endptr[1] != '\0') || endptr == value) { DBG1(DBG_APP, "# bad percent value: %s=%s", key, value); return FALSE; } } break; } case ARG_ULLI: { char *endptr; unsigned long long *ll = (unsigned long long *)p; *ll = strtoull(value, &endptr, 10); if (*endptr != '\0') { DBG1(DBG_APP, "# bad integer value: %s=%s", key, value); return FALSE; } break; } case ARG_UBIN: { char *endptr; u_int *u = (u_int *)p; *u = strtoul(value, &endptr, 2); if (*endptr != '\0') { DBG1(DBG_APP, "# bad binary value: %s=%s", key, value); return FALSE; } break; } case ARG_TIME: { char *endptr; time_t *t = (time_t *)p; *t = strtoul(value, &endptr, 10); /* time in seconds? */ if (*endptr == '\0' || (*endptr == 's' && endptr[1] == '\0')) { break; } if (endptr[1] == '\0') { if (*endptr == 'm') /* time in minutes? */ { *t *= 60; break; } if (*endptr == 'h') /* time in hours? */ { *t *= 3600; break; } if (*endptr == 'd') /* time in days? */ { *t *= 3600*24; break; } } DBG1(DBG_APP, "# bad duration value: %s=%s", key, value); return FALSE; } case ARG_STR: { char **cp = (char **)p; /* free any existing string */ free(*cp); /* assign the new string */ *cp = strdupnull(value); break; } default: return TRUE; } *assigned = TRUE; return TRUE; } /* * frees all dynamically allocated arguments in a struct */ void free_args(kw_token_t first, kw_token_t last, void *base) { kw_token_t token; for (token = first; token <= last; token++) { char *p = (char*)base + token_info[token].offset; switch (token_info[token].type) { case ARG_STR: { char **cp = (char **)p; free(*cp); *cp = NULL; break; } default: break; } } } /* * compare all arguments in a struct */ bool cmp_args(kw_token_t first, kw_token_t last, void *base1, void *base2) { kw_token_t token; for (token = first; token <= last; token++) { char *p1 = (char*)base1 + token_info[token].offset; char *p2 = (char*)base2 + token_info[token].offset; switch (token_info[token].type) { case ARG_ENUM: { if (token_info[token].list == LST_bool) { bool *b1 = (bool *)p1; bool *b2 = (bool *)p2; if (*b1 != *b2) { return FALSE; } } else { int *i1 = (int *)p1; int *i2 = (int *)p2; if (*i1 != *i2) { return FALSE; } } break; } case ARG_UINT: { u_int *u1 = (u_int *)p1; u_int *u2 = (u_int *)p2; if (*u1 != *u2) { return FALSE; } break; } case ARG_ULNG: case ARG_PCNT: { unsigned long *l1 = (unsigned long *)p1; unsigned long *l2 = (unsigned long *)p2; if (*l1 != *l2) { return FALSE; } break; } case ARG_ULLI: { unsigned long long *ll1 = (unsigned long long *)p1; unsigned long long *ll2 = (unsigned long long *)p2; if (*ll1 != *ll2) { return FALSE; } break; } case ARG_TIME: { time_t *t1 = (time_t *)p1; time_t *t2 = (time_t *)p2; if (*t1 != *t2) { return FALSE; } break; } case ARG_STR: { char **cp1 = (char **)p1; char **cp2 = (char **)p2; if (*cp1 == NULL && *cp2 == NULL) { break; } if (*cp1 == NULL || *cp2 == NULL || strcmp(*cp1, *cp2) != 0) { return FALSE; } break; } default: break; } } return TRUE; }