Use roken_get_*() instead of getpwuuid()

Using non-reentrant getpwuid() (or getpwnam(), or getspnam())  can be
dangerous.  We had a report of a login application / PAM that calls
those, and Heimdal, by calling them too, clobbered the cached struct
passwd used by the login app / PAM.
This commit is contained in:
Nicolas Williams
2017-10-12 12:24:05 -05:00
committed by Nico Williams
parent 95eb83c424
commit 620862049e
7 changed files with 42 additions and 145 deletions

View File

@@ -99,6 +99,7 @@ main(int argc, char **argv)
{ {
int f; int f;
char tf[1024]; char tf[1024];
char shellbuf[MAX_PATH];
char *p; char *p;
char *path; char *path;
@@ -166,13 +167,10 @@ main(int argc, char **argv)
(unsigned long)((argc + 10)*sizeof(char *))); (unsigned long)((argc + 10)*sizeof(char *)));
if(*argv == NULL) { if(*argv == NULL) {
path = getenv("SHELL"); if (roken_get_shell(shellbuf, sizeof(shellbuf)) != NULL)
if(path == NULL){ path = strdup(shellbuf);
struct passwd *pw = k_getpwuid(geteuid()); else
if (pw == NULL) path = strdup("/bin/sh");
errx(1, "no such user: %d", (int)geteuid());
path = strdup(pw->pw_shell);
}
} else { } else {
path = strdup(*argv++); path = strdup(*argv++);
} }

View File

