c042f71c80
- replace older proposed changes for ksu with backports of the changes after review and merging upstream (#1015559, #1026099, #1118347)
418 lines
15 KiB
Diff
418 lines
15 KiB
Diff
From dccc80a469b1925fcfe7697406a69912efe4baa1 Mon Sep 17 00:00:00 2001
|
|
From: Nalin Dahyabhai <nalin@dahyabhai.net>
|
|
Date: Wed, 30 Oct 2013 21:45:35 -0400
|
|
Subject: [PATCH 3/7] Use an intermediate memory cache in ksu
|
|
|
|
Instead of copying source or obtained creds into the target cache and
|
|
changing ownership if everything succeeds, copy them into a MEMORY:
|
|
cache and then, if everything succeeds, create the target cache as the
|
|
target user.
|
|
|
|
We no longer need to clean up the temporary ccache when exiting in
|
|
most error cases.
|
|
|
|
Use a fake principal name ("_ksu/_ksu@_ksu") as the primary holder of
|
|
the temporary cache so that we won't accidentally select it when we
|
|
make a subsequent call to krb5_cc_cache_match() (to be added in a
|
|
later patch) to find the target location where the creds should be
|
|
stored for use while running as the target user.
|
|
---
|
|
src/clients/ksu/ccache.c | 10 +--
|
|
src/clients/ksu/ksu.h | 4 +-
|
|
src/clients/ksu/main.c | 156 ++++++++++++++++++++++++-----------------------
|
|
3 files changed, 87 insertions(+), 83 deletions(-)
|
|
|
|
diff --git a/src/clients/ksu/ccache.c b/src/clients/ksu/ccache.c
|
|
index 5f57279..d0fc389 100644
|
|
--- a/src/clients/ksu/ccache.c
|
|
+++ b/src/clients/ksu/ccache.c
|
|
@@ -47,14 +47,15 @@ void show_credential();
|
|
*/
|
|
|
|
krb5_error_code krb5_ccache_copy (context, cc_def, cc_other_tag,
|
|
- primary_principal, restrict_creds, cc_out,
|
|
- stored, target_uid)
|
|
+ primary_principal, restrict_creds,
|
|
+ target_principal, cc_out, stored, target_uid)
|
|
/* IN */
|
|
krb5_context context;
|
|
krb5_ccache cc_def;
|
|
char *cc_other_tag;
|
|
krb5_principal primary_principal;
|
|
krb5_boolean restrict_creds;
|
|
+ krb5_principal target_principal;
|
|
uid_t target_uid;
|
|
/* OUT */
|
|
krb5_ccache *cc_out;
|
|
@@ -86,10 +87,9 @@ krb5_error_code krb5_ccache_copy (context, cc_def, cc_other_tag,
|
|
return errno;
|
|
}
|
|
|
|
-
|
|
- if ((retval = krb5_cc_initialize(context, *cc_other, primary_principal))){
|
|
+ retval = krb5_cc_initialize(context, *cc_other, target_principal);
|
|
+ if (retval)
|
|
return retval;
|
|
- }
|
|
|
|
if (restrict_creds) {
|
|
retval = krb5_store_some_creds(context, *cc_other, cc_def_creds_arr,
|
|
diff --git a/src/clients/ksu/ksu.h b/src/clients/ksu/ksu.h
|
|
index e1e34f1..08bf01b 100644
|
|
--- a/src/clients/ksu/ksu.h
|
|
+++ b/src/clients/ksu/ksu.h
|
|
@@ -106,8 +106,8 @@ extern krb5_error_code get_best_principal
|
|
|
|
/* ccache.c */
|
|
extern krb5_error_code krb5_ccache_copy
|
|
-(krb5_context, krb5_ccache, char *, krb5_principal,
|
|
- krb5_boolean, krb5_ccache *, krb5_boolean *, uid_t);
|
|
+(krb5_context, krb5_ccache, char *, krb5_principal, krb5_boolean,
|
|
+ krb5_principal, krb5_ccache *, krb5_boolean *, uid_t);
|
|
|
|
extern krb5_error_code krb5_store_all_creds
|
|
(krb5_context, krb5_ccache, krb5_creds **, krb5_creds **);
|
|
diff --git a/src/clients/ksu/main.c b/src/clients/ksu/main.c
|
|
index 8c49f94..d1bb8ca 100644
|
|
--- a/src/clients/ksu/main.c
|
|
+++ b/src/clients/ksu/main.c
|
|
@@ -42,10 +42,13 @@ char * gb_err = NULL;
|
|
int quiet = 0;
|
|
/***********/
|
|
|
|
+#define KS_TEMPORARY_CACHE "MEMORY:_ksu"
|
|
+#define KS_TEMPORARY_PRINC "_ksu/_ksu@_ksu"
|
|
#define _DEF_CSH "/bin/csh"
|
|
static int set_env_var (char *, char *);
|
|
static void sweep_up (krb5_context, krb5_ccache);
|
|
static char * ontty (void);
|
|
+static krb5_error_code set_ccname_env(krb5_context, krb5_ccache);
|
|
static void print_status( const char *fmt, ...)
|
|
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)
|
|
__attribute__ ((__format__ (__printf__, 1, 2)))
|
|
@@ -84,8 +87,8 @@ main (argc, argv)
|
|
int option=0;
|
|
int statusp=0;
|
|
krb5_error_code retval = 0;
|
|
- krb5_principal client = NULL;
|
|
- krb5_ccache cc_target = NULL;
|
|
+ krb5_principal client = NULL, tmp_princ = NULL;
|
|
+ krb5_ccache cc_tmp = NULL, cc_target = NULL;
|
|
krb5_context ksu_context;
|
|
char * cc_target_tag = NULL;
|
|
char * target_user = NULL;
|
|
@@ -93,7 +96,6 @@ main (argc, argv)
|
|
|
|
krb5_ccache cc_source = NULL;
|
|
const char * cc_source_tag = NULL;
|
|
- uid_t source_gid;
|
|
const char * cc_source_tag_tmp = NULL;
|
|
char * cmd = NULL, * exec_cmd = NULL;
|
|
int errflg = 0;
|
|
@@ -342,8 +344,6 @@ main (argc, argv)
|
|
/* allocate space and copy the usernamane there */
|
|
source_user = xstrdup(pwd->pw_name);
|
|
source_uid = pwd->pw_uid;
|
|
- source_gid = pwd->pw_gid;
|
|
-
|
|
|
|
if (!strcmp(SOURCE_USER_LOGIN, target_user)){
|
|
target_user = xstrdup (source_user);
|
|
@@ -435,25 +435,32 @@ main (argc, argv)
|
|
}
|
|
|
|
/*
|
|
- Only when proper authentication and authorization
|
|
- takes place, the target user becomes the owner of the cache.
|
|
- */
|
|
-
|
|
- /* we continue to run as source uid until
|
|
- the middle of the copy, when becomewe become the target user
|
|
- The cache is owned by the target user.*/
|
|
+ * After proper authentication and authorization, populate a cache for the
|
|
+ * target user.
|
|
+ */
|
|
|
|
+ /*
|
|
+ * We read the set of creds we want to copy from the source ccache as the
|
|
+ * source uid, become root for authentication, and then become the target
|
|
+ * user to handle authorization and creating the target user's cache.
|
|
+ */
|
|
|
|
/* if root ksu's to a regular user, then
|
|
then only the credentials for that particular user
|
|
should be copied */
|
|
|
|
restrict_creds = (source_uid == 0) && (target_uid != 0);
|
|
- retval = krb5_ccache_copy(ksu_context, cc_source, cc_target_tag, client,
|
|
- restrict_creds, &cc_target, &stored, target_uid);
|
|
+ retval = krb5_parse_name(ksu_context, KS_TEMPORARY_PRINC, &tmp_princ);
|
|
+ if (retval) {
|
|
+ com_err(prog_name, retval, _("while parsing temporary name"));
|
|
+ exit(1);
|
|
+ }
|
|
+ retval = krb5_ccache_copy(ksu_context, cc_source, KS_TEMPORARY_CACHE,
|
|
+ client, restrict_creds, tmp_princ, &cc_tmp,
|
|
+ &stored, 0);
|
|
if (retval) {
|
|
com_err(prog_name, retval, _("while copying cache %s to %s"),
|
|
- krb5_cc_get_name(ksu_context, cc_source), cc_target_tag);
|
|
+ krb5_cc_get_name(ksu_context, cc_source), KS_TEMPORARY_CACHE);
|
|
exit(1);
|
|
}
|
|
|
|
@@ -473,7 +480,6 @@ main (argc, argv)
|
|
&kdc_server))){
|
|
com_err(prog_name, retval,
|
|
_("while creating tgt for local realm"));
|
|
- sweep_up(ksu_context, cc_target);
|
|
exit(1);
|
|
}
|
|
|
|
@@ -481,13 +487,12 @@ main (argc, argv)
|
|
"enter it here and are logged\n"));
|
|
fprintf(stderr, _(" in remotely using an unsecure "
|
|
"(non-encrypted) channel.\n"));
|
|
- if (krb5_get_tkt_via_passwd (ksu_context, &cc_target, client,
|
|
- kdc_server, &options,
|
|
- &zero_password) == FALSE){
|
|
+ if (krb5_get_tkt_via_passwd(ksu_context, &cc_tmp, client,
|
|
+ kdc_server, &options,
|
|
+ &zero_password) == FALSE){
|
|
|
|
if (zero_password == FALSE){
|
|
fprintf(stderr, _("Goodbye\n"));
|
|
- sweep_up(ksu_context, cc_target);
|
|
exit(1);
|
|
}
|
|
|
|
@@ -506,48 +511,20 @@ main (argc, argv)
|
|
if (source_uid && (source_uid != target_uid)) {
|
|
char * client_name;
|
|
|
|
- auth_val = krb5_auth_check(ksu_context, client, localhostname, &options,
|
|
- target_user,cc_target, &path_passwd, target_uid);
|
|
+ auth_val = krb5_auth_check(ksu_context, client, localhostname,
|
|
+ &options, target_user, cc_tmp,
|
|
+ &path_passwd, target_uid);
|
|
|
|
/* if Kerberos authentication failed then exit */
|
|
if (auth_val ==FALSE){
|
|
fprintf(stderr, _("Authentication failed.\n"));
|
|
syslog(LOG_WARNING, "'%s %s' authentication failed for %s%s",
|
|
prog_name,target_user,source_user,ontty());
|
|
- sweep_up(ksu_context, cc_target);
|
|
exit(1);
|
|
}
|
|
|
|
-#if 0
|
|
- /* At best, this avoids a single kdc request
|
|
- It is hard to implement dealing with file permissions and
|
|
- is unnecessary. It is important
|
|
- to properly handle races in chown if this code is ever re-enabled.
|
|
- */
|
|
- /* cache the tickets if possible in the source cache */
|
|
- if (!path_passwd){
|
|
-
|
|
- if ((retval = krb5_ccache_overwrite(ksu_context, cc_target, cc_source,
|
|
- client))){
|
|
- com_err (prog_name, retval,
|
|
- "while copying cache %s to %s",
|
|
- krb5_cc_get_name(ksu_context, cc_target),
|
|
- krb5_cc_get_name(ksu_context, cc_source));
|
|
- sweep_up(ksu_context, cc_target);
|
|
- exit(1);
|
|
- }
|
|
- if (chown(cc_source_tag_tmp, source_uid, source_gid)){
|
|
- com_err(prog_name, errno,
|
|
- "while changing owner for %s",
|
|
- cc_source_tag_tmp);
|
|
- exit(1);
|
|
- }
|
|
- }
|
|
-#endif /*0*/
|
|
-
|
|
if ((retval = krb5_unparse_name(ksu_context, client, &client_name))) {
|
|
com_err(prog_name, retval, _("When unparsing name"));
|
|
- sweep_up(ksu_context, cc_target);
|
|
exit(1);
|
|
}
|
|
|
|
@@ -560,7 +537,6 @@ main (argc, argv)
|
|
if (krb5_seteuid(target_uid)) {
|
|
com_err(prog_name, errno, _("while switching to target for "
|
|
"authorization check"));
|
|
- sweep_up(ksu_context, cc_target);
|
|
exit(1);
|
|
}
|
|
|
|
@@ -568,14 +544,12 @@ main (argc, argv)
|
|
cmd, &authorization_val, &exec_cmd))){
|
|
com_err(prog_name,retval, _("while checking authorization"));
|
|
krb5_seteuid(0); /*So we have some chance of sweeping up*/
|
|
- sweep_up(ksu_context, cc_target);
|
|
exit(1);
|
|
}
|
|
|
|
if (krb5_seteuid(0)) {
|
|
com_err(prog_name, errno, _("while switching back from target "
|
|
"after authorization check"));
|
|
- sweep_up(ksu_context, cc_target);
|
|
exit(1);
|
|
}
|
|
if (authorization_val == TRUE){
|
|
@@ -617,25 +591,25 @@ main (argc, argv)
|
|
|
|
}
|
|
|
|
- sweep_up(ksu_context, cc_target);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
if( some_rest_copy){
|
|
- if ((retval = krb5_ccache_filter(ksu_context, cc_target, client))){
|
|
+ retval = krb5_ccache_filter(ksu_context, cc_tmp, client);
|
|
+ if (retval) {
|
|
com_err(prog_name,retval, _("while calling cc_filter"));
|
|
- sweep_up(ksu_context, cc_target);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
if (all_rest_copy){
|
|
- if ((retval = krb5_cc_initialize(ksu_context, cc_target, client))){
|
|
+ retval = krb5_cc_initialize(ksu_context, cc_tmp, tmp_princ);
|
|
+ if (retval) {
|
|
com_err(prog_name, retval, _("while erasing target cache"));
|
|
exit(1);
|
|
}
|
|
-
|
|
+ stored = FALSE;
|
|
}
|
|
|
|
/* get the shell of the user, this will be the shell used by su */
|
|
@@ -653,7 +627,6 @@ main (argc, argv)
|
|
|
|
if (!standard_shell(target_pwd->pw_shell) && source_uid) {
|
|
fprintf(stderr, _("ksu: permission denied (shell).\n"));
|
|
- sweep_up(ksu_context, cc_target);
|
|
exit(1);
|
|
}
|
|
#endif /* HAVE_GETUSERSHELL */
|
|
@@ -663,43 +636,28 @@ main (argc, argv)
|
|
if(set_env_var("USER", target_pwd->pw_name)){
|
|
fprintf(stderr,
|
|
_("ksu: couldn't set environment variable USER\n"));
|
|
- sweep_up(ksu_context, cc_target);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
if(set_env_var( "HOME", target_pwd->pw_dir)){
|
|
fprintf(stderr, _("ksu: couldn't set environment variable HOME\n"));
|
|
- sweep_up(ksu_context, cc_target);
|
|
exit(1);
|
|
}
|
|
|
|
if(set_env_var( "SHELL", shell)){
|
|
fprintf(stderr, _("ksu: couldn't set environment variable SHELL\n"));
|
|
- sweep_up(ksu_context, cc_target);
|
|
- exit(1);
|
|
- }
|
|
-
|
|
- /* set the cc env name to target */
|
|
-
|
|
- if(set_env_var( KRB5_ENV_CCNAME, cc_target_tag)){
|
|
- fprintf(stderr, _("ksu: couldn't set environment variable %s\n"),
|
|
- KRB5_ENV_CCNAME);
|
|
- sweep_up(ksu_context, cc_target);
|
|
exit(1);
|
|
}
|
|
|
|
/* set permissions */
|
|
if (setgid(target_pwd->pw_gid) < 0) {
|
|
perror("ksu: setgid");
|
|
- sweep_up(ksu_context, cc_target);
|
|
exit(1);
|
|
}
|
|
|
|
-
|
|
if (initgroups(target_user, target_pwd->pw_gid)) {
|
|
fprintf(stderr, _("ksu: initgroups failed.\n"));
|
|
- sweep_up(ksu_context, cc_target);
|
|
exit(1);
|
|
}
|
|
|
|
@@ -719,13 +677,36 @@ main (argc, argv)
|
|
*/
|
|
if (setluid((uid_t) pwd->pw_uid) < 0) {
|
|
perror("setluid");
|
|
- sweep_up(ksu_context, cc_target);
|
|
exit(1);
|
|
}
|
|
#endif /* HAVE_SETLUID */
|
|
|
|
if (setuid(target_pwd->pw_uid) < 0) {
|
|
perror("ksu: setuid");
|
|
+ exit(1);
|
|
+ }
|
|
+
|
|
+ retval = krb5_ccache_copy(ksu_context, cc_tmp, cc_target_tag,
|
|
+ client, FALSE, client, &cc_target, &stored,
|
|
+ target_pwd->pw_uid);
|
|
+ if (retval) {
|
|
+ com_err(prog_name, retval, _("while copying cache %s to %s"),
|
|
+ KS_TEMPORARY_CACHE, cc_target_tag);
|
|
+ exit(1);
|
|
+ }
|
|
+
|
|
+ if (stored && !ks_ccache_is_initialized(ksu_context, cc_target)) {
|
|
+ com_err(prog_name, errno,
|
|
+ _("%s does not have correct permissions for %s, %s aborted"),
|
|
+ target_user, cc_target_tag, prog_name);
|
|
+ exit(1);
|
|
+ }
|
|
+
|
|
+ free(cc_target_tag);
|
|
+
|
|
+ /* Set the cc env name to target. */
|
|
+ retval = set_ccname_env(ksu_context, cc_target);
|
|
+ if (retval != 0) {
|
|
sweep_up(ksu_context, cc_target);
|
|
exit(1);
|
|
}
|
|
@@ -799,6 +780,29 @@ main (argc, argv)
|
|
}
|
|
}
|
|
|
|
+/* Set KRB5CCNAME in the environment to point to ccache. Print an error
|
|
+ * message on failure. */
|
|
+static krb5_error_code
|
|
+set_ccname_env(krb5_context ksu_context, krb5_ccache ccache)
|
|
+{
|
|
+ krb5_error_code retval;
|
|
+ char *ccname;
|
|
+
|
|
+ retval = krb5_cc_get_full_name(ksu_context, ccache, &ccname);
|
|
+ if (retval) {
|
|
+ com_err(prog_name, retval, _("while reading cache name from ccache"));
|
|
+ return retval;
|
|
+ }
|
|
+ if (set_env_var(KRB5_ENV_CCNAME, ccname)) {
|
|
+ retval = errno;
|
|
+ fprintf(stderr,
|
|
+ _("ksu: couldn't set environment variable %s\n"),
|
|
+ KRB5_ENV_CCNAME);
|
|
+ }
|
|
+ krb5_free_string(ksu_context, ccname);
|
|
+ return retval;
|
|
+}
|
|
+
|
|
#ifdef HAVE_GETUSERSHELL
|
|
|
|
int standard_shell(sh)
|
|
--
|
|
2.0.4
|
|
|