Sun Jun 23 19:42:05 1996 Ulrich Drepper <drepper@cygnus.com>
authorroland <roland>
Tue, 25 Jun 1996 06:50:12 +0000 (06:50 +0000)
committerroland <roland>
Tue, 25 Jun 1996 06:50:12 +0000 (06:50 +0000)
* nss/Makefile, nss/XXX-lookup.c, nss/file-lookup.c,
nss/getXXbyYY.c, nss/getXXbyYY_r.c, nss/getXXent.c,
nss/getXXent_r.c, nss/host-lookup.c, nss/network-lookup.c,
nss/nsswitch.c, nss/nsswitch.h, nss/proto-lookup.c,
nss/service-lookup.c: New files.  Implementation of name
service switch, following the approach in Solaris.
Interface specification and general structure inspired by Peter
Eriksson <pen@lysator.liu.se>.
* nss/nss_files/files-host.c, nss/nss_files/files-network.c,
nss/nss_files/files-proto.c, nss/nss_files/files-service.c:
Implementation of libnss_files.so module for file based databases
in NSS service.
* nss/nss_dns/dns-host.c, nss/nss_dns/dns-network.c: Implementation
        if libnss_dns.so module for DNS name lookup in NSS service.

12 files changed:
nss/XXX-lookup.c [new file with mode: 0644]
nss/file-lookup.c [new file with mode: 0644]
nss/getXXbyYY.c [new file with mode: 0644]
nss/getXXbyYY_r.c [new file with mode: 0644]
nss/getXXent.c [new file with mode: 0644]
nss/host-lookup.c [new file with mode: 0644]
nss/network-lookup.c [new file with mode: 0644]
nss/nss_dns/dns-host.c [new file with mode: 0644]
nss/nsswitch.c [new file with mode: 0644]
nss/nsswitch.h [new file with mode: 0644]
nss/proto-lookup.c [new file with mode: 0644]
nss/service-lookup.c [new file with mode: 0644]

