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