1*5b133f3fSguenther /* $OpenBSD: control.c,v 1.11 2023/03/08 04:43:13 guenther Exp $ */
2bde1ae23Sclaudio
3bde1ae23Sclaudio /*
4bde1ae23Sclaudio * Copyright (c) 2010 Claudio Jeker <claudio@openbsd.org>
5bde1ae23Sclaudio * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
6bde1ae23Sclaudio *
7bde1ae23Sclaudio * Permission to use, copy, modify, and distribute this software for any
8bde1ae23Sclaudio * purpose with or without fee is hereby granted, provided that the above
9bde1ae23Sclaudio * copyright notice and this permission notice appear in all copies.
10bde1ae23Sclaudio *
11bde1ae23Sclaudio * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12bde1ae23Sclaudio * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13bde1ae23Sclaudio * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14bde1ae23Sclaudio * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15bde1ae23Sclaudio * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16bde1ae23Sclaudio * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17bde1ae23Sclaudio * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18bde1ae23Sclaudio */
19bde1ae23Sclaudio
20bde1ae23Sclaudio #include <sys/types.h>
21bde1ae23Sclaudio #include <sys/queue.h>
22bde1ae23Sclaudio #include <sys/stat.h>
23bde1ae23Sclaudio #include <sys/socket.h>
24bde1ae23Sclaudio #include <sys/uio.h>
25bde1ae23Sclaudio #include <sys/un.h>
26bde1ae23Sclaudio #include <errno.h>
27bde1ae23Sclaudio #include <event.h>
28bde1ae23Sclaudio #include <fcntl.h>
29bde1ae23Sclaudio #include <stdlib.h>
30bde1ae23Sclaudio #include <string.h>
31bde1ae23Sclaudio #include <unistd.h>
32bde1ae23Sclaudio
33bde1ae23Sclaudio #include "iscsid.h"
34bde1ae23Sclaudio #include "log.h"
35bde1ae23Sclaudio
36bde1ae23Sclaudio struct control {
37bde1ae23Sclaudio struct event ev;
38bde1ae23Sclaudio struct pduq channel;
39bde1ae23Sclaudio int fd;
40f74bd295Sclaudio };
41f74bd295Sclaudio
42f74bd295Sclaudio struct control_state {
43f74bd295Sclaudio struct event ev;
44f74bd295Sclaudio struct event evt;
45f74bd295Sclaudio int fd;
46bde1ae23Sclaudio } *control_state;
47bde1ae23Sclaudio
48bde1ae23Sclaudio #define CONTROL_BACKLOG 5
49bde1ae23Sclaudio
50bde1ae23Sclaudio void control_accept(int, short, void *);
51bde1ae23Sclaudio void control_close(struct control *);
52bde1ae23Sclaudio void control_dispatch(int, short, void *);
53bde1ae23Sclaudio struct pdu *control_getpdu(char *, size_t);
54bde1ae23Sclaudio
55bde1ae23Sclaudio int
control_init(char * path)56bde1ae23Sclaudio control_init(char *path)
57bde1ae23Sclaudio {
58bde1ae23Sclaudio struct sockaddr_un sun;
59bde1ae23Sclaudio int fd;
60bde1ae23Sclaudio mode_t old_umask;
61bde1ae23Sclaudio
62bde1ae23Sclaudio if ((control_state = calloc(1, sizeof(*control_state))) == NULL) {
63bde1ae23Sclaudio log_warn("control_init: calloc");
64be16f395Sclaudio return -1;
65bde1ae23Sclaudio }
66bde1ae23Sclaudio
67f73922b8Sclaudio if ((fd = socket(AF_UNIX, SOCK_SEQPACKET, 0)) == -1) {
68bde1ae23Sclaudio log_warn("control_init: socket");
69be16f395Sclaudio return -1;
70bde1ae23Sclaudio }
71bde1ae23Sclaudio
72bde1ae23Sclaudio bzero(&sun, sizeof(sun));
73bde1ae23Sclaudio sun.sun_family = AF_UNIX;
74be16f395Sclaudio if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >=
75be16f395Sclaudio sizeof(sun.sun_path)) {
76be16f395Sclaudio log_warnx("control_init: path %s too long", path);
7775b6a596Sjsg close(fd);
78be16f395Sclaudio return -1;
79be16f395Sclaudio }
80bde1ae23Sclaudio
81bde1ae23Sclaudio if (unlink(path) == -1)
82bde1ae23Sclaudio if (errno != ENOENT) {
83bde1ae23Sclaudio log_warn("control_init: unlink %s", path);
84bde1ae23Sclaudio close(fd);
85be16f395Sclaudio return -1;
86bde1ae23Sclaudio }
87bde1ae23Sclaudio
88bde1ae23Sclaudio old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
89bde1ae23Sclaudio if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
90bde1ae23Sclaudio log_warn("control_init: bind: %s", path);
91bde1ae23Sclaudio close(fd);
92bde1ae23Sclaudio umask(old_umask);
93be16f395Sclaudio return -1;
94bde1ae23Sclaudio }
95bde1ae23Sclaudio umask(old_umask);
96bde1ae23Sclaudio
97bde1ae23Sclaudio if (chmod(path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) {
98bde1ae23Sclaudio log_warn("control_init: chmod");
99bde1ae23Sclaudio close(fd);
100bde1ae23Sclaudio (void)unlink(path);
101be16f395Sclaudio return -1;
102bde1ae23Sclaudio }
103bde1ae23Sclaudio
10477822a85Sclaudio if (listen(fd, CONTROL_BACKLOG) == -1) {
10577822a85Sclaudio log_warn("control_init: listen");
10677822a85Sclaudio close(fd);
10777822a85Sclaudio (void)unlink(path);
108be16f395Sclaudio return -1;
10977822a85Sclaudio }
11077822a85Sclaudio
111bde1ae23Sclaudio socket_setblockmode(fd, 1);
112bde1ae23Sclaudio control_state->fd = fd;
113bde1ae23Sclaudio
114be16f395Sclaudio return 0;
115bde1ae23Sclaudio }
116bde1ae23Sclaudio
117bde1ae23Sclaudio void
control_cleanup(char * path)118bde1ae23Sclaudio control_cleanup(char *path)
119bde1ae23Sclaudio {
120bde1ae23Sclaudio if (path)
121bde1ae23Sclaudio unlink(path);
122bde1ae23Sclaudio
123f74bd295Sclaudio event_del(&control_state->ev);
124f74bd295Sclaudio event_del(&control_state->evt);
125f74bd295Sclaudio close(control_state->fd);
126f74bd295Sclaudio free(control_state);
127bde1ae23Sclaudio }
128bde1ae23Sclaudio
12977822a85Sclaudio void
control_event_init(void)13077822a85Sclaudio control_event_init(void)
131bde1ae23Sclaudio {
132f74bd295Sclaudio event_set(&control_state->ev, control_state->fd, EV_READ,
133bde1ae23Sclaudio control_accept, NULL);
134bde1ae23Sclaudio event_add(&control_state->ev, NULL);
135f74bd295Sclaudio evtimer_set(&control_state->evt, control_accept, NULL);
136bde1ae23Sclaudio }
137bde1ae23Sclaudio
138bde1ae23Sclaudio void
control_accept(int listenfd,short event,void * bula)139bde1ae23Sclaudio control_accept(int listenfd, short event, void *bula)
140bde1ae23Sclaudio {
141bde1ae23Sclaudio int connfd;
142bde1ae23Sclaudio socklen_t len;
143bde1ae23Sclaudio struct sockaddr_un sun;
144bde1ae23Sclaudio struct control *c;
145bde1ae23Sclaudio
146f74bd295Sclaudio event_add(&control_state->ev, NULL);
147f74bd295Sclaudio if ((event & EV_TIMEOUT))
148f74bd295Sclaudio return;
149f74bd295Sclaudio
150bde1ae23Sclaudio len = sizeof(sun);
151bde1ae23Sclaudio if ((connfd = accept(listenfd,
152bde1ae23Sclaudio (struct sockaddr *)&sun, &len)) == -1) {
153f74bd295Sclaudio /*
154f74bd295Sclaudio * Pause accept if we are out of file descriptors, or
155f74bd295Sclaudio * libevent will haunt us here too.
156f74bd295Sclaudio */
157f74bd295Sclaudio if (errno == ENFILE || errno == EMFILE) {
158f74bd295Sclaudio struct timeval evtpause = { 1, 0 };
159f74bd295Sclaudio
160f74bd295Sclaudio event_del(&control_state->ev);
161f74bd295Sclaudio evtimer_add(&control_state->evt, &evtpause);
16262e3c252Sderaadt } else if (errno != EWOULDBLOCK && errno != EINTR &&
16362e3c252Sderaadt errno != ECONNABORTED)
164bde1ae23Sclaudio log_warn("control_accept");
165bde1ae23Sclaudio return;
166bde1ae23Sclaudio }
167bde1ae23Sclaudio
168bde1ae23Sclaudio if ((c = malloc(sizeof(struct control))) == NULL) {
169bde1ae23Sclaudio log_warn("control_accept");
170bde1ae23Sclaudio close(connfd);
171bde1ae23Sclaudio return;
172bde1ae23Sclaudio }
173bde1ae23Sclaudio
174bde1ae23Sclaudio TAILQ_INIT(&c->channel);
175bde1ae23Sclaudio c->fd = connfd;
176bde1ae23Sclaudio event_set(&c->ev, connfd, EV_READ, control_dispatch, c);
177bde1ae23Sclaudio event_add(&c->ev, NULL);
178bde1ae23Sclaudio }
179bde1ae23Sclaudio
180bde1ae23Sclaudio void
control_close(struct control * c)181bde1ae23Sclaudio control_close(struct control *c)
182bde1ae23Sclaudio {
183bde1ae23Sclaudio event_del(&c->ev);
184f74bd295Sclaudio close(c->fd);
185f74bd295Sclaudio
186f74bd295Sclaudio /* Some file descriptors are available again. */
187f74bd295Sclaudio if (evtimer_pending(&control_state->evt, NULL)) {
188f74bd295Sclaudio evtimer_del(&control_state->evt);
189f74bd295Sclaudio event_add(&control_state->ev, NULL);
190f74bd295Sclaudio }
191f74bd295Sclaudio
192bde1ae23Sclaudio pdu_free_queue(&c->channel);
193bde1ae23Sclaudio free(c);
194bde1ae23Sclaudio }
195bde1ae23Sclaudio
196bde1ae23Sclaudio static char cbuf[CONTROL_READ_SIZE];
197bde1ae23Sclaudio
198bde1ae23Sclaudio void
control_dispatch(int fd,short event,void * bula)199bde1ae23Sclaudio control_dispatch(int fd, short event, void *bula)
200bde1ae23Sclaudio {
201bde1ae23Sclaudio struct iovec iov[PDU_MAXIOV];
202bde1ae23Sclaudio struct msghdr msg;
203bde1ae23Sclaudio struct control *c = bula;
204bde1ae23Sclaudio struct pdu *pdu;
205bde1ae23Sclaudio ssize_t n;
206bde1ae23Sclaudio unsigned int niov = 0;
207bde1ae23Sclaudio short flags = EV_READ;
208bde1ae23Sclaudio
209bde1ae23Sclaudio if (event & EV_TIMEOUT) {
210bde1ae23Sclaudio log_debug("control connection (fd %d) timed out.", fd);
211bde1ae23Sclaudio control_close(c);
212bde1ae23Sclaudio return;
213bde1ae23Sclaudio }
214bde1ae23Sclaudio if (event & EV_READ) {
215bde1ae23Sclaudio if ((n = recv(fd, cbuf, sizeof(cbuf), 0)) == -1 &&
216bde1ae23Sclaudio !(errno == EAGAIN || errno == EINTR)) {
217bde1ae23Sclaudio control_close(c);
218bde1ae23Sclaudio return;
219bde1ae23Sclaudio }
220bde1ae23Sclaudio if (n == 0) {
221bde1ae23Sclaudio control_close(c);
222bde1ae23Sclaudio return;
223bde1ae23Sclaudio }
224bde1ae23Sclaudio pdu = control_getpdu(cbuf, n);
225bde1ae23Sclaudio if (!pdu) {
226bde1ae23Sclaudio log_debug("control connection (fd %d) bad msg.", fd);
227bde1ae23Sclaudio control_close(c);
228bde1ae23Sclaudio return;
229bde1ae23Sclaudio }
230bde1ae23Sclaudio iscsid_ctrl_dispatch(c, pdu);
231bde1ae23Sclaudio }
232bde1ae23Sclaudio if (event & EV_WRITE) {
233bde1ae23Sclaudio if ((pdu = TAILQ_FIRST(&c->channel)) != NULL) {
234bde1ae23Sclaudio for (niov = 0; niov < PDU_MAXIOV; niov++) {
235bde1ae23Sclaudio iov[niov].iov_base = pdu->iov[niov].iov_base;
236bde1ae23Sclaudio iov[niov].iov_len = pdu->iov[niov].iov_len;
237bde1ae23Sclaudio }
238bde1ae23Sclaudio bzero(&msg, sizeof(msg));
239bde1ae23Sclaudio msg.msg_iov = iov;
240bde1ae23Sclaudio msg.msg_iovlen = niov;
241f73922b8Sclaudio if (sendmsg(fd, &msg, 0) == -1) {
242f73922b8Sclaudio if (errno == EAGAIN || errno == ENOBUFS)
243f73922b8Sclaudio goto requeue;
244bde1ae23Sclaudio control_close(c);
245bde1ae23Sclaudio return;
246bde1ae23Sclaudio }
247f73922b8Sclaudio TAILQ_REMOVE(&c->channel, pdu, entry);
248bde1ae23Sclaudio }
249bde1ae23Sclaudio }
250f73922b8Sclaudio requeue:
251bde1ae23Sclaudio if (!TAILQ_EMPTY(&c->channel))
252bde1ae23Sclaudio flags |= EV_WRITE;
253bde1ae23Sclaudio
254bde1ae23Sclaudio event_del(&c->ev);
255bde1ae23Sclaudio event_set(&c->ev, fd, flags, control_dispatch, c);
256bde1ae23Sclaudio event_add(&c->ev, NULL);
257bde1ae23Sclaudio }
258bde1ae23Sclaudio
259bde1ae23Sclaudio struct pdu *
control_getpdu(char * buf,size_t len)260bde1ae23Sclaudio control_getpdu(char *buf, size_t len)
261bde1ae23Sclaudio {
262bde1ae23Sclaudio struct pdu *p;
263bde1ae23Sclaudio struct ctrlmsghdr *cmh;
264bde1ae23Sclaudio void *data;
265bde1ae23Sclaudio size_t n;
266bde1ae23Sclaudio int i;
267bde1ae23Sclaudio
268bde1ae23Sclaudio if (len < sizeof(*cmh))
269bde1ae23Sclaudio return NULL;
270bde1ae23Sclaudio
271bde1ae23Sclaudio if (!(p = pdu_new()))
272bde1ae23Sclaudio return NULL;
273bde1ae23Sclaudio
274bde1ae23Sclaudio n = sizeof(*cmh);
275bde1ae23Sclaudio cmh = pdu_alloc(n);
276a86db512Sclaudio memcpy(cmh, buf, n);
277bde1ae23Sclaudio buf += n;
278bde1ae23Sclaudio len -= n;
279bde1ae23Sclaudio
280bde1ae23Sclaudio if (pdu_addbuf(p, cmh, n, 0)) {
281bde1ae23Sclaudio free(cmh);
282bde1ae23Sclaudio fail:
283bde1ae23Sclaudio pdu_free(p);
284bde1ae23Sclaudio return NULL;
285bde1ae23Sclaudio }
286bde1ae23Sclaudio
287bde1ae23Sclaudio for (i = 0; i < 3; i++) {
288bde1ae23Sclaudio n = cmh->len[i];
289bde1ae23Sclaudio if (n == 0)
290bde1ae23Sclaudio continue;
291bde1ae23Sclaudio if (PDU_LEN(n) > len)
292bde1ae23Sclaudio goto fail;
293bde1ae23Sclaudio if (!(data = pdu_alloc(n)))
294bde1ae23Sclaudio goto fail;
295a86db512Sclaudio memcpy(data, buf, n);
296bde1ae23Sclaudio if (pdu_addbuf(p, data, n, i + 1)) {
297bde1ae23Sclaudio free(data);
298bde1ae23Sclaudio goto fail;
299bde1ae23Sclaudio }
300bde1ae23Sclaudio buf += PDU_LEN(n);
301bde1ae23Sclaudio len -= PDU_LEN(n);
302bde1ae23Sclaudio }
303bde1ae23Sclaudio
304bde1ae23Sclaudio return p;
305bde1ae23Sclaudio }
306bde1ae23Sclaudio
307f73922b8Sclaudio void
control_queue(void * ch,struct pdu * pdu)308bde1ae23Sclaudio control_queue(void *ch, struct pdu *pdu)
309bde1ae23Sclaudio {
310bde1ae23Sclaudio struct control *c = ch;
311bde1ae23Sclaudio
312bde1ae23Sclaudio TAILQ_INSERT_TAIL(&c->channel, pdu, entry);
313bde1ae23Sclaudio
314bde1ae23Sclaudio event_del(&c->ev);
315bde1ae23Sclaudio event_set(&c->ev, c->fd, EV_READ|EV_WRITE, control_dispatch, c);
316bde1ae23Sclaudio event_add(&c->ev, NULL);
317bde1ae23Sclaudio }
318