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