]> git.ipfire.org Git - thirdparty/openssl.git/blob - crypto/txt_db/txt_db.c
Identify and move common internal libcrypto header files
[thirdparty/openssl.git] / crypto / txt_db / txt_db.c
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 "internal/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 esc = 0;
75 long ln = 0;
76 int i, add, n;
77 int size = BUFSIZE;
78 int offset = 0;
79 char *p, *f;
80 OPENSSL_STRING *pp;
81 BUF_MEM *buf = NULL;
82
83 if ((buf = BUF_MEM_new()) == NULL)
84 goto err;
85 if (!BUF_MEM_grow(buf, size))
86 goto err;
87
88 if ((ret = OPENSSL_malloc(sizeof(*ret))) == NULL)
89 goto err;
90 ret->num_fields = num;
91 ret->index = NULL;
92 ret->qual = NULL;
93 if ((ret->data = sk_OPENSSL_PSTRING_new_null()) == NULL)
94 goto err;
95 if ((ret->index = OPENSSL_malloc(sizeof(*ret->index) * num)) == NULL)
96 goto err;
97 if ((ret->qual = OPENSSL_malloc(sizeof(*(ret->qual)) * num)) == NULL)
98 goto err;
99 for (i = 0; i < num; i++) {
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 if (offset != 0) {
109 size += BUFSIZE;
110 if (!BUF_MEM_grow_clean(buf, size))
111 goto err;
112 }
113 buf->data[offset] = '\0';
114 BIO_gets(in, &(buf->data[offset]), size - offset);
115 ln++;
116 if (buf->data[offset] == '\0')
117 break;
118 if ((offset == 0) && (buf->data[0] == '#'))
119 continue;
120 i = strlen(&(buf->data[offset]));
121 offset += i;
122 if (buf->data[offset - 1] != '\n')
123 continue;
124 else {
125 buf->data[offset - 1] = '\0'; /* blat the '\n' */
126 if ((p = OPENSSL_malloc(add + offset)) == NULL)
127 goto err;
128 offset = 0;
129 }
130 pp = (char **)p;
131 p += add;
132 n = 0;
133 pp[n++] = p;
134 i = 0;
135 f = buf->data;
136
137 esc = 0;
138 for (;;) {
139 if (*f == '\0')
140 break;
141 if (*f == '\t') {
142 if (esc)
143 p--;
144 else {
145 *(p++) = '\0';
146 f++;
147 if (n >= num)
148 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 #if !defined(OPENSSL_NO_STDIO) /* temporary fix :-( */
159 fprintf(stderr,
160 "wrong number of fields on line %ld (looking for field %d, got %d, '%s' left)\n",
161 ln, num, n, f);
162 #endif
163 goto err;
164 }
165 pp[n] = p;
166 if (!sk_OPENSSL_PSTRING_push(ret->data, pp))
167 goto err;
168 }
169 BUF_MEM_free(buf);
170 return ret;
171 err:
172 BUF_MEM_free(buf);
173 if (ret != NULL) {
174 sk_OPENSSL_PSTRING_free(ret->data);
175 OPENSSL_free(ret->index);
176 OPENSSL_free(ret->qual);
177 OPENSSL_free(ret);
178 }
179 return (NULL);
180 }
181
182 OPENSSL_STRING *TXT_DB_get_by_index(TXT_DB *db, int idx,
183 OPENSSL_STRING *value)
184 {
185 OPENSSL_STRING *ret;
186 LHASH_OF(OPENSSL_STRING) *lh;
187
188 if (idx >= db->num_fields) {
189 db->error = DB_ERROR_INDEX_OUT_OF_RANGE;
190 return (NULL);
191 }
192 lh = db->index[idx];
193 if (lh == NULL) {
194 db->error = DB_ERROR_NO_INDEX;
195 return (NULL);
196 }
197 ret = lh_OPENSSL_STRING_retrieve(lh, value);
198 db->error = DB_ERROR_OK;
199 return (ret);
200 }
201
202 int TXT_DB_create_index(TXT_DB *db, int field, int (*qual) (OPENSSL_STRING *),
203 LHASH_HASH_FN_TYPE hash, LHASH_COMP_FN_TYPE cmp)
204 {
205 LHASH_OF(OPENSSL_STRING) *idx;
206 OPENSSL_STRING *r;
207 int i, n;
208
209 if (field >= db->num_fields) {
210 db->error = DB_ERROR_INDEX_OUT_OF_RANGE;
211 return (0);
212 }
213 /* FIXME: we lose type checking at this point */
214 if ((idx = (LHASH_OF(OPENSSL_STRING) *)lh_new(hash, cmp)) == NULL) {
215 db->error = DB_ERROR_MALLOC;
216 return (0);
217 }
218 n = sk_OPENSSL_PSTRING_num(db->data);
219 for (i = 0; i < n; i++) {
220 r = sk_OPENSSL_PSTRING_value(db->data, i);
221 if ((qual != NULL) && (qual(r) == 0))
222 continue;
223 if ((r = lh_OPENSSL_STRING_insert(idx, r)) != NULL) {
224 db->error = DB_ERROR_INDEX_CLASH;
225 db->arg1 = sk_OPENSSL_PSTRING_find(db->data, r);
226 db->arg2 = i;
227 lh_OPENSSL_STRING_free(idx);
228 return (0);
229 }
230 }
231 lh_OPENSSL_STRING_free(db->index[field]);
232 db->index[field] = idx;
233 db->qual[field] = qual;
234 return (1);
235 }
236
237 long TXT_DB_write(BIO *out, TXT_DB *db)
238 {
239 long i, j, n, nn, l, tot = 0;
240 char *p, **pp, *f;
241 BUF_MEM *buf = NULL;
242 long ret = -1;
243
244 if ((buf = BUF_MEM_new()) == NULL)
245 goto err;
246 n = sk_OPENSSL_PSTRING_num(db->data);
247 nn = db->num_fields;
248 for (i = 0; i < n; i++) {
249 pp = sk_OPENSSL_PSTRING_value(db->data, i);
250
251 l = 0;
252 for (j = 0; j < nn; j++) {
253 if (pp[j] != NULL)
254 l += strlen(pp[j]);
255 }
256 if (!BUF_MEM_grow_clean(buf, (int)(l * 2 + nn)))
257 goto err;
258
259 p = buf->data;
260 for (j = 0; j < nn; j++) {
261 f = pp[j];
262 if (f != NULL)
263 for (;;) {
264 if (*f == '\0')
265 break;
266 if (*f == '\t')
267 *(p++) = '\\';
268 *(p++) = *(f++);
269 }
270 *(p++) = '\t';
271 }
272 p[-1] = '\n';
273 j = p - buf->data;
274 if (BIO_write(out, buf->data, (int)j) != j)
275 goto err;
276 tot += j;
277 }
278 ret = tot;
279 err:
280 BUF_MEM_free(buf);
281 return (ret);
282 }
283
284 int TXT_DB_insert(TXT_DB *db, OPENSSL_STRING *row)
285 {
286 int i;
287 OPENSSL_STRING *r;
288
289 for (i = 0; i < db->num_fields; i++) {
290 if (db->index[i] != NULL) {
291 if ((db->qual[i] != NULL) && (db->qual[i] (row) == 0))
292 continue;
293 r = lh_OPENSSL_STRING_retrieve(db->index[i], row);
294 if (r != NULL) {
295 db->error = DB_ERROR_INDEX_CLASH;
296 db->arg1 = i;
297 db->arg_row = r;
298 goto err;
299 }
300 }
301 }
302 /* We have passed the index checks, now just append and insert */
303 if (!sk_OPENSSL_PSTRING_push(db->data, row)) {
304 db->error = DB_ERROR_MALLOC;
305 goto err;
306 }
307
308 for (i = 0; i < db->num_fields; i++) {
309 if (db->index[i] != NULL) {
310 if ((db->qual[i] != NULL) && (db->qual[i] (row) == 0))
311 continue;
312 (void)lh_OPENSSL_STRING_insert(db->index[i], row);
313 }
314 }
315 return (1);
316 err:
317 return (0);
318 }
319
320 void TXT_DB_free(TXT_DB *db)
321 {
322 int i, n;
323 char **p, *max;
324
325 if (db == NULL)
326 return;
327
328 if (db->index != NULL) {
329 for (i = db->num_fields - 1; i >= 0; i--)
330 lh_OPENSSL_STRING_free(db->index[i]);
331 OPENSSL_free(db->index);
332 }
333 OPENSSL_free(db->qual);
334 if (db->data != NULL) {
335 for (i = sk_OPENSSL_PSTRING_num(db->data) - 1; i >= 0; i--) {
336 /*
337 * check if any 'fields' have been allocated from outside of the
338 * initial block
339 */
340 p = sk_OPENSSL_PSTRING_value(db->data, i);
341 max = p[db->num_fields]; /* last address */
342 if (max == NULL) { /* new row */
343 for (n = 0; n < db->num_fields; n++)
344 OPENSSL_free(p[n]);
345 } else {
346 for (n = 0; n < db->num_fields; n++) {
347 if (((p[n] < (char *)p) || (p[n] > max)))
348 OPENSSL_free(p[n]);
349 }
350 }
351 OPENSSL_free(sk_OPENSSL_PSTRING_value(db->data, i));
352 }
353 sk_OPENSSL_PSTRING_free(db->data);
354 }
355 OPENSSL_free(db);
356 }