From 21983497ff98e34e34f8a626fd0bba24831fd1b4 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Sat, 26 Jul 2014 12:46:26 +0200 Subject: UTIL: Move become_user outside krb5 tree In order for several other SSSD processes to run as a non-root user, we need to move the functions to become another user to a shared space in our source tree. --- Makefile.am | 20 ++-- src/providers/krb5/krb5_become_user.c | 199 ---------------------------------- src/providers/krb5/krb5_utils.h | 8 -- src/util/become_user.c | 198 +++++++++++++++++++++++++++++++++ src/util/util.h | 9 ++ 5 files changed, 219 insertions(+), 215 deletions(-) delete mode 100644 src/providers/krb5/krb5_become_user.c create mode 100644 src/util/become_user.c diff --git a/Makefile.am b/Makefile.am index eb0e64943..ac3f26cad 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1286,13 +1286,14 @@ strtonum_tests_LDADD = \ krb5_utils_tests_SOURCES = \ src/tests/krb5_utils-tests.c \ src/providers/krb5/krb5_utils.c \ - src/providers/krb5/krb5_become_user.c \ src/providers/krb5/krb5_common.c \ src/util/sss_krb5.c \ src/providers/data_provider_fo.c \ src/providers/data_provider_opts.c \ src/providers/data_provider_callbacks.c \ - $(SSSD_FAILOVER_OBJ) + src/util/become_user.c \ + $(SSSD_FAILOVER_OBJ) \ + $(NULL) krb5_utils_tests_CFLAGS = \ $(AM_CFLAGS) \ $(KRB5_CFLAGS) \ @@ -1567,13 +1568,14 @@ krb5_child_test_SOURCES = \ src/tests/krb5_child-test.c \ src/providers/krb5/krb5_utils.c \ src/providers/krb5/krb5_child_handler.c \ - src/providers/krb5/krb5_become_user.c \ src/providers/krb5/krb5_common.c \ src/util/sss_krb5.c \ src/providers/data_provider_fo.c \ src/providers/data_provider_opts.c \ src/providers/data_provider_callbacks.c \ - $(SSSD_FAILOVER_OBJ) + src/util/become_user.c \ + $(SSSD_FAILOVER_OBJ) \ + $(NULL) krb5_child_test_CFLAGS = \ $(AM_CFLAGS) \ -DKRB5_CHILD_DIR=\"$(builddir)\" \ @@ -2243,7 +2245,6 @@ libsss_ad_common_la_LIBADD = \ libsss_krb5_common_la_SOURCES = \ src/providers/krb5/krb5_utils.c \ - src/providers/krb5/krb5_become_user.c \ src/providers/krb5/krb5_delayed_online_authentication.c \ src/providers/krb5/krb5_renew_tgt.c \ src/providers/krb5/krb5_wait_queue.c \ @@ -2252,7 +2253,9 @@ libsss_krb5_common_la_SOURCES = \ src/providers/krb5/krb5_access.c \ src/providers/krb5/krb5_child_handler.c \ src/providers/krb5/krb5_init_shared.c \ - src/util/sss_krb5.c + src/util/sss_krb5.c \ + src/util/become_user.c \ + $(NULL) libsss_krb5_common_la_CFLAGS = \ $(KRB5_CFLAGS) libsss_krb5_common_la_LIBADD = \ @@ -2432,7 +2435,6 @@ libsss_ad_la_LDFLAGS = \ -module krb5_child_SOURCES = \ - src/providers/krb5/krb5_become_user.c \ src/providers/krb5/krb5_child.c \ src/providers/dp_pam_data_util.c \ src/util/user_info_msg.c \ @@ -2441,7 +2443,9 @@ krb5_child_SOURCES = \ src/util/authtok.c \ src/util/util.c \ src/util/signal.c \ - src/sss_client/common.c + src/util/become_user.c \ + src/sss_client/common.c \ + $(NULL) krb5_child_CFLAGS = \ $(AM_CFLAGS) \ $(POPT_CFLAGS) \ diff --git a/src/providers/krb5/krb5_become_user.c b/src/providers/krb5/krb5_become_user.c deleted file mode 100644 index 6ddb35a56..000000000 --- a/src/providers/krb5/krb5_become_user.c +++ /dev/null @@ -1,199 +0,0 @@ -/* - SSSD - - Kerberos 5 Backend Module -- Utilities - - Authors: - Sumit Bose - - Copyright (C) 2009 Red Hat - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "util/util.h" -#include "providers/krb5/krb5_utils.h" -#include - -errno_t become_user(uid_t uid, gid_t gid) -{ - uid_t cuid; - int ret; - - DEBUG(SSSDBG_FUNC_DATA, - "Trying to become user [%"SPRIuid"][%"SPRIgid"].\n", uid, gid); - - /* skip call if we already are the requested user */ - cuid = geteuid(); - if (uid == cuid) { - DEBUG(SSSDBG_FUNC_DATA, "Already user [%"SPRIuid"].\n", uid); - return EOK; - } - - /* drop supplmentary groups first */ - ret = setgroups(0, NULL); - if (ret == -1) { - ret = errno; - DEBUG(SSSDBG_CRIT_FAILURE, - "setgroups failed [%d][%s].\n", ret, strerror(ret)); - return ret; - } - - /* change gid so that root cannot be regained (changes saved gid too) */ - ret = setresgid(gid, gid, gid); - if (ret == -1) { - ret = errno; - DEBUG(SSSDBG_CRIT_FAILURE, - "setresgid failed [%d][%s].\n", ret, strerror(ret)); - return ret; - } - - /* change uid so that root cannot be regained (changes saved uid too) */ - /* this call also takes care of dropping CAP_SETUID, so this is a PNR */ - ret = setresuid(uid, uid, uid); - if (ret == -1) { - ret = errno; - DEBUG(SSSDBG_CRIT_FAILURE, - "setresuid failed [%d][%s].\n", ret, strerror(ret)); - return ret; - } - - 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 4b1ebb0bb..f54a07f79 100644 --- a/src/providers/krb5/krb5_utils.h +++ b/src/providers/krb5/krb5_utils.h @@ -49,14 +49,6 @@ char *expand_ccname_template(TALLOC_CTX *mem_ctx, struct krb5child_req *kr, const char *template, bool file_mode, bool case_sensitive); -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 sss_krb5_precreate_ccache(const char *ccname, pcre *illegal_re, uid_t uid, gid_t gid); errno_t sss_krb5_cc_destroy(const char *ccname, uid_t uid, gid_t gid); diff --git a/src/util/become_user.c b/src/util/become_user.c new file mode 100644 index 000000000..b5f94f993 --- /dev/null +++ b/src/util/become_user.c @@ -0,0 +1,198 @@ +/* + SSSD + + Kerberos 5 Backend Module -- Utilities + + Authors: + Sumit Bose + + Copyright (C) 2009 Red Hat + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "util/util.h" +#include + +errno_t become_user(uid_t uid, gid_t gid) +{ + uid_t cuid; + int ret; + + DEBUG(SSSDBG_FUNC_DATA, + "Trying to become user [%"SPRIuid"][%"SPRIgid"].\n", uid, gid); + + /* skip call if we already are the requested user */ + cuid = geteuid(); + if (uid == cuid) { + DEBUG(SSSDBG_FUNC_DATA, "Already user [%"SPRIuid"].\n", uid); + return EOK; + } + + /* drop supplmentary groups first */ + ret = setgroups(0, NULL); + if (ret == -1) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, + "setgroups failed [%d][%s].\n", ret, strerror(ret)); + return ret; + } + + /* change gid so that root cannot be regained (changes saved gid too) */ + ret = setresgid(gid, gid, gid); + if (ret == -1) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, + "setresgid failed [%d][%s].\n", ret, strerror(ret)); + return ret; + } + + /* change uid so that root cannot be regained (changes saved uid too) */ + /* this call also takes care of dropping CAP_SETUID, so this is a PNR */ + ret = setresuid(uid, uid, uid); + if (ret == -1) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, + "setresuid failed [%d][%s].\n", ret, strerror(ret)); + return ret; + } + + 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/util/util.h b/src/util/util.h index df82b3fa4..24db52d23 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -578,4 +578,13 @@ char * sss_reverse_replace_space(TALLOC_CTX *mem_ctx, const char *orig_name, const char replace_char); +/* from become_user.c */ +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); + #endif /* __SSSD_UTIL_H__ */ -- cgit