add.c 40.5 KB
Newer Older
1
2
3
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
4
 * Copyright 1999-2021 The OpenLDAP Foundation.
5
 * Portions Copyright 1999 Dmitry Kovalev.
6
 * Portions Copyright 2002 Pierangelo Masarati.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
7
 * Portions Copyright 2004 Mark Adamson.
8
9
10
11
12
13
14
15
16
17
18
19
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
 *
 * A copy of this license is available in the file LICENSE in the
 * top-level directory of the distribution or, alternatively, at
 * <http://www.OpenLDAP.org/license.html>.
 */
/* ACKNOWLEDGEMENTS:
 * This work was initially developed by Dmitry Kovalev for inclusion
20
21
22
 * by OpenLDAP Software.  Additional significant contributors include
 * Pierangelo Masarati and Mark Adamson.

23
24
25
26
27
28
29
30
31
32
33
 */

#include "portable.h"

#include <stdio.h>
#include <sys/types.h>
#include "ac/string.h"

#include "slap.h"
#include "proto-sql.h"

34
35
36
37
#ifdef BACKSQL_SYNCPROV
#include <lutil.h>
#endif /* BACKSQL_SYNCPROV */

38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
const char * processable_op_attrs[] = {
		"pwdAccountLockedTime",
		"pwdChangedTime",
		"pwdFailureTime",
		"pwdGraceUseTime",
		"pwdHistory",
		"pwdPolicySubentry",
		"pwdReset",
		"entryUUID"
};

#define processable_op_attrs_length (sizeof (processable_op_attrs) / sizeof (const char *))

static int indexOf(const char *array[], int array_size, const char * value) {
	for (int i = 0; i < array_size; ++i) {
		if(strcmp(array[i], value) == 0) {
			return i;
		}
	}
	return -1;
}

static int is_processable_opattr(const char * attr) {
	return indexOf(processable_op_attrs, processable_op_attrs_length, attr) >= 0;
}

#define backsql_opattr_skip(ad) \
	(is_at_operational( (ad)->ad_type ) && (ad) != slap_schema.si_ad_ref )

67
68
/*
 * Skip:
Pierangelo Masarati's avatar
Pierangelo Masarati committed
69
70
71
 * - null values (e.g. delete modification)
 * - single occurrence of objectClass, because it is already used
 *   to determine how to build the SQL entry
72
 * - operational attributes (except those in processable_op_attrs)
Pierangelo Masarati's avatar
Pierangelo Masarati committed
73
 * - empty attributes
74
 */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
75
#define	backsql_attr_skip(ad, vals) \
76
	( \
77
		( ( (ad) == slap_schema.si_ad_objectClass \
Pierangelo Masarati's avatar
Pierangelo Masarati committed
78
				&& (vals) && BER_BVISNULL( &((vals)[ 1 ]) ) ) \
79
		|| backsql_opattr_skip( (ad) ) \
80
		|| ( (vals) && BER_BVISNULL( &((vals)[ 0 ]) ) ) \
81
	) && !is_processable_opattr( ad->ad_cname.bv_val ) )
82

83
84
85
86
87
88
89
90
91
92
int
backsql_modify_delete_all_values(
	Operation 		*op,
	SlapReply		*rs,
	SQLHDBC			dbh, 
	backsql_entryID		*e_id,
	backsql_at_map_rec	*at )
{
	backsql_info	*bi = (backsql_info *)op->o_bd->be_private;
	RETCODE		rc;
93
	SQLHSTMT	asth = SQL_NULL_HSTMT;
94
95
	BACKSQL_ROW_NTS	row;

96
	assert( at != NULL );
97
98
99
100
101
	if ( at->bam_delete_proc == NULL ) {
		Debug( LDAP_DEBUG_TRACE,
			"   backsql_modify_delete_all_values(): "
			"missing attribute value delete procedure "
			"for attr \"%s\"\n",
102
			at->bam_ad->ad_cname.bv_val );
103
104
105
106
107
108
109
110
		if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
			rs->sr_text = "SQL-backend error";
			return rs->sr_err = LDAP_OTHER;
		}

		return LDAP_SUCCESS;
	}

111
112
113
114
	rc = backsql_Prepare( dbh, &asth, at->bam_query, 0 );
	if ( rc != SQL_SUCCESS ) {
		Debug( LDAP_DEBUG_TRACE,
			"   backsql_modify_delete_all_values(): "
115
116
			"error preparing attribute value select query "
			"\"%s\"\n",
117
			at->bam_query );
118
		backsql_PrintErrors( bi->sql_db_env, dbh, 
119
120
				asth, rc );

121
122
		rs->sr_text = "SQL-backend error";
		return rs->sr_err = LDAP_OTHER;
123
124
	}

125
	rc = backsql_BindParamID( asth, 1, SQL_PARAM_INPUT, &e_id->eid_keyval );
126
127
128
	if ( rc != SQL_SUCCESS ) {
		Debug( LDAP_DEBUG_TRACE,
			"   backsql_modify_delete_all_values(): "
129
			"error binding key value parameter "
130
			"to attribute value select query\n" );
131
		backsql_PrintErrors( bi->sql_db_env, dbh, 
132
133
134
				asth, rc );
		SQLFreeStmt( asth, SQL_DROP );

135
136
		rs->sr_text = "SQL-backend error";
		return rs->sr_err = LDAP_OTHER;
137
138
139
140
141
142
	}
			
	rc = SQLExecute( asth );
	if ( !BACKSQL_SUCCESS( rc ) ) {
		Debug( LDAP_DEBUG_TRACE,
			"   backsql_modify_delete_all_values(): "
143
			"error executing attribute value select query\n" );
144
		backsql_PrintErrors( bi->sql_db_env, dbh, 
145
146
147
				asth, rc );
		SQLFreeStmt( asth, SQL_DROP );

148
149
		rs->sr_text = "SQL-backend error";
		return rs->sr_err = LDAP_OTHER;
150
151
	}

