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