Home | History | Annotate | Line # | Download | only in lloadd
      1 /*	$NetBSD: config.c,v 1.3 2025/09/05 21:16:24 christos Exp $	*/
      2 
      3 /* config.c - configuration file handling routines */
      4 /* $OpenLDAP$ */
      5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      6  *
      7  * Copyright 1998-2024 The OpenLDAP Foundation.
      8  * All rights reserved.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted only as authorized by the OpenLDAP
     12  * Public License.
     13  *
     14  * A copy of this license is available in the file LICENSE in the
     15  * top-level directory of the distribution or, alternatively, at
     16  * <http://www.OpenLDAP.org/license.html>.
     17  */
     18 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
     19  * All rights reserved.
     20  *
     21  * Redistribution and use in source and binary forms are permitted
     22  * provided that this notice is preserved and that due credit is given
     23  * to the University of Michigan at Ann Arbor. The name of the University
     24  * may not be used to endorse or promote products derived from this
     25  * software without specific prior written permission. This software
     26  * is provided ``as is'' without express or implied warranty.
     27  */
     28 
     29 #include <sys/cdefs.h>
     30 __RCSID("$NetBSD: config.c,v 1.3 2025/09/05 21:16:24 christos Exp $");
     31 
     32 #include "portable.h"
     33 
     34 #include <stdio.h>
     35 
     36 #include <ac/string.h>
     37 #include <ac/ctype.h>
     38 #include <ac/signal.h>
     39 #include <ac/socket.h>
     40 #include <ac/errno.h>
     41 #include <ac/unistd.h>
     42 
     43 #include <sys/types.h>
     44 #include <sys/stat.h>
     45 
     46 #ifndef S_ISREG
     47 #define S_ISREG(m) ( ((m) & _S_IFMT ) == _S_IFREG )
     48 #endif
     49 
     50 #include "lload.h"
     51 #include "lutil.h"
     52 #include "lutil_ldap.h"
     53 #include "lload-config.h"
     54 #include "../slapd/slap-cfglog.h"
     55 
     56 #ifdef _WIN32
     57 #define LUTIL_ATOULX lutil_atoullx
     58 #define Z "I"
     59 #else
     60 #define LUTIL_ATOULX lutil_atoulx
     61 #define Z "z"
     62 #endif
     63 
     64 #define ARGS_STEP 512
     65 
     66 /*
     67  * defaults for various global variables
     68  */
     69 #ifdef BALANCER_MODULE
     70 char *listeners_list = NULL;
     71 #else /* !BALANCER_MODULE */
     72 slap_mask_t global_allows = 0;
     73 slap_mask_t global_disallows = 0;
     74 int global_gentlehup = 0;
     75 int global_idletimeout = 0;
     76 char *global_host = NULL;
     77 
     78 char *slapd_pid_file = NULL;
     79 char *slapd_args_file = NULL;
     80 #endif /* !BALANCER_MODULE */
     81 
     82 static struct timeval timeout_api_tv, timeout_net_tv,
     83         timeout_write_tv = { 10, 0 };
     84 
     85 lload_features_t lload_features;
     86 int lload_write_coherence = 0;
     87 
     88 ber_len_t sockbuf_max_incoming_client = LLOAD_SB_MAX_INCOMING_CLIENT;
     89 ber_len_t sockbuf_max_incoming_upstream = LLOAD_SB_MAX_INCOMING_UPSTREAM;
     90 
     91 int lload_conn_max_pdus_per_cycle = LLOAD_CONN_MAX_PDUS_PER_CYCLE_DEFAULT;
     92 
     93 struct timeval *lload_timeout_api = NULL;
     94 struct timeval *lload_timeout_net = NULL;
     95 struct timeval *lload_write_timeout = &timeout_write_tv;
     96 
     97 static int fp_getline( FILE *fp, ConfigArgs *c );
     98 static void fp_getline_init( ConfigArgs *c );
     99 
    100 static char *strtok_quote(
    101         char *line,
    102         char *sep,
    103         char **quote_ptr,
    104         int *inquote );
    105 
    106 typedef struct ConfigFile {
    107     struct ConfigFile *c_sibs;
    108     struct ConfigFile *c_kids;
    109     struct berval c_file;
    110     BerVarray c_dseFiles;
    111 } ConfigFile;
    112 
    113 static ConfigFile *cfn;
    114 
    115 static ConfigDriver config_fname;
    116 static ConfigDriver config_generic;
    117 static ConfigDriver config_tier;
    118 static ConfigDriver config_backend;
    119 static ConfigDriver config_bindconf;
    120 static ConfigDriver config_restrict_oid;
    121 #ifdef LDAP_TCP_BUFFER
    122 static ConfigDriver config_tcp_buffer;
    123 #endif /* LDAP_TCP_BUFFER */
    124 static ConfigDriver config_restrict;
    125 static ConfigDriver config_include;
    126 static ConfigDriver config_feature;
    127 #ifdef HAVE_TLS
    128 static ConfigDriver config_tls_option;
    129 static ConfigDriver config_tls_config;
    130 #endif
    131 #ifdef BALANCER_MODULE
    132 static ConfigDriver config_share_tls_ctx;
    133 static ConfigDriver backend_cf_gen;
    134 #endif /* BALANCER_MODULE */
    135 
    136 struct slap_bindconf bindconf = {};
    137 struct berval lloadd_identity = BER_BVNULL;
    138 
    139 enum {
    140     CFG_ACL = 1,
    141     CFG_BACKEND,
    142     CFG_BINDCONF,
    143     CFG_LISTEN,
    144     CFG_LISTEN_URI,
    145     CFG_TLS_RAND,
    146     CFG_TLS_CIPHER,
    147     CFG_TLS_PROTOCOL_MIN,
    148     CFG_TLS_CERT_FILE,
    149     CFG_TLS_CERT_KEY,
    150     CFG_TLS_CA_PATH,
    151     CFG_TLS_CA_FILE,
    152     CFG_TLS_DH_FILE,
    153     CFG_TLS_VERIFY,
    154     CFG_TLS_CRLCHECK,
    155     CFG_TLS_CRL_FILE,
    156     CFG_TLS_SHARE_CTX,
    157     CFG_CONCUR,
    158     CFG_THREADS,
    159     CFG_MIRRORMODE,
    160     CFG_IOTHREADS,
    161     CFG_MAXBUF_CLIENT,
    162     CFG_MAXBUF_UPSTREAM,
    163     CFG_FEATURE,
    164     CFG_THREADQS,
    165     CFG_TLS_ECNAME,
    166     CFG_TLS_CACERT,
    167     CFG_TLS_CERT,
    168     CFG_TLS_KEY,
    169     CFG_RESCOUNT,
    170     CFG_IOTIMEOUT,
    171     CFG_URI,
    172     CFG_NUMCONNS,
    173     CFG_BINDCONNS,
    174     CFG_RETRY,
    175     CFG_MAX_PENDING_OPS,
    176     CFG_MAX_PENDING_CONNS,
    177     CFG_STARTTLS,
    178     CFG_CLIENT_PENDING,
    179     CFG_RESTRICT_EXOP,
    180     CFG_RESTRICT_CONTROL,
    181     CFG_TIER,
    182     CFG_WEIGHT,
    183 
    184     CFG_LAST
    185 };
    186 
    187 /* alphabetical ordering */
    188 
    189 static ConfigTable config_back_cf_table[] = {
    190     /* This attr is read-only */
    191     { "", "", 0, 0, 0,
    192         ARG_MAGIC,
    193         &config_fname,
    194         NULL, NULL, NULL
    195     },
    196     { "argsfile", "file", 2, 2, 0,
    197         ARG_STRING,
    198         &slapd_args_file,
    199         NULL, NULL, NULL
    200     },
    201     { "concurrency", "level", 2, 2, 0,
    202         ARG_UINT|ARG_MAGIC|CFG_CONCUR,
    203         &config_generic,
    204         NULL, NULL, NULL
    205     },
    206     { "tier", "name", 2, 2, 0,
    207         ARG_MAGIC|ARG_STRING|CFG_TIER,
    208         &config_tier,
    209         "( OLcfgBkAt:13.39 "
    210             "NAME 'olcBkLloadTierType' "
    211             "DESC 'Tier type' "
    212             "EQUALITY caseIgnoreMatch "
    213             "SYNTAX OMsDirectoryString "
    214             "SINGLE-VALUE )",
    215         NULL, NULL
    216     },
    217     /* conf-file only option */
    218     { "backend-server", "backend options", 2, 0, 0,
    219         ARG_MAGIC|CFG_BACKEND,
    220         &config_backend,
    221         NULL, NULL, NULL
    222     },
    223     { "bindconf", "backend credentials", 2, 0, 0,
    224         ARG_MAGIC|CFG_BINDCONF,
    225         &config_bindconf,
    226         "( OLcfgBkAt:13.2 "
    227             "NAME 'olcBkLloadBindconf' "
    228             "DESC 'Backend credentials' "
    229             /* No EQUALITY since this is a compound attribute (and needs
    230              * splitting up anyway - which is a TODO) */
    231             "SYNTAX OMsDirectoryString "
    232             "SINGLE-VALUE )",
    233         NULL, NULL
    234     },
    235     { "gentlehup", "on|off", 2, 2, 0,
    236 #ifdef SIGHUP
    237         ARG_ON_OFF,
    238         &global_gentlehup,
    239 #else
    240         ARG_IGNORED,
    241         NULL,
    242 #endif
    243         NULL, NULL, NULL
    244     },
    245     { "idletimeout", "timeout", 2, 2, 0,
    246         ARG_UINT,
    247         &global_idletimeout,
    248         "( OLcfgBkAt:13.3 "
    249             "NAME 'olcBkLloadIdleTimeout' "
    250             "DESC 'Connection idle timeout' "
    251             "EQUALITY integerMatch "
    252             "SYNTAX OMsInteger "
    253             "SINGLE-VALUE )",
    254         NULL, NULL
    255     },
    256     { "include", "file", 2, 2, 0,
    257         ARG_MAGIC,
    258         &config_include,
    259         NULL, NULL, NULL
    260     },
    261     { "io-threads", "count", 2, 0, 0,
    262         ARG_UINT|ARG_MAGIC|CFG_IOTHREADS,
    263         &config_generic,
    264         "( OLcfgBkAt:13.4 "
    265             "NAME 'olcBkLloadIOThreads' "
    266             "DESC 'I/O thread count' "
    267             "EQUALITY integerMatch "
    268             "SYNTAX OMsInteger "
    269             "SINGLE-VALUE )",
    270         NULL, NULL
    271     },
    272 #ifdef BALANCER_MODULE
    273     { "listen", "uri list", 2, 2, 0,
    274         ARG_STRING|ARG_MAGIC|CFG_LISTEN,
    275         &config_generic,
    276         NULL, NULL, NULL
    277     },
    278     { "", "uri", 2, 2, 0,
    279         ARG_MAGIC|CFG_LISTEN_URI,
    280         &config_generic,
    281         "( OLcfgBkAt:13.5 "
    282             "NAME 'olcBkLloadListen' "
    283             "DESC 'A listener adress' "
    284             /* We don't handle adding/removing a value, so no EQUALITY yet */
    285             "SYNTAX OMsDirectoryString )",
    286         NULL, NULL
    287     },
    288 #endif /* BALANCER_MODULE */
    289     { "logfile", "file", 2, 2, 0,
    290         ARG_STRING|ARG_MAGIC|CFG_LOGFILE,
    291         &config_logging,
    292         NULL, NULL, NULL
    293     },
    294     { "logfile-format", "debug|syslog-utc|syslog-localtime", 2, 2, 0,
    295         ARG_MAGIC|CFG_LOGFILE_FORMAT,
    296         &config_logging,
    297         NULL, NULL, NULL
    298     },
    299     { "logfile-only", "on|off", 2, 2, 0,
    300         ARG_ON_OFF|ARG_MAGIC|CFG_LOGFILE_ONLY,
    301         &config_logging,
    302         NULL, NULL, NULL
    303     },
    304     { "logfile-rotate", "max> <Mbyte> <hours", 4, 4, 0,
    305         ARG_MAGIC|CFG_LOGFILE_ROTATE,
    306         &config_logging,
    307         NULL, NULL, NULL
    308     },
    309     { "loglevel", "level", 2, 0, 0,
    310         ARG_MAGIC|CFG_LOGLEVEL,
    311         &config_logging,
    312         NULL, NULL, NULL
    313     },
    314     { "pidfile", "file", 2, 2, 0,
    315         ARG_STRING,
    316         &slapd_pid_file,
    317         NULL, NULL, NULL
    318     },
    319     { "restrict", "op_list", 2, 0, 0,
    320         ARG_MAGIC,
    321         &config_restrict,
    322         NULL, NULL, NULL
    323     },
    324     { "sockbuf_max_incoming_client", "max", 2, 2, 0,
    325         ARG_BER_LEN_T|ARG_MAGIC|CFG_MAXBUF_CLIENT,
    326         &config_generic,
    327         "( OLcfgBkAt:13.6 "
    328             "NAME 'olcBkLloadSockbufMaxClient' "
    329             "DESC 'The maximum LDAP PDU size accepted coming from clients' "
    330             "EQUALITY integerMatch "
    331             "SYNTAX OMsInteger "
    332             "SINGLE-VALUE )",
    333         NULL,
    334         { .v_ber_t = LLOAD_SB_MAX_INCOMING_CLIENT }
    335     },
    336     { "sockbuf_max_incoming_upstream", "max", 2, 2, 0,
    337         ARG_BER_LEN_T|ARG_MAGIC|CFG_MAXBUF_UPSTREAM,
    338         &config_generic,
    339         "( OLcfgBkAt:13.7 "
    340             "NAME 'olcBkLloadSockbufMaxUpstream' "
    341             "DESC 'The maximum LDAP PDU size accepted coming from upstream' "
    342             "EQUALITY integerMatch "
    343             "SYNTAX OMsInteger "
    344             "SINGLE-VALUE )",
    345         NULL,
    346         { .v_ber_t = LLOAD_SB_MAX_INCOMING_UPSTREAM }
    347     },
    348     { "tcp-buffer", "[listener=<listener>] [{read|write}=]size", 0, 0, 0,
    349 #ifdef LDAP_TCP_BUFFER
    350         ARG_MAGIC,
    351         &config_tcp_buffer,
    352 #else
    353         ARG_IGNORED,
    354         NULL,
    355 #endif
    356         "( OLcfgBkAt:13.8 "
    357             "NAME 'olcBkLloadTcpBuffer' "
    358             "DESC 'TCP Buffer size' "
    359             "EQUALITY caseIgnoreMatch "
    360             "SYNTAX OMsDirectoryString "
    361             "SINGLE-VALUE )",
    362         NULL, NULL
    363     },
    364     { "threads", "count", 2, 2, 0,
    365         ARG_UINT|ARG_MAGIC|CFG_THREADS,
    366         &config_generic,
    367         NULL, NULL, NULL
    368     },
    369     { "threadqueues", "count", 2, 2, 0,
    370         ARG_UINT|ARG_MAGIC|CFG_THREADQS,
    371         &config_generic,
    372         NULL, NULL, NULL
    373     },
    374     { "max_pdus_per_cycle", "count", 2, 2, 0,
    375         ARG_UINT|ARG_MAGIC|CFG_RESCOUNT,
    376         &config_generic,
    377         "( OLcfgBkAt:13.9 "
    378             "NAME 'olcBkLloadMaxPDUPerCycle' "
    379             "DESC 'Maximum number of PDUs to handle in a single cycle' "
    380             "EQUALITY integerMatch "
    381             "SYNTAX OMsInteger "
    382             "SINGLE-VALUE )",
    383         NULL, NULL
    384     },
    385     { "feature", "name", 2, 0, 0,
    386         ARG_MAGIC|CFG_FEATURE,
    387         &config_feature,
    388         "( OLcfgBkAt:13.10 "
    389             "NAME 'olcBkLloadFeature' "
    390             "DESC 'Lload features enabled' "
    391             "EQUALITY caseIgnoreMatch "
    392             "SYNTAX OMsDirectoryString )",
    393         NULL, NULL
    394     },
    395     { "TLSCACertificate", NULL, 2, 2, 0,
    396 #ifdef HAVE_TLS
    397         CFG_TLS_CACERT|ARG_BINARY|ARG_MAGIC,
    398         &config_tls_option,
    399 #else
    400         ARG_IGNORED,
    401         NULL,
    402 #endif
    403         "( OLcfgBkAt:13.11 "
    404             "NAME 'olcBkLloadTLSCACertificate' "
    405             "DESC 'X.509 certificate, must use ;binary' "
    406             "EQUALITY certificateExactMatch "
    407             "SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 "
    408             "SINGLE-VALUE )",
    409         NULL, NULL
    410     },
    411     { "TLSCACertificateFile", NULL, 2, 2, 0,
    412 #ifdef HAVE_TLS
    413         CFG_TLS_CA_FILE|ARG_STRING|ARG_MAGIC,
    414         &config_tls_option,
    415 #else
    416         ARG_IGNORED,
    417         NULL,
    418 #endif
    419         "( OLcfgBkAt:13.12 "
    420             "NAME 'olcBkLloadTLSCACertificateFile' "
    421             "EQUALITY caseExactMatch "
    422             "SYNTAX OMsDirectoryString "
    423             "SINGLE-VALUE )",
    424         NULL, NULL
    425     },
    426     { "TLSCACertificatePath", NULL, 2, 2, 0,
    427 #ifdef HAVE_TLS
    428         CFG_TLS_CA_PATH|ARG_STRING|ARG_MAGIC,
    429         &config_tls_option,
    430 #else
    431         ARG_IGNORED,
    432         NULL,
    433 #endif
    434         "( OLcfgBkAt:13.13 "
    435             "NAME 'olcBkLloadTLSCACertificatePath' "
    436             "EQUALITY caseExactMatch "
    437             "SYNTAX OMsDirectoryString "
    438             "SINGLE-VALUE )",
    439         NULL, NULL
    440     },
    441     { "TLSCertificate", NULL, 2, 2, 0,
    442 #ifdef HAVE_TLS
    443         CFG_TLS_CERT|ARG_BINARY|ARG_MAGIC,
    444         &config_tls_option,
    445 #else
    446         ARG_IGNORED,
    447         NULL,
    448 #endif
    449         "( OLcfgBkAt:13.14 "
    450             "NAME 'olcBkLloadTLSCertificate' "
    451             "DESC 'X.509 certificate, must use ;binary' "
    452             "EQUALITY certificateExactMatch "
    453             "SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 "
    454             "SINGLE-VALUE )",
    455         NULL, NULL
    456     },
    457     { "TLSCertificateFile", NULL, 2, 2, 0,
    458 #ifdef HAVE_TLS
    459         CFG_TLS_CERT_FILE|ARG_STRING|ARG_MAGIC,
    460         &config_tls_option,
    461 #else
    462         ARG_IGNORED,
    463         NULL,
    464 #endif
    465         "( OLcfgBkAt:13.15 "
    466             "NAME 'olcBkLloadTLSCertificateFile' "
    467             "EQUALITY caseExactMatch "
    468             "SYNTAX OMsDirectoryString "
    469             "SINGLE-VALUE )",
    470         NULL, NULL
    471     },
    472     { "TLSCertificateKey", NULL, 2, 2, 0,
    473 #ifdef HAVE_TLS
    474         CFG_TLS_KEY|ARG_BINARY|ARG_MAGIC,
    475         &config_tls_option,
    476 #else
    477         ARG_IGNORED,
    478         NULL,
    479 #endif
    480         "( OLcfgBkAt:13.16 "
    481             "NAME 'olcBkLloadTLSCertificateKey' "
    482             "DESC 'X.509 privateKey, must use ;binary' "
    483             "EQUALITY privateKeyMatch "
    484             "SYNTAX 1.2.840.113549.1.8.1.1 "
    485             "SINGLE-VALUE )",
    486         NULL, NULL
    487     },
    488     { "TLSCertificateKeyFile", NULL, 2, 2, 0,
    489 #ifdef HAVE_TLS
    490         CFG_TLS_CERT_KEY|ARG_STRING|ARG_MAGIC,
    491         &config_tls_option,
    492 #else
    493         ARG_IGNORED,
    494         NULL,
    495 #endif
    496         "( OLcfgBkAt:13.17 "
    497             "NAME 'olcBkLloadTLSCertificateKeyFile' "
    498             "EQUALITY caseExactMatch "
    499             "SYNTAX OMsDirectoryString "
    500             "SINGLE-VALUE )",
    501         NULL, NULL
    502     },
    503     { "TLSCipherSuite", NULL, 2, 2, 0,
    504 #ifdef HAVE_TLS
    505         CFG_TLS_CIPHER|ARG_STRING|ARG_MAGIC,
    506         &config_tls_option,
    507 #else
    508         ARG_IGNORED,
    509         NULL,
    510 #endif
    511         "( OLcfgBkAt:13.18 "
    512             "NAME 'olcBkLloadTLSCipherSuite' "
    513             "EQUALITY caseExactMatch "
    514             "SYNTAX OMsDirectoryString "
    515             "SINGLE-VALUE )",
    516         NULL, NULL
    517     },
    518     { "TLSCRLCheck", NULL, 2, 2, 0,
    519 #if defined(HAVE_TLS) && defined(HAVE_OPENSSL)
    520         CFG_TLS_CRLCHECK|ARG_STRING|ARG_MAGIC,
    521         &config_tls_config,
    522 #else
    523         ARG_IGNORED,
    524         NULL,
    525 #endif
    526         "( OLcfgBkAt:13.19 "
    527             "NAME 'olcBkLloadTLSCRLCheck' "
    528             "EQUALITY caseIgnoreMatch "
    529             "SYNTAX OMsDirectoryString "
    530             "SINGLE-VALUE )",
    531         NULL, NULL
    532     },
    533     { "TLSCRLFile", NULL, 2, 2, 0,
    534 #if defined(HAVE_GNUTLS)
    535         CFG_TLS_CRL_FILE|ARG_STRING|ARG_MAGIC,
    536         &config_tls_option,
    537 #else
    538         ARG_IGNORED,
    539         NULL,
    540 #endif
    541         "( OLcfgBkAt:13.20 "
    542             "NAME 'olcBkLloadTLSCRLFile' "
    543             "EQUALITY caseExactMatch "
    544             "SYNTAX OMsDirectoryString "
    545             "SINGLE-VALUE )",
    546         NULL, NULL
    547     },
    548     { "TLSRandFile", NULL, 2, 2, 0,
    549 #ifdef HAVE_TLS
    550         CFG_TLS_RAND|ARG_STRING|ARG_MAGIC,
    551         &config_tls_option,
    552 #else
    553         ARG_IGNORED,
    554         NULL,
    555 #endif
    556         "( OLcfgBkAt:13.21 "
    557             "NAME 'olcBkLloadTLSRandFile' "
    558             "EQUALITY caseExactMatch "
    559             "SYNTAX OMsDirectoryString "
    560             "SINGLE-VALUE )",
    561         NULL, NULL
    562     },
    563     { "TLSVerifyClient", NULL, 2, 2, 0,
    564 #ifdef HAVE_TLS
    565         CFG_TLS_VERIFY|ARG_STRING|ARG_MAGIC,
    566         &config_tls_config,
    567 #else
    568         ARG_IGNORED,
    569         NULL,
    570 #endif
    571         "( OLcfgBkAt:13.22 "
    572             "NAME 'olcBkLloadVerifyClient' "
    573             "EQUALITY caseIgnoreMatch "
    574             "SYNTAX OMsDirectoryString "
    575             "SINGLE-VALUE )",
    576         NULL, NULL
    577     },
    578     { "TLSDHParamFile", NULL, 2, 2, 0,
    579 #ifdef HAVE_TLS
    580         CFG_TLS_DH_FILE|ARG_STRING|ARG_MAGIC,
    581         &config_tls_option,
    582 #else
    583         ARG_IGNORED,
    584         NULL,
    585 #endif
    586         "( OLcfgBkAt:13.23 "
    587             "NAME 'olcBkLloadTLSDHParamFile' "
    588             "EQUALITY caseExactMatch "
    589             "SYNTAX OMsDirectoryString "
    590             "SINGLE-VALUE )",
    591         NULL, NULL
    592     },
    593     { "TLSECName", NULL, 2, 2, 0,
    594 #ifdef HAVE_TLS
    595         CFG_TLS_ECNAME|ARG_STRING|ARG_MAGIC,
    596         &config_tls_option,
    597 #else
    598         ARG_IGNORED,
    599         NULL,
    600 #endif
    601         "( OLcfgBkAt:13.24 "
    602             "NAME 'olcBkLloadTLSECName' "
    603             "EQUALITY caseExactMatch "
    604             "SYNTAX OMsDirectoryString "
    605             "SINGLE-VALUE )",
    606         NULL, NULL
    607     },
    608     { "TLSProtocolMin", NULL, 2, 2, 0,
    609 #ifdef HAVE_TLS
    610         CFG_TLS_PROTOCOL_MIN|ARG_STRING|ARG_MAGIC,
    611         &config_tls_config,
    612 #else
    613         ARG_IGNORED,
    614         NULL,
    615 #endif
    616         "( OLcfgBkAt:13.25 "
    617             "NAME 'olcBkLloadTLSProtocolMin' "
    618             "EQUALITY caseIgnoreMatch "
    619             "SYNTAX OMsDirectoryString "
    620             "SINGLE-VALUE )",
    621         NULL, NULL
    622     },
    623     { "TLSShareSlapdCTX", NULL, 2, 2, 0,
    624 #if defined(HAVE_TLS) && defined(BALANCER_MODULE)
    625         CFG_TLS_SHARE_CTX|ARG_ON_OFF|ARG_MAGIC,
    626         &config_share_tls_ctx,
    627 #else
    628         ARG_IGNORED,
    629         NULL,
    630 #endif
    631         "( OLcfgBkAt:13.33 "
    632             "NAME 'olcBkLloadTLSShareSlapdCTX' "
    633             "DESC 'Share slapd TLS context (all other lloadd TLS options cease to take effect)' "
    634             "EQUALITY booleanMatch "
    635             "SYNTAX OMsBoolean "
    636             "SINGLE-VALUE )",
    637         NULL, NULL
    638     },
    639     { "iotimeout", "ms timeout", 2, 2, 0,
    640         ARG_UINT|ARG_MAGIC|CFG_IOTIMEOUT,
    641         &config_generic,
    642         "( OLcfgBkAt:13.26 "
    643             "NAME 'olcBkLloadIOTimeout' "
    644             "DESC 'I/O timeout threshold in milliseconds' "
    645             "EQUALITY integerMatch "
    646             "SYNTAX OMsInteger "
    647             "SINGLE-VALUE )",
    648         NULL, NULL
    649     },
    650     { "client_max_pending", NULL, 2, 2, 0,
    651         ARG_MAGIC|ARG_UINT|CFG_CLIENT_PENDING,
    652         &config_generic,
    653         "( OLcfgBkAt:13.35 "
    654             "NAME 'olcBkLloadClientMaxPending' "
    655             "DESC 'Maximum pending operations per client connection' "
    656             "EQUALITY integerMatch "
    657             "SYNTAX OMsInteger "
    658             "SINGLE-VALUE )",
    659         NULL,
    660         { .v_uint = 0 }
    661     },
    662     { "write_coherence", "seconds", 2, 2, 0,
    663         ARG_INT,
    664         &lload_write_coherence,
    665         "( OLcfgBkAt:13.36 "
    666             "NAME 'olcBkLloadWriteCoherence' "
    667             "DESC 'Keep operations to the same backend after a write' "
    668             "EQUALITY integerMatch "
    669             "SYNTAX OMsInteger "
    670             "SINGLE-VALUE )",
    671         NULL,
    672         { .v_int = 0 }
    673     },
    674     { "restrict_exop", "OID> <action", 3, 3, 0,
    675         ARG_MAGIC|CFG_RESTRICT_EXOP,
    676         &config_restrict_oid,
    677         "( OLcfgBkAt:13.37 "
    678             "NAME 'olcBkLloadRestrictExop' "
    679             "DESC 'Restrict upstream selection after forwarding an extended operation' "
    680             "EQUALITY caseIgnoreMatch "
    681             "SYNTAX OMsDirectoryString )",
    682         NULL, NULL
    683     },
    684     { "restrict_control", "OID> <action", 3, 3, 0,
    685         ARG_MAGIC|CFG_RESTRICT_CONTROL,
    686         &config_restrict_oid,
    687         "( OLcfgBkAt:13.38 "
    688             "NAME 'olcBkLloadRestrictControl' "
    689             "DESC 'Restrict upstream selection after forwarding a control' "
    690             "EQUALITY caseIgnoreMatch "
    691             "SYNTAX OMsDirectoryString )",
    692         NULL, NULL
    693     },
    694 
    695     /* cn=config only options */
    696 #ifdef BALANCER_MODULE
    697     { "", "uri", 2, 2, 0,
    698         ARG_BERVAL|ARG_MAGIC|CFG_URI,
    699         &backend_cf_gen,
    700         "( OLcfgBkAt:13.27 "
    701             "NAME 'olcBkLloadBackendUri' "
    702             "DESC 'URI to contact the server on' "
    703             "EQUALITY caseIgnoreMatch "
    704             "SYNTAX OMsDirectoryString "
    705             "SINGLE-VALUE )",
    706         NULL, NULL
    707     },
    708     { "", NULL, 2, 2, 0,
    709         ARG_UINT|ARG_MAGIC|CFG_NUMCONNS,
    710         &backend_cf_gen,
    711         "( OLcfgBkAt:13.28 "
    712             "NAME 'olcBkLloadNumconns' "
    713             "DESC 'Number of regular connections to maintain' "
    714             "EQUALITY integerMatch "
    715             "SYNTAX OMsInteger "
    716             "SINGLE-VALUE )",
    717         NULL, NULL
    718     },
    719     { "", NULL, 2, 2, 0,
    720         ARG_UINT|ARG_MAGIC|CFG_BINDCONNS,
    721         &backend_cf_gen,
    722         "( OLcfgBkAt:13.29 "
    723             "NAME 'olcBkLloadBindconns' "
    724             "DESC 'Number of bind connections to maintain' "
    725             "EQUALITY integerMatch "
    726             "SYNTAX OMsInteger "
    727             "SINGLE-VALUE )",
    728         NULL, NULL
    729     },
    730     { "", NULL, 2, 2, 0,
    731         ARG_UINT|ARG_MAGIC|CFG_RETRY,
    732         &backend_cf_gen,
    733         "( OLcfgBkAt:13.30 "
    734             "NAME 'olcBkLloadRetry' "
    735             "DESC 'Number of seconds to wait before trying to reconnect' "
    736             "EQUALITY integerMatch "
    737             "SYNTAX OMsInteger "
    738             "SINGLE-VALUE )",
    739         NULL, NULL
    740     },
    741     { "", NULL, 2, 2, 0,
    742         ARG_UINT|ARG_MAGIC|CFG_MAX_PENDING_OPS,
    743         &backend_cf_gen,
    744         "( OLcfgBkAt:13.31 "
    745             "NAME 'olcBkLloadMaxPendingOps' "
    746             "DESC 'Maximum number of pending operations for this backend' "
    747             "EQUALITY integerMatch "
    748             "SYNTAX OMsInteger "
    749             "SINGLE-VALUE )",
    750         NULL, NULL
    751     },
    752     { "", NULL, 2, 2, 0,
    753         ARG_UINT|ARG_MAGIC|CFG_MAX_PENDING_CONNS,
    754         &backend_cf_gen,
    755         "( OLcfgBkAt:13.32 "
    756             "NAME 'olcBkLloadMaxPendingConns' "
    757             "DESC 'Maximum number of pending operations on each connection' "
    758             "EQUALITY integerMatch "
    759             "SYNTAX OMsInteger "
    760             "SINGLE-VALUE )",
    761         NULL, NULL
    762     },
    763     { "", NULL, 2, 2, 0,
    764         ARG_BERVAL|ARG_MAGIC|CFG_STARTTLS,
    765         &backend_cf_gen,
    766         "( OLcfgBkAt:13.34 "
    767             "NAME 'olcBkLloadStartTLS' "
    768             "DESC 'Whether StartTLS should be attempted on the connection' "
    769             "EQUALITY caseIgnoreMatch "
    770             "SYNTAX OMsDirectoryString "
    771             "SINGLE-VALUE )",
    772         NULL, NULL
    773     },
    774     { "", NULL, 2, 2, 0,
    775         ARG_MAGIC|ARG_UINT|CFG_WEIGHT,
    776         &backend_cf_gen,
    777         "( OLcfgBkAt:13.40 "
    778             "NAME 'olcBkLloadWeight' "
    779             "DESC 'Backend weight' "
    780             "SYNTAX OMsInteger "
    781             "SINGLE-VALUE )",
    782         NULL,
    783         { .v_uint = 0 },
    784     },
    785 #endif /* BALANCER_MODULE */
    786 
    787     { NULL, NULL, 0, 0, 0, ARG_IGNORED, NULL }
    788 };
    789 
    790 #ifdef BALANCER_MODULE
    791 static ConfigCfAdd lload_cfadd;
    792 
    793 static ConfigLDAPadd lload_backend_ldadd;
    794 static ConfigLDAPadd lload_tier_ldadd;
    795 
    796 #ifdef SLAP_CONFIG_DELETE
    797 static ConfigLDAPdel lload_backend_lddel;
    798 static ConfigLDAPdel lload_tier_lddel;
    799 #endif /* SLAP_CONFIG_DELETE */
    800 
    801 static ConfigOCs lloadocs[] = {
    802     { "( OLcfgBkOc:13.1 "
    803         "NAME 'olcBkLloadConfig' "
    804         "DESC 'Lload backend configuration' "
    805         "SUP olcBackendConfig "
    806         "MUST ( olcBkLloadBindconf "
    807             "$ olcBkLloadIOThreads "
    808             "$ olcBkLloadListen "
    809             "$ olcBkLloadSockbufMaxClient "
    810             "$ olcBkLloadSockbufMaxUpstream "
    811             "$ olcBkLloadMaxPDUPerCycle "
    812             "$ olcBkLloadIOTimeout ) "
    813         "MAY ( olcBkLloadFeature "
    814             "$ olcBkLloadTcpBuffer "
    815             "$ olcBkLloadTLSCACertificateFile "
    816             "$ olcBkLloadTLSCACertificatePath "
    817             "$ olcBkLloadTLSCertificateFile "
    818             "$ olcBkLloadTLSCertificateKeyFile "
    819             "$ olcBkLloadTLSCipherSuite "
    820             "$ olcBkLloadTLSCRLCheck "
    821             "$ olcBkLloadTLSRandFile "
    822             "$ olcBkLloadVerifyClient "
    823             "$ olcBkLloadTLSDHParamFile "
    824             "$ olcBkLloadTLSECName "
    825             "$ olcBkLloadTLSProtocolMin "
    826             "$ olcBkLloadTLSCRLFile "
    827             "$ olcBkLloadTLSShareSlapdCTX "
    828             "$ olcBkLloadClientMaxPending "
    829             "$ olcBkLloadWriteCoherence "
    830             "$ olcBkLloadRestrictExop "
    831             "$ olcBkLloadRestrictControl "
    832         ") )",
    833         Cft_Backend, config_back_cf_table,
    834         NULL,
    835         lload_cfadd,
    836     },
    837     { "( OLcfgBkOc:13.2 "
    838         "NAME 'olcBkLloadBackendConfig' "
    839         "DESC 'Lload backend server configuration' "
    840         "SUP olcConfig STRUCTURAL "
    841         "MUST ( cn "
    842             "$ olcBkLloadBackendUri "
    843             "$ olcBkLloadNumconns "
    844             "$ olcBkLloadBindconns "
    845             "$ olcBkLloadRetry "
    846             "$ olcBkLloadMaxPendingOps "
    847             "$ olcBkLloadMaxPendingConns ) "
    848         "MAY ( olcBkLloadStartTLS "
    849             "$ olcBkLloadWeight ) "
    850         ") )",
    851         Cft_Misc, config_back_cf_table,
    852         lload_backend_ldadd,
    853         NULL,
    854 #ifdef SLAP_CONFIG_DELETE
    855         lload_backend_lddel,
    856 #endif /* SLAP_CONFIG_DELETE */
    857     },
    858     { "( OLcfgBkOc:13.3 "
    859         "NAME 'olcBkLloadTierConfig' "
    860         "DESC 'Lload tier configuration' "
    861         "SUP olcConfig STRUCTURAL "
    862         "MUST ( cn "
    863             "$ olcBkLloadTierType "
    864         ") )",
    865         Cft_Misc, config_back_cf_table,
    866         lload_tier_ldadd,
    867         NULL,
    868 #ifdef SLAP_CONFIG_DELETE
    869         lload_tier_lddel,
    870 #endif /* SLAP_CONFIG_DELETE */
    871     },
    872     { NULL, 0, NULL }
    873 };
    874 #endif /* BALANCER_MODULE */
    875 
    876 static int
    877 config_generic( ConfigArgs *c )
    878 {
    879     enum lcf_daemon flag = 0;
    880     int rc = LDAP_SUCCESS;
    881 
    882     if ( c->op == SLAP_CONFIG_EMIT ) {
    883         switch ( c->type ) {
    884             case CFG_IOTHREADS:
    885                 c->value_uint = lload_daemon_threads;
    886                 break;
    887             case CFG_LISTEN_URI: {
    888                 LloadListener **ll = lloadd_get_listeners();
    889                 struct berval bv = BER_BVNULL;
    890 
    891                 for ( ; ll && *ll; ll++ ) {
    892                     /* The same url could have spawned several consecutive
    893                      * listeners */
    894                     if ( !BER_BVISNULL( &bv ) &&
    895                             !ber_bvcmp( &bv, &(*ll)->sl_url ) ) {
    896                         continue;
    897                     }
    898                     ber_dupbv( &bv, &(*ll)->sl_url );
    899                     ber_bvarray_add( &c->rvalue_vals, &bv );
    900                 }
    901             } break;
    902             case CFG_MAXBUF_CLIENT:
    903                 c->value_uint = sockbuf_max_incoming_client;
    904                 break;
    905             case CFG_MAXBUF_UPSTREAM:
    906                 c->value_uint = sockbuf_max_incoming_upstream;
    907                 break;
    908             case CFG_RESCOUNT:
    909                 c->value_uint = lload_conn_max_pdus_per_cycle;
    910                 break;
    911             case CFG_IOTIMEOUT:
    912                 c->value_uint = 1000 * lload_write_timeout->tv_sec +
    913                         lload_write_timeout->tv_usec / 1000;
    914                 break;
    915             case CFG_CLIENT_PENDING:
    916                 c->value_uint = lload_client_max_pending;
    917                 break;
    918             default:
    919                 rc = 1;
    920                 break;
    921         }
    922         return rc;
    923 
    924     } else if ( c->op == LDAP_MOD_DELETE ) {
    925         /* We only need to worry about deletions to multi-value or MAY
    926          * attributes that belong to the lloadd module - we don't have any at
    927          * the moment */
    928         return rc;
    929     }
    930 
    931     lload_change.type = LLOAD_CHANGE_MODIFY;
    932     lload_change.object = LLOAD_DAEMON;
    933 
    934     switch ( c->type ) {
    935         case CFG_CONCUR:
    936             ldap_pvt_thread_set_concurrency( c->value_uint );
    937             break;
    938         case CFG_LISTEN:
    939             if ( lloadd_inited ) {
    940                 snprintf( c->cr_msg, sizeof(c->cr_msg),
    941                         "listen directive can only be specified once" );
    942                 ch_free( c->value_string );
    943                 return 1;
    944             }
    945             if ( lloadd_listeners_init( c->value_string ) ) {
    946                 snprintf( c->cr_msg, sizeof(c->cr_msg),
    947                         "could not open one of the listener sockets: %s",
    948                         c->value_string );
    949                 ch_free( c->value_string );
    950                 return 1;
    951             }
    952             ch_free( c->value_string );
    953             break;
    954         case CFG_LISTEN_URI: {
    955             LDAPURLDesc *lud;
    956             LloadListener *l;
    957 
    958             if ( ldap_url_parse_ext(
    959                          c->line, &lud, LDAP_PVT_URL_PARSE_DEF_PORT ) ) {
    960                 snprintf( c->cr_msg, sizeof(c->cr_msg),
    961                         "string %s could not be parsed as an LDAP URL",
    962                         c->line );
    963                 goto fail;
    964             }
    965 
    966             /* A sanity check, although it will not catch everything */
    967             if ( ( l = lload_config_check_my_url( c->line, lud ) ) ) {
    968                 snprintf( c->cr_msg, sizeof(c->cr_msg),
    969                         "Load Balancer already configured to listen on %s "
    970                         "(while adding %s)",
    971                         l->sl_url.bv_val, c->line );
    972                 goto fail;
    973             }
    974 
    975             if ( !lloadd_inited ) {
    976                 if ( lload_open_new_listener( c->line, lud ) ) {
    977                     snprintf( c->cr_msg, sizeof(c->cr_msg),
    978                             "could not open a listener for %s", c->line );
    979                     goto fail;
    980                 }
    981             } else {
    982                 snprintf( c->cr_msg, sizeof(c->cr_msg),
    983                         "listener changes will not take effect until restart: "
    984                         "%s",
    985                         c->line );
    986                 Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg );
    987             }
    988         } break;
    989         case CFG_THREADS:
    990             if ( c->value_uint < 2 ) {
    991                 snprintf( c->cr_msg, sizeof(c->cr_msg),
    992                         "threads=%d smaller than minimum value 2",
    993                         c->value_uint );
    994                 goto fail;
    995 
    996             } else if ( c->value_uint > 2 * SLAP_MAX_WORKER_THREADS ) {
    997                 snprintf( c->cr_msg, sizeof(c->cr_msg),
    998                         "warning, threads=%d larger than twice the default "
    999                         "(2*%d=%d); YMMV",
   1000                         c->value_uint, SLAP_MAX_WORKER_THREADS,
   1001                         2 * SLAP_MAX_WORKER_THREADS );
   1002                 Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg );
   1003             }
   1004             if ( slapMode & SLAP_SERVER_MODE )
   1005                 ldap_pvt_thread_pool_maxthreads(
   1006                         &connection_pool, c->value_uint );
   1007             connection_pool_max = c->value_uint; /* save for reference */
   1008             break;
   1009 
   1010         case CFG_THREADQS:
   1011             if ( c->value_uint < 1 ) {
   1012                 snprintf( c->cr_msg, sizeof(c->cr_msg),
   1013                         "threadqueues=%d smaller than minimum value 1",
   1014                         c->value_uint );
   1015                 goto fail;
   1016             }
   1017             if ( slapMode & SLAP_SERVER_MODE )
   1018                 ldap_pvt_thread_pool_queues( &connection_pool, c->value_uint );
   1019             connection_pool_queues = c->value_uint; /* save for reference */
   1020             break;
   1021 
   1022         case CFG_IOTHREADS: {
   1023             int mask = 0;
   1024             /* use a power of two */
   1025             while ( c->value_uint > 1 ) {
   1026                 c->value_uint >>= 1;
   1027                 mask <<= 1;
   1028                 mask |= 1;
   1029             }
   1030             if ( !lloadd_inited ) {
   1031                 lload_daemon_mask = mask;
   1032                 lload_daemon_threads = mask + 1;
   1033                 flag = LLOAD_DAEMON_MOD_THREADS;
   1034             } else {
   1035                 snprintf( c->cr_msg, sizeof(c->cr_msg),
   1036                         "io thread changes will not take effect until "
   1037                         "restart" );
   1038                 Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg );
   1039             }
   1040         } break;
   1041 
   1042         case CFG_RESCOUNT:
   1043             lload_conn_max_pdus_per_cycle = c->value_uint;
   1044             break;
   1045 
   1046         case CFG_IOTIMEOUT:
   1047             if ( c->value_uint > 0 ) {
   1048                 timeout_write_tv.tv_sec = c->value_uint / 1000;
   1049                 timeout_write_tv.tv_usec = 1000 * ( c->value_uint % 1000 );
   1050                 lload_write_timeout = &timeout_write_tv;
   1051             } else {
   1052                 lload_write_timeout = NULL;
   1053             }
   1054             break;
   1055         case CFG_MAXBUF_CLIENT:
   1056             sockbuf_max_incoming_client = c->value_uint;
   1057             break;
   1058         case CFG_MAXBUF_UPSTREAM:
   1059             sockbuf_max_incoming_upstream = c->value_uint;
   1060             break;
   1061         case CFG_CLIENT_PENDING:
   1062             lload_client_max_pending = c->value_uint;
   1063             break;
   1064         default:
   1065             Debug( LDAP_DEBUG_ANY, "%s: unknown CFG_TYPE %d\n",
   1066                     c->log, c->type );
   1067             return 1;
   1068     }
   1069 
   1070     lload_change.flags.daemon |= flag;
   1071 
   1072     return 0;
   1073 
   1074 fail:
   1075     if ( lload_change.type == LLOAD_CHANGE_ADD ) {
   1076         /* Abort the ADD */
   1077         lload_change.type = LLOAD_CHANGE_DEL;
   1078     }
   1079 
   1080     Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg );
   1081     return 1;
   1082 }
   1083 
   1084 static int
   1085 lload_backend_finish( ConfigArgs *ca )
   1086 {
   1087     LloadBackend *b = ca->ca_private;
   1088 
   1089     if ( ca->reply.err != LDAP_SUCCESS ) {
   1090         /* Not reached since cleanup is only called on success */
   1091         goto fail;
   1092     }
   1093 
   1094     if ( b->b_numconns <= 0 || b->b_numbindconns <= 0 ) {
   1095         Debug( LDAP_DEBUG_ANY, "lload_backend_finish: "
   1096                 "invalid connection pool configuration\n" );
   1097         goto fail;
   1098     }
   1099 
   1100     if ( b->b_retry_timeout < 0 ) {
   1101         Debug( LDAP_DEBUG_ANY, "lload_backend_finish: "
   1102                 "invalid retry timeout configuration\n" );
   1103         goto fail;
   1104     }
   1105 
   1106     b->b_retry_tv.tv_sec = b->b_retry_timeout / 1000;
   1107     b->b_retry_tv.tv_usec = ( b->b_retry_timeout % 1000 ) * 1000;
   1108 
   1109     /* daemon_base is only allocated after initial configuration happens, those
   1110      * events are allocated on startup, we only deal with online Adds */
   1111     if ( !b->b_retry_event && daemon_base ) {
   1112         struct event *event;
   1113         assert( CONFIG_ONLINE_ADD( ca ) );
   1114         event = evtimer_new( daemon_base, backend_connect, b );
   1115         if ( !event ) {
   1116             Debug( LDAP_DEBUG_ANY, "lload_backend_finish: "
   1117                     "failed to allocate retry event\n" );
   1118             goto fail;
   1119         }
   1120         b->b_retry_event = event;
   1121     }
   1122 
   1123     if ( BER_BVISEMPTY( &b->b_name ) ) {
   1124         struct berval bv;
   1125         LloadBackend *b2;
   1126         int i = 1;
   1127 
   1128         LDAP_CIRCLEQ_FOREACH ( b2, &b->b_tier->t_backends, b_next ) {
   1129             i++;
   1130         }
   1131 
   1132         bv.bv_val = ca->cr_msg;
   1133         bv.bv_len =
   1134                 snprintf( ca->cr_msg, sizeof(ca->cr_msg), "server %d", i );
   1135 
   1136         ber_dupbv( &b->b_name, &bv );
   1137     }
   1138 
   1139     if ( b->b_tier->t_type.tier_add_backend( b->b_tier, b ) ) {
   1140         goto fail;
   1141     }
   1142 
   1143     return LDAP_SUCCESS;
   1144 
   1145 fail:
   1146     if ( lload_change.type == LLOAD_CHANGE_ADD ) {
   1147         /* Abort the ADD */
   1148         lload_change.type = LLOAD_CHANGE_DEL;
   1149     }
   1150 
   1151     lload_backend_destroy( b );
   1152     return -1;
   1153 }
   1154 
   1155 static int
   1156 backend_config_url( LloadBackend *b, struct berval *uri )
   1157 {
   1158     LDAPURLDesc *lud = NULL;
   1159     char *host = NULL;
   1160     int rc, proto, tls = b->b_tls_conf;
   1161 
   1162     /* Effect no changes until we've checked everything */
   1163 
   1164     rc = ldap_url_parse_ext( uri->bv_val, &lud, LDAP_PVT_URL_PARSE_DEF_PORT );
   1165     if ( rc != LDAP_URL_SUCCESS ) {
   1166         Debug( LDAP_DEBUG_ANY, "backend_config_url: "
   1167                 "listen URL \"%s\" parse error=%d\n",
   1168                 uri->bv_val, rc );
   1169         return -1;
   1170     }
   1171 
   1172     if ( ldap_pvt_url_scheme2tls( lud->lud_scheme ) ) {
   1173 #ifdef HAVE_TLS
   1174         /* Specifying ldaps:// overrides starttls= settings */
   1175         tls = LLOAD_LDAPS;
   1176 #else /* ! HAVE_TLS */
   1177 
   1178         Debug( LDAP_DEBUG_ANY, "backend_config_url: "
   1179                 "TLS not supported (%s)\n",
   1180                 uri->bv_val );
   1181         rc = -1;
   1182         goto done;
   1183 #endif /* ! HAVE_TLS */
   1184     }
   1185 
   1186     proto = ldap_pvt_url_scheme2proto( lud->lud_scheme );
   1187     if ( proto == LDAP_PROTO_IPC ) {
   1188 #ifdef LDAP_PF_LOCAL
   1189         if ( lud->lud_host == NULL || lud->lud_host[0] == '\0' ) {
   1190             host = LDAPI_SOCK;
   1191         }
   1192 #else /* ! LDAP_PF_LOCAL */
   1193 
   1194         Debug( LDAP_DEBUG_ANY, "backend_config_url: "
   1195                 "URL scheme not supported: %s",
   1196                 url );
   1197         rc = -1;
   1198         goto done;
   1199 #endif /* ! LDAP_PF_LOCAL */
   1200     } else {
   1201         if ( lud->lud_host == NULL || lud->lud_host[0] == '\0' ) {
   1202             Debug( LDAP_DEBUG_ANY, "backend_config_url: "
   1203                     "backend url missing hostname: '%s'\n",
   1204                     uri->bv_val );
   1205             rc = -1;
   1206             goto done;
   1207         }
   1208     }
   1209     if ( !host ) {
   1210         host = lud->lud_host;
   1211     }
   1212 
   1213     if ( b->b_host ) {
   1214         ch_free( b->b_host );
   1215     }
   1216 
   1217     b->b_proto = proto;
   1218     b->b_tls = tls;
   1219     b->b_port = lud->lud_port;
   1220     b->b_host = ch_strdup( host );
   1221 
   1222 done:
   1223     ldap_free_urldesc( lud );
   1224     return rc;
   1225 }
   1226 
   1227 static int
   1228 config_backend( ConfigArgs *c )
   1229 {
   1230     LloadBackend *b;
   1231     LloadTier *tier;
   1232     int i, rc = 0;
   1233 
   1234     tier = LDAP_STAILQ_LAST( &tiers, LloadTier, t_next );
   1235     if ( !tier ) {
   1236         Debug( LDAP_DEBUG_ANY, "config_backend: "
   1237                 "no tier configured yet\n" );
   1238         return -1;
   1239     }
   1240 
   1241     /* FIXME: maybe tier_add_backend could allocate it? */
   1242     b = lload_backend_new();
   1243     b->b_tier = tier;
   1244 
   1245     for ( i = 1; i < c->argc; i++ ) {
   1246         if ( lload_backend_parse( c->argv[i], b ) ) {
   1247             if ( !tier->t_type.tier_backend_config ||
   1248                     tier->t_type.tier_backend_config( tier, b, c->argv[i] ) ) {
   1249                 Debug( LDAP_DEBUG_ANY, "config_backend: "
   1250                         "error parsing backend configuration item '%s'\n",
   1251                         c->argv[i] );
   1252                 return -1;
   1253             }
   1254         }
   1255     }
   1256 
   1257     if ( BER_BVISNULL( &b->b_uri ) ) {
   1258         Debug( LDAP_DEBUG_ANY, "config_backend: "
   1259                 "backend address not specified\n" );
   1260         rc = -1;
   1261         goto done;
   1262     }
   1263 
   1264     if ( backend_config_url( b, &b->b_uri ) ) {
   1265         rc = -1;
   1266         goto done;
   1267     }
   1268 
   1269     c->ca_private = b;
   1270     rc = lload_backend_finish( c );
   1271 done:
   1272     if ( rc ) {
   1273         ch_free( b );
   1274     }
   1275     return rc;
   1276 }
   1277 
   1278 static int
   1279 config_bindconf( ConfigArgs *c )
   1280 {
   1281     int i;
   1282 
   1283     if ( c->op == SLAP_CONFIG_EMIT ) {
   1284         struct berval bv;
   1285 
   1286         lload_bindconf_unparse( &bindconf, &bv );
   1287 
   1288         for ( i = 0; isspace( (unsigned char)bv.bv_val[i] ); i++ )
   1289             /* count spaces */;
   1290 
   1291         if ( i ) {
   1292             bv.bv_len -= i;
   1293             AC_MEMCPY( bv.bv_val, &bv.bv_val[i], bv.bv_len + 1 );
   1294         }
   1295 
   1296         value_add_one( &c->rvalue_vals, &bv );
   1297         ber_memfree( bv.bv_val );
   1298         return LDAP_SUCCESS;
   1299     } else if ( c->op == LDAP_MOD_DELETE ) {
   1300         /* It's a MUST single-valued attribute, noop for now */
   1301         lload_bindconf_free( &bindconf );
   1302         return LDAP_SUCCESS;
   1303     }
   1304 
   1305     lload_change.type = LLOAD_CHANGE_MODIFY;
   1306     lload_change.object = LLOAD_DAEMON;
   1307     lload_change.flags.daemon |= LLOAD_DAEMON_MOD_BINDCONF;
   1308 
   1309     for ( i = 1; i < c->argc; i++ ) {
   1310         if ( lload_bindconf_parse( c->argv[i], &bindconf ) ) {
   1311             Debug( LDAP_DEBUG_ANY, "config_bindconf: "
   1312                     "error parsing backend configuration item '%s'\n",
   1313                     c->argv[i] );
   1314             return -1;
   1315         }
   1316     }
   1317 
   1318     if ( bindconf.sb_method == LDAP_AUTH_SASL ) {
   1319 #ifndef HAVE_CYRUS_SASL
   1320         Debug( LDAP_DEBUG_ANY, "config_bindconf: "
   1321                 "no sasl support available\n" );
   1322         return -1;
   1323 #endif
   1324     }
   1325 
   1326     if ( !BER_BVISNULL( &bindconf.sb_authzId ) ) {
   1327         ber_bvreplace( &lloadd_identity, &bindconf.sb_authzId );
   1328     } else if ( !BER_BVISNULL( &bindconf.sb_authcId ) ) {
   1329         ber_bvreplace( &lloadd_identity, &bindconf.sb_authcId );
   1330     } else if ( !BER_BVISNULL( &bindconf.sb_binddn ) ) {
   1331         char *ptr;
   1332 
   1333         lloadd_identity.bv_len = STRLENOF("dn:") + bindconf.sb_binddn.bv_len;
   1334         lloadd_identity.bv_val = ch_realloc(
   1335                 lloadd_identity.bv_val, lloadd_identity.bv_len + 1 );
   1336 
   1337         ptr = lutil_strcopy( lloadd_identity.bv_val, "dn:" );
   1338         ptr = lutil_strncopy(
   1339                 ptr, bindconf.sb_binddn.bv_val, bindconf.sb_binddn.bv_len );
   1340         *ptr = '\0';
   1341     }
   1342 
   1343     if ( bindconf.sb_timeout_api ) {
   1344         timeout_api_tv.tv_sec = bindconf.sb_timeout_api;
   1345         lload_timeout_api = &timeout_api_tv;
   1346         if ( lload_timeout_event ) {
   1347             event_add( lload_timeout_event, lload_timeout_api );
   1348         }
   1349     } else {
   1350         lload_timeout_api = NULL;
   1351         if ( lload_timeout_event ) {
   1352             event_del( lload_timeout_event );
   1353         }
   1354     }
   1355 
   1356     if ( bindconf.sb_timeout_net ) {
   1357         timeout_net_tv.tv_sec = bindconf.sb_timeout_net;
   1358         lload_timeout_net = &timeout_net_tv;
   1359     } else {
   1360         lload_timeout_net = NULL;
   1361     }
   1362 
   1363 #ifdef HAVE_TLS
   1364     if ( bindconf.sb_tls_do_init ) {
   1365         lload_bindconf_tls_set( &bindconf, lload_tls_backend_ld );
   1366     }
   1367 #endif /* HAVE_TLS */
   1368     return 0;
   1369 }
   1370 
   1371 #ifndef BALANCER_MODULE
   1372 char *
   1373 oidm_find( char *oid )
   1374 {
   1375     if ( OID_LEADCHAR( *oid ) ) {
   1376         return oid;
   1377     }
   1378     Debug( LDAP_DEBUG_ANY, "oidm_find: "
   1379             "full OID parsing only available when compiled as a module\n" );
   1380     return NULL;
   1381 }
   1382 #endif /* !BALANCER_MODULE */
   1383 
   1384 static struct {
   1385     const char *name;
   1386     enum op_restriction action;
   1387 } restrictopts[] = {
   1388     { "ignore", LLOAD_OP_NOT_RESTRICTED },
   1389     { "write", LLOAD_OP_RESTRICTED_WRITE },
   1390     { "backend", LLOAD_OP_RESTRICTED_BACKEND },
   1391     { "connection", LLOAD_OP_RESTRICTED_UPSTREAM },
   1392     { "isolate", LLOAD_OP_RESTRICTED_ISOLATE },
   1393     { "reject", LLOAD_OP_RESTRICTED_REJECT },
   1394     { NULL }
   1395 };
   1396 
   1397 void
   1398 lload_restriction_free( struct restriction_entry *restriction )
   1399 {
   1400     ch_free( restriction->oid.bv_val );
   1401     ch_free( restriction );
   1402 }
   1403 
   1404 static int
   1405 config_restrict_oid( ConfigArgs *c )
   1406 {
   1407     TAvlnode *node = NULL, **root = ( c->type == CFG_RESTRICT_EXOP ) ?
   1408             &lload_exop_actions :
   1409             &lload_control_actions;
   1410     struct restriction_entry *entry = NULL;
   1411     char *parsed_oid;
   1412     int i, rc = -1;
   1413 
   1414     if ( c->op == SLAP_CONFIG_EMIT ) {
   1415         struct berval bv = { .bv_val = c->cr_msg };
   1416 
   1417         if ( c->type == CFG_RESTRICT_EXOP && lload_default_exop_action ) {
   1418             bv.bv_len = snprintf( bv.bv_val, sizeof(c->cr_msg), "1.1 %s",
   1419                     restrictopts[lload_default_exop_action].name );
   1420             value_add_one( &c->rvalue_vals, &bv );
   1421         }
   1422         for ( node = ldap_tavl_end( *root, TAVL_DIR_LEFT );
   1423                 node;
   1424                 node = ldap_tavl_next( node, TAVL_DIR_RIGHT ) ) {
   1425             entry = node->avl_data;
   1426 
   1427             bv.bv_len = snprintf( bv.bv_val, sizeof(c->cr_msg), "%s %s",
   1428                     entry->oid.bv_val, restrictopts[entry->action].name );
   1429             value_add_one( &c->rvalue_vals, &bv );
   1430         }
   1431 
   1432         return LDAP_SUCCESS;
   1433 
   1434     } else if ( c->op == LDAP_MOD_DELETE ) {
   1435         if ( !c->line ) {
   1436             ldap_tavl_free( *root, (AVL_FREE)lload_restriction_free );
   1437             *root = NULL;
   1438             if ( c->type == CFG_RESTRICT_EXOP ) {
   1439                 lload_default_exop_action = LLOAD_OP_NOT_RESTRICTED;
   1440             }
   1441             rc = LDAP_SUCCESS;
   1442         } else {
   1443             struct restriction_entry needle;
   1444 
   1445             parsed_oid = strchr( c->line, ' ' );
   1446             if ( !parsed_oid ) {
   1447                 return rc;
   1448             }
   1449 
   1450             memcpy( c->cr_msg, c->line, parsed_oid - c->line );
   1451             c->cr_msg[parsed_oid - c->line] = '\0';
   1452 
   1453             needle.oid.bv_val = oidm_find( c->cr_msg );
   1454             needle.oid.bv_len = strlen( needle.oid.bv_val );
   1455 
   1456             if ( !needle.oid.bv_val ) {
   1457                 return rc;
   1458             } else if ( c->type == CFG_RESTRICT_EXOP &&
   1459                     !strcmp( needle.oid.bv_val, "1.1" ) ) {
   1460                 lload_default_exop_action = LLOAD_OP_NOT_RESTRICTED;
   1461             } else {
   1462                 /* back-config should have checked we have this value */
   1463                 entry = ldap_tavl_delete( root, &needle,
   1464                         lload_restriction_cmp );
   1465                 assert( entry != NULL );
   1466             }
   1467             rc = LDAP_SUCCESS;
   1468         }
   1469         return rc;
   1470     }
   1471 
   1472     parsed_oid = oidm_find( c->argv[1] );
   1473     if ( !parsed_oid ) {
   1474         snprintf( c->cr_msg, sizeof(c->cr_msg), "Could not parse oid %s",
   1475                 c->argv[1] );
   1476         goto done;
   1477     }
   1478 
   1479     for ( i = 0; restrictopts[i].name; i++ ) {
   1480         if ( !strcasecmp( c->argv[2], restrictopts[i].name ) ) {
   1481             break;
   1482         }
   1483     }
   1484 
   1485     if ( !restrictopts[i].name ) {
   1486         snprintf( c->cr_msg, sizeof(c->cr_msg), "Could not parse action %s",
   1487                 c->argv[2] );
   1488         goto done;
   1489     }
   1490 
   1491     if ( !strcmp( parsed_oid, "1.1" ) ) {
   1492         if ( lload_default_exop_action ) {
   1493             snprintf( c->cr_msg, sizeof(c->cr_msg), "Default already set" );
   1494             goto done;
   1495         } else {
   1496             lload_default_exop_action = i;
   1497         }
   1498     }
   1499 
   1500     entry = ch_malloc( sizeof(struct restriction_entry) );
   1501     /* Copy only if a reference to argv[1] was returned */
   1502     ber_str2bv( parsed_oid, 0, parsed_oid == c->argv[1], &entry->oid );
   1503     entry->action = i;
   1504 
   1505     if ( ldap_tavl_insert( root, entry, lload_restriction_cmp,
   1506                 ldap_avl_dup_error ) ) {
   1507         snprintf( c->cr_msg, sizeof(c->cr_msg),
   1508                 "%s with OID %s already restricted",
   1509                 c->type == CFG_RESTRICT_EXOP ? "Extended operation" : "Control",
   1510                 c->argv[1] );
   1511         goto done;
   1512     }
   1513 
   1514     rc = LDAP_SUCCESS;
   1515 done:
   1516     if ( rc ) {
   1517         Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg );
   1518         if ( parsed_oid ) ch_free( parsed_oid );
   1519         if ( entry ) ch_free( entry );
   1520     }
   1521 
   1522     return rc;
   1523 }
   1524 
   1525 static int
   1526 config_tier( ConfigArgs *c )
   1527 {
   1528     int rc = LDAP_SUCCESS;
   1529     struct lload_tier_type *tier_impl;
   1530     LloadTier *tier = c->ca_private;
   1531     struct berval bv;
   1532     int i = 1;
   1533 
   1534     if ( c->op == SLAP_CONFIG_EMIT ) {
   1535         switch ( c->type ) {
   1536             case CFG_TIER:
   1537                 c->value_string = ch_strdup( tier->t_type.tier_name );
   1538                 break;
   1539             default:
   1540                 goto fail;
   1541                 break;
   1542         }
   1543         return rc;
   1544 
   1545     } else if ( c->op == LDAP_MOD_DELETE ) {
   1546         if ( lload_change.type != LLOAD_CHANGE_DEL ) {
   1547             /*
   1548              * TODO: Shouldn't really happen while this attribute is in the
   1549              * RDN, but we don't enforce it yet.
   1550              *
   1551              * How would we go about changing the backend type if we ever supported that?
   1552              */
   1553             goto fail;
   1554         }
   1555         return rc;
   1556     }
   1557 
   1558     if ( CONFIG_ONLINE_ADD( c ) ) {
   1559         assert( tier );
   1560         lload_change.target = tier;
   1561         ch_free( c->value_string );
   1562         return rc;
   1563     }
   1564 
   1565     tier_impl = lload_tier_find( c->value_string );
   1566     ch_free( c->value_string );
   1567     if ( !tier_impl ) {
   1568         goto fail;
   1569     }
   1570     tier = tier_impl->tier_init();
   1571     if ( !tier ) {
   1572         goto fail;
   1573     }
   1574 
   1575     lload_change.target = tier;
   1576 
   1577     if ( LDAP_STAILQ_EMPTY( &tiers ) ) {
   1578         LDAP_STAILQ_INSERT_HEAD( &tiers, tier, t_next );
   1579     } else {
   1580         LloadTier *tier2;
   1581         LDAP_STAILQ_FOREACH ( tier2, &tiers, t_next ) {
   1582             i++;
   1583         }
   1584         LDAP_STAILQ_INSERT_TAIL( &tiers, tier, t_next );
   1585     }
   1586 
   1587     bv.bv_val = c->cr_msg;
   1588     bv.bv_len = snprintf( c->cr_msg, sizeof(c->cr_msg), "tier %d", i );
   1589     ber_dupbv( &tier->t_name, &bv );
   1590 
   1591     return rc;
   1592 
   1593 fail:
   1594     if ( lload_change.type == LLOAD_CHANGE_ADD ) {
   1595         /* Abort the ADD */
   1596         lload_change.type = LLOAD_CHANGE_DEL;
   1597     }
   1598     return 1;
   1599 }
   1600 
   1601 static int
   1602 config_fname( ConfigArgs *c )
   1603 {
   1604     return 0;
   1605 }
   1606 
   1607 /*
   1608  * [listener=<listener>] [{read|write}=]<size>
   1609  */
   1610 
   1611 #ifdef LDAP_TCP_BUFFER
   1612 static BerVarray tcp_buffer;
   1613 static int tcp_buffer_num;
   1614 
   1615 #define SLAP_TCP_RMEM ( 0x1U )
   1616 #define SLAP_TCP_WMEM ( 0x2U )
   1617 
   1618 static int
   1619 tcp_buffer_parse(
   1620         struct berval *val,
   1621         int argc,
   1622         char **argv,
   1623         int *size,
   1624         int *rw,
   1625         LloadListener **l )
   1626 {
   1627     int i, rc = LDAP_SUCCESS;
   1628     LDAPURLDesc *lud = NULL;
   1629     char *ptr;
   1630 
   1631     if ( val != NULL && argv == NULL ) {
   1632         char *s = val->bv_val;
   1633 
   1634         argv = ldap_str2charray( s, " \t" );
   1635         if ( argv == NULL ) {
   1636             return LDAP_OTHER;
   1637         }
   1638     }
   1639 
   1640     i = 0;
   1641     if ( strncasecmp( argv[i], "listener=", STRLENOF("listener=") ) == 0 ) {
   1642         char *url = argv[i] + STRLENOF("listener=");
   1643 
   1644         if ( ldap_url_parse_ext( url, &lud, LDAP_PVT_URL_PARSE_DEF_PORT ) ) {
   1645             rc = LDAP_INVALID_SYNTAX;
   1646             goto done;
   1647         }
   1648 
   1649         *l = lload_config_check_my_url( url, lud );
   1650         if ( *l == NULL ) {
   1651             rc = LDAP_NO_SUCH_ATTRIBUTE;
   1652             goto done;
   1653         }
   1654 
   1655         i++;
   1656     }
   1657 
   1658     ptr = argv[i];
   1659     if ( strncasecmp( ptr, "read=", STRLENOF("read=") ) == 0 ) {
   1660         *rw |= SLAP_TCP_RMEM;
   1661         ptr += STRLENOF("read=");
   1662 
   1663     } else if ( strncasecmp( ptr, "write=", STRLENOF("write=") ) == 0 ) {
   1664         *rw |= SLAP_TCP_WMEM;
   1665         ptr += STRLENOF("write=");
   1666 
   1667     } else {
   1668         *rw |= ( SLAP_TCP_RMEM | SLAP_TCP_WMEM );
   1669     }
   1670 
   1671     /* accept any base */
   1672     if ( lutil_atoix( size, ptr, 0 ) ) {
   1673         rc = LDAP_INVALID_SYNTAX;
   1674         goto done;
   1675     }
   1676 
   1677 done:;
   1678     if ( val != NULL && argv != NULL ) {
   1679         ldap_charray_free( argv );
   1680     }
   1681 
   1682     if ( lud != NULL ) {
   1683         ldap_free_urldesc( lud );
   1684     }
   1685 
   1686     return rc;
   1687 }
   1688 
   1689 #ifdef BALANCER_MODULE
   1690 static int
   1691 tcp_buffer_delete_one( struct berval *val )
   1692 {
   1693     int rc = 0;
   1694     int size = -1, rw = 0;
   1695     LloadListener *l = NULL;
   1696 
   1697     rc = tcp_buffer_parse( val, 0, NULL, &size, &rw, &l );
   1698     if ( rc != 0 ) {
   1699         return rc;
   1700     }
   1701 
   1702     if ( l != NULL ) {
   1703         int i;
   1704         LloadListener **ll = lloadd_get_listeners();
   1705 
   1706         for ( i = 0; ll[i] != NULL; i++ ) {
   1707             if ( ll[i] == l ) break;
   1708         }
   1709 
   1710         if ( ll[i] == NULL ) {
   1711             return LDAP_NO_SUCH_ATTRIBUTE;
   1712         }
   1713 
   1714         if ( rw & SLAP_TCP_RMEM ) l->sl_tcp_rmem = -1;
   1715         if ( rw & SLAP_TCP_WMEM ) l->sl_tcp_wmem = -1;
   1716 
   1717         for ( i++; ll[i] != NULL && bvmatch( &l->sl_url, &ll[i]->sl_url );
   1718                 i++ ) {
   1719             if ( rw & SLAP_TCP_RMEM ) ll[i]->sl_tcp_rmem = -1;
   1720             if ( rw & SLAP_TCP_WMEM ) ll[i]->sl_tcp_wmem = -1;
   1721         }
   1722 
   1723     } else {
   1724         /* NOTE: this affects listeners without a specific setting,
   1725          * does not reset all listeners.  If a listener without
   1726          * specific settings was assigned a buffer because of
   1727          * a global setting, it will not be reset.  In any case,
   1728          * buffer changes will only take place at restart. */
   1729         if ( rw & SLAP_TCP_RMEM ) slapd_tcp_rmem = -1;
   1730         if ( rw & SLAP_TCP_WMEM ) slapd_tcp_wmem = -1;
   1731     }
   1732 
   1733     return rc;
   1734 }
   1735 
   1736 static int
   1737 tcp_buffer_delete( BerVarray vals )
   1738 {
   1739     int i;
   1740 
   1741     for ( i = 0; !BER_BVISNULL( &vals[i] ); i++ ) {
   1742         tcp_buffer_delete_one( &vals[i] );
   1743     }
   1744 
   1745     return 0;
   1746 }
   1747 #endif /* BALANCER_MODULE */
   1748 
   1749 static int
   1750 tcp_buffer_unparse( int size, int rw, LloadListener *l, struct berval *val )
   1751 {
   1752     char buf[sizeof("2147483648")], *ptr;
   1753 
   1754     /* unparse for later use */
   1755     val->bv_len = snprintf( buf, sizeof(buf), "%d", size );
   1756     if ( l != NULL ) {
   1757         val->bv_len += STRLENOF( "listener="
   1758                                  " " ) +
   1759                 l->sl_url.bv_len;
   1760     }
   1761 
   1762     if ( rw != ( SLAP_TCP_RMEM | SLAP_TCP_WMEM ) ) {
   1763         if ( rw & SLAP_TCP_RMEM ) {
   1764             val->bv_len += STRLENOF("read=");
   1765         } else if ( rw & SLAP_TCP_WMEM ) {
   1766             val->bv_len += STRLENOF("write=");
   1767         }
   1768     }
   1769 
   1770     val->bv_val = SLAP_MALLOC( val->bv_len + 1 );
   1771 
   1772     ptr = val->bv_val;
   1773 
   1774     if ( l != NULL ) {
   1775         ptr = lutil_strcopy( ptr, "listener=" );
   1776         ptr = lutil_strncopy( ptr, l->sl_url.bv_val, l->sl_url.bv_len );
   1777         *ptr++ = ' ';
   1778     }
   1779 
   1780     if ( rw != ( SLAP_TCP_RMEM | SLAP_TCP_WMEM ) ) {
   1781         if ( rw & SLAP_TCP_RMEM ) {
   1782             ptr = lutil_strcopy( ptr, "read=" );
   1783         } else if ( rw & SLAP_TCP_WMEM ) {
   1784             ptr = lutil_strcopy( ptr, "write=" );
   1785         }
   1786     }
   1787 
   1788     ptr = lutil_strcopy( ptr, buf );
   1789     *ptr = '\0';
   1790 
   1791     assert( val->bv_val + val->bv_len == ptr );
   1792 
   1793     return LDAP_SUCCESS;
   1794 }
   1795 
   1796 static int
   1797 tcp_buffer_add_one( int argc, char **argv )
   1798 {
   1799     int rc = 0;
   1800     int size = -1, rw = 0;
   1801     LloadListener *l = NULL;
   1802 
   1803     struct berval val;
   1804 
   1805     /* parse */
   1806     rc = tcp_buffer_parse( NULL, argc, argv, &size, &rw, &l );
   1807     if ( rc != 0 ) {
   1808         return rc;
   1809     }
   1810 
   1811     /* unparse for later use */
   1812     rc = tcp_buffer_unparse( size, rw, l, &val );
   1813     if ( rc != LDAP_SUCCESS ) {
   1814         return rc;
   1815     }
   1816 
   1817     /* use parsed values */
   1818     if ( l != NULL ) {
   1819         int i;
   1820         LloadListener **ll = lloadd_get_listeners();
   1821 
   1822         for ( i = 0; ll[i] != NULL; i++ ) {
   1823             if ( ll[i] == l ) break;
   1824         }
   1825 
   1826         if ( ll[i] == NULL ) {
   1827             return LDAP_NO_SUCH_ATTRIBUTE;
   1828         }
   1829 
   1830         /* buffer only applies to TCP listeners;
   1831          * we do not do any check here, and delegate them
   1832          * to setsockopt(2) */
   1833         if ( rw & SLAP_TCP_RMEM ) l->sl_tcp_rmem = size;
   1834         if ( rw & SLAP_TCP_WMEM ) l->sl_tcp_wmem = size;
   1835 
   1836         for ( i++; ll[i] != NULL && bvmatch( &l->sl_url, &ll[i]->sl_url );
   1837                 i++ ) {
   1838             if ( rw & SLAP_TCP_RMEM ) ll[i]->sl_tcp_rmem = size;
   1839             if ( rw & SLAP_TCP_WMEM ) ll[i]->sl_tcp_wmem = size;
   1840         }
   1841 
   1842     } else {
   1843         /* NOTE: this affects listeners without a specific setting,
   1844          * does not set all listeners */
   1845         if ( rw & SLAP_TCP_RMEM ) slapd_tcp_rmem = size;
   1846         if ( rw & SLAP_TCP_WMEM ) slapd_tcp_wmem = size;
   1847     }
   1848 
   1849     tcp_buffer = SLAP_REALLOC(
   1850             tcp_buffer, sizeof(struct berval) * ( tcp_buffer_num + 2 ) );
   1851     /* append */
   1852     tcp_buffer[tcp_buffer_num] = val;
   1853 
   1854     tcp_buffer_num++;
   1855     BER_BVZERO( &tcp_buffer[tcp_buffer_num] );
   1856 
   1857     return rc;
   1858 }
   1859 
   1860 static int
   1861 config_tcp_buffer( ConfigArgs *c )
   1862 {
   1863     int rc = LDAP_SUCCESS;
   1864 
   1865 #ifdef BALANCER_MODULE
   1866     if ( c->op == SLAP_CONFIG_EMIT ) {
   1867         if ( tcp_buffer == NULL || BER_BVISNULL( &tcp_buffer[0] ) ) {
   1868             return 1;
   1869         }
   1870         value_add( &c->rvalue_vals, tcp_buffer );
   1871         value_add( &c->rvalue_nvals, tcp_buffer );
   1872 
   1873         return 0;
   1874     } else if ( c->op == LDAP_MOD_DELETE ) {
   1875         if ( !c->line ) {
   1876             tcp_buffer_delete( tcp_buffer );
   1877             ber_bvarray_free( tcp_buffer );
   1878             tcp_buffer = NULL;
   1879             tcp_buffer_num = 0;
   1880 
   1881         } else {
   1882             int size = -1, rw = 0;
   1883             LloadListener *l = NULL;
   1884 
   1885             struct berval val = BER_BVNULL;
   1886 
   1887             int i;
   1888 
   1889             if ( tcp_buffer_num == 0 ) {
   1890                 return 1;
   1891             }
   1892 
   1893             /* parse */
   1894             rc = tcp_buffer_parse(
   1895                     NULL, c->argc - 1, &c->argv[1], &size, &rw, &l );
   1896             if ( rc != 0 ) {
   1897                 return 1;
   1898             }
   1899 
   1900             /* unparse for later use */
   1901             rc = tcp_buffer_unparse( size, rw, l, &val );
   1902             if ( rc != LDAP_SUCCESS ) {
   1903                 return 1;
   1904             }
   1905 
   1906             for ( i = 0; !BER_BVISNULL( &tcp_buffer[i] ); i++ ) {
   1907                 if ( bvmatch( &tcp_buffer[i], &val ) ) {
   1908                     break;
   1909                 }
   1910             }
   1911 
   1912             if ( BER_BVISNULL( &tcp_buffer[i] ) ) {
   1913                 /* not found */
   1914                 rc = 1;
   1915                 goto done;
   1916             }
   1917 
   1918             tcp_buffer_delete_one( &tcp_buffer[i] );
   1919             ber_memfree( tcp_buffer[i].bv_val );
   1920             for ( ; i < tcp_buffer_num; i++ ) {
   1921                 tcp_buffer[i] = tcp_buffer[i + 1];
   1922             }
   1923             tcp_buffer_num--;
   1924 
   1925 done:;
   1926             if ( !BER_BVISNULL( &val ) ) {
   1927                 SLAP_FREE(val.bv_val);
   1928             }
   1929         }
   1930 
   1931         return rc;
   1932     }
   1933 #endif /* BALANCER_MODULE */
   1934 
   1935     rc = tcp_buffer_add_one( c->argc - 1, &c->argv[1] );
   1936     if ( rc ) {
   1937         snprintf( c->cr_msg, sizeof(c->cr_msg), "<%s> unable to add value #%d",
   1938                 c->argv[0], tcp_buffer_num );
   1939         Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg );
   1940         return 1;
   1941     }
   1942 
   1943     return 0;
   1944 }
   1945 #endif /* LDAP_TCP_BUFFER */
   1946 
   1947 static int
   1948 config_restrict( ConfigArgs *c )
   1949 {
   1950     slap_mask_t restrictops = 0;
   1951     int i;
   1952     slap_verbmasks restrictable_ops[] = {
   1953         { BER_BVC("bind"), SLAP_RESTRICT_OP_BIND },
   1954         { BER_BVC("add"), SLAP_RESTRICT_OP_ADD },
   1955         { BER_BVC("modify"), SLAP_RESTRICT_OP_MODIFY },
   1956         { BER_BVC("rename"), SLAP_RESTRICT_OP_RENAME },
   1957         { BER_BVC("modrdn"), 0 },
   1958         { BER_BVC("delete"), SLAP_RESTRICT_OP_DELETE },
   1959         { BER_BVC("search"), SLAP_RESTRICT_OP_SEARCH },
   1960         { BER_BVC("compare"), SLAP_RESTRICT_OP_COMPARE },
   1961         { BER_BVC("read"), SLAP_RESTRICT_OP_READS },
   1962         { BER_BVC("write"), SLAP_RESTRICT_OP_WRITES },
   1963         { BER_BVC("extended"), SLAP_RESTRICT_OP_EXTENDED },
   1964         { BER_BVC("extended=" LDAP_EXOP_START_TLS), SLAP_RESTRICT_EXOP_START_TLS },
   1965         { BER_BVC("extended=" LDAP_EXOP_MODIFY_PASSWD), SLAP_RESTRICT_EXOP_MODIFY_PASSWD },
   1966         { BER_BVC("extended=" LDAP_EXOP_X_WHO_AM_I), SLAP_RESTRICT_EXOP_WHOAMI },
   1967         { BER_BVC("extended=" LDAP_EXOP_X_CANCEL), SLAP_RESTRICT_EXOP_CANCEL },
   1968         { BER_BVC("all"), SLAP_RESTRICT_OP_ALL },
   1969         { BER_BVNULL, 0 }
   1970     };
   1971 
   1972     i = verbs_to_mask( c->argc, c->argv, restrictable_ops, &restrictops );
   1973     if ( i ) {
   1974         snprintf( c->cr_msg, sizeof(c->cr_msg), "<%s> unknown operation",
   1975                 c->argv[0] );
   1976         Debug( LDAP_DEBUG_ANY, "%s: %s %s\n",
   1977                 c->log, c->cr_msg, c->argv[i] );
   1978         return 1;
   1979     }
   1980     if ( restrictops & SLAP_RESTRICT_OP_EXTENDED )
   1981         restrictops &= ~SLAP_RESTRICT_EXOP_MASK;
   1982     return 0;
   1983 }
   1984 
   1985 static int
   1986 config_include( ConfigArgs *c )
   1987 {
   1988     int savelineno = c->lineno;
   1989     int rc;
   1990     ConfigFile *cf;
   1991     ConfigFile *cfsave = cfn;
   1992     ConfigFile *cf2 = NULL;
   1993 
   1994     /* Leftover from RE23. No dynamic config for include files */
   1995     if ( c->op == SLAP_CONFIG_EMIT || c->op == LDAP_MOD_DELETE ) return 1;
   1996 
   1997     cf = ch_calloc( 1, sizeof(ConfigFile) );
   1998     if ( cfn->c_kids ) {
   1999         for ( cf2 = cfn->c_kids; cf2 && cf2->c_sibs; cf2 = cf2->c_sibs )
   2000             /* empty */;
   2001         cf2->c_sibs = cf;
   2002     } else {
   2003         cfn->c_kids = cf;
   2004     }
   2005     cfn = cf;
   2006     ber_str2bv( c->argv[1], 0, 1, &cf->c_file );
   2007     rc = lload_read_config_file(
   2008             c->argv[1], c->depth + 1, c, config_back_cf_table );
   2009     c->lineno = savelineno - 1;
   2010     cfn = cfsave;
   2011     if ( rc ) {
   2012         if ( cf2 )
   2013             cf2->c_sibs = NULL;
   2014         else
   2015             cfn->c_kids = NULL;
   2016         ch_free( cf->c_file.bv_val );
   2017         ch_free( cf );
   2018     } else {
   2019         c->ca_private = cf;
   2020     }
   2021     return rc;
   2022 }
   2023 
   2024 static int
   2025 config_feature( ConfigArgs *c )
   2026 {
   2027     slap_verbmasks features[] = {
   2028 #ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS
   2029         { BER_BVC("vc"), LLOAD_FEATURE_VC },
   2030 #endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */
   2031         { BER_BVC("proxyauthz"), LLOAD_FEATURE_PROXYAUTHZ },
   2032         { BER_BVC("read_pause"), LLOAD_FEATURE_PAUSE },
   2033         { BER_BVNULL, 0 }
   2034     };
   2035     slap_mask_t mask = 0;
   2036     int i;
   2037 
   2038     if ( c->op == SLAP_CONFIG_EMIT ) {
   2039         return mask_to_verbs( features, lload_features, &c->rvalue_vals );
   2040     }
   2041 
   2042     lload_change.type = LLOAD_CHANGE_MODIFY;
   2043     lload_change.object = LLOAD_DAEMON;
   2044     lload_change.flags.daemon |= LLOAD_DAEMON_MOD_FEATURES;
   2045     if ( !lload_change.target ) {
   2046         lload_change.target = (void *)(uintptr_t)~lload_features;
   2047     }
   2048 
   2049     if ( c->op == LDAP_MOD_DELETE ) {
   2050         if ( !c->line ) {
   2051             /* Last value has been deleted */
   2052             lload_features = 0;
   2053         } else {
   2054             i = verb_to_mask( c->line, features );
   2055             lload_features &= ~features[i].mask;
   2056         }
   2057         return 0;
   2058     }
   2059 
   2060     i = verbs_to_mask( c->argc, c->argv, features, &mask );
   2061     if ( i ) {
   2062         Debug( LDAP_DEBUG_ANY, "%s: <%s> unknown feature %s\n", c->log,
   2063                 c->argv[0], c->argv[i] );
   2064         return 1;
   2065     }
   2066 
   2067     if ( mask & ~LLOAD_FEATURE_SUPPORTED_MASK ) {
   2068         for ( i = 1; i < c->argc; i++ ) {
   2069             int j = verb_to_mask( c->argv[i], features );
   2070             if ( features[j].mask & ~LLOAD_FEATURE_SUPPORTED_MASK ) {
   2071                 Debug( LDAP_DEBUG_ANY, "%s: <%s> "
   2072                         "experimental feature %s is undocumented, unsupported "
   2073                         "and can change or disappear at any time!\n",
   2074                         c->log, c->argv[0], c->argv[i] );
   2075             }
   2076         }
   2077     }
   2078 
   2079     lload_features |= mask;
   2080     return 0;
   2081 }
   2082 
   2083 #ifdef HAVE_TLS
   2084 static int
   2085 config_tls_cleanup( ConfigArgs *c )
   2086 {
   2087     int rc = 0;
   2088 
   2089     if ( lload_tls_ld ) {
   2090         int opt = 1;
   2091 
   2092         ldap_pvt_tls_ctx_free( lload_tls_ctx );
   2093         lload_tls_ctx = NULL;
   2094 
   2095         /* Force new ctx to be created */
   2096         rc = ldap_pvt_tls_set_option(
   2097                 lload_tls_ld, LDAP_OPT_X_TLS_NEWCTX, &opt );
   2098         if ( rc == 0 ) {
   2099             /* The ctx's refcount is bumped up here */
   2100             ldap_pvt_tls_get_option(
   2101                     lload_tls_ld, LDAP_OPT_X_TLS_CTX, &lload_tls_ctx );
   2102         } else {
   2103             if ( rc == LDAP_NOT_SUPPORTED )
   2104                 rc = LDAP_UNWILLING_TO_PERFORM;
   2105             else
   2106                 rc = LDAP_OTHER;
   2107         }
   2108     }
   2109     return rc;
   2110 }
   2111 
   2112 static int
   2113 config_tls_option( ConfigArgs *c )
   2114 {
   2115     int flag;
   2116     int berval = 0;
   2117     LDAP *ld = lload_tls_ld;
   2118 
   2119     switch ( c->type ) {
   2120         case CFG_TLS_RAND:
   2121             flag = LDAP_OPT_X_TLS_RANDOM_FILE;
   2122             ld = NULL;
   2123             break;
   2124         case CFG_TLS_CIPHER:
   2125             flag = LDAP_OPT_X_TLS_CIPHER_SUITE;
   2126             break;
   2127         case CFG_TLS_CERT_FILE:
   2128             flag = LDAP_OPT_X_TLS_CERTFILE;
   2129             break;
   2130         case CFG_TLS_CERT_KEY:
   2131             flag = LDAP_OPT_X_TLS_KEYFILE;
   2132             break;
   2133         case CFG_TLS_CA_PATH:
   2134             flag = LDAP_OPT_X_TLS_CACERTDIR;
   2135             break;
   2136         case CFG_TLS_CA_FILE:
   2137             flag = LDAP_OPT_X_TLS_CACERTFILE;
   2138             break;
   2139         case CFG_TLS_DH_FILE:
   2140             flag = LDAP_OPT_X_TLS_DHFILE;
   2141             break;
   2142         case CFG_TLS_ECNAME:
   2143             flag = LDAP_OPT_X_TLS_ECNAME;
   2144             break;
   2145 #ifdef HAVE_GNUTLS
   2146         case CFG_TLS_CRL_FILE:
   2147             flag = LDAP_OPT_X_TLS_CRLFILE;
   2148             break;
   2149 #endif
   2150         case CFG_TLS_CACERT:
   2151             flag = LDAP_OPT_X_TLS_CACERT;
   2152             berval = 1;
   2153             break;
   2154         case CFG_TLS_CERT:
   2155             flag = LDAP_OPT_X_TLS_CERT;
   2156             berval = 1;
   2157             break;
   2158         case CFG_TLS_KEY:
   2159             flag = LDAP_OPT_X_TLS_KEY;
   2160             berval = 1;
   2161             break;
   2162         default:
   2163             Debug( LDAP_DEBUG_ANY, "%s: "
   2164                     "unknown tls_option <0x%x>\n",
   2165                     c->log, c->type );
   2166             return 1;
   2167     }
   2168     if ( c->op == SLAP_CONFIG_EMIT ) {
   2169         return ldap_pvt_tls_get_option( ld, flag,
   2170                 berval ? (void *)&c->value_bv : (void *)&c->value_string );
   2171     }
   2172 
   2173     lload_change.type = LLOAD_CHANGE_MODIFY;
   2174     lload_change.object = LLOAD_DAEMON;
   2175     lload_change.flags.daemon |= LLOAD_DAEMON_MOD_TLS;
   2176 
   2177     config_push_cleanup( c, config_tls_cleanup );
   2178     if ( c->op == LDAP_MOD_DELETE ) {
   2179         return ldap_pvt_tls_set_option( ld, flag, NULL );
   2180     }
   2181     if ( !berval ) ch_free( c->value_string );
   2182     return ldap_pvt_tls_set_option(
   2183             ld, flag, berval ? (void *)&c->value_bv : (void *)c->argv[1] );
   2184 }
   2185 
   2186 /* FIXME: this ought to be provided by libldap */
   2187 static int
   2188 config_tls_config( ConfigArgs *c )
   2189 {
   2190     int i, flag;
   2191 
   2192     switch ( c->type ) {
   2193         case CFG_TLS_CRLCHECK:
   2194             flag = LDAP_OPT_X_TLS_CRLCHECK;
   2195             break;
   2196         case CFG_TLS_VERIFY:
   2197             flag = LDAP_OPT_X_TLS_REQUIRE_CERT;
   2198             break;
   2199         case CFG_TLS_PROTOCOL_MIN:
   2200             flag = LDAP_OPT_X_TLS_PROTOCOL_MIN;
   2201             break;
   2202         default:
   2203             Debug( LDAP_DEBUG_ANY, "%s: "
   2204                     "unknown tls_option <0x%x>\n",
   2205                     c->log, c->type );
   2206             return 1;
   2207     }
   2208     if ( c->op == SLAP_CONFIG_EMIT ) {
   2209         return lload_tls_get_config( lload_tls_ld, flag, &c->value_string );
   2210     }
   2211 
   2212     lload_change.type = LLOAD_CHANGE_MODIFY;
   2213     lload_change.object = LLOAD_DAEMON;
   2214     lload_change.flags.daemon |= LLOAD_DAEMON_MOD_TLS;
   2215 
   2216     config_push_cleanup( c, config_tls_cleanup );
   2217     if ( c->op == LDAP_MOD_DELETE ) {
   2218         int i = 0;
   2219         return ldap_pvt_tls_set_option( lload_tls_ld, flag, &i );
   2220     }
   2221     ch_free( c->value_string );
   2222     if ( isdigit( (unsigned char)c->argv[1][0] ) &&
   2223             c->type != CFG_TLS_PROTOCOL_MIN ) {
   2224         if ( lutil_atoi( &i, c->argv[1] ) != 0 ) {
   2225             Debug( LDAP_DEBUG_ANY, "%s: "
   2226                     "unable to parse %s \"%s\"\n",
   2227                     c->log, c->argv[0], c->argv[1] );
   2228             return 1;
   2229         }
   2230         return ldap_pvt_tls_set_option( lload_tls_ld, flag, &i );
   2231     } else {
   2232         return ldap_pvt_tls_config( lload_tls_ld, flag, c->argv[1] );
   2233     }
   2234 }
   2235 #endif
   2236 
   2237 #ifdef BALANCER_MODULE
   2238 static int
   2239 config_share_tls_ctx( ConfigArgs *c )
   2240 {
   2241     int rc = LDAP_SUCCESS;
   2242 
   2243     if ( c->op == SLAP_CONFIG_EMIT ) {
   2244         c->value_int = lload_use_slap_tls_ctx;
   2245         return rc;
   2246     }
   2247 
   2248     lload_change.type = LLOAD_CHANGE_MODIFY;
   2249     lload_change.object = LLOAD_DAEMON;
   2250     lload_change.flags.daemon |= LLOAD_DAEMON_MOD_TLS;
   2251 
   2252     if ( c->op == LDAP_MOD_DELETE ) {
   2253         lload_use_slap_tls_ctx = 0;
   2254         return rc;
   2255     }
   2256 
   2257     lload_use_slap_tls_ctx = c->value_int;
   2258     return rc;
   2259 }
   2260 #endif /* BALANCER_MODULE */
   2261 
   2262 void
   2263 lload_init_config_argv( ConfigArgs *c )
   2264 {
   2265     c->argv = ch_calloc( ARGS_STEP + 1, sizeof(*c->argv) );
   2266     c->argv_size = ARGS_STEP + 1;
   2267 }
   2268 
   2269 ConfigTable *
   2270 lload_config_find_keyword( ConfigTable *Conf, ConfigArgs *c )
   2271 {
   2272     int i;
   2273 
   2274     for ( i = 0; Conf[i].name; i++ )
   2275         if ( ( Conf[i].length &&
   2276                      ( !strncasecmp(
   2277                              c->argv[0], Conf[i].name, Conf[i].length ) ) ) ||
   2278                 ( !strcasecmp( c->argv[0], Conf[i].name ) ) )
   2279             break;
   2280     if ( !Conf[i].name ) return NULL;
   2281     if ( (Conf[i].arg_type & ARGS_TYPES) == ARG_BINARY ) {
   2282         size_t decode_len = LUTIL_BASE64_DECODE_LEN( c->linelen );
   2283         ch_free( c->tline );
   2284         c->tline = ch_malloc( decode_len + 1 );
   2285         c->linelen = lutil_b64_pton( c->line, c->tline, decode_len );
   2286         if ( c->linelen < 0 ) {
   2287             ch_free( c->tline );
   2288             c->tline = NULL;
   2289             return NULL;
   2290         }
   2291         c->line = c->tline;
   2292     }
   2293     c->ca_desc = Conf + i;
   2294     return c->ca_desc;
   2295 }
   2296 
   2297 int
   2298 lload_config_check_vals( ConfigTable *Conf, ConfigArgs *c, int check_only )
   2299 {
   2300     int arg_user, arg_type, arg_syn, iarg;
   2301     unsigned uiarg;
   2302     long larg;
   2303     unsigned long ularg;
   2304     ber_len_t barg;
   2305 
   2306     if ( Conf->arg_type == ARG_IGNORED ) {
   2307         Debug( LDAP_DEBUG_CONFIG, "%s: keyword <%s> ignored\n",
   2308                 c->log, Conf->name );
   2309         return 0;
   2310     }
   2311     arg_type = Conf->arg_type & ARGS_TYPES;
   2312     arg_user = Conf->arg_type & ARGS_USERLAND;
   2313     arg_syn = Conf->arg_type & ARGS_SYNTAX;
   2314 
   2315     if ( Conf->min_args && ( c->argc < Conf->min_args ) ) {
   2316         snprintf( c->cr_msg, sizeof(c->cr_msg), "<%s> missing <%s> argument",
   2317                 c->argv[0], Conf->what ? Conf->what : "" );
   2318         Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: keyword %s\n",
   2319                 c->log, c->cr_msg );
   2320         return ARG_BAD_CONF;
   2321     }
   2322     if ( Conf->max_args && ( c->argc > Conf->max_args ) ) {
   2323         char *ignored = " ignored";
   2324 
   2325         snprintf( c->cr_msg, sizeof(c->cr_msg), "<%s> extra cruft after <%s>",
   2326                 c->argv[0], Conf->what );
   2327 
   2328         ignored = "";
   2329         Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s%s\n",
   2330                 c->log, c->cr_msg, ignored );
   2331         return ARG_BAD_CONF;
   2332     }
   2333     if ( (arg_syn & ARG_PAREN) && *c->argv[1] != '(' /*')'*/ ) {
   2334         snprintf( c->cr_msg, sizeof(c->cr_msg), "<%s> old format not supported",
   2335                 c->argv[0] );
   2336         Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n",
   2337                 c->log, c->cr_msg );
   2338         return ARG_BAD_CONF;
   2339     }
   2340     if ( arg_type && !Conf->arg_item && !(arg_syn & ARG_OFFSET) ) {
   2341         snprintf( c->cr_msg, sizeof(c->cr_msg),
   2342                 "<%s> invalid config_table, arg_item is NULL",
   2343                 c->argv[0] );
   2344         Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n",
   2345                 c->log, c->cr_msg );
   2346         return ARG_BAD_CONF;
   2347     }
   2348     c->type = arg_user;
   2349     memset( &c->values, 0, sizeof(c->values) );
   2350     if ( arg_type == ARG_STRING ) {
   2351         assert( c->argc == 2 );
   2352         if ( !check_only ) c->value_string = ch_strdup( c->argv[1] );
   2353     } else if ( arg_type == ARG_BERVAL ) {
   2354         assert( c->argc == 2 );
   2355         if ( !check_only ) ber_str2bv( c->argv[1], 0, 1, &c->value_bv );
   2356     } else if ( arg_type == ARG_BINARY ) {
   2357         assert( c->argc == 2 );
   2358         if ( !check_only ) {
   2359             c->value_bv.bv_len = c->linelen;
   2360             c->value_bv.bv_val = ch_malloc( c->linelen );
   2361             AC_MEMCPY( c->value_bv.bv_val, c->line, c->linelen );
   2362         }
   2363     } else { /* all numeric */
   2364         int j;
   2365         iarg = 0;
   2366         larg = 0;
   2367         barg = 0;
   2368         switch ( arg_type ) {
   2369             case ARG_INT:
   2370                 assert( c->argc == 2 );
   2371                 if ( lutil_atoix( &iarg, c->argv[1], 0 ) != 0 ) {
   2372                     snprintf( c->cr_msg, sizeof(c->cr_msg),
   2373                             "<%s> unable to parse \"%s\" as int",
   2374                             c->argv[0], c->argv[1] );
   2375                     Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n",
   2376                             c->log, c->cr_msg );
   2377                     return ARG_BAD_CONF;
   2378                 }
   2379                 break;
   2380             case ARG_UINT:
   2381                 assert( c->argc == 2 );
   2382                 if ( lutil_atoux( &uiarg, c->argv[1], 0 ) != 0 ) {
   2383                     snprintf( c->cr_msg, sizeof(c->cr_msg),
   2384                             "<%s> unable to parse \"%s\" as unsigned int",
   2385                             c->argv[0], c->argv[1] );
   2386                     Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n",
   2387                             c->log, c->cr_msg );
   2388                     return ARG_BAD_CONF;
   2389                 }
   2390                 break;
   2391             case ARG_LONG:
   2392                 assert( c->argc == 2 );
   2393                 if ( lutil_atolx( &larg, c->argv[1], 0 ) != 0 ) {
   2394                     snprintf( c->cr_msg, sizeof(c->cr_msg),
   2395                             "<%s> unable to parse \"%s\" as long",
   2396                             c->argv[0], c->argv[1] );
   2397                     Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n",
   2398                             c->log, c->cr_msg );
   2399                     return ARG_BAD_CONF;
   2400                 }
   2401                 break;
   2402             case ARG_ULONG:
   2403                 assert( c->argc == 2 );
   2404                 if ( LUTIL_ATOULX( &ularg, c->argv[1], 0 ) != 0 ) {
   2405                     snprintf( c->cr_msg, sizeof(c->cr_msg),
   2406                             "<%s> unable to parse \"%s\" as unsigned long",
   2407                             c->argv[0], c->argv[1] );
   2408                     Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n",
   2409                             c->log, c->cr_msg );
   2410                     return ARG_BAD_CONF;
   2411                 }
   2412                 break;
   2413             case ARG_BER_LEN_T: {
   2414                 unsigned long l;
   2415                 assert( c->argc == 2 );
   2416                 if ( lutil_atoulx( &l, c->argv[1], 0 ) != 0 ) {
   2417                     snprintf( c->cr_msg, sizeof(c->cr_msg),
   2418                             "<%s> unable to parse \"%s\" as ber_len_t",
   2419                             c->argv[0], c->argv[1] );
   2420                     Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n",
   2421                             c->log, c->cr_msg );
   2422                     return ARG_BAD_CONF;
   2423                 }
   2424                 barg = (ber_len_t)l;
   2425             } break;
   2426             case ARG_ON_OFF:
   2427                 /* note: this is an explicit exception
   2428                  * to the "need exactly 2 args" rule */
   2429                 if ( c->argc == 1 ) {
   2430                     iarg = 1;
   2431                 } else if ( !strcasecmp( c->argv[1], "on" ) ||
   2432                         !strcasecmp( c->argv[1], "true" ) ||
   2433                         !strcasecmp( c->argv[1], "yes" ) ) {
   2434                     iarg = 1;
   2435                 } else if ( !strcasecmp( c->argv[1], "off" ) ||
   2436                         !strcasecmp( c->argv[1], "false" ) ||
   2437                         !strcasecmp( c->argv[1], "no" ) ) {
   2438                     iarg = 0;
   2439                 } else {
   2440                     snprintf( c->cr_msg, sizeof(c->cr_msg),
   2441                             "<%s> invalid value",
   2442                             c->argv[0] );
   2443                     Debug( LDAP_DEBUG_ANY|LDAP_DEBUG_NONE, "%s: %s\n",
   2444                             c->log, c->cr_msg );
   2445                     return ARG_BAD_CONF;
   2446                 }
   2447                 break;
   2448         }
   2449         j = (arg_type & ARG_NONZERO) ? 1 : 0;
   2450         if ( iarg < j && larg < j && barg < (unsigned)j ) {
   2451             larg = larg ? larg : ( barg ? (long)barg : iarg );
   2452             snprintf( c->cr_msg, sizeof(c->cr_msg), "<%s> invalid value",
   2453                     c->argv[0] );
   2454             Debug( LDAP_DEBUG_ANY|LDAP_DEBUG_NONE, "%s: %s\n",
   2455                     c->log, c->cr_msg );
   2456             return ARG_BAD_CONF;
   2457         }
   2458         switch ( arg_type ) {
   2459             case ARG_ON_OFF:
   2460             case ARG_INT:
   2461                 c->value_int = iarg;
   2462                 break;
   2463             case ARG_UINT:
   2464                 c->value_uint = uiarg;
   2465                 break;
   2466             case ARG_LONG:
   2467                 c->value_long = larg;
   2468                 break;
   2469             case ARG_ULONG:
   2470                 c->value_ulong = ularg;
   2471                 break;
   2472             case ARG_BER_LEN_T:
   2473                 c->value_ber_t = barg;
   2474                 break;
   2475         }
   2476     }
   2477     return 0;
   2478 }
   2479 
   2480 int
   2481 lload_config_set_vals( ConfigTable *Conf, ConfigArgs *c )
   2482 {
   2483     int rc, arg_type;
   2484     void *ptr = NULL;
   2485 
   2486     arg_type = Conf->arg_type;
   2487     if ( arg_type & ARG_MAGIC ) {
   2488         c->cr_msg[0] = '\0';
   2489         rc = ( *( (ConfigDriver *)Conf->arg_item ) )( c );
   2490         if ( rc ) {
   2491             if ( !c->cr_msg[0] ) {
   2492                 snprintf( c->cr_msg, sizeof(c->cr_msg),
   2493                         "<%s> handler exited with %d",
   2494                         c->argv[0], rc );
   2495                 Debug( LDAP_DEBUG_CONFIG, "%s: %s!\n", c->log, c->cr_msg );
   2496             }
   2497             return ARG_BAD_CONF;
   2498         }
   2499         return 0;
   2500     }
   2501     if ( arg_type & ARG_OFFSET ) {
   2502         {
   2503             snprintf( c->cr_msg, sizeof(c->cr_msg),
   2504                     "<%s> offset is missing base pointer",
   2505                     c->argv[0] );
   2506             Debug( LDAP_DEBUG_CONFIG, "%s: %s!\n", c->log, c->cr_msg );
   2507             return ARG_BAD_CONF;
   2508         }
   2509         ptr = (void *)( (char *)ptr + (long)Conf->arg_item );
   2510     } else if ( arg_type & ARGS_TYPES ) {
   2511         ptr = Conf->arg_item;
   2512     }
   2513     if ( arg_type & ARGS_TYPES ) switch ( arg_type & ARGS_TYPES ) {
   2514             case ARG_ON_OFF:
   2515             case ARG_INT:
   2516                 *(int *)ptr = c->value_int;
   2517                 break;
   2518             case ARG_UINT:
   2519                 *(unsigned *)ptr = c->value_uint;
   2520                 break;
   2521             case ARG_LONG:
   2522                 *(long *)ptr = c->value_long;
   2523                 break;
   2524             case ARG_ULONG:
   2525                 *(size_t *)ptr = c->value_ulong;
   2526                 break;
   2527             case ARG_BER_LEN_T:
   2528                 *(ber_len_t *)ptr = c->value_ber_t;
   2529                 break;
   2530             case ARG_STRING: {
   2531                 char *cc = *(char **)ptr;
   2532                 if ( cc ) {
   2533                     if ( (arg_type & ARG_UNIQUE) &&
   2534                             c->op == SLAP_CONFIG_ADD ) {
   2535                         Debug( LDAP_DEBUG_CONFIG, "%s: already set %s!\n",
   2536                                 c->log, Conf->name );
   2537                         return ARG_BAD_CONF;
   2538                     }
   2539                     ch_free( cc );
   2540                 }
   2541                 *(char **)ptr = c->value_string;
   2542                 break;
   2543             }
   2544             case ARG_BERVAL:
   2545             case ARG_BINARY:
   2546                 *(struct berval *)ptr = c->value_bv;
   2547                 break;
   2548         }
   2549     return 0;
   2550 }
   2551 
   2552 int
   2553 lload_config_add_vals( ConfigTable *Conf, ConfigArgs *c )
   2554 {
   2555     int rc, arg_type;
   2556 
   2557     arg_type = Conf->arg_type;
   2558     if ( arg_type == ARG_IGNORED ) {
   2559         Debug( LDAP_DEBUG_CONFIG, "%s: keyword <%s> ignored\n",
   2560                 c->log, Conf->name );
   2561         return 0;
   2562     }
   2563     rc = lload_config_check_vals( Conf, c, 0 );
   2564     if ( rc ) return rc;
   2565     return lload_config_set_vals( Conf, c );
   2566 }
   2567 
   2568 int
   2569 lload_read_config_file(
   2570         const char *fname,
   2571         int depth,
   2572         ConfigArgs *cf,
   2573         ConfigTable *cft )
   2574 {
   2575     FILE *fp;
   2576     ConfigTable *ct;
   2577     ConfigArgs *c;
   2578     int rc;
   2579     struct stat s;
   2580 
   2581     c = ch_calloc( 1, sizeof(ConfigArgs) );
   2582     if ( c == NULL ) {
   2583         return 1;
   2584     }
   2585 
   2586     if ( depth ) {
   2587         memcpy( c, cf, sizeof(ConfigArgs) );
   2588     } else {
   2589         c->depth = depth; /* XXX */
   2590     }
   2591 
   2592     c->valx = -1;
   2593     c->fname = fname;
   2594     lload_init_config_argv( c );
   2595 
   2596     if ( stat( fname, &s ) != 0 ) {
   2597         char ebuf[128];
   2598         int saved_errno = errno;
   2599         ldap_syslog = 1;
   2600         Debug( LDAP_DEBUG_ANY, "could not stat config file \"%s\": %s (%d)\n",
   2601                 fname, AC_STRERROR_R( saved_errno, ebuf, sizeof(ebuf) ),
   2602                 saved_errno );
   2603         ch_free( c->argv );
   2604         ch_free( c );
   2605         return 1;
   2606     }
   2607 
   2608     if ( !S_ISREG(s.st_mode) ) {
   2609         ldap_syslog = 1;
   2610         Debug( LDAP_DEBUG_ANY, "regular file expected, got \"%s\"\n", fname );
   2611         ch_free( c->argv );
   2612         ch_free( c );
   2613         return 1;
   2614     }
   2615 
   2616     fp = fopen( fname, "r" );
   2617     if ( fp == NULL ) {
   2618         char ebuf[128];
   2619         int saved_errno = errno;
   2620         ldap_syslog = 1;
   2621         Debug( LDAP_DEBUG_ANY, "could not open config file \"%s\": %s (%d)\n",
   2622                 fname, AC_STRERROR_R( saved_errno, ebuf, sizeof(ebuf) ),
   2623                 saved_errno );
   2624         ch_free( c->argv );
   2625         ch_free( c );
   2626         return 1;
   2627     }
   2628 
   2629     Debug( LDAP_DEBUG_CONFIG, "reading config file %s\n", fname );
   2630 
   2631     fp_getline_init( c );
   2632 
   2633     c->tline = NULL;
   2634 
   2635     while ( fp_getline( fp, c ) ) {
   2636         /* skip comments and blank lines */
   2637         if ( c->line[0] == '#' || c->line[0] == '\0' ) {
   2638             continue;
   2639         }
   2640 
   2641         snprintf( c->log, sizeof(c->log), "%s: line %d",
   2642                 c->fname, c->lineno );
   2643 
   2644         c->argc = 0;
   2645         ch_free( c->tline );
   2646         if ( lload_config_fp_parse_line( c ) ) {
   2647             rc = 1;
   2648             goto done;
   2649         }
   2650 
   2651         if ( c->argc < 1 ) {
   2652             Debug( LDAP_DEBUG_ANY, "%s: bad config line\n", c->log );
   2653             rc = 1;
   2654             goto done;
   2655         }
   2656 
   2657         c->op = SLAP_CONFIG_ADD;
   2658 
   2659         ct = lload_config_find_keyword( cft, c );
   2660         if ( ct ) {
   2661             c->table = Cft_Global;
   2662             rc = lload_config_add_vals( ct, c );
   2663             if ( !rc ) continue;
   2664 
   2665             if ( rc & ARGS_USERLAND ) {
   2666                 /* XXX a usertype would be opaque here */
   2667                 Debug( LDAP_DEBUG_CONFIG, "%s: unknown user type <%s>\n",
   2668                         c->log, c->argv[0] );
   2669                 rc = 1;
   2670                 goto done;
   2671 
   2672             } else if ( rc == ARG_BAD_CONF ) {
   2673                 rc = 1;
   2674                 goto done;
   2675             }
   2676 
   2677         } else {
   2678             Debug( LDAP_DEBUG_ANY, "%s: unknown directive "
   2679                     "<%s> outside backend info and database definitions\n",
   2680                     c->log, *c->argv );
   2681             rc = 1;
   2682             goto done;
   2683         }
   2684     }
   2685 
   2686     rc = 0;
   2687 
   2688 done:
   2689     ch_free( c->tline );
   2690     fclose( fp );
   2691     ch_free( c->argv );
   2692     ch_free( c );
   2693     return rc;
   2694 }
   2695 
   2696 int
   2697 lload_read_config( const char *fname, const char *dir )
   2698 {
   2699     if ( !fname ) fname = LLOADD_DEFAULT_CONFIGFILE;
   2700 
   2701     cfn = ch_calloc( 1, sizeof(ConfigFile) );
   2702 
   2703     return lload_read_config_file( fname, 0, NULL, config_back_cf_table );
   2704 }
   2705 
   2706 #ifndef BALANCER_MODULE
   2707 int
   2708 config_push_cleanup( ConfigArgs *ca, ConfigDriver *cleanup )
   2709 {
   2710     /* Stub, cleanups only run in online config */
   2711     return 0;
   2712 }
   2713 #endif /* !BALANCER_MODULE */
   2714 
   2715 static slap_verbmasks tlskey[] = {
   2716     { BER_BVC("no"), LLOAD_CLEARTEXT },
   2717     { BER_BVC("yes"), LLOAD_STARTTLS_OPTIONAL },
   2718     { BER_BVC("critical"), LLOAD_STARTTLS },
   2719     { BER_BVNULL, 0 }
   2720 };
   2721 
   2722 static slap_verbmasks crlkeys[] = {
   2723     { BER_BVC("none"), LDAP_OPT_X_TLS_CRL_NONE },
   2724     { BER_BVC("peer"), LDAP_OPT_X_TLS_CRL_PEER },
   2725     { BER_BVC("all"), LDAP_OPT_X_TLS_CRL_ALL },
   2726     { BER_BVNULL, 0 }
   2727 };
   2728 
   2729 static slap_verbmasks vfykeys[] = {
   2730     { BER_BVC("never"), LDAP_OPT_X_TLS_NEVER },
   2731     { BER_BVC("allow"), LDAP_OPT_X_TLS_ALLOW },
   2732     { BER_BVC("try"), LDAP_OPT_X_TLS_TRY },
   2733     { BER_BVC("demand"), LDAP_OPT_X_TLS_DEMAND },
   2734     { BER_BVC("hard"), LDAP_OPT_X_TLS_HARD },
   2735     { BER_BVC("true"), LDAP_OPT_X_TLS_HARD },
   2736     { BER_BVNULL, 0 }
   2737 };
   2738 
   2739 static slap_verbmasks methkey[] = {
   2740     { BER_BVC("none"), LDAP_AUTH_NONE },
   2741     { BER_BVC("simple"), LDAP_AUTH_SIMPLE },
   2742 #ifdef HAVE_CYRUS_SASL
   2743     { BER_BVC("sasl"), LDAP_AUTH_SASL },
   2744 #endif
   2745     { BER_BVNULL, 0 }
   2746 };
   2747 
   2748 int
   2749 lload_keepalive_parse(
   2750         struct berval *val,
   2751         void *bc,
   2752         slap_cf_aux_table *tab0,
   2753         const char *tabmsg,
   2754         int unparse )
   2755 {
   2756     if ( unparse ) {
   2757         slap_keepalive *sk = (slap_keepalive *)bc;
   2758         int rc = snprintf( val->bv_val, val->bv_len, "%d:%d:%d",
   2759                 sk->sk_idle, sk->sk_probes, sk->sk_interval );
   2760         if ( rc < 0 ) {
   2761             return -1;
   2762         }
   2763 
   2764         if ( (unsigned)rc >= val->bv_len ) {
   2765             return -1;
   2766         }
   2767 
   2768         val->bv_len = rc;
   2769 
   2770     } else {
   2771         char *s = val->bv_val;
   2772         char *next;
   2773         slap_keepalive *sk = (slap_keepalive *)bc;
   2774         slap_keepalive sk2;
   2775 
   2776         if ( s[0] == ':' ) {
   2777             sk2.sk_idle = 0;
   2778             s++;
   2779 
   2780         } else {
   2781             sk2.sk_idle = strtol( s, &next, 10 );
   2782             if ( next == s || next[0] != ':' ) {
   2783                 return -1;
   2784             }
   2785 
   2786             if ( sk2.sk_idle < 0 ) {
   2787                 return -1;
   2788             }
   2789 
   2790             s = ++next;
   2791         }
   2792 
   2793         if ( s[0] == ':' ) {
   2794             sk2.sk_probes = 0;
   2795             s++;
   2796 
   2797         } else {
   2798             sk2.sk_probes = strtol( s, &next, 10 );
   2799             if ( next == s || next[0] != ':' ) {
   2800                 return -1;
   2801             }
   2802 
   2803             if ( sk2.sk_probes < 0 ) {
   2804                 return -1;
   2805             }
   2806 
   2807             s = ++next;
   2808         }
   2809 
   2810         if ( *s == '\0' ) {
   2811             sk2.sk_interval = 0;
   2812 
   2813         } else {
   2814             sk2.sk_interval = strtol( s, &next, 10 );
   2815             if ( next == s || next[0] != '\0' ) {
   2816                 return -1;
   2817             }
   2818 
   2819             if ( sk2.sk_interval < 0 ) {
   2820                 return -1;
   2821             }
   2822         }
   2823 
   2824         *sk = sk2;
   2825 
   2826         ber_memfree( val->bv_val );
   2827         BER_BVZERO( val );
   2828     }
   2829 
   2830     return 0;
   2831 }
   2832 
   2833 static slap_cf_aux_table backendkey[] = {
   2834     { BER_BVC("uri="), offsetof(LloadBackend, b_uri), 'b', 1, NULL },
   2835 
   2836     { BER_BVC("numconns="), offsetof(LloadBackend, b_numconns), 'i', 0, NULL },
   2837     { BER_BVC("bindconns="), offsetof(LloadBackend, b_numbindconns), 'i', 0, NULL },
   2838     { BER_BVC("retry="), offsetof(LloadBackend, b_retry_timeout), 'i', 0, NULL },
   2839 
   2840     { BER_BVC("max-pending-ops="), offsetof(LloadBackend, b_max_pending), 'i', 0, NULL },
   2841     { BER_BVC("conn-max-pending="), offsetof(LloadBackend, b_max_conn_pending), 'i', 0, NULL },
   2842     { BER_BVC("starttls="), offsetof(LloadBackend, b_tls_conf), 'i', 0, tlskey },
   2843 
   2844     { BER_BVC("weight="), offsetof(LloadBackend, b_weight), 'i', 0, NULL },
   2845 
   2846     { BER_BVNULL, 0, 0, 0, NULL }
   2847 };
   2848 
   2849 static slap_cf_aux_table bindkey[] = {
   2850     { BER_BVC("bindmethod="), offsetof(slap_bindconf, sb_method), 'i', 0, methkey },
   2851     { BER_BVC("timeout="), offsetof(slap_bindconf, sb_timeout_api), 'i', 0, NULL },
   2852     { BER_BVC("network-timeout="), offsetof(slap_bindconf, sb_timeout_net), 'i', 0, NULL },
   2853     { BER_BVC("binddn="), offsetof(slap_bindconf, sb_binddn), 'b', 1, NULL },
   2854     { BER_BVC("credentials="), offsetof(slap_bindconf, sb_cred), 'b', 1, NULL },
   2855     { BER_BVC("saslmech="), offsetof(slap_bindconf, sb_saslmech), 'b', 0, NULL },
   2856     { BER_BVC("secprops="), offsetof(slap_bindconf, sb_secprops), 's', 0, NULL },
   2857     { BER_BVC("realm="), offsetof(slap_bindconf, sb_realm), 'b', 0, NULL },
   2858     { BER_BVC("authcID="), offsetof(slap_bindconf, sb_authcId), 'b', 1, NULL },
   2859     { BER_BVC("authzID="), offsetof(slap_bindconf, sb_authzId), 'b', 1, NULL },
   2860     { BER_BVC("keepalive="), offsetof(slap_bindconf, sb_keepalive), 'x', 0, (slap_verbmasks *)lload_keepalive_parse },
   2861     { BER_BVC("tcp-user-timeout="), offsetof(slap_bindconf, sb_tcp_user_timeout), 'u', 0, NULL },
   2862 #ifdef HAVE_TLS
   2863     /* NOTE: replace "12" with the actual index
   2864      * of the first TLS-related line */
   2865 #define aux_TLS (bindkey+12) /* beginning of TLS keywords */
   2866 
   2867     { BER_BVC("tls_cert="), offsetof(slap_bindconf, sb_tls_cert), 's', 1, NULL },
   2868     { BER_BVC("tls_key="), offsetof(slap_bindconf, sb_tls_key), 's', 1, NULL },
   2869     { BER_BVC("tls_cacert="), offsetof(slap_bindconf, sb_tls_cacert), 's', 1, NULL },
   2870     { BER_BVC("tls_cacertdir="), offsetof(slap_bindconf, sb_tls_cacertdir), 's', 1, NULL },
   2871     { BER_BVC("tls_reqcert="), offsetof(slap_bindconf, sb_tls_reqcert), 's', 0, NULL },
   2872     { BER_BVC("tls_reqsan="), offsetof(slap_bindconf, sb_tls_reqsan), 's', 0, NULL },
   2873     { BER_BVC("tls_cipher_suite="), offsetof(slap_bindconf, sb_tls_cipher_suite), 's', 0, NULL },
   2874     { BER_BVC("tls_protocol_min="), offsetof(slap_bindconf, sb_tls_protocol_min), 's', 0, NULL },
   2875     { BER_BVC("tls_ecname="), offsetof(slap_bindconf, sb_tls_ecname), 's', 0, NULL },
   2876 #ifdef HAVE_OPENSSL
   2877     { BER_BVC("tls_crlcheck="), offsetof(slap_bindconf, sb_tls_crlcheck), 's', 0, NULL },
   2878 #endif
   2879 #endif
   2880     { BER_BVNULL, 0, 0, 0, NULL }
   2881 };
   2882 
   2883 /*
   2884  * 's': char *
   2885  * 'b': struct berval
   2886  * 'i': int; if !NULL, compute using ((slap_verbmasks *)aux)
   2887  * 'u': unsigned
   2888  * 'I': long
   2889  * 'U': unsigned long
   2890  */
   2891 
   2892 int
   2893 lload_cf_aux_table_parse(
   2894         const char *word,
   2895         void *dst,
   2896         slap_cf_aux_table *tab0,
   2897         LDAP_CONST char *tabmsg )
   2898 {
   2899     int rc = SLAP_CONF_UNKNOWN;
   2900     slap_cf_aux_table *tab;
   2901 
   2902     for ( tab = tab0; !BER_BVISNULL( &tab->key ); tab++ ) {
   2903         if ( !strncasecmp( word, tab->key.bv_val, tab->key.bv_len ) ) {
   2904             char **cptr;
   2905             int *iptr, j;
   2906             unsigned *uptr;
   2907             long *lptr;
   2908             unsigned long *ulptr;
   2909             struct berval *bptr;
   2910             const char *val = word + tab->key.bv_len;
   2911 
   2912             switch ( tab->type ) {
   2913                 case 's':
   2914                     cptr = (char **)( (char *)dst + tab->off );
   2915                     *cptr = ch_strdup( val );
   2916                     rc = 0;
   2917                     break;
   2918 
   2919                 case 'b':
   2920                     bptr = (struct berval *)( (char *)dst + tab->off );
   2921                     assert( tab->aux == NULL );
   2922                     ber_str2bv( val, 0, 1, bptr );
   2923                     rc = 0;
   2924                     break;
   2925 
   2926                 case 'i':
   2927                     iptr = (int *)( (char *)dst + tab->off );
   2928 
   2929                     if ( tab->aux != NULL ) {
   2930                         slap_verbmasks *aux = (slap_verbmasks *)tab->aux;
   2931 
   2932                         assert( aux != NULL );
   2933 
   2934                         rc = 1;
   2935                         for ( j = 0; !BER_BVISNULL( &aux[j].word ); j++ ) {
   2936                             if ( !strcasecmp( val, aux[j].word.bv_val ) ) {
   2937                                 *iptr = aux[j].mask;
   2938                                 rc = 0;
   2939                                 break;
   2940                             }
   2941                         }
   2942 
   2943                     } else {
   2944                         rc = lutil_atoix( iptr, val, 0 );
   2945                     }
   2946                     break;
   2947 
   2948                 case 'u':
   2949                     uptr = (unsigned *)( (char *)dst + tab->off );
   2950 
   2951                     rc = lutil_atoux( uptr, val, 0 );
   2952                     break;
   2953 
   2954                 case 'I':
   2955                     lptr = (long *)( (char *)dst + tab->off );
   2956 
   2957                     rc = lutil_atolx( lptr, val, 0 );
   2958                     break;
   2959 
   2960                 case 'U':
   2961                     ulptr = (unsigned long *)( (char *)dst + tab->off );
   2962 
   2963                     rc = lutil_atoulx( ulptr, val, 0 );
   2964                     break;
   2965 
   2966                 case 'x':
   2967                     if ( tab->aux != NULL ) {
   2968                         struct berval value;
   2969                         lload_cf_aux_table_parse_x *func =
   2970                                 (lload_cf_aux_table_parse_x *)tab->aux;
   2971 
   2972                         ber_str2bv( val, 0, 1, &value );
   2973 
   2974                         rc = func( &value, (void *)( (char *)dst + tab->off ),
   2975                                 tab, tabmsg, 0 );
   2976 
   2977                     } else {
   2978                         rc = 1;
   2979                     }
   2980                     break;
   2981             }
   2982 
   2983             if ( rc ) {
   2984                 Debug( LDAP_DEBUG_ANY, "invalid %s value %s\n", tabmsg, word );
   2985             }
   2986 
   2987             return rc;
   2988         }
   2989     }
   2990 
   2991     return rc;
   2992 }
   2993 
   2994 int
   2995 lload_cf_aux_table_unparse(
   2996         void *src,
   2997         struct berval *bv,
   2998         slap_cf_aux_table *tab0 )
   2999 {
   3000     char buf[AC_LINE_MAX], *ptr;
   3001     slap_cf_aux_table *tab;
   3002     struct berval tmp;
   3003 
   3004     ptr = buf;
   3005     for ( tab = tab0; !BER_BVISNULL( &tab->key ); tab++ ) {
   3006         char **cptr;
   3007         int *iptr, i;
   3008         unsigned *uptr;
   3009         long *lptr;
   3010         unsigned long *ulptr;
   3011         struct berval *bptr;
   3012 
   3013         cptr = (char **)( (char *)src + tab->off );
   3014 
   3015         switch ( tab->type ) {
   3016             case 'b':
   3017                 bptr = (struct berval *)( (char *)src + tab->off );
   3018                 cptr = &bptr->bv_val;
   3019 
   3020             case 's':
   3021                 if ( *cptr ) {
   3022                     *ptr++ = ' ';
   3023                     ptr = lutil_strcopy( ptr, tab->key.bv_val );
   3024                     if ( tab->quote ) *ptr++ = '"';
   3025                     ptr = lutil_strcopy( ptr, *cptr );
   3026                     if ( tab->quote ) *ptr++ = '"';
   3027                 }
   3028                 break;
   3029 
   3030             case 'i':
   3031                 iptr = (int *)( (char *)src + tab->off );
   3032 
   3033                 if ( tab->aux != NULL ) {
   3034                     slap_verbmasks *aux = (slap_verbmasks *)tab->aux;
   3035 
   3036                     for ( i = 0; !BER_BVISNULL( &aux[i].word ); i++ ) {
   3037                         if ( *iptr == aux[i].mask ) {
   3038                             *ptr++ = ' ';
   3039                             ptr = lutil_strcopy( ptr, tab->key.bv_val );
   3040                             ptr = lutil_strcopy( ptr, aux[i].word.bv_val );
   3041                             break;
   3042                         }
   3043                     }
   3044 
   3045                 } else {
   3046                     *ptr++ = ' ';
   3047                     ptr = lutil_strcopy( ptr, tab->key.bv_val );
   3048                     ptr += snprintf( ptr, sizeof(buf) - ( ptr - buf ), "%d",
   3049                             *iptr );
   3050                 }
   3051                 break;
   3052 
   3053             case 'u':
   3054                 uptr = (unsigned *)( (char *)src + tab->off );
   3055                 *ptr++ = ' ';
   3056                 ptr = lutil_strcopy( ptr, tab->key.bv_val );
   3057                 ptr += snprintf( ptr, sizeof(buf) - ( ptr - buf ), "%u",
   3058                         *uptr );
   3059                 break;
   3060 
   3061             case 'I':
   3062                 lptr = (long *)( (char *)src + tab->off );
   3063                 *ptr++ = ' ';
   3064                 ptr = lutil_strcopy( ptr, tab->key.bv_val );
   3065                 ptr += snprintf( ptr, sizeof(buf) - ( ptr - buf ), "%ld",
   3066                         *lptr );
   3067                 break;
   3068 
   3069             case 'U':
   3070                 ulptr = (unsigned long *)( (char *)src + tab->off );
   3071                 *ptr++ = ' ';
   3072                 ptr = lutil_strcopy( ptr, tab->key.bv_val );
   3073                 ptr += snprintf( ptr, sizeof(buf) - ( ptr - buf ), "%lu",
   3074                         *ulptr );
   3075                 break;
   3076 
   3077             case 'x': {
   3078                 char *saveptr = ptr;
   3079                 *ptr++ = ' ';
   3080                 ptr = lutil_strcopy( ptr, tab->key.bv_val );
   3081                 if ( tab->quote ) *ptr++ = '"';
   3082                 if ( tab->aux != NULL ) {
   3083                     struct berval value;
   3084                     lload_cf_aux_table_parse_x *func =
   3085                             (lload_cf_aux_table_parse_x *)tab->aux;
   3086                     int rc;
   3087 
   3088                     value.bv_val = ptr;
   3089                     value.bv_len = buf + sizeof(buf) - ptr;
   3090 
   3091                     rc = func( &value, (void *)( (char *)src + tab->off ), tab,
   3092                             "(unparse)", 1 );
   3093                     if ( rc == 0 ) {
   3094                         if ( value.bv_len ) {
   3095                             ptr += value.bv_len;
   3096                         } else {
   3097                             ptr = saveptr;
   3098                             break;
   3099                         }
   3100                     }
   3101                 }
   3102                 if ( tab->quote ) *ptr++ = '"';
   3103             } break;
   3104 
   3105             default:
   3106                 assert(0);
   3107         }
   3108     }
   3109     tmp.bv_val = buf;
   3110     tmp.bv_len = ptr - buf;
   3111     ber_dupbv( bv, &tmp );
   3112     return 0;
   3113 }
   3114 
   3115 int
   3116 lload_tls_get_config( LDAP *ld, int opt, char **val )
   3117 {
   3118 #ifdef HAVE_TLS
   3119     slap_verbmasks *keys;
   3120     int i, ival;
   3121 
   3122     *val = NULL;
   3123     switch ( opt ) {
   3124         case LDAP_OPT_X_TLS_CRLCHECK:
   3125             keys = crlkeys;
   3126             break;
   3127         case LDAP_OPT_X_TLS_REQUIRE_CERT:
   3128             keys = vfykeys;
   3129             break;
   3130         case LDAP_OPT_X_TLS_PROTOCOL_MIN: {
   3131             char buf[8];
   3132             ldap_pvt_tls_get_option( ld, opt, &ival );
   3133             snprintf( buf, sizeof(buf), "%d.%d",
   3134                     ( ival >> 8 ) & 0xff, ival & 0xff );
   3135             *val = ch_strdup( buf );
   3136             return 0;
   3137         }
   3138         default:
   3139             return -1;
   3140     }
   3141     ldap_pvt_tls_get_option( ld, opt, &ival );
   3142     for ( i = 0; !BER_BVISNULL( &keys[i].word ); i++ ) {
   3143         if ( keys[i].mask == ival ) {
   3144             *val = ch_strdup( keys[i].word.bv_val );
   3145             return 0;
   3146         }
   3147     }
   3148 #endif
   3149     return -1;
   3150 }
   3151 
   3152 #ifdef HAVE_TLS
   3153 static struct {
   3154     const char *key;
   3155     size_t offset;
   3156     int opt;
   3157 } bindtlsopts[] = {
   3158     { "tls_cert", offsetof(slap_bindconf, sb_tls_cert), LDAP_OPT_X_TLS_CERTFILE },
   3159     { "tls_key", offsetof(slap_bindconf, sb_tls_key), LDAP_OPT_X_TLS_KEYFILE },
   3160     { "tls_cacert", offsetof(slap_bindconf, sb_tls_cacert), LDAP_OPT_X_TLS_CACERTFILE },
   3161     { "tls_cacertdir", offsetof(slap_bindconf, sb_tls_cacertdir), LDAP_OPT_X_TLS_CACERTDIR },
   3162     { "tls_cipher_suite", offsetof(slap_bindconf, sb_tls_cipher_suite), LDAP_OPT_X_TLS_CIPHER_SUITE },
   3163     { "tls_ecname", offsetof(slap_bindconf, sb_tls_ecname), LDAP_OPT_X_TLS_ECNAME },
   3164     { NULL, 0 }
   3165 };
   3166 
   3167 int
   3168 lload_bindconf_tls_set( slap_bindconf *bc, LDAP *ld )
   3169 {
   3170     int i, rc, newctx = 0, res = 0;
   3171     char *ptr = (char *)bc, **word;
   3172 
   3173     if ( bc->sb_tls_do_init ) {
   3174         for ( i = 0; bindtlsopts[i].opt; i++ ) {
   3175             word = (char **)( ptr + bindtlsopts[i].offset );
   3176             if ( *word ) {
   3177                 rc = ldap_set_option( ld, bindtlsopts[i].opt, *word );
   3178                 if ( rc ) {
   3179                     Debug( LDAP_DEBUG_ANY, "lload_bindconf_tls_set: "
   3180                             "failed to set %s to %s\n",
   3181                             bindtlsopts[i].key, *word );
   3182                     res = -1;
   3183                 } else
   3184                     newctx = 1;
   3185             }
   3186         }
   3187         if ( bc->sb_tls_reqcert ) {
   3188             rc = ldap_pvt_tls_config(
   3189                     ld, LDAP_OPT_X_TLS_REQUIRE_CERT, bc->sb_tls_reqcert );
   3190             if ( rc ) {
   3191                 Debug( LDAP_DEBUG_ANY, "lload_bindconf_tls_set: "
   3192                         "failed to set tls_reqcert to %s\n",
   3193                         bc->sb_tls_reqcert );
   3194                 res = -1;
   3195             } else {
   3196                 newctx = 1;
   3197                 /* retrieve the parsed setting for later use */
   3198                 ldap_get_option( ld, LDAP_OPT_X_TLS_REQUIRE_CERT,
   3199                         &bc->sb_tls_int_reqcert );
   3200             }
   3201         }
   3202         if ( bc->sb_tls_reqsan ) {
   3203             rc = ldap_pvt_tls_config(
   3204                     ld, LDAP_OPT_X_TLS_REQUIRE_SAN, bc->sb_tls_reqsan );
   3205             if ( rc ) {
   3206                 Debug( LDAP_DEBUG_ANY, "lload_bindconf_tls_set: "
   3207                         "failed to set tls_reqsan to %s\n",
   3208                         bc->sb_tls_reqsan );
   3209                 res = -1;
   3210             } else {
   3211                 newctx = 1;
   3212                 /* retrieve the parsed setting for later use */
   3213                 ldap_get_option( ld, LDAP_OPT_X_TLS_REQUIRE_SAN,
   3214                         &bc->sb_tls_int_reqsan );
   3215             }
   3216         }
   3217         if ( bc->sb_tls_protocol_min ) {
   3218             rc = ldap_pvt_tls_config(
   3219                     ld, LDAP_OPT_X_TLS_PROTOCOL_MIN, bc->sb_tls_protocol_min );
   3220             if ( rc ) {
   3221                 Debug( LDAP_DEBUG_ANY, "lload_bindconf_tls_set: "
   3222                         "failed to set tls_protocol_min to %s\n",
   3223                         bc->sb_tls_protocol_min );
   3224                 res = -1;
   3225             } else
   3226                 newctx = 1;
   3227         }
   3228 #ifdef HAVE_OPENSSL
   3229         if ( bc->sb_tls_crlcheck ) {
   3230             rc = ldap_pvt_tls_config(
   3231                     ld, LDAP_OPT_X_TLS_CRLCHECK, bc->sb_tls_crlcheck );
   3232             if ( rc ) {
   3233                 Debug( LDAP_DEBUG_ANY, "lload_bindconf_tls_set: "
   3234                         "failed to set tls_crlcheck to %s\n",
   3235                         bc->sb_tls_crlcheck );
   3236                 res = -1;
   3237             } else
   3238                 newctx = 1;
   3239         }
   3240 #endif
   3241         if ( !res ) bc->sb_tls_do_init = 0;
   3242     }
   3243 
   3244     if ( newctx ) {
   3245         int opt = 0;
   3246 
   3247         if ( bc->sb_tls_ctx ) {
   3248             ldap_pvt_tls_ctx_free( bc->sb_tls_ctx );
   3249             bc->sb_tls_ctx = NULL;
   3250         }
   3251         rc = ldap_set_option( ld, LDAP_OPT_X_TLS_NEWCTX, &opt );
   3252         if ( rc )
   3253             res = rc;
   3254         else
   3255             ldap_get_option( ld, LDAP_OPT_X_TLS_CTX, &bc->sb_tls_ctx );
   3256     } else if ( bc->sb_tls_ctx ) {
   3257         rc = ldap_set_option( ld, LDAP_OPT_X_TLS_CTX, bc->sb_tls_ctx );
   3258         if ( rc == LDAP_SUCCESS ) {
   3259             /* these options aren't actually inside the ctx, so have to be set again */
   3260             ldap_set_option(
   3261                     ld, LDAP_OPT_X_TLS_REQUIRE_CERT, &bc->sb_tls_int_reqcert );
   3262             ldap_set_option(
   3263                     ld, LDAP_OPT_X_TLS_REQUIRE_SAN, &bc->sb_tls_int_reqsan );
   3264         } else
   3265             res = rc;
   3266     }
   3267 
   3268     return res;
   3269 }
   3270 #endif
   3271 
   3272 int
   3273 lload_bindconf_tls_parse( const char *word, slap_bindconf *bc )
   3274 {
   3275 #ifdef HAVE_TLS
   3276     if ( lload_cf_aux_table_parse( word, bc, aux_TLS, "tls config" ) == 0 ) {
   3277         bc->sb_tls_do_init = 1;
   3278         return 0;
   3279     }
   3280 #endif
   3281     return -1;
   3282 }
   3283 
   3284 int
   3285 lload_backend_parse( const char *word, LloadBackend *b )
   3286 {
   3287     return lload_cf_aux_table_parse( word, b, backendkey, "backend config" );
   3288 }
   3289 
   3290 int
   3291 lload_bindconf_parse( const char *word, slap_bindconf *bc )
   3292 {
   3293 #ifdef HAVE_TLS
   3294     /* Detect TLS config changes explicitly */
   3295     if ( lload_bindconf_tls_parse( word, bc ) == 0 ) {
   3296         return 0;
   3297     }
   3298 #endif
   3299     return lload_cf_aux_table_parse( word, bc, bindkey, "bind config" );
   3300 }
   3301 
   3302 int
   3303 lload_bindconf_unparse( slap_bindconf *bc, struct berval *bv )
   3304 {
   3305     return lload_cf_aux_table_unparse( bc, bv, bindkey );
   3306 }
   3307 
   3308 void
   3309 lload_bindconf_free( slap_bindconf *bc )
   3310 {
   3311     if ( !BER_BVISNULL( &bc->sb_uri ) ) {
   3312         ch_free( bc->sb_uri.bv_val );
   3313         BER_BVZERO( &bc->sb_uri );
   3314     }
   3315     if ( !BER_BVISNULL( &bc->sb_binddn ) ) {
   3316         ch_free( bc->sb_binddn.bv_val );
   3317         BER_BVZERO( &bc->sb_binddn );
   3318     }
   3319     if ( !BER_BVISNULL( &bc->sb_cred ) ) {
   3320         ch_free( bc->sb_cred.bv_val );
   3321         BER_BVZERO( &bc->sb_cred );
   3322     }
   3323     if ( !BER_BVISNULL( &bc->sb_saslmech ) ) {
   3324         ch_free( bc->sb_saslmech.bv_val );
   3325         BER_BVZERO( &bc->sb_saslmech );
   3326     }
   3327     if ( bc->sb_secprops ) {
   3328         ch_free( bc->sb_secprops );
   3329         bc->sb_secprops = NULL;
   3330     }
   3331     if ( !BER_BVISNULL( &bc->sb_realm ) ) {
   3332         ch_free( bc->sb_realm.bv_val );
   3333         BER_BVZERO( &bc->sb_realm );
   3334     }
   3335     if ( !BER_BVISNULL( &bc->sb_authcId ) ) {
   3336         ch_free( bc->sb_authcId.bv_val );
   3337         BER_BVZERO( &bc->sb_authcId );
   3338     }
   3339     if ( !BER_BVISNULL( &bc->sb_authzId ) ) {
   3340         ch_free( bc->sb_authzId.bv_val );
   3341         BER_BVZERO( &bc->sb_authzId );
   3342     }
   3343 #ifdef HAVE_TLS
   3344     if ( bc->sb_tls_cert ) {
   3345         ch_free( bc->sb_tls_cert );
   3346         bc->sb_tls_cert = NULL;
   3347     }
   3348     if ( bc->sb_tls_key ) {
   3349         ch_free( bc->sb_tls_key );
   3350         bc->sb_tls_key = NULL;
   3351     }
   3352     if ( bc->sb_tls_cacert ) {
   3353         ch_free( bc->sb_tls_cacert );
   3354         bc->sb_tls_cacert = NULL;
   3355     }
   3356     if ( bc->sb_tls_cacertdir ) {
   3357         ch_free( bc->sb_tls_cacertdir );
   3358         bc->sb_tls_cacertdir = NULL;
   3359     }
   3360     if ( bc->sb_tls_reqcert ) {
   3361         ch_free( bc->sb_tls_reqcert );
   3362         bc->sb_tls_reqcert = NULL;
   3363     }
   3364     if ( bc->sb_tls_cipher_suite ) {
   3365         ch_free( bc->sb_tls_cipher_suite );
   3366         bc->sb_tls_cipher_suite = NULL;
   3367     }
   3368     if ( bc->sb_tls_protocol_min ) {
   3369         ch_free( bc->sb_tls_protocol_min );
   3370         bc->sb_tls_protocol_min = NULL;
   3371     }
   3372 #ifdef HAVE_OPENSSL_CRL
   3373     if ( bc->sb_tls_crlcheck ) {
   3374         ch_free( bc->sb_tls_crlcheck );
   3375         bc->sb_tls_crlcheck = NULL;
   3376     }
   3377 #endif
   3378     if ( bc->sb_tls_ctx ) {
   3379         ldap_pvt_tls_ctx_free( bc->sb_tls_ctx );
   3380         bc->sb_tls_ctx = NULL;
   3381     }
   3382 #endif
   3383 }
   3384 
   3385 void
   3386 lload_bindconf_tls_defaults( slap_bindconf *bc )
   3387 {
   3388 #ifdef HAVE_TLS
   3389     if ( bc->sb_tls_do_init ) {
   3390         if ( !bc->sb_tls_cacert )
   3391             ldap_pvt_tls_get_option( lload_tls_ld, LDAP_OPT_X_TLS_CACERTFILE,
   3392                     &bc->sb_tls_cacert );
   3393         if ( !bc->sb_tls_cacertdir )
   3394             ldap_pvt_tls_get_option( lload_tls_ld, LDAP_OPT_X_TLS_CACERTDIR,
   3395                     &bc->sb_tls_cacertdir );
   3396         if ( !bc->sb_tls_cert )
   3397             ldap_pvt_tls_get_option(
   3398                     lload_tls_ld, LDAP_OPT_X_TLS_CERTFILE, &bc->sb_tls_cert );
   3399         if ( !bc->sb_tls_key )
   3400             ldap_pvt_tls_get_option(
   3401                     lload_tls_ld, LDAP_OPT_X_TLS_KEYFILE, &bc->sb_tls_key );
   3402         if ( !bc->sb_tls_cipher_suite )
   3403             ldap_pvt_tls_get_option( lload_tls_ld, LDAP_OPT_X_TLS_CIPHER_SUITE,
   3404                     &bc->sb_tls_cipher_suite );
   3405         if ( !bc->sb_tls_reqcert ) bc->sb_tls_reqcert = ch_strdup( "demand" );
   3406 #ifdef HAVE_OPENSSL_CRL
   3407         if ( !bc->sb_tls_crlcheck )
   3408             lload_tls_get_config( lload_tls_ld, LDAP_OPT_X_TLS_CRLCHECK,
   3409                     &bc->sb_tls_crlcheck );
   3410 #endif
   3411     }
   3412 #endif
   3413 }
   3414 
   3415 /* -------------------------------------- */
   3416 
   3417 static char *
   3418 strtok_quote( char *line, char *sep, char **quote_ptr, int *iqp )
   3419 {
   3420     int inquote;
   3421     char *tmp;
   3422     static char *next;
   3423 
   3424     *quote_ptr = NULL;
   3425     if ( line != NULL ) {
   3426         next = line;
   3427     }
   3428     while ( *next && strchr( sep, *next ) ) {
   3429         next++;
   3430     }
   3431 
   3432     if ( *next == '\0' ) {
   3433         next = NULL;
   3434         return NULL;
   3435     }
   3436     tmp = next;
   3437 
   3438     for ( inquote = 0; *next; ) {
   3439         switch ( *next ) {
   3440             case '"':
   3441                 if ( inquote ) {
   3442                     inquote = 0;
   3443                 } else {
   3444                     inquote = 1;
   3445                 }
   3446                 AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
   3447                 break;
   3448 
   3449             case '\\':
   3450                 if ( next[1] )
   3451                     AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
   3452                 next++; /* dont parse the escaped character */
   3453                 break;
   3454 
   3455             default:
   3456                 if ( !inquote ) {
   3457                     if ( strchr( sep, *next ) != NULL ) {
   3458                         *quote_ptr = next;
   3459                         *next++ = '\0';
   3460                         return tmp;
   3461                     }
   3462                 }
   3463                 next++;
   3464                 break;
   3465         }
   3466     }
   3467     *iqp = inquote;
   3468 
   3469     return tmp;
   3470 }
   3471 
   3472 static char buf[AC_LINE_MAX];
   3473 static char *line;
   3474 static size_t lmax, lcur;
   3475 
   3476 #define CATLINE( buf ) \
   3477     do { \
   3478         size_t len = strlen( buf ); \
   3479         while ( lcur + len + 1 > lmax ) { \
   3480             lmax += AC_LINE_MAX; \
   3481             line = (char *)ch_realloc( line, lmax ); \
   3482         } \
   3483         strcpy( line + lcur, buf ); \
   3484         lcur += len; \
   3485     } while (0)
   3486 
   3487 static void
   3488 fp_getline_init( ConfigArgs *c )
   3489 {
   3490     c->lineno = -1;
   3491     buf[0] = '\0';
   3492 }
   3493 
   3494 static int
   3495 fp_getline( FILE *fp, ConfigArgs *c )
   3496 {
   3497     char *p;
   3498 
   3499     lcur = 0;
   3500     CATLINE( buf );
   3501     c->lineno++;
   3502 
   3503     /* avoid stack of bufs */
   3504     if ( strncasecmp( line, "include", STRLENOF("include") ) == 0 ) {
   3505         buf[0] = '\0';
   3506         c->line = line;
   3507         return 1;
   3508     }
   3509 
   3510     while ( fgets( buf, sizeof(buf), fp ) ) {
   3511         p = strchr( buf, '\n' );
   3512         if ( p ) {
   3513             if ( p > buf && p[-1] == '\r' ) {
   3514                 --p;
   3515             }
   3516             *p = '\0';
   3517         }
   3518         /* XXX ugly */
   3519         c->line = line;
   3520         if ( line[0] && ( p = line + strlen( line ) - 1 )[0] == '\\' &&
   3521                 p[-1] != '\\' ) {
   3522             p[0] = '\0';
   3523             lcur--;
   3524 
   3525         } else {
   3526             if ( !isspace( (unsigned char)buf[0] ) ) {
   3527                 return 1;
   3528             }
   3529             buf[0] = ' ';
   3530         }
   3531         CATLINE( buf );
   3532         c->lineno++;
   3533     }
   3534 
   3535     buf[0] = '\0';
   3536     c->line = line;
   3537     return ( line[0] ? 1 : 0 );
   3538 }
   3539 
   3540 int
   3541 lload_config_fp_parse_line( ConfigArgs *c )
   3542 {
   3543     char *token;
   3544     static char *const hide[] = { "bindconf", NULL };
   3545     static char *const raw[] = { NULL };
   3546     char *quote_ptr;
   3547     int i = (int)( sizeof(hide) / sizeof(hide[0]) ) - 1;
   3548     int inquote = 0;
   3549 
   3550     c->tline = ch_strdup( c->line );
   3551     c->linelen = strlen( c->line );
   3552     token = strtok_quote( c->tline, " \t", &quote_ptr, &inquote );
   3553 
   3554     if ( token )
   3555         for ( i = 0; hide[i]; i++ )
   3556             if ( !strcasecmp( token, hide[i] ) ) break;
   3557     if ( quote_ptr ) *quote_ptr = ' ';
   3558     Debug( LDAP_DEBUG_CONFIG, "%s (%s%s)\n",
   3559             c->log, hide[i] ? hide[i] : c->line, hide[i] ? " ***" : "" );
   3560     if ( quote_ptr ) *quote_ptr = '\0';
   3561 
   3562     for ( ;; token = strtok_quote( NULL, " \t", &quote_ptr, &inquote ) ) {
   3563         if ( c->argc >= c->argv_size ) {
   3564             char **tmp;
   3565             tmp = ch_realloc( c->argv,
   3566                     ( c->argv_size + ARGS_STEP ) * sizeof(*c->argv) );
   3567             if ( !tmp ) {
   3568                 Debug( LDAP_DEBUG_ANY, "%s: out of memory\n", c->log );
   3569                 return -1;
   3570             }
   3571             c->argv = tmp;
   3572             c->argv_size += ARGS_STEP;
   3573         }
   3574         if ( token == NULL ) break;
   3575         c->argv[c->argc++] = token;
   3576     }
   3577     c->argv[c->argc] = NULL;
   3578     if ( inquote ) {
   3579         /* these directives parse c->line independently of argv tokenizing */
   3580         for ( i = 0; raw[i]; i++ )
   3581             if ( !strcasecmp( c->argv[0], raw[i] ) ) return 0;
   3582 
   3583         Debug( LDAP_DEBUG_ANY, "%s: unterminated quoted string \"%s\"\n",
   3584                 c->log, c->argv[c->argc - 1] );
   3585         return -1;
   3586     }
   3587     return 0;
   3588 }
   3589 
   3590 void
   3591 lload_config_destroy( void )
   3592 {
   3593     free( line );
   3594     if ( slapd_args_file ) free( slapd_args_file );
   3595     if ( slapd_pid_file ) free( slapd_pid_file );
   3596     slap_loglevel_destroy();
   3597 }
   3598 
   3599 /* See if the given URL (in plain and parsed form) matches
   3600  * any of the server's listener addresses. Return matching
   3601  * LloadListener or NULL for no match.
   3602  */
   3603 LloadListener *
   3604 lload_config_check_my_url( const char *url, LDAPURLDesc *lud )
   3605 {
   3606     LloadListener **l = lloadd_get_listeners();
   3607     int i, isMe;
   3608 
   3609     /* Try a straight compare with LloadListener strings */
   3610     for ( i = 0; l && l[i]; i++ ) {
   3611         if ( !strcasecmp( url, l[i]->sl_url.bv_val ) ) {
   3612             return l[i];
   3613         }
   3614     }
   3615 
   3616     isMe = 0;
   3617     /* If hostname is empty, or is localhost, or matches
   3618      * our hostname, this url refers to this host.
   3619      * Compare it against listeners and ports.
   3620      */
   3621     if ( !lud->lud_host || !lud->lud_host[0] ||
   3622             !strncasecmp(
   3623                     "localhost", lud->lud_host, STRLENOF("localhost") ) ||
   3624             !strcasecmp( global_host, lud->lud_host ) ) {
   3625         for ( i = 0; l && l[i]; i++ ) {
   3626             LDAPURLDesc *lu2;
   3627             ldap_url_parse_ext(
   3628                     l[i]->sl_url.bv_val, &lu2, LDAP_PVT_URL_PARSE_DEF_PORT );
   3629             do {
   3630                 if ( strcasecmp( lud->lud_scheme, lu2->lud_scheme ) ) break;
   3631                 if ( lud->lud_port != lu2->lud_port ) break;
   3632                 /* Listener on ANY address */
   3633                 if ( !lu2->lud_host || !lu2->lud_host[0] ) {
   3634                     isMe = 1;
   3635                     break;
   3636                 }
   3637                 /* URL on ANY address */
   3638                 if ( !lud->lud_host || !lud->lud_host[0] ) {
   3639                     isMe = 1;
   3640                     break;
   3641                 }
   3642                 /* Listener has specific host, must
   3643                  * match it
   3644                  */
   3645                 if ( !strcasecmp( lud->lud_host, lu2->lud_host ) ) {
   3646                     isMe = 1;
   3647                     break;
   3648                 }
   3649             } while (0);
   3650             ldap_free_urldesc( lu2 );
   3651             if ( isMe ) {
   3652                 return l[i];
   3653             }
   3654         }
   3655     }
   3656     return NULL;
   3657 }
   3658 
   3659 #ifdef BALANCER_MODULE
   3660 static int
   3661 backend_cf_gen( ConfigArgs *c )
   3662 {
   3663     LloadBackend *b = c->ca_private;
   3664     enum lcf_backend flag = 0;
   3665     int rc = LDAP_SUCCESS;
   3666 
   3667     assert( b != NULL );
   3668 
   3669     if ( c->op == SLAP_CONFIG_EMIT ) {
   3670         switch ( c->type ) {
   3671             case CFG_URI:
   3672                 c->value_bv = b->b_uri;
   3673                 break;
   3674             case CFG_NUMCONNS:
   3675                 c->value_uint = b->b_numconns;
   3676                 break;
   3677             case CFG_BINDCONNS:
   3678                 c->value_uint = b->b_numbindconns;
   3679                 break;
   3680             case CFG_RETRY:
   3681                 c->value_uint = b->b_retry_timeout;
   3682                 break;
   3683             case CFG_MAX_PENDING_CONNS:
   3684                 c->value_uint = b->b_max_conn_pending;
   3685                 break;
   3686             case CFG_MAX_PENDING_OPS:
   3687                 c->value_uint = b->b_max_pending;
   3688                 break;
   3689             case CFG_STARTTLS:
   3690                 enum_to_verb( tlskey, b->b_tls_conf, &c->value_bv );
   3691                 break;
   3692             case CFG_WEIGHT:
   3693                 c->value_uint = b->b_weight;
   3694                 break;
   3695             default:
   3696                 rc = 1;
   3697                 break;
   3698         }
   3699 
   3700         return rc;
   3701     } else if ( c->op == LDAP_MOD_DELETE ) {
   3702         /* We only need to worry about deletions to multi-value or MAY
   3703          * attributes */
   3704         switch ( c->type ) {
   3705             case CFG_STARTTLS:
   3706                 b->b_tls_conf = LLOAD_CLEARTEXT;
   3707                 break;
   3708             default:
   3709                 break;
   3710         }
   3711         return rc;
   3712     }
   3713 
   3714     switch ( c->type ) {
   3715         case CFG_URI:
   3716             rc = backend_config_url( b, &c->value_bv );
   3717             if ( rc ) {
   3718                 backend_config_url( b, &b->b_uri );
   3719                 goto fail;
   3720             }
   3721             if ( !BER_BVISNULL( &b->b_uri ) ) {
   3722                 ch_free( b->b_uri.bv_val );
   3723             }
   3724             b->b_uri = c->value_bv;
   3725             flag = LLOAD_BACKEND_MOD_OTHER;
   3726             break;
   3727         case CFG_NUMCONNS:
   3728             if ( !c->value_uint ) {
   3729                 snprintf( c->cr_msg, sizeof(c->cr_msg),
   3730                         "invalid connection pool configuration" );
   3731                 goto fail;
   3732             }
   3733             b->b_numconns = c->value_uint;
   3734             flag = LLOAD_BACKEND_MOD_CONNS;
   3735             break;
   3736         case CFG_BINDCONNS:
   3737             if ( !c->value_uint ) {
   3738                 snprintf( c->cr_msg, sizeof(c->cr_msg),
   3739                         "invalid connection pool configuration" );
   3740                 goto fail;
   3741             }
   3742             b->b_numbindconns = c->value_uint;
   3743             flag = LLOAD_BACKEND_MOD_CONNS;
   3744             break;
   3745         case CFG_RETRY:
   3746             b->b_retry_timeout = c->value_uint;
   3747             break;
   3748         case CFG_MAX_PENDING_CONNS:
   3749             b->b_max_conn_pending = c->value_uint;
   3750             break;
   3751         case CFG_MAX_PENDING_OPS:
   3752             b->b_max_pending = c->value_uint;
   3753             break;
   3754         case CFG_STARTTLS: {
   3755             int i = bverb_to_mask( &c->value_bv, tlskey );
   3756             if ( BER_BVISNULL( &tlskey[i].word ) ) {
   3757                 snprintf( c->cr_msg, sizeof(c->cr_msg),
   3758                         "invalid starttls configuration" );
   3759                 goto fail;
   3760             }
   3761 #ifndef HAVE_TLS
   3762             if ( tlskey[i].mask == LLOAD_STARTTLS_OPTIONAL ) {
   3763                 Debug( LDAP_DEBUG_ANY, "%s: "
   3764                         "lloadd compiled without TLS but starttls specified, "
   3765                         "it will be ignored\n",
   3766                         c->log );
   3767             } else if ( tlskey[i].mask != LLOAD_CLEARTEXT ) {
   3768                 snprintf( c->cr_msg, sizeof(c->cr_msg),
   3769                         "invalid starttls configuration when compiled without "
   3770                         "TLS support" );
   3771                 goto fail;
   3772             }
   3773 #endif /* ! HAVE_TLS */
   3774             b->b_tls_conf = tlskey[i].mask;
   3775             if ( b->b_tls != LLOAD_LDAPS ) {
   3776                 b->b_tls = b->b_tls_conf;
   3777                 flag = LLOAD_BACKEND_MOD_OTHER;
   3778             }
   3779         } break;
   3780         case CFG_WEIGHT:
   3781             b->b_weight = c->value_uint;
   3782             break;
   3783         default:
   3784             rc = 1;
   3785             break;
   3786     }
   3787 
   3788     /* do not set this if it has already been set by another callback, e.g.
   3789      * lload_backend_ldadd */
   3790     if ( lload_change.type == LLOAD_CHANGE_UNDEFINED ) {
   3791         lload_change.type = LLOAD_CHANGE_MODIFY;
   3792     }
   3793     lload_change.object = LLOAD_BACKEND;
   3794     lload_change.target = b;
   3795     lload_change.flags.backend |= flag;
   3796 
   3797     config_push_cleanup( c, lload_backend_finish );
   3798     return rc;
   3799 
   3800 fail:
   3801     if ( lload_change.type == LLOAD_CHANGE_ADD ) {
   3802         /* Abort the ADD */
   3803         lload_change.type = LLOAD_CHANGE_DEL;
   3804     }
   3805 
   3806     Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg );
   3807     return 1;
   3808 }
   3809 
   3810 int
   3811 lload_back_init_cf( BackendInfo *bi )
   3812 {
   3813     /* Make sure we don't exceed the bits reserved for userland */
   3814     config_check_userland( CFG_LAST );
   3815 
   3816     bi->bi_cf_ocs = lloadocs;
   3817 
   3818     return config_register_schema( config_back_cf_table, lloadocs );
   3819 }
   3820 
   3821 static int
   3822 lload_tier_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
   3823 {
   3824     LloadTier *tier;
   3825     Attribute *a;
   3826     AttributeDescription *ad = NULL;
   3827     struct lload_tier_type *tier_impl;
   3828     struct berval bv, type, rdn;
   3829     const char *text;
   3830     char *name;
   3831 
   3832     Debug( LDAP_DEBUG_TRACE, "lload_tier_ldadd: "
   3833             "a new tier is being added\n" );
   3834 
   3835     if ( p->ce_type != Cft_Backend || !p->ce_bi ||
   3836             p->ce_bi->bi_cf_ocs != lloadocs )
   3837         return LDAP_CONSTRAINT_VIOLATION;
   3838 
   3839     dnRdn( &e->e_name, &rdn );
   3840     type.bv_len = strchr( rdn.bv_val, '=' ) - rdn.bv_val;
   3841     type.bv_val = rdn.bv_val;
   3842 
   3843     /* Find attr */
   3844     slap_bv2ad( &type, &ad, &text );
   3845     if ( ad != slap_schema.si_ad_cn ) return LDAP_NAMING_VIOLATION;
   3846 
   3847     a = attr_find( e->e_attrs, ad );
   3848     if ( !a || a->a_numvals != 1 ) return LDAP_NAMING_VIOLATION;
   3849     bv = a->a_vals[0];
   3850 
   3851     if ( bv.bv_val[0] == '{' && ( name = strchr( bv.bv_val, '}' ) ) ) {
   3852         name++;
   3853         bv.bv_len -= name - bv.bv_val;
   3854         bv.bv_val = name;
   3855     }
   3856 
   3857     ad = NULL;
   3858     slap_str2ad( "olcBkLloadTierType", &ad, &text );
   3859     assert( ad != NULL );
   3860 
   3861     a = attr_find( e->e_attrs, ad );
   3862     if ( !a || a->a_numvals != 1 ) return LDAP_OBJECT_CLASS_VIOLATION;
   3863 
   3864     tier_impl = lload_tier_find( a->a_vals[0].bv_val );
   3865     if ( !tier_impl ) {
   3866         Debug( LDAP_DEBUG_ANY, "lload_tier_ldadd: "
   3867                 "tier type %s not recongnised\n",
   3868                 bv.bv_val );
   3869         return LDAP_OTHER;
   3870     }
   3871 
   3872     tier = tier_impl->tier_init();
   3873     if ( !tier ) {
   3874         return LDAP_OTHER;
   3875     }
   3876 
   3877     ber_dupbv( &tier->t_name, &bv );
   3878 
   3879     ca->bi = p->ce_bi;
   3880     ca->ca_private = tier;
   3881 
   3882     if ( !lloadd_inited ) {
   3883         if ( LDAP_STAILQ_EMPTY( &tiers ) ) {
   3884             LDAP_STAILQ_INSERT_HEAD( &tiers, tier, t_next );
   3885         } else {
   3886             LDAP_STAILQ_INSERT_TAIL( &tiers, tier, t_next );
   3887         }
   3888     }
   3889 
   3890     /* ca cleanups are only run in the case of online config but we use it to
   3891      * save the new config when done with the entry */
   3892     ca->lineno = 0;
   3893 
   3894     lload_change.type = LLOAD_CHANGE_ADD;
   3895     lload_change.object = LLOAD_TIER;
   3896     lload_change.target = tier;
   3897 
   3898     return LDAP_SUCCESS;
   3899 }
   3900 
   3901 static int
   3902 lload_backend_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
   3903 {
   3904     LloadTier *tier = p->ce_private;
   3905     LloadBackend *b;
   3906     Attribute *a;
   3907     AttributeDescription *ad = NULL;
   3908     struct berval bv, type, rdn;
   3909     const char *text;
   3910     char *name;
   3911 
   3912     Debug( LDAP_DEBUG_TRACE, "lload_backend_ldadd: "
   3913             "a new backend-server is being added\n" );
   3914 
   3915     if ( p->ce_type != Cft_Misc || !p->ce_bi ||
   3916             p->ce_bi->bi_cf_ocs != lloadocs )
   3917         return LDAP_CONSTRAINT_VIOLATION;
   3918 
   3919     dnRdn( &e->e_name, &rdn );
   3920     type.bv_len = strchr( rdn.bv_val, '=' ) - rdn.bv_val;
   3921     type.bv_val = rdn.bv_val;
   3922 
   3923     /* Find attr */
   3924     slap_bv2ad( &type, &ad, &text );
   3925     if ( ad != slap_schema.si_ad_cn ) return LDAP_NAMING_VIOLATION;
   3926 
   3927     a = attr_find( e->e_attrs, ad );
   3928     if ( !a || a->a_numvals != 1 ) return LDAP_NAMING_VIOLATION;
   3929     bv = a->a_vals[0];
   3930 
   3931     if ( bv.bv_val[0] == '{' && ( name = strchr( bv.bv_val, '}' ) ) ) {
   3932         name++;
   3933         bv.bv_len -= name - bv.bv_val;
   3934         bv.bv_val = name;
   3935     }
   3936 
   3937     b = lload_backend_new();
   3938     ber_dupbv( &b->b_name, &bv );
   3939     b->b_tier = tier;
   3940 
   3941     ca->bi = p->ce_bi;
   3942     ca->ca_private = b;
   3943     config_push_cleanup( ca, lload_backend_finish );
   3944 
   3945     /* ca cleanups are only run in the case of online config but we use it to
   3946      * save the new config when done with the entry */
   3947     ca->lineno = 0;
   3948 
   3949     lload_change.type = LLOAD_CHANGE_ADD;
   3950     lload_change.object = LLOAD_BACKEND;
   3951     lload_change.target = b;
   3952 
   3953     return LDAP_SUCCESS;
   3954 }
   3955 
   3956 #ifdef SLAP_CONFIG_DELETE
   3957 static int
   3958 lload_backend_lddel( CfEntryInfo *ce, Operation *op )
   3959 {
   3960     LloadBackend *b = ce->ce_private;
   3961 
   3962     lload_change.type = LLOAD_CHANGE_DEL;
   3963     lload_change.object = LLOAD_BACKEND;
   3964     lload_change.target = b;
   3965 
   3966     return LDAP_SUCCESS;
   3967 }
   3968 
   3969 static int
   3970 lload_tier_lddel( CfEntryInfo *ce, Operation *op )
   3971 {
   3972     LloadTier *tier = ce->ce_private;
   3973 
   3974     lload_change.type = LLOAD_CHANGE_DEL;
   3975     lload_change.object = LLOAD_TIER;
   3976     lload_change.target = tier;
   3977 
   3978     return LDAP_SUCCESS;
   3979 }
   3980 #endif /* SLAP_CONFIG_DELETE */
   3981 
   3982 static int
   3983 lload_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *c )
   3984 {
   3985     struct berval bv;
   3986     LloadTier *tier;
   3987     int i = 0;
   3988 
   3989     bv.bv_val = c->cr_msg;
   3990     LDAP_STAILQ_FOREACH ( tier, &tiers, t_next ) {
   3991         LloadBackend *b;
   3992         ConfigOCs *coc;
   3993         Entry *e;
   3994         int j = 0;
   3995 
   3996         bv.bv_len = snprintf( c->cr_msg, sizeof(c->cr_msg),
   3997                 "cn=" SLAP_X_ORDERED_FMT "%s", i, tier->t_name.bv_val );
   3998 
   3999         c->ca_private = tier;
   4000         c->valx = i;
   4001 
   4002         for ( coc = lloadocs; coc->co_type; coc++ ) {
   4003             if ( !ber_bvcmp( coc->co_name, &tier->t_type.tier_oc ) ) {
   4004                 break;
   4005             }
   4006         }
   4007         assert( coc->co_type );
   4008 
   4009         e = config_build_entry( op, rs, p->e_private, c, &bv, coc, NULL );
   4010         if ( !e ) {
   4011             return 1;
   4012         }
   4013 
   4014         LDAP_CIRCLEQ_FOREACH ( b, &tier->t_backends, b_next ) {
   4015             bv.bv_len = snprintf( c->cr_msg, sizeof(c->cr_msg),
   4016                     "cn=" SLAP_X_ORDERED_FMT "%s", j, b->b_name.bv_val );
   4017 
   4018             for ( coc = lloadocs; coc->co_type; coc++ ) {
   4019                 if ( !ber_bvcmp(
   4020                              coc->co_name, &tier->t_type.tier_backend_oc ) ) {
   4021                     break;
   4022                 }
   4023             }
   4024             assert( coc->co_type );
   4025 
   4026             c->ca_private = b;
   4027             c->valx = j;
   4028 
   4029             if ( !config_build_entry(
   4030                          op, rs, e->e_private, c, &bv, coc, NULL ) ) {
   4031                 return 1;
   4032             }
   4033 
   4034             j++;
   4035         }
   4036 
   4037         i++;
   4038     }
   4039     return LDAP_SUCCESS;
   4040 }
   4041 #endif /* BALANCER_MODULE */
   4042