Home | History | Annotate | Line # | Download | only in slapi
      1 /*	$NetBSD: slapi_ext.c,v 1.4 2025/09/05 21:16:33 christos Exp $	*/
      2 
      3 /* $OpenLDAP$ */
      4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      5  *
      6  * Copyright 2003-2024 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.4 2025/09/05 21:16:33 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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 */
    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 
    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