152
	backsql_BindRowAsStrings_x( asth, &row, op->o_tmpmemctx );
153
154
155
156
	for ( rc = SQLFetch( asth );
			BACKSQL_SUCCESS( rc );
			rc = SQLFetch( asth ) )
	{
157
		int		i;
158
		/* first parameter no, parameter order */
159
		SQLUSMALLINT	pno = 0,
160
				po = 0;
161
		/* procedure return code */
162
		int		prc = LDAP_SUCCESS;
163
164
		
		for ( i = 0; i < row.ncols; i++ ) {
165
			SQLHSTMT	sth = SQL_NULL_HSTMT;
166
			ber_len_t	col_len;
167
168
169
170
171
			
			rc = backsql_Prepare( dbh, &sth, at->bam_delete_proc, 0 );
			if ( rc != SQL_SUCCESS ) {
				Debug( LDAP_DEBUG_TRACE,
					"   backsql_modify_delete_all_values(): "
172
173
174
					"error preparing attribute value "
					"delete procedure "
					"\"%s\"\n",
175
					at->bam_delete_proc );
176
				backsql_PrintErrors( bi->sql_db_env, dbh, 
177
178
						sth, rc );

179
				rs->sr_text = "SQL-backend error";
180
181
				rs->sr_err = LDAP_OTHER;
				goto done;
182
183
184
185
			}

	   		if ( BACKSQL_IS_DEL( at->bam_expect_return ) ) {
				pno = 1;
186
187
188
189
190
191
				rc = backsql_BindParamInt( sth, 1,
						SQL_PARAM_OUTPUT, &prc );
				if ( rc != SQL_SUCCESS ) {
					Debug( LDAP_DEBUG_TRACE,
						"   backsql_modify_delete_all_values(): "
						"error binding output parameter for %s[%d]\n",
192
						at->bam_ad->ad_cname.bv_val, i );
193
					backsql_PrintErrors( bi->sql_db_env, dbh, 
194
195
196
						sth, rc );
					SQLFreeStmt( sth, SQL_DROP );

197
					rs->sr_text = "SQL-backend error";
198
199
					rs->sr_err = LDAP_OTHER;
					goto done;
200
				}
201
202
			}
			po = ( BACKSQL_IS_DEL( at->bam_param_order ) ) > 0;
203
204
205
206
207
208
			rc = backsql_BindParamID( sth, pno + 1 + po,
				SQL_PARAM_INPUT, &e_id->eid_keyval );
			if ( rc != SQL_SUCCESS ) {
				Debug( LDAP_DEBUG_TRACE,
					"   backsql_modify_delete_all_values(): "
					"error binding keyval parameter for %s[%d]\n",
209
					at->bam_ad->ad_cname.bv_val, i );
210
				backsql_PrintErrors( bi->sql_db_env, dbh, 
211
212
213
					sth, rc );
				SQLFreeStmt( sth, SQL_DROP );

214
				rs->sr_text = "SQL-backend error";
215
216
				rs->sr_err = LDAP_OTHER;
				goto done;
217
			}
218

219
			Debug( LDAP_DEBUG_TRACE,
220
				"   backsql_modify_delete_all_values() "
221
222
				"arg(%d)=" BACKSQL_IDFMT "\n",
				pno + 1 + po,
223
				BACKSQL_IDARG(e_id->eid_keyval) );
224
225
226
227
228

			/*
			 * check for syntax needed here 
			 * maybe need binary bind?
			 */
229
			col_len = strlen( row.cols[ i ] );
230
231
232
233
234
235
			rc = backsql_BindParamStr( sth, pno + 2 - po,
				SQL_PARAM_INPUT, row.cols[ i ], col_len );
			if ( rc != SQL_SUCCESS ) {
				Debug( LDAP_DEBUG_TRACE,
					"   backsql_modify_delete_all_values(): "
					"error binding value parameter for %s[%d]\n",
236
					at->bam_ad->ad_cname.bv_val, i );
237
				backsql_PrintErrors( bi->sql_db_env, dbh, 
238
239
240
					sth, rc );
				SQLFreeStmt( sth, SQL_DROP );

241
				rs->sr_text = "SQL-backend error";
242
243
				rs->sr_err = LDAP_OTHER;
				goto done;
244
			}
245
246
247
	 
			Debug( LDAP_DEBUG_TRACE, 
				"   backsql_modify_delete_all_values(): "
248
				"arg(%d)=%s; executing \"%s\"\n",
249
250
251
				pno + 2 - po, row.cols[ i ],
				at->bam_delete_proc );
			rc = SQLExecute( sth );
252
253
254
255
			if ( rc == SQL_SUCCESS && prc == LDAP_SUCCESS ) {
				rs->sr_err = LDAP_SUCCESS;

			} else {
256
257
258
				Debug( LDAP_DEBUG_TRACE,
					"   backsql_modify_delete_all_values(): "
					"delete_proc "
259
					"execution failed (rc=%d, prc=%d)\n",
260
					rc, prc );
261
262
263
264
265
266
267
268
				if ( prc != LDAP_SUCCESS ) {
					/* SQL procedure executed fine 
					 * but returned an error */
					rs->sr_err = BACKSQL_SANITIZE_ERROR( prc );

				} else {
					backsql_PrintErrors( bi->sql_db_env, dbh,
							sth, rc );
269
					rs->sr_err = LDAP_OTHER;
270
				}
271
				rs->sr_text = op->o_req_dn.bv_val;
272
				SQLFreeStmt( sth, SQL_DROP );
273
				goto done;
274
275
276
277
			}
			SQLFreeStmt( sth, SQL_DROP );
		}
	}
