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