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 );
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 );
220 pCurrentPB = (Slapi_PBlock *)be->be_pb;
222 while ( pCurrentPB != NULL && rc == LDAP_SUCCESS ) {
223 rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr );
224 if ( rc == LDAP_SUCCESS ) {
225 if ( FuncPtr != NULL ) {
228 rc = slapi_pblock_get( pCurrentPB,
229 SLAPI_IBM_PBLOCK, &pCurrentPB );
240 * Now, build the function pointer array of backend-specific
241 * plugins followed by global plugins.
243 *ppFuncPtrs = pTmpFuncPtr =
244 (SLAPI_FUNC *)ch_malloc( ( numPB + 1 ) * sizeof(SLAPI_FUNC) );
245 if ( ppFuncPtrs == NULL ) {
250 pCurrentPB = (Slapi_PBlock *)be->be_pb;
252 while ( pCurrentPB != NULL && rc == LDAP_SUCCESS ) {
253 rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr );
254 if ( rc == LDAP_SUCCESS ) {
255 if ( FuncPtr != NULL ) {
256 *pTmpFuncPtr = FuncPtr;
259 rc = slapi_pblock_get( pCurrentPB,
260 SLAPI_IBM_PBLOCK, &pCurrentPB );
268 if ( rc != LDAP_SUCCESS && *ppFuncPtrs != NULL ) {
269 ch_free( *ppFuncPtrs );
276 /*********************************************************************
277 * Function Name: createExtendedOp
279 * Description: Creates an extended operation structure and
280 * initializes the fields
282 * Return value: A newly allocated structure or NULL
283 ********************************************************************/
289 ret = (ExtendedOp *)ch_malloc(sizeof(ExtendedOp));
291 ret->ext_oid.bv_val = NULL;
292 ret->ext_oid.bv_len = 0;
293 ret->ext_func = NULL;
295 ret->ext_next = NULL;
302 /*********************************************************************
303 * Function Name: slapi_int_unregister_extop
305 * Description: This routine removes the ExtendedOp structures
306 * asscoiated with a particular extended operation
309 * Input: pBE - pointer to a backend structure
310 * opList - pointer to a linked list of extended
311 * operation structures
312 * pPB - pointer to a slapi parameter block
319 *********************************************************************/
321 slapi_int_unregister_extop(
326 ExtendedOp *pTmpExtOp, *backExtOp;
331 assert( pBE != NULL); /* unused */
333 assert( opList != NULL );
334 assert( pPB != NULL );
336 if ( *opList == NULL ) {
340 slapi_pblock_get( pPB, SLAPI_PLUGIN_EXT_OP_OIDLIST, &pTmpOIDs );
341 if ( pTmpOIDs == NULL ) {
345 for ( i = 0; pTmpOIDs[i] != NULL; i++ ) {
348 for ( ; pTmpExtOp != NULL; pTmpExtOp = pTmpExtOp->ext_next) {
350 rc = strcasecmp( pTmpExtOp->ext_oid.bv_val,
353 if ( backExtOp == NULL ) {
354 *opList = pTmpExtOp->ext_next;
357 = pTmpExtOp->ext_next;
360 ch_free( pTmpExtOp );
363 backExtOp = pTmpExtOp;
369 /*********************************************************************
370 * Function Name: slapi_int_register_extop
372 * Description: This routine creates a new ExtendedOp structure, loads
373 * in the extended op module and put the extended op function address
374 * in the structure. The function will not be executed in
377 * Input: pBE - pointer to a backend structure
378 * opList - pointer to a linked list of extended
379 * operation structures
380 * pPB - pointer to a slapi parameter block
384 * Return Value: an LDAP return code
387 *********************************************************************/
389 slapi_int_register_extop(
394 ExtendedOp *pTmpExtOp = NULL;
400 if ( (*opList) == NULL ) {
401 *opList = createExtendedOp();
402 if ( (*opList) == NULL ) {
408 } else { /* Find the end of the list */
409 for ( pTmpExtOp = *opList; pTmpExtOp->ext_next != NULL;
410 pTmpExtOp = pTmpExtOp->ext_next )
412 pTmpExtOp->ext_next = createExtendedOp();
413 if ( pTmpExtOp->ext_next == NULL ) {
417 pTmpExtOp = pTmpExtOp->ext_next;
420 rc = slapi_pblock_get( pPB,SLAPI_PLUGIN_EXT_OP_OIDLIST, &pTmpOIDs );
426 rc = slapi_pblock_get(pPB,SLAPI_PLUGIN_EXT_OP_FN, &tmpFunc);
432 if ( (pTmpOIDs == NULL) || (tmpFunc == NULL) ) {
437 for ( i = 0; pTmpOIDs[i] != NULL; i++ ) {
438 pTmpExtOp->ext_oid.bv_val = pTmpOIDs[i];
439 pTmpExtOp->ext_oid.bv_len = strlen( pTmpOIDs[i] );
440 pTmpExtOp->ext_func = tmpFunc;
441 pTmpExtOp->ext_be = pBE;
442 if ( pTmpOIDs[i + 1] != NULL ) {
443 pTmpExtOp->ext_next = createExtendedOp();
444 if ( pTmpExtOp->ext_next == NULL ) {
448 pTmpExtOp = pTmpExtOp->ext_next;
456 /*********************************************************************
457 * Function Name: slapi_int_get_extop_plugin
459 * Description: This routine gets the function address for a given function
463 * funcName - name of the extended op function, ie. an OID.
465 * Output: pFuncAddr - the function address of the requested function name.
467 * Return Values: a pointer to a newly created ExtendOp structrue or
468 * NULL - function failed
471 *********************************************************************/
473 slapi_int_get_extop_plugin(
474 struct berval *reqoid,
475 SLAPI_FUNC *pFuncAddr )
477 ExtendedOp *pTmpExtOp;
479 assert( reqoid != NULL );
480 assert( pFuncAddr != NULL );
484 if ( pGExtendedOps == NULL ) {
488 pTmpExtOp = pGExtendedOps;
489 while ( pTmpExtOp != NULL ) {
492 rc = strcasecmp( reqoid->bv_val, pTmpExtOp->ext_oid.bv_val );
494 *pFuncAddr = pTmpExtOp->ext_func;
497 pTmpExtOp = pTmpExtOp->ext_next;
500 return ( *pFuncAddr == NULL ? 1 : 0 );
503 /***************************************************************************
504 * This function is similar to slapi_int_get_extop_plugin above. except it returns one OID
505 * per call. It is called from root_dse_info (root_dse.c).
506 * The function is a modified version of get_supported_extop (file extended.c).
507 ***************************************************************************/
509 slapi_int_get_supported_extop( int index )
513 for ( ext = pGExtendedOps ; ext != NULL && --index >= 0;
514 ext = ext->ext_next) {
522 return &ext->ext_oid ;
525 /*********************************************************************
526 * Function Name: slapi_int_load_plugin
528 * Description: This routine loads the specified DLL, gets and executes the init function
532 * pPlugin - a pointer to a Slapi_PBlock struct which will be passed to
533 * the DLL init function.
534 * path - path name of the DLL to be load.
535 * initfunc - either the DLL initialization function or an OID of the
536 * loaded extended operation.
537 * doInit - if it is TRUE, execute the init function, otherwise, save the
538 * function address but not execute it.
540 * Output: pInitFunc - the function address of the loaded function. This param
541 * should be not be null if doInit is FALSE.
542 * pLdHandle - handle returned by lt_dlopen()
544 * Return Values: LDAP_SUCCESS, LDAP_LOCAL_ERROR
547 *********************************************************************/
550 slapi_int_load_plugin(
551 Slapi_PBlock *pPlugin,
553 const char *initfunc,
555 SLAPI_FUNC *pInitFunc,
556 lt_dlhandle *pLdHandle )
558 int rc = LDAP_SUCCESS;
559 SLAPI_FUNC fpInitFunc = NULL;
561 assert( pLdHandle != NULL );
564 return LDAP_LOCAL_ERROR;
567 /* load in the module */
568 *pLdHandle = lt_dlopen( path );
569 if ( *pLdHandle == NULL ) {
570 return LDAP_LOCAL_ERROR;
573 fpInitFunc = (SLAPI_FUNC)lt_dlsym( *pLdHandle, initfunc );
574 if ( fpInitFunc == NULL ) {
575 lt_dlclose( *pLdHandle );
576 return LDAP_LOCAL_ERROR;
580 rc = ( *fpInitFunc )( pPlugin );
581 if ( rc != LDAP_SUCCESS ) {
582 lt_dlclose( *pLdHandle );
586 *pInitFunc = fpInitFunc;
593 * Special support for computed attribute plugins
596 slapi_int_call_plugins(
603 SLAPI_FUNC *pGetPlugin = NULL, *tmpPlugin = NULL;
609 rc = slapi_int_get_plugins( be, funcType, &tmpPlugin );
610 if ( rc != LDAP_SUCCESS || tmpPlugin == NULL ) {
611 /* Nothing to do, front-end should ignore. */
615 for ( pGetPlugin = tmpPlugin ; *pGetPlugin != NULL; pGetPlugin++ ) {
617 * FIXME: we should provide here a sort of sandbox,
618 * to protect from plugin faults; e.g. trap signals
619 * and longjump here, marking the plugin as unsafe for
620 * later executions ...
622 rc = (*pGetPlugin)(pPB);
625 * Only non-postoperation plugins abort processing on
626 * failure (confirmed with SLAPI specification).
628 if ( !SLAPI_PLUGIN_IS_POST_FN( funcType ) && rc != 0 ) {
630 * Plugins generally return negative error codes
631 * to indicate failure, although in the case of
632 * bind plugins they may return SLAPI_BIND_xxx
638 slapi_ch_free( (void **)&tmpPlugin );
644 slapi_int_read_config(
652 int numPluginArgc = 0;
656 "%s: line %d: missing arguments "
657 "in \"plugin <plugin_type> <lib_path> "
658 "<init_function> [<arguments>]\" line\n",
663 /* automatically instantiate overlay if necessary */
664 if ( !overlay_is_inst( be, SLAPI_OVERLAY_NAME ) ) {
665 if ( overlay_config( be, SLAPI_OVERLAY_NAME ) != 0 ) {
666 fprintf( stderr, "Failed to instantiate SLAPI overlay\n");
671 if ( strcasecmp( argv[1], "preoperation" ) == 0 ) {
672 iType = SLAPI_PLUGIN_PREOPERATION;
673 } else if ( strcasecmp( argv[1], "postoperation" ) == 0 ) {
674 iType = SLAPI_PLUGIN_POSTOPERATION;
675 } else if ( strcasecmp( argv[1], "extendedop" ) == 0 ) {
676 iType = SLAPI_PLUGIN_EXTENDEDOP;
677 } else if ( strcasecmp( argv[1], "object" ) == 0 ) {
678 iType = SLAPI_PLUGIN_OBJECT;
680 fprintf( stderr, "%s: line %d: invalid plugin type \"%s\".\n",
681 fname, lineno, argv[1] );
685 numPluginArgc = argc - 4;
687 if ( iType == SLAPI_PLUGIN_PREOPERATION ||
688 iType == SLAPI_PLUGIN_EXTENDEDOP ||
689 iType == SLAPI_PLUGIN_POSTOPERATION ||
690 iType == SLAPI_PLUGIN_OBJECT ) {
692 Slapi_PBlock *pPlugin;
694 pPlugin = plugin_pblock_new( iType, numPluginArgc, argv );
695 if (pPlugin == NULL) {
699 if (iType == SLAPI_PLUGIN_EXTENDEDOP) {
700 rc = slapi_int_register_extop(be, &pGExtendedOps, pPlugin);
701 if ( rc != LDAP_SUCCESS ) {
702 slapi_pblock_destroy( pPlugin );
707 rc = slapi_int_register_plugin( be, pPlugin );
708 if ( rc != LDAP_SUCCESS ) {
709 if ( iType == SLAPI_PLUGIN_EXTENDEDOP ) {
710 slapi_int_unregister_extop( be, &pGExtendedOps, pPlugin );
712 slapi_pblock_destroy( pPlugin );
721 slapi_int_plugin_unparse(
728 char **argv, ibuf[32], *ptr;
729 struct berval idx, bv;
735 for ( pp = be->be_pb;
737 slapi_pblock_get( pp, SLAPI_IBM_PBLOCK, &pp ) )
739 slapi_pblock_get( pp, SLAPI_X_CONFIG_ARGV, &argv );
740 if ( argv == NULL ) /* could be dynamic plugin */
742 idx.bv_len = sprintf( idx.bv_val, "{%d}", i );
743 bv.bv_len = idx.bv_len;
744 for (j=1; argv[j]; j++) {
745 bv.bv_len += strlen(argv[j]);
746 if ( j ) bv.bv_len++;
748 bv.bv_val = ch_malloc( bv.bv_len + 1 );
749 ptr = lutil_strcopy( bv.bv_val, ibuf );
750 for (j=1; argv[j]; j++) {
751 if ( j ) *ptr++ = ' ';
752 ptr = lutil_strcopy( ptr, argv[j] );
754 ber_bvarray_add( out, &bv );
759 slapi_int_initialize(void)
761 if ( ldap_pvt_thread_mutex_init( &slapi_hn_mutex ) ) {
765 if ( ldap_pvt_thread_mutex_init( &slapi_time_mutex ) ) {
769 if ( ldap_pvt_thread_mutex_init( &slapi_printmessage_mutex ) ) {
773 slapi_log_file = ch_strdup( LDAP_RUNDIR LDAP_DIRSEP "errors" );
774 if ( slapi_log_file == NULL ) {
778 if ( slapi_int_init_object_extensions() != 0 ) {
782 return slapi_int_overlay_init();