]> git.proxmox.com Git - systemd.git/blame - src/shared/socket-label.c
Imported Upstream version 217
[systemd.git] / src / shared / socket-label.c
CommitLineData
663996b3
MS
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <assert.h>
23#include <string.h>
24#include <unistd.h>
25#include <errno.h>
26#include <stdlib.h>
27#include <arpa/inet.h>
28#include <stdio.h>
29#include <net/if.h>
30#include <sys/types.h>
31#include <sys/stat.h>
32#include <stddef.h>
33#include <sys/ioctl.h>
34
35#include "macro.h"
36#include "util.h"
37#include "mkdir.h"
38#include "socket-util.h"
39#include "missing.h"
40#include "label.h"
41
42int socket_address_listen(
43 const SocketAddress *a,
60f067b4 44 int flags,
663996b3
MS
45 int backlog,
46 SocketAddressBindIPv6Only only,
47 const char *bind_to_device,
48 bool free_bind,
49 bool transparent,
50 mode_t directory_mode,
51 mode_t socket_mode,
60f067b4
JS
52 const char *label) {
53
54 _cleanup_close_ int fd = -1;
55 int r, one;
663996b3 56
663996b3 57 assert(a);
663996b3 58
60f067b4
JS
59 r = socket_address_verify(a);
60 if (r < 0)
663996b3
MS
61 return r;
62
63 if (socket_address_family(a) == AF_INET6 && !socket_ipv6_is_supported())
64 return -EAFNOSUPPORT;
65
60f067b4 66 if (label) {
5eef597e 67 r = mac_selinux_create_socket_prepare(label);
60f067b4
JS
68 if (r < 0)
69 return r;
70 }
663996b3 71
60f067b4 72 fd = socket(socket_address_family(a), a->type | flags, a->protocol);
663996b3
MS
73 r = fd < 0 ? -errno : 0;
74
60f067b4 75 if (label)
5eef597e 76 mac_selinux_create_socket_clear();
663996b3
MS
77
78 if (r < 0)
79 return r;
80
81 if (socket_address_family(a) == AF_INET6 && only != SOCKET_ADDRESS_DEFAULT) {
82 int flag = only == SOCKET_ADDRESS_IPV6_ONLY;
83
84 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag)) < 0)
60f067b4 85 return -errno;
663996b3
MS
86 }
87
88 if (socket_address_family(a) == AF_INET || socket_address_family(a) == AF_INET6) {
89 if (bind_to_device)
90 if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, bind_to_device, strlen(bind_to_device)+1) < 0)
60f067b4 91 return -errno;
663996b3
MS
92
93 if (free_bind) {
94 one = 1;
95 if (setsockopt(fd, IPPROTO_IP, IP_FREEBIND, &one, sizeof(one)) < 0)
96 log_warning("IP_FREEBIND failed: %m");
97 }
98
99 if (transparent) {
100 one = 1;
101 if (setsockopt(fd, IPPROTO_IP, IP_TRANSPARENT, &one, sizeof(one)) < 0)
102 log_warning("IP_TRANSPARENT failed: %m");
103 }
104 }
105
106 one = 1;
107 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
60f067b4 108 return -errno;
663996b3
MS
109
110 if (socket_address_family(a) == AF_UNIX && a->sockaddr.un.sun_path[0] != 0) {
111 mode_t old_mask;
112
113 /* Create parents */
114 mkdir_parents_label(a->sockaddr.un.sun_path, directory_mode);
115
60f067b4 116 /* Enforce the right access mode for the socket */
663996b3
MS
117 old_mask = umask(~ socket_mode);
118
119 /* Include the original umask in our mask */
120 umask(~socket_mode | old_mask);
121
5eef597e 122 r = mac_selinux_bind(fd, &a->sockaddr.sa, a->size);
663996b3
MS
123
124 if (r < 0 && errno == EADDRINUSE) {
125 /* Unlink and try again */
126 unlink(a->sockaddr.un.sun_path);
127 r = bind(fd, &a->sockaddr.sa, a->size);
128 }
129
130 umask(old_mask);
131 } else
132 r = bind(fd, &a->sockaddr.sa, a->size);
133
134 if (r < 0)
60f067b4 135 return -errno;
663996b3
MS
136
137 if (socket_address_can_accept(a))
138 if (listen(fd, backlog) < 0)
60f067b4 139 return -errno;
663996b3 140
60f067b4
JS
141 r = fd;
142 fd = -1;
663996b3 143
663996b3
MS
144 return r;
145}
60f067b4
JS
146
147int make_socket_fd(int log_level, const char* address, int flags) {
148 SocketAddress a;
149 int fd, r;
150
151 r = socket_address_parse(&a, address);
152 if (r < 0) {
5eef597e
MP
153 log_error("Failed to parse socket address \"%s\": %s",
154 address, strerror(-r));
60f067b4
JS
155 return r;
156 }
157
158 fd = socket_address_listen(&a, flags, SOMAXCONN, SOCKET_ADDRESS_DEFAULT,
159 NULL, false, false, 0755, 0644, NULL);
160 if (fd < 0 || log_get_max_level() >= log_level) {
e842803a 161 _cleanup_free_ char *p = NULL;
60f067b4
JS
162
163 r = socket_address_print(&a, &p);
164 if (r < 0) {
165 log_error("socket_address_print(): %s", strerror(-r));
166 return r;
167 }
168
169 if (fd < 0)
5eef597e 170 log_error("Failed to listen on %s: %s", p, strerror(-fd));
60f067b4
JS
171 else
172 log_full(log_level, "Listening on %s", p);
173 }
174
175 return fd;
176}