chiark / gitweb /
Remove src/nss-myhostname
[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, int 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', "iay")) > 0) {
43                 int family;
44
45                 r = sd_bus_message_read(m, "i", &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_close_unref_ sd_bus *bus = NULL;
83         _cleanup_free_ int *ifindices = 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_ifindices, 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_ifindices = sd_machine_get_ifindices(name, &ifindices);
105         if (n_ifindices < 0) {
106                 r = n_ifindices;
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', "(iay)");
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 = ESRCH;
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 = TRY_AGAIN;
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', "iay")) > 0) {
155                 int family;
156                 const void *a;
157                 size_t sz;
158
159                 r = sd_bus_message_read(reply, "i", &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 (!IN_SET(family, AF_INET, AF_INET6)) {
172                         r = -EAFNOSUPPORT;
173                         goto fail;
174                 }
175
176                 if (sz != FAMILY_ADDRESS_SIZE(family)) {
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;
185                 r_tuple->scopeid = n_ifindices == 1 ? ifindices[0] : 0;
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
208         /* Explicitly reset all error variables */
209         *errnop = 0;
210         *h_errnop = NETDB_SUCCESS;
211         h_errno = 0;
212
213         return NSS_STATUS_SUCCESS;
214
215 fail:
216         *errnop = -r;
217         *h_errnop = NO_DATA;
218         return NSS_STATUS_UNAVAIL;
219 }
220
221 enum 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;
231         _cleanup_bus_close_unref_ sd_bus *bus = NULL;
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
275         r = sd_bus_message_enter_container(reply, 'a', "(iay)");
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
289         alen = FAMILY_ADDRESS_SIZE(af);
290         l = strlen(name);
291
292         ms = ALIGN(l+1) + c * ALIGN(alen) + (c+2) * sizeof(char*);
293
294         if (buflen < ms) {
295                 *errnop = ENOMEM;
296                 *h_errnop = NO_RECOVERY;
297                 return NSS_STATUS_TRYAGAIN;
298         }
299
300         /* First, append name */
301         r_name = buffer;
302         memcpy(r_name, name, l+1);
303         idx = ALIGN(l+1);
304
305         /* Second, create aliases array */
306         r_aliases = buffer + idx;
307         ((char**) r_aliases)[0] = NULL;
308         idx += sizeof(char*);
309
310         /* Third, append addresses */
311         r_addr = buffer + idx;
312         while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) {
313                 int family;
314                 const void *a;
315                 size_t sz;
316
317                 r = sd_bus_message_read(reply, "i", &family);
318                 if (r < 0)
319                         goto fail;
320
321                 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
322                 if (r < 0)
323                         goto fail;
324
325                 r = sd_bus_message_exit_container(reply);
326                 if (r < 0)
327                         goto fail;
328
329                 if (family != af)
330                         continue;
331
332                 if (sz != alen) {
333                         r = -EINVAL;
334                         goto fail;
335                 }
336
337                 memcpy(r_addr + i*ALIGN(alen), a, alen);
338                 i++;
339         }
340
341         assert(i == c);
342         idx += c * ALIGN(alen);
343
344         r = sd_bus_message_exit_container(reply);
345         if (r < 0)
346                 goto fail;
347
348         /* Third, append address pointer array */
349         r_addr_list = buffer + idx;
350         for (i = 0; i < c; i++)
351                 ((char**) r_addr_list)[i] = r_addr + i*ALIGN(alen);
352
353         ((char**) r_addr_list)[i] = NULL;
354         idx += (c+1) * sizeof(char*);
355
356         assert(idx == ms);
357
358         result->h_name = r_name;
359         result->h_aliases = (char**) r_aliases;
360         result->h_addrtype = af;
361         result->h_length = alen;
362         result->h_addr_list = (char**) r_addr_list;
363
364         if (ttlp)
365                 *ttlp = 0;
366
367         if (canonp)
368                 *canonp = r_name;
369
370         /* Explicitly reset all error variables */
371         *errnop = 0;
372         *h_errnop = NETDB_SUCCESS;
373         h_errno = 0;
374
375         return NSS_STATUS_SUCCESS;
376
377 fail:
378         *errnop = -r;
379         *h_errnop = NO_DATA;
380         return NSS_STATUS_UNAVAIL;
381 }
382
383 NSS_GETHOSTBYNAME_FALLBACKS(mymachines)