Blame nscd/pwdcache.c

Packit Service 82fcde
/* Cache handling for passwd lookup.
Packit Service 82fcde
   Copyright (C) 1998-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
Packit Service 82fcde
Packit Service 82fcde
   This program is free software; you can redistribute it and/or modify
Packit Service 82fcde
   it under the terms of the GNU General Public License as published
Packit Service 82fcde
   by the Free Software Foundation; version 2 of the License, or
Packit Service 82fcde
   (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   This program is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 82fcde
   GNU General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU General Public License
Packit Service 82fcde
   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#include <assert.h>
Packit Service 82fcde
#include <errno.h>
Packit Service 82fcde
#include <error.h>
Packit Service 82fcde
#include <libintl.h>
Packit Service 82fcde
#include <pwd.h>
Packit Service 82fcde
#include <stdbool.h>
Packit Service 82fcde
#include <stddef.h>
Packit Service 82fcde
#include <stdio.h>
Packit Service 82fcde
#include <stdlib.h>
Packit Service 82fcde
#include <string.h>
Packit Service 82fcde
#include <time.h>
Packit Service 82fcde
#include <unistd.h>
Packit Service 82fcde
#include <sys/mman.h>
Packit Service 82fcde
#include <sys/socket.h>
Packit Service 82fcde
#include <stackinfo.h>
Packit Service 82fcde
#include <scratch_buffer.h>
Packit Service 82fcde
Packit Service 82fcde
#include "nscd.h"
Packit Service 82fcde
#include "dbg_log.h"
Packit Service 82fcde
Packit Service 82fcde
/* This is the standard reply in case the service is disabled.  */
Packit Service 82fcde
static const pw_response_header disabled =
Packit Service 82fcde
{
Packit Service 82fcde
  .version = NSCD_VERSION,
Packit Service 82fcde
  .found = -1,
Packit Service 82fcde
  .pw_name_len = 0,
Packit Service 82fcde
  .pw_passwd_len = 0,
Packit Service 82fcde
  .pw_uid = -1,
Packit Service 82fcde
  .pw_gid = -1,
Packit Service 82fcde
  .pw_gecos_len = 0,
Packit Service 82fcde
  .pw_dir_len = 0,
Packit Service 82fcde
  .pw_shell_len = 0
Packit Service 82fcde
};
Packit Service 82fcde
Packit Service 82fcde
/* This is the struct describing how to write this record.  */
Packit Service 82fcde
const struct iovec pwd_iov_disabled =
Packit Service 82fcde
{
Packit Service 82fcde
  .iov_base = (void *) &disabled,
Packit Service 82fcde
  .iov_len = sizeof (disabled)
Packit Service 82fcde
};
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* This is the standard reply in case we haven't found the dataset.  */
Packit Service 82fcde
static const pw_response_header notfound =
Packit Service 82fcde
{
Packit Service 82fcde
  .version = NSCD_VERSION,
Packit Service 82fcde
  .found = 0,
Packit Service 82fcde
  .pw_name_len = 0,
Packit Service 82fcde
  .pw_passwd_len = 0,
Packit Service 82fcde
  .pw_uid = -1,
Packit Service 82fcde
  .pw_gid = -1,
Packit Service 82fcde
  .pw_gecos_len = 0,
Packit Service 82fcde
  .pw_dir_len = 0,
Packit Service 82fcde
  .pw_shell_len = 0
Packit Service 82fcde
};
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
static time_t
Packit Service 82fcde
cache_addpw (struct database_dyn *db, int fd, request_header *req,
Packit Service 82fcde
	     const void *key, struct passwd *pwd, uid_t owner,
Packit Service 82fcde
	     struct hashentry *const he, struct datahead *dh, int errval)
