cc.c revision 1.3 1 1.2 christos /* $NetBSD: cc.c,v 1.3 2019/01/09 16:55:18 christos Exp $ */
2 1.1 christos
3 1.1 christos /*
4 1.1 christos * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 1.1 christos *
6 1.1 christos * This Source Code Form is subject to the terms of the Mozilla Public
7 1.1 christos * License, v. 2.0. If a copy of the MPL was not distributed with this
8 1.1 christos * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 1.1 christos *
10 1.1 christos * See the COPYRIGHT file distributed with this work for additional
11 1.1 christos * information regarding copyright ownership.
12 1.1 christos *
13 1.1 christos * Portions Copyright (C) 2001 Nominum, Inc.
14 1.1 christos *
15 1.1 christos * Permission to use, copy, modify, and/or distribute this software for any
16 1.1 christos * purpose with or without fee is hereby granted, provided that the above
17 1.1 christos * copyright notice and this permission notice appear in all copies.
18 1.1 christos *
19 1.1 christos * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
20 1.1 christos * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
21 1.1 christos * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
22 1.1 christos * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
23 1.1 christos * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
24 1.1 christos * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
25 1.1 christos * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
26 1.1 christos */
27 1.1 christos
28 1.1 christos /*! \file */
29 1.1 christos
30 1.1 christos #include <config.h>
31 1.1 christos
32 1.3 christos #include <stdbool.h>
33 1.1 christos #include <stdio.h>
34 1.3 christos #include <inttypes.h>
35 1.1 christos #include <string.h>
36 1.1 christos #include <errno.h>
37 1.1 christos
38 1.1 christos #include <isc/assertions.h>
39 1.3 christos #include <isc/hmac.h>
40 1.1 christos #include <isc/print.h>
41 1.1 christos #include <isc/safe.h>
42 1.1 christos
43 1.1 christos #include <pk11/site.h>
44 1.1 christos
45 1.1 christos #include <isccc/alist.h>
46 1.1 christos #include <isccc/base64.h>
47 1.1 christos #include <isccc/cc.h>
48 1.1 christos #include <isccc/result.h>
49 1.1 christos #include <isccc/sexpr.h>
50 1.1 christos #include <isccc/symtab.h>
51 1.1 christos #include <isccc/symtype.h>
52 1.1 christos #include <isccc/util.h>
53 1.1 christos
54 1.1 christos #define MAX_TAGS 256
55 1.1 christos #define DUP_LIFETIME 900
56 1.1 christos
57 1.1 christos typedef isccc_sexpr_t *sexpr_ptr;
58 1.1 christos
59 1.1 christos static unsigned char auth_hmd5[] = {
60 1.1 christos 0x05, 0x5f, 0x61, 0x75, 0x74, 0x68, /*%< len + _auth */
61 1.1 christos ISCCC_CCMSGTYPE_TABLE, /*%< message type */
62 1.1 christos 0x00, 0x00, 0x00, 0x20, /*%< length == 32 */
63 1.1 christos 0x04, 0x68, 0x6d, 0x64, 0x35, /*%< len + hmd5 */
64 1.1 christos ISCCC_CCMSGTYPE_BINARYDATA, /*%< message type */
65 1.1 christos 0x00, 0x00, 0x00, 0x16, /*%< length == 22 */
66 1.1 christos /*
67 1.1 christos * The base64 encoding of one of our HMAC-MD5 signatures is
68 1.1 christos * 22 bytes.
69 1.1 christos */
70 1.1 christos 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
71 1.1 christos 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
72 1.1 christos 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
73 1.1 christos };
74 1.1 christos
75 1.1 christos #define HMD5_OFFSET 21 /*%< 21 = 6 + 1 + 4 + 5 + 1 + 4 */
76 1.1 christos #define HMD5_LENGTH 22
77 1.1 christos
78 1.1 christos static unsigned char auth_hsha[] = {
79 1.1 christos 0x05, 0x5f, 0x61, 0x75, 0x74, 0x68, /*%< len + _auth */
80 1.1 christos ISCCC_CCMSGTYPE_TABLE, /*%< message type */
81 1.1 christos 0x00, 0x00, 0x00, 0x63, /*%< length == 99 */
82 1.1 christos 0x04, 0x68, 0x73, 0x68, 0x61, /*%< len + hsha */
83 1.1 christos ISCCC_CCMSGTYPE_BINARYDATA, /*%< message type */
84 1.1 christos 0x00, 0x00, 0x00, 0x59, /*%< length == 89 */
85 1.1 christos 0x00, /*%< algorithm */
86 1.1 christos /*
87 1.1 christos * The base64 encoding of one of our HMAC-SHA* signatures is
88 1.1 christos * 88 bytes.
89 1.1 christos */
90 1.1 christos 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
91 1.1 christos 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
92 1.1 christos 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
93 1.1 christos 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
94 1.1 christos 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
95 1.1 christos 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
96 1.1 christos 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
97 1.1 christos 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
98 1.1 christos 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
99 1.1 christos 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
100 1.1 christos 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
101 1.1 christos };
102 1.1 christos
103 1.1 christos #define HSHA_OFFSET 22 /*%< 21 = 6 + 1 + 4 + 5 + 1 + 4 + 1 */
104 1.1 christos #define HSHA_LENGTH 88
105 1.1 christos
106 1.1 christos static isc_result_t
107 1.1 christos table_towire(isccc_sexpr_t *alist, isc_buffer_t **buffer);
108 1.1 christos
109 1.1 christos static isc_result_t
110 1.1 christos list_towire(isccc_sexpr_t *alist, isc_buffer_t **buffer);
111 1.1 christos
112 1.1 christos static isc_result_t
113 1.1 christos value_towire(isccc_sexpr_t *elt, isc_buffer_t **buffer) {
114 1.1 christos unsigned int len;
115 1.1 christos isccc_region_t *vr;
116 1.1 christos isc_result_t result;
117 1.1 christos
118 1.1 christos if (isccc_sexpr_binaryp(elt)) {
119 1.1 christos vr = isccc_sexpr_tobinary(elt);
120 1.1 christos len = REGION_SIZE(*vr);
121 1.1 christos result = isc_buffer_reserve(buffer, 1 + 4);
122 1.1 christos if (result != ISC_R_SUCCESS)
123 1.1 christos return (ISC_R_NOSPACE);
124 1.1 christos isc_buffer_putuint8(*buffer, ISCCC_CCMSGTYPE_BINARYDATA);
125 1.1 christos isc_buffer_putuint32(*buffer, len);
126 1.1 christos
127 1.1 christos result = isc_buffer_reserve(buffer, len);
128 1.1 christos if (result != ISC_R_SUCCESS)
129 1.1 christos return (ISC_R_NOSPACE);
130 1.1 christos isc_buffer_putmem(*buffer, vr->rstart, len);
131 1.1 christos } else if (isccc_alist_alistp(elt)) {
132 1.1 christos unsigned int used;
133 1.1 christos isc_buffer_t b;
134 1.1 christos
135 1.1 christos result = isc_buffer_reserve(buffer, 1 + 4);
136 1.1 christos if (result != ISC_R_SUCCESS)
137 1.1 christos return (ISC_R_NOSPACE);
138 1.1 christos isc_buffer_putuint8(*buffer, ISCCC_CCMSGTYPE_TABLE);
139 1.1 christos /*
140 1.1 christos * Emit a placeholder length.
141 1.1 christos */
142 1.1 christos used = (*buffer)->used;
143 1.1 christos isc_buffer_putuint32(*buffer, 0);
144 1.1 christos
145 1.1 christos /*
146 1.1 christos * Emit the table.
147 1.1 christos */
148 1.1 christos result = table_towire(elt, buffer);
149 1.1 christos if (result != ISC_R_SUCCESS)
150 1.1 christos return (result);
151 1.1 christos
152 1.1 christos len = (*buffer)->used - used;
153 1.1 christos /*
154 1.1 christos * 'len' is 4 bytes too big, since it counts
155 1.1 christos * the placeholder length too. Adjust and
156 1.1 christos * emit.
157 1.1 christos */
158 1.1 christos INSIST(len >= 4U);
159 1.1 christos len -= 4;
160 1.1 christos
161 1.1 christos isc_buffer_init(&b, (unsigned char *) (*buffer)->base + used, 4);
162 1.1 christos isc_buffer_putuint32(&b, len);
163 1.1 christos } else if (isccc_sexpr_listp(elt)) {
164 1.1 christos unsigned int used;
165 1.1 christos isc_buffer_t b;
166 1.1 christos
167 1.1 christos result = isc_buffer_reserve(buffer, 1 + 4);
168 1.1 christos if (result != ISC_R_SUCCESS)
169 1.1 christos return (ISC_R_NOSPACE);
170 1.1 christos isc_buffer_putuint8(*buffer, ISCCC_CCMSGTYPE_LIST);
171 1.1 christos /*
172 1.1 christos * Emit a placeholder length.
173 1.1 christos */
174 1.1 christos used = (*buffer)->used;
175 1.1 christos isc_buffer_putuint32(*buffer, 0);
176 1.1 christos
177 1.1 christos /*
178 1.1 christos * Emit the list.
179 1.1 christos */
180 1.1 christos result = list_towire(elt, buffer);
181 1.1 christos if (result != ISC_R_SUCCESS)
182 1.1 christos return (result);
183 1.1 christos
184 1.1 christos len = (*buffer)->used - used;
185 1.1 christos /*
186 1.1 christos * 'len' is 4 bytes too big, since it counts
187 1.1 christos * the placeholder length too. Adjust and
188 1.1 christos * emit.
189 1.1 christos */
190 1.1 christos INSIST(len >= 4U);
191 1.1 christos len -= 4;
192 1.1 christos
193 1.1 christos isc_buffer_init(&b, (unsigned char *) (*buffer)->base + used, 4);
194 1.1 christos isc_buffer_putuint32(&b, len);
195 1.1 christos }
196 1.1 christos
197 1.1 christos return (ISC_R_SUCCESS);
198 1.1 christos }
199 1.1 christos
200 1.1 christos static isc_result_t
201 1.1 christos table_towire(isccc_sexpr_t *alist, isc_buffer_t **buffer) {
202 1.1 christos isccc_sexpr_t *kv, *elt, *k, *v;
203 1.1 christos char *ks;
204 1.1 christos isc_result_t result;
205 1.1 christos unsigned int len;
206 1.1 christos
207 1.1 christos for (elt = isccc_alist_first(alist);
208 1.1 christos elt != NULL;
209 1.1 christos elt = ISCCC_SEXPR_CDR(elt)) {
210 1.1 christos kv = ISCCC_SEXPR_CAR(elt);
211 1.1 christos k = ISCCC_SEXPR_CAR(kv);
212 1.1 christos ks = isccc_sexpr_tostring(k);
213 1.1 christos v = ISCCC_SEXPR_CDR(kv);
214 1.1 christos len = (unsigned int)strlen(ks);
215 1.1 christos INSIST(len <= 255U);
216 1.1 christos /*
217 1.1 christos * Emit the key name.
218 1.1 christos */
219 1.1 christos result = isc_buffer_reserve(buffer, 1 + len);
220 1.1 christos if (result != ISC_R_SUCCESS)
221 1.1 christos return (ISC_R_NOSPACE);
222 1.3 christos isc_buffer_putuint8(*buffer, (uint8_t)len);
223 1.1 christos isc_buffer_putmem(*buffer, (const unsigned char *) ks, len);
224 1.1 christos /*
225 1.1 christos * Emit the value.
226 1.1 christos */
227 1.1 christos result = value_towire(v, buffer);
228 1.1 christos if (result != ISC_R_SUCCESS)
229 1.1 christos return (result);
230 1.1 christos }
231 1.1 christos
232 1.1 christos return (ISC_R_SUCCESS);
233 1.1 christos }
234 1.1 christos
235 1.1 christos static isc_result_t
236 1.1 christos list_towire(isccc_sexpr_t *list, isc_buffer_t **buffer) {
237 1.1 christos isc_result_t result;
238 1.1 christos
239 1.1 christos while (list != NULL) {
240 1.1 christos result = value_towire(ISCCC_SEXPR_CAR(list), buffer);
241 1.1 christos if (result != ISC_R_SUCCESS)
242 1.1 christos return (result);
243 1.1 christos list = ISCCC_SEXPR_CDR(list);
244 1.1 christos }
245 1.1 christos
246 1.1 christos return (ISC_R_SUCCESS);
247 1.1 christos }
248 1.1 christos
249 1.1 christos static isc_result_t
250 1.1 christos sign(unsigned char *data, unsigned int length, unsigned char *hmac,
251 1.3 christos uint32_t algorithm, isccc_region_t *secret)
252 1.1 christos {
253 1.3 christos isc_md_type_t md_type;
254 1.1 christos isc_result_t result;
255 1.1 christos isccc_region_t source, target;
256 1.3 christos unsigned char digest[ISC_MAX_MD_SIZE];
257 1.3 christos unsigned int digestlen;
258 1.1 christos unsigned char digestb64[HSHA_LENGTH + 4];
259 1.1 christos
260 1.1 christos source.rstart = digest;
261 1.1 christos
262 1.1 christos switch (algorithm) {
263 1.1 christos case ISCCC_ALG_HMACMD5:
264 1.3 christos md_type = ISC_MD_MD5;
265 1.1 christos break;
266 1.1 christos case ISCCC_ALG_HMACSHA1:
267 1.3 christos md_type = ISC_MD_SHA1;
268 1.1 christos break;
269 1.1 christos case ISCCC_ALG_HMACSHA224:
270 1.3 christos md_type = ISC_MD_SHA224;
271 1.1 christos break;
272 1.1 christos case ISCCC_ALG_HMACSHA256:
273 1.3 christos md_type = ISC_MD_SHA256;
274 1.1 christos break;
275 1.1 christos case ISCCC_ALG_HMACSHA384:
276 1.3 christos md_type = ISC_MD_SHA384;
277 1.1 christos break;
278 1.1 christos case ISCCC_ALG_HMACSHA512:
279 1.3 christos md_type = ISC_MD_SHA512;
280 1.1 christos break;
281 1.3 christos default:
282 1.3 christos return (ISC_R_NOTIMPLEMENTED);
283 1.3 christos }
284 1.1 christos
285 1.3 christos result = isc_hmac(md_type,
286 1.3 christos secret->rstart, REGION_SIZE(*secret),
287 1.3 christos data, length,
288 1.3 christos digest, &digestlen);
289 1.3 christos if (result != ISC_R_SUCCESS) {
290 1.3 christos return (result);
291 1.1 christos }
292 1.3 christos source.rend = digest + digestlen;
293 1.1 christos
294 1.1 christos memset(digestb64, 0, sizeof(digestb64));
295 1.1 christos target.rstart = digestb64;
296 1.1 christos target.rend = digestb64 + sizeof(digestb64);
297 1.1 christos result = isccc_base64_encode(&source, 64, "", &target);
298 1.1 christos if (result != ISC_R_SUCCESS)
299 1.1 christos return (result);
300 1.1 christos if (algorithm == ISCCC_ALG_HMACMD5)
301 1.1 christos PUT_MEM(digestb64, HMD5_LENGTH, hmac);
302 1.1 christos else
303 1.1 christos PUT_MEM(digestb64, HSHA_LENGTH, hmac);
304 1.1 christos return (ISC_R_SUCCESS);
305 1.1 christos }
306 1.1 christos
307 1.1 christos isc_result_t
308 1.1 christos isccc_cc_towire(isccc_sexpr_t *alist, isc_buffer_t **buffer,
309 1.3 christos uint32_t algorithm, isccc_region_t *secret)
310 1.1 christos {
311 1.1 christos unsigned int hmac_base, signed_base;
312 1.1 christos isc_result_t result;
313 1.1 christos
314 1.1 christos result = isc_buffer_reserve(buffer,
315 1.1 christos 4 + ((algorithm == ISCCC_ALG_HMACMD5) ?
316 1.1 christos sizeof(auth_hmd5) :
317 1.1 christos sizeof(auth_hsha)));
318 1.1 christos if (result != ISC_R_SUCCESS)
319 1.1 christos return (ISC_R_NOSPACE);
320 1.1 christos
321 1.1 christos /*
322 1.1 christos * Emit protocol version.
323 1.1 christos */
324 1.1 christos isc_buffer_putuint32(*buffer, 1);
325 1.1 christos
326 1.1 christos if (secret != NULL) {
327 1.1 christos /*
328 1.1 christos * Emit _auth section with zeroed HMAC signature.
329 1.1 christos * We'll replace the zeros with the real signature once
330 1.1 christos * we know what it is.
331 1.1 christos */
332 1.1 christos if (algorithm == ISCCC_ALG_HMACMD5) {
333 1.1 christos hmac_base = (*buffer)->used + HMD5_OFFSET;
334 1.1 christos isc_buffer_putmem(*buffer,
335 1.1 christos auth_hmd5, sizeof(auth_hmd5));
336 1.1 christos } else
337 1.1 christos {
338 1.1 christos unsigned char *hmac_alg;
339 1.1 christos
340 1.1 christos hmac_base = (*buffer)->used + HSHA_OFFSET;
341 1.1 christos hmac_alg = (unsigned char *) isc_buffer_used(*buffer) +
342 1.1 christos HSHA_OFFSET - 1;
343 1.1 christos isc_buffer_putmem(*buffer,
344 1.1 christos auth_hsha, sizeof(auth_hsha));
345 1.1 christos *hmac_alg = algorithm;
346 1.1 christos }
347 1.1 christos } else
348 1.1 christos hmac_base = 0;
349 1.1 christos signed_base = (*buffer)->used;
350 1.1 christos /*
351 1.1 christos * Delete any existing _auth section so that we don't try
352 1.1 christos * to encode it.
353 1.1 christos */
354 1.1 christos isccc_alist_delete(alist, "_auth");
355 1.1 christos /*
356 1.1 christos * Emit the message.
357 1.1 christos */
358 1.1 christos result = table_towire(alist, buffer);
359 1.1 christos if (result != ISC_R_SUCCESS)
360 1.1 christos return (result);
361 1.1 christos if (secret != NULL)
362 1.1 christos return (sign((unsigned char *) (*buffer)->base + signed_base,
363 1.1 christos (*buffer)->used - signed_base,
364 1.1 christos (unsigned char *) (*buffer)->base + hmac_base,
365 1.1 christos algorithm, secret));
366 1.1 christos return (ISC_R_SUCCESS);
367 1.1 christos }
368 1.1 christos
369 1.1 christos static isc_result_t
370 1.1 christos verify(isccc_sexpr_t *alist, unsigned char *data, unsigned int length,
371 1.3 christos uint32_t algorithm, isccc_region_t *secret)
372 1.1 christos {
373 1.3 christos isc_md_type_t md_type;
374 1.1 christos isccc_region_t source;
375 1.1 christos isccc_region_t target;
376 1.1 christos isc_result_t result;
377 1.1 christos isccc_sexpr_t *_auth, *hmac;
378 1.3 christos unsigned char digest[ISC_MAX_MD_SIZE];
379 1.3 christos unsigned int digestlen;
380 1.1 christos unsigned char digestb64[HSHA_LENGTH * 4];
381 1.1 christos
382 1.1 christos /*
383 1.1 christos * Extract digest.
384 1.1 christos */
385 1.1 christos _auth = isccc_alist_lookup(alist, "_auth");
386 1.1 christos if (!isccc_alist_alistp(_auth))
387 1.1 christos return (ISC_R_FAILURE);
388 1.1 christos if (algorithm == ISCCC_ALG_HMACMD5)
389 1.1 christos hmac = isccc_alist_lookup(_auth, "hmd5");
390 1.1 christos else
391 1.1 christos hmac = isccc_alist_lookup(_auth, "hsha");
392 1.1 christos if (!isccc_sexpr_binaryp(hmac))
393 1.1 christos return (ISC_R_FAILURE);
394 1.1 christos /*
395 1.1 christos * Compute digest.
396 1.1 christos */
397 1.1 christos source.rstart = digest;
398 1.3 christos
399 1.1 christos switch (algorithm) {
400 1.1 christos case ISCCC_ALG_HMACMD5:
401 1.3 christos md_type = ISC_MD_MD5;
402 1.1 christos break;
403 1.1 christos case ISCCC_ALG_HMACSHA1:
404 1.3 christos md_type = ISC_MD_SHA1;
405 1.1 christos break;
406 1.1 christos case ISCCC_ALG_HMACSHA224:
407 1.3 christos md_type = ISC_MD_SHA224;
408 1.1 christos break;
409 1.1 christos case ISCCC_ALG_HMACSHA256:
410 1.3 christos md_type = ISC_MD_SHA256;
411 1.1 christos break;
412 1.1 christos case ISCCC_ALG_HMACSHA384:
413 1.3 christos md_type = ISC_MD_SHA384;
414 1.1 christos break;
415 1.1 christos case ISCCC_ALG_HMACSHA512:
416 1.3 christos md_type = ISC_MD_SHA512;
417 1.1 christos break;
418 1.3 christos default:
419 1.3 christos return (ISC_R_NOTIMPLEMENTED);
420 1.3 christos }
421 1.1 christos
422 1.3 christos result = isc_hmac(md_type,
423 1.3 christos secret->rstart, REGION_SIZE(*secret),
424 1.3 christos data, length,
425 1.3 christos digest, &digestlen);
426 1.3 christos if (result != ISC_R_SUCCESS) {
427 1.3 christos return (result);
428 1.1 christos }
429 1.3 christos source.rend = digest + digestlen;
430 1.3 christos
431 1.1 christos target.rstart = digestb64;
432 1.1 christos target.rend = digestb64 + sizeof(digestb64);
433 1.1 christos memset(digestb64, 0, sizeof(digestb64));
434 1.1 christos result = isccc_base64_encode(&source, 64, "", &target);
435 1.1 christos if (result != ISC_R_SUCCESS)
436 1.1 christos return (result);
437 1.1 christos
438 1.1 christos /*
439 1.1 christos * Verify.
440 1.1 christos */
441 1.1 christos if (algorithm == ISCCC_ALG_HMACMD5) {
442 1.1 christos isccc_region_t *region;
443 1.1 christos unsigned char *value;
444 1.1 christos
445 1.1 christos region = isccc_sexpr_tobinary(hmac);
446 1.1 christos if ((region->rend - region->rstart) != HMD5_LENGTH)
447 1.1 christos return (ISCCC_R_BADAUTH);
448 1.1 christos value = region->rstart;
449 1.1 christos if (!isc_safe_memequal(value, digestb64, HMD5_LENGTH))
450 1.1 christos return (ISCCC_R_BADAUTH);
451 1.3 christos } else {
452 1.1 christos isccc_region_t *region;
453 1.1 christos unsigned char *value;
454 1.3 christos uint32_t valalg;
455 1.1 christos
456 1.1 christos region = isccc_sexpr_tobinary(hmac);
457 1.1 christos
458 1.1 christos /*
459 1.1 christos * Note: with non-MD5 algorithms, there's an extra octet
460 1.1 christos * to identify which algorithm is in use.
461 1.1 christos */
462 1.1 christos if ((region->rend - region->rstart) != HSHA_LENGTH + 1)
463 1.1 christos return (ISCCC_R_BADAUTH);
464 1.1 christos value = region->rstart;
465 1.1 christos GET8(valalg, value);
466 1.1 christos if ((valalg != algorithm) ||
467 1.1 christos !isc_safe_memequal(value, digestb64, HSHA_LENGTH))
468 1.1 christos return (ISCCC_R_BADAUTH);
469 1.1 christos }
470 1.1 christos
471 1.1 christos return (ISC_R_SUCCESS);
472 1.1 christos }
473 1.1 christos
474 1.1 christos static isc_result_t
475 1.1 christos table_fromwire(isccc_region_t *source, isccc_region_t *secret,
476 1.3 christos uint32_t algorithm, isccc_sexpr_t **alistp);
477 1.1 christos
478 1.1 christos static isc_result_t
479 1.1 christos list_fromwire(isccc_region_t *source, isccc_sexpr_t **listp);
480 1.1 christos
481 1.1 christos static isc_result_t
482 1.1 christos value_fromwire(isccc_region_t *source, isccc_sexpr_t **valuep) {
483 1.1 christos unsigned int msgtype;
484 1.3 christos uint32_t len;
485 1.1 christos isccc_sexpr_t *value;
486 1.1 christos isccc_region_t active;
487 1.1 christos isc_result_t result;
488 1.1 christos
489 1.1 christos if (REGION_SIZE(*source) < 1 + 4)
490 1.1 christos return (ISC_R_UNEXPECTEDEND);
491 1.1 christos GET8(msgtype, source->rstart);
492 1.1 christos GET32(len, source->rstart);
493 1.1 christos if (REGION_SIZE(*source) < len)
494 1.1 christos return (ISC_R_UNEXPECTEDEND);
495 1.1 christos active.rstart = source->rstart;
496 1.1 christos active.rend = active.rstart + len;
497 1.1 christos source->rstart = active.rend;
498 1.1 christos if (msgtype == ISCCC_CCMSGTYPE_BINARYDATA) {
499 1.1 christos value = isccc_sexpr_frombinary(&active);
500 1.1 christos if (value != NULL) {
501 1.1 christos *valuep = value;
502 1.1 christos result = ISC_R_SUCCESS;
503 1.1 christos } else
504 1.1 christos result = ISC_R_NOMEMORY;
505 1.1 christos } else if (msgtype == ISCCC_CCMSGTYPE_TABLE)
506 1.1 christos result = table_fromwire(&active, NULL, 0, valuep);
507 1.1 christos else if (msgtype == ISCCC_CCMSGTYPE_LIST)
508 1.1 christos result = list_fromwire(&active, valuep);
509 1.1 christos else
510 1.1 christos result = ISCCC_R_SYNTAX;
511 1.1 christos
512 1.1 christos return (result);
513 1.1 christos }
514 1.1 christos
515 1.1 christos static isc_result_t
516 1.1 christos table_fromwire(isccc_region_t *source, isccc_region_t *secret,
517 1.3 christos uint32_t algorithm, isccc_sexpr_t **alistp)
518 1.1 christos {
519 1.1 christos char key[256];
520 1.3 christos uint32_t len;
521 1.1 christos isc_result_t result;
522 1.1 christos isccc_sexpr_t *alist, *value;
523 1.3 christos bool first_tag;
524 1.1 christos unsigned char *checksum_rstart;
525 1.1 christos
526 1.1 christos REQUIRE(alistp != NULL && *alistp == NULL);
527 1.1 christos
528 1.1 christos checksum_rstart = NULL;
529 1.3 christos first_tag = true;
530 1.1 christos alist = isccc_alist_create();
531 1.1 christos if (alist == NULL)
532 1.1 christos return (ISC_R_NOMEMORY);
533 1.1 christos
534 1.1 christos while (!REGION_EMPTY(*source)) {
535 1.1 christos GET8(len, source->rstart);
536 1.1 christos if (REGION_SIZE(*source) < len) {
537 1.1 christos result = ISC_R_UNEXPECTEDEND;
538 1.1 christos goto bad;
539 1.1 christos }
540 1.1 christos GET_MEM(key, len, source->rstart);
541 1.1 christos key[len] = '\0'; /* Ensure NUL termination. */
542 1.1 christos value = NULL;
543 1.1 christos result = value_fromwire(source, &value);
544 1.1 christos if (result != ISC_R_SUCCESS)
545 1.1 christos goto bad;
546 1.1 christos if (isccc_alist_define(alist, key, value) == NULL) {
547 1.1 christos result = ISC_R_NOMEMORY;
548 1.1 christos goto bad;
549 1.1 christos }
550 1.1 christos if (first_tag && secret != NULL && strcmp(key, "_auth") == 0)
551 1.1 christos checksum_rstart = source->rstart;
552 1.3 christos first_tag = false;
553 1.1 christos }
554 1.1 christos
555 1.1 christos if (secret != NULL) {
556 1.1 christos if (checksum_rstart != NULL)
557 1.1 christos result = verify(alist, checksum_rstart,
558 1.1 christos (unsigned int)
559 1.1 christos (source->rend - checksum_rstart),
560 1.1 christos algorithm, secret);
561 1.1 christos else
562 1.1 christos result = ISCCC_R_BADAUTH;
563 1.1 christos } else
564 1.1 christos result = ISC_R_SUCCESS;
565 1.1 christos
566 1.1 christos bad:
567 1.1 christos if (result == ISC_R_SUCCESS)
568 1.1 christos *alistp = alist;
569 1.1 christos else
570 1.1 christos isccc_sexpr_free(&alist);
571 1.1 christos
572 1.1 christos return (result);
573 1.1 christos }
574 1.1 christos
575 1.1 christos static isc_result_t
576 1.1 christos list_fromwire(isccc_region_t *source, isccc_sexpr_t **listp) {
577 1.1 christos isccc_sexpr_t *list, *value;
578 1.1 christos isc_result_t result;
579 1.1 christos
580 1.1 christos list = NULL;
581 1.1 christos while (!REGION_EMPTY(*source)) {
582 1.1 christos value = NULL;
583 1.1 christos result = value_fromwire(source, &value);
584 1.1 christos if (result != ISC_R_SUCCESS) {
585 1.1 christos isccc_sexpr_free(&list);
586 1.1 christos return (result);
587 1.1 christos }
588 1.1 christos if (isccc_sexpr_addtolist(&list, value) == NULL) {
589 1.1 christos isccc_sexpr_free(&value);
590 1.1 christos isccc_sexpr_free(&list);
591 1.1 christos return (ISC_R_NOMEMORY);
592 1.1 christos }
593 1.1 christos }
594 1.1 christos
595 1.1 christos *listp = list;
596 1.1 christos
597 1.1 christos return (ISC_R_SUCCESS);
598 1.1 christos }
599 1.1 christos
600 1.1 christos isc_result_t
601 1.1 christos isccc_cc_fromwire(isccc_region_t *source, isccc_sexpr_t **alistp,
602 1.3 christos uint32_t algorithm, isccc_region_t *secret)
603 1.1 christos {
604 1.1 christos unsigned int size;
605 1.3 christos uint32_t version;
606 1.1 christos
607 1.1 christos size = REGION_SIZE(*source);
608 1.1 christos if (size < 4)
609 1.1 christos return (ISC_R_UNEXPECTEDEND);
610 1.1 christos GET32(version, source->rstart);
611 1.1 christos if (version != 1)
612 1.1 christos return (ISCCC_R_UNKNOWNVERSION);
613 1.1 christos
614 1.1 christos return (table_fromwire(source, secret, algorithm, alistp));
615 1.1 christos }
616 1.1 christos
617 1.1 christos static isc_result_t
618 1.3 christos createmessage(uint32_t version, const char *from, const char *to,
619 1.3 christos uint32_t serial, isccc_time_t now,
620 1.1 christos isccc_time_t expires, isccc_sexpr_t **alistp,
621 1.3 christos bool want_expires)
622 1.1 christos {
623 1.1 christos isccc_sexpr_t *alist, *_ctrl, *_data;
624 1.1 christos isc_result_t result;
625 1.1 christos
626 1.1 christos REQUIRE(alistp != NULL && *alistp == NULL);
627 1.1 christos
628 1.1 christos if (version != 1)
629 1.1 christos return (ISCCC_R_UNKNOWNVERSION);
630 1.1 christos
631 1.1 christos alist = isccc_alist_create();
632 1.1 christos if (alist == NULL)
633 1.1 christos return (ISC_R_NOMEMORY);
634 1.1 christos
635 1.1 christos result = ISC_R_NOMEMORY;
636 1.1 christos
637 1.1 christos _ctrl = isccc_alist_create();
638 1.1 christos if (_ctrl == NULL)
639 1.1 christos goto bad;
640 1.1 christos if (isccc_alist_define(alist, "_ctrl", _ctrl) == NULL) {
641 1.1 christos isccc_sexpr_free(&_ctrl);
642 1.1 christos goto bad;
643 1.1 christos }
644 1.1 christos
645 1.1 christos _data = isccc_alist_create();
646 1.1 christos if (_data == NULL)
647 1.1 christos goto bad;
648 1.1 christos if (isccc_alist_define(alist, "_data", _data) == NULL) {
649 1.1 christos isccc_sexpr_free(&_data);
650 1.1 christos goto bad;
651 1.1 christos }
652 1.1 christos
653 1.1 christos if (isccc_cc_defineuint32(_ctrl, "_ser", serial) == NULL ||
654 1.1 christos isccc_cc_defineuint32(_ctrl, "_tim", now) == NULL ||
655 1.1 christos (want_expires &&
656 1.1 christos isccc_cc_defineuint32(_ctrl, "_exp", expires) == NULL))
657 1.1 christos goto bad;
658 1.1 christos if (from != NULL &&
659 1.1 christos isccc_cc_definestring(_ctrl, "_frm", from) == NULL)
660 1.1 christos goto bad;
661 1.1 christos if (to != NULL &&
662 1.1 christos isccc_cc_definestring(_ctrl, "_to", to) == NULL)
663 1.1 christos goto bad;
664 1.1 christos
665 1.1 christos *alistp = alist;
666 1.1 christos
667 1.1 christos return (ISC_R_SUCCESS);
668 1.1 christos
669 1.1 christos bad:
670 1.1 christos isccc_sexpr_free(&alist);
671 1.1 christos
672 1.1 christos return (result);
673 1.1 christos }
674 1.1 christos
675 1.1 christos isc_result_t
676 1.3 christos isccc_cc_createmessage(uint32_t version, const char *from, const char *to,
677 1.3 christos uint32_t serial, isccc_time_t now,
678 1.1 christos isccc_time_t expires, isccc_sexpr_t **alistp)
679 1.1 christos {
680 1.1 christos return (createmessage(version, from, to, serial, now, expires,
681 1.3 christos alistp, true));
682 1.1 christos }
683 1.1 christos
684 1.1 christos isc_result_t
685 1.3 christos isccc_cc_createack(isccc_sexpr_t *message, bool ok,
686 1.1 christos isccc_sexpr_t **ackp)
687 1.1 christos {
688 1.1 christos char *_frm, *_to;
689 1.3 christos uint32_t serial;
690 1.1 christos isccc_sexpr_t *ack, *_ctrl;
691 1.1 christos isc_result_t result;
692 1.1 christos isccc_time_t t;
693 1.1 christos
694 1.1 christos REQUIRE(ackp != NULL && *ackp == NULL);
695 1.1 christos
696 1.1 christos _ctrl = isccc_alist_lookup(message, "_ctrl");
697 1.1 christos if (!isccc_alist_alistp(_ctrl) ||
698 1.1 christos isccc_cc_lookupuint32(_ctrl, "_ser", &serial) != ISC_R_SUCCESS ||
699 1.1 christos isccc_cc_lookupuint32(_ctrl, "_tim", &t) != ISC_R_SUCCESS)
700 1.1 christos return (ISC_R_FAILURE);
701 1.1 christos /*
702 1.1 christos * _frm and _to are optional.
703 1.1 christos */
704 1.1 christos _frm = NULL;
705 1.1 christos (void)isccc_cc_lookupstring(_ctrl, "_frm", &_frm);
706 1.1 christos _to = NULL;
707 1.1 christos (void)isccc_cc_lookupstring(_ctrl, "_to", &_to);
708 1.1 christos /*
709 1.1 christos * Create the ack.
710 1.1 christos */
711 1.1 christos ack = NULL;
712 1.3 christos result = createmessage(1, _to, _frm, serial, t, 0, &ack, false);
713 1.1 christos if (result != ISC_R_SUCCESS)
714 1.1 christos return (result);
715 1.1 christos
716 1.1 christos _ctrl = isccc_alist_lookup(ack, "_ctrl");
717 1.1 christos if (_ctrl == NULL) {
718 1.1 christos result = ISC_R_FAILURE;
719 1.1 christos goto bad;
720 1.1 christos }
721 1.1 christos if (isccc_cc_definestring(ack, "_ack", (ok) ? "1" : "0") == NULL) {
722 1.1 christos result = ISC_R_NOMEMORY;
723 1.1 christos goto bad;
724 1.1 christos }
725 1.1 christos
726 1.1 christos *ackp = ack;
727 1.1 christos
728 1.1 christos return (ISC_R_SUCCESS);
729 1.1 christos
730 1.1 christos bad:
731 1.1 christos isccc_sexpr_free(&ack);
732 1.1 christos
733 1.1 christos return (result);
734 1.1 christos }
735 1.1 christos
736 1.3 christos bool
737 1.1 christos isccc_cc_isack(isccc_sexpr_t *message) {
738 1.1 christos isccc_sexpr_t *_ctrl;
739 1.1 christos
740 1.1 christos _ctrl = isccc_alist_lookup(message, "_ctrl");
741 1.1 christos if (!isccc_alist_alistp(_ctrl))
742 1.3 christos return (false);
743 1.1 christos if (isccc_cc_lookupstring(_ctrl, "_ack", NULL) == ISC_R_SUCCESS)
744 1.3 christos return (true);
745 1.3 christos return (false);
746 1.1 christos }
747 1.1 christos
748 1.3 christos bool
749 1.1 christos isccc_cc_isreply(isccc_sexpr_t *message) {
750 1.1 christos isccc_sexpr_t *_ctrl;
751 1.1 christos
752 1.1 christos _ctrl = isccc_alist_lookup(message, "_ctrl");
753 1.1 christos if (!isccc_alist_alistp(_ctrl))
754 1.3 christos return (false);
755 1.1 christos if (isccc_cc_lookupstring(_ctrl, "_rpl", NULL) == ISC_R_SUCCESS)
756 1.3 christos return (true);
757 1.3 christos return (false);
758 1.1 christos }
759 1.1 christos
760 1.1 christos isc_result_t
761 1.1 christos isccc_cc_createresponse(isccc_sexpr_t *message, isccc_time_t now,
762 1.1 christos isccc_time_t expires, isccc_sexpr_t **alistp)
763 1.1 christos {
764 1.1 christos char *_frm, *_to, *type = NULL;
765 1.3 christos uint32_t serial;
766 1.1 christos isccc_sexpr_t *alist, *_ctrl, *_data;
767 1.1 christos isc_result_t result;
768 1.1 christos
769 1.1 christos REQUIRE(alistp != NULL && *alistp == NULL);
770 1.1 christos
771 1.1 christos _ctrl = isccc_alist_lookup(message, "_ctrl");
772 1.1 christos _data = isccc_alist_lookup(message, "_data");
773 1.1 christos if (!isccc_alist_alistp(_ctrl) || !isccc_alist_alistp(_data) ||
774 1.1 christos isccc_cc_lookupuint32(_ctrl, "_ser", &serial) != ISC_R_SUCCESS ||
775 1.1 christos isccc_cc_lookupstring(_data, "type", &type) != ISC_R_SUCCESS)
776 1.1 christos return (ISC_R_FAILURE);
777 1.1 christos /*
778 1.1 christos * _frm and _to are optional.
779 1.1 christos */
780 1.1 christos _frm = NULL;
781 1.1 christos (void)isccc_cc_lookupstring(_ctrl, "_frm", &_frm);
782 1.1 christos _to = NULL;
783 1.1 christos (void)isccc_cc_lookupstring(_ctrl, "_to", &_to);
784 1.1 christos /*
785 1.1 christos * Create the response.
786 1.1 christos */
787 1.1 christos alist = NULL;
788 1.1 christos result = isccc_cc_createmessage(1, _to, _frm, serial, now, expires,
789 1.1 christos &alist);
790 1.1 christos if (result != ISC_R_SUCCESS)
791 1.1 christos return (result);
792 1.1 christos
793 1.1 christos _ctrl = isccc_alist_lookup(alist, "_ctrl");
794 1.1 christos if (_ctrl == NULL) {
795 1.1 christos result = ISC_R_FAILURE;
796 1.1 christos goto bad;
797 1.1 christos }
798 1.1 christos
799 1.1 christos _data = isccc_alist_lookup(alist, "_data");
800 1.1 christos if (_data == NULL) {
801 1.1 christos result = ISC_R_FAILURE;
802 1.1 christos goto bad;
803 1.1 christos }
804 1.1 christos
805 1.1 christos if (isccc_cc_definestring(_ctrl, "_rpl", "1") == NULL ||
806 1.1 christos isccc_cc_definestring(_data, "type", type) == NULL)
807 1.1 christos {
808 1.1 christos result = ISC_R_NOMEMORY;
809 1.1 christos goto bad;
810 1.1 christos }
811 1.1 christos
812 1.1 christos *alistp = alist;
813 1.1 christos
814 1.1 christos return (ISC_R_SUCCESS);
815 1.1 christos
816 1.1 christos bad:
817 1.1 christos isccc_sexpr_free(&alist);
818 1.1 christos return (result);
819 1.1 christos }
820 1.1 christos
821 1.1 christos isccc_sexpr_t *
822 1.1 christos isccc_cc_definestring(isccc_sexpr_t *alist, const char *key, const char *str) {
823 1.1 christos size_t len;
824 1.1 christos isccc_region_t r;
825 1.1 christos
826 1.1 christos len = strlen(str);
827 1.1 christos DE_CONST(str, r.rstart);
828 1.1 christos r.rend = r.rstart + len;
829 1.1 christos
830 1.1 christos return (isccc_alist_definebinary(alist, key, &r));
831 1.1 christos }
832 1.1 christos
833 1.1 christos isccc_sexpr_t *
834 1.3 christos isccc_cc_defineuint32(isccc_sexpr_t *alist, const char *key, uint32_t i) {
835 1.1 christos char b[100];
836 1.1 christos size_t len;
837 1.1 christos isccc_region_t r;
838 1.1 christos
839 1.1 christos snprintf(b, sizeof(b), "%u", i);
840 1.1 christos len = strlen(b);
841 1.1 christos r.rstart = (unsigned char *)b;
842 1.1 christos r.rend = (unsigned char *)b + len;
843 1.1 christos
844 1.1 christos return (isccc_alist_definebinary(alist, key, &r));
845 1.1 christos }
846 1.1 christos
847 1.1 christos isc_result_t
848 1.1 christos isccc_cc_lookupstring(isccc_sexpr_t *alist, const char *key, char **strp) {
849 1.1 christos isccc_sexpr_t *kv, *v;
850 1.1 christos
851 1.1 christos REQUIRE(strp == NULL || *strp == NULL);
852 1.1 christos
853 1.1 christos kv = isccc_alist_assq(alist, key);
854 1.1 christos if (kv != NULL) {
855 1.1 christos v = ISCCC_SEXPR_CDR(kv);
856 1.1 christos if (isccc_sexpr_binaryp(v)) {
857 1.1 christos if (strp != NULL)
858 1.1 christos *strp = isccc_sexpr_tostring(v);
859 1.1 christos return (ISC_R_SUCCESS);
860 1.1 christos } else
861 1.1 christos return (ISC_R_EXISTS);
862 1.1 christos }
863 1.1 christos
864 1.1 christos return (ISC_R_NOTFOUND);
865 1.1 christos }
866 1.1 christos
867 1.1 christos isc_result_t
868 1.1 christos isccc_cc_lookupuint32(isccc_sexpr_t *alist, const char *key,
869 1.3 christos uint32_t *uintp)
870 1.1 christos {
871 1.1 christos isccc_sexpr_t *kv, *v;
872 1.1 christos
873 1.1 christos kv = isccc_alist_assq(alist, key);
874 1.1 christos if (kv != NULL) {
875 1.1 christos v = ISCCC_SEXPR_CDR(kv);
876 1.1 christos if (isccc_sexpr_binaryp(v)) {
877 1.1 christos if (uintp != NULL)
878 1.3 christos *uintp = (uint32_t)
879 1.1 christos strtoul(isccc_sexpr_tostring(v),
880 1.1 christos NULL, 10);
881 1.1 christos return (ISC_R_SUCCESS);
882 1.1 christos } else
883 1.1 christos return (ISC_R_EXISTS);
884 1.1 christos }
885 1.1 christos
886 1.1 christos return (ISC_R_NOTFOUND);
887 1.1 christos }
888 1.1 christos
889 1.1 christos static void
890 1.1 christos symtab_undefine(char *key, unsigned int type, isccc_symvalue_t value,
891 1.1 christos void *arg)
892 1.1 christos {
893 1.1 christos UNUSED(type);
894 1.1 christos UNUSED(value);
895 1.1 christos UNUSED(arg);
896 1.1 christos
897 1.1 christos free(key);
898 1.1 christos }
899 1.1 christos
900 1.3 christos static bool
901 1.1 christos symtab_clean(char *key, unsigned int type, isccc_symvalue_t value, void *arg) {
902 1.1 christos isccc_time_t *now;
903 1.1 christos
904 1.1 christos UNUSED(key);
905 1.1 christos UNUSED(type);
906 1.1 christos
907 1.1 christos now = arg;
908 1.1 christos
909 1.1 christos if (*now < value.as_uinteger)
910 1.3 christos return (false);
911 1.1 christos if ((*now - value.as_uinteger) < DUP_LIFETIME)
912 1.3 christos return (false);
913 1.3 christos return (true);
914 1.1 christos }
915 1.1 christos
916 1.1 christos isc_result_t
917 1.1 christos isccc_cc_createsymtab(isccc_symtab_t **symtabp) {
918 1.3 christos return (isccc_symtab_create(11897, symtab_undefine, NULL, false,
919 1.1 christos symtabp));
920 1.1 christos }
921 1.1 christos
922 1.1 christos void
923 1.1 christos isccc_cc_cleansymtab(isccc_symtab_t *symtab, isccc_time_t now) {
924 1.1 christos isccc_symtab_foreach(symtab, symtab_clean, &now);
925 1.1 christos }
926 1.1 christos
927 1.3 christos static bool
928 1.1 christos has_whitespace(const char *str) {
929 1.1 christos char c;
930 1.1 christos
931 1.1 christos if (str == NULL)
932 1.3 christos return (false);
933 1.1 christos while ((c = *str++) != '\0') {
934 1.1 christos if (c == ' ' || c == '\t' || c == '\n')
935 1.3 christos return (true);
936 1.1 christos }
937 1.3 christos return (false);
938 1.1 christos }
939 1.1 christos
940 1.1 christos isc_result_t
941 1.1 christos isccc_cc_checkdup(isccc_symtab_t *symtab, isccc_sexpr_t *message,
942 1.1 christos isccc_time_t now)
943 1.1 christos {
944 1.1 christos const char *_frm;
945 1.1 christos const char *_to;
946 1.1 christos char *_ser = NULL, *_tim = NULL, *tmp;
947 1.1 christos isc_result_t result;
948 1.1 christos char *key;
949 1.1 christos size_t len;
950 1.1 christos isccc_symvalue_t value;
951 1.1 christos isccc_sexpr_t *_ctrl;
952 1.1 christos
953 1.1 christos _ctrl = isccc_alist_lookup(message, "_ctrl");
954 1.1 christos if (!isccc_alist_alistp(_ctrl) ||
955 1.1 christos isccc_cc_lookupstring(_ctrl, "_ser", &_ser) != ISC_R_SUCCESS ||
956 1.1 christos isccc_cc_lookupstring(_ctrl, "_tim", &_tim) != ISC_R_SUCCESS)
957 1.1 christos return (ISC_R_FAILURE);
958 1.1 christos
959 1.1 christos INSIST(_ser != NULL);
960 1.1 christos INSIST(_tim != NULL);
961 1.1 christos
962 1.1 christos /*
963 1.1 christos * _frm and _to are optional.
964 1.1 christos */
965 1.1 christos tmp = NULL;
966 1.1 christos if (isccc_cc_lookupstring(_ctrl, "_frm", &tmp) != ISC_R_SUCCESS)
967 1.1 christos _frm = "";
968 1.1 christos else
969 1.1 christos _frm = tmp;
970 1.1 christos tmp = NULL;
971 1.1 christos if (isccc_cc_lookupstring(_ctrl, "_to", &tmp) != ISC_R_SUCCESS)
972 1.1 christos _to = "";
973 1.1 christos else
974 1.1 christos _to = tmp;
975 1.1 christos /*
976 1.1 christos * Ensure there is no newline in any of the strings. This is so
977 1.1 christos * we can write them to a file later.
978 1.1 christos */
979 1.1 christos if (has_whitespace(_frm) || has_whitespace(_to) ||
980 1.1 christos has_whitespace(_ser) || has_whitespace(_tim))
981 1.1 christos return (ISC_R_FAILURE);
982 1.1 christos len = strlen(_frm) + strlen(_to) + strlen(_ser) + strlen(_tim) + 4;
983 1.1 christos key = malloc(len);
984 1.1 christos if (key == NULL)
985 1.1 christos return (ISC_R_NOMEMORY);
986 1.1 christos snprintf(key, len, "%s;%s;%s;%s", _frm, _to, _ser, _tim);
987 1.1 christos value.as_uinteger = now;
988 1.1 christos result = isccc_symtab_define(symtab, key, ISCCC_SYMTYPE_CCDUP, value,
989 1.1 christos isccc_symexists_reject);
990 1.1 christos if (result != ISC_R_SUCCESS) {
991 1.1 christos free(key);
992 1.1 christos return (result);
993 1.1 christos }
994 1.1 christos
995 1.1 christos return (ISC_R_SUCCESS);
996 1.1 christos }
997