diff options
author | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
---|---|---|
committer | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
commit | 7c478bd95313f5f23a4c958a745db2134aa03244 (patch) | |
tree | c871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/lib/nsswitch/files/common/gethostent.c | |
download | illumos-gate-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz |
OpenSolaris Launch
Diffstat (limited to 'usr/src/lib/nsswitch/files/common/gethostent.c')
-rw-r--r-- | usr/src/lib/nsswitch/files/common/gethostent.c | 434 |
1 files changed, 434 insertions, 0 deletions
diff --git a/usr/src/lib/nsswitch/files/common/gethostent.c b/usr/src/lib/nsswitch/files/common/gethostent.c new file mode 100644 index 0000000000..24dd4550c1 --- /dev/null +++ b/usr/src/lib/nsswitch/files/common/gethostent.c @@ -0,0 +1,434 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * files/gethostent.c -- "files" backend for nsswitch "hosts" database + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <netdb.h> +#include "files_common.h" +#include <string.h> +#include <strings.h> +#include <stddef.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <ctype.h> + +static int check_name(); +static char *do_aliases(); +static char *strcasestr(); +nss_status_t __nss_files_XY_hostbyname(); +int __nss_files_2herrno(); + +static int +check_name(host, args) + struct hostent *host; + nss_XbyY_args_t *args; +{ + const char *name = args->key.name; + char **aliasp; + + if (!host->h_name) + return (0); + if (strcasecmp(host->h_name, name) == 0) { + return (1); + } + for (aliasp = host->h_aliases; *aliasp != 0; aliasp++) { + if (strcasecmp(*aliasp, name) == 0) { + return (1); + } + } + return (0); +} + +static nss_status_t +getbyname(be, a) + files_backend_ptr_t be; + void *a; +{ + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; + nss_status_t res; + + res = __nss_files_XY_hostbyname(be, argp, argp->key.name, AF_INET); + if (res != NSS_SUCCESS) + argp->h_errno = __nss_files_2herrno(res); + return (res); +} + + +int +__nss_files_check_addr(argp) + nss_XbyY_args_t *argp; +{ + struct hostent *host = (struct hostent *)argp->returnval; + + /* + * We know that /etc/hosts can only store one address per host, so... + */ + return (host->h_length == argp->key.hostaddr.len && + host->h_addrtype == argp->key.hostaddr.type && + memcmp(host->h_addr_list[0], argp->key.hostaddr.addr, + argp->key.hostaddr.len) == 0); +} + + +static nss_status_t +getbyaddr(be, a) + files_backend_ptr_t be; + void *a; +{ + nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; + nss_status_t res; + + res = _nss_files_XY_all(be, argp, 1, 0, __nss_files_check_addr); + if (res != NSS_SUCCESS) + argp->h_errno = __nss_files_2herrno(res); + return (res); +} + + +static files_backend_op_t host_ops[] = { + _nss_files_destr, + _nss_files_endent, + _nss_files_setent, + _nss_files_getent_netdb, + getbyname, + getbyaddr, +}; + +/*ARGSUSED*/ +nss_backend_t * +_nss_files_hosts_constr(dummy1, dummy2, dummy3) + const char *dummy1, *dummy2, *dummy3; +{ + return (_nss_files_constr(host_ops, + sizeof (host_ops) / sizeof (host_ops[0]), + _PATH_HOSTS, + NSS_LINELEN_HOSTS, + NULL)); +} + + +/* + * XXX - this duplicates code from files_common.c because we need to keep + * going after we've found a match to satisfy the multihomed host case. + */ +nss_status_t +__nss_files_XY_hostbyname(be, args, filter, type) + files_backend_ptr_t be; + nss_XbyY_args_t *args; + const char *filter; /* hint for name string */ + int type; +{ + nss_status_t res; + int parsestat; + char *first; + char *last; + int i, nhosts = 0; + struct hostent he, *hp, *thp; + in_addr_t taddr[MAXADDRS]; + struct in6_addr taddr6[MAXADDRS]; + char *abuf = 0; /* alias buffer */ + char *abuf_start = 0, *abuf_end; + int (*func)(); + + if (be->buf == 0 && + (be->buf = malloc(be->minbuf)) == 0) { + return (NSS_UNAVAIL); + } + + if (be->f == 0) { + if ((res = _nss_files_setent(be, 0)) != NSS_SUCCESS) + return (res); + } + + res = NSS_NOTFOUND; + args->erange = 0; + args->returnval = (char *)0; + hp = thp = (struct hostent *)args->buf.result; + + for (;;) { + char *instr = be->buf; + int linelen; + + if ((linelen = _nss_files_read_line(be->f, + instr, be->minbuf)) < 0) { + break; /* EOF */ + } + + /* + * This check avoids a malloc()/free() for the common + * case. Also, if we're trying to match an alias and an + * already matched entry doesn't share a canonical name + * with the current one, bail. + */ + if (nhosts == 0 && strcasestr(instr, filter) == 0) { + continue; + } + + if ((last = strchr(instr, '#')) == 0) + last = instr + linelen; + *last-- = '\0'; + for (first = instr; isspace(*first); first++) + ; + /* Ignore blank and comment lines */ + if (*first == '\0') + continue; + + while (isspace(*last)) + --last; + linelen = last - first + 1; + if (first != instr) + instr = first; + + if (nhosts && strcasestr(instr, hp->h_name) == 0) { + break; + } + /* + * If we've already matched once and have a possible match + * on this line, copy the aliases where they're safe from + * being overwritten when we look at the next entry. They're + * saved as a string of blank separated names for the alias + * parser. On errors, we return failure whether or not we + * have already obtained a valid address. + */ + if (nhosts == 1 && !abuf) { + abuf = malloc(args->buf.buflen); + if (abuf == NULL) { + res = NSS_UNAVAIL; + break; + } + abuf_start = &abuf[0]; + abuf_end = abuf_start + args->buf.buflen; + if (abuf + strlen(hp->h_name) + 1 > abuf_end) { + free(abuf_start); + abuf = NULL; + args->erange = 1; + res = NSS_NOTFOUND; + break; + } + (void) strcpy(abuf, hp->h_name); + abuf += strlen(hp->h_name); + *abuf++ = ' '; + abuf = do_aliases(hp, abuf, abuf_start, abuf_end); + if (abuf == NULL) { + args->erange = 1; + res = NSS_NOTFOUND; + break; + } + } + func = args->str2ent; + parsestat = (*func)(instr, linelen, thp, + args->buf.buffer, args->buf.buflen); + + if (parsestat != NSS_STR_PARSE_SUCCESS) { + if (parsestat == NSS_STR_PARSE_ERANGE) + args->erange = 1; + continue; + } + + /* + * Still need to check, strcasestr() above is just a hint. + */ + + if (type == thp->h_addrtype) + if (check_name(thp, args)) { + if (type == AF_INET) + taddr[nhosts++] = + (*(in_addr_t *)thp->h_addr_list[0]); + else { + memcpy(&taddr6[nhosts++], thp->h_addr_list[0], + sizeof (struct in6_addr)); + } + + + if (nhosts == 1) { + res = NSS_SUCCESS; + args->returnval = args->buf.result; + thp = &he; /* switch to tmp hostent */ + continue; + } + if (nhosts >= MAXADDRS) + break; + abuf = do_aliases(thp, abuf, abuf_start, abuf_end); + if (abuf == NULL) { + args->erange = 1; + res = NSS_NOTFOUND; + break; + } + } else if (abuf && + strcasecmp(hp->h_name, thp->h_name) == 0) { + /* + * This line didn't have the requested name but + * is part of the same multihomed host (i.e. it + * has the same canonical name as the previous + * line), so march on... + */ + continue; + } else if (nhosts) { + break; + } + } + + if (abuf) { + struct in_addr *addrp; + struct in6_addr *addrp6; + + if (type == AF_INET) { + addrp = (struct in_addr *)(ROUND_DOWN(args->buf.buffer + + args->buf.buflen, sizeof (*addrp))); + hp->h_addr_list = (char **)(ROUND_DOWN(addrp - + ((nhosts + 1) * sizeof (char *) + + (nhosts * sizeof (*addrp))), sizeof (char *))); + for (i = 0, --addrp; i < nhosts; i++, --addrp) { + (*(in_addr_t *)addrp) = taddr[i]; + hp->h_addr_list[i] = (char *)addrp; + } + } else { + addrp6 = (struct in6_addr *) + (ROUND_DOWN(args->buf.buffer + args->buf.buflen, + sizeof (*addrp6))); + hp->h_addr_list = (char **)(ROUND_DOWN(addrp6 - + ((nhosts + 1) * sizeof (char *) + + (nhosts * sizeof (*addrp6))), sizeof (char *))); + for (i = 0, --addrp6; i < nhosts; i++, --addrp6) { + memcpy(addrp6, &taddr6[i], + sizeof (struct in6_addr)); + hp->h_addr_list[i] = (char *)addrp6; + } + } + + hp->h_addr_list[nhosts] = 0; + hp->h_aliases = _nss_netdb_aliases(abuf_start, + abuf - abuf_start, args->buf.buffer, + (char *)hp->h_addr_list - args->buf.buffer); + if (hp->h_aliases == 0) { + args->erange = 1; + res = NSS_STR_PARSE_ERANGE; + } else { + hp->h_name = hp->h_aliases[0]; + hp->h_aliases++; + } + free(abuf_start); + } + + /* + * stayopen is set to 0 by default in order to close the opened + * file. Some applications may break if it is set to 1. + */ + if (!args->stayopen) + (void) _nss_files_endent(be, 0); + + return (res); +} + +/* + * A case-insensitive version of strstr(). + */ +static char * +strcasestr(as1, as2) + char *as1; + char *as2; +{ + int c2; + register char *tptr; + register char *s1, *s2; + + s1 = as1; + s2 = as2; + + if (s2 == NULL || *s2 == '\0') + return (0); + + while (*s1) { + if (tolower(*s1++) == tolower(c2 = *s2)) { + tptr = s1; + while ((tolower(c2 = *++s2) == + tolower(*s1++)) && c2 != 0) + ; + if (c2 == 0) + return ((char *)tptr - 1); + s1 = tptr; + s2 = as2; + } + } + return (0); +} + + +static char * +do_aliases(hp, abuf, start, end) + struct hostent *hp; + char *abuf; + char *start; + char *end; +{ + char **cp; + + for (cp = hp->h_aliases; cp && *cp && **cp; cp++) { + size_t len; + + len = strlen(*cp); + if (abuf+len+1 >= end) { + free(start); + return ((char *)0); + } + (void) strcpy(abuf, *cp); + abuf += len; + *abuf++ = ' '; + } + *abuf = '\0'; + + return (abuf); +} + + +/* + * This is a copy of a routine in libnsl/nss/netdir_inet.c. It is + * here because /etc/lib/nss_files.so.1 cannot call routines + * in libnsl. Care should be taken to keep the two copies in sync. + */ +int +__nss_files_2herrno(nsstat) + nss_status_t nsstat; +{ + switch (nsstat) { + case NSS_SUCCESS: + /* no macro-defined success code for h_errno */ + return (0); + case NSS_NOTFOUND: + return (HOST_NOT_FOUND); + case NSS_TRYAGAIN: + return (TRY_AGAIN); + case NSS_UNAVAIL: + return (NO_RECOVERY); + } + /* anything else */ + return (NO_RECOVERY); +} |