tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

nsdispatch, nss-pam-ldapd, __nss_compat_xxx() functions



I'm currently porting nss-pam-ldapd to NetBSD and need some advice.

The nss-pam-ldapd clients have originally been designed for glibc and then 
extended to support Solaris and FreeBSD NSS via compatibility shims. For 
FreeBSD, this is made easier by __nss_compat_xxx() functions in their libc 
(lib/libc/net/nss_compat.c) emulating the FreeBSD NSS interface on top of 
glibc's. I haven't looked at PAM yet.

I do have a working (at least for NSS and as far as I can currently tell) 
package, but I would like someone to have a look at my code, especially the 
xxx_r() functions.
I attach both my patches and the resulting files. The patches are against 
nss/bsdnss.c and compat/nss_compat.h from nss-pam-ldapd 0.8.13 and 
lib/libc/net/nss_compat.c from FreeBSD trunk.

It's somewhat weird that FreeBSD and NetBSD have their NSS module functions 
arguments/results the other way round. For getpwnam_r(), FreeBSD returns the 
struct passwd * via the method's first argument (cbrv) and the numeric 
status result via the last thing in the va_list ap argument, while for 
NetBSD, the first thing in the va_list ap is int *retval for the numeric 
result and the last one is struct passwd **result for the pointer (and the 
method's first argument is unused). On the other hand, for gethostbyname(), 
FreeBSD seems to have a pointer to the result as the first thing in 
va_list ap, while this time, NetBSD returns the result via the method's 
first argument void *cbrv.

I can also post the complete pkgsrc package if that helps.
/*
   bsdnss.c - BSD NSS functions
   This file was part of the nss-pam-ldapd FreeBSD port and part of the
   nss_ldap FreeBSD port before that.

   Copyright (C) 2003 Jacques Vidrine
   Copyright (C) 2006 Artem Kazakov
   Copyright (C) 2009 Alexander V. Chernikov
   Copyright (C) 2011, 2012 Arthur de Jong
   Copyright (C) 2011 Tom Judge

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   This 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
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
   02110-1301 USA
*/

#include "config.h"

#include <errno.h>
#include <sys/param.h>
#include <netinet/in.h>

#include "prototypes.h"
#include "common.h"
#include "compat/attrs.h"

#define BUFFER_SIZE 1024

NSS_METHOD_PROTOTYPE(__nss_compat_getgrnam_r);
NSS_METHOD_PROTOTYPE(__nss_compat_getgrgid_r);
NSS_METHOD_PROTOTYPE(__nss_compat_getgrent_r);
NSS_METHOD_PROTOTYPE(__nss_compat_getgrent);
NSS_METHOD_PROTOTYPE(__nss_compat_setgrent);
NSS_METHOD_PROTOTYPE(__nss_compat_endgrent);
NSS_METHOD_PROTOTYPE(__nss_compat_getgrnam);
NSS_METHOD_PROTOTYPE(__nss_compat_getgrgid);
NSS_METHOD_PROTOTYPE(__netbsd_getgroupmembership);

NSS_METHOD_PROTOTYPE(__nss_compat_getpwnam_r);
NSS_METHOD_PROTOTYPE(__nss_compat_getpwuid_r);
NSS_METHOD_PROTOTYPE(__nss_compat_getpwent_r);
NSS_METHOD_PROTOTYPE(__nss_compat_getpwent);
NSS_METHOD_PROTOTYPE(__nss_compat_setpwent);
NSS_METHOD_PROTOTYPE(__nss_compat_endpwent);
NSS_METHOD_PROTOTYPE(__nss_compat_getpwnam);
NSS_METHOD_PROTOTYPE(__nss_compat_getpwuid);

NSS_METHOD_PROTOTYPE(__nss_compat_gethostbyname);
NSS_METHOD_PROTOTYPE(__nss_compat_gethostbyaddr);

static ns_mtab methods[]={
  { NSDB_GROUP, "getgrnam_r", __nss_compat_getgrnam_r, _nss_ldap_getgrnam_r },
  { NSDB_GROUP, "getgrgid_r", __nss_compat_getgrgid_r, _nss_ldap_getgrgid_r },
  { NSDB_GROUP, "getgrent_r", __nss_compat_getgrent_r, _nss_ldap_getgrent_r },
  { NSDB_GROUP, "getgrent",   __nss_compat_getgrent,   _nss_ldap_getgrent_r },
  { NSDB_GROUP, "setgrent",   __nss_compat_setgrent,   _nss_ldap_setgrent },
  { NSDB_GROUP, "endgrent",   __nss_compat_endgrent,   _nss_ldap_endgrent },
  { NSDB_GROUP, "getgrnam", __nss_compat_getgrnam, _nss_ldap_getgrnam_r },
  { NSDB_GROUP, "getgrgid", __nss_compat_getgrgid, _nss_ldap_getgrgid_r },
  { NSDB_GROUP, "getgroupmembership", __netbsd_getgroupmembership, NULL },

  { NSDB_PASSWD, "getpwnam_r", __nss_compat_getpwnam_r, _nss_ldap_getpwnam_r },
  { NSDB_PASSWD, "getpwuid_r", __nss_compat_getpwuid_r, _nss_ldap_getpwuid_r },
  { NSDB_PASSWD, "getpwent_r", __nss_compat_getpwent_r, _nss_ldap_getpwent_r },
  { NSDB_PASSWD, "getpwent",   __nss_compat_getpwent,   _nss_ldap_getpwent_r },
  { NSDB_PASSWD, "setpwent",   __nss_compat_setpwent,   _nss_ldap_setpwent },
  { NSDB_PASSWD, "endpwent",   __nss_compat_endpwent,   _nss_ldap_endpwent },
  { NSDB_PASSWD, "getpwnam", __nss_compat_getpwnam, _nss_ldap_getpwnam_r },
  { NSDB_PASSWD, "getpwuid", __nss_compat_getpwuid, _nss_ldap_getpwuid_r },

  { NSDB_HOSTS, "gethostbyname", __nss_compat_gethostbyname, 
_nss_ldap_gethostbyname_r },
  { NSDB_HOSTS, "gethostbyaddr", __nss_compat_gethostbyaddr, 
_nss_ldap_gethostbyaddr_r },

  { NSDB_GROUP_COMPAT, "getgrnam_r", __nss_compat_getgrnam_r, 
_nss_ldap_getgrnam_r },
  { NSDB_GROUP_COMPAT, "getgrgid_r", __nss_compat_getgrgid_r, 
_nss_ldap_getgrgid_r },
  { NSDB_GROUP_COMPAT, "getgrent_r", __nss_compat_getgrent_r, 
_nss_ldap_getgrent_r },
  { NSDB_GROUP_COMPAT, "getgrent",   __nss_compat_getgrent,   
_nss_ldap_getgrent_r },
  { NSDB_GROUP_COMPAT, "setgrent",   __nss_compat_setgrent,   
_nss_ldap_setgrent },
  { NSDB_GROUP_COMPAT, "endgrent",   __nss_compat_endgrent,   
_nss_ldap_endgrent },
  { NSDB_GROUP_COMPAT, "getgrnam", __nss_compat_getgrnam, _nss_ldap_getgrnam_r 
},
  { NSDB_GROUP_COMPAT, "getgrgid", __nss_compat_getgrgid, _nss_ldap_getgrgid_r 
},

  { NSDB_PASSWD_COMPAT, "getpwnam_r", __nss_compat_getpwnam_r, 
_nss_ldap_getpwnam_r },
  { NSDB_PASSWD_COMPAT, "getpwuid_r", __nss_compat_getpwuid_r, 
_nss_ldap_getpwuid_r },
  { NSDB_PASSWD_COMPAT, "getpwent_r", __nss_compat_getpwent_r, 
_nss_ldap_getpwent_r },
  { NSDB_PASSWD_COMPAT, "getpwent",   __nss_compat_getpwent,   
_nss_ldap_getpwent_r },
  { NSDB_PASSWD_COMPAT, "setpwent",   __nss_compat_setpwent,   
_nss_ldap_setpwent },
  { NSDB_PASSWD_COMPAT, "endpwent",   __nss_compat_endpwent,   
_nss_ldap_endpwent },
  { NSDB_PASSWD_COMPAT, "getpwnam", __nss_compat_getpwnam, _nss_ldap_getpwnam_r 
},
  { NSDB_PASSWD_COMPAT, "getpwuid", __nss_compat_getpwuid, _nss_ldap_getpwuid_r 
},
};

#ifdef __NetBSD__
#include <compat/nss_compat.c>
#endif

int __nss_compat_gethostbyname(void *cbrv,void *cbdata,va_list ap)
{
  nss_status_t (*fn)(const char *,struct hostent *,char *,size_t,int *,int *);
  const char *name;
  int namelen;
  char buffer[BUFFER_SIZE];
  int errnop;
  int h_errnop;
  int af;
  nss_status_t status;
  fn=cbdata;
  name=va_arg(ap,const char*);
  namelen=va_arg(ap,int);
  af=va_arg(ap,int);
  status=fn(name,(struct hostent 
*)cbrv,buffer,sizeof(buffer),&errnop,&h_errnop);
  status=__nss_compat_result(status,errnop);
  h_errno=h_errnop;
  return (status);
}

int __nss_compat_gethostbyaddr(void *cbrv,void *cbdata,va_list ap)
{
  struct in_addr *addr;
  int addrlen;
  int af;
  char buffer[BUFFER_SIZE];
  int errnop;
  int h_errnop;
  nss_status_t (*fn)(struct in_addr *,int,int,struct hostent *,char 
*,size_t,int *,int *);
  nss_status_t status;
  fn=cbdata;
  addr=va_arg(ap,struct in_addr*);
  addrlen=va_arg(ap,int);
  af=va_arg(ap,int);
  status=fn(addr,addrlen,af,(struct hostent 
*)cbrv,buffer,sizeof(buffer),&errnop,&h_errnop);
  status=__nss_compat_result(status,errnop);
  h_errno=h_errnop;
  return (status);
}

static int __gr_addgid(gid_t gid,gid_t *groups,int maxgrp,int *groupc)
{
  int ret,dupc;
  /* skip duplicates */
  for (dupc=0;dupc<MIN(maxgrp,*groupc);dupc++)
  {
    if (groups[dupc]==gid)
      return 1;
  }
  ret=1;
  if (*groupc<maxgrp)  /* add this gid */
    groups[*groupc]=gid;
  else
    ret=0;
  (*groupc)++;
  return ret;
}

int __netbsd_getgroupmembership(void *cbrv,void *cbdata,va_list ap)
{
  int err;
  nss_status_t s;
  gid_t group;
  gid_t *tmpgroups;
  int *retval;
  const char *user;
  gid_t *groups;
  int maxgrp,*grpcnt;
  int i;
  long int lstart,lsize;
  (void)cbdata;
  retval=va_arg(ap,int *);
  user=va_arg(ap,const char *);
  group=va_arg(ap,gid_t);
  groups=va_arg(ap,gid_t *);
  maxgrp=va_arg(ap,int);
  grpcnt=va_arg(ap,int *);
  (void)retval;
  tmpgroups=malloc(maxgrp*sizeof(gid_t));
  if (tmpgroups==NULL)
    return NSS_STATUS_UNAVAIL;
  /* insert primary membership */
  __gr_addgid(group,groups,maxgrp,grpcnt);
  lstart=0;
  lsize=maxgrp;
  s=_nss_ldap_initgroups_dyn(user,group,&lstart,&lsize,&tmpgroups,0,&err);
  if (s==NSS_STATUS_SUCCESS)
  {
    for (i=0;i<lstart;i++)
      __gr_addgid(tmpgroups[i],groups,maxgrp,grpcnt);
    s=NSS_STATUS_NOTFOUND;
  }
  free(tmpgroups);
  return __nss_compat_result(s,0);
}

ns_mtab *nss_module_register(const char *source,unsigned int *mtabsize,
    nss_module_unregister_fn *unreg)
{
  *mtabsize=sizeof(methods)/sizeof(methods[0]);
  *unreg=NULL;
  return (methods);
}
/*
   nss_compat.h - compatibility definitions for NSS functions

   Copyright (C) 2010, 2012 Arthur de Jong
   Copyright (C) 2010 Symas Corporation

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   This 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
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
   02110-1301 USA
*/

#ifndef COMPAT__NSS_H
#define COMPAT__NSS_H 1

#ifdef HAVE_NSS_H
#include <nss.h>
#else
#ifdef __NetBSD__
#include <nsswitch.h>
enum nss_status {
        NSS_STATUS_TRYAGAIN = -2,
        NSS_STATUS_UNAVAIL,
        NSS_STATUS_NOTFOUND,
        NSS_STATUS_SUCCESS,
        NSS_STATUS_RETURN
};
#define HAVE_ENUM_NSS_STATUS 1
#include <stdarg.h>
#define NSS_METHOD_PROTOTYPE(method) \
        int method(void *, void *, va_list)
#define __nss_compat_result(rv, err) \
        ((rv == NSS_STATUS_TRYAGAIN) ? (err == ERANGE ? NS_UNAVAIL : 
NS_TRYAGAIN) : \
         (rv == NSS_STATUS_TRYAGAIN) ? NS_TRYAGAIN : \
         (rv == NSS_STATUS_UNAVAIL)  ? NS_UNAVAIL  : \
         (rv == NSS_STATUS_NOTFOUND) ? NS_NOTFOUND : \
         (rv == NSS_STATUS_SUCCESS)  ? NS_SUCCESS  : \
         (rv == NSS_STATUS_RETURN)   ? NS_UNAVAIL  : \
        0)
#endif /* __NetBSD__ */
#endif /* HAVE_NSS_H */
#ifdef HAVE_NSS_COMMON_H
#include <nss_common.h>
#endif /* HAVE_NSS_COMMON_H */
#ifdef HAVE_ALIASES_H
#include <aliases.h>
#endif
#include <sys/socket.h>
#include <sys/types.h>
#include <grp.h>
#include <netdb.h>
#include <pwd.h>
#ifdef HAVE_SHADOW_H
#include <shadow.h>
#endif /* HAVE_SHADOW_H */
#ifdef HAVE_RPC_RPCENT_H
#include <rpc/rpcent.h>
#endif /* HAVE_RPC_RPCENT_H */
#ifdef HAVE_NSS_DBDEFS_H
#include <nss_dbdefs.h>
#endif /* HAVE_NSS_DBDEFS_H */
#ifdef HAVE_NSSWITCH_H
#include <nsswitch.h>
#endif /* HAVE_NSSWITCH_H */
#ifdef HAVE_IRS_NSS_H
#include "irs-nss.h"
#endif /* HAVE_IRS_NSS_H */

#include "compat/ether.h"

/* define missing status codes */
#ifndef HAVE_ENUM_NSS_STATUS
#ifndef NSS_STATUS_SUCCESS
#define NSS_STATUS_SUCCESS NSS_SUCCESS
#endif
#ifndef NSS_STATUS_NOTFOUND
#define NSS_STATUS_NOTFOUND NSS_NOTFOUND
#endif
#ifndef NSS_STATUS_UNAVAIL
#define NSS_STATUS_UNAVAIL NSS_UNAVAIL
#endif
#ifndef NSS_STATUS_TRYAGAIN
#define NSS_STATUS_TRYAGAIN NSS_TRYAGAIN
#endif
#ifndef NSS_STATUS_RETURN
#define NSS_STATUS_RETURN NSS_NOTFOUND
#endif
#endif /* not HAVE_ENUM_NSS_STATUS */

/* define nss_status_t */
#ifdef HAVE_ENUM_NSS_STATUS
typedef enum nss_status nss_status_t;
#endif

/* Define an aliasent if it was not found on the system. */
#ifndef HAVE_STRUCT_ALIASENT
struct aliasent
{
  char *alias_name;
  size_t alias_members_len;
  char **alias_members;
  int alias_local;
};
#endif /* not HAVE_STRUCT_ALIASENT */

/* Define an rpcent if it was not found on the system */
#ifndef HAVE_STRUCT_RPCENT
struct rpcent
{
  char *r_name;
  char **r_aliases;
  int r_number;
};
#endif /* not HAVE_STRUCT_RPCENT */

/* We define struct etherent here because it does not seem to
   be defined in any publicly available header file exposed
   by glibc. This is taken from include/netinet/ether.h
   of the glibc (2.3.6) source tarball. */
#ifndef HAVE_STRUCT_ETHERENT
struct etherent
{
  const char *e_name;
  struct ether_addr e_addr;
};
#endif /* not HAVE_STRUCT_ETHERENT */

/* We also define struct __netgrent because it's definition is
   not publically available. This is taken from inet/netgroup.h
   of the glibc (2.3.6) source tarball.
   The first part of the struct is the only part that is modified
   by our getnetgrent() function, all the other fields are not
   touched at all. */
struct __netgrent
{
  enum { triple_val, group_val } type;
  union
  {
    struct
    {
      const char *host;
      const char *user;
      const char *domain;
    } triple;
    const char *group;
  } val;
  /* the following stuff is used by some NSS services
     but not by ours (it's not completely clear how these
     are shared between different services) or is used
     by our caller */
  char *data;
  size_t data_size;
  union
  {
    char *cursor;
    unsigned long int position;
  } insertedname; /* added name to union to avoid warning */
  int first;
  struct name_list *known_groups;
  struct name_list *needed_groups;
  void *nip; /* changed from `service_user *nip' */
};

/* Define struct spwd if it was not found on the system. */
#ifndef HAVE_STRUCT_SPWD
struct spwd {
  char *sp_namp;
  char *sp_pwdp;
  long sp_lstchg;
  long sp_min;
  long sp_max;
  long sp_warn;
  long sp_inact;
  long sp_expire;
  unsigned long sp_flag;
};
#endif /* not HAVE_STRUCT_SPWD */

#endif /* not COMPAT__NSS_H */
/*-
 * Copyright (c) 2003 Networks Associates Technology, Inc.
 * All rights reserved.
 *
 * This software was developed for the FreeBSD Project by
 * Jacques A. Vidrine, Safeport Network Services, and Network
 * Associates Laboratories, the Security Research Division of Network
 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
 * ("CBOSS"), as part of the DARPA CHATS research program.
 *
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
 *
 * Compatibility shims for the GNU C Library-style nsswitch interface.
 *
 * Ported to NetBSD by Edgar Fuß, Mathematisches Institut der Uni Bonn,
 * <ef%math.uni-bonn.de@localhost>.
 */
#include <sys/cdefs.h>

#include <sys/param.h>
#include <errno.h>
#include <pthread.h>

#include <stdarg.h>
#include <lwp.h>
extern int __isthreaded;
#define pthread_main_np() (_lwp_self() == 1)
#include <compat/nss_compat.h>

struct group;
struct passwd;

static int      terminator;

#define DECLARE_TERMINATOR(x)                                   \
static pthread_key_t     _term_key_##x;                         \
static void                                                     \
_term_create_##x(void)                                          \
{                                                               \
        (void)pthread_key_create(&_term_key_##x, NULL); \
}                                                               \
static void             *_term_main_##x;                        \
static pthread_once_t    _term_once_##x = PTHREAD_ONCE_INIT

#define SET_TERMINATOR(x, y)                                            \
do {                                                                    \
        if (!__isthreaded || pthread_main_np())                 \
                _term_main_##x = (y);                                   \
        else {                                                          \
                (void)pthread_once(&_term_once_##x, _term_create_##x);  \
                (void)pthread_setspecific(_term_key_##x, y);            \
        }                                                               \
} while (0)

#define CHECK_TERMINATOR(x)                                     \
(!__isthreaded || pthread_main_np() ?                           \
    (_term_main_##x) :                                          \
    ((void)pthread_once(&_term_once_##x, _term_create_##x),     \
    pthread_getspecific(_term_key_##x)))



DECLARE_TERMINATOR(group);


int
__nss_compat_getgrnam(void *cbrv, void *cbdata, va_list ap)
{
        int (*fn)(const char *, struct group *, char *, size_t, int *);
        struct group   **retval;
        const char      *name;
        int              errno;
        enum nss_status  status;
        static struct group grp;
        static char buffer[BUFFER_SIZE];

        fn = cbdata;
        retval = va_arg(ap, struct group **);
        name = va_arg(ap, const char *);
        status = fn(name, &grp, buffer, sizeof buffer, &errno);
        status = __nss_compat_result(status, errno);
        if (status == NS_SUCCESS)
                *retval = &grp;
        else
                *retval = NULL;
        return (status);
}

int
__nss_compat_getgrnam_r(void *cbrv, void *cbdata, va_list ap)
{
        int (*fn)(const char *, struct group *, char *, size_t, int *);
        int             *retval;
        const char      *name;
        struct group    *grp;
        char            *buffer;
        size_t           bufsize;
        struct group   **result;
        enum nss_status  status;

        fn = cbdata;
        retval = va_arg(ap, int *);
        name = va_arg(ap, const char *);
        grp = va_arg(ap, struct group *);
        buffer = va_arg(ap, char *);
        bufsize = va_arg(ap, size_t);
        result = va_arg(ap, struct group **);
        status = fn(name, grp, buffer, bufsize, retval);
        status = __nss_compat_result(status, *retval);
        if (status == NS_SUCCESS)
                *result = grp;
        else
                *result = NULL;
        return (status);
}


int
__nss_compat_getgrgid(void *cbrv, void *cbdata, va_list ap)
{
        int (*fn)(gid_t, struct group *, char *, size_t, int *);
        struct group   **retval;
        gid_t            gid;
        int              errno;
        enum nss_status  status;
        static struct group grp;
        static char buffer[BUFFER_SIZE];
        
        fn = cbdata;
        retval = va_arg(ap, struct group **);
        gid = va_arg(ap, gid_t);
        status = fn(gid, &grp, buffer, sizeof buffer, &errno);
        status = __nss_compat_result(status, errno);
        if (status == NS_SUCCESS)
                *retval = &grp;
        else
                *retval = NULL;
        return (status);
}

int
__nss_compat_getgrgid_r(void *cbrv, void *cbdata, va_list ap)
{
        int (*fn)(gid_t, struct group *, char *, size_t, int *);
        int             *retval;
        gid_t            gid;
        struct group    *grp;
        char            *buffer;
        size_t           bufsize;
        struct group   **result;
        enum nss_status  status;
        
        fn = cbdata;
        retval = va_arg(ap, int *);
        gid = va_arg(ap, gid_t);
        grp = va_arg(ap, struct group *);
        buffer = va_arg(ap, char *);
        bufsize = va_arg(ap, size_t);
        result = va_arg(ap, struct group **);
        status = fn(gid, grp, buffer, bufsize, retval);
        status = __nss_compat_result(status, *retval);
        if (status == NS_SUCCESS)
                *result = grp;
        else
                *result = NULL;
        return (status);
}


int
__nss_compat_getgrent(void *cbrv, void *cbdata, va_list ap)
{
        int (*fn)(struct group *, char *, size_t, int *);
        struct group   **retval;
        int               errno;
        enum nss_status  status;
        static struct group grp;
        static char buffer[BUFFER_SIZE];

        fn = cbdata;
        retval = va_arg(ap, struct group **);
        status = fn(&grp, buffer, sizeof buffer, &errno);
        status = __nss_compat_result(status, errno);
        if (status == NS_SUCCESS)
                *retval = &grp;
        else
                *retval = NULL;
        return (status);
}

int
__nss_compat_getgrent_r(void *cbrv, void *cbdata, va_list ap)
{
        int (*fn)(struct group *, char *, size_t, int *);
        int             *retval;
        struct group    *grp;
        char            *buffer;
        size_t           bufsize;
        struct group   **result;
        enum nss_status  status;

        if (CHECK_TERMINATOR(group))
                return (NS_NOTFOUND);
        fn = cbdata;
        retval = va_arg(ap, int *);
        grp = va_arg(ap, struct group *);
        buffer = va_arg(ap, char *);
        bufsize = va_arg(ap, size_t);
        result = va_arg(ap, struct group **);
        status = fn(grp, buffer, bufsize, retval);
        status = __nss_compat_result(status, *retval);
        if (status == NS_SUCCESS)
                *result = grp;
        else
                *result = NULL;
        if (status != NS_RETURN)
                SET_TERMINATOR(group, &terminator);
        return (status);
}


int
__nss_compat_setgrent(void *cbrv, void *cbdata, va_list ap)
{

        SET_TERMINATOR(group, NULL);
        ((int (*)(void))cbdata)();
        return (NS_UNAVAIL);
}


int
__nss_compat_endgrent(void *cbrv, void *cbdata, va_list ap)
{

        SET_TERMINATOR(group, NULL);
        ((int (*)(void))cbdata)();
        return (NS_UNAVAIL);
}



DECLARE_TERMINATOR(passwd);


int
__nss_compat_getpwnam(void *cbrv, void *cbdata, va_list ap)
{
        int (*fn)(const char *, struct passwd *, char *, size_t, int *);
        struct passwd  **retval;
        const char      *name;
        int              errno;
        enum nss_status  status;
        static struct passwd pwd;
        static char buffer[BUFFER_SIZE];

        fn = cbdata;
        retval = va_arg(ap, struct passwd **);
        name = va_arg(ap, const char *);
        status = fn(name, &pwd, buffer, sizeof buffer, &errno);
        status = __nss_compat_result(status, errno);
        if (status == NS_SUCCESS)
                *retval = &pwd;
        else
                *retval = NULL;
        return (status);
}

int
__nss_compat_getpwnam_r(void *cbrv, void *cbdata, va_list ap)
{
        int (*fn)(const char *, struct passwd *, char *, size_t, int *);
        int             *retval;
        const char      *name;
        struct passwd   *pwd;
        char            *buffer;
        size_t           bufsize;
        struct passwd  **result;
        int              errno;
        enum nss_status  status;

        fn = cbdata;
        retval = va_arg(ap, int *);
        name = va_arg(ap, const char *);
        pwd = va_arg(ap, struct passwd *);
        buffer = va_arg(ap, char *);
        bufsize = va_arg(ap, size_t);
        result = va_arg(ap, struct passwd **);
        status = fn(name, pwd, buffer, bufsize, retval);
        status = __nss_compat_result(status, *retval);
        if (status == NS_SUCCESS)
                *result = pwd;
        else
                *result = NULL;
        return (status);
}


int
__nss_compat_getpwuid(void *cbrv, void *cbdata, va_list ap)
{
        int (*fn)(uid_t, struct passwd *, char *, size_t, int *);
        struct passwd  **retval;
        uid_t            uid;
        int              errno;
        enum nss_status  status;
        static struct passwd pwd;
        static char buffer[BUFFER_SIZE];
        
        fn = cbdata;
        retval = va_arg(ap, struct passwd **);
        uid = va_arg(ap, uid_t);
        status = fn(uid, &pwd, buffer, sizeof buffer, &errno);
        status = __nss_compat_result(status, errno);
        if (status == NS_SUCCESS)
                *retval = &pwd;
        else
                *retval = NULL;
        return (status);
}

int
__nss_compat_getpwuid_r(void *cbrv, void *cbdata, va_list ap)
{
        int (*fn)(uid_t, struct passwd *, char *, size_t, int *);
        int             *retval;
        uid_t            uid;
        struct passwd   *pwd;
        char            *buffer;
        size_t           bufsize;
        struct passwd   **result;
        enum nss_status  status;
        
        fn = cbdata;
        retval = va_arg(ap, int *);
        uid = va_arg(ap, uid_t);
        pwd = va_arg(ap, struct passwd *);
        buffer = va_arg(ap, char *);
        bufsize = va_arg(ap, size_t);
        result = va_arg(ap, struct passwd **);
        retval = va_arg(ap, int *);
        status = fn(uid, pwd, buffer, bufsize, retval);
        status = __nss_compat_result(status, *retval);
        if (status == NS_SUCCESS)
                *result = pwd;
        else
                *result = NULL;
        return (status);
}


int
__nss_compat_getpwent(void *cbrv, void *cbdata, va_list ap)
{
        int (*fn)(struct passwd *, char *, size_t, int *);
        struct passwd  **retval;
        int              errno;
        enum nss_status  status;
        static struct passwd pwd;
        static char buffer[BUFFER_SIZE];

        fn = cbdata;
        retval = va_arg(ap, struct passwd **);
        status = fn(&pwd, buffer, sizeof buffer, &errno);
        status = __nss_compat_result(status, errno);
        if (status == NS_SUCCESS)
                *retval = &pwd;
        else
                *retval = NULL;
        return (status);
}

int
__nss_compat_getpwent_r(void *cbrv, void *cbdata, va_list ap)
{
        int (*fn)(struct passwd *, char *, size_t, int *);
        int             *retval;
        struct passwd   *pwd;
        char            *buffer;
        size_t           bufsize;
        struct passwd  **result;
        enum nss_status  status;

        if (CHECK_TERMINATOR(passwd))
                return (NS_NOTFOUND);
        fn = cbdata;
        retval = va_arg(ap, int *);
        pwd = va_arg(ap, struct passwd *);
        buffer = va_arg(ap, char *);
        bufsize = va_arg(ap, size_t);
        result = va_arg(ap, struct passwd **);
        status = fn(pwd, buffer, bufsize, retval);
        status = __nss_compat_result(status, *retval);
        if (status == NS_SUCCESS)
                *result = pwd;
        else
                *result = NULL;
        if (status != NS_RETURN)
                SET_TERMINATOR(passwd, &terminator);
        return (status);
}


int
__nss_compat_setpwent(void *cbrv, void *cbdata, va_list ap)
{

        SET_TERMINATOR(passwd, NULL);
        ((int (*)(void))cbdata)();
        return (NS_UNAVAIL);
}


int
__nss_compat_endpwent(void *cbrv, void *cbdata, va_list ap)
{

        SET_TERMINATOR(passwd, NULL);
        ((int (*)(void))cbdata)();
        return (NS_UNAVAIL);
}
$NetBSD$

NetBSD does not have __nss_compat_xxx functions in its C library.
It also need non-_r variants.

--- nss/bsdnss.c.orig   2012-05-18 15:34:22.000000000 +0200
+++ nss/bsdnss.c        2013-12-03 17:18:50.000000000 +0100
@@ -40,108 +40,106 @@
 NSS_METHOD_PROTOTYPE(__nss_compat_getgrnam_r);
 NSS_METHOD_PROTOTYPE(__nss_compat_getgrgid_r);
 NSS_METHOD_PROTOTYPE(__nss_compat_getgrent_r);
+NSS_METHOD_PROTOTYPE(__nss_compat_getgrent);
 NSS_METHOD_PROTOTYPE(__nss_compat_setgrent);
 NSS_METHOD_PROTOTYPE(__nss_compat_endgrent);
-NSS_METHOD_PROTOTYPE(__freebsd_getgroupmembership);
+NSS_METHOD_PROTOTYPE(__nss_compat_getgrnam);
+NSS_METHOD_PROTOTYPE(__nss_compat_getgrgid);
+NSS_METHOD_PROTOTYPE(__netbsd_getgroupmembership);
 
 NSS_METHOD_PROTOTYPE(__nss_compat_getpwnam_r);
 NSS_METHOD_PROTOTYPE(__nss_compat_getpwuid_r);
 NSS_METHOD_PROTOTYPE(__nss_compat_getpwent_r);
+NSS_METHOD_PROTOTYPE(__nss_compat_getpwent);
 NSS_METHOD_PROTOTYPE(__nss_compat_setpwent);
 NSS_METHOD_PROTOTYPE(__nss_compat_endpwent);
+NSS_METHOD_PROTOTYPE(__nss_compat_getpwnam);
+NSS_METHOD_PROTOTYPE(__nss_compat_getpwuid);
 
 NSS_METHOD_PROTOTYPE(__nss_compat_gethostbyname);
-NSS_METHOD_PROTOTYPE(__nss_compat_gethostbyname2);
 NSS_METHOD_PROTOTYPE(__nss_compat_gethostbyaddr);
 
 static ns_mtab methods[]={
   { NSDB_GROUP, "getgrnam_r", __nss_compat_getgrnam_r, _nss_ldap_getgrnam_r },
   { NSDB_GROUP, "getgrgid_r", __nss_compat_getgrgid_r, _nss_ldap_getgrgid_r },
   { NSDB_GROUP, "getgrent_r", __nss_compat_getgrent_r, _nss_ldap_getgrent_r },
+  { NSDB_GROUP, "getgrent",   __nss_compat_getgrent,   _nss_ldap_getgrent_r },
   { NSDB_GROUP, "setgrent",   __nss_compat_setgrent,   _nss_ldap_setgrent },
   { NSDB_GROUP, "endgrent",   __nss_compat_endgrent,   _nss_ldap_endgrent },
-  { NSDB_GROUP, "getgroupmembership", __freebsd_getgroupmembership, NULL },
+  { NSDB_GROUP, "getgrnam", __nss_compat_getgrnam, _nss_ldap_getgrnam_r },
+  { NSDB_GROUP, "getgrgid", __nss_compat_getgrgid, _nss_ldap_getgrgid_r },
+  { NSDB_GROUP, "getgroupmembership", __netbsd_getgroupmembership, NULL },
 
   { NSDB_PASSWD, "getpwnam_r", __nss_compat_getpwnam_r, _nss_ldap_getpwnam_r },
   { NSDB_PASSWD, "getpwuid_r", __nss_compat_getpwuid_r, _nss_ldap_getpwuid_r },
   { NSDB_PASSWD, "getpwent_r", __nss_compat_getpwent_r, _nss_ldap_getpwent_r },
+  { NSDB_PASSWD, "getpwent",   __nss_compat_getpwent,   _nss_ldap_getpwent_r },
   { NSDB_PASSWD, "setpwent",   __nss_compat_setpwent,   _nss_ldap_setpwent },
   { NSDB_PASSWD, "endpwent",   __nss_compat_endpwent,   _nss_ldap_endpwent },
+  { NSDB_PASSWD, "getpwnam", __nss_compat_getpwnam, _nss_ldap_getpwnam_r },
+  { NSDB_PASSWD, "getpwuid", __nss_compat_getpwuid, _nss_ldap_getpwuid_r },
 
   { NSDB_HOSTS, "gethostbyname", __nss_compat_gethostbyname, 
_nss_ldap_gethostbyname_r },
   { NSDB_HOSTS, "gethostbyaddr", __nss_compat_gethostbyaddr, 
_nss_ldap_gethostbyaddr_r },
-  { NSDB_HOSTS, "gethostbyname2", __nss_compat_gethostbyname2, 
_nss_ldap_gethostbyname2_r },
 
   { NSDB_GROUP_COMPAT, "getgrnam_r", __nss_compat_getgrnam_r, 
_nss_ldap_getgrnam_r },
   { NSDB_GROUP_COMPAT, "getgrgid_r", __nss_compat_getgrgid_r, 
_nss_ldap_getgrgid_r },
   { NSDB_GROUP_COMPAT, "getgrent_r", __nss_compat_getgrent_r, 
_nss_ldap_getgrent_r },
+  { NSDB_GROUP_COMPAT, "getgrent",   __nss_compat_getgrent,   
_nss_ldap_getgrent_r },
   { NSDB_GROUP_COMPAT, "setgrent",   __nss_compat_setgrent,   
_nss_ldap_setgrent },
   { NSDB_GROUP_COMPAT, "endgrent",   __nss_compat_endgrent,   
_nss_ldap_endgrent },
+  { NSDB_GROUP_COMPAT, "getgrnam", __nss_compat_getgrnam, _nss_ldap_getgrnam_r 
},
+  { NSDB_GROUP_COMPAT, "getgrgid", __nss_compat_getgrgid, _nss_ldap_getgrgid_r 
},
 
   { NSDB_PASSWD_COMPAT, "getpwnam_r", __nss_compat_getpwnam_r, 
_nss_ldap_getpwnam_r },
   { NSDB_PASSWD_COMPAT, "getpwuid_r", __nss_compat_getpwuid_r, 
_nss_ldap_getpwuid_r },
   { NSDB_PASSWD_COMPAT, "getpwent_r", __nss_compat_getpwent_r, 
_nss_ldap_getpwent_r },
+  { NSDB_PASSWD_COMPAT, "getpwent",   __nss_compat_getpwent,   
_nss_ldap_getpwent_r },
   { NSDB_PASSWD_COMPAT, "setpwent",   __nss_compat_setpwent,   
_nss_ldap_setpwent },
   { NSDB_PASSWD_COMPAT, "endpwent",   __nss_compat_endpwent,   
_nss_ldap_endpwent },
+  { NSDB_PASSWD_COMPAT, "getpwnam", __nss_compat_getpwnam, 
_nss_ldap_getpwnam_r },
+  { NSDB_PASSWD_COMPAT, "getpwuid", __nss_compat_getpwuid, 
_nss_ldap_getpwuid_r },
 };
 
-int __nss_compat_gethostbyname(void *retval,void *mdata,va_list ap)
-{
-  nss_status_t (*fn)(const char *,struct hostent *,char *,size_t,int *,int *);
-  const char *name;
-  struct hostent *result;
-  char buffer[BUFFER_SIZE];
-  int errnop;
-  int h_errnop;
-  int af;
-  nss_status_t status;
-  fn=mdata;
-  name=va_arg(ap,const char*);
-  af=va_arg(ap,int);
-  result=va_arg(ap,struct hostent *);
-  status=fn(name,result,buffer,sizeof(buffer),&errnop,&h_errnop);
-  status=__nss_compat_result(status,errnop);
-  h_errno=h_errnop;
-  return (status);
-}
+#ifdef __NetBSD__
+#include <compat/nss_compat.c>
+#endif
 
-int __nss_compat_gethostbyname2(void *retval,void *mdata,va_list ap)
+int __nss_compat_gethostbyname(void *cbrv,void *cbdata,va_list ap)
 {
   nss_status_t (*fn)(const char *,struct hostent *,char *,size_t,int *,int *);
   const char *name;
-  struct hostent *result;
+  int namelen;
   char buffer[BUFFER_SIZE];
   int errnop;
   int h_errnop;
   int af;
   nss_status_t status;
-  fn=mdata;
+  fn=cbdata;
   name=va_arg(ap,const char*);
+  namelen=va_arg(ap,int);
   af=va_arg(ap,int);
-  result=va_arg(ap,struct hostent *);
-  status=fn(name,result,buffer,sizeof(buffer),&errnop,&h_errnop);
+  status=fn(name,(struct hostent 
*)cbrv,buffer,sizeof(buffer),&errnop,&h_errnop);
   status=__nss_compat_result(status,errnop);
   h_errno=h_errnop;
   return (status);
 }
 
-int __nss_compat_gethostbyaddr(void *retval,void *mdata,va_list ap)
+int __nss_compat_gethostbyaddr(void *cbrv,void *cbdata,va_list ap)
 {
   struct in_addr *addr;
-  int len;
-  int type;
-  struct hostent *result;
+  int addrlen;
+  int af;
   char buffer[BUFFER_SIZE];
   int errnop;
   int h_errnop;
   nss_status_t (*fn)(struct in_addr *,int,int,struct hostent *,char 
*,size_t,int *,int *);
   nss_status_t status;
-  fn=mdata;
+  fn=cbdata;
   addr=va_arg(ap,struct in_addr*);
-  len=va_arg(ap,int);
-  type=va_arg(ap,int);
-  result=va_arg(ap,struct hostent*);
-  status=fn(addr,len,type,result,buffer,sizeof(buffer),&errnop,&h_errnop);
+  addrlen=va_arg(ap,int);
+  af=va_arg(ap,int);
+  status=fn(addr,addrlen,af,(struct hostent 
*)cbrv,buffer,sizeof(buffer),&errnop,&h_errnop);
   status=__nss_compat_result(status,errnop);
   h_errno=h_errnop;
   return (status);
@@ -165,22 +163,26 @@
   return ret;
 }
 
-int __freebsd_getgroupmembership(void *retval,void *mdata,va_list ap)
+int __netbsd_getgroupmembership(void *cbrv,void *cbdata,va_list ap)
 {
   int err;
   nss_status_t s;
   gid_t group;
   gid_t *tmpgroups;
+  int *retval;
   const char *user;
   gid_t *groups;
   int maxgrp,*grpcnt;
   int i;
   long int lstart,lsize;
+  (void)cbdata;
+  retval=va_arg(ap,int *);
   user=va_arg(ap,const char *);
   group=va_arg(ap,gid_t);
   groups=va_arg(ap,gid_t *);
   maxgrp=va_arg(ap,int);
   grpcnt=va_arg(ap,int *);
+  (void)retval;
   tmpgroups=malloc(maxgrp*sizeof(gid_t));
   if (tmpgroups==NULL)
     return NSS_STATUS_UNAVAIL;
$NetBSD$

NetBSD doesn't have <nss.h>

--- compat/nss_compat.h.orig    2012-05-11 14:25:15.000000000 +0200
+++ compat/nss_compat.h 2013-11-28 18:11:22.000000000 +0100
@@ -25,6 +25,29 @@
 
 #ifdef HAVE_NSS_H
 #include <nss.h>
+#else
+#ifdef __NetBSD__
+#include <nsswitch.h>
+enum nss_status {
+       NSS_STATUS_TRYAGAIN = -2,
+       NSS_STATUS_UNAVAIL,
+       NSS_STATUS_NOTFOUND,
+       NSS_STATUS_SUCCESS,
+       NSS_STATUS_RETURN
+};
+#define HAVE_ENUM_NSS_STATUS 1
+#include <stdarg.h>
+#define NSS_METHOD_PROTOTYPE(method) \
+       int method(void *, void *, va_list)
+#define __nss_compat_result(rv, err) \
+       ((rv == NSS_STATUS_TRYAGAIN) ? (err == ERANGE ? NS_UNAVAIL : 
NS_TRYAGAIN) : \
+        (rv == NSS_STATUS_TRYAGAIN) ? NS_TRYAGAIN : \
+        (rv == NSS_STATUS_UNAVAIL)  ? NS_UNAVAIL  : \
+        (rv == NSS_STATUS_NOTFOUND) ? NS_NOTFOUND : \
+        (rv == NSS_STATUS_SUCCESS)  ? NS_SUCCESS  : \
+        (rv == NSS_STATUS_RETURN)   ? NS_UNAVAIL  : \
+       0)
+#endif /* __NetBSD__ */
 #endif /* HAVE_NSS_H */
 #ifdef HAVE_NSS_COMMON_H
 #include <nss_common.h>
$NetBSD$

Adjust FreeBSD's nss_compat.c to NetBSD.

--- compat/nss_compat.c.orig    2013-12-03 17:20:30.000000000 +0100
+++ compat/nss_compat.c 2013-12-03 18:06:25.000000000 +0100
@@ -30,19 +30,21 @@
  * SUCH DAMAGE.
  *
  * Compatibility shims for the GNU C Library-style nsswitch interface.
+ *
+ * Ported to NetBSD by Edgar Fuß, Mathematisches Institut der Uni Bonn,
+ * <ef%math.uni-bonn.de@localhost>.
  */
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
 
-#include "namespace.h"
 #include <sys/param.h>
 #include <errno.h>
-#include <nss.h>
 #include <pthread.h>
-#include <pthread_np.h>
-#include "un-namespace.h"
-#include "libc_private.h"
 
+#include <stdarg.h>
+#include <lwp.h>
+extern int __isthreaded;
+#define pthread_main_np() (_lwp_self() == 1)
+#include <compat/nss_compat.h>
 
 struct group;
 struct passwd;
@@ -54,26 +56,26 @@
 static void                                                    \
 _term_create_##x(void)                                         \
 {                                                              \
-       (void)_pthread_key_create(&_term_key_##x, NULL);        \
+       (void)pthread_key_create(&_term_key_##x, NULL); \
 }                                                              \
 static void            *_term_main_##x;                        \
 static pthread_once_t   _term_once_##x = PTHREAD_ONCE_INIT
 
 #define SET_TERMINATOR(x, y)                                           \
 do {                                                                   \
-       if (!__isthreaded || _pthread_main_np())                        \
+       if (!__isthreaded || pthread_main_np())                 \
                _term_main_##x = (y);                                   \
        else {                                                          \
-               (void)_pthread_once(&_term_once_##x, _term_create_##x); \
-               (void)_pthread_setspecific(_term_key_##x, y);           \
+               (void)pthread_once(&_term_once_##x, _term_create_##x);  \
+               (void)pthread_setspecific(_term_key_##x, y);            \
        }                                                               \
 } while (0)
 
 #define CHECK_TERMINATOR(x)                                    \
-(!__isthreaded || _pthread_main_np() ?                         \
+(!__isthreaded || pthread_main_np() ?                          \
     (_term_main_##x) :                                         \
-    ((void)_pthread_once(&_term_once_##x, _term_create_##x),   \
-    _pthread_getspecific(_term_key_##x)))
+    ((void)pthread_once(&_term_once_##x, _term_create_##x),    \
+    pthread_getspecific(_term_key_##x)))
 
 
 
@@ -81,98 +83,177 @@
 
 
 int
-__nss_compat_getgrnam_r(void *retval, void *mdata, va_list ap)
+__nss_compat_getgrnam(void *cbrv, void *cbdata, va_list ap)
+{
+       int (*fn)(const char *, struct group *, char *, size_t, int *);
+       struct group   **retval;
+       const char      *name;
+       int              errno;
+       enum nss_status  status;
+       static struct group grp;
+       static char buffer[BUFFER_SIZE];
+
+       fn = cbdata;
+       retval = va_arg(ap, struct group **);
+       name = va_arg(ap, const char *);
+       status = fn(name, &grp, buffer, sizeof buffer, &errno);
+       status = __nss_compat_result(status, errno);
+       if (status == NS_SUCCESS)
+               *retval = &grp;
+       else
+               *retval = NULL;
+       return (status);
+}
+
+int
+__nss_compat_getgrnam_r(void *cbrv, void *cbdata, va_list ap)
 {
        int (*fn)(const char *, struct group *, char *, size_t, int *);
+       int             *retval;
        const char      *name;
        struct group    *grp;
        char            *buffer;
-       int             *errnop;
        size_t           bufsize;
+       struct group   **result;
        enum nss_status  status;
 
-       fn = mdata;
+       fn = cbdata;
+       retval = va_arg(ap, int *);
        name = va_arg(ap, const char *);
        grp = va_arg(ap, struct group *);
        buffer = va_arg(ap, char *);
        bufsize = va_arg(ap, size_t);
-       errnop = va_arg(ap, int *);
-       status = fn(name, grp, buffer, bufsize, errnop);
-       status = __nss_compat_result(status, *errnop);
+       result = va_arg(ap, struct group **);
+       status = fn(name, grp, buffer, bufsize, retval);
+       status = __nss_compat_result(status, *retval);
        if (status == NS_SUCCESS)
-               *(struct group **)retval = grp;
+               *result = grp;
+       else
+               *result = NULL;
        return (status);
 }
 
 
 int
-__nss_compat_getgrgid_r(void *retval, void *mdata, va_list ap)
+__nss_compat_getgrgid(void *cbrv, void *cbdata, va_list ap)
+{
+       int (*fn)(gid_t, struct group *, char *, size_t, int *);
+       struct group   **retval;
+       gid_t            gid;
+       int              errno;
+       enum nss_status  status;
+       static struct group grp;
+       static char buffer[BUFFER_SIZE];
+       
+       fn = cbdata;
+       retval = va_arg(ap, struct group **);
+       gid = va_arg(ap, gid_t);
+       status = fn(gid, &grp, buffer, sizeof buffer, &errno);
+       status = __nss_compat_result(status, errno);
+       if (status == NS_SUCCESS)
+               *retval = &grp;
+       else
+               *retval = NULL;
+       return (status);
+}
+
+int
+__nss_compat_getgrgid_r(void *cbrv, void *cbdata, va_list ap)
 {
        int (*fn)(gid_t, struct group *, char *, size_t, int *);
+       int             *retval;
        gid_t            gid;
        struct group    *grp;
        char            *buffer;
-       int             *errnop;
        size_t           bufsize;
+       struct group   **result;
        enum nss_status  status;
        
-       fn = mdata;
+       fn = cbdata;
+       retval = va_arg(ap, int *);
        gid = va_arg(ap, gid_t);
        grp = va_arg(ap, struct group *);
        buffer = va_arg(ap, char *);
        bufsize = va_arg(ap, size_t);
-       errnop = va_arg(ap, int *);
-       status = fn(gid, grp, buffer, bufsize, errnop);
-       status = __nss_compat_result(status, *errnop);
+       result = va_arg(ap, struct group **);
+       status = fn(gid, grp, buffer, bufsize, retval);
+       status = __nss_compat_result(status, *retval);
        if (status == NS_SUCCESS)
-               *(struct group **)retval = grp;
+               *result = grp;
+       else
+               *result = NULL;
        return (status);
 }
 
 
 int
-__nss_compat_getgrent_r(void *retval, void *mdata, va_list ap)
+__nss_compat_getgrent(void *cbrv, void *cbdata, va_list ap)
+{
+       int (*fn)(struct group *, char *, size_t, int *);
+       struct group   **retval;
+       int               errno;
+       enum nss_status  status;
+       static struct group grp;
+       static char buffer[BUFFER_SIZE];
+
+       fn = cbdata;
+       retval = va_arg(ap, struct group **);
+       status = fn(&grp, buffer, sizeof buffer, &errno);
+       status = __nss_compat_result(status, errno);
+       if (status == NS_SUCCESS)
+               *retval = &grp;
+       else
+               *retval = NULL;
+       return (status);
+}
+
+int
+__nss_compat_getgrent_r(void *cbrv, void *cbdata, va_list ap)
 {
        int (*fn)(struct group *, char *, size_t, int *);
+       int             *retval;
        struct group    *grp;
        char            *buffer;
-       int             *errnop;
        size_t           bufsize;
+       struct group   **result;
        enum nss_status  status;
 
        if (CHECK_TERMINATOR(group))
                return (NS_NOTFOUND);
-       fn = mdata;
+       fn = cbdata;
+       retval = va_arg(ap, int *);
        grp = va_arg(ap, struct group *);
        buffer = va_arg(ap, char *);
        bufsize = va_arg(ap, size_t);
-       errnop = va_arg(ap, int *);
-       status = fn(grp, buffer, bufsize, errnop);
-       status = __nss_compat_result(status, *errnop);
+       result = va_arg(ap, struct group **);
+       status = fn(grp, buffer, bufsize, retval);
+       status = __nss_compat_result(status, *retval);
        if (status == NS_SUCCESS)
-               *(struct group **)retval = grp;
-       else if (status != NS_RETURN)
+               *result = grp;
+       else
+               *result = NULL;
+       if (status != NS_RETURN)
                SET_TERMINATOR(group, &terminator);
        return (status);
 }
 
 
 int
-__nss_compat_setgrent(void *retval, void *mdata, va_list ap)
+__nss_compat_setgrent(void *cbrv, void *cbdata, va_list ap)
 {
 
        SET_TERMINATOR(group, NULL);
-       ((int (*)(void))mdata)();
+       ((int (*)(void))cbdata)();
        return (NS_UNAVAIL);
 }
 
 
 int
-__nss_compat_endgrent(void *retval, void *mdata, va_list ap)
+__nss_compat_endgrent(void *cbrv, void *cbdata, va_list ap)
 {
 
        SET_TERMINATOR(group, NULL);
-       ((int (*)(void))mdata)();
+       ((int (*)(void))cbdata)();
        return (NS_UNAVAIL);
 }
 
@@ -182,97 +263,178 @@
 
 
 int
-__nss_compat_getpwnam_r(void *retval, void *mdata, va_list ap)
+__nss_compat_getpwnam(void *cbrv, void *cbdata, va_list ap)
 {
        int (*fn)(const char *, struct passwd *, char *, size_t, int *);
+       struct passwd  **retval;
+       const char      *name;
+       int              errno;
+       enum nss_status  status;
+       static struct passwd pwd;
+       static char buffer[BUFFER_SIZE];
+
+       fn = cbdata;
+       retval = va_arg(ap, struct passwd **);
+       name = va_arg(ap, const char *);
+       status = fn(name, &pwd, buffer, sizeof buffer, &errno);
+       status = __nss_compat_result(status, errno);
+       if (status == NS_SUCCESS)
+               *retval = &pwd;
+       else
+               *retval = NULL;
+       return (status);
+}
+
+int
+__nss_compat_getpwnam_r(void *cbrv, void *cbdata, va_list ap)
+{
+       int (*fn)(const char *, struct passwd *, char *, size_t, int *);
+       int             *retval;
        const char      *name;
        struct passwd   *pwd;
        char            *buffer;
-       int             *errnop;
        size_t           bufsize;
+       struct passwd  **result;
+       int              errno;
        enum nss_status  status;
 
-       fn = mdata;
+       fn = cbdata;
+       retval = va_arg(ap, int *);
        name = va_arg(ap, const char *);
        pwd = va_arg(ap, struct passwd *);
        buffer = va_arg(ap, char *);
        bufsize = va_arg(ap, size_t);
-       errnop = va_arg(ap, int *);
-       status = fn(name, pwd, buffer, bufsize, errnop);
-       status = __nss_compat_result(status, *errnop);
+       result = va_arg(ap, struct passwd **);
+       status = fn(name, pwd, buffer, bufsize, retval);
+       status = __nss_compat_result(status, *retval);
        if (status == NS_SUCCESS)
-               *(struct passwd **)retval = pwd;
+               *result = pwd;
+       else
+               *result = NULL;
        return (status);
 }
 
 
 int
-__nss_compat_getpwuid_r(void *retval, void *mdata, va_list ap)
+__nss_compat_getpwuid(void *cbrv, void *cbdata, va_list ap)
 {
        int (*fn)(uid_t, struct passwd *, char *, size_t, int *);
+       struct passwd  **retval;
+       uid_t            uid;
+       int              errno;
+       enum nss_status  status;
+       static struct passwd pwd;
+       static char buffer[BUFFER_SIZE];
+       
+       fn = cbdata;
+       retval = va_arg(ap, struct passwd **);
+       uid = va_arg(ap, uid_t);
+       status = fn(uid, &pwd, buffer, sizeof buffer, &errno);
+       status = __nss_compat_result(status, errno);
+       if (status == NS_SUCCESS)
+               *retval = &pwd;
+       else
+               *retval = NULL;
+       return (status);
+}
+
+int
+__nss_compat_getpwuid_r(void *cbrv, void *cbdata, va_list ap)
+{
+       int (*fn)(uid_t, struct passwd *, char *, size_t, int *);
+       int             *retval;
        uid_t            uid;
        struct passwd   *pwd;
        char            *buffer;
-       int             *errnop;
        size_t           bufsize;
+       struct passwd   **result;
        enum nss_status  status;
        
-       fn = mdata;
+       fn = cbdata;
+       retval = va_arg(ap, int *);
        uid = va_arg(ap, uid_t);
        pwd = va_arg(ap, struct passwd *);
        buffer = va_arg(ap, char *);
        bufsize = va_arg(ap, size_t);
-       errnop = va_arg(ap, int *);
-       status = fn(uid, pwd, buffer, bufsize, errnop);
-       status = __nss_compat_result(status, *errnop);
+       result = va_arg(ap, struct passwd **);
+       retval = va_arg(ap, int *);
+       status = fn(uid, pwd, buffer, bufsize, retval);
+       status = __nss_compat_result(status, *retval);
        if (status == NS_SUCCESS)
-               *(struct passwd **)retval = pwd;
+               *result = pwd;
+       else
+               *result = NULL;
        return (status);
 }
 
 
 int
-__nss_compat_getpwent_r(void *retval, void *mdata, va_list ap)
+__nss_compat_getpwent(void *cbrv, void *cbdata, va_list ap)
+{
+       int (*fn)(struct passwd *, char *, size_t, int *);
+       struct passwd  **retval;
+       int              errno;
+       enum nss_status  status;
+       static struct passwd pwd;
+       static char buffer[BUFFER_SIZE];
+
+       fn = cbdata;
+       retval = va_arg(ap, struct passwd **);
+       status = fn(&pwd, buffer, sizeof buffer, &errno);
+       status = __nss_compat_result(status, errno);
+       if (status == NS_SUCCESS)
+               *retval = &pwd;
+       else
+               *retval = NULL;
+       return (status);
+}
+
+int
+__nss_compat_getpwent_r(void *cbrv, void *cbdata, va_list ap)
 {
        int (*fn)(struct passwd *, char *, size_t, int *);
+       int             *retval;
        struct passwd   *pwd;
        char            *buffer;
-       int             *errnop;
        size_t           bufsize;
+       struct passwd  **result;
        enum nss_status  status;
 
        if (CHECK_TERMINATOR(passwd))
                return (NS_NOTFOUND);
-       fn = mdata;
+       fn = cbdata;
+       retval = va_arg(ap, int *);
        pwd = va_arg(ap, struct passwd *);
        buffer = va_arg(ap, char *);
        bufsize = va_arg(ap, size_t);
-       errnop = va_arg(ap, int *);
-       status = fn(pwd, buffer, bufsize, errnop);
-       status = __nss_compat_result(status, *errnop);
+       result = va_arg(ap, struct passwd **);
+       status = fn(pwd, buffer, bufsize, retval);
+       status = __nss_compat_result(status, *retval);
        if (status == NS_SUCCESS)
-               *(struct passwd **)retval = pwd;
-       else if (status != NS_RETURN)
+               *result = pwd;
+       else
+               *result = NULL;
+       if (status != NS_RETURN)
                SET_TERMINATOR(passwd, &terminator);
        return (status);
 }
 
 
 int
-__nss_compat_setpwent(void *retval, void *mdata, va_list ap)
+__nss_compat_setpwent(void *cbrv, void *cbdata, va_list ap)
 {
 
        SET_TERMINATOR(passwd, NULL);
-       ((int (*)(void))mdata)();
+       ((int (*)(void))cbdata)();
        return (NS_UNAVAIL);
 }
 
 
 int
-__nss_compat_endpwent(void *retval, void *mdata, va_list ap)
+__nss_compat_endpwent(void *cbrv, void *cbdata, va_list ap)
 {
 
        SET_TERMINATOR(passwd, NULL);
-       ((int (*)(void))mdata)();
+       ((int (*)(void))cbdata)();
        return (NS_UNAVAIL);
 }


Home | Main Index | Thread Index | Old Index