ctld.c revision 274949
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 274949 2014-11-24 07:59:44Z 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 525263724Straszstatic int 526263724Straszauth_group_set_type(struct auth_group *ag, int type) 527263724Strasz{ 528263724Strasz 529263724Strasz if (ag->ag_type == AG_TYPE_UNKNOWN) { 530263724Strasz ag->ag_type = type; 531263724Strasz return (0); 532263724Strasz } 533263724Strasz 534263724Strasz if (ag->ag_type == type) 535263724Strasz return (0); 536263724Strasz 537263724Strasz return (1); 538263724Strasz} 539263724Strasz 540263724Straszint 541263724Straszauth_group_set_type_str(struct auth_group *ag, const char *str) 542263724Strasz{ 543263724Strasz int error, type; 544263724Strasz 545263724Strasz if (strcmp(str, "none") == 0) { 546263724Strasz type = AG_TYPE_NO_AUTHENTICATION; 547263729Strasz } else if (strcmp(str, "deny") == 0) { 548263729Strasz type = AG_TYPE_DENY; 549263724Strasz } else if (strcmp(str, "chap") == 0) { 550263724Strasz type = AG_TYPE_CHAP; 551263724Strasz } else if (strcmp(str, "chap-mutual") == 0) { 552263724Strasz type = AG_TYPE_CHAP_MUTUAL; 553263724Strasz } else { 554263724Strasz if (ag->ag_name != NULL) 555263724Strasz log_warnx("invalid auth-type \"%s\" for auth-group " 556263724Strasz "\"%s\"", str, ag->ag_name); 557263724Strasz else 558263724Strasz log_warnx("invalid auth-type \"%s\" for target " 559263724Strasz "\"%s\"", str, ag->ag_target->t_name); 560263724Strasz return (1); 561263724Strasz } 562263724Strasz 563263724Strasz error = auth_group_set_type(ag, type); 564263724Strasz if (error != 0) { 565263724Strasz if (ag->ag_name != NULL) 566263724Strasz log_warnx("cannot set auth-type to \"%s\" for " 567263724Strasz "auth-group \"%s\"; already has a different " 568263724Strasz "type", str, ag->ag_name); 569263724Strasz else 570263724Strasz log_warnx("cannot set auth-type to \"%s\" for target " 571263724Strasz "\"%s\"; already has a different type", 572263724Strasz str, ag->ag_target->t_name); 573263724Strasz return (1); 574263724Strasz } 575263724Strasz 576263724Strasz return (error); 577263724Strasz} 578263724Strasz 579255570Straszstatic struct portal * 580255570Straszportal_new(struct portal_group *pg) 581255570Strasz{ 582255570Strasz struct portal *portal; 583255570Strasz 584255570Strasz portal = calloc(1, sizeof(*portal)); 585255570Strasz if (portal == NULL) 586255570Strasz log_err(1, "calloc"); 587255570Strasz TAILQ_INIT(&portal->p_targets); 588255570Strasz portal->p_portal_group = pg; 589255570Strasz TAILQ_INSERT_TAIL(&pg->pg_portals, portal, p_next); 590255570Strasz return (portal); 591255570Strasz} 592255570Strasz 593255570Straszstatic void 594255570Straszportal_delete(struct portal *portal) 595255570Strasz{ 596271632Strasz 597255570Strasz TAILQ_REMOVE(&portal->p_portal_group->pg_portals, portal, p_next); 598271632Strasz if (portal->p_ai != NULL) 599271632Strasz freeaddrinfo(portal->p_ai); 600255570Strasz free(portal->p_listen); 601255570Strasz free(portal); 602255570Strasz} 603255570Strasz 604255570Straszstruct portal_group * 605255570Straszportal_group_new(struct conf *conf, const char *name) 606255570Strasz{ 607255570Strasz struct portal_group *pg; 608255570Strasz 609255678Strasz pg = portal_group_find(conf, name); 610255678Strasz if (pg != NULL) { 611255678Strasz log_warnx("duplicated portal-group \"%s\"", name); 612255678Strasz return (NULL); 613255570Strasz } 614255570Strasz 615255570Strasz pg = calloc(1, sizeof(*pg)); 616255570Strasz if (pg == NULL) 617255570Strasz log_err(1, "calloc"); 618255570Strasz pg->pg_name = checked_strdup(name); 619255570Strasz TAILQ_INIT(&pg->pg_portals); 620255570Strasz pg->pg_conf = conf; 621255570Strasz conf->conf_last_portal_group_tag++; 622255570Strasz pg->pg_tag = conf->conf_last_portal_group_tag; 623255570Strasz TAILQ_INSERT_TAIL(&conf->conf_portal_groups, pg, pg_next); 624255570Strasz 625255570Strasz return (pg); 626255570Strasz} 627255570Strasz 628255570Straszvoid 629255570Straszportal_group_delete(struct portal_group *pg) 630255570Strasz{ 631255570Strasz struct portal *portal, *tmp; 632255570Strasz 633255570Strasz TAILQ_REMOVE(&pg->pg_conf->conf_portal_groups, pg, pg_next); 634255570Strasz 635255570Strasz TAILQ_FOREACH_SAFE(portal, &pg->pg_portals, p_next, tmp) 636255570Strasz portal_delete(portal); 637255570Strasz free(pg->pg_name); 638255570Strasz free(pg); 639255570Strasz} 640255570Strasz 641255570Straszstruct portal_group * 642265514Straszportal_group_find(const struct conf *conf, const char *name) 643255570Strasz{ 644255570Strasz struct portal_group *pg; 645255570Strasz 646255570Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 647255570Strasz if (strcmp(pg->pg_name, name) == 0) 648255570Strasz return (pg); 649255570Strasz } 650255570Strasz 651255570Strasz return (NULL); 652255570Strasz} 653255570Strasz 654274939Smavstatic int 655274939Smavparse_addr_port(char *arg, const char *def_port, struct addrinfo **ai) 656255570Strasz{ 657255570Strasz struct addrinfo hints; 658274939Smav char *addr, *ch; 659255570Strasz const char *port; 660255570Strasz int error, colons = 0; 661255570Strasz 662255570Strasz if (arg[0] == '[') { 663255570Strasz /* 664255570Strasz * IPv6 address in square brackets, perhaps with port. 665255570Strasz */ 666255570Strasz arg++; 667255570Strasz addr = strsep(&arg, "]"); 668274939Smav if (arg == NULL) 669255570Strasz return (1); 670255570Strasz if (arg[0] == '\0') { 671274939Smav port = def_port; 672255570Strasz } else if (arg[0] == ':') { 673255570Strasz port = arg + 1; 674274939Smav } else 675255570Strasz return (1); 676255570Strasz } else { 677255570Strasz /* 678255570Strasz * Either IPv6 address without brackets - and without 679255570Strasz * a port - or IPv4 address. Just count the colons. 680255570Strasz */ 681255570Strasz for (ch = arg; *ch != '\0'; ch++) { 682255570Strasz if (*ch == ':') 683255570Strasz colons++; 684255570Strasz } 685255570Strasz if (colons > 1) { 686255570Strasz addr = arg; 687274939Smav port = def_port; 688255570Strasz } else { 689255570Strasz addr = strsep(&arg, ":"); 690255570Strasz if (arg == NULL) 691274939Smav port = def_port; 692255570Strasz else 693255570Strasz port = arg; 694255570Strasz } 695255570Strasz } 696255570Strasz 697255570Strasz memset(&hints, 0, sizeof(hints)); 698255570Strasz hints.ai_family = PF_UNSPEC; 699255570Strasz hints.ai_socktype = SOCK_STREAM; 700255570Strasz hints.ai_flags = AI_PASSIVE; 701274939Smav error = getaddrinfo(addr, port, &hints, ai); 702274939Smav if (error != 0) 703274939Smav return (1); 704274939Smav return (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; 793274939Smav struct isns_req *req; 794274939Smav int res = 0; 795274939Smav uint32_t error; 796274939Smav 797274939Smav req = isns_req_create(ISNS_FUNC_DEVATTRREG, ISNS_FLAG_CLIENT); 798274939Smav isns_req_add_str(req, 32, TAILQ_FIRST(&conf->conf_targets)->t_name); 799274939Smav isns_req_add_delim(req); 800274939Smav isns_req_add_str(req, 1, hostname); 801274939Smav isns_req_add_32(req, 2, 2); /* 2 -- iSCSI */ 802274939Smav isns_req_add_32(req, 6, conf->conf_isns_period); 803274939Smav TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 804274939Smav if (pg->pg_unassigned) 805274939Smav continue; 806274939Smav TAILQ_FOREACH(portal, &pg->pg_portals, p_next) { 807274939Smav isns_req_add_addr(req, 16, portal->p_ai); 808274939Smav isns_req_add_port(req, 17, portal->p_ai); 809274939Smav } 810274939Smav } 811274939Smav TAILQ_FOREACH(target, &conf->conf_targets, t_next) { 812274939Smav isns_req_add_str(req, 32, target->t_name); 813274939Smav isns_req_add_32(req, 33, 1); /* 1 -- Target*/ 814274939Smav if (target->t_alias != NULL) 815274939Smav isns_req_add_str(req, 34, target->t_alias); 816274939Smav pg = target->t_portal_group; 817274939Smav isns_req_add_32(req, 51, pg->pg_tag); 818274939Smav TAILQ_FOREACH(portal, &pg->pg_portals, p_next) { 819274939Smav isns_req_add_addr(req, 49, portal->p_ai); 820274939Smav isns_req_add_port(req, 50, portal->p_ai); 821274939Smav } 822274939Smav } 823274939Smav res = isns_req_send(s, req); 824274939Smav if (res < 0) { 825274939Smav log_warn("send(2) failed for %s", isns->i_addr); 826274939Smav goto quit; 827274939Smav } 828274939Smav res = isns_req_receive(s, req); 829274939Smav if (res < 0) { 830274939Smav log_warn("receive(2) failed for %s", isns->i_addr); 831274939Smav goto quit; 832274939Smav } 833274939Smav error = isns_req_get_status(req); 834274939Smav if (error != 0) { 835274939Smav log_warnx("iSNS register error %d for %s", error, isns->i_addr); 836274939Smav res = -1; 837274939Smav } 838274939Smavquit: 839274939Smav isns_req_free(req); 840274939Smav return (res); 841274939Smav} 842274939Smav 843274939Smavstatic int 844274939Smavisns_do_check(struct isns *isns, int s, const char *hostname) 845274939Smav{ 846274939Smav struct conf *conf = isns->i_conf; 847274939Smav struct isns_req *req; 848274939Smav int res = 0; 849274939Smav uint32_t error; 850274939Smav 851274939Smav req = isns_req_create(ISNS_FUNC_DEVATTRQRY, ISNS_FLAG_CLIENT); 852274939Smav isns_req_add_str(req, 32, TAILQ_FIRST(&conf->conf_targets)->t_name); 853274939Smav isns_req_add_str(req, 1, hostname); 854274939Smav isns_req_add_delim(req); 855274939Smav isns_req_add(req, 2, 0, NULL); 856274939Smav res = isns_req_send(s, req); 857274939Smav if (res < 0) { 858274939Smav log_warn("send(2) failed for %s", isns->i_addr); 859274939Smav goto quit; 860274939Smav } 861274939Smav res = isns_req_receive(s, req); 862274939Smav if (res < 0) { 863274939Smav log_warn("receive(2) failed for %s", isns->i_addr); 864274939Smav goto quit; 865274939Smav } 866274939Smav error = isns_req_get_status(req); 867274939Smav if (error != 0) { 868274939Smav log_warnx("iSNS check error %d for %s", error, isns->i_addr); 869274939Smav res = -1; 870274939Smav } 871274939Smavquit: 872274939Smav isns_req_free(req); 873274939Smav return (res); 874274939Smav} 875274939Smav 876274939Smavstatic int 877274939Smavisns_do_deregister(struct isns *isns, int s, const char *hostname) 878274939Smav{ 879274939Smav struct conf *conf = isns->i_conf; 880274939Smav struct isns_req *req; 881274939Smav int res = 0; 882274939Smav uint32_t error; 883274939Smav 884274939Smav req = isns_req_create(ISNS_FUNC_DEVDEREG, ISNS_FLAG_CLIENT); 885274939Smav isns_req_add_str(req, 32, TAILQ_FIRST(&conf->conf_targets)->t_name); 886274939Smav isns_req_add_delim(req); 887274939Smav isns_req_add_str(req, 1, hostname); 888274939Smav res = isns_req_send(s, req); 889274939Smav if (res < 0) { 890274939Smav log_warn("send(2) failed for %s", isns->i_addr); 891274939Smav goto quit; 892274939Smav } 893274939Smav res = isns_req_receive(s, req); 894274939Smav if (res < 0) { 895274939Smav log_warn("receive(2) failed for %s", isns->i_addr); 896274939Smav goto quit; 897274939Smav } 898274939Smav error = isns_req_get_status(req); 899274939Smav if (error != 0) { 900274939Smav log_warnx("iSNS deregister error %d for %s", error, isns->i_addr); 901274939Smav res = -1; 902274939Smav } 903274939Smavquit: 904274939Smav isns_req_free(req); 905274939Smav return (res); 906274939Smav} 907274939Smav 908274939Smavvoid 909274939Smavisns_register(struct isns *isns, struct isns *oldisns) 910274939Smav{ 911274939Smav struct conf *conf = isns->i_conf; 912274939Smav int s, res; 913274939Smav char hostname[256]; 914274939Smav 915274939Smav if (TAILQ_EMPTY(&conf->conf_targets) || 916274939Smav TAILQ_EMPTY(&conf->conf_portal_groups)) 917274939Smav return; 918274939Smav set_timeout(conf->conf_isns_timeout, false); 919274939Smav s = isns_do_connect(isns); 920274939Smav if (s < 0) { 921274939Smav set_timeout(0, false); 922274939Smav return; 923274939Smav } 924274939Smav gethostname(hostname, sizeof(hostname)); 925274939Smav 926274939Smav if (oldisns == NULL || TAILQ_EMPTY(&oldisns->i_conf->conf_targets)) 927274939Smav oldisns = isns; 928274939Smav res = isns_do_deregister(oldisns, s, hostname); 929274939Smav res = isns_do_register(isns, s, hostname); 930274939Smav close(s); 931274939Smav set_timeout(0, false); 932274939Smav} 933274939Smav 934274939Smavvoid 935274939Smavisns_check(struct isns *isns) 936274939Smav{ 937274939Smav struct conf *conf = isns->i_conf; 938274939Smav int s, res; 939274939Smav char hostname[256]; 940274939Smav 941274939Smav if (TAILQ_EMPTY(&conf->conf_targets) || 942274939Smav TAILQ_EMPTY(&conf->conf_portal_groups)) 943274939Smav return; 944274939Smav set_timeout(conf->conf_isns_timeout, false); 945274939Smav s = isns_do_connect(isns); 946274939Smav if (s < 0) { 947274939Smav set_timeout(0, false); 948274939Smav return; 949274939Smav } 950274939Smav gethostname(hostname, sizeof(hostname)); 951274939Smav 952274939Smav res = isns_do_check(isns, s, hostname); 953274939Smav if (res < 0) { 954274939Smav res = isns_do_deregister(isns, s, hostname); 955274939Smav res = isns_do_register(isns, s, hostname); 956274939Smav } 957274939Smav close(s); 958274939Smav set_timeout(0, false); 959274939Smav} 960274939Smav 961274939Smavvoid 962274939Smavisns_deregister(struct isns *isns) 963274939Smav{ 964274939Smav struct conf *conf = isns->i_conf; 965274939Smav int s, res; 966274939Smav char hostname[256]; 967274939Smav 968274939Smav if (TAILQ_EMPTY(&conf->conf_targets) || 969274939Smav TAILQ_EMPTY(&conf->conf_portal_groups)) 970274939Smav return; 971274939Smav set_timeout(conf->conf_isns_timeout, false); 972274939Smav s = isns_do_connect(isns); 973274939Smav if (s < 0) 974274939Smav return; 975274939Smav gethostname(hostname, sizeof(hostname)); 976274939Smav 977274939Smav res = isns_do_deregister(isns, s, hostname); 978274939Smav close(s); 979274939Smav set_timeout(0, false); 980274939Smav} 981274939Smav 982255570Straszstatic bool 983255570Straszvalid_hex(const char ch) 984255570Strasz{ 985255570Strasz switch (ch) { 986255570Strasz case '0': 987255570Strasz case '1': 988255570Strasz case '2': 989255570Strasz case '3': 990255570Strasz case '4': 991255570Strasz case '5': 992255570Strasz case '6': 993255570Strasz case '7': 994255570Strasz case '8': 995255570Strasz case '9': 996255570Strasz case 'a': 997255570Strasz case 'A': 998255570Strasz case 'b': 999255570Strasz case 'B': 1000255570Strasz case 'c': 1001255570Strasz case 'C': 1002255570Strasz case 'd': 1003255570Strasz case 'D': 1004255570Strasz case 'e': 1005255570Strasz case 'E': 1006255570Strasz case 'f': 1007255570Strasz case 'F': 1008255570Strasz return (true); 1009255570Strasz default: 1010255570Strasz return (false); 1011255570Strasz } 1012255570Strasz} 1013255570Strasz 1014255570Straszbool 1015255570Straszvalid_iscsi_name(const char *name) 1016255570Strasz{ 1017255570Strasz int i; 1018255570Strasz 1019255570Strasz if (strlen(name) >= MAX_NAME_LEN) { 1020255570Strasz log_warnx("overlong name for target \"%s\"; max length allowed " 1021255570Strasz "by iSCSI specification is %d characters", 1022255570Strasz name, MAX_NAME_LEN); 1023255570Strasz return (false); 1024255570Strasz } 1025255570Strasz 1026255570Strasz /* 1027255570Strasz * In the cases below, we don't return an error, just in case the admin 1028255570Strasz * was right, and we're wrong. 1029255570Strasz */ 1030255570Strasz if (strncasecmp(name, "iqn.", strlen("iqn.")) == 0) { 1031255570Strasz for (i = strlen("iqn."); name[i] != '\0'; i++) { 1032255570Strasz /* 1033255570Strasz * XXX: We should verify UTF-8 normalisation, as defined 1034274870Strasz * by 3.2.6.2: iSCSI Name Encoding. 1035255570Strasz */ 1036255570Strasz if (isalnum(name[i])) 1037255570Strasz continue; 1038255570Strasz if (name[i] == '-' || name[i] == '.' || name[i] == ':') 1039255570Strasz continue; 1040255570Strasz log_warnx("invalid character \"%c\" in target name " 1041255570Strasz "\"%s\"; allowed characters are letters, digits, " 1042255570Strasz "'-', '.', and ':'", name[i], name); 1043255570Strasz break; 1044255570Strasz } 1045255570Strasz /* 1046255570Strasz * XXX: Check more stuff: valid date and a valid reversed domain. 1047255570Strasz */ 1048255570Strasz } else if (strncasecmp(name, "eui.", strlen("eui.")) == 0) { 1049255570Strasz if (strlen(name) != strlen("eui.") + 16) 1050255570Strasz log_warnx("invalid target name \"%s\"; the \"eui.\" " 1051255570Strasz "should be followed by exactly 16 hexadecimal " 1052255570Strasz "digits", name); 1053255570Strasz for (i = strlen("eui."); name[i] != '\0'; i++) { 1054255570Strasz if (!valid_hex(name[i])) { 1055255570Strasz log_warnx("invalid character \"%c\" in target " 1056255570Strasz "name \"%s\"; allowed characters are 1-9 " 1057255570Strasz "and A-F", name[i], name); 1058255570Strasz break; 1059255570Strasz } 1060255570Strasz } 1061255570Strasz } else if (strncasecmp(name, "naa.", strlen("naa.")) == 0) { 1062255570Strasz if (strlen(name) > strlen("naa.") + 32) 1063255570Strasz log_warnx("invalid target name \"%s\"; the \"naa.\" " 1064255570Strasz "should be followed by at most 32 hexadecimal " 1065255570Strasz "digits", name); 1066255570Strasz for (i = strlen("naa."); name[i] != '\0'; i++) { 1067255570Strasz if (!valid_hex(name[i])) { 1068255570Strasz log_warnx("invalid character \"%c\" in target " 1069255570Strasz "name \"%s\"; allowed characters are 1-9 " 1070255570Strasz "and A-F", name[i], name); 1071255570Strasz break; 1072255570Strasz } 1073255570Strasz } 1074255570Strasz } else { 1075255570Strasz log_warnx("invalid target name \"%s\"; should start with " 1076255570Strasz "either \".iqn\", \"eui.\", or \"naa.\"", 1077255570Strasz name); 1078255570Strasz } 1079255570Strasz return (true); 1080255570Strasz} 1081255570Strasz 1082255570Straszstruct target * 1083263723Strasztarget_new(struct conf *conf, const char *name) 1084255570Strasz{ 1085255570Strasz struct target *targ; 1086255570Strasz int i, len; 1087255570Strasz 1088263723Strasz targ = target_find(conf, name); 1089255570Strasz if (targ != NULL) { 1090263723Strasz log_warnx("duplicated target \"%s\"", name); 1091255570Strasz return (NULL); 1092255570Strasz } 1093263723Strasz if (valid_iscsi_name(name) == false) { 1094263723Strasz log_warnx("target name \"%s\" is invalid", name); 1095255570Strasz return (NULL); 1096255570Strasz } 1097255570Strasz targ = calloc(1, sizeof(*targ)); 1098255570Strasz if (targ == NULL) 1099255570Strasz log_err(1, "calloc"); 1100263723Strasz targ->t_name = checked_strdup(name); 1101255570Strasz 1102255570Strasz /* 1103255570Strasz * RFC 3722 requires us to normalize the name to lowercase. 1104255570Strasz */ 1105263723Strasz len = strlen(name); 1106255570Strasz for (i = 0; i < len; i++) 1107263723Strasz targ->t_name[i] = tolower(targ->t_name[i]); 1108255570Strasz 1109255570Strasz TAILQ_INIT(&targ->t_luns); 1110255570Strasz targ->t_conf = conf; 1111255570Strasz TAILQ_INSERT_TAIL(&conf->conf_targets, targ, t_next); 1112255570Strasz 1113255570Strasz return (targ); 1114255570Strasz} 1115255570Strasz 1116255570Straszvoid 1117255570Strasztarget_delete(struct target *targ) 1118255570Strasz{ 1119255570Strasz struct lun *lun, *tmp; 1120255570Strasz 1121255570Strasz TAILQ_REMOVE(&targ->t_conf->conf_targets, targ, t_next); 1122255570Strasz 1123255570Strasz TAILQ_FOREACH_SAFE(lun, &targ->t_luns, l_next, tmp) 1124255570Strasz lun_delete(lun); 1125263723Strasz free(targ->t_name); 1126255570Strasz free(targ); 1127255570Strasz} 1128255570Strasz 1129255570Straszstruct target * 1130263723Strasztarget_find(struct conf *conf, const char *name) 1131255570Strasz{ 1132255570Strasz struct target *targ; 1133255570Strasz 1134255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 1135263723Strasz if (strcasecmp(targ->t_name, name) == 0) 1136255570Strasz return (targ); 1137255570Strasz } 1138255570Strasz 1139255570Strasz return (NULL); 1140255570Strasz} 1141255570Strasz 1142255570Straszstruct lun * 1143255570Straszlun_new(struct target *targ, int lun_id) 1144255570Strasz{ 1145255570Strasz struct lun *lun; 1146255570Strasz 1147255570Strasz lun = lun_find(targ, lun_id); 1148255570Strasz if (lun != NULL) { 1149255570Strasz log_warnx("duplicated lun %d for target \"%s\"", 1150263723Strasz lun_id, targ->t_name); 1151255570Strasz return (NULL); 1152255570Strasz } 1153255570Strasz 1154255570Strasz lun = calloc(1, sizeof(*lun)); 1155255570Strasz if (lun == NULL) 1156255570Strasz log_err(1, "calloc"); 1157255570Strasz lun->l_lun = lun_id; 1158255570Strasz TAILQ_INIT(&lun->l_options); 1159255570Strasz lun->l_target = targ; 1160255570Strasz TAILQ_INSERT_TAIL(&targ->t_luns, lun, l_next); 1161255570Strasz 1162255570Strasz return (lun); 1163255570Strasz} 1164255570Strasz 1165255570Straszvoid 1166255570Straszlun_delete(struct lun *lun) 1167255570Strasz{ 1168255570Strasz struct lun_option *lo, *tmp; 1169255570Strasz 1170255570Strasz TAILQ_REMOVE(&lun->l_target->t_luns, lun, l_next); 1171255570Strasz 1172255570Strasz TAILQ_FOREACH_SAFE(lo, &lun->l_options, lo_next, tmp) 1173255570Strasz lun_option_delete(lo); 1174255570Strasz free(lun->l_backend); 1175255570Strasz free(lun->l_device_id); 1176255570Strasz free(lun->l_path); 1177255570Strasz free(lun->l_serial); 1178255570Strasz free(lun); 1179255570Strasz} 1180255570Strasz 1181255570Straszstruct lun * 1182265514Straszlun_find(const struct target *targ, int lun_id) 1183255570Strasz{ 1184255570Strasz struct lun *lun; 1185255570Strasz 1186255570Strasz TAILQ_FOREACH(lun, &targ->t_luns, l_next) { 1187255570Strasz if (lun->l_lun == lun_id) 1188255570Strasz return (lun); 1189255570Strasz } 1190255570Strasz 1191255570Strasz return (NULL); 1192255570Strasz} 1193255570Strasz 1194255570Straszvoid 1195255570Straszlun_set_backend(struct lun *lun, const char *value) 1196255570Strasz{ 1197255570Strasz free(lun->l_backend); 1198255570Strasz lun->l_backend = checked_strdup(value); 1199255570Strasz} 1200255570Strasz 1201255570Straszvoid 1202255570Straszlun_set_blocksize(struct lun *lun, size_t value) 1203255570Strasz{ 1204255570Strasz 1205255570Strasz lun->l_blocksize = value; 1206255570Strasz} 1207255570Strasz 1208255570Straszvoid 1209255570Straszlun_set_device_id(struct lun *lun, const char *value) 1210255570Strasz{ 1211255570Strasz free(lun->l_device_id); 1212255570Strasz lun->l_device_id = checked_strdup(value); 1213255570Strasz} 1214255570Strasz 1215255570Straszvoid 1216255570Straszlun_set_path(struct lun *lun, const char *value) 1217255570Strasz{ 1218255570Strasz free(lun->l_path); 1219255570Strasz lun->l_path = checked_strdup(value); 1220255570Strasz} 1221255570Strasz 1222255570Straszvoid 1223255570Straszlun_set_serial(struct lun *lun, const char *value) 1224255570Strasz{ 1225255570Strasz free(lun->l_serial); 1226255570Strasz lun->l_serial = checked_strdup(value); 1227255570Strasz} 1228255570Strasz 1229255570Straszvoid 1230255570Straszlun_set_size(struct lun *lun, size_t value) 1231255570Strasz{ 1232255570Strasz 1233255570Strasz lun->l_size = value; 1234255570Strasz} 1235255570Strasz 1236255570Straszvoid 1237255570Straszlun_set_ctl_lun(struct lun *lun, uint32_t value) 1238255570Strasz{ 1239255570Strasz 1240255570Strasz lun->l_ctl_lun = value; 1241255570Strasz} 1242255570Strasz 1243255570Straszstruct lun_option * 1244255570Straszlun_option_new(struct lun *lun, const char *name, const char *value) 1245255570Strasz{ 1246255570Strasz struct lun_option *lo; 1247255570Strasz 1248255570Strasz lo = lun_option_find(lun, name); 1249255570Strasz if (lo != NULL) { 1250255570Strasz log_warnx("duplicated lun option %s for lun %d, target \"%s\"", 1251263723Strasz name, lun->l_lun, lun->l_target->t_name); 1252255570Strasz return (NULL); 1253255570Strasz } 1254255570Strasz 1255255570Strasz lo = calloc(1, sizeof(*lo)); 1256255570Strasz if (lo == NULL) 1257255570Strasz log_err(1, "calloc"); 1258255570Strasz lo->lo_name = checked_strdup(name); 1259255570Strasz lo->lo_value = checked_strdup(value); 1260255570Strasz lo->lo_lun = lun; 1261255570Strasz TAILQ_INSERT_TAIL(&lun->l_options, lo, lo_next); 1262255570Strasz 1263255570Strasz return (lo); 1264255570Strasz} 1265255570Strasz 1266255570Straszvoid 1267255570Straszlun_option_delete(struct lun_option *lo) 1268255570Strasz{ 1269255570Strasz 1270255570Strasz TAILQ_REMOVE(&lo->lo_lun->l_options, lo, lo_next); 1271255570Strasz 1272255570Strasz free(lo->lo_name); 1273255570Strasz free(lo->lo_value); 1274255570Strasz free(lo); 1275255570Strasz} 1276255570Strasz 1277255570Straszstruct lun_option * 1278265514Straszlun_option_find(const struct lun *lun, const char *name) 1279255570Strasz{ 1280255570Strasz struct lun_option *lo; 1281255570Strasz 1282255570Strasz TAILQ_FOREACH(lo, &lun->l_options, lo_next) { 1283255570Strasz if (strcmp(lo->lo_name, name) == 0) 1284255570Strasz return (lo); 1285255570Strasz } 1286255570Strasz 1287255570Strasz return (NULL); 1288255570Strasz} 1289255570Strasz 1290255570Straszvoid 1291255570Straszlun_option_set(struct lun_option *lo, const char *value) 1292255570Strasz{ 1293255570Strasz 1294255570Strasz free(lo->lo_value); 1295255570Strasz lo->lo_value = checked_strdup(value); 1296255570Strasz} 1297255570Strasz 1298255570Straszstatic struct connection * 1299270137Smavconnection_new(struct portal *portal, int fd, const char *host, 1300270137Smav const struct sockaddr *client_sa) 1301255570Strasz{ 1302255570Strasz struct connection *conn; 1303255570Strasz 1304255570Strasz conn = calloc(1, sizeof(*conn)); 1305255570Strasz if (conn == NULL) 1306255570Strasz log_err(1, "calloc"); 1307255570Strasz conn->conn_portal = portal; 1308255570Strasz conn->conn_socket = fd; 1309255570Strasz conn->conn_initiator_addr = checked_strdup(host); 1310270137Smav memcpy(&conn->conn_initiator_sa, client_sa, client_sa->sa_len); 1311255570Strasz 1312255570Strasz /* 1313255570Strasz * Default values, from RFC 3720, section 12. 1314255570Strasz */ 1315255570Strasz conn->conn_max_data_segment_length = 8192; 1316255570Strasz conn->conn_max_burst_length = 262144; 1317255570Strasz conn->conn_immediate_data = true; 1318255570Strasz 1319255570Strasz return (conn); 1320255570Strasz} 1321255570Strasz 1322255570Strasz#if 0 1323255570Straszstatic void 1324255570Straszconf_print(struct conf *conf) 1325255570Strasz{ 1326255570Strasz struct auth_group *ag; 1327255570Strasz struct auth *auth; 1328263720Strasz struct auth_name *auth_name; 1329263720Strasz struct auth_portal *auth_portal; 1330255570Strasz struct portal_group *pg; 1331255570Strasz struct portal *portal; 1332255570Strasz struct target *targ; 1333255570Strasz struct lun *lun; 1334255570Strasz struct lun_option *lo; 1335255570Strasz 1336255570Strasz TAILQ_FOREACH(ag, &conf->conf_auth_groups, ag_next) { 1337255570Strasz fprintf(stderr, "auth-group %s {\n", ag->ag_name); 1338255570Strasz TAILQ_FOREACH(auth, &ag->ag_auths, a_next) 1339255570Strasz fprintf(stderr, "\t chap-mutual %s %s %s %s\n", 1340255570Strasz auth->a_user, auth->a_secret, 1341255570Strasz auth->a_mutual_user, auth->a_mutual_secret); 1342263720Strasz TAILQ_FOREACH(auth_name, &ag->ag_names, an_next) 1343263720Strasz fprintf(stderr, "\t initiator-name %s\n", 1344263720Strasz auth_name->an_initator_name); 1345263720Strasz TAILQ_FOREACH(auth_portal, &ag->ag_portals, an_next) 1346263720Strasz fprintf(stderr, "\t initiator-portal %s\n", 1347263720Strasz auth_portal->an_initator_portal); 1348255570Strasz fprintf(stderr, "}\n"); 1349255570Strasz } 1350255570Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 1351255570Strasz fprintf(stderr, "portal-group %s {\n", pg->pg_name); 1352255570Strasz TAILQ_FOREACH(portal, &pg->pg_portals, p_next) 1353255570Strasz fprintf(stderr, "\t listen %s\n", portal->p_listen); 1354255570Strasz fprintf(stderr, "}\n"); 1355255570Strasz } 1356255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 1357263723Strasz fprintf(stderr, "target %s {\n", targ->t_name); 1358255570Strasz if (targ->t_alias != NULL) 1359255570Strasz fprintf(stderr, "\t alias %s\n", targ->t_alias); 1360255570Strasz TAILQ_FOREACH(lun, &targ->t_luns, l_next) { 1361255570Strasz fprintf(stderr, "\tlun %d {\n", lun->l_lun); 1362255570Strasz fprintf(stderr, "\t\tpath %s\n", lun->l_path); 1363255570Strasz TAILQ_FOREACH(lo, &lun->l_options, lo_next) 1364255570Strasz fprintf(stderr, "\t\toption %s %s\n", 1365255570Strasz lo->lo_name, lo->lo_value); 1366255570Strasz fprintf(stderr, "\t}\n"); 1367255570Strasz } 1368255570Strasz fprintf(stderr, "}\n"); 1369255570Strasz } 1370255570Strasz} 1371255570Strasz#endif 1372255570Strasz 1373263717Straszstatic int 1374263717Straszconf_verify_lun(struct lun *lun) 1375263717Strasz{ 1376263717Strasz const struct lun *lun2; 1377263718Strasz const struct target *targ2; 1378263717Strasz 1379263717Strasz if (lun->l_backend == NULL) 1380263717Strasz lun_set_backend(lun, "block"); 1381263717Strasz if (strcmp(lun->l_backend, "block") == 0) { 1382263717Strasz if (lun->l_path == NULL) { 1383263717Strasz log_warnx("missing path for lun %d, target \"%s\"", 1384263723Strasz lun->l_lun, lun->l_target->t_name); 1385263717Strasz return (1); 1386263717Strasz } 1387263717Strasz } else if (strcmp(lun->l_backend, "ramdisk") == 0) { 1388263717Strasz if (lun->l_size == 0) { 1389263717Strasz log_warnx("missing size for ramdisk-backed lun %d, " 1390263723Strasz "target \"%s\"", lun->l_lun, lun->l_target->t_name); 1391263717Strasz return (1); 1392263717Strasz } 1393263717Strasz if (lun->l_path != NULL) { 1394263717Strasz log_warnx("path must not be specified " 1395263717Strasz "for ramdisk-backed lun %d, target \"%s\"", 1396263723Strasz lun->l_lun, lun->l_target->t_name); 1397263717Strasz return (1); 1398263717Strasz } 1399263717Strasz } 1400263717Strasz if (lun->l_lun < 0 || lun->l_lun > 255) { 1401263717Strasz log_warnx("invalid lun number for lun %d, target \"%s\"; " 1402263717Strasz "must be between 0 and 255", lun->l_lun, 1403263723Strasz lun->l_target->t_name); 1404263717Strasz return (1); 1405263717Strasz } 1406263717Strasz if (lun->l_blocksize == 0) { 1407263717Strasz lun_set_blocksize(lun, DEFAULT_BLOCKSIZE); 1408263717Strasz } else if (lun->l_blocksize < 0) { 1409263717Strasz log_warnx("invalid blocksize for lun %d, target \"%s\"; " 1410263723Strasz "must be larger than 0", lun->l_lun, lun->l_target->t_name); 1411263717Strasz return (1); 1412263717Strasz } 1413263717Strasz if (lun->l_size != 0 && lun->l_size % lun->l_blocksize != 0) { 1414263717Strasz log_warnx("invalid size for lun %d, target \"%s\"; " 1415263717Strasz "must be multiple of blocksize", lun->l_lun, 1416263723Strasz lun->l_target->t_name); 1417263717Strasz return (1); 1418263717Strasz } 1419263718Strasz TAILQ_FOREACH(targ2, &lun->l_target->t_conf->conf_targets, t_next) { 1420263718Strasz TAILQ_FOREACH(lun2, &targ2->t_luns, l_next) { 1421263718Strasz if (lun == lun2) 1422263718Strasz continue; 1423263718Strasz if (lun->l_path != NULL && lun2->l_path != NULL && 1424263718Strasz strcmp(lun->l_path, lun2->l_path) == 0) { 1425263718Strasz log_debugx("WARNING: path \"%s\" duplicated " 1426263718Strasz "between lun %d, target \"%s\", and " 1427263718Strasz "lun %d, target \"%s\"", lun->l_path, 1428263723Strasz lun->l_lun, lun->l_target->t_name, 1429263723Strasz lun2->l_lun, lun2->l_target->t_name); 1430263718Strasz } 1431263718Strasz } 1432263718Strasz } 1433263717Strasz 1434263717Strasz return (0); 1435263717Strasz} 1436263717Strasz 1437255570Straszint 1438255570Straszconf_verify(struct conf *conf) 1439255570Strasz{ 1440255570Strasz struct auth_group *ag; 1441255570Strasz struct portal_group *pg; 1442255570Strasz struct target *targ; 1443263717Strasz struct lun *lun; 1444274871Strasz bool found; 1445263717Strasz int error; 1446255570Strasz 1447255570Strasz if (conf->conf_pidfile_path == NULL) 1448255570Strasz conf->conf_pidfile_path = checked_strdup(DEFAULT_PIDFILE); 1449255570Strasz 1450255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 1451255570Strasz if (targ->t_auth_group == NULL) { 1452263726Strasz targ->t_auth_group = auth_group_find(conf, 1453263726Strasz "default"); 1454263726Strasz assert(targ->t_auth_group != NULL); 1455255570Strasz } 1456255570Strasz if (targ->t_portal_group == NULL) { 1457255570Strasz targ->t_portal_group = portal_group_find(conf, 1458255570Strasz "default"); 1459255570Strasz assert(targ->t_portal_group != NULL); 1460255570Strasz } 1461274871Strasz found = false; 1462255570Strasz TAILQ_FOREACH(lun, &targ->t_luns, l_next) { 1463263717Strasz error = conf_verify_lun(lun); 1464263717Strasz if (error != 0) 1465263717Strasz return (error); 1466274871Strasz found = true; 1467255570Strasz } 1468274871Strasz if (!found) { 1469265506Strasz log_warnx("no LUNs defined for target \"%s\"", 1470265506Strasz targ->t_name); 1471255570Strasz } 1472255570Strasz } 1473255570Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 1474255570Strasz assert(pg->pg_name != NULL); 1475255570Strasz if (pg->pg_discovery_auth_group == NULL) { 1476255570Strasz pg->pg_discovery_auth_group = 1477263728Strasz auth_group_find(conf, "default"); 1478255570Strasz assert(pg->pg_discovery_auth_group != NULL); 1479255570Strasz } 1480255570Strasz 1481255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 1482255570Strasz if (targ->t_portal_group == pg) 1483255570Strasz break; 1484255570Strasz } 1485255570Strasz if (targ == NULL) { 1486255570Strasz if (strcmp(pg->pg_name, "default") != 0) 1487255570Strasz log_warnx("portal-group \"%s\" not assigned " 1488255570Strasz "to any target", pg->pg_name); 1489255570Strasz pg->pg_unassigned = true; 1490255570Strasz } else 1491255570Strasz pg->pg_unassigned = false; 1492255570Strasz } 1493255570Strasz TAILQ_FOREACH(ag, &conf->conf_auth_groups, ag_next) { 1494255570Strasz if (ag->ag_name == NULL) 1495255570Strasz assert(ag->ag_target != NULL); 1496255570Strasz else 1497255570Strasz assert(ag->ag_target == NULL); 1498255570Strasz 1499274871Strasz found = false; 1500255570Strasz TAILQ_FOREACH(targ, &conf->conf_targets, t_next) { 1501274871Strasz if (targ->t_auth_group == ag) { 1502274871Strasz found = true; 1503255570Strasz break; 1504274871Strasz } 1505255570Strasz } 1506274871Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 1507274871Strasz if (pg->pg_discovery_auth_group == ag) { 1508274871Strasz found = true; 1509274871Strasz break; 1510274871Strasz } 1511274871Strasz } 1512274871Strasz if (!found && ag->ag_name != NULL && 1513263728Strasz strcmp(ag->ag_name, "default") != 0 && 1514255570Strasz strcmp(ag->ag_name, "no-authentication") != 0 && 1515255570Strasz strcmp(ag->ag_name, "no-access") != 0) { 1516255570Strasz log_warnx("auth-group \"%s\" not assigned " 1517255570Strasz "to any target", ag->ag_name); 1518255570Strasz } 1519255570Strasz } 1520255570Strasz 1521255570Strasz return (0); 1522255570Strasz} 1523255570Strasz 1524255570Straszstatic int 1525255570Straszconf_apply(struct conf *oldconf, struct conf *newconf) 1526255570Strasz{ 1527255570Strasz struct target *oldtarg, *newtarg, *tmptarg; 1528255570Strasz struct lun *oldlun, *newlun, *tmplun; 1529255570Strasz struct portal_group *oldpg, *newpg; 1530255570Strasz struct portal *oldp, *newp; 1531274939Smav struct isns *oldns, *newns; 1532255570Strasz pid_t otherpid; 1533255570Strasz int changed, cumulated_error = 0, error; 1534255570Strasz int one = 1; 1535255570Strasz 1536255570Strasz if (oldconf->conf_debug != newconf->conf_debug) { 1537255570Strasz log_debugx("changing debug level to %d", newconf->conf_debug); 1538255570Strasz log_init(newconf->conf_debug); 1539255570Strasz } 1540255570Strasz 1541255570Strasz if (oldconf->conf_pidfh != NULL) { 1542255570Strasz assert(oldconf->conf_pidfile_path != NULL); 1543255570Strasz if (newconf->conf_pidfile_path != NULL && 1544255570Strasz strcmp(oldconf->conf_pidfile_path, 1545255570Strasz newconf->conf_pidfile_path) == 0) { 1546255570Strasz newconf->conf_pidfh = oldconf->conf_pidfh; 1547255570Strasz oldconf->conf_pidfh = NULL; 1548255570Strasz } else { 1549255570Strasz log_debugx("removing pidfile %s", 1550255570Strasz oldconf->conf_pidfile_path); 1551255570Strasz pidfile_remove(oldconf->conf_pidfh); 1552255570Strasz oldconf->conf_pidfh = NULL; 1553255570Strasz } 1554255570Strasz } 1555255570Strasz 1556255570Strasz if (newconf->conf_pidfh == NULL && newconf->conf_pidfile_path != NULL) { 1557255570Strasz log_debugx("opening pidfile %s", newconf->conf_pidfile_path); 1558255570Strasz newconf->conf_pidfh = 1559255570Strasz pidfile_open(newconf->conf_pidfile_path, 0600, &otherpid); 1560255570Strasz if (newconf->conf_pidfh == NULL) { 1561255570Strasz if (errno == EEXIST) 1562255570Strasz log_errx(1, "daemon already running, pid: %jd.", 1563255570Strasz (intmax_t)otherpid); 1564255570Strasz log_err(1, "cannot open or create pidfile \"%s\"", 1565255570Strasz newconf->conf_pidfile_path); 1566255570Strasz } 1567255570Strasz } 1568255570Strasz 1569274939Smav /* Deregister on removed iSNS servers. */ 1570274939Smav TAILQ_FOREACH(oldns, &oldconf->conf_isns, i_next) { 1571274939Smav TAILQ_FOREACH(newns, &newconf->conf_isns, i_next) { 1572274939Smav if (strcmp(oldns->i_addr, newns->i_addr) == 0) 1573274939Smav break; 1574274939Smav } 1575274939Smav if (newns == NULL) 1576274939Smav isns_deregister(oldns); 1577274939Smav } 1578274939Smav 1579265518Strasz /* 1580265518Strasz * XXX: If target or lun removal fails, we should somehow "move" 1581274870Strasz * the old lun or target into newconf, so that subsequent 1582274870Strasz * conf_apply() would try to remove them again. That would 1583274870Strasz * be somewhat hairy, though, and lun deletion failures don't 1584274870Strasz * really happen, so leave it as it is for now. 1585265518Strasz */ 1586255570Strasz TAILQ_FOREACH_SAFE(oldtarg, &oldconf->conf_targets, t_next, tmptarg) { 1587255570Strasz /* 1588255570Strasz * First, remove any targets present in the old configuration 1589255570Strasz * and missing in the new one. 1590255570Strasz */ 1591263723Strasz newtarg = target_find(newconf, oldtarg->t_name); 1592255570Strasz if (newtarg == NULL) { 1593255570Strasz TAILQ_FOREACH_SAFE(oldlun, &oldtarg->t_luns, l_next, 1594255570Strasz tmplun) { 1595263716Strasz log_debugx("target %s not found in new " 1596263716Strasz "configuration; removing its lun %d, " 1597255570Strasz "backed by CTL lun %d", 1598263723Strasz oldtarg->t_name, oldlun->l_lun, 1599255570Strasz oldlun->l_ctl_lun); 1600255570Strasz error = kernel_lun_remove(oldlun); 1601255570Strasz if (error != 0) { 1602255570Strasz log_warnx("failed to remove lun %d, " 1603255570Strasz "target %s, CTL lun %d", 1604263723Strasz oldlun->l_lun, oldtarg->t_name, 1605255570Strasz oldlun->l_ctl_lun); 1606255570Strasz cumulated_error++; 1607255570Strasz } 1608255570Strasz } 1609268682Smav kernel_port_remove(oldtarg); 1610255570Strasz continue; 1611255570Strasz } 1612255570Strasz 1613255570Strasz /* 1614255570Strasz * Second, remove any LUNs present in the old target 1615255570Strasz * and missing in the new one. 1616255570Strasz */ 1617255570Strasz TAILQ_FOREACH_SAFE(oldlun, &oldtarg->t_luns, l_next, tmplun) { 1618255570Strasz newlun = lun_find(newtarg, oldlun->l_lun); 1619255570Strasz if (newlun == NULL) { 1620255570Strasz log_debugx("lun %d, target %s, CTL lun %d " 1621263716Strasz "not found in new configuration; " 1622263723Strasz "removing", oldlun->l_lun, oldtarg->t_name, 1623255570Strasz oldlun->l_ctl_lun); 1624255570Strasz error = kernel_lun_remove(oldlun); 1625255570Strasz if (error != 0) { 1626255570Strasz log_warnx("failed to remove lun %d, " 1627255570Strasz "target %s, CTL lun %d", 1628263723Strasz oldlun->l_lun, oldtarg->t_name, 1629255570Strasz oldlun->l_ctl_lun); 1630255570Strasz cumulated_error++; 1631255570Strasz } 1632255570Strasz continue; 1633255570Strasz } 1634255570Strasz 1635255570Strasz /* 1636255570Strasz * Also remove the LUNs changed by more than size. 1637255570Strasz */ 1638255570Strasz changed = 0; 1639255570Strasz assert(oldlun->l_backend != NULL); 1640255570Strasz assert(newlun->l_backend != NULL); 1641255570Strasz if (strcmp(newlun->l_backend, oldlun->l_backend) != 0) { 1642255570Strasz log_debugx("backend for lun %d, target %s, " 1643255570Strasz "CTL lun %d changed; removing", 1644263723Strasz oldlun->l_lun, oldtarg->t_name, 1645255570Strasz oldlun->l_ctl_lun); 1646255570Strasz changed = 1; 1647255570Strasz } 1648255570Strasz if (oldlun->l_blocksize != newlun->l_blocksize) { 1649255570Strasz log_debugx("blocksize for lun %d, target %s, " 1650255570Strasz "CTL lun %d changed; removing", 1651263723Strasz oldlun->l_lun, oldtarg->t_name, 1652255570Strasz oldlun->l_ctl_lun); 1653255570Strasz changed = 1; 1654255570Strasz } 1655255570Strasz if (newlun->l_device_id != NULL && 1656255570Strasz (oldlun->l_device_id == NULL || 1657255570Strasz strcmp(oldlun->l_device_id, newlun->l_device_id) != 1658255570Strasz 0)) { 1659255570Strasz log_debugx("device-id for lun %d, target %s, " 1660255570Strasz "CTL lun %d changed; removing", 1661263723Strasz oldlun->l_lun, oldtarg->t_name, 1662255570Strasz oldlun->l_ctl_lun); 1663255570Strasz changed = 1; 1664255570Strasz } 1665255570Strasz if (newlun->l_path != NULL && 1666255570Strasz (oldlun->l_path == NULL || 1667255570Strasz strcmp(oldlun->l_path, newlun->l_path) != 0)) { 1668255570Strasz log_debugx("path for lun %d, target %s, " 1669255570Strasz "CTL lun %d, changed; removing", 1670263723Strasz oldlun->l_lun, oldtarg->t_name, 1671255570Strasz oldlun->l_ctl_lun); 1672255570Strasz changed = 1; 1673255570Strasz } 1674255570Strasz if (newlun->l_serial != NULL && 1675255570Strasz (oldlun->l_serial == NULL || 1676255570Strasz strcmp(oldlun->l_serial, newlun->l_serial) != 0)) { 1677255570Strasz log_debugx("serial for lun %d, target %s, " 1678255570Strasz "CTL lun %d changed; removing", 1679263723Strasz oldlun->l_lun, oldtarg->t_name, 1680255570Strasz oldlun->l_ctl_lun); 1681255570Strasz changed = 1; 1682255570Strasz } 1683255570Strasz if (changed) { 1684255570Strasz error = kernel_lun_remove(oldlun); 1685255570Strasz if (error != 0) { 1686255570Strasz log_warnx("failed to remove lun %d, " 1687255570Strasz "target %s, CTL lun %d", 1688263723Strasz oldlun->l_lun, oldtarg->t_name, 1689255570Strasz oldlun->l_ctl_lun); 1690255570Strasz cumulated_error++; 1691255570Strasz } 1692255570Strasz lun_delete(oldlun); 1693255570Strasz continue; 1694255570Strasz } 1695255570Strasz 1696255570Strasz lun_set_ctl_lun(newlun, oldlun->l_ctl_lun); 1697255570Strasz } 1698255570Strasz } 1699255570Strasz 1700255570Strasz /* 1701255570Strasz * Now add new targets or modify existing ones. 1702255570Strasz */ 1703255570Strasz TAILQ_FOREACH(newtarg, &newconf->conf_targets, t_next) { 1704263723Strasz oldtarg = target_find(oldconf, newtarg->t_name); 1705255570Strasz 1706265518Strasz TAILQ_FOREACH_SAFE(newlun, &newtarg->t_luns, l_next, tmplun) { 1707255570Strasz if (oldtarg != NULL) { 1708255570Strasz oldlun = lun_find(oldtarg, newlun->l_lun); 1709255570Strasz if (oldlun != NULL) { 1710271929Smav if (newlun->l_size != oldlun->l_size || 1711271929Smav newlun->l_size == 0) { 1712255570Strasz log_debugx("resizing lun %d, " 1713255570Strasz "target %s, CTL lun %d", 1714255570Strasz newlun->l_lun, 1715263723Strasz newtarg->t_name, 1716255570Strasz newlun->l_ctl_lun); 1717255570Strasz error = 1718255570Strasz kernel_lun_resize(newlun); 1719255570Strasz if (error != 0) { 1720255570Strasz log_warnx("failed to " 1721255570Strasz "resize lun %d, " 1722255570Strasz "target %s, " 1723255570Strasz "CTL lun %d", 1724255570Strasz newlun->l_lun, 1725263723Strasz newtarg->t_name, 1726255570Strasz newlun->l_lun); 1727255570Strasz cumulated_error++; 1728255570Strasz } 1729255570Strasz } 1730255570Strasz continue; 1731255570Strasz } 1732255570Strasz } 1733255570Strasz log_debugx("adding lun %d, target %s", 1734263723Strasz newlun->l_lun, newtarg->t_name); 1735255570Strasz error = kernel_lun_add(newlun); 1736255570Strasz if (error != 0) { 1737255570Strasz log_warnx("failed to add lun %d, target %s", 1738263723Strasz newlun->l_lun, newtarg->t_name); 1739265518Strasz lun_delete(newlun); 1740255570Strasz cumulated_error++; 1741255570Strasz } 1742255570Strasz } 1743268682Smav if (oldtarg == NULL) 1744268682Smav kernel_port_add(newtarg); 1745255570Strasz } 1746255570Strasz 1747255570Strasz /* 1748255570Strasz * Go through the new portals, opening the sockets as neccessary. 1749255570Strasz */ 1750255570Strasz TAILQ_FOREACH(newpg, &newconf->conf_portal_groups, pg_next) { 1751255570Strasz if (newpg->pg_unassigned) { 1752255570Strasz log_debugx("not listening on portal-group \"%s\", " 1753255570Strasz "not assigned to any target", 1754255570Strasz newpg->pg_name); 1755255570Strasz continue; 1756255570Strasz } 1757255570Strasz TAILQ_FOREACH(newp, &newpg->pg_portals, p_next) { 1758255570Strasz /* 1759255570Strasz * Try to find already open portal and reuse 1760255570Strasz * the listening socket. We don't care about 1761255570Strasz * what portal or portal group that was, what 1762255570Strasz * matters is the listening address. 1763255570Strasz */ 1764255570Strasz TAILQ_FOREACH(oldpg, &oldconf->conf_portal_groups, 1765255570Strasz pg_next) { 1766255570Strasz TAILQ_FOREACH(oldp, &oldpg->pg_portals, 1767255570Strasz p_next) { 1768255570Strasz if (strcmp(newp->p_listen, 1769255570Strasz oldp->p_listen) == 0 && 1770255570Strasz oldp->p_socket > 0) { 1771255570Strasz newp->p_socket = 1772255570Strasz oldp->p_socket; 1773255570Strasz oldp->p_socket = 0; 1774255570Strasz break; 1775255570Strasz } 1776255570Strasz } 1777255570Strasz } 1778255570Strasz if (newp->p_socket > 0) { 1779255570Strasz /* 1780255570Strasz * We're done with this portal. 1781255570Strasz */ 1782255570Strasz continue; 1783255570Strasz } 1784255570Strasz 1785255570Strasz#ifdef ICL_KERNEL_PROXY 1786265507Strasz if (proxy_mode) { 1787265509Strasz newpg->pg_conf->conf_portal_id++; 1788265509Strasz newp->p_id = newpg->pg_conf->conf_portal_id; 1789265509Strasz log_debugx("listening on %s, portal-group " 1790265509Strasz "\"%s\", portal id %d, using ICL proxy", 1791265509Strasz newp->p_listen, newpg->pg_name, newp->p_id); 1792265509Strasz kernel_listen(newp->p_ai, newp->p_iser, 1793265509Strasz newp->p_id); 1794265507Strasz continue; 1795265507Strasz } 1796265507Strasz#endif 1797265507Strasz assert(proxy_mode == false); 1798255570Strasz assert(newp->p_iser == false); 1799255570Strasz 1800255570Strasz log_debugx("listening on %s, portal-group \"%s\"", 1801255570Strasz newp->p_listen, newpg->pg_name); 1802255570Strasz newp->p_socket = socket(newp->p_ai->ai_family, 1803255570Strasz newp->p_ai->ai_socktype, 1804255570Strasz newp->p_ai->ai_protocol); 1805255570Strasz if (newp->p_socket < 0) { 1806255570Strasz log_warn("socket(2) failed for %s", 1807255570Strasz newp->p_listen); 1808255570Strasz cumulated_error++; 1809255570Strasz continue; 1810255570Strasz } 1811255570Strasz error = setsockopt(newp->p_socket, SOL_SOCKET, 1812255570Strasz SO_REUSEADDR, &one, sizeof(one)); 1813255570Strasz if (error != 0) { 1814255570Strasz log_warn("setsockopt(SO_REUSEADDR) failed " 1815255570Strasz "for %s", newp->p_listen); 1816255570Strasz close(newp->p_socket); 1817255570Strasz newp->p_socket = 0; 1818255570Strasz cumulated_error++; 1819255570Strasz continue; 1820255570Strasz } 1821255570Strasz error = bind(newp->p_socket, newp->p_ai->ai_addr, 1822255570Strasz newp->p_ai->ai_addrlen); 1823255570Strasz if (error != 0) { 1824255570Strasz log_warn("bind(2) failed for %s", 1825255570Strasz newp->p_listen); 1826255570Strasz close(newp->p_socket); 1827255570Strasz newp->p_socket = 0; 1828255570Strasz cumulated_error++; 1829255570Strasz continue; 1830255570Strasz } 1831255570Strasz error = listen(newp->p_socket, -1); 1832255570Strasz if (error != 0) { 1833255570Strasz log_warn("listen(2) failed for %s", 1834255570Strasz newp->p_listen); 1835255570Strasz close(newp->p_socket); 1836255570Strasz newp->p_socket = 0; 1837255570Strasz cumulated_error++; 1838255570Strasz continue; 1839255570Strasz } 1840255570Strasz } 1841255570Strasz } 1842255570Strasz 1843255570Strasz /* 1844255570Strasz * Go through the no longer used sockets, closing them. 1845255570Strasz */ 1846255570Strasz TAILQ_FOREACH(oldpg, &oldconf->conf_portal_groups, pg_next) { 1847255570Strasz TAILQ_FOREACH(oldp, &oldpg->pg_portals, p_next) { 1848255570Strasz if (oldp->p_socket <= 0) 1849255570Strasz continue; 1850255570Strasz log_debugx("closing socket for %s, portal-group \"%s\"", 1851255570Strasz oldp->p_listen, oldpg->pg_name); 1852255570Strasz close(oldp->p_socket); 1853255570Strasz oldp->p_socket = 0; 1854255570Strasz } 1855255570Strasz } 1856255570Strasz 1857274939Smav /* (Re-)Register on remaining/new iSNS servers. */ 1858274939Smav TAILQ_FOREACH(newns, &newconf->conf_isns, i_next) { 1859274939Smav TAILQ_FOREACH(oldns, &oldconf->conf_isns, i_next) { 1860274939Smav if (strcmp(oldns->i_addr, newns->i_addr) == 0) 1861274939Smav break; 1862274939Smav } 1863274939Smav isns_register(newns, oldns); 1864274939Smav } 1865274939Smav 1866274939Smav /* Schedule iSNS update */ 1867274939Smav if (!TAILQ_EMPTY(&newconf->conf_isns)) 1868274939Smav set_timeout((newconf->conf_isns_period + 2) / 3, false); 1869274939Smav 1870255570Strasz return (cumulated_error); 1871255570Strasz} 1872255570Strasz 1873255570Straszbool 1874255570Strasztimed_out(void) 1875255570Strasz{ 1876255570Strasz 1877255570Strasz return (sigalrm_received); 1878255570Strasz} 1879255570Strasz 1880255570Straszstatic void 1881274939Smavsigalrm_handler_fatal(int dummy __unused) 1882255570Strasz{ 1883255570Strasz /* 1884255570Strasz * It would be easiest to just log an error and exit. We can't 1885255570Strasz * do this, though, because log_errx() is not signal safe, since 1886255570Strasz * it calls syslog(3). Instead, set a flag checked by pdu_send() 1887255570Strasz * and pdu_receive(), to call log_errx() there. Should they fail 1888255570Strasz * to notice, we'll exit here one second later. 1889255570Strasz */ 1890255570Strasz if (sigalrm_received) { 1891255570Strasz /* 1892255570Strasz * Oh well. Just give up and quit. 1893255570Strasz */ 1894255570Strasz _exit(2); 1895255570Strasz } 1896255570Strasz 1897255570Strasz sigalrm_received = true; 1898255570Strasz} 1899255570Strasz 1900255570Straszstatic void 1901274939Smavsigalrm_handler(int dummy __unused) 1902255570Strasz{ 1903274939Smav 1904274939Smav sigalrm_received = true; 1905274939Smav} 1906274939Smav 1907274939Smavvoid 1908274939Smavset_timeout(int timeout, int fatal) 1909274939Smav{ 1910255570Strasz struct sigaction sa; 1911255570Strasz struct itimerval itv; 1912255570Strasz int error; 1913255570Strasz 1914274939Smav if (timeout <= 0) { 1915255570Strasz log_debugx("session timeout disabled"); 1916274939Smav bzero(&itv, sizeof(itv)); 1917274939Smav error = setitimer(ITIMER_REAL, &itv, NULL); 1918274939Smav if (error != 0) 1919274939Smav log_err(1, "setitimer"); 1920274939Smav sigalrm_received = false; 1921255570Strasz return; 1922255570Strasz } 1923255570Strasz 1924274939Smav sigalrm_received = false; 1925255570Strasz bzero(&sa, sizeof(sa)); 1926274939Smav if (fatal) 1927274939Smav sa.sa_handler = sigalrm_handler_fatal; 1928274939Smav else 1929274939Smav sa.sa_handler = sigalrm_handler; 1930255570Strasz sigfillset(&sa.sa_mask); 1931255570Strasz error = sigaction(SIGALRM, &sa, NULL); 1932255570Strasz if (error != 0) 1933255570Strasz log_err(1, "sigaction"); 1934255570Strasz 1935255570Strasz /* 1936255570Strasz * First SIGALRM will arive after conf_timeout seconds. 1937255570Strasz * If we do nothing, another one will arrive a second later. 1938255570Strasz */ 1939274939Smav log_debugx("setting session timeout to %d seconds", timeout); 1940255570Strasz bzero(&itv, sizeof(itv)); 1941255570Strasz itv.it_interval.tv_sec = 1; 1942274939Smav itv.it_value.tv_sec = timeout; 1943255570Strasz error = setitimer(ITIMER_REAL, &itv, NULL); 1944255570Strasz if (error != 0) 1945255570Strasz log_err(1, "setitimer"); 1946255570Strasz} 1947255570Strasz 1948255570Straszstatic int 1949255570Straszwait_for_children(bool block) 1950255570Strasz{ 1951255570Strasz pid_t pid; 1952255570Strasz int status; 1953255570Strasz int num = 0; 1954255570Strasz 1955255570Strasz for (;;) { 1956255570Strasz /* 1957255570Strasz * If "block" is true, wait for at least one process. 1958255570Strasz */ 1959255570Strasz if (block && num == 0) 1960255570Strasz pid = wait4(-1, &status, 0, NULL); 1961255570Strasz else 1962255570Strasz pid = wait4(-1, &status, WNOHANG, NULL); 1963255570Strasz if (pid <= 0) 1964255570Strasz break; 1965255570Strasz if (WIFSIGNALED(status)) { 1966255570Strasz log_warnx("child process %d terminated with signal %d", 1967255570Strasz pid, WTERMSIG(status)); 1968255570Strasz } else if (WEXITSTATUS(status) != 0) { 1969255570Strasz log_warnx("child process %d terminated with exit status %d", 1970255570Strasz pid, WEXITSTATUS(status)); 1971255570Strasz } else { 1972255570Strasz log_debugx("child process %d terminated gracefully", pid); 1973255570Strasz } 1974255570Strasz num++; 1975255570Strasz } 1976255570Strasz 1977255570Strasz return (num); 1978255570Strasz} 1979255570Strasz 1980255570Straszstatic void 1981265513Straszhandle_connection(struct portal *portal, int fd, 1982270137Smav const struct sockaddr *client_sa, bool dont_fork) 1983255570Strasz{ 1984255570Strasz struct connection *conn; 1985255570Strasz int error; 1986255570Strasz pid_t pid; 1987255570Strasz char host[NI_MAXHOST + 1]; 1988255570Strasz struct conf *conf; 1989255570Strasz 1990255570Strasz conf = portal->p_portal_group->pg_conf; 1991255570Strasz 1992255570Strasz if (dont_fork) { 1993255570Strasz log_debugx("incoming connection; not forking due to -d flag"); 1994255570Strasz } else { 1995255570Strasz nchildren -= wait_for_children(false); 1996255570Strasz assert(nchildren >= 0); 1997255570Strasz 1998255570Strasz while (conf->conf_maxproc > 0 && nchildren >= conf->conf_maxproc) { 1999255570Strasz log_debugx("maxproc limit of %d child processes hit; " 2000255570Strasz "waiting for child process to exit", conf->conf_maxproc); 2001255570Strasz nchildren -= wait_for_children(true); 2002255570Strasz assert(nchildren >= 0); 2003255570Strasz } 2004255570Strasz log_debugx("incoming connection; forking child process #%d", 2005255570Strasz nchildren); 2006255570Strasz nchildren++; 2007255570Strasz pid = fork(); 2008255570Strasz if (pid < 0) 2009255570Strasz log_err(1, "fork"); 2010255570Strasz if (pid > 0) { 2011255570Strasz close(fd); 2012255570Strasz return; 2013255570Strasz } 2014255570Strasz } 2015255570Strasz pidfile_close(conf->conf_pidfh); 2016255570Strasz 2017270137Smav error = getnameinfo(client_sa, client_sa->sa_len, 2018265513Strasz host, sizeof(host), NULL, 0, NI_NUMERICHOST); 2019265513Strasz if (error != 0) 2020265513Strasz log_errx(1, "getnameinfo: %s", gai_strerror(error)); 2021255570Strasz 2022265513Strasz log_debugx("accepted connection from %s; portal group \"%s\"", 2023265513Strasz host, portal->p_portal_group->pg_name); 2024265513Strasz log_set_peer_addr(host); 2025265513Strasz setproctitle("%s", host); 2026255570Strasz 2027270137Smav conn = connection_new(portal, fd, host, client_sa); 2028274939Smav set_timeout(conf->conf_timeout, true); 2029255570Strasz kernel_capsicate(); 2030255570Strasz login(conn); 2031255570Strasz if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) { 2032255570Strasz kernel_handoff(conn); 2033255570Strasz log_debugx("connection handed off to the kernel"); 2034255570Strasz } else { 2035255570Strasz assert(conn->conn_session_type == CONN_SESSION_TYPE_DISCOVERY); 2036255570Strasz discovery(conn); 2037255570Strasz } 2038255570Strasz log_debugx("nothing more to do; exiting"); 2039255570Strasz exit(0); 2040255570Strasz} 2041255570Strasz 2042255570Straszstatic int 2043255570Straszfd_add(int fd, fd_set *fdset, int nfds) 2044255570Strasz{ 2045255570Strasz 2046255570Strasz /* 2047255570Strasz * Skip sockets which we failed to bind. 2048255570Strasz */ 2049255570Strasz if (fd <= 0) 2050255570Strasz return (nfds); 2051255570Strasz 2052255570Strasz FD_SET(fd, fdset); 2053255570Strasz if (fd > nfds) 2054255570Strasz nfds = fd; 2055255570Strasz return (nfds); 2056255570Strasz} 2057255570Strasz 2058255570Straszstatic void 2059255570Straszmain_loop(struct conf *conf, bool dont_fork) 2060255570Strasz{ 2061255570Strasz struct portal_group *pg; 2062255570Strasz struct portal *portal; 2063265512Strasz struct sockaddr_storage client_sa; 2064265512Strasz socklen_t client_salen; 2065255570Strasz#ifdef ICL_KERNEL_PROXY 2066255570Strasz int connection_id; 2067265509Strasz int portal_id; 2068265507Strasz#endif 2069255570Strasz fd_set fdset; 2070255570Strasz int error, nfds, client_fd; 2071255570Strasz 2072255570Strasz pidfile_write(conf->conf_pidfh); 2073255570Strasz 2074255570Strasz for (;;) { 2075274939Smav if (sighup_received || sigterm_received || timed_out()) 2076255570Strasz return; 2077255570Strasz 2078255570Strasz#ifdef ICL_KERNEL_PROXY 2079265507Strasz if (proxy_mode) { 2080265513Strasz client_salen = sizeof(client_sa); 2081265513Strasz kernel_accept(&connection_id, &portal_id, 2082265513Strasz (struct sockaddr *)&client_sa, &client_salen); 2083271627Strasz assert(client_salen >= client_sa.ss_len); 2084255570Strasz 2085265509Strasz log_debugx("incoming connection, id %d, portal id %d", 2086265509Strasz connection_id, portal_id); 2087265509Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 2088265509Strasz TAILQ_FOREACH(portal, &pg->pg_portals, p_next) { 2089265509Strasz if (portal->p_id == portal_id) { 2090265509Strasz goto found; 2091265509Strasz } 2092265509Strasz } 2093265509Strasz } 2094255570Strasz 2095265509Strasz log_errx(1, "kernel returned invalid portal_id %d", 2096265509Strasz portal_id); 2097265509Strasz 2098265509Straszfound: 2099265513Strasz handle_connection(portal, connection_id, 2100270137Smav (struct sockaddr *)&client_sa, dont_fork); 2101265507Strasz } else { 2102265507Strasz#endif 2103265507Strasz assert(proxy_mode == false); 2104265507Strasz 2105265507Strasz FD_ZERO(&fdset); 2106265507Strasz nfds = 0; 2107265507Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 2108265507Strasz TAILQ_FOREACH(portal, &pg->pg_portals, p_next) 2109265507Strasz nfds = fd_add(portal->p_socket, &fdset, nfds); 2110255570Strasz } 2111265507Strasz error = select(nfds + 1, &fdset, NULL, NULL, NULL); 2112265507Strasz if (error <= 0) { 2113265507Strasz if (errno == EINTR) 2114265507Strasz return; 2115265507Strasz log_err(1, "select"); 2116265507Strasz } 2117265507Strasz TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { 2118265507Strasz TAILQ_FOREACH(portal, &pg->pg_portals, p_next) { 2119265507Strasz if (!FD_ISSET(portal->p_socket, &fdset)) 2120265507Strasz continue; 2121265512Strasz client_salen = sizeof(client_sa); 2122265512Strasz client_fd = accept(portal->p_socket, 2123265512Strasz (struct sockaddr *)&client_sa, 2124265512Strasz &client_salen); 2125265507Strasz if (client_fd < 0) 2126265507Strasz log_err(1, "accept"); 2127271627Strasz assert(client_salen >= client_sa.ss_len); 2128271627Strasz 2129265512Strasz handle_connection(portal, client_fd, 2130265513Strasz (struct sockaddr *)&client_sa, 2131270137Smav dont_fork); 2132265507Strasz break; 2133265507Strasz } 2134265507Strasz } 2135265507Strasz#ifdef ICL_KERNEL_PROXY 2136255570Strasz } 2137265507Strasz#endif 2138255570Strasz } 2139255570Strasz} 2140255570Strasz 2141255570Straszstatic void 2142255570Straszsighup_handler(int dummy __unused) 2143255570Strasz{ 2144255570Strasz 2145255570Strasz sighup_received = true; 2146255570Strasz} 2147255570Strasz 2148255570Straszstatic void 2149255570Straszsigterm_handler(int dummy __unused) 2150255570Strasz{ 2151255570Strasz 2152255570Strasz sigterm_received = true; 2153255570Strasz} 2154255570Strasz 2155255570Straszstatic void 2156263730Straszsigchld_handler(int dummy __unused) 2157263730Strasz{ 2158263730Strasz 2159263730Strasz /* 2160263730Strasz * The only purpose of this handler is to make SIGCHLD 2161263730Strasz * interrupt the ISCSIDWAIT ioctl(2), so we can call 2162263730Strasz * wait_for_children(). 2163263730Strasz */ 2164263730Strasz} 2165263730Strasz 2166263730Straszstatic void 2167255570Straszregister_signals(void) 2168255570Strasz{ 2169255570Strasz struct sigaction sa; 2170255570Strasz int error; 2171255570Strasz 2172255570Strasz bzero(&sa, sizeof(sa)); 2173255570Strasz sa.sa_handler = sighup_handler; 2174255570Strasz sigfillset(&sa.sa_mask); 2175255570Strasz error = sigaction(SIGHUP, &sa, NULL); 2176255570Strasz if (error != 0) 2177255570Strasz log_err(1, "sigaction"); 2178255570Strasz 2179255570Strasz sa.sa_handler = sigterm_handler; 2180255570Strasz error = sigaction(SIGTERM, &sa, NULL); 2181255570Strasz if (error != 0) 2182255570Strasz log_err(1, "sigaction"); 2183255570Strasz 2184255570Strasz sa.sa_handler = sigterm_handler; 2185255570Strasz error = sigaction(SIGINT, &sa, NULL); 2186255570Strasz if (error != 0) 2187255570Strasz log_err(1, "sigaction"); 2188263730Strasz 2189263730Strasz sa.sa_handler = sigchld_handler; 2190263730Strasz error = sigaction(SIGCHLD, &sa, NULL); 2191263730Strasz if (error != 0) 2192263730Strasz log_err(1, "sigaction"); 2193255570Strasz} 2194255570Strasz 2195255570Straszint 2196255570Straszmain(int argc, char **argv) 2197255570Strasz{ 2198255570Strasz struct conf *oldconf, *newconf, *tmpconf; 2199274939Smav struct isns *newns; 2200255570Strasz const char *config_path = DEFAULT_CONFIG_PATH; 2201255570Strasz int debug = 0, ch, error; 2202255570Strasz bool dont_daemonize = false; 2203255570Strasz 2204265507Strasz while ((ch = getopt(argc, argv, "df:R")) != -1) { 2205255570Strasz switch (ch) { 2206255570Strasz case 'd': 2207255570Strasz dont_daemonize = true; 2208255570Strasz debug++; 2209255570Strasz break; 2210255570Strasz case 'f': 2211255570Strasz config_path = optarg; 2212255570Strasz break; 2213265507Strasz case 'R': 2214265507Strasz#ifndef ICL_KERNEL_PROXY 2215265507Strasz log_errx(1, "ctld(8) compiled without ICL_KERNEL_PROXY " 2216265507Strasz "does not support iSER protocol"); 2217265507Strasz#endif 2218265507Strasz proxy_mode = true; 2219265507Strasz break; 2220255570Strasz case '?': 2221255570Strasz default: 2222255570Strasz usage(); 2223255570Strasz } 2224255570Strasz } 2225255570Strasz argc -= optind; 2226255570Strasz if (argc != 0) 2227255570Strasz usage(); 2228255570Strasz 2229255570Strasz log_init(debug); 2230255570Strasz kernel_init(); 2231255570Strasz 2232255570Strasz oldconf = conf_new_from_kernel(); 2233255570Strasz newconf = conf_new_from_file(config_path); 2234255570Strasz if (newconf == NULL) 2235265516Strasz log_errx(1, "configuration error; exiting"); 2236255570Strasz if (debug > 0) { 2237255570Strasz oldconf->conf_debug = debug; 2238255570Strasz newconf->conf_debug = debug; 2239255570Strasz } 2240255570Strasz 2241255570Strasz error = conf_apply(oldconf, newconf); 2242255570Strasz if (error != 0) 2243265516Strasz log_errx(1, "failed to apply configuration; exiting"); 2244265516Strasz 2245255570Strasz conf_delete(oldconf); 2246255570Strasz oldconf = NULL; 2247255570Strasz 2248255570Strasz register_signals(); 2249255570Strasz 2250263719Strasz if (dont_daemonize == false) { 2251263719Strasz log_debugx("daemonizing"); 2252263719Strasz if (daemon(0, 0) == -1) { 2253263719Strasz log_warn("cannot daemonize"); 2254263719Strasz pidfile_remove(newconf->conf_pidfh); 2255263719Strasz exit(1); 2256263719Strasz } 2257263719Strasz } 2258263719Strasz 2259274939Smav /* Schedule iSNS update */ 2260274939Smav if (!TAILQ_EMPTY(&newconf->conf_isns)) 2261274939Smav set_timeout((newconf->conf_isns_period + 2) / 3, false); 2262274939Smav 2263255570Strasz for (;;) { 2264255570Strasz main_loop(newconf, dont_daemonize); 2265255570Strasz if (sighup_received) { 2266255570Strasz sighup_received = false; 2267255570Strasz log_debugx("received SIGHUP, reloading configuration"); 2268255570Strasz tmpconf = conf_new_from_file(config_path); 2269255570Strasz if (tmpconf == NULL) { 2270255570Strasz log_warnx("configuration error, " 2271255570Strasz "continuing with old configuration"); 2272255570Strasz } else { 2273255570Strasz if (debug > 0) 2274255570Strasz tmpconf->conf_debug = debug; 2275255570Strasz oldconf = newconf; 2276255570Strasz newconf = tmpconf; 2277255570Strasz error = conf_apply(oldconf, newconf); 2278255570Strasz if (error != 0) 2279255570Strasz log_warnx("failed to reload " 2280255570Strasz "configuration"); 2281255570Strasz conf_delete(oldconf); 2282255570Strasz oldconf = NULL; 2283255570Strasz } 2284255570Strasz } else if (sigterm_received) { 2285255570Strasz log_debugx("exiting on signal; " 2286255570Strasz "reloading empty configuration"); 2287255570Strasz 2288255570Strasz log_debugx("disabling CTL iSCSI port " 2289255570Strasz "and terminating all connections"); 2290255570Strasz 2291255570Strasz oldconf = newconf; 2292255570Strasz newconf = conf_new(); 2293255570Strasz if (debug > 0) 2294255570Strasz newconf->conf_debug = debug; 2295255570Strasz error = conf_apply(oldconf, newconf); 2296255570Strasz if (error != 0) 2297255570Strasz log_warnx("failed to apply configuration"); 2298274939Smav conf_delete(oldconf); 2299274939Smav oldconf = NULL; 2300255570Strasz 2301255570Strasz log_warnx("exiting on signal"); 2302255570Strasz exit(0); 2303255570Strasz } else { 2304255570Strasz nchildren -= wait_for_children(false); 2305255570Strasz assert(nchildren >= 0); 2306274939Smav if (timed_out()) { 2307274939Smav set_timeout(0, false); 2308274939Smav TAILQ_FOREACH(newns, &newconf->conf_isns, i_next) 2309274939Smav isns_check(newns); 2310274939Smav /* Schedule iSNS update */ 2311274939Smav if (!TAILQ_EMPTY(&newconf->conf_isns)) { 2312274939Smav set_timeout((newconf->conf_isns_period 2313274939Smav + 2) / 3, 2314274939Smav false); 2315274939Smav } 2316274939Smav } 2317255570Strasz } 2318255570Strasz } 2319255570Strasz /* NOTREACHED */ 2320255570Strasz} 2321