| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: ftp.c,v 1.6 2013/10/19 22:58:40 mrg Exp $ */ | | 1 | /* $NetBSD: ftp.c,v 1.7 2014/01/07 02:13:00 joerg Exp $ */ |
2 | /*- | | 2 | /*- |
3 | * Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav | | 3 | * Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav |
4 | * Copyright (c) 2008, 2009, 2010 Joerg Sonnenberger <joerg@NetBSD.org> | | 4 | * Copyright (c) 2008, 2009, 2010 Joerg Sonnenberger <joerg@NetBSD.org> |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer | | 11 | * notice, this list of conditions and the following disclaimer |
12 | * in this position and unchanged. | | 12 | * in this position and unchanged. |
13 | * 2. Redistributions in binary form must reproduce the above copyright | | 13 | * 2. Redistributions in binary form must reproduce the above copyright |
14 | * notice, this list of conditions and the following disclaimer in the | | 14 | * notice, this list of conditions and the following disclaimer in the |
| @@ -188,26 +188,27 @@ ftp_chkerr(conn_t *conn) | | | @@ -188,26 +188,27 @@ ftp_chkerr(conn_t *conn) |
188 | return (-1); | | 188 | return (-1); |
189 | } | | 189 | } |
190 | | | 190 | |
191 | conn->err = (conn->buf[0] - '0') * 100 | | 191 | conn->err = (conn->buf[0] - '0') * 100 |
192 | + (conn->buf[1] - '0') * 10 | | 192 | + (conn->buf[1] - '0') * 10 |
193 | + (conn->buf[2] - '0'); | | 193 | + (conn->buf[2] - '0'); |
194 | | | 194 | |
195 | return (conn->err); | | 195 | return (conn->err); |
196 | } | | 196 | } |
197 | | | 197 | |
198 | /* | | 198 | /* |
199 | * Send a command and check reply | | 199 | * Send a command and check reply |
200 | */ | | 200 | */ |
| | | 201 | __printflike(2, 3) |
201 | static int | | 202 | static int |
202 | ftp_cmd(conn_t *conn, const char *fmt, ...) | | 203 | ftp_cmd(conn_t *conn, const char *fmt, ...) |
203 | { | | 204 | { |
204 | va_list ap; | | 205 | va_list ap; |
205 | size_t len; | | 206 | size_t len; |
206 | char *msg; | | 207 | char *msg; |
207 | ssize_t r; | | 208 | ssize_t r; |
208 | | | 209 | |
209 | va_start(ap, fmt); | | 210 | va_start(ap, fmt); |
210 | len = vasprintf(&msg, fmt, ap); | | 211 | len = vasprintf(&msg, fmt, ap); |
211 | va_end(ap); | | 212 | va_end(ap); |
212 | | | 213 | |
213 | if (msg == NULL) { | | 214 | if (msg == NULL) { |
| @@ -381,27 +382,27 @@ ftp_cwd(conn_t *conn, const char *path, | | | @@ -381,27 +382,27 @@ ftp_cwd(conn_t *conn, const char *path, |
381 | e = ftp_cmd(conn, "CWD %.*s\r\n", (int)(end - beg), beg); | | 382 | e = ftp_cmd(conn, "CWD %.*s\r\n", (int)(end - beg), beg); |
382 | if (e == FTP_FILE_ACTION_OK) { | | 383 | if (e == FTP_FILE_ACTION_OK) { |
383 | free(dst); | | 384 | free(dst); |
384 | return (0); | | 385 | return (0); |
385 | } | | 386 | } |
386 | #endif /* FTP_COMBINE_CWDS */ | | 387 | #endif /* FTP_COMBINE_CWDS */ |
387 | | | 388 | |
388 | /* That didn't work so go back to legacy behavior (multiple CWDs). */ | | 389 | /* That didn't work so go back to legacy behavior (multiple CWDs). */ |
389 | for (beg = dst + i; beg < end; beg = dst + i + 1) { | | 390 | for (beg = dst + i; beg < end; beg = dst + i + 1) { |
390 | while (*beg == '/') | | 391 | while (*beg == '/') |
391 | ++beg, ++i; | | 392 | ++beg, ++i; |
392 | for (++i; dst + i < end && dst[i] != '/'; ++i) | | 393 | for (++i; dst + i < end && dst[i] != '/'; ++i) |
393 | /* nothing */ ; | | 394 | /* nothing */ ; |
394 | e = ftp_cmd(conn, "CWD %.*s\r\n", dst + i - beg, beg); | | 395 | e = ftp_cmd(conn, "CWD %.*s\r\n", (int)(dst + i - beg), beg); |
395 | if (e != FTP_FILE_ACTION_OK) { | | 396 | if (e != FTP_FILE_ACTION_OK) { |
396 | free(dst); | | 397 | free(dst); |
397 | ftp_seterr(e); | | 398 | ftp_seterr(e); |
398 | return (-1); | | 399 | return (-1); |
399 | } | | 400 | } |
400 | } | | 401 | } |
401 | free(dst); | | 402 | free(dst); |
402 | return (0); | | 403 | return (0); |
403 | } | | 404 | } |
404 | | | 405 | |
405 | /* | | 406 | /* |
406 | * Set transfer mode and data type | | 407 | * Set transfer mode and data type |
407 | */ | | 408 | */ |
| @@ -479,44 +480,44 @@ ftp_stat(conn_t *conn, const char *file, | | | @@ -479,44 +480,44 @@ ftp_stat(conn_t *conn, const char *file, |
479 | time_t t; | | 480 | time_t t; |
480 | int e; | | 481 | int e; |
481 | | | 482 | |
482 | us->size = -1; | | 483 | us->size = -1; |
483 | us->atime = us->mtime = 0; | | 484 | us->atime = us->mtime = 0; |
484 | | | 485 | |
485 | filename = ftp_filename(file, &filenamelen, &type, 0); | | 486 | filename = ftp_filename(file, &filenamelen, &type, 0); |
486 | | | 487 | |
487 | if ((e = ftp_mode_type(conn, 0, type)) != FTP_OK) { | | 488 | if ((e = ftp_mode_type(conn, 0, type)) != FTP_OK) { |
488 | ftp_seterr(e); | | 489 | ftp_seterr(e); |
489 | return (-1); | | 490 | return (-1); |
490 | } | | 491 | } |
491 | | | 492 | |
492 | e = ftp_cmd(conn, "SIZE %.*s\r\n", filenamelen, filename); | | 493 | e = ftp_cmd(conn, "SIZE %.*s\r\n", (int)filenamelen, filename); |
493 | if (e != FTP_FILE_STATUS) { | | 494 | if (e != FTP_FILE_STATUS) { |
494 | ftp_seterr(e); | | 495 | ftp_seterr(e); |
495 | return (-1); | | 496 | return (-1); |
496 | } | | 497 | } |
497 | for (ln = conn->buf + 4; *ln && isspace((unsigned char)*ln); ln++) | | 498 | for (ln = conn->buf + 4; *ln && isspace((unsigned char)*ln); ln++) |
498 | /* nothing */ ; | | 499 | /* nothing */ ; |
499 | for (us->size = 0; *ln && isdigit((unsigned char)*ln); ln++) | | 500 | for (us->size = 0; *ln && isdigit((unsigned char)*ln); ln++) |
500 | us->size = us->size * 10 + *ln - '0'; | | 501 | us->size = us->size * 10 + *ln - '0'; |
501 | if (*ln && !isspace((unsigned char)*ln)) { | | 502 | if (*ln && !isspace((unsigned char)*ln)) { |
502 | ftp_seterr(FTP_PROTOCOL_ERROR); | | 503 | ftp_seterr(FTP_PROTOCOL_ERROR); |
503 | us->size = -1; | | 504 | us->size = -1; |
504 | return (-1); | | 505 | return (-1); |
505 | } | | 506 | } |
506 | if (us->size == 0) | | 507 | if (us->size == 0) |
507 | us->size = -1; | | 508 | us->size = -1; |
508 | | | 509 | |
509 | e = ftp_cmd(conn, "MDTM %.*s\r\n", filenamelen, filename); | | 510 | e = ftp_cmd(conn, "MDTM %.*s\r\n", (int)filenamelen, filename); |
510 | if (e != FTP_FILE_STATUS) { | | 511 | if (e != FTP_FILE_STATUS) { |
511 | ftp_seterr(e); | | 512 | ftp_seterr(e); |
512 | return (-1); | | 513 | return (-1); |
513 | } | | 514 | } |
514 | for (ln = conn->buf + 4; *ln && isspace((unsigned char)*ln); ln++) | | 515 | for (ln = conn->buf + 4; *ln && isspace((unsigned char)*ln); ln++) |
515 | /* nothing */ ; | | 516 | /* nothing */ ; |
516 | switch (strspn(ln, "0123456789")) { | | 517 | switch (strspn(ln, "0123456789")) { |
517 | case 14: | | 518 | case 14: |
518 | break; | | 519 | break; |
519 | case 15: | | 520 | case 15: |
520 | ln++; | | 521 | ln++; |
521 | ln[0] = '2'; | | 522 | ln[0] = '2'; |
522 | ln[1] = '0'; | | 523 | ln[1] = '0'; |
| @@ -841,27 +842,27 @@ retry_mode: | | | @@ -841,27 +842,27 @@ retry_mode: |
841 | if (bindaddr != NULL && *bindaddr != '\0' && | | 842 | if (bindaddr != NULL && *bindaddr != '\0' && |
842 | fetch_bind(sd, u.ss.ss_family, bindaddr) != 0) | | 843 | fetch_bind(sd, u.ss.ss_family, bindaddr) != 0) |
843 | goto sysouch; | | 844 | goto sysouch; |
844 | if (connect(sd, &u.sa, l) == -1) | | 845 | if (connect(sd, &u.sa, l) == -1) |
845 | goto sysouch; | | 846 | goto sysouch; |
846 | | | 847 | |
847 | /* make the server initiate the transfer */ | | 848 | /* make the server initiate the transfer */ |
848 | if (verbose) | | 849 | if (verbose) |
849 | fetch_info("initiating transfer"); | | 850 | fetch_info("initiating transfer"); |
850 | if (op_arg) | | 851 | if (op_arg) |
851 | e = ftp_cmd(conn, "%s%s%s\r\n", oper, *op_arg ? " " : "", op_arg); | | 852 | e = ftp_cmd(conn, "%s%s%s\r\n", oper, *op_arg ? " " : "", op_arg); |
852 | else | | 853 | else |
853 | e = ftp_cmd(conn, "%s %.*s\r\n", oper, | | 854 | e = ftp_cmd(conn, "%s %.*s\r\n", oper, |
854 | filenamelen, filename); | | 855 | (int)filenamelen, filename); |
855 | if (e != FTP_CONNECTION_ALREADY_OPEN && e != FTP_OPEN_DATA_CONNECTION) | | 856 | if (e != FTP_CONNECTION_ALREADY_OPEN && e != FTP_OPEN_DATA_CONNECTION) |
856 | goto ouch; | | 857 | goto ouch; |
857 | | | 858 | |
858 | } else { | | 859 | } else { |
859 | uint32_t a; | | 860 | uint32_t a; |
860 | uint16_t p; | | 861 | uint16_t p; |
861 | #if defined(IPV6_PORTRANGE) || defined(IP_PORTRANGE) | | 862 | #if defined(IPV6_PORTRANGE) || defined(IP_PORTRANGE) |
862 | int arg; | | 863 | int arg; |
863 | #endif | | 864 | #endif |
864 | int d; | | 865 | int d; |
865 | char hname[INET6_ADDRSTRLEN]; | | 866 | char hname[INET6_ADDRSTRLEN]; |
866 | | | 867 | |
867 | switch (u.ss.ss_family) { | | 868 | switch (u.ss.ss_family) { |
| @@ -938,27 +939,27 @@ retry_mode: | | | @@ -938,27 +939,27 @@ retry_mode: |
938 | | | 939 | |
939 | /* seek to required offset */ | | 940 | /* seek to required offset */ |
940 | if (offset) | | 941 | if (offset) |
941 | if (ftp_cmd(conn, "REST %llu\r\n", (unsigned long long)offset) != FTP_FILE_OK) | | 942 | if (ftp_cmd(conn, "REST %llu\r\n", (unsigned long long)offset) != FTP_FILE_OK) |
942 | goto sysouch; | | 943 | goto sysouch; |
943 | | | 944 | |
944 | /* make the server initiate the transfer */ | | 945 | /* make the server initiate the transfer */ |
945 | if (verbose) | | 946 | if (verbose) |
946 | fetch_info("initiating transfer"); | | 947 | fetch_info("initiating transfer"); |
947 | if (op_arg) | | 948 | if (op_arg) |
948 | e = ftp_cmd(conn, "%s%s%s\r\n", oper, *op_arg ? " " : "", op_arg); | | 949 | e = ftp_cmd(conn, "%s%s%s\r\n", oper, *op_arg ? " " : "", op_arg); |
949 | else | | 950 | else |
950 | e = ftp_cmd(conn, "%s %.*s\r\n", oper, | | 951 | e = ftp_cmd(conn, "%s %.*s\r\n", oper, |
951 | filenamelen, filename); | | 952 | (int)filenamelen, filename); |
952 | if (e != FTP_CONNECTION_ALREADY_OPEN && e != FTP_OPEN_DATA_CONNECTION) | | 953 | if (e != FTP_CONNECTION_ALREADY_OPEN && e != FTP_OPEN_DATA_CONNECTION) |
953 | goto ouch; | | 954 | goto ouch; |
954 | | | 955 | |
955 | /* accept the incoming connection and go to town */ | | 956 | /* accept the incoming connection and go to town */ |
956 | if ((d = accept(sd, NULL, NULL)) == -1) | | 957 | if ((d = accept(sd, NULL, NULL)) == -1) |
957 | goto sysouch; | | 958 | goto sysouch; |
958 | close(sd); | | 959 | close(sd); |
959 | sd = d; | | 960 | sd = d; |
960 | } | | 961 | } |
961 | | | 962 | |
962 | if ((df = ftp_setup(conn, fetch_reopen(sd), mode)) == NULL) | | 963 | if ((df = ftp_setup(conn, fetch_reopen(sd), mode)) == NULL) |
963 | goto sysouch; | | 964 | goto sysouch; |
964 | return (df); | | 965 | return (df); |