Correct PPTP server firewall rules chain.
[tomato/davidwu.git] / release / src / router / vsftpd / ftpcmdio.c
blob08a2548359557af0bd474467b2823bf31cf679ea
1 /*
2 * Part of Very Secure FTPd
3 * Licence: GPL v2
4 * Author: Chris Evans
5 * ftpcmdio.c
7 * Routines applicable to reading and writing the FTP command stream.
8 */
10 #include "ftpcmdio.h"
11 #include "ftpcodes.h"
12 #include "str.h"
13 #include "netstr.h"
14 #include "sysutil.h"
15 #include "tunables.h"
16 #include "defs.h"
17 #include "secbuf.h"
18 #include "utility.h"
19 #include "logging.h"
20 #include "session.h"
21 #include "readwrite.h"
23 /* Internal functions */
24 static void control_getline(struct mystr* p_str, struct vsf_session* p_sess);
25 static void ftp_write_text_common(struct vsf_session* p_sess, int status,
26 const char* p_text, int noblock, char sep);
27 static void ftp_write_str_common(struct vsf_session* p_sess, int status,
28 char sep, const struct mystr* p_str,
29 int noblock);
30 static void handle_alarm_timeout(void* p_private);
32 void
33 vsf_cmdio_sock_setup(void)
35 vsf_sysutil_activate_keepalive(VSFTP_COMMAND_FD);
36 vsf_sysutil_set_nodelay(VSFTP_COMMAND_FD);
37 vsf_sysutil_activate_oobinline(VSFTP_COMMAND_FD);
40 static void
41 handle_alarm_timeout(void* p_private)
43 struct vsf_session* p_sess = (struct vsf_session*) p_private;
44 vsf_cmdio_write_exit(p_sess, FTP_IDLE_TIMEOUT, "Timeout.");
47 void
48 vsf_cmdio_write(struct vsf_session* p_sess, int status, const char* p_text)
50 ftp_write_text_common(p_sess, status, p_text, 0, ' ');
53 void
54 vsf_cmdio_write_hyphen(struct vsf_session* p_sess, int status,
55 const char* p_text)
57 ftp_write_text_common(p_sess, status, p_text, 0, '-');
60 void
61 vsf_cmdio_write_raw(struct vsf_session* p_sess, const char* p_text)
63 static struct mystr s_the_str;
64 int retval;
65 str_alloc_text(&s_the_str, p_text);
66 if (tunable_log_ftp_protocol)
68 vsf_log_line(p_sess, kVSFLogEntryFTPOutput, &s_the_str);
70 retval = ftp_write_str(p_sess, &s_the_str, kVSFRWControl);
71 if (retval != 0)
73 die("ftp_write_str");
77 void
78 vsf_cmdio_write_exit(struct vsf_session* p_sess, int status, const char* p_text)
80 /* Unblock any readers on the dying control channel. This is needed for SSL
81 * connections, where the SSL control channel slave is in a separate
82 * process.
84 vsf_sysutil_shutdown_read_failok(VSFTP_COMMAND_FD);
85 ftp_write_text_common(p_sess, status, p_text, 1, ' ');
86 vsf_sysutil_shutdown_failok(VSFTP_COMMAND_FD);
87 vsf_sysutil_exit(0);
90 static void
91 ftp_write_text_common(struct vsf_session* p_sess, int status,
92 const char* p_text, int noblock, char sep)
94 /* XXX - could optimize */
95 static struct mystr s_the_str;
96 str_alloc_text(&s_the_str, p_text);
97 ftp_write_str_common(p_sess, status, sep, &s_the_str, noblock);
100 void
101 vsf_cmdio_write_str_hyphen(struct vsf_session* p_sess, int status,
102 const struct mystr* p_str)
104 ftp_write_str_common(p_sess, status, '-', p_str, 0);
107 void
108 vsf_cmdio_write_str(struct vsf_session* p_sess, int status,
109 const struct mystr* p_str)
111 ftp_write_str_common(p_sess, status, ' ', p_str, 0);
114 static void
115 ftp_write_str_common(struct vsf_session* p_sess, int status, char sep,
116 const struct mystr* p_str, int noblock)
118 static struct mystr s_write_buf_str;
119 static struct mystr s_text_mangle_str;
120 int retval;
121 if (tunable_log_ftp_protocol)
123 str_alloc_ulong(&s_write_buf_str, (unsigned long) status);
124 str_append_char(&s_write_buf_str, sep);
125 str_append_str(&s_write_buf_str, p_str);
126 vsf_log_line(p_sess, kVSFLogEntryFTPOutput, &s_write_buf_str);
128 str_copy(&s_text_mangle_str, p_str);
129 /* Process the output response according to the specifications.. */
130 /* Escape telnet characters properly */
131 str_replace_text(&s_text_mangle_str, "\377", "\377\377");
132 /* Change \n for \0 in response */
133 str_replace_char(&s_text_mangle_str, '\n', '\0');
134 /* Build string to squirt down network */
135 str_alloc_ulong(&s_write_buf_str, (unsigned long) status);
136 str_append_char(&s_write_buf_str, sep);
137 str_append_str(&s_write_buf_str, &s_text_mangle_str);
138 str_append_text(&s_write_buf_str, "\r\n");
139 if (noblock)
141 vsf_sysutil_activate_noblock(VSFTP_COMMAND_FD);
143 retval = ftp_write_str(p_sess, &s_write_buf_str, kVSFRWControl);
144 if (retval != 0 && !noblock)
146 die("ftp_write");
148 if (noblock)
150 vsf_sysutil_deactivate_noblock(VSFTP_COMMAND_FD);
154 void
155 vsf_cmdio_set_alarm(struct vsf_session* p_sess)
157 if (tunable_idle_session_timeout > 0)
159 vsf_sysutil_install_sighandler(kVSFSysUtilSigALRM,
160 handle_alarm_timeout,
161 p_sess,
163 vsf_sysutil_set_alarm(tunable_idle_session_timeout);
167 void
168 vsf_cmdio_get_cmd_and_arg(struct vsf_session* p_sess, struct mystr* p_cmd_str,
169 struct mystr* p_arg_str, int set_alarm)
171 /* Prepare an alarm to timeout the session.. */
172 if (set_alarm)
174 vsf_cmdio_set_alarm(p_sess);
176 /* Blocks */
177 control_getline(p_cmd_str, p_sess);
178 /* View a single space as a command of " ", which although a useless command,
179 * permits the caller to distinguish input of "" from " ".
181 if (str_getlen(p_cmd_str) == 1 && str_get_char_at(p_cmd_str, 0) == ' ')
183 str_empty(p_arg_str);
185 else
187 str_split_char(p_cmd_str, p_arg_str, ' ');
189 str_upper(p_cmd_str);
190 if (tunable_log_ftp_protocol)
192 static struct mystr s_log_str;
193 if (str_equal_text(p_cmd_str, "PASS"))
195 str_alloc_text(&s_log_str, "PASS <password>");
197 else
199 str_copy(&s_log_str, p_cmd_str);
200 if (!str_isempty(p_arg_str))
202 str_append_char(&s_log_str, ' ');
203 str_append_str(&s_log_str, p_arg_str);
206 vsf_log_line(p_sess, kVSFLogEntryFTPInput, &s_log_str);
210 static void
211 control_getline(struct mystr* p_str, struct vsf_session* p_sess)
213 int ret;
214 if (p_sess->p_control_line_buf == 0)
216 vsf_secbuf_alloc(&p_sess->p_control_line_buf, VSFTP_MAX_COMMAND_LINE);
218 ret = ftp_getline(p_sess, p_str, p_sess->p_control_line_buf);
219 if (ret < 0)
221 vsf_cmdio_write_exit(p_sess, FTP_BADCMD, "Input line too long.");
223 /* As mandated by the FTP specifications.. */
224 str_replace_char(p_str, '\0', '\n');
225 /* If the last character is a \r, strip it */
227 unsigned int len = str_getlen(p_str);
228 while (len > 0 && str_get_char_at(p_str, len - 1) == '\r')
230 str_trunc(p_str, len - 1);
231 --len;