LCOV - code coverage report
Current view: top level - nss-myhostname - nss-myhostname.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 0 272 0.0 %
Date: 2019-08-22 15:41:25 Functions: 0 7 0.0 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <errno.h>
       4             : #include <net/if.h>
       5             : #include <netdb.h>
       6             : #include <nss.h>
       7             : #include <stdlib.h>
       8             : #include <string.h>
       9             : 
      10             : #include "alloc-util.h"
      11             : #include "errno-util.h"
      12             : #include "hostname-util.h"
      13             : #include "local-addresses.h"
      14             : #include "macro.h"
      15             : #include "nss-util.h"
      16             : #include "signal-util.h"
      17             : #include "string-util.h"
      18             : 
      19             : /* We use 127.0.0.2 as IPv4 address. This has the advantage over
      20             :  * 127.0.0.1 that it can be translated back to the local hostname. For
      21             :  * IPv6 we use ::1 which unfortunately will not translate back to the
      22             :  * hostname but instead something like "localhost" or so. */
      23             : 
      24             : #define LOCALADDRESS_IPV4 (htobe32(0x7F000002))
      25             : #define LOCALADDRESS_IPV6 &in6addr_loopback
      26             : 
      27             : NSS_GETHOSTBYNAME_PROTOTYPES(myhostname);
      28             : NSS_GETHOSTBYADDR_PROTOTYPES(myhostname);
      29             : 
      30           0 : enum nss_status _nss_myhostname_gethostbyname4_r(
      31             :                 const char *name,
      32             :                 struct gaih_addrtuple **pat,
      33             :                 char *buffer, size_t buflen,
      34             :                 int *errnop, int *h_errnop,
      35             :                 int32_t *ttlp) {
      36             : 
      37           0 :         struct gaih_addrtuple *r_tuple, *r_tuple_prev = NULL;
      38           0 :         _cleanup_free_ struct local_address *addresses = NULL;
      39           0 :         _cleanup_free_ char *hn = NULL;
      40           0 :         const char *canonical = NULL;
      41           0 :         int n_addresses = 0;
      42             :         uint32_t local_address_ipv4;
      43             :         struct local_address *a;
      44             :         size_t l, idx, ms;
      45             :         char *r_name;
      46             :         unsigned n;
      47             : 
      48           0 :         PROTECT_ERRNO;
      49           0 :         BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
      50             : 
      51           0 :         assert(name);
      52           0 :         assert(pat);
      53           0 :         assert(buffer);
      54           0 :         assert(errnop);
      55           0 :         assert(h_errnop);
      56             : 
      57           0 :         if (is_localhost(name)) {
      58             :                 /* We respond to 'localhost', so that /etc/hosts
      59             :                  * is optional */
      60             : 
      61           0 :                 canonical = "localhost";
      62           0 :                 local_address_ipv4 = htobe32(INADDR_LOOPBACK);
      63             : 
      64           0 :         } else if (is_gateway_hostname(name)) {
      65             : 
      66           0 :                 n_addresses = local_gateways(NULL, 0, AF_UNSPEC, &addresses);
      67           0 :                 if (n_addresses <= 0)
      68           0 :                         goto not_found;
      69             : 
      70           0 :                 canonical = "_gateway";
      71             : 
      72             :         } else {
      73           0 :                 hn = gethostname_malloc();
      74           0 :                 if (!hn) {
      75           0 :                         UNPROTECT_ERRNO;
      76           0 :                         *errnop = ENOMEM;
      77           0 :                         *h_errnop = NO_RECOVERY;
      78           0 :                         return NSS_STATUS_TRYAGAIN;
      79             :                 }
      80             : 
      81             :                 /* We respond to our local host name, our hostname suffixed with a single dot. */
      82           0 :                 if (!streq(name, hn) && !streq_ptr(startswith(name, hn), "."))
      83           0 :                         goto not_found;
      84             : 
      85           0 :                 n_addresses = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
      86           0 :                 if (n_addresses < 0)
      87           0 :                         n_addresses = 0;
      88             : 
      89           0 :                 canonical = hn;
      90           0 :                 local_address_ipv4 = LOCALADDRESS_IPV4;
      91             :         }
      92             : 
      93           0 :         l = strlen(canonical);
      94           0 :         ms = ALIGN(l+1) + ALIGN(sizeof(struct gaih_addrtuple)) * (n_addresses > 0 ? n_addresses : 2);
      95           0 :         if (buflen < ms) {
      96           0 :                 UNPROTECT_ERRNO;
      97           0 :                 *errnop = ERANGE;
      98           0 :                 *h_errnop = NETDB_INTERNAL;
      99           0 :                 return NSS_STATUS_TRYAGAIN;
     100             :         }
     101             : 
     102             :         /* First, fill in hostname */
     103           0 :         r_name = buffer;
     104           0 :         memcpy(r_name, canonical, l+1);
     105           0 :         idx = ALIGN(l+1);
     106             : 
     107           0 :         assert(n_addresses >= 0);
     108           0 :         if (n_addresses == 0) {
     109             :                 /* Second, fill in IPv6 tuple */
     110           0 :                 r_tuple = (struct gaih_addrtuple*) (buffer + idx);
     111           0 :                 r_tuple->next = r_tuple_prev;
     112           0 :                 r_tuple->name = r_name;
     113           0 :                 r_tuple->family = AF_INET6;
     114           0 :                 memcpy(r_tuple->addr, LOCALADDRESS_IPV6, 16);
     115           0 :                 r_tuple->scopeid = 0;
     116             : 
     117           0 :                 idx += ALIGN(sizeof(struct gaih_addrtuple));
     118           0 :                 r_tuple_prev = r_tuple;
     119             : 
     120             :                 /* Third, fill in IPv4 tuple */
     121           0 :                 r_tuple = (struct gaih_addrtuple*) (buffer + idx);
     122           0 :                 r_tuple->next = r_tuple_prev;
     123           0 :                 r_tuple->name = r_name;
     124           0 :                 r_tuple->family = AF_INET;
     125           0 :                 *(uint32_t*) r_tuple->addr = local_address_ipv4;
     126           0 :                 r_tuple->scopeid = 0;
     127             : 
     128           0 :                 idx += ALIGN(sizeof(struct gaih_addrtuple));
     129           0 :                 r_tuple_prev = r_tuple;
     130             :         }
     131             : 
     132             :         /* Fourth, fill actual addresses in, but in backwards order */
     133           0 :         for (a = addresses + n_addresses - 1, n = 0; (int) n < n_addresses; n++, a--) {
     134           0 :                 r_tuple = (struct gaih_addrtuple*) (buffer + idx);
     135           0 :                 r_tuple->next = r_tuple_prev;
     136           0 :                 r_tuple->name = r_name;
     137           0 :                 r_tuple->family = a->family;
     138           0 :                 r_tuple->scopeid = a->family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&a->address.in6) ? a->ifindex : 0;
     139           0 :                 memcpy(r_tuple->addr, &a->address, 16);
     140             : 
     141           0 :                 idx += ALIGN(sizeof(struct gaih_addrtuple));
     142           0 :                 r_tuple_prev = r_tuple;
     143             :         }
     144             : 
     145             :         /* Verify the size matches */
     146           0 :         assert(idx == ms);
     147             : 
     148             :         /* Nscd expects us to store the first record in **pat. */
     149           0 :         if (*pat)
     150           0 :                 **pat = *r_tuple_prev;
     151             :         else
     152           0 :                 *pat = r_tuple_prev;
     153             : 
     154           0 :         if (ttlp)
     155           0 :                 *ttlp = 0;
     156             : 
     157             :         /* Explicitly reset both *h_errnop and h_errno to work around
     158             :          * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
     159           0 :         *h_errnop = NETDB_SUCCESS;
     160           0 :         h_errno = 0;
     161             : 
     162           0 :         return NSS_STATUS_SUCCESS;
     163             : 
     164           0 : not_found:
     165           0 :         *h_errnop = HOST_NOT_FOUND;
     166           0 :         return NSS_STATUS_NOTFOUND;
     167             : }
     168             : 
     169           0 : static enum nss_status fill_in_hostent(
     170             :                 const char *canonical, const char *additional,
     171             :                 int af,
     172             :                 struct local_address *addresses, unsigned n_addresses,
     173             :                 uint32_t local_address_ipv4,
     174             :                 struct hostent *result,
     175             :                 char *buffer, size_t buflen,
     176             :                 int *errnop, int *h_errnop,
     177             :                 int32_t *ttlp,
     178             :                 char **canonp) {
     179             : 
     180             :         size_t l_canonical, l_additional, idx, ms, alen;
     181           0 :         char *r_addr, *r_name, *r_aliases, *r_alias = NULL, *r_addr_list;
     182             :         struct local_address *a;
     183             :         unsigned n, c;
     184             : 
     185           0 :         assert(canonical);
     186           0 :         assert(result);
     187           0 :         assert(buffer);
     188           0 :         assert(errnop);
     189           0 :         assert(h_errnop);
     190             : 
     191           0 :         PROTECT_ERRNO;
     192             : 
     193           0 :         alen = FAMILY_ADDRESS_SIZE(af);
     194             : 
     195           0 :         for (a = addresses, n = 0, c = 0; n < n_addresses; a++, n++)
     196           0 :                 if (af == a->family)
     197           0 :                         c++;
     198             : 
     199           0 :         l_canonical = strlen(canonical);
     200           0 :         l_additional = strlen_ptr(additional);
     201           0 :         ms = ALIGN(l_canonical+1)+
     202           0 :                 (additional ? ALIGN(l_additional+1) : 0) +
     203           0 :                 sizeof(char*) +
     204           0 :                 (additional ? sizeof(char*) : 0) +
     205           0 :                 (c > 0 ? c : 1) * ALIGN(alen) +
     206           0 :                 (c > 0 ? c+1 : 2) * sizeof(char*);
     207             : 
     208           0 :         if (buflen < ms) {
     209           0 :                 UNPROTECT_ERRNO;
     210           0 :                 *errnop = ERANGE;
     211           0 :                 *h_errnop = NETDB_INTERNAL;
     212           0 :                 return NSS_STATUS_TRYAGAIN;
     213             :         }
     214             : 
     215             :         /* First, fill in hostnames */
     216           0 :         r_name = buffer;
     217           0 :         memcpy(r_name, canonical, l_canonical+1);
     218           0 :         idx = ALIGN(l_canonical+1);
     219             : 
     220           0 :         if (additional) {
     221           0 :                 r_alias = buffer + idx;
     222           0 :                 memcpy(r_alias, additional, l_additional+1);
     223           0 :                 idx += ALIGN(l_additional+1);
     224             :         }
     225             : 
     226             :         /* Second, create aliases array */
     227           0 :         r_aliases = buffer + idx;
     228           0 :         if (additional) {
     229           0 :                 ((char**) r_aliases)[0] = r_alias;
     230           0 :                 ((char**) r_aliases)[1] = NULL;
     231           0 :                 idx += 2*sizeof(char*);
     232             :         } else {
     233           0 :                 ((char**) r_aliases)[0] = NULL;
     234           0 :                 idx += sizeof(char*);
     235             :         }
     236             : 
     237             :         /* Third, add addresses */
     238           0 :         r_addr = buffer + idx;
     239           0 :         if (c > 0) {
     240           0 :                 unsigned i = 0;
     241             : 
     242           0 :                 for (a = addresses, n = 0; n < n_addresses; a++, n++) {
     243           0 :                         if (af != a->family)
     244           0 :                                 continue;
     245             : 
     246           0 :                         memcpy(r_addr + i*ALIGN(alen), &a->address, alen);
     247           0 :                         i++;
     248             :                 }
     249             : 
     250           0 :                 assert(i == c);
     251           0 :                 idx += c*ALIGN(alen);
     252             :         } else {
     253           0 :                 if (af == AF_INET)
     254           0 :                         *(uint32_t*) r_addr = local_address_ipv4;
     255             :                 else
     256           0 :                         memcpy(r_addr, LOCALADDRESS_IPV6, 16);
     257             : 
     258           0 :                 idx += ALIGN(alen);
     259             :         }
     260             : 
     261             :         /* Fourth, add address pointer array */
     262           0 :         r_addr_list = buffer + idx;
     263           0 :         if (c > 0) {
     264             :                 unsigned i;
     265             : 
     266           0 :                 for (i = 0; i < c; i++)
     267           0 :                         ((char**) r_addr_list)[i] = r_addr + i*ALIGN(alen);
     268             : 
     269           0 :                 ((char**) r_addr_list)[i] = NULL;
     270           0 :                 idx += (c+1) * sizeof(char*);
     271             : 
     272             :         } else {
     273           0 :                 ((char**) r_addr_list)[0] = r_addr;
     274           0 :                 ((char**) r_addr_list)[1] = NULL;
     275           0 :                 idx += 2 * sizeof(char*);
     276             :         }
     277             : 
     278             :         /* Verify the size matches */
     279           0 :         assert(idx == ms);
     280             : 
     281           0 :         result->h_name = r_name;
     282           0 :         result->h_aliases = (char**) r_aliases;
     283           0 :         result->h_addrtype = af;
     284           0 :         result->h_length = alen;
     285           0 :         result->h_addr_list = (char**) r_addr_list;
     286             : 
     287           0 :         if (ttlp)
     288           0 :                 *ttlp = 0;
     289             : 
     290           0 :         if (canonp)
     291           0 :                 *canonp = r_name;
     292             : 
     293             :         /* Explicitly reset both *h_errnop and h_errno to work around
     294             :          * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
     295           0 :         *h_errnop = NETDB_SUCCESS;
     296           0 :         h_errno = 0;
     297             : 
     298           0 :         return NSS_STATUS_SUCCESS;
     299             : }
     300             : 
     301           0 : enum nss_status _nss_myhostname_gethostbyname3_r(
     302             :                 const char *name,
     303             :                 int af,
     304             :                 struct hostent *host,
     305             :                 char *buffer, size_t buflen,
     306             :                 int *errnop, int *h_errnop,
     307             :                 int32_t *ttlp,
     308             :                 char **canonp) {
     309             : 
     310           0 :         _cleanup_free_ struct local_address *addresses = NULL;
     311           0 :         const char *canonical, *additional = NULL;
     312           0 :         _cleanup_free_ char *hn = NULL;
     313           0 :         uint32_t local_address_ipv4 = 0;
     314           0 :         int n_addresses = 0;
     315             : 
     316           0 :         PROTECT_ERRNO;
     317           0 :         BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
     318             : 
     319           0 :         assert(name);
     320           0 :         assert(host);
     321           0 :         assert(buffer);
     322           0 :         assert(errnop);
     323           0 :         assert(h_errnop);
     324             : 
     325           0 :         if (af == AF_UNSPEC)
     326           0 :                 af = AF_INET;
     327             : 
     328           0 :         if (!IN_SET(af, AF_INET, AF_INET6)) {
     329           0 :                 UNPROTECT_ERRNO;
     330           0 :                 *errnop = EAFNOSUPPORT;
     331           0 :                 *h_errnop = NO_DATA;
     332           0 :                 return NSS_STATUS_UNAVAIL;
     333             :         }
     334             : 
     335           0 :         if (is_localhost(name)) {
     336           0 :                 canonical = "localhost";
     337           0 :                 local_address_ipv4 = htobe32(INADDR_LOOPBACK);
     338             : 
     339           0 :         } else if (is_gateway_hostname(name)) {
     340             : 
     341           0 :                 n_addresses = local_gateways(NULL, 0, af, &addresses);
     342           0 :                 if (n_addresses <= 0)
     343           0 :                         goto not_found;
     344             : 
     345           0 :                 canonical = "_gateway";
     346             : 
     347             :         } else {
     348           0 :                 hn = gethostname_malloc();
     349           0 :                 if (!hn) {
     350           0 :                         UNPROTECT_ERRNO;
     351           0 :                         *errnop = ENOMEM;
     352           0 :                         *h_errnop = NO_RECOVERY;
     353           0 :                         return NSS_STATUS_TRYAGAIN;
     354             :                 }
     355             : 
     356           0 :                 if (!streq(name, hn) && !streq_ptr(startswith(name, hn), "."))
     357           0 :                         goto not_found;
     358             : 
     359           0 :                 n_addresses = local_addresses(NULL, 0, af, &addresses);
     360           0 :                 if (n_addresses < 0)
     361           0 :                         n_addresses = 0;
     362             : 
     363           0 :                 canonical = hn;
     364           0 :                 additional = n_addresses <= 0 && af == AF_INET6 ? "localhost" : NULL;
     365           0 :                 local_address_ipv4 = LOCALADDRESS_IPV4;
     366             :         }
     367             : 
     368           0 :         UNPROTECT_ERRNO;
     369             : 
     370           0 :         return fill_in_hostent(
     371             :                         canonical, additional,
     372             :                         af,
     373             :                         addresses, n_addresses,
     374             :                         local_address_ipv4,
     375             :                         host,
     376             :                         buffer, buflen,
     377             :                         errnop, h_errnop,
     378             :                         ttlp,
     379             :                         canonp);
     380             : 
     381           0 : not_found:
     382           0 :         *h_errnop = HOST_NOT_FOUND;
     383           0 :         return NSS_STATUS_NOTFOUND;
     384             : }
     385             : 
     386           0 : enum nss_status _nss_myhostname_gethostbyaddr2_r(
     387             :                 const void* addr, socklen_t len,
     388             :                 int af,
     389             :                 struct hostent *host,
     390             :                 char *buffer, size_t buflen,
     391             :                 int *errnop, int *h_errnop,
     392             :                 int32_t *ttlp) {
     393             : 
     394           0 :         const char *canonical = NULL, *additional = NULL;
     395           0 :         uint32_t local_address_ipv4 = LOCALADDRESS_IPV4;
     396           0 :         _cleanup_free_ struct local_address *addresses = NULL;
     397           0 :         _cleanup_free_ char *hn = NULL;
     398           0 :         int n_addresses = 0;
     399             :         struct local_address *a;
     400           0 :         bool additional_from_hostname = false;
     401             :         unsigned n;
     402             : 
     403           0 :         PROTECT_ERRNO;
     404           0 :         BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
     405             : 
     406           0 :         assert(addr);
     407           0 :         assert(host);
     408           0 :         assert(buffer);
     409           0 :         assert(errnop);
     410           0 :         assert(h_errnop);
     411             : 
     412           0 :         if (!IN_SET(af, AF_INET, AF_INET6)) {
     413           0 :                 UNPROTECT_ERRNO;
     414           0 :                 *errnop = EAFNOSUPPORT;
     415           0 :                 *h_errnop = NO_DATA;
     416           0 :                 return NSS_STATUS_UNAVAIL;
     417             :         }
     418             : 
     419           0 :         if (len != FAMILY_ADDRESS_SIZE(af)) {
     420           0 :                 UNPROTECT_ERRNO;
     421           0 :                 *errnop = EINVAL;
     422           0 :                 *h_errnop = NO_RECOVERY;
     423           0 :                 return NSS_STATUS_UNAVAIL;
     424             :         }
     425             : 
     426           0 :         if (af == AF_INET) {
     427           0 :                 if ((*(uint32_t*) addr) == LOCALADDRESS_IPV4)
     428           0 :                         goto found;
     429             : 
     430           0 :                 if ((*(uint32_t*) addr) == htobe32(INADDR_LOOPBACK)) {
     431           0 :                         canonical = "localhost";
     432           0 :                         local_address_ipv4 = htobe32(INADDR_LOOPBACK);
     433           0 :                         goto found;
     434             :                 }
     435             : 
     436             :         } else {
     437           0 :                 assert(af == AF_INET6);
     438             : 
     439           0 :                 if (memcmp(addr, LOCALADDRESS_IPV6, 16) == 0) {
     440           0 :                         canonical = "localhost";
     441           0 :                         additional_from_hostname = true;
     442           0 :                         goto found;
     443             :                 }
     444             :         }
     445             : 
     446           0 :         n_addresses = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
     447           0 :         for (a = addresses, n = 0; (int) n < n_addresses; n++, a++) {
     448           0 :                 if (af != a->family)
     449           0 :                         continue;
     450             : 
     451           0 :                 if (memcmp(addr, &a->address, FAMILY_ADDRESS_SIZE(af)) == 0)
     452           0 :                         goto found;
     453             :         }
     454             : 
     455           0 :         addresses = mfree(addresses);
     456             : 
     457           0 :         n_addresses = local_gateways(NULL, 0, AF_UNSPEC, &addresses);
     458           0 :         for (a = addresses, n = 0; (int) n < n_addresses; n++, a++) {
     459           0 :                 if (af != a->family)
     460           0 :                         continue;
     461             : 
     462           0 :                 if (memcmp(addr, &a->address, FAMILY_ADDRESS_SIZE(af)) == 0) {
     463           0 :                         canonical = "_gateway";
     464           0 :                         goto found;
     465             :                 }
     466             :         }
     467             : 
     468           0 :         *h_errnop = HOST_NOT_FOUND;
     469           0 :         return NSS_STATUS_NOTFOUND;
     470             : 
     471           0 : found:
     472           0 :         if (!canonical || additional_from_hostname) {
     473           0 :                 hn = gethostname_malloc();
     474           0 :                 if (!hn) {
     475           0 :                         UNPROTECT_ERRNO;
     476           0 :                         *errnop = ENOMEM;
     477           0 :                         *h_errnop = NO_RECOVERY;
     478           0 :                         return NSS_STATUS_TRYAGAIN;
     479             :                 }
     480             : 
     481           0 :                 if (!canonical)
     482           0 :                         canonical = hn;
     483             :                 else
     484           0 :                         additional = hn;
     485             :         }
     486             : 
     487           0 :         UNPROTECT_ERRNO;
     488           0 :         return fill_in_hostent(
     489             :                         canonical, additional,
     490             :                         af,
     491             :                         addresses, n_addresses,
     492             :                         local_address_ipv4,
     493             :                         host,
     494             :                         buffer, buflen,
     495             :                         errnop, h_errnop,
     496             :                         ttlp,
     497             :                         NULL);
     498             : }
     499             : 
     500           0 : NSS_GETHOSTBYNAME_FALLBACKS(myhostname);
     501           0 : NSS_GETHOSTBYADDR_FALLBACKS(myhostname);

Generated by: LCOV version 1.14