278
279
280
281
282

	rs->sr_err = LDAP_SUCCESS;

done:;
	backsql_FreeRow_x( &row, op->o_tmpmemctx );
283
284
	SQLFreeStmt( asth, SQL_DROP );

285
	return rs->sr_err;
286
287
}

288
289
290
291
292
293
294
295
296
int
backsql_modify_internal(
	Operation 		*op,
	SlapReply		*rs,
	SQLHDBC			dbh, 
	backsql_oc_map_rec	*oc,
	backsql_entryID		*e_id,
	Modifications		*modlist )
{
297
	backsql_info	*bi = (backsql_info *)op->o_bd->be_private;
298
299
300
301
	RETCODE		rc;
	Modifications	*ml;

	Debug( LDAP_DEBUG_TRACE, "==>backsql_modify_internal(): "
302
		"traversing modifications list\n" );
303
304
305

	for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
		AttributeDescription	*ad;
306
307
308
309
310
		int			sm_op;
		static char		*sm_ops[] = { "add", "delete", "replace", "increment", NULL };

		BerVarray		sm_values;
#if 0
Pierangelo Masarati's avatar
Pierangelo Masarati committed
311
		/* NOTE: some day we'll have to pass 
312
		 * the normalized values as well */
313
		BerVarray		sm_nvalues;
314
#endif
315
316
317
		backsql_at_map_rec	*at = NULL;
		struct berval		*at_val;
		int			i;
318
		
319
320
321
322
323
324
		ad = ml->sml_mod.sm_desc;
		sm_op = ( ml->sml_mod.sm_op & LDAP_MOD_OP );
		sm_values = ml->sml_mod.sm_values;
#if 0
		sm_nvalues = ml->sml_mod.sm_nvalues;
#endif
325
326

		Debug( LDAP_DEBUG_TRACE, "   backsql_modify_internal(): "
327
			"modifying attribute \"%s\" (%s) according to "
328
			"mappings for objectClass \"%s\"\n",
329
			ad->ad_cname.bv_val, sm_ops[ sm_op ], BACKSQL_OC_NAME( oc ) );
330

331
		if ( backsql_attr_skip( ad, sm_values ) ) {
332
333
334
335
			Debug( LDAP_DEBUG_TRACE, "   backsql_modify_internal(): "
				"skipping attribute \"%s\"\n",
				ad->ad_cname.bv_val, 0, 0 );

336
337
338
339
340
341
342
343
			continue;
		}

  		at = backsql_ad2at( oc, ad );
		if ( at == NULL ) {
			Debug( LDAP_DEBUG_TRACE, "   backsql_modify_internal(): "
				"attribute \"%s\" is not registered "
				"in objectClass \"%s\"\n",
344
				ad->ad_cname.bv_val, BACKSQL_OC_NAME( oc ) );
345
346
347
348
349
350
351
352
353
354
355

			if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
				rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
				rs->sr_text = "operation not permitted "
					"within namingContext";
				goto done;
			}

			continue;
		}
  
356
		switch ( sm_op ) {
357
358
359
		case LDAP_MOD_REPLACE: {
			Debug( LDAP_DEBUG_TRACE, "   backsql_modify_internal(): "
				"replacing values for attribute \"%s\"\n",
360
				at->bam_ad->ad_cname.bv_val );
361
362
363
364
365
366
367

			if ( at->bam_add_proc == NULL ) {
				Debug( LDAP_DEBUG_TRACE,
					"   backsql_modify_internal(): "
					"add procedure is not defined "
					"for attribute \"%s\" "
					"- unable to perform replacements\n",
368
					at->bam_ad->ad_cname.bv_val );
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385

				if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
					rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
					rs->sr_text = "operation not permitted "
						"within namingContext";
					goto done;
				}

				break;
			}

			if ( at->bam_delete_proc == NULL ) {
				if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
					Debug( LDAP_DEBUG_TRACE,
						"   backsql_modify_internal(): "
						"delete procedure is not defined "
						"for attribute \"%s\"\n",
386
						at->bam_ad->ad_cname.bv_val );
387
388
389
390
391
392
393
394
395
396
397
398

					rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
					rs->sr_text = "operation not permitted "
						"within namingContext";
					goto done;
				}

				Debug( LDAP_DEBUG_TRACE,
					"   backsql_modify_internal(): "
					"delete procedure is not defined "
					"for attribute \"%s\" "
					"- adding only\n",
399
					at->bam_ad->ad_cname.bv_val );
400
401
402

				goto add_only;
			}
403

404
del_all:
405
406
407
			rs->sr_err = backsql_modify_delete_all_values( op, rs, dbh, e_id, at );
			if ( rs->sr_err != LDAP_SUCCESS ) {
				goto done;
408
			}
409
410

			/* LDAP_MOD_DELETE gets here if all values must be deleted */
411
			if ( sm_op == LDAP_MOD_DELETE ) {
412
413
				break;
			}
