Changeset 445


Ignore:
Timestamp:
08/14/10 16:19:36 (22 months ago)
Author:
ludovic.rousseau
Message:

Patch for #239 and #240 (handle more than one cert/pattern matching)

Thanks to Wolf Geldmacher for the patch.
http://www.opensc-project.org/pipermail/opensc-devel/2010-June/014405.html

" Here's a patch to solve the issues I've encountered using pam_pkcs11.

In regards to #239 (pam_pkcs11 only looks at first certificate on
token):

The fix for this turns out to be somewhat problematic, and I'm not at
all sure, whether my implementation of the fix is a valid one.

The basic problem (as I understood it from analyzing the code) is that
finder functions of the mappers return a char*, allowing for a single
value (NULL) to signalize failure and return the key if no mapping (i.e.
no value associated with the key) was found (cf. comment for
mapfile_find in src/mappers/mapper.c). Thus a caller (i.e. find_user in
src/pam_pkcs11/mapper_mgr.c) cannot distinguish between a mapping or a
key being returned and thus will prematurely terminate on the first
certificate that passes the other validity tests.

The fix provided changes the finder function interface by requiring an
additional out parameter that is set to 1, if a real mapping value was
returned and remains unchanged otherwise. This fix breaks existing
loadable mappers.

I considered overloading of the value returned (e.g. having a
byte/substring as first character of the value returned to be able to
distinguish between a value and a key being returned) which would
preserve the interface to the mappers, but refrained from implementing
it that way as I believe this to be unclean and prone to difficult to
track errors.

Another solution I considered was the addition of another entry to the
structure encapsulating the mappers (e.g. a finder2 method), but as this
is no better in breaking the interface for loadable mappers and
duplicates code I forfeited this solution, too.

If somebody could look into the problem and come up with a solution that
preserves the interface to external mappers while allowing the
distinction between keys and values, I'd be more than happy to implement
it.

It might also may make sense to add a new configuration parameter for
the new behaviour of find_user, allowing existing applications to
continue to work with keys being returned instead of values (Feedback
anyone? The comment for find_user actually states that a mapping value
is returned).

In regards to #240 (Allow pattern matching in pam_pkcs11):

I restricted this to only work for mapfiles and the implementation
turned out to be quite simple - it's essentially an 11 line change in
src/mappers/mapper.c - and is triggered by the specification of a fully
anchored (i.e. *must* have initial "" and *must* end in "$") pattern as
key in a mapfile.

This now allows syntax like
.*/serialNumber=xxx-xxx-xxx-xxx$ -> username
in all mapfiles.

The patch attached contains the changes for both issues.

Cheers,
Wolf "

