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