414
415
416
417
418
419
	       	}

		/*
		 * PASSTHROUGH - to add new attributes -- do NOT add break
		 */
		case LDAP_MOD_ADD:
420
		/* case SLAP_MOD_SOFTADD: */
421
		/* case SLAP_MOD_ADD_IF_NOT_PRESENT: */
422
423
424
425
426
427
add_only:;
			if ( at->bam_add_proc == NULL ) {
				Debug( LDAP_DEBUG_TRACE,
					"   backsql_modify_internal(): "
					"add procedure is not defined "
					"for attribute \"%s\"\n",
428
					at->bam_ad->ad_cname.bv_val );
429
430
431
432
433
434
435
436
437
438
439
440
441

				if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
					rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
					rs->sr_text = "operation not permitted "
						"within namingContext";
					goto done;
				}

				break;
			}
			
			Debug( LDAP_DEBUG_TRACE, "   backsql_modify_internal(): "
				"adding new values for attribute \"%s\"\n",
442
				at->bam_ad->ad_cname.bv_val );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
443
444
445
446

			/* can't add a NULL val array */
			assert( sm_values != NULL );
			
447
448
449
450
			for ( i = 0, at_val = sm_values;
					!BER_BVISNULL( at_val ); 
					i++, at_val++ )
			{
451
452
453
454
455
456
457
				SQLHSTMT	sth = SQL_NULL_HSTMT;
				/* first parameter position, parameter order */
				SQLUSMALLINT	pno = 0,
						po;
				/* procedure return code */
				int		prc = LDAP_SUCCESS;

458
459
460
461
				rc = backsql_Prepare( dbh, &sth, at->bam_add_proc, 0 );
				if ( rc != SQL_SUCCESS ) {
					Debug( LDAP_DEBUG_TRACE,
						"   backsql_modify_internal(): "
462
						"error preparing add query\n" );
463
					backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
464
465
466
467
468
469

					rs->sr_err = LDAP_OTHER;
					rs->sr_text = "SQL-backend error";
					goto done;
				}

470
471
				if ( BACKSQL_IS_ADD( at->bam_expect_return ) ) {
					pno = 1;
472
473
474
475
476
477
	      				rc = backsql_BindParamInt( sth, 1,
						SQL_PARAM_OUTPUT, &prc );
					if ( rc != SQL_SUCCESS ) {
						Debug( LDAP_DEBUG_TRACE,
							"   backsql_modify_internal(): "
							"error binding output parameter for %s[%d]\n",
478
							at->bam_ad->ad_cname.bv_val, i );
479
						backsql_PrintErrors( bi->sql_db_env, dbh, 
480
481
482
483
484
485
486
							sth, rc );
						SQLFreeStmt( sth, SQL_DROP );

						rs->sr_text = "SQL-backend error";
						rs->sr_err = LDAP_OTHER;
						goto done;
					}
487
488
				}
				po = ( BACKSQL_IS_ADD( at->bam_param_order ) ) > 0;
489
490
491
492
493
494
				rc = backsql_BindParamID( sth, pno + 1 + po,
					SQL_PARAM_INPUT, &e_id->eid_keyval );
				if ( rc != SQL_SUCCESS ) {
					Debug( LDAP_DEBUG_TRACE,
						"   backsql_modify_internal(): "
						"error binding keyval parameter for %s[%d]\n",
495
						at->bam_ad->ad_cname.bv_val, i );
496
					backsql_PrintErrors( bi->sql_db_env, dbh, 
497
498
499
500
501
502
503
						sth, rc );
					SQLFreeStmt( sth, SQL_DROP );

					rs->sr_text = "SQL-backend error";
					rs->sr_err = LDAP_OTHER;
					goto done;
				}
504

505
506
				Debug( LDAP_DEBUG_TRACE,
					"   backsql_modify_internal(): "
507
508
					"arg(%d)=" BACKSQL_IDFMT "\n", 
					pno + 1 + po,
509
					BACKSQL_IDARG(e_id->eid_keyval) );
510
511
512
513
514

				/*
				 * check for syntax needed here
				 * maybe need binary bind?
				 */
515
516
517
518
519
520
				rc = backsql_BindParamBerVal( sth, pno + 2 - po,
					SQL_PARAM_INPUT, at_val );
				if ( rc != SQL_SUCCESS ) {
					Debug( LDAP_DEBUG_TRACE,
						"   backsql_modify_internal(): "
						"error binding value parameter for %s[%d]\n",
521
						at->bam_ad->ad_cname.bv_val, i );
522
					backsql_PrintErrors( bi->sql_db_env, dbh, 
523
524
525
526
527
528
529
						sth, rc );
					SQLFreeStmt( sth, SQL_DROP );

					rs->sr_text = "SQL-backend error";
					rs->sr_err = LDAP_OTHER;
					goto done;
				}
530
531
				Debug( LDAP_DEBUG_TRACE,
					"   backsql_modify_internal(): "
532
					"arg(%d)=\"%s\"; executing \"%s\"\n", 
533
534
535
					pno + 2 - po, at_val->bv_val,
					at->bam_add_proc );

536
				rc = SQLExecute( sth );
537
538
539
540
				if ( rc == SQL_SUCCESS && prc == LDAP_SUCCESS ) {
					rs->sr_err = LDAP_SUCCESS;

				} else {
541
542
					Debug( LDAP_DEBUG_TRACE,
						"   backsql_modify_internal(): "
543
544
						"add_proc execution failed "
						"(rc=%d, prc=%d)\n",
545
						rc, prc );
546
547
548
549
					if ( prc != LDAP_SUCCESS ) {
						/* SQL procedure executed fine 
						 * but returned an error */
						SQLFreeStmt( sth, SQL_DROP );
550

551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
						rs->sr_err = BACKSQL_SANITIZE_ERROR( prc );
						rs->sr_text = at->bam_ad->ad_cname.bv_val;
						return rs->sr_err;
					
					} else {
						backsql_PrintErrors( bi->sql_db_env, dbh,
								sth, rc );
						if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) 
						{
							SQLFreeStmt( sth, SQL_DROP );

							rs->sr_err = LDAP_OTHER;
							rs->sr_text = "SQL-backend error";
							goto done;
						}
					}
567
568
569
570
571
572
				}
				SQLFreeStmt( sth, SQL_DROP );
			}
			break;
			
	      	case LDAP_MOD_DELETE:
