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 * postprivparent.c
22 *
23 * This file contains all privileged parent services offered after logging
24 * in. This includes e.g. chown() of uploaded files, issuing of port 20
25 * sockets.
26 */
27
28#include "postprivparent.h"
29#include "session.h"
30#include "privops.h"
31#include "privsock.h"
32#include "utility.h"
33#include "tunables.h"
34#include "defs.h"
35#include "sysutil.h"
36#include "str.h"
37#include "secutil.h"
38#include "sysstr.h"
39#include "sysdeputil.h"
40
41static void minimize_privilege(struct vsf_session* p_sess);
42static void process_post_login_req(struct vsf_session* p_sess);
43static void cmd_process_chown(struct vsf_session* p_sess);
44static void cmd_process_get_data_sock(struct vsf_session* p_sess);
45
46void
47vsf_priv_parent_postlogin(struct vsf_session* p_sess)
48{
49  minimize_privilege(p_sess);
50  /* We're still here... */
51  while (1)
52  {
53    process_post_login_req(p_sess);
54  }
55}
56
57static void
58process_post_login_req(struct vsf_session* p_sess)
59{
60  char cmd;
61  vsf_sysutil_unblock_sig(kVSFSysUtilSigCHLD);
62  /* Blocks */
63  cmd = priv_sock_get_cmd(p_sess->parent_fd);
64  vsf_sysutil_block_sig(kVSFSysUtilSigCHLD);
65  if (tunable_chown_uploads && cmd == PRIV_SOCK_CHOWN)
66  {
67    cmd_process_chown(p_sess);
68  }
69  else if (tunable_connect_from_port_20 && cmd == PRIV_SOCK_GET_DATA_SOCK)
70  {
71    cmd_process_get_data_sock(p_sess);
72  }
73  else
74  {
75    die("bad request in process_post_login_req");
76  }
77}
78
79static void
80minimize_privilege(struct vsf_session* p_sess)
81{
82  /* So, we logged in and forked a totally unprivileged child. Our job
83   * now is to minimize the privilege we need in order to act as a helper
84   * to the child.
85   *
86   * In some happy circumstances, we can exit and be done with root
87   * altogether.
88   */
89  if (!p_sess->is_anonymous && tunable_session_support)
90  {
91    /* Need to hang around to update logs, utmp, wtmp etc. on logout.
92     * Need to keep privs to do this. */
93    return;
94  }
95  if (!tunable_chown_uploads && !tunable_connect_from_port_20 &&
96      !tunable_max_per_ip && !tunable_max_clients)
97  {
98    /* Cool. We're outta here. */
99    vsf_sysutil_exit(0);
100  }
101  {
102    unsigned int caps = 0;
103    struct mystr user_str = INIT_MYSTR;
104    struct mystr dir_str = INIT_MYSTR;
105    str_alloc_text(&user_str, tunable_nopriv_user);
106    str_alloc_text(&dir_str, tunable_secure_chroot_dir);
107    if (tunable_chown_uploads)
108    {
109      caps |= kCapabilityCAP_CHOWN;
110    }
111    if (tunable_connect_from_port_20)
112    {
113      caps |= kCapabilityCAP_NET_BIND_SERVICE;
114    }
115    vsf_secutil_change_credentials(&user_str, &dir_str, 0, caps,
116                                   VSF_SECUTIL_OPTION_CHROOT);
117    str_free(&user_str);
118    str_free(&dir_str);
119  }
120}
121
122static void
123cmd_process_chown(struct vsf_session* p_sess)
124{
125  int the_fd = priv_sock_recv_fd(p_sess->parent_fd);
126  vsf_privop_do_file_chown(p_sess, the_fd);
127  vsf_sysutil_close(the_fd);
128  priv_sock_send_result(p_sess->parent_fd, PRIV_SOCK_RESULT_OK);
129}
130
131static void
132cmd_process_get_data_sock(struct vsf_session* p_sess)
133{
134  int sock_fd = vsf_privop_get_ftp_port_sock(p_sess);
135  priv_sock_send_result(p_sess->parent_fd, PRIV_SOCK_RESULT_OK);
136  priv_sock_send_fd(p_sess->parent_fd, sock_fd);
137  vsf_sysutil_close(sock_fd);
138}
139
140