]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/socket-label.c
mkdir: append _label to all mkdir() calls that explicitly set the selinux context
[thirdparty/systemd.git] / src / shared / socket-label.c
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
42 int socket_address_listen(
43 const SocketAddress *a,
44 int backlog,
45 SocketAddressBindIPv6Only only,
46 const char *bind_to_device,
47 bool free_bind,
48 bool transparent,
49 mode_t directory_mode,
50 mode_t socket_mode,
51 const char *label,
52 int *ret) {
53
54 int r, fd, one;
55 assert(a);
56 assert(ret);
57
58 if ((r = socket_address_verify(a)) < 0)
59 return r;
60
61 if (socket_address_family(a) == AF_INET6 && !socket_ipv6_is_supported())
62 return -EAFNOSUPPORT;
63
64 r = label_socket_set(label);
65 if (r < 0)
66 return r;
67
68 fd = socket(socket_address_family(a), a->type | SOCK_NONBLOCK | SOCK_CLOEXEC, a->protocol);
69 r = fd < 0 ? -errno : 0;
70
71 label_socket_clear();
72
73 if (r < 0)
74 return r;
75
76 if (socket_address_family(a) == AF_INET6 && only != SOCKET_ADDRESS_DEFAULT) {
77 int flag = only == SOCKET_ADDRESS_IPV6_ONLY;
78
79 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag)) < 0)
80 goto fail;
81 }
82
83 if (socket_address_family(a) == AF_INET || socket_address_family(a) == AF_INET6) {
84 if (bind_to_device)
85 if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, bind_to_device, strlen(bind_to_device)+1) < 0)
86 goto fail;
87
88 if (free_bind) {
89 one = 1;
90 if (setsockopt(fd, IPPROTO_IP, IP_FREEBIND, &one, sizeof(one)) < 0)
91 log_warning("IP_FREEBIND failed: %m");
92 }
93
94 if (transparent) {
95 one = 1;
96 if (setsockopt(fd, IPPROTO_IP, IP_TRANSPARENT, &one, sizeof(one)) < 0)
97 log_warning("IP_TRANSPARENT failed: %m");
98 }
99 }
100
101 one = 1;
102 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
103 goto fail;
104
105 if (socket_address_family(a) == AF_UNIX && a->sockaddr.un.sun_path[0] != 0) {
106 mode_t old_mask;
107
108 /* Create parents */
109 mkdir_parents_label(a->sockaddr.un.sun_path, directory_mode);
110
111 /* Enforce the right access mode for the socket*/
112 old_mask = umask(~ socket_mode);
113
114 /* Include the original umask in our mask */
115 umask(~socket_mode | old_mask);
116
117 r = label_bind(fd, &a->sockaddr.sa, a->size);
118
119 if (r < 0 && errno == EADDRINUSE) {
120 /* Unlink and try again */
121 unlink(a->sockaddr.un.sun_path);
122 r = bind(fd, &a->sockaddr.sa, a->size);
123 }
124
125 umask(old_mask);
126 } else
127 r = bind(fd, &a->sockaddr.sa, a->size);
128
129 if (r < 0)
130 goto fail;
131
132 if (socket_address_can_accept(a))
133 if (listen(fd, backlog) < 0)
134 goto fail;
135
136 *ret = fd;
137 return 0;
138
139 fail:
140 r = -errno;
141 close_nointr_nofail(fd);
142 return r;
143 }