1/* allop.c - returns all operational attributes when appropriate */
2/* $OpenLDAP$ */
3/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 *
5 * Copyright 2005-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 Pierangelo Masarati for inclusion in
18 * OpenLDAP Software.
19 */
20
21/*
22 * The intended usage is as a global overlay for use with those clients
23 * that do not make use of the RFC3673 allOp ("+") in the requested
24 * attribute list, but expect all operational attributes to be returned.
25 * Usage: add
26 *
27
28overlay		allop
29allop-URI	<ldapURI>
30
31 *
32 * if the allop-URI is not given, the rootDSE, i.e. "ldap:///??base",
33 * is assumed.
34 */
35
36#include "portable.h"
37
38#include <stdio.h>
39#include <ac/string.h>
40
41#include "slap.h"
42#include "config.h"
43
44#define	SLAP_OVER_VERSION_REQUIRE(major,minor,patch) \
45	( \
46		( LDAP_VENDOR_VERSION_MAJOR == X || LDAP_VENDOR_VERSION_MAJOR >= (major) ) \
47		&& ( LDAP_VENDOR_VERSION_MINOR == X || LDAP_VENDOR_VERSION_MINOR >= (minor) ) \
48		&& ( LDAP_VENDOR_VERSION_PATCH == X || LDAP_VENDOR_VERSION_PATCH >= (patch) ) \
49	)
50
51#if !SLAP_OVER_VERSION_REQUIRE(2,3,0)
52#error "version mismatch"
53#endif
54
55typedef struct allop_t {
56	struct berval	ao_ndn;
57	int		ao_scope;
58} allop_t;
59
60static int
61allop_db_config(
62	BackendDB	*be,
63	const char	*fname,
64	int		lineno,
65	int		argc,
66	char		**argv )
67{
68	slap_overinst	*on = (slap_overinst *)be->bd_info;
69	allop_t		*ao = (allop_t *)on->on_bi.bi_private;
70
71	if ( strcasecmp( argv[ 0 ], "allop-uri" ) == 0 ) {
72		LDAPURLDesc	*lud;
73		struct berval	dn,
74				ndn;
75		int		scope,
76				rc = LDAP_SUCCESS;
77
78		if ( argc != 2 ) {
79			fprintf( stderr, "%s line %d: "
80				"need exactly 1 arg "
81				"in \"allop-uri <ldapURI>\" "
82				"directive.\n",
83				fname, lineno );
84			return 1;
85		}
86
87		if ( ldap_url_parse( argv[ 1 ], &lud ) != LDAP_URL_SUCCESS ) {
88			return -1;
89		}
90
91		scope = lud->lud_scope;
92		if ( scope == LDAP_SCOPE_DEFAULT ) {
93			scope = LDAP_SCOPE_BASE;
94		}
95
96		if ( lud->lud_dn == NULL || lud->lud_dn[ 0 ] == '\0' ) {
97			if ( scope == LDAP_SCOPE_BASE ) {
98				BER_BVZERO( &ndn );
99
100			} else {
101				ber_str2bv( "", 0, 1, &ndn );
102			}
103
104		} else {
105
106			ber_str2bv( lud->lud_dn, 0, 0, &dn );
107			rc = dnNormalize( 0, NULL, NULL, &dn, &ndn, NULL );
108		}
109
110		ldap_free_urldesc( lud );
111		if ( rc != LDAP_SUCCESS ) {
112			return -1;
113		}
114
115		if ( BER_BVISNULL( &ndn ) ) {
116			/* rootDSE */
117			if ( ao != NULL ) {
118				ch_free( ao->ao_ndn.bv_val );
119				ch_free( ao );
120				on->on_bi.bi_private = NULL;
121			}
122
123		} else {
124			if ( ao == NULL ) {
125				ao = ch_calloc( 1, sizeof( allop_t ) );
126				on->on_bi.bi_private = (void *)ao;
127
128			} else {
129				ch_free( ao->ao_ndn.bv_val );
130			}
131
132			ao->ao_ndn = ndn;
133			ao->ao_scope = scope;
134		}
135
136	} else {
137		return SLAP_CONF_UNKNOWN;
138	}
139
140	return 0;
141}
142
143static int
144allop_db_destroy( BackendDB *be, ConfigReply *cr )
145{
146	slap_overinst	*on = (slap_overinst *)be->bd_info;
147	allop_t		*ao = (allop_t *)on->on_bi.bi_private;
148
149	if ( ao != NULL ) {
150		assert( !BER_BVISNULL( &ao->ao_ndn ) );
151
152		ch_free( ao->ao_ndn.bv_val );
153		ch_free( ao );
154		on->on_bi.bi_private = NULL;
155	}
156
157	return 0;
158}
159
160static int
161allop_op_search( Operation *op, SlapReply *rs )
162{
163	slap_overinst	*on = (slap_overinst *)op->o_bd->bd_info;
164	allop_t		*ao = (allop_t *)on->on_bi.bi_private;
165
166	slap_mask_t	mask;
167	int		i,
168			add_allUser = 0;
169
170	if ( ao == NULL ) {
171		if ( !BER_BVISEMPTY( &op->o_req_ndn )
172			|| op->ors_scope != LDAP_SCOPE_BASE )
173		{
174			return SLAP_CB_CONTINUE;
175		}
176
177	} else {
178		if ( !dnIsSuffix( &op->o_req_ndn, &ao->ao_ndn ) ) {
179			return SLAP_CB_CONTINUE;
180		}
181
182		switch ( ao->ao_scope ) {
183		case LDAP_SCOPE_BASE:
184			if ( op->o_req_ndn.bv_len != ao->ao_ndn.bv_len ) {
185				return SLAP_CB_CONTINUE;
186			}
187			break;
188
189		case LDAP_SCOPE_ONELEVEL:
190			if ( op->ors_scope == LDAP_SCOPE_BASE ) {
191				struct berval	rdn = op->o_req_ndn;
192
193				rdn.bv_len -= ao->ao_ndn.bv_len + STRLENOF( "," );
194				if ( !dnIsOneLevelRDN( &rdn ) ) {
195					return SLAP_CB_CONTINUE;
196				}
197
198				break;
199			}
200			return SLAP_CB_CONTINUE;
201
202		case LDAP_SCOPE_SUBTREE:
203			break;
204		}
205	}
206
207	mask = slap_attr_flags( op->ors_attrs );
208	if ( SLAP_OPATTRS( mask ) ) {
209		return SLAP_CB_CONTINUE;
210	}
211
212	if ( !SLAP_USERATTRS( mask ) ) {
213		return SLAP_CB_CONTINUE;
214	}
215
216	i = 0;
217	if ( op->ors_attrs == NULL ) {
218		add_allUser = 1;
219
220	} else {
221		for ( ; !BER_BVISNULL( &op->ors_attrs[ i ].an_name ); i++ )
222			;
223	}
224
225	op->ors_attrs = op->o_tmprealloc( op->ors_attrs,
226		sizeof( AttributeName ) * ( i + add_allUser + 2 ),
227		op->o_tmpmemctx );
228
229	if ( add_allUser ) {
230		op->ors_attrs[ i ] = slap_anlist_all_user_attributes[ 0 ];
231		i++;
232	}
233
234	op->ors_attrs[ i ] = slap_anlist_all_operational_attributes[ 0 ];
235
236	BER_BVZERO( &op->ors_attrs[ i + 1 ].an_name );
237
238	return SLAP_CB_CONTINUE;
239}
240
241static slap_overinst 		allop;
242
243int
244allop_init()
245{
246	allop.on_bi.bi_type = "allop";
247
248	allop.on_bi.bi_db_config = allop_db_config;
249	allop.on_bi.bi_db_destroy = allop_db_destroy;
250
251	allop.on_bi.bi_op_search = allop_op_search;
252
253	return overlay_register( &allop );
254}
255
256int
257init_module( int argc, char *argv[] )
258{
259	return allop_init();
260}
261
262