2 * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
3 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6 * Portions Copyright IBM Corp. 1997,2002,2003
7 * Redistribution and use in source and binary forms are permitted
8 * provided that this notice is preserved and that due credit is
9 * given to IBM Corporation. This software is provided ``as is''
10 * without express or implied warranty.
14 #include <ldap_pvt_thread.h>
19 * Note: if ltdl.h is not available, slapi should not be compiled
23 static int loadPlugin( Slapi_PBlock *, const char *, const char *, int,
24 SLAPI_FUNC *, lt_dlhandle * );
26 /* pointer to link list of extended objects */
27 static ExtendedOp *pGExtendedOps = NULL;
28 /* global plugins not associated with a specific backend */
29 static Slapi_PBlock *pGPlugins = NULL;
31 /*********************************************************************
32 * Function Name: newPlugin
34 * Description: This routine creates a new Slapi_PBlock structure,
35 * loads in the plugin module and executes the init
36 * function provided by the module.
38 * Input: type - type of the plugin, such as SASL, database, etc.
39 * path - the loadpath to load the module in
40 * initfunc - name of the plugin function to execute first
41 * argc - number of arguements
42 * argv[] - an array of char pointers point to
43 * the arguments passed in via
44 * the configuration file.
48 * Return Values: a pointer to a newly created Slapi_PBlock structrue or
49 * NULL - function failed
52 *********************************************************************/
62 Slapi_PBlock *pPlugin = NULL;
63 Slapi_PluginDesc *pPluginDesc = NULL;
64 lt_dlhandle hdLoadHandle;
67 pPlugin = slapi_pblock_new();
68 if ( pPlugin == NULL ) {
73 rc = slapi_pblock_set( pPlugin, SLAPI_PLUGIN_TYPE, (void *)type );
78 rc = slapi_pblock_set( pPlugin, SLAPI_PLUGIN_ARGC, (void *)argc );
83 rc = slapi_pblock_set( pPlugin, SLAPI_PLUGIN_ARGV, (void *)argv );
88 rc = loadPlugin( pPlugin, path, initfunc, TRUE, NULL, &hdLoadHandle );
93 if ( slapi_pblock_get( pPlugin, SLAPI_PLUGIN_DESCRIPTION, (void **)&pPluginDesc ) == 0 &&
94 pPluginDesc != NULL ) {
95 slapi_log_error(SLAPI_LOG_TRACE, "newPlugin",
96 "Registered plugin %s %s [%s] (%s)\n",
98 pPluginDesc->spd_version,
99 pPluginDesc->spd_vendor,
100 pPluginDesc->spd_description);
104 if ( rc != 0 && pPlugin != NULL ) {
105 slapi_pblock_destroy( pPlugin );
112 /*********************************************************************
113 * Function Name: insertPlugin
115 * Description: insert the slapi_pblock structure to the end of the plugin
118 * Input: a pointer to a plugin slapi_pblock structure to be added to
123 * Return Values: LDAP_SUCCESS - successfully inserted.
127 *********************************************************************/
133 Slapi_PBlock *pTmpPB;
134 Slapi_PBlock *pSavePB;
135 int rc = LDAP_SUCCESS;
137 pTmpPB = ( be == NULL ) ? pGPlugins : (Slapi_PBlock *)(be->be_pb);
139 if ( pTmpPB == NULL ) {
141 be->be_pb = (void *)pPB;
145 while ( pTmpPB != NULL && rc == LDAP_SUCCESS ) {
147 rc = slapi_pblock_get( pTmpPB, SLAPI_IBM_PBLOCK,
149 if ( rc != LDAP_SUCCESS ) {
154 if ( rc == LDAP_SUCCESS ) {
155 rc = slapi_pblock_set( pSavePB, SLAPI_IBM_PBLOCK,
157 if ( rc != LDAP_SUCCESS ) {
166 /*********************************************************************
167 * Function Name: getAllPluginFuncs
169 * Description: get the desired type of function pointers defined
172 * Input: the type of the functions to get, such as pre-operation,etc.
176 * Return Values: this routine returns a pointer to an array of function
177 * pointers containing backend-specific plugin functions
178 * followed by global plugin functions
181 *********************************************************************/
186 SLAPI_FUNC **ppFuncPtrs )
189 Slapi_PBlock *pCurrentPB;
191 SLAPI_FUNC *pTmpFuncPtr;
193 int rc = LDAP_SUCCESS;
195 assert( ppFuncPtrs );
198 * First, count the plugins associated with a specific
202 pCurrentPB = (Slapi_PBlock *)be->be_pb;
204 while ( pCurrentPB != NULL && rc == LDAP_SUCCESS ) {
205 rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr );
206 if ( rc == LDAP_SUCCESS ) {
207 if ( FuncPtr != NULL ) {
210 rc = slapi_pblock_get( pCurrentPB,
211 SLAPI_IBM_PBLOCK, &pCurrentPB );
216 if ( rc != LDAP_SUCCESS ) {
221 * Then, count the global plugins.
223 pCurrentPB = pGPlugins;
225 while ( pCurrentPB != NULL && rc == LDAP_SUCCESS ) {
226 rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr );
227 if ( rc == LDAP_SUCCESS ) {
228 if ( FuncPtr != NULL ) {
231 rc = slapi_pblock_get( pCurrentPB,
232 SLAPI_IBM_PBLOCK, &pCurrentPB );
236 if ( rc != LDAP_SUCCESS ) {
247 * Now, build the function pointer array of backend-specific
248 * plugins followed by global plugins.
250 *ppFuncPtrs = pTmpFuncPtr =
251 (SLAPI_FUNC *)ch_malloc( ( numPB + 1 ) * sizeof(SLAPI_FUNC) );
252 if ( ppFuncPtrs == NULL ) {
258 pCurrentPB = (Slapi_PBlock *)be->be_pb;
260 while ( pCurrentPB != NULL && rc == LDAP_SUCCESS ) {
261 rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr );
262 if ( rc == LDAP_SUCCESS ) {
263 if ( FuncPtr != NULL ) {
264 *pTmpFuncPtr = FuncPtr;
267 rc = slapi_pblock_get( pCurrentPB,
268 SLAPI_IBM_PBLOCK, &pCurrentPB );
273 pCurrentPB = pGPlugins;
275 while ( pCurrentPB != NULL && rc == LDAP_SUCCESS ) {
276 rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr );
277 if ( rc == LDAP_SUCCESS ) {
278 if ( FuncPtr != NULL ) {
279 *pTmpFuncPtr = FuncPtr;
282 rc = slapi_pblock_get( pCurrentPB,
283 SLAPI_IBM_PBLOCK, &pCurrentPB );
286 *pTmpFuncPtr = NULL ;
289 if ( rc != LDAP_SUCCESS && *ppFuncPtrs != NULL ) {
290 ch_free( *ppFuncPtrs );
297 /*********************************************************************
298 * Function Name: createExtendedOp
300 * Description: Creates an extended operation structure and
301 * initializes the fields
303 * Return value: A newly allocated structure or NULL
304 ********************************************************************/
310 ret = (ExtendedOp *)ch_malloc(sizeof(ExtendedOp));
312 ret->ext_oid.bv_val = NULL;
313 ret->ext_oid.bv_len = 0;
314 ret->ext_func = NULL;
316 ret->ext_next = NULL;
323 /*********************************************************************
324 * Function Name: removeExtendedOp
326 * Description: This routine removes the ExtendedOp structures
327 * asscoiated with a particular extended operation
330 * Input: pBE - pointer to a backend structure
331 * opList - pointer to a linked list of extended
332 * operation structures
333 * pPB - pointer to a slapi parameter block
340 *********************************************************************/
347 ExtendedOp *pTmpExtOp, *backExtOp;
352 assert( pBE != NULL); /* unused */
354 assert( opList != NULL );
355 assert( pPB != NULL );
357 if ( *opList == NULL ) {
361 slapi_pblock_get( pPB, SLAPI_PLUGIN_EXT_OP_OIDLIST, &pTmpOIDs );
362 if ( pTmpOIDs == NULL ) {
366 for ( i = 0; pTmpOIDs[i] != NULL; i++ ) {
369 for ( ; pTmpExtOp != NULL; pTmpExtOp = pTmpExtOp->ext_next) {
371 rc = strcasecmp( pTmpExtOp->ext_oid.bv_val,
374 if ( backExtOp == NULL ) {
375 *opList = pTmpExtOp->ext_next;
378 = pTmpExtOp->ext_next;
381 ch_free( pTmpExtOp );
384 backExtOp = pTmpExtOp;
390 /*********************************************************************
391 * Function Name: newExtendedOp
393 * Description: This routine creates a new ExtendedOp structure, loads
394 * in the extended op module and put the extended op function address
395 * in the structure. The function will not be executed in
398 * Input: pBE - pointer to a backend structure
399 * opList - pointer to a linked list of extended
400 * operation structures
401 * pPB - pointer to a slapi parameter block
405 * Return Value: an LDAP return code
408 *********************************************************************/
415 ExtendedOp *pTmpExtOp = NULL;
421 if ( (*opList) == NULL ) {
422 *opList = createExtendedOp();
423 if ( (*opList) == NULL ) {
429 } else { /* Find the end of the list */
430 for ( pTmpExtOp = *opList; pTmpExtOp->ext_next != NULL;
431 pTmpExtOp = pTmpExtOp->ext_next )
433 pTmpExtOp->ext_next = createExtendedOp();
434 if ( pTmpExtOp->ext_next == NULL ) {
438 pTmpExtOp = pTmpExtOp->ext_next;
441 rc = slapi_pblock_get( pPB,SLAPI_PLUGIN_EXT_OP_OIDLIST, &pTmpOIDs );
442 if ( rc != LDAP_SUCCESS ) {
447 rc = slapi_pblock_get(pPB,SLAPI_PLUGIN_EXT_OP_FN, &tmpFunc);
453 if ( (pTmpOIDs == NULL) || (tmpFunc == NULL) ) {
458 for ( i = 0; pTmpOIDs[i] != NULL; i++ ) {
459 pTmpExtOp->ext_oid.bv_val = pTmpOIDs[i];
460 pTmpExtOp->ext_oid.bv_len = strlen( pTmpOIDs[i] );
461 pTmpExtOp->ext_func = tmpFunc;
462 pTmpExtOp->ext_be = pBE;
463 if ( pTmpOIDs[i + 1] != NULL ) {
464 pTmpExtOp->ext_next = createExtendedOp();
465 if ( pTmpExtOp->ext_next == NULL ) {
469 pTmpExtOp = pTmpExtOp->ext_next;
477 /*********************************************************************
478 * Function Name: getPluginFunc
480 * Description: This routine gets the function address for a given function
484 * funcName - name of the extended op function, ie. an OID.
486 * Output: pFuncAddr - the function address of the requested function name.
488 * Return Values: a pointer to a newly created ExtendOp structrue or
489 * NULL - function failed
492 *********************************************************************/
495 struct berval *reqoid,
496 SLAPI_FUNC *pFuncAddr )
498 ExtendedOp *pTmpExtOp;
500 assert( reqoid != NULL );
501 assert( pFuncAddr != NULL );
505 if ( pGExtendedOps == NULL ) {
509 pTmpExtOp = pGExtendedOps;
510 while ( pTmpExtOp != NULL ) {
513 rc = strcasecmp( reqoid->bv_val, pTmpExtOp->ext_oid.bv_val );
515 *pFuncAddr = pTmpExtOp->ext_func;
518 pTmpExtOp = pTmpExtOp->ext_next;
521 return ( *pFuncAddr == NULL ? 1 : 0 );
524 /***************************************************************************
525 * This function is similar to getPluginFunc above. except it returns one OID
526 * per call. It is called from root_dse_info (root_dse.c).
527 * The function is a modified version of get_supported_extop (file extended.c).
528 ***************************************************************************/
530 ns_get_supported_extop( int index )
534 for ( ext = pGExtendedOps ; ext != NULL && --index >= 0;
535 ext = ext->ext_next) {
543 return &ext->ext_oid ;
546 /*********************************************************************
547 * Function Name: loadPlugin
549 * Description: This routine loads the specified DLL, gets and executes the init function
553 * pPlugin - a pointer to a Slapi_PBlock struct which will be passed to
554 * the DLL init function.
555 * path - path name of the DLL to be load.
556 * initfunc - either the DLL initialization function or an OID of the
557 * loaded extended operation.
558 * doInit - if it is TRUE, execute the init function, otherwise, save the
559 * function address but not execute it.
561 * Output: pInitFunc - the function address of the loaded function. This param
562 * should be not be null if doInit is FALSE.
563 * pLdHandle - handle returned by lt_dlopen()
565 * Return Values: LDAP_SUCCESS, LDAP_LOCAL_ERROR
568 *********************************************************************/
572 Slapi_PBlock *pPlugin,
574 const char *initfunc,
576 SLAPI_FUNC *pInitFunc,
577 lt_dlhandle *pLdHandle )
579 int rc = LDAP_SUCCESS;
580 SLAPI_FUNC fpInitFunc = NULL;
585 return LDAP_LOCAL_ERROR;
588 /* load in the module */
589 *pLdHandle = lt_dlopen( path );
590 if ( *pLdHandle == NULL ) {
591 return LDAP_LOCAL_ERROR;
594 fpInitFunc = (SLAPI_FUNC)lt_dlsym( *pLdHandle, initfunc );
595 if ( fpInitFunc == NULL ) {
596 lt_dlclose( *pLdHandle );
597 return LDAP_LOCAL_ERROR;
600 if ( doInit == TRUE ) {
601 rc = ( *fpInitFunc )( pPlugin );
602 if ( rc != LDAP_SUCCESS ) {
603 lt_dlclose( *pLdHandle );
607 *pInitFunc = fpInitFunc;
614 * Special support for computed attribute plugins
624 SLAPI_FUNC *pGetPlugin = NULL, *tmpPlugin = NULL;
630 rc = getAllPluginFuncs( be, funcType, &tmpPlugin );
631 if ( rc != LDAP_SUCCESS || tmpPlugin == NULL ) {
632 /* Nothing to do, front-end should ignore. */
636 for ( pGetPlugin = tmpPlugin ; *pGetPlugin != NULL; pGetPlugin++ ) {
638 * FIXME: we should provide here a sort of sandbox,
639 * to protect from plugin faults; e.g. trap signals
640 * and longjump here, marking the plugin as unsafe for
641 * later executions ...
643 rc = (*pGetPlugin)(pPB);
646 * Only non-postoperation plugins abort processing on
647 * failure (confirmed with SLAPI specification).
649 if ( !SLAPI_PLUGIN_IS_POST_FN( funcType ) && rc != 0 ) {
651 * Plugins generally return negative error codes
652 * to indicate failure, although in the case of
653 * bind plugins they may return SLAPI_BIND_xxx
659 slapi_ch_free( (void **)&tmpPlugin );
673 int numPluginArgc = 0;
674 char **ppPluginArgv = NULL;
678 "%s: line %d: missing arguments "
679 "in \"plugin <plugin_type> <lib_path> "
680 "<init_function> [<arguments>]\" line\n",
685 if ( strcasecmp( argv[1], "preoperation" ) == 0 ) {
686 iType = SLAPI_PLUGIN_PREOPERATION;
687 } else if ( strcasecmp( argv[1], "postoperation" ) == 0 ) {
688 iType = SLAPI_PLUGIN_POSTOPERATION;
689 } else if ( strcasecmp( argv[1], "extendedop" ) == 0 ) {
690 iType = SLAPI_PLUGIN_EXTENDEDOP;
691 } else if ( strcasecmp( argv[1], "object" ) == 0 ) {
692 iType = SLAPI_PLUGIN_OBJECT;
694 fprintf( stderr, "%s: line %d: invalid plugin type \"%s\".\n",
695 fname, lineno, argv[1] );
699 numPluginArgc = argc - 4;
700 if ( numPluginArgc > 0 ) {
701 ppPluginArgv = &argv[4];
706 if ( iType == SLAPI_PLUGIN_PREOPERATION ||
707 iType == SLAPI_PLUGIN_EXTENDEDOP ||
708 iType == SLAPI_PLUGIN_POSTOPERATION ||
709 iType == SLAPI_PLUGIN_OBJECT ) {
711 Slapi_PBlock *pPlugin;
713 pPlugin = newPlugin( iType, argv[2], argv[3],
714 numPluginArgc, ppPluginArgv );
715 if (pPlugin == NULL) {
719 if (iType == SLAPI_PLUGIN_EXTENDEDOP) {
720 rc = newExtendedOp(be, &pGExtendedOps, pPlugin);
721 if ( rc != LDAP_SUCCESS ) {
722 slapi_pblock_destroy( pPlugin );
727 rc = insertPlugin( be, pPlugin );
728 if ( rc != LDAP_SUCCESS ) {
729 if ( iType == SLAPI_PLUGIN_EXTENDEDOP ) {
730 removeExtendedOp( be, &pGExtendedOps, pPlugin );
732 slapi_pblock_destroy( pPlugin );
743 if ( ldap_pvt_thread_mutex_init( &slapi_hn_mutex ) ) {
747 if ( ldap_pvt_thread_mutex_init( &slapi_time_mutex ) ) {
751 if ( ldap_pvt_thread_mutex_init( &slapi_printmessage_mutex ) ) {
755 slapi_log_file = ch_strdup( LDAP_RUNDIR LDAP_DIRSEP "errors" );
756 if ( slapi_log_file == NULL ) {
760 if ( slapi_x_init_object_extensions() != 0 ) {