split user and dir, use rk_getpwnam_r
This commit is contained in:
@@ -102,17 +102,23 @@ reg_def_plugins_once(void *ctx)
|
|||||||
*
|
*
|
||||||
* Inputs:
|
* Inputs:
|
||||||
*
|
*
|
||||||
* @context A krb5_context
|
* @param context A krb5_context
|
||||||
* @is_system_location TRUE if the dir/file are system locations or
|
* @param filename Name of item to introspection
|
||||||
* FALSE if they are user home directory locations
|
* @param is_system_location TRUE if the dir/file are system locations or
|
||||||
* @dir Directory (optional)
|
* FALSE if they are user home directory locations
|
||||||
* @dirlstat A pointer to struct stat for the directory (optional)
|
* @param dir Directory (optional)
|
||||||
* @file File (optional)
|
* @param dirlstat A pointer to struct stat for the directory (optional)
|
||||||
* @owner Name of user that is expected to own the file
|
* @param file File (optional)
|
||||||
|
* @param owner Name of user that is expected to own the file
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static krb5_error_code
|
static krb5_error_code
|
||||||
check_owner(krb5_context context, krb5_boolean is_system_location,
|
check_owner_dir(krb5_context context,
|
||||||
DIR *dir, struct stat *dirlstat, FILE *file, const char *owner)
|
const char *filename,
|
||||||
|
krb5_boolean is_system_location,
|
||||||
|
DIR *dir,
|
||||||
|
struct stat *dirlstat,
|
||||||
|
const char *owner)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
/*
|
/*
|
||||||
@@ -132,79 +138,124 @@ check_owner(krb5_context context, krb5_boolean is_system_location,
|
|||||||
"User k5login files not supported on Windows");
|
"User k5login files not supported on Windows");
|
||||||
return EACCES;
|
return EACCES;
|
||||||
#else
|
#else
|
||||||
struct stat st;
|
struct passwd pw, *pwd = NULL;
|
||||||
struct passwd *pwd = NULL;
|
|
||||||
#ifdef POSIX_GETPWNAM_R
|
|
||||||
char pwbuf[2048];
|
char pwbuf[2048];
|
||||||
struct passwd pw;
|
struct stat st;
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef POSIX_GETPWNAM_R
|
heim_assert(owner != NULL, "no directory owner ?");
|
||||||
if (owner != NULL && getpwnam_r(owner, &pw, pwbuf, sizeof(pwbuf), &pwd) != 0) {
|
|
||||||
krb5_set_error_message(context, errno, "User unknown (getpwnam_r())");
|
if (rk_getpwnam_r(owner, &pw, pwbuf, sizeof(pwbuf), &pwd) != 0) {
|
||||||
|
krb5_set_error_message(context, errno,
|
||||||
|
"User unknown %s (getpwnam_r())", owner);
|
||||||
return EACCES;
|
return EACCES;
|
||||||
}
|
}
|
||||||
#else
|
if (pwd == NULL) {
|
||||||
pwd = getpwnam(luser);
|
krb5_set_error_message(context, EACCES, "no user %s", owner);
|
||||||
if (owner != NULL && pwd == NULL) {
|
|
||||||
krb5_set_error_message(context, errno, "User unknown (getpwnam())");
|
|
||||||
return EACCES;
|
return EACCES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fstat(dirfd(dir), &st) == -1) {
|
||||||
|
krb5_set_error_message(context, EACCES,
|
||||||
|
"fstat(%s) of k5login.d failed",
|
||||||
|
filename);
|
||||||
|
return EACCES;
|
||||||
|
}
|
||||||
|
if (!S_ISDIR(st.st_mode)) {
|
||||||
|
krb5_set_error_message(context, ENOTDIR, "%s not a directory",
|
||||||
|
filename);
|
||||||
|
return ENOTDIR;
|
||||||
|
}
|
||||||
|
if (st.st_dev != dirlstat->st_dev || st.st_ino != dirlstat->st_ino) {
|
||||||
|
krb5_set_error_message(context, EACCES,
|
||||||
|
"%s was renamed during kuserok "
|
||||||
|
"operation", filename);
|
||||||
|
return EACCES;
|
||||||
|
}
|
||||||
|
if ((st.st_mode & (S_IWGRP | S_IWOTH)) != 0) {
|
||||||
|
krb5_set_error_message(context, EACCES,
|
||||||
|
"%s has world and/or group write "
|
||||||
|
"permissions", filename);
|
||||||
|
return EACCES;
|
||||||
|
}
|
||||||
|
if (pwd->pw_uid != st.st_uid && st.st_uid != 0) {
|
||||||
|
krb5_set_error_message(context, EACCES,
|
||||||
|
"%s not owned by the user (%s) or root",
|
||||||
|
filename, owner);
|
||||||
|
return EACCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
if (dir) {
|
}
|
||||||
if (fstat(dirfd(dir), &st) == -1) {
|
|
||||||
krb5_set_error_message(context, errno, "fstat() of k5login.d failed");
|
static krb5_error_code
|
||||||
return errno;
|
check_owner_file(krb5_context context,
|
||||||
}
|
const char *filename,
|
||||||
if (!S_ISDIR(st.st_mode)) {
|
FILE *file, const char *owner)
|
||||||
krb5_set_error_message(context, ENOTDIR, "k5login.d not a directory");
|
{
|
||||||
return ENOTDIR;
|
#ifdef _WIN32
|
||||||
}
|
/*
|
||||||
if (st.st_dev != dirlstat->st_dev || st.st_ino != dirlstat->st_ino) {
|
* XXX Implement this!
|
||||||
krb5_set_error_message(context, EACCES,
|
*
|
||||||
"k5login.d was renamed during kuserok "
|
* The thing to do is to call _get_osfhandle() on fileno(file) and
|
||||||
"operation");
|
* dirfd(dir) to get HANDLEs to the same, then call
|
||||||
return EACCES;
|
* GetSecurityInfo() on those HANDLEs to get the security descriptor
|
||||||
}
|
* (SD), then check the owner and DACL. Checking the DACL sounds
|
||||||
if ((st.st_mode & (S_IWGRP | S_IWOTH)) != 0) {
|
* like a lot of work (what, derive a mode from the ACL the way
|
||||||
krb5_set_error_message(context, EACCES,
|
* NFSv4 servers do?). Checking the owner means doing an LSARPC
|
||||||
"k5login.d has world and/or group write "
|
* lookup at least (to get the user's SID).
|
||||||
"permissions");
|
*/
|
||||||
return EACCES; /* XXX We should have a better code */
|
if (is_system_location || owner == NULL)
|
||||||
}
|
return 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;
|
|
||||||
}
|
|
||||||
if (file == NULL)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (file) {
|
|
||||||
if (fstat(fileno(file), &st) == -1) {
|
|
||||||
krb5_set_error_message(context, errno, "fstat() of k5login failed");
|
|
||||||
return errno;
|
|
||||||
}
|
|
||||||
if (S_ISDIR(st.st_mode)) {
|
|
||||||
krb5_set_error_message(context, EISDIR, "k5login is a directory");
|
|
||||||
return EISDIR;
|
|
||||||
}
|
|
||||||
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 */
|
|
||||||
}
|
|
||||||
if (pwd == NULL || pwd->pw_uid == st.st_uid || st.st_uid == 0)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
krb5_set_error_message(context, EACCES,
|
krb5_set_error_message(context, EACCES,
|
||||||
"k5login not owned by the user or root");
|
"User k5login files not supported on Windows");
|
||||||
return EACCES;
|
return EACCES;
|
||||||
|
#else
|
||||||
|
struct passwd pw, *pwd = NULL;
|
||||||
|
char pwbuf[2048];
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
heim_assert(owner != NULL, "no file owner ?");
|
||||||
|
|
||||||
|
if (rk_getpwnam_r(owner, &pw, pwbuf, sizeof(pwbuf), &pwd) != 0) {
|
||||||
|
krb5_set_error_message(context, errno,
|
||||||
|
"User unknown %s (getpwnam_r())", owner);
|
||||||
|
return EACCES;
|
||||||
|
}
|
||||||
|
if (pwd == NULL) {
|
||||||
|
krb5_set_error_message(context, EACCES, "no user %s", owner);
|
||||||
|
return EACCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fstat(fileno(file), &st) == -1) {
|
||||||
|
krb5_set_error_message(context, EACCES, "fstat(%s) of k5login failed",
|
||||||
|
filename);
|
||||||
|
return EACCES;
|
||||||
|
}
|
||||||
|
if (S_ISDIR(st.st_mode)) {
|
||||||
|
krb5_set_error_message(context, EISDIR, "k5login: %s is a directory",
|
||||||
|
filename);
|
||||||
|
return EISDIR;
|
||||||
|
}
|
||||||
|
if ((st.st_mode & (S_IWGRP | S_IWOTH)) != 0) {
|
||||||
|
krb5_set_error_message(context, EISDIR,
|
||||||
|
"k5login %s has world and/or group write "
|
||||||
|
"permissions", filename);
|
||||||
|
return EACCES;
|
||||||
|
}
|
||||||
|
if (pwd->pw_uid != st.st_uid || st.st_uid != 0) {
|
||||||
|
krb5_set_error_message(context, EACCES,
|
||||||
|
"k5login %s not owned by the user or root",
|
||||||
|
filename);
|
||||||
|
return EACCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* see if principal is mentioned in the filename access file, return
|
/* see if principal is mentioned in the filename access file, return
|
||||||
TRUE (in result) if so, FALSE otherwise */
|
TRUE (in result) if so, FALSE otherwise */
|
||||||
|
|
||||||
@@ -227,7 +278,7 @@ check_one_file(krb5_context context,
|
|||||||
return errno;
|
return errno;
|
||||||
rk_cloexec_file(f);
|
rk_cloexec_file(f);
|
||||||
|
|
||||||
ret = check_owner(context, 0, NULL, NULL, f, owner);
|
ret = check_owner_file(context, filename, f, owner);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@@ -291,7 +342,7 @@ check_directory(krb5_context context,
|
|||||||
return errno;
|
return errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = check_owner(context, is_system_location, d, &st, NULL, owner);
|
ret = check_owner_dir(context, dirname, is_system_location, d, &st, owner);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@@ -551,11 +602,8 @@ kuserok_user_k5login_plug_f(void *plug_ctx, krb5_context context,
|
|||||||
const char *profile_dir = NULL;
|
const char *profile_dir = NULL;
|
||||||
krb5_error_code ret;
|
krb5_error_code ret;
|
||||||
krb5_boolean found_file = FALSE;
|
krb5_boolean found_file = FALSE;
|
||||||
struct passwd *pwd = NULL;
|
struct passwd pw, *pwd = NULL;
|
||||||
#ifdef POSIX_GETPWNAM_R
|
|
||||||
struct passwd pw;
|
|
||||||
char pwbuf[2048];
|
char pwbuf[2048];
|
||||||
#endif
|
|
||||||
|
|
||||||
if (strcmp(rule, "USER-K5LOGIN") != 0)
|
if (strcmp(rule, "USER-K5LOGIN") != 0)
|
||||||
return KRB5_PLUGIN_NO_HANDLE;
|
return KRB5_PLUGIN_NO_HANDLE;
|
||||||
@@ -566,15 +614,10 @@ kuserok_user_k5login_plug_f(void *plug_ctx, krb5_context context,
|
|||||||
if (!_krb5_homedir_access(context))
|
if (!_krb5_homedir_access(context))
|
||||||
return KRB5_PLUGIN_NO_HANDLE;
|
return KRB5_PLUGIN_NO_HANDLE;
|
||||||
|
|
||||||
#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())");
|
krb5_set_error_message(context, errno, "User unknown (getpwnam_r())");
|
||||||
return KRB5_PLUGIN_NO_HANDLE;
|
return KRB5_PLUGIN_NO_HANDLE;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
pwd = getpwnam (luser);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (pwd == NULL) {
|
if (pwd == NULL) {
|
||||||
krb5_set_error_message(context, errno, "User unknown (getpwnam())");
|
krb5_set_error_message(context, errno, "User unknown (getpwnam())");
|
||||||
return KRB5_PLUGIN_NO_HANDLE;
|
return KRB5_PLUGIN_NO_HANDLE;
|
||||||
|
Reference in New Issue
Block a user