1 /* $NetBSD: ldapsync.c,v 1.1.1.4 2014/05/28 09:58:46 tron Exp $ */ 2 3 /* ldapsync.c -- LDAP Content Sync Routines */ 4 /* $OpenLDAP$ */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2003-2014 The OpenLDAP Foundation. 8 * Portions Copyright 2003 IBM Corporation. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted only as authorized by the OpenLDAP 13 * Public License. 14 * 15 * A copy of this license is available in the file LICENSE in the 16 * top-level directory of the distribution or, alternatively, at 17 * <http://www.OpenLDAP.org/license.html>. 18 */ 19 20 #include "portable.h" 21 22 #include <stdio.h> 23 24 #include <ac/string.h> 25 #include <ac/socket.h> 26 27 #include "lutil.h" 28 #include "slap.h" 29 #include "../../libraries/liblber/lber-int.h" /* get ber_strndup() */ 30 #include "lutil_ldap.h" 31 32 struct slap_sync_cookie_s slap_sync_cookie = 33 LDAP_STAILQ_HEAD_INITIALIZER( slap_sync_cookie ); 34 35 void 36 slap_compose_sync_cookie( 37 Operation *op, 38 struct berval *cookie, 39 BerVarray csn, 40 int rid, 41 int sid ) 42 { 43 int len, numcsn = 0; 44 45 if ( csn ) { 46 for (; !BER_BVISNULL( &csn[numcsn] ); numcsn++); 47 } 48 49 if ( numcsn == 0 || rid == -1 ) { 50 char cookiestr[ LDAP_PVT_CSNSTR_BUFSIZE + 20 ]; 51 if ( rid == -1 ) { 52 cookiestr[0] = '\0'; 53 len = 0; 54 } else { 55 len = snprintf( cookiestr, sizeof( cookiestr ), 56 "rid=%03d", rid ); 57 if ( sid >= 0 ) { 58 len += sprintf( cookiestr+len, ",sid=%03x", sid ); 59 } 60 } 61 ber_str2bv_x( cookiestr, len, 1, cookie, 62 op ? op->o_tmpmemctx : NULL ); 63 } else { 64 char *ptr; 65 int i; 66 67 len = 0; 68 for ( i=0; i<numcsn; i++) 69 len += csn[i].bv_len + 1; 70 71 len += STRLENOF("rid=123,csn="); 72 if ( sid >= 0 ) 73 len += STRLENOF("sid=xxx,"); 74 75 cookie->bv_val = slap_sl_malloc( len, op ? op->o_tmpmemctx : NULL ); 76 77 len = sprintf( cookie->bv_val, "rid=%03d,", rid ); 78 ptr = cookie->bv_val + len; 79 if ( sid >= 0 ) { 80 ptr += sprintf( ptr, "sid=%03x,", sid ); 81 } 82 ptr = lutil_strcopy( ptr, "csn=" ); 83 for ( i=0; i<numcsn; i++) { 84 ptr = lutil_strncopy( ptr, csn[i].bv_val, csn[i].bv_len ); 85 *ptr++ = ';'; 86 } 87 ptr--; 88 *ptr = '\0'; 89 cookie->bv_len = ptr - cookie->bv_val; 90 } 91 } 92 93 void 94 slap_sync_cookie_free( 95 struct sync_cookie *cookie, 96 int free_cookie 97 ) 98 { 99 if ( cookie == NULL ) 100 return; 101 102 if ( cookie->sids ) { 103 ch_free( cookie->sids ); 104 cookie->sids = NULL; 105 } 106 107 if ( cookie->ctxcsn ) { 108 ber_bvarray_free( cookie->ctxcsn ); 109 cookie->ctxcsn = NULL; 110 } 111 cookie->numcsns = 0; 112 if ( !BER_BVISNULL( &cookie->octet_str )) { 113 ch_free( cookie->octet_str.bv_val ); 114 BER_BVZERO( &cookie->octet_str ); 115 } 116 117 if ( free_cookie ) { 118 ch_free( cookie ); 119 } 120 121 return; 122 } 123 124 int 125 slap_parse_csn_sid( struct berval *csnp ) 126 { 127 char *p, *q; 128 struct berval csn = *csnp; 129 int i; 130 131 p = ber_bvchr( &csn, '#' ); 132 if ( !p ) 133 return -1; 134 p++; 135 csn.bv_len -= p - csn.bv_val; 136 csn.bv_val = p; 137 138 p = ber_bvchr( &csn, '#' ); 139 if ( !p ) 140 return -1; 141 p++; 142 csn.bv_len -= p - csn.bv_val; 143 csn.bv_val = p; 144 145 q = ber_bvchr( &csn, '#' ); 146 if ( !q ) 147 return -1; 148 149 csn.bv_len = q - p; 150 151 i = strtol( p, &q, 16 ); 152 if ( p == q || q != p + csn.bv_len || i < 0 || i > SLAP_SYNC_SID_MAX ) { 153 i = -1; 154 } 155 156 return i; 157 } 158 159 int * 160 slap_parse_csn_sids( BerVarray csns, int numcsns, void *memctx ) 161 { 162 int i, *ret; 163 164 ret = slap_sl_malloc( numcsns * sizeof(int), memctx ); 165 for ( i=0; i<numcsns; i++ ) { 166 ret[i] = slap_parse_csn_sid( &csns[i] ); 167 } 168 return ret; 169 } 170 171 static slap_mr_match_func sidsort_cmp; 172 173 static const MatchingRule sidsort_mr = { 174 { 0 }, 175 NULL, 176 { 0 }, 177 { 0 }, 178 0, 179 NULL, NULL, NULL, sidsort_cmp 180 }; 181 static const AttributeType sidsort_at = { 182 { 0 }, 183 { 0 }, 184 NULL, NULL, (MatchingRule *)&sidsort_mr, 185 NULL, NULL, NULL, NULL, NULL, NULL, NULL, SLAP_AT_SORTED_VAL 186 }; 187 static const AttributeDescription sidsort_ad = { 188 NULL, 189 (AttributeType *)&sidsort_at 190 }; 191 192 static int 193 sidsort_cmp( 194 int *matchp, 195 slap_mask_t flags, 196 Syntax *syntax, 197 MatchingRule *mr, 198 struct berval *b1, 199 void *v2 ) 200 { 201 struct berval *b2 = v2; 202 *matchp = b1->bv_len - b2->bv_len; 203 return LDAP_SUCCESS; 204 } 205 206 /* sort CSNs by SID. Use a fake Attribute with our own 207 * syntax and matching rule, which sorts the nvals by 208 * bv_len order. Stuff our sids into the bv_len. 209 */ 210 int 211 slap_sort_csn_sids( BerVarray csns, int *sids, int numcsns, void *memctx ) 212 { 213 Attribute a; 214 const char *text; 215 int i, rc; 216 217 a.a_desc = (AttributeDescription *)&sidsort_ad; 218 a.a_nvals = slap_sl_malloc( numcsns * sizeof(struct berval), memctx ); 219 for ( i=0; i<numcsns; i++ ) { 220 a.a_nvals[i].bv_len = sids[i]; 221 a.a_nvals[i].bv_val = NULL; 222 } 223 a.a_vals = csns; 224 a.a_numvals = numcsns; 225 a.a_flags = 0; 226 rc = slap_sort_vals( (Modifications *)&a, &text, &i, memctx ); 227 for ( i=0; i<numcsns; i++ ) 228 sids[i] = a.a_nvals[i].bv_len; 229 slap_sl_free( a.a_nvals, memctx ); 230 return rc; 231 } 232 233 void 234 slap_insert_csn_sids( 235 struct sync_cookie *ck, 236 int pos, 237 int sid, 238 struct berval *csn 239 ) 240 { 241 int i; 242 ck->numcsns++; 243 ck->ctxcsn = ch_realloc( ck->ctxcsn, 244 (ck->numcsns+1) * sizeof(struct berval)); 245 BER_BVZERO( &ck->ctxcsn[ck->numcsns] ); 246 ck->sids = ch_realloc( ck->sids, ck->numcsns * sizeof(int)); 247 for ( i = ck->numcsns-1; i > pos; i-- ) { 248 ck->ctxcsn[i] = ck->ctxcsn[i-1]; 249 ck->sids[i] = ck->sids[i-1]; 250 } 251 ck->sids[i] = sid; 252 ber_dupbv( &ck->ctxcsn[i], csn ); 253 } 254 255 int 256 slap_parse_sync_cookie( 257 struct sync_cookie *cookie, 258 void *memctx 259 ) 260 { 261 char *csn_ptr; 262 char *csn_str; 263 char *cval; 264 char *next, *end; 265 AttributeDescription *ad = slap_schema.si_ad_entryCSN; 266 267 if ( cookie == NULL ) 268 return -1; 269 270 if ( cookie->octet_str.bv_len <= STRLENOF( "rid=" ) ) 271 return -1; 272 273 cookie->rid = -1; 274 cookie->sid = -1; 275 cookie->ctxcsn = NULL; 276 cookie->sids = NULL; 277 cookie->numcsns = 0; 278 279 end = cookie->octet_str.bv_val + cookie->octet_str.bv_len; 280 281 for ( next=cookie->octet_str.bv_val; next < end; ) { 282 if ( !strncmp( next, "rid=", STRLENOF("rid=") )) { 283 char *rid_ptr = next; 284 cookie->rid = strtol( &rid_ptr[ STRLENOF( "rid=" ) ], &next, 10 ); 285 if ( next == rid_ptr || 286 next > end || 287 ( *next && *next != ',' ) || 288 cookie->rid < 0 || 289 cookie->rid > SLAP_SYNC_RID_MAX ) 290 { 291 return -1; 292 } 293 if ( *next == ',' ) { 294 next++; 295 } 296 if ( !ad ) { 297 break; 298 } 299 continue; 300 } 301 if ( !strncmp( next, "sid=", STRLENOF("sid=") )) { 302 char *sid_ptr = next; 303 sid_ptr = next; 304 cookie->sid = strtol( &sid_ptr[ STRLENOF( "sid=" ) ], &next, 16 ); 305 if ( next == sid_ptr || 306 next > end || 307 ( *next && *next != ',' ) || 308 cookie->sid < 0 || 309 cookie->sid > SLAP_SYNC_SID_MAX ) 310 { 311 return -1; 312 } 313 if ( *next == ',' ) { 314 next++; 315 } 316 continue; 317 } 318 if ( !strncmp( next, "csn=", STRLENOF("csn=") )) { 319 struct berval stamp; 320 321 next += STRLENOF("csn="); 322 while ( next < end ) { 323 csn_str = next; 324 csn_ptr = strchr( csn_str, '#' ); 325 if ( !csn_ptr || csn_ptr > end ) 326 break; 327 /* ad will be NULL when called from main. we just 328 * want to parse the rid then. But we still iterate 329 * through the string to find the end. 330 */ 331 cval = strchr( csn_ptr, ';' ); 332 if ( !cval ) 333 cval = strchr(csn_ptr, ',' ); 334 if ( cval ) 335 stamp.bv_len = cval - csn_str; 336 else 337 stamp.bv_len = end - csn_str; 338 if ( ad ) { 339 struct berval bv; 340 stamp.bv_val = csn_str; 341 if ( ad->ad_type->sat_syntax->ssyn_validate( 342 ad->ad_type->sat_syntax, &stamp ) != LDAP_SUCCESS ) 343 break; 344 if ( ad->ad_type->sat_equality->smr_normalize( 345 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, 346 ad->ad_type->sat_syntax, 347 ad->ad_type->sat_equality, 348 &stamp, &bv, memctx ) != LDAP_SUCCESS ) 349 break; 350 ber_bvarray_add_x( &cookie->ctxcsn, &bv, memctx ); 351 cookie->numcsns++; 352 } 353 if ( cval ) { 354 next = cval + 1; 355 if ( *cval != ';' ) 356 break; 357 } else { 358 next = end; 359 break; 360 } 361 } 362 continue; 363 } 364 next++; 365 } 366 if ( cookie->numcsns ) { 367 cookie->sids = slap_parse_csn_sids( cookie->ctxcsn, cookie->numcsns, 368 memctx ); 369 if ( cookie->numcsns > 1 ) 370 slap_sort_csn_sids( cookie->ctxcsn, cookie->sids, cookie->numcsns, memctx ); 371 } 372 return 0; 373 } 374 375 /* count the numcsns and regenerate the list of SIDs in a recomposed cookie */ 376 void 377 slap_reparse_sync_cookie( 378 struct sync_cookie *cookie, 379 void *memctx ) 380 { 381 if ( cookie->ctxcsn ) { 382 for (; !BER_BVISNULL( &cookie->ctxcsn[cookie->numcsns] ); cookie->numcsns++); 383 } 384 if ( cookie->numcsns ) { 385 cookie->sids = slap_parse_csn_sids( cookie->ctxcsn, cookie->numcsns, NULL ); 386 if ( cookie->numcsns > 1 ) 387 slap_sort_csn_sids( cookie->ctxcsn, cookie->sids, cookie->numcsns, memctx ); 388 } 389 } 390 391 int 392 slap_init_sync_cookie_ctxcsn( 393 struct sync_cookie *cookie 394 ) 395 { 396 char csnbuf[ LDAP_PVT_CSNSTR_BUFSIZE + 4 ]; 397 struct berval octet_str = BER_BVNULL; 398 struct berval ctxcsn = BER_BVNULL; 399 400 if ( cookie == NULL ) 401 return -1; 402 403 octet_str.bv_len = snprintf( csnbuf, LDAP_PVT_CSNSTR_BUFSIZE + 4, 404 "csn=%4d%02d%02d%02d%02d%02dZ#%06x#%02x#%06x", 405 1900, 1, 1, 0, 0, 0, 0, 0, 0 ); 406 octet_str.bv_val = csnbuf; 407 ch_free( cookie->octet_str.bv_val ); 408 ber_dupbv( &cookie->octet_str, &octet_str ); 409 410 ctxcsn.bv_val = octet_str.bv_val + 4; 411 ctxcsn.bv_len = octet_str.bv_len - 4; 412 cookie->ctxcsn = NULL; 413 value_add_one( &cookie->ctxcsn, &ctxcsn ); 414 cookie->numcsns = 1; 415 cookie->sid = -1; 416 417 return 0; 418 } 419 420 struct sync_cookie * 421 slap_dup_sync_cookie( 422 struct sync_cookie *dst, 423 struct sync_cookie *src 424 ) 425 { 426 struct sync_cookie *new; 427 int i; 428 429 if ( src == NULL ) 430 return NULL; 431 432 if ( dst ) { 433 ber_bvarray_free( dst->ctxcsn ); 434 dst->ctxcsn = NULL; 435 dst->sids = NULL; 436 ch_free( dst->octet_str.bv_val ); 437 BER_BVZERO( &dst->octet_str ); 438 new = dst; 439 } else { 440 new = ( struct sync_cookie * ) 441 ch_calloc( 1, sizeof( struct sync_cookie )); 442 } 443 444 new->rid = src->rid; 445 new->sid = src->sid; 446 new->numcsns = src->numcsns; 447 448 if ( src->numcsns ) { 449 if ( ber_bvarray_dup_x( &new->ctxcsn, src->ctxcsn, NULL )) { 450 if ( !dst ) { 451 ch_free( new ); 452 } 453 return NULL; 454 } 455 new->sids = ch_malloc( src->numcsns * sizeof(int) ); 456 for (i=0; i<src->numcsns; i++) 457 new->sids[i] = src->sids[i]; 458 } 459 460 if ( !BER_BVISNULL( &src->octet_str )) { 461 ber_dupbv( &new->octet_str, &src->octet_str ); 462 } 463 464 return new; 465 } 466 467