You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ftp.c 12KB

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