diff options
author | Arthur de Jong <arthur@arthurdejong.org> | 2006-10-25 15:22:04 +0000 |
---|---|---|
committer | Arthur de Jong <arthur@arthurdejong.org> | 2006-10-25 15:22:04 +0000 |
commit | 4ba0924ee98e297e5ce526367c6aad204b6c3adc (patch) | |
tree | 6fdc9202ebd01dd49be3e78ecc013e2bb31a4b44 /server | |
parent | b586bf84c0bd966abf5cb3d26fa956353d77f9e1 (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.c | 99 | ||||
-rw-r--r-- | server/automount.c | 395 | ||||
-rw-r--r-- | server/ethers.c | 142 | ||||
-rw-r--r-- | server/group.c | 1106 | ||||
-rw-r--r-- | server/hosts.c | 328 | ||||
-rw-r--r-- | server/netgroup.c | 329 | ||||
-rw-r--r-- | server/networks.c | 200 | ||||
-rw-r--r-- | server/passwd.c | 206 | ||||
-rw-r--r-- | server/protocols.c | 118 | ||||
-rw-r--r-- | server/rpc.c | 122 | ||||
-rw-r--r-- | server/services.c | 225 | ||||
-rw-r--r-- | server/shadow.c | 134 |
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), + ðer->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 (ðer->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 */ |