xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/slapi/slapi_ext.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
1 /*	$NetBSD: slapi_ext.c,v 1.3 2021/08/14 16:15:02 christos Exp $	*/
2 
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 2003-2021 The OpenLDAP Foundation.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in the file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 /* (C) Copyright PADL Software Pty Ltd. 2003
18  * Redistribution and use in source and binary forms, with or without
19  * modification, are permitted provided that this notice is preserved
20  * and that due credit is given to PADL Software Pty Ltd. This software
21  * is provided ``as is'' without express or implied warranty.
22  */
23 /* ACKNOWLEDGEMENTS:
24  * This work was initially developed by Luke Howard for inclusion
25  * in OpenLDAP Software.
26  */
27 
28 #include <sys/cdefs.h>
29 __RCSID("$NetBSD: slapi_ext.c,v 1.3 2021/08/14 16:15:02 christos Exp $");
30 
31 #include "portable.h"
32 
33 #include <ac/string.h>
34 #include <ac/stdarg.h>
35 #include <ac/ctype.h>
36 #include <ac/unistd.h>
37 
38 #ifdef LDAP_SLAPI
39 
40 #include <slap.h>
41 #include <slapi.h>
42 
43 /*
44  * Object extensions
45  *
46  * We only support two types -- connection and operation extensions.
47  * Define more types in slapi.h
48  */
49 
50 /* global state */
51 struct slapi_registered_extension_set {
52 	ldap_pvt_thread_mutex_t mutex;
53 	struct slapi_registered_extension {
54 		int active;
55 		int count;
56 		slapi_extension_constructor_fnptr *constructors;
57 		slapi_extension_destructor_fnptr *destructors;
58 	} extensions[SLAPI_X_EXT_MAX];
59 } registered_extensions;
60 
61 /* per-object state */
62 struct slapi_extension_block {
63 	void **extensions;
64 };
65 
get_extension_block(int objecttype,void * object,struct slapi_extension_block ** eblock,void ** parent)66 static int get_extension_block(int objecttype, void *object, struct slapi_extension_block **eblock, void **parent)
67 {
68 	switch ((slapi_extension_t) objecttype) {
69 	case SLAPI_X_EXT_CONNECTION:
70 		*eblock = ((Connection *)object)->c_extensions;
71 		*parent = NULL;
72 		break;
73 	case SLAPI_X_EXT_OPERATION:
74 		*eblock = ((Operation *)object)->o_hdr->oh_extensions;
75 		*parent = ((Operation *)object)->o_conn;
76 		break;
77 	default:
78 		return -1;
79 		break;
80 	}
81 
82 	if ( *eblock == NULL ) {
83 		return -1;
84 	}
85 
86 	return 0;
87 }
88 
map_extension_type(const char * objectname,slapi_extension_t * type)89 static int map_extension_type(const char *objectname, slapi_extension_t *type)
90 {
91 	if ( strcasecmp( objectname, SLAPI_EXT_CONNECTION ) == 0 ) {
92 		*type = SLAPI_X_EXT_CONNECTION;
93 	} else if ( strcasecmp( objectname, SLAPI_EXT_OPERATION ) == 0 ) {
94 		*type = SLAPI_X_EXT_OPERATION;
95 	} else {
96 		return -1;
97 	}
98 
99 	return 0;
100 }
101 
new_extension(struct slapi_extension_block * eblock,int objecttype,void * object,void * parent,int extensionhandle)102 static void new_extension(struct slapi_extension_block *eblock,
103 	int objecttype, void *object, void *parent,
104 	int extensionhandle )
105 {
106 	slapi_extension_constructor_fnptr constructor;
107 
108 	assert( objecttype < SLAPI_X_EXT_MAX );
109 	assert( extensionhandle < registered_extensions.extensions[objecttype].count );
110 
111 	assert( registered_extensions.extensions[objecttype].constructors != NULL );
112 	constructor = registered_extensions.extensions[objecttype].constructors[extensionhandle];
113 
114 	assert( eblock->extensions[extensionhandle] == NULL );
115 
116 	if ( constructor != NULL ) {
117 		eblock->extensions[extensionhandle] = (*constructor)( object, parent );
118 	} else {
119 		eblock->extensions[extensionhandle] = NULL;
120 	}
121 }
122 
free_extension(struct slapi_extension_block * eblock,int objecttype,void * object,void * parent,int extensionhandle)123 static void free_extension(struct slapi_extension_block *eblock, int objecttype, void *object, void *parent, int extensionhandle )
124 {
125 	slapi_extension_destructor_fnptr destructor;
126 
127 	assert( objecttype < SLAPI_X_EXT_MAX );
128 	assert( extensionhandle < registered_extensions.extensions[objecttype].count );
129 
130 	if ( eblock->extensions[extensionhandle] != NULL ) {
131 		assert( registered_extensions.extensions[objecttype].destructors != NULL );
132 		destructor = registered_extensions.extensions[objecttype].destructors[extensionhandle];
133 		if ( destructor != NULL ) {
134 			(*destructor)( eblock->extensions[extensionhandle], object, parent );
135 		}
136 		eblock->extensions[extensionhandle] = NULL;
137 	}
138 }
139 
slapi_get_object_extension(int objecttype,void * object,int extensionhandle)140 void *slapi_get_object_extension(int objecttype, void *object, int extensionhandle)
141 {
142 	struct slapi_extension_block *eblock;
143 	void *parent;
144 
145 	if ( get_extension_block( objecttype, object, &eblock, &parent ) != 0 ) {
146 		return NULL;
147 	}
148 
149 	if ( extensionhandle < registered_extensions.extensions[objecttype].count ) {
150 		return eblock->extensions[extensionhandle];
151 	}
152 
153 	return NULL;
154 }
155 
slapi_set_object_extension(int objecttype,void * object,int extensionhandle,void * extension)156 void slapi_set_object_extension(int objecttype, void *object, int extensionhandle, void *extension)
157 {
158 	struct slapi_extension_block *eblock;
159 	void *parent;
160 
161 	if ( get_extension_block( objecttype, object, &eblock, &parent ) != 0 ) {
162 		return;
163 	}
164 
165 	if ( extensionhandle < registered_extensions.extensions[objecttype].count ) {
166 		/* free the old one */
167 		free_extension( eblock, objecttype, object, parent, extensionhandle );
168 
169 		/* constructed by caller */
170 		eblock->extensions[extensionhandle] = extension;
171 	}
172 }
173 
slapi_register_object_extension(const char * pluginname,const char * objectname,slapi_extension_constructor_fnptr constructor,slapi_extension_destructor_fnptr destructor,int * objecttype,int * extensionhandle)174 int slapi_register_object_extension(
175 	const char *pluginname,
176 	const char *objectname,
177 	slapi_extension_constructor_fnptr constructor,
178 	slapi_extension_destructor_fnptr destructor,
179 	int *objecttype,
180 	int *extensionhandle)
181 {
182 	int rc;
183 	slapi_extension_t type;
184 	struct slapi_registered_extension *re;
185 
186 	ldap_pvt_thread_mutex_lock( &registered_extensions.mutex );
187 
188 	rc = map_extension_type( objectname, &type );
189 	if ( rc != 0 ) {
190 		ldap_pvt_thread_mutex_unlock( &registered_extensions.mutex );
191 		return rc;
192 	}
193 
194 	*objecttype = (int)type;
195 
196 	re = &registered_extensions.extensions[*objecttype];
197 
198 	*extensionhandle = re->count;
199 
200 	if ( re->active ) {
201 		/* can't add new extensions after objects have been created */
202 		ldap_pvt_thread_mutex_unlock( &registered_extensions.mutex );
203 		return -1;
204 	}
205 
206 	re->count++;
207 
208 	if ( re->constructors == NULL ) {
209 		re->constructors = (slapi_extension_constructor_fnptr *)slapi_ch_calloc( re->count,
210 			sizeof( slapi_extension_constructor_fnptr ) );
211 	} else {
212 		re->constructors = (slapi_extension_constructor_fnptr *)slapi_ch_realloc( (char *)re->constructors,
213 			re->count * sizeof( slapi_extension_constructor_fnptr ) );
214 	}
215 	re->constructors[*extensionhandle] = constructor;
216 
217 	if ( re->destructors == NULL ) {
218 		re->destructors = (slapi_extension_destructor_fnptr *)slapi_ch_calloc( re->count,
219 			sizeof( slapi_extension_destructor_fnptr ) );
220 	} else {
221 		re->destructors = (slapi_extension_destructor_fnptr *)slapi_ch_realloc( (char *)re->destructors,
222 			re->count * sizeof( slapi_extension_destructor_fnptr ) );
223 	}
224 	re->destructors[*extensionhandle] = destructor;
225 
226 	ldap_pvt_thread_mutex_unlock( &registered_extensions.mutex );
227 
228 	return 0;
229 }
230 
slapi_int_create_object_extensions(int objecttype,void * object)231 int slapi_int_create_object_extensions(int objecttype, void *object)
232 {
233 	int i;
234 	struct slapi_extension_block *eblock;
235 	void **peblock;
236 	void *parent;
237 
238 	switch ((slapi_extension_t) objecttype) {
239 	case SLAPI_X_EXT_CONNECTION:
240 		peblock = &(((Connection *)object)->c_extensions);
241 		parent = NULL;
242 		break;
243 	case SLAPI_X_EXT_OPERATION:
244 		peblock = &(((Operation *)object)->o_hdr->oh_extensions);
245 		parent = ((Operation *)object)->o_conn;
246 		break;
247 	default:
248 		return -1;
249 		break;
250 	}
251 
252 	*peblock = NULL;
253 
254 	ldap_pvt_thread_mutex_lock( &registered_extensions.mutex );
255 	if ( registered_extensions.extensions[objecttype].active == 0 ) {
256 		/*
257 		 * once we've created some extensions, no new extensions can
258 		 * be registered.
259 		 */
260 		registered_extensions.extensions[objecttype].active = 1;
261 	}
262 	ldap_pvt_thread_mutex_unlock( &registered_extensions.mutex );
263 
264 	eblock = (struct slapi_extension_block *)slapi_ch_calloc( 1, sizeof(*eblock) );
265 
266 	if ( registered_extensions.extensions[objecttype].count ) {
267 		eblock->extensions = (void **)slapi_ch_calloc( registered_extensions.extensions[objecttype].count, sizeof(void *) );
268 		for ( i = 0; i < registered_extensions.extensions[objecttype].count; i++ ) {
269 			new_extension( eblock, objecttype, object, parent, i );
270 		}
271 	} else {
272 		eblock->extensions = NULL;
273 	}
274 
275 	*peblock = eblock;
276 
277 	return 0;
278 }
279 
slapi_int_free_object_extensions(int objecttype,void * object)280 int slapi_int_free_object_extensions(int objecttype, void *object)
281 {
282 	int i;
283 	struct slapi_extension_block *eblock;
284 	void **peblock;
285 	void *parent;
286 
287 	switch ((slapi_extension_t) objecttype) {
288 	case SLAPI_X_EXT_CONNECTION:
289 		peblock = &(((Connection *)object)->c_extensions);
290 		parent = NULL;
291 		break;
292 	case SLAPI_X_EXT_OPERATION:
293 		peblock = &(((Operation *)object)->o_hdr->oh_extensions);
294 		parent = ((Operation *)object)->o_conn;
295 		break;
296 	default:
297 		return -1;
298 		break;
299 	}
300 
301 	eblock = (struct slapi_extension_block *)*peblock;
302 
303 	if ( eblock != NULL && eblock->extensions != NULL ) {
304 		for ( i = registered_extensions.extensions[objecttype].count - 1; i >= 0; --i ) {
305 			free_extension( eblock, objecttype, object, parent, i );
306 		}
307 
308 		slapi_ch_free( (void **)&eblock->extensions );
309 	}
310 
311 	slapi_ch_free( peblock );
312 
313 	return 0;
314 }
315 
316 /* for reusable object types */
slapi_int_clear_object_extensions(int objecttype,void * object)317 int slapi_int_clear_object_extensions(int objecttype, void *object)
318 {
319 	int i;
320 	struct slapi_extension_block *eblock;
321 	void *parent;
322 
323 	if ( get_extension_block( objecttype, object, &eblock, &parent ) != 0 ) {
324 		return -1;
325 	}
326 
327 	if ( eblock->extensions == NULL ) {
328 		/* no extensions */
329 		return 0;
330 	}
331 
332 	for ( i = registered_extensions.extensions[objecttype].count - 1; i >= 0; --i ) {
333 		free_extension( eblock, objecttype, object, parent, i );
334 	}
335 
336 	for ( i = 0; i < registered_extensions.extensions[objecttype].count; i++ ) {
337 		new_extension( eblock, objecttype, object, parent, i );
338 	}
339 
340 	return 0;
341 }
342 
slapi_int_init_object_extensions(void)343 int slapi_int_init_object_extensions(void)
344 {
345 	memset( &registered_extensions, 0, sizeof( registered_extensions ) );
346 
347 	if ( ldap_pvt_thread_mutex_init( &registered_extensions.mutex ) != 0 ) {
348 		return -1;
349 	}
350 
351 	return 0;
352 }
353 
354 #endif /* LDAP_SLAPI */
355