1/* $OpenLDAP$ */ 2/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 3 * 4 * Copyright 1999-2011 The OpenLDAP Foundation. 5 * Portions Copyright 1999 Dmitry Kovalev. 6 * Portions Copyright 2002 Pierangelo Masarati. 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/* ACKNOWLEDGEMENTS: 18 * This work was initially developed by Dmitry Kovalev for inclusion 19 * by OpenLDAP Software. Additional significant contributors include 20 * Pierangelo Masarati. 21 */ 22 23#include "portable.h" 24 25#include <stdio.h> 26#include <sys/types.h> 27#include "ac/string.h" 28#include "ac/ctype.h" 29#include "ac/stdarg.h" 30 31#include "slap.h" 32#include "proto-sql.h" 33#include "lutil.h" 34 35#define BACKSQL_MAX(a,b) ((a)>(b)?(a):(b)) 36#define BACKSQL_MIN(a,b) ((a)<(b)?(a):(b)) 37 38#define BACKSQL_STR_GROW 256 39 40const char backsql_def_oc_query[] = 41 "SELECT id,name,keytbl,keycol,create_proc,delete_proc,expect_return " 42 "FROM ldap_oc_mappings"; 43const char backsql_def_needs_select_oc_query[] = 44 "SELECT id,name,keytbl,keycol,create_proc,create_keyval,delete_proc," 45 "expect_return FROM ldap_oc_mappings"; 46const char backsql_def_at_query[] = 47 "SELECT name,sel_expr,from_tbls,join_where,add_proc,delete_proc," 48 "param_order,expect_return,sel_expr_u FROM ldap_attr_mappings " 49 "WHERE oc_map_id=?"; 50const char backsql_def_delentry_stmt[] = "DELETE FROM ldap_entries WHERE id=?"; 51const char backsql_def_renentry_stmt[] = 52 "UPDATE ldap_entries SET dn=?,parent=?,keyval=? WHERE id=?"; 53const char backsql_def_insentry_stmt[] = 54 "INSERT INTO ldap_entries (dn,oc_map_id,parent,keyval) " 55 "VALUES (?,?,?,?)"; 56const char backsql_def_delobjclasses_stmt[] = "DELETE FROM ldap_entry_objclasses " 57 "WHERE entry_id=?"; 58const char backsql_def_subtree_cond[] = "ldap_entries.dn LIKE CONCAT('%',?)"; 59const char backsql_def_upper_subtree_cond[] = "(ldap_entries.dn) LIKE CONCAT('%',?)"; 60const char backsql_id_query[] = "SELECT id,keyval,oc_map_id,dn FROM ldap_entries WHERE "; 61/* better ?||? or cast(?||? as varchar) */ 62const char backsql_def_concat_func[] = "CONCAT(?,?)"; 63 64/* TimesTen */ 65const char backsql_check_dn_ru_query[] = "SELECT dn_ru FROM ldap_entries"; 66 67struct berbuf * 68backsql_strcat_x( struct berbuf *dest, void *memctx, ... ) 69{ 70 va_list strs; 71 ber_len_t cdlen, cslen, grow; 72 char *cstr; 73 74 assert( dest != NULL ); 75 assert( dest->bb_val.bv_val == NULL 76 || dest->bb_val.bv_len == strlen( dest->bb_val.bv_val ) ); 77 78#ifdef BACKSQL_TRACE 79 Debug( LDAP_DEBUG_TRACE, "==>backsql_strcat()\n", 0, 0, 0 ); 80#endif /* BACKSQL_TRACE */ 81 82 va_start( strs, memctx ); 83 if ( dest->bb_val.bv_val == NULL || dest->bb_len == 0 ) { 84 dest->bb_val.bv_val = (char *)ber_memalloc_x( BACKSQL_STR_GROW * sizeof( char ), memctx ); 85 dest->bb_val.bv_len = 0; 86 dest->bb_len = BACKSQL_STR_GROW; 87 } 88 cdlen = dest->bb_val.bv_len; 89 while ( ( cstr = va_arg( strs, char * ) ) != NULL ) { 90 cslen = strlen( cstr ); 91 grow = BACKSQL_MAX( BACKSQL_STR_GROW, cslen ); 92 if ( dest->bb_len - cdlen <= cslen ) { 93 char *tmp_dest; 94 95#ifdef BACKSQL_TRACE 96 Debug( LDAP_DEBUG_TRACE, "backsql_strcat(): " 97 "buflen=%d, cdlen=%d, cslen=%d " 98 "-- reallocating dest\n", 99 dest->bb_len, cdlen + 1, cslen ); 100#endif /* BACKSQL_TRACE */ 101 102 tmp_dest = (char *)ber_memrealloc_x( dest->bb_val.bv_val, 103 dest->bb_len + grow * sizeof( char ), memctx ); 104 if ( tmp_dest == NULL ) { 105 Debug( LDAP_DEBUG_ANY, "backsql_strcat(): " 106 "could not reallocate string buffer.\n", 107 0, 0, 0 ); 108 return NULL; 109 } 110 dest->bb_val.bv_val = tmp_dest; 111 dest->bb_len += grow; 112 113#ifdef BACKSQL_TRACE 114 Debug( LDAP_DEBUG_TRACE, "backsql_strcat(): " 115 "new buflen=%d, dest=%p\n", 116 dest->bb_len, dest, 0 ); 117#endif /* BACKSQL_TRACE */ 118 } 119 AC_MEMCPY( dest->bb_val.bv_val + cdlen, cstr, cslen + 1 ); 120 cdlen += cslen; 121 } 122 va_end( strs ); 123 124#ifdef BACKSQL_TRACE 125 Debug( LDAP_DEBUG_TRACE, "<==backsql_strcat() (dest=\"%s\")\n", 126 dest->bb_val.bv_val, 0, 0 ); 127#endif /* BACKSQL_TRACE */ 128 129 dest->bb_val.bv_len = cdlen; 130 131 return dest; 132} 133 134struct berbuf * 135backsql_strfcat_x( struct berbuf *dest, void *memctx, const char *fmt, ... ) 136{ 137 va_list strs; 138 ber_len_t cdlen; 139 140 assert( dest != NULL ); 141 assert( fmt != NULL ); 142 assert( dest->bb_len == 0 || dest->bb_len > dest->bb_val.bv_len ); 143 assert( dest->bb_val.bv_val == NULL 144 || dest->bb_val.bv_len == strlen( dest->bb_val.bv_val ) ); 145 146#ifdef BACKSQL_TRACE 147 Debug( LDAP_DEBUG_TRACE, "==>backsql_strfcat()\n", 0, 0, 0 ); 148#endif /* BACKSQL_TRACE */ 149 150 va_start( strs, fmt ); 151 if ( dest->bb_val.bv_val == NULL || dest->bb_len == 0 ) { 152 dest->bb_val.bv_val = (char *)ber_memalloc_x( BACKSQL_STR_GROW * sizeof( char ), memctx ); 153 dest->bb_val.bv_len = 0; 154 dest->bb_len = BACKSQL_STR_GROW; 155 } 156 157 cdlen = dest->bb_val.bv_len; 158 for ( ; fmt[0]; fmt++ ) { 159 ber_len_t cslen, grow; 160 char *cstr, cc[ 2 ] = { '\0', '\0' }; 161 struct berval *cbv; 162 163 switch ( fmt[ 0 ] ) { 164 165 /* berval */ 166 case 'b': 167 cbv = va_arg( strs, struct berval * ); 168 cstr = cbv->bv_val; 169 cslen = cbv->bv_len; 170 break; 171 172 /* length + string */ 173 case 'l': 174 cslen = va_arg( strs, ber_len_t ); 175 cstr = va_arg( strs, char * ); 176 break; 177 178 /* string */ 179 case 's': 180 cstr = va_arg( strs, char * ); 181 cslen = strlen( cstr ); 182 break; 183 184 /* char */ 185 case 'c': 186 /* 187 * `char' is promoted to `int' when passed through `...' 188 */ 189 cc[0] = va_arg( strs, int ); 190 cstr = cc; 191 cslen = 1; 192 break; 193 194 default: 195 assert( 0 ); 196 } 197 198 grow = BACKSQL_MAX( BACKSQL_STR_GROW, cslen ); 199 if ( dest->bb_len - cdlen <= cslen ) { 200 char *tmp_dest; 201 202#ifdef BACKSQL_TRACE 203 Debug( LDAP_DEBUG_TRACE, "backsql_strfcat(): " 204 "buflen=%d, cdlen=%d, cslen=%d " 205 "-- reallocating dest\n", 206 dest->bb_len, cdlen + 1, cslen ); 207#endif /* BACKSQL_TRACE */ 208 209 tmp_dest = (char *)ber_memrealloc_x( dest->bb_val.bv_val, 210 ( dest->bb_len ) + grow * sizeof( char ), memctx ); 211 if ( tmp_dest == NULL ) { 212 Debug( LDAP_DEBUG_ANY, "backsql_strfcat(): " 213 "could not reallocate string buffer.\n", 214 0, 0, 0 ); 215 return NULL; 216 } 217 dest->bb_val.bv_val = tmp_dest; 218 dest->bb_len += grow * sizeof( char ); 219 220#ifdef BACKSQL_TRACE 221 Debug( LDAP_DEBUG_TRACE, "backsql_strfcat(): " 222 "new buflen=%d, dest=%p\n", dest->bb_len, dest, 0 ); 223#endif /* BACKSQL_TRACE */ 224 } 225 226 assert( cstr != NULL ); 227 228 AC_MEMCPY( dest->bb_val.bv_val + cdlen, cstr, cslen + 1 ); 229 cdlen += cslen; 230 } 231 232 va_end( strs ); 233 234#ifdef BACKSQL_TRACE 235 Debug( LDAP_DEBUG_TRACE, "<==backsql_strfcat() (dest=\"%s\")\n", 236 dest->bb_val.bv_val, 0, 0 ); 237#endif /* BACKSQL_TRACE */ 238 239 dest->bb_val.bv_len = cdlen; 240 241 return dest; 242} 243 244int 245backsql_entry_addattr( 246 Entry *e, 247 AttributeDescription *ad, 248 struct berval *val, 249 void *memctx ) 250{ 251 int rc; 252 253#ifdef BACKSQL_TRACE 254 Debug( LDAP_DEBUG_TRACE, "backsql_entry_addattr(\"%s\"): %s=%s\n", 255 e->e_name.bv_val, ad->ad_cname.bv_val, val->bv_val ); 256#endif /* BACKSQL_TRACE */ 257 258 rc = attr_merge_normalize_one( e, ad, val, memctx ); 259 260 if ( rc != LDAP_SUCCESS ) { 261 Debug( LDAP_DEBUG_TRACE, "backsql_entry_addattr(\"%s\"): " 262 "failed to merge value \"%s\" for attribute \"%s\"\n", 263 e->e_name.bv_val, val->bv_val, ad->ad_cname.bv_val ); 264 return rc; 265 } 266 267#ifdef BACKSQL_TRACE 268 Debug( LDAP_DEBUG_TRACE, "<==backsql_entry_addattr(\"%s\")\n", 269 e->e_name.bv_val, 0, 0 ); 270#endif /* BACKSQL_TRACE */ 271 272 return LDAP_SUCCESS; 273} 274 275static char * 276backsql_get_table_spec( backsql_info *bi, char **p ) 277{ 278 char *s, *q; 279 struct berbuf res = BB_NULL; 280 281 assert( p != NULL ); 282 assert( *p != NULL ); 283 284 s = *p; 285 while ( **p && **p != ',' ) { 286 (*p)++; 287 } 288 289 if ( **p ) { 290 *(*p)++ = '\0'; 291 } 292 293#define BACKSQL_NEXT_WORD { \ 294 while ( *s && isspace( (unsigned char)*s ) ) s++; \ 295 if ( !*s ) return res.bb_val.bv_val; \ 296 q = s; \ 297 while ( *q && !isspace( (unsigned char)*q ) ) q++; \ 298 if ( *q ) *q++='\0'; \ 299 } 300 301 BACKSQL_NEXT_WORD; 302 /* table name */ 303 backsql_strcat_x( &res, NULL, s, NULL ); 304 s = q; 305 306 BACKSQL_NEXT_WORD; 307 if ( strcasecmp( s, "AS" ) == 0 ) { 308 s = q; 309 BACKSQL_NEXT_WORD; 310 } 311 312 /* oracle doesn't understand "AS" :( and other RDBMSes don't need it */ 313 backsql_strfcat_x( &res, NULL, "lbbsb", 314 STRLENOF( " " ), " ", 315 &bi->sql_aliasing, 316 &bi->sql_aliasing_quote, 317 s, 318 &bi->sql_aliasing_quote ); 319 320 return res.bb_val.bv_val; 321} 322 323int 324backsql_merge_from_clause( 325 backsql_info *bi, 326 struct berbuf *dest_from, 327 struct berval *src_from ) 328{ 329 char *s, *p, *srcc, *pos, e; 330 struct berbuf res = BB_NULL; 331 332#ifdef BACKSQL_TRACE 333 Debug( LDAP_DEBUG_TRACE, "==>backsql_merge_from_clause(): " 334 "dest_from=\"%s\",src_from=\"%s\"\n", 335 dest_from ? dest_from->bb_val.bv_val : "<NULL>", 336 src_from->bv_val, 0 ); 337#endif /* BACKSQL_TRACE */ 338 339 srcc = ch_strdup( src_from->bv_val ); 340 p = srcc; 341 342 if ( dest_from != NULL ) { 343 res = *dest_from; 344 } 345 346 while ( *p ) { 347 s = backsql_get_table_spec( bi, &p ); 348 349#ifdef BACKSQL_TRACE 350 Debug( LDAP_DEBUG_TRACE, "backsql_merge_from_clause(): " 351 "p=\"%s\" s=\"%s\"\n", p, s, 0 ); 352#endif /* BACKSQL_TRACE */ 353 354 if ( BER_BVISNULL( &res.bb_val ) ) { 355 backsql_strcat_x( &res, NULL, s, NULL ); 356 357 } else { 358 pos = strstr( res.bb_val.bv_val, s ); 359 if ( pos == NULL || ( ( e = pos[ strlen( s ) ] ) != '\0' && e != ',' ) ) { 360 backsql_strfcat_x( &res, NULL, "cs", ',', s ); 361 } 362 } 363 364 if ( s ) { 365 ch_free( s ); 366 } 367 } 368 369#ifdef BACKSQL_TRACE 370 Debug( LDAP_DEBUG_TRACE, "<==backsql_merge_from_clause()\n", 0, 0, 0 ); 371#endif /* BACKSQL_TRACE */ 372 373 free( srcc ); 374 *dest_from = res; 375 376 return 1; 377} 378 379/* 380 * splits a pattern in components separated by '?' 381 * (double ?? are turned into single ? and left in the string) 382 * expected contains the number of expected occurrences of '?' 383 * (a negative value means parse as many as possible) 384 */ 385 386int 387backsql_split_pattern( 388 const char *_pattern, 389 BerVarray *split_pattern, 390 int expected ) 391{ 392 char *pattern, *start, *end; 393 struct berval bv; 394 int rc = 0; 395 396#define SPLIT_CHAR '?' 397 398 assert( _pattern != NULL ); 399 assert( split_pattern != NULL ); 400 401 pattern = ch_strdup( _pattern ); 402 403 start = pattern; 404 end = strchr( start, SPLIT_CHAR ); 405 for ( ; start; expected-- ) { 406 char *real_end = end; 407 ber_len_t real_len; 408 409 if ( real_end == NULL ) { 410 real_end = start + strlen( start ); 411 412 } else if ( real_end[ 1 ] == SPLIT_CHAR ) { 413 expected++; 414 AC_MEMCPY( real_end, real_end + 1, strlen( real_end ) ); 415 end = strchr( real_end + 1, SPLIT_CHAR ); 416 continue; 417 } 418 419 real_len = real_end - start; 420 if ( real_len == 0 ) { 421 ber_str2bv( "", 0, 1, &bv ); 422 } else { 423 ber_str2bv( start, real_len, 1, &bv ); 424 } 425 426 ber_bvarray_add( split_pattern, &bv ); 427 428 if ( expected == 0 ) { 429 if ( end != NULL ) { 430 rc = -1; 431 goto done; 432 } 433 break; 434 } 435 436 if ( end != NULL ) { 437 start = end + 1; 438 end = strchr( start, SPLIT_CHAR ); 439 } 440 } 441 442done:; 443 444 ch_free( pattern ); 445 446 return rc; 447} 448 449int 450backsql_prepare_pattern( 451 BerVarray split_pattern, 452 BerVarray values, 453 struct berval *res ) 454{ 455 int i; 456 struct berbuf bb = BB_NULL; 457 458 assert( res != NULL ); 459 460 for ( i = 0; values[i].bv_val; i++ ) { 461 if ( split_pattern[i].bv_val == NULL ) { 462 ch_free( bb.bb_val.bv_val ); 463 return -1; 464 } 465 backsql_strfcat_x( &bb, NULL, "b", &split_pattern[ i ] ); 466 backsql_strfcat_x( &bb, NULL, "b", &values[ i ] ); 467 } 468 469 if ( split_pattern[ i ].bv_val == NULL ) { 470 ch_free( bb.bb_val.bv_val ); 471 return -1; 472 } 473 474 backsql_strfcat_x( &bb, NULL, "b", &split_pattern[ i ] ); 475 476 *res = bb.bb_val; 477 478 return 0; 479} 480 481int 482backsql_entryUUID( 483 backsql_info *bi, 484 backsql_entryID *id, 485 struct berval *entryUUID, 486 void *memctx ) 487{ 488 char uuidbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE ]; 489 struct berval uuid; 490#ifdef BACKSQL_ARBITRARY_KEY 491 int i; 492 ber_len_t l, lmax; 493#endif /* BACKSQL_ARBITRARY_KEY */ 494 495 /* entryUUID is generated as "%08x-%04x-%04x-0000-eaddrXXX" 496 * with eid_oc_id as %08x and hi and lo eid_id as %04x-%04x */ 497 assert( bi != NULL ); 498 assert( id != NULL ); 499 assert( entryUUID != NULL ); 500 501#ifdef BACKSQL_ARBITRARY_KEY 502 snprintf( uuidbuf, sizeof( uuidbuf ), 503 "%08x-0000-0000-0000-000000000000", 504 ( id->eid_oc_id & 0xFFFFFFFF ) ); 505 lmax = id->eid_keyval.bv_len < 12 ? id->eid_keyval.bv_len : 12; 506 for ( l = 0, i = 9; l < lmax; l++, i += 2 ) { 507 switch ( i ) { 508 case STRLENOF( "00000000-0000" ): 509 case STRLENOF( "00000000-0000-0000" ): 510 case STRLENOF( "00000000-0000-0000-0000" ): 511 uuidbuf[ i++ ] = '-'; 512 /* FALLTHRU */ 513 514 default: 515 snprintf( &uuidbuf[ i ], 3, "%2x", id->eid_keyval.bv_val[ l ] ); 516 break; 517 } 518 } 519#else /* ! BACKSQL_ARBITRARY_KEY */ 520 /* note: works only with 32 bit architectures... */ 521 snprintf( uuidbuf, sizeof( uuidbuf ), 522 "%08x-%04x-%04x-0000-000000000000", 523 ( (unsigned)id->eid_oc_id & 0xFFFFFFFF ), 524 ( ( (unsigned)id->eid_keyval & 0xFFFF0000 ) >> 020 /* 16 */ ), 525 ( (unsigned)id->eid_keyval & 0xFFFF ) ); 526#endif /* ! BACKSQL_ARBITRARY_KEY */ 527 528 uuid.bv_val = uuidbuf; 529 uuid.bv_len = strlen( uuidbuf ); 530 531 ber_dupbv_x( entryUUID, &uuid, memctx ); 532 533 return 0; 534} 535 536int 537backsql_entryUUID_decode( 538 struct berval *entryUUID, 539 unsigned long *oc_id, 540#ifdef BACKSQL_ARBITRARY_KEY 541 struct berval *keyval 542#else /* ! BACKSQL_ARBITRARY_KEY */ 543 unsigned long *keyval 544#endif /* ! BACKSQL_ARBITRARY_KEY */ 545 ) 546{ 547#if 0 548 fprintf( stderr, "==> backsql_entryUUID_decode()\n" ); 549#endif 550 551 *oc_id = ( entryUUID->bv_val[0] << 030 /* 24 */ ) 552 + ( entryUUID->bv_val[1] << 020 /* 16 */ ) 553 + ( entryUUID->bv_val[2] << 010 /* 8 */ ) 554 + entryUUID->bv_val[3]; 555 556#ifdef BACKSQL_ARBITRARY_KEY 557 /* FIXME */ 558#else /* ! BACKSQL_ARBITRARY_KEY */ 559 *keyval = ( entryUUID->bv_val[4] << 030 /* 24 */ ) 560 + ( entryUUID->bv_val[5] << 020 /* 16 */ ) 561 + ( entryUUID->bv_val[6] << 010 /* 8 */ ) 562 + entryUUID->bv_val[7]; 563#endif /* ! BACKSQL_ARBITRARY_KEY */ 564 565#if 0 566 fprintf( stderr, "<== backsql_entryUUID_decode(): oc=%lu id=%lu\n", 567 *oc_id, *keyval ); 568#endif 569 570 return LDAP_SUCCESS; 571} 572 573