1 /* $NetBSD: add.c,v 1.4 2025/09/05 21:16:31 christos Exp $ */ 2 3 /* $OpenLDAP$ */ 4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1999-2024 The OpenLDAP Foundation. 7 * Portions Copyright 1999 Dmitry Kovalev. 8 * Portions Copyright 2002 Pierangelo Masarati. 9 * Portions Copyright 2004 Mark Adamson. 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted only as authorized by the OpenLDAP 14 * Public License. 15 * 16 * A copy of this license is available in the file LICENSE in the 17 * top-level directory of the distribution or, alternatively, at 18 * <http://www.OpenLDAP.org/license.html>. 19 */ 20 /* ACKNOWLEDGEMENTS: 21 * This work was initially developed by Dmitry Kovalev for inclusion 22 * by OpenLDAP Software. Additional significant contributors include 23 * Pierangelo Masarati and Mark Adamson. 24 25 */ 26 27 #include <sys/cdefs.h> 28 __RCSID("$NetBSD: add.c,v 1.4 2025/09/05 21:16:31 christos Exp $"); 29 30 #include "portable.h" 31 32 #include <stdio.h> 33 #include <sys/types.h> 34 #include "ac/string.h" 35 36 #include "slap.h" 37 #include "proto-sql.h" 38 39 #ifdef BACKSQL_SYNCPROV 40 #include <lutil.h> 41 #endif /* BACKSQL_SYNCPROV */ 42 43 const char * processable_op_attrs[] = { 44 "pwdAccountLockedTime", 45 "pwdChangedTime", 46 "pwdFailureTime", 47 "pwdGraceUseTime", 48 "pwdHistory", 49 "pwdPolicySubentry", 50 "pwdReset", 51 "entryUUID" 52 }; 53 54 #define processable_op_attrs_length (sizeof (processable_op_attrs) / sizeof (const char *)) 55 56 static int indexOf(const char *array[], int array_size, const char * value) { 57 for (int i = 0; i < array_size; ++i) { 58 if(strcmp(array[i], value) == 0) { 59 return i; 60 } 61 } 62 return -1; 63 } 64 65 static int is_processable_opattr(const char * attr) { 66 return indexOf(processable_op_attrs, processable_op_attrs_length, attr) >= 0; 67 } 68 69 #define backsql_opattr_skip(ad) \ 70 (is_at_operational( (ad)->ad_type ) && (ad) != slap_schema.si_ad_ref ) 71 72 /* 73 * Skip: 74 * - null values (e.g. delete modification) 75 * - single occurrence of objectClass, because it is already used 76 * to determine how to build the SQL entry 77 * - operational attributes (except those in processable_op_attrs) 78 * - empty attributes 79 */ 80 #define backsql_attr_skip(ad, vals) \ 81 ( \ 82 ( ( (ad) == slap_schema.si_ad_objectClass \ 83 && (vals) && BER_BVISNULL( &((vals)[ 1 ]) ) ) \ 84 || backsql_opattr_skip( (ad) ) \ 85 || ( (vals) && BER_BVISNULL( &((vals)[ 0 ]) ) ) \ 86 ) && !is_processable_opattr( ad->ad_cname.bv_val ) ) 87 88 int 89 backsql_modify_delete_all_values( 90 Operation *op, 91 SlapReply *rs, 92 SQLHDBC dbh, 93 backsql_entryID *e_id, 94 backsql_at_map_rec *at ) 95 { 96 backsql_info *bi = (backsql_info *)op->o_bd->be_private; 97 RETCODE rc; 98 SQLHSTMT asth = SQL_NULL_HSTMT; 99 BACKSQL_ROW_NTS row; 100 101 assert( at != NULL ); 102 if ( at->bam_delete_proc == NULL ) { 103 Debug( LDAP_DEBUG_TRACE, 104 " backsql_modify_delete_all_values(): " 105 "missing attribute value delete procedure " 106 "for attr \"%s\"\n", 107 at->bam_ad->ad_cname.bv_val ); 108 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { 109 rs->sr_text = "SQL-backend error"; 110 return rs->sr_err = LDAP_OTHER; 111 } 112 113 return LDAP_SUCCESS; 114 } 115 116 rc = backsql_Prepare( dbh, &asth, at->bam_query, 0 ); 117 if ( rc != SQL_SUCCESS ) { 118 Debug( LDAP_DEBUG_TRACE, 119 " backsql_modify_delete_all_values(): " 120 "error preparing attribute value select query " 121 "\"%s\"\n", 122 at->bam_query ); 123 backsql_PrintErrors( bi->sql_db_env, dbh, 124 asth, rc ); 125 126 rs->sr_text = "SQL-backend error"; 127 return rs->sr_err = LDAP_OTHER; 128 } 129 130 rc = backsql_BindParamID( asth, 1, SQL_PARAM_INPUT, &e_id->eid_keyval ); 131 if ( rc != SQL_SUCCESS ) { 132 Debug( LDAP_DEBUG_TRACE, 133 " backsql_modify_delete_all_values(): " 134 "error binding key value parameter " 135 "to attribute value select query\n" ); 136 backsql_PrintErrors( bi->sql_db_env, dbh, 137 asth, rc ); 138 SQLFreeStmt( asth, SQL_DROP ); 139 140 rs->sr_text = "SQL-backend error"; 141 return rs->sr_err = LDAP_OTHER; 142 } 143 144 rc = SQLExecute( asth ); 145 if ( !BACKSQL_SUCCESS( rc ) ) { 146 Debug( LDAP_DEBUG_TRACE, 147 " backsql_modify_delete_all_values(): " 148 "error executing attribute value select query\n" ); 149 backsql_PrintErrors( bi->sql_db_env, dbh, 150 asth, rc ); 151 SQLFreeStmt( asth, SQL_DROP ); 152 153 rs->sr_text = "SQL-backend error"; 154 return rs->sr_err = LDAP_OTHER; 155 } 156 157 backsql_BindRowAsStrings_x( asth, &row, op->o_tmpmemctx ); 158 for ( rc = SQLFetch( asth ); 159 BACKSQL_SUCCESS( rc ); 160 rc = SQLFetch( asth ) ) 161 { 162 int i; 163 /* first parameter no, parameter order */ 164 SQLUSMALLINT pno = 0, 165 po = 0; 166 /* procedure return code */ 167 int prc = LDAP_SUCCESS; 168 169 for ( i = 0; i < row.ncols; i++ ) { 170 SQLHSTMT sth = SQL_NULL_HSTMT; 171 ber_len_t col_len; 172 173 rc = backsql_Prepare( dbh, &sth, at->bam_delete_proc, 0 ); 174 if ( rc != SQL_SUCCESS ) { 175 Debug( LDAP_DEBUG_TRACE, 176 " backsql_modify_delete_all_values(): " 177 "error preparing attribute value " 178 "delete procedure " 179 "\"%s\"\n", 180 at->bam_delete_proc ); 181 backsql_PrintErrors( bi->sql_db_env, dbh, 182 sth, rc ); 183 184 rs->sr_text = "SQL-backend error"; 185 rs->sr_err = LDAP_OTHER; 186 goto done; 187 } 188 189 if ( BACKSQL_IS_DEL( at->bam_expect_return ) ) { 190 pno = 1; 191 rc = backsql_BindParamInt( sth, 1, 192 SQL_PARAM_OUTPUT, &prc ); 193 if ( rc != SQL_SUCCESS ) { 194 Debug( LDAP_DEBUG_TRACE, 195 " backsql_modify_delete_all_values(): " 196 "error binding output parameter for %s[%d]\n", 197 at->bam_ad->ad_cname.bv_val, i ); 198 backsql_PrintErrors( bi->sql_db_env, dbh, 199 sth, rc ); 200 SQLFreeStmt( sth, SQL_DROP ); 201 202 rs->sr_text = "SQL-backend error"; 203 rs->sr_err = LDAP_OTHER; 204 goto done; 205 } 206 } 207 po = ( BACKSQL_IS_DEL( at->bam_param_order ) ) > 0; 208 rc = backsql_BindParamID( sth, pno + 1 + po, 209 SQL_PARAM_INPUT, &e_id->eid_keyval ); 210 if ( rc != SQL_SUCCESS ) { 211 Debug( LDAP_DEBUG_TRACE, 212 " backsql_modify_delete_all_values(): " 213 "error binding keyval parameter for %s[%d]\n", 214 at->bam_ad->ad_cname.bv_val, i ); 215 backsql_PrintErrors( bi->sql_db_env, dbh, 216 sth, rc ); 217 SQLFreeStmt( sth, SQL_DROP ); 218 219 rs->sr_text = "SQL-backend error"; 220 rs->sr_err = LDAP_OTHER; 221 goto done; 222 } 223 224 Debug( LDAP_DEBUG_TRACE, 225 " backsql_modify_delete_all_values() " 226 "arg(%d)=" BACKSQL_IDFMT "\n", 227 pno + 1 + po, 228 BACKSQL_IDARG(e_id->eid_keyval) ); 229 230 /* 231 * check for syntax needed here 232 * maybe need binary bind? 233 */ 234 col_len = strlen( row.cols[ i ] ); 235 rc = backsql_BindParamStr( sth, pno + 2 - po, 236 SQL_PARAM_INPUT, row.cols[ i ], col_len ); 237 if ( rc != SQL_SUCCESS ) { 238 Debug( LDAP_DEBUG_TRACE, 239 " backsql_modify_delete_all_values(): " 240 "error binding value parameter for %s[%d]\n", 241 at->bam_ad->ad_cname.bv_val, i ); 242 backsql_PrintErrors( bi->sql_db_env, dbh, 243 sth, rc ); 244 SQLFreeStmt( sth, SQL_DROP ); 245 246 rs->sr_text = "SQL-backend error"; 247 rs->sr_err = LDAP_OTHER; 248 goto done; 249 } 250 251 Debug( LDAP_DEBUG_TRACE, 252 " backsql_modify_delete_all_values(): " 253 "arg(%d)=%s; executing \"%s\"\n", 254 pno + 2 - po, row.cols[ i ], 255 at->bam_delete_proc ); 256 rc = SQLExecute( sth ); 257 if ( rc == SQL_SUCCESS && prc == LDAP_SUCCESS ) { 258 rs->sr_err = LDAP_SUCCESS; 259 260 } else { 261 Debug( LDAP_DEBUG_TRACE, 262 " backsql_modify_delete_all_values(): " 263 "delete_proc " 264 "execution failed (rc=%d, prc=%d)\n", 265 rc, prc ); 266 if ( prc != LDAP_SUCCESS ) { 267 /* SQL procedure executed fine 268 * but returned an error */ 269 rs->sr_err = BACKSQL_SANITIZE_ERROR( prc ); 270 271 } else { 272 backsql_PrintErrors( bi->sql_db_env, dbh, 273 sth, rc ); 274 rs->sr_err = LDAP_OTHER; 275 } 276 rs->sr_text = op->o_req_dn.bv_val; 277 SQLFreeStmt( sth, SQL_DROP ); 278 goto done; 279 } 280 SQLFreeStmt( sth, SQL_DROP ); 281 } 282 } 283 284 rs->sr_err = LDAP_SUCCESS; 285 286 done:; 287 backsql_FreeRow_x( &row, op->o_tmpmemctx ); 288 SQLFreeStmt( asth, SQL_DROP ); 289 290 return rs->sr_err; 291 } 292 293 int 294 backsql_modify_internal( 295 Operation *op, 296 SlapReply *rs, 297 SQLHDBC dbh, 298 backsql_oc_map_rec *oc, 299 backsql_entryID *e_id, 300 Modifications *modlist ) 301 { 302 backsql_info *bi = (backsql_info *)op->o_bd->be_private; 303 RETCODE rc; 304 Modifications *ml; 305 306 Debug( LDAP_DEBUG_TRACE, "==>backsql_modify_internal(): " 307 "traversing modifications list\n" ); 308 309 for ( ml = modlist; ml != NULL; ml = ml->sml_next ) { 310 AttributeDescription *ad; 311 int sm_op; 312 static char *sm_ops[] = { "add", "delete", "replace", "increment", NULL }; 313 314 BerVarray sm_values; 315 #if 0 316 /* NOTE: some day we'll have to pass 317 * the normalized values as well */ 318 BerVarray sm_nvalues; 319 #endif 320 backsql_at_map_rec *at = NULL; 321 struct berval *at_val; 322 int i; 323 324 ad = ml->sml_mod.sm_desc; 325 sm_op = ( ml->sml_mod.sm_op & LDAP_MOD_OP ); 326 sm_values = ml->sml_mod.sm_values; 327 #if 0 328 sm_nvalues = ml->sml_mod.sm_nvalues; 329 #endif 330 331 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): " 332 "modifying attribute \"%s\" (%s) according to " 333 "mappings for objectClass \"%s\"\n", 334 ad->ad_cname.bv_val, sm_ops[ sm_op ], BACKSQL_OC_NAME( oc ) ); 335 336 if ( backsql_attr_skip( ad, sm_values ) ) { 337 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): " 338 "skipping attribute \"%s\"\n", 339 ad->ad_cname.bv_val, 0, 0 ); 340 341 continue; 342 } 343 344 at = backsql_ad2at( oc, ad ); 345 if ( at == NULL ) { 346 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): " 347 "attribute \"%s\" is not registered " 348 "in objectClass \"%s\"\n", 349 ad->ad_cname.bv_val, BACKSQL_OC_NAME( oc ) ); 350 351 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { 352 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 353 rs->sr_text = "operation not permitted " 354 "within namingContext"; 355 goto done; 356 } 357 358 continue; 359 } 360 361 switch ( sm_op ) { 362 case LDAP_MOD_REPLACE: { 363 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): " 364 "replacing values for attribute \"%s\"\n", 365 at->bam_ad->ad_cname.bv_val ); 366 367 if ( at->bam_add_proc == NULL ) { 368 Debug( LDAP_DEBUG_TRACE, 369 " backsql_modify_internal(): " 370 "add procedure is not defined " 371 "for attribute \"%s\" " 372 "- unable to perform replacements\n", 373 at->bam_ad->ad_cname.bv_val ); 374 375 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { 376 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 377 rs->sr_text = "operation not permitted " 378 "within namingContext"; 379 goto done; 380 } 381 382 break; 383 } 384 385 if ( at->bam_delete_proc == NULL ) { 386 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { 387 Debug( LDAP_DEBUG_TRACE, 388 " backsql_modify_internal(): " 389 "delete procedure is not defined " 390 "for attribute \"%s\"\n", 391 at->bam_ad->ad_cname.bv_val ); 392 393 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 394 rs->sr_text = "operation not permitted " 395 "within namingContext"; 396 goto done; 397 } 398 399 Debug( LDAP_DEBUG_TRACE, 400 " backsql_modify_internal(): " 401 "delete procedure is not defined " 402 "for attribute \"%s\" " 403 "- adding only\n", 404 at->bam_ad->ad_cname.bv_val ); 405 406 goto add_only; 407 } 408 409 del_all: 410 rs->sr_err = backsql_modify_delete_all_values( op, rs, dbh, e_id, at ); 411 if ( rs->sr_err != LDAP_SUCCESS ) { 412 goto done; 413 } 414 415 /* LDAP_MOD_DELETE gets here if all values must be deleted */ 416 if ( sm_op == LDAP_MOD_DELETE ) { 417 break; 418 } 419 } 420 421 /* 422 * PASSTHROUGH - to add new attributes -- do NOT add break 423 */ 424 case LDAP_MOD_ADD: 425 /* case SLAP_MOD_SOFTADD: */ 426 /* case SLAP_MOD_ADD_IF_NOT_PRESENT: */ 427 add_only:; 428 if ( at->bam_add_proc == NULL ) { 429 Debug( LDAP_DEBUG_TRACE, 430 " backsql_modify_internal(): " 431 "add procedure is not defined " 432 "for attribute \"%s\"\n", 433 at->bam_ad->ad_cname.bv_val ); 434 435 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { 436 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 437 rs->sr_text = "operation not permitted " 438 "within namingContext"; 439 goto done; 440 } 441 442 break; 443 } 444 445 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): " 446 "adding new values for attribute \"%s\"\n", 447 at->bam_ad->ad_cname.bv_val ); 448 449 /* can't add a NULL val array */ 450 assert( sm_values != NULL ); 451 452 for ( i = 0, at_val = sm_values; 453 !BER_BVISNULL( at_val ); 454 i++, at_val++ ) 455 { 456 SQLHSTMT sth = SQL_NULL_HSTMT; 457 /* first parameter position, parameter order */ 458 SQLUSMALLINT pno = 0, 459 po; 460 /* procedure return code */ 461 int prc = LDAP_SUCCESS; 462 463 rc = backsql_Prepare( dbh, &sth, at->bam_add_proc, 0 ); 464 if ( rc != SQL_SUCCESS ) { 465 Debug( LDAP_DEBUG_TRACE, 466 " backsql_modify_internal(): " 467 "error preparing add query\n" ); 468 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); 469 470 rs->sr_err = LDAP_OTHER; 471 rs->sr_text = "SQL-backend error"; 472 goto done; 473 } 474 475 if ( BACKSQL_IS_ADD( at->bam_expect_return ) ) { 476 pno = 1; 477 rc = backsql_BindParamInt( sth, 1, 478 SQL_PARAM_OUTPUT, &prc ); 479 if ( rc != SQL_SUCCESS ) { 480 Debug( LDAP_DEBUG_TRACE, 481 " backsql_modify_internal(): " 482 "error binding output parameter for %s[%d]\n", 483 at->bam_ad->ad_cname.bv_val, i ); 484 backsql_PrintErrors( bi->sql_db_env, dbh, 485 sth, rc ); 486 SQLFreeStmt( sth, SQL_DROP ); 487 488 rs->sr_text = "SQL-backend error"; 489 rs->sr_err = LDAP_OTHER; 490 goto done; 491 } 492 } 493 po = ( BACKSQL_IS_ADD( at->bam_param_order ) ) > 0; 494 rc = backsql_BindParamID( sth, pno + 1 + po, 495 SQL_PARAM_INPUT, &e_id->eid_keyval ); 496 if ( rc != SQL_SUCCESS ) { 497 Debug( LDAP_DEBUG_TRACE, 498 " backsql_modify_internal(): " 499 "error binding keyval parameter for %s[%d]\n", 500 at->bam_ad->ad_cname.bv_val, i ); 501 backsql_PrintErrors( bi->sql_db_env, dbh, 502 sth, rc ); 503 SQLFreeStmt( sth, SQL_DROP ); 504 505 rs->sr_text = "SQL-backend error"; 506 rs->sr_err = LDAP_OTHER; 507 goto done; 508 } 509 510 Debug( LDAP_DEBUG_TRACE, 511 " backsql_modify_internal(): " 512 "arg(%d)=" BACKSQL_IDFMT "\n", 513 pno + 1 + po, 514 BACKSQL_IDARG(e_id->eid_keyval) ); 515 516 /* 517 * check for syntax needed here 518 * maybe need binary bind? 519 */ 520 rc = backsql_BindParamBerVal( sth, pno + 2 - po, 521 SQL_PARAM_INPUT, at_val ); 522 if ( rc != SQL_SUCCESS ) { 523 Debug( LDAP_DEBUG_TRACE, 524 " backsql_modify_internal(): " 525 "error binding value parameter for %s[%d]\n", 526 at->bam_ad->ad_cname.bv_val, i ); 527 backsql_PrintErrors( bi->sql_db_env, dbh, 528 sth, rc ); 529 SQLFreeStmt( sth, SQL_DROP ); 530 531 rs->sr_text = "SQL-backend error"; 532 rs->sr_err = LDAP_OTHER; 533 goto done; 534 } 535 Debug( LDAP_DEBUG_TRACE, 536 " backsql_modify_internal(): " 537 "arg(%d)=\"%s\"; executing \"%s\"\n", 538 pno + 2 - po, at_val->bv_val, 539 at->bam_add_proc ); 540 541 rc = SQLExecute( sth ); 542 if ( rc == SQL_SUCCESS && prc == LDAP_SUCCESS ) { 543 rs->sr_err = LDAP_SUCCESS; 544 545 } else { 546 Debug( LDAP_DEBUG_TRACE, 547 " backsql_modify_internal(): " 548 "add_proc execution failed " 549 "(rc=%d, prc=%d)\n", 550 rc, prc ); 551 if ( prc != LDAP_SUCCESS ) { 552 /* SQL procedure executed fine 553 * but returned an error */ 554 SQLFreeStmt( sth, SQL_DROP ); 555 556 rs->sr_err = BACKSQL_SANITIZE_ERROR( prc ); 557 rs->sr_text = at->bam_ad->ad_cname.bv_val; 558 return rs->sr_err; 559 560 } else { 561 backsql_PrintErrors( bi->sql_db_env, dbh, 562 sth, rc ); 563 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) 564 { 565 SQLFreeStmt( sth, SQL_DROP ); 566 567 rs->sr_err = LDAP_OTHER; 568 rs->sr_text = "SQL-backend error"; 569 goto done; 570 } 571 } 572 } 573 SQLFreeStmt( sth, SQL_DROP ); 574 } 575 break; 576 577 case LDAP_MOD_DELETE: 578 /* case SLAP_MOD_SOFTDEL: */ 579 if ( at->bam_delete_proc == NULL ) { 580 Debug( LDAP_DEBUG_TRACE, 581 " backsql_modify_internal(): " 582 "delete procedure is not defined " 583 "for attribute \"%s\"\n", 584 at->bam_ad->ad_cname.bv_val ); 585 586 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { 587 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 588 rs->sr_text = "operation not permitted " 589 "within namingContext"; 590 goto done; 591 } 592 593 break; 594 } 595 596 if ( sm_values == NULL ) { 597 Debug( LDAP_DEBUG_TRACE, 598 " backsql_modify_internal(): " 599 "no values given to delete " 600 "for attribute \"%s\" " 601 "-- deleting all values\n", 602 at->bam_ad->ad_cname.bv_val ); 603 goto del_all; 604 } 605 606 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): " 607 "deleting values for attribute \"%s\"\n", 608 at->bam_ad->ad_cname.bv_val ); 609 610 for ( i = 0, at_val = sm_values; 611 !BER_BVISNULL( at_val ); 612 i++, at_val++ ) 613 { 614 SQLHSTMT sth = SQL_NULL_HSTMT; 615 /* first parameter position, parameter order */ 616 SQLUSMALLINT pno = 0, 617 po; 618 /* procedure return code */ 619 int prc = LDAP_SUCCESS; 620 621 rc = backsql_Prepare( dbh, &sth, at->bam_delete_proc, 0 ); 622 if ( rc != SQL_SUCCESS ) { 623 Debug( LDAP_DEBUG_TRACE, 624 " backsql_modify_internal(): " 625 "error preparing delete query\n" ); 626 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); 627 628 rs->sr_err = LDAP_OTHER; 629 rs->sr_text = "SQL-backend error"; 630 goto done; 631 } 632 633 if ( BACKSQL_IS_DEL( at->bam_expect_return ) ) { 634 pno = 1; 635 rc = backsql_BindParamInt( sth, 1, 636 SQL_PARAM_OUTPUT, &prc ); 637 if ( rc != SQL_SUCCESS ) { 638 Debug( LDAP_DEBUG_TRACE, 639 " backsql_modify_internal(): " 640 "error binding output parameter for %s[%d]\n", 641 at->bam_ad->ad_cname.bv_val, i ); 642 backsql_PrintErrors( bi->sql_db_env, dbh, 643 sth, rc ); 644 SQLFreeStmt( sth, SQL_DROP ); 645 646 rs->sr_text = "SQL-backend error"; 647 rs->sr_err = LDAP_OTHER; 648 goto done; 649 } 650 } 651 po = ( BACKSQL_IS_DEL( at->bam_param_order ) ) > 0; 652 rc = backsql_BindParamID( sth, pno + 1 + po, 653 SQL_PARAM_INPUT, &e_id->eid_keyval ); 654 if ( rc != SQL_SUCCESS ) { 655 Debug( LDAP_DEBUG_TRACE, 656 " backsql_modify_internal(): " 657 "error binding keyval parameter for %s[%d]\n", 658 at->bam_ad->ad_cname.bv_val, i ); 659 backsql_PrintErrors( bi->sql_db_env, dbh, 660 sth, rc ); 661 SQLFreeStmt( sth, SQL_DROP ); 662 663 rs->sr_text = "SQL-backend error"; 664 rs->sr_err = LDAP_OTHER; 665 goto done; 666 } 667 668 Debug( LDAP_DEBUG_TRACE, 669 " backsql_modify_internal(): " 670 "arg(%d)=" BACKSQL_IDFMT "\n", 671 pno + 1 + po, 672 BACKSQL_IDARG(e_id->eid_keyval) ); 673 674 /* 675 * check for syntax needed here 676 * maybe need binary bind? 677 */ 678 rc = backsql_BindParamBerVal( sth, pno + 2 - po, 679 SQL_PARAM_INPUT, at_val ); 680 if ( rc != SQL_SUCCESS ) { 681 Debug( LDAP_DEBUG_TRACE, 682 " backsql_modify_internal(): " 683 "error binding value parameter for %s[%d]\n", 684 at->bam_ad->ad_cname.bv_val, i ); 685 backsql_PrintErrors( bi->sql_db_env, dbh, 686 sth, rc ); 687 SQLFreeStmt( sth, SQL_DROP ); 688 689 rs->sr_text = "SQL-backend error"; 690 rs->sr_err = LDAP_OTHER; 691 goto done; 692 } 693 694 Debug( LDAP_DEBUG_TRACE, 695 " backsql_modify_internal(): " 696 "executing \"%s\"\n", 697 at->bam_delete_proc ); 698 rc = SQLExecute( sth ); 699 if ( rc == SQL_SUCCESS && prc == LDAP_SUCCESS ) 700 { 701 rs->sr_err = LDAP_SUCCESS; 702 703 } else { 704 Debug( LDAP_DEBUG_TRACE, 705 " backsql_modify_internal(): " 706 "delete_proc execution " 707 "failed (rc=%d, prc=%d)\n", 708 rc, prc ); 709 710 if ( prc != LDAP_SUCCESS ) { 711 /* SQL procedure executed fine 712 * but returned an error */ 713 rs->sr_err = BACKSQL_SANITIZE_ERROR( prc ); 714 rs->sr_text = at->bam_ad->ad_cname.bv_val; 715 goto done; 716 717 } else { 718 backsql_PrintErrors( bi->sql_db_env, 719 dbh, sth, rc ); 720 SQLFreeStmt( sth, SQL_DROP ); 721 rs->sr_err = LDAP_OTHER; 722 rs->sr_text = at->bam_ad->ad_cname.bv_val; 723 goto done; 724 } 725 } 726 SQLFreeStmt( sth, SQL_DROP ); 727 } 728 break; 729 730 case LDAP_MOD_INCREMENT: 731 Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): " 732 "increment not supported yet\n" ); 733 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { 734 rs->sr_err = LDAP_OTHER; 735 rs->sr_text = "SQL-backend error"; 736 goto done; 737 } 738 break; 739 } 740 } 741 742 done:; 743 Debug( LDAP_DEBUG_TRACE, "<==backsql_modify_internal(): %d%s%s\n", 744 rs->sr_err, 745 rs->sr_text ? ": " : "", 746 rs->sr_text ? rs->sr_text : "" ); 747 748 /* 749 * FIXME: should fail in case one change fails? 750 */ 751 return rs->sr_err; 752 } 753 754 static int 755 backsql_add_attr( 756 Operation *op, 757 SlapReply *rs, 758 SQLHDBC dbh, 759 backsql_oc_map_rec *oc, 760 Attribute *at, 761 backsql_key_t new_keyval ) 762 { 763 backsql_info *bi = (backsql_info*)op->o_bd->be_private; 764 backsql_at_map_rec *at_rec = NULL; 765 struct berval *at_val; 766 unsigned long i; 767 RETCODE rc; 768 SQLUSMALLINT currpos; 769 SQLHSTMT sth = SQL_NULL_HSTMT; 770 771 at_rec = backsql_ad2at( oc, at->a_desc ); 772 773 if ( at_rec == NULL ) { 774 Debug( LDAP_DEBUG_TRACE, " backsql_add_attr(\"%s\"): " 775 "attribute \"%s\" is not registered " 776 "in objectclass \"%s\"\n", 777 op->ora_e->e_name.bv_val, 778 at->a_desc->ad_cname.bv_val, 779 BACKSQL_OC_NAME( oc ) ); 780 781 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { 782 rs->sr_text = "operation not permitted " 783 "within namingContext"; 784 return rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 785 } 786 787 return LDAP_SUCCESS; 788 } 789 790 if ( at_rec->bam_add_proc == NULL ) { 791 Debug( LDAP_DEBUG_TRACE, " backsql_add_attr(\"%s\"): " 792 "add procedure is not defined " 793 "for attribute \"%s\" " 794 "of structuralObjectClass \"%s\"\n", 795 op->ora_e->e_name.bv_val, 796 at->a_desc->ad_cname.bv_val, 797 BACKSQL_OC_NAME( oc ) ); 798 799 if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { 800 rs->sr_text = "operation not permitted " 801 "within namingContext"; 802 return rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 803 } 804 805 return LDAP_SUCCESS; 806 } 807 808 for ( i = 0, at_val = &at->a_vals[ i ]; 809 !BER_BVISNULL( at_val ); 810 i++, at_val = &at->a_vals[ i ] ) 811 { 812 /* procedure return code */ 813 int prc = LDAP_SUCCESS; 814 /* first parameter #, parameter order */ 815 SQLUSMALLINT pno, po; 816 817 /* 818 * Do not deal with the objectClass that is used 819 * to build the entry 820 */ 821 if ( at->a_desc == slap_schema.si_ad_objectClass ) { 822 if ( dn_match( at_val, &oc->bom_oc->soc_cname ) ) 823 { 824 continue; 825 } 826 } 827 828 rc = backsql_Prepare( dbh, &sth, at_rec->bam_add_proc, 0 ); 829 if ( rc != SQL_SUCCESS ) { 830 rs->sr_text = "SQL-backend error"; 831 return rs->sr_err = LDAP_OTHER; 832 } 833 834 if ( BACKSQL_IS_ADD( at_rec->bam_expect_return ) ) { 835 pno = 1; 836 rc = backsql_BindParamInt( sth, 1, SQL_PARAM_OUTPUT, &prc ); 837 if ( rc != SQL_SUCCESS ) { 838 Debug( LDAP_DEBUG_TRACE, 839 " backsql_add_attr(): " 840 "error binding output parameter for %s[%lu]\n", 841 at_rec->bam_ad->ad_cname.bv_val, i ); 842 backsql_PrintErrors( bi->sql_db_env, dbh, 843 sth, rc ); 844 SQLFreeStmt( sth, SQL_DROP ); 845 846 rs->sr_text = "SQL-backend error"; 847 return rs->sr_err = LDAP_OTHER; 848 } 849 850 } else { 851 pno = 0; 852 } 853 854 po = ( BACKSQL_IS_ADD( at_rec->bam_param_order ) ) > 0; 855 currpos = pno + 1 + po; 856 rc = backsql_BindParamNumID( sth, currpos, 857 SQL_PARAM_INPUT, &new_keyval ); 858 if ( rc != SQL_SUCCESS ) { 859 Debug( LDAP_DEBUG_TRACE, 860 " backsql_add_attr(): " 861 "error binding keyval parameter for %s[%lu]\n", 862 at_rec->bam_ad->ad_cname.bv_val, i ); 863 backsql_PrintErrors( bi->sql_db_env, dbh, 864 sth, rc ); 865 SQLFreeStmt( sth, SQL_DROP ); 866 867 rs->sr_text = "SQL-backend error"; 868 return rs->sr_err = LDAP_OTHER; 869 } 870 871 currpos = pno + 2 - po; 872 873 /* 874 * check for syntax needed here 875 * maybe need binary bind? 876 */ 877 878 rc = backsql_BindParamBerVal( sth, currpos, SQL_PARAM_INPUT, at_val ); 879 if ( rc != SQL_SUCCESS ) { 880 Debug( LDAP_DEBUG_TRACE, 881 " backsql_add_attr(): " 882 "error binding value parameter for %s[%lu]\n", 883 at_rec->bam_ad->ad_cname.bv_val, i ); 884 backsql_PrintErrors( bi->sql_db_env, dbh, 885 sth, rc ); 886 SQLFreeStmt( sth, SQL_DROP ); 887 888 rs->sr_text = "SQL-backend error"; 889 return rs->sr_err = LDAP_OTHER; 890 } 891 892 #ifdef LDAP_DEBUG 893 Debug(LDAP_DEBUG_TRACE, 894 " backsql_add_attr(\"%s\"): " "executing \"%s\" val[%lu], id=" BACKSQL_IDNUMFMT "\n", 895 op->ora_e->e_name.bv_val, at_rec->bam_add_proc, 896 i, new_keyval ); 897 #endif 898 rc = SQLExecute( sth ); 899 if ( rc == SQL_SUCCESS && prc == LDAP_SUCCESS ) { 900 rs->sr_err = LDAP_SUCCESS; 901 902 } else { 903 Debug( LDAP_DEBUG_TRACE, 904 " backsql_add_attr(\"%s\"): " 905 "add_proc execution failed (rc=%d, prc=%d)\n", 906 op->ora_e->e_name.bv_val, rc, prc ); 907 if ( prc != LDAP_SUCCESS ) { 908 /* SQL procedure executed fine 909 * but returned an error */ 910 rs->sr_err = BACKSQL_SANITIZE_ERROR( prc ); 911 rs->sr_text = op->ora_e->e_name.bv_val; 912 SQLFreeStmt( sth, SQL_DROP ); 913 return rs->sr_err; 914 915 } else { 916 backsql_PrintErrors( bi->sql_db_env, dbh, 917 sth, rc ); 918 rs->sr_err = LDAP_OTHER; 919 rs->sr_text = op->ora_e->e_name.bv_val; 920 SQLFreeStmt( sth, SQL_DROP ); 921 return rs->sr_err; 922 } 923 } 924 SQLFreeStmt( sth, SQL_DROP ); 925 } 926 927 return LDAP_SUCCESS; 928 } 929 930 int 931 backsql_add( Operation *op, SlapReply *rs ) 932 { 933 backsql_info *bi = (backsql_info*)op->o_bd->be_private; 934 SQLHDBC dbh = SQL_NULL_HDBC; 935 SQLHSTMT sth = SQL_NULL_HSTMT; 936 backsql_key_t new_keyval = 0; 937 RETCODE rc; 938 backsql_oc_map_rec *oc = NULL; 939 backsql_srch_info bsi = { 0 }; 940 Entry p = { 0 }, *e = NULL; 941 Attribute *at, 942 *at_objectClass = NULL; 943 ObjectClass *soc = NULL; 944 struct berval scname = BER_BVNULL; 945 struct berval pdn; 946 struct berval realdn = BER_BVNULL; 947 int colnum; 948 slap_mask_t mask; 949 950 char textbuf[ SLAP_TEXT_BUFLEN ]; 951 size_t textlen = sizeof( textbuf ); 952 953 #ifdef BACKSQL_SYNCPROV 954 /* 955 * NOTE: fake successful result to force contextCSN to be bumped up 956 */ 957 if ( op->o_sync ) { 958 char buf[ LDAP_PVT_CSNSTR_BUFSIZE ]; 959 struct berval csn; 960 961 csn.bv_val = buf; 962 csn.bv_len = sizeof( buf ); 963 slap_get_csn( op, &csn, 1 ); 964 965 rs->sr_err = LDAP_SUCCESS; 966 send_ldap_result( op, rs ); 967 968 slap_graduate_commit_csn( op ); 969 970 return 0; 971 } 972 #endif /* BACKSQL_SYNCPROV */ 973 974 Debug( LDAP_DEBUG_TRACE, "==>backsql_add(\"%s\")\n", 975 op->ora_e->e_name.bv_val ); 976 977 /* check schema */ 978 if ( BACKSQL_CHECK_SCHEMA( bi ) ) { 979 char textbuf[ SLAP_TEXT_BUFLEN ] = { '\0' }; 980 981 rs->sr_err = entry_schema_check( op, op->ora_e, NULL, 0, 1, NULL, 982 &rs->sr_text, textbuf, sizeof( textbuf ) ); 983 if ( rs->sr_err != LDAP_SUCCESS ) { 984 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 985 "entry failed schema check -- aborting\n", 986 op->ora_e->e_name.bv_val ); 987 e = NULL; 988 goto done; 989 } 990 } 991 992 slap_add_opattrs( op, &rs->sr_text, textbuf, textlen, 1 ); 993 994 if ( get_assert( op ) && 995 ( test_filter( op, op->ora_e, get_assertion( op )) != LDAP_COMPARE_TRUE )) 996 { 997 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 998 "assertion control failed -- aborting\n", 999 op->ora_e->e_name.bv_val ); 1000 e = NULL; 1001 rs->sr_err = LDAP_ASSERTION_FAILED; 1002 goto done; 1003 } 1004 1005 /* search structuralObjectClass */ 1006 for ( at = op->ora_e->e_attrs; at != NULL; at = at->a_next ) { 1007 if ( at->a_desc == slap_schema.si_ad_structuralObjectClass ) { 1008 break; 1009 } 1010 } 1011 1012 /* there must exist */ 1013 if ( at == NULL ) { 1014 char buf[ SLAP_TEXT_BUFLEN ]; 1015 const char *text; 1016 1017 /* search structuralObjectClass */ 1018 for ( at = op->ora_e->e_attrs; at != NULL; at = at->a_next ) { 1019 if ( at->a_desc == slap_schema.si_ad_objectClass ) { 1020 break; 1021 } 1022 } 1023 1024 if ( at == NULL ) { 1025 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1026 "no objectClass\n", 1027 op->ora_e->e_name.bv_val ); 1028 rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION; 1029 e = NULL; 1030 goto done; 1031 } 1032 1033 rs->sr_err = structural_class( at->a_vals, &soc, NULL, 1034 &text, buf, sizeof( buf ), op->o_tmpmemctx ); 1035 if ( rs->sr_err != LDAP_SUCCESS ) { 1036 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1037 "%s (%d)\n", 1038 op->ora_e->e_name.bv_val, text, rs->sr_err ); 1039 e = NULL; 1040 goto done; 1041 } 1042 scname = soc->soc_cname; 1043 1044 } else { 1045 scname = at->a_vals[0]; 1046 } 1047 1048 /* I guess we should play with sub/supertypes to find a suitable oc */ 1049 oc = backsql_name2oc( bi, &scname ); 1050 1051 if ( oc == NULL ) { 1052 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1053 "cannot map structuralObjectClass \"%s\" -- aborting\n", 1054 op->ora_e->e_name.bv_val, 1055 scname.bv_val ); 1056 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 1057 rs->sr_text = "operation not permitted within namingContext"; 1058 e = NULL; 1059 goto done; 1060 } 1061 1062 if ( oc->bom_create_proc == NULL ) { 1063 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1064 "create procedure is not defined " 1065 "for structuralObjectClass \"%s\" - aborting\n", 1066 op->ora_e->e_name.bv_val, 1067 scname.bv_val ); 1068 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 1069 rs->sr_text = "operation not permitted within namingContext"; 1070 e = NULL; 1071 goto done; 1072 1073 } else if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) 1074 && oc->bom_create_keyval == NULL ) { 1075 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1076 "create procedure needs select procedure, " 1077 "but none is defined for structuralObjectClass \"%s\" " 1078 "- aborting\n", 1079 op->ora_e->e_name.bv_val, 1080 scname.bv_val ); 1081 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 1082 rs->sr_text = "operation not permitted within namingContext"; 1083 e = NULL; 1084 goto done; 1085 } 1086 1087 /* check write access */ 1088 if ( !access_allowed_mask( op, op->ora_e, 1089 slap_schema.si_ad_entry, 1090 NULL, ACL_WADD, NULL, &mask ) ) 1091 { 1092 rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 1093 e = op->ora_e; 1094 goto done; 1095 } 1096 1097 rs->sr_err = backsql_get_db_conn( op, &dbh ); 1098 if ( rs->sr_err != LDAP_SUCCESS ) { 1099 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1100 "could not get connection handle - exiting\n", 1101 op->ora_e->e_name.bv_val ); 1102 rs->sr_text = ( rs->sr_err == LDAP_OTHER ) 1103 ? "SQL-backend error" : NULL; 1104 e = NULL; 1105 goto done; 1106 } 1107 1108 /* 1109 * Check if entry exists 1110 * 1111 * NOTE: backsql_api_dn2odbc() is called explicitly because 1112 * we need the mucked DN to pass it to the create procedure. 1113 */ 1114 realdn = op->ora_e->e_name; 1115 if ( backsql_api_dn2odbc( op, rs, &realdn ) ) { 1116 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1117 "backsql_api_dn2odbc(\"%s\") failed\n", 1118 op->ora_e->e_name.bv_val, realdn.bv_val ); 1119 rs->sr_err = LDAP_OTHER; 1120 rs->sr_text = "SQL-backend error"; 1121 e = NULL; 1122 goto done; 1123 } 1124 1125 rs->sr_err = backsql_dn2id( op, rs, dbh, &realdn, NULL, 0, 0 ); 1126 if ( rs->sr_err == LDAP_SUCCESS ) { 1127 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1128 "entry exists\n", 1129 op->ora_e->e_name.bv_val ); 1130 rs->sr_err = LDAP_ALREADY_EXISTS; 1131 e = op->ora_e; 1132 goto done; 1133 } 1134 1135 /* 1136 * Get the parent dn and see if the corresponding entry exists. 1137 */ 1138 if ( be_issuffix( op->o_bd, &op->ora_e->e_nname ) ) { 1139 pdn = slap_empty_bv; 1140 1141 } else { 1142 dnParent( &op->ora_e->e_nname, &pdn ); 1143 1144 /* 1145 * Get the parent 1146 */ 1147 bsi.bsi_e = &p; 1148 rs->sr_err = backsql_init_search( &bsi, &pdn, 1149 LDAP_SCOPE_BASE, 1150 (time_t)(-1), NULL, dbh, op, rs, slap_anlist_no_attrs, 1151 ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) ); 1152 if ( rs->sr_err != LDAP_SUCCESS ) { 1153 Debug( LDAP_DEBUG_TRACE, "backsql_add(): " 1154 "could not retrieve addDN parent " 1155 "\"%s\" ID - %s matched=\"%s\"\n", 1156 pdn.bv_val, 1157 rs->sr_err == LDAP_REFERRAL ? "referral" : "no such entry", 1158 rs->sr_matched ? rs->sr_matched : "(null)" ); 1159 e = &p; 1160 goto done; 1161 } 1162 1163 /* check "children" pseudo-attribute access to parent */ 1164 if ( !access_allowed( op, &p, slap_schema.si_ad_children, 1165 NULL, ACL_WADD, NULL ) ) 1166 { 1167 rs->sr_err = LDAP_INSUFFICIENT_ACCESS; 1168 e = &p; 1169 goto done; 1170 } 1171 } 1172 1173 /* 1174 * create_proc is executed; if expect_return is set, then 1175 * an output parameter is bound, which should contain 1176 * the id of the added row; otherwise the procedure 1177 * is expected to return the id as the first column of a select 1178 */ 1179 rc = backsql_Prepare( dbh, &sth, oc->bom_create_proc, 0 ); 1180 if ( rc != SQL_SUCCESS ) { 1181 rs->sr_err = LDAP_OTHER; 1182 rs->sr_text = "SQL-backend error"; 1183 e = NULL; 1184 goto done; 1185 } 1186 1187 colnum = 1; 1188 if ( BACKSQL_IS_ADD( oc->bom_expect_return ) ) { 1189 rc = backsql_BindParamNumID( sth, 1, SQL_PARAM_OUTPUT, &new_keyval ); 1190 if ( rc != SQL_SUCCESS ) { 1191 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1192 "error binding keyval parameter " 1193 "for objectClass %s\n", 1194 op->ora_e->e_name.bv_val, 1195 oc->bom_oc->soc_cname.bv_val ); 1196 backsql_PrintErrors( bi->sql_db_env, dbh, 1197 sth, rc ); 1198 SQLFreeStmt( sth, SQL_DROP ); 1199 1200 rs->sr_text = "SQL-backend error"; 1201 rs->sr_err = LDAP_OTHER; 1202 e = NULL; 1203 goto done; 1204 } 1205 colnum++; 1206 } 1207 1208 if ( oc->bom_create_hint ) { 1209 at = attr_find( op->ora_e->e_attrs, oc->bom_create_hint ); 1210 if ( at && at->a_vals ) { 1211 backsql_BindParamStr( sth, colnum, SQL_PARAM_INPUT, 1212 at->a_vals[0].bv_val, 1213 at->a_vals[0].bv_len ); 1214 Debug( LDAP_DEBUG_TRACE, "backsql_add(): " 1215 "create_proc hint: param = '%s'\n", 1216 at->a_vals[0].bv_val ); 1217 1218 } else { 1219 backsql_BindParamStr( sth, colnum, SQL_PARAM_INPUT, 1220 "", 0 ); 1221 Debug( LDAP_DEBUG_TRACE, "backsql_add(): " 1222 "create_proc hint (%s) not available\n", 1223 oc->bom_create_hint->ad_cname.bv_val ); 1224 } 1225 colnum++; 1226 } 1227 1228 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): executing \"%s\"\n", 1229 op->ora_e->e_name.bv_val, oc->bom_create_proc ); 1230 rc = SQLExecute( sth ); 1231 if ( rc != SQL_SUCCESS ) { 1232 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1233 "create_proc execution failed\n", 1234 op->ora_e->e_name.bv_val ); 1235 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc); 1236 SQLFreeStmt( sth, SQL_DROP ); 1237 rs->sr_err = LDAP_OTHER; 1238 rs->sr_text = "SQL-backend error"; 1239 e = NULL; 1240 goto done; 1241 } 1242 1243 /* FIXME: after SQLExecute(), the row is already inserted 1244 * (at least with PostgreSQL and unixODBC); needs investigation */ 1245 1246 if ( !BACKSQL_IS_ADD( oc->bom_expect_return ) ) { 1247 SWORD ncols; 1248 SQLLEN value_len; 1249 1250 if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) ) { 1251 SQLFreeStmt( sth, SQL_DROP ); 1252 1253 rc = backsql_Prepare( dbh, &sth, oc->bom_create_keyval, 0 ); 1254 if ( rc != SQL_SUCCESS ) { 1255 rs->sr_err = LDAP_OTHER; 1256 rs->sr_text = "SQL-backend error"; 1257 e = NULL; 1258 goto done; 1259 } 1260 1261 rc = SQLExecute( sth ); 1262 if ( rc != SQL_SUCCESS ) { 1263 rs->sr_err = LDAP_OTHER; 1264 rs->sr_text = "SQL-backend error"; 1265 e = NULL; 1266 goto done; 1267 } 1268 } 1269 1270 /* 1271 * the query to know the id of the inserted entry 1272 * must be embedded in the create procedure 1273 */ 1274 rc = SQLNumResultCols( sth, &ncols ); 1275 if ( rc != SQL_SUCCESS ) { 1276 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1277 "create_proc result evaluation failed\n", 1278 op->ora_e->e_name.bv_val ); 1279 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc); 1280 SQLFreeStmt( sth, SQL_DROP ); 1281 rs->sr_err = LDAP_OTHER; 1282 rs->sr_text = "SQL-backend error"; 1283 e = NULL; 1284 goto done; 1285 1286 } else if ( ncols != 1 ) { 1287 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1288 "create_proc result is bogus (ncols=%d)\n", 1289 op->ora_e->e_name.bv_val, ncols ); 1290 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc); 1291 SQLFreeStmt( sth, SQL_DROP ); 1292 rs->sr_err = LDAP_OTHER; 1293 rs->sr_text = "SQL-backend error"; 1294 e = NULL; 1295 goto done; 1296 } 1297 1298 #if 0 1299 { 1300 SQLCHAR colname[ 64 ]; 1301 SQLSMALLINT name_len, col_type, col_scale, col_null; 1302 UDWORD col_prec; 1303 1304 /* 1305 * FIXME: check whether col_type is compatible, 1306 * if it can be null and so on ... 1307 */ 1308 rc = SQLDescribeCol( sth, (SQLUSMALLINT)1, 1309 &colname[ 0 ], 1310 (SQLUINTEGER)( sizeof( colname ) - 1 ), 1311 &name_len, &col_type, 1312 &col_prec, &col_scale, &col_null ); 1313 } 1314 #endif 1315 1316 rc = SQLBindCol( sth, (SQLUSMALLINT)1, SQL_C_ULONG, 1317 (SQLPOINTER)&new_keyval, 1318 (SQLINTEGER)sizeof( new_keyval ), 1319 &value_len ); 1320 1321 rc = SQLFetch( sth ); 1322 1323 if ( value_len <= 0 ) { 1324 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1325 "create_proc result is empty?\n", 1326 op->ora_e->e_name.bv_val ); 1327 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc); 1328 SQLFreeStmt( sth, SQL_DROP ); 1329 rs->sr_err = LDAP_OTHER; 1330 rs->sr_text = "SQL-backend error"; 1331 e = NULL; 1332 goto done; 1333 } 1334 } 1335 1336 SQLFreeStmt( sth, SQL_DROP ); 1337 1338 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1339 "create_proc returned keyval=" BACKSQL_IDNUMFMT "\n", 1340 op->ora_e->e_name.bv_val, new_keyval ); 1341 1342 rc = backsql_Prepare( dbh, &sth, bi->sql_insentry_stmt, 0 ); 1343 if ( rc != SQL_SUCCESS ) { 1344 rs->sr_err = LDAP_OTHER; 1345 rs->sr_text = "SQL-backend error"; 1346 e = NULL; 1347 goto done; 1348 } 1349 1350 rc = backsql_BindParamBerVal( sth, 1, SQL_PARAM_INPUT, &realdn ); 1351 if ( rc != SQL_SUCCESS ) { 1352 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1353 "error binding DN parameter for objectClass %s\n", 1354 op->ora_e->e_name.bv_val, 1355 oc->bom_oc->soc_cname.bv_val ); 1356 backsql_PrintErrors( bi->sql_db_env, dbh, 1357 sth, rc ); 1358 SQLFreeStmt( sth, SQL_DROP ); 1359 1360 rs->sr_text = "SQL-backend error"; 1361 rs->sr_err = LDAP_OTHER; 1362 e = NULL; 1363 goto done; 1364 } 1365 1366 rc = backsql_BindParamNumID( sth, 2, SQL_PARAM_INPUT, &oc->bom_id ); 1367 if ( rc != SQL_SUCCESS ) { 1368 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1369 "error binding objectClass ID parameter " 1370 "for objectClass %s\n", 1371 op->ora_e->e_name.bv_val, 1372 oc->bom_oc->soc_cname.bv_val ); 1373 backsql_PrintErrors( bi->sql_db_env, dbh, 1374 sth, rc ); 1375 SQLFreeStmt( sth, SQL_DROP ); 1376 1377 rs->sr_text = "SQL-backend error"; 1378 rs->sr_err = LDAP_OTHER; 1379 e = NULL; 1380 goto done; 1381 } 1382 1383 rc = backsql_BindParamID( sth, 3, SQL_PARAM_INPUT, &bsi.bsi_base_id.eid_id ); 1384 if ( rc != SQL_SUCCESS ) { 1385 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1386 "error binding parent ID parameter " 1387 "for objectClass %s\n", 1388 op->ora_e->e_name.bv_val, 1389 oc->bom_oc->soc_cname.bv_val ); 1390 backsql_PrintErrors( bi->sql_db_env, dbh, 1391 sth, rc ); 1392 SQLFreeStmt( sth, SQL_DROP ); 1393 1394 rs->sr_text = "SQL-backend error"; 1395 rs->sr_err = LDAP_OTHER; 1396 e = NULL; 1397 goto done; 1398 } 1399 1400 rc = backsql_BindParamNumID( sth, 4, SQL_PARAM_INPUT, &new_keyval ); 1401 if ( rc != SQL_SUCCESS ) { 1402 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1403 "error binding entry ID parameter " 1404 "for objectClass %s\n", 1405 op->ora_e->e_name.bv_val, 1406 oc->bom_oc->soc_cname.bv_val ); 1407 backsql_PrintErrors( bi->sql_db_env, dbh, 1408 sth, rc ); 1409 SQLFreeStmt( sth, SQL_DROP ); 1410 1411 rs->sr_text = "SQL-backend error"; 1412 rs->sr_err = LDAP_OTHER; 1413 e = NULL; 1414 goto done; 1415 } 1416 1417 Debug(LDAP_DEBUG_TRACE, 1418 " backsql_add(): executing \"%s\" for dn=\"%s\" oc_map_id=" BACKSQL_IDNUMFMT " p_id=" BACKSQL_IDFMT " keyval=" BACKSQL_IDNUMFMT "\n", 1419 bi->sql_insentry_stmt, op->ora_e->e_name.bv_val, 1420 oc->bom_id, BACKSQL_IDARG(bsi.bsi_base_id.eid_id), 1421 new_keyval ); 1422 1423 rc = SQLExecute( sth ); 1424 if ( rc != SQL_SUCCESS ) { 1425 Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): " 1426 "could not insert ldap_entries record\n", 1427 op->ora_e->e_name.bv_val ); 1428 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc ); 1429 1430 /* 1431 * execute delete_proc to delete data added !!! 1432 */ 1433 SQLFreeStmt( sth, SQL_DROP ); 1434 rs->sr_err = LDAP_OTHER; 1435 rs->sr_text = "SQL-backend error"; 1436 e = NULL; 1437 goto done; 1438 } 1439 1440 SQLFreeStmt( sth, SQL_DROP ); 1441 1442 for ( at = op->ora_e->e_attrs; at != NULL; at = at->a_next ) { 1443 Debug( LDAP_DEBUG_TRACE, " backsql_add(): " 1444 "adding attribute \"%s\"\n", 1445 at->a_desc->ad_cname.bv_val ); 1446 1447 /* 1448 * Skip: 1449 * - the first occurrence of objectClass, which is used 1450 * to determine how to build the SQL entry (FIXME ?!?) 1451 * - operational attributes 1452 * - empty attributes (FIXME ?!?) 1453 */ 1454 if ( backsql_attr_skip( at->a_desc, at->a_vals ) ) { 1455 continue; 1456 } 1457 1458 if ( at->a_desc == slap_schema.si_ad_objectClass ) { 1459 at_objectClass = at; 1460 continue; 1461 } 1462 1463 rs->sr_err = backsql_add_attr( op, rs, dbh, oc, at, new_keyval ); 1464 if ( rs->sr_err != LDAP_SUCCESS ) { 1465 e = op->ora_e; 1466 goto done; 1467 } 1468 } 1469 1470 if ( at_objectClass ) { 1471 rs->sr_err = backsql_add_attr( op, rs, dbh, oc, 1472 at_objectClass, new_keyval ); 1473 if ( rs->sr_err != LDAP_SUCCESS ) { 1474 e = op->ora_e; 1475 goto done; 1476 } 1477 } 1478 1479 done:; 1480 /* 1481 * Commit only if all operations succeed 1482 */ 1483 if ( sth != SQL_NULL_HSTMT ) { 1484 SQLUSMALLINT CompletionType = SQL_ROLLBACK; 1485 1486 if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) { 1487 assert( e == NULL ); 1488 CompletionType = SQL_COMMIT; 1489 } 1490 1491 SQLTransact( SQL_NULL_HENV, dbh, CompletionType ); 1492 } 1493 1494 /* 1495 * FIXME: NOOP does not work for add -- it works for all 1496 * the other operations, and I don't get the reason :( 1497 * 1498 * hint: there might be some autocommit in Postgres 1499 * so that when the unique id of the key table is 1500 * automatically increased, there's no rollback. 1501 * We might implement a "rollback" procedure consisting 1502 * in deleting that row. 1503 */ 1504 1505 if ( e != NULL ) { 1506 int disclose = 1; 1507 1508 if ( e == op->ora_e && !ACL_GRANT( mask, ACL_DISCLOSE ) ) { 1509 /* mask already collected */ 1510 disclose = 0; 1511 1512 } else if ( e == &p && !access_allowed( op, &p, 1513 slap_schema.si_ad_entry, NULL, 1514 ACL_DISCLOSE, NULL ) ) 1515 { 1516 disclose = 0; 1517 } 1518 1519 if ( disclose == 0 ) { 1520 rs->sr_err = LDAP_NO_SUCH_OBJECT; 1521 rs->sr_text = NULL; 1522 rs->sr_matched = NULL; 1523 if ( rs->sr_ref ) { 1524 ber_bvarray_free( rs->sr_ref ); 1525 rs->sr_ref = NULL; 1526 } 1527 } 1528 } 1529 1530 if ( op->o_noop && rs->sr_err == LDAP_SUCCESS ) { 1531 rs->sr_err = LDAP_X_NO_OPERATION; 1532 } 1533 1534 send_ldap_result( op, rs ); 1535 slap_graduate_commit_csn( op ); 1536 1537 if ( !BER_BVISNULL( &realdn ) 1538 && realdn.bv_val != op->ora_e->e_name.bv_val ) 1539 { 1540 ch_free( realdn.bv_val ); 1541 } 1542 1543 if ( !BER_BVISNULL( &bsi.bsi_base_id.eid_ndn ) ) { 1544 (void)backsql_free_entryID( &bsi.bsi_base_id, 0, op->o_tmpmemctx ); 1545 } 1546 1547 if ( !BER_BVISNULL( &p.e_nname ) ) { 1548 backsql_entry_clean( op, &p ); 1549 } 1550 1551 Debug( LDAP_DEBUG_TRACE, "<==backsql_add(\"%s\"): %d \"%s\"\n", 1552 op->ora_e->e_name.bv_val, 1553 rs->sr_err, 1554 rs->sr_text ? rs->sr_text : "" ); 1555 1556 rs->sr_text = NULL; 1557 rs->sr_matched = NULL; 1558 if ( rs->sr_ref ) { 1559 ber_bvarray_free( rs->sr_ref ); 1560 rs->sr_ref = NULL; 1561 } 1562 1563 return rs->sr_err; 1564 } 1565 1566