diff options
Diffstat (limited to 'contrib/syslinux/syslinux-4.03/gpxe/src/net/tcp/ftp.c')
-rw-r--r-- | contrib/syslinux/syslinux-4.03/gpxe/src/net/tcp/ftp.c | 529 |
1 files changed, 0 insertions, 529 deletions
diff --git a/contrib/syslinux/syslinux-4.03/gpxe/src/net/tcp/ftp.c b/contrib/syslinux/syslinux-4.03/gpxe/src/net/tcp/ftp.c deleted file mode 100644 index 920e537..0000000 --- a/contrib/syslinux/syslinux-4.03/gpxe/src/net/tcp/ftp.c +++ /dev/null @@ -1,529 +0,0 @@ -#include <stdint.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <assert.h> -#include <errno.h> -#include <byteswap.h> -#include <gpxe/socket.h> -#include <gpxe/tcpip.h> -#include <gpxe/in.h> -#include <gpxe/xfer.h> -#include <gpxe/open.h> -#include <gpxe/uri.h> -#include <gpxe/features.h> -#include <gpxe/ftp.h> - -/** @file - * - * File transfer protocol - * - */ - -FEATURE ( FEATURE_PROTOCOL, "FTP", DHCP_EB_FEATURE_FTP, 1 ); - -/** - * FTP states - * - * These @b must be sequential, i.e. a successful FTP session must - * pass through each of these states in order. - */ -enum ftp_state { - FTP_CONNECT = 0, - FTP_USER, - FTP_PASS, - FTP_TYPE, - FTP_PASV, - FTP_RETR, - FTP_WAIT, - FTP_QUIT, - FTP_DONE, -}; - -/** - * An FTP request - * - */ -struct ftp_request { - /** Reference counter */ - struct refcnt refcnt; - /** Data transfer interface */ - struct xfer_interface xfer; - - /** URI being fetched */ - struct uri *uri; - /** FTP control channel interface */ - struct xfer_interface control; - /** FTP data channel interface */ - struct xfer_interface data; - - /** Current state */ - enum ftp_state state; - /** Buffer to be filled with data received via the control channel */ - char *recvbuf; - /** Remaining size of recvbuf */ - size_t recvsize; - /** FTP status code, as text */ - char status_text[5]; - /** Passive-mode parameters, as text */ - char passive_text[24]; /* "aaa,bbb,ccc,ddd,eee,fff" */ -}; - -/** - * Free FTP request - * - * @v refcnt Reference counter - */ -static void ftp_free ( struct refcnt *refcnt ) { - struct ftp_request *ftp = - container_of ( refcnt, struct ftp_request, refcnt ); - - DBGC ( ftp, "FTP %p freed\n", ftp ); - - uri_put ( ftp->uri ); - free ( ftp ); -} - -/** - * Mark FTP operation as complete - * - * @v ftp FTP request - * @v rc Return status code - */ -static void ftp_done ( struct ftp_request *ftp, int rc ) { - - DBGC ( ftp, "FTP %p completed (%s)\n", ftp, strerror ( rc ) ); - - /* Close all data transfer interfaces */ - xfer_nullify ( &ftp->xfer ); - xfer_close ( &ftp->xfer, rc ); - xfer_nullify ( &ftp->control ); - xfer_close ( &ftp->control, rc ); - xfer_nullify ( &ftp->data ); - xfer_close ( &ftp->data, rc ); -} - -/***************************************************************************** - * - * FTP control channel - * - */ - -/** An FTP control channel string */ -struct ftp_control_string { - /** Literal portion */ - const char *literal; - /** Variable portion - * - * @v ftp FTP request - * @ret string Variable portion of string - */ - const char * ( *variable ) ( struct ftp_request *ftp ); -}; - -/** - * Retrieve FTP pathname - * - * @v ftp FTP request - * @ret path FTP pathname - */ -static const char * ftp_uri_path ( struct ftp_request *ftp ) { - return ftp->uri->path; -} - -/** - * Retrieve FTP user - * - * @v ftp FTP request - * @ret user FTP user - */ -static const char * ftp_user ( struct ftp_request *ftp ) { - static char *ftp_default_user = "anonymous"; - return ftp->uri->user ? ftp->uri->user : ftp_default_user; -} - -/** - * Retrieve FTP password - * - * @v ftp FTP request - * @ret password FTP password - */ -static const char * ftp_password ( struct ftp_request *ftp ) { - static char *ftp_default_password = "etherboot@etherboot.org"; - return ftp->uri->password ? ftp->uri->password : ftp_default_password; -} - -/** FTP control channel strings */ -static struct ftp_control_string ftp_strings[] = { - [FTP_CONNECT] = { NULL, NULL }, - [FTP_USER] = { "USER ", ftp_user }, - [FTP_PASS] = { "PASS ", ftp_password }, - [FTP_TYPE] = { "TYPE I", NULL }, - [FTP_PASV] = { "PASV", NULL }, - [FTP_RETR] = { "RETR ", ftp_uri_path }, - [FTP_WAIT] = { NULL, NULL }, - [FTP_QUIT] = { "QUIT", NULL }, - [FTP_DONE] = { NULL, NULL }, -}; - -/** - * Handle control channel being closed - * - * @v control FTP control channel interface - * @v rc Reason for close - * - * When the control channel is closed, the data channel must also be - * closed, if it is currently open. - */ -static void ftp_control_close ( struct xfer_interface *control, int rc ) { - struct ftp_request *ftp = - container_of ( control, struct ftp_request, control ); - - DBGC ( ftp, "FTP %p control connection closed: %s\n", - ftp, strerror ( rc ) ); - - /* Complete FTP operation */ - ftp_done ( ftp, rc ); -} - -/** - * Parse FTP byte sequence value - * - * @v text Text string - * @v value Value buffer - * @v len Length of value buffer - * - * This parses an FTP byte sequence value (e.g. the "aaa,bbb,ccc,ddd" - * form for IP addresses in PORT commands) into a byte sequence. @c - * *text will be updated to point beyond the end of the parsed byte - * sequence. - * - * This function is safe in the presence of malformed data, though the - * output is undefined. - */ -static void ftp_parse_value ( char **text, uint8_t *value, size_t len ) { - do { - *(value++) = strtoul ( *text, text, 10 ); - if ( **text ) - (*text)++; - } while ( --len ); -} - -/** - * Move to next state and send the appropriate FTP control string - * - * @v ftp FTP request - * - */ -static void ftp_next_state ( struct ftp_request *ftp ) { - struct ftp_control_string *ftp_string; - const char *literal; - const char *variable; - - /* Move to next state */ - if ( ftp->state < FTP_DONE ) - ftp->state++; - - /* Send control string if needed */ - ftp_string = &ftp_strings[ftp->state]; - literal = ftp_string->literal; - variable = ( ftp_string->variable ? - ftp_string->variable ( ftp ) : "" ); - if ( literal ) { - DBGC ( ftp, "FTP %p sending %s%s\n", ftp, literal, variable ); - xfer_printf ( &ftp->control, "%s%s\r\n", literal, variable ); - } -} - -/** - * Handle an FTP control channel response - * - * @v ftp FTP request - * - * This is called once we have received a complete response line. - */ -static void ftp_reply ( struct ftp_request *ftp ) { - char status_major = ftp->status_text[0]; - char separator = ftp->status_text[3]; - - DBGC ( ftp, "FTP %p received status %s\n", ftp, ftp->status_text ); - - /* Ignore malformed lines */ - if ( separator != ' ' ) - return; - - /* Ignore "intermediate" responses (1xx codes) */ - if ( status_major == '1' ) - return; - - /* Anything other than success (2xx) or, in the case of a - * repsonse to a "USER" command, a password prompt (3xx), is a - * fatal error. - */ - if ( ! ( ( status_major == '2' ) || - ( ( status_major == '3' ) && ( ftp->state == FTP_USER ) ) ) ){ - /* Flag protocol error and close connections */ - ftp_done ( ftp, -EPROTO ); - return; - } - - /* Open passive connection when we get "PASV" response */ - if ( ftp->state == FTP_PASV ) { - char *ptr = ftp->passive_text; - union { - struct sockaddr_in sin; - struct sockaddr sa; - } sa; - int rc; - - sa.sin.sin_family = AF_INET; - ftp_parse_value ( &ptr, ( uint8_t * ) &sa.sin.sin_addr, - sizeof ( sa.sin.sin_addr ) ); - ftp_parse_value ( &ptr, ( uint8_t * ) &sa.sin.sin_port, - sizeof ( sa.sin.sin_port ) ); - if ( ( rc = xfer_open_socket ( &ftp->data, SOCK_STREAM, - &sa.sa, NULL ) ) != 0 ) { - DBGC ( ftp, "FTP %p could not open data connection\n", - ftp ); - ftp_done ( ftp, rc ); - return; - } - } - - /* Move to next state and send control string */ - ftp_next_state ( ftp ); - -} - -/** - * Handle new data arriving on FTP control channel - * - * @v control FTP control channel interface - * @v data New data - * @v len Length of new data - * - * Data is collected until a complete line is received, at which point - * its information is passed to ftp_reply(). - */ -static int ftp_control_deliver_raw ( struct xfer_interface *control, - const void *data, size_t len ) { - struct ftp_request *ftp = - container_of ( control, struct ftp_request, control ); - char *recvbuf = ftp->recvbuf; - size_t recvsize = ftp->recvsize; - char c; - - while ( len-- ) { - c = * ( ( char * ) data++ ); - switch ( c ) { - case '\r' : - case '\n' : - /* End of line: call ftp_reply() to handle - * completed reply. Avoid calling ftp_reply() - * twice if we receive both \r and \n. - */ - if ( recvsize == 0 ) - ftp_reply ( ftp ); - /* Start filling up the status code buffer */ - recvbuf = ftp->status_text; - recvsize = sizeof ( ftp->status_text ) - 1; - break; - case '(' : - /* Start filling up the passive parameter buffer */ - recvbuf = ftp->passive_text; - recvsize = sizeof ( ftp->passive_text ) - 1; - break; - case ')' : - /* Stop filling the passive parameter buffer */ - recvsize = 0; - break; - default : - /* Fill up buffer if applicable */ - if ( recvsize > 0 ) { - *(recvbuf++) = c; - recvsize--; - } - break; - } - } - - /* Store for next invocation */ - ftp->recvbuf = recvbuf; - ftp->recvsize = recvsize; - - return 0; -} - -/** FTP control channel operations */ -static struct xfer_interface_operations ftp_control_operations = { - .close = ftp_control_close, - .vredirect = xfer_vreopen, - .window = unlimited_xfer_window, - .alloc_iob = default_xfer_alloc_iob, - .deliver_iob = xfer_deliver_as_raw, - .deliver_raw = ftp_control_deliver_raw, -}; - -/***************************************************************************** - * - * FTP data channel - * - */ - -/** - * Handle FTP data channel being closed - * - * @v data FTP data channel interface - * @v rc Reason for closure - * - * When the data channel is closed, the control channel should be left - * alone; the server will send a completion message via the control - * channel which we'll pick up. - * - * If the data channel is closed due to an error, we abort the request. - */ -static void ftp_data_closed ( struct xfer_interface *data, int rc ) { - struct ftp_request *ftp = - container_of ( data, struct ftp_request, data ); - - DBGC ( ftp, "FTP %p data connection closed: %s\n", - ftp, strerror ( rc ) ); - - /* If there was an error, close control channel and record status */ - if ( rc ) { - ftp_done ( ftp, rc ); - } else { - ftp_next_state ( ftp ); - } -} - -/** - * Handle data delivery via FTP data channel - * - * @v xfer FTP data channel interface - * @v iobuf I/O buffer - * @v meta Data transfer metadata - * @ret rc Return status code - */ -static int ftp_data_deliver_iob ( struct xfer_interface *data, - struct io_buffer *iobuf, - struct xfer_metadata *meta __unused ) { - struct ftp_request *ftp = - container_of ( data, struct ftp_request, data ); - int rc; - - if ( ( rc = xfer_deliver_iob ( &ftp->xfer, iobuf ) ) != 0 ) { - DBGC ( ftp, "FTP %p failed to deliver data: %s\n", - ftp, strerror ( rc ) ); - return rc; - } - - return 0; -} - -/** FTP data channel operations */ -static struct xfer_interface_operations ftp_data_operations = { - .close = ftp_data_closed, - .vredirect = xfer_vreopen, - .window = unlimited_xfer_window, - .alloc_iob = default_xfer_alloc_iob, - .deliver_iob = ftp_data_deliver_iob, - .deliver_raw = xfer_deliver_as_iob, -}; - -/***************************************************************************** - * - * Data transfer interface - * - */ - -/** - * Close FTP data transfer interface - * - * @v xfer FTP data transfer interface - * @v rc Reason for close - */ -static void ftp_xfer_closed ( struct xfer_interface *xfer, int rc ) { - struct ftp_request *ftp = - container_of ( xfer, struct ftp_request, xfer ); - - DBGC ( ftp, "FTP %p data transfer interface closed: %s\n", - ftp, strerror ( rc ) ); - - ftp_done ( ftp, rc ); -} - -/** FTP data transfer interface operations */ -static struct xfer_interface_operations ftp_xfer_operations = { - .close = ftp_xfer_closed, - .vredirect = ignore_xfer_vredirect, - .window = unlimited_xfer_window, - .alloc_iob = default_xfer_alloc_iob, - .deliver_iob = xfer_deliver_as_raw, - .deliver_raw = ignore_xfer_deliver_raw, -}; - -/***************************************************************************** - * - * URI opener - * - */ - -/** - * Initiate an FTP connection - * - * @v xfer Data transfer interface - * @v uri Uniform Resource Identifier - * @ret rc Return status code - */ -static int ftp_open ( struct xfer_interface *xfer, struct uri *uri ) { - struct ftp_request *ftp; - struct sockaddr_tcpip server; - int rc; - - /* Sanity checks */ - if ( ! uri->path ) - return -EINVAL; - if ( ! uri->host ) - return -EINVAL; - - /* Allocate and populate structure */ - ftp = zalloc ( sizeof ( *ftp ) ); - if ( ! ftp ) - return -ENOMEM; - ftp->refcnt.free = ftp_free; - xfer_init ( &ftp->xfer, &ftp_xfer_operations, &ftp->refcnt ); - ftp->uri = uri_get ( uri ); - xfer_init ( &ftp->control, &ftp_control_operations, &ftp->refcnt ); - xfer_init ( &ftp->data, &ftp_data_operations, &ftp->refcnt ); - ftp->recvbuf = ftp->status_text; - ftp->recvsize = sizeof ( ftp->status_text ) - 1; - - DBGC ( ftp, "FTP %p fetching %s\n", ftp, ftp->uri->path ); - - /* Open control connection */ - memset ( &server, 0, sizeof ( server ) ); - server.st_port = htons ( uri_port ( uri, FTP_PORT ) ); - if ( ( rc = xfer_open_named_socket ( &ftp->control, SOCK_STREAM, - ( struct sockaddr * ) &server, - uri->host, NULL ) ) != 0 ) - goto err; - - /* Attach to parent interface, mortalise self, and return */ - xfer_plug_plug ( &ftp->xfer, xfer ); - ref_put ( &ftp->refcnt ); - return 0; - - err: - DBGC ( ftp, "FTP %p could not create request: %s\n", - ftp, strerror ( rc ) ); - ftp_done ( ftp, rc ); - ref_put ( &ftp->refcnt ); - return rc; -} - -/** FTP URI opener */ -struct uri_opener ftp_uri_opener __uri_opener = { - .scheme = "ftp", - .open = ftp_open, -}; |