summary refs log tree commit diff
path: root/nss/nsswitch.c
diff options
context:
space:
mode:
Diffstat (limited to 'nss/nsswitch.c')
-rw-r--r--nss/nsswitch.c205
1 files changed, 101 insertions, 104 deletions
diff --git a/nss/nsswitch.c b/nss/nsswitch.c
index 2b3ae0bbe1..9b6c4eb12f 100644
--- a/nss/nsswitch.c
+++ b/nss/nsswitch.c
@@ -38,6 +38,7 @@ 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_user *nss_parse_service_list (const char *line);
 static service_library *nss_new_service (name_database *database,
 					 const char *name);
 
@@ -49,17 +50,6 @@ __libc_lock_define_initialized (static, lock);
 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;
 
@@ -84,8 +74,11 @@ nss_init (void)
 /* -1 == database not found
     0 == database entry pointer stored */
 int
-__nss_database_lookup (const char *database, service_user **ni)
+__nss_database_lookup (const char *database, const char *defconfig,
+		       service_user **ni)
 {
+  name_database_entry *entry;
+
   if (nss_initialized == 0)
     nss_init ();
 
@@ -94,7 +87,6 @@ __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;
 
       /* XXX Could use some faster mechanism here.  But each database is
 	 only requested once and so this might not be critical.  */
@@ -107,29 +99,17 @@ __nss_database_lookup (const char *database, service_user **ni)
     }
 
   /* No configuration data is available, either because nsswitch.conf
-     doesn't exist or because it doesn't have a line for this database.
-     Use a default equivalent to:
-     	database: compat [NOTFOUND=return] dns [NOTFOUND=return] files
-     */
-  {
-#define DEFAULT_SERVICE(name, next)					      \
-    static service_user default_##name =				      \
-      {									      \
-	#name,								      \
-	{								      \
-	  NSS_ACTION_CONTINUE,						      \
-	  NSS_ACTION_CONTINUE,						      \
-	  NSS_ACTION_RETURN,						      \
-	  NSS_ACTION_RETURN,						      \
-	},								      \
-	NULL, NULL,							      \
-	next								      \
-      }
-    DEFAULT_SERVICE (files, NULL);
-    DEFAULT_SERVICE (dns, &default_files);
-    DEFAULT_SERVICE (compat, &default_dns);
-    *ni = &default_compat;
-  }
+     doesn't exist or because it doesn't have a line for this database.  */
+  entry = malloc (sizeof *entry);
+  if (entry == NULL)
+    return -1;
+  entry->name = database;
+  /* DEFCONFIG specifies the default service list for this database,
+     or null to use the most common default.  */
+  entry->service = nss_parse_service_list (defconfig ?:
+					   "compat [NOTFOUND=return] files");
+
+  *ni = entry->service;
   return 0;
 }
 
@@ -246,9 +226,7 @@ nss_lookup_function (service_user *ni, const char *fct_name)
 
       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.  */
+	  /* Open and relocate the shared object.  */
 	  ni->library->lib_handle = _dl_open (shlib_name, RTLD_LAZY);
 	}
 
@@ -370,7 +348,7 @@ nss_parse_file (const char *fname)
       ssize_t n;
       char *cp;
 
-      n = getline (&line, &len, fp);
+      n = __getline (&line, &len, fp);
       if (n < 0)
 	break;
       if (line[n - 1] == '\n')
@@ -410,48 +388,16 @@ nss_parse_file (const char *fname)
 }
 
 
-static name_database_entry *
-nss_getline (char *line)
+/* Read the source names: `<source> ( "[" <status> "=" <action> "]" )*'.  */
+static service_user *
+nss_parse_service_list (const 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';
+  service_user *result = NULL, **nextp = &result;
 
-  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;
+      char *name;
 
       while (isspace (line[0]))
 	++line;
@@ -470,15 +416,6 @@ nss_getline (char *line)
       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);
