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