1 /* $NetBSD: ldapsync.c,v 1.1.1.3 2010/12/12 15:22:31 adam Exp $ */ 2 3 /* ldapsync.c -- LDAP Content Sync Routines */ 4 /* OpenLDAP: pkg/ldap/servers/slapd/ldapsync.c,v 1.32.2.13 2010/04/19 16:53:02 quanah Exp */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2003-2010 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 int 172 slap_parse_sync_cookie( 173 struct sync_cookie *cookie, 174 void *memctx 175 ) 176 { 177 char *csn_ptr; 178 char *csn_str; 179 char *cval; 180 char *next, *end; 181 AttributeDescription *ad = slap_schema.si_ad_entryCSN; 182 183 if ( cookie == NULL ) 184 return -1; 185 186 if ( cookie->octet_str.bv_len <= STRLENOF( "rid=" ) ) 187 return -1; 188 189 cookie->rid = -1; 190 cookie->sid = -1; 191 cookie->ctxcsn = NULL; 192 cookie->sids = NULL; 193 cookie->numcsns = 0; 194 195 end = cookie->octet_str.bv_val + cookie->octet_str.bv_len; 196 197 for ( next=cookie->octet_str.bv_val; next < end; ) { 198 if ( !strncmp( next, "rid=", STRLENOF("rid=") )) { 199 char *rid_ptr = next; 200 cookie->rid = strtol( &rid_ptr[ STRLENOF( "rid=" ) ], &next, 10 ); 201 if ( next == rid_ptr || 202 next > end || 203 ( *next && *next != ',' ) || 204 cookie->rid < 0 || 205 cookie->rid > SLAP_SYNC_RID_MAX ) 206 { 207 return -1; 208 } 209 if ( *next == ',' ) { 210 next++; 211 } 212 if ( !ad ) { 213 break; 214 } 215 continue; 216 } 217 if ( !strncmp( next, "sid=", STRLENOF("sid=") )) { 218 char *sid_ptr = next; 219 sid_ptr = next; 220 cookie->sid = strtol( &sid_ptr[ STRLENOF( "sid=" ) ], &next, 16 ); 221 if ( next == sid_ptr || 222 next > end || 223 ( *next && *next != ',' ) || 224 cookie->sid < 0 || 225 cookie->sid > SLAP_SYNC_SID_MAX ) 226 { 227 return -1; 228 } 229 if ( *next == ',' ) { 230 next++; 231 } 232 continue; 233 } 234 if ( !strncmp( next, "csn=", STRLENOF("csn=") )) { 235 struct berval stamp; 236 237 next += STRLENOF("csn="); 238 while ( next < end ) { 239 csn_str = next; 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 cval = strchr( csn_ptr, ';' ); 248 if ( !cval ) 249 cval = strchr(csn_ptr, ',' ); 250 if ( cval ) 251 stamp.bv_len = cval - csn_str; 252 else 253 stamp.bv_len = end - csn_str; 254 if ( ad ) { 255 struct berval bv; 256 stamp.bv_val = csn_str; 257 if ( ad->ad_type->sat_syntax->ssyn_validate( 258 ad->ad_type->sat_syntax, &stamp ) != LDAP_SUCCESS ) 259 break; 260 if ( ad->ad_type->sat_equality->smr_normalize( 261 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, 262 ad->ad_type->sat_syntax, 263 ad->ad_type->sat_equality, 264 &stamp, &bv, memctx ) != LDAP_SUCCESS ) 265 break; 266 ber_bvarray_add_x( &cookie->ctxcsn, &bv, memctx ); 267 cookie->numcsns++; 268 } 269 if ( cval ) { 270 next = cval + 1; 271 if ( *cval != ';' ) 272 break; 273 } else { 274 next = end; 275 break; 276 } 277 } 278 continue; 279 } 280 next++; 281 } 282 if ( cookie->numcsns ) { 283 cookie->sids = slap_parse_csn_sids( cookie->ctxcsn, cookie->numcsns, 284 memctx ); 285 } 286 return 0; 287 } 288 289 int 290 slap_init_sync_cookie_ctxcsn( 291 struct sync_cookie *cookie 292 ) 293 { 294 char csnbuf[ LDAP_PVT_CSNSTR_BUFSIZE + 4 ]; 295 struct berval octet_str = BER_BVNULL; 296 struct berval ctxcsn = BER_BVNULL; 297 298 if ( cookie == NULL ) 299 return -1; 300 301 octet_str.bv_len = snprintf( csnbuf, LDAP_PVT_CSNSTR_BUFSIZE + 4, 302 "csn=%4d%02d%02d%02d%02d%02dZ#%06x#%02x#%06x", 303 1900, 1, 1, 0, 0, 0, 0, 0, 0 ); 304 octet_str.bv_val = csnbuf; 305 ch_free( cookie->octet_str.bv_val ); 306 ber_dupbv( &cookie->octet_str, &octet_str ); 307 308 ctxcsn.bv_val = octet_str.bv_val + 4; 309 ctxcsn.bv_len = octet_str.bv_len - 4; 310 cookie->ctxcsn = NULL; 311 value_add_one( &cookie->ctxcsn, &ctxcsn ); 312 cookie->numcsns = 1; 313 cookie->sid = -1; 314 315 return 0; 316 } 317 318 struct sync_cookie * 319 slap_dup_sync_cookie( 320 struct sync_cookie *dst, 321 struct sync_cookie *src 322 ) 323 { 324 struct sync_cookie *new; 325 int i; 326 327 if ( src == NULL ) 328 return NULL; 329 330 if ( dst ) { 331 ber_bvarray_free( dst->ctxcsn ); 332 dst->ctxcsn = NULL; 333 dst->sids = NULL; 334 ch_free( dst->octet_str.bv_val ); 335 BER_BVZERO( &dst->octet_str ); 336 new = dst; 337 } else { 338 new = ( struct sync_cookie * ) 339 ch_calloc( 1, sizeof( struct sync_cookie )); 340 } 341 342 new->rid = src->rid; 343 new->sid = src->sid; 344 new->numcsns = src->numcsns; 345 346 if ( src->numcsns ) { 347 if ( ber_bvarray_dup_x( &new->ctxcsn, src->ctxcsn, NULL )) { 348 if ( !dst ) { 349 ch_free( new ); 350 } 351 return NULL; 352 } 353 new->sids = ch_malloc( src->numcsns * sizeof(int) ); 354 for (i=0; i<src->numcsns; i++) 355 new->sids[i] = src->sids[i]; 356 } 357 358 if ( !BER_BVISNULL( &src->octet_str )) { 359 ber_dupbv( &new->octet_str, &src->octet_str ); 360 } 361 362 return new; 363 } 364 365