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