573
		/* case SLAP_MOD_SOFTDEL: */
574
575
576
577
578
			if ( at->bam_delete_proc == NULL ) {
				Debug( LDAP_DEBUG_TRACE,
					"   backsql_modify_internal(): "
					"delete procedure is not defined "
					"for attribute \"%s\"\n",
579
					at->bam_ad->ad_cname.bv_val );
580
581
582
583
584
585
586
587
588
589
590

				if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
					rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
					rs->sr_text = "operation not permitted "
						"within namingContext";
					goto done;
				}

				break;
			}

591
			if ( sm_values == NULL ) {
592
593
594
595
596
				Debug( LDAP_DEBUG_TRACE,
					"   backsql_modify_internal(): "
					"no values given to delete "
					"for attribute \"%s\" "
					"-- deleting all values\n",
597
					at->bam_ad->ad_cname.bv_val );
598
599
600
601
602
				goto del_all;
			}

			Debug( LDAP_DEBUG_TRACE, "   backsql_modify_internal(): "
				"deleting values for attribute \"%s\"\n",
603
				at->bam_ad->ad_cname.bv_val );
604

605
606
607
608
			for ( i = 0, at_val = sm_values;
					!BER_BVISNULL( at_val );
					i++, at_val++ )
			{
609
610
611
612
613
614
615
				SQLHSTMT	sth = SQL_NULL_HSTMT;
				/* first parameter position, parameter order */
				SQLUSMALLINT	pno = 0,
						po;
				/* procedure return code */
				int		prc = LDAP_SUCCESS;

616
617
618
619
				rc = backsql_Prepare( dbh, &sth, at->bam_delete_proc, 0 );
				if ( rc != SQL_SUCCESS ) {
					Debug( LDAP_DEBUG_TRACE,
						"   backsql_modify_internal(): "
620
						"error preparing delete query\n" );
621
					backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
622
623
624
625
626
627

					rs->sr_err = LDAP_OTHER;
					rs->sr_text = "SQL-backend error";
					goto done;
				}

628
629
				if ( BACKSQL_IS_DEL( at->bam_expect_return ) ) {
					pno = 1;
630
631
632
633
634
635
					rc = backsql_BindParamInt( sth, 1,
						SQL_PARAM_OUTPUT, &prc );
					if ( rc != SQL_SUCCESS ) {
						Debug( LDAP_DEBUG_TRACE,
							"   backsql_modify_internal(): "
							"error binding output parameter for %s[%d]\n",
636
							at->bam_ad->ad_cname.bv_val, i );
637
						backsql_PrintErrors( bi->sql_db_env, dbh, 
638
639
640
641
642
643
644
							sth, rc );
						SQLFreeStmt( sth, SQL_DROP );

						rs->sr_text = "SQL-backend error";
						rs->sr_err = LDAP_OTHER;
						goto done;
					}
645
646
				}
				po = ( BACKSQL_IS_DEL( at->bam_param_order ) ) > 0;
647
648
649
650
651
652
				rc = backsql_BindParamID( sth, pno + 1 + po,
					SQL_PARAM_INPUT, &e_id->eid_keyval );
				if ( rc != SQL_SUCCESS ) {
					Debug( LDAP_DEBUG_TRACE,
						"   backsql_modify_internal(): "
						"error binding keyval parameter for %s[%d]\n",
653
						at->bam_ad->ad_cname.bv_val, i );
654
					backsql_PrintErrors( bi->sql_db_env, dbh, 
655
656
657
658
659
660
661
						sth, rc );
					SQLFreeStmt( sth, SQL_DROP );

					rs->sr_text = "SQL-backend error";
					rs->sr_err = LDAP_OTHER;
					goto done;
				}
662

663
664
				Debug( LDAP_DEBUG_TRACE,
					"   backsql_modify_internal(): "
665
666
					"arg(%d)=" BACKSQL_IDFMT "\n", 
					pno + 1 + po,
667
					BACKSQL_IDARG(e_id->eid_keyval) );
668
669
670
671
672

				/*
				 * check for syntax needed here 
				 * maybe need binary bind?
				 */
673
674
675
676
677
678
				rc = backsql_BindParamBerVal( sth, pno + 2 - po,
					SQL_PARAM_INPUT, at_val );
				if ( rc != SQL_SUCCESS ) {
					Debug( LDAP_DEBUG_TRACE,
						"   backsql_modify_internal(): "
						"error binding value parameter for %s[%d]\n",
679
						at->bam_ad->ad_cname.bv_val, i );
680
					backsql_PrintErrors( bi->sql_db_env, dbh, 
681
682
683
						sth, rc );
					SQLFreeStmt( sth, SQL_DROP );

684
685
686
					rs->sr_text = "SQL-backend error";
					rs->sr_err = LDAP_OTHER;
					goto done;
687
				}
688
689
690
691

				Debug( LDAP_DEBUG_TRACE,
					"   backsql_modify_internal(): "
					"executing \"%s\"\n", 
692
					at->bam_delete_proc );
693
				rc = SQLExecute( sth );
694
695
696
697
698
				if ( rc == SQL_SUCCESS && prc == LDAP_SUCCESS )
				{
					rs->sr_err = LDAP_SUCCESS;
					
				} else {
699
700
701
					Debug( LDAP_DEBUG_TRACE,
						"   backsql_modify_internal(): "
						"delete_proc execution "
702
						"failed (rc=%d, prc=%d)\n",
703
						rc, prc );
704
705
706
707
708
709

					if ( prc != LDAP_SUCCESS ) {
						/* SQL procedure executed fine
						 * but returned an error */
						rs->sr_err = BACKSQL_SANITIZE_ERROR( prc );
						rs->sr_text = at->bam_ad->ad_cname.bv_val;
710
						goto done;
711
712
713
714
						
					} else {
						backsql_PrintErrors( bi->sql_db_env,
								dbh, sth, rc );
715
716
717
718
						SQLFreeStmt( sth, SQL_DROP );
						rs->sr_err = LDAP_OTHER;
						rs->sr_text = at->bam_ad->ad_cname.bv_val;
						goto done;
719
720
721
					}
				}
				SQLFreeStmt( sth, SQL_DROP );
722
723
724
725
726
			}
			break;

	      	case LDAP_MOD_INCREMENT:
			Debug( LDAP_DEBUG_TRACE, "   backsql_modify_internal(): "
727
				"increment not supported yet\n" );
