Annotation of qemu/roms/ipxe/src/net/tcp/ftp.c, revision 1.1.1.1

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: };

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.