Packit Service 82fcde
{
Packit Service 82fcde
  bool all_written = true;
Packit Service 82fcde
  ssize_t total;
Packit Service 82fcde
  time_t t = time (NULL);
Packit Service 82fcde
Packit Service 82fcde
  /* We allocate all data in one memory block: the iov vector,
Packit Service 82fcde
     the response header and the dataset itself.  */
Packit Service 82fcde
  struct dataset
Packit Service 82fcde
  {
Packit Service 82fcde
    struct datahead head;
Packit Service 82fcde
    pw_response_header resp;
Packit Service 82fcde
    char strdata[0];
Packit Service 82fcde
  } *dataset;
Packit Service 82fcde
Packit Service 82fcde
  assert (offsetof (struct dataset, resp) == offsetof (struct datahead, data));
Packit Service 82fcde
Packit Service 82fcde
  time_t timeout = MAX_TIMEOUT_VALUE;
Packit Service 82fcde
  if (pwd == NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      if (he != NULL && errval == EAGAIN)
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* If we have an old record available but cannot find one
Packit Service 82fcde
	     now because the service is not available we keep the old
Packit Service 82fcde
	     record and make sure it does not get removed.  */
Packit Service 82fcde
	  if (reload_count != UINT_MAX && dh->nreloads == reload_count)
Packit Service 82fcde
	    /* Do not reset the value if we never not reload the record.  */
Packit Service 82fcde
	    dh->nreloads = reload_count - 1;
Packit Service 82fcde
Packit Service 82fcde
	  /* Reload with the same time-to-live value.  */
Packit Service 82fcde
	  timeout = dh->timeout = t + db->postimeout;
Packit Service 82fcde
Packit Service 82fcde
	  total = 0;
Packit Service 82fcde
	}
Packit Service 82fcde
      else
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* We have no data.  This means we send the standard reply for this
Packit Service 82fcde
	     case.  */
Packit Service 82fcde
	  total = sizeof (notfound);
Packit Service 82fcde
Packit Service 82fcde
	  if (fd != -1
Packit Service 82fcde
	      && TEMP_FAILURE_RETRY (send (fd, &notfound, total,
Packit Service 82fcde
					   MSG_NOSIGNAL)) != total)
Packit Service 82fcde
	    all_written = false;
Packit Service 82fcde
Packit Service 82fcde
	  /* If we have a transient error or cannot permanently store
Packit Service 82fcde
	     the result, so be it.  */
Packit Service 82fcde
	  if (errno == EAGAIN || __builtin_expect (db->negtimeout == 0, 0))
Packit Service 82fcde
	    {
Packit Service 82fcde
	      /* Mark the old entry as obsolete.  */
Packit Service 82fcde
	      if (dh != NULL)
Packit Service 82fcde
		dh->usable = false;
Packit Service 82fcde
	    }
Packit Service 82fcde
	  else if ((dataset = mempool_alloc (db, (sizeof (struct dataset)
Packit Service 82fcde
						  + req->key_len), 1)) != NULL)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      timeout = datahead_init_neg (&dataset->head,
Packit Service 82fcde
					   (sizeof (struct dataset)
Packit Service 82fcde
					    + req->key_len), total,
Packit Service 82fcde
					   db->negtimeout);
Packit Service 82fcde
Packit Service 82fcde
	      /* This is the reply.  */
Packit Service 82fcde
	      memcpy (&dataset->resp, &notfound, total);
Packit Service 82fcde
Packit Service 82fcde
	      /* Copy the key data.  */
Packit Service 82fcde
	      char *key_copy = memcpy (dataset->strdata, key, req->key_len);
Packit Service 82fcde
Packit Service 82fcde
	      /* If necessary, we also propagate the data to disk.  */
Packit Service 82fcde
	      if (db->persistent)
Packit Service 82fcde
		{
Packit Service 82fcde
		  // XXX async OK?
Packit Service 82fcde
		  uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
Packit Service 82fcde
		  msync ((void *) pval,
Packit Service 82fcde
			 ((uintptr_t) dataset & pagesize_m1)
Packit Service 82fcde
			 + sizeof (struct dataset) + req->key_len, MS_ASYNC);
Packit Service 82fcde
		}
Packit Service 82fcde
Packit Service 82fcde
	      (void) cache_add (req->type, key_copy, req->key_len,
Packit Service 82fcde
				&dataset->head, true, db, owner, he == NULL);
Packit Service 82fcde
Packit Service 82fcde
	      pthread_rwlock_unlock (&db->lock);
Packit Service 82fcde
Packit Service 82fcde
	      /* Mark the old entry as obsolete.  */
Packit Service 82fcde
	      if (dh != NULL)
Packit Service 82fcde
		dh->usable = false;
Packit Service 82fcde
	    }
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
      /* Determine the I/O structure.  */
Packit Service 82fcde
      size_t pw_name_len = strlen (pwd->pw_name) + 1;
Packit Service 82fcde
      size_t pw_passwd_len = strlen (pwd->pw_passwd) + 1;
Packit Service 82fcde
      size_t pw_gecos_len = strlen (pwd->pw_gecos) + 1;
Packit Service 82fcde
      size_t pw_dir_len = strlen (pwd->pw_dir) + 1;