728
729
730
731
			if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
				rs->sr_err = LDAP_OTHER;
				rs->sr_text = "SQL-backend error";
				goto done;
732
733
734
735
736
737
			}
			break;
		}
	}

done:;
738
739
740
	Debug( LDAP_DEBUG_TRACE, "<==backsql_modify_internal(): %d%s%s\n",
		rs->sr_err,
		rs->sr_text ? ": " : "",
741
742
743
744
745
746
747
748
		rs->sr_text ? rs->sr_text : "" );

	/*
	 * FIXME: should fail in case one change fails?
	 */
	return rs->sr_err;
}

749
750
751
752
753
754
755
static int
backsql_add_attr(
	Operation		*op,
	SlapReply		*rs,
	SQLHDBC 		dbh,
	backsql_oc_map_rec 	*oc,
	Attribute		*at,
756
	backsql_key_t		new_keyval )
757
758
759
760
761
762
763
{
	backsql_info		*bi = (backsql_info*)op->o_bd->be_private;
	backsql_at_map_rec	*at_rec = NULL;
	struct berval		*at_val;
	unsigned long		i;
	RETCODE			rc;
	SQLUSMALLINT		currpos;
764
	SQLHSTMT 		sth = SQL_NULL_HSTMT;
765
766
767
768

	at_rec = backsql_ad2at( oc, at->a_desc ); 
  
	if ( at_rec == NULL ) {
769
		Debug( LDAP_DEBUG_TRACE, "   backsql_add_attr(\"%s\"): "
770
771
			"attribute \"%s\" is not registered "
			"in objectclass \"%s\"\n",
772
			op->ora_e->e_name.bv_val,
773
774
775
776
777
778
779
780
781
782
783
784
785
			at->a_desc->ad_cname.bv_val,
			BACKSQL_OC_NAME( oc ) );

		if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
			rs->sr_text = "operation not permitted "
				"within namingContext";
			return rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
		}

		return LDAP_SUCCESS;
	}
	
	if ( at_rec->bam_add_proc == NULL ) {
786
		Debug( LDAP_DEBUG_TRACE, "   backsql_add_attr(\"%s\"): "
787
788
789
			"add procedure is not defined "
			"for attribute \"%s\" "
			"of structuralObjectClass \"%s\"\n",
790
			op->ora_e->e_name.bv_val,
791
792
793
794
795
796
797
798
799
800
801
802
803
			at->a_desc->ad_cname.bv_val,
			BACKSQL_OC_NAME( oc ) );

		if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
			rs->sr_text = "operation not permitted "
				"within namingContext";
			return rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
		}

		return LDAP_SUCCESS;
	}

	for ( i = 0, at_val = &at->a_vals[ i ];
804
		       	!BER_BVISNULL( at_val );
805
806
			i++, at_val = &at->a_vals[ i ] )
	{
807
808
809
810
		/* procedure return code */
		int		prc = LDAP_SUCCESS;
		/* first parameter #, parameter order */
		SQLUSMALLINT	pno, po;
811
812
813
814
815
816
		
		/*
		 * Do not deal with the objectClass that is used
		 * to build the entry
		 */
		if ( at->a_desc == slap_schema.si_ad_objectClass ) {
817
			if ( dn_match( at_val, &oc->bom_oc->soc_cname ) )
818
819
820
821
822
			{
				continue;
			}
		}

823
		rc = backsql_Prepare( dbh, &sth, at_rec->bam_add_proc, 0 );
824
		if ( rc != SQL_SUCCESS ) {
825
826
			rs->sr_text = "SQL-backend error";
			return rs->sr_err = LDAP_OTHER;
827
828
829
830
		}

		if ( BACKSQL_IS_ADD( at_rec->bam_expect_return ) ) {
			pno = 1;
831
832
833
834
			rc = backsql_BindParamInt( sth, 1, SQL_PARAM_OUTPUT, &prc );
			if ( rc != SQL_SUCCESS ) {
				Debug( LDAP_DEBUG_TRACE,
					"   backsql_add_attr(): "
835
					"error binding output parameter for %s[%lu]\n",
836
					at_rec->bam_ad->ad_cname.bv_val, i );
837
				backsql_PrintErrors( bi->sql_db_env, dbh, 
838
839
840
					sth, rc );
				SQLFreeStmt( sth, SQL_DROP );

841
842
				rs->sr_text = "SQL-backend error";
				return rs->sr_err = LDAP_OTHER;
843
844
			}

845
846
847
848
849
850
		} else {
			pno = 0;
		}

		po = ( BACKSQL_IS_ADD( at_rec->bam_param_order ) ) > 0;
		currpos = pno + 1 + po;
851
		rc = backsql_BindParamNumID( sth, currpos,
852
853
854
855
				SQL_PARAM_INPUT, &new_keyval );
		if ( rc != SQL_SUCCESS ) {
			Debug( LDAP_DEBUG_TRACE,
				"   backsql_add_attr(): "
856
				"error binding keyval parameter for %s[%lu]\n",
857
				at_rec->bam_ad->ad_cname.bv_val, i );
858
			backsql_PrintErrors( bi->sql_db_env, dbh, 
859
860
861
				sth, rc );
			SQLFreeStmt( sth, SQL_DROP );

862
863
			rs->sr_text = "SQL-backend error";
			return rs->sr_err = LDAP_OTHER;
864
865
		}

866
867
868
869
870
871
872
		currpos = pno + 2 - po;

		/*
		 * check for syntax needed here 
		 * maybe need binary bind?
		 */

873
874
875
876
		rc = backsql_BindParamBerVal( sth, currpos, SQL_PARAM_INPUT, at_val );
		if ( rc != SQL_SUCCESS ) {
			Debug( LDAP_DEBUG_TRACE,
				"   backsql_add_attr(): "
877
				"error binding value parameter for %s[%lu]\n",
878
				at_rec->bam_ad->ad_cname.bv_val, i );
879
			backsql_PrintErrors( bi->sql_db_env, dbh, 
880
881
882
				sth, rc );
			SQLFreeStmt( sth, SQL_DROP );

883
884
			rs->sr_text = "SQL-backend error";
			return rs->sr_err = LDAP_OTHER;
885
		}
886
887

#ifdef LDAP_DEBUG
888
889
890
891
		Debug(LDAP_DEBUG_TRACE,
		      "   backsql_add_attr(\"%s\"): " "executing \"%s\" val[%lu], id=" BACKSQL_IDNUMFMT "\n",
		      op->ora_e->e_name.bv_val, at_rec->bam_add_proc,
		      i, new_keyval );
892
#endif
893
		rc = SQLExecute( sth );
894
895
896
897
		if ( rc == SQL_SUCCESS && prc == LDAP_SUCCESS ) {
			rs->sr_err = LDAP_SUCCESS;

		} else {
898
			Debug( LDAP_DEBUG_TRACE,
899
				"   backsql_add_attr(\"%s\"): "
900
				"add_proc execution failed (rc=%d, prc=%d)\n", 
901
				op->ora_e->e_name.bv_val, rc, prc );
902
903
904
905
			if ( prc != LDAP_SUCCESS ) {
				/* SQL procedure executed fine
				 * but returned an error */
				rs->sr_err = BACKSQL_SANITIZE_ERROR( prc );
906
				rs->sr_text = op->ora_e->e_name.bv_val;
907
				SQLFreeStmt( sth, SQL_DROP );
908
909
910
911
912
				return rs->sr_err;

			} else {
				backsql_PrintErrors( bi->sql_db_env, dbh,
						sth, rc );
913
914
915
916
				rs->sr_err = LDAP_OTHER;
				rs->sr_text = op->ora_e->e_name.bv_val;
				SQLFreeStmt( sth, SQL_DROP );
				return rs->sr_err;
917
918
			}
		}
919
		SQLFreeStmt( sth, SQL_DROP );
920
921
922
923
924
	}

	return LDAP_SUCCESS;
}

