xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/slapi/plugin.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
1 /*	$NetBSD: plugin.c,v 1.3 2021/08/14 16:15:02 christos Exp $	*/
2 
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 2002-2021 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.3 2021/08/14 16:15:02 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 * );
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 *
plugin_pblock_new(int type,int argc,char * argv[])73 plugin_pblock_new(
74 	int type,
75 	int argc,
76 	char *argv[] )
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 = argv[2];
84 	char		*initfunc = 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( 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 );
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
slapi_int_register_plugin_index(Backend * be,Slapi_PBlock * pPB,int index)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
slapi_int_register_plugin(Backend * be,Slapi_PBlock * pPB)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
slapi_int_get_plugins(Backend * be,int functype,SLAPI_FUNC ** ppFuncPtrs)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 *
createExtendedOp()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
slapi_int_unregister_extop(Backend * pBE,ExtendedOp ** opList,Slapi_PBlock * pPB)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
slapi_int_register_extop(Backend * pBE,ExtendedOp ** opList,Slapi_PBlock * pPB)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
slapi_int_get_extop_plugin(struct berval * reqoid,SLAPI_FUNC * pFuncAddr)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 *
slapi_int_get_supported_extop(int index)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
slapi_int_load_plugin(Slapi_PBlock * pPlugin,const char * path,const char * initfunc,int doInit,SLAPI_FUNC * pInitFunc,lt_dlhandle * pLdHandle)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 {
566 	int		rc = LDAP_SUCCESS;
567 	SLAPI_FUNC	fpInitFunc = NULL;
568 
569 	assert( pLdHandle != NULL );
570 
571 	if ( lt_dlinit() ) {
572 		return LDAP_LOCAL_ERROR;
573 	}
574 
575 	/* load in the module */
576 	*pLdHandle = lt_dlopen( path );
577 	if ( *pLdHandle == NULL ) {
578 		fprintf( stderr, "failed to load plugin %s: %s\n",
579 			 path, lt_dlerror() );
580 		return LDAP_LOCAL_ERROR;
581 	}
582 
583 	fpInitFunc = (SLAPI_FUNC)lt_dlsym( *pLdHandle, initfunc );
584 	if ( fpInitFunc == NULL ) {
585 		fprintf( stderr, "failed to find symbol %s in plugin %s: %s\n",
586 			 initfunc, path, lt_dlerror() );
587 		lt_dlclose( *pLdHandle );
588 		return LDAP_LOCAL_ERROR;
589 	}
590 
591 	if ( doInit ) {
592 		rc = ( *fpInitFunc )( pPlugin );
593 		if ( rc != LDAP_SUCCESS ) {
594 			lt_dlclose( *pLdHandle );
595 		}
596 
597 	} else {
598 		*pInitFunc = fpInitFunc;
599 	}
600 
601 	return rc;
602 }
603 
604 /*
605  * Special support for computed attribute plugins
606  */
607 int
slapi_int_call_plugins(Backend * be,int funcType,Slapi_PBlock * pPB)608 slapi_int_call_plugins(
609 	Backend		*be,
610 	int		funcType,
611 	Slapi_PBlock	*pPB )
612 {
613 
614 	int rc = 0;
615 	SLAPI_FUNC *pGetPlugin = NULL, *tmpPlugin = NULL;
616 
617 	if ( pPB == NULL ) {
618 		return 1;
619 	}
620 
621 	rc = slapi_int_get_plugins( be, funcType, &tmpPlugin );
622 	if ( rc != LDAP_SUCCESS || tmpPlugin == NULL ) {
623 		/* Nothing to do, front-end should ignore. */
624 		return rc;
625 	}
626 
627 	for ( pGetPlugin = tmpPlugin ; *pGetPlugin != NULL; pGetPlugin++ ) {
628 		rc = (*pGetPlugin)(pPB);
629 
630 		/*
631 		 * Only non-postoperation plugins abort processing on
632 		 * failure (confirmed with SLAPI specification).
633 		 */
634 		if ( !SLAPI_PLUGIN_IS_POST_FN( funcType ) && rc != 0 ) {
635 			/*
636 			 * Plugins generally return negative error codes
637 			 * to indicate failure, although in the case of
638 			 * bind plugins they may return SLAPI_BIND_xxx
639 			 */
640 			break;
641 		}
642 	}
643 
644 	slapi_ch_free( (void **)&tmpPlugin );
645 
646 	return rc;
647 }
648 
649 int
slapi_int_read_config(Backend * be,const char * fname,int lineno,int argc,char ** argv,int index)650 slapi_int_read_config(
651 	Backend		*be,
652 	const char	*fname,
653 	int		lineno,
654 	int		argc,
655 	char		**argv,
656 	int		index )
657 {
658 	int		iType = -1;
659 	int		numPluginArgc = 0;
660 
661 	if ( argc < 4 ) {
662 		fprintf( stderr,
663 			"%s: line %d: missing arguments "
664 			"in \"plugin <plugin_type> <lib_path> "
665 			"<init_function> [<arguments>]\" line\n",
666 			fname, lineno );
667 		return 1;
668 	}
669 
670 	/* automatically instantiate overlay if necessary */
671 	if ( !slapi_over_is_inst( be ) ) {
672 		ConfigReply cr = { 0 };
673 		if ( slapi_over_config( be, &cr ) != 0 ) {
674 			fprintf( stderr, "Failed to instantiate SLAPI overlay: "
675 				"err=%d msg=\"%s\"\n", cr.err, cr.msg );
676 			return -1;
677 		}
678 	}
679 
680 	if ( strcasecmp( argv[1], "preoperation" ) == 0 ) {
681 		iType = SLAPI_PLUGIN_PREOPERATION;
682 	} else if ( strcasecmp( argv[1], "postoperation" ) == 0 ) {
683 		iType = SLAPI_PLUGIN_POSTOPERATION;
684 	} else if ( strcasecmp( argv[1], "extendedop" ) == 0 ) {
685 		iType = SLAPI_PLUGIN_EXTENDEDOP;
686 	} else if ( strcasecmp( argv[1], "object" ) == 0 ) {
687 		iType = SLAPI_PLUGIN_OBJECT;
688 	} else {
689 		fprintf( stderr, "%s: line %d: invalid plugin type \"%s\".\n",
690 				fname, lineno, argv[1] );
691 		return 1;
692 	}
693 
694 	numPluginArgc = argc - 4;
695 
696 	if ( iType == SLAPI_PLUGIN_PREOPERATION ||
697 		  	iType == SLAPI_PLUGIN_EXTENDEDOP ||
698 			iType == SLAPI_PLUGIN_POSTOPERATION ||
699 			iType == SLAPI_PLUGIN_OBJECT ) {
700 		int rc;
701 		Slapi_PBlock *pPlugin;
702 
703 		pPlugin = plugin_pblock_new( iType, numPluginArgc, argv );
704 		if (pPlugin == NULL) {
705 			return 1;
706 		}
707 
708 		if (iType == SLAPI_PLUGIN_EXTENDEDOP) {
709 			rc = slapi_int_register_extop(be, &pGExtendedOps, pPlugin);
710 			if ( rc != LDAP_SUCCESS ) {
711 				slapi_pblock_destroy( pPlugin );
712 				return 1;
713 			}
714 		}
715 
716 		rc = slapi_int_register_plugin_index( be, pPlugin, index );
717 		if ( rc != LDAP_SUCCESS ) {
718 			if ( iType == SLAPI_PLUGIN_EXTENDEDOP ) {
719 				slapi_int_unregister_extop( be, &pGExtendedOps, pPlugin );
720 			}
721 			slapi_pblock_destroy( pPlugin );
722 			return 1;
723 		}
724 	}
725 
726 	return 0;
727 }
728 
729 int
slapi_int_unregister_plugin(Backend * be,Slapi_PBlock * pPlugin,Slapi_PBlock * pPrev)730 slapi_int_unregister_plugin(
731 	Backend *be,
732 	Slapi_PBlock *pPlugin,
733 	Slapi_PBlock *pPrev
734 )
735 {
736 	int type;
737 
738 	assert( pPlugin != NULL );
739 
740 	slapi_pblock_get( pPlugin, SLAPI_PLUGIN_TYPE, (void *)&type );
741 	if ( type == SLAPI_PLUGIN_EXTENDEDOP ) {
742 		slapi_int_unregister_extop( be, &pGExtendedOps, pPlugin );
743 	}
744 
745 	if ( pPrev != NULL ) {
746 		Slapi_PBlock *pNext = NULL;
747 
748 		slapi_pblock_get( pPlugin, SLAPI_IBM_PBLOCK, &pNext );
749 		slapi_pblock_set( pPrev, SLAPI_IBM_PBLOCK, &pNext );
750 	}
751 	slapi_pblock_destroy( pPlugin );
752 
753 	return LDAP_SUCCESS;
754 }
755 
756 int
slapi_int_unregister_plugins(Backend * be,int index)757 slapi_int_unregister_plugins(
758 	Backend *be,
759 	int index
760 )
761 {
762 	Slapi_PBlock	*pTmpPB = NULL;
763 	Slapi_PBlock	*pSavePB = NULL;
764 	int rc = LDAP_SUCCESS;
765 
766 	pTmpPB = SLAPI_BACKEND_PBLOCK( be );
767 	if ( pTmpPB == NULL ) {
768 		return ( index < 0 ) ? LDAP_SUCCESS : LDAP_OTHER;
769 	}
770 
771 	if ( index < 0 ) {
772 		/* All plugins must go */
773 		while ( pTmpPB != NULL && rc == LDAP_SUCCESS ) {
774 			pSavePB = pTmpPB;
775 			rc = slapi_pblock_get( pTmpPB, SLAPI_IBM_PBLOCK, &pTmpPB );
776 			if ( pSavePB != NULL ) {
777 				slapi_int_unregister_plugin( be, pSavePB, NULL );
778 			}
779 		}
780 	} else if ( index == 0 ) {
781 		slapi_pblock_get( pTmpPB, SLAPI_IBM_PBLOCK, &pSavePB );
782 		SLAPI_BACKEND_PBLOCK( be ) = pSavePB;
783 		slapi_int_unregister_plugin( be, pTmpPB, NULL );
784 	} else {
785 		int pos = -1;
786 		while ( pTmpPB != NULL && rc == LDAP_SUCCESS && ++pos < index ) {
787 			pSavePB = pTmpPB;
788 			rc = slapi_pblock_get( pTmpPB, SLAPI_IBM_PBLOCK, &pTmpPB );
789 		}
790 		if ( pos == index ) {
791 			slapi_int_unregister_plugin( be, pTmpPB, pSavePB );
792 		}
793 	}
794 	return rc;
795 }
796 
797 void
slapi_int_plugin_unparse(Backend * be,BerVarray * out)798 slapi_int_plugin_unparse(
799 	Backend *be,
800 	BerVarray *out
801 )
802 {
803 	Slapi_PBlock *pp;
804 	int i, j;
805 	char **argv, ibuf[32], *ptr;
806 	struct berval idx, bv;
807 
808 	*out = NULL;
809 	idx.bv_val = ibuf;
810 	i = 0;
811 
812 	for ( pp = SLAPI_BACKEND_PBLOCK( be );
813 	      pp != NULL;
814 	      slapi_pblock_get( pp, SLAPI_IBM_PBLOCK, &pp ) )
815 	{
816 		slapi_pblock_get( pp, SLAPI_X_CONFIG_ARGV, &argv );
817 		if ( argv == NULL ) /* could be dynamic plugin */
818 			continue;
819 		idx.bv_len = snprintf( idx.bv_val, sizeof( ibuf ), "{%d}", i );
820 		if ( idx.bv_len >= sizeof( ibuf ) ) {
821 			/* FIXME: just truncating by now */
822 			idx.bv_len = sizeof( ibuf ) - 1;
823 		}
824 		bv.bv_len = idx.bv_len;
825 		for (j=1; argv[j]; j++) {
826 			bv.bv_len += strlen(argv[j]);
827 			if ( j ) bv.bv_len++;
828 		}
829 		bv.bv_val = ch_malloc( bv.bv_len + 1 );
830 		ptr = lutil_strcopy( bv.bv_val, ibuf );
831 		for (j=1; argv[j]; j++) {
832 			if ( j ) *ptr++ = ' ';
833 			ptr = lutil_strcopy( ptr, argv[j] );
834 		}
835 		ber_bvarray_add( out, &bv );
836 	}
837 }
838 #endif /* HAVE_LTDL_H */
839