ctld.c revision 275245
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 275245 2014-11-29 15:34:17Z trasz $"); 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"); 90255570Strasz TAILQ_INIT(&conf->conf_targets); 91255570Strasz TAILQ_INIT(&conf->conf_auth_groups); 92255570Strasz TAILQ_INIT(&conf->conf_portal_groups); 93274939Smav TAILQ_INIT(&conf->conf_isns); 94255570Strasz 95274939Smav conf->conf_isns_period = 900; 96274939Smav conf->conf_isns_timeout = 5; 97255570Strasz conf->conf_debug = 0; 98255570Strasz conf->conf_timeout = 60; 99255570Strasz conf->conf_maxproc = 30; 100255570Strasz 101255570Strasz return (conf); 102255570Strasz} 103255570Strasz 104255570Straszvoid 105255570Straszconf_delete(struct conf *conf) 106255570Strasz{ 107255570Strasz struct target *targ, *tmp; 108255570Strasz struct auth_group *ag, *cagtmp; 109255570Strasz struct portal_group *pg, *cpgtmp; 110274939Smav struct isns *is, *istmp; 111255570Strasz 112255570Strasz assert(conf->conf_pidfh == NULL); 113255570Strasz 114255570Strasz TAILQ_FOREACH_SAFE(targ, &conf->conf_targets, t_next, tmp) 115255570Strasz target_delete(targ); 116255570Strasz TAILQ_FOREACH_SAFE(ag, &conf->conf_auth_groups, ag_next, cagtmp) 117255570Strasz auth_group_delete(ag); 118255570Strasz TAILQ_FOREACH_SAFE(pg, &conf->conf_portal_groups, pg_next, cpgtmp) 119255570Strasz portal_group_delete(pg); 120274939Smav TAILQ_FOREACH_SAFE(is, &conf->conf_isns, i_next, istmp) 121274939Smav isns_delete(is); 122255570Strasz free(conf->conf_pidfile_path); 123255570Strasz free(conf); 124255570Strasz} 125255570Strasz 126255570Straszstatic struct auth * 127255570Straszauth_new(struct auth_group *ag) 128255570Strasz{ 129255570Strasz struct auth *auth; 130255570Strasz 131255570Strasz auth = calloc(1, sizeof(*auth)); 132255570Strasz if (auth == NULL) 133255570Strasz log_err(1, "calloc"); 134255570Strasz auth->a_auth_group = ag; 135255570Strasz TAILQ_INSERT_TAIL(&ag->ag_auths, auth, a_next); 136255570Strasz return (auth); 137255570Strasz} 138255570Strasz 139255570Straszstatic void 140255570Straszauth_delete(struct auth *auth) 141255570Strasz{ 142255570Strasz TAILQ_REMOVE(&auth->a_auth_group->ag_auths, auth, a_next); 143255570Strasz 144255570Strasz free(auth->a_user); 145255570Strasz free(auth->a_secret); 146255570Strasz free(auth->a_mutual_user); 147255570Strasz free(auth->a_mutual_secret); 148255570Strasz free(auth); 149255570Strasz} 150255570Strasz 151255570Straszconst struct auth * 152265514Straszauth_find(const struct auth_group *ag, const char *user) 153255570Strasz{ 154255570Strasz const struct auth *auth; 155255570Strasz 156255570Strasz TAILQ_FOREACH(auth, &ag->ag_auths, a_next) { 157255570Strasz if (strcmp(auth->a_user, user) == 0) 158255570Strasz return (auth); 159255570Strasz } 160255570Strasz 161255570Strasz return (NULL); 162255570Strasz} 163255570Strasz 164263721Straszstatic void 165263721Straszauth_check_secret_length(struct auth *auth) 166263721Strasz{ 167263721Strasz size_t len; 168263721Strasz 169263721Strasz len = strlen(auth->a_secret); 170263721Strasz if (len > 16) { 171263721Strasz if (auth->a_auth_group->ag_name != NULL) 172263721Strasz log_warnx("secret for user \"%s\", auth-group \"%s\", " 173263721Strasz "is too long; it should be at most 16 characters " 174263721Strasz "long", auth->a_user, auth->a_auth_group->ag_name); 175263721Strasz else 176263721Strasz log_warnx("secret for user \"%s\", target \"%s\", " 177263721Strasz "is too long; it should be at most 16 characters " 178263721Strasz "long", auth->a_user, 179263723Strasz auth->a_auth_group->ag_target->t_name); 180263721Strasz } 181263721Strasz if (len < 12) { 182263721Strasz if (auth->a_auth_group->ag_name != NULL) 183263721Strasz log_warnx("secret for user \"%s\", auth-group \"%s\", " 184263721Strasz "is too short; it should be at least 12 characters " 185263721Strasz "long", auth->a_user, 186263721Strasz auth->a_auth_group->ag_name); 187263721Strasz else 188263721Strasz log_warnx("secret for user \"%s\", target \"%s\", " 189263721Strasz "is too short; it should be at least 16 characters " 190263721Strasz "long", auth->a_user, 191263723Strasz auth->a_auth_group->ag_target->t_name); 192263721Strasz } 193263721Strasz 194263721Strasz if (auth->a_mutual_secret != NULL) { 195263721Strasz len = strlen(auth->a_secret); 196263721Strasz if (len > 16) { 197263721Strasz if (auth->a_auth_group->ag_name != NULL) 198263721Strasz log_warnx("mutual secret for user \"%s\", " 199263721Strasz "auth-group \"%s\", is too long; it should " 200263721Strasz "be at most 16 characters long", 201263721Strasz auth->a_user, auth->a_auth_group->ag_name); 202263721Strasz else 203263721Strasz log_warnx("mutual secret for user \"%s\", " 204263721Strasz "target \"%s\", is too long; it should " 205263721Strasz "be at most 16 characters long", 206263721Strasz auth->a_user, 207263723Strasz auth->a_auth_group->ag_target->t_name); 208263721Strasz } 209263721Strasz if (len < 12) { 210263721Strasz if (auth->a_auth_group->ag_name != NULL) 211263721Strasz log_warnx("mutual secret for user \"%s\", " 212263721Strasz "auth-group \"%s\", is too short; it " 213263721Strasz "should be at least 12 characters long", 214263721Strasz auth->a_user, auth->a_auth_group->ag_name); 215263721Strasz else 216263721Strasz log_warnx("mutual secret for user \"%s\", " 217263721Strasz "target \"%s\", is too short; it should be " 218263721Strasz "at least 16 characters long", 219263721Strasz auth->a_user, 220263723Strasz auth->a_auth_group->ag_target->t_name); 221263721Strasz } 222263721Strasz } 223263721Strasz} 224263721Strasz 225263721Straszconst struct auth * 226263721Straszauth_new_chap(struct auth_group *ag, const char *user, 227263721Strasz const char *secret) 228263721Strasz{ 229263721Strasz struct auth *auth; 230263721Strasz 231263721Strasz if (ag->ag_type == AG_TYPE_UNKNOWN) 232263721Strasz ag->ag_type = AG_TYPE_CHAP; 233263721Strasz if (ag->ag_type != AG_TYPE_CHAP) { 234263721Strasz if (ag->ag_name != NULL) 235263721Strasz log_warnx("cannot mix \"chap\" authentication with " 236263721Strasz "other types for auth-group \"%s\"", ag->ag_name); 237263721Strasz else 238263721Strasz log_warnx("cannot mix \"chap\" authentication with " 239263721Strasz "other types for target \"%s\"", 240263723Strasz ag->ag_target->t_name); 241263721Strasz return (NULL); 242263721Strasz } 243263721Strasz 244263721Strasz auth = auth_new(ag); 245263721Strasz auth->a_user = checked_strdup(user); 246263721Strasz auth->a_secret = checked_strdup(secret); 247263721Strasz 248263721Strasz auth_check_secret_length(auth); 249263721Strasz 250263721Strasz return (auth); 251263721Strasz} 252263721Strasz 253263721Straszconst struct auth * 254263721Straszauth_new_chap_mutual(struct auth_group *ag, const char *user, 255263721Strasz const char *secret, const char *user2, const char *secret2) 256263721Strasz{ 257263721Strasz struct auth *auth; 258263721Strasz 259263721Strasz if (ag->ag_type == AG_TYPE_UNKNOWN) 260263721Strasz ag->ag_type = AG_TYPE_CHAP_MUTUAL; 261263721Strasz if (ag->ag_type != AG_TYPE_CHAP_MUTUAL) { 262263721Strasz if (ag->ag_name != NULL) 263263721Strasz log_warnx("cannot mix \"chap-mutual\" authentication " 264263721Strasz "with other types for auth-group \"%s\"", 265274870Strasz ag->ag_name); 266263721Strasz else 267263721Strasz log_warnx("cannot mix \"chap-mutual\" authentication " 268263721Strasz "with other types for target \"%s\"", 269263723Strasz ag->ag_target->t_name); 270263721Strasz return (NULL); 271263721Strasz } 272263721Strasz 273263721Strasz auth = auth_new(ag); 274263721Strasz auth->a_user = checked_strdup(user); 275263721Strasz auth->a_secret = checked_strdup(secret); 276263721Strasz auth->a_mutual_user = checked_strdup(user2); 277263721Strasz auth->a_mutual_secret = checked_strdup(secret2); 278263721Strasz 279263721Strasz auth_check_secret_length(auth); 280263721Strasz 281263721Strasz return (auth); 282263721Strasz} 283263721Strasz 284263720Straszconst struct auth_name * 285263720Straszauth_name_new(struct auth_group *ag, const char *name) 286263720Strasz{ 287263720Strasz struct auth_name *an; 288263720Strasz 289263720Strasz an = calloc(1, sizeof(*an)); 290263720Strasz if (an == NULL) 291263720Strasz log_err(1, "calloc"); 292263720Strasz an->an_auth_group = ag; 293263720Strasz an->an_initator_name = checked_strdup(name); 294263720Strasz TAILQ_INSERT_TAIL(&ag->ag_names, an, an_next); 295263720Strasz return (an); 296263720Strasz} 297263720Strasz 298263720Straszstatic void 299263720Straszauth_name_delete(struct auth_name *an) 300263720Strasz{ 301263720Strasz TAILQ_REMOVE(&an->an_auth_group->ag_names, an, an_next); 302263720Strasz 303263720Strasz free(an->an_initator_name); 304263720Strasz free(an); 305263720Strasz} 306263720Strasz 307263720Straszbool 308263720Straszauth_name_defined(const struct auth_group *ag) 309263720Strasz{ 310263720Strasz if (TAILQ_EMPTY(&ag->ag_names)) 311263720Strasz return (false); 312263720Strasz return (true); 313263720Strasz} 314263720Strasz 315263720Straszconst struct auth_name * 316263720Straszauth_name_find(const struct auth_group *ag, const char *name) 317263720Strasz{ 318263720Strasz const struct auth_name *auth_name; 319263720Strasz 320263720Strasz TAILQ_FOREACH(auth_name, &ag->ag_names, an_next) { 321263720Strasz if (strcmp(auth_name->an_initator_name, name) == 0) 322263720Strasz return (auth_name); 323263720Strasz } 324263720Strasz 325263720Strasz return (NULL); 326263720Strasz} 327263720Strasz 328274949Straszint 329274949Straszauth_name_check(const struct auth_group *ag, const char *initiator_name) 330274949Strasz{ 331274949Strasz if (!auth_name_defined(ag)) 332274949Strasz return (0); 333274949Strasz 334274949Strasz if (auth_name_find(ag, initiator_name) == NULL) 335274949Strasz return (1); 336274949Strasz 337274949Strasz return (0); 338274949Strasz} 339274949Strasz 340263720Straszconst struct auth_portal * 341263720Straszauth_portal_new(struct auth_group *ag, const char *portal) 342263720Strasz{ 343263720Strasz struct auth_portal *ap; 344270137Smav char *net, *mask, *str, *tmp; 345270137Smav int len, dm, m; 346263720Strasz 347263720Strasz ap = calloc(1, sizeof(*ap)); 348263720Strasz if (ap == NULL) 349263720Strasz log_err(1, "calloc"); 350263720Strasz ap->ap_auth_group = ag; 351263720Strasz ap->ap_initator_portal = checked_strdup(portal); 352270137Smav mask = str = checked_strdup(portal); 353270137Smav net = strsep(&mask, "/"); 354270137Smav if (net[0] == '[') 355270137Smav net++; 356270137Smav len = strlen(net); 357270137Smav if (len == 0) 358270137Smav goto error; 359270137Smav if (net[len - 1] == ']') 360270137Smav net[len - 1] = 0; 361270137Smav if (strchr(net, ':') != NULL) { 362270137Smav struct sockaddr_in6 *sin6 = 363270137Smav (struct sockaddr_in6 *)&ap->ap_sa; 364270137Smav 365270137Smav sin6->sin6_len = sizeof(*sin6); 366270137Smav sin6->sin6_family = AF_INET6; 367270137Smav if (inet_pton(AF_INET6, net, &sin6->sin6_addr) <= 0) 368270137Smav goto error; 369270137Smav dm = 128; 370270137Smav } else { 371270137Smav struct sockaddr_in *sin = 372270137Smav (struct sockaddr_in *)&ap->ap_sa; 373270137Smav 374270137Smav sin->sin_len = sizeof(*sin); 375270137Smav sin->sin_family = AF_INET; 376270137Smav if (inet_pton(AF_INET, net, &sin->sin_addr) <= 0) 377270137Smav goto error; 378270137Smav dm = 32; 379270137Smav } 380270137Smav if (mask != NULL) { 381270137Smav m = strtol(mask, &tmp, 0); 382270137Smav if (m < 0 || m > dm || tmp[0] != 0) 383270137Smav goto error; 384270137Smav } else 385270137Smav m = dm; 386270137Smav ap->ap_mask = m; 387270137Smav free(str); 388263720Strasz TAILQ_INSERT_TAIL(&ag->ag_portals, ap, ap_next); 389263720Strasz return (ap); 390270137Smav 391270137Smaverror: 392270137Smav log_errx(1, "Incorrect initiator portal '%s'", portal); 393270137Smav return (NULL); 394263720Strasz} 395263720Strasz 396263720Straszstatic void 397263720Straszauth_portal_delete(struct auth_portal *ap) 398263720Strasz{ 399263720Strasz TAILQ_REMOVE(&ap->ap_auth_group->ag_portals, ap, ap_next); 400263720Strasz 401263720Strasz free(ap->ap_initator_portal); 402263720Strasz free(ap); 403263720Strasz} 404263720Strasz 405263720Straszbool 406263720Straszauth_portal_defined(const struct auth_group *ag) 407263720Strasz{ 408263720Strasz if (TAILQ_EMPTY(&ag->ag_portals)) 409263720Strasz return (false); 410263720Strasz return (true); 411263720Strasz} 412263720Strasz 413263720Straszconst struct auth_portal * 414270137Smavauth_portal_find(const struct auth_group *ag, const struct sockaddr_storage *ss) 415263720Strasz{ 416270137Smav const struct auth_portal *ap; 417270137Smav const uint8_t *a, *b; 418270137Smav int i; 419270137Smav uint8_t bmask; 420263720Strasz 421270137Smav TAILQ_FOREACH(ap, &ag->ag_portals, ap_next) { 422270137Smav if (ap->ap_sa.ss_family != ss->ss_family) 423270137Smav continue; 424270137Smav if (ss->ss_family == AF_INET) { 425270137Smav a = (const uint8_t *) 426270137Smav &((const struct sockaddr_in *)ss)->sin_addr; 427270137Smav b = (const uint8_t *) 428270137Smav &((const struct sockaddr_in *)&ap->ap_sa)->sin_addr; 429270137Smav } else { 430270137Smav a = (const uint8_t *) 431270137Smav &((const struct sockaddr_in6 *)ss)->sin6_addr; 432270137Smav b = (const uint8_t *) 433270137Smav &((const struct sockaddr_in6 *)&ap->ap_sa)->sin6_addr; 434270137Smav } 435270137Smav for (i = 0; i < ap->ap_mask / 8; i++) { 436270137Smav if (a[i] != b[i]) 437270137Smav goto next; 438270137Smav } 439270137Smav if (ap->ap_mask % 8) { 440270137Smav bmask = 0xff << (8 - (ap->ap_mask % 8)); 441270137Smav if ((a[i] & bmask) != (b[i] & bmask)) 442270137Smav goto next; 443270137Smav } 444270137Smav return (ap); 445270137Smavnext: 446270137Smav ; 447263720Strasz } 448263720Strasz 449263720Strasz return (NULL); 450263720Strasz} 451263720Strasz 452274949Straszint 453274949Straszauth_portal_check(const struct auth_group *ag, const struct sockaddr_storage *sa) 454274949Strasz{ 455274949Strasz 456274949Strasz if (!auth_portal_defined(ag)) 457274949Strasz return (0); 458274949Strasz 459274949Strasz if (auth_portal_find(ag, sa) == NULL) 460274949Strasz return (1); 461274949Strasz 462274949Strasz return (0); 463274949Strasz} 464274949Strasz 465255570Straszstruct auth_group * 466255570Straszauth_group_new(struct conf *conf, const char *name) 467255570Strasz{ 468255570Strasz struct auth_group *ag; 469255570Strasz 470255570Strasz if (name != NULL) { 471255570Strasz ag = auth_group_find(conf, name); 472255570Strasz if (ag != NULL) { 473255570Strasz log_warnx("duplicated auth-group \"%s\"", name); 474255570Strasz return (NULL); 475255570Strasz } 476255570Strasz } 477255570Strasz 478255570Strasz ag = calloc(1, sizeof(*ag)); 479255570Strasz if (ag == NULL) 480255570Strasz log_err(1, "calloc"); 481255570Strasz if (name != NULL) 482255570Strasz ag->ag_name = checked_strdup(name); 483255570Strasz TAILQ_INIT(&ag->ag_auths); 484263720Strasz TAILQ_INIT(&ag->ag_names); 485263720Strasz TAILQ_INIT(&ag->ag_portals); 486255570Strasz ag->ag_conf = conf; 487255570Strasz TAILQ_INSERT_TAIL(&conf->conf_auth_groups, ag, ag_next); 488255570Strasz 489255570Strasz return (ag); 490255570Strasz} 491255570Strasz 492255570Straszvoid 493255570Straszauth_group_delete(struct auth_group *ag) 494255570Strasz{ 495263720Strasz struct auth *auth, *auth_tmp; 496263720Strasz struct auth_name *auth_name, *auth_name_tmp; 497263720Strasz struct auth_portal *auth_portal, *auth_portal_tmp; 498255570Strasz 499255570Strasz TAILQ_REMOVE(&ag->ag_conf->conf_auth_groups, ag, ag_next); 500255570Strasz 501263720Strasz TAILQ_FOREACH_SAFE(auth, &ag->ag_auths, a_next, auth_tmp) 502255570Strasz auth_delete(auth); 503263720Strasz TAILQ_FOREACH_SAFE(auth_name, &ag->ag_names, an_next, auth_name_tmp) 504263720Strasz auth_name_delete(auth_name); 505263720Strasz TAILQ_FOREACH_SAFE(auth_portal, &ag->ag_portals, ap_next, 506263720Strasz auth_portal_tmp) 507263720Strasz auth_portal_delete(auth_portal); 508255570Strasz free(ag->ag_name); 509255570Strasz free(ag); 510255570Strasz} 511255570Strasz 512255570Straszstruct auth_group * 513265514Straszauth_group_find(const struct conf *conf, const char *name) 514255570Strasz{ 515255570Strasz struct auth_group *ag; 516255570Strasz 517255570Strasz TAILQ_FOREACH(ag, &conf->conf_auth_groups, ag_next) { 518255570Strasz if (ag->ag_name != NULL && strcmp(ag->ag_name, name) == 0) 519255570Strasz return (ag); 520255570Strasz } 521255570Strasz 522255570Strasz return (NULL); 523255570Strasz} 524255570Strasz 525263724Straszint 526275245Straszauth_group_set_type(struct auth_group *ag, const char *str) 527263724Strasz{ 528275245Strasz int type; 529263724Strasz 530263724Strasz if (strcmp(str, "none") == 0) { 531263724Strasz type = AG_TYPE_NO_AUTHENTICATION; 532263729Strasz } else if (strcmp(str, "deny") == 0) { 533263729Strasz type = AG_TYPE_DENY; 534263724Strasz } else if (strcmp(str, "chap") == 0) { 535263724Strasz type = AG_TYPE_CHAP; 536263724Strasz } else if (strcmp(str, "chap-mutual") == 0) { 537263724Strasz type = AG_TYPE_CHAP_MUTUAL; 538263724Strasz } else { 539263724Strasz if (ag->ag_name != NULL) 540263724Strasz log_warnx("invalid auth-type \"%s\" for auth-group " 541263724Strasz "\"%s\"", str, ag->ag_name); 542263724Strasz else 543263724Strasz log_warnx("invalid auth-type \"%s\" for target " 544263724Strasz "\"%s\"", str, ag->ag_target->t_name); 545263724Strasz return (1); 546263724Strasz } 547263724Strasz 548275245Strasz if (ag->ag_type != AG_TYPE_UNKNOWN && ag->ag_type != type) { 549275245Strasz if (ag->ag_name != NULL) { 550263724Strasz log_warnx("cannot set auth-type to \"%s\" for " 551263724Strasz "auth-group \"%s\"; already has a different " 552263724Strasz "type", str, ag->ag_name); 553275245Strasz } else { 554263724Strasz log_warnx("cannot set auth-type to \"%s\" for target " 555263724Strasz "\"%s\"; already has a different type", 556263724Strasz str, ag->ag_target->t_name); 557275245Strasz } 558263724Strasz return (1); 559263724Strasz } 560263724Strasz 561275245Strasz ag->ag_type = type; 562275245Strasz 563275245Strasz return (0); 564263724Strasz} 565263724Strasz 566255570Straszstatic struct portal * 567255570Straszportal_new(struct portal_group *pg) 568255570Strasz{ 569255570Strasz struct portal *portal; 570255570Strasz 571255570Strasz portal = calloc(1, sizeof(*portal)); 572255570Strasz if (portal == NULL) 573255570Strasz log_err(1, "calloc"); 574255570Strasz TAILQ_INIT(&portal->p_targets); 575255570Strasz portal->p_portal_group = pg; 576255570Strasz TAILQ_INSERT_TAIL(&pg->pg_portals, portal, p_next); 577255570Strasz return (portal); 578255570Strasz} 579255570Strasz 580255570Straszstatic void 581255570Straszportal_delete(struct portal *portal) 582255570Strasz{ 583271632Strasz 584255570Strasz TAILQ_REMOVE(&portal->p_portal_group->pg_portals, portal, p_next); 585271632Strasz if (portal->p_ai != NULL) 586271632Strasz freeaddrinfo(portal->p_ai); 587255570Strasz free(portal->p_listen); 588255570Strasz free(portal); 589255570Strasz} 590255570Strasz 591255570Straszstruct portal_group * 592255570Straszportal_group_new(struct conf *conf, const char *name) 593255570Strasz{ 594255570Strasz struct portal_group *pg; 595255570Strasz 596255678Strasz pg = portal_group_find(conf, name); 597255678Strasz if (pg != NULL) { 598255678Strasz log_warnx("duplicated portal-group \"%s\"", name); 599255678Strasz return (NULL); 600255570Strasz } 601255570Strasz 602255570Strasz pg = calloc(1, sizeof(*pg)); 603255570Strasz if (pg == NULL) 604255570Strasz log_err(1, "calloc"); 605255570Strasz pg->pg_name = checked_strdup(name); 606255570Strasz TAILQ_INIT(&pg->pg_portals); 607255570Strasz pg->pg_conf = conf; 608255570Strasz conf->conf_last_portal_group_tag++; 609255570Strasz pg->pg_tag = conf->conf_last_portal_group_tag; 610255570Strasz TAILQ_INSERT_TAIL(&conf->conf_portal_groups, pg, pg_next); 611255570Strasz 612255570Strasz return (pg); 613255570Strasz} 614255570Strasz 615255570Straszvoid 616255570Straszportal_group_delete(struct portal_group *pg) 617255570Strasz{ 618255570Strasz struct portal *portal, *tmp; 619255570Strasz 620255570Strasz TAILQ_REMOVE(&pg->pg_conf->conf_portal_groups, pg, pg_next); 621255570Strasz 622255570Strasz TAILQ_FOREACH_SAFE(portal, &pg->pg_portals, p_next, tmp) 623255570Strasz portal_delete(portal); 624255570Strasz free(pg->pg_name); 625255570Strasz free(pg); 626255570Strasz} 627255570Strasz 628255570Straszstruct portal_group * 629265514Straszportal_group_find(const struct conf *conf, const char *name) 630255570Strasz{ 631255570Strasz struct portal_group *pg; 632255570Strasz 633255570Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 634255570Strasz if (strcmp(pg->pg_name, name) == 0) 635255570Strasz return (pg); 636255570Strasz } 637255570Strasz 638255570Strasz return (NULL); 639255570Strasz} 640255570Strasz 641274939Smavstatic int 642274939Smavparse_addr_port(char *arg, const char *def_port, struct addrinfo **ai) 643255570Strasz{ 644255570Strasz struct addrinfo hints; 645274939Smav char *addr, *ch; 646255570Strasz const char *port; 647255570Strasz int error, colons = 0; 648255570Strasz 649255570Strasz if (arg[0] == '[') { 650255570Strasz /* 651255570Strasz * IPv6 address in square brackets, perhaps with port. 652255570Strasz */ 653255570Strasz arg++; 654255570Strasz addr = strsep(&arg, "]"); 655274939Smav if (arg == NULL) 656255570Strasz return (1); 657255570Strasz if (arg[0] == '\0') { 658274939Smav port = def_port; 659255570Strasz } else if (arg[0] == ':') { 660255570Strasz port = arg + 1; 661274939Smav } else 662255570Strasz return (1); 663255570Strasz } else { 664255570Strasz /* 665255570Strasz * Either IPv6 address without brackets - and without 666255570Strasz * a port - or IPv4 address. Just count the colons. 667255570Strasz */ 668255570Strasz for (ch = arg; *ch != '\0'; ch++) { 669255570Strasz if (*ch == ':') 670255570Strasz colons++; 671255570Strasz } 672255570Strasz if (colons > 1) { 673255570Strasz addr = arg; 674274939Smav port = def_port; 675255570Strasz } else { 676255570Strasz addr = strsep(&arg, ":"); 677255570Strasz if (arg == NULL) 678274939Smav port = def_port; 679255570Strasz else 680255570Strasz port = arg; 681255570Strasz } 682255570Strasz } 683255570Strasz 684255570Strasz memset(&hints, 0, sizeof(hints)); 685255570Strasz hints.ai_family = PF_UNSPEC; 686255570Strasz hints.ai_socktype = SOCK_STREAM; 687255570Strasz hints.ai_flags = AI_PASSIVE; 688274939Smav error = getaddrinfo(addr, port, &hints, ai); 689274939Smav if (error != 0) 690274939Smav return (1); 691274939Smav return (0); 692274939Smav} 693255570Strasz 694274939Smavint 695274939Smavportal_group_add_listen(struct portal_group *pg, const char *value, bool iser) 696274939Smav{ 697274939Smav struct portal *portal; 698274939Smav 699274939Smav portal = portal_new(pg); 700274939Smav portal->p_listen = checked_strdup(value); 701274939Smav portal->p_iser = iser; 702274939Smav 703274939Smav if (parse_addr_port(portal->p_listen, "3260", &portal->p_ai)) { 704274939Smav log_warnx("invalid listen address %s", portal->p_listen); 705271632Strasz portal_delete(portal); 706255570Strasz return (1); 707255570Strasz } 708255570Strasz 709255570Strasz /* 710255570Strasz * XXX: getaddrinfo(3) may return multiple addresses; we should turn 711255570Strasz * those into multiple portals. 712255570Strasz */ 713255570Strasz 714255570Strasz return (0); 715255570Strasz} 716255570Strasz 717274939Smavint 718274939Smavisns_new(struct conf *conf, const char *addr) 719274939Smav{ 720274939Smav struct isns *isns; 721274939Smav 722274939Smav isns = calloc(1, sizeof(*isns)); 723274939Smav if (isns == NULL) 724274939Smav log_err(1, "calloc"); 725274939Smav isns->i_conf = conf; 726274939Smav TAILQ_INSERT_TAIL(&conf->conf_isns, isns, i_next); 727274939Smav isns->i_addr = checked_strdup(addr); 728274939Smav 729274939Smav if (parse_addr_port(isns->i_addr, "3205", &isns->i_ai)) { 730274939Smav log_warnx("invalid iSNS address %s", isns->i_addr); 731274939Smav isns_delete(isns); 732274939Smav return (1); 733274939Smav } 734274939Smav 735274939Smav /* 736274939Smav * XXX: getaddrinfo(3) may return multiple addresses; we should turn 737274939Smav * those into multiple servers. 738274939Smav */ 739274939Smav 740274939Smav return (0); 741274939Smav} 742274939Smav 743274939Smavvoid 744274939Smavisns_delete(struct isns *isns) 745274939Smav{ 746274939Smav 747274939Smav TAILQ_REMOVE(&isns->i_conf->conf_isns, isns, i_next); 748274939Smav free(isns->i_addr); 749274939Smav if (isns->i_ai != NULL) 750274939Smav freeaddrinfo(isns->i_ai); 751274939Smav free(isns); 752274939Smav} 753274939Smav 754274939Smavstatic int 755274939Smavisns_do_connect(struct isns *isns) 756274939Smav{ 757274939Smav int s; 758274939Smav 759274939Smav s = socket(isns->i_ai->ai_family, isns->i_ai->ai_socktype, 760274939Smav isns->i_ai->ai_protocol); 761274939Smav if (s < 0) { 762274939Smav log_warn("socket(2) failed for %s", isns->i_addr); 763274939Smav return (-1); 764274939Smav } 765274939Smav if (connect(s, isns->i_ai->ai_addr, isns->i_ai->ai_addrlen)) { 766274939Smav log_warn("connect(2) failed for %s", isns->i_addr); 767274939Smav close(s); 768274939Smav return (-1); 769274939Smav } 770274939Smav return(s); 771274939Smav} 772274939Smav 773274939Smavstatic int 774274939Smavisns_do_register(struct isns *isns, int s, const char *hostname) 775274939Smav{ 776274939Smav struct conf *conf = isns->i_conf; 777274939Smav struct target *target; 778274939Smav struct portal *portal; 779274939Smav struct portal_group *pg; 780274939Smav struct isns_req *req; 781274939Smav int res = 0; 782274939Smav uint32_t error; 783274939Smav 784274939Smav req = isns_req_create(ISNS_FUNC_DEVATTRREG, ISNS_FLAG_CLIENT); 785274939Smav isns_req_add_str(req, 32, TAILQ_FIRST(&conf->conf_targets)->t_name); 786274939Smav isns_req_add_delim(req); 787274939Smav isns_req_add_str(req, 1, hostname); 788274939Smav isns_req_add_32(req, 2, 2); /* 2 -- iSCSI */ 789274939Smav isns_req_add_32(req, 6, conf->conf_isns_period); 790274939Smav TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 791274939Smav if (pg->pg_unassigned) 792274939Smav continue; 793274939Smav TAILQ_FOREACH(portal, &pg->pg_portals, p_next) { 794274939Smav isns_req_add_addr(req, 16, portal->p_ai); 795274939Smav isns_req_add_port(req, 17, portal->p_ai); 796274939Smav } 797274939Smav } 798274939Smav TAILQ_FOREACH(target, &conf->conf_targets, t_next) { 799274939Smav isns_req_add_str(req, 32, target->t_name); 800274939Smav isns_req_add_32(req, 33, 1); /* 1 -- Target*/ 801274939Smav if (target->t_alias != NULL) 802274939Smav isns_req_add_str(req, 34, target->t_alias); 803274939Smav pg = target->t_portal_group; 804274939Smav isns_req_add_32(req, 51, pg->pg_tag); 805274939Smav TAILQ_FOREACH(portal, &pg->pg_portals, p_next) { 806274939Smav isns_req_add_addr(req, 49, portal->p_ai); 807274939Smav isns_req_add_port(req, 50, portal->p_ai); 808274939Smav } 809274939Smav } 810274939Smav res = isns_req_send(s, req); 811274939Smav if (res < 0) { 812274939Smav log_warn("send(2) failed for %s", isns->i_addr); 813274939Smav goto quit; 814274939Smav } 815274939Smav res = isns_req_receive(s, req); 816274939Smav if (res < 0) { 817274939Smav log_warn("receive(2) failed for %s", isns->i_addr); 818274939Smav goto quit; 819274939Smav } 820274939Smav error = isns_req_get_status(req); 821274939Smav if (error != 0) { 822274939Smav log_warnx("iSNS register error %d for %s", error, isns->i_addr); 823274939Smav res = -1; 824274939Smav } 825274939Smavquit: 826274939Smav isns_req_free(req); 827274939Smav return (res); 828274939Smav} 829274939Smav 830274939Smavstatic int 831274939Smavisns_do_check(struct isns *isns, int s, const char *hostname) 832274939Smav{ 833274939Smav struct conf *conf = isns->i_conf; 834274939Smav struct isns_req *req; 835274939Smav int res = 0; 836274939Smav uint32_t error; 837274939Smav 838274939Smav req = isns_req_create(ISNS_FUNC_DEVATTRQRY, ISNS_FLAG_CLIENT); 839274939Smav isns_req_add_str(req, 32, TAILQ_FIRST(&conf->conf_targets)->t_name); 840274939Smav isns_req_add_str(req, 1, hostname); 841274939Smav isns_req_add_delim(req); 842274939Smav isns_req_add(req, 2, 0, NULL); 843274939Smav res = isns_req_send(s, req); 844274939Smav if (res < 0) { 845274939Smav log_warn("send(2) failed for %s", isns->i_addr); 846274939Smav goto quit; 847274939Smav } 848274939Smav res = isns_req_receive(s, req); 849274939Smav if (res < 0) { 850274939Smav log_warn("receive(2) failed for %s", isns->i_addr); 851274939Smav goto quit; 852274939Smav } 853274939Smav error = isns_req_get_status(req); 854274939Smav if (error != 0) { 855274939Smav log_warnx("iSNS check error %d for %s", error, isns->i_addr); 856274939Smav res = -1; 857274939Smav } 858274939Smavquit: 859274939Smav isns_req_free(req); 860274939Smav return (res); 861274939Smav} 862274939Smav 863274939Smavstatic int 864274939Smavisns_do_deregister(struct isns *isns, int s, const char *hostname) 865274939Smav{ 866274939Smav struct conf *conf = isns->i_conf; 867274939Smav struct isns_req *req; 868274939Smav int res = 0; 869274939Smav uint32_t error; 870274939Smav 871274939Smav req = isns_req_create(ISNS_FUNC_DEVDEREG, ISNS_FLAG_CLIENT); 872274939Smav isns_req_add_str(req, 32, TAILQ_FIRST(&conf->conf_targets)->t_name); 873274939Smav isns_req_add_delim(req); 874274939Smav isns_req_add_str(req, 1, hostname); 875274939Smav res = isns_req_send(s, req); 876274939Smav if (res < 0) { 877274939Smav log_warn("send(2) failed for %s", isns->i_addr); 878274939Smav goto quit; 879274939Smav } 880274939Smav res = isns_req_receive(s, req); 881274939Smav if (res < 0) { 882274939Smav log_warn("receive(2) failed for %s", isns->i_addr); 883274939Smav goto quit; 884274939Smav } 885274939Smav error = isns_req_get_status(req); 886274939Smav if (error != 0) { 887274939Smav log_warnx("iSNS deregister error %d for %s", error, isns->i_addr); 888274939Smav res = -1; 889274939Smav } 890274939Smavquit: 891274939Smav isns_req_free(req); 892274939Smav return (res); 893274939Smav} 894274939Smav 895274939Smavvoid 896274939Smavisns_register(struct isns *isns, struct isns *oldisns) 897274939Smav{ 898274939Smav struct conf *conf = isns->i_conf; 899274939Smav int s, res; 900274939Smav char hostname[256]; 901274939Smav 902274939Smav if (TAILQ_EMPTY(&conf->conf_targets) || 903274939Smav TAILQ_EMPTY(&conf->conf_portal_groups)) 904274939Smav return; 905274939Smav set_timeout(conf->conf_isns_timeout, false); 906274939Smav s = isns_do_connect(isns); 907274939Smav if (s < 0) { 908274939Smav set_timeout(0, false); 909274939Smav return; 910274939Smav } 911274939Smav gethostname(hostname, sizeof(hostname)); 912274939Smav 913274939Smav if (oldisns == NULL || TAILQ_EMPTY(&oldisns->i_conf->conf_targets)) 914274939Smav oldisns = isns; 915274939Smav res = isns_do_deregister(oldisns, s, hostname); 916274939Smav res = isns_do_register(isns, s, hostname); 917274939Smav close(s); 918274939Smav set_timeout(0, false); 919274939Smav} 920274939Smav 921274939Smavvoid 922274939Smavisns_check(struct isns *isns) 923274939Smav{ 924274939Smav struct conf *conf = isns->i_conf; 925274939Smav int s, res; 926274939Smav char hostname[256]; 927274939Smav 928274939Smav if (TAILQ_EMPTY(&conf->conf_targets) || 929274939Smav TAILQ_EMPTY(&conf->conf_portal_groups)) 930274939Smav return; 931274939Smav set_timeout(conf->conf_isns_timeout, false); 932274939Smav s = isns_do_connect(isns); 933274939Smav if (s < 0) { 934274939Smav set_timeout(0, false); 935274939Smav return; 936274939Smav } 937274939Smav gethostname(hostname, sizeof(hostname)); 938274939Smav 939274939Smav res = isns_do_check(isns, s, hostname); 940274939Smav if (res < 0) { 941274939Smav res = isns_do_deregister(isns, s, hostname); 942274939Smav res = isns_do_register(isns, s, hostname); 943274939Smav } 944274939Smav close(s); 945274939Smav set_timeout(0, false); 946274939Smav} 947274939Smav 948274939Smavvoid 949274939Smavisns_deregister(struct isns *isns) 950274939Smav{ 951274939Smav struct conf *conf = isns->i_conf; 952274939Smav int s, res; 953274939Smav char hostname[256]; 954274939Smav 955274939Smav if (TAILQ_EMPTY(&conf->conf_targets) || 956274939Smav TAILQ_EMPTY(&conf->conf_portal_groups)) 957274939Smav return; 958274939Smav set_timeout(conf->conf_isns_timeout, false); 959274939Smav s = isns_do_connect(isns); 960274939Smav if (s < 0) 961274939Smav return; 962274939Smav gethostname(hostname, sizeof(hostname)); 963274939Smav 964274939Smav res = isns_do_deregister(isns, s, hostname); 965274939Smav close(s); 966274939Smav set_timeout(0, false); 967274939Smav} 968274939Smav 969275244Straszint 970275245Straszportal_group_set_filter(struct portal_group *pg, const char *str) 971275244Strasz{ 972275245Strasz int filter; 973275244Strasz 974275244Strasz if (strcmp(str, "none") == 0) { 975275244Strasz filter = PG_FILTER_NONE; 976275244Strasz } else if (strcmp(str, "portal") == 0) { 977275244Strasz filter = PG_FILTER_PORTAL; 978275244Strasz } else if (strcmp(str, "portal-name") == 0) { 979275244Strasz filter = PG_FILTER_PORTAL_NAME; 980275244Strasz } else if (strcmp(str, "portal-name-auth") == 0) { 981275244Strasz filter = PG_FILTER_PORTAL_NAME_AUTH; 982275244Strasz } else { 983275244Strasz log_warnx("invalid discovery-filter \"%s\" for portal-group " 984275244Strasz "\"%s\"; valid values are \"none\", \"portal\", " 985275244Strasz "\"portal-name\", and \"portal-name-auth\"", 986275244Strasz str, pg->pg_name); 987275244Strasz return (1); 988275244Strasz } 989275244Strasz 990275245Strasz if (pg->pg_discovery_filter != PG_FILTER_UNKNOWN && 991275245Strasz pg->pg_discovery_filter != filter) { 992275244Strasz log_warnx("cannot set discovery-filter to \"%s\" for " 993275244Strasz "portal-group \"%s\"; already has a different " 994275244Strasz "value", str, pg->pg_name); 995275244Strasz return (1); 996275244Strasz } 997275244Strasz 998275245Strasz pg->pg_discovery_filter = filter; 999275245Strasz 1000275245Strasz return (0); 1001275244Strasz} 1002275244Strasz 1003255570Straszstatic bool 1004255570Straszvalid_hex(const char ch) 1005255570Strasz{ 1006255570Strasz switch (ch) { 1007255570Strasz case '0': 1008255570Strasz case '1': 1009255570Strasz case '2': 1010255570Strasz case '3': 1011255570Strasz case '4': 1012255570Strasz case '5': 1013255570Strasz case '6': 1014255570Strasz case '7': 1015255570Strasz case '8': 1016255570Strasz case '9': 1017255570Strasz case 'a': 1018255570Strasz case 'A': 1019255570Strasz case 'b': 1020255570Strasz case 'B': 1021255570Strasz case 'c': 1022255570Strasz case 'C': 1023255570Strasz case 'd': 1024255570Strasz case 'D': 1025255570Strasz case 'e': 1026255570Strasz case 'E': 1027255570Strasz case 'f': 1028255570Strasz case 'F': 1029255570Strasz return (true); 1030255570Strasz default: 1031255570Strasz return (false); 1032255570Strasz } 1033255570Strasz} 1034255570Strasz 1035255570Straszbool 1036255570Straszvalid_iscsi_name(const char *name) 1037255570Strasz{ 1038255570Strasz int i; 1039255570Strasz 1040255570Strasz if (strlen(name) >= MAX_NAME_LEN) { 1041255570Strasz log_warnx("overlong name for target \"%s\"; max length allowed " 1042255570Strasz "by iSCSI specification is %d characters", 1043255570Strasz name, MAX_NAME_LEN); 1044255570Strasz return (false); 1045255570Strasz } 1046255570Strasz 1047255570Strasz /* 1048255570Strasz * In the cases below, we don't return an error, just in case the admin 1049255570Strasz * was right, and we're wrong. 1050255570Strasz */ 1051255570Strasz if (strncasecmp(name, "iqn.", strlen("iqn.")) == 0) { 1052255570Strasz for (i = strlen("iqn."); name[i] != '\0'; i++) { 1053255570Strasz /* 1054255570Strasz * XXX: We should verify UTF-8 normalisation, as defined 1055274870Strasz * by 3.2.6.2: iSCSI Name Encoding. 1056255570Strasz */ 1057255570Strasz if (isalnum(name[i])) 1058255570Strasz continue; 1059255570Strasz if (name[i] == '-' || name[i] == '.' || name[i] == ':') 1060255570Strasz continue; 1061255570Strasz log_warnx("invalid character \"%c\" in target name " 1062255570Strasz "\"%s\"; allowed characters are letters, digits, " 1063255570Strasz "'-', '.', and ':'", name[i], name); 1064255570Strasz break; 1065255570Strasz } 1066255570Strasz /* 1067255570Strasz * XXX: Check more stuff: valid date and a valid reversed domain. 1068255570Strasz */ 1069255570Strasz } else if (strncasecmp(name, "eui.", strlen("eui.")) == 0) { 1070255570Strasz if (strlen(name) != strlen("eui.") + 16) 1071255570Strasz log_warnx("invalid target name \"%s\"; the \"eui.\" " 1072255570Strasz "should be followed by exactly 16 hexadecimal " 1073255570Strasz "digits", name); 1074255570Strasz for (i = strlen("eui."); name[i] != '\0'; i++) { 1075255570Strasz if (!valid_hex(name[i])) { 1076255570Strasz log_warnx("invalid character \"%c\" in target " 1077255570Strasz "name \"%s\"; allowed characters are 1-9 " 1078255570Strasz "and A-F", name[i], name); 1079255570Strasz break; 1080255570Strasz } 1081255570Strasz } 1082255570Strasz } else if (strncasecmp(name, "naa.", strlen("naa.")) == 0) { 1083255570Strasz if (strlen(name) > strlen("naa.") + 32) 1084255570Strasz log_warnx("invalid target name \"%s\"; the \"naa.\" " 1085255570Strasz "should be followed by at most 32 hexadecimal " 1086255570Strasz "digits", name); 1087255570Strasz for (i = strlen("naa."); name[i] != '\0'; i++) { 1088255570Strasz if (!valid_hex(name[i])) { 1089255570Strasz log_warnx("invalid character \"%c\" in target " 1090255570Strasz "name \"%s\"; allowed characters are 1-9 " 1091255570Strasz "and A-F", name[i], name); 1092255570Strasz break; 1093255570Strasz } 1094255570Strasz } 1095255570Strasz } else { 1096255570Strasz log_warnx("invalid target name \"%s\"; should start with " 1097255570Strasz "either \".iqn\", \"eui.\", or \"naa.\"", 1098255570Strasz name); 1099255570Strasz } 1100255570Strasz return (true); 1101255570Strasz} 1102255570Strasz 1103255570Straszstruct target * 1104263723Strasztarget_new(struct conf *conf, const char *name) 1105255570Strasz{ 1106255570Strasz struct target *targ; 1107255570Strasz int i, len; 1108255570Strasz 1109263723Strasz targ = target_find(conf, name); 1110255570Strasz if (targ != NULL) { 1111263723Strasz log_warnx("duplicated target \"%s\"", name); 1112255570Strasz return (NULL); 1113255570Strasz } 1114263723Strasz if (valid_iscsi_name(name) == false) { 1115263723Strasz log_warnx("target name \"%s\" is invalid", name); 1116255570Strasz return (NULL); 1117255570Strasz } 1118255570Strasz targ = calloc(1, sizeof(*targ)); 1119255570Strasz if (targ == NULL) 1120255570Strasz log_err(1, "calloc"); 1121263723Strasz targ->t_name = checked_strdup(name); 1122255570Strasz 1123255570Strasz /* 1124255570Strasz * RFC 3722 requires us to normalize the name to lowercase. 1125255570Strasz */ 1126263723Strasz len = strlen(name); 1127255570Strasz for (i = 0; i < len; i++) 1128263723Strasz targ->t_name[i] = tolower(targ->t_name[i]); 1129255570Strasz 1130255570Strasz TAILQ_INIT(&targ->t_luns); 1131255570Strasz targ->t_conf = conf; 1132255570Strasz TAILQ_INSERT_TAIL(&conf->conf_targets, targ, t_next); 1133255570Strasz 1134255570Strasz return (targ); 1135255570Strasz} 1136255570Strasz 1137255570Straszvoid 1138255570Strasztarget_delete(struct target *targ) 1139255570Strasz{ 1140255570Strasz struct lun *lun, *tmp; 1141255570Strasz 1142255570Strasz TAILQ_REMOVE(&targ->t_conf->conf_targets, targ, t_next); 1143255570Strasz 1144255570Strasz TAILQ_FOREACH_SAFE(lun, &targ->t_luns, l_next, tmp) 1145255570Strasz lun_delete(lun); 1146263723Strasz free(targ->t_name); 1147255570Strasz free(targ); 1148255570Strasz} 1149255570Strasz 1150255570Straszstruct target * 1151263723Strasztarget_find(struct conf *conf, const char *name) 1152255570Strasz{ 1153255570Strasz struct target *targ; 1154255570Strasz 1155255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 1156263723Strasz if (strcasecmp(targ->t_name, name) == 0) 1157255570Strasz return (targ); 1158255570Strasz } 1159255570Strasz 1160255570Strasz return (NULL); 1161255570Strasz} 1162255570Strasz 1163255570Straszstruct lun * 1164255570Straszlun_new(struct target *targ, int lun_id) 1165255570Strasz{ 1166255570Strasz struct lun *lun; 1167255570Strasz 1168255570Strasz lun = lun_find(targ, lun_id); 1169255570Strasz if (lun != NULL) { 1170255570Strasz log_warnx("duplicated lun %d for target \"%s\"", 1171263723Strasz lun_id, targ->t_name); 1172255570Strasz return (NULL); 1173255570Strasz } 1174255570Strasz 1175255570Strasz lun = calloc(1, sizeof(*lun)); 1176255570Strasz if (lun == NULL) 1177255570Strasz log_err(1, "calloc"); 1178255570Strasz lun->l_lun = lun_id; 1179255570Strasz TAILQ_INIT(&lun->l_options); 1180255570Strasz lun->l_target = targ; 1181255570Strasz TAILQ_INSERT_TAIL(&targ->t_luns, lun, l_next); 1182255570Strasz 1183255570Strasz return (lun); 1184255570Strasz} 1185255570Strasz 1186255570Straszvoid 1187255570Straszlun_delete(struct lun *lun) 1188255570Strasz{ 1189255570Strasz struct lun_option *lo, *tmp; 1190255570Strasz 1191255570Strasz TAILQ_REMOVE(&lun->l_target->t_luns, lun, l_next); 1192255570Strasz 1193255570Strasz TAILQ_FOREACH_SAFE(lo, &lun->l_options, lo_next, tmp) 1194255570Strasz lun_option_delete(lo); 1195255570Strasz free(lun->l_backend); 1196255570Strasz free(lun->l_device_id); 1197255570Strasz free(lun->l_path); 1198255570Strasz free(lun->l_serial); 1199255570Strasz free(lun); 1200255570Strasz} 1201255570Strasz 1202255570Straszstruct lun * 1203265514Straszlun_find(const struct target *targ, int lun_id) 1204255570Strasz{ 1205255570Strasz struct lun *lun; 1206255570Strasz 1207255570Strasz TAILQ_FOREACH(lun, &targ->t_luns, l_next) { 1208255570Strasz if (lun->l_lun == lun_id) 1209255570Strasz return (lun); 1210255570Strasz } 1211255570Strasz 1212255570Strasz return (NULL); 1213255570Strasz} 1214255570Strasz 1215255570Straszvoid 1216255570Straszlun_set_backend(struct lun *lun, const char *value) 1217255570Strasz{ 1218255570Strasz free(lun->l_backend); 1219255570Strasz lun->l_backend = checked_strdup(value); 1220255570Strasz} 1221255570Strasz 1222255570Straszvoid 1223255570Straszlun_set_blocksize(struct lun *lun, size_t value) 1224255570Strasz{ 1225255570Strasz 1226255570Strasz lun->l_blocksize = value; 1227255570Strasz} 1228255570Strasz 1229255570Straszvoid 1230255570Straszlun_set_device_id(struct lun *lun, const char *value) 1231255570Strasz{ 1232255570Strasz free(lun->l_device_id); 1233255570Strasz lun->l_device_id = checked_strdup(value); 1234255570Strasz} 1235255570Strasz 1236255570Straszvoid 1237255570Straszlun_set_path(struct lun *lun, const char *value) 1238255570Strasz{ 1239255570Strasz free(lun->l_path); 1240255570Strasz lun->l_path = checked_strdup(value); 1241255570Strasz} 1242255570Strasz 1243255570Straszvoid 1244255570Straszlun_set_serial(struct lun *lun, const char *value) 1245255570Strasz{ 1246255570Strasz free(lun->l_serial); 1247255570Strasz lun->l_serial = checked_strdup(value); 1248255570Strasz} 1249255570Strasz 1250255570Straszvoid 1251255570Straszlun_set_size(struct lun *lun, size_t value) 1252255570Strasz{ 1253255570Strasz 1254255570Strasz lun->l_size = value; 1255255570Strasz} 1256255570Strasz 1257255570Straszvoid 1258255570Straszlun_set_ctl_lun(struct lun *lun, uint32_t value) 1259255570Strasz{ 1260255570Strasz 1261255570Strasz lun->l_ctl_lun = value; 1262255570Strasz} 1263255570Strasz 1264255570Straszstruct lun_option * 1265255570Straszlun_option_new(struct lun *lun, const char *name, const char *value) 1266255570Strasz{ 1267255570Strasz struct lun_option *lo; 1268255570Strasz 1269255570Strasz lo = lun_option_find(lun, name); 1270255570Strasz if (lo != NULL) { 1271255570Strasz log_warnx("duplicated lun option %s for lun %d, target \"%s\"", 1272263723Strasz name, lun->l_lun, lun->l_target->t_name); 1273255570Strasz return (NULL); 1274255570Strasz } 1275255570Strasz 1276255570Strasz lo = calloc(1, sizeof(*lo)); 1277255570Strasz if (lo == NULL) 1278255570Strasz log_err(1, "calloc"); 1279255570Strasz lo->lo_name = checked_strdup(name); 1280255570Strasz lo->lo_value = checked_strdup(value); 1281255570Strasz lo->lo_lun = lun; 1282255570Strasz TAILQ_INSERT_TAIL(&lun->l_options, lo, lo_next); 1283255570Strasz 1284255570Strasz return (lo); 1285255570Strasz} 1286255570Strasz 1287255570Straszvoid 1288255570Straszlun_option_delete(struct lun_option *lo) 1289255570Strasz{ 1290255570Strasz 1291255570Strasz TAILQ_REMOVE(&lo->lo_lun->l_options, lo, lo_next); 1292255570Strasz 1293255570Strasz free(lo->lo_name); 1294255570Strasz free(lo->lo_value); 1295255570Strasz free(lo); 1296255570Strasz} 1297255570Strasz 1298255570Straszstruct lun_option * 1299265514Straszlun_option_find(const struct lun *lun, const char *name) 1300255570Strasz{ 1301255570Strasz struct lun_option *lo; 1302255570Strasz 1303255570Strasz TAILQ_FOREACH(lo, &lun->l_options, lo_next) { 1304255570Strasz if (strcmp(lo->lo_name, name) == 0) 1305255570Strasz return (lo); 1306255570Strasz } 1307255570Strasz 1308255570Strasz return (NULL); 1309255570Strasz} 1310255570Strasz 1311255570Straszvoid 1312255570Straszlun_option_set(struct lun_option *lo, const char *value) 1313255570Strasz{ 1314255570Strasz 1315255570Strasz free(lo->lo_value); 1316255570Strasz lo->lo_value = checked_strdup(value); 1317255570Strasz} 1318255570Strasz 1319255570Straszstatic struct connection * 1320270137Smavconnection_new(struct portal *portal, int fd, const char *host, 1321270137Smav const struct sockaddr *client_sa) 1322255570Strasz{ 1323255570Strasz struct connection *conn; 1324255570Strasz 1325255570Strasz conn = calloc(1, sizeof(*conn)); 1326255570Strasz if (conn == NULL) 1327255570Strasz log_err(1, "calloc"); 1328255570Strasz conn->conn_portal = portal; 1329255570Strasz conn->conn_socket = fd; 1330255570Strasz conn->conn_initiator_addr = checked_strdup(host); 1331270137Smav memcpy(&conn->conn_initiator_sa, client_sa, client_sa->sa_len); 1332255570Strasz 1333255570Strasz /* 1334255570Strasz * Default values, from RFC 3720, section 12. 1335255570Strasz */ 1336255570Strasz conn->conn_max_data_segment_length = 8192; 1337255570Strasz conn->conn_max_burst_length = 262144; 1338255570Strasz conn->conn_immediate_data = true; 1339255570Strasz 1340255570Strasz return (conn); 1341255570Strasz} 1342255570Strasz 1343255570Strasz#if 0 1344255570Straszstatic void 1345255570Straszconf_print(struct conf *conf) 1346255570Strasz{ 1347255570Strasz struct auth_group *ag; 1348255570Strasz struct auth *auth; 1349263720Strasz struct auth_name *auth_name; 1350263720Strasz struct auth_portal *auth_portal; 1351255570Strasz struct portal_group *pg; 1352255570Strasz struct portal *portal; 1353255570Strasz struct target *targ; 1354255570Strasz struct lun *lun; 1355255570Strasz struct lun_option *lo; 1356255570Strasz 1357255570Strasz TAILQ_FOREACH(ag, &conf->conf_auth_groups, ag_next) { 1358255570Strasz fprintf(stderr, "auth-group %s {\n", ag->ag_name); 1359255570Strasz TAILQ_FOREACH(auth, &ag->ag_auths, a_next) 1360255570Strasz fprintf(stderr, "\t chap-mutual %s %s %s %s\n", 1361255570Strasz auth->a_user, auth->a_secret, 1362255570Strasz auth->a_mutual_user, auth->a_mutual_secret); 1363263720Strasz TAILQ_FOREACH(auth_name, &ag->ag_names, an_next) 1364263720Strasz fprintf(stderr, "\t initiator-name %s\n", 1365263720Strasz auth_name->an_initator_name); 1366263720Strasz TAILQ_FOREACH(auth_portal, &ag->ag_portals, an_next) 1367263720Strasz fprintf(stderr, "\t initiator-portal %s\n", 1368263720Strasz auth_portal->an_initator_portal); 1369255570Strasz fprintf(stderr, "}\n"); 1370255570Strasz } 1371255570Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 1372255570Strasz fprintf(stderr, "portal-group %s {\n", pg->pg_name); 1373255570Strasz TAILQ_FOREACH(portal, &pg->pg_portals, p_next) 1374255570Strasz fprintf(stderr, "\t listen %s\n", portal->p_listen); 1375255570Strasz fprintf(stderr, "}\n"); 1376255570Strasz } 1377255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 1378263723Strasz fprintf(stderr, "target %s {\n", targ->t_name); 1379255570Strasz if (targ->t_alias != NULL) 1380255570Strasz fprintf(stderr, "\t alias %s\n", targ->t_alias); 1381255570Strasz TAILQ_FOREACH(lun, &targ->t_luns, l_next) { 1382255570Strasz fprintf(stderr, "\tlun %d {\n", lun->l_lun); 1383255570Strasz fprintf(stderr, "\t\tpath %s\n", lun->l_path); 1384255570Strasz TAILQ_FOREACH(lo, &lun->l_options, lo_next) 1385255570Strasz fprintf(stderr, "\t\toption %s %s\n", 1386255570Strasz lo->lo_name, lo->lo_value); 1387255570Strasz fprintf(stderr, "\t}\n"); 1388255570Strasz } 1389255570Strasz fprintf(stderr, "}\n"); 1390255570Strasz } 1391255570Strasz} 1392255570Strasz#endif 1393255570Strasz 1394263717Straszstatic int 1395263717Straszconf_verify_lun(struct lun *lun) 1396263717Strasz{ 1397263717Strasz const struct lun *lun2; 1398263718Strasz const struct target *targ2; 1399263717Strasz 1400263717Strasz if (lun->l_backend == NULL) 1401263717Strasz lun_set_backend(lun, "block"); 1402263717Strasz if (strcmp(lun->l_backend, "block") == 0) { 1403263717Strasz if (lun->l_path == NULL) { 1404263717Strasz log_warnx("missing path for lun %d, target \"%s\"", 1405263723Strasz lun->l_lun, lun->l_target->t_name); 1406263717Strasz return (1); 1407263717Strasz } 1408263717Strasz } else if (strcmp(lun->l_backend, "ramdisk") == 0) { 1409263717Strasz if (lun->l_size == 0) { 1410263717Strasz log_warnx("missing size for ramdisk-backed lun %d, " 1411263723Strasz "target \"%s\"", lun->l_lun, lun->l_target->t_name); 1412263717Strasz return (1); 1413263717Strasz } 1414263717Strasz if (lun->l_path != NULL) { 1415263717Strasz log_warnx("path must not be specified " 1416263717Strasz "for ramdisk-backed lun %d, target \"%s\"", 1417263723Strasz lun->l_lun, lun->l_target->t_name); 1418263717Strasz return (1); 1419263717Strasz } 1420263717Strasz } 1421263717Strasz if (lun->l_lun < 0 || lun->l_lun > 255) { 1422263717Strasz log_warnx("invalid lun number for lun %d, target \"%s\"; " 1423263717Strasz "must be between 0 and 255", lun->l_lun, 1424263723Strasz lun->l_target->t_name); 1425263717Strasz return (1); 1426263717Strasz } 1427263717Strasz if (lun->l_blocksize == 0) { 1428263717Strasz lun_set_blocksize(lun, DEFAULT_BLOCKSIZE); 1429263717Strasz } else if (lun->l_blocksize < 0) { 1430263717Strasz log_warnx("invalid blocksize for lun %d, target \"%s\"; " 1431263723Strasz "must be larger than 0", lun->l_lun, lun->l_target->t_name); 1432263717Strasz return (1); 1433263717Strasz } 1434263717Strasz if (lun->l_size != 0 && lun->l_size % lun->l_blocksize != 0) { 1435263717Strasz log_warnx("invalid size for lun %d, target \"%s\"; " 1436263717Strasz "must be multiple of blocksize", lun->l_lun, 1437263723Strasz lun->l_target->t_name); 1438263717Strasz return (1); 1439263717Strasz } 1440263718Strasz TAILQ_FOREACH(targ2, &lun->l_target->t_conf->conf_targets, t_next) { 1441263718Strasz TAILQ_FOREACH(lun2, &targ2->t_luns, l_next) { 1442263718Strasz if (lun == lun2) 1443263718Strasz continue; 1444263718Strasz if (lun->l_path != NULL && lun2->l_path != NULL && 1445263718Strasz strcmp(lun->l_path, lun2->l_path) == 0) { 1446263718Strasz log_debugx("WARNING: path \"%s\" duplicated " 1447263718Strasz "between lun %d, target \"%s\", and " 1448263718Strasz "lun %d, target \"%s\"", lun->l_path, 1449263723Strasz lun->l_lun, lun->l_target->t_name, 1450263723Strasz lun2->l_lun, lun2->l_target->t_name); 1451263718Strasz } 1452263718Strasz } 1453263718Strasz } 1454263717Strasz 1455263717Strasz return (0); 1456263717Strasz} 1457263717Strasz 1458255570Straszint 1459255570Straszconf_verify(struct conf *conf) 1460255570Strasz{ 1461255570Strasz struct auth_group *ag; 1462255570Strasz struct portal_group *pg; 1463255570Strasz struct target *targ; 1464263717Strasz struct lun *lun; 1465274871Strasz bool found; 1466263717Strasz int error; 1467255570Strasz 1468255570Strasz if (conf->conf_pidfile_path == NULL) 1469255570Strasz conf->conf_pidfile_path = checked_strdup(DEFAULT_PIDFILE); 1470255570Strasz 1471255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 1472255570Strasz if (targ->t_auth_group == NULL) { 1473263726Strasz targ->t_auth_group = auth_group_find(conf, 1474263726Strasz "default"); 1475263726Strasz assert(targ->t_auth_group != NULL); 1476255570Strasz } 1477255570Strasz if (targ->t_portal_group == NULL) { 1478255570Strasz targ->t_portal_group = portal_group_find(conf, 1479255570Strasz "default"); 1480255570Strasz assert(targ->t_portal_group != NULL); 1481255570Strasz } 1482274871Strasz found = false; 1483255570Strasz TAILQ_FOREACH(lun, &targ->t_luns, l_next) { 1484263717Strasz error = conf_verify_lun(lun); 1485263717Strasz if (error != 0) 1486263717Strasz return (error); 1487274871Strasz found = true; 1488255570Strasz } 1489274871Strasz if (!found) { 1490265506Strasz log_warnx("no LUNs defined for target \"%s\"", 1491265506Strasz targ->t_name); 1492255570Strasz } 1493255570Strasz } 1494255570Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 1495255570Strasz assert(pg->pg_name != NULL); 1496255570Strasz if (pg->pg_discovery_auth_group == NULL) { 1497255570Strasz pg->pg_discovery_auth_group = 1498263728Strasz auth_group_find(conf, "default"); 1499255570Strasz assert(pg->pg_discovery_auth_group != NULL); 1500255570Strasz } 1501255570Strasz 1502275244Strasz if (pg->pg_discovery_filter == PG_FILTER_UNKNOWN) 1503275244Strasz pg->pg_discovery_filter = PG_FILTER_NONE; 1504275244Strasz 1505255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 1506255570Strasz if (targ->t_portal_group == pg) 1507255570Strasz break; 1508255570Strasz } 1509255570Strasz if (targ == NULL) { 1510255570Strasz if (strcmp(pg->pg_name, "default") != 0) 1511255570Strasz log_warnx("portal-group \"%s\" not assigned " 1512255570Strasz "to any target", pg->pg_name); 1513255570Strasz pg->pg_unassigned = true; 1514255570Strasz } else 1515255570Strasz pg->pg_unassigned = false; 1516255570Strasz } 1517255570Strasz TAILQ_FOREACH(ag, &conf->conf_auth_groups, ag_next) { 1518255570Strasz if (ag->ag_name == NULL) 1519255570Strasz assert(ag->ag_target != NULL); 1520255570Strasz else 1521255570Strasz assert(ag->ag_target == NULL); 1522255570Strasz 1523274871Strasz found = false; 1524255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 1525274871Strasz if (targ->t_auth_group == ag) { 1526274871Strasz found = true; 1527255570Strasz break; 1528274871Strasz } 1529255570Strasz } 1530274871Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 1531274871Strasz if (pg->pg_discovery_auth_group == ag) { 1532274871Strasz found = true; 1533274871Strasz break; 1534274871Strasz } 1535274871Strasz } 1536274871Strasz if (!found && ag->ag_name != NULL && 1537263728Strasz strcmp(ag->ag_name, "default") != 0 && 1538255570Strasz strcmp(ag->ag_name, "no-authentication") != 0 && 1539255570Strasz strcmp(ag->ag_name, "no-access") != 0) { 1540255570Strasz log_warnx("auth-group \"%s\" not assigned " 1541255570Strasz "to any target", ag->ag_name); 1542255570Strasz } 1543255570Strasz } 1544255570Strasz 1545255570Strasz return (0); 1546255570Strasz} 1547255570Strasz 1548255570Straszstatic int 1549255570Straszconf_apply(struct conf *oldconf, struct conf *newconf) 1550255570Strasz{ 1551255570Strasz struct target *oldtarg, *newtarg, *tmptarg; 1552255570Strasz struct lun *oldlun, *newlun, *tmplun; 1553255570Strasz struct portal_group *oldpg, *newpg; 1554255570Strasz struct portal *oldp, *newp; 1555274939Smav struct isns *oldns, *newns; 1556255570Strasz pid_t otherpid; 1557255570Strasz int changed, cumulated_error = 0, error; 1558255570Strasz int one = 1; 1559255570Strasz 1560255570Strasz if (oldconf->conf_debug != newconf->conf_debug) { 1561255570Strasz log_debugx("changing debug level to %d", newconf->conf_debug); 1562255570Strasz log_init(newconf->conf_debug); 1563255570Strasz } 1564255570Strasz 1565255570Strasz if (oldconf->conf_pidfh != NULL) { 1566255570Strasz assert(oldconf->conf_pidfile_path != NULL); 1567255570Strasz if (newconf->conf_pidfile_path != NULL && 1568255570Strasz strcmp(oldconf->conf_pidfile_path, 1569255570Strasz newconf->conf_pidfile_path) == 0) { 1570255570Strasz newconf->conf_pidfh = oldconf->conf_pidfh; 1571255570Strasz oldconf->conf_pidfh = NULL; 1572255570Strasz } else { 1573255570Strasz log_debugx("removing pidfile %s", 1574255570Strasz oldconf->conf_pidfile_path); 1575255570Strasz pidfile_remove(oldconf->conf_pidfh); 1576255570Strasz oldconf->conf_pidfh = NULL; 1577255570Strasz } 1578255570Strasz } 1579255570Strasz 1580255570Strasz if (newconf->conf_pidfh == NULL && newconf->conf_pidfile_path != NULL) { 1581255570Strasz log_debugx("opening pidfile %s", newconf->conf_pidfile_path); 1582255570Strasz newconf->conf_pidfh = 1583255570Strasz pidfile_open(newconf->conf_pidfile_path, 0600, &otherpid); 1584255570Strasz if (newconf->conf_pidfh == NULL) { 1585255570Strasz if (errno == EEXIST) 1586255570Strasz log_errx(1, "daemon already running, pid: %jd.", 1587255570Strasz (intmax_t)otherpid); 1588255570Strasz log_err(1, "cannot open or create pidfile \"%s\"", 1589255570Strasz newconf->conf_pidfile_path); 1590255570Strasz } 1591255570Strasz } 1592255570Strasz 1593274939Smav /* Deregister on removed iSNS servers. */ 1594274939Smav TAILQ_FOREACH(oldns, &oldconf->conf_isns, i_next) { 1595274939Smav TAILQ_FOREACH(newns, &newconf->conf_isns, i_next) { 1596274939Smav if (strcmp(oldns->i_addr, newns->i_addr) == 0) 1597274939Smav break; 1598274939Smav } 1599274939Smav if (newns == NULL) 1600274939Smav isns_deregister(oldns); 1601274939Smav } 1602274939Smav 1603265518Strasz /* 1604265518Strasz * XXX: If target or lun removal fails, we should somehow "move" 1605274870Strasz * the old lun or target into newconf, so that subsequent 1606274870Strasz * conf_apply() would try to remove them again. That would 1607274870Strasz * be somewhat hairy, though, and lun deletion failures don't 1608274870Strasz * really happen, so leave it as it is for now. 1609265518Strasz */ 1610255570Strasz TAILQ_FOREACH_SAFE(oldtarg, &oldconf->conf_targets, t_next, tmptarg) { 1611255570Strasz /* 1612255570Strasz * First, remove any targets present in the old configuration 1613255570Strasz * and missing in the new one. 1614255570Strasz */ 1615263723Strasz newtarg = target_find(newconf, oldtarg->t_name); 1616255570Strasz if (newtarg == NULL) { 1617255570Strasz TAILQ_FOREACH_SAFE(oldlun, &oldtarg->t_luns, l_next, 1618255570Strasz tmplun) { 1619263716Strasz log_debugx("target %s not found in new " 1620263716Strasz "configuration; removing its lun %d, " 1621255570Strasz "backed by CTL lun %d", 1622263723Strasz oldtarg->t_name, oldlun->l_lun, 1623255570Strasz oldlun->l_ctl_lun); 1624255570Strasz error = kernel_lun_remove(oldlun); 1625255570Strasz if (error != 0) { 1626255570Strasz log_warnx("failed to remove lun %d, " 1627255570Strasz "target %s, CTL lun %d", 1628263723Strasz oldlun->l_lun, oldtarg->t_name, 1629255570Strasz oldlun->l_ctl_lun); 1630255570Strasz cumulated_error++; 1631255570Strasz } 1632255570Strasz } 1633268682Smav kernel_port_remove(oldtarg); 1634255570Strasz continue; 1635255570Strasz } 1636255570Strasz 1637255570Strasz /* 1638255570Strasz * Second, remove any LUNs present in the old target 1639255570Strasz * and missing in the new one. 1640255570Strasz */ 1641255570Strasz TAILQ_FOREACH_SAFE(oldlun, &oldtarg->t_luns, l_next, tmplun) { 1642255570Strasz newlun = lun_find(newtarg, oldlun->l_lun); 1643255570Strasz if (newlun == NULL) { 1644255570Strasz log_debugx("lun %d, target %s, CTL lun %d " 1645263716Strasz "not found in new configuration; " 1646263723Strasz "removing", oldlun->l_lun, oldtarg->t_name, 1647255570Strasz oldlun->l_ctl_lun); 1648255570Strasz error = kernel_lun_remove(oldlun); 1649255570Strasz if (error != 0) { 1650255570Strasz log_warnx("failed to remove lun %d, " 1651255570Strasz "target %s, CTL lun %d", 1652263723Strasz oldlun->l_lun, oldtarg->t_name, 1653255570Strasz oldlun->l_ctl_lun); 1654255570Strasz cumulated_error++; 1655255570Strasz } 1656255570Strasz continue; 1657255570Strasz } 1658255570Strasz 1659255570Strasz /* 1660255570Strasz * Also remove the LUNs changed by more than size. 1661255570Strasz */ 1662255570Strasz changed = 0; 1663255570Strasz assert(oldlun->l_backend != NULL); 1664255570Strasz assert(newlun->l_backend != NULL); 1665255570Strasz if (strcmp(newlun->l_backend, oldlun->l_backend) != 0) { 1666255570Strasz log_debugx("backend for lun %d, target %s, " 1667255570Strasz "CTL lun %d changed; removing", 1668263723Strasz oldlun->l_lun, oldtarg->t_name, 1669255570Strasz oldlun->l_ctl_lun); 1670255570Strasz changed = 1; 1671255570Strasz } 1672255570Strasz if (oldlun->l_blocksize != newlun->l_blocksize) { 1673255570Strasz log_debugx("blocksize for lun %d, target %s, " 1674255570Strasz "CTL lun %d changed; removing", 1675263723Strasz oldlun->l_lun, oldtarg->t_name, 1676255570Strasz oldlun->l_ctl_lun); 1677255570Strasz changed = 1; 1678255570Strasz } 1679255570Strasz if (newlun->l_device_id != NULL && 1680255570Strasz (oldlun->l_device_id == NULL || 1681255570Strasz strcmp(oldlun->l_device_id, newlun->l_device_id) != 1682255570Strasz 0)) { 1683255570Strasz log_debugx("device-id for lun %d, target %s, " 1684255570Strasz "CTL lun %d changed; removing", 1685263723Strasz oldlun->l_lun, oldtarg->t_name, 1686255570Strasz oldlun->l_ctl_lun); 1687255570Strasz changed = 1; 1688255570Strasz } 1689255570Strasz if (newlun->l_path != NULL && 1690255570Strasz (oldlun->l_path == NULL || 1691255570Strasz strcmp(oldlun->l_path, newlun->l_path) != 0)) { 1692255570Strasz log_debugx("path for lun %d, target %s, " 1693255570Strasz "CTL lun %d, changed; removing", 1694263723Strasz oldlun->l_lun, oldtarg->t_name, 1695255570Strasz oldlun->l_ctl_lun); 1696255570Strasz changed = 1; 1697255570Strasz } 1698255570Strasz if (newlun->l_serial != NULL && 1699255570Strasz (oldlun->l_serial == NULL || 1700255570Strasz strcmp(oldlun->l_serial, newlun->l_serial) != 0)) { 1701255570Strasz log_debugx("serial for lun %d, target %s, " 1702255570Strasz "CTL lun %d changed; removing", 1703263723Strasz oldlun->l_lun, oldtarg->t_name, 1704255570Strasz oldlun->l_ctl_lun); 1705255570Strasz changed = 1; 1706255570Strasz } 1707255570Strasz if (changed) { 1708255570Strasz error = kernel_lun_remove(oldlun); 1709255570Strasz if (error != 0) { 1710255570Strasz log_warnx("failed to remove lun %d, " 1711255570Strasz "target %s, CTL lun %d", 1712263723Strasz oldlun->l_lun, oldtarg->t_name, 1713255570Strasz oldlun->l_ctl_lun); 1714255570Strasz cumulated_error++; 1715255570Strasz } 1716255570Strasz lun_delete(oldlun); 1717255570Strasz continue; 1718255570Strasz } 1719255570Strasz 1720255570Strasz lun_set_ctl_lun(newlun, oldlun->l_ctl_lun); 1721255570Strasz } 1722255570Strasz } 1723255570Strasz 1724255570Strasz /* 1725255570Strasz * Now add new targets or modify existing ones. 1726255570Strasz */ 1727255570Strasz TAILQ_FOREACH(newtarg, &newconf->conf_targets, t_next) { 1728263723Strasz oldtarg = target_find(oldconf, newtarg->t_name); 1729255570Strasz 1730265518Strasz TAILQ_FOREACH_SAFE(newlun, &newtarg->t_luns, l_next, tmplun) { 1731255570Strasz if (oldtarg != NULL) { 1732255570Strasz oldlun = lun_find(oldtarg, newlun->l_lun); 1733255570Strasz if (oldlun != NULL) { 1734271929Smav if (newlun->l_size != oldlun->l_size || 1735271929Smav newlun->l_size == 0) { 1736255570Strasz log_debugx("resizing lun %d, " 1737255570Strasz "target %s, CTL lun %d", 1738255570Strasz newlun->l_lun, 1739263723Strasz newtarg->t_name, 1740255570Strasz newlun->l_ctl_lun); 1741255570Strasz error = 1742255570Strasz kernel_lun_resize(newlun); 1743255570Strasz if (error != 0) { 1744255570Strasz log_warnx("failed to " 1745255570Strasz "resize lun %d, " 1746255570Strasz "target %s, " 1747255570Strasz "CTL lun %d", 1748255570Strasz newlun->l_lun, 1749263723Strasz newtarg->t_name, 1750255570Strasz newlun->l_lun); 1751255570Strasz cumulated_error++; 1752255570Strasz } 1753255570Strasz } 1754255570Strasz continue; 1755255570Strasz } 1756255570Strasz } 1757255570Strasz log_debugx("adding lun %d, target %s", 1758263723Strasz newlun->l_lun, newtarg->t_name); 1759255570Strasz error = kernel_lun_add(newlun); 1760255570Strasz if (error != 0) { 1761255570Strasz log_warnx("failed to add lun %d, target %s", 1762263723Strasz newlun->l_lun, newtarg->t_name); 1763265518Strasz lun_delete(newlun); 1764255570Strasz cumulated_error++; 1765255570Strasz } 1766255570Strasz } 1767268682Smav if (oldtarg == NULL) 1768268682Smav kernel_port_add(newtarg); 1769255570Strasz } 1770255570Strasz 1771255570Strasz /* 1772255570Strasz * Go through the new portals, opening the sockets as neccessary. 1773255570Strasz */ 1774255570Strasz TAILQ_FOREACH(newpg, &newconf->conf_portal_groups, pg_next) { 1775255570Strasz if (newpg->pg_unassigned) { 1776255570Strasz log_debugx("not listening on portal-group \"%s\", " 1777255570Strasz "not assigned to any target", 1778255570Strasz newpg->pg_name); 1779255570Strasz continue; 1780255570Strasz } 1781255570Strasz TAILQ_FOREACH(newp, &newpg->pg_portals, p_next) { 1782255570Strasz /* 1783255570Strasz * Try to find already open portal and reuse 1784255570Strasz * the listening socket. We don't care about 1785255570Strasz * what portal or portal group that was, what 1786255570Strasz * matters is the listening address. 1787255570Strasz */ 1788255570Strasz TAILQ_FOREACH(oldpg, &oldconf->conf_portal_groups, 1789255570Strasz pg_next) { 1790255570Strasz TAILQ_FOREACH(oldp, &oldpg->pg_portals, 1791255570Strasz p_next) { 1792255570Strasz if (strcmp(newp->p_listen, 1793255570Strasz oldp->p_listen) == 0 && 1794255570Strasz oldp->p_socket > 0) { 1795255570Strasz newp->p_socket = 1796255570Strasz oldp->p_socket; 1797255570Strasz oldp->p_socket = 0; 1798255570Strasz break; 1799255570Strasz } 1800255570Strasz } 1801255570Strasz } 1802255570Strasz if (newp->p_socket > 0) { 1803255570Strasz /* 1804255570Strasz * We're done with this portal. 1805255570Strasz */ 1806255570Strasz continue; 1807255570Strasz } 1808255570Strasz 1809255570Strasz#ifdef ICL_KERNEL_PROXY 1810265507Strasz if (proxy_mode) { 1811265509Strasz newpg->pg_conf->conf_portal_id++; 1812265509Strasz newp->p_id = newpg->pg_conf->conf_portal_id; 1813265509Strasz log_debugx("listening on %s, portal-group " 1814265509Strasz "\"%s\", portal id %d, using ICL proxy", 1815265509Strasz newp->p_listen, newpg->pg_name, newp->p_id); 1816265509Strasz kernel_listen(newp->p_ai, newp->p_iser, 1817265509Strasz newp->p_id); 1818265507Strasz continue; 1819265507Strasz } 1820265507Strasz#endif 1821265507Strasz assert(proxy_mode == false); 1822255570Strasz assert(newp->p_iser == false); 1823255570Strasz 1824255570Strasz log_debugx("listening on %s, portal-group \"%s\"", 1825255570Strasz newp->p_listen, newpg->pg_name); 1826255570Strasz newp->p_socket = socket(newp->p_ai->ai_family, 1827255570Strasz newp->p_ai->ai_socktype, 1828255570Strasz newp->p_ai->ai_protocol); 1829255570Strasz if (newp->p_socket < 0) { 1830255570Strasz log_warn("socket(2) failed for %s", 1831255570Strasz newp->p_listen); 1832255570Strasz cumulated_error++; 1833255570Strasz continue; 1834255570Strasz } 1835255570Strasz error = setsockopt(newp->p_socket, SOL_SOCKET, 1836255570Strasz SO_REUSEADDR, &one, sizeof(one)); 1837255570Strasz if (error != 0) { 1838255570Strasz log_warn("setsockopt(SO_REUSEADDR) failed " 1839255570Strasz "for %s", newp->p_listen); 1840255570Strasz close(newp->p_socket); 1841255570Strasz newp->p_socket = 0; 1842255570Strasz cumulated_error++; 1843255570Strasz continue; 1844255570Strasz } 1845255570Strasz error = bind(newp->p_socket, newp->p_ai->ai_addr, 1846255570Strasz newp->p_ai->ai_addrlen); 1847255570Strasz if (error != 0) { 1848255570Strasz log_warn("bind(2) failed for %s", 1849255570Strasz newp->p_listen); 1850255570Strasz close(newp->p_socket); 1851255570Strasz newp->p_socket = 0; 1852255570Strasz cumulated_error++; 1853255570Strasz continue; 1854255570Strasz } 1855255570Strasz error = listen(newp->p_socket, -1); 1856255570Strasz if (error != 0) { 1857255570Strasz log_warn("listen(2) failed for %s", 1858255570Strasz newp->p_listen); 1859255570Strasz close(newp->p_socket); 1860255570Strasz newp->p_socket = 0; 1861255570Strasz cumulated_error++; 1862255570Strasz continue; 1863255570Strasz } 1864255570Strasz } 1865255570Strasz } 1866255570Strasz 1867255570Strasz /* 1868255570Strasz * Go through the no longer used sockets, closing them. 1869255570Strasz */ 1870255570Strasz TAILQ_FOREACH(oldpg, &oldconf->conf_portal_groups, pg_next) { 1871255570Strasz TAILQ_FOREACH(oldp, &oldpg->pg_portals, p_next) { 1872255570Strasz if (oldp->p_socket <= 0) 1873255570Strasz continue; 1874255570Strasz log_debugx("closing socket for %s, portal-group \"%s\"", 1875255570Strasz oldp->p_listen, oldpg->pg_name); 1876255570Strasz close(oldp->p_socket); 1877255570Strasz oldp->p_socket = 0; 1878255570Strasz } 1879255570Strasz } 1880255570Strasz 1881274939Smav /* (Re-)Register on remaining/new iSNS servers. */ 1882274939Smav TAILQ_FOREACH(newns, &newconf->conf_isns, i_next) { 1883274939Smav TAILQ_FOREACH(oldns, &oldconf->conf_isns, i_next) { 1884274939Smav if (strcmp(oldns->i_addr, newns->i_addr) == 0) 1885274939Smav break; 1886274939Smav } 1887274939Smav isns_register(newns, oldns); 1888274939Smav } 1889274939Smav 1890274939Smav /* Schedule iSNS update */ 1891274939Smav if (!TAILQ_EMPTY(&newconf->conf_isns)) 1892274939Smav set_timeout((newconf->conf_isns_period + 2) / 3, false); 1893274939Smav 1894255570Strasz return (cumulated_error); 1895255570Strasz} 1896255570Strasz 1897255570Straszbool 1898255570Strasztimed_out(void) 1899255570Strasz{ 1900255570Strasz 1901255570Strasz return (sigalrm_received); 1902255570Strasz} 1903255570Strasz 1904255570Straszstatic void 1905274939Smavsigalrm_handler_fatal(int dummy __unused) 1906255570Strasz{ 1907255570Strasz /* 1908255570Strasz * It would be easiest to just log an error and exit. We can't 1909255570Strasz * do this, though, because log_errx() is not signal safe, since 1910255570Strasz * it calls syslog(3). Instead, set a flag checked by pdu_send() 1911255570Strasz * and pdu_receive(), to call log_errx() there. Should they fail 1912255570Strasz * to notice, we'll exit here one second later. 1913255570Strasz */ 1914255570Strasz if (sigalrm_received) { 1915255570Strasz /* 1916255570Strasz * Oh well. Just give up and quit. 1917255570Strasz */ 1918255570Strasz _exit(2); 1919255570Strasz } 1920255570Strasz 1921255570Strasz sigalrm_received = true; 1922255570Strasz} 1923255570Strasz 1924255570Straszstatic void 1925274939Smavsigalrm_handler(int dummy __unused) 1926255570Strasz{ 1927274939Smav 1928274939Smav sigalrm_received = true; 1929274939Smav} 1930274939Smav 1931274939Smavvoid 1932274939Smavset_timeout(int timeout, int fatal) 1933274939Smav{ 1934255570Strasz struct sigaction sa; 1935255570Strasz struct itimerval itv; 1936255570Strasz int error; 1937255570Strasz 1938274939Smav if (timeout <= 0) { 1939255570Strasz log_debugx("session timeout disabled"); 1940274939Smav bzero(&itv, sizeof(itv)); 1941274939Smav error = setitimer(ITIMER_REAL, &itv, NULL); 1942274939Smav if (error != 0) 1943274939Smav log_err(1, "setitimer"); 1944274939Smav sigalrm_received = false; 1945255570Strasz return; 1946255570Strasz } 1947255570Strasz 1948274939Smav sigalrm_received = false; 1949255570Strasz bzero(&sa, sizeof(sa)); 1950274939Smav if (fatal) 1951274939Smav sa.sa_handler = sigalrm_handler_fatal; 1952274939Smav else 1953274939Smav sa.sa_handler = sigalrm_handler; 1954255570Strasz sigfillset(&sa.sa_mask); 1955255570Strasz error = sigaction(SIGALRM, &sa, NULL); 1956255570Strasz if (error != 0) 1957255570Strasz log_err(1, "sigaction"); 1958255570Strasz 1959255570Strasz /* 1960255570Strasz * First SIGALRM will arive after conf_timeout seconds. 1961255570Strasz * If we do nothing, another one will arrive a second later. 1962255570Strasz */ 1963274939Smav log_debugx("setting session timeout to %d seconds", timeout); 1964255570Strasz bzero(&itv, sizeof(itv)); 1965255570Strasz itv.it_interval.tv_sec = 1; 1966274939Smav itv.it_value.tv_sec = timeout; 1967255570Strasz error = setitimer(ITIMER_REAL, &itv, NULL); 1968255570Strasz if (error != 0) 1969255570Strasz log_err(1, "setitimer"); 1970255570Strasz} 1971255570Strasz 1972255570Straszstatic int 1973255570Straszwait_for_children(bool block) 1974255570Strasz{ 1975255570Strasz pid_t pid; 1976255570Strasz int status; 1977255570Strasz int num = 0; 1978255570Strasz 1979255570Strasz for (;;) { 1980255570Strasz /* 1981255570Strasz * If "block" is true, wait for at least one process. 1982255570Strasz */ 1983255570Strasz if (block && num == 0) 1984255570Strasz pid = wait4(-1, &status, 0, NULL); 1985255570Strasz else 1986255570Strasz pid = wait4(-1, &status, WNOHANG, NULL); 1987255570Strasz if (pid <= 0) 1988255570Strasz break; 1989255570Strasz if (WIFSIGNALED(status)) { 1990255570Strasz log_warnx("child process %d terminated with signal %d", 1991255570Strasz pid, WTERMSIG(status)); 1992255570Strasz } else if (WEXITSTATUS(status) != 0) { 1993255570Strasz log_warnx("child process %d terminated with exit status %d", 1994255570Strasz pid, WEXITSTATUS(status)); 1995255570Strasz } else { 1996255570Strasz log_debugx("child process %d terminated gracefully", pid); 1997255570Strasz } 1998255570Strasz num++; 1999255570Strasz } 2000255570Strasz 2001255570Strasz return (num); 2002255570Strasz} 2003255570Strasz 2004255570Straszstatic void 2005265513Straszhandle_connection(struct portal *portal, int fd, 2006270137Smav const struct sockaddr *client_sa, bool dont_fork) 2007255570Strasz{ 2008255570Strasz struct connection *conn; 2009255570Strasz int error; 2010255570Strasz pid_t pid; 2011255570Strasz char host[NI_MAXHOST + 1]; 2012255570Strasz struct conf *conf; 2013255570Strasz 2014255570Strasz conf = portal->p_portal_group->pg_conf; 2015255570Strasz 2016255570Strasz if (dont_fork) { 2017255570Strasz log_debugx("incoming connection; not forking due to -d flag"); 2018255570Strasz } else { 2019255570Strasz nchildren -= wait_for_children(false); 2020255570Strasz assert(nchildren >= 0); 2021255570Strasz 2022255570Strasz while (conf->conf_maxproc > 0 && nchildren >= conf->conf_maxproc) { 2023255570Strasz log_debugx("maxproc limit of %d child processes hit; " 2024255570Strasz "waiting for child process to exit", conf->conf_maxproc); 2025255570Strasz nchildren -= wait_for_children(true); 2026255570Strasz assert(nchildren >= 0); 2027255570Strasz } 2028255570Strasz log_debugx("incoming connection; forking child process #%d", 2029255570Strasz nchildren); 2030255570Strasz nchildren++; 2031255570Strasz pid = fork(); 2032255570Strasz if (pid < 0) 2033255570Strasz log_err(1, "fork"); 2034255570Strasz if (pid > 0) { 2035255570Strasz close(fd); 2036255570Strasz return; 2037255570Strasz } 2038255570Strasz } 2039255570Strasz pidfile_close(conf->conf_pidfh); 2040255570Strasz 2041270137Smav error = getnameinfo(client_sa, client_sa->sa_len, 2042265513Strasz host, sizeof(host), NULL, 0, NI_NUMERICHOST); 2043265513Strasz if (error != 0) 2044265513Strasz log_errx(1, "getnameinfo: %s", gai_strerror(error)); 2045255570Strasz 2046265513Strasz log_debugx("accepted connection from %s; portal group \"%s\"", 2047265513Strasz host, portal->p_portal_group->pg_name); 2048265513Strasz log_set_peer_addr(host); 2049265513Strasz setproctitle("%s", host); 2050255570Strasz 2051270137Smav conn = connection_new(portal, fd, host, client_sa); 2052274939Smav set_timeout(conf->conf_timeout, true); 2053255570Strasz kernel_capsicate(); 2054255570Strasz login(conn); 2055255570Strasz if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) { 2056255570Strasz kernel_handoff(conn); 2057255570Strasz log_debugx("connection handed off to the kernel"); 2058255570Strasz } else { 2059255570Strasz assert(conn->conn_session_type == CONN_SESSION_TYPE_DISCOVERY); 2060255570Strasz discovery(conn); 2061255570Strasz } 2062255570Strasz log_debugx("nothing more to do; exiting"); 2063255570Strasz exit(0); 2064255570Strasz} 2065255570Strasz 2066255570Straszstatic int 2067255570Straszfd_add(int fd, fd_set *fdset, int nfds) 2068255570Strasz{ 2069255570Strasz 2070255570Strasz /* 2071255570Strasz * Skip sockets which we failed to bind. 2072255570Strasz */ 2073255570Strasz if (fd <= 0) 2074255570Strasz return (nfds); 2075255570Strasz 2076255570Strasz FD_SET(fd, fdset); 2077255570Strasz if (fd > nfds) 2078255570Strasz nfds = fd; 2079255570Strasz return (nfds); 2080255570Strasz} 2081255570Strasz 2082255570Straszstatic void 2083255570Straszmain_loop(struct conf *conf, bool dont_fork) 2084255570Strasz{ 2085255570Strasz struct portal_group *pg; 2086255570Strasz struct portal *portal; 2087265512Strasz struct sockaddr_storage client_sa; 2088265512Strasz socklen_t client_salen; 2089255570Strasz#ifdef ICL_KERNEL_PROXY 2090255570Strasz int connection_id; 2091265509Strasz int portal_id; 2092265507Strasz#endif 2093255570Strasz fd_set fdset; 2094255570Strasz int error, nfds, client_fd; 2095255570Strasz 2096255570Strasz pidfile_write(conf->conf_pidfh); 2097255570Strasz 2098255570Strasz for (;;) { 2099274939Smav if (sighup_received || sigterm_received || timed_out()) 2100255570Strasz return; 2101255570Strasz 2102255570Strasz#ifdef ICL_KERNEL_PROXY 2103265507Strasz if (proxy_mode) { 2104265513Strasz client_salen = sizeof(client_sa); 2105265513Strasz kernel_accept(&connection_id, &portal_id, 2106265513Strasz (struct sockaddr *)&client_sa, &client_salen); 2107271627Strasz assert(client_salen >= client_sa.ss_len); 2108255570Strasz 2109265509Strasz log_debugx("incoming connection, id %d, portal id %d", 2110265509Strasz connection_id, portal_id); 2111265509Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 2112265509Strasz TAILQ_FOREACH(portal, &pg->pg_portals, p_next) { 2113265509Strasz if (portal->p_id == portal_id) { 2114265509Strasz goto found; 2115265509Strasz } 2116265509Strasz } 2117265509Strasz } 2118255570Strasz 2119265509Strasz log_errx(1, "kernel returned invalid portal_id %d", 2120265509Strasz portal_id); 2121265509Strasz 2122265509Straszfound: 2123265513Strasz handle_connection(portal, connection_id, 2124270137Smav (struct sockaddr *)&client_sa, dont_fork); 2125265507Strasz } else { 2126265507Strasz#endif 2127265507Strasz assert(proxy_mode == false); 2128265507Strasz 2129265507Strasz FD_ZERO(&fdset); 2130265507Strasz nfds = 0; 2131265507Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 2132265507Strasz TAILQ_FOREACH(portal, &pg->pg_portals, p_next) 2133265507Strasz nfds = fd_add(portal->p_socket, &fdset, nfds); 2134255570Strasz } 2135265507Strasz error = select(nfds + 1, &fdset, NULL, NULL, NULL); 2136265507Strasz if (error <= 0) { 2137265507Strasz if (errno == EINTR) 2138265507Strasz return; 2139265507Strasz log_err(1, "select"); 2140265507Strasz } 2141265507Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 2142265507Strasz TAILQ_FOREACH(portal, &pg->pg_portals, p_next) { 2143265507Strasz if (!FD_ISSET(portal->p_socket, &fdset)) 2144265507Strasz continue; 2145265512Strasz client_salen = sizeof(client_sa); 2146265512Strasz client_fd = accept(portal->p_socket, 2147265512Strasz (struct sockaddr *)&client_sa, 2148265512Strasz &client_salen); 2149265507Strasz if (client_fd < 0) 2150265507Strasz log_err(1, "accept"); 2151271627Strasz assert(client_salen >= client_sa.ss_len); 2152271627Strasz 2153265512Strasz handle_connection(portal, client_fd, 2154265513Strasz (struct sockaddr *)&client_sa, 2155270137Smav dont_fork); 2156265507Strasz break; 2157265507Strasz } 2158265507Strasz } 2159265507Strasz#ifdef ICL_KERNEL_PROXY 2160255570Strasz } 2161265507Strasz#endif 2162255570Strasz } 2163255570Strasz} 2164255570Strasz 2165255570Straszstatic void 2166255570Straszsighup_handler(int dummy __unused) 2167255570Strasz{ 2168255570Strasz 2169255570Strasz sighup_received = true; 2170255570Strasz} 2171255570Strasz 2172255570Straszstatic void 2173255570Straszsigterm_handler(int dummy __unused) 2174255570Strasz{ 2175255570Strasz 2176255570Strasz sigterm_received = true; 2177255570Strasz} 2178255570Strasz 2179255570Straszstatic void 2180263730Straszsigchld_handler(int dummy __unused) 2181263730Strasz{ 2182263730Strasz 2183263730Strasz /* 2184263730Strasz * The only purpose of this handler is to make SIGCHLD 2185263730Strasz * interrupt the ISCSIDWAIT ioctl(2), so we can call 2186263730Strasz * wait_for_children(). 2187263730Strasz */ 2188263730Strasz} 2189263730Strasz 2190263730Straszstatic void 2191255570Straszregister_signals(void) 2192255570Strasz{ 2193255570Strasz struct sigaction sa; 2194255570Strasz int error; 2195255570Strasz 2196255570Strasz bzero(&sa, sizeof(sa)); 2197255570Strasz sa.sa_handler = sighup_handler; 2198255570Strasz sigfillset(&sa.sa_mask); 2199255570Strasz error = sigaction(SIGHUP, &sa, NULL); 2200255570Strasz if (error != 0) 2201255570Strasz log_err(1, "sigaction"); 2202255570Strasz 2203255570Strasz sa.sa_handler = sigterm_handler; 2204255570Strasz error = sigaction(SIGTERM, &sa, NULL); 2205255570Strasz if (error != 0) 2206255570Strasz log_err(1, "sigaction"); 2207255570Strasz 2208255570Strasz sa.sa_handler = sigterm_handler; 2209255570Strasz error = sigaction(SIGINT, &sa, NULL); 2210255570Strasz if (error != 0) 2211255570Strasz log_err(1, "sigaction"); 2212263730Strasz 2213263730Strasz sa.sa_handler = sigchld_handler; 2214263730Strasz error = sigaction(SIGCHLD, &sa, NULL); 2215263730Strasz if (error != 0) 2216263730Strasz log_err(1, "sigaction"); 2217255570Strasz} 2218255570Strasz 2219255570Straszint 2220255570Straszmain(int argc, char **argv) 2221255570Strasz{ 2222255570Strasz struct conf *oldconf, *newconf, *tmpconf; 2223274939Smav struct isns *newns; 2224255570Strasz const char *config_path = DEFAULT_CONFIG_PATH; 2225255570Strasz int debug = 0, ch, error; 2226255570Strasz bool dont_daemonize = false; 2227255570Strasz 2228265507Strasz while ((ch = getopt(argc, argv, "df:R")) != -1) { 2229255570Strasz switch (ch) { 2230255570Strasz case 'd': 2231255570Strasz dont_daemonize = true; 2232255570Strasz debug++; 2233255570Strasz break; 2234255570Strasz case 'f': 2235255570Strasz config_path = optarg; 2236255570Strasz break; 2237265507Strasz case 'R': 2238265507Strasz#ifndef ICL_KERNEL_PROXY 2239265507Strasz log_errx(1, "ctld(8) compiled without ICL_KERNEL_PROXY " 2240265507Strasz "does not support iSER protocol"); 2241265507Strasz#endif 2242265507Strasz proxy_mode = true; 2243265507Strasz break; 2244255570Strasz case '?': 2245255570Strasz default: 2246255570Strasz usage(); 2247255570Strasz } 2248255570Strasz } 2249255570Strasz argc -= optind; 2250255570Strasz if (argc != 0) 2251255570Strasz usage(); 2252255570Strasz 2253255570Strasz log_init(debug); 2254255570Strasz kernel_init(); 2255255570Strasz 2256255570Strasz oldconf = conf_new_from_kernel(); 2257255570Strasz newconf = conf_new_from_file(config_path); 2258255570Strasz if (newconf == NULL) 2259265516Strasz log_errx(1, "configuration error; exiting"); 2260255570Strasz if (debug > 0) { 2261255570Strasz oldconf->conf_debug = debug; 2262255570Strasz newconf->conf_debug = debug; 2263255570Strasz } 2264255570Strasz 2265255570Strasz error = conf_apply(oldconf, newconf); 2266255570Strasz if (error != 0) 2267265516Strasz log_errx(1, "failed to apply configuration; exiting"); 2268265516Strasz 2269255570Strasz conf_delete(oldconf); 2270255570Strasz oldconf = NULL; 2271255570Strasz 2272255570Strasz register_signals(); 2273255570Strasz 2274263719Strasz if (dont_daemonize == false) { 2275263719Strasz log_debugx("daemonizing"); 2276263719Strasz if (daemon(0, 0) == -1) { 2277263719Strasz log_warn("cannot daemonize"); 2278263719Strasz pidfile_remove(newconf->conf_pidfh); 2279263719Strasz exit(1); 2280263719Strasz } 2281263719Strasz } 2282263719Strasz 2283274939Smav /* Schedule iSNS update */ 2284274939Smav if (!TAILQ_EMPTY(&newconf->conf_isns)) 2285274939Smav set_timeout((newconf->conf_isns_period + 2) / 3, false); 2286274939Smav 2287255570Strasz for (;;) { 2288255570Strasz main_loop(newconf, dont_daemonize); 2289255570Strasz if (sighup_received) { 2290255570Strasz sighup_received = false; 2291255570Strasz log_debugx("received SIGHUP, reloading configuration"); 2292255570Strasz tmpconf = conf_new_from_file(config_path); 2293255570Strasz if (tmpconf == NULL) { 2294255570Strasz log_warnx("configuration error, " 2295255570Strasz "continuing with old configuration"); 2296255570Strasz } else { 2297255570Strasz if (debug > 0) 2298255570Strasz tmpconf->conf_debug = debug; 2299255570Strasz oldconf = newconf; 2300255570Strasz newconf = tmpconf; 2301255570Strasz error = conf_apply(oldconf, newconf); 2302255570Strasz if (error != 0) 2303255570Strasz log_warnx("failed to reload " 2304255570Strasz "configuration"); 2305255570Strasz conf_delete(oldconf); 2306255570Strasz oldconf = NULL; 2307255570Strasz } 2308255570Strasz } else if (sigterm_received) { 2309255570Strasz log_debugx("exiting on signal; " 2310255570Strasz "reloading empty configuration"); 2311255570Strasz 2312255570Strasz log_debugx("disabling CTL iSCSI port " 2313255570Strasz "and terminating all connections"); 2314255570Strasz 2315255570Strasz oldconf = newconf; 2316255570Strasz newconf = conf_new(); 2317255570Strasz if (debug > 0) 2318255570Strasz newconf->conf_debug = debug; 2319255570Strasz error = conf_apply(oldconf, newconf); 2320255570Strasz if (error != 0) 2321255570Strasz log_warnx("failed to apply configuration"); 2322274939Smav conf_delete(oldconf); 2323274939Smav oldconf = NULL; 2324255570Strasz 2325255570Strasz log_warnx("exiting on signal"); 2326255570Strasz exit(0); 2327255570Strasz } else { 2328255570Strasz nchildren -= wait_for_children(false); 2329255570Strasz assert(nchildren >= 0); 2330274939Smav if (timed_out()) { 2331274939Smav set_timeout(0, false); 2332274939Smav TAILQ_FOREACH(newns, &newconf->conf_isns, i_next) 2333274939Smav isns_check(newns); 2334274939Smav /* Schedule iSNS update */ 2335274939Smav if (!TAILQ_EMPTY(&newconf->conf_isns)) { 2336274939Smav set_timeout((newconf->conf_isns_period 2337274939Smav + 2) / 3, 2338274939Smav false); 2339274939Smav } 2340274939Smav } 2341255570Strasz } 2342255570Strasz } 2343255570Strasz /* NOTREACHED */ 2344255570Strasz} 2345