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