00001 #include <stdint.h>
00002 #include <stdlib.h>
00003 #include <stdio.h>
00004 #include <string.h>
00005 #include <assert.h>
00006 #include <errno.h>
00007 #include <byteswap.h>
00008 #include <gpxe/socket.h>
00009 #include <gpxe/tcpip.h>
00010 #include <gpxe/in.h>
00011 #include <gpxe/xfer.h>
00012 #include <gpxe/open.h>
00013 #include <gpxe/uri.h>
00014 #include <gpxe/features.h>
00015 #include <gpxe/ftp.h>
00016
00017
00018
00019
00020
00021
00022
00023 FEATURE ( FEATURE_PROTOCOL, "FTP", DHCP_EB_FEATURE_FTP, 1 );
00024
00025
00026
00027
00028
00029
00030
00031 enum ftp_state {
00032 FTP_CONNECT = 0,
00033 FTP_USER,
00034 FTP_PASS,
00035 FTP_TYPE,
00036 FTP_PASV,
00037 FTP_RETR,
00038 FTP_WAIT,
00039 FTP_QUIT,
00040 FTP_DONE,
00041 };
00042
00043
00044
00045
00046
00047 struct ftp_request {
00048
00049 struct refcnt refcnt;
00050
00051 struct xfer_interface xfer;
00052
00053
00054 struct uri *uri;
00055
00056 struct xfer_interface control;
00057
00058 struct xfer_interface data;
00059
00060
00061 enum ftp_state state;
00062
00063 char *recvbuf;
00064
00065 size_t recvsize;
00066
00067 char status_text[5];
00068
00069 char passive_text[24];
00070 };
00071
00072
00073
00074
00075
00076
00077 static void ftp_free ( struct refcnt *refcnt ) {
00078 struct ftp_request *ftp =
00079 container_of ( refcnt, struct ftp_request, refcnt );
00080
00081 DBGC ( ftp, "FTP %p freed\n", ftp );
00082
00083 uri_put ( ftp->uri );
00084 free ( ftp );
00085 }
00086
00087
00088
00089
00090
00091
00092
00093 static void ftp_done ( struct ftp_request *ftp, int rc ) {
00094
00095 DBGC ( ftp, "FTP %p completed (%s)\n", ftp, strerror ( rc ) );
00096
00097
00098 xfer_nullify ( &ftp->xfer );
00099 xfer_close ( &ftp->xfer, rc );
00100 xfer_nullify ( &ftp->control );
00101 xfer_close ( &ftp->control, rc );
00102 xfer_nullify ( &ftp->data );
00103 xfer_close ( &ftp->data, rc );
00104 }
00105
00106
00107
00108
00109
00110
00111
00112
00113 struct ftp_control_string {
00114
00115 const char *literal;
00116
00117
00118
00119
00120
00121 const char * ( *variable ) ( struct ftp_request *ftp );
00122 };
00123
00124
00125
00126
00127
00128
00129
00130 static const char * ftp_uri_path ( struct ftp_request *ftp ) {
00131 return ftp->uri->path;
00132 }
00133
00134
00135
00136
00137
00138
00139
00140 static const char * ftp_user ( struct ftp_request *ftp ) {
00141 static char *ftp_default_user = "anonymous";
00142 return ftp->uri->user ? ftp->uri->user : ftp_default_user;
00143 }
00144
00145
00146
00147
00148
00149
00150
00151 static const char * ftp_password ( struct ftp_request *ftp ) {
00152 static char *ftp_default_password = "etherboot@etherboot.org";
00153 return ftp->uri->password ? ftp->uri->password : ftp_default_password;
00154 }
00155
00156
00157 static struct ftp_control_string ftp_strings[] = {
00158 [FTP_CONNECT] = { NULL, NULL },
00159 [FTP_USER] = { "USER ", ftp_user },
00160 [FTP_PASS] = { "PASS ", ftp_password },
00161 [FTP_TYPE] = { "TYPE I", NULL },
00162 [FTP_PASV] = { "PASV", NULL },
00163 [FTP_RETR] = { "RETR ", ftp_uri_path },
00164 [FTP_WAIT] = { NULL, NULL },
00165 [FTP_QUIT] = { "QUIT", NULL },
00166 [FTP_DONE] = { NULL, NULL },
00167 };
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178 static void ftp_control_close ( struct xfer_interface *control, int rc ) {
00179 struct ftp_request *ftp =
00180 container_of ( control, struct ftp_request, control );
00181
00182 DBGC ( ftp, "FTP %p control connection closed: %s\n",
00183 ftp, strerror ( rc ) );
00184
00185
00186 ftp_done ( ftp, rc );
00187 }
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204 static void ftp_parse_value ( char **text, uint8_t *value, size_t len ) {
00205 do {
00206 *(value++) = strtoul ( *text, text, 10 );
00207 if ( **text )
00208 (*text)++;
00209 } while ( --len );
00210 }
00211
00212
00213
00214
00215
00216
00217
00218 static void ftp_next_state ( struct ftp_request *ftp ) {
00219 struct ftp_control_string *ftp_string;
00220 const char *literal;
00221 const char *variable;
00222
00223
00224 if ( ftp->state < FTP_DONE )
00225 ftp->state++;
00226
00227
00228 ftp_string = &ftp_strings[ftp->state];
00229 literal = ftp_string->literal;
00230 variable = ( ftp_string->variable ?
00231 ftp_string->variable ( ftp ) : "" );
00232 if ( literal ) {
00233 DBGC ( ftp, "FTP %p sending %s%s\n", ftp, literal, variable );
00234 xfer_printf ( &ftp->control, "%s%s\r\n", literal, variable );
00235 }
00236 }
00237
00238
00239
00240
00241
00242
00243
00244
00245 static void ftp_reply ( struct ftp_request *ftp ) {
00246 char status_major = ftp->status_text[0];
00247 char separator = ftp->status_text[3];
00248
00249 DBGC ( ftp, "FTP %p received status %s\n", ftp, ftp->status_text );
00250
00251
00252 if ( separator != ' ' )
00253 return;
00254
00255
00256 if ( status_major == '1' )
00257 return;
00258
00259
00260
00261
00262
00263 if ( ! ( ( status_major == '2' ) ||
00264 ( ( status_major == '3' ) && ( ftp->state == FTP_USER ) ) ) ){
00265
00266 ftp_done ( ftp, -EPROTO );
00267 return;
00268 }
00269
00270
00271 if ( ftp->state == FTP_PASV ) {
00272 char *ptr = ftp->passive_text;
00273 union {
00274 struct sockaddr_in sin;
00275 struct sockaddr sa;
00276 } sa;
00277 int rc;
00278
00279 sa.sin.sin_family = AF_INET;
00280 ftp_parse_value ( &ptr, ( uint8_t * ) &sa.sin.sin_addr,
00281 sizeof ( sa.sin.sin_addr ) );
00282 ftp_parse_value ( &ptr, ( uint8_t * ) &sa.sin.sin_port,
00283 sizeof ( sa.sin.sin_port ) );
00284 if ( ( rc = xfer_open_socket ( &ftp->data, SOCK_STREAM,
00285 &sa.sa, NULL ) ) != 0 ) {
00286 DBGC ( ftp, "FTP %p could not open data connection\n",
00287 ftp );
00288 ftp_done ( ftp, rc );
00289 return;
00290 }
00291 }
00292
00293
00294 ftp_next_state ( ftp );
00295
00296 }
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308 static int ftp_control_deliver_raw ( struct xfer_interface *control,
00309 const void *data, size_t len ) {
00310 struct ftp_request *ftp =
00311 container_of ( control, struct ftp_request, control );
00312 char *recvbuf = ftp->recvbuf;
00313 size_t recvsize = ftp->recvsize;
00314 char c;
00315
00316 while ( len-- ) {
00317 c = * ( ( char * ) data++ );
00318 switch ( c ) {
00319 case '\r' :
00320 case '\n' :
00321
00322
00323
00324
00325 if ( recvsize == 0 )
00326 ftp_reply ( ftp );
00327
00328 recvbuf = ftp->status_text;
00329 recvsize = sizeof ( ftp->status_text ) - 1;
00330 break;
00331 case '(' :
00332
00333 recvbuf = ftp->passive_text;
00334 recvsize = sizeof ( ftp->passive_text ) - 1;
00335 break;
00336 case ')' :
00337
00338 recvsize = 0;
00339 break;
00340 default :
00341
00342 if ( recvsize > 0 ) {
00343 *(recvbuf++) = c;
00344 recvsize--;
00345 }
00346 break;
00347 }
00348 }
00349
00350
00351 ftp->recvbuf = recvbuf;
00352 ftp->recvsize = recvsize;
00353
00354 return 0;
00355 }
00356
00357
00358 static struct xfer_interface_operations ftp_control_operations = {
00359 .close = ftp_control_close,
00360 .vredirect = xfer_vreopen,
00361 .window = unlimited_xfer_window,
00362 .alloc_iob = default_xfer_alloc_iob,
00363 .deliver_iob = xfer_deliver_as_raw,
00364 .deliver_raw = ftp_control_deliver_raw,
00365 };
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385 static void ftp_data_closed ( struct xfer_interface *data, int rc ) {
00386 struct ftp_request *ftp =
00387 container_of ( data, struct ftp_request, data );
00388
00389 DBGC ( ftp, "FTP %p data connection closed: %s\n",
00390 ftp, strerror ( rc ) );
00391
00392
00393 if ( rc ) {
00394 ftp_done ( ftp, rc );
00395 } else {
00396 ftp_next_state ( ftp );
00397 }
00398 }
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408 static int ftp_data_deliver_iob ( struct xfer_interface *data,
00409 struct io_buffer *iobuf,
00410 struct xfer_metadata *meta __unused ) {
00411 struct ftp_request *ftp =
00412 container_of ( data, struct ftp_request, data );
00413 int rc;
00414
00415 if ( ( rc = xfer_deliver_iob ( &ftp->xfer, iobuf ) ) != 0 ) {
00416 DBGC ( ftp, "FTP %p failed to deliver data: %s\n",
00417 ftp, strerror ( rc ) );
00418 return rc;
00419 }
00420
00421 return 0;
00422 }
00423
00424
00425 static struct xfer_interface_operations ftp_data_operations = {
00426 .close = ftp_data_closed,
00427 .vredirect = xfer_vreopen,
00428 .window = unlimited_xfer_window,
00429 .alloc_iob = default_xfer_alloc_iob,
00430 .deliver_iob = ftp_data_deliver_iob,
00431 .deliver_raw = xfer_deliver_as_iob,
00432 };
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446 static void ftp_xfer_closed ( struct xfer_interface *xfer, int rc ) {
00447 struct ftp_request *ftp =
00448 container_of ( xfer, struct ftp_request, xfer );
00449
00450 DBGC ( ftp, "FTP %p data transfer interface closed: %s\n",
00451 ftp, strerror ( rc ) );
00452
00453 ftp_done ( ftp, rc );
00454 }
00455
00456
00457 static struct xfer_interface_operations ftp_xfer_operations = {
00458 .close = ftp_xfer_closed,
00459 .vredirect = ignore_xfer_vredirect,
00460 .window = unlimited_xfer_window,
00461 .alloc_iob = default_xfer_alloc_iob,
00462 .deliver_iob = xfer_deliver_as_raw,
00463 .deliver_raw = ignore_xfer_deliver_raw,
00464 };
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479 static int ftp_open ( struct xfer_interface *xfer, struct uri *uri ) {
00480 struct ftp_request *ftp;
00481 struct sockaddr_tcpip server;
00482 int rc;
00483
00484
00485 if ( ! uri->path )
00486 return -EINVAL;
00487 if ( ! uri->host )
00488 return -EINVAL;
00489
00490
00491 ftp = zalloc ( sizeof ( *ftp ) );
00492 if ( ! ftp )
00493 return -ENOMEM;
00494 ftp->refcnt.free = ftp_free;
00495 xfer_init ( &ftp->xfer, &ftp_xfer_operations, &ftp->refcnt );
00496 ftp->uri = uri_get ( uri );
00497 xfer_init ( &ftp->control, &ftp_control_operations, &ftp->refcnt );
00498 xfer_init ( &ftp->data, &ftp_data_operations, &ftp->refcnt );
00499 ftp->recvbuf = ftp->status_text;
00500 ftp->recvsize = sizeof ( ftp->status_text ) - 1;
00501
00502 DBGC ( ftp, "FTP %p fetching %s\n", ftp, ftp->uri->path );
00503
00504
00505 memset ( &server, 0, sizeof ( server ) );
00506 server.st_port = htons ( uri_port ( uri, FTP_PORT ) );
00507 if ( ( rc = xfer_open_named_socket ( &ftp->control, SOCK_STREAM,
00508 ( struct sockaddr * ) &server,
00509 uri->host, NULL ) ) != 0 )
00510 goto err;
00511
00512
00513 xfer_plug_plug ( &ftp->xfer, xfer );
00514 ref_put ( &ftp->refcnt );
00515 return 0;
00516
00517 err:
00518 DBGC ( ftp, "FTP %p could not create request: %s\n",
00519 ftp, strerror ( rc ) );
00520 ftp_done ( ftp, rc );
00521 ref_put ( &ftp->refcnt );
00522 return rc;
00523 }
00524
00525
00526 struct uri_opener ftp_uri_opener __uri_opener = {
00527 .scheme = "ftp",
00528 .open = ftp_open,
00529 };