]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/socket-label.c
build-sys: split internal basic/ library from shared/
[thirdparty/systemd.git] / src / basic / socket-label.c
CommitLineData
cc527a47
KS
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
5430f7f2
LP
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
cc527a47
KS
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
5430f7f2 16 Lesser General Public License for more details.
cc527a47 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
cc527a47
KS
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
cc527a47
KS
22#include <string.h>
23#include <unistd.h>
24#include <errno.h>
cc527a47
KS
25#include <sys/stat.h>
26#include <stddef.h>
cc527a47
KS
27
28#include "macro.h"
29#include "util.h"
30#include "mkdir.h"
cc527a47 31#include "missing.h"
d7b8eec7
LP
32#include "selinux-util.h"
33#include "socket-util.h"
cc527a47
KS
34
35int socket_address_listen(
36 const SocketAddress *a,
175a3d25 37 int flags,
cc527a47
KS
38 int backlog,
39 SocketAddressBindIPv6Only only,
40 const char *bind_to_device,
41 bool free_bind,
42 bool transparent,
43 mode_t directory_mode,
44 mode_t socket_mode,
175a3d25
LP
45 const char *label) {
46
47 _cleanup_close_ int fd = -1;
48 int r, one;
cc527a47 49
cc527a47 50 assert(a);
cc527a47 51
175a3d25
LP
52 r = socket_address_verify(a);
53 if (r < 0)
cc527a47
KS
54 return r;
55
56 if (socket_address_family(a) == AF_INET6 && !socket_ipv6_is_supported())
57 return -EAFNOSUPPORT;
58
175a3d25 59 if (label) {
ecabcf8b 60 r = mac_selinux_create_socket_prepare(label);
175a3d25
LP
61 if (r < 0)
62 return r;
63 }
cc527a47 64
175a3d25 65 fd = socket(socket_address_family(a), a->type | flags, a->protocol);
cc527a47
KS
66 r = fd < 0 ? -errno : 0;
67
175a3d25 68 if (label)
ecabcf8b 69 mac_selinux_create_socket_clear();
cc527a47
KS
70
71 if (r < 0)
72 return r;
73
74 if (socket_address_family(a) == AF_INET6 && only != SOCKET_ADDRESS_DEFAULT) {
75 int flag = only == SOCKET_ADDRESS_IPV6_ONLY;
76
77 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag)) < 0)
175a3d25 78 return -errno;
cc527a47
KS
79 }
80
81 if (socket_address_family(a) == AF_INET || socket_address_family(a) == AF_INET6) {
82 if (bind_to_device)
83 if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, bind_to_device, strlen(bind_to_device)+1) < 0)
175a3d25 84 return -errno;
cc527a47
KS
85
86 if (free_bind) {
87 one = 1;
88 if (setsockopt(fd, IPPROTO_IP, IP_FREEBIND, &one, sizeof(one)) < 0)
56f64d95 89 log_warning_errno(errno, "IP_FREEBIND failed: %m");
cc527a47
KS
90 }
91
92 if (transparent) {
93 one = 1;
94 if (setsockopt(fd, IPPROTO_IP, IP_TRANSPARENT, &one, sizeof(one)) < 0)
56f64d95 95 log_warning_errno(errno, "IP_TRANSPARENT failed: %m");
cc527a47
KS
96 }
97 }
98
99 one = 1;
100 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
175a3d25 101 return -errno;
cc527a47
KS
102
103 if (socket_address_family(a) == AF_UNIX && a->sockaddr.un.sun_path[0] != 0) {
104 mode_t old_mask;
105
106 /* Create parents */
d2e54fae 107 mkdir_parents_label(a->sockaddr.un.sun_path, directory_mode);
cc527a47 108
175a3d25 109 /* Enforce the right access mode for the socket */
cc527a47
KS
110 old_mask = umask(~ socket_mode);
111
cc56fafe 112 r = mac_selinux_bind(fd, &a->sockaddr.sa, a->size);
cc527a47
KS
113
114 if (r < 0 && errno == EADDRINUSE) {
115 /* Unlink and try again */
116 unlink(a->sockaddr.un.sun_path);
117 r = bind(fd, &a->sockaddr.sa, a->size);
118 }
119
120 umask(old_mask);
121 } else
122 r = bind(fd, &a->sockaddr.sa, a->size);
123
124 if (r < 0)
175a3d25 125 return -errno;
cc527a47
KS
126
127 if (socket_address_can_accept(a))
128 if (listen(fd, backlog) < 0)
175a3d25 129 return -errno;
cc527a47 130
175a3d25
LP
131 r = fd;
132 fd = -1;
cc527a47 133
cc527a47
KS
134 return r;
135}
e0aa3726
ZJS
136
137int make_socket_fd(int log_level, const char* address, int flags) {
138 SocketAddress a;
139 int fd, r;
140
141 r = socket_address_parse(&a, address);
142 if (r < 0) {
1af719ed
ZJS
143 log_error("Failed to parse socket address \"%s\": %s",
144 address, strerror(-r));
e0aa3726
ZJS
145 return r;
146 }
147
148 fd = socket_address_listen(&a, flags, SOMAXCONN, SOCKET_ADDRESS_DEFAULT,
149 NULL, false, false, 0755, 0644, NULL);
150 if (fd < 0 || log_get_max_level() >= log_level) {
c8b32e11 151 _cleanup_free_ char *p = NULL;
e0aa3726
ZJS
152
153 r = socket_address_print(&a, &p);
f647962d
MS
154 if (r < 0)
155 return log_error_errno(r, "socket_address_print(): %m");
e0aa3726
ZJS
156
157 if (fd < 0)
da927ba9 158 log_error_errno(fd, "Failed to listen on %s: %m", p);
e0aa3726
ZJS
159 else
160 log_full(log_level, "Listening on %s", p);
161 }
162
163 return fd;
164}