]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/socket-label.c
treewide: auto-convert the simple cases to log_*_errno()
[thirdparty/systemd.git] / src / shared / 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
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,
175a3d25 44 int flags,
cc527a47
KS
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,
175a3d25
LP
52 const char *label) {
53
54 _cleanup_close_ int fd = -1;
55 int r, one;
cc527a47 56
cc527a47 57 assert(a);
cc527a47 58
175a3d25
LP
59 r = socket_address_verify(a);
60 if (r < 0)
cc527a47
KS
61 return r;
62
63 if (socket_address_family(a) == AF_INET6 && !socket_ipv6_is_supported())
64 return -EAFNOSUPPORT;
65
175a3d25 66 if (label) {
ecabcf8b 67 r = mac_selinux_create_socket_prepare(label);
175a3d25
LP
68 if (r < 0)
69 return r;
70 }
cc527a47 71
175a3d25 72 fd = socket(socket_address_family(a), a->type | flags, a->protocol);
cc527a47
KS
73 r = fd < 0 ? -errno : 0;
74
175a3d25 75 if (label)
ecabcf8b 76 mac_selinux_create_socket_clear();
cc527a47
KS
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)
175a3d25 85 return -errno;
cc527a47
KS
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)
175a3d25 91 return -errno;
cc527a47
KS
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)
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
119 /* Include the original umask in our mask */
120 umask(~socket_mode | old_mask);
121
cc56fafe 122 r = mac_selinux_bind(fd, &a->sockaddr.sa, a->size);
cc527a47
KS
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)
175a3d25 135 return -errno;
cc527a47
KS
136
137 if (socket_address_can_accept(a))
138 if (listen(fd, backlog) < 0)
175a3d25 139 return -errno;
cc527a47 140
175a3d25
LP
141 r = fd;
142 fd = -1;
cc527a47 143
cc527a47
KS
144 return r;
145}
e0aa3726
ZJS
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) {
1af719ed
ZJS
153 log_error("Failed to parse socket address \"%s\": %s",
154 address, strerror(-r));
e0aa3726
ZJS
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) {
c8b32e11 161 _cleanup_free_ char *p = NULL;
e0aa3726
ZJS
162
163 r = socket_address_print(&a, &p);
164 if (r < 0) {
0a1beeb6 165 log_error_errno(-r, "socket_address_print(): %m");
e0aa3726
ZJS
166 return r;
167 }
168
169 if (fd < 0)
0a1beeb6 170 log_error_errno(-fd, "Failed to listen on %s: %m", p);
e0aa3726
ZJS
171 else
172 log_full(log_level, "Listening on %s", p);
173 }
174
175 return fd;
176}