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