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