X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fnss-resolve%2Fnss-resolve.c;h=3f32ed06507df81eb72a7aa0c975b27cf5cba52e;hb=18ee085c155dcd5f196f2ef9b712698dfd377f82;hp=c67f59e17910efa9cc6d3fbf2bc54f4e65592dab;hpb=9d485985338a46b8cb1acdf1af6c1eb2e88acfee;p=elogind.git diff --git a/src/nss-resolve/nss-resolve.c b/src/nss-resolve/nss-resolve.c index c67f59e17..3f32ed065 100644 --- a/src/nss-resolve/nss-resolve.c +++ b/src/nss-resolve/nss-resolve.c @@ -29,10 +29,11 @@ #include #include #include +#include #include "sd-bus.h" #include "bus-util.h" -#include "bus-errors.h" +#include "bus-common-errors.h" #include "macro.h" #include "nss-util.h" #include "util.h" @@ -43,24 +44,49 @@ NSS_GETHOSTBYADDR_PROTOTYPES(resolve); #define DNS_CALL_TIMEOUT_USEC (45*USEC_PER_SEC) -static int count_addresses(sd_bus_message *m, unsigned af, const char **canonical) { - int c = 0, r; +typedef void (*voidfunc_t)(void); + +static voidfunc_t find_fallback(const char *module, const char *symbol) { + void *dl; + + /* Try to find a fallback NSS module symbol */ + + dl = dlopen(module, RTLD_LAZY|RTLD_NODELETE); + if (!dl) + return NULL; + + return dlsym(dl, symbol); +} + +static bool bus_error_shall_fallback(sd_bus_error *e) { + return sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN) || + sd_bus_error_has_name(e, SD_BUS_ERROR_NAME_HAS_NO_OWNER) || + sd_bus_error_has_name(e, SD_BUS_ERROR_NO_REPLY) || + sd_bus_error_has_name(e, SD_BUS_ERROR_ACCESS_DENIED); +} + +static int count_addresses(sd_bus_message *m, int af, const char **canonical) { + int c = 0, r, ifindex; assert(m); assert(canonical); - r = sd_bus_message_enter_container(m, 'a', "(yayi)"); + r = sd_bus_message_read(m, "i", &ifindex); + if (r < 0) + return r; + + r = sd_bus_message_enter_container(m, 'a', "(iay)"); if (r < 0) return r; - while ((r = sd_bus_message_enter_container(m, 'r', "yayi")) > 0) { - unsigned char family; + while ((r = sd_bus_message_enter_container(m, 'r', "iay")) > 0) { + int family; - r = sd_bus_message_read(m, "y", &family); + r = sd_bus_message_read(m, "i", &family); if (r < 0) return r; - r = sd_bus_message_skip(m, "ayi"); + r = sd_bus_message_skip(m, "ay"); if (r < 0) return r; @@ -101,11 +127,11 @@ enum nss_status _nss_resolve_gethostbyname4_r( _cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL; _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; struct gaih_addrtuple *r_tuple, *r_tuple_first = NULL; - _cleanup_bus_unref_ sd_bus *bus = NULL; + _cleanup_bus_close_unref_ sd_bus *bus = NULL; const char *canonical = NULL; size_t l, ms, idx; char *r_name; - int c, r, i = 0; + int c, r, i = 0, ifindex; assert(name); assert(pat); @@ -131,7 +157,7 @@ enum nss_status _nss_resolve_gethostbyname4_r( if (r < 0) goto fail; - r = sd_bus_message_append(req, "sy", name, AF_UNSPEC); + r = sd_bus_message_append(req, "isit", 0, name, AF_UNSPEC, (uint64_t) 0); if (r < 0) goto fail; @@ -143,6 +169,25 @@ enum nss_status _nss_resolve_gethostbyname4_r( return NSS_STATUS_NOTFOUND; } + if (bus_error_shall_fallback(&error)) { + + enum nss_status (*fallback)( + const char *name, + struct gaih_addrtuple **pat, + char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp); + + fallback = (enum nss_status (*)(const char *name, + struct gaih_addrtuple **pat, + char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp)) + find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyname4_r"); + if (fallback) + return fallback(name, pat, buffer, buflen, errnop, h_errnop, ttlp); + } + *errnop = -r; *h_errnop = NO_RECOVERY; return NSS_STATUS_UNAVAIL; @@ -178,17 +223,25 @@ enum nss_status _nss_resolve_gethostbyname4_r( /* Second, append addresses */ r_tuple_first = (struct gaih_addrtuple*) (buffer + idx); - r = sd_bus_message_enter_container(reply, 'a', "(yayi)"); + r = sd_bus_message_read(reply, "i", &ifindex); if (r < 0) goto fail; - while ((r = sd_bus_message_enter_container(reply, 'r', "yayi")) > 0) { - unsigned char family; + if (ifindex < 0) { + r = -EINVAL; + goto fail; + } + + r = sd_bus_message_enter_container(reply, 'a', "(iay)"); + if (r < 0) + goto fail; + + while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) { + int family; const void *a; - int ifindex; size_t sz; - r = sd_bus_message_read(reply, "y", &family); + r = sd_bus_message_read(reply, "i", &family); if (r < 0) goto fail; @@ -196,10 +249,6 @@ enum nss_status _nss_resolve_gethostbyname4_r( if (r < 0) goto fail; - r = sd_bus_message_read(reply, "i", &ifindex); - if (r < 0) - goto fail; - r = sd_bus_message_exit_container(reply); if (r < 0) goto fail; @@ -212,11 +261,6 @@ enum nss_status _nss_resolve_gethostbyname4_r( goto fail; } - if (ifindex < 0) { - r = -EINVAL; - goto fail; - } - r_tuple = (struct gaih_addrtuple*) (buffer + idx); r_tuple->next = i == c-1 ? NULL : (struct gaih_addrtuple*) ((char*) r_tuple + ALIGN(sizeof(struct gaih_addrtuple))); r_tuple->name = r_name; @@ -241,6 +285,11 @@ enum nss_status _nss_resolve_gethostbyname4_r( if (ttlp) *ttlp = 0; + /* Explicitly reset all error variables */ + *errnop = 0; + *h_errnop = NETDB_SUCCESS; + h_errno = 0; + return NSS_STATUS_SUCCESS; fail: @@ -261,10 +310,10 @@ enum nss_status _nss_resolve_gethostbyname3_r( _cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL; _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; char *r_name, *r_aliases, *r_addr, *r_addr_list; - _cleanup_bus_unref_ sd_bus *bus = NULL; + _cleanup_bus_close_unref_ sd_bus *bus = NULL; size_t l, idx, ms, alen; const char *canonical; - int c, r, i = 0; + int c, r, i = 0, ifindex; assert(name); assert(result); @@ -298,7 +347,7 @@ enum nss_status _nss_resolve_gethostbyname3_r( if (r < 0) goto fail; - r = sd_bus_message_append(req, "sy", name, af); + r = sd_bus_message_append(req, "isit", 0, name, af, (uint64_t) 0); if (r < 0) goto fail; @@ -310,6 +359,29 @@ enum nss_status _nss_resolve_gethostbyname3_r( return NSS_STATUS_NOTFOUND; } + if (bus_error_shall_fallback(&error)) { + + enum nss_status (*fallback)( + const char *name, + int af, + struct hostent *result, + char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp, + char **canonp); + + fallback = (enum nss_status (*)(const char *name, + int af, + struct hostent *result, + char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp, + char **canonp)) + find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyname3_r"); + if (fallback) + return fallback(name, af, result, buffer, buflen, errnop, h_errnop, ttlp, canonp); + } + *errnop = -r; *h_errnop = NO_RECOVERY; return NSS_STATUS_UNAVAIL; @@ -332,10 +404,7 @@ enum nss_status _nss_resolve_gethostbyname3_r( alen = FAMILY_ADDRESS_SIZE(af); l = strlen(canonical); - ms = ALIGN(l+1) + - sizeof(char*) + - (c > 0 ? c : 1) * ALIGN(alen) + - (c > 0 ? c+1 : 2) * sizeof(char*); + ms = ALIGN(l+1) + c * ALIGN(alen) + (c+2) * sizeof(char*); if (buflen < ms) { *errnop = ENOMEM; @@ -356,17 +425,25 @@ enum nss_status _nss_resolve_gethostbyname3_r( /* Third, append addresses */ r_addr = buffer + idx; - r = sd_bus_message_enter_container(reply, 'a', "(yayi)"); + r = sd_bus_message_read(reply, "i", &ifindex); if (r < 0) goto fail; - while ((r = sd_bus_message_enter_container(reply, 'r', "yayi")) > 0) { - unsigned char family; + if (ifindex < 0) { + r = -EINVAL; + goto fail; + } + + r = sd_bus_message_enter_container(reply, 'a', "(iay)"); + if (r < 0) + goto fail; + + while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) { + int family; const void *a; - int ifindex; size_t sz; - r = sd_bus_message_read(reply, "y", &family); + r = sd_bus_message_read(reply, "i", &family); if (r < 0) goto fail; @@ -374,10 +451,6 @@ enum nss_status _nss_resolve_gethostbyname3_r( if (r < 0) goto fail; - r = sd_bus_message_read(reply, "i", &ifindex); - if (r < 0) - goto fail; - r = sd_bus_message_exit_container(reply); if (r < 0) goto fail; @@ -390,11 +463,6 @@ enum nss_status _nss_resolve_gethostbyname3_r( goto fail; } - if (ifindex < 0) { - r = -EINVAL; - goto fail; - } - memcpy(r_addr + i*ALIGN(alen), a, alen); i++; } @@ -420,6 +488,11 @@ enum nss_status _nss_resolve_gethostbyname3_r( result->h_length = alen; result->h_addr_list = (char**) r_addr_list; + /* Explicitly reset all error variables */ + *errnop = 0; + *h_errnop = NETDB_SUCCESS; + h_errno = 0; + if (ttlp) *ttlp = 0; @@ -445,11 +518,11 @@ enum nss_status _nss_resolve_gethostbyaddr2_r( _cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL; _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; char *r_name, *r_aliases, *r_addr, *r_addr_list; - _cleanup_bus_unref_ sd_bus *bus = NULL; + _cleanup_bus_close_unref_ sd_bus *bus = NULL; unsigned c = 0, i = 0; size_t ms = 0, idx; const char *n; - int r; + int r, ifindex; assert(addr); assert(result); @@ -487,7 +560,7 @@ enum nss_status _nss_resolve_gethostbyaddr2_r( if (r < 0) goto fail; - r = sd_bus_message_append(req, "y", af); + r = sd_bus_message_append(req, "ii", 0, af); if (r < 0) goto fail; @@ -495,7 +568,7 @@ enum nss_status _nss_resolve_gethostbyaddr2_r( if (r < 0) goto fail; - r = sd_bus_message_append(req, "i", 0); + r = sd_bus_message_append(req, "t", (uint64_t) 0); if (r < 0) goto fail; @@ -507,11 +580,43 @@ enum nss_status _nss_resolve_gethostbyaddr2_r( return NSS_STATUS_NOTFOUND; } + if (bus_error_shall_fallback(&error)) { + + enum nss_status (*fallback)( + const void* addr, socklen_t len, + int af, + struct hostent *result, + char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp); + + fallback = (enum nss_status (*)( + const void* addr, socklen_t len, + int af, + struct hostent *result, + char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp)) + find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyaddr2_r"); + + if (fallback) + return fallback(addr, len, af, result, buffer, buflen, errnop, h_errnop, ttlp); + } + *errnop = -r; *h_errnop = NO_RECOVERY; return NSS_STATUS_UNAVAIL; } + r = sd_bus_message_read(reply, "i", &ifindex); + if (r < 0) + goto fail; + + if (ifindex < 0) { + r = -EINVAL; + goto fail; + } + r = sd_bus_message_enter_container(reply, 'a', "s"); if (r < 0) goto fail; @@ -590,6 +695,11 @@ enum nss_status _nss_resolve_gethostbyaddr2_r( if (ttlp) *ttlp = 0; + /* Explicitly reset all error variables */ + *errnop = 0; + *h_errnop = NETDB_SUCCESS; + h_errno = 0; + return NSS_STATUS_SUCCESS; fail: