summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArthur de Jong <arthur@arthurdejong.org>2011-08-05 21:28:23 +0000
committerArthur de Jong <arthur@arthurdejong.org>2011-08-05 21:28:23 +0000
commite267ef351a3f0e5bb36faba777d9963dcfdc7bca (patch)
tree7f9e792179c24e7e74b205ea021b4486ad686231
parenta63c0da4aad5f5d3c50ebc988eb822e5bed0701f (diff)
check whether the NSS shadow map queries LDAP before returning x as a password has for shadow users
git-svn-id: http://arthurdejong.org/svn/nss-pam-ldapd/nss-pam-ldapd@1487 ef36b2f9-881f-0410-afb5-c4e39611909c
-rw-r--r--nslcd/Makefile.am3
-rw-r--r--nslcd/common.h4
-rw-r--r--nslcd/nsswitch.c116
-rw-r--r--nslcd/passwd.c17
-rw-r--r--tests/Makefile.am2
5 files changed, 137 insertions, 5 deletions
diff --git a/nslcd/Makefile.am b/nslcd/Makefile.am
index 0e2abe2..2f259dd 100644
--- a/nslcd/Makefile.am
+++ b/nslcd/Makefile.am
@@ -1,7 +1,7 @@
# Makefile.am - use automake to generate Makefile.in
#
# Copyright (C) 2006, 2007 West Consulting
-# Copyright (C) 2006, 2007, 2008, 2009 Arthur de Jong
+# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Arthur de Jong
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -30,6 +30,7 @@ nslcd_SOURCES = nslcd.c ../nslcd.h ../common/nslcd-prot.h \
myldap.c myldap.h \
cfg.c cfg.h \
attmap.c attmap.h \
+ nsswitch.c \
alias.c ether.c group.c host.c netgroup.c network.c \
passwd.c protocol.c rpc.c service.c shadow.c pam.c
nslcd_LDADD = @nslcd_LIBS@ @PTHREAD_LIBS@ ../common/libtio.a ../common/libdict.a \
diff --git a/nslcd/common.h b/nslcd/common.h
index b8c2367..a998bff 100644
--- a/nslcd/common.h
+++ b/nslcd/common.h
@@ -120,6 +120,10 @@ void get_shadow_properties(MYLDAP_ENTRY *entry,long *lastchangedate,
long *mindays,long *maxdays,long *warndays,
long *inactdays,long *expiredate,unsigned long *flag);
+
+/* check whether the nsswitch.conf file has LDAP as a naming source for db */
+int nsswitch_db_uses_ldap(const char *filename,const char *db);
+
/* fallback definition of HOST_NAME_MAX */
#ifndef HOST_NAME_MAX
#ifdef _POSIX_HOST_NAME_MAX
diff --git a/nslcd/nsswitch.c b/nslcd/nsswitch.c
new file mode 100644
index 0000000..13782c6
--- /dev/null
+++ b/nslcd/nsswitch.c
@@ -0,0 +1,116 @@
+/*
+ nsswitch.c - functions for parsing /etc/nsswitch.conf
+
+ Copyright (C) 2011 Arthur de Jong
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA
+*/
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "log.h"
+
+/* the maximum line length supported of nsswitch.conf */
+#define MAX_LINE_LENGTH 4096
+
+
+/* TODO: store mtime of file and use it to check reparse */
+/* TODO: cache entries for x minutes */
+
+/* see if the line is a service definition for db and return a pointer to
+ the beginning of the services list if it is */
+static const char *find_db(const char *line,const char *db)
+{
+ int i;
+ i=strlen(db);
+ /* the line should begin with the db we're looking for */
+ if (strncmp(line,db,i)!=0)
+ return NULL;
+ /* followed by a : */
+ while (isspace(line[i])) i++;
+ if (line[i]!=':')
+ return NULL;
+ i++;
+ while (isspace(line[i])) i++;
+ return line+i;
+}
+
+/* check to see if the list of services contains the specified service */
+static int has_service(const char *services,const char *service,
+ const char *filename,int lnr)
+{
+ int i=0,l;
+ if (services==NULL)
+ return 0;
+ l=strlen(service);
+ while (services[i]!='\0')
+ {
+ /* skip spaces */
+ while (isspace(services[i])) i++;
+ /* check if this is the service */
+ if ((strncmp(services+i,service,l)==0)&&(!isalnum(services[i+l])))
+ return 1;
+ /* skip service name and spaces */
+ i++;
+ while (isalnum(services[i])) i++;
+ while (isspace(services[i])) i++;
+ /* skip action mappings */
+ if (services[i]=='[')
+ {
+ i++; /* skip [ */
+ while ((services[i]!=']')&&(services[i]!='\0')) i++;
+ if (services[i]!=']')
+ {
+ log_log(LOG_WARNING,"%s: error parsing line %d",filename,lnr);
+ return 0; /* parse error */
+ }
+ i++; /* skip ] */
+ }
+ }
+ return 0;
+}
+
+int nsswitch_db_uses_ldap(const char *filename,const char *db)
+{
+ FILE *fp;
+ int lnr=0;
+ char linebuf[MAX_LINE_LENGTH];
+ const char *services;
+ /* open config file */
+ if ((fp=fopen(filename,"r"))==NULL)
+ {
+ log_log(LOG_ERR,"cannot open %s: %s",filename,strerror(errno));
+ return 0;
+ }
+ /* read file and parse lines */
+ while (fgets(linebuf,sizeof(linebuf),fp)!=NULL)
+ {
+ lnr++;
+ services=find_db(linebuf,db);
+ if ((services!=NULL)&&has_service(services,"ldap",filename,lnr))
+ {
+ fclose(fp);
+ return 1;
+ }
+ }
+ fclose(fp);
+ return 0;
+}
diff --git a/nslcd/passwd.c b/nslcd/passwd.c
index c7a5dde..d22c63e 100644
--- a/nslcd/passwd.c
+++ b/nslcd/passwd.c
@@ -377,6 +377,17 @@ char *uid2dn(MYLDAP_SESSION *session,const char *uid,char *buf,size_t buflen)
return myldap_cpy_dn(entry,buf,buflen);
}
+#define CACHED_UNKNOWN 22
+static int cached_shadow_uses_ldap=CACHED_UNKNOWN;
+
+/* check whether shadow lookups are configured to use ldap */
+static int shadow_uses_ldap(void)
+{
+ if (cached_shadow_uses_ldap==CACHED_UNKNOWN)
+ cached_shadow_uses_ldap=nsswitch_db_uses_ldap("/etc/nsswitch.conf","shadow");
+ return cached_shadow_uses_ldap;
+}
+
/* the maximum number of uidNumber attributes per entry */
#define MAXUIDS_PER_ENTRY 5
@@ -405,10 +416,10 @@ static int write_passwd(TFILE *fp,MYLDAP_ENTRY *entry,const char *requser,
myldap_get_dn(entry),attmap_passwd_uid);
return 0;
}
- /* get the password for this entry */
- if (myldap_has_objectclass(entry,"shadowAccount"))
+ /* if we are using shadow maps and this entry looks like it would return
+ shadow information, make the passwd entry indicate it */
+ if (myldap_has_objectclass(entry,"shadowAccount")&&shadow_uses_ldap())
{
- /* if the entry has a shadowAccount entry, point to that instead */
passwd="x";
}
else
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 7ef204d..42fd0eb 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -55,7 +55,7 @@ test_getpeercred_LDADD = ../compat/libcompat.a
# common objects that are included for the tests of nslcd functionality
common_nslcd_LDADD = ../nslcd/log.o ../nslcd/common.o \
- ../nslcd/myldap.o ../nslcd/attmap.o \
+ ../nslcd/myldap.o ../nslcd/attmap.o ../nslcd/nsswitch.o \
../nslcd/alias.o ../nslcd/ether.o ../nslcd/group.o \
../nslcd/host.o ../nslcd/netgroup.o ../nslcd/network.o \
../nslcd/passwd.o ../nslcd/protocol.o ../nslcd/rpc.o \