1 /* 2 * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the OpenSSL license (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <string.h> 13 #include "internal/cryptlib.h" 14 #include <openssl/buffer.h> 15 #include <openssl/txt_db.h> 16 17 #undef BUFSIZE 18 #define BUFSIZE 512 19 20 TXT_DB *TXT_DB_read(BIO *in, int num) 21 { 22 TXT_DB *ret = NULL; 23 int esc = 0; 24 long ln = 0; 25 int i, add, n; 26 int size = BUFSIZE; 27 int offset = 0; 28 char *p, *f; 29 OPENSSL_STRING *pp; 30 BUF_MEM *buf = NULL; 31 32 if ((buf = BUF_MEM_new()) == NULL) 33 goto err; 34 if (!BUF_MEM_grow(buf, size)) 35 goto err; 36 37 if ((ret = OPENSSL_malloc(sizeof(*ret))) == NULL) 38 goto err; 39 ret->num_fields = num; 40 ret->index = NULL; 41 ret->qual = NULL; 42 if ((ret->data = sk_OPENSSL_PSTRING_new_null()) == NULL) 43 goto err; 44 if ((ret->index = OPENSSL_malloc(sizeof(*ret->index) * num)) == NULL) 45 goto err; 46 if ((ret->qual = OPENSSL_malloc(sizeof(*(ret->qual)) * num)) == NULL) 47 goto err; 48 for (i = 0; i < num; i++) { 49 ret->index[i] = NULL; 50 ret->qual[i] = NULL; 51 } 52 53 add = (num + 1) * sizeof(char *); 54 buf->data[size - 1] = '\0'; 55 offset = 0; 56 for (;;) { 57 if (offset != 0) { 58 size += BUFSIZE; 59 if (!BUF_MEM_grow_clean(buf, size)) 60 goto err; 61 } 62 buf->data[offset] = '\0'; 63 BIO_gets(in, &(buf->data[offset]), size - offset); 64 ln++; 65 if (buf->data[offset] == '\0') 66 break; 67 if ((offset == 0) && (buf->data[0] == '#')) 68 continue; 69 i = strlen(&(buf->data[offset])); 70 offset += i; 71 if (buf->data[offset - 1] != '\n') 72 continue; 73 else { 74 buf->data[offset - 1] = '\0'; /* blat the '\n' */ 75 if ((p = OPENSSL_malloc(add + offset)) == NULL) 76 goto err; 77 offset = 0; 78 } 79 pp = (char **)p; 80 p += add; 81 n = 0; 82 pp[n++] = p; 83 i = 0; 84 f = buf->data; 85 86 esc = 0; 87 for (;;) { 88 if (*f == '\0') 89 break; 90 if (*f == '\t') { 91 if (esc) 92 p--; 93 else { 94 *(p++) = '\0'; 95 f++; 96 if (n >= num) 97 break; 98 pp[n++] = p; 99 continue; 100 } 101 } 102 esc = (*f == '\\'); 103 *(p++) = *(f++); 104 } 105 *(p++) = '\0'; 106 if ((n != num) || (*f != '\0')) { 107 OPENSSL_free(pp); 108 ret->error = DB_ERROR_WRONG_NUM_FIELDS; 109 goto err; 110 } 111 pp[n] = p; 112 if (!sk_OPENSSL_PSTRING_push(ret->data, pp)) { 113 OPENSSL_free(pp); 114 goto err; 115 } 116 } 117 BUF_MEM_free(buf); 118 return ret; 119 err: 120 BUF_MEM_free(buf); 121 if (ret != NULL) { 122 sk_OPENSSL_PSTRING_free(ret->data); 123 OPENSSL_free(ret->index); 124 OPENSSL_free(ret->qual); 125 OPENSSL_free(ret); 126 } 127 return NULL; 128 } 129 130 OPENSSL_STRING *TXT_DB_get_by_index(TXT_DB *db, int idx, 131 OPENSSL_STRING *value) 132 { 133 OPENSSL_STRING *ret; 134 LHASH_OF(OPENSSL_STRING) *lh; 135 136 if (idx >= db->num_fields) { 137 db->error = DB_ERROR_INDEX_OUT_OF_RANGE; 138 return NULL; 139 } 140 lh = db->index[idx]; 141 if (lh == NULL) { 142 db->error = DB_ERROR_NO_INDEX; 143 return NULL; 144 } 145 ret = lh_OPENSSL_STRING_retrieve(lh, value); 146 db->error = DB_ERROR_OK; 147 return ret; 148 } 149 150 int TXT_DB_create_index(TXT_DB *db, int field, int (*qual) (OPENSSL_STRING *), 151 OPENSSL_LH_HASHFUNC hash, OPENSSL_LH_COMPFUNC cmp) 152 { 153 LHASH_OF(OPENSSL_STRING) *idx; 154 OPENSSL_STRING *r, *k; 155 int i, n; 156 157 if (field >= db->num_fields) { 158 db->error = DB_ERROR_INDEX_OUT_OF_RANGE; 159 return 0; 160 } 161 /* FIXME: we lose type checking at this point */ 162 if ((idx = (LHASH_OF(OPENSSL_STRING) *)OPENSSL_LH_new(hash, cmp)) == NULL) { 163 db->error = DB_ERROR_MALLOC; 164 return 0; 165 } 166 n = sk_OPENSSL_PSTRING_num(db->data); 167 for (i = 0; i < n; i++) { 168 r = sk_OPENSSL_PSTRING_value(db->data, i); 169 if ((qual != NULL) && (qual(r) == 0)) 170 continue; 171 if ((k = lh_OPENSSL_STRING_insert(idx, r)) != NULL) { 172 db->error = DB_ERROR_INDEX_CLASH; 173 db->arg1 = sk_OPENSSL_PSTRING_find(db->data, k); 174 db->arg2 = i; 175 lh_OPENSSL_STRING_free(idx); 176 return 0; 177 } 178 if (lh_OPENSSL_STRING_retrieve(idx, r) == NULL) { 179 db->error = DB_ERROR_MALLOC; 180 lh_OPENSSL_STRING_free(idx); 181 return 0; 182 } 183 } 184 lh_OPENSSL_STRING_free(db->index[field]); 185 db->index[field] = idx; 186 db->qual[field] = qual; 187 return 1; 188 } 189 190 long TXT_DB_write(BIO *out, TXT_DB *db) 191 { 192 long i, j, n, nn, l, tot = 0; 193 char *p, **pp, *f; 194 BUF_MEM *buf = NULL; 195 long ret = -1; 196 197 if ((buf = BUF_MEM_new()) == NULL) 198 goto err; 199 n = sk_OPENSSL_PSTRING_num(db->data); 200 nn = db->num_fields; 201 for (i = 0; i < n; i++) { 202 pp = sk_OPENSSL_PSTRING_value(db->data, i); 203 204 l = 0; 205 for (j = 0; j < nn; j++) { 206 if (pp[j] != NULL) 207 l += strlen(pp[j]); 208 } 209 if (!BUF_MEM_grow_clean(buf, (int)(l * 2 + nn))) 210 goto err; 211 212 p = buf->data; 213 for (j = 0; j < nn; j++) { 214 f = pp[j]; 215 if (f != NULL) 216 for (;;) { 217 if (*f == '\0') 218 break; 219 if (*f == '\t') 220 *(p++) = '\\'; 221 *(p++) = *(f++); 222 } 223 *(p++) = '\t'; 224 } 225 p[-1] = '\n'; 226 j = p - buf->data; 227 if (BIO_write(out, buf->data, (int)j) != j) 228 goto err; 229 tot += j; 230 } 231 ret = tot; 232 err: 233 BUF_MEM_free(buf); 234 return ret; 235 } 236 237 int TXT_DB_insert(TXT_DB *db, OPENSSL_STRING *row) 238 { 239 int i; 240 OPENSSL_STRING *r; 241 242 for (i = 0; i < db->num_fields; i++) { 243 if (db->index[i] != NULL) { 244 if ((db->qual[i] != NULL) && (db->qual[i] (row) == 0)) 245 continue; 246 r = lh_OPENSSL_STRING_retrieve(db->index[i], row); 247 if (r != NULL) { 248 db->error = DB_ERROR_INDEX_CLASH; 249 db->arg1 = i; 250 db->arg_row = r; 251 goto err; 252 } 253 } 254 } 255 256 for (i = 0; i < db->num_fields; i++) { 257 if (db->index[i] != NULL) { 258 if ((db->qual[i] != NULL) && (db->qual[i] (row) == 0)) 259 continue; 260 (void)lh_OPENSSL_STRING_insert(db->index[i], row); 261 if (lh_OPENSSL_STRING_retrieve(db->index[i], row) == NULL) 262 goto err1; 263 } 264 } 265 if (!sk_OPENSSL_PSTRING_push(db->data, row)) 266 goto err1; 267 return 1; 268 269 err1: 270 db->error = DB_ERROR_MALLOC; 271 while (i-- > 0) { 272 if (db->index[i] != NULL) { 273 if ((db->qual[i] != NULL) && (db->qual[i] (row) == 0)) 274 continue; 275 (void)lh_OPENSSL_STRING_delete(db->index[i], row); 276 } 277 } 278 err: 279 return 0; 280 } 281 282 void TXT_DB_free(TXT_DB *db) 283 { 284 int i, n; 285 char **p, *max; 286 287 if (db == NULL) 288 return; 289 if (db->index != NULL) { 290 for (i = db->num_fields - 1; i >= 0; i--) 291 lh_OPENSSL_STRING_free(db->index[i]); 292 OPENSSL_free(db->index); 293 } 294 OPENSSL_free(db->qual); 295 if (db->data != NULL) { 296 for (i = sk_OPENSSL_PSTRING_num(db->data) - 1; i >= 0; i--) { 297 /* 298 * check if any 'fields' have been allocated from outside of the 299 * initial block 300 */ 301 p = sk_OPENSSL_PSTRING_value(db->data, i); 302 max = p[db->num_fields]; /* last address */ 303 if (max == NULL) { /* new row */ 304 for (n = 0; n < db->num_fields; n++) 305 OPENSSL_free(p[n]); 306 } else { 307 for (n = 0; n < db->num_fields; n++) { 308 if (((p[n] < (char *)p) || (p[n] > max))) 309 OPENSSL_free(p[n]); 310 } 311 } 312 OPENSSL_free(sk_OPENSSL_PSTRING_value(db->data, i)); 313 } 314 sk_OPENSSL_PSTRING_free(db->data); 315 } 316 OPENSSL_free(db); 317 } 318