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-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 /* 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 
28 overlay		allop
29 allop-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 
55 typedef struct allop_t {
56 	struct berval	ao_ndn;
57 	int		ao_scope;
58 } allop_t;
59 
60 static int
allop_db_config(BackendDB * be,const char * fname,int lineno,int argc,char ** argv)61 allop_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 
143 static int
allop_db_destroy(BackendDB * be,ConfigReply * cr)144 allop_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 
160 static int
allop_op_search(Operation * op,SlapReply * rs)161 allop_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 
241 static slap_overinst 		allop;
242 
243 int
allop_init()244 allop_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 
256 int
init_module(int argc,char * argv[])257 init_module( int argc, char *argv[] )
258 {
259 	return allop_init();
260 }
261 
262