ld_fld.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * LDAP Database Driver for SER
00005  *
00006  * Copyright (C) 2008 iptelorg GmbH
00007  *
00008  * This file is part of SER, a free SIP server.
00009  *
00010  * SER is free software; you can redistribute it and/or modify it under the
00011  * terms of the GNU General Public License as published by the Free Software
00012  * Foundation; either version 2 of the License, or (at your option) any later
00013  * version.
00014  *
00015  * SER is distributed in the hope that it will be useful, but WITHOUT ANY
00016  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00017  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
00018  * details.
00019  *
00020  * You should have received a copy of the GNU General Public License along
00021  * with this program; if not, write to the Free Software Foundation, Inc.,
00022  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00023  */
00024 
00033 #define _XOPEN_SOURCE 4     /* bsd */
00034 #define _XOPEN_SOURCE_EXTENDED 1    /* solaris */
00035 #define _SVID_SOURCE 1 /* timegm */
00036 
00037 #define _BSD_SOURCE /* snprintf */
00038 
00039 #include "ld_fld.h"
00040 
00041 #include "../../lib/srdb2/db_drv.h"
00042 #include "../../mem/mem.h"
00043 #include "../../dprint.h"
00044 #include "../../ut.h"
00045 
00046 #include <stdlib.h>
00047 #include <stdio.h>
00048 #include <strings.h>
00049 #include <stdint.h>
00050 #include <string.h>
00051 #include <time.h>   /* strptime, XOPEN issue must be >= 4 */
00052 
00053 
00057 struct sbuf {
00058         char *s;                        
00059         int   len;                      
00060         int   size;                     
00061         int   increment;        
00062 };
00063 
00064 
00065 #define TEST_RESIZE \
00066         if (rsize > sb->size) { \
00067                 asize = rsize - sb->size; \
00068                 new_size = sb->size + (asize / sb->increment  + \
00069                                                            (asize % sb->increment > 0)) * sb->increment; \
00070                 newp = pkg_malloc(new_size); \
00071                 if (!newp) { \
00072                         ERR("ldap: No memory left\n"); \
00073                         return -1; \
00074                 } \
00075                 if (sb->s) { \
00076                         memcpy(newp, sb->s, sb->len); \
00077                         pkg_free(sb->s); \
00078                 } \
00079                 sb->s = newp; \
00080                 sb->size = new_size; \
00081         }
00082 
00083 
00084 static inline int sb_add(struct sbuf *sb, char* str, int len)
00085 {
00086         int new_size = 0, asize;
00087         int rsize = sb->len + len;
00088         char *newp;
00089 
00090         TEST_RESIZE;
00091 
00092         memcpy(sb->s + sb->len, str, len);
00093         sb->len += len;
00094         return 0;
00095 }
00096 
00097 
00098 static inline int sb_add_esc(struct sbuf *sb, char* str, int len)
00099 {
00100         int new_size = 0, asize, i;
00101         int rsize = sb->len + len * 3;
00102         char *newp, *w;
00103 
00104         TEST_RESIZE;
00105 
00106         w = sb->s + sb->len;
00107         for(i = 0; i < len; i++) {
00108                 switch(str[i]) {
00109                 case '*':
00110                         *w++ = '\\'; *w++ = '2'; *w++ = 'A';
00111                         sb->len += 3;
00112                         break;
00113 
00114                 case '(':
00115                         *w++ = '\\'; *w++ = '2'; *w++ = '8';
00116                         sb->len += 3;
00117                         break;
00118 
00119                 case ')':
00120                         *w++ = '\\'; *w++ = '2'; *w++ = '9';
00121                         sb->len += 3;
00122                         break;
00123 
00124                 case '\\':
00125                         *w++ = '\\'; *w++ = '5'; *w++ = 'C';
00126                         sb->len += 3;
00127                         break;
00128 
00129                 case '\0':
00130                         *w++ = '\\'; *w++ = '0'; *w++ = '0';
00131                         sb->len += 3;
00132                         break;
00133 
00134                 default:
00135                         *w++ = str[i];
00136                         sb->len++;
00137                         break;
00138                 }
00139         }
00140 
00141         return 0;
00142 }
00143 
00144 
00150 static void ld_fld_free(db_fld_t* fld, struct ld_fld* payload)
00151 {
00152         db_drv_free(&payload->gen);
00153         if (payload->values) ldap_value_free_len(payload->values);      
00154         payload->values = NULL;
00155         if (payload->filter) pkg_free(payload->filter);
00156         payload->filter = NULL;
00157         pkg_free(payload);
00158 }
00159 
00160 
00161 int ld_fld(db_fld_t* fld, char* table)
00162 {
00163         struct ld_fld* res;
00164 
00165         res = (struct ld_fld*)pkg_malloc(sizeof(struct ld_fld));
00166         if (res == NULL) {
00167                 ERR("ldap: No memory left\n");
00168                 return -1;
00169         }
00170         memset(res, '\0', sizeof(struct ld_fld));
00171         if (db_drv_init(&res->gen, ld_fld_free) < 0) goto error;
00172 
00173         DB_SET_PAYLOAD(fld, res);
00174         return 0;
00175 
00176  error:
00177         if (res) pkg_free(res);
00178         return -1;
00179 }
00180 
00181 
00182 int ld_resolve_fld(db_fld_t* fld, struct ld_cfg* cfg)
00183 {
00184         int i;
00185         struct ld_fld* lfld;
00186 
00187         if (fld == NULL || cfg == NULL) return 0;
00188 
00189         for(i = 0; !DB_FLD_EMPTY(fld) && !DB_FLD_LAST(fld[i]); i++) {
00190                 lfld = DB_GET_PAYLOAD(fld + i);
00191                 lfld->attr.s = ld_find_attr_name(&lfld->syntax, cfg, fld[i].name);
00192                 if (lfld->attr.s == NULL) lfld->attr.s = fld[i].name;
00193                 if (lfld->attr.s) lfld->attr.len = strlen(lfld->attr.s);
00194         }
00195         return 0;
00196 }
00197 
00198 
00199 static inline int ldap_int2db_int(int* dst, str* src)
00200 {
00201         if (str2sint(src, dst) != 0) {
00202                 ERR("ldap: Error while converting value '%.*s' to integer\n",
00203                         src->len, ZSW(src->s));
00204                 return -1;
00205         }
00206         return 0;
00207 }
00208 
00209 
00210 static inline int ldap_bit2db_int(int* dst, str* src)
00211 {
00212         int i, v;
00213 
00214         if (src->len > 32) {
00215                 WARN("ldap: bitString '%.*s'B is longer than 32 bits, truncating\n",
00216                          src->len, ZSW(src->s));
00217         }
00218         v = 0;
00219         for(i = 0; i < src->len; i++) {
00220                 v <<= 1;
00221                 v += src->s[i] - '0';
00222         }
00223         *dst = v;
00224         return 0;
00225 }
00226 
00227 
00228 static inline int ldap_gentime2db_datetime(time_t* dst, str* src)
00229 {
00230         struct tm time;
00231 
00232         if (src->len < 12) return -1;
00233 
00234         /* It is necessary to zero tm structure first */
00235         memset(&time, '\0', sizeof(struct tm));
00236         /* YYYYMMDDHHMMSS[.sss][ 'Z' | ( {'+'|'-'} ZZZZ) ] */
00237         strptime(src->s, "%Y%m%d%H%M%S", &time);  /* Note: frac of seconds are lost in time_t representation */
00238         
00239         if (src->s[src->len-1] == 'Z' || src->s[src->len-5] == '-' || src->s[src->len-5] == '+') {
00240                 /* GMT or specified TZ, no daylight saving time */
00241                 #ifdef HAVE_TIMEGM
00242                 *dst = timegm(&time);
00243                 #else
00244                 *dst = _timegm(&time);
00245                 #endif /* HAVE_TIMEGM */
00246 
00247                 if (src->s[src->len-1] != 'Z') {
00248                         /* timezone is specified */
00249                         memset(&time, '\0', sizeof(struct tm));
00250                         strptime(src->s + src->len - 4, "%H%M", &time);
00251                         switch (src->s[src->len-5]) {
00252                                 case '-':
00253                                         *dst -= time.tm_hour*3600+time.tm_min*60;
00254                                         break;
00255                                 case '+':
00256                                         *dst += time.tm_hour*3600+time.tm_min*60;
00257                                         break;
00258                                 default:
00259                                         ;
00260                         }
00261                 }
00262         }
00263         else {
00264                 /* it's local time */
00265 
00266                 /* Daylight saving information got lost in the database
00267                  * so let timegm to guess it. This eliminates the bug when
00268                  * contacts reloaded from the database have different time
00269                  * of expiration by one hour when daylight saving is used
00270                  */
00271                 time.tm_isdst = -1;
00272                 *dst = timelocal(&time);
00273         }
00274         
00275         return 0;
00276 }
00277 
00278 
00279 static inline int ldap_str2db_double(double* dst, char* src)
00280 {
00281         *dst = atof(src);
00282         return 0;
00283 }
00284 
00285 
00286 static inline int ldap_str2db_float(float* dst, char* src)
00287 {
00288         *dst = (float)atof(src);
00289         return 0;
00290 }
00291 
00292 static inline int ldap_fld2db_fld(db_fld_t* fld, str v) {
00293 
00294         switch(fld->type) {
00295                 case DB_CSTR:
00296                         fld->v.cstr = v.s;
00297                         break;
00298 
00299                 case DB_STR:
00300                 case DB_BLOB:
00301                         fld->v.lstr.s = v.s;
00302                         fld->v.lstr.len = v.len;
00303                         break;
00304 
00305                 case DB_INT:
00306                 case DB_BITMAP:
00307                         if (v.s[0] == '\'' && v.s[v.len - 1] == 'B' &&
00308                                 v.s[v.len - 2] == '\'') {
00309                                 v.s++;
00310                                 v.len -= 3;
00311                                 if (ldap_bit2db_int(&fld->v.int4, &v) != 0) {
00312                                         ERR("ldap: Error while converting bit string '%.*s'\n",
00313                                                 v.len, ZSW(v.s));
00314                                         return -1;
00315                                 }
00316                                 break;
00317                         }
00318 
00319                         if (v.len == 4 && !strncasecmp("TRUE", v.s, v.len)) {
00320                                 fld->v.int4 = 1;
00321                                 break;
00322                         }
00323 
00324                         if (v.len == 5 && !strncasecmp("FALSE", v.s, v.len)) {
00325                                 fld->v.int4 = 0;
00326                                 break;
00327                         }
00328 
00329                         if (ldap_int2db_int(&fld->v.int4, &v) != 0) {
00330                                 ERR("ldap: Error while converting %.*s to integer\n",
00331                                         v.len, ZSW(v.s));
00332                                 return -1;
00333                         }
00334                         break;
00335 
00336                 case DB_DATETIME:
00337                         if (ldap_gentime2db_datetime(&fld->v.time, &v) != 0) {
00338                                 ERR("ldap: Error while converting LDAP time value '%.*s'\n",
00339                                         v.len, ZSW(v.s));
00340                                 return -1;
00341                         }
00342                         break;
00343 
00344                 case DB_FLOAT:
00345                         /* We know that the ldap library zero-terminated v.s */
00346                         if (ldap_str2db_float(&fld->v.flt, v.s) != 0) {
00347                                 ERR("ldap: Error while converting '%.*s' to float\n",
00348                                         v.len, ZSW(v.s));
00349                                 return -1;
00350                         }
00351                         break;
00352 
00353                 case DB_DOUBLE:
00354                         /* We know that the ldap library zero-terminated v.s */
00355                         if (ldap_str2db_double(&fld->v.dbl, v.s) != 0) {
00356                                 ERR("ldap: Error while converting '%.*s' to double\n",
00357                                         v.len, ZSW(v.s));
00358                                 return -1;
00359                         }
00360                         break;
00361 
00362                 default:
00363                         ERR("ldap: Unsupported field type: %d\n", fld->type);
00364                         return -1;
00365         }
00366         return 0;
00367 }
00368 
00369 int ld_ldap2fldinit(db_fld_t* fld, LDAP* ldap, LDAPMessage* msg)
00370 {
00371         return ld_ldap2fldex(fld, ldap, msg, 1);
00372 }
00373 
00374 int ld_ldap2fld(db_fld_t* fld, LDAP* ldap, LDAPMessage* msg)
00375 {
00376         return ld_ldap2fldex(fld, ldap, msg, 0);
00377 }
00378 
00379 int ld_incindex(db_fld_t* fld) {
00380         int i;
00381         struct ld_fld* lfld;
00382 
00383 
00384         if (fld == NULL) return 0;
00385 
00386         i = 0;
00387         while (!DB_FLD_EMPTY(fld) && !DB_FLD_LAST(fld[i])) {
00388                 lfld = DB_GET_PAYLOAD(fld + i);
00389                 lfld->index++;
00390                 /* the index limit has been reached */
00391                 if (lfld->index >= lfld->valuesnum) {
00392                         lfld->index = 0;
00393                 } else {
00394                         return 0;
00395                 }
00396                 i++;
00397         }
00398 
00399         /* there is no more value combination left */
00400         return 1;
00401 }
00402 
00403 #define CMP_NUM(fld_v,match_v,fld) \
00404         if (fld_v.fld == match_v.fld) \
00405                 op = 0x02; \
00406         else if (fld_v.fld < match_v.fld) \
00407                 op = 0x01; \
00408         else if (fld_v.fld > match_v.fld) \
00409                 op = 0x04;
00410                 
00411 int ld_ldap2fldex(db_fld_t* fld, LDAP* ldap, LDAPMessage* msg, int init)
00412 {
00413         int i;
00414         struct ld_fld* lfld;
00415         str v;
00416 
00417         if (fld == NULL || msg == NULL) return 0;
00418         for(i = 0; !DB_FLD_EMPTY(fld) && !DB_FLD_LAST(fld[i]); i++) {
00419                 lfld = DB_GET_PAYLOAD(fld + i);
00420                 if (init) {
00421                         if (fld[i].type == DB_NONE) {
00422                                 switch (lfld->syntax) {
00423                                         case LD_SYNTAX_STRING:
00424                                                 fld[i].type = DB_STR;
00425                                                 break;
00426                                         case LD_SYNTAX_INT:
00427                                         case LD_SYNTAX_BOOL:
00428                                         case LD_SYNTAX_BIT:
00429                                                 fld[i].type = DB_INT;
00430                                                 break;
00431                                         case LD_SYNTAX_FLOAT:
00432                                                 fld[i].type = DB_FLOAT;
00433                                                 break;
00434                                                 
00435                                         case LD_SYNTAX_GENTIME:
00436                                                 fld[i].type = DB_DATETIME;
00437                                                 break;
00438                                         case LD_SYNTAX_BIN:
00439                                                 fld[i].type = DB_BITMAP;
00440                                                 break;
00441                                 }
00442 
00443                         }
00444                         
00445                         /* free the values of the previous object */
00446                         if (lfld->values) ldap_value_free_len(lfld->values);
00447                         lfld->values = ldap_get_values_len(ldap, msg, lfld->attr.s);
00448                         lfld->index = 0;
00449                         
00450                         if (lfld->values == NULL || lfld->values[0] == NULL) {
00451                                 fld[i].flags |= DB_NULL;
00452                                 /* index == 0 means no value available */
00453                                 lfld->valuesnum = 0;
00454                                 if (lfld->client_side_filtering && lfld->filter) {
00455                                         int j;
00456                                         /* if the all filter conditions requires NULL value then we can accept the record */
00457                                         for (j=0; lfld->filter[j]; j++) {
00458                                                 if (lfld->filter[j]->flags & DB_NULL && lfld->filter[j]->op == DB_EQ) {
00459                                                         continue;
00460                                                 }
00461                                                 return 1; /* get next record */
00462                                         }
00463                                 }
00464                         } else {
00465                                 /* init the number of values */
00466                                 fld[i].flags &= ~DB_NULL;
00467                                 lfld->valuesnum = ldap_count_values_len(lfld->values);
00468                         
00469                                 if ((lfld->valuesnum > 1 || lfld->client_side_filtering) && lfld->filter) {
00470                                         
00471                                         /* in case of multivalue we must check if value fits in filter criteria.
00472                                            LDAP returns record (having each multivalue) if one particular
00473                                            multivalue fits in filter provided to LDAP search. We need
00474                                            filter out these values manually. It not perfect because 
00475                                            LDAP filtering may be based on different rule/locale than
00476                                            raw (ASCII,...) comparision. 
00477                                         
00478                                            We reorder values so we'll have interesting values located from top up to valuesnum at the end.
00479 
00480                                            The same algorithm is applied for client side filtering
00481                                            
00482                                          */
00483                                          
00484                                         do {
00485                                                 int passed, j;
00486                                                 for (j=0, passed = 1; lfld->filter[j] && passed; j++) {
00487                                                         int op;  /* b0..less, b1..equal, b2..greater, zero..non equal */ 
00488                                                         op = 0x00;
00489                                                         if (lfld->filter[j]->flags & DB_NULL) {
00490                                                                 /* always non equal because field is not NULL */
00491                                                         }
00492                                                         else {
00493                                                                 
00494                                                                 v.s = lfld->values[lfld->index]->bv_val;
00495                                                                 v.len = lfld->values[lfld->index]->bv_len;
00496                                                         
00497                                                                 if (ldap_fld2db_fld(fld + i, v) < 0) {
00498                                                                         passed = 0;
00499                                                                         break; /* for loop */
00500                                                                 }
00501                                                                 else {
00502                                                                         db_fld_val_t v;
00503                                                                         int t;
00504                                                                         static char buf[30];
00505                                                                         t = lfld->filter[j]->type;
00506                                                                         /* we need compare value provided in match condition with value returned by LDAP.
00507                                                                            The match value should be the same type as LDAP value obtained during
00508                                                                            db_cmd(). We implement some basic conversions.
00509                                                                          */
00510                                                                         v = lfld->filter[j]->v;
00511                                                                         if (t == DB_CSTR) {
00512                                                                                 v.lstr.s = v.cstr;
00513                                                                                 v.lstr.len = strlen(v.lstr.s);
00514                                                                                 t = DB_STR;
00515                                                                         } 
00516                                                                         switch (fld[i].type) {
00517                                                                                 case DB_CSTR:
00518                                                                                         fld[i].v.lstr.s = fld[i].v.cstr;
00519                                                                                         fld[i].v.lstr.len = strlen(fld[i].v.lstr.s);
00520                                                                                         fld[i].type = DB_STR; 
00521                                                                                         /* no break */
00522                                                                                 case DB_STR:
00523                                                                                         
00524                                                                                         switch (t) {
00525                                                                                                 case DB_INT:
00526                                                                                                         v.lstr.len = snprintf(buf, sizeof(buf)-1, "%d", v.int4);
00527                                                                                                         v.lstr.s = buf;
00528                                                                                                         break;
00529                                                                                                 /* numeric conversion for double/float not supported because of non unique string representation */
00530                                                                                                 default:
00531                                                                                                         goto skip_conv;
00532                                                                                         }
00533                                                                                         break;
00534                                                                                 case DB_INT:
00535                                                                                         switch (t) {
00536                                                                                                 case DB_DOUBLE:
00537                                                                                                         if ((double)(int)v.dbl != (double)v.dbl) 
00538                                                                                                                 goto skip_conv;
00539                                                                                                         v.int4 = v.dbl;
00540                                                                                                         break;
00541                                                                                                 case DB_FLOAT:
00542                                                                                                         if ((float)(int)v.flt != (float)v.flt) 
00543                                                                                                                 goto skip_conv;
00544                                                                                                         v.int4 = v.flt;
00545                                                                                                         break;
00546                                                                                                 case DB_STR: 
00547                                                                                                         if (v.lstr.len > 0) {
00548                                                                                                                 char c, *p;
00549                                                                                                                 int n;
00550                                                                                                                 c = v.lstr.s[v.lstr.len];
00551                                                                                                                 v.lstr.s[v.lstr.len] = '\0';
00552                                                                                                                 n = strtol(v.lstr.s, &p, 10);
00553                                                                                                                 v.lstr.s[v.lstr.len] = c;
00554                                                                                                                 if ((*p) != '\0') {
00555                                                                                                                         goto skip_conv;
00556                                                                                                                 }
00557                                                                                                                 v.int4 = n;
00558                                                                                                         }
00559                                                                                                         break;
00560                                                                                                 default:
00561                                                                                                         goto skip_conv;
00562                                                                                         }
00563                                                                                         break;
00564                                                                                 case DB_FLOAT:
00565                                                                                         switch (t) {
00566                                                                                                 case DB_DOUBLE:
00567                                                                                                         v.flt = v.dbl;
00568                                                                                                         break;
00569                                                                                                 case DB_INT:
00570                                                                                                         v.flt = v.int4;
00571                                                                                                         break;
00572                                                                                                 #ifdef  __USE_ISOC99
00573                                                                                                 case DB_STR: 
00574                                                                                                         if (v.lstr.len > 0) {
00575                                                                                                                 char c, *p;
00576                                                                                                                 float n;
00577                                                                                                                 c = v.lstr.s[v.lstr.len];
00578                                                                                                                 v.lstr.s[v.lstr.len] = '\0';
00579                                                                                                                 n = strtof(v.lstr.s, &p);
00580                                                                                                                 v.lstr.s[v.lstr.len] = c;
00581                                                                                                                 if ((*p) != '\0') {
00582                                                                                                                         goto skip_conv;
00583                                                                                                                 }
00584                                                                                                                 v.flt = n;
00585                                                                                                         }
00586                                                                                                         break;
00587                                                                                                 #endif
00588                                                                                                 default:
00589                                                                                                         goto skip_conv;
00590                                                                                         }
00591                                                                                         break;
00592                                                                                 case DB_DOUBLE:
00593                                                                                         switch (t) {
00594                                                                                                 case DB_FLOAT:
00595                                                                                                         v.dbl = v.flt;
00596                                                                                                         break;
00597                                                                                                 case DB_INT:
00598                                                                                                         v.dbl = v.int4;
00599                                                                                                         break;
00600                                                                                                 case DB_STR: 
00601                                                                                                         if (v.lstr.len > 0) {
00602                                                                                                                 char c, *p;
00603                                                                                                                 double n;
00604                                                                                                                 c = v.lstr.s[v.lstr.len];
00605                                                                                                                 v.lstr.s[v.lstr.len] = '\0';
00606                                                                                                                 n = strtod(v.lstr.s, &p);
00607                                                                                                                 v.lstr.s[v.lstr.len] = c;
00608                                                                                                                 if ((*p) != '\0') {
00609                                                                                                                         goto skip_conv;
00610                                                                                                                 }
00611                                                                                                                 v.dbl = n;
00612                                                                                                         }
00613                                                                                                         break;
00614                                                                                                 default:
00615                                                                                                         goto skip_conv;
00616                                                                                         }
00617                                                                                         break;
00618                                                                                 case DB_BLOB:
00619                                                                                 case DB_BITMAP:
00620                                                                                 case DB_DATETIME:
00621                                                                                 default:
00622                                                                                         goto skip_conv;
00623                                                                                 }
00624                                                                         t = fld[i].type;
00625                                                                 skip_conv:
00626                                                                         if (t == fld[i].type) {
00627                                                                         
00628                                                                                 switch (fld[i].type) {
00629                                                                                         case DB_CSTR: /* impossible, already converted to DB_STR */
00630                                                                                         case DB_STR:
00631                                                                                                 if (fld[i].v.lstr.len == v.lstr.len) {
00632                                                                                                         op = strncmp(fld[i].v.lstr.s, v.lstr.s, v.lstr.len);
00633                                                                                                         if (op < 0) 
00634                                                                                                                 op = 0x01;
00635                                                                                                         else if (op > 0)
00636                                                                                                                 op = 0x04;
00637                                                                                                         else
00638                                                                                                                 op = 0x02;
00639                                                                                                 }
00640                                                                                                 else if (fld[i].v.lstr.len < v.lstr.len) {
00641                                                                                                         op = strncmp(fld[i].v.lstr.s, v.lstr.s, fld[i].v.lstr.len);
00642                                                                                                         if (op < 0) 
00643                                                                                                                 op = 0x01;
00644                                                                                                         else 
00645                                                                                                                 op = 0x04;
00646                                                                                                 }
00647                                                                                                 else /* if (fld[i].v.lstr.len > v.lstr.len) */ {
00648                                                                                                         op = strncmp(fld[i].v.lstr.s, v.lstr.s, v.lstr.len);
00649                                                                                                         if (op > 0) 
00650                                                                                                                 op = 0x04;
00651                                                                                                         else 
00652                                                                                                                 op = 0x01;
00653                                                                                                 }
00654                                                                                                 break;
00655                                                                                         case DB_BLOB:
00656                                                                                                 if (fld[i].v.blob.len == v.blob.len && memcmp(fld[i].v.blob.s, v.blob.s, v.blob.len) == 0)
00657                                                                                                         op = 0x02;
00658                                                                                                 break;                                                                                  
00659                                                                                         case DB_INT:
00660                                                                                                 CMP_NUM(fld[i].v, v, int4);
00661                                                                                                 break; 
00662                                                                                         case DB_BITMAP:
00663                                                                                                 CMP_NUM(fld[i].v, v, bitmap);
00664                                                                                                 break; 
00665                                                                                         case DB_DATETIME:
00666                                                                                                 CMP_NUM(fld[i].v, v, time);
00667                                                                                                 break; 
00668                                                                                         case DB_FLOAT:
00669                                                                                                 CMP_NUM(fld[i].v, v, flt);
00670                                                                                                 break; 
00671                                                                                         case DB_DOUBLE:
00672                                                                                                 CMP_NUM(fld[i].v, v, dbl);
00673                                                                                                 break; 
00674                                                                                         default:
00675                                                                                                 ;
00676                                                                                 }
00677                                                                         }
00678                                                                          
00679                                                                 }
00680                                                         }
00681                                                         switch (lfld->filter[j]->op) {
00682                                                                 case DB_EQ:
00683                                                                         passed = op == 0x02;
00684                                                                         break;
00685                                                                 case DB_NE:
00686                                                                         passed = (op & 0x02) == 0;
00687                                                                         break;
00688                                                                 case DB_LT:
00689                                                                         passed = op == 0x01;
00690                                                                         break;
00691                                                                 case DB_LEQ:
00692                                                                         passed = op == 0x01 || op == 0x02;
00693                                                                         break;
00694                                                                 case DB_GT:
00695                                                                         passed = op == 0x04;
00696                                                                         break;
00697                                                                 case DB_GEQ:
00698                                                                         passed = op == 0x04 || op == 0x02;
00699                                                                         break;
00700                                                                 default:
00701                                                                         ;
00702                                                         }
00703                                                 }
00704                                                 
00705                                                 if (passed) {
00706                                                         lfld->index++;  
00707                                                 }
00708                                                 else {
00709                                                         char *save_bvval;
00710                                                         int save_bvlen;
00711                                                         int i;
00712                                                         /* shift following values, push useless value at the end and decrease num of values */
00713                                                         
00714                                                         save_bvval = lfld->values[lfld->index]->bv_val;
00715                                                         save_bvlen = lfld->values[lfld->index]->bv_len;
00716                                                         for (i=lfld->index+1; i < lfld->valuesnum; i++) {
00717                                                                  lfld->values[i-1]->bv_val = lfld->values[i]->bv_val;
00718                                                                  lfld->values[i-1]->bv_len = lfld->values[i]->bv_len;
00719                                                         }
00720                                                         lfld->values[lfld->valuesnum-1]->bv_val = save_bvval;
00721                                                         lfld->values[lfld->valuesnum-1]->bv_len = save_bvlen;
00722                                                         lfld->valuesnum--;
00723                                                 }
00724                                 
00725                                         } while (lfld->index < lfld->valuesnum);
00726                                                 
00727                                         if (lfld->valuesnum == 0) {
00728                                                 return 1;  /* get next record */
00729                                         }
00730                                 }
00731                         }       
00732                         /* pointer to the current value */
00733                         lfld->index = 0;
00734                 }
00735 
00736                 /* this is an empty value */
00737                 if (!lfld->valuesnum)
00738                         continue;
00739 
00740                 v.s = lfld->values[lfld->index]->bv_val;
00741                 v.len = lfld->values[lfld->index]->bv_len;
00742 
00743                 if (ldap_fld2db_fld(fld + i, v) < 0) 
00744                         return -1;
00745                 
00746         }
00747         return 0;
00748 }
00749 
00750 
00751 static inline int db_int2ldap_str(struct sbuf* buf, db_fld_t* fld)
00752 {
00753         int len;
00754         char tmp[INT2STR_MAX_LEN + 1];
00755 
00756         len = snprintf(tmp, INT2STR_MAX_LEN + 1, "%-d", fld->v.int4);
00757         if (len < 0 || len >= INT2STR_MAX_LEN + 1) {
00758                 BUG("ldap: Error while converting integer to string\n");
00759                 return -1;
00760         }
00761         return sb_add(buf, tmp, len);
00762 }
00763 
00764 
00765 static inline int db_datetime2ldap_gentime(struct sbuf* buf, db_fld_t* fld)
00766 {
00767         char tmp[16];
00768         struct tm* t;
00769 
00770         t = gmtime(&fld->v.time);
00771         if (strftime(tmp, sizeof(tmp), "%Y%m%d%H%M%SZ", t) != sizeof(tmp)-1) {
00772                 ERR("ldap: Error while converting time_t value to LDAP format\n");
00773                 return -1;
00774         }
00775         return sb_add(buf, tmp, sizeof(tmp)-1);
00776 }
00777 
00778 
00779 static inline int db_int2ldap_bool(struct sbuf* buf, db_fld_t* fld)
00780 {
00781         if (fld->v.int4) 
00782             return sb_add(buf, "TRUE", 4);
00783         else 
00784             return sb_add(buf, "FALSE", 5);
00785 }
00786 
00787 
00788 static inline int db_uint2ldap_int(struct sbuf* buf, db_fld_t* fld)
00789 {
00790         char* num;
00791         int len, v;
00792         
00793         v = fld->v.int4;
00794         num = int2str(v, &len);
00795         return sb_add(buf, num, len);
00796 }
00797 
00798 
00799 static inline int db_bit2ldap_bitstr(struct sbuf* buf, db_fld_t* fld)
00800 {
00801         int rv, i;
00802 
00803         rv = 0;
00804         rv |= sb_add(buf, "'", 1);
00805 
00806         i = 1 << (sizeof(fld->v.int4) * 8 - 1);
00807         while(i) {
00808                 rv |= sb_add(buf, (fld->v.int4 & i)?"1":"0", 1);
00809                 i = i >> 1;
00810         }
00811         rv |= sb_add(buf, "'B", 2);
00812         return rv;
00813 }
00814 
00815 
00816 static inline int db_float2ldap_str(struct sbuf* buf, db_fld_t* fld)
00817 {
00818         char tmp[16];
00819         int len;
00820 
00821         len = snprintf(tmp, 16, "%-10.2f", fld->v.flt);
00822         if (len < 0 || len >= 16) {
00823                 BUG("ldap: Error while converting float to string\n");
00824                 return -1;
00825         }
00826         return sb_add(buf, tmp, len);
00827 }
00828 
00829 
00830 static inline int db_double2ldap_str(struct sbuf* buf, db_fld_t* fld)
00831 {
00832         char tmp[16];
00833         int len;
00834 
00835         len = snprintf(tmp, 16, "%-10.2f", fld->v.dbl);
00836         if (len < 0 || len >= 16) {
00837                 BUG("ldap: Error while converting double to string\n");
00838                 return -1;
00839         }
00840         return sb_add(buf, tmp, len);
00841 }
00842 
00843 static inline int ld_db2ldap(struct sbuf* buf, db_fld_t* fld) {
00844         struct ld_fld* lfld;
00845         
00846         lfld = DB_GET_PAYLOAD(fld);
00847 
00848         switch(fld->type) {
00849                 case DB_CSTR:
00850                         if (sb_add_esc(buf, fld->v.cstr,
00851                                  fld->v.cstr ? strlen(fld->v.cstr) : 0) != 0) goto error;
00852                         break;
00853 
00854                 case DB_STR:
00855                         if (sb_add_esc(buf, fld->v.lstr.s, fld->v.lstr.len) != 0) goto error;
00856                         break;
00857 
00858                 case DB_INT:
00859                         switch(lfld->syntax) {
00860                         case LD_SYNTAX_STRING:
00861                         case LD_SYNTAX_INT:
00862                         case LD_SYNTAX_FLOAT:
00863                                 if (db_int2ldap_str(buf, fld))
00864                                         goto error;
00865                                 break;
00866 
00867                         case LD_SYNTAX_GENTIME:
00868                                 if (db_datetime2ldap_gentime(buf, fld))
00869                                         goto error;
00870                                 break;
00871 
00872                         case LD_SYNTAX_BIT:
00873                                 if (db_bit2ldap_bitstr(buf, fld))
00874                                         goto error;
00875                                 break;
00876 
00877                         case LD_SYNTAX_BOOL:
00878                                 if (db_int2ldap_bool(buf, fld))
00879                                         goto error;
00880                                 break;
00881 
00882                         default:
00883                                 ERR("ldap: Cannot convert integer field %s "
00884                                         "to LDAP attribute %.*s\n",
00885                                         fld->name, lfld->attr.len, ZSW(lfld->attr.s));
00886                                 goto error;
00887                         }
00888                         break;
00889 
00890                 case DB_BITMAP:
00891                         switch(lfld->syntax) {
00892                         case LD_SYNTAX_INT:
00893                                 if (db_uint2ldap_int(buf, fld))
00894                                         goto error;
00895                                 break;
00896 
00897                         case LD_SYNTAX_BIT:
00898                         case LD_SYNTAX_STRING:
00899                                 if (db_bit2ldap_bitstr(buf, fld))
00900                                         goto error;
00901                                 break;
00902 
00903                         default:
00904                                 ERR("ldap: Cannot convert bitmap field %s "
00905                                         "to LDAP attribute %.*s\n",
00906                                         fld->name, lfld->attr.len, ZSW(lfld->attr.s));
00907                                 goto error;
00908                         }
00909                         break;
00910 
00911                 case DB_DATETIME:
00912                         switch(lfld->syntax) {
00913                         case LD_SYNTAX_STRING:
00914                         case LD_SYNTAX_GENTIME:
00915                                 if (db_datetime2ldap_gentime(buf, fld))
00916                                         goto error;
00917                                 break;
00918 
00919                         case LD_SYNTAX_INT:
00920                                 if (db_uint2ldap_int(buf, fld))
00921                                         goto error;
00922                                 break;
00923 
00924                         default:
00925                                 ERR("ldap: Cannot convert datetime field %s "
00926                                         "to LDAP attribute %.*s\n",
00927                                         fld->name, lfld->attr.len, ZSW(lfld->attr.s));
00928                                 goto error;
00929                         }
00930                         break;
00931 
00932                 case DB_FLOAT:
00933                         switch(lfld->syntax) {
00934                         case LD_SYNTAX_STRING:
00935                         case LD_SYNTAX_FLOAT:
00936                                 if (db_float2ldap_str(buf, fld))
00937                                         goto error;
00938                                 break;
00939 
00940                         default:
00941                                 ERR("ldap: Cannot convert float field %s "
00942                                         "to LDAP attribute %.*s\n",
00943                                         fld->name, lfld->attr.len, ZSW(lfld->attr.s));
00944                                 goto error;
00945                         }
00946 
00947                 case DB_DOUBLE:
00948                         switch(lfld->syntax) {
00949                         case LD_SYNTAX_STRING:
00950                         case LD_SYNTAX_FLOAT:
00951                                 if (db_float2ldap_str(buf, fld))
00952                                         goto error;
00953                                 break;
00954 
00955                         default:
00956                                 ERR("ldap: Cannot convert double field %s "
00957                                         "to LDAP attribute %.*s\n",
00958                                         fld->name, lfld->attr.len, ZSW(lfld->attr.s));
00959                                 goto error;
00960                                 break;
00961                         }
00962                         break;
00963 
00964                 case DB_BLOB:
00965                         switch(lfld->syntax) {
00966                         case LD_SYNTAX_STRING:
00967                         case LD_SYNTAX_BIN:
00968                                 if (sb_add_esc(buf, fld->v.lstr.s, fld->v.lstr.len) < 0)
00969                                         goto error;
00970                                 break;
00971 
00972                         default:
00973                                 ERR("ldap: Cannot convert binary field %s "
00974                                         "to LDAP attribute %.*s\n",
00975                                         fld->name, lfld->attr.len, ZSW(lfld->attr.s));
00976                                 goto error;
00977                         }
00978                         break;
00979 
00980                 default:
00981                         BUG("ldap: Unsupported field type encountered: %d\n", fld->type);
00982                         goto error;
00983                 }
00984         return 0;
00985 error:
00986         return -1;
00987 }
00988 
00989 /* skip fields belonging to a field which is requested for filtering at client side */
00990 inline static void skip_client_side_filtering_fields(db_cmd_t* cmd, db_fld_t **fld) {
00991         struct ld_fld* lfld;
00992         db_fld_t *f;
00993 try_next:
00994         if (DB_FLD_EMPTY(*fld) || DB_FLD_LAST(**fld)) return; 
00995         for (f=cmd->result; !DB_FLD_EMPTY(f) && !DB_FLD_LAST(*f); f++) {
00996                 lfld = DB_GET_PAYLOAD(f);
00997                 if (lfld->client_side_filtering && lfld->filter) {
00998                         int j;
00999                         for (j = 0; lfld->filter[j]; j++) {
01000                                 if (lfld->filter[j] == *fld) {
01001                                         (*fld)++;
01002                                         goto try_next;
01003                                 }
01004                         }
01005                 }
01006         }
01007 }
01008                 
01009 int ld_prepare_ldap_filter(char** filter, db_cmd_t* cmd, str* add)
01010 {
01011         db_fld_t* fld;
01012         struct ld_fld* lfld;
01013         int rv = 0;
01014         struct sbuf buf = {
01015                 .s = NULL, .len = 0,
01016                 .size = 0, .increment = 128
01017         };
01018 
01019         fld = cmd->match;
01020         skip_client_side_filtering_fields(cmd, &fld);
01021         
01022         /* Return NULL if there are no fields and no preconfigured search
01023          * string supplied in the configuration file
01024          */
01025         if ((DB_FLD_EMPTY(fld) || DB_FLD_LAST(*fld)) && ((add->s == NULL) || !add->len)) {
01026                 *filter = NULL;
01027                 return 0;
01028         }
01029 
01030         rv = sb_add(&buf, "(&", 2);
01031         if (add->s && add->len) {
01032                 /* Add the filter component specified in the config file */
01033                 rv |= sb_add(&buf, add->s, add->len);
01034         }
01035 
01036         for(; !DB_FLD_EMPTY(fld) && !DB_FLD_LAST(*fld); fld++, skip_client_side_filtering_fields(cmd, &fld)) {
01037                 int op;
01038                 lfld = DB_GET_PAYLOAD(fld);
01039 
01040                 op = fld->op;
01041                 
01042                 if (fld->flags & DB_NULL) {
01043                         switch (op) {
01044                                 case DB_EQ:
01045                                         /* fld==NULL -> (!(x=*)) */
01046                                         op = DB_NE;
01047 
01048                                 case DB_NE:
01049                                         /* fld!=NULL -> (x=*) */
01050                                         op = DB_EQ;
01051                                         break;
01052                                 default:
01053                                         ERR("ldap: Cannot compare null value field %s\n", fld->name);                           
01054                                         goto error;
01055                         }       
01056                 }
01057                 
01058                 /* we need construct operators as:
01059                     not:  (!(fld=val))
01060                     </>:  (!(fld=val))(fld</>val)
01061                 */
01062                 switch (op) {
01063                         case DB_LT:
01064                         case DB_GT:
01065                         case DB_NE:
01066                                 rv |= sb_add(&buf, "(!(", 3);
01067                                 rv |= sb_add(&buf, lfld->attr.s, lfld->attr.len);
01068                                 rv |= sb_add(&buf, "=", 1);
01069                                 if (fld->flags & DB_NULL) {
01070                                         rv |= sb_add(&buf, "*", 1);
01071                                 }
01072                                 else {
01073                                         if (ld_db2ldap(&buf, fld) < 0) {
01074                                                 goto error;
01075                                         }
01076                                 }
01077                                 rv |= sb_add(&buf, "))", 2);
01078                                 break;
01079                         default:
01080                             ;
01081                 }
01082                 if (op != DB_NE) {
01083                         rv |= sb_add(&buf, "(", 1);
01084                         rv |= sb_add(&buf, lfld->attr.s, lfld->attr.len);
01085                         switch (op) {
01086                                 case DB_LEQ:
01087                                 case DB_LT:
01088                                         rv |= sb_add(&buf, "<=", 2);
01089                                         break;
01090                                 case DB_GEQ:
01091                                 case DB_GT:
01092                                         rv |= sb_add(&buf, ">=", 2);
01093                                         break;
01094                                 case DB_EQ:
01095                                         rv |= sb_add(&buf, "=", 1);
01096                                         break;
01097                                 default:
01098                                 ;
01099                         }
01100                         if (fld->flags & DB_NULL) {
01101                                 rv |= sb_add(&buf, "*", 1);
01102                         }
01103                         else {
01104                                 if (ld_db2ldap(&buf, fld) < 0) {
01105                                         goto error;
01106                                 }
01107                         }
01108                         rv |= sb_add(&buf, ")", 1);
01109                 }               
01110         }
01111 
01112         rv |= sb_add(&buf, ")", 1);
01113         rv |= sb_add(&buf, "", 1);
01114         if (rv) goto error;
01115 
01116         *filter = buf.s;
01117         return 0;
01118 
01119 error:
01120         if (buf.s) pkg_free(buf.s);
01121         return -1;
01122 }
01123 
01124