Packit Service 82fcde
      size_t pw_shell_len = strlen (pwd->pw_shell) + 1;
Packit Service 82fcde
      char *cp;
Packit Service 82fcde
      const size_t key_len = strlen (key);
Packit Service 82fcde
      const size_t buf_len = 3 * sizeof (pwd->pw_uid) + key_len + 1;
Packit Service 82fcde
      char *buf = alloca (buf_len);
Packit Service 82fcde
      ssize_t n;
Packit Service 82fcde
Packit Service 82fcde
      /* We need this to insert the `byuid' entry.  */
Packit Service 82fcde
      int key_offset;
Packit Service 82fcde
      n = snprintf (buf, buf_len, "%d%c%n%s", pwd->pw_uid, '\0',
Packit Service 82fcde
		    &key_offset, (char *) key) + 1;
Packit Service 82fcde
Packit Service 82fcde
      total = (offsetof (struct dataset, strdata)
Packit Service 82fcde
	       + pw_name_len + pw_passwd_len
Packit Service 82fcde
	       + pw_gecos_len + pw_dir_len + pw_shell_len);
Packit Service 82fcde
Packit Service 82fcde
      /* If we refill the cache, first assume the reconrd did not
Packit Service 82fcde
	 change.  Allocate memory on the cache since it is likely
Packit Service 82fcde
	 discarded anyway.  If it turns out to be necessary to have a
Packit Service 82fcde
	 new record we can still allocate real memory.  */
Packit Service 82fcde
      bool alloca_used = false;
Packit Service 82fcde
      dataset = NULL;
Packit Service 82fcde
Packit Service 82fcde
      if (he == NULL)
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* Prevent an INVALIDATE request from pruning the data between
Packit Service 82fcde
	     the two calls to cache_add.  */
Packit Service 82fcde
	  if (db->propagate)
Packit Service 82fcde
	    pthread_mutex_lock (&db->prune_run_lock);
Packit Service 82fcde
	  dataset = (struct dataset *) mempool_alloc (db, total + n, 1);
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
      if (dataset == NULL)
