Home | History | Annotate | Line # | Download | only in slapi
      1 /*	$NetBSD: plugin.c,v 1.4 2025/09/05 21:16:33 christos Exp $	*/
      2 
      3 /* $OpenLDAP$ */
      4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      5  *
      6  * Copyright 2002-2024 The OpenLDAP Foundation.
      7  * Portions Copyright 1997,2002-2003 IBM Corporation.
      8  * All rights reserved.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted only as authorized by the OpenLDAP
     12  * Public License.
     13  *
     14  * A copy of this license is available in the file LICENSE in the
     15  * top-level directory of the distribution or, alternatively, at
     16  * <http://www.OpenLDAP.org/license.html>.
     17  */
     18 /* ACKNOWLEDGEMENTS:
     19  * This work was initially developed by IBM Corporation for use in
     20  * IBM products and subsequently ported to OpenLDAP Software by
     21  * Steve Omrani.  Additional significant contributors include:
     22  *    Luke Howard
     23  */
     24 
     25 #include <sys/cdefs.h>
     26 __RCSID("$NetBSD: plugin.c,v 1.4 2025/09/05 21:16:33 christos Exp $");
     27 
     28 #include "portable.h"
     29 
     30 /*
     31  * Note: if ltdl.h is not available, slapi should not be compiled
     32  */
     33 
     34 #ifdef HAVE_LTDL_H
     35 #include "ldap_pvt_thread.h"
     36 #include "slap.h"
     37 #include "slap-config.h"
     38 #include "slapi.h"
     39 #include "lutil.h"
     40 
     41 #include <ltdl.h>
     42 
     43 static int slapi_int_load_plugin( Slapi_PBlock *, const char *, const char *, int,
     44 	SLAPI_FUNC *, lt_dlhandle *, ConfigArgs *c );
     45 
     46 /* pointer to link list of extended objects */
     47 static ExtendedOp *pGExtendedOps = NULL;
     48 
     49 /*********************************************************************
     50  * Function Name:      plugin_pblock_new
     51  *
     52  * Description:        This routine creates a new Slapi_PBlock structure,
     53  *                     loads in the plugin module and executes the init
     54  *                     function provided by the module.
     55  *
     56  * Input:              type - type of the plugin, such as SASL, database, etc.
     57  *                     path - the loadpath to load the module in
     58  *                     initfunc - name of the plugin function to execute first
     59  *                     argc - number of arguments
     60  *                     argv[] - an array of char pointers point to
     61  *                              the arguments passed in via
     62  *                              the configuration file.
     63  *
     64  * Output:
     65  *
     66  * Return Values:      a pointer to a newly created Slapi_PBlock structure or
     67  *                     NULL - function failed
     68  *
     69  * Messages:           None
     70  *********************************************************************/
     71 
     72 static Slapi_PBlock *
     73 plugin_pblock_new(
     74 	int type,
     75 	int argc,
     76 	ConfigArgs *c )
     77 {
     78 	Slapi_PBlock	*pPlugin = NULL;
     79 	Slapi_PluginDesc *pPluginDesc = NULL;
     80 	lt_dlhandle	hdLoadHandle;
     81 	int		rc;
     82 	char		**av2 = NULL, **ppPluginArgv;
     83 	char		*path = c->argv[2];
     84 	char		*initfunc = c->argv[3];
     85 
     86 	pPlugin = slapi_pblock_new();
     87 	if ( pPlugin == NULL ) {
     88 		rc = LDAP_NO_MEMORY;
     89 		goto done;
     90 	}
     91 
     92 	slapi_pblock_set( pPlugin, SLAPI_PLUGIN_TYPE, (void *)&type );
     93 	slapi_pblock_set( pPlugin, SLAPI_PLUGIN_ARGC, (void *)&argc );
     94 
     95 	av2 = ldap_charray_dup( c->argv );
     96 	if ( av2 == NULL ) {
     97 		rc = LDAP_NO_MEMORY;
     98 		goto done;
     99 	}
    100 
    101 	if ( argc > 0 ) {
    102 		ppPluginArgv = &av2[4];
    103 	} else {
    104 		ppPluginArgv = NULL;
    105 	}
    106 
    107 	slapi_pblock_set( pPlugin, SLAPI_PLUGIN_ARGV, (void *)ppPluginArgv );
    108 	slapi_pblock_set( pPlugin, SLAPI_X_CONFIG_ARGV, (void *)av2 );
    109 
    110 	rc = slapi_int_load_plugin( pPlugin, path, initfunc, 1, NULL, &hdLoadHandle, c );
    111 	if ( rc != 0 ) {
    112 		goto done;
    113 	}
    114 
    115 	if ( slapi_pblock_get( pPlugin, SLAPI_PLUGIN_DESCRIPTION, (void **)&pPluginDesc ) == 0 &&
    116 	     pPluginDesc != NULL ) {
    117 		slapi_log_error(SLAPI_LOG_TRACE, "plugin_pblock_new",
    118 				"Registered plugin %s %s [%s] (%s)\n",
    119 				pPluginDesc->spd_id,
    120 				pPluginDesc->spd_version,
    121 				pPluginDesc->spd_vendor,
    122 				pPluginDesc->spd_description);
    123 	}
    124 
    125 done:
    126 	if ( rc != 0 && pPlugin != NULL ) {
    127 		slapi_pblock_destroy( pPlugin );
    128 		pPlugin = NULL;
    129 		if ( av2 != NULL ) {
    130 			ldap_charray_free( av2 );
    131 		}
    132 	}
    133 
    134 	return pPlugin;
    135 }
    136 
    137 /*********************************************************************
    138  * Function Name:      slapi_int_register_plugin
    139  *
    140  * Description:        insert the slapi_pblock structure to a given position the end of the plugin
    141  *                     list
    142  *
    143  * Input:              a pointer to a plugin slapi_pblock structure to be added to
    144  *                     the list
    145  *
    146  * Output:             none
    147  *
    148  * Return Values:      LDAP_SUCCESS - successfully inserted.
    149  *                     LDAP_LOCAL_ERROR.
    150  *
    151  * Messages:           None
    152  *********************************************************************/
    153 int
    154 slapi_int_register_plugin_index(
    155 	Backend *be,
    156 	Slapi_PBlock *pPB,
    157 	int index )
    158 {
    159 	Slapi_PBlock	*pTmpPB;
    160 	Slapi_PBlock	*pSavePB;
    161 	int		pos = 0, rc = LDAP_SUCCESS;
    162 
    163 	assert( be != NULL );
    164 
    165 	pTmpPB = SLAPI_BACKEND_PBLOCK( be );
    166 	if ( pTmpPB == NULL || index == 0 ) {
    167 		SLAPI_BACKEND_PBLOCK( be ) = pPB;
    168 	} else {
    169 		while ( pTmpPB != NULL && rc == LDAP_SUCCESS &&
    170 				( index < 0 || pos++ < index ) ) {
    171 			pSavePB = pTmpPB;
    172 			rc = slapi_pblock_get( pTmpPB, SLAPI_IBM_PBLOCK, &pTmpPB );
    173 		}
    174 
    175 		if ( rc == LDAP_SUCCESS ) {
    176 			rc = slapi_pblock_set( pSavePB, SLAPI_IBM_PBLOCK, (void *)pPB );
    177 		}
    178 	}
    179 
    180 	if ( index >= 0 && rc == LDAP_SUCCESS ) {
    181 		rc = slapi_pblock_set( pPB, SLAPI_IBM_PBLOCK, (void *)pTmpPB );
    182 	}
    183 
    184 	return ( rc != LDAP_SUCCESS ) ? LDAP_OTHER : LDAP_SUCCESS;
    185 }
    186 
    187 int
    188 slapi_int_register_plugin(
    189 	Backend *be,
    190 	Slapi_PBlock *pPB )
    191 {
    192 	return slapi_int_register_plugin_index( be, pPB, -1 );
    193 }
    194 
    195 /*********************************************************************
    196  * Function Name:      slapi_int_get_plugins
    197  *
    198  * Description:        get the desired type of function pointers defined
    199  *                     in all the plugins
    200  *
    201  * Input:              the type of the functions to get, such as pre-operation,etc.
    202  *
    203  * Output:             none
    204  *
    205  * Return Values:      this routine returns a pointer to an array of function
    206  *                     pointers containing backend-specific plugin functions
    207  *                     followed by global plugin functions
    208  *
    209  * Messages:           None
    210  *********************************************************************/
    211 int
    212 slapi_int_get_plugins(
    213 	Backend *be,
    214 	int functype,
    215 	SLAPI_FUNC **ppFuncPtrs )
    216 {
    217 
    218 	Slapi_PBlock	*pCurrentPB;
    219 	SLAPI_FUNC	FuncPtr;
    220 	SLAPI_FUNC	*pTmpFuncPtr;
    221 	int		numPB = 0;
    222 	int		rc = LDAP_SUCCESS;
    223 
    224 	assert( ppFuncPtrs != NULL );
    225 	*ppFuncPtrs = NULL;
    226 
    227 	if ( be == NULL ) {
    228 		goto done;
    229 	}
    230 
    231 	pCurrentPB = SLAPI_BACKEND_PBLOCK( be );
    232 
    233 	while ( pCurrentPB != NULL && rc == LDAP_SUCCESS ) {
    234 		rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr );
    235 		if ( rc == LDAP_SUCCESS ) {
    236 			if ( FuncPtr != NULL )  {
    237 				numPB++;
    238 			}
    239 			rc = slapi_pblock_get( pCurrentPB,
    240 				SLAPI_IBM_PBLOCK, &pCurrentPB );
    241 		}
    242 	}
    243 
    244 	if ( numPB == 0 ) {
    245 		rc = LDAP_SUCCESS;
    246 		goto done;
    247 	}
    248 
    249 	/*
    250 	 * Now, build the function pointer array of backend-specific
    251 	 * plugins followed by global plugins.
    252 	 */
    253 	*ppFuncPtrs = pTmpFuncPtr =
    254 		(SLAPI_FUNC *)ch_malloc( ( numPB + 1 ) * sizeof(SLAPI_FUNC) );
    255 	if ( ppFuncPtrs == NULL ) {
    256 		rc = LDAP_NO_MEMORY;
    257 		goto done;
    258 	}
    259 
    260 	pCurrentPB = SLAPI_BACKEND_PBLOCK( be );
    261 
    262 	while ( pCurrentPB != NULL && rc == LDAP_SUCCESS )  {
    263 		rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr );
    264 		if ( rc == LDAP_SUCCESS ) {
    265 			if ( FuncPtr != NULL )  {
    266 				*pTmpFuncPtr = FuncPtr;
    267 				pTmpFuncPtr++;
    268 			}
    269 			rc = slapi_pblock_get( pCurrentPB,
    270 					SLAPI_IBM_PBLOCK, &pCurrentPB );
    271 		}
    272 	}
    273 
    274 	*pTmpFuncPtr = NULL;
    275 
    276 
    277 done:
    278 	if ( rc != LDAP_SUCCESS && *ppFuncPtrs != NULL ) {
    279 		ch_free( *ppFuncPtrs );
    280 		*ppFuncPtrs = NULL;
    281 	}
    282 
    283 	return rc;
    284 }
    285 
    286 /*********************************************************************
    287  * Function Name:      createExtendedOp
    288  *
    289  * Description: Creates an extended operation structure and
    290  *              initializes the fields
    291  *
    292  * Return value: A newly allocated structure or NULL
    293  ********************************************************************/
    294 ExtendedOp *
    295 createExtendedOp()
    296 {
    297 	ExtendedOp *ret;
    298 
    299 	ret = (ExtendedOp *)slapi_ch_malloc(sizeof(ExtendedOp));
    300 	ret->ext_oid.bv_val = NULL;
    301 	ret->ext_oid.bv_len = 0;
    302 	ret->ext_func = NULL;
    303 	ret->ext_be = NULL;
    304 	ret->ext_next = NULL;
    305 
    306 	return ret;
    307 }
    308 
    309 
    310 /*********************************************************************
    311  * Function Name:      slapi_int_unregister_extop
    312  *
    313  * Description:        This routine removes the ExtendedOp structures
    314  *					   asscoiated with a particular extended operation
    315  *					   plugin.
    316  *
    317  * Input:              pBE - pointer to a backend structure
    318  *                     opList - pointer to a linked list of extended
    319  *                              operation structures
    320  *                     pPB - pointer to a slapi parameter block
    321  *
    322  * Output:
    323  *
    324  * Return Value:       none
    325  *
    326  * Messages:           None
    327  *********************************************************************/
    328 void
    329 slapi_int_unregister_extop(
    330 	Backend *pBE,
    331 	ExtendedOp **opList,
    332 	Slapi_PBlock *pPB )
    333 {
    334 	ExtendedOp	*pTmpExtOp, *backExtOp;
    335 	char		**pTmpOIDs;
    336 	int		i;
    337 
    338 #if 0
    339 	assert( pBE != NULL); /* unused */
    340 #endif /* 0 */
    341 	assert( opList != NULL );
    342 	assert( pPB != NULL );
    343 
    344 	if ( *opList == NULL ) {
    345 		return;
    346 	}
    347 
    348 	slapi_pblock_get( pPB, SLAPI_PLUGIN_EXT_OP_OIDLIST, &pTmpOIDs );
    349 	if ( pTmpOIDs == NULL ) {
    350 		return;
    351 	}
    352 
    353 	for ( i = 0; pTmpOIDs[i] != NULL; i++ ) {
    354 		backExtOp = NULL;
    355 		pTmpExtOp = *opList;
    356 		for ( ; pTmpExtOp != NULL; pTmpExtOp = pTmpExtOp->ext_next) {
    357 			int	rc;
    358 			rc = strcasecmp( pTmpExtOp->ext_oid.bv_val,
    359 					pTmpOIDs[ i ] );
    360 			if ( rc == 0 ) {
    361 				if ( backExtOp == NULL ) {
    362 					*opList = pTmpExtOp->ext_next;
    363 				} else {
    364 					backExtOp->ext_next
    365 						= pTmpExtOp->ext_next;
    366 				}
    367 
    368 				ch_free( pTmpExtOp );
    369 				break;
    370 			}
    371 			backExtOp = pTmpExtOp;
    372 		}
    373 	}
    374 }
    375 
    376 
    377 /*********************************************************************
    378  * Function Name:      slapi_int_register_extop
    379  *
    380  * Description:        This routine creates a new ExtendedOp structure, loads
    381  *                     in the extended op module and put the extended op function address
    382  *                     in the structure. The function will not be executed in
    383  *                     this routine.
    384  *
    385  * Input:              pBE - pointer to a backend structure
    386  *                     opList - pointer to a linked list of extended
    387  *                              operation structures
    388  *                     pPB - pointer to a slapi parameter block
    389  *
    390  * Output:
    391  *
    392  * Return Value:       an LDAP return code
    393  *
    394  * Messages:           None
    395  *********************************************************************/
    396 int
    397 slapi_int_register_extop(
    398 	Backend *pBE,
    399 	ExtendedOp **opList,
    400 	Slapi_PBlock *pPB )
    401 {
    402 	ExtendedOp	*pTmpExtOp = NULL;
    403 	SLAPI_FUNC	tmpFunc;
    404 	char		**pTmpOIDs;
    405 	int		rc = LDAP_OTHER;
    406 	int		i;
    407 
    408 	if ( (*opList) == NULL ) {
    409 		*opList = createExtendedOp();
    410 		if ( (*opList) == NULL ) {
    411 			rc = LDAP_NO_MEMORY;
    412 			goto error_return;
    413 		}
    414 		pTmpExtOp = *opList;
    415 
    416 	} else {                        /* Find the end of the list */
    417 		for ( pTmpExtOp = *opList; pTmpExtOp->ext_next != NULL;
    418 				pTmpExtOp = pTmpExtOp->ext_next )
    419 			; /* EMPTY */
    420 		pTmpExtOp->ext_next = createExtendedOp();
    421 		if ( pTmpExtOp->ext_next == NULL ) {
    422 			rc = LDAP_NO_MEMORY;
    423 			goto error_return;
    424 		}
    425 		pTmpExtOp = pTmpExtOp->ext_next;
    426 	}
    427 
    428 	rc = slapi_pblock_get( pPB,SLAPI_PLUGIN_EXT_OP_OIDLIST, &pTmpOIDs );
    429 	if ( rc != 0 ) {
    430 		rc = LDAP_OTHER;
    431 		goto error_return;
    432 	}
    433 
    434 	rc = slapi_pblock_get(pPB,SLAPI_PLUGIN_EXT_OP_FN, &tmpFunc);
    435 	if ( rc != 0 ) {
    436 		rc = LDAP_OTHER;
    437 		goto error_return;
    438 	}
    439 
    440 	if ( (pTmpOIDs == NULL) || (tmpFunc == NULL) ) {
    441 		rc = LDAP_OTHER;
    442 		goto error_return;
    443 	}
    444 
    445 	for ( i = 0; pTmpOIDs[i] != NULL; i++ ) {
    446 		pTmpExtOp->ext_oid.bv_val = pTmpOIDs[i];
    447 		pTmpExtOp->ext_oid.bv_len = strlen( pTmpOIDs[i] );
    448 		pTmpExtOp->ext_func = tmpFunc;
    449 		pTmpExtOp->ext_be = pBE;
    450 		if ( pTmpOIDs[i + 1] != NULL ) {
    451 			pTmpExtOp->ext_next = createExtendedOp();
    452 			if ( pTmpExtOp->ext_next == NULL ) {
    453 				rc = LDAP_NO_MEMORY;
    454 				break;
    455 			}
    456 			pTmpExtOp = pTmpExtOp->ext_next;
    457 		}
    458 	}
    459 
    460 error_return:
    461 	return rc;
    462 }
    463 
    464 /*********************************************************************
    465  * Function Name:      slapi_int_get_extop_plugin
    466  *
    467  * Description:        This routine gets the function address for a given function
    468  *                     name.
    469  *
    470  * Input:
    471  *                     funcName - name of the extended op function, ie. an OID.
    472  *
    473  * Output:             pFuncAddr - the function address of the requested function name.
    474  *
    475  * Return Values:      a pointer to a newly created ExtendOp structure or
    476  *                     NULL - function failed
    477  *
    478  * Messages:           None
    479  *********************************************************************/
    480 int
    481 slapi_int_get_extop_plugin(
    482 	struct berval *reqoid,
    483 	SLAPI_FUNC *pFuncAddr )
    484 {
    485 	ExtendedOp	*pTmpExtOp;
    486 
    487 	assert( reqoid != NULL );
    488 	assert( pFuncAddr != NULL );
    489 
    490 	*pFuncAddr = NULL;
    491 
    492 	if ( pGExtendedOps == NULL ) {
    493 		return LDAP_OTHER;
    494 	}
    495 
    496 	pTmpExtOp = pGExtendedOps;
    497 	while ( pTmpExtOp != NULL ) {
    498 		int	rc;
    499 
    500 		rc = strcasecmp( reqoid->bv_val, pTmpExtOp->ext_oid.bv_val );
    501 		if ( rc == 0 ) {
    502 			*pFuncAddr = pTmpExtOp->ext_func;
    503 			break;
    504 		}
    505 		pTmpExtOp = pTmpExtOp->ext_next;
    506 	}
    507 
    508 	return ( *pFuncAddr == NULL ? 1 : 0 );
    509 }
    510 
    511 /***************************************************************************
    512  * This function is similar to slapi_int_get_extop_plugin above. except it returns one OID
    513  * per call. It is called from root_dse_info (root_dse.c).
    514  * The function is a modified version of get_supported_extop (file extended.c).
    515  ***************************************************************************/
    516 struct berval *
    517 slapi_int_get_supported_extop( int index )
    518 {
    519         ExtendedOp	*ext;
    520 
    521         for ( ext = pGExtendedOps ; ext != NULL && --index >= 0;
    522 			ext = ext->ext_next) {
    523                 ; /* empty */
    524         }
    525 
    526         if ( ext == NULL ) {
    527 		return NULL;
    528 	}
    529 
    530         return &ext->ext_oid ;
    531 }
    532 
    533 /*********************************************************************
    534  * Function Name:      slapi_int_load_plugin
    535  *
    536  * Description:        This routine loads the specified DLL, gets and executes the init function
    537  *                     if requested.
    538  *
    539  * Input:
    540  *                     pPlugin - a pointer to a Slapi_PBlock struct which will be passed to
    541  *                               the DLL init function.
    542  *                     path - path name of the DLL to be load.
    543  *                     initfunc - either the DLL initialization function or an OID of the
    544  *                                loaded extended operation.
    545  *                     doInit - if it is TRUE, execute the init function, otherwise, save the
    546  *                              function address but not execute it.
    547  *
    548  * Output:             pInitFunc - the function address of the loaded function. This param
    549  *                                 should be not be null if doInit is FALSE.
    550  *                     pLdHandle - handle returned by lt_dlopen()
    551  *
    552  * Return Values:      LDAP_SUCCESS, LDAP_LOCAL_ERROR
    553  *
    554  * Messages:           None
    555  *********************************************************************/
    556 
    557 static int
    558 slapi_int_load_plugin(
    559 	Slapi_PBlock	*pPlugin,
    560 	const char	*path,
    561 	const char	*initfunc,
    562 	int		doInit,
    563 	SLAPI_FUNC	*pInitFunc,
    564 	lt_dlhandle	*pLdHandle,
    565 	ConfigArgs *c )
    566 {
    567 	int		rc = LDAP_SUCCESS;
    568 	SLAPI_FUNC	fpInitFunc = NULL;
    569 
    570 	assert( pLdHandle != NULL );
    571 
    572 	if ( lt_dlinit() ) {
    573 		return LDAP_LOCAL_ERROR;
    574 	}
    575 
    576 	/* load in the module */
    577 	*pLdHandle = lt_dlopen( path );
    578 	if ( *pLdHandle == NULL ) {
    579 		snprintf( c->cr_msg, sizeof( c->cr_msg ), "failed to load plugin %s: %s",
    580 			 path, lt_dlerror() );
    581 		Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
    582 		return LDAP_LOCAL_ERROR;
    583 	}
    584 
    585 	fpInitFunc = (SLAPI_FUNC)lt_dlsym( *pLdHandle, initfunc );
    586 	if ( fpInitFunc == NULL ) {
    587 		snprintf( c->cr_msg, sizeof( c->cr_msg ), "failed to find symbol %s in plugin %s: %s",
    588 			 initfunc, path, lt_dlerror() );
    589 		Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
    590 		lt_dlclose( *pLdHandle );
    591 		return LDAP_LOCAL_ERROR;
    592 	}
    593 
    594 	if ( doInit ) {
    595 		rc = ( *fpInitFunc )( pPlugin );
    596 		if ( rc != LDAP_SUCCESS ) {
    597 			lt_dlclose( *pLdHandle );
    598 		}
    599 
    600 	} else {
    601 		*pInitFunc = fpInitFunc;
    602 	}
    603 
    604 	return rc;
    605 }
    606 
    607 /*
    608  * Special support for computed attribute plugins
    609  */
    610 int
    611 slapi_int_call_plugins(
    612 	Backend		*be,
    613 	int		funcType,
    614 	Slapi_PBlock	*pPB )
    615 {
    616 
    617 	int rc = 0;
    618 	SLAPI_FUNC *pGetPlugin = NULL, *tmpPlugin = NULL;
    619 
    620 	if ( pPB == NULL ) {
    621 		return 1;
    622 	}
    623 
    624 	rc = slapi_int_get_plugins( be, funcType, &tmpPlugin );
    625 	if ( rc != LDAP_SUCCESS || tmpPlugin == NULL ) {
    626 		/* Nothing to do, front-end should ignore. */
    627 		return rc;
    628 	}
    629 
    630 	for ( pGetPlugin = tmpPlugin ; *pGetPlugin != NULL; pGetPlugin++ ) {
    631 		rc = (*pGetPlugin)(pPB);
    632 
    633 		/*
    634 		 * Only non-postoperation plugins abort processing on
    635 		 * failure (confirmed with SLAPI specification).
    636 		 */
    637 		if ( !SLAPI_PLUGIN_IS_POST_FN( funcType ) && rc != 0 ) {
    638 			/*
    639 			 * Plugins generally return negative error codes
    640 			 * to indicate failure, although in the case of
    641 			 * bind plugins they may return SLAPI_BIND_xxx
    642 			 */
    643 			break;
    644 		}
    645 	}
    646 
    647 	slapi_ch_free( (void **)&tmpPlugin );
    648 
    649 	return rc;
    650 }
    651 
    652 int
    653 slapi_int_read_config(
    654 	struct config_args_s *c )
    655 {
    656 	int		iType = -1;
    657 	int		numPluginArgc = 0;
    658 
    659 	if ( c->argc < 4 ) {
    660 		snprintf( c->cr_msg, sizeof( c->cr_msg ),
    661 			"missing arguments "
    662 			"in \"plugin <plugin_type> <lib_path> "
    663 			"<init_function> [<arguments>]\" line" );
    664 		Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
    665 		return 1;
    666 	}
    667 
    668 	/* automatically instantiate overlay if necessary */
    669 	if ( !slapi_over_is_inst( c->be ) ) {
    670 		if ( slapi_over_config( c->be, &c->reply ) != 0 ) {
    671 			Debug( LDAP_DEBUG_ANY, "%s: "
    672 			"Failed to instantiate SLAPI overlay: "
    673 				"err=%d msg=\"%s\"\n", c->log, c->reply.err, c->reply.msg );
    674 			return -1;
    675 		}
    676 	}
    677 
    678 	if ( strcasecmp( c->argv[1], "preoperation" ) == 0 ) {
    679 		iType = SLAPI_PLUGIN_PREOPERATION;
    680 	} else if ( strcasecmp( c->argv[1], "postoperation" ) == 0 ) {
    681 		iType = SLAPI_PLUGIN_POSTOPERATION;
    682 	} else if ( strcasecmp( c->argv[1], "extendedop" ) == 0 ) {
    683 		iType = SLAPI_PLUGIN_EXTENDEDOP;
    684 	} else if ( strcasecmp( c->argv[1], "object" ) == 0 ) {
    685 		iType = SLAPI_PLUGIN_OBJECT;
    686 	} else {
    687 		snprintf( c->cr_msg, sizeof( c->cr_msg ),
    688 			"invalid plugin type \"%s\"", c->argv[1] );
    689 		Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg );
    690 		return 1;
    691 	}
    692 
    693 	numPluginArgc = c->argc - 4;
    694 
    695 	if ( iType == SLAPI_PLUGIN_PREOPERATION ||
    696 		  	iType == SLAPI_PLUGIN_EXTENDEDOP ||
    697 			iType == SLAPI_PLUGIN_POSTOPERATION ||
    698 			iType == SLAPI_PLUGIN_OBJECT ) {
    699 		int rc;
    700 		Slapi_PBlock *pPlugin;
    701 
    702 		pPlugin = plugin_pblock_new( iType, numPluginArgc, c );
    703 		if (pPlugin == NULL) {
    704 			return 1;
    705 		}
    706 
    707 		if (iType == SLAPI_PLUGIN_EXTENDEDOP) {
    708 			rc = slapi_int_register_extop(c->be, &pGExtendedOps, pPlugin);
    709 			if ( rc != LDAP_SUCCESS ) {
    710 				slapi_pblock_destroy( pPlugin );
    711 				return 1;
    712 			}
    713 		}
    714 
    715 		rc = slapi_int_register_plugin_index( c->be, pPlugin, c->valx );
    716 		if ( rc != LDAP_SUCCESS ) {
    717 			if ( iType == SLAPI_PLUGIN_EXTENDEDOP ) {
    718 				slapi_int_unregister_extop( c->be, &pGExtendedOps, pPlugin );
    719 			}
    720 			slapi_pblock_destroy( pPlugin );
    721 			return 1;
    722 		}
    723 	}
    724 
    725 	return 0;
    726 }
    727 
    728 int
    729 slapi_int_unregister_plugin(
    730 	Backend *be,
    731 	Slapi_PBlock *pPlugin,
    732 	Slapi_PBlock *pPrev
    733 )
    734 {
    735 	int type;
    736 
    737 	assert( pPlugin != NULL );
    738 
    739 	slapi_pblock_get( pPlugin, SLAPI_PLUGIN_TYPE, (void *)&type );
    740 	if ( type == SLAPI_PLUGIN_EXTENDEDOP ) {
    741 		slapi_int_unregister_extop( be, &pGExtendedOps, pPlugin );
    742 	}
    743 
    744 	if ( pPrev != NULL ) {
    745 		Slapi_PBlock *pNext = NULL;
    746 
    747 		slapi_pblock_get( pPlugin, SLAPI_IBM_PBLOCK, &pNext );
    748 		slapi_pblock_set( pPrev, SLAPI_IBM_PBLOCK, &pNext );
    749 	}
    750 	slapi_pblock_destroy( pPlugin );
    751 
    752 	return LDAP_SUCCESS;
    753 }
    754 
    755 int
    756 slapi_int_unregister_plugins(
    757 	Backend *be,
    758 	int index
    759 )
    760 {
    761 	Slapi_PBlock	*pTmpPB = NULL;
    762 	Slapi_PBlock	*pSavePB = NULL;
    763 	int rc = LDAP_SUCCESS;
    764 
    765 	pTmpPB = SLAPI_BACKEND_PBLOCK( be );
    766 	if ( pTmpPB == NULL ) {
    767 		return ( index < 0 ) ? LDAP_SUCCESS : LDAP_OTHER;
    768 	}
    769 
    770 	if ( index < 0 ) {
    771 		/* All plugins must go */
    772 		while ( pTmpPB != NULL && rc == LDAP_SUCCESS ) {
    773 			pSavePB = pTmpPB;
    774 			rc = slapi_pblock_get( pTmpPB, SLAPI_IBM_PBLOCK, &pTmpPB );
    775 			if ( pSavePB != NULL ) {
    776 				slapi_int_unregister_plugin( be, pSavePB, NULL );
    777 			}
    778 		}
    779 	} else if ( index == 0 ) {
    780 		slapi_pblock_get( pTmpPB, SLAPI_IBM_PBLOCK, &pSavePB );
    781 		SLAPI_BACKEND_PBLOCK( be ) = pSavePB;
    782 		slapi_int_unregister_plugin( be, pTmpPB, NULL );
    783 	} else {
    784 		int pos = -1;
    785 		while ( pTmpPB != NULL && rc == LDAP_SUCCESS && ++pos < index ) {
    786 			pSavePB = pTmpPB;
    787 			rc = slapi_pblock_get( pTmpPB, SLAPI_IBM_PBLOCK, &pTmpPB );
    788 		}
    789 		if ( pos == index ) {
    790 			slapi_int_unregister_plugin( be, pTmpPB, pSavePB );
    791 		}
    792 	}
    793 	return rc;
    794 }
    795 
    796 void
    797 slapi_int_plugin_unparse(
    798 	Backend *be,
    799 	BerVarray *out
    800 )
    801 {
    802 	Slapi_PBlock *pp;
    803 	int i, j;
    804 	char **argv, ibuf[32], *ptr;
    805 	struct berval idx, bv;
    806 
    807 	*out = NULL;
    808 	idx.bv_val = ibuf;
    809 	i = 0;
    810 
    811 	for ( pp = SLAPI_BACKEND_PBLOCK( be );
    812 	      pp != NULL;
    813 	      slapi_pblock_get( pp, SLAPI_IBM_PBLOCK, &pp ) )
    814 	{
    815 		slapi_pblock_get( pp, SLAPI_X_CONFIG_ARGV, &argv );
    816 		if ( argv == NULL ) /* could be dynamic plugin */
    817 			continue;
    818 		idx.bv_len = snprintf( idx.bv_val, sizeof( ibuf ), "{%d}", i );
    819 		if ( idx.bv_len >= sizeof( ibuf ) ) {
    820 			/* FIXME: just truncating by now */
    821 			idx.bv_len = sizeof( ibuf ) - 1;
    822 		}
    823 		bv.bv_len = idx.bv_len;
    824 		for (j=1; argv[j]; j++) {
    825 			bv.bv_len += strlen(argv[j]);
    826 			if ( j ) bv.bv_len++;
    827 		}
    828 		bv.bv_val = ch_malloc( bv.bv_len + 1 );
    829 		ptr = lutil_strcopy( bv.bv_val, ibuf );
    830 		for (j=1; argv[j]; j++) {
    831 			if ( j ) *ptr++ = ' ';
    832 			ptr = lutil_strcopy( ptr, argv[j] );
    833 		}
    834 		ber_bvarray_add( out, &bv );
    835 	}
    836 }
    837 #endif /* HAVE_LTDL_H */
    838