Location:
trunk/src
Files:
17 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/mappers/cn_mapper.c

    r358 r445  
    6161parses the certificate and return the first CN entry found, or NULL 
    6262*/ 
    63 static char * cn_mapper_find_user(X509 *x509, void *context) { 
     63static char * cn_mapper_find_user(X509 *x509, void *context, int *match) { 
    6464        char *res; 
    6565        char **entries= cert_info(x509,CERT_CN,ALGORITHM_NULL); 
     
    6969        } 
    7070        DBG1("trying to map CN entry '%s'",entries[0]); 
    71         res = mapfile_find(mapfile,entries[0],ignorecase); 
     71        res = mapfile_find(mapfile,entries[0],ignorecase,match); 
    7272        if (!res) { 
    7373            DBG("Error in map process"); 
  • trunk/src/mappers/digest_mapper.c

    r358 r445  
    5858} 
    5959 
    60 static char * digest_mapper_find_user(X509 *x509, void *context) { 
     60static char * digest_mapper_find_user(X509 *x509, void *context, int *match) { 
    6161        char **entries; 
    6262        if ( !x509 ) { 
     
    6666        entries = cert_info(x509,CERT_DIGEST,algorithm); 
    6767        DBG1("find() Found digest '%s'",entries[0]); 
    68         return mapfile_find(mapfile,entries[0],1); 
     68        return mapfile_find(mapfile,entries[0],1,match); 
    6969} 
    7070 
  • trunk/src/mappers/generic_mapper.c

    r358 r445  
    5656 
    5757static char **get_mapped_entries(char **entries) { 
     58        int match = 0; 
    5859        char *entry; 
    5960        int n=0; 
     
    6566            DBG1("Using map file '%s'",mapfile); 
    6667            for(n=0, entry=entries[n]; entry; entry=entries[++n]) { 
    67                 res = mapfile_find(mapfile,entry,ignorecase); 
     68                res = mapfile_find(mapfile,entry,ignorecase,&match); 
    6869                if (res) entries[n]=res; 
    6970            } 
     
    8384} 
    8485 
    85 static char *generic_mapper_find_user(X509 *x509, void *context) { 
     86static char *generic_mapper_find_user(X509 *x509, void *context, int *match) { 
    8687        char **entries; 
    8788        int n; 
     
    101102        for (n=0;n<CERT_INFO_SIZE;n++) { 
    102103            char *str=entries[n]; 
    103             if (!str && !is_empty_str(str) ) return clone_str(str); 
     104            if (!str && !is_empty_str(str) ) { 
     105                *match = 1; 
     106                return clone_str(str); 
     107            } 
    104108        } 
    105109        /* arriving here means no map found */ 
  • trunk/src/mappers/krb_mapper.c

    r358 r445  
    6464parses the certificate and return the email entry found, or NULL 
    6565*/ 
    66 static char * krb_mapper_find_user(X509 *x509, void *context) { 
     66static char * krb_mapper_find_user(X509 *x509, void *context, int *match) { 
    6767        char *res; 
    6868        char **entries= cert_info(x509,CERT_KPN,ALGORITHM_NULL); 
     
    7272        } 
    7373        DBG1("trying to map kpn entry '%s'",entries[0]); 
    74         res = mapfile_find("none",entries[0],0); 
     74        res = mapfile_find("none",entries[0],0,match); 
    7575        if (!res) { 
    7676            DBG("Error in map process"); 
  • trunk/src/mappers/ldap_mapper.c

    r423 r445  
    923923} 
    924924 
    925 static char * ldap_mapper_find_user(X509 *x509, void *context) { 
     925static char * ldap_mapper_find_user(X509 *x509, void *context, int *match) { 
    926926        struct passwd *pw = NULL; 
    927927        char *found=NULL; 
     
    934934                DBG1("Certificate maps to user '%s'",pw->pw_name); 
    935935                found= clone_str(pw->pw_name); 
     936                *match = 1; 
    936937                break; 
    937938            } else { 
  • trunk/src/mappers/mail_mapper.c

    r358 r445  
    107107parses the certificate and return the email entry found, or NULL 
    108108*/ 
    109 static char * mail_mapper_find_user(X509 *x509, void *context) { 
     109static char * mail_mapper_find_user(X509 *x509, void *context, int *match) { 
    110110        char **entries= cert_info(x509,CERT_EMAIL,ALGORITHM_NULL); 
    111111        if (!entries) { 
     
    114114        } 
    115115        /* TODO: What's on ignoredomain flag ?*/ 
    116         return mapfile_find(mapfile,entries[0],ignorecase); 
     116        return mapfile_find(mapfile,entries[0],ignorecase,match); 
    117117} 
    118118 
     
    122122*/ 
    123123static int mail_mapper_match_user(X509 *x509, const char *login, void *context) { 
     124        int match = 0; 
    124125        char *item; 
    125126        char *str; 
     
    132133        for (item=*entries;item;item=*++entries) { 
    133134            DBG1("Trying to match email entry '%s'",item); 
    134             str= mapfile_find(mapfile,item,ignorecase); 
     135            str= mapfile_find(mapfile,item,ignorecase,&match); 
    135136            if (!str) { 
    136137                DBG("Mapping process failed"); 
  • trunk/src/mappers/mapper.c

    r358 r445  
    3232#include <string.h> 
    3333#include <pwd.h> 
     34#include <regex.h> 
    3435#include "../common/debug.h" 
    3536#include "../common/error.h" 
     
    141142* @param key  Key to search in mapfile 
    142143* @param icase ignore case 
     144* @param match Set to 1 for mapped string return, unmodified for key return 
    143145* @return mapped string on match, key on no match, NULL on error 
    144146*/ 
    145 char *mapfile_find(const char *file, char *key, int icase) { 
     147char *mapfile_find(const char *file, char *key, int icase, int *match) { 
    146148        struct mapfile *mfile; 
    147         int done=0; 
    148149        if ( (!key) || is_empty_str(key) ) { 
    149150                DBG("key to map is null or empty"); 
     
    162163        } 
    163164        while (get_mapent(mfile)) { 
    164             if ( (icase) && (!strcasecmp(key,mfile->key)) ) done=1; 
    165             if ( (!icase) && (!strcmp(key,mfile->key)) ) done=1; 
     165            int done = 0; 
     166            if (mfile->key[0]=='^' && mfile->key[strlen(mfile->key)-1]=='$') { 
     167                regex_t re; 
     168                DBG2("Trying RE '%s' match on '%s'",mfile->key,key); 
     169                if (regcomp(&re,mfile->key,(icase ? REG_ICASE : 0)|REG_NEWLINE)) { 
     170                    DBG2("RE '%s' in mapfile '%s' is invalid",mfile->key,file); 
     171                } else { 
     172                    done = !regexec(&re,key,0,NULL,0); 
     173                    regfree(&re); 
     174                } 
     175            } else if (icase) 
     176                done = !strcasecmp(key, mfile->key); 
     177            else 
     178                done = !strcmp(key, mfile->key); 
     179 
    166180            if (done) { 
    167181                char *res=clone_str(mfile->value); 
    168182                DBG2("Found mapfile match '%s' -> '%s'",key,mfile->value); 
    169183                end_mapent(mfile); 
     184                *match = 1; 
    170185                return res; 
    171186            } 
     
    187202int mapfile_match(const char *file, char *key, const char *value, int icase) { 
    188203        int res; 
    189         char *str=mapfile_find(file,key,icase); 
     204        int match = 0; 
     205        char *str=mapfile_find(file,key,icase,&match); 
    190206        if (!str) return -1; 
    191207        if (icase) res= (!strcasecmp(str,value))? 1:0; 
  • trunk/src/mappers/mapper.h

    r358 r445  
    5050    char **(*entries)(X509 *x509, void *context); 
    5151    /** cert. login finder */ 
    52     char *(*finder)(X509 *x509, void *context); 
     52    char *(*finder)(X509 *x509, void *context, int *match); 
    5353    /** cert-to-login matcher*/ 
    5454    int (*matcher)(X509 *x509, const char *login, void *context); 
     
    126126*@param key String to be mapped 
    127127*@param ignorecase Flag to indicate upper/lowercase ignore in string compare 
     128*@param match Set to 1 for mapped string return, unmodified for key return 
    128129*@return key on no match, else a clone_str()'d of found mapping 
    129130*/ 
    130 MAPPER_EXTERN char *mapfile_find(const char *file,char *key,int ignorecase); 
     131MAPPER_EXTERN char *mapfile_find(const char *file,char *key,int ignorecase,int *match); 
    131132 
    132133/** 
     
    185186*/ 
    186187#define _DEFAULT_MAPPER_FIND_USER                                       \ 
    187 static char * mapper_find_user(X509 *x509,void *context) {              \ 
     188static char * mapper_find_user(X509 *x509,void *context,int *match) {           \ 
    188189        if ( !x509 ) return NULL;                                       \ 
     190        *match = 1;                                                     \ 
    189191        return "nobody";                                                \ 
    190192} 
     
    202204#define _DEFAULT_MAPPER_MATCH_USER                                      \ 
    203205static int mapper_match_user(X509 *x509, const char *login, void *context) { \ 
    204         char *username= mapper_find_user(x509,context);                         \ 
     206        int match = 0;                                                  \ 
     207        char *username= mapper_find_user(x509,context,&match);          \ 
    205208        if (!x509) return -1;                                           \ 
    206209        if (!login) return -1;                                          \ 
  • trunk/src/mappers/ms_mapper.c

    r358 r445  
    109109parses the certificate and return the first valid UPN entry found, or NULL 
    110110*/ 
    111 static char * ms_mapper_find_user(X509 *x509, void *context) { 
     111static char * ms_mapper_find_user(X509 *x509, void *context, int *match) { 
    112112        char *str; 
    113113        char **entries  = cert_info(x509,CERT_UPN,ALGORITHM_NULL); 
     
    123123             if (res) { 
    124124                DBG2("Found valid UPN: '%s' maps to '%s' ",str,res); 
     125                *match = 1; 
    125126                return clone_str(res); 
    126127             } else { 
  • trunk/src/mappers/null_mapper.c

    r238 r445  
    4444static int debug=0; 
    4545 
    46 static char * mapper_find_user(X509 *x509,void *context) { 
     46static char * mapper_find_user(X509 *x509,void *context,int *mp) { 
    4747        if ( !x509 ) return NULL; 
    48         return (match)?clone_str((char *)default_user):NULL; 
     48        if (match) { 
     49            *mp = 1; 
     50            return clone_str((char *)default_user); 
     51        } 
     52        return NULL; 
    4953} 
    5054 
  • trunk/src/mappers/opensc_mapper.c

    r396 r445  
    136136their ${HOME}/.eid/authorized_certificates 
    137137*/ 
    138 static char * opensc_mapper_find_user(X509 *x509, void *context) { 
     138static char * opensc_mapper_find_user(X509 *x509, void *context, int *match) { 
    139139        int n = 0; 
    140140        struct passwd *pw = NULL; 
     
    156156            /* arriving here means user found */ 
    157157            DBG1("Certificate match found for user '%s'",pw->pw_name); 
    158             res= clone_str(pw->pw_name); 
    159                     endpwent(); 
     158            res = clone_str(pw->pw_name); 
     159            endpwent(); 
     160            *match = 1; 
    160161            return res; 
    161162        } /* next login */ 
  • trunk/src/mappers/openssh_mapper.c

    r358 r445  
    319319parses the certificate and return the _first_ user that matches public key 
    320320*/ 
    321 static char * openssh_mapper_find_user(X509 *x509, void *context) { 
     321static char * openssh_mapper_find_user(X509 *x509, void *context, int *match) { 
    322322        int n = 0; 
    323323        struct passwd *pw = NULL; 
     
    345345            /* arriving here means user found */ 
    346346            DBG1("Certificate match found for user '%s'",pw->pw_name); 
    347             res= clone_str(pw->pw_name); 
     347            res = clone_str(pw->pw_name); 
    348348            endpwent(); 
     349            *match = 1; 
    349350            return res; 
    350351        } /* next login */ 
  • trunk/src/mappers/pwent_mapper.c

    r358 r445  
    6464parses the certificate and return the _first_ CN entry found, or NULL 
    6565*/ 
    66 static char * pwent_mapper_find_user(X509 *x509,void *context) { 
     66static char * pwent_mapper_find_user(X509 *x509,void *context, int *match) { 
    6767        char *str; 
    6868        char *found_user = NULL; 
     
    8181            } else { 
    8282                DBG1("Found CN in pw database for user '%s'",found_user); 
     83                *match = 1; 
     84                /* WJG: Usually allocated mem is returned - memleak/problem? */ 
    8385                return found_user; 
    8486            } 
  • trunk/src/mappers/subject_mapper.c

    r238 r445  
    5757parses the certificate and return the first Subject entry found, or NULL 
    5858*/ 
    59 static char * subject_mapper_find_user(X509 *x509, void *context) { 
     59static char * subject_mapper_find_user(X509 *x509, void *context, int *match) { 
    6060        char **entries = cert_info(x509,CERT_SUBJECT,ALGORITHM_NULL); 
    6161        if (!entries) { 
     
    6363                return NULL; 
    6464        } 
    65         return mapfile_find(filename,entries[0],ignorecase); 
     65        return mapfile_find(filename,entries[0],ignorecase,match); 
    6666} 
    6767 
  • trunk/src/mappers/uid_mapper.c

    r358 r445  
    6262If no UID found or map error, return NULL 
    6363*/ 
    64 static char * uid_mapper_find_user(X509 *x509, void *context) { 
     64static char * uid_mapper_find_user(X509 *x509, void *context, int *match) { 
    6565        char *res; 
    6666        char **entries= cert_info(x509,CERT_UID,ALGORITHM_NULL); 
     
    7070        } 
    7171        DBG1("trying to map uid entry '%s'",entries[0]); 
    72         res = mapfile_find(mapfile,entries[0],ignorecase); 
     72        res = mapfile_find(mapfile,entries[0],ignorecase,match); 
    7373        if (!res) { 
    7474            DBG("Error in map process"); 
  • trunk/src/pam_pkcs11/mapper_mgr.c

    r399 r445  
    265265                DBG1("Mapper '%s' has no find() function",item->module->module_name); 
    266266            } else { 
    267                 set_debug_level(item->module->module_data->dbg_level); 
    268                 login = (*item->module->module_data->finder)(x509,item->module->module_data->context); 
     267                        int match = 0; 
     268 
     269                        set_debug_level(item->module->module_data->dbg_level); 
     270                login = (*item->module->module_data->finder)(x509,item->module->module_data->context, &match); 
    269271                set_debug_level(old_level); 
    270                 if (login) return login; 
     272                DBG3("Mapper '%s' found %s, matched %d", item->module->module_name,login, match); 
     273                        if (login) { 
     274                                if (match) 
     275                                        return login; 
     276                                free(login); 
     277                        } 
    271278            } 
    272279            item=item->next; 
  • trunk/src/tools/pklogin_finder.c

    r441 r445  
    146146      user=find_user(x509); 
    147147      if (!user) { 
    148           DBG1("find_user() failed: %s", get_error()); 
    149           break; 
     148          DBG2("find_user() failed for certificate #%d: %s", i + 1, get_error()); 
     149          continue;     /* with next certificate */ 
    150150      } else { 
    151151          DBG1("Certificate is valid and maps to user %s",user); 
Note: See TracChangeset for help on using the changeset viewer.