version 1.9, 2003/06/21 16:52:40 |
version 1.10, 2004/09/28 15:10:51 |
|
|
/* |
/* |
* Copyright (c) 1994-1996,1998-2003 Todd C. Miller <Todd.Miller@courtesan.com> |
* Copyright (c) 1994-1996,1998-2004 Todd C. Miller <Todd.Miller@courtesan.com> |
* All rights reserved. |
|
* |
* |
* Redistribution and use in source and binary forms, with or without |
* Permission to use, copy, modify, and distribute this software for any |
* modification, are permitted provided that the following conditions |
* purpose with or without fee is hereby granted, provided that the above |
* are met: |
* copyright notice and this permission notice appear in all copies. |
* |
* |
* 1. Redistributions of source code must retain the above copyright |
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
* notice, this list of conditions and the following disclaimer. |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
* |
* |
* 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. |
|
* |
|
* 4. Products derived from this software may not be called "Sudo" nor |
|
* may "Sudo" appear in their names without specific prior written |
|
* permission from the author. |
|
* |
|
* 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. |
|
* |
|
* Sponsored in part by the Defense Advanced Research Projects |
* Sponsored in part by the Defense Advanced Research Projects |
* Agency (DARPA) and Air Force Research Laboratory, Air Force |
* Agency (DARPA) and Air Force Research Laboratory, Air Force |
* Materiel Command, USAF, under agreement number F39502-99-1-0512. |
* Materiel Command, USAF, under agreement number F39502-99-1-0512. |
|
|
#include "sudo.h" |
#include "sudo.h" |
|
|
#ifndef lint |
#ifndef lint |
static const char rcsid[] = "$Sudo: set_perms.c,v 1.21 2003/04/16 00:42:10 millert Exp $"; |
static const char rcsid[] = "$Sudo: set_perms.c,v 1.30 2004/05/27 23:12:02 millert Exp $"; |
#endif /* lint */ |
#endif /* lint */ |
|
|
|
#ifdef __TANDEM |
|
# define ROOT_UID 65535 |
|
#else |
|
# define ROOT_UID 0 |
|
#endif |
|
|
/* |
/* |
* Prototypes |
* Prototypes |
*/ |
*/ |
|
|
|
|
switch (perm) { |
switch (perm) { |
case PERM_ROOT: |
case PERM_ROOT: |
if (seteuid(0)) |
if (seteuid(ROOT_UID)) |
fatal("seteuid(0) failed, your operating system may have broken POSIX saved ID support\nTry running configure with --disable-saved-ids", 0); |
fatal("seteuid(ROOT_UID) failed, your operating system may have broken POSIX saved ID support\nTry running configure with --disable-saved-ids", 0); |
break; |
break; |
|
|
case PERM_FULL_ROOT: |
case PERM_FULL_ROOT: |
/* headed for exec() */ |
/* headed for exec() */ |
(void) seteuid(0); |
(void) seteuid(ROOT_UID); |
if (setuid(0)) |
if (setuid(ROOT_UID)) |
fatal("setuid(0)", 1); |
fatal("setuid(ROOT_UID)", 1); |
break; |
break; |
|
|
case PERM_USER: |
case PERM_USER: |
|
|
break; |
break; |
|
|
case PERM_RUNAS: |
case PERM_RUNAS: |
/* headed for exec(), assume euid == 0 */ |
if (seteuid(runas_pw->pw_uid)) |
|
fatal("unable to change to runas uid", 1); |
|
break; |
|
|
|
case PERM_FULL_RUNAS: |
|
/* headed for exec(), assume euid == ROOT_UID */ |
runas_setup(); |
runas_setup(); |
if (def_flag(I_STAY_SETUID)) |
if (def_stay_setuid) |
error = seteuid(runas_pw->pw_uid); |
error = seteuid(runas_pw->pw_uid); |
else |
else |
error = setuid(runas_pw->pw_uid); |
error = setuid(runas_pw->pw_uid); |
|
|
break; |
break; |
|
|
case PERM_SUDOERS: |
case PERM_SUDOERS: |
/* assume euid == 0, ruid == user */ |
/* assume euid == ROOT_UID, ruid == user */ |
if (setegid(SUDOERS_GID)) |
if (setegid(SUDOERS_GID)) |
fatal("unable to change to sudoers gid", 1); |
fatal("unable to change to sudoers gid", 1); |
|
|
/* |
/* |
* If SUDOERS_UID == 0 and SUDOERS_MODE |
* If SUDOERS_UID == ROOT_UID and SUDOERS_MODE |
* is group readable we use a non-zero |
* is group readable we use a non-zero |
* uid in order to avoid NFS lossage. |
* uid in order to avoid NFS lossage. |
* Using uid 1 is a bit bogus but should |
* Using uid 1 is a bit bogus but should |
* work on all OS's. |
* work on all OS's. |
*/ |
*/ |
if (SUDOERS_UID == 0) { |
if (SUDOERS_UID == ROOT_UID) { |
if ((SUDOERS_MODE & 040) && seteuid(1)) |
if ((SUDOERS_MODE & 040) && seteuid(1)) |
fatal("seteuid(1)", 1); |
fatal("seteuid(1)", 1); |
} else { |
} else { |
|
|
switch (perm) { |
switch (perm) { |
case PERM_FULL_ROOT: |
case PERM_FULL_ROOT: |
case PERM_ROOT: |
case PERM_ROOT: |
if (setresuid(0, 0, 0)) |
if (setresuid(ROOT_UID, ROOT_UID, ROOT_UID)) |
fatal("setresuid(0, 0, 0) failed, your operating system may have a broken setresuid() function\nTry running configure with --disable-setresuid", 0); |
fatal("setresuid(ROOT_UID, ROOT_UID, ROOT_UID) failed, your operating system may have a broken setresuid() function\nTry running configure with --disable-setresuid", 0); |
break; |
break; |
|
|
case PERM_USER: |
case PERM_USER: |
(void) setresgid(-1, user_gid, -1); |
(void) setresgid(-1, user_gid, -1); |
if (setresuid(user_uid, user_uid, 0)) |
if (setresuid(user_uid, user_uid, ROOT_UID)) |
fatal("setresuid(user_uid, user_uid, 0)", 1); |
fatal("setresuid(user_uid, user_uid, ROOT_UID)", 1); |
break; |
break; |
|
|
case PERM_FULL_USER: |
case PERM_FULL_USER: |
|
|
break; |
break; |
|
|
case PERM_RUNAS: |
case PERM_RUNAS: |
/* headed for exec(), assume euid == 0 */ |
if (setresuid(-1, runas_pw->pw_uid, -1)) |
|
fatal("unable to change to runas uid", 1); |
|
break; |
|
|
|
case PERM_FULL_RUNAS: |
|
/* headed for exec(), assume euid == ROOT_UID */ |
runas_setup(); |
runas_setup(); |
error = setresuid(def_flag(I_STAY_SETUID) ? |
error = setresuid(def_stay_setuid ? |
user_uid : runas_pw->pw_uid, |
user_uid : runas_pw->pw_uid, |
runas_pw->pw_uid, runas_pw->pw_uid); |
runas_pw->pw_uid, runas_pw->pw_uid); |
if (error) |
if (error) |
|
|
break; |
break; |
|
|
case PERM_SUDOERS: |
case PERM_SUDOERS: |
/* assume euid == 0, ruid == user */ |
/* assume euid == ROOT_UID, ruid == user */ |
if (setresgid(-1, SUDOERS_GID, -1)) |
if (setresgid(-1, SUDOERS_GID, -1)) |
fatal("unable to change to sudoers gid", 1); |
fatal("unable to change to sudoers gid", 1); |
|
|
/* |
/* |
* If SUDOERS_UID == 0 and SUDOERS_MODE |
* If SUDOERS_UID == ROOT_UID and SUDOERS_MODE |
* is group readable we use a non-zero |
* is group readable we use a non-zero |
* uid in order to avoid NFS lossage. |
* uid in order to avoid NFS lossage. |
* Using uid 1 is a bit bogus but should |
* Using uid 1 is a bit bogus but should |
* work on all OS's. |
* work on all OS's. |
*/ |
*/ |
if (SUDOERS_UID == 0) { |
if (SUDOERS_UID == ROOT_UID) { |
if ((SUDOERS_MODE & 040) && setresuid(0, 1, 0)) |
if ((SUDOERS_MODE & 040) && setresuid(ROOT_UID, 1, ROOT_UID)) |
fatal("setresuid(0, 1, 0)", 1); |
fatal("setresuid(ROOT_UID, 1, ROOT_UID)", 1); |
} else { |
} else { |
if (setresuid(0, SUDOERS_UID, 0)) |
if (setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID)) |
fatal("setresuid(0, SUDOERS_UID, 0)", 1); |
fatal("setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID)", 1); |
} |
} |
break; |
break; |
case PERM_TIMESTAMP: |
case PERM_TIMESTAMP: |
if (setresuid(0, timestamp_uid, 0)) |
if (setresuid(ROOT_UID, timestamp_uid, ROOT_UID)) |
fatal("setresuid(0, timestamp_uid, 0)", 1); |
fatal("setresuid(ROOT_UID, timestamp_uid, ROOT_UID)", 1); |
break; |
break; |
} |
} |
} |
} |
|
|
|
|
/* |
/* |
* Set real and effective uids and gids based on perm. |
* Set real and effective uids and gids based on perm. |
* We always retain a real or effective uid of 0 unless |
* We always retain a real or effective uid of ROOT_UID unless |
* we are headed for an exec(). |
* we are headed for an exec(). |
* This version of set_perms() works fine with the "stay_setuid" option. |
* This version of set_perms() works fine with the "stay_setuid" option. |
*/ |
*/ |
|
|
switch (perm) { |
switch (perm) { |
case PERM_FULL_ROOT: |
case PERM_FULL_ROOT: |
case PERM_ROOT: |
case PERM_ROOT: |
if (setreuid(0, 0)) |
if (setreuid(-1, ROOT_UID)) |
fatal("setreuid(0, 0) failed, your operating system may have a broken setreuid() function\nTry running configure with --disable-setreuid", 0); |
fatal("setreuid(-1, ROOT_UID) failed, your operating system may have a broken setreuid() function\nTry running configure with --disable-setreuid", 0); |
|
if (setuid(ROOT_UID)) |
|
fatal("setuid(ROOT_UID)", 1); |
break; |
break; |
|
|
case PERM_USER: |
case PERM_USER: |
(void) setregid(-1, user_gid); |
(void) setregid(-1, user_gid); |
if (setreuid(0, user_uid)) |
if (setreuid(ROOT_UID, user_uid)) |
fatal("setreuid(0, user_uid)", 1); |
fatal("setreuid(ROOT_UID, user_uid)", 1); |
break; |
break; |
|
|
case PERM_FULL_USER: |
case PERM_FULL_USER: |
|
|
break; |
break; |
|
|
case PERM_RUNAS: |
case PERM_RUNAS: |
/* headed for exec(), assume euid == 0 */ |
if (setreuid(-1, runas_pw->pw_uid)) |
|
fatal("unable to change to runas uid", 1); |
|
break; |
|
|
|
case PERM_FULL_RUNAS: |
|
/* headed for exec(), assume euid == ROOT_UID */ |
runas_setup(); |
runas_setup(); |
error = setreuid(def_flag(I_STAY_SETUID) ? |
error = setreuid(def_stay_setuid ? |
user_uid : runas_pw->pw_uid, |
user_uid : runas_pw->pw_uid, |
runas_pw->pw_uid); |
runas_pw->pw_uid); |
if (error) |
if (error) |
|
|
break; |
break; |
|
|
case PERM_SUDOERS: |
case PERM_SUDOERS: |
/* assume euid == 0, ruid == user */ |
/* assume euid == ROOT_UID, ruid == user */ |
if (setregid(-1, SUDOERS_GID)) |
if (setregid(-1, SUDOERS_GID)) |
fatal("unable to change to sudoers gid", 1); |
fatal("unable to change to sudoers gid", 1); |
|
|
/* |
/* |
* If SUDOERS_UID == 0 and SUDOERS_MODE |
* If SUDOERS_UID == ROOT_UID and SUDOERS_MODE |
* is group readable we use a non-zero |
* is group readable we use a non-zero |
* uid in order to avoid NFS lossage. |
* uid in order to avoid NFS lossage. |
* Using uid 1 is a bit bogus but should |
* Using uid 1 is a bit bogus but should |
* work on all OS's. |
* work on all OS's. |
*/ |
*/ |
if (SUDOERS_UID == 0) { |
if (SUDOERS_UID == ROOT_UID) { |
if ((SUDOERS_MODE & 040) && setreuid(0, 1)) |
if ((SUDOERS_MODE & 040) && setreuid(ROOT_UID, 1)) |
fatal("setreuid(0, 1)", 1); |
fatal("setreuid(ROOT_UID, 1)", 1); |
} else { |
} else { |
if (setreuid(0, SUDOERS_UID)) |
if (setreuid(ROOT_UID, SUDOERS_UID)) |
fatal("setreuid(0, SUDOERS_UID)", 1); |
fatal("setreuid(ROOT_UID, SUDOERS_UID)", 1); |
} |
} |
break; |
break; |
case PERM_TIMESTAMP: |
case PERM_TIMESTAMP: |
if (setreuid(0, timestamp_uid)) |
if (setreuid(ROOT_UID, timestamp_uid)) |
fatal("setreuid(0, timestamp_uid)", 1); |
fatal("setreuid(ROOT_UID, timestamp_uid)", 1); |
break; |
break; |
} |
} |
} |
} |
|
|
# else |
# else |
|
# ifdef HAVE_SETREUID |
|
|
/* |
/* |
* Set real and effective uids and gids based on perm. |
* Set real and effective uids and gids based on perm. |
|
|
|
|
/* |
/* |
* Since we only have setuid() and seteuid() we have to set |
* Since we only have setuid() and seteuid() we have to set |
* real and effective uids to 0 initially. |
* real and effective uids to ROOT_UID initially. |
*/ |
*/ |
if (setuid(0)) |
if (setuid(ROOT_UID)) |
fatal("setuid(0)", 1); |
fatal("setuid(ROOT_UID)", 1); |
|
|
switch (perm) { |
switch (perm) { |
case PERM_USER: |
case PERM_USER: |
|
|
break; |
break; |
|
|
case PERM_RUNAS: |
case PERM_RUNAS: |
/* headed for exec(), assume euid == 0 */ |
if (seteuid(runas_pw->pw_uid)) |
|
fatal("unable to change to runas uid", 1); |
|
break; |
|
|
|
case PERM_FULL_RUNAS: |
|
/* headed for exec(), assume euid == ROOT_UID */ |
runas_setup(); |
runas_setup(); |
if (setuid(runas_pw->pw_uid)) |
if (setuid(runas_pw->pw_uid)) |
fatal("unable to change to runas uid", 1); |
fatal("unable to change to runas uid", 1); |
break; |
break; |
|
|
case PERM_SUDOERS: |
case PERM_SUDOERS: |
/* assume euid == 0, ruid == user */ |
/* assume euid == ROOT_UID, ruid == user */ |
if (setegid(SUDOERS_GID)) |
if (setegid(SUDOERS_GID)) |
fatal("unable to change to sudoers gid", 1); |
fatal("unable to change to sudoers gid", 1); |
|
|
/* |
/* |
* If SUDOERS_UID == 0 and SUDOERS_MODE |
* If SUDOERS_UID == ROOT_UID and SUDOERS_MODE |
* is group readable we use a non-zero |
* is group readable we use a non-zero |
* uid in order to avoid NFS lossage. |
* uid in order to avoid NFS lossage. |
* Using uid 1 is a bit bogus but should |
* Using uid 1 is a bit bogus but should |
* work on all OS's. |
* work on all OS's. |
*/ |
*/ |
if (SUDOERS_UID == 0) { |
if (SUDOERS_UID == ROOT_UID) { |
if ((SUDOERS_MODE & 040) && seteuid(1)) |
if ((SUDOERS_MODE & 040) && seteuid(1)) |
fatal("seteuid(1)", 1); |
fatal("seteuid(1)", 1); |
} else { |
} else { |
|
|
break; |
break; |
} |
} |
} |
} |
|
|
|
# else |
|
|
|
/* |
|
* Set uids and gids based on perm via setuid() and setgid(). |
|
* NOTE: does not support the "stay_setuid" or timestampowner options. |
|
* Also, SUDOERS_UID and SUDOERS_GID are not used. |
|
*/ |
|
void |
|
set_perms_nosuid(perm) |
|
int perm; |
|
{ |
|
|
|
switch (perm) { |
|
case PERM_FULL_ROOT: |
|
case PERM_ROOT: |
|
if (setuid(ROOT_UID)) |
|
fatal("setuid(ROOT_UID)", 1); |
|
break; |
|
|
|
case PERM_FULL_USER: |
|
(void) setgid(user_gid); |
|
if (setuid(user_uid)) |
|
fatal("setuid(user_uid)", 1); |
|
break; |
|
|
|
case PERM_FULL_RUNAS: |
|
runas_setup(); |
|
if (setuid(runas_pw->pw_uid)) |
|
fatal("unable to change to runas uid", 1); |
|
break; |
|
|
|
case PERM_USER: |
|
case PERM_SUDOERS: |
|
case PERM_RUNAS: |
|
case PERM_TIMESTAMP: |
|
/* Unsupported since we can't set euid. */ |
|
break; |
|
} |
|
} |
|
# endif /* HAVE_SETEUID */ |
# endif /* HAVE_SETREUID */ |
# endif /* HAVE_SETREUID */ |
#endif /* HAVE_SETRESUID */ |
#endif /* HAVE_SETRESUID */ |
|
|
|
|
#endif /* HAVE_PAM */ |
#endif /* HAVE_PAM */ |
|
|
#ifdef HAVE_LOGIN_CAP_H |
#ifdef HAVE_LOGIN_CAP_H |
if (def_flag(I_USE_LOGINCLASS)) { |
if (def_use_loginclass) { |
/* |
/* |
* We don't have setusercontext() set the user since we |
* We don't have setusercontext() set the user since we |
* may only want to set the effective uid. Depending on |
* may only want to set the effective uid. Depending on |
|
|
* setusercontext() to call initgroups(). |
* setusercontext() to call initgroups(). |
*/ |
*/ |
flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY; |
flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY; |
if (!def_flag(I_PRESERVE_GROUPS)) |
if (!def_preserve_groups) |
flags |= LOGIN_SETGROUP; |
SET(flags, LOGIN_SETGROUP); |
else if (setgid(runas_pw->pw_gid)) |
else if (setgid(runas_pw->pw_gid)) |
perror("cannot set gid to runas gid"); |
perror("cannot set gid to runas gid"); |
error = setusercontext(lc, runas_pw, |
error = setusercontext(lc, runas_pw, |
runas_pw->pw_uid, flags); |
runas_pw->pw_uid, flags); |
if (error) { |
if (error) { |
if (runas_pw->pw_uid != 0) |
if (runas_pw->pw_uid != ROOT_UID) |
fatal("unable to set user context", 1); |
fatal("unable to set user context", 1); |
else |
else |
perror("unable to set user context"); |
perror("unable to set user context"); |
|
|
/* |
/* |
* Initialize group vector unless asked not to. |
* Initialize group vector unless asked not to. |
*/ |
*/ |
if (!def_flag(I_PRESERVE_GROUPS) && |
if (!def_preserve_groups && |
initgroups(*user_runas, runas_pw->pw_gid) < 0) |
initgroups(*user_runas, runas_pw->pw_gid) < 0) |
perror("cannot set group vector"); |
perror("cannot set group vector"); |
#endif /* HAVE_INITGROUPS */ |
#endif /* HAVE_INITGROUPS */ |