Packit Service 82fcde
	{
Packit Service 82fcde
	  if (he == NULL && db->propagate)
Packit Service 82fcde
	    pthread_mutex_unlock (&db->prune_run_lock);
Packit Service 82fcde
Packit Service 82fcde
	  /* We cannot permanently add the result in the moment.  But
Packit Service 82fcde
	     we can provide the result as is.  Store the data in some
Packit Service 82fcde
	     temporary memory.  */
Packit Service 82fcde
	  dataset = (struct dataset *) alloca (total + n);
Packit Service 82fcde
Packit Service 82fcde
	  /* We cannot add this record to the permanent database.  */
Packit Service 82fcde
	  alloca_used = true;
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
      timeout = datahead_init_pos (&dataset->head, total + n,
Packit Service 82fcde
				   total - offsetof (struct dataset, resp),
Packit Service 82fcde
				   he == NULL ? 0 : dh->nreloads + 1,
Packit Service 82fcde
				   db->postimeout);
Packit Service 82fcde
Packit Service 82fcde
      dataset->resp.version = NSCD_VERSION;
Packit Service 82fcde
      dataset->resp.found = 1;
Packit Service 82fcde
      dataset->resp.pw_name_len = pw_name_len;
Packit Service 82fcde
      dataset->resp.pw_passwd_len = pw_passwd_len;
Packit Service 82fcde
      dataset->resp.pw_uid = pwd->pw_uid;
Packit Service 82fcde
      dataset->resp.pw_gid = pwd->pw_gid;
Packit Service 82fcde
      dataset->resp.pw_gecos_len = pw_gecos_len;
Packit Service 82fcde
      dataset->resp.pw_dir_len = pw_dir_len;
Packit Service 82fcde
      dataset->resp.pw_shell_len = pw_shell_len;
Packit Service 82fcde
Packit Service 82fcde
      cp = dataset->strdata;
Packit Service 82fcde
Packit Service 82fcde
      /* Copy the strings over into the buffer.  */
Packit Service 82fcde
      cp = mempcpy (cp, pwd->pw_name, pw_name_len);
Packit Service 82fcde
      cp = mempcpy (cp, pwd->pw_passwd, pw_passwd_len);
Packit Service 82fcde
      cp = mempcpy (cp, pwd->pw_gecos, pw_gecos_len);
Packit Service 82fcde
      cp = mempcpy (cp, pwd->pw_dir, pw_dir_len);
Packit Service 82fcde
      cp = mempcpy (cp, pwd->pw_shell, pw_shell_len);
Packit Service 82fcde
Packit Service 82fcde
      /* Finally the stringified UID value.  */
Packit Service 82fcde
      memcpy (cp, buf, n);
Packit Service 82fcde
      char *key_copy = cp + key_offset;
Packit Service 82fcde
      assert (key_copy == (char *) rawmemchr (cp, '\0') + 1);
Packit Service 82fcde
Packit Service 82fcde
      assert (cp == dataset->strdata + total - offsetof (struct dataset,
Packit Service 82fcde
							 strdata));
Packit Service 82fcde
Packit Service 82fcde
      /* Now we can determine whether on refill we have to create a new
Packit Service 82fcde
	 record or not.  */
Packit Service 82fcde
      if (he != NULL)
Packit Service 82fcde
	{
Packit Service 82fcde
	  assert (fd == -1);
Packit Service 82fcde
Packit Service 82fcde
	  if (dataset->head.allocsize == dh->allocsize
Packit Service 82fcde
	      && dataset->head.recsize == dh->recsize
Packit Service 82fcde
	      && memcmp (&dataset->resp, dh->data,
Packit Service 82fcde
			 dh->allocsize - offsetof (struct dataset, resp)) == 0)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      /* The data has not changed.  We will just bump the
Packit Service 82fcde
		 timeout value.  Note that the new record has been
Packit Service 82fcde
		 allocated on the stack and need not be freed.  */
Packit Service 82fcde
	      dh->timeout = dataset->head.timeout;
Packit Service 82fcde
	      ++dh->nreloads;
Packit Service 82fcde
	    }
Packit Service 82fcde
	  else
Packit Service 82fcde
	    {
Packit Service 82fcde
	      /* We have to create a new record.  Just allocate
Packit Service 82fcde
		 appropriate memory and copy it.  */
Packit Service 82fcde
	      struct dataset *newp
Packit Service 82fcde
		= (struct dataset *) mempool_alloc (db, total + n, 1);
Packit Service 82fcde
	      if (newp != NULL)
Packit Service 82fcde
		{
Packit Service 82fcde
		  /* Adjust pointer into the memory block.  */
Packit Service 82fcde
		  cp = (char *) newp + (cp - (char *) dataset);
Packit Service 82fcde
		  key_copy = (char *) newp + (key_copy - (char *) dataset);
Packit Service 82fcde
Packit Service 82fcde
		  dataset = memcpy (newp, dataset, total + n);
Packit Service 82fcde
		  alloca_used = false;
Packit Service 82fcde
		}
Packit Service 82fcde
Packit Service 82fcde
	      /* Mark the old record as obsolete.  */
Packit Service 82fcde
	      dh->usable = false;
Packit Service 82fcde
	    }
Packit Service 82fcde
	}
Packit Service 82fcde
      else
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* We write the dataset before inserting it to the database
Packit Service 82fcde
	     since while inserting this thread might block and so would
Packit Service 82fcde
	     unnecessarily let the receiver wait.  */
Packit Service 82fcde
	  assert (fd != -1);
Packit Service 82fcde
Packit Service 82fcde
	  if (writeall (fd, &dataset->resp, dataset->head.recsize)
Packit Service 82fcde
	      != dataset->head.recsize)
Packit Service 82fcde
	    all_written = false;
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
      /* Add the record to the database.  But only if it has not been
Packit Service 82fcde
	 stored on the stack.  */
Packit Service 82fcde
      if (! alloca_used)
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* If necessary, we also propagate the data to disk.  */
Packit Service 82fcde
	  if (db->persistent)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      // XXX async OK?
Packit Service 82fcde
	      uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
Packit Service 82fcde
	      msync ((void *) pval,
Packit Service 82fcde
		     ((uintptr_t) dataset & pagesize_m1) + total + n,
Packit Service 82fcde
		     MS_ASYNC);
Packit Service 82fcde
	    }
Packit Service 82fcde
Packit Service 82fcde
	  /* NB: in the following code we always must add the entry
Packit Service 82fcde
	     marked with FIRST first.  Otherwise we end up with
Packit Service 82fcde
	     dangling "pointers" in case a latter hash entry cannot be
Packit Service 82fcde
	     added.  */
Packit Service 82fcde
	  bool first = true;
Packit Service 82fcde
Packit Service 82fcde
	  /* If the request was by UID, add that entry first.  */
