1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
|
/*
* Part of Very Secure FTPd
* Licence: GPL v2
* Author: Chris Evans
* secutil.c
*/
#include "secutil.h"
#include "str.h"
#include "sysutil.h"
#include "sysstr.h"
#include "utility.h"
#include "sysdeputil.h"
void
vsf_secutil_change_credentials(const struct mystr* p_user_str,
const struct mystr* p_dir_str,
const struct mystr* p_ext_dir_str,
unsigned int caps, unsigned int options)
{
struct vsf_sysutil_user* p_user;
if (!vsf_sysutil_running_as_root())
{
bug("vsf_secutil_change_credentials: not running as root");
}
p_user = str_getpwnam(p_user_str);
if (p_user == 0)
{
die2("cannot locate user entry:", str_getbuf(p_user_str));
}
{
struct mystr dir_str = INIT_MYSTR;
/* Work out where the chroot() jail is */
if (p_dir_str == 0 || str_isempty(p_dir_str))
{
str_alloc_text(&dir_str, vsf_sysutil_user_get_homedir(p_user));
}
else
{
str_copy(&dir_str, p_dir_str);
}
/* Sort out supplementary groups before the chroot(). We need to access
* /etc/groups
*/
if (options & VSF_SECUTIL_OPTION_USE_GROUPS)
{
vsf_sysutil_initgroups(p_user);
}
else
{
vsf_sysutil_clear_supp_groups();
}
/* Always do the chdir() regardless of whether we are chroot()'ing */
{
/* Do chdir() with the target effective IDs to cater for NFS mounted
* home directories.
*/
int saved_euid = 0;
int saved_egid = 0;
int retval;
if (options & VSF_SECUTIL_OPTION_CHANGE_EUID)
{
saved_euid = vsf_sysutil_geteuid();
saved_egid = vsf_sysutil_getegid();
vsf_sysutil_setegid(p_user);
vsf_sysutil_seteuid(p_user);
}
retval = str_chdir(&dir_str);
if (retval != 0)
{
die2("cannot change directory:", str_getbuf(&dir_str));
}
if (p_ext_dir_str && !str_isempty(p_ext_dir_str))
{
retval = str_chdir(p_ext_dir_str);
/* Failure on the extra directory is OK as long as we're not in
* chroot() mode
*/
if (retval != 0 && !(options & VSF_SECUTIL_OPTION_CHROOT))
{
retval = 0;
}
}
if (retval != 0)
{
die2("cannot change directory:", str_getbuf(p_ext_dir_str));
}
if (options & VSF_SECUTIL_OPTION_CHANGE_EUID)
{
vsf_sysutil_seteuid_numeric(saved_euid);
vsf_sysutil_setegid_numeric(saved_egid);
}
/* Do the chroot() if required */
if (options & VSF_SECUTIL_OPTION_CHROOT)
{
vsf_sysutil_chroot(".");
}
}
str_free(&dir_str);
}
if (options & VSF_SECUTIL_OPTION_NO_FDS)
{
vsf_sysutil_set_no_fds();
}
/* Handle capabilities */
if (caps)
{
if (!vsf_sysdep_has_capabilities())
{
/* Need privilege but OS has no capabilities - have to keep root */
return;
}
if (!vsf_sysdep_has_capabilities_as_non_root())
{
vsf_sysdep_adopt_capabilities(caps);
return;
}
vsf_sysdep_keep_capabilities();
}
/* Set group id */
vsf_sysutil_setgid(p_user);
/* Finally set user id */
vsf_sysutil_setuid(p_user);
if (caps)
{
vsf_sysdep_adopt_capabilities(caps);
}
if (options & VSF_SECUTIL_OPTION_NO_PROCS)
{
vsf_sysutil_set_no_procs();
}
/* Misconfiguration check: don't ever chroot() to a directory writable by
* the current user.
*/
if (options & VSF_SECUTIL_OPTION_CHROOT)
{
if (vsf_sysutil_write_access("/"))
{
die("vsftpd: refusing to run with writable root inside chroot()");
}
}
}
|