]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/slapi/plugin.c
Entry/Attribute struct caching, to minimize malloc fragmentation
[openldap] / servers / slapd / slapi / plugin.c
index fd603bb821d4109d36787befc7760d739077ef22..22e482328a414782d9a6e21e35c9adc5ed2c99bf 100644 (file)
@@ -1,36 +1,44 @@
-/*
- * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
- * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2002-2006 The OpenLDAP Foundation.
+ * Portions Copyright 1997,2002-2003 IBM Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
  */
-/*
- * (C) Copyright IBM Corp. 1997,2002
- * Redistribution and use in source and binary forms are permitted
- * provided that this notice is preserved and that due credit is 
- * given to IBM Corporation. This software is provided ``as is'' 
- * without express or implied warranty.
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by IBM Corporation for use in
+ * IBM products and subsequently ported to OpenLDAP Software by
+ * Steve Omrani.  Additional significant contributors include:
+ *    Luke Howard
  */
 
 #include "portable.h"
-#include "slapi_common.h"
 #include <ldap_pvt_thread.h>
 #include <slap.h>
 #include <slapi.h>
+#include <lutil.h>
 
 /*
  * Note: if ltdl.h is not available, slapi should not be compiled
  */
 #include <ltdl.h>
 
-static int loadPlugin( Slapi_PBlock *, const char *, const char *, int, 
+static int slapi_int_load_plugin( Slapi_PBlock *, const char *, const char *, int, 
        SLAPI_FUNC *, lt_dlhandle * );
 
 /* pointer to link list of extended objects */
 static ExtendedOp *pGExtendedOps = NULL;
-/* global plugins not associated with a specific backend */
-static Slapi_PBlock *pGPlugins = NULL;
 
 /*********************************************************************
- * Function Name:      newPlugin
+ * Function Name:      plugin_pblock_new
  *
  * Description:        This routine creates a new Slapi_PBlock structure,
  *                     loads in the plugin module and executes the init
@@ -52,17 +60,19 @@ static Slapi_PBlock *pGPlugins = NULL;
  * Messages:           None
  *********************************************************************/
 
-Slapi_PBlock *
-newPlugin(
+static Slapi_PBlock *
+plugin_pblock_new(
        int type, 
-       const char *path, 
-       const char *initfunc, 
        int argc, 
        char *argv[] ) 
 {
        Slapi_PBlock    *pPlugin = NULL; 
+       Slapi_PluginDesc *pPluginDesc = NULL;
        lt_dlhandle     hdLoadHandle;
        int             rc;
+       char            **av2 = NULL, **ppPluginArgv;
+       char            *path = argv[2];
+       char            *initfunc = argv[3];
 
        pPlugin = slapi_pblock_new();
        if ( pPlugin == NULL ) {
@@ -70,34 +80,53 @@ newPlugin(
                goto done;
        }
 
-       rc = slapi_pblock_set( pPlugin, SLAPI_PLUGIN_TYPE, (void *)type );
-       if ( rc != LDAP_SUCCESS ) {
+       slapi_pblock_set( pPlugin, SLAPI_PLUGIN_TYPE, (void *)&type );
+       slapi_pblock_set( pPlugin, SLAPI_PLUGIN_ARGC, (void *)&argc );
+
+       av2 = ldap_charray_dup( argv );
+       if ( av2 == NULL ) {
+               rc = LDAP_NO_MEMORY;
                goto done;
        }
 
-       rc = slapi_pblock_set( pPlugin, SLAPI_PLUGIN_ARGC, (void *)argc );
-       if ( rc != LDAP_SUCCESS ) {
-               goto done;
+       if ( argc > 0 ) {
+               ppPluginArgv = &av2[4];
+       } else {
+               ppPluginArgv = NULL;
        }
 
-       rc = slapi_pblock_set( pPlugin, SLAPI_PLUGIN_ARGV, (void *)argv );
-       if ( rc != LDAP_SUCCESS ) { 
+       slapi_pblock_set( pPlugin, SLAPI_PLUGIN_ARGV, (void *)ppPluginArgv );
+       slapi_pblock_set( pPlugin, SLAPI_X_CONFIG_ARGV, (void *)av2 );
+
+       rc = slapi_int_load_plugin( pPlugin, path, initfunc, 1, NULL, &hdLoadHandle );
+       if ( rc != 0 ) {
                goto done;
        }
 
-       rc = loadPlugin( pPlugin, path, initfunc, TRUE, NULL, &hdLoadHandle );
+       if ( slapi_pblock_get( pPlugin, SLAPI_PLUGIN_DESCRIPTION, (void **)&pPluginDesc ) == 0 &&
+            pPluginDesc != NULL ) {
+               slapi_log_error(SLAPI_LOG_TRACE, "plugin_pblock_new",
+                               "Registered plugin %s %s [%s] (%s)\n",
+                               pPluginDesc->spd_id,
+                               pPluginDesc->spd_version,
+                               pPluginDesc->spd_vendor,
+                               pPluginDesc->spd_description);
+       }
 
 done:
-       if ( rc != LDAP_SUCCESS && pPlugin != NULL ) {
+       if ( rc != 0 && pPlugin != NULL ) {
                slapi_pblock_destroy( pPlugin );
                pPlugin = NULL;
+               if ( av2 != NULL ) {
+                       ldap_charray_free( av2 );
+               }
        }
 
        return pPlugin;
 } 
 
 /*********************************************************************
- * Function Name:      insertPlugin
+ * Function Name:      slapi_int_register_plugin
  *
  * Description:        insert the slapi_pblock structure to the end of the plugin
  *                     list 
@@ -113,45 +142,35 @@ done:
  * Messages:           None
  *********************************************************************/
 int 
-insertPlugin(
+slapi_int_register_plugin(
        Backend *be, 
        Slapi_PBlock *pPB )
 { 
-       Slapi_PBlock *pTmpPB;
-       Slapi_PBlock *pSavePB;
-       int    rc = LDAP_SUCCESS;
+       Slapi_PBlock    *pTmpPB;
+       Slapi_PBlock    *pSavePB;
+       int              rc = LDAP_SUCCESS;
 
-       pTmpPB = ( be == NULL ) ? pGPlugins : (Slapi_PBlock *)(be->be_pb);
+       assert( be != NULL );
 
+       pTmpPB = SLAPI_BACKEND_PBLOCK( be );
        if ( pTmpPB == NULL ) {
-               if ( be != NULL )
-                       be->be_pb = (void *)pPB;
-               else
-                       pGPlugins = pPB;
+               SLAPI_BACKEND_PBLOCK( be ) = pPB;
        } else {
                while ( pTmpPB != NULL && rc == LDAP_SUCCESS ) {
                        pSavePB = pTmpPB;
-                       rc = slapi_pblock_get( pTmpPB, SLAPI_IBM_PBLOCK,
-                                       &pTmpPB );
-                       if ( rc != LDAP_SUCCESS ) {
-                               rc = LDAP_OTHER;
-                       }
+                       rc = slapi_pblock_get( pTmpPB, SLAPI_IBM_PBLOCK, &pTmpPB );
                }
 
                if ( rc == LDAP_SUCCESS ) { 
-                       rc = slapi_pblock_set( pSavePB, SLAPI_IBM_PBLOCK,
-                                       (void *)pPB ); 
-                       if ( rc != LDAP_SUCCESS ) {
-                               rc = LDAP_OTHER;
-                       }
+                       rc = slapi_pblock_set( pSavePB, SLAPI_IBM_PBLOCK, (void *)pPB ); 
                }
        }
      
-       return rc;
+       return ( rc != LDAP_SUCCESS ) ? LDAP_OTHER : LDAP_SUCCESS;
 }
        
 /*********************************************************************
- * Function Name:      getAllPluginFuncs
+ * Function Name:      slapi_int_get_plugins
  *
  * Description:        get the desired type of function pointers defined 
  *                     in all the plugins 
@@ -161,12 +180,13 @@ insertPlugin(
  * Output:             none
  *
  * Return Values:      this routine returns a pointer to an array of function
- *                     pointers
+ *                     pointers containing backend-specific plugin functions
+ *                     followed by global plugin functions
  *
  * Messages:           None
  *********************************************************************/
 int 
-getAllPluginFuncs(
+slapi_int_get_plugins(
        Backend *be,            
        int functype, 
        SLAPI_FUNC **ppFuncPtrs )
@@ -178,18 +198,14 @@ getAllPluginFuncs(
        int             numPB = 0;
        int             rc = LDAP_SUCCESS;
 
-       assert( ppFuncPtrs );
+       assert( ppFuncPtrs != NULL );
 
-       pCurrentPB = ( be == NULL ) ? pGPlugins : (Slapi_PBlock *)(be->be_pb);
-     
-       if ( pCurrentPB == NULL ) { 
-               /*
-                * LDAP_OTHER is returned if no plugins are installed
-                */
-               rc = LDAP_OTHER;
+       if ( be == NULL ) {
                goto done;
        }
 
+       pCurrentPB = SLAPI_BACKEND_PBLOCK( be );
+
        while ( pCurrentPB != NULL && rc == LDAP_SUCCESS ) {
                rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr );
                if ( rc == LDAP_SUCCESS ) {
@@ -197,20 +213,20 @@ getAllPluginFuncs(
                                numPB++;
                        }
                        rc = slapi_pblock_get( pCurrentPB,
-                                       SLAPI_IBM_PBLOCK, &pCurrentPB );
+                               SLAPI_IBM_PBLOCK, &pCurrentPB );
                }
        }
 
-       if ( rc != LDAP_SUCCESS ) {
-               goto done;
-       }
-
        if ( numPB == 0 ) {
                *ppFuncPtrs = NULL;
                rc = LDAP_SUCCESS;
                goto done;
        }
 
+       /*
+        * Now, build the function pointer array of backend-specific
+        * plugins followed by global plugins.
+        */
        *ppFuncPtrs = pTmpFuncPtr = 
                (SLAPI_FUNC *)ch_malloc( ( numPB + 1 ) * sizeof(SLAPI_FUNC) ); 
        if ( ppFuncPtrs == NULL ) {
@@ -218,7 +234,8 @@ getAllPluginFuncs(
                goto done;
        }
 
-       pCurrentPB = ( be == NULL ) ? pGPlugins : (Slapi_PBlock *)(be->be_pb);
+       pCurrentPB = SLAPI_BACKEND_PBLOCK( be );
+
        while ( pCurrentPB != NULL && rc == LDAP_SUCCESS )  {
                rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr );
                if ( rc == LDAP_SUCCESS ) {
@@ -230,7 +247,9 @@ getAllPluginFuncs(
                                        SLAPI_IBM_PBLOCK, &pCurrentPB );
                }
        }
-       *pTmpFuncPtr = NULL ;
+
+       *pTmpFuncPtr = NULL;
+
 
 done:
        if ( rc != LDAP_SUCCESS && *ppFuncPtrs != NULL ) {
@@ -240,7 +259,7 @@ done:
 
        return rc;
 }
-              
+
 /*********************************************************************
  * Function Name:      createExtendedOp
  *
@@ -254,21 +273,19 @@ createExtendedOp()
 {
        ExtendedOp *ret;
 
-       ret = (ExtendedOp *)ch_malloc(sizeof(ExtendedOp));
-       if ( ret != NULL ) {
-               ret->ext_oid.bv_val = NULL;
-               ret->ext_oid.bv_len = 0;
-               ret->ext_func = NULL;
-               ret->ext_be = NULL;
-               ret->ext_next = NULL;
-       }
+       ret = (ExtendedOp *)slapi_ch_malloc(sizeof(ExtendedOp));
+       ret->ext_oid.bv_val = NULL;
+       ret->ext_oid.bv_len = 0;
+       ret->ext_func = NULL;
+       ret->ext_be = NULL;
+       ret->ext_next = NULL;
 
        return ret;
 }
 
 
 /*********************************************************************
- * Function Name:      removeExtendedOp
+ * Function Name:      slapi_int_unregister_extop
  *
  * Description:        This routine removes the ExtendedOp structures 
  *                                        asscoiated with a particular extended operation 
@@ -286,7 +303,7 @@ createExtendedOp()
  * Messages:           None
  *********************************************************************/
 void
-removeExtendedOp(
+slapi_int_unregister_extop(
        Backend *pBE, 
        ExtendedOp **opList, 
        Slapi_PBlock *pPB )
@@ -335,7 +352,7 @@ removeExtendedOp(
 
 
 /*********************************************************************
- * Function Name:      newExtendedOp
+ * Function Name:      slapi_int_register_extop
  *
  * Description:        This routine creates a new ExtendedOp structure, loads
  *                     in the extended op module and put the extended op function address
@@ -354,7 +371,7 @@ removeExtendedOp(
  * Messages:           None
  *********************************************************************/
 int 
-newExtendedOp(
+slapi_int_register_extop(
        Backend *pBE,   
        ExtendedOp **opList, 
        Slapi_PBlock *pPB )
@@ -386,7 +403,7 @@ newExtendedOp(
        }
 
        rc = slapi_pblock_get( pPB,SLAPI_PLUGIN_EXT_OP_OIDLIST, &pTmpOIDs );
-       if ( rc != LDAP_SUCCESS ) {
+       if ( rc != 0 ) {
                rc = LDAP_OTHER;
                goto error_return;
        }
@@ -422,7 +439,7 @@ error_return:
 }
 
 /*********************************************************************
- * Function Name:      getPluginFunc
+ * Function Name:      slapi_int_get_extop_plugin
  *
  * Description:        This routine gets the function address for a given function
  *                     name.
@@ -438,7 +455,7 @@ error_return:
  * Messages:           None
  *********************************************************************/
 int 
-getPluginFunc(
+slapi_int_get_extop_plugin(
        struct berval *reqoid,          
        SLAPI_FUNC *pFuncAddr ) 
 {
@@ -469,12 +486,12 @@ getPluginFunc(
 }
 
 /***************************************************************************
- * This function is similar to getPluginFunc above. except it returns one OID
+ * This function is similar to slapi_int_get_extop_plugin above. except it returns one OID
  * per call. It is called from root_dse_info (root_dse.c).
  * The function is a modified version of get_supported_extop (file extended.c).
  ***************************************************************************/
 struct berval *
-ns_get_supported_extop( int index )
+slapi_int_get_supported_extop( int index )
 {
         ExtendedOp     *ext;
 
@@ -491,7 +508,7 @@ ns_get_supported_extop( int index )
 }
 
 /*********************************************************************
- * Function Name:      loadPlugin
+ * Function Name:      slapi_int_load_plugin
  *
  * Description:        This routine loads the specified DLL, gets and executes the init function
  *                     if requested.
@@ -515,7 +532,7 @@ ns_get_supported_extop( int index )
  *********************************************************************/
 
 static int 
-loadPlugin(
+slapi_int_load_plugin(
        Slapi_PBlock    *pPlugin,
        const char      *path,
        const char      *initfunc, 
@@ -526,7 +543,7 @@ loadPlugin(
        int             rc = LDAP_SUCCESS;
        SLAPI_FUNC      fpInitFunc = NULL;
 
-       assert( pLdHandle );
+       assert( pLdHandle != NULL );
 
        if ( lt_dlinit() ) {
                return LDAP_LOCAL_ERROR;
@@ -535,16 +552,20 @@ loadPlugin(
        /* load in the module */
        *pLdHandle = lt_dlopen( path );
        if ( *pLdHandle == NULL ) {
+               fprintf( stderr, "failed to load plugin %s: %s\n",
+                        path, lt_dlerror() );
                return LDAP_LOCAL_ERROR;
        }
 
        fpInitFunc = (SLAPI_FUNC)lt_dlsym( *pLdHandle, initfunc );
        if ( fpInitFunc == NULL ) {
+               fprintf( stderr, "failed to find symbol %s in plugin %s: %s\n",
+                        initfunc, path, lt_dlerror() );
                lt_dlclose( *pLdHandle );
                return LDAP_LOCAL_ERROR;
        }
 
-       if ( doInit == TRUE ) {
+       if ( doInit ) {
                rc = ( *fpInitFunc )( pPlugin );
                if ( rc != LDAP_SUCCESS ) {
                        lt_dlclose( *pLdHandle );
@@ -557,9 +578,11 @@ loadPlugin(
        return rc;
 }
 
-
+/*
+ * Special support for computed attribute plugins
+ */
 int 
-doPluginFNs(
+slapi_int_call_plugins(
        Backend         *be,    
        int             funcType, 
        Slapi_PBlock    *pPB )
@@ -568,19 +591,17 @@ doPluginFNs(
        int rc = 0;
        SLAPI_FUNC *pGetPlugin = NULL, *tmpPlugin = NULL; 
 
-       rc = getAllPluginFuncs(be, funcType, &tmpPlugin );
+       if ( pPB == NULL ) {
+               return 1;
+       }
+
+       rc = slapi_int_get_plugins( be, funcType, &tmpPlugin );
        if ( rc != LDAP_SUCCESS || tmpPlugin == NULL ) {
                /* Nothing to do, front-end should ignore. */
-               return 0;
+               return 1;
        }
 
        for ( pGetPlugin = tmpPlugin ; *pGetPlugin != NULL; pGetPlugin++ ) {
-               /*
-                * FIXME: we should provide here a sort of sandbox,
-                * to protect from plugin faults; e.g. trap signals
-                * and longjump here, marking the plugin as unsafe for
-                * later executions ...
-                */
                rc = (*pGetPlugin)(pPB);
 
                /*
@@ -588,43 +609,22 @@ doPluginFNs(
                 * failure (confirmed with SLAPI specification).
                 */
                if ( !SLAPI_PLUGIN_IS_POST_FN( funcType ) && rc != 0 ) {
+                       /*
+                        * Plugins generally return negative error codes
+                        * to indicate failure, although in the case of
+                        * bind plugins they may return SLAPI_BIND_xxx
+                        */
                        break;
                }
        }
 
        slapi_ch_free( (void **)&tmpPlugin );
 
-       /*
-        * If we failed, and this wasn't a postoperation plugin, we
-        * should return the failure to the frontend.
-        */
-       if ( !SLAPI_PLUGIN_IS_POST_FN( funcType ) && rc != 0 ) {
-               return rc;
-       }
-
-       /*
-        * Try any global plugins (not associated with a specific
-        * backend); same logic as above.
-        */
-       if ( be != NULL ) {
-               rc = getAllPluginFuncs( be, funcType, &tmpPlugin );
-               if ( rc != LDAP_SUCCESS || tmpPlugin == NULL )
-                       return 0;
-               for ( pGetPlugin = tmpPlugin; *pGetPlugin != NULL; pGetPlugin++ ) {
-                       rc = (*pGetPlugin)(pPB);
-                       if ( !SLAPI_PLUGIN_IS_POST_FN( funcType ) && rc != 0 ) {
-                               break;
-                       }
-               }
-       }
-
-       slapi_ch_free( (void **)&tmpPlugin );
-
        return rc;
 }
 
 int
-netscape_plugin(
+slapi_int_read_config(
        Backend         *be,            
        const char      *fname, 
        int             lineno, 
@@ -633,7 +633,6 @@ netscape_plugin(
 {
        int             iType = -1;
        int             numPluginArgc = 0;
-       char            **ppPluginArgv = NULL;
 
        if ( argc < 4 ) {
                fprintf( stderr,
@@ -643,6 +642,14 @@ netscape_plugin(
                        fname, lineno );
                return 1;
        }
+
+       /* automatically instantiate overlay if necessary */
+       if ( !slapi_over_is_inst( be ) ) {
+               if ( slapi_over_config( be ) != 0 ) {
+                       fprintf( stderr, "Failed to instantiate SLAPI overlay\n");
+                       return -1;
+               }
+       }
        
        if ( strcasecmp( argv[1], "preoperation" ) == 0 ) {
                iType = SLAPI_PLUGIN_PREOPERATION;
@@ -650,8 +657,8 @@ netscape_plugin(
                iType = SLAPI_PLUGIN_POSTOPERATION;
        } else if ( strcasecmp( argv[1], "extendedop" ) == 0 ) {
                iType = SLAPI_PLUGIN_EXTENDEDOP;
-       } else if ( strcasecmp( argv[1], "opattrsp" ) == 0 ) {
-               iType = SLAPI_PLUGIN_OPATTR_SP;
+       } else if ( strcasecmp( argv[1], "object" ) == 0 ) {
+               iType = SLAPI_PLUGIN_OBJECT;
        } else {
                fprintf( stderr, "%s: line %d: invalid plugin type \"%s\".\n",
                                fname, lineno, argv[1] );
@@ -659,37 +666,31 @@ netscape_plugin(
        }
        
        numPluginArgc = argc - 4;
-       if ( numPluginArgc > 0 ) {
-               ppPluginArgv = &argv[4];
-       } else {
-               ppPluginArgv = NULL;
-       }
 
        if ( iType == SLAPI_PLUGIN_PREOPERATION ||
                        iType == SLAPI_PLUGIN_EXTENDEDOP ||
                        iType == SLAPI_PLUGIN_POSTOPERATION ||
-                       iType == SLAPI_PLUGIN_OPATTR_SP ) {
+                       iType == SLAPI_PLUGIN_OBJECT ) {
                int rc;
                Slapi_PBlock *pPlugin;
 
-               pPlugin = newPlugin( iType, argv[2], argv[3], 
-                                       numPluginArgc, ppPluginArgv );
+               pPlugin = plugin_pblock_new( iType, numPluginArgc, argv );
                if (pPlugin == NULL) {
                        return 1;
                }
 
                if (iType == SLAPI_PLUGIN_EXTENDEDOP) {
-                       rc = newExtendedOp(be, &pGExtendedOps, pPlugin);
+                       rc = slapi_int_register_extop(be, &pGExtendedOps, pPlugin);
                        if ( rc != LDAP_SUCCESS ) {
                                slapi_pblock_destroy( pPlugin );
                                return 1;
                        }
                }
 
-               rc = insertPlugin( be, pPlugin );
+               rc = slapi_int_register_plugin( be, pPlugin );
                if ( rc != LDAP_SUCCESS ) {
                        if ( iType == SLAPI_PLUGIN_EXTENDEDOP ) {
-                               removeExtendedOp( be, &pGExtendedOps, pPlugin );
+                               slapi_int_unregister_extop( be, &pGExtendedOps, pPlugin );
                        }
                        slapi_pblock_destroy( pPlugin );
                        return 1;
@@ -699,26 +700,41 @@ netscape_plugin(
        return 0;
 }
 
-int
-slapi_init(void)
+void
+slapi_int_plugin_unparse(
+       Backend *be,
+       BerVarray *out
+)
 {
-       if ( ldap_pvt_thread_mutex_init( &slapi_hn_mutex ) ) {
-               return -1;
-       }
-       
-       if ( ldap_pvt_thread_mutex_init( &slapi_time_mutex ) ) {
-               return -1;
-       }
-
-       if ( ldap_pvt_thread_mutex_init( &slapi_printmessage_mutex ) ) {
-               return -1;
-       }
-
-       slapi_log_file = ch_strdup( LDAP_RUNDIR LDAP_DIRSEP "errors" );
-       if ( slapi_log_file == NULL ) {
-               return -1;
+       Slapi_PBlock *pp;
+       int i, j;
+       char **argv, ibuf[32], *ptr;
+       struct berval idx, bv;
+
+       *out = NULL;
+       idx.bv_val = ibuf;
+       i = 0;
+
+       for ( pp = SLAPI_BACKEND_PBLOCK( be );
+             pp != NULL;
+             slapi_pblock_get( pp, SLAPI_IBM_PBLOCK, &pp ) )
+       {
+               slapi_pblock_get( pp, SLAPI_X_CONFIG_ARGV, &argv );
+               if ( argv == NULL ) /* could be dynamic plugin */
+                       continue;
+               idx.bv_len = sprintf( idx.bv_val, "{%d}", i );
+               bv.bv_len = idx.bv_len;
+               for (j=1; argv[j]; j++) {
+                       bv.bv_len += strlen(argv[j]);
+                       if ( j ) bv.bv_len++;
+               }
+               bv.bv_val = ch_malloc( bv.bv_len + 1 );
+               ptr = lutil_strcopy( bv.bv_val, ibuf );
+               for (j=1; argv[j]; j++) {
+                       if ( j ) *ptr++ = ' ';
+                       ptr = lutil_strcopy( ptr, argv[j] );
+               }
+               ber_bvarray_add( out, &bv );
        }
-
-       return 0;
 }