ctld.c revision 263720
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 * $FreeBSD: stable/10/usr.sbin/ctld/ctld.c 263720 2014-03-25 12:01:55Z trasz $ 30255570Strasz */ 31255570Strasz 32255570Strasz#include <sys/types.h> 33255570Strasz#include <sys/time.h> 34255570Strasz#include <sys/socket.h> 35255570Strasz#include <sys/wait.h> 36255570Strasz#include <netinet/in.h> 37255570Strasz#include <assert.h> 38255570Strasz#include <ctype.h> 39255570Strasz#include <errno.h> 40255570Strasz#include <netdb.h> 41255570Strasz#include <signal.h> 42255570Strasz#include <stdbool.h> 43255570Strasz#include <stdio.h> 44255570Strasz#include <stdint.h> 45255570Strasz#include <stdlib.h> 46255570Strasz#include <string.h> 47255570Strasz#include <unistd.h> 48255570Strasz 49255570Strasz#include "ctld.h" 50255570Strasz 51255570Straszstatic volatile bool sighup_received = false; 52255570Straszstatic volatile bool sigterm_received = false; 53255570Straszstatic volatile bool sigalrm_received = false; 54255570Strasz 55255570Straszstatic int nchildren = 0; 56255570Strasz 57255570Straszstatic void 58255570Straszusage(void) 59255570Strasz{ 60255570Strasz 61255570Strasz fprintf(stderr, "usage: ctld [-d][-f config-file]\n"); 62255570Strasz exit(1); 63255570Strasz} 64255570Strasz 65255570Straszchar * 66255570Straszchecked_strdup(const char *s) 67255570Strasz{ 68255570Strasz char *c; 69255570Strasz 70255570Strasz c = strdup(s); 71255570Strasz if (c == NULL) 72255570Strasz log_err(1, "strdup"); 73255570Strasz return (c); 74255570Strasz} 75255570Strasz 76255570Straszstruct conf * 77255570Straszconf_new(void) 78255570Strasz{ 79255570Strasz struct conf *conf; 80255570Strasz 81255570Strasz conf = calloc(1, sizeof(*conf)); 82255570Strasz if (conf == NULL) 83255570Strasz log_err(1, "calloc"); 84255570Strasz TAILQ_INIT(&conf->conf_targets); 85255570Strasz TAILQ_INIT(&conf->conf_auth_groups); 86255570Strasz TAILQ_INIT(&conf->conf_portal_groups); 87255570Strasz 88255570Strasz conf->conf_debug = 0; 89255570Strasz conf->conf_timeout = 60; 90255570Strasz conf->conf_maxproc = 30; 91255570Strasz 92255570Strasz return (conf); 93255570Strasz} 94255570Strasz 95255570Straszvoid 96255570Straszconf_delete(struct conf *conf) 97255570Strasz{ 98255570Strasz struct target *targ, *tmp; 99255570Strasz struct auth_group *ag, *cagtmp; 100255570Strasz struct portal_group *pg, *cpgtmp; 101255570Strasz 102255570Strasz assert(conf->conf_pidfh == NULL); 103255570Strasz 104255570Strasz TAILQ_FOREACH_SAFE(targ, &conf->conf_targets, t_next, tmp) 105255570Strasz target_delete(targ); 106255570Strasz TAILQ_FOREACH_SAFE(ag, &conf->conf_auth_groups, ag_next, cagtmp) 107255570Strasz auth_group_delete(ag); 108255570Strasz TAILQ_FOREACH_SAFE(pg, &conf->conf_portal_groups, pg_next, cpgtmp) 109255570Strasz portal_group_delete(pg); 110255570Strasz free(conf->conf_pidfile_path); 111255570Strasz free(conf); 112255570Strasz} 113255570Strasz 114255570Straszstatic struct auth * 115255570Straszauth_new(struct auth_group *ag) 116255570Strasz{ 117255570Strasz struct auth *auth; 118255570Strasz 119255570Strasz auth = calloc(1, sizeof(*auth)); 120255570Strasz if (auth == NULL) 121255570Strasz log_err(1, "calloc"); 122255570Strasz auth->a_auth_group = ag; 123255570Strasz TAILQ_INSERT_TAIL(&ag->ag_auths, auth, a_next); 124255570Strasz return (auth); 125255570Strasz} 126255570Strasz 127255570Straszstatic void 128255570Straszauth_delete(struct auth *auth) 129255570Strasz{ 130255570Strasz TAILQ_REMOVE(&auth->a_auth_group->ag_auths, auth, a_next); 131255570Strasz 132255570Strasz free(auth->a_user); 133255570Strasz free(auth->a_secret); 134255570Strasz free(auth->a_mutual_user); 135255570Strasz free(auth->a_mutual_secret); 136255570Strasz free(auth); 137255570Strasz} 138255570Strasz 139255570Straszconst struct auth * 140255570Straszauth_find(struct auth_group *ag, const char *user) 141255570Strasz{ 142255570Strasz const struct auth *auth; 143255570Strasz 144255570Strasz TAILQ_FOREACH(auth, &ag->ag_auths, a_next) { 145255570Strasz if (strcmp(auth->a_user, user) == 0) 146255570Strasz return (auth); 147255570Strasz } 148255570Strasz 149255570Strasz return (NULL); 150255570Strasz} 151255570Strasz 152263720Straszconst struct auth_name * 153263720Straszauth_name_new(struct auth_group *ag, const char *name) 154263720Strasz{ 155263720Strasz struct auth_name *an; 156263720Strasz 157263720Strasz an = calloc(1, sizeof(*an)); 158263720Strasz if (an == NULL) 159263720Strasz log_err(1, "calloc"); 160263720Strasz an->an_auth_group = ag; 161263720Strasz an->an_initator_name = checked_strdup(name); 162263720Strasz TAILQ_INSERT_TAIL(&ag->ag_names, an, an_next); 163263720Strasz return (an); 164263720Strasz} 165263720Strasz 166263720Straszstatic void 167263720Straszauth_name_delete(struct auth_name *an) 168263720Strasz{ 169263720Strasz TAILQ_REMOVE(&an->an_auth_group->ag_names, an, an_next); 170263720Strasz 171263720Strasz free(an->an_initator_name); 172263720Strasz free(an); 173263720Strasz} 174263720Strasz 175263720Straszbool 176263720Straszauth_name_defined(const struct auth_group *ag) 177263720Strasz{ 178263720Strasz if (TAILQ_EMPTY(&ag->ag_names)) 179263720Strasz return (false); 180263720Strasz return (true); 181263720Strasz} 182263720Strasz 183263720Straszconst struct auth_name * 184263720Straszauth_name_find(const struct auth_group *ag, const char *name) 185263720Strasz{ 186263720Strasz const struct auth_name *auth_name; 187263720Strasz 188263720Strasz TAILQ_FOREACH(auth_name, &ag->ag_names, an_next) { 189263720Strasz if (strcmp(auth_name->an_initator_name, name) == 0) 190263720Strasz return (auth_name); 191263720Strasz } 192263720Strasz 193263720Strasz return (NULL); 194263720Strasz} 195263720Strasz 196263720Straszconst struct auth_portal * 197263720Straszauth_portal_new(struct auth_group *ag, const char *portal) 198263720Strasz{ 199263720Strasz struct auth_portal *ap; 200263720Strasz 201263720Strasz ap = calloc(1, sizeof(*ap)); 202263720Strasz if (ap == NULL) 203263720Strasz log_err(1, "calloc"); 204263720Strasz ap->ap_auth_group = ag; 205263720Strasz ap->ap_initator_portal = checked_strdup(portal); 206263720Strasz TAILQ_INSERT_TAIL(&ag->ag_portals, ap, ap_next); 207263720Strasz return (ap); 208263720Strasz} 209263720Strasz 210263720Straszstatic void 211263720Straszauth_portal_delete(struct auth_portal *ap) 212263720Strasz{ 213263720Strasz TAILQ_REMOVE(&ap->ap_auth_group->ag_portals, ap, ap_next); 214263720Strasz 215263720Strasz free(ap->ap_initator_portal); 216263720Strasz free(ap); 217263720Strasz} 218263720Strasz 219263720Straszbool 220263720Straszauth_portal_defined(const struct auth_group *ag) 221263720Strasz{ 222263720Strasz if (TAILQ_EMPTY(&ag->ag_portals)) 223263720Strasz return (false); 224263720Strasz return (true); 225263720Strasz} 226263720Strasz 227263720Straszconst struct auth_portal * 228263720Straszauth_portal_find(const struct auth_group *ag, const char *portal) 229263720Strasz{ 230263720Strasz const struct auth_portal *auth_portal; 231263720Strasz 232263720Strasz TAILQ_FOREACH(auth_portal, &ag->ag_portals, ap_next) { 233263720Strasz if (strcmp(auth_portal->ap_initator_portal, portal) == 0) 234263720Strasz return (auth_portal); 235263720Strasz } 236263720Strasz 237263720Strasz return (NULL); 238263720Strasz} 239263720Strasz 240255570Straszstruct auth_group * 241255570Straszauth_group_new(struct conf *conf, const char *name) 242255570Strasz{ 243255570Strasz struct auth_group *ag; 244255570Strasz 245255570Strasz if (name != NULL) { 246255570Strasz ag = auth_group_find(conf, name); 247255570Strasz if (ag != NULL) { 248255570Strasz log_warnx("duplicated auth-group \"%s\"", name); 249255570Strasz return (NULL); 250255570Strasz } 251255570Strasz } 252255570Strasz 253255570Strasz ag = calloc(1, sizeof(*ag)); 254255570Strasz if (ag == NULL) 255255570Strasz log_err(1, "calloc"); 256255570Strasz if (name != NULL) 257255570Strasz ag->ag_name = checked_strdup(name); 258255570Strasz TAILQ_INIT(&ag->ag_auths); 259263720Strasz TAILQ_INIT(&ag->ag_names); 260263720Strasz TAILQ_INIT(&ag->ag_portals); 261255570Strasz ag->ag_conf = conf; 262255570Strasz TAILQ_INSERT_TAIL(&conf->conf_auth_groups, ag, ag_next); 263255570Strasz 264255570Strasz return (ag); 265255570Strasz} 266255570Strasz 267255570Straszvoid 268255570Straszauth_group_delete(struct auth_group *ag) 269255570Strasz{ 270263720Strasz struct auth *auth, *auth_tmp; 271263720Strasz struct auth_name *auth_name, *auth_name_tmp; 272263720Strasz struct auth_portal *auth_portal, *auth_portal_tmp; 273255570Strasz 274255570Strasz TAILQ_REMOVE(&ag->ag_conf->conf_auth_groups, ag, ag_next); 275255570Strasz 276263720Strasz TAILQ_FOREACH_SAFE(auth, &ag->ag_auths, a_next, auth_tmp) 277255570Strasz auth_delete(auth); 278263720Strasz TAILQ_FOREACH_SAFE(auth_name, &ag->ag_names, an_next, auth_name_tmp) 279263720Strasz auth_name_delete(auth_name); 280263720Strasz TAILQ_FOREACH_SAFE(auth_portal, &ag->ag_portals, ap_next, 281263720Strasz auth_portal_tmp) 282263720Strasz auth_portal_delete(auth_portal); 283255570Strasz free(ag->ag_name); 284255570Strasz free(ag); 285255570Strasz} 286255570Strasz 287255570Straszstruct auth_group * 288255570Straszauth_group_find(struct conf *conf, const char *name) 289255570Strasz{ 290255570Strasz struct auth_group *ag; 291255570Strasz 292255570Strasz TAILQ_FOREACH(ag, &conf->conf_auth_groups, ag_next) { 293255570Strasz if (ag->ag_name != NULL && strcmp(ag->ag_name, name) == 0) 294255570Strasz return (ag); 295255570Strasz } 296255570Strasz 297255570Strasz return (NULL); 298255570Strasz} 299255570Strasz 300255570Straszstatic void 301255570Straszauth_check_secret_length(struct auth *auth) 302255570Strasz{ 303255570Strasz size_t len; 304255570Strasz 305255570Strasz len = strlen(auth->a_secret); 306255570Strasz if (len > 16) { 307255570Strasz if (auth->a_auth_group->ag_name != NULL) 308255570Strasz log_warnx("secret for user \"%s\", auth-group \"%s\", " 309255570Strasz "is too long; it should be at most 16 characters " 310255570Strasz "long", auth->a_user, auth->a_auth_group->ag_name); 311255570Strasz else 312255570Strasz log_warnx("secret for user \"%s\", target \"%s\", " 313255570Strasz "is too long; it should be at most 16 characters " 314255570Strasz "long", auth->a_user, 315255570Strasz auth->a_auth_group->ag_target->t_iqn); 316255570Strasz } 317255570Strasz if (len < 12) { 318255570Strasz if (auth->a_auth_group->ag_name != NULL) 319255570Strasz log_warnx("secret for user \"%s\", auth-group \"%s\", " 320255570Strasz "is too short; it should be at least 12 characters " 321255570Strasz "long", auth->a_user, 322255570Strasz auth->a_auth_group->ag_name); 323255570Strasz else 324255570Strasz log_warnx("secret for user \"%s\", target \"%s\", " 325255570Strasz "is too short; it should be at least 16 characters " 326255570Strasz "long", auth->a_user, 327255570Strasz auth->a_auth_group->ag_target->t_iqn); 328255570Strasz } 329255570Strasz 330255570Strasz if (auth->a_mutual_secret != NULL) { 331255570Strasz len = strlen(auth->a_secret); 332255570Strasz if (len > 16) { 333255570Strasz if (auth->a_auth_group->ag_name != NULL) 334255570Strasz log_warnx("mutual secret for user \"%s\", " 335255570Strasz "auth-group \"%s\", is too long; it should " 336255570Strasz "be at most 16 characters long", 337255570Strasz auth->a_user, auth->a_auth_group->ag_name); 338255570Strasz else 339255570Strasz log_warnx("mutual secret for user \"%s\", " 340255570Strasz "target \"%s\", is too long; it should " 341255570Strasz "be at most 16 characters long", 342255570Strasz auth->a_user, 343255570Strasz auth->a_auth_group->ag_target->t_iqn); 344255570Strasz } 345255570Strasz if (len < 12) { 346255570Strasz if (auth->a_auth_group->ag_name != NULL) 347255570Strasz log_warnx("mutual secret for user \"%s\", " 348255570Strasz "auth-group \"%s\", is too short; it " 349255570Strasz "should be at least 12 characters long", 350255570Strasz auth->a_user, auth->a_auth_group->ag_name); 351255570Strasz else 352255570Strasz log_warnx("mutual secret for user \"%s\", " 353255570Strasz "target \"%s\", is too short; it should be " 354255570Strasz "at least 16 characters long", 355255570Strasz auth->a_user, 356255570Strasz auth->a_auth_group->ag_target->t_iqn); 357255570Strasz } 358255570Strasz } 359255570Strasz} 360255570Strasz 361255570Straszconst struct auth * 362255570Straszauth_new_chap(struct auth_group *ag, const char *user, 363255570Strasz const char *secret) 364255570Strasz{ 365255570Strasz struct auth *auth; 366255570Strasz 367255570Strasz if (ag->ag_type == AG_TYPE_UNKNOWN) 368255570Strasz ag->ag_type = AG_TYPE_CHAP; 369255570Strasz if (ag->ag_type != AG_TYPE_CHAP) { 370255570Strasz if (ag->ag_name != NULL) 371255570Strasz log_warnx("cannot mix \"chap\" authentication with " 372255570Strasz "other types for auth-group \"%s\"", ag->ag_name); 373255570Strasz else 374255570Strasz log_warnx("cannot mix \"chap\" authentication with " 375255570Strasz "other types for target \"%s\"", 376255570Strasz ag->ag_target->t_iqn); 377255570Strasz return (NULL); 378255570Strasz } 379255570Strasz 380255570Strasz auth = auth_new(ag); 381255570Strasz auth->a_user = checked_strdup(user); 382255570Strasz auth->a_secret = checked_strdup(secret); 383255570Strasz 384255570Strasz auth_check_secret_length(auth); 385255570Strasz 386255570Strasz return (auth); 387255570Strasz} 388255570Strasz 389255570Straszconst struct auth * 390255570Straszauth_new_chap_mutual(struct auth_group *ag, const char *user, 391255570Strasz const char *secret, const char *user2, const char *secret2) 392255570Strasz{ 393255570Strasz struct auth *auth; 394255570Strasz 395255570Strasz if (ag->ag_type == AG_TYPE_UNKNOWN) 396255570Strasz ag->ag_type = AG_TYPE_CHAP_MUTUAL; 397255570Strasz if (ag->ag_type != AG_TYPE_CHAP_MUTUAL) { 398255570Strasz if (ag->ag_name != NULL) 399255570Strasz log_warnx("cannot mix \"chap-mutual\" authentication " 400255570Strasz "with other types for auth-group \"%s\"", 401255570Strasz ag->ag_name); 402255570Strasz else 403255570Strasz log_warnx("cannot mix \"chap-mutual\" authentication " 404255570Strasz "with other types for target \"%s\"", 405255570Strasz ag->ag_target->t_iqn); 406255570Strasz return (NULL); 407255570Strasz } 408255570Strasz 409255570Strasz auth = auth_new(ag); 410255570Strasz auth->a_user = checked_strdup(user); 411255570Strasz auth->a_secret = checked_strdup(secret); 412255570Strasz auth->a_mutual_user = checked_strdup(user2); 413255570Strasz auth->a_mutual_secret = checked_strdup(secret2); 414255570Strasz 415255570Strasz auth_check_secret_length(auth); 416255570Strasz 417255570Strasz return (auth); 418255570Strasz} 419255570Strasz 420255570Straszstatic struct portal * 421255570Straszportal_new(struct portal_group *pg) 422255570Strasz{ 423255570Strasz struct portal *portal; 424255570Strasz 425255570Strasz portal = calloc(1, sizeof(*portal)); 426255570Strasz if (portal == NULL) 427255570Strasz log_err(1, "calloc"); 428255570Strasz TAILQ_INIT(&portal->p_targets); 429255570Strasz portal->p_portal_group = pg; 430255570Strasz TAILQ_INSERT_TAIL(&pg->pg_portals, portal, p_next); 431255570Strasz return (portal); 432255570Strasz} 433255570Strasz 434255570Straszstatic void 435255570Straszportal_delete(struct portal *portal) 436255570Strasz{ 437255570Strasz TAILQ_REMOVE(&portal->p_portal_group->pg_portals, portal, p_next); 438255570Strasz freeaddrinfo(portal->p_ai); 439255570Strasz free(portal->p_listen); 440255570Strasz free(portal); 441255570Strasz} 442255570Strasz 443255570Straszstruct portal_group * 444255570Straszportal_group_new(struct conf *conf, const char *name) 445255570Strasz{ 446255570Strasz struct portal_group *pg; 447255570Strasz 448255678Strasz pg = portal_group_find(conf, name); 449255678Strasz if (pg != NULL) { 450255678Strasz log_warnx("duplicated portal-group \"%s\"", name); 451255678Strasz return (NULL); 452255570Strasz } 453255570Strasz 454255570Strasz pg = calloc(1, sizeof(*pg)); 455255570Strasz if (pg == NULL) 456255570Strasz log_err(1, "calloc"); 457255570Strasz pg->pg_name = checked_strdup(name); 458255570Strasz TAILQ_INIT(&pg->pg_portals); 459255570Strasz pg->pg_conf = conf; 460255570Strasz conf->conf_last_portal_group_tag++; 461255570Strasz pg->pg_tag = conf->conf_last_portal_group_tag; 462255570Strasz TAILQ_INSERT_TAIL(&conf->conf_portal_groups, pg, pg_next); 463255570Strasz 464255570Strasz return (pg); 465255570Strasz} 466255570Strasz 467255570Straszvoid 468255570Straszportal_group_delete(struct portal_group *pg) 469255570Strasz{ 470255570Strasz struct portal *portal, *tmp; 471255570Strasz 472255570Strasz TAILQ_REMOVE(&pg->pg_conf->conf_portal_groups, pg, pg_next); 473255570Strasz 474255570Strasz TAILQ_FOREACH_SAFE(portal, &pg->pg_portals, p_next, tmp) 475255570Strasz portal_delete(portal); 476255570Strasz free(pg->pg_name); 477255570Strasz free(pg); 478255570Strasz} 479255570Strasz 480255570Straszstruct portal_group * 481255570Straszportal_group_find(struct conf *conf, const char *name) 482255570Strasz{ 483255570Strasz struct portal_group *pg; 484255570Strasz 485255570Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 486255570Strasz if (strcmp(pg->pg_name, name) == 0) 487255570Strasz return (pg); 488255570Strasz } 489255570Strasz 490255570Strasz return (NULL); 491255570Strasz} 492255570Strasz 493255570Straszint 494255570Straszportal_group_add_listen(struct portal_group *pg, const char *value, bool iser) 495255570Strasz{ 496255570Strasz struct addrinfo hints; 497255570Strasz struct portal *portal; 498255570Strasz char *addr, *ch, *arg; 499255570Strasz const char *port; 500255570Strasz int error, colons = 0; 501255570Strasz 502255570Strasz#ifndef ICL_KERNEL_PROXY 503255570Strasz if (iser) { 504255570Strasz log_warnx("ctld(8) compiled without ICL_KERNEL_PROXY " 505255570Strasz "does not support iSER protocol"); 506255570Strasz return (-1); 507255570Strasz } 508255570Strasz#endif 509255570Strasz 510255570Strasz portal = portal_new(pg); 511255570Strasz portal->p_listen = checked_strdup(value); 512255570Strasz portal->p_iser = iser; 513255570Strasz 514255570Strasz arg = portal->p_listen; 515255570Strasz if (arg[0] == '\0') { 516255570Strasz log_warnx("empty listen address"); 517255570Strasz free(portal->p_listen); 518255570Strasz free(portal); 519255570Strasz return (1); 520255570Strasz } 521255570Strasz if (arg[0] == '[') { 522255570Strasz /* 523255570Strasz * IPv6 address in square brackets, perhaps with port. 524255570Strasz */ 525255570Strasz arg++; 526255570Strasz addr = strsep(&arg, "]"); 527255570Strasz if (arg == NULL) { 528255570Strasz log_warnx("invalid listen address %s", 529255570Strasz portal->p_listen); 530255570Strasz free(portal->p_listen); 531255570Strasz free(portal); 532255570Strasz return (1); 533255570Strasz } 534255570Strasz if (arg[0] == '\0') { 535255570Strasz port = "3260"; 536255570Strasz } else if (arg[0] == ':') { 537255570Strasz port = arg + 1; 538255570Strasz } else { 539255570Strasz log_warnx("invalid listen address %s", 540255570Strasz portal->p_listen); 541255570Strasz free(portal->p_listen); 542255570Strasz free(portal); 543255570Strasz return (1); 544255570Strasz } 545255570Strasz } else { 546255570Strasz /* 547255570Strasz * Either IPv6 address without brackets - and without 548255570Strasz * a port - or IPv4 address. Just count the colons. 549255570Strasz */ 550255570Strasz for (ch = arg; *ch != '\0'; ch++) { 551255570Strasz if (*ch == ':') 552255570Strasz colons++; 553255570Strasz } 554255570Strasz if (colons > 1) { 555255570Strasz addr = arg; 556255570Strasz port = "3260"; 557255570Strasz } else { 558255570Strasz addr = strsep(&arg, ":"); 559255570Strasz if (arg == NULL) 560255570Strasz port = "3260"; 561255570Strasz else 562255570Strasz port = arg; 563255570Strasz } 564255570Strasz } 565255570Strasz 566255570Strasz memset(&hints, 0, sizeof(hints)); 567255570Strasz hints.ai_family = PF_UNSPEC; 568255570Strasz hints.ai_socktype = SOCK_STREAM; 569255570Strasz hints.ai_flags = AI_PASSIVE; 570255570Strasz 571255570Strasz error = getaddrinfo(addr, port, &hints, &portal->p_ai); 572255570Strasz if (error != 0) { 573255570Strasz log_warnx("getaddrinfo for %s failed: %s", 574255570Strasz portal->p_listen, gai_strerror(error)); 575255570Strasz free(portal->p_listen); 576255570Strasz free(portal); 577255570Strasz return (1); 578255570Strasz } 579255570Strasz 580255570Strasz /* 581255570Strasz * XXX: getaddrinfo(3) may return multiple addresses; we should turn 582255570Strasz * those into multiple portals. 583255570Strasz */ 584255570Strasz 585255570Strasz return (0); 586255570Strasz} 587255570Strasz 588255570Straszstatic bool 589255570Straszvalid_hex(const char ch) 590255570Strasz{ 591255570Strasz switch (ch) { 592255570Strasz case '0': 593255570Strasz case '1': 594255570Strasz case '2': 595255570Strasz case '3': 596255570Strasz case '4': 597255570Strasz case '5': 598255570Strasz case '6': 599255570Strasz case '7': 600255570Strasz case '8': 601255570Strasz case '9': 602255570Strasz case 'a': 603255570Strasz case 'A': 604255570Strasz case 'b': 605255570Strasz case 'B': 606255570Strasz case 'c': 607255570Strasz case 'C': 608255570Strasz case 'd': 609255570Strasz case 'D': 610255570Strasz case 'e': 611255570Strasz case 'E': 612255570Strasz case 'f': 613255570Strasz case 'F': 614255570Strasz return (true); 615255570Strasz default: 616255570Strasz return (false); 617255570Strasz } 618255570Strasz} 619255570Strasz 620255570Straszbool 621255570Straszvalid_iscsi_name(const char *name) 622255570Strasz{ 623255570Strasz int i; 624255570Strasz 625255570Strasz if (strlen(name) >= MAX_NAME_LEN) { 626255570Strasz log_warnx("overlong name for target \"%s\"; max length allowed " 627255570Strasz "by iSCSI specification is %d characters", 628255570Strasz name, MAX_NAME_LEN); 629255570Strasz return (false); 630255570Strasz } 631255570Strasz 632255570Strasz /* 633255570Strasz * In the cases below, we don't return an error, just in case the admin 634255570Strasz * was right, and we're wrong. 635255570Strasz */ 636255570Strasz if (strncasecmp(name, "iqn.", strlen("iqn.")) == 0) { 637255570Strasz for (i = strlen("iqn."); name[i] != '\0'; i++) { 638255570Strasz /* 639255570Strasz * XXX: We should verify UTF-8 normalisation, as defined 640255570Strasz * by 3.2.6.2: iSCSI Name Encoding. 641255570Strasz */ 642255570Strasz if (isalnum(name[i])) 643255570Strasz continue; 644255570Strasz if (name[i] == '-' || name[i] == '.' || name[i] == ':') 645255570Strasz continue; 646255570Strasz log_warnx("invalid character \"%c\" in target name " 647255570Strasz "\"%s\"; allowed characters are letters, digits, " 648255570Strasz "'-', '.', and ':'", name[i], name); 649255570Strasz break; 650255570Strasz } 651255570Strasz /* 652255570Strasz * XXX: Check more stuff: valid date and a valid reversed domain. 653255570Strasz */ 654255570Strasz } else if (strncasecmp(name, "eui.", strlen("eui.")) == 0) { 655255570Strasz if (strlen(name) != strlen("eui.") + 16) 656255570Strasz log_warnx("invalid target name \"%s\"; the \"eui.\" " 657255570Strasz "should be followed by exactly 16 hexadecimal " 658255570Strasz "digits", name); 659255570Strasz for (i = strlen("eui."); name[i] != '\0'; i++) { 660255570Strasz if (!valid_hex(name[i])) { 661255570Strasz log_warnx("invalid character \"%c\" in target " 662255570Strasz "name \"%s\"; allowed characters are 1-9 " 663255570Strasz "and A-F", name[i], name); 664255570Strasz break; 665255570Strasz } 666255570Strasz } 667255570Strasz } else if (strncasecmp(name, "naa.", strlen("naa.")) == 0) { 668255570Strasz if (strlen(name) > strlen("naa.") + 32) 669255570Strasz log_warnx("invalid target name \"%s\"; the \"naa.\" " 670255570Strasz "should be followed by at most 32 hexadecimal " 671255570Strasz "digits", name); 672255570Strasz for (i = strlen("naa."); name[i] != '\0'; i++) { 673255570Strasz if (!valid_hex(name[i])) { 674255570Strasz log_warnx("invalid character \"%c\" in target " 675255570Strasz "name \"%s\"; allowed characters are 1-9 " 676255570Strasz "and A-F", name[i], name); 677255570Strasz break; 678255570Strasz } 679255570Strasz } 680255570Strasz } else { 681255570Strasz log_warnx("invalid target name \"%s\"; should start with " 682255570Strasz "either \".iqn\", \"eui.\", or \"naa.\"", 683255570Strasz name); 684255570Strasz } 685255570Strasz return (true); 686255570Strasz} 687255570Strasz 688255570Straszstruct target * 689255570Strasztarget_new(struct conf *conf, const char *iqn) 690255570Strasz{ 691255570Strasz struct target *targ; 692255570Strasz int i, len; 693255570Strasz 694255570Strasz targ = target_find(conf, iqn); 695255570Strasz if (targ != NULL) { 696255570Strasz log_warnx("duplicated target \"%s\"", iqn); 697255570Strasz return (NULL); 698255570Strasz } 699255570Strasz if (valid_iscsi_name(iqn) == false) { 700255570Strasz log_warnx("target name \"%s\" is invalid", iqn); 701255570Strasz return (NULL); 702255570Strasz } 703255570Strasz targ = calloc(1, sizeof(*targ)); 704255570Strasz if (targ == NULL) 705255570Strasz log_err(1, "calloc"); 706255570Strasz targ->t_iqn = checked_strdup(iqn); 707255570Strasz 708255570Strasz /* 709255570Strasz * RFC 3722 requires us to normalize the name to lowercase. 710255570Strasz */ 711255570Strasz len = strlen(iqn); 712255570Strasz for (i = 0; i < len; i++) 713255570Strasz targ->t_iqn[i] = tolower(targ->t_iqn[i]); 714255570Strasz 715255570Strasz TAILQ_INIT(&targ->t_luns); 716255570Strasz targ->t_conf = conf; 717255570Strasz TAILQ_INSERT_TAIL(&conf->conf_targets, targ, t_next); 718255570Strasz 719255570Strasz return (targ); 720255570Strasz} 721255570Strasz 722255570Straszvoid 723255570Strasztarget_delete(struct target *targ) 724255570Strasz{ 725255570Strasz struct lun *lun, *tmp; 726255570Strasz 727255570Strasz TAILQ_REMOVE(&targ->t_conf->conf_targets, targ, t_next); 728255570Strasz 729255570Strasz TAILQ_FOREACH_SAFE(lun, &targ->t_luns, l_next, tmp) 730255570Strasz lun_delete(lun); 731255570Strasz free(targ->t_iqn); 732255570Strasz free(targ); 733255570Strasz} 734255570Strasz 735255570Straszstruct target * 736255570Strasztarget_find(struct conf *conf, const char *iqn) 737255570Strasz{ 738255570Strasz struct target *targ; 739255570Strasz 740255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 741255570Strasz if (strcasecmp(targ->t_iqn, iqn) == 0) 742255570Strasz return (targ); 743255570Strasz } 744255570Strasz 745255570Strasz return (NULL); 746255570Strasz} 747255570Strasz 748255570Straszstruct lun * 749255570Straszlun_new(struct target *targ, int lun_id) 750255570Strasz{ 751255570Strasz struct lun *lun; 752255570Strasz 753255570Strasz lun = lun_find(targ, lun_id); 754255570Strasz if (lun != NULL) { 755255570Strasz log_warnx("duplicated lun %d for target \"%s\"", 756255570Strasz lun_id, targ->t_iqn); 757255570Strasz return (NULL); 758255570Strasz } 759255570Strasz 760255570Strasz lun = calloc(1, sizeof(*lun)); 761255570Strasz if (lun == NULL) 762255570Strasz log_err(1, "calloc"); 763255570Strasz lun->l_lun = lun_id; 764255570Strasz TAILQ_INIT(&lun->l_options); 765255570Strasz lun->l_target = targ; 766255570Strasz TAILQ_INSERT_TAIL(&targ->t_luns, lun, l_next); 767255570Strasz 768255570Strasz return (lun); 769255570Strasz} 770255570Strasz 771255570Straszvoid 772255570Straszlun_delete(struct lun *lun) 773255570Strasz{ 774255570Strasz struct lun_option *lo, *tmp; 775255570Strasz 776255570Strasz TAILQ_REMOVE(&lun->l_target->t_luns, lun, l_next); 777255570Strasz 778255570Strasz TAILQ_FOREACH_SAFE(lo, &lun->l_options, lo_next, tmp) 779255570Strasz lun_option_delete(lo); 780255570Strasz free(lun->l_backend); 781255570Strasz free(lun->l_device_id); 782255570Strasz free(lun->l_path); 783255570Strasz free(lun->l_serial); 784255570Strasz free(lun); 785255570Strasz} 786255570Strasz 787255570Straszstruct lun * 788255570Straszlun_find(struct target *targ, int lun_id) 789255570Strasz{ 790255570Strasz struct lun *lun; 791255570Strasz 792255570Strasz TAILQ_FOREACH(lun, &targ->t_luns, l_next) { 793255570Strasz if (lun->l_lun == lun_id) 794255570Strasz return (lun); 795255570Strasz } 796255570Strasz 797255570Strasz return (NULL); 798255570Strasz} 799255570Strasz 800255570Straszvoid 801255570Straszlun_set_backend(struct lun *lun, const char *value) 802255570Strasz{ 803255570Strasz free(lun->l_backend); 804255570Strasz lun->l_backend = checked_strdup(value); 805255570Strasz} 806255570Strasz 807255570Straszvoid 808255570Straszlun_set_blocksize(struct lun *lun, size_t value) 809255570Strasz{ 810255570Strasz 811255570Strasz lun->l_blocksize = value; 812255570Strasz} 813255570Strasz 814255570Straszvoid 815255570Straszlun_set_device_id(struct lun *lun, const char *value) 816255570Strasz{ 817255570Strasz free(lun->l_device_id); 818255570Strasz lun->l_device_id = checked_strdup(value); 819255570Strasz} 820255570Strasz 821255570Straszvoid 822255570Straszlun_set_path(struct lun *lun, const char *value) 823255570Strasz{ 824255570Strasz free(lun->l_path); 825255570Strasz lun->l_path = checked_strdup(value); 826255570Strasz} 827255570Strasz 828255570Straszvoid 829255570Straszlun_set_serial(struct lun *lun, const char *value) 830255570Strasz{ 831255570Strasz free(lun->l_serial); 832255570Strasz lun->l_serial = checked_strdup(value); 833255570Strasz} 834255570Strasz 835255570Straszvoid 836255570Straszlun_set_size(struct lun *lun, size_t value) 837255570Strasz{ 838255570Strasz 839255570Strasz lun->l_size = value; 840255570Strasz} 841255570Strasz 842255570Straszvoid 843255570Straszlun_set_ctl_lun(struct lun *lun, uint32_t value) 844255570Strasz{ 845255570Strasz 846255570Strasz lun->l_ctl_lun = value; 847255570Strasz} 848255570Strasz 849255570Straszstruct lun_option * 850255570Straszlun_option_new(struct lun *lun, const char *name, const char *value) 851255570Strasz{ 852255570Strasz struct lun_option *lo; 853255570Strasz 854255570Strasz lo = lun_option_find(lun, name); 855255570Strasz if (lo != NULL) { 856255570Strasz log_warnx("duplicated lun option %s for lun %d, target \"%s\"", 857255570Strasz name, lun->l_lun, lun->l_target->t_iqn); 858255570Strasz return (NULL); 859255570Strasz } 860255570Strasz 861255570Strasz lo = calloc(1, sizeof(*lo)); 862255570Strasz if (lo == NULL) 863255570Strasz log_err(1, "calloc"); 864255570Strasz lo->lo_name = checked_strdup(name); 865255570Strasz lo->lo_value = checked_strdup(value); 866255570Strasz lo->lo_lun = lun; 867255570Strasz TAILQ_INSERT_TAIL(&lun->l_options, lo, lo_next); 868255570Strasz 869255570Strasz return (lo); 870255570Strasz} 871255570Strasz 872255570Straszvoid 873255570Straszlun_option_delete(struct lun_option *lo) 874255570Strasz{ 875255570Strasz 876255570Strasz TAILQ_REMOVE(&lo->lo_lun->l_options, lo, lo_next); 877255570Strasz 878255570Strasz free(lo->lo_name); 879255570Strasz free(lo->lo_value); 880255570Strasz free(lo); 881255570Strasz} 882255570Strasz 883255570Straszstruct lun_option * 884255570Straszlun_option_find(struct lun *lun, const char *name) 885255570Strasz{ 886255570Strasz struct lun_option *lo; 887255570Strasz 888255570Strasz TAILQ_FOREACH(lo, &lun->l_options, lo_next) { 889255570Strasz if (strcmp(lo->lo_name, name) == 0) 890255570Strasz return (lo); 891255570Strasz } 892255570Strasz 893255570Strasz return (NULL); 894255570Strasz} 895255570Strasz 896255570Straszvoid 897255570Straszlun_option_set(struct lun_option *lo, const char *value) 898255570Strasz{ 899255570Strasz 900255570Strasz free(lo->lo_value); 901255570Strasz lo->lo_value = checked_strdup(value); 902255570Strasz} 903255570Strasz 904255570Straszstatic struct connection * 905255570Straszconnection_new(struct portal *portal, int fd, const char *host) 906255570Strasz{ 907255570Strasz struct connection *conn; 908255570Strasz 909255570Strasz conn = calloc(1, sizeof(*conn)); 910255570Strasz if (conn == NULL) 911255570Strasz log_err(1, "calloc"); 912255570Strasz conn->conn_portal = portal; 913255570Strasz conn->conn_socket = fd; 914255570Strasz conn->conn_initiator_addr = checked_strdup(host); 915255570Strasz 916255570Strasz /* 917255570Strasz * Default values, from RFC 3720, section 12. 918255570Strasz */ 919255570Strasz conn->conn_max_data_segment_length = 8192; 920255570Strasz conn->conn_max_burst_length = 262144; 921255570Strasz conn->conn_immediate_data = true; 922255570Strasz 923255570Strasz return (conn); 924255570Strasz} 925255570Strasz 926255570Strasz#if 0 927255570Straszstatic void 928255570Straszconf_print(struct conf *conf) 929255570Strasz{ 930255570Strasz struct auth_group *ag; 931255570Strasz struct auth *auth; 932263720Strasz struct auth_name *auth_name; 933263720Strasz struct auth_portal *auth_portal; 934255570Strasz struct portal_group *pg; 935255570Strasz struct portal *portal; 936255570Strasz struct target *targ; 937255570Strasz struct lun *lun; 938255570Strasz struct lun_option *lo; 939255570Strasz 940255570Strasz TAILQ_FOREACH(ag, &conf->conf_auth_groups, ag_next) { 941255570Strasz fprintf(stderr, "auth-group %s {\n", ag->ag_name); 942255570Strasz TAILQ_FOREACH(auth, &ag->ag_auths, a_next) 943255570Strasz fprintf(stderr, "\t chap-mutual %s %s %s %s\n", 944255570Strasz auth->a_user, auth->a_secret, 945255570Strasz auth->a_mutual_user, auth->a_mutual_secret); 946263720Strasz TAILQ_FOREACH(auth_name, &ag->ag_names, an_next) 947263720Strasz fprintf(stderr, "\t initiator-name %s\n", 948263720Strasz auth_name->an_initator_name); 949263720Strasz TAILQ_FOREACH(auth_portal, &ag->ag_portals, an_next) 950263720Strasz fprintf(stderr, "\t initiator-portal %s\n", 951263720Strasz auth_portal->an_initator_portal); 952255570Strasz fprintf(stderr, "}\n"); 953255570Strasz } 954255570Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 955255570Strasz fprintf(stderr, "portal-group %s {\n", pg->pg_name); 956255570Strasz TAILQ_FOREACH(portal, &pg->pg_portals, p_next) 957255570Strasz fprintf(stderr, "\t listen %s\n", portal->p_listen); 958255570Strasz fprintf(stderr, "}\n"); 959255570Strasz } 960255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 961255570Strasz fprintf(stderr, "target %s {\n", targ->t_iqn); 962255570Strasz if (targ->t_alias != NULL) 963255570Strasz fprintf(stderr, "\t alias %s\n", targ->t_alias); 964255570Strasz TAILQ_FOREACH(lun, &targ->t_luns, l_next) { 965255570Strasz fprintf(stderr, "\tlun %d {\n", lun->l_lun); 966255570Strasz fprintf(stderr, "\t\tpath %s\n", lun->l_path); 967255570Strasz TAILQ_FOREACH(lo, &lun->l_options, lo_next) 968255570Strasz fprintf(stderr, "\t\toption %s %s\n", 969255570Strasz lo->lo_name, lo->lo_value); 970255570Strasz fprintf(stderr, "\t}\n"); 971255570Strasz } 972255570Strasz fprintf(stderr, "}\n"); 973255570Strasz } 974255570Strasz} 975255570Strasz#endif 976255570Strasz 977263717Straszstatic int 978263717Straszconf_verify_lun(struct lun *lun) 979263717Strasz{ 980263717Strasz const struct lun *lun2; 981263718Strasz const struct target *targ2; 982263717Strasz 983263717Strasz if (lun->l_backend == NULL) 984263717Strasz lun_set_backend(lun, "block"); 985263717Strasz if (strcmp(lun->l_backend, "block") == 0) { 986263717Strasz if (lun->l_path == NULL) { 987263717Strasz log_warnx("missing path for lun %d, target \"%s\"", 988263717Strasz lun->l_lun, lun->l_target->t_iqn); 989263717Strasz return (1); 990263717Strasz } 991263717Strasz } else if (strcmp(lun->l_backend, "ramdisk") == 0) { 992263717Strasz if (lun->l_size == 0) { 993263717Strasz log_warnx("missing size for ramdisk-backed lun %d, " 994263717Strasz "target \"%s\"", lun->l_lun, lun->l_target->t_iqn); 995263717Strasz return (1); 996263717Strasz } 997263717Strasz if (lun->l_path != NULL) { 998263717Strasz log_warnx("path must not be specified " 999263717Strasz "for ramdisk-backed lun %d, target \"%s\"", 1000263717Strasz lun->l_lun, lun->l_target->t_iqn); 1001263717Strasz return (1); 1002263717Strasz } 1003263717Strasz } 1004263717Strasz if (lun->l_lun < 0 || lun->l_lun > 255) { 1005263717Strasz log_warnx("invalid lun number for lun %d, target \"%s\"; " 1006263717Strasz "must be between 0 and 255", lun->l_lun, 1007263717Strasz lun->l_target->t_iqn); 1008263717Strasz return (1); 1009263717Strasz } 1010263717Strasz if (lun->l_blocksize == 0) { 1011263717Strasz lun_set_blocksize(lun, DEFAULT_BLOCKSIZE); 1012263717Strasz } else if (lun->l_blocksize < 0) { 1013263717Strasz log_warnx("invalid blocksize for lun %d, target \"%s\"; " 1014263717Strasz "must be larger than 0", lun->l_lun, lun->l_target->t_iqn); 1015263717Strasz return (1); 1016263717Strasz } 1017263717Strasz if (lun->l_size != 0 && lun->l_size % lun->l_blocksize != 0) { 1018263717Strasz log_warnx("invalid size for lun %d, target \"%s\"; " 1019263717Strasz "must be multiple of blocksize", lun->l_lun, 1020263717Strasz lun->l_target->t_iqn); 1021263717Strasz return (1); 1022263717Strasz } 1023263718Strasz TAILQ_FOREACH(targ2, &lun->l_target->t_conf->conf_targets, t_next) { 1024263718Strasz TAILQ_FOREACH(lun2, &targ2->t_luns, l_next) { 1025263718Strasz if (lun == lun2) 1026263718Strasz continue; 1027263718Strasz if (lun->l_path != NULL && lun2->l_path != NULL && 1028263718Strasz strcmp(lun->l_path, lun2->l_path) == 0) { 1029263718Strasz log_debugx("WARNING: path \"%s\" duplicated " 1030263718Strasz "between lun %d, target \"%s\", and " 1031263718Strasz "lun %d, target \"%s\"", lun->l_path, 1032263718Strasz lun->l_lun, lun->l_target->t_iqn, 1033263718Strasz lun2->l_lun, lun2->l_target->t_iqn); 1034263718Strasz } 1035263718Strasz } 1036263718Strasz } 1037263717Strasz 1038263717Strasz return (0); 1039263717Strasz} 1040263717Strasz 1041255570Straszint 1042255570Straszconf_verify(struct conf *conf) 1043255570Strasz{ 1044255570Strasz struct auth_group *ag; 1045255570Strasz struct portal_group *pg; 1046255570Strasz struct target *targ; 1047263717Strasz struct lun *lun; 1048255570Strasz bool found_lun0; 1049263717Strasz int error; 1050255570Strasz 1051255570Strasz if (conf->conf_pidfile_path == NULL) 1052255570Strasz conf->conf_pidfile_path = checked_strdup(DEFAULT_PIDFILE); 1053255570Strasz 1054255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 1055255570Strasz if (targ->t_auth_group == NULL) { 1056255570Strasz log_warnx("missing authentication for target \"%s\"; " 1057255570Strasz "must specify either \"auth-group\", \"chap\", " 1058255570Strasz "or \"chap-mutual\"", targ->t_iqn); 1059255570Strasz return (1); 1060255570Strasz } 1061255570Strasz if (targ->t_portal_group == NULL) { 1062255570Strasz targ->t_portal_group = portal_group_find(conf, 1063255570Strasz "default"); 1064255570Strasz assert(targ->t_portal_group != NULL); 1065255570Strasz } 1066255570Strasz found_lun0 = false; 1067255570Strasz TAILQ_FOREACH(lun, &targ->t_luns, l_next) { 1068263717Strasz error = conf_verify_lun(lun); 1069263717Strasz if (error != 0) 1070263717Strasz return (error); 1071255570Strasz if (lun->l_lun == 0) 1072255570Strasz found_lun0 = true; 1073255570Strasz } 1074255570Strasz if (!found_lun0) { 1075255570Strasz log_warnx("mandatory LUN 0 not configured " 1076255570Strasz "for target \"%s\"", targ->t_iqn); 1077255570Strasz return (1); 1078255570Strasz } 1079255570Strasz } 1080255570Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 1081255570Strasz assert(pg->pg_name != NULL); 1082255570Strasz if (pg->pg_discovery_auth_group == NULL) { 1083255570Strasz pg->pg_discovery_auth_group = 1084255570Strasz auth_group_find(conf, "no-access"); 1085255570Strasz assert(pg->pg_discovery_auth_group != NULL); 1086255570Strasz } 1087255570Strasz 1088255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 1089255570Strasz if (targ->t_portal_group == pg) 1090255570Strasz break; 1091255570Strasz } 1092255570Strasz if (targ == NULL) { 1093255570Strasz if (strcmp(pg->pg_name, "default") != 0) 1094255570Strasz log_warnx("portal-group \"%s\" not assigned " 1095255570Strasz "to any target", pg->pg_name); 1096255570Strasz pg->pg_unassigned = true; 1097255570Strasz } else 1098255570Strasz pg->pg_unassigned = false; 1099255570Strasz } 1100255570Strasz TAILQ_FOREACH(ag, &conf->conf_auth_groups, ag_next) { 1101255570Strasz if (ag->ag_name == NULL) 1102255570Strasz assert(ag->ag_target != NULL); 1103255570Strasz else 1104255570Strasz assert(ag->ag_target == NULL); 1105255570Strasz 1106255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 1107255570Strasz if (targ->t_auth_group == ag) 1108255570Strasz break; 1109255570Strasz } 1110255570Strasz if (targ == NULL && ag->ag_name != NULL && 1111255570Strasz strcmp(ag->ag_name, "no-authentication") != 0 && 1112255570Strasz strcmp(ag->ag_name, "no-access") != 0) { 1113255570Strasz log_warnx("auth-group \"%s\" not assigned " 1114255570Strasz "to any target", ag->ag_name); 1115255570Strasz } 1116255570Strasz } 1117255570Strasz 1118255570Strasz return (0); 1119255570Strasz} 1120255570Strasz 1121255570Straszstatic int 1122255570Straszconf_apply(struct conf *oldconf, struct conf *newconf) 1123255570Strasz{ 1124255570Strasz struct target *oldtarg, *newtarg, *tmptarg; 1125255570Strasz struct lun *oldlun, *newlun, *tmplun; 1126255570Strasz struct portal_group *oldpg, *newpg; 1127255570Strasz struct portal *oldp, *newp; 1128255570Strasz pid_t otherpid; 1129255570Strasz int changed, cumulated_error = 0, error; 1130255570Strasz#ifndef ICL_KERNEL_PROXY 1131255570Strasz int one = 1; 1132255570Strasz#endif 1133255570Strasz 1134255570Strasz if (oldconf->conf_debug != newconf->conf_debug) { 1135255570Strasz log_debugx("changing debug level to %d", newconf->conf_debug); 1136255570Strasz log_init(newconf->conf_debug); 1137255570Strasz } 1138255570Strasz 1139255570Strasz if (oldconf->conf_pidfh != NULL) { 1140255570Strasz assert(oldconf->conf_pidfile_path != NULL); 1141255570Strasz if (newconf->conf_pidfile_path != NULL && 1142255570Strasz strcmp(oldconf->conf_pidfile_path, 1143255570Strasz newconf->conf_pidfile_path) == 0) { 1144255570Strasz newconf->conf_pidfh = oldconf->conf_pidfh; 1145255570Strasz oldconf->conf_pidfh = NULL; 1146255570Strasz } else { 1147255570Strasz log_debugx("removing pidfile %s", 1148255570Strasz oldconf->conf_pidfile_path); 1149255570Strasz pidfile_remove(oldconf->conf_pidfh); 1150255570Strasz oldconf->conf_pidfh = NULL; 1151255570Strasz } 1152255570Strasz } 1153255570Strasz 1154255570Strasz if (newconf->conf_pidfh == NULL && newconf->conf_pidfile_path != NULL) { 1155255570Strasz log_debugx("opening pidfile %s", newconf->conf_pidfile_path); 1156255570Strasz newconf->conf_pidfh = 1157255570Strasz pidfile_open(newconf->conf_pidfile_path, 0600, &otherpid); 1158255570Strasz if (newconf->conf_pidfh == NULL) { 1159255570Strasz if (errno == EEXIST) 1160255570Strasz log_errx(1, "daemon already running, pid: %jd.", 1161255570Strasz (intmax_t)otherpid); 1162255570Strasz log_err(1, "cannot open or create pidfile \"%s\"", 1163255570Strasz newconf->conf_pidfile_path); 1164255570Strasz } 1165255570Strasz } 1166255570Strasz 1167255570Strasz TAILQ_FOREACH_SAFE(oldtarg, &oldconf->conf_targets, t_next, tmptarg) { 1168255570Strasz /* 1169255570Strasz * First, remove any targets present in the old configuration 1170255570Strasz * and missing in the new one. 1171255570Strasz */ 1172255570Strasz newtarg = target_find(newconf, oldtarg->t_iqn); 1173255570Strasz if (newtarg == NULL) { 1174255570Strasz TAILQ_FOREACH_SAFE(oldlun, &oldtarg->t_luns, l_next, 1175255570Strasz tmplun) { 1176263716Strasz log_debugx("target %s not found in new " 1177263716Strasz "configuration; removing its lun %d, " 1178255570Strasz "backed by CTL lun %d", 1179255570Strasz oldtarg->t_iqn, oldlun->l_lun, 1180255570Strasz oldlun->l_ctl_lun); 1181255570Strasz error = kernel_lun_remove(oldlun); 1182255570Strasz if (error != 0) { 1183255570Strasz log_warnx("failed to remove lun %d, " 1184255570Strasz "target %s, CTL lun %d", 1185255570Strasz oldlun->l_lun, oldtarg->t_iqn, 1186255570Strasz oldlun->l_ctl_lun); 1187255570Strasz cumulated_error++; 1188255570Strasz } 1189255570Strasz lun_delete(oldlun); 1190255570Strasz } 1191255570Strasz target_delete(oldtarg); 1192255570Strasz continue; 1193255570Strasz } 1194255570Strasz 1195255570Strasz /* 1196255570Strasz * Second, remove any LUNs present in the old target 1197255570Strasz * and missing in the new one. 1198255570Strasz */ 1199255570Strasz TAILQ_FOREACH_SAFE(oldlun, &oldtarg->t_luns, l_next, tmplun) { 1200255570Strasz newlun = lun_find(newtarg, oldlun->l_lun); 1201255570Strasz if (newlun == NULL) { 1202255570Strasz log_debugx("lun %d, target %s, CTL lun %d " 1203263716Strasz "not found in new configuration; " 1204255570Strasz "removing", oldlun->l_lun, oldtarg->t_iqn, 1205255570Strasz oldlun->l_ctl_lun); 1206255570Strasz error = kernel_lun_remove(oldlun); 1207255570Strasz if (error != 0) { 1208255570Strasz log_warnx("failed to remove lun %d, " 1209255570Strasz "target %s, CTL lun %d", 1210255570Strasz oldlun->l_lun, oldtarg->t_iqn, 1211255570Strasz oldlun->l_ctl_lun); 1212255570Strasz cumulated_error++; 1213255570Strasz } 1214255570Strasz lun_delete(oldlun); 1215255570Strasz continue; 1216255570Strasz } 1217255570Strasz 1218255570Strasz /* 1219255570Strasz * Also remove the LUNs changed by more than size. 1220255570Strasz */ 1221255570Strasz changed = 0; 1222255570Strasz assert(oldlun->l_backend != NULL); 1223255570Strasz assert(newlun->l_backend != NULL); 1224255570Strasz if (strcmp(newlun->l_backend, oldlun->l_backend) != 0) { 1225255570Strasz log_debugx("backend for lun %d, target %s, " 1226255570Strasz "CTL lun %d changed; removing", 1227255570Strasz oldlun->l_lun, oldtarg->t_iqn, 1228255570Strasz oldlun->l_ctl_lun); 1229255570Strasz changed = 1; 1230255570Strasz } 1231255570Strasz if (oldlun->l_blocksize != newlun->l_blocksize) { 1232255570Strasz log_debugx("blocksize for lun %d, target %s, " 1233255570Strasz "CTL lun %d changed; removing", 1234255570Strasz oldlun->l_lun, oldtarg->t_iqn, 1235255570Strasz oldlun->l_ctl_lun); 1236255570Strasz changed = 1; 1237255570Strasz } 1238255570Strasz if (newlun->l_device_id != NULL && 1239255570Strasz (oldlun->l_device_id == NULL || 1240255570Strasz strcmp(oldlun->l_device_id, newlun->l_device_id) != 1241255570Strasz 0)) { 1242255570Strasz log_debugx("device-id for lun %d, target %s, " 1243255570Strasz "CTL lun %d changed; removing", 1244255570Strasz oldlun->l_lun, oldtarg->t_iqn, 1245255570Strasz oldlun->l_ctl_lun); 1246255570Strasz changed = 1; 1247255570Strasz } 1248255570Strasz if (newlun->l_path != NULL && 1249255570Strasz (oldlun->l_path == NULL || 1250255570Strasz strcmp(oldlun->l_path, newlun->l_path) != 0)) { 1251255570Strasz log_debugx("path for lun %d, target %s, " 1252255570Strasz "CTL lun %d, changed; removing", 1253255570Strasz oldlun->l_lun, oldtarg->t_iqn, 1254255570Strasz oldlun->l_ctl_lun); 1255255570Strasz changed = 1; 1256255570Strasz } 1257255570Strasz if (newlun->l_serial != NULL && 1258255570Strasz (oldlun->l_serial == NULL || 1259255570Strasz strcmp(oldlun->l_serial, newlun->l_serial) != 0)) { 1260255570Strasz log_debugx("serial for lun %d, target %s, " 1261255570Strasz "CTL lun %d changed; removing", 1262255570Strasz oldlun->l_lun, oldtarg->t_iqn, 1263255570Strasz oldlun->l_ctl_lun); 1264255570Strasz changed = 1; 1265255570Strasz } 1266255570Strasz if (changed) { 1267255570Strasz error = kernel_lun_remove(oldlun); 1268255570Strasz if (error != 0) { 1269255570Strasz log_warnx("failed to remove lun %d, " 1270255570Strasz "target %s, CTL lun %d", 1271255570Strasz oldlun->l_lun, oldtarg->t_iqn, 1272255570Strasz oldlun->l_ctl_lun); 1273255570Strasz cumulated_error++; 1274255570Strasz } 1275255570Strasz lun_delete(oldlun); 1276255570Strasz continue; 1277255570Strasz } 1278255570Strasz 1279255570Strasz lun_set_ctl_lun(newlun, oldlun->l_ctl_lun); 1280255570Strasz } 1281255570Strasz } 1282255570Strasz 1283255570Strasz /* 1284255570Strasz * Now add new targets or modify existing ones. 1285255570Strasz */ 1286255570Strasz TAILQ_FOREACH(newtarg, &newconf->conf_targets, t_next) { 1287255570Strasz oldtarg = target_find(oldconf, newtarg->t_iqn); 1288255570Strasz 1289255570Strasz TAILQ_FOREACH(newlun, &newtarg->t_luns, l_next) { 1290255570Strasz if (oldtarg != NULL) { 1291255570Strasz oldlun = lun_find(oldtarg, newlun->l_lun); 1292255570Strasz if (oldlun != NULL) { 1293255570Strasz if (newlun->l_size != oldlun->l_size) { 1294255570Strasz log_debugx("resizing lun %d, " 1295255570Strasz "target %s, CTL lun %d", 1296255570Strasz newlun->l_lun, 1297255570Strasz newtarg->t_iqn, 1298255570Strasz newlun->l_ctl_lun); 1299255570Strasz error = 1300255570Strasz kernel_lun_resize(newlun); 1301255570Strasz if (error != 0) { 1302255570Strasz log_warnx("failed to " 1303255570Strasz "resize lun %d, " 1304255570Strasz "target %s, " 1305255570Strasz "CTL lun %d", 1306255570Strasz newlun->l_lun, 1307255570Strasz newtarg->t_iqn, 1308255570Strasz newlun->l_lun); 1309255570Strasz cumulated_error++; 1310255570Strasz } 1311255570Strasz } 1312255570Strasz continue; 1313255570Strasz } 1314255570Strasz } 1315255570Strasz log_debugx("adding lun %d, target %s", 1316255570Strasz newlun->l_lun, newtarg->t_iqn); 1317255570Strasz error = kernel_lun_add(newlun); 1318255570Strasz if (error != 0) { 1319255570Strasz log_warnx("failed to add lun %d, target %s", 1320255570Strasz newlun->l_lun, newtarg->t_iqn); 1321255570Strasz cumulated_error++; 1322255570Strasz } 1323255570Strasz } 1324255570Strasz } 1325255570Strasz 1326255570Strasz /* 1327255570Strasz * Go through the new portals, opening the sockets as neccessary. 1328255570Strasz */ 1329255570Strasz TAILQ_FOREACH(newpg, &newconf->conf_portal_groups, pg_next) { 1330255570Strasz if (newpg->pg_unassigned) { 1331255570Strasz log_debugx("not listening on portal-group \"%s\", " 1332255570Strasz "not assigned to any target", 1333255570Strasz newpg->pg_name); 1334255570Strasz continue; 1335255570Strasz } 1336255570Strasz TAILQ_FOREACH(newp, &newpg->pg_portals, p_next) { 1337255570Strasz /* 1338255570Strasz * Try to find already open portal and reuse 1339255570Strasz * the listening socket. We don't care about 1340255570Strasz * what portal or portal group that was, what 1341255570Strasz * matters is the listening address. 1342255570Strasz */ 1343255570Strasz TAILQ_FOREACH(oldpg, &oldconf->conf_portal_groups, 1344255570Strasz pg_next) { 1345255570Strasz TAILQ_FOREACH(oldp, &oldpg->pg_portals, 1346255570Strasz p_next) { 1347255570Strasz if (strcmp(newp->p_listen, 1348255570Strasz oldp->p_listen) == 0 && 1349255570Strasz oldp->p_socket > 0) { 1350255570Strasz newp->p_socket = 1351255570Strasz oldp->p_socket; 1352255570Strasz oldp->p_socket = 0; 1353255570Strasz break; 1354255570Strasz } 1355255570Strasz } 1356255570Strasz } 1357255570Strasz if (newp->p_socket > 0) { 1358255570Strasz /* 1359255570Strasz * We're done with this portal. 1360255570Strasz */ 1361255570Strasz continue; 1362255570Strasz } 1363255570Strasz 1364255570Strasz#ifdef ICL_KERNEL_PROXY 1365255570Strasz log_debugx("listening on %s, portal-group \"%s\" using ICL proxy", 1366255570Strasz newp->p_listen, newpg->pg_name); 1367255570Strasz kernel_listen(newp->p_ai, newp->p_iser); 1368255570Strasz#else 1369255570Strasz assert(newp->p_iser == false); 1370255570Strasz 1371255570Strasz log_debugx("listening on %s, portal-group \"%s\"", 1372255570Strasz newp->p_listen, newpg->pg_name); 1373255570Strasz newp->p_socket = socket(newp->p_ai->ai_family, 1374255570Strasz newp->p_ai->ai_socktype, 1375255570Strasz newp->p_ai->ai_protocol); 1376255570Strasz if (newp->p_socket < 0) { 1377255570Strasz log_warn("socket(2) failed for %s", 1378255570Strasz newp->p_listen); 1379255570Strasz cumulated_error++; 1380255570Strasz continue; 1381255570Strasz } 1382255570Strasz error = setsockopt(newp->p_socket, SOL_SOCKET, 1383255570Strasz SO_REUSEADDR, &one, sizeof(one)); 1384255570Strasz if (error != 0) { 1385255570Strasz log_warn("setsockopt(SO_REUSEADDR) failed " 1386255570Strasz "for %s", newp->p_listen); 1387255570Strasz close(newp->p_socket); 1388255570Strasz newp->p_socket = 0; 1389255570Strasz cumulated_error++; 1390255570Strasz continue; 1391255570Strasz } 1392255570Strasz error = bind(newp->p_socket, newp->p_ai->ai_addr, 1393255570Strasz newp->p_ai->ai_addrlen); 1394255570Strasz if (error != 0) { 1395255570Strasz log_warn("bind(2) failed for %s", 1396255570Strasz newp->p_listen); 1397255570Strasz close(newp->p_socket); 1398255570Strasz newp->p_socket = 0; 1399255570Strasz cumulated_error++; 1400255570Strasz continue; 1401255570Strasz } 1402255570Strasz error = listen(newp->p_socket, -1); 1403255570Strasz if (error != 0) { 1404255570Strasz log_warn("listen(2) failed for %s", 1405255570Strasz newp->p_listen); 1406255570Strasz close(newp->p_socket); 1407255570Strasz newp->p_socket = 0; 1408255570Strasz cumulated_error++; 1409255570Strasz continue; 1410255570Strasz } 1411255570Strasz#endif /* !ICL_KERNEL_PROXY */ 1412255570Strasz } 1413255570Strasz } 1414255570Strasz 1415255570Strasz /* 1416255570Strasz * Go through the no longer used sockets, closing them. 1417255570Strasz */ 1418255570Strasz TAILQ_FOREACH(oldpg, &oldconf->conf_portal_groups, pg_next) { 1419255570Strasz TAILQ_FOREACH(oldp, &oldpg->pg_portals, p_next) { 1420255570Strasz if (oldp->p_socket <= 0) 1421255570Strasz continue; 1422255570Strasz log_debugx("closing socket for %s, portal-group \"%s\"", 1423255570Strasz oldp->p_listen, oldpg->pg_name); 1424255570Strasz close(oldp->p_socket); 1425255570Strasz oldp->p_socket = 0; 1426255570Strasz } 1427255570Strasz } 1428255570Strasz 1429255570Strasz return (cumulated_error); 1430255570Strasz} 1431255570Strasz 1432255570Straszbool 1433255570Strasztimed_out(void) 1434255570Strasz{ 1435255570Strasz 1436255570Strasz return (sigalrm_received); 1437255570Strasz} 1438255570Strasz 1439255570Straszstatic void 1440255570Straszsigalrm_handler(int dummy __unused) 1441255570Strasz{ 1442255570Strasz /* 1443255570Strasz * It would be easiest to just log an error and exit. We can't 1444255570Strasz * do this, though, because log_errx() is not signal safe, since 1445255570Strasz * it calls syslog(3). Instead, set a flag checked by pdu_send() 1446255570Strasz * and pdu_receive(), to call log_errx() there. Should they fail 1447255570Strasz * to notice, we'll exit here one second later. 1448255570Strasz */ 1449255570Strasz if (sigalrm_received) { 1450255570Strasz /* 1451255570Strasz * Oh well. Just give up and quit. 1452255570Strasz */ 1453255570Strasz _exit(2); 1454255570Strasz } 1455255570Strasz 1456255570Strasz sigalrm_received = true; 1457255570Strasz} 1458255570Strasz 1459255570Straszstatic void 1460255570Straszset_timeout(const struct conf *conf) 1461255570Strasz{ 1462255570Strasz struct sigaction sa; 1463255570Strasz struct itimerval itv; 1464255570Strasz int error; 1465255570Strasz 1466255570Strasz if (conf->conf_timeout <= 0) { 1467255570Strasz log_debugx("session timeout disabled"); 1468255570Strasz return; 1469255570Strasz } 1470255570Strasz 1471255570Strasz bzero(&sa, sizeof(sa)); 1472255570Strasz sa.sa_handler = sigalrm_handler; 1473255570Strasz sigfillset(&sa.sa_mask); 1474255570Strasz error = sigaction(SIGALRM, &sa, NULL); 1475255570Strasz if (error != 0) 1476255570Strasz log_err(1, "sigaction"); 1477255570Strasz 1478255570Strasz /* 1479255570Strasz * First SIGALRM will arive after conf_timeout seconds. 1480255570Strasz * If we do nothing, another one will arrive a second later. 1481255570Strasz */ 1482255570Strasz bzero(&itv, sizeof(itv)); 1483255570Strasz itv.it_interval.tv_sec = 1; 1484255570Strasz itv.it_value.tv_sec = conf->conf_timeout; 1485255570Strasz 1486255570Strasz log_debugx("setting session timeout to %d seconds", 1487255570Strasz conf->conf_timeout); 1488255570Strasz error = setitimer(ITIMER_REAL, &itv, NULL); 1489255570Strasz if (error != 0) 1490255570Strasz log_err(1, "setitimer"); 1491255570Strasz} 1492255570Strasz 1493255570Straszstatic int 1494255570Straszwait_for_children(bool block) 1495255570Strasz{ 1496255570Strasz pid_t pid; 1497255570Strasz int status; 1498255570Strasz int num = 0; 1499255570Strasz 1500255570Strasz for (;;) { 1501255570Strasz /* 1502255570Strasz * If "block" is true, wait for at least one process. 1503255570Strasz */ 1504255570Strasz if (block && num == 0) 1505255570Strasz pid = wait4(-1, &status, 0, NULL); 1506255570Strasz else 1507255570Strasz pid = wait4(-1, &status, WNOHANG, NULL); 1508255570Strasz if (pid <= 0) 1509255570Strasz break; 1510255570Strasz if (WIFSIGNALED(status)) { 1511255570Strasz log_warnx("child process %d terminated with signal %d", 1512255570Strasz pid, WTERMSIG(status)); 1513255570Strasz } else if (WEXITSTATUS(status) != 0) { 1514255570Strasz log_warnx("child process %d terminated with exit status %d", 1515255570Strasz pid, WEXITSTATUS(status)); 1516255570Strasz } else { 1517255570Strasz log_debugx("child process %d terminated gracefully", pid); 1518255570Strasz } 1519255570Strasz num++; 1520255570Strasz } 1521255570Strasz 1522255570Strasz return (num); 1523255570Strasz} 1524255570Strasz 1525255570Straszstatic void 1526255570Straszhandle_connection(struct portal *portal, int fd, bool dont_fork) 1527255570Strasz{ 1528255570Strasz struct connection *conn; 1529255570Strasz#ifndef ICL_KERNEL_PROXY 1530255570Strasz struct sockaddr_storage ss; 1531255570Strasz socklen_t sslen = sizeof(ss); 1532255570Strasz int error; 1533255570Strasz#endif 1534255570Strasz pid_t pid; 1535255570Strasz char host[NI_MAXHOST + 1]; 1536255570Strasz struct conf *conf; 1537255570Strasz 1538255570Strasz conf = portal->p_portal_group->pg_conf; 1539255570Strasz 1540255570Strasz if (dont_fork) { 1541255570Strasz log_debugx("incoming connection; not forking due to -d flag"); 1542255570Strasz } else { 1543255570Strasz nchildren -= wait_for_children(false); 1544255570Strasz assert(nchildren >= 0); 1545255570Strasz 1546255570Strasz while (conf->conf_maxproc > 0 && nchildren >= conf->conf_maxproc) { 1547255570Strasz log_debugx("maxproc limit of %d child processes hit; " 1548255570Strasz "waiting for child process to exit", conf->conf_maxproc); 1549255570Strasz nchildren -= wait_for_children(true); 1550255570Strasz assert(nchildren >= 0); 1551255570Strasz } 1552255570Strasz log_debugx("incoming connection; forking child process #%d", 1553255570Strasz nchildren); 1554255570Strasz nchildren++; 1555255570Strasz pid = fork(); 1556255570Strasz if (pid < 0) 1557255570Strasz log_err(1, "fork"); 1558255570Strasz if (pid > 0) { 1559255570Strasz close(fd); 1560255570Strasz return; 1561255570Strasz } 1562255570Strasz } 1563255570Strasz pidfile_close(conf->conf_pidfh); 1564255570Strasz 1565255570Strasz#ifdef ICL_KERNEL_PROXY 1566255570Strasz /* 1567255570Strasz * XXX 1568255570Strasz */ 1569255570Strasz log_set_peer_addr("XXX"); 1570255570Strasz#else 1571255570Strasz error = getpeername(fd, (struct sockaddr *)&ss, &sslen); 1572255570Strasz if (error != 0) 1573255570Strasz log_err(1, "getpeername"); 1574255570Strasz error = getnameinfo((struct sockaddr *)&ss, sslen, 1575255570Strasz host, sizeof(host), NULL, 0, NI_NUMERICHOST); 1576255570Strasz if (error != 0) 1577255570Strasz log_errx(1, "getaddrinfo: %s", gai_strerror(error)); 1578255570Strasz 1579255570Strasz log_debugx("accepted connection from %s; portal group \"%s\"", 1580255570Strasz host, portal->p_portal_group->pg_name); 1581255570Strasz log_set_peer_addr(host); 1582255570Strasz setproctitle("%s", host); 1583255570Strasz#endif 1584255570Strasz 1585255570Strasz conn = connection_new(portal, fd, host); 1586255570Strasz set_timeout(conf); 1587255570Strasz kernel_capsicate(); 1588255570Strasz login(conn); 1589255570Strasz if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) { 1590255570Strasz kernel_handoff(conn); 1591255570Strasz log_debugx("connection handed off to the kernel"); 1592255570Strasz } else { 1593255570Strasz assert(conn->conn_session_type == CONN_SESSION_TYPE_DISCOVERY); 1594255570Strasz discovery(conn); 1595255570Strasz } 1596255570Strasz log_debugx("nothing more to do; exiting"); 1597255570Strasz exit(0); 1598255570Strasz} 1599255570Strasz 1600255570Strasz#ifndef ICL_KERNEL_PROXY 1601255570Straszstatic int 1602255570Straszfd_add(int fd, fd_set *fdset, int nfds) 1603255570Strasz{ 1604255570Strasz 1605255570Strasz /* 1606255570Strasz * Skip sockets which we failed to bind. 1607255570Strasz */ 1608255570Strasz if (fd <= 0) 1609255570Strasz return (nfds); 1610255570Strasz 1611255570Strasz FD_SET(fd, fdset); 1612255570Strasz if (fd > nfds) 1613255570Strasz nfds = fd; 1614255570Strasz return (nfds); 1615255570Strasz} 1616255570Strasz#endif 1617255570Strasz 1618255570Straszstatic void 1619255570Straszmain_loop(struct conf *conf, bool dont_fork) 1620255570Strasz{ 1621255570Strasz struct portal_group *pg; 1622255570Strasz struct portal *portal; 1623255570Strasz#ifdef ICL_KERNEL_PROXY 1624255570Strasz int connection_id; 1625255570Strasz#else 1626255570Strasz fd_set fdset; 1627255570Strasz int error, nfds, client_fd; 1628255570Strasz#endif 1629255570Strasz 1630255570Strasz pidfile_write(conf->conf_pidfh); 1631255570Strasz 1632255570Strasz for (;;) { 1633255570Strasz if (sighup_received || sigterm_received) 1634255570Strasz return; 1635255570Strasz 1636255570Strasz#ifdef ICL_KERNEL_PROXY 1637255570Strasz connection_id = kernel_accept(); 1638255570Strasz if (connection_id == 0) 1639255570Strasz continue; 1640255570Strasz 1641255570Strasz /* 1642255570Strasz * XXX: This is obviously temporary. 1643255570Strasz */ 1644255570Strasz pg = TAILQ_FIRST(&conf->conf_portal_groups); 1645255570Strasz portal = TAILQ_FIRST(&pg->pg_portals); 1646255570Strasz 1647255570Strasz handle_connection(portal, connection_id, dont_fork); 1648255570Strasz#else 1649255570Strasz FD_ZERO(&fdset); 1650255570Strasz nfds = 0; 1651255570Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 1652255570Strasz TAILQ_FOREACH(portal, &pg->pg_portals, p_next) 1653255570Strasz nfds = fd_add(portal->p_socket, &fdset, nfds); 1654255570Strasz } 1655255570Strasz error = select(nfds + 1, &fdset, NULL, NULL, NULL); 1656255570Strasz if (error <= 0) { 1657255570Strasz if (errno == EINTR) 1658255570Strasz return; 1659255570Strasz log_err(1, "select"); 1660255570Strasz } 1661255570Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 1662255570Strasz TAILQ_FOREACH(portal, &pg->pg_portals, p_next) { 1663255570Strasz if (!FD_ISSET(portal->p_socket, &fdset)) 1664255570Strasz continue; 1665255570Strasz client_fd = accept(portal->p_socket, NULL, 0); 1666255570Strasz if (client_fd < 0) 1667255570Strasz log_err(1, "accept"); 1668255570Strasz handle_connection(portal, client_fd, dont_fork); 1669255570Strasz break; 1670255570Strasz } 1671255570Strasz } 1672255570Strasz#endif /* !ICL_KERNEL_PROXY */ 1673255570Strasz } 1674255570Strasz} 1675255570Strasz 1676255570Straszstatic void 1677255570Straszsighup_handler(int dummy __unused) 1678255570Strasz{ 1679255570Strasz 1680255570Strasz sighup_received = true; 1681255570Strasz} 1682255570Strasz 1683255570Straszstatic void 1684255570Straszsigterm_handler(int dummy __unused) 1685255570Strasz{ 1686255570Strasz 1687255570Strasz sigterm_received = true; 1688255570Strasz} 1689255570Strasz 1690255570Straszstatic void 1691255570Straszregister_signals(void) 1692255570Strasz{ 1693255570Strasz struct sigaction sa; 1694255570Strasz int error; 1695255570Strasz 1696255570Strasz bzero(&sa, sizeof(sa)); 1697255570Strasz sa.sa_handler = sighup_handler; 1698255570Strasz sigfillset(&sa.sa_mask); 1699255570Strasz error = sigaction(SIGHUP, &sa, NULL); 1700255570Strasz if (error != 0) 1701255570Strasz log_err(1, "sigaction"); 1702255570Strasz 1703255570Strasz sa.sa_handler = sigterm_handler; 1704255570Strasz error = sigaction(SIGTERM, &sa, NULL); 1705255570Strasz if (error != 0) 1706255570Strasz log_err(1, "sigaction"); 1707255570Strasz 1708255570Strasz sa.sa_handler = sigterm_handler; 1709255570Strasz error = sigaction(SIGINT, &sa, NULL); 1710255570Strasz if (error != 0) 1711255570Strasz log_err(1, "sigaction"); 1712255570Strasz} 1713255570Strasz 1714255570Straszint 1715255570Straszmain(int argc, char **argv) 1716255570Strasz{ 1717255570Strasz struct conf *oldconf, *newconf, *tmpconf; 1718255570Strasz const char *config_path = DEFAULT_CONFIG_PATH; 1719255570Strasz int debug = 0, ch, error; 1720255570Strasz bool dont_daemonize = false; 1721255570Strasz 1722255570Strasz while ((ch = getopt(argc, argv, "df:")) != -1) { 1723255570Strasz switch (ch) { 1724255570Strasz case 'd': 1725255570Strasz dont_daemonize = true; 1726255570Strasz debug++; 1727255570Strasz break; 1728255570Strasz case 'f': 1729255570Strasz config_path = optarg; 1730255570Strasz break; 1731255570Strasz case '?': 1732255570Strasz default: 1733255570Strasz usage(); 1734255570Strasz } 1735255570Strasz } 1736255570Strasz argc -= optind; 1737255570Strasz if (argc != 0) 1738255570Strasz usage(); 1739255570Strasz 1740255570Strasz log_init(debug); 1741255570Strasz kernel_init(); 1742255570Strasz 1743255570Strasz oldconf = conf_new_from_kernel(); 1744255570Strasz newconf = conf_new_from_file(config_path); 1745255570Strasz if (newconf == NULL) 1746255570Strasz log_errx(1, "configuration error, exiting"); 1747255570Strasz if (debug > 0) { 1748255570Strasz oldconf->conf_debug = debug; 1749255570Strasz newconf->conf_debug = debug; 1750255570Strasz } 1751255570Strasz 1752255570Strasz#ifdef ICL_KERNEL_PROXY 1753255570Strasz log_debugx("enabling CTL iSCSI port"); 1754255570Strasz error = kernel_port_on(); 1755255570Strasz if (error != 0) 1756255570Strasz log_errx(1, "failed to enable CTL iSCSI port, exiting"); 1757255570Strasz#endif 1758255570Strasz 1759255570Strasz error = conf_apply(oldconf, newconf); 1760255570Strasz if (error != 0) 1761255570Strasz log_errx(1, "failed to apply configuration, exiting"); 1762255570Strasz conf_delete(oldconf); 1763255570Strasz oldconf = NULL; 1764255570Strasz 1765255570Strasz register_signals(); 1766255570Strasz 1767255570Strasz#ifndef ICL_KERNEL_PROXY 1768255570Strasz log_debugx("enabling CTL iSCSI port"); 1769255570Strasz error = kernel_port_on(); 1770255570Strasz if (error != 0) 1771255570Strasz log_errx(1, "failed to enable CTL iSCSI port, exiting"); 1772255570Strasz#endif 1773255570Strasz 1774263719Strasz if (dont_daemonize == false) { 1775263719Strasz log_debugx("daemonizing"); 1776263719Strasz if (daemon(0, 0) == -1) { 1777263719Strasz log_warn("cannot daemonize"); 1778263719Strasz pidfile_remove(newconf->conf_pidfh); 1779263719Strasz exit(1); 1780263719Strasz } 1781263719Strasz } 1782263719Strasz 1783255570Strasz for (;;) { 1784255570Strasz main_loop(newconf, dont_daemonize); 1785255570Strasz if (sighup_received) { 1786255570Strasz sighup_received = false; 1787255570Strasz log_debugx("received SIGHUP, reloading configuration"); 1788255570Strasz tmpconf = conf_new_from_file(config_path); 1789255570Strasz if (tmpconf == NULL) { 1790255570Strasz log_warnx("configuration error, " 1791255570Strasz "continuing with old configuration"); 1792255570Strasz } else { 1793255570Strasz if (debug > 0) 1794255570Strasz tmpconf->conf_debug = debug; 1795255570Strasz oldconf = newconf; 1796255570Strasz newconf = tmpconf; 1797255570Strasz error = conf_apply(oldconf, newconf); 1798255570Strasz if (error != 0) 1799255570Strasz log_warnx("failed to reload " 1800255570Strasz "configuration"); 1801255570Strasz conf_delete(oldconf); 1802255570Strasz oldconf = NULL; 1803255570Strasz } 1804255570Strasz } else if (sigterm_received) { 1805255570Strasz log_debugx("exiting on signal; " 1806255570Strasz "reloading empty configuration"); 1807255570Strasz 1808255570Strasz log_debugx("disabling CTL iSCSI port " 1809255570Strasz "and terminating all connections"); 1810255570Strasz error = kernel_port_off(); 1811255570Strasz if (error != 0) 1812255570Strasz log_warnx("failed to disable CTL iSCSI port"); 1813255570Strasz 1814255570Strasz oldconf = newconf; 1815255570Strasz newconf = conf_new(); 1816255570Strasz if (debug > 0) 1817255570Strasz newconf->conf_debug = debug; 1818255570Strasz error = conf_apply(oldconf, newconf); 1819255570Strasz if (error != 0) 1820255570Strasz log_warnx("failed to apply configuration"); 1821255570Strasz 1822255570Strasz log_warnx("exiting on signal"); 1823255570Strasz exit(0); 1824255570Strasz } else { 1825255570Strasz nchildren -= wait_for_children(false); 1826255570Strasz assert(nchildren >= 0); 1827255570Strasz } 1828255570Strasz } 1829255570Strasz /* NOTREACHED */ 1830255570Strasz} 1831