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:
@@ -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 ,
|
||||
|
@@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user