/* Written by Ricky Zhou * Fredrik Thulin implemented pam_modutil_drop_priv * * Copyright (c) 2011-2012 Yubico AB * Copyright (c) 2011 Ricky Zhou * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * 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. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "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 COPYRIGHT * OWNER OR CONTRIBUTORS 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 #include #include #include #include #include #include "drop_privs.h" #include "util.h" #ifdef HAVE_SECURITY_PAM_APPL_H #include #endif #ifdef HAVE_SECURITY_PAM_MODULES_H #include #endif #ifdef HAVE_PAM_MODUTIL_DROP_PRIV #ifdef HAVE_SECURITY_PAM_MODUTIL_H #include #endif /* HAVE_SECURITY_PAM_MODUTIL_H */ #else static uid_t saved_euid; static gid_t saved_egid; static gid_t *saved_groups = NULL; static int saved_groups_length; #endif /* HAVE_PAM_MODUTIL_DROP_PRIV */ #ifdef HAVE_PAM_MODUTIL_DROP_PRIV static struct pam_modutil_privs * _privs_location(int force_init) { static int init = 0; static struct pam_modutil_privs privs; if (init == 0 || force_init) { PAM_MODUTIL_DEF_PRIVS(def_privs); if(privs.grplist) { free(privs.grplist); } privs = def_privs; /* since we want to save the information longer than the lifetime of dev_privs * we need to allocate space for the grplist.. */ privs.grplist = malloc(def_privs.number_of_groups * sizeof(gid_t)); init = 1; } return &privs; } #endif /* HAVE_PAM_MODUTIL_DROP_PRIV */ int drop_privileges(struct passwd *pw, pam_handle_t *pamh) { #ifdef HAVE_PAM_MODUTIL_DROP_PRIV int res; res = pam_modutil_drop_priv(pamh, _privs_location(0), pw); if (res) D (("pam_modutil_drop_priv: %i", res)); return res; #else saved_euid = geteuid(); saved_egid = getegid(); if ((saved_euid == pw->pw_uid) && (saved_egid == pw->pw_gid)) { D (("Privilges already dropped, pretend it is all right")); return 0; } saved_groups_length = getgroups(0, NULL); if (saved_groups_length < 0) { D (("getgroups: %s", strerror(errno))); return -1; } if (saved_groups_length > 0) { if (saved_groups) free(saved_groups); /* size might have changed */ saved_groups = malloc(saved_groups_length * sizeof(gid_t)); if (saved_groups == NULL) { D (("malloc: %s", strerror(errno))); return -1; } if (getgroups(saved_groups_length, saved_groups) < 0) { D (("getgroups: %s", strerror(errno))); goto free_out; } } if (initgroups(pw->pw_name, pw->pw_gid) < 0) { D (("initgroups: %s", strerror(errno))); goto free_out; } if (setegid(pw->pw_gid) < 0) { D (("setegid: %s", strerror(errno))); goto free_out; } if (seteuid(pw->pw_uid) < 0) { D (("seteuid: %s", strerror(errno))); goto free_out; } return 0; free_out: free(saved_groups); saved_groups = NULL; return -1; #endif /* HAVE_PAM_MODUTIL_DROP_PRIV */ } int restore_privileges(pam_handle_t *pamh) { #ifdef HAVE_PAM_MODUTIL_DROP_PRIV int res; res = pam_modutil_regain_priv(pamh, _privs_location(0)); if (res) { D (("pam_modutil_regain_priv: %i", res)); } /* re-initialize privs in case we want to drop privs again (sic) */ _privs_location(1); return res; #else if ((saved_euid == geteuid()) && (saved_egid == getegid())) { D (("Privilges already as requested, pretend it is all right")); return 0; } if (seteuid(saved_euid) < 0) { D (("seteuid: %s", strerror(errno))); return -1; } if (setegid(saved_egid) < 0) { D (("setegid: %s", strerror(errno))); return -1; } if (saved_groups == NULL) { D (("saved groups are empty, looks like a program error!")); return -1; } if (setgroups(saved_groups_length, saved_groups) < 0) { D (("setgroups: %s", strerror(errno))); return -1; } free(saved_groups); return 0; #endif /* HAVE_PAM_MODUTIL_DROP_PRIV */ }