925
926
927
928
int
backsql_add( Operation *op, SlapReply *rs )
{
	backsql_info		*bi = (backsql_info*)op->o_bd->be_private;
929
930
	SQLHDBC 		dbh = SQL_NULL_HDBC;
	SQLHSTMT 		sth = SQL_NULL_HSTMT;
931
	backsql_key_t		new_keyval = 0;
932
933
	RETCODE			rc;
	backsql_oc_map_rec 	*oc = NULL;
934
	backsql_srch_info	bsi = { 0 };
935
	Entry			p = { 0 }, *e = NULL;
936
937
	Attribute		*at,
				*at_objectClass = NULL;
938
	ObjectClass		*soc = NULL;
939
	struct berval		scname = BER_BVNULL;
940
	struct berval		pdn;
941
	struct berval		realdn = BER_BVNULL;
942
	int			colnum;
943
	slap_mask_t		mask;
944

945
946
947
	char			textbuf[ SLAP_TEXT_BUFLEN ];
	size_t			textlen = sizeof( textbuf );

948
949
950
951
952
#ifdef BACKSQL_SYNCPROV
	/*
	 * NOTE: fake successful result to force contextCSN to be bumped up
	 */
	if ( op->o_sync ) {
953
		char		buf[ LDAP_PVT_CSNSTR_BUFSIZE ];
Howard Chu's avatar
Howard Chu committed
954
		struct berval	csn;
955

Howard Chu's avatar
Howard Chu committed
956
957
958
		csn.bv_val = buf;
		csn.bv_len = sizeof( buf );
		slap_get_csn( op, &csn, 1 );
959
960
961
962
963
964
965
966
967
968

		rs->sr_err = LDAP_SUCCESS;
		send_ldap_result( op, rs );

		slap_graduate_commit_csn( op );

		return 0;
	}
#endif /* BACKSQL_SYNCPROV */

Pierangelo Masarati's avatar
Pierangelo Masarati committed
969
	Debug( LDAP_DEBUG_TRACE, "==>backsql_add(\"%s\")\n",
970
			op->ora_e->e_name.bv_val );
971
972

	/* check schema */
973
	if ( BACKSQL_CHECK_SCHEMA( bi ) ) {
974
975
		char		textbuf[ SLAP_TEXT_BUFLEN ] = { '\0' };

976
		rs->sr_err = entry_schema_check( op, op->ora_e, 0, 1, NULL,
977
			&rs->sr_text, textbuf, sizeof( textbuf ) );
978
		if ( rs->sr_err != LDAP_SUCCESS ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
979
			Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
980
				"entry failed schema check -- aborting\n",
981
				op->ora_e->e_name.bv_val );
982
			e = NULL;
983
984
985
986
			goto done;
		}
	}

