1 /* crypto/txt_db/txt_db.c */
   2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
   3  * All rights reserved.
   4  *
   5  * This package is an SSL implementation written
   6  * by Eric Young (eay@cryptsoft.com).
   7  * The implementation was written so as to conform with Netscapes SSL.
   8  *
   9  * This library is free for commercial and non-commercial use as long as
  10  * the following conditions are aheared to.  The following conditions
  11  * apply to all code found in this distribution, be it the RC4, RSA,
  12  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
  13  * included with this distribution is covered by the same copyright terms
  14  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
  15  *
  16  * Copyright remains Eric Young's, and as such any Copyright notices in
  17  * the code are not to be removed.
  18  * If this package is used in a product, Eric Young should be given attribution
  19  * as the author of the parts of the library used.
  20  * This can be in the form of a textual message at program startup or
  21  * in documentation (online or textual) provided with the package.
  22  *
  23  * Redistribution and use in source and binary forms, with or without
  24  * modification, are permitted provided that the following conditions
  25  * are met:
  26  * 1. Redistributions of source code must retain the copyright
  27  *    notice, this list of conditions and the following disclaimer.
  28  * 2. Redistributions in binary form must reproduce the above copyright
  29  *    notice, this list of conditions and the following disclaimer in the
  30  *    documentation and/or other materials provided with the distribution.
  31  * 3. All advertising materials mentioning features or use of this software
  32  *    must display the following acknowledgement:
  33  *    "This product includes cryptographic software written by
  34  *     Eric Young (eay@cryptsoft.com)"
  35  *    The word 'cryptographic' can be left out if the rouines from the library
  36  *    being used are not cryptographic related :-).
  37  * 4. If you include any Windows specific code (or a derivative thereof) from
  38  *    the apps directory (application code) you must include an acknowledgement:
  39  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
  40  *
  41  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
  42  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  43  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  44  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  45  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  46  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  47  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  49  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  50  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  51  * SUCH DAMAGE.
  52  *
  53  * The licence and distribution terms for any publically available version or
  54  * derivative of this code cannot be changed.  i.e. this code cannot simply be
  55  * copied and put under another distribution licence
  56  * [including the GNU Public Licence.]
  57  */
  58 
  59 #include <stdio.h>
  60 #include <stdlib.h>
  61 #include <string.h>
  62 #include "cryptlib.h"
  63 #include <openssl/buffer.h>
  64 #include <openssl/txt_db.h>
  65 
  66 #undef BUFSIZE
  67 #define BUFSIZE 512
  68 
  69 const char TXT_DB_version[]="TXT_DB" OPENSSL_VERSION_PTEXT;
  70 
  71 TXT_DB *TXT_DB_read(BIO *in, int num)
  72         {
  73         TXT_DB *ret=NULL;
  74         int er=1;
  75         int esc=0;
  76         long ln=0;
  77         int i,add,n;
  78         int size=BUFSIZE;
  79         int offset=0;
  80         char *p,*f;
  81         OPENSSL_STRING *pp;
  82         BUF_MEM *buf=NULL;
  83 
  84         if ((buf=BUF_MEM_new()) == NULL) goto err;
  85         if (!BUF_MEM_grow(buf,size)) goto err;
  86 
  87         if ((ret=OPENSSL_malloc(sizeof(TXT_DB))) == NULL)
  88                 goto err;
  89         ret->num_fields=num;
  90         ret->index=NULL;
  91         ret->qual=NULL;
  92         if ((ret->data=sk_OPENSSL_PSTRING_new_null()) == NULL)
  93                 goto err;
  94         if ((ret->index=OPENSSL_malloc(sizeof(*ret->index)*num)) == NULL)
  95                 goto err;
  96         if ((ret->qual=OPENSSL_malloc(sizeof(*(ret->qual))*num)) == NULL)
  97                 goto err;
  98         for (i=0; i<num; i++)
  99                 {
 100                 ret->index[i]=NULL;
 101                 ret->qual[i]=NULL;
 102                 }
 103 
 104         add=(num+1)*sizeof(char *);
 105         buf->data[size-1]='\0';
 106         offset=0;
 107         for (;;)
 108                 {
 109                 if (offset != 0)
 110                         {
 111                         size+=BUFSIZE;
 112                         if (!BUF_MEM_grow_clean(buf,size)) goto err;
 113                         }
 114                 buf->data[offset]='\0';
 115                 BIO_gets(in,&(buf->data[offset]),size-offset);
 116                 ln++;
 117                 if (buf->data[offset] == '\0') break;
 118                 if ((offset == 0) && (buf->data[0] == '#')) continue;
 119                 i=strlen(&(buf->data[offset]));
 120                 offset+=i;
 121                 if (buf->data[offset-1] != '\n')
 122                         continue;
 123                 else
 124                         {
 125                         buf->data[offset-1]='\0'; /* blat the '\n' */
 126                         if (!(p=OPENSSL_malloc(add+offset))) goto err;
 127                         offset=0;
 128                         }
 129                 pp=(char **)p;
 130                 p+=add;
 131                 n=0;
 132                 pp[n++]=p;
 133                 i=0;
 134                 f=buf->data;
 135 
 136                 esc=0;
 137                 for (;;)
 138                         {
 139                         if (*f == '\0') break;
 140                         if (*f == '\t')
 141                                 {
 142                                 if (esc)
 143                                         p--;
 144                                 else
 145                                         {
 146                                         *(p++)='\0';
 147                                         f++;
 148                                         if (n >=  num) break;
 149                                         pp[n++]=p;
 150                                         continue;
 151                                         }
 152                                 }
 153                         esc=(*f == '\\');
 154                         *(p++)= *(f++);
 155                         }
 156                 *(p++)='\0';
 157                 if ((n != num) || (*f != '\0'))
 158                         {
 159 #if !defined(OPENSSL_NO_STDIO) && !defined(OPENSSL_SYS_WIN16)   /* temporary fix :-( */
 160                         fprintf(stderr,"wrong number of fields on line %ld (looking for field %d, got %d, '%s' left)\n",ln,num,n,f);
 161 #endif
 162                         er=2;
 163                         goto err;
 164                         }
 165                 pp[n]=p;
 166                 if (!sk_OPENSSL_PSTRING_push(ret->data,pp))
 167                         {
 168 #if !defined(OPENSSL_NO_STDIO) && !defined(OPENSSL_SYS_WIN16)   /* temporary fix :-( */
 169                         fprintf(stderr,"failure in sk_push\n");
 170 #endif
 171                         er=2;
 172                         goto err;
 173                         }
 174                 }
 175         er=0;
 176 err:
 177         BUF_MEM_free(buf);
 178         if (er)
 179                 {
 180 #if !defined(OPENSSL_NO_STDIO) && !defined(OPENSSL_SYS_WIN16)
 181                 if (er == 1) fprintf(stderr,"OPENSSL_malloc failure\n");
 182 #endif
 183                 if (ret != NULL)
 184                         {
 185                         if (ret->data != NULL) sk_OPENSSL_PSTRING_free(ret->data);
 186                         if (ret->index != NULL) OPENSSL_free(ret->index);
 187                         if (ret->qual != NULL) OPENSSL_free(ret->qual);
 188                         if (ret != NULL) OPENSSL_free(ret);
 189                         }
 190                 return(NULL);
 191                 }
 192         else
 193                 return(ret);
 194         }
 195 
 196 OPENSSL_STRING *TXT_DB_get_by_index(TXT_DB *db, int idx, OPENSSL_STRING *value)
 197         {
 198         OPENSSL_STRING *ret;
 199         LHASH_OF(OPENSSL_STRING) *lh;
 200 
 201         if (idx >= db->num_fields)
 202                 {
 203                 db->error=DB_ERROR_INDEX_OUT_OF_RANGE;
 204                 return(NULL);
 205                 }
 206         lh=db->index[idx];
 207         if (lh == NULL)
 208                 {
 209                 db->error=DB_ERROR_NO_INDEX;
 210                 return(NULL);
 211                 }
 212         ret=lh_OPENSSL_STRING_retrieve(lh,value);
 213         db->error=DB_ERROR_OK;
 214         return(ret);
 215         }
 216 
 217 int TXT_DB_create_index(TXT_DB *db, int field, int (*qual)(OPENSSL_STRING *),
 218                         LHASH_HASH_FN_TYPE hash, LHASH_COMP_FN_TYPE cmp)
 219         {
 220         LHASH_OF(OPENSSL_STRING) *idx;
 221         OPENSSL_STRING *r;
 222         int i,n;
 223 
 224         if (field >= db->num_fields)
 225                 {
 226                 db->error=DB_ERROR_INDEX_OUT_OF_RANGE;
 227                 return(0);
 228                 }
 229         /* FIXME: we lose type checking at this point */
 230         if ((idx=(LHASH_OF(OPENSSL_STRING) *)lh_new(hash,cmp)) == NULL)
 231                 {
 232                 db->error=DB_ERROR_MALLOC;
 233                 return(0);
 234                 }
 235         n=sk_OPENSSL_PSTRING_num(db->data);
 236         for (i=0; i<n; i++)
 237                 {
 238                 r=sk_OPENSSL_PSTRING_value(db->data,i);
 239                 if ((qual != NULL) && (qual(r) == 0)) continue;
 240                 if ((r=lh_OPENSSL_STRING_insert(idx,r)) != NULL)
 241                         {
 242                         db->error=DB_ERROR_INDEX_CLASH;
 243                         db->arg1=sk_OPENSSL_PSTRING_find(db->data,r);
 244                         db->arg2=i;
 245                         lh_OPENSSL_STRING_free(idx);
 246                         return(0);
 247                         }
 248                 }
 249         if (db->index[field] != NULL) lh_OPENSSL_STRING_free(db->index[field]);
 250         db->index[field]=idx;
 251         db->qual[field]=qual;
 252         return(1);
 253         }
 254 
 255 long TXT_DB_write(BIO *out, TXT_DB *db)
 256         {
 257         long i,j,n,nn,l,tot=0;
 258         char *p,**pp,*f;
 259         BUF_MEM *buf=NULL;
 260         long ret= -1;
 261 
 262         if ((buf=BUF_MEM_new()) == NULL)
 263                 goto err;
 264         n=sk_OPENSSL_PSTRING_num(db->data);
 265         nn=db->num_fields;
 266         for (i=0; i<n; i++)
 267                 {
 268                 pp=sk_OPENSSL_PSTRING_value(db->data,i);
 269 
 270                 l=0;
 271                 for (j=0; j<nn; j++)
 272                         {
 273                         if (pp[j] != NULL)
 274                                 l+=strlen(pp[j]);
 275                         }
 276                 if (!BUF_MEM_grow_clean(buf,(int)(l*2+nn))) goto err;
 277 
 278                 p=buf->data;
 279                 for (j=0; j<nn; j++)
 280                         {
 281                         f=pp[j];
 282                         if (f != NULL)
 283                                 for (;;)
 284                                         {
 285                                         if (*f == '\0') break;
 286                                         if (*f == '\t') *(p++)='\\';
 287                                         *(p++)= *(f++);
 288                                         }
 289                         *(p++)='\t';
 290                         }
 291                 p[-1]='\n';
 292                 j=p-buf->data;
 293                 if (BIO_write(out,buf->data,(int)j) != j)
 294                         goto err;
 295                 tot+=j;
 296                 }
 297         ret=tot;
 298 err:
 299         if (buf != NULL) BUF_MEM_free(buf);
 300         return(ret);
 301         }
 302 
 303 int TXT_DB_insert(TXT_DB *db, OPENSSL_STRING *row)
 304         {
 305         int i;
 306         OPENSSL_STRING *r;
 307 
 308         for (i=0; i<db->num_fields; i++)
 309                 {
 310                 if (db->index[i] != NULL)
 311                         {
 312                         if ((db->qual[i] != NULL) &&
 313                                 (db->qual[i](row) == 0)) continue;
 314                         r=lh_OPENSSL_STRING_retrieve(db->index[i],row);
 315                         if (r != NULL)
 316                                 {
 317                                 db->error=DB_ERROR_INDEX_CLASH;
 318                                 db->arg1=i;
 319                                 db->arg_row=r;
 320                                 goto err;
 321                                 }
 322                         }
 323                 }
 324         /* We have passed the index checks, now just append and insert */
 325         if (!sk_OPENSSL_PSTRING_push(db->data,row))
 326                 {
 327                 db->error=DB_ERROR_MALLOC;
 328                 goto err;
 329                 }
 330 
 331         for (i=0; i<db->num_fields; i++)
 332                 {
 333                 if (db->index[i] != NULL)
 334                         {
 335                         if ((db->qual[i] != NULL) &&
 336                                 (db->qual[i](row) == 0)) continue;
 337                         (void)lh_OPENSSL_STRING_insert(db->index[i],row);
 338                         }
 339                 }
 340         return(1);
 341 err:
 342         return(0);
 343         }
 344 
 345 void TXT_DB_free(TXT_DB *db)
 346         {
 347         int i,n;
 348         char **p,*max;
 349 
 350         if(db == NULL)
 351             return;
 352 
 353         if (db->index != NULL)
 354                 {
 355                 for (i=db->num_fields-1; i>=0; i--)
 356                         if (db->index[i] != NULL) lh_OPENSSL_STRING_free(db->index[i]);
 357                 OPENSSL_free(db->index);
 358                 }
 359         if (db->qual != NULL)
 360                 OPENSSL_free(db->qual);
 361         if (db->data != NULL)
 362                 {
 363                 for (i=sk_OPENSSL_PSTRING_num(db->data)-1; i>=0; i--)
 364                         {
 365                         /* check if any 'fields' have been allocated
 366                          * from outside of the initial block */
 367                         p=sk_OPENSSL_PSTRING_value(db->data,i);
 368                         max=p[db->num_fields]; /* last address */
 369                         if (max == NULL) /* new row */
 370                                 {
 371                                 for (n=0; n<db->num_fields; n++)
 372                                         if (p[n] != NULL) OPENSSL_free(p[n]);
 373                                 }
 374                         else
 375                                 {
 376                                 for (n=0; n<db->num_fields; n++)
 377                                         {
 378                                         if (((p[n] < (char *)p) || (p[n] > max))
 379                                                 && (p[n] != NULL))
 380                                                 OPENSSL_free(p[n]);
 381                                         }
 382                                 }
 383                         OPENSSL_free(sk_OPENSSL_PSTRING_value(db->data,i));
 384                         }
 385                 sk_OPENSSL_PSTRING_free(db->data);
 386                 }
 387         OPENSSL_free(db);
 388         }