diff options
author | Arthur de Jong <arthur@arthurdejong.org> | 2010-05-07 21:45:06 +0000 |
---|---|---|
committer | Arthur de Jong <arthur@arthurdejong.org> | 2010-05-07 21:45:06 +0000 |
commit | a034ed2f01a14c4d20904442b2820b1f02e4e67a (patch) | |
tree | b3fc600407dfc9b9e734d921bc108376947ea9b7 | |
parent | 458b8e289ad6fb5df0a44c5a119ef9bda8861604 (diff) |
implement an authz_search option to test whether the user is authorised
git-svn-id: http://arthurdejong.org/svn/nss-pam-ldapd/nss-pam-ldapd@1088 ef36b2f9-881f-0410-afb5-c4e39611909c
-rw-r--r-- | man/nslcd.conf.5.xml | 31 | ||||
-rw-r--r-- | man/pam_ldap.8.xml | 4 | ||||
-rw-r--r-- | nslcd/cfg.c | 6 | ||||
-rw-r--r-- | nslcd/cfg.h | 2 | ||||
-rw-r--r-- | nslcd/pam.c | 123 |
5 files changed, 163 insertions, 3 deletions
diff --git a/man/nslcd.conf.5.xml b/man/nslcd.conf.5.xml index 0aa4454..76cf422 100644 --- a/man/nslcd.conf.5.xml +++ b/man/nslcd.conf.5.xml @@ -642,6 +642,37 @@ </listitem> </varlistentry> + <varlistentry> + <term><option>authz_search</option> + <replaceable>FILTER</replaceable></term> + <listitem> + <para> + This option allows flexible fine tuning of the authorisation check that + should be performed. The search filter specified is executed and + if any entries match, access is granted, otherwise access is denied. + </para> + <para> + The search filter can contain the following variable references: + <literal>$username</literal>, <literal>$service</literal>, + <literal>$ruser</literal>, <literal>$rhost</literal>, + <literal>$tty</literal>, <literal>$hostname</literal>, + <literal>$dn</literal>, and <literal>$uid</literal>. + These references are substituted in the search filter using the + same syntax as described in the section on attribute mapping + expressions below. + </para> + <para> + For example, to check that the user has a proper authorizedService + value if the attribute is present: + <literal>(&(objectClass=posixAccount)(uid=$username)(|(authorizedService=$service)(!(authorizedService=*))))</literal> + </para> + <para> + The default behaviour is not to do this extra search and always + grant access. + </para> + </listitem> + </varlistentry> + </variablelist> </refsect2> diff --git a/man/pam_ldap.8.xml b/man/pam_ldap.8.xml index 19d9884..ad91878 100644 --- a/man/pam_ldap.8.xml +++ b/man/pam_ldap.8.xml @@ -166,8 +166,8 @@ <refsect1 id="moduleservices"> <title>Module Services Provided</title> <para> - All services are provided by this module but currently only authentication - (auth) and password change (password) are implemented in the nslcd daemon. + All services are provided by this module but currently sessions changes + are not implemented in the nslcd daemon. </para> </refsect1> diff --git a/nslcd/cfg.c b/nslcd/cfg.c index a82fc6e..7715a3f 100644 --- a/nslcd/cfg.c +++ b/nslcd/cfg.c @@ -119,6 +119,7 @@ static void cfg_defaults(struct ldap_config *cfg) cfg->ldc_restart=1; cfg->ldc_pagesize=0; cfg->ldc_nss_initgroups_ignoreusers=NULL; + cfg->ldc_authz_search=NULL; } /* simple strdup wrapper */ @@ -1020,6 +1021,11 @@ static void cfg_read(const char *filename,struct ldap_config *cfg) { parse_nss_initgroups_ignoreusers_statement(filename,lnr,keyword,line,cfg); } + else if (strcasecmp(keyword,"authz_search")==0) + { + check_argumentcount(filename,lnr,keyword,(line!=NULL)&&(*line!='\0')); + cfg->ldc_authz_search=xstrdup(line); + } #ifdef ENABLE_CONFIGFILE_CHECKING /* fallthrough */ else diff --git a/nslcd/cfg.h b/nslcd/cfg.h index 8367b45..8ff9924 100644 --- a/nslcd/cfg.h +++ b/nslcd/cfg.h @@ -136,6 +136,8 @@ struct ldap_config /* the users for which no initgroups() searches should be done Note: because we use a set here comparisons will be case-insensitive */ SET *ldc_nss_initgroups_ignoreusers; + /* the search that should be performed to do autorisation checks */ + char *ldc_authz_search; }; /* this is a pointer to the global configuration, it should be available diff --git a/nslcd/pam.c b/nslcd/pam.c index a544185..eedb9aa 100644 --- a/nslcd/pam.c +++ b/nslcd/pam.c @@ -28,12 +28,19 @@ #ifdef HAVE_STDINT_H #include <stdint.h> #endif /* HAVE_STDINT_H */ +#include <unistd.h> #include "common.h" #include "log.h" #include "myldap.h" #include "cfg.h" #include "attmap.h" +#include "common/dict.h" +#include "common/expr.h" + +#ifndef HOST_NAME_MAX +#define HOST_NAME_MAX 255 +#endif /* not HOST_NAME_MAX */ /* set up a connection and try to bind with the specified DN and password returns a NSLCD_PAM_* error code */ @@ -170,6 +177,92 @@ int nslcd_pam_authc(TFILE *fp,MYLDAP_SESSION *session) return 0; } +static void autzsearch_var_add(DICT *dict,const char *name,const char *value) +{ + size_t sz; + char *escaped_value; + /* allocate memory for escaped string */ + sz=((strlen(value)+8)*120)/100; + escaped_value=(char *)malloc(sz); + if (escaped_value==NULL) + { + log_log(LOG_CRIT,"autzsearch_var_add(): malloc() failed to allocate memory"); + return; + } + /* perform escaping of the value */ + if(myldap_escape(value,escaped_value,sz)) + { + log_log(LOG_CRIT,"autzsearch_var_add(): myldap_escape() failed to fit in buffer"); + return; + } + /* add to dict */ + dict_put(dict,name,escaped_value); +} + +static void autzsearch_vars_free(DICT *dict) +{ + int i; + const char **keys; + void *value; + /* go over all keys and free all the values + (they were allocated in autzsearch_var_add) */ + /* loop over dictionary contents */ + keys=dict_keys(dict); + for (i=0;keys[i]!=NULL;i++) + { + value=dict_get(dict,keys[i]); + if (value) + free(value); + } + free(keys); + /* after this values from the dict should obviously no longer be used */ +} + +static const char *autzsearch_var_get(const char *name,void *expander_attr) +{ + DICT *dict=(DICT *)expander_attr; + return (const char *)dict_get(dict,name); + /* TODO: if not set use entry to get attribute name (entry can be an + element in the dict) */ +} + +static int try_autzsearch(MYLDAP_SESSION *session,DICT *dict,const char *searchfilter) +{ + char filter_buffer[1024]; + MYLDAP_SEARCH *search; + MYLDAP_ENTRY *entry; + static const char *attrs[2]; + int rc; + /* build the search filter */ + if (expr_parse(searchfilter,filter_buffer,sizeof(filter_buffer), + autzsearch_var_get,(void *)dict)==NULL) + { + log_log(LOG_ERR,"authorisation search \"%s\" is invalid",searchfilter); + return -1; + } + /* perform the search */ + attrs[0]="dn"; + attrs[1]=NULL; + /* FIXME: this only searches the first base */ + search=myldap_search(session,nslcd_cfg->ldc_bases[0],LDAP_SCOPE_SUB, + filter_buffer,attrs,&rc); + if (search==NULL) + { + log_log(LOG_ERR,"authorisation search \"%s\" failed: %s", + filter_buffer,ldap_err2string(rc)); + return -1; + } + /* try to get an entry */ + entry=myldap_get_entry(search,NULL); + if (entry==NULL) + { + log_log(LOG_ERR,"no entry found"); + return -1; + } + /* we've found an entry so it's OK */ + return 0; +} + /* check authorisation of the user */ int nslcd_pam_authz(TFILE *fp,MYLDAP_SESSION *session) { @@ -180,6 +273,8 @@ int nslcd_pam_authz(TFILE *fp,MYLDAP_SESSION *session) char ruser[32]; char rhost[256]; char tty[256]; + char hostname[HOST_NAME_MAX+1]; + DICT *dict; /* read request parameters */ READ_STRING(fp,username); READ_STRING(fp,userdn); @@ -199,7 +294,33 @@ int nslcd_pam_authz(TFILE *fp,MYLDAP_SESSION *session) WRITE_INT32(fp,NSLCD_RESULT_END); return -1; } - /* TODO: perform any authorisation checks */ + if (nslcd_cfg->ldc_authz_search) + { + /* TODO: perform any authorisation checks */ + dict=dict_new(); + autzsearch_var_add(dict,"username",username); + autzsearch_var_add(dict,"service",servicename); + autzsearch_var_add(dict,"ruser",ruser); + autzsearch_var_add(dict,"rhost",rhost); + autzsearch_var_add(dict,"tty",tty); + if (gethostname(hostname,sizeof(hostname))==0) + autzsearch_var_add(dict,"hostname",hostname); + /* TODO: fqdn */ + autzsearch_var_add(dict,"dn",userdn); + autzsearch_var_add(dict,"uid",username); + if (try_autzsearch(session,dict,nslcd_cfg->ldc_authz_search)) + { + log_log(LOG_DEBUG,"LDAP authorisation check failed"); + WRITE_INT32(fp,NSLCD_RESULT_BEGIN); + WRITE_STRING(fp,username); + WRITE_STRING(fp,userdn); + WRITE_INT32(fp,NSLCD_PAM_PERM_DENIED); /* authz */ + WRITE_STRING(fp,"LDAP authorisation check failed"); /* authzmsg */ + WRITE_INT32(fp,NSLCD_RESULT_END); + } + autzsearch_vars_free(dict); + dict_free(dict); + } /* write response */ WRITE_INT32(fp,NSLCD_RESULT_BEGIN); WRITE_STRING(fp,username); |