1/*	$NetBSD: config.c,v 1.3 2021/08/14 16:15:01 christos Exp $	*/
2
3/* config.c - sock backend configuration file routine */
4/* $OpenLDAP$ */
5/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6 *
7 * Copyright 2007-2021 The OpenLDAP Foundation.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted only as authorized by the OpenLDAP
12 * Public License.
13 *
14 * A copy of this license is available in the file LICENSE in the
15 * top-level directory of the distribution or, alternatively, at
16 * <http://www.OpenLDAP.org/license.html>.
17 */
18/* ACKNOWLEDGEMENTS:
19 * This work was initially developed by Brian Candler for inclusion
20 * in OpenLDAP Software. Dynamic config support by Howard Chu.
21 */
22
23#include <sys/cdefs.h>
24__RCSID("$NetBSD: config.c,v 1.3 2021/08/14 16:15:01 christos Exp $");
25
26#include "portable.h"
27
28#include <stdio.h>
29
30#include <ac/string.h>
31#include <ac/socket.h>
32
33#include "slap.h"
34#include "slap-config.h"
35#include "back-sock.h"
36
37static ConfigDriver bs_cf_gen;
38static int sock_over_setup();
39static slap_response sock_over_response;
40
41enum {
42	BS_EXT = 1,
43	BS_OPS,
44	BS_RESP,
45	BS_DNPAT
46};
47
48/* The number of overlay-only config attrs */
49#define NUM_OV_ATTRS	3
50
51static ConfigTable bscfg[] = {
52	{ "sockops", "ops", 2, 0, 0, ARG_MAGIC|BS_OPS,
53		bs_cf_gen, "( OLcfgDbAt:7.3 NAME 'olcOvSocketOps' "
54			"DESC 'Operation types to forward' "
55			"EQUALITY caseIgnoreMatch "
56			"SYNTAX OMsDirectoryString )", NULL, NULL },
57	{ "sockresps", "resps", 2, 0, 0, ARG_MAGIC|BS_RESP,
58		bs_cf_gen, "( OLcfgDbAt:7.4 NAME 'olcOvSocketResps' "
59			"DESC 'Response types to forward' "
60			"EQUALITY caseIgnoreMatch "
61			"SYNTAX OMsDirectoryString )", NULL, NULL },
62	{ "sockdnpat", "regexp", 2, 2, 0, ARG_MAGIC|BS_DNPAT,
63		bs_cf_gen, "( OLcfgDbAt:7.5 NAME 'olcOvSocketDNpat' "
64			"DESC 'DN pattern to match' "
65			"EQUALITY caseIgnoreMatch "
66			"SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
67
68	{ "socketpath", "pathname", 2, 2, 0, ARG_STRING|ARG_OFFSET,
69		(void *)offsetof(struct sockinfo, si_sockpath),
70		"( OLcfgDbAt:7.1 NAME 'olcDbSocketPath' "
71			"DESC 'Pathname for Unix domain socket' "
72			"EQUALITY caseExactMatch "
73			"SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
74	{ "extensions", "ext", 2, 0, 0, ARG_MAGIC|BS_EXT,
75		bs_cf_gen, "( OLcfgDbAt:7.2 NAME 'olcDbSocketExtensions' "
76			"DESC 'binddn, peername, or ssf' "
77			"EQUALITY caseIgnoreMatch "
78			"SYNTAX OMsDirectoryString )", NULL, NULL },
79	{ NULL, NULL }
80};
81
82static ConfigOCs bsocs[] = {
83	{ "( OLcfgDbOc:7.1 "
84		"NAME 'olcDbSocketConfig' "
85		"DESC 'Socket backend configuration' "
86		"SUP olcDatabaseConfig "
87		"MUST olcDbSocketPath "
88		"MAY olcDbSocketExtensions )",
89			Cft_Database, bscfg+NUM_OV_ATTRS },
90	{ NULL, 0, NULL }
91};
92
93static ConfigOCs osocs[] = {
94	{ "( OLcfgDbOc:7.2 "
95		"NAME 'olcOvSocketConfig' "
96		"DESC 'Socket overlay configuration' "
97		"SUP olcOverlayConfig "
98		"MUST olcDbSocketPath "
99		"MAY ( olcDbSocketExtensions $ "
100			" olcOvSocketOps $ olcOvSocketResps $ "
101			" olcOvSocketDNpat ) )",
102			Cft_Overlay, bscfg },
103	{ NULL, 0, NULL }
104};
105
106#define SOCK_OP_BIND	0x001
107#define SOCK_OP_UNBIND	0x002
108#define SOCK_OP_SEARCH	0x004
109#define SOCK_OP_COMPARE	0x008
110#define SOCK_OP_MODIFY	0x010
111#define SOCK_OP_MODRDN	0x020
112#define SOCK_OP_ADD		0x040
113#define SOCK_OP_DELETE	0x080
114#define SOCK_OP_EXTENDED	0x100
115
116#define SOCK_REP_RESULT	0x001
117#define SOCK_REP_SEARCH	0x002
118
119static slap_verbmasks bs_exts[] = {
120	{ BER_BVC("binddn"), SOCK_EXT_BINDDN },
121	{ BER_BVC("peername"), SOCK_EXT_PEERNAME },
122	{ BER_BVC("ssf"), SOCK_EXT_SSF },
123	{ BER_BVC("connid"), SOCK_EXT_CONNID },
124	{ BER_BVNULL, 0 }
125};
126
127static slap_verbmasks ov_ops[] = {
128	{ BER_BVC("bind"), SOCK_OP_BIND },
129	{ BER_BVC("unbind"), SOCK_OP_UNBIND },
130	{ BER_BVC("search"), SOCK_OP_SEARCH },
131	{ BER_BVC("compare"), SOCK_OP_COMPARE },
132	{ BER_BVC("modify"), SOCK_OP_MODIFY },
133	{ BER_BVC("modrdn"), SOCK_OP_MODRDN },
134	{ BER_BVC("add"), SOCK_OP_ADD },
135	{ BER_BVC("delete"), SOCK_OP_DELETE },
136	{ BER_BVC("extended"), SOCK_OP_EXTENDED },
137	{ BER_BVNULL, 0 }
138};
139
140static slap_verbmasks ov_resps[] = {
141	{ BER_BVC("result"), SOCK_REP_RESULT },
142	{ BER_BVC("search"), SOCK_REP_SEARCH },
143	{ BER_BVNULL, 0 }
144};
145
146static int
147bs_cf_gen( ConfigArgs *c )
148{
149	struct sockinfo	*si;
150	int rc;
151
152	if ( c->be && c->table == Cft_Database )
153		si = c->be->be_private;
154	else if ( c->bi )
155		si = c->bi->bi_private;
156	else
157		return ARG_BAD_CONF;
158
159	if ( c->op == SLAP_CONFIG_EMIT ) {
160		switch( c->type ) {
161		case BS_EXT:
162			return mask_to_verbs( bs_exts, si->si_extensions, &c->rvalue_vals );
163		case BS_OPS:
164			return mask_to_verbs( ov_ops, si->si_ops, &c->rvalue_vals );
165		case BS_RESP:
166			return mask_to_verbs( ov_resps, si->si_resps, &c->rvalue_vals );
167		case BS_DNPAT:
168			value_add_one( &c->rvalue_vals, &si->si_dnpatstr );
169			return 0;
170		}
171	} else if ( c->op == LDAP_MOD_DELETE ) {
172		switch( c->type ) {
173		case BS_EXT:
174			if ( c->valx < 0 ) {
175				si->si_extensions = 0;
176				rc = 0;
177			} else {
178				slap_mask_t dels = 0;
179				rc = verbs_to_mask( c->argc, c->argv, bs_exts, &dels );
180				if ( rc == 0 )
181					si->si_extensions ^= dels;
182			}
183			return rc;
184		case BS_OPS:
185			if ( c->valx < 0 ) {
186				si->si_ops = 0;
187				rc = 0;
188			} else {
189				slap_mask_t dels = 0;
190				rc = verbs_to_mask( c->argc, c->argv, ov_ops, &dels );
191				if ( rc == 0 )
192					si->si_ops ^= dels;
193			}
194			return rc;
195		case BS_RESP:
196			if ( c->valx < 0 ) {
197				si->si_resps = 0;
198				rc = 0;
199			} else {
200				slap_mask_t dels = 0;
201				rc = verbs_to_mask( c->argc, c->argv, ov_resps, &dels );
202				if ( rc == 0 )
203					si->si_resps ^= dels;
204			}
205			return rc;
206		case BS_DNPAT:
207			regfree( &si->si_dnpat );
208			ch_free( si->si_dnpatstr.bv_val );
209			BER_BVZERO( &si->si_dnpatstr );
210			return 0;
211		}
212
213	} else {
214		switch( c->type ) {
215		case BS_EXT:
216			return verbs_to_mask( c->argc, c->argv, bs_exts, &si->si_extensions );
217		case BS_OPS:
218			return verbs_to_mask( c->argc, c->argv, ov_ops, &si->si_ops );
219		case BS_RESP:
220			return verbs_to_mask( c->argc, c->argv, ov_resps, &si->si_resps );
221		case BS_DNPAT:
222			if ( !regcomp( &si->si_dnpat, c->argv[1], REG_EXTENDED|REG_ICASE|REG_NOSUB )) {
223				ber_str2bv( c->argv[1], 0, 1, &si->si_dnpatstr );
224				return 0;
225			} else {
226				return 1;
227			}
228		}
229	}
230	return 1;
231}
232
233int
234sock_back_init_cf( BackendInfo *bi )
235{
236	int rc;
237	bi->bi_cf_ocs = bsocs;
238
239	rc = config_register_schema( bscfg, bsocs );
240	if ( !rc )
241		rc = sock_over_setup();
242	return rc;
243}
244
245/* sock overlay wrapper */
246static slap_overinst sockover;
247
248static int sock_over_db_init( Backend *be, struct config_reply_s *cr );
249static int sock_over_db_destroy( Backend *be, struct config_reply_s *cr );
250
251static BI_op_bind *sockfuncs[] = {
252	sock_back_bind,
253	sock_back_unbind,
254	sock_back_search,
255	sock_back_compare,
256	sock_back_modify,
257	sock_back_modrdn,
258	sock_back_add,
259	sock_back_delete,
260	0,                    /* abandon not supported */
261	sock_back_extended
262};
263
264static const int sockopflags[] = {
265	SOCK_OP_BIND,
266	SOCK_OP_UNBIND,
267	SOCK_OP_SEARCH,
268	SOCK_OP_COMPARE,
269	SOCK_OP_MODIFY,
270	SOCK_OP_MODRDN,
271	SOCK_OP_ADD,
272	SOCK_OP_DELETE,
273	0,                    /* abandon not supported */
274	SOCK_OP_EXTENDED
275};
276
277static int sock_over_op(
278	Operation *op,
279	SlapReply *rs
280)
281{
282	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
283	void *private = op->o_bd->be_private;
284	slap_callback *sc;
285	struct sockinfo	*si;
286	slap_operation_t which;
287
288	switch (op->o_tag) {
289	case LDAP_REQ_BIND:	which = op_bind; break;
290	case LDAP_REQ_UNBIND:	which = op_unbind; break;
291	case LDAP_REQ_SEARCH:	which = op_search; break;
292	case LDAP_REQ_COMPARE:	which = op_compare; break;
293	case LDAP_REQ_MODIFY:	which = op_modify; break;
294	case LDAP_REQ_MODRDN:	which = op_modrdn; break;
295	case LDAP_REQ_ADD:	which = op_add; break;
296	case LDAP_REQ_DELETE:	which = op_delete; break;
297	case LDAP_REQ_EXTENDED:	which = op_extended; break;
298	default:
299		return SLAP_CB_CONTINUE;
300	}
301	si = on->on_bi.bi_private;
302	if ( !(si->si_ops & sockopflags[which]))
303		return SLAP_CB_CONTINUE;
304
305	if ( !BER_BVISEMPTY( &si->si_dnpatstr ) &&
306		regexec( &si->si_dnpat, op->o_req_ndn.bv_val, 0, NULL, 0 ))
307		return SLAP_CB_CONTINUE;
308
309	op->o_bd->be_private = si;
310	sc = op->o_callback;
311	op->o_callback = NULL;
312	sockfuncs[which]( op, rs );
313	op->o_bd->be_private = private;
314	op->o_callback = sc;
315	return rs->sr_err;
316}
317
318static int
319sock_over_response( Operation *op, SlapReply *rs )
320{
321	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
322	struct sockinfo *si = (struct sockinfo *)on->on_bi.bi_private;
323	FILE *fp;
324
325	if ( rs->sr_type == REP_RESULT ) {
326		if ( !( si->si_resps & SOCK_REP_RESULT ))
327			return SLAP_CB_CONTINUE;
328	} else if ( rs->sr_type == REP_SEARCH ) {
329		if ( !( si->si_resps & SOCK_REP_SEARCH ))
330			return SLAP_CB_CONTINUE;
331	} else
332		return SLAP_CB_CONTINUE;
333
334	if (( fp = opensock( si->si_sockpath )) == NULL )
335		return SLAP_CB_CONTINUE;
336
337	if ( rs->sr_type == REP_RESULT ) {
338		/* write out the result */
339		fprintf( fp, "RESULT\n" );
340		fprintf( fp, "msgid: %ld\n", (long) op->o_msgid );
341		sock_print_conn( fp, op->o_conn, si );
342		fprintf( fp, "code: %d\n", rs->sr_err );
343		if ( rs->sr_matched )
344			fprintf( fp, "matched: %s\n", rs->sr_matched );
345		if (rs->sr_text )
346			fprintf( fp, "info: %s\n", rs->sr_text );
347	} else {
348		/* write out the search entry */
349		int len;
350		fprintf( fp, "ENTRY\n" );
351		fprintf( fp, "msgid: %ld\n", (long) op->o_msgid );
352		sock_print_conn( fp, op->o_conn, si );
353		ldap_pvt_thread_mutex_lock( &entry2str_mutex );
354		fprintf( fp, "%s", entry2str( rs->sr_entry, &len ) );
355		ldap_pvt_thread_mutex_unlock( &entry2str_mutex );
356	}
357	fprintf( fp, "\n" );
358	fclose( fp );
359
360	return SLAP_CB_CONTINUE;
361}
362
363static int
364sock_over_setup()
365{
366	int rc;
367
368	sockover.on_bi.bi_type = "sock";
369	sockover.on_bi.bi_db_init = sock_over_db_init;
370	sockover.on_bi.bi_db_destroy = sock_over_db_destroy;
371
372	sockover.on_bi.bi_op_bind = sock_over_op;
373	sockover.on_bi.bi_op_unbind = sock_over_op;
374	sockover.on_bi.bi_op_search = sock_over_op;
375	sockover.on_bi.bi_op_compare = sock_over_op;
376	sockover.on_bi.bi_op_modify = sock_over_op;
377	sockover.on_bi.bi_op_modrdn = sock_over_op;
378	sockover.on_bi.bi_op_add = sock_over_op;
379	sockover.on_bi.bi_op_delete = sock_over_op;
380	sockover.on_bi.bi_extended = sock_over_op;
381	sockover.on_response = sock_over_response;
382
383	sockover.on_bi.bi_cf_ocs = osocs;
384
385	rc = config_register_schema( bscfg, osocs );
386	if ( rc ) return rc;
387
388	return overlay_register( &sockover );
389}
390
391static int
392sock_over_db_init(
393    Backend	*be,
394	struct config_reply_s *cr
395)
396{
397	slap_overinst	*on = (slap_overinst *)be->bd_info;
398	void *private = be->be_private;
399	void *cf_ocs = be->be_cf_ocs;
400	int rc;
401
402	be->be_private = NULL;
403	rc = sock_back_db_init( be, cr );
404	on->on_bi.bi_private = be->be_private;
405	be->be_private = private;
406	be->be_cf_ocs = cf_ocs;
407	return rc;
408}
409
410static int
411sock_over_db_destroy(
412    Backend	*be,
413	struct config_reply_s *cr
414)
415{
416	slap_overinst	*on = (slap_overinst *)be->bd_info;
417	void *private = be->be_private;
418	int rc;
419
420	be->be_private = on->on_bi.bi_private;
421	rc = sock_back_db_destroy( be, cr );
422	on->on_bi.bi_private = be->be_private;
423	be->be_private = private;
424	return rc;
425}
426