1 /* $NetBSD: cc.c,v 1.8 2014/12/10 04:38:01 christos Exp $ */
4 * Portions Copyright (C) 2004-2007, 2012, 2013 Internet Systems Consortium, Inc. ("ISC")
5 * Portions Copyright (C) 2001-2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
12 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
13 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
14 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 * Portions Copyright (C) 2001 Nominum, Inc.
21 * Permission to use, copy, modify, and/or distribute this software for any
22 * purpose with or without fee is hereby granted, provided that the above
23 * copyright notice and this permission notice appear in all copies.
25 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
26 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
27 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
28 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
29 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
30 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
31 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
34 /* Id: cc.c,v 1.18 2007/08/28 07:20:43 tbox Exp */
44 #include <isc/assertions.h>
45 #include <isc/hmacmd5.h>
46 #include <isc/hmacsha.h>
47 #include <isc/print.h>
49 #include <isc/stdlib.h>
51 #include <isccc/alist.h>
52 #include <isccc/base64.h>
54 #include <isccc/result.h>
55 #include <isccc/sexpr.h>
56 #include <isccc/symtab.h>
57 #include <isccc/symtype.h>
58 #include <isccc/util.h>
61 #define DUP_LIFETIME 900
63 typedef isccc_sexpr_t
*sexpr_ptr
;
65 static unsigned char auth_hmd5
[] = {
66 0x05, 0x5f, 0x61, 0x75, 0x74, 0x68, /*%< len + _auth */
67 ISCCC_CCMSGTYPE_TABLE
, /*%< message type */
68 0x00, 0x00, 0x00, 0x20, /*%< length == 32 */
69 0x04, 0x68, 0x6d, 0x64, 0x35, /*%< len + hmd5 */
70 ISCCC_CCMSGTYPE_BINARYDATA
, /*%< message type */
71 0x00, 0x00, 0x00, 0x16, /*%< length == 22 */
73 * The base64 encoding of one of our HMAC-MD5 signatures is
76 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
77 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
78 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
81 #define HMD5_OFFSET 21 /*%< 21 = 6 + 1 + 4 + 5 + 1 + 4 */
82 #define HMD5_LENGTH 22
84 static unsigned char auth_hsha
[] = {
85 0x05, 0x5f, 0x61, 0x75, 0x74, 0x68, /*%< len + _auth */
86 ISCCC_CCMSGTYPE_TABLE
, /*%< message type */
87 0x00, 0x00, 0x00, 0x63, /*%< length == 99 */
88 0x04, 0x68, 0x73, 0x68, 0x61, /*%< len + hsha */
89 ISCCC_CCMSGTYPE_BINARYDATA
, /*%< message type */
90 0x00, 0x00, 0x00, 0x59, /*%< length == 89 */
91 0x00, /*%< algorithm */
93 * The base64 encoding of one of our HMAC-SHA* signatures is
96 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
97 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
98 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
99 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
100 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
101 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
102 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
103 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
104 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
105 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
106 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
109 #define HSHA_OFFSET 22 /*%< 21 = 6 + 1 + 4 + 5 + 1 + 4 + 1 */
110 #define HSHA_LENGTH 88
113 table_towire(isccc_sexpr_t
*alist
, isccc_region_t
*target
);
116 list_towire(isccc_sexpr_t
*alist
, isccc_region_t
*target
);
119 value_towire(isccc_sexpr_t
*elt
, isccc_region_t
*target
)
126 if (isccc_sexpr_binaryp(elt
)) {
127 vr
= isccc_sexpr_tobinary(elt
);
128 len
= REGION_SIZE(*vr
);
129 if (REGION_SIZE(*target
) < 1 + 4 + len
)
130 return (ISC_R_NOSPACE
);
131 PUT8(ISCCC_CCMSGTYPE_BINARYDATA
, target
->rstart
);
132 PUT32(len
, target
->rstart
);
133 if (REGION_SIZE(*target
) < len
)
134 return (ISC_R_NOSPACE
);
135 PUT_MEM(vr
->rstart
, len
, target
->rstart
);
136 } else if (isccc_alist_alistp(elt
)) {
137 if (REGION_SIZE(*target
) < 1 + 4)
138 return (ISC_R_NOSPACE
);
139 PUT8(ISCCC_CCMSGTYPE_TABLE
, target
->rstart
);
141 * Emit a placeholder length.
143 lenp
= target
->rstart
;
144 PUT32(0, target
->rstart
);
148 result
= table_towire(elt
, target
);
149 if (result
!= ISC_R_SUCCESS
)
151 len
= (unsigned int)(target
->rstart
- lenp
);
153 * 'len' is 4 bytes too big, since it counts
154 * the placeholder length too. Adjust and
160 } else if (isccc_sexpr_listp(elt
)) {
161 if (REGION_SIZE(*target
) < 1 + 4)
162 return (ISC_R_NOSPACE
);
163 PUT8(ISCCC_CCMSGTYPE_LIST
, target
->rstart
);
165 * Emit a placeholder length and count.
167 lenp
= target
->rstart
;
168 PUT32(0, target
->rstart
);
172 result
= list_towire(elt
, target
);
173 if (result
!= ISC_R_SUCCESS
)
175 len
= (unsigned int)(target
->rstart
- lenp
);
177 * 'len' is 4 bytes too big, since it counts
178 * the placeholder length. Adjust and emit.
185 return (ISC_R_SUCCESS
);
189 table_towire(isccc_sexpr_t
*alist
, isccc_region_t
*target
)
191 isccc_sexpr_t
*kv
, *elt
, *k
, *v
;
196 for (elt
= isccc_alist_first(alist
);
198 elt
= ISCCC_SEXPR_CDR(elt
)) {
199 kv
= ISCCC_SEXPR_CAR(elt
);
200 k
= ISCCC_SEXPR_CAR(kv
);
201 ks
= isccc_sexpr_tostring(k
);
202 v
= ISCCC_SEXPR_CDR(kv
);
208 if (REGION_SIZE(*target
) < 1 + len
)
209 return (ISC_R_NOSPACE
);
210 PUT8(len
, target
->rstart
);
211 PUT_MEM(ks
, len
, target
->rstart
);
215 result
= value_towire(v
, target
);
216 if (result
!= ISC_R_SUCCESS
)
220 return (ISC_R_SUCCESS
);
224 list_towire(isccc_sexpr_t
*list
, isccc_region_t
*target
)
228 while (list
!= NULL
) {
229 result
= value_towire(ISCCC_SEXPR_CAR(list
), target
);
230 if (result
!= ISC_R_SUCCESS
)
232 list
= ISCCC_SEXPR_CDR(list
);
235 return (ISC_R_SUCCESS
);
239 sign(unsigned char *data
, unsigned int length
, unsigned char *hmac
,
240 isc_uint32_t algorithm
, isccc_region_t
*secret
)
245 isc_hmacsha224_t h224
;
246 isc_hmacsha256_t h256
;
247 isc_hmacsha384_t h384
;
248 isc_hmacsha512_t h512
;
251 isccc_region_t source
, target
;
252 unsigned char digest
[ISC_SHA512_DIGESTLENGTH
];
253 unsigned char digestb64
[HSHA_LENGTH
+ 4];
255 source
.rstart
= digest
;
258 case ISCCC_ALG_HMACMD5
:
259 isc_hmacmd5_init(&ctx
.hmd5
, secret
->rstart
,
260 REGION_SIZE(*secret
));
261 isc_hmacmd5_update(&ctx
.hmd5
, data
, length
);
262 isc_hmacmd5_sign(&ctx
.hmd5
, digest
);
263 source
.rend
= digest
+ ISC_MD5_DIGESTLENGTH
;
266 case ISCCC_ALG_HMACSHA1
:
267 isc_hmacsha1_init(&ctx
.hsha
, secret
->rstart
,
268 REGION_SIZE(*secret
));
269 isc_hmacsha1_update(&ctx
.hsha
, data
, length
);
270 isc_hmacsha1_sign(&ctx
.hsha
, digest
,
271 ISC_SHA1_DIGESTLENGTH
);
272 source
.rend
= digest
+ ISC_SHA1_DIGESTLENGTH
;
275 case ISCCC_ALG_HMACSHA224
:
276 isc_hmacsha224_init(&ctx
.h224
, secret
->rstart
,
277 REGION_SIZE(*secret
));
278 isc_hmacsha224_update(&ctx
.h224
, data
, length
);
279 isc_hmacsha224_sign(&ctx
.h224
, digest
,
280 ISC_SHA224_DIGESTLENGTH
);
281 source
.rend
= digest
+ ISC_SHA224_DIGESTLENGTH
;
284 case ISCCC_ALG_HMACSHA256
:
285 isc_hmacsha256_init(&ctx
.h256
, secret
->rstart
,
286 REGION_SIZE(*secret
));
287 isc_hmacsha256_update(&ctx
.h256
, data
, length
);
288 isc_hmacsha256_sign(&ctx
.h256
, digest
,
289 ISC_SHA256_DIGESTLENGTH
);
290 source
.rend
= digest
+ ISC_SHA256_DIGESTLENGTH
;
293 case ISCCC_ALG_HMACSHA384
:
294 isc_hmacsha384_init(&ctx
.h384
, secret
->rstart
,
295 REGION_SIZE(*secret
));
296 isc_hmacsha384_update(&ctx
.h384
, data
, length
);
297 isc_hmacsha384_sign(&ctx
.h384
, digest
,
298 ISC_SHA384_DIGESTLENGTH
);
299 source
.rend
= digest
+ ISC_SHA384_DIGESTLENGTH
;
302 case ISCCC_ALG_HMACSHA512
:
303 isc_hmacsha512_init(&ctx
.h512
, secret
->rstart
,
304 REGION_SIZE(*secret
));
305 isc_hmacsha512_update(&ctx
.h512
, data
, length
);
306 isc_hmacsha512_sign(&ctx
.h512
, digest
,
307 ISC_SHA512_DIGESTLENGTH
);
308 source
.rend
= digest
+ ISC_SHA512_DIGESTLENGTH
;
312 return (ISC_R_FAILURE
);
315 memset(digestb64
, 0, sizeof(digestb64
));
316 target
.rstart
= digestb64
;
317 target
.rend
= digestb64
+ sizeof(digestb64
);
318 result
= isccc_base64_encode(&source
, 64, "", &target
);
319 if (result
!= ISC_R_SUCCESS
)
321 if (algorithm
== ISCCC_ALG_HMACMD5
)
322 PUT_MEM(digestb64
, HMD5_LENGTH
, hmac
);
324 PUT_MEM(digestb64
, HSHA_LENGTH
, hmac
);
325 return (ISC_R_SUCCESS
);
329 isccc_cc_towire(isccc_sexpr_t
*alist
, isccc_region_t
*target
,
330 isc_uint32_t algorithm
, isccc_region_t
*secret
)
332 unsigned char *hmac_rstart
, *signed_rstart
;
335 if (algorithm
== ISCCC_ALG_HMACMD5
) {
336 if (REGION_SIZE(*target
) < 4 + sizeof(auth_hmd5
))
337 return (ISC_R_NOSPACE
);
339 if (REGION_SIZE(*target
) < 4 + sizeof(auth_hsha
))
340 return (ISC_R_NOSPACE
);
344 * Emit protocol version.
346 PUT32(1, target
->rstart
);
347 if (secret
!= NULL
) {
349 * Emit _auth section with zeroed HMAC signature.
350 * We'll replace the zeros with the real signature once
351 * we know what it is.
353 if (algorithm
== ISCCC_ALG_HMACMD5
) {
354 hmac_rstart
= target
->rstart
+ HMD5_OFFSET
;
355 PUT_MEM(auth_hmd5
, sizeof(auth_hmd5
), target
->rstart
);
357 unsigned char *hmac_alg
;
359 hmac_rstart
= target
->rstart
+ HSHA_OFFSET
;
360 hmac_alg
= hmac_rstart
- 1;
361 PUT_MEM(auth_hsha
, sizeof(auth_hsha
), target
->rstart
);
362 PUT8(algorithm
, hmac_alg
);
366 signed_rstart
= target
->rstart
;
368 * Delete any existing _auth section so that we don't try
371 isccc_alist_delete(alist
, "_auth");
375 result
= table_towire(alist
, target
);
376 if (result
!= ISC_R_SUCCESS
)
379 return (sign(signed_rstart
,
380 (unsigned int)(target
->rstart
- signed_rstart
),
381 hmac_rstart
, algorithm
, secret
));
382 return (ISC_R_SUCCESS
);
386 verify(isccc_sexpr_t
*alist
, unsigned char *data
, unsigned int length
,
387 isc_uint32_t algorithm
, isccc_region_t
*secret
)
392 isc_hmacsha224_t h224
;
393 isc_hmacsha256_t h256
;
394 isc_hmacsha384_t h384
;
395 isc_hmacsha512_t h512
;
397 isccc_region_t source
;
398 isccc_region_t target
;
400 isccc_sexpr_t
*_auth
, *hmac
;
401 unsigned char digest
[ISC_SHA512_DIGESTLENGTH
];
402 unsigned char digestb64
[HSHA_LENGTH
* 4];
407 _auth
= isccc_alist_lookup(alist
, "_auth");
409 return (ISC_R_FAILURE
);
410 if (algorithm
== ISCCC_ALG_HMACMD5
)
411 hmac
= isccc_alist_lookup(_auth
, "hmd5");
413 hmac
= isccc_alist_lookup(_auth
, "hsha");
415 return (ISC_R_FAILURE
);
419 source
.rstart
= digest
;
420 target
.rstart
= digestb64
;
422 case ISCCC_ALG_HMACMD5
:
423 isc_hmacmd5_init(&ctx
.hmd5
, secret
->rstart
,
424 REGION_SIZE(*secret
));
425 isc_hmacmd5_update(&ctx
.hmd5
, data
, length
);
426 isc_hmacmd5_sign(&ctx
.hmd5
, digest
);
427 source
.rend
= digest
+ ISC_MD5_DIGESTLENGTH
;
430 case ISCCC_ALG_HMACSHA1
:
431 isc_hmacsha1_init(&ctx
.hsha
, secret
->rstart
,
432 REGION_SIZE(*secret
));
433 isc_hmacsha1_update(&ctx
.hsha
, data
, length
);
434 isc_hmacsha1_sign(&ctx
.hsha
, digest
,
435 ISC_SHA1_DIGESTLENGTH
);
436 source
.rend
= digest
+ ISC_SHA1_DIGESTLENGTH
;
439 case ISCCC_ALG_HMACSHA224
:
440 isc_hmacsha224_init(&ctx
.h224
, secret
->rstart
,
441 REGION_SIZE(*secret
));
442 isc_hmacsha224_update(&ctx
.h224
, data
, length
);
443 isc_hmacsha224_sign(&ctx
.h224
, digest
,
444 ISC_SHA224_DIGESTLENGTH
);
445 source
.rend
= digest
+ ISC_SHA224_DIGESTLENGTH
;
448 case ISCCC_ALG_HMACSHA256
:
449 isc_hmacsha256_init(&ctx
.h256
, secret
->rstart
,
450 REGION_SIZE(*secret
));
451 isc_hmacsha256_update(&ctx
.h256
, data
, length
);
452 isc_hmacsha256_sign(&ctx
.h256
, digest
,
453 ISC_SHA256_DIGESTLENGTH
);
454 source
.rend
= digest
+ ISC_SHA256_DIGESTLENGTH
;
457 case ISCCC_ALG_HMACSHA384
:
458 isc_hmacsha384_init(&ctx
.h384
, secret
->rstart
,
459 REGION_SIZE(*secret
));
460 isc_hmacsha384_update(&ctx
.h384
, data
, length
);
461 isc_hmacsha384_sign(&ctx
.h384
, digest
,
462 ISC_SHA384_DIGESTLENGTH
);
463 source
.rend
= digest
+ ISC_SHA384_DIGESTLENGTH
;
466 case ISCCC_ALG_HMACSHA512
:
467 isc_hmacsha512_init(&ctx
.h512
, secret
->rstart
,
468 REGION_SIZE(*secret
));
469 isc_hmacsha512_update(&ctx
.h512
, data
, length
);
470 isc_hmacsha512_sign(&ctx
.h512
, digest
,
471 ISC_SHA512_DIGESTLENGTH
);
472 source
.rend
= digest
+ ISC_SHA512_DIGESTLENGTH
;
476 return (ISC_R_FAILURE
);
478 target
.rstart
= digestb64
;
479 target
.rend
= digestb64
+ sizeof(digestb64
);
480 memset(digestb64
, 0, sizeof(digestb64
));
481 result
= isccc_base64_encode(&source
, 64, "", &target
);
482 if (result
!= ISC_R_SUCCESS
)
488 if (algorithm
== ISCCC_ALG_HMACMD5
) {
489 unsigned char *value
;
491 value
= (unsigned char *) isccc_sexpr_tostring(hmac
);
492 if (!isc_safe_memcmp(value
, digestb64
, HMD5_LENGTH
))
493 return (ISCCC_R_BADAUTH
);
495 unsigned char *value
;
498 value
= (unsigned char *) isccc_sexpr_tostring(hmac
);
500 if ((valalg
!= algorithm
) ||
501 (!isc_safe_memcmp(value
, digestb64
, HSHA_LENGTH
)))
502 return (ISCCC_R_BADAUTH
);
505 return (ISC_R_SUCCESS
);
509 table_fromwire(isccc_region_t
*source
, isccc_region_t
*secret
,
510 isc_uint32_t algorithm
, isccc_sexpr_t
**alistp
);
513 list_fromwire(isccc_region_t
*source
, isccc_sexpr_t
**listp
);
516 value_fromwire(isccc_region_t
*source
, isccc_sexpr_t
**valuep
)
518 unsigned int msgtype
;
520 isccc_sexpr_t
*value
;
521 isccc_region_t active
;
524 if (REGION_SIZE(*source
) < 1 + 4)
525 return (ISC_R_UNEXPECTEDEND
);
526 GET8(msgtype
, source
->rstart
);
527 GET32(len
, source
->rstart
);
528 if (REGION_SIZE(*source
) < len
)
529 return (ISC_R_UNEXPECTEDEND
);
530 active
.rstart
= source
->rstart
;
531 active
.rend
= active
.rstart
+ len
;
532 source
->rstart
= active
.rend
;
533 if (msgtype
== ISCCC_CCMSGTYPE_BINARYDATA
) {
534 value
= isccc_sexpr_frombinary(&active
);
537 result
= ISC_R_SUCCESS
;
539 result
= ISC_R_NOMEMORY
;
540 } else if (msgtype
== ISCCC_CCMSGTYPE_TABLE
)
541 result
= table_fromwire(&active
, NULL
, 0, valuep
);
542 else if (msgtype
== ISCCC_CCMSGTYPE_LIST
)
543 result
= list_fromwire(&active
, valuep
);
545 result
= ISCCC_R_SYNTAX
;
551 table_fromwire(isccc_region_t
*source
, isccc_region_t
*secret
,
552 isc_uint32_t algorithm
, isccc_sexpr_t
**alistp
)
557 isccc_sexpr_t
*alist
, *value
;
558 isc_boolean_t first_tag
;
559 unsigned char *checksum_rstart
;
561 REQUIRE(alistp
!= NULL
&& *alistp
== NULL
);
563 checksum_rstart
= NULL
;
564 first_tag
= ISC_TRUE
;
565 alist
= isccc_alist_create();
567 return (ISC_R_NOMEMORY
);
569 while (!REGION_EMPTY(*source
)) {
570 GET8(len
, source
->rstart
);
571 if (REGION_SIZE(*source
) < len
) {
572 result
= ISC_R_UNEXPECTEDEND
;
575 GET_MEM(key
, len
, source
->rstart
);
576 key
[len
] = '\0'; /* Ensure NUL termination. */
578 result
= value_fromwire(source
, &value
);
579 if (result
!= ISC_R_SUCCESS
)
581 if (isccc_alist_define(alist
, key
, value
) == NULL
) {
582 result
= ISC_R_NOMEMORY
;
585 if (first_tag
&& secret
!= NULL
&& strcmp(key
, "_auth") == 0)
586 checksum_rstart
= source
->rstart
;
587 first_tag
= ISC_FALSE
;
590 if (secret
!= NULL
) {
591 if (checksum_rstart
!= NULL
)
592 result
= verify(alist
, checksum_rstart
,
594 (source
->rend
- checksum_rstart
),
597 result
= ISCCC_R_BADAUTH
;
599 result
= ISC_R_SUCCESS
;
602 if (result
== ISC_R_SUCCESS
)
605 isccc_sexpr_free(&alist
);
611 list_fromwire(isccc_region_t
*source
, isccc_sexpr_t
**listp
)
613 isccc_sexpr_t
*list
, *value
;
617 while (!REGION_EMPTY(*source
)) {
619 result
= value_fromwire(source
, &value
);
620 if (result
!= ISC_R_SUCCESS
) {
621 isccc_sexpr_free(&list
);
624 if (isccc_sexpr_addtolist(&list
, value
) == NULL
) {
625 isccc_sexpr_free(&value
);
626 isccc_sexpr_free(&list
);
633 return (ISC_R_SUCCESS
);
637 isccc_cc_fromwire(isccc_region_t
*source
, isccc_sexpr_t
**alistp
,
638 isc_uint32_t algorithm
, isccc_region_t
*secret
)
641 isc_uint32_t version
;
643 size
= REGION_SIZE(*source
);
645 return (ISC_R_UNEXPECTEDEND
);
646 GET32(version
, source
->rstart
);
648 return (ISCCC_R_UNKNOWNVERSION
);
650 return (table_fromwire(source
, secret
, algorithm
, alistp
));
654 createmessage(isc_uint32_t version
, const char *from
, const char *to
,
655 isc_uint32_t serial
, isccc_time_t now
,
656 isccc_time_t expires
, isccc_sexpr_t
**alistp
,
657 isc_boolean_t want_expires
)
659 isccc_sexpr_t
*alist
, *_ctrl
, *_data
;
662 REQUIRE(alistp
!= NULL
&& *alistp
== NULL
);
665 return (ISCCC_R_UNKNOWNVERSION
);
667 alist
= isccc_alist_create();
669 return (ISC_R_NOMEMORY
);
671 result
= ISC_R_NOMEMORY
;
673 _ctrl
= isccc_alist_create();
676 if (isccc_alist_define(alist
, "_ctrl", _ctrl
) == NULL
) {
677 isccc_sexpr_free(&_ctrl
);
681 _data
= isccc_alist_create();
684 if (isccc_alist_define(alist
, "_data", _data
) == NULL
) {
685 isccc_sexpr_free(&_data
);
689 if (isccc_cc_defineuint32(_ctrl
, "_ser", serial
) == NULL
||
690 isccc_cc_defineuint32(_ctrl
, "_tim", now
) == NULL
||
692 isccc_cc_defineuint32(_ctrl
, "_exp", expires
) == NULL
))
695 isccc_cc_definestring(_ctrl
, "_frm", from
) == NULL
)
698 isccc_cc_definestring(_ctrl
, "_to", to
) == NULL
)
703 return (ISC_R_SUCCESS
);
706 isccc_sexpr_free(&alist
);
712 isccc_cc_createmessage(isc_uint32_t version
, const char *from
, const char *to
,
713 isc_uint32_t serial
, isccc_time_t now
,
714 isccc_time_t expires
, isccc_sexpr_t
**alistp
)
716 return (createmessage(version
, from
, to
, serial
, now
, expires
,
721 isccc_cc_createack(isccc_sexpr_t
*message
, isc_boolean_t ok
,
722 isccc_sexpr_t
**ackp
)
726 isccc_sexpr_t
*ack
, *_ctrl
;
730 REQUIRE(ackp
!= NULL
&& *ackp
== NULL
);
732 _ctrl
= isccc_alist_lookup(message
, "_ctrl");
734 isccc_cc_lookupuint32(_ctrl
, "_ser", &serial
) != ISC_R_SUCCESS
||
735 isccc_cc_lookupuint32(_ctrl
, "_tim", &t
) != ISC_R_SUCCESS
)
736 return (ISC_R_FAILURE
);
738 * _frm and _to are optional.
741 (void)isccc_cc_lookupstring(_ctrl
, "_frm", &_frm
);
743 (void)isccc_cc_lookupstring(_ctrl
, "_to", &_to
);
748 result
= createmessage(1, _to
, _frm
, serial
, t
, 0, &ack
, ISC_FALSE
);
749 if (result
!= ISC_R_SUCCESS
)
752 _ctrl
= isccc_alist_lookup(ack
, "_ctrl");
754 result
= ISC_R_FAILURE
;
757 if (isccc_cc_definestring(ack
, "_ack", (ok
) ? "1" : "0") == NULL
) {
758 result
= ISC_R_NOMEMORY
;
764 return (ISC_R_SUCCESS
);
767 isccc_sexpr_free(&ack
);
773 isccc_cc_isack(isccc_sexpr_t
*message
)
775 isccc_sexpr_t
*_ctrl
;
777 _ctrl
= isccc_alist_lookup(message
, "_ctrl");
780 if (isccc_cc_lookupstring(_ctrl
, "_ack", NULL
) == ISC_R_SUCCESS
)
786 isccc_cc_isreply(isccc_sexpr_t
*message
)
788 isccc_sexpr_t
*_ctrl
;
790 _ctrl
= isccc_alist_lookup(message
, "_ctrl");
793 if (isccc_cc_lookupstring(_ctrl
, "_rpl", NULL
) == ISC_R_SUCCESS
)
799 isccc_cc_createresponse(isccc_sexpr_t
*message
, isccc_time_t now
,
800 isccc_time_t expires
, isccc_sexpr_t
**alistp
)
802 char *_frm
, *_to
, *type
= NULL
;
804 isccc_sexpr_t
*alist
, *_ctrl
, *_data
;
807 REQUIRE(alistp
!= NULL
&& *alistp
== NULL
);
809 _ctrl
= isccc_alist_lookup(message
, "_ctrl");
810 _data
= isccc_alist_lookup(message
, "_data");
811 if (_ctrl
== NULL
|| _data
== NULL
||
812 isccc_cc_lookupuint32(_ctrl
, "_ser", &serial
) != ISC_R_SUCCESS
||
813 isccc_cc_lookupstring(_data
, "type", &type
) != ISC_R_SUCCESS
)
814 return (ISC_R_FAILURE
);
816 * _frm and _to are optional.
819 (void)isccc_cc_lookupstring(_ctrl
, "_frm", &_frm
);
821 (void)isccc_cc_lookupstring(_ctrl
, "_to", &_to
);
823 * Create the response.
826 result
= isccc_cc_createmessage(1, _to
, _frm
, serial
, now
, expires
,
828 if (result
!= ISC_R_SUCCESS
)
831 _ctrl
= isccc_alist_lookup(alist
, "_ctrl");
833 result
= ISC_R_FAILURE
;
837 _data
= isccc_alist_lookup(alist
, "_data");
839 result
= ISC_R_FAILURE
;
843 if (isccc_cc_definestring(_ctrl
, "_rpl", "1") == NULL
||
844 isccc_cc_definestring(_data
, "type", type
) == NULL
)
846 result
= ISC_R_NOMEMORY
;
852 return (ISC_R_SUCCESS
);
855 isccc_sexpr_free(&alist
);
860 isccc_cc_definestring(isccc_sexpr_t
*alist
, const char *key
, const char *str
)
866 DE_CONST(str
, r
.rstart
);
867 r
.rend
= r
.rstart
+ len
;
869 return (isccc_alist_definebinary(alist
, key
, &r
));
873 isccc_cc_defineuint32(isccc_sexpr_t
*alist
, const char *key
, isc_uint32_t i
)
879 snprintf(b
, sizeof(b
), "%u", i
);
881 r
.rstart
= (unsigned char *)b
;
882 r
.rend
= (unsigned char *)b
+ len
;
884 return (isccc_alist_definebinary(alist
, key
, &r
));
888 isccc_cc_lookupstring(isccc_sexpr_t
*alist
, const char *key
, char **strp
)
890 isccc_sexpr_t
*kv
, *v
;
892 REQUIRE(strp
== NULL
|| *strp
== NULL
);
894 kv
= isccc_alist_assq(alist
, key
);
896 v
= ISCCC_SEXPR_CDR(kv
);
897 if (isccc_sexpr_binaryp(v
)) {
899 *strp
= isccc_sexpr_tostring(v
);
900 return (ISC_R_SUCCESS
);
902 return (ISC_R_EXISTS
);
905 return (ISC_R_NOTFOUND
);
909 isccc_cc_lookupuint32(isccc_sexpr_t
*alist
, const char *key
,
912 isccc_sexpr_t
*kv
, *v
;
914 kv
= isccc_alist_assq(alist
, key
);
916 v
= ISCCC_SEXPR_CDR(kv
);
917 if (isccc_sexpr_binaryp(v
)) {
919 *uintp
= (isc_uint32_t
)
920 strtoul(isccc_sexpr_tostring(v
),
922 return (ISC_R_SUCCESS
);
924 return (ISC_R_EXISTS
);
927 return (ISC_R_NOTFOUND
);
931 symtab_undefine(char *key
, unsigned int type
, isccc_symvalue_t value
,
942 symtab_clean(char *key
, unsigned int type
, isccc_symvalue_t value
,
952 if (*now
< value
.as_uinteger
)
954 if ((*now
- value
.as_uinteger
) < DUP_LIFETIME
)
960 isccc_cc_createsymtab(isccc_symtab_t
**symtabp
)
962 return (isccc_symtab_create(11897, symtab_undefine
, NULL
, ISC_FALSE
,
967 isccc_cc_cleansymtab(isccc_symtab_t
*symtab
, isccc_time_t now
)
969 isccc_symtab_foreach(symtab
, symtab_clean
, &now
);
973 has_whitespace(const char *str
)
979 while ((c
= *str
++) != '\0') {
980 if (c
== ' ' || c
== '\t' || c
== '\n')
987 isccc_cc_checkdup(isccc_symtab_t
*symtab
, isccc_sexpr_t
*message
,
992 char *_ser
= NULL
, *_tim
= NULL
, *tmp
;
996 isccc_symvalue_t value
;
997 isccc_sexpr_t
*_ctrl
;
999 _ctrl
= isccc_alist_lookup(message
, "_ctrl");
1000 if (_ctrl
== NULL
||
1001 isccc_cc_lookupstring(_ctrl
, "_ser", &_ser
) != ISC_R_SUCCESS
||
1002 isccc_cc_lookupstring(_ctrl
, "_tim", &_tim
) != ISC_R_SUCCESS
)
1003 return (ISC_R_FAILURE
);
1005 INSIST(_ser
!= NULL
);
1006 INSIST(_tim
!= NULL
);
1009 * _frm and _to are optional.
1012 if (isccc_cc_lookupstring(_ctrl
, "_frm", &tmp
) != ISC_R_SUCCESS
)
1017 if (isccc_cc_lookupstring(_ctrl
, "_to", &tmp
) != ISC_R_SUCCESS
)
1022 * Ensure there is no newline in any of the strings. This is so
1023 * we can write them to a file later.
1025 if (has_whitespace(_frm
) || has_whitespace(_to
) ||
1026 has_whitespace(_ser
) || has_whitespace(_tim
))
1027 return (ISC_R_FAILURE
);
1028 len
= strlen(_frm
) + strlen(_to
) + strlen(_ser
) + strlen(_tim
) + 4;
1031 return (ISC_R_NOMEMORY
);
1032 snprintf(key
, len
, "%s;%s;%s;%s", _frm
, _to
, _ser
, _tim
);
1033 value
.as_uinteger
= now
;
1034 result
= isccc_symtab_define(symtab
, key
, ISCCC_SYMTYPE_CCDUP
, value
,
1035 isccc_symexists_reject
);
1036 if (result
!= ISC_R_SUCCESS
) {
1041 return (ISC_R_SUCCESS
);