|
|
1.1 root 1: #include <stdint.h>
2: #include <stdlib.h>
3: #include <stdio.h>
4: #include <string.h>
5: #include <assert.h>
6: #include <errno.h>
7: #include <byteswap.h>
8: #include <ipxe/socket.h>
9: #include <ipxe/tcpip.h>
10: #include <ipxe/in.h>
11: #include <ipxe/iobuf.h>
12: #include <ipxe/xfer.h>
13: #include <ipxe/open.h>
14: #include <ipxe/uri.h>
15: #include <ipxe/features.h>
16: #include <ipxe/ftp.h>
17:
18: /** @file
19: *
20: * File transfer protocol
21: *
22: */
23:
24: FEATURE ( FEATURE_PROTOCOL, "FTP", DHCP_EB_FEATURE_FTP, 1 );
25:
26: /**
27: * FTP states
28: *
29: * These @b must be sequential, i.e. a successful FTP session must
30: * pass through each of these states in order.
31: */
32: enum ftp_state {
33: FTP_CONNECT = 0,
34: FTP_USER,
35: FTP_PASS,
36: FTP_TYPE,
37: FTP_PASV,
38: FTP_RETR,
39: FTP_WAIT,
40: FTP_QUIT,
41: FTP_DONE,
42: };
43:
44: /**
45: * An FTP request
46: *
47: */
48: struct ftp_request {
49: /** Reference counter */
50: struct refcnt refcnt;
51: /** Data transfer interface */
52: struct interface xfer;
53:
54: /** URI being fetched */
55: struct uri *uri;
56: /** FTP control channel interface */
57: struct interface control;
58: /** FTP data channel interface */
59: struct interface data;
60:
61: /** Current state */
62: enum ftp_state state;
63: /** Buffer to be filled with data received via the control channel */
64: char *recvbuf;
65: /** Remaining size of recvbuf */
66: size_t recvsize;
67: /** FTP status code, as text */
68: char status_text[5];
69: /** Passive-mode parameters, as text */
70: char passive_text[24]; /* "aaa,bbb,ccc,ddd,eee,fff" */
71: };
72:
73: /**
74: * Free FTP request
75: *
76: * @v refcnt Reference counter
77: */
78: static void ftp_free ( struct refcnt *refcnt ) {
79: struct ftp_request *ftp =
80: container_of ( refcnt, struct ftp_request, refcnt );
81:
82: DBGC ( ftp, "FTP %p freed\n", ftp );
83:
84: uri_put ( ftp->uri );
85: free ( ftp );
86: }
87:
88: /**
89: * Mark FTP operation as complete
90: *
91: * @v ftp FTP request
92: * @v rc Return status code
93: */
94: static void ftp_done ( struct ftp_request *ftp, int rc ) {
95:
96: DBGC ( ftp, "FTP %p completed (%s)\n", ftp, strerror ( rc ) );
97:
98: /* Close all data transfer interfaces */
99: intf_shutdown ( &ftp->data, rc );
100: intf_shutdown ( &ftp->control, rc );
101: intf_shutdown ( &ftp->xfer, rc );
102: }
103:
104: /*****************************************************************************
105: *
106: * FTP control channel
107: *
108: */
109:
110: /** An FTP control channel string */
111: struct ftp_control_string {
112: /** Literal portion */
113: const char *literal;
114: /** Variable portion
115: *
116: * @v ftp FTP request
117: * @ret string Variable portion of string
118: */
119: const char * ( *variable ) ( struct ftp_request *ftp );
120: };
121:
122: /**
123: * Retrieve FTP pathname
124: *
125: * @v ftp FTP request
126: * @ret path FTP pathname
127: */
128: static const char * ftp_uri_path ( struct ftp_request *ftp ) {
129: return ftp->uri->path;
130: }
131:
132: /**
133: * Retrieve FTP user
134: *
135: * @v ftp FTP request
136: * @ret user FTP user
137: */
138: static const char * ftp_user ( struct ftp_request *ftp ) {
139: static char *ftp_default_user = "anonymous";
140: return ftp->uri->user ? ftp->uri->user : ftp_default_user;
141: }
142:
143: /**
144: * Retrieve FTP password
145: *
146: * @v ftp FTP request
147: * @ret password FTP password
148: */
149: static const char * ftp_password ( struct ftp_request *ftp ) {
150: static char *ftp_default_password = "[email protected]";
151: return ftp->uri->password ? ftp->uri->password : ftp_default_password;
152: }
153:
154: /** FTP control channel strings */
155: static struct ftp_control_string ftp_strings[] = {
156: [FTP_CONNECT] = { NULL, NULL },
157: [FTP_USER] = { "USER ", ftp_user },
158: [FTP_PASS] = { "PASS ", ftp_password },
159: [FTP_TYPE] = { "TYPE I", NULL },
160: [FTP_PASV] = { "PASV", NULL },
161: [FTP_RETR] = { "RETR ", ftp_uri_path },
162: [FTP_WAIT] = { NULL, NULL },
163: [FTP_QUIT] = { "QUIT", NULL },
164: [FTP_DONE] = { NULL, NULL },
165: };
166:
167: /**
168: * Parse FTP byte sequence value
169: *
170: * @v text Text string
171: * @v value Value buffer
172: * @v len Length of value buffer
173: *
174: * This parses an FTP byte sequence value (e.g. the "aaa,bbb,ccc,ddd"
175: * form for IP addresses in PORT commands) into a byte sequence. @c
176: * *text will be updated to point beyond the end of the parsed byte
177: * sequence.
178: *
179: * This function is safe in the presence of malformed data, though the
180: * output is undefined.
181: */
182: static void ftp_parse_value ( char **text, uint8_t *value, size_t len ) {
183: do {
184: *(value++) = strtoul ( *text, text, 10 );
185: if ( **text )
186: (*text)++;
187: } while ( --len );
188: }
189:
190: /**
191: * Move to next state and send the appropriate FTP control string
192: *
193: * @v ftp FTP request
194: *
195: */
196: static void ftp_next_state ( struct ftp_request *ftp ) {
197: struct ftp_control_string *ftp_string;
198: const char *literal;
199: const char *variable;
200:
201: /* Move to next state */
202: if ( ftp->state < FTP_DONE )
203: ftp->state++;
204:
205: /* Send control string if needed */
206: ftp_string = &ftp_strings[ftp->state];
207: literal = ftp_string->literal;
208: variable = ( ftp_string->variable ?
209: ftp_string->variable ( ftp ) : "" );
210: if ( literal ) {
211: DBGC ( ftp, "FTP %p sending %s%s\n", ftp, literal, variable );
212: xfer_printf ( &ftp->control, "%s%s\r\n", literal, variable );
213: }
214: }
215:
216: /**
217: * Handle an FTP control channel response
218: *
219: * @v ftp FTP request
220: *
221: * This is called once we have received a complete response line.
222: */
223: static void ftp_reply ( struct ftp_request *ftp ) {
224: char status_major = ftp->status_text[0];
225: char separator = ftp->status_text[3];
226:
227: DBGC ( ftp, "FTP %p received status %s\n", ftp, ftp->status_text );
228:
229: /* Ignore malformed lines */
230: if ( separator != ' ' )
231: return;
232:
233: /* Ignore "intermediate" responses (1xx codes) */
234: if ( status_major == '1' )
235: return;
236:
237: /* Anything other than success (2xx) or, in the case of a
238: * repsonse to a "USER" command, a password prompt (3xx), is a
239: * fatal error.
240: */
241: if ( ! ( ( status_major == '2' ) ||
242: ( ( status_major == '3' ) && ( ftp->state == FTP_USER ) ) ) ){
243: /* Flag protocol error and close connections */
244: ftp_done ( ftp, -EPROTO );
245: return;
246: }
247:
248: /* Open passive connection when we get "PASV" response */
249: if ( ftp->state == FTP_PASV ) {
250: char *ptr = ftp->passive_text;
251: union {
252: struct sockaddr_in sin;
253: struct sockaddr sa;
254: } sa;
255: int rc;
256:
257: sa.sin.sin_family = AF_INET;
258: ftp_parse_value ( &ptr, ( uint8_t * ) &sa.sin.sin_addr,
259: sizeof ( sa.sin.sin_addr ) );
260: ftp_parse_value ( &ptr, ( uint8_t * ) &sa.sin.sin_port,
261: sizeof ( sa.sin.sin_port ) );
262: if ( ( rc = xfer_open_socket ( &ftp->data, SOCK_STREAM,
263: &sa.sa, NULL ) ) != 0 ) {
264: DBGC ( ftp, "FTP %p could not open data connection\n",
265: ftp );
266: ftp_done ( ftp, rc );
267: return;
268: }
269: }
270:
271: /* Move to next state and send control string */
272: ftp_next_state ( ftp );
273:
274: }
275:
276: /**
277: * Handle new data arriving on FTP control channel
278: *
279: * @v ftp FTP request
280: * @v iob I/O buffer
281: * @v meta Data transfer metadata
282: * @ret rc Return status code
283: *
284: * Data is collected until a complete line is received, at which point
285: * its information is passed to ftp_reply().
286: */
287: static int ftp_control_deliver ( struct ftp_request *ftp,
288: struct io_buffer *iobuf,
289: struct xfer_metadata *meta __unused ) {
290: char *data = iobuf->data;
291: size_t len = iob_len ( iobuf );
292: char *recvbuf = ftp->recvbuf;
293: size_t recvsize = ftp->recvsize;
294: char c;
295:
296: while ( len-- ) {
297: c = *(data++);
298: switch ( c ) {
299: case '\r' :
300: case '\n' :
301: /* End of line: call ftp_reply() to handle
302: * completed reply. Avoid calling ftp_reply()
303: * twice if we receive both \r and \n.
304: */
305: if ( recvsize == 0 )
306: ftp_reply ( ftp );
307: /* Start filling up the status code buffer */
308: recvbuf = ftp->status_text;
309: recvsize = sizeof ( ftp->status_text ) - 1;
310: break;
311: case '(' :
312: /* Start filling up the passive parameter buffer */
313: recvbuf = ftp->passive_text;
314: recvsize = sizeof ( ftp->passive_text ) - 1;
315: break;
316: case ')' :
317: /* Stop filling the passive parameter buffer */
318: recvsize = 0;
319: break;
320: default :
321: /* Fill up buffer if applicable */
322: if ( recvsize > 0 ) {
323: *(recvbuf++) = c;
324: recvsize--;
325: }
326: break;
327: }
328: }
329:
330: /* Store for next invocation */
331: ftp->recvbuf = recvbuf;
332: ftp->recvsize = recvsize;
333:
334: /* Free I/O buffer */
335: free_iob ( iobuf );
336:
337: return 0;
338: }
339:
340: /** FTP control channel interface operations */
341: static struct interface_operation ftp_control_operations[] = {
342: INTF_OP ( xfer_deliver, struct ftp_request *, ftp_control_deliver ),
343: INTF_OP ( intf_close, struct ftp_request *, ftp_done ),
344: };
345:
346: /** FTP control channel interface descriptor */
347: static struct interface_descriptor ftp_control_desc =
348: INTF_DESC ( struct ftp_request, control, ftp_control_operations );
349:
350: /*****************************************************************************
351: *
352: * FTP data channel
353: *
354: */
355:
356: /**
357: * Handle FTP data channel being closed
358: *
359: * @v ftp FTP request
360: * @v rc Reason for closure
361: *
362: * When the data channel is closed, the control channel should be left
363: * alone; the server will send a completion message via the control
364: * channel which we'll pick up.
365: *
366: * If the data channel is closed due to an error, we abort the request.
367: */
368: static void ftp_data_closed ( struct ftp_request *ftp, int rc ) {
369:
370: DBGC ( ftp, "FTP %p data connection closed: %s\n",
371: ftp, strerror ( rc ) );
372:
373: /* If there was an error, close control channel and record status */
374: if ( rc ) {
375: ftp_done ( ftp, rc );
376: } else {
377: ftp_next_state ( ftp );
378: }
379: }
380:
381: /**
382: * Handle data delivery via FTP data channel
383: *
384: * @v ftp FTP request
385: * @v iobuf I/O buffer
386: * @v meta Data transfer metadata
387: * @ret rc Return status code
388: */
389: static int ftp_data_deliver ( struct ftp_request *ftp,
390: struct io_buffer *iobuf,
391: struct xfer_metadata *meta __unused ) {
392: int rc;
393:
394: if ( ( rc = xfer_deliver_iob ( &ftp->xfer, iobuf ) ) != 0 ) {
395: DBGC ( ftp, "FTP %p failed to deliver data: %s\n",
396: ftp, strerror ( rc ) );
397: return rc;
398: }
399:
400: return 0;
401: }
402:
403: /** FTP data channel interface operations */
404: static struct interface_operation ftp_data_operations[] = {
405: INTF_OP ( xfer_deliver, struct ftp_request *, ftp_data_deliver ),
406: INTF_OP ( intf_close, struct ftp_request *, ftp_data_closed ),
407: };
408:
409: /** FTP data channel interface descriptor */
410: static struct interface_descriptor ftp_data_desc =
411: INTF_DESC ( struct ftp_request, data, ftp_data_operations );
412:
413: /*****************************************************************************
414: *
415: * Data transfer interface
416: *
417: */
418:
419: /** FTP data transfer interface operations */
420: static struct interface_operation ftp_xfer_operations[] = {
421: INTF_OP ( intf_close, struct ftp_request *, ftp_done ),
422: };
423:
424: /** FTP data transfer interface descriptor */
425: static struct interface_descriptor ftp_xfer_desc =
426: INTF_DESC ( struct ftp_request, xfer, ftp_xfer_operations );
427:
428: /*****************************************************************************
429: *
430: * URI opener
431: *
432: */
433:
434: /**
435: * Initiate an FTP connection
436: *
437: * @v xfer Data transfer interface
438: * @v uri Uniform Resource Identifier
439: * @ret rc Return status code
440: */
441: static int ftp_open ( struct interface *xfer, struct uri *uri ) {
442: struct ftp_request *ftp;
443: struct sockaddr_tcpip server;
444: int rc;
445:
446: /* Sanity checks */
447: if ( ! uri->path )
448: return -EINVAL;
449: if ( ! uri->host )
450: return -EINVAL;
451:
452: /* Allocate and populate structure */
453: ftp = zalloc ( sizeof ( *ftp ) );
454: if ( ! ftp )
455: return -ENOMEM;
456: ref_init ( &ftp->refcnt, ftp_free );
457: intf_init ( &ftp->xfer, &ftp_xfer_desc, &ftp->refcnt );
458: intf_init ( &ftp->control, &ftp_control_desc, &ftp->refcnt );
459: intf_init ( &ftp->data, &ftp_data_desc, &ftp->refcnt );
460: ftp->uri = uri_get ( uri );
461: ftp->recvbuf = ftp->status_text;
462: ftp->recvsize = sizeof ( ftp->status_text ) - 1;
463:
464: DBGC ( ftp, "FTP %p fetching %s\n", ftp, ftp->uri->path );
465:
466: /* Open control connection */
467: memset ( &server, 0, sizeof ( server ) );
468: server.st_port = htons ( uri_port ( uri, FTP_PORT ) );
469: if ( ( rc = xfer_open_named_socket ( &ftp->control, SOCK_STREAM,
470: ( struct sockaddr * ) &server,
471: uri->host, NULL ) ) != 0 )
472: goto err;
473:
474: /* Attach to parent interface, mortalise self, and return */
475: intf_plug_plug ( &ftp->xfer, xfer );
476: ref_put ( &ftp->refcnt );
477: return 0;
478:
479: err:
480: DBGC ( ftp, "FTP %p could not create request: %s\n",
481: ftp, strerror ( rc ) );
482: ftp_done ( ftp, rc );
483: ref_put ( &ftp->refcnt );
484: return rc;
485: }
486:
487: /** FTP URI opener */
488: struct uri_opener ftp_uri_opener __uri_opener = {
489: .scheme = "ftp",
490: .open = ftp_open,
491: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.