X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=socket-util.c;h=96567c6d81ec247e78e7303d483f166046633e05;hp=77b80d01270cf71afb05e9f8a003680c99c7830a;hb=7072ced8274274cd1b0fa085dd4118462e03884e;hpb=9152c765065184d0c1267ed2499e3fe4cac53755 diff --git a/socket-util.c b/socket-util.c index 77b80d012..96567c6d8 100644 --- a/socket-util.c +++ b/socket-util.c @@ -1,5 +1,24 @@ /*-*- Mode: C; c-basic-offset: 8 -*-*/ +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with systemd; If not, see . +***/ + #include #include #include @@ -8,6 +27,8 @@ #include #include #include +#include +#include #include "macro.h" #include "util.h" @@ -69,7 +90,7 @@ int socket_address_parse(SocketAddress *a, const char *s) { memcpy(a->sockaddr.un.sun_path, s, l); a->size = sizeof(sa_family_t) + l + 1; - } else if (*s == '=') { + } else if (*s == '@') { /* Abstract AF_UNIX socket */ size_t l; @@ -84,7 +105,6 @@ int socket_address_parse(SocketAddress *a, const char *s) { } else { if ((e = strchr(s, ':'))) { - int r; if ((r = safe_atou(e+1, &u)) < 0) return r; @@ -111,6 +131,11 @@ int socket_address_parse(SocketAddress *a, const char *s) { } else { unsigned idx; + if (strlen(n) > IF_NAMESIZE-1) { + free(n); + return -EINVAL; + } + /* Uh, our last resort, an interface name */ idx = if_nametoindex(n); free(n); @@ -123,6 +148,7 @@ int socket_address_parse(SocketAddress *a, const char *s) { a->sockaddr.in6.sin6_scope_id = idx; a->sockaddr.in6.sin6_addr = in6addr_any; a->size = sizeof(struct sockaddr_in6); + } } else { @@ -255,7 +281,7 @@ int socket_address_print(const SocketAddress *a, char **p) { if (!(ret = new(char, sizeof(a->sockaddr.un.sun_path)+1))) return -ENOMEM; - ret[0] = '='; + ret[0] = '@'; memcpy(ret+1, a->sockaddr.un.sun_path+1, sizeof(a->sockaddr.un.sun_path)-1); ret[sizeof(a->sockaddr.un.sun_path)] = 0; @@ -274,8 +300,16 @@ int socket_address_print(const SocketAddress *a, char **p) { } } -int socket_address_listen(const SocketAddress *a, int backlog, SocketAddressBindIPv6Only only, int *ret) { - int r, fd; +int socket_address_listen( + const SocketAddress *a, + int backlog, + SocketAddressBindIPv6Only only, + const char *bind_to_device, + mode_t directory_mode, + mode_t socket_mode, + int *ret) { + + int r, fd, one; assert(a); assert(ret); @@ -288,23 +322,54 @@ int socket_address_listen(const SocketAddress *a, int backlog, SocketAddressBind if (socket_address_family(a) == AF_INET6 && only != SOCKET_ADDRESS_DEFAULT) { int flag = only == SOCKET_ADDRESS_IPV6_ONLY; - if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag)) < 0) { - close_nointr(fd); - return -errno; - } + if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag)) < 0) + goto fail; } - if (bind(fd, &a->sockaddr.sa, a->size) < 0) { - close_nointr(fd); - return -errno; - } + if (bind_to_device) + if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, bind_to_device, strlen(bind_to_device)+1) < 0) + goto fail; - if (a->type == SOCK_STREAM) - if (listen(fd, backlog) < 0) { - close_nointr(fd); - return -errno; + one = 1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) + goto fail; + + if (socket_address_family(a) == AF_UNIX && a->sockaddr.un.sun_path[0] != 0) { + mode_t old_mask; + + /* Create parents */ + mkdir_parents(a->sockaddr.un.sun_path, directory_mode); + + /* Enforce the right access mode for the socket*/ + old_mask = umask(~ socket_mode); + + /* Include the original umask in our mask */ + umask(~socket_mode | old_mask); + + r = bind(fd, &a->sockaddr.sa, a->size); + + if (r < 0 && errno == EADDRINUSE) { + /* Unlink and try again */ + unlink(a->sockaddr.un.sun_path); + r = bind(fd, &a->sockaddr.sa, a->size); } + umask(old_mask); + } else + r = bind(fd, &a->sockaddr.sa, a->size); + + if (r < 0) + goto fail; + + if (a->type == SOCK_STREAM) + if (listen(fd, backlog) < 0) + goto fail; + *ret = fd; return 0; + +fail: + r = -errno; + close_nointr(fd); + return r; }