Browse Source

reimplement and document auth.conf

We have support for an netrc-like auth.conf file since 0.7.25 (closing
518473), but it was never documented in apt that it even exists and
netrc seems to have fallen out of usage as a manpage for it no longer
exists making the feature even more arcane.

On top of that the code was a bit of a mess (as it is written in c-style)
and as a result the matching of machine tokens to URIs also a bit
strange by checking for less specific matches (= without path) first.
We now do a single pass over the stanzas.

In practice early adopters of the undocumented implementation will not
really notice the differences and the 'new' behaviour is simpler to
document and more usual for an apt user.

Closes: #811181
tags/debian/1.5_beta2
David Kalnischkies 4 years ago
parent
commit
ea408c560e
13 changed files with 499 additions and 195 deletions
  1. +1
    -0
      CMake/config.h.in
  2. +110
    -186
      apt-pkg/contrib/netrc.cc
  3. +6
    -1
      apt-pkg/contrib/netrc.h
  4. +1
    -0
      doc/CMakeLists.txt
  5. +132
    -0
      doc/apt_auth.conf.5.xml
  6. +19
    -0
      methods/aptmethod.h
  7. +1
    -1
      methods/basehttp.cc
  8. +1
    -1
      methods/basehttp.h
  9. +1
    -1
      methods/curl.cc
  10. +1
    -2
      methods/ftp.cc
  11. +2
    -3
      methods/http.cc
  12. +1
    -0
      test/integration/test-authentication-basic
  13. +223
    -0
      test/libapt/authconf_test.cc

+ 1
- 0
CMake/config.h.in View File

@@ -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

+ 110
- 186
apt-pkg/contrib/netrc.cc View File

@@ -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

+ 6
- 1
apt-pkg/contrib/netrc.h View File

@@ -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

+ 1
- 0
doc/CMakeLists.txt View File

@@ -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


+ 132
- 0
doc/apt_auth.conf.5.xml View File

@@ -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>

+ 19
- 0
methods/aptmethod.h View File

@@ -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);


+ 1
- 1
methods/basehttp.cc View File

@@ -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())


+ 1
- 1
methods/basehttp.h View File

@@ -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() {};


+ 1
- 1
methods/curl.cc View File

@@ -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);



+ 1
- 2
methods/ftp.cc View File

@@ -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)


+ 2
- 3
methods/http.cc View File

@@ -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";


+ 1
- 0
test/integration/test-authentication-basic View File

@@ -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


+ 223
- 0
test/libapt/authconf_test.cc View File

@@ -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);
}

Loading…
Cancel
Save