• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/ubus/ubusd_main.c

  1 /*
  2  * Copyright (C) 2011-2014 Felix Fietkau <nbd@openwrt.org>
  3  *
  4  * SPDX-License-Identifier: LGPL-2.1-only
  5  */
  6 
  7 #define _GNU_SOURCE
  8 
  9 #include <sys/socket.h>
 10 #include <sys/stat.h>
 11 #include <sys/types.h>
 12 #ifdef FreeBSD
 13 #include <sys/param.h>
 14 #endif
 15 #include <fcntl.h>
 16 #include <string.h>
 17 #include <syslog.h>
 18 
 19 #include <libubox/usock.h>
 20 
 21 #include "ubusd.h"
 22 
 23 static void ubus_client_cmd_free(struct ubus_client_cmd *cmd);
 24 
 25 static void handle_client_disconnect(struct ubus_client *cl)
 26 {
 27         struct ubus_msg_buf_list *ubl, *ubl2;
 28         struct ubus_client_cmd *cmd, *cmd2;
 29 
 30         list_for_each_entry_safe(cmd, cmd2, &cl->cmd_queue, list)
 31                 ubus_client_cmd_free(cmd);
 32 
 33         ubusd_monitor_disconnect(cl);
 34         ubusd_proto_free_client(cl);
 35 
 36         /*
 37          * Freeing the client's objects above can queue new messages for the
 38          * disconnecting client itself (e.g. the subscribers-gone notification
 39          * sent by ubus_unsubscribe), so the tx queue must be flushed last.
 40          */
 41         list_for_each_entry_safe(ubl, ubl2, &cl->tx_queue, list)
 42                 ubus_msg_list_free(ubl);
 43         if (cl->pending_msg_fd >= 0)
 44                 close(cl->pending_msg_fd);
 45         if (cl->pending_msg)
 46                 ubus_msg_free(cl->pending_msg);
 47         uloop_fd_delete(&cl->sock);
 48         close(cl->sock.fd);
 49         free(cl);
 50 }
 51 
 52 static void ubus_client_cmd_free(struct ubus_client_cmd *cmd)
 53 {
 54         list_del(&cmd->list);
 55         ubus_msg_free(cmd->msg);
 56         free(cmd->lookup_path);
 57         free(cmd);
 58 }
 59 
 60 static void ubus_client_cmd_queue_process(struct ubus_client *cl)
 61 {
 62         struct ubus_client_cmd *cmd, *tmp;
 63 
 64         list_for_each_entry_safe(cmd, tmp, &cl->cmd_queue, list) {
 65                 int ret = ubusd_cmd_lookup(cl, cmd);
 66 
 67                 /* Stop if the last command caused buffering again */
 68                 if (ret == -2)
 69                         break;
 70 
 71                 ubus_client_cmd_free(cmd);
 72         }
 73 }
 74 
 75 static int ubusd_recv_fd(struct msghdr *msghdr)
 76 {
 77         struct cmsghdr *cmsg;
 78 
 79         for (cmsg = CMSG_FIRSTHDR(msghdr); cmsg; cmsg = CMSG_NXTHDR(msghdr, cmsg)) {
 80                 if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS)
 81                         continue;
 82                 if (cmsg->cmsg_len < CMSG_LEN(sizeof(int)))
 83                         continue;
 84 
 85                 return *(int *) CMSG_DATA(cmsg);
 86         }
 87 
 88         return -1;
 89 }
 90 
 91 static void client_cb(struct uloop_fd *sock, unsigned int events)
 92 {
 93         struct ubus_client *cl = container_of(sock, struct ubus_client, sock);
 94         uint8_t fd_buf[CMSG_SPACE(sizeof(int))] = { 0 };
 95         struct msghdr msghdr = { 0 };
 96         struct ubus_msg_buf *ub;
 97         struct ubus_msg_buf_list *ubl, *ubl2;
 98         static struct iovec iov;
 99 
100         msghdr.msg_iov = &iov;
101         msghdr.msg_iovlen = 1;
102 
103         /* first try to tx more pending data */
104         list_for_each_entry_safe(ubl, ubl2, &cl->tx_queue, list) {
105                 ssize_t written;
106 
107                 ub = ubl->msg;
108 retry_writev:
109                 written = ubus_msg_writev(sock->fd, ub, cl->txq_ofs);
110                 if (written < 0) {
111                         switch(errno) {
112                         case EINTR:
113                                 goto retry_writev;
114                         case EAGAIN:
115                         case EACCES:
116                                 break;
117                         default:
118                                 goto disconnect;
119                         }
120                         break;
121                 }
122 
123                 cl->txq_ofs += written;
124                 cl->txq_len -= written;
125                 if (cl->txq_ofs < ub->len + sizeof(ub->hdr))
126                         goto retry_writev;
127 
128                 cl->txq_ofs = 0;
129                 ubus_msg_list_free(ubl);
130         }
131 
132         if (list_empty(&cl->tx_queue) && (events & ULOOP_WRITE)) {
133                 /* Process queued commands */
134                 ubus_client_cmd_queue_process(cl);
135 
136                 /* prevent further ULOOP_WRITE events if we don't have data
137                  * to send anymore */
138                 if (list_empty(&cl->tx_queue))
139                         uloop_fd_add(sock, ULOOP_READ | ULOOP_EDGE_TRIGGER);
140         }
141 
142 retry:
143         if (!sock->eof && cl->pending_msg_offset < (int) sizeof(cl->hdrbuf)) {
144                 int offset = cl->pending_msg_offset;
145                 int bytes;
146 
147                 iov.iov_base = ((char *) &cl->hdrbuf) + offset;
148                 iov.iov_len = sizeof(cl->hdrbuf) - offset;
149 
150                 msghdr.msg_control = fd_buf;
151                 msghdr.msg_controllen = cl->pending_msg_fd < 0 ? sizeof(fd_buf) : 0;
152 
153                 bytes = recvmsg(sock->fd, &msghdr, 0);
154                 if (bytes < 0)
155                         goto out;
156 
157                 if (cl->pending_msg_fd < 0) {
158                         int fd = ubusd_recv_fd(&msghdr);
159 
160                         if (fd >= 0)
161                                 cl->pending_msg_fd = fd;
162                 }
163 
164                 cl->pending_msg_offset += bytes;
165                 if (cl->pending_msg_offset < (int) sizeof(cl->hdrbuf))
166                         goto out;
167 
168                 if (blob_raw_len(&cl->hdrbuf.data) < sizeof(struct blob_attr))
169                         goto disconnect;
170                 if (blob_pad_len(&cl->hdrbuf.data) > UBUS_MAX_MSGLEN)
171                         goto disconnect;
172 
173                 cl->pending_msg = ubus_msg_new(NULL, blob_raw_len(&cl->hdrbuf.data), false);
174                 if (!cl->pending_msg)
175                         goto disconnect;
176 
177                 cl->hdrbuf.hdr.seq = be16_to_cpu(cl->hdrbuf.hdr.seq);
178                 cl->hdrbuf.hdr.peer = be32_to_cpu(cl->hdrbuf.hdr.peer);
179 
180                 memcpy(&cl->pending_msg->hdr, &cl->hdrbuf.hdr, sizeof(cl->hdrbuf.hdr));
181                 memcpy(cl->pending_msg->data, &cl->hdrbuf.data, sizeof(cl->hdrbuf.data));
182         }
183 
184         ub = cl->pending_msg;
185         if (ub) {
186                 /*
187                  * offset and len derive from client-controlled input, but the
188                  * read stays within bounds: ub->data was allocated with exactly
189                  * blob_raw_len(ub->data) bytes (already capped at UBUS_MAX_MSGLEN
190                  * when the header was received), and offset only grows until it
191                  * reaches that total, at which point the message is accepted and
192                  * pending_msg is reset below. So offset <= blob_raw_len(ub->data)
193                  * and offset + len never exceed the allocation.
194                  */
195                 int offset = cl->pending_msg_offset - sizeof(ub->hdr);
196                 int len = blob_raw_len(ub->data) - offset;
197                 int bytes = 0;
198 
199                 if (len > 0) {
200                         bytes = read(sock->fd, (char *) ub->data + offset, len);
201                         if (bytes <= 0)
202                                 goto out;
203                 }
204 
205                 if (bytes < len) {
206                         cl->pending_msg_offset += bytes;
207                         goto out;
208                 }
209 
210                 /* accept message */
211                 ub->fd = cl->pending_msg_fd;
212                 cl->pending_msg_fd = -1;
213                 cl->pending_msg_offset = 0;
214                 cl->pending_msg = NULL;
215                 ubusd_monitor_message(cl, ub, false);
216                 ubusd_proto_receive_message(cl, ub);
217                 goto retry;
218         }
219 
220 out:
221         if (!sock->eof || !list_empty(&cl->tx_queue))
222                 return;
223 
224 disconnect:
225         handle_client_disconnect(cl);
226 }
227 
228 static bool get_next_connection(int fd)
229 {
230         struct ubus_client *cl;
231         int client_fd;
232 
233         client_fd = accept(fd, NULL, 0);
234         if (client_fd < 0) {
235                 switch (errno) {
236                 case ECONNABORTED:
237                 case EINTR:
238                         return true;
239                 default:
240                         return false;
241                 }
242         }
243 
244         cl = ubusd_proto_new_client(client_fd, client_cb);
245         if (cl)
246                 uloop_fd_add(&cl->sock, ULOOP_READ | ULOOP_EDGE_TRIGGER);
247         else
248                 close(client_fd);
249 
250         return true;
251 }
252 
253 static void server_cb(struct uloop_fd *fd, unsigned int events)
254 {
255         bool next;
256 
257         do {
258                 next = get_next_connection(fd->fd);
259         } while (next);
260 }
261 
262 static struct uloop_fd server_fd = {
263         .cb = server_cb,
264 };
265 
266 static int usage(const char *progname)
267 {
268         fprintf(stderr, "Usage: %s [<options>]\n"
269                 "Options: \n"
270                 "  -A <path>:           Set the path to ACL files\n"
271                 "  -s <socket>:         Set the unix domain socket to listen on\n"
272                 "\n", progname);
273         return 1;
274 }
275 
276 static int sighup_pipe[2] = { -1, -1 };
277 
278 static void sighup_handler(int sig)
279 {
280         int saved_errno = errno;
281         char c = 0;
282         ssize_t r = write(sighup_pipe[1], &c, sizeof(c));
283         (void)r;
284         errno = saved_errno;
285 }
286 
287 static void sighup_fd_cb(struct uloop_fd *ufd, unsigned int events)
288 {
289         char buf[16];
290         while (read(ufd->fd, buf, sizeof(buf)) > 0)
291                 ;
292         ubusd_acl_load();
293 }
294 
295 static struct uloop_fd sighup_ufd = {
296         .cb = sighup_fd_cb,
297 };
298 
299 /*
300  * Best effort only: the -s option may point somewhere else entirely, and
301  * usock() reports a clear error if the requested socket path is unusable.
302  */
303 static void mkdir_sockdir(void)
304 {
305         char *ubus_sock_dir, *tmp;
306 
307         ubus_sock_dir = strdup(UBUS_UNIX_SOCKET);
308         if (!ubus_sock_dir)
309                 return;
310 
311         tmp = strrchr(ubus_sock_dir, '/');
312         if (tmp) {
313                 *tmp = '\0';
314                 if (mkdir(ubus_sock_dir, 0755) && errno == EEXIST) {
315                         struct stat st;
316 
317                         if (stat(ubus_sock_dir, &st) || !S_ISDIR(st.st_mode))
318                                 fprintf(stderr, "%s exists but is not a directory\n",
319                                         ubus_sock_dir);
320                 }
321         }
322 
323         free(ubus_sock_dir);
324 }
325 
326 #include <libubox/ulog.h>
327 
328 int main(int argc, char **argv)
329 {
330         const char *ubus_socket = UBUS_UNIX_SOCKET;
331         int ret = 0;
332         int ch;
333 
334         signal(SIGPIPE, SIG_IGN);
335 
336 #ifdef __linux__
337         ret = pipe2(sighup_pipe, O_NONBLOCK | O_CLOEXEC);
338 #else
339         ret = pipe(sighup_pipe);
340         if (ret == 0) {
341                 fcntl(sighup_pipe[0], F_SETFL, O_NONBLOCK);
342                 fcntl(sighup_pipe[0], F_SETFD, FD_CLOEXEC);
343                 fcntl(sighup_pipe[1], F_SETFL, O_NONBLOCK);
344                 fcntl(sighup_pipe[1], F_SETFD, FD_CLOEXEC);
345         }
346 #endif
347         if (ret == 0)
348                 signal(SIGHUP, sighup_handler);
349         else
350                 signal(SIGHUP, SIG_IGN);
351 
352         ulog_open(ULOG_KMSG | ULOG_SYSLOG, LOG_DAEMON, "ubusd");
353         openlog("ubusd", LOG_PID, LOG_DAEMON);
354         uloop_init();
355 
356         if (sighup_pipe[0] >= 0) {
357                 sighup_ufd.fd = sighup_pipe[0];
358                 uloop_fd_add(&sighup_ufd, ULOOP_READ);
359         }
360 
361         while ((ch = getopt(argc, argv, "A:s:")) != -1) {
362                 switch (ch) {
363                 case 's':
364                         ubus_socket = optarg;
365                         break;
366                 case 'A':
367                         ubusd_acl_dir = optarg;
368                         break;
369                 default:
370                         return usage(argv[0]);
371                 }
372         }
373 
374         mkdir_sockdir();
375         unlink(ubus_socket);
376         umask(0111);
377         server_fd.fd = usock(USOCK_UNIX | USOCK_SERVER | USOCK_NONBLOCK, ubus_socket, NULL);
378         if (server_fd.fd < 0) {
379                 perror("usock");
380                 ret = -1;
381                 goto out;
382         }
383         uloop_fd_add(&server_fd, ULOOP_READ | ULOOP_EDGE_TRIGGER);
384         ubusd_acl_load();
385 
386         uloop_run();
387         unlink(ubus_socket);
388 
389 out:
390         uloop_done();
391         return ret;
392 }
393 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt