]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/socket-label.c
path-util: rework find_binary(), fsck_exists() and mkfs_exists()
[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,
54255c64 41 bool reuse_port,
cc527a47
KS
42 bool free_bind,
43 bool transparent,
44 mode_t directory_mode,
45 mode_t socket_mode,
175a3d25
LP
46 const char *label) {
47
48 _cleanup_close_ int fd = -1;
49 int r, one;
cc527a47 50
cc527a47 51 assert(a);
cc527a47 52
175a3d25
LP
53 r = socket_address_verify(a);
54 if (r < 0)
cc527a47
KS
55 return r;
56
57 if (socket_address_family(a) == AF_INET6 && !socket_ipv6_is_supported())
58 return -EAFNOSUPPORT;
59
175a3d25 60 if (label) {
ecabcf8b 61 r = mac_selinux_create_socket_prepare(label);
175a3d25
LP
62 if (r < 0)
63 return r;
64 }
cc527a47 65
175a3d25 66 fd = socket(socket_address_family(a), a->type | flags, a->protocol);
cc527a47
KS
67 r = fd < 0 ? -errno : 0;
68
175a3d25 69 if (label)
ecabcf8b 70 mac_selinux_create_socket_clear();
cc527a47
KS
71
72 if (r < 0)
73 return r;
74
75 if (socket_address_family(a) == AF_INET6 && only != SOCKET_ADDRESS_DEFAULT) {
76 int flag = only == SOCKET_ADDRESS_IPV6_ONLY;
77
78 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag)) < 0)
175a3d25 79 return -errno;
cc527a47
KS
80 }
81
82 if (socket_address_family(a) == AF_INET || socket_address_family(a) == AF_INET6) {
83 if (bind_to_device)
84 if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, bind_to_device, strlen(bind_to_device)+1) < 0)
175a3d25 85 return -errno;
cc527a47 86
54255c64
CT
87 if (reuse_port) {
88 one = 1;
89 if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) < 0)
90 log_warning_errno(errno, "SO_REUSEPORT failed: %m");
91 }
92
cc527a47
KS
93 if (free_bind) {
94 one = 1;
95 if (setsockopt(fd, IPPROTO_IP, IP_FREEBIND, &one, sizeof(one)) < 0)
56f64d95 96 log_warning_errno(errno, "IP_FREEBIND failed: %m");
cc527a47
KS
97 }
98
99 if (transparent) {
100 one = 1;
101 if (setsockopt(fd, IPPROTO_IP, IP_TRANSPARENT, &one, sizeof(one)) < 0)
56f64d95 102 log_warning_errno(errno, "IP_TRANSPARENT failed: %m");
cc527a47
KS
103 }
104 }
105
106 one = 1;
107 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
175a3d25 108 return -errno;
cc527a47
KS
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 */
d2e54fae 114 mkdir_parents_label(a->sockaddr.un.sun_path, directory_mode);
cc527a47 115
175a3d25 116 /* Enforce the right access mode for the socket */
cc527a47
KS
117 old_mask = umask(~ socket_mode);
118
cc56fafe 119 r = mac_selinux_bind(fd, &a->sockaddr.sa, a->size);
cc527a47
KS
120
121 if (r < 0 && errno == EADDRINUSE) {
122 /* Unlink and try again */
123 unlink(a->sockaddr.un.sun_path);
124 r = bind(fd, &a->sockaddr.sa, a->size);
125 }
126
127 umask(old_mask);
128 } else
129 r = bind(fd, &a->sockaddr.sa, a->size);
130
131 if (r < 0)
175a3d25 132 return -errno;
cc527a47
KS
133
134 if (socket_address_can_accept(a))
135 if (listen(fd, backlog) < 0)
175a3d25 136 return -errno;
cc527a47 137
175a3d25
LP
138 r = fd;
139 fd = -1;
cc527a47 140
cc527a47
KS
141 return r;
142}
e0aa3726
ZJS
143
144int make_socket_fd(int log_level, const char* address, int flags) {
145 SocketAddress a;
146 int fd, r;
147
148 r = socket_address_parse(&a, address);
e53fc357
LP
149 if (r < 0)
150 return log_error_errno(r, "Failed to parse socket address \"%s\": %m", address);
e0aa3726
ZJS
151
152 fd = socket_address_listen(&a, flags, SOMAXCONN, SOCKET_ADDRESS_DEFAULT,
54255c64 153 NULL, false, false, false, 0755, 0644, NULL);
e0aa3726 154 if (fd < 0 || log_get_max_level() >= log_level) {
c8b32e11 155 _cleanup_free_ char *p = NULL;
e0aa3726
ZJS
156
157 r = socket_address_print(&a, &p);
f647962d
MS
158 if (r < 0)
159 return log_error_errno(r, "socket_address_print(): %m");
e0aa3726
ZJS
160
161 if (fd < 0)
da927ba9 162 log_error_errno(fd, "Failed to listen on %s: %m", p);
e0aa3726
ZJS
163 else
164 log_full(log_level, "Listening on %s", p);
165 }
166
167 return fd;
168}