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, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
9 * Public License, version 2.7 or later.
13 #include <ldap_pvt_thread.h>
18 * Note: if ltdl.h is not available, slapi should not be compiled
22 static int loadPlugin( Slapi_PBlock *, const char *, const char *, int,
23 SLAPI_FUNC *, lt_dlhandle * );
25 /* pointer to link list of extended objects */
26 static ExtendedOp *pGExtendedOps = NULL;
27 /* global plugins not associated with a specific backend */
28 static Slapi_PBlock *pGPlugins = NULL;
30 /*********************************************************************
31 * Function Name: newPlugin
33 * Description: This routine creates a new Slapi_PBlock structure,
34 * loads in the plugin module and executes the init
35 * function provided by the module.
37 * Input: type - type of the plugin, such as SASL, database, etc.
38 * path - the loadpath to load the module in
39 * initfunc - name of the plugin function to execute first
40 * argc - number of arguements
41 * argv[] - an array of char pointers point to
42 * the arguments passed in via
43 * the configuration file.
47 * Return Values: a pointer to a newly created Slapi_PBlock structrue or
48 * NULL - function failed
51 *********************************************************************/
61 Slapi_PBlock *pPlugin = NULL;
62 Slapi_PluginDesc *pPluginDesc = NULL;
63 lt_dlhandle hdLoadHandle;
66 pPlugin = slapi_pblock_new();
67 if ( pPlugin == NULL ) {
72 rc = slapi_pblock_set( pPlugin, SLAPI_PLUGIN_TYPE, (void *)type );
77 rc = slapi_pblock_set( pPlugin, SLAPI_PLUGIN_ARGC, (void *)argc );
82 rc = slapi_pblock_set( pPlugin, SLAPI_PLUGIN_ARGV, (void *)argv );
87 rc = loadPlugin( pPlugin, path, initfunc, TRUE, NULL, &hdLoadHandle );
92 if ( slapi_pblock_get( pPlugin, SLAPI_PLUGIN_DESCRIPTION, (void **)&pPluginDesc ) == 0 &&
93 pPluginDesc != NULL ) {
94 slapi_log_error(SLAPI_LOG_TRACE, "newPlugin",
95 "Registered plugin %s %s [%s] (%s)\n",
97 pPluginDesc->spd_version,
98 pPluginDesc->spd_vendor,
99 pPluginDesc->spd_description);
103 if ( rc != 0 && pPlugin != NULL ) {
104 slapi_pblock_destroy( pPlugin );
111 /*********************************************************************
112 * Function Name: insertPlugin
114 * Description: insert the slapi_pblock structure to the end of the plugin
117 * Input: a pointer to a plugin slapi_pblock structure to be added to
122 * Return Values: LDAP_SUCCESS - successfully inserted.
126 *********************************************************************/
132 Slapi_PBlock *pTmpPB;
133 Slapi_PBlock *pSavePB;
134 int rc = LDAP_SUCCESS;
136 pTmpPB = ( be == NULL ) ? pGPlugins : (Slapi_PBlock *)(be->be_pb);
138 if ( pTmpPB == NULL ) {
140 be->be_pb = (void *)pPB;
144 while ( pTmpPB != NULL && rc == LDAP_SUCCESS ) {
146 rc = slapi_pblock_get( pTmpPB, SLAPI_IBM_PBLOCK,
148 if ( rc != LDAP_SUCCESS ) {
153 if ( rc == LDAP_SUCCESS ) {
154 rc = slapi_pblock_set( pSavePB, SLAPI_IBM_PBLOCK,
156 if ( rc != LDAP_SUCCESS ) {
165 /*********************************************************************
166 * Function Name: getAllPluginFuncs
168 * Description: get the desired type of function pointers defined
171 * Input: the type of the functions to get, such as pre-operation,etc.
175 * Return Values: this routine returns a pointer to an array of function
176 * pointers containing backend-specific plugin functions
177 * followed by global plugin functions
180 *********************************************************************/
185 SLAPI_FUNC **ppFuncPtrs )
188 Slapi_PBlock *pCurrentPB;
190 SLAPI_FUNC *pTmpFuncPtr;
192 int rc = LDAP_SUCCESS;
194 assert( ppFuncPtrs );
197 * First, count the plugins associated with a specific
201 pCurrentPB = (Slapi_PBlock *)be->be_pb;
203 while ( pCurrentPB != NULL && rc == LDAP_SUCCESS ) {
204 rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr );
205 if ( rc == LDAP_SUCCESS ) {
206 if ( FuncPtr != NULL ) {
209 rc = slapi_pblock_get( pCurrentPB,
210 SLAPI_IBM_PBLOCK, &pCurrentPB );
215 if ( rc != LDAP_SUCCESS ) {
220 * Then, count the global plugins.
222 pCurrentPB = pGPlugins;
224 while ( pCurrentPB != NULL && rc == LDAP_SUCCESS ) {
225 rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr );
226 if ( rc == LDAP_SUCCESS ) {
227 if ( FuncPtr != NULL ) {
230 rc = slapi_pblock_get( pCurrentPB,
231 SLAPI_IBM_PBLOCK, &pCurrentPB );
235 if ( rc != LDAP_SUCCESS ) {
246 * Now, build the function pointer array of backend-specific
247 * plugins followed by global plugins.
249 *ppFuncPtrs = pTmpFuncPtr =
250 (SLAPI_FUNC *)ch_malloc( ( numPB + 1 ) * sizeof(SLAPI_FUNC) );
251 if ( ppFuncPtrs == NULL ) {
257 pCurrentPB = (Slapi_PBlock *)be->be_pb;
259 while ( pCurrentPB != NULL && rc == LDAP_SUCCESS ) {
260 rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr );
261 if ( rc == LDAP_SUCCESS ) {
262 if ( FuncPtr != NULL ) {
263 *pTmpFuncPtr = FuncPtr;
266 rc = slapi_pblock_get( pCurrentPB,
267 SLAPI_IBM_PBLOCK, &pCurrentPB );
272 pCurrentPB = pGPlugins;
274 while ( pCurrentPB != NULL && rc == LDAP_SUCCESS ) {
275 rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr );
276 if ( rc == LDAP_SUCCESS ) {
277 if ( FuncPtr != NULL ) {
278 *pTmpFuncPtr = FuncPtr;
281 rc = slapi_pblock_get( pCurrentPB,
282 SLAPI_IBM_PBLOCK, &pCurrentPB );
285 *pTmpFuncPtr = NULL ;
288 if ( rc != LDAP_SUCCESS && *ppFuncPtrs != NULL ) {
289 ch_free( *ppFuncPtrs );
296 /*********************************************************************
297 * Function Name: createExtendedOp
299 * Description: Creates an extended operation structure and
300 * initializes the fields
302 * Return value: A newly allocated structure or NULL
303 ********************************************************************/
309 ret = (ExtendedOp *)ch_malloc(sizeof(ExtendedOp));
311 ret->ext_oid.bv_val = NULL;
312 ret->ext_oid.bv_len = 0;
313 ret->ext_func = NULL;
315 ret->ext_next = NULL;
322 /*********************************************************************
323 * Function Name: removeExtendedOp
325 * Description: This routine removes the ExtendedOp structures
326 * asscoiated with a particular extended operation
329 * Input: pBE - pointer to a backend structure
330 * opList - pointer to a linked list of extended
331 * operation structures
332 * pPB - pointer to a slapi parameter block
339 *********************************************************************/
346 ExtendedOp *pTmpExtOp, *backExtOp;
351 assert( pBE != NULL); /* unused */
353 assert( opList != NULL );
354 assert( pPB != NULL );
356 if ( *opList == NULL ) {
360 slapi_pblock_get( pPB, SLAPI_PLUGIN_EXT_OP_OIDLIST, &pTmpOIDs );
361 if ( pTmpOIDs == NULL ) {
365 for ( i = 0; pTmpOIDs[i] != NULL; i++ ) {
368 for ( ; pTmpExtOp != NULL; pTmpExtOp = pTmpExtOp->ext_next) {
370 rc = strcasecmp( pTmpExtOp->ext_oid.bv_val,
373 if ( backExtOp == NULL ) {
374 *opList = pTmpExtOp->ext_next;
377 = pTmpExtOp->ext_next;
380 ch_free( pTmpExtOp );
383 backExtOp = pTmpExtOp;
389 /*********************************************************************
390 * Function Name: newExtendedOp
392 * Description: This routine creates a new ExtendedOp structure, loads
393 * in the extended op module and put the extended op function address
394 * in the structure. The function will not be executed in
397 * Input: pBE - pointer to a backend structure
398 * opList - pointer to a linked list of extended
399 * operation structures
400 * pPB - pointer to a slapi parameter block
404 * Return Value: an LDAP return code
407 *********************************************************************/
414 ExtendedOp *pTmpExtOp = NULL;
420 if ( (*opList) == NULL ) {
421 *opList = createExtendedOp();
422 if ( (*opList) == NULL ) {
428 } else { /* Find the end of the list */
429 for ( pTmpExtOp = *opList; pTmpExtOp->ext_next != NULL;
430 pTmpExtOp = pTmpExtOp->ext_next )
432 pTmpExtOp->ext_next = createExtendedOp();
433 if ( pTmpExtOp->ext_next == NULL ) {
437 pTmpExtOp = pTmpExtOp->ext_next;
440 rc = slapi_pblock_get( pPB,SLAPI_PLUGIN_EXT_OP_OIDLIST, &pTmpOIDs );
441 if ( rc != LDAP_SUCCESS ) {
446 rc = slapi_pblock_get(pPB,SLAPI_PLUGIN_EXT_OP_FN, &tmpFunc);
452 if ( (pTmpOIDs == NULL) || (tmpFunc == NULL) ) {
457 for ( i = 0; pTmpOIDs[i] != NULL; i++ ) {
458 pTmpExtOp->ext_oid.bv_val = pTmpOIDs[i];
459 pTmpExtOp->ext_oid.bv_len = strlen( pTmpOIDs[i] );
460 pTmpExtOp->ext_func = tmpFunc;
461 pTmpExtOp->ext_be = pBE;
462 if ( pTmpOIDs[i + 1] != NULL ) {
463 pTmpExtOp->ext_next = createExtendedOp();
464 if ( pTmpExtOp->ext_next == NULL ) {
468 pTmpExtOp = pTmpExtOp->ext_next;
476 /*********************************************************************
477 * Function Name: getPluginFunc
479 * Description: This routine gets the function address for a given function
483 * funcName - name of the extended op function, ie. an OID.
485 * Output: pFuncAddr - the function address of the requested function name.
487 * Return Values: a pointer to a newly created ExtendOp structrue or
488 * NULL - function failed
491 *********************************************************************/
494 struct berval *reqoid,
495 SLAPI_FUNC *pFuncAddr )
497 ExtendedOp *pTmpExtOp;
499 assert( reqoid != NULL );
500 assert( pFuncAddr != NULL );
504 if ( pGExtendedOps == NULL ) {
508 pTmpExtOp = pGExtendedOps;
509 while ( pTmpExtOp != NULL ) {
512 rc = strcasecmp( reqoid->bv_val, pTmpExtOp->ext_oid.bv_val );
514 *pFuncAddr = pTmpExtOp->ext_func;
517 pTmpExtOp = pTmpExtOp->ext_next;
520 return ( *pFuncAddr == NULL ? 1 : 0 );
523 /***************************************************************************
524 * This function is similar to getPluginFunc above. except it returns one OID
525 * per call. It is called from root_dse_info (root_dse.c).
526 * The function is a modified version of get_supported_extop (file extended.c).
527 ***************************************************************************/
529 ns_get_supported_extop( int index )
533 for ( ext = pGExtendedOps ; ext != NULL && --index >= 0;
534 ext = ext->ext_next) {
542 return &ext->ext_oid ;
545 /*********************************************************************
546 * Function Name: loadPlugin
548 * Description: This routine loads the specified DLL, gets and executes the init function
552 * pPlugin - a pointer to a Slapi_PBlock struct which will be passed to
553 * the DLL init function.
554 * path - path name of the DLL to be load.
555 * initfunc - either the DLL initialization function or an OID of the
556 * loaded extended operation.
557 * doInit - if it is TRUE, execute the init function, otherwise, save the
558 * function address but not execute it.
560 * Output: pInitFunc - the function address of the loaded function. This param
561 * should be not be null if doInit is FALSE.
562 * pLdHandle - handle returned by lt_dlopen()
564 * Return Values: LDAP_SUCCESS, LDAP_LOCAL_ERROR
567 *********************************************************************/
571 Slapi_PBlock *pPlugin,
573 const char *initfunc,
575 SLAPI_FUNC *pInitFunc,
576 lt_dlhandle *pLdHandle )
578 int rc = LDAP_SUCCESS;
579 SLAPI_FUNC fpInitFunc = NULL;
584 return LDAP_LOCAL_ERROR;
587 /* load in the module */
588 *pLdHandle = lt_dlopen( path );
589 if ( *pLdHandle == NULL ) {
590 return LDAP_LOCAL_ERROR;
593 fpInitFunc = (SLAPI_FUNC)lt_dlsym( *pLdHandle, initfunc );
594 if ( fpInitFunc == NULL ) {
595 lt_dlclose( *pLdHandle );
596 return LDAP_LOCAL_ERROR;
599 if ( doInit == TRUE ) {
600 rc = ( *fpInitFunc )( pPlugin );
601 if ( rc != LDAP_SUCCESS ) {
602 lt_dlclose( *pLdHandle );
606 *pInitFunc = fpInitFunc;
613 * Special support for computed attribute plugins
623 SLAPI_FUNC *pGetPlugin = NULL, *tmpPlugin = NULL;
629 rc = getAllPluginFuncs( be, funcType, &tmpPlugin );
630 if ( rc != LDAP_SUCCESS || tmpPlugin == NULL ) {
631 /* Nothing to do, front-end should ignore. */
635 for ( pGetPlugin = tmpPlugin ; *pGetPlugin != NULL; pGetPlugin++ ) {
637 * FIXME: we should provide here a sort of sandbox,
638 * to protect from plugin faults; e.g. trap signals
639 * and longjump here, marking the plugin as unsafe for
640 * later executions ...
642 rc = (*pGetPlugin)(pPB);
645 * Only non-postoperation plugins abort processing on
646 * failure (confirmed with SLAPI specification).
648 if ( !SLAPI_PLUGIN_IS_POST_FN( funcType ) && rc != 0 ) {
650 * Plugins generally return negative error codes
651 * to indicate failure, although in the case of
652 * bind plugins they may return SLAPI_BIND_xxx
658 slapi_ch_free( (void **)&tmpPlugin );
672 int numPluginArgc = 0;
673 char **ppPluginArgv = NULL;
677 "%s: line %d: missing arguments "
678 "in \"plugin <plugin_type> <lib_path> "
679 "<init_function> [<arguments>]\" line\n",
684 if ( strcasecmp( argv[1], "preoperation" ) == 0 ) {
685 iType = SLAPI_PLUGIN_PREOPERATION;
686 } else if ( strcasecmp( argv[1], "postoperation" ) == 0 ) {
687 iType = SLAPI_PLUGIN_POSTOPERATION;
688 } else if ( strcasecmp( argv[1], "extendedop" ) == 0 ) {
689 iType = SLAPI_PLUGIN_EXTENDEDOP;
690 } else if ( strcasecmp( argv[1], "object" ) == 0 ) {
691 iType = SLAPI_PLUGIN_OBJECT;
693 fprintf( stderr, "%s: line %d: invalid plugin type \"%s\".\n",
694 fname, lineno, argv[1] );
698 numPluginArgc = argc - 4;
699 if ( numPluginArgc > 0 ) {
700 ppPluginArgv = &argv[4];
705 if ( iType == SLAPI_PLUGIN_PREOPERATION ||
706 iType == SLAPI_PLUGIN_EXTENDEDOP ||
707 iType == SLAPI_PLUGIN_POSTOPERATION ||
708 iType == SLAPI_PLUGIN_OBJECT ) {
710 Slapi_PBlock *pPlugin;
712 pPlugin = newPlugin( iType, argv[2], argv[3],
713 numPluginArgc, ppPluginArgv );
714 if (pPlugin == NULL) {
718 if (iType == SLAPI_PLUGIN_EXTENDEDOP) {
719 rc = newExtendedOp(be, &pGExtendedOps, pPlugin);
720 if ( rc != LDAP_SUCCESS ) {
721 slapi_pblock_destroy( pPlugin );
726 rc = insertPlugin( be, pPlugin );
727 if ( rc != LDAP_SUCCESS ) {
728 if ( iType == SLAPI_PLUGIN_EXTENDEDOP ) {
729 removeExtendedOp( be, &pGExtendedOps, pPlugin );
731 slapi_pblock_destroy( pPlugin );
742 if ( ldap_pvt_thread_mutex_init( &slapi_hn_mutex ) ) {
746 if ( ldap_pvt_thread_mutex_init( &slapi_time_mutex ) ) {
750 if ( ldap_pvt_thread_mutex_init( &slapi_printmessage_mutex ) ) {
754 slapi_log_file = ch_strdup( LDAP_RUNDIR LDAP_DIRSEP "errors" );
755 if ( slapi_log_file == NULL ) {
759 if ( slapi_x_init_object_extensions() != 0 ) {