1*592a196eSniklas /* $OpenBSD: conf.c,v 1.15 2000/05/03 13:47:15 niklas Exp $ */ 2*592a196eSniklas /* $EOM: conf.c,v 1.28 2000/05/03 13:24:45 niklas Exp $ */ 32040585eSniklas 42040585eSniklas /* 598ef4a55Sniklas * Copyright (c) 1998, 1999, 2000 Niklas Hallqvist. All rights reserved. 62040585eSniklas * 72040585eSniklas * Redistribution and use in source and binary forms, with or without 82040585eSniklas * modification, are permitted provided that the following conditions 92040585eSniklas * are met: 102040585eSniklas * 1. Redistributions of source code must retain the above copyright 112040585eSniklas * notice, this list of conditions and the following disclaimer. 122040585eSniklas * 2. Redistributions in binary form must reproduce the above copyright 132040585eSniklas * notice, this list of conditions and the following disclaimer in the 142040585eSniklas * documentation and/or other materials provided with the distribution. 152040585eSniklas * 3. All advertising materials mentioning features or use of this software 162040585eSniklas * must display the following acknowledgement: 172040585eSniklas * This product includes software developed by Ericsson Radio Systems. 182040585eSniklas * 4. The name of the author may not be used to endorse or promote products 192040585eSniklas * derived from this software without specific prior written permission. 202040585eSniklas * 212040585eSniklas * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 222040585eSniklas * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 232040585eSniklas * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 242040585eSniklas * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 252040585eSniklas * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 262040585eSniklas * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 272040585eSniklas * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 282040585eSniklas * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 292040585eSniklas * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 302040585eSniklas * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 312040585eSniklas */ 322040585eSniklas 332040585eSniklas /* 342040585eSniklas * This code was written under funding by Ericsson Radio Systems. 352040585eSniklas */ 362040585eSniklas 372040585eSniklas #include <sys/param.h> 382040585eSniklas #include <sys/mman.h> 392040585eSniklas #include <sys/queue.h> 402040585eSniklas #include <sys/stat.h> 412040585eSniklas #include <ctype.h> 422040585eSniklas #include <fcntl.h> 432040585eSniklas #include <stdio.h> 442040585eSniklas #include <stdlib.h> 452040585eSniklas #include <string.h> 462040585eSniklas #include <unistd.h> 472040585eSniklas 48a2d30fd1Sniklas #include "sysdep.h" 49a2d30fd1Sniklas 50a2d30fd1Sniklas #include "app.h" 512040585eSniklas #include "conf.h" 522040585eSniklas #include "log.h" 532040585eSniklas 54f8f1e192Sniklas struct conf_trans { 55f8f1e192Sniklas TAILQ_ENTRY (conf_trans) link; 56f8f1e192Sniklas int trans; 57f8f1e192Sniklas enum conf_op { CONF_SET, CONF_REMOVE, CONF_REMOVE_SECTION } op; 58f8f1e192Sniklas char *section; 59f8f1e192Sniklas char *tag; 60f8f1e192Sniklas char *value; 61f8f1e192Sniklas int override; 62510d8b0cSniklas int is_default; 63f8f1e192Sniklas }; 64f8f1e192Sniklas 65f8f1e192Sniklas TAILQ_HEAD (conf_trans_head, conf_trans) conf_trans_queue; 66f8f1e192Sniklas 672040585eSniklas /* 682040585eSniklas * Radix-64 Encoding. 692040585eSniklas */ 70510d8b0cSniklas const u_int8_t bin2asc[] 71510d8b0cSniklas = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 722040585eSniklas 732040585eSniklas const u_int8_t asc2bin[] = 742040585eSniklas { 752040585eSniklas 255, 255, 255, 255, 255, 255, 255, 255, 762040585eSniklas 255, 255, 255, 255, 255, 255, 255, 255, 772040585eSniklas 255, 255, 255, 255, 255, 255, 255, 255, 782040585eSniklas 255, 255, 255, 255, 255, 255, 255, 255, 792040585eSniklas 255, 255, 255, 255, 255, 255, 255, 255, 802040585eSniklas 255, 255, 255, 62, 255, 255, 255, 63, 812040585eSniklas 52, 53, 54, 55, 56, 57, 58, 59, 822040585eSniklas 60, 61, 255, 255, 255, 255, 255, 255, 832040585eSniklas 255, 0, 1, 2, 3, 4, 5, 6, 842040585eSniklas 7, 8, 9, 10, 11, 12, 13, 14, 852040585eSniklas 15, 16, 17, 18, 19, 20, 21, 22, 862040585eSniklas 23, 24, 25, 255, 255, 255, 255, 255, 872040585eSniklas 255, 26, 27, 28, 29, 30, 31, 32, 882040585eSniklas 33, 34, 35, 36, 37, 38, 39, 40, 892040585eSniklas 41, 42, 43, 44, 45, 46, 47, 48, 902040585eSniklas 49, 50, 51, 255, 255, 255, 255, 255 912040585eSniklas }; 922040585eSniklas 932040585eSniklas struct conf_binding { 942040585eSniklas LIST_ENTRY (conf_binding) link; 952040585eSniklas char *section; 962040585eSniklas char *tag; 972040585eSniklas char *value; 98510d8b0cSniklas int is_default; 992040585eSniklas }; 1002040585eSniklas 1012040585eSniklas char *conf_path = CONFIG_FILE; 102f8f1e192Sniklas LIST_HEAD (conf_bindings, conf_binding) conf_bindings[256]; 1032040585eSniklas 1042040585eSniklas static char *conf_addr; 1052040585eSniklas 106f8f1e192Sniklas static __inline__ u_int8_t 107f8f1e192Sniklas conf_hash (char *s) 108f8f1e192Sniklas { 109f8f1e192Sniklas u_int8_t hash = 0; 110f8f1e192Sniklas 111f8f1e192Sniklas while (*s) 112f8f1e192Sniklas { 113f8f1e192Sniklas hash = ((hash << 1) | (hash >> 7)) ^ tolower (*s); 114f8f1e192Sniklas s++; 115f8f1e192Sniklas } 116f8f1e192Sniklas return hash; 117f8f1e192Sniklas } 118f8f1e192Sniklas 119f8f1e192Sniklas /* 120f8f1e192Sniklas * Insert a tag-value combination from LINE (the equal sign is at POS) 121f8f1e192Sniklas */ 122f8f1e192Sniklas static int 123f8f1e192Sniklas conf_remove_now (char *section, char *tag) 124f8f1e192Sniklas { 125f8f1e192Sniklas struct conf_binding *cb, *next; 126f8f1e192Sniklas 127f8f1e192Sniklas for (cb = LIST_FIRST (&conf_bindings[conf_hash (section)]); cb; cb = next) 128f8f1e192Sniklas { 129f8f1e192Sniklas next = LIST_NEXT (cb, link); 130f8f1e192Sniklas if (strcasecmp (cb->section, section) == 0 131f8f1e192Sniklas && strcasecmp (cb->tag, tag) == 0) 132f8f1e192Sniklas { 133f8f1e192Sniklas LIST_REMOVE (cb, link); 13451ca15aeSniklas LOG_DBG ((LOG_MISC, 70, "[%s]:%s->%s removed", section, tag, 13551ca15aeSniklas cb->value)); 136f8f1e192Sniklas free (cb->section); 137f8f1e192Sniklas free (cb->tag); 138f8f1e192Sniklas free (cb->value); 139f8f1e192Sniklas free (cb); 140f8f1e192Sniklas return 0; 141f8f1e192Sniklas } 142f8f1e192Sniklas } 143f8f1e192Sniklas return 1; 144f8f1e192Sniklas } 145f8f1e192Sniklas 146f8f1e192Sniklas static int 147f8f1e192Sniklas conf_remove_section_now (char *section) 148f8f1e192Sniklas { 149f8f1e192Sniklas struct conf_binding *cb, *next; 150f8f1e192Sniklas int unseen = 1; 151f8f1e192Sniklas 152f8f1e192Sniklas for (cb = LIST_FIRST (&conf_bindings[conf_hash (section)]); cb; cb = next) 153f8f1e192Sniklas { 154f8f1e192Sniklas next = LIST_NEXT (cb, link); 155f8f1e192Sniklas if (strcasecmp (cb->section, section) == 0) 156f8f1e192Sniklas { 157f8f1e192Sniklas unseen = 0; 158f8f1e192Sniklas LIST_REMOVE (cb, link); 15951ca15aeSniklas LOG_DBG ((LOG_MISC, 70, "[%s]:%s->%s removed", section, cb->tag, 16051ca15aeSniklas cb->value)); 161f8f1e192Sniklas free (cb->section); 162f8f1e192Sniklas free (cb->tag); 163f8f1e192Sniklas free (cb->value); 164f8f1e192Sniklas free (cb); 165f8f1e192Sniklas } 166f8f1e192Sniklas } 167f8f1e192Sniklas return unseen; 168f8f1e192Sniklas } 169f8f1e192Sniklas 1702040585eSniklas /* 1712040585eSniklas * Insert a tag-value combination from LINE (the equal sign is at POS) 1722040585eSniklas * into SECTION of our configuration database. 1732040585eSniklas */ 174f8f1e192Sniklas static int 175510d8b0cSniklas conf_set_now (char *section, char *tag, char *value, int override, 176510d8b0cSniklas int is_default) 1772040585eSniklas { 178f8f1e192Sniklas struct conf_binding *node = 0; 1792040585eSniklas 180f8f1e192Sniklas if (override) 181f8f1e192Sniklas conf_remove_now (section, tag); 182f8f1e192Sniklas else if (conf_get_str (section, tag)) 1832040585eSniklas { 184510d8b0cSniklas if (is_default == 0) 1852040585eSniklas log_print ("conf_set: duplicate tag [%s]:%s, ignoring...\n", section, 186f8f1e192Sniklas tag); 187f8f1e192Sniklas return 1; 1882040585eSniklas } 189f8f1e192Sniklas 190f8f1e192Sniklas node = calloc (1, sizeof *node); 191f8f1e192Sniklas if (!node) 192f8f1e192Sniklas { 193f8f1e192Sniklas log_error ("conf_set: calloc (1, %d) failed", sizeof *node); 194f8f1e192Sniklas return 1; 195f8f1e192Sniklas } 196f8f1e192Sniklas node->section = section; 197f8f1e192Sniklas node->tag = tag; 198f8f1e192Sniklas node->value = value; 199510d8b0cSniklas node->is_default = is_default; 200f8f1e192Sniklas 201f8f1e192Sniklas LIST_INSERT_HEAD (&conf_bindings[conf_hash (section)], node, link); 20251ca15aeSniklas LOG_DBG ((LOG_MISC, 70, "[%s]:%s->%s", node->section, node->tag, 20351ca15aeSniklas node->value)); 204f8f1e192Sniklas return 0; 2052040585eSniklas } 2062040585eSniklas 2072040585eSniklas /* 2082040585eSniklas * Parse the line LINE of SZ bytes. Skip Comments, recognize section 2092040585eSniklas * headers and feed tag-value pairs into our configuration database. 2102040585eSniklas */ 2112040585eSniklas static void 212f8f1e192Sniklas conf_parse_line (int trans, char *line, size_t sz) 2132040585eSniklas { 2142040585eSniklas char *cp = line; 2152040585eSniklas int i; 2162040585eSniklas static char *section = 0; 2172040585eSniklas static int ln = 0; 2182040585eSniklas 2192040585eSniklas ln++; 2202040585eSniklas 2212040585eSniklas /* Lines starting with '#' or ';' are comments. */ 2222040585eSniklas if (*line == '#' || *line == ';') 2232040585eSniklas return; 2242040585eSniklas 2252040585eSniklas /* '[section]' parsing... */ 2262040585eSniklas if (*line == '[') 2272040585eSniklas { 2282040585eSniklas for (i = 1; i < sz; i++) 2292040585eSniklas if (line[i] == ']') 2302040585eSniklas break; 2312040585eSniklas if (i == sz) 2322040585eSniklas { 2332040585eSniklas log_print ("conf_parse_line: %d:" 2342040585eSniklas "non-matched ']', ignoring until next section", ln); 2352040585eSniklas section = 0; 2362040585eSniklas return; 2372040585eSniklas } 2382040585eSniklas section = malloc (i); 2392040585eSniklas strncpy (section, line + 1, i - 1); 2402040585eSniklas section[i - 1] = '\0'; 2412040585eSniklas return; 2422040585eSniklas } 2432040585eSniklas 2442040585eSniklas /* Deal with assignments. */ 2452040585eSniklas for (i = 0; i < sz; i++) 2462040585eSniklas if (cp[i] == '=') 2472040585eSniklas { 2482040585eSniklas /* If no section, we are ignoring the lines. */ 2492040585eSniklas if (!section) 2502040585eSniklas { 2512040585eSniklas log_print ("conf_parse_line: %d: ignoring line due to no section", 2522040585eSniklas ln); 2532040585eSniklas return; 2542040585eSniklas } 255f8f1e192Sniklas line[strcspn (line, " \t=")] = '\0'; 256f8f1e192Sniklas /* XXX Perhaps should we not ignore errors? */ 257f8f1e192Sniklas conf_set (trans, section, line, 258510d8b0cSniklas line + i + 1 + strspn (line + i + 1, " \t"), 0, 0); 2592040585eSniklas return; 2602040585eSniklas } 2612040585eSniklas 2622040585eSniklas /* Other non-empty lines are wierd. */ 2632040585eSniklas i = strspn (line, " \t"); 2642040585eSniklas if (line[i]) 2652040585eSniklas log_print ("conf_parse_line: %d: syntax error", ln); 2662040585eSniklas 2672040585eSniklas return; 2682040585eSniklas } 2692040585eSniklas 2702040585eSniklas /* Parse the mapped configuration file. */ 2712040585eSniklas static void 272f8f1e192Sniklas conf_parse (int trans, char *buf, size_t sz) 2732040585eSniklas { 274f8f1e192Sniklas char *cp = buf; 275f8f1e192Sniklas char *bufend = buf + sz; 2762040585eSniklas char *line; 2772040585eSniklas 2782040585eSniklas line = cp; 279f8f1e192Sniklas while (cp < bufend) 2802040585eSniklas { 2812040585eSniklas if (*cp == '\n') 2822040585eSniklas { 2832040585eSniklas /* Check for escaped newlines. */ 284f8f1e192Sniklas if (cp > buf && *(cp - 1) == '\\') 2852040585eSniklas *(cp - 1) = *cp = ' '; 2862040585eSniklas else 2872040585eSniklas { 2882040585eSniklas *cp = '\0'; 289f8f1e192Sniklas conf_parse_line (trans, line, cp - line); 2902040585eSniklas line = cp + 1; 2912040585eSniklas } 2922040585eSniklas } 2932040585eSniklas cp++; 2942040585eSniklas } 2952040585eSniklas if (cp != line) 2962040585eSniklas log_print ("conf_parse: last line non-terminated, ignored."); 2972040585eSniklas } 2982040585eSniklas 299510d8b0cSniklas /* 300510d8b0cSniklas * Auto-generate default configuration values for the transforms and 301510d8b0cSniklas * suites the user wants. 302510d8b0cSniklas * 303510d8b0cSniklas * Resulting section names can be: 304510d8b0cSniklas * For main mode: 305510d8b0cSniklas * {DES,BLF,3DES,CAST}-{MD5,SHA}[-{DSS,RSA_SIG}] 306510d8b0cSniklas * For quick mode: 307510d8b0cSniklas * QM-{ESP,AH}[-TRP]-{DES,3DES,CAST,BLF}[-{MD5,SHA}][-PFS]-SUITE 308510d8b0cSniklas * DH groups; currently always MODP_768 for MD5, and MODP_1024 for SHA. 309510d8b0cSniklas * 310510d8b0cSniklas * XXX We may want to support USE_BLOWFISH, USE_TRIPLEDES, etc... 311510d8b0cSniklas * XXX No EC2N DH support here yet. 312510d8b0cSniklas */ 313510d8b0cSniklas 314510d8b0cSniklas int 315510d8b0cSniklas conf_find_trans_xf (int phase, char *xf) 316510d8b0cSniklas { 317510d8b0cSniklas struct conf_trans *node; 318510d8b0cSniklas char *p; 319510d8b0cSniklas 320510d8b0cSniklas /* Find the relevant transforms and suites, if any. */ 321510d8b0cSniklas for (node = TAILQ_FIRST (&conf_trans_queue); node; 322510d8b0cSniklas node = TAILQ_NEXT (node, link)) 323510d8b0cSniklas if (( phase == 1 && !strcmp ("Transforms", node->tag)) || 324510d8b0cSniklas ( phase == 2 && !strcmp ("Suites", node->tag))) 325510d8b0cSniklas { 326510d8b0cSniklas p = node->value; 327510d8b0cSniklas while ((p = strstr (p, xf)) != NULL) 328510d8b0cSniklas if ( *(p + strlen (p)) && *(p + strlen(p)) != ',') 329510d8b0cSniklas p += strlen(p); 330510d8b0cSniklas else 331510d8b0cSniklas return 1; 332510d8b0cSniklas } 333510d8b0cSniklas return 0; 334510d8b0cSniklas } 335510d8b0cSniklas 336510d8b0cSniklas void 337510d8b0cSniklas conf_load_defaults (int tr) 338510d8b0cSniklas { 339510d8b0cSniklas int enc, auth, hash, proto, mode, pfs; 340510d8b0cSniklas char sect[256]; 341510d8b0cSniklas 342510d8b0cSniklas char *mm_auth[] = { "PRE_SHARED", "DSS", "RSA_SIG", NULL }; 343510d8b0cSniklas char *mm_hash[] = { "MD5", "SHA", NULL }; 344510d8b0cSniklas char *mm_enc[] = { "DES_CBC", "BLOWFISH_CBC", "3DES_CBC", 345510d8b0cSniklas "CAST_CBC", NULL }; 346510d8b0cSniklas char *dh_group[] = { "MODP_768", "MODP_1024", "MODP_1536", NULL }; 347510d8b0cSniklas char *qm_enc[] = { "DES", "3DES", "CAST", "BLOWFISH", NULL }; 348510d8b0cSniklas char *qm_hash[] = { "HMAC_MD5", "HMAC_SHA", "NONE", NULL }; 349510d8b0cSniklas 350510d8b0cSniklas /* Abbreviations to make section names a bit shorter. */ 351510d8b0cSniklas char *mm_auth_p[] = { "", "-DSS", "-RSA_SIG", NULL }; 352510d8b0cSniklas char *mm_enc_p[] = { "DES", "BLF", "3DES", "CAST", NULL }; 353510d8b0cSniklas char *qm_enc_p[] = { "-DES", "-3DES", "-CAST", "-BLF", NULL }; 354510d8b0cSniklas char *qm_hash_p[] = { "-MD5", "-SHA", "", NULL }; 355510d8b0cSniklas 356510d8b0cSniklas /* Helper #defines, incl abbreviations. */ 357510d8b0cSniklas #define PROTO(x) ((x) ? "AH" : "ESP") 358510d8b0cSniklas #define PFS(x) ((x) ? "-PFS" : "") 359510d8b0cSniklas #define MODE(x) ((x) ? "TRANSPORT" : "TUNNEL") 360510d8b0cSniklas #define MODE_p(x) ((x) ? "-TRP" : "") 361510d8b0cSniklas 362510d8b0cSniklas /* General and X509 defaults */ 363510d8b0cSniklas conf_set (tr, "General", "Retransmits", CONF_DFLT_RETRANSMITS, 0, 1); 364510d8b0cSniklas conf_set (tr, "General", "Exchange-max-time", CONF_DFLT_EXCH_MAX_TIME, 0, 1); 365510d8b0cSniklas conf_set (tr, "General", "Policy-file", CONF_DFLT_POLICY_FILE, 0, 1); 366510d8b0cSniklas 367510d8b0cSniklas #ifdef USE_X509 368510d8b0cSniklas conf_set (tr, "X509-certificates", "CA-directory", CONF_DFLT_X509_CA_DIR, 0, 369510d8b0cSniklas 1); 370510d8b0cSniklas conf_set (tr, "X509-certificates", "Cert-directory", CONF_DFLT_X509_CERT_DIR, 371510d8b0cSniklas 0, 1); 372510d8b0cSniklas conf_set (tr, "X509-certificates", "Private-key", CONF_DFLT_X509_PRIVATE_KEY, 373510d8b0cSniklas 0, 1); 374510d8b0cSniklas #endif 375510d8b0cSniklas 376510d8b0cSniklas /* Main modes */ 377510d8b0cSniklas for (enc = 0; mm_enc[enc]; enc ++) 378510d8b0cSniklas for (hash = 0; mm_hash[hash]; hash ++) 379510d8b0cSniklas for (auth = 0; mm_auth[auth]; auth ++) 380510d8b0cSniklas { 381510d8b0cSniklas sprintf (sect, "%s-%s%s", mm_enc_p[enc], mm_hash[hash], 382510d8b0cSniklas mm_auth_p[auth]); 383510d8b0cSniklas 384510d8b0cSniklas if (!conf_find_trans_xf (1, sect)) 385510d8b0cSniklas continue; 386510d8b0cSniklas 387510d8b0cSniklas LOG_DBG ((LOG_MISC, 40, "conf_load_defaults : main mode %s", sect)); 388510d8b0cSniklas 389510d8b0cSniklas conf_set (tr, sect, "ENCRYPTION_ALGORITHM", mm_enc[enc], 0, 1); 390510d8b0cSniklas if (!strcmp (mm_enc[enc], "BLOWFISH_CBC")) 391510d8b0cSniklas conf_set (tr, sect, "KEY_LENGTH", CONF_DFLT_VAL_BLF_KEYLEN, 0, 1); 392510d8b0cSniklas 393510d8b0cSniklas conf_set (tr, sect, "HASH_ALGORITHM", mm_hash[hash], 0, 1); 394510d8b0cSniklas conf_set (tr, sect, "AUTHENTICATION_METHOD", mm_auth[auth], 0, 1); 395510d8b0cSniklas 396510d8b0cSniklas /* XXX Assumes md5 -> modp768 and sha -> modp1024 */ 397510d8b0cSniklas conf_set (tr, sect, "GROUP_DESCRIPTION", dh_group[hash], 0, 1); 398510d8b0cSniklas 399510d8b0cSniklas conf_set (tr, sect, "Life", CONF_DFLT_TAG_LIFE_MAIN_MODE, 0, 1); 400510d8b0cSniklas } 401510d8b0cSniklas 402510d8b0cSniklas /* Quick modes */ 403510d8b0cSniklas for (enc = 0; qm_enc[enc]; enc ++) 404510d8b0cSniklas for (proto = 0; proto < 2; proto ++) 405510d8b0cSniklas for (mode = 0; mode < 2; mode ++) 406510d8b0cSniklas for (pfs = 0; pfs < 2; pfs ++) 407510d8b0cSniklas for (hash = 0; qm_hash[hash]; hash ++) 408510d8b0cSniklas if ((proto == 1 && /* AH */ 409510d8b0cSniklas !strcmp (qm_hash[hash], "NONE"))) 410510d8b0cSniklas continue; 411510d8b0cSniklas else 412510d8b0cSniklas { 413510d8b0cSniklas char tmp[256]; 414510d8b0cSniklas 415510d8b0cSniklas sprintf (tmp, "QM-%s%s%s%s%s", PROTO (proto), MODE_p (mode), 416510d8b0cSniklas qm_enc_p[enc], qm_hash_p[hash], PFS (pfs)); 417510d8b0cSniklas 418510d8b0cSniklas strcpy (sect, tmp); 419510d8b0cSniklas strcat (sect, "-SUITE"); 420510d8b0cSniklas 421510d8b0cSniklas if (!conf_find_trans_xf (2, sect)) 422510d8b0cSniklas continue; 423510d8b0cSniklas 424510d8b0cSniklas LOG_DBG ((LOG_MISC, 40, "conf_load_defaults : quick mode %s", 425510d8b0cSniklas sect)); 426510d8b0cSniklas 427510d8b0cSniklas conf_set (tr, sect, "Protocols", tmp, 0, 1); 428510d8b0cSniklas 429510d8b0cSniklas sprintf (sect, "IPSEC_%s", PROTO (proto)); 430510d8b0cSniklas conf_set (tr, tmp, "PROTOCOL_ID", sect, 0, 1); 431510d8b0cSniklas 432510d8b0cSniklas strcpy (sect, tmp); 433510d8b0cSniklas strcat (sect, "-XF"); 434510d8b0cSniklas conf_set (tr, tmp, "Transforms", sect, 0, 1); 435510d8b0cSniklas 436510d8b0cSniklas /* XXX For now, defaults contain just one xf per protocol. */ 437510d8b0cSniklas 438510d8b0cSniklas conf_set (tr, sect, "TRANSFORM_ID", qm_enc[enc], 0, 1); 439510d8b0cSniklas 440510d8b0cSniklas if (!strcmp (qm_enc[enc], "BLOWFISH")) 441510d8b0cSniklas conf_set (tr, sect, "KEY_LENGTH", CONF_DFLT_VAL_BLF_KEYLEN, 442510d8b0cSniklas 0, 1); 443510d8b0cSniklas 444510d8b0cSniklas conf_set (tr, sect, "ENCAPSULATION_MODE", MODE (mode), 0, 1); 445510d8b0cSniklas 446510d8b0cSniklas if (strcmp (qm_hash[hash], "NONE")) 447510d8b0cSniklas { 448510d8b0cSniklas conf_set (tr, sect, "AUTHENTICATION_ALGORITHM", 449510d8b0cSniklas qm_hash[hash], 0, 1); 450510d8b0cSniklas 451510d8b0cSniklas /* XXX Another shortcut -- to keep length down. */ 452510d8b0cSniklas if (pfs) 453510d8b0cSniklas conf_set (tr, sect, "GROUP_DESCRIPTION", 454510d8b0cSniklas dh_group[ ((hash<2) ? hash : 1) ], 0, 1); 455510d8b0cSniklas } 456510d8b0cSniklas 457510d8b0cSniklas /* XXX Lifetimes depending on enc/auth strength? */ 458510d8b0cSniklas conf_set (tr, sect, "Life", CONF_DFLT_TAG_LIFE_QUICK_MODE, 0, 459510d8b0cSniklas 1); 460510d8b0cSniklas } 461510d8b0cSniklas 462510d8b0cSniklas /* Lifetimes */ 463510d8b0cSniklas conf_set (tr, CONF_DFLT_TAG_LIFE_MAIN_MODE, "LIFE_TYPE", 464510d8b0cSniklas CONF_DFLT_TYPE_LIFE_MAIN_MODE, 0, 1); 465510d8b0cSniklas conf_set (tr, CONF_DFLT_TAG_LIFE_MAIN_MODE, "LIFE_DURATION", 466510d8b0cSniklas CONF_DFLT_VAL_LIFE_MAIN_MODE, 0, 1); 467510d8b0cSniklas 468510d8b0cSniklas conf_set (tr, CONF_DFLT_TAG_LIFE_QUICK_MODE, "LIFE_TYPE", 469510d8b0cSniklas CONF_DFLT_TYPE_LIFE_QUICK_MODE, 0, 1); 470510d8b0cSniklas conf_set (tr, CONF_DFLT_TAG_LIFE_QUICK_MODE, "LIFE_DURATION", 471510d8b0cSniklas CONF_DFLT_VAL_LIFE_QUICK_MODE, 0, 1); 472510d8b0cSniklas 473510d8b0cSniklas return; 474510d8b0cSniklas } 475510d8b0cSniklas 4762040585eSniklas void 4772040585eSniklas conf_init (void) 4782040585eSniklas { 479f8f1e192Sniklas int i; 4802040585eSniklas 481f8f1e192Sniklas for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++) 482f8f1e192Sniklas LIST_INIT (&conf_bindings[i]); 483f8f1e192Sniklas TAILQ_INIT (&conf_trans_queue); 484f8f1e192Sniklas conf_reinit (); 4852040585eSniklas } 4862040585eSniklas 487f8f1e192Sniklas /* Open the config file and map it into our address space, then parse it. */ 488f8f1e192Sniklas void 489f8f1e192Sniklas conf_reinit (void) 490f8f1e192Sniklas { 491f8f1e192Sniklas struct conf_binding *cb = 0; 492f8f1e192Sniklas int fd, i, trans; 493f8f1e192Sniklas struct stat st; 494f8f1e192Sniklas off_t sz; 495f8f1e192Sniklas char *new_conf_addr = 0; 496f8f1e192Sniklas 4972040585eSniklas fd = open (conf_path, O_RDONLY); 4982040585eSniklas if (fd == -1) 499f8f1e192Sniklas { 500757a19b2Sniklas log_error ("conf_reinit: open (\"%s\", O_RDONLY) failed", conf_path); 501f8f1e192Sniklas return; 502f8f1e192Sniklas } 5032040585eSniklas if (fstat (fd, &st) == -1) 504f8f1e192Sniklas { 505757a19b2Sniklas log_error ("conf_reinit: fstat (%d, &st) failed", fd); 506f8f1e192Sniklas goto fail; 507f8f1e192Sniklas } 508510d8b0cSniklas if (st.st_uid != geteuid () && st.st_uid != getuid ()) 509510d8b0cSniklas { 510510d8b0cSniklas log_print ("conf_reinit: not loading %s - file owner is not process " 511510d8b0cSniklas "user", conf_path); 512510d8b0cSniklas close (fd); 513510d8b0cSniklas return; 514510d8b0cSniklas } 515510d8b0cSniklas if ((st.st_mode & (S_IRWXG | S_IRWXO)) != 0) 516510d8b0cSniklas { 517510d8b0cSniklas log_print ("conf_reinit: not loading %s - too open permissions", 518510d8b0cSniklas conf_path); 519510d8b0cSniklas close (fd); 520510d8b0cSniklas return; 521510d8b0cSniklas } 522f8f1e192Sniklas sz = st.st_size; 523f8f1e192Sniklas new_conf_addr = malloc (sz); 524f8f1e192Sniklas if (!new_conf_addr) 525f8f1e192Sniklas { 526757a19b2Sniklas log_error ("conf_reinit: malloc (%d) failed", sz); 527f8f1e192Sniklas goto fail; 528f8f1e192Sniklas } 5292040585eSniklas /* XXX I assume short reads won't happen here. */ 530f8f1e192Sniklas if (read (fd, new_conf_addr, sz) != sz) 531f8f1e192Sniklas { 532757a19b2Sniklas log_error ("conf_reinit: read (%d, %p, %d) failed", fd, new_conf_addr, 533757a19b2Sniklas sz); 534f8f1e192Sniklas goto fail; 535f8f1e192Sniklas } 5362040585eSniklas close (fd); 5372040585eSniklas 538f8f1e192Sniklas trans = conf_begin (); 539f8f1e192Sniklas 540f8f1e192Sniklas /* XXX Should we not care about errors and rollback? */ 541f8f1e192Sniklas conf_parse (trans, new_conf_addr, sz); 542f8f1e192Sniklas 543510d8b0cSniklas /* Load default configuration values. */ 544510d8b0cSniklas conf_load_defaults (trans); 545510d8b0cSniklas 546f8f1e192Sniklas /* Free potential existing configuration. */ 547f8f1e192Sniklas if (conf_addr) 548f8f1e192Sniklas { 549f8f1e192Sniklas for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++) 550f8f1e192Sniklas for (cb = LIST_FIRST (&conf_bindings[i]); cb; 551f8f1e192Sniklas cb = LIST_FIRST (&conf_bindings[i])) 552f8f1e192Sniklas conf_remove_now (cb->section, cb->tag); 553f8f1e192Sniklas free (conf_addr); 554f8f1e192Sniklas } 555f8f1e192Sniklas 556f8f1e192Sniklas conf_end (trans, 1); 557f8f1e192Sniklas conf_addr = new_conf_addr; 558f8f1e192Sniklas return; 559f8f1e192Sniklas 560f8f1e192Sniklas fail: 561f8f1e192Sniklas if (new_conf_addr) 562f8f1e192Sniklas free (new_conf_addr); 563f8f1e192Sniklas close (fd); 5642040585eSniklas } 5652040585eSniklas 566a2d30fd1Sniklas /* 567a2d30fd1Sniklas * Return the numeric value denoted by TAG in section SECTION or DEF 568a2d30fd1Sniklas * if that tag does not exist. 569a2d30fd1Sniklas */ 5702040585eSniklas int 571a2d30fd1Sniklas conf_get_num (char *section, char *tag, int def) 5722040585eSniklas { 5732040585eSniklas char *value = conf_get_str (section, tag); 5742040585eSniklas 5752040585eSniklas if (value) 5762040585eSniklas return atoi (value); 577a2d30fd1Sniklas return def; 5782040585eSniklas } 5792040585eSniklas 58082d8fe06Sniklas /* Validate X according to the range denoted by TAG in section SECTION. */ 58182d8fe06Sniklas int 58282d8fe06Sniklas conf_match_num (char *section, char *tag, int x) 58382d8fe06Sniklas { 58482d8fe06Sniklas char *value = conf_get_str (section, tag); 58582d8fe06Sniklas int val, min, max, n; 58682d8fe06Sniklas 58782d8fe06Sniklas if (!value) 58882d8fe06Sniklas return 0; 58982d8fe06Sniklas n = sscanf (value, "%d,%d:%d", &val, &min, &max); 59082d8fe06Sniklas switch (n) 59182d8fe06Sniklas { 59282d8fe06Sniklas case 1: 59351ca15aeSniklas LOG_DBG ((LOG_MISC, 90, "conf_match_num: %s:%s %d==%d?", section, tag, 59451ca15aeSniklas val, x)); 59582d8fe06Sniklas return x == val; 59682d8fe06Sniklas case 3: 59751ca15aeSniklas LOG_DBG ((LOG_MISC, 90, "conf_match_num: %s:%s %d<=%d<=%d?", section, 59851ca15aeSniklas tag, min, x, max)); 59982d8fe06Sniklas return min <= x && max >= x; 60082d8fe06Sniklas default: 60182d8fe06Sniklas log_error ("conf_match_num: section %s tag %s: invalid number spec %s", 60282d8fe06Sniklas section, tag, value); 60382d8fe06Sniklas } 60482d8fe06Sniklas return 0; 60582d8fe06Sniklas } 60682d8fe06Sniklas 6072040585eSniklas /* Return the string value denoted by TAG in section SECTION. */ 6082040585eSniklas char * 6092040585eSniklas conf_get_str (char *section, char *tag) 6102040585eSniklas { 6112040585eSniklas struct conf_binding *cb; 6122040585eSniklas 613f8f1e192Sniklas for (cb = LIST_FIRST (&conf_bindings[conf_hash (section)]); cb; 614f8f1e192Sniklas cb = LIST_NEXT (cb, link)) 6152040585eSniklas if (strcasecmp (section, cb->section) == 0 6162040585eSniklas && strcasecmp (tag, cb->tag) == 0) 6172040585eSniklas { 61851ca15aeSniklas LOG_DBG ((LOG_MISC, 60, "conf_get_str: [%s]:%s->%s", section, 61951ca15aeSniklas tag, cb->value)); 6202040585eSniklas return cb->value; 6212040585eSniklas } 62251ca15aeSniklas LOG_DBG ((LOG_MISC, 60, 623f8f1e192Sniklas "conf_get_str: configuration value not found [%s]:%s", section, 62451ca15aeSniklas tag)); 6252040585eSniklas return 0; 6262040585eSniklas } 6272040585eSniklas 628a9753648Sniklas /* 629a9753648Sniklas * Build a list of string values out of the comma separated value denoted by 630a9753648Sniklas * TAG in SECTION. 631a9753648Sniklas */ 6322040585eSniklas struct conf_list * 6332040585eSniklas conf_get_list (char *section, char *tag) 6342040585eSniklas { 6352040585eSniklas char *liststr = 0, *p, *field; 6362040585eSniklas struct conf_list *list = 0; 6372040585eSniklas struct conf_list_node *node; 6382040585eSniklas 6392040585eSniklas list = malloc (sizeof *list); 6402040585eSniklas if (!list) 6412040585eSniklas goto cleanup; 6422040585eSniklas TAILQ_INIT (&list->fields); 6432040585eSniklas list->cnt = 0; 6442040585eSniklas liststr = conf_get_str (section, tag); 6452040585eSniklas if (!liststr) 6462040585eSniklas goto cleanup; 6472040585eSniklas liststr = strdup (liststr); 6482040585eSniklas if (!liststr) 6492040585eSniklas goto cleanup; 6502040585eSniklas p = liststr; 6512040585eSniklas while ((field = strsep (&p, ", \t")) != NULL) 6522040585eSniklas { 6532040585eSniklas if (*field == '\0') 6542040585eSniklas { 6552040585eSniklas log_print ("conf_get_list: empty field, ignoring..."); 6562040585eSniklas continue; 6572040585eSniklas } 6582040585eSniklas list->cnt++; 659a9753648Sniklas node = calloc (1, sizeof *node); 6602040585eSniklas if (!node) 6612040585eSniklas goto cleanup; 662a9753648Sniklas node->field = strdup (field); 663a9753648Sniklas if (!node->field) 664a9753648Sniklas goto cleanup; 6652040585eSniklas TAILQ_INSERT_TAIL (&list->fields, node, link); 6662040585eSniklas } 667a9753648Sniklas free (liststr); 6682040585eSniklas return list; 6692040585eSniklas 6702040585eSniklas cleanup: 6712040585eSniklas if (list) 6722040585eSniklas conf_free_list (list); 6732040585eSniklas if (liststr) 6742040585eSniklas free (liststr); 6752040585eSniklas return 0; 6762040585eSniklas } 6772040585eSniklas 67882d8fe06Sniklas struct conf_list * 67982d8fe06Sniklas conf_get_tag_list (char *section) 68082d8fe06Sniklas { 68182d8fe06Sniklas struct conf_list *list = 0; 68282d8fe06Sniklas struct conf_list_node *node; 68382d8fe06Sniklas struct conf_binding *cb; 68482d8fe06Sniklas 68582d8fe06Sniklas list = malloc (sizeof *list); 68682d8fe06Sniklas if (!list) 68782d8fe06Sniklas goto cleanup; 68882d8fe06Sniklas TAILQ_INIT (&list->fields); 68982d8fe06Sniklas list->cnt = 0; 690f8f1e192Sniklas for (cb = LIST_FIRST (&conf_bindings[conf_hash (section)]); cb; 691f8f1e192Sniklas cb = LIST_NEXT (cb, link)) 69282d8fe06Sniklas if (strcasecmp (section, cb->section) == 0) 69382d8fe06Sniklas { 69482d8fe06Sniklas list->cnt++; 695a9753648Sniklas node = calloc (1, sizeof *node); 69682d8fe06Sniklas if (!node) 69782d8fe06Sniklas goto cleanup; 698a9753648Sniklas node->field = strdup (cb->tag); 699a9753648Sniklas if (!node->field) 700a9753648Sniklas goto cleanup; 70182d8fe06Sniklas TAILQ_INSERT_TAIL (&list->fields, node, link); 70282d8fe06Sniklas } 70382d8fe06Sniklas return list; 70482d8fe06Sniklas 70582d8fe06Sniklas cleanup: 70682d8fe06Sniklas if (list) 70782d8fe06Sniklas conf_free_list (list); 70882d8fe06Sniklas return 0; 70982d8fe06Sniklas } 71082d8fe06Sniklas 7112040585eSniklas /* Decode a PEM encoded buffer. */ 7122040585eSniklas int 7132040585eSniklas conf_decode_base64 (u_int8_t *out, u_int32_t *len, u_char *buf) 7142040585eSniklas { 7152040585eSniklas u_int32_t c = 0; 7162040585eSniklas u_int8_t c1, c2, c3, c4; 7172040585eSniklas 7182040585eSniklas while (*buf) 7192040585eSniklas { 7202040585eSniklas if (*buf > 127 || (c1 = asc2bin[*buf]) == 255) 7212040585eSniklas return 0; 7222040585eSniklas buf++; 7232040585eSniklas 7242040585eSniklas if (*buf > 127 || (c2 = asc2bin[*buf]) == 255) 7252040585eSniklas return 0; 7262040585eSniklas buf++; 7272040585eSniklas 7282040585eSniklas if (*buf == '=') 7292040585eSniklas { 7302040585eSniklas c3 = c4 = 0; 7312040585eSniklas c++; 7322040585eSniklas 7332040585eSniklas /* Check last four bit */ 7342040585eSniklas if (c2 & 0xF) 7352040585eSniklas return 0; 7362040585eSniklas 7372040585eSniklas if (!strcmp (buf, "==")) 7382040585eSniklas buf++; 7392040585eSniklas else 7402040585eSniklas return 0; 7412040585eSniklas } 7422040585eSniklas else if (*buf > 127 || (c3 = asc2bin[*buf]) == 255) 7432040585eSniklas return 0; 7442040585eSniklas else 7452040585eSniklas { 7462040585eSniklas if (*++buf == '=') 7472040585eSniklas { 7482040585eSniklas c4 = 0; 7492040585eSniklas c += 2; 7502040585eSniklas 7512040585eSniklas /* Check last two bit */ 7522040585eSniklas if (c3 & 3) 7532040585eSniklas return 0; 7542040585eSniklas 7552040585eSniklas if (strcmp (buf, "=")) 7562040585eSniklas return 0; 7572040585eSniklas 7582040585eSniklas } 7592040585eSniklas else if (*buf > 127 || (c4 = asc2bin[*buf]) == 255) 7602040585eSniklas return 0; 7612040585eSniklas else 7622040585eSniklas c += 3; 7632040585eSniklas } 7642040585eSniklas 7652040585eSniklas buf++; 7662040585eSniklas *out++ = (c1 << 2) | (c2 >> 4); 7672040585eSniklas *out++ = (c2 << 4) | (c3 >> 2); 7682040585eSniklas *out++ = (c3 << 6) | c4; 7692040585eSniklas } 7702040585eSniklas 7712040585eSniklas *len = c; 7722040585eSniklas return 1; 7732040585eSniklas 7742040585eSniklas } 7752040585eSniklas 7762040585eSniklas /* Read a line from a stream to the buffer. */ 7772040585eSniklas int 7782040585eSniklas conf_get_line (FILE *stream, char *buf, u_int32_t len) 7792040585eSniklas { 7802040585eSniklas char c; 7812040585eSniklas 7822040585eSniklas while (len-- > 1) 7832040585eSniklas { 7842040585eSniklas c = fgetc (stream); 7852040585eSniklas if (c == '\n') 7862040585eSniklas { 7872040585eSniklas *buf = 0; 7882040585eSniklas return 1; 7892040585eSniklas } 7902040585eSniklas else if (c == EOF) 7912040585eSniklas break; 7922040585eSniklas 7932040585eSniklas *buf++ = c; 7942040585eSniklas } 7952040585eSniklas 7962040585eSniklas *buf = 0; 7972040585eSniklas return 0; 7982040585eSniklas } 7992040585eSniklas 8002040585eSniklas void 8012040585eSniklas conf_free_list (struct conf_list *list) 8022040585eSniklas { 803a9753648Sniklas struct conf_list_node *node = TAILQ_FIRST (&list->fields); 804a9753648Sniklas 805a9753648Sniklas while (node) 806a9753648Sniklas { 807a9753648Sniklas TAILQ_REMOVE (&list->fields, node, link); 808a9753648Sniklas if (node->field) 809a9753648Sniklas free (node->field); 810a9753648Sniklas free (node); 811a9753648Sniklas node = TAILQ_FIRST (&list->fields); 812a9753648Sniklas } 8132040585eSniklas free (list); 8142040585eSniklas } 815f8f1e192Sniklas 816f8f1e192Sniklas int 817f8f1e192Sniklas conf_begin (void) 818f8f1e192Sniklas { 819f8f1e192Sniklas static int seq = 0; 820f8f1e192Sniklas 821f8f1e192Sniklas return ++seq; 822f8f1e192Sniklas } 823f8f1e192Sniklas 824f8f1e192Sniklas static struct conf_trans * 825f8f1e192Sniklas conf_trans_node (int transaction, enum conf_op op) 826f8f1e192Sniklas { 827f8f1e192Sniklas struct conf_trans *node; 828f8f1e192Sniklas 829f8f1e192Sniklas node = calloc (1, sizeof *node); 830f8f1e192Sniklas if (!node) 831f8f1e192Sniklas { 832f8f1e192Sniklas log_error ("conf_trans_node: calloc (1, %d) failed", sizeof *node); 833f8f1e192Sniklas return 0; 834f8f1e192Sniklas } 835f8f1e192Sniklas node->trans = transaction; 836f8f1e192Sniklas node->op = op; 837f8f1e192Sniklas TAILQ_INSERT_TAIL (&conf_trans_queue, node, link); 838f8f1e192Sniklas return node; 839f8f1e192Sniklas } 840f8f1e192Sniklas 841f8f1e192Sniklas /* Queue a set operation. */ 842f8f1e192Sniklas int 843510d8b0cSniklas conf_set (int transaction, char *section, char *tag, char *value, int override, 844510d8b0cSniklas int is_default) 845f8f1e192Sniklas { 846f8f1e192Sniklas struct conf_trans *node; 847f8f1e192Sniklas 848f8f1e192Sniklas node = conf_trans_node (transaction, CONF_SET); 849f8f1e192Sniklas if (!node) 850f8f1e192Sniklas return 1; 851f8f1e192Sniklas node->section = strdup (section); 852f8f1e192Sniklas if (!node->section) 853f8f1e192Sniklas { 854f8f1e192Sniklas log_error ("conf_set: strdup (\"%s\") failed", section); 855f8f1e192Sniklas goto fail; 856f8f1e192Sniklas } 857f8f1e192Sniklas node->tag = strdup (tag); 858f8f1e192Sniklas if (!node->tag) 859f8f1e192Sniklas { 860f8f1e192Sniklas log_error ("conf_set: strdup (\"%s\") failed", tag); 861f8f1e192Sniklas goto fail; 862f8f1e192Sniklas } 863f8f1e192Sniklas node->value = strdup (value); 864f8f1e192Sniklas if (!node->value) 865f8f1e192Sniklas { 866f8f1e192Sniklas log_error ("conf_set: strdup (\"%s\") failed", value); 867f8f1e192Sniklas goto fail; 868f8f1e192Sniklas } 869f8f1e192Sniklas node->override = override; 870510d8b0cSniklas node->is_default = is_default; 871f8f1e192Sniklas return 0; 872f8f1e192Sniklas 873f8f1e192Sniklas fail: 874f8f1e192Sniklas if (node->tag) 875f8f1e192Sniklas free (node->tag); 876f8f1e192Sniklas if (node->section) 877f8f1e192Sniklas free (node->section); 878f8f1e192Sniklas if (node) 879f8f1e192Sniklas free (node); 880f8f1e192Sniklas return 1; 881f8f1e192Sniklas } 882f8f1e192Sniklas 883f8f1e192Sniklas /* Queue a remove operation. */ 884f8f1e192Sniklas int 885f8f1e192Sniklas conf_remove (int transaction, char *section, char *tag) 886f8f1e192Sniklas { 887f8f1e192Sniklas struct conf_trans *node; 888f8f1e192Sniklas 889f8f1e192Sniklas node = conf_trans_node (transaction, CONF_REMOVE); 890f8f1e192Sniklas if (!node) 891f8f1e192Sniklas goto fail; 892f8f1e192Sniklas node->section = strdup (section); 893f8f1e192Sniklas if (!node->section) 894f8f1e192Sniklas { 895f8f1e192Sniklas log_error ("conf_remove: strdup (\"%s\") failed", section); 896f8f1e192Sniklas goto fail; 897f8f1e192Sniklas } 898f8f1e192Sniklas node->tag = strdup (tag); 899f8f1e192Sniklas if (!node->tag) 900f8f1e192Sniklas { 901f8f1e192Sniklas log_error ("conf_remove: strdup (\"%s\") failed", tag); 902f8f1e192Sniklas goto fail; 903f8f1e192Sniklas } 904f8f1e192Sniklas return 0; 905f8f1e192Sniklas 906f8f1e192Sniklas fail: 907f8f1e192Sniklas if (node->section) 908f8f1e192Sniklas free (node->section); 909f8f1e192Sniklas if (node) 910f8f1e192Sniklas free (node); 911f8f1e192Sniklas return 1; 912f8f1e192Sniklas } 913f8f1e192Sniklas 914f8f1e192Sniklas /* Queue a remove section operation. */ 915f8f1e192Sniklas int 916f8f1e192Sniklas conf_remove_section (int transaction, char *section) 917f8f1e192Sniklas { 918f8f1e192Sniklas struct conf_trans *node; 919f8f1e192Sniklas 920f8f1e192Sniklas node = conf_trans_node (transaction, CONF_REMOVE_SECTION); 921f8f1e192Sniklas if (!node) 922f8f1e192Sniklas goto fail; 923f8f1e192Sniklas node->section = strdup (section); 924f8f1e192Sniklas if (!node->section) 925f8f1e192Sniklas { 926f8f1e192Sniklas log_error ("conf_remove_section: strdup (\"%s\") failed", section); 927f8f1e192Sniklas goto fail; 928f8f1e192Sniklas } 929f8f1e192Sniklas return 0; 930f8f1e192Sniklas 931f8f1e192Sniklas fail: 932f8f1e192Sniklas if (node) 933f8f1e192Sniklas free (node); 934f8f1e192Sniklas return 1; 935f8f1e192Sniklas } 936f8f1e192Sniklas 937f8f1e192Sniklas /* Execute all queued operations for this transaction. Cleanup. */ 938f8f1e192Sniklas int 939f8f1e192Sniklas conf_end (int transaction, int commit) 940f8f1e192Sniklas { 941f8f1e192Sniklas struct conf_trans *node, *next; 942f8f1e192Sniklas 943f8f1e192Sniklas for (node = TAILQ_FIRST (&conf_trans_queue); node; node = next) 944f8f1e192Sniklas { 945f8f1e192Sniklas next = TAILQ_NEXT (node, link); 946f8f1e192Sniklas if (node->trans == transaction) 947f8f1e192Sniklas { 948f8f1e192Sniklas if (commit) 949f8f1e192Sniklas switch (node->op) 950f8f1e192Sniklas { 951f8f1e192Sniklas case CONF_SET: 952f8f1e192Sniklas conf_set_now (node->section, node->tag, node->value, 953510d8b0cSniklas node->override, node->is_default); 954f8f1e192Sniklas break; 955f8f1e192Sniklas case CONF_REMOVE: 956f8f1e192Sniklas conf_remove_now (node->section, node->tag); 957f8f1e192Sniklas break; 958f8f1e192Sniklas case CONF_REMOVE_SECTION: 959f8f1e192Sniklas conf_remove_section_now (node->section); 960f8f1e192Sniklas break; 961f8f1e192Sniklas default: 962f8f1e192Sniklas log_print ("conf_end: unknown operation: %d", node->op); 963f8f1e192Sniklas } 964f8f1e192Sniklas TAILQ_REMOVE (&conf_trans_queue, node, link); 965f8f1e192Sniklas free (node); 966f8f1e192Sniklas } 967f8f1e192Sniklas } 968f8f1e192Sniklas return 0; 969f8f1e192Sniklas } 970510d8b0cSniklas 971510d8b0cSniklas /* Dump running configuration upon SIGUSR1. */ 972510d8b0cSniklas /* XXX Configuration is "stored in reverse order", so reverse it. */ 973510d8b0cSniklas struct dumper { 974510d8b0cSniklas char *s, *v; 975510d8b0cSniklas struct dumper *next; 976510d8b0cSniklas }; 977510d8b0cSniklas 978510d8b0cSniklas static void 979510d8b0cSniklas conf_report_dump (struct dumper *node) 980510d8b0cSniklas { 981510d8b0cSniklas /* Recursive, cleanup when we're done. */ 982510d8b0cSniklas 983510d8b0cSniklas if (node->next) 984510d8b0cSniklas conf_report_dump (node->next); 985510d8b0cSniklas 986510d8b0cSniklas if (node->v) 987510d8b0cSniklas LOG_DBG ((LOG_REPORT, 0, "%s=\t%s", node->s, node->v)); 988510d8b0cSniklas else 989510d8b0cSniklas { 990510d8b0cSniklas LOG_DBG ((LOG_REPORT, 0, "%s", node->s)); 991510d8b0cSniklas if (strlen (node->s) > 0) 992510d8b0cSniklas free (node->s); 993510d8b0cSniklas } 994510d8b0cSniklas 995510d8b0cSniklas free (node); 996510d8b0cSniklas } 997510d8b0cSniklas 998510d8b0cSniklas void 999510d8b0cSniklas conf_report (void) 1000510d8b0cSniklas { 1001510d8b0cSniklas struct conf_binding *cb, *last = NULL; 1002510d8b0cSniklas int i; 1003510d8b0cSniklas char *current_section = (char *)0; 1004510d8b0cSniklas struct dumper *dumper, *dnode; 1005510d8b0cSniklas 1006*592a196eSniklas dumper = dnode = (struct dumper *)calloc (1, sizeof *dumper); 1007510d8b0cSniklas if (!dumper) 1008510d8b0cSniklas goto mem_fail; 1009510d8b0cSniklas 1010510d8b0cSniklas LOG_DBG ((LOG_REPORT, 0, "conf_report: dumping running configuration")); 1011510d8b0cSniklas 1012510d8b0cSniklas for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++) 1013510d8b0cSniklas for (cb = LIST_FIRST (&conf_bindings[i]); cb; 1014510d8b0cSniklas cb = LIST_NEXT (cb, link)) 1015510d8b0cSniklas { 1016510d8b0cSniklas if (!cb->is_default) 1017510d8b0cSniklas { 1018510d8b0cSniklas /* Dump this entry */ 1019510d8b0cSniklas if (!current_section || strcmp (cb->section, current_section)) 1020510d8b0cSniklas { 1021510d8b0cSniklas if (current_section) 1022510d8b0cSniklas { 1023510d8b0cSniklas dnode->s = malloc (strlen (current_section) + 3); 1024510d8b0cSniklas if (!dnode->s) 1025510d8b0cSniklas goto mem_fail; 1026510d8b0cSniklas 1027510d8b0cSniklas sprintf (dnode->s, "[%s]", current_section); 1028*592a196eSniklas dnode->next 1029*592a196eSniklas = (struct dumper *)calloc (1, sizeof (struct dumper)); 1030510d8b0cSniklas dnode = dnode->next; 1031510d8b0cSniklas if (!dnode) 1032510d8b0cSniklas goto mem_fail; 1033510d8b0cSniklas 1034510d8b0cSniklas dnode->s = ""; 1035*592a196eSniklas dnode->next 1036*592a196eSniklas = (struct dumper *)calloc (1, sizeof (struct dumper)); 1037510d8b0cSniklas dnode = dnode->next; 1038510d8b0cSniklas if (!dnode) 1039510d8b0cSniklas goto mem_fail; 1040510d8b0cSniklas } 1041510d8b0cSniklas current_section = cb->section; 1042510d8b0cSniklas } 1043510d8b0cSniklas dnode->s = cb->tag; 1044510d8b0cSniklas dnode->v = cb->value; 1045510d8b0cSniklas dnode->next = (struct dumper *)calloc (1, sizeof (struct dumper)); 1046510d8b0cSniklas dnode = dnode->next; 1047510d8b0cSniklas if (!dnode) 1048510d8b0cSniklas goto mem_fail; 1049510d8b0cSniklas last = cb; 1050510d8b0cSniklas } 1051510d8b0cSniklas } 1052510d8b0cSniklas 1053510d8b0cSniklas if (last) 1054510d8b0cSniklas { 1055510d8b0cSniklas dnode->s = malloc (strlen (last->section) + 3); 1056510d8b0cSniklas if (!dnode->s) 1057510d8b0cSniklas goto mem_fail; 1058510d8b0cSniklas sprintf (dnode->s, "[%s]", last->section); 1059510d8b0cSniklas } 1060510d8b0cSniklas 1061510d8b0cSniklas conf_report_dump (dumper); 1062510d8b0cSniklas 1063510d8b0cSniklas return; 1064510d8b0cSniklas 1065510d8b0cSniklas mem_fail: 1066510d8b0cSniklas LOG_DBG ((LOG_REPORT, 0, "conf_report: memory allocation failure.")); 1067510d8b0cSniklas while ((dnode = dumper) != NULL) 1068510d8b0cSniklas { 1069510d8b0cSniklas dumper = dumper->next; 1070510d8b0cSniklas if (dnode->s) 1071510d8b0cSniklas free (dnode->s); 1072510d8b0cSniklas free (dnode); 1073510d8b0cSniklas } 1074510d8b0cSniklas return; 1075510d8b0cSniklas } 1076