@@ -507,8 +444,6 @@ nss_getline (char *line)
 
       if (line[0] == '[')
 	{
-	  int status;
-
 	  /* Read criterions.  */
 	  do
 	    ++line;
@@ -516,6 +451,14 @@ nss_getline (char *line)
 
 	  do
 	    {
+	      int not;
+	      enum nss_status status;
+	      lookup_actions action;
+
+	      /* Grok ! before name to mean all statii but that one.  */
+	      if (not = line[0] == '!')
+		++line;
+
 	      /* Read status name.  */
 	      name = line;
 	      while (line[0] != '\0' && !isspace (line[0]) && line[0] != '='
@@ -525,18 +468,18 @@ nss_getline (char *line)
 	      /* Compare with known statii.  */
 	      if (line - name == 7)
 		{
-		  if (strncasecmp (name, "SUCCESS", 7) == 0)
+		  if (__strncasecmp (name, "SUCCESS", 7) == 0)
 		    status = NSS_STATUS_SUCCESS;
-		  else if (strncasecmp (name, "UNAVAIL", 7) == 0)
+		  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)
+		  if (__strncasecmp (name, "NOTFOUND", 8) == 0)
 		    status = NSS_STATUS_NOTFOUND;
-		  else if (strncasecmp (name, "TRYAGAIN", 8) == 0)
+		  else if (__strncasecmp (name, "TRYAGAIN", 8) == 0)
 		    status = NSS_STATUS_TRYAGAIN;
 		  else
 		    return result;
@@ -557,15 +500,29 @@ nss_getline (char *line)
 		     && line[0] != ']')
 		++line;
 
-	      if (line - name == 6 && strncasecmp (name, "RETURN", 6) == 0)
-		new_service->actions[2 + status] = NSS_ACTION_RETURN;
+	      if (line - name == 6 && __strncasecmp (name, "RETURN", 6) == 0)
+		action = NSS_ACTION_RETURN;
 	      else if (line - name == 8
-		       && strncasecmp (name, "CONTINUE", 8) == 0)
-		new_service->actions[2 + status] = NSS_ACTION_CONTINUE;
+		       && __strncasecmp (name, "CONTINUE", 8) == 0)
+		action = NSS_ACTION_CONTINUE;
 	      else
 		return result;
 
-	      /* Match white spaces.  */
+	      if (not)
+		{
+		  /* Save the current action setting for this status,
+		     set them all to the given action, and reset this one.  */
+		  const lookup_actions save = new_service->actions[2 + status];
+		  new_service->actions[2 + NSS_STATUS_TRYAGAIN] = action;
+		  new_service->actions[2 + NSS_STATUS_UNAVAIL] = action;
+		  new_service->actions[2 + NSS_STATUS_NOTFOUND] = action;
+		  new_service->actions[2 + NSS_STATUS_SUCCESS] = action;
+		  new_service->actions[2 + status] = save;
+		}
+	      else
+		new_service->actions[2 + status] = action;
+
+	      /* Skip white spaces.  */
 	      while (isspace (line[0]))
 		++line;
 	    }
@@ -575,14 +532,54 @@ nss_getline (char *line)
 	  ++line;
 	}
 
-      if (last == NULL)
-	result->service = new_service;
-      else
-	last->next = new_service;
-      last = new_service;
+      *nextp = new_service;
+      nextp = &new_service->next;
     }
-  /* NOTREACHED */
-  return NULL;
+}
+
+static name_database_entry *
+nss_getline (char *line)
+{
+  const char *name;
+  name_database_entry *result;
+
+  /* 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;
+
+  /* Save the database name.  */
+  {
+    const size_t len = strlen (name) + 1;
+    char *new = malloc (len);
+    if (new == NULL)
+      {
+	free (result);
+	return NULL;
+      }
+    result->name = memcpy (new, name, len);
+  }
+
+  /* Parse the list of services.  */
+  result->service = nss_parse_service_list (line);
+
+  result->next = NULL;
+  return result;
 }