Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / bsd / openldap / dist / servers / slapd / slapi / plugin.c
blob8283fa279cfb584b38a37f5501c94429610b46b3
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.
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
10 * Public License.
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>.
16 /* ACKNOWLEDGEMENTS:
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:
20 * Luke Howard
23 #include "portable.h"
24 #include "ldap_pvt_thread.h"
25 #include "slap.h"
26 #include "config.h"
27 #include "slapi.h"
28 #include "lutil.h"
31 * Note: if ltdl.h is not available, slapi should not be compiled
33 #include <ltdl.h>
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.
56 * Output:
58 * Return Values: a pointer to a newly created Slapi_PBlock structrue or
59 * NULL - function failed
61 * Messages: None
62 *********************************************************************/
64 static Slapi_PBlock *
65 plugin_pblock_new(
66 int type,
67 int argc,
68 char *argv[] )
70 Slapi_PBlock *pPlugin = NULL;
71 Slapi_PluginDesc *pPluginDesc = NULL;
72 lt_dlhandle hdLoadHandle;
73 int rc;
74 char **av2 = NULL, **ppPluginArgv;
75 char *path = argv[2];
76 char *initfunc = argv[3];
78 pPlugin = slapi_pblock_new();
79 if ( pPlugin == NULL ) {
80 rc = LDAP_NO_MEMORY;
81 goto done;
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 );
88 if ( av2 == NULL ) {
89 rc = LDAP_NO_MEMORY;
90 goto done;
93 if ( argc > 0 ) {
94 ppPluginArgv = &av2[4];
95 } else {
96 ppPluginArgv = NULL;
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 );
103 if ( rc != 0 ) {
104 goto done;
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",
111 pPluginDesc->spd_id,
112 pPluginDesc->spd_version,
113 pPluginDesc->spd_vendor,
114 pPluginDesc->spd_description);
117 done:
118 if ( rc != 0 && pPlugin != NULL ) {
119 slapi_pblock_destroy( pPlugin );
120 pPlugin = NULL;
121 if ( av2 != NULL ) {
122 ldap_charray_free( av2 );
126 return pPlugin;
129 /*********************************************************************
130 * Function Name: slapi_int_register_plugin
132 * Description: insert the slapi_pblock structure to the end of the plugin
133 * list
135 * Input: a pointer to a plugin slapi_pblock structure to be added to
136 * the list
138 * Output: none
140 * Return Values: LDAP_SUCCESS - successfully inserted.
141 * LDAP_LOCAL_ERROR.
143 * Messages: None
144 *********************************************************************/
145 int
146 slapi_int_register_plugin(
147 Backend *be,
148 Slapi_PBlock *pPB )
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;
159 } else {
160 while ( pTmpPB != NULL && rc == LDAP_SUCCESS ) {
161 pSavePB = pTmpPB;
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
177 * in all the plugins
179 * Input: the type of the functions to get, such as pre-operation,etc.
181 * Output: none
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
187 * Messages: None
188 *********************************************************************/
189 int
190 slapi_int_get_plugins(
191 Backend *be,
192 int functype,
193 SLAPI_FUNC **ppFuncPtrs )
196 Slapi_PBlock *pCurrentPB;
197 SLAPI_FUNC FuncPtr;
198 SLAPI_FUNC *pTmpFuncPtr;
199 int numPB = 0;
200 int rc = LDAP_SUCCESS;
202 assert( ppFuncPtrs != NULL );
204 if ( be == NULL ) {
205 goto done;
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 ) {
214 numPB++;
216 rc = slapi_pblock_get( pCurrentPB,
217 SLAPI_IBM_PBLOCK, &pCurrentPB );
221 if ( numPB == 0 ) {
222 *ppFuncPtrs = NULL;
223 rc = LDAP_SUCCESS;
224 goto done;
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 ) {
234 rc = LDAP_NO_MEMORY;
235 goto done;
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;
245 pTmpFuncPtr++;
247 rc = slapi_pblock_get( pCurrentPB,
248 SLAPI_IBM_PBLOCK, &pCurrentPB );
252 *pTmpFuncPtr = NULL;
255 done:
256 if ( rc != LDAP_SUCCESS && *ppFuncPtrs != NULL ) {
257 ch_free( *ppFuncPtrs );
258 *ppFuncPtrs = NULL;
261 return rc;
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 ********************************************************************/
272 ExtendedOp *
273 createExtendedOp()
275 ExtendedOp *ret;
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;
281 ret->ext_be = NULL;
282 ret->ext_next = NULL;
284 return ret;
288 /*********************************************************************
289 * Function Name: slapi_int_unregister_extop
291 * Description: This routine removes the ExtendedOp structures
292 * asscoiated with a particular extended operation
293 * plugin.
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
300 * Output:
302 * Return Value: none
304 * Messages: None
305 *********************************************************************/
306 void
307 slapi_int_unregister_extop(
308 Backend *pBE,
309 ExtendedOp **opList,
310 Slapi_PBlock *pPB )
312 ExtendedOp *pTmpExtOp, *backExtOp;
313 char **pTmpOIDs;
314 int i;
316 #if 0
317 assert( pBE != NULL); /* unused */
318 #endif /* 0 */
319 assert( opList != NULL );
320 assert( pPB != NULL );
322 if ( *opList == NULL ) {
323 return;
326 slapi_pblock_get( pPB, SLAPI_PLUGIN_EXT_OP_OIDLIST, &pTmpOIDs );
327 if ( pTmpOIDs == NULL ) {
328 return;
331 for ( i = 0; pTmpOIDs[i] != NULL; i++ ) {
332 backExtOp = NULL;
333 pTmpExtOp = *opList;
334 for ( ; pTmpExtOp != NULL; pTmpExtOp = pTmpExtOp->ext_next) {
335 int rc;
336 rc = strcasecmp( pTmpExtOp->ext_oid.bv_val,
337 pTmpOIDs[ i ] );
338 if ( rc == 0 ) {
339 if ( backExtOp == NULL ) {
340 *opList = pTmpExtOp->ext_next;
341 } else {
342 backExtOp->ext_next
343 = pTmpExtOp->ext_next;
346 ch_free( pTmpExtOp );
347 break;
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
361 * this routine.
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
368 * Output:
370 * Return Value: an LDAP return code
372 * Messages: None
373 *********************************************************************/
374 int
375 slapi_int_register_extop(
376 Backend *pBE,
377 ExtendedOp **opList,
378 Slapi_PBlock *pPB )
380 ExtendedOp *pTmpExtOp = NULL;
381 SLAPI_FUNC tmpFunc;
382 char **pTmpOIDs;
383 int rc = LDAP_OTHER;
384 int i;
386 if ( (*opList) == NULL ) {
387 *opList = createExtendedOp();
388 if ( (*opList) == NULL ) {
389 rc = LDAP_NO_MEMORY;
390 goto error_return;
392 pTmpExtOp = *opList;
394 } else { /* Find the end of the list */
395 for ( pTmpExtOp = *opList; pTmpExtOp->ext_next != NULL;
396 pTmpExtOp = pTmpExtOp->ext_next )
397 ; /* EMPTY */
398 pTmpExtOp->ext_next = createExtendedOp();
399 if ( pTmpExtOp->ext_next == NULL ) {
400 rc = LDAP_NO_MEMORY;
401 goto error_return;
403 pTmpExtOp = pTmpExtOp->ext_next;
406 rc = slapi_pblock_get( pPB,SLAPI_PLUGIN_EXT_OP_OIDLIST, &pTmpOIDs );
407 if ( rc != 0 ) {
408 rc = LDAP_OTHER;
409 goto error_return;
412 rc = slapi_pblock_get(pPB,SLAPI_PLUGIN_EXT_OP_FN, &tmpFunc);
413 if ( rc != 0 ) {
414 rc = LDAP_OTHER;
415 goto error_return;
418 if ( (pTmpOIDs == NULL) || (tmpFunc == NULL) ) {
419 rc = LDAP_OTHER;
420 goto error_return;
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 ) {
431 rc = LDAP_NO_MEMORY;
432 break;
434 pTmpExtOp = pTmpExtOp->ext_next;
438 error_return:
439 return rc;
442 /*********************************************************************
443 * Function Name: slapi_int_get_extop_plugin
445 * Description: This routine gets the function address for a given function
446 * name.
448 * Input:
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
456 * Messages: None
457 *********************************************************************/
458 int
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 );
468 *pFuncAddr = NULL;
470 if ( pGExtendedOps == NULL ) {
471 return LDAP_OTHER;
474 pTmpExtOp = pGExtendedOps;
475 while ( pTmpExtOp != NULL ) {
476 int rc;
478 rc = strcasecmp( reqoid->bv_val, pTmpExtOp->ext_oid.bv_val );
479 if ( rc == 0 ) {
480 *pFuncAddr = pTmpExtOp->ext_func;
481 break;
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 ***************************************************************************/
494 struct berval *
495 slapi_int_get_supported_extop( int index )
497 ExtendedOp *ext;
499 for ( ext = pGExtendedOps ; ext != NULL && --index >= 0;
500 ext = ext->ext_next) {
501 ; /* empty */
504 if ( ext == NULL ) {
505 return NULL;
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
515 * if requested.
517 * Input:
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
532 * Messages: None
533 *********************************************************************/
535 static int
536 slapi_int_load_plugin(
537 Slapi_PBlock *pPlugin,
538 const char *path,
539 const char *initfunc,
540 int doInit,
541 SLAPI_FUNC *pInitFunc,
542 lt_dlhandle *pLdHandle )
544 int rc = LDAP_SUCCESS;
545 SLAPI_FUNC fpInitFunc = NULL;
547 assert( pLdHandle != NULL );
549 if ( lt_dlinit() ) {
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;
569 if ( doInit ) {
570 rc = ( *fpInitFunc )( pPlugin );
571 if ( rc != LDAP_SUCCESS ) {
572 lt_dlclose( *pLdHandle );
575 } else {
576 *pInitFunc = fpInitFunc;
579 return rc;
583 * Special support for computed attribute plugins
585 int
586 slapi_int_call_plugins(
587 Backend *be,
588 int funcType,
589 Slapi_PBlock *pPB )
592 int rc = 0;
593 SLAPI_FUNC *pGetPlugin = NULL, *tmpPlugin = NULL;
595 if ( pPB == NULL ) {
596 return 1;
599 rc = slapi_int_get_plugins( be, funcType, &tmpPlugin );
600 if ( rc != LDAP_SUCCESS || tmpPlugin == NULL ) {
601 /* Nothing to do, front-end should ignore. */
602 return rc;
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
618 break;
622 slapi_ch_free( (void **)&tmpPlugin );
624 return rc;
628 slapi_int_read_config(
629 Backend *be,
630 const char *fname,
631 int lineno,
632 int argc,
633 char **argv )
635 int iType = -1;
636 int numPluginArgc = 0;
638 if ( argc < 4 ) {
639 fprintf( stderr,
640 "%s: line %d: missing arguments "
641 "in \"plugin <plugin_type> <lib_path> "
642 "<init_function> [<arguments>]\" line\n",
643 fname, lineno );
644 return 1;
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 );
653 return -1;
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;
665 } else {
666 fprintf( stderr, "%s: line %d: invalid plugin type \"%s\".\n",
667 fname, lineno, argv[1] );
668 return 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 ) {
677 int rc;
678 Slapi_PBlock *pPlugin;
680 pPlugin = plugin_pblock_new( iType, numPluginArgc, argv );
681 if (pPlugin == NULL) {
682 return 1;
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 );
689 return 1;
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 );
699 return 1;
703 return 0;
706 void
707 slapi_int_plugin_unparse(
708 Backend *be,
709 BerVarray *out
712 Slapi_PBlock *pp;
713 int i, j;
714 char **argv, ibuf[32], *ptr;
715 struct berval idx, bv;
717 *out = NULL;
718 idx.bv_val = ibuf;
719 i = 0;
721 for ( pp = SLAPI_BACKEND_PBLOCK( be );
722 pp != NULL;
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 */
727 continue;
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 );