BIND - Update BIND to 9.5.2
[dragonfly.git] / contrib / bind-9.5.2 / lib / isccc / cc.c
blobcfa1db662e38f5e4d304cf0de158a3577c71dcbb
1 /*
2 * Portions Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
3 * Portions Copyright (C) 2001-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
11 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
12 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 * Portions Copyright (C) 2001 Nominum, Inc.
19 * Permission to use, copy, modify, and/or distribute this software for any
20 * purpose with or without fee is hereby granted, provided that the above
21 * copyright notice and this permission notice appear in all copies.
23 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
24 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
26 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
27 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
28 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
29 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
32 /* $Id: cc.c,v 1.18 2007/08/28 07:20:43 tbox Exp $ */
34 /*! \file */
36 #include <config.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <errno.h>
42 #include <isc/assertions.h>
43 #include <isc/hmacmd5.h>
44 #include <isc/print.h>
45 #include <isc/stdlib.h>
47 #include <isccc/alist.h>
48 #include <isccc/base64.h>
49 #include <isccc/cc.h>
50 #include <isccc/result.h>
51 #include <isccc/sexpr.h>
52 #include <isccc/symtab.h>
53 #include <isccc/symtype.h>
54 #include <isccc/util.h>
56 #define MAX_TAGS 256
57 #define DUP_LIFETIME 900
59 typedef isccc_sexpr_t *sexpr_ptr;
61 static unsigned char auth_hmd5[] = {
62 0x05, 0x5f, 0x61, 0x75, 0x74, 0x68, /*%< len + _auth */
63 ISCCC_CCMSGTYPE_TABLE, /*%< message type */
64 0x00, 0x00, 0x00, 0x20, /*%< length == 32 */
65 0x04, 0x68, 0x6d, 0x64, 0x35, /*%< len + hmd5 */
66 ISCCC_CCMSGTYPE_BINARYDATA, /*%< message type */
67 0x00, 0x00, 0x00, 0x16, /*%< length == 22 */
69 * The base64 encoding of one of our HMAC-MD5 signatures is
70 * 22 bytes.
72 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
73 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
74 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
77 #define HMD5_OFFSET 21 /*%< 21 = 6 + 1 + 4 + 5 + 1 + 4 */
78 #define HMD5_LENGTH 22
80 static isc_result_t
81 table_towire(isccc_sexpr_t *alist, isccc_region_t *target);
83 static isc_result_t
84 list_towire(isccc_sexpr_t *alist, isccc_region_t *target);
86 static isc_result_t
87 value_towire(isccc_sexpr_t *elt, isccc_region_t *target)
89 size_t len;
90 unsigned char *lenp;
91 isccc_region_t *vr;
92 isc_result_t result;
94 if (isccc_sexpr_binaryp(elt)) {
95 vr = isccc_sexpr_tobinary(elt);
96 len = REGION_SIZE(*vr);
97 if (REGION_SIZE(*target) < 1 + 4 + len)
98 return (ISC_R_NOSPACE);
99 PUT8(ISCCC_CCMSGTYPE_BINARYDATA, target->rstart);
100 PUT32(len, target->rstart);
101 if (REGION_SIZE(*target) < len)
102 return (ISC_R_NOSPACE);
103 PUT_MEM(vr->rstart, len, target->rstart);
104 } else if (isccc_alist_alistp(elt)) {
105 if (REGION_SIZE(*target) < 1 + 4)
106 return (ISC_R_NOSPACE);
107 PUT8(ISCCC_CCMSGTYPE_TABLE, target->rstart);
109 * Emit a placeholder length.
111 lenp = target->rstart;
112 PUT32(0, target->rstart);
114 * Emit the table.
116 result = table_towire(elt, target);
117 if (result != ISC_R_SUCCESS)
118 return (result);
119 len = (size_t)(target->rstart - lenp);
121 * 'len' is 4 bytes too big, since it counts
122 * the placeholder length too. Adjust and
123 * emit.
125 INSIST(len >= 4U);
126 len -= 4;
127 PUT32(len, lenp);
128 } else if (isccc_sexpr_listp(elt)) {
129 if (REGION_SIZE(*target) < 1 + 4)
130 return (ISC_R_NOSPACE);
131 PUT8(ISCCC_CCMSGTYPE_LIST, target->rstart);
133 * Emit a placeholder length and count.
135 lenp = target->rstart;
136 PUT32(0, target->rstart);
138 * Emit the list.
140 result = list_towire(elt, target);
141 if (result != ISC_R_SUCCESS)
142 return (result);
143 len = (size_t)(target->rstart - lenp);
145 * 'len' is 4 bytes too big, since it counts
146 * the placeholder length. Adjust and emit.
148 INSIST(len >= 4U);
149 len -= 4;
150 PUT32(len, lenp);
153 return (ISC_R_SUCCESS);
156 static isc_result_t
157 table_towire(isccc_sexpr_t *alist, isccc_region_t *target)
159 isccc_sexpr_t *kv, *elt, *k, *v;
160 char *ks;
161 isc_result_t result;
162 size_t len;
164 for (elt = isccc_alist_first(alist);
165 elt != NULL;
166 elt = ISCCC_SEXPR_CDR(elt)) {
167 kv = ISCCC_SEXPR_CAR(elt);
168 k = ISCCC_SEXPR_CAR(kv);
169 ks = isccc_sexpr_tostring(k);
170 v = ISCCC_SEXPR_CDR(kv);
171 len = strlen(ks);
172 INSIST(len <= 255U);
174 * Emit the key name.
176 if (REGION_SIZE(*target) < 1 + len)
177 return (ISC_R_NOSPACE);
178 PUT8(len, target->rstart);
179 PUT_MEM(ks, len, target->rstart);
181 * Emit the value.
183 result = value_towire(v, target);
184 if (result != ISC_R_SUCCESS)
185 return (result);
188 return (ISC_R_SUCCESS);
191 static isc_result_t
192 list_towire(isccc_sexpr_t *list, isccc_region_t *target)
194 isc_result_t result;
196 while (list != NULL) {
197 result = value_towire(ISCCC_SEXPR_CAR(list), target);
198 if (result != ISC_R_SUCCESS)
199 return (result);
200 list = ISCCC_SEXPR_CDR(list);
203 return (ISC_R_SUCCESS);
206 static isc_result_t
207 sign(unsigned char *data, unsigned int length, unsigned char *hmd5,
208 isccc_region_t *secret)
210 isc_hmacmd5_t ctx;
211 isc_result_t result;
212 isccc_region_t source, target;
213 unsigned char digest[ISC_MD5_DIGESTLENGTH];
214 unsigned char digestb64[ISC_MD5_DIGESTLENGTH * 4];
216 isc_hmacmd5_init(&ctx, secret->rstart, REGION_SIZE(*secret));
217 isc_hmacmd5_update(&ctx, data, length);
218 isc_hmacmd5_sign(&ctx, digest);
219 source.rstart = digest;
220 source.rend = digest + ISC_MD5_DIGESTLENGTH;
221 target.rstart = digestb64;
222 target.rend = digestb64 + ISC_MD5_DIGESTLENGTH * 4;
223 result = isccc_base64_encode(&source, 64, "", &target);
224 if (result != ISC_R_SUCCESS)
225 return (result);
226 PUT_MEM(digestb64, HMD5_LENGTH, hmd5);
228 return (ISC_R_SUCCESS);
231 isc_result_t
232 isccc_cc_towire(isccc_sexpr_t *alist, isccc_region_t *target,
233 isccc_region_t *secret)
235 unsigned char *hmd5_rstart, *signed_rstart;
236 isc_result_t result;
238 if (REGION_SIZE(*target) < 4 + sizeof(auth_hmd5))
239 return (ISC_R_NOSPACE);
241 * Emit protocol version.
243 PUT32(1, target->rstart);
244 if (secret != NULL) {
246 * Emit _auth section with zeroed HMAC-MD5 signature.
247 * We'll replace the zeros with the real signature once
248 * we know what it is.
250 hmd5_rstart = target->rstart + HMD5_OFFSET;
251 PUT_MEM(auth_hmd5, sizeof(auth_hmd5), target->rstart);
252 } else
253 hmd5_rstart = NULL;
254 signed_rstart = target->rstart;
256 * Delete any existing _auth section so that we don't try
257 * to encode it.
259 isccc_alist_delete(alist, "_auth");
261 * Emit the message.
263 result = table_towire(alist, target);
264 if (result != ISC_R_SUCCESS)
265 return (result);
266 if (secret != NULL)
267 return (sign(signed_rstart, (target->rstart - signed_rstart),
268 hmd5_rstart, secret));
269 return (ISC_R_SUCCESS);
272 static isc_result_t
273 verify(isccc_sexpr_t *alist, unsigned char *data, unsigned int length,
274 isccc_region_t *secret)
276 isc_hmacmd5_t ctx;
277 isccc_region_t source;
278 isccc_region_t target;
279 isc_result_t result;
280 isccc_sexpr_t *_auth, *hmd5;
281 unsigned char digest[ISC_MD5_DIGESTLENGTH];
282 unsigned char digestb64[ISC_MD5_DIGESTLENGTH * 4];
285 * Extract digest.
287 _auth = isccc_alist_lookup(alist, "_auth");
288 if (_auth == NULL)
289 return (ISC_R_FAILURE);
290 hmd5 = isccc_alist_lookup(_auth, "hmd5");
291 if (hmd5 == NULL)
292 return (ISC_R_FAILURE);
294 * Compute digest.
296 isc_hmacmd5_init(&ctx, secret->rstart, REGION_SIZE(*secret));
297 isc_hmacmd5_update(&ctx, data, length);
298 isc_hmacmd5_sign(&ctx, digest);
299 source.rstart = digest;
300 source.rend = digest + ISC_MD5_DIGESTLENGTH;
301 target.rstart = digestb64;
302 target.rend = digestb64 + ISC_MD5_DIGESTLENGTH * 4;
303 result = isccc_base64_encode(&source, 64, "", &target);
304 if (result != ISC_R_SUCCESS)
305 return (result);
307 * Strip trailing == and NUL terminate target.
309 target.rstart -= 2;
310 *target.rstart++ = '\0';
312 * Verify.
314 if (strcmp((char *)digestb64, isccc_sexpr_tostring(hmd5)) != 0)
315 return (ISCCC_R_BADAUTH);
317 return (ISC_R_SUCCESS);
320 static isc_result_t
321 table_fromwire(isccc_region_t *source, isccc_region_t *secret,
322 isccc_sexpr_t **alistp);
324 static isc_result_t
325 list_fromwire(isccc_region_t *source, isccc_sexpr_t **listp);
327 static isc_result_t
328 value_fromwire(isccc_region_t *source, isccc_sexpr_t **valuep)
330 unsigned int msgtype;
331 isc_uint32_t len;
332 isccc_sexpr_t *value;
333 isccc_region_t active;
334 isc_result_t result;
336 if (REGION_SIZE(*source) < 1 + 4)
337 return (ISC_R_UNEXPECTEDEND);
338 GET8(msgtype, source->rstart);
339 GET32(len, source->rstart);
340 if (REGION_SIZE(*source) < len)
341 return (ISC_R_UNEXPECTEDEND);
342 active.rstart = source->rstart;
343 active.rend = active.rstart + len;
344 source->rstart = active.rend;
345 if (msgtype == ISCCC_CCMSGTYPE_BINARYDATA) {
346 value = isccc_sexpr_frombinary(&active);
347 if (value != NULL) {
348 *valuep = value;
349 result = ISC_R_SUCCESS;
350 } else
351 result = ISC_R_NOMEMORY;
352 } else if (msgtype == ISCCC_CCMSGTYPE_TABLE)
353 result = table_fromwire(&active, NULL, valuep);
354 else if (msgtype == ISCCC_CCMSGTYPE_LIST)
355 result = list_fromwire(&active, valuep);
356 else
357 result = ISCCC_R_SYNTAX;
359 return (result);
362 static isc_result_t
363 table_fromwire(isccc_region_t *source, isccc_region_t *secret,
364 isccc_sexpr_t **alistp)
366 char key[256];
367 isc_uint32_t len;
368 isc_result_t result;
369 isccc_sexpr_t *alist, *value;
370 isc_boolean_t first_tag;
371 unsigned char *checksum_rstart;
373 REQUIRE(alistp != NULL && *alistp == NULL);
375 checksum_rstart = NULL;
376 first_tag = ISC_TRUE;
377 alist = isccc_alist_create();
378 if (alist == NULL)
379 return (ISC_R_NOMEMORY);
381 while (!REGION_EMPTY(*source)) {
382 GET8(len, source->rstart);
383 if (REGION_SIZE(*source) < len) {
384 result = ISC_R_UNEXPECTEDEND;
385 goto bad;
387 GET_MEM(key, len, source->rstart);
388 key[len] = '\0'; /* Ensure NUL termination. */
389 value = NULL;
390 result = value_fromwire(source, &value);
391 if (result != ISC_R_SUCCESS)
392 goto bad;
393 if (isccc_alist_define(alist, key, value) == NULL) {
394 result = ISC_R_NOMEMORY;
395 goto bad;
397 if (first_tag && secret != NULL && strcmp(key, "_auth") == 0)
398 checksum_rstart = source->rstart;
399 first_tag = ISC_FALSE;
402 *alistp = alist;
404 if (secret != NULL) {
405 if (checksum_rstart != NULL)
406 return (verify(alist, checksum_rstart,
407 (source->rend - checksum_rstart),
408 secret));
409 return (ISCCC_R_BADAUTH);
412 return (ISC_R_SUCCESS);
414 bad:
415 isccc_sexpr_free(&alist);
417 return (result);
420 static isc_result_t
421 list_fromwire(isccc_region_t *source, isccc_sexpr_t **listp)
423 isccc_sexpr_t *list, *value;
424 isc_result_t result;
426 list = NULL;
427 while (!REGION_EMPTY(*source)) {
428 value = NULL;
429 result = value_fromwire(source, &value);
430 if (result != ISC_R_SUCCESS) {
431 isccc_sexpr_free(&list);
432 return (result);
434 if (isccc_sexpr_addtolist(&list, value) == NULL) {
435 isccc_sexpr_free(&value);
436 isccc_sexpr_free(&list);
437 return (result);
441 *listp = list;
443 return (ISC_R_SUCCESS);
446 isc_result_t
447 isccc_cc_fromwire(isccc_region_t *source, isccc_sexpr_t **alistp,
448 isccc_region_t *secret)
450 unsigned int size;
451 isc_uint32_t version;
453 size = REGION_SIZE(*source);
454 if (size < 4)
455 return (ISC_R_UNEXPECTEDEND);
456 GET32(version, source->rstart);
457 if (version != 1)
458 return (ISCCC_R_UNKNOWNVERSION);
460 return (table_fromwire(source, secret, alistp));
463 static isc_result_t
464 createmessage(isc_uint32_t version, const char *from, const char *to,
465 isc_uint32_t serial, isccc_time_t now,
466 isccc_time_t expires, isccc_sexpr_t **alistp,
467 isc_boolean_t want_expires)
469 isccc_sexpr_t *alist, *_ctrl, *_data;
470 isc_result_t result;
472 REQUIRE(alistp != NULL && *alistp == NULL);
474 if (version != 1)
475 return (ISCCC_R_UNKNOWNVERSION);
477 alist = isccc_alist_create();
478 if (alist == NULL)
479 return (ISC_R_NOMEMORY);
481 result = ISC_R_NOMEMORY;
483 _ctrl = isccc_alist_create();
484 if (_ctrl == NULL)
485 goto bad;
486 if (isccc_alist_define(alist, "_ctrl", _ctrl) == NULL) {
487 isccc_sexpr_free(&_ctrl);
488 goto bad;
491 _data = isccc_alist_create();
492 if (_data == NULL)
493 goto bad;
494 if (isccc_alist_define(alist, "_data", _data) == NULL) {
495 isccc_sexpr_free(&_data);
496 goto bad;
499 if (isccc_cc_defineuint32(_ctrl, "_ser", serial) == NULL ||
500 isccc_cc_defineuint32(_ctrl, "_tim", now) == NULL ||
501 (want_expires &&
502 isccc_cc_defineuint32(_ctrl, "_exp", expires) == NULL))
503 goto bad;
504 if (from != NULL &&
505 isccc_cc_definestring(_ctrl, "_frm", from) == NULL)
506 goto bad;
507 if (to != NULL &&
508 isccc_cc_definestring(_ctrl, "_to", to) == NULL)
509 goto bad;
511 *alistp = alist;
513 return (ISC_R_SUCCESS);
515 bad:
516 isccc_sexpr_free(&alist);
518 return (result);
521 isc_result_t
522 isccc_cc_createmessage(isc_uint32_t version, const char *from, const char *to,
523 isc_uint32_t serial, isccc_time_t now,
524 isccc_time_t expires, isccc_sexpr_t **alistp)
526 return (createmessage(version, from, to, serial, now, expires,
527 alistp, ISC_TRUE));
530 isc_result_t
531 isccc_cc_createack(isccc_sexpr_t *message, isc_boolean_t ok,
532 isccc_sexpr_t **ackp)
534 char *_frm, *_to;
535 isc_uint32_t serial;
536 isccc_sexpr_t *ack, *_ctrl;
537 isc_result_t result;
538 isccc_time_t t;
540 REQUIRE(ackp != NULL && *ackp == NULL);
542 _ctrl = isccc_alist_lookup(message, "_ctrl");
543 if (_ctrl == NULL ||
544 isccc_cc_lookupuint32(_ctrl, "_ser", &serial) != ISC_R_SUCCESS ||
545 isccc_cc_lookupuint32(_ctrl, "_tim", &t) != ISC_R_SUCCESS)
546 return (ISC_R_FAILURE);
548 * _frm and _to are optional.
550 _frm = NULL;
551 (void)isccc_cc_lookupstring(_ctrl, "_frm", &_frm);
552 _to = NULL;
553 (void)isccc_cc_lookupstring(_ctrl, "_to", &_to);
555 * Create the ack.
557 ack = NULL;
558 result = createmessage(1, _to, _frm, serial, t, 0, &ack, ISC_FALSE);
559 if (result != ISC_R_SUCCESS)
560 return (result);
562 _ctrl = isccc_alist_lookup(ack, "_ctrl");
563 if (_ctrl == NULL)
564 return (ISC_R_FAILURE);
565 if (isccc_cc_definestring(ack, "_ack", (ok) ? "1" : "0") == NULL) {
566 result = ISC_R_NOMEMORY;
567 goto bad;
570 *ackp = ack;
572 return (ISC_R_SUCCESS);
574 bad:
575 isccc_sexpr_free(&ack);
577 return (result);
580 isc_boolean_t
581 isccc_cc_isack(isccc_sexpr_t *message)
583 isccc_sexpr_t *_ctrl;
585 _ctrl = isccc_alist_lookup(message, "_ctrl");
586 if (_ctrl == NULL)
587 return (ISC_FALSE);
588 if (isccc_cc_lookupstring(_ctrl, "_ack", NULL) == ISC_R_SUCCESS)
589 return (ISC_TRUE);
590 return (ISC_FALSE);
593 isc_boolean_t
594 isccc_cc_isreply(isccc_sexpr_t *message)
596 isccc_sexpr_t *_ctrl;
598 _ctrl = isccc_alist_lookup(message, "_ctrl");
599 if (_ctrl == NULL)
600 return (ISC_FALSE);
601 if (isccc_cc_lookupstring(_ctrl, "_rpl", NULL) == ISC_R_SUCCESS)
602 return (ISC_TRUE);
603 return (ISC_FALSE);
606 isc_result_t
607 isccc_cc_createresponse(isccc_sexpr_t *message, isccc_time_t now,
608 isccc_time_t expires, isccc_sexpr_t **alistp)
610 char *_frm, *_to, *type;
611 isc_uint32_t serial;
612 isccc_sexpr_t *alist, *_ctrl, *_data;
613 isc_result_t result;
615 REQUIRE(alistp != NULL && *alistp == NULL);
617 _ctrl = isccc_alist_lookup(message, "_ctrl");
618 _data = isccc_alist_lookup(message, "_data");
619 if (_ctrl == NULL ||
620 _data == NULL ||
621 isccc_cc_lookupuint32(_ctrl, "_ser", &serial) != ISC_R_SUCCESS ||
622 isccc_cc_lookupstring(_data, "type", &type) != ISC_R_SUCCESS)
623 return (ISC_R_FAILURE);
625 * _frm and _to are optional.
627 _frm = NULL;
628 (void)isccc_cc_lookupstring(_ctrl, "_frm", &_frm);
629 _to = NULL;
630 (void)isccc_cc_lookupstring(_ctrl, "_to", &_to);
632 * Create the response.
634 alist = NULL;
635 result = isccc_cc_createmessage(1, _to, _frm, serial, now, expires,
636 &alist);
637 if (result != ISC_R_SUCCESS)
638 return (result);
639 _ctrl = isccc_alist_lookup(alist, "_ctrl");
640 if (_ctrl == NULL)
641 return (ISC_R_FAILURE);
642 _data = isccc_alist_lookup(alist, "_data");
643 if (_data == NULL)
644 return (ISC_R_FAILURE);
645 if (isccc_cc_definestring(_ctrl, "_rpl", "1") == NULL ||
646 isccc_cc_definestring(_data, "type", type) == NULL) {
647 isccc_sexpr_free(&alist);
648 return (ISC_R_NOMEMORY);
651 *alistp = alist;
653 return (ISC_R_SUCCESS);
656 isccc_sexpr_t *
657 isccc_cc_definestring(isccc_sexpr_t *alist, const char *key, const char *str)
659 size_t len;
660 isccc_region_t r;
662 len = strlen(str);
663 DE_CONST(str, r.rstart);
664 r.rend = r.rstart + len;
666 return (isccc_alist_definebinary(alist, key, &r));
669 isccc_sexpr_t *
670 isccc_cc_defineuint32(isccc_sexpr_t *alist, const char *key, isc_uint32_t i)
672 char b[100];
673 size_t len;
674 isccc_region_t r;
676 snprintf(b, sizeof(b), "%u", i);
677 len = strlen(b);
678 r.rstart = (unsigned char *)b;
679 r.rend = (unsigned char *)b + len;
681 return (isccc_alist_definebinary(alist, key, &r));
684 isc_result_t
685 isccc_cc_lookupstring(isccc_sexpr_t *alist, const char *key, char **strp)
687 isccc_sexpr_t *kv, *v;
689 kv = isccc_alist_assq(alist, key);
690 if (kv != NULL) {
691 v = ISCCC_SEXPR_CDR(kv);
692 if (isccc_sexpr_binaryp(v)) {
693 if (strp != NULL)
694 *strp = isccc_sexpr_tostring(v);
695 return (ISC_R_SUCCESS);
696 } else
697 return (ISC_R_EXISTS);
700 return (ISC_R_NOTFOUND);
703 isc_result_t
704 isccc_cc_lookupuint32(isccc_sexpr_t *alist, const char *key,
705 isc_uint32_t *uintp)
707 isccc_sexpr_t *kv, *v;
709 kv = isccc_alist_assq(alist, key);
710 if (kv != NULL) {
711 v = ISCCC_SEXPR_CDR(kv);
712 if (isccc_sexpr_binaryp(v)) {
713 if (uintp != NULL)
714 *uintp = (isc_uint32_t)
715 strtoul(isccc_sexpr_tostring(v),
716 NULL, 10);
717 return (ISC_R_SUCCESS);
718 } else
719 return (ISC_R_EXISTS);
722 return (ISC_R_NOTFOUND);
725 static void
726 symtab_undefine(char *key, unsigned int type, isccc_symvalue_t value,
727 void *arg)
729 UNUSED(type);
730 UNUSED(value);
731 UNUSED(arg);
733 free(key);
736 static isc_boolean_t
737 symtab_clean(char *key, unsigned int type, isccc_symvalue_t value,
738 void *arg)
740 isccc_time_t *now;
742 UNUSED(key);
743 UNUSED(type);
745 now = arg;
747 if (*now < value.as_uinteger)
748 return (ISC_FALSE);
749 if ((*now - value.as_uinteger) < DUP_LIFETIME)
750 return (ISC_FALSE);
751 return (ISC_TRUE);
754 isc_result_t
755 isccc_cc_createsymtab(isccc_symtab_t **symtabp)
757 return (isccc_symtab_create(11897, symtab_undefine, NULL, ISC_FALSE,
758 symtabp));
761 void
762 isccc_cc_cleansymtab(isccc_symtab_t *symtab, isccc_time_t now)
764 isccc_symtab_foreach(symtab, symtab_clean, &now);
767 static isc_boolean_t
768 has_whitespace(const char *str)
770 char c;
772 if (str == NULL)
773 return (ISC_FALSE);
774 while ((c = *str++) != '\0') {
775 if (c == ' ' || c == '\t' || c == '\n')
776 return (ISC_TRUE);
778 return (ISC_FALSE);
781 isc_result_t
782 isccc_cc_checkdup(isccc_symtab_t *symtab, isccc_sexpr_t *message,
783 isccc_time_t now)
785 const char *_frm;
786 const char *_to;
787 char *_ser, *_tim, *tmp;
788 isc_result_t result;
789 char *key;
790 size_t len;
791 isccc_symvalue_t value;
792 isccc_sexpr_t *_ctrl;
794 _ctrl = isccc_alist_lookup(message, "_ctrl");
795 if (_ctrl == NULL ||
796 isccc_cc_lookupstring(_ctrl, "_ser", &_ser) != ISC_R_SUCCESS ||
797 isccc_cc_lookupstring(_ctrl, "_tim", &_tim) != ISC_R_SUCCESS)
798 return (ISC_R_FAILURE);
800 * _frm and _to are optional.
802 if (isccc_cc_lookupstring(_ctrl, "_frm", &tmp) != ISC_R_SUCCESS)
803 _frm = "";
804 else
805 _frm = tmp;
806 if (isccc_cc_lookupstring(_ctrl, "_to", &tmp) != ISC_R_SUCCESS)
807 _to = "";
808 else
809 _to = tmp;
811 * Ensure there is no newline in any of the strings. This is so
812 * we can write them to a file later.
814 if (has_whitespace(_frm) || has_whitespace(_to) ||
815 has_whitespace(_ser) || has_whitespace(_tim))
816 return (ISC_R_FAILURE);
817 len = strlen(_frm) + strlen(_to) + strlen(_ser) + strlen(_tim) + 4;
818 key = malloc(len);
819 if (key == NULL)
820 return (ISC_R_NOMEMORY);
821 snprintf(key, len, "%s;%s;%s;%s", _frm, _to, _ser, _tim);
822 value.as_uinteger = now;
823 result = isccc_symtab_define(symtab, key, ISCCC_SYMTYPE_CCDUP, value,
824 isccc_symexists_reject);
825 if (result != ISC_R_SUCCESS) {
826 free(key);
827 return (result);
830 return (ISC_R_SUCCESS);