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 slapi_pblock_set( pPlugin, SLAPI_PLUGIN_TYPE, (void *)&type );
84 slapi_pblock_set( pPlugin, SLAPI_PLUGIN_ARGC, (void *)&argc );
86 av2 = ldap_charray_dup( argv );
93 ppPluginArgv = &av2[4];
98 slapi_pblock_set( pPlugin, SLAPI_PLUGIN_ARGV, (void *)ppPluginArgv );
99 slapi_pblock_set( pPlugin, SLAPI_X_CONFIG_ARGV, (void *)av2 );
101 rc = slapi_int_load_plugin( pPlugin, path, initfunc, 1, NULL, &hdLoadHandle );
106 if ( slapi_pblock_get( pPlugin, SLAPI_PLUGIN_DESCRIPTION, (void **)&pPluginDesc ) == 0 &&
107 pPluginDesc != NULL ) {
108 slapi_log_error(SLAPI_LOG_TRACE, "plugin_pblock_new",
109 "Registered plugin %s %s [%s] (%s)\n",
111 pPluginDesc->spd_version,
112 pPluginDesc->spd_vendor,
113 pPluginDesc->spd_description);
117 if ( rc != 0 && pPlugin != NULL ) {
118 slapi_pblock_destroy( pPlugin );
121 ldap_charray_free( av2 );
128 /*********************************************************************
129 * Function Name: slapi_int_register_plugin
131 * Description: insert the slapi_pblock structure to the end of the plugin
134 * Input: a pointer to a plugin slapi_pblock structure to be added to
139 * Return Values: LDAP_SUCCESS - successfully inserted.
143 *********************************************************************/
145 slapi_int_register_plugin(
149 Slapi_PBlock *pTmpPB;
150 Slapi_PBlock *pSavePB;
151 int rc = LDAP_SUCCESS;
153 assert( be != NULL );
155 pTmpPB = SLAPI_BACKEND_PBLOCK( be );
156 if ( pTmpPB == NULL ) {
157 SLAPI_BACKEND_PBLOCK( be ) = pPB;
159 while ( pTmpPB != NULL && rc == LDAP_SUCCESS ) {
161 rc = slapi_pblock_get( pTmpPB, SLAPI_IBM_PBLOCK, &pTmpPB );
164 if ( rc == LDAP_SUCCESS ) {
165 rc = slapi_pblock_set( pSavePB, SLAPI_IBM_PBLOCK, (void *)pPB );
169 return ( rc != LDAP_SUCCESS ) ? LDAP_OTHER : LDAP_SUCCESS;
172 /*********************************************************************
173 * Function Name: slapi_int_get_plugins
175 * Description: get the desired type of function pointers defined
178 * Input: the type of the functions to get, such as pre-operation,etc.
182 * Return Values: this routine returns a pointer to an array of function
183 * pointers containing backend-specific plugin functions
184 * followed by global plugin functions
187 *********************************************************************/
189 slapi_int_get_plugins(
192 SLAPI_FUNC **ppFuncPtrs )
195 Slapi_PBlock *pCurrentPB;
197 SLAPI_FUNC *pTmpFuncPtr;
199 int rc = LDAP_SUCCESS;
201 assert( ppFuncPtrs != NULL );
207 pCurrentPB = SLAPI_BACKEND_PBLOCK( be );
209 while ( pCurrentPB != NULL && rc == LDAP_SUCCESS ) {
210 rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr );
211 if ( rc == LDAP_SUCCESS ) {
212 if ( FuncPtr != NULL ) {
215 rc = slapi_pblock_get( pCurrentPB,
216 SLAPI_IBM_PBLOCK, &pCurrentPB );
227 * Now, build the function pointer array of backend-specific
228 * plugins followed by global plugins.
230 *ppFuncPtrs = pTmpFuncPtr =
231 (SLAPI_FUNC *)ch_malloc( ( numPB + 1 ) * sizeof(SLAPI_FUNC) );
232 if ( ppFuncPtrs == NULL ) {
237 pCurrentPB = SLAPI_BACKEND_PBLOCK( be );
239 while ( pCurrentPB != NULL && rc == LDAP_SUCCESS ) {
240 rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr );
241 if ( rc == LDAP_SUCCESS ) {
242 if ( FuncPtr != NULL ) {
243 *pTmpFuncPtr = FuncPtr;
246 rc = slapi_pblock_get( pCurrentPB,
247 SLAPI_IBM_PBLOCK, &pCurrentPB );
255 if ( rc != LDAP_SUCCESS && *ppFuncPtrs != NULL ) {
256 ch_free( *ppFuncPtrs );
263 /*********************************************************************
264 * Function Name: createExtendedOp
266 * Description: Creates an extended operation structure and
267 * initializes the fields
269 * Return value: A newly allocated structure or NULL
270 ********************************************************************/
276 ret = (ExtendedOp *)ch_malloc(sizeof(ExtendedOp));
278 ret->ext_oid.bv_val = NULL;
279 ret->ext_oid.bv_len = 0;
280 ret->ext_func = NULL;
282 ret->ext_next = NULL;
289 /*********************************************************************
290 * Function Name: slapi_int_unregister_extop
292 * Description: This routine removes the ExtendedOp structures
293 * asscoiated with a particular extended operation
296 * Input: pBE - pointer to a backend structure
297 * opList - pointer to a linked list of extended
298 * operation structures
299 * pPB - pointer to a slapi parameter block
306 *********************************************************************/
308 slapi_int_unregister_extop(
313 ExtendedOp *pTmpExtOp, *backExtOp;
318 assert( pBE != NULL); /* unused */
320 assert( opList != NULL );
321 assert( pPB != NULL );
323 if ( *opList == NULL ) {
327 slapi_pblock_get( pPB, SLAPI_PLUGIN_EXT_OP_OIDLIST, &pTmpOIDs );
328 if ( pTmpOIDs == NULL ) {
332 for ( i = 0; pTmpOIDs[i] != NULL; i++ ) {
335 for ( ; pTmpExtOp != NULL; pTmpExtOp = pTmpExtOp->ext_next) {
337 rc = strcasecmp( pTmpExtOp->ext_oid.bv_val,
340 if ( backExtOp == NULL ) {
341 *opList = pTmpExtOp->ext_next;
344 = pTmpExtOp->ext_next;
347 ch_free( pTmpExtOp );
350 backExtOp = pTmpExtOp;
356 /*********************************************************************
357 * Function Name: slapi_int_register_extop
359 * Description: This routine creates a new ExtendedOp structure, loads
360 * in the extended op module and put the extended op function address
361 * in the structure. The function will not be executed in
364 * Input: pBE - pointer to a backend structure
365 * opList - pointer to a linked list of extended
366 * operation structures
367 * pPB - pointer to a slapi parameter block
371 * Return Value: an LDAP return code
374 *********************************************************************/
376 slapi_int_register_extop(
381 ExtendedOp *pTmpExtOp = NULL;
387 if ( (*opList) == NULL ) {
388 *opList = createExtendedOp();
389 if ( (*opList) == NULL ) {
395 } else { /* Find the end of the list */
396 for ( pTmpExtOp = *opList; pTmpExtOp->ext_next != NULL;
397 pTmpExtOp = pTmpExtOp->ext_next )
399 pTmpExtOp->ext_next = createExtendedOp();
400 if ( pTmpExtOp->ext_next == NULL ) {
404 pTmpExtOp = pTmpExtOp->ext_next;
407 rc = slapi_pblock_get( pPB,SLAPI_PLUGIN_EXT_OP_OIDLIST, &pTmpOIDs );
413 rc = slapi_pblock_get(pPB,SLAPI_PLUGIN_EXT_OP_FN, &tmpFunc);
419 if ( (pTmpOIDs == NULL) || (tmpFunc == NULL) ) {
424 for ( i = 0; pTmpOIDs[i] != NULL; i++ ) {
425 pTmpExtOp->ext_oid.bv_val = pTmpOIDs[i];
426 pTmpExtOp->ext_oid.bv_len = strlen( pTmpOIDs[i] );
427 pTmpExtOp->ext_func = tmpFunc;
428 pTmpExtOp->ext_be = pBE;
429 if ( pTmpOIDs[i + 1] != NULL ) {
430 pTmpExtOp->ext_next = createExtendedOp();
431 if ( pTmpExtOp->ext_next == NULL ) {
435 pTmpExtOp = pTmpExtOp->ext_next;
443 /*********************************************************************
444 * Function Name: slapi_int_get_extop_plugin
446 * Description: This routine gets the function address for a given function
450 * funcName - name of the extended op function, ie. an OID.
452 * Output: pFuncAddr - the function address of the requested function name.
454 * Return Values: a pointer to a newly created ExtendOp structrue or
455 * NULL - function failed
458 *********************************************************************/
460 slapi_int_get_extop_plugin(
461 struct berval *reqoid,
462 SLAPI_FUNC *pFuncAddr )
464 ExtendedOp *pTmpExtOp;
466 assert( reqoid != NULL );
467 assert( pFuncAddr != NULL );
471 if ( pGExtendedOps == NULL ) {
475 pTmpExtOp = pGExtendedOps;
476 while ( pTmpExtOp != NULL ) {
479 rc = strcasecmp( reqoid->bv_val, pTmpExtOp->ext_oid.bv_val );
481 *pFuncAddr = pTmpExtOp->ext_func;
484 pTmpExtOp = pTmpExtOp->ext_next;
487 return ( *pFuncAddr == NULL ? 1 : 0 );
490 /***************************************************************************
491 * This function is similar to slapi_int_get_extop_plugin above. except it returns one OID
492 * per call. It is called from root_dse_info (root_dse.c).
493 * The function is a modified version of get_supported_extop (file extended.c).
494 ***************************************************************************/
496 slapi_int_get_supported_extop( int index )
500 for ( ext = pGExtendedOps ; ext != NULL && --index >= 0;
501 ext = ext->ext_next) {
509 return &ext->ext_oid ;
512 /*********************************************************************
513 * Function Name: slapi_int_load_plugin
515 * Description: This routine loads the specified DLL, gets and executes the init function
519 * pPlugin - a pointer to a Slapi_PBlock struct which will be passed to
520 * the DLL init function.
521 * path - path name of the DLL to be load.
522 * initfunc - either the DLL initialization function or an OID of the
523 * loaded extended operation.
524 * doInit - if it is TRUE, execute the init function, otherwise, save the
525 * function address but not execute it.
527 * Output: pInitFunc - the function address of the loaded function. This param
528 * should be not be null if doInit is FALSE.
529 * pLdHandle - handle returned by lt_dlopen()
531 * Return Values: LDAP_SUCCESS, LDAP_LOCAL_ERROR
534 *********************************************************************/
537 slapi_int_load_plugin(
538 Slapi_PBlock *pPlugin,
540 const char *initfunc,
542 SLAPI_FUNC *pInitFunc,
543 lt_dlhandle *pLdHandle )
545 int rc = LDAP_SUCCESS;
546 SLAPI_FUNC fpInitFunc = NULL;
548 assert( pLdHandle != NULL );
551 return LDAP_LOCAL_ERROR;
554 /* load in the module */
555 *pLdHandle = lt_dlopen( path );
556 if ( *pLdHandle == NULL ) {
557 return LDAP_LOCAL_ERROR;
560 fpInitFunc = (SLAPI_FUNC)lt_dlsym( *pLdHandle, initfunc );
561 if ( fpInitFunc == NULL ) {
562 lt_dlclose( *pLdHandle );
563 return LDAP_LOCAL_ERROR;
567 rc = ( *fpInitFunc )( pPlugin );
568 if ( rc != LDAP_SUCCESS ) {
569 lt_dlclose( *pLdHandle );
573 *pInitFunc = fpInitFunc;
580 * Special support for computed attribute plugins
583 slapi_int_call_plugins(
590 SLAPI_FUNC *pGetPlugin = NULL, *tmpPlugin = NULL;
596 rc = slapi_int_get_plugins( be, funcType, &tmpPlugin );
597 if ( rc != LDAP_SUCCESS || tmpPlugin == NULL ) {
598 /* Nothing to do, front-end should ignore. */
602 for ( pGetPlugin = tmpPlugin ; *pGetPlugin != NULL; pGetPlugin++ ) {
604 * FIXME: we should provide here a sort of sandbox,
605 * to protect from plugin faults; e.g. trap signals
606 * and longjump here, marking the plugin as unsafe for
607 * later executions ...
609 rc = (*pGetPlugin)(pPB);
612 * Only non-postoperation plugins abort processing on
613 * failure (confirmed with SLAPI specification).
615 if ( !SLAPI_PLUGIN_IS_POST_FN( funcType ) && rc != 0 ) {
617 * Plugins generally return negative error codes
618 * to indicate failure, although in the case of
619 * bind plugins they may return SLAPI_BIND_xxx
625 slapi_ch_free( (void **)&tmpPlugin );
631 slapi_int_read_config(
639 int numPluginArgc = 0;
643 "%s: line %d: missing arguments "
644 "in \"plugin <plugin_type> <lib_path> "
645 "<init_function> [<arguments>]\" line\n",
650 /* automatically instantiate overlay if necessary */
651 if ( !overlay_is_inst( be, SLAPI_OVERLAY_NAME ) ) {
652 if ( overlay_config( be, SLAPI_OVERLAY_NAME ) != 0 ) {
653 fprintf( stderr, "Failed to instantiate SLAPI overlay\n");
658 if ( strcasecmp( argv[1], "preoperation" ) == 0 ) {
659 iType = SLAPI_PLUGIN_PREOPERATION;
660 } else if ( strcasecmp( argv[1], "postoperation" ) == 0 ) {
661 iType = SLAPI_PLUGIN_POSTOPERATION;
662 } else if ( strcasecmp( argv[1], "extendedop" ) == 0 ) {
663 iType = SLAPI_PLUGIN_EXTENDEDOP;
664 } else if ( strcasecmp( argv[1], "object" ) == 0 ) {
665 iType = SLAPI_PLUGIN_OBJECT;
667 fprintf( stderr, "%s: line %d: invalid plugin type \"%s\".\n",
668 fname, lineno, argv[1] );
672 numPluginArgc = argc - 4;
674 if ( iType == SLAPI_PLUGIN_PREOPERATION ||
675 iType == SLAPI_PLUGIN_EXTENDEDOP ||
676 iType == SLAPI_PLUGIN_POSTOPERATION ||
677 iType == SLAPI_PLUGIN_OBJECT ) {
679 Slapi_PBlock *pPlugin;
681 pPlugin = plugin_pblock_new( iType, numPluginArgc, argv );
682 if (pPlugin == NULL) {
686 if (iType == SLAPI_PLUGIN_EXTENDEDOP) {
687 rc = slapi_int_register_extop(be, &pGExtendedOps, pPlugin);
688 if ( rc != LDAP_SUCCESS ) {
689 slapi_pblock_destroy( pPlugin );
694 rc = slapi_int_register_plugin( be, pPlugin );
695 if ( rc != LDAP_SUCCESS ) {
696 if ( iType == SLAPI_PLUGIN_EXTENDEDOP ) {
697 slapi_int_unregister_extop( be, &pGExtendedOps, pPlugin );
699 slapi_pblock_destroy( pPlugin );
708 slapi_int_plugin_unparse(
715 char **argv, ibuf[32], *ptr;
716 struct berval idx, bv;
722 for ( pp = SLAPI_BACKEND_PBLOCK( be );
724 slapi_pblock_get( pp, SLAPI_IBM_PBLOCK, &pp ) )
726 slapi_pblock_get( pp, SLAPI_X_CONFIG_ARGV, &argv );
727 if ( argv == NULL ) /* could be dynamic plugin */
729 idx.bv_len = sprintf( idx.bv_val, "{%d}", i );
730 bv.bv_len = idx.bv_len;
731 for (j=1; argv[j]; j++) {
732 bv.bv_len += strlen(argv[j]);
733 if ( j ) bv.bv_len++;
735 bv.bv_val = ch_malloc( bv.bv_len + 1 );
736 ptr = lutil_strcopy( bv.bv_val, ibuf );
737 for (j=1; argv[j]; j++) {
738 if ( j ) *ptr++ = ' ';
739 ptr = lutil_strcopy( ptr, argv[j] );
741 ber_bvarray_add( out, &bv );
746 slapi_int_initialize(void)
748 if ( ldap_pvt_thread_mutex_init( &slapi_hn_mutex ) ) {
752 if ( ldap_pvt_thread_mutex_init( &slapi_time_mutex ) ) {
756 if ( ldap_pvt_thread_mutex_init( &slapi_printmessage_mutex ) ) {
760 slapi_log_file = ch_strdup( LDAP_RUNDIR LDAP_DIRSEP "errors" );
761 if ( slapi_log_file == NULL ) {
765 if ( slapi_int_init_object_extensions() != 0 ) {
769 return slapi_int_overlay_init();