ctld.c revision 279006
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 279006 2015-02-19 14:52:01Z 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; 62279003Smavstatic uint16_t last_portal_group_tag = 0; 63255570Strasz 64255570Straszstatic void 65255570Straszusage(void) 66255570Strasz{ 67255570Strasz 68255570Strasz fprintf(stderr, "usage: ctld [-d][-f config-file]\n"); 69255570Strasz exit(1); 70255570Strasz} 71255570Strasz 72255570Straszchar * 73255570Straszchecked_strdup(const char *s) 74255570Strasz{ 75255570Strasz char *c; 76255570Strasz 77255570Strasz c = strdup(s); 78255570Strasz if (c == NULL) 79255570Strasz log_err(1, "strdup"); 80255570Strasz return (c); 81255570Strasz} 82255570Strasz 83255570Straszstruct conf * 84255570Straszconf_new(void) 85255570Strasz{ 86255570Strasz struct conf *conf; 87255570Strasz 88255570Strasz conf = calloc(1, sizeof(*conf)); 89255570Strasz if (conf == NULL) 90255570Strasz log_err(1, "calloc"); 91279002Smav TAILQ_INIT(&conf->conf_luns); 92255570Strasz TAILQ_INIT(&conf->conf_targets); 93255570Strasz TAILQ_INIT(&conf->conf_auth_groups); 94279006Smav TAILQ_INIT(&conf->conf_ports); 95255570Strasz TAILQ_INIT(&conf->conf_portal_groups); 96274939Smav TAILQ_INIT(&conf->conf_isns); 97255570Strasz 98274939Smav conf->conf_isns_period = 900; 99274939Smav conf->conf_isns_timeout = 5; 100255570Strasz conf->conf_debug = 0; 101255570Strasz conf->conf_timeout = 60; 102255570Strasz conf->conf_maxproc = 30; 103255570Strasz 104255570Strasz return (conf); 105255570Strasz} 106255570Strasz 107255570Straszvoid 108255570Straszconf_delete(struct conf *conf) 109255570Strasz{ 110279002Smav struct lun *lun, *ltmp; 111255570Strasz struct target *targ, *tmp; 112255570Strasz struct auth_group *ag, *cagtmp; 113255570Strasz struct portal_group *pg, *cpgtmp; 114274939Smav struct isns *is, *istmp; 115255570Strasz 116255570Strasz assert(conf->conf_pidfh == NULL); 117255570Strasz 118279002Smav TAILQ_FOREACH_SAFE(lun, &conf->conf_luns, l_next, ltmp) 119279002Smav lun_delete(lun); 120255570Strasz TAILQ_FOREACH_SAFE(targ, &conf->conf_targets, t_next, tmp) 121255570Strasz target_delete(targ); 122255570Strasz TAILQ_FOREACH_SAFE(ag, &conf->conf_auth_groups, ag_next, cagtmp) 123255570Strasz auth_group_delete(ag); 124255570Strasz TAILQ_FOREACH_SAFE(pg, &conf->conf_portal_groups, pg_next, cpgtmp) 125255570Strasz portal_group_delete(pg); 126274939Smav TAILQ_FOREACH_SAFE(is, &conf->conf_isns, i_next, istmp) 127274939Smav isns_delete(is); 128279006Smav assert(TAILQ_EMPTY(&conf->conf_ports)); 129255570Strasz free(conf->conf_pidfile_path); 130255570Strasz free(conf); 131255570Strasz} 132255570Strasz 133255570Straszstatic struct auth * 134255570Straszauth_new(struct auth_group *ag) 135255570Strasz{ 136255570Strasz struct auth *auth; 137255570Strasz 138255570Strasz auth = calloc(1, sizeof(*auth)); 139255570Strasz if (auth == NULL) 140255570Strasz log_err(1, "calloc"); 141255570Strasz auth->a_auth_group = ag; 142255570Strasz TAILQ_INSERT_TAIL(&ag->ag_auths, auth, a_next); 143255570Strasz return (auth); 144255570Strasz} 145255570Strasz 146255570Straszstatic void 147255570Straszauth_delete(struct auth *auth) 148255570Strasz{ 149255570Strasz TAILQ_REMOVE(&auth->a_auth_group->ag_auths, auth, a_next); 150255570Strasz 151255570Strasz free(auth->a_user); 152255570Strasz free(auth->a_secret); 153255570Strasz free(auth->a_mutual_user); 154255570Strasz free(auth->a_mutual_secret); 155255570Strasz free(auth); 156255570Strasz} 157255570Strasz 158255570Straszconst struct auth * 159265514Straszauth_find(const struct auth_group *ag, const char *user) 160255570Strasz{ 161255570Strasz const struct auth *auth; 162255570Strasz 163255570Strasz TAILQ_FOREACH(auth, &ag->ag_auths, a_next) { 164255570Strasz if (strcmp(auth->a_user, user) == 0) 165255570Strasz return (auth); 166255570Strasz } 167255570Strasz 168255570Strasz return (NULL); 169255570Strasz} 170255570Strasz 171263721Straszstatic void 172263721Straszauth_check_secret_length(struct auth *auth) 173263721Strasz{ 174263721Strasz size_t len; 175263721Strasz 176263721Strasz len = strlen(auth->a_secret); 177263721Strasz if (len > 16) { 178263721Strasz if (auth->a_auth_group->ag_name != NULL) 179263721Strasz log_warnx("secret for user \"%s\", auth-group \"%s\", " 180263721Strasz "is too long; it should be at most 16 characters " 181263721Strasz "long", auth->a_user, auth->a_auth_group->ag_name); 182263721Strasz else 183263721Strasz log_warnx("secret for user \"%s\", target \"%s\", " 184263721Strasz "is too long; it should be at most 16 characters " 185263721Strasz "long", auth->a_user, 186263723Strasz auth->a_auth_group->ag_target->t_name); 187263721Strasz } 188263721Strasz if (len < 12) { 189263721Strasz if (auth->a_auth_group->ag_name != NULL) 190263721Strasz log_warnx("secret for user \"%s\", auth-group \"%s\", " 191263721Strasz "is too short; it should be at least 12 characters " 192263721Strasz "long", auth->a_user, 193263721Strasz auth->a_auth_group->ag_name); 194263721Strasz else 195263721Strasz log_warnx("secret for user \"%s\", target \"%s\", " 196263721Strasz "is too short; it should be at least 16 characters " 197263721Strasz "long", auth->a_user, 198263723Strasz auth->a_auth_group->ag_target->t_name); 199263721Strasz } 200263721Strasz 201263721Strasz if (auth->a_mutual_secret != NULL) { 202263721Strasz len = strlen(auth->a_secret); 203263721Strasz if (len > 16) { 204263721Strasz if (auth->a_auth_group->ag_name != NULL) 205263721Strasz log_warnx("mutual secret for user \"%s\", " 206263721Strasz "auth-group \"%s\", is too long; it should " 207263721Strasz "be at most 16 characters long", 208263721Strasz auth->a_user, auth->a_auth_group->ag_name); 209263721Strasz else 210263721Strasz log_warnx("mutual secret for user \"%s\", " 211263721Strasz "target \"%s\", is too long; it should " 212263721Strasz "be at most 16 characters long", 213263721Strasz auth->a_user, 214263723Strasz auth->a_auth_group->ag_target->t_name); 215263721Strasz } 216263721Strasz if (len < 12) { 217263721Strasz if (auth->a_auth_group->ag_name != NULL) 218263721Strasz log_warnx("mutual secret for user \"%s\", " 219263721Strasz "auth-group \"%s\", is too short; it " 220263721Strasz "should be at least 12 characters long", 221263721Strasz auth->a_user, auth->a_auth_group->ag_name); 222263721Strasz else 223263721Strasz log_warnx("mutual secret for user \"%s\", " 224263721Strasz "target \"%s\", is too short; it should be " 225263721Strasz "at least 16 characters long", 226263721Strasz auth->a_user, 227263723Strasz auth->a_auth_group->ag_target->t_name); 228263721Strasz } 229263721Strasz } 230263721Strasz} 231263721Strasz 232263721Straszconst struct auth * 233263721Straszauth_new_chap(struct auth_group *ag, const char *user, 234263721Strasz const char *secret) 235263721Strasz{ 236263721Strasz struct auth *auth; 237263721Strasz 238263721Strasz if (ag->ag_type == AG_TYPE_UNKNOWN) 239263721Strasz ag->ag_type = AG_TYPE_CHAP; 240263721Strasz if (ag->ag_type != AG_TYPE_CHAP) { 241263721Strasz if (ag->ag_name != NULL) 242263721Strasz log_warnx("cannot mix \"chap\" authentication with " 243263721Strasz "other types for auth-group \"%s\"", ag->ag_name); 244263721Strasz else 245263721Strasz log_warnx("cannot mix \"chap\" authentication with " 246263721Strasz "other types for target \"%s\"", 247263723Strasz ag->ag_target->t_name); 248263721Strasz return (NULL); 249263721Strasz } 250263721Strasz 251263721Strasz auth = auth_new(ag); 252263721Strasz auth->a_user = checked_strdup(user); 253263721Strasz auth->a_secret = checked_strdup(secret); 254263721Strasz 255263721Strasz auth_check_secret_length(auth); 256263721Strasz 257263721Strasz return (auth); 258263721Strasz} 259263721Strasz 260263721Straszconst struct auth * 261263721Straszauth_new_chap_mutual(struct auth_group *ag, const char *user, 262263721Strasz const char *secret, const char *user2, const char *secret2) 263263721Strasz{ 264263721Strasz struct auth *auth; 265263721Strasz 266263721Strasz if (ag->ag_type == AG_TYPE_UNKNOWN) 267263721Strasz ag->ag_type = AG_TYPE_CHAP_MUTUAL; 268263721Strasz if (ag->ag_type != AG_TYPE_CHAP_MUTUAL) { 269263721Strasz if (ag->ag_name != NULL) 270263721Strasz log_warnx("cannot mix \"chap-mutual\" authentication " 271263721Strasz "with other types for auth-group \"%s\"", 272274870Strasz ag->ag_name); 273263721Strasz else 274263721Strasz log_warnx("cannot mix \"chap-mutual\" authentication " 275263721Strasz "with other types for target \"%s\"", 276263723Strasz ag->ag_target->t_name); 277263721Strasz return (NULL); 278263721Strasz } 279263721Strasz 280263721Strasz auth = auth_new(ag); 281263721Strasz auth->a_user = checked_strdup(user); 282263721Strasz auth->a_secret = checked_strdup(secret); 283263721Strasz auth->a_mutual_user = checked_strdup(user2); 284263721Strasz auth->a_mutual_secret = checked_strdup(secret2); 285263721Strasz 286263721Strasz auth_check_secret_length(auth); 287263721Strasz 288263721Strasz return (auth); 289263721Strasz} 290263721Strasz 291263720Straszconst struct auth_name * 292263720Straszauth_name_new(struct auth_group *ag, const char *name) 293263720Strasz{ 294263720Strasz struct auth_name *an; 295263720Strasz 296263720Strasz an = calloc(1, sizeof(*an)); 297263720Strasz if (an == NULL) 298263720Strasz log_err(1, "calloc"); 299263720Strasz an->an_auth_group = ag; 300263720Strasz an->an_initator_name = checked_strdup(name); 301263720Strasz TAILQ_INSERT_TAIL(&ag->ag_names, an, an_next); 302263720Strasz return (an); 303263720Strasz} 304263720Strasz 305263720Straszstatic void 306263720Straszauth_name_delete(struct auth_name *an) 307263720Strasz{ 308263720Strasz TAILQ_REMOVE(&an->an_auth_group->ag_names, an, an_next); 309263720Strasz 310263720Strasz free(an->an_initator_name); 311263720Strasz free(an); 312263720Strasz} 313263720Strasz 314263720Straszbool 315263720Straszauth_name_defined(const struct auth_group *ag) 316263720Strasz{ 317263720Strasz if (TAILQ_EMPTY(&ag->ag_names)) 318263720Strasz return (false); 319263720Strasz return (true); 320263720Strasz} 321263720Strasz 322263720Straszconst struct auth_name * 323263720Straszauth_name_find(const struct auth_group *ag, const char *name) 324263720Strasz{ 325263720Strasz const struct auth_name *auth_name; 326263720Strasz 327263720Strasz TAILQ_FOREACH(auth_name, &ag->ag_names, an_next) { 328263720Strasz if (strcmp(auth_name->an_initator_name, name) == 0) 329263720Strasz return (auth_name); 330263720Strasz } 331263720Strasz 332263720Strasz return (NULL); 333263720Strasz} 334263720Strasz 335274949Straszint 336274949Straszauth_name_check(const struct auth_group *ag, const char *initiator_name) 337274949Strasz{ 338274949Strasz if (!auth_name_defined(ag)) 339274949Strasz return (0); 340274949Strasz 341274949Strasz if (auth_name_find(ag, initiator_name) == NULL) 342274949Strasz return (1); 343274949Strasz 344274949Strasz return (0); 345274949Strasz} 346274949Strasz 347263720Straszconst struct auth_portal * 348263720Straszauth_portal_new(struct auth_group *ag, const char *portal) 349263720Strasz{ 350263720Strasz struct auth_portal *ap; 351270137Smav char *net, *mask, *str, *tmp; 352270137Smav int len, dm, m; 353263720Strasz 354263720Strasz ap = calloc(1, sizeof(*ap)); 355263720Strasz if (ap == NULL) 356263720Strasz log_err(1, "calloc"); 357263720Strasz ap->ap_auth_group = ag; 358263720Strasz ap->ap_initator_portal = checked_strdup(portal); 359270137Smav mask = str = checked_strdup(portal); 360270137Smav net = strsep(&mask, "/"); 361270137Smav if (net[0] == '[') 362270137Smav net++; 363270137Smav len = strlen(net); 364270137Smav if (len == 0) 365270137Smav goto error; 366270137Smav if (net[len - 1] == ']') 367270137Smav net[len - 1] = 0; 368270137Smav if (strchr(net, ':') != NULL) { 369270137Smav struct sockaddr_in6 *sin6 = 370270137Smav (struct sockaddr_in6 *)&ap->ap_sa; 371270137Smav 372270137Smav sin6->sin6_len = sizeof(*sin6); 373270137Smav sin6->sin6_family = AF_INET6; 374270137Smav if (inet_pton(AF_INET6, net, &sin6->sin6_addr) <= 0) 375270137Smav goto error; 376270137Smav dm = 128; 377270137Smav } else { 378270137Smav struct sockaddr_in *sin = 379270137Smav (struct sockaddr_in *)&ap->ap_sa; 380270137Smav 381270137Smav sin->sin_len = sizeof(*sin); 382270137Smav sin->sin_family = AF_INET; 383270137Smav if (inet_pton(AF_INET, net, &sin->sin_addr) <= 0) 384270137Smav goto error; 385270137Smav dm = 32; 386270137Smav } 387270137Smav if (mask != NULL) { 388270137Smav m = strtol(mask, &tmp, 0); 389270137Smav if (m < 0 || m > dm || tmp[0] != 0) 390270137Smav goto error; 391270137Smav } else 392270137Smav m = dm; 393270137Smav ap->ap_mask = m; 394270137Smav free(str); 395263720Strasz TAILQ_INSERT_TAIL(&ag->ag_portals, ap, ap_next); 396263720Strasz return (ap); 397270137Smav 398270137Smaverror: 399270137Smav log_errx(1, "Incorrect initiator portal '%s'", portal); 400270137Smav return (NULL); 401263720Strasz} 402263720Strasz 403263720Straszstatic void 404263720Straszauth_portal_delete(struct auth_portal *ap) 405263720Strasz{ 406263720Strasz TAILQ_REMOVE(&ap->ap_auth_group->ag_portals, ap, ap_next); 407263720Strasz 408263720Strasz free(ap->ap_initator_portal); 409263720Strasz free(ap); 410263720Strasz} 411263720Strasz 412263720Straszbool 413263720Straszauth_portal_defined(const struct auth_group *ag) 414263720Strasz{ 415263720Strasz if (TAILQ_EMPTY(&ag->ag_portals)) 416263720Strasz return (false); 417263720Strasz return (true); 418263720Strasz} 419263720Strasz 420263720Straszconst struct auth_portal * 421270137Smavauth_portal_find(const struct auth_group *ag, const struct sockaddr_storage *ss) 422263720Strasz{ 423270137Smav const struct auth_portal *ap; 424270137Smav const uint8_t *a, *b; 425270137Smav int i; 426270137Smav uint8_t bmask; 427263720Strasz 428270137Smav TAILQ_FOREACH(ap, &ag->ag_portals, ap_next) { 429270137Smav if (ap->ap_sa.ss_family != ss->ss_family) 430270137Smav continue; 431270137Smav if (ss->ss_family == AF_INET) { 432270137Smav a = (const uint8_t *) 433270137Smav &((const struct sockaddr_in *)ss)->sin_addr; 434270137Smav b = (const uint8_t *) 435270137Smav &((const struct sockaddr_in *)&ap->ap_sa)->sin_addr; 436270137Smav } else { 437270137Smav a = (const uint8_t *) 438270137Smav &((const struct sockaddr_in6 *)ss)->sin6_addr; 439270137Smav b = (const uint8_t *) 440270137Smav &((const struct sockaddr_in6 *)&ap->ap_sa)->sin6_addr; 441270137Smav } 442270137Smav for (i = 0; i < ap->ap_mask / 8; i++) { 443270137Smav if (a[i] != b[i]) 444270137Smav goto next; 445270137Smav } 446270137Smav if (ap->ap_mask % 8) { 447270137Smav bmask = 0xff << (8 - (ap->ap_mask % 8)); 448270137Smav if ((a[i] & bmask) != (b[i] & bmask)) 449270137Smav goto next; 450270137Smav } 451270137Smav return (ap); 452270137Smavnext: 453270137Smav ; 454263720Strasz } 455263720Strasz 456263720Strasz return (NULL); 457263720Strasz} 458263720Strasz 459274949Straszint 460274949Straszauth_portal_check(const struct auth_group *ag, const struct sockaddr_storage *sa) 461274949Strasz{ 462274949Strasz 463274949Strasz if (!auth_portal_defined(ag)) 464274949Strasz return (0); 465274949Strasz 466274949Strasz if (auth_portal_find(ag, sa) == NULL) 467274949Strasz return (1); 468274949Strasz 469274949Strasz return (0); 470274949Strasz} 471274949Strasz 472255570Straszstruct auth_group * 473255570Straszauth_group_new(struct conf *conf, const char *name) 474255570Strasz{ 475255570Strasz struct auth_group *ag; 476255570Strasz 477255570Strasz if (name != NULL) { 478255570Strasz ag = auth_group_find(conf, name); 479255570Strasz if (ag != NULL) { 480255570Strasz log_warnx("duplicated auth-group \"%s\"", name); 481255570Strasz return (NULL); 482255570Strasz } 483255570Strasz } 484255570Strasz 485255570Strasz ag = calloc(1, sizeof(*ag)); 486255570Strasz if (ag == NULL) 487255570Strasz log_err(1, "calloc"); 488255570Strasz if (name != NULL) 489255570Strasz ag->ag_name = checked_strdup(name); 490255570Strasz TAILQ_INIT(&ag->ag_auths); 491263720Strasz TAILQ_INIT(&ag->ag_names); 492263720Strasz TAILQ_INIT(&ag->ag_portals); 493255570Strasz ag->ag_conf = conf; 494255570Strasz TAILQ_INSERT_TAIL(&conf->conf_auth_groups, ag, ag_next); 495255570Strasz 496255570Strasz return (ag); 497255570Strasz} 498255570Strasz 499255570Straszvoid 500255570Straszauth_group_delete(struct auth_group *ag) 501255570Strasz{ 502263720Strasz struct auth *auth, *auth_tmp; 503263720Strasz struct auth_name *auth_name, *auth_name_tmp; 504263720Strasz struct auth_portal *auth_portal, *auth_portal_tmp; 505255570Strasz 506255570Strasz TAILQ_REMOVE(&ag->ag_conf->conf_auth_groups, ag, ag_next); 507255570Strasz 508263720Strasz TAILQ_FOREACH_SAFE(auth, &ag->ag_auths, a_next, auth_tmp) 509255570Strasz auth_delete(auth); 510263720Strasz TAILQ_FOREACH_SAFE(auth_name, &ag->ag_names, an_next, auth_name_tmp) 511263720Strasz auth_name_delete(auth_name); 512263720Strasz TAILQ_FOREACH_SAFE(auth_portal, &ag->ag_portals, ap_next, 513263720Strasz auth_portal_tmp) 514263720Strasz auth_portal_delete(auth_portal); 515255570Strasz free(ag->ag_name); 516255570Strasz free(ag); 517255570Strasz} 518255570Strasz 519255570Straszstruct auth_group * 520265514Straszauth_group_find(const struct conf *conf, const char *name) 521255570Strasz{ 522255570Strasz struct auth_group *ag; 523255570Strasz 524255570Strasz TAILQ_FOREACH(ag, &conf->conf_auth_groups, ag_next) { 525255570Strasz if (ag->ag_name != NULL && strcmp(ag->ag_name, name) == 0) 526255570Strasz return (ag); 527255570Strasz } 528255570Strasz 529255570Strasz return (NULL); 530255570Strasz} 531255570Strasz 532263724Straszint 533275245Straszauth_group_set_type(struct auth_group *ag, const char *str) 534263724Strasz{ 535275245Strasz int type; 536263724Strasz 537263724Strasz if (strcmp(str, "none") == 0) { 538263724Strasz type = AG_TYPE_NO_AUTHENTICATION; 539263729Strasz } else if (strcmp(str, "deny") == 0) { 540263729Strasz type = AG_TYPE_DENY; 541263724Strasz } else if (strcmp(str, "chap") == 0) { 542263724Strasz type = AG_TYPE_CHAP; 543263724Strasz } else if (strcmp(str, "chap-mutual") == 0) { 544263724Strasz type = AG_TYPE_CHAP_MUTUAL; 545263724Strasz } else { 546263724Strasz if (ag->ag_name != NULL) 547263724Strasz log_warnx("invalid auth-type \"%s\" for auth-group " 548263724Strasz "\"%s\"", str, ag->ag_name); 549263724Strasz else 550263724Strasz log_warnx("invalid auth-type \"%s\" for target " 551263724Strasz "\"%s\"", str, ag->ag_target->t_name); 552263724Strasz return (1); 553263724Strasz } 554263724Strasz 555275245Strasz if (ag->ag_type != AG_TYPE_UNKNOWN && ag->ag_type != type) { 556275245Strasz if (ag->ag_name != NULL) { 557263724Strasz log_warnx("cannot set auth-type to \"%s\" for " 558263724Strasz "auth-group \"%s\"; already has a different " 559263724Strasz "type", str, ag->ag_name); 560275245Strasz } else { 561263724Strasz log_warnx("cannot set auth-type to \"%s\" for target " 562263724Strasz "\"%s\"; already has a different type", 563263724Strasz str, ag->ag_target->t_name); 564275245Strasz } 565263724Strasz return (1); 566263724Strasz } 567263724Strasz 568275245Strasz ag->ag_type = type; 569275245Strasz 570275245Strasz return (0); 571263724Strasz} 572263724Strasz 573255570Straszstatic struct portal * 574255570Straszportal_new(struct portal_group *pg) 575255570Strasz{ 576255570Strasz struct portal *portal; 577255570Strasz 578255570Strasz portal = calloc(1, sizeof(*portal)); 579255570Strasz if (portal == NULL) 580255570Strasz log_err(1, "calloc"); 581255570Strasz TAILQ_INIT(&portal->p_targets); 582255570Strasz portal->p_portal_group = pg; 583255570Strasz TAILQ_INSERT_TAIL(&pg->pg_portals, portal, p_next); 584255570Strasz return (portal); 585255570Strasz} 586255570Strasz 587255570Straszstatic void 588255570Straszportal_delete(struct portal *portal) 589255570Strasz{ 590271632Strasz 591255570Strasz TAILQ_REMOVE(&portal->p_portal_group->pg_portals, portal, p_next); 592271632Strasz if (portal->p_ai != NULL) 593271632Strasz freeaddrinfo(portal->p_ai); 594255570Strasz free(portal->p_listen); 595255570Strasz free(portal); 596255570Strasz} 597255570Strasz 598255570Straszstruct portal_group * 599255570Straszportal_group_new(struct conf *conf, const char *name) 600255570Strasz{ 601255570Strasz struct portal_group *pg; 602255570Strasz 603255678Strasz pg = portal_group_find(conf, name); 604255678Strasz if (pg != NULL) { 605255678Strasz log_warnx("duplicated portal-group \"%s\"", name); 606255678Strasz return (NULL); 607255570Strasz } 608255570Strasz 609255570Strasz pg = calloc(1, sizeof(*pg)); 610255570Strasz if (pg == NULL) 611255570Strasz log_err(1, "calloc"); 612255570Strasz pg->pg_name = checked_strdup(name); 613255570Strasz TAILQ_INIT(&pg->pg_portals); 614279006Smav TAILQ_INIT(&pg->pg_ports); 615255570Strasz pg->pg_conf = conf; 616279003Smav pg->pg_tag = 0; /* Assigned later in conf_apply(). */ 617255570Strasz TAILQ_INSERT_TAIL(&conf->conf_portal_groups, pg, pg_next); 618255570Strasz 619255570Strasz return (pg); 620255570Strasz} 621255570Strasz 622255570Straszvoid 623255570Straszportal_group_delete(struct portal_group *pg) 624255570Strasz{ 625255570Strasz struct portal *portal, *tmp; 626279006Smav struct port *port, *tport; 627255570Strasz 628279006Smav TAILQ_FOREACH_SAFE(port, &pg->pg_ports, p_pgs, tport) 629279006Smav port_delete(port); 630255570Strasz TAILQ_REMOVE(&pg->pg_conf->conf_portal_groups, pg, pg_next); 631255570Strasz 632255570Strasz TAILQ_FOREACH_SAFE(portal, &pg->pg_portals, p_next, tmp) 633255570Strasz portal_delete(portal); 634255570Strasz free(pg->pg_name); 635275642Strasz free(pg->pg_redirection); 636255570Strasz free(pg); 637255570Strasz} 638255570Strasz 639255570Straszstruct portal_group * 640265514Straszportal_group_find(const struct conf *conf, const char *name) 641255570Strasz{ 642255570Strasz struct portal_group *pg; 643255570Strasz 644255570Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 645255570Strasz if (strcmp(pg->pg_name, name) == 0) 646255570Strasz return (pg); 647255570Strasz } 648255570Strasz 649255570Strasz return (NULL); 650255570Strasz} 651255570Strasz 652274939Smavstatic int 653274939Smavparse_addr_port(char *arg, const char *def_port, struct addrinfo **ai) 654255570Strasz{ 655255570Strasz struct addrinfo hints; 656275674Smav char *str, *addr, *ch; 657255570Strasz const char *port; 658255570Strasz int error, colons = 0; 659255570Strasz 660275674Smav str = arg = strdup(arg); 661255570Strasz if (arg[0] == '[') { 662255570Strasz /* 663255570Strasz * IPv6 address in square brackets, perhaps with port. 664255570Strasz */ 665255570Strasz arg++; 666255570Strasz addr = strsep(&arg, "]"); 667274939Smav if (arg == NULL) 668255570Strasz return (1); 669255570Strasz if (arg[0] == '\0') { 670274939Smav port = def_port; 671255570Strasz } else if (arg[0] == ':') { 672255570Strasz port = arg + 1; 673275674Smav } else { 674275674Smav free(str); 675255570Strasz return (1); 676275674Smav } 677255570Strasz } else { 678255570Strasz /* 679255570Strasz * Either IPv6 address without brackets - and without 680255570Strasz * a port - or IPv4 address. Just count the colons. 681255570Strasz */ 682255570Strasz for (ch = arg; *ch != '\0'; ch++) { 683255570Strasz if (*ch == ':') 684255570Strasz colons++; 685255570Strasz } 686255570Strasz if (colons > 1) { 687255570Strasz addr = arg; 688274939Smav port = def_port; 689255570Strasz } else { 690255570Strasz addr = strsep(&arg, ":"); 691255570Strasz if (arg == NULL) 692274939Smav port = def_port; 693255570Strasz else 694255570Strasz port = arg; 695255570Strasz } 696255570Strasz } 697255570Strasz 698255570Strasz memset(&hints, 0, sizeof(hints)); 699255570Strasz hints.ai_family = PF_UNSPEC; 700255570Strasz hints.ai_socktype = SOCK_STREAM; 701255570Strasz hints.ai_flags = AI_PASSIVE; 702274939Smav error = getaddrinfo(addr, port, &hints, ai); 703275674Smav free(str); 704275674Smav return ((error != 0) ? 1 : 0); 705274939Smav} 706255570Strasz 707274939Smavint 708274939Smavportal_group_add_listen(struct portal_group *pg, const char *value, bool iser) 709274939Smav{ 710274939Smav struct portal *portal; 711274939Smav 712274939Smav portal = portal_new(pg); 713274939Smav portal->p_listen = checked_strdup(value); 714274939Smav portal->p_iser = iser; 715274939Smav 716274939Smav if (parse_addr_port(portal->p_listen, "3260", &portal->p_ai)) { 717274939Smav log_warnx("invalid listen address %s", portal->p_listen); 718271632Strasz portal_delete(portal); 719255570Strasz return (1); 720255570Strasz } 721255570Strasz 722255570Strasz /* 723255570Strasz * XXX: getaddrinfo(3) may return multiple addresses; we should turn 724255570Strasz * those into multiple portals. 725255570Strasz */ 726255570Strasz 727255570Strasz return (0); 728255570Strasz} 729255570Strasz 730274939Smavint 731274939Smavisns_new(struct conf *conf, const char *addr) 732274939Smav{ 733274939Smav struct isns *isns; 734274939Smav 735274939Smav isns = calloc(1, sizeof(*isns)); 736274939Smav if (isns == NULL) 737274939Smav log_err(1, "calloc"); 738274939Smav isns->i_conf = conf; 739274939Smav TAILQ_INSERT_TAIL(&conf->conf_isns, isns, i_next); 740274939Smav isns->i_addr = checked_strdup(addr); 741274939Smav 742274939Smav if (parse_addr_port(isns->i_addr, "3205", &isns->i_ai)) { 743274939Smav log_warnx("invalid iSNS address %s", isns->i_addr); 744274939Smav isns_delete(isns); 745274939Smav return (1); 746274939Smav } 747274939Smav 748274939Smav /* 749274939Smav * XXX: getaddrinfo(3) may return multiple addresses; we should turn 750274939Smav * those into multiple servers. 751274939Smav */ 752274939Smav 753274939Smav return (0); 754274939Smav} 755274939Smav 756274939Smavvoid 757274939Smavisns_delete(struct isns *isns) 758274939Smav{ 759274939Smav 760274939Smav TAILQ_REMOVE(&isns->i_conf->conf_isns, isns, i_next); 761274939Smav free(isns->i_addr); 762274939Smav if (isns->i_ai != NULL) 763274939Smav freeaddrinfo(isns->i_ai); 764274939Smav free(isns); 765274939Smav} 766274939Smav 767274939Smavstatic int 768274939Smavisns_do_connect(struct isns *isns) 769274939Smav{ 770274939Smav int s; 771274939Smav 772274939Smav s = socket(isns->i_ai->ai_family, isns->i_ai->ai_socktype, 773274939Smav isns->i_ai->ai_protocol); 774274939Smav if (s < 0) { 775274939Smav log_warn("socket(2) failed for %s", isns->i_addr); 776274939Smav return (-1); 777274939Smav } 778274939Smav if (connect(s, isns->i_ai->ai_addr, isns->i_ai->ai_addrlen)) { 779274939Smav log_warn("connect(2) failed for %s", isns->i_addr); 780274939Smav close(s); 781274939Smav return (-1); 782274939Smav } 783274939Smav return(s); 784274939Smav} 785274939Smav 786274939Smavstatic int 787274939Smavisns_do_register(struct isns *isns, int s, const char *hostname) 788274939Smav{ 789274939Smav struct conf *conf = isns->i_conf; 790274939Smav struct target *target; 791274939Smav struct portal *portal; 792274939Smav struct portal_group *pg; 793279006Smav struct port *port; 794274939Smav struct isns_req *req; 795274939Smav int res = 0; 796274939Smav uint32_t error; 797274939Smav 798274939Smav req = isns_req_create(ISNS_FUNC_DEVATTRREG, ISNS_FLAG_CLIENT); 799274939Smav isns_req_add_str(req, 32, TAILQ_FIRST(&conf->conf_targets)->t_name); 800274939Smav isns_req_add_delim(req); 801274939Smav isns_req_add_str(req, 1, hostname); 802274939Smav isns_req_add_32(req, 2, 2); /* 2 -- iSCSI */ 803274939Smav isns_req_add_32(req, 6, conf->conf_isns_period); 804274939Smav TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 805274939Smav if (pg->pg_unassigned) 806274939Smav continue; 807274939Smav TAILQ_FOREACH(portal, &pg->pg_portals, p_next) { 808274939Smav isns_req_add_addr(req, 16, portal->p_ai); 809274939Smav isns_req_add_port(req, 17, portal->p_ai); 810274939Smav } 811274939Smav } 812274939Smav TAILQ_FOREACH(target, &conf->conf_targets, t_next) { 813274939Smav isns_req_add_str(req, 32, target->t_name); 814274939Smav isns_req_add_32(req, 33, 1); /* 1 -- Target*/ 815274939Smav if (target->t_alias != NULL) 816274939Smav isns_req_add_str(req, 34, target->t_alias); 817279006Smav TAILQ_FOREACH(port, &target->t_ports, p_ts) { 818279006Smav if ((pg = port->p_portal_group) == NULL) 819279006Smav continue; 820279006Smav isns_req_add_32(req, 51, pg->pg_tag); 821279006Smav TAILQ_FOREACH(portal, &pg->pg_portals, p_next) { 822279006Smav isns_req_add_addr(req, 49, portal->p_ai); 823279006Smav isns_req_add_port(req, 50, portal->p_ai); 824279006Smav } 825274939Smav } 826274939Smav } 827274939Smav res = isns_req_send(s, req); 828274939Smav if (res < 0) { 829274939Smav log_warn("send(2) failed for %s", isns->i_addr); 830274939Smav goto quit; 831274939Smav } 832274939Smav res = isns_req_receive(s, req); 833274939Smav if (res < 0) { 834274939Smav log_warn("receive(2) failed for %s", isns->i_addr); 835274939Smav goto quit; 836274939Smav } 837274939Smav error = isns_req_get_status(req); 838274939Smav if (error != 0) { 839274939Smav log_warnx("iSNS register error %d for %s", error, isns->i_addr); 840274939Smav res = -1; 841274939Smav } 842274939Smavquit: 843274939Smav isns_req_free(req); 844274939Smav return (res); 845274939Smav} 846274939Smav 847274939Smavstatic int 848274939Smavisns_do_check(struct isns *isns, int s, const char *hostname) 849274939Smav{ 850274939Smav struct conf *conf = isns->i_conf; 851274939Smav struct isns_req *req; 852274939Smav int res = 0; 853274939Smav uint32_t error; 854274939Smav 855274939Smav req = isns_req_create(ISNS_FUNC_DEVATTRQRY, ISNS_FLAG_CLIENT); 856274939Smav isns_req_add_str(req, 32, TAILQ_FIRST(&conf->conf_targets)->t_name); 857274939Smav isns_req_add_str(req, 1, hostname); 858274939Smav isns_req_add_delim(req); 859274939Smav isns_req_add(req, 2, 0, NULL); 860274939Smav res = isns_req_send(s, req); 861274939Smav if (res < 0) { 862274939Smav log_warn("send(2) failed for %s", isns->i_addr); 863274939Smav goto quit; 864274939Smav } 865274939Smav res = isns_req_receive(s, req); 866274939Smav if (res < 0) { 867274939Smav log_warn("receive(2) failed for %s", isns->i_addr); 868274939Smav goto quit; 869274939Smav } 870274939Smav error = isns_req_get_status(req); 871274939Smav if (error != 0) { 872274939Smav log_warnx("iSNS check error %d for %s", error, isns->i_addr); 873274939Smav res = -1; 874274939Smav } 875274939Smavquit: 876274939Smav isns_req_free(req); 877274939Smav return (res); 878274939Smav} 879274939Smav 880274939Smavstatic int 881274939Smavisns_do_deregister(struct isns *isns, int s, const char *hostname) 882274939Smav{ 883274939Smav struct conf *conf = isns->i_conf; 884274939Smav struct isns_req *req; 885274939Smav int res = 0; 886274939Smav uint32_t error; 887274939Smav 888274939Smav req = isns_req_create(ISNS_FUNC_DEVDEREG, ISNS_FLAG_CLIENT); 889274939Smav isns_req_add_str(req, 32, TAILQ_FIRST(&conf->conf_targets)->t_name); 890274939Smav isns_req_add_delim(req); 891274939Smav isns_req_add_str(req, 1, hostname); 892274939Smav res = isns_req_send(s, req); 893274939Smav if (res < 0) { 894274939Smav log_warn("send(2) failed for %s", isns->i_addr); 895274939Smav goto quit; 896274939Smav } 897274939Smav res = isns_req_receive(s, req); 898274939Smav if (res < 0) { 899274939Smav log_warn("receive(2) failed for %s", isns->i_addr); 900274939Smav goto quit; 901274939Smav } 902274939Smav error = isns_req_get_status(req); 903274939Smav if (error != 0) { 904274939Smav log_warnx("iSNS deregister error %d for %s", error, isns->i_addr); 905274939Smav res = -1; 906274939Smav } 907274939Smavquit: 908274939Smav isns_req_free(req); 909274939Smav return (res); 910274939Smav} 911274939Smav 912274939Smavvoid 913274939Smavisns_register(struct isns *isns, struct isns *oldisns) 914274939Smav{ 915274939Smav struct conf *conf = isns->i_conf; 916275496Smav int s; 917274939Smav char hostname[256]; 918274939Smav 919274939Smav if (TAILQ_EMPTY(&conf->conf_targets) || 920274939Smav TAILQ_EMPTY(&conf->conf_portal_groups)) 921274939Smav return; 922274939Smav set_timeout(conf->conf_isns_timeout, false); 923274939Smav s = isns_do_connect(isns); 924274939Smav if (s < 0) { 925274939Smav set_timeout(0, false); 926274939Smav return; 927274939Smav } 928274939Smav gethostname(hostname, sizeof(hostname)); 929274939Smav 930274939Smav if (oldisns == NULL || TAILQ_EMPTY(&oldisns->i_conf->conf_targets)) 931274939Smav oldisns = isns; 932275496Smav isns_do_deregister(oldisns, s, hostname); 933275496Smav isns_do_register(isns, s, hostname); 934274939Smav close(s); 935274939Smav set_timeout(0, false); 936274939Smav} 937274939Smav 938274939Smavvoid 939274939Smavisns_check(struct isns *isns) 940274939Smav{ 941274939Smav struct conf *conf = isns->i_conf; 942274939Smav int s, res; 943274939Smav char hostname[256]; 944274939Smav 945274939Smav if (TAILQ_EMPTY(&conf->conf_targets) || 946274939Smav TAILQ_EMPTY(&conf->conf_portal_groups)) 947274939Smav return; 948274939Smav set_timeout(conf->conf_isns_timeout, false); 949274939Smav s = isns_do_connect(isns); 950274939Smav if (s < 0) { 951274939Smav set_timeout(0, false); 952274939Smav return; 953274939Smav } 954274939Smav gethostname(hostname, sizeof(hostname)); 955274939Smav 956274939Smav res = isns_do_check(isns, s, hostname); 957274939Smav if (res < 0) { 958275496Smav isns_do_deregister(isns, s, hostname); 959275496Smav isns_do_register(isns, s, hostname); 960274939Smav } 961274939Smav close(s); 962274939Smav set_timeout(0, false); 963274939Smav} 964274939Smav 965274939Smavvoid 966274939Smavisns_deregister(struct isns *isns) 967274939Smav{ 968274939Smav struct conf *conf = isns->i_conf; 969275496Smav int s; 970274939Smav char hostname[256]; 971274939Smav 972274939Smav if (TAILQ_EMPTY(&conf->conf_targets) || 973274939Smav TAILQ_EMPTY(&conf->conf_portal_groups)) 974274939Smav return; 975274939Smav set_timeout(conf->conf_isns_timeout, false); 976274939Smav s = isns_do_connect(isns); 977274939Smav if (s < 0) 978274939Smav return; 979274939Smav gethostname(hostname, sizeof(hostname)); 980274939Smav 981275496Smav isns_do_deregister(isns, s, hostname); 982274939Smav close(s); 983274939Smav set_timeout(0, false); 984274939Smav} 985274939Smav 986275244Straszint 987275245Straszportal_group_set_filter(struct portal_group *pg, const char *str) 988275244Strasz{ 989275245Strasz int filter; 990275244Strasz 991275244Strasz if (strcmp(str, "none") == 0) { 992275244Strasz filter = PG_FILTER_NONE; 993275244Strasz } else if (strcmp(str, "portal") == 0) { 994275244Strasz filter = PG_FILTER_PORTAL; 995275244Strasz } else if (strcmp(str, "portal-name") == 0) { 996275244Strasz filter = PG_FILTER_PORTAL_NAME; 997275244Strasz } else if (strcmp(str, "portal-name-auth") == 0) { 998275244Strasz filter = PG_FILTER_PORTAL_NAME_AUTH; 999275244Strasz } else { 1000275244Strasz log_warnx("invalid discovery-filter \"%s\" for portal-group " 1001275244Strasz "\"%s\"; valid values are \"none\", \"portal\", " 1002275244Strasz "\"portal-name\", and \"portal-name-auth\"", 1003275244Strasz str, pg->pg_name); 1004275244Strasz return (1); 1005275244Strasz } 1006275244Strasz 1007275245Strasz if (pg->pg_discovery_filter != PG_FILTER_UNKNOWN && 1008275245Strasz pg->pg_discovery_filter != filter) { 1009275244Strasz log_warnx("cannot set discovery-filter to \"%s\" for " 1010275244Strasz "portal-group \"%s\"; already has a different " 1011275244Strasz "value", str, pg->pg_name); 1012275244Strasz return (1); 1013275244Strasz } 1014275244Strasz 1015275245Strasz pg->pg_discovery_filter = filter; 1016275245Strasz 1017275245Strasz return (0); 1018275244Strasz} 1019275244Strasz 1020275642Straszint 1021275642Straszportal_group_set_redirection(struct portal_group *pg, const char *addr) 1022275642Strasz{ 1023275642Strasz 1024275642Strasz if (pg->pg_redirection != NULL) { 1025275642Strasz log_warnx("cannot set redirection to \"%s\" for " 1026275642Strasz "portal-group \"%s\"; already defined", 1027275642Strasz addr, pg->pg_name); 1028275642Strasz return (1); 1029275642Strasz } 1030275642Strasz 1031275642Strasz pg->pg_redirection = checked_strdup(addr); 1032275642Strasz 1033275642Strasz return (0); 1034275642Strasz} 1035275642Strasz 1036255570Straszstatic bool 1037255570Straszvalid_hex(const char ch) 1038255570Strasz{ 1039255570Strasz switch (ch) { 1040255570Strasz case '0': 1041255570Strasz case '1': 1042255570Strasz case '2': 1043255570Strasz case '3': 1044255570Strasz case '4': 1045255570Strasz case '5': 1046255570Strasz case '6': 1047255570Strasz case '7': 1048255570Strasz case '8': 1049255570Strasz case '9': 1050255570Strasz case 'a': 1051255570Strasz case 'A': 1052255570Strasz case 'b': 1053255570Strasz case 'B': 1054255570Strasz case 'c': 1055255570Strasz case 'C': 1056255570Strasz case 'd': 1057255570Strasz case 'D': 1058255570Strasz case 'e': 1059255570Strasz case 'E': 1060255570Strasz case 'f': 1061255570Strasz case 'F': 1062255570Strasz return (true); 1063255570Strasz default: 1064255570Strasz return (false); 1065255570Strasz } 1066255570Strasz} 1067255570Strasz 1068255570Straszbool 1069255570Straszvalid_iscsi_name(const char *name) 1070255570Strasz{ 1071255570Strasz int i; 1072255570Strasz 1073255570Strasz if (strlen(name) >= MAX_NAME_LEN) { 1074255570Strasz log_warnx("overlong name for target \"%s\"; max length allowed " 1075255570Strasz "by iSCSI specification is %d characters", 1076255570Strasz name, MAX_NAME_LEN); 1077255570Strasz return (false); 1078255570Strasz } 1079255570Strasz 1080255570Strasz /* 1081255570Strasz * In the cases below, we don't return an error, just in case the admin 1082255570Strasz * was right, and we're wrong. 1083255570Strasz */ 1084255570Strasz if (strncasecmp(name, "iqn.", strlen("iqn.")) == 0) { 1085255570Strasz for (i = strlen("iqn."); name[i] != '\0'; i++) { 1086255570Strasz /* 1087255570Strasz * XXX: We should verify UTF-8 normalisation, as defined 1088274870Strasz * by 3.2.6.2: iSCSI Name Encoding. 1089255570Strasz */ 1090255570Strasz if (isalnum(name[i])) 1091255570Strasz continue; 1092255570Strasz if (name[i] == '-' || name[i] == '.' || name[i] == ':') 1093255570Strasz continue; 1094255570Strasz log_warnx("invalid character \"%c\" in target name " 1095255570Strasz "\"%s\"; allowed characters are letters, digits, " 1096255570Strasz "'-', '.', and ':'", name[i], name); 1097255570Strasz break; 1098255570Strasz } 1099255570Strasz /* 1100255570Strasz * XXX: Check more stuff: valid date and a valid reversed domain. 1101255570Strasz */ 1102255570Strasz } else if (strncasecmp(name, "eui.", strlen("eui.")) == 0) { 1103255570Strasz if (strlen(name) != strlen("eui.") + 16) 1104255570Strasz log_warnx("invalid target name \"%s\"; the \"eui.\" " 1105255570Strasz "should be followed by exactly 16 hexadecimal " 1106255570Strasz "digits", name); 1107255570Strasz for (i = strlen("eui."); name[i] != '\0'; i++) { 1108255570Strasz if (!valid_hex(name[i])) { 1109255570Strasz log_warnx("invalid character \"%c\" in target " 1110255570Strasz "name \"%s\"; allowed characters are 1-9 " 1111255570Strasz "and A-F", name[i], name); 1112255570Strasz break; 1113255570Strasz } 1114255570Strasz } 1115255570Strasz } else if (strncasecmp(name, "naa.", strlen("naa.")) == 0) { 1116255570Strasz if (strlen(name) > strlen("naa.") + 32) 1117255570Strasz log_warnx("invalid target name \"%s\"; the \"naa.\" " 1118255570Strasz "should be followed by at most 32 hexadecimal " 1119255570Strasz "digits", name); 1120255570Strasz for (i = strlen("naa."); name[i] != '\0'; i++) { 1121255570Strasz if (!valid_hex(name[i])) { 1122255570Strasz log_warnx("invalid character \"%c\" in target " 1123255570Strasz "name \"%s\"; allowed characters are 1-9 " 1124255570Strasz "and A-F", name[i], name); 1125255570Strasz break; 1126255570Strasz } 1127255570Strasz } 1128255570Strasz } else { 1129255570Strasz log_warnx("invalid target name \"%s\"; should start with " 1130255570Strasz "either \".iqn\", \"eui.\", or \"naa.\"", 1131255570Strasz name); 1132255570Strasz } 1133255570Strasz return (true); 1134255570Strasz} 1135255570Strasz 1136279006Smavstruct port * 1137279006Smavport_new(struct conf *conf, struct target *target, struct portal_group *pg) 1138279006Smav{ 1139279006Smav struct port *port; 1140279006Smav 1141279006Smav port = calloc(1, sizeof(*port)); 1142279006Smav if (port == NULL) 1143279006Smav log_err(1, "calloc"); 1144279006Smav asprintf(&port->p_name, "%s-%s", pg->pg_name, target->t_name); 1145279006Smav if (port_find(conf, port->p_name) != NULL) { 1146279006Smav log_warnx("duplicate port \"%s\"", port->p_name); 1147279006Smav free(port); 1148279006Smav return (NULL); 1149279006Smav } 1150279006Smav port->p_conf = conf; 1151279006Smav TAILQ_INSERT_TAIL(&conf->conf_ports, port, p_next); 1152279006Smav TAILQ_INSERT_TAIL(&target->t_ports, port, p_ts); 1153279006Smav port->p_target = target; 1154279006Smav TAILQ_INSERT_TAIL(&pg->pg_ports, port, p_pgs); 1155279006Smav port->p_portal_group = pg; 1156279006Smav return (port); 1157279006Smav} 1158279006Smav 1159279006Smavstruct port * 1160279006Smavport_find(const struct conf *conf, const char *name) 1161279006Smav{ 1162279006Smav struct port *port; 1163279006Smav 1164279006Smav TAILQ_FOREACH(port, &conf->conf_ports, p_next) { 1165279006Smav if (strcasecmp(port->p_name, name) == 0) 1166279006Smav return (port); 1167279006Smav } 1168279006Smav 1169279006Smav return (NULL); 1170279006Smav} 1171279006Smav 1172279006Smavstruct port * 1173279006Smavport_find_in_pg(const struct portal_group *pg, const char *target) 1174279006Smav{ 1175279006Smav struct port *port; 1176279006Smav 1177279006Smav TAILQ_FOREACH(port, &pg->pg_ports, p_pgs) { 1178279006Smav if (strcasecmp(port->p_target->t_name, target) == 0) 1179279006Smav return (port); 1180279006Smav } 1181279006Smav 1182279006Smav return (NULL); 1183279006Smav} 1184279006Smav 1185279006Smavvoid 1186279006Smavport_delete(struct port *port) 1187279006Smav{ 1188279006Smav 1189279006Smav if (port->p_portal_group) 1190279006Smav TAILQ_REMOVE(&port->p_portal_group->pg_ports, port, p_pgs); 1191279006Smav if (port->p_target) 1192279006Smav TAILQ_REMOVE(&port->p_target->t_ports, port, p_ts); 1193279006Smav TAILQ_REMOVE(&port->p_conf->conf_ports, port, p_next); 1194279006Smav free(port->p_name); 1195279006Smav free(port); 1196279006Smav} 1197279006Smav 1198255570Straszstruct target * 1199263723Strasztarget_new(struct conf *conf, const char *name) 1200255570Strasz{ 1201255570Strasz struct target *targ; 1202255570Strasz int i, len; 1203255570Strasz 1204263723Strasz targ = target_find(conf, name); 1205255570Strasz if (targ != NULL) { 1206263723Strasz log_warnx("duplicated target \"%s\"", name); 1207255570Strasz return (NULL); 1208255570Strasz } 1209263723Strasz if (valid_iscsi_name(name) == false) { 1210263723Strasz log_warnx("target name \"%s\" is invalid", name); 1211255570Strasz return (NULL); 1212255570Strasz } 1213255570Strasz targ = calloc(1, sizeof(*targ)); 1214255570Strasz if (targ == NULL) 1215255570Strasz log_err(1, "calloc"); 1216263723Strasz targ->t_name = checked_strdup(name); 1217255570Strasz 1218255570Strasz /* 1219255570Strasz * RFC 3722 requires us to normalize the name to lowercase. 1220255570Strasz */ 1221263723Strasz len = strlen(name); 1222255570Strasz for (i = 0; i < len; i++) 1223263723Strasz targ->t_name[i] = tolower(targ->t_name[i]); 1224255570Strasz 1225255570Strasz targ->t_conf = conf; 1226279006Smav TAILQ_INIT(&targ->t_ports); 1227255570Strasz TAILQ_INSERT_TAIL(&conf->conf_targets, targ, t_next); 1228255570Strasz 1229255570Strasz return (targ); 1230255570Strasz} 1231255570Strasz 1232255570Straszvoid 1233255570Strasztarget_delete(struct target *targ) 1234255570Strasz{ 1235279006Smav struct port *port, *tport; 1236255570Strasz 1237279006Smav TAILQ_FOREACH_SAFE(port, &targ->t_ports, p_ts, tport) 1238279006Smav port_delete(port); 1239255570Strasz TAILQ_REMOVE(&targ->t_conf->conf_targets, targ, t_next); 1240255570Strasz 1241263723Strasz free(targ->t_name); 1242275642Strasz free(targ->t_redirection); 1243255570Strasz free(targ); 1244255570Strasz} 1245255570Strasz 1246255570Straszstruct target * 1247263723Strasztarget_find(struct conf *conf, const char *name) 1248255570Strasz{ 1249255570Strasz struct target *targ; 1250255570Strasz 1251255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 1252263723Strasz if (strcasecmp(targ->t_name, name) == 0) 1253255570Strasz return (targ); 1254255570Strasz } 1255255570Strasz 1256255570Strasz return (NULL); 1257255570Strasz} 1258255570Strasz 1259275642Straszint 1260275642Strasztarget_set_redirection(struct target *target, const char *addr) 1261275642Strasz{ 1262275642Strasz 1263275642Strasz if (target->t_redirection != NULL) { 1264275642Strasz log_warnx("cannot set redirection to \"%s\" for " 1265275642Strasz "target \"%s\"; already defined", 1266275642Strasz addr, target->t_name); 1267275642Strasz return (1); 1268275642Strasz } 1269275642Strasz 1270275642Strasz target->t_redirection = checked_strdup(addr); 1271275642Strasz 1272275642Strasz return (0); 1273275642Strasz} 1274275642Strasz 1275255570Straszstruct lun * 1276279002Smavlun_new(struct conf *conf, const char *name) 1277255570Strasz{ 1278255570Strasz struct lun *lun; 1279255570Strasz 1280279002Smav lun = lun_find(conf, name); 1281255570Strasz if (lun != NULL) { 1282279002Smav log_warnx("duplicated lun \"%s\"", name); 1283255570Strasz return (NULL); 1284255570Strasz } 1285255570Strasz 1286255570Strasz lun = calloc(1, sizeof(*lun)); 1287255570Strasz if (lun == NULL) 1288255570Strasz log_err(1, "calloc"); 1289279002Smav lun->l_conf = conf; 1290279002Smav lun->l_name = checked_strdup(name); 1291255570Strasz TAILQ_INIT(&lun->l_options); 1292279002Smav TAILQ_INSERT_TAIL(&conf->conf_luns, lun, l_next); 1293255570Strasz 1294255570Strasz return (lun); 1295255570Strasz} 1296255570Strasz 1297255570Straszvoid 1298255570Straszlun_delete(struct lun *lun) 1299255570Strasz{ 1300279002Smav struct target *targ; 1301255570Strasz struct lun_option *lo, *tmp; 1302279002Smav int i; 1303255570Strasz 1304279002Smav TAILQ_FOREACH(targ, &lun->l_conf->conf_targets, t_next) { 1305279002Smav for (i = 0; i < MAX_LUNS; i++) { 1306279002Smav if (targ->t_luns[i] == lun) 1307279002Smav targ->t_luns[i] = NULL; 1308279002Smav } 1309279002Smav } 1310279002Smav TAILQ_REMOVE(&lun->l_conf->conf_luns, lun, l_next); 1311255570Strasz 1312255570Strasz TAILQ_FOREACH_SAFE(lo, &lun->l_options, lo_next, tmp) 1313255570Strasz lun_option_delete(lo); 1314279002Smav free(lun->l_name); 1315255570Strasz free(lun->l_backend); 1316255570Strasz free(lun->l_device_id); 1317255570Strasz free(lun->l_path); 1318279002Smav free(lun->l_scsiname); 1319255570Strasz free(lun->l_serial); 1320255570Strasz free(lun); 1321255570Strasz} 1322255570Strasz 1323255570Straszstruct lun * 1324279002Smavlun_find(const struct conf *conf, const char *name) 1325255570Strasz{ 1326255570Strasz struct lun *lun; 1327255570Strasz 1328279002Smav TAILQ_FOREACH(lun, &conf->conf_luns, l_next) { 1329279002Smav if (strcmp(lun->l_name, name) == 0) 1330255570Strasz return (lun); 1331255570Strasz } 1332255570Strasz 1333255570Strasz return (NULL); 1334255570Strasz} 1335255570Strasz 1336255570Straszvoid 1337255570Straszlun_set_backend(struct lun *lun, const char *value) 1338255570Strasz{ 1339255570Strasz free(lun->l_backend); 1340255570Strasz lun->l_backend = checked_strdup(value); 1341255570Strasz} 1342255570Strasz 1343255570Straszvoid 1344255570Straszlun_set_blocksize(struct lun *lun, size_t value) 1345255570Strasz{ 1346255570Strasz 1347255570Strasz lun->l_blocksize = value; 1348255570Strasz} 1349255570Strasz 1350255570Straszvoid 1351255570Straszlun_set_device_id(struct lun *lun, const char *value) 1352255570Strasz{ 1353255570Strasz free(lun->l_device_id); 1354255570Strasz lun->l_device_id = checked_strdup(value); 1355255570Strasz} 1356255570Strasz 1357255570Straszvoid 1358255570Straszlun_set_path(struct lun *lun, const char *value) 1359255570Strasz{ 1360255570Strasz free(lun->l_path); 1361255570Strasz lun->l_path = checked_strdup(value); 1362255570Strasz} 1363255570Strasz 1364255570Straszvoid 1365279002Smavlun_set_scsiname(struct lun *lun, const char *value) 1366279002Smav{ 1367279002Smav free(lun->l_scsiname); 1368279002Smav lun->l_scsiname = checked_strdup(value); 1369279002Smav} 1370279002Smav 1371279002Smavvoid 1372255570Straszlun_set_serial(struct lun *lun, const char *value) 1373255570Strasz{ 1374255570Strasz free(lun->l_serial); 1375255570Strasz lun->l_serial = checked_strdup(value); 1376255570Strasz} 1377255570Strasz 1378255570Straszvoid 1379255570Straszlun_set_size(struct lun *lun, size_t value) 1380255570Strasz{ 1381255570Strasz 1382255570Strasz lun->l_size = value; 1383255570Strasz} 1384255570Strasz 1385255570Straszvoid 1386255570Straszlun_set_ctl_lun(struct lun *lun, uint32_t value) 1387255570Strasz{ 1388255570Strasz 1389255570Strasz lun->l_ctl_lun = value; 1390255570Strasz} 1391255570Strasz 1392255570Straszstruct lun_option * 1393255570Straszlun_option_new(struct lun *lun, const char *name, const char *value) 1394255570Strasz{ 1395255570Strasz struct lun_option *lo; 1396255570Strasz 1397255570Strasz lo = lun_option_find(lun, name); 1398255570Strasz if (lo != NULL) { 1399279002Smav log_warnx("duplicated lun option \"%s\" for lun \"%s\"", 1400279002Smav name, lun->l_name); 1401255570Strasz return (NULL); 1402255570Strasz } 1403255570Strasz 1404255570Strasz lo = calloc(1, sizeof(*lo)); 1405255570Strasz if (lo == NULL) 1406255570Strasz log_err(1, "calloc"); 1407255570Strasz lo->lo_name = checked_strdup(name); 1408255570Strasz lo->lo_value = checked_strdup(value); 1409255570Strasz lo->lo_lun = lun; 1410255570Strasz TAILQ_INSERT_TAIL(&lun->l_options, lo, lo_next); 1411255570Strasz 1412255570Strasz return (lo); 1413255570Strasz} 1414255570Strasz 1415255570Straszvoid 1416255570Straszlun_option_delete(struct lun_option *lo) 1417255570Strasz{ 1418255570Strasz 1419255570Strasz TAILQ_REMOVE(&lo->lo_lun->l_options, lo, lo_next); 1420255570Strasz 1421255570Strasz free(lo->lo_name); 1422255570Strasz free(lo->lo_value); 1423255570Strasz free(lo); 1424255570Strasz} 1425255570Strasz 1426255570Straszstruct lun_option * 1427265514Straszlun_option_find(const struct lun *lun, const char *name) 1428255570Strasz{ 1429255570Strasz struct lun_option *lo; 1430255570Strasz 1431255570Strasz TAILQ_FOREACH(lo, &lun->l_options, lo_next) { 1432255570Strasz if (strcmp(lo->lo_name, name) == 0) 1433255570Strasz return (lo); 1434255570Strasz } 1435255570Strasz 1436255570Strasz return (NULL); 1437255570Strasz} 1438255570Strasz 1439255570Straszvoid 1440255570Straszlun_option_set(struct lun_option *lo, const char *value) 1441255570Strasz{ 1442255570Strasz 1443255570Strasz free(lo->lo_value); 1444255570Strasz lo->lo_value = checked_strdup(value); 1445255570Strasz} 1446255570Strasz 1447255570Straszstatic struct connection * 1448270137Smavconnection_new(struct portal *portal, int fd, const char *host, 1449270137Smav const struct sockaddr *client_sa) 1450255570Strasz{ 1451255570Strasz struct connection *conn; 1452255570Strasz 1453255570Strasz conn = calloc(1, sizeof(*conn)); 1454255570Strasz if (conn == NULL) 1455255570Strasz log_err(1, "calloc"); 1456255570Strasz conn->conn_portal = portal; 1457255570Strasz conn->conn_socket = fd; 1458255570Strasz conn->conn_initiator_addr = checked_strdup(host); 1459270137Smav memcpy(&conn->conn_initiator_sa, client_sa, client_sa->sa_len); 1460255570Strasz 1461255570Strasz /* 1462255570Strasz * Default values, from RFC 3720, section 12. 1463255570Strasz */ 1464255570Strasz conn->conn_max_data_segment_length = 8192; 1465255570Strasz conn->conn_max_burst_length = 262144; 1466255570Strasz conn->conn_immediate_data = true; 1467255570Strasz 1468255570Strasz return (conn); 1469255570Strasz} 1470255570Strasz 1471255570Strasz#if 0 1472255570Straszstatic void 1473255570Straszconf_print(struct conf *conf) 1474255570Strasz{ 1475255570Strasz struct auth_group *ag; 1476255570Strasz struct auth *auth; 1477263720Strasz struct auth_name *auth_name; 1478263720Strasz struct auth_portal *auth_portal; 1479255570Strasz struct portal_group *pg; 1480255570Strasz struct portal *portal; 1481255570Strasz struct target *targ; 1482255570Strasz struct lun *lun; 1483255570Strasz struct lun_option *lo; 1484255570Strasz 1485255570Strasz TAILQ_FOREACH(ag, &conf->conf_auth_groups, ag_next) { 1486255570Strasz fprintf(stderr, "auth-group %s {\n", ag->ag_name); 1487255570Strasz TAILQ_FOREACH(auth, &ag->ag_auths, a_next) 1488255570Strasz fprintf(stderr, "\t chap-mutual %s %s %s %s\n", 1489255570Strasz auth->a_user, auth->a_secret, 1490255570Strasz auth->a_mutual_user, auth->a_mutual_secret); 1491263720Strasz TAILQ_FOREACH(auth_name, &ag->ag_names, an_next) 1492263720Strasz fprintf(stderr, "\t initiator-name %s\n", 1493263720Strasz auth_name->an_initator_name); 1494263720Strasz TAILQ_FOREACH(auth_portal, &ag->ag_portals, an_next) 1495263720Strasz fprintf(stderr, "\t initiator-portal %s\n", 1496263720Strasz auth_portal->an_initator_portal); 1497255570Strasz fprintf(stderr, "}\n"); 1498255570Strasz } 1499255570Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 1500255570Strasz fprintf(stderr, "portal-group %s {\n", pg->pg_name); 1501255570Strasz TAILQ_FOREACH(portal, &pg->pg_portals, p_next) 1502255570Strasz fprintf(stderr, "\t listen %s\n", portal->p_listen); 1503255570Strasz fprintf(stderr, "}\n"); 1504255570Strasz } 1505279002Smav TAILQ_FOREACH(lun, &conf->conf_luns, l_next) { 1506279002Smav fprintf(stderr, "\tlun %s {\n", lun->l_name); 1507279002Smav fprintf(stderr, "\t\tpath %s\n", lun->l_path); 1508279002Smav TAILQ_FOREACH(lo, &lun->l_options, lo_next) 1509279002Smav fprintf(stderr, "\t\toption %s %s\n", 1510279002Smav lo->lo_name, lo->lo_value); 1511279002Smav fprintf(stderr, "\t}\n"); 1512279002Smav } 1513255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 1514263723Strasz fprintf(stderr, "target %s {\n", targ->t_name); 1515255570Strasz if (targ->t_alias != NULL) 1516255570Strasz fprintf(stderr, "\t alias %s\n", targ->t_alias); 1517255570Strasz fprintf(stderr, "}\n"); 1518255570Strasz } 1519255570Strasz} 1520255570Strasz#endif 1521255570Strasz 1522263717Straszstatic int 1523263717Straszconf_verify_lun(struct lun *lun) 1524263717Strasz{ 1525263717Strasz const struct lun *lun2; 1526263717Strasz 1527263717Strasz if (lun->l_backend == NULL) 1528263717Strasz lun_set_backend(lun, "block"); 1529263717Strasz if (strcmp(lun->l_backend, "block") == 0) { 1530263717Strasz if (lun->l_path == NULL) { 1531279002Smav log_warnx("missing path for lun \"%s\"", 1532279002Smav lun->l_name); 1533263717Strasz return (1); 1534263717Strasz } 1535263717Strasz } else if (strcmp(lun->l_backend, "ramdisk") == 0) { 1536263717Strasz if (lun->l_size == 0) { 1537279002Smav log_warnx("missing size for ramdisk-backed lun \"%s\"", 1538279002Smav lun->l_name); 1539263717Strasz return (1); 1540263717Strasz } 1541263717Strasz if (lun->l_path != NULL) { 1542263717Strasz log_warnx("path must not be specified " 1543279002Smav "for ramdisk-backed lun \"%s\"", 1544279002Smav lun->l_name); 1545263717Strasz return (1); 1546263717Strasz } 1547263717Strasz } 1548263717Strasz if (lun->l_blocksize == 0) { 1549263717Strasz lun_set_blocksize(lun, DEFAULT_BLOCKSIZE); 1550263717Strasz } else if (lun->l_blocksize < 0) { 1551279002Smav log_warnx("invalid blocksize for lun \"%s\"; " 1552279002Smav "must be larger than 0", lun->l_name); 1553263717Strasz return (1); 1554263717Strasz } 1555263717Strasz if (lun->l_size != 0 && lun->l_size % lun->l_blocksize != 0) { 1556279002Smav log_warnx("invalid size for lun \"%s\"; " 1557279002Smav "must be multiple of blocksize", lun->l_name); 1558263717Strasz return (1); 1559263717Strasz } 1560279002Smav TAILQ_FOREACH(lun2, &lun->l_conf->conf_luns, l_next) { 1561279002Smav if (lun == lun2) 1562279002Smav continue; 1563279002Smav if (lun->l_path != NULL && lun2->l_path != NULL && 1564279002Smav strcmp(lun->l_path, lun2->l_path) == 0) { 1565279002Smav log_debugx("WARNING: path \"%s\" duplicated " 1566279002Smav "between lun \"%s\", and " 1567279002Smav "lun \"%s\"", lun->l_path, 1568279002Smav lun->l_name, lun2->l_name); 1569263718Strasz } 1570263718Strasz } 1571263717Strasz 1572263717Strasz return (0); 1573263717Strasz} 1574263717Strasz 1575255570Straszint 1576255570Straszconf_verify(struct conf *conf) 1577255570Strasz{ 1578255570Strasz struct auth_group *ag; 1579255570Strasz struct portal_group *pg; 1580279006Smav struct port *port; 1581255570Strasz struct target *targ; 1582263717Strasz struct lun *lun; 1583274871Strasz bool found; 1584279002Smav int error, i; 1585255570Strasz 1586255570Strasz if (conf->conf_pidfile_path == NULL) 1587255570Strasz conf->conf_pidfile_path = checked_strdup(DEFAULT_PIDFILE); 1588255570Strasz 1589279002Smav TAILQ_FOREACH(lun, &conf->conf_luns, l_next) { 1590279002Smav error = conf_verify_lun(lun); 1591279002Smav if (error != 0) 1592279002Smav return (error); 1593279002Smav } 1594255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 1595255570Strasz if (targ->t_auth_group == NULL) { 1596263726Strasz targ->t_auth_group = auth_group_find(conf, 1597263726Strasz "default"); 1598263726Strasz assert(targ->t_auth_group != NULL); 1599255570Strasz } 1600279006Smav if (TAILQ_EMPTY(&targ->t_ports)) { 1601279006Smav pg = portal_group_find(conf, "default"); 1602279006Smav assert(pg != NULL); 1603279006Smav port_new(conf, targ, pg); 1604255570Strasz } 1605274871Strasz found = false; 1606279002Smav for (i = 0; i < MAX_LUNS; i++) { 1607279002Smav if (targ->t_luns[i] != NULL) 1608279002Smav found = true; 1609255570Strasz } 1610275642Strasz if (!found && targ->t_redirection == NULL) { 1611265506Strasz log_warnx("no LUNs defined for target \"%s\"", 1612265506Strasz targ->t_name); 1613255570Strasz } 1614275642Strasz if (found && targ->t_redirection != NULL) { 1615275642Strasz log_debugx("target \"%s\" contains luns, " 1616275642Strasz " but configured for redirection", 1617275642Strasz targ->t_name); 1618275642Strasz } 1619255570Strasz } 1620255570Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 1621255570Strasz assert(pg->pg_name != NULL); 1622255570Strasz if (pg->pg_discovery_auth_group == NULL) { 1623255570Strasz pg->pg_discovery_auth_group = 1624263728Strasz auth_group_find(conf, "default"); 1625255570Strasz assert(pg->pg_discovery_auth_group != NULL); 1626255570Strasz } 1627255570Strasz 1628275244Strasz if (pg->pg_discovery_filter == PG_FILTER_UNKNOWN) 1629275244Strasz pg->pg_discovery_filter = PG_FILTER_NONE; 1630275244Strasz 1631279006Smav if (!TAILQ_EMPTY(&pg->pg_ports)) { 1632279006Smav if (pg->pg_redirection != NULL) { 1633275642Strasz log_debugx("portal-group \"%s\" assigned " 1634279006Smav "to target, but configured " 1635275642Strasz "for redirection", 1636279006Smav pg->pg_name); 1637275642Strasz } 1638275642Strasz pg->pg_unassigned = false; 1639275642Strasz } else { 1640255570Strasz if (strcmp(pg->pg_name, "default") != 0) 1641255570Strasz log_warnx("portal-group \"%s\" not assigned " 1642255570Strasz "to any target", pg->pg_name); 1643255570Strasz pg->pg_unassigned = true; 1644275642Strasz } 1645255570Strasz } 1646255570Strasz TAILQ_FOREACH(ag, &conf->conf_auth_groups, ag_next) { 1647255570Strasz if (ag->ag_name == NULL) 1648255570Strasz assert(ag->ag_target != NULL); 1649255570Strasz else 1650255570Strasz assert(ag->ag_target == NULL); 1651255570Strasz 1652274871Strasz found = false; 1653255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 1654274871Strasz if (targ->t_auth_group == ag) { 1655274871Strasz found = true; 1656255570Strasz break; 1657274871Strasz } 1658255570Strasz } 1659279006Smav TAILQ_FOREACH(port, &conf->conf_ports, p_next) { 1660279006Smav if (port->p_auth_group == ag) { 1661279006Smav found = true; 1662279006Smav break; 1663279006Smav } 1664279006Smav } 1665274871Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 1666274871Strasz if (pg->pg_discovery_auth_group == ag) { 1667274871Strasz found = true; 1668274871Strasz break; 1669274871Strasz } 1670274871Strasz } 1671274871Strasz if (!found && ag->ag_name != NULL && 1672263728Strasz strcmp(ag->ag_name, "default") != 0 && 1673255570Strasz strcmp(ag->ag_name, "no-authentication") != 0 && 1674255570Strasz strcmp(ag->ag_name, "no-access") != 0) { 1675255570Strasz log_warnx("auth-group \"%s\" not assigned " 1676255570Strasz "to any target", ag->ag_name); 1677255570Strasz } 1678255570Strasz } 1679255570Strasz 1680255570Strasz return (0); 1681255570Strasz} 1682255570Strasz 1683255570Straszstatic int 1684255570Straszconf_apply(struct conf *oldconf, struct conf *newconf) 1685255570Strasz{ 1686255570Strasz struct lun *oldlun, *newlun, *tmplun; 1687255570Strasz struct portal_group *oldpg, *newpg; 1688255570Strasz struct portal *oldp, *newp; 1689279006Smav struct port *oldport, *newport, *tmpport; 1690274939Smav struct isns *oldns, *newns; 1691255570Strasz pid_t otherpid; 1692279001Smav int changed, cumulated_error = 0, error, sockbuf; 1693255570Strasz int one = 1; 1694255570Strasz 1695255570Strasz if (oldconf->conf_debug != newconf->conf_debug) { 1696255570Strasz log_debugx("changing debug level to %d", newconf->conf_debug); 1697255570Strasz log_init(newconf->conf_debug); 1698255570Strasz } 1699255570Strasz 1700255570Strasz if (oldconf->conf_pidfh != NULL) { 1701255570Strasz assert(oldconf->conf_pidfile_path != NULL); 1702255570Strasz if (newconf->conf_pidfile_path != NULL && 1703255570Strasz strcmp(oldconf->conf_pidfile_path, 1704255570Strasz newconf->conf_pidfile_path) == 0) { 1705255570Strasz newconf->conf_pidfh = oldconf->conf_pidfh; 1706255570Strasz oldconf->conf_pidfh = NULL; 1707255570Strasz } else { 1708255570Strasz log_debugx("removing pidfile %s", 1709255570Strasz oldconf->conf_pidfile_path); 1710255570Strasz pidfile_remove(oldconf->conf_pidfh); 1711255570Strasz oldconf->conf_pidfh = NULL; 1712255570Strasz } 1713255570Strasz } 1714255570Strasz 1715255570Strasz if (newconf->conf_pidfh == NULL && newconf->conf_pidfile_path != NULL) { 1716255570Strasz log_debugx("opening pidfile %s", newconf->conf_pidfile_path); 1717255570Strasz newconf->conf_pidfh = 1718255570Strasz pidfile_open(newconf->conf_pidfile_path, 0600, &otherpid); 1719255570Strasz if (newconf->conf_pidfh == NULL) { 1720255570Strasz if (errno == EEXIST) 1721255570Strasz log_errx(1, "daemon already running, pid: %jd.", 1722255570Strasz (intmax_t)otherpid); 1723255570Strasz log_err(1, "cannot open or create pidfile \"%s\"", 1724255570Strasz newconf->conf_pidfile_path); 1725255570Strasz } 1726255570Strasz } 1727255570Strasz 1728279003Smav /* 1729279003Smav * Go through the new portal groups, assigning tags or preserving old. 1730279003Smav */ 1731279003Smav TAILQ_FOREACH(newpg, &newconf->conf_portal_groups, pg_next) { 1732279003Smav oldpg = portal_group_find(oldconf, newpg->pg_name); 1733279003Smav if (oldpg != NULL) 1734279003Smav newpg->pg_tag = oldpg->pg_tag; 1735279003Smav else 1736279003Smav newpg->pg_tag = ++last_portal_group_tag; 1737279003Smav } 1738279003Smav 1739274939Smav /* Deregister on removed iSNS servers. */ 1740274939Smav TAILQ_FOREACH(oldns, &oldconf->conf_isns, i_next) { 1741274939Smav TAILQ_FOREACH(newns, &newconf->conf_isns, i_next) { 1742274939Smav if (strcmp(oldns->i_addr, newns->i_addr) == 0) 1743274939Smav break; 1744274939Smav } 1745274939Smav if (newns == NULL) 1746274939Smav isns_deregister(oldns); 1747274939Smav } 1748274939Smav 1749265518Strasz /* 1750265518Strasz * XXX: If target or lun removal fails, we should somehow "move" 1751274870Strasz * the old lun or target into newconf, so that subsequent 1752274870Strasz * conf_apply() would try to remove them again. That would 1753274870Strasz * be somewhat hairy, though, and lun deletion failures don't 1754274870Strasz * really happen, so leave it as it is for now. 1755265518Strasz */ 1756279002Smav /* 1757279006Smav * First, remove any ports present in the old configuration 1758279002Smav * and missing in the new one. 1759279002Smav */ 1760279006Smav TAILQ_FOREACH_SAFE(oldport, &oldconf->conf_ports, p_next, tmpport) { 1761279006Smav newport = port_find(newconf, oldport->p_name); 1762279006Smav if (newport != NULL) 1763279002Smav continue; 1764279006Smav error = kernel_port_remove(oldport); 1765279002Smav if (error != 0) { 1766279006Smav log_warnx("failed to remove port %s", 1767279006Smav oldport->p_name); 1768279002Smav /* 1769279002Smav * XXX: Uncomment after fixing the root cause. 1770279002Smav * 1771279002Smav * cumulated_error++; 1772279002Smav */ 1773279002Smav } 1774279002Smav } 1775279002Smav 1776279002Smav /* 1777279002Smav * Second, remove any LUNs present in the old configuration 1778279002Smav * and missing in the new one. 1779279002Smav */ 1780279002Smav TAILQ_FOREACH_SAFE(oldlun, &oldconf->conf_luns, l_next, tmplun) { 1781279002Smav newlun = lun_find(newconf, oldlun->l_name); 1782279002Smav if (newlun == NULL) { 1783279002Smav log_debugx("lun \"%s\", CTL lun %d " 1784279002Smav "not found in new configuration; " 1785279002Smav "removing", oldlun->l_name, oldlun->l_ctl_lun); 1786279002Smav error = kernel_lun_remove(oldlun); 1787279000Smav if (error != 0) { 1788279002Smav log_warnx("failed to remove lun \"%s\", " 1789279002Smav "CTL lun %d", 1790279002Smav oldlun->l_name, oldlun->l_ctl_lun); 1791279002Smav cumulated_error++; 1792279000Smav } 1793255570Strasz continue; 1794255570Strasz } 1795255570Strasz 1796255570Strasz /* 1797279002Smav * Also remove the LUNs changed by more than size. 1798255570Strasz */ 1799279002Smav changed = 0; 1800279002Smav assert(oldlun->l_backend != NULL); 1801279002Smav assert(newlun->l_backend != NULL); 1802279002Smav if (strcmp(newlun->l_backend, oldlun->l_backend) != 0) { 1803279002Smav log_debugx("backend for lun \"%s\", " 1804279002Smav "CTL lun %d changed; removing", 1805279002Smav oldlun->l_name, oldlun->l_ctl_lun); 1806279002Smav changed = 1; 1807279002Smav } 1808279002Smav if (oldlun->l_blocksize != newlun->l_blocksize) { 1809279002Smav log_debugx("blocksize for lun \"%s\", " 1810279002Smav "CTL lun %d changed; removing", 1811279002Smav oldlun->l_name, oldlun->l_ctl_lun); 1812279002Smav changed = 1; 1813279002Smav } 1814279002Smav if (newlun->l_device_id != NULL && 1815279002Smav (oldlun->l_device_id == NULL || 1816279002Smav strcmp(oldlun->l_device_id, newlun->l_device_id) != 1817279002Smav 0)) { 1818279002Smav log_debugx("device-id for lun \"%s\", " 1819279002Smav "CTL lun %d changed; removing", 1820279002Smav oldlun->l_name, oldlun->l_ctl_lun); 1821279002Smav changed = 1; 1822279002Smav } 1823279002Smav if (newlun->l_path != NULL && 1824279002Smav (oldlun->l_path == NULL || 1825279002Smav strcmp(oldlun->l_path, newlun->l_path) != 0)) { 1826279002Smav log_debugx("path for lun \"%s\", " 1827279002Smav "CTL lun %d, changed; removing", 1828279002Smav oldlun->l_name, oldlun->l_ctl_lun); 1829279002Smav changed = 1; 1830279002Smav } 1831279002Smav if (newlun->l_serial != NULL && 1832279002Smav (oldlun->l_serial == NULL || 1833279002Smav strcmp(oldlun->l_serial, newlun->l_serial) != 0)) { 1834279002Smav log_debugx("serial for lun \"%s\", " 1835279002Smav "CTL lun %d changed; removing", 1836279002Smav oldlun->l_name, oldlun->l_ctl_lun); 1837279002Smav changed = 1; 1838279002Smav } 1839279002Smav if (changed) { 1840279002Smav error = kernel_lun_remove(oldlun); 1841279002Smav if (error != 0) { 1842279002Smav log_warnx("failed to remove lun \"%s\", " 1843279002Smav "CTL lun %d", 1844279002Smav oldlun->l_name, oldlun->l_ctl_lun); 1845279002Smav cumulated_error++; 1846255570Strasz } 1847279002Smav lun_delete(oldlun); 1848279002Smav continue; 1849279002Smav } 1850255570Strasz 1851279002Smav lun_set_ctl_lun(newlun, oldlun->l_ctl_lun); 1852279002Smav } 1853279002Smav 1854279002Smav TAILQ_FOREACH_SAFE(newlun, &newconf->conf_luns, l_next, tmplun) { 1855279002Smav oldlun = lun_find(oldconf, newlun->l_name); 1856279002Smav if (oldlun != NULL) { 1857279002Smav if (newlun->l_size != oldlun->l_size || 1858279002Smav newlun->l_size == 0) { 1859279002Smav log_debugx("resizing lun \"%s\", CTL lun %d", 1860279002Smav newlun->l_name, newlun->l_ctl_lun); 1861279002Smav error = kernel_lun_resize(newlun); 1862255570Strasz if (error != 0) { 1863279002Smav log_warnx("failed to " 1864279002Smav "resize lun \"%s\", CTL lun %d", 1865279002Smav newlun->l_name, 1866279002Smav newlun->l_ctl_lun); 1867255570Strasz cumulated_error++; 1868255570Strasz } 1869255570Strasz } 1870279002Smav continue; 1871255570Strasz } 1872279002Smav log_debugx("adding lun \"%s\"", newlun->l_name); 1873279002Smav error = kernel_lun_add(newlun); 1874279002Smav if (error != 0) { 1875279002Smav log_warnx("failed to add lun \"%s\"", newlun->l_name); 1876279002Smav lun_delete(newlun); 1877279002Smav cumulated_error++; 1878279002Smav } 1879255570Strasz } 1880255570Strasz 1881255570Strasz /* 1882279006Smav * Now add new ports or modify existing ones. 1883255570Strasz */ 1884279006Smav TAILQ_FOREACH(newport, &newconf->conf_ports, p_next) { 1885279006Smav oldport = port_find(oldconf, newport->p_name); 1886255570Strasz 1887279006Smav if (oldport == NULL) { 1888279006Smav error = kernel_port_add(newport); 1889279006Smav } else { 1890279006Smav newport->p_ctl_port = oldport->p_ctl_port; 1891279006Smav error = kernel_port_update(newport); 1892277749Strasz } 1893279002Smav if (error != 0) { 1894279006Smav log_warnx("failed to %s port %s", 1895279006Smav (oldport == NULL) ? "add" : "update", 1896279006Smav newport->p_name); 1897279002Smav /* 1898279002Smav * XXX: Uncomment after fixing the root cause. 1899279002Smav * 1900279002Smav * cumulated_error++; 1901279002Smav */ 1902279002Smav } 1903255570Strasz } 1904255570Strasz 1905255570Strasz /* 1906255570Strasz * Go through the new portals, opening the sockets as neccessary. 1907255570Strasz */ 1908255570Strasz TAILQ_FOREACH(newpg, &newconf->conf_portal_groups, pg_next) { 1909255570Strasz if (newpg->pg_unassigned) { 1910255570Strasz log_debugx("not listening on portal-group \"%s\", " 1911255570Strasz "not assigned to any target", 1912255570Strasz newpg->pg_name); 1913255570Strasz continue; 1914255570Strasz } 1915255570Strasz TAILQ_FOREACH(newp, &newpg->pg_portals, p_next) { 1916255570Strasz /* 1917255570Strasz * Try to find already open portal and reuse 1918255570Strasz * the listening socket. We don't care about 1919255570Strasz * what portal or portal group that was, what 1920255570Strasz * matters is the listening address. 1921255570Strasz */ 1922255570Strasz TAILQ_FOREACH(oldpg, &oldconf->conf_portal_groups, 1923255570Strasz pg_next) { 1924255570Strasz TAILQ_FOREACH(oldp, &oldpg->pg_portals, 1925255570Strasz p_next) { 1926255570Strasz if (strcmp(newp->p_listen, 1927255570Strasz oldp->p_listen) == 0 && 1928255570Strasz oldp->p_socket > 0) { 1929255570Strasz newp->p_socket = 1930255570Strasz oldp->p_socket; 1931255570Strasz oldp->p_socket = 0; 1932255570Strasz break; 1933255570Strasz } 1934255570Strasz } 1935255570Strasz } 1936255570Strasz if (newp->p_socket > 0) { 1937255570Strasz /* 1938255570Strasz * We're done with this portal. 1939255570Strasz */ 1940255570Strasz continue; 1941255570Strasz } 1942255570Strasz 1943255570Strasz#ifdef ICL_KERNEL_PROXY 1944265507Strasz if (proxy_mode) { 1945265509Strasz newpg->pg_conf->conf_portal_id++; 1946265509Strasz newp->p_id = newpg->pg_conf->conf_portal_id; 1947265509Strasz log_debugx("listening on %s, portal-group " 1948265509Strasz "\"%s\", portal id %d, using ICL proxy", 1949265509Strasz newp->p_listen, newpg->pg_name, newp->p_id); 1950265509Strasz kernel_listen(newp->p_ai, newp->p_iser, 1951265509Strasz newp->p_id); 1952265507Strasz continue; 1953265507Strasz } 1954265507Strasz#endif 1955265507Strasz assert(proxy_mode == false); 1956255570Strasz assert(newp->p_iser == false); 1957255570Strasz 1958255570Strasz log_debugx("listening on %s, portal-group \"%s\"", 1959255570Strasz newp->p_listen, newpg->pg_name); 1960255570Strasz newp->p_socket = socket(newp->p_ai->ai_family, 1961255570Strasz newp->p_ai->ai_socktype, 1962255570Strasz newp->p_ai->ai_protocol); 1963255570Strasz if (newp->p_socket < 0) { 1964255570Strasz log_warn("socket(2) failed for %s", 1965255570Strasz newp->p_listen); 1966255570Strasz cumulated_error++; 1967255570Strasz continue; 1968255570Strasz } 1969279001Smav sockbuf = SOCKBUF_SIZE; 1970279001Smav if (setsockopt(newp->p_socket, SOL_SOCKET, SO_RCVBUF, 1971279001Smav &sockbuf, sizeof(sockbuf)) == -1) 1972279001Smav log_warn("setsockopt(SO_RCVBUF) failed " 1973279001Smav "for %s", newp->p_listen); 1974279001Smav sockbuf = SOCKBUF_SIZE; 1975279001Smav if (setsockopt(newp->p_socket, SOL_SOCKET, SO_SNDBUF, 1976279001Smav &sockbuf, sizeof(sockbuf)) == -1) 1977279001Smav log_warn("setsockopt(SO_SNDBUF) failed " 1978279001Smav "for %s", newp->p_listen); 1979255570Strasz error = setsockopt(newp->p_socket, SOL_SOCKET, 1980255570Strasz SO_REUSEADDR, &one, sizeof(one)); 1981255570Strasz if (error != 0) { 1982255570Strasz log_warn("setsockopt(SO_REUSEADDR) failed " 1983255570Strasz "for %s", newp->p_listen); 1984255570Strasz close(newp->p_socket); 1985255570Strasz newp->p_socket = 0; 1986255570Strasz cumulated_error++; 1987255570Strasz continue; 1988255570Strasz } 1989255570Strasz error = bind(newp->p_socket, newp->p_ai->ai_addr, 1990255570Strasz newp->p_ai->ai_addrlen); 1991255570Strasz if (error != 0) { 1992255570Strasz log_warn("bind(2) failed for %s", 1993255570Strasz newp->p_listen); 1994255570Strasz close(newp->p_socket); 1995255570Strasz newp->p_socket = 0; 1996255570Strasz cumulated_error++; 1997255570Strasz continue; 1998255570Strasz } 1999255570Strasz error = listen(newp->p_socket, -1); 2000255570Strasz if (error != 0) { 2001255570Strasz log_warn("listen(2) failed for %s", 2002255570Strasz newp->p_listen); 2003255570Strasz close(newp->p_socket); 2004255570Strasz newp->p_socket = 0; 2005255570Strasz cumulated_error++; 2006255570Strasz continue; 2007255570Strasz } 2008255570Strasz } 2009255570Strasz } 2010255570Strasz 2011255570Strasz /* 2012255570Strasz * Go through the no longer used sockets, closing them. 2013255570Strasz */ 2014255570Strasz TAILQ_FOREACH(oldpg, &oldconf->conf_portal_groups, pg_next) { 2015255570Strasz TAILQ_FOREACH(oldp, &oldpg->pg_portals, p_next) { 2016255570Strasz if (oldp->p_socket <= 0) 2017255570Strasz continue; 2018255570Strasz log_debugx("closing socket for %s, portal-group \"%s\"", 2019255570Strasz oldp->p_listen, oldpg->pg_name); 2020255570Strasz close(oldp->p_socket); 2021255570Strasz oldp->p_socket = 0; 2022255570Strasz } 2023255570Strasz } 2024255570Strasz 2025274939Smav /* (Re-)Register on remaining/new iSNS servers. */ 2026274939Smav TAILQ_FOREACH(newns, &newconf->conf_isns, i_next) { 2027274939Smav TAILQ_FOREACH(oldns, &oldconf->conf_isns, i_next) { 2028274939Smav if (strcmp(oldns->i_addr, newns->i_addr) == 0) 2029274939Smav break; 2030274939Smav } 2031274939Smav isns_register(newns, oldns); 2032274939Smav } 2033274939Smav 2034274939Smav /* Schedule iSNS update */ 2035274939Smav if (!TAILQ_EMPTY(&newconf->conf_isns)) 2036274939Smav set_timeout((newconf->conf_isns_period + 2) / 3, false); 2037274939Smav 2038255570Strasz return (cumulated_error); 2039255570Strasz} 2040255570Strasz 2041255570Straszbool 2042255570Strasztimed_out(void) 2043255570Strasz{ 2044255570Strasz 2045255570Strasz return (sigalrm_received); 2046255570Strasz} 2047255570Strasz 2048255570Straszstatic void 2049274939Smavsigalrm_handler_fatal(int dummy __unused) 2050255570Strasz{ 2051255570Strasz /* 2052255570Strasz * It would be easiest to just log an error and exit. We can't 2053255570Strasz * do this, though, because log_errx() is not signal safe, since 2054255570Strasz * it calls syslog(3). Instead, set a flag checked by pdu_send() 2055255570Strasz * and pdu_receive(), to call log_errx() there. Should they fail 2056255570Strasz * to notice, we'll exit here one second later. 2057255570Strasz */ 2058255570Strasz if (sigalrm_received) { 2059255570Strasz /* 2060255570Strasz * Oh well. Just give up and quit. 2061255570Strasz */ 2062255570Strasz _exit(2); 2063255570Strasz } 2064255570Strasz 2065255570Strasz sigalrm_received = true; 2066255570Strasz} 2067255570Strasz 2068255570Straszstatic void 2069274939Smavsigalrm_handler(int dummy __unused) 2070255570Strasz{ 2071274939Smav 2072274939Smav sigalrm_received = true; 2073274939Smav} 2074274939Smav 2075274939Smavvoid 2076274939Smavset_timeout(int timeout, int fatal) 2077274939Smav{ 2078255570Strasz struct sigaction sa; 2079255570Strasz struct itimerval itv; 2080255570Strasz int error; 2081255570Strasz 2082274939Smav if (timeout <= 0) { 2083255570Strasz log_debugx("session timeout disabled"); 2084274939Smav bzero(&itv, sizeof(itv)); 2085274939Smav error = setitimer(ITIMER_REAL, &itv, NULL); 2086274939Smav if (error != 0) 2087274939Smav log_err(1, "setitimer"); 2088274939Smav sigalrm_received = false; 2089255570Strasz return; 2090255570Strasz } 2091255570Strasz 2092274939Smav sigalrm_received = false; 2093255570Strasz bzero(&sa, sizeof(sa)); 2094274939Smav if (fatal) 2095274939Smav sa.sa_handler = sigalrm_handler_fatal; 2096274939Smav else 2097274939Smav sa.sa_handler = sigalrm_handler; 2098255570Strasz sigfillset(&sa.sa_mask); 2099255570Strasz error = sigaction(SIGALRM, &sa, NULL); 2100255570Strasz if (error != 0) 2101255570Strasz log_err(1, "sigaction"); 2102255570Strasz 2103255570Strasz /* 2104255570Strasz * First SIGALRM will arive after conf_timeout seconds. 2105255570Strasz * If we do nothing, another one will arrive a second later. 2106255570Strasz */ 2107274939Smav log_debugx("setting session timeout to %d seconds", timeout); 2108255570Strasz bzero(&itv, sizeof(itv)); 2109255570Strasz itv.it_interval.tv_sec = 1; 2110274939Smav itv.it_value.tv_sec = timeout; 2111255570Strasz error = setitimer(ITIMER_REAL, &itv, NULL); 2112255570Strasz if (error != 0) 2113255570Strasz log_err(1, "setitimer"); 2114255570Strasz} 2115255570Strasz 2116255570Straszstatic int 2117255570Straszwait_for_children(bool block) 2118255570Strasz{ 2119255570Strasz pid_t pid; 2120255570Strasz int status; 2121255570Strasz int num = 0; 2122255570Strasz 2123255570Strasz for (;;) { 2124255570Strasz /* 2125255570Strasz * If "block" is true, wait for at least one process. 2126255570Strasz */ 2127255570Strasz if (block && num == 0) 2128255570Strasz pid = wait4(-1, &status, 0, NULL); 2129255570Strasz else 2130255570Strasz pid = wait4(-1, &status, WNOHANG, NULL); 2131255570Strasz if (pid <= 0) 2132255570Strasz break; 2133255570Strasz if (WIFSIGNALED(status)) { 2134255570Strasz log_warnx("child process %d terminated with signal %d", 2135255570Strasz pid, WTERMSIG(status)); 2136255570Strasz } else if (WEXITSTATUS(status) != 0) { 2137255570Strasz log_warnx("child process %d terminated with exit status %d", 2138255570Strasz pid, WEXITSTATUS(status)); 2139255570Strasz } else { 2140255570Strasz log_debugx("child process %d terminated gracefully", pid); 2141255570Strasz } 2142255570Strasz num++; 2143255570Strasz } 2144255570Strasz 2145255570Strasz return (num); 2146255570Strasz} 2147255570Strasz 2148255570Straszstatic void 2149265513Straszhandle_connection(struct portal *portal, int fd, 2150270137Smav const struct sockaddr *client_sa, bool dont_fork) 2151255570Strasz{ 2152255570Strasz struct connection *conn; 2153255570Strasz int error; 2154255570Strasz pid_t pid; 2155255570Strasz char host[NI_MAXHOST + 1]; 2156255570Strasz struct conf *conf; 2157255570Strasz 2158255570Strasz conf = portal->p_portal_group->pg_conf; 2159255570Strasz 2160255570Strasz if (dont_fork) { 2161255570Strasz log_debugx("incoming connection; not forking due to -d flag"); 2162255570Strasz } else { 2163255570Strasz nchildren -= wait_for_children(false); 2164255570Strasz assert(nchildren >= 0); 2165255570Strasz 2166255570Strasz while (conf->conf_maxproc > 0 && nchildren >= conf->conf_maxproc) { 2167255570Strasz log_debugx("maxproc limit of %d child processes hit; " 2168255570Strasz "waiting for child process to exit", conf->conf_maxproc); 2169255570Strasz nchildren -= wait_for_children(true); 2170255570Strasz assert(nchildren >= 0); 2171255570Strasz } 2172255570Strasz log_debugx("incoming connection; forking child process #%d", 2173255570Strasz nchildren); 2174255570Strasz nchildren++; 2175255570Strasz pid = fork(); 2176255570Strasz if (pid < 0) 2177255570Strasz log_err(1, "fork"); 2178255570Strasz if (pid > 0) { 2179255570Strasz close(fd); 2180255570Strasz return; 2181255570Strasz } 2182255570Strasz } 2183255570Strasz pidfile_close(conf->conf_pidfh); 2184255570Strasz 2185270137Smav error = getnameinfo(client_sa, client_sa->sa_len, 2186265513Strasz host, sizeof(host), NULL, 0, NI_NUMERICHOST); 2187265513Strasz if (error != 0) 2188265513Strasz log_errx(1, "getnameinfo: %s", gai_strerror(error)); 2189255570Strasz 2190265513Strasz log_debugx("accepted connection from %s; portal group \"%s\"", 2191265513Strasz host, portal->p_portal_group->pg_name); 2192265513Strasz log_set_peer_addr(host); 2193265513Strasz setproctitle("%s", host); 2194255570Strasz 2195270137Smav conn = connection_new(portal, fd, host, client_sa); 2196274939Smav set_timeout(conf->conf_timeout, true); 2197255570Strasz kernel_capsicate(); 2198255570Strasz login(conn); 2199255570Strasz if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) { 2200255570Strasz kernel_handoff(conn); 2201255570Strasz log_debugx("connection handed off to the kernel"); 2202255570Strasz } else { 2203255570Strasz assert(conn->conn_session_type == CONN_SESSION_TYPE_DISCOVERY); 2204255570Strasz discovery(conn); 2205255570Strasz } 2206255570Strasz log_debugx("nothing more to do; exiting"); 2207255570Strasz exit(0); 2208255570Strasz} 2209255570Strasz 2210255570Straszstatic int 2211255570Straszfd_add(int fd, fd_set *fdset, int nfds) 2212255570Strasz{ 2213255570Strasz 2214255570Strasz /* 2215255570Strasz * Skip sockets which we failed to bind. 2216255570Strasz */ 2217255570Strasz if (fd <= 0) 2218255570Strasz return (nfds); 2219255570Strasz 2220255570Strasz FD_SET(fd, fdset); 2221255570Strasz if (fd > nfds) 2222255570Strasz nfds = fd; 2223255570Strasz return (nfds); 2224255570Strasz} 2225255570Strasz 2226255570Straszstatic void 2227255570Straszmain_loop(struct conf *conf, bool dont_fork) 2228255570Strasz{ 2229255570Strasz struct portal_group *pg; 2230255570Strasz struct portal *portal; 2231265512Strasz struct sockaddr_storage client_sa; 2232265512Strasz socklen_t client_salen; 2233255570Strasz#ifdef ICL_KERNEL_PROXY 2234255570Strasz int connection_id; 2235265509Strasz int portal_id; 2236265507Strasz#endif 2237255570Strasz fd_set fdset; 2238255570Strasz int error, nfds, client_fd; 2239255570Strasz 2240255570Strasz pidfile_write(conf->conf_pidfh); 2241255570Strasz 2242255570Strasz for (;;) { 2243274939Smav if (sighup_received || sigterm_received || timed_out()) 2244255570Strasz return; 2245255570Strasz 2246255570Strasz#ifdef ICL_KERNEL_PROXY 2247265507Strasz if (proxy_mode) { 2248265513Strasz client_salen = sizeof(client_sa); 2249265513Strasz kernel_accept(&connection_id, &portal_id, 2250265513Strasz (struct sockaddr *)&client_sa, &client_salen); 2251271627Strasz assert(client_salen >= client_sa.ss_len); 2252255570Strasz 2253265509Strasz log_debugx("incoming connection, id %d, portal id %d", 2254265509Strasz connection_id, portal_id); 2255265509Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 2256265509Strasz TAILQ_FOREACH(portal, &pg->pg_portals, p_next) { 2257265509Strasz if (portal->p_id == portal_id) { 2258265509Strasz goto found; 2259265509Strasz } 2260265509Strasz } 2261265509Strasz } 2262255570Strasz 2263265509Strasz log_errx(1, "kernel returned invalid portal_id %d", 2264265509Strasz portal_id); 2265265509Strasz 2266265509Straszfound: 2267265513Strasz handle_connection(portal, connection_id, 2268270137Smav (struct sockaddr *)&client_sa, dont_fork); 2269265507Strasz } else { 2270265507Strasz#endif 2271265507Strasz assert(proxy_mode == false); 2272265507Strasz 2273265507Strasz FD_ZERO(&fdset); 2274265507Strasz nfds = 0; 2275265507Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 2276265507Strasz TAILQ_FOREACH(portal, &pg->pg_portals, p_next) 2277265507Strasz nfds = fd_add(portal->p_socket, &fdset, nfds); 2278255570Strasz } 2279265507Strasz error = select(nfds + 1, &fdset, NULL, NULL, NULL); 2280265507Strasz if (error <= 0) { 2281265507Strasz if (errno == EINTR) 2282265507Strasz return; 2283265507Strasz log_err(1, "select"); 2284265507Strasz } 2285265507Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 2286265507Strasz TAILQ_FOREACH(portal, &pg->pg_portals, p_next) { 2287265507Strasz if (!FD_ISSET(portal->p_socket, &fdset)) 2288265507Strasz continue; 2289265512Strasz client_salen = sizeof(client_sa); 2290265512Strasz client_fd = accept(portal->p_socket, 2291265512Strasz (struct sockaddr *)&client_sa, 2292265512Strasz &client_salen); 2293265507Strasz if (client_fd < 0) 2294265507Strasz log_err(1, "accept"); 2295271627Strasz assert(client_salen >= client_sa.ss_len); 2296271627Strasz 2297265512Strasz handle_connection(portal, client_fd, 2298265513Strasz (struct sockaddr *)&client_sa, 2299270137Smav dont_fork); 2300265507Strasz break; 2301265507Strasz } 2302265507Strasz } 2303265507Strasz#ifdef ICL_KERNEL_PROXY 2304255570Strasz } 2305265507Strasz#endif 2306255570Strasz } 2307255570Strasz} 2308255570Strasz 2309255570Straszstatic void 2310255570Straszsighup_handler(int dummy __unused) 2311255570Strasz{ 2312255570Strasz 2313255570Strasz sighup_received = true; 2314255570Strasz} 2315255570Strasz 2316255570Straszstatic void 2317255570Straszsigterm_handler(int dummy __unused) 2318255570Strasz{ 2319255570Strasz 2320255570Strasz sigterm_received = true; 2321255570Strasz} 2322255570Strasz 2323255570Straszstatic void 2324263730Straszsigchld_handler(int dummy __unused) 2325263730Strasz{ 2326263730Strasz 2327263730Strasz /* 2328263730Strasz * The only purpose of this handler is to make SIGCHLD 2329263730Strasz * interrupt the ISCSIDWAIT ioctl(2), so we can call 2330263730Strasz * wait_for_children(). 2331263730Strasz */ 2332263730Strasz} 2333263730Strasz 2334263730Straszstatic void 2335255570Straszregister_signals(void) 2336255570Strasz{ 2337255570Strasz struct sigaction sa; 2338255570Strasz int error; 2339255570Strasz 2340255570Strasz bzero(&sa, sizeof(sa)); 2341255570Strasz sa.sa_handler = sighup_handler; 2342255570Strasz sigfillset(&sa.sa_mask); 2343255570Strasz error = sigaction(SIGHUP, &sa, NULL); 2344255570Strasz if (error != 0) 2345255570Strasz log_err(1, "sigaction"); 2346255570Strasz 2347255570Strasz sa.sa_handler = sigterm_handler; 2348255570Strasz error = sigaction(SIGTERM, &sa, NULL); 2349255570Strasz if (error != 0) 2350255570Strasz log_err(1, "sigaction"); 2351255570Strasz 2352255570Strasz sa.sa_handler = sigterm_handler; 2353255570Strasz error = sigaction(SIGINT, &sa, NULL); 2354255570Strasz if (error != 0) 2355255570Strasz log_err(1, "sigaction"); 2356263730Strasz 2357263730Strasz sa.sa_handler = sigchld_handler; 2358263730Strasz error = sigaction(SIGCHLD, &sa, NULL); 2359263730Strasz if (error != 0) 2360263730Strasz log_err(1, "sigaction"); 2361255570Strasz} 2362255570Strasz 2363255570Straszint 2364255570Straszmain(int argc, char **argv) 2365255570Strasz{ 2366255570Strasz struct conf *oldconf, *newconf, *tmpconf; 2367274939Smav struct isns *newns; 2368255570Strasz const char *config_path = DEFAULT_CONFIG_PATH; 2369255570Strasz int debug = 0, ch, error; 2370255570Strasz bool dont_daemonize = false; 2371255570Strasz 2372265507Strasz while ((ch = getopt(argc, argv, "df:R")) != -1) { 2373255570Strasz switch (ch) { 2374255570Strasz case 'd': 2375255570Strasz dont_daemonize = true; 2376255570Strasz debug++; 2377255570Strasz break; 2378255570Strasz case 'f': 2379255570Strasz config_path = optarg; 2380255570Strasz break; 2381265507Strasz case 'R': 2382265507Strasz#ifndef ICL_KERNEL_PROXY 2383265507Strasz log_errx(1, "ctld(8) compiled without ICL_KERNEL_PROXY " 2384265507Strasz "does not support iSER protocol"); 2385265507Strasz#endif 2386265507Strasz proxy_mode = true; 2387265507Strasz break; 2388255570Strasz case '?': 2389255570Strasz default: 2390255570Strasz usage(); 2391255570Strasz } 2392255570Strasz } 2393255570Strasz argc -= optind; 2394255570Strasz if (argc != 0) 2395255570Strasz usage(); 2396255570Strasz 2397255570Strasz log_init(debug); 2398255570Strasz kernel_init(); 2399255570Strasz 2400255570Strasz oldconf = conf_new_from_kernel(); 2401255570Strasz newconf = conf_new_from_file(config_path); 2402255570Strasz if (newconf == NULL) 2403265516Strasz log_errx(1, "configuration error; exiting"); 2404255570Strasz if (debug > 0) { 2405255570Strasz oldconf->conf_debug = debug; 2406255570Strasz newconf->conf_debug = debug; 2407255570Strasz } 2408255570Strasz 2409255570Strasz error = conf_apply(oldconf, newconf); 2410255570Strasz if (error != 0) 2411265516Strasz log_errx(1, "failed to apply configuration; exiting"); 2412265516Strasz 2413255570Strasz conf_delete(oldconf); 2414255570Strasz oldconf = NULL; 2415255570Strasz 2416255570Strasz register_signals(); 2417255570Strasz 2418263719Strasz if (dont_daemonize == false) { 2419263719Strasz log_debugx("daemonizing"); 2420263719Strasz if (daemon(0, 0) == -1) { 2421263719Strasz log_warn("cannot daemonize"); 2422263719Strasz pidfile_remove(newconf->conf_pidfh); 2423263719Strasz exit(1); 2424263719Strasz } 2425263719Strasz } 2426263719Strasz 2427274939Smav /* Schedule iSNS update */ 2428274939Smav if (!TAILQ_EMPTY(&newconf->conf_isns)) 2429274939Smav set_timeout((newconf->conf_isns_period + 2) / 3, false); 2430274939Smav 2431255570Strasz for (;;) { 2432255570Strasz main_loop(newconf, dont_daemonize); 2433255570Strasz if (sighup_received) { 2434255570Strasz sighup_received = false; 2435255570Strasz log_debugx("received SIGHUP, reloading configuration"); 2436255570Strasz tmpconf = conf_new_from_file(config_path); 2437255570Strasz if (tmpconf == NULL) { 2438255570Strasz log_warnx("configuration error, " 2439255570Strasz "continuing with old configuration"); 2440255570Strasz } else { 2441255570Strasz if (debug > 0) 2442255570Strasz tmpconf->conf_debug = debug; 2443255570Strasz oldconf = newconf; 2444255570Strasz newconf = tmpconf; 2445255570Strasz error = conf_apply(oldconf, newconf); 2446255570Strasz if (error != 0) 2447255570Strasz log_warnx("failed to reload " 2448255570Strasz "configuration"); 2449255570Strasz conf_delete(oldconf); 2450255570Strasz oldconf = NULL; 2451255570Strasz } 2452255570Strasz } else if (sigterm_received) { 2453255570Strasz log_debugx("exiting on signal; " 2454255570Strasz "reloading empty configuration"); 2455255570Strasz 2456279003Smav log_debugx("removing CTL iSCSI ports " 2457255570Strasz "and terminating all connections"); 2458255570Strasz 2459255570Strasz oldconf = newconf; 2460255570Strasz newconf = conf_new(); 2461255570Strasz if (debug > 0) 2462255570Strasz newconf->conf_debug = debug; 2463255570Strasz error = conf_apply(oldconf, newconf); 2464255570Strasz if (error != 0) 2465255570Strasz log_warnx("failed to apply configuration"); 2466274939Smav conf_delete(oldconf); 2467274939Smav oldconf = NULL; 2468255570Strasz 2469255570Strasz log_warnx("exiting on signal"); 2470255570Strasz exit(0); 2471255570Strasz } else { 2472255570Strasz nchildren -= wait_for_children(false); 2473255570Strasz assert(nchildren >= 0); 2474274939Smav if (timed_out()) { 2475274939Smav set_timeout(0, false); 2476274939Smav TAILQ_FOREACH(newns, &newconf->conf_isns, i_next) 2477274939Smav isns_check(newns); 2478274939Smav /* Schedule iSNS update */ 2479274939Smav if (!TAILQ_EMPTY(&newconf->conf_isns)) { 2480274939Smav set_timeout((newconf->conf_isns_period 2481274939Smav + 2) / 3, 2482274939Smav false); 2483274939Smav } 2484274939Smav } 2485255570Strasz } 2486255570Strasz } 2487255570Strasz /* NOTREACHED */ 2488255570Strasz} 2489