1 /* $OpenLDAP: pkg/ldap/servers/slapd/slapi/plugin.c,v 1.43.2.6 2008/06/02 18:00:53 quanah Exp $ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 2002-2008 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"
31 * Note: if ltdl.h is not available, slapi should not be compiled
35 static int slapi_int_load_plugin( Slapi_PBlock
*, const char *, const char *, int,
36 SLAPI_FUNC
*, lt_dlhandle
* );
38 /* pointer to link list of extended objects */
39 static ExtendedOp
*pGExtendedOps
= NULL
;
41 /*********************************************************************
42 * Function Name: plugin_pblock_new
44 * Description: This routine creates a new Slapi_PBlock structure,
45 * loads in the plugin module and executes the init
46 * function provided by the module.
48 * Input: type - type of the plugin, such as SASL, database, etc.
49 * path - the loadpath to load the module in
50 * initfunc - name of the plugin function to execute first
51 * argc - number of arguements
52 * argv[] - an array of char pointers point to
53 * the arguments passed in via
54 * the configuration file.
58 * Return Values: a pointer to a newly created Slapi_PBlock structrue or
59 * NULL - function failed
62 *********************************************************************/
70 Slapi_PBlock
*pPlugin
= NULL
;
71 Slapi_PluginDesc
*pPluginDesc
= NULL
;
72 lt_dlhandle hdLoadHandle
;
74 char **av2
= NULL
, **ppPluginArgv
;
76 char *initfunc
= argv
[3];
78 pPlugin
= slapi_pblock_new();
79 if ( pPlugin
== NULL
) {
84 slapi_pblock_set( pPlugin
, SLAPI_PLUGIN_TYPE
, (void *)&type
);
85 slapi_pblock_set( pPlugin
, SLAPI_PLUGIN_ARGC
, (void *)&argc
);
87 av2
= ldap_charray_dup( argv
);
94 ppPluginArgv
= &av2
[4];
99 slapi_pblock_set( pPlugin
, SLAPI_PLUGIN_ARGV
, (void *)ppPluginArgv
);
100 slapi_pblock_set( pPlugin
, SLAPI_X_CONFIG_ARGV
, (void *)av2
);
102 rc
= slapi_int_load_plugin( pPlugin
, path
, initfunc
, 1, NULL
, &hdLoadHandle
);
107 if ( slapi_pblock_get( pPlugin
, SLAPI_PLUGIN_DESCRIPTION
, (void **)&pPluginDesc
) == 0 &&
108 pPluginDesc
!= NULL
) {
109 slapi_log_error(SLAPI_LOG_TRACE
, "plugin_pblock_new",
110 "Registered plugin %s %s [%s] (%s)\n",
112 pPluginDesc
->spd_version
,
113 pPluginDesc
->spd_vendor
,
114 pPluginDesc
->spd_description
);
118 if ( rc
!= 0 && pPlugin
!= NULL
) {
119 slapi_pblock_destroy( pPlugin
);
122 ldap_charray_free( av2
);
129 /*********************************************************************
130 * Function Name: slapi_int_register_plugin
132 * Description: insert the slapi_pblock structure to the end of the plugin
135 * Input: a pointer to a plugin slapi_pblock structure to be added to
140 * Return Values: LDAP_SUCCESS - successfully inserted.
144 *********************************************************************/
146 slapi_int_register_plugin(
150 Slapi_PBlock
*pTmpPB
;
151 Slapi_PBlock
*pSavePB
;
152 int rc
= LDAP_SUCCESS
;
154 assert( be
!= NULL
);
156 pTmpPB
= SLAPI_BACKEND_PBLOCK( be
);
157 if ( pTmpPB
== NULL
) {
158 SLAPI_BACKEND_PBLOCK( be
) = pPB
;
160 while ( pTmpPB
!= NULL
&& rc
== LDAP_SUCCESS
) {
162 rc
= slapi_pblock_get( pTmpPB
, SLAPI_IBM_PBLOCK
, &pTmpPB
);
165 if ( rc
== LDAP_SUCCESS
) {
166 rc
= slapi_pblock_set( pSavePB
, SLAPI_IBM_PBLOCK
, (void *)pPB
);
170 return ( rc
!= LDAP_SUCCESS
) ? LDAP_OTHER
: LDAP_SUCCESS
;
173 /*********************************************************************
174 * Function Name: slapi_int_get_plugins
176 * Description: get the desired type of function pointers defined
179 * Input: the type of the functions to get, such as pre-operation,etc.
183 * Return Values: this routine returns a pointer to an array of function
184 * pointers containing backend-specific plugin functions
185 * followed by global plugin functions
188 *********************************************************************/
190 slapi_int_get_plugins(
193 SLAPI_FUNC
**ppFuncPtrs
)
196 Slapi_PBlock
*pCurrentPB
;
198 SLAPI_FUNC
*pTmpFuncPtr
;
200 int rc
= LDAP_SUCCESS
;
202 assert( ppFuncPtrs
!= NULL
);
208 pCurrentPB
= SLAPI_BACKEND_PBLOCK( be
);
210 while ( pCurrentPB
!= NULL
&& rc
== LDAP_SUCCESS
) {
211 rc
= slapi_pblock_get( pCurrentPB
, functype
, &FuncPtr
);
212 if ( rc
== LDAP_SUCCESS
) {
213 if ( FuncPtr
!= NULL
) {
216 rc
= slapi_pblock_get( pCurrentPB
,
217 SLAPI_IBM_PBLOCK
, &pCurrentPB
);
228 * Now, build the function pointer array of backend-specific
229 * plugins followed by global plugins.
231 *ppFuncPtrs
= pTmpFuncPtr
=
232 (SLAPI_FUNC
*)ch_malloc( ( numPB
+ 1 ) * sizeof(SLAPI_FUNC
) );
233 if ( ppFuncPtrs
== NULL
) {
238 pCurrentPB
= SLAPI_BACKEND_PBLOCK( be
);
240 while ( pCurrentPB
!= NULL
&& rc
== LDAP_SUCCESS
) {
241 rc
= slapi_pblock_get( pCurrentPB
, functype
, &FuncPtr
);
242 if ( rc
== LDAP_SUCCESS
) {
243 if ( FuncPtr
!= NULL
) {
244 *pTmpFuncPtr
= FuncPtr
;
247 rc
= slapi_pblock_get( pCurrentPB
,
248 SLAPI_IBM_PBLOCK
, &pCurrentPB
);
256 if ( rc
!= LDAP_SUCCESS
&& *ppFuncPtrs
!= NULL
) {
257 ch_free( *ppFuncPtrs
);
264 /*********************************************************************
265 * Function Name: createExtendedOp
267 * Description: Creates an extended operation structure and
268 * initializes the fields
270 * Return value: A newly allocated structure or NULL
271 ********************************************************************/
277 ret
= (ExtendedOp
*)slapi_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
;
288 /*********************************************************************
289 * Function Name: slapi_int_unregister_extop
291 * Description: This routine removes the ExtendedOp structures
292 * asscoiated with a particular extended operation
295 * Input: pBE - pointer to a backend structure
296 * opList - pointer to a linked list of extended
297 * operation structures
298 * pPB - pointer to a slapi parameter block
305 *********************************************************************/
307 slapi_int_unregister_extop(
312 ExtendedOp
*pTmpExtOp
, *backExtOp
;
317 assert( pBE
!= NULL
); /* unused */
319 assert( opList
!= NULL
);
320 assert( pPB
!= NULL
);
322 if ( *opList
== NULL
) {
326 slapi_pblock_get( pPB
, SLAPI_PLUGIN_EXT_OP_OIDLIST
, &pTmpOIDs
);
327 if ( pTmpOIDs
== NULL
) {
331 for ( i
= 0; pTmpOIDs
[i
] != NULL
; i
++ ) {
334 for ( ; pTmpExtOp
!= NULL
; pTmpExtOp
= pTmpExtOp
->ext_next
) {
336 rc
= strcasecmp( pTmpExtOp
->ext_oid
.bv_val
,
339 if ( backExtOp
== NULL
) {
340 *opList
= pTmpExtOp
->ext_next
;
343 = pTmpExtOp
->ext_next
;
346 ch_free( pTmpExtOp
);
349 backExtOp
= pTmpExtOp
;
355 /*********************************************************************
356 * Function Name: slapi_int_register_extop
358 * Description: This routine creates a new ExtendedOp structure, loads
359 * in the extended op module and put the extended op function address
360 * in the structure. The function will not be executed in
363 * Input: pBE - pointer to a backend structure
364 * opList - pointer to a linked list of extended
365 * operation structures
366 * pPB - pointer to a slapi parameter block
370 * Return Value: an LDAP return code
373 *********************************************************************/
375 slapi_int_register_extop(
380 ExtendedOp
*pTmpExtOp
= NULL
;
386 if ( (*opList
) == NULL
) {
387 *opList
= createExtendedOp();
388 if ( (*opList
) == NULL
) {
394 } else { /* Find the end of the list */
395 for ( pTmpExtOp
= *opList
; pTmpExtOp
->ext_next
!= NULL
;
396 pTmpExtOp
= pTmpExtOp
->ext_next
)
398 pTmpExtOp
->ext_next
= createExtendedOp();
399 if ( pTmpExtOp
->ext_next
== NULL
) {
403 pTmpExtOp
= pTmpExtOp
->ext_next
;
406 rc
= slapi_pblock_get( pPB
,SLAPI_PLUGIN_EXT_OP_OIDLIST
, &pTmpOIDs
);
412 rc
= slapi_pblock_get(pPB
,SLAPI_PLUGIN_EXT_OP_FN
, &tmpFunc
);
418 if ( (pTmpOIDs
== NULL
) || (tmpFunc
== NULL
) ) {
423 for ( i
= 0; pTmpOIDs
[i
] != NULL
; i
++ ) {
424 pTmpExtOp
->ext_oid
.bv_val
= pTmpOIDs
[i
];
425 pTmpExtOp
->ext_oid
.bv_len
= strlen( pTmpOIDs
[i
] );
426 pTmpExtOp
->ext_func
= tmpFunc
;
427 pTmpExtOp
->ext_be
= pBE
;
428 if ( pTmpOIDs
[i
+ 1] != NULL
) {
429 pTmpExtOp
->ext_next
= createExtendedOp();
430 if ( pTmpExtOp
->ext_next
== NULL
) {
434 pTmpExtOp
= pTmpExtOp
->ext_next
;
442 /*********************************************************************
443 * Function Name: slapi_int_get_extop_plugin
445 * Description: This routine gets the function address for a given function
449 * funcName - name of the extended op function, ie. an OID.
451 * Output: pFuncAddr - the function address of the requested function name.
453 * Return Values: a pointer to a newly created ExtendOp structrue or
454 * NULL - function failed
457 *********************************************************************/
459 slapi_int_get_extop_plugin(
460 struct berval
*reqoid
,
461 SLAPI_FUNC
*pFuncAddr
)
463 ExtendedOp
*pTmpExtOp
;
465 assert( reqoid
!= NULL
);
466 assert( pFuncAddr
!= NULL
);
470 if ( pGExtendedOps
== NULL
) {
474 pTmpExtOp
= pGExtendedOps
;
475 while ( pTmpExtOp
!= NULL
) {
478 rc
= strcasecmp( reqoid
->bv_val
, pTmpExtOp
->ext_oid
.bv_val
);
480 *pFuncAddr
= pTmpExtOp
->ext_func
;
483 pTmpExtOp
= pTmpExtOp
->ext_next
;
486 return ( *pFuncAddr
== NULL
? 1 : 0 );
489 /***************************************************************************
490 * This function is similar to slapi_int_get_extop_plugin above. except it returns one OID
491 * per call. It is called from root_dse_info (root_dse.c).
492 * The function is a modified version of get_supported_extop (file extended.c).
493 ***************************************************************************/
495 slapi_int_get_supported_extop( int index
)
499 for ( ext
= pGExtendedOps
; ext
!= NULL
&& --index
>= 0;
500 ext
= ext
->ext_next
) {
508 return &ext
->ext_oid
;
511 /*********************************************************************
512 * Function Name: slapi_int_load_plugin
514 * Description: This routine loads the specified DLL, gets and executes the init function
518 * pPlugin - a pointer to a Slapi_PBlock struct which will be passed to
519 * the DLL init function.
520 * path - path name of the DLL to be load.
521 * initfunc - either the DLL initialization function or an OID of the
522 * loaded extended operation.
523 * doInit - if it is TRUE, execute the init function, otherwise, save the
524 * function address but not execute it.
526 * Output: pInitFunc - the function address of the loaded function. This param
527 * should be not be null if doInit is FALSE.
528 * pLdHandle - handle returned by lt_dlopen()
530 * Return Values: LDAP_SUCCESS, LDAP_LOCAL_ERROR
533 *********************************************************************/
536 slapi_int_load_plugin(
537 Slapi_PBlock
*pPlugin
,
539 const char *initfunc
,
541 SLAPI_FUNC
*pInitFunc
,
542 lt_dlhandle
*pLdHandle
)
544 int rc
= LDAP_SUCCESS
;
545 SLAPI_FUNC fpInitFunc
= NULL
;
547 assert( pLdHandle
!= NULL
);
550 return LDAP_LOCAL_ERROR
;
553 /* load in the module */
554 *pLdHandle
= lt_dlopen( path
);
555 if ( *pLdHandle
== NULL
) {
556 fprintf( stderr
, "failed to load plugin %s: %s\n",
557 path
, lt_dlerror() );
558 return LDAP_LOCAL_ERROR
;
561 fpInitFunc
= (SLAPI_FUNC
)lt_dlsym( *pLdHandle
, initfunc
);
562 if ( fpInitFunc
== NULL
) {
563 fprintf( stderr
, "failed to find symbol %s in plugin %s: %s\n",
564 initfunc
, path
, lt_dlerror() );
565 lt_dlclose( *pLdHandle
);
566 return LDAP_LOCAL_ERROR
;
570 rc
= ( *fpInitFunc
)( pPlugin
);
571 if ( rc
!= LDAP_SUCCESS
) {
572 lt_dlclose( *pLdHandle
);
576 *pInitFunc
= fpInitFunc
;
583 * Special support for computed attribute plugins
586 slapi_int_call_plugins(
593 SLAPI_FUNC
*pGetPlugin
= NULL
, *tmpPlugin
= NULL
;
599 rc
= slapi_int_get_plugins( be
, funcType
, &tmpPlugin
);
600 if ( rc
!= LDAP_SUCCESS
|| tmpPlugin
== NULL
) {
601 /* Nothing to do, front-end should ignore. */
605 for ( pGetPlugin
= tmpPlugin
; *pGetPlugin
!= NULL
; pGetPlugin
++ ) {
606 rc
= (*pGetPlugin
)(pPB
);
609 * Only non-postoperation plugins abort processing on
610 * failure (confirmed with SLAPI specification).
612 if ( !SLAPI_PLUGIN_IS_POST_FN( funcType
) && rc
!= 0 ) {
614 * Plugins generally return negative error codes
615 * to indicate failure, although in the case of
616 * bind plugins they may return SLAPI_BIND_xxx
622 slapi_ch_free( (void **)&tmpPlugin
);
628 slapi_int_read_config(
636 int numPluginArgc
= 0;
640 "%s: line %d: missing arguments "
641 "in \"plugin <plugin_type> <lib_path> "
642 "<init_function> [<arguments>]\" line\n",
647 /* automatically instantiate overlay if necessary */
648 if ( !slapi_over_is_inst( be
) ) {
649 ConfigReply cr
= { 0 };
650 if ( slapi_over_config( be
, &cr
) != 0 ) {
651 fprintf( stderr
, "Failed to instantiate SLAPI overlay: "
652 "err=%d msg=\"%s\"\n", cr
.err
, cr
.msg
);
657 if ( strcasecmp( argv
[1], "preoperation" ) == 0 ) {
658 iType
= SLAPI_PLUGIN_PREOPERATION
;
659 } else if ( strcasecmp( argv
[1], "postoperation" ) == 0 ) {
660 iType
= SLAPI_PLUGIN_POSTOPERATION
;
661 } else if ( strcasecmp( argv
[1], "extendedop" ) == 0 ) {
662 iType
= SLAPI_PLUGIN_EXTENDEDOP
;
663 } else if ( strcasecmp( argv
[1], "object" ) == 0 ) {
664 iType
= SLAPI_PLUGIN_OBJECT
;
666 fprintf( stderr
, "%s: line %d: invalid plugin type \"%s\".\n",
667 fname
, lineno
, argv
[1] );
671 numPluginArgc
= argc
- 4;
673 if ( iType
== SLAPI_PLUGIN_PREOPERATION
||
674 iType
== SLAPI_PLUGIN_EXTENDEDOP
||
675 iType
== SLAPI_PLUGIN_POSTOPERATION
||
676 iType
== SLAPI_PLUGIN_OBJECT
) {
678 Slapi_PBlock
*pPlugin
;
680 pPlugin
= plugin_pblock_new( iType
, numPluginArgc
, argv
);
681 if (pPlugin
== NULL
) {
685 if (iType
== SLAPI_PLUGIN_EXTENDEDOP
) {
686 rc
= slapi_int_register_extop(be
, &pGExtendedOps
, pPlugin
);
687 if ( rc
!= LDAP_SUCCESS
) {
688 slapi_pblock_destroy( pPlugin
);
693 rc
= slapi_int_register_plugin( be
, pPlugin
);
694 if ( rc
!= LDAP_SUCCESS
) {
695 if ( iType
== SLAPI_PLUGIN_EXTENDEDOP
) {
696 slapi_int_unregister_extop( be
, &pGExtendedOps
, pPlugin
);
698 slapi_pblock_destroy( pPlugin
);
707 slapi_int_plugin_unparse(
714 char **argv
, ibuf
[32], *ptr
;
715 struct berval idx
, bv
;
721 for ( pp
= SLAPI_BACKEND_PBLOCK( be
);
723 slapi_pblock_get( pp
, SLAPI_IBM_PBLOCK
, &pp
) )
725 slapi_pblock_get( pp
, SLAPI_X_CONFIG_ARGV
, &argv
);
726 if ( argv
== NULL
) /* could be dynamic plugin */
728 idx
.bv_len
= snprintf( idx
.bv_val
, sizeof( ibuf
), "{%d}", i
);
729 if ( idx
.bv_len
>= sizeof( ibuf
) ) {
730 /* FIXME: just truncating by now */
731 idx
.bv_len
= sizeof( ibuf
) - 1;
733 bv
.bv_len
= idx
.bv_len
;
734 for (j
=1; argv
[j
]; j
++) {
735 bv
.bv_len
+= strlen(argv
[j
]);
736 if ( j
) bv
.bv_len
++;
738 bv
.bv_val
= ch_malloc( bv
.bv_len
+ 1 );
739 ptr
= lutil_strcopy( bv
.bv_val
, ibuf
);
740 for (j
=1; argv
[j
]; j
++) {
741 if ( j
) *ptr
++ = ' ';
742 ptr
= lutil_strcopy( ptr
, argv
[j
] );
744 ber_bvarray_add( out
, &bv
);