summaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
authorArthur de Jong <arthur@arthurdejong.org>2006-10-25 15:22:04 +0000
committerArthur de Jong <arthur@arthurdejong.org>2006-10-25 15:22:04 +0000
commit4ba0924ee98e297e5ce526367c6aad204b6c3adc (patch)
tree6fdc9202ebd01dd49be3e78ecc013e2bb31a4b44 /server
parentb586bf84c0bd966abf5cb3d26fa956353d77f9e1 (diff)
move ldap server code into separate directory
git-svn-id: http://arthurdejong.org/svn/nss-pam-ldapd/libnss_ldapd@25 ef36b2f9-881f-0410-afb5-c4e39611909c
Diffstat (limited to 'server')
-rw-r--r--server/aliases.c99
-rw-r--r--server/automount.c395
-rw-r--r--server/ethers.c142
-rw-r--r--server/group.c1106
-rw-r--r--server/hosts.c328
-rw-r--r--server/netgroup.c329
-rw-r--r--server/networks.c200
-rw-r--r--server/passwd.c206
-rw-r--r--server/protocols.c118
-rw-r--r--server/rpc.c122
-rw-r--r--server/services.c225
-rw-r--r--server/shadow.c134
12 files changed, 3404 insertions, 0 deletions
diff --git a/server/aliases.c b/server/aliases.c
new file mode 100644
index 0000000..0d9ec33
--- /dev/null
+++ b/server/aliases.c
@@ -0,0 +1,99 @@
+/*
+ Copyright (C) 1997-2005 Luke Howard
+ This file is part of the nss_ldap library.
+ Contributed by Luke Howard, <lukeh@padl.com>, 1997.
+
+ The nss_ldap library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The nss_ldap 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the nss_ldap library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ $Id$
+*/
+
+#include "config.h"
+
+#ifdef HAVE_ALIASES_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <lber.h>
+#include <ldap.h>
+#include <errno.h>
+#include <aliases.h>
+#if defined(HAVE_THREAD_H)
+#include <thread.h>
+#elif defined(HAVE_PTHREAD_H)
+#include <pthread.h>
+#endif
+
+#include "ldap-nss.h"
+#include "util.h"
+
+static struct ent_context *alias_context = NULL;
+
+static enum nss_status
+_nss_ldap_parse_alias (LDAPMessage * e,
+ struct ldap_state * pvt,
+ void *result, char *buffer, size_t buflen)
+{
+
+ struct aliasent *alias = (struct aliasent *) result;
+ enum nss_status stat;
+
+ stat =
+ _nss_ldap_getrdnvalue (e, ATM (LM_ALIASES, cn), &alias->alias_name,
+ &buffer, &buflen);
+ if (stat != NSS_STATUS_SUCCESS)
+ return stat;
+
+ stat =
+ _nss_ldap_assign_attrvals (e, AT (rfc822MailMember), NULL,
+ &alias->alias_members, &buffer, &buflen,
+ &alias->alias_members_len);
+
+ alias->alias_local = 0;
+
+ return stat;
+}
+
+enum nss_status
+_nss_ldap_getaliasbyname_r (const char *name, struct aliasent * result,
+ char *buffer, size_t buflen, int *errnop)
+{
+ LOOKUP_NAME (name, result, buffer, buflen, errnop,
+ _nss_ldap_filt_getaliasbyname, LM_ALIASES,
+ _nss_ldap_parse_alias, LDAP_NSS_BUFLEN_DEFAULT);
+}
+
+enum nss_status _nss_ldap_setaliasent (void)
+{
+ LOOKUP_SETENT (alias_context);
+}
+
+enum nss_status _nss_ldap_endaliasent (void)
+{
+ LOOKUP_ENDENT (alias_context);
+}
+
+enum nss_status
+_nss_ldap_getaliasent_r (struct aliasent *result, char *buffer, size_t buflen,
+ int *errnop)
+{
+ LOOKUP_GETENT (alias_context, result, buffer, buflen, errnop,
+ _nss_ldap_filt_getaliasent, LM_ALIASES,
+ _nss_ldap_parse_alias, LDAP_NSS_BUFLEN_DEFAULT);
+}
+
+#endif /* HAVE_ALIASES_H */
diff --git a/server/automount.c b/server/automount.c
new file mode 100644
index 0000000..1b7b4cb
--- /dev/null
+++ b/server/automount.c
@@ -0,0 +1,395 @@
+/*
+ Copyright (C) 2005 Luke Howard
+ This file is part of the nss_ldap library.
+ Contributed by Luke Howard, <lukeh@padl.com>, 2005.
+
+ The nss_ldap library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The nss_ldap 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the nss_ldap library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ $Id$
+*/
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#ifdef HAVE_LBER_H
+#include <lber.h>
+#endif
+#ifdef HAVE_LDAP_H
+#include <ldap.h>
+#endif
+#if defined(HAVE_THREAD_H)
+#include <thread.h>
+#elif defined(HAVE_PTHREAD_H)
+#include <pthread.h>
+#endif
+
+#include "ldap-nss.h"
+#include "util.h"
+
+/* Linux only for now */
+struct ldap_automount_context {
+ /* Enumeration state */
+ struct ent_context *lac_state;
+
+ /* DNs of containers representing automount map */
+ char **lac_dn_list;
+ size_t lac_dn_size;
+ size_t lac_dn_count;
+ size_t lac_dn_index;
+};
+
+static enum nss_status
+_nss_ldap_parse_automount (LDAPMessage * e,
+ struct ldap_state * pvt,
+ void *result, char *buffer, size_t buflen)
+{
+ enum nss_status stat;
+ char ***keyval = result;
+
+ stat =
+ _nss_ldap_assign_attrval (e, AT (automountKey), keyval[0],
+ &buffer, &buflen);
+ if (stat != NSS_STATUS_SUCCESS)
+ return stat;
+
+ stat =
+ _nss_ldap_assign_attrval (e, AT (automountInformation), keyval[1],
+ &buffer, &buflen);
+ if (stat != NSS_STATUS_SUCCESS)
+ return stat;
+
+ return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status
+_nss_ldap_am_context_alloc(struct ldap_automount_context **pContext)
+{
+ struct ldap_automount_context *context;
+
+ context = (struct ldap_automount_context *)malloc (sizeof(*context));
+ if (context == NULL)
+ {
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ context->lac_state = NULL;
+
+ context->lac_dn_size = 1; /* number of slots allocated */
+ context->lac_dn_count = 0; /* number of slots used */
+ context->lac_dn_index = 0; /* enumeration index */
+
+ /* List of DNs, grown on demand */
+ context->lac_dn_list = (char **)malloc (context->lac_dn_size *
+ sizeof(char *));
+ if (context->lac_dn_list == NULL)
+ {
+ free (context);
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ if (_nss_ldap_ent_context_init_locked (&context->lac_state) == NULL)
+ {
+ free (context->lac_dn_list);
+ free (context);
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ *pContext = context;
+
+ return NSS_STATUS_SUCCESS;
+}
+
+static void
+_nss_ldap_am_context_free(struct ldap_automount_context **pContext)
+{
+ struct ldap_automount_context *context;
+ size_t i;
+
+ context = *pContext;
+
+ if (context == NULL)
+ return;
+
+ if (context->lac_dn_list != NULL)
+ {
+ for (i = 0; i < context->lac_dn_count; i++)
+ {
+#ifdef HAVE_LDAP_MEMFREE
+ ldap_memfree (context->lac_dn_list[i]);
+#else
+ free (context->lac_dn_list[i]);
+#endif /* HAVE_LDAP_MEMFREE */
+ }
+ free (context->lac_dn_list);
+ }
+
+ if (context->lac_state != NULL)
+ {
+ _nss_ldap_ent_context_release (context->lac_state);
+ free (context->lac_state);
+ }
+
+ memset (context, 0, sizeof (*context));
+ free (context);
+
+ *pContext = NULL;
+
+ return;
+}
+
+static enum nss_status
+am_context_add_dn (LDAPMessage * e,
+ struct ldap_state * pvt,
+ void *result, char *buffer, size_t buflen)
+{
+ struct ldap_automount_context *context = (struct ldap_automount_context *) result;
+ char *dn;
+
+ dn = _nss_ldap_get_dn (e);
+ if (dn == NULL)
+ {
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ if (context->lac_dn_count >= context->lac_dn_size)
+ {
+ char **new_dns;
+
+ new_dns = (char **)realloc(context->lac_dn_list,
+ 2 * context->lac_dn_size * sizeof(char *));
+ if (new_dns == NULL)
+ {
+#ifdef HAVE_LDAP_MEMFREE
+ ldap_memfree (dn);
+#else
+ free (dn);
+#endif /* HAVE_LDAP_MEMFREE */
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ context->lac_dn_list = new_dns;
+ context->lac_dn_size *= 2;
+ }
+
+ context->lac_dn_list[context->lac_dn_count++] = dn;
+
+ return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status
+_nss_ldap_am_context_init(const char *mapname, struct ldap_automount_context **pContext)
+{
+ enum nss_status stat;
+ struct ldap_automount_context *context = NULL;
+ const char *no_attrs[] = { NULL };
+ struct ldap_args a;
+ struct ent_context *key = NULL;
+ int errnop;
+
+ *pContext = NULL;
+
+ stat = _nss_ldap_am_context_alloc (&context);
+ if (stat != NSS_STATUS_SUCCESS)
+ return stat;
+
+ LA_INIT (a);
+ LA_TYPE (a) = LA_TYPE_STRING;
+ LA_STRING (a) = mapname;
+
+ do
+ {
+ stat = _nss_ldap_getent_ex (&a, &key,
+ (void *)context,
+ NULL, 0, &errnop,
+ _nss_ldap_filt_setautomntent,
+ LM_AUTOMOUNT,
+ no_attrs,
+ am_context_add_dn);
+ }
+ while (stat == NSS_STATUS_SUCCESS);
+
+ if (key != NULL)
+ {
+ _nss_ldap_ent_context_release (key);
+ free (key);
+ }
+
+ if (context->lac_dn_count == 0)
+ {
+ _nss_ldap_am_context_free (&context);
+ return NSS_STATUS_NOTFOUND;
+ }
+ else if (stat == NSS_STATUS_NOTFOUND)
+ {
+ stat = NSS_STATUS_SUCCESS;
+ }
+
+ context->lac_dn_index = 0;
+
+ *pContext = context;
+ return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status _nss_ldap_setautomntent(const char *mapname, void **private)
+{
+ struct ldap_automount_context *context = NULL;
+ enum nss_status stat;
+
+ debug ("==> _nss_ldap_setautomntent");
+
+ _nss_ldap_enter ();
+
+ stat = _nss_ldap_init ();
+ if (stat != NSS_STATUS_SUCCESS)
+ {
+ _nss_ldap_leave ();
+ debug ("<== _nss_ldap_setautomntent");
+ return stat;
+ }
+
+ stat = _nss_ldap_am_context_init (mapname, &context);
+ if (stat != NSS_STATUS_SUCCESS)
+ {
+ _nss_ldap_leave ();
+ debug ("<== _nss_ldap_setautomntent");
+ return stat;
+ }
+
+ *private = (void *)context;
+ _nss_ldap_leave ();
+
+ debug ("<== _nss_ldap_setautomntent");
+
+ return stat;
+}
+
+enum nss_status _nss_ldap_getautomntent_r(void *private, const char **key, const char **value,
+ char *buffer, size_t buflen, int *errnop)
+{
+ enum nss_status stat;
+ struct ldap_automount_context *context = (struct ldap_automount_context *)private;
+ struct ldap_args a;
+ char **keyval[2];
+
+ if (context == NULL)
+ return NSS_STATUS_NOTFOUND;
+
+ debug ("==> _nss_ldap_getautomntent_r");
+
+ keyval[0] = (char **)key;
+ keyval[1] = (char **)value;
+
+ _nss_ldap_enter ();
+
+ do
+ {
+ assert (context->lac_dn_index < context->lac_dn_count);
+
+ LA_INIT (a);
+ LA_TYPE (a) = LA_TYPE_NONE;
+ LA_BASE (a) = context->lac_dn_list[context->lac_dn_index];
+
+ stat = _nss_ldap_getent_ex (&a, &context->lac_state,
+ (void *)keyval,
+ buffer, buflen, errnop,
+ _nss_ldap_filt_getautomntent,
+ LM_AUTOMOUNT,
+ NULL,
+ _nss_ldap_parse_automount);
+ if (stat == NSS_STATUS_NOTFOUND)
+ {
+ if (context->lac_dn_index < context->lac_dn_count - 1)
+ context->lac_dn_index++;
+ else
+ break; /* move along, nothing more to see here */
+ }
+ }
+ while (stat == NSS_STATUS_NOTFOUND);
+
+ _nss_ldap_leave ();
+
+ debug ("<== _nss_ldap_getautomntent_r");
+
+ return stat;
+}
+
+enum nss_status _nss_ldap_endautomntent(void **private)
+{
+ struct ldap_automount_context **pContext = (struct ldap_automount_context **)private;
+
+ debug ("==> _nss_ldap_endautomntent");
+
+ _nss_ldap_enter ();
+ _nss_ldap_am_context_free (pContext);
+ /* workaround because Linux automounter spawns a lot of processes */
+ _nss_ldap_close ();
+ _nss_ldap_leave ();
+
+ debug ("<== _nss_ldap_endautomntent");
+
+ return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status _nss_ldap_getautomntbyname_r(void *private, const char *key,
+ const char **canon_key, const char **value,
+ char *buffer, size_t buflen, int *errnop)
+{
+ enum nss_status stat = NSS_STATUS_NOTFOUND;
+ struct ldap_automount_context *context = (struct ldap_automount_context *)private;
+ struct ldap_args a;
+ char **keyval[2];
+ size_t i;
+
+ if (context == NULL)
+ return NSS_STATUS_NOTFOUND;
+
+ debug ("==> _nss_ldap_getautomntbyname_r");
+
+ keyval[0] = (char **)canon_key;
+ keyval[1] = (char **)value;
+
+ for (i = 0; i < context->lac_dn_count; i++)
+ {
+ LA_INIT (a);
+ LA_TYPE (a) = LA_TYPE_STRING;
+ LA_STRING (a) = key;
+ LA_BASE (a) = context->lac_dn_list[i];
+
+ /* we do not acquire lock in this case */
+ stat = _nss_ldap_getbyname (&a,
+ (void *)keyval,
+ buffer, buflen, errnop,
+ _nss_ldap_filt_getautomntbyname,
+ LM_AUTOMOUNT,
+ _nss_ldap_parse_automount);
+
+ if (stat != NSS_STATUS_NOTFOUND)
+ {
+ break; /* on success or error other than not found */
+ }
+ }
+
+ debug ("<== _nss_ldap_getautomntbyname_r");
+
+ return stat;
+}
diff --git a/server/ethers.c b/server/ethers.c
new file mode 100644
index 0000000..a6dafe9
--- /dev/null
+++ b/server/ethers.c
@@ -0,0 +1,142 @@
+/*
+ Copyright (C) 1997-2005 Luke Howard
+ This file is part of the nss_ldap library.
+ Contributed by Luke Howard, <lukeh@padl.com>, 1997.
+
+ The nss_ldap library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The nss_ldap 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the nss_ldap library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ $Id$
+*/
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#ifdef HAVE_LBER_H
+#include <lber.h>
+#endif
+#ifdef HAVE_LDAP_H
+#include <ldap.h>
+#endif
+#if defined(HAVE_THREAD_H)
+#include <thread.h>
+#elif defined(HAVE_PTHREAD_H)
+#include <pthread.h>
+#endif
+#ifdef HAVE_NET_ROUTE_H
+#include <net/route.h>
+#endif
+#ifdef HAVE_NETINET_IF_ETHER_H
+#include <netinet/if_ether.h>
+#endif
+#ifdef HAVE_NETINET_ETHER_H
+#include <netinet/ether.h>
+#endif
+
+#include "ldap-nss.h"
+#include "util.h"
+
+/* for HP-UX */
+#ifndef NSS_BUFLEN_ETHERS
+#define NSS_BUFLEN_ETHERS 1024
+#endif /* NSS_BUFLEN_ETHERS */
+
+#ifndef HAVE_STRUCT_ETHER_ADDR
+struct ether_addr {
+ u_char ether_addr_octet[6];
+};
+#endif
+
+struct ether
+{
+ char *e_name;
+ struct ether_addr e_addr;
+};
+
+static struct ent_context *ether_context = NULL;
+
+static enum nss_status
+_nss_ldap_parse_ether (LDAPMessage * e,
+ struct ldap_state * pvt,
+ void *result, char *buffer, size_t buflen)
+{
+ struct ether *ether = (struct ether *) result;
+ char *saddr;
+ enum nss_status stat;
+ struct ether_addr *addr;
+
+ stat = _nss_ldap_assign_attrval (e, ATM (LM_ETHERS, cn),
+ &ether->e_name, &buffer, &buflen);
+ if (stat != NSS_STATUS_SUCCESS)
+ return stat;
+
+ stat = _nss_ldap_assign_attrval (e, AT (macAddress), &saddr,
+ &buffer, &buflen);
+
+ if (stat != NSS_STATUS_SUCCESS || ((addr = ether_aton (saddr)) == NULL))
+ return NSS_STATUS_NOTFOUND;
+
+ memcpy (&ether->e_addr, addr, sizeof (*addr));
+
+ return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_ldap_gethostton_r (const char *name, struct ether * result,
+ char *buffer, size_t buflen, int *errnop)
+{
+ LOOKUP_NAME (name, result, buffer, buflen, errnop,
+ _nss_ldap_filt_gethostton, LM_ETHERS, _nss_ldap_parse_ether,
+ LDAP_NSS_BUFLEN_DEFAULT);
+}
+
+enum nss_status
+_nss_ldap_getntohost_r (struct ether_addr * addr, struct ether * result,
+ char *buffer, size_t buflen, int *errnop)
+{
+/* The correct ether_ntoa call would have a struct ether instead of whatever
+ result->e_addr is */
+
+ LOOKUP_NAME (ether_ntoa ((struct ether_addr *) (&result->e_addr)), result,
+ buffer, buflen, errnop, _nss_ldap_filt_getntohost, LM_ETHERS,
+ _nss_ldap_parse_ether, LDAP_NSS_BUFLEN_DEFAULT);
+}
+
+enum nss_status _nss_ldap_setetherent (void)
+{
+ LOOKUP_SETENT (ether_context);
+}
+
+enum nss_status _nss_ldap_endetherent (void)
+{
+ LOOKUP_ENDENT (ether_context);
+}
+
+enum nss_status
+_nss_ldap_getetherent_r (struct ether * result, char *buffer, size_t buflen,
+ int *errnop)
+{
+ LOOKUP_GETENT (ether_context, result, buffer, buflen, errnop,
+ _nss_ldap_filt_getetherent, LM_ETHERS,
+ _nss_ldap_parse_ether, LDAP_NSS_BUFLEN_DEFAULT);
+}
diff --git a/server/group.c b/server/group.c
new file mode 100644
index 0000000..7eaf4a4
--- /dev/null
+++ b/server/group.c
@@ -0,0 +1,1106 @@
+/*
+ Copyright (C) 1997-2006 Luke Howard
+ This file is part of the nss_ldap library.
+ Contributed by Luke Howard, <lukeh@padl.com>, 1997.
+
+ The nss_ldap library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The nss_ldap 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the nss_ldap library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ $Id$
+*/
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <grp.h>
+#include <errno.h>
+#ifdef HAVE_LBER_H
+#include <lber.h>
+#endif
+#ifdef HAVE_LDAP_H
+#include <ldap.h>
+#endif
+#if defined(HAVE_THREAD_H)
+#include <thread.h>
+#elif defined(HAVE_PTHREAD_H)
+#include <pthread.h>
+#endif
+
+#include "ldap-nss.h"
+#include "util.h"
+
+/* the context to use for {set,get,end}grent() calls */
+static struct ent_context *gr_context = NULL;
+
+#ifdef HAVE_USERSEC_H
+typedef struct ldap_initgroups_args
+{
+ char *grplist;
+ size_t listlen;
+ int depth;
+ struct name_list *known_groups;
+ int backlink;
+}
+ldap_initgroups_args_t;
+#else
+typedef struct ldap_initgroups_args
+{
+ gid_t group;
+ long int *start;
+ long int *size;
+ gid_t **groups;
+ long int limit;
+ int depth;
+ struct name_list *known_groups;
+ int backlink;
+}
+ldap_initgroups_args_t;
+#endif /* HAVE_USERSEC_H */
+
+static enum nss_status
+ng_chase (const char *dn, ldap_initgroups_args_t * lia);
+
+static enum nss_status
+ng_chase_backlink (const char ** membersOf, ldap_initgroups_args_t * lia);
+
+/*
+ * Range retrieval logic was reimplemented from example in
+ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ldap/ldap/searching_using_range_retrieval.asp
+ */
+
+static enum nss_status
+do_parse_range (const char *attributeType,
+ const char *attributeDescription, int *start, int *end)
+{
+ enum nss_status stat = NSS_STATUS_NOTFOUND;
+ char *attribute;
+ size_t attributeTypeLength;
+ size_t attributeDescriptionLength;
+ char *p;
+#ifdef HAVE_STRTOK_R
+ char *st = NULL;
+#endif
+
+ *start = 0;
+ *end = -1;
+
+ if (strcasecmp (attributeType, attributeDescription) == 0)
+ {
+ return NSS_STATUS_SUCCESS;
+ }
+
+ attributeDescriptionLength = strlen (attributeDescription);
+ attributeTypeLength = strlen (attributeType);
+
+ if (attributeDescriptionLength < attributeTypeLength)
+ {
+ /* could not be a subtype */
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ /* XXX need to copy as strtok() is destructive */
+ attribute = strdup (attributeDescription);
+ if (attribute == NULL)
+ {
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+#ifndef HAVE_STRTOK_R
+ for (p = strtok (attribute, ";"); p != NULL; p = strtok (NULL, ";"))
+#else
+ for (p = strtok_r (attribute, ";", &st);
+ p != NULL; p = strtok_r (NULL, ";", &st))
+#endif /* !HAVE_STRTOK_R */
+ {
+ char *q;
+
+ if (p == attribute)
+ {
+ if (strcasecmp (p, attributeType) != 0)
+ {
+ free (attribute);
+ return NSS_STATUS_NOTFOUND;
+ }
+ }
+ else if (strncasecmp (p, "range=", sizeof ("range=") - 1) == 0)
+ {
+ p += sizeof ("range=") - 1;
+
+ q = strchr (p, '-');
+ if (q == NULL)
+ {
+ free (attribute);
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ *q++ = '\0';
+
+ *start = strtoul (p, (char **) NULL, 10);
+ if (strcmp (q, "*") == 0)
+ *end = -1;
+ else
+ *end = strtoul (q, (char **) NULL, 10);
+
+ stat = NSS_STATUS_SUCCESS;
+ break;
+ }
+ }
+
+ free (attribute);
+ return stat;
+}
+
+static enum nss_status
+do_get_range_values (LDAPMessage * e,
+ const char *attributeType,
+ int *start, int *end, char ***pGroupMembers)
+{
+ enum nss_status stat = NSS_STATUS_NOTFOUND;
+ BerElement *ber = NULL;
+ char *attribute;
+
+ *pGroupMembers = NULL;
+
+ for (attribute = _nss_ldap_first_attribute (e, &ber);
+ attribute != NULL; attribute = _nss_ldap_next_attribute (e, ber))
+ {
+ stat = do_parse_range (attributeType, attribute, start, end);
+ if (stat == NSS_STATUS_SUCCESS)
+ {
+ *pGroupMembers = _nss_ldap_get_values (e, attribute);
+ if (*pGroupMembers == NULL)
+ {
+ stat = NSS_STATUS_NOTFOUND;
+ }
+ else if ((*pGroupMembers)[0] == NULL)
+ {
+ ldap_value_free (*pGroupMembers);
+ *pGroupMembers = NULL;
+ stat = NSS_STATUS_NOTFOUND;
+ }
+ }
+
+#ifdef HAVE_LDAP_MEMFREE
+ ldap_memfree (attribute);
+#endif
+
+ if (stat == NSS_STATUS_SUCCESS)
+ break;
+ }
+
+ if (ber != NULL)
+ ber_free (ber, 0);
+
+ return stat;
+}
+
+/*
+ * Format an attribute with description as:
+ * attribute;range=START-END
+ */
+static enum nss_status
+do_construct_range_attribute (const char *attribute,
+ int start,
+ int end,
+ char **buffer,
+ size_t * buflen,
+ const char **pAttributeWithRange)
+{
+ size_t len;
+ char startbuf[32], endbuf[32];
+
+ snprintf (startbuf, sizeof (startbuf), "%u", start);
+
+ if (end != -1)
+ snprintf (endbuf, sizeof (endbuf), "%u", end);
+ else
+ snprintf (endbuf, sizeof (endbuf), "*");
+
+ len = strlen (attribute) + sizeof (";range=") - 1;
+ len += strlen (startbuf) + 1 /* - */ + strlen (endbuf);
+ len++; /* \0 */
+
+ if (*buflen < len)
+ return NSS_STATUS_TRYAGAIN;
+
+ *pAttributeWithRange = *buffer;
+
+ snprintf (*buffer, len, "%s;range=%s-%s", attribute, startbuf, endbuf);
+
+ *buffer += len;
+ *buflen -= len;
+
+ return NSS_STATUS_SUCCESS;
+}
+
+/*
+ * Expand group members, including nested groups
+ */
+static enum nss_status
+do_parse_group_members (LDAPMessage * e,
+ char ***pGroupMembers,
+ size_t * pGroupMembersCount,
+ size_t * pGroupMembersBufferSize,
+ int *pGroupMembersBufferIsMalloced,
+ char **buffer, size_t * buflen,
+ int *depth,
+ struct name_list **pKnownGroups) /* traversed groups */
+{
+ enum nss_status stat = NSS_STATUS_SUCCESS;
+ char **dnValues = NULL;
+ char **uidValues = NULL;
+ char **groupMembers;
+ size_t groupMembersCount, i;
+ char **valiter;
+ /* support for range retrieval */
+ const char *uniquemember_attr;
+ const char *uniquemember_attrs[2];
+ LDAPMessage *res = NULL;
+ int start, end = 0;
+ char *groupdn = NULL;
+
+ uniquemember_attr = ATM (LM_GROUP, uniqueMember);
+
+ uniquemember_attrs[0] = uniquemember_attr;
+ uniquemember_attrs[1] = NULL;
+
+ if (*depth > LDAP_NSS_MAXGR_DEPTH)
+ {
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ i = *pGroupMembersCount; /* index of next member */
+ groupMembers = *pGroupMembers;
+
+ groupdn = _nss_ldap_get_dn (e);
+ if (groupdn == NULL)
+ {
+ stat = NSS_STATUS_NOTFOUND;
+ goto out;
+ }
+
+ if (_nss_ldap_namelist_find (*pKnownGroups, groupdn))
+ {
+ stat = NSS_STATUS_NOTFOUND;
+ goto out;
+ }
+
+ /* store group DN for nested group loop detection */
+ stat = _nss_ldap_namelist_push (pKnownGroups, groupdn);
+ if (stat != NSS_STATUS_SUCCESS)
+ {
+ goto out;
+ }
+
+ do
+ {
+ if (e == NULL)
+ {
+ stat = NSS_STATUS_NOTFOUND;
+ goto out;
+ }
+
+ groupMembersCount = 0; /* number of members in this group */
+
+ (void) do_get_range_values (e, uniquemember_attrs[0], &start, &end, &dnValues);
+ if (dnValues != NULL)
+ {
+ groupMembersCount += ldap_count_values (dnValues);
+ }
+
+ uidValues = _nss_ldap_get_values (e, ATM (LM_GROUP, memberUid));
+ if (uidValues != NULL)
+ {
+ groupMembersCount += ldap_count_values (uidValues);
+ }
+
+ /*
+ * Check whether we need to increase the group membership buffer.
+ * As an optimization the buffer is preferentially allocated off
+ * the stack
+ */
+ if ((i + groupMembersCount) * sizeof (char *) >=
+ *pGroupMembersBufferSize)
+ {
+ *pGroupMembersBufferSize =
+ (i + groupMembersCount + 1) * sizeof (char *);
+ *pGroupMembersBufferSize +=
+ (LDAP_NSS_NGROUPS * sizeof (char *)) - 1;
+ *pGroupMembersBufferSize -=
+ (*pGroupMembersBufferSize %
+ (LDAP_NSS_NGROUPS * sizeof (char *)));
+
+ if (*pGroupMembersBufferIsMalloced == 0)
+ {
+ groupMembers = *pGroupMembers;
+ *pGroupMembers = NULL; /* force malloc() */
+ }
+
+ *pGroupMembers =
+ (char **) realloc (*pGroupMembers, *pGroupMembersBufferSize);
+ if (*pGroupMembers == NULL)
+ {
+ *pGroupMembersBufferIsMalloced = 0; /* don't try to free */
+ stat = NSS_STATUS_TRYAGAIN;
+ goto out;
+ }
+
+ if (*pGroupMembersBufferIsMalloced == 0)
+ {
+ memcpy (*pGroupMembers, groupMembers, i * sizeof (char *));
+ groupMembers = NULL; /* defensive programming */
+ *pGroupMembersBufferIsMalloced = 1;
+ }
+ }
+
+ groupMembers = *pGroupMembers;
+
+ /* Parse distinguished name members */
+ if (dnValues != NULL)
+ {
+ for (valiter = dnValues; *valiter != NULL; valiter++)
+ {
+ LDAPMessage *res;
+ enum nss_status parseStat;
+ int isNestedGroup = 0;
+ char *uid;
+
+ uid = strrchr (*valiter, '#');
+ if (uid != NULL)
+ {
+ *uid = '\0';
+ }
+
+ parseStat = _nss_ldap_dn2uid (*valiter, &groupMembers[i],
+ buffer, buflen, &isNestedGroup,
+ &res);
+ if (parseStat == NSS_STATUS_SUCCESS)
+ {
+ if (isNestedGroup == 0)
+ {
+ /* just a normal user which we have flattened */
+ i++;
+ continue;
+ }
+
+ (*depth)++;
+ parseStat =
+ do_parse_group_members (_nss_ldap_first_entry (res),
+ &groupMembers, &i,
+ pGroupMembersBufferSize,
+ pGroupMembersBufferIsMalloced,
+ buffer, buflen, depth,
+ pKnownGroups);
+ (*depth)--;
+
+ if (parseStat == NSS_STATUS_TRYAGAIN)
+ {
+ stat = NSS_STATUS_TRYAGAIN;
+ goto out;
+ }
+
+ ldap_msgfree (res);
+ }
+ else if (parseStat == NSS_STATUS_TRYAGAIN)
+ {
+ stat = NSS_STATUS_TRYAGAIN;
+ goto out;
+ }
+ }
+ }
+
+ /* Parse RFC 2307 (flat) members */
+ if (uidValues != NULL)
+ {
+ for (valiter = uidValues; *valiter != NULL; valiter++)
+ {
+ size_t len = strlen (*valiter) + 1;
+ if (*buflen < len)
+ {
+ stat = NSS_STATUS_TRYAGAIN;
+ goto out;
+ }
+ groupMembers[i] = *buffer;
+ *buffer += len;
+ *buflen -= len;
+
+ memcpy (groupMembers[i++], *valiter, len);
+ }
+ }
+
+ /* Get next range for Active Directory compat */
+ if (end != -1)
+ {
+ stat = do_construct_range_attribute (uniquemember_attr,
+ end + 1,
+ -1,
+ buffer,
+ buflen,
+ &uniquemember_attrs[0]);
+ if (stat == NSS_STATUS_SUCCESS)
+ {
+ if (dnValues != NULL)
+ {
+ ldap_value_free (dnValues);
+ dnValues = NULL;
+ }
+ if (uidValues != NULL)
+ {
+ ldap_value_free (uidValues);
+ uidValues = NULL;
+ }
+ if (res != NULL)
+ {
+ ldap_msgfree (res);
+ res = NULL;
+ }
+
+ stat = _nss_ldap_read (groupdn, uniquemember_attrs, &res);
+ if (stat != NSS_STATUS_SUCCESS)
+ goto out;
+
+ e = _nss_ldap_first_entry (res);
+ }
+ }
+ }
+ while (end != -1);
+
+out:
+ if (dnValues != NULL)
+ ldap_value_free (dnValues);
+ if (uidValues != NULL)
+ ldap_value_free (uidValues);
+ if (res != NULL)
+ ldap_msgfree (res);
+ if (groupdn != NULL)
+#ifdef HAVE_LDAP_MEMFREE
+ ldap_memfree (groupdn);
+#else
+ free (groupdn);
+#endif
+
+ *pGroupMembers = groupMembers;
+ *pGroupMembersCount = i;
+
+ return stat;
+}
+
+/*
+ * "Fix" group membership list into caller provided buffer,
+ * and NULL terminate.
+*/
+static enum nss_status
+do_fix_group_members_buffer (char **mallocedGroupMembers,
+ size_t groupMembersCount,
+ char ***pGroupMembers,
+ char **buffer, size_t * buflen)
+{
+ size_t len;
+
+ len = (groupMembersCount + 1) * sizeof (char *);
+
+ if (bytesleft (*buffer, *buflen, char *) < len)
+ {
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ align (*buffer, *buflen, char *);
+ *pGroupMembers = (char **) *buffer;
+ *buffer += len;
+ *buflen -= len;
+
+ memcpy (*pGroupMembers, mallocedGroupMembers,
+ groupMembersCount * sizeof (char *));
+ (*pGroupMembers)[groupMembersCount] = NULL;
+
+ return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status
+_nss_ldap_parse_gr (LDAPMessage * e,
+ struct ldap_state * pvt,
+ void *result, char *buffer, size_t buflen)
+{
+ struct group *gr = (struct group *) result;
+ char *gid;
+ enum nss_status stat;
+ char **groupMembers;
+ size_t groupMembersCount;
+ size_t groupMembersBufferSize;
+ char *groupMembersBuffer[LDAP_NSS_NGROUPS];
+ int groupMembersBufferIsMalloced;
+ int depth;
+ struct name_list *knownGroups = NULL;
+
+ stat =
+ _nss_ldap_assign_attrval (e, ATM (LM_GROUP, gidNumber), &gid, &buffer,
+ &buflen);
+ if (stat != NSS_STATUS_SUCCESS)
+ return stat;
+
+ gr->gr_gid =
+ (*gid == '\0') ? (unsigned) GID_NOBODY : (gid_t) strtoul (gid,
+ (char **) NULL,
+ 10);
+
+ stat =
+ _nss_ldap_getrdnvalue (e, ATM (LM_GROUP, cn), &gr->gr_name, &buffer,
+ &buflen);
+ if (stat != NSS_STATUS_SUCCESS)
+ return stat;
+
+ stat =
+ _nss_ldap_assign_userpassword (e, ATM (LM_GROUP, userPassword),
+ &gr->gr_passwd, &buffer, &buflen);
+ if (stat != NSS_STATUS_SUCCESS)
+ return stat;
+
+ if (_nss_ldap_test_config_flag (NSS_LDAP_FLAGS_RFC2307BIS))
+ {
+ groupMembers = groupMembersBuffer;
+ groupMembersCount = 0;
+ groupMembersBufferSize = sizeof (groupMembers);
+ groupMembersBufferIsMalloced = 0;
+ depth = 0;
+
+ stat = do_parse_group_members (e, &groupMembers, &groupMembersCount,
+ &groupMembersBufferSize,
+ &groupMembersBufferIsMalloced, &buffer,
+ &buflen, &depth, &knownGroups);
+ if (stat != NSS_STATUS_SUCCESS)
+ {
+ if (groupMembersBufferIsMalloced)
+ free (groupMembers);
+ _nss_ldap_namelist_destroy (&knownGroups);
+ return stat;
+ }
+
+ stat = do_fix_group_members_buffer (groupMembers, groupMembersCount,
+ &gr->gr_mem, &buffer, &buflen);
+
+ if (groupMembersBufferIsMalloced)
+ free (groupMembers);
+ _nss_ldap_namelist_destroy (&knownGroups);
+ }
+ else
+ {
+ stat =
+ _nss_ldap_assign_attrvals (e, ATM (LM_GROUP, memberUid), NULL,
+ &gr->gr_mem, &buffer, &buflen, NULL);
+ }
+
+ return stat;
+}
+
+/*
+ * Add a group ID to a group list, and optionally the group IDs
+ * of any groups to which this group belongs (RFC2307bis nested
+ * group expansion is done by do_parse_initgroups_nested()).
+ */
+static enum nss_status
+do_parse_initgroups (LDAPMessage * e,
+ struct ldap_state * pvt, void *result,
+ char *buffer, size_t buflen)
+{
+ char **values;
+ ssize_t i;
+ gid_t gid;
+ ldap_initgroups_args_t *lia = (ldap_initgroups_args_t *) result;
+
+ values = _nss_ldap_get_values (e, ATM (LM_GROUP, gidNumber));
+ if (values == NULL)
+ {
+ /* invalid group; skip it */
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ if (values[0] == NULL)
+ {
+ /* invalid group; skip it */
+ ldap_value_free (values);
+ return NSS_STATUS_NOTFOUND;
+ }
+
+#ifdef HAVE_USERSEC_H
+ i = strlen (values[0]);
+ lia->grplist = realloc (lia->grplist, lia->listlen + i + 2);
+ if (lia->grplist == NULL)
+ {
+ ldap_value_free (values);
+ return NSS_STATUS_TRYAGAIN;
+ }
+ memcpy (lia->grplist + lia->listlen, values[0], i);
+ lia->grplist[lia->listlen + i] = ',';
+ lia->listlen += i + 1;
+ ldap_value_free (values);
+#else
+ gid = strtoul (values[0], (char **) NULL, 10);
+ ldap_value_free (values);
+
+ if (gid == LONG_MAX && errno == ERANGE)
+ {
+ /* invalid group, skip it */
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ if (gid == lia->group)
+ {
+ /* primary group, so skip it */
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ if (lia->limit > 0)
+ {
+ if (*(lia->start) >= lia->limit)
+ {
+ /* can't fit any more */
+ return NSS_STATUS_TRYAGAIN;
+ }
+ }
+ if (*(lia->start) == *(lia->size))
+ {
+ /* Need a bigger buffer */
+ *(lia->groups) = (gid_t *) realloc (*(lia->groups),
+ 2 * *(lia->size) * sizeof (gid_t));
+ if (*(lia->groups) == NULL)
+ {
+ return NSS_STATUS_TRYAGAIN;
+ }
+ *(lia->size) *= 2;
+ }
+
+ /* weed out duplicates; is this really our responsibility? */
+ for (i = 0; i < *(lia->start); i++)
+ {
+ if ((*(lia->groups))[i] == gid)
+ {
+ return NSS_STATUS_NOTFOUND;
+ }
+ }
+
+ /* add to group list */
+ (*(lia->groups))[*(lia->start)] = gid;
+ (*(lia->start)) += 1;
+#endif /* HAVE_USERSEC_H */
+
+ return NSS_STATUS_NOTFOUND;
+}
+
+static enum nss_status
+do_parse_initgroups_nested (LDAPMessage * e,
+ struct ldap_state * pvt, void *result,
+ char *buffer, size_t buflen)
+{
+ enum nss_status status;
+ ldap_initgroups_args_t *lia = (ldap_initgroups_args_t *) result;
+ char **values;
+ char *groupdn;
+
+ status = do_parse_initgroups (e, pvt, result, buffer, buflen);
+ if (status != NSS_STATUS_NOTFOUND)
+ {
+ return status;
+ }
+
+ if (!_nss_ldap_test_config_flag (NSS_LDAP_FLAGS_RFC2307BIS))
+ {
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ if (lia->backlink != 0)
+ {
+ /*
+ * Now add the GIDs of any groups of which this group is
+ * a member.
+ */
+ values = _nss_ldap_get_values (e, ATM (LM_GROUP, memberOf));
+ if (values != NULL)
+ {
+ lia->depth++;
+ status = ng_chase_backlink ((const char **)values, lia);
+ lia->depth--;
+
+ ldap_value_free (values);
+
+ return status;
+ }
+ }
+ else
+ {
+ /*
+ * Now add the GIDs of any groups which refer to this group
+ */
+ groupdn = _nss_ldap_get_dn (e);
+ if (groupdn != NULL)
+ {
+ /* Note: there was a problem here with stat in the orriginal code */
+ lia->depth++;
+ status = ng_chase (groupdn, lia);
+ lia->depth--;
+#ifdef HAVE_LDAP_MEMFREE
+ ldap_memfree (groupdn);
+#else
+ free (groupdn);
+#endif
+ }
+ }
+
+ return status;
+}
+
+static enum nss_status
+ng_chase (const char *dn, ldap_initgroups_args_t * lia)
+{
+ struct ldap_args a;
+ enum nss_status stat;
+ struct ent_context *ctx = NULL;
+ const char *gidnumber_attrs[2];
+ int erange;
+
+ if (lia->depth > LDAP_NSS_MAXGR_DEPTH)
+ return NSS_STATUS_NOTFOUND;
+
+ if (_nss_ldap_namelist_find (lia->known_groups, dn))
+ return NSS_STATUS_NOTFOUND;
+
+ gidnumber_attrs[0] = ATM (LM_GROUP, gidNumber);
+ gidnumber_attrs[1] = NULL;
+
+ LA_INIT (a);
+ LA_STRING (a) = dn;
+ LA_TYPE (a) = LA_TYPE_STRING;
+
+ if (_nss_ldap_ent_context_init_locked (&ctx) == NULL)
+ {
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ stat = _nss_ldap_getent_ex (&a, &ctx, lia, NULL, 0,
+ &erange, _nss_ldap_filt_getgroupsbydn,
+ LM_GROUP, gidnumber_attrs,
+ do_parse_initgroups_nested);
+
+ if (stat == NSS_STATUS_SUCCESS)
+ {
+ stat = _nss_ldap_namelist_push (&lia->known_groups, dn);
+ }
+
+ _nss_ldap_ent_context_release (ctx);
+ free (ctx);
+
+ return stat;
+}
+
+static enum nss_status
+ng_chase_backlink (const char ** membersOf, ldap_initgroups_args_t * lia)
+{
+ struct ldap_args a;
+ enum nss_status stat;
+ struct ent_context *ctx = NULL;
+ const char *gidnumber_attrs[3];
+ const char **memberP;
+ const char **filteredMembersOf; /* remove already traversed groups */
+ size_t memberCount, i;
+ int erange;
+
+ if (lia->depth > LDAP_NSS_MAXGR_DEPTH)
+ return NSS_STATUS_NOTFOUND;
+
+ for (memberCount = 0; membersOf[memberCount] != NULL; memberCount++)
+ ;
+
+ /* Build a list of membersOf values without any already traversed groups */
+ filteredMembersOf = (const char **) malloc(sizeof(char *) * (memberCount + 1));
+ if (filteredMembersOf == NULL)
+ {
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ memberP = filteredMembersOf;
+
+ for (i = 0; i < memberCount; i++)
+ {
+ if (_nss_ldap_namelist_find (lia->known_groups, membersOf[i]))
+ continue;
+
+ *memberP = membersOf[i];
+ memberP++;
+ }
+
+ *memberP = NULL;
+
+ if (filteredMembersOf[0] == NULL)
+ {
+ free (filteredMembersOf);
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ gidnumber_attrs[0] = ATM (LM_GROUP, gidNumber);
+ gidnumber_attrs[1] = ATM (LM_GROUP, memberOf);
+ gidnumber_attrs[2] = NULL;
+
+ LA_INIT (a);
+ LA_STRING_LIST (a) = filteredMembersOf;
+ LA_TYPE (a) = LA_TYPE_STRING_LIST_OR;
+
+ if (_nss_ldap_ent_context_init_locked (&ctx) == NULL)
+ {
+ free (filteredMembersOf);
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ stat = _nss_ldap_getent_ex (&a, &ctx, lia, NULL, 0,
+ &erange, "(distinguishedName=%s)",
+ LM_GROUP, gidnumber_attrs,
+ do_parse_initgroups_nested);
+
+ if (stat == NSS_STATUS_SUCCESS)
+ {
+ enum nss_status stat2;
+
+ for (memberP = filteredMembersOf; *memberP != NULL; memberP++)
+ {
+ stat2 = _nss_ldap_namelist_push (&lia->known_groups, *memberP);
+ if (stat2 != NSS_STATUS_SUCCESS)
+ {
+ stat = stat2;
+ break;
+ }
+ }
+ }
+
+ free (filteredMembersOf);
+
+ _nss_ldap_ent_context_release (ctx);
+ free (ctx);
+
+ return stat;
+}
+
+
+#define NSS_LDAP_INITGROUPS_FUNCTION "_nss_ldap_initgroups_dyn"
+
+enum nss_status _nss_ldap_initgroups_dyn (const char *user, gid_t group, long int *start,
+ long int *size, gid_t ** groupsp, long int limit,
+ int *errnop)
+{
+ ldap_initgroups_args_t lia;
+ int erange = 0;
+ char *userdn = NULL;
+ LDAPMessage *res, *e;
+ static const char *no_attrs[] = { NULL };
+ const char *filter;
+ struct ldap_args a;
+ enum nss_status stat;
+ struct ent_context *ctx = NULL;
+ const char *gidnumber_attrs[3];
+ enum ldap_map_selector map = LM_GROUP;
+
+ LA_INIT (a);
+ LA_STRING (a) = user;
+ LA_TYPE (a) = LA_TYPE_STRING;
+
+ debug ("==> " NSS_LDAP_INITGROUPS_FUNCTION " (user=%s)", LA_STRING (a) );
+
+#ifdef INITGROUPS_ROOT_ONLY
+ /* XXX performance hack for old versions of KDE only */
+ if ((getuid() != 0) && (geteuid() != 0))
+ return NSS_STATUS_NOTFOUND;
+#endif
+
+#ifdef HAVE_USERSEC_H
+ lia.grplist = NULL;
+ lia.listlen = 0;
+ lia.group = group;
+ lia.start = start;
+ lia.size = size;
+ lia.groups = groupsp;
+ lia.limit = limit;
+#endif /* HAVE_USERSEC_H */
+ lia.depth = 0;
+ lia.known_groups = NULL;
+
+ _nss_ldap_enter ();
+
+ /* initialize schema */
+ stat = _nss_ldap_init ();
+ if (stat != NSS_STATUS_SUCCESS)
+ {
+ debug ("<== " NSS_LDAP_INITGROUPS_FUNCTION " (init failed)");
+ _nss_ldap_leave ();
+#ifdef HAVE_USERSEC_H
+ return NULL;
+#else
+ return stat;
+#endif /* !HAVE_USERSEC_H */
+ }
+
+ if (_nss_ldap_test_initgroups_ignoreuser (LA_STRING (a)))
+ {
+ debug ("<== " NSS_LDAP_INITGROUPS_FUNCTION " (user ignored)");
+ _nss_ldap_leave ();
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ lia.backlink = _nss_ldap_test_config_flag (NSS_LDAP_FLAGS_INITGROUPS_BACKLINK);
+
+ if (lia.backlink != 0)
+ {
+ filter = _nss_ldap_filt_getpwnam_groupsbymember;
+ LA_STRING2 (a) = LA_STRING (a);
+ LA_TYPE (a) = LA_TYPE_STRING_AND_STRING;
+
+ gidnumber_attrs[0] = ATM (LM_GROUP, gidNumber);
+ gidnumber_attrs[1] = ATM (LM_GROUP, memberOf);
+ gidnumber_attrs[2] = NULL;
+
+ map = LM_PASSWD;
+ }
+ else
+ {
+ if (_nss_ldap_test_config_flag (NSS_LDAP_FLAGS_RFC2307BIS))
+ {
+ /* lookup the user's DN. */
+ stat = _nss_ldap_search_s (&a, _nss_ldap_filt_getpwnam, LM_PASSWD,
+ no_attrs, 1, &res);
+ if (stat == NSS_STATUS_SUCCESS)
+ {
+ e = _nss_ldap_first_entry (res);
+ if (e != NULL)
+ {
+ userdn = _nss_ldap_get_dn (e);
+ }
+ ldap_msgfree (res);
+ }
+ }
+ else
+ {
+ userdn = NULL;
+ }
+
+ if (userdn != NULL)
+ {
+ LA_STRING2 (a) = userdn;
+ LA_TYPE (a) = LA_TYPE_STRING_AND_STRING;
+ filter = _nss_ldap_filt_getgroupsbymemberanddn;
+ }
+ else
+ {
+ filter = _nss_ldap_filt_getgroupsbymember;
+ }
+
+ gidnumber_attrs[0] = ATM (LM_GROUP, gidNumber);
+ gidnumber_attrs[1] = NULL;
+ }
+
+ if (_nss_ldap_ent_context_init_locked (&ctx) == NULL)
+ {
+ debug ("<== " NSS_LDAP_INITGROUPS_FUNCTION " (ent_context_init failed)");
+ _nss_ldap_leave ();
+#ifdef HAVE_USERSEC_H
+ return NULL;
+#else
+ return NSS_STATUS_UNAVAIL;
+#endif /* HAVE_USERSEC_H */
+ }
+
+ stat = _nss_ldap_getent_ex (&a, &ctx, (void *) &lia, NULL, 0,
+ errnop,
+ filter,
+ map,
+ gidnumber_attrs,
+ do_parse_initgroups_nested);
+
+ if (userdn != NULL)
+ {
+#ifdef HAVE_LDAP_MEMFREE
+ ldap_memfree (userdn);
+#else
+ free (userdn);
+#endif /* HAVE_LDAP_MEMFREE */
+ }
+
+ _nss_ldap_namelist_destroy (&lia.known_groups);
+ _nss_ldap_ent_context_release (ctx);
+ free (ctx);
+ _nss_ldap_leave ();
+
+ /*
+ * We return NSS_STATUS_NOTFOUND to force the parser to be called
+ * for as many entries (i.e. groups) as exist, for all
+ * search descriptors. So confusingly this means "success".
+ */
+ if (stat != NSS_STATUS_SUCCESS && stat != NSS_STATUS_NOTFOUND)
+ {
+ debug ("<== " NSS_LDAP_INITGROUPS_FUNCTION " (not found)");
+ if (erange)
+ errno = ERANGE;
+#ifndef HAVE_USERSEC_H
+ return stat;
+#else
+ return NULL;
+#endif /* HAVE_USERSEC_H */
+ }
+
+ debug ("<== " NSS_LDAP_INITGROUPS_FUNCTION " (success)");
+
+ return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status _nss_ldap_initgroups (const char *user, gid_t group, long int *start,
+ long int *size, gid_t * groups, long int limit,
+ int *errnop)
+{
+ return (_nss_ldap_initgroups_dyn (user, group, start, size, &groups, limit,
+ errnop));
+}
+
+enum nss_status _nss_ldap_getgrnam_r (const char *name,
+ struct group * result,
+ char *buffer, size_t buflen, int *errnop)
+{
+ LOOKUP_NAME (name, result, buffer, buflen, errnop, _nss_ldap_filt_getgrnam,
+ LM_GROUP, _nss_ldap_parse_gr, LDAP_NSS_BUFLEN_GROUP);
+}
+
+enum nss_status _nss_ldap_getgrgid_r (gid_t gid,
+ struct group *result,
+ char *buffer, size_t buflen, int *errnop)
+{
+ LOOKUP_NUMBER (gid, result, buffer, buflen, errnop, _nss_ldap_filt_getgrgid,
+ LM_GROUP, _nss_ldap_parse_gr, LDAP_NSS_BUFLEN_GROUP);
+}
+
+enum nss_status _nss_ldap_setgrent (void)
+{
+ LOOKUP_SETENT (gr_context);
+}
+
+enum nss_status _nss_ldap_getgrent_r (struct group *result,
+ char *buffer, size_t buflen, int *errnop)
+{
+ LOOKUP_GETENT (gr_context, result, buffer, buflen, errnop,
+ _nss_ldap_filt_getgrent, LM_GROUP, _nss_ldap_parse_gr,
+ LDAP_NSS_BUFLEN_GROUP);
+}
+
+enum nss_status _nss_ldap_endgrent (void)
+{
+ LOOKUP_ENDENT (gr_context);
+}
diff --git a/server/hosts.c b/server/hosts.c
new file mode 100644
index 0000000..935c857
--- /dev/null
+++ b/server/hosts.c
@@ -0,0 +1,328 @@
+/*
+ Copyright (C) 1997-2005 Luke Howard
+ This file is part of the nss_ldap library.
+ Contributed by Luke Howard, <lukeh@padl.com>, 1997.
+
+ The nss_ldap library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The nss_ldap 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the nss_ldap library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ $Id$
+*/
+
+#include "config.h"
+
+#include <sys/socket.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#ifdef HAVE_LBER_H
+#include <lber.h>
+#endif
+#ifdef HAVE_LDAP_H
+#include <ldap.h>
+#endif
+#if defined(HAVE_THREAD_H)
+#include <thread.h>
+#elif defined(HAVE_PTHREAD_H)
+#include <pthread.h>
+#endif
+#ifdef INET6
+#include <resolv/mapv4v6addr.h>
+#endif
+
+#include "ldap-nss.h"
+#include "util.h"
+
+#ifndef MAXALIASES
+#define MAXALIASES 35
+#endif
+
+static struct ent_context *hosts_context = NULL;
+
+static enum nss_status
+_nss_ldap_parse_host (LDAPMessage * e,
+ struct ldap_state * pvt,
+ void *result, char *buffer, size_t buflen,
+ int af)
+{
+ /* this code needs reviewing. XXX */
+ struct hostent *host = (struct hostent *) result;
+ enum nss_status stat;
+#ifdef INET6
+ char addressbuf[sizeof ("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") *
+ MAXALIASES];
+#else
+ char addressbuf[sizeof ("255.255.255.255") * MAXALIASES];
+#endif
+ char *p_addressbuf = addressbuf;
+ char **addresses = NULL;
+ size_t addresslen = sizeof (addressbuf);
+ size_t addresscount = 0;
+ char **host_addresses = NULL;
+ int i;
+
+ *addressbuf = *buffer = '\0';
+
+ stat = _nss_ldap_assign_attrval (e, ATM (LM_HOSTS, cn), &host->h_name,
+ &buffer, &buflen);
+ if (stat != NSS_STATUS_SUCCESS)
+ return stat;
+
+ stat =
+ _nss_ldap_assign_attrvals (e, ATM (LM_HOSTS, cn), host->h_name,
+ &host->h_aliases, &buffer, &buflen, NULL);
+ if (stat != NSS_STATUS_SUCCESS)
+ return stat;
+
+ stat =
+ _nss_ldap_assign_attrvals (e, AT (ipHostNumber), NULL, &addresses,
+ &p_addressbuf, &addresslen, &addresscount);
+ if (stat != NSS_STATUS_SUCCESS)
+ return stat;
+ if (addresscount == 0)
+ return NSS_STATUS_NOTFOUND;
+
+#ifdef INET6
+ if (af == AF_INET6)
+ {
+ if (bytesleft (buffer, buflen, char *) <
+ (size_t) ((addresscount + 1) * IN6ADDRSZ))
+ return NSS_STATUS_TRYAGAIN;
+ }
+ else
+ {
+ if (bytesleft (buffer, buflen, char *) <
+ (size_t) ((addresscount + 1) * INADDRSZ))
+ return NSS_STATUS_TRYAGAIN;
+ }
+#else
+ if (bytesleft (buffer, buflen, char *) <
+ (size_t) ((addresscount + 1) * INADDRSZ))
+ return NSS_STATUS_TRYAGAIN;
+#endif
+
+ align (buffer, buflen, char *);
+ host_addresses = (char **) buffer;
+ host->h_addr_list = host_addresses;
+ host_addresses[addresscount] = NULL;
+
+ buffer += (addresscount + 1) * sizeof (char *);
+ buflen -= (addresscount + 1) * sizeof (char *);
+#ifdef INET6
+ host->h_addrtype = 0;
+ host->h_length = 0;
+#else
+ host->h_addrtype = AF_INET;
+ host->h_length = INADDRSZ;
+#endif
+
+ for (i = 0; i < (int) addresscount; i++)
+ {
+#ifdef INET6
+ char *addr = addresses[i];
+ char entdata[16];
+ /* from glibc NIS parser. Thanks, Uli. */
+
+ if (af == AF_INET && inet_pton (AF_INET, addr, entdata) > 0)
+ {
+ if (_res.options & RES_USE_INET6)
+ {
+ map_v4v6_address ((char *) entdata,
+ (char *) entdata);
+ host->h_addrtype = AF_INET6;
+ host->h_length = IN6ADDRSZ;
+ }
+ else
+ {
+ host->h_addrtype = AF_INET;
+ host->h_length = INADDRSZ;
+ }
+ }
+ else if (af == AF_INET6
+ && inet_pton (AF_INET6, addr, entdata) > 0)
+ {
+ host->h_addrtype = AF_INET6;
+ host->h_length = IN6ADDRSZ;
+ }
+ else
+ /* Illegal address: ignore line. */
+ continue;
+
+#else
+ unsigned long haddr;
+ haddr = inet_addr (addresses[i]);
+#endif
+
+ if (buflen < (size_t) host->h_length)
+ return NSS_STATUS_TRYAGAIN;
+
+#ifdef INET6
+ memcpy (buffer, entdata, host->h_length);
+ *host_addresses = buffer;
+ buffer += host->h_length;
+ buflen -= host->h_length;
+#else
+ memcpy (buffer, &haddr, INADDRSZ);
+ *host_addresses = buffer;
+ buffer += INADDRSZ;
+ buflen -= INADDRSZ;
+#endif
+
+ host_addresses++;
+ *host_addresses = NULL;
+ }
+
+#ifdef INET6
+ /* if host->h_addrtype is not changed, this entry does not
+ have the right IP address. */
+ if (host->h_addrtype == 0)
+ return NSS_STATUS_NOTFOUND;
+#endif
+
+ return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status
+_nss_ldap_parse_hostv4 (LDAPMessage * e,
+ struct ldap_state * pvt,
+ void *result, char *buffer, size_t buflen)
+{
+ return _nss_ldap_parse_host (e, pvt, result, buffer, buflen,
+ AF_INET);
+}
+
+#ifdef INET6
+static enum nss_status
+_nss_ldap_parse_hostv6 (LDAPMessage * e,
+ struct ldap_state * pvt,
+ void *result, char *buffer, size_t buflen)
+{
+ return _nss_ldap_parse_host (e, pvt, result, buffer, buflen,
+ AF_INET6);
+}
+#endif
+
+enum nss_status _nss_ldap_gethostbyname2_r (const char *name, int af, struct hostent * result,
+ char *buffer, size_t buflen, int *errnop,
+ int *h_errnop)
+{
+ enum nss_status status;
+ struct ldap_args a;
+
+ LA_INIT (a);
+ LA_STRING (a) = name;
+ LA_TYPE (a) = LA_TYPE_STRING;
+
+ status = _nss_ldap_getbyname (&a,
+ result,
+ buffer,
+ buflen,
+ errnop,
+ _nss_ldap_filt_gethostbyname,
+ LM_HOSTS,
+#ifdef INET6
+ (af == AF_INET6) ?
+ _nss_ldap_parse_hostv6 :
+#endif
+ _nss_ldap_parse_hostv4);
+
+ MAP_H_ERRNO (status, *h_errnop);
+
+ return status;
+}
+
+enum nss_status _nss_ldap_gethostbyname_r (const char *name, struct hostent * result,
+ char *buffer, size_t buflen, int *errnop,
+ int *h_errnop)
+{
+ return _nss_ldap_gethostbyname2_r (name,
+#ifdef INET6
+ (_res.options & RES_USE_INET6) ?
+ AF_INET6 :
+#endif
+ AF_INET, result, buffer, buflen,
+ errnop, h_errnop);
+}
+
+enum nss_status _nss_ldap_gethostbyaddr_r (struct in_addr * addr, int len, int type,
+ struct hostent * result, char *buffer,
+ size_t buflen, int *errnop, int *h_errnop)
+{
+ enum nss_status status;
+ struct ldap_args a;
+
+ /* if querying by IPv6 address, make sure the address is "normalized" --
+ * it should contain no leading zeros and all components of the address.
+ * still we can't fit an IPv6 address in an int, so who cares for now.
+ */
+
+ LA_INIT (a);
+ LA_STRING (a) = inet_ntoa (*addr);
+ LA_TYPE (a) = LA_TYPE_STRING;
+
+ status = _nss_ldap_getbyname (&a,
+ result,
+ buffer,
+ buflen,
+ errnop,
+ _nss_ldap_filt_gethostbyaddr,
+ LM_HOSTS,
+#ifdef INET6
+ (type == AF_INET6) ?
+ _nss_ldap_parse_hostv6 :
+#endif
+ _nss_ldap_parse_hostv4);
+
+ MAP_H_ERRNO (status, *h_errnop);
+
+ return status;
+}
+
+enum nss_status _nss_ldap_sethostent (void)
+{
+ LOOKUP_SETENT (hosts_context);
+}
+
+enum nss_status _nss_ldap_endhostent (void)
+{
+ LOOKUP_ENDENT (hosts_context);
+}
+
+enum nss_status _nss_ldap_gethostent_r (struct hostent * result, char *buffer, size_t buflen,
+ int *errnop, int *h_errnop)
+{
+ enum nss_status status;
+
+ status = _nss_ldap_getent (&hosts_context,
+ result,
+ buffer,
+ buflen,
+ errnop,
+ _nss_ldap_filt_gethostent, LM_HOSTS,
+#ifdef INET6
+ (_res.options & RES_USE_INET6) ?
+ _nss_ldap_parse_hostv6 :
+#endif
+ _nss_ldap_parse_hostv4);
+
+ MAP_H_ERRNO (status, *h_errnop);
+
+ return status;
+}
diff --git a/server/netgroup.c b/server/netgroup.c
new file mode 100644
index 0000000..b5b93cb
--- /dev/null
+++ b/server/netgroup.c
@@ -0,0 +1,329 @@
+/*
+ Copyright (C) 2002-2005 Luke Howard
+ This file is part of the nss_ldap library.
+ Linux support contributed by Larry Lile, <llile@dreamworks.com>, 2002.
+ Solaris support contributed by Luke Howard, <lukeh@padl.com>, 2004.
+
+ The nss_ldap library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The nss_ldap 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the nss_ldap library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ $Id$
+*/
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <string.h>
+#include <assert.h>
+#if defined(HAVE_THREAD_H)
+#include <thread.h>
+#elif defined(HAVE_PTHREAD_H)
+#include <pthread.h>
+#endif
+#ifdef HAVE_LBER_H
+#include <lber.h>
+#endif
+#ifdef HAVE_LDAP_H
+#include <ldap.h>
+#endif
+
+#include "ldap-nss.h"
+#include "util.h"
+
+static struct ent_context *_ngbe = NULL;
+
+/*
+ * I pulled the following macro (EXPAND), functions (strip_whitespace and
+ * _nss_netgroup_parseline) and structures (name_list and __netgrent) from
+ * glibc-2.2.x. _nss_netgroup_parseline became _nss_ldap_parse_netgr after
+ * some modification.
+ *
+ * The rest of the code is modeled on various other _nss_ldap functions.
+ */
+
+#define EXPAND(needed) \
+ do \
+ { \
+ size_t old_cursor = result->cursor - result->data; \
+ \
+ result->data_size += 512 > 2 * needed ? 512 : 2 * needed; \
+ result->data = realloc (result->data, result->data_size); \
+ \
+ if (result->data == NULL) \
+ { \
+ stat = NSS_STATUS_UNAVAIL; \
+ goto out; \
+ } \
+ \
+ result->cursor = result->data + old_cursor; \
+ } \
+ while (0)
+
+/* A netgroup can consist of names of other netgroups. We have to
+ track which netgroups were read and which still have to be read. */
+
+/* Dataset for iterating netgroups. */
+struct __netgrent
+{
+ enum
+ { triple_val, group_val }
+ type;
+
+ union
+ {
+ struct
+ {
+ const char *host;
+ const char *user;
+ const char *domain;
+ }
+ triple;
+
+ const char *group;
+ }
+ val;
+
+ /* Room for the data kept between the calls to the netgroup
+ functions. We must avoid global variables. */
+ char *data;
+ size_t data_size;
+ char *cursor;
+ int first;
+
+ struct name_list *known_groups;
+ struct name_list *needed_groups;
+};
+
+static char *
+strip_whitespace (char *str)
+{
+ char *cp = str;
+
+ /* Skip leading spaces. */
+ while (isspace ((int) *cp))
+ cp++;
+
+ str = cp;
+ while (*cp != '\0' && !isspace ((int) *cp))
+ cp++;
+
+ /* Null-terminate, stripping off any trailing spaces. */
+ *cp = '\0';
+
+ return *str == '\0' ? NULL : str;
+}
+
+static enum nss_status
+_nss_ldap_parse_netgr (void *vresultp, char *buffer, size_t buflen)
+{
+ struct __netgrent *result = (struct __netgrent *) vresultp;
+ char *cp = result->cursor;
+ char *user, *host, *domain;
+
+ /* The netgroup either doesn't exist or is empty. */
+ if (cp == NULL)
+ return NSS_STATUS_RETURN;
+
+ /* First skip leading spaces. */
+ while (isspace ((int) *cp))
+ ++cp;
+
+ if (*cp != '(')
+ {
+ /* We have a list of other netgroups. */
+ char *name = cp;
+
+ while (*cp != '\0' && !isspace ((int) *cp))
+ ++cp;
+
+ if (name != cp)
+ {
+ /* It is another netgroup name. */
+ int last = *cp == '\0';
+
+ result->type = group_val;
+ result->val.group = name;
+ *cp = '\0';
+ if (!last)
+ ++cp;
+ result->cursor = cp;
+ result->first = 0;
+
+ return NSS_STATUS_SUCCESS;
+ }
+ return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN;
+ }
+
+ /* Match host name. */
+ host = ++cp;
+ while (*cp != ',')
+ if (*cp++ == '\0')
+ return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN;
+
+ /* Match user name. */
+ user = ++cp;
+ while (*cp != ',')
+ if (*cp++ == '\0')
+ return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN;
+
+ /* Match domain name. */
+ domain = ++cp;
+ while (*cp != ')')
+ if (*cp++ == '\0')
+ return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN;
+ ++cp;
+
+ /* When we got here we have found an entry. Before we can copy it
+ to the private buffer we have to make sure it is big enough. */
+ if (cp - host > buflen)
+ return NSS_STATUS_TRYAGAIN;
+
+ strncpy (buffer, host, cp - host);
+ result->type = triple_val;
+
+ buffer[(user - host) - 1] = '\0';
+ result->val.triple.host = strip_whitespace (buffer);
+
+ buffer[(domain - host) - 1] = '\0';
+ result->val.triple.user = strip_whitespace (buffer + (user - host));
+
+ buffer[(cp - host) - 1] = '\0';
+ result->val.triple.domain = strip_whitespace (buffer + (domain - host));
+
+ /* Remember where we stopped reading. */
+ result->cursor = cp;
+ result->first = 0;
+
+ return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status
+_nss_ldap_load_netgr (LDAPMessage * e,
+ struct ldap_state * pvt,
+ void *vresultp, char *buffer, size_t buflen)
+{
+ int attr;
+ int nvals;
+ int valcount = 0;
+ char **vals;
+ char **valiter;
+ struct __netgrent *result = vresultp;
+ enum nss_status stat = NSS_STATUS_SUCCESS;
+
+ for (attr = 0; attr < 2; attr++)
+ {
+ switch (attr)
+ {
+ case 1:
+ vals = _nss_ldap_get_values (e, AT (nisNetgroupTriple));
+ break;
+ default:
+ vals = _nss_ldap_get_values (e, AT (memberNisNetgroup));
+ break;
+ }
+
+ nvals = ldap_count_values (vals);
+
+ if (vals == NULL)
+ continue;
+
+ if (nvals == 0)
+ {
+ ldap_value_free (vals);
+ continue;
+ }
+
+ if (result->data_size > 0
+ && result->cursor - result->data + 1 > result->data_size)
+ EXPAND (1);
+
+ if (result->data_size > 0)
+ *result->cursor++ = ' ';
+
+ valcount += nvals;
+ valiter = vals;
+
+ while (*valiter != NULL)
+ {
+ int curlen = strlen (*valiter);
+ if (result->cursor - result->data + curlen + 1 > result->data_size)
+ EXPAND (curlen + 1);
+ memcpy (result->cursor, *valiter, curlen + 1);
+ result->cursor += curlen;
+ valiter++;
+ if (*valiter != NULL)
+ *result->cursor++ = ' ';
+ }
+ ldap_value_free (vals);
+ }
+
+ result->first = 1;
+ result->cursor = result->data;
+
+out:
+
+ return stat;
+}
+
+enum nss_status _nss_ldap_endnetgrent(struct __netgrent *result)
+{
+ if (result->data != NULL)
+ {
+ free (result->data);
+ result->data = NULL;
+ result->data_size = 0;
+ result->cursor = NULL;
+ }
+
+ LOOKUP_ENDENT (_ngbe);
+}
+
+enum nss_status _nss_ldap_setnetgrent(char *group,struct __netgrent *result)
+{
+ int errnop = 0, buflen = 0;
+ char *buffer = (char *) NULL;
+ struct ldap_args a;
+ enum nss_status stat = NSS_STATUS_SUCCESS;
+
+ if (group[0] == '\0')
+ return NSS_STATUS_UNAVAIL;
+
+ if (result->data != NULL)
+ free (result->data);
+ result->data = result->cursor = NULL;
+ result->data_size = 0;
+
+ LA_INIT (a);
+ LA_STRING (a) = group;
+ LA_TYPE (a) = LA_TYPE_STRING;
+
+ stat =
+ _nss_ldap_getbyname (&a, result, buffer, buflen, &errnop,
+ _nss_ldap_filt_getnetgrent, LM_NETGROUP,
+ _nss_ldap_load_netgr);
+
+ LOOKUP_SETENT (_ngbe);
+}
+
+enum nss_status _nss_ldap_getnetgrent_r(struct __netgrent *result,
+ char *buffer,size_t buflen,int *errnop)
+{
+ return _nss_ldap_parse_netgr (result, buffer, buflen);
+}
diff --git a/server/networks.c b/server/networks.c
new file mode 100644
index 0000000..959c531
--- /dev/null
+++ b/server/networks.c
@@ -0,0 +1,200 @@
+/*
+ Copyright (C) 1997-2005 Luke Howard
+ This file is part of the nss_ldap library.
+ Contributed by Luke Howard, <lukeh@padl.com>, 1997.
+
+ The nss_ldap library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The nss_ldap 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the nss_ldap library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ $Id$
+*/
+
+/* parts based on nss_nis */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <sys/socket.h>
+#include <errno.h>
+#ifdef HAVE_LBER_H
+#include <lber.h>
+#endif
+#ifdef HAVE_LDAP_H
+#include <ldap.h>
+#endif
+#if defined(HAVE_THREAD_H)
+#include <thread.h>
+#elif defined(HAVE_PTHREAD_H)
+#include <pthread.h>
+#endif
+
+#include "ldap-nss.h"
+#include "util.h"
+
+#if defined(HAVE_USERSEC_H)
+#define MAXALIASES 35
+#define MAXADDRSIZE 4
+#endif /* HAVE_USERSEC_H */
+
+static struct ent_context *net_context = NULL;
+
+static enum nss_status
+_nss_ldap_parse_net (LDAPMessage * e,
+ struct ldap_state * pvt,
+ void *result, char *buffer, size_t buflen)
+{
+
+ char *tmp;
+ struct netent *network = (struct netent *) result;
+ enum nss_status stat;
+
+ /* IPv6 support ? XXX */
+ network->n_addrtype = AF_INET;
+
+ stat = _nss_ldap_assign_attrval (e, ATM (LM_NETWORKS, cn), &network->n_name,
+ &buffer, &buflen);
+ if (stat != NSS_STATUS_SUCCESS)
+ return stat;
+
+ stat =
+ _nss_ldap_assign_attrval (e, AT (ipNetworkNumber), &tmp, &buffer,
+ &buflen);
+ if (stat != NSS_STATUS_SUCCESS)
+ return stat;
+
+ network->n_net = inet_network (tmp);
+
+ stat =
+ _nss_ldap_assign_attrvals (e, ATM (LM_NETWORKS, cn), network->n_name,
+ &network->n_aliases, &buffer, &buflen, NULL);
+ if (stat != NSS_STATUS_SUCCESS)
+ return stat;
+
+ return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status _nss_ldap_getnetbyname_r(const char *name,struct netent *result,
+ char *buffer,size_t buflen,int *errnop,
+ int *herrnop)
+{
+ enum nss_status status;
+ struct ldap_args a;
+
+ LA_INIT (a);
+ LA_STRING (a) = name;
+ LA_TYPE (a) = LA_TYPE_STRING;
+
+ status = _nss_ldap_getbyname (&a,
+ result,
+ buffer,
+ buflen,
+ errnop,
+ _nss_ldap_filt_getnetbyname,
+ LM_NETWORKS, _nss_ldap_parse_net);
+
+ MAP_H_ERRNO (status, *herrnop);
+
+ return status;
+}
+
+enum nss_status _nss_ldap_getnetbyaddr_r(unsigned long addr,int type,
+ struct netent *result,char *buffer,size_t buflen,
+ int *errnop,int *herrnop)
+{
+ struct in_addr in;
+ char buf[256];
+ int blen;
+ struct ldap_args a;
+ enum nss_status retval = NSS_STATUS_NOTFOUND;
+
+ LA_INIT (a);
+ LA_TYPE (a) = LA_TYPE_STRING;
+
+ in = inet_makeaddr (addr, 0);
+ strcpy (buf, inet_ntoa (in));
+ blen = strlen (buf);
+ LA_STRING (a) = buf;
+
+ while (1)
+ {
+ retval = _nss_ldap_getbyname (&a, result, buffer, buflen, errnop,
+ _nss_ldap_filt_getnetbyaddr,
+ LM_NETWORKS, _nss_ldap_parse_net);
+
+ if (retval != NSS_STATUS_SUCCESS)
+ {
+ if (retval == NSS_STATUS_NOTFOUND)
+ {
+ if (buf[blen - 2] == '.' && buf[blen - 1] == '\0')
+ {
+ buf[blen - 2] = '\0';
+ blen -= 2;
+ continue;
+ }
+ else
+ {
+ MAP_H_ERRNO (retval, *herrnop);
+ return NSS_STATUS_NOTFOUND;
+ }
+ }
+ else
+ {
+ MAP_H_ERRNO (retval, *herrnop);
+ return retval;
+ }
+ }
+ else
+ {
+ /* retval == NSS_STATUS_SUCCESS */
+ break;
+ }
+ }
+
+ MAP_H_ERRNO (NSS_STATUS_SUCCESS, *herrnop);
+
+ return retval;
+}
+
+enum nss_status _nss_ldap_setnetent(void)
+{
+ LOOKUP_SETENT (net_context);
+}
+
+enum nss_status _nss_ldap_getnetent_r(struct netent *result,char *buffer,size_t buflen,
+ int *errnop,int *herrnop)
+{
+ enum nss_status status;
+ status = _nss_ldap_getent (&net_context,
+ result,
+ buffer,
+ buflen,
+ errnop,
+ _nss_ldap_filt_getnetent,
+ LM_NETWORKS, _nss_ldap_parse_net);
+
+ MAP_H_ERRNO (status, *herrnop);
+ return status;
+}
+
+enum nss_status _nss_ldap_endnetent(void)
+{
+ LOOKUP_ENDENT (net_context);
+}
diff --git a/server/passwd.c b/server/passwd.c
new file mode 100644
index 0000000..11155a9
--- /dev/null
+++ b/server/passwd.c
@@ -0,0 +1,206 @@
+/*
+ Copyright (C) 1997-2005 Luke Howard
+ This file is part of the nss_ldap library.
+ Contributed by Luke Howard, <lukeh@padl.com>, 1997.
+
+ The nss_ldap library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The nss_ldap 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the nss_ldap library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <string.h>
+#include <pwd.h>
+#include <errno.h>
+#ifdef HAVE_LBER_H
+#include <lber.h>
+#endif
+#ifdef HAVE_LDAP_H
+#include <ldap.h>
+#endif
+#if defined(HAVE_THREAD_H)
+#include <thread.h>
+#elif defined(HAVE_PTHREAD_H)
+#include <pthread.h>
+#endif
+
+#include "ldap-nss.h"
+#include "util.h"
+
+static struct ent_context *pw_context = NULL;
+
+static inline enum nss_status _nss_ldap_assign_emptystring(
+ char **valptr, char **buffer, size_t * buflen)
+{
+ if (*buflen < 2)
+ return NSS_STATUS_TRYAGAIN;
+
+ *valptr = *buffer;
+
+ **valptr = '\0';
+
+ (*buffer)++;
+ (*buflen)--;
+
+ return NSS_STATUS_SUCCESS;
+}
+
+/* FIXME: make this non-static for now for testing purposes */
+enum nss_status _nss_ldap_parse_pw (LDAPMessage * e,
+ struct ldap_state * pvt,
+ void *result, char *buffer, size_t buflen)
+{
+ struct passwd *pw = (struct passwd *) result;
+ char *uid, *gid;
+ enum nss_status stat;
+ char tmpbuf[ sizeof( uid_t ) * 8 / 3 + 2 ];
+ size_t tmplen;
+ char *tmp;
+
+ tmpbuf[ sizeof(tmpbuf) - 1 ] = '\0';
+
+ if (_nss_ldap_oc_check (e, "shadowAccount") == NSS_STATUS_SUCCESS)
+ {
+ /* don't include password for shadowAccount */
+ if (buflen < 3)
+ return NSS_STATUS_TRYAGAIN;
+
+ pw->pw_passwd = buffer;
+ strcpy (buffer, "x");
+ buffer += 2;
+ buflen -= 2;
+ }
+ else
+ {
+ stat =
+ _nss_ldap_assign_userpassword (e, ATM (LM_PASSWD, userPassword),
+ &pw->pw_passwd, &buffer, &buflen);
+ if (stat != NSS_STATUS_SUCCESS)
+ return stat;
+ }
+
+ stat =
+ _nss_ldap_assign_attrval (e, ATM (LM_PASSWD, uid), &pw->pw_name, &buffer,
+ &buflen);
+ if (stat != NSS_STATUS_SUCCESS)
+ return stat;
+
+ tmp = tmpbuf;
+ tmplen = sizeof (tmpbuf) - 1;
+ stat =
+ _nss_ldap_assign_attrval (e, AT (uidNumber), &uid, &tmp, &tmplen);
+ if (stat != NSS_STATUS_SUCCESS)
+ return stat;
+ pw->pw_uid = (*uid == '\0') ? UID_NOBODY : (uid_t) atol (uid);
+
+ tmp = tmpbuf;
+ tmplen = sizeof (tmpbuf) - 1;
+ stat =
+ _nss_ldap_assign_attrval (e, ATM (LM_PASSWD, gidNumber), &gid, &tmp,
+ &tmplen);
+ if (stat != NSS_STATUS_SUCCESS)
+ return stat;
+ pw->pw_gid = (*gid == '\0') ? GID_NOBODY : (gid_t) atol (gid);
+
+ stat =
+ _nss_ldap_assign_attrval (e, AT (gecos), &pw->pw_gecos, &buffer,
+ &buflen);
+ if (stat != NSS_STATUS_SUCCESS)
+ {
+ pw->pw_gecos = NULL;
+ stat =
+ _nss_ldap_assign_attrval (e, ATM (LM_PASSWD, cn), &pw->pw_gecos,
+ &buffer, &buflen);
+ if (stat != NSS_STATUS_SUCCESS)
+ return stat;
+ }
+
+ stat =
+ _nss_ldap_assign_attrval (e, AT (homeDirectory), &pw->pw_dir, &buffer,
+ &buflen);
+ if (stat != NSS_STATUS_SUCCESS)
+ (void) _nss_ldap_assign_emptystring (&pw->pw_dir, &buffer, &buflen);
+
+ stat =
+ _nss_ldap_assign_attrval (e, AT (loginShell), &pw->pw_shell, &buffer,
+ &buflen);
+ if (stat != NSS_STATUS_SUCCESS)
+ (void) _nss_ldap_assign_emptystring (&pw->pw_shell, &buffer, &buflen);
+
+#ifdef HAVE_PASSWD_PW_CHANGE
+ tmp = NULL;
+ stat =
+ _nss_ldap_assign_attrval (e, AT (shadowMax), &tmp, &buffer, &buflen);
+ pw->pw_change = (stat == NSS_STATUS_SUCCESS) ? atol(tmp) * (24*60*60) : 0;
+
+ if (pw->pw_change > 0)
+ {
+ tmp = NULL;
+ stat =
+ _nss_ldap_assign_attrval (e, AT (shadowLastChange), &tmp, &buffer,
+ &buflen);
+ if (stat == NSS_STATUS_SUCCESS)
+ pw->pw_change += atol(tmp);
+ else
+ pw->pw_change = 0;
+ }
+#endif /* HAVE_PASSWD_PW_CHANGE */
+
+#ifdef HAVE_PASSWD_PW_EXPIRE
+ tmp = NULL;
+ stat =
+ _nss_ldap_assign_attrval (e, AT (shadowExpire), &tmp, &buffer, &buflen);
+ pw->pw_expire = (stat == NSS_STATUS_SUCCESS) ? atol(tmp) * (24*60*60) : 0;
+#endif /* HAVE_PASSWD_PW_EXPIRE */
+
+ return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status _nss_ldap_getpwnam_r(const char *name,
+ struct passwd *result,
+ char *buffer,size_t buflen,int *errnop)
+{
+ LOOKUP_NAME (name, result, buffer, buflen, errnop, _nss_ldap_filt_getpwnam,
+ LM_PASSWD, _nss_ldap_parse_pw, LDAP_NSS_BUFLEN_DEFAULT);
+}
+
+enum nss_status _nss_ldap_getpwuid_r(uid_t uid,
+ struct passwd *result,
+ char *buffer,size_t buflen,int *errnop)
+{
+ LOOKUP_NUMBER (uid, result, buffer, buflen, errnop, _nss_ldap_filt_getpwuid,
+ LM_PASSWD, _nss_ldap_parse_pw, LDAP_NSS_BUFLEN_DEFAULT);
+}
+
+enum nss_status _nss_ldap_setpwent(void)
+{
+ LOOKUP_SETENT (pw_context);
+}
+
+enum nss_status _nss_ldap_getpwent_r(struct passwd *result,
+ char *buffer,size_t buflen,int *errnop)
+{
+ LOOKUP_GETENT (pw_context, result, buffer, buflen, errnop,
+ _nss_ldap_filt_getpwent, LM_PASSWD, _nss_ldap_parse_pw,
+ LDAP_NSS_BUFLEN_DEFAULT);
+}
+
+enum nss_status _nss_ldap_endpwent(void)
+{
+ LOOKUP_ENDENT (pw_context);
+}
diff --git a/server/protocols.c b/server/protocols.c
new file mode 100644
index 0000000..d601c40
--- /dev/null
+++ b/server/protocols.c
@@ -0,0 +1,118 @@
+/*
+ Copyright (C) 1997-2005 Luke Howard
+ This file is part of the nss_ldap library.
+ Contributed by Luke Howard, <lukeh@padl.com>, 1997.
+
+ The nss_ldap library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The nss_ldap 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the nss_ldap library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ $Id$
+*/
+
+/*
+ Determine the canonical name of the RPC with _nss_ldap_getrdnvalue(),
+ and assign any values of "cn" which do NOT match this canonical name
+ as aliases.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+#include <errno.h>
+#ifdef HAVE_LBER_H
+#include <lber.h>
+#endif
+#ifdef HAVE_LDAP_H
+#include <ldap.h>
+#endif
+#if defined(HAVE_THREAD_H)
+#include <thread.h>
+#elif defined(HAVE_PTHREAD_H)
+#include <pthread.h>
+#endif
+
+#include "ldap-nss.h"
+#include "util.h"
+
+static struct ent_context *proto_context = NULL;
+
+static enum nss_status _nss_ldap_parse_proto (LDAPMessage *e,
+ struct ldap_state *pvt,
+ void *result, char *buffer, size_t buflen)
+{
+
+ struct protoent *proto = (struct protoent *) result;
+ char *number;
+ enum nss_status stat;
+
+ stat =
+ _nss_ldap_getrdnvalue (e, ATM (LM_PROTOCOLS, cn), &proto->p_name,
+ &buffer, &buflen);
+ if (stat != NSS_STATUS_SUCCESS)
+ return stat;
+
+ stat =
+ _nss_ldap_assign_attrval (e, AT (ipProtocolNumber), &number, &buffer,
+ &buflen);
+ if (stat != NSS_STATUS_SUCCESS)
+ return stat;
+
+ proto->p_proto = atoi (number);
+
+ stat =
+ _nss_ldap_assign_attrvals (e, ATM (LM_PROTOCOLS, cn), proto->p_name,
+ &proto->p_aliases, &buffer, &buflen, NULL);
+ if (stat != NSS_STATUS_SUCCESS)
+ return stat;
+
+ return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status _nss_ldap_getprotobyname_r(const char *name,struct protoent *result,
+ char *buffer,size_t buflen,int *errnop)
+{
+ LOOKUP_NAME (name, result, buffer, buflen, errnop,
+ _nss_ldap_filt_getprotobyname, LM_PROTOCOLS,
+ _nss_ldap_parse_proto, LDAP_NSS_BUFLEN_DEFAULT);
+}
+
+enum nss_status _nss_ldap_getprotobynumber_r(int number,struct protoent *result,
+ char *buffer,size_t buflen,int *errnop)
+{
+ LOOKUP_NUMBER (number, result, buffer, buflen, errnop,
+ _nss_ldap_filt_getprotobynumber, LM_PROTOCOLS,
+ _nss_ldap_parse_proto, LDAP_NSS_BUFLEN_DEFAULT);
+}
+
+enum nss_status _nss_ldap_setprotoent(void)
+{
+ LOOKUP_SETENT (proto_context);
+}
+
+enum nss_status _nss_ldap_getprotoent_r(struct protoent *result,char *buffer,size_t buflen,
+ int *errnop)
+{
+ LOOKUP_GETENT (proto_context, result, buffer, buflen, errnop,
+ _nss_ldap_filt_getprotoent, LM_PROTOCOLS,
+ _nss_ldap_parse_proto, LDAP_NSS_BUFLEN_DEFAULT);
+}
+
+enum nss_status _nss_ldap_endprotoent(void)
+{
+ LOOKUP_ENDENT (proto_context);
+}
diff --git a/server/rpc.c b/server/rpc.c
new file mode 100644
index 0000000..3a12026
--- /dev/null
+++ b/server/rpc.c
@@ -0,0 +1,122 @@
+/*
+ Copyright (C) 1997-2005 Luke Howard
+ This file is part of the nss_ldap library.
+ Contributed by Luke Howard, <lukeh@padl.com>, 1997.
+
+ The nss_ldap library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The nss_ldap 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the nss_ldap library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ $Id$
+*/
+
+/*
+ Determine the canonical name of the RPC with _nss_ldap_getrdnvalue(),
+ and assign any values of "cn" which do NOT match this canonical name
+ as aliases.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#ifdef HAVE_RPC_RPCENT_H
+#include <rpc/rpcent.h>
+#else
+#include <netdb.h>
+#endif
+#ifdef HAVE_LBER_H
+#include <lber.h>
+#endif
+#ifdef HAVE_LDAP_H
+#include <ldap.h>
+#endif
+#if defined(HAVE_THREAD_H)
+#include <thread.h>
+#elif defined(HAVE_PTHREAD_H)
+#include <pthread.h>
+#endif
+
+#include "ldap-nss.h"
+#include "util.h"
+
+static struct ent_context *rpc_context = NULL;
+
+static enum nss_status _nss_ldap_parse_rpc (LDAPMessage * e,
+ struct ldap_state * pvt,
+ void *result, char *buffer, size_t buflen)
+{
+
+ struct rpcent *rpc = (struct rpcent *) result;
+ char *number;
+ enum nss_status stat;
+
+ stat =
+ _nss_ldap_getrdnvalue (e, ATM (LM_RPC, cn), &rpc->r_name, &buffer,
+ &buflen);
+ if (stat != NSS_STATUS_SUCCESS)
+ return stat;
+
+ stat =
+ _nss_ldap_assign_attrval (e, AT (oncRpcNumber), &number, &buffer,
+ &buflen);
+ if (stat != NSS_STATUS_SUCCESS)
+ return stat;
+
+ rpc->r_number = atol (number);
+
+ stat =
+ _nss_ldap_assign_attrvals (e, ATM (LM_RPC, cn), rpc->r_name,
+ &rpc->r_aliases, &buffer, &buflen, NULL);
+ if (stat != NSS_STATUS_SUCCESS)
+ return stat;
+
+ return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status _nss_ldap_getrpcbyname_r(const char *name,struct rpcent *result,
+ char *buffer,size_t buflen,int *errnop)
+{
+ LOOKUP_NAME(name, result, buffer, buflen, errnop,
+ _nss_ldap_filt_getrpcbyname, LM_RPC, _nss_ldap_parse_rpc,
+ LDAP_NSS_BUFLEN_DEFAULT);
+}
+
+enum nss_status _nss_ldap_getrpcbynumber_r(int number,struct rpcent *result,
+ char *buffer,size_t buflen,int *errnop)
+{
+ LOOKUP_NUMBER(number, result, buffer, buflen, errnop,
+ _nss_ldap_filt_getrpcbynumber, LM_RPC, _nss_ldap_parse_rpc,
+ LDAP_NSS_BUFLEN_DEFAULT);
+}
+
+enum nss_status _nss_ldap_setrpcent(void)
+{
+ LOOKUP_SETENT(rpc_context);
+}
+
+enum nss_status _nss_ldap_getrpcent_r(struct rpcent *result,char *buffer,size_t buflen,
+ int *errnop)
+{
+ LOOKUP_GETENT(rpc_context,result,buffer,buflen,errnop,
+ _nss_ldap_filt_getrpcent,LM_RPC,_nss_ldap_parse_rpc,
+ LDAP_NSS_BUFLEN_DEFAULT);
+}
+
+enum nss_status _nss_ldap_endrpcent(void)
+{
+ LOOKUP_ENDENT(rpc_context);
+}
diff --git a/server/services.c b/server/services.c
new file mode 100644
index 0000000..ffe9b62
--- /dev/null
+++ b/server/services.c
@@ -0,0 +1,225 @@
+/*
+ Copyright (C) 1997-2005 Luke Howard
+ This file is part of the nss_ldap library.
+ Contributed by Luke Howard, <lukeh@padl.com>, 1997.
+
+ The nss_ldap library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The nss_ldap 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the nss_ldap library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ $Id$
+*/
+
+/*
+ Determine the canonical name of the RPC with _nss_ldap_getrdnvalue(),
+ and assign any values of "cn" which do NOT match this canonical name
+ as aliases.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <errno.h>
+#ifdef HAVE_SYS_BYTEORDER_H
+#include <sys/byteorder.h>
+#endif
+#ifdef HAVE_LBER_H
+#include <lber.h>
+#endif
+#ifdef HAVE_LDAP_H
+#include <ldap.h>
+#endif
+#if defined(HAVE_THREAD_H)
+#include <thread.h>
+#elif defined(HAVE_PTHREAD_H)
+#include <pthread.h>
+#endif
+
+#include "ldap-nss.h"
+#include "util.h"
+
+static struct ent_context *serv_context = NULL;
+
+static enum nss_status _nss_ldap_parse_serv (LDAPMessage *e,
+ struct ldap_state *state,
+ void *result,char *buffer,size_t buflen)
+{
+ struct servent *service = (struct servent *)result;
+ char *port;
+ enum nss_status stat = NSS_STATUS_SUCCESS;
+
+ /* this is complicated and ugly, because some git (me) specified that service
+ * entries should expand to two entities (or more) if they have multi-valued
+ * ipServiceProtocol fields.
+ */
+
+ if (state->ls_type == LS_TYPE_KEY)
+ {
+ if (state->ls_info.ls_key == NULL)
+ {
+ /* non-deterministic behaviour is ok */
+ stat =
+ _nss_ldap_assign_attrval (e, AT (ipServiceProtocol),
+ &service->s_proto, &buffer, &buflen);
+ if (stat != NSS_STATUS_SUCCESS)
+ {
+ return stat;
+ }
+ }
+ else
+ {
+ register int len;
+ len = strlen (state->ls_info.ls_key);
+ if (buflen < (size_t) (len + 1))
+ {
+ return NSS_STATUS_TRYAGAIN;
+ }
+ strncpy (buffer, state->ls_info.ls_key, len);
+ buffer[len] = '\0';
+ service->s_proto = buffer;
+ buffer += len + 1;
+ buflen -= len + 1;
+ }
+ }
+ else
+ {
+ char **vals = _nss_ldap_get_values (e, AT (ipServiceProtocol));
+ int len;
+ if (vals == NULL)
+ {
+ state->ls_info.ls_index = -1;
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ switch (state->ls_info.ls_index)
+ {
+ case 0:
+ /* last time. decrementing ls_index to -1 AND returning !NSS_STATUS_SUCCESS
+ will force this entry to be discarded.
+ */
+ stat = NSS_STATUS_NOTFOUND;
+ break;
+ case -1:
+ /* first time */
+ state->ls_info.ls_index = ldap_count_values (vals);
+ /* fall off to default ... */
+ default:
+ len = strlen (vals[state->ls_info.ls_index - 1]);
+ if (buflen < (size_t) (len + 1))
+ {
+ return NSS_STATUS_TRYAGAIN;
+ }
+ strncpy (buffer, vals[state->ls_info.ls_index - 1], len);
+ buffer[len] = '\0';
+ service->s_proto = buffer;
+ buffer += len + 1;
+ buflen -= len + 1;
+ stat = NSS_STATUS_SUCCESS;
+ }
+
+ ldap_value_free (vals);
+ state->ls_info.ls_index--;
+ }
+
+ if (stat != NSS_STATUS_SUCCESS)
+ {
+ return stat;
+ }
+
+ stat =
+ _nss_ldap_getrdnvalue (e, ATM (LM_SERVICES, cn), &service->s_name,
+ &buffer, &buflen);
+ if (stat != NSS_STATUS_SUCCESS)
+ {
+ return stat;
+ }
+
+ stat =
+ _nss_ldap_assign_attrvals (e, ATM (LM_SERVICES, cn), service->s_name,
+ &service->s_aliases, &buffer, &buflen, NULL);
+ if (stat != NSS_STATUS_SUCCESS)
+ {
+ return stat;
+ }
+
+ stat =
+ _nss_ldap_assign_attrval (e, AT (ipServicePort), &port, &buffer,
+ &buflen);
+ if (stat != NSS_STATUS_SUCCESS)
+ {
+ return stat;
+ }
+
+ service->s_port = htons (atoi (port));
+
+ return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status _nss_ldap_getservbyname_r(const char *name,
+ const char *proto,
+ struct servent *result,
+ char *buffer,size_t buflen,int *errnop)
+{
+ struct ldap_args a;
+
+ LA_INIT (a);
+ LA_STRING (a) = name;
+ LA_TYPE (a) = (proto == NULL) ? LA_TYPE_STRING : LA_TYPE_STRING_AND_STRING;
+ LA_STRING2 (a) = proto;
+
+ return _nss_ldap_getbyname (&a, result, buffer, buflen, errnop,
+ ((proto == NULL) ? _nss_ldap_filt_getservbyname
+ : _nss_ldap_filt_getservbynameproto),
+ LM_SERVICES, _nss_ldap_parse_serv);
+}
+
+enum nss_status _nss_ldap_getservbyport_r(int port,
+ const char *proto,
+ struct servent *result,
+ char *buffer,size_t buflen,int *errnop)
+{
+ struct ldap_args a;
+
+ LA_INIT (a);
+ LA_NUMBER (a) = htons (port);
+ LA_TYPE (a) = (proto == NULL) ? LA_TYPE_NUMBER : LA_TYPE_NUMBER_AND_STRING;
+ LA_STRING2 (a) = proto;
+ return _nss_ldap_getbyname (&a, result, buffer, buflen, errnop,
+ (proto ==
+ NULL) ? _nss_ldap_filt_getservbyport :
+ _nss_ldap_filt_getservbyportproto,
+ LM_SERVICES, _nss_ldap_parse_serv);
+}
+
+enum nss_status _nss_ldap_setservent(void)
+{
+ LOOKUP_SETENT(serv_context);
+}
+
+enum nss_status _nss_ldap_getservent_r(struct servent *result,char *buffer,size_t buflen,
+ int *errnop)
+{
+ LOOKUP_GETENT(serv_context, result, buffer, buflen, errnop,
+ _nss_ldap_filt_getservent, LM_SERVICES,
+ _nss_ldap_parse_serv, LDAP_NSS_BUFLEN_DEFAULT);
+}
+
+enum nss_status _nss_ldap_endservent(void)
+{
+ LOOKUP_ENDENT(serv_context);
+}
diff --git a/server/shadow.c b/server/shadow.c
new file mode 100644
index 0000000..5319ade
--- /dev/null
+++ b/server/shadow.c
@@ -0,0 +1,134 @@
+/*
+ Copyright (C) 1997-2005 Luke Howard
+ This file is part of the nss_ldap library.
+ Contributed by Luke Howard, <lukeh@padl.com>, 1997.
+
+ The nss_ldap library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The nss_ldap 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the nss_ldap library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ $Id$
+*/
+
+#include "config.h"
+
+#ifdef HAVE_SHADOW_H
+
+#include <stdlib.h>
+#include <string.h>
+#include <shadow.h>
+#include <errno.h>
+#ifdef HAVE_PROT_H
+#define _PROT_INCLUDED
+#endif
+#ifdef HAVE_LBER_H
+#include <lber.h>
+#endif
+#ifdef HAVE_LDAP_H
+#include <ldap.h>
+#endif
+#if defined(HAVE_THREAD_H)
+#include <thread.h>
+#elif defined(HAVE_PTHREAD_H)
+#include <pthread.h>
+#endif
+
+#include "ldap-nss.h"
+
+static struct ent_context *sp_context = NULL;
+
+static enum nss_status _nss_ldap_parse_sp(LDAPMessage *e,
+ struct ldap_state *pvt,
+ void *result,char *buffer,size_t buflen)
+{
+ struct spwd *sp = (struct spwd *) result;
+ enum nss_status stat;
+ char *tmp = NULL;
+
+ stat =
+ _nss_ldap_assign_userpassword (e, ATM (LM_SHADOW, userPassword),
+ &sp->sp_pwdp, &buffer, &buflen);
+ if (stat != NSS_STATUS_SUCCESS)
+ return stat;
+
+ stat =
+ _nss_ldap_assign_attrval (e, ATM (LM_SHADOW, uid), &sp->sp_namp, &buffer,
+ &buflen);
+ if (stat != NSS_STATUS_SUCCESS)
+ return stat;
+
+ stat =
+ _nss_ldap_assign_attrval (e, AT (shadowLastChange), &tmp, &buffer,
+ &buflen);
+ sp->sp_lstchg = (stat == NSS_STATUS_SUCCESS) ? _nss_ldap_shadow_date (tmp) : -1;
+
+ stat =
+ _nss_ldap_assign_attrval (e, AT (shadowMax), &tmp, &buffer, &buflen);
+ sp->sp_max = (stat == NSS_STATUS_SUCCESS) ? atol (tmp) : -1;
+
+ stat =
+ _nss_ldap_assign_attrval (e, AT (shadowMin), &tmp, &buffer, &buflen);
+ sp->sp_min = (stat == NSS_STATUS_SUCCESS) ? atol (tmp) : -1;
+
+ stat =
+ _nss_ldap_assign_attrval (e, AT (shadowWarning), &tmp, &buffer,
+ &buflen);
+ sp->sp_warn = (stat == NSS_STATUS_SUCCESS) ? atol (tmp) : -1;
+
+ stat =
+ _nss_ldap_assign_attrval (e, AT (shadowInactive), &tmp, &buffer,
+ &buflen);
+ sp->sp_inact = (stat == NSS_STATUS_SUCCESS) ? atol (tmp) : -1;
+
+ stat =
+ _nss_ldap_assign_attrval (e, AT (shadowExpire), &tmp, &buffer,
+ &buflen);
+ sp->sp_expire = (stat == NSS_STATUS_SUCCESS) ? _nss_ldap_shadow_date (tmp) : -1;
+
+ stat =
+ _nss_ldap_assign_attrval (e, AT (shadowFlag), &tmp, &buffer, &buflen);
+ sp->sp_flag = (stat == NSS_STATUS_SUCCESS) ? atol (tmp) : 0;
+
+ _nss_ldap_shadow_handle_flag(sp);
+
+ return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status _nss_ldap_getspnam_r(const char *name,
+ struct spwd *result,
+ char *buffer,size_t buflen,int *errnop)
+{
+ LOOKUP_NAME(name, result, buffer, buflen, errnop, _nss_ldap_filt_getspnam,
+ LM_SHADOW, _nss_ldap_parse_sp, LDAP_NSS_BUFLEN_DEFAULT);
+}
+
+enum nss_status _nss_ldap_setspent(void)
+{
+ LOOKUP_SETENT(sp_context);
+}
+
+enum nss_status _nss_ldap_getspent_r(struct spwd *result,
+ char *buffer,size_t buflen,int *errnop)
+{
+ LOOKUP_GETENT(sp_context, result, buffer, buflen, errnop,
+ _nss_ldap_filt_getspent, LM_SHADOW, _nss_ldap_parse_sp,
+ LDAP_NSS_BUFLEN_DEFAULT);
+}
+
+enum nss_status _nss_ldap_endspent(void)
+{
+ LOOKUP_ENDENT(sp_context);
+}
+
+#endif /* HAVE_SHADOW_H */