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 */ 51struct 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 */ 62struct slapi_extension_block { 63 void **extensions; 64}; 65 66static 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 89static 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 102static 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 123static 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 140void *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 156void 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 174int 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 231int 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 280int 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 */ 317int 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 343int 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