987
988
	slap_add_opattrs( op, &rs->sr_text, textbuf, textlen, 1 );

989
990
991
992
993
	if ( get_assert( op ) &&
		( test_filter( op, op->ora_e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
	{
		Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
			"assertion control failed -- aborting\n",
994
			op->ora_e->e_name.bv_val );
995
996
997
998
999
		e = NULL;
		rs->sr_err = LDAP_ASSERTION_FAILED;
		goto done;
	}

1000
	/* search structuralObjectClass */
1001
	for ( at = op->ora_e->e_attrs; at != NULL; at = at->a_next ) {
1002
1003
1004
1005
1006
1007
		if ( at->a_desc == slap_schema.si_ad_structuralObjectClass ) {
			break;
		}
	}

	/* there must exist */
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
	if ( at == NULL ) {
		char		buf[ SLAP_TEXT_BUFLEN ];
		const char	*text;

		/* search structuralObjectClass */
		for ( at = op->ora_e->e_attrs; at != NULL; at = at->a_next ) {
			if ( at->a_desc == slap_schema.si_ad_objectClass ) {
				break;
			}
		}

		if ( at == NULL ) {
			Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
				"no objectClass\n",
1022
				op->ora_e->e_name.bv_val );
1023
1024
1025
1026
1027
			rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
			e = NULL;
			goto done;
		}

1028
		rs->sr_err = structural_class( at->a_vals, &soc, NULL,
1029
				&text, buf, sizeof( buf ), op->o_tmpmemctx );
1030
1031
1032
1033
1034
1035
1036
		if ( rs->sr_err != LDAP_SUCCESS ) {
			Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
				"%s (%d)\n",
				op->ora_e->e_name.bv_val, text, rs->sr_err );
			e = NULL;
			goto done;
		}
1037
		scname = soc->soc_cname;
1038
1039
1040
1041

	} else {
		scname = at->a_vals[0];
	}
1042
1043

	/* I guess we should play with sub/supertypes to find a suitable oc */
1044
	oc = backsql_name2oc( bi, &scname );
1045
1046

	if ( oc == NULL ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1047
1048
		Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
			"cannot map structuralObjectClass \"%s\" -- aborting\n",
1049
			op->ora_e->e_name.bv_val,
1050
			scname.bv_val );
1051
1052
		rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
		rs->sr_text = "operation not permitted within namingContext";
1053
		e = NULL;
1054
1055
1056
1057
		goto done;
	}

	if ( oc->bom_create_proc == NULL ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1058
1059
1060
		Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
			"create procedure is not defined "
			"for structuralObjectClass \"%s\" - aborting\n",
1061
			op->ora_e->e_name.bv_val,
1062
			scname.bv_val );
1063
1064
		rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
		rs->sr_text = "operation not permitted within namingContext";
1065
		e = NULL;
1066
1067
1068
1069
		goto done;

	} else if ( BACKSQL_CREATE_NEEDS_SELECT( bi )
			&& oc->bom_create_keyval == NULL ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1070
		Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
1071
			"create procedure needs select procedure, "
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1072
1073
			"but none is defined for structuralObjectClass \"%s\" "
			"- aborting\n",
1074
			op->ora_e->e_name.bv_val,
1075
			scname.bv_val );
1076
1077
		rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
		rs->sr_text = "operation not permitted within namingContext";
1078
		e = NULL;
1079
1080
1081
		goto done;
	}

1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
	/* check write access */
	if ( !access_allowed_mask( op, op->ora_e,
				slap_schema.si_ad_entry,
				NULL, ACL_WADD, NULL, &mask ) )
	{
		rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
		e = op->ora_e;
		goto done;
	}

1092
1093
	rs->sr_err = backsql_get_db_conn( op, &dbh );
	if ( rs->sr_err != LDAP_SUCCESS ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1094
		Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
1095
			"could not get connection handle - exiting\n", 
1096
			op->ora_e->e_name.bv_val );
1097
1098