]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/nss-mymachines/nss-mymachines.c
machine: make sure unpriviliged "machinectl status" can show the machine's OS version
[thirdparty/systemd.git] / src / nss-mymachines / nss-mymachines.c
CommitLineData
cabb0bc6
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2014 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 <nss.h>
23#include <netdb.h>
24
25#include "sd-bus.h"
26#include "sd-login.h"
27#include "macro.h"
28#include "util.h"
29#include "nss-util.h"
30#include "bus-util.h"
31#include "in-addr-util.h"
32
33NSS_GETHOSTBYNAME_PROTOTYPES(mymachines);
34
0dd25fb9 35static int count_addresses(sd_bus_message *m, int af, unsigned *ret) {
cabb0bc6
LP
36 unsigned c = 0;
37 int r;
38
39 assert(m);
40 assert(ret);
41
42 while ((r = sd_bus_message_enter_container(m, 'r', "yay")) > 0) {
0dd25fb9 43 int family;
cabb0bc6 44
0dd25fb9 45 r = sd_bus_message_read(m, "i", &family);
cabb0bc6
LP
46 if (r < 0)
47 return r;
48
49 r = sd_bus_message_skip(m, "ay");
50 if (r < 0)
51 return r;
52
53 r = sd_bus_message_exit_container(m);
54 if (r < 0)
55 return r;
56
57 if (af != AF_UNSPEC && family != af)
58 continue;
59
60 c ++;
61 }
62 if (r < 0)
63 return r;
64
65 r = sd_bus_message_rewind(m, false);
66 if (r < 0)
67 return r;
68
69 *ret = c;
70 return 0;
71}
72
73enum nss_status _nss_mymachines_gethostbyname4_r(
74 const char *name,
75 struct gaih_addrtuple **pat,
76 char *buffer, size_t buflen,
77 int *errnop, int *h_errnop,
78 int32_t *ttlp) {
79
80 struct gaih_addrtuple *r_tuple, *r_tuple_first = NULL;
81 _cleanup_bus_message_unref_ sd_bus_message* reply = NULL;
24996861 82 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
634af566 83 _cleanup_free_ int *ifindices = NULL;
cabb0bc6
LP
84 _cleanup_free_ char *class = NULL;
85 size_t l, ms, idx;
86 unsigned i = 0, c = 0;
87 char *r_name;
634af566 88 int n_ifindices, r;
cabb0bc6
LP
89
90 assert(name);
91 assert(pat);
92 assert(buffer);
93 assert(errnop);
94 assert(h_errnop);
95
96 r = sd_machine_get_class(name, &class);
97 if (r < 0)
98 goto fail;
99 if (!streq(class, "container")) {
100 r = -ENOTTY;
101 goto fail;
102 }
103
634af566
LP
104 n_ifindices = sd_machine_get_ifindices(name, &ifindices);
105 if (n_ifindices < 0) {
106 r = n_ifindices;
cabb0bc6
LP
107 goto fail;
108 }
109
110 r = sd_bus_open_system(&bus);
111 if (r < 0)
112 goto fail;
113
114 r = sd_bus_call_method(bus,
115 "org.freedesktop.machine1",
116 "/org/freedesktop/machine1",
117 "org.freedesktop.machine1.Manager",
118 "GetMachineAddresses",
119 NULL,
120 &reply,
121 "s", name);
122 if (r < 0)
123 goto fail;
124
0dd25fb9 125 r = sd_bus_message_enter_container(reply, 'a', "(iay)");
cabb0bc6
LP
126 if (r < 0)
127 goto fail;
128
129 r = count_addresses(reply, AF_UNSPEC, &c);
130 if (r < 0)
131 goto fail;
132
133 if (c <= 0) {
555bd6e9 134 *errnop = ESRCH;
cabb0bc6
LP
135 *h_errnop = HOST_NOT_FOUND;
136 return NSS_STATUS_NOTFOUND;
137 }
138
139 l = strlen(name);
140 ms = ALIGN(l+1) + ALIGN(sizeof(struct gaih_addrtuple)) * c;
141 if (buflen < ms) {
142 *errnop = ENOMEM;
555bd6e9 143 *h_errnop = TRY_AGAIN;
cabb0bc6
LP
144 return NSS_STATUS_TRYAGAIN;
145 }
146
147 /* First, append name */
148 r_name = buffer;
149 memcpy(r_name, name, l+1);
150 idx = ALIGN(l+1);
151
152 /* Second, append addresses */
153 r_tuple_first = (struct gaih_addrtuple*) (buffer + idx);
0dd25fb9
LP
154 while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) {
155 int family;
cabb0bc6
LP
156 const void *a;
157 size_t sz;
158
0dd25fb9 159 r = sd_bus_message_read(reply, "i", &family);
cabb0bc6
LP
160 if (r < 0)
161 goto fail;
162
163 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
164 if (r < 0)
165 goto fail;
166
167 r = sd_bus_message_exit_container(reply);
168 if (r < 0)
169 goto fail;
170
555bd6e9
LP
171 if (!IN_SET(family, AF_INET, AF_INET6)) {
172 r = -EAFNOSUPPORT;
173 goto fail;
174 }
175
9d485985 176 if (sz != FAMILY_ADDRESS_SIZE(family)) {
cabb0bc6
LP
177 r = -EINVAL;
178 goto fail;
179 }
180
181 r_tuple = (struct gaih_addrtuple*) (buffer + idx);
182 r_tuple->next = i == c-1 ? NULL : (struct gaih_addrtuple*) ((char*) r_tuple + ALIGN(sizeof(struct gaih_addrtuple)));
183 r_tuple->name = r_name;
184 r_tuple->family = family;
634af566 185 r_tuple->scopeid = n_ifindices == 1 ? ifindices[0] : 0;
cabb0bc6
LP
186 memcpy(r_tuple->addr, a, sz);
187
188 idx += ALIGN(sizeof(struct gaih_addrtuple));
189 i++;
190 }
191
192 assert(i == c);
193
194 r = sd_bus_message_exit_container(reply);
195 if (r < 0)
196 goto fail;
197
198 assert(idx == ms);
199
200 if (*pat)
201 **pat = *r_tuple_first;
202 else
203 *pat = r_tuple_first;
204
205 if (ttlp)
206 *ttlp = 0;
207
e70df46b
LP
208 /* Explicitly reset all error variables */
209 *errnop = 0;
210 *h_errnop = NETDB_SUCCESS;
211 h_errno = 0;
212
cabb0bc6
LP
213 return NSS_STATUS_SUCCESS;
214
215fail:
216 *errnop = -r;
217 *h_errnop = NO_DATA;
218 return NSS_STATUS_UNAVAIL;
219}
220
221enum nss_status _nss_mymachines_gethostbyname3_r(
222 const char *name,
223 int af,
224 struct hostent *result,
225 char *buffer, size_t buflen,
226 int *errnop, int *h_errnop,
227 int32_t *ttlp,
228 char **canonp) {
229
230 _cleanup_bus_message_unref_ sd_bus_message* reply = NULL;
24996861 231 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
cabb0bc6
LP
232 _cleanup_free_ char *class = NULL;
233 unsigned c = 0, i = 0;
234 char *r_name, *r_aliases, *r_addr, *r_addr_list;
235 size_t l, idx, ms, alen;
236 int r;
237
238 assert(name);
239 assert(result);
240 assert(buffer);
241 assert(errnop);
242 assert(h_errnop);
243
244 if (af == AF_UNSPEC)
245 af = AF_INET;
246
247 if (af != AF_INET && af != AF_INET6) {
248 r = -EAFNOSUPPORT;
249 goto fail;
250 }
251
252 r = sd_machine_get_class(name, &class);
253 if (r < 0)
254 goto fail;
255 if (!streq(class, "container")) {
256 r = -ENOTTY;
257 goto fail;
258 }
259
260 r = sd_bus_open_system(&bus);
261 if (r < 0)
262 goto fail;
263
264 r = sd_bus_call_method(bus,
265 "org.freedesktop.machine1",
266 "/org/freedesktop/machine1",
267 "org.freedesktop.machine1.Manager",
268 "GetMachineAddresses",
269 NULL,
270 &reply,
271 "s", name);
272 if (r < 0)
273 goto fail;
274
0dd25fb9 275 r = sd_bus_message_enter_container(reply, 'a', "(iay)");
cabb0bc6
LP
276 if (r < 0)
277 goto fail;
278
279 r = count_addresses(reply, af, &c);
280 if (r < 0)
281 goto fail;
282
283 if (c <= 0) {
284 *errnop = ENOENT;
285 *h_errnop = HOST_NOT_FOUND;
286 return NSS_STATUS_NOTFOUND;
287 }
288
9d485985 289 alen = FAMILY_ADDRESS_SIZE(af);
cabb0bc6
LP
290 l = strlen(name);
291
292 ms = ALIGN(l+1) +
293 sizeof(char*) +
294 (c > 0 ? c : 1) * ALIGN(alen) +
295 (c > 0 ? c+1 : 2) * sizeof(char*);
296
297 if (buflen < ms) {
298 *errnop = ENOMEM;
299 *h_errnop = NO_RECOVERY;
300 return NSS_STATUS_TRYAGAIN;
301 }
302
303 /* First, append name */
304 r_name = buffer;
305 memcpy(r_name, name, l+1);
306 idx = ALIGN(l+1);
307
308 /* Second, create aliases array */
309 r_aliases = buffer + idx;
310 ((char**) r_aliases)[0] = NULL;
311 idx += sizeof(char*);
312
313 /* Third, append addresses */
314 r_addr = buffer + idx;
0dd25fb9
LP
315 while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) {
316 int family;
cabb0bc6
LP
317 const void *a;
318 size_t sz;
319
0dd25fb9 320 r = sd_bus_message_read(reply, "i", &family);
cabb0bc6
LP
321 if (r < 0)
322 goto fail;
323
324 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
325 if (r < 0)
326 goto fail;
327
328 r = sd_bus_message_exit_container(reply);
329 if (r < 0)
330 goto fail;
331
332 if (family != af)
333 continue;
334
335 if (sz != alen) {
336 r = -EINVAL;
337 goto fail;
338 }
339
340 memcpy(r_addr + i*ALIGN(alen), a, alen);
341 i++;
342 }
343
344 assert(i == c);
345 idx += c * ALIGN(alen);
346
347 r = sd_bus_message_exit_container(reply);
348 if (r < 0)
349 goto fail;
350
351 /* Third, append address pointer array */
352 r_addr_list = buffer + idx;
353 for (i = 0; i < c; i++)
354 ((char**) r_addr_list)[i] = r_addr + i*ALIGN(alen);
355
356 ((char**) r_addr_list)[i] = NULL;
357 idx += (c+1) * sizeof(char*);
358
359 assert(idx == ms);
360
361 result->h_name = r_name;
362 result->h_aliases = (char**) r_aliases;
363 result->h_addrtype = af;
364 result->h_length = alen;
365 result->h_addr_list = (char**) r_addr_list;
366
367 if (ttlp)
368 *ttlp = 0;
369
370 if (canonp)
371 *canonp = r_name;
372
e70df46b
LP
373 /* Explicitly reset all error variables */
374 *errnop = 0;
375 *h_errnop = NETDB_SUCCESS;
376 h_errno = 0;
377
cabb0bc6
LP
378 return NSS_STATUS_SUCCESS;
379
380fail:
381 *errnop = -r;
382 *h_errnop = NO_DATA;
383 return NSS_STATUS_UNAVAIL;
384}
385
386NSS_GETHOSTBYNAME_FALLBACKS(mymachines)