1 /*
2  * Part of Very Secure FTPd
3  * Licence: GPL v2
4  * Author: Chris Evans
5  * sslslave.c
6  */
7 
8 #include "sslslave.h"
9 #include "session.h"
10 #include "privsock.h"
11 #include "tunables.h"
12 #include "sysutil.h"
13 #include "sysdeputil.h"
14 #include "utility.h"
15 #include "ssl.h"
16 #include "readwrite.h"
17 #include "defs.h"
18 
19 void
ssl_slave(struct vsf_session * p_sess)20 ssl_slave(struct vsf_session* p_sess)
21 {
22   struct mystr data_str = INIT_MYSTR;
23   str_reserve(&data_str, VSFTP_DATA_BUFSIZE);
24   /* Before becoming the slave, clear the alarm for the FTP protocol. */
25   vsf_sysutil_clear_alarm();
26   /* No need for any further communications with the privileged parent. */
27   priv_sock_set_parent_context(p_sess);
28   if (tunable_setproctitle_enable)
29   {
30     vsf_sysutil_setproctitle("SSL handler");
31   }
32   while (1)
33   {
34     char cmd = priv_sock_get_cmd(p_sess->ssl_slave_fd);
35     int ret;
36     if (cmd == PRIV_SOCK_GET_USER_CMD)
37     {
38       ret = ftp_getline(p_sess, &p_sess->ftp_cmd_str,
39                         p_sess->p_control_line_buf);
40       priv_sock_send_int(p_sess->ssl_slave_fd, ret);
41       if (ret >= 0)
42       {
43         priv_sock_send_str(p_sess->ssl_slave_fd, &p_sess->ftp_cmd_str);
44       }
45     }
46     else if (cmd == PRIV_SOCK_WRITE_USER_RESP)
47     {
48       priv_sock_get_str(p_sess->ssl_slave_fd, &p_sess->ftp_cmd_str);
49       ret = ftp_write_str(p_sess, &p_sess->ftp_cmd_str, kVSFRWControl);
50       priv_sock_send_int(p_sess->ssl_slave_fd, ret);
51     }
52     else if (cmd == PRIV_SOCK_DO_SSL_HANDSHAKE)
53     {
54       char result = PRIV_SOCK_RESULT_BAD;
55       if (p_sess->data_fd != -1 || p_sess->p_data_ssl != 0)
56       {
57         bug("state not clean");
58       }
59       p_sess->data_fd = priv_sock_recv_fd(p_sess->ssl_slave_fd);
60       ret = ssl_accept(p_sess, p_sess->data_fd);
61       if (ret == 1)
62       {
63         result = PRIV_SOCK_RESULT_OK;
64       }
65       else
66       {
67         vsf_sysutil_close(p_sess->data_fd);
68         p_sess->data_fd = -1;
69       }
70       priv_sock_send_result(p_sess->ssl_slave_fd, result);
71     }
72     else if (cmd == PRIV_SOCK_DO_SSL_READ)
73     {
74       int size = priv_sock_get_int(p_sess->ssl_slave_fd);
75       if (size <= 0 || size > VSFTP_DATA_BUFSIZE)
76       {
77         bug("bad size");
78       }
79       if (p_sess->data_fd == -1 || p_sess->p_data_ssl == 0)
80       {
81         bug("invalid state");
82       }
83       str_trunc(&data_str, (unsigned int) size);
84       ret = ssl_read_into_str(p_sess, p_sess->p_data_ssl, &data_str);
85       priv_sock_send_int(p_sess->ssl_slave_fd, ret);
86       priv_sock_send_str(p_sess->ssl_slave_fd, &data_str);
87     }
88     else if (cmd == PRIV_SOCK_DO_SSL_WRITE)
89     {
90       if (p_sess->data_fd == -1 || p_sess->p_data_ssl == 0)
91       {
92         bug("invalid state");
93       }
94       priv_sock_get_str(p_sess->ssl_slave_fd, &data_str);
95       ret = ssl_write(p_sess->p_data_ssl,
96                       str_getbuf(&data_str),
97                       str_getlen(&data_str));
98       priv_sock_send_int(p_sess->ssl_slave_fd, ret);
99     }
100     else if (cmd == PRIV_SOCK_DO_SSL_CLOSE)
101     {
102       char result = PRIV_SOCK_RESULT_BAD;
103       if (p_sess->data_fd == -1 && p_sess->p_data_ssl == 0)
104       {
105         result = PRIV_SOCK_RESULT_OK;
106       }
107       else
108       {
109         if (p_sess->data_fd == -1 || p_sess->p_data_ssl == 0)
110         {
111           bug("invalid state");
112         }
113         ret = ssl_data_close(p_sess);
114         if (ret == 1)
115         {
116           result = PRIV_SOCK_RESULT_OK;
117         }
118         vsf_sysutil_close(p_sess->data_fd);
119         p_sess->data_fd = -1;
120       }
121       priv_sock_send_result(p_sess->ssl_slave_fd, result);
122     }
123     else
124     {
125       die("bad request in process_ssl_slave_req");
126     }
127   }
128 }
129