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;
39 /* global plugins not associated with a specific backend */
40 static Slapi_PBlock *pGPlugins = NULL;
42 /*********************************************************************
43 * Function Name: plugin_pblock_new
45 * Description: This routine creates a new Slapi_PBlock structure,
46 * loads in the plugin module and executes the init
47 * function provided by the module.
49 * Input: type - type of the plugin, such as SASL, database, etc.
50 * path - the loadpath to load the module in
51 * initfunc - name of the plugin function to execute first
52 * argc - number of arguements
53 * argv[] - an array of char pointers point to
54 * the arguments passed in via
55 * the configuration file.
59 * Return Values: a pointer to a newly created Slapi_PBlock structrue or
60 * NULL - function failed
63 *********************************************************************/
71 Slapi_PBlock *pPlugin = NULL;
72 Slapi_PluginDesc *pPluginDesc = NULL;
73 lt_dlhandle hdLoadHandle;
75 char **av2 = NULL, **ppPluginArgv;
77 char *initfunc = argv[3];
79 pPlugin = slapi_pblock_new();
80 if ( pPlugin == NULL ) {
85 rc = slapi_pblock_set( pPlugin, SLAPI_PLUGIN_TYPE, (void *)type );
90 rc = slapi_pblock_set( pPlugin, SLAPI_PLUGIN_ARGC, (void *)argc );
95 av2 = ldap_charray_dup( argv );
102 ppPluginArgv = &av2[4];
106 rc = slapi_pblock_set( pPlugin, SLAPI_PLUGIN_ARGV, (void *)ppPluginArgv );
111 rc = slapi_pblock_set( pPlugin, SLAPI_X_CONFIG_ARGV, (void *)av2 );
116 rc = slapi_int_load_plugin( pPlugin, path, initfunc, TRUE, NULL, &hdLoadHandle );
121 if ( slapi_pblock_get( pPlugin, SLAPI_PLUGIN_DESCRIPTION, (void **)&pPluginDesc ) == 0 &&
122 pPluginDesc != NULL ) {
123 slapi_log_error(SLAPI_LOG_TRACE, "plugin_pblock_new",
124 "Registered plugin %s %s [%s] (%s)\n",
126 pPluginDesc->spd_version,
127 pPluginDesc->spd_vendor,
128 pPluginDesc->spd_description);
132 if ( rc != 0 && pPlugin != NULL ) {
133 slapi_pblock_destroy( pPlugin );
136 ldap_charray_free( av2 );
143 /*********************************************************************
144 * Function Name: slapi_int_register_plugin
146 * Description: insert the slapi_pblock structure to the end of the plugin
149 * Input: a pointer to a plugin slapi_pblock structure to be added to
154 * Return Values: LDAP_SUCCESS - successfully inserted.
158 *********************************************************************/
160 slapi_int_register_plugin(
164 Slapi_PBlock *pTmpPB;
165 Slapi_PBlock *pSavePB;
166 int rc = LDAP_SUCCESS;
168 pTmpPB = ( be == NULL ) ? pGPlugins : (Slapi_PBlock *)(be->be_pb);
170 if ( pTmpPB == NULL ) {
172 be->be_pb = (void *)pPB;
176 while ( pTmpPB != NULL && rc == LDAP_SUCCESS ) {
178 rc = slapi_pblock_get( pTmpPB, SLAPI_IBM_PBLOCK,
180 if ( rc != LDAP_SUCCESS ) {
185 if ( rc == LDAP_SUCCESS ) {
186 rc = slapi_pblock_set( pSavePB, SLAPI_IBM_PBLOCK,
188 if ( rc != LDAP_SUCCESS ) {
197 /*********************************************************************
198 * Function Name: slapi_int_get_plugins
200 * Description: get the desired type of function pointers defined
203 * Input: the type of the functions to get, such as pre-operation,etc.
207 * Return Values: this routine returns a pointer to an array of function
208 * pointers containing backend-specific plugin functions
209 * followed by global plugin functions
212 *********************************************************************/
214 slapi_int_get_plugins(
217 SLAPI_FUNC **ppFuncPtrs )
220 Slapi_PBlock *pCurrentPB;
222 SLAPI_FUNC *pTmpFuncPtr;
224 int rc = LDAP_SUCCESS;
226 assert( ppFuncPtrs );
229 * First, count the plugins associated with a specific
233 pCurrentPB = (Slapi_PBlock *)be->be_pb;
235 while ( pCurrentPB != NULL && rc == LDAP_SUCCESS ) {
236 rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr );
237 if ( rc == LDAP_SUCCESS ) {
238 if ( FuncPtr != NULL ) {
241 rc = slapi_pblock_get( pCurrentPB,
242 SLAPI_IBM_PBLOCK, &pCurrentPB );
247 if ( rc != LDAP_SUCCESS ) {
252 * Then, count the global plugins.
254 pCurrentPB = pGPlugins;
256 while ( pCurrentPB != NULL && rc == LDAP_SUCCESS ) {
257 rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr );
258 if ( rc == LDAP_SUCCESS ) {
259 if ( FuncPtr != NULL ) {
262 rc = slapi_pblock_get( pCurrentPB,
263 SLAPI_IBM_PBLOCK, &pCurrentPB );
267 if ( rc != LDAP_SUCCESS ) {
278 * Now, build the function pointer array of backend-specific
279 * plugins followed by global plugins.
281 *ppFuncPtrs = pTmpFuncPtr =
282 (SLAPI_FUNC *)ch_malloc( ( numPB + 1 ) * sizeof(SLAPI_FUNC) );
283 if ( ppFuncPtrs == NULL ) {
289 pCurrentPB = (Slapi_PBlock *)be->be_pb;
291 while ( pCurrentPB != NULL && rc == LDAP_SUCCESS ) {
292 rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr );
293 if ( rc == LDAP_SUCCESS ) {
294 if ( FuncPtr != NULL ) {
295 *pTmpFuncPtr = FuncPtr;
298 rc = slapi_pblock_get( pCurrentPB,
299 SLAPI_IBM_PBLOCK, &pCurrentPB );
304 pCurrentPB = pGPlugins;
306 while ( pCurrentPB != NULL && rc == LDAP_SUCCESS ) {
307 rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr );
308 if ( rc == LDAP_SUCCESS ) {
309 if ( FuncPtr != NULL ) {
310 *pTmpFuncPtr = FuncPtr;
313 rc = slapi_pblock_get( pCurrentPB,
314 SLAPI_IBM_PBLOCK, &pCurrentPB );
317 *pTmpFuncPtr = NULL ;
320 if ( rc != LDAP_SUCCESS && *ppFuncPtrs != NULL ) {
321 ch_free( *ppFuncPtrs );
328 /*********************************************************************
329 * Function Name: createExtendedOp
331 * Description: Creates an extended operation structure and
332 * initializes the fields
334 * Return value: A newly allocated structure or NULL
335 ********************************************************************/
341 ret = (ExtendedOp *)ch_malloc(sizeof(ExtendedOp));
343 ret->ext_oid.bv_val = NULL;
344 ret->ext_oid.bv_len = 0;
345 ret->ext_func = NULL;
347 ret->ext_next = NULL;
354 /*********************************************************************
355 * Function Name: slapi_int_unregister_extop
357 * Description: This routine removes the ExtendedOp structures
358 * asscoiated with a particular extended operation
361 * Input: pBE - pointer to a backend structure
362 * opList - pointer to a linked list of extended
363 * operation structures
364 * pPB - pointer to a slapi parameter block
371 *********************************************************************/
373 slapi_int_unregister_extop(
378 ExtendedOp *pTmpExtOp, *backExtOp;
383 assert( pBE != NULL); /* unused */
385 assert( opList != NULL );
386 assert( pPB != NULL );
388 if ( *opList == NULL ) {
392 slapi_pblock_get( pPB, SLAPI_PLUGIN_EXT_OP_OIDLIST, &pTmpOIDs );
393 if ( pTmpOIDs == NULL ) {
397 for ( i = 0; pTmpOIDs[i] != NULL; i++ ) {
400 for ( ; pTmpExtOp != NULL; pTmpExtOp = pTmpExtOp->ext_next) {
402 rc = strcasecmp( pTmpExtOp->ext_oid.bv_val,
405 if ( backExtOp == NULL ) {
406 *opList = pTmpExtOp->ext_next;
409 = pTmpExtOp->ext_next;
412 ch_free( pTmpExtOp );
415 backExtOp = pTmpExtOp;
421 /*********************************************************************
422 * Function Name: slapi_int_register_extop
424 * Description: This routine creates a new ExtendedOp structure, loads
425 * in the extended op module and put the extended op function address
426 * in the structure. The function will not be executed in
429 * Input: pBE - pointer to a backend structure
430 * opList - pointer to a linked list of extended
431 * operation structures
432 * pPB - pointer to a slapi parameter block
436 * Return Value: an LDAP return code
439 *********************************************************************/
441 slapi_int_register_extop(
446 ExtendedOp *pTmpExtOp = NULL;
452 if ( (*opList) == NULL ) {
453 *opList = createExtendedOp();
454 if ( (*opList) == NULL ) {
460 } else { /* Find the end of the list */
461 for ( pTmpExtOp = *opList; pTmpExtOp->ext_next != NULL;
462 pTmpExtOp = pTmpExtOp->ext_next )
464 pTmpExtOp->ext_next = createExtendedOp();
465 if ( pTmpExtOp->ext_next == NULL ) {
469 pTmpExtOp = pTmpExtOp->ext_next;
472 rc = slapi_pblock_get( pPB,SLAPI_PLUGIN_EXT_OP_OIDLIST, &pTmpOIDs );
478 rc = slapi_pblock_get(pPB,SLAPI_PLUGIN_EXT_OP_FN, &tmpFunc);
484 if ( (pTmpOIDs == NULL) || (tmpFunc == NULL) ) {
489 for ( i = 0; pTmpOIDs[i] != NULL; i++ ) {
490 pTmpExtOp->ext_oid.bv_val = pTmpOIDs[i];
491 pTmpExtOp->ext_oid.bv_len = strlen( pTmpOIDs[i] );
492 pTmpExtOp->ext_func = tmpFunc;
493 pTmpExtOp->ext_be = pBE;
494 if ( pTmpOIDs[i + 1] != NULL ) {
495 pTmpExtOp->ext_next = createExtendedOp();
496 if ( pTmpExtOp->ext_next == NULL ) {
500 pTmpExtOp = pTmpExtOp->ext_next;
508 /*********************************************************************
509 * Function Name: slapi_int_get_extop_plugin
511 * Description: This routine gets the function address for a given function
515 * funcName - name of the extended op function, ie. an OID.
517 * Output: pFuncAddr - the function address of the requested function name.
519 * Return Values: a pointer to a newly created ExtendOp structrue or
520 * NULL - function failed
523 *********************************************************************/
525 slapi_int_get_extop_plugin(
526 struct berval *reqoid,
527 SLAPI_FUNC *pFuncAddr )
529 ExtendedOp *pTmpExtOp;
531 assert( reqoid != NULL );
532 assert( pFuncAddr != NULL );
536 if ( pGExtendedOps == NULL ) {
540 pTmpExtOp = pGExtendedOps;
541 while ( pTmpExtOp != NULL ) {
544 rc = strcasecmp( reqoid->bv_val, pTmpExtOp->ext_oid.bv_val );
546 *pFuncAddr = pTmpExtOp->ext_func;
549 pTmpExtOp = pTmpExtOp->ext_next;
552 return ( *pFuncAddr == NULL ? 1 : 0 );
555 /***************************************************************************
556 * This function is similar to slapi_int_get_extop_plugin above. except it returns one OID
557 * per call. It is called from root_dse_info (root_dse.c).
558 * The function is a modified version of get_supported_extop (file extended.c).
559 ***************************************************************************/
561 slapi_int_get_supported_extop( int index )
565 for ( ext = pGExtendedOps ; ext != NULL && --index >= 0;
566 ext = ext->ext_next) {
574 return &ext->ext_oid ;
577 /*********************************************************************
578 * Function Name: slapi_int_load_plugin
580 * Description: This routine loads the specified DLL, gets and executes the init function
584 * pPlugin - a pointer to a Slapi_PBlock struct which will be passed to
585 * the DLL init function.
586 * path - path name of the DLL to be load.
587 * initfunc - either the DLL initialization function or an OID of the
588 * loaded extended operation.
589 * doInit - if it is TRUE, execute the init function, otherwise, save the
590 * function address but not execute it.
592 * Output: pInitFunc - the function address of the loaded function. This param
593 * should be not be null if doInit is FALSE.
594 * pLdHandle - handle returned by lt_dlopen()
596 * Return Values: LDAP_SUCCESS, LDAP_LOCAL_ERROR
599 *********************************************************************/
602 slapi_int_load_plugin(
603 Slapi_PBlock *pPlugin,
605 const char *initfunc,
607 SLAPI_FUNC *pInitFunc,
608 lt_dlhandle *pLdHandle )
610 int rc = LDAP_SUCCESS;
611 SLAPI_FUNC fpInitFunc = NULL;
616 return LDAP_LOCAL_ERROR;
619 /* load in the module */
620 *pLdHandle = lt_dlopen( path );
621 if ( *pLdHandle == NULL ) {
622 return LDAP_LOCAL_ERROR;
625 fpInitFunc = (SLAPI_FUNC)lt_dlsym( *pLdHandle, initfunc );
626 if ( fpInitFunc == NULL ) {
627 lt_dlclose( *pLdHandle );
628 return LDAP_LOCAL_ERROR;
631 if ( doInit == TRUE ) {
632 rc = ( *fpInitFunc )( pPlugin );
633 if ( rc != LDAP_SUCCESS ) {
634 lt_dlclose( *pLdHandle );
638 *pInitFunc = fpInitFunc;
645 * Special support for computed attribute plugins
648 slapi_int_call_plugins(
655 SLAPI_FUNC *pGetPlugin = NULL, *tmpPlugin = NULL;
661 rc = slapi_int_get_plugins( be, funcType, &tmpPlugin );
662 if ( rc != LDAP_SUCCESS || tmpPlugin == NULL ) {
663 /* Nothing to do, front-end should ignore. */
667 for ( pGetPlugin = tmpPlugin ; *pGetPlugin != NULL; pGetPlugin++ ) {
669 * FIXME: we should provide here a sort of sandbox,
670 * to protect from plugin faults; e.g. trap signals
671 * and longjump here, marking the plugin as unsafe for
672 * later executions ...
674 rc = (*pGetPlugin)(pPB);
677 * Only non-postoperation plugins abort processing on
678 * failure (confirmed with SLAPI specification).
680 if ( !SLAPI_PLUGIN_IS_POST_FN( funcType ) && rc != 0 ) {
682 * Plugins generally return negative error codes
683 * to indicate failure, although in the case of
684 * bind plugins they may return SLAPI_BIND_xxx
690 slapi_ch_free( (void **)&tmpPlugin );
696 slapi_int_read_config(
704 int numPluginArgc = 0;
708 "%s: line %d: missing arguments "
709 "in \"plugin <plugin_type> <lib_path> "
710 "<init_function> [<arguments>]\" line\n",
715 if ( strcasecmp( argv[1], "preoperation" ) == 0 ) {
716 iType = SLAPI_PLUGIN_PREOPERATION;
717 } else if ( strcasecmp( argv[1], "postoperation" ) == 0 ) {
718 iType = SLAPI_PLUGIN_POSTOPERATION;
719 } else if ( strcasecmp( argv[1], "extendedop" ) == 0 ) {
720 iType = SLAPI_PLUGIN_EXTENDEDOP;
721 } else if ( strcasecmp( argv[1], "object" ) == 0 ) {
722 iType = SLAPI_PLUGIN_OBJECT;
724 fprintf( stderr, "%s: line %d: invalid plugin type \"%s\".\n",
725 fname, lineno, argv[1] );
729 numPluginArgc = argc - 4;
731 if ( iType == SLAPI_PLUGIN_PREOPERATION ||
732 iType == SLAPI_PLUGIN_EXTENDEDOP ||
733 iType == SLAPI_PLUGIN_POSTOPERATION ||
734 iType == SLAPI_PLUGIN_OBJECT ) {
736 Slapi_PBlock *pPlugin;
738 pPlugin = plugin_pblock_new( iType, numPluginArgc, argv );
739 if (pPlugin == NULL) {
743 if (iType == SLAPI_PLUGIN_EXTENDEDOP) {
744 rc = slapi_int_register_extop(be, &pGExtendedOps, pPlugin);
745 if ( rc != LDAP_SUCCESS ) {
746 slapi_pblock_destroy( pPlugin );
751 rc = slapi_int_register_plugin( be, pPlugin );
752 if ( rc != LDAP_SUCCESS ) {
753 if ( iType == SLAPI_PLUGIN_EXTENDEDOP ) {
754 slapi_int_unregister_extop( be, &pGExtendedOps, pPlugin );
756 slapi_pblock_destroy( pPlugin );
765 slapi_int_plugin_unparse(
772 char **argv, ibuf[32], *ptr;
773 struct berval idx, bv;
778 for ( pp=be->be_pb; pp; slapi_pblock_get( pp, SLAPI_IBM_PBLOCK, &pp ) ) {
779 slapi_pblock_get( pp, SLAPI_X_CONFIG_ARGV, &argv );
780 idx.bv_len = sprintf( idx.bv_val, "{%d}", i );
781 bv.bv_len = idx.bv_len;
782 for (j=1; argv[j]; j++) {
783 bv.bv_len += strlen(argv[j]);
784 if ( j ) bv.bv_len++;
786 bv.bv_val = ch_malloc( bv.bv_len + 1 );
787 ptr = lutil_strcopy( bv.bv_val, ibuf );
788 for (j=1; argv[j]; j++) {
789 if ( j ) *ptr++ = ' ';
790 ptr = lutil_strcopy( ptr, argv[j] );
792 ber_bvarray_add( out, &bv );
797 slapi_int_initialize(void)
799 if ( ldap_pvt_thread_mutex_init( &slapi_hn_mutex ) ) {
803 if ( ldap_pvt_thread_mutex_init( &slapi_time_mutex ) ) {
807 if ( ldap_pvt_thread_mutex_init( &slapi_printmessage_mutex ) ) {
811 slapi_log_file = ch_strdup( LDAP_RUNDIR LDAP_DIRSEP "errors" );
812 if ( slapi_log_file == NULL ) {
816 if ( slapi_int_init_object_extensions() != 0 ) {