chiark / gitweb /
sd-daemon: add API to verify socket types
authorLennart Poettering <lennart@poettering.net>
Wed, 19 May 2010 23:13:43 +0000 (01:13 +0200)
committerLennart Poettering <lennart@poettering.net>
Wed, 19 May 2010 23:13:43 +0000 (01:13 +0200)
src/initctl.c
src/logger.c
src/sd-daemon.c
src/sd-daemon.h

index 9d8ecee..407d32d 100644 (file)
@@ -280,6 +280,20 @@ static int server_init(Server *s, unsigned n_sockets) {
         for (i = 0; i < n_sockets; i++) {
                 struct epoll_event ev;
                 Fifo *f;
         for (i = 0; i < n_sockets; i++) {
                 struct epoll_event ev;
                 Fifo *f;
+                int fd;
+
+                fd = SD_LISTEN_FDS_START+i;
+
+                if ((r = sd_is_fifo(fd, NULL)) < 0) {
+                        log_error("Failed to determine file descriptor type: %s", strerror(-r));
+                        goto fail;
+                }
+
+                if (!r) {
+                        log_error("Wrong file descriptor type.");
+                        r = -EINVAL;
+                        goto fail;
+                }
 
                 if (!(f = new0(Fifo, 1))) {
                         r = -ENOMEM;
 
                 if (!(f = new0(Fifo, 1))) {
                         r = -ENOMEM;
@@ -292,7 +306,7 @@ static int server_init(Server *s, unsigned n_sockets) {
                 zero(ev);
                 ev.events = EPOLLIN;
                 ev.data.ptr = f;
                 zero(ev);
                 ev.events = EPOLLIN;
                 ev.data.ptr = f;
-                if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, SD_LISTEN_FDS_START+i, &ev) < 0) {
+                if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
                         r = -errno;
                         fifo_free(f);
                         log_error("Failed to add fifo fd to epoll object: %s", strerror(errno));
                         r = -errno;
                         fifo_free(f);
                         log_error("Failed to add fifo fd to epoll object: %s", strerror(errno));
index e7c2be0..c486a8a 100644 (file)
@@ -424,11 +424,25 @@ static int server_init(Server *s, unsigned n_sockets) {
 
         for (i = 0; i < n_sockets; i++) {
                 struct epoll_event ev;
 
         for (i = 0; i < n_sockets; i++) {
                 struct epoll_event ev;
+                int fd;
+
+                fd = SD_LISTEN_FDS_START+i;
+
+                if ((r = sd_is_socket(fd, SOCK_STREAM, 1)) < 0) {
+                        log_error("Failed to determine file descriptor type: %s", strerror(-r));
+                        goto fail;
+                }
+
+                if (!r) {
+                        log_error("Wrong file descriptor type.");
+                        r = -EINVAL;
+                        goto fail;
+                }
 
                 zero(ev);
                 ev.events = EPOLLIN;
 
                 zero(ev);
                 ev.events = EPOLLIN;
-                ev.data.ptr = UINT_TO_PTR(SD_LISTEN_FDS_START+i);
-                if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, SD_LISTEN_FDS_START+i, &ev) < 0) {
+                ev.data.ptr = UINT_TO_PTR(fd);
+                if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
                         r = -errno;
                         log_error("Failed to add server fd to epoll object: %s", strerror(errno));
                         goto fail;
                         r = -errno;
                         log_error("Failed to add server fd to epoll object: %s", strerror(errno));
                         goto fail;
index cc972da..8a7c9e8 100644 (file)
   SOFTWARE.
 ***/
 
   SOFTWARE.
 ***/
 
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
 #include <stdlib.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <errno.h>
-#include <sys/types.h>
 #include <unistd.h>
 #include <unistd.h>
+#include <string.h>
 
 #include "sd-daemon.h"
 
 
 #include "sd-daemon.h"
 
@@ -94,3 +99,171 @@ finish:
         return r;
 #endif
 }
         return r;
 #endif
 }
+
+int sd_is_fifo(int fd, const char *path) {
+        struct stat st_fd;
+
+        if (fd < 0)
+                return -EINVAL;
+
+        memset(&st_fd, 0, sizeof(st_fd));
+        if (fstat(fd, &st_fd) < 0)
+                return -errno;
+
+        if (!S_ISFIFO(st_fd.st_mode))
+                return 0;
+
+        if (path) {
+                struct stat st_path;
+
+                memset(&st_path, 0, sizeof(st_path));
+                if (fstat(fd, &st_path) < 0) {
+
+                        if (errno == ENOENT || errno == ENOTDIR)
+                                return 0;
+
+                        return -errno;
+                }
+
+                return
+                        st_path.st_dev == st_fd.st_dev &&
+                        st_path.st_ino == st_fd.st_ino;
+        }
+
+        return 1;
+}
+
+int sd_is_socket(int fd, int type, int listening) {
+        struct stat st_fd;
+
+        if (fd < 0 || type < 0)
+                return -EINVAL;
+
+        if (fstat(fd, &st_fd) < 0)
+                return -errno;
+
+        if (!S_ISSOCK(st_fd.st_mode))
+                return 0;
+
+        if (type != 0) {
+                int other_type = 0;
+                socklen_t l = sizeof(other_type);
+
+                if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0)
+                        return -errno;
+
+                if (l != sizeof(other_type))
+                        return -EINVAL;
+
+                if (other_type != type)
+                        return 0;
+        }
+
+        if (listening >= 0) {
+                int accepting = 0;
+                socklen_t l = sizeof(accepting);
+
+                if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0)
+                        return -errno;
+
+                if (l != sizeof(accepting))
+                        return -EINVAL;
+
+                if (!accepting == !listening)
+                        return 0;
+        }
+
+        return 1;
+}
+
+int sd_is_socket_inet(int fd, int type, int listening, uint16_t port) {
+        union {
+                struct sockaddr sa;
+                struct sockaddr_in in4;
+                struct sockaddr_in6 in6;
+                struct sockaddr_un un;
+                struct sockaddr_storage storage;
+        } sockaddr;
+        socklen_t l;
+        int r;
+
+        if ((r = sd_is_socket(fd, type, listening)) <= 0)
+                return r;
+
+        memset(&sockaddr, 0, sizeof(sockaddr));
+        l = sizeof(sockaddr);
+
+        if (getsockname(fd, &sockaddr.sa, &l) < 0)
+                return -errno;
+
+        if (l < sizeof(struct sockaddr))
+                return -EINVAL;
+
+        if (sockaddr.sa.sa_family != AF_INET &&
+            sockaddr.sa.sa_family != AF_INET6)
+                return 0;
+
+        if (port > 0) {
+                if (sockaddr.sa.sa_family == AF_INET) {
+                        if (l < sizeof(struct sockaddr_in))
+                                return -EINVAL;
+
+                        return htons(port) == sockaddr.in4.sin_port;
+                } else {
+                        if (l < sizeof(struct sockaddr_in6))
+                                return -EINVAL;
+
+                        return htons(port) == sockaddr.in6.sin6_port;
+                }
+        }
+
+        return 1;
+}
+
+int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) {
+        union {
+                struct sockaddr sa;
+                struct sockaddr_in in4;
+                struct sockaddr_in6 in6;
+                struct sockaddr_un un;
+                struct sockaddr_storage storage;
+        } sockaddr;
+        socklen_t l;
+        int r;
+
+        if ((r = sd_is_socket(fd, type, listening)) <= 0)
+                return r;
+
+        memset(&sockaddr, 0, sizeof(sockaddr));
+        l = sizeof(sockaddr);
+
+        if (getsockname(fd, &sockaddr.sa, &l) < 0)
+                return -errno;
+
+        if (l < sizeof(sa_family_t))
+                return -EINVAL;
+
+        if (sockaddr.sa.sa_family != AF_UNIX)
+                return 0;
+
+        if (path) {
+                if (length <= 0)
+                        length = strlen(path);
+
+                if (length <= 0)
+                        /* Unnamed socket */
+                        return l == sizeof(sa_family_t);
+
+                if (l < sizeof(sa_family_t) + length + 1)
+                        return 0;
+
+                if (path[0])
+                        /* Normal path socket */
+                        return memcmp(path, sockaddr.un.sun_path, length+1) == 0;
+                else
+                        /* Abstract namespace socket */
+                        return memcmp(path, sockaddr.un.sun_path+1, length) == 0;
+        }
+
+        return 1;
+}
index c7f5c1d..b7100bc 100644 (file)
@@ -27,6 +27,8 @@
   SOFTWARE.
 ***/
 
   SOFTWARE.
 ***/
 
+#include <inttypes.h>
+
 /* Reference implementation of a few systemd related interfaces for
  * writing daemons. These interfaces are trivial to implement, however
  * to simplify porting we provide this reference
 /* Reference implementation of a few systemd related interfaces for
  * writing daemons. These interfaces are trivial to implement, however
  * to simplify porting we provide this reference
 
 /* Returns how many file descriptors have been passed, or a negative
  * errno code on failure. Optionally removes the $LISTEN_FDS and
 
 /* Returns how many file descriptors have been passed, or a negative
  * errno code on failure. Optionally removes the $LISTEN_FDS and
- * $LISTEN_PID file descriptors from the environment (recommended). */
+ * $LISTEN_PID file descriptors from the environment
+ * (recommended). You'll find the file descriptors passed as fds
+ * SD_LISTEN_FDS_START to SD_LISTEN_FDS_START+r-1 if r is the return
+ * value of this functioin. Returns a negative errno style error code
+ * on failure. */
 int sd_listen_fds(int unset_environment);
 
 int sd_listen_fds(int unset_environment);
 
+/* Helper call for identifying a passed file descriptor. Returns 1 if
+ * the file descriptor is a FIFO in the file system stored under the
+ * specified path, 0 otherwise. If path is NULL a path name check will
+ * not be done and the call only verifies if the file descriptor
+ * refers to a FIFO. Returns a negative errno style error code on
+ * failure. */
+int sd_is_fifo(int fd, const char *path);
+
+/* Helper call for identifying a passed file descriptor. Returns 1 if
+ * the file descriptor is a socket of the specified type (SOCK_DGRAM,
+ * SOCK_STREAM, ...), 0 otherwise. If type is 0 a socket type check
+ * will not be done and the call only verifies if the file descriptor
+ * refers to a socket. Returns a negative errno style error code on
+ * failure. */
+int sd_is_socket(int fd, int type, int listening);
+
+/* Helper call for identifying a passed file descriptor. Returns 1 if
+ * the file descriptor is an Internet socket (either AF_INET or
+ * AF_INET6) of the specified type (SOCK_DGRAM, SOCK_STREAM, ...), 0
+ * otherwise. If type is 0 a socket type check will not be done. If
+ * port is 0 a socket port check will not be done. Returns a negative
+ * errno style error code on failure. */
+int sd_is_socket_inet(int fd, int type, int listening, uint16_t port);
+
+/* Helper call for identifying a passed file descriptor. Returns 1 if
+ * the file descriptor is an AF_UNIX socket of the specified type
+ * (SOCK_DGRAM, SOCK_STREAM, ...) and path, 0 otherwise. If type is 0
+ * a socket type check will not be done. If path is NULL a socket path
+ * check will not be done. For normal AF_UNIX sockets set length to
+ * 0. For abstract namespace sockets set length to the length of the
+ * socket name (excluding the initial 0 byte). Returns a negative
+ * errno style error code on failure. */
+int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length);
+
 #endif
 #endif