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