summaryrefslogtreecommitdiff
path: root/REORG.TODO/hesiod
diff options
context:
space:
mode:
Diffstat (limited to 'REORG.TODO/hesiod')
-rw-r--r--REORG.TODO/hesiod/Depend2
-rw-r--r--REORG.TODO/hesiod/Makefile41
-rw-r--r--REORG.TODO/hesiod/README.hesiod155
-rw-r--r--REORG.TODO/hesiod/Versions14
-rw-r--r--REORG.TODO/hesiod/hesiod.c443
-rw-r--r--REORG.TODO/hesiod/hesiod.h50
-rw-r--r--REORG.TODO/hesiod/hesiod_p.h56
-rw-r--r--REORG.TODO/hesiod/nss_hesiod/hesiod-grp.c262
-rw-r--r--REORG.TODO/hesiod/nss_hesiod/hesiod-proto.c142
-rw-r--r--REORG.TODO/hesiod/nss_hesiod/hesiod-pwd.c110
-rw-r--r--REORG.TODO/hesiod/nss_hesiod/hesiod-service.c145
11 files changed, 1420 insertions, 0 deletions
diff --git a/REORG.TODO/hesiod/Depend b/REORG.TODO/hesiod/Depend
new file mode 100644
index 0000000000..0554b47da6
--- /dev/null
+++ b/REORG.TODO/hesiod/Depend
@@ -0,0 +1,2 @@
+nss
+resolv
diff --git a/REORG.TODO/hesiod/Makefile b/REORG.TODO/hesiod/Makefile
new file mode 100644
index 0000000000..3c967441e1
--- /dev/null
+++ b/REORG.TODO/hesiod/Makefile
@@ -0,0 +1,41 @@
+# Copyright (C) 1997-2017 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <http://www.gnu.org/licenses/>.
+
+#
+# Sub-makefile for hesiod portion of the library.
+#
+subdir := hesiod
+
+include ../Makeconfig
+
+extra-libs := libnss_hesiod
+extra-libs-others = $(extra-libs)
+
+subdir-dirs = nss_hesiod
+vpath %.c nss_hesiod
+
+libnss_hesiod-routines := hesiod hesiod-grp hesiod-proto \
+ hesiod-pwd hesiod-service
+# Build only shared library
+libnss_hesiod-inhibit-o = $(filter-out .os,$(object-suffixes))
+
+include ../Rules
+
+# The Hesiod NSS module also needs the resolver and some help from
+# the file service.
+$(objpfx)libnss_hesiod.so: $(common-objpfx)resolv/libresolv.so \
+ $(common-objpfx)nss/libnss_files.so
diff --git a/REORG.TODO/hesiod/README.hesiod b/REORG.TODO/hesiod/README.hesiod
new file mode 100644
index 0000000000..259ce8d447
--- /dev/null
+++ b/REORG.TODO/hesiod/README.hesiod
@@ -0,0 +1,155 @@
+The GNU C library contains an NSS module for the Hesiod name service.
+Hesiod is a general name service for a variety of applications and is
+based on the Berkeley Internet Name Daemon (BIND).
+
+Introduction
+============
+
+The Hesiod NSS module implements access to all relevant standard
+Hesiod types, which means that Hesiod can be used for the `group',
+`passwd' and `services' databases. There is however a restriction.
+In the same way that it is impossible to use `gethostent()' to iterate
+over all the data provided by DNS, it is not possible to scan the
+entire Hesiod database by means of `getgrent()', `getpwent()' and
+`getservent()'. Besides, Hesiod only provides support for looking up
+services by name and not for looking them up by port. In essence this
+means that the Hesiod name service is only consulted as a result of
+one of the following function calls:
+
+ * getgrname(), getgrgid()
+ * getpwname(), getpwuid()
+ * getservbyname()
+
+and their reentrant counterparts.
+
+
+Configuring your systems
+========================
+
+Configuring your systems to make use the Hesiod name service requires
+one or more of the following steps, depending on whether you are
+already running Hesiod in your network.
+
+Configuring NSS
+---------------
+
+First you should modify the file `/etc/nsswitch.conf' to tell
+NSS for which database you want to use the Hesiod name service. If
+you want to use Hesiod for all databases it can handle your
+configuration file could look like this:
+
+ # /etc/nsswitch.conf
+ #
+ # Example configuration of GNU Name Service Switch functionality.
+ #
+
+ passwd: db files hesiod
+ group: db files hesiod
+ shadow: db files
+
+ hosts: files dns
+ networks: files dns
+
+ protocols: db files
+ services: db files hesiod
+ ethers: db files
+ rpc: db files
+
+For more information on NSS, please refer to the `The GNU C Library
+Reference Manual'.
+
+
+Configuring Hesiod
+------------------
+
+Next, you will have to configure Hesiod. If you are already running
+Hesiod in your network, you probably already have a file named
+`hesiod.conf' on your machines (probably as `/etc/hesiod.conf' or
+`/usr/local/etc/hesiod.conf'). The Hesiod NSS module looks for
+`/etc/hesiod.conf' by default. If there is no configuration file you
+will want to create your own. It should look something like:
+
+ rhs=.your.domain
+ lhs=.ns
+ classes=in,hs
+
+The optional classes settings specifies which DNS classes Hesiod
+should do lookups in. Possible values are IN (the preferred class)
+and HS (the deprecated class, still used by some sites).
+You may specify both classes separated by a comma to try one class
+first and then the other if no entry is available in the first
+class. The default value of the classes variable is `IN,HS'.
+
+The value of rhs can be overridden by the environment variable
+`HES_DOMAIN'.
+
+Configuring your name servers
+-----------------------------
+
+In addition, if you are not already running Hesiod in your network,
+you need to create Hesiod information on your central name servers.
+You need to run `named' from BIND 4.9 or higher on these servers, and
+make them authoritative for the domain `ns.your.domain' with a line in
+`/etc/named.boot' reading something like:
+
+ primary ns.your.domain named.hesiod
+
+or if you are using the new BIND 8.1 or higher add something to
+`/etc/named.conf' like:
+
+ zone "ns.your.domain" {
+ type master;
+ file "named.hesiod";
+ };
+
+Then in the BIND working directory (usually `/var/named') create the
+file `named.hesiod' containing data that looks something like:
+
+ ; SOA and NS records.
+ @ IN SOA server1.your.domain admin-address.your.domain (
+ 40000 ; serial - database version number
+ 1800 ; refresh - sec servers
+ 300 ; retry - for refresh
+ 3600000 ; expire - unrefreshed data
+ 7200 ) ; min
+ NS server1.your.domain
+ NS server2.your.domain
+
+ ; Actual Hesiod data.
+ libc.group TXT "libc:*:123:gnu,gnat"
+ 123.gid CNAME libc.group
+ gnu.passwd TXT "gnu:*:4567:123:GNU:/home/gnu:/bin/bash"
+ 456.uid CNAME mark.passwd
+ nss.service TXT "nss tcp 789 switch sw "
+ nss.service TXT "nss udp 789 switch sw"
+
+where `libc' is an example of a group, `gnu' an example of an user,
+and `nss' an example of a service. Note that the format used to
+describe services differs from the format used in `/etc/services'.
+For more information on `named' refer to the `Name Server Operations
+Guide for BIND' that is included in the BIND distribution.
+
+
+Security
+========
+
+Note that the information stored in the Hesiod database in principle
+is publicly available. Care should be taken with including vulnerable
+information like encrypted passwords in the Hesiod database. There
+are some ways to improve security by using features provided by
+`named' (see the discussion about `secure zones' in the BIND
+documentation), but one should keep in mind that Hesiod was never
+intended to distribute passwords. In the origional design
+authenticating users was the job of the Kerberos service.
+
+
+More information
+================
+
+For more information on the Hesiod name service take a look at some of
+the papers in ftp://athena-dist.mit.edu:/pub/ATHENA/usenix and the
+documentation that accompanies the source code for the Hesiod name
+service library in ftp://athena-dist.mit.edu:/pub/ATHENA/hesiod.
+
+There is a mailing list at MIT for Hesiod users, hesiod@mit.edu. To
+get yourself on or off the list, send mail to hesiod-request@mit.edu.
diff --git a/REORG.TODO/hesiod/Versions b/REORG.TODO/hesiod/Versions
new file mode 100644
index 0000000000..1255b6825c
--- /dev/null
+++ b/REORG.TODO/hesiod/Versions
@@ -0,0 +1,14 @@
+libnss_hesiod {
+ GLIBC_PRIVATE {
+ _nss_hesiod_setpwent; _nss_hesiod_endpwent;
+ _nss_hesiod_getpwnam_r; _nss_hesiod_getpwuid_r;
+ _nss_hesiod_setgrent; _nss_hesiod_endgrent;
+ _nss_hesiod_getgrnam_r; _nss_hesiod_getgrgid_r;
+ _nss_hesiod_setservent; _nss_hesiod_endservent;
+ _nss_hesiod_getservbyname_r;
+ _nss_hesiod_initgroups_dyn;
+ _nss_hesiod_getservbyport_r;
+ _nss_hesiod_setprotoent; _nss_hesiod_endprotoent;
+ _nss_hesiod_getprotobyname_r; _nss_hesiod_getprotobynumber_r;
+ }
+}
diff --git a/REORG.TODO/hesiod/hesiod.c b/REORG.TODO/hesiod/hesiod.c
new file mode 100644
index 0000000000..9b54d1cb6b
--- /dev/null
+++ b/REORG.TODO/hesiod/hesiod.c
@@ -0,0 +1,443 @@
+/* Copyright (C) 1997-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/*
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * This file is primarily maintained by <tytso@mit.edu> and <ghudson@mit.edu>.
+ */
+
+/*
+ * hesiod.c --- the core portion of the hesiod resolver.
+ *
+ * This file is derived from the hesiod library from Project Athena;
+ * It has been extensively rewritten by Theodore Ts'o to have a more
+ * thread-safe interface.
+ */
+
+/* Imports */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "hesiod.h"
+#include "hesiod_p.h"
+
+#define _PATH_HESIOD_CONF "/etc/hesiod.conf"
+
+/* Forward */
+
+static int parse_config_file(struct hesiod_p *ctx, const char *filename);
+static char ** get_txt_records(struct hesiod_p *ctx, int class,
+ const char *name);
+
+/* Public */
+
+/*
+ * This function is called to initialize a hesiod_p.
+ */
+int
+hesiod_init(void **context) {
+ struct hesiod_p *ctx;
+ const char *configname;
+ char *cp;
+
+ ctx = malloc(sizeof(struct hesiod_p));
+ if (ctx == 0)
+ return (-1);
+
+ ctx->LHS = NULL;
+ ctx->RHS = NULL;
+ /* Set default query classes. */
+ ctx->classes[0] = C_IN;
+ ctx->classes[1] = C_HS;
+
+ configname = __libc_secure_getenv("HESIOD_CONFIG");
+ if (!configname)
+ configname = _PATH_HESIOD_CONF;
+ if (parse_config_file(ctx, configname) < 0) {
+ goto cleanup;
+ }
+ /*
+ * The default RHS can be overridden by an environment
+ * variable.
+ */
+ if ((cp = __libc_secure_getenv("HES_DOMAIN")) != NULL) {
+ free(ctx->RHS);
+ ctx->RHS = malloc(strlen(cp)+2);
+ if (!ctx->RHS)
+ goto cleanup;
+ if (cp[0] == '.')
+ strcpy(ctx->RHS, cp);
+ else {
+ ctx->RHS[0] = '.';
+ strcpy(ctx->RHS + 1, cp);
+ }
+ }
+
+ /*
+ * If there is no default hesiod realm set, we return an
+ * error.
+ */
+ if (!ctx->RHS) {
+ __set_errno(ENOEXEC);
+ goto cleanup;
+ }
+
+ *context = ctx;
+ return (0);
+
+ cleanup:
+ hesiod_end(ctx);
+ return (-1);
+}
+
+/*
+ * This function deallocates the hesiod_p
+ */
+void
+hesiod_end(void *context) {
+ struct hesiod_p *ctx = (struct hesiod_p *) context;
+ int save_errno = errno;
+
+ free(ctx->RHS);
+ free(ctx->LHS);
+ free(ctx);
+ __set_errno(save_errno);
+}
+
+/*
+ * This function takes a hesiod (name, type) and returns a DNS
+ * name which is to be resolved.
+ */
+char *
+hesiod_to_bind(void *context, const char *name, const char *type) {
+ struct hesiod_p *ctx = (struct hesiod_p *) context;
+ char *bindname;
+ char **rhs_list = NULL;
+ const char *RHS, *cp;
+ char *endp;
+
+ /* Decide what our RHS is, and set cp to the end of the actual name. */
+ if ((cp = strchr(name, '@')) != NULL) {
+ if (strchr(cp + 1, '.'))
+ RHS = cp + 1;
+ else if ((rhs_list = hesiod_resolve(context, cp + 1,
+ "rhs-extension")) != NULL)
+ RHS = *rhs_list;
+ else {
+ __set_errno(ENOENT);
+ return (NULL);
+ }
+ } else {
+ RHS = ctx->RHS;
+ cp = name + strlen(name);
+ }
+
+ /*
+ * Allocate the space we need, including up to three periods and
+ * the terminating NUL.
+ */
+ if ((bindname = malloc((cp - name) + strlen(type) + strlen(RHS) +
+ (ctx->LHS ? strlen(ctx->LHS) : 0) + 4)) == NULL) {
+ if (rhs_list)
+ hesiod_free_list(context, rhs_list);
+ return NULL;
+ }
+
+ /* Now put together the DNS name. */
+ endp = (char *) __mempcpy (bindname, name, cp - name);
+ *endp++ = '.';
+ endp = (char *) __stpcpy (endp, type);
+ if (ctx->LHS) {
+ if (ctx->LHS[0] != '.')
+ *endp++ = '.';
+ endp = __stpcpy (endp, ctx->LHS);
+ }
+ if (RHS[0] != '.')
+ *endp++ = '.';
+ strcpy (endp, RHS);
+
+ if (rhs_list)
+ hesiod_free_list(context, rhs_list);
+
+ return (bindname);
+}
+
+/*
+ * This is the core function. Given a hesiod (name, type), it
+ * returns an array of strings returned by the resolver.
+ */
+char **
+hesiod_resolve(void *context, const char *name, const char *type) {
+ struct hesiod_p *ctx = (struct hesiod_p *) context;
+ char *bindname = hesiod_to_bind(context, name, type);
+ char **retvec;
+
+ if (bindname == NULL)
+ return (NULL);
+
+ retvec = get_txt_records(ctx, ctx->classes[0], bindname);
+
+ if (retvec == NULL && (errno == ENOENT || errno == ECONNREFUSED) && ctx->classes[1])
+ retvec = get_txt_records(ctx, ctx->classes[1], bindname);
+
+
+ free(bindname);
+ return (retvec);
+}
+
+void
+hesiod_free_list(void *context, char **list) {
+ char **p;
+
+ for (p = list; *p; p++)
+ free(*p);
+ free(list);
+}
+
+/*
+ * This function parses the /etc/hesiod.conf file
+ */
+static int
+parse_config_file(struct hesiod_p *ctx, const char *filename) {
+ char buf[MAXDNAME+7];
+ FILE *fp;
+
+ /*
+ * Clear the existing configuration variable, just in case
+ * they're set.
+ */
+ free(ctx->RHS);
+ free(ctx->LHS);
+ ctx->RHS = ctx->LHS = 0;
+ /* Set default query classes. */
+ ctx->classes[0] = C_IN;
+ ctx->classes[1] = C_HS;
+
+ /*
+ * Now open and parse the file...
+ */
+ if (!(fp = fopen(filename, "rce")))
+ return (-1);
+
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ char *key, *data, *cp, **cpp;
+
+ cp = buf;
+ if (*cp == '#' || *cp == '\n' || *cp == '\r')
+ continue;
+ while(*cp == ' ' || *cp == '\t')
+ cp++;
+ key = cp;
+ while(*cp != ' ' && *cp != '\t' && *cp != '=')
+ cp++;
+ *cp++ = '\0';
+
+ while(*cp == ' ' || *cp == '\t' || *cp == '=')
+ cp++;
+ data = cp;
+ while(*cp != ' ' && *cp != '\n' && *cp != '\r')
+ cp++;
+ *cp++ = '\0';
+
+ cpp = NULL;
+ if (strcasecmp(key, "lhs") == 0)
+ cpp = &ctx->LHS;
+ else if (strcasecmp(key, "rhs") == 0)
+ cpp = &ctx->RHS;
+ if (cpp) {
+ *cpp = strdup(data);
+ if (!*cpp)
+ goto cleanup;
+ } else if (strcasecmp(key, "classes") == 0) {
+ int n = 0;
+ while (*data && n < 2) {
+ cp = strchrnul(data, ',');
+ if (*cp != '\0')
+ *cp++ = '\0';
+ if (strcasecmp(data, "IN") == 0)
+ ctx->classes[n++] = C_IN;
+ else if (strcasecmp(data, "HS") == 0)
+ ctx->classes[n++] = C_HS;
+ data = cp;
+ }
+ if (n == 0) {
+ /* Restore the default. Better than
+ nother at all. */
+ ctx->classes[0] = C_IN;
+ ctx->classes[1] = C_HS;
+ } else if (n == 1
+ || ctx->classes[0] == ctx->classes[1])
+ ctx->classes[1] = 0;
+ }
+ }
+ fclose(fp);
+ return (0);
+
+ cleanup:
+ fclose(fp);
+ free(ctx->RHS);
+ free(ctx->LHS);
+ ctx->RHS = ctx->LHS = 0;
+ return (-1);
+}
+
+/*
+ * Given a DNS class and a DNS name, do a lookup for TXT records, and
+ * return a list of them.
+ */
+static char **
+get_txt_records(struct hesiod_p *ctx, int class, const char *name) {
+ struct {
+ int type; /* RR type */
+ int class; /* RR class */
+ int dlen; /* len of data section */
+ u_char *data; /* pointer to data */
+ } rr;
+ HEADER *hp;
+ u_char qbuf[MAX_HESRESP], abuf[MAX_HESRESP];
+ u_char *cp, *erdata, *eom;
+ char *dst, *edst, **list;
+ int ancount, qdcount;
+ int i, j, n, skip;
+
+ /*
+ * Construct the query and send it.
+ */
+ n = res_mkquery(QUERY, name, class, T_TXT, NULL, 0,
+ NULL, qbuf, MAX_HESRESP);
+ if (n < 0) {
+ __set_errno(EMSGSIZE);
+ return (NULL);
+ }
+ n = res_send(qbuf, n, abuf, MAX_HESRESP);
+ if (n < 0) {
+ __set_errno(ECONNREFUSED);
+ return (NULL);
+ }
+ if (n < HFIXEDSZ) {
+ __set_errno(EMSGSIZE);
+ return (NULL);
+ }
+
+ /*
+ * OK, parse the result.
+ */
+ hp = (HEADER *) abuf;
+ ancount = ntohs(hp->ancount);
+ qdcount = ntohs(hp->qdcount);
+ cp = abuf + sizeof(HEADER);
+ eom = abuf + n;
+
+ /* Skip query, trying to get to the answer section which follows. */
+ for (i = 0; i < qdcount; i++) {
+ skip = dn_skipname(cp, eom);
+ if (skip < 0 || cp + skip + QFIXEDSZ > eom) {
+ __set_errno(EMSGSIZE);
+ return (NULL);
+ }
+ cp += skip + QFIXEDSZ;
+ }
+
+ list = malloc((ancount + 1) * sizeof(char *));
+ if (!list)
+ return (NULL);
+ j = 0;
+ for (i = 0; i < ancount; i++) {
+ skip = dn_skipname(cp, eom);
+ if (skip < 0) {
+ __set_errno(EMSGSIZE);
+ goto cleanup;
+ }
+ cp += skip;
+ if (cp + 3 * INT16SZ + INT32SZ > eom) {
+ __set_errno(EMSGSIZE);
+ goto cleanup;
+ }
+ rr.type = ns_get16(cp);
+ cp += INT16SZ;
+ rr.class = ns_get16(cp);
+ cp += INT16SZ + INT32SZ; /* skip the ttl, too */
+ rr.dlen = ns_get16(cp);
+ cp += INT16SZ;
+ if (rr.dlen == 0 || cp + rr.dlen > eom) {
+ __set_errno(EMSGSIZE);
+ goto cleanup;
+ }
+ rr.data = cp;
+ cp += rr.dlen;
+ if (rr.class != class || rr.type != T_TXT)
+ continue;
+ if (!(list[j] = malloc(rr.dlen)))
+ goto cleanup;
+ dst = list[j++];
+ edst = dst + rr.dlen;
+ erdata = rr.data + rr.dlen;
+ cp = rr.data;
+ while (cp < erdata) {
+ n = (unsigned char) *cp++;
+ if (cp + n > eom || dst + n > edst) {
+ __set_errno(EMSGSIZE);
+ goto cleanup;
+ }
+ memcpy(dst, cp, n);
+ cp += n;
+ dst += n;
+ }
+ if (cp != erdata) {
+ __set_errno(EMSGSIZE);
+ goto cleanup;
+ }
+ *dst = '\0';
+ }
+ list[j] = NULL;
+ if (j == 0) {
+ __set_errno(ENOENT);
+ goto cleanup;
+ }
+ return (list);
+
+ cleanup:
+ for (i = 0; i < j; i++)
+ free(list[i]);
+ free(list);
+ return (NULL);
+}
diff --git a/REORG.TODO/hesiod/hesiod.h b/REORG.TODO/hesiod/hesiod.h
new file mode 100644
index 0000000000..2cb640a7df
--- /dev/null
+++ b/REORG.TODO/hesiod/hesiod.h
@@ -0,0 +1,50 @@
+/* Copyright (C) 1997-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/*
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * This file is primarily maintained by <tytso@mit.edu> and <ghudson@mit.edu>.
+ */
+
+#ifndef _HESIOD_H_INCLUDED
+#define _HESIOD_H_INCLUDED
+
+int hesiod_init (void **context) attribute_hidden;
+void hesiod_end (void *context) attribute_hidden;
+char * hesiod_to_bind (void *context, const char *name,
+ const char *type) attribute_hidden;
+char ** hesiod_resolve (void *context, const char *name,
+ const char *type) attribute_hidden;
+void hesiod_free_list (void *context, char **list) attribute_hidden;
+
+#endif /*_HESIOD_H_INCLUDED*/
diff --git a/REORG.TODO/hesiod/hesiod_p.h b/REORG.TODO/hesiod/hesiod_p.h
new file mode 100644
index 0000000000..7ed70158d9
--- /dev/null
+++ b/REORG.TODO/hesiod/hesiod_p.h
@@ -0,0 +1,56 @@
+/* Copyright (C) 1997-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/*
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * This file is primarily maintained by <tytso@mit.edu> and <ghudson@mit.edu>.
+ */
+
+/*
+ * hesiod_p.h -- private definitions for the hesiod library
+ */
+
+#ifndef _HESIOD_P_H_INCLUDED
+#define _HESIOD_P_H_INCLUDED
+
+#define DEF_LHS ".ns" /* file is not */
+ /* present. */
+struct hesiod_p {
+ char * LHS; /* normally ".ns" */
+ char * RHS; /* AKA the default hesiod domain */
+ int classes[2]; /* The class search order. */
+};
+
+#define MAX_HESRESP 1024
+
+#endif /*_HESIOD_P_H_INCLUDED*/
diff --git a/REORG.TODO/hesiod/nss_hesiod/hesiod-grp.c b/REORG.TODO/hesiod/nss_hesiod/hesiod-grp.c
new file mode 100644
index 0000000000..a04f530945
--- /dev/null
+++ b/REORG.TODO/hesiod/nss_hesiod/hesiod-grp.c
@@ -0,0 +1,262 @@
+/* Copyright (C) 1997-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <ctype.h>
+#include <errno.h>
+#include <grp.h>
+#include <hesiod.h>
+#include <nss.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+
+/* Get the declaration of the parser function. */
+#define ENTNAME grent
+#define STRUCTURE group
+#define EXTERN_PARSER
+#include <nss/nss_files/files-parse.c>
+
+enum nss_status
+_nss_hesiod_setgrent (int stayopen)
+{
+ return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_hesiod_endgrent (void)
+{
+ return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status
+lookup (const char *name, const char *type, struct group *grp,
+ char *buffer, size_t buflen, int *errnop)
+{
+ struct parser_data *data = (void *) buffer;
+ size_t linebuflen;
+ void *context;
+ char **list;
+ int parse_res;
+ size_t len;
+ int olderr = errno;
+
+ if (hesiod_init (&context) < 0)
+ return NSS_STATUS_UNAVAIL;
+
+ list = hesiod_resolve (context, name, type);
+ if (list == NULL)
+ {
+ int err = errno;
+ hesiod_end (context);
+ __set_errno (olderr);
+ return err == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL;
+ }
+
+ linebuflen = buffer + buflen - data->linebuffer;
+ len = strlen (*list) + 1;
+ if (linebuflen < len)
+ {
+ hesiod_free_list (context, list);
+ hesiod_end (context);
+ *errnop = ERANGE;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ memcpy (data->linebuffer, *list, len);
+ hesiod_free_list (context, list);
+ hesiod_end (context);
+
+ parse_res = _nss_files_parse_grent (buffer, grp, data, buflen, errnop);
+ if (parse_res < 1)
+ {
+ __set_errno (olderr);
+ return parse_res == -1 ? NSS_STATUS_TRYAGAIN : NSS_STATUS_NOTFOUND;
+ }
+
+ return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_hesiod_getgrnam_r (const char *name, struct group *grp,
+ char *buffer, size_t buflen, int *errnop)
+{
+ return lookup (name, "group", grp, buffer, buflen, errnop);
+}
+
+enum nss_status
+_nss_hesiod_getgrgid_r (gid_t gid, struct group *grp,
+ char *buffer, size_t buflen, int *errnop)
+{
+ char gidstr[21]; /* We will probably never have a gid_t with more
+ than 64 bits. */
+
+ snprintf (gidstr, sizeof gidstr, "%d", gid);
+
+ return lookup (gidstr, "gid", grp, buffer, buflen, errnop);
+}
+
+static int
+internal_gid_in_list (const gid_t *list, const gid_t g, long int len)
+{
+ while (len > 0)
+ {
+ if (*list == g)
+ return 1;
+ --len;
+ ++list;
+ }
+ return 0;
+}
+
+static enum nss_status
+internal_gid_from_group (void *context, const char *groupname, gid_t *group)
+{
+ char **grp_res;
+ enum nss_status status = NSS_STATUS_NOTFOUND;
+
+ grp_res = hesiod_resolve (context, groupname, "group");
+ if (grp_res != NULL && *grp_res != NULL)
+ {
+ char *p = *grp_res;
+
+ /* Skip to third field. */
+ while (*p != '\0' && *p != ':')
+ ++p;
+ if (*p != '\0')
+ ++p;
+ while (*p != '\0' && *p != ':')
+ ++p;
+ if (*p != '\0')
+ {
+ char *endp;
+ char *q = ++p;
+ long int val;
+
+ while (*q != '\0' && *q != ':')
+ ++q;
+
+ val = strtol (p, &endp, 10);
+ if (sizeof (gid_t) == sizeof (long int) || (gid_t) val == val)
+ {
+ *group = val;
+ if (endp == q && endp != p)
+ status = NSS_STATUS_SUCCESS;
+ }
+ }
+ hesiod_free_list (context, grp_res);
+ }
+ return status;
+}
+
+enum nss_status
+_nss_hesiod_initgroups_dyn (const char *user, gid_t group, long int *start,
+ long int *size, gid_t **groupsp, long int limit,
+ int *errnop)
+{
+ enum nss_status status = NSS_STATUS_SUCCESS;
+ char **list = NULL;
+ char *p;
+ void *context;
+ gid_t *groups = *groupsp;
+ int save_errno;
+
+ if (hesiod_init (&context) < 0)
+ return NSS_STATUS_UNAVAIL;
+
+ list = hesiod_resolve (context, user, "grplist");
+
+ if (list == NULL)
+ {
+ hesiod_end (context);
+ return errno == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL;
+ }
+
+ save_errno = errno;
+
+ p = *list;
+ while (*p != '\0')
+ {
+ char *endp;
+ char *q;
+ long int val;
+
+ status = NSS_STATUS_NOTFOUND;
+
+ q = p;
+ while (*q != '\0' && *q != ':' && *q != ',')
+ ++q;
+
+ if (*q != '\0')
+ *q++ = '\0';
+
+ __set_errno (0);
+ val = strtol (p, &endp, 10);
+ /* Test whether the number is representable in a variable of
+ type `gid_t'. If not ignore the number. */
+ if ((sizeof (gid_t) == sizeof (long int) || (gid_t) val == val)
+ && errno == 0)
+ {
+ if (*endp == '\0' && endp != p)
+ {
+ group = val;
+ status = NSS_STATUS_SUCCESS;
+ }
+ else
+ status = internal_gid_from_group (context, p, &group);
+
+ if (status == NSS_STATUS_SUCCESS
+ && !internal_gid_in_list (groups, group, *start))
+ {
+ if (__glibc_unlikely (*start == *size))
+ {
+ /* Need a bigger buffer. */
+ gid_t *newgroups;
+ long int newsize;
+
+ if (limit > 0 && *size == limit)
+ /* We reached the maximum. */
+ goto done;
+
+ if (limit <= 0)
+ newsize = 2 * *size;
+ else
+ newsize = MIN (limit, 2 * *size);
+
+ newgroups = realloc (groups, newsize * sizeof (*groups));
+ if (newgroups == NULL)
+ goto done;
+ *groupsp = groups = newgroups;
+ *size = newsize;
+ }
+
+ groups[(*start)++] = group;
+ }
+ }
+
+ p = q;
+ }
+
+ __set_errno (save_errno);
+
+ done:
+ hesiod_free_list (context, list);
+ hesiod_end (context);
+
+ return NSS_STATUS_SUCCESS;
+}
diff --git a/REORG.TODO/hesiod/nss_hesiod/hesiod-proto.c b/REORG.TODO/hesiod/nss_hesiod/hesiod-proto.c
new file mode 100644
index 0000000000..6af32aad35
--- /dev/null
+++ b/REORG.TODO/hesiod/nss_hesiod/hesiod-proto.c
@@ -0,0 +1,142 @@
+/* Copyright (C) 1997-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <hesiod.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <nss.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Declare a parser for Hesiod protocol entries. Although the format
+ of the entries is identical to those in /etc/protocols, here is no
+ predefined parser for us to use. */
+
+#define ENTNAME protoent
+
+struct protoent_data {};
+
+#define TRAILING_LIST_MEMBER p_aliases
+#define TRAILING_LIST_SEPARATOR_P isspace
+#include <nss/nss_files/files-parse.c>
+LINE_PARSER
+("#",
+ STRING_FIELD (result->p_name, isspace, 1);
+ INT_FIELD (result->p_proto, isspace, 1, 10,);
+ )
+
+enum nss_status
+_nss_hesiod_setprotoent (int stayopen)
+{
+ return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_hesiod_endprotoent (void)
+{
+ return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status
+lookup (const char *name, const char *type, struct protoent *proto,
+ char *buffer, size_t buflen, int *errnop)
+{
+ struct parser_data *data = (void *) buffer;
+ size_t linebuflen;
+ void *context;
+ char **list, **item;
+ int parse_res;
+ int found;
+ int olderr = errno;
+
+ if (hesiod_init (&context) < 0)
+ return NSS_STATUS_UNAVAIL;
+
+ list = hesiod_resolve (context, name, type);
+ if (list == NULL)
+ {
+ int err = errno;
+ hesiod_end (context);
+ __set_errno (olderr);
+ return err == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL;
+ }
+
+ linebuflen = buffer + buflen - data->linebuffer;
+
+ item = list;
+ found = 0;
+ do
+ {
+ size_t len = strlen (*item) + 1;
+
+ if (linebuflen < len)
+ {
+ hesiod_free_list (context, list);
+ hesiod_end (context);
+ *errnop = ERANGE;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ memcpy (data->linebuffer, *item, len);
+
+ parse_res = parse_line (buffer, proto, data, buflen, errnop);
+ if (parse_res == -1)
+ {
+ hesiod_free_list (context, list);
+ hesiod_end (context);
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ if (parse_res > 0)
+ found = 1;
+
+ ++item;
+ }
+ while (*item != NULL && !found);
+
+ hesiod_free_list (context, list);
+ hesiod_end (context);
+
+ if (found == 0)
+ {
+ __set_errno (olderr);
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_hesiod_getprotobyname_r (const char *name, struct protoent *proto,
+ char *buffer, size_t buflen, int *errnop)
+{
+ return lookup (name, "protocol", proto, buffer, buflen, errnop);
+}
+
+enum nss_status
+_nss_hesiod_getprotobynumber_r (const int protocol, struct protoent *proto,
+ char *buffer, size_t buflen, int *errnop)
+{
+ char protostr[21];
+
+ snprintf (protostr, sizeof protostr, "%d", protocol);
+
+ return lookup (protostr, "protonum", proto, buffer, buflen, errnop);
+}
diff --git a/REORG.TODO/hesiod/nss_hesiod/hesiod-pwd.c b/REORG.TODO/hesiod/nss_hesiod/hesiod-pwd.c
new file mode 100644
index 0000000000..8309af245d
--- /dev/null
+++ b/REORG.TODO/hesiod/nss_hesiod/hesiod-pwd.c
@@ -0,0 +1,110 @@
+/* Copyright (C) 1997-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <hesiod.h>
+#include <pwd.h>
+#include <nss.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Get the declaration of the parser function. */
+#define ENTNAME pwent
+#define STRUCTURE passwd
+#define EXTERN_PARSER
+#include <nss/nss_files/files-parse.c>
+
+enum nss_status
+_nss_hesiod_setpwent (int stayopen)
+{
+ return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_hesiod_endpwent (void)
+{
+ return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status
+lookup (const char *name, const char *type, struct passwd *pwd,
+ char *buffer, size_t buflen, int *errnop)
+{
+ struct parser_data *data = (void *) buffer;
+ size_t linebuflen;
+ void *context;
+ char **list;
+ int parse_res;
+ size_t len;
+ int olderr = errno;
+
+ if (hesiod_init (&context) < 0)
+ return NSS_STATUS_UNAVAIL;
+
+ list = hesiod_resolve (context, name, type);
+ if (list == NULL)
+ {
+ int err = errno;
+ hesiod_end (context);
+ __set_errno (olderr);
+ return err == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL;
+ }
+
+ linebuflen = buffer + buflen - data->linebuffer;
+ len = strlen (*list) + 1;
+ if (linebuflen < len)
+ {
+ hesiod_free_list (context, list);
+ hesiod_end (context);
+ *errnop = ERANGE;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ memcpy (data->linebuffer, *list, len);
+ hesiod_free_list (context, list);
+ hesiod_end (context);
+
+ parse_res = _nss_files_parse_pwent (buffer, pwd, data, buflen, errnop);
+ if (parse_res < 1)
+ {
+ __set_errno (olderr);
+ return parse_res == -1 ? NSS_STATUS_TRYAGAIN : NSS_STATUS_NOTFOUND;
+ }
+
+ return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_hesiod_getpwnam_r (const char *name, struct passwd *pwd,
+ char *buffer, size_t buflen, int *errnop)
+{
+ return lookup (name, "passwd", pwd, buffer, buflen, errnop);
+}
+
+enum nss_status
+_nss_hesiod_getpwuid_r (uid_t uid, struct passwd *pwd,
+ char *buffer, size_t buflen, int *errnop)
+{
+ char uidstr[21]; /* We will probably never have a gid_t with more
+ than 64 bits. */
+
+ snprintf (uidstr, sizeof uidstr, "%d", uid);
+
+ return lookup (uidstr, "uid", pwd, buffer, buflen, errnop);
+}
diff --git a/REORG.TODO/hesiod/nss_hesiod/hesiod-service.c b/REORG.TODO/hesiod/nss_hesiod/hesiod-service.c
new file mode 100644
index 0000000000..1942188517
--- /dev/null
+++ b/REORG.TODO/hesiod/nss_hesiod/hesiod-service.c
@@ -0,0 +1,145 @@
+/* Copyright (C) 1997-2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <hesiod.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <nss.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Hesiod uses a format for service entries that differs from the
+ traditional format. We therefore declare our own parser. */
+
+#define ENTNAME servent
+
+struct servent_data {};
+
+#define TRAILING_LIST_MEMBER s_aliases
+#define TRAILING_LIST_SEPARATOR_P isspace
+#include <nss/nss_files/files-parse.c>
+#define ISSC_OR_SPACE(c) ((c) == ';' || isspace (c))
+LINE_PARSER
+("#",
+ STRING_FIELD (result->s_name, ISSC_OR_SPACE, 1);
+ STRING_FIELD (result->s_proto, ISSC_OR_SPACE, 1);
+ INT_FIELD (result->s_port, ISSC_OR_SPACE, 10, 0, htons);
+ )
+
+enum nss_status
+_nss_hesiod_setservent (int stayopen)
+{
+ return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_hesiod_endservent (void)
+{
+ return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status
+lookup (const char *name, const char *type, const char *protocol,
+ struct servent *serv, char *buffer, size_t buflen, int *errnop)
+{
+ struct parser_data *data = (void *) buffer;
+ size_t linebuflen;
+ void *context;
+ char **list, **item;
+ int parse_res;
+ int found;
+ int olderr = errno;
+
+ if (hesiod_init (&context) < 0)
+ return NSS_STATUS_UNAVAIL;
+
+ list = hesiod_resolve (context, name, type);
+ if (list == NULL)
+ {
+ int err = errno;
+ hesiod_end (context);
+ __set_errno (olderr);
+ return err == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL;
+ }
+
+ linebuflen = buffer + buflen - data->linebuffer;
+
+ item = list;
+ found = 0;
+ do
+ {
+ size_t len = strlen (*item) + 1;
+
+ if (linebuflen < len)
+ {
+ hesiod_free_list (context, list);
+ hesiod_end (context);
+ *errnop = ERANGE;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ memcpy (data->linebuffer, *item, len);
+
+ parse_res = parse_line (buffer, serv, data, buflen, errnop);
+ if (parse_res == -1)
+ {
+ hesiod_free_list (context, list);
+ hesiod_end (context);
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ if (parse_res > 0)
+ found = protocol == NULL || strcasecmp (serv->s_proto, protocol) == 0;
+
+ ++item;
+ }
+ while (*item != NULL && !found);
+
+ hesiod_free_list (context, list);
+ hesiod_end (context);
+
+ if (found == 0)
+ {
+ __set_errno (olderr);
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_hesiod_getservbyname_r (const char *name, const char *protocol,
+ struct servent *serv,
+ char *buffer, size_t buflen, int *errnop)
+{
+ return lookup (name, "service", protocol, serv, buffer, buflen, errnop);
+}
+
+enum nss_status
+_nss_hesiod_getservbyport_r (const int port, const char *protocol,
+ struct servent *serv,
+ char *buffer, size_t buflen, int *errnop)
+{
+ char portstr[6]; /* Port numbers are restricted to 16 bits. */
+
+ snprintf (portstr, sizeof portstr, "%d", ntohs (port));
+
+ return lookup (portstr, "port", protocol, serv, buffer, buflen, errnop);
+}