chiark / gitweb /
bus: always explicitly close bus from main programs
[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', "yay")) > 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) +
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;
315         while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) {
316                 int family;
317                 const void *a;
318                 size_t sz;
319
320                 r = sd_bus_message_read(reply, "i", &family);
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
373         /* Explicitly reset all error variables */
374         *errnop = 0;
375         *h_errnop = NETDB_SUCCESS;
376         h_errno = 0;
377
378         return NSS_STATUS_SUCCESS;
379
380 fail:
381         *errnop = -r;
382         *h_errnop = NO_DATA;
383         return NSS_STATUS_UNAVAIL;
384 }
385
386 NSS_GETHOSTBYNAME_FALLBACKS(mymachines)