Packit Service 82fcde
	  if (req->type == GETPWBYUID)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      if (cache_add (GETPWBYUID, cp, key_offset, &dataset->head, true,
Packit Service 82fcde
			     db, owner, he == NULL) < 0)
Packit Service 82fcde
		goto out;
Packit Service 82fcde
Packit Service 82fcde
	      first = false;
Packit Service 82fcde
	    }
Packit Service 82fcde
	  /* If the key is different from the name add a separate entry.  */
Packit Service 82fcde
	  else if (strcmp (key_copy, dataset->strdata) != 0)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      if (cache_add (GETPWBYNAME, key_copy, key_len + 1,
Packit Service 82fcde
			     &dataset->head, true, db, owner, he == NULL) < 0)
Packit Service 82fcde
		goto out;
Packit Service 82fcde
Packit Service 82fcde
	      first = false;
Packit Service 82fcde
	    }
Packit Service 82fcde
Packit Service 82fcde
	  /* We have to add the value for both, byname and byuid.  */
Packit Service 82fcde
	  if ((req->type == GETPWBYNAME || db->propagate)
Packit Service 82fcde
	      && __builtin_expect (cache_add (GETPWBYNAME, dataset->strdata,
Packit Service 82fcde
					      pw_name_len, &dataset->head,
Packit Service 82fcde
					      first, db, owner, he == NULL)
Packit Service 82fcde
				   == 0, 1))
Packit Service 82fcde
	    {
Packit Service 82fcde
	      if (req->type == GETPWBYNAME && db->propagate)
Packit Service 82fcde
		(void) cache_add (GETPWBYUID, cp, key_offset, &dataset->head,
Packit Service 82fcde
				  false, db, owner, false);
Packit Service 82fcde
	    }
Packit Service 82fcde
Packit Service 82fcde
	out:
Packit Service 82fcde
	  pthread_rwlock_unlock (&db->lock);
Packit Service 82fcde
	  if (he == NULL && db->propagate)
