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