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