]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/overlays/syncprov.c
Fix void* pointer arithmetic from ber_bvchr()
[openldap] / servers / slapd / overlays / syncprov.c
index 1a863686926142a835d53392014bca47c5888ca2..afe894f795bf021f2a8a5f46885d47591f7f80b1 100644 (file)
@@ -122,6 +122,7 @@ typedef struct syncprov_info_t {
        int             si_chktime;
        int             si_numops;      /* number of ops since last checkpoint */
        int             si_nopres;      /* Skip present phase */
+       int             si_usehint;     /* use reload hint */
        time_t  si_chklast;     /* time of last checkpoint */
        Avlnode *si_mods;       /* entries being modified */
        sessionlog      *si_logs;
@@ -382,6 +383,9 @@ findbase_cb( Operation *op, SlapReply *rs )
        return LDAP_SUCCESS;
 }
 
+static Filter generic_filter = { LDAP_FILTER_PRESENT, { 0 }, NULL };
+static struct berval generic_filterstr = BER_BVC("(objectclass=*)");
+
 static int
 syncprov_findbase( Operation *op, fbase_cookie *fc )
 {
@@ -421,6 +425,8 @@ syncprov_findbase( Operation *op, fbase_cookie *fc )
                fop.ors_tlimit = SLAP_NO_LIMIT;
                fop.ors_attrs = slap_anlist_no_attrs;
                fop.ors_attrsonly = 1;
+               fop.ors_filter = &generic_filter;
+               fop.ors_filterstr = generic_filterstr;
 
                fop.o_bd->bd_info = on->on_info->oi_orig;
                rc = fop.o_bd->be_search( &fop, &frs );
@@ -477,9 +483,11 @@ syncprov_findbase( Operation *op, fbase_cookie *fc )
  * CSN, and generate Present records for them. We always collect this result
  * in SyncID sets, even if there's only one match.
  */
-#define        FIND_MAXCSN     1
-#define        FIND_CSN        2
-#define        FIND_PRESENT    3
+typedef enum find_csn_t {
+       FIND_MAXCSN     = 1,
+       FIND_CSN        = 2,
+       FIND_PRESENT    = 3
+} find_csn_t;
 
 static int
 findmax_cb( Operation *op, SlapReply *rs )
@@ -558,7 +566,7 @@ findpres_cb( Operation *op, SlapReply *rs )
 }
 
 static int
-syncprov_findcsn( Operation *op, int mode )
+syncprov_findcsn( Operation *op, find_csn_t mode )
 {
        slap_overinst           *on = (slap_overinst *)op->o_bd->bd_info;
        syncprov_info_t         *si = on->on_bi.bi_private;
@@ -697,9 +705,39 @@ again:
        return rc;
 }
 
+static void
+syncprov_free_syncop( syncops *so )
+{
+       syncres *sr, *srnext;
+       GroupAssertion *ga, *gnext;
+
+       ldap_pvt_thread_mutex_lock( &so->s_mutex );
+       if ( --so->s_inuse > 0 ) {
+               ldap_pvt_thread_mutex_unlock( &so->s_mutex );
+               return;
+       }
+       ldap_pvt_thread_mutex_unlock( &so->s_mutex );
+       if ( so->s_flags & PS_IS_DETACHED ) {
+               filter_free( so->s_op->ors_filter );
+               for ( ga = so->s_op->o_groups; ga; ga=gnext ) {
+                       gnext = ga->ga_next;
+                       ch_free( ga );
+               }
+               ch_free( so->s_op );
+       }
+       ch_free( so->s_base.bv_val );
+       for ( sr=so->s_res; sr; sr=srnext ) {
+               srnext = sr->s_next;
+               ch_free( sr );
+       }
+       ldap_pvt_thread_mutex_destroy( &so->s_mutex );
+       ch_free( so );
+}
+
 /* Send a persistent search response */
 static int
