summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMake/config.h.in1
-rw-r--r--apt-pkg/contrib/netrc.cc296
-rw-r--r--apt-pkg/contrib/netrc.h7
-rw-r--r--doc/CMakeLists.txt1
-rw-r--r--doc/apt_auth.conf.5.xml132
-rw-r--r--methods/aptmethod.h19
-rw-r--r--methods/basehttp.cc2
-rw-r--r--methods/basehttp.h2
-rw-r--r--methods/curl.cc2
-rw-r--r--methods/ftp.cc3
-rw-r--r--methods/http.cc5
-rwxr-xr-xtest/integration/test-authentication-basic1
-rw-r--r--test/libapt/authconf_test.cc223
13 files changed, 499 insertions, 195 deletions
diff --git a/CMake/config.h.in b/CMake/config.h.in
index ee822e204..f5a03eedd 100644
--- a/CMake/config.h.in
+++ b/CMake/config.h.in
@@ -68,6 +68,7 @@
#define APT_8_CLEANER_HEADERS
#define APT_9_CLEANER_HEADERS
#define APT_10_CLEANER_HEADERS
+#define APT_15_CLEANER_HEADERS
/* unrolling is faster combined with an optimizing compiler */
#define SHA2_UNROLL_TRANSFORM
diff --git a/apt-pkg/contrib/netrc.cc b/apt-pkg/contrib/netrc.cc
index 88027c989..27511d413 100644
--- a/apt-pkg/contrib/netrc.cc
+++ b/apt-pkg/contrib/netrc.cc
@@ -14,205 +14,129 @@
#include <config.h>
#include <apt-pkg/configuration.h>
+#include <apt-pkg/fileutl.h>
#include <apt-pkg/strutl.h>
#include <iostream>
-#include <pwd.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
#include "netrc.h"
-using std::string;
-
/* Get user and password from .netrc when given a machine name */
-
-enum {
- NOTHING,
- HOSTFOUND, /* the 'machine' keyword was found */
- HOSTCOMPLETE, /* the machine name following the keyword was found too */
- HOSTVALID, /* this is "our" machine! */
- HOSTEND /* LAST enum */
-};
-
-/* make sure we have room for at least this size: */
-#define LOGINSIZE 256
-#define PASSWORDSIZE 256
-#define NETRC DOT_CHAR "netrc"
-
-/* returns -1 on failure, 0 if the host is found, 1 is the host isn't found */
-static int parsenetrc_string (char *host, std::string &login, std::string &password, char *netrcfile = NULL)
+bool MaybeAddAuth(FileFd &NetRCFile, URI &Uri)
{
- FILE *file;
- int retcode = 1;
- int specific_login = (login.empty() == false);
- bool netrc_alloc = false;
-
- if (!netrcfile) {
- char const * home = getenv ("HOME"); /* portable environment reader */
-
- if (!home) {
- struct passwd *pw;
- pw = getpwuid (geteuid ());
- if(pw)
- home = pw->pw_dir;
- }
-
- if (!home)
- return -1;
-
- if (asprintf (&netrcfile, "%s%s%s", home, DIR_CHAR, NETRC) == -1 || netrcfile == NULL)
- return -1;
- else
- netrc_alloc = true;
- }
-
- file = fopen (netrcfile, "r");
- if(file) {
- char *tok;
- char *tok_buf;
- bool done = false;
- char *netrcbuffer = NULL;
- size_t netrcbuffer_size = 0;
-
- int state = NOTHING;
- char state_login = 0; /* Found a login keyword */
- char state_password = 0; /* Found a password keyword */
- int state_our_login = false; /* With specific_login,
- found *our* login name */
-
- while (!done && getline(&netrcbuffer, &netrcbuffer_size, file) != -1) {
- tok = strtok_r (netrcbuffer, " \t\n", &tok_buf);
- while (!done && tok) {
- if(login.empty() == false && password.empty() == false) {
- done = true;
- break;
- }
-
- switch(state) {
- case NOTHING:
- if (!strcasecmp ("machine", tok)) {
- /* the next tok is the machine name, this is in itself the
- delimiter that starts the stuff entered for this machine,
- after this we need to search for 'login' and
- 'password'. */
- state = HOSTFOUND;
- }
- break;
- case HOSTFOUND:
- /* extended definition of a "machine" if we have a "/"
- we match the start of the string (host.startswith(token) */
- if ((strchr(host, '/') && strstr(host, tok) == host) ||
- (!strcasecmp (host, tok))) {
- /* and yes, this is our host! */
- state = HOSTVALID;
- retcode = 0; /* we did find our host */
- }
- else
- /* not our host */
- state = NOTHING;
- break;
- case HOSTVALID:
- /* we are now parsing sub-keywords regarding "our" host */
- if (state_login) {
- if (specific_login)
- state_our_login = !strcasecmp (login.c_str(), tok);
- else
- login = tok;
- state_login = 0;
- } else if (state_password) {
- if (state_our_login || !specific_login)
- password = tok;
- state_password = 0;
- } else if (!strcasecmp ("login", tok))
- state_login = 1;
- else if (!strcasecmp ("password", tok))
- state_password = 1;
- else if(!strcasecmp ("machine", tok)) {
- /* ok, there's machine here go => */
- state = HOSTFOUND;
- state_our_login = false;
- }
- break;
- } /* switch (state) */
-
- tok = strtok_r (NULL, " \t\n", &tok_buf);
- } /* while(tok) */
- } /* while getline() */
-
- free(netrcbuffer);
- fclose(file);
- }
-
- if (netrc_alloc)
- free(netrcfile);
-
- return retcode;
-}
-
-void maybe_add_auth (URI &Uri, string NetRCFile)
-{
- if (_config->FindB("Debug::Acquire::netrc", false) == true)
- std::clog << "maybe_add_auth: " << (string)Uri
- << " " << NetRCFile << std::endl;
- if (Uri.Password.empty () == true || Uri.User.empty () == true)
- {
- if (NetRCFile.empty () == false)
- {
- std::string login, password;
- char *netrcfile = strdup(NetRCFile.c_str());
-
- // first check for a generic host based netrc entry
- char *host = strdup(Uri.Host.c_str());
- if (host && parsenetrc_string(host, login, password, netrcfile) == 0)
+ if (Uri.User.empty() == false || Uri.Password.empty() == false)
+ return true;
+ if (NetRCFile.IsOpen() == false || NetRCFile.Failed())
+ return false;
+ auto const Debug = _config->FindB("Debug::Acquire::netrc", false);
+
+ std::string lookfor;
+ if (Uri.Port != 0)
+ strprintf(lookfor, "%s:%i%s", Uri.Host.c_str(), Uri.Port, Uri.Path.c_str());
+ else
+ lookfor.append(Uri.Host).append(Uri.Path);
+
+ enum
+ {
+ NO,
+ MACHINE,
+ GOOD_MACHINE,
+ LOGIN,
+ PASSWORD
+ } active_token = NO;
+ std::string line;
+ while (NetRCFile.Eof() == false || line.empty() == false)
+ {
+ if (line.empty())
{
- if (_config->FindB("Debug::Acquire::netrc", false) == true)
- std::clog << "host: " << host
- << " user: " << login
- << " pass-size: " << password.size()
- << std::endl;
- Uri.User = login;
- Uri.Password = password;
- free(netrcfile);
- free(host);
- return;
+ if (NetRCFile.ReadLine(line) == false)
+ break;
+ else if (line.empty())
+ continue;
}
- free(host);
-
- // if host did not work, try Host+Path next, this will trigger
- // a lookup uri.startswith(host) in the netrc file parser (because
- // of the "/"
- char *hostpath = strdup((Uri.Host + Uri.Path).c_str());
- if (hostpath && parsenetrc_string(hostpath, login, password, netrcfile) == 0)
+ auto tokenend = line.find_first_of("\t ");
+ std::string token;
+ if (tokenend != std::string::npos)
+ {
+ token = line.substr(0, tokenend);
+ line.erase(0, tokenend + 1);
+ }
+ else
+ std::swap(line, token);
+ if (token.empty())
+ continue;
+ switch (active_token)
{
- if (_config->FindB("Debug::Acquire::netrc", false) == true)
- std::clog << "hostpath: " << hostpath
- << " user: " << login
- << " pass-size: " << password.size()
- << std::endl;
- Uri.User = login;
- Uri.Password = password;
+ case NO:
+ if (token == "machine")
+ active_token = MACHINE;
+ break;
+ case MACHINE:
+ if (token.find('/') == std::string::npos)
+ {
+ if (Uri.Port != 0 && Uri.Host == token)
+ active_token = GOOD_MACHINE;
+ else if (lookfor.compare(0, lookfor.length() - Uri.Path.length(), token) == 0)
+ active_token = GOOD_MACHINE;
+ else
+ active_token = NO;
+ }
+ else
+ {
+ if (APT::String::Startswith(lookfor, token))
+ active_token = GOOD_MACHINE;
+ else
+ active_token = NO;
+ }
+ break;
+ case GOOD_MACHINE:
+ if (token == "login")
+ active_token = LOGIN;
+ else if (token == "password")
+ active_token = PASSWORD;
+ else if (token == "machine")
+ {
+ if (Debug)
+ std::clog << "MaybeAddAuth: Found matching host adding '" << Uri.User << "' and '" << Uri.Password << "' for "
+ << (std::string)Uri << " from " << NetRCFile.Name() << std::endl;
+ return true;
+ }
+ break;
+ case LOGIN:
+ std::swap(Uri.User, token);
+ active_token = GOOD_MACHINE;
+ break;
+ case PASSWORD:
+ std::swap(Uri.Password, token);
+ active_token = GOOD_MACHINE;
+ break;
}
- free(netrcfile);
- free(hostpath);
- }
- }
+ }
+ if (active_token == GOOD_MACHINE)
+ {
+ if (Debug)
+ std::clog << "MaybeAddAuth: Found matching host adding '" << Uri.User << "' and '" << Uri.Password << "' for "
+ << (std::string)Uri << " from " << NetRCFile.Name() << std::endl;
+ return true;
+ }
+ else if (active_token == NO)
+ {
+ if (Debug)
+ std::clog << "MaybeAddAuth: Found no matching host for "
+ << (std::string)Uri << " from " << NetRCFile.Name() << std::endl;
+ return true;
+ }
+ else if (Debug)
+ std::clog << "MaybeAddAuth: Found no matching host (syntax error: " << active_token << ") for "
+ << (std::string)Uri << " from " << NetRCFile.Name() << std::endl;
+ return false;
}
-#ifdef DEBUG
-int main(int argc, char* argv[])
+void maybe_add_auth(URI &Uri, std::string NetRCFile)
{
- char login[64] = "";
- char password[64] = "";
-
- if(argc < 2)
- return -1;
-
- if(0 == parsenetrc (argv[1], login, password, argv[2])) {
- printf("HOST: %s LOGIN: %s PASSWORD: %s\n", argv[1], login, password);
- }
+ if (FileExists(NetRCFile) == false)
+ return;
+ FileFd fd;
+ if (fd.Open(NetRCFile, FileFd::ReadOnly))
+ MaybeAddAuth(fd, Uri);
}
-#endif
diff --git a/apt-pkg/contrib/netrc.h b/apt-pkg/contrib/netrc.h
index b5b56f5d4..46d8cab3d 100644
--- a/apt-pkg/contrib/netrc.h
+++ b/apt-pkg/contrib/netrc.h
@@ -22,10 +22,15 @@
#include <apt-pkg/strutl.h>
#endif
+#ifndef APT_15_CLEANER_HEADERS
#define DOT_CHAR "."
#define DIR_CHAR "/"
+#endif
class URI;
+class FileFd;
-void maybe_add_auth (URI &Uri, std::string NetRCFile);
+APT_DEPRECATED_MSG("Use FileFd-based MaybeAddAuth instead")
+void maybe_add_auth(URI &Uri, std::string NetRCFile);
+bool MaybeAddAuth(FileFd &NetRCFile, URI &Uri);
#endif
diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt
index a1491428f..d7241eb5e 100644
--- a/doc/CMakeLists.txt
+++ b/doc/CMakeLists.txt
@@ -66,6 +66,7 @@ endif()
add_docbook(apt-man MANPAGE ALL
DOCUMENTS
apt.8.xml
+ apt_auth.conf.5.xml
apt-cache.8.xml
apt-cdrom.8.xml
apt.conf.5.xml
diff --git a/doc/apt_auth.conf.5.xml b/doc/apt_auth.conf.5.xml
new file mode 100644
index 000000000..8a1882604
--- /dev/null
+++ b/doc/apt_auth.conf.5.xml
@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+ "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % aptent SYSTEM "apt.ent"> %aptent;
+<!ENTITY % aptverbatiment SYSTEM "apt-verbatim.ent"> %aptverbatiment;
+<!ENTITY % aptvendor SYSTEM "apt-vendor.ent"> %aptvendor;
+]>
+
+<refentry>
+
+ <refentryinfo>
+ &apt-author.team;
+ &apt-email;
+ &apt-product;
+ <!-- The last update date -->
+ <date>2017-07-07T00:00:00Z</date>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>apt_auth.conf</refentrytitle>
+ <manvolnum>5</manvolnum>
+ <refmiscinfo class="manual">APT</refmiscinfo>
+ </refmeta>
+
+ <!-- Man page title -->
+ <refnamediv>
+ <refname>apt_auth.conf</refname>
+ <refpurpose>Login configuration file for APT sources and proxies</refpurpose>
+ </refnamediv>
+
+<refsect1><title>Description</title>
+<para>APT configuration files like &sources-list; or &apt-conf; need to be accessible
+for everyone using apt tools on the system to have access to all package-related
+information like the available packages in a repository. Login information
+needed to connect to a proxy or to download data from a repository on the other
+hand shouldn't always be accessible by everyone and can hence not be placed in a
+file with world-readable file permissions.</para>
+
+<para>The APT auth.conf file <filename>/etc/apt/auth.conf</filename> can be used to store
+login information in a netrc-like format with restrictive file permissions.</para>
+</refsect1>
+
+<refsect1><title>netrc-like format</title>
+<para>The format defined here is similar to the format of the <filename>~/.netrc</filename>
+file used by <citerefentry><refentrytitle><command>ftp</command></refentrytitle><manvolnum>1</manvolnum></citerefentry>
+and similar programs interacting with servers.
+It is a simple token-based format with the following tokens being recognized;
+Unknown tokens will be ignored. Tokens may be separated by spaces, tabs or newlines.</para>
+
+<variablelist>
+<varlistentry>
+<term><literal>machine</literal> <replaceable>hostname</replaceable>[:<replaceable>port</replaceable>][/<replaceable>path</replaceable>]</term>
+<listitem><para>Entries are looked up by searching for the
+<emphasis><literal>machine</literal></emphasis> token matching the
+hostname of the URI apt needs login information for. Extending the netrc-format
+a portnumber can be specified. If no port is given the token matches for all ports.
+Similar the path is optional and only needed and useful if multiple repositories with
+different login information reside on the same server. A machine token with a path
+matches if the path in the URI starts with the path given in the token.
+Once a match is made, the subsequent tokens are processed, stopping when the
+end of file is reached or another <emphasis><literal>machine</literal></emphasis>
+token is encountered.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><literal>login</literal> <replaceable>name</replaceable></term>
+<listitem><para>The username to be used.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><literal>password</literal> <replaceable>string</replaceable></term>
+<listitem><para>The password to be used.</para></listitem>
+</varlistentry>
+
+</variablelist>
+
+</refsect1>
+
+<refsect1><title>Example</title>
+<para>Supplying login information for a user named <literal>apt</literal>
+with the password <literal>debian</literal> for the &sources-list; entry
+<literallayout>deb http://example.org/debian &debian-stable-codename; main</literallayout>
+could be done in the entry directly:
+<literallayout>deb http://apt:debian@example.org/debian &debian-stable-codename; main</literallayout>
+Alternatively an entry like the following in the auth.conf file could be used:
+<literallayout>machine example.org
+login apt
+password debian</literallayout>
+Or alternatively within a single line:
+<literallayout>machine example.org login apt password debian</literallayout>
+If you need to be more specific all of these lines will also apply to the example entry:</para>
+<literallayout>machine example.org/deb login apt password debian
+machine example.org/debian login apt password debian
+machine example.org/debian/ login apt password debian
+</literallayout>
+On the other hand neither of the following lines apply:
+<literallayout>machine example.org:80 login apt password debian
+machine example.org/deb/ login apt password debian
+machine example.org/ubuntu login apt password debian
+machine example.orga login apt password debian
+machine example.net login apt password debian
+</literallayout>
+</refsect1>
+
+<refsect1><title>Notes</title>
+<para>Basic support for this feature is present since version 0.7.25, but was
+undocumented for years. The documentation was added in version 1.5 changing
+also the implementation slightly. For maximum backward compatibility you should
+avoid multiple <literal>machine</literal> tokens with the same hostname, but if
+you need multiple they should all have a path specified in the
+<literal>machine</literal> token.</para>
+</refsect1>
+
+<refsect1>
+<title>Files</title>
+ <variablelist>
+ <varlistentry><term><filename>/etc/apt/auth.conf</filename></term>
+ <listitem><para>Login information for APT sources and proxies in a netrc-like format.
+ Configuration Item: <literal>Dir::Etc::netrc</literal>.</para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+<refsect1>
+<title>See Also</title>
+<para>&apt-conf; &sources-list;
+</para>
+</refsect1>
+
+ &manbugs;
+
+</refentry>
diff --git a/methods/aptmethod.h b/methods/aptmethod.h
index 04858e29d..a9af63fb7 100644
--- a/methods/aptmethod.h
+++ b/methods/aptmethod.h
@@ -5,6 +5,7 @@
#include <apt-pkg/configuration.h>
#include <apt-pkg/error.h>
#include <apt-pkg/fileutl.h>
+#include <apt-pkg/netrc.h>
#include <algorithm>
#include <locale>
@@ -42,6 +43,24 @@ public:
return true;
}
+ bool MaybeAddAuthTo(URI &uri)
+ {
+ if (uri.User.empty() == false || uri.Password.empty() == false)
+ return true;
+ auto const netrc = _config->FindFile("Dir::Etc::netrc");
+ if (netrc.empty() == true)
+ return true;
+ // ignore errors with opening the auth file as it doesn't need to exist
+ _error->PushToStack();
+ FileFd authconf(netrc, FileFd::ReadOnly);
+ _error->RevertToStack();
+ if (authconf.IsOpen() == false)
+ return true;
+ if (authconf.Seek(0) == false)
+ return false;
+ return MaybeAddAuth(authconf, uri);
+ }
+
bool CalculateHashes(FetchItem const * const Itm, FetchResult &Res) const APT_NONNULL(2)
{
Hashes Hash(Itm->ExpectedHashes);
diff --git a/methods/basehttp.cc b/methods/basehttp.cc
index cc5039c75..03409a8d4 100644
--- a/methods/basehttp.cc
+++ b/methods/basehttp.cc
@@ -845,7 +845,7 @@ bool BaseHttpMethod::Configuration(std::string Message) /*{{{*/
return true;
}
/*}}}*/
-bool BaseHttpMethod::AddProxyAuth(URI &Proxy, URI const &Server) const /*{{{*/
+bool BaseHttpMethod::AddProxyAuth(URI &Proxy, URI const &Server) /*{{{*/
{
if (std::find(methodNames.begin(), methodNames.end(), "tor") != methodNames.end() &&
Proxy.User == "apt-transport-tor" && Proxy.Password.empty())
diff --git a/methods/basehttp.h b/methods/basehttp.h
index 7000e7b89..d2e085968 100644
--- a/methods/basehttp.h
+++ b/methods/basehttp.h
@@ -164,7 +164,7 @@ class BaseHttpMethod : public aptMethod
virtual void RotateDNS() = 0;
virtual bool Configuration(std::string Message) APT_OVERRIDE;
- bool AddProxyAuth(URI &Proxy, URI const &Server) const;
+ bool AddProxyAuth(URI &Proxy, URI const &Server);
BaseHttpMethod(std::string &&Binary, char const * const Ver,unsigned long const Flags);
virtual ~BaseHttpMethod() {};
diff --git a/methods/curl.cc b/methods/curl.cc
index 71149217a..8e06d858d 100644
--- a/methods/curl.cc
+++ b/methods/curl.cc
@@ -270,7 +270,7 @@ bool HttpsMethod::Fetch(FetchItem *Itm)
if (SetupProxy() == false)
return _error->Error("Unsupported proxy configured: %s", URI::SiteOnly(Proxy).c_str());
- maybe_add_auth (Uri, _config->FindFile("Dir::Etc::netrc"));
+ MaybeAddAuthTo(Uri);
if (Server == nullptr || Server->Comp(Itm->Uri) == false)
Server = CreateServerState(Itm->Uri);
diff --git a/methods/ftp.cc b/methods/ftp.cc
index 4972337e3..c5c4001fa 100644
--- a/methods/ftp.cc
+++ b/methods/ftp.cc
@@ -21,7 +21,6 @@
#include <apt-pkg/error.h>
#include <apt-pkg/fileutl.h>
#include <apt-pkg/hashes.h>
-#include <apt-pkg/netrc.h>
#include <apt-pkg/strutl.h>
#include <iostream>
@@ -1015,7 +1014,7 @@ bool FtpMethod::Fetch(FetchItem *Itm)
Res.Filename = Itm->DestFile;
Res.IMSHit = false;
- maybe_add_auth (Get, _config->FindFile("Dir::Etc::netrc"));
+ MaybeAddAuthTo(Get);
// Connect to the server
if (Server == 0 || Server->Comp(Get) == false)
diff --git a/methods/http.cc b/methods/http.cc
index db4542981..f0cd77139 100644
--- a/methods/http.cc
+++ b/methods/http.cc
@@ -23,7 +23,6 @@
#include <apt-pkg/error.h>
#include <apt-pkg/fileutl.h>
#include <apt-pkg/hashes.h>
-#include <apt-pkg/netrc.h>
#include <apt-pkg/proxy.h>
#include <apt-pkg/strutl.h>
@@ -350,7 +349,7 @@ bool UnwrapHTTPConnect(std::string Host, int Port, URI Proxy, std::unique_ptr<Me
Req << "Host: " << ProperHost << "\r\n";
;
- maybe_add_auth(Proxy, _config->FindFile("Dir::Etc::netrc"));
+ Owner->MaybeAddAuthTo(Proxy);
if (Proxy.User.empty() == false || Proxy.Password.empty() == false)
Req << "Proxy-Authorization: Basic "
<< Base64Encode(Proxy.User + ":" + Proxy.Password) << "\r\n";
@@ -931,7 +930,7 @@ void HttpMethod::SendReq(FetchItem *Itm)
Req << "Proxy-Authorization: Basic "
<< Base64Encode(Server->Proxy.User + ":" + Server->Proxy.Password) << "\r\n";
- maybe_add_auth (Uri, _config->FindFile("Dir::Etc::netrc"));
+ MaybeAddAuthTo(Uri);
if (Uri.User.empty() == false || Uri.Password.empty() == false)
Req << "Authorization: Basic "
<< Base64Encode(Uri.User + ":" + Uri.Password) << "\r\n";
diff --git a/test/integration/test-authentication-basic b/test/integration/test-authentication-basic
index 3bfd076ce..e724e243e 100755
--- a/test/integration/test-authentication-basic
+++ b/test/integration/test-authentication-basic
@@ -13,6 +13,7 @@ setupaptarchive --no-update
changetohttpswebserver --authorization="$(printf '%s' 'star@irc:hunter2' | base64 )"
echo 'See, when YOU type hunter2, it shows to us as *******' > aptarchive/bash
+echo 'Debug::Acquire::netrc "true";' > rootdir/etc/apt/apt.conf.d/netrcdebug.conf
testauthfailure() {
testfailure apthelper download-file "${1}/bash" ./downloaded/bash
diff --git a/test/libapt/authconf_test.cc b/test/libapt/authconf_test.cc
new file mode 100644
index 000000000..10d818ec9
--- /dev/null
+++ b/test/libapt/authconf_test.cc
@@ -0,0 +1,223 @@
+#include <config.h>
+
+#include <apt-pkg/fileutl.h>
+#include <apt-pkg/netrc.h>
+#include <apt-pkg/strutl.h>
+
+#include <string>
+
+#include <gtest/gtest.h>
+
+#include "file-helpers.h"
+
+TEST(NetRCTest, Parsing)
+{
+ FileFd fd;
+ URI U("http://file.not/open");
+ EXPECT_FALSE(MaybeAddAuth(fd, U));
+ EXPECT_TRUE(U.User.empty());
+ EXPECT_TRUE(U.Password.empty());
+ EXPECT_EQ("file.not", U.Host);
+ EXPECT_EQ("/open", U.Path);
+
+ createTemporaryFile("doublesignedfile", fd, nullptr, R"apt(
+machine example.netter login bar password foo
+machine example.net login foo password bar
+
+machine example.org:90 login apt password apt
+machine example.org:8080
+login
+example password foobar
+
+machine example.org
+login anonymous
+password pass
+
+machine example.com/foo login user1 unknown token password pass1
+machine example.com/bar password pass2 login user2
+ unknown token
+machine example.com/user login user
+machine example.netter login unused password firstentry
+machine example.last/debian login debian password rules)apt");
+ U = URI("http://example.net/foo");
+ EXPECT_TRUE(MaybeAddAuth(fd, U));
+ EXPECT_EQ("foo", U.User);
+ EXPECT_EQ("bar", U.Password);
+ EXPECT_EQ("example.net", U.Host);
+ EXPECT_EQ("/foo", U.Path);
+
+ EXPECT_TRUE(fd.Seek(0));
+ U = URI("http://user:pass@example.net/foo");
+ EXPECT_TRUE(MaybeAddAuth(fd, U));
+ EXPECT_EQ("user", U.User);
+ EXPECT_EQ("pass", U.Password);
+ EXPECT_EQ("example.net", U.Host);
+ EXPECT_EQ("/foo", U.Path);
+
+ EXPECT_TRUE(fd.Seek(0));
+ U = URI("http://example.org:90/foo");
+ EXPECT_TRUE(MaybeAddAuth(fd, U));
+ EXPECT_EQ("apt", U.User);
+ EXPECT_EQ("apt", U.Password);
+ EXPECT_EQ("example.org", U.Host);
+ EXPECT_EQ(90, U.Port);
+ EXPECT_EQ("/foo", U.Path);
+
+ EXPECT_TRUE(fd.Seek(0));
+ U = URI("http://example.org:8080/foo");
+ EXPECT_TRUE(MaybeAddAuth(fd, U));
+ EXPECT_EQ("example", U.User);
+ EXPECT_EQ("foobar", U.Password);
+
+ EXPECT_TRUE(fd.Seek(0));
+ U = URI("http://example.net:42/foo");
+ EXPECT_TRUE(MaybeAddAuth(fd, U));
+ EXPECT_EQ("foo", U.User);
+ EXPECT_EQ("bar", U.Password);
+
+ EXPECT_TRUE(fd.Seek(0));
+ U = URI("http://example.org/foo");
+ EXPECT_TRUE(MaybeAddAuth(fd, U));
+ EXPECT_EQ("anonymous", U.User);
+ EXPECT_EQ("pass", U.Password);
+
+ EXPECT_TRUE(fd.Seek(0));
+ U = URI("http://example.com/apt");
+ EXPECT_TRUE(MaybeAddAuth(fd, U));
+ EXPECT_TRUE(U.User.empty());
+ EXPECT_TRUE(U.Password.empty());
+
+ EXPECT_TRUE(fd.Seek(0));
+ U = URI("http://example.com/foo");
+ EXPECT_TRUE(MaybeAddAuth(fd, U));
+ EXPECT_EQ("user1", U.User);
+ EXPECT_EQ("pass1", U.Password);
+
+ EXPECT_TRUE(fd.Seek(0));
+ U = URI("http://example.com/fooo");
+ EXPECT_TRUE(MaybeAddAuth(fd, U));
+ EXPECT_EQ("user1", U.User);
+ EXPECT_EQ("pass1", U.Password);
+
+ EXPECT_TRUE(fd.Seek(0));
+ U = URI("http://example.com/fo");
+ EXPECT_TRUE(MaybeAddAuth(fd, U));
+ EXPECT_TRUE(U.User.empty());
+ EXPECT_TRUE(U.Password.empty());
+
+ EXPECT_TRUE(fd.Seek(0));
+ U = URI("http://example.com/bar");
+ EXPECT_TRUE(MaybeAddAuth(fd, U));
+ EXPECT_EQ("user2", U.User);
+ EXPECT_EQ("pass2", U.Password);
+
+ EXPECT_TRUE(fd.Seek(0));
+ U = URI("http://example.com/user");
+ EXPECT_TRUE(MaybeAddAuth(fd, U));
+ EXPECT_EQ("user", U.User);
+ EXPECT_TRUE(U.Password.empty());
+
+ EXPECT_TRUE(fd.Seek(0));
+ U = URI("socks5h://example.last/debian");
+ EXPECT_TRUE(MaybeAddAuth(fd, U));
+ EXPECT_EQ("debian", U.User);
+ EXPECT_EQ("rules", U.Password);
+
+ EXPECT_TRUE(fd.Seek(0));
+ U = URI("socks5h://example.debian/");
+ EXPECT_TRUE(MaybeAddAuth(fd, U));
+ EXPECT_TRUE(U.User.empty());
+ EXPECT_TRUE(U.Password.empty());
+
+ EXPECT_TRUE(fd.Seek(0));
+ U = URI("socks5h://user:pass@example.debian/");
+ EXPECT_TRUE(MaybeAddAuth(fd, U));
+ EXPECT_EQ("user", U.User);
+ EXPECT_EQ("pass", U.Password);
+}
+TEST(NetRCTest, BadFileNoMachine)
+{
+ FileFd fd;
+ createTemporaryFile("doublesignedfile", fd, nullptr, R"apt(
+foo example.org login foo1 password bar
+machin example.org login foo2 password bar
+machine2 example.org login foo3 password bar
+)apt");
+
+ URI U("http://example.org/foo");
+ EXPECT_TRUE(MaybeAddAuth(fd, U));
+ EXPECT_TRUE(U.User.empty());
+ EXPECT_TRUE(U.Password.empty());
+}
+TEST(NetRCTest, BadFileEndsMachine)
+{
+ FileFd fd;
+ createTemporaryFile("doublesignedfile", fd, nullptr, R"apt(
+machine example.org login foo1 password bar
+machine)apt");
+
+ URI U("http://example.org/foo");
+ EXPECT_TRUE(MaybeAddAuth(fd, U));
+ EXPECT_EQ("foo1", U.User);
+ EXPECT_EQ("bar", U.Password);
+
+ EXPECT_TRUE(fd.Seek(0));
+ U = URI("http://example.net/foo");
+ EXPECT_FALSE(MaybeAddAuth(fd, U));
+ EXPECT_TRUE(U.User.empty());
+ EXPECT_TRUE(U.Password.empty());
+
+ EXPECT_TRUE(fd.Seek(0));
+ U = URI("http://foo:bar@example.net/foo");
+ EXPECT_TRUE(MaybeAddAuth(fd, U));
+ EXPECT_EQ("foo", U.User);
+ EXPECT_EQ("bar", U.Password);
+}
+TEST(NetRCTest, BadFileEndsLogin)
+{
+ FileFd fd;
+ createTemporaryFile("doublesignedfile", fd, nullptr, R"apt(
+machine example.org login foo1 password bar
+machine example.net login)apt");
+
+ URI U("http://example.org/foo");
+ EXPECT_TRUE(MaybeAddAuth(fd, U));
+ EXPECT_EQ("foo1", U.User);
+ EXPECT_EQ("bar", U.Password);
+
+ EXPECT_TRUE(fd.Seek(0));
+ U = URI("http://example.net/foo");
+ EXPECT_FALSE(MaybeAddAuth(fd, U));
+ EXPECT_TRUE(U.User.empty());
+ EXPECT_TRUE(U.Password.empty());
+
+ EXPECT_TRUE(fd.Seek(0));
+ U = URI("http://foo:bar@example.net/foo");
+ EXPECT_TRUE(MaybeAddAuth(fd, U));
+ EXPECT_EQ("foo", U.User);
+ EXPECT_EQ("bar", U.Password);
+}
+TEST(NetRCTest, BadFileEndsPassword)
+{
+ FileFd fd;
+ createTemporaryFile("doublesignedfile", fd, nullptr, R"apt(
+machine example.org login foo1 password bar
+machine example.net password)apt");
+
+ URI U("http://example.org/foo");
+ EXPECT_TRUE(MaybeAddAuth(fd, U));
+ EXPECT_EQ("foo1", U.User);
+ EXPECT_EQ("bar", U.Password);
+
+ EXPECT_TRUE(fd.Seek(0));
+ U = URI("http://example.net/foo");
+ EXPECT_FALSE(MaybeAddAuth(fd, U));
+ EXPECT_TRUE(U.User.empty());
+ EXPECT_TRUE(U.Password.empty());
+
+ EXPECT_TRUE(fd.Seek(0));
+ U = URI("http://foo:bar@example.net/foo");
+ EXPECT_TRUE(MaybeAddAuth(fd, U));
+ EXPECT_EQ("foo", U.User);
+ EXPECT_EQ("bar", U.Password);
+}