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( ®istered_extensions.mutex );
187
188 rc = map_extension_type( objectname, &type );
189 if ( rc != 0 ) {
190 ldap_pvt_thread_mutex_unlock( ®istered_extensions.mutex );
191 return rc;
192 }
193
194 *objecttype = (int)type;
195
196 re = ®istered_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( ®istered_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( ®istered_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( ®istered_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( ®istered_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( ®istered_extensions, 0, sizeof( registered_extensions ) );
346
347 if ( ldap_pvt_thread_mutex_init( ®istered_extensions.mutex ) != 0 ) {
348 return -1;
349 }
350
351 return 0;
352 }
353
354 #endif /* LDAP_SLAPI */
355