Back to index

openldap  2.4.31
ldapsync.c
Go to the documentation of this file.
00001 /* ldapsync.c -- LDAP Content Sync Routines */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 2003-2012 The OpenLDAP Foundation.
00006  * Portions Copyright 2003 IBM Corporation.
00007  * All rights reserved.
00008  *
00009  * Redistribution and use in source and binary forms, with or without
00010  * modification, are permitted only as authorized by the OpenLDAP
00011  * Public License.
00012  *
00013  * A copy of this license is available in the file LICENSE in the
00014  * top-level directory of the distribution or, alternatively, at
00015  * <http://www.OpenLDAP.org/license.html>.
00016  */
00017 
00018 #include "portable.h"
00019 
00020 #include <stdio.h>
00021 
00022 #include <ac/string.h>
00023 #include <ac/socket.h>
00024 
00025 #include "lutil.h"
00026 #include "slap.h"
00027 #include "../../libraries/liblber/lber-int.h" /* get ber_strndup() */
00028 #include "lutil_ldap.h"
00029 
00030 struct slap_sync_cookie_s slap_sync_cookie =
00031        LDAP_STAILQ_HEAD_INITIALIZER( slap_sync_cookie );
00032 
00033 void
00034 slap_compose_sync_cookie(
00035        Operation *op,
00036        struct berval *cookie,
00037        BerVarray csn,
00038        int rid,
00039        int sid )
00040 {
00041        int len, numcsn = 0;
00042 
00043        if ( csn ) {
00044               for (; !BER_BVISNULL( &csn[numcsn] ); numcsn++);
00045        }
00046 
00047        if ( numcsn == 0 || rid == -1 ) {
00048               char cookiestr[ LDAP_PVT_CSNSTR_BUFSIZE + 20 ];
00049               if ( rid == -1 ) {
00050                      cookiestr[0] = '\0';
00051                      len = 0;
00052               } else {
00053                      len = snprintf( cookiestr, sizeof( cookiestr ),
00054                                    "rid=%03d", rid );
00055                      if ( sid >= 0 ) {
00056                             len += sprintf( cookiestr+len, ",sid=%03x", sid );
00057                      }
00058               }
00059               ber_str2bv_x( cookiestr, len, 1, cookie, 
00060                      op ? op->o_tmpmemctx : NULL );
00061        } else {
00062               char *ptr;
00063               int i;
00064 
00065               len = 0;
00066               for ( i=0; i<numcsn; i++)
00067                      len += csn[i].bv_len + 1;
00068 
00069               len += STRLENOF("rid=123,csn=");
00070               if ( sid >= 0 )
00071                      len += STRLENOF("sid=xxx,");
00072 
00073               cookie->bv_val = slap_sl_malloc( len, op ? op->o_tmpmemctx : NULL );
00074 
00075               len = sprintf( cookie->bv_val, "rid=%03d,", rid );
00076               ptr = cookie->bv_val + len;
00077               if ( sid >= 0 ) {
00078                      ptr += sprintf( ptr, "sid=%03x,", sid );
00079               }
00080               ptr = lutil_strcopy( ptr, "csn=" );
00081               for ( i=0; i<numcsn; i++) {
00082                      ptr = lutil_strncopy( ptr, csn[i].bv_val, csn[i].bv_len );
00083                      *ptr++ = ';';
00084               }
00085               ptr--;
00086               *ptr = '\0';
00087               cookie->bv_len = ptr - cookie->bv_val;
00088        }
00089 }
00090 
00091 void
00092 slap_sync_cookie_free(
00093        struct sync_cookie *cookie,
00094        int free_cookie
00095 )
00096 {
00097        if ( cookie == NULL )
00098               return;
00099 
00100        if ( cookie->sids ) {
00101               ch_free( cookie->sids );
00102               cookie->sids = NULL;
00103        }
00104 
00105        if ( cookie->ctxcsn ) {
00106               ber_bvarray_free( cookie->ctxcsn );
00107               cookie->ctxcsn = NULL;
00108        }
00109        cookie->numcsns = 0;
00110        if ( !BER_BVISNULL( &cookie->octet_str )) {
00111               ch_free( cookie->octet_str.bv_val );
00112               BER_BVZERO( &cookie->octet_str );
00113        }
00114 
00115        if ( free_cookie ) {
00116               ch_free( cookie );
00117        }
00118 
00119        return;
00120 }
00121 
00122 int
00123 slap_parse_csn_sid( struct berval *csnp )
00124 {
00125        char *p, *q;
00126        struct berval csn = *csnp;
00127        int i;
00128 
00129        p = ber_bvchr( &csn, '#' );
00130        if ( !p )
00131               return -1;
00132        p++;
00133        csn.bv_len -= p - csn.bv_val;
00134        csn.bv_val = p;
00135 
00136        p = ber_bvchr( &csn, '#' );
00137        if ( !p )
00138               return -1;
00139        p++;
00140        csn.bv_len -= p - csn.bv_val;
00141        csn.bv_val = p;
00142 
00143        q = ber_bvchr( &csn, '#' );
00144        if ( !q )
00145               return -1;
00146 
00147        csn.bv_len = q - p;
00148 
00149        i = strtol( p, &q, 16 );
00150        if ( p == q || q != p + csn.bv_len || i < 0 || i > SLAP_SYNC_SID_MAX ) {
00151               i = -1;
00152        }
00153 
00154        return i;
00155 }
00156 
00157 int *
00158 slap_parse_csn_sids( BerVarray csns, int numcsns, void *memctx )
00159 {
00160        int i, *ret;
00161 
00162        ret = slap_sl_malloc( numcsns * sizeof(int), memctx );
00163        for ( i=0; i<numcsns; i++ ) {
00164               ret[i] = slap_parse_csn_sid( &csns[i] );
00165        }
00166        return ret;
00167 }
00168 
00169 static slap_mr_match_func sidsort_cmp;
00170 
00171 static const MatchingRule sidsort_mr = {
00172        { 0 },
00173        NULL,
00174        { 0 },
00175        { 0 },
00176        0,
00177        NULL, NULL, NULL, sidsort_cmp
00178 };
00179 static const AttributeType sidsort_at = {
00180        { 0 },
00181        { 0 },
00182        NULL, NULL, (MatchingRule *)&sidsort_mr,
00183        NULL, NULL, NULL, NULL, NULL, NULL, NULL, SLAP_AT_SORTED_VAL
00184 };
00185 static const AttributeDescription sidsort_ad = {
00186        NULL,
00187        (AttributeType *)&sidsort_at
00188 };
00189 
00190 static int
00191 sidsort_cmp(
00192        int *matchp,
00193        slap_mask_t flags,
00194        Syntax *syntax,
00195        MatchingRule *mr,
00196        struct berval *b1,
00197        void *v2 )
00198 {
00199        struct berval *b2 = v2;
00200        *matchp = b1->bv_len - b2->bv_len;
00201        return LDAP_SUCCESS;
00202 }
00203 
00204 /* sort CSNs by SID. Use a fake Attribute with our own
00205  * syntax and matching rule, which sorts the nvals by
00206  * bv_len order. Stuff our sids into the bv_len.
00207  */
00208 int
00209 slap_sort_csn_sids( BerVarray csns, int *sids, int numcsns, void *memctx )
00210 {
00211        Attribute a;
00212        const char *text;
00213        int i, rc;
00214 
00215        a.a_desc = (AttributeDescription *)&sidsort_ad;
00216        a.a_nvals = slap_sl_malloc( numcsns * sizeof(struct berval), memctx );
00217        for ( i=0; i<numcsns; i++ ) {
00218               a.a_nvals[i].bv_len = sids[i];
00219               a.a_nvals[i].bv_val = NULL;
00220        }
00221        a.a_vals = csns;
00222        a.a_numvals = numcsns;
00223        a.a_flags = 0;
00224        rc = slap_sort_vals( (Modifications *)&a, &text, &i, memctx );
00225        for ( i=0; i<numcsns; i++ )
00226               sids[i] = a.a_nvals[i].bv_len;
00227        slap_sl_free( a.a_nvals, memctx );
00228        return rc;
00229 }
00230 
00231 void
00232 slap_insert_csn_sids(
00233        struct sync_cookie *ck,
00234        int pos,
00235        int sid,
00236        struct berval *csn
00237 )
00238 {
00239        int i;
00240        ck->numcsns++;
00241        ck->ctxcsn = ch_realloc( ck->ctxcsn,
00242               (ck->numcsns+1) * sizeof(struct berval));
00243        BER_BVZERO( &ck->ctxcsn[ck->numcsns] );
00244        ck->sids = ch_realloc( ck->sids, ck->numcsns * sizeof(int));
00245        for ( i = ck->numcsns-1; i > pos; i-- ) {
00246               ck->ctxcsn[i] = ck->ctxcsn[i-1];
00247               ck->sids[i] = ck->sids[i-1];
00248        }
00249        ck->sids[i] = sid;
00250        ber_dupbv( &ck->ctxcsn[i], csn );
00251 }
00252 
00253 int
00254 slap_parse_sync_cookie(
00255        struct sync_cookie *cookie,
00256        void *memctx
00257 )
00258 {
00259        char *csn_ptr;
00260        char *csn_str;
00261        char *cval;
00262        char *next, *end;
00263        AttributeDescription *ad = slap_schema.si_ad_entryCSN;
00264 
00265        if ( cookie == NULL )
00266               return -1;
00267 
00268        if ( cookie->octet_str.bv_len <= STRLENOF( "rid=" ) )
00269               return -1;
00270 
00271        cookie->rid = -1;
00272        cookie->sid = -1;
00273        cookie->ctxcsn = NULL;
00274        cookie->sids = NULL;
00275        cookie->numcsns = 0;
00276 
00277        end = cookie->octet_str.bv_val + cookie->octet_str.bv_len;
00278 
00279        for ( next=cookie->octet_str.bv_val; next < end; ) {
00280               if ( !strncmp( next, "rid=", STRLENOF("rid=") )) {
00281                      char *rid_ptr = next;
00282                      cookie->rid = strtol( &rid_ptr[ STRLENOF( "rid=" ) ], &next, 10 );
00283                      if ( next == rid_ptr ||
00284                             next > end ||
00285                             ( *next && *next != ',' ) ||
00286                             cookie->rid < 0 ||
00287                             cookie->rid > SLAP_SYNC_RID_MAX )
00288                      {
00289                             return -1;
00290                      }
00291                      if ( *next == ',' ) {
00292                             next++;
00293                      }
00294                      if ( !ad ) {
00295                             break;
00296                      }
00297                      continue;
00298               }
00299               if ( !strncmp( next, "sid=", STRLENOF("sid=") )) {
00300                      char *sid_ptr = next;
00301                      sid_ptr = next;
00302                      cookie->sid = strtol( &sid_ptr[ STRLENOF( "sid=" ) ], &next, 16 );
00303                      if ( next == sid_ptr ||
00304                             next > end ||
00305                             ( *next && *next != ',' ) ||
00306                             cookie->sid < 0 ||
00307                             cookie->sid > SLAP_SYNC_SID_MAX )
00308                      {
00309                             return -1;
00310                      }
00311                      if ( *next == ',' ) {
00312                             next++;
00313                      }
00314                      continue;
00315               }
00316               if ( !strncmp( next, "csn=", STRLENOF("csn=") )) {
00317                      struct berval stamp;
00318 
00319                      next += STRLENOF("csn=");
00320                      while ( next < end ) {
00321                             csn_str = next;
00322                             csn_ptr = strchr( csn_str, '#' );
00323                             if ( !csn_ptr || csn_ptr > end )
00324                                    break;
00325                             /* ad will be NULL when called from main. we just
00326                              * want to parse the rid then. But we still iterate
00327                              * through the string to find the end.
00328                              */
00329                             cval = strchr( csn_ptr, ';' );
00330                             if ( !cval )
00331                                    cval = strchr(csn_ptr, ',' );
00332                             if ( cval )
00333                                    stamp.bv_len = cval - csn_str;
00334                             else
00335                                    stamp.bv_len = end - csn_str;
00336                             if ( ad ) {
00337                                    struct berval bv;
00338                                    stamp.bv_val = csn_str;
00339                                    if ( ad->ad_type->sat_syntax->ssyn_validate(
00340                                           ad->ad_type->sat_syntax, &stamp ) != LDAP_SUCCESS )
00341                                           break;
00342                                    if ( ad->ad_type->sat_equality->smr_normalize(
00343                                           SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
00344                                           ad->ad_type->sat_syntax,
00345                                           ad->ad_type->sat_equality,
00346                                           &stamp, &bv, memctx ) != LDAP_SUCCESS )
00347                                           break;
00348                                    ber_bvarray_add_x( &cookie->ctxcsn, &bv, memctx );
00349                                    cookie->numcsns++;
00350                             }
00351                             if ( cval ) {
00352                                    next = cval + 1;
00353                                    if ( *cval != ';' )
00354                                           break;
00355                             } else {
00356                                    next = end;
00357                                    break;
00358                             }
00359                      }
00360                      continue;
00361               }
00362               next++;
00363        }
00364        if ( cookie->numcsns ) {
00365               cookie->sids = slap_parse_csn_sids( cookie->ctxcsn, cookie->numcsns,
00366                      memctx );
00367               if ( cookie->numcsns > 1 )
00368                      slap_sort_csn_sids( cookie->ctxcsn, cookie->sids, cookie->numcsns, memctx );
00369        }
00370        return 0;
00371 }
00372 
00373 int
00374 slap_init_sync_cookie_ctxcsn(
00375        struct sync_cookie *cookie
00376 )
00377 {
00378        char csnbuf[ LDAP_PVT_CSNSTR_BUFSIZE + 4 ];
00379        struct berval octet_str = BER_BVNULL;
00380        struct berval ctxcsn = BER_BVNULL;
00381 
00382        if ( cookie == NULL )
00383               return -1;
00384 
00385        octet_str.bv_len = snprintf( csnbuf, LDAP_PVT_CSNSTR_BUFSIZE + 4,
00386                                    "csn=%4d%02d%02d%02d%02d%02dZ#%06x#%02x#%06x",
00387                                    1900, 1, 1, 0, 0, 0, 0, 0, 0 );
00388        octet_str.bv_val = csnbuf;
00389        ch_free( cookie->octet_str.bv_val );
00390        ber_dupbv( &cookie->octet_str, &octet_str );
00391 
00392        ctxcsn.bv_val = octet_str.bv_val + 4;
00393        ctxcsn.bv_len = octet_str.bv_len - 4;
00394        cookie->ctxcsn = NULL;
00395        value_add_one( &cookie->ctxcsn, &ctxcsn );
00396        cookie->numcsns = 1;
00397        cookie->sid = -1;
00398 
00399        return 0;
00400 }
00401 
00402 struct sync_cookie *
00403 slap_dup_sync_cookie(
00404        struct sync_cookie *dst,
00405        struct sync_cookie *src
00406 )
00407 {
00408        struct sync_cookie *new;
00409        int i;
00410 
00411        if ( src == NULL )
00412               return NULL;
00413 
00414        if ( dst ) {
00415               ber_bvarray_free( dst->ctxcsn );
00416               dst->ctxcsn = NULL;
00417               dst->sids = NULL;
00418               ch_free( dst->octet_str.bv_val );
00419               BER_BVZERO( &dst->octet_str );
00420               new = dst;
00421        } else {
00422               new = ( struct sync_cookie * )
00423                             ch_calloc( 1, sizeof( struct sync_cookie ));
00424        }
00425 
00426        new->rid = src->rid;
00427        new->sid = src->sid;
00428        new->numcsns = src->numcsns;
00429 
00430        if ( src->numcsns ) {
00431               if ( ber_bvarray_dup_x( &new->ctxcsn, src->ctxcsn, NULL )) {
00432                      if ( !dst ) {
00433                             ch_free( new );
00434                      }
00435                      return NULL;
00436               }
00437               new->sids = ch_malloc( src->numcsns * sizeof(int) );
00438               for (i=0; i<src->numcsns; i++)
00439                      new->sids[i] = src->sids[i];
00440        }
00441 
00442        if ( !BER_BVISNULL( &src->octet_str )) {
00443               ber_dupbv( &new->octet_str, &src->octet_str );
00444        }
00445 
00446        return new;
00447 }
00448