@@ -292,6 +292,7 @@ main (int argc, char **argv)
int uid = getuid(); int uid = getuid();
OtpAlgorithm *alg = otp_find_alg (OTP_ALG_DEFAULT); OtpAlgorithm *alg = otp_find_alg (OTP_ALG_DEFAULT);
int optidx = 0; int optidx = 0;
char userbuf[128];
setprogname (argv[0]); setprogname (argv[0]);
if(getarg(args, num_args, argc, argv, &optidx)) if(getarg(args, num_args, argc, argv, &optidx))
@@ -332,12 +333,9 @@ main (int argc, char **argv)
return list_otps (argc, argv, user); return list_otps (argc, argv, user);
if (user == NULL) { if (user == NULL) {
struct passwd *pwd; user = roken_get_username(userbuf, sizeof(userbuf));
if (user == NULL)
pwd = k_getpwuid(uid);
if (pwd == NULL)
err (1, "You don't exist"); err (1, "You don't exist");
user = pwd->pw_name;
} }
/* /*

View File

@@ -524,6 +524,7 @@ KRB_CAPABILITIES
rk_DLADDR rk_DLADDR
AC_CHECK_GETPWNAM_R_POSIX AC_CHECK_GETPWNAM_R_POSIX
AC_CHECK_GETPWUID_R_POSIX
dnl detect doors on solaris dnl detect doors on solaris
if test "$enable_pthread_support" != no; then if test "$enable_pthread_support" != no; then

View File

@@ -84,7 +84,7 @@ $(OBJ)\kadmin-commands.c $(OBJ)\kadmin-commands.h: kadmin-commands.in
cd $(SRCDIR) cd $(SRCDIR)
$(SBINDIR)\kadmin.exe: $(KADMIN_OBJS) $(KADMIN_LIBS) $(SBINDIR)\kadmin.exe: $(KADMIN_OBJS) $(KADMIN_LIBS)
$(EXECONLINK) $(EXECONLINK) Secur32.lib Shell32.lib
$(EXEPREP) $(EXEPREP)
KADMIND_OBJS= \ KADMIND_OBJS= \
@@ -100,7 +100,7 @@ KADMIND_LIBS=\
$(COMMON_LIBS) $(COMMON_LIBS)
$(LIBEXECDIR)\kadmind.exe: $(KADMIND_OBJS) $(KADMIND_LIBS) $(LIBEXECDIR)\kadmind.exe: $(KADMIND_OBJS) $(KADMIND_LIBS)
$(EXECONLINK) $(EXECONLINK) Secur32.lib Shell32.lib
$(EXEPREP) $(EXEPREP)
all:: $(INCFILES) $(SBIN_PROGRAMS) $(LIBEXEC_PROGRAMS) all:: $(INCFILES) $(SBIN_PROGRAMS) $(LIBEXEC_PROGRAMS)
@@ -115,13 +115,13 @@ clean::
NOINST_PROGRAMS=$(OBJ)\add_random_users.exe NOINST_PROGRAMS=$(OBJ)\add_random_users.exe
$(OBJ)\add_random_users.exe: $(OBJ)\add_random_users.obj $(LIBKADM5SRV) $(LIBKADM5CLNT) $(COMMON_LIBS) $(OBJ)\add_random_users.exe: $(OBJ)\add_random_users.obj $(LIBKADM5SRV) $(LIBKADM5CLNT) $(COMMON_LIBS)
$(EXECONLINK) $(EXECONLINK) Secur32.lib Shell32.lib
$(EXEPREP_NODIST) $(EXEPREP_NODIST)
TEST_BINARIES=$(OBJ)\test_util.exe TEST_BINARIES=$(OBJ)\test_util.exe
$(OBJ)\test_util.exe: $(OBJ)\test_util.obj $(OBJ)\util.obj $(KADMIN_LIBS) $(OBJ)\test_util.exe: $(OBJ)\test_util.obj $(OBJ)\util.obj $(KADMIN_LIBS)
$(EXECONLINK) $(EXECONLINK) Secur32.lib Shell32.lib
$(EXEPREP_NODIST) $(EXEPREP_NODIST)
test-binaries: $(TEST_BINARIES) test-binaries: $(TEST_BINARIES)

View File

@@ -819,45 +819,25 @@ static char *
get_config_file_for_user(void) get_config_file_for_user(void)
{ {
char *fn; char *fn;
#ifndef _WIN32
char *home;
int ret; int ret;
fn = secure_getenv("SOFTPKCS11RC"); fn = secure_getenv("SOFTPKCS11RC");
if (fn) if (fn)
fn = strdup(fn); fn = strdup(fn);
home = secure_getenv("HOME");
if (fn == NULL && home == NULL) {
struct passwd *pw = getpwuid(getuid());
if(pw != NULL)
home = pw->pw_dir;
}
if (fn == NULL) { if (fn == NULL) {
char homebuf[MAX_PATH];
const char *home = roken_get_appdatadir(homebuf, sizeof(homebuf));
if (home) { if (home) {
ret = asprintf(&fn, "%s/.soft-token.rc", home); ret = asprintf(&fn, "%s/.soft-token.rc", home);
if (ret == -1) if (ret == -1)
fn = NULL; fn = NULL;
} else } else {
#ifndef WIN32
fn = strdup("/etc/soft-token.rc"); fn = strdup("/etc/soft-token.rc");
#endif
}
} }
#else /* Windows */
char appdatafolder[MAX_PATH];
fn = getenv("SOFTPKCS11RC");
/* Retrieve the roaming AppData folder for the current user. The
current user is the user account represented by the current
thread token. */
if (fn == NULL &&
SUCCEEDED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, appdatafolder))) {
asprintf(&fn, "%s\\.soft-token.rc", appdatafolder);
}
#endif /* _WIN32 */
return fn; return fn;
} }

View File