diff --git a/nss/XXX-lookup.c b/nss/XXX-lookup.c
new file mode 100644 (file)
index 0000000..1f8cbbf
--- /dev/null
@@ -0,0 +1,51 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+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 "nsswitch.h"
+
+/*******************************************************************\
+|* Here we assume one symbol to be defined:                       *|
+|*                                                                *|
+|* DATABASE_NAME - name of the database the function accesses     *|
+|*                (e.g., hosts, servicess, ...)                   *|
+|*                                                                *|
+\*******************************************************************/
+
+#define DB_LOOKUP_FCT CONCAT3_1 (__nss_, DATABASE_NAME, _lookup)
+#define CONCAT3_1(Pre, Name, Post) CONCAT3_2 (Pre, Name, Post)
+#define CONCAT3_2(Pre, Name, Post) Pre##Name##Post
+
+#define DATABASE_NAME_STRING STRINGIFY1 (DATABASE_NAME)
+#define STRINGIFY1(Name) STRINGIFY2 (Name)
+#define STRINGIFY2(Name) #Name
+
+
+static service_user *database = NULL;
+
+int
+DB_LOOKUP_FCT (service_user **ni, const char *fct_name, void **fctp)
+{
+  if (database == NULL
+      && __nss_database_lookup (DATABASE_NAME_STRING, &database) < 0)
+    return -1;
+
+  *ni = database;
+
+  return __nss_lookup (ni, fct_name, fctp);
+}
diff --git a/nss/file-lookup.c b/nss/file-lookup.c
new file mode 100644 (file)
index 0000000..d9f7c67
--- /dev/null
@@ -0,0 +1,22 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+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.  */
+
+#define DATABASE_NAME hosts
+
+#include "XXX-lookup.c"
diff --git a/nss/getXXbyYY.c b/nss/getXXbyYY.c
new file mode 100644 (file)
index 0000000..5eb9ee9
--- /dev/null
@@ -0,0 +1,71 @@
+/* Copyright (C) 1996 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.  */
+
+#include "../nss/nsswitch.h"
+
+/*******************************************************************\
+|* Here we assume several symbols to be defined:                  *|
+|*                                                                *|
+|* LOOKUP_TYPE   - the return type of the function                *|
+|*                                                                *|
+|* FUNCTION_NAME - name of the non-reentrant function             *|
+|*                                                                *|
+|* DATABASE_NAME - name of the database the function accesses     *|
+|*                (e.g., host, services, ...)                     *|
+|*                                                                *|
+|* ADD_PARAMS    - additional parameter, can vary in number       *|
+|*                                                                *|
+|* ADD_VARIABLES - names of additional parameter                  *|
+|*                                                                *|
+|* BUFLEN       - length of buffer allocated for the non          *|
+|*                reentrant version                               *|
+|*                                                                *|
+|* Optionally the following vars can be defined:                  *|
+|*                                                                *|
+|* NEED_H_ERRNO  - an extra parameter will be passed to point to   *|
+|*                the global `h_errno' variable.                  *|
+|*                                                                *|
+\*******************************************************************/
+
+/* To make the real sources a bit prettier.  */
+#define REENTRANT_NAME APPEND_R (FUNCTION_NAME)
+#define APPEND_R(name) APPEND_R1 (name)
+#define APPEND_R1(name) name##_r
+
+/* Sometimes we need to store error codes in the `h_errno' variable.  */
+#ifdef NEED_H_ERRNO
+# define H_ERRNO_PARM , int *h_errnop
+# define H_ERRNO_VAR , &h_errno
+#else
+# define H_ERRNO_PARM
+# define H_ERRNO_VAR
+#endif
+
+
+/* Prototype for reentrant version we use here.  */
+extern LOOKUP_TYPE *REENTRANT_NAME (ADD_PARAMS, LOOKUP_TYPE *result,
+                                   char *buffer, int buflen H_ERRNO_PARM);
+
+LOOKUP_TYPE *
+FUNCTION_NAME (ADD_PARAMS)
+{
+  static LOOKUP_TYPE result;
+  static char buffer[BUFLEN];
+
+  return REENTRANT_NAME (ADD_VARIABLES, &result, buffer, BUFLEN H_ERRNO_VAR);
+}
diff --git a/nss/getXXbyYY_r.c b/nss/getXXbyYY_r.c
new file mode 100644 (file)
index 0000000..4209236
--- /dev/null
@@ -0,0 +1,129 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+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 "nsswitch.h"
+
+/*******************************************************************\
+|* Here we assume several symbols to be defined:                  *|
+|*                                                                *|
+|* LOOKUP_TYPE   - the return type of the function                *|
+|*                                                                *|
+|* FUNCTION_NAME - name of the non-reentrant function             *|
+|*                                                                *|
+|* DATABASE_NAME - name of the database the function accesses     *|
+|*                (e.g., host, services, ...)                     *|
+|*                                                                *|
+|* ADD_PARAMS    - additional parameter, can vary in number       *|
+|*                                                                *|
+|* ADD_VARIABLES - names of additional parameter                  *|
+|*                                                                *|
+|* Optionally the following vars can be defined:                  *|
+|*                                                                *|
+|* NEED_H_ERRNO  - an extra parameter will be passed to point to   *|
+|*                the global `h_errno' variable.                  *|
+|*                                                                *|
+|* NEED__RES     - the global _res variable might be used so we           *|
+|*                will have to initialize it if necessary         *|
+|*                                                                *|
+\*******************************************************************/
+
+/* To make the real sources a bit prettier.  */
+#define REENTRANT_NAME APPEND_R (FUNCTION_NAME)
+#define APPEND_R(name) APPEND_R1 (name)
+#define APPEND_R1(name) name##_r
+
+#define FUNCTION_NAME_STRING STRINGIZE (FUNCTION_NAME)
+#define REENTRANT_NAME_STRING STRINGIZE (REENTRANT_NAME)
+#define DATABASE_NAME_STRING STRINGIZE (DATABASE_NAME)
+#define STRINGIZE(name) STRINGIZE1 (name)
+#define STRINGIZE1(name) #name
+
+#define DB_LOOKUP_FCT CONCAT3_1 (__nss_, DATABASE_NAME, _lookup)
+#define CONCAT3_1(Pre, Name, Post) CONCAT3_2 (Pre, Name, Post)
+#define CONCAT3_2(Pre, Name, Post) Pre##Name##Post
+
+/* Sometimes we need to store error codes in the `h_errno' variable.  */
+#ifdef NEED_H_ERRNO
+# define H_ERRNO_PARM , int *h_errnop
+# define H_ERRNO_VAR , h_errnop
+#else
+# define H_ERRNO_PARM
+# define H_ERRNO_VAR
+#endif
+
+
+/* Type of the lookup function we need here.  */
+typedef int (*lookup_function) (ADD_PARAMS, LOOKUP_TYPE *, char *, int
+                               H_ERRNO_PARM);
+
+/* Some usages of this file might use this variable.  */
+extern struct __res_state _res;
+
+/* The lookup function for the first entry of this service.  */
+extern int DB_LOOKUP_FCT (service_user **nip, const char *name, void **fctp);
+
+
+
+LOOKUP_TYPE *
+REENTRANT_NAME (ADD_PARAMS, LOOKUP_TYPE *result, char *buffer, int buflen
+               H_ERRNO_PARM)
+{
+  static service_user *startp = NULL;
+  static lookup_function start_fct;
+  service_user *nip;
+  lookup_function fct;
+  int no_more;
+  enum nss_status status = NSS_STATUS_UNAVAIL;
+
+  if (startp == NULL)
+    {
+      no_more = DB_LOOKUP_FCT (&nip, REENTRANT_NAME_STRING, (void **) &fct);
+      if (no_more)
+       startp = (service_user *) -1;
+      else
+       {
+         startp = nip;
+         start_fct = fct;
+
+#ifdef NEED__RES
+         /* The resolver code will really be used so we have to
+            initialize it.  */
+         if ((_res.options & RES_INIT) == 0 && res_init () == -1)
+           {
+             h_errno = NETDB_INTERNAL;
+             return NULL;
+           }
+#endif /* need _res */
+       }
+    }
+  else
+    {
+      fct = start_fct;
+      no_more = (nip = startp) == (service_user *) -1;
+    }
+
+  while (no_more == 0)
+    {
+      status = (*fct) (ADD_VARIABLES, result, buffer, buflen H_ERRNO_VAR);
+
+      no_more = __nss_next (&nip, REENTRANT_NAME_STRING, &fct, status, 0);
+    }
+
+  return status == NSS_STATUS_SUCCESS ? result : NULL;
+}
diff --git a/nss/getXXent.c b/nss/getXXent.c
new file mode 100644 (file)
index 0000000..da3712c
--- /dev/null
@@ -0,0 +1,63 @@
+/* Copyright (C) 1996 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.  */
+
+#include "nsswitch.h"
+
+/*******************************************************************\
+|* Here we assume several symbols to be defined:                  *|
+|*                                                                *|
+|* LOOKUP_TYPE   - the return type of the function                *|
+|*                                                                *|
+|* GETFUNC_NAME  - name of the non-reentrant getXXXent function           *|
+|*                                                                *|
+|* BUFLEN       - size of static buffer                           *|
+|*                                                                *|
+|* Optionally the following vars can be defined:                  *|
+|*                                                                *|
+|* NEED_H_ERRNO  - an extra parameter will be passed to point to   *|
+|*                the global `h_errno' variable.                  *|
+|*                                                                *|
+\*******************************************************************/
+
+/* To make the real sources a bit prettier.  */
+#define REENTRANT_GETNAME APPEND_R (GETFUNC_NAME)
+#define APPEND_R(name) APPEND_R1 (name)
+#define APPEND_R1(name) name##_r
+
+/* Sometimes we need to store error codes in the `h_errno' variable.  */
+#ifdef NEED_H_ERRNO
+# define H_ERRNO_PARM , int *h_errnop
+# define H_ERRNO_VAR , &h_errno
+#else
+# define H_ERRNO_PARM
+# define H_ERRNO_VAR
+#endif
+
+/* Prototype of the reentrant version.  */
+LOOKUP_TYPE *REENTRANT_GETNAME (LOOKUP_TYPE *result, char *buffer,
+                               int buflen H_ERRNO_PARM);
+
+
+LOOKUP_TYPE *
+GETFUNC_NAME (void)
+{
+  static char buffer[BUFLEN];
+  LOOKUP_TYPE result;
+
+  return REENTRANT_GETNAME (&result, buffer, BUFLEN H_ERRNO_VAR);
+}
diff --git a/nss/host-lookup.c b/nss/host-lookup.c
new file mode 100644 (file)
index 0000000..d9f7c67
--- /dev/null
@@ -0,0 +1,22 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+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.  */
+
+#define DATABASE_NAME hosts
+
+#include "XXX-lookup.c"
diff --git a/nss/network-lookup.c b/nss/network-lookup.c
new file mode 100644 (file)
index 0000000..ab6e51f
--- /dev/null
@@ -0,0 +1,22 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+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.  */
+
+#define DATABASE_NAME networks
+
+#include "XXX-lookup.c"
diff --git a/nss/nss_dns/dns-host.c b/nss/nss_dns/dns-host.c
new file mode 100644 (file)
index 0000000..eaa9e81
--- /dev/null
@@ -0,0 +1,611 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Extended from original form by Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+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.  */
+
+/* Parts of this file are plain copies of the file `getnetnamadr.c' from
+   the bind package and it has the following copyright.  */
+
+/* Copyright (c) 1993 Carlos Leandro and Rui Salgueiro
+ *      Dep. Matematica Universidade de Coimbra, Portugal, Europe
+ *
+ * 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.
+ */
+/*
+ * Copyright (c) 1983, 1993
+ *      The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by the University of
+ *      California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/syslog.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include "nsswitch.h"
+
+/* Get implementation for some internal functions.  */
+#include "../resolv/mapv4v6addr.h"
+#include "../resolv/mapv4v6hostent.h"
+
+/* Maximum number of aliases we allow.  */
+#define MAX_NR_ALIASES 48
+#define MAX_NR_ADDRS   48
+
+#if PACKETSZ > 1024
+# define MAXPACKET     PACKETSZ
+#else
+# define MAXPACKET     1024
+#endif
+
+static const char AskedForGot[] = "\
+gethostby*.getanswer: asked for \"%s\", got \"%s\"";
+
+
+/* We need this time later.  */
+typedef union querybuf
+{
+  HEADER hdr;
+  u_char buf[MAXPACKET];
+} querybuf;
+
+
+static enum nss_status getanswer_r (const querybuf *answer, int anslen,
+                                   const char *qname, int qtype,
+                                   struct hostent *result,
+                                   char *buffer, int buflen, int *h_errnop);
+
+enum nss_status
+_nss_dns_gethostbyname2_r (const char *name, int af, struct hostent *result,
+                          char *buffer, int buflen, int *h_errnop)
+{
+  struct host_data
+  {
+    char *aliases[MAX_NR_ALIASES];
+    unsigned char host_addr[16];       /* IPv4 or IPv6 */
+    char *h_addr_ptrs[MAX_NR_ADDRS + 1];
+    char linebuffer[0];
+  } *host_data = (struct host_data *) buffer;
+  int linebuflen = buflen - offsetof (struct host_data, linebuffer);
+  querybuf host_buffer;
+  int size, type, n;
+  const char *cp;
+
+  switch (af) {
+  case AF_INET:
+    size = INADDRSZ;
+    type = T_A;
+    break;
+  case AF_INET6:
+    size = IN6ADDRSZ;
+    type = T_AAAA;
+    break;
+  default:
+    *h_errnop = NETDB_INTERNAL;
+    errno = EAFNOSUPPORT;
+    return NSS_STATUS_UNAVAIL;
+  }
+
+  result->h_addrtype = af;
+  result->h_length = size;
+
+  /*
+   * if there aren't any dots, it could be a user-level alias.
+   * this is also done in res_query() since we are not the only
+   * function that looks up host names.
+   */
+  if (strchr (name, '.') == NULL && (cp = __hostalias (name)) != NULL)
+    name = cp;
+
+  /*
+   * disallow names consisting only of digits/dots, unless
+   * they end in a dot.
+   */
+  if (isdigit (name[0]))
+    for (cp = name;; ++cp)
+      {
+       if (*cp == '\0')
+         {
+           char *bp;
+
+           if (*--cp == '.')
+             break;
+           /*
+            * All-numeric, no dot at the end.  Fake up a hostent
+            * as if we'd actually done a lookup.
+            */
+           if (inet_pton (af, name, host_data->host_addr) <= 0)
+             {
+               *h_errnop = HOST_NOT_FOUND;
+               return NSS_STATUS_NOTFOUND;
+             }
+
+           bp = __stpncpy (host_data->linebuffer, name, linebuflen);
+           host_data->linebuffer[linebuflen - 1] = '\0';
+           linebuflen -= bp - host_data->linebuffer;
+
+           result->h_name = host_data->linebuffer;
+           result->h_aliases = host_data->aliases;
+           host_data->aliases[0] = NULL;
+           host_data->h_addr_ptrs[0] = (char *) host_data->host_addr;
+           host_data->h_addr_ptrs[1] = NULL;
+           result->h_addr_list = host_data->h_addr_ptrs;
+
+           if (_res.options & RES_USE_INET6)
+             map_v4v6_hostent (result, &bp, &linebuflen);
+           *h_errnop = NETDB_SUCCESS;
+           return NSS_STATUS_SUCCESS;
+         }
+       if (!isdigit (*cp) && *cp != '.')
+         break;
+      }
+
+  n = res_search (name, C_IN, type, host_buffer.buf, sizeof (host_buffer));
+  if (n < 0)
+    return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND;
+
+  return getanswer_r (&host_buffer, n, name, type, result, buffer, buflen,
+                     h_errnop);
+}
+
+
+enum nss_status
+_nss_dns_gethostbyname_r (const char *name, struct hostent *result,
+                         char *buffer, int buflen, int *h_errnop)
+{
+  enum nss_status status = NSS_STATUS_NOTFOUND;
+
+  if (_res.options & RES_USE_INET6)
+    status = _nss_dns_gethostbyname2_r (name, AF_INET6, result, buffer,
+                                       buflen, h_errnop);
+  if (status == NSS_STATUS_NOTFOUND)
+    status = _nss_dns_gethostbyname2_r (name, AF_INET, result, buffer,
+                                       buflen, h_errnop);
+
+  return status;
+}
+
+
+enum nss_status
+_nss_dns_gethostbyaddr_r (const char *addr, int len, int af,
+                         struct hostent *result, char *buffer, int buflen,
+                         int *h_errnop)
+{
+  static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
+  static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
+  const u_char *uaddr = (const u_char *)addr;
+  struct host_data
+  {
+    char *aliases[MAX_NR_ALIASES];
+    unsigned char host_addr[16];       /* IPv4 or IPv6 */
+    char *h_addr_ptrs[MAX_NR_ADDRS + 1];
+    char linebuffer[0];
+  } *host_data = (struct host_data *) buffer;
+  querybuf host_buffer;
+  char qbuf[MAXDNAME+1], *qp;
+  int size, n, status;
+
+  if (af == AF_INET6 && len == IN6ADDRSZ &&
+      (bcmp (uaddr, mapped, sizeof mapped) == 0
+       || bcmp (uaddr, tunnelled, sizeof tunnelled) == 0))
+    {
+      /* Unmap. */
+      addr += sizeof mapped;
+      uaddr += sizeof mapped;
+      af = AF_INET;
+      len = INADDRSZ;
+    }
+
+  switch (af)
+    {
+    case AF_INET:
+      size = INADDRSZ;
+      break;
+    case AF_INET6:
+      size = IN6ADDRSZ;
+      break;
+    default:
+      errno = EAFNOSUPPORT;
+      *h_errnop = NETDB_INTERNAL;
+      return NSS_STATUS_UNAVAIL;
+    }
+  if (size != len)
+    {
+      errno = EAFNOSUPPORT;
+      *h_errnop = NETDB_INTERNAL;
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  switch (af)
+    {
+    case AF_INET:
+      sprintf (qbuf, "%u.%u.%u.%u.in-addr.arpa", (uaddr[3] & 0xff),
+              (uaddr[2] & 0xff), (uaddr[1] & 0xff), (uaddr[0] & 0xff));
+      break;
+    case AF_INET6:
+      qp = qbuf;
+      for (n = IN6ADDRSZ - 1; n >= 0; n--)
+       qp += sprintf (qp, "%x.%x.", uaddr[n] & 0xf, (uaddr[n] >> 4) & 0xf);
+      strcpy(qp, "ip6.int");
+      break;
+    default:
+      /* Cannot happen.  */
+    }
+
+  n = res_query (qbuf, C_IN, T_PTR, (u_char *)host_buffer.buf,
+                sizeof host_buffer);
+  if (n < 0)
+    return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND;
+
+  status = getanswer_r (&host_buffer, n, qbuf, T_PTR, result, buffer, buflen,
+                       h_errnop);
+  if (status != NSS_STATUS_SUCCESS)
+    return status;
+
+#ifdef SUNSECURITY
+  This is not implemented because it is not possible to use the current
+  source from bind in a multi-threaded program.
+#endif
+
+  result->h_addrtype = af;
+  result->h_length = len;
+  bcopy (addr, host_data->host_addr, len);
+  host_data->h_addr_ptrs[0] = (char *) host_data->host_addr;
+  host_data->h_addr_ptrs[1] = NULL;
+  if (af == AF_INET && (_res.options & RES_USE_INET6))
+    {
+      map_v4v6_address ((char *) host_data->host_addr,
+                       (char *) host_data->host_addr);
+      result->h_addrtype = AF_INET6;
+      result->h_length = IN6ADDRSZ;
+    }
+  *h_errnop = NETDB_SUCCESS;
+  return NSS_STATUS_SUCCESS;
+}
+
+
+static enum nss_status
+getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
+            struct hostent *result, char *buffer, int buflen, int *h_errnop)
+{
+  struct host_data
+  {
+    char *aliases[MAX_NR_ALIASES];
+    unsigned char host_addr[16];       /* IPv4 or IPv6 */
+    char *h_addr_ptrs[MAX_NR_ADDRS + 1];
+    char linebuffer[0];
+  } *host_data = (struct host_data *) buffer;
+  int linebuflen = buflen - offsetof (struct host_data, linebuffer);
+  register const HEADER *hp;
+  const u_char *end_of_message, *cp;
+  int n, ancount, qdcount;
+  int haveanswer, had_error;
+  char *bp, **ap, **hap;
+  char tbuf[MAXDNAME+1];
+  const char *tname;
+  int (*name_ok) __P ((const char *));
+
+  tname = qname;
+  result->h_name = NULL;
+  end_of_message = answer->buf + anslen;
+  switch (qtype)
+    {
+    case T_A:
+    case T_AAAA:
+      name_ok = res_hnok;
+      break;
+    case T_PTR:
+      name_ok = res_dnok;
+      break;
+    default:
+      return NSS_STATUS_UNAVAIL;  /* XXX should be abort(); */
+    }
+
+  /*
+   * find first satisfactory answer
+   */
+  hp = &answer->hdr;
+  bp = host_data->linebuffer;
+  ancount = ntohs (hp->ancount);
+  qdcount = ntohs (hp->qdcount);
+  cp = answer->buf + HFIXEDSZ;
+  if (qdcount != 1)
+    {
+      *h_errnop = NO_RECOVERY;
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  n = dn_expand (answer->buf, end_of_message, cp, bp, linebuflen);
+  if (n < 0 || (*name_ok) (bp) == 0)
+    {
+      *h_errnop = NO_RECOVERY;
+      return NSS_STATUS_UNAVAIL;
+    }
+  cp += n + QFIXEDSZ;
+
+  if (qtype == T_A || qtype == T_AAAA)
+    {
+      /* res_send() has already verified that the query name is the
+       * same as the one we sent; this just gets the expanded name
+       * (i.e., with the succeeding search-domain tacked on).
+       */
+      n = strlen (bp) + 1;             /* for the \0 */
+      result->h_name = bp;
+      bp += n;
+      linebuflen -= n;
+      /* The qname can be abbreviated, but h_name is now absolute. */
+      qname = result->h_name;
+    }
+
+  ap = host_data->aliases;
+  *ap = NULL;
+  result->h_aliases = host_data->aliases;
+  hap = host_data->h_addr_ptrs;
+  *hap = NULL;
+  result->h_addr_list = host_data->h_addr_ptrs;
+  haveanswer = 0;
+  had_error = 0;
+
+  while (ancount-- > 0 && cp < end_of_message && had_error == 0)
+    {
+      int type, class;
+
+      n = dn_expand (answer->buf, end_of_message, cp, bp, linebuflen);
+      if (n < 0 || (*name_ok) (bp) == 0)
+       {
+         ++had_error;
+         continue;
+       }
+      cp += n;                         /* name */
+      type = _getshort (cp);
+      cp += INT16SZ;                   /* type */
+      class = _getshort(cp);
+      cp += INT16SZ + INT32SZ;         /* class, TTL */
+      n = _getshort(cp);
+      cp += INT16SZ;                   /* len */
+      if (class != C_IN)
+       {
+         /* XXX - debug? syslog? */
+         cp += n;
+         continue;                     /* XXX - had_error++ ? */
+       }
+
+      if ((qtype ==T_A || qtype == T_AAAA) && type == T_CNAME)
+       {
+         if (ap >= &host_data->aliases[MAX_NR_ALIASES - 1])
+           continue;
+         n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf);
+         if (n < 0 || (*name_ok) (tbuf) == 0)
+           {
+             ++had_error;
+             continue;
+           }
+         cp += n;
+         /* Store alias.  */
+         *ap++ = bp;
+         n = strlen (bp) + 1;          /* For the \0.  */
+         bp += n;
+         linebuflen -= n;
+         /* Get canonical name.  */
+         n = strlen (tbuf) + 1;        /* For the \0.  */
+         if (n > buflen)
+           {
+             ++had_error;
+             continue;
+           }
+         strcpy (bp, tbuf);
+         result->h_name = bp;
+         bp += n;
+         linebuflen -= n;
+         continue;
+       }
+
+      if (qtype == T_PTR && type == T_CNAME)
+       {
+         n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf);
+         if (n < 0 || res_hnok (tbuf) == 0)
+           {
+             ++had_error;
+             continue;
+           }
+         cp += n;
+         /* Get canonical name. */
+         n = strlen (tbuf) + 1;   /* For the \0.  */
+         if (n > buflen)
+           {
+             ++had_error;
+             continue;
+           }
+         strcpy (bp, tbuf);
+         tname = bp;
+         bp += n;
+         linebuflen -= n;
+         continue;
+       }
+      if (type != qtype)
+       {
+         syslog (LOG_NOTICE | LOG_AUTH,
+              "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
+                 qname, p_class (C_IN), p_type (qtype), p_type (type));
+         cp += n;
+         continue;                     /* XXX - had_error++ ? */
+       }
+
+      switch (type)
+       {
+       case T_PTR:
+         if (strcasecmp (tname, bp) != 0)
+           {
+             syslog (LOG_NOTICE | LOG_AUTH, AskedForGot, qname, bp);
+             cp += n;
+             continue;                 /* XXX - had_error++ ? */
+           }
+         n = dn_expand (answer->buf, end_of_message, cp, bp, linebuflen);
+         if (n < 0 || res_hnok (bp) == 0)
+           {
+             ++had_error;
+             break;
+           }
+#if MULTI_PTRS_ARE_ALIASES
+         cp += n;
+         if (haveanswer == 0)
+           result->h_name = bp;
+         else if (ap < &host_data->aliases[MAXALIASES-1])
+           *ap++ = bp;
+         else
+           n = -1;
+         if (n != -1)
+           {
+             n = strlen (bp) + 1;      /* for the \0 */
+             bp += n;
+             linebuflen -= n;
+           }
+         break;
+#else
+         result->h_name = bp;
+         if (_res.options & RES_USE_INET6)
+           {
+             n = strlen (bp) + 1;      /* for the \0 */
+             bp += n;
+             linebuflen -= n;
+             map_v4v6_hostent (result, &bp, &linebuflen);
+           }
+         *h_errnop = NETDB_SUCCESS;
+         return NSS_STATUS_SUCCESS;
+#endif
+       case T_A:
+       case T_AAAA:
+         if (strcasecmp (result->h_name, bp) != 0)
+           {
+             syslog (LOG_NOTICE | LOG_AUTH, AskedForGot, result->h_name, bp);
+             cp += n;
+             continue;                 /* XXX - had_error++ ? */
+           }
+         if (haveanswer)
+           {
+             if (n != result->h_length)
+               {
+                 cp += n;
+                 continue;
+               }
+           }
+         else
+           {
+             register int nn;
+
+             result->h_name = bp;
+             nn = strlen (bp) + 1;     /* for the \0 */
+             bp += nn;
+             linebuflen -= nn;
+           }
+
+         bp += sizeof (align) - ((u_long) bp % sizeof (align));
+
+         if (n >= linebuflen)
+           {
+             ++had_error;
+             continue;
+           }
+         if (hap >= &host_data->h_addr_ptrs[MAX_NR_ADDRS-1])
+           {
+             cp += n;
+             continue;
+           }
+         bcopy (cp, *hap++ = bp, n);
+         bp += n;
+         cp += n;
+         linebuflen -= n;
+         break;
+       default:
+         abort ();
+       }
+      if (had_error == 0)
+       ++haveanswer;
+    }
+
+  if (haveanswer > 0)
+    {
+      *ap = NULL;
+      *hap = NULL;
+#if defined(RESOLVSORT)
+      /*
+       * Note: we sort even if host can take only one address
+       * in its return structures - should give it the "best"
+       * address in that case, not some random one
+       */
+      if (_res.nsort && haveanswer > 1 && qtype == T_A)
+       addrsort (host_data->h_addr_ptrs, haveanswer);
+#endif /*RESOLVSORT*/
+
+      if (result->h_name == NULL)
+       {
+         n = strlen (qname) + 1;       /* For the \0.  */
+         if (n > linebuflen)
+           goto try_again;
+         strcpy (bp, qname);
+         result->h_name = bp;
+         bp += n;
+         linebuflen -= n;
+       }
+
+      if (_res.options & RES_USE_INET6)
+       map_v4v6_hostent (result, &bp, &linebuflen);
+      *h_errnop = NETDB_SUCCESS;
+      return NSS_STATUS_SUCCESS;
+    }
+try_again:
+  *h_errnop = TRY_AGAIN;
+  return NSS_STATUS_TRYAGAIN;
+}
diff --git a/nss/nsswitch.c b/nss/nsswitch.c
new file mode 100644 (file)
index 0000000..4c2ccf6
--- /dev/null
@@ -0,0 +1,588 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+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 <ctype.h>
+#include <dlfcn.h>
+#include <netdb.h>
+#include <libc-lock.h>
+#include <search.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "nsswitch.h"
+#include "../elf/link.h"       /* We need some help from ld.so.  */
+
+/* Prototypes for the local functions.  */
+static void nss_init (void);
+static void *nss_lookup_function (service_user *ni, const char *fct_name);
+static int nss_find_entry (struct entry **knownp, const char *key,
+                          void **valp);
+static void nss_insert_entry (struct entry **knownp, const char *key,
+                             void *val);
+static name_database *nss_parse_file (const char *fname);
+static name_database_entry *nss_getline (char *line);
+static service_library *nss_new_service (name_database *database,
+                                        const char *name);
+
+
+__libc_lock_define_initialized (static, lock);
+
+
+/* Global variable.  */
+struct __res_state _res;
+
+
+/* Known aliases for service names.  */
+static struct {
+  const char *alias;
+  const char *value;
+} service_alias[] =
+{
+  { "nis+", "nisplus" },
+  { "yp", "nis" }
+};
+
+
+/* Nonzero if the sevices are already initialized.  */
+static int nss_initialized;
+
+
+/* The root of the whole data base.  */
+static name_database *service_table;
+
+
+static void
+nss_init (void)
+{
+  /* Prevent multiple threads to change the service table.  */
+  __libc_lock_lock (lock);
+
+  if (service_table == NULL)
+    service_table = nss_parse_file (_PATH_NSSWITCH_CONF);
+
+  __libc_lock_unlock (lock);
+}
+
+
+/* -1 == database not found
+    0 == database entry pointer stored */
+int
+__nss_database_lookup (const char *database, service_user **ni)
+{
+  /* Return first `service_user' entry for DATABASE.
+     XXX Will use perfect hashing function for known databases.  */
+  name_database_entry *entry;
+
+  /* Test whether configuration data is available.  */
+  if (service_table == NULL)
+    {
+      if (nss_initialized == 0)
+       nss_init ();
+
+      if (service_table == NULL)
+       return -1;
+    }
+
+  /* XXX Could use some faster mechanism here.  But each database is
+     only requested once and so this might not be critical.  */
+  for (entry = service_table->entry; entry != NULL; entry = entry->next)
+    if (strcmp (database, entry->name) == 0)
+      break;
+
+  if (entry == NULL || (*ni = entry->service) == NULL)
+    return -1;
+
+  return 0;
+}
+
+
+/* -1 == not found
+    0 == adjusted for next function */
+int
+__nss_lookup (service_user **ni, const char *fct_name, void **fctp)
+{
+  *fctp = nss_lookup_function (*ni, fct_name);
+
+  while (*fctp == NULL
+        && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_CONTINUE
+        && (*ni)->next != NULL)
+    {
+      *ni = (*ni)->next;
+
+      *fctp = nss_lookup_function (*ni, fct_name);
+    }
+
+  return *fctp != NULL ? 0 : -1;
+}
+
+
+/* -1 == not found
+    0 == adjusted for next function
+    1 == finished */
+int
+__nss_next (service_user **ni, const char *fct_name, void **fctp, int status,
+           int all_values)
+{
+  if (all_values)
+    {
+      if (nss_next_action (*ni, NSS_STATUS_TRYAGAIN) == NSS_ACTION_RETURN
+         && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_RETURN
+         && nss_next_action (*ni, NSS_STATUS_NOTFOUND) == NSS_ACTION_RETURN
+         && nss_next_action (*ni, NSS_STATUS_SUCCESS) == NSS_ACTION_RETURN)
+       return 1;
+    }
+  else
+    {
+      /* This is really only for debugging.  */
+       if (NSS_STATUS_TRYAGAIN > status || status > NSS_STATUS_SUCCESS)
+        __libc_fatal ("illegal status in " __FUNCTION__);
+
+       if (nss_next_action (*ni, status) == NSS_ACTION_RETURN)
+        return 1;
+    }
+
+  if ((*ni)->next == NULL)
+    return -1;
+
+  do
+    {
+      *ni = (*ni)->next;
+
+      *fctp = nss_lookup_function (*ni, fct_name);
+    }
+  while (*fctp == NULL
+        && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_CONTINUE
+        && (*ni)->next != NULL);
+
+  return *fctp != NULL ? 0 : -1;
+}
+
+
+static int
+nss_dlerror_run (void (*operate) (void))
+{
+  const char *last_errstring = NULL;
+  const char *last_object_name = NULL;
+
+  (void) _dl_catch_error (&last_errstring, &last_object_name, operate);
+
+  return last_errstring != NULL;
+}
+
+
+static void *
+nss_lookup_function (service_user *ni, const char *fct_name)
+{
+  void *result;
+
+  /* Determine whether current function is loaded.  */
+  if (nss_find_entry (&ni->known, fct_name, &result) >= 0)
+    return result;
+
+  /* If we failed to allocate the needed data structures for the
+     service return an error.  This should only happen when we are out
+     of memory.  */
+  if (ni->library == NULL)
+    return NULL;
+
+  /* We now modify global data.  Protect it.  */
+  __libc_lock_lock (lock);
+
+  if (ni->library->lib_handle == NULL)
+    {
+      /* Load the shared library.  */
+      size_t shlen = (7 + strlen (ni->library->name) + 3
+                     + sizeof (NSS_SHLIB_REVISION));
+      char shlib_name[shlen];
+
+      void do_open (void)
+       {
+         /* The used function is found in GNU ld.so.  XXX The first
+            argument to _dl_open used to be `_dl_loaded'.  But this
+            does (currently) not work.  */
+         ni->library->lib_handle = _dl_open (shlib_name, RTLD_LAZY);
+       }
+
+      /* Construct name.  */
+      __stpcpy (__stpcpy (__stpcpy (shlib_name, "libnss_"), ni->library->name),
+               ".so" NSS_SHLIB_REVISION);
+
+      if (nss_dlerror_run (do_open) != 0)
+       /* Failed to load the library.  */
+       ni->library->lib_handle = (void *) -1;
+    }
+
+  if (ni->library->lib_handle == (void *) -1)
+    /* Library not found => function not found.  */
+    result = NULL;
+  else
+    {
+      /* Get the desired function.  Again,  GNU ld.so magic ahead.  */
+      size_t namlen = (5 + strlen (ni->library->name) + 1
+                      + strlen (fct_name) + 1);
+      char name[namlen];
+      struct link_map *map = ni->library->lib_handle;
+      Elf32_Addr loadbase;
+      const Elf32_Sym *ref = NULL;
+      void get_sym (void)
+       {
+         struct link_map *scope[2] = { map, NULL };
+         loadbase = _dl_lookup_symbol (name, &ref, scope, map->l_name, 0, 0);
+       }
+
+      __stpcpy (__stpcpy (__stpcpy (__stpcpy (name, "_nss_"),
+                                   ni->library->name),
+                         "_"),
+               fct_name);
+
+      result = (nss_dlerror_run (get_sym)
+               ? NULL : (void *) (loadbase + ref->st_value));
+    }
+
+  /* Remember function pointer for the usage.  */
+  nss_insert_entry (&ni->known, fct_name, result);
+
+  /* Remove the lock.  */
+  __libc_lock_unlock (lock);
+
+  return result;
+}
+
+
+static int
+known_compare (const void *p1, const void *p2)
+{
+  known_function *v1 = (known_function *) p1;
+  known_function *v2 = (known_function *) p2;
+
+  return strcmp (v1->fct_name, v2->fct_name);
+}
+
+
+static int
+nss_find_entry (struct entry **knownp, const char *key, void **valp)
+{
+  known_function looking_for = { fct_name: key };
+  struct entry **found;
+
+  found = __tfind (&looking_for, (const void **) knownp, known_compare);
+
+  if (found == NULL)
+    return -1;
+
+  *valp = ((known_function *) (*found)->key)->fct_ptr;
+
+  return 0;
+}
+
+
+static void
+nss_insert_entry (struct entry **knownp, const char *key, void *val)
+{
+  known_function *to_insert;
+
+  to_insert = (known_function *) malloc (sizeof (known_function));
+  if (to_insert == NULL)
+    return;
+
+  to_insert->fct_name = key;
+  to_insert->fct_ptr = val;
+
+  __tsearch (to_insert, (void **) knownp, known_compare);
+}
+
+
+static name_database *
+nss_parse_file (const char *fname)
+{
+  FILE *fp;
+  name_database *result;
+  name_database_entry *last;
+  char *line;
+  size_t len;
+
+  /* Open the configuration file.  */
+  fp = fopen (fname, "r");
+  if (fp == NULL)
+    return NULL;
+
+  result = (name_database *) malloc (sizeof (name_database));
+  if (result == NULL)
+    return NULL;
+
+  result->entry = NULL;
+  result->library = NULL;
+  last = NULL;
+  line = NULL;
+  len = 0;
+  do
+    {
+      name_database_entry *this;
+      ssize_t n;
+      char *cp;
+
+      n = getline (&line, &len, fp);
+      if (n < 0)
+       break;
+      if (line[n - 1] == '\n')
+       line[n - 1] = '\0';
+
+      /* Because the file format does not know any form of quoting we
+        can search forward for the next '#' character and if found
+        make it terminating the line.  */
+      cp = strchr (line, '#');
+      if (cp != NULL)
+       *cp = '\0';
+
+      /* If the line is blank it is ignored.  */
+      if (line[0] == '\0')
+       continue;
+
+      /* Each line completely specifies the actions for a database.  */
+      this = nss_getline (line);
+      if (this != NULL)
+       {
+         if (last != NULL)
+           last->next = this;
+         else
+           result->entry = this;
+
+         last = this;
+       }
+    }
+  while (!feof (fp));
+
+  /* Free the buffer.  */
+  free (line);
+  /* Close configuration file.  */
+  fclose (fp);
+
+  /* Now create for each service we could use an entry in LIBRARY list.  */
+  for (last = result->entry; last != NULL; last = last->next)
+    {
+      service_user *runp;
+
+      for (runp = last->service; runp != NULL; runp = runp->next)
+       runp->library = nss_new_service (result, runp->name);
+    }
+
+  return result;
+}
+
+
+static name_database_entry *
+nss_getline (char *line)
+{
+  const char *name;
+  name_database_entry *result;
+  service_user *last;
+
+  /* Ignore leading white spaces.  ATTENTION: this is different from
+     what is implemented in Solaris.  The Solaris man page says a line
+     beginning with a white space character is ignored.  We regard
+     this as just another misfeature in Solaris.  */
+  while (isspace (line[0]))
+    ++line;
+
+  /* Recognize `<database> ":"'.  */
+  name = line;
+  while (line[0] != '\0' && !isspace (line[0]) && line[0] != ':')
+    ++line;
+  if (line[0] == '\0' || name == line)
+    /* Syntax error.  */
+    return NULL;
+  *line++ = '\0';
+
+  result = (name_database_entry *) malloc (sizeof (name_database_entry));
+  if (result == NULL)
+    return NULL;
+
+  result->name = strdup (name);
+  if (result->name == NULL)
+    {
+      free (result);
+      return NULL;
+    }
+  result->service = NULL;
+  result->next = NULL;
+  last = NULL;
+
+  /* Read the source names: `<source> ( "[" <status> "=" <action> "]" )*'.  */
+  while (1)
+    {
+      service_user *new_service;
+      size_t n;
+
+      while (isspace (line[0]))
+       ++line;
+      if (line[0] == '\0')
+       /* No source specified.  */
+       return result;
+
+      /* Read <source> identifier.  */
+      name = line;
+      while (line[0] != '\0' && !isspace (line[0]) && line[0] != '[')
+       ++line;
+      if (name == line)
+       return result;
+
+
+      new_service = (service_user *) malloc (sizeof (service_user));
+      if (new_service == NULL)
+       return result;
+
+      /* Test whether the source name is one of the aliases.  */
+      for (n = 0; n < sizeof (service_alias) / sizeof (service_alias[0]); ++n)
+       if (strncmp (service_alias[n].alias, name, line - name) == 0
+           && service_alias[n].alias[line - name] == '\0')
+         break;
+
+      if (n < sizeof (service_alias) / sizeof (service_alias[0]))
+       new_service->name = service_alias[n].value;
+      else
+       {
+         char *source = (char *) malloc (line - name + 1);
+         if (source == NULL)
+           {
+             free (new_service);
+             return result;
+           }
+         memcpy (source, name, line - name);
+         source[line - name] = '\0';
+
+         new_service->name = source;
+       }
+
+      /* Set default actions.  */
+      new_service->actions[2 + NSS_STATUS_TRYAGAIN] = NSS_ACTION_CONTINUE;
+      new_service->actions[2 + NSS_STATUS_UNAVAIL] = NSS_ACTION_CONTINUE;
+      new_service->actions[2 + NSS_STATUS_NOTFOUND] = NSS_ACTION_CONTINUE;
+      new_service->actions[2 + NSS_STATUS_SUCCESS] = NSS_ACTION_RETURN;
+      new_service->library = NULL;
+      new_service->known = NULL;
+      new_service->next = NULL;
+
+      while (isspace (line[0]))
+       ++line;
+
+      if (line[0] == '[')
+       {
+         int status;
+
+         /* Read criterions.  */
+         do
+           ++line;
+         while (line[0] != '\0' && isspace (line[0]));
+
+         do
+           {
+             /* Read status name.  */
+             name = line;
+             while (line[0] != '\0' && !isspace (line[0]) && line[0] != '='
+                    && line[0] != ']')
+               ++line;
+
+             /* Compare with known statii.  */
+             if (line - name == 7)
+               {
+                 if (strncasecmp (name, "SUCCESS", 7) == 0)
+                   status = NSS_STATUS_SUCCESS;
+                 else if (strncasecmp (name, "UNAVAIL", 7) == 0)
+                   status = NSS_STATUS_UNAVAIL;
+                 else
+                   return result;
+               }
+             else if (line - name == 8)
+               {
+                 if (strncasecmp (name, "NOTFOUND", 8) == 0)
+                   status = NSS_STATUS_NOTFOUND;
+                 else if (strncasecmp (name, "TRYAGAIN", 8) == 0)
+                   status = NSS_STATUS_TRYAGAIN;
+                 else
+                   return result;
+               }
+             else
+               return result;
+
+             while (isspace (line[0]))
+               ++line;
+             if (line[0] != '=')
+               return result;
+             do
+               ++line;
+             while (isspace (line[0]));
+
+             name = line;
+             while (line[0] != '\0' && !isspace (line[0]) && line[0] != '='
+                    && line[0] != ']')
+               ++line;
+
+             if (line - name == 6 && strncasecmp (name, "RETURN", 6) == 0)
+               new_service->actions[2 + status] = NSS_ACTION_RETURN;
+             else if (line - name == 8
+                      && strncasecmp (name, "CONTINUE", 8) == 0)
+               new_service->actions[2 + status] = NSS_ACTION_CONTINUE;
+             else
+               return result;
+
+             /* Match white spaces.  */
+             while (isspace (line[0]))
+               ++line;
+           }
+         while (line[0] != ']');
+
+         /* Skip the ']'.  */
+         ++line;
+       }
+
+      if (last == NULL)
+       result->service = new_service;
+      else
+       last->next = new_service;
+      last = new_service;
+    }
+  /* NOTREACHED */
+  return NULL;
+}
+
+
+static service_library *
+nss_new_service (name_database *database, const char *name)
+{
+  service_library **currentp = &database->library;
+
+  while (*currentp != NULL)
+    {
+      if (strcmp ((*currentp)->name, name) == 0)
+       return *currentp;
+      currentp = &(*currentp)->next;
+    }
+
+  /* We have to add the new service.  */
+  *currentp = (service_library *) malloc (sizeof (service_library));
+  if (*currentp == NULL)
+    return NULL;
+
+  (*currentp)->name = name;
+  (*currentp)->lib_handle = NULL;
+  (*currentp)->next = NULL;
+
+  return *currentp;
+}
diff --git a/nss/nsswitch.h b/nss/nsswitch.h
new file mode 100644 (file)
index 0000000..f597a58
--- /dev/null
@@ -0,0 +1,138 @@
+/* Copyright (C) 1996 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.  */
+
+#ifndef _NSSWITCH_H
+#define _NSSWITCH_H    1
+
+/* This is an *internal* header.  */
+
+#include <arpa/nameser.h>
+#include <netinet/in.h>
+#include <resolv.h>
+#include <search.h>
+
+
+/* Revision number of NSS interface (must be a string).  */
+#define NSS_SHLIB_REVISION ".1"
+
+
+/* Possible results of lookup using a nss_* function.  */
+enum nss_status
+{
+  NSS_STATUS_TRYAGAIN = -2,
+  NSS_STATUS_UNAVAIL,
+  NSS_STATUS_NOTFOUND,
+  NSS_STATUS_SUCCESS,
+};
+
+
+/* Actions performed after lookup finished.  */
+typedef enum
+{
+  NSS_ACTION_CONTINUE,
+  NSS_ACTION_RETURN
+} lookup_actions;
+
+
+typedef struct service_library
+{
+  /* Name of service (`files', `dns', `nis', ...).  */
+  const char *name;
+  /* Pointer to the loaded shared library.  */
+  void *lib_handle;
+  /* And the link to the next entry.  */
+  struct service_library *next;
+} service_library;
+
+
+/* For mappng a function name to a function pointer.  */
+typedef struct
+{
+  const char *fct_name;
+  void *fct_ptr;
+} known_function;
+
+
+typedef struct service_user
+{
+  /* Name of the service (`files', `dns', `nis', ...).  */
+  const char *name;
+  /* Action according to result.  */
+  lookup_actions actions[4];
+  /* Link to the underlying library object.  */
+  service_library *library;
+  /* Collection of known functions.  */
+  struct entry *known;
+  /* And the link to the next entry.  */
+  struct service_user *next;
+} service_user;
+
+/* To access the action based on the status value use this macro.  */
+#define nss_next_action(ni, status) ((ni)->actions[2 + status])
+
+
+typedef struct name_database_entry
+{
+  /* Name of the database.  */
+  const char *name;
+  /* List of service to be used.  */
+  service_user *service;
+  /* And the link to the next entry.  */
+  struct name_database_entry *next;
+} name_database_entry;
+
+
+typedef struct name_database
+{
+  /* List of all known databases.  */
+  name_database_entry *entry;
+  /* List of libraries with service implementation.  */
+  service_library *library;
+} name_database;
+
+
+/* Interface functions for NSS.  */
+
+/* Get the data structure representing the specified database.  More
+   than one function can use the database.  */
+int __nss_database_lookup (const char *database, service_user **ni);
+
+
+/* Put first function with name FCT_NAME for SERVICE in FCTP.  The
+   position is remembered in NI.  The function returns a value < 0 if
+   an error occured or no such function exists.  */
+int __nss_lookup (service_user **ni, const char *fct_name, void **fctp);
+
+/* Determine the next step in the lookup process according to the
+   result STATUS of the call to the last function returned by
+   `__nss_lookup' or `__nss_next'.  NI specifies the last function
+   examined.  The function return a value > 0 if the process should
+   stop with the last result of the last function call to be the
+   result of the entire lookup.  The returned valie is 0 if there is
+   another function to use and < 0 if an error occured.
+
+   If ALL_VALUES is nonzero, the return value will not be > 0 as long as
+   there is a possibility the lookup process can ever use following
+   services.  In other words, only if all four lookup results have
+   the action RETURN associated the lookup process stops before the
+   natural end.  */
+int __nss_next (service_user **ni, const char *fct_name, void **fctp,
+               int status, int all_values);
+
+
+#endif /* nsswitch.h */
diff --git a/nss/proto-lookup.c b/nss/proto-lookup.c
new file mode 100644 (file)
index 0000000..f27ff59
--- /dev/null
@@ -0,0 +1,22 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+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.  */
+
+#define DATABASE_NAME protocols
+
+#include "XXX-lookup.c"
diff --git a/nss/service-lookup.c b/nss/service-lookup.c
new file mode 100644 (file)
index 0000000..c1a3256
--- /dev/null
@@ -0,0 +1,22 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+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.  */
+
+#define DATABASE_NAME services
+
+#include "XXX-lookup.c"