1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2012 The FreeBSD Foundation
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 */
31
32 #include <sys/types.h>
33 #include <assert.h>
34 #include <stddef.h>
35 #include <stdint.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <stdbool.h>
39 #include <string.h>
40 #include <cam/scsi/scsi_all.h>
41
42 #include "conf.h"
43 #include "ctld.h"
44
45 static struct conf *conf = NULL;
46 static struct auth_group *auth_group = NULL;
47 static struct portal_group *portal_group = NULL;
48 static struct target *target = NULL;
49 static struct lun *lun = NULL;
50
51 void
conf_start(struct conf * new_conf)52 conf_start(struct conf *new_conf)
53 {
54 assert(conf == NULL);
55 conf = new_conf;
56 }
57
58 void
conf_finish(void)59 conf_finish(void)
60 {
61 auth_group = NULL;
62 portal_group = NULL;
63 target = NULL;
64 lun = NULL;
65 conf = NULL;
66 }
67
68 bool
isns_add_server(const char * addr)69 isns_add_server(const char *addr)
70 {
71 return (isns_new(conf, addr));
72 }
73
74 void
conf_set_debug(int debug)75 conf_set_debug(int debug)
76 {
77 conf->conf_debug = debug;
78 }
79
80 void
conf_set_isns_period(int period)81 conf_set_isns_period(int period)
82 {
83 conf->conf_isns_period = period;
84 }
85
86 void
conf_set_isns_timeout(int timeout)87 conf_set_isns_timeout(int timeout)
88 {
89 conf->conf_isns_timeout = timeout;
90 }
91
92 void
conf_set_maxproc(int maxproc)93 conf_set_maxproc(int maxproc)
94 {
95 conf->conf_maxproc = maxproc;
96 }
97
98 bool
conf_set_pidfile_path(const char * path)99 conf_set_pidfile_path(const char *path)
100 {
101 if (conf->conf_pidfile_path != NULL) {
102 log_warnx("pidfile specified more than once");
103 return (false);
104 }
105 conf->conf_pidfile_path = checked_strdup(path);
106 return (true);
107 }
108
109 void
conf_set_timeout(int timeout)110 conf_set_timeout(int timeout)
111 {
112 conf->conf_timeout = timeout;
113 }
114
115 static bool
_auth_group_set_type(struct auth_group * ag,const char * str)116 _auth_group_set_type(struct auth_group *ag, const char *str)
117 {
118 int type;
119
120 if (strcmp(str, "none") == 0) {
121 type = AG_TYPE_NO_AUTHENTICATION;
122 } else if (strcmp(str, "deny") == 0) {
123 type = AG_TYPE_DENY;
124 } else if (strcmp(str, "chap") == 0) {
125 type = AG_TYPE_CHAP;
126 } else if (strcmp(str, "chap-mutual") == 0) {
127 type = AG_TYPE_CHAP_MUTUAL;
128 } else {
129 log_warnx("invalid auth-type \"%s\" for %s", str, ag->ag_label);
130 return (false);
131 }
132
133 if (ag->ag_type != AG_TYPE_UNKNOWN && ag->ag_type != type) {
134 log_warnx("cannot set auth-type to \"%s\" for %s; "
135 "already has a different type", str, ag->ag_label);
136 return (false);
137 }
138
139 ag->ag_type = type;
140
141 return (true);
142 }
143
144 bool
auth_group_add_chap(const char * user,const char * secret)145 auth_group_add_chap(const char *user, const char *secret)
146 {
147 return (auth_new_chap(auth_group, user, secret));
148 }
149
150 bool
auth_group_add_chap_mutual(const char * user,const char * secret,const char * user2,const char * secret2)151 auth_group_add_chap_mutual(const char *user, const char *secret,
152 const char *user2, const char *secret2)
153 {
154 return (auth_new_chap_mutual(auth_group, user, secret, user2, secret2));
155 }
156
157 bool
auth_group_add_initiator_name(const char * name)158 auth_group_add_initiator_name(const char *name)
159 {
160 return (auth_name_new(auth_group, name));
161 }
162
163 bool
auth_group_add_initiator_portal(const char * portal)164 auth_group_add_initiator_portal(const char *portal)
165 {
166 return (auth_portal_new(auth_group, portal));
167 }
168
169 bool
auth_group_set_type(const char * type)170 auth_group_set_type(const char *type)
171 {
172 return (_auth_group_set_type(auth_group, type));
173 }
174
175 bool
auth_group_start(const char * name)176 auth_group_start(const char *name)
177 {
178 /*
179 * Make it possible to redefine the default auth-group. but
180 * only once.
181 */
182 if (strcmp(name, "default") == 0) {
183 if (conf->conf_default_ag_defined) {
184 log_warnx("duplicated auth-group \"default\"");
185 return (false);
186 }
187
188 conf->conf_default_ag_defined = true;
189 auth_group = auth_group_find(conf, "default");
190 return (true);
191 }
192
193 auth_group = auth_group_new(conf, name);
194 return (auth_group != NULL);
195 }
196
197 void
auth_group_finish(void)198 auth_group_finish(void)
199 {
200 auth_group = NULL;
201 }
202
203 bool
portal_group_start(const char * name)204 portal_group_start(const char *name)
205 {
206 /*
207 * Make it possible to redefine the default portal-group. but
208 * only once.
209 */
210 if (strcmp(name, "default") == 0) {
211 if (conf->conf_default_pg_defined) {
212 log_warnx("duplicated portal-group \"default\"");
213 return (false);
214 }
215
216 conf->conf_default_pg_defined = true;
217 portal_group = portal_group_find(conf, "default");
218 return (true);
219 }
220
221 portal_group = portal_group_new(conf, name);
222 return (portal_group != NULL);
223 }
224
225 void
portal_group_finish(void)226 portal_group_finish(void)
227 {
228 portal_group = NULL;
229 }
230
231 bool
portal_group_add_listen(const char * listen,bool iser)232 portal_group_add_listen(const char *listen, bool iser)
233 {
234 return (portal_group_add_portal(portal_group, listen, iser));
235 }
236
237 bool
portal_group_add_option(const char * name,const char * value)238 portal_group_add_option(const char *name, const char *value)
239 {
240 return (option_new(portal_group->pg_options, name, value));
241 }
242
243 bool
portal_group_set_discovery_auth_group(const char * name)244 portal_group_set_discovery_auth_group(const char *name)
245 {
246 if (portal_group->pg_discovery_auth_group != NULL) {
247 log_warnx("discovery-auth-group for portal-group "
248 "\"%s\" specified more than once",
249 portal_group->pg_name);
250 return (false);
251 }
252 portal_group->pg_discovery_auth_group = auth_group_find(conf, name);
253 if (portal_group->pg_discovery_auth_group == NULL) {
254 log_warnx("unknown discovery-auth-group \"%s\" "
255 "for portal-group \"%s\"", name, portal_group->pg_name);
256 return (false);
257 }
258 return (true);
259 }
260
261 bool
portal_group_set_dscp(u_int dscp)262 portal_group_set_dscp(u_int dscp)
263 {
264 if (dscp >= 0x40) {
265 log_warnx("invalid DSCP value %u for portal-group \"%s\"",
266 dscp, portal_group->pg_name);
267 return (false);
268 }
269
270 portal_group->pg_dscp = dscp;
271 return (true);
272 }
273
274 bool
portal_group_set_filter(const char * str)275 portal_group_set_filter(const char *str)
276 {
277 int filter;
278
279 if (strcmp(str, "none") == 0) {
280 filter = PG_FILTER_NONE;
281 } else if (strcmp(str, "portal") == 0) {
282 filter = PG_FILTER_PORTAL;
283 } else if (strcmp(str, "portal-name") == 0) {
284 filter = PG_FILTER_PORTAL_NAME;
285 } else if (strcmp(str, "portal-name-auth") == 0) {
286 filter = PG_FILTER_PORTAL_NAME_AUTH;
287 } else {
288 log_warnx("invalid discovery-filter \"%s\" for portal-group "
289 "\"%s\"; valid values are \"none\", \"portal\", "
290 "\"portal-name\", and \"portal-name-auth\"",
291 str, portal_group->pg_name);
292 return (false);
293 }
294
295 if (portal_group->pg_discovery_filter != PG_FILTER_UNKNOWN &&
296 portal_group->pg_discovery_filter != filter) {
297 log_warnx("cannot set discovery-filter to \"%s\" for "
298 "portal-group \"%s\"; already has a different "
299 "value", str, portal_group->pg_name);
300 return (false);
301 }
302
303 portal_group->pg_discovery_filter = filter;
304
305 return (true);
306 }
307
308 void
portal_group_set_foreign(void)309 portal_group_set_foreign(void)
310 {
311 portal_group->pg_foreign = true;
312 }
313
314 bool
portal_group_set_offload(const char * offload)315 portal_group_set_offload(const char *offload)
316 {
317
318 if (portal_group->pg_offload != NULL) {
319 log_warnx("cannot set offload to \"%s\" for "
320 "portal-group \"%s\"; already defined",
321 offload, portal_group->pg_name);
322 return (false);
323 }
324
325 portal_group->pg_offload = checked_strdup(offload);
326
327 return (true);
328 }
329
330 bool
portal_group_set_pcp(u_int pcp)331 portal_group_set_pcp(u_int pcp)
332 {
333 if (pcp > 7) {
334 log_warnx("invalid PCP value %u for portal-group \"%s\"",
335 pcp, portal_group->pg_name);
336 return (false);
337 }
338
339 portal_group->pg_pcp = pcp;
340 return (true);
341 }
342
343 bool
portal_group_set_redirection(const char * addr)344 portal_group_set_redirection(const char *addr)
345 {
346
347 if (portal_group->pg_redirection != NULL) {
348 log_warnx("cannot set redirection to \"%s\" for "
349 "portal-group \"%s\"; already defined",
350 addr, portal_group->pg_name);
351 return (false);
352 }
353
354 portal_group->pg_redirection = checked_strdup(addr);
355
356 return (true);
357 }
358
359 void
portal_group_set_tag(uint16_t tag)360 portal_group_set_tag(uint16_t tag)
361 {
362 portal_group->pg_tag = tag;
363 }
364
365 bool
lun_start(const char * name)366 lun_start(const char *name)
367 {
368 lun = lun_new(conf, name);
369 return (lun != NULL);
370 }
371
372 void
lun_finish(void)373 lun_finish(void)
374 {
375 lun = NULL;
376 }
377
378 bool
lun_add_option(const char * name,const char * value)379 lun_add_option(const char *name, const char *value)
380 {
381 return (option_new(lun->l_options, name, value));
382 }
383
384 bool
lun_set_backend(const char * value)385 lun_set_backend(const char *value)
386 {
387 if (lun->l_backend != NULL) {
388 log_warnx("backend for lun \"%s\" specified more than once",
389 lun->l_name);
390 return (false);
391 }
392
393 lun->l_backend = checked_strdup(value);
394 return (true);
395 }
396
397 bool
lun_set_blocksize(size_t value)398 lun_set_blocksize(size_t value)
399 {
400 if (lun->l_blocksize != 0) {
401 log_warnx("blocksize for lun \"%s\" specified more than once",
402 lun->l_name);
403 return (false);
404 }
405 lun->l_blocksize = value;
406 return (true);
407 }
408
409 bool
lun_set_device_type(const char * value)410 lun_set_device_type(const char *value)
411 {
412 uint64_t device_type;
413
414 if (strcasecmp(value, "disk") == 0 ||
415 strcasecmp(value, "direct") == 0)
416 device_type = T_DIRECT;
417 else if (strcasecmp(value, "processor") == 0)
418 device_type = T_PROCESSOR;
419 else if (strcasecmp(value, "cd") == 0 ||
420 strcasecmp(value, "cdrom") == 0 ||
421 strcasecmp(value, "dvd") == 0 ||
422 strcasecmp(value, "dvdrom") == 0)
423 device_type = T_CDROM;
424 else if (expand_number(value, &device_type) != 0 || device_type > 15) {
425 log_warnx("invalid device-type \"%s\" for lun \"%s\"", value,
426 lun->l_name);
427 return (false);
428 }
429
430 lun->l_device_type = device_type;
431 return (true);
432 }
433
434 bool
lun_set_device_id(const char * value)435 lun_set_device_id(const char *value)
436 {
437 if (lun->l_device_id != NULL) {
438 log_warnx("device_id for lun \"%s\" specified more than once",
439 lun->l_name);
440 return (false);
441 }
442
443 lun->l_device_id = checked_strdup(value);
444 return (true);
445 }
446
447 bool
lun_set_path(const char * value)448 lun_set_path(const char *value)
449 {
450 if (lun->l_path != NULL) {
451 log_warnx("path for lun \"%s\" specified more than once",
452 lun->l_name);
453 return (false);
454 }
455
456 lun->l_path = checked_strdup(value);
457 return (true);
458 }
459
460 bool
lun_set_serial(const char * value)461 lun_set_serial(const char *value)
462 {
463 if (lun->l_serial != NULL) {
464 log_warnx("serial for lun \"%s\" specified more than once",
465 lun->l_name);
466 return (false);
467 }
468
469 lun->l_serial = checked_strdup(value);
470 return (true);
471 }
472
473 bool
lun_set_size(uint64_t value)474 lun_set_size(uint64_t value)
475 {
476 if (lun->l_size != 0) {
477 log_warnx("size for lun \"%s\" specified more than once",
478 lun->l_name);
479 return (false);
480 }
481
482 lun->l_size = value;
483 return (true);
484 }
485
486 bool
lun_set_ctl_lun(uint32_t value)487 lun_set_ctl_lun(uint32_t value)
488 {
489
490 if (lun->l_ctl_lun >= 0) {
491 log_warnx("ctl_lun for lun \"%s\" specified more than once",
492 lun->l_name);
493 return (false);
494 }
495 lun->l_ctl_lun = value;
496 return (true);
497 }
498
499 bool
target_start(const char * name)500 target_start(const char *name)
501 {
502 target = target_new(conf, name);
503 return (target != NULL);
504 }
505
506 void
target_finish(void)507 target_finish(void)
508 {
509 target = NULL;
510 }
511
512 bool
target_add_chap(const char * user,const char * secret)513 target_add_chap(const char *user, const char *secret)
514 {
515 if (target->t_auth_group != NULL) {
516 if (target->t_auth_group->ag_name != NULL) {
517 log_warnx("cannot use both auth-group and "
518 "chap for target \"%s\"", target->t_name);
519 return (false);
520 }
521 } else {
522 target->t_auth_group = auth_group_new(conf, target);
523 if (target->t_auth_group == NULL)
524 return (false);
525 }
526 return (auth_new_chap(target->t_auth_group, user, secret));
527 }
528
529 bool
target_add_chap_mutual(const char * user,const char * secret,const char * user2,const char * secret2)530 target_add_chap_mutual(const char *user, const char *secret,
531 const char *user2, const char *secret2)
532 {
533 if (target->t_auth_group != NULL) {
534 if (target->t_auth_group->ag_name != NULL) {
535 log_warnx("cannot use both auth-group and "
536 "chap-mutual for target \"%s\"", target->t_name);
537 return (false);
538 }
539 } else {
540 target->t_auth_group = auth_group_new(conf, target);
541 if (target->t_auth_group == NULL)
542 return (false);
543 }
544 return (auth_new_chap_mutual(target->t_auth_group, user, secret, user2,
545 secret2));
546 }
547
548 bool
target_add_initiator_name(const char * name)549 target_add_initiator_name(const char *name)
550 {
551 if (target->t_auth_group != NULL) {
552 if (target->t_auth_group->ag_name != NULL) {
553 log_warnx("cannot use both auth-group and "
554 "initiator-name for target \"%s\"", target->t_name);
555 return (false);
556 }
557 } else {
558 target->t_auth_group = auth_group_new(conf, target);
559 if (target->t_auth_group == NULL)
560 return (false);
561 }
562 return (auth_name_new(target->t_auth_group, name));
563 }
564
565 bool
target_add_initiator_portal(const char * addr)566 target_add_initiator_portal(const char *addr)
567 {
568 if (target->t_auth_group != NULL) {
569 if (target->t_auth_group->ag_name != NULL) {
570 log_warnx("cannot use both auth-group and "
571 "initiator-portal for target \"%s\"",
572 target->t_name);
573 return (false);
574 }
575 } else {
576 target->t_auth_group = auth_group_new(conf, target);
577 if (target->t_auth_group == NULL)
578 return (false);
579 }
580 return (auth_portal_new(target->t_auth_group, addr));
581 }
582
583 bool
target_add_lun(u_int id,const char * name)584 target_add_lun(u_int id, const char *name)
585 {
586 struct lun *t_lun;
587
588 if (id >= MAX_LUNS) {
589 log_warnx("LUN %u too big for target \"%s\"", id,
590 target->t_name);
591 return (false);
592 }
593
594 if (target->t_luns[id] != NULL) {
595 log_warnx("duplicate LUN %u for target \"%s\"", id,
596 target->t_name);
597 return (false);
598 }
599
600 t_lun = lun_find(conf, name);
601 if (t_lun == NULL) {
602 log_warnx("unknown LUN named %s used for target \"%s\"",
603 name, target->t_name);
604 return (false);
605 }
606
607 target->t_luns[id] = t_lun;
608 return (true);
609 }
610
611 bool
target_add_portal_group(const char * pg_name,const char * ag_name)612 target_add_portal_group(const char *pg_name, const char *ag_name)
613 {
614 struct portal_group *pg;
615 struct auth_group *ag;
616 struct port *p;
617
618 pg = portal_group_find(conf, pg_name);
619 if (pg == NULL) {
620 log_warnx("unknown portal-group \"%s\" for target \"%s\"",
621 pg_name, target->t_name);
622 return (false);
623 }
624
625 if (ag_name != NULL) {
626 ag = auth_group_find(conf, ag_name);
627 if (ag == NULL) {
628 log_warnx("unknown auth-group \"%s\" for target \"%s\"",
629 ag_name, target->t_name);
630 return (false);
631 }
632 } else
633 ag = NULL;
634
635 p = port_new(conf, target, pg);
636 if (p == NULL) {
637 log_warnx("can't link portal-group \"%s\" to target \"%s\"",
638 pg_name, target->t_name);
639 return (false);
640 }
641 p->p_auth_group = ag;
642 return (true);
643 }
644
645 bool
target_set_alias(const char * alias)646 target_set_alias(const char *alias)
647 {
648 if (target->t_alias != NULL) {
649 log_warnx("alias for target \"%s\" specified more than once",
650 target->t_name);
651 return (false);
652 }
653 target->t_alias = checked_strdup(alias);
654 return (true);
655 }
656
657 bool
target_set_auth_group(const char * name)658 target_set_auth_group(const char *name)
659 {
660 if (target->t_auth_group != NULL) {
661 if (target->t_auth_group->ag_name != NULL)
662 log_warnx("auth-group for target \"%s\" "
663 "specified more than once", target->t_name);
664 else
665 log_warnx("cannot use both auth-group and explicit "
666 "authorisations for target \"%s\"", target->t_name);
667 return (false);
668 }
669 target->t_auth_group = auth_group_find(conf, name);
670 if (target->t_auth_group == NULL) {
671 log_warnx("unknown auth-group \"%s\" for target \"%s\"", name,
672 target->t_name);
673 return (false);
674 }
675 return (true);
676 }
677
678 bool
target_set_auth_type(const char * type)679 target_set_auth_type(const char *type)
680 {
681 if (target->t_auth_group != NULL) {
682 if (target->t_auth_group->ag_name != NULL) {
683 log_warnx("cannot use both auth-group and "
684 "auth-type for target \"%s\"", target->t_name);
685 return (false);
686 }
687 } else {
688 target->t_auth_group = auth_group_new(conf, target);
689 if (target->t_auth_group == NULL)
690 return (false);
691 }
692 return (_auth_group_set_type(target->t_auth_group, type));
693 }
694
695 bool
target_set_physical_port(const char * pport)696 target_set_physical_port(const char *pport)
697 {
698 if (target->t_pport != NULL) {
699 log_warnx("cannot set multiple physical ports for target "
700 "\"%s\"", target->t_name);
701 return (false);
702 }
703 target->t_pport = checked_strdup(pport);
704 return (true);
705 }
706
707 bool
target_set_redirection(const char * addr)708 target_set_redirection(const char *addr)
709 {
710
711 if (target->t_redirection != NULL) {
712 log_warnx("cannot set redirection to \"%s\" for "
713 "target \"%s\"; already defined",
714 addr, target->t_name);
715 return (false);
716 }
717
718 target->t_redirection = checked_strdup(addr);
719
720 return (true);
721 }
722
723 bool
target_start_lun(u_int id)724 target_start_lun(u_int id)
725 {
726 struct lun *new_lun;
727 char *name;
728
729 if (id >= MAX_LUNS) {
730 log_warnx("LUN %u too big for target \"%s\"", id,
731 target->t_name);
732 return (false);
733 }
734
735 if (target->t_luns[id] != NULL) {
736 log_warnx("duplicate LUN %u for target \"%s\"", id,
737 target->t_name);
738 return (false);
739 }
740
741 if (asprintf(&name, "%s,lun,%u", target->t_name, id) <= 0)
742 log_err(1, "asprintf");
743
744 new_lun = lun_new(conf, name);
745 if (new_lun == NULL)
746 return (false);
747
748 lun_set_scsiname(new_lun, name);
749 free(name);
750
751 target->t_luns[id] = new_lun;
752
753 lun = new_lun;
754 return (true);
755 }
756