YP-server with NSS backend: winbind for YP domains

Peter Åstrand peter at cendio.se
Thu Aug 1 07:30:05 GMT 2002


I've been working on one problem with winbind
(http://us1.samba.org/samba/docs/man/winbindd.8.html, if you wonder): The
user and group ids will only be valid for the local machine. I want to
have an entire cluster of Linux machines join a NT domain, and then be
able to run NFSv2/v3 between these machines. This is not possible today.

My solution to this problem is an YP-server which uses Name Service Switch
(NSS) as backend. So, passwd.byname, passwd,byuid, group.byname and
group.bygid are not read from gdbm files, but rather constructed via
getpwent(), getgrent() etc. With this, you only need one winbind rid <->
uid translation database for all machines. Users and groups are then
"exported" by the YP-server, which uses libnss_winbind via NSS.

Other machines just use ypbind as usual. For authentication, though, these
will still need to run winbind. (Maybe it makes sense to add some kind of
command line switch to winbindd, to instruct it to only serve
authentication requests via PAM, and never try to create a local
translation database. I suppose the local db won't hurt though, as long 
as you don't enter "winbind" keywords into nsswitch.conf. One problem is 
that you still need to specify uid/gid ranges in smb.conf.)

My patch to ypserver can also be used for other purposes, like 
re-exporting NIS-domains. 

Thorsten, it would be great if my patch or similar could be included in 
future ypserv releases. Any chance at all for this to happen? The patch 
can probably be made a bit less intrusive than it is today. 

Patch to ypserv-2.4 follows. 

diff -urN -X diffexclude ypserv-2.4/etc/ypserv.conf ypserv/etc/ypserv.conf
--- ypserv-2.4/etc/ypserv.conf	Sun Feb 18 10:19:09 2001
+++ ypserv/etc/ypserv.conf	Mon Jul 29 12:56:37 2002
@@ -19,6 +19,9 @@
 # xfr requests are only allowed from ports < 1024
 xfr_check_port: yes
 
+# Serv passwd and group from NSS instead of dbm
+passwd_group_from_nss: no
+
 # The following, when uncommented,  will give you shadow like passwords.
 # Note that it will not work if you have slave NIS servers in your
 # network that do not run the same server as you.
diff -urN -X diffexclude ypserv-2.4/etc/ypserv.conf.5 ypserv/etc/ypserv.conf.5
--- ypserv-2.4/etc/ypserv.conf.5	Mon May 27 08:21:09 2002
+++ ypserv/etc/ypserv.conf.5	Mon Jul 29 12:56:37 2002
@@ -31,6 +31,10 @@
 With this option enabled, the NIS master server have to run on a
 port < 1024. The default is "yes" (enabled).
 .TP
+.B passwd_group_from_nss
+With this option enabled, the passwd and group will be fetched from
+NSS (Name Service Switch) instead from database. 
+.TP
 .B trusted_master
 This option expects a different argument than the other above. The argument
 is the FQDN of the master host. If this option is set on a slave server,
diff -urN -X diffexclude ypserv-2.4/lib/Makefile.am ypserv/lib/Makefile.am
--- ypserv-2.4/lib/Makefile.am	Mon May 27 08:45:27 2002
+++ ypserv/lib/Makefile.am	Mon Jul 29 18:43:52 2002
@@ -17,7 +17,7 @@
 INCLUDES = -I$(top_srcdir) -I$(top_builddir) -I$(srcdir)
 
 libyp_a_SOURCES = log_msg.c ypserv_conf.c ypxfrd_xdr.c \
-		ypproc_match_2.c securenets.c access.c yp_db.c
+		ypproc_match_2.c securenets.c access.c yp_db.c ypdb_nss.c
 
 CLEANFILES = *~
 
diff -urN -X diffexclude ypserv-2.4/lib/yp_db.c ypserv/lib/yp_db.c
--- ypserv-2.4/lib/yp_db.c	Sun Apr  8 22:39:23 2001
+++ ypserv/lib/yp_db.c	Thu Aug  1 11:44:06 2002
@@ -31,9 +31,11 @@
 #include "log_msg.h"
 #include "yp_db.h"
 #include "yp.h"
+#include "ypserv_conf.h"
 
 #if defined(HAVE_LIBGDBM)
 #include <gdbm.h>
+#include "ypdb_nss.h"
 #elif defined(HAVE_NDBM)
 #include <ndbm.h>
 #endif
@@ -42,7 +44,7 @@
 
 /* Open a GDBM database */
 static GDBM_FILE
-_db_open (const char *domain, const char *map)
+_db_open_gdbm (const char *domain, const char *map)
 {
   GDBM_FILE dbp;
   char buf[MAXPATHLEN + 2];
@@ -71,12 +73,77 @@
   return dbp;
 }
 
+
+static YPDB_NSS *
+_db_open (const char *domain, const char *map)
+{
+  YPDB_NSS *ypdb_nss;
+
+  ypdb_nss = malloc (sizeof (YPDB_NSS));
+
+  /* Initialize variables */
+  ypdb_nss->mapname = strdup (map);
+  ypdb_nss->db = NULL;
+  ypdb_nss->last_ent = NULL;
+  ypdb_nss->nextdb = NULL;
+  ypdb_nss->firstname = NULL;
+  ypdb_nss->passwd_from_nss = 0;
+  ypdb_nss->group_from_nss = 0;
+  ypdb_nss->byid = 0;
+
+  if (passwd_group_from_nss)
+    {
+      if (!strcmp (map, "passwd") || !strcmp (map, "passwd.byname"))
+	{
+	  ypdb_nss->passwd_from_nss = 1;
+	}
+      else if (!strcmp (map, "passwd.byuid"))
+	{
+	  ypdb_nss->passwd_from_nss = 1;
+	  ypdb_nss->byid = 1;
+	}
+      else if (!strcmp (map, "group") || !strcmp (map, "group.byname"))
+	{
+	  ypdb_nss->group_from_nss = 1;
+	}
+      else if (!strcmp (map, "group.bygid"))
+	{
+	  ypdb_nss->group_from_nss = 1;
+	  ypdb_nss->byid = 1;
+	}
+    }
+
+  if (!(ypdb_nss->passwd_from_nss || ypdb_nss->group_from_nss))
+    {
+      ypdb_nss->db = _db_open_gdbm (domain, map);
+      if (ypdb_nss->db == NULL)
+	return NULL;
+    }
+
+  return ypdb_nss;
+}
+
+
 static inline int
-_db_close (GDBM_FILE file)
+_db_close (YPDB_NSS* dbf)
 {
-  gdbm_close (file);
-  return 0;
+    if (!(dbf->passwd_from_nss || dbf->group_from_nss)) {
+	/* Normal local db */
+	gdbm_close(dbf->db);
+	dbf->db = NULL;
+	return 0;
+    } else {
+	if (dbf->nextdb != NULL) {
+	    gdbm_close (dbf->nextdb);
+	    dbf->nextdb = NULL;
+	    return 0;
+	}
+    }
+    free(dbf->mapname);
+    free(dbf->last_ent);
+    free(dbf->firstname);
 }
+
 
 #elif defined(HAVE_NDBM)
 
diff -urN -X diffexclude ypserv-2.4/lib/yp_db.h ypserv/lib/yp_db.h
--- ypserv-2.4/lib/yp_db.h	Sun Apr  8 22:39:23 2001
+++ ypserv/lib/yp_db.h	Mon Jul 29 18:43:37 2002
@@ -10,14 +10,15 @@
 
 #if defined(HAVE_LIBGDBM)
 #include <gdbm.h>
+#include "ypdb_nss.h"
+
+#define DB_FILE YPDB_NSS*  
+#define ypdb_fetch(a,b)  ypdb_nss_fetch(a,b)
+#define ypdb_exists(a,b)  ypdb_nss_exists(a,b)
+#define ypdb_free(a) free(a) 
+#define ypdb_firstkey(a) ypdb_nss_firstkey(a)
+#define ypdb_nextkey(a,b) ypdb_nss_nextkey(a,b)
 
-#define DB_FILE GDBM_FILE
-#define ypdb_fetch(a,b)  gdbm_fetch(a,b)
-#define ypdb_exists(a,b)  gdbm_exists(a,b)
-#define ypdb_free(a) free(a)
-#define ypdb_firstkey(a) gdbm_firstkey(a)
-#define ypdb_nextkey(a,b) gdbm_nextkey(a,b)
-#define ypdb_fetch(a,b) gdbm_fetch(a,b)
 
 #elif defined(HAVE_NDBM)
 
diff -urN -X diffexclude ypserv-2.4/lib/ypdb_nss.c ypserv/lib/ypdb_nss.c
--- ypserv-2.4/lib/ypdb_nss.c	Thu Jan  1 01:00:00 1970
+++ ypserv/lib/ypdb_nss.c	Thu Aug  1 15:52:54 2002
@@ -0,0 +1,669 @@
+#include <gdbm.h>
+#include <stdio.h>
+#include "ypdb_nss.h"
+#include "log_msg.h"
+#include <malloc.h>
+#include <string.h>
+#include <pwd.h>
+
+#ifndef __USE_GNU
+#define __USE_GNU
+#endif
+#include <grp.h>
+
+#include <sys/types.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+/* 1024 should be enough for anybody... */
+#define MAX_PW_GR_LINE 1024
+
+#define DB_FILENAME_PREFIX "ypdb_nss_nextdb."
+
+static void make_nextdb (YPDB_NSS * dbf);
+
+
+/* Get sysconf value. Default to 1024 on error. */
+static long int
+get_sysconf_value (int name)
+{
+  long int result;
+  result = sysconf (name);
+  if (result < 1)
+    result = 1024;
+  return result;
+}
+
+
+/*
+ * The purpose of the _r_wrapper functions are:
+ * 1) Get rid of the stupid **RESULT argument
+ * 2) Fixing wrong return values
+ * 3) Print error messages upon failure
+ */
+
+static int
+getpwent_r_wrapper (struct passwd *RESULT_BUF, char *BUFFER, int BUFLEN)
+{
+  struct passwd *resultp;
+  int result;
+
+  result = getpwent_r (RESULT_BUF, BUFFER, BUFLEN, &resultp);
+
+  /* Some implementations, like winbind, returns zero,
+     even on errors. */
+  if (resultp == NULL)
+    result = ENOENT;
+
+  switch (result)
+    {
+    case 0:
+    case ENOENT:
+      break;
+    default:
+      perror ("getpwent_r");
+      break;
+    }
+
+  return result;
+}
+
+
+static int
+getpwnam_r_wrapper (const char *NAME, struct passwd *RESULT_BUF,
+		    char *BUFFER, size_t BUFLEN)
+{
+  struct passwd *resultp;
+  int result;
+
+  result = getpwnam_r (NAME, RESULT_BUF, BUFFER, BUFLEN, &resultp);
+
+  /* Some implementations, like winbind, returns zero,
+     even on errors. */
+  if (resultp == NULL)
+    result = ENOENT;
+
+  switch (result)
+    {
+    case 0:
+    case ENOENT:
+      break;
+    default:
+      perror ("getpwnam_r");
+      break;
+    }
+
+  return result;
+}
+
+
+static int
+getpwuid_r_wrapper (uid_t UID, struct passwd *RESULT_BUF,
+		    char *BUFFER, size_t BUFLEN)
+{
+  struct passwd *resultp;
+  int result;
+
+  result = getpwuid_r (UID, RESULT_BUF, BUFFER, BUFLEN, &resultp);
+
+  /* Some implementations, like winbind, returns zero,
+     even on errors. */
+  if (resultp == NULL)
+    result = ENOENT;
+
+  switch (result)
+    {
+    case 0:
+    case ENOENT:
+      break;
+    default:
+      perror ("getpwuid_r");
+      break;
+    }
+
+  return result;
+}
+
+
+static int
+getgrent_r_wrapper (struct group *RESULT_BUF, char *BUFFER, int BUFLEN)
+{
+  struct group *resultp;
+  int result;
+
+  result = getgrent_r (RESULT_BUF, BUFFER, BUFLEN, &resultp);
+
+  /* Some implementations, like winbind, returns zero,
+     even on errors. */
+  if (resultp == NULL)
+    result = ENOENT;
+
+  switch (result)
+    {
+    case 0:
+    case ENOENT:
+      break;
+    default:
+      perror ("getgrent_r");
+      break;
+    }
+
+  return result;
+}
+
+
+static int
+getgrnam_r_wrapper (const char *NAME, struct group *RESULT_BUF,
+		    char *BUFFER, size_t BUFLEN)
+{
+  struct group *resultp;
+  int result;
+
+  result = getgrnam_r (NAME, RESULT_BUF, BUFFER, BUFLEN, &resultp);
+
+  /* Some implementations, like winbind, returns zero,
+     even on errors. */
+  if (resultp == NULL)
+    result = ENOENT;
+
+  switch (result)
+    {
+    case 0:
+    case ENOENT:
+      break;
+    case EAGAIN:
+      /* Some versions of glibc incorrectly reports EAGAIN instead of
+         ENOENT */
+      result = ENOENT;
+      break;
+    default:
+      perror ("getgrnam_r");
+      break;
+    }
+
+  return result;
+}
+
+
+static int
+getgrgid_r_wrapper (gid_t GID, struct group *RESULT_BUF,
+		    char *BUFFER, size_t BUFLEN)
+{
+  struct group *resultp;
+  int result;
+
+  result = getgrgid_r (GID, RESULT_BUF, BUFFER, BUFLEN, &resultp);
+
+  /* Some implementations, like winbind, returns zero,
+     even on errors. */
+  if (resultp == NULL)
+    result = ENOENT;
+
+  switch (result)
+    {
+    case 0:
+    case ENOENT:
+      break;
+    case EAGAIN:
+      /* Some versions of glibc incorrectly reports EAGAIN instead of
+         ENOENT */
+      result = ENOENT;
+      break;
+    default:
+      perror ("getgrnam_r");
+      break;
+    }
+
+  return result;
+}
+
+
+/* Note: caller must free returned pointer */
+char *
+datum2string (datum d)
+{
+  char *str;
+
+  str = malloc (d.dsize + 1);
+  assert (str != NULL);
+  strncpy (str, d.dptr, d.dsize);
+  str[d.dsize] = '\0';
+
+  return str;
+}
+
+
+/* Note: caller must free d.dptr */
+datum
+string2datum (char *str)
+{
+  datum d;
+
+  d.dsize = strlen (str);
+  d.dptr = malloc (d.dsize);
+  assert (d.dptr != NULL);
+  strncpy (d.dptr, str, d.dsize);
+
+  return d;
+}
+
+
+static datum
+ypdb_nss_fetch_passwd (YPDB_NSS * dbf, datum key)
+{
+  datum d;
+  char *keystring;
+  struct passwd ent;
+  char *buffer;
+  long getpw_r_size_max;
+  char *pwline;
+  int result;
+
+  keystring = datum2string (key);
+  d.dptr = NULL;
+
+  getpw_r_size_max = get_sysconf_value (_SC_GETPW_R_SIZE_MAX);
+
+  buffer = malloc (getpw_r_size_max);
+  assert (buffer != NULL);
+
+  if (dbf->byid)
+    {
+      /* By uid */
+      uid_t uid;
+      char *endptr;
+      uid = strtol (keystring, &endptr, 10);
+      /* Make sure the entire string was a valid digit */
+      if (!strlen (keystring) || strlen (endptr))
+	/* error. Return d with d.dptr = NULL */
+	return d;
+
+      result = getpwuid_r_wrapper (uid, &ent, buffer, getpw_r_size_max);
+    }
+  else
+    {
+      /* By name */
+      result = getpwnam_r_wrapper (keystring, &ent, buffer, getpw_r_size_max);
+    }
+
+  free (keystring);
+  if (result)
+    {
+      /* error. Return d with d.dptr = NULL */
+      return d;
+    }
+
+  pwline = malloc (MAX_PW_GR_LINE);
+  assert (pwline != NULL);
+  snprintf (pwline, MAX_PW_GR_LINE, "%s:%s:%d:%d:%s:%s:%s",
+	    ent.pw_name,
+	    ent.pw_passwd,
+	    ent.pw_uid, ent.pw_gid, ent.pw_gecos, ent.pw_dir, ent.pw_shell);
+
+  free (buffer);
+
+  d.dptr = pwline;
+  d.dsize = strlen (pwline);
+
+  /* Called must free d.dptr */
+  return d;
+}
+
+
+static datum
+ypdb_nss_fetch_group (YPDB_NSS * dbf, datum key)
+{
+  datum d;
+  char *keystring;
+  struct group ent;
+  char *buffer;
+  long getgr_r_size_max;
+  char *grline;
+  char *member;
+  int first_member = 1;
+  char *tmpstr;
+  int result;
+
+  keystring = datum2string (key);
+  d.dptr = NULL;
+
+  getgr_r_size_max = get_sysconf_value (_SC_GETGR_R_SIZE_MAX);
+
+  buffer = malloc (getgr_r_size_max);
+  assert (buffer != NULL);
+
+  if (dbf->byid)
+    {
+      /* By gid */
+      gid_t gid;
+      char *endptr;
+      gid = strtol (keystring, &endptr, 10);
+      /* Make sure the entire string was a valid digit */
+      if (!strlen (keystring) || strlen (endptr))
+	/* error. Return d with d.dptr = NULL */
+	return d;
+
+      result = getgrgid_r_wrapper (gid, &ent, buffer, getgr_r_size_max);
+    }
+  else
+    {
+      /* By name */
+      result = getgrnam_r_wrapper (keystring, &ent, buffer, getgr_r_size_max);
+    }
+
+  free (keystring);
+  if (result)
+    {
+      /* error. Return d with d.dptr = NULL */
+      return d;
+    }
+
+  grline = malloc (MAX_PW_GR_LINE);
+  assert (grline != NULL);
+  snprintf (grline, MAX_PW_GR_LINE, "%s:%s:%d:",
+	    ent.gr_name, ent.gr_passwd, ent.gr_gid);
+
+  /* Add groups */
+  while (*ent.gr_mem != NULL)
+    {
+      member = *ent.gr_mem;
+      ent.gr_mem++;
+      tmpstr = strdup (grline);
+      assert (tmpstr != NULL);
+      if (first_member)
+	{
+	  /* Do not add comma */
+	  snprintf (grline, MAX_PW_GR_LINE, "%s%s", tmpstr, member);
+	  first_member = 0;
+	}
+      else
+	{
+	  snprintf (grline, MAX_PW_GR_LINE, "%s,%s", tmpstr, member);
+
+	}
+      free (tmpstr);
+    }
+
+  free (buffer);
+
+  d.dptr = grline;
+  d.dsize = strlen (grline);
+
+  /* Called must free d.dptr */
+  return d;
+}
+
+
+datum
+ypdb_nss_fetch (YPDB_NSS * dbf, datum key)
+{
+  if (debug_flag)
+    {
+      char *keystr;
+      keystr = datum2string (key);
+      log_msg ("ypdb_nss_fetch() called for key %s", keystr);
+      free (keystr);
+    }
+
+  if (dbf->passwd_from_nss)
+    {
+      return ypdb_nss_fetch_passwd (dbf, key);
+    }
+  else if (dbf->group_from_nss)
+    {
+      return ypdb_nss_fetch_group (dbf, key);
+    }
+  else
+    {
+      /* Normal local db */
+      return gdbm_fetch (dbf->db, key);
+    }
+}
+
+
+int
+ypdb_nss_exists (YPDB_NSS * dbf, datum key)
+{
+  if (debug_flag)
+    {
+      char *keystr;
+      keystr = datum2string (key);
+      log_msg ("ypdb_nss_exists() called for key %s", keystr);
+      free (keystr);
+    }
+
+  if (dbf->passwd_from_nss || dbf->group_from_nss)
+    {
+      datum d;
+      d = ypdb_nss_fetch (dbf, key);
+      return (d.dptr != NULL);
+    }
+  else
+    {
+      /* Normal local db */
+      return gdbm_exists (dbf->db, key);
+    }
+}
+
+
+datum
+ypdb_nss_firstkey (YPDB_NSS * dbf)
+{
+  if (debug_flag)
+    log_msg ("ypdb_nss_firstkey() called");
+
+  if (dbf->passwd_from_nss || dbf->group_from_nss)
+    {
+      datum d;
+
+      log_msg ("Making nextdb...");
+      make_nextdb (dbf);
+      log_msg ("done.");
+
+      /* Called must free d.dptr */
+      d.dptr = strdup (dbf->firstname);
+      assert (d.dptr != NULL);
+      d.dsize = strlen (d.dptr);
+      return d;
+    }
+  else
+    {
+      return gdbm_firstkey (dbf->db);
+    }
+}
+
+
+datum
+ypdb_nss_nextkey (YPDB_NSS * dbf, datum key)
+{
+  if (debug_flag)
+    {
+      char *keystr;
+      keystr = datum2string (key);
+      log_msg ("ypdb_nss_nextkey() called for key %s", keystr);
+      free (keystr);
+    }
+
+  if (dbf->passwd_from_nss || dbf->group_from_nss)
+    {
+      return gdbm_fetch (dbf->nextdb, key);
+    }
+  else
+    {
+      return gdbm_nextkey (dbf->db, key);
+    }
+
+}
+
+
+static void
+make_nextdb_passwd (YPDB_NSS * dbf)
+{
+  struct passwd ent;
+  struct passwd last_ent;
+  /* Buffer from which, for example, pw_name, are allocated from */
+  char *buffer;
+  char *last_buffer;
+  datum key, content;
+  long getpw_r_size_max;
+
+  getpw_r_size_max = get_sysconf_value (_SC_GETPW_R_SIZE_MAX);
+
+  setpwent ();
+
+  /* Iterate over all users and fill db */
+  last_ent.pw_name = NULL;
+  last_buffer = NULL;
+  dbf->firstname = NULL;
+  while (1)
+    {
+      buffer = malloc (getpw_r_size_max);
+      assert (buffer != NULL);
+      if (getpwent_r_wrapper (&ent, buffer, getpw_r_size_max) != 0)
+	{
+	  /* Error or end of enumeration */
+	  free (buffer);
+	  break;
+	}
+
+      if (dbf->firstname == NULL)
+	{
+	  /* First loop */
+	  dbf->firstname = strdup (ent.pw_name);
+	  assert (dbf->firstname != NULL);
+	}
+
+      if (last_ent.pw_name != NULL)
+	{
+	  /* printf("Creating mapping %s -> %s\n", last_ent.pw_name, ent.pw_name); */
+	  key = string2datum (last_ent.pw_name);
+	  content = string2datum (ent.pw_name);
+	  if (gdbm_store (dbf->nextdb, key, content, GDBM_REPLACE) < 0)
+	    {
+	      perror ("gdbm_store");
+	      free (key.dptr);
+	      free (content.dptr);
+	      exit (1);
+	    }
+	  free (key.dptr);
+	  free (content.dptr);
+	}
+
+      if (last_buffer != NULL)
+	{
+	  free (last_buffer);
+	  last_buffer = NULL;
+	}
+
+      last_ent = ent;
+      last_buffer = buffer;
+    }
+
+  endpwent ();
+
+  free (last_buffer);
+}
+
+
+static void
+make_nextdb_group (YPDB_NSS * dbf)
+{
+  struct group ent;
+  struct group last_ent;
+  /* Buffer from which, for example, gr_name, are allocated from */
+  char *buffer;
+  char *last_buffer;
+  datum key, content;
+  long getgr_r_size_max;
+
+  getgr_r_size_max = get_sysconf_value (_SC_GETGR_R_SIZE_MAX);
+
+  setgrent ();
+
+  /* Iterate over all users and fill db */
+  last_ent.gr_name = NULL;
+  last_buffer = NULL;
+  dbf->firstname = NULL;
+  while (1)
+    {
+      buffer = malloc (getgr_r_size_max);
+      assert (buffer != NULL);
+      if (getgrent_r_wrapper (&ent, buffer, getgr_r_size_max) != 0)
+	{
+	  /* Error or end of enumeration */
+	  free (buffer);
+	  break;
+	}
+
+      if (dbf->firstname == NULL)
+	{
+	  /* First loop */
+	  dbf->firstname = strdup (ent.gr_name);
+	  assert (dbf->firstname != NULL);
+	}
+
+      if (last_ent.gr_name != NULL)
+	{
+	  /* printf("Creating mapping %s -> %s\n", last_ent.gr_name, ent.gr_name); */
+	  key = string2datum (last_ent.gr_name);
+	  content = string2datum (ent.gr_name);
+	  if (gdbm_store (dbf->nextdb, key, content, GDBM_REPLACE) < 0)
+	    {
+	      perror ("gdbm_store");
+	      free (key.dptr);
+	      free (content.dptr);
+	      exit (1);
+	    }
+	  free (key.dptr);
+	  free (content.dptr);
+	}
+
+      if (last_buffer != NULL)
+	{
+	  free (last_buffer);
+	  last_buffer = NULL;
+	}
+
+      last_ent = ent;
+      last_buffer = buffer;
+    }
+
+  endgrent ();
+
+  free (last_buffer);
+}
+
+
+static void
+make_nextdb (YPDB_NSS * dbf)
+{
+  char *filename;
+
+  filename = malloc (sizeof (DB_FILENAME_PREFIX) + strlen (dbf->mapname) + 1);
+  assert (filename != NULL);
+  strcpy (filename, DB_FILENAME_PREFIX);
+  strcat (filename, dbf->mapname);
+
+  /* Open temporary database */
+  if (dbf->nextdb != NULL)
+    {
+      gdbm_close (dbf->nextdb);
+    }
+
+  dbf->nextdb = gdbm_open (filename, 0, GDBM_NEWDB, 0644, NULL);
+  free (filename);
+  if (dbf->nextdb == NULL)
+    {
+      perror ("gdbm_open");
+      exit (1);
+    }
+
+  if (dbf->passwd_from_nss)
+    make_nextdb_passwd (dbf);
+  else if (dbf->group_from_nss)
+    make_nextdb_group (dbf);
+  else
+    assert (0);
+}
diff -urN -X diffexclude ypserv-2.4/lib/ypdb_nss.h ypserv/lib/ypdb_nss.h
--- ypserv-2.4/lib/ypdb_nss.h	Thu Jan  1 01:00:00 1970
+++ ypserv/lib/ypdb_nss.h	Thu Aug  1 11:39:06 2002
@@ -0,0 +1,27 @@
+#ifndef __YPDB_NSS_H__
+#define __YPDB_NSS_H__
+
+#include <sys/types.h>
+
+
+struct _YPDB_NSS
+{
+  char *mapname;
+  GDBM_FILE db;
+  struct passwd *last_ent;
+  GDBM_FILE nextdb;
+  char *firstname;
+  int passwd_from_nss;
+  int group_from_nss;
+  int byid;
+};
+
+typedef struct _YPDB_NSS YPDB_NSS;
+
+datum ypdb_nss_fetch (YPDB_NSS * dbf, datum key);
+int ypdb_nss_exists (YPDB_NSS * dbf, datum key);
+datum ypdb_nss_firstkey (YPDB_NSS * dbf);
+datum ypdb_nss_nextkey (YPDB_NSS * dbf, datum key);
+
+
+#endif /* __YPDB_NSS_H__ */
diff -urN -X diffexclude ypserv-2.4/lib/ypserv_conf.c ypserv/lib/ypserv_conf.c
--- ypserv-2.4/lib/ypserv_conf.c	Mon Aug  6 20:51:17 2001
+++ ypserv/lib/ypserv_conf.c	Mon Jul 29 12:57:21 2002
@@ -35,6 +35,7 @@
 int dns_flag = 0;
 int cached_filehandles = 30;
 int xfr_check_port = 0;
+int passwd_group_from_nss = 0;
 char *trusted_master = NULL;
 
 static int
@@ -381,6 +382,51 @@
 
 	    if (debug_flag)
 	      log_msg ("ypserv.conf: xfr_check_port: %d", xfr_check_port);
+	    break;
+	  }
+	case 'p':
+	    {			/* passwd_group_from_nss */
+	    size_t i, j;
+
+	    fgets (buf1, sizeof (buf1) - 1, in);
+	    i = 0;
+	    while (c != ':' && i <= strlen (buf1))
+	      {
+		if ((c == ' ') || (c == '\t'))
+		  break;
+		buf2[i] = c;
+		buf2[i + 1] = '\0';
+		c = buf1[i];
+		i++;
+	      }
+
+	    while ((buf1[i - 1] != ':') && (i <= strlen (buf1)))
+	      i++;
+
+	    if ((buf1[i - 1] == ':') && (strcmp (buf2, "passwd_group_from_nss") == 0))
+	      {
+		while (((buf1[i] == ' ') || (buf1[i] == '\t')) &&
+		       (i <= strlen (buf1)))
+		  i++;
+		j = 0;
+		while ((buf1[i] != '\0') && (buf1[i] != '\n'))
+		  buf3[j++] = buf1[i++];
+		buf3[j] = 0;
+
+		sscanf (buf3, "%s", buf2);
+		if (strcmp (buf2, "yes") == 0)
+		  passwd_group_from_nss = 1;
+		else if (strcmp (buf2, "no") == 0)
+		  passwd_group_from_nss = 0;
+		else
+		  log_msg ("Unknown passwd_group_from_nss option in line %d: => Ignore line",
+			  line);
+	      }
+	    else
+	      log_msg ("Parse error in line %d: => Ignore line", line);
+
+	    if (debug_flag)
+	      log_msg ("ypserv.conf: passwd_group_from_nss: %d", passwd_group_from_nss);
 	    break;
 	  }
 #ifdef __GNUC__
