ctld.c revision 279002
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 31270888Strasz#include <sys/cdefs.h> 32270888Strasz__FBSDID("$FreeBSD: stable/10/usr.sbin/ctld/ctld.c 279002 2015-02-19 14:31:16Z mav $"); 33270888Strasz 34255570Strasz#include <sys/types.h> 35255570Strasz#include <sys/time.h> 36255570Strasz#include <sys/socket.h> 37255570Strasz#include <sys/wait.h> 38255570Strasz#include <netinet/in.h> 39270137Smav#include <arpa/inet.h> 40255570Strasz#include <assert.h> 41255570Strasz#include <ctype.h> 42255570Strasz#include <errno.h> 43255570Strasz#include <netdb.h> 44255570Strasz#include <signal.h> 45255570Strasz#include <stdbool.h> 46255570Strasz#include <stdio.h> 47255570Strasz#include <stdint.h> 48255570Strasz#include <stdlib.h> 49255570Strasz#include <string.h> 50255570Strasz#include <unistd.h> 51255570Strasz 52255570Strasz#include "ctld.h" 53274939Smav#include "isns.h" 54255570Strasz 55265507Straszbool proxy_mode = false; 56265507Strasz 57255570Straszstatic volatile bool sighup_received = false; 58255570Straszstatic volatile bool sigterm_received = false; 59255570Straszstatic volatile bool sigalrm_received = false; 60255570Strasz 61255570Straszstatic int nchildren = 0; 62255570Strasz 63255570Straszstatic void 64255570Straszusage(void) 65255570Strasz{ 66255570Strasz 67255570Strasz fprintf(stderr, "usage: ctld [-d][-f config-file]\n"); 68255570Strasz exit(1); 69255570Strasz} 70255570Strasz 71255570Straszchar * 72255570Straszchecked_strdup(const char *s) 73255570Strasz{ 74255570Strasz char *c; 75255570Strasz 76255570Strasz c = strdup(s); 77255570Strasz if (c == NULL) 78255570Strasz log_err(1, "strdup"); 79255570Strasz return (c); 80255570Strasz} 81255570Strasz 82255570Straszstruct conf * 83255570Straszconf_new(void) 84255570Strasz{ 85255570Strasz struct conf *conf; 86255570Strasz 87255570Strasz conf = calloc(1, sizeof(*conf)); 88255570Strasz if (conf == NULL) 89255570Strasz log_err(1, "calloc"); 90279002Smav TAILQ_INIT(&conf->conf_luns); 91255570Strasz TAILQ_INIT(&conf->conf_targets); 92255570Strasz TAILQ_INIT(&conf->conf_auth_groups); 93255570Strasz TAILQ_INIT(&conf->conf_portal_groups); 94274939Smav TAILQ_INIT(&conf->conf_isns); 95255570Strasz 96274939Smav conf->conf_isns_period = 900; 97274939Smav conf->conf_isns_timeout = 5; 98255570Strasz conf->conf_debug = 0; 99255570Strasz conf->conf_timeout = 60; 100255570Strasz conf->conf_maxproc = 30; 101255570Strasz 102255570Strasz return (conf); 103255570Strasz} 104255570Strasz 105255570Straszvoid 106255570Straszconf_delete(struct conf *conf) 107255570Strasz{ 108279002Smav struct lun *lun, *ltmp; 109255570Strasz struct target *targ, *tmp; 110255570Strasz struct auth_group *ag, *cagtmp; 111255570Strasz struct portal_group *pg, *cpgtmp; 112274939Smav struct isns *is, *istmp; 113255570Strasz 114255570Strasz assert(conf->conf_pidfh == NULL); 115255570Strasz 116279002Smav TAILQ_FOREACH_SAFE(lun, &conf->conf_luns, l_next, ltmp) 117279002Smav lun_delete(lun); 118255570Strasz TAILQ_FOREACH_SAFE(targ, &conf->conf_targets, t_next, tmp) 119255570Strasz target_delete(targ); 120255570Strasz TAILQ_FOREACH_SAFE(ag, &conf->conf_auth_groups, ag_next, cagtmp) 121255570Strasz auth_group_delete(ag); 122255570Strasz TAILQ_FOREACH_SAFE(pg, &conf->conf_portal_groups, pg_next, cpgtmp) 123255570Strasz portal_group_delete(pg); 124274939Smav TAILQ_FOREACH_SAFE(is, &conf->conf_isns, i_next, istmp) 125274939Smav isns_delete(is); 126255570Strasz free(conf->conf_pidfile_path); 127255570Strasz free(conf); 128255570Strasz} 129255570Strasz 130255570Straszstatic struct auth * 131255570Straszauth_new(struct auth_group *ag) 132255570Strasz{ 133255570Strasz struct auth *auth; 134255570Strasz 135255570Strasz auth = calloc(1, sizeof(*auth)); 136255570Strasz if (auth == NULL) 137255570Strasz log_err(1, "calloc"); 138255570Strasz auth->a_auth_group = ag; 139255570Strasz TAILQ_INSERT_TAIL(&ag->ag_auths, auth, a_next); 140255570Strasz return (auth); 141255570Strasz} 142255570Strasz 143255570Straszstatic void 144255570Straszauth_delete(struct auth *auth) 145255570Strasz{ 146255570Strasz TAILQ_REMOVE(&auth->a_auth_group->ag_auths, auth, a_next); 147255570Strasz 148255570Strasz free(auth->a_user); 149255570Strasz free(auth->a_secret); 150255570Strasz free(auth->a_mutual_user); 151255570Strasz free(auth->a_mutual_secret); 152255570Strasz free(auth); 153255570Strasz} 154255570Strasz 155255570Straszconst struct auth * 156265514Straszauth_find(const struct auth_group *ag, const char *user) 157255570Strasz{ 158255570Strasz const struct auth *auth; 159255570Strasz 160255570Strasz TAILQ_FOREACH(auth, &ag->ag_auths, a_next) { 161255570Strasz if (strcmp(auth->a_user, user) == 0) 162255570Strasz return (auth); 163255570Strasz } 164255570Strasz 165255570Strasz return (NULL); 166255570Strasz} 167255570Strasz 168263721Straszstatic void 169263721Straszauth_check_secret_length(struct auth *auth) 170263721Strasz{ 171263721Strasz size_t len; 172263721Strasz 173263721Strasz len = strlen(auth->a_secret); 174263721Strasz if (len > 16) { 175263721Strasz if (auth->a_auth_group->ag_name != NULL) 176263721Strasz log_warnx("secret for user \"%s\", auth-group \"%s\", " 177263721Strasz "is too long; it should be at most 16 characters " 178263721Strasz "long", auth->a_user, auth->a_auth_group->ag_name); 179263721Strasz else 180263721Strasz log_warnx("secret for user \"%s\", target \"%s\", " 181263721Strasz "is too long; it should be at most 16 characters " 182263721Strasz "long", auth->a_user, 183263723Strasz auth->a_auth_group->ag_target->t_name); 184263721Strasz } 185263721Strasz if (len < 12) { 186263721Strasz if (auth->a_auth_group->ag_name != NULL) 187263721Strasz log_warnx("secret for user \"%s\", auth-group \"%s\", " 188263721Strasz "is too short; it should be at least 12 characters " 189263721Strasz "long", auth->a_user, 190263721Strasz auth->a_auth_group->ag_name); 191263721Strasz else 192263721Strasz log_warnx("secret for user \"%s\", target \"%s\", " 193263721Strasz "is too short; it should be at least 16 characters " 194263721Strasz "long", auth->a_user, 195263723Strasz auth->a_auth_group->ag_target->t_name); 196263721Strasz } 197263721Strasz 198263721Strasz if (auth->a_mutual_secret != NULL) { 199263721Strasz len = strlen(auth->a_secret); 200263721Strasz if (len > 16) { 201263721Strasz if (auth->a_auth_group->ag_name != NULL) 202263721Strasz log_warnx("mutual secret for user \"%s\", " 203263721Strasz "auth-group \"%s\", is too long; it should " 204263721Strasz "be at most 16 characters long", 205263721Strasz auth->a_user, auth->a_auth_group->ag_name); 206263721Strasz else 207263721Strasz log_warnx("mutual secret for user \"%s\", " 208263721Strasz "target \"%s\", is too long; it should " 209263721Strasz "be at most 16 characters long", 210263721Strasz auth->a_user, 211263723Strasz auth->a_auth_group->ag_target->t_name); 212263721Strasz } 213263721Strasz if (len < 12) { 214263721Strasz if (auth->a_auth_group->ag_name != NULL) 215263721Strasz log_warnx("mutual secret for user \"%s\", " 216263721Strasz "auth-group \"%s\", is too short; it " 217263721Strasz "should be at least 12 characters long", 218263721Strasz auth->a_user, auth->a_auth_group->ag_name); 219263721Strasz else 220263721Strasz log_warnx("mutual secret for user \"%s\", " 221263721Strasz "target \"%s\", is too short; it should be " 222263721Strasz "at least 16 characters long", 223263721Strasz auth->a_user, 224263723Strasz auth->a_auth_group->ag_target->t_name); 225263721Strasz } 226263721Strasz } 227263721Strasz} 228263721Strasz 229263721Straszconst struct auth * 230263721Straszauth_new_chap(struct auth_group *ag, const char *user, 231263721Strasz const char *secret) 232263721Strasz{ 233263721Strasz struct auth *auth; 234263721Strasz 235263721Strasz if (ag->ag_type == AG_TYPE_UNKNOWN) 236263721Strasz ag->ag_type = AG_TYPE_CHAP; 237263721Strasz if (ag->ag_type != AG_TYPE_CHAP) { 238263721Strasz if (ag->ag_name != NULL) 239263721Strasz log_warnx("cannot mix \"chap\" authentication with " 240263721Strasz "other types for auth-group \"%s\"", ag->ag_name); 241263721Strasz else 242263721Strasz log_warnx("cannot mix \"chap\" authentication with " 243263721Strasz "other types for target \"%s\"", 244263723Strasz ag->ag_target->t_name); 245263721Strasz return (NULL); 246263721Strasz } 247263721Strasz 248263721Strasz auth = auth_new(ag); 249263721Strasz auth->a_user = checked_strdup(user); 250263721Strasz auth->a_secret = checked_strdup(secret); 251263721Strasz 252263721Strasz auth_check_secret_length(auth); 253263721Strasz 254263721Strasz return (auth); 255263721Strasz} 256263721Strasz 257263721Straszconst struct auth * 258263721Straszauth_new_chap_mutual(struct auth_group *ag, const char *user, 259263721Strasz const char *secret, const char *user2, const char *secret2) 260263721Strasz{ 261263721Strasz struct auth *auth; 262263721Strasz 263263721Strasz if (ag->ag_type == AG_TYPE_UNKNOWN) 264263721Strasz ag->ag_type = AG_TYPE_CHAP_MUTUAL; 265263721Strasz if (ag->ag_type != AG_TYPE_CHAP_MUTUAL) { 266263721Strasz if (ag->ag_name != NULL) 267263721Strasz log_warnx("cannot mix \"chap-mutual\" authentication " 268263721Strasz "with other types for auth-group \"%s\"", 269274870Strasz ag->ag_name); 270263721Strasz else 271263721Strasz log_warnx("cannot mix \"chap-mutual\" authentication " 272263721Strasz "with other types for target \"%s\"", 273263723Strasz ag->ag_target->t_name); 274263721Strasz return (NULL); 275263721Strasz } 276263721Strasz 277263721Strasz auth = auth_new(ag); 278263721Strasz auth->a_user = checked_strdup(user); 279263721Strasz auth->a_secret = checked_strdup(secret); 280263721Strasz auth->a_mutual_user = checked_strdup(user2); 281263721Strasz auth->a_mutual_secret = checked_strdup(secret2); 282263721Strasz 283263721Strasz auth_check_secret_length(auth); 284263721Strasz 285263721Strasz return (auth); 286263721Strasz} 287263721Strasz 288263720Straszconst struct auth_name * 289263720Straszauth_name_new(struct auth_group *ag, const char *name) 290263720Strasz{ 291263720Strasz struct auth_name *an; 292263720Strasz 293263720Strasz an = calloc(1, sizeof(*an)); 294263720Strasz if (an == NULL) 295263720Strasz log_err(1, "calloc"); 296263720Strasz an->an_auth_group = ag; 297263720Strasz an->an_initator_name = checked_strdup(name); 298263720Strasz TAILQ_INSERT_TAIL(&ag->ag_names, an, an_next); 299263720Strasz return (an); 300263720Strasz} 301263720Strasz 302263720Straszstatic void 303263720Straszauth_name_delete(struct auth_name *an) 304263720Strasz{ 305263720Strasz TAILQ_REMOVE(&an->an_auth_group->ag_names, an, an_next); 306263720Strasz 307263720Strasz free(an->an_initator_name); 308263720Strasz free(an); 309263720Strasz} 310263720Strasz 311263720Straszbool 312263720Straszauth_name_defined(const struct auth_group *ag) 313263720Strasz{ 314263720Strasz if (TAILQ_EMPTY(&ag->ag_names)) 315263720Strasz return (false); 316263720Strasz return (true); 317263720Strasz} 318263720Strasz 319263720Straszconst struct auth_name * 320263720Straszauth_name_find(const struct auth_group *ag, const char *name) 321263720Strasz{ 322263720Strasz const struct auth_name *auth_name; 323263720Strasz 324263720Strasz TAILQ_FOREACH(auth_name, &ag->ag_names, an_next) { 325263720Strasz if (strcmp(auth_name->an_initator_name, name) == 0) 326263720Strasz return (auth_name); 327263720Strasz } 328263720Strasz 329263720Strasz return (NULL); 330263720Strasz} 331263720Strasz 332274949Straszint 333274949Straszauth_name_check(const struct auth_group *ag, const char *initiator_name) 334274949Strasz{ 335274949Strasz if (!auth_name_defined(ag)) 336274949Strasz return (0); 337274949Strasz 338274949Strasz if (auth_name_find(ag, initiator_name) == NULL) 339274949Strasz return (1); 340274949Strasz 341274949Strasz return (0); 342274949Strasz} 343274949Strasz 344263720Straszconst struct auth_portal * 345263720Straszauth_portal_new(struct auth_group *ag, const char *portal) 346263720Strasz{ 347263720Strasz struct auth_portal *ap; 348270137Smav char *net, *mask, *str, *tmp; 349270137Smav int len, dm, m; 350263720Strasz 351263720Strasz ap = calloc(1, sizeof(*ap)); 352263720Strasz if (ap == NULL) 353263720Strasz log_err(1, "calloc"); 354263720Strasz ap->ap_auth_group = ag; 355263720Strasz ap->ap_initator_portal = checked_strdup(portal); 356270137Smav mask = str = checked_strdup(portal); 357270137Smav net = strsep(&mask, "/"); 358270137Smav if (net[0] == '[') 359270137Smav net++; 360270137Smav len = strlen(net); 361270137Smav if (len == 0) 362270137Smav goto error; 363270137Smav if (net[len - 1] == ']') 364270137Smav net[len - 1] = 0; 365270137Smav if (strchr(net, ':') != NULL) { 366270137Smav struct sockaddr_in6 *sin6 = 367270137Smav (struct sockaddr_in6 *)&ap->ap_sa; 368270137Smav 369270137Smav sin6->sin6_len = sizeof(*sin6); 370270137Smav sin6->sin6_family = AF_INET6; 371270137Smav if (inet_pton(AF_INET6, net, &sin6->sin6_addr) <= 0) 372270137Smav goto error; 373270137Smav dm = 128; 374270137Smav } else { 375270137Smav struct sockaddr_in *sin = 376270137Smav (struct sockaddr_in *)&ap->ap_sa; 377270137Smav 378270137Smav sin->sin_len = sizeof(*sin); 379270137Smav sin->sin_family = AF_INET; 380270137Smav if (inet_pton(AF_INET, net, &sin->sin_addr) <= 0) 381270137Smav goto error; 382270137Smav dm = 32; 383270137Smav } 384270137Smav if (mask != NULL) { 385270137Smav m = strtol(mask, &tmp, 0); 386270137Smav if (m < 0 || m > dm || tmp[0] != 0) 387270137Smav goto error; 388270137Smav } else 389270137Smav m = dm; 390270137Smav ap->ap_mask = m; 391270137Smav free(str); 392263720Strasz TAILQ_INSERT_TAIL(&ag->ag_portals, ap, ap_next); 393263720Strasz return (ap); 394270137Smav 395270137Smaverror: 396270137Smav log_errx(1, "Incorrect initiator portal '%s'", portal); 397270137Smav return (NULL); 398263720Strasz} 399263720Strasz 400263720Straszstatic void 401263720Straszauth_portal_delete(struct auth_portal *ap) 402263720Strasz{ 403263720Strasz TAILQ_REMOVE(&ap->ap_auth_group->ag_portals, ap, ap_next); 404263720Strasz 405263720Strasz free(ap->ap_initator_portal); 406263720Strasz free(ap); 407263720Strasz} 408263720Strasz 409263720Straszbool 410263720Straszauth_portal_defined(const struct auth_group *ag) 411263720Strasz{ 412263720Strasz if (TAILQ_EMPTY(&ag->ag_portals)) 413263720Strasz return (false); 414263720Strasz return (true); 415263720Strasz} 416263720Strasz 417263720Straszconst struct auth_portal * 418270137Smavauth_portal_find(const struct auth_group *ag, const struct sockaddr_storage *ss) 419263720Strasz{ 420270137Smav const struct auth_portal *ap; 421270137Smav const uint8_t *a, *b; 422270137Smav int i; 423270137Smav uint8_t bmask; 424263720Strasz 425270137Smav TAILQ_FOREACH(ap, &ag->ag_portals, ap_next) { 426270137Smav if (ap->ap_sa.ss_family != ss->ss_family) 427270137Smav continue; 428270137Smav if (ss->ss_family == AF_INET) { 429270137Smav a = (const uint8_t *) 430270137Smav &((const struct sockaddr_in *)ss)->sin_addr; 431270137Smav b = (const uint8_t *) 432270137Smav &((const struct sockaddr_in *)&ap->ap_sa)->sin_addr; 433270137Smav } else { 434270137Smav a = (const uint8_t *) 435270137Smav &((const struct sockaddr_in6 *)ss)->sin6_addr; 436270137Smav b = (const uint8_t *) 437270137Smav &((const struct sockaddr_in6 *)&ap->ap_sa)->sin6_addr; 438270137Smav } 439270137Smav for (i = 0; i < ap->ap_mask / 8; i++) { 440270137Smav if (a[i] != b[i]) 441270137Smav goto next; 442270137Smav } 443270137Smav if (ap->ap_mask % 8) { 444270137Smav bmask = 0xff << (8 - (ap->ap_mask % 8)); 445270137Smav if ((a[i] & bmask) != (b[i] & bmask)) 446270137Smav goto next; 447270137Smav } 448270137Smav return (ap); 449270137Smavnext: 450270137Smav ; 451263720Strasz } 452263720Strasz 453263720Strasz return (NULL); 454263720Strasz} 455263720Strasz 456274949Straszint 457274949Straszauth_portal_check(const struct auth_group *ag, const struct sockaddr_storage *sa) 458274949Strasz{ 459274949Strasz 460274949Strasz if (!auth_portal_defined(ag)) 461274949Strasz return (0); 462274949Strasz 463274949Strasz if (auth_portal_find(ag, sa) == NULL) 464274949Strasz return (1); 465274949Strasz 466274949Strasz return (0); 467274949Strasz} 468274949Strasz 469255570Straszstruct auth_group * 470255570Straszauth_group_new(struct conf *conf, const char *name) 471255570Strasz{ 472255570Strasz struct auth_group *ag; 473255570Strasz 474255570Strasz if (name != NULL) { 475255570Strasz ag = auth_group_find(conf, name); 476255570Strasz if (ag != NULL) { 477255570Strasz log_warnx("duplicated auth-group \"%s\"", name); 478255570Strasz return (NULL); 479255570Strasz } 480255570Strasz } 481255570Strasz 482255570Strasz ag = calloc(1, sizeof(*ag)); 483255570Strasz if (ag == NULL) 484255570Strasz log_err(1, "calloc"); 485255570Strasz if (name != NULL) 486255570Strasz ag->ag_name = checked_strdup(name); 487255570Strasz TAILQ_INIT(&ag->ag_auths); 488263720Strasz TAILQ_INIT(&ag->ag_names); 489263720Strasz TAILQ_INIT(&ag->ag_portals); 490255570Strasz ag->ag_conf = conf; 491255570Strasz TAILQ_INSERT_TAIL(&conf->conf_auth_groups, ag, ag_next); 492255570Strasz 493255570Strasz return (ag); 494255570Strasz} 495255570Strasz 496255570Straszvoid 497255570Straszauth_group_delete(struct auth_group *ag) 498255570Strasz{ 499263720Strasz struct auth *auth, *auth_tmp; 500263720Strasz struct auth_name *auth_name, *auth_name_tmp; 501263720Strasz struct auth_portal *auth_portal, *auth_portal_tmp; 502255570Strasz 503255570Strasz TAILQ_REMOVE(&ag->ag_conf->conf_auth_groups, ag, ag_next); 504255570Strasz 505263720Strasz TAILQ_FOREACH_SAFE(auth, &ag->ag_auths, a_next, auth_tmp) 506255570Strasz auth_delete(auth); 507263720Strasz TAILQ_FOREACH_SAFE(auth_name, &ag->ag_names, an_next, auth_name_tmp) 508263720Strasz auth_name_delete(auth_name); 509263720Strasz TAILQ_FOREACH_SAFE(auth_portal, &ag->ag_portals, ap_next, 510263720Strasz auth_portal_tmp) 511263720Strasz auth_portal_delete(auth_portal); 512255570Strasz free(ag->ag_name); 513255570Strasz free(ag); 514255570Strasz} 515255570Strasz 516255570Straszstruct auth_group * 517265514Straszauth_group_find(const struct conf *conf, const char *name) 518255570Strasz{ 519255570Strasz struct auth_group *ag; 520255570Strasz 521255570Strasz TAILQ_FOREACH(ag, &conf->conf_auth_groups, ag_next) { 522255570Strasz if (ag->ag_name != NULL && strcmp(ag->ag_name, name) == 0) 523255570Strasz return (ag); 524255570Strasz } 525255570Strasz 526255570Strasz return (NULL); 527255570Strasz} 528255570Strasz 529263724Straszint 530275245Straszauth_group_set_type(struct auth_group *ag, const char *str) 531263724Strasz{ 532275245Strasz int type; 533263724Strasz 534263724Strasz if (strcmp(str, "none") == 0) { 535263724Strasz type = AG_TYPE_NO_AUTHENTICATION; 536263729Strasz } else if (strcmp(str, "deny") == 0) { 537263729Strasz type = AG_TYPE_DENY; 538263724Strasz } else if (strcmp(str, "chap") == 0) { 539263724Strasz type = AG_TYPE_CHAP; 540263724Strasz } else if (strcmp(str, "chap-mutual") == 0) { 541263724Strasz type = AG_TYPE_CHAP_MUTUAL; 542263724Strasz } else { 543263724Strasz if (ag->ag_name != NULL) 544263724Strasz log_warnx("invalid auth-type \"%s\" for auth-group " 545263724Strasz "\"%s\"", str, ag->ag_name); 546263724Strasz else 547263724Strasz log_warnx("invalid auth-type \"%s\" for target " 548263724Strasz "\"%s\"", str, ag->ag_target->t_name); 549263724Strasz return (1); 550263724Strasz } 551263724Strasz 552275245Strasz if (ag->ag_type != AG_TYPE_UNKNOWN && ag->ag_type != type) { 553275245Strasz if (ag->ag_name != NULL) { 554263724Strasz log_warnx("cannot set auth-type to \"%s\" for " 555263724Strasz "auth-group \"%s\"; already has a different " 556263724Strasz "type", str, ag->ag_name); 557275245Strasz } else { 558263724Strasz log_warnx("cannot set auth-type to \"%s\" for target " 559263724Strasz "\"%s\"; already has a different type", 560263724Strasz str, ag->ag_target->t_name); 561275245Strasz } 562263724Strasz return (1); 563263724Strasz } 564263724Strasz 565275245Strasz ag->ag_type = type; 566275245Strasz 567275245Strasz return (0); 568263724Strasz} 569263724Strasz 570255570Straszstatic struct portal * 571255570Straszportal_new(struct portal_group *pg) 572255570Strasz{ 573255570Strasz struct portal *portal; 574255570Strasz 575255570Strasz portal = calloc(1, sizeof(*portal)); 576255570Strasz if (portal == NULL) 577255570Strasz log_err(1, "calloc"); 578255570Strasz TAILQ_INIT(&portal->p_targets); 579255570Strasz portal->p_portal_group = pg; 580255570Strasz TAILQ_INSERT_TAIL(&pg->pg_portals, portal, p_next); 581255570Strasz return (portal); 582255570Strasz} 583255570Strasz 584255570Straszstatic void 585255570Straszportal_delete(struct portal *portal) 586255570Strasz{ 587271632Strasz 588255570Strasz TAILQ_REMOVE(&portal->p_portal_group->pg_portals, portal, p_next); 589271632Strasz if (portal->p_ai != NULL) 590271632Strasz freeaddrinfo(portal->p_ai); 591255570Strasz free(portal->p_listen); 592255570Strasz free(portal); 593255570Strasz} 594255570Strasz 595255570Straszstruct portal_group * 596255570Straszportal_group_new(struct conf *conf, const char *name) 597255570Strasz{ 598255570Strasz struct portal_group *pg; 599255570Strasz 600255678Strasz pg = portal_group_find(conf, name); 601255678Strasz if (pg != NULL) { 602255678Strasz log_warnx("duplicated portal-group \"%s\"", name); 603255678Strasz return (NULL); 604255570Strasz } 605255570Strasz 606255570Strasz pg = calloc(1, sizeof(*pg)); 607255570Strasz if (pg == NULL) 608255570Strasz log_err(1, "calloc"); 609255570Strasz pg->pg_name = checked_strdup(name); 610255570Strasz TAILQ_INIT(&pg->pg_portals); 611255570Strasz pg->pg_conf = conf; 612255570Strasz conf->conf_last_portal_group_tag++; 613255570Strasz pg->pg_tag = conf->conf_last_portal_group_tag; 614255570Strasz TAILQ_INSERT_TAIL(&conf->conf_portal_groups, pg, pg_next); 615255570Strasz 616255570Strasz return (pg); 617255570Strasz} 618255570Strasz 619255570Straszvoid 620255570Straszportal_group_delete(struct portal_group *pg) 621255570Strasz{ 622255570Strasz struct portal *portal, *tmp; 623255570Strasz 624255570Strasz TAILQ_REMOVE(&pg->pg_conf->conf_portal_groups, pg, pg_next); 625255570Strasz 626255570Strasz TAILQ_FOREACH_SAFE(portal, &pg->pg_portals, p_next, tmp) 627255570Strasz portal_delete(portal); 628255570Strasz free(pg->pg_name); 629275642Strasz free(pg->pg_redirection); 630255570Strasz free(pg); 631255570Strasz} 632255570Strasz 633255570Straszstruct portal_group * 634265514Straszportal_group_find(const struct conf *conf, const char *name) 635255570Strasz{ 636255570Strasz struct portal_group *pg; 637255570Strasz 638255570Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 639255570Strasz if (strcmp(pg->pg_name, name) == 0) 640255570Strasz return (pg); 641255570Strasz } 642255570Strasz 643255570Strasz return (NULL); 644255570Strasz} 645255570Strasz 646274939Smavstatic int 647274939Smavparse_addr_port(char *arg, const char *def_port, struct addrinfo **ai) 648255570Strasz{ 649255570Strasz struct addrinfo hints; 650275674Smav char *str, *addr, *ch; 651255570Strasz const char *port; 652255570Strasz int error, colons = 0; 653255570Strasz 654275674Smav str = arg = strdup(arg); 655255570Strasz if (arg[0] == '[') { 656255570Strasz /* 657255570Strasz * IPv6 address in square brackets, perhaps with port. 658255570Strasz */ 659255570Strasz arg++; 660255570Strasz addr = strsep(&arg, "]"); 661274939Smav if (arg == NULL) 662255570Strasz return (1); 663255570Strasz if (arg[0] == '\0') { 664274939Smav port = def_port; 665255570Strasz } else if (arg[0] == ':') { 666255570Strasz port = arg + 1; 667275674Smav } else { 668275674Smav free(str); 669255570Strasz return (1); 670275674Smav } 671255570Strasz } else { 672255570Strasz /* 673255570Strasz * Either IPv6 address without brackets - and without 674255570Strasz * a port - or IPv4 address. Just count the colons. 675255570Strasz */ 676255570Strasz for (ch = arg; *ch != '\0'; ch++) { 677255570Strasz if (*ch == ':') 678255570Strasz colons++; 679255570Strasz } 680255570Strasz if (colons > 1) { 681255570Strasz addr = arg; 682274939Smav port = def_port; 683255570Strasz } else { 684255570Strasz addr = strsep(&arg, ":"); 685255570Strasz if (arg == NULL) 686274939Smav port = def_port; 687255570Strasz else 688255570Strasz port = arg; 689255570Strasz } 690255570Strasz } 691255570Strasz 692255570Strasz memset(&hints, 0, sizeof(hints)); 693255570Strasz hints.ai_family = PF_UNSPEC; 694255570Strasz hints.ai_socktype = SOCK_STREAM; 695255570Strasz hints.ai_flags = AI_PASSIVE; 696274939Smav error = getaddrinfo(addr, port, &hints, ai); 697275674Smav free(str); 698275674Smav return ((error != 0) ? 1 : 0); 699274939Smav} 700255570Strasz 701274939Smavint 702274939Smavportal_group_add_listen(struct portal_group *pg, const char *value, bool iser) 703274939Smav{ 704274939Smav struct portal *portal; 705274939Smav 706274939Smav portal = portal_new(pg); 707274939Smav portal->p_listen = checked_strdup(value); 708274939Smav portal->p_iser = iser; 709274939Smav 710274939Smav if (parse_addr_port(portal->p_listen, "3260", &portal->p_ai)) { 711274939Smav log_warnx("invalid listen address %s", portal->p_listen); 712271632Strasz portal_delete(portal); 713255570Strasz return (1); 714255570Strasz } 715255570Strasz 716255570Strasz /* 717255570Strasz * XXX: getaddrinfo(3) may return multiple addresses; we should turn 718255570Strasz * those into multiple portals. 719255570Strasz */ 720255570Strasz 721255570Strasz return (0); 722255570Strasz} 723255570Strasz 724274939Smavint 725274939Smavisns_new(struct conf *conf, const char *addr) 726274939Smav{ 727274939Smav struct isns *isns; 728274939Smav 729274939Smav isns = calloc(1, sizeof(*isns)); 730274939Smav if (isns == NULL) 731274939Smav log_err(1, "calloc"); 732274939Smav isns->i_conf = conf; 733274939Smav TAILQ_INSERT_TAIL(&conf->conf_isns, isns, i_next); 734274939Smav isns->i_addr = checked_strdup(addr); 735274939Smav 736274939Smav if (parse_addr_port(isns->i_addr, "3205", &isns->i_ai)) { 737274939Smav log_warnx("invalid iSNS address %s", isns->i_addr); 738274939Smav isns_delete(isns); 739274939Smav return (1); 740274939Smav } 741274939Smav 742274939Smav /* 743274939Smav * XXX: getaddrinfo(3) may return multiple addresses; we should turn 744274939Smav * those into multiple servers. 745274939Smav */ 746274939Smav 747274939Smav return (0); 748274939Smav} 749274939Smav 750274939Smavvoid 751274939Smavisns_delete(struct isns *isns) 752274939Smav{ 753274939Smav 754274939Smav TAILQ_REMOVE(&isns->i_conf->conf_isns, isns, i_next); 755274939Smav free(isns->i_addr); 756274939Smav if (isns->i_ai != NULL) 757274939Smav freeaddrinfo(isns->i_ai); 758274939Smav free(isns); 759274939Smav} 760274939Smav 761274939Smavstatic int 762274939Smavisns_do_connect(struct isns *isns) 763274939Smav{ 764274939Smav int s; 765274939Smav 766274939Smav s = socket(isns->i_ai->ai_family, isns->i_ai->ai_socktype, 767274939Smav isns->i_ai->ai_protocol); 768274939Smav if (s < 0) { 769274939Smav log_warn("socket(2) failed for %s", isns->i_addr); 770274939Smav return (-1); 771274939Smav } 772274939Smav if (connect(s, isns->i_ai->ai_addr, isns->i_ai->ai_addrlen)) { 773274939Smav log_warn("connect(2) failed for %s", isns->i_addr); 774274939Smav close(s); 775274939Smav return (-1); 776274939Smav } 777274939Smav return(s); 778274939Smav} 779274939Smav 780274939Smavstatic int 781274939Smavisns_do_register(struct isns *isns, int s, const char *hostname) 782274939Smav{ 783274939Smav struct conf *conf = isns->i_conf; 784274939Smav struct target *target; 785274939Smav struct portal *portal; 786274939Smav struct portal_group *pg; 787274939Smav struct isns_req *req; 788274939Smav int res = 0; 789274939Smav uint32_t error; 790274939Smav 791274939Smav req = isns_req_create(ISNS_FUNC_DEVATTRREG, ISNS_FLAG_CLIENT); 792274939Smav isns_req_add_str(req, 32, TAILQ_FIRST(&conf->conf_targets)->t_name); 793274939Smav isns_req_add_delim(req); 794274939Smav isns_req_add_str(req, 1, hostname); 795274939Smav isns_req_add_32(req, 2, 2); /* 2 -- iSCSI */ 796274939Smav isns_req_add_32(req, 6, conf->conf_isns_period); 797274939Smav TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 798274939Smav if (pg->pg_unassigned) 799274939Smav continue; 800274939Smav TAILQ_FOREACH(portal, &pg->pg_portals, p_next) { 801274939Smav isns_req_add_addr(req, 16, portal->p_ai); 802274939Smav isns_req_add_port(req, 17, portal->p_ai); 803274939Smav } 804274939Smav } 805274939Smav TAILQ_FOREACH(target, &conf->conf_targets, t_next) { 806274939Smav isns_req_add_str(req, 32, target->t_name); 807274939Smav isns_req_add_32(req, 33, 1); /* 1 -- Target*/ 808274939Smav if (target->t_alias != NULL) 809274939Smav isns_req_add_str(req, 34, target->t_alias); 810274939Smav pg = target->t_portal_group; 811274939Smav isns_req_add_32(req, 51, pg->pg_tag); 812274939Smav TAILQ_FOREACH(portal, &pg->pg_portals, p_next) { 813274939Smav isns_req_add_addr(req, 49, portal->p_ai); 814274939Smav isns_req_add_port(req, 50, portal->p_ai); 815274939Smav } 816274939Smav } 817274939Smav res = isns_req_send(s, req); 818274939Smav if (res < 0) { 819274939Smav log_warn("send(2) failed for %s", isns->i_addr); 820274939Smav goto quit; 821274939Smav } 822274939Smav res = isns_req_receive(s, req); 823274939Smav if (res < 0) { 824274939Smav log_warn("receive(2) failed for %s", isns->i_addr); 825274939Smav goto quit; 826274939Smav } 827274939Smav error = isns_req_get_status(req); 828274939Smav if (error != 0) { 829274939Smav log_warnx("iSNS register error %d for %s", error, isns->i_addr); 830274939Smav res = -1; 831274939Smav } 832274939Smavquit: 833274939Smav isns_req_free(req); 834274939Smav return (res); 835274939Smav} 836274939Smav 837274939Smavstatic int 838274939Smavisns_do_check(struct isns *isns, int s, const char *hostname) 839274939Smav{ 840274939Smav struct conf *conf = isns->i_conf; 841274939Smav struct isns_req *req; 842274939Smav int res = 0; 843274939Smav uint32_t error; 844274939Smav 845274939Smav req = isns_req_create(ISNS_FUNC_DEVATTRQRY, ISNS_FLAG_CLIENT); 846274939Smav isns_req_add_str(req, 32, TAILQ_FIRST(&conf->conf_targets)->t_name); 847274939Smav isns_req_add_str(req, 1, hostname); 848274939Smav isns_req_add_delim(req); 849274939Smav isns_req_add(req, 2, 0, NULL); 850274939Smav res = isns_req_send(s, req); 851274939Smav if (res < 0) { 852274939Smav log_warn("send(2) failed for %s", isns->i_addr); 853274939Smav goto quit; 854274939Smav } 855274939Smav res = isns_req_receive(s, req); 856274939Smav if (res < 0) { 857274939Smav log_warn("receive(2) failed for %s", isns->i_addr); 858274939Smav goto quit; 859274939Smav } 860274939Smav error = isns_req_get_status(req); 861274939Smav if (error != 0) { 862274939Smav log_warnx("iSNS check error %d for %s", error, isns->i_addr); 863274939Smav res = -1; 864274939Smav } 865274939Smavquit: 866274939Smav isns_req_free(req); 867274939Smav return (res); 868274939Smav} 869274939Smav 870274939Smavstatic int 871274939Smavisns_do_deregister(struct isns *isns, int s, const char *hostname) 872274939Smav{ 873274939Smav struct conf *conf = isns->i_conf; 874274939Smav struct isns_req *req; 875274939Smav int res = 0; 876274939Smav uint32_t error; 877274939Smav 878274939Smav req = isns_req_create(ISNS_FUNC_DEVDEREG, ISNS_FLAG_CLIENT); 879274939Smav isns_req_add_str(req, 32, TAILQ_FIRST(&conf->conf_targets)->t_name); 880274939Smav isns_req_add_delim(req); 881274939Smav isns_req_add_str(req, 1, hostname); 882274939Smav res = isns_req_send(s, req); 883274939Smav if (res < 0) { 884274939Smav log_warn("send(2) failed for %s", isns->i_addr); 885274939Smav goto quit; 886274939Smav } 887274939Smav res = isns_req_receive(s, req); 888274939Smav if (res < 0) { 889274939Smav log_warn("receive(2) failed for %s", isns->i_addr); 890274939Smav goto quit; 891274939Smav } 892274939Smav error = isns_req_get_status(req); 893274939Smav if (error != 0) { 894274939Smav log_warnx("iSNS deregister error %d for %s", error, isns->i_addr); 895274939Smav res = -1; 896274939Smav } 897274939Smavquit: 898274939Smav isns_req_free(req); 899274939Smav return (res); 900274939Smav} 901274939Smav 902274939Smavvoid 903274939Smavisns_register(struct isns *isns, struct isns *oldisns) 904274939Smav{ 905274939Smav struct conf *conf = isns->i_conf; 906275496Smav int s; 907274939Smav char hostname[256]; 908274939Smav 909274939Smav if (TAILQ_EMPTY(&conf->conf_targets) || 910274939Smav TAILQ_EMPTY(&conf->conf_portal_groups)) 911274939Smav return; 912274939Smav set_timeout(conf->conf_isns_timeout, false); 913274939Smav s = isns_do_connect(isns); 914274939Smav if (s < 0) { 915274939Smav set_timeout(0, false); 916274939Smav return; 917274939Smav } 918274939Smav gethostname(hostname, sizeof(hostname)); 919274939Smav 920274939Smav if (oldisns == NULL || TAILQ_EMPTY(&oldisns->i_conf->conf_targets)) 921274939Smav oldisns = isns; 922275496Smav isns_do_deregister(oldisns, s, hostname); 923275496Smav isns_do_register(isns, s, hostname); 924274939Smav close(s); 925274939Smav set_timeout(0, false); 926274939Smav} 927274939Smav 928274939Smavvoid 929274939Smavisns_check(struct isns *isns) 930274939Smav{ 931274939Smav struct conf *conf = isns->i_conf; 932274939Smav int s, res; 933274939Smav char hostname[256]; 934274939Smav 935274939Smav if (TAILQ_EMPTY(&conf->conf_targets) || 936274939Smav TAILQ_EMPTY(&conf->conf_portal_groups)) 937274939Smav return; 938274939Smav set_timeout(conf->conf_isns_timeout, false); 939274939Smav s = isns_do_connect(isns); 940274939Smav if (s < 0) { 941274939Smav set_timeout(0, false); 942274939Smav return; 943274939Smav } 944274939Smav gethostname(hostname, sizeof(hostname)); 945274939Smav 946274939Smav res = isns_do_check(isns, s, hostname); 947274939Smav if (res < 0) { 948275496Smav isns_do_deregister(isns, s, hostname); 949275496Smav isns_do_register(isns, s, hostname); 950274939Smav } 951274939Smav close(s); 952274939Smav set_timeout(0, false); 953274939Smav} 954274939Smav 955274939Smavvoid 956274939Smavisns_deregister(struct isns *isns) 957274939Smav{ 958274939Smav struct conf *conf = isns->i_conf; 959275496Smav int s; 960274939Smav char hostname[256]; 961274939Smav 962274939Smav if (TAILQ_EMPTY(&conf->conf_targets) || 963274939Smav TAILQ_EMPTY(&conf->conf_portal_groups)) 964274939Smav return; 965274939Smav set_timeout(conf->conf_isns_timeout, false); 966274939Smav s = isns_do_connect(isns); 967274939Smav if (s < 0) 968274939Smav return; 969274939Smav gethostname(hostname, sizeof(hostname)); 970274939Smav 971275496Smav isns_do_deregister(isns, s, hostname); 972274939Smav close(s); 973274939Smav set_timeout(0, false); 974274939Smav} 975274939Smav 976275244Straszint 977275245Straszportal_group_set_filter(struct portal_group *pg, const char *str) 978275244Strasz{ 979275245Strasz int filter; 980275244Strasz 981275244Strasz if (strcmp(str, "none") == 0) { 982275244Strasz filter = PG_FILTER_NONE; 983275244Strasz } else if (strcmp(str, "portal") == 0) { 984275244Strasz filter = PG_FILTER_PORTAL; 985275244Strasz } else if (strcmp(str, "portal-name") == 0) { 986275244Strasz filter = PG_FILTER_PORTAL_NAME; 987275244Strasz } else if (strcmp(str, "portal-name-auth") == 0) { 988275244Strasz filter = PG_FILTER_PORTAL_NAME_AUTH; 989275244Strasz } else { 990275244Strasz log_warnx("invalid discovery-filter \"%s\" for portal-group " 991275244Strasz "\"%s\"; valid values are \"none\", \"portal\", " 992275244Strasz "\"portal-name\", and \"portal-name-auth\"", 993275244Strasz str, pg->pg_name); 994275244Strasz return (1); 995275244Strasz } 996275244Strasz 997275245Strasz if (pg->pg_discovery_filter != PG_FILTER_UNKNOWN && 998275245Strasz pg->pg_discovery_filter != filter) { 999275244Strasz log_warnx("cannot set discovery-filter to \"%s\" for " 1000275244Strasz "portal-group \"%s\"; already has a different " 1001275244Strasz "value", str, pg->pg_name); 1002275244Strasz return (1); 1003275244Strasz } 1004275244Strasz 1005275245Strasz pg->pg_discovery_filter = filter; 1006275245Strasz 1007275245Strasz return (0); 1008275244Strasz} 1009275244Strasz 1010275642Straszint 1011275642Straszportal_group_set_redirection(struct portal_group *pg, const char *addr) 1012275642Strasz{ 1013275642Strasz 1014275642Strasz if (pg->pg_redirection != NULL) { 1015275642Strasz log_warnx("cannot set redirection to \"%s\" for " 1016275642Strasz "portal-group \"%s\"; already defined", 1017275642Strasz addr, pg->pg_name); 1018275642Strasz return (1); 1019275642Strasz } 1020275642Strasz 1021275642Strasz pg->pg_redirection = checked_strdup(addr); 1022275642Strasz 1023275642Strasz return (0); 1024275642Strasz} 1025275642Strasz 1026255570Straszstatic bool 1027255570Straszvalid_hex(const char ch) 1028255570Strasz{ 1029255570Strasz switch (ch) { 1030255570Strasz case '0': 1031255570Strasz case '1': 1032255570Strasz case '2': 1033255570Strasz case '3': 1034255570Strasz case '4': 1035255570Strasz case '5': 1036255570Strasz case '6': 1037255570Strasz case '7': 1038255570Strasz case '8': 1039255570Strasz case '9': 1040255570Strasz case 'a': 1041255570Strasz case 'A': 1042255570Strasz case 'b': 1043255570Strasz case 'B': 1044255570Strasz case 'c': 1045255570Strasz case 'C': 1046255570Strasz case 'd': 1047255570Strasz case 'D': 1048255570Strasz case 'e': 1049255570Strasz case 'E': 1050255570Strasz case 'f': 1051255570Strasz case 'F': 1052255570Strasz return (true); 1053255570Strasz default: 1054255570Strasz return (false); 1055255570Strasz } 1056255570Strasz} 1057255570Strasz 1058255570Straszbool 1059255570Straszvalid_iscsi_name(const char *name) 1060255570Strasz{ 1061255570Strasz int i; 1062255570Strasz 1063255570Strasz if (strlen(name) >= MAX_NAME_LEN) { 1064255570Strasz log_warnx("overlong name for target \"%s\"; max length allowed " 1065255570Strasz "by iSCSI specification is %d characters", 1066255570Strasz name, MAX_NAME_LEN); 1067255570Strasz return (false); 1068255570Strasz } 1069255570Strasz 1070255570Strasz /* 1071255570Strasz * In the cases below, we don't return an error, just in case the admin 1072255570Strasz * was right, and we're wrong. 1073255570Strasz */ 1074255570Strasz if (strncasecmp(name, "iqn.", strlen("iqn.")) == 0) { 1075255570Strasz for (i = strlen("iqn."); name[i] != '\0'; i++) { 1076255570Strasz /* 1077255570Strasz * XXX: We should verify UTF-8 normalisation, as defined 1078274870Strasz * by 3.2.6.2: iSCSI Name Encoding. 1079255570Strasz */ 1080255570Strasz if (isalnum(name[i])) 1081255570Strasz continue; 1082255570Strasz if (name[i] == '-' || name[i] == '.' || name[i] == ':') 1083255570Strasz continue; 1084255570Strasz log_warnx("invalid character \"%c\" in target name " 1085255570Strasz "\"%s\"; allowed characters are letters, digits, " 1086255570Strasz "'-', '.', and ':'", name[i], name); 1087255570Strasz break; 1088255570Strasz } 1089255570Strasz /* 1090255570Strasz * XXX: Check more stuff: valid date and a valid reversed domain. 1091255570Strasz */ 1092255570Strasz } else if (strncasecmp(name, "eui.", strlen("eui.")) == 0) { 1093255570Strasz if (strlen(name) != strlen("eui.") + 16) 1094255570Strasz log_warnx("invalid target name \"%s\"; the \"eui.\" " 1095255570Strasz "should be followed by exactly 16 hexadecimal " 1096255570Strasz "digits", name); 1097255570Strasz for (i = strlen("eui."); name[i] != '\0'; i++) { 1098255570Strasz if (!valid_hex(name[i])) { 1099255570Strasz log_warnx("invalid character \"%c\" in target " 1100255570Strasz "name \"%s\"; allowed characters are 1-9 " 1101255570Strasz "and A-F", name[i], name); 1102255570Strasz break; 1103255570Strasz } 1104255570Strasz } 1105255570Strasz } else if (strncasecmp(name, "naa.", strlen("naa.")) == 0) { 1106255570Strasz if (strlen(name) > strlen("naa.") + 32) 1107255570Strasz log_warnx("invalid target name \"%s\"; the \"naa.\" " 1108255570Strasz "should be followed by at most 32 hexadecimal " 1109255570Strasz "digits", name); 1110255570Strasz for (i = strlen("naa."); name[i] != '\0'; i++) { 1111255570Strasz if (!valid_hex(name[i])) { 1112255570Strasz log_warnx("invalid character \"%c\" in target " 1113255570Strasz "name \"%s\"; allowed characters are 1-9 " 1114255570Strasz "and A-F", name[i], name); 1115255570Strasz break; 1116255570Strasz } 1117255570Strasz } 1118255570Strasz } else { 1119255570Strasz log_warnx("invalid target name \"%s\"; should start with " 1120255570Strasz "either \".iqn\", \"eui.\", or \"naa.\"", 1121255570Strasz name); 1122255570Strasz } 1123255570Strasz return (true); 1124255570Strasz} 1125255570Strasz 1126255570Straszstruct target * 1127263723Strasztarget_new(struct conf *conf, const char *name) 1128255570Strasz{ 1129255570Strasz struct target *targ; 1130255570Strasz int i, len; 1131255570Strasz 1132263723Strasz targ = target_find(conf, name); 1133255570Strasz if (targ != NULL) { 1134263723Strasz log_warnx("duplicated target \"%s\"", name); 1135255570Strasz return (NULL); 1136255570Strasz } 1137263723Strasz if (valid_iscsi_name(name) == false) { 1138263723Strasz log_warnx("target name \"%s\" is invalid", name); 1139255570Strasz return (NULL); 1140255570Strasz } 1141255570Strasz targ = calloc(1, sizeof(*targ)); 1142255570Strasz if (targ == NULL) 1143255570Strasz log_err(1, "calloc"); 1144263723Strasz targ->t_name = checked_strdup(name); 1145255570Strasz 1146255570Strasz /* 1147255570Strasz * RFC 3722 requires us to normalize the name to lowercase. 1148255570Strasz */ 1149263723Strasz len = strlen(name); 1150255570Strasz for (i = 0; i < len; i++) 1151263723Strasz targ->t_name[i] = tolower(targ->t_name[i]); 1152255570Strasz 1153255570Strasz targ->t_conf = conf; 1154255570Strasz TAILQ_INSERT_TAIL(&conf->conf_targets, targ, t_next); 1155255570Strasz 1156255570Strasz return (targ); 1157255570Strasz} 1158255570Strasz 1159255570Straszvoid 1160255570Strasztarget_delete(struct target *targ) 1161255570Strasz{ 1162255570Strasz 1163255570Strasz TAILQ_REMOVE(&targ->t_conf->conf_targets, targ, t_next); 1164255570Strasz 1165263723Strasz free(targ->t_name); 1166275642Strasz free(targ->t_redirection); 1167255570Strasz free(targ); 1168255570Strasz} 1169255570Strasz 1170255570Straszstruct target * 1171263723Strasztarget_find(struct conf *conf, const char *name) 1172255570Strasz{ 1173255570Strasz struct target *targ; 1174255570Strasz 1175255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 1176263723Strasz if (strcasecmp(targ->t_name, name) == 0) 1177255570Strasz return (targ); 1178255570Strasz } 1179255570Strasz 1180255570Strasz return (NULL); 1181255570Strasz} 1182255570Strasz 1183275642Straszint 1184275642Strasztarget_set_redirection(struct target *target, const char *addr) 1185275642Strasz{ 1186275642Strasz 1187275642Strasz if (target->t_redirection != NULL) { 1188275642Strasz log_warnx("cannot set redirection to \"%s\" for " 1189275642Strasz "target \"%s\"; already defined", 1190275642Strasz addr, target->t_name); 1191275642Strasz return (1); 1192275642Strasz } 1193275642Strasz 1194275642Strasz target->t_redirection = checked_strdup(addr); 1195275642Strasz 1196275642Strasz return (0); 1197275642Strasz} 1198275642Strasz 1199279002Smavvoid 1200279002Smavtarget_set_ctl_port(struct target *target, uint32_t value) 1201279002Smav{ 1202279002Smav 1203279002Smav target->t_ctl_port = value; 1204279002Smav} 1205279002Smav 1206255570Straszstruct lun * 1207279002Smavlun_new(struct conf *conf, const char *name) 1208255570Strasz{ 1209255570Strasz struct lun *lun; 1210255570Strasz 1211279002Smav lun = lun_find(conf, name); 1212255570Strasz if (lun != NULL) { 1213279002Smav log_warnx("duplicated lun \"%s\"", name); 1214255570Strasz return (NULL); 1215255570Strasz } 1216255570Strasz 1217255570Strasz lun = calloc(1, sizeof(*lun)); 1218255570Strasz if (lun == NULL) 1219255570Strasz log_err(1, "calloc"); 1220279002Smav lun->l_conf = conf; 1221279002Smav lun->l_name = checked_strdup(name); 1222255570Strasz TAILQ_INIT(&lun->l_options); 1223279002Smav TAILQ_INSERT_TAIL(&conf->conf_luns, lun, l_next); 1224255570Strasz 1225255570Strasz return (lun); 1226255570Strasz} 1227255570Strasz 1228255570Straszvoid 1229255570Straszlun_delete(struct lun *lun) 1230255570Strasz{ 1231279002Smav struct target *targ; 1232255570Strasz struct lun_option *lo, *tmp; 1233279002Smav int i; 1234255570Strasz 1235279002Smav TAILQ_FOREACH(targ, &lun->l_conf->conf_targets, t_next) { 1236279002Smav for (i = 0; i < MAX_LUNS; i++) { 1237279002Smav if (targ->t_luns[i] == lun) 1238279002Smav targ->t_luns[i] = NULL; 1239279002Smav } 1240279002Smav } 1241279002Smav TAILQ_REMOVE(&lun->l_conf->conf_luns, lun, l_next); 1242255570Strasz 1243255570Strasz TAILQ_FOREACH_SAFE(lo, &lun->l_options, lo_next, tmp) 1244255570Strasz lun_option_delete(lo); 1245279002Smav free(lun->l_name); 1246255570Strasz free(lun->l_backend); 1247255570Strasz free(lun->l_device_id); 1248255570Strasz free(lun->l_path); 1249279002Smav free(lun->l_scsiname); 1250255570Strasz free(lun->l_serial); 1251255570Strasz free(lun); 1252255570Strasz} 1253255570Strasz 1254255570Straszstruct lun * 1255279002Smavlun_find(const struct conf *conf, const char *name) 1256255570Strasz{ 1257255570Strasz struct lun *lun; 1258255570Strasz 1259279002Smav TAILQ_FOREACH(lun, &conf->conf_luns, l_next) { 1260279002Smav if (strcmp(lun->l_name, name) == 0) 1261255570Strasz return (lun); 1262255570Strasz } 1263255570Strasz 1264255570Strasz return (NULL); 1265255570Strasz} 1266255570Strasz 1267255570Straszvoid 1268255570Straszlun_set_backend(struct lun *lun, const char *value) 1269255570Strasz{ 1270255570Strasz free(lun->l_backend); 1271255570Strasz lun->l_backend = checked_strdup(value); 1272255570Strasz} 1273255570Strasz 1274255570Straszvoid 1275255570Straszlun_set_blocksize(struct lun *lun, size_t value) 1276255570Strasz{ 1277255570Strasz 1278255570Strasz lun->l_blocksize = value; 1279255570Strasz} 1280255570Strasz 1281255570Straszvoid 1282255570Straszlun_set_device_id(struct lun *lun, const char *value) 1283255570Strasz{ 1284255570Strasz free(lun->l_device_id); 1285255570Strasz lun->l_device_id = checked_strdup(value); 1286255570Strasz} 1287255570Strasz 1288255570Straszvoid 1289255570Straszlun_set_path(struct lun *lun, const char *value) 1290255570Strasz{ 1291255570Strasz free(lun->l_path); 1292255570Strasz lun->l_path = checked_strdup(value); 1293255570Strasz} 1294255570Strasz 1295255570Straszvoid 1296279002Smavlun_set_scsiname(struct lun *lun, const char *value) 1297279002Smav{ 1298279002Smav free(lun->l_scsiname); 1299279002Smav lun->l_scsiname = checked_strdup(value); 1300279002Smav} 1301279002Smav 1302279002Smavvoid 1303255570Straszlun_set_serial(struct lun *lun, const char *value) 1304255570Strasz{ 1305255570Strasz free(lun->l_serial); 1306255570Strasz lun->l_serial = checked_strdup(value); 1307255570Strasz} 1308255570Strasz 1309255570Straszvoid 1310255570Straszlun_set_size(struct lun *lun, size_t value) 1311255570Strasz{ 1312255570Strasz 1313255570Strasz lun->l_size = value; 1314255570Strasz} 1315255570Strasz 1316255570Straszvoid 1317255570Straszlun_set_ctl_lun(struct lun *lun, uint32_t value) 1318255570Strasz{ 1319255570Strasz 1320255570Strasz lun->l_ctl_lun = value; 1321255570Strasz} 1322255570Strasz 1323255570Straszstruct lun_option * 1324255570Straszlun_option_new(struct lun *lun, const char *name, const char *value) 1325255570Strasz{ 1326255570Strasz struct lun_option *lo; 1327255570Strasz 1328255570Strasz lo = lun_option_find(lun, name); 1329255570Strasz if (lo != NULL) { 1330279002Smav log_warnx("duplicated lun option \"%s\" for lun \"%s\"", 1331279002Smav name, lun->l_name); 1332255570Strasz return (NULL); 1333255570Strasz } 1334255570Strasz 1335255570Strasz lo = calloc(1, sizeof(*lo)); 1336255570Strasz if (lo == NULL) 1337255570Strasz log_err(1, "calloc"); 1338255570Strasz lo->lo_name = checked_strdup(name); 1339255570Strasz lo->lo_value = checked_strdup(value); 1340255570Strasz lo->lo_lun = lun; 1341255570Strasz TAILQ_INSERT_TAIL(&lun->l_options, lo, lo_next); 1342255570Strasz 1343255570Strasz return (lo); 1344255570Strasz} 1345255570Strasz 1346255570Straszvoid 1347255570Straszlun_option_delete(struct lun_option *lo) 1348255570Strasz{ 1349255570Strasz 1350255570Strasz TAILQ_REMOVE(&lo->lo_lun->l_options, lo, lo_next); 1351255570Strasz 1352255570Strasz free(lo->lo_name); 1353255570Strasz free(lo->lo_value); 1354255570Strasz free(lo); 1355255570Strasz} 1356255570Strasz 1357255570Straszstruct lun_option * 1358265514Straszlun_option_find(const struct lun *lun, const char *name) 1359255570Strasz{ 1360255570Strasz struct lun_option *lo; 1361255570Strasz 1362255570Strasz TAILQ_FOREACH(lo, &lun->l_options, lo_next) { 1363255570Strasz if (strcmp(lo->lo_name, name) == 0) 1364255570Strasz return (lo); 1365255570Strasz } 1366255570Strasz 1367255570Strasz return (NULL); 1368255570Strasz} 1369255570Strasz 1370255570Straszvoid 1371255570Straszlun_option_set(struct lun_option *lo, const char *value) 1372255570Strasz{ 1373255570Strasz 1374255570Strasz free(lo->lo_value); 1375255570Strasz lo->lo_value = checked_strdup(value); 1376255570Strasz} 1377255570Strasz 1378255570Straszstatic struct connection * 1379270137Smavconnection_new(struct portal *portal, int fd, const char *host, 1380270137Smav const struct sockaddr *client_sa) 1381255570Strasz{ 1382255570Strasz struct connection *conn; 1383255570Strasz 1384255570Strasz conn = calloc(1, sizeof(*conn)); 1385255570Strasz if (conn == NULL) 1386255570Strasz log_err(1, "calloc"); 1387255570Strasz conn->conn_portal = portal; 1388255570Strasz conn->conn_socket = fd; 1389255570Strasz conn->conn_initiator_addr = checked_strdup(host); 1390270137Smav memcpy(&conn->conn_initiator_sa, client_sa, client_sa->sa_len); 1391255570Strasz 1392255570Strasz /* 1393255570Strasz * Default values, from RFC 3720, section 12. 1394255570Strasz */ 1395255570Strasz conn->conn_max_data_segment_length = 8192; 1396255570Strasz conn->conn_max_burst_length = 262144; 1397255570Strasz conn->conn_immediate_data = true; 1398255570Strasz 1399255570Strasz return (conn); 1400255570Strasz} 1401255570Strasz 1402255570Strasz#if 0 1403255570Straszstatic void 1404255570Straszconf_print(struct conf *conf) 1405255570Strasz{ 1406255570Strasz struct auth_group *ag; 1407255570Strasz struct auth *auth; 1408263720Strasz struct auth_name *auth_name; 1409263720Strasz struct auth_portal *auth_portal; 1410255570Strasz struct portal_group *pg; 1411255570Strasz struct portal *portal; 1412255570Strasz struct target *targ; 1413255570Strasz struct lun *lun; 1414255570Strasz struct lun_option *lo; 1415255570Strasz 1416255570Strasz TAILQ_FOREACH(ag, &conf->conf_auth_groups, ag_next) { 1417255570Strasz fprintf(stderr, "auth-group %s {\n", ag->ag_name); 1418255570Strasz TAILQ_FOREACH(auth, &ag->ag_auths, a_next) 1419255570Strasz fprintf(stderr, "\t chap-mutual %s %s %s %s\n", 1420255570Strasz auth->a_user, auth->a_secret, 1421255570Strasz auth->a_mutual_user, auth->a_mutual_secret); 1422263720Strasz TAILQ_FOREACH(auth_name, &ag->ag_names, an_next) 1423263720Strasz fprintf(stderr, "\t initiator-name %s\n", 1424263720Strasz auth_name->an_initator_name); 1425263720Strasz TAILQ_FOREACH(auth_portal, &ag->ag_portals, an_next) 1426263720Strasz fprintf(stderr, "\t initiator-portal %s\n", 1427263720Strasz auth_portal->an_initator_portal); 1428255570Strasz fprintf(stderr, "}\n"); 1429255570Strasz } 1430255570Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 1431255570Strasz fprintf(stderr, "portal-group %s {\n", pg->pg_name); 1432255570Strasz TAILQ_FOREACH(portal, &pg->pg_portals, p_next) 1433255570Strasz fprintf(stderr, "\t listen %s\n", portal->p_listen); 1434255570Strasz fprintf(stderr, "}\n"); 1435255570Strasz } 1436279002Smav TAILQ_FOREACH(lun, &conf->conf_luns, l_next) { 1437279002Smav fprintf(stderr, "\tlun %s {\n", lun->l_name); 1438279002Smav fprintf(stderr, "\t\tpath %s\n", lun->l_path); 1439279002Smav TAILQ_FOREACH(lo, &lun->l_options, lo_next) 1440279002Smav fprintf(stderr, "\t\toption %s %s\n", 1441279002Smav lo->lo_name, lo->lo_value); 1442279002Smav fprintf(stderr, "\t}\n"); 1443279002Smav } 1444255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 1445263723Strasz fprintf(stderr, "target %s {\n", targ->t_name); 1446255570Strasz if (targ->t_alias != NULL) 1447255570Strasz fprintf(stderr, "\t alias %s\n", targ->t_alias); 1448255570Strasz fprintf(stderr, "}\n"); 1449255570Strasz } 1450255570Strasz} 1451255570Strasz#endif 1452255570Strasz 1453263717Straszstatic int 1454263717Straszconf_verify_lun(struct lun *lun) 1455263717Strasz{ 1456263717Strasz const struct lun *lun2; 1457263717Strasz 1458263717Strasz if (lun->l_backend == NULL) 1459263717Strasz lun_set_backend(lun, "block"); 1460263717Strasz if (strcmp(lun->l_backend, "block") == 0) { 1461263717Strasz if (lun->l_path == NULL) { 1462279002Smav log_warnx("missing path for lun \"%s\"", 1463279002Smav lun->l_name); 1464263717Strasz return (1); 1465263717Strasz } 1466263717Strasz } else if (strcmp(lun->l_backend, "ramdisk") == 0) { 1467263717Strasz if (lun->l_size == 0) { 1468279002Smav log_warnx("missing size for ramdisk-backed lun \"%s\"", 1469279002Smav lun->l_name); 1470263717Strasz return (1); 1471263717Strasz } 1472263717Strasz if (lun->l_path != NULL) { 1473263717Strasz log_warnx("path must not be specified " 1474279002Smav "for ramdisk-backed lun \"%s\"", 1475279002Smav lun->l_name); 1476263717Strasz return (1); 1477263717Strasz } 1478263717Strasz } 1479263717Strasz if (lun->l_blocksize == 0) { 1480263717Strasz lun_set_blocksize(lun, DEFAULT_BLOCKSIZE); 1481263717Strasz } else if (lun->l_blocksize < 0) { 1482279002Smav log_warnx("invalid blocksize for lun \"%s\"; " 1483279002Smav "must be larger than 0", lun->l_name); 1484263717Strasz return (1); 1485263717Strasz } 1486263717Strasz if (lun->l_size != 0 && lun->l_size % lun->l_blocksize != 0) { 1487279002Smav log_warnx("invalid size for lun \"%s\"; " 1488279002Smav "must be multiple of blocksize", lun->l_name); 1489263717Strasz return (1); 1490263717Strasz } 1491279002Smav TAILQ_FOREACH(lun2, &lun->l_conf->conf_luns, l_next) { 1492279002Smav if (lun == lun2) 1493279002Smav continue; 1494279002Smav if (lun->l_path != NULL && lun2->l_path != NULL && 1495279002Smav strcmp(lun->l_path, lun2->l_path) == 0) { 1496279002Smav log_debugx("WARNING: path \"%s\" duplicated " 1497279002Smav "between lun \"%s\", and " 1498279002Smav "lun \"%s\"", lun->l_path, 1499279002Smav lun->l_name, lun2->l_name); 1500263718Strasz } 1501263718Strasz } 1502263717Strasz 1503263717Strasz return (0); 1504263717Strasz} 1505263717Strasz 1506255570Straszint 1507255570Straszconf_verify(struct conf *conf) 1508255570Strasz{ 1509255570Strasz struct auth_group *ag; 1510255570Strasz struct portal_group *pg; 1511255570Strasz struct target *targ; 1512263717Strasz struct lun *lun; 1513274871Strasz bool found; 1514279002Smav int error, i; 1515255570Strasz 1516255570Strasz if (conf->conf_pidfile_path == NULL) 1517255570Strasz conf->conf_pidfile_path = checked_strdup(DEFAULT_PIDFILE); 1518255570Strasz 1519279002Smav TAILQ_FOREACH(lun, &conf->conf_luns, l_next) { 1520279002Smav error = conf_verify_lun(lun); 1521279002Smav if (error != 0) 1522279002Smav return (error); 1523279002Smav } 1524255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 1525255570Strasz if (targ->t_auth_group == NULL) { 1526263726Strasz targ->t_auth_group = auth_group_find(conf, 1527263726Strasz "default"); 1528263726Strasz assert(targ->t_auth_group != NULL); 1529255570Strasz } 1530255570Strasz if (targ->t_portal_group == NULL) { 1531255570Strasz targ->t_portal_group = portal_group_find(conf, 1532255570Strasz "default"); 1533255570Strasz assert(targ->t_portal_group != NULL); 1534255570Strasz } 1535274871Strasz found = false; 1536279002Smav for (i = 0; i < MAX_LUNS; i++) { 1537279002Smav if (targ->t_luns[i] != NULL) 1538279002Smav found = true; 1539255570Strasz } 1540275642Strasz if (!found && targ->t_redirection == NULL) { 1541265506Strasz log_warnx("no LUNs defined for target \"%s\"", 1542265506Strasz targ->t_name); 1543255570Strasz } 1544275642Strasz if (found && targ->t_redirection != NULL) { 1545275642Strasz log_debugx("target \"%s\" contains luns, " 1546275642Strasz " but configured for redirection", 1547275642Strasz targ->t_name); 1548275642Strasz } 1549255570Strasz } 1550255570Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 1551255570Strasz assert(pg->pg_name != NULL); 1552255570Strasz if (pg->pg_discovery_auth_group == NULL) { 1553255570Strasz pg->pg_discovery_auth_group = 1554263728Strasz auth_group_find(conf, "default"); 1555255570Strasz assert(pg->pg_discovery_auth_group != NULL); 1556255570Strasz } 1557255570Strasz 1558275244Strasz if (pg->pg_discovery_filter == PG_FILTER_UNKNOWN) 1559275244Strasz pg->pg_discovery_filter = PG_FILTER_NONE; 1560275244Strasz 1561255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 1562255570Strasz if (targ->t_portal_group == pg) 1563255570Strasz break; 1564255570Strasz } 1565275642Strasz if (pg->pg_redirection != NULL) { 1566275642Strasz if (targ != NULL) { 1567275642Strasz log_debugx("portal-group \"%s\" assigned " 1568275642Strasz "to target \"%s\", but configured " 1569275642Strasz "for redirection", 1570275642Strasz pg->pg_name, targ->t_name); 1571275642Strasz } 1572275642Strasz pg->pg_unassigned = false; 1573275642Strasz } else if (targ != NULL) { 1574275642Strasz pg->pg_unassigned = false; 1575275642Strasz } else { 1576255570Strasz if (strcmp(pg->pg_name, "default") != 0) 1577255570Strasz log_warnx("portal-group \"%s\" not assigned " 1578255570Strasz "to any target", pg->pg_name); 1579255570Strasz pg->pg_unassigned = true; 1580275642Strasz } 1581255570Strasz } 1582255570Strasz TAILQ_FOREACH(ag, &conf->conf_auth_groups, ag_next) { 1583255570Strasz if (ag->ag_name == NULL) 1584255570Strasz assert(ag->ag_target != NULL); 1585255570Strasz else 1586255570Strasz assert(ag->ag_target == NULL); 1587255570Strasz 1588274871Strasz found = false; 1589255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 1590274871Strasz if (targ->t_auth_group == ag) { 1591274871Strasz found = true; 1592255570Strasz break; 1593274871Strasz } 1594255570Strasz } 1595274871Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 1596274871Strasz if (pg->pg_discovery_auth_group == ag) { 1597274871Strasz found = true; 1598274871Strasz break; 1599274871Strasz } 1600274871Strasz } 1601274871Strasz if (!found && ag->ag_name != NULL && 1602263728Strasz strcmp(ag->ag_name, "default") != 0 && 1603255570Strasz strcmp(ag->ag_name, "no-authentication") != 0 && 1604255570Strasz strcmp(ag->ag_name, "no-access") != 0) { 1605255570Strasz log_warnx("auth-group \"%s\" not assigned " 1606255570Strasz "to any target", ag->ag_name); 1607255570Strasz } 1608255570Strasz } 1609255570Strasz 1610255570Strasz return (0); 1611255570Strasz} 1612255570Strasz 1613255570Straszstatic int 1614255570Straszconf_apply(struct conf *oldconf, struct conf *newconf) 1615255570Strasz{ 1616255570Strasz struct target *oldtarg, *newtarg, *tmptarg; 1617255570Strasz struct lun *oldlun, *newlun, *tmplun; 1618255570Strasz struct portal_group *oldpg, *newpg; 1619255570Strasz struct portal *oldp, *newp; 1620274939Smav struct isns *oldns, *newns; 1621255570Strasz pid_t otherpid; 1622279001Smav int changed, cumulated_error = 0, error, sockbuf; 1623255570Strasz int one = 1; 1624255570Strasz 1625255570Strasz if (oldconf->conf_debug != newconf->conf_debug) { 1626255570Strasz log_debugx("changing debug level to %d", newconf->conf_debug); 1627255570Strasz log_init(newconf->conf_debug); 1628255570Strasz } 1629255570Strasz 1630255570Strasz if (oldconf->conf_pidfh != NULL) { 1631255570Strasz assert(oldconf->conf_pidfile_path != NULL); 1632255570Strasz if (newconf->conf_pidfile_path != NULL && 1633255570Strasz strcmp(oldconf->conf_pidfile_path, 1634255570Strasz newconf->conf_pidfile_path) == 0) { 1635255570Strasz newconf->conf_pidfh = oldconf->conf_pidfh; 1636255570Strasz oldconf->conf_pidfh = NULL; 1637255570Strasz } else { 1638255570Strasz log_debugx("removing pidfile %s", 1639255570Strasz oldconf->conf_pidfile_path); 1640255570Strasz pidfile_remove(oldconf->conf_pidfh); 1641255570Strasz oldconf->conf_pidfh = NULL; 1642255570Strasz } 1643255570Strasz } 1644255570Strasz 1645255570Strasz if (newconf->conf_pidfh == NULL && newconf->conf_pidfile_path != NULL) { 1646255570Strasz log_debugx("opening pidfile %s", newconf->conf_pidfile_path); 1647255570Strasz newconf->conf_pidfh = 1648255570Strasz pidfile_open(newconf->conf_pidfile_path, 0600, &otherpid); 1649255570Strasz if (newconf->conf_pidfh == NULL) { 1650255570Strasz if (errno == EEXIST) 1651255570Strasz log_errx(1, "daemon already running, pid: %jd.", 1652255570Strasz (intmax_t)otherpid); 1653255570Strasz log_err(1, "cannot open or create pidfile \"%s\"", 1654255570Strasz newconf->conf_pidfile_path); 1655255570Strasz } 1656255570Strasz } 1657255570Strasz 1658274939Smav /* Deregister on removed iSNS servers. */ 1659274939Smav TAILQ_FOREACH(oldns, &oldconf->conf_isns, i_next) { 1660274939Smav TAILQ_FOREACH(newns, &newconf->conf_isns, i_next) { 1661274939Smav if (strcmp(oldns->i_addr, newns->i_addr) == 0) 1662274939Smav break; 1663274939Smav } 1664274939Smav if (newns == NULL) 1665274939Smav isns_deregister(oldns); 1666274939Smav } 1667274939Smav 1668265518Strasz /* 1669265518Strasz * XXX: If target or lun removal fails, we should somehow "move" 1670274870Strasz * the old lun or target into newconf, so that subsequent 1671274870Strasz * conf_apply() would try to remove them again. That would 1672274870Strasz * be somewhat hairy, though, and lun deletion failures don't 1673274870Strasz * really happen, so leave it as it is for now. 1674265518Strasz */ 1675279002Smav /* 1676279002Smav * First, remove any targets present in the old configuration 1677279002Smav * and missing in the new one. 1678279002Smav */ 1679255570Strasz TAILQ_FOREACH_SAFE(oldtarg, &oldconf->conf_targets, t_next, tmptarg) { 1680263723Strasz newtarg = target_find(newconf, oldtarg->t_name); 1681279002Smav if (newtarg != NULL) 1682279002Smav continue; 1683279002Smav error = kernel_port_remove(oldtarg); 1684279002Smav if (error != 0) { 1685279002Smav log_warnx("failed to remove target %s", 1686279002Smav oldtarg->t_name); 1687279002Smav /* 1688279002Smav * XXX: Uncomment after fixing the root cause. 1689279002Smav * 1690279002Smav * cumulated_error++; 1691279002Smav */ 1692279002Smav } 1693279002Smav } 1694279002Smav 1695279002Smav /* 1696279002Smav * Second, remove any LUNs present in the old configuration 1697279002Smav * and missing in the new one. 1698279002Smav */ 1699279002Smav TAILQ_FOREACH_SAFE(oldlun, &oldconf->conf_luns, l_next, tmplun) { 1700279002Smav newlun = lun_find(newconf, oldlun->l_name); 1701279002Smav if (newlun == NULL) { 1702279002Smav log_debugx("lun \"%s\", CTL lun %d " 1703279002Smav "not found in new configuration; " 1704279002Smav "removing", oldlun->l_name, oldlun->l_ctl_lun); 1705279002Smav error = kernel_lun_remove(oldlun); 1706279000Smav if (error != 0) { 1707279002Smav log_warnx("failed to remove lun \"%s\", " 1708279002Smav "CTL lun %d", 1709279002Smav oldlun->l_name, oldlun->l_ctl_lun); 1710279002Smav cumulated_error++; 1711279000Smav } 1712255570Strasz continue; 1713255570Strasz } 1714255570Strasz 1715255570Strasz /* 1716279002Smav * Also remove the LUNs changed by more than size. 1717255570Strasz */ 1718279002Smav changed = 0; 1719279002Smav assert(oldlun->l_backend != NULL); 1720279002Smav assert(newlun->l_backend != NULL); 1721279002Smav if (strcmp(newlun->l_backend, oldlun->l_backend) != 0) { 1722279002Smav log_debugx("backend for lun \"%s\", " 1723279002Smav "CTL lun %d changed; removing", 1724279002Smav oldlun->l_name, oldlun->l_ctl_lun); 1725279002Smav changed = 1; 1726279002Smav } 1727279002Smav if (oldlun->l_blocksize != newlun->l_blocksize) { 1728279002Smav log_debugx("blocksize for lun \"%s\", " 1729279002Smav "CTL lun %d changed; removing", 1730279002Smav oldlun->l_name, oldlun->l_ctl_lun); 1731279002Smav changed = 1; 1732279002Smav } 1733279002Smav if (newlun->l_device_id != NULL && 1734279002Smav (oldlun->l_device_id == NULL || 1735279002Smav strcmp(oldlun->l_device_id, newlun->l_device_id) != 1736279002Smav 0)) { 1737279002Smav log_debugx("device-id for lun \"%s\", " 1738279002Smav "CTL lun %d changed; removing", 1739279002Smav oldlun->l_name, oldlun->l_ctl_lun); 1740279002Smav changed = 1; 1741279002Smav } 1742279002Smav if (newlun->l_path != NULL && 1743279002Smav (oldlun->l_path == NULL || 1744279002Smav strcmp(oldlun->l_path, newlun->l_path) != 0)) { 1745279002Smav log_debugx("path for lun \"%s\", " 1746279002Smav "CTL lun %d, changed; removing", 1747279002Smav oldlun->l_name, oldlun->l_ctl_lun); 1748279002Smav changed = 1; 1749279002Smav } 1750279002Smav if (newlun->l_serial != NULL && 1751279002Smav (oldlun->l_serial == NULL || 1752279002Smav strcmp(oldlun->l_serial, newlun->l_serial) != 0)) { 1753279002Smav log_debugx("serial for lun \"%s\", " 1754279002Smav "CTL lun %d changed; removing", 1755279002Smav oldlun->l_name, oldlun->l_ctl_lun); 1756279002Smav changed = 1; 1757279002Smav } 1758279002Smav if (changed) { 1759279002Smav error = kernel_lun_remove(oldlun); 1760279002Smav if (error != 0) { 1761279002Smav log_warnx("failed to remove lun \"%s\", " 1762279002Smav "CTL lun %d", 1763279002Smav oldlun->l_name, oldlun->l_ctl_lun); 1764279002Smav cumulated_error++; 1765255570Strasz } 1766279002Smav lun_delete(oldlun); 1767279002Smav continue; 1768279002Smav } 1769255570Strasz 1770279002Smav lun_set_ctl_lun(newlun, oldlun->l_ctl_lun); 1771279002Smav } 1772279002Smav 1773279002Smav TAILQ_FOREACH_SAFE(newlun, &newconf->conf_luns, l_next, tmplun) { 1774279002Smav oldlun = lun_find(oldconf, newlun->l_name); 1775279002Smav if (oldlun != NULL) { 1776279002Smav if (newlun->l_size != oldlun->l_size || 1777279002Smav newlun->l_size == 0) { 1778279002Smav log_debugx("resizing lun \"%s\", CTL lun %d", 1779279002Smav newlun->l_name, newlun->l_ctl_lun); 1780279002Smav error = kernel_lun_resize(newlun); 1781255570Strasz if (error != 0) { 1782279002Smav log_warnx("failed to " 1783279002Smav "resize lun \"%s\", CTL lun %d", 1784279002Smav newlun->l_name, 1785279002Smav newlun->l_ctl_lun); 1786255570Strasz cumulated_error++; 1787255570Strasz } 1788255570Strasz } 1789279002Smav continue; 1790255570Strasz } 1791279002Smav log_debugx("adding lun \"%s\"", newlun->l_name); 1792279002Smav error = kernel_lun_add(newlun); 1793279002Smav if (error != 0) { 1794279002Smav log_warnx("failed to add lun \"%s\"", newlun->l_name); 1795279002Smav lun_delete(newlun); 1796279002Smav cumulated_error++; 1797279002Smav } 1798255570Strasz } 1799255570Strasz 1800255570Strasz /* 1801255570Strasz * Now add new targets or modify existing ones. 1802255570Strasz */ 1803255570Strasz TAILQ_FOREACH(newtarg, &newconf->conf_targets, t_next) { 1804263723Strasz oldtarg = target_find(oldconf, newtarg->t_name); 1805255570Strasz 1806279002Smav if (oldtarg == NULL) 1807277749Strasz error = kernel_port_add(newtarg); 1808279002Smav else { 1809279002Smav target_set_ctl_port(newtarg, oldtarg->t_ctl_port); 1810279002Smav error = kernel_port_update(newtarg); 1811277749Strasz } 1812279002Smav if (error != 0) { 1813279002Smav log_warnx("failed to %s target %s", 1814279002Smav (oldtarg == NULL) ? "add" : "update", 1815279002Smav newtarg->t_name); 1816279002Smav /* 1817279002Smav * XXX: Uncomment after fixing the root cause. 1818279002Smav * 1819279002Smav * cumulated_error++; 1820279002Smav */ 1821279002Smav } 1822255570Strasz } 1823255570Strasz 1824255570Strasz /* 1825255570Strasz * Go through the new portals, opening the sockets as neccessary. 1826255570Strasz */ 1827255570Strasz TAILQ_FOREACH(newpg, &newconf->conf_portal_groups, pg_next) { 1828255570Strasz if (newpg->pg_unassigned) { 1829255570Strasz log_debugx("not listening on portal-group \"%s\", " 1830255570Strasz "not assigned to any target", 1831255570Strasz newpg->pg_name); 1832255570Strasz continue; 1833255570Strasz } 1834255570Strasz TAILQ_FOREACH(newp, &newpg->pg_portals, p_next) { 1835255570Strasz /* 1836255570Strasz * Try to find already open portal and reuse 1837255570Strasz * the listening socket. We don't care about 1838255570Strasz * what portal or portal group that was, what 1839255570Strasz * matters is the listening address. 1840255570Strasz */ 1841255570Strasz TAILQ_FOREACH(oldpg, &oldconf->conf_portal_groups, 1842255570Strasz pg_next) { 1843255570Strasz TAILQ_FOREACH(oldp, &oldpg->pg_portals, 1844255570Strasz p_next) { 1845255570Strasz if (strcmp(newp->p_listen, 1846255570Strasz oldp->p_listen) == 0 && 1847255570Strasz oldp->p_socket > 0) { 1848255570Strasz newp->p_socket = 1849255570Strasz oldp->p_socket; 1850255570Strasz oldp->p_socket = 0; 1851255570Strasz break; 1852255570Strasz } 1853255570Strasz } 1854255570Strasz } 1855255570Strasz if (newp->p_socket > 0) { 1856255570Strasz /* 1857255570Strasz * We're done with this portal. 1858255570Strasz */ 1859255570Strasz continue; 1860255570Strasz } 1861255570Strasz 1862255570Strasz#ifdef ICL_KERNEL_PROXY 1863265507Strasz if (proxy_mode) { 1864265509Strasz newpg->pg_conf->conf_portal_id++; 1865265509Strasz newp->p_id = newpg->pg_conf->conf_portal_id; 1866265509Strasz log_debugx("listening on %s, portal-group " 1867265509Strasz "\"%s\", portal id %d, using ICL proxy", 1868265509Strasz newp->p_listen, newpg->pg_name, newp->p_id); 1869265509Strasz kernel_listen(newp->p_ai, newp->p_iser, 1870265509Strasz newp->p_id); 1871265507Strasz continue; 1872265507Strasz } 1873265507Strasz#endif 1874265507Strasz assert(proxy_mode == false); 1875255570Strasz assert(newp->p_iser == false); 1876255570Strasz 1877255570Strasz log_debugx("listening on %s, portal-group \"%s\"", 1878255570Strasz newp->p_listen, newpg->pg_name); 1879255570Strasz newp->p_socket = socket(newp->p_ai->ai_family, 1880255570Strasz newp->p_ai->ai_socktype, 1881255570Strasz newp->p_ai->ai_protocol); 1882255570Strasz if (newp->p_socket < 0) { 1883255570Strasz log_warn("socket(2) failed for %s", 1884255570Strasz newp->p_listen); 1885255570Strasz cumulated_error++; 1886255570Strasz continue; 1887255570Strasz } 1888279001Smav sockbuf = SOCKBUF_SIZE; 1889279001Smav if (setsockopt(newp->p_socket, SOL_SOCKET, SO_RCVBUF, 1890279001Smav &sockbuf, sizeof(sockbuf)) == -1) 1891279001Smav log_warn("setsockopt(SO_RCVBUF) failed " 1892279001Smav "for %s", newp->p_listen); 1893279001Smav sockbuf = SOCKBUF_SIZE; 1894279001Smav if (setsockopt(newp->p_socket, SOL_SOCKET, SO_SNDBUF, 1895279001Smav &sockbuf, sizeof(sockbuf)) == -1) 1896279001Smav log_warn("setsockopt(SO_SNDBUF) failed " 1897279001Smav "for %s", newp->p_listen); 1898255570Strasz error = setsockopt(newp->p_socket, SOL_SOCKET, 1899255570Strasz SO_REUSEADDR, &one, sizeof(one)); 1900255570Strasz if (error != 0) { 1901255570Strasz log_warn("setsockopt(SO_REUSEADDR) failed " 1902255570Strasz "for %s", newp->p_listen); 1903255570Strasz close(newp->p_socket); 1904255570Strasz newp->p_socket = 0; 1905255570Strasz cumulated_error++; 1906255570Strasz continue; 1907255570Strasz } 1908255570Strasz error = bind(newp->p_socket, newp->p_ai->ai_addr, 1909255570Strasz newp->p_ai->ai_addrlen); 1910255570Strasz if (error != 0) { 1911255570Strasz log_warn("bind(2) failed for %s", 1912255570Strasz newp->p_listen); 1913255570Strasz close(newp->p_socket); 1914255570Strasz newp->p_socket = 0; 1915255570Strasz cumulated_error++; 1916255570Strasz continue; 1917255570Strasz } 1918255570Strasz error = listen(newp->p_socket, -1); 1919255570Strasz if (error != 0) { 1920255570Strasz log_warn("listen(2) failed for %s", 1921255570Strasz newp->p_listen); 1922255570Strasz close(newp->p_socket); 1923255570Strasz newp->p_socket = 0; 1924255570Strasz cumulated_error++; 1925255570Strasz continue; 1926255570Strasz } 1927255570Strasz } 1928255570Strasz } 1929255570Strasz 1930255570Strasz /* 1931255570Strasz * Go through the no longer used sockets, closing them. 1932255570Strasz */ 1933255570Strasz TAILQ_FOREACH(oldpg, &oldconf->conf_portal_groups, pg_next) { 1934255570Strasz TAILQ_FOREACH(oldp, &oldpg->pg_portals, p_next) { 1935255570Strasz if (oldp->p_socket <= 0) 1936255570Strasz continue; 1937255570Strasz log_debugx("closing socket for %s, portal-group \"%s\"", 1938255570Strasz oldp->p_listen, oldpg->pg_name); 1939255570Strasz close(oldp->p_socket); 1940255570Strasz oldp->p_socket = 0; 1941255570Strasz } 1942255570Strasz } 1943255570Strasz 1944274939Smav /* (Re-)Register on remaining/new iSNS servers. */ 1945274939Smav TAILQ_FOREACH(newns, &newconf->conf_isns, i_next) { 1946274939Smav TAILQ_FOREACH(oldns, &oldconf->conf_isns, i_next) { 1947274939Smav if (strcmp(oldns->i_addr, newns->i_addr) == 0) 1948274939Smav break; 1949274939Smav } 1950274939Smav isns_register(newns, oldns); 1951274939Smav } 1952274939Smav 1953274939Smav /* Schedule iSNS update */ 1954274939Smav if (!TAILQ_EMPTY(&newconf->conf_isns)) 1955274939Smav set_timeout((newconf->conf_isns_period + 2) / 3, false); 1956274939Smav 1957255570Strasz return (cumulated_error); 1958255570Strasz} 1959255570Strasz 1960255570Straszbool 1961255570Strasztimed_out(void) 1962255570Strasz{ 1963255570Strasz 1964255570Strasz return (sigalrm_received); 1965255570Strasz} 1966255570Strasz 1967255570Straszstatic void 1968274939Smavsigalrm_handler_fatal(int dummy __unused) 1969255570Strasz{ 1970255570Strasz /* 1971255570Strasz * It would be easiest to just log an error and exit. We can't 1972255570Strasz * do this, though, because log_errx() is not signal safe, since 1973255570Strasz * it calls syslog(3). Instead, set a flag checked by pdu_send() 1974255570Strasz * and pdu_receive(), to call log_errx() there. Should they fail 1975255570Strasz * to notice, we'll exit here one second later. 1976255570Strasz */ 1977255570Strasz if (sigalrm_received) { 1978255570Strasz /* 1979255570Strasz * Oh well. Just give up and quit. 1980255570Strasz */ 1981255570Strasz _exit(2); 1982255570Strasz } 1983255570Strasz 1984255570Strasz sigalrm_received = true; 1985255570Strasz} 1986255570Strasz 1987255570Straszstatic void 1988274939Smavsigalrm_handler(int dummy __unused) 1989255570Strasz{ 1990274939Smav 1991274939Smav sigalrm_received = true; 1992274939Smav} 1993274939Smav 1994274939Smavvoid 1995274939Smavset_timeout(int timeout, int fatal) 1996274939Smav{ 1997255570Strasz struct sigaction sa; 1998255570Strasz struct itimerval itv; 1999255570Strasz int error; 2000255570Strasz 2001274939Smav if (timeout <= 0) { 2002255570Strasz log_debugx("session timeout disabled"); 2003274939Smav bzero(&itv, sizeof(itv)); 2004274939Smav error = setitimer(ITIMER_REAL, &itv, NULL); 2005274939Smav if (error != 0) 2006274939Smav log_err(1, "setitimer"); 2007274939Smav sigalrm_received = false; 2008255570Strasz return; 2009255570Strasz } 2010255570Strasz 2011274939Smav sigalrm_received = false; 2012255570Strasz bzero(&sa, sizeof(sa)); 2013274939Smav if (fatal) 2014274939Smav sa.sa_handler = sigalrm_handler_fatal; 2015274939Smav else 2016274939Smav sa.sa_handler = sigalrm_handler; 2017255570Strasz sigfillset(&sa.sa_mask); 2018255570Strasz error = sigaction(SIGALRM, &sa, NULL); 2019255570Strasz if (error != 0) 2020255570Strasz log_err(1, "sigaction"); 2021255570Strasz 2022255570Strasz /* 2023255570Strasz * First SIGALRM will arive after conf_timeout seconds. 2024255570Strasz * If we do nothing, another one will arrive a second later. 2025255570Strasz */ 2026274939Smav log_debugx("setting session timeout to %d seconds", timeout); 2027255570Strasz bzero(&itv, sizeof(itv)); 2028255570Strasz itv.it_interval.tv_sec = 1; 2029274939Smav itv.it_value.tv_sec = timeout; 2030255570Strasz error = setitimer(ITIMER_REAL, &itv, NULL); 2031255570Strasz if (error != 0) 2032255570Strasz log_err(1, "setitimer"); 2033255570Strasz} 2034255570Strasz 2035255570Straszstatic int 2036255570Straszwait_for_children(bool block) 2037255570Strasz{ 2038255570Strasz pid_t pid; 2039255570Strasz int status; 2040255570Strasz int num = 0; 2041255570Strasz 2042255570Strasz for (;;) { 2043255570Strasz /* 2044255570Strasz * If "block" is true, wait for at least one process. 2045255570Strasz */ 2046255570Strasz if (block && num == 0) 2047255570Strasz pid = wait4(-1, &status, 0, NULL); 2048255570Strasz else 2049255570Strasz pid = wait4(-1, &status, WNOHANG, NULL); 2050255570Strasz if (pid <= 0) 2051255570Strasz break; 2052255570Strasz if (WIFSIGNALED(status)) { 2053255570Strasz log_warnx("child process %d terminated with signal %d", 2054255570Strasz pid, WTERMSIG(status)); 2055255570Strasz } else if (WEXITSTATUS(status) != 0) { 2056255570Strasz log_warnx("child process %d terminated with exit status %d", 2057255570Strasz pid, WEXITSTATUS(status)); 2058255570Strasz } else { 2059255570Strasz log_debugx("child process %d terminated gracefully", pid); 2060255570Strasz } 2061255570Strasz num++; 2062255570Strasz } 2063255570Strasz 2064255570Strasz return (num); 2065255570Strasz} 2066255570Strasz 2067255570Straszstatic void 2068265513Straszhandle_connection(struct portal *portal, int fd, 2069270137Smav const struct sockaddr *client_sa, bool dont_fork) 2070255570Strasz{ 2071255570Strasz struct connection *conn; 2072255570Strasz int error; 2073255570Strasz pid_t pid; 2074255570Strasz char host[NI_MAXHOST + 1]; 2075255570Strasz struct conf *conf; 2076255570Strasz 2077255570Strasz conf = portal->p_portal_group->pg_conf; 2078255570Strasz 2079255570Strasz if (dont_fork) { 2080255570Strasz log_debugx("incoming connection; not forking due to -d flag"); 2081255570Strasz } else { 2082255570Strasz nchildren -= wait_for_children(false); 2083255570Strasz assert(nchildren >= 0); 2084255570Strasz 2085255570Strasz while (conf->conf_maxproc > 0 && nchildren >= conf->conf_maxproc) { 2086255570Strasz log_debugx("maxproc limit of %d child processes hit; " 2087255570Strasz "waiting for child process to exit", conf->conf_maxproc); 2088255570Strasz nchildren -= wait_for_children(true); 2089255570Strasz assert(nchildren >= 0); 2090255570Strasz } 2091255570Strasz log_debugx("incoming connection; forking child process #%d", 2092255570Strasz nchildren); 2093255570Strasz nchildren++; 2094255570Strasz pid = fork(); 2095255570Strasz if (pid < 0) 2096255570Strasz log_err(1, "fork"); 2097255570Strasz if (pid > 0) { 2098255570Strasz close(fd); 2099255570Strasz return; 2100255570Strasz } 2101255570Strasz } 2102255570Strasz pidfile_close(conf->conf_pidfh); 2103255570Strasz 2104270137Smav error = getnameinfo(client_sa, client_sa->sa_len, 2105265513Strasz host, sizeof(host), NULL, 0, NI_NUMERICHOST); 2106265513Strasz if (error != 0) 2107265513Strasz log_errx(1, "getnameinfo: %s", gai_strerror(error)); 2108255570Strasz 2109265513Strasz log_debugx("accepted connection from %s; portal group \"%s\"", 2110265513Strasz host, portal->p_portal_group->pg_name); 2111265513Strasz log_set_peer_addr(host); 2112265513Strasz setproctitle("%s", host); 2113255570Strasz 2114270137Smav conn = connection_new(portal, fd, host, client_sa); 2115274939Smav set_timeout(conf->conf_timeout, true); 2116255570Strasz kernel_capsicate(); 2117255570Strasz login(conn); 2118255570Strasz if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) { 2119255570Strasz kernel_handoff(conn); 2120255570Strasz log_debugx("connection handed off to the kernel"); 2121255570Strasz } else { 2122255570Strasz assert(conn->conn_session_type == CONN_SESSION_TYPE_DISCOVERY); 2123255570Strasz discovery(conn); 2124255570Strasz } 2125255570Strasz log_debugx("nothing more to do; exiting"); 2126255570Strasz exit(0); 2127255570Strasz} 2128255570Strasz 2129255570Straszstatic int 2130255570Straszfd_add(int fd, fd_set *fdset, int nfds) 2131255570Strasz{ 2132255570Strasz 2133255570Strasz /* 2134255570Strasz * Skip sockets which we failed to bind. 2135255570Strasz */ 2136255570Strasz if (fd <= 0) 2137255570Strasz return (nfds); 2138255570Strasz 2139255570Strasz FD_SET(fd, fdset); 2140255570Strasz if (fd > nfds) 2141255570Strasz nfds = fd; 2142255570Strasz return (nfds); 2143255570Strasz} 2144255570Strasz 2145255570Straszstatic void 2146255570Straszmain_loop(struct conf *conf, bool dont_fork) 2147255570Strasz{ 2148255570Strasz struct portal_group *pg; 2149255570Strasz struct portal *portal; 2150265512Strasz struct sockaddr_storage client_sa; 2151265512Strasz socklen_t client_salen; 2152255570Strasz#ifdef ICL_KERNEL_PROXY 2153255570Strasz int connection_id; 2154265509Strasz int portal_id; 2155265507Strasz#endif 2156255570Strasz fd_set fdset; 2157255570Strasz int error, nfds, client_fd; 2158255570Strasz 2159255570Strasz pidfile_write(conf->conf_pidfh); 2160255570Strasz 2161255570Strasz for (;;) { 2162274939Smav if (sighup_received || sigterm_received || timed_out()) 2163255570Strasz return; 2164255570Strasz 2165255570Strasz#ifdef ICL_KERNEL_PROXY 2166265507Strasz if (proxy_mode) { 2167265513Strasz client_salen = sizeof(client_sa); 2168265513Strasz kernel_accept(&connection_id, &portal_id, 2169265513Strasz (struct sockaddr *)&client_sa, &client_salen); 2170271627Strasz assert(client_salen >= client_sa.ss_len); 2171255570Strasz 2172265509Strasz log_debugx("incoming connection, id %d, portal id %d", 2173265509Strasz connection_id, portal_id); 2174265509Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 2175265509Strasz TAILQ_FOREACH(portal, &pg->pg_portals, p_next) { 2176265509Strasz if (portal->p_id == portal_id) { 2177265509Strasz goto found; 2178265509Strasz } 2179265509Strasz } 2180265509Strasz } 2181255570Strasz 2182265509Strasz log_errx(1, "kernel returned invalid portal_id %d", 2183265509Strasz portal_id); 2184265509Strasz 2185265509Straszfound: 2186265513Strasz handle_connection(portal, connection_id, 2187270137Smav (struct sockaddr *)&client_sa, dont_fork); 2188265507Strasz } else { 2189265507Strasz#endif 2190265507Strasz assert(proxy_mode == false); 2191265507Strasz 2192265507Strasz FD_ZERO(&fdset); 2193265507Strasz nfds = 0; 2194265507Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 2195265507Strasz TAILQ_FOREACH(portal, &pg->pg_portals, p_next) 2196265507Strasz nfds = fd_add(portal->p_socket, &fdset, nfds); 2197255570Strasz } 2198265507Strasz error = select(nfds + 1, &fdset, NULL, NULL, NULL); 2199265507Strasz if (error <= 0) { 2200265507Strasz if (errno == EINTR) 2201265507Strasz return; 2202265507Strasz log_err(1, "select"); 2203265507Strasz } 2204265507Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 2205265507Strasz TAILQ_FOREACH(portal, &pg->pg_portals, p_next) { 2206265507Strasz if (!FD_ISSET(portal->p_socket, &fdset)) 2207265507Strasz continue; 2208265512Strasz client_salen = sizeof(client_sa); 2209265512Strasz client_fd = accept(portal->p_socket, 2210265512Strasz (struct sockaddr *)&client_sa, 2211265512Strasz &client_salen); 2212265507Strasz if (client_fd < 0) 2213265507Strasz log_err(1, "accept"); 2214271627Strasz assert(client_salen >= client_sa.ss_len); 2215271627Strasz 2216265512Strasz handle_connection(portal, client_fd, 2217265513Strasz (struct sockaddr *)&client_sa, 2218270137Smav dont_fork); 2219265507Strasz break; 2220265507Strasz } 2221265507Strasz } 2222265507Strasz#ifdef ICL_KERNEL_PROXY 2223255570Strasz } 2224265507Strasz#endif 2225255570Strasz } 2226255570Strasz} 2227255570Strasz 2228255570Straszstatic void 2229255570Straszsighup_handler(int dummy __unused) 2230255570Strasz{ 2231255570Strasz 2232255570Strasz sighup_received = true; 2233255570Strasz} 2234255570Strasz 2235255570Straszstatic void 2236255570Straszsigterm_handler(int dummy __unused) 2237255570Strasz{ 2238255570Strasz 2239255570Strasz sigterm_received = true; 2240255570Strasz} 2241255570Strasz 2242255570Straszstatic void 2243263730Straszsigchld_handler(int dummy __unused) 2244263730Strasz{ 2245263730Strasz 2246263730Strasz /* 2247263730Strasz * The only purpose of this handler is to make SIGCHLD 2248263730Strasz * interrupt the ISCSIDWAIT ioctl(2), so we can call 2249263730Strasz * wait_for_children(). 2250263730Strasz */ 2251263730Strasz} 2252263730Strasz 2253263730Straszstatic void 2254255570Straszregister_signals(void) 2255255570Strasz{ 2256255570Strasz struct sigaction sa; 2257255570Strasz int error; 2258255570Strasz 2259255570Strasz bzero(&sa, sizeof(sa)); 2260255570Strasz sa.sa_handler = sighup_handler; 2261255570Strasz sigfillset(&sa.sa_mask); 2262255570Strasz error = sigaction(SIGHUP, &sa, NULL); 2263255570Strasz if (error != 0) 2264255570Strasz log_err(1, "sigaction"); 2265255570Strasz 2266255570Strasz sa.sa_handler = sigterm_handler; 2267255570Strasz error = sigaction(SIGTERM, &sa, NULL); 2268255570Strasz if (error != 0) 2269255570Strasz log_err(1, "sigaction"); 2270255570Strasz 2271255570Strasz sa.sa_handler = sigterm_handler; 2272255570Strasz error = sigaction(SIGINT, &sa, NULL); 2273255570Strasz if (error != 0) 2274255570Strasz log_err(1, "sigaction"); 2275263730Strasz 2276263730Strasz sa.sa_handler = sigchld_handler; 2277263730Strasz error = sigaction(SIGCHLD, &sa, NULL); 2278263730Strasz if (error != 0) 2279263730Strasz log_err(1, "sigaction"); 2280255570Strasz} 2281255570Strasz 2282255570Straszint 2283255570Straszmain(int argc, char **argv) 2284255570Strasz{ 2285255570Strasz struct conf *oldconf, *newconf, *tmpconf; 2286274939Smav struct isns *newns; 2287255570Strasz const char *config_path = DEFAULT_CONFIG_PATH; 2288255570Strasz int debug = 0, ch, error; 2289255570Strasz bool dont_daemonize = false; 2290255570Strasz 2291265507Strasz while ((ch = getopt(argc, argv, "df:R")) != -1) { 2292255570Strasz switch (ch) { 2293255570Strasz case 'd': 2294255570Strasz dont_daemonize = true; 2295255570Strasz debug++; 2296255570Strasz break; 2297255570Strasz case 'f': 2298255570Strasz config_path = optarg; 2299255570Strasz break; 2300265507Strasz case 'R': 2301265507Strasz#ifndef ICL_KERNEL_PROXY 2302265507Strasz log_errx(1, "ctld(8) compiled without ICL_KERNEL_PROXY " 2303265507Strasz "does not support iSER protocol"); 2304265507Strasz#endif 2305265507Strasz proxy_mode = true; 2306265507Strasz break; 2307255570Strasz case '?': 2308255570Strasz default: 2309255570Strasz usage(); 2310255570Strasz } 2311255570Strasz } 2312255570Strasz argc -= optind; 2313255570Strasz if (argc != 0) 2314255570Strasz usage(); 2315255570Strasz 2316255570Strasz log_init(debug); 2317255570Strasz kernel_init(); 2318255570Strasz 2319255570Strasz oldconf = conf_new_from_kernel(); 2320255570Strasz newconf = conf_new_from_file(config_path); 2321255570Strasz if (newconf == NULL) 2322265516Strasz log_errx(1, "configuration error; exiting"); 2323255570Strasz if (debug > 0) { 2324255570Strasz oldconf->conf_debug = debug; 2325255570Strasz newconf->conf_debug = debug; 2326255570Strasz } 2327255570Strasz 2328255570Strasz error = conf_apply(oldconf, newconf); 2329255570Strasz if (error != 0) 2330265516Strasz log_errx(1, "failed to apply configuration; exiting"); 2331265516Strasz 2332255570Strasz conf_delete(oldconf); 2333255570Strasz oldconf = NULL; 2334255570Strasz 2335255570Strasz register_signals(); 2336255570Strasz 2337263719Strasz if (dont_daemonize == false) { 2338263719Strasz log_debugx("daemonizing"); 2339263719Strasz if (daemon(0, 0) == -1) { 2340263719Strasz log_warn("cannot daemonize"); 2341263719Strasz pidfile_remove(newconf->conf_pidfh); 2342263719Strasz exit(1); 2343263719Strasz } 2344263719Strasz } 2345263719Strasz 2346274939Smav /* Schedule iSNS update */ 2347274939Smav if (!TAILQ_EMPTY(&newconf->conf_isns)) 2348274939Smav set_timeout((newconf->conf_isns_period + 2) / 3, false); 2349274939Smav 2350255570Strasz for (;;) { 2351255570Strasz main_loop(newconf, dont_daemonize); 2352255570Strasz if (sighup_received) { 2353255570Strasz sighup_received = false; 2354255570Strasz log_debugx("received SIGHUP, reloading configuration"); 2355255570Strasz tmpconf = conf_new_from_file(config_path); 2356255570Strasz if (tmpconf == NULL) { 2357255570Strasz log_warnx("configuration error, " 2358255570Strasz "continuing with old configuration"); 2359255570Strasz } else { 2360255570Strasz if (debug > 0) 2361255570Strasz tmpconf->conf_debug = debug; 2362255570Strasz oldconf = newconf; 2363255570Strasz newconf = tmpconf; 2364255570Strasz error = conf_apply(oldconf, newconf); 2365255570Strasz if (error != 0) 2366255570Strasz log_warnx("failed to reload " 2367255570Strasz "configuration"); 2368255570Strasz conf_delete(oldconf); 2369255570Strasz oldconf = NULL; 2370255570Strasz } 2371255570Strasz } else if (sigterm_received) { 2372255570Strasz log_debugx("exiting on signal; " 2373255570Strasz "reloading empty configuration"); 2374255570Strasz 2375255570Strasz log_debugx("disabling CTL iSCSI port " 2376255570Strasz "and terminating all connections"); 2377255570Strasz 2378255570Strasz oldconf = newconf; 2379255570Strasz newconf = conf_new(); 2380255570Strasz if (debug > 0) 2381255570Strasz newconf->conf_debug = debug; 2382255570Strasz error = conf_apply(oldconf, newconf); 2383255570Strasz if (error != 0) 2384255570Strasz log_warnx("failed to apply configuration"); 2385274939Smav conf_delete(oldconf); 2386274939Smav oldconf = NULL; 2387255570Strasz 2388255570Strasz log_warnx("exiting on signal"); 2389255570Strasz exit(0); 2390255570Strasz } else { 2391255570Strasz nchildren -= wait_for_children(false); 2392255570Strasz assert(nchildren >= 0); 2393274939Smav if (timed_out()) { 2394274939Smav set_timeout(0, false); 2395274939Smav TAILQ_FOREACH(newns, &newconf->conf_isns, i_next) 2396274939Smav isns_check(newns); 2397274939Smav /* Schedule iSNS update */ 2398274939Smav if (!TAILQ_EMPTY(&newconf->conf_isns)) { 2399274939Smav set_timeout((newconf->conf_isns_period 2400274939Smav + 2) / 3, 2401274939Smav false); 2402274939Smav } 2403274939Smav } 2404255570Strasz } 2405255570Strasz } 2406255570Strasz /* NOTREACHED */ 2407255570Strasz} 2408