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, TRUE, 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 );
215 assert( be != NULL );
218 * First, count the plugins associated with a specific
221 if ( be != frontendDB ) {
222 pCurrentPB = (Slapi_PBlock *)be->be_pb;
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 ) {
240 * Then, count the global plugins.
242 pCurrentPB = (Slapi_PBlock *)frontendDB->be_pb;
244 while ( pCurrentPB != NULL && rc == LDAP_SUCCESS ) {
245 rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr );
246 if ( rc == LDAP_SUCCESS ) {
247 if ( FuncPtr != NULL ) {
250 rc = slapi_pblock_get( pCurrentPB,
251 SLAPI_IBM_PBLOCK, &pCurrentPB );
254 if ( rc != LDAP_SUCCESS ) {
265 * Now, build the function pointer array of backend-specific
266 * plugins followed by global plugins.
268 *ppFuncPtrs = pTmpFuncPtr =
269 (SLAPI_FUNC *)ch_malloc( ( numPB + 1 ) * sizeof(SLAPI_FUNC) );
270 if ( ppFuncPtrs == NULL ) {
275 if ( be != frontendDB ) {
276 pCurrentPB = (Slapi_PBlock *)be->be_pb;
278 while ( pCurrentPB != NULL && rc == LDAP_SUCCESS ) {
279 rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr );
280 if ( rc == LDAP_SUCCESS ) {
281 if ( FuncPtr != NULL ) {
282 *pTmpFuncPtr = FuncPtr;
285 rc = slapi_pblock_get( pCurrentPB,
286 SLAPI_IBM_PBLOCK, &pCurrentPB );
291 pCurrentPB = (Slapi_PBlock *)frontendDB->be_pb;
293 while ( pCurrentPB != NULL && rc == LDAP_SUCCESS ) {
294 rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr );
295 if ( rc == LDAP_SUCCESS ) {
296 if ( FuncPtr != NULL ) {
297 *pTmpFuncPtr = FuncPtr;
300 rc = slapi_pblock_get( pCurrentPB,
301 SLAPI_IBM_PBLOCK, &pCurrentPB );
304 *pTmpFuncPtr = NULL ;
307 if ( rc != LDAP_SUCCESS && *ppFuncPtrs != NULL ) {
308 ch_free( *ppFuncPtrs );
315 /*********************************************************************
316 * Function Name: createExtendedOp
318 * Description: Creates an extended operation structure and
319 * initializes the fields
321 * Return value: A newly allocated structure or NULL
322 ********************************************************************/
328 ret = (ExtendedOp *)ch_malloc(sizeof(ExtendedOp));
330 ret->ext_oid.bv_val = NULL;
331 ret->ext_oid.bv_len = 0;
332 ret->ext_func = NULL;
334 ret->ext_next = NULL;
341 /*********************************************************************
342 * Function Name: slapi_int_unregister_extop
344 * Description: This routine removes the ExtendedOp structures
345 * asscoiated with a particular extended operation
348 * Input: pBE - pointer to a backend structure
349 * opList - pointer to a linked list of extended
350 * operation structures
351 * pPB - pointer to a slapi parameter block
358 *********************************************************************/
360 slapi_int_unregister_extop(
365 ExtendedOp *pTmpExtOp, *backExtOp;
370 assert( pBE != NULL); /* unused */
372 assert( opList != NULL );
373 assert( pPB != NULL );
375 if ( *opList == NULL ) {
379 slapi_pblock_get( pPB, SLAPI_PLUGIN_EXT_OP_OIDLIST, &pTmpOIDs );
380 if ( pTmpOIDs == NULL ) {
384 for ( i = 0; pTmpOIDs[i] != NULL; i++ ) {
387 for ( ; pTmpExtOp != NULL; pTmpExtOp = pTmpExtOp->ext_next) {
389 rc = strcasecmp( pTmpExtOp->ext_oid.bv_val,
392 if ( backExtOp == NULL ) {
393 *opList = pTmpExtOp->ext_next;
396 = pTmpExtOp->ext_next;
399 ch_free( pTmpExtOp );
402 backExtOp = pTmpExtOp;
408 /*********************************************************************
409 * Function Name: slapi_int_register_extop
411 * Description: This routine creates a new ExtendedOp structure, loads
412 * in the extended op module and put the extended op function address
413 * in the structure. The function will not be executed in
416 * Input: pBE - pointer to a backend structure
417 * opList - pointer to a linked list of extended
418 * operation structures
419 * pPB - pointer to a slapi parameter block
423 * Return Value: an LDAP return code
426 *********************************************************************/
428 slapi_int_register_extop(
433 ExtendedOp *pTmpExtOp = NULL;
439 if ( (*opList) == NULL ) {
440 *opList = createExtendedOp();
441 if ( (*opList) == NULL ) {
447 } else { /* Find the end of the list */
448 for ( pTmpExtOp = *opList; pTmpExtOp->ext_next != NULL;
449 pTmpExtOp = pTmpExtOp->ext_next )
451 pTmpExtOp->ext_next = createExtendedOp();
452 if ( pTmpExtOp->ext_next == NULL ) {
456 pTmpExtOp = pTmpExtOp->ext_next;
459 rc = slapi_pblock_get( pPB,SLAPI_PLUGIN_EXT_OP_OIDLIST, &pTmpOIDs );
465 rc = slapi_pblock_get(pPB,SLAPI_PLUGIN_EXT_OP_FN, &tmpFunc);
471 if ( (pTmpOIDs == NULL) || (tmpFunc == NULL) ) {
476 for ( i = 0; pTmpOIDs[i] != NULL; i++ ) {
477 pTmpExtOp->ext_oid.bv_val = pTmpOIDs[i];
478 pTmpExtOp->ext_oid.bv_len = strlen( pTmpOIDs[i] );
479 pTmpExtOp->ext_func = tmpFunc;
480 pTmpExtOp->ext_be = pBE;
481 if ( pTmpOIDs[i + 1] != NULL ) {
482 pTmpExtOp->ext_next = createExtendedOp();
483 if ( pTmpExtOp->ext_next == NULL ) {
487 pTmpExtOp = pTmpExtOp->ext_next;
495 /*********************************************************************
496 * Function Name: slapi_int_get_extop_plugin
498 * Description: This routine gets the function address for a given function
502 * funcName - name of the extended op function, ie. an OID.
504 * Output: pFuncAddr - the function address of the requested function name.
506 * Return Values: a pointer to a newly created ExtendOp structrue or
507 * NULL - function failed
510 *********************************************************************/
512 slapi_int_get_extop_plugin(
513 struct berval *reqoid,
514 SLAPI_FUNC *pFuncAddr )
516 ExtendedOp *pTmpExtOp;
518 assert( reqoid != NULL );
519 assert( pFuncAddr != NULL );
523 if ( pGExtendedOps == NULL ) {
527 pTmpExtOp = pGExtendedOps;
528 while ( pTmpExtOp != NULL ) {
531 rc = strcasecmp( reqoid->bv_val, pTmpExtOp->ext_oid.bv_val );
533 *pFuncAddr = pTmpExtOp->ext_func;
536 pTmpExtOp = pTmpExtOp->ext_next;
539 return ( *pFuncAddr == NULL ? 1 : 0 );
542 /***************************************************************************
543 * This function is similar to slapi_int_get_extop_plugin above. except it returns one OID
544 * per call. It is called from root_dse_info (root_dse.c).
545 * The function is a modified version of get_supported_extop (file extended.c).
546 ***************************************************************************/
548 slapi_int_get_supported_extop( int index )
552 for ( ext = pGExtendedOps ; ext != NULL && --index >= 0;
553 ext = ext->ext_next) {
561 return &ext->ext_oid ;
564 /*********************************************************************
565 * Function Name: slapi_int_load_plugin
567 * Description: This routine loads the specified DLL, gets and executes the init function
571 * pPlugin - a pointer to a Slapi_PBlock struct which will be passed to
572 * the DLL init function.
573 * path - path name of the DLL to be load.
574 * initfunc - either the DLL initialization function or an OID of the
575 * loaded extended operation.
576 * doInit - if it is TRUE, execute the init function, otherwise, save the
577 * function address but not execute it.
579 * Output: pInitFunc - the function address of the loaded function. This param
580 * should be not be null if doInit is FALSE.
581 * pLdHandle - handle returned by lt_dlopen()
583 * Return Values: LDAP_SUCCESS, LDAP_LOCAL_ERROR
586 *********************************************************************/
589 slapi_int_load_plugin(
590 Slapi_PBlock *pPlugin,
592 const char *initfunc,
594 SLAPI_FUNC *pInitFunc,
595 lt_dlhandle *pLdHandle )
597 int rc = LDAP_SUCCESS;
598 SLAPI_FUNC fpInitFunc = NULL;
600 assert( pLdHandle != NULL );
603 return LDAP_LOCAL_ERROR;
606 /* load in the module */
607 *pLdHandle = lt_dlopen( path );
608 if ( *pLdHandle == NULL ) {
609 return LDAP_LOCAL_ERROR;
612 fpInitFunc = (SLAPI_FUNC)lt_dlsym( *pLdHandle, initfunc );
613 if ( fpInitFunc == NULL ) {
614 lt_dlclose( *pLdHandle );
615 return LDAP_LOCAL_ERROR;
618 if ( doInit == TRUE ) {
619 rc = ( *fpInitFunc )( pPlugin );
620 if ( rc != LDAP_SUCCESS ) {
621 lt_dlclose( *pLdHandle );
625 *pInitFunc = fpInitFunc;
632 * Special support for computed attribute plugins
635 slapi_int_call_plugins(
642 SLAPI_FUNC *pGetPlugin = NULL, *tmpPlugin = NULL;
648 rc = slapi_int_get_plugins( be, funcType, &tmpPlugin );
649 if ( rc != LDAP_SUCCESS || tmpPlugin == NULL ) {
650 /* Nothing to do, front-end should ignore. */
654 for ( pGetPlugin = tmpPlugin ; *pGetPlugin != NULL; pGetPlugin++ ) {
656 * FIXME: we should provide here a sort of sandbox,
657 * to protect from plugin faults; e.g. trap signals
658 * and longjump here, marking the plugin as unsafe for
659 * later executions ...
661 rc = (*pGetPlugin)(pPB);
664 * Only non-postoperation plugins abort processing on
665 * failure (confirmed with SLAPI specification).
667 if ( !SLAPI_PLUGIN_IS_POST_FN( funcType ) && rc != 0 ) {
669 * Plugins generally return negative error codes
670 * to indicate failure, although in the case of
671 * bind plugins they may return SLAPI_BIND_xxx
677 slapi_ch_free( (void **)&tmpPlugin );
683 slapi_int_read_config(
691 int numPluginArgc = 0;
695 "%s: line %d: missing arguments "
696 "in \"plugin <plugin_type> <lib_path> "
697 "<init_function> [<arguments>]\" line\n",
702 if ( strcasecmp( argv[1], "preoperation" ) == 0 ) {
703 iType = SLAPI_PLUGIN_PREOPERATION;
704 } else if ( strcasecmp( argv[1], "postoperation" ) == 0 ) {
705 iType = SLAPI_PLUGIN_POSTOPERATION;
706 } else if ( strcasecmp( argv[1], "extendedop" ) == 0 ) {
707 iType = SLAPI_PLUGIN_EXTENDEDOP;
708 } else if ( strcasecmp( argv[1], "object" ) == 0 ) {
709 iType = SLAPI_PLUGIN_OBJECT;
711 fprintf( stderr, "%s: line %d: invalid plugin type \"%s\".\n",
712 fname, lineno, argv[1] );
716 numPluginArgc = argc - 4;
718 if ( iType == SLAPI_PLUGIN_PREOPERATION ||
719 iType == SLAPI_PLUGIN_EXTENDEDOP ||
720 iType == SLAPI_PLUGIN_POSTOPERATION ||
721 iType == SLAPI_PLUGIN_OBJECT ) {
723 Slapi_PBlock *pPlugin;
725 pPlugin = plugin_pblock_new( iType, numPluginArgc, argv );
726 if (pPlugin == NULL) {
730 if (iType == SLAPI_PLUGIN_EXTENDEDOP) {
731 rc = slapi_int_register_extop(be, &pGExtendedOps, pPlugin);
732 if ( rc != LDAP_SUCCESS ) {
733 slapi_pblock_destroy( pPlugin );
738 rc = slapi_int_register_plugin( be, pPlugin );
739 if ( rc != LDAP_SUCCESS ) {
740 if ( iType == SLAPI_PLUGIN_EXTENDEDOP ) {
741 slapi_int_unregister_extop( be, &pGExtendedOps, pPlugin );
743 slapi_pblock_destroy( pPlugin );
752 slapi_int_plugin_unparse(
759 char **argv, ibuf[32], *ptr;
760 struct berval idx, bv;
766 for ( pp = be->be_pb;
768 slapi_pblock_get( pp, SLAPI_IBM_PBLOCK, &pp ) )
770 slapi_pblock_get( pp, SLAPI_X_CONFIG_ARGV, &argv );
771 if ( argv == NULL ) /* could be dynamic plugin */
773 idx.bv_len = sprintf( idx.bv_val, "{%d}", i );
774 bv.bv_len = idx.bv_len;
775 for (j=1; argv[j]; j++) {
776 bv.bv_len += strlen(argv[j]);
777 if ( j ) bv.bv_len++;
779 bv.bv_val = ch_malloc( bv.bv_len + 1 );
780 ptr = lutil_strcopy( bv.bv_val, ibuf );
781 for (j=1; argv[j]; j++) {
782 if ( j ) *ptr++ = ' ';
783 ptr = lutil_strcopy( ptr, argv[j] );
785 ber_bvarray_add( out, &bv );
790 slapi_int_initialize(void)
792 if ( ldap_pvt_thread_mutex_init( &slapi_hn_mutex ) ) {
796 if ( ldap_pvt_thread_mutex_init( &slapi_time_mutex ) ) {
800 if ( ldap_pvt_thread_mutex_init( &slapi_printmessage_mutex ) ) {
804 slapi_log_file = ch_strdup( LDAP_RUNDIR LDAP_DIRSEP "errors" );
805 if ( slapi_log_file == NULL ) {
809 if ( slapi_int_init_object_extensions() != 0 ) {