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