/src/systemd/src/shared/bus-message-util.c
Line | Count | Source |
1 | | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
2 | | |
3 | | #include <unistd.h> |
4 | | |
5 | | #include "sd-bus.h" |
6 | | |
7 | | #include "alloc-util.h" |
8 | | #include "bus-message-util.h" |
9 | | #include "bus-util.h" |
10 | | #include "copy.h" |
11 | | #include "in-addr-util.h" |
12 | | #include "resolve-util.h" |
13 | | #include "set.h" |
14 | | #include "socket-netlink.h" |
15 | | |
16 | 0 | int bus_message_read_id128(sd_bus_message *m, sd_id128_t *ret) { |
17 | 0 | const void *a; |
18 | 0 | size_t sz; |
19 | 0 | int r; |
20 | |
|
21 | 0 | assert(m); |
22 | |
|
23 | 0 | r = sd_bus_message_read_array(m, 'y', &a, &sz); |
24 | 0 | if (r < 0) |
25 | 0 | return r; |
26 | | |
27 | 0 | switch (sz) { |
28 | | |
29 | 0 | case 0: |
30 | 0 | if (ret) |
31 | 0 | *ret = SD_ID128_NULL; |
32 | 0 | return 0; |
33 | | |
34 | 0 | case sizeof(sd_id128_t): |
35 | 0 | if (ret) |
36 | 0 | memcpy(ret, a, sz); |
37 | 0 | return !memeqzero(a, sz); /* This mimics sd_id128_is_null(), but ret may be NULL, |
38 | | * and a may be misaligned, so use memeqzero() here. */ |
39 | | |
40 | 0 | default: |
41 | 0 | return -EINVAL; |
42 | 0 | } |
43 | 0 | } |
44 | | |
45 | 0 | int bus_message_read_ifindex(sd_bus_message *message, sd_bus_error *reterr_error, int *ret) { |
46 | 0 | int ifindex, r; |
47 | |
|
48 | 0 | assert(message); |
49 | 0 | assert(ret); |
50 | |
|
51 | 0 | assert_cc(sizeof(int) == sizeof(int32_t)); |
52 | |
|
53 | 0 | r = sd_bus_message_read(message, "i", &ifindex); |
54 | 0 | if (r < 0) |
55 | 0 | return r; |
56 | | |
57 | 0 | if (ifindex <= 0) |
58 | 0 | return sd_bus_error_set(reterr_error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index"); |
59 | | |
60 | 0 | *ret = ifindex; |
61 | |
|
62 | 0 | return 0; |
63 | 0 | } |
64 | | |
65 | 0 | int bus_message_read_family(sd_bus_message *message, sd_bus_error *reterr_error, int *ret) { |
66 | 0 | int family, r; |
67 | |
|
68 | 0 | assert(message); |
69 | 0 | assert(ret); |
70 | |
|
71 | 0 | assert_cc(sizeof(int) == sizeof(int32_t)); |
72 | |
|
73 | 0 | r = sd_bus_message_read(message, "i", &family); |
74 | 0 | if (r < 0) |
75 | 0 | return r; |
76 | | |
77 | 0 | if (!IN_SET(family, AF_INET, AF_INET6)) |
78 | 0 | return sd_bus_error_setf(reterr_error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family); |
79 | | |
80 | 0 | *ret = family; |
81 | 0 | return 0; |
82 | 0 | } |
83 | | |
84 | 0 | int bus_message_read_in_addr_auto(sd_bus_message *message, sd_bus_error *reterr_error, int *ret_family, union in_addr_union *ret_addr) { |
85 | 0 | int family, r; |
86 | 0 | const void *d; |
87 | 0 | size_t sz; |
88 | |
|
89 | 0 | assert(message); |
90 | |
|
91 | 0 | r = bus_message_read_family(message, reterr_error, &family); |
92 | 0 | if (r < 0) |
93 | 0 | return r; |
94 | | |
95 | 0 | r = sd_bus_message_read_array(message, 'y', &d, &sz); |
96 | 0 | if (r < 0) |
97 | 0 | return r; |
98 | | |
99 | 0 | if (sz != FAMILY_ADDRESS_SIZE(family)) |
100 | 0 | return sd_bus_error_set(reterr_error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size"); |
101 | | |
102 | 0 | if (ret_family) |
103 | 0 | *ret_family = family; |
104 | 0 | if (ret_addr) |
105 | 0 | memcpy(ret_addr, d, sz); |
106 | 0 | return 0; |
107 | 0 | } |
108 | | |
109 | | static int bus_message_read_dns_one( |
110 | | sd_bus_message *message, |
111 | | sd_bus_error *reterr_error, |
112 | | bool extended, |
113 | | int *ret_family, |
114 | | union in_addr_union *ret_address, |
115 | | uint16_t *ret_port, |
116 | 0 | const char **ret_server_name) { |
117 | 0 | const char *server_name = NULL; |
118 | 0 | union in_addr_union a; |
119 | 0 | uint16_t port = 0; |
120 | 0 | int family, r; |
121 | |
|
122 | 0 | assert(message); |
123 | 0 | assert(ret_family); |
124 | 0 | assert(ret_address); |
125 | 0 | assert(ret_port); |
126 | 0 | assert(ret_server_name); |
127 | |
|
128 | 0 | r = sd_bus_message_enter_container(message, 'r', extended ? "iayqs" : "iay"); |
129 | 0 | if (r <= 0) |
130 | 0 | return r; |
131 | | |
132 | 0 | r = bus_message_read_in_addr_auto(message, reterr_error, &family, &a); |
133 | 0 | if (r < 0) |
134 | 0 | return r; |
135 | | |
136 | 0 | if (!dns_server_address_valid(family, &a)) { |
137 | 0 | r = sd_bus_error_set(reterr_error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNS server address"); |
138 | 0 | assert(r < 0); |
139 | 0 | return r; |
140 | 0 | } |
141 | | |
142 | 0 | if (extended) { |
143 | 0 | r = sd_bus_message_read(message, "q", &port); |
144 | 0 | if (r < 0) |
145 | 0 | return r; |
146 | | |
147 | 0 | if (IN_SET(port, 53, 853)) |
148 | 0 | port = 0; |
149 | |
|
150 | 0 | r = sd_bus_message_read(message, "s", &server_name); |
151 | 0 | if (r < 0) |
152 | 0 | return r; |
153 | 0 | } |
154 | | |
155 | 0 | r = sd_bus_message_exit_container(message); |
156 | 0 | if (r < 0) |
157 | 0 | return r; |
158 | | |
159 | 0 | *ret_family = family; |
160 | 0 | *ret_address = a; |
161 | 0 | *ret_port = port; |
162 | 0 | *ret_server_name = server_name; |
163 | |
|
164 | 0 | return 1; |
165 | 0 | } |
166 | | |
167 | | int bus_message_read_dns_servers( |
168 | | sd_bus_message *message, |
169 | | sd_bus_error *reterr_error, |
170 | | bool extended, |
171 | | struct in_addr_full ***ret_dns, |
172 | 0 | size_t *ret_n_dns) { |
173 | |
|
174 | 0 | struct in_addr_full **dns = NULL; |
175 | 0 | size_t n = 0; |
176 | 0 | int r; |
177 | |
|
178 | 0 | assert(message); |
179 | 0 | assert(ret_dns); |
180 | 0 | assert(ret_n_dns); |
181 | |
|
182 | 0 | r = sd_bus_message_enter_container(message, 'a', extended ? "(iayqs)" : "(iay)"); |
183 | 0 | if (r < 0) |
184 | 0 | return r; |
185 | | |
186 | 0 | for (;;) { |
187 | 0 | const char *server_name; |
188 | 0 | union in_addr_union a; |
189 | 0 | uint16_t port; |
190 | 0 | int family; |
191 | |
|
192 | 0 | r = bus_message_read_dns_one(message, reterr_error, extended, &family, &a, &port, &server_name); |
193 | 0 | if (r < 0) |
194 | 0 | goto clear; |
195 | 0 | if (r == 0) |
196 | 0 | break; |
197 | | |
198 | 0 | if (!GREEDY_REALLOC(dns, n+1)) { |
199 | 0 | r = -ENOMEM; |
200 | 0 | goto clear; |
201 | 0 | } |
202 | | |
203 | 0 | r = in_addr_full_new(family, &a, port, 0, server_name, dns + n); |
204 | 0 | if (r < 0) |
205 | 0 | goto clear; |
206 | | |
207 | 0 | n++; |
208 | 0 | } |
209 | | |
210 | 0 | *ret_dns = TAKE_PTR(dns); |
211 | 0 | *ret_n_dns = n; |
212 | 0 | return 0; |
213 | | |
214 | 0 | clear: |
215 | 0 | for (size_t i = 0; i < n; i++) |
216 | 0 | in_addr_full_free(dns[i]); |
217 | 0 | free(dns); |
218 | |
|
219 | 0 | return r; |
220 | 0 | } |
221 | | |
222 | 0 | int bus_message_append_string_set(sd_bus_message *m, const Set *set) { |
223 | 0 | int r; |
224 | |
|
225 | 0 | assert(m); |
226 | |
|
227 | 0 | r = sd_bus_message_open_container(m, 'a', "s"); |
228 | 0 | if (r < 0) |
229 | 0 | return r; |
230 | | |
231 | 0 | const char *s; |
232 | 0 | SET_FOREACH(s, set) { |
233 | 0 | r = sd_bus_message_append(m, "s", s); |
234 | 0 | if (r < 0) |
235 | 0 | return r; |
236 | 0 | } |
237 | | |
238 | 0 | return sd_bus_message_close_container(m); |
239 | 0 | } |
240 | | |
241 | 0 | int bus_message_dump_string(sd_bus_message *message) { |
242 | 0 | const char *s; |
243 | 0 | int r; |
244 | |
|
245 | 0 | assert(message); |
246 | |
|
247 | 0 | r = sd_bus_message_read(message, "s", &s); |
248 | 0 | if (r < 0) |
249 | 0 | return bus_log_parse_error(r); |
250 | | |
251 | 0 | fputs(s, stdout); |
252 | 0 | return 0; |
253 | 0 | } |
254 | | |
255 | 0 | int bus_message_dump_fd(sd_bus_message *message) { |
256 | 0 | int fd, r; |
257 | |
|
258 | 0 | assert(message); |
259 | |
|
260 | 0 | r = sd_bus_message_read(message, "h", &fd); |
261 | 0 | if (r < 0) |
262 | 0 | return bus_log_parse_error(r); |
263 | | |
264 | 0 | fflush(stdout); |
265 | 0 | r = copy_bytes(fd, STDOUT_FILENO, UINT64_MAX, 0); |
266 | 0 | if (r < 0) |
267 | 0 | return log_error_errno(r, "Failed to dump contents in received file descriptor: %m"); |
268 | | |
269 | 0 | return 0; |
270 | 0 | } |
271 | | |
272 | | DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(bus_message_hash_ops, |
273 | | void, trivial_hash_func, trivial_compare_func, |
274 | | sd_bus_message, sd_bus_message_unref); |