LDAP_BEGIN_DECL
+#define LDAP_CLIENT_UPDATE 1
+#undef LDAP_CLIENT_UPDATE
+
#define LDAP_VERSION1 1
#define LDAP_VERSION2 2
#define LDAP_VERSION3 3
#define LDAP_CONTROL_PAGEDRESULTS "1.2.840.113556.1.4.319"
#endif
+#if LDAP_CLIENT_UPDATE
+#define LDAP_CONTROL_CLIENT_UPDATE "1.3.6.1.4.1.4203.666.7.1"
+#define LDAP_CONTROL_ENTRY_UPDATE "1.3.6.1.4.1.4203.666.7.2"
+#define LDAP_CONTROL_CLIENT_UPDATE_DONE "1.3.6.1.4.1.4203.666.7.3"
+#endif
+
#define LDAP_CONTROL_SORTREQUEST "1.2.840.113556.1.4.473"
#define LDAP_CONTROL_SORTRESPONSE "1.2.840.113556.1.4.474"
#define LDAP_CONTROL_VLVREQUEST "2.16.840.1.113730.3.4.9"
/* general stuff */
#define LDAP_TAG_MESSAGE ((ber_tag_t) 0x30U) /* constructed + 16 */
#define LDAP_TAG_MSGID ((ber_tag_t) 0x02U) /* integer */
+
+#ifdef LDAP_CLIENT_UPDATE
+#define LDAP_TAG_INTERVAL ((ber_tag_t) 0x02U) /* integer */
+#endif /* LDAP_CLIENT_UPDATE */
+
#define LDAP_TAG_LDAPDN ((ber_tag_t) 0x04U) /* octet string */
#define LDAP_TAG_LDAPCRED ((ber_tag_t) 0x04U) /* octet string */
+
+#ifdef LDAP_CLIENT_UPDATE
+#define LDAP_TAG_COOKIE ((ber_tag_t) 0x30U) /* sequence */
+#endif /* LDAP_CLIENT_UPDATE */
+
#define LDAP_TAG_CONTROLS ((ber_tag_t) 0xa0U) /* context specific + constructed + 0 */
#define LDAP_TAG_REFERRAL ((ber_tag_t) 0xa3U) /* context specific + constructed + 3 */
#define LDAP_CLIENT_LOOP 0x60 /* draft-ietf-ldap-c-api-xx */
#define LDAP_REFERRAL_LIMIT_EXCEEDED 0x61 /* draft-ietf-ldap-c-api-xx */
+#ifdef LDAP_CLIENT_UPDATE
+/* resultCode for LCUP */
+#define LCUP_RESOURCES_EXHAUSTED 0x62
+#define LCUP_SECURITY_VIOLATION 0x63
+#define LCUP_INVALID_COOKIE 0x64
+#define LCUP_UNSUPPORTED_SCHEME 0x65
+#define LCUP_CLIENT_DISCONNECT 0x66
+#define LCUP_RELOAD_REQUIRED 0x67
+#endif /* LDAP_CLIENT_UPDATE */
+
+#ifdef LDAP_CLIENT_UPDATE
+#define SYNCHRONIZE_ONLY 0x00
+#define SYNCHRONIZE_AND_PERSIST 0x01
+#define PERSIST_ONLY 0x02
+#endif /* LDAP_CLIENT_UPDATE */
+
+#ifdef LDAP_CLIENT_UPDATE
+#define LDAP_LCUP_DEFAULT_SEND_COOKIE_INTERVAL 0x01
+#endif /* LDAP_CLIENT_UPDATE */
+
/*
* This structure represents both ldap messages and ldap responses.
* These are really the same, except in the case of search responses,
int nentries = 0;
int manageDSAit;
+#ifdef LDAP_CLIENT_UPDATE
+ Filter lcupf, csnfnot, csnfeq, csnfand, csnfge;
+ AttributeAssertion aa_ge, aa_eq;
+ LDAPControl ctrl;
+ int entry_count = 0;
+#endif /* LDAP_CLIENT_UPDATE */
+
struct slap_limits_set *limit = NULL;
int isroot = 0;
filter_hasSubordinates = filter_has_subordinates( filter );
#endif /* SLAP_X_FILTER_HASSUBORDINATES */
+#ifdef LDAP_CLIENT_UPDATE
+ if ( op->o_clientupdatetype == SYNCHRONIZE_ONLY ||
+ op->o_clientupdatetype == SYNCHRONIZE_AND_PERSIST ) {
+ lcupf.f_choice = LDAP_FILTER_AND;
+ lcupf.f_and = &csnfnot;
+ lcupf.f_next = NULL;
+
+ csnfnot.f_choice = LDAP_FILTER_NOT;
+ csnfnot.f_not = &csnfeq;
+ csnfnot.f_next = &csnfand;
+
+ csnfeq.f_choice = LDAP_FILTER_EQUALITY;
+ csnfeq.f_ava = &aa_eq;
+ csnfeq.f_av_desc = slap_schema.si_ad_entryCSN;
+ ber_dupbv(&csnfeq.f_av_value, op->o_clientupdatestate);
+
+ csnfand.f_choice = LDAP_FILTER_AND;
+ csnfand.f_and = &csnfge;
+ csnfand.f_next = NULL;
+
+ csnfge.f_choice = LDAP_FILTER_GE;
+ csnfge.f_ava = &aa_ge;
+ csnfge.f_av_desc = slap_schema.si_ad_entryCSN;
+ ber_dupbv(&csnfge.f_av_value, op->o_clientupdatestate);
+ csnfge.f_next = filter;
+ }
+#endif /* LDAP_CLIENT_UPDATE */
+
for ( id = bdb_idl_first( candidates, &cursor );
id != NOID;
id = bdb_idl_next( candidates, &cursor ) )
#endif /* SLAP_X_FILTER_HASSUBORDINATES */
/* if it matches the filter and scope, send it */
+#ifdef LDAP_CLIENT_UPDATE
+ if ( op->o_clientupdatetype == SYNCHRONIZE_ONLY ||
+ op->o_clientupdatetype == SYNCHRONIZE_AND_PERSIST ) {
+ rc = test_filter( be, conn, op, e, &lcupf );
+ }
+ else {
+ rc = test_filter( be, conn, op, e, filter );
+ }
+#else /* LDAP_CLIENT_UPDATE */
rc = test_filter( be, conn, op, e, filter );
+#endif /* LDAP_CLIENT_UPDATE */
#ifdef SLAP_X_FILTER_HASSUBORDINATES
if ( hasSubordinates ) {
#endif
result = send_search_entry( be, conn, op,
e, attrs, attrsonly, NULL);
+
#if 0
}
#endif
ldap_pvt_thread_yield();
}
+
send_search_result( conn, op,
v2refs == NULL ? LDAP_SUCCESS : LDAP_REFERRAL,
NULL, NULL, v2refs, NULL, nentries );
static SLAP_CTRL_PARSE_FN parsePagedResults;
static SLAP_CTRL_PARSE_FN parseValuesReturnFilter;
+#ifdef LDAP_CLIENT_UPDATE
+static SLAP_CTRL_PARSE_FN parseClientUpdate;
+#endif /* LDAP_CLIENT_UPDATE */
+
#undef sc_mask /* avoid conflict with Irix 6.5 <sys/signal.h> */
static struct slap_control {
{ LDAP_CONTROL_VALUESRETURNFILTER,
SLAP_CTRL_SEARCH, NULL,
parseValuesReturnFilter },
+#endif
+#ifdef LDAP_CLIENT_UPDATE
+ { LDAP_CONTROL_CLIENT_UPDATE,
+ SLAP_CTRL_SEARCH, NULL,
+ parseClientUpdate },
#endif
{ NULL }
};
int rc = LDAP_SUCCESS;
const char *errmsg = NULL;
+#ifdef LDAP_CLIENT_UPDATE
+ op->o_clientupdatetype = -1;
+#endif
+
len = ber_pvt_ber_remaining(ber);
if( len == 0) {
return LDAP_SUCCESS;
}
#endif
+
+#ifdef LDAP_CLIENT_UPDATE
+static int parseClientUpdate (
+ Connection *conn,
+ Operation *op,
+ LDAPControl *ctrl,
+ const char **text )
+{
+ ber_tag_t tag;
+ BerElement *ber;
+ ber_int_t type;
+ ber_int_t interval;
+ ber_len_t len;
+ struct berval scheme = { 0, NULL };
+ struct berval cookie = { 0, NULL };
+
+ if ( op->o_noop != SLAP_NO_CONTROL ) {
+ *text = "LCUP client update control specified multiple times";
+ return LDAP_PROTOCOL_ERROR;
+ }
+
+ if ( ctrl->ldctl_value.bv_len == 0 ) {
+ *text = "LCUP client update control value is empty";
+ return LDAP_PROTOCOL_ERROR;
+ }
+
+ /* Parse the control value
+ * ClientUpdateControlValue ::= SEQUENCE {
+ * updateType ENUMERATED {
+ * synchronizeOnly {0},
+ * synchronizeAndPersist {1},
+ * persistOnly {2} },
+ * sendCookieInterval INTEGER OPTIONAL,
+ * cookie LCUPCookie OPTIONAL
+ * }
+ */
+
+ ber = ber_init( &ctrl->ldctl_value );
+ if( ber == NULL ) {
+ *text = "internal error";
+ return LDAP_OTHER;
+ }
+
+ if ( (tag = ber_scanf( ber, "{i" /*}*/, &type )) == LBER_ERROR ) {
+ *text = "LCUP client update control : decoding error";
+ return LDAP_PROTOCOL_ERROR;
+ }
+
+ if ( type != SYNCHRONIZE_ONLY &&
+ type != SYNCHRONIZE_AND_PERSIST &&
+ type != PERSIST_ONLY ) {
+ *text = "LCUP client update control : unknown update type";
+ return LDAP_PROTOCOL_ERROR;
+ }
+
+ if ( (tag = ber_peek_tag( ber, &len )) == LBER_DEFAULT ) {
+ *text = "LCUP client update control : decoding error";
+ return LDAP_PROTOCOL_ERROR;
+ }
+
+ if ( tag == LDAP_TAG_INTERVAL ) {
+ if ( (tag = ber_scanf( ber, "i", &interval )) == LBER_ERROR ) {
+ *text = "LCUP client update control : decoding error";
+ return LDAP_PROTOCOL_ERROR;
+ }
+
+ if ( interval <= 0 ) {
+ /* server chooses interval */
+ interval = LDAP_LCUP_DEFAULT_SEND_COOKIE_INTERVAL;
+ }
+ }
+ else {
+ /* server chooses interval */
+ interval = LDAP_LCUP_DEFAULT_SEND_COOKIE_INTERVAL;
+ }
+
+ if ( (tag = ber_peek_tag( ber, &len )) == LBER_DEFAULT ) {
+ *text = "LCUP client update control : decoding error";
+ return LDAP_PROTOCOL_ERROR;
+ }
+
+ if ( tag == LDAP_TAG_COOKIE ) {
+ if ( (tag = ber_scanf( ber, /*{*/ "{mm}}",
+ &scheme, &cookie )) == LBER_ERROR ) {
+ *text = "LCUP client update control : decoding error";
+ return LDAP_PROTOCOL_ERROR;
+ }
+ }
+
+ /* TODO : Cookie Scheme Validation */
+#if 0
+ if ( lcup_cookie_validate(scheme, cookie) != LDAP_SUCCESS ) {
+ *text = "Invalid LCUP cookie";
+ return LCUP_INVALID_COOKIE;
+ }
+
+ if ( lcup_cookie_scheme_validate(scheme) != LDAP_SUCCESS ) {
+ *text = "Unsupported LCUP cookie scheme";
+ return LCUP_UNSUPPORTED_SCHEME;
+ }
+#endif
+
+ op->o_clientupdatestate = ber_dupbv(NULL, &cookie);
+
+ (void) ber_free( ber, 1 );
+
+ op->o_clientupdatetype = type;
+ op->o_clientupdateinterval = interval;
+
+ op->o_clientupdate = ctrl->ldctl_iscritical
+ ? SLAP_CRITICAL_CONTROL
+ : SLAP_NONCRITICAL_CONTROL;
+
+ return LDAP_SUCCESS;
+}
+#endif
#define caseExactOrderingMatch caseExactMatch
#define integerOrderingMatch integerMatch
+#ifdef LDAP_CLIENT_UPDATE
+#define octetStringOrderingMatch octetStringMatch
+#endif /* LDAP_CLIENT_UPDATE */
+
/* unimplemented matching routines */
#define caseIgnoreListMatch NULL
#define caseIgnoreListSubstringsMatch NULL
octetStringMatch, octetStringIndexer, octetStringFilter,
NULL},
+#ifdef LDAP_CLIENT_UPDATE
+ {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
+ "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
+ SLAP_MR_ORDERING, NULL,
+ NULL, NULL,
+ octetStringOrderingMatch, NULL, NULL,
+ NULL},
+#endif /* LDAP_CLIENT_UPDATE */
+
{"( 2.5.13.20 NAME 'telephoneNumberMatch' "
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_DN_FOLD, NULL,
{ "entryCSN", "( 1.3.6.1.4.1.4203.666.1.7 NAME 'entryCSN' "
"DESC 'LCUP/LDUP: change sequence number' "
"EQUALITY octetStringMatch "
+#ifdef LDAP_CLIENT_UPDATE
+ "ORDERING octetStringOrderingMatch "
+#endif /* LDAP_CLIENT_UPDATE */
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.40{64} "
"SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )",
NULL, SLAP_AT_HIDE,
ber_int_t o_pagedresults_size;
PagedResultsState o_pagedresults_state;
+#ifdef LDAP_CLIENT_UPDATE
+ char o_clientupdate;
+ ber_int_t o_clientupdatetype;
+ ber_int_t o_clientupdateinterval;
+ struct berval* o_clientupdatestate;
+#endif
+
#ifdef LDAP_CONNECTIONLESS
Sockaddr o_peeraddr; /* UDP peer address */
#endif