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