chiark / gitweb /
dns-domain: never allow labels that are larger than 63 chars
[elogind.git] / src / nss-mymachines / nss-mymachines.c
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
33 NSS_GETHOSTBYNAME_PROTOTYPES(mymachines);
34
35 static int count_addresses(sd_bus_message *m, unsigned af, unsigned *ret) {
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) {
43                 unsigned char family;
44
45                 r = sd_bus_message_read(m, "y", &family);
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
73 enum 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;
82         _cleanup_bus_unref_ sd_bus *bus = NULL;
83         _cleanup_free_ int *ifindexes = NULL;
84         _cleanup_free_ char *class = NULL;
85         size_t l, ms, idx;
86         unsigned i = 0, c = 0;
87         char *r_name;
88         int n_ifindexes, r;
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
104         n_ifindexes = sd_machine_get_ifindexes(name, &ifindexes);
105         if (n_ifindexes < 0) {
106                 r = n_ifindexes;
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
125         r = sd_bus_message_enter_container(reply, 'a', "(yay)");
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) {
134                 *errnop = ENOENT;
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;
143                 *h_errnop = NO_RECOVERY;
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);
154         while ((r = sd_bus_message_enter_container(reply, 'r', "yay")) > 0) {
155                 unsigned char family;
156                 const void *a;
157                 size_t sz;
158
159                 r = sd_bus_message_read(reply, "y", &family);
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
171                 if (sz != PROTO_ADDRESS_SIZE(family)) {
172                         r = -EINVAL;
173                         goto fail;
174                 }
175
176                 r_tuple = (struct gaih_addrtuple*) (buffer + idx);
177                 r_tuple->next = i == c-1 ? NULL : (struct gaih_addrtuple*) ((char*) r_tuple + ALIGN(sizeof(struct gaih_addrtuple)));
178                 r_tuple->name = r_name;
179                 r_tuple->family = family;
180                 r_tuple->scopeid = n_ifindexes == 1 ? ifindexes[0] : 0;
181                 memcpy(r_tuple->addr, a, sz);
182
183                 idx += ALIGN(sizeof(struct gaih_addrtuple));
184                 i++;
185         }
186
187         assert(i == c);
188
189         r = sd_bus_message_exit_container(reply);
190         if (r < 0)
191                 goto fail;
192
193         assert(idx == ms);
194
195         if (*pat)
196                 **pat = *r_tuple_first;
197         else
198                 *pat = r_tuple_first;
199
200         if (ttlp)
201                 *ttlp = 0;
202
203         return NSS_STATUS_SUCCESS;
204
205 fail:
206         *errnop = -r;
207         *h_errnop = NO_DATA;
208         return NSS_STATUS_UNAVAIL;
209 }
210
211 enum nss_status _nss_mymachines_gethostbyname3_r(
212                 const char *name,
213                 int af,
214                 struct hostent *result,
215                 char *buffer, size_t buflen,
216                 int *errnop, int *h_errnop,
217                 int32_t *ttlp,
218                 char **canonp) {
219
220         _cleanup_bus_message_unref_ sd_bus_message* reply = NULL;
221         _cleanup_bus_unref_ sd_bus *bus = NULL;
222         _cleanup_free_ char *class = NULL;
223         unsigned c = 0, i = 0;
224         char *r_name, *r_aliases, *r_addr, *r_addr_list;
225         size_t l, idx, ms, alen;
226         int r;
227
228         assert(name);
229         assert(result);
230         assert(buffer);
231         assert(errnop);
232         assert(h_errnop);
233
234         if (af == AF_UNSPEC)
235                 af = AF_INET;
236
237         if (af != AF_INET && af != AF_INET6) {
238                 r = -EAFNOSUPPORT;
239                 goto fail;
240         }
241
242         r = sd_machine_get_class(name, &class);
243         if (r < 0)
244                 goto fail;
245         if (!streq(class, "container")) {
246                 r = -ENOTTY;
247                 goto fail;
248         }
249
250         r = sd_bus_open_system(&bus);
251         if (r < 0)
252                 goto fail;
253
254         r = sd_bus_call_method(bus,
255                                "org.freedesktop.machine1",
256                                "/org/freedesktop/machine1",
257                                "org.freedesktop.machine1.Manager",
258                                "GetMachineAddresses",
259                                NULL,
260                                &reply,
261                                "s", name);
262         if (r < 0)
263                 goto fail;
264
265         r = sd_bus_message_enter_container(reply, 'a', "(yay)");
266         if (r < 0)
267                 goto fail;
268
269         r = count_addresses(reply, af, &c);
270         if (r < 0)
271                 goto fail;
272
273         if (c <= 0) {
274                 *errnop = ENOENT;
275                 *h_errnop = HOST_NOT_FOUND;
276                 return NSS_STATUS_NOTFOUND;
277         }
278
279         alen = PROTO_ADDRESS_SIZE(af);
280         l = strlen(name);
281
282         ms = ALIGN(l+1) +
283                 sizeof(char*) +
284                 (c > 0 ? c : 1) * ALIGN(alen) +
285                 (c > 0 ? c+1 : 2) * sizeof(char*);
286
287         if (buflen < ms) {
288                 *errnop = ENOMEM;
289                 *h_errnop = NO_RECOVERY;
290                 return NSS_STATUS_TRYAGAIN;
291         }
292
293         /* First, append name */
294         r_name = buffer;
295         memcpy(r_name, name, l+1);
296         idx = ALIGN(l+1);
297
298         /* Second, create aliases array */
299         r_aliases = buffer + idx;
300         ((char**) r_aliases)[0] = NULL;
301         idx += sizeof(char*);
302
303         /* Third, append addresses */
304         r_addr = buffer + idx;
305         while ((r = sd_bus_message_enter_container(reply, 'r', "yay")) > 0) {
306                 unsigned char family;
307                 const void *a;
308                 size_t sz;
309
310                 r = sd_bus_message_read(reply, "y", &family);
311                 if (r < 0)
312                         goto fail;
313
314                 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
315                 if (r < 0)
316                         goto fail;
317
318                 r = sd_bus_message_exit_container(reply);
319                 if (r < 0)
320                         goto fail;
321
322                 if (family != af)
323                         continue;
324
325                 if (sz != alen) {
326                         r = -EINVAL;
327                         goto fail;
328                 }
329
330                 memcpy(r_addr + i*ALIGN(alen), a, alen);
331                 i++;
332         }
333
334         assert(i == c);
335         idx += c * ALIGN(alen);
336
337         r = sd_bus_message_exit_container(reply);
338         if (r < 0)
339                 goto fail;
340
341         /* Third, append address pointer array */
342         r_addr_list = buffer + idx;
343         for (i = 0; i < c; i++)
344                 ((char**) r_addr_list)[i] = r_addr + i*ALIGN(alen);
345
346         ((char**) r_addr_list)[i] = NULL;
347         idx += (c+1) * sizeof(char*);
348
349         assert(idx == ms);
350
351         result->h_name = r_name;
352         result->h_aliases = (char**) r_aliases;
353         result->h_addrtype = af;
354         result->h_length = alen;
355         result->h_addr_list = (char**) r_addr_list;
356
357         if (ttlp)
358                 *ttlp = 0;
359
360         if (canonp)
361                 *canonp = r_name;
362
363         return NSS_STATUS_SUCCESS;
364
365 fail:
366         *errnop = -r;
367         *h_errnop = NO_DATA;
368         return NSS_STATUS_UNAVAIL;
369 }
370
371 NSS_GETHOSTBYNAME_FALLBACKS(mymachines)