-syncprov_sendresp( Operation *op, opcookie *opc, syncops *so, Entry **e, int mode)
+syncprov_sendresp( Operation *op, opcookie *opc, syncops *so,
+       Entry **e, int mode )
 {
        slap_overinst *on = opc->son;
 
@@ -720,6 +758,7 @@ syncprov_sendresp( Operation *op, opcookie *opc, syncops *so, Entry **e, int mod
        a_uuid.a_nvals = &opc->suuid;
        rs.sr_err = syncprov_state_ctrl( op, &rs, &e_uuid,
                mode, ctrls, 0, 1, &cookie );
+       op->o_tmpfree( cookie.bv_val, op->o_tmpmemctx );
 
        rs.sr_ctrls = ctrls;
        op->o_bd->bd_info = (BackendInfo *)on->on_info;
@@ -762,8 +801,11 @@ syncprov_sendresp( Operation *op, opcookie *opc, syncops *so, Entry **e, int mod
        default:
                assert(0);
        }
-       op->o_tmpfree( rs.sr_ctrls[0], op->o_tmpmemctx );
-       rs.sr_ctrls = NULL;
+       /* In case someone else freed it already? */
+       if ( rs.sr_ctrls ) {
+               op->o_tmpfree( rs.sr_ctrls[0], op->o_tmpmemctx );
+               rs.sr_ctrls = NULL;
+       }
 
        return rs.sr_err;
 }
@@ -789,34 +831,33 @@ syncprov_qplay( Operation *op, slap_overinst *on, syncops *so )
                        so->s_restail = NULL;
                ldap_pvt_thread_mutex_unlock( &so->s_mutex );
 
-               if ( !sr )
+               if ( !sr || so->s_op->o_abandon )
                        break;
 
-               if ( !so->s_op->o_abandon ) {
-                       opc.sdn = sr->s_dn;
-                       opc.sndn = sr->s_ndn;
-                       opc.suuid = sr->s_uuid;
-                       opc.sctxcsn = sr->s_csn;
-                       opc.sreference = sr->s_isreference;
-                       e = NULL;
-
-                       if ( sr->s_mode != LDAP_SYNC_DELETE ) {
-                               rc = be_entry_get_rw( op, &opc.sndn, NULL, NULL, 0, &e );
-                               if ( rc ) {
-                                       ch_free( sr );
-                                       continue;
-                               }
+               opc.sdn = sr->s_dn;
+               opc.sndn = sr->s_ndn;
+               opc.suuid = sr->s_uuid;
+               opc.sctxcsn = sr->s_csn;
+               opc.sreference = sr->s_isreference;
+               e = NULL;
+
+               if ( sr->s_mode != LDAP_SYNC_DELETE ) {
+                       rc = be_entry_get_rw( op, &opc.sndn, NULL, NULL, 0, &e );
+                       if ( rc ) {
+                               ch_free( sr );
+                               continue;
                        }
-                       rc = syncprov_sendresp( op, &opc, so, &e, sr->s_mode );
+               }
+               rc = syncprov_sendresp( op, &opc, so, &e, sr->s_mode );
 
-                       if ( e ) {
-                               be_entry_release_rw( op, e, 0 );
-                       }
-                       if ( rc )
-                               break;
+               if ( e ) {
+                       be_entry_release_rw( op, e, 0 );
                }
 
                ch_free( sr );
+
+               if ( rc )
+                       break;
        }
        op->o_bd->bd_info = (BackendInfo *)on;
        return rc;
@@ -829,14 +870,15 @@ syncprov_qtask( void *ctx, void *arg )
        struct re_s *rtask = arg;
        syncops *so = rtask->arg;
        slap_overinst *on = so->s_op->o_private;
-       char opbuf[OPERATION_BUFFER_SIZE];
+       OperationBuffer opbuf;
        Operation *op;
        BackendDB be;
 
-       op = (Operation *)opbuf;
-       memset( op, 0, sizeof(opbuf));
+       op = (Operation *) &opbuf;
+       *op = *so->s_op;
        op->o_hdr = (Opheader *)(op+1);
        op->o_controls = (void **)(op->o_hdr+1);
+       memset( op->o_controls, 0, SLAP_MAX_CIDS * sizeof(void *));
 
        *op->o_hdr = *so->s_op->o_hdr;
 
@@ -853,6 +895,9 @@ syncprov_qtask( void *ctx, void *arg )
 
        syncprov_qplay( op, on, so );
 
+       /* decrement use count... */
+       syncprov_free_syncop( so );
+
        /* wait until we get explicitly scheduled again */
        ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
        ldap_pvt_runqueue_stoptask( &slapd_rq, so->s_qtask );
@@ -875,13 +920,14 @@ syncprov_qresp( opcookie *opc, syncops *so, int mode )
        sr->s_dn.bv_len = opc->sdn.bv_len;
        sr->s_mode = mode;
        sr->s_isreference = opc->sreference;
-       sr->s_ndn.bv_val = lutil_strcopy( sr->s_dn.bv_val, opc->sdn.bv_val );
+       sr->s_ndn.bv_val = lutil_strcopy( sr->s_dn.bv_val,
+                opc->sdn.bv_val ) + 1;
        sr->s_ndn.bv_len = opc->sndn.bv_len;
-       *(sr->s_ndn.bv_val++) = '\0';
-       sr->s_uuid.bv_val = lutil_strcopy( sr->s_ndn.bv_val, opc->sndn.bv_val );
+       sr->s_uuid.bv_val = lutil_strcopy( sr->s_ndn.bv_val,
+                opc->sndn.bv_val ) + 1;
        sr->s_uuid.bv_len = opc->suuid.bv_len;
-       *(sr->s_uuid.bv_val++) = '\0';
-       sr->s_csn.bv_val = lutil_strcopy( sr->s_uuid.bv_val, opc->suuid.bv_val );
+       AC_MEMCPY( sr->s_uuid.bv_val, opc->suuid.bv_val, opc->suuid.bv_len );
+       sr->s_csn.bv_val = sr->s_uuid.bv_val + sr->s_uuid.bv_len + 1;
        sr->s_csn.bv_len = opc->sctxcsn.bv_len;
        strcpy( sr->s_csn.bv_val, opc->sctxcsn.bv_val );
 
@@ -904,11 +950,14 @@ syncprov_qresp( opcookie *opc, syncops *so, int mode )
                        so->s_qtask = ldap_pvt_runqueue_insert( &slapd_rq, RUNQ_INTERVAL,
                                syncprov_qtask, so, "syncprov_qtask",
                                so->s_op->o_conn->c_peer_name.bv_val );
+                       ++so->s_inuse;
                } else {
-                       if (!ldap_pvt_runqueue_isrunning( &slapd_rq, so->s_qtask )) {
+                       if (!ldap_pvt_runqueue_isrunning( &slapd_rq, so->s_qtask ) &&
+                               !so->s_qtask->next_sched.tv_sec ) {
                                so->s_qtask->interval.tv_sec = 0;
                                ldap_pvt_runqueue_resched( &slapd_rq, so->s_qtask, 0 );
                                so->s_qtask->interval.tv_sec = RUNQ_INTERVAL;
+                               ++so->s_inuse;
                        }
                }
                ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
@@ -917,36 +966,6 @@ syncprov_qresp( opcookie *opc, syncops *so, int mode )
        return LDAP_SUCCESS;
 }
 
-static void
-syncprov_free_syncop( syncops *so )
-{
-       syncres *sr, *srnext;
-       GroupAssertion *ga, *gnext;
-
-       ldap_pvt_thread_mutex_lock( &so->s_mutex );
-       so->s_inuse--;
-       if ( so->s_inuse > 0 ) {
-               ldap_pvt_thread_mutex_unlock( &so->s_mutex );
-               return;
-       }
-       ldap_pvt_thread_mutex_unlock( &so->s_mutex );
-       if ( so->s_flags & PS_IS_DETACHED ) {
-               filter_free( so->s_op->ors_filter );
-               for ( ga = so->s_op->o_groups; ga; ga=gnext ) {
-                       gnext = ga->ga_next;
-                       ch_free( ga );
-               }
-               ch_free( so->s_op );
-       }
-       ch_free( so->s_base.bv_val );
-       for ( sr=so->s_res; sr; sr=srnext ) {
-               srnext = sr->s_next;
-               ch_free( sr );
-       }
-       ldap_pvt_thread_mutex_destroy( &so->s_mutex );
-       ch_free( so );
-}
-
 static int
 syncprov_drop_psearch( syncops *so, int lock )
 {
@@ -1122,14 +1141,14 @@ syncprov_matchops( Operation *op, opcookie *opc, int saveit )
                                sm = op->o_tmpalloc( sizeof(syncmatches), op->o_tmpmemctx );
                                sm->sm_next = opc->smatches;
                                sm->sm_op = ss;
-                               ss->s_inuse++;
+                               ldap_pvt_thread_mutex_lock( &ss->s_mutex );
+                               ++ss->s_inuse;
+                               ldap_pvt_thread_mutex_unlock( &ss->s_mutex );
                                opc->smatches = sm;
                        } else {
                                /* if found send UPDATE else send ADD */
-                               ss->s_inuse++;
                                syncprov_qresp( opc, ss,
                                        found ? LDAP_SYNC_MODIFY : LDAP_SYNC_ADD );
-                               ss->s_inuse--;
                        }
                } else if ( !saveit && found ) {
                        /* send DELETE */
@@ -1205,7 +1224,6 @@ syncprov_checkpoint( Operation *op, SlapReply *rs, slap_overinst *on )
        Operation opm;
        struct berval bv[2];
        slap_callback cb = {0};
-       int manage = get_manageDSAit(op);
 
        mod.sml_values = bv;
        bv[1].bv_val = NULL;
@@ -1226,7 +1244,9 @@ syncprov_checkpoint( Operation *op, SlapReply *rs, slap_overinst *on )
        opm.o_bd->bd_info = on->on_info->oi_orig;
        opm.o_managedsait = SLAP_CONTROL_NONCRITICAL;
        opm.o_bd->be_modify( &opm, rs );
-       opm.o_managedsait = manage;
+       if ( mod.sml_next != NULL ) {
+               slap_mods_free( mod.sml_next, 1 );
+       }
 }
 
 static void
@@ -1802,15 +1822,13 @@ syncprov_search_response( Operation *op, SlapReply *rs )
                        rs->sr_err = syncprov_done_ctrl( op, rs, rs->sr_ctrls,
                                0, 1, &cookie, ss->ss_present ?  LDAP_SYNC_REFRESH_PRESENTS :
                                        LDAP_SYNC_REFRESH_DELETES );
+                       op->o_tmpfree( cookie.bv_val, op->o_tmpmemctx );
                } else {
                /* It's RefreshAndPersist, transition to Persist phase */
                        syncprov_sendinfo( op, rs, ( ss->ss_present && rs->sr_nentries ) ?
                                LDAP_TAG_SYNC_REFRESH_PRESENT : LDAP_TAG_SYNC_REFRESH_DELETE,
                                &cookie, 1, NULL, 0 );
-                       /* Flush any queued persist messages */
-                       if ( ss->ss_so->s_res ) {
-                               syncprov_qplay( op, on, ss->ss_so );
-                       }
+                       op->o_tmpfree( cookie.bv_val, op->o_tmpmemctx );
 
                        /* Detach this Op from frontend control */
                        ldap_pvt_thread_mutex_lock( &ss->ss_so->s_mutex );
@@ -1935,12 +1953,11 @@ syncprov_op_search( Operation *op, SlapReply *rs )
                /* Is the CSN still present in the database? */
                if ( syncprov_findcsn( op, FIND_CSN ) != LDAP_SUCCESS ) {
                        /* No, so a reload is required */
-#if 0          /* the consumer doesn't seem to send this hint */
-                       if ( op->o_sync_rhint == 0 ) {
+                       /* the 2.2 consumer doesn't send this hint */
+                       if ( si->si_usehint && srs->sr_rhint == 0 ) {
                                send_ldap_error( op, rs, LDAP_SYNC_REFRESH_REQUIRED, "sync cookie is stale" );
                                return rs->sr_err;
                        }
-#endif
                } else {
                        gotstate = 1;
                        /* If changed and doing Present lookup, send Present UUIDs */
@@ -2061,7 +2078,8 @@ syncprov_operational(
 enum {
        SP_CHKPT = 1,
        SP_SESSL,
-       SP_NOPRES
+       SP_NOPRES,
+       SP_USEHINT
 };
 
 static ConfigDriver sp_cf_gen;
@@ -2079,6 +2097,10 @@ static ConfigTable spcfg[] = {
                sp_cf_gen, "( OLcfgOvAt:1.3 NAME 'olcSpNoPresent' "
                        "DESC 'Omit Present phase processing' "
                        "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
+       { "syncprov-reloadhint", NULL, 2, 2, 0, ARG_ON_OFF|ARG_MAGIC|SP_USEHINT,
+               sp_cf_gen, "( OLcfgOvAt:1.4 NAME 'olcSpReloadHint' "
+                       "DESC 'Observe Reload Hint in Request control' "
+                       "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
        { NULL, NULL, 0, 0, 0, ARG_IGNORED }
 };
 
@@ -2126,6 +2148,13 @@ sp_cf_gen(ConfigArgs *c)
                                rc = 1;
                        }
                        break;
+               case SP_USEHINT:
+                       if ( si->si_usehint ) {
+                               c->value_int = 1;
+                       } else {
+                               rc = 1;
+                       }
+                       break;
                }
                return rc;
        } else if ( c->op == LDAP_MOD_DELETE ) {
@@ -2146,6 +2175,12 @@ sp_cf_gen(ConfigArgs *c)
                        else
                                rc = LDAP_NO_SUCH_ATTRIBUTE;
                        break;
+               case SP_USEHINT:
+                       if ( si->si_usehint )
+                               si->si_usehint = 0;
+                       else
+                               rc = LDAP_NO_SUCH_ATTRIBUTE;
+                       break;
                }
                return rc;
        }
@@ -2180,6 +2215,9 @@ sp_cf_gen(ConfigArgs *c)
        case SP_NOPRES:
                si->si_nopres = c->value_int;
                break;
+       case SP_USEHINT:
+               si->si_usehint = c->value_int;
+               break;
        }
        return rc;
 }
