ctld.c revision 277749
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 277749 2015-01-26 13:21:30Z trasz $"); 33270888Strasz 34255570Strasz#include <sys/types.h> 35255570Strasz#include <sys/time.h> 36255570Strasz#include <sys/socket.h> 37255570Strasz#include <sys/wait.h> 38255570Strasz#include <netinet/in.h> 39270137Smav#include <arpa/inet.h> 40255570Strasz#include <assert.h> 41255570Strasz#include <ctype.h> 42255570Strasz#include <errno.h> 43255570Strasz#include <netdb.h> 44255570Strasz#include <signal.h> 45255570Strasz#include <stdbool.h> 46255570Strasz#include <stdio.h> 47255570Strasz#include <stdint.h> 48255570Strasz#include <stdlib.h> 49255570Strasz#include <string.h> 50255570Strasz#include <unistd.h> 51255570Strasz 52255570Strasz#include "ctld.h" 53274939Smav#include "isns.h" 54255570Strasz 55265507Straszbool proxy_mode = false; 56265507Strasz 57255570Straszstatic volatile bool sighup_received = false; 58255570Straszstatic volatile bool sigterm_received = false; 59255570Straszstatic volatile bool sigalrm_received = false; 60255570Strasz 61255570Straszstatic int nchildren = 0; 62255570Strasz 63255570Straszstatic void 64255570Straszusage(void) 65255570Strasz{ 66255570Strasz 67255570Strasz fprintf(stderr, "usage: ctld [-d][-f config-file]\n"); 68255570Strasz exit(1); 69255570Strasz} 70255570Strasz 71255570Straszchar * 72255570Straszchecked_strdup(const char *s) 73255570Strasz{ 74255570Strasz char *c; 75255570Strasz 76255570Strasz c = strdup(s); 77255570Strasz if (c == NULL) 78255570Strasz log_err(1, "strdup"); 79255570Strasz return (c); 80255570Strasz} 81255570Strasz 82255570Straszstruct conf * 83255570Straszconf_new(void) 84255570Strasz{ 85255570Strasz struct conf *conf; 86255570Strasz 87255570Strasz conf = calloc(1, sizeof(*conf)); 88255570Strasz if (conf == NULL) 89255570Strasz log_err(1, "calloc"); 90255570Strasz TAILQ_INIT(&conf->conf_targets); 91255570Strasz TAILQ_INIT(&conf->conf_auth_groups); 92255570Strasz TAILQ_INIT(&conf->conf_portal_groups); 93274939Smav TAILQ_INIT(&conf->conf_isns); 94255570Strasz 95274939Smav conf->conf_isns_period = 900; 96274939Smav conf->conf_isns_timeout = 5; 97255570Strasz conf->conf_debug = 0; 98255570Strasz conf->conf_timeout = 60; 99255570Strasz conf->conf_maxproc = 30; 100255570Strasz 101255570Strasz return (conf); 102255570Strasz} 103255570Strasz 104255570Straszvoid 105255570Straszconf_delete(struct conf *conf) 106255570Strasz{ 107255570Strasz struct target *targ, *tmp; 108255570Strasz struct auth_group *ag, *cagtmp; 109255570Strasz struct portal_group *pg, *cpgtmp; 110274939Smav struct isns *is, *istmp; 111255570Strasz 112255570Strasz assert(conf->conf_pidfh == NULL); 113255570Strasz 114255570Strasz TAILQ_FOREACH_SAFE(targ, &conf->conf_targets, t_next, tmp) 115255570Strasz target_delete(targ); 116255570Strasz TAILQ_FOREACH_SAFE(ag, &conf->conf_auth_groups, ag_next, cagtmp) 117255570Strasz auth_group_delete(ag); 118255570Strasz TAILQ_FOREACH_SAFE(pg, &conf->conf_portal_groups, pg_next, cpgtmp) 119255570Strasz portal_group_delete(pg); 120274939Smav TAILQ_FOREACH_SAFE(is, &conf->conf_isns, i_next, istmp) 121274939Smav isns_delete(is); 122255570Strasz free(conf->conf_pidfile_path); 123255570Strasz free(conf); 124255570Strasz} 125255570Strasz 126255570Straszstatic struct auth * 127255570Straszauth_new(struct auth_group *ag) 128255570Strasz{ 129255570Strasz struct auth *auth; 130255570Strasz 131255570Strasz auth = calloc(1, sizeof(*auth)); 132255570Strasz if (auth == NULL) 133255570Strasz log_err(1, "calloc"); 134255570Strasz auth->a_auth_group = ag; 135255570Strasz TAILQ_INSERT_TAIL(&ag->ag_auths, auth, a_next); 136255570Strasz return (auth); 137255570Strasz} 138255570Strasz 139255570Straszstatic void 140255570Straszauth_delete(struct auth *auth) 141255570Strasz{ 142255570Strasz TAILQ_REMOVE(&auth->a_auth_group->ag_auths, auth, a_next); 143255570Strasz 144255570Strasz free(auth->a_user); 145255570Strasz free(auth->a_secret); 146255570Strasz free(auth->a_mutual_user); 147255570Strasz free(auth->a_mutual_secret); 148255570Strasz free(auth); 149255570Strasz} 150255570Strasz 151255570Straszconst struct auth * 152265514Straszauth_find(const struct auth_group *ag, const char *user) 153255570Strasz{ 154255570Strasz const struct auth *auth; 155255570Strasz 156255570Strasz TAILQ_FOREACH(auth, &ag->ag_auths, a_next) { 157255570Strasz if (strcmp(auth->a_user, user) == 0) 158255570Strasz return (auth); 159255570Strasz } 160255570Strasz 161255570Strasz return (NULL); 162255570Strasz} 163255570Strasz 164263721Straszstatic void 165263721Straszauth_check_secret_length(struct auth *auth) 166263721Strasz{ 167263721Strasz size_t len; 168263721Strasz 169263721Strasz len = strlen(auth->a_secret); 170263721Strasz if (len > 16) { 171263721Strasz if (auth->a_auth_group->ag_name != NULL) 172263721Strasz log_warnx("secret for user \"%s\", auth-group \"%s\", " 173263721Strasz "is too long; it should be at most 16 characters " 174263721Strasz "long", auth->a_user, auth->a_auth_group->ag_name); 175263721Strasz else 176263721Strasz log_warnx("secret for user \"%s\", target \"%s\", " 177263721Strasz "is too long; it should be at most 16 characters " 178263721Strasz "long", auth->a_user, 179263723Strasz auth->a_auth_group->ag_target->t_name); 180263721Strasz } 181263721Strasz if (len < 12) { 182263721Strasz if (auth->a_auth_group->ag_name != NULL) 183263721Strasz log_warnx("secret for user \"%s\", auth-group \"%s\", " 184263721Strasz "is too short; it should be at least 12 characters " 185263721Strasz "long", auth->a_user, 186263721Strasz auth->a_auth_group->ag_name); 187263721Strasz else 188263721Strasz log_warnx("secret for user \"%s\", target \"%s\", " 189263721Strasz "is too short; it should be at least 16 characters " 190263721Strasz "long", auth->a_user, 191263723Strasz auth->a_auth_group->ag_target->t_name); 192263721Strasz } 193263721Strasz 194263721Strasz if (auth->a_mutual_secret != NULL) { 195263721Strasz len = strlen(auth->a_secret); 196263721Strasz if (len > 16) { 197263721Strasz if (auth->a_auth_group->ag_name != NULL) 198263721Strasz log_warnx("mutual secret for user \"%s\", " 199263721Strasz "auth-group \"%s\", is too long; it should " 200263721Strasz "be at most 16 characters long", 201263721Strasz auth->a_user, auth->a_auth_group->ag_name); 202263721Strasz else 203263721Strasz log_warnx("mutual secret for user \"%s\", " 204263721Strasz "target \"%s\", is too long; it should " 205263721Strasz "be at most 16 characters long", 206263721Strasz auth->a_user, 207263723Strasz auth->a_auth_group->ag_target->t_name); 208263721Strasz } 209263721Strasz if (len < 12) { 210263721Strasz if (auth->a_auth_group->ag_name != NULL) 211263721Strasz log_warnx("mutual secret for user \"%s\", " 212263721Strasz "auth-group \"%s\", is too short; it " 213263721Strasz "should be at least 12 characters long", 214263721Strasz auth->a_user, auth->a_auth_group->ag_name); 215263721Strasz else 216263721Strasz log_warnx("mutual secret for user \"%s\", " 217263721Strasz "target \"%s\", is too short; it should be " 218263721Strasz "at least 16 characters long", 219263721Strasz auth->a_user, 220263723Strasz auth->a_auth_group->ag_target->t_name); 221263721Strasz } 222263721Strasz } 223263721Strasz} 224263721Strasz 225263721Straszconst struct auth * 226263721Straszauth_new_chap(struct auth_group *ag, const char *user, 227263721Strasz const char *secret) 228263721Strasz{ 229263721Strasz struct auth *auth; 230263721Strasz 231263721Strasz if (ag->ag_type == AG_TYPE_UNKNOWN) 232263721Strasz ag->ag_type = AG_TYPE_CHAP; 233263721Strasz if (ag->ag_type != AG_TYPE_CHAP) { 234263721Strasz if (ag->ag_name != NULL) 235263721Strasz log_warnx("cannot mix \"chap\" authentication with " 236263721Strasz "other types for auth-group \"%s\"", ag->ag_name); 237263721Strasz else 238263721Strasz log_warnx("cannot mix \"chap\" authentication with " 239263721Strasz "other types for target \"%s\"", 240263723Strasz ag->ag_target->t_name); 241263721Strasz return (NULL); 242263721Strasz } 243263721Strasz 244263721Strasz auth = auth_new(ag); 245263721Strasz auth->a_user = checked_strdup(user); 246263721Strasz auth->a_secret = checked_strdup(secret); 247263721Strasz 248263721Strasz auth_check_secret_length(auth); 249263721Strasz 250263721Strasz return (auth); 251263721Strasz} 252263721Strasz 253263721Straszconst struct auth * 254263721Straszauth_new_chap_mutual(struct auth_group *ag, const char *user, 255263721Strasz const char *secret, const char *user2, const char *secret2) 256263721Strasz{ 257263721Strasz struct auth *auth; 258263721Strasz 259263721Strasz if (ag->ag_type == AG_TYPE_UNKNOWN) 260263721Strasz ag->ag_type = AG_TYPE_CHAP_MUTUAL; 261263721Strasz if (ag->ag_type != AG_TYPE_CHAP_MUTUAL) { 262263721Strasz if (ag->ag_name != NULL) 263263721Strasz log_warnx("cannot mix \"chap-mutual\" authentication " 264263721Strasz "with other types for auth-group \"%s\"", 265274870Strasz ag->ag_name); 266263721Strasz else 267263721Strasz log_warnx("cannot mix \"chap-mutual\" authentication " 268263721Strasz "with other types for target \"%s\"", 269263723Strasz ag->ag_target->t_name); 270263721Strasz return (NULL); 271263721Strasz } 272263721Strasz 273263721Strasz auth = auth_new(ag); 274263721Strasz auth->a_user = checked_strdup(user); 275263721Strasz auth->a_secret = checked_strdup(secret); 276263721Strasz auth->a_mutual_user = checked_strdup(user2); 277263721Strasz auth->a_mutual_secret = checked_strdup(secret2); 278263721Strasz 279263721Strasz auth_check_secret_length(auth); 280263721Strasz 281263721Strasz return (auth); 282263721Strasz} 283263721Strasz 284263720Straszconst struct auth_name * 285263720Straszauth_name_new(struct auth_group *ag, const char *name) 286263720Strasz{ 287263720Strasz struct auth_name *an; 288263720Strasz 289263720Strasz an = calloc(1, sizeof(*an)); 290263720Strasz if (an == NULL) 291263720Strasz log_err(1, "calloc"); 292263720Strasz an->an_auth_group = ag; 293263720Strasz an->an_initator_name = checked_strdup(name); 294263720Strasz TAILQ_INSERT_TAIL(&ag->ag_names, an, an_next); 295263720Strasz return (an); 296263720Strasz} 297263720Strasz 298263720Straszstatic void 299263720Straszauth_name_delete(struct auth_name *an) 300263720Strasz{ 301263720Strasz TAILQ_REMOVE(&an->an_auth_group->ag_names, an, an_next); 302263720Strasz 303263720Strasz free(an->an_initator_name); 304263720Strasz free(an); 305263720Strasz} 306263720Strasz 307263720Straszbool 308263720Straszauth_name_defined(const struct auth_group *ag) 309263720Strasz{ 310263720Strasz if (TAILQ_EMPTY(&ag->ag_names)) 311263720Strasz return (false); 312263720Strasz return (true); 313263720Strasz} 314263720Strasz 315263720Straszconst struct auth_name * 316263720Straszauth_name_find(const struct auth_group *ag, const char *name) 317263720Strasz{ 318263720Strasz const struct auth_name *auth_name; 319263720Strasz 320263720Strasz TAILQ_FOREACH(auth_name, &ag->ag_names, an_next) { 321263720Strasz if (strcmp(auth_name->an_initator_name, name) == 0) 322263720Strasz return (auth_name); 323263720Strasz } 324263720Strasz 325263720Strasz return (NULL); 326263720Strasz} 327263720Strasz 328274949Straszint 329274949Straszauth_name_check(const struct auth_group *ag, const char *initiator_name) 330274949Strasz{ 331274949Strasz if (!auth_name_defined(ag)) 332274949Strasz return (0); 333274949Strasz 334274949Strasz if (auth_name_find(ag, initiator_name) == NULL) 335274949Strasz return (1); 336274949Strasz 337274949Strasz return (0); 338274949Strasz} 339274949Strasz 340263720Straszconst struct auth_portal * 341263720Straszauth_portal_new(struct auth_group *ag, const char *portal) 342263720Strasz{ 343263720Strasz struct auth_portal *ap; 344270137Smav char *net, *mask, *str, *tmp; 345270137Smav int len, dm, m; 346263720Strasz 347263720Strasz ap = calloc(1, sizeof(*ap)); 348263720Strasz if (ap == NULL) 349263720Strasz log_err(1, "calloc"); 350263720Strasz ap->ap_auth_group = ag; 351263720Strasz ap->ap_initator_portal = checked_strdup(portal); 352270137Smav mask = str = checked_strdup(portal); 353270137Smav net = strsep(&mask, "/"); 354270137Smav if (net[0] == '[') 355270137Smav net++; 356270137Smav len = strlen(net); 357270137Smav if (len == 0) 358270137Smav goto error; 359270137Smav if (net[len - 1] == ']') 360270137Smav net[len - 1] = 0; 361270137Smav if (strchr(net, ':') != NULL) { 362270137Smav struct sockaddr_in6 *sin6 = 363270137Smav (struct sockaddr_in6 *)&ap->ap_sa; 364270137Smav 365270137Smav sin6->sin6_len = sizeof(*sin6); 366270137Smav sin6->sin6_family = AF_INET6; 367270137Smav if (inet_pton(AF_INET6, net, &sin6->sin6_addr) <= 0) 368270137Smav goto error; 369270137Smav dm = 128; 370270137Smav } else { 371270137Smav struct sockaddr_in *sin = 372270137Smav (struct sockaddr_in *)&ap->ap_sa; 373270137Smav 374270137Smav sin->sin_len = sizeof(*sin); 375270137Smav sin->sin_family = AF_INET; 376270137Smav if (inet_pton(AF_INET, net, &sin->sin_addr) <= 0) 377270137Smav goto error; 378270137Smav dm = 32; 379270137Smav } 380270137Smav if (mask != NULL) { 381270137Smav m = strtol(mask, &tmp, 0); 382270137Smav if (m < 0 || m > dm || tmp[0] != 0) 383270137Smav goto error; 384270137Smav } else 385270137Smav m = dm; 386270137Smav ap->ap_mask = m; 387270137Smav free(str); 388263720Strasz TAILQ_INSERT_TAIL(&ag->ag_portals, ap, ap_next); 389263720Strasz return (ap); 390270137Smav 391270137Smaverror: 392270137Smav log_errx(1, "Incorrect initiator portal '%s'", portal); 393270137Smav return (NULL); 394263720Strasz} 395263720Strasz 396263720Straszstatic void 397263720Straszauth_portal_delete(struct auth_portal *ap) 398263720Strasz{ 399263720Strasz TAILQ_REMOVE(&ap->ap_auth_group->ag_portals, ap, ap_next); 400263720Strasz 401263720Strasz free(ap->ap_initator_portal); 402263720Strasz free(ap); 403263720Strasz} 404263720Strasz 405263720Straszbool 406263720Straszauth_portal_defined(const struct auth_group *ag) 407263720Strasz{ 408263720Strasz if (TAILQ_EMPTY(&ag->ag_portals)) 409263720Strasz return (false); 410263720Strasz return (true); 411263720Strasz} 412263720Strasz 413263720Straszconst struct auth_portal * 414270137Smavauth_portal_find(const struct auth_group *ag, const struct sockaddr_storage *ss) 415263720Strasz{ 416270137Smav const struct auth_portal *ap; 417270137Smav const uint8_t *a, *b; 418270137Smav int i; 419270137Smav uint8_t bmask; 420263720Strasz 421270137Smav TAILQ_FOREACH(ap, &ag->ag_portals, ap_next) { 422270137Smav if (ap->ap_sa.ss_family != ss->ss_family) 423270137Smav continue; 424270137Smav if (ss->ss_family == AF_INET) { 425270137Smav a = (const uint8_t *) 426270137Smav &((const struct sockaddr_in *)ss)->sin_addr; 427270137Smav b = (const uint8_t *) 428270137Smav &((const struct sockaddr_in *)&ap->ap_sa)->sin_addr; 429270137Smav } else { 430270137Smav a = (const uint8_t *) 431270137Smav &((const struct sockaddr_in6 *)ss)->sin6_addr; 432270137Smav b = (const uint8_t *) 433270137Smav &((const struct sockaddr_in6 *)&ap->ap_sa)->sin6_addr; 434270137Smav } 435270137Smav for (i = 0; i < ap->ap_mask / 8; i++) { 436270137Smav if (a[i] != b[i]) 437270137Smav goto next; 438270137Smav } 439270137Smav if (ap->ap_mask % 8) { 440270137Smav bmask = 0xff << (8 - (ap->ap_mask % 8)); 441270137Smav if ((a[i] & bmask) != (b[i] & bmask)) 442270137Smav goto next; 443270137Smav } 444270137Smav return (ap); 445270137Smavnext: 446270137Smav ; 447263720Strasz } 448263720Strasz 449263720Strasz return (NULL); 450263720Strasz} 451263720Strasz 452274949Straszint 453274949Straszauth_portal_check(const struct auth_group *ag, const struct sockaddr_storage *sa) 454274949Strasz{ 455274949Strasz 456274949Strasz if (!auth_portal_defined(ag)) 457274949Strasz return (0); 458274949Strasz 459274949Strasz if (auth_portal_find(ag, sa) == NULL) 460274949Strasz return (1); 461274949Strasz 462274949Strasz return (0); 463274949Strasz} 464274949Strasz 465255570Straszstruct auth_group * 466255570Straszauth_group_new(struct conf *conf, const char *name) 467255570Strasz{ 468255570Strasz struct auth_group *ag; 469255570Strasz 470255570Strasz if (name != NULL) { 471255570Strasz ag = auth_group_find(conf, name); 472255570Strasz if (ag != NULL) { 473255570Strasz log_warnx("duplicated auth-group \"%s\"", name); 474255570Strasz return (NULL); 475255570Strasz } 476255570Strasz } 477255570Strasz 478255570Strasz ag = calloc(1, sizeof(*ag)); 479255570Strasz if (ag == NULL) 480255570Strasz log_err(1, "calloc"); 481255570Strasz if (name != NULL) 482255570Strasz ag->ag_name = checked_strdup(name); 483255570Strasz TAILQ_INIT(&ag->ag_auths); 484263720Strasz TAILQ_INIT(&ag->ag_names); 485263720Strasz TAILQ_INIT(&ag->ag_portals); 486255570Strasz ag->ag_conf = conf; 487255570Strasz TAILQ_INSERT_TAIL(&conf->conf_auth_groups, ag, ag_next); 488255570Strasz 489255570Strasz return (ag); 490255570Strasz} 491255570Strasz 492255570Straszvoid 493255570Straszauth_group_delete(struct auth_group *ag) 494255570Strasz{ 495263720Strasz struct auth *auth, *auth_tmp; 496263720Strasz struct auth_name *auth_name, *auth_name_tmp; 497263720Strasz struct auth_portal *auth_portal, *auth_portal_tmp; 498255570Strasz 499255570Strasz TAILQ_REMOVE(&ag->ag_conf->conf_auth_groups, ag, ag_next); 500255570Strasz 501263720Strasz TAILQ_FOREACH_SAFE(auth, &ag->ag_auths, a_next, auth_tmp) 502255570Strasz auth_delete(auth); 503263720Strasz TAILQ_FOREACH_SAFE(auth_name, &ag->ag_names, an_next, auth_name_tmp) 504263720Strasz auth_name_delete(auth_name); 505263720Strasz TAILQ_FOREACH_SAFE(auth_portal, &ag->ag_portals, ap_next, 506263720Strasz auth_portal_tmp) 507263720Strasz auth_portal_delete(auth_portal); 508255570Strasz free(ag->ag_name); 509255570Strasz free(ag); 510255570Strasz} 511255570Strasz 512255570Straszstruct auth_group * 513265514Straszauth_group_find(const struct conf *conf, const char *name) 514255570Strasz{ 515255570Strasz struct auth_group *ag; 516255570Strasz 517255570Strasz TAILQ_FOREACH(ag, &conf->conf_auth_groups, ag_next) { 518255570Strasz if (ag->ag_name != NULL && strcmp(ag->ag_name, name) == 0) 519255570Strasz return (ag); 520255570Strasz } 521255570Strasz 522255570Strasz return (NULL); 523255570Strasz} 524255570Strasz 525263724Straszint 526275245Straszauth_group_set_type(struct auth_group *ag, const char *str) 527263724Strasz{ 528275245Strasz int type; 529263724Strasz 530263724Strasz if (strcmp(str, "none") == 0) { 531263724Strasz type = AG_TYPE_NO_AUTHENTICATION; 532263729Strasz } else if (strcmp(str, "deny") == 0) { 533263729Strasz type = AG_TYPE_DENY; 534263724Strasz } else if (strcmp(str, "chap") == 0) { 535263724Strasz type = AG_TYPE_CHAP; 536263724Strasz } else if (strcmp(str, "chap-mutual") == 0) { 537263724Strasz type = AG_TYPE_CHAP_MUTUAL; 538263724Strasz } else { 539263724Strasz if (ag->ag_name != NULL) 540263724Strasz log_warnx("invalid auth-type \"%s\" for auth-group " 541263724Strasz "\"%s\"", str, ag->ag_name); 542263724Strasz else 543263724Strasz log_warnx("invalid auth-type \"%s\" for target " 544263724Strasz "\"%s\"", str, ag->ag_target->t_name); 545263724Strasz return (1); 546263724Strasz } 547263724Strasz 548275245Strasz if (ag->ag_type != AG_TYPE_UNKNOWN && ag->ag_type != type) { 549275245Strasz if (ag->ag_name != NULL) { 550263724Strasz log_warnx("cannot set auth-type to \"%s\" for " 551263724Strasz "auth-group \"%s\"; already has a different " 552263724Strasz "type", str, ag->ag_name); 553275245Strasz } else { 554263724Strasz log_warnx("cannot set auth-type to \"%s\" for target " 555263724Strasz "\"%s\"; already has a different type", 556263724Strasz str, ag->ag_target->t_name); 557275245Strasz } 558263724Strasz return (1); 559263724Strasz } 560263724Strasz 561275245Strasz ag->ag_type = type; 562275245Strasz 563275245Strasz return (0); 564263724Strasz} 565263724Strasz 566255570Straszstatic struct portal * 567255570Straszportal_new(struct portal_group *pg) 568255570Strasz{ 569255570Strasz struct portal *portal; 570255570Strasz 571255570Strasz portal = calloc(1, sizeof(*portal)); 572255570Strasz if (portal == NULL) 573255570Strasz log_err(1, "calloc"); 574255570Strasz TAILQ_INIT(&portal->p_targets); 575255570Strasz portal->p_portal_group = pg; 576255570Strasz TAILQ_INSERT_TAIL(&pg->pg_portals, portal, p_next); 577255570Strasz return (portal); 578255570Strasz} 579255570Strasz 580255570Straszstatic void 581255570Straszportal_delete(struct portal *portal) 582255570Strasz{ 583271632Strasz 584255570Strasz TAILQ_REMOVE(&portal->p_portal_group->pg_portals, portal, p_next); 585271632Strasz if (portal->p_ai != NULL) 586271632Strasz freeaddrinfo(portal->p_ai); 587255570Strasz free(portal->p_listen); 588255570Strasz free(portal); 589255570Strasz} 590255570Strasz 591255570Straszstruct portal_group * 592255570Straszportal_group_new(struct conf *conf, const char *name) 593255570Strasz{ 594255570Strasz struct portal_group *pg; 595255570Strasz 596255678Strasz pg = portal_group_find(conf, name); 597255678Strasz if (pg != NULL) { 598255678Strasz log_warnx("duplicated portal-group \"%s\"", name); 599255678Strasz return (NULL); 600255570Strasz } 601255570Strasz 602255570Strasz pg = calloc(1, sizeof(*pg)); 603255570Strasz if (pg == NULL) 604255570Strasz log_err(1, "calloc"); 605255570Strasz pg->pg_name = checked_strdup(name); 606255570Strasz TAILQ_INIT(&pg->pg_portals); 607255570Strasz pg->pg_conf = conf; 608255570Strasz conf->conf_last_portal_group_tag++; 609255570Strasz pg->pg_tag = conf->conf_last_portal_group_tag; 610255570Strasz TAILQ_INSERT_TAIL(&conf->conf_portal_groups, pg, pg_next); 611255570Strasz 612255570Strasz return (pg); 613255570Strasz} 614255570Strasz 615255570Straszvoid 616255570Straszportal_group_delete(struct portal_group *pg) 617255570Strasz{ 618255570Strasz struct portal *portal, *tmp; 619255570Strasz 620255570Strasz TAILQ_REMOVE(&pg->pg_conf->conf_portal_groups, pg, pg_next); 621255570Strasz 622255570Strasz TAILQ_FOREACH_SAFE(portal, &pg->pg_portals, p_next, tmp) 623255570Strasz portal_delete(portal); 624255570Strasz free(pg->pg_name); 625275642Strasz free(pg->pg_redirection); 626255570Strasz free(pg); 627255570Strasz} 628255570Strasz 629255570Straszstruct portal_group * 630265514Straszportal_group_find(const struct conf *conf, const char *name) 631255570Strasz{ 632255570Strasz struct portal_group *pg; 633255570Strasz 634255570Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 635255570Strasz if (strcmp(pg->pg_name, name) == 0) 636255570Strasz return (pg); 637255570Strasz } 638255570Strasz 639255570Strasz return (NULL); 640255570Strasz} 641255570Strasz 642274939Smavstatic int 643274939Smavparse_addr_port(char *arg, const char *def_port, struct addrinfo **ai) 644255570Strasz{ 645255570Strasz struct addrinfo hints; 646275674Smav char *str, *addr, *ch; 647255570Strasz const char *port; 648255570Strasz int error, colons = 0; 649255570Strasz 650275674Smav str = arg = strdup(arg); 651255570Strasz if (arg[0] == '[') { 652255570Strasz /* 653255570Strasz * IPv6 address in square brackets, perhaps with port. 654255570Strasz */ 655255570Strasz arg++; 656255570Strasz addr = strsep(&arg, "]"); 657274939Smav if (arg == NULL) 658255570Strasz return (1); 659255570Strasz if (arg[0] == '\0') { 660274939Smav port = def_port; 661255570Strasz } else if (arg[0] == ':') { 662255570Strasz port = arg + 1; 663275674Smav } else { 664275674Smav free(str); 665255570Strasz return (1); 666275674Smav } 667255570Strasz } else { 668255570Strasz /* 669255570Strasz * Either IPv6 address without brackets - and without 670255570Strasz * a port - or IPv4 address. Just count the colons. 671255570Strasz */ 672255570Strasz for (ch = arg; *ch != '\0'; ch++) { 673255570Strasz if (*ch == ':') 674255570Strasz colons++; 675255570Strasz } 676255570Strasz if (colons > 1) { 677255570Strasz addr = arg; 678274939Smav port = def_port; 679255570Strasz } else { 680255570Strasz addr = strsep(&arg, ":"); 681255570Strasz if (arg == NULL) 682274939Smav port = def_port; 683255570Strasz else 684255570Strasz port = arg; 685255570Strasz } 686255570Strasz } 687255570Strasz 688255570Strasz memset(&hints, 0, sizeof(hints)); 689255570Strasz hints.ai_family = PF_UNSPEC; 690255570Strasz hints.ai_socktype = SOCK_STREAM; 691255570Strasz hints.ai_flags = AI_PASSIVE; 692274939Smav error = getaddrinfo(addr, port, &hints, ai); 693275674Smav free(str); 694275674Smav return ((error != 0) ? 1 : 0); 695274939Smav} 696255570Strasz 697274939Smavint 698274939Smavportal_group_add_listen(struct portal_group *pg, const char *value, bool iser) 699274939Smav{ 700274939Smav struct portal *portal; 701274939Smav 702274939Smav portal = portal_new(pg); 703274939Smav portal->p_listen = checked_strdup(value); 704274939Smav portal->p_iser = iser; 705274939Smav 706274939Smav if (parse_addr_port(portal->p_listen, "3260", &portal->p_ai)) { 707274939Smav log_warnx("invalid listen address %s", portal->p_listen); 708271632Strasz portal_delete(portal); 709255570Strasz return (1); 710255570Strasz } 711255570Strasz 712255570Strasz /* 713255570Strasz * XXX: getaddrinfo(3) may return multiple addresses; we should turn 714255570Strasz * those into multiple portals. 715255570Strasz */ 716255570Strasz 717255570Strasz return (0); 718255570Strasz} 719255570Strasz 720274939Smavint 721274939Smavisns_new(struct conf *conf, const char *addr) 722274939Smav{ 723274939Smav struct isns *isns; 724274939Smav 725274939Smav isns = calloc(1, sizeof(*isns)); 726274939Smav if (isns == NULL) 727274939Smav log_err(1, "calloc"); 728274939Smav isns->i_conf = conf; 729274939Smav TAILQ_INSERT_TAIL(&conf->conf_isns, isns, i_next); 730274939Smav isns->i_addr = checked_strdup(addr); 731274939Smav 732274939Smav if (parse_addr_port(isns->i_addr, "3205", &isns->i_ai)) { 733274939Smav log_warnx("invalid iSNS address %s", isns->i_addr); 734274939Smav isns_delete(isns); 735274939Smav return (1); 736274939Smav } 737274939Smav 738274939Smav /* 739274939Smav * XXX: getaddrinfo(3) may return multiple addresses; we should turn 740274939Smav * those into multiple servers. 741274939Smav */ 742274939Smav 743274939Smav return (0); 744274939Smav} 745274939Smav 746274939Smavvoid 747274939Smavisns_delete(struct isns *isns) 748274939Smav{ 749274939Smav 750274939Smav TAILQ_REMOVE(&isns->i_conf->conf_isns, isns, i_next); 751274939Smav free(isns->i_addr); 752274939Smav if (isns->i_ai != NULL) 753274939Smav freeaddrinfo(isns->i_ai); 754274939Smav free(isns); 755274939Smav} 756274939Smav 757274939Smavstatic int 758274939Smavisns_do_connect(struct isns *isns) 759274939Smav{ 760274939Smav int s; 761274939Smav 762274939Smav s = socket(isns->i_ai->ai_family, isns->i_ai->ai_socktype, 763274939Smav isns->i_ai->ai_protocol); 764274939Smav if (s < 0) { 765274939Smav log_warn("socket(2) failed for %s", isns->i_addr); 766274939Smav return (-1); 767274939Smav } 768274939Smav if (connect(s, isns->i_ai->ai_addr, isns->i_ai->ai_addrlen)) { 769274939Smav log_warn("connect(2) failed for %s", isns->i_addr); 770274939Smav close(s); 771274939Smav return (-1); 772274939Smav } 773274939Smav return(s); 774274939Smav} 775274939Smav 776274939Smavstatic int 777274939Smavisns_do_register(struct isns *isns, int s, const char *hostname) 778274939Smav{ 779274939Smav struct conf *conf = isns->i_conf; 780274939Smav struct target *target; 781274939Smav struct portal *portal; 782274939Smav struct portal_group *pg; 783274939Smav struct isns_req *req; 784274939Smav int res = 0; 785274939Smav uint32_t error; 786274939Smav 787274939Smav req = isns_req_create(ISNS_FUNC_DEVATTRREG, ISNS_FLAG_CLIENT); 788274939Smav isns_req_add_str(req, 32, TAILQ_FIRST(&conf->conf_targets)->t_name); 789274939Smav isns_req_add_delim(req); 790274939Smav isns_req_add_str(req, 1, hostname); 791274939Smav isns_req_add_32(req, 2, 2); /* 2 -- iSCSI */ 792274939Smav isns_req_add_32(req, 6, conf->conf_isns_period); 793274939Smav TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 794274939Smav if (pg->pg_unassigned) 795274939Smav continue; 796274939Smav TAILQ_FOREACH(portal, &pg->pg_portals, p_next) { 797274939Smav isns_req_add_addr(req, 16, portal->p_ai); 798274939Smav isns_req_add_port(req, 17, portal->p_ai); 799274939Smav } 800274939Smav } 801274939Smav TAILQ_FOREACH(target, &conf->conf_targets, t_next) { 802274939Smav isns_req_add_str(req, 32, target->t_name); 803274939Smav isns_req_add_32(req, 33, 1); /* 1 -- Target*/ 804274939Smav if (target->t_alias != NULL) 805274939Smav isns_req_add_str(req, 34, target->t_alias); 806274939Smav pg = target->t_portal_group; 807274939Smav isns_req_add_32(req, 51, pg->pg_tag); 808274939Smav TAILQ_FOREACH(portal, &pg->pg_portals, p_next) { 809274939Smav isns_req_add_addr(req, 49, portal->p_ai); 810274939Smav isns_req_add_port(req, 50, portal->p_ai); 811274939Smav } 812274939Smav } 813274939Smav res = isns_req_send(s, req); 814274939Smav if (res < 0) { 815274939Smav log_warn("send(2) failed for %s", isns->i_addr); 816274939Smav goto quit; 817274939Smav } 818274939Smav res = isns_req_receive(s, req); 819274939Smav if (res < 0) { 820274939Smav log_warn("receive(2) failed for %s", isns->i_addr); 821274939Smav goto quit; 822274939Smav } 823274939Smav error = isns_req_get_status(req); 824274939Smav if (error != 0) { 825274939Smav log_warnx("iSNS register error %d for %s", error, isns->i_addr); 826274939Smav res = -1; 827274939Smav } 828274939Smavquit: 829274939Smav isns_req_free(req); 830274939Smav return (res); 831274939Smav} 832274939Smav 833274939Smavstatic int 834274939Smavisns_do_check(struct isns *isns, int s, const char *hostname) 835274939Smav{ 836274939Smav struct conf *conf = isns->i_conf; 837274939Smav struct isns_req *req; 838274939Smav int res = 0; 839274939Smav uint32_t error; 840274939Smav 841274939Smav req = isns_req_create(ISNS_FUNC_DEVATTRQRY, ISNS_FLAG_CLIENT); 842274939Smav isns_req_add_str(req, 32, TAILQ_FIRST(&conf->conf_targets)->t_name); 843274939Smav isns_req_add_str(req, 1, hostname); 844274939Smav isns_req_add_delim(req); 845274939Smav isns_req_add(req, 2, 0, NULL); 846274939Smav res = isns_req_send(s, req); 847274939Smav if (res < 0) { 848274939Smav log_warn("send(2) failed for %s", isns->i_addr); 849274939Smav goto quit; 850274939Smav } 851274939Smav res = isns_req_receive(s, req); 852274939Smav if (res < 0) { 853274939Smav log_warn("receive(2) failed for %s", isns->i_addr); 854274939Smav goto quit; 855274939Smav } 856274939Smav error = isns_req_get_status(req); 857274939Smav if (error != 0) { 858274939Smav log_warnx("iSNS check error %d for %s", error, isns->i_addr); 859274939Smav res = -1; 860274939Smav } 861274939Smavquit: 862274939Smav isns_req_free(req); 863274939Smav return (res); 864274939Smav} 865274939Smav 866274939Smavstatic int 867274939Smavisns_do_deregister(struct isns *isns, int s, const char *hostname) 868274939Smav{ 869274939Smav struct conf *conf = isns->i_conf; 870274939Smav struct isns_req *req; 871274939Smav int res = 0; 872274939Smav uint32_t error; 873274939Smav 874274939Smav req = isns_req_create(ISNS_FUNC_DEVDEREG, ISNS_FLAG_CLIENT); 875274939Smav isns_req_add_str(req, 32, TAILQ_FIRST(&conf->conf_targets)->t_name); 876274939Smav isns_req_add_delim(req); 877274939Smav isns_req_add_str(req, 1, hostname); 878274939Smav res = isns_req_send(s, req); 879274939Smav if (res < 0) { 880274939Smav log_warn("send(2) failed for %s", isns->i_addr); 881274939Smav goto quit; 882274939Smav } 883274939Smav res = isns_req_receive(s, req); 884274939Smav if (res < 0) { 885274939Smav log_warn("receive(2) failed for %s", isns->i_addr); 886274939Smav goto quit; 887274939Smav } 888274939Smav error = isns_req_get_status(req); 889274939Smav if (error != 0) { 890274939Smav log_warnx("iSNS deregister error %d for %s", error, isns->i_addr); 891274939Smav res = -1; 892274939Smav } 893274939Smavquit: 894274939Smav isns_req_free(req); 895274939Smav return (res); 896274939Smav} 897274939Smav 898274939Smavvoid 899274939Smavisns_register(struct isns *isns, struct isns *oldisns) 900274939Smav{ 901274939Smav struct conf *conf = isns->i_conf; 902275496Smav int s; 903274939Smav char hostname[256]; 904274939Smav 905274939Smav if (TAILQ_EMPTY(&conf->conf_targets) || 906274939Smav TAILQ_EMPTY(&conf->conf_portal_groups)) 907274939Smav return; 908274939Smav set_timeout(conf->conf_isns_timeout, false); 909274939Smav s = isns_do_connect(isns); 910274939Smav if (s < 0) { 911274939Smav set_timeout(0, false); 912274939Smav return; 913274939Smav } 914274939Smav gethostname(hostname, sizeof(hostname)); 915274939Smav 916274939Smav if (oldisns == NULL || TAILQ_EMPTY(&oldisns->i_conf->conf_targets)) 917274939Smav oldisns = isns; 918275496Smav isns_do_deregister(oldisns, s, hostname); 919275496Smav isns_do_register(isns, s, hostname); 920274939Smav close(s); 921274939Smav set_timeout(0, false); 922274939Smav} 923274939Smav 924274939Smavvoid 925274939Smavisns_check(struct isns *isns) 926274939Smav{ 927274939Smav struct conf *conf = isns->i_conf; 928274939Smav int s, res; 929274939Smav char hostname[256]; 930274939Smav 931274939Smav if (TAILQ_EMPTY(&conf->conf_targets) || 932274939Smav TAILQ_EMPTY(&conf->conf_portal_groups)) 933274939Smav return; 934274939Smav set_timeout(conf->conf_isns_timeout, false); 935274939Smav s = isns_do_connect(isns); 936274939Smav if (s < 0) { 937274939Smav set_timeout(0, false); 938274939Smav return; 939274939Smav } 940274939Smav gethostname(hostname, sizeof(hostname)); 941274939Smav 942274939Smav res = isns_do_check(isns, s, hostname); 943274939Smav if (res < 0) { 944275496Smav isns_do_deregister(isns, s, hostname); 945275496Smav isns_do_register(isns, s, hostname); 946274939Smav } 947274939Smav close(s); 948274939Smav set_timeout(0, false); 949274939Smav} 950274939Smav 951274939Smavvoid 952274939Smavisns_deregister(struct isns *isns) 953274939Smav{ 954274939Smav struct conf *conf = isns->i_conf; 955275496Smav int s; 956274939Smav char hostname[256]; 957274939Smav 958274939Smav if (TAILQ_EMPTY(&conf->conf_targets) || 959274939Smav TAILQ_EMPTY(&conf->conf_portal_groups)) 960274939Smav return; 961274939Smav set_timeout(conf->conf_isns_timeout, false); 962274939Smav s = isns_do_connect(isns); 963274939Smav if (s < 0) 964274939Smav return; 965274939Smav gethostname(hostname, sizeof(hostname)); 966274939Smav 967275496Smav isns_do_deregister(isns, s, hostname); 968274939Smav close(s); 969274939Smav set_timeout(0, false); 970274939Smav} 971274939Smav 972275244Straszint 973275245Straszportal_group_set_filter(struct portal_group *pg, const char *str) 974275244Strasz{ 975275245Strasz int filter; 976275244Strasz 977275244Strasz if (strcmp(str, "none") == 0) { 978275244Strasz filter = PG_FILTER_NONE; 979275244Strasz } else if (strcmp(str, "portal") == 0) { 980275244Strasz filter = PG_FILTER_PORTAL; 981275244Strasz } else if (strcmp(str, "portal-name") == 0) { 982275244Strasz filter = PG_FILTER_PORTAL_NAME; 983275244Strasz } else if (strcmp(str, "portal-name-auth") == 0) { 984275244Strasz filter = PG_FILTER_PORTAL_NAME_AUTH; 985275244Strasz } else { 986275244Strasz log_warnx("invalid discovery-filter \"%s\" for portal-group " 987275244Strasz "\"%s\"; valid values are \"none\", \"portal\", " 988275244Strasz "\"portal-name\", and \"portal-name-auth\"", 989275244Strasz str, pg->pg_name); 990275244Strasz return (1); 991275244Strasz } 992275244Strasz 993275245Strasz if (pg->pg_discovery_filter != PG_FILTER_UNKNOWN && 994275245Strasz pg->pg_discovery_filter != filter) { 995275244Strasz log_warnx("cannot set discovery-filter to \"%s\" for " 996275244Strasz "portal-group \"%s\"; already has a different " 997275244Strasz "value", str, pg->pg_name); 998275244Strasz return (1); 999275244Strasz } 1000275244Strasz 1001275245Strasz pg->pg_discovery_filter = filter; 1002275245Strasz 1003275245Strasz return (0); 1004275244Strasz} 1005275244Strasz 1006275642Straszint 1007275642Straszportal_group_set_redirection(struct portal_group *pg, const char *addr) 1008275642Strasz{ 1009275642Strasz 1010275642Strasz if (pg->pg_redirection != NULL) { 1011275642Strasz log_warnx("cannot set redirection to \"%s\" for " 1012275642Strasz "portal-group \"%s\"; already defined", 1013275642Strasz addr, pg->pg_name); 1014275642Strasz return (1); 1015275642Strasz } 1016275642Strasz 1017275642Strasz pg->pg_redirection = checked_strdup(addr); 1018275642Strasz 1019275642Strasz return (0); 1020275642Strasz} 1021275642Strasz 1022255570Straszstatic bool 1023255570Straszvalid_hex(const char ch) 1024255570Strasz{ 1025255570Strasz switch (ch) { 1026255570Strasz case '0': 1027255570Strasz case '1': 1028255570Strasz case '2': 1029255570Strasz case '3': 1030255570Strasz case '4': 1031255570Strasz case '5': 1032255570Strasz case '6': 1033255570Strasz case '7': 1034255570Strasz case '8': 1035255570Strasz case '9': 1036255570Strasz case 'a': 1037255570Strasz case 'A': 1038255570Strasz case 'b': 1039255570Strasz case 'B': 1040255570Strasz case 'c': 1041255570Strasz case 'C': 1042255570Strasz case 'd': 1043255570Strasz case 'D': 1044255570Strasz case 'e': 1045255570Strasz case 'E': 1046255570Strasz case 'f': 1047255570Strasz case 'F': 1048255570Strasz return (true); 1049255570Strasz default: 1050255570Strasz return (false); 1051255570Strasz } 1052255570Strasz} 1053255570Strasz 1054255570Straszbool 1055255570Straszvalid_iscsi_name(const char *name) 1056255570Strasz{ 1057255570Strasz int i; 1058255570Strasz 1059255570Strasz if (strlen(name) >= MAX_NAME_LEN) { 1060255570Strasz log_warnx("overlong name for target \"%s\"; max length allowed " 1061255570Strasz "by iSCSI specification is %d characters", 1062255570Strasz name, MAX_NAME_LEN); 1063255570Strasz return (false); 1064255570Strasz } 1065255570Strasz 1066255570Strasz /* 1067255570Strasz * In the cases below, we don't return an error, just in case the admin 1068255570Strasz * was right, and we're wrong. 1069255570Strasz */ 1070255570Strasz if (strncasecmp(name, "iqn.", strlen("iqn.")) == 0) { 1071255570Strasz for (i = strlen("iqn."); name[i] != '\0'; i++) { 1072255570Strasz /* 1073255570Strasz * XXX: We should verify UTF-8 normalisation, as defined 1074274870Strasz * by 3.2.6.2: iSCSI Name Encoding. 1075255570Strasz */ 1076255570Strasz if (isalnum(name[i])) 1077255570Strasz continue; 1078255570Strasz if (name[i] == '-' || name[i] == '.' || name[i] == ':') 1079255570Strasz continue; 1080255570Strasz log_warnx("invalid character \"%c\" in target name " 1081255570Strasz "\"%s\"; allowed characters are letters, digits, " 1082255570Strasz "'-', '.', and ':'", name[i], name); 1083255570Strasz break; 1084255570Strasz } 1085255570Strasz /* 1086255570Strasz * XXX: Check more stuff: valid date and a valid reversed domain. 1087255570Strasz */ 1088255570Strasz } else if (strncasecmp(name, "eui.", strlen("eui.")) == 0) { 1089255570Strasz if (strlen(name) != strlen("eui.") + 16) 1090255570Strasz log_warnx("invalid target name \"%s\"; the \"eui.\" " 1091255570Strasz "should be followed by exactly 16 hexadecimal " 1092255570Strasz "digits", name); 1093255570Strasz for (i = strlen("eui."); name[i] != '\0'; i++) { 1094255570Strasz if (!valid_hex(name[i])) { 1095255570Strasz log_warnx("invalid character \"%c\" in target " 1096255570Strasz "name \"%s\"; allowed characters are 1-9 " 1097255570Strasz "and A-F", name[i], name); 1098255570Strasz break; 1099255570Strasz } 1100255570Strasz } 1101255570Strasz } else if (strncasecmp(name, "naa.", strlen("naa.")) == 0) { 1102255570Strasz if (strlen(name) > strlen("naa.") + 32) 1103255570Strasz log_warnx("invalid target name \"%s\"; the \"naa.\" " 1104255570Strasz "should be followed by at most 32 hexadecimal " 1105255570Strasz "digits", name); 1106255570Strasz for (i = strlen("naa."); name[i] != '\0'; i++) { 1107255570Strasz if (!valid_hex(name[i])) { 1108255570Strasz log_warnx("invalid character \"%c\" in target " 1109255570Strasz "name \"%s\"; allowed characters are 1-9 " 1110255570Strasz "and A-F", name[i], name); 1111255570Strasz break; 1112255570Strasz } 1113255570Strasz } 1114255570Strasz } else { 1115255570Strasz log_warnx("invalid target name \"%s\"; should start with " 1116255570Strasz "either \".iqn\", \"eui.\", or \"naa.\"", 1117255570Strasz name); 1118255570Strasz } 1119255570Strasz return (true); 1120255570Strasz} 1121255570Strasz 1122255570Straszstruct target * 1123263723Strasztarget_new(struct conf *conf, const char *name) 1124255570Strasz{ 1125255570Strasz struct target *targ; 1126255570Strasz int i, len; 1127255570Strasz 1128263723Strasz targ = target_find(conf, name); 1129255570Strasz if (targ != NULL) { 1130263723Strasz log_warnx("duplicated target \"%s\"", name); 1131255570Strasz return (NULL); 1132255570Strasz } 1133263723Strasz if (valid_iscsi_name(name) == false) { 1134263723Strasz log_warnx("target name \"%s\" is invalid", name); 1135255570Strasz return (NULL); 1136255570Strasz } 1137255570Strasz targ = calloc(1, sizeof(*targ)); 1138255570Strasz if (targ == NULL) 1139255570Strasz log_err(1, "calloc"); 1140263723Strasz targ->t_name = checked_strdup(name); 1141255570Strasz 1142255570Strasz /* 1143255570Strasz * RFC 3722 requires us to normalize the name to lowercase. 1144255570Strasz */ 1145263723Strasz len = strlen(name); 1146255570Strasz for (i = 0; i < len; i++) 1147263723Strasz targ->t_name[i] = tolower(targ->t_name[i]); 1148255570Strasz 1149255570Strasz TAILQ_INIT(&targ->t_luns); 1150255570Strasz targ->t_conf = conf; 1151255570Strasz TAILQ_INSERT_TAIL(&conf->conf_targets, targ, t_next); 1152255570Strasz 1153255570Strasz return (targ); 1154255570Strasz} 1155255570Strasz 1156255570Straszvoid 1157255570Strasztarget_delete(struct target *targ) 1158255570Strasz{ 1159255570Strasz struct lun *lun, *tmp; 1160255570Strasz 1161255570Strasz TAILQ_REMOVE(&targ->t_conf->conf_targets, targ, t_next); 1162255570Strasz 1163255570Strasz TAILQ_FOREACH_SAFE(lun, &targ->t_luns, l_next, tmp) 1164255570Strasz lun_delete(lun); 1165263723Strasz free(targ->t_name); 1166275642Strasz free(targ->t_redirection); 1167255570Strasz free(targ); 1168255570Strasz} 1169255570Strasz 1170255570Straszstruct target * 1171263723Strasztarget_find(struct conf *conf, const char *name) 1172255570Strasz{ 1173255570Strasz struct target *targ; 1174255570Strasz 1175255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 1176263723Strasz if (strcasecmp(targ->t_name, name) == 0) 1177255570Strasz return (targ); 1178255570Strasz } 1179255570Strasz 1180255570Strasz return (NULL); 1181255570Strasz} 1182255570Strasz 1183275642Straszint 1184275642Strasztarget_set_redirection(struct target *target, const char *addr) 1185275642Strasz{ 1186275642Strasz 1187275642Strasz if (target->t_redirection != NULL) { 1188275642Strasz log_warnx("cannot set redirection to \"%s\" for " 1189275642Strasz "target \"%s\"; already defined", 1190275642Strasz addr, target->t_name); 1191275642Strasz return (1); 1192275642Strasz } 1193275642Strasz 1194275642Strasz target->t_redirection = checked_strdup(addr); 1195275642Strasz 1196275642Strasz return (0); 1197275642Strasz} 1198275642Strasz 1199255570Straszstruct lun * 1200255570Straszlun_new(struct target *targ, int lun_id) 1201255570Strasz{ 1202255570Strasz struct lun *lun; 1203255570Strasz 1204255570Strasz lun = lun_find(targ, lun_id); 1205255570Strasz if (lun != NULL) { 1206255570Strasz log_warnx("duplicated lun %d for target \"%s\"", 1207263723Strasz lun_id, targ->t_name); 1208255570Strasz return (NULL); 1209255570Strasz } 1210255570Strasz 1211255570Strasz lun = calloc(1, sizeof(*lun)); 1212255570Strasz if (lun == NULL) 1213255570Strasz log_err(1, "calloc"); 1214255570Strasz lun->l_lun = lun_id; 1215255570Strasz TAILQ_INIT(&lun->l_options); 1216255570Strasz lun->l_target = targ; 1217255570Strasz TAILQ_INSERT_TAIL(&targ->t_luns, lun, l_next); 1218255570Strasz 1219255570Strasz return (lun); 1220255570Strasz} 1221255570Strasz 1222255570Straszvoid 1223255570Straszlun_delete(struct lun *lun) 1224255570Strasz{ 1225255570Strasz struct lun_option *lo, *tmp; 1226255570Strasz 1227255570Strasz TAILQ_REMOVE(&lun->l_target->t_luns, lun, l_next); 1228255570Strasz 1229255570Strasz TAILQ_FOREACH_SAFE(lo, &lun->l_options, lo_next, tmp) 1230255570Strasz lun_option_delete(lo); 1231255570Strasz free(lun->l_backend); 1232255570Strasz free(lun->l_device_id); 1233255570Strasz free(lun->l_path); 1234255570Strasz free(lun->l_serial); 1235255570Strasz free(lun); 1236255570Strasz} 1237255570Strasz 1238255570Straszstruct lun * 1239265514Straszlun_find(const struct target *targ, int lun_id) 1240255570Strasz{ 1241255570Strasz struct lun *lun; 1242255570Strasz 1243255570Strasz TAILQ_FOREACH(lun, &targ->t_luns, l_next) { 1244255570Strasz if (lun->l_lun == lun_id) 1245255570Strasz return (lun); 1246255570Strasz } 1247255570Strasz 1248255570Strasz return (NULL); 1249255570Strasz} 1250255570Strasz 1251255570Straszvoid 1252255570Straszlun_set_backend(struct lun *lun, const char *value) 1253255570Strasz{ 1254255570Strasz free(lun->l_backend); 1255255570Strasz lun->l_backend = checked_strdup(value); 1256255570Strasz} 1257255570Strasz 1258255570Straszvoid 1259255570Straszlun_set_blocksize(struct lun *lun, size_t value) 1260255570Strasz{ 1261255570Strasz 1262255570Strasz lun->l_blocksize = value; 1263255570Strasz} 1264255570Strasz 1265255570Straszvoid 1266255570Straszlun_set_device_id(struct lun *lun, const char *value) 1267255570Strasz{ 1268255570Strasz free(lun->l_device_id); 1269255570Strasz lun->l_device_id = checked_strdup(value); 1270255570Strasz} 1271255570Strasz 1272255570Straszvoid 1273255570Straszlun_set_path(struct lun *lun, const char *value) 1274255570Strasz{ 1275255570Strasz free(lun->l_path); 1276255570Strasz lun->l_path = checked_strdup(value); 1277255570Strasz} 1278255570Strasz 1279255570Straszvoid 1280255570Straszlun_set_serial(struct lun *lun, const char *value) 1281255570Strasz{ 1282255570Strasz free(lun->l_serial); 1283255570Strasz lun->l_serial = checked_strdup(value); 1284255570Strasz} 1285255570Strasz 1286255570Straszvoid 1287255570Straszlun_set_size(struct lun *lun, size_t value) 1288255570Strasz{ 1289255570Strasz 1290255570Strasz lun->l_size = value; 1291255570Strasz} 1292255570Strasz 1293255570Straszvoid 1294255570Straszlun_set_ctl_lun(struct lun *lun, uint32_t value) 1295255570Strasz{ 1296255570Strasz 1297255570Strasz lun->l_ctl_lun = value; 1298255570Strasz} 1299255570Strasz 1300255570Straszstruct lun_option * 1301255570Straszlun_option_new(struct lun *lun, const char *name, const char *value) 1302255570Strasz{ 1303255570Strasz struct lun_option *lo; 1304255570Strasz 1305255570Strasz lo = lun_option_find(lun, name); 1306255570Strasz if (lo != NULL) { 1307255570Strasz log_warnx("duplicated lun option %s for lun %d, target \"%s\"", 1308263723Strasz name, lun->l_lun, lun->l_target->t_name); 1309255570Strasz return (NULL); 1310255570Strasz } 1311255570Strasz 1312255570Strasz lo = calloc(1, sizeof(*lo)); 1313255570Strasz if (lo == NULL) 1314255570Strasz log_err(1, "calloc"); 1315255570Strasz lo->lo_name = checked_strdup(name); 1316255570Strasz lo->lo_value = checked_strdup(value); 1317255570Strasz lo->lo_lun = lun; 1318255570Strasz TAILQ_INSERT_TAIL(&lun->l_options, lo, lo_next); 1319255570Strasz 1320255570Strasz return (lo); 1321255570Strasz} 1322255570Strasz 1323255570Straszvoid 1324255570Straszlun_option_delete(struct lun_option *lo) 1325255570Strasz{ 1326255570Strasz 1327255570Strasz TAILQ_REMOVE(&lo->lo_lun->l_options, lo, lo_next); 1328255570Strasz 1329255570Strasz free(lo->lo_name); 1330255570Strasz free(lo->lo_value); 1331255570Strasz free(lo); 1332255570Strasz} 1333255570Strasz 1334255570Straszstruct lun_option * 1335265514Straszlun_option_find(const struct lun *lun, const char *name) 1336255570Strasz{ 1337255570Strasz struct lun_option *lo; 1338255570Strasz 1339255570Strasz TAILQ_FOREACH(lo, &lun->l_options, lo_next) { 1340255570Strasz if (strcmp(lo->lo_name, name) == 0) 1341255570Strasz return (lo); 1342255570Strasz } 1343255570Strasz 1344255570Strasz return (NULL); 1345255570Strasz} 1346255570Strasz 1347255570Straszvoid 1348255570Straszlun_option_set(struct lun_option *lo, const char *value) 1349255570Strasz{ 1350255570Strasz 1351255570Strasz free(lo->lo_value); 1352255570Strasz lo->lo_value = checked_strdup(value); 1353255570Strasz} 1354255570Strasz 1355255570Straszstatic struct connection * 1356270137Smavconnection_new(struct portal *portal, int fd, const char *host, 1357270137Smav const struct sockaddr *client_sa) 1358255570Strasz{ 1359255570Strasz struct connection *conn; 1360255570Strasz 1361255570Strasz conn = calloc(1, sizeof(*conn)); 1362255570Strasz if (conn == NULL) 1363255570Strasz log_err(1, "calloc"); 1364255570Strasz conn->conn_portal = portal; 1365255570Strasz conn->conn_socket = fd; 1366255570Strasz conn->conn_initiator_addr = checked_strdup(host); 1367270137Smav memcpy(&conn->conn_initiator_sa, client_sa, client_sa->sa_len); 1368255570Strasz 1369255570Strasz /* 1370255570Strasz * Default values, from RFC 3720, section 12. 1371255570Strasz */ 1372255570Strasz conn->conn_max_data_segment_length = 8192; 1373255570Strasz conn->conn_max_burst_length = 262144; 1374255570Strasz conn->conn_immediate_data = true; 1375255570Strasz 1376255570Strasz return (conn); 1377255570Strasz} 1378255570Strasz 1379255570Strasz#if 0 1380255570Straszstatic void 1381255570Straszconf_print(struct conf *conf) 1382255570Strasz{ 1383255570Strasz struct auth_group *ag; 1384255570Strasz struct auth *auth; 1385263720Strasz struct auth_name *auth_name; 1386263720Strasz struct auth_portal *auth_portal; 1387255570Strasz struct portal_group *pg; 1388255570Strasz struct portal *portal; 1389255570Strasz struct target *targ; 1390255570Strasz struct lun *lun; 1391255570Strasz struct lun_option *lo; 1392255570Strasz 1393255570Strasz TAILQ_FOREACH(ag, &conf->conf_auth_groups, ag_next) { 1394255570Strasz fprintf(stderr, "auth-group %s {\n", ag->ag_name); 1395255570Strasz TAILQ_FOREACH(auth, &ag->ag_auths, a_next) 1396255570Strasz fprintf(stderr, "\t chap-mutual %s %s %s %s\n", 1397255570Strasz auth->a_user, auth->a_secret, 1398255570Strasz auth->a_mutual_user, auth->a_mutual_secret); 1399263720Strasz TAILQ_FOREACH(auth_name, &ag->ag_names, an_next) 1400263720Strasz fprintf(stderr, "\t initiator-name %s\n", 1401263720Strasz auth_name->an_initator_name); 1402263720Strasz TAILQ_FOREACH(auth_portal, &ag->ag_portals, an_next) 1403263720Strasz fprintf(stderr, "\t initiator-portal %s\n", 1404263720Strasz auth_portal->an_initator_portal); 1405255570Strasz fprintf(stderr, "}\n"); 1406255570Strasz } 1407255570Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 1408255570Strasz fprintf(stderr, "portal-group %s {\n", pg->pg_name); 1409255570Strasz TAILQ_FOREACH(portal, &pg->pg_portals, p_next) 1410255570Strasz fprintf(stderr, "\t listen %s\n", portal->p_listen); 1411255570Strasz fprintf(stderr, "}\n"); 1412255570Strasz } 1413255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 1414263723Strasz fprintf(stderr, "target %s {\n", targ->t_name); 1415255570Strasz if (targ->t_alias != NULL) 1416255570Strasz fprintf(stderr, "\t alias %s\n", targ->t_alias); 1417255570Strasz TAILQ_FOREACH(lun, &targ->t_luns, l_next) { 1418255570Strasz fprintf(stderr, "\tlun %d {\n", lun->l_lun); 1419255570Strasz fprintf(stderr, "\t\tpath %s\n", lun->l_path); 1420255570Strasz TAILQ_FOREACH(lo, &lun->l_options, lo_next) 1421255570Strasz fprintf(stderr, "\t\toption %s %s\n", 1422255570Strasz lo->lo_name, lo->lo_value); 1423255570Strasz fprintf(stderr, "\t}\n"); 1424255570Strasz } 1425255570Strasz fprintf(stderr, "}\n"); 1426255570Strasz } 1427255570Strasz} 1428255570Strasz#endif 1429255570Strasz 1430263717Straszstatic int 1431263717Straszconf_verify_lun(struct lun *lun) 1432263717Strasz{ 1433263717Strasz const struct lun *lun2; 1434263718Strasz const struct target *targ2; 1435263717Strasz 1436263717Strasz if (lun->l_backend == NULL) 1437263717Strasz lun_set_backend(lun, "block"); 1438263717Strasz if (strcmp(lun->l_backend, "block") == 0) { 1439263717Strasz if (lun->l_path == NULL) { 1440263717Strasz log_warnx("missing path for lun %d, target \"%s\"", 1441263723Strasz lun->l_lun, lun->l_target->t_name); 1442263717Strasz return (1); 1443263717Strasz } 1444263717Strasz } else if (strcmp(lun->l_backend, "ramdisk") == 0) { 1445263717Strasz if (lun->l_size == 0) { 1446263717Strasz log_warnx("missing size for ramdisk-backed lun %d, " 1447263723Strasz "target \"%s\"", lun->l_lun, lun->l_target->t_name); 1448263717Strasz return (1); 1449263717Strasz } 1450263717Strasz if (lun->l_path != NULL) { 1451263717Strasz log_warnx("path must not be specified " 1452263717Strasz "for ramdisk-backed lun %d, target \"%s\"", 1453263723Strasz lun->l_lun, lun->l_target->t_name); 1454263717Strasz return (1); 1455263717Strasz } 1456263717Strasz } 1457263717Strasz if (lun->l_lun < 0 || lun->l_lun > 255) { 1458263717Strasz log_warnx("invalid lun number for lun %d, target \"%s\"; " 1459263717Strasz "must be between 0 and 255", lun->l_lun, 1460263723Strasz lun->l_target->t_name); 1461263717Strasz return (1); 1462263717Strasz } 1463263717Strasz if (lun->l_blocksize == 0) { 1464263717Strasz lun_set_blocksize(lun, DEFAULT_BLOCKSIZE); 1465263717Strasz } else if (lun->l_blocksize < 0) { 1466263717Strasz log_warnx("invalid blocksize for lun %d, target \"%s\"; " 1467263723Strasz "must be larger than 0", lun->l_lun, lun->l_target->t_name); 1468263717Strasz return (1); 1469263717Strasz } 1470263717Strasz if (lun->l_size != 0 && lun->l_size % lun->l_blocksize != 0) { 1471263717Strasz log_warnx("invalid size for lun %d, target \"%s\"; " 1472263717Strasz "must be multiple of blocksize", lun->l_lun, 1473263723Strasz lun->l_target->t_name); 1474263717Strasz return (1); 1475263717Strasz } 1476263718Strasz TAILQ_FOREACH(targ2, &lun->l_target->t_conf->conf_targets, t_next) { 1477263718Strasz TAILQ_FOREACH(lun2, &targ2->t_luns, l_next) { 1478263718Strasz if (lun == lun2) 1479263718Strasz continue; 1480263718Strasz if (lun->l_path != NULL && lun2->l_path != NULL && 1481263718Strasz strcmp(lun->l_path, lun2->l_path) == 0) { 1482263718Strasz log_debugx("WARNING: path \"%s\" duplicated " 1483263718Strasz "between lun %d, target \"%s\", and " 1484263718Strasz "lun %d, target \"%s\"", lun->l_path, 1485263723Strasz lun->l_lun, lun->l_target->t_name, 1486263723Strasz lun2->l_lun, lun2->l_target->t_name); 1487263718Strasz } 1488263718Strasz } 1489263718Strasz } 1490263717Strasz 1491263717Strasz return (0); 1492263717Strasz} 1493263717Strasz 1494255570Straszint 1495255570Straszconf_verify(struct conf *conf) 1496255570Strasz{ 1497255570Strasz struct auth_group *ag; 1498255570Strasz struct portal_group *pg; 1499255570Strasz struct target *targ; 1500263717Strasz struct lun *lun; 1501274871Strasz bool found; 1502263717Strasz int error; 1503255570Strasz 1504255570Strasz if (conf->conf_pidfile_path == NULL) 1505255570Strasz conf->conf_pidfile_path = checked_strdup(DEFAULT_PIDFILE); 1506255570Strasz 1507255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 1508255570Strasz if (targ->t_auth_group == NULL) { 1509263726Strasz targ->t_auth_group = auth_group_find(conf, 1510263726Strasz "default"); 1511263726Strasz assert(targ->t_auth_group != NULL); 1512255570Strasz } 1513255570Strasz if (targ->t_portal_group == NULL) { 1514255570Strasz targ->t_portal_group = portal_group_find(conf, 1515255570Strasz "default"); 1516255570Strasz assert(targ->t_portal_group != NULL); 1517255570Strasz } 1518274871Strasz found = false; 1519255570Strasz TAILQ_FOREACH(lun, &targ->t_luns, l_next) { 1520263717Strasz error = conf_verify_lun(lun); 1521263717Strasz if (error != 0) 1522263717Strasz return (error); 1523274871Strasz found = true; 1524255570Strasz } 1525275642Strasz if (!found && targ->t_redirection == NULL) { 1526265506Strasz log_warnx("no LUNs defined for target \"%s\"", 1527265506Strasz targ->t_name); 1528255570Strasz } 1529275642Strasz if (found && targ->t_redirection != NULL) { 1530275642Strasz log_debugx("target \"%s\" contains luns, " 1531275642Strasz " but configured for redirection", 1532275642Strasz targ->t_name); 1533275642Strasz } 1534255570Strasz } 1535255570Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 1536255570Strasz assert(pg->pg_name != NULL); 1537255570Strasz if (pg->pg_discovery_auth_group == NULL) { 1538255570Strasz pg->pg_discovery_auth_group = 1539263728Strasz auth_group_find(conf, "default"); 1540255570Strasz assert(pg->pg_discovery_auth_group != NULL); 1541255570Strasz } 1542255570Strasz 1543275244Strasz if (pg->pg_discovery_filter == PG_FILTER_UNKNOWN) 1544275244Strasz pg->pg_discovery_filter = PG_FILTER_NONE; 1545275244Strasz 1546255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 1547255570Strasz if (targ->t_portal_group == pg) 1548255570Strasz break; 1549255570Strasz } 1550275642Strasz if (pg->pg_redirection != NULL) { 1551275642Strasz if (targ != NULL) { 1552275642Strasz log_debugx("portal-group \"%s\" assigned " 1553275642Strasz "to target \"%s\", but configured " 1554275642Strasz "for redirection", 1555275642Strasz pg->pg_name, targ->t_name); 1556275642Strasz } 1557275642Strasz pg->pg_unassigned = false; 1558275642Strasz } else if (targ != NULL) { 1559275642Strasz pg->pg_unassigned = false; 1560275642Strasz } else { 1561255570Strasz if (strcmp(pg->pg_name, "default") != 0) 1562255570Strasz log_warnx("portal-group \"%s\" not assigned " 1563255570Strasz "to any target", pg->pg_name); 1564255570Strasz pg->pg_unassigned = true; 1565275642Strasz } 1566255570Strasz } 1567255570Strasz TAILQ_FOREACH(ag, &conf->conf_auth_groups, ag_next) { 1568255570Strasz if (ag->ag_name == NULL) 1569255570Strasz assert(ag->ag_target != NULL); 1570255570Strasz else 1571255570Strasz assert(ag->ag_target == NULL); 1572255570Strasz 1573274871Strasz found = false; 1574255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 1575274871Strasz if (targ->t_auth_group == ag) { 1576274871Strasz found = true; 1577255570Strasz break; 1578274871Strasz } 1579255570Strasz } 1580274871Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 1581274871Strasz if (pg->pg_discovery_auth_group == ag) { 1582274871Strasz found = true; 1583274871Strasz break; 1584274871Strasz } 1585274871Strasz } 1586274871Strasz if (!found && ag->ag_name != NULL && 1587263728Strasz strcmp(ag->ag_name, "default") != 0 && 1588255570Strasz strcmp(ag->ag_name, "no-authentication") != 0 && 1589255570Strasz strcmp(ag->ag_name, "no-access") != 0) { 1590255570Strasz log_warnx("auth-group \"%s\" not assigned " 1591255570Strasz "to any target", ag->ag_name); 1592255570Strasz } 1593255570Strasz } 1594255570Strasz 1595255570Strasz return (0); 1596255570Strasz} 1597255570Strasz 1598255570Straszstatic int 1599255570Straszconf_apply(struct conf *oldconf, struct conf *newconf) 1600255570Strasz{ 1601255570Strasz struct target *oldtarg, *newtarg, *tmptarg; 1602255570Strasz struct lun *oldlun, *newlun, *tmplun; 1603255570Strasz struct portal_group *oldpg, *newpg; 1604255570Strasz struct portal *oldp, *newp; 1605274939Smav struct isns *oldns, *newns; 1606255570Strasz pid_t otherpid; 1607255570Strasz int changed, cumulated_error = 0, error; 1608255570Strasz int one = 1; 1609255570Strasz 1610255570Strasz if (oldconf->conf_debug != newconf->conf_debug) { 1611255570Strasz log_debugx("changing debug level to %d", newconf->conf_debug); 1612255570Strasz log_init(newconf->conf_debug); 1613255570Strasz } 1614255570Strasz 1615255570Strasz if (oldconf->conf_pidfh != NULL) { 1616255570Strasz assert(oldconf->conf_pidfile_path != NULL); 1617255570Strasz if (newconf->conf_pidfile_path != NULL && 1618255570Strasz strcmp(oldconf->conf_pidfile_path, 1619255570Strasz newconf->conf_pidfile_path) == 0) { 1620255570Strasz newconf->conf_pidfh = oldconf->conf_pidfh; 1621255570Strasz oldconf->conf_pidfh = NULL; 1622255570Strasz } else { 1623255570Strasz log_debugx("removing pidfile %s", 1624255570Strasz oldconf->conf_pidfile_path); 1625255570Strasz pidfile_remove(oldconf->conf_pidfh); 1626255570Strasz oldconf->conf_pidfh = NULL; 1627255570Strasz } 1628255570Strasz } 1629255570Strasz 1630255570Strasz if (newconf->conf_pidfh == NULL && newconf->conf_pidfile_path != NULL) { 1631255570Strasz log_debugx("opening pidfile %s", newconf->conf_pidfile_path); 1632255570Strasz newconf->conf_pidfh = 1633255570Strasz pidfile_open(newconf->conf_pidfile_path, 0600, &otherpid); 1634255570Strasz if (newconf->conf_pidfh == NULL) { 1635255570Strasz if (errno == EEXIST) 1636255570Strasz log_errx(1, "daemon already running, pid: %jd.", 1637255570Strasz (intmax_t)otherpid); 1638255570Strasz log_err(1, "cannot open or create pidfile \"%s\"", 1639255570Strasz newconf->conf_pidfile_path); 1640255570Strasz } 1641255570Strasz } 1642255570Strasz 1643274939Smav /* Deregister on removed iSNS servers. */ 1644274939Smav TAILQ_FOREACH(oldns, &oldconf->conf_isns, i_next) { 1645274939Smav TAILQ_FOREACH(newns, &newconf->conf_isns, i_next) { 1646274939Smav if (strcmp(oldns->i_addr, newns->i_addr) == 0) 1647274939Smav break; 1648274939Smav } 1649274939Smav if (newns == NULL) 1650274939Smav isns_deregister(oldns); 1651274939Smav } 1652274939Smav 1653265518Strasz /* 1654265518Strasz * XXX: If target or lun removal fails, we should somehow "move" 1655274870Strasz * the old lun or target into newconf, so that subsequent 1656274870Strasz * conf_apply() would try to remove them again. That would 1657274870Strasz * be somewhat hairy, though, and lun deletion failures don't 1658274870Strasz * really happen, so leave it as it is for now. 1659265518Strasz */ 1660255570Strasz TAILQ_FOREACH_SAFE(oldtarg, &oldconf->conf_targets, t_next, tmptarg) { 1661255570Strasz /* 1662255570Strasz * First, remove any targets present in the old configuration 1663255570Strasz * and missing in the new one. 1664255570Strasz */ 1665263723Strasz newtarg = target_find(newconf, oldtarg->t_name); 1666255570Strasz if (newtarg == NULL) { 1667255570Strasz TAILQ_FOREACH_SAFE(oldlun, &oldtarg->t_luns, l_next, 1668255570Strasz tmplun) { 1669263716Strasz log_debugx("target %s not found in new " 1670263716Strasz "configuration; removing its lun %d, " 1671255570Strasz "backed by CTL lun %d", 1672263723Strasz oldtarg->t_name, oldlun->l_lun, 1673255570Strasz oldlun->l_ctl_lun); 1674255570Strasz error = kernel_lun_remove(oldlun); 1675255570Strasz if (error != 0) { 1676255570Strasz log_warnx("failed to remove lun %d, " 1677255570Strasz "target %s, CTL lun %d", 1678263723Strasz oldlun->l_lun, oldtarg->t_name, 1679255570Strasz oldlun->l_ctl_lun); 1680255570Strasz cumulated_error++; 1681255570Strasz } 1682255570Strasz } 1683277749Strasz error = kernel_port_remove(oldtarg); 1684277749Strasz if (error != 0) { 1685277749Strasz log_warnx("failed to remove target %s", 1686277749Strasz oldtarg->t_name); 1687277749Strasz /* 1688277749Strasz * XXX: Uncomment after fixing the root cause. 1689277749Strasz * 1690277749Strasz * cumulated_error++; 1691277749Strasz */ 1692277749Strasz } 1693255570Strasz continue; 1694255570Strasz } 1695255570Strasz 1696255570Strasz /* 1697255570Strasz * Second, remove any LUNs present in the old target 1698255570Strasz * and missing in the new one. 1699255570Strasz */ 1700255570Strasz TAILQ_FOREACH_SAFE(oldlun, &oldtarg->t_luns, l_next, tmplun) { 1701255570Strasz newlun = lun_find(newtarg, oldlun->l_lun); 1702255570Strasz if (newlun == NULL) { 1703255570Strasz log_debugx("lun %d, target %s, CTL lun %d " 1704263716Strasz "not found in new configuration; " 1705263723Strasz "removing", oldlun->l_lun, oldtarg->t_name, 1706255570Strasz oldlun->l_ctl_lun); 1707255570Strasz error = kernel_lun_remove(oldlun); 1708255570Strasz if (error != 0) { 1709255570Strasz log_warnx("failed to remove lun %d, " 1710255570Strasz "target %s, CTL lun %d", 1711263723Strasz oldlun->l_lun, oldtarg->t_name, 1712255570Strasz oldlun->l_ctl_lun); 1713255570Strasz cumulated_error++; 1714255570Strasz } 1715255570Strasz continue; 1716255570Strasz } 1717255570Strasz 1718255570Strasz /* 1719255570Strasz * Also remove the LUNs changed by more than size. 1720255570Strasz */ 1721255570Strasz changed = 0; 1722255570Strasz assert(oldlun->l_backend != NULL); 1723255570Strasz assert(newlun->l_backend != NULL); 1724255570Strasz if (strcmp(newlun->l_backend, oldlun->l_backend) != 0) { 1725255570Strasz log_debugx("backend for lun %d, target %s, " 1726255570Strasz "CTL lun %d changed; removing", 1727263723Strasz oldlun->l_lun, oldtarg->t_name, 1728255570Strasz oldlun->l_ctl_lun); 1729255570Strasz changed = 1; 1730255570Strasz } 1731255570Strasz if (oldlun->l_blocksize != newlun->l_blocksize) { 1732255570Strasz log_debugx("blocksize for lun %d, target %s, " 1733255570Strasz "CTL lun %d changed; removing", 1734263723Strasz oldlun->l_lun, oldtarg->t_name, 1735255570Strasz oldlun->l_ctl_lun); 1736255570Strasz changed = 1; 1737255570Strasz } 1738255570Strasz if (newlun->l_device_id != NULL && 1739255570Strasz (oldlun->l_device_id == NULL || 1740255570Strasz strcmp(oldlun->l_device_id, newlun->l_device_id) != 1741255570Strasz 0)) { 1742255570Strasz log_debugx("device-id for lun %d, target %s, " 1743255570Strasz "CTL lun %d changed; removing", 1744263723Strasz oldlun->l_lun, oldtarg->t_name, 1745255570Strasz oldlun->l_ctl_lun); 1746255570Strasz changed = 1; 1747255570Strasz } 1748255570Strasz if (newlun->l_path != NULL && 1749255570Strasz (oldlun->l_path == NULL || 1750255570Strasz strcmp(oldlun->l_path, newlun->l_path) != 0)) { 1751255570Strasz log_debugx("path for lun %d, target %s, " 1752255570Strasz "CTL lun %d, changed; removing", 1753263723Strasz oldlun->l_lun, oldtarg->t_name, 1754255570Strasz oldlun->l_ctl_lun); 1755255570Strasz changed = 1; 1756255570Strasz } 1757255570Strasz if (newlun->l_serial != NULL && 1758255570Strasz (oldlun->l_serial == NULL || 1759255570Strasz strcmp(oldlun->l_serial, newlun->l_serial) != 0)) { 1760255570Strasz log_debugx("serial for lun %d, target %s, " 1761255570Strasz "CTL lun %d changed; removing", 1762263723Strasz oldlun->l_lun, oldtarg->t_name, 1763255570Strasz oldlun->l_ctl_lun); 1764255570Strasz changed = 1; 1765255570Strasz } 1766255570Strasz if (changed) { 1767255570Strasz error = kernel_lun_remove(oldlun); 1768255570Strasz if (error != 0) { 1769255570Strasz log_warnx("failed to remove lun %d, " 1770255570Strasz "target %s, CTL lun %d", 1771263723Strasz oldlun->l_lun, oldtarg->t_name, 1772255570Strasz oldlun->l_ctl_lun); 1773255570Strasz cumulated_error++; 1774255570Strasz } 1775255570Strasz lun_delete(oldlun); 1776255570Strasz continue; 1777255570Strasz } 1778255570Strasz 1779255570Strasz lun_set_ctl_lun(newlun, oldlun->l_ctl_lun); 1780255570Strasz } 1781255570Strasz } 1782255570Strasz 1783255570Strasz /* 1784255570Strasz * Now add new targets or modify existing ones. 1785255570Strasz */ 1786255570Strasz TAILQ_FOREACH(newtarg, &newconf->conf_targets, t_next) { 1787263723Strasz oldtarg = target_find(oldconf, newtarg->t_name); 1788255570Strasz 1789265518Strasz TAILQ_FOREACH_SAFE(newlun, &newtarg->t_luns, l_next, tmplun) { 1790255570Strasz if (oldtarg != NULL) { 1791255570Strasz oldlun = lun_find(oldtarg, newlun->l_lun); 1792255570Strasz if (oldlun != NULL) { 1793271929Smav if (newlun->l_size != oldlun->l_size || 1794271929Smav newlun->l_size == 0) { 1795255570Strasz log_debugx("resizing lun %d, " 1796255570Strasz "target %s, CTL lun %d", 1797255570Strasz newlun->l_lun, 1798263723Strasz newtarg->t_name, 1799255570Strasz newlun->l_ctl_lun); 1800255570Strasz error = 1801255570Strasz kernel_lun_resize(newlun); 1802255570Strasz if (error != 0) { 1803255570Strasz log_warnx("failed to " 1804255570Strasz "resize lun %d, " 1805255570Strasz "target %s, " 1806255570Strasz "CTL lun %d", 1807255570Strasz newlun->l_lun, 1808263723Strasz newtarg->t_name, 1809255570Strasz newlun->l_lun); 1810255570Strasz cumulated_error++; 1811255570Strasz } 1812255570Strasz } 1813255570Strasz continue; 1814255570Strasz } 1815255570Strasz } 1816255570Strasz log_debugx("adding lun %d, target %s", 1817263723Strasz newlun->l_lun, newtarg->t_name); 1818255570Strasz error = kernel_lun_add(newlun); 1819255570Strasz if (error != 0) { 1820255570Strasz log_warnx("failed to add lun %d, target %s", 1821263723Strasz newlun->l_lun, newtarg->t_name); 1822265518Strasz lun_delete(newlun); 1823255570Strasz cumulated_error++; 1824255570Strasz } 1825255570Strasz } 1826277749Strasz if (oldtarg == NULL) { 1827277749Strasz error = kernel_port_add(newtarg); 1828277749Strasz if (error != 0) { 1829277749Strasz log_warnx("failed to add target %s", 1830277749Strasz newtarg->t_name); 1831277749Strasz /* 1832277749Strasz * XXX: Uncomment after fixing the root cause. 1833277749Strasz * 1834277749Strasz * cumulated_error++; 1835277749Strasz */ 1836277749Strasz } 1837277749Strasz } 1838255570Strasz } 1839255570Strasz 1840255570Strasz /* 1841255570Strasz * Go through the new portals, opening the sockets as neccessary. 1842255570Strasz */ 1843255570Strasz TAILQ_FOREACH(newpg, &newconf->conf_portal_groups, pg_next) { 1844255570Strasz if (newpg->pg_unassigned) { 1845255570Strasz log_debugx("not listening on portal-group \"%s\", " 1846255570Strasz "not assigned to any target", 1847255570Strasz newpg->pg_name); 1848255570Strasz continue; 1849255570Strasz } 1850255570Strasz TAILQ_FOREACH(newp, &newpg->pg_portals, p_next) { 1851255570Strasz /* 1852255570Strasz * Try to find already open portal and reuse 1853255570Strasz * the listening socket. We don't care about 1854255570Strasz * what portal or portal group that was, what 1855255570Strasz * matters is the listening address. 1856255570Strasz */ 1857255570Strasz TAILQ_FOREACH(oldpg, &oldconf->conf_portal_groups, 1858255570Strasz pg_next) { 1859255570Strasz TAILQ_FOREACH(oldp, &oldpg->pg_portals, 1860255570Strasz p_next) { 1861255570Strasz if (strcmp(newp->p_listen, 1862255570Strasz oldp->p_listen) == 0 && 1863255570Strasz oldp->p_socket > 0) { 1864255570Strasz newp->p_socket = 1865255570Strasz oldp->p_socket; 1866255570Strasz oldp->p_socket = 0; 1867255570Strasz break; 1868255570Strasz } 1869255570Strasz } 1870255570Strasz } 1871255570Strasz if (newp->p_socket > 0) { 1872255570Strasz /* 1873255570Strasz * We're done with this portal. 1874255570Strasz */ 1875255570Strasz continue; 1876255570Strasz } 1877255570Strasz 1878255570Strasz#ifdef ICL_KERNEL_PROXY 1879265507Strasz if (proxy_mode) { 1880265509Strasz newpg->pg_conf->conf_portal_id++; 1881265509Strasz newp->p_id = newpg->pg_conf->conf_portal_id; 1882265509Strasz log_debugx("listening on %s, portal-group " 1883265509Strasz "\"%s\", portal id %d, using ICL proxy", 1884265509Strasz newp->p_listen, newpg->pg_name, newp->p_id); 1885265509Strasz kernel_listen(newp->p_ai, newp->p_iser, 1886265509Strasz newp->p_id); 1887265507Strasz continue; 1888265507Strasz } 1889265507Strasz#endif 1890265507Strasz assert(proxy_mode == false); 1891255570Strasz assert(newp->p_iser == false); 1892255570Strasz 1893255570Strasz log_debugx("listening on %s, portal-group \"%s\"", 1894255570Strasz newp->p_listen, newpg->pg_name); 1895255570Strasz newp->p_socket = socket(newp->p_ai->ai_family, 1896255570Strasz newp->p_ai->ai_socktype, 1897255570Strasz newp->p_ai->ai_protocol); 1898255570Strasz if (newp->p_socket < 0) { 1899255570Strasz log_warn("socket(2) failed for %s", 1900255570Strasz newp->p_listen); 1901255570Strasz cumulated_error++; 1902255570Strasz continue; 1903255570Strasz } 1904255570Strasz error = setsockopt(newp->p_socket, SOL_SOCKET, 1905255570Strasz SO_REUSEADDR, &one, sizeof(one)); 1906255570Strasz if (error != 0) { 1907255570Strasz log_warn("setsockopt(SO_REUSEADDR) failed " 1908255570Strasz "for %s", newp->p_listen); 1909255570Strasz close(newp->p_socket); 1910255570Strasz newp->p_socket = 0; 1911255570Strasz cumulated_error++; 1912255570Strasz continue; 1913255570Strasz } 1914255570Strasz error = bind(newp->p_socket, newp->p_ai->ai_addr, 1915255570Strasz newp->p_ai->ai_addrlen); 1916255570Strasz if (error != 0) { 1917255570Strasz log_warn("bind(2) failed for %s", 1918255570Strasz newp->p_listen); 1919255570Strasz close(newp->p_socket); 1920255570Strasz newp->p_socket = 0; 1921255570Strasz cumulated_error++; 1922255570Strasz continue; 1923255570Strasz } 1924255570Strasz error = listen(newp->p_socket, -1); 1925255570Strasz if (error != 0) { 1926255570Strasz log_warn("listen(2) failed for %s", 1927255570Strasz newp->p_listen); 1928255570Strasz close(newp->p_socket); 1929255570Strasz newp->p_socket = 0; 1930255570Strasz cumulated_error++; 1931255570Strasz continue; 1932255570Strasz } 1933255570Strasz } 1934255570Strasz } 1935255570Strasz 1936255570Strasz /* 1937255570Strasz * Go through the no longer used sockets, closing them. 1938255570Strasz */ 1939255570Strasz TAILQ_FOREACH(oldpg, &oldconf->conf_portal_groups, pg_next) { 1940255570Strasz TAILQ_FOREACH(oldp, &oldpg->pg_portals, p_next) { 1941255570Strasz if (oldp->p_socket <= 0) 1942255570Strasz continue; 1943255570Strasz log_debugx("closing socket for %s, portal-group \"%s\"", 1944255570Strasz oldp->p_listen, oldpg->pg_name); 1945255570Strasz close(oldp->p_socket); 1946255570Strasz oldp->p_socket = 0; 1947255570Strasz } 1948255570Strasz } 1949255570Strasz 1950274939Smav /* (Re-)Register on remaining/new iSNS servers. */ 1951274939Smav TAILQ_FOREACH(newns, &newconf->conf_isns, i_next) { 1952274939Smav TAILQ_FOREACH(oldns, &oldconf->conf_isns, i_next) { 1953274939Smav if (strcmp(oldns->i_addr, newns->i_addr) == 0) 1954274939Smav break; 1955274939Smav } 1956274939Smav isns_register(newns, oldns); 1957274939Smav } 1958274939Smav 1959274939Smav /* Schedule iSNS update */ 1960274939Smav if (!TAILQ_EMPTY(&newconf->conf_isns)) 1961274939Smav set_timeout((newconf->conf_isns_period + 2) / 3, false); 1962274939Smav 1963255570Strasz return (cumulated_error); 1964255570Strasz} 1965255570Strasz 1966255570Straszbool 1967255570Strasztimed_out(void) 1968255570Strasz{ 1969255570Strasz 1970255570Strasz return (sigalrm_received); 1971255570Strasz} 1972255570Strasz 1973255570Straszstatic void 1974274939Smavsigalrm_handler_fatal(int dummy __unused) 1975255570Strasz{ 1976255570Strasz /* 1977255570Strasz * It would be easiest to just log an error and exit. We can't 1978255570Strasz * do this, though, because log_errx() is not signal safe, since 1979255570Strasz * it calls syslog(3). Instead, set a flag checked by pdu_send() 1980255570Strasz * and pdu_receive(), to call log_errx() there. Should they fail 1981255570Strasz * to notice, we'll exit here one second later. 1982255570Strasz */ 1983255570Strasz if (sigalrm_received) { 1984255570Strasz /* 1985255570Strasz * Oh well. Just give up and quit. 1986255570Strasz */ 1987255570Strasz _exit(2); 1988255570Strasz } 1989255570Strasz 1990255570Strasz sigalrm_received = true; 1991255570Strasz} 1992255570Strasz 1993255570Straszstatic void 1994274939Smavsigalrm_handler(int dummy __unused) 1995255570Strasz{ 1996274939Smav 1997274939Smav sigalrm_received = true; 1998274939Smav} 1999274939Smav 2000274939Smavvoid 2001274939Smavset_timeout(int timeout, int fatal) 2002274939Smav{ 2003255570Strasz struct sigaction sa; 2004255570Strasz struct itimerval itv; 2005255570Strasz int error; 2006255570Strasz 2007274939Smav if (timeout <= 0) { 2008255570Strasz log_debugx("session timeout disabled"); 2009274939Smav bzero(&itv, sizeof(itv)); 2010274939Smav error = setitimer(ITIMER_REAL, &itv, NULL); 2011274939Smav if (error != 0) 2012274939Smav log_err(1, "setitimer"); 2013274939Smav sigalrm_received = false; 2014255570Strasz return; 2015255570Strasz } 2016255570Strasz 2017274939Smav sigalrm_received = false; 2018255570Strasz bzero(&sa, sizeof(sa)); 2019274939Smav if (fatal) 2020274939Smav sa.sa_handler = sigalrm_handler_fatal; 2021274939Smav else 2022274939Smav sa.sa_handler = sigalrm_handler; 2023255570Strasz sigfillset(&sa.sa_mask); 2024255570Strasz error = sigaction(SIGALRM, &sa, NULL); 2025255570Strasz if (error != 0) 2026255570Strasz log_err(1, "sigaction"); 2027255570Strasz 2028255570Strasz /* 2029255570Strasz * First SIGALRM will arive after conf_timeout seconds. 2030255570Strasz * If we do nothing, another one will arrive a second later. 2031255570Strasz */ 2032274939Smav log_debugx("setting session timeout to %d seconds", timeout); 2033255570Strasz bzero(&itv, sizeof(itv)); 2034255570Strasz itv.it_interval.tv_sec = 1; 2035274939Smav itv.it_value.tv_sec = timeout; 2036255570Strasz error = setitimer(ITIMER_REAL, &itv, NULL); 2037255570Strasz if (error != 0) 2038255570Strasz log_err(1, "setitimer"); 2039255570Strasz} 2040255570Strasz 2041255570Straszstatic int 2042255570Straszwait_for_children(bool block) 2043255570Strasz{ 2044255570Strasz pid_t pid; 2045255570Strasz int status; 2046255570Strasz int num = 0; 2047255570Strasz 2048255570Strasz for (;;) { 2049255570Strasz /* 2050255570Strasz * If "block" is true, wait for at least one process. 2051255570Strasz */ 2052255570Strasz if (block && num == 0) 2053255570Strasz pid = wait4(-1, &status, 0, NULL); 2054255570Strasz else 2055255570Strasz pid = wait4(-1, &status, WNOHANG, NULL); 2056255570Strasz if (pid <= 0) 2057255570Strasz break; 2058255570Strasz if (WIFSIGNALED(status)) { 2059255570Strasz log_warnx("child process %d terminated with signal %d", 2060255570Strasz pid, WTERMSIG(status)); 2061255570Strasz } else if (WEXITSTATUS(status) != 0) { 2062255570Strasz log_warnx("child process %d terminated with exit status %d", 2063255570Strasz pid, WEXITSTATUS(status)); 2064255570Strasz } else { 2065255570Strasz log_debugx("child process %d terminated gracefully", pid); 2066255570Strasz } 2067255570Strasz num++; 2068255570Strasz } 2069255570Strasz 2070255570Strasz return (num); 2071255570Strasz} 2072255570Strasz 2073255570Straszstatic void 2074265513Straszhandle_connection(struct portal *portal, int fd, 2075270137Smav const struct sockaddr *client_sa, bool dont_fork) 2076255570Strasz{ 2077255570Strasz struct connection *conn; 2078255570Strasz int error; 2079255570Strasz pid_t pid; 2080255570Strasz char host[NI_MAXHOST + 1]; 2081255570Strasz struct conf *conf; 2082255570Strasz 2083255570Strasz conf = portal->p_portal_group->pg_conf; 2084255570Strasz 2085255570Strasz if (dont_fork) { 2086255570Strasz log_debugx("incoming connection; not forking due to -d flag"); 2087255570Strasz } else { 2088255570Strasz nchildren -= wait_for_children(false); 2089255570Strasz assert(nchildren >= 0); 2090255570Strasz 2091255570Strasz while (conf->conf_maxproc > 0 && nchildren >= conf->conf_maxproc) { 2092255570Strasz log_debugx("maxproc limit of %d child processes hit; " 2093255570Strasz "waiting for child process to exit", conf->conf_maxproc); 2094255570Strasz nchildren -= wait_for_children(true); 2095255570Strasz assert(nchildren >= 0); 2096255570Strasz } 2097255570Strasz log_debugx("incoming connection; forking child process #%d", 2098255570Strasz nchildren); 2099255570Strasz nchildren++; 2100255570Strasz pid = fork(); 2101255570Strasz if (pid < 0) 2102255570Strasz log_err(1, "fork"); 2103255570Strasz if (pid > 0) { 2104255570Strasz close(fd); 2105255570Strasz return; 2106255570Strasz } 2107255570Strasz } 2108255570Strasz pidfile_close(conf->conf_pidfh); 2109255570Strasz 2110270137Smav error = getnameinfo(client_sa, client_sa->sa_len, 2111265513Strasz host, sizeof(host), NULL, 0, NI_NUMERICHOST); 2112265513Strasz if (error != 0) 2113265513Strasz log_errx(1, "getnameinfo: %s", gai_strerror(error)); 2114255570Strasz 2115265513Strasz log_debugx("accepted connection from %s; portal group \"%s\"", 2116265513Strasz host, portal->p_portal_group->pg_name); 2117265513Strasz log_set_peer_addr(host); 2118265513Strasz setproctitle("%s", host); 2119255570Strasz 2120270137Smav conn = connection_new(portal, fd, host, client_sa); 2121274939Smav set_timeout(conf->conf_timeout, true); 2122255570Strasz kernel_capsicate(); 2123255570Strasz login(conn); 2124255570Strasz if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) { 2125255570Strasz kernel_handoff(conn); 2126255570Strasz log_debugx("connection handed off to the kernel"); 2127255570Strasz } else { 2128255570Strasz assert(conn->conn_session_type == CONN_SESSION_TYPE_DISCOVERY); 2129255570Strasz discovery(conn); 2130255570Strasz } 2131255570Strasz log_debugx("nothing more to do; exiting"); 2132255570Strasz exit(0); 2133255570Strasz} 2134255570Strasz 2135255570Straszstatic int 2136255570Straszfd_add(int fd, fd_set *fdset, int nfds) 2137255570Strasz{ 2138255570Strasz 2139255570Strasz /* 2140255570Strasz * Skip sockets which we failed to bind. 2141255570Strasz */ 2142255570Strasz if (fd <= 0) 2143255570Strasz return (nfds); 2144255570Strasz 2145255570Strasz FD_SET(fd, fdset); 2146255570Strasz if (fd > nfds) 2147255570Strasz nfds = fd; 2148255570Strasz return (nfds); 2149255570Strasz} 2150255570Strasz 2151255570Straszstatic void 2152255570Straszmain_loop(struct conf *conf, bool dont_fork) 2153255570Strasz{ 2154255570Strasz struct portal_group *pg; 2155255570Strasz struct portal *portal; 2156265512Strasz struct sockaddr_storage client_sa; 2157265512Strasz socklen_t client_salen; 2158255570Strasz#ifdef ICL_KERNEL_PROXY 2159255570Strasz int connection_id; 2160265509Strasz int portal_id; 2161265507Strasz#endif 2162255570Strasz fd_set fdset; 2163255570Strasz int error, nfds, client_fd; 2164255570Strasz 2165255570Strasz pidfile_write(conf->conf_pidfh); 2166255570Strasz 2167255570Strasz for (;;) { 2168274939Smav if (sighup_received || sigterm_received || timed_out()) 2169255570Strasz return; 2170255570Strasz 2171255570Strasz#ifdef ICL_KERNEL_PROXY 2172265507Strasz if (proxy_mode) { 2173265513Strasz client_salen = sizeof(client_sa); 2174265513Strasz kernel_accept(&connection_id, &portal_id, 2175265513Strasz (struct sockaddr *)&client_sa, &client_salen); 2176271627Strasz assert(client_salen >= client_sa.ss_len); 2177255570Strasz 2178265509Strasz log_debugx("incoming connection, id %d, portal id %d", 2179265509Strasz connection_id, portal_id); 2180265509Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 2181265509Strasz TAILQ_FOREACH(portal, &pg->pg_portals, p_next) { 2182265509Strasz if (portal->p_id == portal_id) { 2183265509Strasz goto found; 2184265509Strasz } 2185265509Strasz } 2186265509Strasz } 2187255570Strasz 2188265509Strasz log_errx(1, "kernel returned invalid portal_id %d", 2189265509Strasz portal_id); 2190265509Strasz 2191265509Straszfound: 2192265513Strasz handle_connection(portal, connection_id, 2193270137Smav (struct sockaddr *)&client_sa, dont_fork); 2194265507Strasz } else { 2195265507Strasz#endif 2196265507Strasz assert(proxy_mode == false); 2197265507Strasz 2198265507Strasz FD_ZERO(&fdset); 2199265507Strasz nfds = 0; 2200265507Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 2201265507Strasz TAILQ_FOREACH(portal, &pg->pg_portals, p_next) 2202265507Strasz nfds = fd_add(portal->p_socket, &fdset, nfds); 2203255570Strasz } 2204265507Strasz error = select(nfds + 1, &fdset, NULL, NULL, NULL); 2205265507Strasz if (error <= 0) { 2206265507Strasz if (errno == EINTR) 2207265507Strasz return; 2208265507Strasz log_err(1, "select"); 2209265507Strasz } 2210265507Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 2211265507Strasz TAILQ_FOREACH(portal, &pg->pg_portals, p_next) { 2212265507Strasz if (!FD_ISSET(portal->p_socket, &fdset)) 2213265507Strasz continue; 2214265512Strasz client_salen = sizeof(client_sa); 2215265512Strasz client_fd = accept(portal->p_socket, 2216265512Strasz (struct sockaddr *)&client_sa, 2217265512Strasz &client_salen); 2218265507Strasz if (client_fd < 0) 2219265507Strasz log_err(1, "accept"); 2220271627Strasz assert(client_salen >= client_sa.ss_len); 2221271627Strasz 2222265512Strasz handle_connection(portal, client_fd, 2223265513Strasz (struct sockaddr *)&client_sa, 2224270137Smav dont_fork); 2225265507Strasz break; 2226265507Strasz } 2227265507Strasz } 2228265507Strasz#ifdef ICL_KERNEL_PROXY 2229255570Strasz } 2230265507Strasz#endif 2231255570Strasz } 2232255570Strasz} 2233255570Strasz 2234255570Straszstatic void 2235255570Straszsighup_handler(int dummy __unused) 2236255570Strasz{ 2237255570Strasz 2238255570Strasz sighup_received = true; 2239255570Strasz} 2240255570Strasz 2241255570Straszstatic void 2242255570Straszsigterm_handler(int dummy __unused) 2243255570Strasz{ 2244255570Strasz 2245255570Strasz sigterm_received = true; 2246255570Strasz} 2247255570Strasz 2248255570Straszstatic void 2249263730Straszsigchld_handler(int dummy __unused) 2250263730Strasz{ 2251263730Strasz 2252263730Strasz /* 2253263730Strasz * The only purpose of this handler is to make SIGCHLD 2254263730Strasz * interrupt the ISCSIDWAIT ioctl(2), so we can call 2255263730Strasz * wait_for_children(). 2256263730Strasz */ 2257263730Strasz} 2258263730Strasz 2259263730Straszstatic void 2260255570Straszregister_signals(void) 2261255570Strasz{ 2262255570Strasz struct sigaction sa; 2263255570Strasz int error; 2264255570Strasz 2265255570Strasz bzero(&sa, sizeof(sa)); 2266255570Strasz sa.sa_handler = sighup_handler; 2267255570Strasz sigfillset(&sa.sa_mask); 2268255570Strasz error = sigaction(SIGHUP, &sa, NULL); 2269255570Strasz if (error != 0) 2270255570Strasz log_err(1, "sigaction"); 2271255570Strasz 2272255570Strasz sa.sa_handler = sigterm_handler; 2273255570Strasz error = sigaction(SIGTERM, &sa, NULL); 2274255570Strasz if (error != 0) 2275255570Strasz log_err(1, "sigaction"); 2276255570Strasz 2277255570Strasz sa.sa_handler = sigterm_handler; 2278255570Strasz error = sigaction(SIGINT, &sa, NULL); 2279255570Strasz if (error != 0) 2280255570Strasz log_err(1, "sigaction"); 2281263730Strasz 2282263730Strasz sa.sa_handler = sigchld_handler; 2283263730Strasz error = sigaction(SIGCHLD, &sa, NULL); 2284263730Strasz if (error != 0) 2285263730Strasz log_err(1, "sigaction"); 2286255570Strasz} 2287255570Strasz 2288255570Straszint 2289255570Straszmain(int argc, char **argv) 2290255570Strasz{ 2291255570Strasz struct conf *oldconf, *newconf, *tmpconf; 2292274939Smav struct isns *newns; 2293255570Strasz const char *config_path = DEFAULT_CONFIG_PATH; 2294255570Strasz int debug = 0, ch, error; 2295255570Strasz bool dont_daemonize = false; 2296255570Strasz 2297265507Strasz while ((ch = getopt(argc, argv, "df:R")) != -1) { 2298255570Strasz switch (ch) { 2299255570Strasz case 'd': 2300255570Strasz dont_daemonize = true; 2301255570Strasz debug++; 2302255570Strasz break; 2303255570Strasz case 'f': 2304255570Strasz config_path = optarg; 2305255570Strasz break; 2306265507Strasz case 'R': 2307265507Strasz#ifndef ICL_KERNEL_PROXY 2308265507Strasz log_errx(1, "ctld(8) compiled without ICL_KERNEL_PROXY " 2309265507Strasz "does not support iSER protocol"); 2310265507Strasz#endif 2311265507Strasz proxy_mode = true; 2312265507Strasz break; 2313255570Strasz case '?': 2314255570Strasz default: 2315255570Strasz usage(); 2316255570Strasz } 2317255570Strasz } 2318255570Strasz argc -= optind; 2319255570Strasz if (argc != 0) 2320255570Strasz usage(); 2321255570Strasz 2322255570Strasz log_init(debug); 2323255570Strasz kernel_init(); 2324255570Strasz 2325255570Strasz oldconf = conf_new_from_kernel(); 2326255570Strasz newconf = conf_new_from_file(config_path); 2327255570Strasz if (newconf == NULL) 2328265516Strasz log_errx(1, "configuration error; exiting"); 2329255570Strasz if (debug > 0) { 2330255570Strasz oldconf->conf_debug = debug; 2331255570Strasz newconf->conf_debug = debug; 2332255570Strasz } 2333255570Strasz 2334255570Strasz error = conf_apply(oldconf, newconf); 2335255570Strasz if (error != 0) 2336265516Strasz log_errx(1, "failed to apply configuration; exiting"); 2337265516Strasz 2338255570Strasz conf_delete(oldconf); 2339255570Strasz oldconf = NULL; 2340255570Strasz 2341255570Strasz register_signals(); 2342255570Strasz 2343263719Strasz if (dont_daemonize == false) { 2344263719Strasz log_debugx("daemonizing"); 2345263719Strasz if (daemon(0, 0) == -1) { 2346263719Strasz log_warn("cannot daemonize"); 2347263719Strasz pidfile_remove(newconf->conf_pidfh); 2348263719Strasz exit(1); 2349263719Strasz } 2350263719Strasz } 2351263719Strasz 2352274939Smav /* Schedule iSNS update */ 2353274939Smav if (!TAILQ_EMPTY(&newconf->conf_isns)) 2354274939Smav set_timeout((newconf->conf_isns_period + 2) / 3, false); 2355274939Smav 2356255570Strasz for (;;) { 2357255570Strasz main_loop(newconf, dont_daemonize); 2358255570Strasz if (sighup_received) { 2359255570Strasz sighup_received = false; 2360255570Strasz log_debugx("received SIGHUP, reloading configuration"); 2361255570Strasz tmpconf = conf_new_from_file(config_path); 2362255570Strasz if (tmpconf == NULL) { 2363255570Strasz log_warnx("configuration error, " 2364255570Strasz "continuing with old configuration"); 2365255570Strasz } else { 2366255570Strasz if (debug > 0) 2367255570Strasz tmpconf->conf_debug = debug; 2368255570Strasz oldconf = newconf; 2369255570Strasz newconf = tmpconf; 2370255570Strasz error = conf_apply(oldconf, newconf); 2371255570Strasz if (error != 0) 2372255570Strasz log_warnx("failed to reload " 2373255570Strasz "configuration"); 2374255570Strasz conf_delete(oldconf); 2375255570Strasz oldconf = NULL; 2376255570Strasz } 2377255570Strasz } else if (sigterm_received) { 2378255570Strasz log_debugx("exiting on signal; " 2379255570Strasz "reloading empty configuration"); 2380255570Strasz 2381255570Strasz log_debugx("disabling CTL iSCSI port " 2382255570Strasz "and terminating all connections"); 2383255570Strasz 2384255570Strasz oldconf = newconf; 2385255570Strasz newconf = conf_new(); 2386255570Strasz if (debug > 0) 2387255570Strasz newconf->conf_debug = debug; 2388255570Strasz error = conf_apply(oldconf, newconf); 2389255570Strasz if (error != 0) 2390255570Strasz log_warnx("failed to apply configuration"); 2391274939Smav conf_delete(oldconf); 2392274939Smav oldconf = NULL; 2393255570Strasz 2394255570Strasz log_warnx("exiting on signal"); 2395255570Strasz exit(0); 2396255570Strasz } else { 2397255570Strasz nchildren -= wait_for_children(false); 2398255570Strasz assert(nchildren >= 0); 2399274939Smav if (timed_out()) { 2400274939Smav set_timeout(0, false); 2401274939Smav TAILQ_FOREACH(newns, &newconf->conf_isns, i_next) 2402274939Smav isns_check(newns); 2403274939Smav /* Schedule iSNS update */ 2404274939Smav if (!TAILQ_EMPTY(&newconf->conf_isns)) { 2405274939Smav set_timeout((newconf->conf_isns_period 2406274939Smav + 2) / 3, 2407274939Smav false); 2408274939Smav } 2409274939Smav } 2410255570Strasz } 2411255570Strasz } 2412255570Strasz /* NOTREACHED */ 2413255570Strasz} 2414