Re: aname_to_locaname vs gssapi svc/host.domain.org@REALM
Harry Coin <[email protected]>
| Newsgroups | gmane.comp.encryption.kerberos.heimdal.general |
|---|---|
| Message-ID | <[email protected]> |
On 10/24/2011 5:17 PM, Nico Williams wrote: > On Mon, Oct 24, 2011 at 4:50 PM, Harry Coin<[email protected]> wrote: >> On 10/24/2011 4:19 PM, Nico Williams wrote: >> >>> But again, *daemons* have NO business using NFS resources unless the >>> host is a diskless NFS client. But as I've explained, NFS is a very >>> poor protocol for diskless clients. If you do not use NFS for >>> disklessness, then that problem goes away. >> I must respectfully disagree. While few that might come prepackaged as >> system utilities meant to deliver services to the masses may not, to say >> that none have any business doing so denies the ongoing use of user-specific >> enterprise wide efforts that do just that. > Sure, Apache comes to mind as a daemon that needs to go all over (per > configuration). But sldapd? nscd? no, they don't need to, not > outside a diskless case. And Apache is special because of what it's > intended for. > > Let's get a few things clear: > > - System daemons have no business being NFS clients outside diskless clients. > - Daemons like Apache, or services that *you* write, might. > - Such daemons can access NFS using whatever GSS credentials they > care to: all they have to do is have acquired them (e.g., have > kinit'ed). I believe this is true of Linux's client as well as > Solaris'. > - On the server-side you'll need to make authorization decisions. > These can be done using PACs (if you have them in your tickets and > have the ability to use them) and/or principal name->authorization > context mappings. > - Typical NFS servers let you map arbitrary principals to > arbitrary "user accounts" as a way of mapping client principals to > authorization contexts. I believe this is true of Linux's as well as > Solaris' servers. > - Yes, Solaris lets you use aname2lname() for this, but that's not > the only option it gives you. You can also list principal->username > mappings in a "gsscred" file (man gsscred). > > Now, can you clarify what it is you want? > > Sure. I want everything that worked great here to continue as before (ldap, pam_krb5, nslcd, local software) -- except with -sec=krb5x kerberos benefits as advertised. Specifically A) without taboo against uid:uname:principal name combinations if I specifically indicate I permit them. and, as pre-kerberos, B) if a server should offer N directories for remote access, but restricting each of them specifically to F(N) boxes, where F(N) < all the boxen in the realm, there exists at least one directory available to processes on box Y but not Z, and likely too some on Z not available to Y. then: Files written on the share by account-name:uid QQ on Y will not be available to QQ if on Z. Such files will appear with the QQ's correct uname:uid. Should QQ write on Z, such files may not be visible if on Y, but will appear correctly named on Z. If a process running as QQ exists on the server it will have access to both the files written from Y and from Z by user QQ. C) Unames map onto uids in a 1 to 1 way. Unames map onto 'multi-application-use' kerberos principals in a 1 to 1 way. Just as they all did before kerberos meets network wire integrity/privacy assurance. Except, now with the advertised kerberos ability to authenticate the user, or to provide integrity checks of the traffic, or to encrypt the trafffic entirely if asked. Being that it's all free instead of asking for a refund I wrote some patches that get it done. Harry I did this against freebsd 8stable it's all good: patch -p diff -u /usr/src/crypto/heimdal/lib/krb5/aname_to_localname.c new/aname_to_localname.c --- /usr/src/crypto/heimdal/lib/krb5/aname_to_localname.c 2008-05-07 08:39:37.000000000 -0500 +++ new/aname_to_localname.c 2011-10-21 15:10:50.000000000 -0500 @@ -32,9 +32,56 @@ */ #include <krb5_locl.h> +#include <sys/types.h> +#include <dirent.h> +#include <pwd.h> RCSID("$Id: aname_to_localname.c 13863 2004-05-25 21:46:46Z lha $"); +static int reverse_etck5logind(krb5_context context,krb5_const_principal principal,char **user ){ + DIR *d; + struct dirent *dent; + struct passwd *pwd; + krb5_boolean result; + int errc; +#ifdef POSIX_GETPWNAM_R + char pwbuf[2048]; + struct passwd pw; +#endif + if (user==NULL) return EFAULT; + *user=NULL; + if((d = opendir(ETCK5LOGIND)) == NULL) + return errno; + setpassent(TRUE); + while((dent = readdir(d)) != NULL) { + char *fname; + if(strcmp(dent->d_name, ".") == 0 || + strcmp(dent->d_name, "..") == 0 || + dent->d_name[0] == '#' || /* emacs autosave */ + dent->d_name[strlen(dent->d_name) - 1] == '~') /* emacs backup */ + continue; +#ifdef POSIX_GETPWNAM_R + if(getpwnam_r(dent->d_name, &pw, pwbuf, sizeof(pwbuf), &pwd) != 0) continue; +#else + pwd = getpwnam (dent->d_name); +#endif + if (pwd == NULL) continue; + asprintf(&fname,"%s%s",ETCK5LOGIND,dent->d_name); + errc = krb5_internal_check_one_file(context,fname,pwd,principal,2,&result); + free(fname); + if (0==errc) { + if (result) { + *user = strdup(dent->d_name); + break; + } + } + } + endpwent(); + closedir(d); + return 0; +} + + krb5_error_code KRB5_LIB_FUNCTION krb5_aname_to_localname (krb5_context context, krb5_const_principal aname, @@ -46,7 +93,9 @@ int valid; size_t len; const char *res; - + char *rk5; + + //Fastest: one part principal name in the default realm. ret = krb5_get_default_realms (context, &lrealms); if (ret) return ret; @@ -59,13 +108,31 @@ } } krb5_free_host_realm (context, lrealms); - if (valid == 0) - return KRB5_NO_LOCALNAME; - if (aname->name.name_string.len == 1) + if (valid && (aname->name.name_string.len == 1)) { res = aname->name.name_string.val[0]; - else if (aname->name.name_string.len == 2 - && strcmp (aname->name.name_string.val[1], "root") == 0) { + len = strlen (res); + if (len >= lnsize) + return ERANGE; + strlcpy (lname, res, lnsize); + return 0; // do not clutter the cache by adding these simplename@REALM principals. + } + + //Second fastest: check the cache. + rk5=NULL; + _krb5_luser_principal_cache_query_princ(context,aname,&rk5); //check the cache. + if (rk5!=NULL) { //found it. + len = strlen (res); + if (len >= lnsize) + return ERANGE; + strlcpy (lname, rk5, lnsize); + free(rk5); + return 0; + } + + //Third fastest: check the whatnot/root@REALM format. + if ((valid == 1) && (aname->name.name_string.len == 2) + && (strcmp (aname->name.name_string.val[1], "root") == 0)) { krb5_principal rootprinc; krb5_boolean userok; @@ -75,18 +142,27 @@ if (ret) return ret; - userok = krb5_kuserok(context, rootprinc, res); + userok = krb5_kuserok(context, rootprinc, res); //note this makes use of the cache, so it is fast. krb5_free_principal(context, rootprinc); - if (!userok) - return KRB5_NO_LOCALNAME; + if (userok) { + len = strlen (res); + if (len >= lnsize) + return ERANGE; + strlcpy (lname, res, lnsize); + return 0; + } + } - } else - return KRB5_NO_LOCALNAME; + //Slowest: check the files and if found add the result to the cache before returning it. + reverse_etck5logind(context,aname,&rk5); + if (rk5!=NULL) { + len = strlen (rk5); + if (len >= lnsize) { free(rk5); return ERANGE; } + strlcpy (lname, rk5, lnsize); + free(rk5); + return 0; + } + return KRB5_NO_LOCALNAME; +} - len = strlen (res); - if (len >= lnsize) - return ERANGE; - strlcpy (lname, res, lnsize); - return 0; -} diff -u /usr/src/crypto/heimdal/lib/krb5/context.c new/context.c --- /usr/src/crypto/heimdal/lib/krb5/context.c 2008-05-07 08:39:38.000000000 -0500 +++ new/context.c 2011-10-21 15:19:52.000000000 -0500 @@ -230,6 +230,16 @@ } HEIMDAL_MUTEX_init(p->mutex); + p->luser_principal_cache_mutex = malloc(sizeof(HEIMDAL_MUTEX)); + if (p->luser_principal_cache_mutex == NULL) { + free(p->mutex); + free(p); + return ENOMEM; + } + HEIMDAL_MUTEX_init(p->luser_principal_cache_mutex); + + p->luser_principal_cache=NULL; + ret = krb5_get_default_config_files(&files); if(ret) goto out; @@ -252,6 +262,7 @@ p->num_kt_types = 0; p->kt_types = NULL; + krb5_kt_register (p, &krb5_fkt_uid_ops); krb5_kt_register (p, &krb5_fkt_ops); krb5_kt_register (p, &krb5_wrfkt_ops); krb5_kt_register (p, &krb5_javakt_ops); @@ -281,6 +292,7 @@ void KRB5_LIB_FUNCTION krb5_free_context(krb5_context context) { + krb5_luser_principal_cache_free(context); if (context->default_cc_name) free(context->default_cc_name); if (context->default_cc_name_env) @@ -302,6 +314,10 @@ HEIMDAL_MUTEX_destroy(context->mutex); free(context->mutex); } + if (context->luser_principal_cache_mutex != NULL) { + HEIMDAL_MUTEX_destroy(context->luser_principal_cache_mutex); + free(context->luser_principal_cache_mutex); + } memset(context, 0, sizeof(*context)); free(context); } diff -u /usr/src/crypto/heimdal/lib/krb5/keytab_file.c new/keytab_file.c --- /usr/src/crypto/heimdal/lib/krb5/keytab_file.c 2008-05-07 08:39:37.000000000 -0500 +++ new/keytab_file.c 2011-10-21 15:11:05.000000000 -0500 @@ -268,6 +268,42 @@ } static krb5_error_code +fkt_uid_resolve(krb5_context context, const char *name, krb5_keytab id) +{ + struct fkt_data *d; + char *c, *b; + + d = malloc(sizeof(*d)); + if(d == NULL) { + krb5_set_error_string (context, "malloc: out of memory"); + return ENOMEM; + } + c = strdup(name); + if (c==NULL) return ENOMEM; + b = index(c,'.'); + if (b!=NULL) { + *b=0; + if (asprintf(&d->filename,"%s.%d.%s",c,geteuid(),b+1)<2) return ENOMEM; + if (access(d->filename,R_OK)) { + free(d->filename); + *b='.'; + d->filename = c; + } else free(c); + } else { + d->filename = c; + } + if(d->filename == NULL) { + free(d); + krb5_set_error_string (context, "malloc: out of memory"); + return ENOMEM; + } + d->flags = 0; + id->data = d; + return 0; +} + + +static krb5_error_code fkt_resolve_java14(krb5_context context, const char *name, krb5_keytab id) { krb5_error_code ret; @@ -656,6 +692,19 @@ return 0; } +const krb5_kt_ops krb5_fkt_uid_ops = { + "UIDF", + fkt_uid_resolve, + fkt_get_name, + fkt_close, + NULL, /* get */ + fkt_start_seq_get, + fkt_next_entry, + fkt_end_seq_get, + fkt_add_entry, + fkt_remove_entry +}; + const krb5_kt_ops krb5_fkt_ops = { "FILE", fkt_resolve, diff -u /usr/src/crypto/heimdal/lib/krb5/krb5-private.h new/krb5-private.h --- /usr/src/crypto/heimdal/lib/krb5/krb5-private.h 2008-05-07 08:39:40.000000000 -0500 +++ new/krb5-private.h 2011-10-21 15:11:14.000000000 -0500 @@ -444,4 +444,31 @@ krb5_context /*context*/, int /*fd*/); + +void +_krb5_luser_principal_add_to_cache( + krb5_context /*context*/, + krb5_const_principal /*princ*/, + const char */*luser*/); + +krb5_error_code +_krb5_luser_principal_cache_query_luser( + krb5_context /*context*/, + const char */*luser*/, + krb5_principal */*princ*/); + +krb5_error_code +_krb5_luser_principal_cache_query_princ( + krb5_context /*context*/, + krb5_const_principal /*princ*/, + char **/*luser*/); + +krb5_error_code +krb5_internal_check_one_file(krb5_context /*context*/, + const char */*filename*/, + struct passwd */*pwd*/, + krb5_const_principal /*principal*/, + int /*pattern_match_level*/, + krb5_boolean */*result*/); + #endif /* __krb5_private_h__ */ diff -u /usr/src/crypto/heimdal/lib/krb5/krb5-protos.h new/krb5-protos.h --- /usr/src/crypto/heimdal/lib/krb5/krb5-protos.h 2008-05-07 08:39:38.000000000 -0500 +++ new/krb5-protos.h 2011-10-21 15:11:21.000000000 -0500 @@ -4107,6 +4107,10 @@ krb5_error_code KRB5_LIB_FUNCTION krb5_xfree (void */*ptr*/); +void KRB5_LIB_FUNCTION +krb5_luser_principal_cache_free( + krb5_context context/*context*/); + #ifdef __cplusplus } #endif diff -u /usr/src/crypto/heimdal/lib/krb5/krb5.h new/krb5.h --- /usr/src/crypto/heimdal/lib/krb5/krb5.h 2008-05-07 08:39:37.000000000 -0500 +++ new/krb5.h 2011-10-21 15:11:27.000000000 -0500 @@ -686,6 +686,7 @@ extern const krb5_cc_ops krb5_mcc_ops; extern const krb5_cc_ops krb5_kcm_ops; +extern const krb5_kt_ops krb5_fkt_uid_ops; extern const krb5_kt_ops krb5_fkt_ops; extern const krb5_kt_ops krb5_wrfkt_ops; extern const krb5_kt_ops krb5_javakt_ops; diff -u /usr/src/crypto/heimdal/lib/krb5/krb5_locl.h new/krb5_locl.h --- /usr/src/crypto/heimdal/lib/krb5/krb5_locl.h 2009-08-03 03:13:06.000000000 -0500 +++ new/krb5_locl.h 2011-10-21 15:11:32.000000000 -0500 @@ -167,6 +167,9 @@ /* should this be public? */ #define KEYTAB_DEFAULT "ANY:FILE:" SYSCONFDIR "/krb5.keytab,krb4:" SYSCONFDIR "/srvtab" #define KEYTAB_DEFAULT_MODIFY "FILE:" SYSCONFDIR "/krb5.keytab" +#define ETCK5LOGIND "/etc/k5login.d/" + + #define MODULI_FILE SYSCONFDIR "/krb5.moduli" @@ -198,6 +201,8 @@ #define KRB5_INIT_CREDS_NO_C_CANON_CHECK 2 }; +struct _krb5_luser_principal_cache; //defined&used only in misc.c + typedef struct krb5_context_data { krb5_enctype *etypes; krb5_enctype *etypes_des; @@ -239,6 +244,10 @@ #define KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME 1 #define KRB5_CTX_F_CHECK_PAC 2 struct send_to_kdc *send_to_kdc; + + void *luser_principal_cache_mutex; + struct _krb5_luser_principal_cache *luser_principal_cache; + } krb5_context_data; #define KRB5_DEFAULT_CCNAME_FILE "FILE:/tmp/krb5cc_%{uid}" diff -u /usr/src/crypto/heimdal/lib/krb5/kuserok.c new/kuserok.c --- /usr/src/crypto/heimdal/lib/krb5/kuserok.c 2008-05-07 08:39:38.000000000 -0500 +++ new/kuserok.c 2011-10-21 15:11:39.000000000 -0500 @@ -39,11 +39,12 @@ /* see if principal is mentioned in the filename access file, return TRUE (in result) if so, FALSE otherwise */ -static krb5_error_code -check_one_file(krb5_context context, +krb5_error_code +krb5_internal_check_one_file(krb5_context context, const char *filename, struct passwd *pwd, - krb5_principal principal, + krb5_const_principal principal, + int pattern_match_level, krb5_boolean *result) { FILE *f; @@ -90,10 +91,14 @@ } } *newline = '\0'; + if (pattern_match_level>1) { + if (!strncmp(buf,"#STOP",5)) break; + } ret = krb5_parse_name (context, buf, &tmp); if (ret) continue; - *result = krb5_principal_compare (context, principal, tmp); + *result = (pattern_match_level ? krb5_principal_match (context, principal, tmp): krb5_principal_compare (context, principal, tmp)); + if (*result) _krb5_luser_principal_add_to_cache(context,principal,pwd->pw_name); krb5_free_principal (context, tmp); if (*result) { fclose (f); @@ -157,7 +162,7 @@ dent->d_name[strlen(dent->d_name) - 1] == '~') /* emacs backup */ continue; snprintf(filename, sizeof(filename), "%s/%s", dirname, dent->d_name); - ret = check_one_file(context, filename, pwd, principal, result); + ret = krb5_internal_check_one_file(context, filename, pwd, principal, FALSE, result); if(ret == 0 && *result == TRUE) break; ret = 0; /* don't propagate errors upstream */ @@ -194,6 +199,7 @@ } } krb5_free_host_realm (context, realms); + if (result) _krb5_luser_principal_add_to_cache(context,principal,luser); return result; } @@ -226,6 +232,18 @@ if (pwd == NULL) return FALSE; + if(0==_krb5_luser_principal_cache_query_luser(context,luser,&principal)) return TRUE; + + buflen = strlen(luser) + strlen(ETCK5LOGIND) + 1; + buf = malloc(buflen); + if(buf == NULL) + return FALSE; + strlcpy(buf,ETCK5LOGIND,buflen); + strlcat(buf,luser,buflen); + ret = krb5_internal_check_one_file(context, buf, pwd, principal, TRUE, &result); + free(buf); + if (ret == 0) return result; //if there is a file, don't process further. + #define KLOGIN "/.k5login" buflen = strlen(pwd->pw_dir) + sizeof(KLOGIN) + 2; /* 2 for .d */ buf = malloc(buflen); @@ -234,7 +252,7 @@ /* check user's ~/.k5login */ strlcpy(buf, pwd->pw_dir, buflen); strlcat(buf, KLOGIN, buflen); - ret = check_one_file(context, buf, pwd, principal, &result); + ret = krb5_internal_check_one_file(context, buf, pwd, principal, FALSE, &result); if(ret == 0 && result == TRUE) { free(buf); diff -u /usr/src/crypto/heimdal/lib/krb5/misc.c new/misc.c --- /usr/src/crypto/heimdal/lib/krb5/misc.c 2008-05-07 08:39:37.000000000 -0500 +++ new/misc.c 2011-10-21 15:29:06.000000000 -0500 @@ -84,3 +84,205 @@ krb5_clear_error_string(context); return ret; } + + +//Begin caching routines used by kuserok and aname_to_lname. Here we hope to save results of previous scans of +//.k5login and similar files to speed repeated scans. + +//Note these routines impose no significant memory overhead until kuserok or aname_to_lname first returns a positive result. + +//ADMINISTRATIVE EFFECT: kuserok and aname_to_lname almost certainly will approve associations among deleted users/principals +//for 5 minutes after their removal from .k5login/ local passwd / realm, or until the library is reloaded, or until +//krb5_flush_luser_principal_cache(context) is called. + +//Provided are four major entry points: +//add new association validating a link between a principal name and a user name, +//lookup principal name given local user name, lookup user name given principal name, +//and free internal structures. +//Entries are saved for 5 minutes. In the interests of overall speed, it is possible +//but not very likely that an association added within the past 5 minutes will not be found in the cache, depending +//on mostly on how many new associations were recently added and whether the desired is among the then oldest. + +struct _krb5_luser_principal_cache_entry { //the cache is made up as an array of these elements. + char *luser; //local user name, null terminated string. + krb5_principal princ; + clock_t expiration_ticks; //if clock()>expiration ticks, ignore&delete entry + unsigned int lhe,phe; //index into luser,principal hash tables referring to this entry offset+1. +}; +#define KRB5_LUSER_PRINCIPAL_CACHE_ARRAYSIZE 1023 +#define KRB5_LUSER_PRINCIPAL_CACHE_FANOUT 3 +#define KRB5_LUSER_PRINCIPAL_CACHE_HASHSIZE (KRB5_LUSER_PRINCIPAL_CACHE_FANOUT*KRB5_LUSER_PRINCIPAL_CACHE_ARRAYSIZE) + +struct _krb5_luser_principal_cache { + struct _krb5_luser_principal_cache_entry cache[KRB5_LUSER_PRINCIPAL_CACHE_ARRAYSIZE]; + int luser_hash_table[KRB5_LUSER_PRINCIPAL_CACHE_HASHSIZE]; //luser_hash_table[x]==0->free, + //else cache[luser_hash_table[x]-1].lhe==x + int principal_hash_table[KRB5_LUSER_PRINCIPAL_CACHE_HASHSIZE]; //principal_hash_table[x]==0->free, + //else cache[principal_hash_table[x]-1].phe==x +}; + + + +static unsigned int char_hash(const char *s){ + unsigned int h; + if (s==NULL) return 0; + for(h=0;*s;s++) { h = (h&0x80000000) ? (1|(h<<1)) : h<<1; h = h ^ *s; } + return h; +} + +static unsigned int luser_hash(const char *s){ + return char_hash(s)%KRB5_LUSER_PRINCIPAL_CACHE_HASHSIZE; +} + +static unsigned int princ_hash(krb5_const_principal princ){ + unsigned int h; int i; + if (princ==NULL) return 0; + for(h=0,i=0;i<princ->name.name_string.len;i++) h ^= char_hash(princ->name.name_string.val[i]); + h ^= char_hash(princ->realm); + return h % KRB5_LUSER_PRINCIPAL_CACHE_HASHSIZE; +} + +static void free_pce(krb5_context context,struct _krb5_luser_principal_cache_entry *pce){ + if (pce==NULL) return; + free(pce->luser); pce->luser=NULL; + krb5_free_principal(context,pce->princ); pce->princ=NULL; + pce->expiration_ticks=0; + context->luser_principal_cache->luser_hash_table[pce->lhe]=0; + context->luser_principal_cache->principal_hash_table[pce->phe]=0; +} + +static int choose_pce(krb5_context context,int *base,unsigned int h){ + clock_t oldest,pce_expire; + unsigned int oldest_h; int i; + struct _krb5_luser_principal_cache_entry *cache; + oldest=clock(); + cache = &context->luser_principal_cache->cache[0]; + for(i=0,oldest_h=h;i<KRB5_LUSER_PRINCIPAL_CACHE_FANOUT;i++,h=(h+1)%KRB5_LUSER_PRINCIPAL_CACHE_HASHSIZE){ + if (base[h]==0) return h; + pce_expire = cache[base[h]-1].expiration_ticks; + if (pce_expire<oldest) { oldest = pce_expire; oldest_h=h;} + } + return oldest_h; +} + + + +void _krb5_luser_principal_add_to_cache(krb5_context context,krb5_const_principal princ,const char *luser){ + //Here we record that one of the k5login mechanisms has validated an association between a principal and a local user. + //If either the user or principal is given to a lookup routine up to 5 minutes later, the other might be found quickly. + //Note 'might'. Expected associations might not be found and as this exists for speed only, misses only cost time as the + //fallback is to search the primary sources. + //NB: Assumed is that a lookup of what we're inserting failed. It's no error for something to be inserted twice, just wasteful. + unsigned int h,old_h; int i; + clock_t now,old; + struct _krb5_luser_principal_cache *pc; + struct _krb5_luser_principal_cache_entry *pce; + if ((luser==NULL) || (princ==NULL) || (context==NULL)) return; + HEIMDAL_MUTEX_lock(&context->luser_principal_cache_mutex); + if (context->luser_principal_cache==NULL) { //if we haven't done a kuser_ok or aname_to_lname yet, reserve the cache resources. + context->luser_principal_cache = (struct _krb5_luser_principal_cache *) calloc(1,sizeof(*context->luser_principal_cache)); + sranddev(); + } + if (context->luser_principal_cache==NULL) goto bail; + //Find any free entry, or absent that one older than 30 minutes, or absent that the oldest one. + pc = context->luser_principal_cache; + old = now = clock(); + old_h = h = rand() % KRB5_LUSER_PRINCIPAL_CACHE_ARRAYSIZE; + for(i=0,pce=&pc->cache[h];i<KRB5_LUSER_PRINCIPAL_CACHE_ARRAYSIZE;i++,h=(h+1) % KRB5_LUSER_PRINCIPAL_CACHE_ARRAYSIZE,pce=&pc->cache[h]){ + if (pce->luser==NULL) break; + if (pce->expiration_ticks<now) break; + if (pce->expiration_ticks<old) { old=pce->expiration_ticks; old_h=h; } + } + if(i==KRB5_LUSER_PRINCIPAL_CACHE_ARRAYSIZE) { pce= &pc->cache[old_h]; h = old_h; } //expire oldest + if (pce!=NULL) free_pce(context,pce); + pce->luser = strdup(luser); + krb5_copy_principal(context,princ,&pce->princ); + pce->expiration_ticks = clock()*5*60*CLOCKS_PER_SEC; + //Entry secure, now locate it in the hash table. + pce->lhe = choose_pce(context,&pc->luser_hash_table[0],luser_hash(pce->luser)); + if (pc->luser_hash_table[pce->lhe]!=0) free_pce(context,&pc->cache[pc->luser_hash_table[pce->lhe]-1]); + pce->phe = choose_pce(context,&pc->principal_hash_table[0],princ_hash(pce->princ)); + if (pc->principal_hash_table[pce->phe]!=0) free_pce(context,&pc->cache[pc->principal_hash_table[pce->phe]-1]); + pc->luser_hash_table[pce->lhe]=h+1; + pc->principal_hash_table[pce->phe]=h+1; + //{ char *ppn; krb5_unparse_name(context,princ,&ppn); printf("Cached user %s == principal %s - %d/%d/%d\n",luser,ppn,h,pce->lhe,pce->phe); free(ppn); } +bail: + HEIMDAL_MUTEX_unlock(&context->luser_principal_cache_mutex); +} + +void KRB5_LIB_FUNCTION krb5_luser_principal_cache_free(krb5_context context) { + int i; + struct _krb5_luser_principal_cache_entry *ce; + HEIMDAL_MUTEX_lock(&context->luser_principal_cache_mutex); + if (context->luser_principal_cache!=NULL) { + for(i=0,ce=&context->luser_principal_cache->cache[0];i<KRB5_LUSER_PRINCIPAL_CACHE_ARRAYSIZE;i++,ce++) free_pce(context,ce); + free(context->luser_principal_cache); + context->luser_principal_cache=NULL; + } + HEIMDAL_MUTEX_unlock(&context->luser_principal_cache_mutex); +} + +//if *princ!=NULL, return 0 only if the luser<->princ match is in the cache, else ENOENT. +//if *princ==NULL, if luser is in the cache, set princ to the first hit and return 0, else ENOENT +krb5_error_code _krb5_luser_principal_cache_query_luser(krb5_context context,const char *luser,krb5_principal *princ) { + int ret,i,j; unsigned int h; + struct _krb5_luser_principal_cache *pc; + struct _krb5_luser_principal_cache_entry *pce; + clock_t now; + pc = context->luser_principal_cache; + if ((pc==NULL) || (princ==NULL) || (context==NULL) || (luser==NULL)) return ENOENT; + ret = 0; + h = luser_hash(luser); + now = clock(); + HEIMDAL_MUTEX_lock(&context->luser_principal_cache_mutex); + for(i=0;i<KRB5_LUSER_PRINCIPAL_CACHE_FANOUT;i++,h=(h+1)%KRB5_LUSER_PRINCIPAL_CACHE_HASHSIZE){ + j=pc->luser_hash_table[h]; + if (j!=0) { + if ((pc->cache[j-1].expiration_ticks<now) && !strcmp(pc->cache[j-1].luser,luser)) { + if (*princ!=NULL) { + if (krb5_principal_compare(context,*princ,pc->cache[j-1].princ)) break; + } else { + krb5_copy_principal(context,pc->cache[j-1].princ,princ); + break; + } + } + } + } + HEIMDAL_MUTEX_unlock(&context->luser_principal_cache_mutex); + if (i==KRB5_LUSER_PRINCIPAL_CACHE_FANOUT) ret=ENOENT; + //{ char *ppn; if (ret) ppn = strdup("?"); else krb5_unparse_name(context,*princ,&ppn); printf("luser cache %s user %s <--> %s\n",ret?"miss":"hit",luser,ppn); free(ppn); } + return ret; +} + +//if *luser!=NULL, return 0 only if the luser<->princ match is in the cache, else ENOENT. +//if *luser==NULL, if princ is in the cache, set luser to the first hit and return 0, else ENOENT +krb5_error_code _krb5_luser_principal_cache_query_princ(krb5_context context,krb5_const_principal princ,char **luser) { + int ret,i,j; unsigned int h; + struct _krb5_luser_principal_cache *pc; + struct _krb5_luser_principal_cache_entry *pce; + clock_t now; + pc = context->luser_principal_cache; + if ((pc==NULL) || (princ==NULL) || (context==NULL) || (luser==NULL)) return ENOENT; + ret = 0; + h = princ_hash(princ); + now = clock(); + HEIMDAL_MUTEX_lock(&context->luser_principal_cache_mutex); + for(i=0;i<KRB5_LUSER_PRINCIPAL_CACHE_FANOUT;i++,h=(h+1)%KRB5_LUSER_PRINCIPAL_CACHE_HASHSIZE){ + j=pc->principal_hash_table[h]; + if (j!=0) { + if ((pc->cache[j-1].expiration_ticks<now) && krb5_principal_compare(context,princ,pc->cache[j-1].princ)) { + + if (*luser!=NULL) { + if (strcmp(pc->cache[j-1].luser,*luser)) break; + } else { + *luser = strdup(pc->cache[j-1].luser); + break; + } + } + } + } + HEIMDAL_MUTEX_unlock(&context->luser_principal_cache_mutex); + if (i==KRB5_LUSER_PRINCIPAL_CACHE_FANOUT) ret=ENOENT; + //{ char *ppn; krb5_unparse_name(context,princ,&ppn); printf("princ cache %s user %s <--> %s\n",ret?"miss":"hit",ret? "?":*luser,ppn); free(ppn); } + return ret; +} diff -u /usr/src/kerberos5/lib/libgssapi_krb5/gss_krb5.c new/gss_krb5.c --- /usr/src/kerberos5/lib/libgssapi_krb5/gss_krb5.c 2009-08-03 03:13:06.000000000 -0500 +++ new/gss_krb5.c 2011-10-24 17:47:21.407712267 -0500 @@ -33,6 +33,7 @@ #include <krb5.h> #include <roken.h> +#include <der.h> OM_uint32 gss_krb5_copy_ccache(OM_uint32 *minor_status, diff -u /usr/src/kerberos5/lib/libgssapi_krb5/pname_to_uid.c new/pname_to_uid.c --- /usr/src/kerberos5/lib/libgssapi_krb5/pname_to_uid.c 2009-08-03 03:13:06.000000000 -0500 +++ new/pname_to_uid.c 2011-10-24 17:47:35.422326641 -0500 @@ -37,7 +37,7 @@ krb5_context context; krb5_const_principal name = (krb5_const_principal) pname; krb5_error_code kret; - char lname[MAXLOGNAME + 1], buf[128]; + char lname[MAXLOGNAME + 1], buf[1024]; struct passwd pwd, *pw; GSSAPI_KRB5_INIT (&context);