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
usage(void)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
create_node_name(void)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
init_daemon(void)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 *
make_rsp(size_t len,iscsid_response_t ** prsp,int * prsp_temp)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
process_message(iscsid_request_t * req,iscsid_response_t ** prsp,int * prsp_temp)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
iscsid_log(const char * fmt,...)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
exit_daemon(void)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
handler_exit(void)500 handler_exit(void)
501 {
502 pthread_kill(main_thread, SIGINT);
503 }
504
505 static void
sighandler(int sig)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*/
main(int argc,char ** argv)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