summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArthur de Jong <arthur@arthurdejong.org>2009-12-28 12:18:12 +0000
committerArthur de Jong <arthur@arthurdejong.org>2009-12-28 12:18:12 +0000
commit9c0cf90c858dd020756d7cd51661beedacdf9924 (patch)
tree215b28b4e0f754819590185e02e290df814c5b74
parent93182ac6939bece7e538bc06e5f09f47bcaddf8a (diff)
implement attribute mapping using shell-like expressions
git-svn-id: http://arthurdejong.org/svn/nss-pam-ldapd/nss-pam-ldapd@1041 ef36b2f9-881f-0410-afb5-c4e39611909c
-rw-r--r--common/Makefile.am6
-rw-r--r--common/expr.c207
-rw-r--r--common/expr.h41
-rw-r--r--man/nslcd.conf.5.xml79
-rw-r--r--nslcd.conf2
-rw-r--r--nslcd/Makefile.am2
-rw-r--r--nslcd/attmap.c86
-rw-r--r--nslcd/attmap.h18
-rw-r--r--nslcd/cfg.c12
-rw-r--r--nslcd/passwd.c104
-rw-r--r--nslcd/shadow.c89
-rw-r--r--tests/Makefile.am13
-rw-r--r--tests/test_cfg.c1
-rw-r--r--tests/test_common.c5
-rw-r--r--tests/test_expr.c146
-rw-r--r--tests/test_myldap.c5
16 files changed, 657 insertions, 159 deletions
diff --git a/common/Makefile.am b/common/Makefile.am
index 1120b07..df90b8e 100644
--- a/common/Makefile.am
+++ b/common/Makefile.am
@@ -1,6 +1,6 @@
# Makefile.am - use automake to generate Makefile.in
#
-# Copyright (C) 2007, 2008 Arthur de Jong
+# Copyright (C) 2007, 2008, 2009 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
@@ -17,7 +17,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
-noinst_LIBRARIES = libtio.a libprot.a libdict.a
+noinst_LIBRARIES = libtio.a libprot.a libdict.a libexpr.a
AM_CPPFLAGS=-I$(top_srcdir)
AM_CFLAGS = -fPIC
@@ -28,3 +28,5 @@ libprot_a_SOURCES = nslcd-prot.c nslcd-prot.h
libdict_a_SOURCES = dict.c dict.h \
set.c set.h
+
+libexpr_a_SOURCES = expr.c expr.h
diff --git a/common/expr.c b/common/expr.c
new file mode 100644
index 0000000..679d8b7
--- /dev/null
+++ b/common/expr.c
@@ -0,0 +1,207 @@
+/*
+ expr.c - limited shell-like expression parsing functions
+ This file is part of the nss-pam-ldapd library.
+
+ Copyright (C) 2009 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 <stdlib.h>
+#include <string.h>
+
+#include "expr.h"
+
+/* the maximum length of a variable name */
+#define MAXVARLENGTH 30
+
+static inline int my_isalpha(const char c)
+{
+ return ((c>='a')&&(c<='z'))||((c>='A')&&(c<='Z'));
+}
+
+static inline int my_isalphanum(const char c)
+{
+ return my_isalpha(c)||((c>='0')&&(c<='9'));
+}
+
+#include <stdio.h>
+
+/* return the part of the string that is a valid name */
+MUST_USE static const char *parse_name(const char *str,int *ptr,char *buffer,size_t buflen)
+{
+ int i=0;
+ /* clear the buffer */
+ buffer[i]='\0';
+ /* look for an alpha+alphanumeric* string */
+ if (!my_isalpha(str[*ptr]))
+ return NULL;
+ while (my_isalphanum(str[*ptr]))
+ {
+ if ((size_t)i>=buflen)
+ return NULL;
+ buffer[i++]=str[(*ptr)++];
+ }
+ /* NULL-terminate the string */
+ if ((size_t)i>=buflen)
+ return NULL;
+ buffer[i++]='\0';
+ return buffer;
+}
+
+/* definition of the parse functions (they call eachother) */
+MUST_USE static const char *parse_dollar_expression(
+ const char *str,int *ptr,char *buffer,size_t buflen,
+ expander_t expander,void *expander_arg);
+MUST_USE static const char *parse_expression(
+ const char *str,int *ptr,int endat,char *buffer,size_t buflen,
+ expander_t expander,void *expander_arg);
+
+MUST_USE static const char *parse_dollar_expression(
+ const char *str,int *ptr,char *buffer,size_t buflen,
+ expander_t expander,void *expander_arg)
+{
+ char varname[MAXVARLENGTH];
+ const char *varvalue;
+ if ((buflen<=0)||(buffer==NULL)||(str==NULL)||(ptr==NULL))
+ return NULL;
+ if (str[*ptr]=='{')
+ {
+ (*ptr)++;
+ /* the first part is always a variable name */
+ if (parse_name(str,ptr,varname,sizeof(varname))==NULL)
+ return NULL;
+ varvalue=expander(varname,expander_arg);
+ if (str[*ptr]=='}')
+ {
+ /* simple substitute */
+ if (strlen(varvalue)>=buflen)
+ return NULL;
+ strcpy(buffer,varvalue);
+ }
+ else if (strncmp(str+*ptr,":-",2)==0)
+ {
+ /* if variable is not set or empty, substitute remainder */
+ (*ptr)+=2;
+ if (parse_expression(str,ptr,'}',buffer,buflen,expander,expander_arg)==NULL)
+ return NULL;
+ if ((varvalue!=NULL)&&(*varvalue!='\0'))
+ {
+ if (strlen(varvalue)>=buflen)
+ return NULL;
+ strcpy(buffer,varvalue);
+ }
+ }
+ else if (strncmp(str+*ptr,":+",2)==0)
+ {
+ /* if variable is set, substitute remainer */
+ (*ptr)+=2;
+ if (parse_expression(str,ptr,'}',buffer,buflen,expander,expander_arg)==NULL)
+ return NULL;
+ if ((varvalue==NULL)||(*varvalue=='\0'))
+ buffer[0]='\0';
+ }
+ else
+ return NULL;
+ (*ptr)++; /* skip closing } */
+ }
+ else
+ {
+ /* it is a simple reference to a variable, like $uidNumber */
+ if (parse_name(str,ptr,varname,sizeof(varname))==NULL)
+ return NULL;
+ varvalue=expander(varname,expander_arg);
+ if (strlen(varvalue)>=buflen)
+ return NULL;
+ strcpy(buffer,varvalue);
+ }
+ return buffer;
+}
+
+MUST_USE static const char *parse_expression(
+ const char *str,int *ptr,int endat,char *buffer,size_t buflen,
+ expander_t expander,void *expander_arg)
+{
+ int j=0;
+ /* go over string */
+ while ((str[*ptr]!=endat)&&(str[*ptr]!='\0'))
+ {
+ switch (str[*ptr])
+ {
+ case '$': /* beginning of an expression */
+ (*ptr)++;
+ if ((size_t)j>=buflen)
+ return NULL;
+ if (parse_dollar_expression(str,ptr,buffer+j,buflen-j,expander,expander_arg)==NULL)
+ return NULL;
+ j=strlen(buffer);
+ break;
+ case '\\': /* escaped character, unescape */
+ (*ptr)++;
+ default: /* just copy the text */
+ if ((size_t)j>=buflen)
+ return NULL;
+ buffer[j++]=str[*ptr];
+ (*ptr)++;
+ }
+ }
+ /* NULL-terminate buffer */
+ if ((size_t)j>=buflen)
+ return NULL;
+ buffer[j++]='\0';
+ return buffer;
+}
+
+MUST_USE const char *expr_parse(const char *str,char *buffer,size_t buflen,
+ expander_t expander,void *expander_arg)
+
+{
+ int i=0;
+ return parse_expression(str,&i,'\0',buffer,buflen,expander,expander_arg);
+}
+
+SET *expr_vars(const char *str,SET *set)
+{
+ char varname[MAXVARLENGTH];
+ int i=0;
+ /* allocate set if needed */
+ if (set==NULL)
+ set=set_new();
+ if (set==NULL)
+ return NULL;
+ /* go over string */
+ while (str[i]!='\0')
+ {
+ switch (str[i])
+ {
+ case '$': /* beginning of a $-expression */
+ i++;
+ if (str[i]=='{')
+ i++;
+ /* the rest should start with a variable name */
+ if (parse_name(str,&i,varname,sizeof(varname))!=NULL)
+ set_add(set,varname);
+ break;
+ case '\\': /* escaped character, unescape */
+ i++;
+ default: /* just skip */
+ i++;
+ }
+ }
+ return set;
+}
diff --git a/common/expr.h b/common/expr.h
new file mode 100644
index 0000000..9861a49
--- /dev/null
+++ b/common/expr.h
@@ -0,0 +1,41 @@
+/*
+ expr.h - limited shell-like expression parsing functions
+ This file is part of the nss-pam-ldapd library.
+
+ Copyright (C) 2009 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
+*/
+
+#ifndef _EXPR_H
+#define _EXPR_H 1
+
+#include "compat/attrs.h"
+#include "common/set.h"
+
+typedef const char *(*expander_t)(const char *name,void *expander_arg);
+
+/* Parse the expression and store the result in buffer, using the
+ expander function to expand variable names to values. If the expression
+ is invalid or the result didn't fit in the buffer NULL is returned. */
+MUST_USE const char *expr_parse(const char *expr,char *buffer,size_t buflen,
+ expander_t expander,void *expander_arg);
+
+/* Return the variable names that are used in expr. If set is NULL a new one
+ is allocated, otherwise the passed set is added to. */
+SET *expr_vars(const char *expr,SET *set);
+
+#endif /* not _EXPR_H */
diff --git a/man/nslcd.conf.5.xml b/man/nslcd.conf.5.xml
index b553354..704bd58 100644
--- a/man/nslcd.conf.5.xml
+++ b/man/nslcd.conf.5.xml
@@ -375,13 +375,13 @@
<code>ipProtocolNumber</code> or <code>macAddress</code>).
The <emphasis remap="I">NEWATTRIBUTE</emphasis> may be any attribute
as it is available in the directory.
-<!--
+ </para>
+ <para>
If the <emphasis remap="I">NEWATTRIBUTE</emphasis> is presented in
- quotes (") the specfied value will be used instead of looking up the
- value in the directory.
- Specifies a value to use for the specified attribute in preference
- to that contained in the actual entry.
--->
+ quotes (") it is treated as an expression which will be evaluated
+ to build up the actual value used.
+ Not all attributes can be mapped this way.
+ See the section on attribute mapping below for more details.
</para>
</listitem>
</varlistentry>
@@ -686,6 +686,73 @@
</variablelist>
</refsect1>
+ <refsect1 id="attmappingexpressions">
+ <title>Attribute mapping expressions</title>
+ <para>
+ For some attributes a mapping expression may be used to construct the
+ resulting value. This is currently only possible for attributes that do
+ not need to be used in search filters.
+ </para>
+ <para>
+ The expressions are a subset of the double quoted string expressions in the
+ Bourne (POSIX) shell.
+ Instead of variable substitution, attribute lookups are done on the current
+ entry and the attribute value is substituted.
+ The following expressions are supported:
+ </para>
+ <variablelist remap="TP">
+ <varlistentry>
+ <term><literal>${attr}</literal> (or <literal>$attr</literal> for short)</term>
+ <listitem><para>
+ will substitute the value of the attribute
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>${attr:-word}</literal></term>
+ <listitem><para>
+ (use default) will substitbute the value of the attribute or, if the
+ attribute is not set or empty substitute the word
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>${attr:+word}</literal></term>
+ <listitem><para>
+ (use alternative) will substitbute word if attribute is set, otherwise
+ substitute the empty string
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+ <para>
+ The <command>nslcd</command> daemon checks the expressions to figure
+ out which attributes to fetch from <acronym>LDAP</acronym>.
+ Some examples to demonstrate how these expressions may be used in
+ attribute mapping:
+ </para>
+ <variablelist remap="TP">
+ <varlistentry>
+ <term><literal>"${shadowFlag:-0}"</literal></term>
+ <listitem><para>
+ use the <literal>shadowFlag</literal> attribute, using the
+ value 0 as default
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>"/home/$uid/$uid"</literal></term>
+ <listitem><para>
+ use the <literal>uid</literal> attribute to build a
+ <literal>homeDirectory</literal> value if that attribute is missing
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>"${isDisabled:+100}"</literal></term>
+ <listitem><para>
+ if the <literal>isDisabled</literal> attribute is set, return 100,
+ otherwise leave value empty
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
<refsect1 id="files">
<title>Files</title>
<variablelist remap="TP">
diff --git a/nslcd.conf b/nslcd.conf
index ec2ad50..2e1651f 100644
--- a/nslcd.conf
+++ b/nslcd.conf
@@ -91,7 +91,7 @@ base dc=example,dc=com
#map passwd uid msSFUName
#map passwd userPassword msSFUPassword
#map passwd homeDirectory msSFUHomeDirectory
-#map passwd cn msSFUName
+#map passwd gecos msSFUName
#filter shadow (objectClass=User)
#map shadow uid msSFUName
#map shadow userPassword msSFUPassword
diff --git a/nslcd/Makefile.am b/nslcd/Makefile.am
index bdf3150..3989c4a 100644
--- a/nslcd/Makefile.am
+++ b/nslcd/Makefile.am
@@ -33,4 +33,4 @@ nslcd_SOURCES = nslcd.c ../nslcd.h ../common/nslcd-prot.h \
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@ ../common/libtio.a ../common/libdict.a \
- ../compat/libcompat.a
+ ../common/libexpr.a ../compat/libcompat.a
diff --git a/nslcd/attmap.c b/nslcd/attmap.c
index 765d178..f703345 100644
--- a/nslcd/attmap.c
+++ b/nslcd/attmap.c
@@ -26,8 +26,8 @@
#include <strings.h>
#include "attmap.h"
-
-const char *attmap_objectClass = "objectClass";
+#include "log.h"
+#include "common/expr.h"
/* these are the bases that are defined per database */
extern const char *alias_bases[];
@@ -172,7 +172,6 @@ const char **attmap_get_var(enum ldap_map_selector map,const char *name)
if (strcasecmp(name,"uidNumber")==0) return &attmap_passwd_uidNumber;
if (strcasecmp(name,"gidNumber")==0) return &attmap_passwd_gidNumber;
if (strcasecmp(name,"gecos")==0) return &attmap_passwd_gecos;
- if (strcasecmp(name,"cn")==0) return &attmap_passwd_cn;
if (strcasecmp(name,"homeDirectory")==0) return &attmap_passwd_homeDirectory;
if (strcasecmp(name,"loginShell")==0) return &attmap_passwd_loginShell;
}
@@ -206,3 +205,84 @@ const char **attmap_get_var(enum ldap_map_selector map,const char *name)
}
return NULL;
}
+
+const char *attmap_set_mapping(const char **var,const char *value)
+{
+ /* check if we are setting an expression */
+ if (value[0]=='"')
+ {
+ /* these attributes may contain an expression
+ (note that this needs to match the functionality in the specific
+ lookup module) */
+ if ( (var!=&attmap_passwd_gidNumber) &&
+ (var!=&attmap_passwd_gecos) &&
+ (var!=&attmap_passwd_homeDirectory) &&
+ (var!=&attmap_passwd_loginShell) &&
+ (var!=&attmap_shadow_shadowLastChange) &&
+ (var!=&attmap_shadow_shadowMin) &&
+ (var!=&attmap_shadow_shadowMax) &&
+ (var!=&attmap_shadow_shadowWarning) &&
+ (var!=&attmap_shadow_shadowInactive) &&
+ (var!=&attmap_shadow_shadowExpire) &&
+ (var!=&attmap_shadow_shadowFlag) )
+ return NULL;
+ }
+ /* check if the value will be changed */
+ if ( (*var==NULL) || (strcmp(*var,value)!=0) )
+ *var=strdup(value);
+ return *var;
+}
+
+static const char *entry_expand(const char *name,void *expander_attr)
+{
+ MYLDAP_ENTRY *entry=(MYLDAP_ENTRY *)expander_attr;
+ const char **values;
+ if (strcasecmp(name,"dn")==0)
+ return myldap_get_dn(entry);
+ values=myldap_get_values(entry,name);
+ if (values==NULL)
+ return "";
+ /* TODO: handle userPassword attribute specially */
+ if ((values[0]!=NULL)&&(values[1]!=NULL))
+ {
+ log_log(LOG_WARNING,"entry %s contains multiple %s values",
+ myldap_get_dn(entry),name);
+ }
+ return values[0];
+}
+
+MUST_USE const char *attmap_get_value(MYLDAP_ENTRY *entry,const char *attr,char *buffer,size_t buflen)
+{
+ const char **values;
+ /* for simple values just return the attribute */
+ if (attr[0]!='"')
+ {
+ values=myldap_get_values(entry,attr);
+ if (values==NULL)
+ return NULL;
+ strncpy(buffer,values[0],buflen);
+ buffer[buflen-1]='\0';
+ return buffer;
+ /* TODO: maybe warn when multiple values are found */
+ }
+ if ( (attr[strlen(attr)-1]!='"') ||
+ (expr_parse(attr+1,buffer,buflen,entry_expand,(void *)entry)==NULL) )
+ {
+ log_log(LOG_ERR,"attribute mapping %s is invalid",attr);
+ buffer[0]='\0';
+ return NULL;
+ }
+ /* strip trailing " */
+ if (buffer[strlen(buffer)-1]=='"')
+ buffer[strlen(buffer)-1]='\0';
+ return buffer;
+}
+
+SET *attmap_add_attributes(SET *set,const char *attr)
+{
+ if (attr[0]!='\"')
+ set_add(set,attr);
+ else
+ expr_vars(attr,set);
+ return set;
+}
diff --git a/nslcd/attmap.h b/nslcd/attmap.h
index 7ec9177..48578c1 100644
--- a/nslcd/attmap.h
+++ b/nslcd/attmap.h
@@ -2,7 +2,7 @@
attmap.h - attribute mapping variables
This file is part of the nss-pam-ldapd library.
- Copyright (C) 2007, 2008 Arthur de Jong
+ Copyright (C) 2007, 2008, 2009 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
@@ -24,6 +24,8 @@
#define _ATTMAP_H 1
#include "cfg.h"
+#include "myldap.h"
+#include "common/set.h"
/* these are the attribute names per database */
extern const char *attmap_alias_cn;
@@ -49,7 +51,6 @@ extern const char *attmap_passwd_userPassword;
extern const char *attmap_passwd_uidNumber;
extern const char *attmap_passwd_gidNumber;
extern const char *attmap_passwd_gecos;
-extern const char *attmap_passwd_cn;
extern const char *attmap_passwd_homeDirectory;
extern const char *attmap_passwd_loginShell;
extern const char *attmap_protocol_cn;
@@ -83,4 +84,17 @@ const char **filter_get_var(enum ldap_map_selector map);
underscode replaced by a dot (e.g passwd.homeDirectory) */
const char **attmap_get_var(enum ldap_map_selector map,const char *name);
+/* Set the attribute mapping of the variable to the value specified.
+ Returns the new value on success. */
+
+const char *attmap_set_mapping(const char **var,const char *value);
+
+/* Return a value for the attribute, handling the case where attr
+ is an expression. */
+const char *attmap_get_value(MYLDAP_ENTRY *entry,const char *attr,char *buffer,size_t buflen);
+
+/* Add the attributes from attr to the set. The attr argumenent
+ can either be an attribute or an attribute expression. */
+SET *attmap_add_attributes(SET *set,const char *attr);
+
#endif /* not _ATTMAP_H */
diff --git a/nslcd/cfg.c b/nslcd/cfg.c
index e8a5408..060b566 100644
--- a/nslcd/cfg.c
+++ b/nslcd/cfg.c
@@ -623,7 +623,7 @@ static void parse_map_statement(const char *filename,int lnr,
{
enum ldap_map_selector map;
const char **var;
- char oldatt[32], newatt[32];
+ char oldatt[32], newatt[1024];
/* get the map */
if ((map=get_map(&line))==LM_NONE)
{
@@ -636,19 +636,17 @@ static void parse_map_statement(const char *filename,int lnr,
(get_token(&line,newatt,sizeof(newatt))!=NULL));
/* check that there are no more tokens left on the line */
get_eol(filename,lnr,keyword,&line);
- /* get the attribute variable to set */
+ /* change attribute mapping */
var=attmap_get_var(map,oldatt);
if (var==NULL)
{
log_log(LOG_ERR,"%s:%d: unknown attribute to map: '%s'",filename,lnr,oldatt);
exit(EXIT_FAILURE);
}
- /* check if the value will be changed */
- if ( (*var==NULL) || (strcmp(*var,newatt)!=0) )
+ if (attmap_set_mapping(var,newatt)==NULL)
{
- /* Note: we have a memory leak here if a single mapping is changed
- multiple times in one config (deemed not a problem) */
- *var=xstrdup(newatt);
+ log_log(LOG_ERR,"%s:%d: attribute %s cannot be an expression",filename,lnr,oldatt);
+ exit(EXIT_FAILURE);
}
}
diff --git a/nslcd/passwd.c b/nslcd/passwd.c
index 63bfce8..a5149f5 100644
--- a/nslcd/passwd.c
+++ b/nslcd/passwd.c
@@ -59,17 +59,14 @@ const char *attmap_passwd_uid = "uid";
const char *attmap_passwd_userPassword = "userPassword";
const char *attmap_passwd_uidNumber = "uidNumber";
const char *attmap_passwd_gidNumber = "gidNumber";
-const char *attmap_passwd_gecos = "gecos";
-const char *attmap_passwd_cn = "cn";
+const char *attmap_passwd_gecos = "\"${gecos:-$cn}\"";
const char *attmap_passwd_homeDirectory = "homeDirectory";
const char *attmap_passwd_loginShell = "loginShell";
/* default values for attributes */
static const char *default_passwd_userPassword = "*"; /* unmatchable */
-static const char *default_passwd_homeDirectory = "";
-static const char *default_passwd_loginShell = "";
-/* Note that the password value should be one of:
+/* Note that the resulting password value should be one of:
<empty> - no password set, allow login without password
* - often used to prevent logins
x - "valid" encrypted password that does not match any valid password
@@ -77,7 +74,7 @@ static const char *default_passwd_loginShell = "";
other - encrypted password, usually in crypt(3) format */
/* the attribute list to request with searches */
-static const char *passwd_attrs[10];
+static const char **passwd_attrs=NULL;
/* create a search filter for searching a passwd entry
by name, return -1 on errors */
@@ -109,6 +106,7 @@ static int mkfilter_passwd_byuid(uid_t uid,
void passwd_init(void)
{
int i;
+ SET *set;
/* set up search bases */
if (passwd_bases[0]==NULL)
for (i=0;i<NSS_LDAP_CONFIG_MAX_BASES;i++)
@@ -117,16 +115,17 @@ void passwd_init(void)
if (passwd_scope==LDAP_SCOPE_DEFAULT)
passwd_scope=nslcd_cfg->ldc_scope;
/* set up attribute list */
- passwd_attrs[0]=attmap_passwd_uid;
- passwd_attrs[1]=attmap_passwd_userPassword;
- passwd_attrs[2]=attmap_passwd_uidNumber;
- passwd_attrs[3]=attmap_passwd_gidNumber;
- passwd_attrs[4]=attmap_passwd_cn;
- passwd_attrs[5]=attmap_passwd_homeDirectory;
- passwd_attrs[6]=attmap_passwd_loginShell;
- passwd_attrs[7]=attmap_passwd_gecos;
- passwd_attrs[8]="objectClass";
- passwd_attrs[9]=NULL;
+ set=set_new();
+ attmap_add_attributes(set,"objectClass"); /* for testing shadowAccount */
+ attmap_add_attributes(set,attmap_passwd_uid);
+ attmap_add_attributes(set,attmap_passwd_userPassword);
+ attmap_add_attributes(set,attmap_passwd_uidNumber);
+ attmap_add_attributes(set,attmap_passwd_gidNumber);
+ attmap_add_attributes(set,attmap_passwd_gecos);
+ attmap_add_attributes(set,attmap_passwd_homeDirectory);
+ attmap_add_attributes(set,attmap_passwd_loginShell);
+ passwd_attrs=set_tolist(set);
+ set_free(set);
}
/* the cache that is used in dn2uid() */
@@ -301,10 +300,11 @@ static int write_passwd(TFILE *fp,MYLDAP_ENTRY *entry,const char *requser,
const char *passwd;
uid_t uids[MAXUIDS_PER_ENTRY];
int numuids;
+ char gidbuf[10];
gid_t gid;
- const char *gecos;
- const char *homedir;
- const char *shell;
+ char gecos[100];
+ char homedir[100];
+ char shell[100];
int i,j;
/* get the usernames for this entry */
usernames=myldap_get_values(entry,attmap_passwd_uid);
@@ -353,77 +353,29 @@ static int write_passwd(TFILE *fp,MYLDAP_ENTRY *entry,const char *requser,
}
}
/* get the gid for this entry */
- tmpvalues=myldap_get_values(entry,attmap_passwd_gidNumber);
- if ((tmpvalues==NULL)||(tmpvalues[0]==NULL))
+ attmap_get_value(entry,attmap_passwd_gidNumber,gidbuf,sizeof(gidbuf));
+ if (gidbuf[0]=='\0')
{
log_log(LOG_WARNING,"passwd entry %s does not contain %s value",
myldap_get_dn(entry),attmap_passwd_gidNumber);
return 0;
}
- else if (tmpvalues[1]!=NULL)
- {
- log_log(LOG_WARNING,"passwd entry %s contains multiple %s values",
- myldap_get_dn(entry),attmap_passwd_gidNumber);
- }
- gid=(gid_t)strtol(tmpvalues[0],&tmp,0);
- if ((*(tmpvalues[0])=='\0')||(*tmp!='\0'))
+ gid=(gid_t)strtol(gidbuf,&tmp,0);
+ if ((gidbuf[0]=='\0')||(*tmp!='\0'))
{
log_log(LOG_WARNING,"passwd entry %s contains non-numeric %s value",
myldap_get_dn(entry),attmap_passwd_gidNumber);
return 0;
}
- /* get the gecos for this entry (fall back to cn) */
- tmpvalues=myldap_get_values(entry,attmap_passwd_gecos);
- if ((tmpvalues==NULL)||(tmpvalues[0]==NULL))
- tmpvalues=myldap_get_values(entry,attmap_passwd_cn);
- if ((tmpvalues==NULL)||(tmpvalues[0]==NULL))
- {
- log_log(LOG_WARNING,"passwd entry %s does not contain %s or %s value",
- myldap_get_dn(entry),attmap_passwd_gecos,attmap_passwd_cn);
- return 0;
- }
- else if (tmpvalues[1]!=NULL)
- {
- log_log(LOG_WARNING,"passwd entry %s contains multiple %s or %s values",
- myldap_get_dn(entry),attmap_passwd_gecos,attmap_passwd_cn);
- }
- gecos=tmpvalues[0];
+ /* get the gecos for this entry */
+ attmap_get_value(entry,attmap_passwd_gecos,gecos,sizeof(gecos));
/* get the home directory for this entry */
- tmpvalues=myldap_get_values(entry,attmap_passwd_homeDirectory);
- if ((tmpvalues==NULL)||(tmpvalues[0]==NULL))
- {
+ attmap_get_value(entry,attmap_passwd_homeDirectory,homedir,sizeof(homedir));
+ if (homedir[0]=='\0')
log_log(LOG_WARNING,"passwd entry %s does not contain %s value",
myldap_get_dn(entry),attmap_passwd_homeDirectory);
- homedir=default_passwd_homeDirectory;
- }
- else
- {
- if (tmpvalues[1]!=NULL)
- {
- log_log(LOG_WARNING,"passwd entry %s contains multiple %s values",
- myldap_get_dn(entry),attmap_passwd_homeDirectory);
- }
- homedir=tmpvalues[0];
- if (*homedir=='\0')
- homedir=default_passwd_homeDirectory;
- }
/* get the shell for this entry */
- tmpvalues=myldap_get_values(entry,attmap_passwd_loginShell);
- if ((tmpvalues==NULL)||(tmpvalues[0]==NULL))
- {
- shell=default_passwd_loginShell;
- }
- else
- {
- if (tmpvalues[1]!=NULL)
- {
- log_log(LOG_WARNING,"passwd entry %s contains multiple %s values",
- myldap_get_dn(entry),attmap_passwd_loginShell);
- }
- shell=tmpvalues[0];
- if (*shell=='\0')
- shell=default_passwd_loginShell;
- }
+ attmap_get_value(entry,attmap_passwd_loginShell,shell,sizeof(shell));
/* write the entries */
for (i=0;usernames[i]!=NULL;i++)
if ((requser==NULL)||(strcmp(requser,usernames[i])==0))
diff --git a/nslcd/shadow.c b/nslcd/shadow.c
index ac00bda..4cb7067 100644
--- a/nslcd/shadow.c
+++ b/nslcd/shadow.c
@@ -55,26 +55,19 @@ const char *shadow_filter = "(objectClass=shadowAccount)";
/* the attributes to request with searches */
const char *attmap_shadow_uid = "uid";
const char *attmap_shadow_userPassword = "userPassword";
-const char *attmap_shadow_shadowLastChange = "shadowLastChange";
-const char *attmap_shadow_shadowMin = "shadowMin";
-const char *attmap_shadow_shadowMax = "shadowMax";
-const char *attmap_shadow_shadowWarning = "shadowWarning";
-const char *attmap_shadow_shadowInactive = "shadowInactive";
-const char *attmap_shadow_shadowExpire = "shadowExpire";
-const char *attmap_shadow_shadowFlag = "shadowFlag";
+const char *attmap_shadow_shadowLastChange = "\"${shadowLastChange:--1}\"";
+const char *attmap_shadow_shadowMin = "\"${shadowMin:--1}\"";
+const char *attmap_shadow_shadowMax = "\"${shadowMax:--1}\"";
+const char *attmap_shadow_shadowWarning = "\"${shadowWarning:--1}\"";
+const char *attmap_shadow_shadowInactive = "\"${shadowInactive:--1}\"";
+const char *attmap_shadow_shadowExpire = "\"${shadowExpire:--1}\"";
+const char *attmap_shadow_shadowFlag = "\"${shadowFlag:-0}\"";
/* default values for attributes */
static const char *default_shadow_userPassword = "*"; /* unmatchable */
-static const char *default_shadow_shadowLastChange = "-1";
-static const char *default_shadow_shadowMin = "-1";
-static const char *default_shadow_shadowMax = "-1";
-static const char *default_shadow_shadowWarning = "-1";
-static const char *default_shadow_shadowInactive = "-1";
-static const char *default_shadow_shadowExpire = "-1";
-static const char *default_shadow_shadowFlag = "0";
/* the attribute list to request with searches */
-static const char *shadow_attrs[10];
+static const char **shadow_attrs=NULL;
static int mkfilter_shadow_byname(const char *name,
char *buffer,size_t buflen)
@@ -93,6 +86,7 @@ static int mkfilter_shadow_byname(const char *name,
void shadow_init(void)
{
int i;
+ SET *set;
/* set up search bases */
if (shadow_bases[0]==NULL)
for (i=0;i<NSS_LDAP_CONFIG_MAX_BASES;i++)
@@ -101,16 +95,18 @@ void shadow_init(void)
if (shadow_scope==LDAP_SCOPE_DEFAULT)
shadow_scope=nslcd_cfg->ldc_scope;
/* set up attribute list */
- shadow_attrs[0]=attmap_shadow_uid;
- shadow_attrs[1]=attmap_shadow_userPassword;
- shadow_attrs[2]=attmap_shadow_shadowLastChange;
- shadow_attrs[3]=attmap_shadow_shadowMax;
- shadow_attrs[4]=attmap_shadow_shadowMin;
- shadow_attrs[5]=attmap_shadow_shadowWarning;
- shadow_attrs[6]=attmap_shadow_shadowInactive;
- shadow_attrs[7]=attmap_shadow_shadowExpire;
- shadow_attrs[8]=attmap_shadow_shadowFlag;
- shadow_attrs[9]=NULL;
+ set=set_new();
+ attmap_add_attributes(set,attmap_shadow_uid);
+ attmap_add_attributes(set,attmap_shadow_userPassword);
+ attmap_add_attributes(set,attmap_shadow_shadowLastChange);
+ attmap_add_attributes(set,attmap_shadow_shadowMax);
+ attmap_add_attributes(set,attmap_shadow_shadowMin);
+ attmap_add_attributes(set,attmap_shadow_shadowWarning);
+ attmap_add_attributes(set,attmap_shadow_shadowInactive);
+ attmap_add_attributes(set,attmap_shadow_shadowExpire);
+ attmap_add_attributes(set,attmap_shadow_shadowFlag);
+ shadow_attrs=set_tolist(set);
+ set_free(set);
}
static long to_date(const char *date,const char *attr)
@@ -156,43 +152,27 @@ static long to_date(const char *date,const char *attr)
#endif
#define GET_OPTIONAL_LONG(var,att) \
- tmpvalues=myldap_get_values(entry,attmap_shadow_##att); \
- if ((tmpvalues==NULL)||(tmpvalues[0]==NULL)) \
- var=strtol(default_shadow_##att,NULL,0); \
- else \
+ tmpvalue=attmap_get_value(entry,attmap_shadow_##att,buffer,sizeof(buffer)); \
+ if (tmpvalue==NULL) \
+ tmpvalue=""; \
+ var=strtol(tmpvalue,&tmp,0); \
+ if ((*(tmpvalue)=='\0')||(*tmp!='\0')) \
{ \
- if (tmpvalues[1]!=NULL) \
- { \
- log_log(LOG_WARNING,"shadow entry %s contains multiple %s values", \
- myldap_get_dn(entry),attmap_shadow_##att); \
- } \
- var=strtol(tmpvalues[0],&tmp,0); \
- if ((*(tmpvalues[0])=='\0')||(*tmp!='\0')) \
- { \
- log_log(LOG_WARNING,"shadow entry %s contains non-numeric %s value", \
- myldap_get_dn(entry),attmap_shadow_##att); \
- return 0; \
- } \
+ log_log(LOG_WARNING,"shadow entry %s contains non-numeric %s value", \
+ myldap_get_dn(entry),attmap_shadow_##att); \
+ return 0; \
}
#define GET_OPTIONAL_DATE(var,att) \
- tmpvalues=myldap_get_values(entry,attmap_shadow_##att); \
- if ((tmpvalues==NULL)||(tmpvalues[0]==NULL)) \
- var=to_date(default_shadow_##att,attmap_shadow_##att); \
- else \
- { \
- if (tmpvalues[1]!=NULL) \
- { \
- log_log(LOG_WARNING,"shadow entry %s contains multiple %s values", \
- myldap_get_dn(entry),attmap_shadow_##att); \
- } \
- var=to_date(tmpvalues[0],attmap_shadow_##att); \
- }
+ tmpvalue=attmap_get_value(entry,attmap_shadow_##att,buffer,sizeof(buffer)); \
+ if (tmpvalue==NULL) \
+ tmpvalue=""; \
+ var=to_date(tmpvalue,attmap_shadow_##att);
static int write_shadow(TFILE *fp,MYLDAP_ENTRY *entry,const char *requser)
{
int32_t tmpint32;
- const char **tmpvalues;
+ const char *tmpvalue;
char *tmp;
const char **usernames;
const char *passwd;
@@ -204,6 +184,7 @@ static int write_shadow(TFILE *fp,MYLDAP_ENTRY *entry,const char *requser)
long expiredate;
unsigned long flag;
int i;
+ char buffer[80];
/* get username */
usernames=myldap_get_values(entry,attmap_shadow_uid);
if ((usernames==NULL)||(usernames[0]==NULL))
diff --git a/tests/Makefile.am b/tests/Makefile.am
index feac01d..a0be82c 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,7 +1,7 @@
# Makefile.am - use automake to generate Makefile.in
#
# Copyright (C) 2006 West Consulting
-# Copyright (C) 2006, 2007, 2008 Arthur de Jong
+# Copyright (C) 2006, 2007, 2008, 2009 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
@@ -19,10 +19,10 @@
# 02110-1301 USA
TESTS = test_dict test_set test_tio test_cfg test_myldap.sh test_nsscmds.sh \
- test_getpeercred test_common
+ test_getpeercred test_common test_expr
check_PROGRAMS = test_dict test_set test_tio test_cfg test_myldap \
- test_getpeercred test_common
+ test_getpeercred test_common test_expr
EXTRA_PROGRAMS = test_aliases test_ethers test_group test_hosts \
test_netgroup test_networks test_passwd test_protocols \
@@ -52,14 +52,17 @@ test_tio_SOURCES = test_tio.c ../common/tio.h ../common/tio.c
test_tio_LDFLAGS = $(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
test_cfg_SOURCES = test_cfg.c
-test_cfg_LDADD = ../nslcd/log.o ../nslcd/attmap.o \
+test_cfg_LDADD = ../nslcd/log.o ../nslcd/attmap.o \
../nslcd/common.o ../nslcd/myldap.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 \
../nslcd/service.o ../nslcd/shadow.o \
@nslcd_LIBS@ ../common/libtio.a ../common/libdict.a \
- ../compat/libcompat.a
+ ../common/libexpr.a ../compat/libcompat.a
+
+test_expr_SOURCES = test_expr.c
+test_expr_LDADD = ../common/set.o ../common/dict.o
test_myldap_SOURCES = test_myldap.c
test_myldap_LDADD = ../nslcd/log.o ../nslcd/common.o ../nslcd/cfg.o \
diff --git a/tests/test_cfg.c b/tests/test_cfg.c
index 269b57c..dc558c2 100644
--- a/tests/test_cfg.c
+++ b/tests/test_cfg.c
@@ -206,6 +206,7 @@ static void test_read(void)
"base dc=test, dc=tld\n"
"base passwd ou=Some People,dc=test,dc=tld\n"
"map\tpasswd uid\t\tsAMAccountName\n"
+ "map passwd homeDirectory \"${homeDirectory:-/home/$uid}\"\n"
"filter group (&(objeclClass=posixGroup)(gid=1*))\n"
"\n"
"scope passwd one\n");
diff --git a/tests/test_common.c b/tests/test_common.c
index 89856d4..4831815 100644
--- a/tests/test_common.c
+++ b/tests/test_common.c
@@ -2,7 +2,7 @@
test_common.c - simple test for the common module
This file is part of the nss-pam-ldapd library.
- Copyright (C) 2008 Arthur de Jong
+ Copyright (C) 2008, 2009 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
@@ -32,6 +32,9 @@ const char **base_get_var(int UNUSED(map)) {return NULL;}
int *scope_get_var(int UNUSED(map)) {return NULL;}
const char **filter_get_var(int UNUSED(map)) {return NULL;}
const char **attmap_get_var(int UNUSED(map),const char UNUSED(*name)) {return NULL;}
+const char *attmap_get_value(MYLDAP_ENTRY UNUSED(*entry),const char UNUSED(*attr),char UNUSED(*buffer),size_t UNUSED(buflen)) {return "";}
+void *attmap_add_attributes(void UNUSED(*set),const char UNUSED(*attr)) {return NULL;}
+const char *attmap_set_mapping(const char UNUSED(**var),const char UNUSED(*value)) {return NULL;}
static void test_isvalidname(void)
{
diff --git a/tests/test_expr.c b/tests/test_expr.c
new file mode 100644
index 0000000..dfc00cb
--- /dev/null
+++ b/tests/test_expr.c
@@ -0,0 +1,146 @@
+/*
+ test_expr.c - simple tests for the expr module
+ This file is part of the nss-pam-ldapd library.
+
+ Copyright (C) 2009 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 <assert.h>
+
+/* we include expr.c because we want to test the static methods */
+#include "common/expr.c"
+
+#ifndef __ASSERT_FUNCTION
+#define __ASSERT_FUNCTION ""
+#endif /* not __ASSERT_FUNCTION */
+
+#define assertstreq(str1,str2) \
+ (assertstreq_impl(str1,str2,"strcmp(" __STRING(str1) "," __STRING(str2) ")==0", \
+ __FILE__, __LINE__, __ASSERT_FUNCTION))
+
+/* for Solaris: */
+#define __assert_fail(assertion,file,line,function) __assert(assertion,file,line)
+
+/* method for determening string equalness */
+static void assertstreq_impl(const char *str1,const char *str2,
+ const char *assertion,const char *file,
+ int line,const char *function)
+{
+ if (strcmp(str1,str2)!=0)
+ __assert_fail(assertion,file,line,function);
+}
+
+static void test_parse_name(void)
+{
+ char buffer[20];
+ int i;
+ i=0;
+ assert(parse_name("fooBar",&i,buffer,sizeof(buffer))!=NULL);
+ assert(i==6);
+ i=0;
+ assert(parse_name("nameThatWillNotFitInBuffer",&i,buffer,sizeof(buffer))==NULL);
+ i=0;
+ assert(parse_name("foo Bar",&i,buffer,sizeof(buffer))!=NULL);
+ assert(i==3);
+ assertstreq(buffer,"foo");
+}
+
+static const char *expanderfn(const char *name,void UNUSED(*expander_attr))
+{
+ if (strcmp(name,"empty")==0)
+ return "";
+ else
+ return "foobar";
+}
+
+static void test_expr_parse(void)
+{
+ char buffer[1024];
+ assert(expr_parse("$test1",buffer,sizeof(buffer),expanderfn,NULL)!=NULL);
+ assertstreq(buffer,"foobar");
+ assert(expr_parse("$empty",buffer,sizeof(buffer),expanderfn,NULL)!=NULL);
+ assertstreq(buffer,"");
+ assert(expr_parse("${test1}\\$",buffer,sizeof(buffer),expanderfn,NULL)!=NULL);
+ assertstreq(buffer,"foobar$");
+ assert(expr_parse("${test1:-default}",buffer,sizeof(buffer),expanderfn,NULL)!=NULL);
+ assertstreq(buffer,"foobar");
+ assert(expr_parse("${empty:-default}",buffer,sizeof(buffer),expanderfn,NULL)!=NULL);
+ assertstreq(buffer,"default");
+ assert(expr_parse("${test1:+setset}",buffer,sizeof(buffer),expanderfn,NULL)!=NULL);
+ assertstreq(buffer,"setset");
+ assert(expr_parse("${empty:+setset}",buffer,sizeof(buffer),expanderfn,NULL)!=NULL);
+ assertstreq(buffer,"");
+ assert(expr_parse("${empty:-$test1}",buffer,sizeof(buffer),expanderfn,NULL)!=NULL);
+ assertstreq(buffer,"foobar");
+ assert(expr_parse("a/$test1/b",buffer,sizeof(buffer),expanderfn,NULL)!=NULL);
+ assertstreq(buffer,"a/foobar/b");
+ assert(expr_parse("a/$empty/b",buffer,sizeof(buffer),expanderfn,NULL)!=NULL);
+ assertstreq(buffer,"a//b");
+ assert(expr_parse("a${test1}b",buffer,sizeof(buffer),expanderfn,NULL)!=NULL);
+ assertstreq(buffer,"afoobarb");
+ assert(expr_parse("a${test1}b${test2:+${test3:-d$test4}e}c",buffer,sizeof(buffer),expanderfn,NULL)!=NULL);
+ assertstreq(buffer,"afoobarbfoobarec");
+ assert(expr_parse("a${test1}b${test2:+${empty:-d$test4}e}c",buffer,sizeof(buffer),expanderfn,NULL)!=NULL);
+ assertstreq(buffer,"afoobarbdfoobarec");
+}
+
+static void test_buffer_overflow(void)
+{
+ char buffer[10];
+ assert(expr_parse("$test1$empty$test1",buffer,sizeof(buffer),expanderfn,NULL)==NULL);
+ assert(expr_parse("long test value",buffer,sizeof(buffer),expanderfn,NULL)==NULL);
+ assert(expr_parse("${test1:-long test value}",buffer,sizeof(buffer),expanderfn,NULL)==NULL);
+}
+
+static void test_expr_vars(void)
+{
+ SET *set;
+ /* simple test */
+ set=set_new();
+ assert(expr_vars("$a",set)!=NULL);
+ assert(set_contains(set,"a"));
+ assert(!set_contains(set,"$a"));
+ set_free(set);
+ /* more elaborate test */
+ set=set_new();
+ assert(expr_vars("\"${gecos:-$cn}\"",set)!=NULL);
+ assert(set_contains(set,"gecos"));
+ assert(set_contains(set,"cn"));
+ set_free(set);
+ /* more elaborate test */
+ set=set_new();
+ assert(expr_vars("\"${homeDirectory:-/home/$uidNumber/$uid}\"",set)!=NULL);
+ assert(set_contains(set,"homeDirectory"));
+ assert(set_contains(set,"uidNumber"));
+ assert(set_contains(set,"uid"));
+ set_free(set);
+}
+
+/* the main program... */
+int main(int UNUSED(argc),char UNUSED(*argv[]))
+{
+ test_parse_name();
+ test_expr_parse();
+ test_buffer_overflow();
+ test_expr_vars();
+ return EXIT_SUCCESS;
+}
diff --git a/tests/test_myldap.c b/tests/test_myldap.c
index 7387d51..44dfc34 100644
--- a/tests/test_myldap.c
+++ b/tests/test_myldap.c
@@ -2,7 +2,7 @@
test_myldap.c - simple test for the myldap module
This file is part of the nss-pam-ldapd library.
- Copyright (C) 2007 Arthur de Jong
+ Copyright (C) 2007, 2008, 2009 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
@@ -45,6 +45,9 @@ const char **base_get_var(int UNUSED(map)) {return NULL;}
int *scope_get_var(int UNUSED(map)) {return NULL;}
const char **filter_get_var(int UNUSED(map)) {return &foo;}
const char **attmap_get_var(int UNUSED(map),const char UNUSED(*name)) {return &foo;}
+const char *attmap_get_value(MYLDAP_ENTRY UNUSED(*entry),const char UNUSED(*attr),char UNUSED(*buffer),size_t UNUSED(buflen)) {return "";}
+void *attmap_add_attributes(void UNUSED(*set),const char UNUSED(*attr)) {return NULL;}
+const char *attmap_set_mapping(const char UNUSED(**var),const char UNUSED(*value)) {return NULL;}
/* the maxium number of results to print (all results are retrieved) */
#define MAXRESULTS 10