2 * Part of Very Secure FTPd
7 * Routines applicable to reading and writing the FTP command stream.
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
,
30 static void handle_alarm_timeout(void* p_private
);
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
);
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.");
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, ' ');
54 vsf_cmdio_write_hyphen(struct vsf_session
* p_sess
, int status
,
57 ftp_write_text_common(p_sess
, status
, p_text
, 0, '-');
61 vsf_cmdio_write_raw(struct vsf_session
* p_sess
, const char* p_text
)
63 static struct mystr s_the_str
;
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
);
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
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
);
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
);
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);
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);
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
;
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");
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
)
150 vsf_sysutil_deactivate_noblock(VSFTP_COMMAND_FD
);
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
,
163 vsf_sysutil_set_alarm(tunable_idle_session_timeout
);
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.. */
174 vsf_cmdio_set_alarm(p_sess
);
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
);
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>");
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
);
211 control_getline(struct mystr
* p_str
, struct vsf_session
* p_sess
)
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
);
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);