summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apt-pkg/acquire-worker.cc2
-rw-r--r--debian/NEWS12
-rw-r--r--methods/CMakeLists.txt8
-rw-r--r--methods/ftp.cc1188
-rw-r--r--methods/ftp.h91
-rw-r--r--methods/rsh.cc561
-rw-r--r--methods/rsh.h75
7 files changed, 14 insertions, 1923 deletions
diff --git a/apt-pkg/acquire-worker.cc b/apt-pkg/acquire-worker.cc
index 696a3e0b8..4840ea16a 100644
--- a/apt-pkg/acquire-worker.cc
+++ b/apt-pkg/acquire-worker.cc
@@ -98,8 +98,6 @@ bool pkgAcquire::Worker::Start()
std::string Method;
if (_config->Exists(confItem))
Method = _config->FindFile(confItem.c_str());
- else if (Access == "ftp" || Access == "rsh" || Access == "ssh")
- return _error->Error(_("The method '%s' is unsupported and disabled by default. Consider switching to http(s). Set Dir::Bin::Methods::%s to \"%s\" to enable it again."), Access.c_str(), Access.c_str(), Access.c_str());
else
Method = _config->FindDir(methodsDir) + Access;
if (FileExists(Method) == false)
diff --git a/debian/NEWS b/debian/NEWS
index 749ee478b..ae555f15f 100644
--- a/debian/NEWS
+++ b/debian/NEWS
@@ -1,3 +1,15 @@
+apt (2.9.11) unstable; urgency=medium
+
+ The ftp, rsh, ssh methods have been removed. They have been unsupported
+ and disabled since 1.8. Please migrate to http(s) instead, or contribute
+ an sftp method.
+
+ If you need ad-hoc access to a remote repository, you can usually run
+ `python3 -m http.server` on that machine and use SSH port forwarding to
+ run http over ssh.
+
+ -- Julian Andres Klode <jak@debian.org> Thu, 07 Nov 2024 14:02:07 +0100
+
apt (2.5.2) unstable; urgency=medium
Installing or upgrading a binary package now upgrades other binaries from
diff --git a/methods/CMakeLists.txt b/methods/CMakeLists.txt
index a94cb413d..548d867dc 100644
--- a/methods/CMakeLists.txt
+++ b/methods/CMakeLists.txt
@@ -11,9 +11,7 @@ add_executable(gpgv gpgv.cc)
add_executable(cdrom cdrom.cc)
add_executable(http http.cc basehttp.cc $<TARGET_OBJECTS:connectlib>)
add_executable(mirror mirror.cc)
-add_executable(ftp ftp.cc $<TARGET_OBJECTS:connectlib>)
add_executable(rred rred.cc)
-add_executable(rsh rsh.cc)
if (HAVE_GNUTLS)
target_compile_definitions(connectlib PRIVATE ${GNUTLS_DEFINITIONS})
@@ -23,16 +21,14 @@ target_include_directories(http PRIVATE $<$<BOOL:${SYSTEMD_FOUND}>:${SYSTEMD_INC
# Additional libraries to link against for networked stuff
target_link_libraries(http $<$<BOOL:${GNUTLS_FOUND}>:${GNUTLS_LIBRARIES}> $<$<BOOL:${SYSTEMD_FOUND}>:${SYSTEMD_LIBRARIES}>)
-target_link_libraries(ftp $<$<BOOL:${GNUTLS_FOUND}>:${GNUTLS_LIBRARIES}>)
target_link_libraries(rred apt-private)
# Install the library
-install(TARGETS file copy store gpgv cdrom http ftp rred rsh mirror
+install(TARGETS file copy store gpgv cdrom http rred mirror
RUNTIME DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}/apt/methods)
-add_links(${CMAKE_INSTALL_LIBEXECDIR}/apt/methods mirror mirror+ftp mirror+http mirror+https mirror+file mirror+copy)
-add_links(${CMAKE_INSTALL_LIBEXECDIR}/apt/methods rsh ssh)
+add_links(${CMAKE_INSTALL_LIBEXECDIR}/apt/methods mirror mirror+http mirror+https mirror+file mirror+copy)
add_links(${CMAKE_INSTALL_LIBEXECDIR}/apt/methods http https)
diff --git a/methods/ftp.cc b/methods/ftp.cc
deleted file mode 100644
index 5ceae4d70..000000000
--- a/methods/ftp.cc
+++ /dev/null
@@ -1,1188 +0,0 @@
-// -*- mode: cpp; mode: fold -*-
-// Description /*{{{*/
-/* ######################################################################
-
- FTP Acquire Method - This is the FTP acquire method for APT.
-
- This is a very simple implementation that does not try to optimize
- at all. Commands are sent synchronously with the FTP server (as the
- rfc recommends, but it is not really necessary..) and no tricks are
- done to speed things along.
-
- RFC 2428 describes the IPv6 FTP behavior
-
- ##################################################################### */
- /*}}}*/
-// Include Files /*{{{*/
-#include <config.h>
-
-#include <apt-pkg/configuration.h>
-#include <apt-pkg/error.h>
-#include <apt-pkg/fileutl.h>
-#include <apt-pkg/hashes.h>
-#include <apt-pkg/strutl.h>
-
-#include <cctype>
-#include <cerrno>
-#include <csignal>
-#include <cstdarg>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <iostream>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <unistd.h>
-
-// Internet stuff
-#include <netdb.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-
-#include "connect.h"
-#include "ftp.h"
-#include "rfc2553emu.h"
-
-#include <apti18n.h>
- /*}}}*/
-
-using namespace std;
-
-/* This table is for the EPRT and EPSV commands, it maps the OS address
- family to the IETF address families */
-struct AFMap
-{
- unsigned long Family;
- unsigned long IETFFamily;
-};
-
-#ifndef AF_INET6
-struct AFMap AFMap[] = {{AF_INET,1},{0, 0}};
-#else
-struct AFMap AFMap[] = {{AF_INET,1},{AF_INET6,2},{0, 0}};
-#endif
-
-unsigned long TimeOut = 30;
-URI Proxy;
-string FtpMethod::FailFile;
-int FtpMethod::FailFd = -1;
-time_t FtpMethod::FailTime = 0;
-
-// FTPConn::FTPConn - Constructor /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-FTPConn::FTPConn(URI Srv) : Len(0), ServerFd(MethodFd::FromFd(-1)), DataFd(-1),
- DataListenFd(-1), ServerName(Srv),
- ForceExtended(false), TryPassive(true),
- PeerAddrLen(0), ServerAddrLen(0)
-{
- Debug = _config->FindB("Debug::Acquire::Ftp",false);
- PasvAddr = 0;
- Buffer[0] = '\0';
-}
- /*}}}*/
-// FTPConn::~FTPConn - Destructor /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-FTPConn::~FTPConn()
-{
- Close();
-}
- /*}}}*/
-// FTPConn::Close - Close down the connection /*{{{*/
-// ---------------------------------------------------------------------
-/* Just tear down the socket and data socket */
-void FTPConn::Close()
-{
- ServerFd->Close();
- close(DataFd);
- DataFd = -1;
- close(DataListenFd);
- DataListenFd = -1;
-
- if (PasvAddr != 0)
- freeaddrinfo(PasvAddr);
- PasvAddr = 0;
-}
- /*}}}*/
-// FTPConn::Open - Open a new connection /*{{{*/
-// ---------------------------------------------------------------------
-/* Connect to the server using a non-blocking connection and perform a
- login. */
-ResultState FTPConn::Open(aptMethod *Owner)
-{
- // Use the already open connection if possible.
- if (ServerFd->Fd() != -1)
- return ResultState::SUCCESSFUL;
-
- Close();
-
- // Determine the proxy setting
- string SpecificProxy = _config->Find("Acquire::ftp::Proxy::" + ServerName.Host);
- if (!SpecificProxy.empty())
- {
- if (SpecificProxy == "DIRECT")
- Proxy = "";
- else
- Proxy = SpecificProxy;
- }
- else
- {
- string DefProxy = _config->Find("Acquire::ftp::Proxy");
- if (!DefProxy.empty())
- {
- Proxy = DefProxy;
- }
- else
- {
- char* result = getenv("ftp_proxy");
- Proxy = result ? result : "";
- }
- }
-
- // Parse no_proxy, a , separated list of domains
- if (getenv("no_proxy") != 0)
- {
- if (CheckDomainList(ServerName.Host,getenv("no_proxy")) == true)
- Proxy = "";
- }
-
- // Determine what host and port to use based on the proxy settings
- int Port = 0;
- string Host;
- if (Proxy.empty() == true)
- {
- if (ServerName.Port != 0)
- Port = ServerName.Port;
- Host = ServerName.Host;
- }
- else
- {
- if (Proxy.Port != 0)
- Port = Proxy.Port;
- Host = Proxy.Host;
- }
-
- /* Connect to the remote server. Since FTP is connection oriented we
- want to make sure we get a new server every time we reconnect */
- RotateDNS();
- auto result = Connect(Host, Port, "ftp", 21, ServerFd, TimeOut, Owner);
- if (result != ResultState::SUCCESSFUL)
- return result;
-
- // Login must be before getpeername otherwise dante won't work.
- Owner->Status(_("Logging in"));
- result = Login();
- if (result != ResultState::SUCCESSFUL)
- return result;
-
- // Get the remote server's address
- PeerAddrLen = sizeof(PeerAddr);
- if (getpeername(ServerFd->Fd(), (sockaddr *)&PeerAddr, &PeerAddrLen) != 0)
- {
- _error->Errno("getpeername", _("Unable to determine the peer name"));
- return ResultState::TRANSIENT_ERROR;
- }
-
- // Get the local machine's address
- ServerAddrLen = sizeof(ServerAddr);
- if (getsockname(ServerFd->Fd(), (sockaddr *)&ServerAddr, &ServerAddrLen) != 0)
- {
- _error->Errno("getsockname", _("Unable to determine the local name"));
- return ResultState::TRANSIENT_ERROR;
- }
-
- return ResultState::SUCCESSFUL;
-}
- /*}}}*/
-// FTPConn::Login - Login to the remote server /*{{{*/
-// ---------------------------------------------------------------------
-/* This performs both normal login and proxy login using a simples script
- stored in the config file. */
-ResultState FTPConn::Login()
-{
- unsigned int Tag;
- string Msg;
-
- // Setup the variables needed for authentication
- string User = "anonymous";
- string Pass = "apt_get_ftp_2.1@debian.linux.user";
-
- // Fill in the user/pass
- if (ServerName.User.empty() == false)
- User = ServerName.User;
- if (ServerName.Password.empty() == false)
- Pass = ServerName.Password;
-
- // Perform simple login
- if (Proxy.empty() == true)
- {
- // Read the initial response
- if (ReadResp(Tag,Msg) == false)
- return ResultState::TRANSIENT_ERROR;
- if (Tag >= 400)
- {
- _error->Error(_("The server refused the connection and said: %s"), Msg.c_str());
- return ResultState::FATAL_ERROR;
- }
-
- // Send the user
- if (WriteMsg(Tag,Msg,"USER %s",User.c_str()) == false)
- return ResultState::TRANSIENT_ERROR;
- if (Tag >= 400)
- {
- _error->Error(_("USER failed, server said: %s"), Msg.c_str());
- return ResultState::FATAL_ERROR;
- }
-
- if (Tag == 331) { // 331 User name okay, need password.
- // Send the Password
- if (WriteMsg(Tag,Msg,"PASS %s",Pass.c_str()) == false)
- return ResultState::TRANSIENT_ERROR;
- if (Tag >= 400)
- {
- _error->Error(_("PASS failed, server said: %s"), Msg.c_str());
- return ResultState::FATAL_ERROR;
- }
- }
-
- // Enter passive mode
- if (_config->Exists("Acquire::FTP::Passive::" + ServerName.Host) == true)
- TryPassive = _config->FindB("Acquire::FTP::Passive::" + ServerName.Host,true);
- else
- TryPassive = _config->FindB("Acquire::FTP::Passive",true);
- }
- else
- {
- // Read the initial response
- if (ReadResp(Tag,Msg) == false)
- return ResultState::TRANSIENT_ERROR;
- if (Tag >= 400)
- {
- _error->Error(_("The server refused the connection and said: %s"), Msg.c_str());
- return ResultState::TRANSIENT_ERROR;
- }
-
- // Perform proxy script execution
- Configuration::Item const *Opts = _config->Tree("Acquire::ftp::ProxyLogin");
- if (Opts == 0 || Opts->Child == 0)
- {
- _error->Error(_("A proxy server was specified but no login "
- "script, Acquire::ftp::ProxyLogin is empty."));
- return ResultState::FATAL_ERROR;
- }
- Opts = Opts->Child;
-
- // Iterate over the entire login script
- for (; Opts != 0; Opts = Opts->Next)
- {
- if (Opts->Value.empty() == true)
- continue;
-
- // Substitute the variables into the command
- string Tmp = Opts->Value;
- Tmp = SubstVar(Tmp,"$(PROXY_USER)",Proxy.User);
- Tmp = SubstVar(Tmp,"$(PROXY_PASS)",Proxy.Password);
- Tmp = SubstVar(Tmp,"$(SITE_USER)",User);
- Tmp = SubstVar(Tmp,"$(SITE_PASS)",Pass);
- if (ServerName.Port != 0)
- {
- std::string SitePort;
- strprintf(SitePort, "%u", ServerName.Port);
- Tmp = SubstVar(Tmp,"$(SITE_PORT)", SitePort);
- }
- else
- Tmp = SubstVar(Tmp,"$(SITE_PORT)", "21");
- Tmp = SubstVar(Tmp,"$(SITE)",ServerName.Host);
-
- // Send the command
- if (WriteMsg(Tag,Msg,"%s",Tmp.c_str()) == false)
- return ResultState::TRANSIENT_ERROR;
- if (Tag >= 400)
- {
- _error->Error(_("Login script command '%s' failed, server said: %s"), Tmp.c_str(), Msg.c_str());
- return ResultState::FATAL_ERROR;
- }
- }
-
- // Enter passive mode
- TryPassive = false;
- if (_config->Exists("Acquire::FTP::Passive::" + ServerName.Host) == true)
- TryPassive = _config->FindB("Acquire::FTP::Passive::" + ServerName.Host,true);
- else
- {
- if (_config->Exists("Acquire::FTP::Proxy::Passive") == true)
- TryPassive = _config->FindB("Acquire::FTP::Proxy::Passive",true);
- else
- TryPassive = _config->FindB("Acquire::FTP::Passive",true);
- }
- }
-
- // Force the use of extended commands
- if (_config->Exists("Acquire::FTP::ForceExtended::" + ServerName.Host) == true)
- ForceExtended = _config->FindB("Acquire::FTP::ForceExtended::" + ServerName.Host,true);
- else
- ForceExtended = _config->FindB("Acquire::FTP::ForceExtended",false);
-
- // Binary mode
- if (WriteMsg(Tag,Msg,"TYPE I") == false)
- return ResultState::TRANSIENT_ERROR;
- if (Tag >= 400)
- {
- _error->Error(_("TYPE failed, server said: %s"), Msg.c_str());
- return ResultState::FATAL_ERROR;
- }
- return ResultState::SUCCESSFUL;
-}
- /*}}}*/
-// FTPConn::ReadLine - Read a line from the server /*{{{*/
-// ---------------------------------------------------------------------
-/* This performs a very simple buffered read. */
-bool FTPConn::ReadLine(string &Text)
-{
- if (ServerFd->Fd() == -1)
- return false;
-
- // Suck in a line
- while (Len < sizeof(Buffer))
- {
- // Scan the buffer for a new line
- for (unsigned int I = 0; I != Len; I++)
- {
- // Escape some special chars
- if (Buffer[I] == 0)
- Buffer[I] = '?';
-
- // End of line?
- if (Buffer[I] != '\n')
- continue;
-
- I++;
- Text = string(Buffer,I);
- memmove(Buffer,Buffer+I,Len - I);
- Len -= I;
- return true;
- }
-
- // Wait for some data..
- if (WaitFd(ServerFd->Fd(), false, TimeOut) == false)
- {
- Close();
- return _error->Error(_("Connection timeout"));
- }
-
- // Suck it back
- int Res = ServerFd->Read(Buffer + Len, sizeof(Buffer) - Len);
- if (Res == 0)
- _error->Error(_("Server closed the connection"));
- if (Res <= 0)
- {
- _error->Errno("read",_("Read error"));
- Close();
- return false;
- }
- Len += Res;
- }
-
- return _error->Error(_("A response overflowed the buffer."));
-}
- /*}}}*/
-// FTPConn::ReadResp - Read a full response from the server /*{{{*/
-// ---------------------------------------------------------------------
-/* This reads a reply code from the server, it handles both p */
-bool FTPConn::ReadResp(unsigned int &Ret,string &Text)
-{
- // Grab the first line of the response
- string Msg;
- if (ReadLine(Msg) == false)
- return false;
-
- // Get the ID code
- char *End;
- Ret = strtol(Msg.c_str(),&End,10);
- if (End - Msg.c_str() != 3)
- return _error->Error(_("Protocol corruption"));
-
- // All done ?
- Text = Msg.c_str()+4;
- if (*End == ' ')
- {
- if (Debug == true)
- cerr << "<- '" << QuoteString(Text,"") << "'" << endl;
- return true;
- }
-
- if (*End != '-')
- return _error->Error(_("Protocol corruption"));
-
- /* Okay, here we do the continued message trick. This is foolish, but
- proftpd follows the protocol as specified and wu-ftpd doesn't, so
- we filter. I wonder how many clients break if you use proftpd and
- put a '- in the 3rd spot in the message? */
- char Leader[4];
- strncpy(Leader,Msg.c_str(),3);
- Leader[3] = 0;
- while (ReadLine(Msg) == true)
- {
- // Short, it must be using RFC continuation..
- if (Msg.length() < 4)
- {
- Text += Msg;
- continue;
- }
-
- // Oops, finished
- if (strncmp(Msg.c_str(),Leader,3) == 0 && Msg[3] == ' ')
- {
- Text += Msg.c_str()+4;
- break;
- }
-
- // This message has the wu-ftpd style reply code prefixed
- if (strncmp(Msg.c_str(),Leader,3) == 0 && Msg[3] == '-')
- {
- Text += Msg.c_str()+4;
- continue;
- }
-
- // Must be RFC style prefixing
- Text += Msg;
- }
-
- if (Debug == true && _error->PendingError() == false)
- cerr << "<- '" << QuoteString(Text,"") << "'" << endl;
-
- return !_error->PendingError();
-}
- /*}}}*/
-// FTPConn::WriteMsg - Send a message to the server /*{{{*/
-// ---------------------------------------------------------------------
-/* Simple printf like function.. */
-bool FTPConn::WriteMsg(unsigned int &Ret,string &Text,const char *Fmt,...)
-{
- va_list args;
- va_start(args,Fmt);
-
- // sprintf the description
- char S[400];
- vsnprintf(S,sizeof(S) - 4,Fmt,args);
- strcat(S,"\r\n");
- va_end(args);
-
- if (Debug == true)
- cerr << "-> '" << QuoteString(S,"") << "'" << endl;
-
- // Send it off
- unsigned long Len = strlen(S);
- unsigned long Start = 0;
- while (Len != 0)
- {
- if (WaitFd(ServerFd->Fd(), true, TimeOut) == false)
- {
- Close();
- return _error->Error(_("Connection timeout"));
- }
-
- int Res = ServerFd->Write(S + Start, Len);
- if (Res <= 0)
- {
- _error->Errno("write",_("Write error"));
- Close();
- return false;
- }
-
- Len -= Res;
- Start += Res;
- }
-
- return ReadResp(Ret,Text);
-}
- /*}}}*/
-// FTPConn::GoPasv - Enter Passive mode /*{{{*/
-// ---------------------------------------------------------------------
-/* Try to enter passive mode, the return code does not indicate if passive
- mode could or could not be established, only if there was a fatal error.
- We have to enter passive mode every time we make a data connection :| */
-bool FTPConn::GoPasv()
-{
- /* The PASV command only works on IPv4 sockets, even though it could
- in theory suppory IPv6 via an all zeros reply */
- if (((struct sockaddr *)&PeerAddr)->sa_family != AF_INET ||
- ForceExtended == true)
- return ExtGoPasv();
-
- if (PasvAddr != 0)
- freeaddrinfo(PasvAddr);
- PasvAddr = 0;
-
- // Try to enable pasv mode
- unsigned int Tag;
- string Msg;
- if (WriteMsg(Tag,Msg,"PASV") == false)
- return false;
-
- // Unsupported function
- string::size_type Pos = Msg.find('(');
- if (Tag >= 400)
- return true;
-
- //wu-2.6.2(1) ftp server, returns
- //227 Entering Passive Mode 193,219,28,140,150,111
- //without parentheses, let's try to cope with it.
- //wget(1) and ftp(1) can.
- if (Pos == string::npos)
- Pos = Msg.rfind(' ');
- else
- ++Pos;
-
- // Still unsupported function
- if (Pos == string::npos)
- return true;
-
- // Scan it
- unsigned a0,a1,a2,a3,p0,p1;
- if (sscanf(Msg.c_str() + Pos,"%u,%u,%u,%u,%u,%u",&a0,&a1,&a2,&a3,&p0,&p1) != 6)
- return true;
-
- /* Some evil servers return 0 to mean their addr. We can actually speak
- to these servers natively using IPv6 */
- if (a0 == 0 && a1 == 0 && a2 == 0 && a3 == 0)
- {
- // Get the IP in text form
- char Name[NI_MAXHOST];
- char Service[NI_MAXSERV];
- getnameinfo((struct sockaddr *)&PeerAddr,PeerAddrLen,
- Name,sizeof(Name),Service,sizeof(Service),
- NI_NUMERICHOST|NI_NUMERICSERV);
-
- struct addrinfo Hints;
- memset(&Hints,0,sizeof(Hints));
- Hints.ai_socktype = SOCK_STREAM;
- Hints.ai_family = ((struct sockaddr *)&PeerAddr)->sa_family;
- Hints.ai_flags |= AI_NUMERICHOST;
-
- // Get a new passive address.
- char Port[100];
- snprintf(Port,sizeof(Port),"%u",(p0 << 8) + p1);
- if (getaddrinfo(Name,Port,&Hints,&PasvAddr) != 0)
- return true;
- return true;
- }
-
- struct addrinfo Hints;
- memset(&Hints,0,sizeof(Hints));
- Hints.ai_socktype = SOCK_STREAM;
- Hints.ai_family = AF_INET;
- Hints.ai_flags |= AI_NUMERICHOST;
-
- // Get a new passive address.
- char Port[100];
- snprintf(Port,sizeof(Port),"%u",(p0 << 8) + p1);
- char Name[100];
- snprintf(Name,sizeof(Name),"%u.%u.%u.%u",a0,a1,a2,a3);
- if (getaddrinfo(Name,Port,&Hints,&PasvAddr) != 0)
- return true;
- return true;
-}
- /*}}}*/
-// FTPConn::ExtGoPasv - Enter Extended Passive mode /*{{{*/
-// ---------------------------------------------------------------------
-/* Try to enter extended passive mode. See GoPasv above and RFC 2428 */
-bool FTPConn::ExtGoPasv()
-{
- if (PasvAddr != 0)
- freeaddrinfo(PasvAddr);
- PasvAddr = 0;
-
- // Try to enable pasv mode
- unsigned int Tag;
- string Msg;
- if (WriteMsg(Tag,Msg,"EPSV") == false)
- return false;
-
- // Unsupported function
- string::size_type Pos = Msg.find('(');
- if (Tag >= 400 || Pos == string::npos)
- return true;
-
- // Scan it
- string::const_iterator List[4];
- unsigned Count = 0;
- Pos++;
- for (string::const_iterator I = Msg.begin() + Pos; I < Msg.end(); ++I)
- {
- if (*I != Msg[Pos])
- continue;
- if (Count >= 4)
- return true;
- List[Count++] = I;
- }
- if (Count != 4)
- return true;
-
- // Break it up ..
- unsigned long Proto = 0;
- unsigned long Port = 0;
- string IP;
- IP = string(List[1]+1,List[2]);
- Port = atoi(string(List[2]+1,List[3]).c_str());
- if (IP.empty() == false)
- Proto = atoi(string(List[0]+1,List[1]).c_str());
-
- if (Port == 0)
- return false;
-
- // String version of the port
- char PStr[100];
- snprintf(PStr,sizeof(PStr),"%lu",Port);
-
- // Get the IP in text form
- struct addrinfo Hints;
- memset(&Hints,0,sizeof(Hints));
- Hints.ai_socktype = SOCK_STREAM;
- Hints.ai_flags |= AI_NUMERICHOST;
-
- /* The RFC defined case, connect to the old IP/protocol using the
- new port. */
- if (IP.empty() == true)
- {
- // Get the IP in text form
- char Name[NI_MAXHOST];
- char Service[NI_MAXSERV];
- getnameinfo((struct sockaddr *)&PeerAddr,PeerAddrLen,
- Name,sizeof(Name),Service,sizeof(Service),
- NI_NUMERICHOST|NI_NUMERICSERV);
- IP = Name;
- Hints.ai_family = ((struct sockaddr *)&PeerAddr)->sa_family;
- }
- else
- {
- // Get the family..
- Hints.ai_family = 0;
- for (unsigned J = 0; AFMap[J].Family != 0; J++)
- if (AFMap[J].IETFFamily == Proto)
- Hints.ai_family = AFMap[J].Family;
- if (Hints.ai_family == 0)
- return true;
- }
-
- // Get a new passive address.
- if (getaddrinfo(IP.c_str(),PStr,&Hints,&PasvAddr) != 0)
- return true;
-
- return true;
-}
- /*}}}*/
-// FTPConn::Size - Return the size of a file /*{{{*/
-// ---------------------------------------------------------------------
-/* Grab the file size from the server, 0 means no size or empty file */
-bool FTPConn::Size(const char *Path,unsigned long long &Size)
-{
- // Query the size
- unsigned int Tag;
- string Msg;
- Size = 0;
- if (WriteMsg(Tag,Msg,"SIZE %s",Path) == false)
- return false;
-
- char *End;
- Size = strtoull(Msg.c_str(),&End,10);
- if (Tag >= 400 || End == Msg.c_str())
- Size = 0;
- return true;
-}
- /*}}}*/
-// FTPConn::ModTime - Return the modification time of the file /*{{{*/
-// ---------------------------------------------------------------------
-/* Like Size no error is returned if the command is not supported. If the
- command fails then time is set to the current time of day to fool
- date checks. */
-bool FTPConn::ModTime(const char *Path, time_t &Time)
-{
- Time = time(&Time);
-
- // Query the mod time
- unsigned int Tag;
- string Msg;
- if (WriteMsg(Tag,Msg,"MDTM %s",Path) == false)
- return false;
- if (Tag >= 400 || Msg.empty() == true || isdigit(Msg[0]) == 0)
- return true;
-
- // Parse it
- return FTPMDTMStrToTime(Msg.c_str(), Time);
-}
- /*}}}*/
-// FTPConn::CreateDataFd - Get a data connection /*{{{*/
-// ---------------------------------------------------------------------
-/* Create the data connection. Call FinalizeDataFd after this though.. */
-bool FTPConn::CreateDataFd()
-{
- close(DataFd);
- DataFd = -1;
-
- // Attempt to enter passive mode.
- if (TryPassive == true)
- {
- if (GoPasv() == false)
- return false;
-
- // Oops, didn't work out, don't bother trying again.
- if (PasvAddr == 0)
- TryPassive = false;
- }
-
- // Passive mode?
- if (PasvAddr != 0)
- {
- // Get a socket
- if ((DataFd = socket(PasvAddr->ai_family,PasvAddr->ai_socktype,
- PasvAddr->ai_protocol)) < 0)
- return _error->Errno("socket",_("Could not create a socket"));
-
- // Connect to the server
- SetNonBlock(DataFd,true);
- if (connect(DataFd,PasvAddr->ai_addr,PasvAddr->ai_addrlen) < 0 &&
- errno != EINPROGRESS)
- return _error->Errno("socket",_("Could not create a socket"));
-
- /* This implements a timeout for connect by opening the connection
- nonblocking */
- if (WaitFd(DataFd,true,TimeOut) == false)
- return _error->Error(_("Could not connect data socket, connection timed out"));
- unsigned int Err;
- unsigned int Len = sizeof(Err);
- if (getsockopt(DataFd,SOL_SOCKET,SO_ERROR,&Err,&Len) != 0)
- return _error->Errno("getsockopt",_("Failed"));
- if (Err != 0)
- return _error->Error(_("Could not connect passive socket."));
-
- return true;
- }
-
- // Port mode :<
- close(DataListenFd);
- DataListenFd = -1;
-
- // Get the information for a listening socket.
- struct addrinfo *BindAddr = NULL;
- struct addrinfo Hints;
- memset(&Hints,0,sizeof(Hints));
- Hints.ai_socktype = SOCK_STREAM;
- Hints.ai_flags |= AI_PASSIVE;
- Hints.ai_family = ((struct sockaddr *)&ServerAddr)->sa_family;
- if (getaddrinfo(0,"0",&Hints,&BindAddr) != 0 || BindAddr == NULL)
- return _error->Error(_("getaddrinfo was unable to get a listening socket"));
-
- // Construct the socket
- if ((DataListenFd = socket(BindAddr->ai_family,BindAddr->ai_socktype,
- BindAddr->ai_protocol)) < 0)
- {
- freeaddrinfo(BindAddr);
- return _error->Errno("socket",_("Could not create a socket"));
- }
-
- // Bind and listen
- if (::bind(DataListenFd,BindAddr->ai_addr,BindAddr->ai_addrlen) < 0)
- {
- freeaddrinfo(BindAddr);
- return _error->Errno("bind",_("Could not bind a socket"));
- }
- freeaddrinfo(BindAddr);
- if (listen(DataListenFd,1) < 0)
- return _error->Errno("listen",_("Could not listen on the socket"));
- SetNonBlock(DataListenFd,true);
-
- // Determine the name to send to the remote
- struct sockaddr_storage Addr;
- socklen_t AddrLen = sizeof(Addr);
- if (getsockname(DataListenFd,(sockaddr *)&Addr,&AddrLen) < 0)
- return _error->Errno("getsockname",_("Could not determine the socket's name"));
-
-
- // Reverse the address. We need the server address and the data port.
- char Name[NI_MAXHOST];
- char Service[NI_MAXSERV];
- char Service2[NI_MAXSERV];
- getnameinfo((struct sockaddr *)&Addr,AddrLen,
- Name,sizeof(Name),Service,sizeof(Service),
- NI_NUMERICHOST|NI_NUMERICSERV);
- getnameinfo((struct sockaddr *)&ServerAddr,ServerAddrLen,
- Name,sizeof(Name),Service2,sizeof(Service2),
- NI_NUMERICHOST|NI_NUMERICSERV);
-
- // Send off an IPv4 address in the old port format
- if (((struct sockaddr *)&Addr)->sa_family == AF_INET &&
- ForceExtended == false)
- {
- // Convert the dots in the quad into commas
- for (char *I = Name; *I != 0; I++)
- if (*I == '.')
- *I = ',';
- unsigned long Port = atoi(Service);
-
- // Send the port command
- unsigned int Tag;
- string Msg;
- if (WriteMsg(Tag,Msg,"PORT %s,%d,%d",
- Name,
- (int)(Port >> 8) & 0xff, (int)(Port & 0xff)) == false)
- return false;
- if (Tag >= 400)
- return _error->Error(_("Unable to send PORT command"));
- return true;
- }
-
- // Construct an EPRT command
- unsigned Proto = 0;
- for (unsigned J = 0; AFMap[J].Family != 0; J++)
- if (AFMap[J].Family == ((struct sockaddr *)&Addr)->sa_family)
- Proto = AFMap[J].IETFFamily;
- if (Proto == 0)
- return _error->Error(_("Unknown address family %u (AF_*)"),
- ((struct sockaddr *)&Addr)->sa_family);
-
- // Send the EPRT command
- unsigned int Tag;
- string Msg;
- if (WriteMsg(Tag,Msg,"EPRT |%u|%s|%s|",Proto,Name,Service) == false)
- return false;
- if (Tag >= 400)
- return _error->Error(_("EPRT failed, server said: %s"),Msg.c_str());
- return true;
-}
- /*}}}*/
-// FTPConn::Finalize - Complete the Data connection /*{{{*/
-// ---------------------------------------------------------------------
-/* If the connection is in port mode this waits for the other end to hook
- up to us. */
-bool FTPConn::Finalize()
-{
- // Passive mode? Do nothing
- if (PasvAddr != 0)
- return true;
-
- // Close any old socket..
- close(DataFd);
- DataFd = -1;
-
- // Wait for someone to connect..
- if (WaitFd(DataListenFd,false,TimeOut) == false)
- return _error->Error(_("Data socket connect timed out"));
-
- // Accept the connection
- struct sockaddr_in Addr;
- socklen_t Len = sizeof(Addr);
- DataFd = accept(DataListenFd,(struct sockaddr *)&Addr,&Len);
- if (DataFd < 0)
- return _error->Errno("accept",_("Unable to accept connection"));
-
- close(DataListenFd);
- DataListenFd = -1;
-
- return true;
-}
- /*}}}*/
-// FTPConn::Get - Get a file /*{{{*/
-// ---------------------------------------------------------------------
-/* This opens a data connection, sends REST and RETR and then
- transfers the file over. */
-bool FTPConn::Get(const char *Path,FileFd &To,unsigned long long Resume,
- Hashes &Hash,bool &Missing, unsigned long long MaximumSize,
- pkgAcqMethod *Owner)
-{
- Missing = false;
- if (CreateDataFd() == false)
- return false;
-
- unsigned int Tag;
- string Msg;
- if (Resume != 0)
- {
- if (WriteMsg(Tag,Msg,"REST %u",Resume) == false)
- return false;
- if (Tag >= 400)
- Resume = 0;
- }
-
- if (To.Truncate(Resume) == false)
- return false;
-
- if (To.Seek(0) == false)
- return false;
-
- if (Resume != 0)
- {
- if (Hash.AddFD(To,Resume) == false)
- {
- _error->Errno("read",_("Problem hashing file"));
- return false;
- }
- }
-
- // Send the get command
- if (WriteMsg(Tag,Msg,"RETR %s",Path) == false)
- return false;
-
- if (Tag >= 400)
- {
- if (Tag == 550)
- Missing = true;
- return _error->Error(_("Unable to fetch file, server said '%s'"),Msg.c_str());
- }
-
- // Finish off the data connection
- if (Finalize() == false)
- return false;
-
- // Copy loop
- unsigned char Buffer[APT_BUFFER_SIZE];
- while (1)
- {
- // Wait for some data..
- if (WaitFd(DataFd,false,TimeOut) == false)
- {
- Close();
- return _error->Error(_("Data socket timed out"));
- }
-
- // Read the data..
- int Res = read(DataFd,Buffer,sizeof(Buffer));
- if (Res == 0)
- break;
- if (Res < 0)
- {
- if (errno == EAGAIN)
- continue;
- break;
- }
-
- Hash.Add(Buffer,Res);
- if (To.Write(Buffer,Res) == false)
- {
- Close();
- return false;
- }
-
- if (MaximumSize > 0 && To.Tell() > MaximumSize)
- {
- Owner->SetFailReason("MaximumSizeExceeded");
- return _error->Error(_("File has unexpected size (%llu != %llu). Mirror sync in progress?"),
- To.Tell(), MaximumSize);
- }
- }
-
- // All done
- close(DataFd);
- DataFd = -1;
-
- // Read the closing message from the server
- if (ReadResp(Tag,Msg) == false)
- return false;
- if (Tag >= 400)
- return _error->Error(_("Data transfer failed, server said '%s'"),Msg.c_str());
- return true;
-}
- /*}}}*/
-
-// FtpMethod::FtpMethod - Constructor /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-FtpMethod::FtpMethod() : aptAuthConfMethod("ftp", "1.0", SendConfig | SendURIEncoded)
-{
- SeccompFlags = aptMethod::BASE | aptMethod::NETWORK;
- signal(SIGTERM,SigTerm);
- signal(SIGINT,SigTerm);
-
- Server = 0;
- FailFd = -1;
-}
- /*}}}*/
-// FtpMethod::SigTerm - Handle a fatal signal /*{{{*/
-// ---------------------------------------------------------------------
-/* This closes and timestamps the open file. This is necessary to get
- resume behavior on user abort */
-void FtpMethod::SigTerm(int)
-{
- if (FailFd == -1)
- _exit(100);
-
- // Timestamp
- struct timeval times[2];
- times[0].tv_sec = FailTime;
- times[1].tv_sec = FailTime;
- times[0].tv_usec = times[1].tv_usec = 0;
- utimes(FailFile.c_str(), times);
-
- close(FailFd);
-
- _exit(100);
-}
- /*}}}*/
-// FtpMethod::Configuration - Handle a configuration message /*{{{*/
-// ---------------------------------------------------------------------
-/* We stash the desired pipeline depth */
-bool FtpMethod::Configuration(string Message)
-{
- if (aptAuthConfMethod::Configuration(Message) == false)
- return false;
-
- TimeOut = _config->FindI("Acquire::Ftp::Timeout",TimeOut);
-
- return true;
-}
- /*}}}*/
-// FtpMethod::Fetch - Fetch a file /*{{{*/
-// ---------------------------------------------------------------------
-/* Fetch a single file, called by the base class.. */
-bool FtpMethod::Fetch(FetchItem *Itm)
-{
- URI Get(Itm->Uri);
- auto const File = DecodeSendURI(Get.Path);
- FetchResult Res;
- Res.Filename = Itm->DestFile;
- Res.IMSHit = false;
-
- MaybeAddAuthTo(Get);
-
- // Connect to the server
- if (Server == 0 || Server->Comp(Get) == false)
- {
- delete Server;
- Server = new FTPConn(Get);
- }
-
- // Could not connect is a transient error..
- switch (Server->Open(this))
- {
- case ResultState::TRANSIENT_ERROR:
- Server->Close();
- Fail(true);
- return true;
- case ResultState::FATAL_ERROR:
- Server->Close();
- Fail(false);
- return true;
- case ResultState::SUCCESSFUL:
- break;
- }
-
- // Get the files information
- Status(_("Query"));
- unsigned long long Size;
- if (not Server->Size(File.c_str(), Size) ||
- not Server->ModTime(File.c_str(), FailTime))
- {
- Fail(true);
- return true;
- }
- Res.Size = Size;
-
- // See if it is an IMS hit
- if (Itm->LastModified == FailTime)
- {
- Res.Size = 0;
- Res.IMSHit = true;
- URIDone(Res);
- return true;
- }
-
- // See if the file exists
- struct stat Buf;
- if (stat(Itm->DestFile.c_str(),&Buf) == 0)
- {
- if (Size == (unsigned long long)Buf.st_size && FailTime == Buf.st_mtime)
- {
- Res.Size = Buf.st_size;
- Res.LastModified = Buf.st_mtime;
- Res.ResumePoint = Buf.st_size;
- URIDone(Res);
- return true;
- }
-
- // Resume?
- if (FailTime == Buf.st_mtime && Size > (unsigned long long)Buf.st_size)
- Res.ResumePoint = Buf.st_size;
- }
-
- // Open the file
- Hashes Hash(Itm->ExpectedHashes);
- {
- FileFd Fd(Itm->DestFile,FileFd::WriteAny);
- if (_error->PendingError() == true)
- return false;
-
- URIStart(Res);
-
- FailFile = Itm->DestFile;
- (void)(FailFile.c_str()); // Make sure we don't do a malloc in the signal handler
- FailFd = Fd.Fd();
-
- bool Missing;
- if (not Server->Get(File.c_str(), Fd, Res.ResumePoint, Hash, Missing, Itm->MaximumSize, this))
- {
- Fd.Close();
-
- // Timestamp
- struct timeval times[2];
- times[0].tv_sec = FailTime;
- times[1].tv_sec = FailTime;
- times[0].tv_usec = times[1].tv_usec = 0;
- utimes(FailFile.c_str(), times);
-
- // If the file is missing we hard fail and delete the destfile
- // otherwise transient fail
- if (Missing == true) {
- RemoveFile("ftp", FailFile);
- return false;
- }
- Fail(true);
- return true;
- }
-
- Res.Size = Fd.Size();
-
- // Timestamp
- struct timeval times[2];
- times[0].tv_sec = FailTime;
- times[1].tv_sec = FailTime;
- times[0].tv_usec = times[1].tv_usec = 0;
- utimes(Fd.Name().c_str(), times);
- FailFd = -1;
- }
-
- Res.LastModified = FailTime;
- Res.TakeHashes(Hash);
-
- URIDone(Res);
-
- return true;
-}
- /*}}}*/
-
-int main(int, const char *argv[])
-{
- /* See if we should be come the http client - we do this for http
- proxy urls */
- if (getenv("ftp_proxy") != 0)
- {
- URI Proxy(string(getenv("ftp_proxy")));
-
- // Run the HTTP method
- if (Proxy.Access == "http")
- {
- // Copy over the environment setting
- char S[300];
- snprintf(S,sizeof(S),"http_proxy=%s",getenv("ftp_proxy"));
- putenv(S);
- putenv((char *)"no_proxy=");
-
- // Run the http method
- string Path = flNotFile(argv[0]) + "http";
- execl(Path.c_str(),Path.c_str(),(char *)NULL);
- cerr << _("Unable to invoke ") << Path << endl;
- exit(100);
- }
- }
- return FtpMethod().Run();
-}
diff --git a/methods/ftp.h b/methods/ftp.h
deleted file mode 100644
index 953a1da86..000000000
--- a/methods/ftp.h
+++ /dev/null
@@ -1,91 +0,0 @@
-// -*- mode: cpp; mode: fold -*-
-// Description /*{{{*/
-/* ######################################################################
-
- FTP Acquire Method - This is the FTP acquire method for APT.
-
- ##################################################################### */
- /*}}}*/
-#ifndef APT_FTP_H
-#define APT_FTP_H
-
-#include "aptmethod.h"
-#include "connect.h"
-#include <apt-pkg/strutl.h>
-
-#include <ctime>
-#include <string>
-#include <sys/socket.h>
-#include <sys/types.h>
-
-class FTPConn
-{
- char Buffer[1024*10];
- unsigned long Len;
- std::unique_ptr<MethodFd> ServerFd;
- int DataFd;
- int DataListenFd;
- URI ServerName;
- bool ForceExtended;
- bool TryPassive;
- bool Debug;
-
- struct addrinfo *PasvAddr;
-
- // Generic Peer Address
- struct sockaddr_storage PeerAddr;
- socklen_t PeerAddrLen;
-
- // Generic Server Address (us)
- struct sockaddr_storage ServerAddr;
- socklen_t ServerAddrLen;
-
- // Private helper functions
- bool ReadLine(std::string &Text);
- ResultState Login();
- bool CreateDataFd();
- bool Finalize();
-
- public:
-
- bool Comp(URI Other) {return Other.Host == ServerName.Host && Other.Port == ServerName.Port && Other.User == ServerName.User && Other.Password == ServerName.Password; };
-
- // Raw connection IO
- bool ReadResp(unsigned int &Ret,std::string &Text);
- bool WriteMsg(unsigned int &Ret,std::string &Text,const char *Fmt,...);
-
- // Connection control
- ResultState Open(aptMethod *Owner);
- void Close();
- bool GoPasv();
- bool ExtGoPasv();
-
- // Query
- bool Size(const char *Path,unsigned long long &Size);
- bool ModTime(const char *Path, time_t &Time);
- bool Get(const char *Path,FileFd &To,unsigned long long Resume,
- Hashes &MD5,bool &Missing, unsigned long long MaximumSize,
- pkgAcqMethod *Owner);
-
- explicit FTPConn(URI Srv);
- ~FTPConn();
-};
-
-class FtpMethod : public aptAuthConfMethod
-{
- virtual bool Fetch(FetchItem *Itm) APT_OVERRIDE;
- virtual bool Configuration(std::string Message) APT_OVERRIDE;
-
- FTPConn *Server;
-
- static std::string FailFile;
- static int FailFd;
- static time_t FailTime;
- static APT_NORETURN void SigTerm(int);
-
- public:
-
- FtpMethod();
-};
-
-#endif
diff --git a/methods/rsh.cc b/methods/rsh.cc
deleted file mode 100644
index 25d2a3286..000000000
--- a/methods/rsh.cc
+++ /dev/null
@@ -1,561 +0,0 @@
-// -*- mode: cpp; mode: fold -*-
-// Description /*{{{*/
-/* ######################################################################
-
- RSH method - Transfer files via rsh compatible program
-
- Written by Ben Collins <bcollins@debian.org>, Copyright (c) 2000
-
- This file stated:
- Licensed under the GNU General Public License v2 [no exception clauses]
-
- We believe that this was intended to be not a statement against future
- versions of the GPL, but meant to exclude the Qt license exception in
- place in APT until that time.
-
- We received permission from Ben in 2021 to relicense under GPL-2+,
- contributions from Adam Heath and Daniel Hartwig may still have to
- be considered GPL-2 for the time being.
-
- Other contributions are GPL-2+
-
- See https://lists.debian.org/deity/2021/04/msg00013.html for details
-
- ##################################################################### */
- /*}}}*/
-// Include Files /*{{{*/
-#include <config.h>
-
-#include <apt-pkg/configuration.h>
-#include <apt-pkg/error.h>
-#include <apt-pkg/fileutl.h>
-#include <apt-pkg/hashes.h>
-#include <apt-pkg/strutl.h>
-
-#include "rsh.h"
-#include <cerrno>
-#include <csignal>
-#include <cstdarg>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <unistd.h>
-
-#include <apti18n.h>
- /*}}}*/
-
-unsigned long TimeOut = 30;
-Configuration::Item const *RshOptions = 0;
-time_t RSHMethod::FailTime = 0;
-std::string RSHMethod::FailFile;
-int RSHMethod::FailFd = -1;
-
-// RSHConn::RSHConn - Constructor /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-RSHConn::RSHConn(std::string const &pProg, URI Srv) : Len(0), WriteFd(-1), ReadFd(-1),
- ServerName(Srv), Prog(pProg), Process(-1) {
- Buffer[0] = '\0';
-}
- /*}}}*/
-// RSHConn::RSHConn - Destructor /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-RSHConn::~RSHConn()
-{
- Close();
-}
- /*}}}*/
-// RSHConn::Close - Forcibly terminate the connection /*{{{*/
-// ---------------------------------------------------------------------
-/* Often this is called when things have gone wrong to indicate that the
- connection is no longer usable. */
-void RSHConn::Close()
-{
- if (Process == -1)
- return;
-
- close(WriteFd);
- close(ReadFd);
- kill(Process,SIGINT);
- ExecWait(Process,"",true);
- WriteFd = -1;
- ReadFd = -1;
- Process = -1;
-}
- /*}}}*/
-// RSHConn::Open - Connect to a host /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-bool RSHConn::Open()
-{
- // Use the already open connection if possible.
- if (Process != -1)
- return true;
-
- if (Connect(ServerName.Host,ServerName.Port,ServerName.User) == false)
- return false;
-
- return true;
-}
- /*}}}*/
-// RSHConn::Connect - Fire up rsh and connect /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-bool RSHConn::Connect(std::string const &Host, unsigned int Port, std::string const &User)
-{
- char *PortStr = NULL;
- if (Port != 0)
- {
- if (asprintf (&PortStr, "%d", Port) == -1 || PortStr == NULL)
- return _error->Errno("asprintf", _("Failed"));
- }
-
- // Create the pipes
- int Pipes[4] = {-1,-1,-1,-1};
- if (pipe(Pipes) != 0 || pipe(Pipes+2) != 0)
- {
- _error->Errno("pipe",_("Failed to create IPC pipe to subprocess"));
- for (int I = 0; I != 4; I++)
- close(Pipes[I]);
- return false;
- }
- for (int I = 0; I != 4; I++)
- SetCloseExec(Pipes[I],true);
-
- Process = ExecFork();
-
- // The child
- if (Process == 0)
- {
- const char *Args[400];
- unsigned int i = 0;
-
- dup2(Pipes[1],STDOUT_FILENO);
- dup2(Pipes[2],STDIN_FILENO);
-
- // Probably should do
- // dup2(open("/dev/null",O_RDONLY),STDERR_FILENO);
-
- Args[i++] = Prog.c_str();
-
- // Insert user-supplied command line options
- Configuration::Item const *Opts = RshOptions;
- if (Opts != 0)
- {
- Opts = Opts->Child;
- for (; Opts != 0; Opts = Opts->Next)
- {
- if (Opts->Value.empty() == true)
- continue;
- Args[i++] = Opts->Value.c_str();
- }
- }
-
- if (User.empty() == false) {
- Args[i++] = "-l";
- Args[i++] = User.c_str();
- }
- if (PortStr != NULL) {
- Args[i++] = "-p";
- Args[i++] = PortStr;
- }
- if (Host.empty() == false) {
- Args[i++] = Host.c_str();
- }
- Args[i++] = "/bin/sh";
- Args[i] = 0;
- execvp(Args[0],(char **)Args);
- exit(100);
- }
-
- if (PortStr != NULL)
- free(PortStr);
-
- ReadFd = Pipes[0];
- WriteFd = Pipes[3];
- SetNonBlock(Pipes[0],true);
- SetNonBlock(Pipes[3],true);
- close(Pipes[1]);
- close(Pipes[2]);
-
- return true;
-}
-bool RSHConn::Connect(std::string const &Host, std::string const &User)
-{
- return Connect(Host, 0, User);
-}
- /*}}}*/
-// RSHConn::ReadLine - Very simple buffered read with timeout /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-bool RSHConn::ReadLine(std::string &Text)
-{
- if (Process == -1 || ReadFd == -1)
- return false;
-
- // Suck in a line
- while (Len < sizeof(Buffer))
- {
- // Scan the buffer for a new line
- for (unsigned int I = 0; I != Len; I++)
- {
- // Escape some special chars
- if (Buffer[I] == 0)
- Buffer[I] = '?';
-
- // End of line?
- if (Buffer[I] != '\n')
- continue;
-
- I++;
- Text = std::string(Buffer,I);
- memmove(Buffer,Buffer+I,Len - I);
- Len -= I;
- return true;
- }
-
- // Wait for some data..
- if (WaitFd(ReadFd,false,TimeOut) == false)
- {
- Close();
- return _error->Error(_("Connection timeout"));
- }
-
- // Suck it back
- int Res = read(ReadFd,Buffer + Len,sizeof(Buffer) - Len);
- if (Res <= 0)
- {
- _error->Errno("read",_("Read error"));
- Close();
- return false;
- }
- Len += Res;
- }
-
- return _error->Error(_("A response overflowed the buffer."));
-}
- /*}}}*/
-// RSHConn::WriteMsg - Send a message with optional remote sync. /*{{{*/
-// ---------------------------------------------------------------------
-/* The remote sync flag appends a || echo which will insert blank line
- once the command completes. */
-bool RSHConn::WriteMsg(std::string &Text,bool Sync,const char *Fmt,...)
-{
- va_list args;
- va_start(args,Fmt);
-
- // sprintf into a buffer
- char Tmp[1024];
- vsnprintf(Tmp,sizeof(Tmp),Fmt,args);
- va_end(args);
-
- // concat to create the real msg
- std::string Msg;
- if (Sync == true)
- Msg = std::string(Tmp) + " 2> /dev/null || echo\n";
- else
- Msg = std::string(Tmp) + " 2> /dev/null\n";
-
- // Send it off
- const char *S = Msg.c_str();
- unsigned long Len = strlen(S);
- unsigned long Start = 0;
- while (Len != 0)
- {
- if (WaitFd(WriteFd,true,TimeOut) == false)
- {
-
- Close();
- return _error->Error(_("Connection timeout"));
- }
-
- int Res = write(WriteFd,S + Start,Len);
- if (Res <= 0)
- {
- _error->Errno("write",_("Write error"));
- Close();
- return false;
- }
-
- Len -= Res;
- Start += Res;
- }
-
- if (Sync == true)
- return ReadLine(Text);
- return true;
-}
- /*}}}*/
-// RSHConn::Size - Return the size of the file /*{{{*/
-// ---------------------------------------------------------------------
-/* Right now for successful transfer the file size must be known in
- advance. */
-bool RSHConn::Size(const char *Path,unsigned long long &Size)
-{
- // Query the size
- std::string Msg;
- Size = 0;
-
- if (WriteMsg(Msg,true,"find %s -follow -printf '%%s\\n'",Path) == false)
- return false;
-
- // FIXME: Sense if the bad reply is due to a File Not Found.
-
- char *End;
- Size = strtoull(Msg.c_str(),&End,10);
- if (End == Msg.c_str())
- return _error->Error(_("File not found"));
- return true;
-}
- /*}}}*/
-// RSHConn::ModTime - Get the modification time in UTC /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-bool RSHConn::ModTime(const char *Path, time_t &Time)
-{
- Time = time(&Time);
- // Query the mod time
- std::string Msg;
-
- if (WriteMsg(Msg,true,"TZ=UTC find %s -follow -printf '%%TY%%Tm%%Td%%TH%%TM%%TS\\n'",Path) == false)
- return false;
-
- // Parse it
- return FTPMDTMStrToTime(Msg.c_str(), Time);
-}
- /*}}}*/
-// RSHConn::Get - Get a file /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-bool RSHConn::Get(const char *Path,FileFd &To,unsigned long long Resume,
- Hashes &Hash,bool &Missing, unsigned long long Size)
-{
- Missing = false;
-
- // Round to a 2048 byte block
- Resume = Resume - (Resume % 2048);
-
- if (To.Truncate(Resume) == false)
- return false;
- if (To.Seek(0) == false)
- return false;
-
- if (Resume != 0) {
- if (Hash.AddFD(To,Resume) == false) {
- _error->Errno("read",_("Problem hashing file"));
- return false;
- }
- }
-
- // FIXME: Detect file-not openable type errors.
- std::string Jnk;
- if (WriteMsg(Jnk,false,"dd if=%s bs=2048 skip=%u", Path, Resume / 2048) == false)
- return false;
-
- // Copy loop
- unsigned long long MyLen = Resume;
- unsigned char Buffer[APT_BUFFER_SIZE];
- while (MyLen < Size)
- {
- // Wait for some data..
- if (WaitFd(ReadFd,false,TimeOut) == false)
- {
- Close();
- return _error->Error(_("Data socket timed out"));
- }
-
- // Read the data..
- int Res = read(ReadFd,Buffer,sizeof(Buffer));
- if (Res == 0)
- {
- Close();
- return _error->Error(_("Connection closed prematurely"));
- }
-
- if (Res < 0)
- {
- if (errno == EAGAIN)
- continue;
- break;
- }
- MyLen += Res;
-
- Hash.Add(Buffer,Res);
- if (To.Write(Buffer,Res) == false)
- {
- Close();
- return false;
- }
- }
-
- return true;
-}
- /*}}}*/
-
-// RSHMethod::RSHMethod - Constructor /*{{{*/
-RSHMethod::RSHMethod(std::string &&pProg) : aptMethod(std::move(pProg),"1.0",SendConfig | SendURIEncoded)
-{
- signal(SIGTERM,SigTerm);
- signal(SIGINT,SigTerm);
- Server = 0;
- FailFd = -1;
-}
- /*}}}*/
-// RSHMethod::Configuration - Handle a configuration message /*{{{*/
-// ---------------------------------------------------------------------
-bool RSHMethod::Configuration(std::string Message)
-{
- // enabling privilege dropping for this method requires configuration…
- // … which is otherwise lifted straight from root, so use it by default.
- _config->Set(std::string("Binary::") + Binary + "::APT::Sandbox::User", "");
-
- if (aptMethod::Configuration(Message) == false)
- return false;
-
- std::string const timeconf = std::string("Acquire::") + Binary + "::Timeout";
- TimeOut = _config->FindI(timeconf, TimeOut);
- std::string const optsconf = std::string("Acquire::") + Binary + "::Options";
- RshOptions = _config->Tree(optsconf.c_str());
-
- return true;
-}
- /*}}}*/
-// RSHMethod::SigTerm - Clean up and timestamp the files on exit /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-void RSHMethod::SigTerm(int)
-{
- if (FailFd == -1)
- _exit(100);
-
- // Transfer the modification times
- struct timeval times[2];
- times[0].tv_sec = FailTime;
- times[1].tv_sec = FailTime;
- times[0].tv_usec = times[1].tv_usec = 0;
- utimes(FailFile.c_str(), times);
- close(FailFd);
-
- _exit(100);
-}
- /*}}}*/
-// RSHMethod::Fetch - Fetch a URI /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-bool RSHMethod::Fetch(FetchItem *Itm)
-{
- URI Get(Itm->Uri);
- auto const File = DecodeSendURI(Get.Path);
- FetchResult Res;
- Res.Filename = Itm->DestFile;
- Res.IMSHit = false;
-
- // Connect to the server
- if (Server == 0 || Server->Comp(Get) == false) {
- delete Server;
- Server = new RSHConn(Binary, Get);
- }
-
- // Could not connect is a transient error..
- if (Server->Open() == false) {
- Server->Close();
- Fail(true);
- return true;
- }
-
- // We say this mainly because the pause here is for the
- // ssh connection that is still going
- Status(_("Connecting to %s"), Get.Host.c_str());
-
- // Get the files information
- unsigned long long Size;
- if (not Server->Size(File.c_str(), Size) ||
- not Server->ModTime(File.c_str(), FailTime))
- {
- //Fail(true);
- //_error->Error(_("File not found")); // Will be handled by Size
- return false;
- }
- Res.Size = Size;
-
- // See if it is an IMS hit
- if (Itm->LastModified == FailTime) {
- Res.Size = 0;
- Res.IMSHit = true;
- URIDone(Res);
- return true;
- }
-
- // See if the file exists
- struct stat Buf;
- if (stat(Itm->DestFile.c_str(),&Buf) == 0) {
- if (Size == (unsigned long long)Buf.st_size && FailTime == Buf.st_mtime) {
- Res.Size = Buf.st_size;
- Res.LastModified = Buf.st_mtime;
- Res.ResumePoint = Buf.st_size;
- URIDone(Res);
- return true;
- }
-
- // Resume?
- if (FailTime == Buf.st_mtime && Size > (unsigned long long)Buf.st_size)
- Res.ResumePoint = Buf.st_size;
- }
-
- // Open the file
- Hashes Hash(Itm->ExpectedHashes);
- {
- FileFd Fd(Itm->DestFile,FileFd::WriteAny);
- if (_error->PendingError() == true)
- return false;
-
- URIStart(Res);
-
- FailFile = Itm->DestFile;
- (void)(FailFile.c_str()); // Make sure we don't do a malloc in the signal handler
- FailFd = Fd.Fd();
-
- bool Missing;
- if (not Server->Get(File.c_str(), Fd, Res.ResumePoint, Hash, Missing, Res.Size))
- {
- Fd.Close();
-
- // Timestamp
- struct timeval times[2];
- times[0].tv_sec = FailTime;
- times[1].tv_sec = FailTime;
- times[0].tv_usec = times[1].tv_usec = 0;
- utimes(FailFile.c_str(), times);
-
- // If the file is missing we hard fail otherwise transient fail
- if (Missing == true)
- return false;
- Fail(true);
- return true;
- }
-
- Res.Size = Fd.Size();
- struct timeval times[2];
- times[0].tv_sec = FailTime;
- times[1].tv_sec = FailTime;
- times[0].tv_usec = times[1].tv_usec = 0;
- utimes(Fd.Name().c_str(), times);
- FailFd = -1;
- }
-
- Res.LastModified = FailTime;
- Res.TakeHashes(Hash);
-
- URIDone(Res);
-
- return true;
-}
- /*}}}*/
-
-int main(int, const char *argv[])
-{
- return RSHMethod(flNotDir(argv[0])).Run();
-}
diff --git a/methods/rsh.h b/methods/rsh.h
deleted file mode 100644
index 82ac54319..000000000
--- a/methods/rsh.h
+++ /dev/null
@@ -1,75 +0,0 @@
-// -*- mode: cpp; mode: fold -*-
-// Description /*{{{*/
-/* ######################################################################
-
- RSH method - Transfer files via rsh compatible program
-
- ##################################################################### */
- /*}}}*/
-#ifndef APT_RSH_H
-#define APT_RSH_H
-
-#include <ctime>
-#include <string>
-
-#include <apt-pkg/strutl.h>
-
-class Hashes;
-class FileFd;
-
-class RSHConn
-{
- char Buffer[1024*10];
- unsigned long Len;
- int WriteFd;
- int ReadFd;
- URI ServerName;
- std::string const Prog;
-
- // Private helper functions
- bool ReadLine(std::string &Text);
-
- public:
-
- pid_t Process;
-
- // Raw connection IO
- bool WriteMsg(std::string &Text,bool Sync,const char *Fmt,...);
- bool Connect(std::string const &Host, std::string const &User);
- bool Connect(std::string const &Host, unsigned int Port, std::string const &User);
- bool Comp(URI Other) const {return Other.Host == ServerName.Host && Other.Port == ServerName.Port;};
-
- // Connection control
- bool Open();
- void Close();
-
- // Query
- bool Size(const char *Path,unsigned long long &Size);
- bool ModTime(const char *Path, time_t &Time);
- bool Get(const char *Path,FileFd &To,unsigned long long Resume,
- Hashes &Hash,bool &Missing, unsigned long long Size);
-
- RSHConn(std::string const &Prog, URI Srv);
- ~RSHConn();
-};
-
-#include "aptmethod.h"
-
-class RSHMethod : public aptMethod
-{
- virtual bool Fetch(FetchItem *Itm) APT_OVERRIDE;
- virtual bool Configuration(std::string Message) APT_OVERRIDE;
-
- RSHConn *Server;
-
- static std::string FailFile;
- static int FailFd;
- static time_t FailTime;
- static APT_NORETURN void SigTerm(int);
-
- public:
-
- explicit RSHMethod(std::string &&Prog);
-};
-
-#endif