caching + admin specified principals enhance aname_to_lname
Harry Coin <[email protected]>
| Newsgroups | gmane.comp.encryption.kerberos.heimdal.general |
|---|---|
| Message-ID | <[email protected]> |
Here we have the bulk of the changes that add caching to
krb5_aname_to_lname. And, it adds the ability to extract the user names
the administrator prefers from the principal names, defaulting otherwise
to the current behavior. Here one administration place, /etc/k5login.d
serves to enhance both krb5_kuserok, and krb5_aname_to_lname.
So, if file /etc/k5login.d/oscillscopes had
oscillscopes/*.innerlab.domain.org
#stop
firedept@REALM
then principal 'oscilloscopes/whatnot.innerlab.domain.org would be able
to log in to the local box, and when asked what local user name ought to
be associated with 'oscilloscopes/whatnot.innerlab.domain.org' the
routine will return 'oscilloscopes' after consulting the files once,
then almost instantly for the next 5 minutes. It will not return
'oscilloscopes' if asked what user ought be matched to 'firedept@REALM'.
Without these changes, principals having a / in the name will not be
able to use NFS, such users will regress to 'nobody:nogroup' .
Caching routines in the tarball in misc.c here:
http://www.quietfountain.com/krb5nfspatches.tbz
#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,
size_t lnsize,
char *lname)
{
krb5_error_code ret;
krb5_realm *lrealms, *r;
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;
valid = 0;
for (r = lrealms; *r != NULL; ++r) {
if (strcmp (*r, aname->realm) == 0) {
valid = 1;
break;
}
}
krb5_free_host_realm (context, lrealms);
if (valid && (aname->name.name_string.len == 1)) {
res = aname->name.name_string.val[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;
res = "root";
ret = krb5_copy_principal(context, aname, &rootprinc);
if (ret)
return ret;
userok = krb5_kuserok(context, rootprinc, res); //note this makes
use of the cache, so it is fast.
krb5_free_principal(context, rootprinc);
if (userok) {
len = strlen (res);
if (len >= lnsize)
return ERANGE;
strlcpy (lname, res, lnsize);
return 0;
}
}
//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;
}