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