00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include <config.h>
00037
00038 #include <stdio.h>
00039 #include <string.h>
00040 #include <errno.h>
00041
00042 #include <isc/assertions.h>
00043 #include <isc/hmacmd5.h>
00044 #include <isc/hmacsha.h>
00045 #include <isc/print.h>
00046 #include <isc/safe.h>
00047 #include <isc/stdlib.h>
00048
00049 #include <isccc/alist.h>
00050 #include <isccc/base64.h>
00051 #include <isccc/cc.h>
00052 #include <isccc/result.h>
00053 #include <isccc/sexpr.h>
00054 #include <isccc/symtab.h>
00055 #include <isccc/symtype.h>
00056 #include <isccc/util.h>
00057
00058 #define MAX_TAGS 256
00059 #define DUP_LIFETIME 900
00060
00061 typedef isccc_sexpr_t *sexpr_ptr;
00062
00063 static unsigned char auth_hmd5[] = {
00064 0x05, 0x5f, 0x61, 0x75, 0x74, 0x68,
00065 ISCCC_CCMSGTYPE_TABLE,
00066 0x00, 0x00, 0x00, 0x20,
00067 0x04, 0x68, 0x6d, 0x64, 0x35,
00068 ISCCC_CCMSGTYPE_BINARYDATA,
00069 0x00, 0x00, 0x00, 0x16,
00070
00071
00072
00073
00074 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00075 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00076 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
00077 };
00078
00079 #define HMD5_OFFSET 21
00080 #define HMD5_LENGTH 22
00081
00082 static unsigned char auth_hsha[] = {
00083 0x05, 0x5f, 0x61, 0x75, 0x74, 0x68,
00084 ISCCC_CCMSGTYPE_TABLE,
00085 0x00, 0x00, 0x00, 0x63,
00086 0x04, 0x68, 0x73, 0x68, 0x61,
00087 ISCCC_CCMSGTYPE_BINARYDATA,
00088 0x00, 0x00, 0x00, 0x59,
00089 0x00,
00090
00091
00092
00093
00094 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00095 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00096 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00097 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00098 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00099 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00100 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00101 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00102 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00103 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00104 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
00105 };
00106
00107 #define HSHA_OFFSET 22
00108 #define HSHA_LENGTH 88
00109
00110 static isc_result_t
00111 table_towire(isccc_sexpr_t *alist, isc_buffer_t **buffer);
00112
00113 static isc_result_t
00114 list_towire(isccc_sexpr_t *alist, isc_buffer_t **buffer);
00115
00116 static isc_result_t
00117 value_towire(isccc_sexpr_t *elt, isc_buffer_t **buffer)
00118 {
00119 unsigned int len;
00120 isccc_region_t *vr;
00121 isc_result_t result;
00122
00123 if (isccc_sexpr_binaryp(elt)) {
00124 vr = isccc_sexpr_tobinary(elt);
00125 len = REGION_SIZE(*vr);
00126 result = isc_buffer_reserve(buffer, 1 + 4);
00127 if (result != ISC_R_SUCCESS)
00128 return (ISC_R_NOSPACE);
00129 isc_buffer_putuint8(*buffer, ISCCC_CCMSGTYPE_BINARYDATA);
00130 isc_buffer_putuint32(*buffer, len);
00131
00132 result = isc_buffer_reserve(buffer, len);
00133 if (result != ISC_R_SUCCESS)
00134 return (ISC_R_NOSPACE);
00135 isc_buffer_putmem(*buffer, vr->rstart, len);
00136 } else if (isccc_alist_alistp(elt)) {
00137 unsigned int used;
00138 isc_buffer_t b;
00139
00140 result = isc_buffer_reserve(buffer, 1 + 4);
00141 if (result != ISC_R_SUCCESS)
00142 return (ISC_R_NOSPACE);
00143 isc_buffer_putuint8(*buffer, ISCCC_CCMSGTYPE_TABLE);
00144
00145
00146
00147 used = (*buffer)->used;
00148 isc_buffer_putuint32(*buffer, 0);
00149
00150
00151
00152
00153 result = table_towire(elt, buffer);
00154 if (result != ISC_R_SUCCESS)
00155 return (result);
00156
00157 len = (*buffer)->used - used;
00158
00159
00160
00161
00162
00163 INSIST(len >= 4U);
00164 len -= 4;
00165
00166 isc_buffer_init(&b, (unsigned char *) (*buffer)->base + used, 4);
00167 isc_buffer_putuint32(&b, len);
00168 } else if (isccc_sexpr_listp(elt)) {
00169 unsigned int used;
00170 isc_buffer_t b;
00171
00172 result = isc_buffer_reserve(buffer, 1 + 4);
00173 if (result != ISC_R_SUCCESS)
00174 return (ISC_R_NOSPACE);
00175 isc_buffer_putuint8(*buffer, ISCCC_CCMSGTYPE_LIST);
00176
00177
00178
00179 used = (*buffer)->used;
00180 isc_buffer_putuint32(*buffer, 0);
00181
00182
00183
00184
00185 result = list_towire(elt, buffer);
00186 if (result != ISC_R_SUCCESS)
00187 return (result);
00188
00189 len = (*buffer)->used - used;
00190
00191
00192
00193
00194
00195 INSIST(len >= 4U);
00196 len -= 4;
00197
00198 isc_buffer_init(&b, (unsigned char *) (*buffer)->base + used, 4);
00199 isc_buffer_putuint32(&b, len);
00200 }
00201
00202 return (ISC_R_SUCCESS);
00203 }
00204
00205 static isc_result_t
00206 table_towire(isccc_sexpr_t *alist, isc_buffer_t **buffer) {
00207 isccc_sexpr_t *kv, *elt, *k, *v;
00208 char *ks;
00209 isc_result_t result;
00210 unsigned int len;
00211
00212 for (elt = isccc_alist_first(alist);
00213 elt != NULL;
00214 elt = ISCCC_SEXPR_CDR(elt)) {
00215 kv = ISCCC_SEXPR_CAR(elt);
00216 k = ISCCC_SEXPR_CAR(kv);
00217 ks = isccc_sexpr_tostring(k);
00218 v = ISCCC_SEXPR_CDR(kv);
00219 len = (unsigned int)strlen(ks);
00220 INSIST(len <= 255U);
00221
00222
00223
00224 result = isc_buffer_reserve(buffer, 1 + len);
00225 if (result != ISC_R_SUCCESS)
00226 return (ISC_R_NOSPACE);
00227 isc_buffer_putuint8(*buffer, (isc_uint8_t)len);
00228 isc_buffer_putmem(*buffer, (const unsigned char *) ks, len);
00229
00230
00231
00232 result = value_towire(v, buffer);
00233 if (result != ISC_R_SUCCESS)
00234 return (result);
00235 }
00236
00237 return (ISC_R_SUCCESS);
00238 }
00239
00240 static isc_result_t
00241 list_towire(isccc_sexpr_t *list, isc_buffer_t **buffer) {
00242 isc_result_t result;
00243
00244 while (list != NULL) {
00245 result = value_towire(ISCCC_SEXPR_CAR(list), buffer);
00246 if (result != ISC_R_SUCCESS)
00247 return (result);
00248 list = ISCCC_SEXPR_CDR(list);
00249 }
00250
00251 return (ISC_R_SUCCESS);
00252 }
00253
00254 static isc_result_t
00255 sign(unsigned char *data, unsigned int length, unsigned char *hmac,
00256 isc_uint32_t algorithm, isccc_region_t *secret)
00257 {
00258 union {
00259 isc_hmacmd5_t hmd5;
00260 isc_hmacsha1_t hsha;
00261 isc_hmacsha224_t h224;
00262 isc_hmacsha256_t h256;
00263 isc_hmacsha384_t h384;
00264 isc_hmacsha512_t h512;
00265 } ctx;
00266 isc_result_t result;
00267 isccc_region_t source, target;
00268 unsigned char digest[ISC_SHA512_DIGESTLENGTH];
00269 unsigned char digestb64[HSHA_LENGTH + 4];
00270
00271 source.rstart = digest;
00272
00273 switch (algorithm) {
00274 case ISCCC_ALG_HMACMD5:
00275 isc_hmacmd5_init(&ctx.hmd5, secret->rstart,
00276 REGION_SIZE(*secret));
00277 isc_hmacmd5_update(&ctx.hmd5, data, length);
00278 isc_hmacmd5_sign(&ctx.hmd5, digest);
00279 source.rend = digest + ISC_MD5_DIGESTLENGTH;
00280 break;
00281
00282 case ISCCC_ALG_HMACSHA1:
00283 isc_hmacsha1_init(&ctx.hsha, secret->rstart,
00284 REGION_SIZE(*secret));
00285 isc_hmacsha1_update(&ctx.hsha, data, length);
00286 isc_hmacsha1_sign(&ctx.hsha, digest,
00287 ISC_SHA1_DIGESTLENGTH);
00288 source.rend = digest + ISC_SHA1_DIGESTLENGTH;
00289 break;
00290
00291 case ISCCC_ALG_HMACSHA224:
00292 isc_hmacsha224_init(&ctx.h224, secret->rstart,
00293 REGION_SIZE(*secret));
00294 isc_hmacsha224_update(&ctx.h224, data, length);
00295 isc_hmacsha224_sign(&ctx.h224, digest,
00296 ISC_SHA224_DIGESTLENGTH);
00297 source.rend = digest + ISC_SHA224_DIGESTLENGTH;
00298 break;
00299
00300 case ISCCC_ALG_HMACSHA256:
00301 isc_hmacsha256_init(&ctx.h256, secret->rstart,
00302 REGION_SIZE(*secret));
00303 isc_hmacsha256_update(&ctx.h256, data, length);
00304 isc_hmacsha256_sign(&ctx.h256, digest,
00305 ISC_SHA256_DIGESTLENGTH);
00306 source.rend = digest + ISC_SHA256_DIGESTLENGTH;
00307 break;
00308
00309 case ISCCC_ALG_HMACSHA384:
00310 isc_hmacsha384_init(&ctx.h384, secret->rstart,
00311 REGION_SIZE(*secret));
00312 isc_hmacsha384_update(&ctx.h384, data, length);
00313 isc_hmacsha384_sign(&ctx.h384, digest,
00314 ISC_SHA384_DIGESTLENGTH);
00315 source.rend = digest + ISC_SHA384_DIGESTLENGTH;
00316 break;
00317
00318 case ISCCC_ALG_HMACSHA512:
00319 isc_hmacsha512_init(&ctx.h512, secret->rstart,
00320 REGION_SIZE(*secret));
00321 isc_hmacsha512_update(&ctx.h512, data, length);
00322 isc_hmacsha512_sign(&ctx.h512, digest,
00323 ISC_SHA512_DIGESTLENGTH);
00324 source.rend = digest + ISC_SHA512_DIGESTLENGTH;
00325 break;
00326
00327 default:
00328 return (ISC_R_FAILURE);
00329 }
00330
00331 memset(digestb64, 0, sizeof(digestb64));
00332 target.rstart = digestb64;
00333 target.rend = digestb64 + sizeof(digestb64);
00334 result = isccc_base64_encode(&source, 64, "", &target);
00335 if (result != ISC_R_SUCCESS)
00336 return (result);
00337 if (algorithm == ISCCC_ALG_HMACMD5)
00338 PUT_MEM(digestb64, HMD5_LENGTH, hmac);
00339 else
00340 PUT_MEM(digestb64, HSHA_LENGTH, hmac);
00341 return (ISC_R_SUCCESS);
00342 }
00343
00344 isc_result_t
00345 isccc_cc_towire(isccc_sexpr_t *alist, isc_buffer_t **buffer,
00346 isc_uint32_t algorithm, isccc_region_t *secret)
00347 {
00348 unsigned int hmac_size, signed_size;
00349 isc_result_t result;
00350
00351 result = isc_buffer_reserve(buffer,
00352 4 + ((algorithm == ISCCC_ALG_HMACMD5) ?
00353 sizeof(auth_hmd5) :
00354 sizeof(auth_hsha)));
00355 if (result != ISC_R_SUCCESS)
00356 return (ISC_R_NOSPACE);
00357
00358
00359
00360
00361 isc_buffer_putuint32(*buffer, 1);
00362
00363 if (secret != NULL) {
00364
00365
00366
00367
00368
00369 if (algorithm == ISCCC_ALG_HMACMD5) {
00370 hmac_size = (*buffer)->used + HMD5_OFFSET;
00371 isc_buffer_putmem(*buffer,
00372 auth_hmd5, sizeof(auth_hmd5));
00373 } else {
00374 unsigned char *hmac_alg;
00375
00376 hmac_size = (*buffer)->used + HSHA_OFFSET;
00377 hmac_alg = (unsigned char *) isc_buffer_used(*buffer) + HSHA_OFFSET - 1;
00378 isc_buffer_putmem(*buffer,
00379 auth_hsha, sizeof(auth_hsha));
00380 *hmac_alg = algorithm;
00381 }
00382 } else
00383 hmac_size = 0;
00384 signed_size = (*buffer)->used;
00385
00386
00387
00388
00389 isccc_alist_delete(alist, "_auth");
00390
00391
00392
00393 result = table_towire(alist, buffer);
00394 if (result != ISC_R_SUCCESS)
00395 return (result);
00396 if (secret != NULL)
00397 return (sign((unsigned char *) (*buffer)->base + signed_size,
00398 (*buffer)->used - signed_size,
00399 (hmac_size == 0 ? NULL :
00400 (unsigned char *) (*buffer)->base + hmac_size),
00401 algorithm, secret));
00402 return (ISC_R_SUCCESS);
00403 }
00404
00405 static isc_result_t
00406 verify(isccc_sexpr_t *alist, unsigned char *data, unsigned int length,
00407 isc_uint32_t algorithm, isccc_region_t *secret)
00408 {
00409 union {
00410 isc_hmacmd5_t hmd5;
00411 isc_hmacsha1_t hsha;
00412 isc_hmacsha224_t h224;
00413 isc_hmacsha256_t h256;
00414 isc_hmacsha384_t h384;
00415 isc_hmacsha512_t h512;
00416 } ctx;
00417 isccc_region_t source;
00418 isccc_region_t target;
00419 isc_result_t result;
00420 isccc_sexpr_t *_auth, *hmac;
00421 unsigned char digest[ISC_SHA512_DIGESTLENGTH];
00422 unsigned char digestb64[HSHA_LENGTH * 4];
00423
00424
00425
00426
00427 _auth = isccc_alist_lookup(alist, "_auth");
00428 if (_auth == NULL)
00429 return (ISC_R_FAILURE);
00430 if (algorithm == ISCCC_ALG_HMACMD5)
00431 hmac = isccc_alist_lookup(_auth, "hmd5");
00432 else
00433 hmac = isccc_alist_lookup(_auth, "hsha");
00434 if (hmac == NULL)
00435 return (ISC_R_FAILURE);
00436
00437
00438
00439 source.rstart = digest;
00440 target.rstart = digestb64;
00441 switch (algorithm) {
00442 case ISCCC_ALG_HMACMD5:
00443 isc_hmacmd5_init(&ctx.hmd5, secret->rstart,
00444 REGION_SIZE(*secret));
00445 isc_hmacmd5_update(&ctx.hmd5, data, length);
00446 isc_hmacmd5_sign(&ctx.hmd5, digest);
00447 source.rend = digest + ISC_MD5_DIGESTLENGTH;
00448 break;
00449
00450 case ISCCC_ALG_HMACSHA1:
00451 isc_hmacsha1_init(&ctx.hsha, secret->rstart,
00452 REGION_SIZE(*secret));
00453 isc_hmacsha1_update(&ctx.hsha, data, length);
00454 isc_hmacsha1_sign(&ctx.hsha, digest,
00455 ISC_SHA1_DIGESTLENGTH);
00456 source.rend = digest + ISC_SHA1_DIGESTLENGTH;
00457 break;
00458
00459 case ISCCC_ALG_HMACSHA224:
00460 isc_hmacsha224_init(&ctx.h224, secret->rstart,
00461 REGION_SIZE(*secret));
00462 isc_hmacsha224_update(&ctx.h224, data, length);
00463 isc_hmacsha224_sign(&ctx.h224, digest,
00464 ISC_SHA224_DIGESTLENGTH);
00465 source.rend = digest + ISC_SHA224_DIGESTLENGTH;
00466 break;
00467
00468 case ISCCC_ALG_HMACSHA256:
00469 isc_hmacsha256_init(&ctx.h256, secret->rstart,
00470 REGION_SIZE(*secret));
00471 isc_hmacsha256_update(&ctx.h256, data, length);
00472 isc_hmacsha256_sign(&ctx.h256, digest,
00473 ISC_SHA256_DIGESTLENGTH);
00474 source.rend = digest + ISC_SHA256_DIGESTLENGTH;
00475 break;
00476
00477 case ISCCC_ALG_HMACSHA384:
00478 isc_hmacsha384_init(&ctx.h384, secret->rstart,
00479 REGION_SIZE(*secret));
00480 isc_hmacsha384_update(&ctx.h384, data, length);
00481 isc_hmacsha384_sign(&ctx.h384, digest,
00482 ISC_SHA384_DIGESTLENGTH);
00483 source.rend = digest + ISC_SHA384_DIGESTLENGTH;
00484 break;
00485
00486 case ISCCC_ALG_HMACSHA512:
00487 isc_hmacsha512_init(&ctx.h512, secret->rstart,
00488 REGION_SIZE(*secret));
00489 isc_hmacsha512_update(&ctx.h512, data, length);
00490 isc_hmacsha512_sign(&ctx.h512, digest,
00491 ISC_SHA512_DIGESTLENGTH);
00492 source.rend = digest + ISC_SHA512_DIGESTLENGTH;
00493 break;
00494
00495 default:
00496 return (ISC_R_FAILURE);
00497 }
00498 target.rstart = digestb64;
00499 target.rend = digestb64 + sizeof(digestb64);
00500 memset(digestb64, 0, sizeof(digestb64));
00501 result = isccc_base64_encode(&source, 64, "", &target);
00502 if (result != ISC_R_SUCCESS)
00503 return (result);
00504
00505
00506
00507
00508 if (algorithm == ISCCC_ALG_HMACMD5) {
00509 unsigned char *value;
00510
00511 value = (unsigned char *) isccc_sexpr_tostring(hmac);
00512 if (!isc_safe_memcmp(value, digestb64, HMD5_LENGTH))
00513 return (ISCCC_R_BADAUTH);
00514 } else {
00515 unsigned char *value;
00516 isc_uint32_t valalg;
00517
00518 value = (unsigned char *) isccc_sexpr_tostring(hmac);
00519 GET8(valalg, value);
00520 if ((valalg != algorithm) ||
00521 (!isc_safe_memcmp(value, digestb64, HSHA_LENGTH)))
00522 return (ISCCC_R_BADAUTH);
00523 }
00524
00525 return (ISC_R_SUCCESS);
00526 }
00527
00528 static isc_result_t
00529 table_fromwire(isccc_region_t *source, isccc_region_t *secret,
00530 isc_uint32_t algorithm, isccc_sexpr_t **alistp);
00531
00532 static isc_result_t
00533 list_fromwire(isccc_region_t *source, isccc_sexpr_t **listp);
00534
00535 static isc_result_t
00536 value_fromwire(isccc_region_t *source, isccc_sexpr_t **valuep)
00537 {
00538 unsigned int msgtype;
00539 isc_uint32_t len;
00540 isccc_sexpr_t *value;
00541 isccc_region_t active;
00542 isc_result_t result;
00543
00544 if (REGION_SIZE(*source) < 1 + 4)
00545 return (ISC_R_UNEXPECTEDEND);
00546 GET8(msgtype, source->rstart);
00547 GET32(len, source->rstart);
00548 if (REGION_SIZE(*source) < len)
00549 return (ISC_R_UNEXPECTEDEND);
00550 active.rstart = source->rstart;
00551 active.rend = active.rstart + len;
00552 source->rstart = active.rend;
00553 if (msgtype == ISCCC_CCMSGTYPE_BINARYDATA) {
00554 value = isccc_sexpr_frombinary(&active);
00555 if (value != NULL) {
00556 *valuep = value;
00557 result = ISC_R_SUCCESS;
00558 } else
00559 result = ISC_R_NOMEMORY;
00560 } else if (msgtype == ISCCC_CCMSGTYPE_TABLE)
00561 result = table_fromwire(&active, NULL, 0, valuep);
00562 else if (msgtype == ISCCC_CCMSGTYPE_LIST)
00563 result = list_fromwire(&active, valuep);
00564 else
00565 result = ISCCC_R_SYNTAX;
00566
00567 return (result);
00568 }
00569
00570 static isc_result_t
00571 table_fromwire(isccc_region_t *source, isccc_region_t *secret,
00572 isc_uint32_t algorithm, isccc_sexpr_t **alistp)
00573 {
00574 char key[256];
00575 isc_uint32_t len;
00576 isc_result_t result;
00577 isccc_sexpr_t *alist, *value;
00578 isc_boolean_t first_tag;
00579 unsigned char *checksum_rstart;
00580
00581 REQUIRE(alistp != NULL && *alistp == NULL);
00582
00583 checksum_rstart = NULL;
00584 first_tag = ISC_TRUE;
00585 alist = isccc_alist_create();
00586 if (alist == NULL)
00587 return (ISC_R_NOMEMORY);
00588
00589 while (!REGION_EMPTY(*source)) {
00590 GET8(len, source->rstart);
00591 if (REGION_SIZE(*source) < len) {
00592 result = ISC_R_UNEXPECTEDEND;
00593 goto bad;
00594 }
00595 GET_MEM(key, len, source->rstart);
00596 key[len] = '\0';
00597 value = NULL;
00598 result = value_fromwire(source, &value);
00599 if (result != ISC_R_SUCCESS)
00600 goto bad;
00601 if (isccc_alist_define(alist, key, value) == NULL) {
00602 result = ISC_R_NOMEMORY;
00603 goto bad;
00604 }
00605 if (first_tag && secret != NULL && strcmp(key, "_auth") == 0)
00606 checksum_rstart = source->rstart;
00607 first_tag = ISC_FALSE;
00608 }
00609
00610 if (secret != NULL) {
00611 if (checksum_rstart != NULL)
00612 result = verify(alist, checksum_rstart,
00613 (unsigned int)
00614 (source->rend - checksum_rstart),
00615 algorithm, secret);
00616 else
00617 result = ISCCC_R_BADAUTH;
00618 } else
00619 result = ISC_R_SUCCESS;
00620
00621 bad:
00622 if (result == ISC_R_SUCCESS)
00623 *alistp = alist;
00624 else
00625 isccc_sexpr_free(&alist);
00626
00627 return (result);
00628 }
00629
00630 static isc_result_t
00631 list_fromwire(isccc_region_t *source, isccc_sexpr_t **listp)
00632 {
00633 isccc_sexpr_t *list, *value;
00634 isc_result_t result;
00635
00636 list = NULL;
00637 while (!REGION_EMPTY(*source)) {
00638 value = NULL;
00639 result = value_fromwire(source, &value);
00640 if (result != ISC_R_SUCCESS) {
00641 isccc_sexpr_free(&list);
00642 return (result);
00643 }
00644 if (isccc_sexpr_addtolist(&list, value) == NULL) {
00645 isccc_sexpr_free(&value);
00646 isccc_sexpr_free(&list);
00647 return (result);
00648 }
00649 }
00650
00651 *listp = list;
00652
00653 return (ISC_R_SUCCESS);
00654 }
00655
00656 isc_result_t
00657 isccc_cc_fromwire(isccc_region_t *source, isccc_sexpr_t **alistp,
00658 isc_uint32_t algorithm, isccc_region_t *secret)
00659 {
00660 unsigned int size;
00661 isc_uint32_t version;
00662
00663 size = REGION_SIZE(*source);
00664 if (size < 4)
00665 return (ISC_R_UNEXPECTEDEND);
00666 GET32(version, source->rstart);
00667 if (version != 1)
00668 return (ISCCC_R_UNKNOWNVERSION);
00669
00670 return (table_fromwire(source, secret, algorithm, alistp));
00671 }
00672
00673 static isc_result_t
00674 createmessage(isc_uint32_t version, const char *from, const char *to,
00675 isc_uint32_t serial, isccc_time_t now,
00676 isccc_time_t expires, isccc_sexpr_t **alistp,
00677 isc_boolean_t want_expires)
00678 {
00679 isccc_sexpr_t *alist, *_ctrl, *_data;
00680 isc_result_t result;
00681
00682 REQUIRE(alistp != NULL && *alistp == NULL);
00683
00684 if (version != 1)
00685 return (ISCCC_R_UNKNOWNVERSION);
00686
00687 alist = isccc_alist_create();
00688 if (alist == NULL)
00689 return (ISC_R_NOMEMORY);
00690
00691 result = ISC_R_NOMEMORY;
00692
00693 _ctrl = isccc_alist_create();
00694 if (_ctrl == NULL)
00695 goto bad;
00696 if (isccc_alist_define(alist, "_ctrl", _ctrl) == NULL) {
00697 isccc_sexpr_free(&_ctrl);
00698 goto bad;
00699 }
00700
00701 _data = isccc_alist_create();
00702 if (_data == NULL)
00703 goto bad;
00704 if (isccc_alist_define(alist, "_data", _data) == NULL) {
00705 isccc_sexpr_free(&_data);
00706 goto bad;
00707 }
00708
00709 if (isccc_cc_defineuint32(_ctrl, "_ser", serial) == NULL ||
00710 isccc_cc_defineuint32(_ctrl, "_tim", now) == NULL ||
00711 (want_expires &&
00712 isccc_cc_defineuint32(_ctrl, "_exp", expires) == NULL))
00713 goto bad;
00714 if (from != NULL &&
00715 isccc_cc_definestring(_ctrl, "_frm", from) == NULL)
00716 goto bad;
00717 if (to != NULL &&
00718 isccc_cc_definestring(_ctrl, "_to", to) == NULL)
00719 goto bad;
00720
00721 *alistp = alist;
00722
00723 return (ISC_R_SUCCESS);
00724
00725 bad:
00726 isccc_sexpr_free(&alist);
00727
00728 return (result);
00729 }
00730
00731 isc_result_t
00732 isccc_cc_createmessage(isc_uint32_t version, const char *from, const char *to,
00733 isc_uint32_t serial, isccc_time_t now,
00734 isccc_time_t expires, isccc_sexpr_t **alistp)
00735 {
00736 return (createmessage(version, from, to, serial, now, expires,
00737 alistp, ISC_TRUE));
00738 }
00739
00740 isc_result_t
00741 isccc_cc_createack(isccc_sexpr_t *message, isc_boolean_t ok,
00742 isccc_sexpr_t **ackp)
00743 {
00744 char *_frm, *_to;
00745 isc_uint32_t serial;
00746 isccc_sexpr_t *ack, *_ctrl;
00747 isc_result_t result;
00748 isccc_time_t t;
00749
00750 REQUIRE(ackp != NULL && *ackp == NULL);
00751
00752 _ctrl = isccc_alist_lookup(message, "_ctrl");
00753 if (_ctrl == NULL ||
00754 isccc_cc_lookupuint32(_ctrl, "_ser", &serial) != ISC_R_SUCCESS ||
00755 isccc_cc_lookupuint32(_ctrl, "_tim", &t) != ISC_R_SUCCESS)
00756 return (ISC_R_FAILURE);
00757
00758
00759
00760 _frm = NULL;
00761 (void)isccc_cc_lookupstring(_ctrl, "_frm", &_frm);
00762 _to = NULL;
00763 (void)isccc_cc_lookupstring(_ctrl, "_to", &_to);
00764
00765
00766
00767 ack = NULL;
00768 result = createmessage(1, _to, _frm, serial, t, 0, &ack, ISC_FALSE);
00769 if (result != ISC_R_SUCCESS)
00770 return (result);
00771
00772 _ctrl = isccc_alist_lookup(ack, "_ctrl");
00773 if (_ctrl == NULL) {
00774 result = ISC_R_FAILURE;
00775 goto bad;
00776 }
00777 if (isccc_cc_definestring(ack, "_ack", (ok) ? "1" : "0") == NULL) {
00778 result = ISC_R_NOMEMORY;
00779 goto bad;
00780 }
00781
00782 *ackp = ack;
00783
00784 return (ISC_R_SUCCESS);
00785
00786 bad:
00787 isccc_sexpr_free(&ack);
00788
00789 return (result);
00790 }
00791
00792 isc_boolean_t
00793 isccc_cc_isack(isccc_sexpr_t *message)
00794 {
00795 isccc_sexpr_t *_ctrl;
00796
00797 _ctrl = isccc_alist_lookup(message, "_ctrl");
00798 if (_ctrl == NULL)
00799 return (ISC_FALSE);
00800 if (isccc_cc_lookupstring(_ctrl, "_ack", NULL) == ISC_R_SUCCESS)
00801 return (ISC_TRUE);
00802 return (ISC_FALSE);
00803 }
00804
00805 isc_boolean_t
00806 isccc_cc_isreply(isccc_sexpr_t *message)
00807 {
00808 isccc_sexpr_t *_ctrl;
00809
00810 _ctrl = isccc_alist_lookup(message, "_ctrl");
00811 if (_ctrl == NULL)
00812 return (ISC_FALSE);
00813 if (isccc_cc_lookupstring(_ctrl, "_rpl", NULL) == ISC_R_SUCCESS)
00814 return (ISC_TRUE);
00815 return (ISC_FALSE);
00816 }
00817
00818 isc_result_t
00819 isccc_cc_createresponse(isccc_sexpr_t *message, isccc_time_t now,
00820 isccc_time_t expires, isccc_sexpr_t **alistp)
00821 {
00822 char *_frm, *_to, *type = NULL;
00823 isc_uint32_t serial;
00824 isccc_sexpr_t *alist, *_ctrl, *_data;
00825 isc_result_t result;
00826
00827 REQUIRE(alistp != NULL && *alistp == NULL);
00828
00829 _ctrl = isccc_alist_lookup(message, "_ctrl");
00830 _data = isccc_alist_lookup(message, "_data");
00831 if (_ctrl == NULL || _data == NULL ||
00832 isccc_cc_lookupuint32(_ctrl, "_ser", &serial) != ISC_R_SUCCESS ||
00833 isccc_cc_lookupstring(_data, "type", &type) != ISC_R_SUCCESS)
00834 return (ISC_R_FAILURE);
00835
00836
00837
00838 _frm = NULL;
00839 (void)isccc_cc_lookupstring(_ctrl, "_frm", &_frm);
00840 _to = NULL;
00841 (void)isccc_cc_lookupstring(_ctrl, "_to", &_to);
00842
00843
00844
00845 alist = NULL;
00846 result = isccc_cc_createmessage(1, _to, _frm, serial, now, expires,
00847 &alist);
00848 if (result != ISC_R_SUCCESS)
00849 return (result);
00850
00851 _ctrl = isccc_alist_lookup(alist, "_ctrl");
00852 if (_ctrl == NULL) {
00853 result = ISC_R_FAILURE;
00854 goto bad;
00855 }
00856
00857 _data = isccc_alist_lookup(alist, "_data");
00858 if (_data == NULL) {
00859 result = ISC_R_FAILURE;
00860 goto bad;
00861 }
00862
00863 if (isccc_cc_definestring(_ctrl, "_rpl", "1") == NULL ||
00864 isccc_cc_definestring(_data, "type", type) == NULL)
00865 {
00866 result = ISC_R_NOMEMORY;
00867 goto bad;
00868 }
00869
00870 *alistp = alist;
00871
00872 return (ISC_R_SUCCESS);
00873
00874 bad:
00875 isccc_sexpr_free(&alist);
00876 return (result);
00877 }
00878
00879 isccc_sexpr_t *
00880 isccc_cc_definestring(isccc_sexpr_t *alist, const char *key, const char *str)
00881 {
00882 size_t len;
00883 isccc_region_t r;
00884
00885 len = strlen(str);
00886 DE_CONST(str, r.rstart);
00887 r.rend = r.rstart + len;
00888
00889 return (isccc_alist_definebinary(alist, key, &r));
00890 }
00891
00892 isccc_sexpr_t *
00893 isccc_cc_defineuint32(isccc_sexpr_t *alist, const char *key, isc_uint32_t i)
00894 {
00895 char b[100];
00896 size_t len;
00897 isccc_region_t r;
00898
00899 snprintf(b, sizeof(b), "%u", i);
00900 len = strlen(b);
00901 r.rstart = (unsigned char *)b;
00902 r.rend = (unsigned char *)b + len;
00903
00904 return (isccc_alist_definebinary(alist, key, &r));
00905 }
00906
00907 isc_result_t
00908 isccc_cc_lookupstring(isccc_sexpr_t *alist, const char *key, char **strp)
00909 {
00910 isccc_sexpr_t *kv, *v;
00911
00912 REQUIRE(strp == NULL || *strp == NULL);
00913
00914 kv = isccc_alist_assq(alist, key);
00915 if (kv != NULL) {
00916 v = ISCCC_SEXPR_CDR(kv);
00917 if (isccc_sexpr_binaryp(v)) {
00918 if (strp != NULL)
00919 *strp = isccc_sexpr_tostring(v);
00920 return (ISC_R_SUCCESS);
00921 } else
00922 return (ISC_R_EXISTS);
00923 }
00924
00925 return (ISC_R_NOTFOUND);
00926 }
00927
00928 isc_result_t
00929 isccc_cc_lookupuint32(isccc_sexpr_t *alist, const char *key,
00930 isc_uint32_t *uintp)
00931 {
00932 isccc_sexpr_t *kv, *v;
00933
00934 kv = isccc_alist_assq(alist, key);
00935 if (kv != NULL) {
00936 v = ISCCC_SEXPR_CDR(kv);
00937 if (isccc_sexpr_binaryp(v)) {
00938 if (uintp != NULL)
00939 *uintp = (isc_uint32_t)
00940 strtoul(isccc_sexpr_tostring(v),
00941 NULL, 10);
00942 return (ISC_R_SUCCESS);
00943 } else
00944 return (ISC_R_EXISTS);
00945 }
00946
00947 return (ISC_R_NOTFOUND);
00948 }
00949
00950 static void
00951 symtab_undefine(char *key, unsigned int type, isccc_symvalue_t value,
00952 void *arg)
00953 {
00954 UNUSED(type);
00955 UNUSED(value);
00956 UNUSED(arg);
00957
00958 free(key);
00959 }
00960
00961 static isc_boolean_t
00962 symtab_clean(char *key, unsigned int type, isccc_symvalue_t value,
00963 void *arg)
00964 {
00965 isccc_time_t *now;
00966
00967 UNUSED(key);
00968 UNUSED(type);
00969
00970 now = arg;
00971
00972 if (*now < value.as_uinteger)
00973 return (ISC_FALSE);
00974 if ((*now - value.as_uinteger) < DUP_LIFETIME)
00975 return (ISC_FALSE);
00976 return (ISC_TRUE);
00977 }
00978
00979 isc_result_t
00980 isccc_cc_createsymtab(isccc_symtab_t **symtabp)
00981 {
00982 return (isccc_symtab_create(11897, symtab_undefine, NULL, ISC_FALSE,
00983 symtabp));
00984 }
00985
00986 void
00987 isccc_cc_cleansymtab(isccc_symtab_t *symtab, isccc_time_t now)
00988 {
00989 isccc_symtab_foreach(symtab, symtab_clean, &now);
00990 }
00991
00992 static isc_boolean_t
00993 has_whitespace(const char *str)
00994 {
00995 char c;
00996
00997 if (str == NULL)
00998 return (ISC_FALSE);
00999 while ((c = *str++) != '\0') {
01000 if (c == ' ' || c == '\t' || c == '\n')
01001 return (ISC_TRUE);
01002 }
01003 return (ISC_FALSE);
01004 }
01005
01006 isc_result_t
01007 isccc_cc_checkdup(isccc_symtab_t *symtab, isccc_sexpr_t *message,
01008 isccc_time_t now)
01009 {
01010 const char *_frm;
01011 const char *_to;
01012 char *_ser = NULL, *_tim = NULL, *tmp;
01013 isc_result_t result;
01014 char *key;
01015 size_t len;
01016 isccc_symvalue_t value;
01017 isccc_sexpr_t *_ctrl;
01018
01019 _ctrl = isccc_alist_lookup(message, "_ctrl");
01020 if (_ctrl == NULL ||
01021 isccc_cc_lookupstring(_ctrl, "_ser", &_ser) != ISC_R_SUCCESS ||
01022 isccc_cc_lookupstring(_ctrl, "_tim", &_tim) != ISC_R_SUCCESS)
01023 return (ISC_R_FAILURE);
01024
01025 INSIST(_ser != NULL);
01026 INSIST(_tim != NULL);
01027
01028
01029
01030
01031 tmp = NULL;
01032 if (isccc_cc_lookupstring(_ctrl, "_frm", &tmp) != ISC_R_SUCCESS)
01033 _frm = "";
01034 else
01035 _frm = tmp;
01036 tmp = NULL;
01037 if (isccc_cc_lookupstring(_ctrl, "_to", &tmp) != ISC_R_SUCCESS)
01038 _to = "";
01039 else
01040 _to = tmp;
01041
01042
01043
01044
01045 if (has_whitespace(_frm) || has_whitespace(_to) ||
01046 has_whitespace(_ser) || has_whitespace(_tim))
01047 return (ISC_R_FAILURE);
01048 len = strlen(_frm) + strlen(_to) + strlen(_ser) + strlen(_tim) + 4;
01049 key = malloc(len);
01050 if (key == NULL)
01051 return (ISC_R_NOMEMORY);
01052 snprintf(key, len, "%s;%s;%s;%s", _frm, _to, _ser, _tim);
01053 value.as_uinteger = now;
01054 result = isccc_symtab_define(symtab, key, ISCCC_SYMTYPE_CCDUP, value,
01055 isccc_symexists_reject);
01056 if (result != ISC_R_SUCCESS) {
01057 free(key);
01058 return (result);
01059 }
01060
01061 return (ISC_R_SUCCESS);
01062 }