xref: /openbsd-src/usr.sbin/iscsid/iscsid.c (revision a0747c9f67a4ae71ccb71e62a28d1ea19e06a63c)
1 /*	$OpenBSD: iscsid.c,v 1.22 2021/04/16 14:37:06 claudio Exp $ */
2 
3 /*
4  * Copyright (c) 2009 Claudio Jeker <claudio@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/queue.h>
20 #include <sys/socket.h>
21 #include <sys/sysctl.h>
22 #include <sys/time.h>
23 #include <sys/uio.h>
24 
25 #include <err.h>
26 #include <event.h>
27 #include <pwd.h>
28 #include <signal.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 
34 #include "iscsid.h"
35 #include "log.h"
36 
37 void		main_sig_handler(int, short, void *);
38 __dead void	usage(void);
39 void		shutdown_cb(int, short, void *);
40 
41 extern struct initiator *initiator;
42 struct event exit_ev;
43 int exit_rounds;
44 #define ISCSI_EXIT_WAIT 5
45 
46 const struct session_params	iscsi_sess_defaults = {
47 	.MaxBurstLength = 262144,
48 	.FirstBurstLength = 65536,
49 	.DefaultTime2Wait = 2,
50 	.DefaultTime2Retain = 20,
51 	.MaxOutstandingR2T = 1,
52 	.MaxConnections = 1,
53 	.InitialR2T = 1,
54 	.ImmediateData = 1,
55 	.DataPDUInOrder = 1,
56 	.DataSequenceInOrder = 1,
57 	.ErrorRecoveryLevel = 0
58 };
59 
60 const struct connection_params	iscsi_conn_defaults = {
61 	.MaxRecvDataSegmentLength = 8192
62 };
63 
64 int
65 main(int argc, char *argv[])
66 {
67 	struct event ev_sigint, ev_sigterm, ev_sighup;
68 	struct passwd *pw;
69 	char *ctrlsock = ISCSID_CONTROL;
70 	char *vscsidev = ISCSID_DEVICE;
71 	int name[] = { CTL_KERN, KERN_PROC_NOBROADCASTKILL, 0 };
72 	int ch, debug = 0, verbose = 0, nobkill = 1;
73 
74 	log_procname = getprogname();
75 
76 	log_init(1);    /* log to stderr until daemonized */
77 	log_verbose(1);
78 
79 	while ((ch = getopt(argc, argv, "dn:s:v")) != -1) {
80 		switch (ch) {
81 		case 'd':
82 			debug = 1;
83 			break;
84 		case 'n':
85 			vscsidev = optarg;
86 			break;
87 		case 's':
88 			ctrlsock = optarg;
89 			break;
90 		case 'v':
91 			verbose = 1;
92 			break;
93 		default:
94 			usage();
95 			/* NOTREACHED */
96 		}
97 	}
98 
99 	argc -= optind;
100 	argv += optind;
101 
102 	if (argc > 0)
103 		usage();
104 
105 	/* check for root privileges  */
106 	if (geteuid())
107 		errx(1, "need root privileges");
108 
109 	log_init(debug);
110 	log_verbose(verbose);
111 
112 	if (control_init(ctrlsock) == -1)
113 		fatalx("control socket setup failed");
114 
115 	if (!debug)
116 		daemon(1, 0);
117 	log_info("startup");
118 
119 	name[2] = getpid();
120 	if (sysctl(name, 3, NULL, 0, &nobkill, sizeof(nobkill)) != 0)
121 		fatal("sysctl");
122 
123 	event_init();
124 	vscsi_open(vscsidev);
125 
126 	/* chroot and drop to iscsid user */
127 	if ((pw = getpwnam(ISCSID_USER)) == NULL)
128 		errx(1, "unknown user %s", ISCSID_USER);
129 
130 	if (chroot(pw->pw_dir) == -1)
131 		fatal("chroot");
132 	if (chdir("/") == -1)
133 		fatal("chdir(\"/\")");
134 	if (setgroups(1, &pw->pw_gid) ||
135 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
136 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
137 		fatal("can't drop privileges");
138 
139 	/* setup signal handler */
140 	signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL);
141 	signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL);
142 	signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL);
143 	signal_add(&ev_sigint, NULL);
144 	signal_add(&ev_sigterm, NULL);
145 	signal_add(&ev_sighup, NULL);
146 	signal(SIGPIPE, SIG_IGN);
147 
148 	control_event_init();
149 	initiator = initiator_init();
150 
151 	event_dispatch();
152 
153 	/* do some cleanup on the way out */
154 	control_cleanup(ctrlsock);
155 	initiator_cleanup(initiator);
156 	log_info("exiting.");
157 	return 0;
158 }
159 
160 void
161 shutdown_cb(int fd, short event, void *arg)
162 {
163 	struct timeval tv;
164 
165 	if (exit_rounds++ >= ISCSI_EXIT_WAIT || initiator_isdown(initiator))
166 		event_loopexit(NULL);
167 
168 	timerclear(&tv);
169 	tv.tv_sec = 1;
170 
171 	if (evtimer_add(&exit_ev, &tv) == -1)
172 		fatal("shutdown_cb");
173 }
174 
175 void
176 main_sig_handler(int sig, short event, void *arg)
177 {
178 	struct timeval tv;
179 
180 	/* signal handler rules don't apply, libevent decouples for us */
181 	switch (sig) {
182 	case SIGTERM:
183 	case SIGINT:
184 	case SIGHUP:
185 		initiator_shutdown(initiator);
186 		evtimer_set(&exit_ev, shutdown_cb, NULL);
187 		timerclear(&tv);
188 		if (evtimer_add(&exit_ev, &tv) == -1)
189 			fatal("main_sig_handler");
190 		break;
191 	default:
192 		fatalx("unexpected signal");
193 		/* NOTREACHED */
194 	}
195 }
196 
197 __dead void
198 usage(void)
199 {
200 	extern char *__progname;
201 
202 	fprintf(stderr, "usage: %s [-dv] [-n device] [-s socket]\n",
203 	    __progname);
204 	exit(1);
205 }
206 
207 void
208 iscsid_ctrl_dispatch(void *ch, struct pdu *pdu)
209 {
210 	struct ctrlmsghdr *cmh;
211 	struct initiator_config *ic;
212 	struct session_config *sc;
213 	struct session *s;
214 	struct session_poll p = { 0 };
215 	int *valp;
216 
217 	cmh = pdu_getbuf(pdu, NULL, 0);
218 	if (cmh == NULL)
219 		goto done;
220 
221 	switch (cmh->type) {
222 	case CTRL_INITIATOR_CONFIG:
223 		if (cmh->len[0] != sizeof(*ic)) {
224 			log_warnx("CTRL_INITIATOR_CONFIG bad size");
225 			control_compose(ch, CTRL_FAILURE, NULL, 0);
226 			break;
227 		}
228 		ic = pdu_getbuf(pdu, NULL, 1);
229 		memcpy(&initiator->config, ic, sizeof(initiator->config));
230 		control_compose(ch, CTRL_SUCCESS, NULL, 0);
231 		break;
232 	case CTRL_SESSION_CONFIG:
233 		if (cmh->len[0] != sizeof(*sc)) {
234 			log_warnx("CTRL_SESSION_CONFIG bad size");
235 			control_compose(ch, CTRL_FAILURE, NULL, 0);
236 			break;
237 		}
238 		sc = pdu_getbuf(pdu, NULL, 1);
239 		if (cmh->len[1])
240 			sc->TargetName = pdu_getbuf(pdu, NULL, 2);
241 		else if (sc->SessionType != SESSION_TYPE_DISCOVERY) {
242 			control_compose(ch, CTRL_FAILURE, NULL, 0);
243 			goto done;
244 		} else
245 			sc->TargetName = NULL;
246 		if (cmh->len[2])
247 			sc->InitiatorName = pdu_getbuf(pdu, NULL, 3);
248 		else
249 			sc->InitiatorName = NULL;
250 
251 		s = session_find(initiator, sc->SessionName);
252 		if (s == NULL) {
253 			s = session_new(initiator, sc->SessionType);
254 			if (s == NULL) {
255 				control_compose(ch, CTRL_FAILURE, NULL, 0);
256 				goto done;
257 			}
258 		}
259 
260 		session_config(s, sc);
261 		if (s->state == SESS_INIT)
262 			session_fsm(s, SESS_EV_START, NULL, 0);
263 
264 		control_compose(ch, CTRL_SUCCESS, NULL, 0);
265 		break;
266 	case CTRL_LOG_VERBOSE:
267 		if (cmh->len[0] != sizeof(int)) {
268 			log_warnx("CTRL_LOG_VERBOSE bad size");
269 			control_compose(ch, CTRL_FAILURE, NULL, 0);
270 			break;
271 		}
272 		valp = pdu_getbuf(pdu, NULL, 1);
273 		log_verbose(*valp);
274 		control_compose(ch, CTRL_SUCCESS, NULL, 0);
275 		break;
276 	case CTRL_VSCSI_STATS:
277 		control_compose(ch, CTRL_VSCSI_STATS, vscsi_stats(),
278 		    sizeof(struct vscsi_stats));
279 		break;
280 	case CTRL_SHOW_SUM:
281 		control_compose(ch, CTRL_INITIATOR_CONFIG, &initiator->config,
282 		    sizeof(initiator->config));
283 
284 		TAILQ_FOREACH(s, &initiator->sessions, entry) {
285 			struct ctrldata cdv[3];
286 			bzero(cdv, sizeof(cdv));
287 
288 			cdv[0].buf = &s->config;
289 			cdv[0].len = sizeof(s->config);
290 
291 			if (s->config.TargetName) {
292 				cdv[1].buf = s->config.TargetName;
293 				cdv[1].len =
294 				    strlen(s->config.TargetName) + 1;
295 			}
296 			if (s->config.InitiatorName) {
297 				cdv[2].buf = s->config.InitiatorName;
298 				cdv[2].len =
299 				    strlen(s->config.InitiatorName) + 1;
300 			}
301 
302 			control_build(ch, CTRL_SESSION_CONFIG,
303 			    nitems(cdv), cdv);
304 		}
305 
306 		control_compose(ch, CTRL_SUCCESS, NULL, 0);
307 		break;
308 	case CTRL_SESS_POLL:
309 		TAILQ_FOREACH(s, &initiator->sessions, entry)
310 			poll_session(&p, s);
311 		poll_finalize(&p);
312 		control_compose(ch, CTRL_SESS_POLL, &p, sizeof(p));
313 		break;
314 	default:
315 		log_warnx("unknown control message type %d", cmh->type);
316 		control_compose(ch, CTRL_FAILURE, NULL, 0);
317 		break;
318 	}
319 
320 done:
321 	pdu_free(pdu);
322 }
323 
324 #define MERGE_MIN(r, a, b, v)				\
325 	r->v = (a->v < b->v ? a->v : b->v)
326 #define MERGE_MAX(r, a, b, v)				\
327 	r->v = (a->v > b->v ? a->v : b->v)
328 #define MERGE_OR(r, a, b, v)				\
329 	r->v = (a->v || b->v)
330 #define MERGE_AND(r, a, b, v)				\
331 	r->v = (a->v && b->v)
332 
333 void
334 iscsi_merge_sess_params(struct session_params *res,
335     struct session_params *mine, struct session_params *his)
336 {
337 	MERGE_MIN(res, mine, his, MaxBurstLength);
338 	MERGE_MIN(res, mine, his, FirstBurstLength);
339 	MERGE_MAX(res, mine, his, DefaultTime2Wait);
340 	MERGE_MIN(res, mine, his, DefaultTime2Retain);
341 	MERGE_MIN(res, mine, his, MaxOutstandingR2T);
342 	res->TargetPortalGroupTag = his->TargetPortalGroupTag;
343 	MERGE_MIN(res, mine, his, MaxConnections);
344 	MERGE_OR(res, mine, his, InitialR2T);
345 	MERGE_AND(res, mine, his, ImmediateData);
346 	MERGE_OR(res, mine, his, DataPDUInOrder);
347 	MERGE_OR(res, mine, his, DataSequenceInOrder);
348 	MERGE_MIN(res, mine, his, ErrorRecoveryLevel);
349 
350 }
351 
352 void
353 iscsi_merge_conn_params(struct connection_params *res,
354     struct connection_params *mine, struct connection_params *his)
355 {
356 	res->MaxRecvDataSegmentLength = his->MaxRecvDataSegmentLength;
357 	/* XXX HeaderDigest and DataDigest */
358 }
359 
360 #undef MERGE_MIN
361 #undef MERGE_MAX
362 #undef MERGE_OR
363 #undef MERGE_AND
364