Example #1
0
/* -1 == not found
    0 == function found
    1 == finished */
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 : (*ni)->next == NULL ? 1 : -1;
}
Example #2
0
static int
internal_function
__internal_setnetgrent_reuse (const char *group, struct __netgrent *datap,
			      int *errnop)
{
  union
  {
    enum nss_status (*f) (const char *, struct __netgrent *);
    void *ptr;
  } fct;
  enum nss_status status = NSS_STATUS_UNAVAIL;
  struct name_list *new_elem;

  /* Free data from previous service.  */
  endnetgrent_hook (datap);

  /* Cycle through all the services and run their setnetgrent functions.  */
  int no_more = setup (&fct.ptr, &datap->nip);
  while (! no_more)
    {
      assert (datap->data == NULL);

      /* Ignore status, we force check in `__nss_next2'.  */
      status = DL_CALL_FCT (*fct.f, (group, datap));

      service_user *old_nip = datap->nip;
      no_more = __nss_next2 (&datap->nip, "setnetgrent", NULL, &fct.ptr,
			     status, 0);

      if (status == NSS_STATUS_SUCCESS && ! no_more)
	{
	  enum nss_status (*endfct) (struct __netgrent *);

	  endfct = __nss_lookup_function (old_nip, "endnetgrent");
	  if (endfct != NULL)
	    (void) DL_CALL_FCT (*endfct, (datap));
	}
    }

  /* Add the current group to the list of known groups.  */
  size_t group_len = strlen (group) + 1;
  new_elem = (struct name_list *) malloc (sizeof (struct name_list)
					  + group_len);
  if (new_elem == NULL)
    {
      *errnop = errno;
      status = NSS_STATUS_TRYAGAIN;
    }
  else
    {
      new_elem->next = datap->known_groups;
      memcpy (new_elem->name, group, group_len);
      datap->known_groups = new_elem;
    }

  return status == NSS_STATUS_SUCCESS;
}
Example #3
0
/* -1 == not found
    0 == adjusted for next function
    1 == finished */
int
__nss_next2 (service_user **ni, const char *fct_name, const char *fct2_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 (__builtin_expect (NSS_STATUS_TRYAGAIN > status
			    || status > NSS_STATUS_RETURN, 0))
	 __libc_fatal ("illegal status in __nss_next");

       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);
      if (*fctp == NULL && fct2_name != NULL)
	*fctp = __nss_lookup_function (*ni, fct2_name);
    }
  while (*fctp == NULL
	 && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_CONTINUE
	 && (*ni)->next != NULL);

  return *fctp != NULL ? 0 : -1;
}
Example #4
0
static void
endnetgrent_hook (struct __netgrent *datap)
{
  enum nss_status (*endfct) (struct __netgrent *);

  if (datap->nip == NULL || datap->nip == (service_user *) -1l)
    return;

  endfct = __nss_lookup_function (datap->nip, "endnetgrent");
  if (endfct != NULL)
    (void) (*endfct) (datap);
  datap->nip = NULL;
}
static int
internal_function
__nss_passwd_nonlocal_lookup(service_user **ni, const char *fct_name,
			     void **fctp)
{
    if (__nss_passwd_nonlocal_database == NULL
	&& __nss_database_lookup("passwd_nonlocal", NULL, NULL,
				 &__nss_passwd_nonlocal_database) < 0)
	return -1;

    *ni = __nss_passwd_nonlocal_database;

    *fctp = __nss_lookup_function(*ni, fct_name);
    return 0;
}
/* Initialize the NSS interface/functions. The calling function must
   hold the lock.  */
