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( ®istered_extensions.mutex );
182
183 rc = map_extension_type( objectname, &type );
184 if ( rc != 0 ) {
185 ldap_pvt_thread_mutex_unlock( ®istered_extensions.mutex );
186 return rc;
187 }
188
189 *objecttype = (int)type;
190
191 re = ®istered_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( ®istered_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( ®istered_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( ®istered_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( ®istered_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( ®istered_extensions, 0, sizeof( registered_extensions ) );
341
342 if ( ldap_pvt_thread_mutex_init( ®istered_extensions.mutex ) != 0 ) {
343 return -1;
344 }
345
346 return 0;
347 }
348
349 #endif /* LDAP_SLAPI */
350