2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 2002-2004 The OpenLDAP Foundation.
5 * Portions Copyright 1997,2002-2003 IBM Corporation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
17 * This work was initially developed by IBM Corporation for use in
18 * IBM products and subsequently ported to OpenLDAP Software by
19 * Steve Omrani. Additional significant contributors include:
24 #include <ldap_pvt_thread.h>
29 * Note: if ltdl.h is not available, slapi should not be compiled
33 static int slapi_int_load_plugin( Slapi_PBlock *, const char *, const char *, int,
34 SLAPI_FUNC *, lt_dlhandle * );
36 /* pointer to link list of extended objects */
37 static ExtendedOp *pGExtendedOps = NULL;
38 /* global plugins not associated with a specific backend */
39 static Slapi_PBlock *pGPlugins = NULL;
41 /*********************************************************************
42 * Function Name: plugin_pblock_new
44 * Description: This routine creates a new Slapi_PBlock structure,
45 * loads in the plugin module and executes the init
46 * function provided by the module.
48 * Input: type - type of the plugin, such as SASL, database, etc.
49 * path - the loadpath to load the module in
50 * initfunc - name of the plugin function to execute first
51 * argc - number of arguements
52 * argv[] - an array of char pointers point to
53 * the arguments passed in via
54 * the configuration file.
58 * Return Values: a pointer to a newly created Slapi_PBlock structrue or
59 * NULL - function failed
62 *********************************************************************/
72 Slapi_PBlock *pPlugin = NULL;
73 Slapi_PluginDesc *pPluginDesc = NULL;
74 lt_dlhandle hdLoadHandle;
77 pPlugin = slapi_pblock_new();
78 if ( pPlugin == NULL ) {
83 rc = slapi_pblock_set( pPlugin, SLAPI_PLUGIN_TYPE, (void *)type );
88 rc = slapi_pblock_set( pPlugin, SLAPI_PLUGIN_ARGC, (void *)argc );
93 rc = slapi_pblock_set( pPlugin, SLAPI_PLUGIN_ARGV, (void *)argv );
98 rc = slapi_int_load_plugin( pPlugin, path, initfunc, TRUE, NULL, &hdLoadHandle );
103 if ( slapi_pblock_get( pPlugin, SLAPI_PLUGIN_DESCRIPTION, (void **)&pPluginDesc ) == 0 &&
104 pPluginDesc != NULL ) {
105 slapi_log_error(SLAPI_LOG_TRACE, "plugin_pblock_new",
106 "Registered plugin %s %s [%s] (%s)\n",
108 pPluginDesc->spd_version,
109 pPluginDesc->spd_vendor,
110 pPluginDesc->spd_description);
114 if ( rc != 0 && pPlugin != NULL ) {
115 slapi_pblock_destroy( pPlugin );
122 /*********************************************************************
123 * Function Name: slapi_int_register_plugin
125 * Description: insert the slapi_pblock structure to the end of the plugin
128 * Input: a pointer to a plugin slapi_pblock structure to be added to
133 * Return Values: LDAP_SUCCESS - successfully inserted.
137 *********************************************************************/
139 slapi_int_register_plugin(
143 Slapi_PBlock *pTmpPB;
144 Slapi_PBlock *pSavePB;
145 int rc = LDAP_SUCCESS;
147 pTmpPB = ( be == NULL ) ? pGPlugins : (Slapi_PBlock *)(be->be_pb);
149 if ( pTmpPB == NULL ) {
151 be->be_pb = (void *)pPB;
155 while ( pTmpPB != NULL && rc == LDAP_SUCCESS ) {
157 rc = slapi_pblock_get( pTmpPB, SLAPI_IBM_PBLOCK,
159 if ( rc != LDAP_SUCCESS ) {
164 if ( rc == LDAP_SUCCESS ) {
165 rc = slapi_pblock_set( pSavePB, SLAPI_IBM_PBLOCK,
167 if ( rc != LDAP_SUCCESS ) {
176 /*********************************************************************
177 * Function Name: slapi_int_get_plugins
179 * Description: get the desired type of function pointers defined
182 * Input: the type of the functions to get, such as pre-operation,etc.
186 * Return Values: this routine returns a pointer to an array of function
187 * pointers containing backend-specific plugin functions
188 * followed by global plugin functions
191 *********************************************************************/
193 slapi_int_get_plugins(
196 SLAPI_FUNC **ppFuncPtrs )
199 Slapi_PBlock *pCurrentPB;
201 SLAPI_FUNC *pTmpFuncPtr;
203 int rc = LDAP_SUCCESS;
205 assert( ppFuncPtrs );
208 * First, count the plugins associated with a specific
212 pCurrentPB = (Slapi_PBlock *)be->be_pb;
214 while ( pCurrentPB != NULL && rc == LDAP_SUCCESS ) {
215 rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr );
216 if ( rc == LDAP_SUCCESS ) {
217 if ( FuncPtr != NULL ) {
220 rc = slapi_pblock_get( pCurrentPB,
221 SLAPI_IBM_PBLOCK, &pCurrentPB );
226 if ( rc != LDAP_SUCCESS ) {
231 * Then, count the global plugins.
233 pCurrentPB = pGPlugins;
235 while ( pCurrentPB != NULL && rc == LDAP_SUCCESS ) {
236 rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr );
237 if ( rc == LDAP_SUCCESS ) {
238 if ( FuncPtr != NULL ) {
241 rc = slapi_pblock_get( pCurrentPB,
242 SLAPI_IBM_PBLOCK, &pCurrentPB );
246 if ( rc != LDAP_SUCCESS ) {
257 * Now, build the function pointer array of backend-specific
258 * plugins followed by global plugins.
260 *ppFuncPtrs = pTmpFuncPtr =
261 (SLAPI_FUNC *)ch_malloc( ( numPB + 1 ) * sizeof(SLAPI_FUNC) );
262 if ( ppFuncPtrs == NULL ) {
268 pCurrentPB = (Slapi_PBlock *)be->be_pb;
270 while ( pCurrentPB != NULL && rc == LDAP_SUCCESS ) {
271 rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr );
272 if ( rc == LDAP_SUCCESS ) {
273 if ( FuncPtr != NULL ) {
274 *pTmpFuncPtr = FuncPtr;
277 rc = slapi_pblock_get( pCurrentPB,
278 SLAPI_IBM_PBLOCK, &pCurrentPB );
283 pCurrentPB = pGPlugins;
285 while ( pCurrentPB != NULL && rc == LDAP_SUCCESS ) {
286 rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr );
287 if ( rc == LDAP_SUCCESS ) {
288 if ( FuncPtr != NULL ) {
289 *pTmpFuncPtr = FuncPtr;
292 rc = slapi_pblock_get( pCurrentPB,
293 SLAPI_IBM_PBLOCK, &pCurrentPB );
296 *pTmpFuncPtr = NULL ;
299 if ( rc != LDAP_SUCCESS && *ppFuncPtrs != NULL ) {
300 ch_free( *ppFuncPtrs );
307 /*********************************************************************
308 * Function Name: createExtendedOp
310 * Description: Creates an extended operation structure and
311 * initializes the fields
313 * Return value: A newly allocated structure or NULL
314 ********************************************************************/
320 ret = (ExtendedOp *)ch_malloc(sizeof(ExtendedOp));
322 ret->ext_oid.bv_val = NULL;
323 ret->ext_oid.bv_len = 0;
324 ret->ext_func = NULL;
326 ret->ext_next = NULL;
333 /*********************************************************************
334 * Function Name: slapi_int_unregister_extop
336 * Description: This routine removes the ExtendedOp structures
337 * asscoiated with a particular extended operation
340 * Input: pBE - pointer to a backend structure
341 * opList - pointer to a linked list of extended
342 * operation structures
343 * pPB - pointer to a slapi parameter block
350 *********************************************************************/
352 slapi_int_unregister_extop(
357 ExtendedOp *pTmpExtOp, *backExtOp;
362 assert( pBE != NULL); /* unused */
364 assert( opList != NULL );
365 assert( pPB != NULL );
367 if ( *opList == NULL ) {
371 slapi_pblock_get( pPB, SLAPI_PLUGIN_EXT_OP_OIDLIST, &pTmpOIDs );
372 if ( pTmpOIDs == NULL ) {
376 for ( i = 0; pTmpOIDs[i] != NULL; i++ ) {
379 for ( ; pTmpExtOp != NULL; pTmpExtOp = pTmpExtOp->ext_next) {
381 rc = strcasecmp( pTmpExtOp->ext_oid.bv_val,
384 if ( backExtOp == NULL ) {
385 *opList = pTmpExtOp->ext_next;
388 = pTmpExtOp->ext_next;
391 ch_free( pTmpExtOp );
394 backExtOp = pTmpExtOp;
400 /*********************************************************************
401 * Function Name: slapi_int_register_extop
403 * Description: This routine creates a new ExtendedOp structure, loads
404 * in the extended op module and put the extended op function address
405 * in the structure. The function will not be executed in
408 * Input: pBE - pointer to a backend structure
409 * opList - pointer to a linked list of extended
410 * operation structures
411 * pPB - pointer to a slapi parameter block
415 * Return Value: an LDAP return code
418 *********************************************************************/
420 slapi_int_register_extop(
425 ExtendedOp *pTmpExtOp = NULL;
431 if ( (*opList) == NULL ) {
432 *opList = createExtendedOp();
433 if ( (*opList) == NULL ) {
439 } else { /* Find the end of the list */
440 for ( pTmpExtOp = *opList; pTmpExtOp->ext_next != NULL;
441 pTmpExtOp = pTmpExtOp->ext_next )
443 pTmpExtOp->ext_next = createExtendedOp();
444 if ( pTmpExtOp->ext_next == NULL ) {
448 pTmpExtOp = pTmpExtOp->ext_next;
451 rc = slapi_pblock_get( pPB,SLAPI_PLUGIN_EXT_OP_OIDLIST, &pTmpOIDs );
457 rc = slapi_pblock_get(pPB,SLAPI_PLUGIN_EXT_OP_FN, &tmpFunc);
463 if ( (pTmpOIDs == NULL) || (tmpFunc == NULL) ) {
468 for ( i = 0; pTmpOIDs[i] != NULL; i++ ) {
469 pTmpExtOp->ext_oid.bv_val = pTmpOIDs[i];
470 pTmpExtOp->ext_oid.bv_len = strlen( pTmpOIDs[i] );
471 pTmpExtOp->ext_func = tmpFunc;
472 pTmpExtOp->ext_be = pBE;
473 if ( pTmpOIDs[i + 1] != NULL ) {
474 pTmpExtOp->ext_next = createExtendedOp();
475 if ( pTmpExtOp->ext_next == NULL ) {
479 pTmpExtOp = pTmpExtOp->ext_next;
487 /*********************************************************************
488 * Function Name: slapi_int_get_extop_plugin
490 * Description: This routine gets the function address for a given function
494 * funcName - name of the extended op function, ie. an OID.
496 * Output: pFuncAddr - the function address of the requested function name.
498 * Return Values: a pointer to a newly created ExtendOp structrue or
499 * NULL - function failed
502 *********************************************************************/
504 slapi_int_get_extop_plugin(
505 struct berval *reqoid,
506 SLAPI_FUNC *pFuncAddr )
508 ExtendedOp *pTmpExtOp;
510 assert( reqoid != NULL );
511 assert( pFuncAddr != NULL );
515 if ( pGExtendedOps == NULL ) {
519 pTmpExtOp = pGExtendedOps;
520 while ( pTmpExtOp != NULL ) {
523 rc = strcasecmp( reqoid->bv_val, pTmpExtOp->ext_oid.bv_val );
525 *pFuncAddr = pTmpExtOp->ext_func;
528 pTmpExtOp = pTmpExtOp->ext_next;
531 return ( *pFuncAddr == NULL ? 1 : 0 );
534 /***************************************************************************
535 * This function is similar to slapi_int_get_extop_plugin above. except it returns one OID
536 * per call. It is called from root_dse_info (root_dse.c).
537 * The function is a modified version of get_supported_extop (file extended.c).
538 ***************************************************************************/
540 slapi_int_get_supported_extop( int index )
544 for ( ext = pGExtendedOps ; ext != NULL && --index >= 0;
545 ext = ext->ext_next) {
553 return &ext->ext_oid ;
556 /*********************************************************************
557 * Function Name: slapi_int_load_plugin
559 * Description: This routine loads the specified DLL, gets and executes the init function
563 * pPlugin - a pointer to a Slapi_PBlock struct which will be passed to
564 * the DLL init function.
565 * path - path name of the DLL to be load.
566 * initfunc - either the DLL initialization function or an OID of the
567 * loaded extended operation.
568 * doInit - if it is TRUE, execute the init function, otherwise, save the
569 * function address but not execute it.
571 * Output: pInitFunc - the function address of the loaded function. This param
572 * should be not be null if doInit is FALSE.
573 * pLdHandle - handle returned by lt_dlopen()
575 * Return Values: LDAP_SUCCESS, LDAP_LOCAL_ERROR
578 *********************************************************************/
581 slapi_int_load_plugin(
582 Slapi_PBlock *pPlugin,
584 const char *initfunc,
586 SLAPI_FUNC *pInitFunc,
587 lt_dlhandle *pLdHandle )
589 int rc = LDAP_SUCCESS;
590 SLAPI_FUNC fpInitFunc = NULL;
595 return LDAP_LOCAL_ERROR;
598 /* load in the module */
599 *pLdHandle = lt_dlopen( path );
600 if ( *pLdHandle == NULL ) {
601 return LDAP_LOCAL_ERROR;
604 fpInitFunc = (SLAPI_FUNC)lt_dlsym( *pLdHandle, initfunc );
605 if ( fpInitFunc == NULL ) {
606 lt_dlclose( *pLdHandle );
607 return LDAP_LOCAL_ERROR;
610 if ( doInit == TRUE ) {
611 rc = ( *fpInitFunc )( pPlugin );
612 if ( rc != LDAP_SUCCESS ) {
613 lt_dlclose( *pLdHandle );
617 *pInitFunc = fpInitFunc;
624 * Special support for computed attribute plugins
627 slapi_int_call_plugins(
634 SLAPI_FUNC *pGetPlugin = NULL, *tmpPlugin = NULL;
640 rc = slapi_int_get_plugins( be, funcType, &tmpPlugin );
641 if ( rc != LDAP_SUCCESS || tmpPlugin == NULL ) {
642 /* Nothing to do, front-end should ignore. */
646 for ( pGetPlugin = tmpPlugin ; *pGetPlugin != NULL; pGetPlugin++ ) {
648 * FIXME: we should provide here a sort of sandbox,
649 * to protect from plugin faults; e.g. trap signals
650 * and longjump here, marking the plugin as unsafe for
651 * later executions ...
653 rc = (*pGetPlugin)(pPB);
656 * Only non-postoperation plugins abort processing on
657 * failure (confirmed with SLAPI specification).
659 if ( !SLAPI_PLUGIN_IS_POST_FN( funcType ) && rc != 0 ) {
661 * Plugins generally return negative error codes
662 * to indicate failure, although in the case of
663 * bind plugins they may return SLAPI_BIND_xxx
669 slapi_ch_free( (void **)&tmpPlugin );
675 slapi_int_read_config(
683 int numPluginArgc = 0;
684 char **ppPluginArgv = NULL;
688 "%s: line %d: missing arguments "
689 "in \"plugin <plugin_type> <lib_path> "
690 "<init_function> [<arguments>]\" line\n",
695 if ( strcasecmp( argv[1], "preoperation" ) == 0 ) {
696 iType = SLAPI_PLUGIN_PREOPERATION;
697 } else if ( strcasecmp( argv[1], "postoperation" ) == 0 ) {
698 iType = SLAPI_PLUGIN_POSTOPERATION;
699 } else if ( strcasecmp( argv[1], "extendedop" ) == 0 ) {
700 iType = SLAPI_PLUGIN_EXTENDEDOP;
701 } else if ( strcasecmp( argv[1], "object" ) == 0 ) {
702 iType = SLAPI_PLUGIN_OBJECT;
704 fprintf( stderr, "%s: line %d: invalid plugin type \"%s\".\n",
705 fname, lineno, argv[1] );
709 numPluginArgc = argc - 4;
710 if ( numPluginArgc > 0 ) {
711 ppPluginArgv = &argv[4];
716 if ( iType == SLAPI_PLUGIN_PREOPERATION ||
717 iType == SLAPI_PLUGIN_EXTENDEDOP ||
718 iType == SLAPI_PLUGIN_POSTOPERATION ||
719 iType == SLAPI_PLUGIN_OBJECT ) {
721 Slapi_PBlock *pPlugin;
723 pPlugin = plugin_pblock_new( iType, argv[2], argv[3],
724 numPluginArgc, ppPluginArgv );
725 if (pPlugin == NULL) {
729 if (iType == SLAPI_PLUGIN_EXTENDEDOP) {
730 rc = slapi_int_register_extop(be, &pGExtendedOps, pPlugin);
731 if ( rc != LDAP_SUCCESS ) {
732 slapi_pblock_destroy( pPlugin );
737 rc = slapi_int_register_plugin( be, pPlugin );
738 if ( rc != LDAP_SUCCESS ) {
739 if ( iType == SLAPI_PLUGIN_EXTENDEDOP ) {
740 slapi_int_unregister_extop( be, &pGExtendedOps, pPlugin );
742 slapi_pblock_destroy( pPlugin );
751 slapi_int_initialize(void)
753 if ( ldap_pvt_thread_mutex_init( &slapi_hn_mutex ) ) {
757 if ( ldap_pvt_thread_mutex_init( &slapi_time_mutex ) ) {
761 if ( ldap_pvt_thread_mutex_init( &slapi_printmessage_mutex ) ) {
765 slapi_log_file = ch_strdup( LDAP_RUNDIR LDAP_DIRSEP "errors" );
766 if ( slapi_log_file == NULL ) {
770 if ( slapi_int_init_object_extensions() != 0 ) {