169 lines
5.6 KiB
Diff
169 lines
5.6 KiB
Diff
|
From 0371fbcf60d4dd8e25b9bb0a83029c812b66f3d6 Mon Sep 17 00:00:00 2001
|
||
|
From: Simo Sorce <simo@redhat.com>
|
||
|
Date: Wed, 28 Aug 2013 21:19:32 -0400
|
||
|
Subject: [PATCH 01/14] krb5: Add calls to change and restore credentials
|
||
|
|
||
|
In some cases we want to temporarily assume user credentials but allow the
|
||
|
process to regain back the original credentials (normally regaining uid 0).
|
||
|
|
||
|
Related:
|
||
|
https://fedorahosted.org/sssd/ticket/2061
|
||
|
---
|
||
|
src/providers/krb5/krb5_become_user.c | 125 ++++++++++++++++++++++++++++++++++
|
||
|
src/providers/krb5/krb5_utils.h | 6 ++
|
||
|
2 files changed, 131 insertions(+)
|
||
|
|
||
|
diff --git a/src/providers/krb5/krb5_become_user.c b/src/providers/krb5/krb5_become_user.c
|
||
|
index 70bc5630ece21505b58bd1a8795d7ab4b7864460..567cf237569f70a6b0fd500327438f2dbb08d24d 100644
|
||
|
--- a/src/providers/krb5/krb5_become_user.c
|
||
|
+++ b/src/providers/krb5/krb5_become_user.c
|
||
|
@@ -70,3 +70,128 @@ errno_t become_user(uid_t uid, gid_t gid)
|
||
|
return EOK;
|
||
|
}
|
||
|
|
||
|
+struct sss_creds {
|
||
|
+ uid_t uid;
|
||
|
+ gid_t gid;
|
||
|
+ int num_gids;
|
||
|
+ gid_t gids[];
|
||
|
+};
|
||
|
+
|
||
|
+errno_t restore_creds(struct sss_creds *saved_creds);
|
||
|
+
|
||
|
+/* This is a reversible version of become_user, and returns the saved
|
||
|
+ * credentials so that creds can be switched back calling restore_creds */
|
||
|
+errno_t switch_creds(TALLOC_CTX *mem_ctx,
|
||
|
+ uid_t uid, gid_t gid,
|
||
|
+ int num_gids, gid_t *gids,
|
||
|
+ struct sss_creds **saved_creds)
|
||
|
+{
|
||
|
+ struct sss_creds *ssc = NULL;
|
||
|
+ int size;
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ DEBUG(SSSDBG_FUNC_DATA, ("Switch user to [%d][%d].\n", uid, gid));
|
||
|
+
|
||
|
+ if (saved_creds) {
|
||
|
+ /* save current user credentials */
|
||
|
+ size = getgroups(0, NULL);
|
||
|
+ if (size == -1) {
|
||
|
+ ret = errno;
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Getgroups failed! (%d, %s)\n",
|
||
|
+ ret, strerror(ret)));
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ ssc = talloc_size(mem_ctx,
|
||
|
+ (sizeof(struct sss_creds) + size * sizeof(gid_t)));
|
||
|
+ if (!ssc) {
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Allocation failed!\n"));
|
||
|
+ ret = ENOMEM;
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+ ssc->num_gids = size;
|
||
|
+
|
||
|
+ size = getgroups(ssc->num_gids, ssc->gids);
|
||
|
+ if (size == -1) {
|
||
|
+ ret = errno;
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Getgroups failed! (%d, %s)\n",
|
||
|
+ ret, strerror(ret)));
|
||
|
+ /* free ssc immediately otherwise the code will try to restore
|
||
|
+ * wrong creds */
|
||
|
+ talloc_zfree(ssc);
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* we care only about effective ids */
|
||
|
+ ssc->uid = geteuid();
|
||
|
+ ssc->gid = getegid();
|
||
|
+ }
|
||
|
+
|
||
|
+ /* if we are regaining root set euid first so that we have CAP_SETUID back,
|
||
|
+ * ane the other calls work too, otherwise call it last so that we can
|
||
|
+ * change groups before we loose CAP_SETUID */
|
||
|
+ if (uid == 0) {
|
||
|
+ ret = setresuid(0, 0, 0);
|
||
|
+ if (ret == -1) {
|
||
|
+ ret = errno;
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE,
|
||
|
+ ("setresuid failed [%d][%s].\n", ret, strerror(ret)));
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ /* TODO: use prctl to get/set capabilities too ? */
|
||
|
+
|
||
|
+ /* try to setgroups first should always work if CAP_SETUID is set,
|
||
|
+ * otherwise it will always fail, failure is not critical though as
|
||
|
+ * generally we only really care about uid and at mot primary gid */
|
||
|
+ ret = setgroups(num_gids, gids);
|
||
|
+ if (ret == -1) {
|
||
|
+ ret = errno;
|
||
|
+ DEBUG(SSSDBG_TRACE_FUNC,
|
||
|
+ ("setgroups failed [%d][%s].\n", ret, strerror(ret)));
|
||
|
+ }
|
||
|
+
|
||
|
+ /* change gid now, (leaves saved gid to current, so we can restore) */
|
||
|
+ ret = setresgid(-1, gid, -1);
|
||
|
+ if (ret == -1) {
|
||
|
+ ret = errno;
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE,
|
||
|
+ ("setresgid failed [%d][%s].\n", ret, strerror(ret)));
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (uid != 0) {
|
||
|
+ /* change uid, (leaves saved uid to current, so we can restore) */
|
||
|
+ ret = setresuid(-1, uid, -1);
|
||
|
+ if (ret == -1) {
|
||
|
+ ret = errno;
|
||
|
+ DEBUG(SSSDBG_CRIT_FAILURE,
|
||
|
+ ("setresuid failed [%d][%s].\n", ret, strerror(ret)));
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = 0;
|
||
|
+
|
||
|
+done:
|
||
|
+ if (ret) {
|
||
|
+ if (ssc) {
|
||
|
+ /* attempt to restore creds first */
|
||
|
+ restore_creds(ssc);
|
||
|
+ talloc_free(ssc);
|
||
|
+ }
|
||
|
+ } else if (saved_creds) {
|
||
|
+ *saved_creds = ssc;
|
||
|
+ }
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+errno_t restore_creds(struct sss_creds *saved_creds)
|
||
|
+{
|
||
|
+ return switch_creds(saved_creds,
|
||
|
+ saved_creds->uid,
|
||
|
+ saved_creds->gid,
|
||
|
+ saved_creds->num_gids,
|
||
|
+ saved_creds->gids, NULL);
|
||
|
+}
|
||
|
diff --git a/src/providers/krb5/krb5_utils.h b/src/providers/krb5/krb5_utils.h
|
||
|
index cdc9f23641905cff300077f708087e98ba683e0d..aac3ec72ec7e1664ae96cc4e53d368e22448f5f1 100644
|
||
|
--- a/src/providers/krb5/krb5_utils.h
|
||
|
+++ b/src/providers/krb5/krb5_utils.h
|
||
|
@@ -80,6 +80,12 @@ char *expand_ccname_template(TALLOC_CTX *mem_ctx, struct krb5child_req *kr,
|
||
|
bool case_sensitive, bool *private_path);
|
||
|
|
||
|
errno_t become_user(uid_t uid, gid_t gid);
|
||
|
+struct sss_creds;
|
||
|
+errno_t switch_creds(TALLOC_CTX *mem_ctx,
|
||
|
+ uid_t uid, gid_t gid,
|
||
|
+ int num_gids, gid_t *gids,
|
||
|
+ struct sss_creds **saved_creds);
|
||
|
+errno_t restore_creds(struct sss_creds *saved_creds);
|
||
|
|
||
|
errno_t get_ccache_file_data(const char *ccache_file, const char *client_name,
|
||
|
struct tgt_times *tgtt);
|
||
|
--
|
||
|
1.8.3.1
|
||
|
|