1 /* $NetBSD: iscsid_main.c,v 1.12 2019/02/04 08:21:12 mrg Exp $ */ 2 3 /*- 4 * Copyright (c) 2005,2006,2011 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Wasabi Systems, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include "iscsid_globals.h" 33 34 #include <sys/types.h> 35 #include <sys/socket.h> 36 #include <sys/un.h> 37 #include <sys/sysctl.h> 38 39 #include <ctype.h> 40 #include <err.h> 41 #include <fcntl.h> 42 #include <syslog.h> 43 #include <util.h> 44 45 #define DEVICE "/dev/iscsi0" 46 47 /* -------------------------------------------------------------------------- */ 48 49 list_head_t list[NUM_DAEMON_LISTS]; /* the lists this daemon keeps */ 50 51 pthread_mutex_t sesslist_lock; /* session list lock */ 52 pthread_t main_thread; /* main thread handle */ 53 pthread_t event_thread; /* event thread handle */ 54 55 int driver = -1; /* the driver's file desc */ 56 int client_sock; /* the client communication socket */ 57 58 int debug_level; /* How much info to display */ 59 int debugging; 60 61 /* 62 To avoid memory fragmentation (and speed things up a bit), we use the 63 static bufs unless the request or response exceeds the buffer size 64 (which it normally shouldn't, assuming we don't have thousands 65 of list entries). 66 */ 67 static uint8_t req_buf[REQ_BUFFER_SIZE]; /* default buffer for requests */ 68 static uint8_t rsp_buf[RSP_BUFFER_SIZE]; /* default buffer for responses */ 69 70 /* -------------------------------------------------------------------------- */ 71 72 static void __dead 73 usage(void) 74 { 75 fprintf(stderr, "Usage: %s [-d <lvl>] [-n]\n", getprogname()); 76 exit(EXIT_FAILURE); 77 } 78 79 /* 80 * create_node_name: 81 * Create and set default node name. 82 * 83 * Returns 0 on success, else an error code. 84 */ 85 86 static int 87 create_node_name(void) 88 { 89 iscsi_set_node_name_parameters_t snp; 90 uint32_t hid = 0; 91 size_t siz; 92 int mib[2]; 93 int total; 94 unsigned char *s; 95 96 (void) memset(&snp, 0x0, sizeof(snp)); 97 mib[0] = CTL_KERN; 98 mib[1] = KERN_HOSTID; 99 siz = sizeof(hid); 100 sysctl(mib, 2, &hid, &siz, NULL, 0); 101 mib[1] = KERN_HOSTNAME; 102 siz = ISCSI_STRING_LENGTH - 45; 103 sysctl(mib, 2, snp.InitiatorAlias, &siz, NULL, 0); 104 105 DEB(3, ("Host Name: <%s>, Host ID: %u", snp.InitiatorAlias, hid)); 106 if (!snp.InitiatorAlias[0]) { 107 printf("Warning: iSCSI Node Name not set (No Host Name)!\n"); 108 return ISCSID_STATUS_NO_INITIATOR_NAME; 109 } 110 for (s = snp.InitiatorAlias; *s; s++) 111 if (!isalnum((unsigned char) *s) && *s != '-' && *s != '.' && *s != ':') 112 *s = '-'; 113 total = snprintf((char *)snp.InitiatorName, sizeof(snp.InitiatorName), 114 "iqn.1994-04.org.netbsd:iscsi.%s:%u", snp.InitiatorAlias, hid); 115 if ((size_t)total > sizeof(snp.InitiatorName)) { 116 printf("Warning: iSCSI Node InitiatorName too long to set InitiatorAlias!\n"); 117 return ISCSID_STATUS_NO_INITIATOR_NAME; 118 } 119 120 ioctl(driver, ISCSI_SET_NODE_NAME, &snp); 121 return snp.status; 122 } 123 124 125 /* 126 * init_daemon: 127 * Open driver, create communication socket. 128 * 129 * Returns: <0 on error 130 */ 131 132 static int 133 init_daemon(void) 134 { 135 int sock, i; 136 struct sockaddr_un name; 137 iscsid_request_t req; 138 139 if ((driver = open(DEVICE, O_RDONLY)) < 0) { 140 perror("opening " DEVICE); 141 return -1; 142 } 143 144 sock = socket(AF_UNIX, SOCK_DGRAM, 0); 145 if (sock < 0) { 146 perror("opening datagram socket"); 147 return -1; 148 } 149 150 name.sun_family = AF_UNIX; 151 strlcpy(name.sun_path, ISCSID_SOCK_NAME, sizeof(name.sun_path)); 152 153 req.request = ISCSID_DAEMON_TEST; 154 req.parameter_length = 0; 155 156 i = sendto(sock, &req, sizeof(req), 0, (struct sockaddr *)(void *)&name, 157 (socklen_t)sizeof(struct sockaddr_un)); 158 if (i == sizeof(req)) { 159 printf("Daemon already loaded!\n"); 160 close(sock); 161 return -1; 162 } 163 164 unlink(ISCSID_SOCK_NAME); 165 if (bind(sock, (struct sockaddr *)(void *)&name, (socklen_t)sizeof(struct sockaddr_un))) { 166 perror("binding name to socket"); 167 return -1; 168 } 169 170 for (i = 0; i < NUM_DAEMON_LISTS; i++) { 171 TAILQ_INIT(&list[i].list); 172 list[i].num_entries = 0; 173 } 174 175 if ((i = pthread_mutex_init(&sesslist_lock, NULL)) != 0) { 176 printf("Mutex init failed (%d)\n", i); 177 close(sock); 178 return -1; 179 } 180 181 if (!register_event_handler()) { 182 printf("Couldn't register event handler\n"); 183 close(sock); 184 unlink(ISCSID_SOCK_NAME); 185 pthread_mutex_destroy(&sesslist_lock); 186 return -1; 187 } 188 189 create_node_name(); 190 191 return sock; 192 } 193 194 195 /* 196 * make_rsp: 197 * Allocate a response buffer if the static buffer is insufficient, set 198 * the response parameter length. 199 * 200 * Parameter: 201 * len Response parameter size (not counting header) 202 * prsp Pointer to address of response buffer 203 * prsp_temp Will be set to TRUE if buffer was allocated, FALSE 204 * for static buffer. 205 * 206 * Returns: Pointer to response buffer, NULL if allocation failed. 207 */ 208 209 iscsid_response_t * 210 make_rsp(size_t len, iscsid_response_t ** prsp, int *prsp_temp) 211 { 212 iscsid_response_t *rsp; 213 214 if ((len + sizeof(iscsid_response_t)) > RSP_BUFFER_SIZE) { 215 if ((rsp = calloc(1, len)) == NULL) { 216 (*prsp)->status = ISCSID_STATUS_NO_RESOURCES; 217 return NULL; 218 } 219 *prsp_temp = TRUE; 220 *prsp = rsp; 221 } else 222 rsp = *prsp; 223 224 memset (rsp, 0, len + sizeof(iscsid_response_t)); 225 rsp->parameter_length = (uint32_t)len; 226 return rsp; 227 } 228 229 230 /* 231 * process_message: 232 * minimal parameter check and dispatch for the daemon functions. 233 * 234 * Parameter: 235 * req The request 236 * prsp Pointer to address of response buffer 237 * prsp_temp Will be set to TRUE if buffer was allocated, FALSE 238 * for static buffer. 239 */ 240 241 static void 242 process_message(iscsid_request_t *req, iscsid_response_t **prsp, int *prsp_temp) 243 { 244 iscsid_response_t *rsp; 245 void *p = req->parameter; 246 247 *prsp_temp = FALSE; 248 *prsp = rsp = (iscsid_response_t *)(void *)rsp_buf; 249 rsp->parameter_length = 0; 250 rsp->status = ISCSID_STATUS_SUCCESS; 251 252 switch (req->request) { 253 case ISCSID_ADD_TARGET: 254 if (req->parameter_length < sizeof(iscsid_add_target_req_t)) { 255 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 256 break; 257 } 258 add_target((iscsid_add_target_req_t *)p, prsp, prsp_temp); 259 break; 260 261 case ISCSID_ADD_PORTAL: 262 if (req->parameter_length != sizeof(iscsid_add_portal_req_t)) { 263 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 264 break; 265 } 266 add_portal((iscsid_add_portal_req_t *)p, prsp, prsp_temp); 267 break; 268 269 case ISCSID_SET_TARGET_OPTIONS: 270 if (req->parameter_length != sizeof(iscsid_get_set_target_options_t)) { 271 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 272 break; 273 } 274 rsp->status = set_target_options((iscsid_get_set_target_options_t *)p); 275 break; 276 277 case ISCSID_GET_TARGET_OPTIONS: 278 if (req->parameter_length != sizeof(iscsid_sym_id_t)) { 279 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 280 break; 281 } 282 rsp->status = ISCSID_STATUS_NOTIMPL; 283 break; 284 285 case ISCSID_SET_TARGET_AUTHENTICATION: 286 if (req->parameter_length != 287 sizeof(iscsid_set_target_authentication_req_t)) { 288 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 289 break; 290 } 291 rsp->status = set_target_auth((iscsid_set_target_authentication_req_t *)p); 292 break; 293 294 case ISCSID_SLP_FIND_TARGETS: 295 rsp->status = ISCSID_STATUS_NOTIMPL; 296 break; 297 298 case ISCSID_REFRESH_TARGETS: 299 if (req->parameter_length < sizeof(iscsid_refresh_req_t)) { 300 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 301 break; 302 } 303 rsp->status = refresh_targets((iscsid_refresh_req_t *)p); 304 break; 305 306 case ISCSID_REMOVE_TARGET: 307 if (req->parameter_length != sizeof(iscsid_list_id_t)) { 308 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 309 break; 310 } 311 rsp->status = remove_target((iscsid_list_id_t *)p); 312 break; 313 314 case ISCSID_SEARCH_LIST: 315 if (req->parameter_length != sizeof(iscsid_search_list_req_t)) { 316 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 317 break; 318 } 319 search_list((iscsid_search_list_req_t *)p, prsp, prsp_temp); 320 break; 321 322 case ISCSID_GET_LIST: 323 if (req->parameter_length != sizeof(iscsid_get_list_req_t)) { 324 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 325 break; 326 } 327 get_list((iscsid_get_list_req_t *)p, prsp, prsp_temp); 328 break; 329 330 case ISCSID_GET_TARGET_INFO: 331 if (req->parameter_length != sizeof(iscsid_list_id_t)) { 332 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 333 break; 334 } 335 get_target_info((iscsid_list_id_t *)p, prsp, prsp_temp); 336 break; 337 338 case ISCSID_GET_PORTAL_INFO: 339 if (req->parameter_length != sizeof(iscsid_list_id_t)) { 340 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 341 break; 342 } 343 get_portal_info((iscsid_list_id_t *)p, prsp, prsp_temp); 344 break; 345 346 #ifndef ISCSI_MINIMAL 347 case ISCSID_ADD_ISNS_SERVER: 348 if (req->parameter_length != sizeof(iscsid_add_isns_server_req_t)) { 349 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 350 break; 351 } 352 add_isns_server((iscsid_add_isns_server_req_t *)p, 353 prsp, prsp_temp); 354 break; 355 356 case ISCSID_GET_ISNS_SERVER: 357 if (req->parameter_length != sizeof(iscsid_sym_id_t)) { 358 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 359 break; 360 } 361 get_isns_server((iscsid_sym_id_t *)p, prsp, prsp_temp); 362 break; 363 364 case ISCSID_SLP_FIND_ISNS_SERVERS: 365 rsp->status = ISCSID_STATUS_NOTIMPL; 366 break; 367 368 case ISCSID_REMOVE_ISNS_SERVER: 369 if (req->parameter_length != sizeof(iscsid_sym_id_t)) { 370 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 371 break; 372 } 373 rsp->status = remove_isns_server((iscsid_sym_id_t *)p); 374 break; 375 #endif 376 377 case ISCSID_ADD_INITIATOR_PORTAL: 378 if (req->parameter_length != sizeof(iscsid_add_initiator_req_t)) { 379 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 380 break; 381 } 382 add_initiator_portal((iscsid_add_initiator_req_t *)p, 383 prsp, prsp_temp); 384 break; 385 386 case ISCSID_GET_INITIATOR_PORTAL: 387 if (req->parameter_length != sizeof(iscsid_sym_id_t)) { 388 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 389 break; 390 } 391 get_initiator_portal((iscsid_sym_id_t *)p, prsp, prsp_temp); 392 break; 393 394 case ISCSID_REMOVE_INITIATOR_PORTAL: 395 if (req->parameter_length != sizeof(iscsid_sym_id_t)) { 396 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 397 break; 398 } 399 rsp->status = remove_initiator_portal((iscsid_sym_id_t *)p); 400 break; 401 402 case ISCSID_LOGIN: 403 if (req->parameter_length != sizeof(iscsid_login_req_t)) { 404 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 405 break; 406 } 407 log_in((iscsid_login_req_t *)p, rsp); 408 break; 409 410 case ISCSID_ADD_CONNECTION: 411 if (req->parameter_length != sizeof(iscsid_login_req_t)) { 412 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 413 break; 414 } 415 add_connection((iscsid_login_req_t *)p, rsp); 416 break; 417 418 case ISCSID_LOGOUT: 419 if (req->parameter_length != sizeof(iscsid_sym_id_t)) { 420 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 421 break; 422 } 423 rsp->status = log_out((iscsid_sym_id_t *)p); 424 break; 425 426 case ISCSID_REMOVE_CONNECTION: 427 if (req->parameter_length != sizeof(iscsid_remove_connection_req_t)) { 428 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 429 break; 430 } 431 rsp->status = remove_connection((iscsid_remove_connection_req_t *)p); 432 break; 433 434 case ISCSID_GET_SESSION_LIST: 435 get_session_list(prsp, prsp_temp); 436 break; 437 438 case ISCSID_GET_CONNECTION_LIST: 439 if (req->parameter_length != sizeof(iscsid_sym_id_t)) { 440 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 441 break; 442 } 443 get_connection_list((iscsid_sym_id_t *)p, prsp, prsp_temp); 444 break; 445 446 case ISCSID_GET_CONNECTION_INFO: 447 if (req->parameter_length != sizeof(iscsid_get_connection_info_req_t)) { 448 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 449 break; 450 } 451 get_connection_info((iscsid_get_connection_info_req_t *)p, 452 prsp, prsp_temp); 453 break; 454 455 case ISCSID_SET_NODE_NAME: 456 if (req->parameter_length != sizeof(iscsid_set_node_name_req_t)) { 457 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 458 break; 459 } 460 rsp->status = set_node_name((iscsid_set_node_name_req_t *)p); 461 break; 462 463 case ISCSID_GET_VERSION: 464 get_version(prsp, prsp_temp); 465 break; 466 467 default: 468 rsp->status = ISCSID_STATUS_INVALID_REQUEST; 469 break; 470 } 471 } 472 473 void 474 iscsid_log(const char *fmt, ...) 475 { 476 va_list ap; 477 va_start(ap, fmt); 478 vsyslog(LOG_INFO, fmt, ap); 479 va_end(ap); 480 } 481 482 /* 483 * exit_daemon: 484 * Deregister the event handler, deregister isns servers, then exit program. 485 */ 486 487 static void __dead 488 exit_daemon(void) 489 { 490 LOCK_SESSIONS; 491 deregister_event_handler(); 492 493 #ifndef ISCSI_MINIMAL 494 dereg_all_isns_servers(); 495 #endif 496 exit(0); 497 } 498 499 static void 500 handler_exit(void) 501 { 502 pthread_kill(main_thread, SIGINT); 503 } 504 505 static void 506 sighandler(int sig) 507 { 508 } 509 510 /* 511 * main: 512 * init, go daemon, then loop reading requests, processing them, 513 * and sending responses. 514 * Stops on receiving a terminate message (no response to that one is sent), 515 * or when an error occurs reading or writing the socket. 516 * 517 * Parameter: argc, argv currently ignored. 518 */ 519 520 int 521 /*ARGSUSED*/ 522 main(int argc, char **argv) 523 { 524 int req_temp, rsp_temp, c; 525 ssize_t ret; 526 size_t len; 527 struct sockaddr_un from; 528 socklen_t fromlen; 529 iscsid_request_t *req; 530 iscsid_response_t *rsp; 531 char *p; 532 struct sigaction sa; 533 534 while ((c = getopt(argc, argv, "Dd:")) != -1) 535 switch (c) { 536 case 'D': 537 debugging++; 538 break; 539 case 'd': 540 debug_level=(int)strtol(optarg, &p, 10); 541 if (*p) 542 errx(EXIT_FAILURE, "illegal log level -- %s", 543 optarg); 544 break; 545 default: 546 usage(); 547 } 548 549 openlog("iscsid", (debugging ? LOG_PERROR : 0) | LOG_PID, LOG_DAEMON); 550 551 client_sock = init_daemon(); 552 if (client_sock < 0) 553 exit(1); 554 555 DEBOUT(("iSCSI daemon loaded")); 556 557 if (!debugging) { 558 if (daemon(0, 1) < 0) 559 err(EXIT_FAILURE, "daemon() failed"); 560 pidfile(NULL); 561 } 562 563 memset(&sa, 0, sizeof(sa)); 564 sa.sa_handler = sighandler; 565 sigaction(SIGINT, &sa, NULL); 566 sigaction(SIGTERM, &sa, NULL); 567 568 main_thread = pthread_self(); 569 ret = pthread_create(&event_thread, NULL, event_handler, handler_exit); 570 if (ret) { 571 printf("Thread creation failed (%zd)\n", ret); 572 close(client_sock); 573 unlink(ISCSID_SOCK_NAME); 574 deregister_event_handler(); 575 pthread_mutex_destroy(&sesslist_lock); 576 return -1; 577 } 578 579 /* ---------------------------------------------------------------------- */ 580 581 for (;;) { 582 583 /* First, get size of request */ 584 req = (iscsid_request_t *)(void *)req_buf; 585 fromlen = sizeof(from); 586 len = sizeof(iscsid_request_t); 587 588 do { 589 ret = recvfrom(client_sock, req, len, MSG_PEEK | 590 MSG_WAITALL, (struct sockaddr *) &from, 591 &fromlen); 592 } while (ret == -1 && errno == EAGAIN); 593 594 if ((size_t)ret != len) { 595 DEBOUT(("Receiving from socket: %s",strerror(errno))); 596 break; 597 } 598 DEB(2, ("Request %d, parlen %d", 599 req->request, req->parameter_length)); 600 601 len += req->parameter_length; 602 603 /* now that we know the size, get the buffer for it */ 604 req_temp = (len > REQ_BUFFER_SIZE); 605 606 if (req_temp) { 607 req = malloc(len); 608 if (!req) { 609 printf("Can't alloc %zu bytes\n", len); 610 break; 611 } 612 } 613 /* read the complete request */ 614 fromlen = sizeof(from); 615 ret = recvfrom(client_sock, req, len, MSG_WAITALL, 616 (struct sockaddr *)(void *)&from, &fromlen); 617 if ((size_t)ret != len) { 618 DEB(2, ("Error receiving from socket!")); 619 if (req_temp) 620 free(req); 621 continue; 622 } 623 /* terminate? then go die. */ 624 if (req->request == ISCSID_DAEMON_TERMINATE) 625 break; 626 627 /* No reply required to test message */ 628 if (req->request == ISCSID_DAEMON_TEST) { 629 if (req_temp) 630 free(req); 631 DEB(2, ("Test message!")); 632 continue; 633 } 634 /* no return path? then we can't send a reply, */ 635 /* so don't process the command */ 636 if (!from.sun_path[0]) { 637 if (req_temp) 638 free(req); 639 DEB(2, ("No Return Address!")); 640 continue; 641 } 642 /* process the request */ 643 process_message(req, &rsp, &rsp_temp); 644 if (rsp == NULL) { 645 if (req_temp) 646 free(req); 647 DEB(2, ("Invalid message!")); 648 continue; 649 } 650 651 DEB(2, ("Sending reply: status %d, len %d", 652 rsp->status, rsp->parameter_length)); 653 654 /* send the response */ 655 len = sizeof(iscsid_response_t) + rsp->parameter_length; 656 ret = sendto(client_sock, rsp, len, 0, 657 (struct sockaddr *)(void *)&from, fromlen); 658 if (len != (size_t)ret) { 659 DEB(2, ("Error sending reply!")); 660 } 661 /* free temp buffers if we needed them */ 662 if (req_temp) 663 free(req); 664 if (rsp_temp) 665 free(rsp); 666 } 667 668 pthread_join(event_thread, NULL); 669 670 DEBOUT(("Exiting daemon")); 671 672 exit_daemon(); 673 674 /* we never get here */ 675 return 0; 676 } 677