mirror of
https://git.openldap.org/openldap/openldap.git
synced 2026-01-14 10:53:22 -05:00
Reject operations in such a case with LDAP_BUSY. If read_event feature is on, just stop reading from the connection. However this could still result in deadlocks in reasonable situations. Need to figure out better ways to make it safe and still protect ourselves.
3793 lines
108 KiB
C
3793 lines
108 KiB
C
/* config.c - configuration file handling routines */
|
|
/* $OpenLDAP$ */
|
|
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
|
*
|
|
* Copyright 1998-2020 The OpenLDAP Foundation.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted only as authorized by the OpenLDAP
|
|
* Public License.
|
|
*
|
|
* A copy of this license is available in the file LICENSE in the
|
|
* top-level directory of the distribution or, alternatively, at
|
|
* <http://www.OpenLDAP.org/license.html>.
|
|
*/
|
|
/* Portions Copyright (c) 1995 Regents of the University of Michigan.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms are permitted
|
|
* provided that this notice is preserved and that due credit is given
|
|
* to the University of Michigan at Ann Arbor. The name of the University
|
|
* may not be used to endorse or promote products derived from this
|
|
* software without specific prior written permission. This software
|
|
* is provided ``as is'' without express or implied warranty.
|
|
*/
|
|
|
|
#include "portable.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <ac/string.h>
|
|
#include <ac/ctype.h>
|
|
#include <ac/signal.h>
|
|
#include <ac/socket.h>
|
|
#include <ac/errno.h>
|
|
#include <ac/unistd.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
|
|
#ifndef S_ISREG
|
|
#define S_ISREG(m) ( ((m) & _S_IFMT ) == _S_IFREG )
|
|
#endif
|
|
|
|
#include "lload.h"
|
|
#include "lutil.h"
|
|
#include "lutil_ldap.h"
|
|
#include "config.h"
|
|
|
|
#ifdef _WIN32
|
|
#define LUTIL_ATOULX lutil_atoullx
|
|
#define Z "I"
|
|
#else
|
|
#define LUTIL_ATOULX lutil_atoulx
|
|
#define Z "z"
|
|
#endif
|
|
|
|
#define ARGS_STEP 512
|
|
|
|
/*
|
|
* defaults for various global variables
|
|
*/
|
|
#ifdef BALANCER_MODULE
|
|
char *listeners_list = NULL;
|
|
#else /* !BALANCER_MODULE */
|
|
slap_mask_t global_allows = 0;
|
|
slap_mask_t global_disallows = 0;
|
|
int global_gentlehup = 0;
|
|
int global_idletimeout = 0;
|
|
char *global_host = NULL;
|
|
|
|
char *slapd_pid_file = NULL;
|
|
char *slapd_args_file = NULL;
|
|
#endif /* !BALANCER_MODULE */
|
|
|
|
static FILE *logfile;
|
|
static char *logfileName;
|
|
|
|
static struct timeval timeout_api_tv, timeout_net_tv,
|
|
timeout_write_tv = { 10, 0 };
|
|
|
|
lload_features_t lload_features;
|
|
|
|
ber_len_t sockbuf_max_incoming_client = LLOAD_SB_MAX_INCOMING_CLIENT;
|
|
ber_len_t sockbuf_max_incoming_upstream = LLOAD_SB_MAX_INCOMING_UPSTREAM;
|
|
|
|
int lload_conn_max_pdus_per_cycle = LLOAD_CONN_MAX_PDUS_PER_CYCLE_DEFAULT;
|
|
|
|
struct timeval *lload_timeout_api = NULL;
|
|
struct timeval *lload_timeout_net = NULL;
|
|
struct timeval *lload_write_timeout = &timeout_write_tv;
|
|
|
|
static slap_verbmasks tlskey[];
|
|
|
|
static int fp_getline( FILE *fp, ConfigArgs *c );
|
|
static void fp_getline_init( ConfigArgs *c );
|
|
|
|
static char *strtok_quote(
|
|
char *line,
|
|
char *sep,
|
|
char **quote_ptr,
|
|
int *inquote );
|
|
|
|
typedef struct ConfigFile {
|
|
struct ConfigFile *c_sibs;
|
|
struct ConfigFile *c_kids;
|
|
struct berval c_file;
|
|
BerVarray c_dseFiles;
|
|
} ConfigFile;
|
|
|
|
static ConfigFile *cfn;
|
|
|
|
static ConfigDriver config_fname;
|
|
static ConfigDriver config_generic;
|
|
static ConfigDriver config_backend;
|
|
static ConfigDriver config_bindconf;
|
|
#ifdef LDAP_TCP_BUFFER
|
|
static ConfigDriver config_tcp_buffer;
|
|
#endif /* LDAP_TCP_BUFFER */
|
|
static ConfigDriver config_restrict;
|
|
static ConfigDriver config_loglevel;
|
|
static ConfigDriver config_include;
|
|
static ConfigDriver config_feature;
|
|
#ifdef HAVE_TLS
|
|
static ConfigDriver config_tls_option;
|
|
static ConfigDriver config_tls_config;
|
|
#endif
|
|
#ifdef BALANCER_MODULE
|
|
static ConfigDriver config_share_tls_ctx;
|
|
static ConfigDriver backend_cf_gen;
|
|
#endif /* BALANCER_MODULE */
|
|
|
|
lload_b_head backend = LDAP_CIRCLEQ_HEAD_INITIALIZER(backend);
|
|
ldap_pvt_thread_mutex_t backend_mutex;
|
|
LloadBackend *current_backend = NULL;
|
|
|
|
struct slap_bindconf bindconf = {};
|
|
struct berval lloadd_identity = BER_BVNULL;
|
|
|
|
enum {
|
|
CFG_ACL = 1,
|
|
CFG_BACKEND,
|
|
CFG_BINDCONF,
|
|
CFG_LISTEN,
|
|
CFG_LISTEN_URI,
|
|
CFG_TLS_RAND,
|
|
CFG_TLS_CIPHER,
|
|
CFG_TLS_PROTOCOL_MIN,
|
|
CFG_TLS_CERT_FILE,
|
|
CFG_TLS_CERT_KEY,
|
|
CFG_TLS_CA_PATH,
|
|
CFG_TLS_CA_FILE,
|
|
CFG_TLS_DH_FILE,
|
|
CFG_TLS_VERIFY,
|
|
CFG_TLS_CRLCHECK,
|
|
CFG_TLS_CRL_FILE,
|
|
CFG_TLS_SHARE_CTX,
|
|
CFG_CONCUR,
|
|
CFG_THREADS,
|
|
CFG_LOGFILE,
|
|
CFG_MIRRORMODE,
|
|
CFG_IOTHREADS,
|
|
CFG_MAXBUF_CLIENT,
|
|
CFG_MAXBUF_UPSTREAM,
|
|
CFG_FEATURE,
|
|
CFG_THREADQS,
|
|
CFG_TLS_ECNAME,
|
|
CFG_TLS_CACERT,
|
|
CFG_TLS_CERT,
|
|
CFG_TLS_KEY,
|
|
CFG_RESCOUNT,
|
|
CFG_IOTIMEOUT,
|
|
CFG_URI,
|
|
CFG_NUMCONNS,
|
|
CFG_BINDCONNS,
|
|
CFG_RETRY,
|
|
CFG_MAX_PENDING_OPS,
|
|
CFG_MAX_PENDING_CONNS,
|
|
CFG_STARTTLS,
|
|
CFG_CLIENT_PENDING,
|
|
|
|
CFG_LAST
|
|
};
|
|
|
|
/* alphabetical ordering */
|
|
|
|
static ConfigTable config_back_cf_table[] = {
|
|
/* This attr is read-only */
|
|
{ "", "", 0, 0, 0,
|
|
ARG_MAGIC,
|
|
&config_fname,
|
|
NULL, NULL, NULL
|
|
},
|
|
{ "argsfile", "file", 2, 2, 0,
|
|
ARG_STRING,
|
|
&slapd_args_file,
|
|
NULL, NULL, NULL
|
|
},
|
|
{ "concurrency", "level", 2, 2, 0,
|
|
ARG_UINT|ARG_MAGIC|CFG_CONCUR,
|
|
&config_generic,
|
|
NULL, NULL, NULL
|
|
},
|
|
/* conf-file only option */
|
|
{ "backend-server", "backend options", 2, 0, 0,
|
|
ARG_MAGIC|CFG_BACKEND,
|
|
&config_backend,
|
|
NULL, NULL, NULL
|
|
},
|
|
{ "bindconf", "backend credentials", 2, 0, 0,
|
|
ARG_MAGIC|CFG_BINDCONF,
|
|
&config_bindconf,
|
|
"( OLcfgBkAt:13.2 "
|
|
"NAME 'olcBkLloadBindconf' "
|
|
"DESC 'Backend credentials' "
|
|
/* No EQUALITY since this is a compound attribute (and needs
|
|
* splitting up anyway - which is a TODO) */
|
|
"SYNTAX OMsDirectoryString "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "gentlehup", "on|off", 2, 2, 0,
|
|
#ifdef SIGHUP
|
|
ARG_ON_OFF,
|
|
&global_gentlehup,
|
|
#else
|
|
ARG_IGNORED,
|
|
NULL,
|
|
#endif
|
|
NULL, NULL, NULL
|
|
},
|
|
{ "idletimeout", "timeout", 2, 2, 0,
|
|
ARG_UINT,
|
|
&global_idletimeout,
|
|
"( OLcfgBkAt:13.3 "
|
|
"NAME 'olcBkLloadIdleTimeout' "
|
|
"DESC 'Connection idle timeout' "
|
|
"EQUALITY integerMatch "
|
|
"SYNTAX OMsInteger "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "include", "file", 2, 2, 0,
|
|
ARG_MAGIC,
|
|
&config_include,
|
|
NULL, NULL, NULL
|
|
},
|
|
{ "io-threads", "count", 2, 0, 0,
|
|
ARG_UINT|ARG_MAGIC|CFG_IOTHREADS,
|
|
&config_generic,
|
|
"( OLcfgBkAt:13.4 "
|
|
"NAME 'olcBkLloadIOThreads' "
|
|
"DESC 'I/O thread count' "
|
|
"EQUALITY integerMatch "
|
|
"SYNTAX OMsInteger "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
#ifdef BALANCER_MODULE
|
|
{ "listen", "uri list", 2, 2, 0,
|
|
ARG_STRING|ARG_MAGIC|CFG_LISTEN,
|
|
&config_generic,
|
|
NULL, NULL, NULL
|
|
},
|
|
{ "", "uri", 2, 2, 0,
|
|
ARG_MAGIC|CFG_LISTEN_URI,
|
|
&config_generic,
|
|
"( OLcfgBkAt:13.5 "
|
|
"NAME 'olcBkLloadListen' "
|
|
"DESC 'A listener adress' "
|
|
/* We don't handle adding/removing a value, so no EQUALITY yet */
|
|
"SYNTAX OMsDirectoryString )",
|
|
NULL, NULL
|
|
},
|
|
#endif /* BALANCER_MODULE */
|
|
{ "logfile", "file", 2, 2, 0,
|
|
ARG_STRING|ARG_MAGIC|CFG_LOGFILE,
|
|
&config_generic,
|
|
NULL, NULL, NULL
|
|
},
|
|
{ "loglevel", "level", 2, 0, 0,
|
|
ARG_MAGIC,
|
|
&config_loglevel,
|
|
NULL, NULL, NULL
|
|
},
|
|
{ "pidfile", "file", 2, 2, 0,
|
|
ARG_STRING,
|
|
&slapd_pid_file,
|
|
NULL, NULL, NULL
|
|
},
|
|
{ "restrict", "op_list", 2, 0, 0,
|
|
ARG_MAGIC,
|
|
&config_restrict,
|
|
NULL, NULL, NULL
|
|
},
|
|
{ "sockbuf_max_incoming_client", "max", 2, 2, 0,
|
|
ARG_BER_LEN_T|ARG_MAGIC|CFG_MAXBUF_CLIENT,
|
|
&config_generic,
|
|
"( OLcfgBkAt:13.6 "
|
|
"NAME 'olcBkLloadSockbufMaxClient' "
|
|
"DESC 'The maximum LDAP PDU size accepted coming from clients' "
|
|
"EQUALITY integerMatch "
|
|
"SYNTAX OMsInteger "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "sockbuf_max_incoming_upstream", "max", 2, 2, 0,
|
|
ARG_BER_LEN_T|ARG_MAGIC|CFG_MAXBUF_UPSTREAM,
|
|
&config_generic,
|
|
"( OLcfgBkAt:13.7 "
|
|
"NAME 'olcBkLloadSockbufMaxUpstream' "
|
|
"DESC 'The maximum LDAP PDU size accepted coming from upstream' "
|
|
"EQUALITY integerMatch "
|
|
"SYNTAX OMsInteger "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "tcp-buffer", "[listener=<listener>] [{read|write}=]size", 0, 0, 0,
|
|
#ifdef LDAP_TCP_BUFFER
|
|
ARG_MAGIC,
|
|
&config_tcp_buffer,
|
|
#else
|
|
ARG_IGNORED,
|
|
NULL,
|
|
#endif
|
|
"( OLcfgBkAt:13.8 "
|
|
"NAME 'olcBkLloadTcpBuffer' "
|
|
"DESC 'TCP Buffer size' "
|
|
"EQUALITY caseIgnoreMatch "
|
|
"SYNTAX OMsDirectoryString "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "threads", "count", 2, 2, 0,
|
|
ARG_UINT|ARG_MAGIC|CFG_THREADS,
|
|
&config_generic,
|
|
NULL, NULL, NULL
|
|
},
|
|
{ "threadqueues", "count", 2, 2, 0,
|
|
ARG_UINT|ARG_MAGIC|CFG_THREADQS,
|
|
&config_generic,
|
|
NULL, NULL, NULL
|
|
},
|
|
{ "max_pdus_per_cycle", "count", 2, 2, 0,
|
|
ARG_UINT|ARG_MAGIC|CFG_RESCOUNT,
|
|
&config_generic,
|
|
"( OLcfgBkAt:13.9 "
|
|
"NAME 'olcBkLloadMaxPDUPerCycle' "
|
|
"DESC 'Maximum number of PDUs to handle in a single cycle' "
|
|
"EQUALITY integerMatch "
|
|
"SYNTAX OMsInteger "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "feature", "name", 2, 0, 0,
|
|
ARG_MAGIC|CFG_FEATURE,
|
|
&config_feature,
|
|
"( OLcfgBkAt:13.10 "
|
|
"NAME 'olcBkLloadFeature' "
|
|
"DESC 'Lload features enabled' "
|
|
"EQUALITY caseIgnoreMatch "
|
|
"SYNTAX OMsDirectoryString )",
|
|
NULL, NULL
|
|
},
|
|
{ "TLSCACertificate", NULL, 2, 2, 0,
|
|
#ifdef HAVE_TLS
|
|
CFG_TLS_CACERT|ARG_BINARY|ARG_MAGIC,
|
|
&config_tls_option,
|
|
#else
|
|
ARG_IGNORED,
|
|
NULL,
|
|
#endif
|
|
"( OLcfgBkAt:13.11 "
|
|
"NAME 'olcBkLloadTLSCACertificate' "
|
|
"DESC 'X.509 certificate, must use ;binary' "
|
|
"EQUALITY certificateExactMatch "
|
|
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "TLSCACertificateFile", NULL, 2, 2, 0,
|
|
#ifdef HAVE_TLS
|
|
CFG_TLS_CA_FILE|ARG_STRING|ARG_MAGIC,
|
|
&config_tls_option,
|
|
#else
|
|
ARG_IGNORED,
|
|
NULL,
|
|
#endif
|
|
"( OLcfgBkAt:13.12 "
|
|
"NAME 'olcBkLloadTLSCACertificateFile' "
|
|
"EQUALITY caseExactMatch "
|
|
"SYNTAX OMsDirectoryString "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "TLSCACertificatePath", NULL, 2, 2, 0,
|
|
#ifdef HAVE_TLS
|
|
CFG_TLS_CA_PATH|ARG_STRING|ARG_MAGIC,
|
|
&config_tls_option,
|
|
#else
|
|
ARG_IGNORED,
|
|
NULL,
|
|
#endif
|
|
"( OLcfgBkAt:13.13 "
|
|
"NAME 'olcBkLloadTLSCACertificatePath' "
|
|
"EQUALITY caseExactMatch "
|
|
"SYNTAX OMsDirectoryString "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "TLSCertificate", NULL, 2, 2, 0,
|
|
#ifdef HAVE_TLS
|
|
CFG_TLS_CERT|ARG_BINARY|ARG_MAGIC,
|
|
&config_tls_option,
|
|
#else
|
|
ARG_IGNORED,
|
|
NULL,
|
|
#endif
|
|
"( OLcfgBkAt:13.14 "
|
|
"NAME 'olcBkLloadTLSCertificate' "
|
|
"DESC 'X.509 certificate, must use ;binary' "
|
|
"EQUALITY certificateExactMatch "
|
|
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "TLSCertificateFile", NULL, 2, 2, 0,
|
|
#ifdef HAVE_TLS
|
|
CFG_TLS_CERT_FILE|ARG_STRING|ARG_MAGIC,
|
|
&config_tls_option,
|
|
#else
|
|
ARG_IGNORED,
|
|
NULL,
|
|
#endif
|
|
"( OLcfgBkAt:13.15 "
|
|
"NAME 'olcBkLloadTLSCertificateFile' "
|
|
"EQUALITY caseExactMatch "
|
|
"SYNTAX OMsDirectoryString "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "TLSCertificateKey", NULL, 2, 2, 0,
|
|
#ifdef HAVE_TLS
|
|
CFG_TLS_KEY|ARG_BINARY|ARG_MAGIC,
|
|
&config_tls_option,
|
|
#else
|
|
ARG_IGNORED,
|
|
NULL,
|
|
#endif
|
|
"( OLcfgBkAt:13.16 "
|
|
"NAME 'olcBkLloadTLSCertificateKey' "
|
|
"DESC 'X.509 privateKey, must use ;binary' "
|
|
"EQUALITY privateKeyMatch "
|
|
"SYNTAX 1.2.840.113549.1.8.1.1 "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "TLSCertificateKeyFile", NULL, 2, 2, 0,
|
|
#ifdef HAVE_TLS
|
|
CFG_TLS_CERT_KEY|ARG_STRING|ARG_MAGIC,
|
|
&config_tls_option,
|
|
#else
|
|
ARG_IGNORED,
|
|
NULL,
|
|
#endif
|
|
"( OLcfgBkAt:13.17 "
|
|
"NAME 'olcBkLloadTLSCertificateKeyFile' "
|
|
"EQUALITY caseExactMatch "
|
|
"SYNTAX OMsDirectoryString "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "TLSCipherSuite", NULL, 2, 2, 0,
|
|
#ifdef HAVE_TLS
|
|
CFG_TLS_CIPHER|ARG_STRING|ARG_MAGIC,
|
|
&config_tls_option,
|
|
#else
|
|
ARG_IGNORED,
|
|
NULL,
|
|
#endif
|
|
"( OLcfgBkAt:13.18 "
|
|
"NAME 'olcBkLloadTLSCipherSuite' "
|
|
"EQUALITY caseExactMatch "
|
|
"SYNTAX OMsDirectoryString "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "TLSCRLCheck", NULL, 2, 2, 0,
|
|
#if defined(HAVE_TLS) && defined(HAVE_OPENSSL)
|
|
CFG_TLS_CRLCHECK|ARG_STRING|ARG_MAGIC,
|
|
&config_tls_config,
|
|
#else
|
|
ARG_IGNORED,
|
|
NULL,
|
|
#endif
|
|
"( OLcfgBkAt:13.19 "
|
|
"NAME 'olcBkLloadTLSCRLCheck' "
|
|
"EQUALITY caseIgnoreMatch "
|
|
"SYNTAX OMsDirectoryString "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "TLSCRLFile", NULL, 2, 2, 0,
|
|
#if defined(HAVE_GNUTLS)
|
|
CFG_TLS_CRL_FILE|ARG_STRING|ARG_MAGIC,
|
|
&config_tls_option,
|
|
#else
|
|
ARG_IGNORED,
|
|
NULL,
|
|
#endif
|
|
"( OLcfgBkAt:13.20 "
|
|
"NAME 'olcBkLloadTLSCRLFile' "
|
|
"EQUALITY caseExactMatch "
|
|
"SYNTAX OMsDirectoryString "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "TLSRandFile", NULL, 2, 2, 0,
|
|
#ifdef HAVE_TLS
|
|
CFG_TLS_RAND|ARG_STRING|ARG_MAGIC,
|
|
&config_tls_option,
|
|
#else
|
|
ARG_IGNORED,
|
|
NULL,
|
|
#endif
|
|
"( OLcfgBkAt:13.21 "
|
|
"NAME 'olcBkLloadTLSRandFile' "
|
|
"EQUALITY caseExactMatch "
|
|
"SYNTAX OMsDirectoryString "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "TLSVerifyClient", NULL, 2, 2, 0,
|
|
#ifdef HAVE_TLS
|
|
CFG_TLS_VERIFY|ARG_STRING|ARG_MAGIC,
|
|
&config_tls_config,
|
|
#else
|
|
ARG_IGNORED,
|
|
NULL,
|
|
#endif
|
|
"( OLcfgBkAt:13.22 "
|
|
"NAME 'olcBkLloadVerifyClient' "
|
|
"EQUALITY caseIgnoreMatch "
|
|
"SYNTAX OMsDirectoryString "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "TLSDHParamFile", NULL, 2, 2, 0,
|
|
#ifdef HAVE_TLS
|
|
CFG_TLS_DH_FILE|ARG_STRING|ARG_MAGIC,
|
|
&config_tls_option,
|
|
#else
|
|
ARG_IGNORED,
|
|
NULL,
|
|
#endif
|
|
"( OLcfgBkAt:13.23 "
|
|
"NAME 'olcBkLloadTLSDHParamFile' "
|
|
"EQUALITY caseExactMatch "
|
|
"SYNTAX OMsDirectoryString "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "TLSECName", NULL, 2, 2, 0,
|
|
#ifdef HAVE_TLS
|
|
CFG_TLS_ECNAME|ARG_STRING|ARG_MAGIC,
|
|
&config_tls_option,
|
|
#else
|
|
ARG_IGNORED,
|
|
NULL,
|
|
#endif
|
|
"( OLcfgBkAt:13.24 "
|
|
"NAME 'olcBkLloadTLSECName' "
|
|
"EQUALITY caseExactMatch "
|
|
"SYNTAX OMsDirectoryString "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "TLSProtocolMin", NULL, 2, 2, 0,
|
|
#ifdef HAVE_TLS
|
|
CFG_TLS_PROTOCOL_MIN|ARG_STRING|ARG_MAGIC,
|
|
&config_tls_config,
|
|
#else
|
|
ARG_IGNORED,
|
|
NULL,
|
|
#endif
|
|
"( OLcfgBkAt:13.25 "
|
|
"NAME 'olcBkLloadTLSProtocolMin' "
|
|
"EQUALITY caseIgnoreMatch "
|
|
"SYNTAX OMsDirectoryString "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "TLSShareSlapdCTX", NULL, 2, 2, 0,
|
|
#if defined(HAVE_TLS) && defined(BALANCER_MODULE)
|
|
CFG_TLS_SHARE_CTX|ARG_ON_OFF|ARG_MAGIC,
|
|
&config_share_tls_ctx,
|
|
#else
|
|
ARG_IGNORED,
|
|
NULL,
|
|
#endif
|
|
"( OLcfgBkAt:13.33 "
|
|
"NAME 'olcBkLloadTLSShareSlapdCTX' "
|
|
"DESC 'Share slapd TLS context (all other lloadd TLS options cease to take effect)' "
|
|
"EQUALITY booleanMatch "
|
|
"SYNTAX OMsBoolean "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "iotimeout", "ms timeout", 2, 2, 0,
|
|
ARG_UINT|ARG_MAGIC|CFG_IOTIMEOUT,
|
|
&config_generic,
|
|
"( OLcfgBkAt:13.26 "
|
|
"NAME 'olcBkLloadIOTimeout' "
|
|
"DESC 'I/O timeout threshold in miliseconds' "
|
|
"EQUALITY integerMatch "
|
|
"SYNTAX OMsInteger "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "client_max_pending", NULL, 2, 2, 0,
|
|
ARG_MAGIC|ARG_UINT|CFG_CLIENT_PENDING,
|
|
&config_generic,
|
|
"( OLcfgBkAt:13.35 "
|
|
"NAME 'olcBkLloadClientMaxPending' "
|
|
"DESC 'Maximum pending operations per client connection' "
|
|
"EQUALITY integerMatch "
|
|
"SYNTAX OMsInteger "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
|
|
/* cn=config only options */
|
|
#ifdef BALANCER_MODULE
|
|
{ "", "uri", 2, 2, 0,
|
|
ARG_BERVAL|ARG_MAGIC|CFG_URI,
|
|
&backend_cf_gen,
|
|
"( OLcfgBkAt:13.27 "
|
|
"NAME 'olcBkLloadBackendUri' "
|
|
"DESC 'URI to contact the server on' "
|
|
"EQUALITY caseIgnoreMatch "
|
|
"SYNTAX OMsDirectoryString "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "", NULL, 2, 2, 0,
|
|
ARG_UINT|ARG_MAGIC|CFG_NUMCONNS,
|
|
&backend_cf_gen,
|
|
"( OLcfgBkAt:13.28 "
|
|
"NAME 'olcBkLloadNumconns' "
|
|
"DESC 'Number of regular connections to maintain' "
|
|
"EQUALITY integerMatch "
|
|
"SYNTAX OMsInteger "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "", NULL, 2, 2, 0,
|
|
ARG_UINT|ARG_MAGIC|CFG_BINDCONNS,
|
|
&backend_cf_gen,
|
|
"( OLcfgBkAt:13.29 "
|
|
"NAME 'olcBkLloadBindconns' "
|
|
"DESC 'Number of bind connections to maintain' "
|
|
"EQUALITY integerMatch "
|
|
"SYNTAX OMsInteger "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "", NULL, 2, 2, 0,
|
|
ARG_UINT|ARG_MAGIC|CFG_RETRY,
|
|
&backend_cf_gen,
|
|
"( OLcfgBkAt:13.30 "
|
|
"NAME 'olcBkLloadRetry' "
|
|
"DESC 'Number of seconds to wait before trying to reconnect' "
|
|
"EQUALITY integerMatch "
|
|
"SYNTAX OMsInteger "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "", NULL, 2, 2, 0,
|
|
ARG_UINT|ARG_MAGIC|CFG_MAX_PENDING_OPS,
|
|
&backend_cf_gen,
|
|
"( OLcfgBkAt:13.31 "
|
|
"NAME 'olcBkLloadMaxPendingOps' "
|
|
"DESC 'Maximum number of pending operations for this backend' "
|
|
"EQUALITY integerMatch "
|
|
"SYNTAX OMsInteger "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "", NULL, 2, 2, 0,
|
|
ARG_UINT|ARG_MAGIC|CFG_MAX_PENDING_CONNS,
|
|
&backend_cf_gen,
|
|
"( OLcfgBkAt:13.32 "
|
|
"NAME 'olcBkLloadMaxPendingConns' "
|
|
"DESC 'Maximum number of pending operations on each connection' "
|
|
"EQUALITY integerMatch "
|
|
"SYNTAX OMsInteger "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "", NULL, 2, 2, 0,
|
|
ARG_BERVAL|ARG_MAGIC|CFG_STARTTLS,
|
|
&backend_cf_gen,
|
|
"( OLcfgBkAt:13.34 "
|
|
"NAME 'olcBkLloadStartTLS' "
|
|
"DESC 'Whether StartTLS should be attempted on the connection' "
|
|
"EQUALITY caseIgnoreMatch "
|
|
"SYNTAX OMsDirectoryString "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
#endif /* BALANCER_MODULE */
|
|
|
|
{ NULL, NULL, 0, 0, 0, ARG_IGNORED, NULL }
|
|
};
|
|
|
|
#ifdef BALANCER_MODULE
|
|
static ConfigCfAdd lload_cfadd;
|
|
static ConfigLDAPadd lload_backend_ldadd;
|
|
#ifdef SLAP_CONFIG_DELETE
|
|
static ConfigLDAPdel lload_backend_lddel;
|
|
#endif /* SLAP_CONFIG_DELETE */
|
|
|
|
static ConfigOCs lloadocs[] = {
|
|
{ "( OLcfgBkOc:13.1 "
|
|
"NAME 'olcBkLloadConfig' "
|
|
"DESC 'Lload backend configuration' "
|
|
"SUP olcBackendConfig "
|
|
"MUST ( olcBkLloadBindconf "
|
|
"$ olcBkLloadIOThreads "
|
|
"$ olcBkLloadListen "
|
|
"$ olcBkLloadSockbufMaxClient "
|
|
"$ olcBkLloadSockbufMaxUpstream "
|
|
"$ olcBkLloadMaxPDUPerCycle "
|
|
"$ olcBkLloadIOTimeout ) "
|
|
"MAY ( olcBkLloadFeature "
|
|
"$ olcBkLloadTcpBuffer "
|
|
"$ olcBkLloadTLSCACertificateFile "
|
|
"$ olcBkLloadTLSCACertificatePath "
|
|
"$ olcBkLloadTLSCertificateFile "
|
|
"$ olcBkLloadTLSCertificateKeyFile "
|
|
"$ olcBkLloadTLSCipherSuite "
|
|
"$ olcBkLloadTLSCRLCheck "
|
|
"$ olcBkLloadTLSRandFile "
|
|
"$ olcBkLloadVerifyClient "
|
|
"$ olcBkLloadTLSDHParamFile "
|
|
"$ olcBkLloadTLSECName "
|
|
"$ olcBkLloadTLSProtocolMin "
|
|
"$ olcBkLloadTLSCRLFile "
|
|
"$ olcBkLloadTLSShareSlapdCTX "
|
|
") )",
|
|
Cft_Backend, config_back_cf_table,
|
|
NULL,
|
|
lload_cfadd,
|
|
},
|
|
{ "( OLcfgBkOc:13.2 "
|
|
"NAME 'olcBkLloadBackendConfig' "
|
|
"DESC 'Lload backend server configuration' "
|
|
"SUP olcConfig STRUCTURAL "
|
|
"MUST ( cn "
|
|
"$ olcBkLloadBackendUri "
|
|
"$ olcBkLloadNumconns "
|
|
"$ olcBkLloadBindconns "
|
|
"$ olcBkLloadRetry "
|
|
"$ olcBkLloadMaxPendingOps "
|
|
"$ olcBkLloadMaxPendingConns ) "
|
|
"MAY ( olcBkLloadStartTLS "
|
|
") )",
|
|
Cft_Misc, config_back_cf_table,
|
|
lload_backend_ldadd,
|
|
NULL,
|
|
#ifdef SLAP_CONFIG_DELETE
|
|
lload_backend_lddel,
|
|
#endif /* SLAP_CONFIG_DELETE */
|
|
},
|
|
{ NULL, 0, NULL }
|
|
};
|
|
#endif /* BALANCER_MODULE */
|
|
|
|
static int
|
|
config_generic( ConfigArgs *c )
|
|
{
|
|
enum lcf_daemon flag = 0;
|
|
int rc = LDAP_SUCCESS;
|
|
|
|
if ( c->op == SLAP_CONFIG_EMIT ) {
|
|
switch ( c->type ) {
|
|
case CFG_IOTHREADS:
|
|
c->value_uint = lload_daemon_threads;
|
|
break;
|
|
case CFG_LISTEN_URI: {
|
|
LloadListener **ll = lloadd_get_listeners();
|
|
struct berval bv = BER_BVNULL;
|
|
|
|
for ( ; ll && *ll; ll++ ) {
|
|
/* The same url could have spawned several consecutive
|
|
* listeners */
|
|
if ( !BER_BVISNULL( &bv ) &&
|
|
!ber_bvcmp( &bv, &(*ll)->sl_url ) ) {
|
|
continue;
|
|
}
|
|
ber_dupbv( &bv, &(*ll)->sl_url );
|
|
ber_bvarray_add( &c->rvalue_vals, &bv );
|
|
}
|
|
} break;
|
|
case CFG_MAXBUF_CLIENT:
|
|
c->value_uint = sockbuf_max_incoming_client;
|
|
break;
|
|
case CFG_MAXBUF_UPSTREAM:
|
|
c->value_uint = sockbuf_max_incoming_upstream;
|
|
break;
|
|
case CFG_RESCOUNT:
|
|
c->value_uint = lload_conn_max_pdus_per_cycle;
|
|
break;
|
|
case CFG_IOTIMEOUT:
|
|
c->value_uint = 1000 * lload_write_timeout->tv_sec +
|
|
lload_write_timeout->tv_usec / 1000;
|
|
break;
|
|
case CFG_CLIENT_PENDING:
|
|
c->value_uint = lload_client_max_pending;
|
|
break;
|
|
default:
|
|
rc = 1;
|
|
break;
|
|
}
|
|
return rc;
|
|
|
|
} else if ( c->op == LDAP_MOD_DELETE ) {
|
|
/* We only need to worry about deletions to multi-value or MAY
|
|
* attributes that belong to the lloadd module - we don't have any at
|
|
* the moment */
|
|
return rc;
|
|
}
|
|
|
|
lload_change.type = LLOAD_CHANGE_MODIFY;
|
|
lload_change.object = LLOAD_DAEMON;
|
|
|
|
switch ( c->type ) {
|
|
case CFG_CONCUR:
|
|
ldap_pvt_thread_set_concurrency( c->value_uint );
|
|
break;
|
|
case CFG_LISTEN:
|
|
if ( lloadd_inited ) {
|
|
snprintf( c->cr_msg, sizeof(c->cr_msg),
|
|
"listen directive can only be specified once" );
|
|
ch_free( c->value_string );
|
|
return 1;
|
|
}
|
|
if ( lloadd_listeners_init( c->value_string ) ) {
|
|
snprintf( c->cr_msg, sizeof(c->cr_msg),
|
|
"could not open one of the listener sockets: %s",
|
|
c->value_string );
|
|
ch_free( c->value_string );
|
|
return 1;
|
|
}
|
|
ch_free( c->value_string );
|
|
break;
|
|
case CFG_LISTEN_URI: {
|
|
LDAPURLDesc *lud;
|
|
LloadListener *l;
|
|
|
|
if ( ldap_url_parse_ext(
|
|
c->line, &lud, LDAP_PVT_URL_PARSE_DEF_PORT ) ) {
|
|
snprintf( c->cr_msg, sizeof(c->cr_msg),
|
|
"string %s could not be parsed as an LDAP URL",
|
|
c->line );
|
|
goto fail;
|
|
}
|
|
|
|
/* A sanity check, although it will not catch everything */
|
|
if ( ( l = lload_config_check_my_url( c->line, lud ) ) ) {
|
|
snprintf( c->cr_msg, sizeof(c->cr_msg),
|
|
"Load Balancer already configured to listen on %s "
|
|
"(while adding %s)",
|
|
l->sl_url.bv_val, c->line );
|
|
goto fail;
|
|
}
|
|
|
|
if ( !lloadd_inited ) {
|
|
if ( lload_open_new_listener( c->line, lud ) ) {
|
|
snprintf( c->cr_msg, sizeof(c->cr_msg),
|
|
"could not open a listener for %s", c->line );
|
|
goto fail;
|
|
}
|
|
} else {
|
|
snprintf( c->cr_msg, sizeof(c->cr_msg),
|
|
"listener changes will not take effect until restart: "
|
|
"%s",
|
|
c->line );
|
|
Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg );
|
|
}
|
|
} break;
|
|
case CFG_THREADS:
|
|
if ( c->value_uint < 2 ) {
|
|
snprintf( c->cr_msg, sizeof(c->cr_msg),
|
|
"threads=%d smaller than minimum value 2",
|
|
c->value_uint );
|
|
goto fail;
|
|
|
|
} else if ( c->value_uint > 2 * SLAP_MAX_WORKER_THREADS ) {
|
|
snprintf( c->cr_msg, sizeof(c->cr_msg),
|
|
"warning, threads=%d larger than twice the default "
|
|
"(2*%d=%d); YMMV",
|
|
c->value_uint, SLAP_MAX_WORKER_THREADS,
|
|
2 * SLAP_MAX_WORKER_THREADS );
|
|
Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg );
|
|
}
|
|
if ( slapMode & SLAP_SERVER_MODE )
|
|
ldap_pvt_thread_pool_maxthreads(
|
|
&connection_pool, c->value_uint );
|
|
connection_pool_max = c->value_uint; /* save for reference */
|
|
break;
|
|
|
|
case CFG_THREADQS:
|
|
if ( c->value_uint < 1 ) {
|
|
snprintf( c->cr_msg, sizeof(c->cr_msg),
|
|
"threadqueues=%d smaller than minimum value 1",
|
|
c->value_uint );
|
|
goto fail;
|
|
}
|
|
if ( slapMode & SLAP_SERVER_MODE )
|
|
ldap_pvt_thread_pool_queues( &connection_pool, c->value_uint );
|
|
connection_pool_queues = c->value_uint; /* save for reference */
|
|
break;
|
|
|
|
case CFG_IOTHREADS: {
|
|
int mask = 0;
|
|
/* use a power of two */
|
|
while ( c->value_uint > 1 ) {
|
|
c->value_uint >>= 1;
|
|
mask <<= 1;
|
|
mask |= 1;
|
|
}
|
|
if ( !lloadd_inited ) {
|
|
lload_daemon_mask = mask;
|
|
lload_daemon_threads = mask + 1;
|
|
flag = LLOAD_DAEMON_MOD_THREADS;
|
|
} else {
|
|
snprintf( c->cr_msg, sizeof(c->cr_msg),
|
|
"io thread changes will not take effect until "
|
|
"restart" );
|
|
Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg );
|
|
}
|
|
} break;
|
|
|
|
case CFG_LOGFILE: {
|
|
if ( logfileName ) ch_free( logfileName );
|
|
logfileName = c->value_string;
|
|
logfile = fopen( logfileName, "w" );
|
|
if ( logfile ) lutil_debug_file( logfile );
|
|
} break;
|
|
|
|
case CFG_RESCOUNT:
|
|
lload_conn_max_pdus_per_cycle = c->value_uint;
|
|
break;
|
|
|
|
case CFG_IOTIMEOUT:
|
|
if ( c->value_uint > 0 ) {
|
|
timeout_write_tv.tv_sec = c->value_uint / 1000;
|
|
timeout_write_tv.tv_usec = 1000 * ( c->value_uint % 1000 );
|
|
lload_write_timeout = &timeout_write_tv;
|
|
} else {
|
|
lload_write_timeout = NULL;
|
|
}
|
|
break;
|
|
case CFG_MAXBUF_CLIENT:
|
|
sockbuf_max_incoming_client = c->value_uint;
|
|
break;
|
|
case CFG_MAXBUF_UPSTREAM:
|
|
sockbuf_max_incoming_upstream = c->value_uint;
|
|
break;
|
|
case CFG_CLIENT_PENDING:
|
|
lload_client_max_pending = c->value_uint;
|
|
break;
|
|
default:
|
|
Debug( LDAP_DEBUG_ANY, "%s: unknown CFG_TYPE %d\n",
|
|
c->log, c->type );
|
|
return 1;
|
|
}
|
|
|
|
lload_change.flags.daemon |= flag;
|
|
|
|
return 0;
|
|
|
|
fail:
|
|
if ( lload_change.type == LLOAD_CHANGE_ADD ) {
|
|
/* Abort the ADD */
|
|
lload_change.type = LLOAD_CHANGE_DEL;
|
|
}
|
|
|
|
Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg );
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
lload_backend_finish( ConfigArgs *ca )
|
|
{
|
|
LloadBackend *b = ca->ca_private;
|
|
|
|
if ( ca->reply.err != LDAP_SUCCESS ) {
|
|
/* Not reached since cleanup is only called on success */
|
|
goto fail;
|
|
}
|
|
|
|
if ( b->b_numconns <= 0 || b->b_numbindconns <= 0 ) {
|
|
Debug( LDAP_DEBUG_ANY, "lload_backend_finish: "
|
|
"invalid connection pool configuration\n" );
|
|
goto fail;
|
|
}
|
|
|
|
if ( b->b_retry_timeout < 0 ) {
|
|
Debug( LDAP_DEBUG_ANY, "lload_backend_finish: "
|
|
"invalid retry timeout configuration\n" );
|
|
goto fail;
|
|
}
|
|
|
|
b->b_retry_tv.tv_sec = b->b_retry_timeout / 1000;
|
|
b->b_retry_tv.tv_usec = ( b->b_retry_timeout % 1000 ) * 1000;
|
|
|
|
/* daemon_base is only allocated after initial configuration happens, those
|
|
* events are allocated on startup, we only deal with online Adds */
|
|
if ( !b->b_retry_event && daemon_base ) {
|
|
struct event *event;
|
|
assert( CONFIG_ONLINE_ADD( ca ) );
|
|
event = evtimer_new( daemon_base, backend_connect, b );
|
|
if ( !event ) {
|
|
Debug( LDAP_DEBUG_ANY, "lload_backend_finish: "
|
|
"failed to allocate retry event\n" );
|
|
goto fail;
|
|
}
|
|
b->b_retry_event = event;
|
|
}
|
|
|
|
return LDAP_SUCCESS;
|
|
|
|
fail:
|
|
if ( lload_change.type == LLOAD_CHANGE_ADD ) {
|
|
/* Abort the ADD */
|
|
lload_change.type = LLOAD_CHANGE_DEL;
|
|
}
|
|
|
|
lload_backend_destroy( b );
|
|
return -1;
|
|
}
|
|
|
|
static LloadBackend *
|
|
backend_alloc( void )
|
|
{
|
|
LloadBackend *b;
|
|
|
|
b = ch_calloc( 1, sizeof(LloadBackend) );
|
|
|
|
LDAP_CIRCLEQ_INIT( &b->b_conns );
|
|
LDAP_CIRCLEQ_INIT( &b->b_bindconns );
|
|
LDAP_CIRCLEQ_INIT( &b->b_preparing );
|
|
|
|
b->b_numconns = 1;
|
|
b->b_numbindconns = 1;
|
|
|
|
b->b_retry_timeout = 5000;
|
|
|
|
ldap_pvt_thread_mutex_init( &b->b_mutex );
|
|
|
|
LDAP_CIRCLEQ_INSERT_TAIL( &backend, b, b_next );
|
|
return b;
|
|
}
|
|
|
|
static int
|
|
backend_config_url( LloadBackend *b, struct berval *uri )
|
|
{
|
|
LDAPURLDesc *lud = NULL;
|
|
char *host = NULL;
|
|
int rc, proto, tls = b->b_tls_conf;
|
|
|
|
/* Effect no changes until we've checked everything */
|
|
|
|
rc = ldap_url_parse_ext( uri->bv_val, &lud, LDAP_PVT_URL_PARSE_DEF_PORT );
|
|
if ( rc != LDAP_URL_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_ANY, "backend_config_url: "
|
|
"listen URL \"%s\" parse error=%d\n",
|
|
uri->bv_val, rc );
|
|
return -1;
|
|
}
|
|
|
|
if ( ldap_pvt_url_scheme2tls( lud->lud_scheme ) ) {
|
|
#ifdef HAVE_TLS
|
|
/* Specifying ldaps:// overrides starttls= settings */
|
|
tls = LLOAD_LDAPS;
|
|
#else /* ! HAVE_TLS */
|
|
|
|
Debug( LDAP_DEBUG_ANY, "backend_config_url: "
|
|
"TLS not supported (%s)\n",
|
|
uri->bv_val );
|
|
rc = -1;
|
|
goto done;
|
|
#endif /* ! HAVE_TLS */
|
|
}
|
|
|
|
proto = ldap_pvt_url_scheme2proto( lud->lud_scheme );
|
|
if ( proto == LDAP_PROTO_IPC ) {
|
|
#ifdef LDAP_PF_LOCAL
|
|
if ( lud->lud_host == NULL || lud->lud_host[0] == '\0' ) {
|
|
host = LDAPI_SOCK;
|
|
}
|
|
#else /* ! LDAP_PF_LOCAL */
|
|
|
|
Debug( LDAP_DEBUG_ANY, "backend_config_url: "
|
|
"URL scheme not supported: %s",
|
|
url );
|
|
rc = -1;
|
|
goto done;
|
|
#endif /* ! LDAP_PF_LOCAL */
|
|
} else {
|
|
if ( lud->lud_host == NULL || lud->lud_host[0] == '\0' ) {
|
|
Debug( LDAP_DEBUG_ANY, "backend_config_url: "
|
|
"backend url missing hostname: '%s'\n",
|
|
uri->bv_val );
|
|
rc = -1;
|
|
goto done;
|
|
}
|
|
}
|
|
if ( !host ) {
|
|
host = lud->lud_host;
|
|
}
|
|
|
|
if ( b->b_host ) {
|
|
ch_free( b->b_host );
|
|
}
|
|
|
|
b->b_proto = proto;
|
|
b->b_tls = tls;
|
|
b->b_port = lud->lud_port;
|
|
b->b_host = ch_strdup( host );
|
|
|
|
done:
|
|
ldap_free_urldesc( lud );
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
config_backend( ConfigArgs *c )
|
|
{
|
|
LloadBackend *b;
|
|
int i, rc = 0;
|
|
|
|
b = backend_alloc();
|
|
|
|
for ( i = 1; i < c->argc; i++ ) {
|
|
if ( lload_backend_parse( c->argv[i], b ) ) {
|
|
Debug( LDAP_DEBUG_ANY, "config_backend: "
|
|
"error parsing backend configuration item '%s'\n",
|
|
c->argv[i] );
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if ( BER_BVISNULL( &b->b_uri ) ) {
|
|
Debug( LDAP_DEBUG_ANY, "config_backend: "
|
|
"backend address not specified\n" );
|
|
rc = -1;
|
|
goto done;
|
|
}
|
|
|
|
if ( backend_config_url( b, &b->b_uri ) ) {
|
|
rc = -1;
|
|
goto done;
|
|
}
|
|
|
|
c->ca_private = b;
|
|
rc = lload_backend_finish( c );
|
|
done:
|
|
if ( rc ) {
|
|
ch_free( b );
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
config_bindconf( ConfigArgs *c )
|
|
{
|
|
int i;
|
|
|
|
if ( c->op == SLAP_CONFIG_EMIT ) {
|
|
struct berval bv;
|
|
|
|
lload_bindconf_unparse( &bindconf, &bv );
|
|
|
|
for ( i = 0; isspace( (unsigned char)bv.bv_val[i] ); i++ )
|
|
/* count spaces */;
|
|
|
|
if ( i ) {
|
|
bv.bv_len -= i;
|
|
AC_MEMCPY( bv.bv_val, &bv.bv_val[i], bv.bv_len + 1 );
|
|
}
|
|
|
|
value_add_one( &c->rvalue_vals, &bv );
|
|
ber_memfree( bv.bv_val );
|
|
return LDAP_SUCCESS;
|
|
} else if ( c->op == LDAP_MOD_DELETE ) {
|
|
/* It's a MUST single-valued attribute, noop for now */
|
|
lload_bindconf_free( &bindconf );
|
|
return LDAP_SUCCESS;
|
|
}
|
|
|
|
lload_change.type = LLOAD_CHANGE_MODIFY;
|
|
lload_change.object = LLOAD_DAEMON;
|
|
lload_change.flags.daemon |= LLOAD_DAEMON_MOD_BINDCONF;
|
|
|
|
for ( i = 1; i < c->argc; i++ ) {
|
|
if ( lload_bindconf_parse( c->argv[i], &bindconf ) ) {
|
|
Debug( LDAP_DEBUG_ANY, "config_bindconf: "
|
|
"error parsing backend configuration item '%s'\n",
|
|
c->argv[i] );
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if ( bindconf.sb_method == LDAP_AUTH_SASL ) {
|
|
#ifndef HAVE_CYRUS_SASL
|
|
Debug( LDAP_DEBUG_ANY, "config_bindconf: "
|
|
"no sasl support available\n" );
|
|
return -1;
|
|
#endif
|
|
}
|
|
|
|
if ( !BER_BVISNULL( &bindconf.sb_authzId ) ) {
|
|
ber_dupbv( &lloadd_identity, &bindconf.sb_authzId );
|
|
} else if ( !BER_BVISNULL( &bindconf.sb_authcId ) ) {
|
|
ber_dupbv( &lloadd_identity, &bindconf.sb_authcId );
|
|
} else if ( !BER_BVISNULL( &bindconf.sb_binddn ) ) {
|
|
char *ptr;
|
|
|
|
lloadd_identity.bv_len = STRLENOF("dn:") + bindconf.sb_binddn.bv_len;
|
|
lloadd_identity.bv_val = ch_malloc( lloadd_identity.bv_len + 1 );
|
|
|
|
ptr = lutil_strcopy( lloadd_identity.bv_val, "dn:" );
|
|
ptr = lutil_strncopy(
|
|
ptr, bindconf.sb_binddn.bv_val, bindconf.sb_binddn.bv_len );
|
|
*ptr = '\0';
|
|
}
|
|
|
|
if ( bindconf.sb_timeout_api ) {
|
|
timeout_api_tv.tv_sec = bindconf.sb_timeout_api;
|
|
lload_timeout_api = &timeout_api_tv;
|
|
if ( lload_timeout_event ) {
|
|
event_add( lload_timeout_event, lload_timeout_api );
|
|
}
|
|
} else {
|
|
lload_timeout_api = NULL;
|
|
if ( lload_timeout_event ) {
|
|
event_del( lload_timeout_event );
|
|
}
|
|
}
|
|
|
|
if ( bindconf.sb_timeout_net ) {
|
|
timeout_net_tv.tv_sec = bindconf.sb_timeout_net;
|
|
lload_timeout_net = &timeout_net_tv;
|
|
} else {
|
|
lload_timeout_net = NULL;
|
|
}
|
|
|
|
#ifdef HAVE_TLS
|
|
if ( bindconf.sb_tls_do_init ) {
|
|
lload_bindconf_tls_set( &bindconf, lload_tls_backend_ld );
|
|
}
|
|
#endif /* HAVE_TLS */
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
config_fname( ConfigArgs *c )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* [listener=<listener>] [{read|write}=]<size>
|
|
*/
|
|
|
|
#ifdef LDAP_TCP_BUFFER
|
|
static BerVarray tcp_buffer;
|
|
int tcp_buffer_num;
|
|
|
|
#define SLAP_TCP_RMEM ( 0x1U )
|
|
#define SLAP_TCP_WMEM ( 0x2U )
|
|
|
|
static int
|
|
tcp_buffer_parse(
|
|
struct berval *val,
|
|
int argc,
|
|
char **argv,
|
|
int *size,
|
|
int *rw,
|
|
LloadListener **l )
|
|
{
|
|
int i, rc = LDAP_SUCCESS;
|
|
LDAPURLDesc *lud = NULL;
|
|
char *ptr;
|
|
|
|
if ( val != NULL && argv == NULL ) {
|
|
char *s = val->bv_val;
|
|
|
|
argv = ldap_str2charray( s, " \t" );
|
|
if ( argv == NULL ) {
|
|
return LDAP_OTHER;
|
|
}
|
|
}
|
|
|
|
i = 0;
|
|
if ( strncasecmp( argv[i], "listener=", STRLENOF("listener=") ) == 0 ) {
|
|
char *url = argv[i] + STRLENOF("listener=");
|
|
|
|
if ( ldap_url_parse_ext( url, &lud, LDAP_PVT_URL_PARSE_DEF_PORT ) ) {
|
|
rc = LDAP_INVALID_SYNTAX;
|
|
goto done;
|
|
}
|
|
|
|
*l = lload_config_check_my_url( url, lud );
|
|
if ( *l == NULL ) {
|
|
rc = LDAP_NO_SUCH_ATTRIBUTE;
|
|
goto done;
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
ptr = argv[i];
|
|
if ( strncasecmp( ptr, "read=", STRLENOF("read=") ) == 0 ) {
|
|
*rw |= SLAP_TCP_RMEM;
|
|
ptr += STRLENOF("read=");
|
|
|
|
} else if ( strncasecmp( ptr, "write=", STRLENOF("write=") ) == 0 ) {
|
|
*rw |= SLAP_TCP_WMEM;
|
|
ptr += STRLENOF("write=");
|
|
|
|
} else {
|
|
*rw |= ( SLAP_TCP_RMEM | SLAP_TCP_WMEM );
|
|
}
|
|
|
|
/* accept any base */
|
|
if ( lutil_atoix( size, ptr, 0 ) ) {
|
|
rc = LDAP_INVALID_SYNTAX;
|
|
goto done;
|
|
}
|
|
|
|
done:;
|
|
if ( val != NULL && argv != NULL ) {
|
|
ldap_charray_free( argv );
|
|
}
|
|
|
|
if ( lud != NULL ) {
|
|
ldap_free_urldesc( lud );
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
#ifdef BALANCER_MODULE
|
|
static int
|
|
tcp_buffer_delete_one( struct berval *val )
|
|
{
|
|
int rc = 0;
|
|
int size = -1, rw = 0;
|
|
LloadListener *l = NULL;
|
|
|
|
rc = tcp_buffer_parse( val, 0, NULL, &size, &rw, &l );
|
|
if ( rc != 0 ) {
|
|
return rc;
|
|
}
|
|
|
|
if ( l != NULL ) {
|
|
int i;
|
|
LloadListener **ll = lloadd_get_listeners();
|
|
|
|
for ( i = 0; ll[i] != NULL; i++ ) {
|
|
if ( ll[i] == l ) break;
|
|
}
|
|
|
|
if ( ll[i] == NULL ) {
|
|
return LDAP_NO_SUCH_ATTRIBUTE;
|
|
}
|
|
|
|
if ( rw & SLAP_TCP_RMEM ) l->sl_tcp_rmem = -1;
|
|
if ( rw & SLAP_TCP_WMEM ) l->sl_tcp_wmem = -1;
|
|
|
|
for ( i++; ll[i] != NULL && bvmatch( &l->sl_url, &ll[i]->sl_url );
|
|
i++ ) {
|
|
if ( rw & SLAP_TCP_RMEM ) ll[i]->sl_tcp_rmem = -1;
|
|
if ( rw & SLAP_TCP_WMEM ) ll[i]->sl_tcp_wmem = -1;
|
|
}
|
|
|
|
} else {
|
|
/* NOTE: this affects listeners without a specific setting,
|
|
* does not reset all listeners. If a listener without
|
|
* specific settings was assigned a buffer because of
|
|
* a global setting, it will not be reset. In any case,
|
|
* buffer changes will only take place at restart. */
|
|
if ( rw & SLAP_TCP_RMEM ) slapd_tcp_rmem = -1;
|
|
if ( rw & SLAP_TCP_WMEM ) slapd_tcp_wmem = -1;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
tcp_buffer_delete( BerVarray vals )
|
|
{
|
|
int i;
|
|
|
|
for ( i = 0; !BER_BVISNULL( &vals[i] ); i++ ) {
|
|
tcp_buffer_delete_one( &vals[i] );
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif /* BALANCER_MODULE */
|
|
|
|
static int
|
|
tcp_buffer_unparse( int size, int rw, LloadListener *l, struct berval *val )
|
|
{
|
|
char buf[sizeof("2147483648")], *ptr;
|
|
|
|
/* unparse for later use */
|
|
val->bv_len = snprintf( buf, sizeof(buf), "%d", size );
|
|
if ( l != NULL ) {
|
|
val->bv_len += STRLENOF( "listener="
|
|
" " ) +
|
|
l->sl_url.bv_len;
|
|
}
|
|
|
|
if ( rw != ( SLAP_TCP_RMEM | SLAP_TCP_WMEM ) ) {
|
|
if ( rw & SLAP_TCP_RMEM ) {
|
|
val->bv_len += STRLENOF("read=");
|
|
} else if ( rw & SLAP_TCP_WMEM ) {
|
|
val->bv_len += STRLENOF("write=");
|
|
}
|
|
}
|
|
|
|
val->bv_val = SLAP_MALLOC( val->bv_len + 1 );
|
|
|
|
ptr = val->bv_val;
|
|
|
|
if ( l != NULL ) {
|
|
ptr = lutil_strcopy( ptr, "listener=" );
|
|
ptr = lutil_strncopy( ptr, l->sl_url.bv_val, l->sl_url.bv_len );
|
|
*ptr++ = ' ';
|
|
}
|
|
|
|
if ( rw != ( SLAP_TCP_RMEM | SLAP_TCP_WMEM ) ) {
|
|
if ( rw & SLAP_TCP_RMEM ) {
|
|
ptr = lutil_strcopy( ptr, "read=" );
|
|
} else if ( rw & SLAP_TCP_WMEM ) {
|
|
ptr = lutil_strcopy( ptr, "write=" );
|
|
}
|
|
}
|
|
|
|
ptr = lutil_strcopy( ptr, buf );
|
|
*ptr = '\0';
|
|
|
|
assert( val->bv_val + val->bv_len == ptr );
|
|
|
|
return LDAP_SUCCESS;
|
|
}
|
|
|
|
static int
|
|
tcp_buffer_add_one( int argc, char **argv )
|
|
{
|
|
int rc = 0;
|
|
int size = -1, rw = 0;
|
|
LloadListener *l = NULL;
|
|
|
|
struct berval val;
|
|
|
|
/* parse */
|
|
rc = tcp_buffer_parse( NULL, argc, argv, &size, &rw, &l );
|
|
if ( rc != 0 ) {
|
|
return rc;
|
|
}
|
|
|
|
/* unparse for later use */
|
|
rc = tcp_buffer_unparse( size, rw, l, &val );
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
return rc;
|
|
}
|
|
|
|
/* use parsed values */
|
|
if ( l != NULL ) {
|
|
int i;
|
|
LloadListener **ll = lloadd_get_listeners();
|
|
|
|
for ( i = 0; ll[i] != NULL; i++ ) {
|
|
if ( ll[i] == l ) break;
|
|
}
|
|
|
|
if ( ll[i] == NULL ) {
|
|
return LDAP_NO_SUCH_ATTRIBUTE;
|
|
}
|
|
|
|
/* buffer only applies to TCP listeners;
|
|
* we do not do any check here, and delegate them
|
|
* to setsockopt(2) */
|
|
if ( rw & SLAP_TCP_RMEM ) l->sl_tcp_rmem = size;
|
|
if ( rw & SLAP_TCP_WMEM ) l->sl_tcp_wmem = size;
|
|
|
|
for ( i++; ll[i] != NULL && bvmatch( &l->sl_url, &ll[i]->sl_url );
|
|
i++ ) {
|
|
if ( rw & SLAP_TCP_RMEM ) ll[i]->sl_tcp_rmem = size;
|
|
if ( rw & SLAP_TCP_WMEM ) ll[i]->sl_tcp_wmem = size;
|
|
}
|
|
|
|
} else {
|
|
/* NOTE: this affects listeners without a specific setting,
|
|
* does not set all listeners */
|
|
if ( rw & SLAP_TCP_RMEM ) slapd_tcp_rmem = size;
|
|
if ( rw & SLAP_TCP_WMEM ) slapd_tcp_wmem = size;
|
|
}
|
|
|
|
tcp_buffer = SLAP_REALLOC(
|
|
tcp_buffer, sizeof(struct berval) * ( tcp_buffer_num + 2 ) );
|
|
/* append */
|
|
tcp_buffer[tcp_buffer_num] = val;
|
|
|
|
tcp_buffer_num++;
|
|
BER_BVZERO( &tcp_buffer[tcp_buffer_num] );
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
config_tcp_buffer( ConfigArgs *c )
|
|
{
|
|
int rc = LDAP_SUCCESS;
|
|
|
|
#ifdef BALANCER_MODULE
|
|
if ( c->op == SLAP_CONFIG_EMIT ) {
|
|
if ( tcp_buffer == NULL || BER_BVISNULL( &tcp_buffer[0] ) ) {
|
|
return 1;
|
|
}
|
|
value_add( &c->rvalue_vals, tcp_buffer );
|
|
value_add( &c->rvalue_nvals, tcp_buffer );
|
|
|
|
return 0;
|
|
} else if ( c->op == LDAP_MOD_DELETE ) {
|
|
if ( !c->line ) {
|
|
tcp_buffer_delete( tcp_buffer );
|
|
ber_bvarray_free( tcp_buffer );
|
|
tcp_buffer = NULL;
|
|
tcp_buffer_num = 0;
|
|
|
|
} else {
|
|
int size = -1, rw = 0;
|
|
LloadListener *l = NULL;
|
|
|
|
struct berval val = BER_BVNULL;
|
|
|
|
int i;
|
|
|
|
if ( tcp_buffer_num == 0 ) {
|
|
return 1;
|
|
}
|
|
|
|
/* parse */
|
|
rc = tcp_buffer_parse(
|
|
NULL, c->argc - 1, &c->argv[1], &size, &rw, &l );
|
|
if ( rc != 0 ) {
|
|
return 1;
|
|
}
|
|
|
|
/* unparse for later use */
|
|
rc = tcp_buffer_unparse( size, rw, l, &val );
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
return 1;
|
|
}
|
|
|
|
for ( i = 0; !BER_BVISNULL( &tcp_buffer[i] ); i++ ) {
|
|
if ( bvmatch( &tcp_buffer[i], &val ) ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( BER_BVISNULL( &tcp_buffer[i] ) ) {
|
|
/* not found */
|
|
rc = 1;
|
|
goto done;
|
|
}
|
|
|
|
tcp_buffer_delete_one( &tcp_buffer[i] );
|
|
ber_memfree( tcp_buffer[i].bv_val );
|
|
for ( ; i < tcp_buffer_num; i++ ) {
|
|
tcp_buffer[i] = tcp_buffer[i + 1];
|
|
}
|
|
tcp_buffer_num--;
|
|
|
|
done:;
|
|
if ( !BER_BVISNULL( &val ) ) {
|
|
SLAP_FREE(val.bv_val);
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
#endif /* BALANCER_MODULE */
|
|
|
|
rc = tcp_buffer_add_one( c->argc - 1, &c->argv[1] );
|
|
if ( rc ) {
|
|
snprintf( c->cr_msg, sizeof(c->cr_msg), "<%s> unable to add value #%d",
|
|
c->argv[0], tcp_buffer_num );
|
|
Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg );
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif /* LDAP_TCP_BUFFER */
|
|
|
|
static int
|
|
config_restrict( ConfigArgs *c )
|
|
{
|
|
slap_mask_t restrictops = 0;
|
|
int i;
|
|
slap_verbmasks restrictable_ops[] = {
|
|
{ BER_BVC("bind"), SLAP_RESTRICT_OP_BIND },
|
|
{ BER_BVC("add"), SLAP_RESTRICT_OP_ADD },
|
|
{ BER_BVC("modify"), SLAP_RESTRICT_OP_MODIFY },
|
|
{ BER_BVC("rename"), SLAP_RESTRICT_OP_RENAME },
|
|
{ BER_BVC("modrdn"), 0 },
|
|
{ BER_BVC("delete"), SLAP_RESTRICT_OP_DELETE },
|
|
{ BER_BVC("search"), SLAP_RESTRICT_OP_SEARCH },
|
|
{ BER_BVC("compare"), SLAP_RESTRICT_OP_COMPARE },
|
|
{ BER_BVC("read"), SLAP_RESTRICT_OP_READS },
|
|
{ BER_BVC("write"), SLAP_RESTRICT_OP_WRITES },
|
|
{ BER_BVC("extended"), SLAP_RESTRICT_OP_EXTENDED },
|
|
{ BER_BVC("extended=" LDAP_EXOP_START_TLS), SLAP_RESTRICT_EXOP_START_TLS },
|
|
{ BER_BVC("extended=" LDAP_EXOP_MODIFY_PASSWD), SLAP_RESTRICT_EXOP_MODIFY_PASSWD },
|
|
{ BER_BVC("extended=" LDAP_EXOP_X_WHO_AM_I), SLAP_RESTRICT_EXOP_WHOAMI },
|
|
{ BER_BVC("extended=" LDAP_EXOP_X_CANCEL), SLAP_RESTRICT_EXOP_CANCEL },
|
|
{ BER_BVC("all"), SLAP_RESTRICT_OP_ALL },
|
|
{ BER_BVNULL, 0 }
|
|
};
|
|
|
|
i = verbs_to_mask( c->argc, c->argv, restrictable_ops, &restrictops );
|
|
if ( i ) {
|
|
snprintf( c->cr_msg, sizeof(c->cr_msg), "<%s> unknown operation",
|
|
c->argv[0] );
|
|
Debug( LDAP_DEBUG_ANY, "%s: %s %s\n",
|
|
c->log, c->cr_msg, c->argv[i] );
|
|
return 1;
|
|
}
|
|
if ( restrictops & SLAP_RESTRICT_OP_EXTENDED )
|
|
restrictops &= ~SLAP_RESTRICT_EXOP_MASK;
|
|
return 0;
|
|
}
|
|
|
|
static slap_verbmasks *loglevel_ops;
|
|
|
|
static int
|
|
loglevel_init( void )
|
|
{
|
|
slap_verbmasks lo[] = {
|
|
{ BER_BVC("Any"), (slap_mask_t)LDAP_DEBUG_ANY },
|
|
{ BER_BVC("Trace"), LDAP_DEBUG_TRACE },
|
|
{ BER_BVC("Packets"), LDAP_DEBUG_PACKETS },
|
|
{ BER_BVC("Args"), LDAP_DEBUG_ARGS },
|
|
{ BER_BVC("Conns"), LDAP_DEBUG_CONNS },
|
|
{ BER_BVC("BER"), LDAP_DEBUG_BER },
|
|
{ BER_BVC("Filter"), LDAP_DEBUG_FILTER },
|
|
{ BER_BVC("Config"), LDAP_DEBUG_CONFIG },
|
|
{ BER_BVC("ACL"), LDAP_DEBUG_ACL },
|
|
{ BER_BVC("Stats"), LDAP_DEBUG_STATS },
|
|
{ BER_BVC("Stats2"), LDAP_DEBUG_STATS2 },
|
|
{ BER_BVC("Shell"), LDAP_DEBUG_SHELL },
|
|
{ BER_BVC("Parse"), LDAP_DEBUG_PARSE },
|
|
{ BER_BVC("Sync"), LDAP_DEBUG_SYNC },
|
|
{ BER_BVC("None"), LDAP_DEBUG_NONE },
|
|
{ BER_BVNULL, 0 }
|
|
};
|
|
|
|
return slap_verbmasks_init( &loglevel_ops, lo );
|
|
}
|
|
|
|
static void
|
|
loglevel_destroy( void )
|
|
{
|
|
if ( loglevel_ops ) {
|
|
(void)slap_verbmasks_destroy( loglevel_ops );
|
|
}
|
|
loglevel_ops = NULL;
|
|
}
|
|
|
|
int
|
|
str2loglevel( const char *s, int *l )
|
|
{
|
|
int i;
|
|
|
|
if ( loglevel_ops == NULL ) {
|
|
loglevel_init();
|
|
}
|
|
|
|
i = verb_to_mask( s, loglevel_ops );
|
|
|
|
if ( BER_BVISNULL( &loglevel_ops[i].word ) ) {
|
|
return -1;
|
|
}
|
|
|
|
*l = loglevel_ops[i].mask;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
loglevel2bvarray( int l, BerVarray *bva )
|
|
{
|
|
if ( loglevel_ops == NULL ) {
|
|
loglevel_init();
|
|
}
|
|
|
|
if ( l == 0 ) {
|
|
struct berval bv = BER_BVC("0");
|
|
return value_add_one( bva, &bv );
|
|
}
|
|
|
|
return mask_to_verbs( loglevel_ops, l, bva );
|
|
}
|
|
|
|
int
|
|
loglevel_print( FILE *out )
|
|
{
|
|
int i;
|
|
|
|
if ( loglevel_ops == NULL ) {
|
|
loglevel_init();
|
|
}
|
|
|
|
fprintf( out, "Installed log subsystems:\n\n" );
|
|
for ( i = 0; !BER_BVISNULL( &loglevel_ops[i].word ); i++ ) {
|
|
unsigned mask = loglevel_ops[i].mask & 0xffffffffUL;
|
|
fprintf( out,
|
|
( mask == ( (slap_mask_t)-1 & 0xffffffffUL ) ?
|
|
"\t%-30s (-1, 0xffffffff)\n" :
|
|
"\t%-30s (%u, 0x%x)\n" ),
|
|
loglevel_ops[i].word.bv_val, mask, mask );
|
|
}
|
|
|
|
fprintf( out,
|
|
"\nNOTE: custom log subsystems may be later installed "
|
|
"by specific code\n\n" );
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int config_syslog;
|
|
|
|
static int
|
|
config_loglevel( ConfigArgs *c )
|
|
{
|
|
int i;
|
|
|
|
if ( loglevel_ops == NULL ) {
|
|
loglevel_init();
|
|
}
|
|
|
|
if ( c->op == SLAP_CONFIG_EMIT ) {
|
|
/* Get default or commandline slapd setting */
|
|
if ( ldap_syslog && !config_syslog ) config_syslog = ldap_syslog;
|
|
return loglevel2bvarray( config_syslog, &c->rvalue_vals );
|
|
|
|
} else if ( c->op == LDAP_MOD_DELETE ) {
|
|
if ( !c->line ) {
|
|
config_syslog = 0;
|
|
} else {
|
|
i = verb_to_mask( c->line, loglevel_ops );
|
|
config_syslog &= ~loglevel_ops[i].mask;
|
|
}
|
|
if ( slapMode & SLAP_SERVER_MODE ) {
|
|
ldap_syslog = config_syslog;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
for ( i = 1; i < c->argc; i++ ) {
|
|
int level;
|
|
|
|
if ( isdigit( (unsigned char)c->argv[i][0] ) || c->argv[i][0] == '-' ) {
|
|
if ( lutil_atoix( &level, c->argv[i], 0 ) != 0 ) {
|
|
snprintf( c->cr_msg, sizeof(c->cr_msg),
|
|
"<%s> unable to parse level",
|
|
c->argv[0] );
|
|
Debug( LDAP_DEBUG_ANY, "%s: %s \"%s\"\n",
|
|
c->log, c->cr_msg, c->argv[i] );
|
|
return 1;
|
|
}
|
|
} else {
|
|
if ( str2loglevel( c->argv[i], &level ) ) {
|
|
snprintf( c->cr_msg, sizeof(c->cr_msg), "<%s> unknown level",
|
|
c->argv[0] );
|
|
Debug( LDAP_DEBUG_ANY, "%s: %s \"%s\"\n",
|
|
c->log, c->cr_msg, c->argv[i] );
|
|
return 1;
|
|
}
|
|
}
|
|
/* Explicitly setting a zero clears all the levels */
|
|
if ( level )
|
|
config_syslog |= level;
|
|
else
|
|
config_syslog = 0;
|
|
}
|
|
if ( slapMode & SLAP_SERVER_MODE ) {
|
|
ldap_syslog = config_syslog;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
config_include( ConfigArgs *c )
|
|
{
|
|
int savelineno = c->lineno;
|
|
int rc;
|
|
ConfigFile *cf;
|
|
ConfigFile *cfsave = cfn;
|
|
ConfigFile *cf2 = NULL;
|
|
|
|
/* Leftover from RE23. No dynamic config for include files */
|
|
if ( c->op == SLAP_CONFIG_EMIT || c->op == LDAP_MOD_DELETE ) return 1;
|
|
|
|
cf = ch_calloc( 1, sizeof(ConfigFile) );
|
|
if ( cfn->c_kids ) {
|
|
for ( cf2 = cfn->c_kids; cf2 && cf2->c_sibs; cf2 = cf2->c_sibs )
|
|
/* empty */;
|
|
cf2->c_sibs = cf;
|
|
} else {
|
|
cfn->c_kids = cf;
|
|
}
|
|
cfn = cf;
|
|
ber_str2bv( c->argv[1], 0, 1, &cf->c_file );
|
|
rc = lload_read_config_file(
|
|
c->argv[1], c->depth + 1, c, config_back_cf_table );
|
|
c->lineno = savelineno - 1;
|
|
cfn = cfsave;
|
|
if ( rc ) {
|
|
if ( cf2 )
|
|
cf2->c_sibs = NULL;
|
|
else
|
|
cfn->c_kids = NULL;
|
|
ch_free( cf->c_file.bv_val );
|
|
ch_free( cf );
|
|
} else {
|
|
c->ca_private = cf;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
config_feature( ConfigArgs *c )
|
|
{
|
|
slap_verbmasks features[] = {
|
|
#ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS
|
|
{ BER_BVC("vc"), LLOAD_FEATURE_VC },
|
|
#endif /* LDAP_API_FEATURE_VERIFY_CREDENTIALS */
|
|
{ BER_BVC("proxyauthz"), LLOAD_FEATURE_PROXYAUTHZ },
|
|
{ BER_BVC("read_pause"), LLOAD_FEATURE_PAUSE },
|
|
{ BER_BVNULL, 0 }
|
|
};
|
|
slap_mask_t mask = 0;
|
|
int i;
|
|
|
|
if ( c->op == SLAP_CONFIG_EMIT ) {
|
|
return mask_to_verbs( features, lload_features, &c->rvalue_vals );
|
|
}
|
|
|
|
lload_change.type = LLOAD_CHANGE_MODIFY;
|
|
lload_change.object = LLOAD_DAEMON;
|
|
lload_change.flags.daemon |= LLOAD_DAEMON_MOD_FEATURES;
|
|
if ( !lload_change.target ) {
|
|
lload_change.target = (void *)(uintptr_t)~lload_features;
|
|
}
|
|
|
|
if ( c->op == LDAP_MOD_DELETE ) {
|
|
if ( !c->line ) {
|
|
/* Last value has been deleted */
|
|
lload_features = 0;
|
|
} else {
|
|
i = verb_to_mask( c->line, features );
|
|
lload_features &= ~features[i].mask;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
i = verbs_to_mask( c->argc, c->argv, features, &mask );
|
|
if ( i ) {
|
|
Debug( LDAP_DEBUG_ANY, "%s: <%s> unknown feature %s\n", c->log,
|
|
c->argv[0], c->argv[i] );
|
|
return 1;
|
|
}
|
|
lload_features |= mask;
|
|
return 0;
|
|
}
|
|
|
|
#ifdef HAVE_TLS
|
|
static int
|
|
config_tls_cleanup( ConfigArgs *c )
|
|
{
|
|
int rc = 0;
|
|
|
|
if ( lload_tls_ld ) {
|
|
int opt = 1;
|
|
|
|
ldap_pvt_tls_ctx_free( lload_tls_ctx );
|
|
lload_tls_ctx = NULL;
|
|
|
|
/* Force new ctx to be created */
|
|
rc = ldap_pvt_tls_set_option(
|
|
lload_tls_ld, LDAP_OPT_X_TLS_NEWCTX, &opt );
|
|
if ( rc == 0 ) {
|
|
/* The ctx's refcount is bumped up here */
|
|
ldap_pvt_tls_get_option(
|
|
lload_tls_ld, LDAP_OPT_X_TLS_CTX, &lload_tls_ctx );
|
|
} else {
|
|
if ( rc == LDAP_NOT_SUPPORTED )
|
|
rc = LDAP_UNWILLING_TO_PERFORM;
|
|
else
|
|
rc = LDAP_OTHER;
|
|
}
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
config_tls_option( ConfigArgs *c )
|
|
{
|
|
int flag;
|
|
int berval = 0;
|
|
LDAP *ld = lload_tls_ld;
|
|
|
|
switch ( c->type ) {
|
|
case CFG_TLS_RAND:
|
|
flag = LDAP_OPT_X_TLS_RANDOM_FILE;
|
|
ld = NULL;
|
|
break;
|
|
case CFG_TLS_CIPHER:
|
|
flag = LDAP_OPT_X_TLS_CIPHER_SUITE;
|
|
break;
|
|
case CFG_TLS_CERT_FILE:
|
|
flag = LDAP_OPT_X_TLS_CERTFILE;
|
|
break;
|
|
case CFG_TLS_CERT_KEY:
|
|
flag = LDAP_OPT_X_TLS_KEYFILE;
|
|
break;
|
|
case CFG_TLS_CA_PATH:
|
|
flag = LDAP_OPT_X_TLS_CACERTDIR;
|
|
break;
|
|
case CFG_TLS_CA_FILE:
|
|
flag = LDAP_OPT_X_TLS_CACERTFILE;
|
|
break;
|
|
case CFG_TLS_DH_FILE:
|
|
flag = LDAP_OPT_X_TLS_DHFILE;
|
|
break;
|
|
case CFG_TLS_ECNAME:
|
|
flag = LDAP_OPT_X_TLS_ECNAME;
|
|
break;
|
|
#ifdef HAVE_GNUTLS
|
|
case CFG_TLS_CRL_FILE:
|
|
flag = LDAP_OPT_X_TLS_CRLFILE;
|
|
break;
|
|
#endif
|
|
case CFG_TLS_CACERT:
|
|
flag = LDAP_OPT_X_TLS_CACERT;
|
|
berval = 1;
|
|
break;
|
|
case CFG_TLS_CERT:
|
|
flag = LDAP_OPT_X_TLS_CERT;
|
|
berval = 1;
|
|
break;
|
|
case CFG_TLS_KEY:
|
|
flag = LDAP_OPT_X_TLS_KEY;
|
|
berval = 1;
|
|
break;
|
|
default:
|
|
Debug( LDAP_DEBUG_ANY, "%s: "
|
|
"unknown tls_option <0x%x>\n",
|
|
c->log, c->type );
|
|
return 1;
|
|
}
|
|
if ( c->op == SLAP_CONFIG_EMIT ) {
|
|
return ldap_pvt_tls_get_option( ld, flag,
|
|
berval ? (void *)&c->value_bv : (void *)&c->value_string );
|
|
}
|
|
|
|
lload_change.type = LLOAD_CHANGE_MODIFY;
|
|
lload_change.object = LLOAD_DAEMON;
|
|
lload_change.flags.daemon |= LLOAD_DAEMON_MOD_TLS;
|
|
|
|
config_push_cleanup( c, config_tls_cleanup );
|
|
if ( c->op == LDAP_MOD_DELETE ) {
|
|
return ldap_pvt_tls_set_option( ld, flag, NULL );
|
|
}
|
|
if ( !berval ) ch_free( c->value_string );
|
|
return ldap_pvt_tls_set_option(
|
|
ld, flag, berval ? (void *)&c->value_bv : (void *)c->argv[1] );
|
|
}
|
|
|
|
/* FIXME: this ought to be provided by libldap */
|
|
static int
|
|
config_tls_config( ConfigArgs *c )
|
|
{
|
|
int i, flag;
|
|
|
|
switch ( c->type ) {
|
|
case CFG_TLS_CRLCHECK:
|
|
flag = LDAP_OPT_X_TLS_CRLCHECK;
|
|
break;
|
|
case CFG_TLS_VERIFY:
|
|
flag = LDAP_OPT_X_TLS_REQUIRE_CERT;
|
|
break;
|
|
case CFG_TLS_PROTOCOL_MIN:
|
|
flag = LDAP_OPT_X_TLS_PROTOCOL_MIN;
|
|
break;
|
|
default:
|
|
Debug( LDAP_DEBUG_ANY, "%s: "
|
|
"unknown tls_option <0x%x>\n",
|
|
c->log, c->type );
|
|
return 1;
|
|
}
|
|
if ( c->op == SLAP_CONFIG_EMIT ) {
|
|
return lload_tls_get_config( lload_tls_ld, flag, &c->value_string );
|
|
}
|
|
|
|
lload_change.type = LLOAD_CHANGE_MODIFY;
|
|
lload_change.object = LLOAD_DAEMON;
|
|
lload_change.flags.daemon |= LLOAD_DAEMON_MOD_TLS;
|
|
|
|
config_push_cleanup( c, config_tls_cleanup );
|
|
if ( c->op == LDAP_MOD_DELETE ) {
|
|
int i = 0;
|
|
return ldap_pvt_tls_set_option( lload_tls_ld, flag, &i );
|
|
}
|
|
ch_free( c->value_string );
|
|
if ( isdigit( (unsigned char)c->argv[1][0] ) &&
|
|
c->type != CFG_TLS_PROTOCOL_MIN ) {
|
|
if ( lutil_atoi( &i, c->argv[1] ) != 0 ) {
|
|
Debug( LDAP_DEBUG_ANY, "%s: "
|
|
"unable to parse %s \"%s\"\n",
|
|
c->log, c->argv[0], c->argv[1] );
|
|
return 1;
|
|
}
|
|
return ldap_pvt_tls_set_option( lload_tls_ld, flag, &i );
|
|
} else {
|
|
return ldap_pvt_tls_config( lload_tls_ld, flag, c->argv[1] );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef BALANCER_MODULE
|
|
static int
|
|
config_share_tls_ctx( ConfigArgs *c )
|
|
{
|
|
int rc = LDAP_SUCCESS;
|
|
|
|
if ( c->op == SLAP_CONFIG_EMIT ) {
|
|
c->value_int = lload_use_slap_tls_ctx;
|
|
return rc;
|
|
}
|
|
|
|
lload_change.type = LLOAD_CHANGE_MODIFY;
|
|
lload_change.object = LLOAD_DAEMON;
|
|
lload_change.flags.daemon |= LLOAD_DAEMON_MOD_TLS;
|
|
|
|
if ( c->op == LDAP_MOD_DELETE ) {
|
|
lload_use_slap_tls_ctx = 0;
|
|
return rc;
|
|
}
|
|
|
|
lload_use_slap_tls_ctx = c->value_int;
|
|
return rc;
|
|
}
|
|
#endif /* BALANCER_MODULE */
|
|
|
|
void
|
|
lload_init_config_argv( ConfigArgs *c )
|
|
{
|
|
c->argv = ch_calloc( ARGS_STEP + 1, sizeof(*c->argv) );
|
|
c->argv_size = ARGS_STEP + 1;
|
|
}
|
|
|
|
ConfigTable *
|
|
lload_config_find_keyword( ConfigTable *Conf, ConfigArgs *c )
|
|
{
|
|
int i;
|
|
|
|
for ( i = 0; Conf[i].name; i++ )
|
|
if ( ( Conf[i].length &&
|
|
( !strncasecmp(
|
|
c->argv[0], Conf[i].name, Conf[i].length ) ) ) ||
|
|
( !strcasecmp( c->argv[0], Conf[i].name ) ) )
|
|
break;
|
|
if ( !Conf[i].name ) return NULL;
|
|
if ( (Conf[i].arg_type & ARGS_TYPES) == ARG_BINARY ) {
|
|
size_t decode_len = LUTIL_BASE64_DECODE_LEN( c->linelen );
|
|
ch_free( c->tline );
|
|
c->tline = ch_malloc( decode_len + 1 );
|
|
c->linelen = lutil_b64_pton( c->line, c->tline, decode_len );
|
|
if ( c->linelen < 0 ) {
|
|
ch_free( c->tline );
|
|
c->tline = NULL;
|
|
return NULL;
|
|
}
|
|
c->line = c->tline;
|
|
}
|
|
return Conf + i;
|
|
}
|
|
|
|
int
|
|
lload_config_check_vals( ConfigTable *Conf, ConfigArgs *c, int check_only )
|
|
{
|
|
int arg_user, arg_type, arg_syn, iarg;
|
|
unsigned uiarg;
|
|
long larg;
|
|
unsigned long ularg;
|
|
ber_len_t barg;
|
|
|
|
if ( Conf->arg_type == ARG_IGNORED ) {
|
|
Debug( LDAP_DEBUG_CONFIG, "%s: keyword <%s> ignored\n",
|
|
c->log, Conf->name );
|
|
return 0;
|
|
}
|
|
arg_type = Conf->arg_type & ARGS_TYPES;
|
|
arg_user = Conf->arg_type & ARGS_USERLAND;
|
|
arg_syn = Conf->arg_type & ARGS_SYNTAX;
|
|
|
|
if ( Conf->min_args && ( c->argc < Conf->min_args ) ) {
|
|
snprintf( c->cr_msg, sizeof(c->cr_msg), "<%s> missing <%s> argument",
|
|
c->argv[0], Conf->what ? Conf->what : "" );
|
|
Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: keyword %s\n",
|
|
c->log, c->cr_msg );
|
|
return ARG_BAD_CONF;
|
|
}
|
|
if ( Conf->max_args && ( c->argc > Conf->max_args ) ) {
|
|
char *ignored = " ignored";
|
|
|
|
snprintf( c->cr_msg, sizeof(c->cr_msg), "<%s> extra cruft after <%s>",
|
|
c->argv[0], Conf->what );
|
|
|
|
ignored = "";
|
|
Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s%s\n",
|
|
c->log, c->cr_msg, ignored );
|
|
return ARG_BAD_CONF;
|
|
}
|
|
if ( (arg_syn & ARG_PAREN) && *c->argv[1] != '(' /*')'*/ ) {
|
|
snprintf( c->cr_msg, sizeof(c->cr_msg), "<%s> old format not supported",
|
|
c->argv[0] );
|
|
Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n",
|
|
c->log, c->cr_msg );
|
|
return ARG_BAD_CONF;
|
|
}
|
|
if ( arg_type && !Conf->arg_item && !(arg_syn & ARG_OFFSET) ) {
|
|
snprintf( c->cr_msg, sizeof(c->cr_msg),
|
|
"<%s> invalid config_table, arg_item is NULL",
|
|
c->argv[0] );
|
|
Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n",
|
|
c->log, c->cr_msg );
|
|
return ARG_BAD_CONF;
|
|
}
|
|
c->type = arg_user;
|
|
memset( &c->values, 0, sizeof(c->values) );
|
|
if ( arg_type == ARG_STRING ) {
|
|
assert( c->argc == 2 );
|
|
if ( !check_only ) c->value_string = ch_strdup( c->argv[1] );
|
|
} else if ( arg_type == ARG_BERVAL ) {
|
|
assert( c->argc == 2 );
|
|
if ( !check_only ) ber_str2bv( c->argv[1], 0, 1, &c->value_bv );
|
|
} else if ( arg_type == ARG_BINARY ) {
|
|
assert( c->argc == 2 );
|
|
if ( !check_only ) {
|
|
c->value_bv.bv_len = c->linelen;
|
|
c->value_bv.bv_val = ch_malloc( c->linelen );
|
|
AC_MEMCPY( c->value_bv.bv_val, c->line, c->linelen );
|
|
}
|
|
} else { /* all numeric */
|
|
int j;
|
|
iarg = 0;
|
|
larg = 0;
|
|
barg = 0;
|
|
switch ( arg_type ) {
|
|
case ARG_INT:
|
|
assert( c->argc == 2 );
|
|
if ( lutil_atoix( &iarg, c->argv[1], 0 ) != 0 ) {
|
|
snprintf( c->cr_msg, sizeof(c->cr_msg),
|
|
"<%s> unable to parse \"%s\" as int",
|
|
c->argv[0], c->argv[1] );
|
|
Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n",
|
|
c->log, c->cr_msg );
|
|
return ARG_BAD_CONF;
|
|
}
|
|
break;
|
|
case ARG_UINT:
|
|
assert( c->argc == 2 );
|
|
if ( lutil_atoux( &uiarg, c->argv[1], 0 ) != 0 ) {
|
|
snprintf( c->cr_msg, sizeof(c->cr_msg),
|
|
"<%s> unable to parse \"%s\" as unsigned int",
|
|
c->argv[0], c->argv[1] );
|
|
Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n",
|
|
c->log, c->cr_msg );
|
|
return ARG_BAD_CONF;
|
|
}
|
|
break;
|
|
case ARG_LONG:
|
|
assert( c->argc == 2 );
|
|
if ( lutil_atolx( &larg, c->argv[1], 0 ) != 0 ) {
|
|
snprintf( c->cr_msg, sizeof(c->cr_msg),
|
|
"<%s> unable to parse \"%s\" as long",
|
|
c->argv[0], c->argv[1] );
|
|
Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n",
|
|
c->log, c->cr_msg );
|
|
return ARG_BAD_CONF;
|
|
}
|
|
break;
|
|
case ARG_ULONG:
|
|
assert( c->argc == 2 );
|
|
if ( LUTIL_ATOULX( &ularg, c->argv[1], 0 ) != 0 ) {
|
|
snprintf( c->cr_msg, sizeof(c->cr_msg),
|
|
"<%s> unable to parse \"%s\" as unsigned long",
|
|
c->argv[0], c->argv[1] );
|
|
Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n",
|
|
c->log, c->cr_msg );
|
|
return ARG_BAD_CONF;
|
|
}
|
|
break;
|
|
case ARG_BER_LEN_T: {
|
|
unsigned long l;
|
|
assert( c->argc == 2 );
|
|
if ( lutil_atoulx( &l, c->argv[1], 0 ) != 0 ) {
|
|
snprintf( c->cr_msg, sizeof(c->cr_msg),
|
|
"<%s> unable to parse \"%s\" as ber_len_t",
|
|
c->argv[0], c->argv[1] );
|
|
Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "%s: %s\n",
|
|
c->log, c->cr_msg );
|
|
return ARG_BAD_CONF;
|
|
}
|
|
barg = (ber_len_t)l;
|
|
} break;
|
|
case ARG_ON_OFF:
|
|
/* note: this is an explicit exception
|
|
* to the "need exactly 2 args" rule */
|
|
if ( c->argc == 1 ) {
|
|
iarg = 1;
|
|
} else if ( !strcasecmp( c->argv[1], "on" ) ||
|
|
!strcasecmp( c->argv[1], "true" ) ||
|
|
!strcasecmp( c->argv[1], "yes" ) ) {
|
|
iarg = 1;
|
|
} else if ( !strcasecmp( c->argv[1], "off" ) ||
|
|
!strcasecmp( c->argv[1], "false" ) ||
|
|
!strcasecmp( c->argv[1], "no" ) ) {
|
|
iarg = 0;
|
|
} else {
|
|
snprintf( c->cr_msg, sizeof(c->cr_msg),
|
|
"<%s> invalid value",
|
|
c->argv[0] );
|
|
Debug( LDAP_DEBUG_ANY|LDAP_DEBUG_NONE, "%s: %s\n",
|
|
c->log, c->cr_msg );
|
|
return ARG_BAD_CONF;
|
|
}
|
|
break;
|
|
}
|
|
j = (arg_type & ARG_NONZERO) ? 1 : 0;
|
|
if ( iarg < j && larg < j && barg < (unsigned)j ) {
|
|
larg = larg ? larg : ( barg ? (long)barg : iarg );
|
|
snprintf( c->cr_msg, sizeof(c->cr_msg), "<%s> invalid value",
|
|
c->argv[0] );
|
|
Debug( LDAP_DEBUG_ANY|LDAP_DEBUG_NONE, "%s: %s\n",
|
|
c->log, c->cr_msg );
|
|
return ARG_BAD_CONF;
|
|
}
|
|
switch ( arg_type ) {
|
|
case ARG_ON_OFF:
|
|
case ARG_INT:
|
|
c->value_int = iarg;
|
|
break;
|
|
case ARG_UINT:
|
|
c->value_uint = uiarg;
|
|
break;
|
|
case ARG_LONG:
|
|
c->value_long = larg;
|
|
break;
|
|
case ARG_ULONG:
|
|
c->value_ulong = ularg;
|
|
break;
|
|
case ARG_BER_LEN_T:
|
|
c->value_ber_t = barg;
|
|
break;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
lload_config_set_vals( ConfigTable *Conf, ConfigArgs *c )
|
|
{
|
|
int rc, arg_type;
|
|
void *ptr = NULL;
|
|
|
|
arg_type = Conf->arg_type;
|
|
if ( arg_type & ARG_MAGIC ) {
|
|
c->cr_msg[0] = '\0';
|
|
rc = ( *( (ConfigDriver *)Conf->arg_item ) )( c );
|
|
if ( rc ) {
|
|
if ( !c->cr_msg[0] ) {
|
|
snprintf( c->cr_msg, sizeof(c->cr_msg),
|
|
"<%s> handler exited with %d",
|
|
c->argv[0], rc );
|
|
Debug( LDAP_DEBUG_CONFIG, "%s: %s!\n", c->log, c->cr_msg );
|
|
}
|
|
return ARG_BAD_CONF;
|
|
}
|
|
return 0;
|
|
}
|
|
if ( arg_type & ARG_OFFSET ) {
|
|
{
|
|
snprintf( c->cr_msg, sizeof(c->cr_msg),
|
|
"<%s> offset is missing base pointer",
|
|
c->argv[0] );
|
|
Debug( LDAP_DEBUG_CONFIG, "%s: %s!\n", c->log, c->cr_msg );
|
|
return ARG_BAD_CONF;
|
|
}
|
|
ptr = (void *)( (char *)ptr + (long)Conf->arg_item );
|
|
} else if ( arg_type & ARGS_TYPES ) {
|
|
ptr = Conf->arg_item;
|
|
}
|
|
if ( arg_type & ARGS_TYPES ) switch ( arg_type & ARGS_TYPES ) {
|
|
case ARG_ON_OFF:
|
|
case ARG_INT:
|
|
*(int *)ptr = c->value_int;
|
|
break;
|
|
case ARG_UINT:
|
|
*(unsigned *)ptr = c->value_uint;
|
|
break;
|
|
case ARG_LONG:
|
|
*(long *)ptr = c->value_long;
|
|
break;
|
|
case ARG_ULONG:
|
|
*(size_t *)ptr = c->value_ulong;
|
|
break;
|
|
case ARG_BER_LEN_T:
|
|
*(ber_len_t *)ptr = c->value_ber_t;
|
|
break;
|
|
case ARG_STRING: {
|
|
char *cc = *(char **)ptr;
|
|
if ( cc ) {
|
|
if ( (arg_type & ARG_UNIQUE) &&
|
|
c->op == SLAP_CONFIG_ADD ) {
|
|
Debug( LDAP_DEBUG_CONFIG, "%s: already set %s!\n",
|
|
c->log, Conf->name );
|
|
return ARG_BAD_CONF;
|
|
}
|
|
ch_free( cc );
|
|
}
|
|
*(char **)ptr = c->value_string;
|
|
break;
|
|
}
|
|
case ARG_BERVAL:
|
|
case ARG_BINARY:
|
|
*(struct berval *)ptr = c->value_bv;
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
lload_config_add_vals( ConfigTable *Conf, ConfigArgs *c )
|
|
{
|
|
int rc, arg_type;
|
|
|
|
arg_type = Conf->arg_type;
|
|
if ( arg_type == ARG_IGNORED ) {
|
|
Debug( LDAP_DEBUG_CONFIG, "%s: keyword <%s> ignored\n",
|
|
c->log, Conf->name );
|
|
return 0;
|
|
}
|
|
rc = lload_config_check_vals( Conf, c, 0 );
|
|
if ( rc ) return rc;
|
|
return lload_config_set_vals( Conf, c );
|
|
}
|
|
|
|
int
|
|
lload_read_config_file(
|
|
const char *fname,
|
|
int depth,
|
|
ConfigArgs *cf,
|
|
ConfigTable *cft )
|
|
{
|
|
FILE *fp;
|
|
ConfigTable *ct;
|
|
ConfigArgs *c;
|
|
int rc;
|
|
struct stat s;
|
|
|
|
c = ch_calloc( 1, sizeof(ConfigArgs) );
|
|
if ( c == NULL ) {
|
|
return 1;
|
|
}
|
|
|
|
if ( depth ) {
|
|
memcpy( c, cf, sizeof(ConfigArgs) );
|
|
} else {
|
|
c->depth = depth; /* XXX */
|
|
}
|
|
|
|
c->valx = -1;
|
|
c->fname = fname;
|
|
lload_init_config_argv( c );
|
|
|
|
if ( stat( fname, &s ) != 0 ) {
|
|
char ebuf[128];
|
|
int saved_errno = errno;
|
|
ldap_syslog = 1;
|
|
Debug( LDAP_DEBUG_ANY, "could not stat config file \"%s\": %s (%d)\n",
|
|
fname, AC_STRERROR_R( saved_errno, ebuf, sizeof(ebuf) ),
|
|
saved_errno );
|
|
ch_free( c->argv );
|
|
ch_free( c );
|
|
return 1;
|
|
}
|
|
|
|
if ( !S_ISREG(s.st_mode) ) {
|
|
ldap_syslog = 1;
|
|
Debug( LDAP_DEBUG_ANY, "regular file expected, got \"%s\"\n", fname );
|
|
ch_free( c->argv );
|
|
ch_free( c );
|
|
return 1;
|
|
}
|
|
|
|
fp = fopen( fname, "r" );
|
|
if ( fp == NULL ) {
|
|
char ebuf[128];
|
|
int saved_errno = errno;
|
|
ldap_syslog = 1;
|
|
Debug( LDAP_DEBUG_ANY, "could not open config file \"%s\": %s (%d)\n",
|
|
fname, AC_STRERROR_R( saved_errno, ebuf, sizeof(ebuf) ),
|
|
saved_errno );
|
|
ch_free( c->argv );
|
|
ch_free( c );
|
|
return 1;
|
|
}
|
|
|
|
Debug( LDAP_DEBUG_CONFIG, "reading config file %s\n", fname );
|
|
|
|
fp_getline_init( c );
|
|
|
|
c->tline = NULL;
|
|
|
|
while ( fp_getline( fp, c ) ) {
|
|
/* skip comments and blank lines */
|
|
if ( c->line[0] == '#' || c->line[0] == '\0' ) {
|
|
continue;
|
|
}
|
|
|
|
snprintf( c->log, sizeof(c->log), "%s: line %d",
|
|
c->fname, c->lineno );
|
|
|
|
c->argc = 0;
|
|
ch_free( c->tline );
|
|
if ( lload_config_fp_parse_line( c ) ) {
|
|
rc = 1;
|
|
goto done;
|
|
}
|
|
|
|
if ( c->argc < 1 ) {
|
|
Debug( LDAP_DEBUG_ANY, "%s: bad config line\n", c->log );
|
|
rc = 1;
|
|
goto done;
|
|
}
|
|
|
|
c->op = SLAP_CONFIG_ADD;
|
|
|
|
ct = lload_config_find_keyword( cft, c );
|
|
if ( ct ) {
|
|
c->table = Cft_Global;
|
|
rc = lload_config_add_vals( ct, c );
|
|
if ( !rc ) continue;
|
|
|
|
if ( rc & ARGS_USERLAND ) {
|
|
/* XXX a usertype would be opaque here */
|
|
Debug( LDAP_DEBUG_CONFIG, "%s: unknown user type <%s>\n",
|
|
c->log, c->argv[0] );
|
|
rc = 1;
|
|
goto done;
|
|
|
|
} else if ( rc == ARG_BAD_CONF ) {
|
|
rc = 1;
|
|
goto done;
|
|
}
|
|
|
|
} else {
|
|
Debug( LDAP_DEBUG_ANY, "%s: unknown directive "
|
|
"<%s> outside backend info and database definitions\n",
|
|
c->log, *c->argv );
|
|
rc = 1;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
rc = 0;
|
|
|
|
done:
|
|
ch_free( c->tline );
|
|
fclose( fp );
|
|
ch_free( c->argv );
|
|
ch_free( c );
|
|
return rc;
|
|
}
|
|
|
|
int
|
|
lload_read_config( const char *fname, const char *dir )
|
|
{
|
|
if ( !fname ) fname = LLOADD_DEFAULT_CONFIGFILE;
|
|
|
|
cfn = ch_calloc( 1, sizeof(ConfigFile) );
|
|
|
|
return lload_read_config_file( fname, 0, NULL, config_back_cf_table );
|
|
}
|
|
|
|
/* restrictops, allows, disallows, requires, loglevel */
|
|
|
|
int
|
|
bverb_to_mask( struct berval *bword, slap_verbmasks *v )
|
|
{
|
|
int i;
|
|
for ( i = 0; !BER_BVISNULL( &v[i].word ); i++ ) {
|
|
if ( !ber_bvstrcasecmp( bword, &v[i].word ) ) break;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
int
|
|
verb_to_mask( const char *word, slap_verbmasks *v )
|
|
{
|
|
struct berval bword;
|
|
ber_str2bv( word, 0, 0, &bword );
|
|
return bverb_to_mask( &bword, v );
|
|
}
|
|
|
|
int
|
|
verbs_to_mask( int argc, char *argv[], slap_verbmasks *v, slap_mask_t *m )
|
|
{
|
|
int i, j;
|
|
for ( i = 1; i < argc; i++ ) {
|
|
j = verb_to_mask( argv[i], v );
|
|
if ( BER_BVISNULL( &v[j].word ) ) return i;
|
|
while ( !v[j].mask )
|
|
j--;
|
|
*m |= v[j].mask;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* Mask keywords that represent multiple bits should occur before single
|
|
* bit keywords in the verbmasks array.
|
|
*/
|
|
int
|
|
mask_to_verbs( slap_verbmasks *v, slap_mask_t m, BerVarray *bva )
|
|
{
|
|
int i, rc = 1;
|
|
|
|
if ( m ) {
|
|
for ( i = 0; !BER_BVISNULL( &v[i].word ); i++ ) {
|
|
if ( !v[i].mask ) continue;
|
|
if ( (m & v[i].mask) == v[i].mask ) {
|
|
value_add_one( bva, &v[i].word );
|
|
rc = 0;
|
|
m ^= v[i].mask;
|
|
if ( !m ) break;
|
|
}
|
|
}
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
int
|
|
slap_verbmasks_init( slap_verbmasks **vp, slap_verbmasks *v )
|
|
{
|
|
int i;
|
|
|
|
assert( *vp == NULL );
|
|
|
|
for ( i = 0; !BER_BVISNULL( &v[i].word ); i++ ) /* EMPTY */;
|
|
|
|
*vp = ch_calloc( i + 1, sizeof(slap_verbmasks) );
|
|
|
|
for ( i = 0; !BER_BVISNULL( &v[i].word ); i++ ) {
|
|
ber_dupbv( &(*vp)[i].word, &v[i].word );
|
|
*( (slap_mask_t *)&(*vp)[i].mask ) = v[i].mask;
|
|
}
|
|
|
|
BER_BVZERO( &(*vp)[i].word );
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
slap_verbmasks_destroy( slap_verbmasks *v )
|
|
{
|
|
int i;
|
|
|
|
assert( v != NULL );
|
|
|
|
for ( i = 0; !BER_BVISNULL( &v[i].word ); i++ ) {
|
|
ch_free( v[i].word.bv_val );
|
|
}
|
|
|
|
ch_free( v );
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifndef BALANCER_MODULE
|
|
int
|
|
config_push_cleanup( ConfigArgs *ca, ConfigDriver *cleanup )
|
|
{
|
|
/* Stub, cleanups only run in online config */
|
|
return 0;
|
|
}
|
|
#endif /* !BALANCER_MODULE */
|
|
|
|
static slap_verbmasks tlskey[] = {
|
|
{ BER_BVC("no"), LLOAD_CLEARTEXT },
|
|
{ BER_BVC("yes"), LLOAD_STARTTLS_OPTIONAL },
|
|
{ BER_BVC("critical"), LLOAD_STARTTLS },
|
|
{ BER_BVNULL, 0 }
|
|
};
|
|
|
|
static slap_verbmasks crlkeys[] = {
|
|
{ BER_BVC("none"), LDAP_OPT_X_TLS_CRL_NONE },
|
|
{ BER_BVC("peer"), LDAP_OPT_X_TLS_CRL_PEER },
|
|
{ BER_BVC("all"), LDAP_OPT_X_TLS_CRL_ALL },
|
|
{ BER_BVNULL, 0 }
|
|
};
|
|
|
|
static slap_verbmasks vfykeys[] = {
|
|
{ BER_BVC("never"), LDAP_OPT_X_TLS_NEVER },
|
|
{ BER_BVC("allow"), LDAP_OPT_X_TLS_ALLOW },
|
|
{ BER_BVC("try"), LDAP_OPT_X_TLS_TRY },
|
|
{ BER_BVC("demand"), LDAP_OPT_X_TLS_DEMAND },
|
|
{ BER_BVC("hard"), LDAP_OPT_X_TLS_HARD },
|
|
{ BER_BVC("true"), LDAP_OPT_X_TLS_HARD },
|
|
{ BER_BVNULL, 0 }
|
|
};
|
|
|
|
static slap_verbmasks methkey[] = {
|
|
{ BER_BVC("none"), LDAP_AUTH_NONE },
|
|
{ BER_BVC("simple"), LDAP_AUTH_SIMPLE },
|
|
#ifdef HAVE_CYRUS_SASL
|
|
{ BER_BVC("sasl"), LDAP_AUTH_SASL },
|
|
#endif
|
|
{ BER_BVNULL, 0 }
|
|
};
|
|
|
|
int
|
|
lload_keepalive_parse(
|
|
struct berval *val,
|
|
void *bc,
|
|
slap_cf_aux_table *tab0,
|
|
const char *tabmsg,
|
|
int unparse )
|
|
{
|
|
if ( unparse ) {
|
|
slap_keepalive *sk = (slap_keepalive *)bc;
|
|
int rc = snprintf( val->bv_val, val->bv_len, "%d:%d:%d",
|
|
sk->sk_idle, sk->sk_probes, sk->sk_interval );
|
|
if ( rc < 0 ) {
|
|
return -1;
|
|
}
|
|
|
|
if ( (unsigned)rc >= val->bv_len ) {
|
|
return -1;
|
|
}
|
|
|
|
val->bv_len = rc;
|
|
|
|
} else {
|
|
char *s = val->bv_val;
|
|
char *next;
|
|
slap_keepalive *sk = (slap_keepalive *)bc;
|
|
slap_keepalive sk2;
|
|
|
|
if ( s[0] == ':' ) {
|
|
sk2.sk_idle = 0;
|
|
s++;
|
|
|
|
} else {
|
|
sk2.sk_idle = strtol( s, &next, 10 );
|
|
if ( next == s || next[0] != ':' ) {
|
|
return -1;
|
|
}
|
|
|
|
if ( sk2.sk_idle < 0 ) {
|
|
return -1;
|
|
}
|
|
|
|
s = ++next;
|
|
}
|
|
|
|
if ( s[0] == ':' ) {
|
|
sk2.sk_probes = 0;
|
|
s++;
|
|
|
|
} else {
|
|
sk2.sk_probes = strtol( s, &next, 10 );
|
|
if ( next == s || next[0] != ':' ) {
|
|
return -1;
|
|
}
|
|
|
|
if ( sk2.sk_probes < 0 ) {
|
|
return -1;
|
|
}
|
|
|
|
s = ++next;
|
|
}
|
|
|
|
if ( *s == '\0' ) {
|
|
sk2.sk_interval = 0;
|
|
|
|
} else {
|
|
sk2.sk_interval = strtol( s, &next, 10 );
|
|
if ( next == s || next[0] != '\0' ) {
|
|
return -1;
|
|
}
|
|
|
|
if ( sk2.sk_interval < 0 ) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
*sk = sk2;
|
|
|
|
ber_memfree( val->bv_val );
|
|
BER_BVZERO( val );
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static slap_cf_aux_table backendkey[] = {
|
|
{ BER_BVC("uri="), offsetof(LloadBackend, b_uri), 'b', 1, NULL },
|
|
|
|
{ BER_BVC("numconns="), offsetof(LloadBackend, b_numconns), 'i', 0, NULL },
|
|
{ BER_BVC("bindconns="), offsetof(LloadBackend, b_numbindconns), 'i', 0, NULL },
|
|
{ BER_BVC("retry="), offsetof(LloadBackend, b_retry_timeout), 'i', 0, NULL },
|
|
|
|
{ BER_BVC("max-pending-ops="), offsetof(LloadBackend, b_max_pending), 'i', 0, NULL },
|
|
{ BER_BVC("conn-max-pending="), offsetof(LloadBackend, b_max_conn_pending), 'i', 0, NULL },
|
|
{ BER_BVC("starttls="), offsetof(LloadBackend, b_tls_conf), 'i', 0, tlskey },
|
|
{ BER_BVNULL, 0, 0, 0, NULL }
|
|
};
|
|
|
|
static slap_cf_aux_table bindkey[] = {
|
|
{ BER_BVC("bindmethod="), offsetof(slap_bindconf, sb_method), 'i', 0, methkey },
|
|
{ BER_BVC("timeout="), offsetof(slap_bindconf, sb_timeout_api), 'i', 0, NULL },
|
|
{ BER_BVC("network-timeout="), offsetof(slap_bindconf, sb_timeout_net), 'i', 0, NULL },
|
|
{ BER_BVC("binddn="), offsetof(slap_bindconf, sb_binddn), 'b', 1, NULL },
|
|
{ BER_BVC("credentials="), offsetof(slap_bindconf, sb_cred), 'b', 1, NULL },
|
|
{ BER_BVC("saslmech="), offsetof(slap_bindconf, sb_saslmech), 'b', 0, NULL },
|
|
{ BER_BVC("secprops="), offsetof(slap_bindconf, sb_secprops), 's', 0, NULL },
|
|
{ BER_BVC("realm="), offsetof(slap_bindconf, sb_realm), 'b', 0, NULL },
|
|
{ BER_BVC("authcID="), offsetof(slap_bindconf, sb_authcId), 'b', 1, NULL },
|
|
{ BER_BVC("authzID="), offsetof(slap_bindconf, sb_authzId), 'b', 1, NULL },
|
|
{ BER_BVC("keepalive="), offsetof(slap_bindconf, sb_keepalive), 'x', 0, (slap_verbmasks *)lload_keepalive_parse },
|
|
#ifdef HAVE_TLS
|
|
/* NOTE: replace "11" with the actual index
|
|
* of the first TLS-related line */
|
|
#define aux_TLS (bindkey+11) /* beginning of TLS keywords */
|
|
|
|
{ BER_BVC("tls_cert="), offsetof(slap_bindconf, sb_tls_cert), 's', 1, NULL },
|
|
{ BER_BVC("tls_key="), offsetof(slap_bindconf, sb_tls_key), 's', 1, NULL },
|
|
{ BER_BVC("tls_cacert="), offsetof(slap_bindconf, sb_tls_cacert), 's', 1, NULL },
|
|
{ BER_BVC("tls_cacertdir="), offsetof(slap_bindconf, sb_tls_cacertdir), 's', 1, NULL },
|
|
{ BER_BVC("tls_reqcert="), offsetof(slap_bindconf, sb_tls_reqcert), 's', 0, NULL },
|
|
{ BER_BVC("tls_reqsan="), offsetof(slap_bindconf, sb_tls_reqsan), 's', 0, NULL },
|
|
{ BER_BVC("tls_cipher_suite="), offsetof(slap_bindconf, sb_tls_cipher_suite), 's', 0, NULL },
|
|
{ BER_BVC("tls_protocol_min="), offsetof(slap_bindconf, sb_tls_protocol_min), 's', 0, NULL },
|
|
{ BER_BVC("tls_ecname="), offsetof(slap_bindconf, sb_tls_ecname), 's', 0, NULL },
|
|
#ifdef HAVE_OPENSSL
|
|
{ BER_BVC("tls_crlcheck="), offsetof(slap_bindconf, sb_tls_crlcheck), 's', 0, NULL },
|
|
#endif
|
|
#endif
|
|
{ BER_BVNULL, 0, 0, 0, NULL }
|
|
};
|
|
|
|
/*
|
|
* 's': char *
|
|
* 'b': struct berval
|
|
* 'i': int; if !NULL, compute using ((slap_verbmasks *)aux)
|
|
* 'u': unsigned
|
|
* 'I': long
|
|
* 'U': unsigned long
|
|
*/
|
|
|
|
int
|
|
lload_cf_aux_table_parse(
|
|
const char *word,
|
|
void *dst,
|
|
slap_cf_aux_table *tab0,
|
|
LDAP_CONST char *tabmsg )
|
|
{
|
|
int rc = SLAP_CONF_UNKNOWN;
|
|
slap_cf_aux_table *tab;
|
|
|
|
for ( tab = tab0; !BER_BVISNULL( &tab->key ); tab++ ) {
|
|
if ( !strncasecmp( word, tab->key.bv_val, tab->key.bv_len ) ) {
|
|
char **cptr;
|
|
int *iptr, j;
|
|
unsigned *uptr;
|
|
long *lptr;
|
|
unsigned long *ulptr;
|
|
struct berval *bptr;
|
|
const char *val = word + tab->key.bv_len;
|
|
|
|
switch ( tab->type ) {
|
|
case 's':
|
|
cptr = (char **)( (char *)dst + tab->off );
|
|
*cptr = ch_strdup( val );
|
|
rc = 0;
|
|
break;
|
|
|
|
case 'b':
|
|
bptr = (struct berval *)( (char *)dst + tab->off );
|
|
assert( tab->aux == NULL );
|
|
ber_str2bv( val, 0, 1, bptr );
|
|
rc = 0;
|
|
break;
|
|
|
|
case 'i':
|
|
iptr = (int *)( (char *)dst + tab->off );
|
|
|
|
if ( tab->aux != NULL ) {
|
|
slap_verbmasks *aux = (slap_verbmasks *)tab->aux;
|
|
|
|
assert( aux != NULL );
|
|
|
|
rc = 1;
|
|
for ( j = 0; !BER_BVISNULL( &aux[j].word ); j++ ) {
|
|
if ( !strcasecmp( val, aux[j].word.bv_val ) ) {
|
|
*iptr = aux[j].mask;
|
|
rc = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
rc = lutil_atoix( iptr, val, 0 );
|
|
}
|
|
break;
|
|
|
|
case 'u':
|
|
uptr = (unsigned *)( (char *)dst + tab->off );
|
|
|
|
rc = lutil_atoux( uptr, val, 0 );
|
|
break;
|
|
|
|
case 'I':
|
|
lptr = (long *)( (char *)dst + tab->off );
|
|
|
|
rc = lutil_atolx( lptr, val, 0 );
|
|
break;
|
|
|
|
case 'U':
|
|
ulptr = (unsigned long *)( (char *)dst + tab->off );
|
|
|
|
rc = lutil_atoulx( ulptr, val, 0 );
|
|
break;
|
|
|
|
case 'x':
|
|
if ( tab->aux != NULL ) {
|
|
struct berval value;
|
|
lload_cf_aux_table_parse_x *func =
|
|
(lload_cf_aux_table_parse_x *)tab->aux;
|
|
|
|
ber_str2bv( val, 0, 1, &value );
|
|
|
|
rc = func( &value, (void *)( (char *)dst + tab->off ),
|
|
tab, tabmsg, 0 );
|
|
|
|
} else {
|
|
rc = 1;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if ( rc ) {
|
|
Debug( LDAP_DEBUG_ANY, "invalid %s value %s\n", tabmsg, word );
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
int
|
|
lload_cf_aux_table_unparse(
|
|
void *src,
|
|
struct berval *bv,
|
|
slap_cf_aux_table *tab0 )
|
|
{
|
|
char buf[AC_LINE_MAX], *ptr;
|
|
slap_cf_aux_table *tab;
|
|
struct berval tmp;
|
|
|
|
ptr = buf;
|
|
for ( tab = tab0; !BER_BVISNULL( &tab->key ); tab++ ) {
|
|
char **cptr;
|
|
int *iptr, i;
|
|
unsigned *uptr;
|
|
long *lptr;
|
|
unsigned long *ulptr;
|
|
struct berval *bptr;
|
|
|
|
cptr = (char **)( (char *)src + tab->off );
|
|
|
|
switch ( tab->type ) {
|
|
case 'b':
|
|
bptr = (struct berval *)( (char *)src + tab->off );
|
|
cptr = &bptr->bv_val;
|
|
|
|
case 's':
|
|
if ( *cptr ) {
|
|
*ptr++ = ' ';
|
|
ptr = lutil_strcopy( ptr, tab->key.bv_val );
|
|
if ( tab->quote ) *ptr++ = '"';
|
|
ptr = lutil_strcopy( ptr, *cptr );
|
|
if ( tab->quote ) *ptr++ = '"';
|
|
}
|
|
break;
|
|
|
|
case 'i':
|
|
iptr = (int *)( (char *)src + tab->off );
|
|
|
|
if ( tab->aux != NULL ) {
|
|
slap_verbmasks *aux = (slap_verbmasks *)tab->aux;
|
|
|
|
for ( i = 0; !BER_BVISNULL( &aux[i].word ); i++ ) {
|
|
if ( *iptr == aux[i].mask ) {
|
|
*ptr++ = ' ';
|
|
ptr = lutil_strcopy( ptr, tab->key.bv_val );
|
|
ptr = lutil_strcopy( ptr, aux[i].word.bv_val );
|
|
break;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
*ptr++ = ' ';
|
|
ptr = lutil_strcopy( ptr, tab->key.bv_val );
|
|
ptr += snprintf( ptr, sizeof(buf) - ( ptr - buf ), "%d",
|
|
*iptr );
|
|
}
|
|
break;
|
|
|
|
case 'u':
|
|
uptr = (unsigned *)( (char *)src + tab->off );
|
|
*ptr++ = ' ';
|
|
ptr = lutil_strcopy( ptr, tab->key.bv_val );
|
|
ptr += snprintf( ptr, sizeof(buf) - ( ptr - buf ), "%u",
|
|
*uptr );
|
|
break;
|
|
|
|
case 'I':
|
|
lptr = (long *)( (char *)src + tab->off );
|
|
*ptr++ = ' ';
|
|
ptr = lutil_strcopy( ptr, tab->key.bv_val );
|
|
ptr += snprintf( ptr, sizeof(buf) - ( ptr - buf ), "%ld",
|
|
*lptr );
|
|
break;
|
|
|
|
case 'U':
|
|
ulptr = (unsigned long *)( (char *)src + tab->off );
|
|
*ptr++ = ' ';
|
|
ptr = lutil_strcopy( ptr, tab->key.bv_val );
|
|
ptr += snprintf( ptr, sizeof(buf) - ( ptr - buf ), "%lu",
|
|
*ulptr );
|
|
break;
|
|
|
|
case 'x': {
|
|
char *saveptr = ptr;
|
|
*ptr++ = ' ';
|
|
ptr = lutil_strcopy( ptr, tab->key.bv_val );
|
|
if ( tab->quote ) *ptr++ = '"';
|
|
if ( tab->aux != NULL ) {
|
|
struct berval value;
|
|
lload_cf_aux_table_parse_x *func =
|
|
(lload_cf_aux_table_parse_x *)tab->aux;
|
|
int rc;
|
|
|
|
value.bv_val = ptr;
|
|
value.bv_len = buf + sizeof(buf) - ptr;
|
|
|
|
rc = func( &value, (void *)( (char *)src + tab->off ), tab,
|
|
"(unparse)", 1 );
|
|
if ( rc == 0 ) {
|
|
if ( value.bv_len ) {
|
|
ptr += value.bv_len;
|
|
} else {
|
|
ptr = saveptr;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if ( tab->quote ) *ptr++ = '"';
|
|
} break;
|
|
|
|
default:
|
|
assert(0);
|
|
}
|
|
}
|
|
tmp.bv_val = buf;
|
|
tmp.bv_len = ptr - buf;
|
|
ber_dupbv( bv, &tmp );
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
lload_tls_get_config( LDAP *ld, int opt, char **val )
|
|
{
|
|
#ifdef HAVE_TLS
|
|
slap_verbmasks *keys;
|
|
int i, ival;
|
|
|
|
*val = NULL;
|
|
switch ( opt ) {
|
|
case LDAP_OPT_X_TLS_CRLCHECK:
|
|
keys = crlkeys;
|
|
break;
|
|
case LDAP_OPT_X_TLS_REQUIRE_CERT:
|
|
keys = vfykeys;
|
|
break;
|
|
case LDAP_OPT_X_TLS_PROTOCOL_MIN: {
|
|
char buf[8];
|
|
ldap_pvt_tls_get_option( ld, opt, &ival );
|
|
snprintf( buf, sizeof(buf), "%d.%d",
|
|
( ival >> 8 ) & 0xff, ival & 0xff );
|
|
*val = ch_strdup( buf );
|
|
return 0;
|
|
}
|
|
default:
|
|
return -1;
|
|
}
|
|
ldap_pvt_tls_get_option( ld, opt, &ival );
|
|
for ( i = 0; !BER_BVISNULL( &keys[i].word ); i++ ) {
|
|
if ( keys[i].mask == ival ) {
|
|
*val = ch_strdup( keys[i].word.bv_val );
|
|
return 0;
|
|
}
|
|
}
|
|
#endif
|
|
return -1;
|
|
}
|
|
|
|
#ifdef HAVE_TLS
|
|
static struct {
|
|
const char *key;
|
|
size_t offset;
|
|
int opt;
|
|
} bindtlsopts[] = {
|
|
{ "tls_cert", offsetof(slap_bindconf, sb_tls_cert), LDAP_OPT_X_TLS_CERTFILE },
|
|
{ "tls_key", offsetof(slap_bindconf, sb_tls_key), LDAP_OPT_X_TLS_KEYFILE },
|
|
{ "tls_cacert", offsetof(slap_bindconf, sb_tls_cacert), LDAP_OPT_X_TLS_CACERTFILE },
|
|
{ "tls_cacertdir", offsetof(slap_bindconf, sb_tls_cacertdir), LDAP_OPT_X_TLS_CACERTDIR },
|
|
{ "tls_cipher_suite", offsetof(slap_bindconf, sb_tls_cipher_suite), LDAP_OPT_X_TLS_CIPHER_SUITE },
|
|
{ "tls_ecname", offsetof(slap_bindconf, sb_tls_ecname), LDAP_OPT_X_TLS_ECNAME },
|
|
{ NULL, 0 }
|
|
};
|
|
|
|
int
|
|
lload_bindconf_tls_set( slap_bindconf *bc, LDAP *ld )
|
|
{
|
|
int i, rc, newctx = 0, res = 0;
|
|
char *ptr = (char *)bc, **word;
|
|
|
|
if ( bc->sb_tls_do_init ) {
|
|
for ( i = 0; bindtlsopts[i].opt; i++ ) {
|
|
word = (char **)( ptr + bindtlsopts[i].offset );
|
|
if ( *word ) {
|
|
rc = ldap_set_option( ld, bindtlsopts[i].opt, *word );
|
|
if ( rc ) {
|
|
Debug( LDAP_DEBUG_ANY, "lload_bindconf_tls_set: "
|
|
"failed to set %s to %s\n",
|
|
bindtlsopts[i].key, *word );
|
|
res = -1;
|
|
} else
|
|
newctx = 1;
|
|
}
|
|
}
|
|
if ( bc->sb_tls_reqcert ) {
|
|
rc = ldap_pvt_tls_config(
|
|
ld, LDAP_OPT_X_TLS_REQUIRE_CERT, bc->sb_tls_reqcert );
|
|
if ( rc ) {
|
|
Debug( LDAP_DEBUG_ANY, "lload_bindconf_tls_set: "
|
|
"failed to set tls_reqcert to %s\n",
|
|
bc->sb_tls_reqcert );
|
|
res = -1;
|
|
} else {
|
|
newctx = 1;
|
|
/* retrieve the parsed setting for later use */
|
|
ldap_get_option( ld, LDAP_OPT_X_TLS_REQUIRE_CERT,
|
|
&bc->sb_tls_int_reqcert );
|
|
}
|
|
}
|
|
if ( bc->sb_tls_reqsan ) {
|
|
rc = ldap_pvt_tls_config(
|
|
ld, LDAP_OPT_X_TLS_REQUIRE_SAN, bc->sb_tls_reqsan );
|
|
if ( rc ) {
|
|
Debug( LDAP_DEBUG_ANY, "lload_bindconf_tls_set: "
|
|
"failed to set tls_reqsan to %s\n",
|
|
bc->sb_tls_reqsan );
|
|
res = -1;
|
|
} else {
|
|
newctx = 1;
|
|
/* retrieve the parsed setting for later use */
|
|
ldap_get_option( ld, LDAP_OPT_X_TLS_REQUIRE_SAN,
|
|
&bc->sb_tls_int_reqsan );
|
|
}
|
|
}
|
|
if ( bc->sb_tls_protocol_min ) {
|
|
rc = ldap_pvt_tls_config(
|
|
ld, LDAP_OPT_X_TLS_PROTOCOL_MIN, bc->sb_tls_protocol_min );
|
|
if ( rc ) {
|
|
Debug( LDAP_DEBUG_ANY, "lload_bindconf_tls_set: "
|
|
"failed to set tls_protocol_min to %s\n",
|
|
bc->sb_tls_protocol_min );
|
|
res = -1;
|
|
} else
|
|
newctx = 1;
|
|
}
|
|
#ifdef HAVE_OPENSSL
|
|
if ( bc->sb_tls_crlcheck ) {
|
|
rc = ldap_pvt_tls_config(
|
|
ld, LDAP_OPT_X_TLS_CRLCHECK, bc->sb_tls_crlcheck );
|
|
if ( rc ) {
|
|
Debug( LDAP_DEBUG_ANY, "lload_bindconf_tls_set: "
|
|
"failed to set tls_crlcheck to %s\n",
|
|
bc->sb_tls_crlcheck );
|
|
res = -1;
|
|
} else
|
|
newctx = 1;
|
|
}
|
|
#endif
|
|
if ( !res ) bc->sb_tls_do_init = 0;
|
|
}
|
|
|
|
if ( newctx ) {
|
|
int opt = 0;
|
|
|
|
if ( bc->sb_tls_ctx ) {
|
|
ldap_pvt_tls_ctx_free( bc->sb_tls_ctx );
|
|
bc->sb_tls_ctx = NULL;
|
|
}
|
|
rc = ldap_set_option( ld, LDAP_OPT_X_TLS_NEWCTX, &opt );
|
|
if ( rc )
|
|
res = rc;
|
|
else
|
|
ldap_get_option( ld, LDAP_OPT_X_TLS_CTX, &bc->sb_tls_ctx );
|
|
} else if ( bc->sb_tls_ctx ) {
|
|
rc = ldap_set_option( ld, LDAP_OPT_X_TLS_CTX, bc->sb_tls_ctx );
|
|
if ( rc == LDAP_SUCCESS ) {
|
|
/* these options aren't actually inside the ctx, so have to be set again */
|
|
ldap_set_option(
|
|
ld, LDAP_OPT_X_TLS_REQUIRE_CERT, &bc->sb_tls_int_reqcert );
|
|
ldap_set_option(
|
|
ld, LDAP_OPT_X_TLS_REQUIRE_SAN, &bc->sb_tls_int_reqsan );
|
|
} else
|
|
res = rc;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
#endif
|
|
|
|
int
|
|
lload_bindconf_tls_parse( const char *word, slap_bindconf *bc )
|
|
{
|
|
#ifdef HAVE_TLS
|
|
if ( lload_cf_aux_table_parse( word, bc, aux_TLS, "tls config" ) == 0 ) {
|
|
bc->sb_tls_do_init = 1;
|
|
return 0;
|
|
}
|
|
#endif
|
|
return -1;
|
|
}
|
|
|
|
int
|
|
lload_backend_parse( const char *word, LloadBackend *b )
|
|
{
|
|
return lload_cf_aux_table_parse( word, b, backendkey, "backend config" );
|
|
}
|
|
|
|
int
|
|
lload_bindconf_parse( const char *word, slap_bindconf *bc )
|
|
{
|
|
#ifdef HAVE_TLS
|
|
/* Detect TLS config changes explicitly */
|
|
if ( lload_bindconf_tls_parse( word, bc ) == 0 ) {
|
|
return 0;
|
|
}
|
|
#endif
|
|
return lload_cf_aux_table_parse( word, bc, bindkey, "bind config" );
|
|
}
|
|
|
|
int
|
|
lload_bindconf_unparse( slap_bindconf *bc, struct berval *bv )
|
|
{
|
|
return lload_cf_aux_table_unparse( bc, bv, bindkey );
|
|
}
|
|
|
|
void
|
|
lload_bindconf_free( slap_bindconf *bc )
|
|
{
|
|
if ( !BER_BVISNULL( &bc->sb_uri ) ) {
|
|
ch_free( bc->sb_uri.bv_val );
|
|
BER_BVZERO( &bc->sb_uri );
|
|
}
|
|
if ( !BER_BVISNULL( &bc->sb_binddn ) ) {
|
|
ch_free( bc->sb_binddn.bv_val );
|
|
BER_BVZERO( &bc->sb_binddn );
|
|
}
|
|
if ( !BER_BVISNULL( &bc->sb_cred ) ) {
|
|
ch_free( bc->sb_cred.bv_val );
|
|
BER_BVZERO( &bc->sb_cred );
|
|
}
|
|
if ( !BER_BVISNULL( &bc->sb_saslmech ) ) {
|
|
ch_free( bc->sb_saslmech.bv_val );
|
|
BER_BVZERO( &bc->sb_saslmech );
|
|
}
|
|
if ( bc->sb_secprops ) {
|
|
ch_free( bc->sb_secprops );
|
|
bc->sb_secprops = NULL;
|
|
}
|
|
if ( !BER_BVISNULL( &bc->sb_realm ) ) {
|
|
ch_free( bc->sb_realm.bv_val );
|
|
BER_BVZERO( &bc->sb_realm );
|
|
}
|
|
if ( !BER_BVISNULL( &bc->sb_authcId ) ) {
|
|
ch_free( bc->sb_authcId.bv_val );
|
|
BER_BVZERO( &bc->sb_authcId );
|
|
}
|
|
if ( !BER_BVISNULL( &bc->sb_authzId ) ) {
|
|
ch_free( bc->sb_authzId.bv_val );
|
|
BER_BVZERO( &bc->sb_authzId );
|
|
}
|
|
#ifdef HAVE_TLS
|
|
if ( bc->sb_tls_cert ) {
|
|
ch_free( bc->sb_tls_cert );
|
|
bc->sb_tls_cert = NULL;
|
|
}
|
|
if ( bc->sb_tls_key ) {
|
|
ch_free( bc->sb_tls_key );
|
|
bc->sb_tls_key = NULL;
|
|
}
|
|
if ( bc->sb_tls_cacert ) {
|
|
ch_free( bc->sb_tls_cacert );
|
|
bc->sb_tls_cacert = NULL;
|
|
}
|
|
if ( bc->sb_tls_cacertdir ) {
|
|
ch_free( bc->sb_tls_cacertdir );
|
|
bc->sb_tls_cacertdir = NULL;
|
|
}
|
|
if ( bc->sb_tls_reqcert ) {
|
|
ch_free( bc->sb_tls_reqcert );
|
|
bc->sb_tls_reqcert = NULL;
|
|
}
|
|
if ( bc->sb_tls_cipher_suite ) {
|
|
ch_free( bc->sb_tls_cipher_suite );
|
|
bc->sb_tls_cipher_suite = NULL;
|
|
}
|
|
if ( bc->sb_tls_protocol_min ) {
|
|
ch_free( bc->sb_tls_protocol_min );
|
|
bc->sb_tls_protocol_min = NULL;
|
|
}
|
|
#ifdef HAVE_OPENSSL_CRL
|
|
if ( bc->sb_tls_crlcheck ) {
|
|
ch_free( bc->sb_tls_crlcheck );
|
|
bc->sb_tls_crlcheck = NULL;
|
|
}
|
|
#endif
|
|
if ( bc->sb_tls_ctx ) {
|
|
ldap_pvt_tls_ctx_free( bc->sb_tls_ctx );
|
|
bc->sb_tls_ctx = NULL;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void
|
|
lload_bindconf_tls_defaults( slap_bindconf *bc )
|
|
{
|
|
#ifdef HAVE_TLS
|
|
if ( bc->sb_tls_do_init ) {
|
|
if ( !bc->sb_tls_cacert )
|
|
ldap_pvt_tls_get_option( lload_tls_ld, LDAP_OPT_X_TLS_CACERTFILE,
|
|
&bc->sb_tls_cacert );
|
|
if ( !bc->sb_tls_cacertdir )
|
|
ldap_pvt_tls_get_option( lload_tls_ld, LDAP_OPT_X_TLS_CACERTDIR,
|
|
&bc->sb_tls_cacertdir );
|
|
if ( !bc->sb_tls_cert )
|
|
ldap_pvt_tls_get_option(
|
|
lload_tls_ld, LDAP_OPT_X_TLS_CERTFILE, &bc->sb_tls_cert );
|
|
if ( !bc->sb_tls_key )
|
|
ldap_pvt_tls_get_option(
|
|
lload_tls_ld, LDAP_OPT_X_TLS_KEYFILE, &bc->sb_tls_key );
|
|
if ( !bc->sb_tls_cipher_suite )
|
|
ldap_pvt_tls_get_option( lload_tls_ld, LDAP_OPT_X_TLS_CIPHER_SUITE,
|
|
&bc->sb_tls_cipher_suite );
|
|
if ( !bc->sb_tls_reqcert ) bc->sb_tls_reqcert = ch_strdup( "demand" );
|
|
#ifdef HAVE_OPENSSL_CRL
|
|
if ( !bc->sb_tls_crlcheck )
|
|
lload_tls_get_config( lload_tls_ld, LDAP_OPT_X_TLS_CRLCHECK,
|
|
&bc->sb_tls_crlcheck );
|
|
#endif
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* -------------------------------------- */
|
|
|
|
static char *
|
|
strtok_quote( char *line, char *sep, char **quote_ptr, int *iqp )
|
|
{
|
|
int inquote;
|
|
char *tmp;
|
|
static char *next;
|
|
|
|
*quote_ptr = NULL;
|
|
if ( line != NULL ) {
|
|
next = line;
|
|
}
|
|
while ( *next && strchr( sep, *next ) ) {
|
|
next++;
|
|
}
|
|
|
|
if ( *next == '\0' ) {
|
|
next = NULL;
|
|
return NULL;
|
|
}
|
|
tmp = next;
|
|
|
|
for ( inquote = 0; *next; ) {
|
|
switch ( *next ) {
|
|
case '"':
|
|
if ( inquote ) {
|
|
inquote = 0;
|
|
} else {
|
|
inquote = 1;
|
|
}
|
|
AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
|
|
break;
|
|
|
|
case '\\':
|
|
if ( next[1] )
|
|
AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
|
|
next++; /* dont parse the escaped character */
|
|
break;
|
|
|
|
default:
|
|
if ( !inquote ) {
|
|
if ( strchr( sep, *next ) != NULL ) {
|
|
*quote_ptr = next;
|
|
*next++ = '\0';
|
|
return tmp;
|
|
}
|
|
}
|
|
next++;
|
|
break;
|
|
}
|
|
}
|
|
*iqp = inquote;
|
|
|
|
return tmp;
|
|
}
|
|
|
|
static char buf[AC_LINE_MAX];
|
|
static char *line;
|
|
static size_t lmax, lcur;
|
|
|
|
#define CATLINE( buf ) \
|
|
do { \
|
|
size_t len = strlen( buf ); \
|
|
while ( lcur + len + 1 > lmax ) { \
|
|
lmax += AC_LINE_MAX; \
|
|
line = (char *)ch_realloc( line, lmax ); \
|
|
} \
|
|
strcpy( line + lcur, buf ); \
|
|
lcur += len; \
|
|
} while (0)
|
|
|
|
static void
|
|
fp_getline_init( ConfigArgs *c )
|
|
{
|
|
c->lineno = -1;
|
|
buf[0] = '\0';
|
|
}
|
|
|
|
static int
|
|
fp_getline( FILE *fp, ConfigArgs *c )
|
|
{
|
|
char *p;
|
|
|
|
lcur = 0;
|
|
CATLINE( buf );
|
|
c->lineno++;
|
|
|
|
/* avoid stack of bufs */
|
|
if ( strncasecmp( line, "include", STRLENOF("include") ) == 0 ) {
|
|
buf[0] = '\0';
|
|
c->line = line;
|
|
return 1;
|
|
}
|
|
|
|
while ( fgets( buf, sizeof(buf), fp ) ) {
|
|
p = strchr( buf, '\n' );
|
|
if ( p ) {
|
|
if ( p > buf && p[-1] == '\r' ) {
|
|
--p;
|
|
}
|
|
*p = '\0';
|
|
}
|
|
/* XXX ugly */
|
|
c->line = line;
|
|
if ( line[0] && ( p = line + strlen( line ) - 1 )[0] == '\\' &&
|
|
p[-1] != '\\' ) {
|
|
p[0] = '\0';
|
|
lcur--;
|
|
|
|
} else {
|
|
if ( !isspace( (unsigned char)buf[0] ) ) {
|
|
return 1;
|
|
}
|
|
buf[0] = ' ';
|
|
}
|
|
CATLINE( buf );
|
|
c->lineno++;
|
|
}
|
|
|
|
buf[0] = '\0';
|
|
c->line = line;
|
|
return ( line[0] ? 1 : 0 );
|
|
}
|
|
|
|
int
|
|
lload_config_fp_parse_line( ConfigArgs *c )
|
|
{
|
|
char *token;
|
|
static char *const hide[] = { "bindconf", NULL };
|
|
static char *const raw[] = { NULL };
|
|
char *quote_ptr;
|
|
int i = (int)( sizeof(hide) / sizeof(hide[0]) ) - 1;
|
|
int inquote = 0;
|
|
|
|
c->tline = ch_strdup( c->line );
|
|
c->linelen = strlen( c->line );
|
|
token = strtok_quote( c->tline, " \t", "e_ptr, &inquote );
|
|
|
|
if ( token )
|
|
for ( i = 0; hide[i]; i++ )
|
|
if ( !strcasecmp( token, hide[i] ) ) break;
|
|
if ( quote_ptr ) *quote_ptr = ' ';
|
|
Debug( LDAP_DEBUG_CONFIG, "%s (%s%s)\n",
|
|
c->log, hide[i] ? hide[i] : c->line, hide[i] ? " ***" : "" );
|
|
if ( quote_ptr ) *quote_ptr = '\0';
|
|
|
|
for ( ;; token = strtok_quote( NULL, " \t", "e_ptr, &inquote ) ) {
|
|
if ( c->argc >= c->argv_size ) {
|
|
char **tmp;
|
|
tmp = ch_realloc( c->argv,
|
|
( c->argv_size + ARGS_STEP ) * sizeof(*c->argv) );
|
|
if ( !tmp ) {
|
|
Debug( LDAP_DEBUG_ANY, "%s: out of memory\n", c->log );
|
|
return -1;
|
|
}
|
|
c->argv = tmp;
|
|
c->argv_size += ARGS_STEP;
|
|
}
|
|
if ( token == NULL ) break;
|
|
c->argv[c->argc++] = token;
|
|
}
|
|
c->argv[c->argc] = NULL;
|
|
if ( inquote ) {
|
|
/* these directives parse c->line independently of argv tokenizing */
|
|
for ( i = 0; raw[i]; i++ )
|
|
if ( !strcasecmp( c->argv[0], raw[i] ) ) return 0;
|
|
|
|
Debug( LDAP_DEBUG_ANY, "%s: unterminated quoted string \"%s\"\n",
|
|
c->log, c->argv[c->argc - 1] );
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
lload_config_destroy( void )
|
|
{
|
|
free( line );
|
|
if ( slapd_args_file ) free( slapd_args_file );
|
|
if ( slapd_pid_file ) free( slapd_pid_file );
|
|
loglevel_destroy();
|
|
}
|
|
|
|
/* See if the given URL (in plain and parsed form) matches
|
|
* any of the server's listener addresses. Return matching
|
|
* LloadListener or NULL for no match.
|
|
*/
|
|
LloadListener *
|
|
lload_config_check_my_url( const char *url, LDAPURLDesc *lud )
|
|
{
|
|
LloadListener **l = lloadd_get_listeners();
|
|
int i, isMe;
|
|
|
|
/* Try a straight compare with LloadListener strings */
|
|
for ( i = 0; l && l[i]; i++ ) {
|
|
if ( !strcasecmp( url, l[i]->sl_url.bv_val ) ) {
|
|
return l[i];
|
|
}
|
|
}
|
|
|
|
isMe = 0;
|
|
/* If hostname is empty, or is localhost, or matches
|
|
* our hostname, this url refers to this host.
|
|
* Compare it against listeners and ports.
|
|
*/
|
|
if ( !lud->lud_host || !lud->lud_host[0] ||
|
|
!strncasecmp(
|
|
"localhost", lud->lud_host, STRLENOF("localhost") ) ||
|
|
!strcasecmp( global_host, lud->lud_host ) ) {
|
|
for ( i = 0; l && l[i]; i++ ) {
|
|
LDAPURLDesc *lu2;
|
|
ldap_url_parse_ext(
|
|
l[i]->sl_url.bv_val, &lu2, LDAP_PVT_URL_PARSE_DEF_PORT );
|
|
do {
|
|
if ( strcasecmp( lud->lud_scheme, lu2->lud_scheme ) ) break;
|
|
if ( lud->lud_port != lu2->lud_port ) break;
|
|
/* Listener on ANY address */
|
|
if ( !lu2->lud_host || !lu2->lud_host[0] ) {
|
|
isMe = 1;
|
|
break;
|
|
}
|
|
/* URL on ANY address */
|
|
if ( !lud->lud_host || !lud->lud_host[0] ) {
|
|
isMe = 1;
|
|
break;
|
|
}
|
|
/* Listener has specific host, must
|
|
* match it
|
|
*/
|
|
if ( !strcasecmp( lud->lud_host, lu2->lud_host ) ) {
|
|
isMe = 1;
|
|
break;
|
|
}
|
|
} while (0);
|
|
ldap_free_urldesc( lu2 );
|
|
if ( isMe ) {
|
|
return l[i];
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
#ifdef BALANCER_MODULE
|
|
static int
|
|
backend_cf_gen( ConfigArgs *c )
|
|
{
|
|
LloadBackend *b = c->ca_private;
|
|
enum lcf_backend flag = 0;
|
|
int rc = LDAP_SUCCESS;
|
|
|
|
assert( b != NULL );
|
|
|
|
if ( c->op == SLAP_CONFIG_EMIT ) {
|
|
switch ( c->type ) {
|
|
case CFG_URI:
|
|
c->value_bv = b->b_uri;
|
|
break;
|
|
case CFG_NUMCONNS:
|
|
c->value_uint = b->b_numconns;
|
|
break;
|
|
case CFG_BINDCONNS:
|
|
c->value_uint = b->b_numbindconns;
|
|
break;
|
|
case CFG_RETRY:
|
|
c->value_uint = b->b_retry_timeout;
|
|
break;
|
|
case CFG_MAX_PENDING_CONNS:
|
|
c->value_uint = b->b_max_conn_pending;
|
|
break;
|
|
case CFG_MAX_PENDING_OPS:
|
|
c->value_uint = b->b_max_pending;
|
|
break;
|
|
case CFG_STARTTLS:
|
|
enum_to_verb( tlskey, b->b_tls_conf, &c->value_bv );
|
|
break;
|
|
default:
|
|
rc = 1;
|
|
break;
|
|
}
|
|
|
|
return rc;
|
|
} else if ( c->op == LDAP_MOD_DELETE ) {
|
|
/* We only need to worry about deletions to multi-value or MAY
|
|
* attributes */
|
|
switch ( c->type ) {
|
|
case CFG_STARTTLS:
|
|
b->b_tls_conf = LLOAD_CLEARTEXT;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
switch ( c->type ) {
|
|
case CFG_URI:
|
|
rc = backend_config_url( b, &c->value_bv );
|
|
if ( rc ) {
|
|
backend_config_url( b, &b->b_uri );
|
|
goto fail;
|
|
}
|
|
if ( !BER_BVISNULL( &b->b_uri ) ) {
|
|
ch_free( b->b_uri.bv_val );
|
|
}
|
|
b->b_uri = c->value_bv;
|
|
flag = LLOAD_BACKEND_MOD_OTHER;
|
|
break;
|
|
case CFG_NUMCONNS:
|
|
if ( !c->value_uint ) {
|
|
snprintf( c->cr_msg, sizeof(c->cr_msg),
|
|
"invalid connection pool configuration" );
|
|
goto fail;
|
|
}
|
|
b->b_numconns = c->value_uint;
|
|
flag = LLOAD_BACKEND_MOD_CONNS;
|
|
break;
|
|
case CFG_BINDCONNS:
|
|
if ( !c->value_uint ) {
|
|
snprintf( c->cr_msg, sizeof(c->cr_msg),
|
|
"invalid connection pool configuration" );
|
|
goto fail;
|
|
}
|
|
b->b_numbindconns = c->value_uint;
|
|
flag = LLOAD_BACKEND_MOD_CONNS;
|
|
break;
|
|
case CFG_RETRY:
|
|
b->b_retry_timeout = c->value_uint;
|
|
break;
|
|
case CFG_MAX_PENDING_CONNS:
|
|
b->b_max_conn_pending = c->value_uint;
|
|
break;
|
|
case CFG_MAX_PENDING_OPS:
|
|
b->b_max_pending = c->value_uint;
|
|
break;
|
|
case CFG_STARTTLS: {
|
|
int i = bverb_to_mask( &c->value_bv, tlskey );
|
|
if ( BER_BVISNULL( &tlskey[i].word ) ) {
|
|
snprintf( c->cr_msg, sizeof(c->cr_msg),
|
|
"invalid starttls configuration" );
|
|
goto fail;
|
|
}
|
|
b->b_tls_conf = tlskey[i].mask;
|
|
} break;
|
|
default:
|
|
rc = 1;
|
|
break;
|
|
}
|
|
|
|
/* do not set this if it has already been set by another callback, e.g.
|
|
* lload_backend_ldadd */
|
|
if ( lload_change.type == LLOAD_CHANGE_UNDEFINED ) {
|
|
lload_change.type = LLOAD_CHANGE_MODIFY;
|
|
}
|
|
lload_change.object = LLOAD_BACKEND;
|
|
lload_change.target = b;
|
|
lload_change.flags.backend |= flag;
|
|
|
|
config_push_cleanup( c, lload_backend_finish );
|
|
return rc;
|
|
|
|
fail:
|
|
if ( lload_change.type == LLOAD_CHANGE_ADD ) {
|
|
/* Abort the ADD */
|
|
lload_change.type = LLOAD_CHANGE_DEL;
|
|
}
|
|
|
|
Debug( LDAP_DEBUG_ANY, "%s: %s\n", c->log, c->cr_msg );
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
lload_back_init_cf( BackendInfo *bi )
|
|
{
|
|
/* Make sure we don't exceed the bits reserved for userland */
|
|
config_check_userland( CFG_LAST );
|
|
|
|
bi->bi_cf_ocs = lloadocs;
|
|
|
|
return config_register_schema( config_back_cf_table, lloadocs );
|
|
}
|
|
|
|
static int
|
|
lload_backend_ldadd( CfEntryInfo *p, Entry *e, ConfigArgs *ca )
|
|
{
|
|
LloadBackend *b;
|
|
Attribute *a;
|
|
AttributeDescription *ad = NULL;
|
|
struct berval bv, type, rdn;
|
|
const char *text;
|
|
char *name;
|
|
|
|
Debug( LDAP_DEBUG_TRACE, "lload_backend_ldadd: "
|
|
"a new backend-server is being added\n" );
|
|
|
|
if ( p->ce_type != Cft_Backend || !p->ce_bi ||
|
|
p->ce_bi->bi_cf_ocs != lloadocs )
|
|
return LDAP_CONSTRAINT_VIOLATION;
|
|
|
|
dnRdn( &e->e_name, &rdn );
|
|
type.bv_len = strchr( rdn.bv_val, '=' ) - rdn.bv_val;
|
|
type.bv_val = rdn.bv_val;
|
|
|
|
/* Find attr */
|
|
slap_bv2ad( &type, &ad, &text );
|
|
if ( ad != slap_schema.si_ad_cn ) return LDAP_NAMING_VIOLATION;
|
|
|
|
a = attr_find( e->e_attrs, ad );
|
|
if ( !a || a->a_numvals != 1 ) return LDAP_NAMING_VIOLATION;
|
|
bv = a->a_vals[0];
|
|
|
|
if ( bv.bv_val[0] == '{' && ( name = strchr( bv.bv_val, '}' ) ) ) {
|
|
name++;
|
|
bv.bv_len -= name - bv.bv_val;
|
|
bv.bv_val = name;
|
|
}
|
|
|
|
b = backend_alloc();
|
|
ber_dupbv( &b->b_name, &bv );
|
|
|
|
ca->bi = p->ce_bi;
|
|
ca->ca_private = b;
|
|
config_push_cleanup( ca, lload_backend_finish );
|
|
|
|
/* ca cleanups are only run in the case of online config but we use it to
|
|
* save the new config when done with the entry */
|
|
ca->lineno = 0;
|
|
|
|
lload_change.type = LLOAD_CHANGE_ADD;
|
|
lload_change.object = LLOAD_BACKEND;
|
|
lload_change.target = b;
|
|
|
|
return LDAP_SUCCESS;
|
|
}
|
|
|
|
#ifdef SLAP_CONFIG_DELETE
|
|
static int
|
|
lload_backend_lddel( CfEntryInfo *ce, Operation *op )
|
|
{
|
|
LloadBackend *b = ce->ce_private;
|
|
|
|
lload_change.type = LLOAD_CHANGE_DEL;
|
|
lload_change.object = LLOAD_BACKEND;
|
|
lload_change.target = b;
|
|
|
|
return LDAP_SUCCESS;
|
|
}
|
|
#endif /* SLAP_CONFIG_DELETE */
|
|
|
|
static int
|
|
lload_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *c )
|
|
{
|
|
struct berval bv;
|
|
LloadBackend *b;
|
|
int i = 0;
|
|
|
|
bv.bv_val = c->cr_msg;
|
|
LDAP_CIRCLEQ_FOREACH ( b, &backend, b_next ) {
|
|
char buf[STRLENOF( "server 4294967295" ) + 1] = { 0 };
|
|
|
|
bv.bv_len = snprintf( c->cr_msg, sizeof(c->cr_msg),
|
|
"cn=" SLAP_X_ORDERED_FMT "server %d", i, i + 1 );
|
|
|
|
snprintf( buf, sizeof(buf), "server %d", i + 1 );
|
|
ber_str2bv( buf, 0, 1, &b->b_name );
|
|
|
|
c->ca_private = b;
|
|
c->valx = i;
|
|
|
|
config_build_entry( op, rs, p->e_private, c, &bv, &lloadocs[1], NULL );
|
|
|
|
i++;
|
|
}
|
|
return LDAP_SUCCESS;
|
|
}
|
|
#endif /* BALANCER_MODULE */
|