From 4b48c05a8e1b9ed776a4bee10ee91986941105de Mon Sep 17 00:00:00 2001 From: Jong Hyuk Choi Date: Wed, 4 Sep 2002 02:00:42 +0000 Subject: [PATCH] LDAP Client Update Protocol - non-persistent update (TODO: response control ...) --- include/ldap.h | 39 ++++++++++ servers/slapd/back-bdb/search.c | 47 ++++++++++++ servers/slapd/controls.c | 129 ++++++++++++++++++++++++++++++++ servers/slapd/schema_init.c | 13 ++++ servers/slapd/schema_prep.c | 3 + servers/slapd/slap.h | 7 ++ 6 files changed, 238 insertions(+) diff --git a/include/ldap.h b/include/ldap.h index 0540f1ffc4..b976dc49f7 100644 --- a/include/ldap.h +++ b/include/ldap.h @@ -32,6 +32,9 @@ LDAP_BEGIN_DECL +#define LDAP_CLIENT_UPDATE 1 +#undef LDAP_CLIENT_UPDATE + #define LDAP_VERSION1 1 #define LDAP_VERSION2 2 #define LDAP_VERSION3 3 @@ -201,6 +204,12 @@ typedef struct ldapcontrol { #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" @@ -254,8 +263,18 @@ typedef struct ldapcontrol { /* 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 */ @@ -442,6 +461,26 @@ typedef struct ldapcontrol { #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, diff --git a/servers/slapd/back-bdb/search.c b/servers/slapd/back-bdb/search.c index 30abec8b25..6cdf1cd41b 100644 --- a/servers/slapd/back-bdb/search.c +++ b/servers/slapd/back-bdb/search.c @@ -56,6 +56,13 @@ bdb_search( 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; @@ -334,6 +341,34 @@ dn2entry_retry: 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 ) ) @@ -529,7 +564,17 @@ id2entry_retry: #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 ) { @@ -586,6 +631,7 @@ id2entry_retry: #endif result = send_search_entry( be, conn, op, e, attrs, attrsonly, NULL); + #if 0 } #endif @@ -633,6 +679,7 @@ loop_continue: ldap_pvt_thread_yield(); } + send_search_result( conn, op, v2refs == NULL ? LDAP_SUCCESS : LDAP_REFERRAL, NULL, NULL, v2refs, NULL, nentries ); diff --git a/servers/slapd/controls.c b/servers/slapd/controls.c index 3450172de7..d0da95c2bb 100644 --- a/servers/slapd/controls.c +++ b/servers/slapd/controls.c @@ -50,6 +50,10 @@ static SLAP_CTRL_PARSE_FN parseNoOp; 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 */ static struct slap_control { @@ -81,6 +85,11 @@ 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 } }; @@ -117,6 +126,10 @@ int get_ctrls( 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) { @@ -595,3 +608,119 @@ int parseValuesReturnFilter ( 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 diff --git a/servers/slapd/schema_init.c b/servers/slapd/schema_init.c index 173fabc1ba..af322982a3 100644 --- a/servers/slapd/schema_init.c +++ b/servers/slapd/schema_init.c @@ -60,6 +60,10 @@ #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 @@ -4631,6 +4635,15 @@ static slap_mrule_defs_rec mrule_defs[] = { 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, diff --git a/servers/slapd/schema_prep.c b/servers/slapd/schema_prep.c index 4ed8cc3054..b9bf64226e 100644 --- a/servers/slapd/schema_prep.c +++ b/servers/slapd/schema_prep.c @@ -450,6 +450,9 @@ static struct slap_schema_ad_map { { "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, diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index a672e1ea86..059cc66f5c 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -1585,6 +1585,13 @@ typedef struct slap_op { 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 -- 2.39.5