GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/iscsid/iscsid.c Lines: 0 153 0.0 %
Date: 2017-11-07 Branches: 0 81 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: iscsid.c,v 1.20 2017/01/23 08:40:07 benno 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
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
	int *valp;
215
216
	cmh = pdu_getbuf(pdu, NULL, 0);
217
	if (cmh == NULL)
218
		goto done;
219
220
	switch (cmh->type) {
221
	case CTRL_INITIATOR_CONFIG:
222
		if (cmh->len[0] != sizeof(*ic)) {
223
			log_warnx("CTRL_INITIATOR_CONFIG bad size");
224
			control_compose(ch, CTRL_FAILURE, NULL, 0);
225
			break;
226
		}
227
		ic = pdu_getbuf(pdu, NULL, 1);
228
		memcpy(&initiator->config, ic, sizeof(initiator->config));
229
		control_compose(ch, CTRL_SUCCESS, NULL, 0);
230
		break;
231
	case CTRL_SESSION_CONFIG:
232
		if (cmh->len[0] != sizeof(*sc)) {
233
			log_warnx("CTRL_SESSION_CONFIG bad size");
234
			control_compose(ch, CTRL_FAILURE, NULL, 0);
235
			break;
236
		}
237
		sc = pdu_getbuf(pdu, NULL, 1);
238
		if (cmh->len[1])
239
			sc->TargetName = pdu_getbuf(pdu, NULL, 2);
240
		else if (sc->SessionType != SESSION_TYPE_DISCOVERY) {
241
			control_compose(ch, CTRL_FAILURE, NULL, 0);
242
			goto done;
243
		} else
244
			sc->TargetName = NULL;
245
		if (cmh->len[2])
246
			sc->InitiatorName = pdu_getbuf(pdu, NULL, 3);
247
		else
248
			sc->InitiatorName = NULL;
249
250
		s = session_find(initiator, sc->SessionName);
251
		if (s == NULL) {
252
			s = session_new(initiator, sc->SessionType);
253
			if (s == NULL) {
254
				control_compose(ch, CTRL_FAILURE, NULL, 0);
255
				goto done;
256
			}
257
		}
258
259
		session_config(s, sc);
260
		if (s->state == SESS_INIT)
261
			session_fsm(s, SESS_EV_START, NULL, 0);
262
263
		control_compose(ch, CTRL_SUCCESS, NULL, 0);
264
		break;
265
	case CTRL_LOG_VERBOSE:
266
		if (cmh->len[0] != sizeof(int)) {
267
			log_warnx("CTRL_LOG_VERBOSE bad size");
268
			control_compose(ch, CTRL_FAILURE, NULL, 0);
269
			break;
270
		}
271
		valp = pdu_getbuf(pdu, NULL, 1);
272
		log_verbose(*valp);
273
		control_compose(ch, CTRL_SUCCESS, NULL, 0);
274
		break;
275
	case CTRL_VSCSI_STATS:
276
		control_compose(ch, CTRL_VSCSI_STATS, vscsi_stats(),
277
		    sizeof(struct vscsi_stats));
278
		break;
279
	case CTRL_SHOW_SUM:
280
		control_compose(ch, CTRL_INITIATOR_CONFIG, &initiator->config,
281
		    sizeof(initiator->config));
282
283
		TAILQ_FOREACH(s, &initiator->sessions, entry) {
284
			struct ctrldata cdv[3];
285
			bzero(cdv, sizeof(cdv));
286
287
			cdv[0].buf = &s->config;
288
			cdv[0].len = sizeof(s->config);
289
290
			if (s->config.TargetName) {
291
				cdv[1].buf = s->config.TargetName;
292
				cdv[1].len =
293
				    strlen(s->config.TargetName) + 1;
294
			}
295
			if (s->config.InitiatorName) {
296
				cdv[2].buf = s->config.InitiatorName;
297
				cdv[2].len =
298
				    strlen(s->config.InitiatorName) + 1;
299
			}
300
301
			control_build(ch, CTRL_SESSION_CONFIG,
302
			    nitems(cdv), cdv);
303
		}
304
305
		control_compose(ch, CTRL_SUCCESS, NULL, 0);
306
		break;
307
	default:
308
		log_warnx("unknown control message type %d", cmh->type);
309
		control_compose(ch, CTRL_FAILURE, NULL, 0);
310
		break;
311
	}
312
313
done:
314
	pdu_free(pdu);
315
}
316
317
#define MERGE_MIN(r, a, b, v)				\
318
	r->v = (a->v < b->v ? a->v : b->v)
319
#define MERGE_MAX(r, a, b, v)				\
320
	r->v = (a->v > b->v ? a->v : b->v)
321
#define MERGE_OR(r, a, b, v)				\
322
	r->v = (a->v || b->v)
323
#define MERGE_AND(r, a, b, v)				\
324
	r->v = (a->v && b->v)
325
326
void
327
iscsi_merge_sess_params(struct session_params *res,
328
    struct session_params *mine, struct session_params *his)
329
{
330
	MERGE_MIN(res, mine, his, MaxBurstLength);
331
	MERGE_MIN(res, mine, his, FirstBurstLength);
332
	MERGE_MAX(res, mine, his, DefaultTime2Wait);
333
	MERGE_MIN(res, mine, his, DefaultTime2Retain);
334
	MERGE_MIN(res, mine, his, MaxOutstandingR2T);
335
	res->TargetPortalGroupTag = his->TargetPortalGroupTag;
336
	MERGE_MIN(res, mine, his, MaxConnections);
337
	MERGE_OR(res, mine, his, InitialR2T);
338
	MERGE_AND(res, mine, his, ImmediateData);
339
	MERGE_OR(res, mine, his, DataPDUInOrder);
340
	MERGE_OR(res, mine, his, DataSequenceInOrder);
341
	MERGE_MIN(res, mine, his, ErrorRecoveryLevel);
342
343
}
344
345
void
346
iscsi_merge_conn_params(struct connection_params *res,
347
    struct connection_params *mine, struct connection_params *his)
348
{
349
	res->MaxRecvDataSegmentLength = his->MaxRecvDataSegmentLength;
350
	/* XXX HeaderDigest and DataDigest */
351
}
352
353
#undef MERGE_MIN
354
#undef MERGE_MAX
355
#undef MERGE_OR
356
#undef MERGE_AND