aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--nldev-handler.c80
-rw-r--r--nldev.c133
2 files changed, 88 insertions, 125 deletions
diff --git a/nldev-handler.c b/nldev-handler.c
index 4fa6e2a..f4f7eb4 100644
--- a/nldev-handler.c
+++ b/nldev-handler.c
@@ -1,12 +1,17 @@
+#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+
#include <sys/types.h>
#include <sys/wait.h>
+#include <sys/socket.h>
+
+#include <linux/netlink.h>
#include "log.h"
@@ -33,21 +38,31 @@ child(char *runpath)
void
usage(void)
{
- die("usage: %s [-d] [-r run]\n", argv0);
+ die("usage: %s [-dku] [-f subsystem] [-r run]\n", argv0);
}
int main(int argc, char *argv[])
{
struct pollfd fds;
int r;
- static char buf[16384];
char *runpath = "/bin/mdev";
char *subsystem = NULL;
+ int showudev, showkernel;
+
+ showudev = 1;
+ showkernel = 1;
+
ARGBEGIN {
case 'd':
dodebug = 1;
break;
+ case 'k':
+ showudev = 0;
+ break;
+ case 'u':
+ showkernel = 0;
+ break;
case 'r':
runpath = EARGF(usage());
break;
@@ -66,6 +81,13 @@ int main(int argc, char *argv[])
size_t len;
int i, slen;
char *key, *value;
+ struct iovec iov;
+ char cbuf[CMSG_SPACE(sizeof(struct ucred))];
+ char buf[16384];
+ struct cmsghdr *chdr;
+ struct ucred *cred;
+ struct msghdr hdr;
+ struct sockaddr_nl cnls;
clearenv();
setenv("PATH", "/sbin:/bin", 1);
@@ -73,11 +95,57 @@ int main(int argc, char *argv[])
if (!(fds.revents & POLLIN))
continue;
- len = read(fds.fd, buf, sizeof(buf)-1);
- buf[len] = 0;
- dbg("Got %u bytes", len);
+ iov.iov_base = &buf;
+ iov.iov_len = sizeof(buf);
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.msg_iov = &iov;
+ hdr.msg_iovlen = 1;
+ hdr.msg_control = cbuf;
+ hdr.msg_controllen = sizeof(cbuf);
+ hdr.msg_name = &cnls;
+ hdr.msg_namelen = sizeof(cnls);
+
+ len = recvmsg(fds.fd, &hdr, 0);
+ if (len < 0) {
+ if (errno == EINTR)
+ continue;
+ edie("recvmsg");
+ }
+ if (len < 32 || len >= sizeof(buf))
+ continue;
+
+ chdr = CMSG_FIRSTHDR(&hdr);
+ if (chdr == NULL || chdr->cmsg_type != SCM_CREDENTIALS)
+ continue;
+
+ /*
+ * Don't allow anyone but root to send us messages.
+ *
+ * We will allow users to send us messages, when
+ * udev is enabled. Udev is just a toy you should
+ * only use for testing.
+ */
+ cred = (struct ucred *)CMSG_DATA(chdr);
+ if (cred->uid != 0 && !showudev)
+ continue;
+
+ if (!memcmp(buf, "libudev", 8)) {
+ /*
+ * Receiving messages from udev is insecure.
+ */
+ if (!showudev)
+ continue;
+ } else {
+ if (!showkernel)
+ continue;
+ /*
+ * Kernel messages shouldn't come from the
+ * userspace.
+ */
+ if (cnls.nl_pid > 0)
+ continue;
+ }
- slen = 0;
for (i = 0; i < len; i += slen + 1) {
key = buf + i;
value = strchr(key, '=');
diff --git a/nldev.c b/nldev.c
index a771931..bbc8eb2 100644
--- a/nldev.c
+++ b/nldev.c
@@ -24,44 +24,22 @@
#include "arg.h"
#include "log.h"
-int listfd = -1;
int dofork = 0;
-struct handler {
- int fd;
- int argc;
- char **argv;
-};
-
-void
-spawn_handler(struct handler *child)
+pid_t
+spawn_handler(int fd, char **argv)
{
- int pipefd[2];
-
- if (pipe(pipefd) == -1)
- edie("pipe");
-
pid_t pid = fork();
if (pid < 0)
edie("fork");
if (pid == 0) {
- close(pipefd[1]);
- dup2(pipefd[0], 0);
- execv(child->argv[0], child->argv);
+ dup2(fd, 0);
+ execv(argv[0], argv);
edie("execl");
}
- close(pipefd[0]);
- child->fd = pipefd[1];
-}
-
-int
-write_to_handler(struct handler *child, const char *buf, size_t count)
-{
- if (child->fd == -1)
- spawn_handler(child);
- return write(child->fd, buf, count);
+ return pid;
}
void
@@ -129,25 +107,13 @@ init_netlink_socket(void)
void
usage(void)
{
- die("usage: %s [-hdb] [-ku] [-- run [...]]\n", argv0);
+ die("usage: %s [-bd] -- runpath [...]\n", argv0);
}
int
main(int argc, char *argv[])
{
- struct sockaddr_nl cnls;
- struct pollfd fds[2];
- struct msghdr hdr;
- struct iovec iov;
- char buf[4097], cbuf[CMSG_SPACE(sizeof(struct ucred))];
- struct cmsghdr *chdr;
- struct ucred *cred;
- int len, showudev, showkernel;
-
- struct handler child;
-
- showkernel = 1;
- showudev = 1;
+ struct pollfd fds;
ARGBEGIN {
case 'b':
@@ -156,27 +122,12 @@ main(int argc, char *argv[])
case 'd':
dodebug = 1;
break;
- case 'k':
- showudev = 0;
- break;
- case 'u':
- showkernel = 0;
- break;
default:
usage();
} ARGEND;
- child.fd = -1;
- child.argc = argc;
- child.argv = argv;
-
- fds[0].events = POLLIN;
- fds[0].fd = init_netlink_socket();
-
- fds[1].fd = child.fd;
- fds[1].events = POLLERR;
-
- listfd = fds[0].fd;
+ fds.events = POLLIN;
+ fds.fd = init_netlink_socket();
if (dofork) {
if (daemon(0, 0) < 0)
@@ -186,68 +137,12 @@ main(int argc, char *argv[])
initsignals();
- while (poll(fds, 2, -1) > -1) {
- if (fds[1].revents & POLLERR) {
- dbg("handler exited");
- close(child.fd);
- fds[1].fd = child.fd = -1;
- }
-
- if (!(fds[0].revents & POLLIN))
- continue;
-
- iov.iov_base = &buf;
- iov.iov_len = sizeof(buf);
- memset(&hdr, 0, sizeof(hdr));
- hdr.msg_iov = &iov;
- hdr.msg_iovlen = 1;
- hdr.msg_control = cbuf;
- hdr.msg_controllen = sizeof(cbuf);
- hdr.msg_name = &cnls;
- hdr.msg_namelen = sizeof(cnls);
-
- len = recvmsg(fds[0].fd, &hdr, 0);
- if (len < 0) {
- if (errno == EINTR)
- continue;
- edie("recvmsg");
- }
- if (len < 32 || len >= sizeof(buf))
- continue;
-
- chdr = CMSG_FIRSTHDR(&hdr);
- if (chdr == NULL || chdr->cmsg_type != SCM_CREDENTIALS)
- continue;
-
- /*
- * Don't allow anyone but root to send us messages.
- *
- * We will allow users to send us messages, when
- * udev is enabled. Udev is just a toy you should
- * only use for testing.
- */
- cred = (struct ucred *)CMSG_DATA(chdr);
- if (cred->uid != 0 && !showudev)
- continue;
-
- if (!memcmp(buf, "libudev", 8)) {
- /*
- * Receiving messages from udev is insecure.
- */
- if (!showudev)
- continue;
- } else {
- if (!showkernel)
- continue;
- /*
- * Kernel messages shouldn't come from the
- * userspace.
- */
- if (cnls.nl_pid > 0)
- continue;
+ while (poll(&fds, 1, -1) > -1) {
+ if (fds.revents & POLLIN) {
+ int status;
+ pid_t childpid = spawn_handler(fds.fd, argv);
+ waitpid(childpid, &status, 0);
}
- write_to_handler(&child, buf, len);
- fds[1].fd = child.fd;
}
return 0;