/* * controlType = LDAP_CONTROL_GET_EFFECTIVE_RIGHTS; * criticality = n/a; * controlValue = OCTET STRING of BER encoding of the SEQUENCE of * ENUMERATED LDAP code */ void _ger_set_response_control ( Slapi_PBlock *pb, int iscritical, int rc ) { LDAPControl **resultctrls = NULL; LDAPControl gerrespctrl; BerElement *ber = NULL; struct berval *berval = NULL; int found = 0; int i; if ( (ber = der_alloc ()) == NULL ) { goto bailout; } /* begin sequence, enumeration, end sequence */ ber_printf ( ber, "{e}", rc ); if ( ber_flatten ( ber, &berval ) != LDAP_SUCCESS ) { goto bailout; } gerrespctrl.ldctl_oid = LDAP_CONTROL_GET_EFFECTIVE_RIGHTS; gerrespctrl.ldctl_iscritical = iscritical; gerrespctrl.ldctl_value.bv_val = berval->bv_val; gerrespctrl.ldctl_value.bv_len = berval->bv_len; slapi_pblock_get ( pb, SLAPI_RESCONTROLS, &resultctrls ); for (i = 0; resultctrls && resultctrls[i]; i++) { if (strcmp(resultctrls[i]->ldctl_oid, LDAP_CONTROL_GET_EFFECTIVE_RIGHTS) == 0) { /* * We get here if search returns more than one entry * and this is not the first entry. */ ldap_control_free ( resultctrls[i] ); resultctrls[i] = slapi_dup_control (&gerrespctrl); found = 1; break; } } if ( !found ) { /* slapi_pblock_set() will dup the control */ slapi_pblock_set ( pb, SLAPI_ADD_RESCONTROL, &gerrespctrl ); } bailout: ber_free ( ber, 1 ); /* ber_free() checks for NULL param */ ber_bvfree ( berval ); /* ber_bvfree() checks for NULL param */ }
static int pblock_add_control( Slapi_PBlock *pb, LDAPControl *control ) { LDAPControl **controls = NULL; size_t i; pblock_get_default( pb, SLAPI_RESCONTROLS, (void **)&controls ); if ( controls != NULL ) { for ( i = 0; controls[i] != NULL; i++ ) ; } else { i = 0; } controls = (LDAPControl **)slapi_ch_realloc( (char *)controls, ( i + 2 ) * sizeof(LDAPControl *)); controls[i++] = slapi_dup_control( control ); controls[i] = NULL; return pblock_set_default( pb, SLAPI_RESCONTROLS, (void *)controls ); }
/* * controlType = LDAP_CONTROL_PAGEDRESULTS; * criticality = n/a; * controlValue: * realSearchControlValue ::= SEQUENCE { * size INTEGER (0..maxInt), * -- requested page size from client * -- result set size estimate from server * cookie OCTET STRING * } */ void pagedresults_set_response_control( Slapi_PBlock *pb, int iscritical, ber_int_t estimate, int current_search_count, int index ) { LDAPControl **resultctrls = NULL; LDAPControl pr_respctrl; BerElement *ber = NULL; struct berval *berval = NULL; char *cookie_str = NULL; int found = 0; int i; LDAPDebug1Arg(LDAP_DEBUG_TRACE, "--> pagedresults_set_response_control: idx=%d\n", index); if ( (ber = der_alloc()) == NULL ) { goto bailout; } /* begin sequence, payload, end sequence */ if (current_search_count < 0) { cookie_str = slapi_ch_strdup(""); } else { cookie_str = slapi_ch_smprintf("%d", index); } ber_printf ( ber, "{io}", estimate, cookie_str, strlen(cookie_str) ); if ( ber_flatten ( ber, &berval ) != LDAP_SUCCESS ) { goto bailout; } pr_respctrl.ldctl_oid = LDAP_CONTROL_PAGEDRESULTS; pr_respctrl.ldctl_iscritical = iscritical; pr_respctrl.ldctl_value.bv_val = berval->bv_val; pr_respctrl.ldctl_value.bv_len = berval->bv_len; slapi_pblock_get ( pb, SLAPI_RESCONTROLS, &resultctrls ); for (i = 0; resultctrls && resultctrls[i]; i++) { if (strcmp(resultctrls[i]->ldctl_oid, LDAP_CONTROL_PAGEDRESULTS) == 0) { /* * We get here if search returns more than one entry * and this is not the first entry. */ ldap_control_free ( resultctrls[i] ); resultctrls[i] = slapi_dup_control (&pr_respctrl); found = 1; break; } } if ( !found ) { /* slapi_pblock_set() will dup the control */ slapi_pblock_set ( pb, SLAPI_ADD_RESCONTROL, &pr_respctrl ); } bailout: slapi_ch_free_string(&cookie_str); ber_free ( ber, 1 ); /* ber_free() checks for NULL param */ ber_bvfree ( berval ); /* ber_bvfree() checks for NULL param */ LDAPDebug1Arg(LDAP_DEBUG_TRACE, "<-- pagedresults_set_response_control: idx=%d\n", index); }
/* * Check if there are any persistent searches. If so, * the check to see if the chgtype is one of those the * client is interested in. If so, then check to see if * the entry matches any of the filters the searches. * If so, then enqueue the entry on that persistent search's * ps_entryqueue and signal it to wake up and send the entry. * * Note that if eprev is NULL we assume that the entry's DN * was not changed by the op. that called this function. If * chgnum is 0 it is unknown so we won't ever send it to a * client in the EntryChangeNotification control. */ void ps_service_persistent_searches( Slapi_Entry *e, Slapi_Entry *eprev, ber_int_t chgtype, ber_int_t chgnum ) { LDAPControl *ctrl = NULL; PSearch *ps = NULL; PSEQNode *pe = NULL; int matched = 0; const char *edn; if ( !PS_IS_INITIALIZED()) { return; } if ( NULL == e ) { /* For now, some backends such as the chaining backend do not provide a post-op entry */ return; } PSL_LOCK_READ(); edn = slapi_entry_get_dn_const(e); for ( ps = psearch_list ? psearch_list->pl_head : NULL; NULL != ps; ps = ps->ps_next ) { char *origbase = NULL; Slapi_DN *base = NULL; Slapi_Filter *f; int scope; /* Skip the node that doesn't meet the changetype, * or is unable to use the change in ps_send_results() */ if (( ps->ps_changetypes & chgtype ) == 0 || ps->ps_pblock->pb_op == NULL || slapi_op_abandoned( ps->ps_pblock ) ) { continue; } slapi_log_error(SLAPI_LOG_CONNS, "Persistent Search", "conn=%" NSPRIu64 " op=%d entry %s with chgtype %d " "matches the ps changetype %d\n", ps->ps_pblock->pb_conn->c_connid, ps->ps_pblock->pb_op->o_opid, edn, chgtype, ps->ps_changetypes); slapi_pblock_get( ps->ps_pblock, SLAPI_SEARCH_FILTER, &f ); slapi_pblock_get( ps->ps_pblock, SLAPI_ORIGINAL_TARGET_DN, &origbase ); slapi_pblock_get( ps->ps_pblock, SLAPI_SEARCH_TARGET_SDN, &base ); slapi_pblock_get( ps->ps_pblock, SLAPI_SEARCH_SCOPE, &scope ); if (NULL == base) { base = slapi_sdn_new_dn_byref(origbase); slapi_pblock_set(ps->ps_pblock, SLAPI_SEARCH_TARGET_SDN, base); } /* * See if the entry meets the scope and filter criteria. * We cannot do the acl check here as this thread * would then potentially clash with the ps_send_results() * thread on the aclpb in ps->ps_pblock. * By avoiding the acl check in this thread, and leaving all the acl * checking to the ps_send_results() thread we avoid * the ps_pblock contention problem. * The lesson here is "Do not give multiple threads arbitary access * to the same pblock" this kind of muti-threaded access * to the same pblock must be done carefully--there is currently no * generic satisfactory way to do this. */ if ( slapi_sdn_scope_test( slapi_entry_get_sdn_const(e), base, scope ) && slapi_vattr_filter_test( ps->ps_pblock, e, f, 0 /* verify_access */ ) == 0 ) { PSEQNode *pOldtail; /* The scope and the filter match - enqueue it */ matched++; pe = (PSEQNode *)slapi_ch_calloc( 1, sizeof( PSEQNode )); pe->pe_entry = slapi_entry_dup( e ); if ( ps->ps_send_entchg_controls ) { /* create_entrychange_control() is more * expensive than slapi_dup_control() */ if ( ctrl == NULL ) { int rc; rc = create_entrychange_control( chgtype, chgnum, eprev ? slapi_entry_get_dn_const(eprev) : NULL, &ctrl ); if ( rc != LDAP_SUCCESS ) { LDAPDebug( LDAP_DEBUG_ANY, "ps_service_persistent_searches:" " unable to create EntryChangeNotification control for" " entry \"%s\" -- control won't be sent.\n", slapi_entry_get_dn_const(e), 0, 0 ); } } if ( ctrl ) { pe->pe_ctrls[0] = slapi_dup_control( ctrl ); } } /* Put it on the end of the list for this pers search */ PR_Lock( ps->ps_lock ); pOldtail = ps->ps_eq_tail; ps->ps_eq_tail = pe; if ( NULL == ps->ps_eq_head ) { ps->ps_eq_head = ps->ps_eq_tail; } else { pOldtail->pe_next = ps->ps_eq_tail; } PR_Unlock( ps->ps_lock ); } } PSL_UNLOCK_READ(); /* Were there any matches? */ if ( matched ) { ldap_control_free( ctrl ); /* Turn 'em loose */ ps_wakeup_all(); LDAPDebug( LDAP_DEBUG_TRACE, "ps_service_persistent_searches: enqueued entry " "\"%s\" on %d persistent search lists\n", slapi_entry_get_dn_const(e), matched, 0 ); } else { LDAPDebug( LDAP_DEBUG_TRACE, "ps_service_persistent_searches: entry " "\"%s\" not enqueued on any persistent search lists\n", slapi_entry_get_dn_const(e), 0, 0 ); } }
/* This function scans the array of controls and updates the Repl_Agmt's Dirsync_Private if the dirsync control is found. */ void windows_private_update_dirsync_control(const Repl_Agmt *ra,LDAPControl **controls ) { Dirsync_Private *dp; int foundDirsyncControl; int i; LDAPControl *dirsync = NULL; BerElement *ber = NULL; ber_int_t hasMoreData; ber_int_t maxAttributeCount; BerValue *serverCookie = NULL; #ifdef FOR_DEBUGGING int return_value = LDAP_SUCCESS; #endif LDAPDebug0Args( LDAP_DEBUG_TRACE, "=> windows_private_update_dirsync_control\n" ); PR_ASSERT(ra); dp = (Dirsync_Private *) agmt_get_priv(ra); PR_ASSERT (dp); if (NULL != controls ) { foundDirsyncControl = 0; for ( i = 0; (( controls[i] != NULL ) && ( !foundDirsyncControl )); i++ ) { foundDirsyncControl = !strcmp( controls[i]->ldctl_oid, REPL_DIRSYNC_CONTROL_OID ); } if ( !foundDirsyncControl ) { #ifdef FOR_DEBUGGING return_value = LDAP_CONTROL_NOT_FOUND; #endif goto choke; } else if (!controls[i-1]->ldctl_value.bv_val) { #ifdef FOR_DEBUGGING return_value = LDAP_CONTROL_NOT_FOUND; #endif goto choke; } else { dirsync = slapi_dup_control( controls[i-1]); } ber = ber_init( &dirsync->ldctl_value ) ; if (ber_scanf( ber, "{iiO}", &hasMoreData, &maxAttributeCount, &serverCookie) == LBER_ERROR) { #ifdef FOR_DEBUGGING return_value = LDAP_CONTROL_NOT_FOUND; #endif goto choke; } slapi_ch_free_string(&dp->dirsync_cookie); dp->dirsync_cookie = ( char* ) slapi_ch_malloc(serverCookie->bv_len + 1); memcpy(dp->dirsync_cookie, serverCookie->bv_val, serverCookie->bv_len); dp->dirsync_cookie_len = (int) serverCookie->bv_len; /* XXX shouldn't cast? */ /* dp->dirsync_maxattributecount = maxAttributeCount; We don't need to keep this */ dp->dirsync_cookie_has_more = hasMoreData; choke: ber_bvfree(serverCookie); ber_free(ber,1); ldap_control_free(dirsync); } else { #ifdef FOR_DEBUGGING return_value = LDAP_CONTROL_NOT_FOUND; #endif } #ifdef FOR_DEBUGGING LDAPDebug1Arg( LDAP_DEBUG_TRACE, "<= windows_private_update_dirsync_control: rc=%d\n", return_value); #else LDAPDebug0Args( LDAP_DEBUG_TRACE, "<= windows_private_update_dirsync_control\n" ); #endif }