Back to index

openldap  2.4.31
util.c
Go to the documentation of this file.
00001 /* $OpenLDAP$ */
00002 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00003  *
00004  * Copyright 1999-2012 The OpenLDAP Foundation.
00005  * Portions Copyright 1999 Dmitry Kovalev.
00006  * Portions Copyright 2002 Pierangelo Masarati.
00007  * All rights reserved.
00008  *
00009  * Redistribution and use in source and binary forms, with or without
00010  * modification, are permitted only as authorized by the OpenLDAP
00011  * Public License.
00012  *
00013  * A copy of this license is available in the file LICENSE in the
00014  * top-level directory of the distribution or, alternatively, at
00015  * <http://www.OpenLDAP.org/license.html>.
00016  */
00017 /* ACKNOWLEDGEMENTS:
00018  * This work was initially developed by Dmitry Kovalev for inclusion
00019  * by OpenLDAP Software.  Additional significant contributors include
00020  * Pierangelo Masarati.
00021  */
00022 
00023 #include "portable.h"
00024 
00025 #include <stdio.h>
00026 #include <sys/types.h>
00027 #include "ac/string.h"
00028 #include "ac/ctype.h"
00029 #include "ac/stdarg.h"
00030 
00031 #include "slap.h"
00032 #include "proto-sql.h"
00033 #include "lutil.h"
00034 
00035 #define BACKSQL_MAX(a,b) ((a)>(b)?(a):(b))
00036 #define BACKSQL_MIN(a,b) ((a)<(b)?(a):(b))
00037 
00038 #define BACKSQL_STR_GROW 256
00039 
00040 const char backsql_def_oc_query[] = 
00041        "SELECT id,name,keytbl,keycol,create_proc,delete_proc,expect_return "
00042        "FROM ldap_oc_mappings";
00043 const char backsql_def_needs_select_oc_query[] = 
00044        "SELECT id,name,keytbl,keycol,create_proc,create_keyval,delete_proc,"
00045        "expect_return FROM ldap_oc_mappings";
00046 const char backsql_def_at_query[] = 
00047        "SELECT name,sel_expr,from_tbls,join_where,add_proc,delete_proc,"
00048        "param_order,expect_return,sel_expr_u FROM ldap_attr_mappings "
00049        "WHERE oc_map_id=?";
00050 const char backsql_def_delentry_stmt[] = "DELETE FROM ldap_entries WHERE id=?";
00051 const char backsql_def_renentry_stmt[] =
00052        "UPDATE ldap_entries SET dn=?,parent=?,keyval=? WHERE id=?";
00053 const char backsql_def_insentry_stmt[] = 
00054        "INSERT INTO ldap_entries (dn,oc_map_id,parent,keyval) "
00055        "VALUES (?,?,?,?)";
00056 const char backsql_def_delobjclasses_stmt[] = "DELETE FROM ldap_entry_objclasses "
00057        "WHERE entry_id=?";
00058 const char backsql_def_subtree_cond[] = "ldap_entries.dn LIKE CONCAT('%',?)";
00059 const char backsql_def_upper_subtree_cond[] = "(ldap_entries.dn) LIKE CONCAT('%',?)";
00060 const char backsql_id_query[] = "SELECT id,keyval,oc_map_id,dn FROM ldap_entries WHERE ";
00061 /* better ?||? or cast(?||? as varchar) */ 
00062 const char backsql_def_concat_func[] = "CONCAT(?,?)";
00063 
00064 /* TimesTen */
00065 const char backsql_check_dn_ru_query[] = "SELECT dn_ru FROM ldap_entries";
00066 
00067 struct berbuf *
00068 backsql_strcat_x( struct berbuf *dest, void *memctx, ... )
00069 {
00070        va_list              strs;
00071        ber_len_t     cdlen, cslen, grow;
00072        char          *cstr;
00073 
00074        assert( dest != NULL );
00075        assert( dest->bb_val.bv_val == NULL 
00076                      || dest->bb_val.bv_len == strlen( dest->bb_val.bv_val ) );
00077  
00078 #ifdef BACKSQL_TRACE
00079        Debug( LDAP_DEBUG_TRACE, "==>backsql_strcat()\n", 0, 0, 0 );
00080 #endif /* BACKSQL_TRACE */
00081 
00082        va_start( strs, memctx );
00083        if ( dest->bb_val.bv_val == NULL || dest->bb_len == 0 ) {
00084               dest->bb_val.bv_val = (char *)ber_memalloc_x( BACKSQL_STR_GROW * sizeof( char ), memctx );
00085               dest->bb_val.bv_len = 0;
00086               dest->bb_len = BACKSQL_STR_GROW;
00087        }
00088        cdlen = dest->bb_val.bv_len;
00089        while ( ( cstr = va_arg( strs, char * ) ) != NULL ) {
00090               cslen = strlen( cstr );
00091               grow = BACKSQL_MAX( BACKSQL_STR_GROW, cslen );
00092               if ( dest->bb_len - cdlen <= cslen ) {
00093                      char   *tmp_dest;
00094 
00095 #ifdef BACKSQL_TRACE
00096                      Debug( LDAP_DEBUG_TRACE, "backsql_strcat(): "
00097                             "buflen=%d, cdlen=%d, cslen=%d "
00098                             "-- reallocating dest\n",
00099                             dest->bb_len, cdlen + 1, cslen );
00100 #endif /* BACKSQL_TRACE */
00101 
00102                      tmp_dest = (char *)ber_memrealloc_x( dest->bb_val.bv_val,
00103                                    dest->bb_len + grow * sizeof( char ), memctx );
00104                      if ( tmp_dest == NULL ) {
00105                             Debug( LDAP_DEBUG_ANY, "backsql_strcat(): "
00106                                    "could not reallocate string buffer.\n",
00107                                    0, 0, 0 );
00108                             return NULL;
00109                      }
00110                      dest->bb_val.bv_val = tmp_dest;
00111                      dest->bb_len += grow;
00112 
00113 #ifdef BACKSQL_TRACE
00114                      Debug( LDAP_DEBUG_TRACE, "backsql_strcat(): "
00115                             "new buflen=%d, dest=%p\n",
00116                             dest->bb_len, dest, 0 );
00117 #endif /* BACKSQL_TRACE */
00118               }
00119               AC_MEMCPY( dest->bb_val.bv_val + cdlen, cstr, cslen + 1 );
00120               cdlen += cslen;
00121        }
00122        va_end( strs );
00123 
00124 #ifdef BACKSQL_TRACE
00125        Debug( LDAP_DEBUG_TRACE, "<==backsql_strcat() (dest=\"%s\")\n", 
00126                      dest->bb_val.bv_val, 0, 0 );
00127 #endif /* BACKSQL_TRACE */
00128 
00129        dest->bb_val.bv_len = cdlen;
00130 
00131        return dest;
00132 } 
00133 
00134 struct berbuf *
00135 backsql_strfcat_x( struct berbuf *dest, void *memctx, const char *fmt, ... )
00136 {
00137        va_list              strs;
00138        ber_len_t     cdlen;
00139 
00140        assert( dest != NULL );
00141        assert( fmt != NULL );
00142        assert( dest->bb_len == 0 || dest->bb_len > dest->bb_val.bv_len );
00143        assert( dest->bb_val.bv_val == NULL 
00144                      || dest->bb_val.bv_len == strlen( dest->bb_val.bv_val ) );
00145  
00146 #ifdef BACKSQL_TRACE
00147        Debug( LDAP_DEBUG_TRACE, "==>backsql_strfcat()\n", 0, 0, 0 );
00148 #endif /* BACKSQL_TRACE */
00149 
00150        va_start( strs, fmt );
00151        if ( dest->bb_val.bv_val == NULL || dest->bb_len == 0 ) {
00152               dest->bb_val.bv_val = (char *)ber_memalloc_x( BACKSQL_STR_GROW * sizeof( char ), memctx );
00153               dest->bb_val.bv_len = 0;
00154               dest->bb_len = BACKSQL_STR_GROW;
00155        }
00156 
00157        cdlen = dest->bb_val.bv_len;
00158        for ( ; fmt[0]; fmt++ ) {
00159               ber_len_t     cslen, grow;
00160               char          *cstr, cc[ 2 ] = { '\0', '\0' };
00161               struct berval *cbv;
00162 
00163               switch ( fmt[ 0 ] ) {
00164 
00165               /* berval */
00166               case 'b':
00167                      cbv = va_arg( strs, struct berval * );
00168                      cstr = cbv->bv_val;
00169                      cslen = cbv->bv_len;
00170                      break;
00171 
00172               /* length + string */
00173               case 'l':
00174                      cslen = va_arg( strs, ber_len_t );
00175                      cstr = va_arg( strs, char * );
00176                      break;
00177 
00178               /* string */
00179               case 's':
00180                      cstr = va_arg( strs, char * );
00181                      cslen = strlen( cstr );
00182                      break;
00183 
00184               /* char */
00185               case 'c':
00186                      /* 
00187                       * `char' is promoted to `int' when passed through `...'
00188                       */
00189                      cc[0] = va_arg( strs, int );
00190                      cstr = cc;
00191                      cslen = 1;
00192                      break;
00193 
00194               default:
00195                      assert( 0 );
00196               }
00197 
00198               grow = BACKSQL_MAX( BACKSQL_STR_GROW, cslen );
00199               if ( dest->bb_len - cdlen <= cslen ) {
00200                      char   *tmp_dest;
00201 
00202 #ifdef BACKSQL_TRACE
00203                      Debug( LDAP_DEBUG_TRACE, "backsql_strfcat(): "
00204                             "buflen=%d, cdlen=%d, cslen=%d "
00205                             "-- reallocating dest\n",
00206                             dest->bb_len, cdlen + 1, cslen );
00207 #endif /* BACKSQL_TRACE */
00208 
00209                      tmp_dest = (char *)ber_memrealloc_x( dest->bb_val.bv_val,
00210                                    ( dest->bb_len ) + grow * sizeof( char ), memctx );
00211                      if ( tmp_dest == NULL ) {
00212                             Debug( LDAP_DEBUG_ANY, "backsql_strfcat(): "
00213                                    "could not reallocate string buffer.\n",
00214                                    0, 0, 0 );
00215                             return NULL;
00216                      }
00217                      dest->bb_val.bv_val = tmp_dest;
00218                      dest->bb_len += grow * sizeof( char );
00219 
00220 #ifdef BACKSQL_TRACE
00221                      Debug( LDAP_DEBUG_TRACE, "backsql_strfcat(): "
00222                             "new buflen=%d, dest=%p\n", dest->bb_len, dest, 0 );
00223 #endif /* BACKSQL_TRACE */
00224               }
00225 
00226               assert( cstr != NULL );
00227               
00228               AC_MEMCPY( dest->bb_val.bv_val + cdlen, cstr, cslen + 1 );
00229               cdlen += cslen;
00230        }
00231 
00232        va_end( strs );
00233 
00234 #ifdef BACKSQL_TRACE
00235        Debug( LDAP_DEBUG_TRACE, "<==backsql_strfcat() (dest=\"%s\")\n", 
00236                      dest->bb_val.bv_val, 0, 0 );
00237 #endif /* BACKSQL_TRACE */
00238 
00239        dest->bb_val.bv_len = cdlen;
00240 
00241        return dest;
00242 } 
00243 
00244 int
00245 backsql_entry_addattr(
00246        Entry                *e,
00247        AttributeDescription *ad,
00248        struct berval        *val,
00249        void                 *memctx )
00250 {
00251        int                  rc;
00252 
00253 #ifdef BACKSQL_TRACE
00254        Debug( LDAP_DEBUG_TRACE, "backsql_entry_addattr(\"%s\"): %s=%s\n", 
00255               e->e_name.bv_val, ad->ad_cname.bv_val, val->bv_val );
00256 #endif /* BACKSQL_TRACE */
00257 
00258        rc = attr_merge_normalize_one( e, ad, val, memctx );
00259 
00260        if ( rc != LDAP_SUCCESS ) {
00261               Debug( LDAP_DEBUG_TRACE, "backsql_entry_addattr(\"%s\"): "
00262                      "failed to merge value \"%s\" for attribute \"%s\"\n",
00263                      e->e_name.bv_val, val->bv_val, ad->ad_cname.bv_val );
00264               return rc;
00265        }
00266 
00267 #ifdef BACKSQL_TRACE
00268        Debug( LDAP_DEBUG_TRACE, "<==backsql_entry_addattr(\"%s\")\n",
00269               e->e_name.bv_val, 0, 0 );
00270 #endif /* BACKSQL_TRACE */
00271 
00272        return LDAP_SUCCESS;
00273 }
00274 
00275 static char *
00276 backsql_get_table_spec( backsql_info *bi, char **p )
00277 {
00278        char          *s, *q;
00279        struct berbuf res = BB_NULL;
00280 
00281        assert( p != NULL );
00282        assert( *p != NULL );
00283 
00284        s = *p;
00285        while ( **p && **p != ',' ) {
00286               (*p)++;
00287        }
00288 
00289        if ( **p ) {
00290               *(*p)++ = '\0';
00291        }
00292        
00293 #define BACKSQL_NEXT_WORD { \
00294               while ( *s && isspace( (unsigned char)*s ) ) s++; \
00295               if ( !*s ) return res.bb_val.bv_val; \
00296               q = s; \
00297               while ( *q && !isspace( (unsigned char)*q ) ) q++; \
00298               if ( *q ) *q++='\0'; \
00299        }
00300 
00301        BACKSQL_NEXT_WORD;
00302        /* table name */
00303        backsql_strcat_x( &res, NULL, s, NULL );
00304        s = q;
00305 
00306        BACKSQL_NEXT_WORD;
00307        if ( strcasecmp( s, "AS" ) == 0 ) {
00308               s = q;
00309               BACKSQL_NEXT_WORD;
00310        }
00311 
00312        /* oracle doesn't understand "AS" :( and other RDBMSes don't need it */
00313        backsql_strfcat_x( &res, NULL, "lbbsb",
00314                      STRLENOF( " " ), " ",
00315                      &bi->sql_aliasing,
00316                      &bi->sql_aliasing_quote,
00317                      s,
00318                      &bi->sql_aliasing_quote );
00319 
00320        return res.bb_val.bv_val;
00321 }
00322 
00323 int
00324 backsql_merge_from_clause( 
00325        backsql_info  *bi,
00326        struct berbuf *dest_from,
00327        struct berval *src_from )
00328 {
00329        char          *s, *p, *srcc, *pos, e;
00330        struct berbuf res = BB_NULL;
00331 
00332 #ifdef BACKSQL_TRACE
00333        Debug( LDAP_DEBUG_TRACE, "==>backsql_merge_from_clause(): "
00334               "dest_from=\"%s\",src_from=\"%s\"\n",
00335               dest_from ? dest_from->bb_val.bv_val : "<NULL>",
00336               src_from->bv_val, 0 );
00337 #endif /* BACKSQL_TRACE */
00338 
00339        srcc = ch_strdup( src_from->bv_val );
00340        p = srcc;
00341 
00342        if ( dest_from != NULL ) {
00343               res = *dest_from;
00344        }
00345        
00346        while ( *p ) {
00347               s = backsql_get_table_spec( bi, &p );
00348 
00349 #ifdef BACKSQL_TRACE
00350               Debug( LDAP_DEBUG_TRACE, "backsql_merge_from_clause(): "
00351                      "p=\"%s\" s=\"%s\"\n", p, s, 0 );
00352 #endif /* BACKSQL_TRACE */
00353 
00354               if ( BER_BVISNULL( &res.bb_val ) ) {
00355                      backsql_strcat_x( &res, NULL, s, NULL );
00356 
00357               } else {
00358                      pos = strstr( res.bb_val.bv_val, s );
00359                      if ( pos == NULL || ( ( e = pos[ strlen( s ) ] ) != '\0' && e != ',' ) ) {
00360                             backsql_strfcat_x( &res, NULL, "cs", ',', s );
00361                      }
00362               }
00363               
00364               if ( s ) {
00365                      ch_free( s );
00366               }
00367        }
00368 
00369 #ifdef BACKSQL_TRACE
00370        Debug( LDAP_DEBUG_TRACE, "<==backsql_merge_from_clause()\n", 0, 0, 0 );
00371 #endif /* BACKSQL_TRACE */
00372 
00373        free( srcc );
00374        *dest_from = res;
00375 
00376        return 1;
00377 }
00378 
00379 /*
00380  * splits a pattern in components separated by '?'
00381  * (double ?? are turned into single ? and left in the string)
00382  * expected contains the number of expected occurrences of '?'
00383  * (a negative value means parse as many as possible)
00384  */
00385 
00386 int
00387 backsql_split_pattern(
00388        const char    *_pattern,
00389        BerVarray     *split_pattern,
00390        int           expected )
00391 {
00392        char          *pattern, *start, *end;
00393        struct berval bv;
00394        int           rc = 0;
00395 
00396 #define SPLIT_CHAR   '?'
00397        
00398        assert( _pattern != NULL );
00399        assert( split_pattern != NULL );
00400 
00401        pattern = ch_strdup( _pattern );
00402 
00403        start = pattern;
00404        end = strchr( start, SPLIT_CHAR );
00405        for ( ; start; expected-- ) {
00406               char          *real_end = end;
00407               ber_len_t     real_len;
00408               
00409               if ( real_end == NULL ) {
00410                      real_end = start + strlen( start );
00411 
00412               } else if ( real_end[ 1 ] == SPLIT_CHAR ) {
00413                      expected++;
00414                      AC_MEMCPY( real_end, real_end + 1, strlen( real_end ) );
00415                      end = strchr( real_end + 1, SPLIT_CHAR );
00416                      continue;
00417               }
00418 
00419               real_len = real_end - start;
00420               if ( real_len == 0 ) {
00421                      ber_str2bv( "", 0, 1, &bv );
00422               } else {
00423                      ber_str2bv( start, real_len, 1, &bv );
00424               }
00425 
00426               ber_bvarray_add( split_pattern, &bv );
00427 
00428               if ( expected == 0 ) {
00429                      if ( end != NULL ) {
00430                             rc = -1;
00431                             goto done;
00432                      }
00433                      break;
00434               }
00435 
00436               if ( end != NULL ) {
00437                      start = end + 1;
00438                      end = strchr( start, SPLIT_CHAR );
00439               }
00440        }
00441 
00442 done:;
00443 
00444        ch_free( pattern );
00445 
00446        return rc;
00447 }
00448 
00449 int
00450 backsql_prepare_pattern(
00451        BerVarray     split_pattern,
00452        BerVarray     values,
00453        struct berval *res )
00454 {
00455        int           i;
00456        struct berbuf bb = BB_NULL;
00457 
00458        assert( res != NULL );
00459 
00460        for ( i = 0; values[i].bv_val; i++ ) {
00461               if ( split_pattern[i].bv_val == NULL ) {
00462                      ch_free( bb.bb_val.bv_val );
00463                      return -1;
00464               }
00465               backsql_strfcat_x( &bb, NULL, "b", &split_pattern[ i ] );
00466               backsql_strfcat_x( &bb, NULL, "b", &values[ i ] );
00467        }
00468 
00469        if ( split_pattern[ i ].bv_val == NULL ) {
00470               ch_free( bb.bb_val.bv_val );
00471               return -1;
00472        }
00473 
00474        backsql_strfcat_x( &bb, NULL, "b", &split_pattern[ i ] );
00475 
00476        *res = bb.bb_val;
00477 
00478        return 0;
00479 }
00480 
00481 int
00482 backsql_entryUUID(
00483        backsql_info  *bi,
00484        backsql_entryID      *id,
00485        struct berval *entryUUID,
00486        void          *memctx )
00487 {
00488        char          uuidbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE ];
00489        struct berval uuid;
00490 #ifdef BACKSQL_ARBITRARY_KEY
00491        int           i;
00492        ber_len_t     l, lmax;
00493 #endif /* BACKSQL_ARBITRARY_KEY */
00494 
00495        /* entryUUID is generated as "%08x-%04x-%04x-0000-eaddrXXX"
00496         * with eid_oc_id as %08x and hi and lo eid_id as %04x-%04x */
00497        assert( bi != NULL );
00498        assert( id != NULL );
00499        assert( entryUUID != NULL );
00500 
00501 #ifdef BACKSQL_ARBITRARY_KEY
00502        snprintf( uuidbuf, sizeof( uuidbuf ),
00503                      "%08x-0000-0000-0000-000000000000",
00504                      ( id->eid_oc_id & 0xFFFFFFFF ) );
00505        lmax = id->eid_keyval.bv_len < 12 ? id->eid_keyval.bv_len : 12;
00506        for ( l = 0, i = 9; l < lmax; l++, i += 2 ) {
00507               switch ( i ) {
00508               case STRLENOF( "00000000-0000" ):
00509               case STRLENOF( "00000000-0000-0000" ):
00510               case STRLENOF( "00000000-0000-0000-0000" ):
00511                      uuidbuf[ i++ ] = '-';
00512               /* FALLTHRU */
00513 
00514               default:
00515                      snprintf( &uuidbuf[ i ], 3, "%2x", id->eid_keyval.bv_val[ l ] );
00516                      break;
00517               }
00518        }
00519 #else /* ! BACKSQL_ARBITRARY_KEY */
00520        /* note: works only with 32 bit architectures... */
00521        snprintf( uuidbuf, sizeof( uuidbuf ),
00522                      "%08x-%04x-%04x-0000-000000000000",
00523                      ( (unsigned)id->eid_oc_id & 0xFFFFFFFF ),
00524                      ( ( (unsigned)id->eid_keyval & 0xFFFF0000 ) >> 020 /* 16 */ ),
00525                      ( (unsigned)id->eid_keyval & 0xFFFF ) );
00526 #endif /* ! BACKSQL_ARBITRARY_KEY */
00527 
00528        uuid.bv_val = uuidbuf;
00529        uuid.bv_len = strlen( uuidbuf );
00530 
00531        ber_dupbv_x( entryUUID, &uuid, memctx );
00532 
00533        return 0;
00534 }
00535 
00536 int
00537 backsql_entryUUID_decode(
00538        struct berval *entryUUID,
00539        unsigned long *oc_id,
00540 #ifdef BACKSQL_ARBITRARY_KEY
00541        struct berval *keyval
00542 #else /* ! BACKSQL_ARBITRARY_KEY */
00543        unsigned long *keyval
00544 #endif /* ! BACKSQL_ARBITRARY_KEY */
00545        )
00546 {
00547 #if 0
00548        fprintf( stderr, "==> backsql_entryUUID_decode()\n" );
00549 #endif
00550 
00551        *oc_id = ( entryUUID->bv_val[0] << 030 /* 24 */ )
00552               + ( entryUUID->bv_val[1] << 020 /* 16 */ )
00553               + ( entryUUID->bv_val[2] << 010 /* 8 */ )
00554               + entryUUID->bv_val[3];
00555 
00556 #ifdef BACKSQL_ARBITRARY_KEY
00557        /* FIXME */
00558 #else /* ! BACKSQL_ARBITRARY_KEY */
00559        *keyval = ( entryUUID->bv_val[4] << 030 /* 24 */ )
00560               + ( entryUUID->bv_val[5] << 020 /* 16 */ )
00561               + ( entryUUID->bv_val[6] << 010 /* 8 */ )
00562               + entryUUID->bv_val[7];
00563 #endif /* ! BACKSQL_ARBITRARY_KEY */
00564 
00565 #if 0
00566        fprintf( stderr, "<== backsql_entryUUID_decode(): oc=%lu id=%lu\n",
00567                      *oc_id, *keyval );
00568 #endif
00569 
00570        return LDAP_SUCCESS;
00571 }
00572