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