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
15void
16vsf_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
27  p_user = str_getpwnam(p_user_str);
28
29  if (p_user == 0)
30  {
31    die2("cannot locate user entry:", str_getbuf(p_user_str));
32  }
33  {
34
35    struct mystr dir_str = INIT_MYSTR;
36    /* Work out where the chroot() jail is */
37    if (p_dir_str == 0 || str_isempty(p_dir_str))
38    {
39      str_alloc_text(&dir_str, vsf_sysutil_user_get_homedir(p_user));
40    }
41    else
42    {
43      str_copy(&dir_str, p_dir_str);
44    }
45
46    /* Sort out supplementary groups before the chroot(). We need to access
47     * /etc/groups
48     */
49    if (options & VSF_SECUTIL_OPTION_USE_GROUPS)
50    {
51      vsf_sysutil_initgroups(p_user);
52    }
53    else
54    {
55      vsf_sysutil_clear_supp_groups();
56    }
57
58    /* Always do the chdir() regardless of whether we are chroot()'ing */
59    {
60      /* Do chdir() with the target effective IDs to cater for NFS mounted
61       * home directories.
62       */
63      int saved_euid = 0;
64      int saved_egid = 0;
65      int retval;
66      if (options & VSF_SECUTIL_OPTION_CHANGE_EUID)
67      {
68        saved_euid = vsf_sysutil_geteuid();
69        saved_egid = vsf_sysutil_getegid();
70        vsf_sysutil_setegid(p_user);
71        vsf_sysutil_seteuid(p_user);
72      }
73
74      retval = str_chdir(&dir_str);
75
76      if (retval != 0)
77      {
78        die2("cannot change directory:", str_getbuf(&dir_str));
79      }
80      if (p_ext_dir_str && !str_isempty(p_ext_dir_str))
81      {
82		retval = str_chdir(p_ext_dir_str);
83
84        /* Failure on the extra directory is OK as long as we're not in
85         * chroot() mode
86         */
87        if (retval != 0 && !(options & VSF_SECUTIL_OPTION_CHROOT))
88        {
89          retval = 0;
90        }
91      }
92
93      if (retval != 0)
94      {
95        die2("cannot change directory:", str_getbuf(p_ext_dir_str));
96      }
97      if (options & VSF_SECUTIL_OPTION_CHANGE_EUID)
98      {
99        vsf_sysutil_seteuid_numeric(saved_euid);
100        vsf_sysutil_setegid_numeric(saved_egid);
101      }
102
103// 2007.05 James {
104      /* Do the chroot() if required */
105      //if (options & VSF_SECUTIL_OPTION_CHROOT)
106      //{
107      //  vsf_sysutil_chroot(".");
108      //}
109// 2007.05 James }
110    }
111    str_free(&dir_str);
112  }
113  /* Handle capabilities */
114  if (caps)
115  {
116    if (!vsf_sysdep_has_capabilities())
117    {
118      /* Need privilege but OS has no capabilities - have to keep root */
119      return;
120    }
121    if (!vsf_sysdep_has_capabilities_as_non_root())
122    {
123      vsf_sysdep_adopt_capabilities(caps);
124      return;
125    }
126    vsf_sysdep_keep_capabilities();
127  }
128
129  /* Set group id */
130  vsf_sysutil_setgid(p_user);
131  /* Finally set user id */
132  vsf_sysutil_setuid(p_user);
133
134  if (caps)
135  {
136    vsf_sysdep_adopt_capabilities(caps);
137  }
138}
139
140