From 3317ad864c997f4897756c0a2989c4199e9cda62 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Sat, 15 Jul 2017 14:12:50 +0200 Subject: use FileFd to parse all apt configuration files Using different ways of opening files means we have different behaviour and error messages for them, so by the same for all we can have more uniformity for users and apt developers alike. --- apt-pkg/contrib/configuration.cc | 23 ++++++----------------- apt-pkg/contrib/fileutl.cc | 32 +++++++++++++++++++++++++++++--- apt-pkg/contrib/fileutl.h | 22 ++++++++++++++++++++++ apt-pkg/policy.cc | 7 +++++-- apt-pkg/sourcelist.cc | 13 +++++++------ 5 files changed, 69 insertions(+), 28 deletions(-) (limited to 'apt-pkg') diff --git a/apt-pkg/contrib/configuration.cc b/apt-pkg/contrib/configuration.cc index 442e31dff..65242bec5 100644 --- a/apt-pkg/contrib/configuration.cc +++ b/apt-pkg/contrib/configuration.cc @@ -840,9 +840,9 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool const &AsSectio unsigned const &Depth) { // Open the stream for reading - ifstream F(FName.c_str(),ios::in); - if (F.fail() == true) - return _error->Errno("ifstream::ifstream",_("Opening configuration file %s"),FName.c_str()); + FileFd F; + if (OpenConfigurationFileFd(FName, F) == false) + return false; string LineBuffer; std::stack Stack; @@ -852,26 +852,15 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool const &AsSectio int CurLine = 0; bool InComment = false; - while (F.eof() == false) + while (F.Eof() == false) { // The raw input line. std::string Input; + if (F.ReadLine(Input) == false) + Input.clear(); // The input line with comments stripped. std::string Fragment; - // Grab the next line of F and place it in Input. - do - { - char *Buffer = new char[1024]; - - F.clear(); - F.getline(Buffer,sizeof(Buffer) / 2); - - Input += Buffer; - delete[] Buffer; - } - while (F.fail() && !F.eof()); - // Expand tabs in the input line and remove leading and trailing // whitespace. { diff --git a/apt-pkg/contrib/fileutl.cc b/apt-pkg/contrib/fileutl.cc index 630a98ce4..7633b07ef 100644 --- a/apt-pkg/contrib/fileutl.cc +++ b/apt-pkg/contrib/fileutl.cc @@ -2493,15 +2493,35 @@ bool FileFd::Read(int const Fd, void *To, unsigned long long Size, unsigned long } /*}}}*/ // FileFd::ReadLine - Read a complete line from the file /*{{{*/ -// --------------------------------------------------------------------- -/* Beware: This method can be quite slow for big buffers on UNcompressed - files because of the naive implementation! */ char* FileFd::ReadLine(char *To, unsigned long long const Size) { *To = '\0'; if (d == nullptr || Failed()) return nullptr; return d->InternalReadLine(To, Size); +} +bool FileFd::ReadLine(std::string &To) +{ + To.clear(); + if (d == nullptr || Failed()) + return false; + constexpr size_t buflen = 4096; + char buffer[buflen]; + size_t len; + do + { + if (d->InternalReadLine(buffer, buflen) == nullptr) + return false; + len = strlen(buffer); + To.append(buffer, len); + } while (len == buflen - 1 && buffer[len - 2] != '\n'); + // remove the newline at the end + auto const i = To.find_last_not_of("\r\n"); + if (i == std::string::npos) + To.clear(); + else + To.erase(i + 1); + return true; } /*}}}*/ // FileFd::Flush - Flush the file /*{{{*/ @@ -3104,3 +3124,9 @@ bool DropPrivileges() /*{{{*/ return true; } /*}}}*/ +bool OpenConfigurationFileFd(std::string const &File, FileFd &Fd) /*{{{*/ +{ + APT::Configuration::Compressor none(".", "", "", nullptr, nullptr, 0); + return Fd.Open(File, FileFd::ReadOnly, none); +} + /*}}}*/ diff --git a/apt-pkg/contrib/fileutl.h b/apt-pkg/contrib/fileutl.h index 5e857b5c8..06c303809 100644 --- a/apt-pkg/contrib/fileutl.h +++ b/apt-pkg/contrib/fileutl.h @@ -87,7 +87,28 @@ class FileFd } bool Read(void *To,unsigned long long Size,unsigned long long *Actual = 0); bool static Read(int const Fd, void *To, unsigned long long Size, unsigned long long * const Actual = 0); + /** read a complete line or until buffer is full + * + * The buffer will always be \\0 terminated, so at most Size-1 characters are read. + * If the buffer holds a complete line the last character (before \\0) will be + * the newline character \\n otherwise the line was longer than the buffer. + * + * @param To buffer which will hold the line + * @param Size of the buffer to fill + * @param \b nullptr is returned in error cases, otherwise + * the parameter \b To now filled with the line. + */ char* ReadLine(char *To, unsigned long long const Size); + /** read a complete line from the file + * + * Similar to std::getline() the string does \b not include + * the newline, but just the content of the line as the newline + * is not needed to distinguish cases as for the other #ReadLine method. + * + * @param To string which will hold the line + * @return \b true if successful, otherwise \b false + */ + bool ReadLine(std::string &To); bool Flush(); bool Write(const void *From,unsigned long long Size); bool static Write(int Fd, const void *From, unsigned long long Size); @@ -256,5 +277,6 @@ std::vector Glob(std::string const &pattern, int flags=0); bool Popen(const char* Args[], FileFd &Fd, pid_t &Child, FileFd::OpenMode Mode, bool CaptureStderr); bool Popen(const char* Args[], FileFd &Fd, pid_t &Child, FileFd::OpenMode Mode); +APT_HIDDEN bool OpenConfigurationFileFd(std::string const &File, FileFd &Fd); #endif diff --git a/apt-pkg/policy.cc b/apt-pkg/policy.cc index 008c98ecb..69c1fbe10 100644 --- a/apt-pkg/policy.cc +++ b/apt-pkg/policy.cc @@ -343,8 +343,11 @@ bool ReadPinFile(pkgPolicy &Plcy,string File) if (RealFileExists(File) == false) return true; - - FileFd Fd(File,FileFd::ReadOnly); + + FileFd Fd; + if (OpenConfigurationFileFd(File, Fd) == false) + return false; + pkgTagFile TF(&Fd, pkgTagFile::SUPPORT_COMMENTS); if (Fd.IsOpen() == false || Fd.Failed()) return false; diff --git a/apt-pkg/sourcelist.cc b/apt-pkg/sourcelist.cc index 17c5c7a11..9f0c7f8ae 100644 --- a/apt-pkg/sourcelist.cc +++ b/apt-pkg/sourcelist.cc @@ -368,13 +368,12 @@ bool pkgSourceList::ReadAppend(string const &File) /* */ bool pkgSourceList::ParseFileOldStyle(std::string const &File) { - // Open the stream for reading - ifstream F(File.c_str(),ios::in /*| ios::nocreate*/); - if (F.fail() == true) - return _error->Errno("ifstream::ifstream",_("Opening %s"),File.c_str()); + FileFd Fd; + if (OpenConfigurationFileFd(File, Fd) == false) + return false; std::string Buffer; - for (unsigned int CurLine = 1; std::getline(F, Buffer); ++CurLine) + for (unsigned int CurLine = 1; Fd.ReadLine(Buffer); ++CurLine) { // remove comments size_t curpos = 0; @@ -423,7 +422,9 @@ bool pkgSourceList::ParseFileOldStyle(std::string const &File) bool pkgSourceList::ParseFileDeb822(string const &File) { // see if we can read the file - FileFd Fd(File, FileFd::ReadOnly); + FileFd Fd; + if (OpenConfigurationFileFd(File, Fd) == false) + return false; pkgTagFile Sources(&Fd, pkgTagFile::SUPPORT_COMMENTS); if (Fd.IsOpen() == false || Fd.Failed()) return _error->Error(_("Malformed stanza %u in source list %s (type)"),0,File.c_str()); -- cgit v1.2.3 From 51751106976b1c6afa8f7991790db87b239fcc84 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Sat, 15 Jul 2017 15:08:35 +0200 Subject: show warnings instead of errors if files are unreadable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We used to fail on unreadable config/preferences/sources files, but at least for sources we didn't in the past and it seems harsh to refuse to work because of a single file, especially as the error messages are inconsistent and end up being silly (like suggesting to run apt update to fix the problem…). LP: #1701852 --- apt-pkg/cachefile.cc | 6 +++--- apt-pkg/contrib/configuration.cc | 11 ++++------- apt-pkg/contrib/fileutl.cc | 13 +++++++++++-- apt-pkg/contrib/fileutl.h | 1 + apt-pkg/init.cc | 20 +++++++++----------- apt-pkg/policy.cc | 6 +++--- apt-pkg/sourcelist.cc | 36 +++++++++++++----------------------- 7 files changed, 44 insertions(+), 49 deletions(-) (limited to 'apt-pkg') diff --git a/apt-pkg/cachefile.cc b/apt-pkg/cachefile.cc index 0116308e5..c070f4b9e 100644 --- a/apt-pkg/cachefile.cc +++ b/apt-pkg/cachefile.cc @@ -161,11 +161,11 @@ bool pkgCacheFile::BuildPolicy(OpProgress * /*Progress*/) if (_error->PendingError() == true) return false; - if (ReadPinFile(*Policy) == false || ReadPinDir(*Policy) == false) - return false; + ReadPinFile(*Policy); + ReadPinDir(*Policy); this->Policy = Policy.release(); - return true; + return _error->PendingError() == false; } /*}}}*/ // CacheFile::BuildDepCache - Open and build the dependency cache /*{{{*/ diff --git a/apt-pkg/contrib/configuration.cc b/apt-pkg/contrib/configuration.cc index 65242bec5..eb873bdba 100644 --- a/apt-pkg/contrib/configuration.cc +++ b/apt-pkg/contrib/configuration.cc @@ -1150,13 +1150,10 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool const &AsSectio bool ReadConfigDir(Configuration &Conf,const string &Dir, bool const &AsSectional, unsigned const &Depth) { - vector const List = GetListOfFilesInDir(Dir, "conf", true, true); - - // Read the files - for (vector::const_iterator I = List.begin(); I != List.end(); ++I) - if (ReadConfigFile(Conf,*I,AsSectional,Depth) == false) - return false; - return true; + bool good = true; + for (auto const &I : GetListOfFilesInDir(Dir, "conf", true, true)) + good = ReadConfigFile(Conf, I, AsSectional, Depth) && good; + return good; } /*}}}*/ // MatchAgainstConfig Constructor /*{{{*/ diff --git a/apt-pkg/contrib/fileutl.cc b/apt-pkg/contrib/fileutl.cc index 7633b07ef..33f4f7e09 100644 --- a/apt-pkg/contrib/fileutl.cc +++ b/apt-pkg/contrib/fileutl.cc @@ -402,7 +402,10 @@ std::vector GetListOfFilesInDir(string const &Dir, std::vector c DIR *D = opendir(Dir.c_str()); if (D == 0) { - _error->Errno("opendir",_("Unable to read %s"),Dir.c_str()); + if (errno == EACCES) + _error->WarningE("opendir", _("Unable to read %s"), Dir.c_str()); + else + _error->Errno("opendir", _("Unable to read %s"), Dir.c_str()); return List; } @@ -3126,7 +3129,13 @@ bool DropPrivileges() /*{{{*/ /*}}}*/ bool OpenConfigurationFileFd(std::string const &File, FileFd &Fd) /*{{{*/ { + int const fd = open(File.c_str(), O_RDONLY | O_CLOEXEC | O_NOCTTY); + if (fd == -1) + return _error->WarningE("open", _("Unable to read %s"), File.c_str()); APT::Configuration::Compressor none(".", "", "", nullptr, nullptr, 0); - return Fd.Open(File, FileFd::ReadOnly, none); + if (Fd.OpenDescriptor(fd, FileFd::ReadOnly, none) == false) + return false; + Fd.SetFileName(File); + return true; } /*}}}*/ diff --git a/apt-pkg/contrib/fileutl.h b/apt-pkg/contrib/fileutl.h index 06c303809..19b4ed49e 100644 --- a/apt-pkg/contrib/fileutl.h +++ b/apt-pkg/contrib/fileutl.h @@ -161,6 +161,7 @@ class FileFd inline bool Eof() {return (Flags & HitEof) == HitEof;}; inline bool IsCompressed() {return (Flags & Compressed) == Compressed;}; inline std::string &Name() {return FileName;}; + inline void SetFileName(std::string const &name) { FileName = name; }; FileFd(std::string FileName,unsigned int const Mode,unsigned long AccessMode = 0666); FileFd(std::string FileName,unsigned int const Mode, CompressMode Compress, unsigned long AccessMode = 0666); diff --git a/apt-pkg/init.cc b/apt-pkg/init.cc index af4e6faa0..207f0d902 100644 --- a/apt-pkg/init.cc +++ b/apt-pkg/init.cc @@ -212,14 +212,13 @@ bool pkgInitConfig(Configuration &Cnf) Cnf.CndSet("Acquire::Changelogs::URI::Origin::Ultimedia", "http://packages.ultimediaos.com/changelogs/pool/@CHANGEPATH@/changelog.txt"); Cnf.CndSet("Acquire::Changelogs::AlwaysOnline::Origin::Ubuntu", true); - bool Res = true; - // Read an alternate config file + _error->PushToStack(); const char *Cfg = getenv("APT_CONFIG"); if (Cfg != 0 && strlen(Cfg) != 0) { if (RealFileExists(Cfg) == true) - Res &= ReadConfigFile(Cnf,Cfg); + ReadConfigFile(Cnf, Cfg); else _error->WarningE("RealFileExists",_("Unable to read %s"),Cfg); } @@ -227,30 +226,29 @@ bool pkgInitConfig(Configuration &Cnf) // Read the configuration parts dir std::string const Parts = Cnf.FindDir("Dir::Etc::parts", "/dev/null"); if (DirectoryExists(Parts) == true) - Res &= ReadConfigDir(Cnf,Parts); + ReadConfigDir(Cnf, Parts); else if (APT::String::Endswith(Parts, "/dev/null") == false) _error->WarningE("DirectoryExists",_("Unable to read %s"),Parts.c_str()); // Read the main config file std::string const FName = Cnf.FindFile("Dir::Etc::main", "/dev/null"); if (RealFileExists(FName) == true) - Res &= ReadConfigFile(Cnf,FName); - - if (Res == false) - return false; + ReadConfigFile(Cnf, FName); if (Cnf.FindB("Debug::pkgInitConfig",false) == true) Cnf.Dump(); - + #ifdef APT_DOMAIN if (Cnf.Exists("Dir::Locale")) - { + { bindtextdomain(APT_DOMAIN,Cnf.FindDir("Dir::Locale").c_str()); bindtextdomain(textdomain(0),Cnf.FindDir("Dir::Locale").c_str()); } #endif - return true; + auto const good = _error->PendingError() == false; + _error->MergeWithStack(); + return good; } /*}}}*/ // pkgInitSystem - Initialize the _system calss /*{{{*/ diff --git a/apt-pkg/policy.cc b/apt-pkg/policy.cc index 69c1fbe10..030bab26b 100644 --- a/apt-pkg/policy.cc +++ b/apt-pkg/policy.cc @@ -324,10 +324,10 @@ bool ReadPinDir(pkgPolicy &Plcy,string Dir) return false; // Read the files + bool good = true; for (vector::const_iterator I = List.begin(); I != List.end(); ++I) - if (ReadPinFile(Plcy, *I) == false) - return false; - return true; + good = ReadPinFile(Plcy, *I) && good; + return good; } /*}}}*/ // ReadPinFile - Load the pin file into a Policy /*{{{*/ diff --git a/apt-pkg/sourcelist.cc b/apt-pkg/sourcelist.cc index 9f0c7f8ae..adf598e48 100644 --- a/apt-pkg/sourcelist.cc +++ b/apt-pkg/sourcelist.cc @@ -300,37 +300,32 @@ pkgSourceList::~pkgSourceList() /* */ bool pkgSourceList::ReadMainList() { - // CNC:2003-03-03 - Multiple sources list support. - bool Res = true; -#if 0 - Res = ReadVendors(); - if (Res == false) - return false; -#endif - Reset(); // CNC:2003-11-28 - Entries in sources.list have priority over // entries in sources.list.d. string Main = _config->FindFile("Dir::Etc::sourcelist", "/dev/null"); string Parts = _config->FindDir("Dir::Etc::sourceparts", "/dev/null"); - + + _error->PushToStack(); if (RealFileExists(Main) == true) - Res &= ReadAppend(Main); + ReadAppend(Main); else if (DirectoryExists(Parts) == false && APT::String::Endswith(Parts, "/dev/null") == false) // Only warn if there are no sources.list.d. _error->WarningE("DirectoryExists", _("Unable to read %s"), Parts.c_str()); if (DirectoryExists(Parts) == true) - Res &= ReadSourceDir(Parts); + ReadSourceDir(Parts); else if (Main.empty() == false && RealFileExists(Main) == false && APT::String::Endswith(Parts, "/dev/null") == false) // Only warn if there is no sources.list file. _error->WarningE("RealFileExists", _("Unable to read %s"), Main.c_str()); for (auto && file: _config->FindVector("APT::Sources::With")) - Res &= AddVolatileFile(file, nullptr); + AddVolatileFile(file, nullptr); - return Res; + auto good = _error->PendingError() == false; + _error->MergeWithStack(); + return good; } /*}}}*/ // SourceList::Reset - Clear the sourcelist contents /*{{{*/ @@ -498,17 +493,12 @@ bool pkgSourceList::GetIndexes(pkgAcquire *Owner, bool GetAll) const /* */ bool pkgSourceList::ReadSourceDir(string const &Dir) { - std::vector ext; - ext.push_back("list"); - ext.push_back("sources"); - std::vector const List = GetListOfFilesInDir(Dir, ext, true); - + std::vector const ext = {"list", "sources"}; // Read the files - for (vector::const_iterator I = List.begin(); I != List.end(); ++I) - if (ReadAppend(*I) == false) - return false; - return true; - + bool good = true; + for (auto const &I : GetListOfFilesInDir(Dir, ext, true)) + good = ReadAppend(I) && good; + return good; } /*}}}*/ // GetLastModified() /*{{{*/ -- cgit v1.2.3 From ea408c560ed85bb4ef7cf8f72f8463653501332c Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Fri, 7 Jul 2017 16:24:21 +0200 Subject: 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 --- apt-pkg/contrib/netrc.cc | 296 ++++++++++++++++++----------------------------- apt-pkg/contrib/netrc.h | 7 +- 2 files changed, 116 insertions(+), 187 deletions(-) (limited to 'apt-pkg') 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 #include +#include #include #include -#include -#include -#include -#include -#include -#include #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 #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 -- cgit v1.2.3 From 881ec045b6660e2fe0c6953720260e380ceeeb99 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Fri, 7 Jul 2017 22:21:44 +0200 Subject: allow the auth.conf to be root:root owned Opening the file before we drop privileges in the methods allows us to avoid chowning in the acquire main process which can apply to the wrong file (imagine Binary scoped settings) and surprises users as their permission setup is overridden. There are no security benefits as the file is open, so an evil method could as before read the contents of the file, but it isn't worse than before and we avoid permission problems in this setup. --- apt-pkg/acquire.cc | 15 --------------- 1 file changed, 15 deletions(-) (limited to 'apt-pkg') diff --git a/apt-pkg/acquire.cc b/apt-pkg/acquire.cc index 5e5e146a8..9272c2402 100644 --- a/apt-pkg/acquire.cc +++ b/apt-pkg/acquire.cc @@ -74,21 +74,6 @@ void pkgAcquire::Initialize() QueueMode = QueueHost; if (strcasecmp(Mode.c_str(),"access") == 0) QueueMode = QueueAccess; - - // chown the auth.conf file as it will be accessed by our methods - std::string const SandboxUser = _config->Find("APT::Sandbox::User"); - if (getuid() == 0 && SandboxUser.empty() == false && SandboxUser != "root") // if we aren't root, we can't chown, so don't try it - { - struct passwd const * const pw = getpwnam(SandboxUser.c_str()); - struct group const * const gr = getgrnam(ROOT_GROUP); - if (pw != NULL && gr != NULL) - { - std::string const AuthConf = _config->FindFile("Dir::Etc::netrc"); - if(AuthConf.empty() == false && RealFileExists(AuthConf) && - chown(AuthConf.c_str(), pw->pw_uid, gr->gr_gid) != 0) - _error->WarningE("SetupAPTPartialDirectory", "chown to %s:root of file %s failed", SandboxUser.c_str(), AuthConf.c_str()); - } - } } /*}}}*/ // Acquire::GetLock - lock directory and prepare for action /*{{{*/ -- cgit v1.2.3