nss-myhostname.c   nss-myhostname.c 
skipping to change at line 33 skipping to change at line 33
#include <nss.h> #include <nss.h>
#include <sys/types.h> #include <sys/types.h>
#include <netdb.h> #include <netdb.h>
#include <errno.h> #include <errno.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <net/if.h> #include <net/if.h>
#include <stdlib.h> #include <stdlib.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include "ifconf.h" #include "local-addresses.h"
#include "macro.h" #include "macro.h"
#include "nss-util.h"
/* Ensure that glibc's assert is used. We cannot use assert from macro.h, a #include "util.h"
s
* libnss_myhostname will be linked into arbitrary programs which will, in
turn
* attempt to write to the journal via log_dispatch() */
#include <assert.h>
/* We use 127.0.0.2 as IPv4 address. This has the advantage over /* We use 127.0.0.2 as IPv4 address. This has the advantage over
* 127.0.0.1 that it can be translated back to the local hostname. For * 127.0.0.1 that it can be translated back to the local hostname. For
* IPv6 we use ::1 which unfortunately will not translate back to the * IPv6 we use ::1 which unfortunately will not translate back to the
* hostname but instead something like "localhost6" or so. */ * hostname but instead something like "localhost6" or so. */
#define LOCALADDRESS_IPV4 (htonl(0x7F000002)) #define LOCALADDRESS_IPV4 (htonl(0x7F000002))
#define LOCALADDRESS_IPV6 &in6addr_loopback #define LOCALADDRESS_IPV6 &in6addr_loopback
#define LOOPBACK_INTERFACE "lo" #define LOOPBACK_INTERFACE "lo"
enum nss_status _nss_myhostname_gethostbyname4_r( NSS_GETHOSTBYNAME_PROTOTYPES(myhostname);
const char *name, NSS_GETHOSTBYADDR_PROTOTYPES(myhostname);
struct gaih_addrtuple **pat,
char *buffer, size_t buflen,
int *errnop, int *h_errnop,
int32_t *ttlp) _public_;
enum nss_status _nss_myhostname_gethostbyname3_r(
const char *name,
int af,
struct hostent *host,
char *buffer, size_t buflen,
int *errnop, int *h_errnop,
int32_t *ttlp,
char **canonp) _public_;
enum nss_status _nss_myhostname_gethostbyname2_r(
const char *name,
int af,
struct hostent *host,
char *buffer, size_t buflen,
int *errnop, int *h_errnop) _public_;
enum nss_status _nss_myhostname_gethostbyname_r(
const char *name,
struct hostent *host,
char *buffer, size_t buflen,
int *errnop, int *h_errnop) _public_;
enum nss_status _nss_myhostname_gethostbyaddr2_r(
const void* addr, socklen_t len,
int af,
struct hostent *host,
char *buffer, size_t buflen,
int *errnop, int *h_errnop,
int32_t *ttlp) _public_;
enum nss_status _nss_myhostname_gethostbyaddr_r(
const void* addr, socklen_t len,
int af,
struct hostent *host,
char *buffer, size_t buflen,
int *errnop, int *h_errnop) _public_;
enum nss_status _nss_myhostname_gethostbyname4_r( enum nss_status _nss_myhostname_gethostbyname4_r(
const char *name, const char *name,
struct gaih_addrtuple **pat, struct gaih_addrtuple **pat,
char *buffer, size_t buflen, char *buffer, size_t buflen,
int *errnop, int *h_errnop, int *errnop, int *h_errnop,
int32_t *ttlp) { int32_t *ttlp) {
unsigned lo_ifi; struct gaih_addrtuple *r_tuple, *r_tuple_prev = NULL;
char hn[HOST_NAME_MAX+1] = {}; _cleanup_free_ struct local_address *addresses = NULL;
_cleanup_free_ char *hn = NULL;
const char *canonical = NULL; const char *canonical = NULL;
int n_addresses = 0, lo_ifi;
uint32_t local_address_ipv4;
struct local_address *a;
size_t l, idx, ms; size_t l, idx, ms;
char *r_name; char *r_name;
struct gaih_addrtuple *r_tuple, *r_tuple_prev = NULL; unsigned n;
struct address *addresses = NULL, *a;
unsigned n_addresses = 0, n; assert(name);
uint32_t local_address_ipv4; assert(pat);
assert(buffer);
assert(errnop);
assert(h_errnop);
if (strcasecmp(name, "localhost") == 0) { if (is_localhost(name)) {
/* We respond to 'localhost', so that /etc/hosts /* We respond to 'localhost', so that /etc/hosts
* is optional */ * is optional */
canonical = "localhost"; canonical = "localhost";
local_address_ipv4 = htonl(INADDR_LOOPBACK); local_address_ipv4 = htonl(INADDR_LOOPBACK);
} else { } else {
/* We respond to our local host name */ hn = gethostname_malloc();
if (!hn) {
if (gethostname(hn, sizeof(hn)-1) < 0) { *errnop = ENOMEM;
*errnop = errno;
*h_errnop = NO_RECOVERY; *h_errnop = NO_RECOVERY;
return NSS_STATUS_UNAVAIL; return NSS_STATUS_TRYAGAIN;
} }
if (strcasecmp(name, hn) != 0) { /* We respond to our local host name, our our hostname suff
ixed with a single dot. */
if (!streq(name, hn) && !streq_ptr(startswith(name, hn), ".
")) {
*errnop = ENOENT; *errnop = ENOENT;
*h_errnop = HOST_NOT_FOUND; *h_errnop = HOST_NOT_FOUND;
return NSS_STATUS_NOTFOUND; return NSS_STATUS_NOTFOUND;
} }
/* If this fails, n_addresses is 0. Which is fine */ n_addresses = local_addresses(NULL, 0, &addresses);
ifconf_acquire_addresses(&addresses, &n_addresses); if (n_addresses < 0)
n_addresses = 0;
canonical = hn; canonical = hn;
local_address_ipv4 = LOCALADDRESS_IPV4; local_address_ipv4 = LOCALADDRESS_IPV4;
} }
/* If this call fails we fill in 0 as scope. Which is fine */ /* If this call fails we fill in 0 as scope. Which is fine */
lo_ifi = n_addresses <= 0 ? if_nametoindex(LOOPBACK_INTERFACE) : 0; lo_ifi = n_addresses <= 0 ? if_nametoindex(LOOPBACK_INTERFACE) : 0;
l = strlen(canonical); l = strlen(canonical);
ms = ALIGN(l+1)+ALIGN(sizeof(struct gaih_addrtuple))*(n_addresses > 0 ? n_addresses : 2); ms = ALIGN(l+1) + ALIGN(sizeof(struct gaih_addrtuple)) * (n_address es > 0 ? n_addresses : 2);
if (buflen < ms) { if (buflen < ms) {
*errnop = ENOMEM; *errnop = ENOMEM;
*h_errnop = NO_RECOVERY; *h_errnop = NO_RECOVERY;
free(addresses);
return NSS_STATUS_TRYAGAIN; return NSS_STATUS_TRYAGAIN;
} }
/* First, fill in hostname */ /* First, fill in hostname */
r_name = buffer; r_name = buffer;
memcpy(r_name, canonical, l+1); memcpy(r_name, canonical, l+1);
idx = ALIGN(l+1); idx = ALIGN(l+1);
if (n_addresses <= 0) { if (n_addresses <= 0) {
/* Second, fill in IPv6 tuple */ /* Second, fill in IPv6 tuple */
skipping to change at line 181 skipping to change at line 144
r_tuple->name = r_name; r_tuple->name = r_name;
r_tuple->family = AF_INET; r_tuple->family = AF_INET;
*(uint32_t*) r_tuple->addr = local_address_ipv4; *(uint32_t*) r_tuple->addr = local_address_ipv4;
r_tuple->scopeid = (uint32_t) lo_ifi; r_tuple->scopeid = (uint32_t) lo_ifi;
idx += ALIGN(sizeof(struct gaih_addrtuple)); idx += ALIGN(sizeof(struct gaih_addrtuple));
r_tuple_prev = r_tuple; r_tuple_prev = r_tuple;
} }
/* Fourth, fill actual addresses in, but in backwards order */ /* Fourth, fill actual addresses in, but in backwards order */
for (a = addresses + n_addresses - 1, n = 0; n < n_addresses; n++, a--) { for (a = addresses + n_addresses - 1, n = 0; (int) n < n_addresses; n++, a--) {
r_tuple = (struct gaih_addrtuple*) (buffer + idx); r_tuple = (struct gaih_addrtuple*) (buffer + idx);
r_tuple->next = r_tuple_prev; r_tuple->next = r_tuple_prev;
r_tuple->name = r_name; r_tuple->name = r_name;
r_tuple->family = a->family; r_tuple->family = a->family;
r_tuple->scopeid = a->ifindex; r_tuple->scopeid = a->ifindex;
memcpy(r_tuple->addr, a->address, 16); memcpy(r_tuple->addr, &a->address, 16);
idx += ALIGN(sizeof(struct gaih_addrtuple)); idx += ALIGN(sizeof(struct gaih_addrtuple));
r_tuple_prev = r_tuple; r_tuple_prev = r_tuple;
} }
/* Verify the size matches */ /* Verify the size matches */
assert(idx == ms); assert(idx == ms);
/* Nscd expects us to store the first record in **pat. */ /* Nscd expects us to store the first record in **pat. */
if (*pat) if (*pat)
**pat = *r_tuple_prev; **pat = *r_tuple_prev;
else else
*pat = r_tuple_prev; *pat = r_tuple_prev;
if (ttlp) if (ttlp)
*ttlp = 0; *ttlp = 0;
free(addresses); /* Explicitly reset all error variables */
*errnop = 0;
*h_errnop = NETDB_SUCCESS;
h_errno = 0;
return NSS_STATUS_SUCCESS; return NSS_STATUS_SUCCESS;
} }
static enum nss_status fill_in_hostent( static enum nss_status fill_in_hostent(
const char *canonical, const char *additional, const char *canonical, const char *additional,
int af, int af,
struct address *addresses, unsigned n_addresses, struct local_address *addresses, unsigned n_addresses,
uint32_t local_address_ipv4, uint32_t local_address_ipv4,
struct hostent *result, struct hostent *result,
char *buffer, size_t buflen, char *buffer, size_t buflen,
int *errnop, int *h_errnop, int *errnop, int *h_errnop,
int32_t *ttlp, int32_t *ttlp,
char **canonp) { char **canonp) {
size_t l_canonical, l_additional, idx, ms; size_t l_canonical, l_additional, idx, ms, alen;
char *r_addr, *r_name, *r_aliases, *r_alias = NULL, *r_addr_list; char *r_addr, *r_name, *r_aliases, *r_alias = NULL, *r_addr_list;
size_t alen; struct local_address *a;
struct address *a;
unsigned n, c; unsigned n, c;
alen = PROTO_ADDRESS_SIZE(af); assert(canonical);
assert(result);
assert(buffer);
assert(errnop);
assert(h_errnop);
alen = FAMILY_ADDRESS_SIZE(af);
for (a = addresses, n = 0, c = 0; n < n_addresses; a++, n++) for (a = addresses, n = 0, c = 0; n < n_addresses; a++, n++)
if (af == a->family) if (af == a->family)
c++; c++;
l_canonical = strlen(canonical); l_canonical = strlen(canonical);
l_additional = additional ? strlen(additional) : 0; l_additional = additional ? strlen(additional) : 0;
ms = ALIGN(l_canonical+1)+ ms = ALIGN(l_canonical+1)+
(additional ? ALIGN(l_additional+1) : 0) + (additional ? ALIGN(l_additional+1) : 0) +
sizeof(char*)+ sizeof(char*) +
(additional ? sizeof(char*) : 0) + (additional ? sizeof(char*) : 0) +
(c > 0 ? c : 1)*ALIGN(alen)+ (c > 0 ? c : 1) * ALIGN(alen) +
(c > 0 ? c+1 : 2)*sizeof(char*); (c > 0 ? c+1 : 2) * sizeof(char*);
if (buflen < ms) { if (buflen < ms) {
*errnop = ENOMEM; *errnop = ENOMEM;
*h_errnop = NO_RECOVERY; *h_errnop = NO_RECOVERY;
free(addresses);
return NSS_STATUS_TRYAGAIN; return NSS_STATUS_TRYAGAIN;
} }
/* First, fill in hostnames */ /* First, fill in hostnames */
r_name = buffer; r_name = buffer;
memcpy(r_name, canonical, l_canonical+1); memcpy(r_name, canonical, l_canonical+1);
idx = ALIGN(l_canonical+1); idx = ALIGN(l_canonical+1);
if (additional) { if (additional) {
r_alias = buffer + idx; r_alias = buffer + idx;
skipping to change at line 280 skipping to change at line 250
/* Third, add addresses */ /* Third, add addresses */
r_addr = buffer + idx; r_addr = buffer + idx;
if (c > 0) { if (c > 0) {
unsigned i = 0; unsigned i = 0;
for (a = addresses, n = 0; n < n_addresses; a++, n++) { for (a = addresses, n = 0; n < n_addresses; a++, n++) {
if (af != a->family) if (af != a->family)
continue; continue;
memcpy(r_addr + i*ALIGN(alen), a->address, alen); memcpy(r_addr + i*ALIGN(alen), &a->address, alen);
i++; i++;
} }
assert(i == c); assert(i == c);
idx += c*ALIGN(alen); idx += c*ALIGN(alen);
} else { } else {
if (af == AF_INET) if (af == AF_INET)
*(uint32_t*) r_addr = local_address_ipv4; *(uint32_t*) r_addr = local_address_ipv4;
else else
memcpy(r_addr, LOCALADDRESS_IPV6, 16); memcpy(r_addr, LOCALADDRESS_IPV6, 16);
idx += ALIGN(alen); idx += ALIGN(alen);
} }
/* Fourth, add address pointer array */ /* Fourth, add address pointer array */
r_addr_list = buffer + idx; r_addr_list = buffer + idx;
if (c > 0) { if (c > 0) {
unsigned i = 0; unsigned i;
for (a = addresses, n = 0; n < n_addresses; a++, n++) {
if (af != a->family)
continue;
((char**) r_addr_list)[i] = (r_addr + i*ALIGN(alen) for (i = 0; i < c; i++)
); ((char**) r_addr_list)[i] = r_addr + i*ALIGN(alen);
i++;
}
assert(i == c); ((char**) r_addr_list)[i] = NULL;
((char**) r_addr_list)[c] = NULL; idx += (c+1) * sizeof(char*);
idx += (c+1)*sizeof(char*);
} else { } else {
((char**) r_addr_list)[0] = r_addr; ((char**) r_addr_list)[0] = r_addr;
((char**) r_addr_list)[1] = NULL; ((char**) r_addr_list)[1] = NULL;
idx += 2*sizeof(char*); idx += 2 * sizeof(char*);
} }
/* Verify the size matches */ /* Verify the size matches */
assert(idx == ms); assert(idx == ms);
result->h_name = r_name; result->h_name = r_name;
result->h_aliases = (char**) r_aliases; result->h_aliases = (char**) r_aliases;
result->h_addrtype = af; result->h_addrtype = af;
result->h_length = alen; result->h_length = alen;
result->h_addr_list = (char**) r_addr_list; result->h_addr_list = (char**) r_addr_list;
if (ttlp) if (ttlp)
*ttlp = 0; *ttlp = 0;
if (canonp) if (canonp)
*canonp = r_name; *canonp = r_name;
free(addresses); /* Explicitly reset all error variables */
*errnop = 0;
*h_errnop = NETDB_SUCCESS;
h_errno = 0;
return NSS_STATUS_SUCCESS; return NSS_STATUS_SUCCESS;
} }
enum nss_status _nss_myhostname_gethostbyname3_r( enum nss_status _nss_myhostname_gethostbyname3_r(
const char *name, const char *name,
int af, int af,
struct hostent *host, struct hostent *host,
char *buffer, size_t buflen, char *buffer, size_t buflen,
int *errnop, int *h_errnop, int *errnop, int *h_errnop,
int32_t *ttlp, int32_t *ttlp,
char **canonp) { char **canonp) {
char hn[HOST_NAME_MAX+1] = {}; _cleanup_free_ struct local_address *addresses = NULL;
struct address *addresses = NULL;
unsigned n_addresses = 0;
const char *canonical, *additional = NULL; const char *canonical, *additional = NULL;
_cleanup_free_ char *hn = NULL;
uint32_t local_address_ipv4; uint32_t local_address_ipv4;
int n_addresses = 0;
assert(name);
assert(host);
assert(buffer);
assert(errnop);
assert(h_errnop);
if (af == AF_UNSPEC) if (af == AF_UNSPEC)
af = AF_INET; af = AF_INET;
if (af != AF_INET && af != AF_INET6) { if (af != AF_INET && af != AF_INET6) {
*errnop = EAFNOSUPPORT; *errnop = EAFNOSUPPORT;
*h_errnop = NO_DATA; *h_errnop = NO_DATA;
return NSS_STATUS_UNAVAIL; return NSS_STATUS_UNAVAIL;
} }
if (strcasecmp(name, "localhost") == 0) { if (is_localhost(name)) {
canonical = "localhost"; canonical = "localhost";
local_address_ipv4 = htonl(INADDR_LOOPBACK); local_address_ipv4 = htonl(INADDR_LOOPBACK);
} else { } else {
if (gethostname(hn, sizeof(hn)-1) < 0) { hn = gethostname_malloc();
*errnop = errno; if (!hn) {
*errnop = ENOMEM;
*h_errnop = NO_RECOVERY; *h_errnop = NO_RECOVERY;
return NSS_STATUS_UNAVAIL; return NSS_STATUS_TRYAGAIN;
} }
if (strcasecmp(name, hn) != 0) { if (!streq(name, hn) && !streq_ptr(startswith(name, hn), ". ")) {
*errnop = ENOENT; *errnop = ENOENT;
*h_errnop = HOST_NOT_FOUND; *h_errnop = HOST_NOT_FOUND;
return NSS_STATUS_NOTFOUND; return NSS_STATUS_NOTFOUND;
} }
ifconf_acquire_addresses(&addresses, &n_addresses); n_addresses = local_addresses(NULL, 0, &addresses);
if (n_addresses < 0)
n_addresses = 0;
canonical = hn; canonical = hn;
additional = n_addresses <= 0 && af == AF_INET6 ? "localhos t" : NULL; additional = n_addresses <= 0 && af == AF_INET6 ? "localhos t" : NULL;
local_address_ipv4 = LOCALADDRESS_IPV4; local_address_ipv4 = LOCALADDRESS_IPV4;
} }
return fill_in_hostent( return fill_in_hostent(
canonical, additional, canonical, additional,
af, af,
addresses, n_addresses, addresses, n_addresses,
local_address_ipv4, local_address_ipv4,
host, host,
buffer, buflen, buffer, buflen,
errnop, h_errnop, errnop, h_errnop,
ttlp, ttlp,
canonp); canonp);
} }
enum nss_status _nss_myhostname_gethostbyname2_r(
const char *name,
int af,
struct hostent *host,
char *buffer, size_t buflen,
int *errnop, int *h_errnop) {
return _nss_myhostname_gethostbyname3_r(
name,
af,
host,
buffer, buflen,
errnop, h_errnop,
NULL,
NULL);
}
enum nss_status _nss_myhostname_gethostbyname_r(
const char *name,
struct hostent *host,
char *buffer, size_t buflen,
int *errnop, int *h_errnop) {
return _nss_myhostname_gethostbyname3_r(
name,
AF_UNSPEC,
host,
buffer, buflen,
errnop, h_errnop,
NULL,
NULL);
}
enum nss_status _nss_myhostname_gethostbyaddr2_r( enum nss_status _nss_myhostname_gethostbyaddr2_r(
const void* addr, socklen_t len, const void* addr, socklen_t len,
int af, int af,
struct hostent *host, struct hostent *host,
char *buffer, size_t buflen, char *buffer, size_t buflen,
int *errnop, int *h_errnop, int *errnop, int *h_errnop,
int32_t *ttlp) { int32_t *ttlp) {
char hn[HOST_NAME_MAX+1] = {};
struct address *addresses = NULL;
struct address *a;
unsigned n_addresses = 0, n;
uint32_t local_address_ipv4 = LOCALADDRESS_IPV4;
const char *canonical = NULL, *additional = NULL; const char *canonical = NULL, *additional = NULL;
uint32_t local_address_ipv4 = LOCALADDRESS_IPV4;
_cleanup_free_ struct local_address *addresses = NULL;
_cleanup_free_ char *hn = NULL;
int n_addresses = 0;
struct local_address *a;
unsigned n;
assert(addr);
assert(host);
assert(buffer);
assert(errnop);
assert(h_errnop);
if (len != PROTO_ADDRESS_SIZE(af)) { if (!IN_SET(af, AF_INET, AF_INET6)) {
*errnop = EAFNOSUPPORT;
*h_errnop = NO_DATA;
return NSS_STATUS_UNAVAIL;
}
if (len != FAMILY_ADDRESS_SIZE(af)) {
*errnop = EINVAL; *errnop = EINVAL;
*h_errnop = NO_RECOVERY; *h_errnop = NO_RECOVERY;
return NSS_STATUS_UNAVAIL; return NSS_STATUS_UNAVAIL;
} }
if (af == AF_INET) { if (af == AF_INET) {
if ((*(uint32_t*) addr) == LOCALADDRESS_IPV4) if ((*(uint32_t*) addr) == LOCALADDRESS_IPV4)
goto found; goto found;
if ((*(uint32_t*) addr) == htonl(INADDR_LOOPBACK)) { if ((*(uint32_t*) addr) == htonl(INADDR_LOOPBACK)) {
canonical = "localhost"; canonical = "localhost";
local_address_ipv4 = htonl(INADDR_LOOPBACK); local_address_ipv4 = htonl(INADDR_LOOPBACK);
goto found; goto found;
} }
} else if (af == AF_INET6) { } else {
assert(af == AF_INET6);
if (memcmp(addr, LOCALADDRESS_IPV6, 16) == 0) { if (memcmp(addr, LOCALADDRESS_IPV6, 16) == 0) {
additional = "localhost"; additional = "localhost";
goto found; goto found;
} }
} else {
*errnop = EAFNOSUPPORT;
*h_errnop = NO_DATA;
return NSS_STATUS_UNAVAIL;
} }
ifconf_acquire_addresses(&addresses, &n_addresses); n_addresses = local_addresses(NULL, 0, &addresses);
if (n_addresses < 0)
n_addresses = 0;
for (a = addresses, n = 0; n < n_addresses; n++, a++) { for (a = addresses, n = 0; (int) n < n_addresses; n++, a++) {
if (af != a->family) if (af != a->family)
continue; continue;
if (memcmp(addr, a->address, PROTO_ADDRESS_SIZE(af)) == 0) if (memcmp(addr, &a->address, FAMILY_ADDRESS_SIZE(af)) == 0 )
goto found; goto found;
} }
*errnop = ENOENT; *errnop = ENOENT;
*h_errnop = HOST_NOT_FOUND; *h_errnop = HOST_NOT_FOUND;
free(addresses);
return NSS_STATUS_NOTFOUND; return NSS_STATUS_NOTFOUND;
found: found:
if (!canonical) { if (!canonical) {
if (gethostname(hn, sizeof(hn)-1) < 0) { hn = gethostname_malloc();
*errnop = errno; if (!hn) {
*errnop = ENOMEM;
*h_errnop = NO_RECOVERY; *h_errnop = NO_RECOVERY;
return NSS_STATUS_TRYAGAIN;
free(addresses);
return NSS_STATUS_UNAVAIL;
} }
canonical = hn; canonical = hn;
} }
return fill_in_hostent( return fill_in_hostent(
canonical, additional, canonical, additional,
af, af,
addresses, n_addresses, addresses, n_addresses,
local_address_ipv4, local_address_ipv4,
host, host,
buffer, buflen, buffer, buflen,
errnop, h_errnop, errnop, h_errnop,
ttlp, ttlp,
NULL); NULL);
} }
enum nss_status _nss_myhostname_gethostbyaddr_r( NSS_GETHOSTBYNAME_FALLBACKS(myhostname);
const void* addr, socklen_t len, NSS_GETHOSTBYADDR_FALLBACKS(myhostname);
int af,
struct hostent *host,
char *buffer, size_t buflen,
int *errnop, int *h_errnop) {
return _nss_myhostname_gethostbyaddr2_r(
addr, len,
af,
host,
buffer, buflen,
errnop, h_errnop,
NULL);
}
 End of changes. 50 change blocks. 
159 lines changed or deleted 109 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/