1 /* ldapsync.c -- LDAP Content Sync Routines */ 2 /* $OpenLDAP: pkg/ldap/servers/slapd/ldapsync.c,v 1.32.2.7 2008/02/11 23:26:44 kurt Exp $ */ 3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 2003-2008 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 34 slap_compose_sync_cookie( 35 Operation *op, 36 struct berval *cookie, 37 BerVarray csn, 38 int rid, 39 int sid ) 40 { 41 int len, numcsn = 0; 42 43 if ( csn ) { 44 for (; !BER_BVISNULL( &csn[numcsn] ); numcsn++); 45 } 46 47 if ( numcsn == 0 || rid == -1 ) { 48 char cookiestr[ LDAP_LUTIL_CSNSTR_BUFSIZE + 20 ]; 49 if ( rid == -1 ) { 50 cookiestr[0] = '\0'; 51 len = 0; 52 } else { 53 len = snprintf( cookiestr, sizeof( cookiestr ), 54 "rid=%03d", rid ); 55 if ( sid >= 0 ) { 56 len += sprintf( cookiestr+len, ",sid=%03x", sid ); 57 } 58 } 59 ber_str2bv_x( cookiestr, len, 1, cookie, 60 op ? op->o_tmpmemctx : NULL ); 61 } else { 62 char *ptr; 63 int i; 64 65 len = 0; 66 for ( i=0; i<numcsn; i++) 67 len += csn[i].bv_len + 1; 68 69 len += STRLENOF("rid=123,csn="); 70 if ( sid >= 0 ) 71 len += STRLENOF("sid=xxx,"); 72 73 cookie->bv_val = slap_sl_malloc( len, op ? op->o_tmpmemctx : NULL ); 74 75 len = sprintf( cookie->bv_val, "rid=%03d,", rid ); 76 ptr = cookie->bv_val + len; 77 if ( sid >= 0 ) { 78 ptr += sprintf( ptr, "sid=%03x,", sid ); 79 } 80 ptr = lutil_strcopy( ptr, "csn=" ); 81 for ( i=0; i<numcsn; i++) { 82 ptr = lutil_strncopy( ptr, csn[i].bv_val, csn[i].bv_len ); 83 *ptr++ = ';'; 84 } 85 ptr--; 86 *ptr = '\0'; 87 cookie->bv_len = ptr - cookie->bv_val; 88 } 89 } 90 91 void 92 slap_sync_cookie_free( 93 struct sync_cookie *cookie, 94 int free_cookie 95 ) 96 { 97 if ( cookie == NULL ) 98 return; 99 100 if ( cookie->sids ) { 101 ch_free( cookie->sids ); 102 cookie->sids = NULL; 103 } 104 105 if ( cookie->ctxcsn ) { 106 ber_bvarray_free( cookie->ctxcsn ); 107 cookie->ctxcsn = NULL; 108 } 109 cookie->numcsns = 0; 110 if ( !BER_BVISNULL( &cookie->octet_str )) { 111 ch_free( cookie->octet_str.bv_val ); 112 BER_BVZERO( &cookie->octet_str ); 113 } 114 115 if ( free_cookie ) { 116 ch_free( cookie ); 117 } 118 119 return; 120 } 121 122 int 123 slap_parse_csn_sid( struct berval *csnp ) 124 { 125 char *p, *q; 126 struct berval csn = *csnp; 127 int i; 128 129 p = ber_bvchr( &csn, '#' ); 130 if ( !p ) 131 return -1; 132 p++; 133 csn.bv_len -= p - csn.bv_val; 134 csn.bv_val = p; 135 136 p = ber_bvchr( &csn, '#' ); 137 if ( !p ) 138 return -1; 139 p++; 140 csn.bv_len -= p - csn.bv_val; 141 csn.bv_val = p; 142 143 q = ber_bvchr( &csn, '#' ); 144 if ( !q ) 145 return -1; 146 147 csn.bv_len = q - p; 148 149 i = strtol( p, &q, 16 ); 150 if ( p == q || q != p + csn.bv_len || i < 0 || i > SLAP_SYNC_SID_MAX ) { 151 i = -1; 152 } 153 154 return i; 155 } 156 157 int * 158 slap_parse_csn_sids( BerVarray csns, int numcsns, void *memctx ) 159 { 160 int i, *ret; 161 162 ret = slap_sl_malloc( numcsns * sizeof(int), memctx ); 163 for ( i=0; i<numcsns; i++ ) { 164 ret[i] = slap_parse_csn_sid( &csns[i] ); 165 } 166 return ret; 167 } 168 169 int 170 slap_parse_sync_cookie( 171 struct sync_cookie *cookie, 172 void *memctx 173 ) 174 { 175 char *csn_ptr; 176 char *csn_str; 177 char *cval; 178 char *next, *end; 179 AttributeDescription *ad = slap_schema.si_ad_modifyTimestamp; 180 181 if ( cookie == NULL ) 182 return -1; 183 184 if ( cookie->octet_str.bv_len <= STRLENOF( "rid=" ) ) 185 return -1; 186 187 cookie->rid = -1; 188 cookie->sid = -1; 189 cookie->ctxcsn = NULL; 190 cookie->sids = NULL; 191 cookie->numcsns = 0; 192 193 end = cookie->octet_str.bv_val + cookie->octet_str.bv_len; 194 195 for ( next=cookie->octet_str.bv_val; next < end; ) { 196 if ( !strncmp( next, "rid=", STRLENOF("rid=") )) { 197 char *rid_ptr = next; 198 cookie->rid = strtol( &rid_ptr[ STRLENOF( "rid=" ) ], &next, 10 ); 199 if ( next == rid_ptr || 200 next > end || 201 ( *next && *next != ',' ) || 202 cookie->rid < 0 || 203 cookie->rid > SLAP_SYNC_RID_MAX ) 204 { 205 return -1; 206 } 207 if ( *next == ',' ) { 208 next++; 209 } 210 if ( !ad ) { 211 break; 212 } 213 continue; 214 } 215 if ( !strncmp( next, "sid=", STRLENOF("sid=") )) { 216 char *sid_ptr = next; 217 sid_ptr = next; 218 cookie->sid = strtol( &sid_ptr[ STRLENOF( "sid=" ) ], &next, 16 ); 219 if ( next == sid_ptr || 220 next > end || 221 ( *next && *next != ',' ) || 222 cookie->sid < 0 || 223 cookie->sid > SLAP_SYNC_SID_MAX ) 224 { 225 return -1; 226 } 227 if ( *next == ',' ) { 228 next++; 229 } 230 continue; 231 } 232 if ( !strncmp( next, "csn=", STRLENOF("csn=") )) { 233 slap_syntax_validate_func *validate; 234 struct berval stamp; 235 236 next += STRLENOF("csn="); 237 while ( next < end ) { 238 csn_str = next; 239 /* FIXME use csnValidate when it gets implemented */ 240 csn_ptr = strchr( csn_str, '#' ); 241 if ( !csn_ptr || csn_ptr > end ) 242 break; 243 /* ad will be NULL when called from main. we just 244 * want to parse the rid then. But we still iterate 245 * through the string to find the end. 246 */ 247 if ( ad ) { 248 stamp.bv_val = csn_str; 249 stamp.bv_len = csn_ptr - csn_str; 250 validate = ad->ad_type->sat_syntax->ssyn_validate; 251 if ( validate( ad->ad_type->sat_syntax, &stamp ) 252 != LDAP_SUCCESS ) 253 break; 254 } 255 cval = strchr( csn_ptr, ';' ); 256 if ( !cval ) 257 cval = strchr(csn_ptr, ',' ); 258 if ( cval ) 259 stamp.bv_len = cval - csn_str; 260 else 261 stamp.bv_len = end - csn_str; 262 if ( ad ) { 263 struct berval bv; 264 ber_dupbv_x( &bv, &stamp, memctx ); 265 ber_bvarray_add_x( &cookie->ctxcsn, &bv, memctx ); 266 cookie->numcsns++; 267 } 268 if ( cval ) { 269 next = cval + 1; 270 if ( *cval != ';' ) 271 break; 272 } else { 273 next = end; 274 break; 275 } 276 } 277 continue; 278 } 279 next++; 280 } 281 if ( cookie->numcsns ) { 282 cookie->sids = slap_parse_csn_sids( cookie->ctxcsn, cookie->numcsns, 283 memctx ); 284 } 285 return 0; 286 } 287 288 int 289 slap_init_sync_cookie_ctxcsn( 290 struct sync_cookie *cookie 291 ) 292 { 293 char csnbuf[ LDAP_LUTIL_CSNSTR_BUFSIZE + 4 ]; 294 struct berval octet_str = BER_BVNULL; 295 struct berval ctxcsn = BER_BVNULL; 296 297 if ( cookie == NULL ) 298 return -1; 299 300 octet_str.bv_len = snprintf( csnbuf, LDAP_LUTIL_CSNSTR_BUFSIZE + 4, 301 "csn=%4d%02d%02d%02d%02d%02dZ#%06x#%02x#%06x", 302 1900, 1, 1, 0, 0, 0, 0, 0, 0 ); 303 octet_str.bv_val = csnbuf; 304 ch_free( cookie->octet_str.bv_val ); 305 ber_dupbv( &cookie->octet_str, &octet_str ); 306 307 ctxcsn.bv_val = octet_str.bv_val + 4; 308 ctxcsn.bv_len = octet_str.bv_len - 4; 309 cookie->ctxcsn = NULL; 310 value_add_one( &cookie->ctxcsn, &ctxcsn ); 311 cookie->numcsns = 1; 312 cookie->sid = -1; 313 314 return 0; 315 } 316 317 struct sync_cookie * 318 slap_dup_sync_cookie( 319 struct sync_cookie *dst, 320 struct sync_cookie *src 321 ) 322 { 323 struct sync_cookie *new; 324 int i; 325 326 if ( src == NULL ) 327 return NULL; 328 329 if ( dst ) { 330 ber_bvarray_free( dst->ctxcsn ); 331 dst->ctxcsn = NULL; 332 dst->sids = NULL; 333 ch_free( dst->octet_str.bv_val ); 334 BER_BVZERO( &dst->octet_str ); 335 new = dst; 336 } else { 337 new = ( struct sync_cookie * ) 338 ch_calloc( 1, sizeof( struct sync_cookie )); 339 } 340 341 new->rid = src->rid; 342 new->sid = src->sid; 343 new->numcsns = src->numcsns; 344 345 if ( src->numcsns ) { 346 if ( ber_bvarray_dup_x( &new->ctxcsn, src->ctxcsn, NULL )) { 347 if ( !dst ) { 348 ch_free( new ); 349 } 350 return NULL; 351 } 352 new->sids = ch_malloc( src->numcsns * sizeof(int) ); 353 for (i=0; i<src->numcsns; i++) 354 new->sids[i] = src->sids[i]; 355 } 356 357 if ( !BER_BVISNULL( &src->octet_str )) { 358 ber_dupbv( &new->octet_str, &src->octet_str ); 359 } 360 361 return new; 362 } 363 364