diff options
author | Arthur de Jong <arthur@arthurdejong.org> | 2011-08-05 21:28:23 +0000 |
---|---|---|
committer | Arthur de Jong <arthur@arthurdejong.org> | 2011-08-05 21:28:23 +0000 |
commit | e267ef351a3f0e5bb36faba777d9963dcfdc7bca (patch) | |
tree | 7f9e792179c24e7e74b205ea021b4486ad686231 | |
parent | a63c0da4aad5f5d3c50ebc988eb822e5bed0701f (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.am | 3 | ||||
-rw-r--r-- | nslcd/common.h | 4 | ||||
-rw-r--r-- | nslcd/nsswitch.c | 116 | ||||
-rw-r--r-- | nslcd/passwd.c | 17 | ||||
-rw-r--r-- | tests/Makefile.am | 2 |
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 \ |