1/*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License as
4 * published by the Free Software Foundation; either version 2 of
5 * the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
15 * MA 02111-1307 USA
16 */
17/*
18 * Part of Very Secure FTPd
19 * Licence: GPL v2
20 * Author: Chris Evans
21 * secutil.c
22 */
23
24#include "secutil.h"
25#include "str.h"
26#include "sysutil.h"
27#include "sysstr.h"
28#include "utility.h"
29#include "sysdeputil.h"
30
31void
32vsf_secutil_change_credentials(const struct mystr* p_user_str,
33                               const struct mystr* p_dir_str,
34                               const struct mystr* p_ext_dir_str,
35                               unsigned int caps, unsigned int options)
36{
37  struct vsf_sysutil_user* p_user;
38  if (!vsf_sysutil_running_as_root())
39  {
40    bug("vsf_secutil_change_credentials: not running as root");
41  }
42
43  p_user = str_getpwnam(p_user_str);
44
45  if (p_user == 0)
46  {
47    die2("cannot locate user entry:", str_getbuf(p_user_str));
48  }
49  {
50
51    struct mystr dir_str = INIT_MYSTR;
52    /* Work out where the chroot() jail is */
53    if (p_dir_str == 0 || str_isempty(p_dir_str))
54    {
55      str_alloc_text(&dir_str, vsf_sysutil_user_get_homedir(p_user));
56    }
57    else
58    {
59      str_copy(&dir_str, p_dir_str);
60    }
61
62    /* Sort out supplementary groups before the chroot(). We need to access
63     * /etc/groups
64     */
65    if (options & VSF_SECUTIL_OPTION_USE_GROUPS)
66    {
67      vsf_sysutil_initgroups(p_user);
68    }
69    else
70    {
71      vsf_sysutil_clear_supp_groups();
72    }
73
74    /* Always do the chdir() regardless of whether we are chroot()'ing */
75    {
76      /* Do chdir() with the target effective IDs to cater for NFS mounted
77       * home directories.
78       */
79      int saved_euid = 0;
80      int saved_egid = 0;
81      int retval;
82      if (options & VSF_SECUTIL_OPTION_CHANGE_EUID)
83      {
84        saved_euid = vsf_sysutil_geteuid();
85        saved_egid = vsf_sysutil_getegid();
86        vsf_sysutil_setegid(p_user);
87        vsf_sysutil_seteuid(p_user);
88      }
89
90      retval = str_chdir(&dir_str);
91
92      if (retval != 0)
93      {
94        die2("cannot change directory:", str_getbuf(&dir_str));
95      }
96      if (p_ext_dir_str && !str_isempty(p_ext_dir_str))
97      {
98		retval = str_chdir(p_ext_dir_str);
99
100        /* Failure on the extra directory is OK as long as we're not in
101         * chroot() mode
102         */
103        if (retval != 0 && !(options & VSF_SECUTIL_OPTION_CHROOT))
104        {
105          retval = 0;
106        }
107      }
108
109      if (retval != 0)
110      {
111        die2("cannot change directory:", str_getbuf(p_ext_dir_str));
112      }
113      if (options & VSF_SECUTIL_OPTION_CHANGE_EUID)
114      {
115        vsf_sysutil_seteuid_numeric(saved_euid);
116        vsf_sysutil_setegid_numeric(saved_egid);
117      }
118
119// 2007.05 James {
120      /* Do the chroot() if required */
121      //if (options & VSF_SECUTIL_OPTION_CHROOT)
122      //{
123      //  vsf_sysutil_chroot(".");
124      //}
125// 2007.05 James }
126    }
127    str_free(&dir_str);
128  }
129  /* Handle capabilities */
130  if (caps)
131  {
132    if (!vsf_sysdep_has_capabilities())
133    {
134      /* Need privilege but OS has no capabilities - have to keep root */
135      return;
136    }
137    if (!vsf_sysdep_has_capabilities_as_non_root())
138    {
139      vsf_sysdep_adopt_capabilities(caps);
140      return;
141    }
142    vsf_sysdep_keep_capabilities();
143  }
144
145  /* Set group id */
146  vsf_sysutil_setgid(p_user);
147  /* Finally set user id */
148  vsf_sysutil_setuid(p_user);
149
150  if (caps)
151  {
152    vsf_sysdep_adopt_capabilities(caps);
153  }
154}
155
156