diff -urN -X diffexclude ypserv-2.4/lib/ypserv_conf.h ypserv/lib/ypserv_conf.h
--- ypserv-2.4/lib/ypserv_conf.h	Sun Feb 18 10:19:09 2001
+++ ypserv/lib/ypserv_conf.h	Mon Jul 29 18:43:37 2002
@@ -35,6 +35,7 @@
 extern int dns_flag;
 extern int cached_filehandles;
 extern int xfr_check_port;
+extern int passwd_group_from_nss;
 extern char *trusted_master;
 
 extern void load_config(void);
diff -urN -X diffexclude ypserv-2.4/ypserv/server.c ypserv/ypserv/server.c
--- ypserv-2.4/ypserv/server.c	Mon Apr 29 09:55:21 2002
+++ ypserv/ypserv/server.c	Thu Aug  1 14:55:56 2002
@@ -284,6 +284,11 @@
       if (dkey.dptr != NULL)
 	{
 	  datum dval = ypdb_fetch (dbp, dkey);
+	  if (dval.dptr == NULL) {
+	    result->stat = YP_YPERR;
+	    return TRUE;
+	  }
+
 	  result->stat = YP_TRUE;
 
 	  result->key.keydat_len = dkey.dsize;
@@ -387,6 +392,10 @@
       else
 	{
 	  datum dval = ypdb_fetch (dbp, dkey);
+	  if (dval.dptr == NULL) {
+	    result->stat = YP_YPERR;
+	    return TRUE;
+	  }
 
 	  result->stat = YP_TRUE;
 	  result->key.keydat_len = dkey.dsize;
@@ -499,6 +508,10 @@
       if(ypdb_exists (dbp, key))
         {
           datum val = ypdb_fetch (dbp, key);
+	  if (val.dptr == NULL) {
+	    result->xfrstat = YP_YPERR;
+	    return TRUE;
+	  }
 
           if ((size_t)val.dsize != strlen (argp->map_parms.peer) ||
               strncmp (val.dptr, argp->map_parms.peer, val.dsize) != 0)
@@ -691,6 +704,10 @@
     {
       ((ypall_data_t) data)->dval =
 	ypdb_fetch (((ypall_data_t) data)->dbm, ((ypall_data_t) data)->dkey);
+      if (((ypall_data_t) data)->dval.dptr == NULL) {
+	val->stat = YP_YPERR;
+	return val->stat;
+      }
 
       val->stat = YP_TRUE;
 
@@ -780,6 +797,10 @@
       if (data->dkey.dptr != NULL)
 	{
 	  data->dval = ypdb_fetch (data->dbm, data->dkey);
+	  if (data->dval.dptr == NULL) {
+	    result->ypresp_all_u.val.stat = YP_YPERR;
+	    return TRUE;
+	  }
 
 	  result->ypresp_all_u.val.stat = YP_TRUE;
 


-- 
Peter Åstrand                Telephone: +46-13-21 46 00
Cendio Systems               E-mail: peter at cendio.se
Teknikringen 3
583 30 Linköping
Sweden





More information about the samba-technical mailing list