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