1 /*	$NetBSD: tsig_test.c,v 1.9 2022/09/23 12:15:32 christos Exp $	*/
2 
3 /*
4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5  *
6  * SPDX-License-Identifier: MPL-2.0
7  *
8  * This Source Code Form is subject to the terms of the Mozilla Public
9  * License, v. 2.0. If a copy of the MPL was not distributed with this
10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11  *
12  * See the COPYRIGHT file distributed with this work for additional
13  * information regarding copyright ownership.
14  */
15 
16 #if HAVE_CMOCKA
17 
18 #include <sched.h> /* IWYU pragma: keep */
19 #include <setjmp.h>
20 #include <stdarg.h>
21 #include <stdbool.h>
22 #include <stddef.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 
26 #define UNIT_TESTING
27 #include <cmocka.h>
28 
29 #include <isc/mem.h>
30 #include <isc/print.h>
31 #include <isc/util.h>
32 
33 #include <dns/rdatalist.h>
34 #include <dns/rdataset.h>
35 #include <dns/tsig.h>
36 
37 #include "../tsig_p.h"
38 #include "dnstest.h"
39 
40 #define CHECK(r)                               \
41 	do {                                   \
42 		result = (r);                  \
43 		if (result != ISC_R_SUCCESS) { \
44 			goto cleanup;          \
45 		}                              \
46 	} while (0)
47 
48 #define TEST_ORIGIN "test"
49 
50 static int
_setup(void ** state)51 _setup(void **state) {
52 	isc_result_t result;
53 
54 	UNUSED(state);
55 
56 	result = dns_test_begin(NULL, false);
57 	assert_int_equal(result, ISC_R_SUCCESS);
58 
59 	return (0);
60 }
61 
62 static int
_teardown(void ** state)63 _teardown(void **state) {
64 	UNUSED(state);
65 
66 	dns_test_end();
67 
68 	return (0);
69 }
70 
71 static int debug = 0;
72 
73 static isc_result_t
add_mac(dst_context_t * tsigctx,isc_buffer_t * buf)74 add_mac(dst_context_t *tsigctx, isc_buffer_t *buf) {
75 	dns_rdata_any_tsig_t tsig;
76 	dns_rdata_t rdata = DNS_RDATA_INIT;
77 	isc_buffer_t databuf;
78 	isc_region_t r;
79 	isc_result_t result;
80 	unsigned char tsigbuf[1024];
81 
82 	isc_buffer_usedregion(buf, &r);
83 	dns_rdata_fromregion(&rdata, dns_rdataclass_any, dns_rdatatype_tsig,
84 			     &r);
85 	isc_buffer_init(&databuf, tsigbuf, sizeof(tsigbuf));
86 	CHECK(dns_rdata_tostruct(&rdata, &tsig, NULL));
87 	isc_buffer_putuint16(&databuf, tsig.siglen);
88 	isc_buffer_putmem(&databuf, tsig.signature, tsig.siglen);
89 	isc_buffer_usedregion(&databuf, &r);
90 	result = dst_context_adddata(tsigctx, &r);
91 	dns_rdata_freestruct(&tsig);
92 cleanup:
93 	return (result);
94 }
95 
96 static isc_result_t
add_tsig(dst_context_t * tsigctx,dns_tsigkey_t * key,isc_buffer_t * target)97 add_tsig(dst_context_t *tsigctx, dns_tsigkey_t *key, isc_buffer_t *target) {
98 	dns_compress_t cctx;
99 	dns_rdata_any_tsig_t tsig;
100 	dns_rdata_t rdata = DNS_RDATA_INIT;
101 	dns_rdatalist_t rdatalist;
102 	dns_rdataset_t rdataset;
103 	isc_buffer_t *dynbuf = NULL;
104 	isc_buffer_t databuf;
105 	isc_buffer_t sigbuf;
106 	isc_region_t r;
107 	isc_result_t result = ISC_R_SUCCESS;
108 	isc_stdtime_t now;
109 	unsigned char tsigbuf[1024];
110 	unsigned int count;
111 	unsigned int sigsize = 0;
112 	bool invalidate_ctx = false;
113 
114 	memset(&tsig, 0, sizeof(tsig));
115 
116 	CHECK(dns_compress_init(&cctx, -1, dt_mctx));
117 	invalidate_ctx = true;
118 
119 	tsig.common.rdclass = dns_rdataclass_any;
120 	tsig.common.rdtype = dns_rdatatype_tsig;
121 	ISC_LINK_INIT(&tsig.common, link);
122 	dns_name_init(&tsig.algorithm, NULL);
123 	dns_name_clone(key->algorithm, &tsig.algorithm);
124 
125 	isc_stdtime_get(&now);
126 	tsig.timesigned = now;
127 	tsig.fudge = DNS_TSIG_FUDGE;
128 	tsig.originalid = 50;
129 	tsig.error = dns_rcode_noerror;
130 	tsig.otherlen = 0;
131 	tsig.other = NULL;
132 
133 	isc_buffer_init(&databuf, tsigbuf, sizeof(tsigbuf));
134 	isc_buffer_putuint48(&databuf, tsig.timesigned);
135 	isc_buffer_putuint16(&databuf, tsig.fudge);
136 	isc_buffer_usedregion(&databuf, &r);
137 	CHECK(dst_context_adddata(tsigctx, &r));
138 
139 	CHECK(dst_key_sigsize(key->key, &sigsize));
140 	tsig.signature = isc_mem_get(dt_mctx, sigsize);
141 	isc_buffer_init(&sigbuf, tsig.signature, sigsize);
142 	CHECK(dst_context_sign(tsigctx, &sigbuf));
143 	tsig.siglen = isc_buffer_usedlength(&sigbuf);
144 	assert_int_equal(sigsize, tsig.siglen);
145 
146 	isc_buffer_allocate(dt_mctx, &dynbuf, 512);
147 	CHECK(dns_rdata_fromstruct(&rdata, dns_rdataclass_any,
148 				   dns_rdatatype_tsig, &tsig, dynbuf));
149 	dns_rdatalist_init(&rdatalist);
150 	rdatalist.rdclass = dns_rdataclass_any;
151 	rdatalist.type = dns_rdatatype_tsig;
152 	ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
153 	dns_rdataset_init(&rdataset);
154 	CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset));
155 	CHECK(dns_rdataset_towire(&rdataset, &key->name, &cctx, target, 0,
156 				  &count));
157 
158 	/*
159 	 * Fixup additional record count.
160 	 */
161 	((unsigned char *)target->base)[11]++;
162 	if (((unsigned char *)target->base)[11] == 0) {
163 		((unsigned char *)target->base)[10]++;
164 	}
165 cleanup:
166 	if (tsig.signature != NULL) {
167 		isc_mem_put(dt_mctx, tsig.signature, sigsize);
168 	}
169 	if (dynbuf != NULL) {
170 		isc_buffer_free(&dynbuf);
171 	}
172 	if (invalidate_ctx) {
173 		dns_compress_invalidate(&cctx);
174 	}
175 
176 	return (result);
177 }
178 
179 static void
printmessage(dns_message_t * msg)180 printmessage(dns_message_t *msg) {
181 	isc_buffer_t b;
182 	char *buf = NULL;
183 	int len = 1024;
184 	isc_result_t result = ISC_R_SUCCESS;
185 
186 	if (!debug) {
187 		return;
188 	}
189 
190 	do {
191 		buf = isc_mem_get(dt_mctx, len);
192 
193 		isc_buffer_init(&b, buf, len);
194 		result = dns_message_totext(msg, &dns_master_style_debug, 0,
195 					    &b);
196 		if (result == ISC_R_NOSPACE) {
197 			isc_mem_put(dt_mctx, buf, len);
198 			len *= 2;
199 		} else if (result == ISC_R_SUCCESS) {
200 			printf("%.*s\n", (int)isc_buffer_usedlength(&b), buf);
201 		}
202 	} while (result == ISC_R_NOSPACE);
203 
204 	if (buf != NULL) {
205 		isc_mem_put(dt_mctx, buf, len);
206 	}
207 }
208 
209 static void
render(isc_buffer_t * buf,unsigned flags,dns_tsigkey_t * key,isc_buffer_t ** tsigin,isc_buffer_t ** tsigout,dst_context_t * tsigctx)210 render(isc_buffer_t *buf, unsigned flags, dns_tsigkey_t *key,
211        isc_buffer_t **tsigin, isc_buffer_t **tsigout, dst_context_t *tsigctx) {
212 	dns_message_t *msg = NULL;
213 	dns_compress_t cctx;
214 	isc_result_t result;
215 
216 	dns_message_create(dt_mctx, DNS_MESSAGE_INTENTRENDER, &msg);
217 	assert_non_null(msg);
218 
219 	msg->id = 50;
220 	msg->rcode = dns_rcode_noerror;
221 	msg->flags = flags;
222 
223 	/*
224 	 * XXXMPA: this hack needs to be replaced with use of
225 	 * dns_message_reply() at some point.
226 	 */
227 	if ((flags & DNS_MESSAGEFLAG_QR) != 0) {
228 		msg->verified_sig = 1;
229 	}
230 
231 	if (tsigin == tsigout) {
232 		msg->tcp_continuation = 1;
233 	}
234 
235 	if (tsigctx == NULL) {
236 		result = dns_message_settsigkey(msg, key);
237 		assert_int_equal(result, ISC_R_SUCCESS);
238 
239 		result = dns_message_setquerytsig(msg, *tsigin);
240 		assert_int_equal(result, ISC_R_SUCCESS);
241 	}
242 
243 	result = dns_compress_init(&cctx, -1, dt_mctx);
244 	assert_int_equal(result, ISC_R_SUCCESS);
245 
246 	result = dns_message_renderbegin(msg, &cctx, buf);
247 	assert_int_equal(result, ISC_R_SUCCESS);
248 
249 	result = dns_message_renderend(msg);
250 	assert_int_equal(result, ISC_R_SUCCESS);
251 
252 	if (tsigctx != NULL) {
253 		isc_region_t r;
254 
255 		isc_buffer_usedregion(buf, &r);
256 		result = dst_context_adddata(tsigctx, &r);
257 		assert_int_equal(result, ISC_R_SUCCESS);
258 	} else {
259 		if (tsigin == tsigout && *tsigin != NULL) {
260 			isc_buffer_free(tsigin);
261 		}
262 
263 		result = dns_message_getquerytsig(msg, dt_mctx, tsigout);
264 		assert_int_equal(result, ISC_R_SUCCESS);
265 	}
266 
267 	dns_compress_invalidate(&cctx);
268 	dns_message_detach(&msg);
269 }
270 
271 /*
272  * Test tsig tcp-continuation validation:
273  * Check that a simulated three message TCP sequence where the first
274  * and last messages contain TSIGs but the intermediate message doesn't
275  * correctly verifies.
276  */
277 static void
tsig_tcp_test(void ** state)278 tsig_tcp_test(void **state) {
279 	const dns_name_t *tsigowner = NULL;
280 	dns_fixedname_t fkeyname;
281 	dns_message_t *msg = NULL;
282 	dns_name_t *keyname;
283 	dns_tsig_keyring_t *ring = NULL;
284 	dns_tsigkey_t *key = NULL;
285 	isc_buffer_t *buf = NULL;
286 	isc_buffer_t *querytsig = NULL;
287 	isc_buffer_t *tsigin = NULL;
288 	isc_buffer_t *tsigout = NULL;
289 	isc_result_t result;
290 	unsigned char secret[16] = { 0 };
291 	dst_context_t *tsigctx = NULL;
292 	dst_context_t *outctx = NULL;
293 
294 	UNUSED(state);
295 
296 	/* isc_log_setdebuglevel(lctx, 99); */
297 
298 	keyname = dns_fixedname_initname(&fkeyname);
299 	result = dns_name_fromstring(keyname, "test", 0, NULL);
300 	assert_int_equal(result, ISC_R_SUCCESS);
301 
302 	result = dns_tsigkeyring_create(dt_mctx, &ring);
303 	assert_int_equal(result, ISC_R_SUCCESS);
304 
305 	result = dns_tsigkey_create(keyname, dns_tsig_hmacsha256_name, secret,
306 				    sizeof(secret), false, NULL, 0, 0, dt_mctx,
307 				    ring, &key);
308 	assert_int_equal(result, ISC_R_SUCCESS);
309 	assert_non_null(key);
310 
311 	/*
312 	 * Create request.
313 	 */
314 	isc_buffer_allocate(dt_mctx, &buf, 65535);
315 	render(buf, 0, key, &tsigout, &querytsig, NULL);
316 	isc_buffer_free(&buf);
317 
318 	/*
319 	 * Create response message 1.
320 	 */
321 	isc_buffer_allocate(dt_mctx, &buf, 65535);
322 	render(buf, DNS_MESSAGEFLAG_QR, key, &querytsig, &tsigout, NULL);
323 	assert_non_null(tsigout);
324 
325 	/*
326 	 * Process response message 1.
327 	 */
328 	dns_message_create(dt_mctx, DNS_MESSAGE_INTENTPARSE, &msg);
329 	assert_non_null(msg);
330 
331 	result = dns_message_settsigkey(msg, key);
332 	assert_int_equal(result, ISC_R_SUCCESS);
333 
334 	result = dns_message_parse(msg, buf, 0);
335 	assert_int_equal(result, ISC_R_SUCCESS);
336 
337 	printmessage(msg);
338 
339 	result = dns_message_setquerytsig(msg, querytsig);
340 	assert_int_equal(result, ISC_R_SUCCESS);
341 
342 	result = dns_tsig_verify(buf, msg, NULL, NULL);
343 	assert_int_equal(result, ISC_R_SUCCESS);
344 	assert_int_equal(msg->verified_sig, 1);
345 	assert_int_equal(msg->tsigstatus, dns_rcode_noerror);
346 
347 	/*
348 	 * Check that we have a TSIG in the first message.
349 	 */
350 	assert_non_null(dns_message_gettsig(msg, &tsigowner));
351 
352 	result = dns_message_getquerytsig(msg, dt_mctx, &tsigin);
353 	assert_int_equal(result, ISC_R_SUCCESS);
354 
355 	tsigctx = msg->tsigctx;
356 	msg->tsigctx = NULL;
357 	isc_buffer_free(&buf);
358 	dns_message_detach(&msg);
359 
360 	result = dst_context_create(key->key, dt_mctx, DNS_LOGCATEGORY_DNSSEC,
361 				    false, 0, &outctx);
362 	assert_int_equal(result, ISC_R_SUCCESS);
363 	assert_non_null(outctx);
364 
365 	/*
366 	 * Start digesting.
367 	 */
368 	result = add_mac(outctx, tsigout);
369 	assert_int_equal(result, ISC_R_SUCCESS);
370 
371 	/*
372 	 * Create response message 2.
373 	 */
374 	isc_buffer_allocate(dt_mctx, &buf, 65535);
375 
376 	assert_int_equal(result, ISC_R_SUCCESS);
377 	render(buf, DNS_MESSAGEFLAG_QR, key, &tsigout, &tsigout, outctx);
378 
379 	/*
380 	 * Process response message 2.
381 	 */
382 	dns_message_create(dt_mctx, DNS_MESSAGE_INTENTPARSE, &msg);
383 	assert_non_null(msg);
384 
385 	msg->tcp_continuation = 1;
386 	msg->tsigctx = tsigctx;
387 	tsigctx = NULL;
388 
389 	result = dns_message_settsigkey(msg, key);
390 	assert_int_equal(result, ISC_R_SUCCESS);
391 
392 	result = dns_message_parse(msg, buf, 0);
393 	assert_int_equal(result, ISC_R_SUCCESS);
394 
395 	printmessage(msg);
396 
397 	result = dns_message_setquerytsig(msg, tsigin);
398 	assert_int_equal(result, ISC_R_SUCCESS);
399 
400 	result = dns_tsig_verify(buf, msg, NULL, NULL);
401 	assert_int_equal(result, ISC_R_SUCCESS);
402 	assert_int_equal(msg->verified_sig, 0);
403 	assert_int_equal(msg->tsigstatus, dns_rcode_noerror);
404 
405 	/*
406 	 * Check that we don't have a TSIG in the second message.
407 	 */
408 	tsigowner = NULL;
409 	assert_true(dns_message_gettsig(msg, &tsigowner) == NULL);
410 
411 	tsigctx = msg->tsigctx;
412 	msg->tsigctx = NULL;
413 	isc_buffer_free(&buf);
414 	dns_message_detach(&msg);
415 
416 	/*
417 	 * Create response message 3.
418 	 */
419 	isc_buffer_allocate(dt_mctx, &buf, 65535);
420 	render(buf, DNS_MESSAGEFLAG_QR, key, &tsigout, &tsigout, outctx);
421 
422 	result = add_tsig(outctx, key, buf);
423 	assert_int_equal(result, ISC_R_SUCCESS);
424 
425 	/*
426 	 * Process response message 3.
427 	 */
428 	dns_message_create(dt_mctx, DNS_MESSAGE_INTENTPARSE, &msg);
429 	assert_non_null(msg);
430 
431 	msg->tcp_continuation = 1;
432 	msg->tsigctx = tsigctx;
433 	tsigctx = NULL;
434 
435 	result = dns_message_settsigkey(msg, key);
436 	assert_int_equal(result, ISC_R_SUCCESS);
437 
438 	result = dns_message_parse(msg, buf, 0);
439 	assert_int_equal(result, ISC_R_SUCCESS);
440 
441 	printmessage(msg);
442 
443 	/*
444 	 * Check that we had a TSIG in the third message.
445 	 */
446 	assert_non_null(dns_message_gettsig(msg, &tsigowner));
447 
448 	result = dns_message_setquerytsig(msg, tsigin);
449 	assert_int_equal(result, ISC_R_SUCCESS);
450 
451 	result = dns_tsig_verify(buf, msg, NULL, NULL);
452 	assert_int_equal(result, ISC_R_SUCCESS);
453 	assert_int_equal(msg->verified_sig, 1);
454 	assert_int_equal(msg->tsigstatus, dns_rcode_noerror);
455 
456 	if (tsigin != NULL) {
457 		isc_buffer_free(&tsigin);
458 	}
459 
460 	result = dns_message_getquerytsig(msg, dt_mctx, &tsigin);
461 	assert_int_equal(result, ISC_R_SUCCESS);
462 
463 	isc_buffer_free(&buf);
464 	dns_message_detach(&msg);
465 
466 	if (outctx != NULL) {
467 		dst_context_destroy(&outctx);
468 	}
469 	if (querytsig != NULL) {
470 		isc_buffer_free(&querytsig);
471 	}
472 	if (tsigin != NULL) {
473 		isc_buffer_free(&tsigin);
474 	}
475 	if (tsigout != NULL) {
476 		isc_buffer_free(&tsigout);
477 	}
478 	dns_tsigkey_detach(&key);
479 	if (ring != NULL) {
480 		dns_tsigkeyring_detach(&ring);
481 	}
482 }
483 
484 /* Tests the dns__tsig_algvalid function */
485 static void
algvalid_test(void ** state)486 algvalid_test(void **state) {
487 	UNUSED(state);
488 
489 	assert_true(dns__tsig_algvalid(DST_ALG_HMACMD5));
490 
491 	assert_true(dns__tsig_algvalid(DST_ALG_HMACSHA1));
492 	assert_true(dns__tsig_algvalid(DST_ALG_HMACSHA224));
493 	assert_true(dns__tsig_algvalid(DST_ALG_HMACSHA256));
494 	assert_true(dns__tsig_algvalid(DST_ALG_HMACSHA384));
495 	assert_true(dns__tsig_algvalid(DST_ALG_HMACSHA512));
496 
497 	assert_false(dns__tsig_algvalid(DST_ALG_GSSAPI));
498 }
499 
500 /* Tests the dns__tsig_algfromname function */
501 static void
algfromname_test(void ** state)502 algfromname_test(void **state) {
503 	UNUSED(state);
504 
505 	assert_int_equal(dns__tsig_algfromname(DNS_TSIG_HMACMD5_NAME),
506 			 DST_ALG_HMACMD5);
507 	assert_int_equal(dns__tsig_algfromname(DNS_TSIG_HMACSHA1_NAME),
508 			 DST_ALG_HMACSHA1);
509 	assert_int_equal(dns__tsig_algfromname(DNS_TSIG_HMACSHA224_NAME),
510 			 DST_ALG_HMACSHA224);
511 	assert_int_equal(dns__tsig_algfromname(DNS_TSIG_HMACSHA256_NAME),
512 			 DST_ALG_HMACSHA256);
513 	assert_int_equal(dns__tsig_algfromname(DNS_TSIG_HMACSHA384_NAME),
514 			 DST_ALG_HMACSHA384);
515 	assert_int_equal(dns__tsig_algfromname(DNS_TSIG_HMACSHA512_NAME),
516 			 DST_ALG_HMACSHA512);
517 
518 	assert_int_equal(dns__tsig_algfromname(DNS_TSIG_GSSAPI_NAME),
519 			 DST_ALG_GSSAPI);
520 	assert_int_equal(dns__tsig_algfromname(DNS_TSIG_GSSAPIMS_NAME),
521 			 DST_ALG_GSSAPI);
522 
523 	assert_int_equal(dns__tsig_algfromname(dns_rootname), 0);
524 }
525 
526 /* Tests the dns__tsig_algnamefromname function */
527 
528 /*
529  * Helper function to create a dns_name_t from a string and see if
530  * the dns__tsig_algnamefromname function can correctly match it against the
531  * static table of known algorithms.
532  */
533 static void
test_name(const char * name_string,const dns_name_t * expected)534 test_name(const char *name_string, const dns_name_t *expected) {
535 	dns_name_t name;
536 	dns_name_init(&name, NULL);
537 	assert_int_equal(dns_name_fromstring(&name, name_string, 0, dt_mctx),
538 			 ISC_R_SUCCESS);
539 	assert_ptr_equal(dns__tsig_algnamefromname(&name), expected);
540 	dns_name_free(&name, dt_mctx);
541 }
542 
543 static void
algnamefromname_test(void ** state)544 algnamefromname_test(void **state) {
545 	UNUSED(state);
546 
547 	/* test the standard algorithms */
548 	test_name("hmac-md5.sig-alg.reg.int", DNS_TSIG_HMACMD5_NAME);
549 	test_name("hmac-sha1", DNS_TSIG_HMACSHA1_NAME);
550 	test_name("hmac-sha224", DNS_TSIG_HMACSHA224_NAME);
551 	test_name("hmac-sha256", DNS_TSIG_HMACSHA256_NAME);
552 	test_name("hmac-sha384", DNS_TSIG_HMACSHA384_NAME);
553 	test_name("hmac-sha512", DNS_TSIG_HMACSHA512_NAME);
554 
555 	test_name("gss-tsig", DNS_TSIG_GSSAPI_NAME);
556 	test_name("gss.microsoft.com", DNS_TSIG_GSSAPIMS_NAME);
557 
558 	/* try another name that isn't a standard algorithm name */
559 	assert_null(dns__tsig_algnamefromname(dns_rootname));
560 }
561 
562 /* Tests the dns__tsig_algallocated function */
563 static void
algallocated_test(void ** state)564 algallocated_test(void **state) {
565 	UNUSED(state);
566 
567 	/* test the standard algorithms */
568 	assert_false(dns__tsig_algallocated(DNS_TSIG_HMACMD5_NAME));
569 	assert_false(dns__tsig_algallocated(DNS_TSIG_HMACSHA1_NAME));
570 	assert_false(dns__tsig_algallocated(DNS_TSIG_HMACSHA224_NAME));
571 	assert_false(dns__tsig_algallocated(DNS_TSIG_HMACSHA256_NAME));
572 	assert_false(dns__tsig_algallocated(DNS_TSIG_HMACSHA384_NAME));
573 	assert_false(dns__tsig_algallocated(DNS_TSIG_HMACSHA512_NAME));
574 
575 	assert_false(dns__tsig_algallocated(DNS_TSIG_HMACSHA512_NAME));
576 	assert_false(dns__tsig_algallocated(DNS_TSIG_HMACSHA512_NAME));
577 
578 	/* try another name that isn't a standard algorithm name */
579 	assert_true(dns__tsig_algallocated(dns_rootname));
580 }
581 
582 int
main(void)583 main(void) {
584 	const struct CMUnitTest tests[] = {
585 		cmocka_unit_test_setup_teardown(tsig_tcp_test, _setup,
586 						_teardown),
587 		cmocka_unit_test(algvalid_test),
588 		cmocka_unit_test(algfromname_test),
589 		cmocka_unit_test_setup_teardown(algnamefromname_test, _setup,
590 						_teardown),
591 		cmocka_unit_test(algallocated_test),
592 	};
593 
594 	return (cmocka_run_group_tests(tests, NULL, NULL));
595 }
596 
597 #else /* HAVE_CMOCKA */
598 
599 #include <stdio.h>
600 
601 int
main(void)602 main(void) {
603 	printf("1..0 # Skipped: cmocka not available\n");
604 	return (SKIPPED_TEST_EXIT_CODE);
605 }
606 
607 #endif /* if HAVE_CMOCKA */
608