]> git.sur5r.net Git - openldap/blob - servers/slapd/back-sql/entry-id.c
fix access checking; fix operational attrs addition
[openldap] / servers / slapd / back-sql / entry-id.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1999-2005 The OpenLDAP Foundation.
5  * Portions Copyright 1999 Dmitry Kovalev.
6  * Portions Copyright 2002 Pierangelo Masarati.
7  * Portions Copyright 2004 Mark Adamson.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted only as authorized by the OpenLDAP
12  * Public License.
13  *
14  * A copy of this license is available in the file LICENSE in the
15  * top-level directory of the distribution or, alternatively, at
16  * <http://www.OpenLDAP.org/license.html>.
17  */
18 /* ACKNOWLEDGEMENTS:
19  * This work was initially developed by Dmitry Kovalev for inclusion
20  * by OpenLDAP Software.  Additional significant contributors include
21  * Pierangelo Masarati and Mark Adamson.
22  */
23
24 #include "portable.h"
25
26 #include <stdio.h>
27 #include <sys/types.h>
28 #include "ac/string.h"
29
30 #include "slap.h"
31 #include "proto-sql.h"
32
33 #ifdef BACKSQL_ARBITRARY_KEY
34 struct berval backsql_baseObject_bv = BER_BVC( BACKSQL_BASEOBJECT_IDSTR );
35 #endif /* BACKSQL_ARBITRARY_KEY */
36
37 backsql_entryID *
38 backsql_free_entryID( Operation *op, backsql_entryID *id, int freeit )
39 {
40         backsql_entryID         *next;
41
42         assert( id != NULL );
43
44         next = id->eid_next;
45
46         if ( !BER_BVISNULL( &id->eid_ndn ) ) {
47                 if ( !BER_BVISNULL( &id->eid_dn )
48                                 && id->eid_dn.bv_val != id->eid_ndn.bv_val )
49                 {
50                         op->o_tmpfree( id->eid_dn.bv_val, op->o_tmpmemctx );
51                         BER_BVZERO( &id->eid_dn );
52                 }
53
54                 op->o_tmpfree( id->eid_ndn.bv_val, op->o_tmpmemctx );
55                 BER_BVZERO( &id->eid_ndn );
56         }
57
58 #ifdef BACKSQL_ARBITRARY_KEY
59         if ( !BER_BVISNULL( &id->eid_id ) ) {
60                 op->o_tmpfree( id->eid_id.bv_val, op->o_tmpmemctx );
61                 BER_BVZERO( &id->eid_id );
62         }
63
64         if ( !BER_BVISNULL( &id->eid_keyval ) ) {
65                 op->o_tmpfree( id->eid_keyval.bv_val, op->o_tmpmemctx );
66                 BER_BVZERO( &id->eid_keyval );
67         }
68 #endif /* BACKSQL_ARBITRARY_KEY */
69
70         if ( freeit ) {
71                 op->o_tmpfree( id, op->o_tmpmemctx );
72         }
73
74         return next;
75 }
76
77 /*
78  * NOTE: the dn must be normalized
79  */
80 int
81 backsql_dn2id(
82         Operation               *op,
83         SlapReply               *rs,
84         SQLHDBC                 dbh,
85         struct berval           *ndn,
86         backsql_entryID         *id,
87         int                     matched,
88         int                     muck )
89 {
90         backsql_info            *bi = op->o_bd->be_private;
91         SQLHSTMT                sth = SQL_NULL_HSTMT; 
92         BACKSQL_ROW_NTS         row;
93         RETCODE                 rc;
94         int                     res;
95         struct berval           realndn = BER_BVNULL;
96
97         /* TimesTen */
98         char                    upperdn[ BACKSQL_MAX_DN_LEN + 1 ];
99         struct berval           tbbDN;
100         int                     i, j;
101
102         /*
103          * NOTE: id can be NULL; in this case, the function
104          * simply checks whether the DN can be successfully 
105          * turned into an ID, returning LDAP_SUCCESS for
106          * positive cases, or the most appropriate error
107          */
108
109         Debug( LDAP_DEBUG_TRACE, "==>backsql_dn2id(\"%s\")%s%s\n", 
110                         ndn->bv_val, id == NULL ? " (no ID expected)" : "",
111                         matched ? " matched expected" : "" );
112
113         if ( id ) {
114                 /* NOTE: trap inconsistencies */
115                 assert( BER_BVISNULL( &id->eid_ndn ) );
116         }
117
118         if ( ndn->bv_len > BACKSQL_MAX_DN_LEN ) {
119                 Debug( LDAP_DEBUG_TRACE, 
120                         "   backsql_dn2id(\"%s\"): DN length=%ld "
121                         "exceeds max DN length %d:\n",
122                         ndn->bv_val, ndn->bv_len, BACKSQL_MAX_DN_LEN );
123                 return LDAP_OTHER;
124         }
125
126         /* return baseObject if available and matches */
127         /* FIXME: if ndn is already mucked, we cannot check this */
128         if ( bi->sql_baseObject != NULL &&
129                         dn_match( ndn, &bi->sql_baseObject->e_nname ) )
130         {
131                 if ( id != NULL ) {
132 #ifdef BACKSQL_ARBITRARY_KEY
133                         ber_dupbv_x( &id->eid_id, &backsql_baseObject_bv,
134                                         op->o_tmpmemctx );
135                         ber_dupbv_x( &id->eid_keyval, &backsql_baseObject_bv,
136                                         op->o_tmpmemctx );
137 #else /* ! BACKSQL_ARBITRARY_KEY */
138                         id->eid_id = BACKSQL_BASEOBJECT_ID;
139                         id->eid_keyval = BACKSQL_BASEOBJECT_KEYVAL;
140 #endif /* ! BACKSQL_ARBITRARY_KEY */
141                         id->eid_oc_id = BACKSQL_BASEOBJECT_OC;
142
143                         ber_dupbv_x( &id->eid_ndn, &bi->sql_baseObject->e_nname,
144                                         op->o_tmpmemctx );
145                         ber_dupbv_x( &id->eid_dn, &bi->sql_baseObject->e_name,
146                                         op->o_tmpmemctx );
147
148                         id->eid_next = NULL;
149                 }
150
151                 return LDAP_SUCCESS;
152         }
153         
154         /* begin TimesTen */
155         Debug( LDAP_DEBUG_TRACE, "   backsql_dn2id(\"%s\"): id_query \"%s\"\n",
156                         ndn->bv_val, bi->sql_id_query, 0 );
157         assert( bi->sql_id_query != NULL );
158         rc = backsql_Prepare( dbh, &sth, bi->sql_id_query, 0 );
159         if ( rc != SQL_SUCCESS ) {
160                 Debug( LDAP_DEBUG_TRACE, 
161                         "   backsql_dn2id(\"%s\"): "
162                         "error preparing SQL:\n   %s", 
163                         ndn->bv_val, bi->sql_id_query, 0 );
164                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
165                 res = LDAP_OTHER;
166                 goto done;
167         }
168
169         realndn = *ndn;
170         if ( muck ) {
171                 if ( backsql_api_dn2odbc( op, rs, &realndn ) ) {
172                         Debug( LDAP_DEBUG_TRACE, "   backsql_dn2id(\"%s\"): "
173                                 "backsql_api_dn2odbc(\"%s\") failed\n", 
174                                 ndn->bv_val, realndn.bv_val, 0 );
175                         res = LDAP_OTHER;
176                         goto done;
177                 }
178         }
179
180         if ( BACKSQL_HAS_LDAPINFO_DN_RU( bi ) ) {
181                 /*
182                  * Prepare an upper cased, byte reversed version 
183                  * that can be searched using indexes
184                  */
185
186                 for ( i = 0, j = realndn.bv_len - 1; realndn.bv_val[ i ]; i++, j--)
187                 {
188                         upperdn[ i ] = realndn.bv_val[ j ];
189                 }
190                 upperdn[ i ] = '\0';
191                 ldap_pvt_str2upper( upperdn );
192
193                 Debug( LDAP_DEBUG_TRACE, "   backsql_dn2id(\"%s\"): "
194                                 "upperdn=\"%s\"\n",
195                                 ndn->bv_val, upperdn, 0 );
196                 ber_str2bv( upperdn, 0, 0, &tbbDN );
197
198         } else {
199                 if ( BACKSQL_USE_REVERSE_DN( bi ) ) {
200                         AC_MEMCPY( upperdn, realndn.bv_val, realndn.bv_len + 1 );
201                         ldap_pvt_str2upper( upperdn );
202                         Debug( LDAP_DEBUG_TRACE,
203                                 "   backsql_dn2id(\"%s\"): "
204                                 "upperdn=\"%s\"\n",
205                                 ndn->bv_val, upperdn, 0 );
206                         ber_str2bv( upperdn, 0, 0, &tbbDN );
207
208                 } else {
209                         tbbDN = realndn;
210                 }
211         }
212
213         rc = backsql_BindParamBerVal( sth, 1, SQL_PARAM_INPUT, &tbbDN );
214         if ( rc != SQL_SUCCESS) {
215                 /* end TimesTen */ 
216                 Debug( LDAP_DEBUG_TRACE, "   backsql_dn2id(\"%s\"): "
217                         "error binding dn=\"%s\" parameter:\n", 
218                         ndn->bv_val, tbbDN.bv_val, 0 );
219                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
220                 res = LDAP_OTHER;
221                 goto done;
222         }
223
224         rc = SQLExecute( sth );
225         if ( rc != SQL_SUCCESS ) {
226                 Debug( LDAP_DEBUG_TRACE, "   backsql_dn2id(\"%s\"): "
227                         "error executing query (\"%s\", \"%s\"):\n", 
228                         ndn->bv_val, bi->sql_id_query, tbbDN.bv_val );
229                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
230                 res = LDAP_OTHER;
231                 goto done;
232         }
233
234         backsql_BindRowAsStrings_x( sth, &row, op->o_tmpmemctx );
235         rc = SQLFetch( sth );
236         if ( BACKSQL_SUCCESS( rc ) ) {
237                 char    buf[ SLAP_TEXT_BUFLEN ];
238
239 #ifdef LDAP_DEBUG
240                 snprintf( buf, sizeof(buf),
241                         "id=%s keyval=%s oc_id=%s dn=%s",
242                         row.cols[ 0 ], row.cols[ 1 ],
243                         row.cols[ 2 ], row.cols[ 3 ] );
244                 Debug( LDAP_DEBUG_TRACE,
245                         "   backsql_dn2id(\"%s\"): %s\n",
246                         ndn->bv_val, buf, 0 );
247 #endif /* LDAP_DEBUG */
248
249                 res = LDAP_SUCCESS;
250                 if ( id != NULL ) {
251                         struct berval   dn;
252
253 #ifdef BACKSQL_ARBITRARY_KEY
254                         ber_str2bv_x( row.cols[ 0 ], 0, 1, &id->eid_id,
255                                         op->o_tmpmemctx );
256                         ber_str2bv_x( row.cols[ 1 ], 0, 1, &id->eid_keyval,
257                                         op->o_tmpmemctx );
258 #else /* ! BACKSQL_ARBITRARY_KEY */
259                         id->eid_id = strtol( row.cols[ 0 ], NULL, 0 );
260                         id->eid_keyval = strtol( row.cols[ 1 ], NULL, 0 );
261 #endif /* ! BACKSQL_ARBITRARY_KEY */
262                         id->eid_oc_id = strtol( row.cols[ 2 ], NULL, 0 );
263
264                         ber_str2bv( row.cols[ 3 ], 0, 0, &dn );
265
266                         if ( backsql_api_odbc2dn( op, rs, &dn ) ) {
267                                 res = LDAP_OTHER;
268
269                         } else {
270                                 res = dnPrettyNormal( NULL, &dn,
271                                                 &id->eid_dn, &id->eid_ndn,
272                                                 op->o_tmpmemctx );
273                                 if ( res != LDAP_SUCCESS ) {
274                                         Debug( LDAP_DEBUG_TRACE,
275                                                 "   backsql_dn2id(\"%s\"): "
276                                                 "dnPrettyNormal failed (%d: %s)\n",
277                                                 realndn.bv_val, res,
278                                                 ldap_err2string( res ) );
279
280                                         /* cleanup... */
281                                         (void)backsql_free_entryID( op, id, 0 );
282                                 }
283
284                                 if ( dn.bv_val != row.cols[ 3 ] ) {
285                                         free( dn.bv_val );
286                                 }
287                         }
288
289                         id->eid_next = NULL;
290                 }
291
292         } else {
293                 res = LDAP_NO_SUCH_OBJECT;
294                 if ( matched ) {
295                         struct berval   pdn = *ndn;
296
297                         /*
298                          * Look for matched
299                          */
300                         rs->sr_matched = NULL;
301                         while ( !be_issuffix( op->o_bd, &pdn ) ) {
302                                 char            *matchedDN = NULL;
303         
304                                 dnParent( &pdn, &pdn );
305         
306                                 /*
307                                  * Empty DN ("") defaults to LDAP_SUCCESS
308                                  */
309                                 rs->sr_err = backsql_dn2id( op, rs, dbh, &pdn, id, 0, 1 );
310                                 switch ( rs->sr_err ) {
311                                 case LDAP_NO_SUCH_OBJECT:
312                                         /* try another one */
313                                         break;
314                                         
315                                 case LDAP_SUCCESS:
316                                         matchedDN = pdn.bv_val;
317                                         /* fail over to next case */
318         
319                                 default:
320                                         rs->sr_err = LDAP_NO_SUCH_OBJECT;
321                                         rs->sr_matched = matchedDN;
322                                         goto done;
323                                 } 
324                         }
325                 }
326         }
327
328 done:;
329         backsql_FreeRow_x( &row, op->o_tmpmemctx );
330
331         Debug( LDAP_DEBUG_TRACE,
332                 "<==backsql_dn2id(\"%s\"): err=%d\n",
333                 ndn->bv_val, res, 0 );
334         if ( sth != SQL_NULL_HSTMT ) {
335                 SQLFreeStmt( sth, SQL_DROP );
336         }
337
338         if ( !BER_BVISNULL( &realndn ) && realndn.bv_val != ndn->bv_val ) {
339                 ch_free( realndn.bv_val );
340         }
341
342         return res;
343 }
344
345 int
346 backsql_count_children(
347         Operation               *op,
348         SQLHDBC                 dbh,
349         struct berval           *dn,
350         unsigned long           *nchildren )
351 {
352         backsql_info            *bi = (backsql_info *)op->o_bd->be_private;
353         SQLHSTMT                sth = SQL_NULL_HSTMT;
354         BACKSQL_ROW_NTS         row;
355         RETCODE                 rc;
356         int                     res = LDAP_SUCCESS;
357
358         Debug( LDAP_DEBUG_TRACE, "==>backsql_count_children(): dn=\"%s\"\n", 
359                         dn->bv_val, 0, 0 );
360
361         if ( dn->bv_len > BACKSQL_MAX_DN_LEN ) {
362                 Debug( LDAP_DEBUG_TRACE, 
363                         "backsql_count_children(): DN \"%s\" (%ld bytes) "
364                         "exceeds max DN length (%d):\n",
365                         dn->bv_val, dn->bv_len, BACKSQL_MAX_DN_LEN );
366                 return LDAP_OTHER;
367         }
368         
369         /* begin TimesTen */
370         Debug(LDAP_DEBUG_TRACE, "children id query \"%s\"\n", 
371                         bi->sql_has_children_query, 0, 0);
372         assert( bi->sql_has_children_query != NULL );
373         rc = backsql_Prepare( dbh, &sth, bi->sql_has_children_query, 0 );
374         if ( rc != SQL_SUCCESS ) {
375                 Debug( LDAP_DEBUG_TRACE, 
376                         "backsql_count_children(): error preparing SQL:\n%s", 
377                         bi->sql_has_children_query, 0, 0);
378                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
379                 SQLFreeStmt( sth, SQL_DROP );
380                 return LDAP_OTHER;
381         }
382
383         rc = backsql_BindParamBerVal( sth, 1, SQL_PARAM_INPUT, dn );
384         if ( rc != SQL_SUCCESS) {
385                 /* end TimesTen */ 
386                 Debug( LDAP_DEBUG_TRACE, "backsql_count_children(): "
387                         "error binding dn=\"%s\" parameter:\n", 
388                         dn->bv_val, 0, 0 );
389                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
390                 SQLFreeStmt( sth, SQL_DROP );
391                 return LDAP_OTHER;
392         }
393
394         rc = SQLExecute( sth );
395         if ( rc != SQL_SUCCESS ) {
396                 Debug( LDAP_DEBUG_TRACE, "backsql_count_children(): "
397                         "error executing query (\"%s\", \"%s\"):\n", 
398                         bi->sql_has_children_query, dn->bv_val, 0 );
399                 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
400                 SQLFreeStmt( sth, SQL_DROP );
401                 return LDAP_OTHER;
402         }
403
404         backsql_BindRowAsStrings_x( sth, &row, op->o_tmpmemctx );
405         
406         rc = SQLFetch( sth );
407         if ( BACKSQL_SUCCESS( rc ) ) {
408                 char *end;
409
410                 *nchildren = strtol( row.cols[ 0 ], &end, 0 );
411                 if ( end[ 0 ] != '\0' && end[0] != '.' ) {
412                         /* FIXME: braindead RDBMSes return
413                          * a fractional number from COUNT!
414                          */
415                         res = LDAP_OTHER;
416                 }
417
418         } else {
419                 res = LDAP_OTHER;
420         }
421         backsql_FreeRow_x( &row, op->o_tmpmemctx );
422
423         SQLFreeStmt( sth, SQL_DROP );
424
425         Debug( LDAP_DEBUG_TRACE, "<==backsql_count_children(): %lu\n",
426                         *nchildren, 0, 0 );
427
428         return res;
429 }
430
431 int
432 backsql_has_children(
433         Operation               *op,
434         SQLHDBC                 dbh,
435         struct berval           *dn )
436 {
437         unsigned long   nchildren;
438         int             rc;
439
440         rc = backsql_count_children( op, dbh, dn, &nchildren );
441
442         if ( rc == LDAP_SUCCESS ) {
443                 return nchildren > 0 ? LDAP_COMPARE_TRUE : LDAP_COMPARE_FALSE;
444         }
445
446         return rc;
447 }
448
449 static int
450 backsql_get_attr_vals( void *v_at, void *v_bsi )
451 {
452         backsql_at_map_rec      *at = v_at;
453         backsql_srch_info       *bsi = v_bsi;
454         backsql_info            *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
455         RETCODE                 rc;
456         SQLHSTMT                sth = SQL_NULL_HSTMT;
457         BACKSQL_ROW_NTS         row;
458         unsigned long           i,
459                                 k = 0,
460                                 oldcount = 0,
461                                 res = 0;
462 #ifdef BACKSQL_COUNTQUERY
463         unsigned long           count,
464                                 countsize = sizeof( count ),
465                                 j,
466                                 append = 0;
467         Attribute               *attr = NULL;
468
469         slap_mr_normalize_func          *normfunc = NULL;
470 #endif /* BACKSQL_COUNTQUERY */
471 #ifdef BACKSQL_PRETTY_VALIDATE
472         slap_syntax_validate_func       *validate = NULL;
473         slap_syntax_transform_func      *pretty = NULL;
474 #endif /* BACKSQL_PRETTY_VALIDATE */
475
476         assert( at != NULL );
477         assert( bsi != NULL );
478
479 #ifdef BACKSQL_ARBITRARY_KEY
480         Debug( LDAP_DEBUG_TRACE, "==>backsql_get_attr_vals(): "
481                 "oc=\"%s\" attr=\"%s\" keyval=%s\n",
482                 BACKSQL_OC_NAME( bsi->bsi_oc ), at->bam_ad->ad_cname.bv_val, 
483                 bsi->bsi_c_eid->eid_keyval.bv_val );
484 #else /* ! BACKSQL_ARBITRARY_KEY */
485         Debug( LDAP_DEBUG_TRACE, "==>backsql_get_attr_vals(): "
486                 "oc=\"%s\" attr=\"%s\" keyval=%ld\n",
487                 BACKSQL_OC_NAME( bsi->bsi_oc ), at->bam_ad->ad_cname.bv_val, 
488                 bsi->bsi_c_eid->eid_keyval );
489 #endif /* ! BACKSQL_ARBITRARY_KEY */
490
491 #ifdef BACKSQL_PRETTY_VALIDATE
492         validate = at->bam_ad->ad_type->sat_syntax->ssyn_validate;
493         pretty =  at->bam_ad->ad_type->sat_syntax->ssyn_pretty;
494
495         if ( validate == NULL && pretty == NULL ) {
496                 return 1;
497         }
498 #endif /* BACKSQL_PRETTY_VALIDATE */
499
500 #ifdef BACKSQL_COUNTQUERY
501         if ( at->bam_ad->ad_type->sat_equality ) {
502                 normfunc = at->bam_ad->ad_type->sat_equality->smr_normalize;
503         }
504
505         /* Count how many rows will be returned. This avoids memory 
506          * fragmentation that can result from loading the values in 
507          * one by one and using realloc() 
508          */
509         rc = backsql_Prepare( bsi->bsi_dbh, &sth, at->bam_countquery, 0 );
510         if ( rc != SQL_SUCCESS ) {
511                 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
512                         "error preparing count query: %s\n",
513                         at->bam_countquery, 0, 0 );
514                 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
515                 return 1;
516         }
517
518         rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT,
519                         &bsi->bsi_c_eid->eid_keyval );
520         if ( rc != SQL_SUCCESS ) {
521                 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
522                         "error binding key value parameter\n", 0, 0, 0 );
523                 SQLFreeStmt( sth, SQL_DROP );
524                 return 1;
525         }
526
527         rc = SQLExecute( sth );
528         if ( ! BACKSQL_SUCCESS( rc ) ) {
529                 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
530                         "error executing attribute count query '%s'\n",
531                         at->bam_countquery, 0, 0 );
532                 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
533                 SQLFreeStmt( sth, SQL_DROP );
534                 return 1;
535         }
536
537         SQLBindCol( sth, (SQLUSMALLINT)1, SQL_C_LONG,
538                         (SQLPOINTER)&count,
539                         (SQLINTEGER)sizeof( count ),
540                         &countsize );
541
542         rc = SQLFetch( sth );
543         if ( rc != SQL_SUCCESS ) {
544                 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
545                         "error fetch results of count query: %s\n",
546                         at->bam_countquery, 0, 0 );
547                 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
548                 SQLFreeStmt( sth, SQL_DROP );
549                 return 1;
550         }
551
552         Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
553                 "number of values in query: %lu\n", count, 0, 0 );
554         SQLFreeStmt( sth, SQL_DROP );
555         if ( count == 0 ) {
556                 return 1;
557         }
558
559         attr = attr_find( bsi->bsi_e->e_attrs, at->bam_ad );
560         if ( attr != NULL ) {
561                 BerVarray       tmp;
562
563                 if ( attr->a_vals != NULL ) {
564                         for ( ; !BER_BVISNULL( &attr->a_vals[ oldcount ] ); oldcount++ )
565                                 /* just count */ ;
566                 }
567
568                 tmp = ch_realloc( attr->a_vals, ( oldcount + count + 1 ) * sizeof( struct berval ) );
569                 if ( tmp == NULL ) {
570                         return 1;
571                 }
572                 attr->a_vals = tmp;
573                 memset( &attr->a_vals[ oldcount ], 0, ( count + 1 ) * sizeof( struct berval ) );
574
575                 if ( normfunc ) {
576                         tmp = ch_realloc( attr->a_nvals, ( oldcount + count + 1 ) * sizeof( struct berval ) );
577                         if ( tmp == NULL ) {
578                                 return 1;
579                         }
580                         attr->a_nvals = tmp;
581                         memset( &attr->a_nvals[ oldcount ], 0, ( count + 1 ) * sizeof( struct berval ) );
582
583                 } else {
584                         attr->a_nvals = attr->a_vals;
585                 }
586
587         } else {
588                 append = 1;
589
590                 /* Make space for the array of values */
591                 attr = (Attribute *) ch_malloc( sizeof( Attribute ) );
592                 attr->a_desc = at->bam_ad;
593                 attr->a_flags = 0;
594                 attr->a_next = NULL;
595                 attr->a_vals = ch_calloc( count + 1, sizeof( struct berval ) );
596                 if ( attr->a_vals == NULL ) {
597                         Debug( LDAP_DEBUG_TRACE, "Out of memory!\n", 0,0,0 );
598                         ch_free( attr );
599                         return 1;
600                 }
601                 memset( attr->a_vals, 0, ( count + 1 ) * sizeof( struct berval ) );
602                 if ( normfunc ) {
603                         attr->a_nvals = ch_calloc( count + 1, sizeof( struct berval ) );
604                         if ( attr->a_nvals == NULL ) {
605                                 ch_free( attr->a_vals );
606                                 ch_free( attr );
607                                 return 1;
608
609                         } else {
610                                 memset( attr->a_nvals, 0, ( count + 1 ) * sizeof( struct berval ) );
611                         }
612
613                 } else {
614                         attr->a_nvals = attr->a_vals;
615                 }
616         }
617 #endif /* BACKSQL_COUNTQUERY */
618
619         rc = backsql_Prepare( bsi->bsi_dbh, &sth, at->bam_query, 0 );
620         if ( rc != SQL_SUCCESS ) {
621                 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
622                         "error preparing query: %s\n", at->bam_query, 0, 0 );
623                 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
624                 return 1;
625         }
626
627         rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT,
628                         &bsi->bsi_c_eid->eid_keyval );
629         if ( rc != SQL_SUCCESS ) {
630                 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
631                         "error binding key value parameter\n", 0, 0, 0 );
632                 return 1;
633         }
634
635 #ifdef BACKSQL_TRACE
636 #ifdef BACKSQL_ARBITRARY_KEY
637         Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
638                 "query=\"%s\" keyval=%s\n", at->bam_query,
639                 bsi->bsi_c_eid->eid_keyval.bv_val, 0 );
640 #else /* !BACKSQL_ARBITRARY_KEY */
641         Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
642                 "query=\"%s\" keyval=%d\n", at->bam_query,
643                 bsi->bsi_c_eid->eid_keyval, 0 );
644 #endif /* ! BACKSQL_ARBITRARY_KEY */
645 #endif /* BACKSQL_TRACE */
646
647         rc = SQLExecute( sth );
648         if ( ! BACKSQL_SUCCESS( rc ) ) {
649                 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_vals(): "
650                         "error executing attribute query \"%s\"\n",
651                         at->bam_query, 0, 0 );
652                 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
653                 SQLFreeStmt( sth, SQL_DROP );
654                 return 1;
655         }
656
657         backsql_BindRowAsStrings_x( sth, &row, bsi->bsi_op->o_tmpmemctx );
658 #ifdef BACKSQL_COUNTQUERY
659         j = oldcount;
660 #endif /* BACKSQL_COUNTQUERY */
661         for ( rc = SQLFetch( sth ), k = 0;
662                         BACKSQL_SUCCESS( rc );
663                         rc = SQLFetch( sth ), k++ )
664         {
665                 for ( i = 0; i < (unsigned long)row.ncols; i++ ) {
666
667                         if ( row.value_len[ i ] > 0 ) {
668                                 struct berval           bv;
669                                 int                     retval;
670 #ifdef BACKSQL_TRACE
671                                 AttributeDescription    *ad = NULL;
672                                 const char              *text;
673
674                                 retval = slap_bv2ad( &row.col_names[ i ], &ad, &text );
675                                 if ( retval != LDAP_SUCCESS ) {
676                                         Debug( LDAP_DEBUG_ANY,
677                                                 "==>backsql_get_attr_vals(\"%s\"): "
678                                                 "unable to find AttributeDescription %s "
679                                                 "in schema (%d)\n",
680                                                 bsi->bsi_e->e_name.bv_val,
681                                                 row.col_names[ i ].bv_val, retval );
682                                         res = 1;
683                                         goto done;
684                                 }
685
686                                 if ( ad != at->bam_ad ) {
687                                         Debug( LDAP_DEBUG_ANY,
688                                                 "==>backsql_get_attr_vals(\"%s\"): "
689                                                 "column name %s differs from "
690                                                 "AttributeDescription %s\n",
691                                                 bsi->bsi_e->e_name.bv_val,
692                                                 ad->ad_cname.bv_val,
693                                                 at->bam_ad->ad_cname.bv_val );
694                                         res = 1;
695                                         goto done;
696                                 }
697 #endif /* BACKSQL_TRACE */
698
699                                 /*
700                                  * FIXME: what if a binary 
701                                  * is fetched?
702                                  */
703                                 ber_str2bv( row.cols[ i ], 0, 0, &bv );
704
705 #ifdef BACKSQL_PRETTY_VALIDATE
706                                 if ( pretty ) {
707                                         struct berval   pbv;
708
709                                         retval = pretty( at->bam_ad->ad_type->sat_syntax,
710                                                 &bv, &pbv, bsi->bsi_op->o_tmpmemctx );
711                                         bv = pbv;
712
713                                 } else {
714                                         retval = validate( at->bam_ad->ad_type->sat_syntax,
715                                                 &bv );
716                                 }
717
718                                 if ( retval != LDAP_SUCCESS ) {
719                                         char    buf[ SLAP_TEXT_BUFLEN ];
720
721                                         /* FIXME: we're ignoring invalid values,
722                                          * but we're accepting the attributes;
723                                          * should we fail at all? */
724                                         snprintf( buf, sizeof( buf ),
725                                                         "unable to %s value #%lu "
726                                                         "of AttributeDescription %s",
727                                                         pretty ? "prettify" : "validate",
728                                                         k - oldcount,
729                                                         at->bam_ad->ad_cname.bv_val );
730                                         Debug( LDAP_DEBUG_TRACE,
731                                                 "==>backsql_get_attr_vals(\"%s\"): "
732                                                 "%s (%d)\n",
733                                                 bsi->bsi_e->e_name.bv_val, buf, retval );
734                                         continue;
735                                 }
736 #endif /* BACKSQL_PRETTY_VALIDATE */
737
738 #ifndef BACKSQL_COUNTQUERY
739                                 (void)backsql_entry_addattr( bsi->bsi_e, 
740                                                 at->bam_ad, &bv,
741                                                 bsi->bsi_op->o_tmpmemctx );
742
743 #else /* BACKSQL_COUNTQUERY */
744                                 if ( normfunc ) {
745                                         struct berval   nbv;
746
747                                         retval = (*normfunc)( SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
748                                                 at->bam_ad->ad_type->sat_syntax,
749                                                 at->bam_ad->ad_type->sat_equality,
750                                                 &bv, &nbv,
751                                                 bsi->bsi_op->o_tmpmemctx );
752
753                                         if ( retval != LDAP_SUCCESS ) {
754                                                 char    buf[ SLAP_TEXT_BUFLEN ];
755
756                                                 /* FIXME: we're ignoring invalid values,
757                                                  * but we're accepting the attributes;
758                                                  * should we fail at all? */
759                                                 snprintf( buf, sizeof( buf ),
760                                                         "unable to normalize value #%lu "
761                                                         "of AttributeDescription %s",
762                                                         k - oldcount,
763                                                         at->bam_ad->ad_cname.bv_val );
764                                                 Debug( LDAP_DEBUG_TRACE,
765                                                         "==>backsql_get_attr_vals(\"%s\"): "
766                                                         "%s (%d)\n",
767                                                         bsi->bsi_e->e_name.bv_val, buf, retval );
768
769 #ifdef BACKSQL_PRETTY_VALIDATE
770                                                 if ( pretty ) {
771                                                         bsi->bsi_op->o_tmpfree( bv.bv_val,
772                                                                         bsi->bsi_op->o_tmpmemctx );
773                                                 }
774 #endif /* BACKSQL_PRETTY_VALIDATE */
775
776                                                 continue;
777                                         }
778                                         ber_dupbv( &attr->a_nvals[ j ], &nbv );
779                                         bsi->bsi_op->o_tmpfree( nbv.bv_val,
780                                                         bsi->bsi_op->o_tmpmemctx );
781                                 }
782
783                                 ber_dupbv( &attr->a_vals[ j ], &bv );
784
785                                 assert( j < oldcount + count );
786                                 j++;
787 #endif /* BACKSQL_COUNTQUERY */
788
789 #ifdef BACKSQL_PRETTY_VALIDATE
790                                 if ( pretty ) {
791                                         bsi->bsi_op->o_tmpfree( bv.bv_val,
792                                                         bsi->bsi_op->o_tmpmemctx );
793                                 }
794 #endif /* BACKSQL_PRETTY_VALIDATE */
795
796 #ifdef BACKSQL_TRACE
797                                 Debug( LDAP_DEBUG_TRACE, "prec=%d\n",
798                                         (int)row.col_prec[ i ], 0, 0 );
799
800                         } else {
801                                 Debug( LDAP_DEBUG_TRACE, "NULL value "
802                                         "in this row for attribute \"%s\"\n",
803                                         row.col_names[ i ].bv_val, 0, 0 );
804 #endif /* BACKSQL_TRACE */
805                         }
806                 }
807         }
808
809 #ifdef BACKSQL_COUNTQUERY
810         if ( BER_BVISNULL( &attr->a_vals[ 0 ] ) ) {
811                 /* don't leave around attributes with no values */
812                 attr_free( attr );
813
814         } else if ( append ) {
815                 Attribute       **ap;
816
817                 for ( ap = &bsi->bsi_e->e_attrs; (*ap) != NULL; ap = &(*ap)->a_next )
818                         /* goto last */ ;
819                 *ap =  attr;
820         }
821 #endif /* BACKSQL_COUNTQUERY */
822
823         SQLFreeStmt( sth, SQL_DROP );
824         Debug( LDAP_DEBUG_TRACE, "<==backsql_get_attr_vals()\n", 0, 0, 0 );
825
826         if ( at->bam_next ) {
827                 res = backsql_get_attr_vals( at->bam_next, v_bsi );
828         } else {
829                 res = 1;
830         }
831
832 #ifdef BACKSQL_TRACE
833 done:;
834 #endif /* BACKSQL_TRACE */
835         backsql_FreeRow_x( &row, bsi->bsi_op->o_tmpmemctx );
836
837         return res;
838 }
839
840 int
841 backsql_id2entry( backsql_srch_info *bsi, backsql_entryID *eid )
842 {
843         Operation               *op = bsi->bsi_op;
844         backsql_info            *bi = (backsql_info *)op->o_bd->be_private;
845         int                     i;
846         int                     rc;
847
848         Debug( LDAP_DEBUG_TRACE, "==>backsql_id2entry()\n", 0, 0, 0 );
849
850         assert( bsi->bsi_e != NULL );
851
852         memset( bsi->bsi_e, 0, sizeof( Entry ) );
853
854         if ( bi->sql_baseObject && BACKSQL_IS_BASEOBJECT_ID( &eid->eid_id ) ) {
855                 Entry   *e;
856
857                 e = entry_dup( bi->sql_baseObject );
858                 if ( e == NULL ) {
859                         return LDAP_NO_MEMORY;
860                 }
861                         
862                 *bsi->bsi_e = *e;
863                 free( e );
864                 goto done;
865         }
866
867         ber_dupbv_x( &bsi->bsi_e->e_name, &eid->eid_dn, op->o_tmpmemctx );
868         ber_dupbv_x( &bsi->bsi_e->e_nname, &eid->eid_ndn, op->o_tmpmemctx );
869
870         bsi->bsi_e->e_attrs = NULL;
871         bsi->bsi_e->e_private = NULL;
872
873         bsi->bsi_oc = backsql_id2oc( bsi->bsi_op->o_bd->be_private,
874                         eid->eid_oc_id );
875         bsi->bsi_c_eid = eid;
876
877 #ifndef BACKSQL_ARBITRARY_KEY   
878         /* FIXME: unused */
879         bsi->bsi_e->e_id = eid->eid_id;
880 #endif /* ! BACKSQL_ARBITRARY_KEY */
881  
882         rc = attr_merge_normalize_one( bsi->bsi_e,
883                         slap_schema.si_ad_objectClass,
884                         &bsi->bsi_oc->bom_oc->soc_cname,
885                         bsi->bsi_op->o_tmpmemctx );
886         if ( rc != LDAP_SUCCESS ) {
887                 backsql_entry_clean( op, bsi->bsi_e );
888                 return rc;
889         }
890
891         if ( bsi->bsi_attrs == NULL || ( bsi->bsi_flags & BSQL_SF_ALL_USER ) )
892         {
893                 Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): "
894                         "retrieving all attributes\n", 0, 0, 0 );
895                 avl_apply( bsi->bsi_oc->bom_attrs, backsql_get_attr_vals,
896                                 bsi, 0, AVL_INORDER );
897
898         } else {
899                 Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): "
900                         "custom attribute list\n", 0, 0, 0 );
901                 for ( i = 0; !BER_BVISNULL( &bsi->bsi_attrs[ i ].an_name ); i++ ) {
902                         backsql_at_map_rec      **vat;
903                         AttributeName           *an = &bsi->bsi_attrs[ i ];
904                         int                     j;
905
906                         /* if one of the attributes listed here is
907                          * a subtype of another, it must be ignored,
908                          * because subtypes are already dealt with
909                          * by backsql_supad2at()
910                          */
911                         for ( j = 0; !BER_BVISNULL( &bsi->bsi_attrs[ j ].an_name ); j++ ) {
912                                 /* skip self */
913                                 if ( j == i ) {
914                                         continue;
915                                 }
916
917                                 /* skip subtypes */
918                                 if ( is_at_subtype( an->an_desc->ad_type,
919                                                         bsi->bsi_attrs[ j ].an_desc->ad_type ) )
920                                 {
921                                         goto next;
922                                 }
923                         }
924
925                         rc = backsql_supad2at( bsi->bsi_oc, an->an_desc, &vat );
926                         if ( rc != 0 || vat == NULL ) {
927                                 Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): "
928                                                 "attribute \"%s\" is not defined "
929                                                 "for objectlass \"%s\"\n",
930                                                 an->an_name.bv_val, 
931                                                 BACKSQL_OC_NAME( bsi->bsi_oc ), 0 );
932                                 continue;
933                         }
934
935                         for ( j = 0; vat[j]; j++ ) {
936                                 backsql_get_attr_vals( vat[j], bsi );
937                         }
938
939                         ch_free( vat );
940
941 next:;
942                 }
943         }
944
945         if ( bsi->bsi_flags & BSQL_SF_RETURN_ENTRYUUID ) {
946                 Attribute       *a_entryUUID,
947                                 **ap;
948
949                 a_entryUUID = backsql_operational_entryUUID( bi, eid );
950                 if ( a_entryUUID != NULL ) {
951                         for ( ap = &bsi->bsi_e->e_attrs; 
952                                         *ap; 
953                                         ap = &(*ap)->a_next );
954
955                         *ap = a_entryUUID;
956                 }
957         }
958
959         if ( ( bsi->bsi_flags & BSQL_SF_ALL_OPER )
960                         || an_find( bsi->bsi_attrs, &AllOper )
961                         || an_find( bsi->bsi_attrs, &slap_schema.si_ad_structuralObjectClass->ad_cname ) )
962         {
963                 if ( BACKSQL_CHECK_SCHEMA( bi ) ) {
964                         Attribute       *a;
965                         const char      *text = NULL;
966                         char            textbuf[ 1024 ];
967                         size_t          textlen = sizeof( textbuf );
968                         struct berval   soc,
969                                         bv[ 2 ],
970                                         *nvals;
971                         int             rc = LDAP_SUCCESS;
972
973                         a = attr_find( bsi->bsi_e->e_attrs,
974                                         slap_schema.si_ad_objectClass );
975                         if ( a != NULL ) {
976                                 nvals = a->a_nvals;
977
978                         } else {
979                                 bv[ 0 ] = bsi->bsi_oc->bom_oc->soc_cname;
980                                 BER_BVZERO( &bv[ 1 ] );
981                                 nvals = bv;
982                         }
983
984                         rc = structural_class( nvals, &soc, NULL, 
985                                         &text, textbuf, textlen );
986                         if ( rc != LDAP_SUCCESS ) {
987                                 Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(%s): "
988                                         "structural_class() failed %d (%s)\n",
989                                         bsi->bsi_e->e_name.bv_val,
990                                         rc, text ? text : "" );
991                                 backsql_entry_clean( op, bsi->bsi_e );
992                                 return rc;
993                         }
994
995                         if ( !bvmatch( &soc, &bsi->bsi_oc->bom_oc->soc_cname ) ) {
996                                 Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(%s): "
997                                         "computed structuralObjectClass %s "
998                                         "does not match objectClass %s associated "
999                                         "to entry\n",
1000                                         bsi->bsi_e->e_name.bv_val, soc.bv_val,
1001                                         bsi->bsi_oc->bom_oc->soc_cname.bv_val );
1002                                 backsql_entry_clean( op, bsi->bsi_e );
1003                                 return rc;
1004                         }
1005                 }
1006
1007                 rc = attr_merge_normalize_one( bsi->bsi_e,
1008                                 slap_schema.si_ad_structuralObjectClass,
1009                                 &bsi->bsi_oc->bom_oc->soc_cname,
1010                                 bsi->bsi_op->o_tmpmemctx );
1011                 if ( rc != LDAP_SUCCESS ) {
1012                         backsql_entry_clean( op, bsi->bsi_e );
1013                         return rc;
1014                 }
1015         }
1016
1017 done:;
1018         Debug( LDAP_DEBUG_TRACE, "<==backsql_id2entry()\n", 0, 0, 0 );
1019
1020         return LDAP_SUCCESS;
1021 }
1022