📄 ftp.c
字号:
/* * ftp.c - ftp code * * Erik Troan <ewt@redhat.com> * Matt Wilson <msw@redhat.com> * Jeremy Katz <katzj@redhat.com> * David Cantrell <dcantrell@redhat.com> * * Copyright 1997 - 2006 Red Hat, Inc. * * This software may be freely redistributed under the terms of the GNU * General Public License. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#define HAVE_ALLOCA_H 1#define HAVE_NETINET_IN_SYSTM_H 1#define HAVE_SYS_SOCKET_H 1#define USE_ALT_DNS 1#if HAVE_ALLOCA_H# include <alloca.h>#endif#if HAVE_SYS_SOCKET_H# include <sys/socket.h>#endif#if HAVE_NETINET_IN_SYSTM_H# include <sys/types.h># include <netinet/in_systm.h>#endif#if ! HAVE_HERRNOextern int h_errno;#endif#include <ctype.h>#include <errno.h>#include <fcntl.h>#include <netdb.h>#include <pwd.h>#include <stdarg.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/socket.h>#include <sys/time.h>#include <sys/types.h>#include <unistd.h>#include <netinet/in.h>#include <netinet/ip.h>#include <arpa/inet.h>#define TIMEOUT_SECS 60#define BUFFER_SIZE 4096#ifndef IPPORT_FTP# define IPPORT_FTP 21#endif#if defined(USE_ALT_DNS) && USE_ALT_DNS #include "../isys/dns.h"#endif#include "ftp.h"#include "log.h"#include "net.h"static int ftpCheckResponse(int sock, char ** str);static int ftpCommand(int sock, char * command, ...);static int getHostAddress(const char * host, void * address, int family);static int ftpCheckResponse(int sock, char ** str) { static char buf[BUFFER_SIZE + 1]; int bufLength = 0; fd_set emptySet, readSet; char * chptr, * start; struct timeval timeout; int bytesRead, rc = 0; int doesContinue = 1; char errorCode[4]; errorCode[0] = '\0'; do { FD_ZERO(&emptySet); FD_ZERO(&readSet); FD_SET(sock, &readSet); timeout.tv_sec = TIMEOUT_SECS; timeout.tv_usec = 0; rc = select(sock + 1, &readSet, &emptySet, &emptySet, &timeout); if (rc < 1) { if (rc==0) return FTPERR_BAD_SERVER_RESPONSE; else rc = FTPERR_UNKNOWN; } else { rc = 0; } bytesRead = read(sock, buf + bufLength, sizeof(buf) - bufLength - 1); bufLength += bytesRead; buf[bufLength] = '\0'; /* divide the response into lines, checking each one to see if we are finished or need to continue */ start = chptr = buf; do { while (*chptr != '\n' && *chptr) chptr++; if (*chptr == '\n') { *chptr = '\0'; if (*(chptr - 1) == '\r') *(chptr - 1) = '\0'; if (str) *str = start; if (errorCode[0]) { if (!strncmp(start, errorCode, 3) && start[3] == ' ') doesContinue = 0; } else { strncpy(errorCode, start, 3); errorCode[3] = '\0'; if (start[3] != '-') { doesContinue = 0; } } start = chptr + 1; chptr++; } else { chptr++; } } while (*chptr); if (doesContinue && chptr > start) { memcpy(buf, start, chptr - start - 1); bufLength = chptr - start - 1; } else { bufLength = 0; } } while (doesContinue && !rc); if (*errorCode == '4' || *errorCode == '5') { if (!strncmp(errorCode, "421", 3)) { return FTPERR_TOO_MANY_CONNECTIONS; } else if (!strncmp(errorCode, "550", 3)) { return FTPERR_FILE_NOT_FOUND; } return FTPERR_BAD_SERVER_RESPONSE; } if (rc) return rc; return 0;}int ftpCommand(int sock, char * command, ...) { va_list ap; int len; char * s; char * buf; int rc; va_start(ap, command); len = strlen(command) + 2; s = va_arg(ap, char *); while (s) { len += strlen(s) + 1; s = va_arg(ap, char *); } va_end(ap); buf = alloca(len + 1); va_start(ap, command); strcpy(buf, command); strcat(buf, " "); s = va_arg(ap, char *); while (s) { strcat(buf, s); strcat(buf, " "); s = va_arg(ap, char *); } va_end(ap); buf[len - 2] = '\r'; buf[len - 1] = '\n'; buf[len] = '\0'; if (write(sock, buf, len) != len) { return FTPERR_SERVER_IO_ERROR; } if ((rc = ftpCheckResponse(sock, NULL))) return rc; return 0;}static int getHostAddress(const char * host, void * address, int family) { char *hostname, *port; splitHostname((char *) host, &hostname, &port); if (family == AF_INET) { if (isdigit(host[0])) { if (inet_pton(AF_INET, hostname, (struct in_addr *)address) >= 1) { return 0; } else { return FTPERR_BAD_HOST_ADDR; } } else { if (mygethostbyname(hostname, (struct in_addr *)address, AF_INET)) { errno = h_errno; return FTPERR_BAD_HOSTNAME; } else { return 0; } } } else if (family == AF_INET6) { if (strchr(hostname, ':')) { if (inet_pton(AF_INET6, hostname, (struct in_addr6 *)address) >= 1) { return 0; } else return FTPERR_BAD_HOST_ADDR; } else { /* FIXME: implement me */ logMessage(ERROR, "we don't have reverse DNS for IPv6 yet"); return FTPERR_BAD_HOSTNAME; } } else { return FTPERR_UNSUPPORTED_FAMILY; }}int ftpOpen(char *host, int family, char *name, char *password, char *proxy, int port) { static int sock; struct in_addr addr; struct in6_addr addr6; struct sockaddr_in destPort; struct sockaddr_in6 destPort6; struct passwd * pw; char * buf; int rc = 0; if (port < 0) port = IPPORT_FTP; if (!name) name = "anonymous"; if (!password) { password = "root@"; if (getuid()) { pw = getpwuid(getuid()); if (pw) { password = alloca(strlen(pw->pw_name) + 2); strcpy(password, pw->pw_name); strcat(password, "@"); } } } if (proxy) { if (asprintf(&buf, "%s@%s", name, host) != -1) name = buf; host = proxy; } if (family == AF_INET) rc = getHostAddress(host, &addr, AF_INET); else if (family == AF_INET6) rc = getHostAddress(host, &addr6, AF_INET6); if (rc) return rc; sock = socket(family, SOCK_STREAM, IPPROTO_IP); if (sock < 0) { return FTPERR_FAILED_CONNECT; } if (family == AF_INET) { destPort.sin_family = family; destPort.sin_port = htons(port); destPort.sin_addr = addr; if (connect(sock, (struct sockaddr *) &destPort, sizeof(destPort))) { close(sock); return FTPERR_FAILED_CONNECT; } } else if (family == AF_INET6) { destPort6.sin6_family = family; destPort6.sin6_port = htons(port); destPort6.sin6_addr = addr6; if (connect(sock, (struct sockaddr *) &destPort6, sizeof(destPort6))) { close(sock); return FTPERR_FAILED_CONNECT; } } /* ftpCheckResponse() assumes the socket is nonblocking */ if (fcntl(sock, F_SETFL, O_NONBLOCK)) { close(sock); return FTPERR_FAILED_CONNECT; } if ((rc = ftpCheckResponse(sock, NULL))) { return rc; } if ((rc = ftpCommand(sock, "USER", name, NULL))) { close(sock); return rc; } if ((rc = ftpCommand(sock, "PASS", password, NULL))) { close(sock); return rc; } if ((rc = ftpCommand(sock, "TYPE", "I", NULL))) { close(sock); return rc; } return sock;}/* * FTP specification: * RFC 959 FILE TRANSFER PROTOCOL (FTP) * RFC 2428 FTP Extensions for IPv6 and NATs */int ftpGetFileDesc(int sock, struct in6_addr host, int family, char * remotename) { int dataSocket; struct sockaddr_in dataAddress; struct sockaddr_in6 dataAddress6; int i, j; char * passReply; char * chptr; char * retrCommand; int rc; if (family == AF_INET) { if (write(sock, "PASV\r\n", 6) != 6) { return FTPERR_SERVER_IO_ERROR; } } else if (family == AF_INET6) { if (write(sock, "EPSV\r\n", 6) != 6) { return FTPERR_SERVER_IO_ERROR; } } if ((rc = ftpCheckResponse(sock, &passReply))) { return FTPERR_PASSIVE_ERROR; } /* get IP address and port number from server response */ if (family == AF_INET) { /* we have a PASV response of the form: * 227 Entering Passive Mode (209,132,176,30,57,229) * where 209.132.176.30 is the IP, and 57 & 229 are the ports */ chptr = passReply; while (*chptr && *chptr != '(') chptr++; if (*chptr != '(') { return FTPERR_PASSIVE_ERROR; } chptr++; passReply = chptr; while (*chptr && *chptr != ')') chptr++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -