"Fossies" - the Fresh Open Source Software Archive 
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "ftp_connection.c" see the
Fossies "Dox" file reference documentation.
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /*
18 * Original Copyright (c) 2005 Covalent Technologies
19 *
20 * FTP Protocol module for Apache 2.0
21 */
22
23 #include "mod_ftp.h"
24 #include "ftp_internal.h"
25
26 /* Placeholder of "unknown" username (not valid for ftp_cmd_pass)
27 */
28 const char ftp_unknown_username[] = "unknown";
29
30 /*
31 * initialize_ftp_connection: Used to initialize the ftp_connection structure
32 * when accepting an incoming FTP connection.
33 *
34 * Arguments: c - The connection associated with the session
35 * fc - The ftp connection to initialize
36 *
37 * Returns: nothing
38 */
39 static void initialize_ftp_connection(conn_rec *c, ftp_connection *fc)
40 {
41 /*
42 * The ftp_connection structure is calloc'ed so only initalize the
43 * members that we need to.
44 */
45 fc->connection = c;
46 fc->user = ftp_unknown_username;
47 fc->auth = FTP_AUTH_NONE;
48 fc->prot = FTP_PROT_CLEAR;
49 fc->type = TYPE_A;
50 fc->passive_created = -1;
51 fc->orig_server = c->base_server;
52
53 fc->cwd = apr_palloc(c->pool, APR_PATH_MAX + 1);
54 fc->cwd[0] = '/';
55 fc->cwd[1] = '\0';
56
57 fc->rename_from = apr_palloc(c->pool, APR_PATH_MAX + 1);
58 fc->rename_from[0] = '\0';
59
60 apr_pool_create(&fc->login_pool, c->pool);
61 apr_pool_tag(fc->login_pool, "login");
62 apr_pool_create(&fc->data_pool, c->pool);
63 apr_pool_tag(fc->data_pool, "data");
64
65 fc->cntlsock = ap_get_module_config(c->conn_config, &core_module);
66
67 ftp_set_module_config(c->conn_config, fc);
68 }
69
70 /* ftp_ssl_init: Fakes a read on the SSL filters to force initialization.
71 *
72 * Arguments: cdata - The data connection
73 *
74 * Return: apr_status_t
75 */
76 apr_status_t ftp_ssl_init(conn_rec *cdata)
77 {
78 ftp_connection *fc = ftp_get_module_config(cdata->conn_config);
79 apr_bucket_brigade *bb;
80 apr_status_t rv;
81 apr_socket_t *client_socket;
82
83 /*
84 * This is handled in the NET_TIME filter, which unfortunately ignores
85 * the timeout for the purpose of AP_MODE_INIT. Fix a timeout so the core
86 * read filter will behave.
87 */
88 client_socket = ap_get_module_config(cdata->conn_config, &core_module);
89 rv = apr_socket_timeout_set(client_socket, fc->orig_server->timeout);
90
91 if (rv != APR_SUCCESS) {
92 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, fc->orig_server,
93 "Failed to set socket timeout");
94 }
95
96 bb = apr_brigade_create(cdata->pool, cdata->bucket_alloc);
97 rv = ap_get_brigade(cdata->input_filters, bb, AP_MODE_INIT,
98 APR_BLOCK_READ, 0);
99 apr_brigade_destroy(bb);
100
101 if (rv != APR_SUCCESS) {
102 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, fc->orig_server,
103 "Failed to initialize the ftp ssl data stream");
104 }
105
106 return rv;
107 }
108
109 /*
110 * ftp_send_welcome: Send the server welcome string to the client
111 *
112 * Arguments: fc - The ftp connection to send the welcome message to
113 *
114 * Returns: apr_status_t
115 */
116 static apr_status_t ftp_send_welcome(ftp_connection *fc)
117 {
118 conn_rec *c = fc->connection;
119 ftp_server_config *fsc;
120 apr_status_t rv;
121
122 fsc = ftp_get_module_config(fc->orig_server->module_config);
123
124 /* Check if a login message has been configured */
125 if (fsc->banner_message) {
126 if (fsc->banner_message_isfile) {
127 rv = ftp_show_file(c->output_filters, fc->data_pool,
128 FTP_REPLY_SERVICE_READY, fc,
129 fsc->banner_message);
130 if (rv != APR_SUCCESS) {
131 return rv;
132 }
133 }
134 else {
135 char outbuf[BUFSIZ];
136
137 ftp_message_generate(fc, fsc->banner_message,
138 outbuf, sizeof(outbuf));
139
140 rv = ftp_reply(fc, c->output_filters, fc->data_pool,
141 FTP_REPLY_SERVICE_READY, 1, outbuf);
142
143 if (rv != APR_SUCCESS) {
144 return rv;
145 }
146 }
147 }
148
149 rv = ftp_reply(fc, c->output_filters, fc->data_pool,
150 FTP_REPLY_SERVICE_READY, 0,
151 "%s FTP Server (%s) ready.",
152 fc->orig_server->server_hostname,
153 #if AP_MODULE_MAGIC_AT_LEAST(20060905,0)
154 ap_get_server_banner());
155 #else
156 ap_get_server_version());
157 #endif
158 return rv;
159 }
160
161 /*
162 * ftp_process_connection: Connection handler for the FTP module.
163 *
164 * Arguments: c - The incoming connection
165 *
166 * Returns: Returns OK when the connection is to be closed.
167 */
168 int ftp_process_connection(conn_rec *c)
169 {
170 ap_filter_t *f;
171 request_rec *r;
172 ftp_connection *fc;
173 apr_status_t rv;
174 int idle_timeout_set = 0;
175 extern ap_filter_rec_t *ftp_ssl_input_filter_handle;
176 extern ap_filter_rec_t *ftp_ssl_output_filter_handle;
177 ftp_server_config *fsc;
178
179 fsc = ftp_get_module_config(c->base_server->module_config);
180
181 if (!fsc->enabled) {
182 return DECLINED;
183 }
184
185 /*
186 * Allocate for FTP connection structure, and initialize
187 */
188 fc = apr_pcalloc(c->pool, sizeof(*fc));
189 initialize_ftp_connection(c, fc);
190
191 /* Check for implicit security on the control connection */
192 if (!fsc->implicit_ssl) {
193 for (f = c->output_filters; f; f = f->next) {
194 if (strcasecmp(f->frec->name, FTP_SSL_FILTER) == 0) {
195 fc->ssl_output_ctx = f->ctx;
196 ap_remove_output_filter(f);
197 }
198 }
199 for (f = c->input_filters; f; f = f->next) {
200 if (strcasecmp(f->frec->name, FTP_SSL_FILTER) == 0) {
201 fc->ssl_input_ctx = f->ctx;
202 ap_remove_input_filter(f);
203 }
204 }
205 }
206 else {
207 /* Initialize control connection */
208 if ((rv = ftp_ssl_init(c)) != APR_SUCCESS) {
209 /*
210 * Error initializing the connection, most likely from a client
211 * attempting to connect w/o SSL. Just drop the connection
212 */
213 ap_log_error(APLOG_MARK, APLOG_INFO, rv, fc->orig_server,
214 "Error initializing SSL connection. Client "
215 "connecting without SSL?");
216 return OK;
217 }
218
219 /*
220 * From draft-murray-auth-ftp-ssl-06.txt: For implicit SSL the data
221 * connection should be implicitly protected (i.e. the PBSZ 0, PROT P
222 * command sequence is not required but the client and server will
223 * protect the data channel as if it had).
224 *
225 * Support for Implicit SSL was declared deprecated as of
226 * draft-murray-auth-ftp-ssl-07.txt, and is not documented whatsoever
227 * within RFC4217.
228 */
229 fc->auth = FTP_AUTH_SSL;
230 fc->prot = FTP_PROT_PRIVATE;
231 fc->is_secure = 1;
232 }
233
234 rv = ftp_send_welcome(fc);
235 if (rv != APR_SUCCESS) {
236 ap_log_error(APLOG_MARK, APLOG_INFO, rv, fc->orig_server,
237 "Error sending server welcome string");
238 return OK;
239 }
240
241 /*
242 * Begin processing requests
243 */
244
245 /* Set initial login timeout value */
246 rv = apr_socket_timeout_set(fc->cntlsock,
247 fsc->timeout_login * APR_USEC_PER_SEC);
248 if (rv != APR_SUCCESS) {
249 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, fc->orig_server,
250 "Couldn't set SO_TIMEOUT socket option");
251 }
252
253 ap_update_child_status(c->sbh,
254 SERVER_BUSY_READ, NULL);
255
256 while ((r = ftp_read_request(fc)) != NULL) {
257
258 /*
259 * Set socket timeout values. A user can use the SITE command to
260 * change the idle timeout during an FTP session, but since we do not
261 * support the SITE command, it doesn't make sense to be setting the
262 * socket timeout on every single request.
263 */
264 if (!idle_timeout_set) {
265 rv = apr_socket_timeout_set(fc->cntlsock,
266 fsc->timeout_idle * APR_USEC_PER_SEC);
267 if (rv != APR_SUCCESS) {
268 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, r->server,
269 "Couldn't set socket timeout");
270 }
271 idle_timeout_set = 1;
272 }
273
274 ap_update_child_status(c->sbh,
275 SERVER_BUSY_WRITE, NULL);
276
277 ftp_process_request(r);
278
279 if (ap_extended_status) {
280 ap_increment_counts(c->sbh, r);
281 }
282
283 apr_pool_destroy(r->pool);
284
285 /* Check if the connection should be closed */
286 if (fc->close_connection) {
287 break;
288 }
289
290 /* Check if the client has requested a secure connection */
291 if ((fc->auth == FTP_AUTH_TLS || fc->auth == FTP_AUTH_SSL) &&
292 fc->is_secure == 0) {
293 ap_add_output_filter_handle(ftp_ssl_output_filter_handle,
294 fc->ssl_output_ctx, NULL, c);
295 ap_add_input_filter_handle(ftp_ssl_input_filter_handle,
296 fc->ssl_input_ctx, NULL, c);
297 fc->is_secure = 1;
298 }
299 }
300 if (fc->logged_in) {
301 ftp_limitlogin_loggedout(c);
302 }
303 return OK;
304 }