2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 2002-2005 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>
30 * Note: if ltdl.h is not available, slapi should not be compiled
34 static int slapi_int_load_plugin( Slapi_PBlock *, const char *, const char *, int,
35 SLAPI_FUNC *, lt_dlhandle * );
37 /* pointer to link list of extended objects */
38 static ExtendedOp *pGExtendedOps = NULL;
40 /*********************************************************************
41 * Function Name: plugin_pblock_new
43 * Description: This routine creates a new Slapi_PBlock structure,
44 * loads in the plugin module and executes the init
45 * function provided by the module.
47 * Input: type - type of the plugin, such as SASL, database, etc.
48 * path - the loadpath to load the module in
49 * initfunc - name of the plugin function to execute first
50 * argc - number of arguements
51 * argv[] - an array of char pointers point to
52 * the arguments passed in via
53 * the configuration file.
57 * Return Values: a pointer to a newly created Slapi_PBlock structrue or
58 * NULL - function failed
61 *********************************************************************/
69 Slapi_PBlock *pPlugin = NULL;
70 Slapi_PluginDesc *pPluginDesc = NULL;
71 lt_dlhandle hdLoadHandle;
73 char **av2 = NULL, **ppPluginArgv;
75 char *initfunc = argv[3];
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 av2 = ldap_charray_dup( argv );
100 ppPluginArgv = &av2[4];
104 rc = slapi_pblock_set( pPlugin, SLAPI_PLUGIN_ARGV, (void *)ppPluginArgv );
109 rc = slapi_pblock_set( pPlugin, SLAPI_X_CONFIG_ARGV, (void *)av2 );
114 rc = slapi_int_load_plugin( pPlugin, path, initfunc, 1, NULL, &hdLoadHandle );
119 if ( slapi_pblock_get( pPlugin, SLAPI_PLUGIN_DESCRIPTION, (void **)&pPluginDesc ) == 0 &&
120 pPluginDesc != NULL ) {
121 slapi_log_error(SLAPI_LOG_TRACE, "plugin_pblock_new",
122 "Registered plugin %s %s [%s] (%s)\n",
124 pPluginDesc->spd_version,
125 pPluginDesc->spd_vendor,
126 pPluginDesc->spd_description);
130 if ( rc != 0 && pPlugin != NULL ) {
131 slapi_pblock_destroy( pPlugin );
134 ldap_charray_free( av2 );
141 /*********************************************************************
142 * Function Name: slapi_int_register_plugin
144 * Description: insert the slapi_pblock structure to the end of the plugin
147 * Input: a pointer to a plugin slapi_pblock structure to be added to
152 * Return Values: LDAP_SUCCESS - successfully inserted.
156 *********************************************************************/
158 slapi_int_register_plugin(
162 Slapi_PBlock *pTmpPB;
163 Slapi_PBlock *pSavePB;
164 int rc = LDAP_SUCCESS;
166 assert( be != NULL ); /* global plugins are now stored in frontendDB */
168 pTmpPB = (Slapi_PBlock *)be->be_pb;
169 if ( pTmpPB == NULL ) {
170 be->be_pb = (void *)pPB;
172 while ( pTmpPB != NULL && rc == LDAP_SUCCESS ) {
174 rc = slapi_pblock_get( pTmpPB, SLAPI_IBM_PBLOCK, &pTmpPB );
177 if ( rc == LDAP_SUCCESS ) {
178 rc = slapi_pblock_set( pSavePB, SLAPI_IBM_PBLOCK, (void *)pPB );
182 return ( rc != LDAP_SUCCESS ) ? LDAP_OTHER : LDAP_SUCCESS;
185 /*********************************************************************
186 * Function Name: slapi_int_get_plugins
188 * Description: get the desired type of function pointers defined
191 * Input: the type of the functions to get, such as pre-operation,etc.
195 * Return Values: this routine returns a pointer to an array of function
196 * pointers containing backend-specific plugin functions
197 * followed by global plugin functions
200 *********************************************************************/
202 slapi_int_get_plugins(
205 SLAPI_FUNC **ppFuncPtrs )
208 Slapi_PBlock *pCurrentPB;
210 SLAPI_FUNC *pTmpFuncPtr;
212 int rc = LDAP_SUCCESS;
214 assert( ppFuncPtrs != NULL );
221 * First, count the plugins associated with a specific
224 if ( be != frontendDB ) {
225 pCurrentPB = (Slapi_PBlock *)be->be_pb;
227 while ( pCurrentPB != NULL && rc == LDAP_SUCCESS ) {
228 rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr );
229 if ( rc == LDAP_SUCCESS ) {
230 if ( FuncPtr != NULL ) {
233 rc = slapi_pblock_get( pCurrentPB,
234 SLAPI_IBM_PBLOCK, &pCurrentPB );
238 if ( rc != LDAP_SUCCESS ) {
243 * Then, count the global plugins.
245 pCurrentPB = (Slapi_PBlock *)frontendDB->be_pb;
247 while ( pCurrentPB != NULL && rc == LDAP_SUCCESS ) {
248 rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr );
249 if ( rc == LDAP_SUCCESS ) {
250 if ( FuncPtr != NULL ) {
253 rc = slapi_pblock_get( pCurrentPB,
254 SLAPI_IBM_PBLOCK, &pCurrentPB );
257 if ( rc != LDAP_SUCCESS ) {
268 * Now, build the function pointer array of backend-specific
269 * plugins followed by global plugins.
271 *ppFuncPtrs = pTmpFuncPtr =
272 (SLAPI_FUNC *)ch_malloc( ( numPB + 1 ) * sizeof(SLAPI_FUNC) );
273 if ( ppFuncPtrs == NULL ) {
278 if ( be != frontendDB ) {
279 pCurrentPB = (Slapi_PBlock *)be->be_pb;
281 while ( pCurrentPB != NULL && rc == LDAP_SUCCESS ) {
282 rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr );
283 if ( rc == LDAP_SUCCESS ) {
284 if ( FuncPtr != NULL ) {
285 *pTmpFuncPtr = FuncPtr;
288 rc = slapi_pblock_get( pCurrentPB,
289 SLAPI_IBM_PBLOCK, &pCurrentPB );
294 pCurrentPB = (Slapi_PBlock *)frontendDB->be_pb;
296 while ( pCurrentPB != NULL && rc == LDAP_SUCCESS ) {
297 rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr );
298 if ( rc == LDAP_SUCCESS ) {
299 if ( FuncPtr != NULL ) {
300 *pTmpFuncPtr = FuncPtr;
303 rc = slapi_pblock_get( pCurrentPB,
304 SLAPI_IBM_PBLOCK, &pCurrentPB );
307 *pTmpFuncPtr = NULL ;
310 if ( rc != LDAP_SUCCESS && *ppFuncPtrs != NULL ) {
311 ch_free( *ppFuncPtrs );
318 /*********************************************************************
319 * Function Name: createExtendedOp
321 * Description: Creates an extended operation structure and
322 * initializes the fields
324 * Return value: A newly allocated structure or NULL
325 ********************************************************************/
331 ret = (ExtendedOp *)ch_malloc(sizeof(ExtendedOp));
333 ret->ext_oid.bv_val = NULL;
334 ret->ext_oid.bv_len = 0;
335 ret->ext_func = NULL;
337 ret->ext_next = NULL;
344 /*********************************************************************
345 * Function Name: slapi_int_unregister_extop
347 * Description: This routine removes the ExtendedOp structures
348 * asscoiated with a particular extended operation
351 * Input: pBE - pointer to a backend structure
352 * opList - pointer to a linked list of extended
353 * operation structures
354 * pPB - pointer to a slapi parameter block
361 *********************************************************************/
363 slapi_int_unregister_extop(
368 ExtendedOp *pTmpExtOp, *backExtOp;
373 assert( pBE != NULL); /* unused */
375 assert( opList != NULL );
376 assert( pPB != NULL );
378 if ( *opList == NULL ) {
382 slapi_pblock_get( pPB, SLAPI_PLUGIN_EXT_OP_OIDLIST, &pTmpOIDs );
383 if ( pTmpOIDs == NULL ) {
387 for ( i = 0; pTmpOIDs[i] != NULL; i++ ) {
390 for ( ; pTmpExtOp != NULL; pTmpExtOp = pTmpExtOp->ext_next) {
392 rc = strcasecmp( pTmpExtOp->ext_oid.bv_val,
395 if ( backExtOp == NULL ) {
396 *opList = pTmpExtOp->ext_next;
399 = pTmpExtOp->ext_next;
402 ch_free( pTmpExtOp );
405 backExtOp = pTmpExtOp;
411 /*********************************************************************
412 * Function Name: slapi_int_register_extop
414 * Description: This routine creates a new ExtendedOp structure, loads
415 * in the extended op module and put the extended op function address
416 * in the structure. The function will not be executed in
419 * Input: pBE - pointer to a backend structure
420 * opList - pointer to a linked list of extended
421 * operation structures
422 * pPB - pointer to a slapi parameter block
426 * Return Value: an LDAP return code
429 *********************************************************************/
431 slapi_int_register_extop(
436 ExtendedOp *pTmpExtOp = NULL;
442 if ( (*opList) == NULL ) {
443 *opList = createExtendedOp();
444 if ( (*opList) == NULL ) {
450 } else { /* Find the end of the list */
451 for ( pTmpExtOp = *opList; pTmpExtOp->ext_next != NULL;
452 pTmpExtOp = pTmpExtOp->ext_next )
454 pTmpExtOp->ext_next = createExtendedOp();
455 if ( pTmpExtOp->ext_next == NULL ) {
459 pTmpExtOp = pTmpExtOp->ext_next;
462 rc = slapi_pblock_get( pPB,SLAPI_PLUGIN_EXT_OP_OIDLIST, &pTmpOIDs );
468 rc = slapi_pblock_get(pPB,SLAPI_PLUGIN_EXT_OP_FN, &tmpFunc);
474 if ( (pTmpOIDs == NULL) || (tmpFunc == NULL) ) {
479 for ( i = 0; pTmpOIDs[i] != NULL; i++ ) {
480 pTmpExtOp->ext_oid.bv_val = pTmpOIDs[i];
481 pTmpExtOp->ext_oid.bv_len = strlen( pTmpOIDs[i] );
482 pTmpExtOp->ext_func = tmpFunc;
483 pTmpExtOp->ext_be = pBE;
484 if ( pTmpOIDs[i + 1] != NULL ) {
485 pTmpExtOp->ext_next = createExtendedOp();
486 if ( pTmpExtOp->ext_next == NULL ) {
490 pTmpExtOp = pTmpExtOp->ext_next;
498 /*********************************************************************
499 * Function Name: slapi_int_get_extop_plugin
501 * Description: This routine gets the function address for a given function
505 * funcName - name of the extended op function, ie. an OID.
507 * Output: pFuncAddr - the function address of the requested function name.
509 * Return Values: a pointer to a newly created ExtendOp structrue or
510 * NULL - function failed
513 *********************************************************************/
515 slapi_int_get_extop_plugin(
516 struct berval *reqoid,
517 SLAPI_FUNC *pFuncAddr )
519 ExtendedOp *pTmpExtOp;
521 assert( reqoid != NULL );
522 assert( pFuncAddr != NULL );
526 if ( pGExtendedOps == NULL ) {
530 pTmpExtOp = pGExtendedOps;
531 while ( pTmpExtOp != NULL ) {
534 rc = strcasecmp( reqoid->bv_val, pTmpExtOp->ext_oid.bv_val );
536 *pFuncAddr = pTmpExtOp->ext_func;
539 pTmpExtOp = pTmpExtOp->ext_next;
542 return ( *pFuncAddr == NULL ? 1 : 0 );
545 /***************************************************************************
546 * This function is similar to slapi_int_get_extop_plugin above. except it returns one OID
547 * per call. It is called from root_dse_info (root_dse.c).
548 * The function is a modified version of get_supported_extop (file extended.c).
549 ***************************************************************************/
551 slapi_int_get_supported_extop( int index )
555 for ( ext = pGExtendedOps ; ext != NULL && --index >= 0;
556 ext = ext->ext_next) {
564 return &ext->ext_oid ;
567 /*********************************************************************
568 * Function Name: slapi_int_load_plugin
570 * Description: This routine loads the specified DLL, gets and executes the init function
574 * pPlugin - a pointer to a Slapi_PBlock struct which will be passed to
575 * the DLL init function.
576 * path - path name of the DLL to be load.
577 * initfunc - either the DLL initialization function or an OID of the
578 * loaded extended operation.
579 * doInit - if it is TRUE, execute the init function, otherwise, save the
580 * function address but not execute it.
582 * Output: pInitFunc - the function address of the loaded function. This param
583 * should be not be null if doInit is FALSE.
584 * pLdHandle - handle returned by lt_dlopen()
586 * Return Values: LDAP_SUCCESS, LDAP_LOCAL_ERROR
589 *********************************************************************/
592 slapi_int_load_plugin(
593 Slapi_PBlock *pPlugin,
595 const char *initfunc,
597 SLAPI_FUNC *pInitFunc,
598 lt_dlhandle *pLdHandle )
600 int rc = LDAP_SUCCESS;
601 SLAPI_FUNC fpInitFunc = NULL;
603 assert( pLdHandle != NULL );
606 return LDAP_LOCAL_ERROR;
609 /* load in the module */
610 *pLdHandle = lt_dlopen( path );
611 if ( *pLdHandle == NULL ) {
612 return LDAP_LOCAL_ERROR;
615 fpInitFunc = (SLAPI_FUNC)lt_dlsym( *pLdHandle, initfunc );
616 if ( fpInitFunc == NULL ) {
617 lt_dlclose( *pLdHandle );
618 return LDAP_LOCAL_ERROR;
622 rc = ( *fpInitFunc )( pPlugin );
623 if ( rc != LDAP_SUCCESS ) {
624 lt_dlclose( *pLdHandle );
628 *pInitFunc = fpInitFunc;
635 * Special support for computed attribute plugins
638 slapi_int_call_plugins(
645 SLAPI_FUNC *pGetPlugin = NULL, *tmpPlugin = NULL;
651 rc = slapi_int_get_plugins( be, funcType, &tmpPlugin );
652 if ( rc != LDAP_SUCCESS || tmpPlugin == NULL ) {
653 /* Nothing to do, front-end should ignore. */
657 for ( pGetPlugin = tmpPlugin ; *pGetPlugin != NULL; pGetPlugin++ ) {
659 * FIXME: we should provide here a sort of sandbox,
660 * to protect from plugin faults; e.g. trap signals
661 * and longjump here, marking the plugin as unsafe for
662 * later executions ...
664 rc = (*pGetPlugin)(pPB);
667 * Only non-postoperation plugins abort processing on
668 * failure (confirmed with SLAPI specification).
670 if ( !SLAPI_PLUGIN_IS_POST_FN( funcType ) && rc != 0 ) {
672 * Plugins generally return negative error codes
673 * to indicate failure, although in the case of
674 * bind plugins they may return SLAPI_BIND_xxx
680 slapi_ch_free( (void **)&tmpPlugin );
686 slapi_int_read_config(
694 int numPluginArgc = 0;
698 "%s: line %d: missing arguments "
699 "in \"plugin <plugin_type> <lib_path> "
700 "<init_function> [<arguments>]\" line\n",
705 /* automatically instantiate overlay if necessary */
706 if ( !overlay_is_inst( be, SLAPI_OVERLAY_NAME ) ) {
707 if ( overlay_config( be, SLAPI_OVERLAY_NAME ) != 0 ) {
708 fprintf( stderr, "Failed to instantiate SLAPI overlay\n");
713 if ( strcasecmp( argv[1], "preoperation" ) == 0 ) {
714 iType = SLAPI_PLUGIN_PREOPERATION;
715 } else if ( strcasecmp( argv[1], "postoperation" ) == 0 ) {
716 iType = SLAPI_PLUGIN_POSTOPERATION;
717 } else if ( strcasecmp( argv[1], "extendedop" ) == 0 ) {
718 iType = SLAPI_PLUGIN_EXTENDEDOP;
719 } else if ( strcasecmp( argv[1], "object" ) == 0 ) {
720 iType = SLAPI_PLUGIN_OBJECT;
722 fprintf( stderr, "%s: line %d: invalid plugin type \"%s\".\n",
723 fname, lineno, argv[1] );
727 numPluginArgc = argc - 4;
729 if ( iType == SLAPI_PLUGIN_PREOPERATION ||
730 iType == SLAPI_PLUGIN_EXTENDEDOP ||
731 iType == SLAPI_PLUGIN_POSTOPERATION ||
732 iType == SLAPI_PLUGIN_OBJECT ) {
734 Slapi_PBlock *pPlugin;
736 pPlugin = plugin_pblock_new( iType, numPluginArgc, argv );
737 if (pPlugin == NULL) {
741 if (iType == SLAPI_PLUGIN_EXTENDEDOP) {
742 rc = slapi_int_register_extop(be, &pGExtendedOps, pPlugin);
743 if ( rc != LDAP_SUCCESS ) {
744 slapi_pblock_destroy( pPlugin );
749 rc = slapi_int_register_plugin( be, pPlugin );
750 if ( rc != LDAP_SUCCESS ) {
751 if ( iType == SLAPI_PLUGIN_EXTENDEDOP ) {
752 slapi_int_unregister_extop( be, &pGExtendedOps, pPlugin );
754 slapi_pblock_destroy( pPlugin );
763 slapi_int_plugin_unparse(
770 char **argv, ibuf[32], *ptr;
771 struct berval idx, bv;
777 for ( pp = be->be_pb;
779 slapi_pblock_get( pp, SLAPI_IBM_PBLOCK, &pp ) )
781 slapi_pblock_get( pp, SLAPI_X_CONFIG_ARGV, &argv );
782 if ( argv == NULL ) /* could be dynamic plugin */
784 idx.bv_len = sprintf( idx.bv_val, "{%d}", i );
785 bv.bv_len = idx.bv_len;
786 for (j=1; argv[j]; j++) {
787 bv.bv_len += strlen(argv[j]);
788 if ( j ) bv.bv_len++;
790 bv.bv_val = ch_malloc( bv.bv_len + 1 );
791 ptr = lutil_strcopy( bv.bv_val, ibuf );
792 for (j=1; argv[j]; j++) {
793 if ( j ) *ptr++ = ' ';
794 ptr = lutil_strcopy( ptr, argv[j] );
796 ber_bvarray_add( out, &bv );
801 slapi_int_initialize(void)
803 if ( ldap_pvt_thread_mutex_init( &slapi_hn_mutex ) ) {
807 if ( ldap_pvt_thread_mutex_init( &slapi_time_mutex ) ) {
811 if ( ldap_pvt_thread_mutex_init( &slapi_printmessage_mutex ) ) {
815 slapi_log_file = ch_strdup( LDAP_RUNDIR LDAP_DIRSEP "errors" );
816 if ( slapi_log_file == NULL ) {
820 if ( slapi_int_init_object_extensions() != 0 ) {
824 return slapi_int_overlay_init();