static void
init_nss_interface (void)
{
  __libc_lock_lock (lock);

  /* Retest.  */
  if (ni == NULL
      && __nss_database_lookup ("group_compat", NULL, "nis", &ni) >= 0)
    {
      nss_initgroups_dyn = __nss_lookup_function (ni, "initgroups_dyn");
      nss_setgrent = __nss_lookup_function (ni, "setgrent");
      nss_getgrnam_r = __nss_lookup_function (ni, "getgrnam_r");
      nss_getgrgid_r = __nss_lookup_function (ni, "getgrgid_r");
      nss_getgrent_r = __nss_lookup_function (ni, "getgrent_r");
      nss_endgrent = __nss_lookup_function (ni, "endgrent");
    }

  __libc_lock_unlock (lock);
}
Example #7
0
/* Test whether given (host,user,domain) triple is in NETGROUP.  */
int
innetgr (const char *netgroup, const char *host, const char *user,
	 const char *domain)
{
#ifdef USE_NSCD
  if (__nss_not_use_nscd_netgroup > 0
      && ++__nss_not_use_nscd_netgroup > NSS_NSCD_RETRY)
    __nss_not_use_nscd_netgroup = 0;

  if (!__nss_not_use_nscd_netgroup
      && !__nss_database_custom[NSS_DBSIDX_netgroup])
    {
      int result = __nscd_innetgr (netgroup, host, user, domain);
      if (result >= 0)
	return result;
    }
#endif

  union
  {
    enum nss_status (*f) (const char *, struct __netgrent *);
    void *ptr;
  } setfct;
  void (*endfct) (struct __netgrent *);
  int (*getfct) (struct __netgrent *, char *, size_t, int *);
  struct __netgrent entry;
  int result = 0;
  const char *current_group = netgroup;

  memset (&entry, '\0', sizeof (entry));

  /* Walk through the services until we found an answer or we shall
     not work further.  We can do some optimization here.  Since all
     services must provide the `setnetgrent' function we can do all
     the work during one walk through the service list.  */
  while (1)
    {
      int no_more = setup (&setfct.ptr, &entry.nip);
      while (! no_more)
	{
	  assert (entry.data == NULL);

	  /* Open netgroup.  */
	  enum nss_status status = DL_CALL_FCT (*setfct.f,
						(current_group, &entry));

	  if (status == NSS_STATUS_SUCCESS
	      && (getfct = __nss_lookup_function (entry.nip, "getnetgrent_r"))
		 != NULL)
	    {
	      char buffer[1024];

	      while (DL_CALL_FCT (*getfct,
				  (&entry, buffer, sizeof buffer, &errno))
		     == NSS_STATUS_SUCCESS)
		{
		  if (entry.type == group_val)
		    {
		      /* Make sure we haven't seen the name before.  */
		      struct name_list *namep;

		      for (namep = entry.known_groups; namep != NULL;
			   namep = namep->next)
			if (strcmp (entry.val.group, namep->name) == 0)
			  break;
		      if (namep == NULL)
			for (namep = entry.needed_groups; namep != NULL;
			     namep = namep->next)
			  if (strcmp (entry.val.group, namep->name) == 0)
			    break;
		      if (namep == NULL
			  && strcmp (netgroup, entry.val.group) != 0)
			{
			  size_t group_len = strlen (entry.val.group) + 1;
			  namep =
			    (struct name_list *) malloc (sizeof (*namep)
							 + group_len);
			  if (namep == NULL)
			    {
			      /* Out of memory, simply return.  */
			      result = -1;
			      break;
			    }

			  namep->next = entry.needed_groups;
			  memcpy (namep->name, entry.val.group, group_len);
			  entry.needed_groups = namep;
			}
		    }
		  else
		    {
		      if ((entry.val.triple.host == NULL || host == NULL
			   || __strcasecmp (entry.val.triple.host, host) == 0)
			  && (entry.val.triple.user == NULL || user == NULL
			      || strcmp (entry.val.triple.user, user) == 0)
			  && (entry.val.triple.domain == NULL || domain == NULL
			      || __strcasecmp (entry.val.triple.domain,
					       domain) == 0))
			{
			  result = 1;
			  break;
			}
		    }
		}

	      /* If we found one service which does know the given
		 netgroup we don't try further.  */
	      status = NSS_STATUS_RETURN;
	    }

	  /* Free all resources of the service.  */
	  endfct = __nss_lookup_function (entry.nip, "endnetgrent");
	  if (endfct != NULL)
	    DL_CALL_FCT (*endfct, (&entry));

	  if (result != 0)
	    break;

	  /* Look for the next service.  */
	  no_more = __nss_next2 (&entry.nip, "setnetgrent", NULL,
				 &setfct.ptr, status, 0);
	}

      if (result == 0 && entry.needed_groups != NULL)
	{
	  struct name_list *tmp = entry.needed_groups;
	  entry.needed_groups = tmp->next;
	  tmp->next = entry.known_groups;
	  entry.known_groups = tmp;
	  current_group = tmp->name;
	  continue;
	}

      /* No way out.  */
      break;
    }

  /* Free the memory.  */
  free_memory (&entry);

  return result == 1;
}
Example #8
0
int
internal_function
__internal_getnetgrent_r (char **hostp, char **userp, char **domainp,
			  struct __netgrent *datap,
			  char *buffer, size_t buflen, int *errnop)
{
  enum nss_status (*fct) (struct __netgrent *, char *, size_t, int *);

  /* Initialize status to return if no more functions are found.  */
  enum nss_status status = NSS_STATUS_NOTFOUND;

  /* Run through available functions, starting with the same function last
     run.  We will repeat each function as long as it succeeds, and then go
     on to the next service action.  */
  int no_more = datap->nip == NULL;
  if (! no_more)
    {
#ifdef USE_NSCD
      /* This bogus function pointer is a special marker left by
	 __nscd_setnetgrent to tell us to use the data it left
	 before considering any modules.  */
      if (datap->nip == (service_user *) -1l)
	fct = nscd_getnetgrent;
      else
#endif
	{
	  fct = __nss_lookup_function (datap->nip, "getnetgrent_r");
	  no_more = fct == NULL;
	}

      while (! no_more)
	{
	  status = DL_CALL_FCT (*fct, (datap, buffer, buflen, &errno));

	  if (status == NSS_STATUS_RETURN
	      /* The service returned a NOTFOUND, but there are more groups that
		 we need to resolve before we give up.  */
	      || (status == NSS_STATUS_NOTFOUND && datap->needed_groups != NULL))
	    {
	      /* This was the last one for this group.  Look at next group
		 if available.  */
	      int found = 0;
	      while (datap->needed_groups != NULL && ! found)
		{
		  struct name_list *tmp = datap->needed_groups;
		  datap->needed_groups = datap->needed_groups->next;
		  tmp->next = datap->known_groups;
		  datap->known_groups = tmp;

		  found = __internal_setnetgrent_reuse (datap->known_groups->name,
							datap, errnop);
		}

	      if (found && datap->nip != NULL)
		{
		  fct = __nss_lookup_function (datap->nip, "getnetgrent_r");
		  if (fct != NULL)
		    continue;
		}
	    }
	  else if (status == NSS_STATUS_SUCCESS && datap->type == group_val)
	    {
	      /* The last entry was a name of another netgroup.  */
	      struct name_list *namep;

	      /* Ignore if we've seen the name before.  */
	      for (namep = datap->known_groups; namep != NULL;
		   namep = namep->next)
		if (strcmp (datap->val.group, namep->name) == 0)
		  break;
	      if (namep == NULL)
		for (namep = datap->needed_groups; namep != NULL;
		     namep = namep->next)
		  if (strcmp (datap->val.group, namep->name) == 0)
		    break;
	      if (namep != NULL)
		/* Really ignore.  */
		continue;

	      size_t group_len = strlen (datap->val.group) + 1;
	      namep = (struct name_list *) malloc (sizeof (struct name_list)
						  + group_len);
	      if (namep == NULL)
		/* We are out of memory.  */
		status = NSS_STATUS_RETURN;
	      else
		{
		  namep->next = datap->needed_groups;
		  memcpy (namep->name, datap->val.group, group_len);
		  datap->needed_groups = namep;
		  /* And get the next entry.  */
		  continue;
		}
	    }
	  break;
	}
    }

  if (status == NSS_STATUS_SUCCESS)
    {
      *hostp = (char *) datap->val.triple.host;
      *userp = (char *) datap->val.triple.user;
      *domainp = (char *) datap->val.triple.domain;
    }

  return status == NSS_STATUS_SUCCESS ? 1 : 0;
}
Example #9
0
static int
internal_getgrouplist (const char *user, gid_t group, long int *size,
		       gid_t **groupsp, long int limit)
{
#ifdef USE_NSCD
  if (__nss_not_use_nscd_group > 0
      && ++__nss_not_use_nscd_group > NSS_NSCD_RETRY)
    __nss_not_use_nscd_group = 0;
  if (!__nss_not_use_nscd_group
      && !__nss_database_custom[NSS_DBSIDX_group])
    {
      int n = __nscd_getgrouplist (user, group, size, groupsp, limit);
      if (n >= 0)
	return n;

      /* nscd is not usable.  */
      __nss_not_use_nscd_group = 1;
    }
#endif

  enum nss_status status = NSS_STATUS_UNAVAIL;
  int no_more = 0;

  /* Never store more than the starting *SIZE number of elements.  */
  assert (*size > 0);
  (*groupsp)[0] = group;
  /* Start is one, because we have the first group as parameter.  */
  long int start = 1;

  if (__nss_initgroups_database == NULL)
    {
      if (__nss_database_lookup ("initgroups", NULL, "",
				 &__nss_initgroups_database) < 0)
	{
	  if (__nss_group_database == NULL)
	    no_more = __nss_database_lookup ("group", NULL, "compat files",
					     &__nss_group_database);

	  __nss_initgroups_database = __nss_group_database;
	}
      else
	use_initgroups_entry = true;
    }
  else
    /* __nss_initgroups_database might have been set through
       __nss_configure_lookup in which case use_initgroups_entry was
       not set here.  */
    use_initgroups_entry = __nss_initgroups_database != __nss_group_database;

  service_user *nip = __nss_initgroups_database;
  while (! no_more)
    {
      long int prev_start = start;

      initgroups_dyn_function fct = __nss_lookup_function (nip,
							   "initgroups_dyn");
      if (fct == NULL)
	status = compat_call (nip, user, group, &start, size, groupsp,
			      limit, &errno);
      else
	status = DL_CALL_FCT (fct, (user, group, &start, size, groupsp,
				    limit, &errno));

      /* Remove duplicates.  */
      long int cnt = prev_start;
      while (cnt < start)
	{
	  long int inner;
	  for (inner = 0; inner < prev_start; ++inner)
	    if ((*groupsp)[inner] == (*groupsp)[cnt])
	      break;

	  if (inner < prev_start)
	    (*groupsp)[cnt] = (*groupsp)[--start];
	  else
	    ++cnt;
	}

      /* This is really only for debugging.  */
      if (NSS_STATUS_TRYAGAIN > status || status > NSS_STATUS_RETURN)
	__libc_fatal ("illegal status in internal_getgrouplist");

      /* For compatibility reason we will continue to look for more
	 entries using the next service even though data has already
	 been found if the nsswitch.conf file contained only a 'groups'
	 line and no 'initgroups' line.  If the latter is available
	 we always respect the status.  This means that the default
	 for successful lookups is to return.  */
      if ((use_initgroups_entry || status != NSS_STATUS_SUCCESS)
	  && nss_next_action (nip, status) == NSS_ACTION_RETURN)
	 break;

      if (nip->next == NULL)
	no_more = -1;
      else
	nip = nip->next;
    }

  return start;
}
int
internal_getnetgrent_r (char **hostp, char **userp, char **domainp,
			  struct __netgrent *datap,
			  char *buffer, size_t buflen, int *errnop)
{
  enum nss_status (*fct) (struct __netgrent *, char *, size_t, int *);

  /* Initialize status to return if no more functions are found.  */
  enum nss_status status = NSS_STATUS_NOTFOUND;

  /* Run through available functions, starting with the same function last
     run.  We will repeat each function as long as it succeeds, and then go
     on to the next service action.  */
  int no_more = (datap->nip == NULL
		 || (fct = __nss_lookup_function (datap->nip, "getnetgrent_r"))
		    == NULL);
  while (! no_more)
    {
      status = (*fct) (datap, buffer, buflen, &errno);

      if (status == NSS_STATUS_RETURN)
	{
	  /* This was the last one for this group.  Look at next group
	     if available.  */
	  int found = 0;
	  while (datap->needed_groups != NULL && ! found)
	    {
	      struct name_list *tmp = datap->needed_groups;
	      datap->needed_groups = datap->needed_groups->next;
	      tmp->next = datap->known_groups;
	      datap->known_groups = tmp;

	      found = __internal_setnetgrent_reuse (datap->known_groups->name,
						    datap, errnop);
	    }

	  if (found && datap->nip != NULL)
	    {
	      fct = __nss_lookup_function (datap->nip, "getnetgrent_r");
	      if (fct != NULL)
		continue;
	    }
	}
      else if (status == NSS_STATUS_SUCCESS && datap->type == group_val)
	{
	  /* The last entry was a name of another netgroup.  */
	  struct name_list *namep;

	  /* Ignore if we've seen the name before.  */
	  for (namep = datap->known_groups; namep != NULL;
	       namep = namep->next)
	    if (strcmp (datap->val.group, namep->name) == 0)
	      break;
	  if (namep != NULL)
	    /* Really ignore.  */
	    continue;

	  size_t group_len = strlen (datap->val.group) + 1;
	  namep = (struct name_list *) malloc (sizeof (struct name_list)
					       + group_len);
	  if (namep == NULL)
	    /* We are out of memory.  */
	    status = NSS_STATUS_RETURN;
	  else
	    {
	      namep->next = datap->needed_groups;
	      memcpy (namep->name, datap->val.group, group_len);
	      datap->needed_groups = namep;
	      /* And get the next entry.  */
	      continue;
	    }
	}

      break;
    }

  if (status == NSS_STATUS_SUCCESS)
    {
      *hostp = (char *) datap->val.triple.host;
      *userp = (char *) datap->val.triple.user;
      *domainp = (char *) datap->val.triple.domain;
    }

  return status == NSS_STATUS_SUCCESS ? 1 : 0;
}