xref: /freebsd/crypto/openssl/crypto/txt_db/txt_db.c (revision 315ee00f)
1 /*
2  * Copyright 1995-2022 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 
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