Add DENY rule for krb5_kuserok() and update manpage

This commit is contained in:
Nicolas Williams
2011-12-08 10:58:18 -06:00
parent 8e63cff2cc
commit b9f8e6d956
2 changed files with 102 additions and 29 deletions

View File

@@ -263,21 +263,27 @@ wrong server name into the gss_accept_sec_context call.
.It Li k5login_directory = Va directory .It Li k5login_directory = Va directory
Alternative location for user .k5login files. Tokens in the form of Alternative location for user .k5login files. Tokens in the form of
%{luser} are expanded to the name of the user whose .k5login file is %{luser} are expanded to the name of the user whose .k5login file is
%needed. needed. This option is provided for compatibility with MIT krb5
configuration files.
.It Li k5login_authoritative = Va boolean .It Li k5login_authoritative = Va boolean
If true then if a principal is not found in k5login files then If true then if a principal is not found in k5login files then
krb5_userok() will not fallback on principal to username mapping. krb5_userok() will not fallback on principal to username mapping. This
option is provided for compatibility with MIT krb5 configuration files.
.It Li kuserok = Va rule ... .It Li kuserok = Va rule ...
Specifies krb5_kuserok(3) behavior. If multiple values are given, then Specifies krb5_kuserok(3) behavior. If multiple values are given, then
krb5_kuserok(3) will try them in order until one succeeds or all fail. krb5_kuserok(3) will evaluate them in order until one succeeds or all
Rules are implemented by plugins, with three built-in plugins described fail. Rules are implemented by plugins, with three built-in plugins
below. Default: USER-K5LOGIN SIMPLE. described below. Default: USER-K5LOGIN SIMPLE DENY.
.It Li kuserok = Va DENY
If set and evaluated then krb5_userok(3) will deny access to the given
username no matter what the principal name might be.
.It Li kuserok = Va SIMPLE .It Li kuserok = Va SIMPLE
If set then krb5_userok(3) will use principal to username mapping (see If set and evaluated then krb5_userok(3) will use principal to username
auth_to_local below). If the principal maps to the requested username mapping (see auth_to_local below). If the principal maps to the
then access is allowed. requested username then access is allowed.
.It Li kuserok = Va SYSTEM-K5LOGIN[:directory] .It Li kuserok = Va SYSTEM-K5LOGIN[:directory]
If set then krb5_userok(3) will use k5login files named after the If set and evaluated then krb5_userok(3) will use k5login files named
after the
.Va luser .Va luser
argument to krb5_kuserok(3) in the given directory or in argument to krb5_kuserok(3) in the given directory or in
/etc/k5login.d/. If a directory is given then tokens will be expanded; /etc/k5login.d/. If a directory is given then tokens will be expanded;
@@ -286,11 +292,13 @@ the %{luser} token will be replaced with the
argument to krb5_kuserok(3). K5login files are text files, with each argument to krb5_kuserok(3). K5login files are text files, with each
line containing just a principal name; principals apearing in a user's line containing just a principal name; principals apearing in a user's
k5login file are permitted access to the user's account. Note: this rule k5login file are permitted access to the user's account. Note: this rule
performs no ownership nor permissions checks on k5login files. performs no ownership nor permissions checks on k5login files; proper
ownership and permissions/ACLs are expected due to the system k5login
location being a system location.
.It Li kuserok = Va USER-K5LOGIN .It Li kuserok = Va USER-K5LOGIN
If set then krb5_userok(3) will use ~luser/.k5login and If set and evaluated then krb5_userok(3) will use ~luser/.k5login and
~luser/.k5login.d/*. User k5login files and directories must be owned ~luser/.k5login.d/*. User k5login files and directories must be owned by
by the user and must not have world nor group write permissions. the user and must not have world nor group write permissions.
.It Li aname2lname-text-db = Va filename .It Li aname2lname-text-db = Va filename
The named file must be a sorted (in increasing order) text file where The named file must be a sorted (in increasing order) text file where
every line consists of an unparsed principal name optionally followed by every line consists of an unparsed principal name optionally followed by

View File

@@ -70,6 +70,7 @@ static krb5_error_code plugin_reg_ret;
static krb5plugin_kuserok_ftable kuserok_simple_plug; static krb5plugin_kuserok_ftable kuserok_simple_plug;
static krb5plugin_kuserok_ftable kuserok_sys_k5login_plug; static krb5plugin_kuserok_ftable kuserok_sys_k5login_plug;
static krb5plugin_kuserok_ftable kuserok_user_k5login_plug; static krb5plugin_kuserok_ftable kuserok_user_k5login_plug;
static krb5plugin_kuserok_ftable kuserok_deny_plug;
static void static void
reg_def_plugins_once(void *ctx) reg_def_plugins_once(void *ctx)
@@ -88,6 +89,10 @@ reg_def_plugins_once(void *ctx)
KRB5_PLUGIN_KUSEROK, &kuserok_user_k5login_plug); KRB5_PLUGIN_KUSEROK, &kuserok_user_k5login_plug);
if (!plugin_reg_ret) if (!plugin_reg_ret)
plugin_reg_ret = ret; plugin_reg_ret = ret;
ret = krb5_plugin_register(context, PLUGIN_TYPE_DATA,
KRB5_PLUGIN_KUSEROK, &kuserok_deny_plug);
if (!plugin_reg_ret)
plugin_reg_ret = ret;
} }
/** /**
@@ -123,6 +128,8 @@ check_owner(krb5_context context, krb5_boolean is_system_location,
*/ */
if (is_system_location || owner == NULL) if (is_system_location || owner == NULL)
return 0; return 0;
krb5_set_error_message(context, EACCES,
"User k5login files not supported on Windows");
return EACCES; return EACCES;
#else #else
struct stat st; struct stat st;
@@ -134,37 +141,67 @@ check_owner(krb5_context context, krb5_boolean is_system_location,
#endif #endif
#ifdef POSIX_GETPWNAM_R #ifdef POSIX_GETPWNAM_R
if (owner != NULL && getpwnam_r(owner, &pw, pwbuf, sizeof(pwbuf), &pwd) != 0) if (owner != NULL && getpwnam_r(owner, &pw, pwbuf, sizeof(pwbuf), &pwd) != 0) {
krb5_set_error_message(context, errno, "User unknown (getpwnam_r())");
return EACCES; return EACCES;
}
#else #else
pwd = getpwnam(luser); pwd = getpwnam(luser);
if (owner != NULL && pwd == NULL) if (owner != NULL && pwd == NULL) {
krb5_set_error_message(context, errno, "User unknown (getpwnam())");
return EACCES; return EACCES;
}
#endif #endif
if (dir) { if (dir) {
if (fstat(dirfd(dir), &st) == -1) if (fstat(dirfd(dir), &st) == -1) {
krb5_set_error_message(context, errno, "fstat() of k5login.d failed");
return errno; return errno;
if (!S_ISDIR(st.st_mode)) }
if (!S_ISDIR(st.st_mode)) {
krb5_set_error_message(context, ENOTDIR, "k5login.d not a directory");
return ENOTDIR; return ENOTDIR;
if (st.st_dev != dirlstat->st_dev || st.st_ino != dirlstat->st_ino) }
if (st.st_dev != dirlstat->st_dev || st.st_ino != dirlstat->st_ino) {
krb5_set_error_message(context, EACCES,
"k5login.d was renamed during kuserok "
"operation");
return EACCES; return EACCES;
if ((st.st_mode & (S_IWGRP | S_IWOTH)) != 0) }
if ((st.st_mode & (S_IWGRP | S_IWOTH)) != 0) {
krb5_set_error_message(context, EACCES,
"k5login.d has world and/or group write "
"permissions");
return EACCES; /* XXX We should have a better code */ return EACCES; /* XXX We should have a better code */
if (pwd != NULL && pwd->pw_uid != st.st_uid && st.st_uid != 0) }
if (pwd != NULL && pwd->pw_uid != st.st_uid && st.st_uid != 0) {
krb5_set_error_message(context, EACCES,
"k5login.d not owned by the user or root");
return EACCES; return EACCES;
}
if (file == NULL) if (file == NULL)
return 0; return 0;
} }
if (file) { if (file) {
if (fstat(fileno(file), &st) == -1) if (fstat(fileno(file), &st) == -1) {
krb5_set_error_message(context, errno, "fstat() of k5login failed");
return errno; return errno;
if (S_ISDIR(st.st_mode)) }
if (S_ISDIR(st.st_mode)) {
krb5_set_error_message(context, EISDIR, "k5login is a directory");
return EISDIR; return EISDIR;
if ((st.st_mode & (S_IWGRP | S_IWOTH)) != 0) }
if ((st.st_mode & (S_IWGRP | S_IWOTH)) != 0) {
krb5_set_error_message(context, EISDIR,
"k5login has world and/or group write "
"permissions");
return EACCES; /* XXX We should have a better code */ return EACCES; /* XXX We should have a better code */
}
if (pwd == NULL || pwd->pw_uid == st.st_uid || st.st_uid == 0) if (pwd == NULL || pwd->pw_uid == st.st_uid || st.st_uid == 0)
return 0; return 0;
} }
krb5_set_error_message(context, EACCES,
"k5login not owned by the user or root");
return EACCES; return EACCES;
} }
@@ -244,11 +281,15 @@ check_directory(krb5_context context,
if (lstat(dirname, &st) < 0) if (lstat(dirname, &st) < 0)
return errno; return errno;
if (!S_ISDIR(st.st_mode)) if (!S_ISDIR(st.st_mode)) {
krb5_set_error_message(context, ENOTDIR, "k5login.d not a directory");
return ENOTDIR; return ENOTDIR;
}
if ((d = opendir(dirname)) == NULL) if ((d = opendir(dirname)) == NULL) {
krb5_set_error_message(context, ENOTDIR, "Could not open k5login.d");
return errno; return errno;
}
ret = check_owner(context, is_system_location, d, &st, NULL, owner); ret = check_owner(context, is_system_location, d, &st, NULL, owner);
if (ret) if (ret)
@@ -293,7 +334,7 @@ check_an2ln(krb5_context context,
lname = malloc(strlen(luser) + 1); lname = malloc(strlen(luser) + 1);
if (lname == NULL) if (lname == NULL)
return ENOMEM; return krb5_enomem(context);
ret = krb5_aname_to_localname(context, principal, strlen(luser)+1, lname); ret = krb5_aname_to_localname(context, principal, strlen(luser)+1, lname);
if (ret) if (ret)
goto out; goto out;
@@ -512,20 +553,24 @@ kuserok_user_k5login_plug_f(void *plug_ctx, krb5_context context,
profile_dir = k5login_dir; profile_dir = k5login_dir;
if (profile_dir == NULL) { if (profile_dir == NULL) {
#ifdef POSIX_GETPWNAM_R #ifdef POSIX_GETPWNAM_R
if (getpwnam_r(luser, &pw, pwbuf, sizeof(pwbuf), &pwd) != 0) if (getpwnam_r(luser, &pw, pwbuf, sizeof(pwbuf), &pwd) != 0) {
krb5_set_error_message(context, errno, "User unknown (getpwnam_r())");
return KRB5_PLUGIN_NO_HANDLE; return KRB5_PLUGIN_NO_HANDLE;
}
#else #else
pwd = getpwnam (luser); pwd = getpwnam (luser);
#endif #endif
if (pwd == NULL) if (pwd == NULL) {
krb5_set_error_message(context, errno, "User unknown (getpwnam())");
return KRB5_PLUGIN_NO_HANDLE; return KRB5_PLUGIN_NO_HANDLE;
}
profile_dir = pwd->pw_dir; profile_dir = pwd->pw_dir;
} }
#define KLOGIN "/.k5login" #define KLOGIN "/.k5login"
if (asprintf(&path, "%s/.k5login.d", profile_dir) == -1) if (asprintf(&path, "%s/.k5login.d", profile_dir) == -1)
return ENOMEM; return krb5_enomem(context);
ret = _krb5_expand_path_tokensv(context, path, &path_exp, ret = _krb5_expand_path_tokensv(context, path, &path_exp,
"luser", luser, NULL); "luser", luser, NULL);
@@ -565,6 +610,19 @@ kuserok_user_k5login_plug_f(void *plug_ctx, krb5_context context,
#endif #endif
} }
static krb5_error_code
kuserok_deny_plug_f(void *plug_ctx, krb5_context context, const char *rule,
unsigned int flags, const char *k5login_dir,
const char *luser, krb5_const_principal principal,
krb5_boolean *result)
{
if (strcmp(rule, "DENY") != 0)
return KRB5_PLUGIN_NO_HANDLE;
*result = FALSE;
return 0;
}
static krb5_error_code static krb5_error_code
kuser_ok_null_plugin_init(krb5_context context, void **ctx) kuser_ok_null_plugin_init(krb5_context context, void **ctx)
{ {
@@ -599,3 +657,10 @@ static krb5plugin_kuserok_ftable kuserok_user_k5login_plug = {
kuserok_user_k5login_plug_f, kuserok_user_k5login_plug_f,
}; };
static krb5plugin_kuserok_ftable kuserok_deny_plug = {
KRB5_PLUGIN_KUSEROK_VERSION_0,
kuser_ok_null_plugin_init,
kuser_ok_null_plugin_fini,
kuserok_deny_plug_f,
};