Packit Service 82fcde
	    pthread_mutex_unlock (&db->prune_run_lock);
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (__builtin_expect (!all_written, 0) && debug_level > 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      char buf[256];
Packit Service 82fcde
      dbg_log (_("short write in %s: %s"),  __FUNCTION__,
Packit Service 82fcde
	       strerror_r (errno, buf, sizeof (buf)));
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  return timeout;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
union keytype
Packit Service 82fcde
{
Packit Service 82fcde
  void *v;
Packit Service 82fcde
  uid_t u;
Packit Service 82fcde
};
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
static int
Packit Service 82fcde
lookup (int type, union keytype key, struct passwd *resultbufp, char *buffer,
Packit Service 82fcde
	size_t buflen, struct passwd **pwd)
Packit Service 82fcde
{
Packit Service 82fcde
  if (type == GETPWBYNAME)
Packit Service 82fcde
    return __getpwnam_r (key.v, resultbufp, buffer, buflen, pwd);
Packit Service 82fcde
  else
Packit Service 82fcde
    return __getpwuid_r (key.u, resultbufp, buffer, buflen, pwd);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
static time_t
Packit Service 82fcde
addpwbyX (struct database_dyn *db, int fd, request_header *req,
Packit Service 82fcde
	  union keytype key, const char *keystr, uid_t c_uid,
Packit Service 82fcde
	  struct hashentry *he, struct datahead *dh)
Packit Service 82fcde
{
Packit Service 82fcde
  /* Search for the entry matching the key.  Please note that we don't
Packit Service 82fcde
     look again in the table whether the dataset is now available.  We
Packit Service 82fcde
     simply insert it.  It does not matter if it is in there twice.  The
Packit Service 82fcde
     pruning function only will look at the timestamp.  */
Packit Service 82fcde
  struct passwd resultbuf;
Packit Service 82fcde
  struct passwd *pwd;
Packit Service 82fcde
  int errval = 0;
Packit Service 82fcde
  struct scratch_buffer tmpbuf;
Packit Service 82fcde
  scratch_buffer_init (&tmpbuf);
Packit Service 82fcde
Packit Service 82fcde
  if (__glibc_unlikely (debug_level > 0))
Packit Service 82fcde
    {
Packit Service 82fcde
      if (he == NULL)
Packit Service 82fcde
	dbg_log (_("Haven't found \"%s\" in user database cache!"), keystr);
Packit Service 82fcde
      else
Packit Service 82fcde
	dbg_log (_("Reloading \"%s\" in user database cache!"), keystr);
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  while (lookup (req->type, key, &resultbuf,
Packit Service 82fcde
		 tmpbuf.data, tmpbuf.length, &pwd) != 0
Packit Service 82fcde
	 && (errval = errno) == ERANGE)
Packit Service 82fcde
    if (!scratch_buffer_grow (&tmpbuf))
Packit Service 82fcde
      {
Packit Service 82fcde
	/* We ran out of memory.  We cannot do anything but sending a
Packit Service 82fcde
	   negative response.  In reality this should never
Packit Service 82fcde
	   happen.  */
Packit Service 82fcde
	pwd = NULL;
Packit Service 82fcde
	/* We set the error to indicate this is (possibly) a temporary
Packit Service 82fcde
	   error and that it does not mean the entry is not available
Packit Service 82fcde
	   at all.  */
Packit Service 82fcde
	errval = EAGAIN;
Packit Service 82fcde
	break;
Packit Service 82fcde
      }
Packit Service 82fcde
Packit Service 82fcde
  /* Add the entry to the cache.  */
Packit Service 82fcde
  time_t timeout = cache_addpw (db, fd, req, keystr, pwd, c_uid, he, dh,
Packit Service 82fcde
				errval);
Packit Service 82fcde
  scratch_buffer_free (&tmpbuf);
Packit Service 82fcde
  return timeout;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
addpwbyname (struct database_dyn *db, int fd, request_header *req,
Packit Service 82fcde
	     void *key, uid_t c_uid)
Packit Service 82fcde
{
Packit Service 82fcde
  union keytype u = { .v = key };
Packit Service 82fcde
Packit Service 82fcde
  addpwbyX (db, fd, req, u, key, c_uid, NULL, NULL);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
time_t
Packit Service 82fcde
readdpwbyname (struct database_dyn *db, struct hashentry *he,
Packit Service 82fcde
	       struct datahead *dh)
Packit Service 82fcde
{
Packit Service 82fcde
  request_header req =
Packit Service 82fcde
    {
Packit Service 82fcde
      .type = GETPWBYNAME,
Packit Service 82fcde
      .key_len = he->len
Packit Service 82fcde
    };
Packit Service 82fcde
  union keytype u = { .v = db->data + he->key };
Packit Service 82fcde
Packit Service 82fcde
  return addpwbyX (db, -1, &req, u, db->data + he->key, he->owner, he, dh);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
addpwbyuid (struct database_dyn *db, int fd, request_header *req,
Packit Service 82fcde
	    void *key, uid_t c_uid)
Packit Service 82fcde
{
Packit Service 82fcde
  char *ep;
Packit Service 82fcde
  uid_t uid = strtoul ((char *) key, &ep, 10);
Packit Service 82fcde
Packit Service 82fcde
  if (*(char *) key == '\0' || *ep != '\0')  /* invalid numeric uid */
Packit Service 82fcde
    {
Packit Service 82fcde
      if (debug_level > 0)
Packit Service 82fcde
	dbg_log (_("Invalid numeric uid \"%s\"!"), (char *) key);
Packit Service 82fcde
Packit Service 82fcde
      errno = EINVAL;
Packit Service 82fcde
      return;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  union keytype u = { .u = uid };
Packit Service 82fcde
Packit Service 82fcde
  addpwbyX (db, fd, req, u, key, c_uid, NULL, NULL);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
time_t
Packit Service 82fcde
readdpwbyuid (struct database_dyn *db, struct hashentry *he,
Packit Service 82fcde
	      struct datahead *dh)
Packit Service 82fcde
{
Packit Service 82fcde
  char *ep;
Packit Service 82fcde
  uid_t uid = strtoul (db->data + he->key, &ep, 10);
Packit Service 82fcde
Packit Service 82fcde
  /* Since the key has been added before it must be OK.  */
Packit Service 82fcde
  assert (*(db->data + he->key) != '\0' && *ep == '\0');
Packit Service 82fcde
Packit Service 82fcde
  request_header req =
Packit Service 82fcde
    {
Packit Service 82fcde
      .type = GETPWBYUID,
Packit Service 82fcde
      .key_len = he->len
Packit Service 82fcde
    };
Packit Service 82fcde
  union keytype u = { .u = uid };
Packit Service 82fcde
Packit Service 82fcde
  return addpwbyX (db, -1, &req, u, db->data + he->key, he->owner, he, dh);
Packit Service 82fcde
}