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