1 /* $NetBSD: iscsid_main.c,v 1.11 2016/05/30 21:58:32 mlelstv 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 unsigned char *s; 94 95 (void) memset(&snp, 0x0, sizeof(snp)); 96 mib[0] = CTL_KERN; 97 mib[1] = KERN_HOSTID; 98 siz = sizeof(hid); 99 sysctl(mib, 2, &hid, &siz, NULL, 0); 100 mib[1] = KERN_HOSTNAME; 101 siz = ISCSI_STRING_LENGTH - 45; 102 sysctl(mib, 2, snp.InitiatorAlias, &siz, NULL, 0); 103 104 DEB(3, ("Host Name: <%s>, Host ID: %u", snp.InitiatorAlias, hid)); 105 if (!snp.InitiatorAlias[0]) { 106 printf("Warning: iSCSI Node Name not set (No Host Name)!\n"); 107 return ISCSID_STATUS_NO_INITIATOR_NAME; 108 } 109 for (s = snp.InitiatorAlias; *s; s++) 110 if (!isalnum((unsigned char) *s) && *s != '-' && *s != '.' && *s != ':') 111 *s = '-'; 112 snprintf((char *)snp.InitiatorName, sizeof(snp.InitiatorName), 113 "iqn.1994-04.org.netbsd:iscsi.%s:%u", snp.InitiatorAlias, hid); 114 115 ioctl(driver, ISCSI_SET_NODE_NAME, &snp); 116 return snp.status; 117 } 118 119 120 /* 121 * init_daemon: 122 * Open driver, create communication socket. 123 * 124 * Returns: <0 on error 125 */ 126 127 static int 128 init_daemon(void) 129 { 130 int sock, i; 131 struct sockaddr_un name; 132 iscsid_request_t req; 133 134 if ((driver = open(DEVICE, O_RDONLY)) < 0) { 135 perror("opening " DEVICE); 136 return -1; 137 } 138 139 sock = socket(AF_UNIX, SOCK_DGRAM, 0); 140 if (sock < 0) { 141 perror("opening datagram socket"); 142 return -1; 143 } 144 145 name.sun_family = AF_UNIX; 146 strlcpy(name.sun_path, ISCSID_SOCK_NAME, sizeof(name.sun_path)); 147 148 req.request = ISCSID_DAEMON_TEST; 149 req.parameter_length = 0; 150 151 i = sendto(sock, &req, sizeof(req), 0, (struct sockaddr *)(void *)&name, 152 (socklen_t)sizeof(struct sockaddr_un)); 153 if (i == sizeof(req)) { 154 printf("Daemon already loaded!\n"); 155 close(sock); 156 return -1; 157 } 158 159 unlink(ISCSID_SOCK_NAME); 160 if (bind(sock, (struct sockaddr *)(void *)&name, (socklen_t)sizeof(struct sockaddr_un))) { 161 perror("binding name to socket"); 162 return -1; 163 } 164 165 for (i = 0; i < NUM_DAEMON_LISTS; i++) { 166 TAILQ_INIT(&list[i].list); 167 list[i].num_entries = 0; 168 } 169 170 if ((i = pthread_mutex_init(&sesslist_lock, NULL)) != 0) { 171 printf("Mutex init failed (%d)\n", i); 172 close(sock); 173 return -1; 174 } 175 176 if (!register_event_handler()) { 177 printf("Couldn't register event handler\n"); 178 close(sock); 179 unlink(ISCSID_SOCK_NAME); 180 pthread_mutex_destroy(&sesslist_lock); 181 return -1; 182 } 183 184 create_node_name(); 185 186 return sock; 187 } 188 189 190 /* 191 * make_rsp: 192 * Allocate a response buffer if the static buffer is insufficient, set 193 * the response parameter length. 194 * 195 * Parameter: 196 * len Response parameter size (not counting header) 197 * prsp Pointer to address of response buffer 198 * prsp_temp Will be set to TRUE if buffer was allocated, FALSE 199 * for static buffer. 200 * 201 * Returns: Pointer to response buffer, NULL if allocation failed. 202 */ 203 204 iscsid_response_t * 205 make_rsp(size_t len, iscsid_response_t ** prsp, int *prsp_temp) 206 { 207 iscsid_response_t *rsp; 208 209 if ((len + sizeof(iscsid_response_t)) > RSP_BUFFER_SIZE) { 210 if ((rsp = calloc(1, len)) == NULL) { 211 (*prsp)->status = ISCSID_STATUS_NO_RESOURCES; 212 return NULL; 213 } 214 *prsp_temp = TRUE; 215 *prsp = rsp; 216 } else 217 rsp = *prsp; 218 219 memset (rsp, 0, len + sizeof(iscsid_response_t)); 220 rsp->parameter_length = (uint32_t)len; 221 return rsp; 222 } 223 224 225 /* 226 * process_message: 227 * minimal parameter check and dispatch for the daemon functions. 228 * 229 * Parameter: 230 * req The request 231 * prsp Pointer to address of response buffer 232 * prsp_temp Will be set to TRUE if buffer was allocated, FALSE 233 * for static buffer. 234 */ 235 236 static void 237 process_message(iscsid_request_t *req, iscsid_response_t **prsp, int *prsp_temp) 238 { 239 iscsid_response_t *rsp; 240 void *p = req->parameter; 241 242 *prsp_temp = FALSE; 243 *prsp = rsp = (iscsid_response_t *)(void *)rsp_buf; 244 rsp->parameter_length = 0; 245 rsp->status = ISCSID_STATUS_SUCCESS; 246 247 switch (req->request) { 248 case ISCSID_ADD_TARGET: 249 if (req->parameter_length < sizeof(iscsid_add_target_req_t)) { 250 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 251 break; 252 } 253 add_target((iscsid_add_target_req_t *)p, prsp, prsp_temp); 254 break; 255 256 case ISCSID_ADD_PORTAL: 257 if (req->parameter_length != sizeof(iscsid_add_portal_req_t)) { 258 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 259 break; 260 } 261 add_portal((iscsid_add_portal_req_t *)p, prsp, prsp_temp); 262 break; 263 264 case ISCSID_SET_TARGET_OPTIONS: 265 if (req->parameter_length != sizeof(iscsid_get_set_target_options_t)) { 266 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 267 break; 268 } 269 rsp->status = set_target_options((iscsid_get_set_target_options_t *)p); 270 break; 271 272 case ISCSID_GET_TARGET_OPTIONS: 273 if (req->parameter_length != sizeof(iscsid_sym_id_t)) { 274 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 275 break; 276 } 277 rsp->status = ISCSID_STATUS_NOTIMPL; 278 break; 279 280 case ISCSID_SET_TARGET_AUTHENTICATION: 281 if (req->parameter_length != 282 sizeof(iscsid_set_target_authentication_req_t)) { 283 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 284 break; 285 } 286 rsp->status = set_target_auth((iscsid_set_target_authentication_req_t *)p); 287 break; 288 289 case ISCSID_SLP_FIND_TARGETS: 290 rsp->status = ISCSID_STATUS_NOTIMPL; 291 break; 292 293 case ISCSID_REFRESH_TARGETS: 294 if (req->parameter_length < sizeof(iscsid_refresh_req_t)) { 295 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 296 break; 297 } 298 rsp->status = refresh_targets((iscsid_refresh_req_t *)p); 299 break; 300 301 case ISCSID_REMOVE_TARGET: 302 if (req->parameter_length != sizeof(iscsid_list_id_t)) { 303 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 304 break; 305 } 306 rsp->status = remove_target((iscsid_list_id_t *)p); 307 break; 308 309 case ISCSID_SEARCH_LIST: 310 if (req->parameter_length != sizeof(iscsid_search_list_req_t)) { 311 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 312 break; 313 } 314 search_list((iscsid_search_list_req_t *)p, prsp, prsp_temp); 315 break; 316 317 case ISCSID_GET_LIST: 318 if (req->parameter_length != sizeof(iscsid_get_list_req_t)) { 319 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 320 break; 321 } 322 get_list((iscsid_get_list_req_t *)p, prsp, prsp_temp); 323 break; 324 325 case ISCSID_GET_TARGET_INFO: 326 if (req->parameter_length != sizeof(iscsid_list_id_t)) { 327 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 328 break; 329 } 330 get_target_info((iscsid_list_id_t *)p, prsp, prsp_temp); 331 break; 332 333 case ISCSID_GET_PORTAL_INFO: 334 if (req->parameter_length != sizeof(iscsid_list_id_t)) { 335 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 336 break; 337 } 338 get_portal_info((iscsid_list_id_t *)p, prsp, prsp_temp); 339 break; 340 341 #ifndef ISCSI_MINIMAL 342 case ISCSID_ADD_ISNS_SERVER: 343 if (req->parameter_length != sizeof(iscsid_add_isns_server_req_t)) { 344 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 345 break; 346 } 347 add_isns_server((iscsid_add_isns_server_req_t *)p, 348 prsp, prsp_temp); 349 break; 350 351 case ISCSID_GET_ISNS_SERVER: 352 if (req->parameter_length != sizeof(iscsid_sym_id_t)) { 353 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 354 break; 355 } 356 get_isns_server((iscsid_sym_id_t *)p, prsp, prsp_temp); 357 break; 358 359 case ISCSID_SLP_FIND_ISNS_SERVERS: 360 rsp->status = ISCSID_STATUS_NOTIMPL; 361 break; 362 363 case ISCSID_REMOVE_ISNS_SERVER: 364 if (req->parameter_length != sizeof(iscsid_sym_id_t)) { 365 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 366 break; 367 } 368 rsp->status = remove_isns_server((iscsid_sym_id_t *)p); 369 break; 370 #endif 371 372 case ISCSID_ADD_INITIATOR_PORTAL: 373 if (req->parameter_length != sizeof(iscsid_add_initiator_req_t)) { 374 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 375 break; 376 } 377 add_initiator_portal((iscsid_add_initiator_req_t *)p, 378 prsp, prsp_temp); 379 break; 380 381 case ISCSID_GET_INITIATOR_PORTAL: 382 if (req->parameter_length != sizeof(iscsid_sym_id_t)) { 383 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 384 break; 385 } 386 get_initiator_portal((iscsid_sym_id_t *)p, prsp, prsp_temp); 387 break; 388 389 case ISCSID_REMOVE_INITIATOR_PORTAL: 390 if (req->parameter_length != sizeof(iscsid_sym_id_t)) { 391 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 392 break; 393 } 394 rsp->status = remove_initiator_portal((iscsid_sym_id_t *)p); 395 break; 396 397 case ISCSID_LOGIN: 398 if (req->parameter_length != sizeof(iscsid_login_req_t)) { 399 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 400 break; 401 } 402 log_in((iscsid_login_req_t *)p, rsp); 403 break; 404 405 case ISCSID_ADD_CONNECTION: 406 if (req->parameter_length != sizeof(iscsid_login_req_t)) { 407 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 408 break; 409 } 410 add_connection((iscsid_login_req_t *)p, rsp); 411 break; 412 413 case ISCSID_LOGOUT: 414 if (req->parameter_length != sizeof(iscsid_sym_id_t)) { 415 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 416 break; 417 } 418 rsp->status = log_out((iscsid_sym_id_t *)p); 419 break; 420 421 case ISCSID_REMOVE_CONNECTION: 422 if (req->parameter_length != sizeof(iscsid_remove_connection_req_t)) { 423 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 424 break; 425 } 426 rsp->status = remove_connection((iscsid_remove_connection_req_t *)p); 427 break; 428 429 case ISCSID_GET_SESSION_LIST: 430 get_session_list(prsp, prsp_temp); 431 break; 432 433 case ISCSID_GET_CONNECTION_LIST: 434 if (req->parameter_length != sizeof(iscsid_sym_id_t)) { 435 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 436 break; 437 } 438 get_connection_list((iscsid_sym_id_t *)p, prsp, prsp_temp); 439 break; 440 441 case ISCSID_GET_CONNECTION_INFO: 442 if (req->parameter_length != sizeof(iscsid_get_connection_info_req_t)) { 443 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 444 break; 445 } 446 get_connection_info((iscsid_get_connection_info_req_t *)p, 447 prsp, prsp_temp); 448 break; 449 450 case ISCSID_SET_NODE_NAME: 451 if (req->parameter_length != sizeof(iscsid_set_node_name_req_t)) { 452 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 453 break; 454 } 455 rsp->status = set_node_name((iscsid_set_node_name_req_t *)p); 456 break; 457 458 case ISCSID_GET_VERSION: 459 get_version(prsp, prsp_temp); 460 break; 461 462 default: 463 rsp->status = ISCSID_STATUS_INVALID_REQUEST; 464 break; 465 } 466 } 467 468 void 469 iscsid_log(const char *fmt, ...) 470 { 471 va_list ap; 472 va_start(ap, fmt); 473 vsyslog(LOG_INFO, fmt, ap); 474 va_end(ap); 475 } 476 477 /* 478 * exit_daemon: 479 * Deregister the event handler, deregister isns servers, then exit program. 480 */ 481 482 static void __dead 483 exit_daemon(void) 484 { 485 LOCK_SESSIONS; 486 deregister_event_handler(); 487 488 #ifndef ISCSI_MINIMAL 489 dereg_all_isns_servers(); 490 #endif 491 exit(0); 492 } 493 494 static void 495 handler_exit(void) 496 { 497 pthread_kill(main_thread, SIGINT); 498 } 499 500 static void 501 sighandler(int sig) 502 { 503 } 504 505 /* 506 * main: 507 * init, go daemon, then loop reading requests, processing them, 508 * and sending responses. 509 * Stops on receiving a terminate message (no response to that one is sent), 510 * or when an error occurs reading or writing the socket. 511 * 512 * Parameter: argc, argv currently ignored. 513 */ 514 515 int 516 /*ARGSUSED*/ 517 main(int argc, char **argv) 518 { 519 int req_temp, rsp_temp, c; 520 ssize_t ret; 521 size_t len; 522 struct sockaddr_un from; 523 socklen_t fromlen; 524 iscsid_request_t *req; 525 iscsid_response_t *rsp; 526 char *p; 527 struct sigaction sa; 528 529 while ((c = getopt(argc, argv, "Dd:")) != -1) 530 switch (c) { 531 case 'D': 532 debugging++; 533 break; 534 case 'd': 535 debug_level=(int)strtol(optarg, &p, 10); 536 if (*p) 537 errx(EXIT_FAILURE, "illegal log level -- %s", 538 optarg); 539 break; 540 default: 541 usage(); 542 } 543 544 openlog("iscsid", (debugging ? LOG_PERROR : 0) | LOG_PID, LOG_DAEMON); 545 546 client_sock = init_daemon(); 547 if (client_sock < 0) 548 exit(1); 549 550 DEBOUT(("iSCSI daemon loaded")); 551 552 if (!debugging) { 553 if (daemon(0, 1) < 0) 554 err(EXIT_FAILURE, "daemon() failed"); 555 pidfile(NULL); 556 } 557 558 memset(&sa, 0, sizeof(sa)); 559 sa.sa_handler = sighandler; 560 sigaction(SIGINT, &sa, NULL); 561 sigaction(SIGTERM, &sa, NULL); 562 563 main_thread = pthread_self(); 564 ret = pthread_create(&event_thread, NULL, event_handler, handler_exit); 565 if (ret) { 566 printf("Thread creation failed (%zd)\n", ret); 567 close(client_sock); 568 unlink(ISCSID_SOCK_NAME); 569 deregister_event_handler(); 570 pthread_mutex_destroy(&sesslist_lock); 571 return -1; 572 } 573 574 /* ---------------------------------------------------------------------- */ 575 576 for (;;) { 577 578 /* First, get size of request */ 579 req = (iscsid_request_t *)(void *)req_buf; 580 fromlen = sizeof(from); 581 len = sizeof(iscsid_request_t); 582 583 do { 584 ret = recvfrom(client_sock, req, len, MSG_PEEK | 585 MSG_WAITALL, (struct sockaddr *) &from, 586 &fromlen); 587 } while (ret == -1 && errno == EAGAIN); 588 589 if ((size_t)ret != len) { 590 DEBOUT(("Receiving from socket: %s",strerror(errno))); 591 break; 592 } 593 DEB(2, ("Request %d, parlen %d", 594 req->request, req->parameter_length)); 595 596 len += req->parameter_length; 597 598 /* now that we know the size, get the buffer for it */ 599 req_temp = (len > REQ_BUFFER_SIZE); 600 601 if (req_temp) { 602 req = malloc(len); 603 if (!req) { 604 printf("Can't alloc %zu bytes\n", len); 605 break; 606 } 607 } 608 /* read the complete request */ 609 fromlen = sizeof(from); 610 ret = recvfrom(client_sock, req, len, MSG_WAITALL, 611 (struct sockaddr *)(void *)&from, &fromlen); 612 if ((size_t)ret != len) { 613 DEB(2, ("Error receiving from socket!")); 614 if (req_temp) 615 free(req); 616 continue; 617 } 618 /* terminate? then go die. */ 619 if (req->request == ISCSID_DAEMON_TERMINATE) 620 break; 621 622 /* No reply required to test message */ 623 if (req->request == ISCSID_DAEMON_TEST) { 624 if (req_temp) 625 free(req); 626 DEB(2, ("Test message!")); 627 continue; 628 } 629 /* no return path? then we can't send a reply, */ 630 /* so don't process the command */ 631 if (!from.sun_path[0]) { 632 if (req_temp) 633 free(req); 634 DEB(2, ("No Return Address!")); 635 continue; 636 } 637 /* process the request */ 638 process_message(req, &rsp, &rsp_temp); 639 if (rsp == NULL) { 640 if (req_temp) 641 free(req); 642 DEB(2, ("Invalid message!")); 643 continue; 644 } 645 646 DEB(2, ("Sending reply: status %d, len %d", 647 rsp->status, rsp->parameter_length)); 648 649 /* send the response */ 650 len = sizeof(iscsid_response_t) + rsp->parameter_length; 651 ret = sendto(client_sock, rsp, len, 0, 652 (struct sockaddr *)(void *)&from, fromlen); 653 if (len != (size_t)ret) { 654 DEB(2, ("Error sending reply!")); 655 } 656 /* free temp buffers if we needed them */ 657 if (req_temp) 658 free(req); 659 if (rsp_temp) 660 free(rsp); 661 } 662 663 pthread_join(event_thread, NULL); 664 665 DEBOUT(("Exiting daemon")); 666 667 exit_daemon(); 668 669 /* we never get here */ 670 return 0; 671 } 672