@@ -2209,9 +2247,9 @@ syncprov_db_open(
        syncprov_info_t *si = (syncprov_info_t *)on->on_bi.bi_private;
 
        Connection conn;
-       char opbuf[OPERATION_BUFFER_SIZE];
+       OperationBuffer opbuf;
        char ctxcsnbuf[LDAP_LUTIL_CSNSTR_BUFSIZE];
-       Operation *op = (Operation *)opbuf;
+       Operation *op = (Operation *) &opbuf;
        Entry *e;
        Attribute *a;
        int rc;
@@ -2267,8 +2305,8 @@ syncprov_db_open(
        }
 
        if ( BER_BVISEMPTY( &si->si_ctxcsn ) ) {
-               slap_get_csn( op, si->si_ctxcsnbuf, sizeof(si->si_ctxcsnbuf),
-                               &si->si_ctxcsn, 0 );
+               si->si_ctxcsn.bv_len = sizeof( si->si_ctxcsnbuf );
+               slap_get_csn( op, &si->si_ctxcsn, 0 );
        }
 
        /* If our ctxcsn is different from what was read from the root
@@ -2299,8 +2337,8 @@ syncprov_db_close(
        }
        if ( si->si_numops ) {
                Connection conn;
-               char opbuf[OPERATION_BUFFER_SIZE];
-               Operation *op = (Operation *)opbuf;
+               OperationBuffer opbuf;
+               Operation *op = (Operation *) &opbuf;
                SlapReply rs = {REP_RESULT};
                void *thrctx;
 
@@ -2427,6 +2465,7 @@ static int syncprov_parseCtrl (
                        rs->sr_text = "Sync control : cookie decoding error";
                        return LDAP_PROTOCOL_ERROR;
                }
+               tag = ber_peek_tag( ber, &len );
        }
        if ( tag == LDAP_TAG_RELOAD_HINT ) {
                if (( ber_scanf( ber, /*{*/ "b", &rhint )) == LBER_ERROR ) {
@@ -2501,6 +2540,8 @@ syncprov_init()
 
        syncprov.on_bi.bi_cf_ocs = spocs;
 
+       generic_filter.f_desc = slap_schema.si_ad_objectClass;
+
        rc = config_register_schema( spcfg, spocs );
        if ( rc ) return rc;