xref: /freebsd/usr.sbin/ctld/parse.y (revision 3fe8969a749c0e4a62ffdbf4f6883898027a9e19)
1 %{
2 /*-
3  * Copyright (c) 2012 The FreeBSD Foundation
4  * All rights reserved.
5  *
6  * This software was developed by Edward Tomasz Napierala under sponsorship
7  * from the FreeBSD Foundation.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  * $FreeBSD$
31  */
32 
33 #include <sys/queue.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <assert.h>
37 #include <stdio.h>
38 #include <stdint.h>
39 #include <stdlib.h>
40 #include <string.h>
41 
42 #include "ctld.h"
43 
44 extern FILE *yyin;
45 extern char *yytext;
46 extern int lineno;
47 
48 static struct conf *conf = NULL;
49 static struct auth_group *auth_group = NULL;
50 static struct portal_group *portal_group = NULL;
51 static struct target *target = NULL;
52 static struct lun *lun = NULL;
53 
54 extern void	yyerror(const char *);
55 extern int	yylex(void);
56 extern void	yyrestart(FILE *);
57 
58 %}
59 
60 %token ALIAS AUTH_GROUP AUTH_TYPE BACKEND BLOCKSIZE CHAP CHAP_MUTUAL
61 %token CLOSING_BRACKET DEBUG DEVICE_ID DISCOVERY_AUTH_GROUP DISCOVERY_FILTER
62 %token INITIATOR_NAME INITIATOR_PORTAL ISNS_SERVER ISNS_PERIOD ISNS_TIMEOUT
63 %token LISTEN LISTEN_ISER LUN MAXPROC OPENING_BRACKET OPTION
64 %token PATH PIDFILE PORTAL_GROUP SEMICOLON SERIAL SIZE STR TARGET TIMEOUT
65 
66 %union
67 {
68 	char *str;
69 }
70 
71 %token <str> STR
72 
73 %%
74 
75 statements:
76 	|
77 	statements statement
78 	|
79 	statements statement SEMICOLON
80 	;
81 
82 statement:
83 	debug
84 	|
85 	timeout
86 	|
87 	maxproc
88 	|
89 	pidfile
90 	|
91 	isns_server
92 	|
93 	isns_period
94 	|
95 	isns_timeout
96 	|
97 	auth_group
98 	|
99 	portal_group
100 	|
101 	target
102 	;
103 
104 debug:		DEBUG STR
105 	{
106 		uint64_t tmp;
107 
108 		if (expand_number($2, &tmp) != 0) {
109 			yyerror("invalid numeric value");
110 			free($2);
111 			return (1);
112 		}
113 
114 		conf->conf_debug = tmp;
115 	}
116 	;
117 
118 timeout:	TIMEOUT STR
119 	{
120 		uint64_t tmp;
121 
122 		if (expand_number($2, &tmp) != 0) {
123 			yyerror("invalid numeric value");
124 			free($2);
125 			return (1);
126 		}
127 
128 		conf->conf_timeout = tmp;
129 	}
130 	;
131 
132 maxproc:	MAXPROC STR
133 	{
134 		uint64_t tmp;
135 
136 		if (expand_number($2, &tmp) != 0) {
137 			yyerror("invalid numeric value");
138 			free($2);
139 			return (1);
140 		}
141 
142 		conf->conf_maxproc = tmp;
143 	}
144 	;
145 
146 pidfile:	PIDFILE STR
147 	{
148 		if (conf->conf_pidfile_path != NULL) {
149 			log_warnx("pidfile specified more than once");
150 			free($2);
151 			return (1);
152 		}
153 		conf->conf_pidfile_path = $2;
154 	}
155 	;
156 
157 isns_server:	ISNS_SERVER STR
158 	{
159 		int error;
160 
161 		error = isns_new(conf, $2);
162 		free($2);
163 		if (error != 0)
164 			return (1);
165 	}
166 	;
167 
168 isns_period:	ISNS_PERIOD STR
169 	{
170 		uint64_t tmp;
171 
172 		if (expand_number($2, &tmp) != 0) {
173 			yyerror("invalid numeric value");
174 			free($2);
175 			return (1);
176 		}
177 
178 		conf->conf_isns_period = tmp;
179 	}
180 	;
181 
182 isns_timeout:	ISNS_TIMEOUT STR
183 	{
184 		uint64_t tmp;
185 
186 		if (expand_number($2, &tmp) != 0) {
187 			yyerror("invalid numeric value");
188 			free($2);
189 			return (1);
190 		}
191 
192 		conf->conf_isns_timeout = tmp;
193 	}
194 	;
195 
196 auth_group:	AUTH_GROUP auth_group_name
197     OPENING_BRACKET auth_group_entries CLOSING_BRACKET
198 	{
199 		auth_group = NULL;
200 	}
201 	;
202 
203 auth_group_name:	STR
204 	{
205 		/*
206 		 * Make it possible to redefine default
207 		 * auth-group. but only once.
208 		 */
209 		if (strcmp($1, "default") == 0 &&
210 		    conf->conf_default_ag_defined == false) {
211 			auth_group = auth_group_find(conf, $1);
212 			conf->conf_default_ag_defined = true;
213 		} else {
214 			auth_group = auth_group_new(conf, $1);
215 		}
216 		free($1);
217 		if (auth_group == NULL)
218 			return (1);
219 	}
220 	;
221 
222 auth_group_entries:
223 	|
224 	auth_group_entries auth_group_entry
225 	|
226 	auth_group_entries auth_group_entry SEMICOLON
227 	;
228 
229 auth_group_entry:
230 	auth_group_auth_type
231 	|
232 	auth_group_chap
233 	|
234 	auth_group_chap_mutual
235 	|
236 	auth_group_initiator_name
237 	|
238 	auth_group_initiator_portal
239 	;
240 
241 auth_group_auth_type:	AUTH_TYPE STR
242 	{
243 		int error;
244 
245 		error = auth_group_set_type(auth_group, $2);
246 		free($2);
247 		if (error != 0)
248 			return (1);
249 	}
250 	;
251 
252 auth_group_chap:	CHAP STR STR
253 	{
254 		const struct auth *ca;
255 
256 		ca = auth_new_chap(auth_group, $2, $3);
257 		free($2);
258 		free($3);
259 		if (ca == NULL)
260 			return (1);
261 	}
262 	;
263 
264 auth_group_chap_mutual:	CHAP_MUTUAL STR STR STR STR
265 	{
266 		const struct auth *ca;
267 
268 		ca = auth_new_chap_mutual(auth_group, $2, $3, $4, $5);
269 		free($2);
270 		free($3);
271 		free($4);
272 		free($5);
273 		if (ca == NULL)
274 			return (1);
275 	}
276 	;
277 
278 auth_group_initiator_name:	INITIATOR_NAME STR
279 	{
280 		const struct auth_name *an;
281 
282 		an = auth_name_new(auth_group, $2);
283 		free($2);
284 		if (an == NULL)
285 			return (1);
286 	}
287 	;
288 
289 auth_group_initiator_portal:	INITIATOR_PORTAL STR
290 	{
291 		const struct auth_portal *ap;
292 
293 		ap = auth_portal_new(auth_group, $2);
294 		free($2);
295 		if (ap == NULL)
296 			return (1);
297 	}
298 	;
299 
300 portal_group:	PORTAL_GROUP portal_group_name
301     OPENING_BRACKET portal_group_entries CLOSING_BRACKET
302 	{
303 		portal_group = NULL;
304 	}
305 	;
306 
307 portal_group_name:	STR
308 	{
309 		/*
310 		 * Make it possible to redefine default
311 		 * portal-group. but only once.
312 		 */
313 		if (strcmp($1, "default") == 0 &&
314 		    conf->conf_default_pg_defined == false) {
315 			portal_group = portal_group_find(conf, $1);
316 			conf->conf_default_pg_defined = true;
317 		} else {
318 			portal_group = portal_group_new(conf, $1);
319 		}
320 		free($1);
321 		if (portal_group == NULL)
322 			return (1);
323 	}
324 	;
325 
326 portal_group_entries:
327 	|
328 	portal_group_entries portal_group_entry
329 	|
330 	portal_group_entries portal_group_entry SEMICOLON
331 	;
332 
333 portal_group_entry:
334 	portal_group_discovery_auth_group
335 	|
336 	portal_group_discovery_filter
337 	|
338 	portal_group_listen
339 	|
340 	portal_group_listen_iser
341 	;
342 
343 portal_group_discovery_auth_group:	DISCOVERY_AUTH_GROUP STR
344 	{
345 		if (portal_group->pg_discovery_auth_group != NULL) {
346 			log_warnx("discovery-auth-group for portal-group "
347 			    "\"%s\" specified more than once",
348 			    portal_group->pg_name);
349 			return (1);
350 		}
351 		portal_group->pg_discovery_auth_group =
352 		    auth_group_find(conf, $2);
353 		if (portal_group->pg_discovery_auth_group == NULL) {
354 			log_warnx("unknown discovery-auth-group \"%s\" "
355 			    "for portal-group \"%s\"",
356 			    $2, portal_group->pg_name);
357 			return (1);
358 		}
359 		free($2);
360 	}
361 	;
362 
363 portal_group_discovery_filter:	DISCOVERY_FILTER STR
364 	{
365 		int error;
366 
367 		error = portal_group_set_filter(portal_group, $2);
368 		free($2);
369 		if (error != 0)
370 			return (1);
371 	}
372 	;
373 
374 portal_group_listen:	LISTEN STR
375 	{
376 		int error;
377 
378 		error = portal_group_add_listen(portal_group, $2, false);
379 		free($2);
380 		if (error != 0)
381 			return (1);
382 	}
383 	;
384 
385 portal_group_listen_iser:	LISTEN_ISER STR
386 	{
387 		int error;
388 
389 		error = portal_group_add_listen(portal_group, $2, true);
390 		free($2);
391 		if (error != 0)
392 			return (1);
393 	}
394 	;
395 
396 target:	TARGET target_name
397     OPENING_BRACKET target_entries CLOSING_BRACKET
398 	{
399 		target = NULL;
400 	}
401 	;
402 
403 target_name:	STR
404 	{
405 		target = target_new(conf, $1);
406 		free($1);
407 		if (target == NULL)
408 			return (1);
409 	}
410 	;
411 
412 target_entries:
413 	|
414 	target_entries target_entry
415 	|
416 	target_entries target_entry SEMICOLON
417 	;
418 
419 target_entry:
420 	target_alias
421 	|
422 	target_auth_group
423 	|
424 	target_auth_type
425 	|
426 	target_chap
427 	|
428 	target_chap_mutual
429 	|
430 	target_initiator_name
431 	|
432 	target_initiator_portal
433 	|
434 	target_portal_group
435 	|
436 	target_lun
437 	;
438 
439 target_alias:	ALIAS STR
440 	{
441 		if (target->t_alias != NULL) {
442 			log_warnx("alias for target \"%s\" "
443 			    "specified more than once", target->t_name);
444 			return (1);
445 		}
446 		target->t_alias = $2;
447 	}
448 	;
449 
450 target_auth_group:	AUTH_GROUP STR
451 	{
452 		if (target->t_auth_group != NULL) {
453 			if (target->t_auth_group->ag_name != NULL)
454 				log_warnx("auth-group for target \"%s\" "
455 				    "specified more than once", target->t_name);
456 			else
457 				log_warnx("cannot use both auth-group and explicit "
458 				    "authorisations for target \"%s\"",
459 				    target->t_name);
460 			return (1);
461 		}
462 		target->t_auth_group = auth_group_find(conf, $2);
463 		if (target->t_auth_group == NULL) {
464 			log_warnx("unknown auth-group \"%s\" for target "
465 			    "\"%s\"", $2, target->t_name);
466 			return (1);
467 		}
468 		free($2);
469 	}
470 	;
471 
472 target_auth_type:	AUTH_TYPE STR
473 	{
474 		int error;
475 
476 		if (target->t_auth_group != NULL) {
477 			if (target->t_auth_group->ag_name != NULL) {
478 				log_warnx("cannot use both auth-group and "
479 				    "auth-type for target \"%s\"",
480 				    target->t_name);
481 				return (1);
482 			}
483 		} else {
484 			target->t_auth_group = auth_group_new(conf, NULL);
485 			if (target->t_auth_group == NULL) {
486 				free($2);
487 				return (1);
488 			}
489 			target->t_auth_group->ag_target = target;
490 		}
491 		error = auth_group_set_type(target->t_auth_group, $2);
492 		free($2);
493 		if (error != 0)
494 			return (1);
495 	}
496 	;
497 
498 target_chap:	CHAP STR STR
499 	{
500 		const struct auth *ca;
501 
502 		if (target->t_auth_group != NULL) {
503 			if (target->t_auth_group->ag_name != NULL) {
504 				log_warnx("cannot use both auth-group and "
505 				    "chap for target \"%s\"",
506 				    target->t_name);
507 				free($2);
508 				free($3);
509 				return (1);
510 			}
511 		} else {
512 			target->t_auth_group = auth_group_new(conf, NULL);
513 			if (target->t_auth_group == NULL) {
514 				free($2);
515 				free($3);
516 				return (1);
517 			}
518 			target->t_auth_group->ag_target = target;
519 		}
520 		ca = auth_new_chap(target->t_auth_group, $2, $3);
521 		free($2);
522 		free($3);
523 		if (ca == NULL)
524 			return (1);
525 	}
526 	;
527 
528 target_chap_mutual:	CHAP_MUTUAL STR STR STR STR
529 	{
530 		const struct auth *ca;
531 
532 		if (target->t_auth_group != NULL) {
533 			if (target->t_auth_group->ag_name != NULL) {
534 				log_warnx("cannot use both auth-group and "
535 				    "chap-mutual for target \"%s\"",
536 				    target->t_name);
537 				free($2);
538 				free($3);
539 				free($4);
540 				free($5);
541 				return (1);
542 			}
543 		} else {
544 			target->t_auth_group = auth_group_new(conf, NULL);
545 			if (target->t_auth_group == NULL) {
546 				free($2);
547 				free($3);
548 				free($4);
549 				free($5);
550 				return (1);
551 			}
552 			target->t_auth_group->ag_target = target;
553 		}
554 		ca = auth_new_chap_mutual(target->t_auth_group,
555 		    $2, $3, $4, $5);
556 		free($2);
557 		free($3);
558 		free($4);
559 		free($5);
560 		if (ca == NULL)
561 			return (1);
562 	}
563 	;
564 
565 target_initiator_name:	INITIATOR_NAME STR
566 	{
567 		const struct auth_name *an;
568 
569 		if (target->t_auth_group != NULL) {
570 			if (target->t_auth_group->ag_name != NULL) {
571 				log_warnx("cannot use both auth-group and "
572 				    "initiator-name for target \"%s\"",
573 				    target->t_name);
574 				free($2);
575 				return (1);
576 			}
577 		} else {
578 			target->t_auth_group = auth_group_new(conf, NULL);
579 			if (target->t_auth_group == NULL) {
580 				free($2);
581 				return (1);
582 			}
583 			target->t_auth_group->ag_target = target;
584 		}
585 		an = auth_name_new(target->t_auth_group, $2);
586 		free($2);
587 		if (an == NULL)
588 			return (1);
589 	}
590 	;
591 
592 target_initiator_portal:	INITIATOR_PORTAL STR
593 	{
594 		const struct auth_portal *ap;
595 
596 		if (target->t_auth_group != NULL) {
597 			if (target->t_auth_group->ag_name != NULL) {
598 				log_warnx("cannot use both auth-group and "
599 				    "initiator-portal for target \"%s\"",
600 				    target->t_name);
601 				free($2);
602 				return (1);
603 			}
604 		} else {
605 			target->t_auth_group = auth_group_new(conf, NULL);
606 			if (target->t_auth_group == NULL) {
607 				free($2);
608 				return (1);
609 			}
610 			target->t_auth_group->ag_target = target;
611 		}
612 		ap = auth_portal_new(target->t_auth_group, $2);
613 		free($2);
614 		if (ap == NULL)
615 			return (1);
616 	}
617 	;
618 
619 target_portal_group:	PORTAL_GROUP STR
620 	{
621 		if (target->t_portal_group != NULL) {
622 			log_warnx("portal-group for target \"%s\" "
623 			    "specified more than once", target->t_name);
624 			free($2);
625 			return (1);
626 		}
627 		target->t_portal_group = portal_group_find(conf, $2);
628 		if (target->t_portal_group == NULL) {
629 			log_warnx("unknown portal-group \"%s\" for target "
630 			    "\"%s\"", $2, target->t_name);
631 			free($2);
632 			return (1);
633 		}
634 		free($2);
635 	}
636 	;
637 
638 target_lun:	LUN lun_number
639     OPENING_BRACKET lun_entries CLOSING_BRACKET
640 	{
641 		lun = NULL;
642 	}
643 	;
644 
645 lun_number:	STR
646 	{
647 		uint64_t tmp;
648 
649 		if (expand_number($1, &tmp) != 0) {
650 			yyerror("invalid numeric value");
651 			free($1);
652 			return (1);
653 		}
654 
655 		lun = lun_new(target, tmp);
656 		if (lun == NULL)
657 			return (1);
658 	}
659 	;
660 
661 lun_entries:
662 	|
663 	lun_entries lun_entry
664 	|
665 	lun_entries lun_entry SEMICOLON
666 	;
667 
668 lun_entry:
669 	lun_backend
670 	|
671 	lun_blocksize
672 	|
673 	lun_device_id
674 	|
675 	lun_option
676 	|
677 	lun_path
678 	|
679 	lun_serial
680 	|
681 	lun_size
682 	;
683 
684 lun_backend:	BACKEND STR
685 	{
686 		if (lun->l_backend != NULL) {
687 			log_warnx("backend for lun %d, target \"%s\" "
688 			    "specified more than once",
689 			    lun->l_lun, target->t_name);
690 			free($2);
691 			return (1);
692 		}
693 		lun_set_backend(lun, $2);
694 		free($2);
695 	}
696 	;
697 
698 lun_blocksize:	BLOCKSIZE STR
699 	{
700 		uint64_t tmp;
701 
702 		if (expand_number($2, &tmp) != 0) {
703 			yyerror("invalid numeric value");
704 			free($2);
705 			return (1);
706 		}
707 
708 		if (lun->l_blocksize != 0) {
709 			log_warnx("blocksize for lun %d, target \"%s\" "
710 			    "specified more than once",
711 			    lun->l_lun, target->t_name);
712 			return (1);
713 		}
714 		lun_set_blocksize(lun, tmp);
715 	}
716 	;
717 
718 lun_device_id:	DEVICE_ID STR
719 	{
720 		if (lun->l_device_id != NULL) {
721 			log_warnx("device_id for lun %d, target \"%s\" "
722 			    "specified more than once",
723 			    lun->l_lun, target->t_name);
724 			free($2);
725 			return (1);
726 		}
727 		lun_set_device_id(lun, $2);
728 		free($2);
729 	}
730 	;
731 
732 lun_option:	OPTION STR STR
733 	{
734 		struct lun_option *clo;
735 
736 		clo = lun_option_new(lun, $2, $3);
737 		free($2);
738 		free($3);
739 		if (clo == NULL)
740 			return (1);
741 	}
742 	;
743 
744 lun_path:	PATH STR
745 	{
746 		if (lun->l_path != NULL) {
747 			log_warnx("path for lun %d, target \"%s\" "
748 			    "specified more than once",
749 			    lun->l_lun, target->t_name);
750 			free($2);
751 			return (1);
752 		}
753 		lun_set_path(lun, $2);
754 		free($2);
755 	}
756 	;
757 
758 lun_serial:	SERIAL STR
759 	{
760 		if (lun->l_serial != NULL) {
761 			log_warnx("serial for lun %d, target \"%s\" "
762 			    "specified more than once",
763 			    lun->l_lun, target->t_name);
764 			free($2);
765 			return (1);
766 		}
767 		lun_set_serial(lun, $2);
768 		free($2);
769 	}
770 	;
771 
772 lun_size:	SIZE STR
773 	{
774 		uint64_t tmp;
775 
776 		if (expand_number($2, &tmp) != 0) {
777 			yyerror("invalid numeric value");
778 			free($2);
779 			return (1);
780 		}
781 
782 		if (lun->l_size != 0) {
783 			log_warnx("size for lun %d, target \"%s\" "
784 			    "specified more than once",
785 			    lun->l_lun, target->t_name);
786 			return (1);
787 		}
788 		lun_set_size(lun, tmp);
789 	}
790 	;
791 %%
792 
793 void
794 yyerror(const char *str)
795 {
796 
797 	log_warnx("error in configuration file at line %d near '%s': %s",
798 	    lineno, yytext, str);
799 }
800 
801 static void
802 check_perms(const char *path)
803 {
804 	struct stat sb;
805 	int error;
806 
807 	error = stat(path, &sb);
808 	if (error != 0) {
809 		log_warn("stat");
810 		return;
811 	}
812 	if (sb.st_mode & S_IWOTH) {
813 		log_warnx("%s is world-writable", path);
814 	} else if (sb.st_mode & S_IROTH) {
815 		log_warnx("%s is world-readable", path);
816 	} else if (sb.st_mode & S_IXOTH) {
817 		/*
818 		 * Ok, this one doesn't matter, but still do it,
819 		 * just for consistency.
820 		 */
821 		log_warnx("%s is world-executable", path);
822 	}
823 
824 	/*
825 	 * XXX: Should we also check for owner != 0?
826 	 */
827 }
828 
829 struct conf *
830 conf_new_from_file(const char *path)
831 {
832 	struct auth_group *ag;
833 	struct portal_group *pg;
834 	int error;
835 
836 	log_debugx("obtaining configuration from %s", path);
837 
838 	conf = conf_new();
839 
840 	ag = auth_group_new(conf, "default");
841 	assert(ag != NULL);
842 
843 	ag = auth_group_new(conf, "no-authentication");
844 	assert(ag != NULL);
845 	ag->ag_type = AG_TYPE_NO_AUTHENTICATION;
846 
847 	ag = auth_group_new(conf, "no-access");
848 	assert(ag != NULL);
849 	ag->ag_type = AG_TYPE_DENY;
850 
851 	pg = portal_group_new(conf, "default");
852 	assert(pg != NULL);
853 
854 	yyin = fopen(path, "r");
855 	if (yyin == NULL) {
856 		log_warn("unable to open configuration file %s", path);
857 		conf_delete(conf);
858 		return (NULL);
859 	}
860 	check_perms(path);
861 	lineno = 1;
862 	yyrestart(yyin);
863 	error = yyparse();
864 	auth_group = NULL;
865 	portal_group = NULL;
866 	target = NULL;
867 	lun = NULL;
868 	fclose(yyin);
869 	if (error != 0) {
870 		conf_delete(conf);
871 		return (NULL);
872 	}
873 
874 	if (conf->conf_default_ag_defined == false) {
875 		log_debugx("auth-group \"default\" not defined; "
876 		    "going with defaults");
877 		ag = auth_group_find(conf, "default");
878 		assert(ag != NULL);
879 		ag->ag_type = AG_TYPE_DENY;
880 	}
881 
882 	if (conf->conf_default_pg_defined == false) {
883 		log_debugx("portal-group \"default\" not defined; "
884 		    "going with defaults");
885 		pg = portal_group_find(conf, "default");
886 		assert(pg != NULL);
887 		portal_group_add_listen(pg, "0.0.0.0:3260", false);
888 		portal_group_add_listen(pg, "[::]:3260", false);
889 	}
890 
891 	conf->conf_kernel_port_on = true;
892 
893 	error = conf_verify(conf);
894 	if (error != 0) {
895 		conf_delete(conf);
896 		return (NULL);
897 	}
898 
899 	return (conf);
900 }
901