diff --git a/src/Makefile.am b/src/Makefile.am index 61526e8..9b54f2a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -31,6 +31,8 @@ libpam_krb5_la_SOURCES = \ items.c \ items.h \ minikafs.h \ + perms.c \ + perms.h \ prompter.c \ prompter.h \ shmem.c \ @@ -106,6 +108,7 @@ harness_LDADD = \ map.lo \ initopts.lo \ options.lo \ + perms.lo \ userinfo.lo \ sly.lo \ v4.lo \ @@ -119,6 +122,7 @@ harness_newpag_LDADD = \ pam_newpag.lo \ logstdio.lo \ options.lo \ + perms.lo \ v4.lo \ v5.lo harness_newpag_LDADD += libpam_krb5.la @PAM_LIBS@ @KRB5_LIBS@ @KRB4_LIBS@ diff --git a/src/perms.c b/src/perms.c new file mode 100644 index 0000000..d999846 --- /dev/null +++ b/src/perms.c @@ -0,0 +1,89 @@ +/* + * Copyright 2008 Red Hat, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of the + * GNU Lesser General Public License, in which case the provisions of the + * LGPL are required INSTEAD OF the above restrictions. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "../config.h" + +#include +#include +#include +#include "perms.h" + +struct _pam_krb5_perms { + uid_t ruid, euid; + gid_t rgid, egid; +}; + +struct _pam_krb5_perms * +_pam_krb5_switch_perms(void) +{ + struct _pam_krb5_perms *ret; + ret = malloc(sizeof(*ret)); + if (ret != NULL) { + ret->ruid = getuid(); + ret->euid = geteuid(); + ret->rgid = getgid(); + ret->egid = getegid(); + if (ret->ruid == ret->euid) { + ret->ruid = -1; + ret->euid = -1; + } + if (ret->rgid == ret->egid) { + ret->rgid = -1; + ret->egid = -1; + } + if (setregid(ret->egid, ret->rgid) == -1) { + free(ret); + ret = NULL; + } else { + if (setreuid(ret->euid, ret->ruid) == -1) { + setregid(ret->rgid, ret->egid); + free(ret); + ret = NULL; + } + } + } + return ret; +} + +int +_pam_krb5_restore_perms(struct _pam_krb5_perms *saved) +{ + int ret = -1; + if (saved != NULL) { + if ((setreuid(saved->ruid, saved->euid) == 0) && + (setregid(saved->rgid, saved->egid) == 0)) { + ret = 0; + } + free(saved); + } + return ret; +} diff --git a/src/perms.h b/src/perms.h new file mode 100644 index 0000000..7aedb61 --- /dev/null +++ b/src/perms.h @@ -0,0 +1,40 @@ +/* + * Copyright 2008 Red Hat, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of the + * GNU Lesser General Public License, in which case the provisions of the + * LGPL are required INSTEAD OF the above restrictions. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef pam_krb5_perms_h +#define pam_krb5_perms_h + +struct _pam_krb5_perms; +struct _pam_krb5_perms *_pam_krb5_switch_perms(void); +int _pam_krb5_restore_perms(struct _pam_krb5_perms *saved); + +#endif diff --git a/src/v5.c b/src/v5.c index 87bf3b6..24ffbc6 100644 --- a/src/v5.c +++ b/src/v5.c @@ -66,6 +66,7 @@ #include "conv.h" #include "log.h" +#include "perms.h" #include "prompter.h" #include "stash.h" #include "userinfo.h" @@ -833,6 +834,7 @@ v5_get_creds(krb5_context ctx, const char *realm; struct pam_message message; struct _pam_krb5_prompter_data prompter_data; + struct _pam_krb5_perms *saved_perms; krb5_principal service_principal; krb5_creds tmpcreds; krb5_ccache ccache; @@ -884,20 +886,46 @@ v5_get_creds(krb5_context ctx, "from %s", krb5_cc_default_name(ctx)); } memset(&ccache, 0, sizeof(ccache)); - if (krb5_cc_default(ctx, &ccache) == 0) { + /* In case we're setuid/setgid, switch to the caller's + * permissions. */ + saved_perms = _pam_krb5_switch_perms(); + if ((saved_perms != NULL) && + (krb5_cc_default(ctx, &ccache) == 0)) { tmpcreds.client = userinfo->principal_name; tmpcreds.server = service_principal; i = krb5_cc_retrieve_cred(ctx, ccache, 0, &tmpcreds, creds); /* FIXME: check if the creds are expired? * What's the right error code if we check, and * they are? */ memset(&tmpcreds, 0, sizeof(tmpcreds)); krb5_cc_close(ctx, ccache); + /* In case we're setuid/setgid, restore the + * previous permissions. */ + if (saved_perms != NULL) { + if (_pam_krb5_restore_perms(saved_perms) != 0) { + krb5_free_cred_contents(ctx, creds); + memset(creds, 0, sizeof(*creds)); + krb5_free_principal(ctx, service_principal); + return PAM_SYSTEM_ERR; + } + saved_perms = NULL; + } } else { warn("error opening default ccache"); i = KRB5_CC_NOTFOUND; } + /* In case we're setuid/setgid, switch back to the + * previous permissions if we didn't already. */ + if (saved_perms != NULL) { + if (_pam_krb5_restore_perms(saved_perms) != 0) { + krb5_free_cred_contents(ctx, creds); + memset(creds, 0, sizeof(*creds)); + krb5_free_principal(ctx, service_principal); + return PAM_SYSTEM_ERR; + } + saved_perms = NULL; + } krb5_free_principal(ctx, service_principal); } else { warn("error parsing TGT principal name (%s) "