summary refs log tree commit diff
path: root/hesiod
diff options
context:
space:
mode:
Diffstat (limited to 'hesiod')
-rw-r--r--hesiod/Makefile49
-rw-r--r--hesiod/hesiod.c470
-rw-r--r--hesiod/hesiod.h73
-rw-r--r--hesiod/hesiod_p.h41
-rw-r--r--hesiod/libnss_hesiod.map12
-rw-r--r--hesiod/nss_hesiod/hesiod-grp.c150
-rw-r--r--hesiod/nss_hesiod/hesiod-pwd.c150
-rw-r--r--hesiod/nss_hesiod/hesiod-service.c165
8 files changed, 1110 insertions, 0 deletions
diff --git a/hesiod/Makefile b/hesiod/Makefile
new file mode 100644
index 0000000000..8d0363b50d
--- /dev/null
+++ b/hesiod/Makefile
@@ -0,0 +1,49 @@
+# Copyright (C) 1997 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 Library General Public License as
+# published by the Free Software Foundation; either version 2 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
+# Library General Public License for more details.
+
+# You should have received a copy of the GNU Library General Public
+# License along with the GNU C Library; see the file COPYING.LIB.  If not,
+# write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+#
+#	Sub-makefile for hesiod portion of the library.
+#
+subdir	:= hesiod
+
+distribute := hesiod.h hesiod_p.h
+
+extra-libs := libnss_hesiod
+extra-libs-others = $(extra-libs)
+
+subdir-dirs = nss_hesiod
+vpath %.c nss_hesiod
+
+libnss_hesiod-routines	:= hesiod hesiod-grp hesiod-pwd hesiod-service
+libnss_hesiod-map	:= libnss_hesiod.map
+ifneq ($(build-static-nss),yes)
+libnss_hesiod-inhibit-o	= $(filter-out .os,$(object-suffixes))
+endif
+
+include ../Rules
+
+CFLAGS-hesiod.c = -DSYSCONFDIR='"$(sysconfdir)"'
+
+# Depend on libc.so so a DT_NEEDED is generated in the shared objects.
+# This ensures they will load libc.so for needed symbols if loaded by
+# a statically-linked program that hasn't already loaded it.
+# The Hesiod NSS modules 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 \
+                           $(common-objpfx)libc.so
diff --git a/hesiod/hesiod.c b/hesiod/hesiod.c
new file mode 100644
index 0000000000..8e95dfb393
--- /dev/null
+++ b/hesiod/hesiod.c
@@ -0,0 +1,470 @@
+/* Copyright (c) 1996 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.
+ */
+
+/* Copyright 1996 by the Massachusetts Institute of Technology.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ */
+
+/* This file is part of the hesiod library.  It implements the core
+ * portion of the hesiod resolver.
+ *
+ * This file is loosely based on an interim version of hesiod.c from
+ * the BIND IRS library, which was in turn based on an earlier version
+ * of this file.  Extensive changes have been made on each step of the
+ * path.
+ *
+ * This implementation is not truly thread-safe at the moment because
+ * it uses res_send() and accesses _res.
+ */
+
+static const char rcsid[] = "$Id$";
+
+#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 <ctype.h>
+#include "hesiod.h"
+#include "hesiod_p.h"
+
+/* A few operating systems don't define these. */
+#ifndef C_HS
+#define C_HS	4
+#endif
+#ifndef T_TXT
+#define T_TXT	16
+#endif
+
+static int read_config_file(struct hesiod_p *ctx, const char *filename);
+static char **get_txt_records(struct hesiod_p *ctx, int class,
+			      const char *name);
+static int cistrcmp(const char *s1, const char *s2);
+
+/* This function is called to initialize a hesiod_p. */
+int hesiod_init(void **context)
+{
+  struct hesiod_p *ctx;
+  const char *p, *configname;
+
+  ctx = malloc(sizeof(struct hesiod_p));
+  if (ctx)
+    {
+      *context = ctx;
+      configname = __secure_getenv("HESIOD_CONFIG");
+      if (!configname)
+	configname = SYSCONFDIR "/hesiod.conf";
+      if (read_config_file(ctx, configname) >= 0)
+	{
+	  /* The default rhs can be overridden by an environment variable. */
+	  p = __secure_getenv("HES_DOMAIN");
+	  if (p)
+	    {
+	      if (ctx->rhs)
+		free(ctx->rhs);
+	      ctx->rhs = malloc(strlen(p) + 2);
+	      if (ctx->rhs)
+		{
+		  *ctx->rhs = '.';
+		  strcpy(ctx->rhs + 1, (*p == '.') ? p + 1 : p);
+		  return 0;
+		}
+	      else
+		__set_errno (ENOMEM);
+	    }
+	  else
+	    return 0;
+	}
+    }
+  else
+    __set_errno (ENOMEM);
+
+  if (ctx->lhs)
+    free(ctx->lhs);
+  if (ctx->rhs)
+    free(ctx->rhs);
+  if (ctx)
+    free(ctx);
+  return -1;
+}
+
+/* This function deallocates the hesiod_p. */
+void hesiod_end(void *context)
+{
+  struct hesiod_p *ctx = (struct hesiod_p *) context;
+
+  free(ctx->rhs);
+  if (ctx->lhs)
+    free(ctx->lhs);
+  free(ctx);
+}
+
+/* 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[MAXDNAME], *p, *ret, **rhs_list = NULL;
+  const char *rhs;
+  int len;
+	
+  strcpy(bindname, name);
+
+  /* Find the right right hand side to use, possibly truncating bindname. */
+  p = strchr(bindname, '@');
+  if (p)
+    {
+      *p++ = 0;
+      if (strchr(p, '.'))
+	rhs = name + (p - bindname);
+      else
+	{
+	  rhs_list = hesiod_resolve(context, p, "rhs-extension");
+	  if (rhs_list)
+	    rhs = *rhs_list;
+	  else
+	    {
+	      __set_errno (ENOENT);
+	      return NULL;
+	    }
+	}
+    } else
+      rhs = ctx->rhs;
+
+  /* See if we have enough room. */
+  len = strlen(bindname) + 1 + strlen(type);
+  if (ctx->lhs)
+    len += strlen(ctx->lhs) + ((ctx->lhs[0] != '.') ? 1 : 0);
+  len += strlen(rhs) + ((rhs[0] != '.') ? 1 : 0);
+  if (len > sizeof(bindname) - 1)
+    {
+      if (rhs_list)
+	hesiod_free_list(context, rhs_list);
+      __set_errno (EMSGSIZE);
+      return NULL;
+    }
+
+  /* Put together the rest of the domain. */
+  strcat(bindname, ".");
+  strcat(bindname, type);
+  if (ctx->lhs)
+    {
+      if (ctx->lhs[0] != '.')
+	strcat(bindname, ".");
+      strcat(bindname, ctx->lhs);
+    }
+  if (rhs[0] != '.')
+    strcat(bindname, ".");
+  strcat(bindname, rhs);
+
+  /* rhs_list is no longer needed, since we're done with rhs. */
+  if (rhs_list)
+    hesiod_free_list(context, rhs_list);
+
+  /* Make a copy of the result and return it to the caller. */
+  ret = malloc(strlen(bindname) + 1);
+  if (!ret)
+    {
+      __set_errno (ENOMEM);
+      return NULL;
+    }
+  strcpy(ret, bindname);
+  return ret;
+}
+
+/* This is the core function.  Given a hesiod name and 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, **retvec;
+
+  bindname = hesiod_to_bind(context, name, type);
+  if (!bindname)
+    return NULL;
+
+  retvec = get_txt_records(ctx, ctx->classes[0], bindname);
+  if (retvec == NULL && errno == ENOENT && 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.  Returns 0 on success,
+ * -1 on failure.  On failure, it might leave values in ctx->lhs or
+ * ctx->rhs which need to be freed by the caller. */
+static int read_config_file(struct hesiod_p *ctx, const char *filename)
+{
+  char *key, *data, *p, **which;
+  char buf[MAXDNAME + 7];
+  int n;
+  FILE *fp;
+
+  /* Set default query classes. */
+  ctx->classes[0] = C_IN;
+  ctx->classes[1] = C_HS;
+
+  /* Try to open the configuration file. */
+  fp = fopen(filename, "r");
+  if (!fp)
+    {
+      /* Use compiled in default domain names. */
+      ctx->lhs = malloc(strlen(DEF_LHS) + 1);
+      ctx->rhs = malloc(strlen(DEF_RHS) + 1);
+      if (ctx->lhs && ctx->rhs)
+	{
+	  strcpy(ctx->lhs, DEF_LHS);
+	  strcpy(ctx->rhs, DEF_RHS);
+	  return 0;
+	}
+      else
+	{
+	  __set_errno (ENOMEM);
+	  return -1;
+	}
+    }
+
+  ctx->lhs = NULL;
+  ctx->rhs = NULL;
+  while (fgets(buf, sizeof(buf), fp) != NULL)
+    {
+      p = buf;
+      if (*p == '#' || *p == '\n' || *p == '\r')
+	continue;
+      while(*p == ' ' || *p == '\t')
+	p++;
+      key = p;
+      while(*p != ' ' && *p != '\t' && *p != '=')
+	p++;
+      *p++ = 0;
+		
+      while(isspace(*p) || *p == '=')
+	p++;
+      data = p;
+      while(!isspace(*p))
+	p++;
+      *p = 0;
+
+      if (cistrcmp(key, "lhs") == 0 || cistrcmp(key, "rhs") == 0)
+	{
+	  which = (strcmp(key, "lhs") == 0) ? &ctx->lhs : &ctx->rhs;
+	  *which = malloc(strlen(data) + 1);
+	  if (!*which)
+	    {
+	      __set_errno (ENOMEM);
+	      return -1;
+	    }
+	  strcpy(*which, data);
+	}
+      else if (cistrcmp(key, "classes") == 0)
+	{
+	  n = 0;
+	  while (*data && n < 2)
+	    {
+	      p = data;
+	      while (*p && *p != ',')
+		p++;
+	      if (*p)
+		*p++ = 0;
+	      if (cistrcmp(data, "IN") == 0)
+		ctx->classes[n++] = C_IN;
+	      else if (cistrcmp(data, "HS") == 0)
+		ctx->classes[n++] = C_HS;
+	      data = p;
+	    }
+	  while (n < 2)
+	    ctx->classes[n++] = 0;
+	}
+    }
+  fclose(fp);
+
+  if (!ctx->rhs || ctx->classes[0] == 0 || ctx->classes[0] == ctx->classes[1])
+    {
+      __set_errno (ENOEXEC);
+      return -1;
+    }
+
+  return 0;
+}	
+
+/* 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 qclass,
+			      const char *name)
+{
+  HEADER *hp;
+  unsigned char qbuf[PACKETSZ], abuf[MAX_HESRESP], *p, *eom, *eor;
+  char *dst, **list;
+  int ancount, qdcount, i, j, n, skip, type, class, len;
+
+  /* Make sure the resolver is initialized. */
+  if ((_res.options & RES_INIT) == 0 && res_init() == -1)
+    return NULL;
+
+  /* Construct the query. */
+  n = res_mkquery(QUERY, name, qclass, T_TXT, NULL, 0,
+		  NULL, qbuf, PACKETSZ);
+  if (n < 0)
+      return NULL;
+
+  /* Send the query. */
+  n = res_send(qbuf, n, abuf, MAX_HESRESP);
+  if (n < 0)
+    {
+      __set_errno (ECONNREFUSED);
+      return NULL;
+    }
+
+  /* Parse the header of the result. */
+  hp = (HEADER *) abuf;
+  ancount = ntohs(hp->ancount);
+  qdcount = ntohs(hp->qdcount);
+  p = abuf + sizeof(HEADER);
+  eom = abuf + n;
+
+  /* Skip questions, trying to get to the answer section which follows. */
+  for (i = 0; i < qdcount; i++)
+    {
+      skip = dn_skipname(p, eom);
+      if (skip < 0 || p + skip + QFIXEDSZ > eom)
+	{
+	  __set_errno (EMSGSIZE);
+	  return NULL;
+	}
+      p += skip + QFIXEDSZ;
+    }
+
+  /* Allocate space for the text record answers. */
+  list = malloc((ancount + 1) * sizeof(char *));
+  if (!list)
+    {
+      __set_errno (ENOMEM);
+      return NULL;
+    }
+
+  /* Parse the answers. */
+  j = 0;
+  for (i = 0; i < ancount; i++)
+    {
+      /* Parse the header of this answer. */
+      skip = dn_skipname(p, eom);
+      if (skip < 0 || p + skip + 10 > eom)
+	break;
+      type = p[skip + 0] << 8 | p[skip + 1];
+      class = p[skip + 2] << 8 | p[skip + 3];
+      len = p[skip + 8] << 8 | p[skip + 9];
+      p += skip + 10;
+      if (p + len > eom)
+	{
+	  __set_errno (EMSGSIZE);
+	  break;
+	}
+
+      /* Skip entries of the wrong class and type. */
+      if (class != qclass || type != T_TXT)
+	{
+	  p += len;
+	  continue;
+	}
+
+      /* Allocate space for this answer. */
+      list[j] = malloc(len);
+      if (!list[j])
+	{
+	  __set_errno (ENOMEM);
+	  break;
+	}
+      dst = list[j++];
+
+      /* Copy answer data into the allocated area. */
+      eor = p + len;
+      while (p < eor)
+	{
+	  n = (unsigned char) *p++;
+	  if (p + n > eor)
+	    {
+	      __set_errno (EMSGSIZE);
+	      break;
+	    }
+	  memcpy(dst, p, n);
+	  p += n;
+	  dst += n;
+	}
+      if (p < eor)
+	{
+	  __set_errno (EMSGSIZE);
+	  break;
+	}
+      *dst = 0;
+    }
+
+  /* If we didn't terminate the loop normally, something went wrong. */
+  if (i < ancount)
+    {
+      for (i = 0; i < j; i++)
+	free(list[i]);
+      free(list);
+      return NULL;
+    }
+
+  if (j == 0)
+    {
+      __set_errno (ENOENT);
+      free(list);
+      return NULL;
+    }
+
+  list[j] = NULL;
+  return list;
+}
+
+static int cistrcmp(const char *s1, const char *s2)
+{
+  while (*s1 && tolower(*s1) == tolower(*s2))
+    {
+      s1++;
+      s2++;
+    }
+  return tolower(*s1) - tolower(*s2);
+}
diff --git a/hesiod/hesiod.h b/hesiod/hesiod.h
new file mode 100644
index 0000000000..9c3d323811
--- /dev/null
+++ b/hesiod/hesiod.h
@@ -0,0 +1,73 @@
+/* $Id$ */
+
+/*
+ * Copyright (c) 1996 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.
+ */
+
+#ifndef HESIOD__INCLUDED
+#define HESIOD__INCLUDED
+
+#include <sys/types.h>
+#include <pwd.h>
+#include <netdb.h>
+
+/* Application-visible define to signal that we have the new interfaces. */
+#define HESIOD_INTERFACES
+
+struct hesiod_postoffice {
+  char *hesiod_po_type;
+  char *hesiod_po_host;
+  char *hesiod_po_name;
+};
+
+int hesiod_init(void **context);
+void hesiod_end(void *context);
+char *hesiod_to_bind(void *context, const char *name, const char *type);
+char **hesiod_resolve(void *context, const char *name, const char *type);
+void hesiod_free_list(void *context, char **list);
+struct passwd *hesiod_getpwnam(void *context, const char *name);
+struct passwd *hesiod_getpwuid(void *context, uid_t uid);
+void hesiod_free_passwd(void *context, struct passwd *pw);
+struct servent *hesiod_getservbyname(void *context, const char *name,
+				     const char *proto);
+void hesiod_free_servent(void *context, struct servent *serv);
+struct hesiod_postoffice *hesiod_getmailhost(void *context, const char *user);
+void hesiod_free_postoffice(void *context, struct hesiod_postoffice *po);
+
+/* Compatibility stuff. */
+
+#define HES_ER_UNINIT	-1	/* uninitialized */
+#define HES_ER_OK	0	/* no error */
+#define HES_ER_NOTFOUND	1	/* Hesiod name not found by server */
+#define HES_ER_CONFIG	2	/* local problem (no config file?) */
+#define HES_ER_NET	3	/* network problem */
+
+struct hes_postoffice {
+  char *po_type;
+  char *po_host;
+  char *po_name;
+};
+
+int hes_init(void);
+char *hes_to_bind(const char *name, const char *type);
+char **hes_resolve(const char *name, const char *type);
+int hes_error(void);
+struct passwd *hes_getpwnam(const char *name);
+struct passwd *hes_getpwuid(uid_t uid);
+struct servent *hes_getservbyname(const char *name, const char *proto);
+struct hes_postoffice *hes_getmailhost(const char *name);
+
+#endif
diff --git a/hesiod/hesiod_p.h b/hesiod/hesiod_p.h
new file mode 100644
index 0000000000..809916ac2b
--- /dev/null
+++ b/hesiod/hesiod_p.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 1996 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.
+ */
+
+/*
+ * $Id$
+ */
+
+/*
+ * hesiod_p.h -- private definitions for the hesiod library
+ */
+
+#ifndef HESIOD_P_H_INCLUDED
+#define HESIOD_P_H_INCLUDED
+
+/* Defaults if the configuration file is not present. */
+#define DEF_RHS ".athena.mit.edu"
+#define DEF_LHS ".ns"
+
+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/hesiod/libnss_hesiod.map b/hesiod/libnss_hesiod.map
new file mode 100644
index 0000000000..6c1fd5eba9
--- /dev/null
+++ b/hesiod/libnss_hesiod.map
@@ -0,0 +1,12 @@
+GLIBC_2.0 {
+  global:
+    _nss_hesiod_setpwent; _nss_hesiod_endpwent;
+    _nss_hesiod_getpwnam_r; _nss_hesiod_getpwuid;
+    _nss_hesiod_setgrent; _nss_hesiod_endgrent;
+    _nss_hesiod_getgrnam_r; _nss_hesiod_getgrgid;
+    _nss_hesiod_setservent; _nss_hesiod_endservent;
+    _nss_hesiod_getservbyname_r;
+
+  local:
+    *;
+};
diff --git a/hesiod/nss_hesiod/hesiod-grp.c b/hesiod/nss_hesiod/hesiod-grp.c
new file mode 100644
index 0000000000..7b0832dbe3
--- /dev/null
+++ b/hesiod/nss_hesiod/hesiod-grp.c
@@ -0,0 +1,150 @@
+/* Copyright (C) 1997 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 Library General Public License as
+   published by the Free Software Foundation; either version 2 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <bits/libc-lock.h>
+#include <errno.h>
+#include <hesiod.h>
+#include <nss.h>
+#include <grp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Get the declaration of the parser function.  */
+#define ENTNAME grent
+#define STRUCTURE group
+#define EXTERN_PARSER
+#include <nss/nss_files/files-parse.c>
+
+/* Locks the static variables in this file.  */
+__libc_lock_define_initialized (static, lock);
+
+static void *context = NULL;
+
+static enum nss_status
+internal_setgrent (void)
+{
+  if (!context)
+    {
+      if (hesiod_init (&context) == -1)
+	return NSS_STATUS_UNAVAIL;
+    }
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_hesiod_setgrent (void)
+{
+  enum nss_status status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_setgrent ();
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+enum nss_status
+_nss_hesiod_endgrent (void)
+{
+  __libc_lock_lock (lock);
+
+  if (context)
+    {
+      hesiod_end (context);
+      context = NULL;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status
+lookup (const char *name, const char *type, struct group *grp,
+	char *buffer, size_t buflen)
+{
+  enum nss_status status;
+  struct parser_data *data = (void *) buffer;
+  size_t linebuflen;
+  char **list;
+  int parse_res;
+
+  status = internal_setgrent ();
+  if (status != NSS_STATUS_SUCCESS)
+    return status;
+
+  list = hesiod_resolve (context, name, type);
+  if (list == NULL)
+    return errno == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL;
+
+  linebuflen = buffer + buflen - data->linebuffer;
+  if (linebuflen < strlen (*list) + 1)
+    {
+      hesiod_free_list (context, list);
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  strcpy (buffer, *list);
+  hesiod_free_list (context, list);
+
+  parse_res = _nss_files_parse_grent (buffer, grp, data, buflen);
+  if (parse_res < 1)
+    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)
+{
+  enum nss_status status;
+
+  __libc_lock_lock (lock);
+
+  status = lookup (name, "group", grp, buffer, buflen);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+enum nss_status
+_nss_hesiod_getgrgid_r (gid_t gid, struct group *grp,
+			char *buffer, size_t buflen)
+{
+  enum nss_status status = NSS_STATUS_UNAVAIL;
+  char gidstr[21];	/* We will probably never have a gid_t with more
+			   than 64 bits.  */
+
+  snprintf (gidstr, sizeof gidstr, "%d", gid);
+
+  __libc_lock_lock (lock);
+
+  status = lookup (gidstr, "gid", grp, buffer, buflen);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
diff --git a/hesiod/nss_hesiod/hesiod-pwd.c b/hesiod/nss_hesiod/hesiod-pwd.c
new file mode 100644
index 0000000000..bb2a4c8785
--- /dev/null
+++ b/hesiod/nss_hesiod/hesiod-pwd.c
@@ -0,0 +1,150 @@
+/* Copyright (C) 1997 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 Library General Public License as
+   published by the Free Software Foundation; either version 2 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <bits/libc-lock.h>
+#include <errno.h>
+#include <hesiod.h>
+#include <nss.h>
+#include <pwd.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>
+
+/* Locks the static variables in this file.  */
+__libc_lock_define_initialized (static, lock);
+
+static void *context = NULL;
+
+static enum nss_status
+internal_setpwent (void)
+{
+  if (!context)
+    {
+      if (hesiod_init (&context) == -1)
+	return NSS_STATUS_UNAVAIL;
+    }
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_hesiod_setpwent (void)
+{
+  enum nss_status status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_setpwent ();
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+enum nss_status
+_nss_hesiod_endpwent (void)
+{
+  __libc_lock_lock (lock);
+
+  if (context)
+    {
+      hesiod_end (context);
+      context = NULL;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status
+lookup (const char *name, const char *type, struct passwd *pwd,
+	char *buffer, size_t buflen)
+{
+  enum nss_status status;
+  struct parser_data *data = (void *) buffer;
+  size_t linebuflen;
+  char **list;
+  int parse_res;
+
+  status = internal_setpwent ();
+  if (status != NSS_STATUS_SUCCESS)
+    return status;
+
+  list = hesiod_resolve (context, name, type);
+  if (list == NULL)
+    return errno == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL;
+
+  linebuflen = buffer + buflen - data->linebuffer;
+  if (linebuflen < strlen (*list) + 1)
+    {
+      hesiod_free_list (context, list);
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  strcpy (data->linebuffer, *list);
+  hesiod_free_list (context, list);
+
+  parse_res = _nss_files_parse_pwent (buffer, pwd, data, buflen);
+  if (parse_res < 1)
+    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)
+{
+  enum nss_status status;
+
+  __libc_lock_lock (lock);
+
+  status = lookup (name, "passwd", pwd, buffer, buflen);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+enum nss_status
+_nss_hesiod_getpwuid_r (uid_t uid, struct passwd *pwd,
+			char *buffer, size_t buflen)
+{
+  enum nss_status status = NSS_STATUS_UNAVAIL;
+  char uidstr[21];	/* We will probably never have a gid_t with more
+			   than 64 bits.  */
+
+  snprintf (uidstr, sizeof uidstr, "%d", uid);
+
+  __libc_lock_lock (lock);
+
+  status = lookup (uidstr, "uid", pwd, buffer, buflen);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
diff --git a/hesiod/nss_hesiod/hesiod-service.c b/hesiod/nss_hesiod/hesiod-service.c
new file mode 100644
index 0000000000..f74877f748
--- /dev/null
+++ b/hesiod/nss_hesiod/hesiod-service.c
@@ -0,0 +1,165 @@
+/* Copyright (C) 1997 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 Library General Public License as
+   published by the Free Software Foundation; either version 2 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <bits/libc-lock.h>
+#include <errno.h>
+#include <hesiod.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <nss.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
+
+#define ENTDATA servent_data
+struct servent_data {};
+
+#define TRAILING_LIST_MEMBER		s_aliases
+#define TRAILING_LIST_SEPARATOR_P	isspace
+#include <nss/nss_files/files-parse.c>
+#define ISSEMICOLON(c)	((c) ==  ';')
+LINE_PARSER
+("",
+ (void) entdata;
+ STRING_FIELD (result->s_name, ISSEMICOLON, 1);
+ STRING_FIELD (result->s_proto, ISSEMICOLON, 1);
+ INT_FIELD (result->s_port, ISSEMICOLON, 10, 0, htons);
+ )
+
+
+/* Locks the static variables in this file.  */
+__libc_lock_define_initialized (static, lock);
+
+static void *context = NULL;
+
+static enum nss_status
+internal_setservent (void)
+{
+  if (!context)
+    {
+      if (hesiod_init (&context) == -1)
+	return NSS_STATUS_UNAVAIL;
+    }
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_hesiod_setservent (void)
+{
+  enum nss_status status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_setservent ();
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+enum nss_status
+_nss_hesiod_endservent (void)
+{
+  __libc_lock_lock (lock);
+
+  if (context)
+    {
+      hesiod_end (context);
+      context = NULL;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status
+lookup (const char *name, const char *protocol, struct servent *serv,
+	char *buffer, size_t buflen)
+{
+  enum nss_status status;
+  struct parser_data *data = (void *) buffer;
+  size_t linebuflen;
+  char **list, **item;
+  int parse_res;
+  int found;
+
+  status = internal_setservent ();
+  if (status != NSS_STATUS_SUCCESS)
+    return status;
+
+  list = hesiod_resolve (context, name, "service");
+  if (list == NULL)
+    return errno == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL;
+
+  linebuflen = buffer + buflen - data->linebuffer;
+
+  item = list;
+  found = 0;
+  do
+    {
+      if (linebuflen < strlen (*item) + 1)
+	{
+	  hesiod_free_list (context, list);
+	  __set_errno (ERANGE);
+	  return NSS_STATUS_TRYAGAIN;
+	}
+
+      strcpy (data->linebuffer, *item);
+
+      parse_res = parse_line (buffer, serv, data, buflen);
+      if (parse_res == -1)
+	{
+	  hesiod_free_list (context, list);
+	  return NSS_STATUS_TRYAGAIN;
+	}
+
+      if (parse_res > 0)
+	found = protocol == NULL || strcmp (serv->s_proto, protocol) == 0;
+
+      ++item;
+    }
+  while (*item != NULL && !found);
+
+  hesiod_free_list (context, list);
+
+  return found ? NSS_STATUS_SUCCESS : NSS_STATUS_NOTFOUND;
+}
+
+enum nss_status
+_nss_hesiod_getservbyname_r (const char *name, const char *protocol,
+			     struct servent *serv,
+			     char *buffer, size_t buflen)
+{
+  enum nss_status status;
+
+  __libc_lock_lock (lock);
+
+  status = lookup (name, protocol, serv, buffer, buflen);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}