split user and dir, use rk_getpwnam_r

This commit is contained in:
Love Hornquist Astrand
2011-12-12 21:53:41 -08:00
parent 167084b3e7
commit d453899462

View File

@@ -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;