Arthur de Jong

Open Source / Free Software developer

summaryrefslogtreecommitdiffstats
path: root/nslcd
diff options
context:
space:
mode:
authorArthur de Jong <arthur@arthurdejong.org>2006-12-21 20:55:55 +0100
committerArthur de Jong <arthur@arthurdejong.org>2006-12-21 20:55:55 +0100
commitfbc5ecfb8cf86d753b7c9a3b5b549a8f279666ab (patch)
tree5d008fb2963ef8a27da784ba851984f64678e6f0 /nslcd
parent8366a3eb4a9032ca43cae9fccaa536182dcece04 (diff)
rename server directory to nslcd
git-svn-id: http://arthurdejong.org/svn/nss-pam-ldapd/nss-ldapd@196 ef36b2f9-881f-0410-afb5-c4e39611909c
Diffstat (limited to 'nslcd')
-rw-r--r--nslcd/Makefile.am33
-rw-r--r--nslcd/alias.c137
-rw-r--r--nslcd/common.c42
-rw-r--r--nslcd/common.h89
-rw-r--r--nslcd/dnsconfig.c188
-rw-r--r--nslcd/dnsconfig.h30
-rw-r--r--nslcd/ether.c231
-rw-r--r--nslcd/group.c1231
-rw-r--r--nslcd/host.c380
-rw-r--r--nslcd/ldap-nss.c4032
-rw-r--r--nslcd/ldap-nss.h611
-rw-r--r--nslcd/ldap-schema.c453
-rw-r--r--nslcd/ldap-schema.h303
-rw-r--r--nslcd/log.c187
-rw-r--r--nslcd/log.h60
-rw-r--r--nslcd/netgroup.c354
-rw-r--r--nslcd/network.c245
-rw-r--r--nslcd/nslcd.c656
-rw-r--r--nslcd/pagectrl.c224
-rw-r--r--nslcd/pagectrl.h45
-rw-r--r--nslcd/passwd.c273
-rw-r--r--nslcd/protocol.c198
-rw-r--r--nslcd/resolve.c352
-rw-r--r--nslcd/resolve.h118
-rw-r--r--nslcd/rpc.c206
-rw-r--r--nslcd/service.c302
-rw-r--r--nslcd/shadow.c189
-rw-r--r--nslcd/util.c1669
-rw-r--r--nslcd/util.h121
-rw-r--r--nslcd/xmalloc.c59
-rw-r--r--nslcd/xmalloc.h36
31 files changed, 13054 insertions, 0 deletions
diff --git a/nslcd/Makefile.am b/nslcd/Makefile.am
new file mode 100644
index 0000000..f451623
--- /dev/null
+++ b/nslcd/Makefile.am
@@ -0,0 +1,33 @@
+# Makefile.am - use automake to generate Makefile.in
+#
+# Copyright (C) 2006 West Consulting
+# Copyright (C) 2006 Arthur de Jong
+#
+# This 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.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+# MA 02110-1301 USA
+
+sbin_PROGRAMS = nslcd
+AM_CFLAGS = -pthread
+
+nslcd_SOURCES = nslcd.c ../nslcd.h ../nslcd-common.h \
+ log.c log.h \
+ xmalloc.c xmalloc.h \
+ common.c common.h \
+ alias.c ether.c group.c host.c netgroup.c network.c \
+ passwd.c protocol.c rpc.c service.c shadow.c \
+ dnsconfig.c dnsconfig.h ldap-nss.c ldap-nss.h \
+ ldap-schema.c ldap-schema.h pagectrl.c pagectrl.h \
+ resolve.c resolve.h util.c util.h
+nslcd_LDADD = @nslcd_LIBS@
diff --git a/nslcd/alias.c b/nslcd/alias.c
new file mode 100644
index 0000000..4698f1b
--- /dev/null
+++ b/nslcd/alias.c
@@ -0,0 +1,137 @@
+/*
+ alias.c - alias entry lookup routines
+ This file was part of the nss_ldap library (as ldap-alias.c)
+ which has been forked into the nss-ldapd library.
+
+ Copyright (C) 1997-2005 Luke Howard
+ Copyright (C) 2006 West Consulting
+ Copyright (C) 2006 Arthur de Jong
+
+ This 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+#include "config.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"
+#include "common.h"
+#include "log.h"
+
+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);
+
+ return stat;
+}
+
+static int write_alias(LDAPMessage *e,struct ldap_state *pvt,FILE *fp)
+{
+ int stat;
+ if ((stat=_nss_ldap_write_rndvalue(fp,e,ATM(LM_ALIASES,cn)))!=NSLCD_RESULT_SUCCESS)
+ return stat;
+ if ((stat=_nss_ldap_write_attrvals(fp,e,AT(rfc822MailMember)))!=NSLCD_RESULT_SUCCESS)
+ return stat;
+ return NSLCD_RESULT_SUCCESS;
+}
+
+
+/* macros for expanding the NSLCD_ALIAS macro */
+#define NSLCD_STRING(field) WRITE_STRING(fp,field)
+#define NSLCD_STRINGLIST(field) WRITE_STRINGLIST_NUM(fp,field,result.alias_members_len)
+#define ALIAS_NAME result.alias_name
+#define ALIAS_RCPTS result.alias_members
+
+int nslcd_alias_byname(FILE *fp)
+{
+ int32_t tmpint32;
+ char *name;
+ struct ldap_args a;
+ /* read request parameters */
+ READ_STRING_ALLOC(fp,name);
+ /* log call */
+ log_log(LOG_DEBUG,"nslcd_alias_byname(%s)",name);
+ /* write the response header */
+ WRITE_INT32(fp,NSLCD_VERSION);
+ WRITE_INT32(fp,NSLCD_ACTION_ALIAS_BYNAME);
+ /* do the LDAP request */
+ LA_INIT(a);
+ LA_STRING(a)=name;
+ LA_TYPE(a)=LA_TYPE_STRING;
+ _nss_ldap_searchbyname(&a,_nss_ldap_filt_getaliasbyname,LM_ALIASES,fp,write_alias);
+ /* no more need for this */
+ free(name);
+ WRITE_FLUSH(fp);
+ /* we're done */
+ return 0;
+}
+
+int nslcd_alias_all(FILE *fp)
+{
+ int32_t tmpint32,tmp2int32;
+ static struct ent_context *alias_context;
+ /* these are here for now until we rewrite the LDAP code */
+ struct aliasent result;
+ char buffer[1024];
+ int errnop;
+ int retv;
+ /* log call */
+ log_log(LOG_DEBUG,"nslcd_alias_all()");
+ /* write the response header */
+ WRITE_INT32(fp,NSLCD_VERSION);
+ WRITE_INT32(fp,NSLCD_ACTION_ALIAS_ALL);
+ /* initialize context */
+ if (_nss_ldap_ent_context_init(&alias_context)==NULL)
+ return -1;
+ /* loop over all results */
+ while ((retv=nss2nslcd(_nss_ldap_getent(&alias_context,&result,buffer,1024,&errnop,_nss_ldap_filt_getaliasent,LM_ALIASES,_nss_ldap_parse_alias)))==NSLCD_RESULT_SUCCESS)
+ {
+ /* write the result */
+ WRITE_INT32(fp,retv);
+ NSLCD_ALIAS;
+ }
+ /* write the final result code */
+ WRITE_INT32(fp,retv);
+ WRITE_FLUSH(fp);
+ /* FIXME: if a previous call returns what happens to the context? */
+ _nss_ldap_enter();
+ _nss_ldap_ent_context_release(alias_context);
+ _nss_ldap_leave();
+ /* we're done */
+ return 0;
+}
diff --git a/nslcd/common.c b/nslcd/common.c
new file mode 100644
index 0000000..33d203d
--- /dev/null
+++ b/nslcd/common.c
@@ -0,0 +1,42 @@
+/*
+ common.c - common server code routines
+ This file is part of the nss-ldapd library.
+
+ Copyright (C) 2006 West Consulting
+ Copyright (C) 2006 Arthur de Jong
+
+ This 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+#include "config.h"
+
+#include "nslcd.h"
+#include "common.h"
+
+/* translates a nslcd return code (as defined in nslcd.h) to
+ a nss code (as defined in nss.h) */
+/* FIXME: this is a temporary hack, get rid of it */
+int nss2nslcd(enum nss_status code)
+{
+ switch (code)
+ {
+ case NSS_STATUS_UNAVAIL: return NSLCD_RESULT_UNAVAIL;
+ case NSS_STATUS_NOTFOUND: return NSLCD_RESULT_NOTFOUND;
+ case NSS_STATUS_SUCCESS: return NSLCD_RESULT_SUCCESS;
+/* case NSS_STATUS_TRYAGAIN: return NSLCD_RS_SMALLBUF; */
+ default: return NSLCD_RESULT_UNAVAIL;
+ }
+}
diff --git a/nslcd/common.h b/nslcd/common.h
new file mode 100644
index 0000000..42f47ea
--- /dev/null
+++ b/nslcd/common.h
@@ -0,0 +1,89 @@
+/*
+ common.h - common server code routines
+ This file is part of the nss-ldapd library.
+
+ Copyright (C) 2006 West Consulting
+ Copyright (C) 2006 Arthur de Jong
+
+ This 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+#ifndef _SERVER_COMMON_H
+#define _SERVER_COMMON_H 1
+
+#include "nslcd.h"
+#include "nslcd-common.h"
+
+
+/* translates a nss code (as defined in nss.h) to a
+ nslcd return code (as defined in nslcd.h) */
+/* FIXME: this is a temporary hack, get rid of it */
+#include <nss.h>
+int nss2nslcd(enum nss_status code);
+
+
+/* macros for basic read and write operations, the following
+ ERROR_OUT* marcos define the action taken on errors
+ the stream is not closed because the caller closes the
+ stream */
+
+#define ERROR_OUT_WRITEERROR(fp) \
+ log_log(LOG_WARNING,"error writing to client"); \
+ return -1;
+
+#define ERROR_OUT_READERROR(fp) \
+ log_log(LOG_WARNING,"error reading from client"); \
+ return -1;
+
+#define ERROR_OUT_ALLOCERROR(fp) \
+ log_log(LOG_ERR,"error allocating memory"); \
+ return -1;
+
+
+/* these are the different functions that handle the database
+ specific actions, see nslcd.h for the action descriptions */
+int nslcd_alias_byname(FILE *fp);
+int nslcd_alias_all(FILE *fp);
+int nslcd_ether_byname(FILE *fp);
+int nslcd_ether_byether(FILE *fp);
+int nslcd_ether_all(FILE *fp);
+int nslcd_group_byname(FILE *fp);
+int nslcd_group_bygid(FILE *fp);
+int nslcd_group_bymember(FILE *fp);
+int nslcd_group_all(FILE *fp);
+int nslcd_host_byname(FILE *fp);
+int nslcd_host_byaddr(FILE *fp);
+int nslcd_host_all(FILE *fp);
+int nslcd_netgroup_byname(FILE *fp);
+int nslcd_network_byname(FILE *fp);
+int nslcd_network_byaddr(FILE *fp);
+int nslcd_network_all(FILE *fp);
+int nslcd_passwd_byname(FILE *fp);
+int nslcd_passwd_byuid(FILE *fp);
+int nslcd_passwd_all(FILE *fp);
+int nslcd_protocol_byname(FILE *fp);
+int nslcd_protocol_bynumber(FILE *fp);
+int nslcd_protocol_all(FILE *fp);
+int nslcd_rpc_byname(FILE *fp);
+int nslcd_rpc_bynumber(FILE *fp);
+int nslcd_rpc_all(FILE *fp);
+int nslcd_service_byname(FILE *fp);
+int nslcd_service_bynumber(FILE *fp);
+int nslcd_service_all(FILE *fp);
+int nslcd_shadow_byname(FILE *fp);
+int nslcd_shadow_all(FILE *fp);
+
+#endif /* not _SERVER_COMMON_H */
diff --git a/nslcd/dnsconfig.c b/nslcd/dnsconfig.c
new file mode 100644
index 0000000..12b0997
--- /dev/null
+++ b/nslcd/dnsconfig.c
@@ -0,0 +1,188 @@
+/*
+ dnsconfig.c - lookup code for DNS SRV records
+ This file was part of the nss_ldap library which has been
+ forked into the nss-ldapd library.
+
+ Copyright (C) 1997-2005 Luke Howard
+
+ This 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+/*
+ * Support DNS SRV records. I look up the SRV record for
+ * _ldap._tcp.gnu.org.
+ * and build the DN DC=gnu,DC=org.
+ * Thanks to Assar & co for resolve.[ch].
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <netdb.h>
+#include <syslog.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <string.h>
+#ifdef HAVE_LBER_H
+#include <lber.h>
+#endif
+#ifdef HAVE_LDAP_H
+#include <ldap.h>
+#endif
+
+#include "ldap-nss.h"
+#include "util.h"
+#include "resolve.h"
+#include "dnsconfig.h"
+
+#define DC_ATTR "DC"
+#define DC_ATTR_AVA DC_ATTR"="
+#define DC_ATTR_AVA_LEN (sizeof(DC_ATTR_AVA) - 1)
+
+/* map gnu.org into DC=gnu,DC=org */
+static enum nss_status
+_nss_ldap_getdnsdn (char *src_domain,
+ char **rval, char **buffer, size_t * buflen)
+{
+ char *p;
+ int len = 0;
+#ifdef HAVE_STRTOK_R
+ char *st = NULL;
+#endif
+ char *bptr;
+ char *domain, *domain_copy;
+
+ /* we need to take a copy of domain, because strtok() modifies
+ * it in place. Bad.
+ */
+ domain_copy = strdup (src_domain);
+ if (domain_copy == NULL)
+ {
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ domain = domain_copy;
+
+ bptr = *rval = *buffer;
+ **rval = '\0';
+
+#ifndef HAVE_STRTOK_R
+ while ((p = strtok (domain, ".")))
+#else
+ while ((p = strtok_r (domain, ".", &st)))
+#endif
+ {
+ len = strlen (p);
+
+ if (*buflen < (size_t) (len + DC_ATTR_AVA_LEN + 1 /* D C = [,|\0] */ ))
+ {
+ free (domain_copy);
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ if (domain == NULL)
+ {
+ strcpy (bptr, ",");
+ bptr++;
+ }
+ else
+ {
+ domain = NULL;
+ }
+
+ strcpy (bptr, DC_ATTR_AVA);
+ bptr += DC_ATTR_AVA_LEN;
+
+ strcpy (bptr, p);
+ bptr += len; /* don't include comma */
+ *buffer += len + DC_ATTR_AVA_LEN + 1;
+ *buflen -= len + DC_ATTR_AVA_LEN + 1;
+ }
+
+ if (bptr != NULL)
+ {
+ (*rval)[bptr - *rval] = '\0';
+ }
+
+ free (domain_copy);
+
+ return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_ldap_mergeconfigfromdns (struct ldap_config * result,
+ char **buffer, size_t *buflen)
+{
+ enum nss_status stat = NSS_STATUS_SUCCESS;
+ struct dns_reply *r;
+ struct resource_record *rr;
+ char domain[MAXHOSTNAMELEN + 1];
+ char *pDomain;
+ char uribuf[NSS_BUFSIZ];
+
+ if ((_res.options & RES_INIT) == 0 && res_init () == -1)
+ {
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ if (result->ldc_srv_domain != NULL)
+ pDomain = result->ldc_srv_domain;
+ else
+ {
+ snprintf (domain, sizeof (domain), "_ldap._tcp.%s.", _res.defdname);
+ pDomain = domain;
+ }
+
+ r = dns_lookup (pDomain, "srv");
+ if (r == NULL)
+ {
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ /* XXX sort by priority */
+ for (rr = r->head; rr != NULL; rr = rr->next)
+ {
+ if (rr->type == T_SRV)
+ {
+ snprintf (uribuf, sizeof(uribuf), "ldap%s:%s:%d",
+ (rr->u.srv->port == LDAPS_PORT) ? "s" : "",
+ rr->u.srv->target,
+ rr->u.srv->port);
+
+ stat = _nss_ldap_add_uri (result, uribuf, buffer, buflen);
+ if (stat != NSS_STATUS_SUCCESS)
+ {
+ break;
+ }
+ }
+ }
+
+ dns_free_data (r);
+ stat = NSS_STATUS_SUCCESS;
+
+ if (result->ldc_base == NULL)
+ {
+ stat = _nss_ldap_getdnsdn (_res.defdname, &result->ldc_base,
+ buffer, buflen);
+ }
+
+ return stat;
+}
+
diff --git a/nslcd/dnsconfig.h b/nslcd/dnsconfig.h
new file mode 100644
index 0000000..479a717
--- /dev/null
+++ b/nslcd/dnsconfig.h
@@ -0,0 +1,30 @@
+/*
+ dnsconfig.c - lookup code for DNS SRV records
+ This file was part of the nss_ldap library which has been
+ forked into the nss-ldapd library.
+
+ Copyright (C) 1997-2005 Luke Howard
+
+ This 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+#ifndef _LDAP_NSS_LDAP_DNSCONFIG_H
+#define _LDAP_NSS_LDAP_DNSCONFIG_H
+
+enum nss_status _nss_ldap_mergeconfigfromdns (struct ldap_config * result,
+ char **buffer, size_t *buflen);
+
+#endif /* _LDAP_NSS_LDAP_DNSCONFIG_H */
diff --git a/nslcd/ether.c b/nslcd/ether.c
new file mode 100644
index 0000000..ab7b870
--- /dev/null
+++ b/nslcd/ether.c
@@ -0,0 +1,231 @@
+/*
+ ether.c - ethernet address entry lookup routines
+ This file was part of the nss_ldap library (as ldap-ethers.c)
+ which has been forked into the nss-ldapd library.
+
+ Copyright (C) 1997-2005 Luke Howard
+ Copyright (C) 2006 West Consulting
+ Copyright (C) 2006 Arthur de Jong
+
+ This 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+#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"
+#include "common.h"
+#include "log.h"
+
+#ifndef HAVE_STRUCT_ETHER_ADDR
+struct ether_addr {
+ u_int8_t ether_addr_octet[6];
+};
+#endif
+
+struct ether
+{
+ char *e_name;
+ struct ether_addr e_addr;
+};
+
+#ifdef NEW
+static int write_ether(LDAPMessage *e,struct ldap_state *pvt,FILE *fp)
+{
+ int stat;
+ char buffer[1024];
+ /* write NSLCD_STRING(ETHER_NAME) */
+ stat=_nss_ldap_write_attrval(fp,e,ATM(LM_ETHERS,cn));
+ if (stat!=NSLCD_RESULT_SUCCESS)
+ return stat;
+ /* write NSLCD_TYPE(ETHER_ADDR,u_int8_t[6]) */
+ stat=_nss_ldap_write_attrval_ether(fp,e,AT(macAddress));
+
+ 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 NSLCD_RESULT_SUCCESS;
+}
+#endif /* NEW */
+
+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;
+}
+
+/* macros for expanding the NSLCD_ETHER macro */
+#define NSLCD_STRING(field) WRITE_STRING(fp,field)
+#define NSLCD_TYPE(field,type) WRITE_TYPE(fp,field,type)
+#define ETHER_NAME result.e_name
+#define ETHER_ADDR result.e_addr
+
+int nslcd_ether_byname(FILE *fp)
+{
+ int32_t tmpint32;
+ char *name;
+ struct ldap_args a;
+ /* these are here for now until we rewrite the LDAP code */
+ struct ether result;
+ char buffer[1024];
+ int errnop;
+ int retv;
+ /* read request parameters */
+ READ_STRING_ALLOC(fp,name);
+ /* log call */
+ log_log(LOG_DEBUG,"nslcd_ether_byname(%s)",name);
+ /* write the response header */
+ WRITE_INT32(fp,NSLCD_VERSION);
+ WRITE_INT32(fp,NSLCD_ACTION_ETHER_BYNAME);
+ /* do the LDAP request */
+ LA_INIT(a);
+ LA_STRING(a)=name;
+ LA_TYPE(a)=LA_TYPE_STRING;
+ retv=nss2nslcd(_nss_ldap_getbyname(&a,&result,buffer,1024,&errnop,_nss_ldap_filt_gethostton,LM_ETHERS,_nss_ldap_parse_ether));
+ /* no more need for this string */
+ free(name);
+ /* write the response */
+ WRITE_INT32(fp,retv);
+ if (retv==NSLCD_RESULT_SUCCESS)
+ {
+ NSLCD_ETHER;
+ }
+ WRITE_FLUSH(fp);
+ /* we're done */
+ return 0;
+}
+
+int nslcd_ether_byether(FILE *fp)
+{
+ int32_t tmpint32;
+ struct ether_addr addr;
+ struct ldap_args a;
+ /* these are here for now until we rewrite the LDAP code */
+ struct ether result;
+ char buffer[1024];
+ int errnop;
+ int retv;
+ /* read request parameters */
+ READ_TYPE(fp,addr,u_int8_t[6]);
+ /* log call */
+ log_log(LOG_DEBUG,"nslcd_ether_byether(%s)",ether_ntoa(&addr));
+ /* write the response header */
+ WRITE_INT32(fp,NSLCD_VERSION);
+ WRITE_INT32(fp,NSLCD_ACTION_ETHER_BYETHER);
+ /* do the LDAP request */
+ LA_INIT(a);
+ /* FIXME: this has a bug when the directory has 01:00:0e:...
+ and we're looking for 1:0:e:... (leading zeros) */
+ LA_STRING(a)=ether_ntoa(&addr);
+ LA_TYPE(a)=LA_TYPE_STRING;
+ retv=nss2nslcd(_nss_ldap_getbyname(&a,&result,buffer,1024,&errnop,_nss_ldap_filt_getntohost,LM_ETHERS,_nss_ldap_parse_ether));
+ /* write the response */
+ WRITE_INT32(fp,retv);
+ if (retv==NSLCD_RESULT_SUCCESS)
+ {
+ NSLCD_ETHER;
+ }
+ WRITE_FLUSH(fp);
+ /* we're done */
+ return 0;
+}
+
+int nslcd_ether_all(FILE *fp)
+{
+ int32_t tmpint32;
+ static struct ent_context *ether_context;
+ /* these are here for now until we rewrite the LDAP code */
+ struct ether result;
+ char buffer[1024];
+ int errnop;
+ int retv;
+ /* log call */
+ log_log(LOG_DEBUG,"nslcd_ether_all()");
+ /* write the response header */
+ WRITE_INT32(fp,NSLCD_VERSION);
+ WRITE_INT32(fp,NSLCD_ACTION_ETHER_ALL);
+ /* initialize context */
+ if (_nss_ldap_ent_context_init(&ether_context)==NULL)
+ return -1;
+ /* loop over all results */
+ while ((retv=nss2nslcd(_nss_ldap_getent(&ether_context,&result,buffer,1024,&errnop,_nss_ldap_filt_getetherent,LM_ETHERS,_nss_ldap_parse_ether)))==NSLCD_RESULT_SUCCESS)
+ {
+ /* write the result */
+ WRITE_INT32(fp,retv);
+ NSLCD_ETHER;
+ }
+ /* write the final result code */
+ WRITE_INT32(fp,retv);
+ WRITE_FLUSH(fp);
+ /* FIXME: if a previous call returns what happens to the context? */
+ _nss_ldap_enter();
+ _nss_ldap_ent_context_release(ether_context);
+ _nss_ldap_leave();
+ /* we're done */
+ return 0;
+}
diff --git a/nslcd/group.c b/nslcd/group.c
new file mode 100644
index 0000000..e537e96
--- /dev/null
+++ b/nslcd/group.c
@@ -0,0 +1,1231 @@
+/*
+ group.c - group entry lookup routines
+ This file was part of the nss_ldap library (as ldap-grp.c) which
+ has been forked into the nss-ldapd library.
+
+ Copyright (C) 1997-2006 Luke Howard
+ Copyright (C) 2006 West Consulting
+ Copyright (C) 2006 Arthur de Jong
+
+ This 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+#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"
+#include "common.h"
+#include "log.h"
+
+#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 */
+
+#define LDAP_NSS_MAXGR_DEPTH 16 /* maximum depth of group nesting for getgrent()/initgroups() */
+
+#if LDAP_NSS_NGROUPS > 64
+#define LDAP_NSS_BUFLEN_GROUP (NSS_BUFSIZ + (LDAP_NSS_NGROUPS * (sizeof (char *) + LOGNAME_MAX)))
+#else
+#define LDAP_NSS_BUFLEN_GROUP NSS_BUFSIZ
+#endif /* LDAP_NSS_NGROUPS > 64 */
+
+#ifndef LOGNAME_MAX
+#define LOGNAME_MAX 8
+#endif /* LOGNAME_MAX */
+
+#ifndef UID_NOBODY
+#define UID_NOBODY (-2)
+#endif
+
+#ifndef GID_NOBODY
+#define GID_NOBODY UID_NOBODY
+#endif
+
+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;
+}
+
+
+static enum nss_status group_bymember(const char *user, long int *start,
+ long int *size, 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 ("==> group_bymember (user=%s)", LA_STRING (a) );
+
+ lia.depth = 0;
+ lia.known_groups = NULL;
+
+ _nss_ldap_enter ();
+
+ /* initialize schema */
+ stat = _nss_ldap_init ();
+ if (stat != NSS_STATUS_SUCCESS)
+ {
+ debug ("<== group_bymember (init failed)");
+ _nss_ldap_leave ();
+ return stat;
+ }
+
+ if (_nss_ldap_test_initgroups_ignoreuser (LA_STRING (a)))
+ {
+ debug ("<== group_bymember (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 ("<== group_bymember (ent_context_init failed)");
+ _nss_ldap_leave ();
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ stat = _nss_ldap_getent_ex (&a, &ctx, (void *) &lia, NULL, 0,
+ errnop,
+ filter,
+ map,
+ gidnumber_attrs,
+ do_parse_initgroups_nested);
+
+ if (userdn != NULL)
+ ldap_memfree (userdn);
+
+ _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 ("<== group_bymember (not found)");
+ if (erange)
+ errno = ERANGE;
+ return stat;
+ }
+
+ debug ("<== group_bymember (success)");
+
+ return NSS_STATUS_SUCCESS;
+}
+
+/* macros for expanding the NSLCD_GROUP macro */
+#define NSLCD_STRING(field) WRITE_STRING(fp,field)
+#define NSLCD_TYPE(field,type) WRITE_TYPE(fp,field,type)
+#define NSLCD_STRINGLIST(field) WRITE_STRINGLIST_NULLTERM(fp,field)
+#define GROUP_NAME result.gr_name
+#define GROUP_PASSWD result.gr_passwd
+#define GROUP_GID result.gr_gid
+#define GROUP_MEMBERS result.gr_mem
+
+int nslcd_group_byname(FILE *fp)
+{
+ int32_t tmpint32,tmp2int32,tmp3int32;
+ char *name;
+ struct ldap_args a;
+ /* these are here for now until we rewrite the LDAP code */
+ struct group result;
+ char buffer[1024];
+ int errnop;
+ int retv;
+ /* read request parameters */
+ READ_STRING_ALLOC(fp,name);
+ /* FIXME: free() this buffer somewhere */
+ /* log call */
+ log_log(LOG_DEBUG,"nslcd_group_byname(%s)",name);
+ /* static buffer size check */
+ if (1024<LDAP_NSS_BUFLEN_GROUP)
+ {
+ log_log(LOG_CRIT,"allocated buffer in nslcd_group_byname() too small");
+ exit(1);
+ }
+ /* do the LDAP request */
+ LA_INIT(a);
+ LA_STRING(a)=name;
+ LA_TYPE(a)=LA_TYPE_STRING;
+ retv=nss2nslcd(_nss_ldap_getbyname(&a,&result,buffer,1024,&errnop,_nss_ldap_filt_getgrnam,LM_GROUP,_nss_ldap_parse_gr));
+ /* no more need for this */
+ free(name);
+ /* write the response */
+ WRITE_INT32(fp,NSLCD_VERSION);
+ WRITE_INT32(fp,NSLCD_ACTION_GROUP_BYNAME);
+ WRITE_INT32(fp,retv);
+ if (retv==NSLCD_RESULT_SUCCESS)
+ {
+ NSLCD_GROUP;
+ }
+ WRITE_FLUSH(fp);
+ /* we're done */
+ return 0;
+}
+
+int nslcd_group_bygid(FILE *fp)
+{
+ int32_t tmpint32,tmp2int32,tmp3int32;
+ gid_t gid;
+ struct ldap_args a;
+ /* these are here for now until we rewrite the LDAP code */
+ struct group result;
+ char buffer[1024];
+ int errnop;
+ int retv;
+ /* read request parameters */
+ READ_TYPE(fp,gid,gid_t);
+ /* FIXME: free() this buffer somewhere */
+ /* log call */
+ log_log(LOG_DEBUG,"nslcd_group_bygid(%d)",(int)gid);
+ /* static buffer size check */
+ if (1024<LDAP_NSS_BUFLEN_GROUP)
+ {
+ log_log(LOG_CRIT,"allocated buffer in nslcd_group_byname() too small");
+ exit(1);
+ }
+ /* do the LDAP request */
+ LA_INIT(a);
+ LA_NUMBER(a)=gid;
+ LA_TYPE(a)=LA_TYPE_NUMBER;
+ retv=nss2nslcd(_nss_ldap_getbyname(&a,&result,buffer,1024,&errnop,_nss_ldap_filt_getgrgid,LM_GROUP,_nss_ldap_parse_gr));
+ /* write the response */
+ WRITE_INT32(fp,NSLCD_VERSION);
+ WRITE_INT32(fp,NSLCD_ACTION_GROUP_BYGID);
+ WRITE_INT32(fp,retv);
+ if (retv==NSLCD_RESULT_SUCCESS)
+ {
+ NSLCD_GROUP;
+ }
+ WRITE_FLUSH(fp);
+ /* we're done */
+ return 0;
+}
+
+int nslcd_group_bymember(FILE *fp)
+{
+ int32_t tmpint32;
+ char *name;
+ /* these are here for now until we rewrite the LDAP code */
+ int errnop;
+ int retv;
+ long int start=0,size=1024;
+ long int i;
+ gid_t groupsp[1024];
+ /* read request parameters */
+ READ_STRING_ALLOC(fp,name);
+ /* FIXME: free() this buffer somewhere */
+ /* log call */
+ log_log(LOG_DEBUG,"nslcd_group_bymember(%s)",name);
+ /* do the LDAP request */
+ retv=NSLCD_RESULT_NOTFOUND;
+ /*
+ retv=nss2nslcd(group_bymember(name,&start,&size,size,&errnop));
+ */
+ /* Note: we write some garbadge here to ensure protocol error as this
+ function currently returns incorrect data */
+ /* Note: what to do with group ids that are not listed as supplemental
+ groups but are the user's primary group id? */
+ WRITE_INT32(fp,1234);
+ start=0;
+ /* TODO: fix this to actually work */
+ /* write the response header */
+ WRITE_INT32(fp,NSLCD_VERSION);
+ WRITE_INT32(fp,NSLCD_ACTION_GROUP_BYNAME);
+ if (retv==NSLCD_RESULT_SUCCESS)
+ {
+ /* loop over the returned gids */
+ for (i=0;i<start;i++)
+ {
+ WRITE_INT32(fp,NSLCD_RESULT_SUCCESS);
+ /* Note: we will write a fake record here for now. This is because
+ we want to keep the protocol but currently the only
+ client application available discards non-gid information */
+ WRITE_STRING(fp,""); /* group name */
+ WRITE_STRING(fp,"*"); /* group passwd */
+ WRITE_TYPE(fp,groupsp[i],gid_t); /* gid */
+ WRITE_INT32(fp,1); /* number of members */
+ WRITE_STRING(fp,name); /* member=user requested */
+ }
+ WRITE_INT32(fp,NSLCD_RESULT_NOTFOUND);
+ }
+ else
+ {
+ /* some error occurred */
+ WRITE_INT32(fp,retv);
+ }
+ WRITE_FLUSH(fp);
+ /* no more need for this */
+ free(name);
+ /* we're done */
+ return 0;
+}
+
+int nslcd_group_all(FILE *fp)
+{
+ int32_t tmpint32,tmp2int32,tmp3int32;
+ struct ent_context *gr_context=NULL;
+ /* these are here for now until we rewrite the LDAP code */
+ struct group result;
+ char buffer[1024];
+ int errnop;
+ int retv;
+ /* log call */
+ log_log(LOG_DEBUG,"nslcd_group_all()");
+ /* write the response header */
+ WRITE_INT32(fp,NSLCD_VERSION);
+ WRITE_INT32(fp,NSLCD_ACTION_GROUP_ALL);
+ /* initialize context */
+ if (_nss_ldap_ent_context_init(&gr_context)==NULL)
+ return -1;
+ /* loop over all results */
+ while ((retv=nss2nslcd(_nss_ldap_getent(&gr_context,&result,buffer,1024,&errnop,_nss_ldap_filt_getgrent,LM_GROUP,_nss_ldap_parse_gr)))==NSLCD_RESULT_SUCCESS)
+ {
+ /* write the result */
+ WRITE_INT32(fp,retv);
+ NSLCD_GROUP;
+ }
+ /* write the final result code */
+ WRITE_INT32(fp,retv);
+ WRITE_FLUSH(fp);
+ /* FIXME: if a previous call returns what happens to the context? */
+ _nss_ldap_enter();
+ _nss_ldap_ent_context_release(gr_context);
+ _nss_ldap_leave();
+ /* we're done */
+ return 0;
+}
diff --git a/nslcd/host.c b/nslcd/host.c
new file mode 100644
index 0000000..ec04bf2
--- /dev/null
+++ b/nslcd/host.c
@@ -0,0 +1,380 @@
+/*
+ host.c - host name lookup routines
+ This file was part of the nss_ldap library (as ldap-hosts.c)
+ which has been forked into the nss-ldapd library.
+
+ Copyright (C) 1997-2005 Luke Howard
+ Copyright (C) 2006 West Consulting
+ Copyright (C) 2006 Arthur de Jong
+
+ This 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+#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"
+#include "common.h"
+#include "log.h"
+
+#ifndef MAXALIASES
+#define MAXALIASES 35
+#endif
+
+/* write a single host entry to the stream */
+static int write_hostent(FILE *fp,struct hostent *result)
+{
+ int32_t tmpint32,tmp2int32,tmp3int32;
+ int numaddr,i;
+ /* write the host entry */
+ WRITE_STRING(fp,result->h_name);
+ /* write the alias list */
+ WRITE_STRINGLIST_NULLTERM(fp,result->h_aliases);
+ /* write the number of addresses */
+ for (numaddr=0;result->h_addr_list[numaddr]!=NULL;numaddr++)
+ /*noting*/ ;
+ WRITE_INT32(fp,numaddr);
+ /* write the addresses */
+ for (i=0;i<numaddr;i++)
+ {
+ WRITE_INT32(fp,result->h_addrtype);
+ WRITE_INT32(fp,result->h_length);
+ WRITE(fp,result->h_addr_list[i],result->h_length);
+ }
+ return 0;
+}
+
+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
+
+int nslcd_host_byname(FILE *fp)
+{
+ int32_t tmpint32;
+ char *name;
+ struct ldap_args a;
+ int retv;
+ struct hostent result;
+ char buffer[1024];
+ int errnop;
+ /* read request parameters */
+ READ_STRING_ALLOC(fp,name);
+ /* log call */
+ log_log(LOG_DEBUG,"nslcd_host_byname(%s)",name);
+ /* write the response header */
+ WRITE_INT32(fp,NSLCD_VERSION);
+ WRITE_INT32(fp,NSLCD_ACTION_HOST_BYNAME);
+ /* do the LDAP request */
+ LA_INIT(a);
+ LA_STRING(a)=name;
+ LA_TYPE(a)=LA_TYPE_STRING;
+ retv=nss2nslcd(_nss_ldap_getbyname(&a,&result,buffer,1024,&errnop,_nss_ldap_filt_gethostbyname,LM_HOSTS,
+#ifdef INET6
+ (af == AF_INET6)?_nss_ldap_parse_hostv6:_nss_ldap_parse_hostv4));
+#else
+ _nss_ldap_parse_hostv4));
+#endif
+ /* no more need for this string */
+ free(name);
+ /* write the response */
+ WRITE_INT32(fp,retv);
+ if (retv==NSLCD_RESULT_SUCCESS)
+ write_hostent(fp,&result);
+ WRITE_FLUSH(fp);
+ /* we're done */
+ return 0;
+}
+
+int nslcd_host_byaddr(FILE *fp)
+{
+ int32_t tmpint32;
+ int af;
+ int len;
+ char addr[64],name[1024];
+ struct ldap_args a;
+ int retv;
+ struct hostent result;
+ char buffer[1024];
+ int errnop;
+ /* read address family */
+ READ_INT32(fp,af);
+ if ((af!=AF_INET)&&(af!=AF_INET6))
+ {
+ log_log(LOG_WARNING,"incorrect address family specified: %d",af);
+ return -1;
+ }
+ /* read address length */
+ READ_INT32(fp,len);
+ if ((len>64)||(len<=0))
+ {
+ log_log(LOG_WARNING,"address length incorrect: %d",len);
+ return -1;
+ }
+ /* read address */
+ READ(fp,addr,len);
+ /* translate the address to a string */
+ if (inet_ntop(af,addr,name,1024)==NULL)
+ {
+ log_log(LOG_WARNING,"unable to convert address to string");
+ return -1;
+ }
+ /* log call */
+ log_log(LOG_DEBUG,"nslcd_host_byaddr(%s)",name);
+ /* write the response header */
+ WRITE_INT32(fp,NSLCD_VERSION);
+ WRITE_INT32(fp,NSLCD_ACTION_HOST_BYADDR);
+ /* do the LDAP request */
+ LA_INIT(a);
+ LA_STRING(a)=name;
+ LA_TYPE(a)=LA_TYPE_STRING;
+ retv=nss2nslcd(_nss_ldap_getbyname(&a,&result,buffer,1024,&errnop,_nss_ldap_filt_gethostbyaddr,LM_HOSTS,
+#ifdef INET6
+ (af == AF_INET6)?_nss_ldap_parse_hostv6:_nss_ldap_parse_hostv4));
+#else
+ _nss_ldap_parse_hostv4));
+#endif
+ /* write the response */
+ WRITE_INT32(fp,retv);
+ if (retv==NSLCD_RESULT_SUCCESS)
+ write_hostent(fp,&result);
+ WRITE_FLUSH(fp);
+ /* we're done */
+ return 0;
+}
+
+int nslcd_host_all(FILE *fp)
+{
+ int32_t tmpint32;
+ static struct ent_context *host_context;
+ /* these are here for now until we rewrite the LDAP code */
+ struct hostent result;
+ char buffer[1024];
+ int errnop;
+ int retv;
+ /* log call */
+ log_log(LOG_DEBUG,"nslcd_host_all()");
+ /* write the response header */
+ WRITE_INT32(fp,NSLCD_VERSION);
+ WRITE_INT32(fp,NSLCD_ACTION_HOST_ALL);
+ /* initialize context */
+ if (_nss_ldap_ent_context_init(&host_context)==NULL)
+ return -1;
+ /* loop over all results */
+ while ((retv=nss2nslcd(_nss_ldap_getent(&host_context,&result,buffer,1024,&errnop,_nss_ldap_filt_gethostent,LM_HOSTS,
+#ifdef INET6
+ (_res.options&RES_USE_INET6)?_nss_ldap_parse_hostv6:_nss_ldap_parse_hostv4
+#else
+ _nss_ldap_parse_hostv4
+#endif
+ )))==NSLCD_RESULT_SUCCESS)
+ {
+ /* write the result */
+ WRITE_INT32(fp,retv);
+ write_hostent(fp,&result);
+ }
+ /* write the final result code */
+ WRITE_INT32(fp,retv);
+ WRITE_FLUSH(fp);
+ /* FIXME: if a previous call returns what happens to the context? */
+ _nss_ldap_enter();
+ _nss_ldap_ent_context_release(host_context);
+ _nss_ldap_leave();
+ /* we're done */
+ return 0;
+}
diff --git a/nslcd/ldap-nss.c b/nslcd/ldap-nss.c
new file mode 100644
index 0000000..f442037
--- /dev/null
+++ b/nslcd/ldap-nss.c
@@ -0,0 +1,4032 @@
+/*
+ ldap-nss.c - main file for NSS interface
+ This file was part of the nss_ldap library which has been
+ forked into the nss-ldapd library.
+
+ Copyright (C) 1997-2006 Luke Howard
+ Copyright (C) 2006 West Consulting
+ Copyright (C) 2006 Arthur de Jong
+
+ This 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#include <stdio.h>
+#include <syslog.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <errno.h>
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+#include <netinet/in.h>
+#ifdef HAVE_LBER_H
+#include <lber.h>
+#endif
+#ifdef HAVE_LDAP_H
+#include <ldap.h>
+#endif
+#ifdef HAVE_LDAP_SSL_H
+#include <ldap_ssl.h>
+#endif
+#ifdef HAVE_GSSLDAP_H
+#include <gssldap.h>
+#endif
+#ifdef HAVE_GSSSASL_H
+#include <gsssasl.h>
+#endif
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+#if defined(HAVE_THREAD_H)
+#include <thread.h>
+#elif defined(HAVE_PTHREAD_H)
+#include <pthread.h>
+#endif
+/* Try to handle systems with both SASL libraries installed */
+#if defined(HAVE_SASL_SASL_H) && defined(HAVE_SASL_AUXPROP_REQUEST)
+#include <sasl/sasl.h>
+#elif defined(HAVE_SASL_H)
+#include <sasl.h>
+#endif
+#ifdef HAVE_GSSAPI_H
+#include <gssapi.h>
+#elif defined(HAVE_GSSAPI_GSSAPI_KRB5_H)
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_krb5.h>
+#endif
+
+#include "ldap-nss.h"
+#include "util.h"
+#include "dnsconfig.h"
+#include "pagectrl.h"
+#include "common.h"
+#include "log.h"
+
+#if defined(HAVE_THREAD_H)
+#ifdef HAVE_PTHREAD_ATFORK
+#undef HAVE_PTHREAD_ATFORK
+#endif
+#endif
+
+/* how many messages to retrieve results for */
+#ifndef LDAP_MSG_ONE
+#define LDAP_MSG_ONE 0x00
+#endif
+#ifndef LDAP_MSG_ALL
+#define LDAP_MSG_ALL 0x01
+#endif
+#ifndef LDAP_MSG_RECEIVED
+#define LDAP_MSG_RECEIVED 0x02
+#endif
+
+#ifdef HAVE_LDAP_LD_FREE
+#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
+extern int ldap_ld_free (LDAP * ld, int close, LDAPControl **,
+ LDAPControl **);
+#else
+extern int ldap_ld_free (LDAP * ld, int close);
+#endif /* OPENLDAP 2.x */
+#endif /* HAVE_LDAP_LD_FREE */
+
+NSS_LDAP_DEFINE_LOCK (__lock);
+
+/*
+ * LS_INIT only used for enumeration contexts
+ */
+#define LS_INIT(state) do { state.ls_type = LS_TYPE_INDEX; state.ls_retry = 0; state.ls_info.ls_index = -1; } while (0)
+
+/*
+ * the configuration is read by the first call to do_open().
+ * Pointers to elements of the list are passed around but should not
+ * be freed.
+ */
+static char __configbuf[NSS_LDAP_CONFIG_BUFSIZ];
+static struct ldap_config *__config = NULL;
+
+#ifdef HAVE_SIGACTION
+static struct sigaction __stored_handler;
+static int __sigaction_retval = -1;
+#else
+static void (*__sigpipe_handler) (int) = SIG_DFL;
+#endif /* HAVE_SIGACTION */
+
+/*
+ * Global LDAP session.
+ */
+static struct ldap_session __session = { NULL, NULL, 0, LS_UNINITIALIZED };
+
+#if defined(HAVE_PTHREAD_ATFORK) || defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H)
+static pthread_once_t __once = PTHREAD_ONCE_INIT;
+#endif
+
+#ifdef LBER_OPT_LOG_PRINT_FILE
+static FILE *__debugfile;
+#endif /* LBER_OPT_LOG_PRINT_FILE */
+
+#ifndef HAVE_PTHREAD_ATFORK
+/*
+ * Process ID that opened the session.
+ */
+static pid_t __pid = -1;
+#endif
+static uid_t __euid = -1;
+
+#ifdef HAVE_LDAPSSL_CLIENT_INIT
+static int __ssl_initialized = 0;
+#endif /* HAVE_LDAPSSL_CLIENT_INIT */
+
+#if defined(HAVE_PTHREAD_ATFORK) || defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H)
+/*
+ * Prepare for fork(); lock mutex.
+ */
+static void do_atfork_prepare (void);
+
+/*
+ * Forked in parent, unlock mutex.
+ */
+static void do_atfork_parent (void);
+
+/*
+ * Forked in child; close LDAP socket, unlock mutex.
+ */
+static void do_atfork_child (void);
+
+/*
+ * Install handlers for atfork, called once.
+ */
+static void do_atfork_setup (void);
+#endif
+
+/*
+ * Close the global session, sending an unbind.
+ */
+static void do_close (void);
+
+/*
+ * Close the global session without sending an unbind.
+ */
+static void do_close_no_unbind (void);
+
+/*
+ * Disable keepalive on a LDAP connection's socket.
+ */
+static void do_set_sockopts (void);
+
+/*
+ * TLS routines: set global SSL session options.
+ */
+#if defined(HAVE_LDAP_START_TLS_S) || defined(HAVE_LDAP_START_TLS) || (defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS))
+static int do_ssl_options (struct ldap_config * cfg);
+static int do_start_tls (struct ldap_session * session);
+#endif
+
+/*
+ * Function to be braced by reconnect harness. Used so we
+ * can apply the reconnect code to both asynchronous and
+ * synchronous searches.
+ */
+typedef int (*search_func_t) (const char *, int, const char *,
+ const char **, int, void *);
+
+static enum nss_status
+do_map_error (int rc)
+{
+ enum nss_status stat;
+
+ switch (rc)
+ {
+ case LDAP_SUCCESS:
+ case LDAP_SIZELIMIT_EXCEEDED:
+ case LDAP_TIMELIMIT_EXCEEDED:
+ stat = NSS_STATUS_SUCCESS;
+ break;
+ case LDAP_NO_SUCH_ATTRIBUTE:
+ case LDAP_UNDEFINED_TYPE:
+ case LDAP_INAPPROPRIATE_MATCHING:
+ case LDAP_CONSTRAINT_VIOLATION:
+ case LDAP_TYPE_OR_VALUE_EXISTS:
+ case LDAP_INVALID_SYNTAX:
+ case LDAP_NO_SUCH_OBJECT:
+ case LDAP_ALIAS_PROBLEM:
+ case LDAP_INVALID_DN_SYNTAX:
+ case LDAP_IS_LEAF:
+ case LDAP_ALIAS_DEREF_PROBLEM:
+ case LDAP_FILTER_ERROR:
+ stat = NSS_STATUS_NOTFOUND;
+ break;
+ case LDAP_SERVER_DOWN:
+ case LDAP_TIMEOUT:
+ case LDAP_UNAVAILABLE:
+ case LDAP_BUSY:
+#ifdef LDAP_CONNECT_ERROR
+ case LDAP_CONNECT_ERROR:
+#endif /* LDAP_CONNECT_ERROR */
+ case LDAP_LOCAL_ERROR:
+ case LDAP_INVALID_CREDENTIALS:
+ default:
+ stat = NSS_STATUS_UNAVAIL;
+ break;
+ }
+ return stat;
+}
+
+#if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) ||defined (HAVE_SASL_SASL_H))
+static int
+do_sasl_interact (LDAP * ld, unsigned flags, void *defaults, void *_interact)
+{
+ char *authzid = (char *) defaults;
+ sasl_interact_t *interact = (sasl_interact_t *) _interact;
+
+ while (interact->id != SASL_CB_LIST_END)
+ {
+ if (interact->id == SASL_CB_USER)
+ {
+ if (authzid != NULL)
+ {
+ interact->result = authzid;
+ interact->len = strlen (authzid);
+ }
+ else if (interact->defresult != NULL)
+ {
+ interact->result = interact->defresult;
+ interact->len = strlen (interact->defresult);
+ }
+ else
+ {
+ interact->result = "";
+ interact->len = 0;
+ }
+#if SASL_VERSION_MAJOR < 2
+ interact->result = strdup (interact->result);
+ if (interact->result == NULL)
+ {
+ return LDAP_NO_MEMORY;
+ }
+#endif /* SASL_VERSION_MAJOR < 2 */
+ }
+ else
+ {
+ return LDAP_PARAM_ERROR;
+ }
+ interact++;
+ }
+ return LDAP_SUCCESS;
+}
+#endif
+
+static int
+do_bind (LDAP * ld, int timelimit, const char *dn, const char *pw,
+ int with_sasl)
+{
+ int rc;
+ int msgid;
+ struct timeval tv;
+ LDAPMessage *result;
+
+ debug("==> do_bind");
+
+ /*
+ * set timelimit in ld for select() call in ldap_pvt_connect()
+ * function implemented in libldap2's os-ip.c
+ */
+ tv.tv_sec = timelimit;
+ tv.tv_usec = 0;
+
+#if (defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H))) || defined(HAVE_LDAP_GSS_BIND)
+ if (!with_sasl)
+ {
+#endif
+ msgid = ldap_simple_bind (ld, dn, pw);
+
+ if (msgid < 0)
+ {
+ if (ldap_get_option (ld, LDAP_OPT_ERROR_NUMBER, &rc) !=
+ LDAP_SUCCESS)
+ {
+ rc = LDAP_UNAVAILABLE;
+ }
+ /* Notify if we failed. */
+ syslog (LOG_AUTHPRIV | LOG_ERR, "nss_ldap: could not connect to any LDAP server as %s - %s",
+ dn, ldap_err2string (rc));
+ debug ("<== do_bind");
+
+ return rc;
+ }
+
+ rc = ldap_result (ld, msgid, 0, &tv, &result);
+ if (rc > 0)
+ {
+ debug ("<== do_bind");
+ return ldap_result2error (ld, result, 1);
+ }
+
+ /* took too long */
+ if (rc == 0)
+ {
+ ldap_abandon (ld, msgid);
+ }
+#if (defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H))) || defined(HAVE_LDAP_GSS_BIND)
+ }
+ else
+ {
+#ifdef HAVE_LDAP_GSS_BIND
+ return ldap_gss_bind (ld, dn, pw, GSSSASL_NO_SECURITY_LAYER,
+ LDAP_SASL_GSSAPI);
+#else
+#ifdef CONFIGURE_KRB5_CCNAME
+#ifndef CONFIGURE_KRB5_CCNAME_GSSAPI
+ char tmpbuf[256];
+ static char envbuf[256];
+#endif
+ char *ccname;
+ const char *oldccname = NULL;
+ int retval;
+#endif /* CONFIGURE_KRB5_CCNAME */
+
+ if (__config->ldc_sasl_secprops != NULL)
+ {
+ rc =
+ ldap_set_option (ld, LDAP_OPT_X_SASL_SECPROPS,
+ (void *) __config->ldc_sasl_secprops);
+ if (rc != LDAP_SUCCESS)
+ {
+ debug ("do_bind: unable to set SASL security properties");
+ return rc;
+ }
+ }
+
+#ifdef CONFIGURE_KRB5_CCNAME
+ /* Set default Kerberos ticket cache for SASL-GSSAPI */
+ /* There are probably race conditions here XXX */
+ if (__config->ldc_krb5_ccname != NULL)
+ {
+ ccname = __config->ldc_krb5_ccname;
+#ifdef CONFIGURE_KRB5_CCNAME_ENV
+ oldccname = getenv ("KRB5CCNAME");
+ if (oldccname != NULL)
+ {
+ strncpy (tmpbuf, oldccname, sizeof (tmpbuf));
+ tmpbuf[sizeof (tmpbuf) - 1] = '\0';
+ }
+ else
+ {
+ tmpbuf[0] = '\0';
+ }
+ oldccname = tmpbuf;
+ snprintf (envbuf, sizeof (envbuf), "KRB5CCNAME=%s", ccname);
+ putenv (envbuf);
+#elif defined(CONFIGURE_KRB5_CCNAME_GSSAPI)
+ if (gss_krb5_ccache_name (&retval, ccname, &oldccname) !=
+ GSS_S_COMPLETE)
+ {
+ debug ("do_bind: unable to set default credential cache");
+ return -1;
+ }
+#endif
+ }
+#endif /* CONFIGURE_KRB5_CCNAME */
+
+ rc = ldap_sasl_interactive_bind_s (ld, dn, "GSSAPI", NULL, NULL,
+ LDAP_SASL_QUIET,
+ do_sasl_interact, (void *) pw);
+
+#ifdef CONFIGURE_KRB5_CCNAME
+ /* Restore default Kerberos ticket cache. */
+ if (oldccname != NULL)
+ {
+#ifdef CONFIGURE_KRB5_CCNAME_ENV
+ snprintf (envbuf, sizeof (envbuf), "KRB5CCNAME=%s", oldccname);
+ putenv (envbuf);
+#elif defined(CONFIGURE_KRB5_CCNAME_GSSAPI)
+ if (gss_krb5_ccache_name (&retval, oldccname, NULL) !=
+ GSS_S_COMPLETE)
+ {
+ debug ("do_bind: unable to restore default credential cache");
+ return -1;
+ }
+#endif
+ }
+#endif /* CONFIGURE_KRB5_CCNAME */
+
+ return rc;
+#endif /* HAVE_LDAP_GSS_BIND */
+ }
+#endif
+
+ debug ("<== do_bind");
+
+ return -1;
+}
+
+/*
+ * Rebind functions.
+ */
+
+#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
+#if LDAP_SET_REBIND_PROC_ARGS == 3
+static int
+do_rebind (LDAP * ld, LDAP_CONST char *url, ber_tag_t request,
+ ber_int_t msgid, void *arg)
+#else
+static int
+do_rebind (LDAP * ld, LDAP_CONST char *url, int request, ber_int_t msgid)
+#endif
+{
+ char *who, *cred;
+ int timelimit;
+ int with_sasl = 0;
+
+ if (geteuid () == 0 && __session.ls_config->ldc_rootbinddn)
+ {
+ who = __session.ls_config->ldc_rootbinddn;
+#if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H))
+ with_sasl = __session.ls_config->ldc_rootusesasl;
+ if (with_sasl)
+ {
+ cred = __session.ls_config->ldc_rootsaslid;
+ }
+ else
+ {
+#endif
+ cred = __session.ls_config->ldc_rootbindpw;
+#if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H))
+ }
+#endif
+ }
+ else
+ {
+ who = __session.ls_config->ldc_binddn;
+#if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H))
+ with_sasl = __session.ls_config->ldc_usesasl;
+ if (with_sasl)
+ {
+ cred = __session.ls_config->ldc_saslid;
+ }
+ else
+ {
+#endif
+ cred = __session.ls_config->ldc_bindpw;
+#if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H))
+ }
+#endif
+ }
+
+ timelimit = __session.ls_config->ldc_bind_timelimit;
+
+#ifdef HAVE_LDAP_START_TLS_S
+ if (__session.ls_config->ldc_ssl_on == SSL_START_TLS)
+ {
+ int version;
+
+ if (ldap_get_option
+ (__session.ls_conn, LDAP_OPT_PROTOCOL_VERSION,
+ &version) == LDAP_OPT_SUCCESS)
+ {
+ if (version < LDAP_VERSION3)
+ {
+ version = LDAP_VERSION3;
+ ldap_set_option (__session.ls_conn, LDAP_OPT_PROTOCOL_VERSION,
+ &version);
+ }
+ }
+
+ if (do_start_tls (&__session) == LDAP_SUCCESS)
+ {
+ debug ("TLS startup succeeded");
+ }
+ else
+ {
+ debug ("TLS startup failed");
+ return NSS_STATUS_UNAVAIL;
+ }
+ }
+#endif /* HAVE_LDAP_START_TLS_S */
+
+ return do_bind (ld, timelimit, who, cred, with_sasl);
+}
+#else
+#if LDAP_SET_REBIND_PROC_ARGS == 3
+static int
+do_rebind (LDAP * ld, char **whop, char **credp, int *methodp,
+ int freeit, void *arg)
+#elif LDAP_SET_REBIND_PROC_ARGS == 2
+static int
+do_rebind (LDAP * ld, char **whop, char **credp, int *methodp, int freeit)
+#endif
+{
+ if (freeit)
+ {
+ if (*whop != NULL)
+ free (*whop);
+ if (*credp != NULL)
+ free (*credp);
+ }
+
+ *whop = *credp = NULL;
+ if (geteuid () == 0 && __session.ls_config->ldc_rootbinddn)
+ {
+ *whop = strdup (__session.ls_config->ldc_rootbinddn);
+ if (__session.ls_config->ldc_rootbindpw != NULL)
+ *credp = strdup (__session.ls_config->ldc_rootbindpw);
+ }
+ else
+ {
+ if (__session.ls_config->ldc_binddn != NULL)
+ *whop = strdup (__session.ls_config->ldc_binddn);
+ if (__session.ls_config->ldc_bindpw != NULL)
+ *credp = strdup (__session.ls_config->ldc_bindpw);
+ }
+
+ *methodp = LDAP_AUTH_SIMPLE;
+
+ return LDAP_SUCCESS;
+}
+#endif
+
+static void
+_nss_ldap_block_sigpipe (void)
+{
+#ifdef HAVE_SIGACTION
+ struct sigaction new_handler;
+
+ memset (&new_handler, 0, sizeof (new_handler));
+#if 0
+ /* XXX need to test for sa_sigaction, not on all platforms */
+ new_handler.sa_sigaction = NULL;
+#endif
+ new_handler.sa_handler = SIG_IGN;
+ sigemptyset (&new_handler.sa_mask);
+ new_handler.sa_flags = 0;
+#endif /* HAVE_SIGACTION */
+
+ /*
+ * Patch for Debian Bug 130006:
+ * ignore SIGPIPE for all LDAP operations.
+ *
+ * The following bug was reintroduced in nss_ldap-213 and is fixed here:
+ * http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=84344
+ *
+ * See:
+ * http://www.gnu.org/software/libc/manual/html_node/Signal-and-Sigaction.html
+ * for more details.
+ */
+#ifdef HAVE_SIGACTION
+ __sigaction_retval = sigaction (SIGPIPE, &new_handler, &__stored_handler);
+#elif defined(HAVE_SIGSET)
+ __sigpipe_handler = sigset (SIGPIPE, SIG_IGN);
+#else
+ __sigpipe_handler = signal (SIGPIPE, SIG_IGN);
+#endif /* HAVE_SIGSET */
+}
+
+static void
+_nss_ldap_unblock_sigpipe (void)
+{
+#ifdef HAVE_SIGACTION
+ if (__sigaction_retval == 0)
+ (void) sigaction (SIGPIPE, &__stored_handler, NULL);
+#else
+ if (__sigpipe_handler != SIG_ERR && __sigpipe_handler != SIG_IGN)
+ {
+#ifdef HAVE_SIGSET
+ (void) sigset (SIGPIPE, __sigpipe_handler);
+#else
+ (void) signal (SIGPIPE, __sigpipe_handler);
+#endif /* HAVE_SIGSET */
+ }
+#endif /* HAVE_SIGACTION */
+}
+
+#if defined(HAVE_PTHREAD_ATFORK) || defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H)
+static void
+do_atfork_prepare (void)
+{
+ debug ("==> do_atfork_prepare");
+ NSS_LDAP_LOCK (__lock);
+ debug ("<== do_atfork_prepare");
+}
+
+static void
+do_atfork_parent (void)
+{
+ debug ("==> do_atfork_parent");
+ NSS_LDAP_UNLOCK (__lock);
+ debug ("<== do_atfork_parent");
+}
+
+static void
+do_atfork_child (void)
+{
+ debug ("==> do_atfork_child");
+ _nss_ldap_block_sigpipe();
+ do_close_no_unbind ();
+ _nss_ldap_unblock_sigpipe();
+ NSS_LDAP_UNLOCK (__lock);
+ debug ("<== do_atfork_child");
+}
+
+static void
+do_atfork_setup (void)
+{
+ debug ("==> do_atfork_setup");
+
+#ifdef HAVE_PTHREAD_ATFORK
+ (void) pthread_atfork (do_atfork_prepare, do_atfork_parent,
+ do_atfork_child);
+#elif defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H)
+ (void) __libc_atfork (do_atfork_prepare, do_atfork_parent, do_atfork_child);
+#endif
+
+ debug ("<== do_atfork_setup");
+}
+#endif
+
+/*
+ * Acquires global lock, blocks SIGPIPE.
+ */
+void
+_nss_ldap_enter (void)
+{
+ debug ("==> _nss_ldap_enter");
+
+ NSS_LDAP_LOCK (__lock);
+ _nss_ldap_block_sigpipe();
+
+ debug ("<== _nss_ldap_enter");
+}
+
+/*
+ * Releases global mutex, releases SIGPIPE.
+ */
+void
+_nss_ldap_leave (void)
+{
+ debug ("==> _nss_ldap_leave");
+
+ _nss_ldap_unblock_sigpipe();
+ NSS_LDAP_UNLOCK (__lock);
+
+ debug ("<== _nss_ldap_leave");
+}
+
+static void
+do_set_sockopts (void)
+{
+/*
+ * Netscape SSL-enabled LDAP library does not
+ * return the real socket.
+ */
+#ifndef HAVE_LDAPSSL_CLIENT_INIT
+ int sd = -1;
+
+ debug ("==> do_set_sockopts");
+ if (ldap_get_option (__session.ls_conn, LDAP_OPT_DESC, &sd) == 0)
+ {
+ int off = 0;
+ socklen_t socknamelen = sizeof (struct sockaddr_storage);
+ socklen_t peernamelen = sizeof (struct sockaddr_storage);
+
+ (void) setsockopt (sd, SOL_SOCKET, SO_KEEPALIVE, (void *) &off,
+ sizeof (off));
+ (void) fcntl (sd, F_SETFD, FD_CLOEXEC);
+ /*
+ * NSS modules shouldn't open file descriptors that the program/utility
+ * linked against NSS doesn't know about. The LDAP library opens a
+ * connection to the LDAP server transparently. There's an edge case
+ * where a daemon might fork a child and, being written well, closes
+ * all its file descriptors. This will close the socket descriptor
+ * being used by the LDAP library! Worse, the daemon might open many
+ * files and sockets, eventually opening a descriptor with the same number
+ * as that originally used by the LDAP library. The only way to know that
+ * this isn't "our" socket descriptor is to save the local and remote
+ * sockaddr_in structures for later comparison.
+ */
+ (void) getsockname (sd, (struct sockaddr *) &__session.ls_sockname,
+ &socknamelen);
+ (void) getpeername (sd, (struct sockaddr *) &__session.ls_peername,
+ &peernamelen);
+ }
+ debug ("<== do_set_sockopts");
+#endif /* HAVE_LDAPSSL_CLIENT_INIT */
+
+ return;
+}
+
+/*
+ * Closes connection to the LDAP server.
+ * This assumes that we have exclusive access to __session.ls_conn,
+ * either by some other function having acquired a lock, or by
+ * using a thread safe libldap.
+ */
+static void
+do_close (void)
+{
+#if defined(DEBUG) || defined(DEBUG_SOCKETS)
+ int sd = -1;
+#endif
+
+ debug ("==> do_close");
+
+ if (__session.ls_conn != NULL)
+ {
+#if defined(DEBUG) || defined(DEBUG_SOCKETS)
+#if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_DESC)
+ ldap_get_option (__session.ls_conn, LDAP_OPT_DESC, &sd);
+#else
+ sd = __session.ls_conn->ld_sb.sb_sd;
+#endif /* LDAP_OPT_DESC */
+ syslog (LOG_AUTHPRIV | LOG_INFO, "nss_ldap: closing connection %p fd %d",
+ (void *)__session.ls_conn, sd);
+#endif /* DEBUG */
+
+ ldap_unbind (__session.ls_conn);
+ __session.ls_conn = NULL;
+ __session.ls_state = LS_UNINITIALIZED;
+ }
+
+ debug ("<== do_close");
+}
+
+static int
+do_sockaddr_isequal (struct sockaddr_storage *_s1,
+ socklen_t _slen1,
+ struct sockaddr_storage *_s2,
+ socklen_t _slen2)
+{
+ int ret;
+
+ if (_s1->ss_family != _s2->ss_family)
+ return 0;
+
+ if (_slen1 != _slen2)
+ return 0;
+
+ ret = 0;
+
+ switch (_s1->ss_family)
+ {
+ case AF_INET:
+ {
+ struct sockaddr_in *s1 = (struct sockaddr_in *) _s1;
+ struct sockaddr_in *s2 = (struct sockaddr_in *) _s2;
+
+ ret = (s1->sin_port == s2->sin_port &&
+ memcmp (&s1->sin_addr, &s2->sin_addr, sizeof(struct in_addr)) == 0);
+ break;
+ }
+ case AF_UNIX:
+ {
+ struct sockaddr_un *s1 = (struct sockaddr_un *) _s1;
+ struct sockaddr_un *s2 = (struct sockaddr_un *) _s2;
+
+ ret = (memcmp (s1->sun_path, s2->sun_path,
+ _slen1 - sizeof (_s1->ss_family)) == 0);
+ break;
+ }
+#ifdef INET6
+ case AF_INET6:
+ {
+ struct sockaddr_in6 *s1 = (struct sockaddr_in6 *) _s1;
+ struct sockaddr_in6 *s2 = (struct sockaddr_in6 *) _s2;
+
+ ret = (s1->sin6_port == s2->sin6_port &&
+ memcmp (&s1->sin6_addr, &s2->sin6_addr, sizeof(struct in6_addr)) == 0 &&
+ s1->sin6_scope_id == s2->sin6_scope_id);
+ break;
+ }
+#endif
+ default:
+ ret = (memcmp (_s1, _s2, _slen1) == 0);
+ break;
+ }
+
+ return ret;
+}
+
+static int
+do_get_our_socket(int *sd)
+{
+ /*
+ * Before freeing the LDAP context or closing the socket descriptor,
+ * we must ensure that it is *our* socket descriptor. See the much
+ * lengthier description of this at the end of do_open () where the
+ * values __session.ls_sockname and __session.ls_peername are saved.
+ * With HAVE_LDAPSSL_CLIENT_INIT this returns 0 if the socket has
+ * been closed or reopened, and sets *sd to the ldap socket
+ * descriptor.. Returns 1 in all other cases.
+ */
+
+ int isOurSocket = 1;
+
+#ifndef HAVE_LDAPSSL_CLIENT_INIT
+ if (ldap_get_option (__session.ls_conn, LDAP_OPT_DESC, sd) == 0)
+ {
+ struct sockaddr_storage sockname;
+ struct sockaddr_storage peername;
+ socklen_t socknamelen = sizeof (sockname);
+ socklen_t peernamelen = sizeof (peername);
+
+ if (getsockname (*sd, (struct sockaddr *) &sockname, &socknamelen) != 0 ||
+ getpeername (*sd, (struct sockaddr *) &peername, &peernamelen) != 0)
+ {
+ isOurSocket = 0;
+ }
+ else
+ {
+ isOurSocket = do_sockaddr_isequal (&__session.ls_sockname,
+ socknamelen,
+ &sockname,
+ socknamelen);
+ if (isOurSocket)
+ {
+ isOurSocket = do_sockaddr_isequal (&__session.ls_peername,
+ peernamelen,
+ &peername,
+ peernamelen);
+ }
+ }
+ }
+#endif /* HAVE_LDAPSSL_CLIENT_INIT */
+ return isOurSocket;
+}
+
+static int
+do_dupfd(int oldfd, int newfd)
+{
+ int d = -1;
+ int flags;
+
+ flags = fcntl(oldfd, F_GETFD);
+
+ while (1)
+ {
+ d = (newfd > -1) ? dup2 (oldfd, newfd) : dup (oldfd);
+ if (d > -1)
+ break;
+
+ if (errno == EBADF)
+ return -1; /* not open */
+
+ if (errno != EINTR
+#ifdef EBUSY
+ && errno != EBUSY
+#endif
+ )
+ return -1;
+ }
+
+ /* duplicate close-on-exec flag */
+ (void) fcntl (d, F_SETFD, flags);
+
+ return d;
+}
+
+static int
+do_closefd(int fd)
+{
+ int rc;
+
+ while ((rc = close(fd)) < 0 && errno == EINTR)
+ ;
+
+ return rc;
+}
+
+static void
+do_drop_connection(int sd, int closeSd)
+{
+ /* Close the LDAP connection without writing anything to the
+ underlying socket. The socket will be left open afterwards if
+ closeSd is 0 */
+#ifndef HAVE_LDAPSSL_CLIENT_INIT
+ {
+ int dummyfd = -1, savedfd = -1;
+ /* Under OpenLDAP 2.x, ldap_set_option (..., LDAP_OPT_DESC, ...) is
+ a no-op, so to shut down the LDAP connection without writing
+ anything to the socket, we swap a dummy socket onto that file
+ descriptor, and then swap the real fd back once the shutdown is
+ done. */
+ savedfd = do_dupfd (sd, -1);
+ dummyfd = socket (AF_INET, SOCK_STREAM, 0);
+ if (dummyfd > -1 && dummyfd != sd)
+ {
+ do_closefd (sd);
+ do_dupfd (dummyfd, sd);
+ do_closefd (dummyfd);
+ }
+
+#ifdef HAVE_LDAP_LD_FREE
+#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
+ (void) ldap_ld_free (__session.ls_conn, 0, NULL, NULL);
+#else
+ (void) ldap_ld_free (__session.ls_conn, 0);
+#endif /* OPENLDAP 2.x */
+#else
+ ldap_unbind (__session.ls_conn);
+#endif /* HAVE_LDAP_LD_FREE */
+
+ /* Do we want our original sd back? */
+ do_closefd (sd);
+ if (savedfd > -1)
+ {
+ if (closeSd == 0)
+ do_dupfd (savedfd, sd);
+ do_closefd (savedfd);
+ }
+ }
+#else /* No sd available */
+ {
+ int bogusSd = -1;
+ if (closeSd == 0)
+ {
+ sd = -1; /* don't want to really close the socket */
+#ifdef HAVE_LDAP_LD_FREE
+#if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_DESC)
+ (void) ldap_set_option (__session.ls_conn, LDAP_OPT_DESC, &sd);
+#else
+ __session.ls_conn->ld_sb.sb_sd = -1;
+#endif /* LDAP_OPT_DESC */
+#endif /* HAVE_LDAP_LD_FREE */
+ }
+
+#ifdef HAVE_LDAP_LD_FREE
+
+#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
+ (void) ldap_ld_free (__session.ls_conn, 0, NULL, NULL);
+#else
+ (void) ldap_ld_free (__session.ls_conn, 0);
+#endif /* OPENLDAP 2.x */
+
+#else
+
+#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_DESC)
+ (void) ldap_set_option (__session.ls_conn, LDAP_OPT_DESC, &bogusSd);
+#else
+ __session.ls_conn->ld_sb.sb_sd = bogusSd;
+#endif /* LDAP_OPT_DESC */
+
+ /* hope we closed it OK! */
+ ldap_unbind (__session.ls_conn);
+
+#endif /* HAVE_LDAP_LD_FREE */
+
+ }
+#endif /* HAVE_LDAPSSL_CLIENT_INIT */
+ __session.ls_conn = NULL;
+ __session.ls_state = LS_UNINITIALIZED;
+
+ return;
+}
+
+/*
+ * If we've forked, then we need to open a new session.
+ * Careful: we have the socket shared with our parent,
+ * so we don't want to send an unbind to the server.
+ * However, we want to close the descriptor to avoid
+ * leaking it, and we also want to release the memory
+ * used by __session.ls_conn. The only entry point
+ * we have is ldap_unbind() which does both of these
+ * things, so we use an internal API, at the expense
+ * of compatibility.
+ */
+static void
+do_close_no_unbind (void)
+{
+ int sd = -1;
+ int closeSd = 1;
+
+ debug ("==> do_close_no_unbind");
+
+ if (__session.ls_state == LS_UNINITIALIZED)
+ {
+ assert (__session.ls_conn == NULL);
+ debug ("<== do_close_no_unbind (connection was not open)");
+ return;
+ }
+
+ closeSd = do_get_our_socket (&sd);
+
+#if defined(DEBUG) || defined(DEBUG_SOCKETS)
+ syslog (LOG_AUTHPRIV | LOG_INFO, "nss_ldap: %sclosing connection (no unbind) %p fd %d",
+ closeSd ? "" : "not ", (void *)__session.ls_conn, sd);
+#endif /* DEBUG */
+
+ do_drop_connection(sd, closeSd);
+
+ debug ("<== do_close_no_unbind");
+
+ return;
+}
+
+static enum nss_status
+do_init_session (LDAP ** ld, const char *uri, int defport)
+{
+ int rc;
+ int ldaps;
+ char uribuf[NSS_BUFSIZ];
+ char *p;
+ enum nss_status stat;
+
+ ldaps = (strncasecmp (uri, "ldaps://", sizeof ("ldaps://") - 1) == 0);
+ p = strchr (uri, ':');
+ /* we should be looking for the second instance to find the port number */
+ if (p != NULL)
+ {
+ p = strchr (p, ':');
+ }
+
+#ifdef HAVE_LDAP_INITIALIZE
+ if (p == NULL &&
+ ((ldaps && defport != LDAPS_PORT) || (!ldaps && defport != LDAP_PORT)))
+ {
+ /* No port specified in URI and non-default port specified */
+ snprintf (uribuf, sizeof (uribuf), "%s:%d", uri, defport);
+ uri = uribuf;
+ }
+
+ rc = ldap_initialize (ld, uri);
+#else
+ if (strncasecmp (uri, "ldap://", sizeof ("ldap://") - 1) != 0)
+ {
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ uri += sizeof ("ldap://") - 1;
+ p = strchr (uri, ':');
+
+ if (p != NULL)
+ {
+ size_t urilen = (p - uri);
+
+ if (urilen >= sizeof (uribuf))
+ {
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ memcpy (uribuf, uri, urilen);
+ uribuf[urilen] = '\0';
+
+ defport = atoi (p + 1);
+ uri = uribuf;
+ }
+
+#ifdef HAVE_LDAP_INIT
+ *ld = ldap_init (uri, defport);
+#else
+ *ld = ldap_open (uri, defport);
+#endif
+
+ rc = (*ld == NULL) ? LDAP_SERVER_DOWN : LDAP_SUCCESS;
+
+#endif /* HAVE_LDAP_INITIALIZE */
+
+ stat = do_map_error (rc);
+ if (stat == NSS_STATUS_SUCCESS && *ld == NULL)
+ {
+ stat = NSS_STATUS_UNAVAIL;
+ }
+ return stat;
+}
+
+static enum nss_status
+do_init (void)
+{
+ struct ldap_config *cfg;
+#ifndef HAVE_PTHREAD_ATFORK
+ pid_t pid;
+#endif
+ uid_t euid;
+ enum nss_status stat;
+ int sd=-1;
+
+ debug ("==> do_init");
+
+ if (_nss_ldap_validateconfig (__config) != NSS_STATUS_SUCCESS)
+ {
+ do_close ();
+ __config = NULL;
+ __session.ls_current_uri = 0;
+ }
+
+#ifndef HAVE_PTHREAD_ATFORK
+#if defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H)
+ /*
+ * This bogosity is necessary because Linux uses different
+ * PIDs for different threads (like IRIX, which we don't
+ * support). We can tell whether we are linked against
+ * libpthreads by whether __pthread_once is NULL or
+ * not. If it is NULL, then we're not linked with the
+ * threading library, and we need to compare the current
+ * process ID against the saved one to figure out
+ * whether we've forked.
+ *
+ * Once we know whether we have forked or not,
+ * courtesy of pthread_atfork() or us checking
+ * ourselves, we can close the socket to the LDAP
+ * server to avoid leaking a socket, and reopen
+ * another connection. Under no circumstances do we
+ * wish to use the same connection, or to send an
+ * unbind PDU over the parents connection, as that
+ * will wreak all sorts of havoc or inefficiencies,
+ * respectively.
+ */
+ if (__pthread_once == NULL)
+ pid = getpid ();
+ else
+ pid = -1; /* linked against libpthreads, don't care */
+#else
+ pid = getpid ();
+#endif /* HAVE_LIBC_LOCK_H || HAVE_BITS_LIBC_LOCK_H */
+#endif /* HAVE_PTHREAD_ATFORK */
+
+ euid = geteuid ();
+
+#ifdef DEBUG
+#ifdef HAVE_PTHREAD_ATFORK
+ syslog (LOG_AUTHPRIV | LOG_DEBUG,
+ "nss_ldap: __session.ls_state=%d, __session.ls_conn=%p, __euid=%i, euid=%i",
+ __session.ls_state, __session.ls_conn, __euid, euid);
+#elif defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H)
+ syslog (LOG_AUTHPRIV | LOG_DEBUG,
+ "nss_ldap: libpthreads=%s, __session.ls_state=%d, __session.ls_conn=%p, __pid=%i, pid=%i, __euid=%i, euid=%i",
+ (__pthread_once == NULL ? "FALSE" : "TRUE"),
+ __session.ls_state,
+ (void *)__session.ls_conn,
+ (__pthread_once == NULL ? __pid : -1),
+ (__pthread_once == NULL ? pid : -1), __euid, euid);
+#else
+ syslog (LOG_AUTHPRIV | LOG_DEBUG,
+ "nss_ldap: __session.ls_state=%d, __session.ls_conn=%p, __pid=%i, pid=%i, __euid=%i, euid=%i",
+ __session.ls_state, __session.ls_conn, __pid, pid, __euid, euid);
+#endif
+#endif /* DEBUG */
+
+ if (__session.ls_state == LS_CONNECTED_TO_DSA &&
+ do_get_our_socket (&sd) == 0)
+ {
+ /* The calling app has stolen our socket. */
+ debug (":== do_init (stolen socket detected)");
+ do_drop_connection (sd, 0);
+ }
+ else
+#ifndef HAVE_PTHREAD_ATFORK
+#if defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H)
+ if (__pthread_once == NULL && __pid != pid)
+#else
+ if (__pid != pid)
+#endif /* HAVE_LIBC_LOCK_H || HAVE_BITS_LIBC_LOCK_H */
+ {
+ do_close_no_unbind ();
+ }
+ else
+#endif /* HAVE_PTHREAD_ATFORK */
+ if (__euid != euid && (__euid == 0 || euid == 0))
+ {
+ /*
+ * If we've changed user ids, close the session so we can
+ * rebind as the correct user.
+ */
+ do_close ();
+ }
+ else if (__session.ls_state == LS_CONNECTED_TO_DSA)
+ {
+ time_t current_time;
+
+ /*
+ * Otherwise we can hand back this process' global
+ * LDAP session.
+ *
+ * Patch from Steven Barrus <sbarrus@eng.utah.edu> to
+ * close the session after an idle timeout.
+ */
+
+ assert (__session.ls_conn != NULL);
+ assert (__session.ls_config != NULL);
+
+ if (__session.ls_config->ldc_idle_timelimit)
+ {
+ time (&current_time);
+ if ((__session.ls_timestamp +
+ __session.ls_config->ldc_idle_timelimit) < current_time)
+ {
+ debug ("idle_timelimit reached");
+ do_close ();
+ }
+ }
+
+ /*
+ * If the connection is still there (ie. do_close() wasn't
+ * called) then we can return the cached connection.
+ */
+ if (__session.ls_state == LS_CONNECTED_TO_DSA)
+ {
+ debug ("<== do_init (cached session)");
+ return NSS_STATUS_SUCCESS;
+ }
+ }
+
+ __session.ls_conn = NULL;
+ __session.ls_timestamp = 0;
+ __session.ls_state = LS_UNINITIALIZED;
+
+#ifdef HAVE_PTHREAD_ATFORK
+ if (pthread_once (&__once, do_atfork_setup) != 0)
+ {
+ debug ("<== do_init (pthread_once failed)");
+ return NSS_STATUS_UNAVAIL;
+ }
+#elif defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H)
+ /*
+ * Only install the pthread_atfork() handlers i
+ * we are linked against libpthreads. Otherwise,
+ * do close the session when the PID changes.
+ */
+ if (__pthread_once == NULL)
+ __pid = pid;
+ else
+ __libc_once (__once, do_atfork_setup);
+#else
+ __pid = pid;
+#endif
+
+ __euid = euid;
+
+ /* Initialize schema and LDAP handle (but do not connect) */
+ if (__config == NULL)
+ {
+ char *configbufp = __configbuf;
+ size_t configbuflen = sizeof (__configbuf);
+
+ stat = _nss_ldap_readconfig (&__config, &configbufp, &configbuflen);
+ if (stat == NSS_STATUS_NOTFOUND)
+ {
+ /* Config was read but no host information specified; try DNS */
+ stat = _nss_ldap_mergeconfigfromdns (__config, &configbufp, &configbuflen);
+ }
+
+ if (stat != NSS_STATUS_SUCCESS)
+ {
+ debug ("<== do_init (failed to read config)");
+ return NSS_STATUS_UNAVAIL;
+ }
+ }
+
+ cfg = __config;
+
+ _nss_ldap_init_attributes (cfg->ldc_attrtab);
+ _nss_ldap_init_filters ();
+
+#ifdef HAVE_LDAP_SET_OPTION
+ if (cfg->ldc_debug)
+ {
+#ifdef LBER_OPT_LOG_PRINT_FILE
+ if (cfg->ldc_logdir && !__debugfile)
+ {
+ char namebuf[PATH_MAX];
+
+ snprintf (namebuf, sizeof (namebuf), "%s/ldap.%d", cfg->ldc_logdir,
+ (int) getpid ());
+ __debugfile = fopen (namebuf, "a");
+
+ if (__debugfile != NULL)
+ {
+ ber_set_option (NULL, LBER_OPT_LOG_PRINT_FILE, __debugfile);
+ }
+ }
+#endif /* LBER_OPT_LOG_PRINT_FILE */
+#ifdef LBER_OPT_DEBUG_LEVEL
+ if (cfg->ldc_debug)
+ {
+ ber_set_option (NULL, LBER_OPT_DEBUG_LEVEL, &cfg->ldc_debug);
+ ldap_set_option (NULL, LDAP_OPT_DEBUG_LEVEL, &cfg->ldc_debug);
+ }
+#endif /* LBER_OPT_DEBUG_LEVEL */
+ }
+#endif /* HAVE_LDAP_SET_OPTION */
+
+#ifdef HAVE_LDAPSSL_CLIENT_INIT
+ /*
+ * Initialize the SSL library.
+ */
+ if (cfg->ldc_ssl_on == SSL_LDAPS)
+ {
+ int rc = 0;
+ if (__ssl_initialized == 0
+ && (rc = ldapssl_client_init (cfg->ldc_sslpath, NULL)) != LDAP_SUCCESS)
+ {
+ debug ("<== do_init (ldapssl_client_init failed with rc = %d)", rc);
+ return NSS_STATUS_UNAVAIL;
+ }
+ __ssl_initialized = 1;
+ }
+#endif /* SSL */
+
+ __session.ls_conn = NULL;
+
+ assert (__session.ls_current_uri <= NSS_LDAP_CONFIG_URI_MAX);
+ assert (cfg->ldc_uris[__session.ls_current_uri] != NULL);
+
+ stat = do_init_session (&__session.ls_conn,
+ cfg->ldc_uris[__session.ls_current_uri],
+ cfg->ldc_port);
+ if (stat != NSS_STATUS_SUCCESS)
+ {
+ debug ("<== do_init (failed to initialize LDAP session)");
+ return stat;
+ }
+
+ __session.ls_config = cfg;
+ __session.ls_state = LS_INITIALIZED;
+
+ debug ("<== do_init (initialized session)");
+
+ return NSS_STATUS_SUCCESS;
+}
+
+/*
+ * A simple alias around do_init().
+ */
+enum nss_status
+_nss_ldap_init (void)
+{
+ return do_init ();
+}
+
+/*
+ * A simple alias around do_close().
+ */
+void
+_nss_ldap_close (void)
+{
+ do_close ();
+}
+
+#if defined(HAVE_LDAP_START_TLS_S) || defined(HAVE_LDAP_START_TLS)
+static int
+do_start_tls (struct ldap_session * session)
+{
+ int rc;
+#ifdef HAVE_LDAP_START_TLS
+ int msgid;
+ struct timeval tv, *timeout;
+ LDAPMessage *res = NULL;
+
+ debug ("==> do_start_tls");
+
+ rc = ldap_start_tls (session->ls_conn, NULL, NULL, &msgid);
+ if (rc != LDAP_SUCCESS)
+ {
+ debug ("<== do_start_tls (ldap_start_tls failed: %s)", ldap_err2string (rc));
+ return rc;
+ }
+
+ if (session->ls_config->ldc_bind_timelimit == LDAP_NO_LIMIT)
+ {
+ timeout = NULL;
+ }
+ else
+ {
+ tv.tv_sec = session->ls_config->ldc_bind_timelimit;
+ tv.tv_usec = 0;
+ timeout = &tv;
+ }
+
+ rc = ldap_result (session->ls_conn, msgid, 1, timeout, &res);
+ if (rc == -1)
+ {
+#if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_ERROR_NUMBER)
+ if (ldap_get_option (session->ls_conn, LDAP_OPT_ERROR_NUMBER, &rc) != LDAP_SUCCESS)
+ {
+ rc = LDAP_UNAVAILABLE;
+ }
+#else
+ rc = ld->ld_errno;
+#endif /* LDAP_OPT_ERROR_NUMBER */
+
+ debug ("<== do_start_tls (ldap_start_tls failed: %s)", ldap_err2string (rc));
+ return rc;
+ }
+
+ rc = ldap_result2error (session->ls_conn, res, 1);
+ if (rc != LDAP_SUCCESS)
+ {
+ debug ("<== do_start_tls (ldap_result2error failed: %s)", ldap_err2string (rc));
+ return rc;
+ }
+
+ rc = ldap_install_tls (session->ls_conn);
+#else
+ rc = ldap_start_tls_s (session->ls_conn, NULL, NULL);
+#endif /* HAVE_LDAP_START_TLS */
+
+ if (rc != LDAP_SUCCESS)
+ {
+ debug ("<== do_start_tls (start TLS failed: %s)", ldap_err2string(rc));
+ return rc;
+ }
+
+ return LDAP_SUCCESS;
+}
+#endif
+
+/*
+ * Opens connection to an LDAP server - should only be called from search
+ * API. Other API that just needs access to configuration and schema should
+ * call do_init().
+ *
+ * As with do_close(), this assumes ownership of sess.
+ * It also wants to own __config: is there a potential deadlock here? XXX
+ */
+static enum nss_status
+do_open (void)
+{
+ struct ldap_config *cfg;
+ int usesasl;
+ char *bindarg;
+ enum nss_status stat;
+#ifdef LDAP_OPT_NETWORK_TIMEOUT
+ struct timeval tv;
+#endif
+#ifdef LDAP_X_OPT_CONNECT_TIMEOUT
+ int timeout;
+#endif
+ int rc;
+
+ debug ("==> do_open");
+
+ /* Moved the head part of do_open() into do_init() */
+ stat = do_init ();
+ if (stat != NSS_STATUS_SUCCESS)
+ {
+ debug ("<== do_open (session initialization failed)");
+ return stat;
+ }
+
+ assert (__session.ls_conn != NULL);
+ assert (__session.ls_config != NULL);
+ assert (__session.ls_state != LS_UNINITIALIZED);
+
+ if (__session.ls_state == LS_CONNECTED_TO_DSA)
+ {
+ debug ("<== do_open (cached session)");
+ return NSS_STATUS_SUCCESS;
+ }
+
+ cfg = __session.ls_config;
+
+#if LDAP_SET_REBIND_PROC_ARGS == 3
+ ldap_set_rebind_proc (__session.ls_conn, do_rebind, NULL);
+#elif LDAP_SET_REBIND_PROC_ARGS == 2
+ ldap_set_rebind_proc (__session.ls_conn, do_rebind);
+#endif
+
+ ldap_set_option (__session.ls_conn, LDAP_OPT_PROTOCOL_VERSION,
+ &cfg->ldc_version);
+
+ ldap_set_option (__session.ls_conn, LDAP_OPT_DEREF, &cfg->ldc_deref);
+
+ ldap_set_option (__session.ls_conn, LDAP_OPT_TIMELIMIT,
+ &cfg->ldc_timelimit);
+
+#ifdef LDAP_X_OPT_CONNECT_TIMEOUT
+ /*
+ * This is a new option in the Netscape SDK which sets
+ * the TCP connect timeout. For want of a better value,
+ * we use the bind_timelimit to control this.
+ */
+ timeout = cfg->ldc_bind_timelimit * 1000;
+ ldap_set_option (__session.ls_conn, LDAP_X_OPT_CONNECT_TIMEOUT, &timeout);
+#endif /* LDAP_X_OPT_CONNECT_TIMEOUT */
+
+#ifdef LDAP_OPT_NETWORK_TIMEOUT
+ tv.tv_sec = cfg->ldc_bind_timelimit;
+ tv.tv_usec = 0;
+ ldap_set_option (__session.ls_conn, LDAP_OPT_NETWORK_TIMEOUT, &tv);
+#endif /* LDAP_OPT_NETWORK_TIMEOUT */
+
+#ifdef LDAP_OPT_REFERRALS
+ ldap_set_option (__session.ls_conn, LDAP_OPT_REFERRALS,
+ cfg->ldc_referrals ? LDAP_OPT_ON : LDAP_OPT_OFF);
+#endif /* LDAP_OPT_REFERRALS */
+
+#ifdef LDAP_OPT_RESTART
+ ldap_set_option (__session.ls_conn, LDAP_OPT_RESTART,
+ cfg->ldc_restart ? LDAP_OPT_ON : LDAP_OPT_OFF);
+#endif /* LDAP_OPT_RESTART */
+
+#if defined(HAVE_LDAP_START_TLS_S) || defined(HAVE_LDAP_START_TLS)
+ if (cfg->ldc_ssl_on == SSL_START_TLS)
+ {
+ int version;
+
+ if (ldap_get_option
+ (__session.ls_conn, LDAP_OPT_PROTOCOL_VERSION,
+ &version) == LDAP_OPT_SUCCESS)
+ {
+ if (version < LDAP_VERSION3)
+ {
+ version = LDAP_VERSION3;
+ ldap_set_option (__session.ls_conn, LDAP_OPT_PROTOCOL_VERSION,
+ &version);
+ }
+ }
+
+ /* set up SSL context */
+ if (do_ssl_options (cfg) != LDAP_SUCCESS)
+ {
+ do_close ();
+ debug ("<== do_open (SSL setup failed)");
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ stat = do_map_error (do_start_tls (&__session));
+ if (stat == NSS_STATUS_SUCCESS)
+ {
+ debug (":== do_open (TLS startup succeeded)");
+ }
+ else
+ {
+ do_close ();
+ debug ("<== do_open (TLS startup failed)");
+ return stat;
+ }
+ }
+ else
+#endif /* HAVE_LDAP_START_TLS_S || HAVE_LDAP_START_TLS */
+
+ /*
+ * If SSL is desired, then enable it.
+ */
+ if (cfg->ldc_ssl_on == SSL_LDAPS)
+ {
+#if defined(LDAP_OPT_X_TLS)
+ int tls = LDAP_OPT_X_TLS_HARD;
+ if (ldap_set_option (__session.ls_conn, LDAP_OPT_X_TLS, &tls) !=
+ LDAP_SUCCESS)
+ {
+ do_close ();
+ debug ("<== do_open (TLS setup failed)");
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ /* set up SSL context */
+ if (do_ssl_options (cfg) != LDAP_SUCCESS)
+ {
+ do_close ();
+ debug ("<== do_open (SSL setup failed)");
+ return NSS_STATUS_UNAVAIL;
+ }
+
+#elif defined(HAVE_LDAPSSL_CLIENT_INIT)
+ if (ldapssl_install_routines (__session.ls_conn) != LDAP_SUCCESS)
+ {
+ do_close ();
+ debug ("<== do_open (SSL setup failed)");
+ return NSS_STATUS_UNAVAIL;
+ }
+/* not in Solaris 9? */
+#ifndef LDAP_OPT_SSL
+#define LDAP_OPT_SSL 0x0A
+#endif
+ if (ldap_set_option (__session.ls_conn, LDAP_OPT_SSL, LDAP_OPT_ON) !=
+ LDAP_SUCCESS)
+ {
+ do_close ();
+ debug ("<== do_open (SSL setup failed)");
+ return NSS_STATUS_UNAVAIL;
+ }
+#endif
+ }
+
+ /*
+ * If we're running as root, let us bind as a special
+ * user, so we can fake shadow passwords.
+ * Thanks to Doug Nazar <nazard@dragoninc.on.ca> for this
+ * patch.
+ */
+ if (__euid == 0 && cfg->ldc_rootbinddn != NULL)
+ {
+#if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H))
+ usesasl = cfg->ldc_rootusesasl;
+ bindarg =
+ cfg->ldc_rootusesasl ? cfg->ldc_rootsaslid : cfg->ldc_rootbindpw;
+#else
+ usesasl = 0;
+ bindarg = cfg->ldc_rootbindpw;
+#endif
+
+ rc = do_bind (__session.ls_conn,
+ cfg->ldc_bind_timelimit,
+ cfg->ldc_rootbinddn, bindarg, usesasl);
+ }
+ else
+ {
+#if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && (defined(HAVE_SASL_H) || defined(HAVE_SASL_SASL_H))
+ usesasl = cfg->ldc_usesasl;
+ bindarg = cfg->ldc_usesasl ? cfg->ldc_saslid : cfg->ldc_bindpw;
+#else
+ usesasl = 0;
+ bindarg = cfg->ldc_bindpw;
+#endif
+
+ rc = do_bind (__session.ls_conn,
+ cfg->ldc_bind_timelimit,
+ cfg->ldc_binddn,
+ cfg->ldc_bindpw, usesasl);
+ }
+
+ if (rc != LDAP_SUCCESS)
+ {
+ /* log actual LDAP error code */
+ syslog (LOG_AUTHPRIV | LOG_INFO,
+ "nss_ldap: failed to bind to LDAP server %s: %s",
+ cfg->ldc_uris[__session.ls_current_uri],
+ ldap_err2string (rc));
+ stat = do_map_error (rc);
+ do_close ();
+ debug ("<== do_open (failed to bind to DSA");
+ }
+ else
+ {
+ do_set_sockopts ();
+ time (&__session.ls_timestamp);
+ __session.ls_state = LS_CONNECTED_TO_DSA;
+ stat = NSS_STATUS_SUCCESS;
+ debug ("<== do_open (session connected to DSA)");
+ }
+
+ return stat;
+}
+
+#if defined HAVE_LDAP_START_TLS_S || (defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS))
+static int
+do_ssl_options (struct ldap_config * cfg)
+{
+ int rc;
+
+ debug ("==> do_ssl_options");
+
+#ifdef LDAP_OPT_X_TLS_RANDOM_FILE
+ if (cfg->ldc_tls_randfile != NULL)
+ {
+ /* rand file */
+ rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_RANDOM_FILE,
+ cfg->ldc_tls_randfile);
+ if (rc != LDAP_SUCCESS)
+ {
+ debug
+ ("<== do_ssl_options: Setting of LDAP_OPT_X_TLS_RANDOM_FILE failed");
+ return LDAP_OPERATIONS_ERROR;
+ }
+ }
+#endif /* LDAP_OPT_X_TLS_RANDOM_FILE */
+
+ if (cfg->ldc_tls_cacertfile != NULL)
+ {
+ /* ca cert file */
+ rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTFILE,
+ cfg->ldc_tls_cacertfile);
+ if (rc != LDAP_SUCCESS)
+ {
+ debug
+ ("<== do_ssl_options: Setting of LDAP_OPT_X_TLS_CACERTFILE failed");
+ return LDAP_OPERATIONS_ERROR;
+ }
+ }
+
+ if (cfg->ldc_tls_cacertdir != NULL)
+ {
+ /* ca cert directory */
+ rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTDIR,
+ cfg->ldc_tls_cacertdir);
+ if (rc != LDAP_SUCCESS)
+ {
+ debug
+ ("<== do_ssl_options: Setting of LDAP_OPT_X_TLS_CACERTDIR failed");
+ return LDAP_OPERATIONS_ERROR;
+ }
+ }
+
+ /* require cert? */
+ if (cfg->ldc_tls_checkpeer > -1)
+ {
+ rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_REQUIRE_CERT,
+ &cfg->ldc_tls_checkpeer);
+ if (rc != LDAP_SUCCESS)
+ {
+ debug
+ ("<== do_ssl_options: Setting of LDAP_OPT_X_TLS_REQUIRE_CERT failed");
+ return LDAP_OPERATIONS_ERROR;
+ }
+ }
+
+ if (cfg->ldc_tls_ciphers != NULL)
+ {
+ /* set cipher suite, certificate and private key: */
+ rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CIPHER_SUITE,
+ cfg->ldc_tls_ciphers);
+ if (rc != LDAP_SUCCESS)
+ {
+ debug
+ ("<== do_ssl_options: Setting of LDAP_OPT_X_TLS_CIPHER_SUITE failed");
+ return LDAP_OPERATIONS_ERROR;
+ }
+ }
+
+ if (cfg->ldc_tls_cert != NULL)
+ {
+ rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CERTFILE, cfg->ldc_tls_cert);
+ if (rc != LDAP_SUCCESS)
+ {
+ debug
+ ("<== do_ssl_options: Setting of LDAP_OPT_X_TLS_CERTFILE failed");
+ return LDAP_OPERATIONS_ERROR;
+ }
+ }
+
+ if (cfg->ldc_tls_key != NULL)
+ {
+ rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_KEYFILE, cfg->ldc_tls_key);
+ if (rc != LDAP_SUCCESS)
+ {
+ debug
+ ("<== do_ssl_options: Setting of LDAP_OPT_X_TLS_KEYFILE failed");
+ return LDAP_OPERATIONS_ERROR;
+ }
+ }
+
+ debug ("<== do_ssl_options");
+
+ return LDAP_SUCCESS;
+}
+#endif
+
+/*
+ * This function initializes an enumeration context, acquiring
+ * the global mutex.
+ *
+ * It could be done from the default constructor, under Solaris, but we
+ * delay it until the setXXent() function is called.
+ */
+struct ent_context *
+_nss_ldap_ent_context_init (struct ent_context ** pctx)
+{
+ struct ent_context *ctx;
+
+ _nss_ldap_enter ();
+
+ ctx = _nss_ldap_ent_context_init_locked (pctx);
+
+ _nss_ldap_leave ();
+
+ return ctx;
+}
+
+/*
+ * Wrapper around ldap_result() to skip over search references
+ * and deal transparently with the last entry.
+ */
+static enum nss_status
+do_result (struct ent_context * ctx, int all)
+{
+ int rc = LDAP_UNAVAILABLE;
+ enum nss_status stat = NSS_STATUS_TRYAGAIN;
+ struct timeval tv, *tvp;
+
+ debug ("==> do_result");
+
+ if (__session.ls_config->ldc_timelimit == LDAP_NO_LIMIT)
+ {
+ tvp = NULL;
+ }
+ else
+ {
+ tv.tv_sec = __session.ls_config->ldc_timelimit;
+ tv.tv_usec = 0;
+ tvp = &tv;
+ }
+
+ do
+ {
+ if (ctx->ec_res != NULL)
+ {
+ ldap_msgfree (ctx->ec_res);
+ ctx->ec_res = NULL;
+ }
+
+ rc =
+ ldap_result (__session.ls_conn, ctx->ec_msgid, all, tvp,
+ &ctx->ec_res);
+ switch (rc)
+ {
+ case -1:
+ case 0:
+ if (ldap_get_option
+ (__session.ls_conn, LDAP_OPT_ERROR_NUMBER, &rc) != LDAP_SUCCESS)
+ {
+ rc = LDAP_UNAVAILABLE;
+ }
+ syslog (LOG_AUTHPRIV | LOG_ERR, "nss_ldap: could not get LDAP result - %s",
+ ldap_err2string (rc));
+ stat = NSS_STATUS_UNAVAIL;
+ break;
+ case LDAP_RES_SEARCH_ENTRY:
+ stat = NSS_STATUS_SUCCESS;
+ break;
+ case LDAP_RES_SEARCH_RESULT:
+ if (all == LDAP_MSG_ALL)
+ {
+ /* we asked for the result chain, we got it. */
+ stat = NSS_STATUS_SUCCESS;
+ }
+ else
+ {
+#ifdef LDAP_MORE_RESULTS_TO_RETURN
+ int parserc;
+ /* NB: this frees ctx->ec_res */
+ LDAPControl **resultControls = NULL;
+
+ ctx->ec_cookie = NULL;
+
+ parserc =
+ ldap_parse_result (__session.ls_conn, ctx->ec_res, &rc, NULL,
+ NULL, NULL, &resultControls, 1);
+ if (parserc != LDAP_SUCCESS
+ && parserc != LDAP_MORE_RESULTS_TO_RETURN)
+ {
+ stat = NSS_STATUS_UNAVAIL;
+ ldap_abandon (__session.ls_conn, ctx->ec_msgid);
+ syslog (LOG_AUTHPRIV | LOG_ERR,
+ "nss_ldap: could not get LDAP result - %s",
+ ldap_err2string (rc));
+ }
+ else if (resultControls != NULL)
+ {
+ /* See if there are any more pages to come */
+ parserc = ldap_parse_page_control (__session.ls_conn,
+ resultControls, NULL,
+ &(ctx->ec_cookie));
+ ldap_controls_free (resultControls);
+ stat = NSS_STATUS_NOTFOUND;
+ }
+ else
+ {
+ stat = NSS_STATUS_NOTFOUND;
+ }
+#else
+ stat = NSS_STATUS_NOTFOUND;
+#endif /* LDAP_MORE_RESULTS_TO_RETURN */
+ ctx->ec_res = NULL;
+ ctx->ec_msgid = -1;
+ }
+ break;
+ default:
+ stat = NSS_STATUS_UNAVAIL;
+ break;
+ }
+ }
+#ifdef LDAP_RES_SEARCH_REFERENCE
+ while (rc == LDAP_RES_SEARCH_REFERENCE);
+#else
+ while (0);
+#endif /* LDAP_RES_SEARCH_REFERENCE */
+
+ if (stat == NSS_STATUS_SUCCESS)
+ time (&__session.ls_timestamp);
+
+ debug ("<== do_result");
+
+ return stat;
+}
+
+/*
+ * This function initializes an enumeration context.
+ *
+ * It could be done from the default constructor, under Solaris, but we
+ * delay it until the setXXent() function is called.
+ */
+struct ent_context *
+_nss_ldap_ent_context_init_locked (struct ent_context ** pctx)
+{
+ struct ent_context *ctx;
+
+ debug ("==> _nss_ldap_ent_context_init_locked");
+
+ ctx = *pctx;
+
+ if (ctx == NULL)
+ {
+ ctx = (struct ent_context *) malloc (sizeof (*ctx));
+ if (ctx == NULL)
+ {
+ debug ("<== _nss_ldap_ent_context_init_locked");
+ return NULL;
+ }
+ *pctx = ctx;
+ }
+ else
+ {
+ if (ctx->ec_res != NULL)
+ {
+ ldap_msgfree (ctx->ec_res);
+ }
+ if (ctx->ec_cookie != NULL)
+ {
+ ber_bvfree (ctx->ec_cookie);
+ }
+ if (ctx->ec_msgid > -1 && do_result (ctx, LDAP_MSG_ONE) == NSS_STATUS_SUCCESS)
+ {
+ ldap_abandon (__session.ls_conn, ctx->ec_msgid);
+ }
+ }
+
+ ctx->ec_cookie = NULL;
+ ctx->ec_res = NULL;
+ ctx->ec_msgid = -1;
+ ctx->ec_sd = NULL;
+
+ LS_INIT (ctx->ec_state);
+
+ debug ("<== _nss_ldap_ent_context_init_locked");
+
+ return ctx;
+}
+
+/*
+ * Clears a given context; we require the caller
+ * to acquire the lock.
+ */
+void
+_nss_ldap_ent_context_release (struct ent_context * ctx)
+{
+ debug ("==> _nss_ldap_ent_context_release");
+
+ if (ctx == NULL)
+ {
+ debug ("<== _nss_ldap_ent_context_release");
+ return;
+ }
+
+ if (ctx->ec_res != NULL)
+ {
+ ldap_msgfree (ctx->ec_res);
+ ctx->ec_res = NULL;
+ }
+
+ /*
+ * Abandon the search if there were more results to fetch.
+ */
+ if (ctx->ec_msgid > -1 && do_result (ctx, LDAP_MSG_ONE) == NSS_STATUS_SUCCESS)
+ {
+ ldap_abandon (__session.ls_conn, ctx->ec_msgid);
+ ctx->ec_msgid = -1;
+ }
+
+ if (ctx->ec_cookie != NULL)
+ {
+ ber_bvfree (ctx->ec_cookie);
+ ctx->ec_cookie = NULL;
+ }
+
+ ctx->ec_sd = NULL;
+
+ LS_INIT (ctx->ec_state);
+
+ if (_nss_ldap_test_config_flag (NSS_LDAP_FLAGS_CONNECT_POLICY_ONESHOT))
+ {
+ do_close ();
+ }
+
+ debug ("<== _nss_ldap_ent_context_release");
+
+ return;
+}
+
+/*
+ * AND or OR a set of filters.
+ */
+static enum nss_status
+do_aggregate_filter (const char **values,
+ enum ldap_args_types type,
+ const char *filterprot, char *bufptr, size_t buflen)
+{
+ enum nss_status stat;
+ const char **valueP;
+
+ assert (buflen > sizeof ("(|)"));
+
+ bufptr[0] = '(';
+ bufptr[1] = (type == LA_TYPE_STRING_LIST_AND) ? '&' : '|';
+
+ bufptr += 2;
+ buflen -= 2;
+
+ for (valueP = values; *valueP != NULL; valueP++)
+ {
+ size_t len;
+ char filter[LDAP_FILT_MAXSIZ], escapedBuf[LDAP_FILT_MAXSIZ];
+
+ stat =
+ _nss_ldap_escape_string (*valueP, escapedBuf, sizeof (escapedBuf));
+ if (stat != NSS_STATUS_SUCCESS)
+ return stat;
+
+ snprintf (filter, sizeof (filter), filterprot, escapedBuf);
+ len = strlen (filter);
+
+ if (buflen < len + 1 /* ')' */ )
+ return NSS_STATUS_TRYAGAIN;
+
+ memcpy (bufptr, filter, len);
+ bufptr[len] = '\0';
+ bufptr += len;
+ buflen -= len;
+ }
+
+ if (buflen < 2)
+ return NSS_STATUS_TRYAGAIN;
+
+ *bufptr++ = ')';
+ *bufptr++ = '\0';
+
+ buflen -= 2;
+
+ return NSS_STATUS_SUCCESS;
+}
+
+/*
+ * Do the necessary formatting to create a string filter.
+ */
+static enum nss_status
+do_filter (const struct ldap_args * args, const char *filterprot,
+ struct ldap_service_search_descriptor * sd, char *userBuf,
+ size_t userBufSiz, char **dynamicUserBuf, const char **retFilter)
+{
+ char buf1[LDAP_FILT_MAXSIZ], buf2[LDAP_FILT_MAXSIZ];
+ char *filterBufP, filterBuf[LDAP_FILT_MAXSIZ];
+ size_t filterSiz;
+ enum nss_status stat = NSS_STATUS_SUCCESS;
+
+ debug ("==> do_filter");
+
+ *dynamicUserBuf = NULL;
+
+ if (args != NULL && args->la_type != LA_TYPE_NONE)
+ {
+ /* choose what to use for temporary storage */
+
+ if (sd != NULL && sd->lsd_filter != NULL)
+ {
+ filterBufP = filterBuf;
+ filterSiz = sizeof (filterBuf);
+ }
+ else
+ {
+ filterBufP = userBuf;
+ filterSiz = userBufSiz;
+ }
+
+ switch (args->la_type)
+ {
+ case LA_TYPE_STRING:
+ stat = _nss_ldap_escape_string (args->la_arg1.la_string, buf1,
+ sizeof (buf1));
+ if (stat != NSS_STATUS_SUCCESS)
+ break;
+
+ snprintf (filterBufP, filterSiz, filterprot, buf1);
+ break;
+ case LA_TYPE_NUMBER:
+ snprintf (filterBufP, filterSiz, filterprot,
+ args->la_arg1.la_number);
+ break;
+ case LA_TYPE_STRING_AND_STRING:
+ stat = _nss_ldap_escape_string (args->la_arg1.la_string, buf1,
+ sizeof (buf1));
+ if (stat != NSS_STATUS_SUCCESS)
+ break;
+
+ stat = _nss_ldap_escape_string (args->la_arg2.la_string, buf2,
+ sizeof (buf2));
+ if (stat != NSS_STATUS_SUCCESS)
+ break;
+
+ snprintf (filterBufP, filterSiz, filterprot, buf1, buf2);
+ break;
+ case LA_TYPE_NUMBER_AND_STRING:
+ stat = _nss_ldap_escape_string (args->la_arg2.la_string, buf1,
+ sizeof (buf1));
+ if (stat != NSS_STATUS_SUCCESS)
+ break;
+
+ snprintf (filterBufP, filterSiz, filterprot,
+ args->la_arg1.la_number, buf1);
+ break;
+ case LA_TYPE_STRING_LIST_OR:
+ case LA_TYPE_STRING_LIST_AND:
+ do
+ {
+ stat = do_aggregate_filter (args->la_arg1.la_string_list,
+ args->la_type,
+ filterprot, filterBufP, filterSiz);
+ if (stat == NSS_STATUS_TRYAGAIN)
+ {
+ filterBufP = *dynamicUserBuf = realloc (*dynamicUserBuf,
+ 2 * filterSiz);
+ if (filterBufP == NULL)
+ return NSS_STATUS_UNAVAIL;
+ filterSiz *= 2;
+ }
+ }
+ while (stat == NSS_STATUS_TRYAGAIN);
+ break;
+ default:
+ return NSS_STATUS_UNAVAIL;
+ break;
+ }
+
+ if (stat != NSS_STATUS_SUCCESS)
+ return stat;
+
+ /*
+ * This code really needs to be cleaned up.
+ */
+ if (sd != NULL && sd->lsd_filter != NULL)
+ {
+ size_t filterBufPLen = strlen (filterBufP);
+
+ /* remove trailing bracket */
+ if (filterBufP[filterBufPLen - 1] == ')')
+ filterBufP[filterBufPLen - 1] = '\0';
+
+ if (*dynamicUserBuf != NULL)
+ {
+ char *oldDynamicUserBuf = *dynamicUserBuf;
+ size_t dynamicUserBufSiz;
+
+ dynamicUserBufSiz = filterBufPLen + strlen (sd->lsd_filter) +
+ sizeof ("())");
+ *dynamicUserBuf = malloc (dynamicUserBufSiz);
+ if (*dynamicUserBuf == NULL)
+ {
+ free (oldDynamicUserBuf);
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ snprintf (*dynamicUserBuf, dynamicUserBufSiz, "%s(%s))",
+ filterBufP, sd->lsd_filter);
+ free (oldDynamicUserBuf);
+ }
+ else
+ {
+ snprintf (userBuf, userBufSiz, "%s(%s))",
+ filterBufP, sd->lsd_filter);
+ }
+ }
+
+ if (*dynamicUserBuf != NULL)
+ *retFilter = *dynamicUserBuf;
+ else
+ *retFilter = userBuf;
+ }
+ else
+ {
+ /* no arguments, probably an enumeration filter */
+ if (sd != NULL && sd->lsd_filter != NULL)
+ {
+ snprintf (userBuf, userBufSiz, "(&%s(%s))",
+ filterprot, sd->lsd_filter);
+ *retFilter = userBuf;
+ }
+ else
+ {
+ *retFilter = filterprot;
+ }
+ }
+
+ debug (":== do_filter: %s", *retFilter);
+
+ debug ("<== do_filter");
+
+ return NSS_STATUS_SUCCESS;
+}
+
+/*
+ * Function to call either do_search() or do_search_s() with
+ * reconnection logic.
+ */
+static enum nss_status
+do_with_reconnect (const char *base, int scope,
+ const char *filter, const char **attrs, int sizelimit,
+ void *private, search_func_t search_func)
+{
+ int rc = LDAP_UNAVAILABLE, tries = 0, backoff = 0;
+ int hard = 1, start_uri = 0, log = 0;
+ enum nss_status stat = NSS_STATUS_UNAVAIL;
+ int maxtries;
+
+ debug ("==> do_with_reconnect");
+
+ /* caller must successfully call do_init() first */
+ assert (__session.ls_config != NULL);
+
+ maxtries = __session.ls_config->ldc_reconnect_maxconntries +
+ __session.ls_config->ldc_reconnect_tries;
+
+ while (stat == NSS_STATUS_UNAVAIL && hard && tries < maxtries)
+ {
+ if (tries >= __session.ls_config->ldc_reconnect_maxconntries)
+ {
+ if (backoff == 0)
+ backoff = __session.ls_config->ldc_reconnect_sleeptime;
+ else if (backoff < __session.ls_config->ldc_reconnect_maxsleeptime)
+ backoff *= 2;
+
+ syslog (LOG_AUTHPRIV | LOG_INFO,
+ "nss_ldap: reconnecting to LDAP server (sleeping %d seconds)...",
+ backoff);
+ (void) sleep (backoff);
+ }
+ else if (tries > 1)
+ {
+ /* Don't sleep, reconnect immediately. */
+ syslog (LOG_AUTHPRIV | LOG_INFO, "nss_ldap: reconnecting to LDAP server...");
+ }
+
+ /* For each "try", attempt to connect to all specified URIs */
+ start_uri = __session.ls_current_uri;
+ do
+ {
+ stat = do_open ();
+ if (stat == NSS_STATUS_SUCCESS)
+ {
+ stat = do_map_error (search_func (base, scope, filter,
+ attrs, sizelimit, private));
+ }
+ if (stat != NSS_STATUS_UNAVAIL)
+ break;
+
+ log++;
+
+ /* test in case config file could not be read */
+ if (__session.ls_config != NULL)
+ {
+ assert (__session.ls_config->
+ ldc_uris[__session.ls_current_uri] != NULL);
+
+ __session.ls_current_uri++;
+
+ if (__session.ls_config->ldc_uris[__session.ls_current_uri] ==
+ NULL)
+ __session.ls_current_uri = 0;
+ }
+ }
+ while (__session.ls_current_uri != start_uri);
+
+ if (stat == NSS_STATUS_UNAVAIL)
+ {
+ do_close ();
+
+ /*
+ * If a soft reconnect policy is specified, then do not
+ * try to reconnect to the LDAP server if it is down.
+ */
+ if (__session.ls_config->ldc_reconnect_pol == LP_RECONNECT_SOFT)
+ hard = 0;
+
+ /*
+ * If the file /lib/init/rw/libnss-ldap.bind_policy_soft exists,
+ * then ignore the actual bind_policy definition and use the
+ * soft semantics. This file should only exist during early
+ * boot and late shutdown, points at which the networking or
+ * the LDAP server itself are likely to be unavailable anyway.
+ */
+ if (access("/lib/init/rw/libnss-ldap.bind_policy_soft",R_OK) == 0)
+ hard = 0;
+
+ ++tries;
+ }
+ }
+
+ switch (stat)
+ {
+ case NSS_STATUS_UNAVAIL:
+ syslog (LOG_AUTHPRIV | LOG_ERR, "nss_ldap: could not search LDAP server - %s",
+ ldap_err2string (rc));
+ break;
+ case NSS_STATUS_TRYAGAIN:
+ syslog (LOG_AUTHPRIV | LOG_ERR,
+ "nss_ldap: could not %s %sconnect to LDAP server - %s",
+ hard ? "hard" : "soft", tries ? "re" : "",
+ ldap_err2string (rc));
+ stat = NSS_STATUS_UNAVAIL;
+ break;
+ case NSS_STATUS_SUCCESS:
+ if (log)
+ {
+ char *uri = __session.ls_config->ldc_uris[__session.ls_current_uri];
+
+ if (uri == NULL)
+ uri = "(null)";
+
+ if (tries)
+ syslog (LOG_AUTHPRIV | LOG_INFO,
+ "nss_ldap: reconnected to LDAP server %s after %d attempt%s",
+ uri, tries, (tries == 1) ? "" : "s");
+ else
+ syslog (LOG_AUTHPRIV | LOG_INFO, "nss_ldap: reconnected to LDAP server %s", uri);
+ }
+ time (&__session.ls_timestamp);
+ break;
+ default:
+ break;
+ }
+
+ debug ("<== do_with_reconnect");
+ return stat;
+}
+
+/*
+ * Synchronous search function. Don't call this directly;
+ * always wrap calls to this with do_with_reconnect(), or,
+ * better still, use _nss_ldap_search_s().
+ */
+static int
+do_search_s (const char *base, int scope,
+ const char *filter, const char **attrs, int sizelimit,
+ LDAPMessage ** res)
+{
+ int rc;
+ struct timeval tv, *tvp;
+
+ debug ("==> do_search_s");
+
+ ldap_set_option (__session.ls_conn, LDAP_OPT_SIZELIMIT,
+ (void *) &sizelimit);
+
+ if (__session.ls_config->ldc_timelimit == LDAP_NO_LIMIT)
+ {
+ tvp = NULL;
+ }
+ else
+ {
+ tv.tv_sec = __session.ls_config->ldc_timelimit;
+ tv.tv_usec = 0;
+ tvp = &tv;
+ }
+
+ rc = ldap_search_st (__session.ls_conn, base, scope, filter,
+ (char **) attrs, 0, tvp, res);
+
+ debug ("<== do_search_s");
+
+ return rc;
+}
+
+/*
+ * Asynchronous search function. Don't call this directly;
+ * always wrap calls to this with do_with_reconnect(), or,
+ * better still, use _nss_ldap_search().
+ */
+static int
+do_search (const char *base, int scope,
+ const char *filter, const char **attrs, int sizelimit, int *msgid)
+{
+ int rc;
+ LDAPControl *serverCtrls[2];
+ LDAPControl **pServerCtrls;
+
+ debug ("==> do_search");
+
+#ifdef HAVE_LDAP_SEARCH_EXT
+ if (_nss_ldap_test_config_flag (NSS_LDAP_FLAGS_PAGED_RESULTS))
+ {
+ rc = ldap_create_page_control (__session.ls_conn,
+ __session.ls_config->ldc_pagesize,
+ NULL, 0, &serverCtrls[0]);
+ if (rc != LDAP_SUCCESS)
+ return rc;
+
+ serverCtrls[1] = NULL;
+ pServerCtrls = serverCtrls;
+ }
+ else
+ {
+ pServerCtrls = NULL;
+ }
+
+ rc = ldap_search_ext (__session.ls_conn, base, scope, filter,
+ (char **) attrs, 0, pServerCtrls, NULL,
+ LDAP_NO_LIMIT, sizelimit, msgid);
+
+ if (pServerCtrls != NULL)
+ {
+ ldap_control_free (serverCtrls[0]);
+ serverCtrls[0] = NULL;
+ }
+
+#else
+ ldap_set_option (__session.ls_conn, LDAP_OPT_SIZELIMIT,
+ (void *) &sizelimit);
+
+ *msgid = ldap_search (__session.ls_conn, base, scope, filter,
+ (char **) attrs, 0);
+ if (*msgid < 0)
+ {
+ if (ldap_get_option
+ (__session.ls_conn, LDAP_OPT_ERROR_NUMBER, &rc) != LDAP_SUCCESS)
+ {
+ rc = LDAP_UNAVAILABLE;
+ }
+ }
+ else
+ {
+ rc = LDAP_SUCCESS;
+ }
+#endif /* HAVE_LDAP_SEARCH_EXT */
+
+ debug ("<== do_search");
+
+ return rc;
+}
+
+static void
+do_map_errno (enum nss_status status, int *errnop)
+{
+ switch (status)
+ {
+ case NSS_STATUS_TRYAGAIN:
+ *errnop = ERANGE;
+ break;
+ case NSS_STATUS_NOTFOUND:
+ *errnop = ENOENT;
+ break;
+ case NSS_STATUS_SUCCESS:
+ default:
+ *errnop = 0;
+ }
+}
+
+/*
+ * Tries parser function "parser" on entries, calling do_result()
+ * to retrieve them from the LDAP server until one parses
+ * correctly or there is an exceptional condition.
+ */
+static enum nss_status
+do_parse (struct ent_context * ctx, void *result, char
+ *buffer, size_t buflen, int *errnop, parser_t parser)
+{
+ enum nss_status parseStat = NSS_STATUS_NOTFOUND;
+
+ debug ("==> do_parse");
+
+ /*
+ * if ec_state.ls_info.ls_index is non-zero, then we don't collect another
+ * entry off the LDAP chain, and instead refeed the existing result to
+ * the parser. Once the parser has finished with it, it will return
+ * NSS_STATUS_NOTFOUND and reset the index to -1, at which point we'll retrieve
+ * another entry.
+ */
+ do
+ {
+ enum nss_status resultStat = NSS_STATUS_SUCCESS;
+
+ if (ctx->ec_state.ls_retry == 0 &&
+ (ctx->ec_state.ls_type == LS_TYPE_KEY
+ || ctx->ec_state.ls_info.ls_index == -1))
+ {
+ resultStat = do_result (ctx, LDAP_MSG_ONE);
+ }
+
+ if (resultStat != NSS_STATUS_SUCCESS)
+ {
+ /* Could not get a result; bail */
+ parseStat = resultStat;
+ break;
+ }
+
+ /*
+ * We have an entry; now, try to parse it.
+ *
+ * If we do not parse the entry because of a schema
+ * violation, the parser should return NSS_STATUS_NOTFOUND.
+ * We'll keep on trying subsequent entries until we
+ * find one which is parseable, or exhaust avialable
+ * entries, whichever is first.
+ */
+ parseStat = parser (ctx->ec_res, &ctx->ec_state, result,
+ buffer, buflen);
+
+ /* hold onto the state if we're out of memory XXX */
+ ctx->ec_state.ls_retry = (parseStat == NSS_STATUS_TRYAGAIN && buffer != NULL ? 1 : 0);
+
+ /* free entry is we're moving on */
+ if (ctx->ec_state.ls_retry == 0 &&
+ (ctx->ec_state.ls_type == LS_TYPE_KEY
+ || ctx->ec_state.ls_info.ls_index == -1))
+ {
+ /* we don't need the result anymore, ditch it. */
+ ldap_msgfree (ctx->ec_res);
+ ctx->ec_res = NULL;
+ }
+ }
+ while (parseStat == NSS_STATUS_NOTFOUND);
+
+ do_map_errno (parseStat, errnop);
+
+ debug ("<== do_parse");
+
+ return parseStat;
+}
+
+/*
+ * Parse, fetching reuslts from chain instead of server.
+ */
+static enum nss_status
+do_parse_s (struct ent_context * ctx, void *result, char
+ *buffer, size_t buflen, int *errnop, parser_t parser)
+{
+ enum nss_status parseStat = NSS_STATUS_NOTFOUND;
+ LDAPMessage *e = NULL;
+
+ debug ("==> do_parse_s");
+
+ /*
+ * if ec_state.ls_info.ls_index is non-zero, then we don't collect another
+ * entry off the LDAP chain, and instead refeed the existing result to
+ * the parser. Once the parser has finished with it, it will return
+ * NSS_STATUS_NOTFOUND and reset the index to -1, at which point we'll retrieve
+ * another entry.
+ */
+ do
+ {
+ if (ctx->ec_state.ls_retry == 0 &&
+ (ctx->ec_state.ls_type == LS_TYPE_KEY
+ || ctx->ec_state.ls_info.ls_index == -1))
+ {
+ if (e == NULL)
+ e = ldap_first_entry (__session.ls_conn, ctx->ec_res);
+ else
+ e = ldap_next_entry (__session.ls_conn, e);
+ }
+
+ if (e == NULL)
+ {
+ /* Could not get a result; bail */
+ parseStat = NSS_STATUS_NOTFOUND;
+ break;
+ }
+
+ /*
+ * We have an entry; now, try to parse it.
+ *
+ * If we do not parse the entry because of a schema
+ * violation, the parser should return NSS_STATUS_NOTFOUND.
+ * We'll keep on trying subsequent entries until we
+ * find one which is parseable, or exhaust avialable
+ * entries, whichever is first.
+ */
+ parseStat = parser (e, &ctx->ec_state, result, buffer, buflen);
+
+ /* hold onto the state if we're out of memory XXX */
+ ctx->ec_state.ls_retry = (parseStat == NSS_STATUS_TRYAGAIN && buffer != NULL ? 1 : 0);
+ }
+ while (parseStat == NSS_STATUS_NOTFOUND);
+
+ do_map_errno (parseStat, errnop);
+
+ debug ("<== do_parse_s");
+
+ return parseStat;
+}
+
+/*
+ * Read an entry from the directory, a la X.500. This is used
+ * for functions that need to retrieve attributes from a DN,
+ * such as the RFC2307bis group expansion function.
+ */
+enum nss_status
+_nss_ldap_read (const char *dn, const char **attributes, LDAPMessage ** res)
+{
+ return do_with_reconnect (dn, LDAP_SCOPE_BASE, "(objectclass=*)",
+ attributes, 1, /* sizelimit */ res,
+ (search_func_t) do_search_s);
+}
+
+/*
+ * Simple wrapper around ldap_get_values(). Requires that
+ * session is already established.
+ */
+char **
+_nss_ldap_get_values (LDAPMessage * e, const char *attr)
+{
+ if (__session.ls_state != LS_CONNECTED_TO_DSA)
+ {
+ return NULL;
+ }
+ assert (__session.ls_conn != NULL);
+
+ return ldap_get_values (__session.ls_conn, e, (char *) attr);
+}
+
+/*
+ * Simple wrapper around ldap_get_dn(). Requires that
+ * session is already established.
+ */
+char *
+_nss_ldap_get_dn (LDAPMessage * e)
+{
+ if (__session.ls_state != LS_CONNECTED_TO_DSA)
+ {
+ return NULL;
+ }
+ assert (__session.ls_conn != NULL);
+
+ return ldap_get_dn (__session.ls_conn, e);
+}
+
+/*
+ * Simple wrapper around ldap_first_entry(). Requires that
+ * session is already established.
+ */
+LDAPMessage *
+_nss_ldap_first_entry (LDAPMessage * res)
+{
+ if (__session.ls_state != LS_CONNECTED_TO_DSA)
+ {
+ return NULL;
+ }
+ assert (__session.ls_conn != NULL);
+
+ return ldap_first_entry (__session.ls_conn, res);
+}
+
+/*
+ * Simple wrapper around ldap_next_entry(). Requires that
+ * session is already established.
+ */
+LDAPMessage *
+_nss_ldap_next_entry (LDAPMessage * res)
+{
+ if (__session.ls_state != LS_CONNECTED_TO_DSA)
+ {
+ return NULL;
+ }
+ assert (__session.ls_conn != NULL);
+
+ return ldap_next_entry (__session.ls_conn, res);
+}
+
+char *
+_nss_ldap_first_attribute (LDAPMessage * entry, BerElement ** berptr)
+{
+ if (__session.ls_state != LS_CONNECTED_TO_DSA)
+ {
+ return NULL;
+ }
+ assert (__session.ls_conn != NULL);
+
+ return ldap_first_attribute (__session.ls_conn, entry, berptr);
+}
+
+char *
+_nss_ldap_next_attribute (LDAPMessage * entry, BerElement * ber)
+{
+ if (__session.ls_state != LS_CONNECTED_TO_DSA)
+ {
+ return NULL;
+ }
+ assert (__session.ls_conn != NULL);
+
+ return ldap_next_attribute (__session.ls_conn, entry, ber);
+}
+
+/*
+ * The generic synchronous lookup cover function.
+ * Assumes caller holds lock.
+ */
+enum nss_status
+_nss_ldap_search_s (const struct ldap_args * args,
+ const char *filterprot, enum ldap_map_selector sel, const
+ char **user_attrs, int sizelimit, LDAPMessage ** res)
+{
+ char sdBase[LDAP_FILT_MAXSIZ];
+ const char *base = NULL;
+ char filterBuf[LDAP_FILT_MAXSIZ], *dynamicFilterBuf = NULL;
+ const char **attrs, *filter;
+ int scope;
+ enum nss_status stat;
+ struct ldap_service_search_descriptor *sd = NULL;
+
+ debug ("==> _nss_ldap_search_s");
+
+ stat = do_init ();
+ if (stat != NSS_STATUS_SUCCESS)
+ {
+ debug ("<== _nss_ldap_search_s");
+ return stat;
+ }
+
+ /* Set some reasonable defaults. */
+ base = __session.ls_config->ldc_base;
+ scope = __session.ls_config->ldc_scope;
+ attrs = NULL;
+
+ if (args != NULL && args->la_base != NULL)
+ {
+ sel = LM_NONE;
+ base = args->la_base;
+ }
+
+ if (sel < LM_NONE)
+ {
+ sd = __session.ls_config->ldc_sds[sel];
+ next:
+ if (sd != NULL)
+ {
+ size_t len = strlen (sd->lsd_base);
+ if (sd->lsd_base[len - 1] == ',')
+ {
+ /* is relative */
+ snprintf (sdBase, sizeof (sdBase),
+ "%s%s", sd->lsd_base,
+ __session.ls_config->ldc_base);
+ base = sdBase;
+ }
+ else
+ {
+ base = sd->lsd_base;
+ }
+
+ if (sd->lsd_scope != -1)
+ {
+ scope = sd->lsd_scope;
+ }
+ }
+ attrs = __session.ls_config->ldc_attrtab[sel];
+ }
+
+ stat =
+ do_filter (args, filterprot, sd, filterBuf, sizeof (filterBuf),
+ &dynamicFilterBuf, &filter);
+ if (stat != NSS_STATUS_SUCCESS)
+ return stat;
+
+ stat = do_with_reconnect (base, scope, filter,
+ (user_attrs != NULL) ? user_attrs : attrs,
+ sizelimit, res, (search_func_t) do_search_s);
+
+ if (dynamicFilterBuf != NULL)
+ {
+ free (dynamicFilterBuf);
+ dynamicFilterBuf = NULL;
+ }
+
+ /* If no entry was returned, try the next search descriptor. */
+ if (sd != NULL && sd->lsd_next != NULL)
+ {
+ if (stat == NSS_STATUS_NOTFOUND ||
+ (stat == NSS_STATUS_SUCCESS &&
+ ldap_first_entry (__session.ls_conn, *res) == NULL))
+ {
+ sd = sd->lsd_next;
+ goto next;
+ }
+ }
+
+ debug ("<== _nss_ldap_search_s");
+
+ return stat;
+}
+
+/*
+ * The generic lookup cover function (asynchronous).
+ * Assumes caller holds lock.
+ */
+static enum nss_status
+_nss_ldap_search (const struct ldap_args * args,
+ const char *filterprot, enum ldap_map_selector sel,
+ const char **user_attrs, int sizelimit, int *msgid,
+ struct ldap_service_search_descriptor ** csd)
+{
+ char sdBase[LDAP_FILT_MAXSIZ];
+ const char *base = NULL;
+ char filterBuf[LDAP_FILT_MAXSIZ], *dynamicFilterBuf = NULL;
+ const char **attrs, *filter;
+ int scope;
+ enum nss_status stat;
+ struct ldap_service_search_descriptor *sd = NULL;
+
+ debug ("==> _nss_ldap_search");
+
+ *msgid = -1;
+
+ stat = do_init ();
+ if (stat != NSS_STATUS_SUCCESS)
+ {
+ debug ("<== _nss_ldap_search");
+ return stat;
+ }
+
+ /* Set some reasonable defaults. */
+ base = __session.ls_config->ldc_base;
+ scope = __session.ls_config->ldc_scope;
+ attrs = NULL;
+
+ if (args != NULL && args->la_base != NULL)
+ {
+ sel = LM_NONE;
+ base = args->la_base;
+ }
+
+ if (sel < LM_NONE || *csd != NULL)
+ {
+ /*
+ * If we were chasing multiple descriptors and there are none left,
+ * just quit with NSS_STATUS_NOTFOUND.
+ */
+ if (*csd != NULL)
+ {
+ sd = (*csd)->lsd_next;
+ if (sd == NULL)
+ return NSS_STATUS_NOTFOUND;
+ }
+ else
+ {
+ sd = __session.ls_config->ldc_sds[sel];
+ }
+
+ *csd = sd;
+
+ if (sd != NULL)
+ {
+ size_t len = strlen (sd->lsd_base);
+ if (sd->lsd_base[len - 1] == ',')
+ {
+ /* is relative */
+ snprintf (sdBase, sizeof (sdBase), "%s%s", sd->lsd_base,
+ __session.ls_config->ldc_base);
+ base = sdBase;
+ }
+ else
+ {
+ base = sd->lsd_base;
+ }
+
+ if (sd->lsd_scope != -1)
+ {
+ scope = sd->lsd_scope;
+ }
+ }
+ attrs = __session.ls_config->ldc_attrtab[sel];
+ }
+
+ stat =
+ do_filter (args, filterprot, sd, filterBuf, sizeof (filterBuf),
+ &dynamicFilterBuf, &filter);
+ if (stat != NSS_STATUS_SUCCESS)
+ return stat;
+
+ stat = do_with_reconnect (base, scope, filter,
+ (user_attrs != NULL) ? user_attrs : attrs,
+ sizelimit, msgid, (search_func_t) do_search);
+
+ if (dynamicFilterBuf != NULL)
+ free (dynamicFilterBuf);
+
+ debug ("<== _nss_ldap_search");
+
+ return stat;
+}
+
+#ifdef HAVE_LDAP_SEARCH_EXT
+static enum nss_status
+do_next_page (const struct ldap_args * args,
+ const char *filterprot, enum ldap_map_selector sel, int
+ sizelimit, int *msgid, struct berval *pCookie)
+{
+ char sdBase[LDAP_FILT_MAXSIZ];
+ const char *base = NULL;
+ char filterBuf[LDAP_FILT_MAXSIZ], *dynamicFilterBuf = NULL;
+ const char **attrs, *filter;
+ int scope;
+ enum nss_status stat;
+ struct ldap_service_search_descriptor *sd = NULL;
+ LDAPControl *serverctrls[2] = {
+ NULL, NULL
+ };
+
+ /* Set some reasonable defaults. */
+ base = __session.ls_config->ldc_base;
+ scope = __session.ls_config->ldc_scope;
+ attrs = NULL;
+
+ if (args != NULL && args->la_base != NULL)
+ {
+ sel = LM_NONE;
+ base = args->la_base;
+ }
+
+ if (sel < LM_NONE)
+ {
+ sd = __session.ls_config->ldc_sds[sel];
+ if (sd != NULL)
+ {
+ size_t len = strlen (sd->lsd_base);
+ if (sd->lsd_base[len - 1] == ',')
+ {
+ snprintf (sdBase, sizeof (sdBase), "%s%s", sd->lsd_base,
+ __session.ls_config->ldc_base);
+ base = sdBase;
+ }
+ else
+ {
+ base = sd->lsd_base;
+ }
+
+ if (sd->lsd_scope != -1)
+ {
+ scope = sd->lsd_scope;
+ }
+ }
+ attrs = __session.ls_config->ldc_attrtab[sel];
+ }
+
+ stat =
+ do_filter (args, filterprot, sd, filterBuf, sizeof (filterBuf),
+ &dynamicFilterBuf, &filter);
+ if (stat != NSS_STATUS_SUCCESS)
+ {
+ return stat;
+ }
+
+ stat =
+ ldap_create_page_control (__session.ls_conn,
+ __session.ls_config->ldc_pagesize,
+ pCookie, 0, &serverctrls[0]);
+ if (stat != LDAP_SUCCESS)
+ {
+ if (dynamicFilterBuf != NULL)
+ free (dynamicFilterBuf);
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ stat =
+ ldap_search_ext (__session.ls_conn, base,
+ __session.ls_config->ldc_scope,
+ filter,
+ (char **) attrs, 0, serverctrls, NULL, LDAP_NO_LIMIT,
+ sizelimit, msgid);
+
+ ldap_control_free (serverctrls[0]);
+ if (dynamicFilterBuf != NULL)
+ free (dynamicFilterBuf);
+
+ return (*msgid < 0) ? NSS_STATUS_UNAVAIL : NSS_STATUS_SUCCESS;
+}
+#endif /* HAVE_LDAP_SEARCH_EXT */
+
+/*
+ * General entry point for enumeration routines.
+ * This should really use the asynchronous LDAP search API to avoid
+ * pulling down all the entries at once, particularly if the
+ * enumeration is not completed.
+ * Locks mutex.
+ */
+enum nss_status
+_nss_ldap_getent (struct ent_context ** ctx,
+ void *result, char *buffer, size_t buflen,
+ int *errnop, const char *filterprot,
+ enum ldap_map_selector sel, parser_t parser)
+{
+ enum nss_status status;
+
+ /*
+ * we need to lock here as the context may not be thread-specific
+ * data (under glibc, for example). Maybe we should make the lock part
+ * of the context.
+ */
+
+ _nss_ldap_enter ();
+ status = _nss_ldap_getent_ex (NULL, ctx, result,
+ buffer, buflen,
+ errnop, filterprot, sel, NULL, parser);
+ _nss_ldap_leave ();
+
+ return status;
+}
+
+/*
+ * Internal entry point for enumeration routines.
+ * Caller holds global mutex
+ */
+enum nss_status
+_nss_ldap_getent_ex (struct ldap_args * args,
+ struct ent_context ** ctx, void *result,
+ char *buffer, size_t buflen, int *errnop,
+ const char *filterprot,
+ enum ldap_map_selector sel,
+ const char **user_attrs, parser_t parser)
+{
+ enum nss_status stat = NSS_STATUS_SUCCESS;
+
+ debug ("==> _nss_ldap_getent_ex");
+
+ if (*ctx == NULL || (*ctx)->ec_msgid < 0)
+ {
+ /*
+ * implicitly call setent() if this is the first time
+ * or there is no active search
+ */
+ if (_nss_ldap_ent_context_init_locked (ctx) == NULL)
+ {
+ debug ("<== _nss_ldap_getent_ex");
+ return NSS_STATUS_UNAVAIL;
+ }
+ }
+
+next:
+ /*
+ * If ctx->ec_msgid < 0, then we haven't searched yet. Let's do it!
+ */
+ if ((*ctx)->ec_msgid < 0)
+ {
+ int msgid;
+
+ stat = _nss_ldap_search (args, filterprot, sel, user_attrs,
+ LDAP_NO_LIMIT, &msgid, &(*ctx)->ec_sd);
+ if (stat != NSS_STATUS_SUCCESS)
+ {
+ debug ("<== _nss_ldap_getent_ex");
+ return stat;
+ }
+
+ (*ctx)->ec_msgid = msgid;
+ }
+
+ stat = do_parse (*ctx, result, buffer, buflen, errnop, parser);
+
+#ifdef HAVE_LDAP_SEARCH_EXT
+ if (stat == NSS_STATUS_NOTFOUND)
+ {
+ /* Is there another page of results? */
+ if ((*ctx)->ec_cookie != NULL && (*ctx)->ec_cookie->bv_len != 0)
+ {
+ int msgid;
+
+ stat =
+ do_next_page (NULL, filterprot, sel, LDAP_NO_LIMIT, &msgid,
+ (*ctx)->ec_cookie);
+ if (stat != NSS_STATUS_SUCCESS)
+ {
+ debug ("<== _nss_ldap_getent_ex");
+ return stat;
+ }
+ (*ctx)->ec_msgid = msgid;
+ stat = do_parse (*ctx, result, buffer, buflen, errnop, parser);
+ }
+ }
+#endif /* HAVE_LDAP_SEARCH_EXT */
+
+ if (stat == NSS_STATUS_NOTFOUND && (*ctx)->ec_sd != NULL)
+ {
+ (*ctx)->ec_msgid = -1;
+ goto next;
+ }
+
+ debug ("<== _nss_ldap_getent_ex");
+
+ return stat;
+}
+
+/*
+ * General match function.
+ * Locks mutex.
+ */
+enum nss_status
+_nss_ldap_getbyname (struct ldap_args * args,
+ void *result, char *buffer, size_t buflen, int
+ *errnop, const char *filterprot,
+ enum ldap_map_selector sel, parser_t parser)
+{
+ enum nss_status stat = NSS_STATUS_NOTFOUND;
+ struct ent_context ctx;
+
+ _nss_ldap_enter ();
+
+ debug ("==> _nss_ldap_getbyname");
+
+ ctx.ec_msgid = -1;
+ ctx.ec_cookie = NULL;
+
+ stat = _nss_ldap_search_s (args, filterprot, sel, NULL, 1, &ctx.ec_res);
+ if (stat != NSS_STATUS_SUCCESS)
+ {
+ _nss_ldap_leave ();
+ debug ("<== _nss_ldap_getbyname");
+ return stat;
+ }
+
+ /*
+ * we pass this along for the benefit of the services parser,
+ * which uses it to figure out which protocol we really wanted.
+ * we only pass the second argument along, as that's what we need
+ * in services.
+ */
+ LS_INIT (ctx.ec_state);
+ ctx.ec_state.ls_type = LS_TYPE_KEY;
+ ctx.ec_state.ls_info.ls_key = args->la_arg2.la_string;
+
+ stat = do_parse_s (&ctx, result, buffer, buflen, errnop, parser);
+
+ _nss_ldap_ent_context_release (&ctx);
+
+ debug ("<== _nss_ldap_getbyname");
+
+ /* moved unlock here to avoid race condition bug #49 */
+ _nss_ldap_leave ();
+
+ return stat;
+}
+
+static int NEW_do_parse_s(struct ent_context *ctx,FILE *fp,NEWparser_t parser)
+{
+ int parseStat=NSLCD_RESULT_NOTFOUND;
+ LDAPMessage *e=NULL;
+ /*
+ * if ec_state.ls_info.ls_index is non-zero, then we don't collect another
+ * entry off the LDAP chain, and instead refeed the existing result to
+ * the parser. Once the parser has finished with it, it will return
+ * NSS_STATUS_NOTFOUND and reset the index to -1, at which point we'll retrieve
+ * another entry.
+ */
+ do
+ {
+ if (ctx->ec_state.ls_retry == 0 &&
+ (ctx->ec_state.ls_type == LS_TYPE_KEY
+ || ctx->ec_state.ls_info.ls_index == -1))
+ {
+ if (e == NULL)
+ e = ldap_first_entry (__session.ls_conn, ctx->ec_res);
+ else
+ e = ldap_next_entry (__session.ls_conn, e);
+ }
+ if (e == NULL)
+ {
+ /* Could not get a result; bail */
+ parseStat=NSLCD_RESULT_NOTFOUND;
+ break;
+ }
+ /*
+ * We have an entry; now, try to parse it.
+ *
+ * If we do not parse the entry because of a schema
+ * violation, the parser should return NSS_STATUS_NOTFOUND.
+ * We'll keep on trying subsequent entries until we
+ * find one which is parseable, or exhaust avialable
+ * entries, whichever is first.
+ */
+ parseStat=parser(e,&ctx->ec_state,fp);
+ /* hold onto the state if we're out of memory XXX */
+ ctx->ec_state.ls_retry=0;
+ }
+ while (parseStat==NSLCD_RESULT_NOTFOUND);
+ return parseStat;
+}
+
+
+int _nss_ldap_searchbyname(
+ struct ldap_args *args,const char *filterprot,
+ enum ldap_map_selector sel,FILE *fp,NEWparser_t parser)
+{
+ int stat;
+ struct ent_context ctx;
+ int32_t tmpint32;
+
+ _nss_ldap_enter();
+
+ ctx.ec_msgid=-1;
+ ctx.ec_cookie=NULL;
+
+ stat=nss2nslcd(_nss_ldap_search_s(args,filterprot,sel,NULL,1,&ctx.ec_res));
+ /* write the result code */
+ WRITE_INT32(fp,stat);
+ /* bail on nothing found */
+ if (stat!=NSLCD_RESULT_SUCCESS)
+ {
+ _nss_ldap_leave();
+ return 1;
+ }
+ /*
+ * we pass this along for the benefit of the services parser,
+ * which uses it to figure out which protocol we really wanted.
+ * we only pass the second argument along, as that's what we need
+ * in services.
+ */
+ LS_INIT(ctx.ec_state);
+ ctx.ec_state.ls_type=LS_TYPE_KEY;
+ ctx.ec_state.ls_info.ls_key=args->la_arg2.la_string;
+ /* call the parser for the result */
+ stat=NEW_do_parse_s(&ctx,fp,parser);
+
+ _nss_ldap_ent_context_release(&ctx);
+
+ /* moved unlock here to avoid race condition bug #49 */
+ _nss_ldap_leave();
+
+ return stat;
+}
+
+/*
+ * These functions are called from within the parser, where it is assumed
+ * to be safe to use the connection and the respective message.
+ */
+
+/*
+ * Assign all values, bar omitvalue (if not NULL), to *valptr.
+ */
+enum nss_status
+_nss_ldap_assign_attrvals (LDAPMessage * e,
+ const char *attr, const char *omitvalue,
+ char ***valptr, char **pbuffer, size_t *
+ pbuflen, size_t * pvalcount)
+{
+ char **vals;
+ char **valiter;
+ int valcount;
+ char **p = NULL;
+
+ register int buflen = *pbuflen;
+ register char *buffer = *pbuffer;
+
+ if (pvalcount != NULL)
+ {
+ *pvalcount = 0;
+ }
+
+ if (__session.ls_conn == NULL)
+ {
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ vals = ldap_get_values (__session.ls_conn, e, (char *) attr);
+
+ valcount = (vals == NULL) ? 0 : ldap_count_values (vals);
+ if (bytesleft (buffer, buflen, char *) < (valcount + 1) * sizeof (char *))
+ {
+ ldap_value_free (vals);
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ align (buffer, buflen, char *);
+ p = *valptr = (char **) buffer;
+
+ buffer += (valcount + 1) * sizeof (char *);
+ buflen -= (valcount + 1) * sizeof (char *);
+
+ if (valcount == 0)
+ {
+ *p = NULL;
+ *pbuffer = buffer;
+ *pbuflen = buflen;
+ return NSS_STATUS_SUCCESS;
+ }
+
+ valiter = vals;
+
+ while (*valiter != NULL)
+ {
+ int vallen;
+ char *elt = NULL;
+
+ if (omitvalue != NULL && strcmp (*valiter, omitvalue) == 0)
+ {
+ valcount--;
+ }
+ else
+ {
+ vallen = strlen (*valiter);
+ if (buflen < (size_t) (vallen + 1))
+ {
+ ldap_value_free (vals);
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ /* copy this value into the next block of buffer space */
+ elt = buffer;
+ buffer += vallen + 1;
+ buflen -= vallen + 1;
+
+ strncpy (elt, *valiter, vallen);
+ elt[vallen] = '\0';
+ *p = elt;
+ p++;
+ }
+ valiter++;
+ }
+
+ *p = NULL;
+ *pbuffer = buffer;
+ *pbuflen = buflen;
+
+ if (pvalcount != NULL)
+ {
+ *pvalcount = valcount;
+ }
+
+ ldap_value_free (vals);
+ return NSS_STATUS_SUCCESS;
+}
+
+int _nss_ldap_write_attrvals(FILE *fp,LDAPMessage *e,const char *attr)
+{
+ char **vals;
+ int valcount;
+ int i;
+ int32_t tmpint32;
+ /* log */
+ log_log(LOG_DEBUG,"_nss_ldap_write_attrvals(%s)",attr);
+ /* check if we have a connection */
+ if (__session.ls_conn==NULL)
+ return NSLCD_RESULT_UNAVAIL;
+ /* get the values and the number of values */
+ vals=ldap_get_values(__session.ls_conn,e,(char *)attr);
+ valcount=(vals==NULL)?0:ldap_count_values(vals);
+ /* write number of entries */
+ WRITE_INT32(fp,valcount);
+ /* write the entries themselves */
+ for (i=0;i<valcount;i++)
+ {
+ WRITE_STRING(fp,vals[i]);
+ }
+ if (vals!=NULL)
+ ldap_value_free(vals);
+ return NSLCD_RESULT_SUCCESS;
+}
+
+/* Assign a single value to *valptr. */
+enum nss_status
+_nss_ldap_assign_attrval (LDAPMessage * e,
+ const char *attr, char **valptr, char **buffer,
+ size_t * buflen)
+{
+ char **vals;
+ int vallen;
+ const char *ovr, *def;
+
+ ovr = OV (attr);
+ if (ovr != NULL)
+ {
+ vallen = strlen (ovr);
+ if (*buflen < (size_t) (vallen + 1))
+ {
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ *valptr = *buffer;
+
+ strncpy (*valptr, ovr, vallen);
+ (*valptr)[vallen] = '\0';
+
+ *buffer += vallen + 1;
+ *buflen -= vallen + 1;
+
+ return NSS_STATUS_SUCCESS;
+ }
+
+ if (__session.ls_conn == NULL)
+ {
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ vals = ldap_get_values (__session.ls_conn, e, (char *) attr);
+ if (vals == NULL)
+ {
+ def = DF (attr);
+ if (def != NULL)
+ {
+ vallen = strlen (def);
+ if (*buflen < (size_t) (vallen + 1))
+ {
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ *valptr = *buffer;
+
+ strncpy (*valptr, def, vallen);
+ (*valptr)[vallen] = '\0';
+
+ *buffer += vallen + 1;
+ *buflen -= vallen + 1;
+
+ return NSS_STATUS_SUCCESS;
+ }
+ else
+ {
+ return NSS_STATUS_NOTFOUND;
+ }
+ }
+
+ vallen = strlen (*vals);
+ if (*buflen < (size_t) (vallen + 1))
+ {
+ ldap_value_free (vals);
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ *valptr = *buffer;
+
+ strncpy (*valptr, *vals, vallen);
+ (*valptr)[vallen] = '\0';
+
+ *buffer += vallen + 1;
+ *buflen -= vallen + 1;
+
+ ldap_value_free (vals);
+
+ return NSS_STATUS_SUCCESS;
+}
+
+const char *
+_nss_ldap_locate_userpassword (char **vals)
+{
+ const char *token = NULL;
+ size_t token_length = 0;
+ char **valiter;
+ const char *pwd = NULL;
+
+ if (__config != NULL)
+ {
+ switch (__config->ldc_password_type)
+ {
+ case LU_RFC2307_USERPASSWORD:
+ token = "{CRYPT}";
+ token_length = sizeof ("{CRYPT}") - 1;
+ break;
+ case LU_RFC3112_AUTHPASSWORD:
+ token = "CRYPT$";
+ token_length = sizeof ("CRYPT$") - 1;
+ break;
+ case LU_OTHER_PASSWORD:
+ break;
+ }
+ }
+
+ if (vals != NULL)
+ {
+ for (valiter = vals; *valiter != NULL; valiter++)
+ {
+ if (token_length == 0 ||
+ strncasecmp (*valiter, token, token_length) == 0)
+ {
+ pwd = *valiter;
+ break;
+ }
+ }
+ }
+
+ if (pwd == NULL)
+ pwd = "*";
+ else
+ pwd += token_length;
+
+ return pwd;
+}
+
+/*
+ * Assign a single value to *valptr, after examining userPassword for
+ * a syntactically suitable value.
+ */
+enum nss_status
+_nss_ldap_assign_userpassword (LDAPMessage * e,
+ const char *attr, char **valptr,
+ char **buffer, size_t * buflen)
+{
+ char **vals;
+ const char *pwd;
+ int vallen;
+
+ debug ("==> _nss_ldap_assign_userpassword");
+
+ if (__session.ls_conn == NULL)
+ {
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ vals = ldap_get_values (__session.ls_conn, e, (char *) attr);
+ pwd = _nss_ldap_locate_userpassword (vals);
+
+ vallen = strlen (pwd);
+
+ if (*buflen < (size_t) (vallen + 1))
+ {
+ if (vals != NULL)
+ {
+ ldap_value_free (vals);
+ }
+ debug ("<== _nss_ldap_assign_userpassword");
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ *valptr = *buffer;
+
+ strncpy (*valptr, pwd, vallen);
+ (*valptr)[vallen] = '\0';
+
+ *buffer += vallen + 1;
+ *buflen -= vallen + 1;
+
+ if (vals != NULL)
+ {
+ ldap_value_free (vals);
+ }
+
+ debug ("<== _nss_ldap_assign_userpassword");
+
+ return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_ldap_oc_check (LDAPMessage * e, const char *oc)
+{
+ char **vals, **valiter;
+ enum nss_status ret = NSS_STATUS_NOTFOUND;
+
+ if (__session.ls_conn == NULL)
+ {
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ vals = ldap_get_values (__session.ls_conn, e, AT (objectClass));
+ if (vals != NULL)
+ {
+ for (valiter = vals; *valiter != NULL; valiter++)
+ {
+ if (strcasecmp (*valiter, oc) == 0)
+ {
+ ret = NSS_STATUS_SUCCESS;
+ break;
+ }
+ }
+ }
+
+ if (vals != NULL)
+ {
+ ldap_value_free (vals);
+ }
+
+ return ret;
+}
+
+#ifdef HAVE_SHADOW_H
+int
+_nss_ldap_shadow_date (const char *val)
+{
+ int date;
+
+ if (__config->ldc_shadow_type == LS_AD_SHADOW)
+ {
+ date = atoll (val) / 864000000000LL - 134774LL;
+ date = (date > 99999) ? 99999 : date;
+ }
+ else
+ {
+ date = atol (val);
+ }
+
+ return date;
+}
+
+void
+_nss_ldap_shadow_handle_flag (struct spwd *sp)
+{
+ if (__config->ldc_shadow_type == LS_AD_SHADOW)
+ {
+ if (sp->sp_flag & UF_DONT_EXPIRE_PASSWD)
+ sp->sp_max = 99999;
+ sp->sp_flag = 0;
+ }
+}
+#endif /* HAVE_SHADOW_H */
+
+const char *
+_nss_ldap_map_at (enum ldap_map_selector sel, const char *attribute)
+{
+ const char *mapped = NULL;
+ enum nss_status stat;
+
+ stat = _nss_ldap_map_get (__config, sel, MAP_ATTRIBUTE, attribute, &mapped);
+
+ return (stat == NSS_STATUS_SUCCESS) ? mapped : attribute;
+}
+
+const char *
+_nss_ldap_unmap_at (enum ldap_map_selector sel, const char *attribute)
+{
+ const char *mapped = NULL;
+ enum nss_status stat;
+
+ stat = _nss_ldap_map_get (__config, sel, MAP_ATTRIBUTE_REVERSE, attribute, &mapped);
+
+ return (stat == NSS_STATUS_SUCCESS) ? mapped : attribute;
+}
+
+const char *
+_nss_ldap_map_oc (enum ldap_map_selector sel, const char *objectclass)
+{
+ const char *mapped = NULL;
+ enum nss_status stat;
+
+ stat = _nss_ldap_map_get (__config, sel, MAP_OBJECTCLASS, objectclass, &mapped);
+
+ return (stat == NSS_STATUS_SUCCESS) ? mapped : objectclass;
+}
+
+const char *
+_nss_ldap_unmap_oc (enum ldap_map_selector sel, const char *objectclass)
+{
+ const char *mapped = NULL;
+ enum nss_status stat;
+
+ stat = _nss_ldap_map_get (__config, sel, MAP_OBJECTCLASS_REVERSE, objectclass, &mapped);
+
+ return (stat == NSS_STATUS_SUCCESS) ? mapped : objectclass;
+}
+
+const char *
+_nss_ldap_map_ov (const char *attribute)
+{
+ const char *value = NULL;
+
+ _nss_ldap_map_get (__config, LM_NONE, MAP_OVERRIDE, attribute, &value);
+
+ return value;
+}
+
+const char *
+_nss_ldap_map_df (const char *attribute)
+{
+ const char *value = NULL;
+
+ _nss_ldap_map_get (__config, LM_NONE, MAP_DEFAULT, attribute, &value);
+
+ return value;
+}
+
+enum nss_status
+_nss_ldap_map_put (struct ldap_config * config,
+ enum ldap_map_selector sel,
+ enum ldap_map_type type,
+ const char *from,
+ const char *to)
+{
+ struct ldap_datum key, val;
+ void **map;
+ enum nss_status stat;
+
+ switch (type)
+ {
+ case MAP_ATTRIBUTE:
+ /* special handling for attribute mapping */ if (strcmp
+ (from,
+ "userPassword") == 0)
+ {
+ if (strcasecmp (to, "userPassword") == 0)
+ config->ldc_password_type = LU_RFC2307_USERPASSWORD;
+ else if (strcasecmp (to, "authPassword") == 0)
+ config->ldc_password_type = LU_RFC3112_AUTHPASSWORD;
+ else
+ config->ldc_password_type = LU_OTHER_PASSWORD;
+ }
+ else if (strcmp (from, "shadowLastChange") == 0)
+ {
+ if (strcasecmp (to, "shadowLastChange") == 0)
+ config->ldc_shadow_type = LS_RFC2307_SHADOW;
+ else if (strcasecmp (to, "pwdLastSet") == 0)
+ config->ldc_shadow_type = LS_AD_SHADOW;
+ else
+ config->ldc_shadow_type = LS_OTHER_SHADOW;
+ }
+ break;
+ case MAP_OBJECTCLASS:
+ case MAP_OVERRIDE:
+ case MAP_DEFAULT:
+ break;
+ default:
+ return NSS_STATUS_NOTFOUND;
+ break;
+ }
+
+ assert (sel <= LM_NONE);
+ map = &config->ldc_maps[sel][type];
+ assert (*map != NULL);
+
+ NSS_LDAP_DATUM_ZERO (&key);
+ key.data = (void *) from;
+ key.size = strlen (from) + 1;
+
+ NSS_LDAP_DATUM_ZERO (&val);
+ val.data = (void *) to;
+ val.size = strlen (to) + 1;
+
+ stat = _nss_ldap_db_put (*map, NSS_LDAP_DB_NORMALIZE_CASE, &key, &val);
+ if (stat == NSS_STATUS_SUCCESS &&
+ (type == MAP_ATTRIBUTE || type == MAP_OBJECTCLASS))
+ {
+ type = (type == MAP_ATTRIBUTE) ? MAP_ATTRIBUTE_REVERSE : MAP_OBJECTCLASS_REVERSE;
+ map = &config->ldc_maps[sel][type];
+
+ stat = _nss_ldap_db_put (*map, NSS_LDAP_DB_NORMALIZE_CASE, &val, &key);
+ }
+
+ return stat;
+}
+
+enum nss_status
+_nss_ldap_map_get (struct ldap_config * config,
+ enum ldap_map_selector sel,
+ enum ldap_map_type type,
+ const char *from, const char **to)
+{
+ struct ldap_datum key, val;
+ void *map;
+ enum nss_status stat;
+
+ if (config == NULL || sel > LM_NONE || type > MAP_MAX)
+ {
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ map = config->ldc_maps[sel][type];
+ assert (map != NULL);
+
+ NSS_LDAP_DATUM_ZERO (&key);
+ key.data = from;
+ key.size = strlen (from) + 1;
+
+ NSS_LDAP_DATUM_ZERO (&val);
+
+ stat = _nss_ldap_db_get (map, NSS_LDAP_DB_NORMALIZE_CASE, &key, &val);
+ if (stat == NSS_STATUS_NOTFOUND && sel != LM_NONE)
+ {
+ map = config->ldc_maps[LM_NONE][type];
+ assert (map != NULL);
+ stat = _nss_ldap_db_get (map, NSS_LDAP_DB_NORMALIZE_CASE, &key, &val);
+ }
+
+ if (stat == NSS_STATUS_SUCCESS)
+ *to = (char *) val.data;
+ else
+ *to = NULL;
+
+ return stat;
+}
+
+/*
+ * Proxy bind support for AIX. Very simple, but should do
+ * the job.
+ */
+
+struct ldap_proxy_bind_args
+{
+ char *binddn;
+ const char *bindpw;
+};
+
+
+#if LDAP_SET_REBIND_PROC_ARGS < 3
+static struct ldap_proxy_bind_args __proxy_args = { NULL, NULL };
+#endif
+
+#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
+#if LDAP_SET_REBIND_PROC_ARGS == 3
+static int
+do_proxy_rebind (LDAP * ld, LDAP_CONST char *url, ber_tag_t request,
+ ber_int_t msgid, void *arg)
+#else
+static int
+do_proxy_rebind (LDAP * ld, LDAP_CONST char *url, int request,
+ ber_int_t msgid)
+#endif
+{
+ int timelimit;
+#if LDAP_SET_REBIND_PROC_ARGS == 3
+ struct ldap_proxy_bind_args *who = (struct ldap_proxy_bind_args *) arg;
+#else
+ struct ldap_proxy_bind_args *who = &__proxy_args;
+#endif
+
+ timelimit = __session.ls_config->ldc_bind_timelimit;
+
+ return do_bind (ld, timelimit, who->binddn, who->bindpw, 0);
+}
+#else
+#if LDAP_SET_REBIND_PROC_ARGS == 3
+static int
+do_proxy_rebind (LDAP * ld, char **whop, char **credp, int *methodp,
+ int freeit, void *arg)
+#elif LDAP_SET_REBIND_PROC_ARGS == 2
+static int
+do_proxy_rebind (LDAP * ld, char **whop, char **credp, int *methodp,
+ int freeit)
+#endif
+{
+#if LDAP_SET_REBIND_PROC_ARGS == 3
+ struct ldap_proxy_bind_args *who = (struct ldap_proxy_bind_args *) arg;
+#else
+ struct ldap_proxy_bind_args *who = &__proxy_args;
+#endif
+ if (freeit)
+ {
+ if (*whop != NULL)
+ free (*whop);
+ if (*credp != NULL)
+ free (*credp);
+ }
+
+ *whop = who->binddn ? strdup (who->binddn) : NULL;
+ *credp = who->bindpw ? strdup (who->bindpw) : NULL;
+
+ *methodp = LDAP_AUTH_SIMPLE;
+
+ return LDAP_SUCCESS;
+}
+#endif
+
+enum nss_status
+_nss_ldap_proxy_bind (const char *user, const char *password)
+{
+ struct ldap_args args;
+ LDAPMessage *res, *e;
+ enum nss_status stat;
+ int rc;
+#if LDAP_SET_REBIND_PROC_ARGS == 3
+ struct ldap_proxy_bind_args proxy_args_buf;
+ struct ldap_proxy_bind_args *proxy_args = &proxy_args_buf;
+#else
+ struct ldap_proxy_bind_args *proxy_args = &__proxy_args;
+#endif
+
+ debug ("==> _nss_ldap_proxy_bind");
+
+ LA_INIT (args);
+ LA_TYPE (args) = LA_TYPE_STRING;
+ LA_STRING (args) = user;
+
+ /*
+ * Binding with an empty password will always work, so don't let
+ * the user in if they try that.
+ */
+ if (password == NULL || password[0] == '\0')
+ {
+ debug ("<== _nss_ldap_proxy_bind (empty password not permitted)");
+ /* XXX overload */
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ _nss_ldap_enter ();
+
+ stat = _nss_ldap_search_s (&args, _nss_ldap_filt_getpwnam,
+ LM_PASSWD, NULL, 1, &res);
+ if (stat == NSS_STATUS_SUCCESS)
+ {
+ e = _nss_ldap_first_entry (res);
+ if (e != NULL)
+ {
+ proxy_args->binddn = _nss_ldap_get_dn (e);
+ proxy_args->bindpw = password;
+
+ if (proxy_args->binddn != NULL)
+ {
+ /* Use our special rebind procedure. */
+#if LDAP_SET_REBIND_PROC_ARGS == 3
+ ldap_set_rebind_proc (__session.ls_conn, do_proxy_rebind, NULL);
+#elif LDAP_SET_REBIND_PROC_ARGS == 2
+ ldap_set_rebind_proc (__session.ls_conn, do_proxy_rebind);
+#endif
+
+ debug (":== _nss_ldap_proxy_bind: %s", proxy_args->binddn);
+
+ rc = do_bind (__session.ls_conn,
+ __session.ls_config->ldc_bind_timelimit,
+ proxy_args->binddn, proxy_args->bindpw, 0);
+ switch (rc)
+ {
+ case LDAP_INVALID_CREDENTIALS:
+ /* XXX overload */
+ stat = NSS_STATUS_TRYAGAIN;
+ break;
+ case LDAP_NO_SUCH_OBJECT:
+ stat = NSS_STATUS_NOTFOUND;
+ break;
+ case LDAP_SUCCESS:
+ stat = NSS_STATUS_SUCCESS;
+ break;
+ default:
+ stat = NSS_STATUS_UNAVAIL;
+ break;
+ }
+ /*
+ * Close the connection, don't want to continue
+ * being bound as this user or using this rebind proc.
+ */
+ do_close ();
+ ldap_memfree (proxy_args->binddn);
+ }
+ else
+ {
+ stat = NSS_STATUS_NOTFOUND;
+ }
+ proxy_args->binddn = NULL;
+ proxy_args->bindpw = NULL;
+ }
+ else
+ {
+ stat = NSS_STATUS_NOTFOUND;
+ }
+ ldap_msgfree (res);
+ }
+
+ _nss_ldap_leave ();
+
+ debug ("<== _nss_ldap_proxy_bind");
+
+ return stat;
+}
+
+const char **
+_nss_ldap_get_attributes (enum ldap_map_selector sel)
+{
+ const char **attrs = NULL;
+
+ debug ("==> _nss_ldap_get_attributes");
+
+ if (sel < LM_NONE)
+ {
+ if (do_init () != NSS_STATUS_SUCCESS)
+ {
+ debug ("<== _nss_ldap_get_attributes (init failed)");
+ return NULL;
+ }
+
+ attrs = __session.ls_config->ldc_attrtab[sel];
+ }
+
+ debug ("<== _nss_ldap_get_attributes");
+
+ return attrs;
+}
+
+int
+_nss_ldap_test_config_flag (unsigned int flag)
+{
+ if (__config != NULL && (__config->ldc_flags & flag) != 0)
+ return 1;
+
+ return 0;
+}
+
+int
+_nss_ldap_test_initgroups_ignoreuser (const char *user)
+{
+ char **p;
+
+ if (__config == NULL)
+ return 0;
+
+ if (__config->ldc_initgroups_ignoreusers == NULL)
+ return 0;
+
+ for (p = __config->ldc_initgroups_ignoreusers; *p != NULL; p++)
+ {
+ if (strcmp (*p, user) == 0)
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/nslcd/ldap-nss.h b/nslcd/ldap-nss.h
new file mode 100644
index 0000000..b59d774
--- /dev/null
+++ b/nslcd/ldap-nss.h
@@ -0,0 +1,611 @@
+/*
+ ldap-nss.c - main file for NSS interface
+ This file was part of the nss_ldap library which has been
+ forked into the nss-ldapd library.
+
+ Copyright (C) 1997-2005 Luke Howard
+ Copyright (C) 2006 West Consulting
+ Copyright (C) 2006 Arthur de Jong
+
+ This 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+#ifndef _LDAP_NSS_LDAP_LDAP_NSS_H
+#define _LDAP_NSS_LDAP_LDAP_NSS_H
+
+/* for glibc, use weak aliases to pthreads functions */
+#ifdef HAVE_LIBC_LOCK_H
+#include <libc-lock.h>
+#elif defined(HAVE_BITS_LIBC_LOCK_H)
+#include <bits/libc-lock.h>
+#endif
+
+#include <time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#ifdef HAVE_SHADOW_H
+#include <shadow.h>
+#endif
+
+#include <netdb.h>
+#include <netinet/in.h>
+#include <syslog.h>
+
+#include <nss.h>
+
+#include "ldap-schema.h"
+
+#ifndef NSS_BUFSIZ
+#define NSS_BUFSIZ 1024
+#endif
+
+#ifndef NSS_BUFLEN_GROUP
+#define NSS_BUFLEN_GROUP LDAP_NSS_BUFLEN_GROUP
+#endif
+
+#ifndef LDAP_FILT_MAXSIZ
+#define LDAP_FILT_MAXSIZ 1024
+#endif /* not LDAP_FILT_MAXSIZ */
+
+#ifndef LDAPS_PORT
+#define LDAPS_PORT 636
+#endif /* not LDAPS_PORT */
+
+#ifdef DEBUG
+#ifdef __XGNUC__
+#define debug(fmt, args...) fprintf(stderr, "nss_ldap: " fmt "\n" , ## args)
+#else
+#include <stdarg.h>
+#include <stdio.h>
+static void
+debug (char *fmt, ...)
+{
+ va_list ap;
+ va_start (ap, fmt);
+ fprintf (stderr, "nss_ldap: ");
+ vfprintf (stderr, fmt, ap);
+ va_end (ap);
+ fprintf (stderr, "\n");
+}
+#endif /* __GNUC__ */
+#else /* DEBUG */
+#ifdef __GNUC__
+#define debug(fmt, args...)
+#else /* __GNUC__ */
+static void
+debug (char *fmt, ...)
+{
+}
+#endif /* not __GNUC__ */
+#endif /* not DEBUG */
+
+#ifdef __GNUC__
+#define alignof(ptr) __alignof__(ptr)
+#elif defined(HAVE_ALIGNOF_H)
+#include <alignof.h>
+#else
+#define alignof(ptr) (sizeof(char *))
+#endif /* __GNUC__ */
+
+#define align(ptr, blen, TYPE)\
+ { \
+ char *qtr = ptr; \
+ ptr += alignof(TYPE) - 1; \
+ ptr -= ((ptr - (char *)NULL) % alignof(TYPE)); \
+ blen -= (ptr - qtr); \
+ }
+
+/* worst case */
+#define bytesleft(ptr, blen, TYPE) \
+ ( (blen < alignof(TYPE)) ? 0 : (blen - alignof(TYPE) + 1))
+
+/* selectors for different maps */
+enum ldap_map_selector
+{
+ LM_PASSWD,
+ LM_SHADOW,
+ LM_GROUP,
+ LM_HOSTS,
+ LM_SERVICES,
+ LM_NETWORKS,
+ LM_PROTOCOLS,
+ LM_RPC,
+ LM_ETHERS,
+ LM_NETMASKS,
+ LM_BOOTPARAMS,
+ LM_ALIASES,
+ LM_NETGROUP,
+ LM_NONE
+};
+
+enum ldap_userpassword_selector
+{
+ LU_RFC2307_USERPASSWORD,
+ LU_RFC3112_AUTHPASSWORD,
+ LU_OTHER_PASSWORD
+};
+
+enum ldap_shadow_selector
+{
+ LS_RFC2307_SHADOW,
+ LS_AD_SHADOW,
+ LS_OTHER_SHADOW
+};
+
+#ifndef UF_DONT_EXPIRE_PASSWD
+#define UF_DONT_EXPIRE_PASSWD 0x10000
+#endif
+
+enum ldap_ssl_options
+{
+ SSL_OFF,
+ SSL_LDAPS,
+ SSL_START_TLS
+};
+
+enum ldap_reconnect_policy
+{
+ LP_RECONNECT_HARD_INIT,
+ LP_RECONNECT_HARD_OPEN,
+ LP_RECONNECT_SOFT
+};
+
+/*
+ * POSIX profile information (not used yet)
+ * see draft-joslin-config-schema-00.txt
+ */
+struct ldap_service_search_descriptor
+{
+ /* search base, qualified */
+ char *lsd_base;
+ /* scope */
+ int lsd_scope;
+ /* filter */
+ char *lsd_filter;
+ /* next */
+ struct ldap_service_search_descriptor *lsd_next;
+};
+
+/* maximum number of URIs */
+#define NSS_LDAP_CONFIG_URI_MAX 31
+
+/*
+ * linked list of configurations pointing to LDAP servers. The first
+ * which has a successful ldap_open() is used. Conceivably the rest
+ * could be used after a failed or exhausted search.
+ */
+struct ldap_config
+{
+ /* NULL terminated list of URIs */
+ char *ldc_uris[NSS_LDAP_CONFIG_URI_MAX + 1];
+ /* default port, if not specified in URI */
+ int ldc_port;
+ /* base DN, eg. dc=gnu,dc=org */
+ char *ldc_base;
+ /* scope for searches */
+ int ldc_scope;
+ /* dereference aliases/links */
+ int ldc_deref;
+ /* bind DN */
+ char *ldc_binddn;
+ /* bind cred */
+ char *ldc_bindpw;
+ /* sasl auth id */
+ char *ldc_saslid;
+ /* do we use sasl when binding? */
+ int ldc_usesasl;
+ /* shadow bind DN */
+ char *ldc_rootbinddn;
+ /* shadow bind cred */
+ char *ldc_rootbindpw;
+ /* shadow sasl auth id */
+ char *ldc_rootsaslid;
+ /* do we use sasl for root? */
+ int ldc_rootusesasl;
+ /* protocol version */
+ int ldc_version;
+ /* search timelimit */
+ int ldc_timelimit;
+ /* bind timelimit */
+ int ldc_bind_timelimit;
+ /* SSL enabled */
+ enum ldap_ssl_options ldc_ssl_on;
+ /* SSL certificate path */
+ char *ldc_sslpath;
+ /* Chase referrals */
+ int ldc_referrals;
+ int ldc_restart;
+ /* naming contexts */
+ struct ldap_service_search_descriptor *ldc_sds[LM_NONE];
+ /* tls check peer */
+ int ldc_tls_checkpeer;
+ /* tls ca certificate file */
+ char *ldc_tls_cacertfile;
+ /* tls ca certificate dir */
+ char *ldc_tls_cacertdir;
+ /* tls ciphersuite */
+ char *ldc_tls_ciphers;
+ /* tls certificate */
+ char *ldc_tls_cert;
+ /* tls key */
+ char *ldc_tls_key;
+ /* tls randfile */
+ char *ldc_tls_randfile;
+ /* idle timeout */
+ time_t ldc_idle_timelimit;
+ /* reconnect policy */
+ enum ldap_reconnect_policy ldc_reconnect_pol;
+ int ldc_reconnect_tries;
+ int ldc_reconnect_sleeptime;
+ int ldc_reconnect_maxsleeptime;
+ int ldc_reconnect_maxconntries;
+ /* sasl security */
+ char *ldc_sasl_secprops;
+ /* DNS SRV RR domain */
+ char *ldc_srv_domain;
+ /* directory for debug files */
+ char *ldc_logdir;
+ /* LDAP debug level */
+ int ldc_debug;
+ int ldc_pagesize;
+#ifdef CONFIGURE_KRB5_CCNAME
+ /* krb5 ccache name */
+ char *ldc_krb5_ccname;
+#endif /* CONFIGURE_KRB5_CCNAME */
+ /* attribute/objectclass maps relative to this config */
+ void *ldc_maps[LM_NONE + 1][6]; /* must match MAP_MAX */
+ /* is userPassword "userPassword" or not? ie. do we need {crypt} to be stripped */
+ enum ldap_userpassword_selector ldc_password_type;
+ /* Use active directory time offsets? */
+ enum ldap_shadow_selector ldc_shadow_type;
+ /* attribute table for ldap search requensts */
+ const char **ldc_attrtab[LM_NONE + 1];
+ unsigned int ldc_flags;
+ /* last modification time */
+ time_t ldc_mtime;
+ char **ldc_initgroups_ignoreusers;
+};
+
+#if defined(__GLIBC__) && __GLIBC_MINOR__ > 1
+#else
+#define ss_family sa_family
+#endif /* __GLIBC__ */
+
+enum ldap_session_state
+{
+ LS_UNINITIALIZED = -1,
+ LS_INITIALIZED,
+ LS_CONNECTED_TO_DSA
+};
+
+/*
+ * convenient wrapper around pointer into global config list, and a
+ * connection to an LDAP server.
+ */
+struct ldap_session
+{
+ /* the connection */
+ LDAP *ls_conn;
+ /* pointer into config table */
+ struct ldap_config *ls_config;
+ /* timestamp of last activity */
+ time_t ls_timestamp;
+ /* has session been connected? */
+ enum ldap_session_state ls_state;
+ /* keep track of the LDAP sockets */
+ struct sockaddr_storage ls_sockname;
+ struct sockaddr_storage ls_peername;
+ /* index into ldc_uris: currently connected DSA */
+ int ls_current_uri;
+};
+
+enum ldap_args_types
+{
+ LA_TYPE_STRING,
+ LA_TYPE_NUMBER,
+ LA_TYPE_STRING_AND_STRING,
+ LA_TYPE_NUMBER_AND_STRING,
+ LA_TYPE_TRIPLE,
+ LA_TYPE_STRING_LIST_OR,
+ LA_TYPE_STRING_LIST_AND,
+ LA_TYPE_NONE
+};
+
+enum ldap_map_type
+{
+ MAP_ATTRIBUTE = 0,
+ MAP_OBJECTCLASS,
+ MAP_OVERRIDE,
+ MAP_DEFAULT,
+ MAP_ATTRIBUTE_REVERSE,
+ MAP_OBJECTCLASS_REVERSE, /* XXX not used yet? */
+ MAP_MAX = MAP_OBJECTCLASS_REVERSE
+};
+
+struct ldap_args
+{
+ enum ldap_args_types la_type;
+ union
+ {
+ const char *la_string;
+ long la_number;
+ struct {
+ /* for Solaris netgroup support */
+ const char *host;
+ const char *user;
+ const char *domain;
+ } la_triple;
+ const char **la_string_list;
+ }
+ la_arg1;
+ union
+ {
+ const char *la_string;
+ }
+ la_arg2;
+ const char *la_base; /* override default base */
+};
+
+#define LA_INIT(q) do { \
+ (q).la_type = LA_TYPE_STRING; \
+ (q).la_arg1.la_string = NULL; \
+ (q).la_arg2.la_string = NULL; \
+ (q).la_base = NULL; \
+ } while (0)
+#define LA_TYPE(q) ((q).la_type)
+#define LA_STRING(q) ((q).la_arg1.la_string)
+#define LA_NUMBER(q) ((q).la_arg1.la_number)
+#define LA_TRIPLE(q) ((q).la_arg1.la_triple)
+#define LA_STRING_LIST(q) ((q).la_arg1.la_string_list)
+#define LA_STRING2(q) ((q).la_arg2.la_string)
+#define LA_BASE(q) ((q).la_base)
+
+/*
+ * the state consists of the desired attribute value or an offset into a list of
+ * values for the desired attribute. This is necessary to support services.
+ *
+ * Be aware of the arbitary distinction between state and context. Context is
+ * the enumeration state of a lookup subsystem (which may be per-subsystem,
+ * or per-subsystem/per-thread, depending on the OS). State is the state
+ * of a particular lookup, and is only concerned with resolving and enumerating
+ * services. State is represented as instances of struct ldap_state; context as
+ * instances of struct ent_context. The latter contains the former.
+ */
+struct ldap_state
+{
+ int ls_type;
+ int ls_retry;
+#define LS_TYPE_KEY (0)
+#define LS_TYPE_INDEX (1)
+ union
+ {
+ /* ls_key is the requested attribute value.
+ ls_index is the desired offset into the value list.
+ */
+ const char *ls_key;
+ int ls_index;
+ }
+ ls_info;
+};
+
+/*
+ * thread specific context: result chain, and state data
+ */
+struct ent_context
+{
+ struct ldap_state ec_state; /* eg. for services */
+ int ec_msgid; /* message ID */
+ LDAPMessage *ec_res; /* result chain */
+ struct ldap_service_search_descriptor *ec_sd; /* current sd */
+ struct berval *ec_cookie; /* cookie for paged searches */
+};
+
+struct name_list
+{
+ char *name;
+ struct name_list *next;
+};
+
+typedef enum nss_status (*parser_t) (LDAPMessage *, struct ldap_state *, void *,
+ char *, size_t);
+
+typedef int (*NEWparser_t)(LDAPMessage *e,struct ldap_state *pvt,FILE *fp);
+
+/*
+ * Portable locking macro.
+ */
+#if defined(HAVE_THREAD_H)
+#define NSS_LDAP_LOCK(m) mutex_lock(&m)
+#define NSS_LDAP_UNLOCK(m) mutex_unlock(&m)
+#define NSS_LDAP_DEFINE_LOCK(m) static mutex_t m = DEFAULTMUTEX
+#elif defined(HAVE_LIBC_LOCK_H) || defined(HAVE_BITS_LIBC_LOCK_H)
+#define NSS_LDAP_LOCK(m) __libc_lock_lock(m)
+#define NSS_LDAP_UNLOCK(m) __libc_lock_unlock(m)
+#define NSS_LDAP_DEFINE_LOCK(m) static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER
+#elif defined(HAVE_PTHREAD_H)
+#define NSS_LDAP_LOCK(m) pthread_mutex_lock(&m)
+#define NSS_LDAP_UNLOCK(m) pthread_mutex_unlock(&m)
+#define NSS_LDAP_DEFINE_LOCK(m) static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER
+#else
+#define NSS_LDAP_LOCK(m)
+#define NSS_LDAP_UNLOCK(m)
+#define NSS_LDAP_DEFINE_LOCK(m)
+#endif
+
+/*
+ * Acquire global nss_ldap lock and blocks SIGPIPE.
+ * Generally this should only be done within ldap-nss.c.
+ */
+void _nss_ldap_enter (void);
+
+/*
+ * Release global nss_ldap lock and blocks SIGPIPE.
+ * Generally this should only be done within ldap-nss.c.
+ */
+void _nss_ldap_leave (void);
+
+/*
+ * _nss_ldap_ent_context_init() is called for each getXXent() call
+ * This will acquire the global mutex.
+ */
+struct ent_context *_nss_ldap_ent_context_init (struct ent_context **);
+
+/*
+ * _nss_ldap_ent_context_init_locked() has the same behaviour
+ * as above, except it assumes that the caller has acquired
+ * the lock
+ */
+
+struct ent_context *_nss_ldap_ent_context_init_locked (struct ent_context **);
+
+/*
+ * _nss_ldap_ent_context_release() is used to manually free a context
+ */
+void _nss_ldap_ent_context_release (struct ent_context *);
+
+/*
+ * these are helper functions for ldap-grp.c only on Solaris
+ */
+char **_nss_ldap_get_values (LDAPMessage * e, const char *attr);
+char *_nss_ldap_get_dn (LDAPMessage * e);
+LDAPMessage *_nss_ldap_first_entry (LDAPMessage * res);
+LDAPMessage *_nss_ldap_next_entry (LDAPMessage * res);
+char *_nss_ldap_first_attribute (LDAPMessage * entry, BerElement **berptr);
+char *_nss_ldap_next_attribute (LDAPMessage * entry, BerElement *ber);
+const char **_nss_ldap_get_attributes (enum ldap_map_selector sel);
+
+/*
+ * Synchronous search cover (caller acquires lock).
+ */
+enum nss_status _nss_ldap_search_s (const struct ldap_args * args, /* IN */
+ const char *filterprot, /* IN */
+ enum ldap_map_selector sel, /* IN */
+ const char **user_attrs, /* IN */
+ int sizelimit, /* IN */
+ LDAPMessage ** pRes /* OUT */ );
+
+/*
+ * Emulate X.500 read operation.
+ */
+enum nss_status _nss_ldap_read (const char *dn, /* IN */
+ const char **attributes, /* IN */
+ LDAPMessage ** pRes /* OUT */ );
+
+/*
+ * extended enumeration routine; uses asynchronous API.
+ * Caller must have acquired the global mutex
+ */
+enum nss_status _nss_ldap_getent_ex (struct ldap_args * args, /* IN */
+ struct ent_context ** key, /* IN/OUT */
+ void *result, /* IN/OUT */
+ char *buffer, /* IN */
+ size_t buflen, /* IN */
+ int *errnop, /* OUT */
+ const char *filterprot, /* IN */
+ enum ldap_map_selector sel, /* IN */
+ const char **user_attrs, /* IN */
+ parser_t parser /* IN */ );
+
+/*
+ * common enumeration routine; uses asynchronous API.
+ * Acquires the global mutex
+ */
+enum nss_status _nss_ldap_getent (struct ent_context ** key, /* IN/OUT */
+ void *result, /* IN/OUT */
+ char *buffer, /* IN */
+ size_t buflen, /* IN */
+ int *errnop, /* OUT */
+ const char *filterprot, /* IN */
+ enum ldap_map_selector sel, /* IN */
+ parser_t parser /* IN */ );
+
+/*
+ * common lookup routine; uses synchronous API.
+ */
+enum nss_status _nss_ldap_getbyname (struct ldap_args * args, /* IN/OUT */
+ void *result, /* IN/OUT */
+ char *buffer, /* IN */
+ size_t buflen, /* IN */
+ int *errnop, /* OUT */
+ const char *filterprot, /* IN */
+ enum ldap_map_selector sel, /* IN */
+ parser_t parser /* IN */ );
+
+int _nss_ldap_searchbyname(struct ldap_args *args, /* IN/OUT */
+ const char *filterprot, /* IN */
+ enum ldap_map_selector sel, /* IN */
+ FILE *fp,NEWparser_t parser /* IN */ );
+
+
+/* parsing utility functions */
+enum nss_status _nss_ldap_assign_attrvals (LDAPMessage * e, /* IN */
+ const char *attr, /* IN */
+ const char *omitvalue, /* IN */
+ char ***valptr, /* OUT */
+ char **buffer, /* IN/OUT */
+ size_t * buflen, /* IN/OUT */
+ size_t * pvalcount /* OUT */ );
+
+int _nss_ldap_write_attrvals(FILE *fp,LDAPMessage *e,const char *attr);
+
+enum nss_status _nss_ldap_assign_attrval (LDAPMessage * e, /* IN */
+ const char *attr, /* IN */
+ char **valptr, /* OUT */
+ char **buffer, /* IN/OUT */
+ size_t * buflen /* IN/OUT */ );
+
+
+const char *_nss_ldap_locate_userpassword (char **vals);
+
+enum nss_status _nss_ldap_assign_userpassword (LDAPMessage * e, /* IN */
+ const char *attr, /* IN */
+ char **valptr, /* OUT */
+ char **buffer, /* IN/OUT */
+ size_t * buflen); /* IN/OUT */
+
+enum nss_status _nss_ldap_oc_check (LDAPMessage * e, const char *oc);
+
+int _nss_ldap_shadow_date(const char *val);
+void _nss_ldap_shadow_handle_flag(struct spwd *sp);
+
+enum nss_status _nss_ldap_map_put (struct ldap_config * config,
+ enum ldap_map_selector sel,
+ enum ldap_map_type map,
+ const char *key, const char *value);
+
+enum nss_status _nss_ldap_map_get (struct ldap_config * config,
+ enum ldap_map_selector sel,
+ enum ldap_map_type map,
+ const char *key, const char **value);
+
+const char *_nss_ldap_map_at (enum ldap_map_selector sel, const char *pChar2);
+const char *_nss_ldap_unmap_at (enum ldap_map_selector sel, const char *attribute);
+
+const char *_nss_ldap_map_oc (enum ldap_map_selector sel, const char *pChar);
+const char *_nss_ldap_unmap_oc (enum ldap_map_selector sel, const char *pChar);
+
+const char *_nss_ldap_map_ov (const char *pChar);
+const char *_nss_ldap_map_df (const char *pChar);
+
+enum nss_status _nss_ldap_proxy_bind (const char *user, const char *password);
+
+enum nss_status _nss_ldap_init (void);
+void _nss_ldap_close (void);
+
+int _nss_ldap_test_config_flag (unsigned int flag);
+int _nss_ldap_test_initgroups_ignoreuser (const char *user);
+
+#endif /* _LDAP_NSS_LDAP_LDAP_NSS_H */
diff --git a/nslcd/ldap-schema.c b/nslcd/ldap-schema.c
new file mode 100644
index 0000000..4ae95a5
--- /dev/null
+++ b/nslcd/ldap-schema.c
@@ -0,0 +1,453 @@
+/*
+ ldap-schema.c - LDAP schema information functions and definitions
+ This file was part of the nss_ldap library which has been
+ forked into the nss-ldapd library.
+
+ Copyright (C) 1997-2005 Luke Howard
+ Copyright (C) 2006 West Consulting
+ Copyright (C) 2006 Arthur de Jong
+
+ This 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.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 "ldap-schema.h"
+#include "util.h"
+
+/* max number of attributes per object class */
+#define ATTRTAB_SIZE 15
+
+/**
+ * declare filters formerly declared in ldap-*.h
+ */
+
+/* rfc822 mail aliases */
+char _nss_ldap_filt_getaliasbyname[LDAP_FILT_MAXSIZ];
+char _nss_ldap_filt_getaliasent[LDAP_FILT_MAXSIZ];
+
+/* boot parameters */
+char _nss_ldap_filt_getbootparamsbyname[LDAP_FILT_MAXSIZ];
+
+/* MAC address mappings */
+char _nss_ldap_filt_gethostton[LDAP_FILT_MAXSIZ];
+char _nss_ldap_filt_getntohost[LDAP_FILT_MAXSIZ];
+char _nss_ldap_filt_getetherent[LDAP_FILT_MAXSIZ];
+
+/* groups */
+char _nss_ldap_filt_getgrnam[LDAP_FILT_MAXSIZ];
+char _nss_ldap_filt_getgrgid[LDAP_FILT_MAXSIZ];
+char _nss_ldap_filt_getgrent[LDAP_FILT_MAXSIZ];
+char _nss_ldap_filt_getgroupsbymemberanddn[LDAP_FILT_MAXSIZ];
+char _nss_ldap_filt_getgroupsbydn[LDAP_FILT_MAXSIZ];
+char _nss_ldap_filt_getpwnam_groupsbymember[LDAP_FILT_MAXSIZ];
+char _nss_ldap_filt_getgroupsbymember[LDAP_FILT_MAXSIZ];
+
+/* IP hosts */
+char _nss_ldap_filt_gethostbyname[LDAP_FILT_MAXSIZ];
+char _nss_ldap_filt_gethostbyaddr[LDAP_FILT_MAXSIZ];
+char _nss_ldap_filt_gethostent[LDAP_FILT_MAXSIZ];
+
+/* IP networks */
+char _nss_ldap_filt_getnetbyname[LDAP_FILT_MAXSIZ];
+char _nss_ldap_filt_getnetbyaddr[LDAP_FILT_MAXSIZ];
+char _nss_ldap_filt_getnetent[LDAP_FILT_MAXSIZ];
+
+/* IP protocols */
+char _nss_ldap_filt_getprotobyname[LDAP_FILT_MAXSIZ];
+char _nss_ldap_filt_getprotobynumber[LDAP_FILT_MAXSIZ];
+char _nss_ldap_filt_getprotoent[LDAP_FILT_MAXSIZ];
+
+/* users */
+char _nss_ldap_filt_getpwnam[LDAP_FILT_MAXSIZ];
+char _nss_ldap_filt_getpwuid[LDAP_FILT_MAXSIZ];
+char _nss_ldap_filt_getpwent[LDAP_FILT_MAXSIZ];
+
+/* RPCs */
+char _nss_ldap_filt_getrpcbyname[LDAP_FILT_MAXSIZ];
+char _nss_ldap_filt_getrpcbynumber[LDAP_FILT_MAXSIZ];
+char _nss_ldap_filt_getrpcent[LDAP_FILT_MAXSIZ];
+
+/* IP services */
+char _nss_ldap_filt_getservbyname[LDAP_FILT_MAXSIZ];
+char _nss_ldap_filt_getservbynameproto[LDAP_FILT_MAXSIZ];
+char _nss_ldap_filt_getservbyport[LDAP_FILT_MAXSIZ];
+char _nss_ldap_filt_getservbyportproto[LDAP_FILT_MAXSIZ];
+char _nss_ldap_filt_getservent[LDAP_FILT_MAXSIZ];
+
+/* shadow users */
+char _nss_ldap_filt_getspnam[LDAP_FILT_MAXSIZ];
+char _nss_ldap_filt_getspent[LDAP_FILT_MAXSIZ];
+
+/* netgroups */
+char _nss_ldap_filt_getnetgrent[LDAP_FILT_MAXSIZ];
+char _nss_ldap_filt_innetgr[LDAP_FILT_MAXSIZ];
+
+/**
+ * lookup filter initialization
+ */
+void
+_nss_ldap_init_filters ()
+{
+ /* rfc822 mail aliases */
+ snprintf (_nss_ldap_filt_getaliasbyname, LDAP_FILT_MAXSIZ,
+ "(&(%s=%s)(%s=%s))", AT (objectClass), OC (nisMailAlias),
+ ATM (LM_ALIASES, cn), "%s");
+ snprintf (_nss_ldap_filt_getaliasent, LDAP_FILT_MAXSIZ,
+ "(%s=%s)", AT (objectClass), OC (nisMailAlias));
+
+ /* boot parameters */
+ snprintf (_nss_ldap_filt_getbootparamsbyname, LDAP_FILT_MAXSIZ,
+ "(&(%s=%s)(%s=%s))", AT (objectClass), OC (bootableDevice),
+ ATM (LM_BOOTPARAMS, cn), "%d");
+
+ /* MAC address mappings */
+ snprintf (_nss_ldap_filt_gethostton, LDAP_FILT_MAXSIZ,
+ "(&(%s=%s)(%s=%s))", AT (objectClass), OC (ieee802Device),
+ ATM (LM_ETHERS, cn), "%s");
+ snprintf (_nss_ldap_filt_getntohost, LDAP_FILT_MAXSIZ,
+ "(&(%s=%s)(%s=%s))", AT (objectClass), OC (ieee802Device), AT (macAddress),
+ "%s");
+ snprintf (_nss_ldap_filt_getetherent, LDAP_FILT_MAXSIZ, "(%s=%s)",
+ AT (objectClass), OC (ieee802Device));
+
+ /* groups */
+ snprintf (_nss_ldap_filt_getgrnam, LDAP_FILT_MAXSIZ,
+ "(&(%s=%s)(%s=%s))", AT (objectClass), OC (posixGroup),
+ ATM (LM_GROUP, cn), "%s");
+ snprintf (_nss_ldap_filt_getgrgid, LDAP_FILT_MAXSIZ,
+ "(&(%s=%s)(%s=%s))", AT (objectClass), OC (posixGroup),
+ ATM (LM_GROUP, gidNumber), "%d");
+ snprintf (_nss_ldap_filt_getgrent, LDAP_FILT_MAXSIZ, "(&(%s=%s))",
+ AT (objectClass), OC (posixGroup));
+ snprintf (_nss_ldap_filt_getgroupsbymemberanddn, LDAP_FILT_MAXSIZ,
+ "(&(%s=%s)(|(%s=%s)(%s=%s)))",
+ AT (objectClass), OC (posixGroup), AT (memberUid), "%s", AT (uniqueMember), "%s");
+ snprintf (_nss_ldap_filt_getgroupsbydn, LDAP_FILT_MAXSIZ,
+ "(&(%s=%s)(%s=%s))",
+ AT (objectClass), OC (posixGroup), AT (uniqueMember), "%s");
+ snprintf (_nss_ldap_filt_getpwnam_groupsbymember, LDAP_FILT_MAXSIZ,
+ "(|(&(%s=%s)(%s=%s))(&(%s=%s)(%s=%s)))",
+ AT (objectClass), OC (posixGroup), AT (memberUid), "%s",
+ AT (objectClass), OC (posixAccount), ATM (LM_PASSWD, uid), "%s");
+ snprintf (_nss_ldap_filt_getgroupsbymember, LDAP_FILT_MAXSIZ,
+ "(&(%s=%s)(%s=%s))", AT (objectClass), OC (posixGroup), AT (memberUid),
+ "%s");
+
+ /* IP hosts */
+ snprintf (_nss_ldap_filt_gethostbyname, LDAP_FILT_MAXSIZ,
+ "(&(%s=%s)(%s=%s))", AT (objectClass), OC (ipHost), ATM (LM_HOSTS, cn),
+ "%s");
+ snprintf (_nss_ldap_filt_gethostbyaddr, LDAP_FILT_MAXSIZ,
+ "(&(%s=%s)(%s=%s))", AT (objectClass), OC (ipHost), AT (ipHostNumber),
+ "%s");
+ snprintf (_nss_ldap_filt_gethostent, LDAP_FILT_MAXSIZ, "(%s=%s)",
+ AT (objectClass), OC (ipHost));
+
+ /* IP networks */
+ snprintf (_nss_ldap_filt_getnetbyname, LDAP_FILT_MAXSIZ,
+ "(&(%s=%s)(%s=%s))", AT (objectClass), OC (ipNetwork),
+ ATM (LM_NETWORKS, cn), "%s");
+ snprintf (_nss_ldap_filt_getnetbyaddr, LDAP_FILT_MAXSIZ,
+ "(&(%s=%s)(%s=%s))", AT (objectClass), OC (ipNetwork),
+ AT (ipNetworkNumber), "%s");
+ snprintf (_nss_ldap_filt_getnetent, LDAP_FILT_MAXSIZ, "(%s=%s)",
+ AT (objectClass), OC (ipNetwork));
+
+ /* IP protocols */
+ snprintf (_nss_ldap_filt_getprotobyname, LDAP_FILT_MAXSIZ,
+ "(&(%s=%s)(%s=%s))", AT (objectClass), OC (ipProtocol),
+ ATM (LM_PROTOCOLS, cn), "%s");
+ snprintf (_nss_ldap_filt_getprotobynumber, LDAP_FILT_MAXSIZ,
+ "(&(%s=%s)(%s=%s))", AT (objectClass), OC (ipProtocol),
+ AT (ipProtocolNumber), "%d");
+ snprintf (_nss_ldap_filt_getprotoent, LDAP_FILT_MAXSIZ, "(%s=%s)",
+ AT (objectClass), OC (ipProtocol));
+
+ /* users */
+ snprintf (_nss_ldap_filt_getpwnam, LDAP_FILT_MAXSIZ,
+ "(&(%s=%s)(%s=%s))", AT (objectClass), OC (posixAccount),
+ ATM (LM_PASSWD, uid), "%s");
+ snprintf (_nss_ldap_filt_getpwuid, LDAP_FILT_MAXSIZ,
+ "(&(%s=%s)(%s=%s))",
+ AT (objectClass), OC (posixAccount), AT (uidNumber), "%d");
+ snprintf (_nss_ldap_filt_getpwent, LDAP_FILT_MAXSIZ,
+ "(%s=%s)", AT (objectClass), OC (posixAccount));
+
+ /* RPCs */
+ snprintf (_nss_ldap_filt_getrpcbyname, LDAP_FILT_MAXSIZ,
+ "(&(%s=%s)(%s=%s))", AT (objectClass), OC (oncRpc), ATM (LM_RPC, cn), "%s");
+ snprintf (_nss_ldap_filt_getrpcbynumber, LDAP_FILT_MAXSIZ,
+ "(&(%s=%s)(%s=%s))", AT (objectClass), OC (oncRpc), AT (oncRpcNumber),
+ "%d");
+ snprintf (_nss_ldap_filt_getrpcent, LDAP_FILT_MAXSIZ, "(%s=%s)",
+ AT (objectClass), OC (oncRpc));
+
+ /* IP services */
+ snprintf (_nss_ldap_filt_getservbyname, LDAP_FILT_MAXSIZ,
+ "(&(%s=%s)(%s=%s))", AT (objectClass), OC (ipService), ATM (LM_SERVICES, cn),
+ "%s");
+ snprintf (_nss_ldap_filt_getservbynameproto, LDAP_FILT_MAXSIZ,
+ "(&(%s=%s)(%s=%s)(%s=%s))",
+ AT (objectClass), OC (ipService), ATM (LM_SERVICES, cn), "%s", AT (ipServiceProtocol),
+ "%s");
+ snprintf (_nss_ldap_filt_getservbyport, LDAP_FILT_MAXSIZ,
+ "(&(%s=%s)(%s=%s))", AT (objectClass), OC (ipService), AT (ipServicePort),
+ "%d");
+ snprintf (_nss_ldap_filt_getservbyportproto, LDAP_FILT_MAXSIZ,
+ "(&(%s=%s)(%s=%s)(%s=%s))", AT (objectClass), OC (ipService),
+ AT (ipServicePort), "%d", AT (ipServiceProtocol), "%s");
+ snprintf (_nss_ldap_filt_getservent, LDAP_FILT_MAXSIZ, "(%s=%s)",
+ AT (objectClass), OC (ipService));
+
+ /* shadow users */
+ snprintf (_nss_ldap_filt_getspnam, LDAP_FILT_MAXSIZ,
+ "(&(%s=%s)(%s=%s))", AT (objectClass), OC (shadowAccount),
+ ATM (LM_SHADOW, uid), "%s");
+ snprintf (_nss_ldap_filt_getspent, LDAP_FILT_MAXSIZ,
+ "(%s=%s)", AT (objectClass), OC (shadowAccount));
+
+ /* netgroups */
+ snprintf (_nss_ldap_filt_getnetgrent, LDAP_FILT_MAXSIZ,
+ "(&(%s=%s)(%s=%s))", AT (objectClass), OC (nisNetgroup),
+ ATM (LM_NETGROUP, cn), "%s");
+ snprintf (_nss_ldap_filt_innetgr, LDAP_FILT_MAXSIZ,
+ "(&(%s=%s)(%s=%s))", AT (objectClass), OC (nisNetgroup), AT (memberNisNetgroup), "%s");
+
+}
+
+static void init_pwd_attributes (const char ***pwd_attrs);
+static void init_sp_attributes (const char ***sp_attrs);
+static void init_grp_attributes (const char ***grp_attrs);
+static void init_hosts_attributes (const char ***hosts_attrs);
+static void init_services_attributes (const char ***services_attrs);
+static void init_network_attributes (const char ***network_attrs);
+static void init_proto_attributes (const char ***proto_attrs);
+static void init_rpc_attributes (const char ***rpc_attrs);
+static void init_ethers_attributes (const char ***ethers_attrs);
+static void init_bp_attributes (const char ***bp_attrs);
+static void init_alias_attributes (const char ***alias_attrs);
+static void init_netgrp_attributes (const char ***netgrp_attrs);
+
+/**
+ * attribute table initialization routines
+ */
+void
+_nss_ldap_init_attributes (const char ***attrtab)
+{
+ init_pwd_attributes (&attrtab[LM_PASSWD]);
+ init_sp_attributes (&attrtab[LM_SHADOW]);
+ init_grp_attributes (&attrtab[LM_GROUP]);
+ init_hosts_attributes (&attrtab[LM_HOSTS]);
+ init_services_attributes (&attrtab[LM_SERVICES]);
+ init_network_attributes (&attrtab[LM_NETWORKS]);
+ init_proto_attributes (&attrtab[LM_PROTOCOLS]);
+ init_rpc_attributes (&attrtab[LM_RPC]);
+ init_ethers_attributes (&attrtab[LM_ETHERS]);
+ init_network_attributes (&attrtab[LM_NETMASKS]);
+ init_bp_attributes (&attrtab[LM_BOOTPARAMS]);
+ init_alias_attributes (&attrtab[LM_ALIASES]);
+ init_netgrp_attributes (&attrtab[LM_NETGROUP]);
+
+ attrtab[LM_NONE] = NULL;
+}
+
+static void
+init_pwd_attributes (const char ***pwd_attrs)
+{
+ int i = 0;
+ static const char *__pwd_attrs[ATTRTAB_SIZE + 1];
+
+ (*pwd_attrs) = __pwd_attrs;
+
+ (*pwd_attrs)[i++] = ATM (LM_PASSWD, uid);
+ (*pwd_attrs)[i++] = ATM (LM_PASSWD, userPassword);
+ (*pwd_attrs)[i++] = AT (uidNumber);
+ (*pwd_attrs)[i++] = ATM (LM_PASSWD, gidNumber);
+ (*pwd_attrs)[i++] = ATM (LM_PASSWD, cn);
+ (*pwd_attrs)[i++] = AT (homeDirectory);
+ (*pwd_attrs)[i++] = AT (loginShell);
+ (*pwd_attrs)[i++] = AT (gecos);
+ (*pwd_attrs)[i++] = ATM (LM_PASSWD, description);
+ (*pwd_attrs)[i++] = AT (objectClass);
+ (*pwd_attrs)[i] = NULL;
+}
+
+static void
+init_sp_attributes (const char ***sp_attrs)
+{
+ static const char *__sp_attrs[ATTRTAB_SIZE + 1];
+
+ (*sp_attrs) = __sp_attrs;
+
+ (*sp_attrs)[0] = (char *) ATM (LM_SHADOW, uid);
+ (*sp_attrs)[1] = (char *) ATM (LM_SHADOW, userPassword);
+ (*sp_attrs)[2] = (char *) AT (shadowLastChange);
+ (*sp_attrs)[3] = (char *) AT (shadowMax);
+ (*sp_attrs)[4] = (char *) AT (shadowMin);
+ (*sp_attrs)[5] = (char *) AT (shadowWarning);
+ (*sp_attrs)[6] = (char *) AT (shadowInactive);
+ (*sp_attrs)[7] = (char *) AT (shadowExpire);
+ (*sp_attrs)[8] = (char *) AT (shadowFlag);
+ (*sp_attrs)[9] = NULL;
+}
+
+static void
+init_grp_attributes (const char ***grp_attrs)
+{
+ int i = 0;
+ static const char *__grp_attrs[ATTRTAB_SIZE + 1];
+
+ (*grp_attrs) = __grp_attrs;
+
+ (*grp_attrs)[i++] = (char *) ATM (LM_GROUP, cn);
+ (*grp_attrs)[i++] = (char *) ATM (LM_GROUP, userPassword);
+ (*grp_attrs)[i++] = (char *) AT (memberUid);
+ if (_nss_ldap_test_config_flag (NSS_LDAP_FLAGS_RFC2307BIS))
+ (*grp_attrs)[i++] = (char *) AT (uniqueMember);
+ (*grp_attrs)[i++] = (char *) ATM (LM_GROUP, gidNumber);
+ (*grp_attrs)[i] = NULL;
+}
+
+static void
+init_hosts_attributes (const char ***hosts_attrs)
+{
+ static const char *__hosts_attrs[ATTRTAB_SIZE + 1];
+
+ (*hosts_attrs) = __hosts_attrs;
+
+ (*hosts_attrs)[0] = (char *) ATM (LM_HOSTS, cn);
+ (*hosts_attrs)[1] = (char *) AT (ipHostNumber);
+ (*hosts_attrs)[2] = NULL;
+}
+
+static void
+init_services_attributes (const char ***services_attrs)
+{
+ static const char *__services_attrs[ATTRTAB_SIZE + 1];
+
+ (*services_attrs) = __services_attrs;
+
+ (*services_attrs)[0] = ATM (LM_SERVICES, cn);
+ (*services_attrs)[1] = AT (ipServicePort);
+ (*services_attrs)[2] = AT (ipServiceProtocol);
+ (*services_attrs)[3] = NULL;
+}
+
+static void
+init_network_attributes (const char ***network_attrs)
+{
+ static const char *__network_attrs[ATTRTAB_SIZE + 1];
+
+ (*network_attrs) = __network_attrs;
+
+ (*network_attrs)[0] = ATM (LM_NETWORKS, cn);
+ (*network_attrs)[1] = AT (ipNetworkNumber);
+ (*network_attrs)[2] = AT (ipNetmaskNumber);
+ (*network_attrs)[3] = NULL;
+}
+
+static void
+init_proto_attributes (const char ***proto_attrs)
+{
+ static const char *__proto_attrs[ATTRTAB_SIZE + 1];
+
+ (*proto_attrs) = __proto_attrs;
+
+ (*proto_attrs)[0] = ATM (LM_PROTOCOLS, cn);
+ (*proto_attrs)[1] = AT (ipProtocolNumber);
+ (*proto_attrs)[2] = NULL;
+}
+
+static void
+init_rpc_attributes (const char ***rpc_attrs)
+{
+ static const char *__rpc_attrs[ATTRTAB_SIZE + 1];
+
+ (*rpc_attrs) = __rpc_attrs;
+
+ (*rpc_attrs)[0] = ATM (LM_RPC, cn);
+ (*rpc_attrs)[1] = AT (oncRpcNumber);
+ (*rpc_attrs)[2] = NULL;
+}
+
+static void
+init_ethers_attributes (const char ***ethers_attrs)
+{
+ static const char *__ethers_attrs[ATTRTAB_SIZE + 1];
+
+ (*ethers_attrs) = __ethers_attrs;
+
+ (*ethers_attrs)[0] = ATM (LM_ETHERS, cn);
+ (*ethers_attrs)[1] = AT (macAddress);
+ (*ethers_attrs)[2] = NULL;
+}
+
+static void
+init_bp_attributes (const char ***bp_attrs)
+{
+ static const char *__bp_attrs[ATTRTAB_SIZE + 1];
+
+ (*bp_attrs) = __bp_attrs;
+
+ (*bp_attrs)[0] = ATM (LM_BOOTPARAMS, cn);
+ (*bp_attrs)[1] = AT (bootParameter);
+ (*bp_attrs)[2] = NULL;
+}
+
+static void
+init_alias_attributes (const char ***alias_attrs)
+{
+ static const char *__alias_attrs[ATTRTAB_SIZE + 1];
+
+ (*alias_attrs) = __alias_attrs;
+
+ (*alias_attrs)[0] = ATM (LM_ALIASES, cn);
+ (*alias_attrs)[1] = AT (rfc822MailMember);
+ (*alias_attrs)[2] = NULL;
+}
+
+static void
+init_netgrp_attributes (const char ***netgrp_attrs)
+{
+ static const char *__netgrp_attrs[ATTRTAB_SIZE + 1];
+
+ (*netgrp_attrs) = __netgrp_attrs;
+
+ (*netgrp_attrs)[0] = ATM (LM_NETGROUP, cn);
+ (*netgrp_attrs)[1] = AT (nisNetgroupTriple);
+ (*netgrp_attrs)[2] = AT (memberNisNetgroup);
+ (*netgrp_attrs)[3] = NULL;
+}
diff --git a/nslcd/ldap-schema.h b/nslcd/ldap-schema.h
new file mode 100644
index 0000000..558c1aa
--- /dev/null
+++ b/nslcd/ldap-schema.h
@@ -0,0 +1,303 @@
+/*
+ ldap-schema.h - LDAP schema information functions and definitions
+ This file was part of the nss_ldap library which has been
+ forked into the nss-ldapd library.
+
+ Copyright (C) 1997-2005 Luke Howard
+ Copyright (C) 2006 West Consulting
+ Copyright (C) 2006 Arthur de Jong
+
+ This 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+#ifndef _LDAP_NSS_LDAP_LDAP_SCHEMA_H
+#define _LDAP_NSS_LDAP_LDAP_SCHEMA_H
+
+/**
+ * function to initialize global lookup filters.
+ */
+void _nss_ldap_init_filters(void);
+void _nss_ldap_init_attributes(const char ***attrtab);
+
+/**
+ * make filters formerly declared in ldap-*.h globally available.
+ */
+
+/* rfc822 mail aliases */
+extern char _nss_ldap_filt_getaliasbyname[];
+extern char _nss_ldap_filt_getaliasent[];
+
+/* boot parameters */
+extern char _nss_ldap_filt_getbootparamsbyname[];
+
+/* MAC address mappings */
+extern char _nss_ldap_filt_gethostton[];
+extern char _nss_ldap_filt_getntohost[];
+extern char _nss_ldap_filt_getetherent[];
+
+/* groups */
+extern char _nss_ldap_filt_getgrnam[];
+extern char _nss_ldap_filt_getgrgid[];
+extern char _nss_ldap_filt_getgrent[];
+extern char _nss_ldap_filt_getgroupsbymemberanddn[];
+extern char _nss_ldap_filt_getgroupsbydn[];
+extern char _nss_ldap_filt_getpwnam_groupsbymember[];
+extern char _nss_ldap_filt_getgroupsbymember[];
+
+/* IP hosts */
+extern char _nss_ldap_filt_gethostbyname[];
+extern char _nss_ldap_filt_gethostbyaddr[];
+extern char _nss_ldap_filt_gethostent[];
+
+/* IP networks */
+extern char _nss_ldap_filt_getnetbyname[];
+extern char _nss_ldap_filt_getnetbyaddr[];
+extern char _nss_ldap_filt_getnetent[];
+
+/* IP protocols */
+extern char _nss_ldap_filt_getprotobyname[];
+extern char _nss_ldap_filt_getprotobynumber[];
+extern char _nss_ldap_filt_getprotoent[];
+
+/* users */
+extern char _nss_ldap_filt_getpwnam[];
+extern char _nss_ldap_filt_getpwuid[];
+extern char _nss_ldap_filt_getpwent[];
+
+/* RPCs */
+extern char _nss_ldap_filt_getrpcbyname[];
+extern char _nss_ldap_filt_getrpcbynumber[];
+extern char _nss_ldap_filt_getrpcent[];
+
+/* IP services */
+extern char _nss_ldap_filt_getservbyname[];
+extern char _nss_ldap_filt_getservbynameproto[];
+extern char _nss_ldap_filt_getservbyport[];
+extern char _nss_ldap_filt_getservbyportproto[];
+extern char _nss_ldap_filt_getservent[];
+
+/* shadow users */
+extern char _nss_ldap_filt_getspnam[];
+extern char _nss_ldap_filt_getspent[];
+
+/* netgroups */
+extern char _nss_ldap_filt_getnetgrent[];
+extern char _nss_ldap_filt_innetgr[];
+
+/**
+ * Initialize attribute vector table indexed by map
+ * selector (eg. LM_PASSWD) relative to an "ldap_config"
+ */
+
+/**
+ * Lookup (potentially mapped)
+ * objectclass/attribute.
+ */
+#define OC(oc) _nss_ldap_map_oc(LM_NONE, OC##_##oc)
+#define OCM(map, at) _nss_ldap_map_oc(map, AT##_##at)
+#define AT(at) _nss_ldap_map_at(LM_NONE, AT##_##at)
+#define ATM(map, at) _nss_ldap_map_at(map, AT##_##at)
+#define DF(at) _nss_ldap_map_df(at)
+#define OV(at) _nss_ldap_map_ov(at)
+
+/**
+ * Common attributes, not from RFC 2307.
+ */
+#define AT_objectClass "objectClass"
+#define AT_cn "cn"
+#define AT_description "description"
+#define AT_l "l"
+#define AT_manager "manager"
+
+/**
+ * Vendor-specific attributes and object classes.
+ * (Mainly from Sun.)
+ */
+#define OC_nisMailAlias "nisMailAlias"
+#define AT_rfc822MailMember "rfc822MailMember"
+
+/**
+ * RFC 2307 attributes and object classes.
+ */
+
+/*
+ * ( nisSchema.2.0 NAME 'posixAccount' SUP top AUXILIARY
+ * DESC 'Abstraction of an account with POSIX attributes'
+ * MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory )
+ * MAY ( userPassword $ loginShell $ gecos $ description ) )
+ */
+#define OC_posixAccount "posixAccount"
+#define AT_uid "uid"
+#define AT_userPassword "userPassword"
+#define AT_uidNumber "uidNumber"
+#define AT_gidNumber "gidNumber"
+#define AT_loginShell "loginShell"
+#define AT_gecos "gecos"
+#define AT_homeDirectory "homeDirectory"
+
+/*
+ * ( nisSchema.2.1 NAME 'shadowAccount' SUP top AUXILIARY
+ * DESC 'Additional attributes for shadow passwords'
+ * MUST uid
+ * MAY ( userPassword $ shadowLastChange $ shadowMin
+ * shadowMax $ shadowWarning $ shadowInactive $
+ * shadowExpire $ shadowFlag $ description ) )
+ */
+#define OC_shadowAccount "shadowAccount"
+#define AT_shadowLastChange "shadowLastChange"
+#define AT_shadowMin "shadowMin"
+#define AT_shadowMax "shadowMax"
+#define AT_shadowWarning "shadowWarning"
+#define AT_shadowInactive "shadowInactive"
+#define AT_shadowExpire "shadowExpire"
+#define AT_shadowFlag "shadowFlag"
+
+/*
+ * ( nisSchema.2.2 NAME 'posixGroup' SUP top STRUCTURAL
+ * DESC 'Abstraction of a group of accounts'
+ * MUST ( cn $ gidNumber )
+ * MAY ( userPassword $ uidMember $ description ) )
+ */
+#define OC_posixGroup "posixGroup"
+#define AT_gidNumber "gidNumber"
+#define AT_memberUid "memberUid"
+#define AT_uniqueMember "uniqueMember"
+#define AT_memberOf "memberOf"
+
+/*
+ * ( nisSchema.2.3 NAME 'ipService' SUP top STRUCTURAL
+ * DESC 'Abstraction an Internet Protocol service.
+ * Maps an IP port and protocol (such as tcp or udp)
+ * to one or more names; the distinguished value of
+ * the cn attribute denotes the service's canonical
+ * name'
+ * MUST ( cn $ ipServicePort $ ipServiceProtocol )
+ * MAY ( description ) )
+ */
+#define OC_ipService "ipService"
+#define AT_ipServicePort "ipServicePort"
+#define AT_ipServiceProtocol "ipServiceProtocol"
+
+/*
+ * ( nisSchema.2.4 NAME 'ipProtocol' SUP top STRUCTURAL
+ * DESC 'Abstraction of an IP protocol. Maps a protocol number
+ * to one or more names. The distinguished value of the cn
+ * attribute denotes the protocol's canonical name'
+ * MUST ( cn $ ipProtocolNumber )
+ * MAY description )
+ */
+#define OC_ipProtocol "ipProtocol"
+#define AT_ipProtocolNumber "ipProtocolNumber"
+
+/*
+ * ( nisSchema.2.5 NAME 'oncRpc' SUP top STRUCTURAL
+ * DESC 'Abstraction of an Open Network Computing (ONC)
+ * [RFC1057] Remote Procedure Call (RPC) binding.
+ * This class maps an ONC RPC number to a name.
+ * The distinguished value of the cn attribute denotes
+ * the RPC service's canonical name'
+ * MUST ( cn $ oncRpcNumber )
+ * MAY description )
+ */
+#define OC_oncRpc "oncRpc"
+#define AT_oncRpcNumber "oncRpcNumber"
+
+/*
+ * ( nisSchema.2.6 NAME 'ipHost' SUP top AUXILIARY
+ * DESC 'Abstraction of a host, an IP device. The distinguished
+ * value of the cn attribute denotes the host's canonical
+ * name. Device SHOULD be used as a structural class'
+ * MUST ( cn $ ipHostNumber )
+ * MAY ( l $ description $ manager ) )
+ */
+#define OC_ipHost "ipHost"
+#define AT_ipHostNumber "ipHostNumber"
+
+/*
+ * ( nisSchema.2.7 NAME 'ipNetwork' SUP top STRUCTURAL
+ * DESC 'Abstraction of a network. The distinguished value of
+ * MUST ( cn $ ipNetworkNumber )
+ * MAY ( ipNetmaskNumber $ l $ description $ manager ) )
+ */
+#define OC_ipNetwork "ipNetwork"
+#define AT_ipNetworkNumber "ipNetworkNumber"
+#define AT_ipNetmaskNumber "ipNetmaskNumber"
+
+/*
+ * ( nisSchema.2.8 NAME 'nisNetgroup' SUP top STRUCTURAL
+ * DESC 'Abstraction of a netgroup. May refer to other netgroups'
+ * MUST cn
+ * MAY ( nisNetgroupTriple $ memberNisNetgroup $ description ) )
+ */
+#define OC_nisNetgroup "nisNetgroup"
+#define AT_nisNetgroupTriple "nisNetgroupTriple"
+#define AT_memberNisNetgroup "memberNisNetgroup"
+
+/*
+ * ( nisSchema.2.09 NAME 'nisMap' SUP top STRUCTURAL
+ * DESC 'A generic abstraction of a NIS map'
+ * MUST nisMapName
+ * MAY description )
+ */
+#define OC_nisMap "nisMap"
+#define AT_nisMapName "nisNapName"
+
+/*
+ * ( nisSchema.2.10 NAME 'nisObject' SUP top STRUCTURAL
+ * DESC 'An entry in a NIS map'
+ * MUST ( cn $ nisMapEntry $ nisMapName )
+ * MAY description )
+ */
+#define OC_nisObject "nisObject"
+#define AT_nisMapEntry "nisMapEntry"
+
+/*
+ * ( nisSchema.2.11 NAME 'ieee802Device' SUP top AUXILIARY
+ * DESC 'A device with a MAC address; device SHOULD be
+ * used as a structural class'
+ * MAY macAddress )
+ */
+#define OC_ieee802Device "ieee802Device"
+#define AT_macAddress "macAddress"
+
+/*
+ * ( nisSchema.2.12 NAME 'bootableDevice' SUP top AUXILIARY
+ * DESC 'A device with boot parameters; device SHOULD be
+ * used as a structural class'
+ * MAY ( bootFile $ bootParameter ) )
+ */
+#define OC_bootableDevice "bootableDevice"
+#define AT_bootFile "bootFile"
+#define AT_bootParameter "bootParameter"
+
+/*
+ * Map names
+ */
+#define MP_passwd "passwd"
+#define MP_shadow "shadow"
+#define MP_group "group"
+#define MP_hosts "hosts"
+#define MP_services "services"
+#define MP_networks "networks"
+#define MP_protocols "protocols"
+#define MP_rpc "rpc"
+#define MP_ethers "ethers"
+#define MP_netmasks "netmasks"
+#define MP_bootparams "bootparams"
+#define MP_aliases "aliases"
+#define MP_netgroup "netgroup"
+
+#endif /* _LDAP_NSS_LDAP_LDAP_SCHEMA_H */
diff --git a/nslcd/log.c b/nslcd/log.c
new file mode 100644
index 0000000..c7370cf
--- /dev/null
+++ b/nslcd/log.c
@@ -0,0 +1,187 @@
+/*
+ log.c - logging funtions
+
+ Copyright (C) 2002, 2003 Arthur de Jong
+
+ This 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+
+#include "config.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <string.h>
+
+#include "log.h"
+#include "xmalloc.h"
+
+
+/* set the logname */
+#undef PACKAGE
+#define PACKAGE "nslcd"
+
+
+/* storage for logging modes */
+static struct cvsd_log {
+ FILE *fp; /* NULL==syslog */
+ int loglevel;
+ struct cvsd_log *next;
+} *cvsd_loglist=NULL;
+
+
+/* default loglevel when no logging is configured */
+static int prelogging_loglevel=LOG_INFO;
+
+
+/* set loglevel when no logging is configured */
+void log_setdefaultloglevel(int loglevel)
+{
+ prelogging_loglevel=loglevel;
+}
+
+
+/* add logging method to configuration list */
+static void log_addlogging_fp(FILE *fp,int loglevel)
+{
+ struct cvsd_log *tmp,*lst;
+ /* create new logstruct */
+ tmp=(struct cvsd_log *)xmalloc(sizeof(struct cvsd_log));
+ tmp->fp=fp;
+ tmp->loglevel=loglevel;
+ tmp->next=NULL;
+ /* save the struct in the list */
+ if (cvsd_loglist==NULL)
+ cvsd_loglist=tmp;
+ else
+ {
+ for (lst=cvsd_loglist;lst->next!=NULL;lst=lst->next);
+ lst->next=tmp;
+ }
+}
+
+
+/* configure logging to a file */
+void log_addlogging_file(const char *filename,int loglevel)
+{
+ FILE *fp;
+ fp=fopen(filename,"a");
+ if (fp==NULL)
+ {
+ log_log(LOG_ERR,"cannot open logfile (%s) for appending: %s",filename,strerror(errno));
+ exit(1);
+ }
+ log_addlogging_fp(fp,loglevel);
+}
+
+
+/* configure logging to syslog */
+void log_addlogging_syslog(int loglevel)
+{
+ openlog(PACKAGE,LOG_PID,LOG_DAEMON);
+ log_addlogging_fp(NULL,loglevel);
+}
+
+
+/* configure a null logging mode (no logging) */
+void log_addlogging_none()
+{
+ /* this is a hack, but it's so easy */
+ log_addlogging_fp(NULL,LOG_EMERG);
+}
+
+
+/* start the logging with the configured logging methods
+ if no method is configured yet, logging is done to syslog */
+void log_startlogging(void)
+{
+ if (cvsd_loglist==NULL)
+ log_addlogging_syslog(LOG_INFO);
+ prelogging_loglevel=-1;
+}
+
+
+/* log the given message using the configured logging method */
+void log_log(int pri,const char *format, ...)
+{
+ int res;
+ struct cvsd_log *lst;
+ /* TODO: make this something better */
+ #define maxbufferlen 120
+ char buffer[maxbufferlen];
+ va_list ap;
+ /* make the message */
+ va_start(ap,format);
+ res=vsnprintf(buffer,maxbufferlen,format,ap);
+ if ((res<0)||(res>=maxbufferlen))
+ {
+ /* truncate with "..." */
+ buffer[maxbufferlen-2]='.';
+ buffer[maxbufferlen-3]='.';
+ buffer[maxbufferlen-4]='.';
+ }
+ buffer[maxbufferlen-1]='\0';
+ va_end(ap);
+ /* do the logging */
+ if (prelogging_loglevel>=0)
+ {
+ /* if logging is not yet defined, log to stderr */
+ if (pri<=prelogging_loglevel)
+ fprintf(stderr,"%s: %s%s\n",PACKAGE,pri==LOG_DEBUG?"DEBUG: ":"",buffer);
+ }
+ else
+ {
+ for (lst=cvsd_loglist;lst!=NULL;lst=lst->next)
+ {
+ if (pri<=lst->loglevel)
+ {
+ if (lst->fp==NULL) /* syslog */
+ syslog(pri,"%s",buffer);
+ else /* file */
+ {
+ fprintf(lst->fp,"%s: %s\n",PACKAGE,buffer);
+ fflush(lst->fp);
+ }
+ }
+ }
+ }
+}
+
+
+/* return the syslog loglevel represented by the string
+ return -1 on unknown */
+int log_getloglevel(const char *lvl)
+{
+ if ( strcmp(lvl,"crit")==0 )
+ return LOG_CRIT;
+ else if ( (strcmp(lvl,"error")==0) ||
+ (strcmp(lvl,"err")==0) )
+ return LOG_ERR;
+ else if ( strcmp(lvl,"warning")==0 )
+ return LOG_WARNING;
+ else if ( strcmp(lvl,"notice")==0 )
+ return LOG_NOTICE;
+ else if ( strcmp(lvl,"info")==0 )
+ return LOG_INFO;
+ else if ( strcmp(lvl,"debug")==0 )
+ return LOG_DEBUG;
+ else
+ return -1; /* unknown */
+}
diff --git a/nslcd/log.h b/nslcd/log.h
new file mode 100644
index 0000000..4124fbe
--- /dev/null
+++ b/nslcd/log.h
@@ -0,0 +1,60 @@
+/*
+ log.h - definitions of logging funtions
+
+ Copyright (C) 2002, 2003 Arthur de Jong
+
+ This 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+
+#ifndef _LOG_H
+#define _LOG_H 1
+
+
+#include <syslog.h>
+
+
+/* set loglevel when no logging is configured */
+void log_setdefaultloglevel(int loglevel);
+
+
+/* configure logging to a file */
+void log_addlogging_file(const char *filename,int loglevel);
+
+
+/* configure logging to syslog */
+void log_addlogging_syslog(int loglevel);
+
+
+/* configure a null logging mode (no logging) */
+void log_addlogging_none(void);
+
+
+/* start the logging with the configured logging methods
+ if no method is configured yet, logging is done to syslog */
+void log_startlogging(void);
+
+
+/* log the given message using the configured logging method */
+void log_log(int pri,const char *format, ...);
+
+
+/* return the syslog loglevel represented by the string
+ return -1 on unknown */
+int log_getloglevel(const char *lvl);
+
+
+#endif /* not _LOG_H */
diff --git a/nslcd/netgroup.c b/nslcd/netgroup.c
new file mode 100644
index 0000000..e79657d
--- /dev/null
+++ b/nslcd/netgroup.c
@@ -0,0 +1,354 @@
+/*
+ netgroup.c - netgroup lookup routines
+ This file was part of the nss_ldap library (as ldap-netgrp.c)
+ which has been forked into the nss-ldapd library.
+ This file also contains code that is taken from the GNU C
+ Library (nss/nss_files/files-netgrp.c).
+
+ Copyright (C) 1996, 1997, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997-2005 Luke Howard
+ Copyright (C) 2006 West Consulting
+ Copyright (C) 2006 Arthur de Jong
+
+ This 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+#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"
+#include "common.h"
+#include "log.h"
+
+/* 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;
+};
+
+/*
+ * I (Luke Howard) 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)
+
+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;
+}
+
+int nslcd_netgroup_byname(FILE *fp)
+{
+
+ int32_t tmpint32;
+ static struct ent_context *netgroup_context=NULL;
+ char *name;
+ /* these are here for now until we rewrite the LDAP code */
+ struct __netgrent result;
+ char buffer[1024];
+ int errnop;
+ struct ldap_args a;
+ enum nss_status stat=NSS_STATUS_SUCCESS;
+ /* read request parameters */
+ READ_STRING_ALLOC(fp,name);
+ /* log call */
+ log_log(LOG_DEBUG,"nslcd_netgroup_byname(%s)",name);
+ /* write the response header */
+ WRITE_INT32(fp,NSLCD_VERSION);
+ WRITE_INT32(fp,NSLCD_ACTION_NETGROUP_BYNAME);
+ /* initialize structure */
+ result.data=result.cursor=NULL;
+ result.data_size = 0;
+ /* do initial ldap request */
+ LA_INIT(a);
+ LA_STRING(a)=name;
+ LA_TYPE(a)=LA_TYPE_STRING;
+ stat=_nss_ldap_getbyname(&a,&result,buffer,1024,&errnop,_nss_ldap_filt_getnetgrent,LM_NETGROUP,_nss_ldap_load_netgr);
+ if (_nss_ldap_ent_context_init(&netgroup_context)==NULL)
+ return -1;
+ /* loop over all results */
+ while ((stat=_nss_ldap_parse_netgr(&result,buffer,1024))==NSS_STATUS_SUCCESS)
+ {
+ if (result.type==triple_val)
+ {
+ WRITE_INT32(fp,NSLCD_RESULT_SUCCESS);
+ WRITE_INT32(fp,NETGROUP_TYPE_TRIPLE);
+ if (result.val.triple.host==NULL)
+ { WRITE_STRING(fp,""); }
+ else
+ { WRITE_STRING(fp,result.val.triple.host); }
+ if (result.val.triple.user==NULL)
+ { WRITE_STRING(fp,""); }
+ else
+ { WRITE_STRING(fp,result.val.triple.user); }
+ if (result.val.triple.domain==NULL)
+ { WRITE_STRING(fp,""); }
+ else
+ { WRITE_STRING(fp,result.val.triple.domain); }
+ }
+ else if (result.type==group_val)
+ {
+ WRITE_INT32(fp,NSLCD_RESULT_SUCCESS);
+ WRITE_INT32(fp,NETGROUP_TYPE_NETGROUP);
+ WRITE_STRING(fp,result.val.group);
+ }
+ }
+ /* free data */
+ if (result.data!=NULL)
+ free(result.data);
+ /* we're done */
+ _nss_ldap_enter();
+ _nss_ldap_ent_context_release(netgroup_context);
+ _nss_ldap_leave();
+ return 0;
+}
+
diff --git a/nslcd/network.c b/nslcd/network.c
new file mode 100644
index 0000000..e44a3e1
--- /dev/null
+++ b/nslcd/network.c
@@ -0,0 +1,245 @@
+/*
+ network.c - network address entry lookup routines
+ This file was part of the nss_ldap library (as ldap-network.c)
+ which has been forked into the nss-ldapd library.
+
+ Copyright (C) 1997-2005 Luke Howard
+ Copyright (C) 2006 West Consulting
+ Copyright (C) 2006 Arthur de Jong
+
+ This 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+#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"
+#include "common.h"
+#include "log.h"
+
+#if defined(HAVE_USERSEC_H)
+#define MAXALIASES 35
+#define MAXADDRSIZE 4
+#endif /* HAVE_USERSEC_H */
+
+/* write a single network entry to the stream */
+static int write_netent(FILE *fp,struct netent *result)
+{
+ int32_t tmpint32,tmp2int32,tmp3int32;
+ /* write the network name */
+ WRITE_STRING(fp,result->n_name);
+ /* write the alias list */
+ WRITE_STRINGLIST_NULLTERM(fp,result->n_aliases);
+ /* write the number of addresses */
+ WRITE_INT32(fp,1);
+ /* write the addresses in network byte order */
+ WRITE_INT32(fp,result->n_addrtype);
+ WRITE_INT32(fp,sizeof(unsigned long int));
+ result->n_net=htonl(result->n_net);
+ WRITE_INT32(fp,result->n_net);
+ return 0;
+}
+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;
+}
+
+int nslcd_network_byname(FILE *fp)
+{
+ int32_t tmpint32;
+ char *name;
+ struct ldap_args a;
+ int retv;
+ struct netent result;
+ char buffer[1024];
+ int errnop;
+ /* read request parameters */
+ READ_STRING_ALLOC(fp,name);
+ /* log call */
+ log_log(LOG_DEBUG,"nslcd_network_byname(%s)",name);
+ /* write the response header */
+ /* FIXME: free(name) when one of these writes fails */
+ WRITE_INT32(fp,NSLCD_VERSION);
+ WRITE_INT32(fp,NSLCD_ACTION_NETWORK_BYNAME);
+ /* do the LDAP request */
+ LA_INIT(a);
+ LA_STRING(a)=name;
+ LA_TYPE(a)=LA_TYPE_STRING;
+ retv=nss2nslcd(_nss_ldap_getbyname(&a,&result,buffer,1024,&errnop,_nss_ldap_filt_getnetbyname,LM_NETWORKS,_nss_ldap_parse_net));
+ /* no more need for this string */
+ free(name);
+ /* write the response */
+ WRITE_INT32(fp,retv);
+ if (retv==NSLCD_RESULT_SUCCESS)
+ write_netent(fp,&result);
+ WRITE_FLUSH(fp);
+ /* we're done */
+ return 0;
+}
+
+int nslcd_network_byaddr(FILE *fp)
+{
+ int32_t tmpint32;
+ int af;
+ int len;
+ char addr[64],name[1024];
+ struct ldap_args a;
+ int retv=456;
+ struct netent result;
+ char buffer[1024];
+ int errnop;
+ /* read address family */
+ READ_INT32(fp,af);
+ if (af!=AF_INET)
+ {
+ log_log(LOG_WARNING,"incorrect address family specified: %d",af);
+ return -1;
+ }
+ /* read address length */
+ READ_INT32(fp,len);
+ if ((len>64)||(len<=0))
+ {
+ log_log(LOG_WARNING,"address length incorrect: %d",len);
+ return -1;
+ }
+ /* read address */
+ READ(fp,addr,len);
+ /* translate the address to a string */
+ if (inet_ntop(af,addr,name,1024)==NULL)
+ {
+ log_log(LOG_WARNING,"unable to convert address to string");
+ return -1;
+ }
+ /* log call */
+ log_log(LOG_DEBUG,"nslcd_network_byaddr(%s)",name);
+ /* write the response header */
+ WRITE_INT32(fp,NSLCD_VERSION);
+ WRITE_INT32(fp,NSLCD_ACTION_NETWORK_BYADDR);
+ /* prepare the LDAP request */
+ LA_INIT(a);
+ LA_STRING(a)=name;
+ LA_TYPE(a)=LA_TYPE_STRING;
+ /* do requests until we find a result */
+ /* TODO: probably do more sofisticated queries */
+ while (retv==456)
+ {
+ /* do the request */
+ retv=nss2nslcd(_nss_ldap_getbyname(&a,&result,buffer,1024,&errnop,_nss_ldap_filt_getnetbyaddr,LM_NETWORKS,_nss_ldap_parse_net));
+ /* if no entry was found, retry with .0 stripped from the end */
+ if ((retv==NSLCD_RESULT_NOTFOUND) &&
+ (strlen(name)>2) &&
+ (strncmp(name+strlen(name)-2,".0",2)==0))
+ {
+ /* strip .0 and try again */
+ name[strlen(name)-2]='\0';
+ retv=456;
+ }
+ }
+ /* write the response */
+ WRITE_INT32(fp,retv);
+ if (retv==NSLCD_RESULT_SUCCESS)
+ write_netent(fp,&result);
+ WRITE_FLUSH(fp);
+ /* we're done */
+ return 0;
+}
+
+int nslcd_network_all(FILE *fp)
+{
+ int32_t tmpint32;
+ static struct ent_context *net_context;
+ /* these are here for now until we rewrite the LDAP code */
+ struct netent result;
+ char buffer[1024];
+ int errnop;
+ int retv;
+ /* log call */
+ log_log(LOG_DEBUG,"nslcd_network_all()");
+ /* write the response header */
+ WRITE_INT32(fp,NSLCD_VERSION);
+ WRITE_INT32(fp,NSLCD_ACTION_NETWORK_ALL);
+ /* initialize context */
+ if (_nss_ldap_ent_context_init(&net_context)==NULL)
+ return -1;
+ /* loop over all results */
+ while ((retv=nss2nslcd(_nss_ldap_getent(&net_context,&result,buffer,1024,&errnop,_nss_ldap_filt_getnetent,LM_NETWORKS,_nss_ldap_parse_net)))==NSLCD_RESULT_SUCCESS)
+ {
+ /* write the result */
+ WRITE_INT32(fp,retv);
+ if (retv==NSLCD_RESULT_SUCCESS)
+ write_netent(fp,&result);
+ }
+ /* write the final result code */
+ WRITE_INT32(fp,retv);
+ WRITE_FLUSH(fp);
+ /* FIXME: if a previous call returns what happens to the context? */
+ _nss_ldap_enter();
+ _nss_ldap_ent_context_release(net_context);
+ _nss_ldap_leave();
+ /* we're done */
+ return 0;
+}
diff --git a/nslcd/nslcd.c b/nslcd/nslcd.c
new file mode 100644
index 0000000..48db1cf
--- /dev/null
+++ b/nslcd/nslcd.c
@@ -0,0 +1,656 @@
+/*
+ nslcd.c - ldap local connection daemon
+
+ Copyright (C) 2006 West Consulting
+ Copyright (C) 2006 Arthur de Jong
+
+ This 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/wait.h>
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif /* HAVE_GETOPT_H */
+#include <assert.h>
+#include <signal.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#ifdef HAVE_GRP_H
+#include <grp.h>
+#endif /* HAVE_GRP_H */
+#include <nss.h>
+#include <pthread.h>
+
+#include "nslcd.h"
+#include "log.h"
+#include "common.h"
+
+
+/* the definition of the environment */
+extern char **environ;
+
+
+/* flag to indictate if we are in debugging mode */
+static int nslcd_debugging=0;
+
+
+/* the exit flag to indicate that a signal was received */
+static volatile int nslcd_exitsignal=0;
+
+
+/* the server socket used for communication */
+static int nslcd_serversocket=-1;
+
+
+/* thread ids of all running threads */
+#define NUM_THREADS 5
+pthread_t nslcd_threads[NUM_THREADS];
+
+
+/* display version information */
+static void display_version(FILE *fp)
+{
+ fprintf(fp,"%s\n",PACKAGE_STRING);
+ fprintf(fp,"Written by Luke Howard and Arthur de Jong.\n\n");
+ fprintf(fp,"Copyright (C) 1997-2006 Luke Howard, Arthur de Jong and West Consulting\n"
+ "This is free software; see the source for copying conditions. There is NO\n"
+ "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
+}
+
+
+/* display usage information to stdout and exit(status) */
+static void display_usage(FILE *fp,const char *program_name)
+{
+ fprintf(fp,"Usage: %s [OPTION]...\n",program_name);
+ fprintf(fp,"Name Service LDAP connection daemon.\n");
+ fprintf(fp," -d, --debug don't fork and print debugging to stderr\n");
+ fprintf(fp," --help display this help and exit\n");
+ fprintf(fp," --version output version information and exit\n");
+ fprintf(fp,"\n"
+ "Report bugs to <%s>.\n",PACKAGE_BUGREPORT);
+}
+
+
+/* the definition of options for getopt(). see getopt(2) */
+static struct option const nslcd_options[] =
+{
+ { "debug", no_argument, NULL, 'd' },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'V' },
+ { NULL, 0, NULL, 0 }
+};
+#define NSLCD_OPTIONSTRING "dhV"
+
+
+/* parse command line options and save settings in struct */
+static void parse_cmdline(int argc,char *argv[])
+{
+ int optc;
+ while ((optc=getopt_long(argc,argv,NSLCD_OPTIONSTRING,nslcd_options,NULL))!=-1)
+ {
+ switch (optc)
+ {
+ case 'd': /* -d, --debug don't fork and print debugging to stderr */
+ nslcd_debugging=1;
+ log_setdefaultloglevel(LOG_DEBUG);
+ break;
+ case 'h': /* --help display this help and exit */
+ display_usage(stdout,argv[0]);
+ exit(0);
+ case 'V': /* --version output version information and exit */
+ display_version(stdout);
+ exit(0);
+ case ':': /* missing required parameter */
+ case '?': /* unknown option character or extraneous parameter */
+ default:
+ fprintf(stderr,"Try `%s --help' for more information.\n",
+ argv[0]);
+ exit(1);
+ }
+ }
+ /* check for remaining arguments */
+ if (optind<argc)
+ {
+ fprintf(stderr,"%s: unrecognized option `%s'\n",
+ argv[0],argv[optind]);
+ fprintf(stderr,"Try `%s --help' for more information.\n",
+ argv[0]);
+ exit(1);
+ }
+}
+
+
+/* get a name of a signal with a given signal number */
+static const char *signame(int signum)
+{
+ switch (signum)
+ {
+ case SIGHUP: return "SIGHUP"; /* Hangup detected */
+ case SIGINT: return "SIGINT"; /* Interrupt from keyboard */
+ case SIGQUIT: return "SIGQUIT"; /* Quit from keyboard */
+ case SIGILL: return "SIGILL"; /* Illegal Instruction */
+ case SIGABRT: return "SIGABRT"; /* Abort signal from abort(3) */
+ case SIGFPE: return "SIGFPE"; /* Floating point exception */
+ case SIGKILL: return "SIGKILL"; /* Kill signal */
+ case SIGSEGV: return "SIGSEGV"; /* Invalid memory reference */
+ case SIGPIPE: return "SIGPIPE"; /* Broken pipe */
+ case SIGALRM: return "SIGALRM"; /* Timer signal from alarm(2) */
+ case SIGTERM: return "SIGTERM"; /* Termination signal */
+ case SIGUSR1: return "SIGUSR1"; /* User-defined signal 1 */
+ case SIGUSR2: return "SIGUSR2"; /* User-defined signal 2 */
+ case SIGCHLD: return "SIGCHLD"; /* Child stopped or terminated */
+ case SIGCONT: return "SIGCONT"; /* Continue if stopped */
+ case SIGSTOP: return "SIGSTOP"; /* Stop process */
+ case SIGTSTP: return "SIGTSTP"; /* Stop typed at tty */
+ case SIGTTIN: return "SIGTTIN"; /* tty input for background process */
+ case SIGTTOU: return "SIGTTOU"; /* tty output for background process */
+#ifdef SIGBUS
+ case SIGBUS: return "SIGBUS"; /* Bus error */
+#endif
+#ifdef SIGPOLL
+ case SIGPOLL: return "SIGPOLL"; /* Pollable event */
+#endif
+#ifdef SIGPROF
+ case SIGPROF: return "SIGPROF"; /* Profiling timer expired */
+#endif
+#ifdef SIGSYS
+ case SIGSYS: return "SIGSYS"; /* Bad argument to routine */
+#endif
+#ifdef SIGTRAP
+ case SIGTRAP: return "SIGTRAP"; /* Trace/breakpoint trap */
+#endif
+#ifdef SIGURG
+ case SIGURG: return "SIGURG"; /* Urgent condition on socket */
+#endif
+#ifdef SIGVTALRM
+ case SIGVTALRM: return "SIGVTALRM"; /* Virtual alarm clock */
+#endif
+#ifdef SIGXCPU
+ case SIGXCPU: return "SIGXCPU"; /* CPU time limit exceeded */
+#endif
+#ifdef SIGXFSZ
+ case SIGXFSZ: return "SIGXFSZ"; /* File size limit exceeded */
+#endif
+ default: return "UNKNOWN";
+ }
+}
+
+
+/* signal handler for closing down */
+static RETSIGTYPE sigexit_handler(int signum)
+{
+ int i;
+ nslcd_exitsignal=signum;
+ /* cancel all running threads */
+ for (i=0;i<NUM_THREADS;i++)
+ pthread_cancel(nslcd_threads[i]);
+
+}
+
+
+/* do some cleaning up before terminating */
+static void exithandler(void)
+{
+ /* close socket if it's still in use */
+ if (nslcd_serversocket >= 0)
+ {
+ if (close(nslcd_serversocket))
+ log_log(LOG_WARNING,"problem closing server socket (ignored): %s",strerror(errno));
+ }
+ /* remove existing named socket */
+ if (unlink(NSLCD_SOCKET)<0)
+ {
+ log_log(LOG_DEBUG,"unlink() of "NSLCD_SOCKET" failed (ignored): %s",
+ strerror(errno));
+ }
+ /* remove pidfile */
+ if (unlink(NSLCD_PIDFILE)<0)
+ {
+ log_log(LOG_DEBUG,"unlink() of "NSLCD_PIDFILE" failed (ignored): %s",
+ strerror(errno));
+ }
+ /* log exit */
+ log_log(LOG_INFO,"version %s bailing out",VERSION);
+}
+
+
+/* returns a socket ready to answer requests from the client,
+ exit()s on error */
+static int open_socket(void)
+{
+ int sock;
+ struct sockaddr_un addr;
+
+ /* create a socket */
+ if ( (sock=socket(PF_UNIX,SOCK_STREAM,0))<0 )
+ {
+ log_log(LOG_ERR,"cannot create socket: %s",strerror(errno));
+ exit(1);
+ }
+
+ /* remove existing named socket */
+ if (unlink(NSLCD_SOCKET)<0)
+ {
+ log_log(LOG_DEBUG,"unlink() of "NSLCD_SOCKET" failed (ignored): %s",
+ strerror(errno));
+ }
+
+ /* create socket address structure */
+ memset(&addr,0,sizeof(struct sockaddr_un));
+ addr.sun_family=AF_UNIX;
+ strcpy(addr.sun_path,NSLCD_SOCKET);
+
+ /* bind to the named socket */
+ if (bind(sock,(struct sockaddr *)&addr,sizeof(struct sockaddr_un)))
+ {
+ log_log(LOG_ERR,"bind() to "NSLCD_SOCKET" failed: %s",
+ strerror(errno));
+ if (close(sock))
+ log_log(LOG_WARNING,"problem closing socket: %s",strerror(errno));
+ exit(1);
+ }
+
+ /* close the file descriptor on exit */
+ if (fcntl(sock,F_SETFD,FD_CLOEXEC)<0)
+ {
+ log_log(LOG_ERR,"fctnl(F_SETFL,O_NONBLOCK) failed: %s",strerror(errno));
+ if (close(sock))
+ log_log(LOG_WARNING,"problem closing socket: %s",strerror(errno));
+ exit(1);
+ }
+
+ /* set permissions of socket so anybody can do requests */
+ if (chmod(NSLCD_SOCKET,0666))
+ {
+ log_log(LOG_ERR,"fctnl(F_SETFL,O_NONBLOCK) failed: %s",strerror(errno));
+ if (close(sock))
+ log_log(LOG_WARNING,"problem closing socket: %s",strerror(errno));
+ exit(1);
+ }
+
+ /* start listening for connections */
+ if (listen(sock,SOMAXCONN)<0)
+ {
+ log_log(LOG_ERR,"listen() failed: %s",strerror(errno));
+ if (close(sock))
+ log_log(LOG_WARNING,"problem closing socket: %s",strerror(errno));
+ exit(1);
+ }
+
+ /* we're done */
+ return sock;
+}
+
+/* read the version information and action from the stream
+ this function returns the read action in location pointer to by action */
+static int read_header(FILE *fp,int32_t *action)
+{
+ int32_t tmpint32;
+ /* read the protocol version */
+ READ_TYPE(fp,tmpint32,int32_t);
+ if (tmpint32 != NSLCD_VERSION)
+ {
+ log_log(LOG_DEBUG,"wrong nslcd version id (%d)",(int)tmpint32);
+ return -1;
+ }
+ /* read the request type */
+ READ(fp,action,sizeof(int32_t));
+ return 0;
+}
+
+/* read a request message, returns <0 in case of errors,
+ this function closes the socket */
+static void handleconnection(int sock)
+{
+ FILE *fp;
+ socklen_t alen;
+ struct ucred client;
+ int32_t action;
+
+ /* look up process information from client */
+ alen=sizeof(struct ucred);
+ if (getsockopt(sock,SOL_SOCKET,SO_PEERCRED,&client,&alen) < 0)
+ {
+ log_log(LOG_ERR,"getsockopt(SO_PEERCRED) failed: %s",strerror(errno));
+ if (close(sock))
+ log_log(LOG_WARNING,"problem closing socket: %s",strerror(errno));
+ return;
+ }
+
+ /* log connection */
+ log_log(LOG_DEBUG,"connection from pid=%d uid=%d gid=%d",
+ (int)client.pid,(int)client.uid,(int)client.gid);
+
+ /* create a stream object */
+ if ((fp=fdopen(sock,"w+"))==NULL)
+ {
+ log_log(LOG_WARNING,"cannot create stream for writing: %s",strerror(errno));
+ close(sock);
+ return;
+ }
+
+ /* read request */
+ if (read_header(fp,&action))
+ {
+ fclose(fp);
+ return;
+ }
+
+ /* handle request */
+ switch (action)
+ {
+ case NSLCD_ACTION_ALIAS_BYNAME: nslcd_alias_byname(fp); break;
+ case NSLCD_ACTION_ALIAS_ALL: nslcd_alias_all(fp); break;
+ case NSLCD_ACTION_ETHER_BYNAME: nslcd_ether_byname(fp); break;
+ case NSLCD_ACTION_ETHER_BYETHER: nslcd_ether_byether(fp); break;
+ case NSLCD_ACTION_ETHER_ALL: nslcd_ether_all(fp); break;
+ case NSLCD_ACTION_GROUP_BYNAME: nslcd_group_byname(fp); break;
+ case NSLCD_ACTION_GROUP_BYGID: nslcd_group_bygid(fp); break;
+ case NSLCD_ACTION_GROUP_BYMEMBER: nslcd_group_bymember(fp); break;
+ case NSLCD_ACTION_GROUP_ALL: nslcd_group_all(fp); break;
+ case NSLCD_ACTION_HOST_BYNAME: nslcd_host_byname(fp); break;
+ case NSLCD_ACTION_HOST_BYADDR: nslcd_host_byaddr(fp); break;
+ case NSLCD_ACTION_HOST_ALL: nslcd_host_all(fp); break;
+ case NSLCD_ACTION_NETGROUP_BYNAME: nslcd_netgroup_byname(fp); break;
+ case NSLCD_ACTION_NETWORK_BYNAME: nslcd_network_byname(fp); break;
+ case NSLCD_ACTION_NETWORK_BYADDR: nslcd_network_byaddr(fp); break;
+ case NSLCD_ACTION_NETWORK_ALL: nslcd_network_all(fp); break;
+ case NSLCD_ACTION_PASSWD_BYNAME: nslcd_passwd_byname(fp); break;
+ case NSLCD_ACTION_PASSWD_BYUID: nslcd_passwd_byuid(fp); break;
+ case NSLCD_ACTION_PASSWD_ALL: nslcd_passwd_all(fp); break;
+ case NSLCD_ACTION_PROTOCOL_BYNAME: nslcd_protocol_byname(fp); break;
+ case NSLCD_ACTION_PROTOCOL_BYNUMBER:nslcd_protocol_bynumber(fp); break;
+ case NSLCD_ACTION_PROTOCOL_ALL: nslcd_protocol_all(fp); break;
+ case NSLCD_ACTION_RPC_BYNAME: nslcd_rpc_byname(fp); break;
+ case NSLCD_ACTION_RPC_BYNUMBER: nslcd_rpc_bynumber(fp); break;
+ case NSLCD_ACTION_RPC_ALL: nslcd_rpc_all(fp); break;
+ case NSLCD_ACTION_SERVICE_BYNAME: nslcd_service_byname(fp); break;
+ case NSLCD_ACTION_SERVICE_BYNUMBER: nslcd_service_bynumber(fp); break;
+ case NSLCD_ACTION_SERVICE_ALL: nslcd_service_all(fp); break;
+ case NSLCD_ACTION_SHADOW_BYNAME: nslcd_shadow_byname(fp); break;
+ case NSLCD_ACTION_SHADOW_ALL: nslcd_shadow_all(fp); break;
+ default:
+ log_log(LOG_WARNING,"invalid request id: %d",(int)action);
+ break;
+ }
+
+ /* we're done with the request */
+ fclose(fp);
+ return;
+}
+
+/* accept a connection on the socket */
+static void acceptconnection(void)
+{
+ int csock;
+ int j;
+ struct sockaddr_storage addr;
+ socklen_t alen;
+
+ /* accept a new connection */
+ alen=(socklen_t)sizeof(struct sockaddr_storage);
+ csock=accept(nslcd_serversocket,(struct sockaddr *)&addr,&alen);
+ if (csock<0)
+ {
+ if ((errno==EINTR)||(errno==EAGAIN)||(errno==EWOULDBLOCK))
+ {
+ log_log(LOG_DEBUG,"debug: accept() failed (ignored): %s",strerror(errno));
+ return;
+ }
+ log_log(LOG_ERR,"accept() failed: %s",strerror(errno));
+ return;
+ }
+
+ /* make sure O_NONBLOCK is not inherited */
+ if ((j=fcntl(csock,F_GETFL,0))<0)
+ {
+ log_log(LOG_ERR,"fctnl(F_GETFL) failed: %s",strerror(errno));
+ if (close(csock))
+ log_log(LOG_WARNING,"problem closing socket: %s",strerror(errno));
+ return;
+ }
+ if (fcntl(csock,F_SETFL,j&~O_NONBLOCK)<0)
+ {
+ log_log(LOG_ERR,"fctnl(F_SETFL,~O_NONBLOCK) failed: %s",strerror(errno));
+ if (close(csock))
+ log_log(LOG_WARNING,"problem closing socket: %s",strerror(errno));
+ return;
+ }
+
+ /* handle the connection */
+ handleconnection(csock);
+}
+
+
+/* write the current process id to the specified file */
+static void write_pidfile(const char *filename)
+{
+ FILE *fp;
+ if (filename!=NULL)
+ {
+ if ((fp=fopen(filename,"w"))==NULL)
+ {
+ log_log(LOG_ERR,"cannot open pid file (%s): %s",filename,strerror(errno));
+ exit(1);
+ }
+ if (fprintf(fp,"%d\n",(int)getpid())<=0)
+ {
+ log_log(LOG_ERR,"error writing pid file (%s)",filename);
+ exit(1);
+ }
+ if (fclose(fp))
+ {
+ log_log(LOG_ERR,"error writing pid file (%s): %s",filename,strerror(errno));
+ exit(1);
+ }
+ }
+}
+
+
+/* try to install signal handler and check result */
+static void install_sighandler(int signum,RETSIGTYPE (*handler) (int))
+{
+ struct sigaction act;
+ memset(&act,0,sizeof(struct sigaction));
+ act.sa_handler=handler;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags=SA_RESTART|SA_NOCLDSTOP;
+ if (sigaction(signum,&act,NULL)!=0)
+ {
+ log_log(LOG_ERR,"error installing signal handler for '%s': %s",signame(signum),strerror(errno));
+ exit(1);
+ }
+}
+
+static void *worker(void *arg)
+{
+ /* start waiting for incoming connections */
+ while (nslcd_exitsignal==0)
+ {
+ /* wait for a new connection */
+ acceptconnection();
+ }
+ return NULL;
+}
+
+
+/* the main program... */
+int main(int argc,char *argv[])
+{
+ gid_t mygid=-1;
+ uid_t myuid=-1;
+ int i;
+
+ /* parse the command line */
+ parse_cmdline(argc,argv);
+
+ /* clear the environment */
+ /* TODO:implement */
+
+ /* check if we are already running */
+ /* FIXME: implement (maybe pass along options or commands) */
+
+ /* disable ldap lookups of host names to avoid lookup loop
+ and fall back to files dns (a sensible default) */
+ /* TODO: parse /etc/nsswitch ourselves and just remove ldap from the list */
+ if (__nss_configure_lookup("hosts","files dns"))
+ log_log(LOG_ERR,"unable to override hosts lookup method: %s",strerror(errno));
+
+ /* daemonize */
+ if ((!nslcd_debugging)&&(daemon(0,0)<0))
+ {
+ log_log(LOG_ERR,"unable to daemonize: %s",strerror(errno));
+ exit(1);
+ }
+
+ /* set default mode for pidfile and socket */
+ umask(0022);
+
+ /* intilialize logging */
+ if (!nslcd_debugging)
+ log_startlogging();
+ log_log(LOG_INFO,"version %s starting",VERSION);
+
+ /* install handler to close stuff off on exit and log notice */
+ atexit(exithandler);
+
+ /* write pidfile */
+ write_pidfile(NSLCD_PIDFILE);
+
+ /* create socket */
+ nslcd_serversocket=open_socket();
+
+#ifdef HAVE_SETGROUPS
+ /* drop all supplemental groups */
+ if (setgroups(0,NULL)<0)
+ {
+ log_log(LOG_WARNING,"cannot setgroups(0,NULL) (ignored): %s",strerror(errno));
+ }
+ else
+ {
+ log_log(LOG_DEBUG,"debug: setgroups(0,NULL) done");
+ }
+#else /* HAVE_SETGROUPS */
+ log_log(LOG_DEBUG,"debug: setgroups() not available");
+#endif /* not HAVE_SETGROUPS */
+
+#ifdef USE_CAPABILITIES
+ /* if we are using capbilities, set them to be kept
+ across setuid() calls so we can limit them later on */
+ if (prctl(PR_SET_KEEPCAPS,1))
+ {
+ log_log(LOG_ERR,"cannot prctl(PR_SET_KEEPCAPS,1): %s",strerror(errno));
+ exit(1);
+ }
+ log_log(LOG_DEBUG,"debug: prctl(PR_SET_KEEPCAPS,1) done");
+ /* dump the current capabilities */
+ caps=cap_get_proc();
+ log_log(LOG_DEBUG,"debug: current capabilities: %s",cap_to_text(caps,NULL));
+ cap_free(caps);
+#endif /* USE_CAPABILITIES */
+
+ /* change to nslcd gid */
+ if (mygid!=((gid_t)-1))
+ {
+ if (setgid(mygid)!=0)
+ {
+ log_log(LOG_ERR,"cannot setgid(%d): %s",(int)mygid,strerror(errno));
+ exit(1);
+ }
+ log_log(LOG_DEBUG,"debug: setgid(%d) done",mygid);
+ }
+
+ /* change to nslcd uid */
+ if (myuid!=((uid_t)-1))
+ {
+ if (setuid(myuid)!=0)
+ {
+ log_log(LOG_ERR,"cannot setuid(%d): %s",(int)myuid,strerror(errno));
+ exit(1);
+ }
+ log_log(LOG_DEBUG,"debug: setuid(%d) done",myuid);
+ }
+
+#ifdef USE_CAPABILITIES
+ /* limit the capabilities */
+ if (cap_set_proc(mycapabilities)!=0)
+ {
+ log_log(LOG_ERR,"cannot cap_set_proc(%s): %s",cap_to_text(mycapabilities,NULL),strerror(errno));
+ exit(1);
+ }
+ log_log(LOG_DEBUG,"debug: cap_set_proc(%2) done",cap_to_text(mycapabilities,NULL));
+ /* we no longer need this so we should free it */
+ cap_free(mycapabilities);
+ /* dump the current capabilities */
+ caps=cap_get_proc();
+ log_log(LOG_DEBUG,"debug: current capabilities: %s",cap_to_text(caps,NULL));
+ cap_free(caps);
+#endif /* USE_CAPABILITIES */
+
+ /* install signalhandlers for some signals */
+ install_sighandler(SIGHUP, sigexit_handler);
+ install_sighandler(SIGINT, sigexit_handler);
+ install_sighandler(SIGQUIT,sigexit_handler);
+ install_sighandler(SIGABRT,sigexit_handler);
+ install_sighandler(SIGPIPE,SIG_IGN);
+ install_sighandler(SIGTERM,sigexit_handler);
+ install_sighandler(SIGUSR1,sigexit_handler);
+ install_sighandler(SIGUSR2,sigexit_handler);
+ /* TODO: install signal handlers for reloading configuration */
+
+ log_log(LOG_INFO,"accepting connections");
+
+ /* start worker threads */
+ for (i=0;i<NUM_THREADS;i++)
+ {
+ if (pthread_create(&nslcd_threads[i],NULL,worker,NULL))
+ {
+ log_log(LOG_ERR,"unable to start worker thread %d: %s",i,strerror(errno));
+ exit(1);
+ }
+ }
+
+ /* wait for all threads to die */
+ for (i=0;i<NUM_THREADS;i++)
+ {
+ if (pthread_join(nslcd_threads[i],NULL))
+ {
+ log_log(LOG_ERR,"unable to wait for worker thread %d: %s",i,strerror(errno));
+ exit(1);
+ }
+ }
+
+ /* print something about received signals */
+ if (nslcd_exitsignal!=0)
+ {
+ log_log(LOG_INFO,"caught signal %s (%d), shutting down",
+ signame(nslcd_exitsignal),nslcd_exitsignal);
+ }
+
+ return 1;
+}
diff --git a/nslcd/pagectrl.c b/nslcd/pagectrl.c
new file mode 100644
index 0000000..ca439dd
--- /dev/null
+++ b/nslcd/pagectrl.c
@@ -0,0 +1,224 @@
+/*
+ pagectrl.c - provide a replacement ldap_create_page_control() function.
+ This file was part of the nss_ldap library which has been
+ forked into the nss-ldapd library.
+
+ Copyright (C) 2002 Max Caines
+ This software is not subject to any license of the University
+ of Wolverhampton.
+
+ This 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+/* TODO: move this to compat/ and add it only when needed */
+/* Note: this is only used in ldap-nss.c */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <lber.h>
+#include <ldap.h>
+
+#include "pagectrl.h"
+
+#ifndef LDAP_CONTROL_PAGE_OID
+#define LDAP_CONTROL_PAGE_OID "1.2.840.113556.1.4.319"
+#endif
+
+#ifndef HAVE_LDAP_CREATE_CONTROL
+#error LDAP client library does not support ldap_create_control()
+#endif
+
+#ifndef HAVE_LDAP_CREATE_PAGE_CONTROL
+/*---
+ ldap_create_page_control
+
+ Create and encode the Paged Results control.
+
+ ld (IN) An LDAP session handle, as obtained from a call to
+ ldap_init().
+
+ pagesize (IN) The number of entries to return in each page
+
+ cookiep (IN) Pointer to a berVal structure that the server uses to
+ determine the current location in the
+ result set (opaque). Set to NULL the
+ first time.
+
+ iscritical (IN) Is this control critical to the search?
+
+ ctrlp (OUT) A result parameter that will be assigned the address
+ of an LDAPControl structure that contains the
+ PagedResult control created by this function.
+ The memory occupied by the LDAPControl structure
+ SHOULD be freed when it is no longer in use by
+ calling ldap_control_free().
+
+
+ Ber encoding
+
+ PageResult ::= SEQUENCE {
+ pageSize INTEGER
+ cookie OCTET STRING }
+
+
+ Note: The first time the Page control is created, the cookie
+ should be set to a zero-length string. The cookie obtained
+ from calling ldap_parse_page_control() should be used as
+ the cookie in the next ldap_create_page_control call.
+
+ ---*/
+
+int
+ldap_create_page_control (LDAP * ld,
+ unsigned long pagesize,
+ struct berval *cookiep,
+ int iscritical, LDAPControl ** ctrlp)
+{
+ ber_tag_t tag;
+ BerElement *ber;
+ BerElement *ldap_alloc_ber_with_options (LDAP * ld);
+ int rc;
+
+ if ((ld == NULL) || (ctrlp == NULL))
+ {
+ return (LDAP_PARAM_ERROR);
+ }
+
+ if ((ber = ldap_alloc_ber_with_options (ld)) == NULL)
+ {
+ return (LDAP_NO_MEMORY);
+ }
+
+ tag = ber_printf (ber, "{i", pagesize);
+ if (tag == LBER_ERROR)
+ goto exit;
+
+ if (cookiep == NULL)
+ tag = ber_printf (ber, "o", "", 0);
+ else
+ tag = ber_printf (ber, "O", cookiep);
+ if (tag == LBER_ERROR)
+ goto exit;
+
+ tag = ber_printf (ber, /*{ */ "N}");
+ if (tag == LBER_ERROR)
+ goto exit;
+
+ rc = ldap_create_control (LDAP_CONTROL_PAGE_OID, ber, iscritical, ctrlp);
+
+ ber_free (ber, 1);
+ return (rc);
+
+exit:
+ ber_free (ber, 1);
+ return (LDAP_ENCODING_ERROR);
+}
+#endif /* HAVE_LDAP_CREATE_PAGE_CONTROL */
+
+#ifndef HAVE_LDAP_PARSE_PAGE_CONTROL
+/*---
+ ldap_parse_page_control
+
+ Decode the Virtual List View control return information.
+
+ ld (IN) An LDAP session handle.
+
+ ctrls (IN) The address of a NULL-terminated array of
+ LDAPControl structures, typically obtained
+ by a call to ldap_parse_result().
+
+ list_countp (OUT) This result parameter is filled in with the number
+ of entries returned in this page
+
+ cookiep (OUT) This result parameter is filled in with the address
+ of a struct berval that contains the server-
+ generated cookie.
+ The returned cookie SHOULD be used in the next call
+ to create a Page sort control. The struct berval
+ returned SHOULD be disposed of by calling ber_bvfree()
+ when it is no longer needed.
+
+---*/
+int
+ldap_parse_page_control (LDAP * ld,
+ LDAPControl ** ctrls,
+ unsigned long *list_countp, struct berval **cookiep)
+{
+ BerElement *ber;
+ LDAPControl *pControl;
+ int i;
+ unsigned long count;
+ ber_tag_t tag;
+
+ if (cookiep)
+ {
+ *cookiep = NULL; /* Make sure we return a NULL if error occurs. */
+ }
+
+ if (ld == NULL)
+ {
+ return (LDAP_PARAM_ERROR);
+ }
+
+ if (ctrls == NULL)
+ {
+ return (LDAP_CONTROL_NOT_FOUND);
+ }
+
+ /* Search the list of control responses for a Page control. */
+ for (i = 0; ctrls[i]; i++)
+ {
+ pControl = ctrls[i];
+ if (!strcmp (LDAP_CONTROL_PAGE_OID, pControl->ldctl_oid))
+ goto foundPageControl;
+ }
+
+ /* No page control was found. */
+ return (LDAP_CONTROL_NOT_FOUND);
+
+foundPageControl:
+ /* Create a BerElement from the berval returned in the control. */
+ ber = ber_init (&pControl->ldctl_value);
+
+ if (ber == NULL)
+ {
+ return (LDAP_NO_MEMORY);
+ }
+
+ /* Extract the data returned in the control. */
+ tag = ber_scanf (ber, "{iO" /*} */ , &count, cookiep);
+
+ if (tag == LBER_ERROR)
+ {
+ ber_free (ber, 1);
+ return (LDAP_DECODING_ERROR);
+ }
+
+ ber_free (ber, 1);
+
+ /* Return data to the caller for items that were requested. */
+ if (list_countp)
+ {
+ *list_countp = count;
+ }
+
+ return (LDAP_SUCCESS);
+}
+#endif /* HAVE_LDAP_PARSE_PAGE_CONTROL */
diff --git a/nslcd/pagectrl.h b/nslcd/pagectrl.h
new file mode 100644
index 0000000..c678ca9
--- /dev/null
+++ b/nslcd/pagectrl.h
@@ -0,0 +1,45 @@
+/*
+ pagectrl.h - provide a replacement ldap_create_page_control() function.
+ This file was part of the nss_ldap library which has been
+ forked into the nss-ldapd library.
+
+ Copyright (C) 1997-2005 Luke Howard
+
+ This 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+#ifndef _LDAP_NSS_LDAP_PAGECTRL_H
+#define _LDAP_NSS_LDAP_PAGECTRL_H
+
+#ifndef HAVE_LDAP_CREATE_PAGE_CONTROL
+int
+ldap_create_page_control( LDAP *ld,
+ unsigned long pagesize,
+ struct berval *cookiep,
+ int iscritical,
+ LDAPControl **ctrlp );
+#endif /* HAVE_LDAP_CREATE_PAGE_CONTROL */
+
+#ifndef HAVE_LDAP_PARSE_PAGE_CONTROL
+int
+ldap_parse_page_control(
+ LDAP *ld,
+ LDAPControl **ctrls,
+ unsigned long *list_countp,
+ struct berval **cookiep );
+#endif /* HAVE_LDAP_PARSE_PAGE_CONTROL */
+
+#endif /* _LDAP_NSS_LDAP_UTIL_H */
diff --git a/nslcd/passwd.c b/nslcd/passwd.c
new file mode 100644
index 0000000..abdb104
--- /dev/null
+++ b/nslcd/passwd.c
@@ -0,0 +1,273 @@
+/*
+ passwd.c - password entry lookup routines
+ This file was part of the nss_ldap library (as ldap-pwd.c)
+ which has been forked into the nss-ldapd library.
+
+ Copyright (C) 1997-2005 Luke Howard
+ Copyright (C) 2006 West Consulting
+ Copyright (C) 2006 Arthur de Jong
+
+ This 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 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 <stdio.h>
+
+#include "ldap-nss.h"
+#include "util.h"
+#include "common.h"
+#include "log.h"
+
+#ifndef UID_NOBODY
+#define UID_NOBODY (-2)
+#endif
+
+#ifndef GID_NOBODY
+#define GID_NOBODY UID_NOBODY
+#endif
+
+
+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;
+}
+
+static 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);
+
+ return NSS_STATUS_SUCCESS;
+}
+
+/* macros for expanding the NSLCD_PASSWD macro */
+#define NSLCD_STRING(field) WRITE_STRING(fp,field)
+#define NSLCD_TYPE(field,type) WRITE_TYPE(fp,field,type)
+#define PASSWD_NAME result.pw_name
+#define PASSWD_PASSWD result.pw_passwd
+#define PASSWD_UID result.pw_uid
+#define PASSWD_GID result.pw_gid
+#define PASSWD_GECOS result.pw_gecos
+#define PASSWD_DIR result.pw_dir
+#define PASSWD_SHELL result.pw_shell
+
+/* the caller should take care of opening and closing the stream */
+int nslcd_passwd_byname(FILE *fp)
+{
+ int32_t tmpint32;
+ char *name;
+ /* these are here for now until we rewrite the LDAP code */
+ struct passwd result;
+ char buffer[1024];
+ int errnop;
+ int retv;
+ struct ldap_args a;
+ /* read request parameters */
+ READ_STRING_ALLOC(fp,name);
+ /* FIXME: free() this buffer somewhere */
+ /* log call */
+ log_log(LOG_DEBUG,"nslcd_passwd_byname(%s)",name);
+ /* do the LDAP request */
+ LA_INIT(a);
+ LA_STRING(a)=name;
+ LA_TYPE(a)=LA_TYPE_STRING;
+ retv=nss2nslcd(_nss_ldap_getbyname(&a,&result,buffer,1024,&errnop,_nss_ldap_filt_getpwnam,LM_PASSWD,_nss_ldap_parse_pw));
+ /* no more need for this string */
+ free(name);
+ /* write the response */
+ WRITE_INT32(fp,NSLCD_VERSION);
+ WRITE_INT32(fp,NSLCD_ACTION_PASSWD_BYNAME);
+ WRITE_INT32(fp,retv);
+ if (retv==NSLCD_RESULT_SUCCESS)
+ {
+ NSLCD_PASSWD;
+ }
+ WRITE_FLUSH(fp);
+ /* we're done */
+ return 0;
+}
+
+int nslcd_passwd_byuid(FILE *fp)
+{
+ int32_t tmpint32;
+ uid_t uid;
+ /* these are here for now until we rewrite the LDAP code */
+ struct passwd result;
+ char buffer[1024];
+ int errnop;
+ int retv;
+ struct ldap_args a;
+ /* read request parameters */
+ READ_TYPE(fp,uid,uid_t);
+ /* log call */
+ log_log(LOG_DEBUG,"nslcd_passwd_byuid(%d)",(int)uid);
+ /* do the LDAP request */
+ LA_INIT(a);
+ LA_NUMBER(a)=uid;
+ LA_TYPE(a)=LA_TYPE_NUMBER;
+ retv=nss2nslcd(_nss_ldap_getbyname(&a,&result,buffer,1024,&errnop,_nss_ldap_filt_getpwuid,LM_PASSWD,_nss_ldap_parse_pw));
+ /* write the response */
+ WRITE_INT32(fp,NSLCD_VERSION);
+ WRITE_INT32(fp,NSLCD_ACTION_PASSWD_BYUID);
+ WRITE_INT32(fp,retv);
+ if (retv==NSLCD_RESULT_SUCCESS)
+ {
+ NSLCD_PASSWD;
+ }
+ WRITE_FLUSH(fp);
+ /* we're done */
+ return 0;
+}
+
+int nslcd_passwd_all(FILE *fp)
+{
+ int32_t tmpint32;
+ /* these are here for now until we rewrite the LDAP code */
+ struct ent_context *pw_context = NULL;
+ struct passwd result;
+ char buffer[1024];
+ int errnop;
+ int retv;
+ /* log call */
+ log_log(LOG_DEBUG,"nslcd_passwd_all()");
+ /* write the response header */
+ WRITE_INT32(fp,NSLCD_VERSION);
+ WRITE_INT32(fp,NSLCD_ACTION_PASSWD_ALL);
+ /* initialize context */
+ if (_nss_ldap_ent_context_init(&pw_context)==NULL)
+ return -1;
+ /* go over results */
+ while ((retv=nss2nslcd(_nss_ldap_getent(&pw_context,&result,buffer,1024,&errnop,_nss_ldap_filt_getpwent,LM_PASSWD,_nss_ldap_parse_pw)))==NSLCD_RESULT_SUCCESS)
+ {
+ /* write the result */
+ WRITE_INT32(fp,retv);
+ NSLCD_PASSWD;
+ }
+ /* write the final result code */
+ WRITE_INT32(fp,retv);
+ WRITE_FLUSH(fp);
+ /* FIXME: if some statement returns what happens to the context? */
+ _nss_ldap_enter(); \
+ _nss_ldap_ent_context_release(pw_context); \
+ _nss_ldap_leave(); \
+ /* we're done */
+ return 0;
+}
diff --git a/nslcd/protocol.c b/nslcd/protocol.c
new file mode 100644
index 0000000..71ce52d
--- /dev/null
+++ b/nslcd/protocol.c
@@ -0,0 +1,198 @@
+/*
+ protocol.c - network address entry lookup routines
+ This file was part of the nss_ldap library (as ldap-proto.c)
+ which has been forked into the nss-ldapd library.
+
+ Copyright (C) 1997-2005 Luke Howard
+ Copyright (C) 2006 West Consulting
+ Copyright (C) 2006 Arthur de Jong
+
+ This 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+/*
+ 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"
+#include "common.h"
+#include "log.h"
+
+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;
+}
+
+/* macros for expanding the NSLCD_PROTOCOL macro */
+#define NSLCD_STRING(field) WRITE_STRING(fp,field)
+#define NSLCD_STRINGLIST(field) WRITE_STRINGLIST_NULLTERM(fp,field)
+#define NSLCD_INT32(field) WRITE_INT32(fp,field)
+#define PROTOCOL_NAME result.p_name
+#define PROTOCOL_ALIASES result.p_aliases
+#define PROTOCOL_NUMBER result.p_proto
+
+int nslcd_protocol_byname(FILE *fp)
+{
+ int32_t tmpint32,tmp2int32,tmp3int32;
+ char *name;
+ struct ldap_args a;
+ /* these are here for now until we rewrite the LDAP code */
+ struct protoent result;
+ char buffer[1024];
+ int errnop;
+ int retv;
+ /* read request parameters */
+ READ_STRING_ALLOC(fp,name);
+ /* log call */
+ log_log(LOG_DEBUG,"nslcd_protocol_byname(%s)",name);
+ /* write the response header */
+ WRITE_INT32(fp,NSLCD_VERSION);
+ WRITE_INT32(fp,NSLCD_ACTION_PROTOCOL_BYNAME);
+ /* do the LDAP request */
+ LA_INIT(a);
+ LA_STRING(a)=name;
+ LA_TYPE(a)=LA_TYPE_STRING;
+ retv=nss2nslcd(_nss_ldap_getbyname(&a,&result,buffer,1024,&errnop,_nss_ldap_filt_getprotobyname,LM_PROTOCOLS,_nss_ldap_parse_proto));
+ /* no more need for this string */
+ free(name);
+ /* write the response */
+ WRITE_INT32(fp,retv);
+ if (retv==NSLCD_RESULT_SUCCESS)
+ {
+ NSLCD_PROTOCOL;
+ }
+ WRITE_FLUSH(fp);
+ /* we're done */
+ return 0;
+}
+
+int nslcd_protocol_bynumber(FILE *fp)
+{
+ int32_t tmpint32,tmp2int32,tmp3int32;
+ int protocol;
+ struct ldap_args a;
+ /* these are here for now until we rewrite the LDAP code */
+ struct protoent result;
+ char buffer[1024];
+ int errnop;
+ int retv;
+ /* read request parameters */
+ READ_INT32(fp,protocol);
+ /* log call */
+ log_log(LOG_DEBUG,"nslcd_protocol_bynumber(%d)",protocol);
+ /* write the response header */
+ WRITE_INT32(fp,NSLCD_VERSION);
+ WRITE_INT32(fp,NSLCD_ACTION_PROTOCOL_BYNUMBER);
+ /* do the LDAP request */
+ LA_INIT(a);
+ LA_NUMBER(a)=protocol;
+ LA_TYPE(a)=LA_TYPE_NUMBER;
+ retv=nss2nslcd(_nss_ldap_getbyname(&a,&result,buffer,1024,&errnop,_nss_ldap_filt_getprotobynumber,LM_PROTOCOLS,_nss_ldap_parse_proto));
+ /* write the response */
+ WRITE_INT32(fp,retv);
+ if (retv==NSLCD_RESULT_SUCCESS)
+ {
+ NSLCD_PROTOCOL;
+ }
+ WRITE_FLUSH(fp);
+ /* we're done */
+ return 0;
+}
+
+int nslcd_protocol_all(FILE *fp)
+{
+ int32_t tmpint32,tmp2int32,tmp3int32;
+ static struct ent_context *protocol_context;
+ /* these are here for now until we rewrite the LDAP code */
+ struct protoent result;
+ char buffer[1024];
+ int errnop;
+ int retv;
+ /* log call */
+ log_log(LOG_DEBUG,"nslcd_protocol_all()");
+ /* write the response header */
+ WRITE_INT32(fp,NSLCD_VERSION);
+ WRITE_INT32(fp,NSLCD_ACTION_PROTOCOL_ALL);
+ /* initialize context */
+ if (_nss_ldap_ent_context_init(&protocol_context)==NULL)
+ return -1;
+ /* loop over all results */
+ while ((retv=nss2nslcd(_nss_ldap_getent(&protocol_context,&result,buffer,1024,&errnop,_nss_ldap_filt_getprotoent,LM_PROTOCOLS,_nss_ldap_parse_proto)))==NSLCD_RESULT_SUCCESS)
+ {
+ /* write the result code */
+ WRITE_INT32(fp,retv);
+ /* write the entry */
+ NSLCD_PROTOCOL;
+ }
+ /* write the final result code */
+ WRITE_INT32(fp,retv);
+ WRITE_FLUSH(fp);
+ /* FIXME: if a previous call returns what happens to the context? */
+ _nss_ldap_enter();
+ _nss_ldap_ent_context_release(protocol_context);
+ _nss_ldap_leave();
+ /* we're done */
+ return 0;
+}
diff --git a/nslcd/resolve.c b/nslcd/resolve.c
new file mode 100644
index 0000000..470d33d
--- /dev/null
+++ b/nslcd/resolve.c
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Hvgskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the Kungliga Tekniska
+ * Hvgskolan and its contributors.
+ *
+ * 4. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <string.h>
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#include <resolv.h>
+
+#include "resolve.h"
+
+#if defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND)
+
+#define DECL(X) {#X, T_##X}
+
+static struct stot
+{
+ char *name;
+ int type;
+}
+stot[] =
+{
+ DECL (A),
+ DECL (NS),
+ DECL (CNAME), DECL (PTR), DECL (MX), DECL (TXT), DECL (AFSDB), DECL (SRV),
+ {
+ NULL, 0}
+};
+
+static int
+string_to_type (const char *name)
+{
+ struct stot *p = stot;
+ for (p = stot; p->name; p++)
+ if (strcasecmp (name, p->name) == 0)
+ return p->type;
+ return -1;
+}
+
+void
+dns_free_data (struct dns_reply *r)
+{
+ struct resource_record *rr;
+ if (r->q.domain)
+ free (r->q.domain);
+ for (rr = r->head; rr;)
+ {
+ struct resource_record *tmp = rr;
+ if (rr->domain)
+ free (rr->domain);
+ if (rr->u.data)
+ free (rr->u.data);
+ rr = rr->next;
+ free (tmp);
+ }
+ free (r);
+}
+
+static struct dns_reply *
+parse_reply (unsigned char *data, int len)
+{
+ unsigned char *p;
+ char host[128];
+ int status;
+ int query, response;
+
+ struct dns_reply *r;
+ struct resource_record **rr;
+
+ r = (struct dns_reply *) malloc (sizeof (struct dns_reply));
+ memset (r, 0, sizeof (struct dns_reply));
+ r->q.domain = NULL;
+
+ p = data;
+ memcpy (&r->h, p, sizeof (HEADER));
+ p += sizeof (HEADER);
+ for (query = 0; query < ntohs(r->h.qdcount); query++)
+ {
+ status = dn_expand (data, data + len, p, host, sizeof (host));
+ if (status < 0)
+ {
+ dns_free_data (r);
+ return NULL;
+ }
+ p += status;
+ if (p + 4 > data + len)
+ {
+ dns_free_data (r);
+ return NULL;
+ }
+ if (r->q.domain == NULL)
+ {
+ r->q.domain = strdup (host);
+ r->q.type = (p[0] << 8 | p[1]);
+ r->q.class = (p[2] << 8 | p[3]);
+ }
+ p += 4;
+ }
+ rr = &r->head;
+ for (response = 0; (response < ntohs(r->h.ancount)) && (p < data + len); response++)
+ {
+ unsigned int type, class, ttl, size;
+ status = dn_expand (data, data + len, p, host, sizeof (host));
+ if (status < 0)
+ {
+ dns_free_data (r);
+ return NULL;
+ }
+ p += status;
+ if (p + 10 > data + len)
+ {
+ dns_free_data (r);
+ return NULL;
+ }
+ type = (p[0] << 8) | p[1];
+ p += 2;
+ class = (p[0] << 8) | p[1];
+ p += 2;
+ ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
+ p += 4;
+ size = (p[0] << 8) | p[1];
+ p += 2;
+ if (p + size > data + len)
+ {
+ dns_free_data (r);
+ return NULL;
+ }
+ *rr = (struct resource_record *) calloc (1,
+ sizeof (struct
+ resource_record));
+ (*rr)->domain = strdup (host);
+ (*rr)->type = type;
+ (*rr)->class = class;
+ (*rr)->ttl = ttl;
+ (*rr)->size = size;
+ switch (type)
+ {
+ case T_NS:
+ case T_CNAME:
+ case T_PTR:
+ status = dn_expand (data, data + len, p, host, sizeof (host));
+ if (status < 0)
+ {
+ dns_free_data (r);
+ return NULL;
+ }
+ (*rr)->u.txt = strdup (host);
+ break;
+ case T_MX:
+ case T_AFSDB:
+ {
+ if (p + 2 > data + len)
+ {
+ dns_free_data (r);
+ return NULL;
+ }
+ status = dn_expand (data, data + len, p + 2, host, sizeof (host));
+ if (status < 0)
+ {
+ dns_free_data (r);
+ return NULL;
+ }
+
+ (*rr)->u.mx =
+ (struct mx_record *) malloc (sizeof (struct mx_record) +
+ strlen (host));
+ (*rr)->u.mx->preference = (p[0] << 8) | p[1];
+ strcpy ((*rr)->u.mx->domain, host);
+ break;
+ }
+ case T_SRV:
+ {
+ if (p + 6 > data + len)
+ {
+ dns_free_data (r);
+ return NULL;
+ }
+ status = dn_expand (data, data + len, p + 6, host, sizeof (host));
+ if (status < 0)
+ {
+ dns_free_data (r);
+ return NULL;
+ }
+ (*rr)->u.srv =
+ (struct srv_record *) malloc (sizeof (struct srv_record) +
+ strlen (host));
+ (*rr)->u.srv->priority = (p[0] << 8) | p[1];
+ (*rr)->u.srv->weight = (p[2] << 8) | p[3];
+ (*rr)->u.srv->port = (p[4] << 8) | p[5];
+ strcpy ((*rr)->u.srv->target, host);
+ break;
+ }
+ case T_TXT:
+ {
+ if (p + *p > data + len)
+ {
+ dns_free_data (r);
+ return NULL;
+ }
+ (*rr)->u.txt = (char *) malloc (size + 1);
+ strncpy ((*rr)->u.txt, (char *) p + 1, *p);
+ (*rr)->u.txt[*p] = 0;
+ break;
+ }
+
+ default:
+ (*rr)->u.data = (unsigned char *) malloc (size);
+ memcpy ((*rr)->u.data, p, size);
+ }
+ p += size;
+ rr = &(*rr)->next;
+ }
+ *rr = NULL;
+ return r;
+}
+
+struct dns_reply *
+dns_lookup (const char *domain, const char *type_name)
+{
+ unsigned char *reply = NULL;
+ int len, rlen;
+ int type;
+ struct dns_reply *r = NULL;
+
+ type = string_to_type (type_name);
+ rlen = 1024;
+ reply = malloc(rlen);
+ do
+ {
+ len = res_search (domain, C_IN, type, reply, rlen);
+ if ((len == -1) || (len < rlen))
+ {
+ break;
+ }
+ reply = realloc (reply, len + 1024);
+ rlen = len + 1024;
+ }
+ while (1);
+ if (len >= 0)
+ r = parse_reply (reply, len);
+ free(reply);
+ return r;
+}
+
+#else /* defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND) */
+
+struct dns_reply *
+dns_lookup (const char *domain, const char *type_name)
+{
+ return NULL;
+}
+
+void
+dns_free_data (struct dns_reply *r)
+{
+}
+
+#endif /* not ( defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND) ) */
+
+#ifdef TEST
+
+int
+main (int argc, char **argv)
+{
+ struct dns_reply *r;
+ struct resource_record *rr;
+ r = dns_lookup (argv[1], argv[2]);
+ if (r == NULL)
+ {
+ printf ("No reply.\n");
+ return 1;
+ }
+ for (rr = r->head; rr; rr = rr->next)
+ {
+ printf ("%s %s %d ", rr->domain, type_to_string (rr->type), rr->ttl);
+ switch (rr->type)
+ {
+ case T_NS:
+ printf ("%s\n", (char *) rr->data);
+ break;
+ case T_A:
+ printf ("%d.%d.%d.%d\n",
+ ((unsigned char *) rr->data)[0],
+ ((unsigned char *) rr->data)[1],
+ ((unsigned char *) rr->data)[2],
+ ((unsigned char *) rr->data)[3]);
+ break;
+ case T_MX:
+ case T_AFSDB:
+ {
+ struct mx_record *mx = (struct mx_record *) rr->data;
+ printf ("%d %s\n", mx->preference, mx->domain);
+ break;
+ }
+ case T_SRV:
+ {
+ struct srv_record *srv = (struct srv_record *) rr->data;
+ printf ("%d %d %d %s\n", srv->priority, srv->weight,
+ srv->port, srv->target);
+ break;
+ }
+ default:
+ printf ("\n");
+ break;
+ }
+ }
+
+ return 0;
+}
+#endif /* TEST */
diff --git a/nslcd/resolve.h b/nslcd/resolve.h
new file mode 100644
index 0000000..62b2574
--- /dev/null
+++ b/nslcd/resolve.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Hvgskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the Kungliga Tekniska
+ * Hvgskolan and its contributors.
+ *
+ * 4. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* THIS IS NOT (yet) A PUBLIC INTERFACE */
+
+#ifndef __RESOLVE_H__
+#define __RESOLVE_H__
+
+/* when would this *not* be defined? */
+#define HAVE_ARPA_NAMESER_H
+
+/* We use these, but they are not always present in <arpa/nameser.h> */
+
+#ifndef T_TXT
+#define T_TXT 16
+#endif
+#ifndef T_AFSDB
+#define T_AFSDB 18
+#endif
+#ifndef T_SRV
+#define T_SRV 33
+#endif
+
+struct dns_query
+{
+ char *domain;
+ unsigned type;
+ unsigned class;
+};
+
+struct mx_record
+{
+ unsigned preference;
+ char domain[1];
+};
+
+struct srv_record
+{
+ unsigned priority;
+ unsigned weight;
+ unsigned port;
+ char target[1];
+};
+
+struct resource_record
+{
+ char *domain;
+ unsigned type;
+ unsigned class;
+ unsigned ttl;
+ unsigned size;
+ union
+ {
+ void *data;
+ struct mx_record *mx;
+ struct mx_record *afsdb; /* mx and afsdb are identical */
+ struct srv_record *srv;
+ struct in_addr *a;
+ char *txt;
+ }
+ u;
+ struct resource_record *next;
+};
+
+#ifndef HAVE_ARPA_NAMESER_H /* XXX */
+typedef int HEADER; /* will never be used */
+#endif
+
+struct dns_reply
+{
+ HEADER h;
+ struct dns_query q;
+ struct resource_record *head;
+};
+
+#define dns_lookup _nss_ldap_dns_lookup
+#define dns_free_data _nss_ldap_dns_free_data
+
+struct dns_reply *dns_lookup (const char *, const char *);
+
+void dns_free_data (struct dns_reply *r);
+
+#endif /* __RESOLVE_H__ */
diff --git a/nslcd/rpc.c b/nslcd/rpc.c
new file mode 100644
index 0000000..b58cca7
--- /dev/null
+++ b/nslcd/rpc.c
@@ -0,0 +1,206 @@
+/*
+ rpc.c - rpc name lookup routines
+ This file was part of the nss_ldap library (as ldap-rpc.c) which
+ has been forked into the nss-ldapd library.
+
+ Copyright (C) 1997-2005 Luke Howard
+ Copyright (C) 2006 West Consulting
+ Copyright (C) 2006 Arthur de Jong
+
+ This 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+/*
+ 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"
+#include "common.h"
+#include "log.h"
+
+/* macros for expanding the NSLCD_RPC macro */
+#define NSLCD_STRING(field) WRITE_STRING(fp,field)
+#define NSLCD_STRINGLIST(field) WRITE_STRINGLIST_NULLTERM(fp,field)
+#define NSLCD_INT32(field) WRITE_INT32(fp,field)
+#define RPC_NAME result->r_name
+#define RPC_ALIASES result->r_aliases
+#define RPC_NUMBER result->r_number
+
+/* write a single rpc entry to the stream */
+static int write_rpcent(FILE *fp,struct rpcent *result)
+{
+ int32_t tmpint32,tmp2int32,tmp3int32;
+ NSLCD_RPC;
+ return 0;
+}
+
+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;
+}
+
+int nslcd_rpc_byname(FILE *fp)
+{
+ int32_t tmpint32;
+ char *name;
+ struct ldap_args a;
+ /* these are here for now until we rewrite the LDAP code */
+ struct rpcent result;
+ char buffer[1024];
+ int errnop;
+ int retv;
+ /* read request parameters */
+ READ_STRING_ALLOC(fp,name);
+ /* log call */
+ log_log(LOG_DEBUG,"nslcd_rpc_byname(%s)",name);
+ /* write the response header */
+ WRITE_INT32(fp,NSLCD_VERSION);
+ WRITE_INT32(fp,NSLCD_ACTION_RPC_BYNAME);
+ /* do the LDAP request */
+ LA_INIT(a);
+ LA_STRING(a)=name;
+ LA_TYPE(a)=LA_TYPE_STRING;
+ retv=nss2nslcd(_nss_ldap_getbyname(&a,&result,buffer,1024,&errnop,_nss_ldap_filt_getrpcbyname,LM_RPC,_nss_ldap_parse_rpc));
+ /* no more need for this string */
+ free(name);
+ /* write the response */
+ WRITE_INT32(fp,retv);
+ if (retv==NSLCD_RESULT_SUCCESS)
+ write_rpcent(fp,&result);
+ WRITE_FLUSH(fp);
+ /* we're done */
+ return 0;
+}
+
+int nslcd_rpc_bynumber(FILE *fp)
+{
+ int32_t tmpint32;
+ int number;
+ struct ldap_args a;
+ /* these are here for now until we rewrite the LDAP code */
+ struct rpcent result;
+ char buffer[1024];
+ int errnop;
+ int retv;
+ /* read request parameters */
+ READ_INT32(fp,number);
+ /* log call */
+ log_log(LOG_DEBUG,"nslcd_rpc_bynumber(%d)",number);
+ /* write the response header */
+ WRITE_INT32(fp,NSLCD_VERSION);
+ WRITE_INT32(fp,NSLCD_ACTION_RPC_BYNUMBER);
+ /* do the LDAP request */
+ LA_INIT(a);
+ LA_NUMBER(a)=number;
+ LA_TYPE(a)=LA_TYPE_NUMBER;
+ retv=nss2nslcd(_nss_ldap_getbyname(&a,&result,buffer,1024,&errnop,_nss_ldap_filt_getrpcbynumber,LM_RPC,_nss_ldap_parse_rpc));
+ /* write the response */
+ WRITE_INT32(fp,retv);
+ if (retv==NSLCD_RESULT_SUCCESS)
+ write_rpcent(fp,&result);
+ WRITE_FLUSH(fp);
+ /* we're done */
+ return 0;
+}
+
+int nslcd_rpc_all(FILE *fp)
+{
+ int32_t tmpint32;
+ static struct ent_context *rpc_context;
+ /* these are here for now until we rewrite the LDAP code */
+ struct rpcent result;
+ char buffer[1024];
+ int errnop;
+ int retv;
+ /* log call */
+ log_log(LOG_DEBUG,"nslcd_rpc_all()");
+ /* write the response header */
+ WRITE_INT32(fp,NSLCD_VERSION);
+ WRITE_INT32(fp,NSLCD_ACTION_RPC_ALL);
+ /* initialize context */
+ if (_nss_ldap_ent_context_init(&rpc_context)==NULL)
+ return -1;
+ /* loop over all results */
+ while ((retv=nss2nslcd(_nss_ldap_getent(&rpc_context,&result,buffer,1024,&errnop,_nss_ldap_filt_getrpcent,LM_RPC,_nss_ldap_parse_rpc)))==NSLCD_RESULT_SUCCESS)
+ {
+ /* write the result code */
+ WRITE_INT32(fp,retv);
+ /* write the entry */
+ write_rpcent(fp,&result);
+ }
+ /* write the final result code */
+ WRITE_INT32(fp,retv);
+ WRITE_FLUSH(fp);
+ /* FIXME: if a previous call returns what happens to the context? */
+ _nss_ldap_enter();
+ _nss_ldap_ent_context_release(rpc_context);
+ _nss_ldap_leave();
+ /* we're done */
+ return 0;
+}
diff --git a/nslcd/service.c b/nslcd/service.c
new file mode 100644
index 0000000..7739b8e
--- /dev/null
+++ b/nslcd/service.c
@@ -0,0 +1,302 @@
+/*
+ service.c - service entry lookup routines
+ This file was part of the nss_ldap library (as ldap-service.c)
+ which has been forked into the nss-ldapd library.
+
+ Copyright (C) 1997-2005 Luke Howard
+ Copyright (C) 2006 West Consulting
+ Copyright (C) 2006 Arthur de Jong
+
+ This 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+/*
+ 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"
+#include "common.h"
+#include "log.h"
+
+/* macros for expanding the NSLCD_SERVICE macro */
+#define NSLCD_STRING(field) WRITE_STRING(fp,field)
+#define NSLCD_STRINGLIST(field) WRITE_STRINGLIST_NULLTERM(fp,field)
+#define NSLCD_INT32(field) WRITE_INT32(fp,field)
+#define SERVICE_NAME result->s_name
+#define SERVICE_ALIASES result->s_aliases
+#define SERVICE_NUMBER htons(result->s_port)
+#define SERVICE_PROTOCOL result->s_proto
+
+/* write a single host entry to the stream */
+static int write_servent(FILE *fp,struct servent *result)
+{
+ int32_t tmpint32,tmp2int32,tmp3int32;
+ NSLCD_SERVICE;
+ return 0;
+}
+
+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;
+}
+
+int nslcd_service_byname(FILE *fp)
+{
+ int32_t tmpint32;
+ char *name,*protocol;
+ struct ldap_args a;
+ /* these are here for now until we rewrite the LDAP code */
+ struct servent result;
+ char buffer[1024];
+ int errnop;
+ int retv;
+ /* read request parameters */
+ READ_STRING_ALLOC(fp,name);
+ READ_STRING_ALLOC(fp,protocol);
+ /* log call */
+ log_log(LOG_DEBUG,"nslcd_service_byname(%s,%s)",name,protocol);
+ /* write the response header */
+ WRITE_INT32(fp,NSLCD_VERSION);
+ WRITE_INT32(fp,NSLCD_ACTION_SERVICE_BYNAME);
+ /* do the LDAP request */
+ LA_INIT(a);
+ LA_STRING(a)=name;
+ LA_TYPE(a)=(strlen(protocol)==0)?LA_TYPE_STRING:LA_TYPE_STRING_AND_STRING;
+ LA_STRING2(a)=protocol;
+ retv=nss2nslcd(_nss_ldap_getbyname(&a,&result,buffer,1024,&errnop,
+ ((strlen(protocol)==0)?_nss_ldap_filt_getservbyname:_nss_ldap_filt_getservbynameproto),
+ LM_SERVICES,_nss_ldap_parse_serv));
+ /* no more need for these strings */
+ free(name);
+ free(protocol);
+ /* write the response */
+ WRITE_INT32(fp,retv);
+ if (retv==NSLCD_RESULT_SUCCESS)
+ write_servent(fp,&result);
+ WRITE_FLUSH(fp);
+ /* we're done */
+ return 0;
+}
+
+int nslcd_service_bynumber(FILE *fp)
+{
+ int32_t tmpint32;
+ int number;
+ char *protocol;
+ struct ldap_args a;
+ /* these are here for now until we rewrite the LDAP code */
+ struct servent result;
+ char buffer[1024];
+ int errnop;
+ int retv;
+ /* read request parameters */
+ READ_INT32(fp,number);
+ READ_STRING_ALLOC(fp,protocol);
+ /* log call */
+ log_log(LOG_DEBUG,"nslcd_service_bynumber(%d,%s)",number,protocol);
+ /* write the response header */
+ WRITE_INT32(fp,NSLCD_VERSION);
+ WRITE_INT32(fp,NSLCD_ACTION_SERVICE_BYNUMBER);
+ /* do the LDAP request */
+ LA_INIT(a);
+ LA_NUMBER(a)=number;
+ LA_TYPE(a)=(strlen(protocol)==0)?LA_TYPE_NUMBER:LA_TYPE_NUMBER_AND_STRING;
+ LA_STRING2(a)=protocol;
+ retv=nss2nslcd(_nss_ldap_getbyname(&a,&result,buffer,1024,&errnop,
+ ((strlen(protocol)==0)?_nss_ldap_filt_getservbyport:_nss_ldap_filt_getservbyportproto),
+ LM_SERVICES,_nss_ldap_parse_serv));
+ /* no more need for this string */
+ free(protocol);
+ /* write the response */
+ WRITE_INT32(fp,retv);
+ if (retv==NSLCD_RESULT_SUCCESS)
+ write_servent(fp,&result);
+ WRITE_FLUSH(fp);
+ /* we're done */
+ return 0;
+}
+
+int nslcd_service_all(FILE *fp)
+{
+ int32_t tmpint32;
+ static struct ent_context *serv_context;
+ /* these are here for now until we rewrite the LDAP code */
+ struct servent result;
+ char buffer[1024];
+ int errnop;
+ int retv;
+ /* log call */
+ log_log(LOG_DEBUG,"nslcd_service_all()");
+ /* write the response header */
+ WRITE_INT32(fp,NSLCD_VERSION);
+ WRITE_INT32(fp,NSLCD_ACTION_SERVICE_ALL);
+ /* initialize context */
+ if (_nss_ldap_ent_context_init(&serv_context)==NULL)
+ return -1;
+ /* loop over all results */
+ while ((retv=nss2nslcd(_nss_ldap_getent(&serv_context,&result,buffer,1024,&errnop,_nss_ldap_filt_getservent,LM_SERVICES,_nss_ldap_parse_serv)))==NSLCD_RESULT_SUCCESS)
+ {
+ /* write the result code */
+ WRITE_INT32(fp,retv);
+ /* write the entry */
+ write_servent(fp,&result);
+ }
+ /* write the final result code */
+ WRITE_INT32(fp,retv);
+ WRITE_FLUSH(fp);
+ /* FIXME: if a previous call returns what happens to the context? */
+ _nss_ldap_enter();
+ _nss_ldap_ent_context_release(serv_context);
+ _nss_ldap_leave();
+ /* we're done */
+ return 0;
+}
diff --git a/nslcd/shadow.c b/nslcd/shadow.c
new file mode 100644
index 0000000..d1b22bd
--- /dev/null
+++ b/nslcd/shadow.c
@@ -0,0 +1,189 @@
+/*
+ shadow.c - service entry lookup routines
+ This file was part of the nss_ldap library (as ldap-spwd.c) which
+ has been forked into the nss-ldapd library.
+
+ Copyright (C) 1997-2005 Luke Howard
+ Copyright (C) 2006 West Consulting
+ Copyright (C) 2006 Arthur de Jong
+
+ This 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+#include "config.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"
+#include "util.h"
+#include "common.h"
+#include "log.h"
+
+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;
+}
+
+/* macros for expanding the NSLCD_SHADOW macro */
+#define NSLCD_STRING(field) WRITE_STRING(fp,field)
+#define NSLCD_INT32(field) WRITE_INT32(fp,field)
+#define SHADOW_NAME result.sp_namp
+#define SHADOW_PASSWD result.sp_pwdp
+#define SHADOW_LASTCHANGE result.sp_lstchg
+#define SHADOW_MINDAYS result.sp_min
+#define SHADOW_MAXDAYS result.sp_max
+#define SHADOW_WARN result.sp_warn
+#define SHADOW_INACT result.sp_inact
+#define SHADOW_EXPIRE result.sp_expire
+#define SHADOW_FLAG result.sp_flag
+
+int nslcd_shadow_byname(FILE *fp)
+{
+ int32_t tmpint32;
+ char *name;
+ struct ldap_args a;
+ int retv;
+ struct spwd result;
+ char buffer[1024];
+ int errnop;
+ /* read request parameters */
+ READ_STRING_ALLOC(fp,name);
+ /* log call */
+ log_log(LOG_DEBUG,"nslcd_shadow_byname(%s)",name);
+ /* write the response header */
+ WRITE_INT32(fp,NSLCD_VERSION);
+ WRITE_INT32(fp,NSLCD_ACTION_SHADOW_BYNAME);
+ /* do the LDAP request */
+ LA_INIT(a);
+ LA_STRING(a)=name;
+ LA_TYPE(a)=LA_TYPE_STRING;
+ retv=nss2nslcd(_nss_ldap_getbyname(&a,&result,buffer,1024,&errnop,_nss_ldap_filt_getspnam,LM_SHADOW,_nss_ldap_parse_sp));
+ /* no more need for this string */
+ free(name);
+ /* write the response */
+ WRITE_INT32(fp,retv);
+ if (retv==NSLCD_RESULT_SUCCESS)
+ {
+ NSLCD_SHADOW;
+ }
+ WRITE_FLUSH(fp);
+ /* we're done */
+ return 0;
+}
+
+int nslcd_shadow_all(FILE *fp)
+{
+ int32_t tmpint32;
+ static struct ent_context *shadow_context;
+ /* these are here for now until we rewrite the LDAP code */
+ struct spwd result;
+ char buffer[1024];
+ int errnop;
+ int retv;
+ /* log call */
+ log_log(LOG_DEBUG,"nslcd_shadow_all()");
+ /* write the response header */
+ WRITE_INT32(fp,NSLCD_VERSION);
+ WRITE_INT32(fp,NSLCD_ACTION_SHADOW_ALL);
+ /* initialize context */
+ if (_nss_ldap_ent_context_init(&shadow_context)==NULL)
+ return -1;
+ /* loop over all results */
+ while ((retv=nss2nslcd(_nss_ldap_getent(&shadow_context,&result,buffer,1024,&errnop,_nss_ldap_filt_getspent,LM_SHADOW,_nss_ldap_parse_sp)))==NSLCD_RESULT_SUCCESS)
+ {
+ /* write the result */
+ WRITE_INT32(fp,retv);
+ NSLCD_SHADOW;
+ }
+ /* write the final result code */
+ WRITE_INT32(fp,retv);
+ WRITE_FLUSH(fp);
+ /* FIXME: if a previous call returns what happens to the context? */
+ _nss_ldap_enter();
+ _nss_ldap_ent_context_release(shadow_context);
+ _nss_ldap_leave();
+ /* we're done */
+ return 0;
+}
diff --git a/nslcd/util.c b/nslcd/util.c
new file mode 100644
index 0000000..57d6a10
--- /dev/null
+++ b/nslcd/util.c
@@ -0,0 +1,1669 @@
+/*
+ util.c - LDAP utility functions
+ This file was part of the nss_ldap library which has been
+ forked into the nss-ldapd library.
+
+ Copyright (C) 1997-2005 Luke Howard
+ Copyright (C) 2006 West Consulting
+ Copyright (C) 2006 Arthur de Jong
+
+ This 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#include <stdlib.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <netdb.h>
+#include <syslog.h>
+#include <string.h>
+#include <fcntl.h>
+#include <assert.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"
+#include "common.h"
+#include "log.h"
+
+
+#define NSS_LDAP_KEY_MAP_ATTRIBUTE "nss_map_attribute"
+#define NSS_LDAP_KEY_MAP_OBJECTCLASS "nss_map_objectclass"
+#define NSS_LDAP_KEY_SET_OVERRIDE "nss_override_attribute_value"
+#define NSS_LDAP_KEY_SET_DEFAULT "nss_default_attribute_value"
+#define NSS_LDAP_KEY_HOST "host"
+#define NSS_LDAP_KEY_SCOPE "scope"
+#define NSS_LDAP_KEY_BASE "base"
+#define NSS_LDAP_KEY_PORT "port"
+#define NSS_LDAP_KEY_BINDDN "binddn"
+#define NSS_LDAP_KEY_BINDPW "bindpw"
+#define NSS_LDAP_KEY_USESASL "use_sasl"
+#define NSS_LDAP_KEY_SASLID "sasl_auth_id"
+#define NSS_LDAP_KEY_DEREF "deref"
+#define NSS_LDAP_KEY_ROOTBINDDN "rootbinddn"
+#define NSS_LDAP_KEY_ROOTUSESASL "rootuse_sasl"
+#define NSS_LDAP_KEY_ROOTSASLID "rootsasl_auth_id"
+#define NSS_LDAP_KEY_LDAP_VERSION "ldap_version"
+#define NSS_LDAP_KEY_TIMELIMIT "timelimit"
+#define NSS_LDAP_KEY_BIND_TIMELIMIT "bind_timelimit"
+#define NSS_LDAP_KEY_SSL "ssl"
+#define NSS_LDAP_KEY_SSLPATH "sslpath"
+#define NSS_LDAP_KEY_REFERRALS "referrals"
+#define NSS_LDAP_KEY_RESTART "restart"
+#define NSS_LDAP_KEY_URI "uri"
+#define NSS_LDAP_KEY_IDLE_TIMELIMIT "idle_timelimit"
+#define NSS_LDAP_KEY_RECONNECT_POLICY "bind_policy"
+#define NSS_LDAP_KEY_SASL_SECPROPS "sasl_secprops"
+#ifdef CONFIGURE_KRB5_CCNAME
+#define NSS_LDAP_KEY_KRB5_CCNAME "krb5_ccname"
+#endif /* CONFIGURE_KRB5_CCNAME */
+#define NSS_LDAP_KEY_LOGDIR "logdir"
+#define NSS_LDAP_KEY_DEBUG "debug"
+#define NSS_LDAP_KEY_PAGESIZE "pagesize"
+#define NSS_LDAP_KEY_INITGROUPS "nss_initgroups"
+#define NSS_LDAP_KEY_INITGROUPS_IGNOREUSERS "nss_initgroups_ignoreusers"
+
+/* more reconnect policy fine-tuning */
+#define NSS_LDAP_KEY_RECONNECT_TRIES "nss_reconnect_tries"
+#define NSS_LDAP_KEY_RECONNECT_SLEEPTIME "nss_reconnect_sleeptime"
+#define NSS_LDAP_KEY_RECONNECT_MAXSLEEPTIME "nss_reconnect_maxsleeptime"
+#define NSS_LDAP_KEY_RECONNECT_MAXCONNTRIES "nss_reconnect_maxconntries"
+
+#define NSS_LDAP_KEY_PAGED_RESULTS "nss_paged_results"
+#define NSS_LDAP_KEY_SCHEMA "nss_schema"
+#define NSS_LDAP_KEY_SRV_DOMAIN "nss_srv_domain"
+#define NSS_LDAP_KEY_CONNECT_POLICY "nss_connect_policy"
+
+/*
+ * Timeouts for reconnecting code. Similar to rebind
+ * logic in Darwin NetInfo. Some may find sleeping
+ * unacceptable, in which case you may wish to adjust
+ * the constants below.
+ */
+#define LDAP_NSS_TRIES 5 /* number of sleeping reconnect attempts */
+#define LDAP_NSS_SLEEPTIME 4 /* seconds to sleep; doubled until max */
+#define LDAP_NSS_MAXSLEEPTIME 64 /* maximum seconds to sleep */
+#define LDAP_NSS_MAXCONNTRIES 2 /* reconnect attempts before sleeping */
+
+#define LDAP_PAGESIZE 1000
+
+
+static struct ldap_dictionary *do_alloc_dictionary(void);
+static enum nss_status do_getrdnvalue (const char *dn,
+ const char *rdntype,
+ char **rval, char **buffer,
+ size_t * buflen);
+
+static enum nss_status do_parse_map_statement (struct ldap_config * cfg,
+ const char *statement,
+ enum ldap_map_type type);
+
+static enum nss_status do_searchdescriptorconfig (const char *key,
+ const char *value,
+ size_t valueLength,
+ struct ldap_service_search_descriptor
+ ** result, char **buffer,
+ size_t * buflen);
+
+static void *__cache = NULL;
+
+NSS_LDAP_DEFINE_LOCK (__cache_lock);
+
+#define cache_lock() NSS_LDAP_LOCK(__cache_lock)
+#define cache_unlock() NSS_LDAP_UNLOCK(__cache_lock)
+
+static enum nss_status
+dn2uid_cache_put (const char *dn, const char *uid)
+{
+ enum nss_status status;
+ struct ldap_datum key, val;
+
+ cache_lock ();
+
+ if (__cache == NULL)
+ {
+ __cache = (void *)do_alloc_dictionary();
+ if (__cache == NULL)
+ {
+ cache_unlock ();
+ return NSS_STATUS_TRYAGAIN;
+ }
+ }
+
+ key.data = (void *) dn;
+ key.size = strlen (dn);
+ val.data = (void *) uid;
+ val.size = strlen (uid);
+
+ status = _nss_ldap_db_put (__cache, 0, &key, &val);
+
+ cache_unlock ();
+
+ return status;
+}
+
+static enum nss_status
+dn2uid_cache_get (const char *dn, char **uid, char **buffer, size_t * buflen)
+{
+ struct ldap_datum key, val;
+ enum nss_status status;
+
+ cache_lock ();
+
+ if (__cache == NULL)
+ {
+ cache_unlock ();
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ key.data = (void *) dn;
+ key.size = strlen (dn);
+
+ status = _nss_ldap_db_get (__cache, 0, &key, &val);
+ if (status != NSS_STATUS_SUCCESS)
+ {
+ cache_unlock ();
+ return status;
+ }
+
+ if (*buflen <= val.size)
+ {
+ cache_unlock ();
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ *uid = *buffer;
+ memcpy (*uid, (char *) val.data, val.size);
+ (*uid)[val.size] = '\0';
+ *buffer += val.size + 1;
+ *buflen -= val.size + 1;
+
+ cache_unlock ();
+ return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_ldap_dn2uid (const char *dn, char **uid, char **buffer, size_t * buflen,
+ int *pIsNestedGroup, LDAPMessage ** pRes)
+{
+ enum nss_status status;
+
+ debug ("==> _nss_ldap_dn2uid");
+
+ *pIsNestedGroup = 0;
+
+ status = dn2uid_cache_get (dn, uid, buffer, buflen);
+ if (status == NSS_STATUS_NOTFOUND)
+ {
+ const char *attrs[4];
+ LDAPMessage *res;
+
+ attrs[0] = ATM (LM_PASSWD, uid);
+ attrs[1] = ATM (LM_GROUP, uniqueMember);
+ attrs[2] = AT (objectClass);
+ attrs[3] = NULL;
+
+ if (_nss_ldap_read (dn, attrs, &res) == NSS_STATUS_SUCCESS)
+ {
+ LDAPMessage *e = _nss_ldap_first_entry (res);
+ if (e != NULL)
+ {
+ if (_nss_ldap_oc_check (e, OC (posixGroup)) == NSS_STATUS_SUCCESS)
+ {
+ *pIsNestedGroup = 1;
+ *pRes = res;
+ debug ("<== _nss_ldap_dn2uid (nested group)");
+ return NSS_STATUS_SUCCESS;
+ }
+
+ status =
+ _nss_ldap_assign_attrval (e, ATM (LM_PASSWD, uid), uid,
+ buffer, buflen);
+ if (status == NSS_STATUS_SUCCESS)
+ dn2uid_cache_put (dn, *uid);
+ }
+ }
+ ldap_msgfree (res);
+ }
+
+ debug ("<== _nss_ldap_dn2uid");
+
+ return status;
+}
+
+enum nss_status
+_nss_ldap_getrdnvalue (LDAPMessage * entry,
+ const char *rdntype,
+ char **rval, char **buffer, size_t * buflen)
+{
+ char *dn;
+ enum nss_status status;
+
+ dn = _nss_ldap_get_dn (entry);
+ if (dn == NULL)
+ {
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ status = do_getrdnvalue (dn, rdntype, rval, buffer, buflen);
+#ifdef HAVE_LDAP_MEMFREE
+ ldap_memfree (dn);
+#else /* HAVE_LDAP_MEMFREE */
+ free (dn);
+#endif /* not HAVE_LDAP_MEMFREE */
+
+ /*
+ * If examining the DN failed, then pick the nominal first
+ * value of cn as the canonical name (recall that attributes
+ * are sets, not sequences)
+ */
+ if (status == NSS_STATUS_NOTFOUND)
+ {
+ char **vals;
+
+ vals = _nss_ldap_get_values (entry, rdntype);
+
+ if (vals != NULL)
+ {
+ int rdnlen = strlen (*vals);
+ if (*buflen > rdnlen)
+ {
+ char *rdnvalue = *buffer;
+ strncpy (rdnvalue, *vals, rdnlen);
+ rdnvalue[rdnlen] = '\0';
+ *buffer += rdnlen + 1;
+ *buflen -= rdnlen + 1;
+ *rval = rdnvalue;
+ status = NSS_STATUS_SUCCESS;
+ }
+ else
+ {
+ status = NSS_STATUS_TRYAGAIN;
+ }
+ ldap_value_free (vals);
+ }
+ }
+
+ return status;
+}
+
+int _nss_ldap_write_rndvalue(FILE *fp,LDAPMessage *entry,const char *rdntype)
+{
+ char *dn;
+ int status=456;
+ char **vals;
+ int32_t tmpint32;
+ char **exploded_dn;
+ char **exploded_rdn;
+ char rdnava[64];
+ int rdnavalen;
+ int i;
+ /* log call */
+ log_log(LOG_DEBUG,"_nss_ldap_write_rndvalue(%s)",rdntype);
+ /* get the dn from the entry */
+ dn=_nss_ldap_get_dn(entry);
+ if (dn==NULL)
+ return NSLCD_RESULT_NOTFOUND;
+ /* append a `=' to the rdntype */
+ snprintf(rdnava,sizeof(rdnava),"%s=",rdntype);
+ rdnavalen=strlen(rdnava);
+ /* explode dn */
+ exploded_dn=ldap_explode_dn(dn,0);
+ if (exploded_dn!=NULL)
+ {
+ /*
+ * attempt to get the naming attribute's principal
+ * value by parsing the RDN. We need to support
+ * multivalued RDNs (as they're essentially mandated
+ * for services)
+ */
+ exploded_rdn=ldap_explode_rdn(exploded_dn[0],0);
+ if (exploded_rdn!=NULL)
+ {
+ for (i=0;exploded_rdn[i]!=NULL;i++)
+ {
+ /* if the values begins with rndava */
+ if (strncasecmp(exploded_rdn[i],rdnava,rdnavalen)==0)
+ {
+ /* FIXME: handle case where WRITE fails */
+ WRITE_STRING(fp,exploded_rdn[i]+rdnavalen);
+ status=0;
+ break;
+ }
+ }
+ ldap_value_free(exploded_rdn);
+ }
+ ldap_value_free(exploded_dn);
+ }
+ ldap_memfree(dn);
+ /*
+ * If examining the DN failed, then pick the nominal first
+ * value of cn as the canonical name (recall that attributes
+ * are sets, not sequences)
+ */
+ if (status==456)
+ {
+ vals=_nss_ldap_get_values(entry,rdntype);
+ if (vals!=NULL)
+ {
+ /* write the first entry */
+ WRITE_STRING(fp,vals[0]);
+ status=NSS_STATUS_SUCCESS;
+ ldap_value_free(vals);
+ status=0;
+ }
+ }
+ return status;
+}
+
+static enum nss_status
+do_getrdnvalue (const char *dn,
+ const char *rdntype,
+ char **rval, char **buffer, size_t * buflen)
+{
+ char **exploded_dn;
+ char *rdnvalue = NULL;
+ char rdnava[64];
+ int rdnlen = 0, rdnavalen;
+
+ snprintf (rdnava, sizeof rdnava, "%s=", rdntype);
+ rdnavalen = strlen (rdnava);
+
+ exploded_dn = ldap_explode_dn (dn, 0);
+
+ if (exploded_dn != NULL)
+ {
+ /*
+ * attempt to get the naming attribute's principal
+ * value by parsing the RDN. We need to support
+ * multivalued RDNs (as they're essentially mandated
+ * for services)
+ */
+#ifdef HAVE_LDAP_EXPLODE_RDN
+ /*
+ * use ldap_explode_rdn() API, as it's cleaner than
+ * strtok(). This code has not been tested!
+ */
+ char **p, **exploded_rdn;
+
+ exploded_rdn = ldap_explode_rdn (*exploded_dn, 0);
+ if (exploded_rdn != NULL)
+ {
+ for (p = exploded_rdn; *p != NULL; p++)
+ {
+ if (strncasecmp (*p, rdnava, rdnavalen) == 0)
+ {
+ char *r = *p + rdnavalen;
+
+ rdnlen = strlen (r);
+ if (*buflen <= rdnlen)
+ {
+ ldap_value_free (exploded_rdn);
+ ldap_value_free (exploded_dn);
+ return NSS_STATUS_TRYAGAIN;
+ }
+ rdnvalue = *buffer;
+ strncpy (rdnvalue, r, rdnlen);
+ break;
+ }
+ }
+ ldap_value_free (exploded_rdn);
+ }
+#else /* HAVE_LDAP_EXPLODE_RDN */
+ /*
+ * we don't have Netscape's ldap_explode_rdn() API,
+ * so we fudge it with strtok(). Note that this will
+ * not handle escaping properly.
+ */
+ char *p, *r = *exploded_dn;
+#ifdef HAVE_STRTOK_R
+ char *st = NULL;
+#endif /* HAVE_STRTOK_R */
+
+#ifndef HAVE_STRTOK_R
+ for (p = strtok (r, "+");
+#else /* HAVE_STRTOK_R */
+ for (p = strtok_r (r, "+", &st);
+#endif /* not HAVE_STRTOK_R */
+ p != NULL;
+#ifndef HAVE_STRTOK_R
+ p = strtok (NULL, "+"))
+#else /* HAVE_STRTOK_R */
+ p = strtok_r (NULL, "+", &st))
+#endif /* not HAVE_STRTOK_R */
+ {
+ if (strncasecmp (p, rdnava, rdnavalen) == 0)
+ {
+ p += rdnavalen;
+ rdnlen = strlen (p);
+ if (*buflen <= rdnlen)
+ {
+ ldap_value_free (exploded_dn);
+ return NSS_STATUS_TRYAGAIN;
+ }
+ rdnvalue = *buffer;
+ strncpy (rdnvalue, p, rdnlen);
+ break;
+ }
+ if (r != NULL)
+ r = NULL;
+ }
+#endif /* not HAVE_LDAP_EXPLODE_RDN */
+ }
+
+ if (exploded_dn != NULL)
+ {
+ ldap_value_free (exploded_dn);
+ }
+
+ if (rdnvalue != NULL)
+ {
+ rdnvalue[rdnlen] = '\0';
+ *buffer += rdnlen + 1;
+ *buflen -= rdnlen + 1;
+ *rval = rdnvalue;
+ return NSS_STATUS_SUCCESS;
+ }
+
+ return NSS_STATUS_NOTFOUND;
+}
+
+static enum ldap_map_selector
+_nss_ldap_str2selector (const char *key)
+{
+ enum ldap_map_selector sel;
+
+ if (!strcasecmp (key, MP_passwd))
+ sel = LM_PASSWD;
+ else if (!strcasecmp (key, MP_shadow))
+ sel = LM_SHADOW;
+ else if (!strcasecmp (key, MP_group))
+ sel = LM_GROUP;
+ else if (!strcasecmp (key, MP_hosts))
+ sel = LM_HOSTS;
+ else if (!strcasecmp (key, MP_services))
+ sel = LM_SERVICES;
+ else if (!strcasecmp (key, MP_networks))
+ sel = LM_NETWORKS;
+ else if (!strcasecmp (key, MP_protocols))
+ sel = LM_PROTOCOLS;
+ else if (!strcasecmp (key, MP_rpc))
+ sel = LM_RPC;
+ else if (!strcasecmp (key, MP_ethers))
+ sel = LM_ETHERS;
+ else if (!strcasecmp (key, MP_netmasks))
+ sel = LM_NETMASKS;
+ else if (!strcasecmp (key, MP_bootparams))
+ sel = LM_BOOTPARAMS;
+ else if (!strcasecmp (key, MP_aliases))
+ sel = LM_ALIASES;
+ else if (!strcasecmp (key, MP_netgroup))
+ sel = LM_NETGROUP;
+ else
+ sel = LM_NONE;
+ return sel;
+}
+
+static enum nss_status
+do_parse_map_statement (struct ldap_config * cfg,
+ const char *statement, enum ldap_map_type type)
+{
+ char *key, *val;
+ enum ldap_map_selector sel = LM_NONE;
+
+ key = (char *) statement;
+ val = key;
+ while (*val != ' ' && *val != '\t')
+ val++;
+ *(val++) = '\0';
+
+ while (*val == ' ' || *val == '\t')
+ val++;
+
+ {
+ char *p = strchr (key, ':');
+
+ if (p != NULL)
+ {
+ *p = '\0';
+ sel = _nss_ldap_str2selector (key);
+ key = ++p;
+ }
+ }
+
+ return _nss_ldap_map_put (cfg, sel, type, key, val);
+}
+
+/* parse a comma-separated list */
+static enum nss_status
+do_parse_list (char *values, char ***valptr,
+ char **pbuffer, size_t *pbuflen)
+{
+ char *s, **p;
+#ifdef HAVE_STRTOK_R
+ char *tok_r;
+#endif /* HAVE_STRTOK_R */
+ int valcount;
+
+ int buflen = *pbuflen;
+ char *buffer = *pbuffer;
+
+ /* comma separated list of values to ignore on initgroups() */
+ for (valcount = 1, s = values; *s != '\0'; s++)
+ {
+ if (*s == ',')
+ valcount++;
+ }
+
+ if (bytesleft (buffer, buflen, char *) < (valcount + 1) * sizeof (char *))
+ {
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ align (buffer, buflen, char *);
+ p = *valptr = (char **) buffer;
+
+ buffer += (valcount + 1) * sizeof (char *);
+ buflen -= (valcount + 1) * sizeof (char *);
+
+#ifdef HAVE_STRTOK_R
+ for (s = strtok_r(values, ",", &tok_r); s != NULL;
+ s = strtok_r(NULL, ",", &tok_r))
+#else /* HAVE_STRTOK_R */
+ for (s = strtok(values, ","); s != NULL; s = strtok(NULL, ","))
+#endif /* not HAVE_STRTOK_R */
+ {
+ int vallen;
+ char *elt = NULL;
+
+ vallen = strlen (s);
+ if (buflen < (size_t) (vallen + 1))
+ {
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ /* copy this value into the next block of buffer space */
+ elt = buffer;
+ buffer += vallen + 1;
+ buflen -= vallen + 1;
+
+ strncpy (elt, s, vallen);
+ elt[vallen] = '\0';
+ *p++ = elt;
+ }
+
+ *p = NULL;
+ *pbuffer = buffer;
+ *pbuflen = buflen;
+
+ return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status
+do_searchdescriptorconfig (const char *key, const char *value, size_t len,
+ struct ldap_service_search_descriptor ** result,
+ char **buffer, size_t * buflen)
+{
+ struct ldap_service_search_descriptor **t, *cur;
+ char *base;
+ char *filter, *s;
+ int scope;
+ enum ldap_map_selector sel;
+
+ t = NULL;
+ filter = NULL;
+ scope = -1;
+
+ if (strncasecmp (key, NSS_LDAP_KEY_NSS_BASE_PREFIX,
+ NSS_LDAP_KEY_NSS_BASE_PREFIX_LEN) != 0)
+ return NSS_STATUS_SUCCESS;
+
+ sel = _nss_ldap_str2selector (&key[NSS_LDAP_KEY_NSS_BASE_PREFIX_LEN]);
+ t = (sel < LM_NONE) ? &result[sel] : NULL;
+
+ if (t == NULL)
+ return NSS_STATUS_SUCCESS;
+
+ /* we have already checked for room for the value */
+ /* len is set to the length of value */
+ base = *buffer;
+ strncpy (base, value, len);
+ base[len] = '\0';
+
+ *buffer += len + 1;
+ *buflen -= len + 1;
+
+ /* probably is some funky escaping needed here. later... */
+ s = strchr (base, '?');
+ if (s != NULL)
+ {
+ *s = '\0';
+ s++;
+ if (!strcasecmp (s, "sub"))
+ scope = LDAP_SCOPE_SUBTREE;
+ else if (!strcasecmp (s, "one"))
+ scope = LDAP_SCOPE_ONELEVEL;
+ else if (!strcasecmp (s, "base"))
+ scope = LDAP_SCOPE_BASE;
+ filter = strchr (s, '?');
+ if (filter != NULL)
+ {
+ *filter = '\0';
+ filter++;
+ }
+ }
+
+ if (bytesleft (*buffer, *buflen, struct ldap_service_search_descriptor) <
+ sizeof (struct ldap_service_search_descriptor))
+ return NSS_STATUS_UNAVAIL;
+
+ align (*buffer, *buflen, struct ldap_service_search_descriptor);
+
+ for (cur = *t; cur && cur->lsd_next; cur = cur->lsd_next)
+ ;
+ if (!cur)
+ {
+ *t = (struct ldap_service_search_descriptor *) * buffer;
+ cur = *t;
+ }
+ else
+ {
+ cur->lsd_next = (struct ldap_service_search_descriptor *) * buffer;
+ cur = cur->lsd_next;
+ }
+
+ cur->lsd_base = base;
+ cur->lsd_scope = scope;
+ cur->lsd_filter = filter;
+ cur->lsd_next = NULL;
+
+ *buffer += sizeof (struct ldap_service_search_descriptor);
+ *buflen -= sizeof (struct ldap_service_search_descriptor);
+
+ return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status _nss_ldap_init_config (struct ldap_config * result)
+{
+ int i, j;
+
+ memset (result, 0, sizeof (*result));
+
+ result->ldc_scope = LDAP_SCOPE_SUBTREE;
+ result->ldc_deref = LDAP_DEREF_NEVER;
+ result->ldc_base = NULL;
+ result->ldc_binddn = NULL;
+ result->ldc_bindpw = NULL;
+ result->ldc_saslid = NULL;
+ result->ldc_usesasl = 0;
+ result->ldc_rootbinddn = NULL;
+ result->ldc_rootbindpw = NULL;
+ result->ldc_rootsaslid = NULL;
+ result->ldc_rootusesasl = 0;
+#ifdef LDAP_VERSION3
+ result->ldc_version = LDAP_VERSION3;
+#else /* LDAP_VERSION3 */
+ result->ldc_version = LDAP_VERSION2;
+#endif /* not LDAP_VERSION3 */
+ result->ldc_timelimit = LDAP_NO_LIMIT;
+ result->ldc_bind_timelimit = 30;
+ result->ldc_ssl_on = SSL_OFF;
+ result->ldc_sslpath = NULL;
+ result->ldc_referrals = 1;
+ result->ldc_restart = 1;
+ result->ldc_tls_checkpeer = -1;
+ result->ldc_tls_cacertfile = NULL;
+ result->ldc_tls_cacertdir = NULL;
+ result->ldc_tls_ciphers = NULL;
+ result->ldc_tls_cert = NULL;
+ result->ldc_tls_key = NULL;
+ result->ldc_tls_randfile = NULL;
+ result->ldc_idle_timelimit = 0;
+ result->ldc_reconnect_pol = LP_RECONNECT_HARD_OPEN;
+ result->ldc_sasl_secprops = NULL;
+ result->ldc_srv_domain = NULL;
+ result->ldc_logdir = NULL;
+ result->ldc_debug = 0;
+ result->ldc_pagesize = LDAP_PAGESIZE;
+#ifdef CONFIGURE_KRB5_CCNAME
+ result->ldc_krb5_ccname = NULL;
+#endif /* CONFIGURE_KRB5_CCNAME */
+ result->ldc_flags = 0;
+#ifdef RFC2307BIS
+ result->ldc_flags |= NSS_LDAP_FLAGS_RFC2307BIS;
+#endif /* RFC2307BIS */
+#ifdef PAGE_RESULTS
+ result->ldc_flags |= NSS_LDAP_FLAGS_PAGED_RESULTS;
+#endif /* PAGE_RESULTS */
+ result->ldc_reconnect_tries = LDAP_NSS_TRIES;
+ result->ldc_reconnect_sleeptime = LDAP_NSS_SLEEPTIME;
+ result->ldc_reconnect_maxsleeptime = LDAP_NSS_MAXSLEEPTIME;
+ result->ldc_reconnect_maxconntries = LDAP_NSS_MAXCONNTRIES;
+ result->ldc_initgroups_ignoreusers = NULL;
+
+ for (i = 0; i <= LM_NONE; i++)
+ {
+ for (j = 0; j <= MAP_MAX; j++)
+ {
+ result->ldc_maps[i][j] = (void *)do_alloc_dictionary();
+ if (result->ldc_maps[i][j] == NULL)
+ return NSS_STATUS_UNAVAIL;
+ }
+ }
+
+ return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_ldap_add_uri (struct ldap_config *result, const char *uri,
+ char **buffer, size_t *buflen)
+{
+ /* add a single URI to the list of URIs in the configuration */
+ int i;
+ size_t uri_len;
+
+ debug ("==> _nss_ldap_add_uri");
+
+ for (i = 0; result->ldc_uris[i] != NULL; i++)
+ ;
+
+ if (i == NSS_LDAP_CONFIG_URI_MAX)
+ {
+ debug ("<== _nss_ldap_add_uri: maximum number of URIs exceeded");
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ assert (i < NSS_LDAP_CONFIG_URI_MAX);
+
+ uri_len = strlen (uri);
+
+ if (*buflen < uri_len + 1)
+ return NSS_STATUS_TRYAGAIN;
+
+ memcpy (*buffer, uri, uri_len + 1);
+
+ result->ldc_uris[i] = *buffer;
+ result->ldc_uris[i + 1] = NULL;
+
+ *buffer += uri_len + 1;
+ *buflen -= uri_len + 1;
+
+ debug ("<== _nss_ldap_add_uri: added URI %s", uri);
+
+ return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status
+do_add_uris (struct ldap_config *result, char *uris,
+ char **buffer, size_t *buflen)
+{
+ /* Add a space separated list of URIs */
+ char *p;
+ enum nss_status status = NSS_STATUS_SUCCESS;
+
+ for (p = uris; p != NULL; )
+ {
+ char *q = strchr (p, ' ');
+ if (q != NULL)
+ *q = '\0';
+
+ status = _nss_ldap_add_uri (result, p, buffer, buflen);
+
+ p = (q != NULL) ? ++q : NULL;
+
+ if (status != NSS_STATUS_SUCCESS)
+ break;
+ }
+
+ return status;
+}
+
+static enum nss_status
+do_add_hosts (struct ldap_config *result, char *hosts,
+ char **buffer, size_t *buflen)
+{
+ /* Add a space separated list of hosts */
+ char *p;
+ enum nss_status status = NSS_STATUS_SUCCESS;
+
+ for (p = hosts; p != NULL; )
+ {
+ char b[NSS_LDAP_CONFIG_BUFSIZ];
+ char *q = strchr (p, ' ');
+
+ if (q != NULL)
+ *q = '\0';
+
+ snprintf (b, sizeof(b), "ldap://%s", p);
+
+ status = _nss_ldap_add_uri (result, b, buffer, buflen);
+
+ p = (q != NULL) ? ++q : NULL;
+
+ if (status != NSS_STATUS_SUCCESS)
+ break;
+ }
+
+ return status;
+}
+
+enum nss_status
+_nss_ldap_readconfig (struct ldap_config ** presult, char **buffer, size_t *buflen)
+{
+ FILE *fp;
+ char b[NSS_LDAP_CONFIG_BUFSIZ];
+ enum nss_status status = NSS_STATUS_SUCCESS;
+ struct ldap_config *result;
+ struct stat statbuf;
+
+ if (bytesleft (*buffer, *buflen, struct ldap_config *) < sizeof (struct ldap_config))
+ {
+ return NSS_STATUS_TRYAGAIN;
+ }
+ align (*buffer, *buflen, struct ldap_config *);
+ result = *presult = (struct ldap_config *) *buffer;
+ *buffer += sizeof (struct ldap_config);
+ *buflen -= sizeof (struct ldap_config);
+
+ status = _nss_ldap_init_config (result);
+ if (status != NSS_STATUS_SUCCESS)
+ {
+ return NSS_STATUS_SUCCESS;
+ }
+
+ fp = fopen (NSS_LDAP_PATH_CONF, "r");
+ if (fp == NULL)
+ {
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ if (fstat (fileno (fp), &statbuf) == 0)
+ result->ldc_mtime = statbuf.st_mtime;
+ else
+ result->ldc_mtime = 0;
+
+ while (fgets (b, sizeof (b), fp) != NULL)
+ {
+ char *k, *v;
+ int len;
+ char **t = NULL;
+
+ if (*b == '\n' || *b == '\r' || *b == '#')
+ continue;
+
+ k = b;
+ v = k;
+
+ /* skip past all characters in keyword */
+ while (*v != '\0' && *v != ' ' && *v != '\t')
+ v++;
+
+ if (*v == '\0')
+ continue;
+
+ /* terminate keyword */
+ *(v++) = '\0';
+
+ /* skip empty lines with more than 3 spaces at the start of the line */
+ /* rds.oliver@samera.com.py 01-set-2004 */
+ if (*v == '\n')
+ continue;
+
+ /* skip all whitespaces between keyword and value */
+ /* Lars Oergel <lars.oergel@innominate.de>, 05.10.2000 */
+ while (*v == ' ' || *v == '\t')
+ v++;
+
+ /* kick off all whitespaces and newline at the end of value */
+ /* Bob Guo <bob@mail.ied.ac.cn>, 08.10.2001 */
+
+ /* Also remove \r (CR) to be able to handle files in DOS format (lines
+ * terminated in CR LF). Alejandro Forero Cuervo
+ * <azul@freaks-unidos.net>, 10-may-2005 */
+
+ len = strlen (v) - 1;
+ while (v[len] == ' ' || v[len] == '\t' || v[len] == '\n' || v[len] == '\r')
+ --len;
+ v[++len] = '\0';
+
+ if (*buflen < (size_t) (len + 1))
+ {
+ status = NSS_STATUS_TRYAGAIN;
+ break;
+ }
+
+ if (!strcasecmp (k, NSS_LDAP_KEY_HOST))
+ {
+ status = do_add_hosts (result, v, buffer, buflen);
+ if (status != NSS_STATUS_SUCCESS)
+ break;
+ }
+ else if (!strcasecmp (k, NSS_LDAP_KEY_URI))
+ {
+ status = do_add_uris (result, v, buffer, buflen);
+ if (status != NSS_STATUS_SUCCESS)
+ break;
+ }
+ else if (!strcasecmp (k, NSS_LDAP_KEY_BASE))
+ {
+ t = &result->ldc_base;
+ }
+ else if (!strcasecmp (k, NSS_LDAP_KEY_BINDDN))
+ {
+ t = &result->ldc_binddn;
+ }
+ else if (!strcasecmp (k, NSS_LDAP_KEY_BINDPW))
+ {
+ t = &result->ldc_bindpw;
+ }
+ else if (!strcasecmp (k, NSS_LDAP_KEY_USESASL))
+ {
+ result->ldc_usesasl = (!strcasecmp (v, "on")
+ || !strcasecmp (v, "yes")
+ || !strcasecmp (v, "true"));
+ }
+ else if (!strcasecmp (k, NSS_LDAP_KEY_SASLID))
+ {
+ t = &result->ldc_saslid;
+ }
+ else if (!strcasecmp (k, NSS_LDAP_KEY_ROOTBINDDN))
+ {
+ t = &result->ldc_rootbinddn;
+ }
+ else if (!strcasecmp (k, NSS_LDAP_KEY_ROOTUSESASL))
+ {
+ result->ldc_rootusesasl = (!strcasecmp (v, "on")
+ || !strcasecmp (v, "yes")
+ || !strcasecmp (v, "true"));
+ }
+ else if (!strcasecmp (k, NSS_LDAP_KEY_ROOTSASLID))
+ {
+ t = &result->ldc_rootsaslid;
+ }
+ else if (!strcasecmp (k, NSS_LDAP_KEY_SSLPATH))
+ {
+ t = &result->ldc_sslpath;
+ }
+ else if (!strcasecmp (k, NSS_LDAP_KEY_SCOPE))
+ {
+ if (!strcasecmp (v, "sub"))
+ {
+ result->ldc_scope = LDAP_SCOPE_SUBTREE;
+ }
+ else if (!strcasecmp (v, "one"))
+ {
+ result->ldc_scope = LDAP_SCOPE_ONELEVEL;
+ }
+ else if (!strcasecmp (v, "base"))
+ {
+ result->ldc_scope = LDAP_SCOPE_BASE;
+ }
+ }
+ else if (!strcasecmp (k, NSS_LDAP_KEY_DEREF))
+ {
+ if (!strcasecmp (v, "never"))
+ {
+ result->ldc_deref = LDAP_DEREF_NEVER;
+ }
+ else if (!strcasecmp (v, "searching"))
+ {
+ result->ldc_deref = LDAP_DEREF_SEARCHING;
+ }
+ else if (!strcasecmp (v, "finding"))
+ {
+ result->ldc_deref = LDAP_DEREF_FINDING;
+ }
+ else if (!strcasecmp (v, "always"))
+ {
+ result->ldc_deref = LDAP_DEREF_ALWAYS;
+ }
+ }
+ else if (!strcasecmp (k, NSS_LDAP_KEY_PORT))
+ {
+ result->ldc_port = atoi (v);
+ }
+ else if (!strcasecmp (k, NSS_LDAP_KEY_SSL))
+ {
+ if (!strcasecmp (v, "on") || !strcasecmp (v, "yes")
+ || !strcasecmp (v, "true"))
+ {
+ result->ldc_ssl_on = SSL_LDAPS;
+ }
+ else if (!strcasecmp (v, "start_tls"))
+ {
+ result->ldc_ssl_on = SSL_START_TLS;
+ }
+ }
+ else if (!strcasecmp (k, NSS_LDAP_KEY_REFERRALS))
+ {
+ result->ldc_referrals = (!strcasecmp (v, "on")
+ || !strcasecmp (v, "yes")
+ || !strcasecmp (v, "true"));
+ }
+ else if (!strcasecmp (k, NSS_LDAP_KEY_RESTART))
+ {
+ result->ldc_restart = (!strcasecmp (v, "on")
+ || !strcasecmp (v, "yes")
+ || !strcasecmp (v, "true"));
+ }
+ else if (!strcasecmp (k, NSS_LDAP_KEY_LDAP_VERSION))
+ {
+ result->ldc_version = atoi (v);
+ }
+ else if (!strcasecmp (k, NSS_LDAP_KEY_TIMELIMIT))
+ {
+ result->ldc_timelimit = atoi (v);
+ }
+ else if (!strcasecmp (k, NSS_LDAP_KEY_BIND_TIMELIMIT))
+ {
+ result->ldc_bind_timelimit = atoi (v);
+ }
+ else if (!strcasecmp (k, NSS_LDAP_KEY_IDLE_TIMELIMIT))
+ {
+ result->ldc_idle_timelimit = atoi (v);
+ }
+ else if (!strcasecmp (k, NSS_LDAP_KEY_RECONNECT_POLICY))
+ {
+ if (!strcasecmp (v, "hard") ||
+ !strcasecmp (v, "hard_open"))
+ {
+ result->ldc_reconnect_pol = LP_RECONNECT_HARD_OPEN;
+ }
+ else if (!strcasecmp (v, "hard_init"))
+ {
+ result->ldc_reconnect_pol = LP_RECONNECT_HARD_INIT;
+ }
+ else if (!strcasecmp (v, "soft"))
+ {
+ result->ldc_reconnect_pol = LP_RECONNECT_SOFT;
+ }
+ }
+ else if (!strcasecmp (k, NSS_LDAP_KEY_RECONNECT_TRIES))
+ {
+ result->ldc_reconnect_tries = atoi (v);
+ }
+ else if (!strcasecmp (k, NSS_LDAP_KEY_RECONNECT_SLEEPTIME))
+ {
+ result->ldc_reconnect_sleeptime = atoi (v);
+ }
+ else if (!strcasecmp (k, NSS_LDAP_KEY_RECONNECT_MAXSLEEPTIME))
+ {
+ result->ldc_reconnect_maxsleeptime = atoi (v);
+ }
+ else if (!strcasecmp (k, NSS_LDAP_KEY_RECONNECT_MAXCONNTRIES))
+ {
+ result->ldc_reconnect_maxconntries = atoi (v);
+ }
+ else if (!strcasecmp (k, NSS_LDAP_KEY_SASL_SECPROPS))
+ {
+ t = &result->ldc_sasl_secprops;
+ }
+ else if (!strcasecmp (k, NSS_LDAP_KEY_LOGDIR))
+ {
+ t = &result->ldc_logdir;
+ }
+ else if (!strcasecmp (k, NSS_LDAP_KEY_DEBUG))
+ {
+ result->ldc_debug = atoi (v);
+ }
+ else if (!strcasecmp (k, NSS_LDAP_KEY_PAGESIZE))
+ {
+ result->ldc_pagesize = atoi (v);
+ }
+#ifdef CONFIGURE_KRB5_CCNAME
+ else if (!strcasecmp (k, NSS_LDAP_KEY_KRB5_CCNAME))
+ {
+ t = &result->ldc_krb5_ccname;
+ }
+#endif /* CONFIGURE_KRB5_CCNAME */
+ else if (!strcasecmp (k, "tls_checkpeer"))
+ {
+ if (!strcasecmp (v, "on") || !strcasecmp (v, "yes")
+ || !strcasecmp (v, "true"))
+ {
+ result->ldc_tls_checkpeer = 1;
+ }
+ else if (!strcasecmp (v, "off") || !strcasecmp (v, "no")
+ || !strcasecmp (v, "false"))
+ {
+ result->ldc_tls_checkpeer = 0;
+ }
+ }
+ else if (!strcasecmp (k, "tls_cacertfile"))
+ {
+ t = &result->ldc_tls_cacertfile;
+ }
+ else if (!strcasecmp (k, "tls_cacertdir"))
+ {
+ t = &result->ldc_tls_cacertdir;
+ }
+ else if (!strcasecmp (k, "tls_ciphers"))
+ {
+ t = &result->ldc_tls_ciphers;
+ }
+ else if (!strcasecmp (k, "tls_cert"))
+ {
+ t = &result->ldc_tls_cert;
+ }
+ else if (!strcasecmp (k, "tls_key"))
+ {
+ t = &result->ldc_tls_key;
+ }
+ else if (!strcasecmp (k, "tls_randfile"))
+ {
+ t = &result->ldc_tls_randfile;
+ }
+ else if (!strncasecmp (k, NSS_LDAP_KEY_MAP_ATTRIBUTE,
+ strlen (NSS_LDAP_KEY_MAP_ATTRIBUTE)))
+ {
+ do_parse_map_statement (result, v, MAP_ATTRIBUTE);
+ }
+ else if (!strncasecmp (k, NSS_LDAP_KEY_MAP_OBJECTCLASS,
+ strlen (NSS_LDAP_KEY_MAP_OBJECTCLASS)))
+ {
+ do_parse_map_statement (result, v, MAP_OBJECTCLASS);
+ }
+ else if (!strncasecmp (k, NSS_LDAP_KEY_SET_OVERRIDE,
+ strlen (NSS_LDAP_KEY_SET_OVERRIDE)))
+ {
+ do_parse_map_statement (result, v, MAP_OVERRIDE);
+ }
+ else if (!strncasecmp (k, NSS_LDAP_KEY_SET_DEFAULT,
+ strlen (NSS_LDAP_KEY_SET_DEFAULT)))
+ {
+ do_parse_map_statement (result, v, MAP_DEFAULT);
+ }
+ else if (!strcasecmp (k, NSS_LDAP_KEY_INITGROUPS))
+ {
+ if (!strcasecmp (v, "backlink"))
+ {
+ result->ldc_flags |= NSS_LDAP_FLAGS_INITGROUPS_BACKLINK;
+ }
+ else
+ {
+ result->ldc_flags &= ~(NSS_LDAP_FLAGS_INITGROUPS_BACKLINK);
+ }
+ }
+ else if (!strcasecmp (k, NSS_LDAP_KEY_SCHEMA))
+ {
+ if (!strcasecmp (v, "rfc2307bis"))
+ {
+ result->ldc_flags |= NSS_LDAP_FLAGS_RFC2307BIS;
+ }
+ else if (!strcasecmp (v, "rfc2307"))
+ {
+ result->ldc_flags &= ~(NSS_LDAP_FLAGS_RFC2307BIS);
+ }
+ }
+ else if (!strcasecmp (k, NSS_LDAP_KEY_PAGED_RESULTS))
+ {
+ if (!strcasecmp (v, "on")
+ || !strcasecmp (v, "yes")
+ || !strcasecmp (v, "true"))
+ {
+ result->ldc_flags |= NSS_LDAP_FLAGS_PAGED_RESULTS;
+ }
+ else
+ {
+ result->ldc_flags &= ~(NSS_LDAP_FLAGS_PAGED_RESULTS);
+ }
+ }
+ else if (!strcasecmp (k, NSS_LDAP_KEY_INITGROUPS_IGNOREUSERS))
+ {
+ status = do_parse_list (v, &result->ldc_initgroups_ignoreusers,
+ buffer, buflen);
+ if (status == NSS_STATUS_UNAVAIL)
+ {
+ break;
+ }
+ }
+ else if (!strcasecmp (k, NSS_LDAP_KEY_CONNECT_POLICY))
+ {
+ if (!strcasecmp (v, "oneshot"))
+ {
+ result->ldc_flags |= NSS_LDAP_FLAGS_CONNECT_POLICY_ONESHOT;
+ }
+ else if (!strcasecmp (v, "persist"))
+ {
+ result->ldc_flags &= ~(NSS_LDAP_FLAGS_CONNECT_POLICY_ONESHOT);
+ }
+ }
+ else if (!strcasecmp (k, NSS_LDAP_KEY_SRV_DOMAIN))
+ {
+ t = &result->ldc_srv_domain;
+ }
+ else
+ {
+ /*
+ * check whether the key is a naming context key
+ * if yes, parse; otherwise just return NSS_STATUS_SUCCESS
+ * so we can ignore keys we don't understand.
+ */
+ status =
+ do_searchdescriptorconfig (k, v, len, result->ldc_sds,
+ buffer, buflen);
+ if (status == NSS_STATUS_UNAVAIL)
+ {
+ break;
+ }
+ }
+
+ if (t != NULL)
+ {
+ strncpy (*buffer, v, len);
+ (*buffer)[len] = '\0';
+ *t = *buffer;
+ *buffer += len + 1;
+ *buflen -= len + 1;
+ }
+ }
+
+ fclose (fp);
+
+ if (status != NSS_STATUS_SUCCESS)
+ {
+ return status;
+ }
+
+ if (result->ldc_rootbinddn != NULL)
+ {
+ fp = fopen (NSS_LDAP_PATH_ROOTPASSWD, "r");
+ if (fp)
+ {
+ if (fgets (b, sizeof (b), fp) != NULL)
+ {
+ int len;
+
+ len = strlen (b);
+ /* BUG#138: check for newline before removing */
+ if (len > 0 && b[len - 1] == '\n')
+ len--;
+
+ if (*buflen < (size_t) (len + 1))
+ {
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ strncpy (*buffer, b, len);
+ (*buffer)[len] = '\0';
+ result->ldc_rootbindpw = *buffer;
+ *buffer += len + 1;
+ *buflen -= len + 1;
+ }
+ fclose (fp);
+ }
+ else if (!result->ldc_rootusesasl)
+ {
+ result->ldc_rootbinddn = NULL;
+ }
+ }
+
+ if (result->ldc_port == 0)
+ {
+ if (result->ldc_ssl_on == SSL_LDAPS)
+ {
+ result->ldc_port = LDAPS_PORT;
+ }
+ else
+ {
+ result->ldc_port = LDAP_PORT;
+ }
+ }
+
+ if (result->ldc_uris[0] == NULL)
+ {
+ status = NSS_STATUS_NOTFOUND;
+ }
+
+ return status;
+}
+
+enum nss_status
+_nss_ldap_escape_string (const char *str, char *buf, size_t buflen)
+{
+ int ret = NSS_STATUS_TRYAGAIN;
+ char *p = buf;
+ char *limit = p + buflen - 3;
+ const char *s = str;
+
+ while (p < limit && *s)
+ {
+ switch (*s)
+ {
+ case '*':
+ strcpy (p, "\\2a");
+ p += 3;
+ break;
+ case '(':
+ strcpy (p, "\\28");
+ p += 3;
+ break;
+ case ')':
+ strcpy (p, "\\29");
+ p += 3;
+ break;
+ case '\\':
+ strcpy (p, "\\5c");
+ p += 3;
+ break;
+ default:
+ *p++ = *s;
+ break;
+ }
+ s++;
+ }
+
+ if (*s == '\0')
+ {
+ /* got to end */
+ *p = '\0';
+ ret = NSS_STATUS_SUCCESS;
+ }
+
+ return ret;
+}
+
+/* XXX just a linked list for now */
+
+struct ldap_dictionary
+{
+ struct ldap_datum key;
+ struct ldap_datum value;
+ struct ldap_dictionary *next;
+};
+
+static struct ldap_dictionary *do_alloc_dictionary(void)
+{
+ struct ldap_dictionary *dict;
+
+ dict = malloc (sizeof (*dict));
+ if (dict == NULL)
+ {
+ return NULL;
+ }
+ NSS_LDAP_DATUM_ZERO (&dict->key);
+ NSS_LDAP_DATUM_ZERO (&dict->value);
+ dict->next = NULL;
+
+ return dict;
+}
+
+static void
+do_free_datum (struct ldap_datum * datum)
+{
+ if (datum->data != NULL)
+ {
+ free (datum->data);
+ datum->data = NULL;
+ }
+ datum->size = 0;
+}
+
+static struct ldap_dictionary *
+do_find_last (struct ldap_dictionary *dict)
+{
+ struct ldap_dictionary *p;
+
+ for (p = dict; p->next != NULL; p = p->next)
+ ;
+
+ return p;
+}
+
+static void
+do_free_dictionary (struct ldap_dictionary *dict)
+{
+ do_free_datum (&dict->key);
+ do_free_datum (&dict->value);
+ free (dict);
+}
+
+static enum nss_status
+do_dup_datum (unsigned flags, struct ldap_datum * dst, const struct ldap_datum * src)
+{
+ dst->data = malloc (src->size);
+ if (dst->data == NULL)
+ return NSS_STATUS_TRYAGAIN;
+
+ memcpy (dst->data, src->data, src->size);
+ dst->size = src->size;
+
+ return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_ldap_db_get (void *db,
+ unsigned flags,
+ const struct ldap_datum * key,
+ struct ldap_datum * value)
+{
+ struct ldap_dictionary *dict = (struct ldap_dictionary *) db;
+ struct ldap_dictionary *p;
+
+ for (p = dict; p != NULL; p = p->next)
+ {
+ int cmp;
+
+ if (p->key.size != key->size)
+ continue;
+
+ if (flags & NSS_LDAP_DB_NORMALIZE_CASE)
+ cmp = strncasecmp ((char *)p->key.data, (char *)key->data, key->size);
+ else
+ cmp = memcmp (p->key.data, key->data, key->size);
+
+ if (cmp == 0)
+ {
+ value->data = p->value.data;
+ value->size = p->value.size;
+
+ return NSS_STATUS_SUCCESS;
+ }
+ }
+
+ return NSS_STATUS_NOTFOUND;
+}
+
+enum nss_status
+_nss_ldap_db_put (void *db,
+ unsigned flags,
+ const struct ldap_datum * key,
+ const struct ldap_datum * value)
+{
+ struct ldap_dictionary *dict = (struct ldap_dictionary *) db;
+ struct ldap_dictionary *p, *q;
+
+ assert (key != NULL);
+ assert (key->data != NULL);
+
+ if (dict->key.data == NULL)
+ {
+ /* uninitialized */
+ q = dict;
+ p = NULL;
+ }
+ else
+ {
+ p = do_find_last (dict);
+ assert (p != NULL);
+ assert (p->next == NULL);
+ q = do_alloc_dictionary();
+ if (q == NULL)
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ if (do_dup_datum (flags, &q->key, key) != NSS_STATUS_SUCCESS)
+ {
+ do_free_dictionary (q);
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ if (do_dup_datum (flags, &q->value, value) != NSS_STATUS_SUCCESS)
+ {
+ do_free_dictionary (q);
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ if (p != NULL)
+ p->next = q;
+
+ return NSS_STATUS_SUCCESS;
+}
+
+/*
+ * Add a nested netgroup or group to the namelist
+ */
+enum nss_status
+_nss_ldap_namelist_push (struct name_list **head, const char *name)
+{
+ struct name_list *nl;
+
+ debug ("==> _nss_ldap_namelist_push (%s)", name);
+
+ nl = (struct name_list *) malloc (sizeof (*nl));
+ if (nl == NULL)
+ {
+ debug ("<== _nss_ldap_namelist_push");
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ nl->name = strdup (name);
+ if (nl->name == NULL)
+ {
+ debug ("<== _nss_ldap_namelist_push");
+ free (nl);
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ nl->next = *head;
+
+ *head = nl;
+
+ debug ("<== _nss_ldap_namelist_push");
+
+ return NSS_STATUS_SUCCESS;
+}
+
+/*
+ * Remove last nested netgroup or group from the namelist
+ */
+void
+_nss_ldap_namelist_pop (struct name_list **head)
+{
+ struct name_list *nl;
+
+ debug ("==> _nss_ldap_namelist_pop");
+
+ assert (*head != NULL);
+ nl = *head;
+
+ *head = nl->next;
+
+ assert (nl->name != NULL);
+ free (nl->name);
+ free (nl);
+
+ debug ("<== _nss_ldap_namelist_pop");
+}
+
+/*
+ * Cleanup nested netgroup or group namelist.
+ */
+void
+_nss_ldap_namelist_destroy (struct name_list **head)
+{
+ struct name_list *p, *next;
+
+ debug ("==> _nss_ldap_namelist_destroy");
+
+ for (p = *head; p != NULL; p = next)
+ {
+ next = p->next;
+
+ if (p->name != NULL)
+ free (p->name);
+ free (p);
+ }
+
+ *head = NULL;
+
+ debug ("<== _nss_ldap_namelist_destroy");
+}
+
+/*
+ * Check whether we have already seen a netgroup or group,
+ * to avoid loops in nested netgroup traversal
+ */
+int
+_nss_ldap_namelist_find (struct name_list *head, const char *netgroup)
+{
+ struct name_list *p;
+ int found = 0;
+
+ debug ("==> _nss_ldap_namelist_find");
+
+ for (p = head; p != NULL; p = p->next)
+ {
+ if (strcasecmp (p->name, netgroup) == 0)
+ {
+ found++;
+ break;
+ }
+ }
+
+ debug ("<== _nss_ldap_namelist_find");
+
+ return found;
+}
+
+enum nss_status _nss_ldap_validateconfig (struct ldap_config *config)
+{
+ struct stat statbuf;
+
+ if (config == NULL)
+ {
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ if (config->ldc_mtime == 0)
+ {
+ return NSS_STATUS_SUCCESS;
+ }
+
+ if (stat (NSS_LDAP_PATH_CONF, &statbuf) == 0)
+ {
+ return (statbuf.st_mtime > config->ldc_mtime) ? NSS_STATUS_TRYAGAIN : NSS_STATUS_SUCCESS;
+ }
+
+ return NSS_STATUS_SUCCESS;
+}
+
diff --git a/nslcd/util.h b/nslcd/util.h
new file mode 100644
index 0000000..f193916
--- /dev/null
+++ b/nslcd/util.h
@@ -0,0 +1,121 @@
+/*
+ util.h - LDAP utility functions
+ This file was part of the nss_ldap library which has been
+ forked into the nss-ldapd library.
+
+ Copyright (C) 1997-2005 Luke Howard
+ Copyright (C) 2006 West Consulting
+ Copyright (C) 2006 Arthur de Jong
+
+ This 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+#ifndef _LDAP_NSS_LDAP_UTIL_H
+#define _LDAP_NSS_LDAP_UTIL_H
+
+/*
+ * get the RDN's value: eg. if the RDN was cn=lukeh, getrdnvalue(entry)
+ * would return lukeh.
+ */
+enum nss_status _nss_ldap_getrdnvalue(LDAPMessage *entry,
+ const char *rdntype,
+ char **rval, char **buf, size_t * len);
+
+int _nss_ldap_write_rndvalue(FILE *fp,LDAPMessage *entry,const char *rdntype);
+
+/*
+ * map a distinguished name to a login name, or group entry
+ */
+enum nss_status _nss_ldap_dn2uid (const char *dn,
+ char **uid, char **buf, size_t * len,
+ int *pIsNestedGroup, LDAPMessage ** pRes);
+
+
+#define NSS_LDAP_CONFIG_BUFSIZ 4096
+
+/*
+ * support separate naming contexts for each map
+ * eventually this will support the syntax defined in
+ * the DUAConfigProfile searchDescriptor attribute
+ */
+#define NSS_LDAP_KEY_NSS_BASE_PREFIX "nss_base_"
+#define NSS_LDAP_KEY_NSS_BASE_PREFIX_LEN ( sizeof(NSS_LDAP_KEY_NSS_BASE_PREFIX) - 1 )
+
+/*
+ * Flags that are exposed via _nss_ldap_test_config_flag()
+ */
+#define NSS_LDAP_FLAGS_INITGROUPS_BACKLINK 0x0001
+#define NSS_LDAP_FLAGS_PAGED_RESULTS 0x0002
+#define NSS_LDAP_FLAGS_RFC2307BIS 0x0004
+#define NSS_LDAP_FLAGS_CONNECT_POLICY_ONESHOT 0x0008
+
+/*
+ * There are a number of means of obtaining configuration information.
+ *
+ * (a) DHCP (Cf draft-hedstrom-dhc-ldap-00.txt)
+ * (b) a configuration file (/etc/ldap.conf) **
+ * (c) a coldstart file & subsequent referrals from the LDAP server
+ * (d) a custom LDAP bind protocol
+ * (e) DNS **
+ *
+ * This should be opaque to the rest of the library.
+ * ** implemented
+ */
+
+enum nss_status _nss_ldap_readconfig (struct ldap_config ** result, char **buffer, size_t *buflen);
+enum nss_status _nss_ldap_validateconfig (struct ldap_config *config);
+
+/*
+ * Escape '*' in a string for use as a filter
+ */
+
+enum nss_status _nss_ldap_escape_string (const char *str,
+ char *buf, size_t buflen);
+
+struct ldap_datum
+{
+ void *data;
+ size_t size;
+};
+
+#define NSS_LDAP_DATUM_ZERO(d) do { \
+ (d)->data = NULL; \
+ (d)->size = 0; \
+ } while (0)
+
+#define NSS_LDAP_DB_NORMALIZE_CASE 0x1
+
+enum nss_status _nss_ldap_db_put (void *db,
+ unsigned flags,
+ const struct ldap_datum * key,
+ const struct ldap_datum * value);
+enum nss_status _nss_ldap_db_get (void *db,
+ unsigned flags,
+ const struct ldap_datum * key,
+ struct ldap_datum * value);
+
+/* Routines for managing namelists */
+
+enum nss_status _nss_ldap_namelist_push (struct name_list **head, const char *name);
+void _nss_ldap_namelist_pop (struct name_list **head);
+int _nss_ldap_namelist_find (struct name_list *head, const char *netgroup);
+void _nss_ldap_namelist_destroy (struct name_list **head);
+
+enum nss_status
+_nss_ldap_add_uri (struct ldap_config *result, const char *uri,
+ char **buffer, size_t *buflen);
+
+#endif /* _LDAP_NSS_LDAP_UTIL_H */
diff --git a/nslcd/xmalloc.c b/nslcd/xmalloc.c
new file mode 100644
index 0000000..9dbd9a4
--- /dev/null
+++ b/nslcd/xmalloc.c
@@ -0,0 +1,59 @@
+/*
+ xmalloc.c - malloc wrapper
+
+ Copyright (C) 2002, 2003, 2006 Arthur de Jong
+
+ This 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "xmalloc.h"
+#include "log.h"
+
+
+/* malloc wrapper */
+void *xmalloc(size_t size)
+{
+ void *tmp;
+ if ((tmp=malloc(size))==NULL)
+ {
+ log_log(LOG_CRIT,"malloc() failed");
+ exit(1);
+ }
+ return tmp;
+}
+
+
+/* strdup wrapper */
+char *xstrdup(const char *s)
+{
+ char *tmp;
+ int l;
+ if (s==NULL)
+ {
+ log_log(LOG_CRIT,"xstrdup() called with NULL");
+ exit(1);
+ }
+ l=strlen(s);
+ tmp=(char *)xmalloc((l+1)*sizeof(char));
+ strncpy(tmp,s,l);
+ tmp[l]='\0';
+ return tmp;
+}
diff --git a/nslcd/xmalloc.h b/nslcd/xmalloc.h
new file mode 100644
index 0000000..04ad025
--- /dev/null
+++ b/nslcd/xmalloc.h
@@ -0,0 +1,36 @@
+/*
+ xmalloc.h - malloc wrapper
+
+ Copyright (C) 2002 Arthur de Jong
+
+ This 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301 USA
+*/
+
+#ifndef _XMALLOC_H
+#define _XMALLOC_H 1
+
+#include <stdlib.h>
+
+/* malloc wrapper */
+void *xmalloc(size_t size);
+
+/* allocate size for a specific type */
+#define xxmalloc(type,count) (type *)xmalloc(sizeof(type)*(count))
+
+/* strdup wrapper */
+char *xstrdup(const char *s);
+
+#endif /* not _XMALLOC_H */