@@ -569,6 +569,7 @@ krb5_config_parse_file_multi (krb5_context context,
if (ISTILDE(fname[0]) && ISPATHSEP(fname[1])) { if (ISTILDE(fname[0]) && ISPATHSEP(fname[1])) {
#ifndef KRB5_USE_PATH_TOKENS #ifndef KRB5_USE_PATH_TOKENS
const char *home = NULL; const char *home = NULL;
char homebuf[MAX_PATH];
if (!_krb5_homedir_access(context)) { if (!_krb5_homedir_access(context)) {
context->config_include_depth--; context->config_include_depth--;
@@ -577,12 +578,7 @@ krb5_config_parse_file_multi (krb5_context context,
return EPERM; return EPERM;
} }
home = secure_getenv("HOME"); home = roken_get_appdatadir(homebuf, sizeof(homebuf));
if (home == NULL) {
struct passwd *pw = getpwuid(getuid());
if(pw != NULL)
home = pw->pw_dir;
}
if (home) { if (home) {
int aret; int aret;

View File

@@ -37,113 +37,37 @@
* Try to find out what's a reasonable default principal. * Try to find out what's a reasonable default principal.
*/ */
static const char*
get_env_user(void)
{
const char *user = getenv("USER");
if(user == NULL)
user = getenv("LOGNAME");
if(user == NULL)
user = getenv("USERNAME");
return user;
}
#ifndef _WIN32
/*
* Will only use operating-system dependant operation to get the
* default principal, for use of functions that in ccache layer to
* avoid recursive calls.
*/
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
_krb5_get_default_principal_local (krb5_context context, _krb5_get_default_principal_local (krb5_context context,
krb5_principal *princ) krb5_principal *princ)
{ {
krb5_error_code ret;
const char *user; const char *user;
uid_t uid; const char *second_component = NULL;
char userbuf[128];
*princ = NULL; *princ = NULL;
uid = getuid(); /*
if(uid == 0) { * NOTE: We depend on roken_get_username() preferentially using
user = getlogin(); * getlogin_r() first when !issuid() && getuid() == 0, otherwise we
if(user == NULL) * won't figure out to output <username>/root@DEFAULT_REALM.
user = get_env_user(); */
if(user != NULL && strcmp(user, "root") != 0) user = roken_get_username(userbuf, sizeof(userbuf));
ret = krb5_make_principal(context, princ, NULL, user, "root", NULL); if (user == NULL) {
else krb5_set_error_message(context, ENOTTY,
ret = krb5_make_principal(context, princ, NULL, "root", NULL); N_("unable to figure out current principal",
} else { ""));
struct passwd *pw = getpwuid(uid); return ENOTTY; /* XXX */
if(pw != NULL)
user = pw->pw_name;
else {
user = get_env_user();
if(user == NULL)
user = getlogin();
}
if(user == NULL) {
krb5_set_error_message(context, ENOTTY,
N_("unable to figure out current "
"principal", ""));
return ENOTTY; /* XXX */
}
ret = krb5_make_principal(context, princ, NULL, user, NULL);
} }
return ret;
#ifndef WIN32
if (!issuid() && getuid() == 0 && strcmp(user, "root") != 0)
second_component = "root"; /* We'll use <user>/root */
#endif;
return krb5_make_principal(context, princ, NULL, user,
second_component, NULL);
} }
#else /* _WIN32 */
#define SECURITY_WIN32
#include <security.h>
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
_krb5_get_default_principal_local(krb5_context context,
krb5_principal *princ)
{
/* See if we can get the principal first. We only expect this to
work if logged into a domain. */
{
char username[1024];
ULONG sz = sizeof(username);
if (GetUserNameEx(NameUserPrincipal, username, &sz)) {
return krb5_parse_name_flags(context, username,
KRB5_PRINCIPAL_PARSE_ENTERPRISE,
princ);
}
}
/* Just get the Windows username. This should pretty much always
work. */
{
char username[1024];
DWORD dsz = sizeof(username);
if (GetUserName(username, &dsz)) {
return krb5_make_principal(context, princ, NULL, username, NULL);
}
}
/* Failing that, we look at the environment */
{
const char * username = get_env_user();
if (username == NULL) {
krb5_set_error_string(context,
"unable to figure out current principal");
return ENOTTY; /* Really? */
}
return krb5_make_principal(context, princ, NULL, username, NULL);
}
}
#endif
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_get_default_principal (krb5_context context, krb5_get_default_principal (krb5_context context,
krb5_principal *princ) krb5_principal *princ)