check the user's ~/.k5login.d directory for access files, all of which

is handled like the regular ~/.k5login


git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@15083 ec53bebd-3082-4978-b11e-865c3cabbd6b
This commit is contained in:
Johan Danielsson
2005-05-04 12:11:22 +00:00
parent e419ac333a
commit 67b2fd15f7
2 changed files with 122 additions and 42 deletions

View File

@@ -1,4 +1,4 @@
.\" Copyright (c) 2003-2004 Kungliga Tekniska H<>gskolan
.\" Copyright (c) 2003-2005 Kungliga Tekniska H<>gskolan
.\" (Royal Institute of Technology, Stockholm, Sweden).
.\" All rights reserved.
.\"
@@ -31,12 +31,12 @@
.\"
.\" $Id$
.\"
.Dd August 19, 2004
.Dd May 4, 2005
.Dt KRB5_KUSEROK 3
.Os HEIMDAL
.Sh NAME
.Nm krb5_kuserok
.Nd "verifies if a principal can log in as a user"
.Nd "checks if a principal is permitted to login as a user"
.Sh LIBRARY
Kerberos 5 Library (libkrb5, -lkrb5)
.Sh SYNOPSIS
@@ -67,10 +67,23 @@ The
.Pa .k5login
file must contain one principal per line, be owned by
.Fa user ,
and not be writable by group or other.
and not be writable by group or other (but must be readable by
anyone).
.Pp
Note that if the file exists, no implicit access rights are given to
.Fa user Ns @ Ns Aq localrealm .
.Pp
Optionally, a set of files may be put in
.Pa ~/.k5login.d ( Ns
a directory), in which case they will all be checked in the same
manner as
.Pa .k5login .
The files may be called anything, but files starting with a hash
.Dq ( # ) ,
or ending with a tilde
.Dq ( ~ )
are ignored. Subdirectories are not traversed. Note that this
directory may not be checked by other implementations.
.Sh RETURN VALUES
.Nm
returns
@@ -78,6 +91,10 @@ returns
if access should be granted,
.Dv FALSE
otherwise.
.Sh HISTORY
The
.Pa ~/.k5login.d
feature appeared in Heimdal 0.7.
.Sh SEE ALSO
.Xr krb5_get_default_realms 3 ,
.Xr krb5_verify_user 3 ,

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997 - 2004 Kungliga Tekniska H<>gskolan
* Copyright (c) 1997 - 2005 Kungliga Tekniska H<>gskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
@@ -36,9 +36,8 @@
RCSID("$Id$");
/*
* Return TRUE iff `principal' is allowed to login as `luser'.
*/
/* 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,
@@ -78,8 +77,9 @@ check_one_file(krb5_context context,
while (fgets (buf, sizeof(buf), f) != NULL) {
krb5_principal tmp;
char *newline = buf + strcspn(buf, "\n");
if(buf[strcspn(buf, "\n")] != '\n') {
if(*newline != '\n') {
int c;
c = fgetc(f);
if(c != EOF) {
@@ -89,7 +89,7 @@ check_one_file(krb5_context context,
continue;
}
}
buf[strcspn(buf, "\n")] = '\0';
*newline = '\0';
ret = krb5_parse_name (context, buf, &tmp);
if (ret)
continue;
@@ -104,6 +104,68 @@ check_one_file(krb5_context context,
return 0;
}
static krb5_error_code
check_directory(krb5_context context,
const char *dirname,
struct passwd *pwd,
krb5_principal principal,
krb5_boolean *result)
{
DIR *d;
struct dirent *dent;
char buf[BUFSIZ];
krb5_error_code ret = 0;
struct stat st;
*result = FALSE;
if(lstat(buf, &st) < 0)
return errno;
if (!S_ISDIR(st.st_mode))
return ENOTDIR;
if (st.st_uid != pwd->pw_uid && st.st_uid != 0)
return EACCES;
if ((st.st_mode & (S_IWGRP | S_IWOTH)) != 0)
return EACCES;
if((d = opendir(buf)) == NULL)
return errno;
#ifdef HAVE_DIRFD
{
int fd;
struct stat st2;
fd = dirfd(d);
if(fstat(fd, &st2) < 0) {
closedir(d);
return errno;
}
if(st.st_dev != st2.st_dev || st.st_ino != st2.st_ino) {
closedir(d);
return EACCES;
}
}
#endif
while((dent = readdir(d)) != NULL) {
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;
snprintf(buf, sizeof(buf), "%s/%s", dirname, dent->d_name);
ret = check_one_file(context, buf, pwd, principal, result);
if(ret == 0 && *result == TRUE)
break;
ret = 0; /* don't propagate errors upstream */
}
closedir(d);
return ret;
}
static krb5_boolean
match_local_principals(krb5_context context,
krb5_principal principal,
@@ -135,16 +197,23 @@ match_local_principals(krb5_context context,
return result;
}
/**
* Return TRUE iff `principal' is allowed to login as `luser'.
*/
krb5_boolean KRB5_LIB_FUNCTION
krb5_kuserok (krb5_context context,
krb5_principal principal,
const char *luser)
{
char *buf;
size_t buflen;
struct passwd *pwd;
krb5_error_code ret;
krb5_boolean result = FALSE;
krb5_boolean found_file = FALSE;
#ifdef HAVE_GETPWNAM_R
char pwbuf[2048];
struct passwd pw;
@@ -157,43 +226,37 @@ krb5_kuserok (krb5_context context,
if (pwd == NULL)
return FALSE;
/* check user's ~/.k5login */
if (asprintf (&buf, "%s/.k5login", pwd->pw_dir) == -1)
#define KLOGIN "/.k5login"
buflen = strlen(pwd->pw_dir) + sizeof(KLOGIN) + 2; /* 2 for .d */
buf = malloc(buflen);
if(buf == NULL)
return FALSE;
/* check user's ~/.k5login */
strlcpy(buf, pwd->pw_dir, buflen);
strlcat(buf, KLOGIN, buflen);
ret = check_one_file(context, buf, pwd, principal, &result);
/* but if it doesn't exist, allow all principals
matching <localuser>@<LOCALREALM> */
if(ret == ENOENT) {
if(ret == 0 && result == TRUE) {
free(buf);
return match_local_principals(context, principal, luser);
return TRUE;
}
#if notyet
/* on the other hand, if it's a directory, check all files
contained therein */
if (ret == EISDIR) {
DIR *d = opendir(buf);
struct dirent *dent;
char *buf2;
if(d == NULL)
return FALSE;
while((dent = readdir(d)) != NULL) {
if(strcmp(dent->d_name, ".") == 0 ||
strcmp(dent->d_name, "..") == 0)
continue;
if (asprintf(&buf2, "%s/%s", buf, dent->d_name) == -1)
break;
ret = check_one_file(context, buf2, pwd, principal, &result);
free(buf2);
if(ret == 0 && result == TRUE)
break;
}
closedir(d);
}
#endif
if(ret != ENOENT)
found_file = TRUE;
strlcat(buf, ".d", buflen);
ret = check_directory(context, buf, pwd, principal, &result);
free(buf);
if (ret)
return FALSE;
return result;
if(ret == 0 && result == TRUE)
return TRUE;
if(ret != ENOENT && ret != ENOTDIR)
found_file = TRUE;
/* finally if no files exist, allow all principals matching
<localuser>@<LOCALREALM> */
if(found_file == FALSE)
return match_local_principals(context, principal, luser);
return FALSE;
}