Diff for /servers/slapd/overlays/translucent.c between versions 1.1.2.16 and 1.2

version 1.1.2.16, 2008/02/11 23:24:25 version 1.2, 2005/03/25 19:11:28
Line 1 Line 1
 /* translucent.c - translucent proxy module */  /* translucent.c - translucent proxy module */
 /* $OpenLDAP: pkg/ldap/servers/slapd/overlays/translucent.c,v 1.1.2.15 2007/11/12 23:51:37 hyc Exp $ */  /* $OpenLDAP: pkg/ldap/servers/slapd/overlays/refint.c,v 1.9 2005/02/01 13:02:53 hyc Exp $ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.  /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *   *
  * Copyright 2004-2008 The OpenLDAP Foundation.   * Copyright 2004-2005 The OpenLDAP Foundation.
  * Portions Copyright 2005 Symas Corporation.   * Portions Copyright 2005 Symas Corporation.
  * All rights reserved.   * All rights reserved.
  *   *
Line 29 Line 29
 #include <ac/socket.h>  #include <ac/socket.h>
   
 #include "slap.h"  #include "slap.h"
 #include "lutil.h"  
   
 /* config block */  /* config block */
   
Line 63  static struct berval glue[] = { BER_BVC( Line 62  static struct berval glue[] = { BER_BVC(
 void glue_parent(Operation *op) {  void glue_parent(Operation *op) {
         Operation nop = *op;          Operation nop = *op;
         slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;          slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
         struct berval ndn = BER_BVNULL;          struct berval dn = { 0, NULL };
           char *odn = op->o_req_ndn.bv_val;
         Attribute *a;          Attribute *a;
         Entry *e;          Entry *e;
         struct berval   pdn;          int idn, ldn;
   
         dnParent( &op->o_req_ndn, &pdn );          /* tis more work to use strchr() for a berval... */
         ber_dupbv_x( &ndn, &pdn, op->o_tmpmemctx );          for(idn = 0; odn[idn] && odn[idn] != ','; idn++);
           if(!idn || !odn[idn]) return;   /* because you never know */
           idn++;
           ldn = dn.bv_len = op->o_req_ndn.bv_len - idn;
           dn.bv_val = ch_malloc(ldn + 1);
           strcpy(dn.bv_val, odn + idn);
   
         Debug(LDAP_DEBUG_TRACE, "=> glue_parent: fabricating glue for <%s>\n", ndn.bv_val, 0, 0);          Debug(LDAP_DEBUG_TRACE, "=> glue_parent: fabricating glue for <%s>\n", dn.bv_val, 0, 0);
   
         e = ch_calloc(1, sizeof(Entry));          e = ch_calloc(1, sizeof(Entry));
         e->e_id = NOID;          e->e_id = NOID;
         ber_dupbv(&e->e_name, &ndn);          ber_dupbv(&e->e_name, &dn);
         ber_dupbv(&e->e_nname, &ndn);          ber_dupbv(&e->e_nname, &dn);
   
         a = ch_calloc(1, sizeof(Attribute));          a = ch_calloc(1, sizeof(Attribute));
         a->a_desc = slap_schema.si_ad_objectClass;          a->a_desc = slap_schema.si_ad_objectClass;
Line 97  void glue_parent(Operation *op) { Line 102  void glue_parent(Operation *op) {
         a->a_next = e->e_attrs;          a->a_next = e->e_attrs;
         e->e_attrs = a;          e->e_attrs = a;
   
         nop.o_req_dn = ndn;          nop.o_req_dn = dn;
         nop.o_req_ndn = ndn;          nop.o_req_ndn = dn;
         nop.ora_e = e;          nop.ora_e = e;
         nop.o_bd->bd_info = (BackendInfo *) on->on_info->oi_orig;          nop.o_bd->bd_info = (BackendInfo *) on->on_info->oi_orig;
   
         syncrepl_add_glue(&nop, e);          syncrepl_add_glue(&nop, e);
   
         op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx );  
   
         return;          return;
 }  }
   
Line 132  BerVarray dup_bervarray(BerVarray b) { Line 134  BerVarray dup_bervarray(BerVarray b) {
 */  */
 void free_attr_chain(Attribute *a) {  void free_attr_chain(Attribute *a) {
         Attribute *ax;          Attribute *ax;
         for(; a; a = ax) {          for(ax = NULL; a; a = a->a_next) {
                 ax = a->a_next;                  if(ax) ch_free(ax);
                 ch_free(a);                  ax = a;
         }          }
         return;          return;
 }  }
Line 205  static int translucent_delete(Operation Line 207  static int translucent_delete(Operation
         return(SLAP_CB_CONTINUE);          return(SLAP_CB_CONTINUE);
 }  }
   
 static int  
 translucent_tag_cb( Operation *op, SlapReply *rs )  
 {  
         op->o_tag = LDAP_REQ_MODIFY;  
         op->orm_modlist = op->o_callback->sc_private;  
         rs->sr_tag = slap_req2res( op->o_tag );  
   
         return SLAP_CB_CONTINUE;  
 }  
   
 /*  /*
 ** translucent_modify()  ** translucent_modify()
 **      modify in local backend if exists in both;  **      modify in local backend if exists in both;
Line 229  static int translucent_modify(Operation Line 221  static int translucent_modify(Operation
   
         slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;          slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
         overlay_stack *ov = on->on_bi.bi_private;          overlay_stack *ov = on->on_bi.bi_private;
           translucent_configuration *cf = ov->config;
         void *private = op->o_bd->be_private;          void *private = op->o_bd->be_private;
         Entry ne, *e = NULL, *re = NULL;          Entry ne, *e, *re = NULL;
         Attribute *a, *ax;          Attribute *a, *ax;
         Modifications *m, **mm;          Modifications *m, *mm;
         int del, rc, erc = 0;          int del, rc, erc = 0;
         slap_callback cb = { 0 };  
   
         Debug(LDAP_DEBUG_TRACE, "==> translucent_modify: %s\n",          Debug(LDAP_DEBUG_TRACE, "==> translucent_modify: %s\n",
                 op->o_req_dn.bv_val, 0, 0);                  op->o_req_dn.bv_val, 0, 0);
Line 252  static int translucent_modify(Operation Line 244  static int translucent_modify(Operation
         op->o_bd->be_private = private;          op->o_bd->be_private = private;
   
         /* if(ov->config->no_add && (!re || rc != LDAP_SUCCESS)) */          /* if(ov->config->no_add && (!re || rc != LDAP_SUCCESS)) */
         if(rc != LDAP_SUCCESS || re == NULL ) {          if(!re || rc != LDAP_SUCCESS) {
                 send_ldap_error(op, rs, LDAP_NO_SUCH_OBJECT,                  send_ldap_error(op, rs, LDAP_NO_SUCH_OBJECT,
                         "attempt to modify nonexistent local record");                          "attempt to modify nonexistent local record");
                 return(rs->sr_err);                  return(rs->sr_err);
Line 275  static int translucent_modify(Operation Line 267  static int translucent_modify(Operation
   
         if(e && rc == LDAP_SUCCESS) {          if(e && rc == LDAP_SUCCESS) {
                 Debug(LDAP_DEBUG_TRACE, "=> translucent_modify: found local entry\n", 0, 0, 0);                  Debug(LDAP_DEBUG_TRACE, "=> translucent_modify: found local entry\n", 0, 0, 0);
                 for(mm = &op->orm_modlist; *mm; ) {                  for(m = op->orm_modlist; m; m = m->sml_next) {
                         m = *mm;  
                         for(a = e->e_attrs; a; a = a->a_next)                          for(a = e->e_attrs; a; a = a->a_next)
                                 if(a->a_desc == m->sml_desc) break;                                  if(a->a_desc == m->sml_desc) break;
                         if(a) {                          if(a) continue;         /* found local attr */
                                 mm = &m->sml_next;  
                                 continue;               /* found local attr */  
                         }  
                         if(m->sml_op == LDAP_MOD_DELETE) {                          if(m->sml_op == LDAP_MOD_DELETE) {
                                 for(a = re->e_attrs; a; a = a->a_next)                                  for(a = re->e_attrs; a; a = a->a_next)
                                         if(a->a_desc == m->sml_desc) break;                                          if(a->a_desc == m->sml_desc) break;
Line 298  static int translucent_modify(Operation Line 286  static int translucent_modify(Operation
                                 Debug(LDAP_DEBUG_TRACE,                                  Debug(LDAP_DEBUG_TRACE,
                                         "=> translucent_modify: silently dropping delete: %s\n",                                          "=> translucent_modify: silently dropping delete: %s\n",
                                         m->sml_desc->ad_cname.bv_val, 0, 0);                                          m->sml_desc->ad_cname.bv_val, 0, 0);
                                 *mm = m->sml_next;                                  for(mm = op->orm_modlist; mm->sml_next != m; mm = mm->sml_next);
                                 m->sml_next = NULL;                                  mm->sml_next = m->sml_next;
                                 slap_mods_free(m, 1);                                  mm = m;
                                 continue;                                  m = m->sml_next;
                                   mm->sml_next = NULL;            /* hack */
                                   slap_mods_free(mm);
                                   if(m) continue;
                         }                          }
                         m->sml_op = LDAP_MOD_ADD;                          m->sml_op = LDAP_MOD_ADD;
                         mm = &m->sml_next;  
                 }                  }
                 erc = SLAP_CB_CONTINUE;                  erc = SLAP_CB_CONTINUE;
 release:  release:
Line 327  release: Line 317  release:
                 }                  }
         }          }
   
         /* don't leak remote entry copy */  
         if(re) {  
                 op->o_bd->be_private = ov->private;  
                 if(ov->info->bi_entry_release_rw)  
                         ov->info->bi_entry_release_rw(op, re, 0);  
                 else  
                         entry_free(re);  
                 op->o_bd->be_private = private;  
         }  
 /*  /*
 ** foreach Modification:  ** foreach Modification:
 **      if MOD_ADD or MOD_REPLACE, add Attribute;  **      if MOD_ADD or MOD_REPLACE, add Attribute;
Line 362  release: Line 343  release:
                 a = ch_calloc(1, sizeof(Attribute));                  a = ch_calloc(1, sizeof(Attribute));
                 a->a_desc  = m->sml_desc;                  a->a_desc  = m->sml_desc;
                 a->a_vals  = m->sml_values;                  a->a_vals  = m->sml_values;
                 a->a_nvals = m->sml_nvalues ? m->sml_nvalues : a->a_vals;                  a->a_nvals = m->sml_nvalues;
                 a->a_next  = ax;                  a->a_next  = ax;
                 ax = a;                  ax = a;
         }          }
Line 402  release: Line 383  release:
         op->o_bd->bd_info = (BackendInfo *) on;          op->o_bd->bd_info = (BackendInfo *) on;
         glue_parent(&nop);          glue_parent(&nop);
   
         cb.sc_response = translucent_tag_cb;  
         cb.sc_private = op->orm_modlist;  
         cb.sc_next = nop.o_callback;  
         nop.o_callback = &cb;  
         rc = on->on_info->oi_orig->bi_op_add(&nop, &nrs);          rc = on->on_info->oi_orig->bi_op_add(&nop, &nrs);
         free_attr_chain(a);          free_attr_chain(a);
   
Line 416  static int translucent_compare(Operation Line 393  static int translucent_compare(Operation
         slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;          slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
         overlay_stack *ov = on->on_bi.bi_private;          overlay_stack *ov = on->on_bi.bi_private;
         void *private = op->o_bd->be_private;          void *private = op->o_bd->be_private;
           translucent_configuration *cf = ov->config;
   
         AttributeAssertion *ava = op->orc_ava;          AttributeAssertion *ava = op->orc_ava;
         Entry *e;          Attribute *a, *an, *ra, *as = NULL;
           Entry *e, *ee, *re;
         int rc;          int rc;
   
         Debug(LDAP_DEBUG_TRACE, "==> translucent_compare: <%s> %s:%s\n",          Debug(LDAP_DEBUG_TRACE, "==> translucent_compare: <%s> %s:%s\n",
Line 461  static int translucent_search_cb(Operati Line 440  static int translucent_search_cb(Operati
         slap_overinst *on;          slap_overinst *on;
         Entry *e, *re = NULL;          Entry *e, *re = NULL;
         Attribute *a, *ax, *an, *as = NULL;          Attribute *a, *ax, *an, *as = NULL;
           BerVarray b, bx;
         void *private;          void *private;
         int rc;          int i, rc, size;
   
         if(!op || !rs || rs->sr_type != REP_SEARCH || !rs->sr_entry)          if(!op || !rs || rs->sr_type != REP_SEARCH || !rs->sr_entry)
                 return(SLAP_CB_CONTINUE);                  return(SLAP_CB_CONTINUE);
Line 540  static int translucent_search_cb(Operati Line 520  static int translucent_search_cb(Operati
 */  */
   
 static int translucent_search(Operation *op, SlapReply *rs) {  static int translucent_search(Operation *op, SlapReply *rs) {
           Operation nop = *op;
   
         slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;          slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
         slap_callback cb = { NULL, NULL, NULL, NULL };          slap_callback cb = { NULL, NULL, NULL, NULL };
         overlay_stack *ov = on->on_bi.bi_private;          overlay_stack *ov = on->on_bi.bi_private;
           translucent_configuration *cf = ov->config;
         void *private = op->o_bd->be_private;          void *private = op->o_bd->be_private;
         int rc;          int rc;
   
Line 551  static int translucent_search(Operation Line 534  static int translucent_search(Operation
         cb.sc_response = (slap_response *) translucent_search_cb;          cb.sc_response = (slap_response *) translucent_search_cb;
         cb.sc_private = private;          cb.sc_private = private;
   
         cb.sc_next = op->o_callback;          cb.sc_next = nop.o_callback;
         op->o_callback = &cb;          nop.o_callback = &cb;
   
         op->o_bd->be_private = ov->private;          op->o_bd->be_private = ov->private;
         rc = ov->info->bi_op_search(op, rs);          rc = ov->info->bi_op_search(&nop, rs);
         op->o_bd->be_private = private;          op->o_bd->be_private = private;
   
         return(rs->sr_err);          return(rs->sr_err);
Line 585  static int translucent_bind(Operation *o Line 568  static int translucent_bind(Operation *o
 }  }
   
 /*  /*
 ** translucent_connection_destroy()  ** translucent_config()
 **      pass disconnect notification to captive backend;  
 **  
 */  
   
 static int translucent_connection_destroy(BackendDB *be, Connection *conn) {  
         slap_overinst *on = (slap_overinst *) be->bd_info;  
         overlay_stack *ov = on->on_bi.bi_private;  
         void *private = be->be_private;  
         int rc = 0;  
   
         Debug(LDAP_DEBUG_TRACE, "translucent_connection_destroy\n", 0, 0, 0);  
   
         be->be_private = ov->private;  
         rc = ov->info->bi_connection_destroy(be, conn);  
         be->be_private = private;  
   
         return(rc);  
 }  
   
 /*  
 ** translucent_db_config()  
 **      pass config directives to captive backend;  **      pass config directives to captive backend;
 **      parse unrecognized directives ourselves;  **      parse unrecognized directives ourselves;
 **  **
 */  */
   
 static int translucent_db_config(  static int translucent_config(
         BackendDB       *be,          BackendDB       *be,
         const char      *fname,          const char      *fname,
         int             lineno,          int             lineno,
Line 623  static int translucent_db_config( Line 585  static int translucent_db_config(
         slap_overinst *on = (slap_overinst *) be->bd_info;          slap_overinst *on = (slap_overinst *) be->bd_info;
         overlay_stack *ov = on->on_bi.bi_private;          overlay_stack *ov = on->on_bi.bi_private;
         void *private = be->be_private;          void *private = be->be_private;
         void *be_cf_ocs = be->be_cf_ocs;  
         int rc;          int rc;
   
         /* "this should never happen" */          /* "this should never happen" */
Line 633  static int translucent_db_config( Line 594  static int translucent_db_config(
         }          }
   
         be->be_private = ov->private;          be->be_private = ov->private;
         be->be_cf_ocs = ov->info->bi_cf_ocs;  
         rc = ov->info->bi_db_config ? ov->info->bi_db_config(be, fname, lineno, argc, argv) : 0;          rc = ov->info->bi_db_config ? ov->info->bi_db_config(be, fname, lineno, argc, argv) : 0;
         be->be_private = private;          be->be_private = private;
         be->be_cf_ocs = be_cf_ocs;  
   
         /* pass okay or error up, SLAP_CONF_UNKNOWN might be ours */          /* pass okay or error up, SLAP_CONF_UNKNOWN might be ours */
         if(rc == 0 || rc == 1) return(rc);          if(rc == 0 || rc == 1) return(rc);
Line 653  static int translucent_db_config( Line 612  static int translucent_db_config(
                         ov->config->debug = 0xFFFF;                          ov->config->debug = 0xFFFF;
                         rc = 0;                          rc = 0;
                 } else if(argc == 2) {                  } else if(argc == 2) {
                         if ( lutil_atoi( &ov->config->debug, argv[1]) != 0 ) {                          ov->config->debug = atoi(argv[1]);
                                 fprintf(stderr, "%s: line %d: unable to parse debug \"%s\"\n",  
                                         fname, lineno, argv[1]);  
                                 return 1;  
                         }  
                         rc = 0;                          rc = 0;
                 } else {                  } else {
                         fprintf(stderr, "%s: line %d: too many arguments (%d) to debug\n",                          fprintf(stderr, "%s: line %d: too many arguments (%d) to debug\n",
Line 684  static int translucent_db_init(BackendDB Line 639  static int translucent_db_init(BackendDB
         overlay_stack *ov;          overlay_stack *ov;
         int rc;          int rc;
   
         Debug(LDAP_DEBUG_TRACE, "==> translucent_db_init\n", 0, 0, 0);          Debug(LDAP_DEBUG_TRACE, "==> translucent_init\n", 0, 0, 0);
   
         ov = ch_calloc(1, sizeof(overlay_stack));          ov = ch_calloc(1, sizeof(overlay_stack));
         ov->config = ch_calloc(1, sizeof(translucent_configuration));          ov->config = ch_calloc(1, sizeof(translucent_configuration));
Line 711  static int translucent_db_init(BackendDB Line 666  static int translucent_db_init(BackendDB
 }  }
   
 /*  /*
 ** translucent_db_open()  ** translucent_open()
 **      if the captive backend has an open() method, call it;  **      if the captive backend has an open() method, call it;
 **  **
 */  */
   
 static int translucent_db_open(BackendDB *be) {  static int translucent_open(BackendDB *be) {
         slap_overinst *on = (slap_overinst *) be->bd_info;          slap_overinst *on = (slap_overinst *) be->bd_info;
         overlay_stack *ov = on->on_bi.bi_private;          overlay_stack *ov = on->on_bi.bi_private;
         void *private = be->be_private;          void *private = be->be_private;
Line 724  static int translucent_db_open(BackendDB Line 679  static int translucent_db_open(BackendDB
   
         /* "should never happen" */          /* "should never happen" */
         if(!ov->info) {          if(!ov->info) {
                 Debug(LDAP_DEBUG_ANY, "translucent_db_open() called with bad ov->info\n", 0, 0, 0);                  Debug(LDAP_DEBUG_ANY, "translucent_open() called with bad ov->info\n", 0, 0, 0);
                 return(LDAP_OTHER);                  return(LDAP_OTHER);
         }          }
   
         Debug(LDAP_DEBUG_TRACE, "translucent_db_open\n", 0, 0, 0);          Debug(LDAP_DEBUG_TRACE, "translucent_open\n", 0, 0, 0);
   
         be->be_private = ov->private;          be->be_private = ov->private;
         rc = ov->info->bi_db_open ? ov->info->bi_db_open(be) : 0;          rc = ov->info->bi_db_open ? ov->info->bi_db_open(be) : 0;
Line 741  static int translucent_db_open(BackendDB Line 696  static int translucent_db_open(BackendDB
 }  }
   
 /*  /*
 ** translucent_db_close()  ** translucent_close()
 **      if the captive backend has a close() method, call it;  **      if the captive backend has a close() method, call it;
 **      free any config data;  **      free any config data;
 **  **
 */  */
   
 static int translucent_db_close(BackendDB *be) {  static int translucent_close(BackendDB *be) {
         slap_overinst *on = (slap_overinst *) be->bd_info;  
         overlay_stack *ov = on->on_bi.bi_private;  
         int rc = 0;  
   
         if ( ov ) {  
                 void *private = be->be_private;  
   
                 be->be_private = ov->private;  
                 rc = (ov->info && ov->info->bi_db_close) ? ov->info->bi_db_close(be) : 0;  
                 be->be_private = private;  
                 if(ov->config) ch_free(ov->config);  
                 ov->config = NULL;  
         }  
   
         return(rc);  
 }  
   
 /*  
 ** translucent_db_destroy()  
 **      if the captive backend has a db_destroy() method, call it  
 **  
 */  
   
 static int translucent_db_destroy(BackendDB *be) {  
         slap_overinst *on = (slap_overinst *) be->bd_info;          slap_overinst *on = (slap_overinst *) be->bd_info;
         overlay_stack *ov = on->on_bi.bi_private;          overlay_stack *ov = on->on_bi.bi_private;
         int rc = 0;          translucent_configuration *cf = ov->config;
           void *private = be->be_private;
         if ( ov ) {          int rc;
                 void *private = be->be_private;  
   
                 be->be_private = ov->private;  
                 rc = (ov->info && ov->info->bi_db_destroy) ? ov->info->bi_db_destroy(be) : 0;  
                 be->be_private = private;  
                 ch_free(ov);  
                 on->on_bi.bi_private = NULL;  
         }  
   
           be->be_private = ov->private;
           rc = (ov->info && ov->info->bi_db_close) ? ov->info->bi_db_close(be) : 0;
           be->be_private = private;
           if(ov->config) ch_free(ov->config);
           ch_free(ov);
         return(rc);          return(rc);
 }  }
   
 /*  /*
 ** translucent_initialize()  ** translucent_init()
 **      initialize the slap_overinst with our entry points;  **      initialize the slap_overinst with our entry points;
 **  **
 */  */
   
 int translucent_initialize() {  int translucent_init() {
   
         translucent.on_bi.bi_type       = "translucent";          translucent.on_bi.bi_type       = "translucent";
         translucent.on_bi.bi_db_init    = translucent_db_init;          translucent.on_bi.bi_db_init    = translucent_db_init;
         translucent.on_bi.bi_db_config  = translucent_db_config;          translucent.on_bi.bi_db_config  = translucent_config;
         translucent.on_bi.bi_db_open    = translucent_db_open;          translucent.on_bi.bi_db_open    = translucent_open;
         translucent.on_bi.bi_db_close   = translucent_db_close;          translucent.on_bi.bi_db_close   = translucent_close;
         translucent.on_bi.bi_db_destroy = translucent_db_destroy;  
         translucent.on_bi.bi_op_bind    = translucent_bind;          translucent.on_bi.bi_op_bind    = translucent_bind;
         translucent.on_bi.bi_op_add     = translucent_add;          translucent.on_bi.bi_op_add     = translucent_add;
         translucent.on_bi.bi_op_modify  = translucent_modify;          translucent.on_bi.bi_op_modify  = translucent_modify;
Line 810  int translucent_initialize() { Line 737  int translucent_initialize() {
         translucent.on_bi.bi_op_delete  = translucent_delete;          translucent.on_bi.bi_op_delete  = translucent_delete;
         translucent.on_bi.bi_op_search  = translucent_search;          translucent.on_bi.bi_op_search  = translucent_search;
         translucent.on_bi.bi_op_compare = translucent_compare;          translucent.on_bi.bi_op_compare = translucent_compare;
         translucent.on_bi.bi_connection_destroy = translucent_connection_destroy;  
   
         return(overlay_register(&translucent));          return(overlay_register(&translucent));
 }  }
   
 #if SLAPD_OVER_TRANSLUCENT == SLAPD_MOD_DYNAMIC && defined(PIC)  #if SLAPD_OVER_TRANSLUCENT == SLAPD_MOD_DYNAMIC && defined(PIC)
 int init_module(int argc, char *argv[]) {  int init_module(int argc, char *argv[]) {
         return translucent_initialize();          return translucent_init();
 }  }
 #endif  #endif
   

Removed from v.1.1.2.16  
changed lines
  Added in v.1.2


______________
© Copyright 1998-2020, OpenLDAP Foundation, info@OpenLDAP.org