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