1255570Strasz/*- 2255570Strasz * Copyright (c) 2012 The FreeBSD Foundation 3255570Strasz * All rights reserved. 4255570Strasz * 5255570Strasz * This software was developed by Edward Tomasz Napierala under sponsorship 6255570Strasz * from the FreeBSD Foundation. 7255570Strasz * 8255570Strasz * Redistribution and use in source and binary forms, with or without 9255570Strasz * modification, are permitted provided that the following conditions 10255570Strasz * are met: 11255570Strasz * 1. Redistributions of source code must retain the above copyright 12255570Strasz * notice, this list of conditions and the following disclaimer. 13255570Strasz * 2. Redistributions in binary form must reproduce the above copyright 14255570Strasz * notice, this list of conditions and the following disclaimer in the 15255570Strasz * documentation and/or other materials provided with the distribution. 16255570Strasz * 17255570Strasz * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18255570Strasz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19255570Strasz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20255570Strasz * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21255570Strasz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22255570Strasz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23255570Strasz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24255570Strasz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25255570Strasz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26255570Strasz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27255570Strasz * SUCH DAMAGE. 28255570Strasz * 29255570Strasz */ 30255570Strasz 31270279Strasz#include <sys/cdefs.h> 32270279Strasz__FBSDID("$FreeBSD: releng/11.0/usr.sbin/ctld/ctld.c 302663 2016-07-12 13:12:01Z trasz $"); 33270279Strasz 34255570Strasz#include <sys/types.h> 35255570Strasz#include <sys/time.h> 36255570Strasz#include <sys/socket.h> 37295212Sjceel#include <sys/stat.h> 38255570Strasz#include <sys/wait.h> 39255570Strasz#include <netinet/in.h> 40269183Smav#include <arpa/inet.h> 41255570Strasz#include <assert.h> 42255570Strasz#include <ctype.h> 43255570Strasz#include <errno.h> 44255570Strasz#include <netdb.h> 45255570Strasz#include <signal.h> 46255570Strasz#include <stdbool.h> 47255570Strasz#include <stdio.h> 48255570Strasz#include <stdint.h> 49255570Strasz#include <stdlib.h> 50255570Strasz#include <string.h> 51255570Strasz#include <unistd.h> 52255570Strasz 53255570Strasz#include "ctld.h" 54273635Smav#include "isns.h" 55255570Strasz 56264524Straszbool proxy_mode = false; 57264524Strasz 58255570Straszstatic volatile bool sighup_received = false; 59255570Straszstatic volatile bool sigterm_received = false; 60255570Straszstatic volatile bool sigalrm_received = false; 61255570Strasz 62255570Straszstatic int nchildren = 0; 63287534Smavstatic uint16_t last_portal_group_tag = 0xff; 64255570Strasz 65255570Straszstatic void 66255570Straszusage(void) 67255570Strasz{ 68255570Strasz 69297860Strasz fprintf(stderr, "usage: ctld [-d][-u][-f config-file]\n"); 70255570Strasz exit(1); 71255570Strasz} 72255570Strasz 73255570Straszchar * 74255570Straszchecked_strdup(const char *s) 75255570Strasz{ 76255570Strasz char *c; 77255570Strasz 78255570Strasz c = strdup(s); 79255570Strasz if (c == NULL) 80255570Strasz log_err(1, "strdup"); 81255570Strasz return (c); 82255570Strasz} 83255570Strasz 84255570Straszstruct conf * 85255570Straszconf_new(void) 86255570Strasz{ 87255570Strasz struct conf *conf; 88255570Strasz 89255570Strasz conf = calloc(1, sizeof(*conf)); 90255570Strasz if (conf == NULL) 91255570Strasz log_err(1, "calloc"); 92278037Smav TAILQ_INIT(&conf->conf_luns); 93255570Strasz TAILQ_INIT(&conf->conf_targets); 94255570Strasz TAILQ_INIT(&conf->conf_auth_groups); 95278322Smav TAILQ_INIT(&conf->conf_ports); 96255570Strasz TAILQ_INIT(&conf->conf_portal_groups); 97278354Smav TAILQ_INIT(&conf->conf_pports); 98273635Smav TAILQ_INIT(&conf->conf_isns); 99255570Strasz 100273635Smav conf->conf_isns_period = 900; 101273635Smav conf->conf_isns_timeout = 5; 102255570Strasz conf->conf_debug = 0; 103255570Strasz conf->conf_timeout = 60; 104255570Strasz conf->conf_maxproc = 30; 105255570Strasz 106255570Strasz return (conf); 107255570Strasz} 108255570Strasz 109255570Straszvoid 110255570Straszconf_delete(struct conf *conf) 111255570Strasz{ 112278037Smav struct lun *lun, *ltmp; 113255570Strasz struct target *targ, *tmp; 114255570Strasz struct auth_group *ag, *cagtmp; 115255570Strasz struct portal_group *pg, *cpgtmp; 116278354Smav struct pport *pp, *pptmp; 117273635Smav struct isns *is, *istmp; 118255570Strasz 119255570Strasz assert(conf->conf_pidfh == NULL); 120255570Strasz 121278037Smav TAILQ_FOREACH_SAFE(lun, &conf->conf_luns, l_next, ltmp) 122278037Smav lun_delete(lun); 123255570Strasz TAILQ_FOREACH_SAFE(targ, &conf->conf_targets, t_next, tmp) 124255570Strasz target_delete(targ); 125255570Strasz TAILQ_FOREACH_SAFE(ag, &conf->conf_auth_groups, ag_next, cagtmp) 126255570Strasz auth_group_delete(ag); 127255570Strasz TAILQ_FOREACH_SAFE(pg, &conf->conf_portal_groups, pg_next, cpgtmp) 128255570Strasz portal_group_delete(pg); 129278354Smav TAILQ_FOREACH_SAFE(pp, &conf->conf_pports, pp_next, pptmp) 130278354Smav pport_delete(pp); 131273635Smav TAILQ_FOREACH_SAFE(is, &conf->conf_isns, i_next, istmp) 132273635Smav isns_delete(is); 133278322Smav assert(TAILQ_EMPTY(&conf->conf_ports)); 134255570Strasz free(conf->conf_pidfile_path); 135255570Strasz free(conf); 136255570Strasz} 137255570Strasz 138255570Straszstatic struct auth * 139255570Straszauth_new(struct auth_group *ag) 140255570Strasz{ 141255570Strasz struct auth *auth; 142255570Strasz 143255570Strasz auth = calloc(1, sizeof(*auth)); 144255570Strasz if (auth == NULL) 145255570Strasz log_err(1, "calloc"); 146255570Strasz auth->a_auth_group = ag; 147255570Strasz TAILQ_INSERT_TAIL(&ag->ag_auths, auth, a_next); 148255570Strasz return (auth); 149255570Strasz} 150255570Strasz 151255570Straszstatic void 152255570Straszauth_delete(struct auth *auth) 153255570Strasz{ 154255570Strasz TAILQ_REMOVE(&auth->a_auth_group->ag_auths, auth, a_next); 155255570Strasz 156255570Strasz free(auth->a_user); 157255570Strasz free(auth->a_secret); 158255570Strasz free(auth->a_mutual_user); 159255570Strasz free(auth->a_mutual_secret); 160255570Strasz free(auth); 161255570Strasz} 162255570Strasz 163255570Straszconst struct auth * 164264531Straszauth_find(const struct auth_group *ag, const char *user) 165255570Strasz{ 166255570Strasz const struct auth *auth; 167255570Strasz 168255570Strasz TAILQ_FOREACH(auth, &ag->ag_auths, a_next) { 169255570Strasz if (strcmp(auth->a_user, user) == 0) 170255570Strasz return (auth); 171255570Strasz } 172255570Strasz 173255570Strasz return (NULL); 174255570Strasz} 175255570Strasz 176261755Straszstatic void 177261755Straszauth_check_secret_length(struct auth *auth) 178261755Strasz{ 179261755Strasz size_t len; 180261755Strasz 181261755Strasz len = strlen(auth->a_secret); 182261755Strasz if (len > 16) { 183261755Strasz if (auth->a_auth_group->ag_name != NULL) 184261755Strasz log_warnx("secret for user \"%s\", auth-group \"%s\", " 185261755Strasz "is too long; it should be at most 16 characters " 186261755Strasz "long", auth->a_user, auth->a_auth_group->ag_name); 187261755Strasz else 188261755Strasz log_warnx("secret for user \"%s\", target \"%s\", " 189261755Strasz "is too long; it should be at most 16 characters " 190261755Strasz "long", auth->a_user, 191261757Strasz auth->a_auth_group->ag_target->t_name); 192261755Strasz } 193261755Strasz if (len < 12) { 194261755Strasz if (auth->a_auth_group->ag_name != NULL) 195261755Strasz log_warnx("secret for user \"%s\", auth-group \"%s\", " 196261755Strasz "is too short; it should be at least 12 characters " 197261755Strasz "long", auth->a_user, 198261755Strasz auth->a_auth_group->ag_name); 199261755Strasz else 200261755Strasz log_warnx("secret for user \"%s\", target \"%s\", " 201261755Strasz "is too short; it should be at least 16 characters " 202261755Strasz "long", auth->a_user, 203261757Strasz auth->a_auth_group->ag_target->t_name); 204261755Strasz } 205261755Strasz 206261755Strasz if (auth->a_mutual_secret != NULL) { 207281084Sjpaetzel len = strlen(auth->a_mutual_secret); 208261755Strasz if (len > 16) { 209261755Strasz if (auth->a_auth_group->ag_name != NULL) 210261755Strasz log_warnx("mutual secret for user \"%s\", " 211261755Strasz "auth-group \"%s\", is too long; it should " 212261755Strasz "be at most 16 characters long", 213261755Strasz auth->a_user, auth->a_auth_group->ag_name); 214261755Strasz else 215261755Strasz log_warnx("mutual secret for user \"%s\", " 216261755Strasz "target \"%s\", is too long; it should " 217261755Strasz "be at most 16 characters long", 218261755Strasz auth->a_user, 219261757Strasz auth->a_auth_group->ag_target->t_name); 220261755Strasz } 221261755Strasz if (len < 12) { 222261755Strasz if (auth->a_auth_group->ag_name != NULL) 223261755Strasz log_warnx("mutual secret for user \"%s\", " 224261755Strasz "auth-group \"%s\", is too short; it " 225261755Strasz "should be at least 12 characters long", 226261755Strasz auth->a_user, auth->a_auth_group->ag_name); 227261755Strasz else 228261755Strasz log_warnx("mutual secret for user \"%s\", " 229261755Strasz "target \"%s\", is too short; it should be " 230261755Strasz "at least 16 characters long", 231261755Strasz auth->a_user, 232261757Strasz auth->a_auth_group->ag_target->t_name); 233261755Strasz } 234261755Strasz } 235261755Strasz} 236261755Strasz 237261755Straszconst struct auth * 238261755Straszauth_new_chap(struct auth_group *ag, const char *user, 239261755Strasz const char *secret) 240261755Strasz{ 241261755Strasz struct auth *auth; 242261755Strasz 243261755Strasz if (ag->ag_type == AG_TYPE_UNKNOWN) 244261755Strasz ag->ag_type = AG_TYPE_CHAP; 245261755Strasz if (ag->ag_type != AG_TYPE_CHAP) { 246261755Strasz if (ag->ag_name != NULL) 247261755Strasz log_warnx("cannot mix \"chap\" authentication with " 248261755Strasz "other types for auth-group \"%s\"", ag->ag_name); 249261755Strasz else 250261755Strasz log_warnx("cannot mix \"chap\" authentication with " 251261755Strasz "other types for target \"%s\"", 252261757Strasz ag->ag_target->t_name); 253261755Strasz return (NULL); 254261755Strasz } 255261755Strasz 256261755Strasz auth = auth_new(ag); 257261755Strasz auth->a_user = checked_strdup(user); 258261755Strasz auth->a_secret = checked_strdup(secret); 259261755Strasz 260261755Strasz auth_check_secret_length(auth); 261261755Strasz 262261755Strasz return (auth); 263261755Strasz} 264261755Strasz 265261755Straszconst struct auth * 266261755Straszauth_new_chap_mutual(struct auth_group *ag, const char *user, 267261755Strasz const char *secret, const char *user2, const char *secret2) 268261755Strasz{ 269261755Strasz struct auth *auth; 270261755Strasz 271261755Strasz if (ag->ag_type == AG_TYPE_UNKNOWN) 272261755Strasz ag->ag_type = AG_TYPE_CHAP_MUTUAL; 273261755Strasz if (ag->ag_type != AG_TYPE_CHAP_MUTUAL) { 274261755Strasz if (ag->ag_name != NULL) 275261755Strasz log_warnx("cannot mix \"chap-mutual\" authentication " 276261755Strasz "with other types for auth-group \"%s\"", 277273464Strasz ag->ag_name); 278261755Strasz else 279261755Strasz log_warnx("cannot mix \"chap-mutual\" authentication " 280261755Strasz "with other types for target \"%s\"", 281261757Strasz ag->ag_target->t_name); 282261755Strasz return (NULL); 283261755Strasz } 284261755Strasz 285261755Strasz auth = auth_new(ag); 286261755Strasz auth->a_user = checked_strdup(user); 287261755Strasz auth->a_secret = checked_strdup(secret); 288261755Strasz auth->a_mutual_user = checked_strdup(user2); 289261755Strasz auth->a_mutual_secret = checked_strdup(secret2); 290261755Strasz 291261755Strasz auth_check_secret_length(auth); 292261755Strasz 293261755Strasz return (auth); 294261755Strasz} 295261755Strasz 296261754Straszconst struct auth_name * 297261754Straszauth_name_new(struct auth_group *ag, const char *name) 298261754Strasz{ 299261754Strasz struct auth_name *an; 300261754Strasz 301261754Strasz an = calloc(1, sizeof(*an)); 302261754Strasz if (an == NULL) 303261754Strasz log_err(1, "calloc"); 304261754Strasz an->an_auth_group = ag; 305261754Strasz an->an_initator_name = checked_strdup(name); 306261754Strasz TAILQ_INSERT_TAIL(&ag->ag_names, an, an_next); 307261754Strasz return (an); 308261754Strasz} 309261754Strasz 310261754Straszstatic void 311261754Straszauth_name_delete(struct auth_name *an) 312261754Strasz{ 313261754Strasz TAILQ_REMOVE(&an->an_auth_group->ag_names, an, an_next); 314261754Strasz 315261754Strasz free(an->an_initator_name); 316261754Strasz free(an); 317261754Strasz} 318261754Strasz 319261754Straszbool 320261754Straszauth_name_defined(const struct auth_group *ag) 321261754Strasz{ 322261754Strasz if (TAILQ_EMPTY(&ag->ag_names)) 323261754Strasz return (false); 324261754Strasz return (true); 325261754Strasz} 326261754Strasz 327261754Straszconst struct auth_name * 328261754Straszauth_name_find(const struct auth_group *ag, const char *name) 329261754Strasz{ 330261754Strasz const struct auth_name *auth_name; 331261754Strasz 332261754Strasz TAILQ_FOREACH(auth_name, &ag->ag_names, an_next) { 333261754Strasz if (strcmp(auth_name->an_initator_name, name) == 0) 334261754Strasz return (auth_name); 335261754Strasz } 336261754Strasz 337261754Strasz return (NULL); 338261754Strasz} 339261754Strasz 340273584Straszint 341273584Straszauth_name_check(const struct auth_group *ag, const char *initiator_name) 342273584Strasz{ 343273584Strasz if (!auth_name_defined(ag)) 344273584Strasz return (0); 345273584Strasz 346273584Strasz if (auth_name_find(ag, initiator_name) == NULL) 347273584Strasz return (1); 348273584Strasz 349273584Strasz return (0); 350273584Strasz} 351273584Strasz 352261754Straszconst struct auth_portal * 353261754Straszauth_portal_new(struct auth_group *ag, const char *portal) 354261754Strasz{ 355261754Strasz struct auth_portal *ap; 356269183Smav char *net, *mask, *str, *tmp; 357269183Smav int len, dm, m; 358261754Strasz 359261754Strasz ap = calloc(1, sizeof(*ap)); 360261754Strasz if (ap == NULL) 361261754Strasz log_err(1, "calloc"); 362261754Strasz ap->ap_auth_group = ag; 363261754Strasz ap->ap_initator_portal = checked_strdup(portal); 364269183Smav mask = str = checked_strdup(portal); 365269183Smav net = strsep(&mask, "/"); 366269183Smav if (net[0] == '[') 367269183Smav net++; 368269183Smav len = strlen(net); 369269183Smav if (len == 0) 370269183Smav goto error; 371269183Smav if (net[len - 1] == ']') 372269183Smav net[len - 1] = 0; 373269183Smav if (strchr(net, ':') != NULL) { 374269183Smav struct sockaddr_in6 *sin6 = 375269183Smav (struct sockaddr_in6 *)&ap->ap_sa; 376269183Smav 377269183Smav sin6->sin6_len = sizeof(*sin6); 378269183Smav sin6->sin6_family = AF_INET6; 379269183Smav if (inet_pton(AF_INET6, net, &sin6->sin6_addr) <= 0) 380269183Smav goto error; 381269183Smav dm = 128; 382269183Smav } else { 383269183Smav struct sockaddr_in *sin = 384269183Smav (struct sockaddr_in *)&ap->ap_sa; 385269183Smav 386269183Smav sin->sin_len = sizeof(*sin); 387269183Smav sin->sin_family = AF_INET; 388269183Smav if (inet_pton(AF_INET, net, &sin->sin_addr) <= 0) 389269183Smav goto error; 390269183Smav dm = 32; 391269183Smav } 392269183Smav if (mask != NULL) { 393269183Smav m = strtol(mask, &tmp, 0); 394269183Smav if (m < 0 || m > dm || tmp[0] != 0) 395269183Smav goto error; 396269183Smav } else 397269183Smav m = dm; 398269183Smav ap->ap_mask = m; 399269183Smav free(str); 400261754Strasz TAILQ_INSERT_TAIL(&ag->ag_portals, ap, ap_next); 401261754Strasz return (ap); 402269183Smav 403269183Smaverror: 404279277Smav free(ap); 405302663Strasz log_warnx("incorrect initiator portal \"%s\"", portal); 406269183Smav return (NULL); 407261754Strasz} 408261754Strasz 409261754Straszstatic void 410261754Straszauth_portal_delete(struct auth_portal *ap) 411261754Strasz{ 412261754Strasz TAILQ_REMOVE(&ap->ap_auth_group->ag_portals, ap, ap_next); 413261754Strasz 414261754Strasz free(ap->ap_initator_portal); 415261754Strasz free(ap); 416261754Strasz} 417261754Strasz 418261754Straszbool 419261754Straszauth_portal_defined(const struct auth_group *ag) 420261754Strasz{ 421261754Strasz if (TAILQ_EMPTY(&ag->ag_portals)) 422261754Strasz return (false); 423261754Strasz return (true); 424261754Strasz} 425261754Strasz 426261754Straszconst struct auth_portal * 427269183Smavauth_portal_find(const struct auth_group *ag, const struct sockaddr_storage *ss) 428261754Strasz{ 429269183Smav const struct auth_portal *ap; 430269191Smav const uint8_t *a, *b; 431269183Smav int i; 432269191Smav uint8_t bmask; 433261754Strasz 434269183Smav TAILQ_FOREACH(ap, &ag->ag_portals, ap_next) { 435269183Smav if (ap->ap_sa.ss_family != ss->ss_family) 436269183Smav continue; 437269183Smav if (ss->ss_family == AF_INET) { 438269191Smav a = (const uint8_t *) 439269191Smav &((const struct sockaddr_in *)ss)->sin_addr; 440269191Smav b = (const uint8_t *) 441269191Smav &((const struct sockaddr_in *)&ap->ap_sa)->sin_addr; 442269183Smav } else { 443269191Smav a = (const uint8_t *) 444269191Smav &((const struct sockaddr_in6 *)ss)->sin6_addr; 445269191Smav b = (const uint8_t *) 446269191Smav &((const struct sockaddr_in6 *)&ap->ap_sa)->sin6_addr; 447269183Smav } 448269183Smav for (i = 0; i < ap->ap_mask / 8; i++) { 449269183Smav if (a[i] != b[i]) 450269183Smav goto next; 451269183Smav } 452269183Smav if (ap->ap_mask % 8) { 453269183Smav bmask = 0xff << (8 - (ap->ap_mask % 8)); 454269183Smav if ((a[i] & bmask) != (b[i] & bmask)) 455269183Smav goto next; 456269183Smav } 457269183Smav return (ap); 458269183Smavnext: 459269183Smav ; 460261754Strasz } 461261754Strasz 462261754Strasz return (NULL); 463261754Strasz} 464261754Strasz 465273584Straszint 466273584Straszauth_portal_check(const struct auth_group *ag, const struct sockaddr_storage *sa) 467273584Strasz{ 468273584Strasz 469273584Strasz if (!auth_portal_defined(ag)) 470273584Strasz return (0); 471273584Strasz 472273584Strasz if (auth_portal_find(ag, sa) == NULL) 473273584Strasz return (1); 474273584Strasz 475273584Strasz return (0); 476273584Strasz} 477273584Strasz 478255570Straszstruct auth_group * 479255570Straszauth_group_new(struct conf *conf, const char *name) 480255570Strasz{ 481255570Strasz struct auth_group *ag; 482255570Strasz 483255570Strasz if (name != NULL) { 484255570Strasz ag = auth_group_find(conf, name); 485255570Strasz if (ag != NULL) { 486255570Strasz log_warnx("duplicated auth-group \"%s\"", name); 487255570Strasz return (NULL); 488255570Strasz } 489255570Strasz } 490255570Strasz 491255570Strasz ag = calloc(1, sizeof(*ag)); 492255570Strasz if (ag == NULL) 493255570Strasz log_err(1, "calloc"); 494255570Strasz if (name != NULL) 495255570Strasz ag->ag_name = checked_strdup(name); 496255570Strasz TAILQ_INIT(&ag->ag_auths); 497261754Strasz TAILQ_INIT(&ag->ag_names); 498261754Strasz TAILQ_INIT(&ag->ag_portals); 499255570Strasz ag->ag_conf = conf; 500255570Strasz TAILQ_INSERT_TAIL(&conf->conf_auth_groups, ag, ag_next); 501255570Strasz 502255570Strasz return (ag); 503255570Strasz} 504255570Strasz 505255570Straszvoid 506255570Straszauth_group_delete(struct auth_group *ag) 507255570Strasz{ 508261754Strasz struct auth *auth, *auth_tmp; 509261754Strasz struct auth_name *auth_name, *auth_name_tmp; 510261754Strasz struct auth_portal *auth_portal, *auth_portal_tmp; 511255570Strasz 512255570Strasz TAILQ_REMOVE(&ag->ag_conf->conf_auth_groups, ag, ag_next); 513255570Strasz 514261754Strasz TAILQ_FOREACH_SAFE(auth, &ag->ag_auths, a_next, auth_tmp) 515255570Strasz auth_delete(auth); 516261754Strasz TAILQ_FOREACH_SAFE(auth_name, &ag->ag_names, an_next, auth_name_tmp) 517261754Strasz auth_name_delete(auth_name); 518261754Strasz TAILQ_FOREACH_SAFE(auth_portal, &ag->ag_portals, ap_next, 519261754Strasz auth_portal_tmp) 520261754Strasz auth_portal_delete(auth_portal); 521255570Strasz free(ag->ag_name); 522255570Strasz free(ag); 523255570Strasz} 524255570Strasz 525255570Straszstruct auth_group * 526264531Straszauth_group_find(const struct conf *conf, const char *name) 527255570Strasz{ 528255570Strasz struct auth_group *ag; 529255570Strasz 530255570Strasz TAILQ_FOREACH(ag, &conf->conf_auth_groups, ag_next) { 531255570Strasz if (ag->ag_name != NULL && strcmp(ag->ag_name, name) == 0) 532255570Strasz return (ag); 533255570Strasz } 534255570Strasz 535255570Strasz return (NULL); 536255570Strasz} 537255570Strasz 538261758Straszint 539273816Straszauth_group_set_type(struct auth_group *ag, const char *str) 540261758Strasz{ 541273816Strasz int type; 542261758Strasz 543261758Strasz if (strcmp(str, "none") == 0) { 544261758Strasz type = AG_TYPE_NO_AUTHENTICATION; 545261763Strasz } else if (strcmp(str, "deny") == 0) { 546261763Strasz type = AG_TYPE_DENY; 547261758Strasz } else if (strcmp(str, "chap") == 0) { 548261758Strasz type = AG_TYPE_CHAP; 549261758Strasz } else if (strcmp(str, "chap-mutual") == 0) { 550261758Strasz type = AG_TYPE_CHAP_MUTUAL; 551261758Strasz } else { 552261758Strasz if (ag->ag_name != NULL) 553261758Strasz log_warnx("invalid auth-type \"%s\" for auth-group " 554261758Strasz "\"%s\"", str, ag->ag_name); 555261758Strasz else 556261758Strasz log_warnx("invalid auth-type \"%s\" for target " 557261758Strasz "\"%s\"", str, ag->ag_target->t_name); 558261758Strasz return (1); 559261758Strasz } 560261758Strasz 561273816Strasz if (ag->ag_type != AG_TYPE_UNKNOWN && ag->ag_type != type) { 562273816Strasz if (ag->ag_name != NULL) { 563261758Strasz log_warnx("cannot set auth-type to \"%s\" for " 564261758Strasz "auth-group \"%s\"; already has a different " 565261758Strasz "type", str, ag->ag_name); 566273816Strasz } else { 567261758Strasz log_warnx("cannot set auth-type to \"%s\" for target " 568261758Strasz "\"%s\"; already has a different type", 569261758Strasz str, ag->ag_target->t_name); 570273816Strasz } 571261758Strasz return (1); 572261758Strasz } 573261758Strasz 574273816Strasz ag->ag_type = type; 575273816Strasz 576273816Strasz return (0); 577261758Strasz} 578261758Strasz 579255570Straszstatic struct portal * 580255570Straszportal_new(struct portal_group *pg) 581255570Strasz{ 582255570Strasz struct portal *portal; 583255570Strasz 584255570Strasz portal = calloc(1, sizeof(*portal)); 585255570Strasz if (portal == NULL) 586255570Strasz log_err(1, "calloc"); 587255570Strasz TAILQ_INIT(&portal->p_targets); 588255570Strasz portal->p_portal_group = pg; 589255570Strasz TAILQ_INSERT_TAIL(&pg->pg_portals, portal, p_next); 590255570Strasz return (portal); 591255570Strasz} 592255570Strasz 593255570Straszstatic void 594255570Straszportal_delete(struct portal *portal) 595255570Strasz{ 596271187Strasz 597255570Strasz TAILQ_REMOVE(&portal->p_portal_group->pg_portals, portal, p_next); 598271187Strasz if (portal->p_ai != NULL) 599271187Strasz freeaddrinfo(portal->p_ai); 600255570Strasz free(portal->p_listen); 601255570Strasz free(portal); 602255570Strasz} 603255570Strasz 604255570Straszstruct portal_group * 605255570Straszportal_group_new(struct conf *conf, const char *name) 606255570Strasz{ 607255570Strasz struct portal_group *pg; 608255570Strasz 609255678Strasz pg = portal_group_find(conf, name); 610255678Strasz if (pg != NULL) { 611255678Strasz log_warnx("duplicated portal-group \"%s\"", name); 612255678Strasz return (NULL); 613255570Strasz } 614255570Strasz 615255570Strasz pg = calloc(1, sizeof(*pg)); 616255570Strasz if (pg == NULL) 617255570Strasz log_err(1, "calloc"); 618255570Strasz pg->pg_name = checked_strdup(name); 619290615Smav TAILQ_INIT(&pg->pg_options); 620255570Strasz TAILQ_INIT(&pg->pg_portals); 621278322Smav TAILQ_INIT(&pg->pg_ports); 622255570Strasz pg->pg_conf = conf; 623278161Smav pg->pg_tag = 0; /* Assigned later in conf_apply(). */ 624255570Strasz TAILQ_INSERT_TAIL(&conf->conf_portal_groups, pg, pg_next); 625255570Strasz 626255570Strasz return (pg); 627255570Strasz} 628255570Strasz 629255570Straszvoid 630255570Straszportal_group_delete(struct portal_group *pg) 631255570Strasz{ 632255570Strasz struct portal *portal, *tmp; 633278322Smav struct port *port, *tport; 634290615Smav struct option *o, *otmp; 635255570Strasz 636278322Smav TAILQ_FOREACH_SAFE(port, &pg->pg_ports, p_pgs, tport) 637278322Smav port_delete(port); 638255570Strasz TAILQ_REMOVE(&pg->pg_conf->conf_portal_groups, pg, pg_next); 639255570Strasz 640255570Strasz TAILQ_FOREACH_SAFE(portal, &pg->pg_portals, p_next, tmp) 641255570Strasz portal_delete(portal); 642290615Smav TAILQ_FOREACH_SAFE(o, &pg->pg_options, o_next, otmp) 643290615Smav option_delete(&pg->pg_options, o); 644255570Strasz free(pg->pg_name); 645279392Strasz free(pg->pg_offload); 646274308Strasz free(pg->pg_redirection); 647255570Strasz free(pg); 648255570Strasz} 649255570Strasz 650255570Straszstruct portal_group * 651264531Straszportal_group_find(const struct conf *conf, const char *name) 652255570Strasz{ 653255570Strasz struct portal_group *pg; 654255570Strasz 655255570Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 656255570Strasz if (strcmp(pg->pg_name, name) == 0) 657255570Strasz return (pg); 658255570Strasz } 659255570Strasz 660255570Strasz return (NULL); 661255570Strasz} 662255570Strasz 663273635Smavstatic int 664273635Smavparse_addr_port(char *arg, const char *def_port, struct addrinfo **ai) 665255570Strasz{ 666255570Strasz struct addrinfo hints; 667275452Smav char *str, *addr, *ch; 668255570Strasz const char *port; 669255570Strasz int error, colons = 0; 670255570Strasz 671275452Smav str = arg = strdup(arg); 672255570Strasz if (arg[0] == '[') { 673255570Strasz /* 674255570Strasz * IPv6 address in square brackets, perhaps with port. 675255570Strasz */ 676255570Strasz arg++; 677255570Strasz addr = strsep(&arg, "]"); 678273635Smav if (arg == NULL) 679255570Strasz return (1); 680255570Strasz if (arg[0] == '\0') { 681273635Smav port = def_port; 682255570Strasz } else if (arg[0] == ':') { 683255570Strasz port = arg + 1; 684275452Smav } else { 685275452Smav free(str); 686255570Strasz return (1); 687275452Smav } 688255570Strasz } else { 689255570Strasz /* 690255570Strasz * Either IPv6 address without brackets - and without 691255570Strasz * a port - or IPv4 address. Just count the colons. 692255570Strasz */ 693255570Strasz for (ch = arg; *ch != '\0'; ch++) { 694255570Strasz if (*ch == ':') 695255570Strasz colons++; 696255570Strasz } 697255570Strasz if (colons > 1) { 698255570Strasz addr = arg; 699273635Smav port = def_port; 700255570Strasz } else { 701255570Strasz addr = strsep(&arg, ":"); 702255570Strasz if (arg == NULL) 703273635Smav port = def_port; 704255570Strasz else 705255570Strasz port = arg; 706255570Strasz } 707255570Strasz } 708255570Strasz 709255570Strasz memset(&hints, 0, sizeof(hints)); 710255570Strasz hints.ai_family = PF_UNSPEC; 711255570Strasz hints.ai_socktype = SOCK_STREAM; 712255570Strasz hints.ai_flags = AI_PASSIVE; 713273635Smav error = getaddrinfo(addr, port, &hints, ai); 714275452Smav free(str); 715275452Smav return ((error != 0) ? 1 : 0); 716273635Smav} 717255570Strasz 718273635Smavint 719273635Smavportal_group_add_listen(struct portal_group *pg, const char *value, bool iser) 720273635Smav{ 721273635Smav struct portal *portal; 722273635Smav 723273635Smav portal = portal_new(pg); 724273635Smav portal->p_listen = checked_strdup(value); 725273635Smav portal->p_iser = iser; 726273635Smav 727273635Smav if (parse_addr_port(portal->p_listen, "3260", &portal->p_ai)) { 728273635Smav log_warnx("invalid listen address %s", portal->p_listen); 729271187Strasz portal_delete(portal); 730255570Strasz return (1); 731255570Strasz } 732255570Strasz 733255570Strasz /* 734255570Strasz * XXX: getaddrinfo(3) may return multiple addresses; we should turn 735255570Strasz * those into multiple portals. 736255570Strasz */ 737255570Strasz 738255570Strasz return (0); 739255570Strasz} 740255570Strasz 741273635Smavint 742273635Smavisns_new(struct conf *conf, const char *addr) 743273635Smav{ 744273635Smav struct isns *isns; 745273635Smav 746273635Smav isns = calloc(1, sizeof(*isns)); 747273635Smav if (isns == NULL) 748273635Smav log_err(1, "calloc"); 749273635Smav isns->i_conf = conf; 750273635Smav TAILQ_INSERT_TAIL(&conf->conf_isns, isns, i_next); 751273635Smav isns->i_addr = checked_strdup(addr); 752273635Smav 753273635Smav if (parse_addr_port(isns->i_addr, "3205", &isns->i_ai)) { 754273635Smav log_warnx("invalid iSNS address %s", isns->i_addr); 755273635Smav isns_delete(isns); 756273635Smav return (1); 757273635Smav } 758273635Smav 759273635Smav /* 760273635Smav * XXX: getaddrinfo(3) may return multiple addresses; we should turn 761273635Smav * those into multiple servers. 762273635Smav */ 763273635Smav 764273635Smav return (0); 765273635Smav} 766273635Smav 767273635Smavvoid 768273635Smavisns_delete(struct isns *isns) 769273635Smav{ 770273635Smav 771273635Smav TAILQ_REMOVE(&isns->i_conf->conf_isns, isns, i_next); 772273635Smav free(isns->i_addr); 773273635Smav if (isns->i_ai != NULL) 774273635Smav freeaddrinfo(isns->i_ai); 775273635Smav free(isns); 776273635Smav} 777273635Smav 778273635Smavstatic int 779273635Smavisns_do_connect(struct isns *isns) 780273635Smav{ 781273635Smav int s; 782273635Smav 783273635Smav s = socket(isns->i_ai->ai_family, isns->i_ai->ai_socktype, 784273635Smav isns->i_ai->ai_protocol); 785273635Smav if (s < 0) { 786273635Smav log_warn("socket(2) failed for %s", isns->i_addr); 787273635Smav return (-1); 788273635Smav } 789273635Smav if (connect(s, isns->i_ai->ai_addr, isns->i_ai->ai_addrlen)) { 790273635Smav log_warn("connect(2) failed for %s", isns->i_addr); 791273635Smav close(s); 792273635Smav return (-1); 793273635Smav } 794273635Smav return(s); 795273635Smav} 796273635Smav 797273635Smavstatic int 798273635Smavisns_do_register(struct isns *isns, int s, const char *hostname) 799273635Smav{ 800273635Smav struct conf *conf = isns->i_conf; 801273635Smav struct target *target; 802273635Smav struct portal *portal; 803273635Smav struct portal_group *pg; 804278322Smav struct port *port; 805273635Smav struct isns_req *req; 806273635Smav int res = 0; 807273635Smav uint32_t error; 808273635Smav 809273635Smav req = isns_req_create(ISNS_FUNC_DEVATTRREG, ISNS_FLAG_CLIENT); 810273635Smav isns_req_add_str(req, 32, TAILQ_FIRST(&conf->conf_targets)->t_name); 811273635Smav isns_req_add_delim(req); 812273635Smav isns_req_add_str(req, 1, hostname); 813273635Smav isns_req_add_32(req, 2, 2); /* 2 -- iSCSI */ 814273635Smav isns_req_add_32(req, 6, conf->conf_isns_period); 815273635Smav TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 816273635Smav if (pg->pg_unassigned) 817273635Smav continue; 818273635Smav TAILQ_FOREACH(portal, &pg->pg_portals, p_next) { 819273635Smav isns_req_add_addr(req, 16, portal->p_ai); 820273635Smav isns_req_add_port(req, 17, portal->p_ai); 821273635Smav } 822273635Smav } 823273635Smav TAILQ_FOREACH(target, &conf->conf_targets, t_next) { 824273635Smav isns_req_add_str(req, 32, target->t_name); 825273635Smav isns_req_add_32(req, 33, 1); /* 1 -- Target*/ 826273635Smav if (target->t_alias != NULL) 827273635Smav isns_req_add_str(req, 34, target->t_alias); 828278322Smav TAILQ_FOREACH(port, &target->t_ports, p_ts) { 829278322Smav if ((pg = port->p_portal_group) == NULL) 830278322Smav continue; 831278322Smav isns_req_add_32(req, 51, pg->pg_tag); 832278322Smav TAILQ_FOREACH(portal, &pg->pg_portals, p_next) { 833278322Smav isns_req_add_addr(req, 49, portal->p_ai); 834278322Smav isns_req_add_port(req, 50, portal->p_ai); 835278322Smav } 836273635Smav } 837273635Smav } 838273635Smav res = isns_req_send(s, req); 839273635Smav if (res < 0) { 840273635Smav log_warn("send(2) failed for %s", isns->i_addr); 841273635Smav goto quit; 842273635Smav } 843273635Smav res = isns_req_receive(s, req); 844273635Smav if (res < 0) { 845273635Smav log_warn("receive(2) failed for %s", isns->i_addr); 846273635Smav goto quit; 847273635Smav } 848273635Smav error = isns_req_get_status(req); 849273635Smav if (error != 0) { 850273635Smav log_warnx("iSNS register error %d for %s", error, isns->i_addr); 851273635Smav res = -1; 852273635Smav } 853273635Smavquit: 854273635Smav isns_req_free(req); 855273635Smav return (res); 856273635Smav} 857273635Smav 858273635Smavstatic int 859273635Smavisns_do_check(struct isns *isns, int s, const char *hostname) 860273635Smav{ 861273635Smav struct conf *conf = isns->i_conf; 862273635Smav struct isns_req *req; 863273635Smav int res = 0; 864273635Smav uint32_t error; 865273635Smav 866273635Smav req = isns_req_create(ISNS_FUNC_DEVATTRQRY, ISNS_FLAG_CLIENT); 867273635Smav isns_req_add_str(req, 32, TAILQ_FIRST(&conf->conf_targets)->t_name); 868273635Smav isns_req_add_str(req, 1, hostname); 869273635Smav isns_req_add_delim(req); 870273635Smav isns_req_add(req, 2, 0, NULL); 871273635Smav res = isns_req_send(s, req); 872273635Smav if (res < 0) { 873273635Smav log_warn("send(2) failed for %s", isns->i_addr); 874273635Smav goto quit; 875273635Smav } 876273635Smav res = isns_req_receive(s, req); 877273635Smav if (res < 0) { 878273635Smav log_warn("receive(2) failed for %s", isns->i_addr); 879273635Smav goto quit; 880273635Smav } 881273635Smav error = isns_req_get_status(req); 882273635Smav if (error != 0) { 883273635Smav log_warnx("iSNS check error %d for %s", error, isns->i_addr); 884273635Smav res = -1; 885273635Smav } 886273635Smavquit: 887273635Smav isns_req_free(req); 888273635Smav return (res); 889273635Smav} 890273635Smav 891273635Smavstatic int 892273635Smavisns_do_deregister(struct isns *isns, int s, const char *hostname) 893273635Smav{ 894273635Smav struct conf *conf = isns->i_conf; 895273635Smav struct isns_req *req; 896273635Smav int res = 0; 897273635Smav uint32_t error; 898273635Smav 899273635Smav req = isns_req_create(ISNS_FUNC_DEVDEREG, ISNS_FLAG_CLIENT); 900273635Smav isns_req_add_str(req, 32, TAILQ_FIRST(&conf->conf_targets)->t_name); 901273635Smav isns_req_add_delim(req); 902273635Smav isns_req_add_str(req, 1, hostname); 903273635Smav res = isns_req_send(s, req); 904273635Smav if (res < 0) { 905273635Smav log_warn("send(2) failed for %s", isns->i_addr); 906273635Smav goto quit; 907273635Smav } 908273635Smav res = isns_req_receive(s, req); 909273635Smav if (res < 0) { 910273635Smav log_warn("receive(2) failed for %s", isns->i_addr); 911273635Smav goto quit; 912273635Smav } 913273635Smav error = isns_req_get_status(req); 914273635Smav if (error != 0) { 915273635Smav log_warnx("iSNS deregister error %d for %s", error, isns->i_addr); 916273635Smav res = -1; 917273635Smav } 918273635Smavquit: 919273635Smav isns_req_free(req); 920273635Smav return (res); 921273635Smav} 922273635Smav 923273635Smavvoid 924273635Smavisns_register(struct isns *isns, struct isns *oldisns) 925273635Smav{ 926273635Smav struct conf *conf = isns->i_conf; 927274248Smav int s; 928273635Smav char hostname[256]; 929273635Smav 930273635Smav if (TAILQ_EMPTY(&conf->conf_targets) || 931273635Smav TAILQ_EMPTY(&conf->conf_portal_groups)) 932273635Smav return; 933273635Smav set_timeout(conf->conf_isns_timeout, false); 934273635Smav s = isns_do_connect(isns); 935273635Smav if (s < 0) { 936273635Smav set_timeout(0, false); 937273635Smav return; 938273635Smav } 939273635Smav gethostname(hostname, sizeof(hostname)); 940273635Smav 941273635Smav if (oldisns == NULL || TAILQ_EMPTY(&oldisns->i_conf->conf_targets)) 942273635Smav oldisns = isns; 943274248Smav isns_do_deregister(oldisns, s, hostname); 944274248Smav isns_do_register(isns, s, hostname); 945273635Smav close(s); 946273635Smav set_timeout(0, false); 947273635Smav} 948273635Smav 949273635Smavvoid 950273635Smavisns_check(struct isns *isns) 951273635Smav{ 952273635Smav struct conf *conf = isns->i_conf; 953273635Smav int s, res; 954273635Smav char hostname[256]; 955273635Smav 956273635Smav if (TAILQ_EMPTY(&conf->conf_targets) || 957273635Smav TAILQ_EMPTY(&conf->conf_portal_groups)) 958273635Smav return; 959273635Smav set_timeout(conf->conf_isns_timeout, false); 960273635Smav s = isns_do_connect(isns); 961273635Smav if (s < 0) { 962273635Smav set_timeout(0, false); 963273635Smav return; 964273635Smav } 965273635Smav gethostname(hostname, sizeof(hostname)); 966273635Smav 967273635Smav res = isns_do_check(isns, s, hostname); 968273635Smav if (res < 0) { 969274248Smav isns_do_deregister(isns, s, hostname); 970274248Smav isns_do_register(isns, s, hostname); 971273635Smav } 972273635Smav close(s); 973273635Smav set_timeout(0, false); 974273635Smav} 975273635Smav 976273635Smavvoid 977273635Smavisns_deregister(struct isns *isns) 978273635Smav{ 979273635Smav struct conf *conf = isns->i_conf; 980274248Smav int s; 981273635Smav char hostname[256]; 982273635Smav 983273635Smav if (TAILQ_EMPTY(&conf->conf_targets) || 984273635Smav TAILQ_EMPTY(&conf->conf_portal_groups)) 985273635Smav return; 986273635Smav set_timeout(conf->conf_isns_timeout, false); 987273635Smav s = isns_do_connect(isns); 988273635Smav if (s < 0) 989273635Smav return; 990273635Smav gethostname(hostname, sizeof(hostname)); 991273635Smav 992274248Smav isns_do_deregister(isns, s, hostname); 993273635Smav close(s); 994273635Smav set_timeout(0, false); 995273635Smav} 996273635Smav 997273813Straszint 998273816Straszportal_group_set_filter(struct portal_group *pg, const char *str) 999273813Strasz{ 1000273816Strasz int filter; 1001273813Strasz 1002273813Strasz if (strcmp(str, "none") == 0) { 1003273813Strasz filter = PG_FILTER_NONE; 1004273813Strasz } else if (strcmp(str, "portal") == 0) { 1005273813Strasz filter = PG_FILTER_PORTAL; 1006273813Strasz } else if (strcmp(str, "portal-name") == 0) { 1007273813Strasz filter = PG_FILTER_PORTAL_NAME; 1008273813Strasz } else if (strcmp(str, "portal-name-auth") == 0) { 1009273813Strasz filter = PG_FILTER_PORTAL_NAME_AUTH; 1010273813Strasz } else { 1011273813Strasz log_warnx("invalid discovery-filter \"%s\" for portal-group " 1012273813Strasz "\"%s\"; valid values are \"none\", \"portal\", " 1013273813Strasz "\"portal-name\", and \"portal-name-auth\"", 1014273813Strasz str, pg->pg_name); 1015273813Strasz return (1); 1016273813Strasz } 1017273813Strasz 1018273816Strasz if (pg->pg_discovery_filter != PG_FILTER_UNKNOWN && 1019273816Strasz pg->pg_discovery_filter != filter) { 1020273813Strasz log_warnx("cannot set discovery-filter to \"%s\" for " 1021273813Strasz "portal-group \"%s\"; already has a different " 1022273813Strasz "value", str, pg->pg_name); 1023273813Strasz return (1); 1024273813Strasz } 1025273813Strasz 1026273816Strasz pg->pg_discovery_filter = filter; 1027273816Strasz 1028273816Strasz return (0); 1029273813Strasz} 1030273813Strasz 1031274308Straszint 1032279392Straszportal_group_set_offload(struct portal_group *pg, const char *offload) 1033279392Strasz{ 1034279392Strasz 1035279392Strasz if (pg->pg_offload != NULL) { 1036279392Strasz log_warnx("cannot set offload to \"%s\" for " 1037279392Strasz "portal-group \"%s\"; already defined", 1038279392Strasz offload, pg->pg_name); 1039279392Strasz return (1); 1040279392Strasz } 1041279392Strasz 1042279392Strasz pg->pg_offload = checked_strdup(offload); 1043279392Strasz 1044279392Strasz return (0); 1045279392Strasz} 1046279392Strasz 1047279392Straszint 1048274308Straszportal_group_set_redirection(struct portal_group *pg, const char *addr) 1049274308Strasz{ 1050274308Strasz 1051274308Strasz if (pg->pg_redirection != NULL) { 1052274308Strasz log_warnx("cannot set redirection to \"%s\" for " 1053274308Strasz "portal-group \"%s\"; already defined", 1054274308Strasz addr, pg->pg_name); 1055274308Strasz return (1); 1056274308Strasz } 1057274308Strasz 1058274308Strasz pg->pg_redirection = checked_strdup(addr); 1059274308Strasz 1060274308Strasz return (0); 1061274308Strasz} 1062274308Strasz 1063255570Straszstatic bool 1064255570Straszvalid_hex(const char ch) 1065255570Strasz{ 1066255570Strasz switch (ch) { 1067255570Strasz case '0': 1068255570Strasz case '1': 1069255570Strasz case '2': 1070255570Strasz case '3': 1071255570Strasz case '4': 1072255570Strasz case '5': 1073255570Strasz case '6': 1074255570Strasz case '7': 1075255570Strasz case '8': 1076255570Strasz case '9': 1077255570Strasz case 'a': 1078255570Strasz case 'A': 1079255570Strasz case 'b': 1080255570Strasz case 'B': 1081255570Strasz case 'c': 1082255570Strasz case 'C': 1083255570Strasz case 'd': 1084255570Strasz case 'D': 1085255570Strasz case 'e': 1086255570Strasz case 'E': 1087255570Strasz case 'f': 1088255570Strasz case 'F': 1089255570Strasz return (true); 1090255570Strasz default: 1091255570Strasz return (false); 1092255570Strasz } 1093255570Strasz} 1094255570Strasz 1095255570Straszbool 1096255570Straszvalid_iscsi_name(const char *name) 1097255570Strasz{ 1098255570Strasz int i; 1099255570Strasz 1100255570Strasz if (strlen(name) >= MAX_NAME_LEN) { 1101255570Strasz log_warnx("overlong name for target \"%s\"; max length allowed " 1102255570Strasz "by iSCSI specification is %d characters", 1103255570Strasz name, MAX_NAME_LEN); 1104255570Strasz return (false); 1105255570Strasz } 1106255570Strasz 1107255570Strasz /* 1108255570Strasz * In the cases below, we don't return an error, just in case the admin 1109255570Strasz * was right, and we're wrong. 1110255570Strasz */ 1111255570Strasz if (strncasecmp(name, "iqn.", strlen("iqn.")) == 0) { 1112255570Strasz for (i = strlen("iqn."); name[i] != '\0'; i++) { 1113255570Strasz /* 1114255570Strasz * XXX: We should verify UTF-8 normalisation, as defined 1115273464Strasz * by 3.2.6.2: iSCSI Name Encoding. 1116255570Strasz */ 1117255570Strasz if (isalnum(name[i])) 1118255570Strasz continue; 1119255570Strasz if (name[i] == '-' || name[i] == '.' || name[i] == ':') 1120255570Strasz continue; 1121255570Strasz log_warnx("invalid character \"%c\" in target name " 1122255570Strasz "\"%s\"; allowed characters are letters, digits, " 1123255570Strasz "'-', '.', and ':'", name[i], name); 1124255570Strasz break; 1125255570Strasz } 1126255570Strasz /* 1127255570Strasz * XXX: Check more stuff: valid date and a valid reversed domain. 1128255570Strasz */ 1129255570Strasz } else if (strncasecmp(name, "eui.", strlen("eui.")) == 0) { 1130255570Strasz if (strlen(name) != strlen("eui.") + 16) 1131255570Strasz log_warnx("invalid target name \"%s\"; the \"eui.\" " 1132255570Strasz "should be followed by exactly 16 hexadecimal " 1133255570Strasz "digits", name); 1134255570Strasz for (i = strlen("eui."); name[i] != '\0'; i++) { 1135255570Strasz if (!valid_hex(name[i])) { 1136255570Strasz log_warnx("invalid character \"%c\" in target " 1137255570Strasz "name \"%s\"; allowed characters are 1-9 " 1138255570Strasz "and A-F", name[i], name); 1139255570Strasz break; 1140255570Strasz } 1141255570Strasz } 1142255570Strasz } else if (strncasecmp(name, "naa.", strlen("naa.")) == 0) { 1143255570Strasz if (strlen(name) > strlen("naa.") + 32) 1144255570Strasz log_warnx("invalid target name \"%s\"; the \"naa.\" " 1145255570Strasz "should be followed by at most 32 hexadecimal " 1146255570Strasz "digits", name); 1147255570Strasz for (i = strlen("naa."); name[i] != '\0'; i++) { 1148255570Strasz if (!valid_hex(name[i])) { 1149255570Strasz log_warnx("invalid character \"%c\" in target " 1150255570Strasz "name \"%s\"; allowed characters are 1-9 " 1151255570Strasz "and A-F", name[i], name); 1152255570Strasz break; 1153255570Strasz } 1154255570Strasz } 1155255570Strasz } else { 1156255570Strasz log_warnx("invalid target name \"%s\"; should start with " 1157288208Sjpaetzel "either \"iqn.\", \"eui.\", or \"naa.\"", 1158255570Strasz name); 1159255570Strasz } 1160255570Strasz return (true); 1161255570Strasz} 1162255570Strasz 1163278354Smavstruct pport * 1164278354Smavpport_new(struct conf *conf, const char *name, uint32_t ctl_port) 1165278354Smav{ 1166278354Smav struct pport *pp; 1167278354Smav 1168278354Smav pp = calloc(1, sizeof(*pp)); 1169278354Smav if (pp == NULL) 1170278354Smav log_err(1, "calloc"); 1171278354Smav pp->pp_conf = conf; 1172278354Smav pp->pp_name = checked_strdup(name); 1173278354Smav pp->pp_ctl_port = ctl_port; 1174278354Smav TAILQ_INIT(&pp->pp_ports); 1175278354Smav TAILQ_INSERT_TAIL(&conf->conf_pports, pp, pp_next); 1176278354Smav return (pp); 1177278354Smav} 1178278354Smav 1179278354Smavstruct pport * 1180278354Smavpport_find(const struct conf *conf, const char *name) 1181278354Smav{ 1182278354Smav struct pport *pp; 1183278354Smav 1184278354Smav TAILQ_FOREACH(pp, &conf->conf_pports, pp_next) { 1185278354Smav if (strcasecmp(pp->pp_name, name) == 0) 1186278354Smav return (pp); 1187278354Smav } 1188278354Smav return (NULL); 1189278354Smav} 1190278354Smav 1191278354Smavstruct pport * 1192278354Smavpport_copy(struct pport *pp, struct conf *conf) 1193278354Smav{ 1194278354Smav struct pport *ppnew; 1195278354Smav 1196278354Smav ppnew = pport_new(conf, pp->pp_name, pp->pp_ctl_port); 1197278354Smav return (ppnew); 1198278354Smav} 1199278354Smav 1200278354Smavvoid 1201278354Smavpport_delete(struct pport *pp) 1202278354Smav{ 1203278354Smav struct port *port, *tport; 1204278354Smav 1205278354Smav TAILQ_FOREACH_SAFE(port, &pp->pp_ports, p_ts, tport) 1206278354Smav port_delete(port); 1207278354Smav TAILQ_REMOVE(&pp->pp_conf->conf_pports, pp, pp_next); 1208278354Smav free(pp->pp_name); 1209278354Smav free(pp); 1210278354Smav} 1211278354Smav 1212278322Smavstruct port * 1213278322Smavport_new(struct conf *conf, struct target *target, struct portal_group *pg) 1214278322Smav{ 1215278322Smav struct port *port; 1216278354Smav char *name; 1217278594Smav int ret; 1218278322Smav 1219278594Smav ret = asprintf(&name, "%s-%s", pg->pg_name, target->t_name); 1220278594Smav if (ret <= 0) 1221278594Smav log_err(1, "asprintf"); 1222278354Smav if (port_find(conf, name) != NULL) { 1223278354Smav log_warnx("duplicate port \"%s\"", name); 1224278354Smav free(name); 1225278354Smav return (NULL); 1226278354Smav } 1227278322Smav port = calloc(1, sizeof(*port)); 1228278322Smav if (port == NULL) 1229278322Smav log_err(1, "calloc"); 1230278322Smav port->p_conf = conf; 1231278354Smav port->p_name = name; 1232278322Smav TAILQ_INSERT_TAIL(&conf->conf_ports, port, p_next); 1233278322Smav TAILQ_INSERT_TAIL(&target->t_ports, port, p_ts); 1234278322Smav port->p_target = target; 1235278322Smav TAILQ_INSERT_TAIL(&pg->pg_ports, port, p_pgs); 1236278322Smav port->p_portal_group = pg; 1237287534Smav port->p_foreign = pg->pg_foreign; 1238278322Smav return (port); 1239278322Smav} 1240278322Smav 1241278322Smavstruct port * 1242278354Smavport_new_pp(struct conf *conf, struct target *target, struct pport *pp) 1243278354Smav{ 1244278354Smav struct port *port; 1245278354Smav char *name; 1246278594Smav int ret; 1247278354Smav 1248278594Smav ret = asprintf(&name, "%s-%s", pp->pp_name, target->t_name); 1249278594Smav if (ret <= 0) 1250278594Smav log_err(1, "asprintf"); 1251278354Smav if (port_find(conf, name) != NULL) { 1252278354Smav log_warnx("duplicate port \"%s\"", name); 1253278354Smav free(name); 1254278354Smav return (NULL); 1255278354Smav } 1256278354Smav port = calloc(1, sizeof(*port)); 1257278354Smav if (port == NULL) 1258278354Smav log_err(1, "calloc"); 1259278354Smav port->p_conf = conf; 1260278354Smav port->p_name = name; 1261278354Smav TAILQ_INSERT_TAIL(&conf->conf_ports, port, p_next); 1262278354Smav TAILQ_INSERT_TAIL(&target->t_ports, port, p_ts); 1263278354Smav port->p_target = target; 1264278354Smav TAILQ_INSERT_TAIL(&pp->pp_ports, port, p_pps); 1265278354Smav port->p_pport = pp; 1266278354Smav return (port); 1267278354Smav} 1268278354Smav 1269278354Smavstruct port * 1270278322Smavport_find(const struct conf *conf, const char *name) 1271278322Smav{ 1272278322Smav struct port *port; 1273278322Smav 1274278322Smav TAILQ_FOREACH(port, &conf->conf_ports, p_next) { 1275278322Smav if (strcasecmp(port->p_name, name) == 0) 1276278322Smav return (port); 1277278322Smav } 1278278322Smav 1279278322Smav return (NULL); 1280278322Smav} 1281278322Smav 1282278322Smavstruct port * 1283278322Smavport_find_in_pg(const struct portal_group *pg, const char *target) 1284278322Smav{ 1285278322Smav struct port *port; 1286278322Smav 1287278322Smav TAILQ_FOREACH(port, &pg->pg_ports, p_pgs) { 1288278322Smav if (strcasecmp(port->p_target->t_name, target) == 0) 1289278322Smav return (port); 1290278322Smav } 1291278322Smav 1292278322Smav return (NULL); 1293278322Smav} 1294278322Smav 1295278322Smavvoid 1296278322Smavport_delete(struct port *port) 1297278322Smav{ 1298278322Smav 1299278322Smav if (port->p_portal_group) 1300278322Smav TAILQ_REMOVE(&port->p_portal_group->pg_ports, port, p_pgs); 1301278354Smav if (port->p_pport) 1302278354Smav TAILQ_REMOVE(&port->p_pport->pp_ports, port, p_pps); 1303278322Smav if (port->p_target) 1304278322Smav TAILQ_REMOVE(&port->p_target->t_ports, port, p_ts); 1305278322Smav TAILQ_REMOVE(&port->p_conf->conf_ports, port, p_next); 1306278322Smav free(port->p_name); 1307278322Smav free(port); 1308278322Smav} 1309278322Smav 1310255570Straszstruct target * 1311261757Strasztarget_new(struct conf *conf, const char *name) 1312255570Strasz{ 1313255570Strasz struct target *targ; 1314255570Strasz int i, len; 1315255570Strasz 1316261757Strasz targ = target_find(conf, name); 1317255570Strasz if (targ != NULL) { 1318261757Strasz log_warnx("duplicated target \"%s\"", name); 1319255570Strasz return (NULL); 1320255570Strasz } 1321261757Strasz if (valid_iscsi_name(name) == false) { 1322261757Strasz log_warnx("target name \"%s\" is invalid", name); 1323255570Strasz return (NULL); 1324255570Strasz } 1325255570Strasz targ = calloc(1, sizeof(*targ)); 1326255570Strasz if (targ == NULL) 1327255570Strasz log_err(1, "calloc"); 1328261757Strasz targ->t_name = checked_strdup(name); 1329255570Strasz 1330255570Strasz /* 1331255570Strasz * RFC 3722 requires us to normalize the name to lowercase. 1332255570Strasz */ 1333261757Strasz len = strlen(name); 1334255570Strasz for (i = 0; i < len; i++) 1335261757Strasz targ->t_name[i] = tolower(targ->t_name[i]); 1336255570Strasz 1337255570Strasz targ->t_conf = conf; 1338278322Smav TAILQ_INIT(&targ->t_ports); 1339255570Strasz TAILQ_INSERT_TAIL(&conf->conf_targets, targ, t_next); 1340255570Strasz 1341255570Strasz return (targ); 1342255570Strasz} 1343255570Strasz 1344255570Straszvoid 1345255570Strasztarget_delete(struct target *targ) 1346255570Strasz{ 1347278322Smav struct port *port, *tport; 1348255570Strasz 1349278322Smav TAILQ_FOREACH_SAFE(port, &targ->t_ports, p_ts, tport) 1350278322Smav port_delete(port); 1351255570Strasz TAILQ_REMOVE(&targ->t_conf->conf_targets, targ, t_next); 1352255570Strasz 1353261757Strasz free(targ->t_name); 1354274308Strasz free(targ->t_redirection); 1355255570Strasz free(targ); 1356255570Strasz} 1357255570Strasz 1358255570Straszstruct target * 1359261757Strasztarget_find(struct conf *conf, const char *name) 1360255570Strasz{ 1361255570Strasz struct target *targ; 1362255570Strasz 1363255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 1364261757Strasz if (strcasecmp(targ->t_name, name) == 0) 1365255570Strasz return (targ); 1366255570Strasz } 1367255570Strasz 1368255570Strasz return (NULL); 1369255570Strasz} 1370255570Strasz 1371274308Straszint 1372274308Strasztarget_set_redirection(struct target *target, const char *addr) 1373274308Strasz{ 1374274308Strasz 1375274308Strasz if (target->t_redirection != NULL) { 1376274308Strasz log_warnx("cannot set redirection to \"%s\" for " 1377274308Strasz "target \"%s\"; already defined", 1378274308Strasz addr, target->t_name); 1379274308Strasz return (1); 1380274308Strasz } 1381274308Strasz 1382274308Strasz target->t_redirection = checked_strdup(addr); 1383274308Strasz 1384274308Strasz return (0); 1385274308Strasz} 1386274308Strasz 1387255570Straszstruct lun * 1388278037Smavlun_new(struct conf *conf, const char *name) 1389255570Strasz{ 1390255570Strasz struct lun *lun; 1391255570Strasz 1392278037Smav lun = lun_find(conf, name); 1393255570Strasz if (lun != NULL) { 1394278037Smav log_warnx("duplicated lun \"%s\"", name); 1395255570Strasz return (NULL); 1396255570Strasz } 1397255570Strasz 1398255570Strasz lun = calloc(1, sizeof(*lun)); 1399255570Strasz if (lun == NULL) 1400255570Strasz log_err(1, "calloc"); 1401278037Smav lun->l_conf = conf; 1402278037Smav lun->l_name = checked_strdup(name); 1403255570Strasz TAILQ_INIT(&lun->l_options); 1404278037Smav TAILQ_INSERT_TAIL(&conf->conf_luns, lun, l_next); 1405287823Smav lun->l_ctl_lun = -1; 1406255570Strasz 1407255570Strasz return (lun); 1408255570Strasz} 1409255570Strasz 1410255570Straszvoid 1411255570Straszlun_delete(struct lun *lun) 1412255570Strasz{ 1413278037Smav struct target *targ; 1414290615Smav struct option *o, *tmp; 1415278037Smav int i; 1416255570Strasz 1417278037Smav TAILQ_FOREACH(targ, &lun->l_conf->conf_targets, t_next) { 1418278037Smav for (i = 0; i < MAX_LUNS; i++) { 1419278037Smav if (targ->t_luns[i] == lun) 1420278037Smav targ->t_luns[i] = NULL; 1421278037Smav } 1422278037Smav } 1423278037Smav TAILQ_REMOVE(&lun->l_conf->conf_luns, lun, l_next); 1424255570Strasz 1425290615Smav TAILQ_FOREACH_SAFE(o, &lun->l_options, o_next, tmp) 1426290615Smav option_delete(&lun->l_options, o); 1427278037Smav free(lun->l_name); 1428255570Strasz free(lun->l_backend); 1429255570Strasz free(lun->l_device_id); 1430255570Strasz free(lun->l_path); 1431278037Smav free(lun->l_scsiname); 1432255570Strasz free(lun->l_serial); 1433255570Strasz free(lun); 1434255570Strasz} 1435255570Strasz 1436255570Straszstruct lun * 1437278037Smavlun_find(const struct conf *conf, const char *name) 1438255570Strasz{ 1439255570Strasz struct lun *lun; 1440255570Strasz 1441278037Smav TAILQ_FOREACH(lun, &conf->conf_luns, l_next) { 1442278037Smav if (strcmp(lun->l_name, name) == 0) 1443255570Strasz return (lun); 1444255570Strasz } 1445255570Strasz 1446255570Strasz return (NULL); 1447255570Strasz} 1448255570Strasz 1449255570Straszvoid 1450255570Straszlun_set_backend(struct lun *lun, const char *value) 1451255570Strasz{ 1452255570Strasz free(lun->l_backend); 1453255570Strasz lun->l_backend = checked_strdup(value); 1454255570Strasz} 1455255570Strasz 1456255570Straszvoid 1457255570Straszlun_set_blocksize(struct lun *lun, size_t value) 1458255570Strasz{ 1459255570Strasz 1460255570Strasz lun->l_blocksize = value; 1461255570Strasz} 1462255570Strasz 1463255570Straszvoid 1464288310Smavlun_set_device_type(struct lun *lun, uint8_t value) 1465288310Smav{ 1466288310Smav 1467288310Smav lun->l_device_type = value; 1468288310Smav} 1469288310Smav 1470288310Smavvoid 1471255570Straszlun_set_device_id(struct lun *lun, const char *value) 1472255570Strasz{ 1473255570Strasz free(lun->l_device_id); 1474255570Strasz lun->l_device_id = checked_strdup(value); 1475255570Strasz} 1476255570Strasz 1477255570Straszvoid 1478255570Straszlun_set_path(struct lun *lun, const char *value) 1479255570Strasz{ 1480255570Strasz free(lun->l_path); 1481255570Strasz lun->l_path = checked_strdup(value); 1482255570Strasz} 1483255570Strasz 1484255570Straszvoid 1485278037Smavlun_set_scsiname(struct lun *lun, const char *value) 1486278037Smav{ 1487278037Smav free(lun->l_scsiname); 1488278037Smav lun->l_scsiname = checked_strdup(value); 1489278037Smav} 1490278037Smav 1491278037Smavvoid 1492255570Straszlun_set_serial(struct lun *lun, const char *value) 1493255570Strasz{ 1494255570Strasz free(lun->l_serial); 1495255570Strasz lun->l_serial = checked_strdup(value); 1496255570Strasz} 1497255570Strasz 1498255570Straszvoid 1499255570Straszlun_set_size(struct lun *lun, size_t value) 1500255570Strasz{ 1501255570Strasz 1502255570Strasz lun->l_size = value; 1503255570Strasz} 1504255570Strasz 1505255570Straszvoid 1506255570Straszlun_set_ctl_lun(struct lun *lun, uint32_t value) 1507255570Strasz{ 1508255570Strasz 1509255570Strasz lun->l_ctl_lun = value; 1510255570Strasz} 1511255570Strasz 1512290615Smavstruct option * 1513290615Smavoption_new(struct options *options, const char *name, const char *value) 1514255570Strasz{ 1515290615Smav struct option *o; 1516255570Strasz 1517290615Smav o = option_find(options, name); 1518290615Smav if (o != NULL) { 1519290615Smav log_warnx("duplicated option \"%s\"", name); 1520255570Strasz return (NULL); 1521255570Strasz } 1522255570Strasz 1523290615Smav o = calloc(1, sizeof(*o)); 1524290615Smav if (o == NULL) 1525255570Strasz log_err(1, "calloc"); 1526290615Smav o->o_name = checked_strdup(name); 1527290615Smav o->o_value = checked_strdup(value); 1528290615Smav TAILQ_INSERT_TAIL(options, o, o_next); 1529255570Strasz 1530290615Smav return (o); 1531255570Strasz} 1532255570Strasz 1533255570Straszvoid 1534290615Smavoption_delete(struct options *options, struct option *o) 1535255570Strasz{ 1536255570Strasz 1537290615Smav TAILQ_REMOVE(options, o, o_next); 1538290615Smav free(o->o_name); 1539290615Smav free(o->o_value); 1540290615Smav free(o); 1541255570Strasz} 1542255570Strasz 1543290615Smavstruct option * 1544290615Smavoption_find(const struct options *options, const char *name) 1545255570Strasz{ 1546290615Smav struct option *o; 1547255570Strasz 1548290615Smav TAILQ_FOREACH(o, options, o_next) { 1549290615Smav if (strcmp(o->o_name, name) == 0) 1550290615Smav return (o); 1551255570Strasz } 1552255570Strasz 1553255570Strasz return (NULL); 1554255570Strasz} 1555255570Strasz 1556255570Straszvoid 1557290615Smavoption_set(struct option *o, const char *value) 1558255570Strasz{ 1559255570Strasz 1560290615Smav free(o->o_value); 1561290615Smav o->o_value = checked_strdup(value); 1562255570Strasz} 1563255570Strasz 1564255570Straszstatic struct connection * 1565269183Smavconnection_new(struct portal *portal, int fd, const char *host, 1566269183Smav const struct sockaddr *client_sa) 1567255570Strasz{ 1568255570Strasz struct connection *conn; 1569255570Strasz 1570255570Strasz conn = calloc(1, sizeof(*conn)); 1571255570Strasz if (conn == NULL) 1572255570Strasz log_err(1, "calloc"); 1573255570Strasz conn->conn_portal = portal; 1574255570Strasz conn->conn_socket = fd; 1575255570Strasz conn->conn_initiator_addr = checked_strdup(host); 1576269183Smav memcpy(&conn->conn_initiator_sa, client_sa, client_sa->sa_len); 1577255570Strasz 1578255570Strasz /* 1579255570Strasz * Default values, from RFC 3720, section 12. 1580255570Strasz */ 1581255570Strasz conn->conn_max_data_segment_length = 8192; 1582255570Strasz conn->conn_max_burst_length = 262144; 1583255570Strasz conn->conn_immediate_data = true; 1584255570Strasz 1585255570Strasz return (conn); 1586255570Strasz} 1587255570Strasz 1588255570Strasz#if 0 1589255570Straszstatic void 1590255570Straszconf_print(struct conf *conf) 1591255570Strasz{ 1592255570Strasz struct auth_group *ag; 1593255570Strasz struct auth *auth; 1594261754Strasz struct auth_name *auth_name; 1595261754Strasz struct auth_portal *auth_portal; 1596255570Strasz struct portal_group *pg; 1597255570Strasz struct portal *portal; 1598255570Strasz struct target *targ; 1599255570Strasz struct lun *lun; 1600290615Smav struct option *o; 1601255570Strasz 1602255570Strasz TAILQ_FOREACH(ag, &conf->conf_auth_groups, ag_next) { 1603255570Strasz fprintf(stderr, "auth-group %s {\n", ag->ag_name); 1604255570Strasz TAILQ_FOREACH(auth, &ag->ag_auths, a_next) 1605255570Strasz fprintf(stderr, "\t chap-mutual %s %s %s %s\n", 1606255570Strasz auth->a_user, auth->a_secret, 1607255570Strasz auth->a_mutual_user, auth->a_mutual_secret); 1608261754Strasz TAILQ_FOREACH(auth_name, &ag->ag_names, an_next) 1609261754Strasz fprintf(stderr, "\t initiator-name %s\n", 1610261754Strasz auth_name->an_initator_name); 1611261754Strasz TAILQ_FOREACH(auth_portal, &ag->ag_portals, an_next) 1612261754Strasz fprintf(stderr, "\t initiator-portal %s\n", 1613261754Strasz auth_portal->an_initator_portal); 1614255570Strasz fprintf(stderr, "}\n"); 1615255570Strasz } 1616255570Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 1617255570Strasz fprintf(stderr, "portal-group %s {\n", pg->pg_name); 1618255570Strasz TAILQ_FOREACH(portal, &pg->pg_portals, p_next) 1619255570Strasz fprintf(stderr, "\t listen %s\n", portal->p_listen); 1620255570Strasz fprintf(stderr, "}\n"); 1621255570Strasz } 1622278037Smav TAILQ_FOREACH(lun, &conf->conf_luns, l_next) { 1623278037Smav fprintf(stderr, "\tlun %s {\n", lun->l_name); 1624278037Smav fprintf(stderr, "\t\tpath %s\n", lun->l_path); 1625290615Smav TAILQ_FOREACH(o, &lun->l_options, o_next) 1626278037Smav fprintf(stderr, "\t\toption %s %s\n", 1627290615Smav lo->o_name, lo->o_value); 1628278037Smav fprintf(stderr, "\t}\n"); 1629278037Smav } 1630255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 1631261757Strasz fprintf(stderr, "target %s {\n", targ->t_name); 1632255570Strasz if (targ->t_alias != NULL) 1633255570Strasz fprintf(stderr, "\t alias %s\n", targ->t_alias); 1634255570Strasz fprintf(stderr, "}\n"); 1635255570Strasz } 1636255570Strasz} 1637255570Strasz#endif 1638255570Strasz 1639261749Straszstatic int 1640261749Straszconf_verify_lun(struct lun *lun) 1641261749Strasz{ 1642261749Strasz const struct lun *lun2; 1643261749Strasz 1644261749Strasz if (lun->l_backend == NULL) 1645261749Strasz lun_set_backend(lun, "block"); 1646261749Strasz if (strcmp(lun->l_backend, "block") == 0) { 1647261749Strasz if (lun->l_path == NULL) { 1648278037Smav log_warnx("missing path for lun \"%s\"", 1649278037Smav lun->l_name); 1650261749Strasz return (1); 1651261749Strasz } 1652261749Strasz } else if (strcmp(lun->l_backend, "ramdisk") == 0) { 1653261749Strasz if (lun->l_size == 0) { 1654278037Smav log_warnx("missing size for ramdisk-backed lun \"%s\"", 1655278037Smav lun->l_name); 1656261749Strasz return (1); 1657261749Strasz } 1658261749Strasz if (lun->l_path != NULL) { 1659261749Strasz log_warnx("path must not be specified " 1660278037Smav "for ramdisk-backed lun \"%s\"", 1661278037Smav lun->l_name); 1662261749Strasz return (1); 1663261749Strasz } 1664261749Strasz } 1665261749Strasz if (lun->l_blocksize == 0) { 1666288486Smav if (lun->l_device_type == 5) 1667288486Smav lun_set_blocksize(lun, DEFAULT_CD_BLOCKSIZE); 1668288486Smav else 1669288486Smav lun_set_blocksize(lun, DEFAULT_BLOCKSIZE); 1670261749Strasz } else if (lun->l_blocksize < 0) { 1671278037Smav log_warnx("invalid blocksize for lun \"%s\"; " 1672278037Smav "must be larger than 0", lun->l_name); 1673261749Strasz return (1); 1674261749Strasz } 1675261749Strasz if (lun->l_size != 0 && lun->l_size % lun->l_blocksize != 0) { 1676278037Smav log_warnx("invalid size for lun \"%s\"; " 1677278037Smav "must be multiple of blocksize", lun->l_name); 1678261749Strasz return (1); 1679261749Strasz } 1680278037Smav TAILQ_FOREACH(lun2, &lun->l_conf->conf_luns, l_next) { 1681278037Smav if (lun == lun2) 1682278037Smav continue; 1683278037Smav if (lun->l_path != NULL && lun2->l_path != NULL && 1684278037Smav strcmp(lun->l_path, lun2->l_path) == 0) { 1685278037Smav log_debugx("WARNING: path \"%s\" duplicated " 1686278037Smav "between lun \"%s\", and " 1687278037Smav "lun \"%s\"", lun->l_path, 1688278037Smav lun->l_name, lun2->l_name); 1689261750Strasz } 1690261750Strasz } 1691261749Strasz 1692261749Strasz return (0); 1693261749Strasz} 1694261749Strasz 1695255570Straszint 1696255570Straszconf_verify(struct conf *conf) 1697255570Strasz{ 1698255570Strasz struct auth_group *ag; 1699255570Strasz struct portal_group *pg; 1700278322Smav struct port *port; 1701255570Strasz struct target *targ; 1702261749Strasz struct lun *lun; 1703273465Strasz bool found; 1704278037Smav int error, i; 1705255570Strasz 1706255570Strasz if (conf->conf_pidfile_path == NULL) 1707255570Strasz conf->conf_pidfile_path = checked_strdup(DEFAULT_PIDFILE); 1708255570Strasz 1709278037Smav TAILQ_FOREACH(lun, &conf->conf_luns, l_next) { 1710278037Smav error = conf_verify_lun(lun); 1711278037Smav if (error != 0) 1712278037Smav return (error); 1713278037Smav } 1714255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 1715255570Strasz if (targ->t_auth_group == NULL) { 1716261760Strasz targ->t_auth_group = auth_group_find(conf, 1717261760Strasz "default"); 1718261760Strasz assert(targ->t_auth_group != NULL); 1719255570Strasz } 1720278322Smav if (TAILQ_EMPTY(&targ->t_ports)) { 1721278322Smav pg = portal_group_find(conf, "default"); 1722278322Smav assert(pg != NULL); 1723278322Smav port_new(conf, targ, pg); 1724255570Strasz } 1725273465Strasz found = false; 1726278037Smav for (i = 0; i < MAX_LUNS; i++) { 1727278037Smav if (targ->t_luns[i] != NULL) 1728278037Smav found = true; 1729255570Strasz } 1730274308Strasz if (!found && targ->t_redirection == NULL) { 1731264500Strasz log_warnx("no LUNs defined for target \"%s\"", 1732264500Strasz targ->t_name); 1733255570Strasz } 1734274308Strasz if (found && targ->t_redirection != NULL) { 1735274308Strasz log_debugx("target \"%s\" contains luns, " 1736274308Strasz " but configured for redirection", 1737274308Strasz targ->t_name); 1738274308Strasz } 1739255570Strasz } 1740255570Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 1741255570Strasz assert(pg->pg_name != NULL); 1742255570Strasz if (pg->pg_discovery_auth_group == NULL) { 1743255570Strasz pg->pg_discovery_auth_group = 1744261762Strasz auth_group_find(conf, "default"); 1745255570Strasz assert(pg->pg_discovery_auth_group != NULL); 1746255570Strasz } 1747255570Strasz 1748273813Strasz if (pg->pg_discovery_filter == PG_FILTER_UNKNOWN) 1749273813Strasz pg->pg_discovery_filter = PG_FILTER_NONE; 1750273813Strasz 1751287534Smav if (pg->pg_redirection != NULL) { 1752287534Smav if (!TAILQ_EMPTY(&pg->pg_ports)) { 1753274308Strasz log_debugx("portal-group \"%s\" assigned " 1754278322Smav "to target, but configured " 1755274308Strasz "for redirection", 1756278322Smav pg->pg_name); 1757274308Strasz } 1758274308Strasz pg->pg_unassigned = false; 1759287534Smav } else if (!TAILQ_EMPTY(&pg->pg_ports)) { 1760287534Smav pg->pg_unassigned = false; 1761274308Strasz } else { 1762255570Strasz if (strcmp(pg->pg_name, "default") != 0) 1763255570Strasz log_warnx("portal-group \"%s\" not assigned " 1764255570Strasz "to any target", pg->pg_name); 1765255570Strasz pg->pg_unassigned = true; 1766274308Strasz } 1767255570Strasz } 1768255570Strasz TAILQ_FOREACH(ag, &conf->conf_auth_groups, ag_next) { 1769255570Strasz if (ag->ag_name == NULL) 1770255570Strasz assert(ag->ag_target != NULL); 1771255570Strasz else 1772255570Strasz assert(ag->ag_target == NULL); 1773255570Strasz 1774273465Strasz found = false; 1775255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 1776273465Strasz if (targ->t_auth_group == ag) { 1777273465Strasz found = true; 1778255570Strasz break; 1779273465Strasz } 1780255570Strasz } 1781278322Smav TAILQ_FOREACH(port, &conf->conf_ports, p_next) { 1782278322Smav if (port->p_auth_group == ag) { 1783278322Smav found = true; 1784278322Smav break; 1785278322Smav } 1786278322Smav } 1787273465Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 1788273465Strasz if (pg->pg_discovery_auth_group == ag) { 1789273465Strasz found = true; 1790273465Strasz break; 1791273465Strasz } 1792273465Strasz } 1793273465Strasz if (!found && ag->ag_name != NULL && 1794261762Strasz strcmp(ag->ag_name, "default") != 0 && 1795255570Strasz strcmp(ag->ag_name, "no-authentication") != 0 && 1796255570Strasz strcmp(ag->ag_name, "no-access") != 0) { 1797255570Strasz log_warnx("auth-group \"%s\" not assigned " 1798255570Strasz "to any target", ag->ag_name); 1799255570Strasz } 1800255570Strasz } 1801255570Strasz 1802255570Strasz return (0); 1803255570Strasz} 1804255570Strasz 1805255570Straszstatic int 1806255570Straszconf_apply(struct conf *oldconf, struct conf *newconf) 1807255570Strasz{ 1808255570Strasz struct lun *oldlun, *newlun, *tmplun; 1809255570Strasz struct portal_group *oldpg, *newpg; 1810255570Strasz struct portal *oldp, *newp; 1811278322Smav struct port *oldport, *newport, *tmpport; 1812273635Smav struct isns *oldns, *newns; 1813255570Strasz pid_t otherpid; 1814274853Smav int changed, cumulated_error = 0, error, sockbuf; 1815255570Strasz int one = 1; 1816255570Strasz 1817255570Strasz if (oldconf->conf_debug != newconf->conf_debug) { 1818255570Strasz log_debugx("changing debug level to %d", newconf->conf_debug); 1819255570Strasz log_init(newconf->conf_debug); 1820255570Strasz } 1821255570Strasz 1822255570Strasz if (oldconf->conf_pidfh != NULL) { 1823255570Strasz assert(oldconf->conf_pidfile_path != NULL); 1824255570Strasz if (newconf->conf_pidfile_path != NULL && 1825255570Strasz strcmp(oldconf->conf_pidfile_path, 1826255570Strasz newconf->conf_pidfile_path) == 0) { 1827255570Strasz newconf->conf_pidfh = oldconf->conf_pidfh; 1828255570Strasz oldconf->conf_pidfh = NULL; 1829255570Strasz } else { 1830255570Strasz log_debugx("removing pidfile %s", 1831255570Strasz oldconf->conf_pidfile_path); 1832255570Strasz pidfile_remove(oldconf->conf_pidfh); 1833255570Strasz oldconf->conf_pidfh = NULL; 1834255570Strasz } 1835255570Strasz } 1836255570Strasz 1837255570Strasz if (newconf->conf_pidfh == NULL && newconf->conf_pidfile_path != NULL) { 1838255570Strasz log_debugx("opening pidfile %s", newconf->conf_pidfile_path); 1839255570Strasz newconf->conf_pidfh = 1840255570Strasz pidfile_open(newconf->conf_pidfile_path, 0600, &otherpid); 1841255570Strasz if (newconf->conf_pidfh == NULL) { 1842255570Strasz if (errno == EEXIST) 1843255570Strasz log_errx(1, "daemon already running, pid: %jd.", 1844255570Strasz (intmax_t)otherpid); 1845255570Strasz log_err(1, "cannot open or create pidfile \"%s\"", 1846255570Strasz newconf->conf_pidfile_path); 1847255570Strasz } 1848255570Strasz } 1849255570Strasz 1850278161Smav /* 1851278161Smav * Go through the new portal groups, assigning tags or preserving old. 1852278161Smav */ 1853278161Smav TAILQ_FOREACH(newpg, &newconf->conf_portal_groups, pg_next) { 1854287534Smav if (newpg->pg_tag != 0) 1855287534Smav continue; 1856278161Smav oldpg = portal_group_find(oldconf, newpg->pg_name); 1857278161Smav if (oldpg != NULL) 1858278161Smav newpg->pg_tag = oldpg->pg_tag; 1859278161Smav else 1860278161Smav newpg->pg_tag = ++last_portal_group_tag; 1861278161Smav } 1862278161Smav 1863273635Smav /* Deregister on removed iSNS servers. */ 1864273635Smav TAILQ_FOREACH(oldns, &oldconf->conf_isns, i_next) { 1865273635Smav TAILQ_FOREACH(newns, &newconf->conf_isns, i_next) { 1866273635Smav if (strcmp(oldns->i_addr, newns->i_addr) == 0) 1867273635Smav break; 1868273635Smav } 1869273635Smav if (newns == NULL) 1870273635Smav isns_deregister(oldns); 1871273635Smav } 1872273635Smav 1873264534Strasz /* 1874264534Strasz * XXX: If target or lun removal fails, we should somehow "move" 1875273464Strasz * the old lun or target into newconf, so that subsequent 1876273464Strasz * conf_apply() would try to remove them again. That would 1877273464Strasz * be somewhat hairy, though, and lun deletion failures don't 1878273464Strasz * really happen, so leave it as it is for now. 1879264534Strasz */ 1880278037Smav /* 1881278322Smav * First, remove any ports present in the old configuration 1882278037Smav * and missing in the new one. 1883278037Smav */ 1884278322Smav TAILQ_FOREACH_SAFE(oldport, &oldconf->conf_ports, p_next, tmpport) { 1885287534Smav if (oldport->p_foreign) 1886287534Smav continue; 1887278322Smav newport = port_find(newconf, oldport->p_name); 1888287534Smav if (newport != NULL && !newport->p_foreign) 1889278037Smav continue; 1890278354Smav log_debugx("removing port \"%s\"", oldport->p_name); 1891278322Smav error = kernel_port_remove(oldport); 1892278037Smav if (error != 0) { 1893278322Smav log_warnx("failed to remove port %s", 1894278322Smav oldport->p_name); 1895278037Smav /* 1896278037Smav * XXX: Uncomment after fixing the root cause. 1897278037Smav * 1898278037Smav * cumulated_error++; 1899278037Smav */ 1900278037Smav } 1901278037Smav } 1902278037Smav 1903278037Smav /* 1904278037Smav * Second, remove any LUNs present in the old configuration 1905278037Smav * and missing in the new one. 1906278037Smav */ 1907278037Smav TAILQ_FOREACH_SAFE(oldlun, &oldconf->conf_luns, l_next, tmplun) { 1908278037Smav newlun = lun_find(newconf, oldlun->l_name); 1909278037Smav if (newlun == NULL) { 1910278037Smav log_debugx("lun \"%s\", CTL lun %d " 1911278037Smav "not found in new configuration; " 1912278037Smav "removing", oldlun->l_name, oldlun->l_ctl_lun); 1913278037Smav error = kernel_lun_remove(oldlun); 1914274804Smav if (error != 0) { 1915278037Smav log_warnx("failed to remove lun \"%s\", " 1916278037Smav "CTL lun %d", 1917278037Smav oldlun->l_name, oldlun->l_ctl_lun); 1918278037Smav cumulated_error++; 1919274804Smav } 1920255570Strasz continue; 1921255570Strasz } 1922255570Strasz 1923255570Strasz /* 1924278037Smav * Also remove the LUNs changed by more than size. 1925255570Strasz */ 1926278037Smav changed = 0; 1927278037Smav assert(oldlun->l_backend != NULL); 1928278037Smav assert(newlun->l_backend != NULL); 1929278037Smav if (strcmp(newlun->l_backend, oldlun->l_backend) != 0) { 1930278037Smav log_debugx("backend for lun \"%s\", " 1931278037Smav "CTL lun %d changed; removing", 1932278037Smav oldlun->l_name, oldlun->l_ctl_lun); 1933278037Smav changed = 1; 1934278037Smav } 1935278037Smav if (oldlun->l_blocksize != newlun->l_blocksize) { 1936278037Smav log_debugx("blocksize for lun \"%s\", " 1937278037Smav "CTL lun %d changed; removing", 1938278037Smav oldlun->l_name, oldlun->l_ctl_lun); 1939278037Smav changed = 1; 1940278037Smav } 1941278037Smav if (newlun->l_device_id != NULL && 1942278037Smav (oldlun->l_device_id == NULL || 1943278037Smav strcmp(oldlun->l_device_id, newlun->l_device_id) != 1944278037Smav 0)) { 1945278037Smav log_debugx("device-id for lun \"%s\", " 1946278037Smav "CTL lun %d changed; removing", 1947278037Smav oldlun->l_name, oldlun->l_ctl_lun); 1948278037Smav changed = 1; 1949278037Smav } 1950278037Smav if (newlun->l_path != NULL && 1951278037Smav (oldlun->l_path == NULL || 1952278037Smav strcmp(oldlun->l_path, newlun->l_path) != 0)) { 1953278037Smav log_debugx("path for lun \"%s\", " 1954278037Smav "CTL lun %d, changed; removing", 1955278037Smav oldlun->l_name, oldlun->l_ctl_lun); 1956278037Smav changed = 1; 1957278037Smav } 1958278037Smav if (newlun->l_serial != NULL && 1959278037Smav (oldlun->l_serial == NULL || 1960278037Smav strcmp(oldlun->l_serial, newlun->l_serial) != 0)) { 1961278037Smav log_debugx("serial for lun \"%s\", " 1962278037Smav "CTL lun %d changed; removing", 1963278037Smav oldlun->l_name, oldlun->l_ctl_lun); 1964278037Smav changed = 1; 1965278037Smav } 1966278037Smav if (changed) { 1967278037Smav error = kernel_lun_remove(oldlun); 1968278037Smav if (error != 0) { 1969278037Smav log_warnx("failed to remove lun \"%s\", " 1970278037Smav "CTL lun %d", 1971278037Smav oldlun->l_name, oldlun->l_ctl_lun); 1972278037Smav cumulated_error++; 1973255570Strasz } 1974278037Smav lun_delete(oldlun); 1975278037Smav continue; 1976278037Smav } 1977255570Strasz 1978278037Smav lun_set_ctl_lun(newlun, oldlun->l_ctl_lun); 1979278037Smav } 1980278037Smav 1981278037Smav TAILQ_FOREACH_SAFE(newlun, &newconf->conf_luns, l_next, tmplun) { 1982278037Smav oldlun = lun_find(oldconf, newlun->l_name); 1983278037Smav if (oldlun != NULL) { 1984287500Smav log_debugx("modifying lun \"%s\", CTL lun %d", 1985287500Smav newlun->l_name, newlun->l_ctl_lun); 1986287500Smav error = kernel_lun_modify(newlun); 1987287500Smav if (error != 0) { 1988287500Smav log_warnx("failed to " 1989287500Smav "modify lun \"%s\", CTL lun %d", 1990278037Smav newlun->l_name, newlun->l_ctl_lun); 1991287500Smav cumulated_error++; 1992255570Strasz } 1993278037Smav continue; 1994255570Strasz } 1995278037Smav log_debugx("adding lun \"%s\"", newlun->l_name); 1996278037Smav error = kernel_lun_add(newlun); 1997278037Smav if (error != 0) { 1998278037Smav log_warnx("failed to add lun \"%s\"", newlun->l_name); 1999278037Smav lun_delete(newlun); 2000278037Smav cumulated_error++; 2001278037Smav } 2002255570Strasz } 2003255570Strasz 2004255570Strasz /* 2005278322Smav * Now add new ports or modify existing ones. 2006255570Strasz */ 2007278322Smav TAILQ_FOREACH(newport, &newconf->conf_ports, p_next) { 2008287534Smav if (newport->p_foreign) 2009287534Smav continue; 2010278322Smav oldport = port_find(oldconf, newport->p_name); 2011255570Strasz 2012287534Smav if (oldport == NULL || oldport->p_foreign) { 2013278354Smav log_debugx("adding port \"%s\"", newport->p_name); 2014278322Smav error = kernel_port_add(newport); 2015278322Smav } else { 2016278354Smav log_debugx("updating port \"%s\"", newport->p_name); 2017278322Smav newport->p_ctl_port = oldport->p_ctl_port; 2018287757Smav error = kernel_port_update(newport, oldport); 2019274791Strasz } 2020278037Smav if (error != 0) { 2021278322Smav log_warnx("failed to %s port %s", 2022278322Smav (oldport == NULL) ? "add" : "update", 2023278322Smav newport->p_name); 2024278037Smav /* 2025278037Smav * XXX: Uncomment after fixing the root cause. 2026278037Smav * 2027278037Smav * cumulated_error++; 2028278037Smav */ 2029278037Smav } 2030255570Strasz } 2031255570Strasz 2032255570Strasz /* 2033289677Seadler * Go through the new portals, opening the sockets as necessary. 2034255570Strasz */ 2035255570Strasz TAILQ_FOREACH(newpg, &newconf->conf_portal_groups, pg_next) { 2036287534Smav if (newpg->pg_foreign) 2037287534Smav continue; 2038255570Strasz if (newpg->pg_unassigned) { 2039255570Strasz log_debugx("not listening on portal-group \"%s\", " 2040255570Strasz "not assigned to any target", 2041255570Strasz newpg->pg_name); 2042255570Strasz continue; 2043255570Strasz } 2044255570Strasz TAILQ_FOREACH(newp, &newpg->pg_portals, p_next) { 2045255570Strasz /* 2046255570Strasz * Try to find already open portal and reuse 2047255570Strasz * the listening socket. We don't care about 2048255570Strasz * what portal or portal group that was, what 2049255570Strasz * matters is the listening address. 2050255570Strasz */ 2051255570Strasz TAILQ_FOREACH(oldpg, &oldconf->conf_portal_groups, 2052255570Strasz pg_next) { 2053255570Strasz TAILQ_FOREACH(oldp, &oldpg->pg_portals, 2054255570Strasz p_next) { 2055255570Strasz if (strcmp(newp->p_listen, 2056255570Strasz oldp->p_listen) == 0 && 2057255570Strasz oldp->p_socket > 0) { 2058255570Strasz newp->p_socket = 2059255570Strasz oldp->p_socket; 2060255570Strasz oldp->p_socket = 0; 2061255570Strasz break; 2062255570Strasz } 2063255570Strasz } 2064255570Strasz } 2065255570Strasz if (newp->p_socket > 0) { 2066255570Strasz /* 2067255570Strasz * We're done with this portal. 2068255570Strasz */ 2069255570Strasz continue; 2070255570Strasz } 2071255570Strasz 2072255570Strasz#ifdef ICL_KERNEL_PROXY 2073264524Strasz if (proxy_mode) { 2074264526Strasz newpg->pg_conf->conf_portal_id++; 2075264526Strasz newp->p_id = newpg->pg_conf->conf_portal_id; 2076264526Strasz log_debugx("listening on %s, portal-group " 2077264526Strasz "\"%s\", portal id %d, using ICL proxy", 2078264526Strasz newp->p_listen, newpg->pg_name, newp->p_id); 2079264526Strasz kernel_listen(newp->p_ai, newp->p_iser, 2080264526Strasz newp->p_id); 2081264524Strasz continue; 2082264524Strasz } 2083264524Strasz#endif 2084264524Strasz assert(proxy_mode == false); 2085255570Strasz assert(newp->p_iser == false); 2086255570Strasz 2087255570Strasz log_debugx("listening on %s, portal-group \"%s\"", 2088255570Strasz newp->p_listen, newpg->pg_name); 2089255570Strasz newp->p_socket = socket(newp->p_ai->ai_family, 2090255570Strasz newp->p_ai->ai_socktype, 2091255570Strasz newp->p_ai->ai_protocol); 2092255570Strasz if (newp->p_socket < 0) { 2093255570Strasz log_warn("socket(2) failed for %s", 2094255570Strasz newp->p_listen); 2095255570Strasz cumulated_error++; 2096255570Strasz continue; 2097255570Strasz } 2098274853Smav sockbuf = SOCKBUF_SIZE; 2099274853Smav if (setsockopt(newp->p_socket, SOL_SOCKET, SO_RCVBUF, 2100274853Smav &sockbuf, sizeof(sockbuf)) == -1) 2101274853Smav log_warn("setsockopt(SO_RCVBUF) failed " 2102274853Smav "for %s", newp->p_listen); 2103274853Smav sockbuf = SOCKBUF_SIZE; 2104274853Smav if (setsockopt(newp->p_socket, SOL_SOCKET, SO_SNDBUF, 2105274853Smav &sockbuf, sizeof(sockbuf)) == -1) 2106274853Smav log_warn("setsockopt(SO_SNDBUF) failed " 2107274853Smav "for %s", newp->p_listen); 2108255570Strasz error = setsockopt(newp->p_socket, SOL_SOCKET, 2109255570Strasz SO_REUSEADDR, &one, sizeof(one)); 2110255570Strasz if (error != 0) { 2111255570Strasz log_warn("setsockopt(SO_REUSEADDR) failed " 2112255570Strasz "for %s", newp->p_listen); 2113255570Strasz close(newp->p_socket); 2114255570Strasz newp->p_socket = 0; 2115255570Strasz cumulated_error++; 2116255570Strasz continue; 2117255570Strasz } 2118255570Strasz error = bind(newp->p_socket, newp->p_ai->ai_addr, 2119255570Strasz newp->p_ai->ai_addrlen); 2120255570Strasz if (error != 0) { 2121255570Strasz log_warn("bind(2) failed for %s", 2122255570Strasz newp->p_listen); 2123255570Strasz close(newp->p_socket); 2124255570Strasz newp->p_socket = 0; 2125255570Strasz cumulated_error++; 2126255570Strasz continue; 2127255570Strasz } 2128255570Strasz error = listen(newp->p_socket, -1); 2129255570Strasz if (error != 0) { 2130255570Strasz log_warn("listen(2) failed for %s", 2131255570Strasz newp->p_listen); 2132255570Strasz close(newp->p_socket); 2133255570Strasz newp->p_socket = 0; 2134255570Strasz cumulated_error++; 2135255570Strasz continue; 2136255570Strasz } 2137255570Strasz } 2138255570Strasz } 2139255570Strasz 2140255570Strasz /* 2141255570Strasz * Go through the no longer used sockets, closing them. 2142255570Strasz */ 2143255570Strasz TAILQ_FOREACH(oldpg, &oldconf->conf_portal_groups, pg_next) { 2144255570Strasz TAILQ_FOREACH(oldp, &oldpg->pg_portals, p_next) { 2145255570Strasz if (oldp->p_socket <= 0) 2146255570Strasz continue; 2147255570Strasz log_debugx("closing socket for %s, portal-group \"%s\"", 2148255570Strasz oldp->p_listen, oldpg->pg_name); 2149255570Strasz close(oldp->p_socket); 2150255570Strasz oldp->p_socket = 0; 2151255570Strasz } 2152255570Strasz } 2153255570Strasz 2154273635Smav /* (Re-)Register on remaining/new iSNS servers. */ 2155273635Smav TAILQ_FOREACH(newns, &newconf->conf_isns, i_next) { 2156273635Smav TAILQ_FOREACH(oldns, &oldconf->conf_isns, i_next) { 2157273635Smav if (strcmp(oldns->i_addr, newns->i_addr) == 0) 2158273635Smav break; 2159273635Smav } 2160273635Smav isns_register(newns, oldns); 2161273635Smav } 2162273635Smav 2163273635Smav /* Schedule iSNS update */ 2164273635Smav if (!TAILQ_EMPTY(&newconf->conf_isns)) 2165273635Smav set_timeout((newconf->conf_isns_period + 2) / 3, false); 2166273635Smav 2167255570Strasz return (cumulated_error); 2168255570Strasz} 2169255570Strasz 2170255570Straszbool 2171255570Strasztimed_out(void) 2172255570Strasz{ 2173255570Strasz 2174255570Strasz return (sigalrm_received); 2175255570Strasz} 2176255570Strasz 2177255570Straszstatic void 2178273635Smavsigalrm_handler_fatal(int dummy __unused) 2179255570Strasz{ 2180255570Strasz /* 2181255570Strasz * It would be easiest to just log an error and exit. We can't 2182255570Strasz * do this, though, because log_errx() is not signal safe, since 2183255570Strasz * it calls syslog(3). Instead, set a flag checked by pdu_send() 2184255570Strasz * and pdu_receive(), to call log_errx() there. Should they fail 2185255570Strasz * to notice, we'll exit here one second later. 2186255570Strasz */ 2187255570Strasz if (sigalrm_received) { 2188255570Strasz /* 2189255570Strasz * Oh well. Just give up and quit. 2190255570Strasz */ 2191255570Strasz _exit(2); 2192255570Strasz } 2193255570Strasz 2194255570Strasz sigalrm_received = true; 2195255570Strasz} 2196255570Strasz 2197255570Straszstatic void 2198273635Smavsigalrm_handler(int dummy __unused) 2199255570Strasz{ 2200273635Smav 2201273635Smav sigalrm_received = true; 2202273635Smav} 2203273635Smav 2204273635Smavvoid 2205273635Smavset_timeout(int timeout, int fatal) 2206273635Smav{ 2207255570Strasz struct sigaction sa; 2208255570Strasz struct itimerval itv; 2209255570Strasz int error; 2210255570Strasz 2211273635Smav if (timeout <= 0) { 2212255570Strasz log_debugx("session timeout disabled"); 2213273635Smav bzero(&itv, sizeof(itv)); 2214273635Smav error = setitimer(ITIMER_REAL, &itv, NULL); 2215273635Smav if (error != 0) 2216273635Smav log_err(1, "setitimer"); 2217273635Smav sigalrm_received = false; 2218255570Strasz return; 2219255570Strasz } 2220255570Strasz 2221273635Smav sigalrm_received = false; 2222255570Strasz bzero(&sa, sizeof(sa)); 2223273635Smav if (fatal) 2224273635Smav sa.sa_handler = sigalrm_handler_fatal; 2225273635Smav else 2226273635Smav sa.sa_handler = sigalrm_handler; 2227255570Strasz sigfillset(&sa.sa_mask); 2228255570Strasz error = sigaction(SIGALRM, &sa, NULL); 2229255570Strasz if (error != 0) 2230255570Strasz log_err(1, "sigaction"); 2231255570Strasz 2232255570Strasz /* 2233255570Strasz * First SIGALRM will arive after conf_timeout seconds. 2234255570Strasz * If we do nothing, another one will arrive a second later. 2235255570Strasz */ 2236273635Smav log_debugx("setting session timeout to %d seconds", timeout); 2237255570Strasz bzero(&itv, sizeof(itv)); 2238255570Strasz itv.it_interval.tv_sec = 1; 2239273635Smav itv.it_value.tv_sec = timeout; 2240255570Strasz error = setitimer(ITIMER_REAL, &itv, NULL); 2241255570Strasz if (error != 0) 2242255570Strasz log_err(1, "setitimer"); 2243255570Strasz} 2244255570Strasz 2245255570Straszstatic int 2246255570Straszwait_for_children(bool block) 2247255570Strasz{ 2248255570Strasz pid_t pid; 2249255570Strasz int status; 2250255570Strasz int num = 0; 2251255570Strasz 2252255570Strasz for (;;) { 2253255570Strasz /* 2254255570Strasz * If "block" is true, wait for at least one process. 2255255570Strasz */ 2256255570Strasz if (block && num == 0) 2257255570Strasz pid = wait4(-1, &status, 0, NULL); 2258255570Strasz else 2259255570Strasz pid = wait4(-1, &status, WNOHANG, NULL); 2260255570Strasz if (pid <= 0) 2261255570Strasz break; 2262255570Strasz if (WIFSIGNALED(status)) { 2263255570Strasz log_warnx("child process %d terminated with signal %d", 2264255570Strasz pid, WTERMSIG(status)); 2265255570Strasz } else if (WEXITSTATUS(status) != 0) { 2266255570Strasz log_warnx("child process %d terminated with exit status %d", 2267255570Strasz pid, WEXITSTATUS(status)); 2268255570Strasz } else { 2269255570Strasz log_debugx("child process %d terminated gracefully", pid); 2270255570Strasz } 2271255570Strasz num++; 2272255570Strasz } 2273255570Strasz 2274255570Strasz return (num); 2275255570Strasz} 2276255570Strasz 2277255570Straszstatic void 2278264530Straszhandle_connection(struct portal *portal, int fd, 2279269183Smav const struct sockaddr *client_sa, bool dont_fork) 2280255570Strasz{ 2281255570Strasz struct connection *conn; 2282255570Strasz int error; 2283255570Strasz pid_t pid; 2284255570Strasz char host[NI_MAXHOST + 1]; 2285255570Strasz struct conf *conf; 2286255570Strasz 2287255570Strasz conf = portal->p_portal_group->pg_conf; 2288255570Strasz 2289255570Strasz if (dont_fork) { 2290255570Strasz log_debugx("incoming connection; not forking due to -d flag"); 2291255570Strasz } else { 2292255570Strasz nchildren -= wait_for_children(false); 2293255570Strasz assert(nchildren >= 0); 2294255570Strasz 2295255570Strasz while (conf->conf_maxproc > 0 && nchildren >= conf->conf_maxproc) { 2296255570Strasz log_debugx("maxproc limit of %d child processes hit; " 2297255570Strasz "waiting for child process to exit", conf->conf_maxproc); 2298255570Strasz nchildren -= wait_for_children(true); 2299255570Strasz assert(nchildren >= 0); 2300255570Strasz } 2301255570Strasz log_debugx("incoming connection; forking child process #%d", 2302255570Strasz nchildren); 2303255570Strasz nchildren++; 2304255570Strasz pid = fork(); 2305255570Strasz if (pid < 0) 2306255570Strasz log_err(1, "fork"); 2307255570Strasz if (pid > 0) { 2308255570Strasz close(fd); 2309255570Strasz return; 2310255570Strasz } 2311255570Strasz } 2312255570Strasz pidfile_close(conf->conf_pidfh); 2313255570Strasz 2314269183Smav error = getnameinfo(client_sa, client_sa->sa_len, 2315264530Strasz host, sizeof(host), NULL, 0, NI_NUMERICHOST); 2316264530Strasz if (error != 0) 2317264530Strasz log_errx(1, "getnameinfo: %s", gai_strerror(error)); 2318255570Strasz 2319264530Strasz log_debugx("accepted connection from %s; portal group \"%s\"", 2320264530Strasz host, portal->p_portal_group->pg_name); 2321264530Strasz log_set_peer_addr(host); 2322264530Strasz setproctitle("%s", host); 2323255570Strasz 2324269183Smav conn = connection_new(portal, fd, host, client_sa); 2325273635Smav set_timeout(conf->conf_timeout, true); 2326255570Strasz kernel_capsicate(); 2327255570Strasz login(conn); 2328255570Strasz if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) { 2329255570Strasz kernel_handoff(conn); 2330255570Strasz log_debugx("connection handed off to the kernel"); 2331255570Strasz } else { 2332255570Strasz assert(conn->conn_session_type == CONN_SESSION_TYPE_DISCOVERY); 2333255570Strasz discovery(conn); 2334255570Strasz } 2335255570Strasz log_debugx("nothing more to do; exiting"); 2336255570Strasz exit(0); 2337255570Strasz} 2338255570Strasz 2339255570Straszstatic int 2340255570Straszfd_add(int fd, fd_set *fdset, int nfds) 2341255570Strasz{ 2342255570Strasz 2343255570Strasz /* 2344255570Strasz * Skip sockets which we failed to bind. 2345255570Strasz */ 2346255570Strasz if (fd <= 0) 2347255570Strasz return (nfds); 2348255570Strasz 2349255570Strasz FD_SET(fd, fdset); 2350255570Strasz if (fd > nfds) 2351255570Strasz nfds = fd; 2352255570Strasz return (nfds); 2353255570Strasz} 2354255570Strasz 2355255570Straszstatic void 2356255570Straszmain_loop(struct conf *conf, bool dont_fork) 2357255570Strasz{ 2358255570Strasz struct portal_group *pg; 2359255570Strasz struct portal *portal; 2360264529Strasz struct sockaddr_storage client_sa; 2361264529Strasz socklen_t client_salen; 2362255570Strasz#ifdef ICL_KERNEL_PROXY 2363255570Strasz int connection_id; 2364264526Strasz int portal_id; 2365264524Strasz#endif 2366255570Strasz fd_set fdset; 2367255570Strasz int error, nfds, client_fd; 2368255570Strasz 2369255570Strasz pidfile_write(conf->conf_pidfh); 2370255570Strasz 2371255570Strasz for (;;) { 2372273635Smav if (sighup_received || sigterm_received || timed_out()) 2373255570Strasz return; 2374255570Strasz 2375255570Strasz#ifdef ICL_KERNEL_PROXY 2376264524Strasz if (proxy_mode) { 2377264530Strasz client_salen = sizeof(client_sa); 2378264530Strasz kernel_accept(&connection_id, &portal_id, 2379264530Strasz (struct sockaddr *)&client_sa, &client_salen); 2380271169Strasz assert(client_salen >= client_sa.ss_len); 2381255570Strasz 2382264526Strasz log_debugx("incoming connection, id %d, portal id %d", 2383264526Strasz connection_id, portal_id); 2384264526Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 2385264526Strasz TAILQ_FOREACH(portal, &pg->pg_portals, p_next) { 2386264526Strasz if (portal->p_id == portal_id) { 2387264526Strasz goto found; 2388264526Strasz } 2389264526Strasz } 2390264526Strasz } 2391255570Strasz 2392264526Strasz log_errx(1, "kernel returned invalid portal_id %d", 2393264526Strasz portal_id); 2394264526Strasz 2395264526Straszfound: 2396264530Strasz handle_connection(portal, connection_id, 2397269183Smav (struct sockaddr *)&client_sa, dont_fork); 2398264524Strasz } else { 2399264524Strasz#endif 2400264524Strasz assert(proxy_mode == false); 2401264524Strasz 2402264524Strasz FD_ZERO(&fdset); 2403264524Strasz nfds = 0; 2404264524Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 2405264524Strasz TAILQ_FOREACH(portal, &pg->pg_portals, p_next) 2406264524Strasz nfds = fd_add(portal->p_socket, &fdset, nfds); 2407255570Strasz } 2408264524Strasz error = select(nfds + 1, &fdset, NULL, NULL, NULL); 2409264524Strasz if (error <= 0) { 2410264524Strasz if (errno == EINTR) 2411264524Strasz return; 2412264524Strasz log_err(1, "select"); 2413264524Strasz } 2414264524Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 2415264524Strasz TAILQ_FOREACH(portal, &pg->pg_portals, p_next) { 2416264524Strasz if (!FD_ISSET(portal->p_socket, &fdset)) 2417264524Strasz continue; 2418264529Strasz client_salen = sizeof(client_sa); 2419264529Strasz client_fd = accept(portal->p_socket, 2420264529Strasz (struct sockaddr *)&client_sa, 2421264529Strasz &client_salen); 2422281163Smav if (client_fd < 0) { 2423281163Smav if (errno == ECONNABORTED) 2424281163Smav continue; 2425264524Strasz log_err(1, "accept"); 2426281163Smav } 2427271169Strasz assert(client_salen >= client_sa.ss_len); 2428271169Strasz 2429264529Strasz handle_connection(portal, client_fd, 2430264530Strasz (struct sockaddr *)&client_sa, 2431269183Smav dont_fork); 2432264524Strasz break; 2433264524Strasz } 2434264524Strasz } 2435264524Strasz#ifdef ICL_KERNEL_PROXY 2436255570Strasz } 2437264524Strasz#endif 2438255570Strasz } 2439255570Strasz} 2440255570Strasz 2441255570Straszstatic void 2442255570Straszsighup_handler(int dummy __unused) 2443255570Strasz{ 2444255570Strasz 2445255570Strasz sighup_received = true; 2446255570Strasz} 2447255570Strasz 2448255570Straszstatic void 2449255570Straszsigterm_handler(int dummy __unused) 2450255570Strasz{ 2451255570Strasz 2452255570Strasz sigterm_received = true; 2453255570Strasz} 2454255570Strasz 2455255570Straszstatic void 2456261764Straszsigchld_handler(int dummy __unused) 2457261764Strasz{ 2458261764Strasz 2459261764Strasz /* 2460261764Strasz * The only purpose of this handler is to make SIGCHLD 2461261764Strasz * interrupt the ISCSIDWAIT ioctl(2), so we can call 2462261764Strasz * wait_for_children(). 2463261764Strasz */ 2464261764Strasz} 2465261764Strasz 2466261764Straszstatic void 2467255570Straszregister_signals(void) 2468255570Strasz{ 2469255570Strasz struct sigaction sa; 2470255570Strasz int error; 2471255570Strasz 2472255570Strasz bzero(&sa, sizeof(sa)); 2473255570Strasz sa.sa_handler = sighup_handler; 2474255570Strasz sigfillset(&sa.sa_mask); 2475255570Strasz error = sigaction(SIGHUP, &sa, NULL); 2476255570Strasz if (error != 0) 2477255570Strasz log_err(1, "sigaction"); 2478255570Strasz 2479255570Strasz sa.sa_handler = sigterm_handler; 2480255570Strasz error = sigaction(SIGTERM, &sa, NULL); 2481255570Strasz if (error != 0) 2482255570Strasz log_err(1, "sigaction"); 2483255570Strasz 2484255570Strasz sa.sa_handler = sigterm_handler; 2485255570Strasz error = sigaction(SIGINT, &sa, NULL); 2486255570Strasz if (error != 0) 2487255570Strasz log_err(1, "sigaction"); 2488261764Strasz 2489261764Strasz sa.sa_handler = sigchld_handler; 2490261764Strasz error = sigaction(SIGCHLD, &sa, NULL); 2491261764Strasz if (error != 0) 2492261764Strasz log_err(1, "sigaction"); 2493255570Strasz} 2494255570Strasz 2495295212Sjceelstatic void 2496295212Sjceelcheck_perms(const char *path) 2497295212Sjceel{ 2498295212Sjceel struct stat sb; 2499295212Sjceel int error; 2500295212Sjceel 2501295212Sjceel error = stat(path, &sb); 2502295212Sjceel if (error != 0) { 2503295212Sjceel log_warn("stat"); 2504295212Sjceel return; 2505295212Sjceel } 2506295212Sjceel if (sb.st_mode & S_IWOTH) { 2507295212Sjceel log_warnx("%s is world-writable", path); 2508295212Sjceel } else if (sb.st_mode & S_IROTH) { 2509295212Sjceel log_warnx("%s is world-readable", path); 2510295212Sjceel } else if (sb.st_mode & S_IXOTH) { 2511295212Sjceel /* 2512295212Sjceel * Ok, this one doesn't matter, but still do it, 2513295212Sjceel * just for consistency. 2514295212Sjceel */ 2515295212Sjceel log_warnx("%s is world-executable", path); 2516295212Sjceel } 2517295212Sjceel 2518295212Sjceel /* 2519295212Sjceel * XXX: Should we also check for owner != 0? 2520295212Sjceel */ 2521295212Sjceel} 2522295212Sjceel 2523295212Sjceelstatic struct conf * 2524295212Sjceelconf_new_from_file(const char *path, struct conf *oldconf, bool ucl) 2525295212Sjceel{ 2526295212Sjceel struct conf *conf; 2527295212Sjceel struct auth_group *ag; 2528295212Sjceel struct portal_group *pg; 2529295212Sjceel struct pport *pp; 2530295212Sjceel int error; 2531295212Sjceel 2532295212Sjceel log_debugx("obtaining configuration from %s", path); 2533295212Sjceel 2534295212Sjceel conf = conf_new(); 2535295212Sjceel 2536295212Sjceel TAILQ_FOREACH(pp, &oldconf->conf_pports, pp_next) 2537295212Sjceel pport_copy(pp, conf); 2538295212Sjceel 2539295212Sjceel ag = auth_group_new(conf, "default"); 2540295212Sjceel assert(ag != NULL); 2541295212Sjceel 2542295212Sjceel ag = auth_group_new(conf, "no-authentication"); 2543295212Sjceel assert(ag != NULL); 2544295212Sjceel ag->ag_type = AG_TYPE_NO_AUTHENTICATION; 2545295212Sjceel 2546295212Sjceel ag = auth_group_new(conf, "no-access"); 2547295212Sjceel assert(ag != NULL); 2548295212Sjceel ag->ag_type = AG_TYPE_DENY; 2549295212Sjceel 2550295212Sjceel pg = portal_group_new(conf, "default"); 2551295212Sjceel assert(pg != NULL); 2552295212Sjceel 2553295212Sjceel if (ucl) 2554295212Sjceel error = uclparse_conf(conf, path); 2555295212Sjceel else 2556295212Sjceel error = parse_conf(conf, path); 2557295212Sjceel 2558295212Sjceel if (error != 0) { 2559295212Sjceel conf_delete(conf); 2560295212Sjceel return (NULL); 2561295212Sjceel } 2562295212Sjceel 2563295212Sjceel check_perms(path); 2564295212Sjceel 2565295212Sjceel if (conf->conf_default_ag_defined == false) { 2566295212Sjceel log_debugx("auth-group \"default\" not defined; " 2567295212Sjceel "going with defaults"); 2568295212Sjceel ag = auth_group_find(conf, "default"); 2569295212Sjceel assert(ag != NULL); 2570295212Sjceel ag->ag_type = AG_TYPE_DENY; 2571295212Sjceel } 2572295212Sjceel 2573295212Sjceel if (conf->conf_default_pg_defined == false) { 2574295212Sjceel log_debugx("portal-group \"default\" not defined; " 2575295212Sjceel "going with defaults"); 2576295212Sjceel pg = portal_group_find(conf, "default"); 2577295212Sjceel assert(pg != NULL); 2578295212Sjceel portal_group_add_listen(pg, "0.0.0.0:3260", false); 2579295212Sjceel portal_group_add_listen(pg, "[::]:3260", false); 2580295212Sjceel } 2581295212Sjceel 2582295212Sjceel conf->conf_kernel_port_on = true; 2583295212Sjceel 2584295212Sjceel error = conf_verify(conf); 2585295212Sjceel if (error != 0) { 2586295212Sjceel conf_delete(conf); 2587295212Sjceel return (NULL); 2588295212Sjceel } 2589295212Sjceel 2590295212Sjceel return (conf); 2591295212Sjceel} 2592295212Sjceel 2593255570Straszint 2594255570Straszmain(int argc, char **argv) 2595255570Strasz{ 2596255570Strasz struct conf *oldconf, *newconf, *tmpconf; 2597273635Smav struct isns *newns; 2598255570Strasz const char *config_path = DEFAULT_CONFIG_PATH; 2599255570Strasz int debug = 0, ch, error; 2600255570Strasz bool dont_daemonize = false; 2601295212Sjceel bool use_ucl = false; 2602255570Strasz 2603295212Sjceel while ((ch = getopt(argc, argv, "duf:R")) != -1) { 2604255570Strasz switch (ch) { 2605255570Strasz case 'd': 2606255570Strasz dont_daemonize = true; 2607255570Strasz debug++; 2608255570Strasz break; 2609295212Sjceel case 'u': 2610295212Sjceel use_ucl = true; 2611295212Sjceel break; 2612255570Strasz case 'f': 2613255570Strasz config_path = optarg; 2614255570Strasz break; 2615264524Strasz case 'R': 2616264524Strasz#ifndef ICL_KERNEL_PROXY 2617264524Strasz log_errx(1, "ctld(8) compiled without ICL_KERNEL_PROXY " 2618264524Strasz "does not support iSER protocol"); 2619264524Strasz#endif 2620264524Strasz proxy_mode = true; 2621264524Strasz break; 2622255570Strasz case '?': 2623255570Strasz default: 2624255570Strasz usage(); 2625255570Strasz } 2626255570Strasz } 2627255570Strasz argc -= optind; 2628255570Strasz if (argc != 0) 2629255570Strasz usage(); 2630255570Strasz 2631255570Strasz log_init(debug); 2632255570Strasz kernel_init(); 2633255570Strasz 2634255570Strasz oldconf = conf_new_from_kernel(); 2635295212Sjceel newconf = conf_new_from_file(config_path, oldconf, use_ucl); 2636295212Sjceel 2637255570Strasz if (newconf == NULL) 2638264533Strasz log_errx(1, "configuration error; exiting"); 2639255570Strasz if (debug > 0) { 2640255570Strasz oldconf->conf_debug = debug; 2641255570Strasz newconf->conf_debug = debug; 2642255570Strasz } 2643255570Strasz 2644255570Strasz error = conf_apply(oldconf, newconf); 2645255570Strasz if (error != 0) 2646264533Strasz log_errx(1, "failed to apply configuration; exiting"); 2647264533Strasz 2648255570Strasz conf_delete(oldconf); 2649255570Strasz oldconf = NULL; 2650255570Strasz 2651255570Strasz register_signals(); 2652255570Strasz 2653261753Strasz if (dont_daemonize == false) { 2654261753Strasz log_debugx("daemonizing"); 2655261753Strasz if (daemon(0, 0) == -1) { 2656261753Strasz log_warn("cannot daemonize"); 2657261753Strasz pidfile_remove(newconf->conf_pidfh); 2658261753Strasz exit(1); 2659261753Strasz } 2660261753Strasz } 2661261753Strasz 2662273635Smav /* Schedule iSNS update */ 2663273635Smav if (!TAILQ_EMPTY(&newconf->conf_isns)) 2664273635Smav set_timeout((newconf->conf_isns_period + 2) / 3, false); 2665273635Smav 2666255570Strasz for (;;) { 2667255570Strasz main_loop(newconf, dont_daemonize); 2668255570Strasz if (sighup_received) { 2669255570Strasz sighup_received = false; 2670255570Strasz log_debugx("received SIGHUP, reloading configuration"); 2671295212Sjceel tmpconf = conf_new_from_file(config_path, newconf, 2672295212Sjceel use_ucl); 2673295212Sjceel 2674255570Strasz if (tmpconf == NULL) { 2675255570Strasz log_warnx("configuration error, " 2676255570Strasz "continuing with old configuration"); 2677255570Strasz } else { 2678255570Strasz if (debug > 0) 2679255570Strasz tmpconf->conf_debug = debug; 2680255570Strasz oldconf = newconf; 2681255570Strasz newconf = tmpconf; 2682255570Strasz error = conf_apply(oldconf, newconf); 2683255570Strasz if (error != 0) 2684255570Strasz log_warnx("failed to reload " 2685255570Strasz "configuration"); 2686255570Strasz conf_delete(oldconf); 2687255570Strasz oldconf = NULL; 2688255570Strasz } 2689255570Strasz } else if (sigterm_received) { 2690255570Strasz log_debugx("exiting on signal; " 2691255570Strasz "reloading empty configuration"); 2692255570Strasz 2693278161Smav log_debugx("removing CTL iSCSI ports " 2694255570Strasz "and terminating all connections"); 2695255570Strasz 2696255570Strasz oldconf = newconf; 2697255570Strasz newconf = conf_new(); 2698255570Strasz if (debug > 0) 2699255570Strasz newconf->conf_debug = debug; 2700255570Strasz error = conf_apply(oldconf, newconf); 2701255570Strasz if (error != 0) 2702255570Strasz log_warnx("failed to apply configuration"); 2703273635Smav conf_delete(oldconf); 2704273635Smav oldconf = NULL; 2705255570Strasz 2706255570Strasz log_warnx("exiting on signal"); 2707255570Strasz exit(0); 2708255570Strasz } else { 2709255570Strasz nchildren -= wait_for_children(false); 2710255570Strasz assert(nchildren >= 0); 2711273635Smav if (timed_out()) { 2712273635Smav set_timeout(0, false); 2713273635Smav TAILQ_FOREACH(newns, &newconf->conf_isns, i_next) 2714273635Smav isns_check(newns); 2715273635Smav /* Schedule iSNS update */ 2716273635Smav if (!TAILQ_EMPTY(&newconf->conf_isns)) { 2717273635Smav set_timeout((newconf->conf_isns_period 2718273635Smav + 2) / 3, 2719273635Smav false); 2720273635Smav } 2721273635Smav } 2722255570Strasz } 2723255570Strasz } 2724255570Strasz /* NOTREACHED */ 2725255570Strasz} 2726