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