diff options
-rw-r--r-- | CMake/config.h.in | 1 | ||||
-rw-r--r-- | apt-pkg/contrib/netrc.cc | 296 | ||||
-rw-r--r-- | apt-pkg/contrib/netrc.h | 7 | ||||
-rw-r--r-- | doc/CMakeLists.txt | 1 | ||||
-rw-r--r-- | doc/apt_auth.conf.5.xml | 132 | ||||
-rw-r--r-- | methods/aptmethod.h | 19 | ||||
-rw-r--r-- | methods/basehttp.cc | 2 | ||||
-rw-r--r-- | methods/basehttp.h | 2 | ||||
-rw-r--r-- | methods/curl.cc | 2 | ||||
-rw-r--r-- | methods/ftp.cc | 3 | ||||
-rw-r--r-- | methods/http.cc | 5 | ||||
-rwxr-xr-x | test/integration/test-authentication-basic | 1 | ||||
-rw-r--r-- | test/libapt/authconf_test.cc | 223 |
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); +} |