diff options
author | Michael Vogt <mvo@ubuntu.com> | 2014-10-06 17:42:39 +0200 |
---|---|---|
committer | Michael Vogt <mvo@ubuntu.com> | 2014-10-06 17:42:39 +0200 |
commit | a2d40703e4a5590a689ace4466f92e590434944d (patch) | |
tree | 5e878fcc11eb94d96c65940ef3d30e922f217950 /apt-pkg/contrib | |
parent | ffd2dd93a640b47663ebdccc4fda00b426b3db71 (diff) | |
parent | 00a06b8eb82cf930511fc003bd16d7034e5a0cb5 (diff) |
make http size check work
Diffstat (limited to 'apt-pkg/contrib')
-rw-r--r-- | apt-pkg/contrib/cmndline.cc | 19 | ||||
-rw-r--r-- | apt-pkg/contrib/configuration.cc | 5 | ||||
-rw-r--r-- | apt-pkg/contrib/configuration.h | 14 | ||||
-rw-r--r-- | apt-pkg/contrib/fileutl.cc | 107 | ||||
-rw-r--r-- | apt-pkg/contrib/fileutl.h | 16 | ||||
-rw-r--r-- | apt-pkg/contrib/gpgv.cc | 63 | ||||
-rw-r--r-- | apt-pkg/contrib/hashes.cc | 4 | ||||
-rw-r--r-- | apt-pkg/contrib/macros.h | 2 | ||||
-rw-r--r-- | apt-pkg/contrib/proxy.cc | 86 | ||||
-rw-r--r-- | apt-pkg/contrib/proxy.h | 16 | ||||
-rw-r--r-- | apt-pkg/contrib/strutl.cc | 80 | ||||
-rw-r--r-- | apt-pkg/contrib/strutl.h | 6 |
12 files changed, 324 insertions, 94 deletions
diff --git a/apt-pkg/contrib/cmndline.cc b/apt-pkg/contrib/cmndline.cc index 3799c822d..93c1f4664 100644 --- a/apt-pkg/contrib/cmndline.cc +++ b/apt-pkg/contrib/cmndline.cc @@ -47,23 +47,26 @@ CommandLine::~CommandLine() char const * CommandLine::GetCommand(Dispatch const * const Map, unsigned int const argc, char const * const * const argv) { - // if there is a -- on the line there must be the word we search for around it - // as -- marks the end of the options, just not sure if the command can be - // considered an option or not, so accept both + // if there is a -- on the line there must be the word we search for either + // before it (as -- marks the end of the options) or right after it (as we can't + // decide if the command is actually an option, given that in theory, you could + // have parameters named like commands) for (size_t i = 1; i < argc; ++i) { if (strcmp(argv[i], "--") != 0) continue; - ++i; - if (i < argc) + // check if command is before -- + for (size_t k = 1; k < i; ++k) for (size_t j = 0; Map[j].Match != NULL; ++j) - if (strcmp(argv[i], Map[j].Match) == 0) + if (strcmp(argv[k], Map[j].Match) == 0) return Map[j].Match; - i -= 2; - if (i != 0) + // see if the next token after -- is the command + ++i; + if (i < argc) for (size_t j = 0; Map[j].Match != NULL; ++j) if (strcmp(argv[i], Map[j].Match) == 0) return Map[j].Match; + // we found a --, but not a command return NULL; } // no --, so search for the first word matching a command diff --git a/apt-pkg/contrib/configuration.cc b/apt-pkg/contrib/configuration.cc index fbe180f8e..4380d64b9 100644 --- a/apt-pkg/contrib/configuration.cc +++ b/apt-pkg/contrib/configuration.cc @@ -253,11 +253,6 @@ string Configuration::FindDir(const char *Name,const char *Default) const // Configuration::FindVector - Find a vector of values /*{{{*/ // --------------------------------------------------------------------- /* Returns a vector of config values under the given item */ -#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR < 13) -vector<string> Configuration::FindVector(const char *Name) const { - return FindVector(Name, ""); -} -#endif vector<string> Configuration::FindVector(const char *Name, std::string const &Default) const { vector<string> Vec; diff --git a/apt-pkg/contrib/configuration.h b/apt-pkg/contrib/configuration.h index 6345c8a5d..2ecea8bee 100644 --- a/apt-pkg/contrib/configuration.h +++ b/apt-pkg/contrib/configuration.h @@ -34,6 +34,8 @@ #include <vector> #include <iostream> +#include <apt-pkg/macros.h> + #ifndef APT_8_CLEANER_HEADERS using std::string; #endif @@ -59,7 +61,7 @@ class Configuration Item *Root; bool ToFree; - + Item *Lookup(Item *Head,const char *S,unsigned long const &Len,bool const &Create); Item *Lookup(const char *Name,const bool &Create); inline const Item *Lookup(const char *Name) const @@ -82,12 +84,8 @@ class Configuration * * \param Name of the parent node * \param Default list of values separated by commas */ - std::vector<std::string> FindVector(const char *Name, std::string const &Default) const; - std::vector<std::string> FindVector(std::string const &Name, std::string const &Default) const { return FindVector(Name.c_str(), Default); }; -#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR < 13) - std::vector<std::string> FindVector(const char *Name) const; -#endif - std::vector<std::string> FindVector(std::string const &Name="") const { return FindVector(Name.c_str(), ""); }; + std::vector<std::string> FindVector(const char *Name, std::string const &Default = "") const; + std::vector<std::string> FindVector(std::string const &Name, std::string const &Default = "") const { return FindVector(Name.c_str(), Default); }; int FindI(const char *Name,int const &Default = 0) const; int FindI(std::string const &Name,int const &Default = 0) const {return FindI(Name.c_str(),Default);}; bool FindB(const char *Name,bool const &Default = false) const; @@ -127,7 +125,7 @@ class Configuration class MatchAgainstConfig { std::vector<regex_t *> patterns; - void clearPatterns(); + APT_HIDDEN void clearPatterns(); public: MatchAgainstConfig(char const * Config); diff --git a/apt-pkg/contrib/fileutl.cc b/apt-pkg/contrib/fileutl.cc index 02b30dc1f..df409fa36 100644 --- a/apt-pkg/contrib/fileutl.cc +++ b/apt-pkg/contrib/fileutl.cc @@ -47,6 +47,8 @@ #include <signal.h> #include <errno.h> #include <glob.h> +#include <pwd.h> +#include <grp.h> #include <set> #include <algorithm> @@ -63,6 +65,10 @@ #include <endian.h> #include <stdint.h> +#if __gnu_linux__ +#include <sys/prctl.h> +#endif + #include <apti18n.h> /*}}}*/ @@ -890,7 +896,7 @@ class FileFdPrivate { /*{{{*/ bool eof; bool compressing; - LZMAFILE() : file(NULL), eof(false), compressing(false) {} + LZMAFILE() : file(NULL), eof(false), compressing(false) { buffer[0] = '\0'; } ~LZMAFILE() { if (compressing == true) { @@ -1278,7 +1284,8 @@ bool FileFd::OpenInternDescriptor(unsigned int const Mode, APT::Configuration::C if (d->lzma == NULL) d->lzma = new FileFdPrivate::LZMAFILE; d->lzma->file = (FILE*) compress_struct; - d->lzma->stream = LZMA_STREAM_INIT; + lzma_stream tmp_stream = LZMA_STREAM_INIT; + d->lzma->stream = tmp_stream; if ((Mode & ReadWrite) == ReadWrite) return FileFdError("ReadWrite mode is not supported for file %s", FileName.c_str()); @@ -1834,7 +1841,8 @@ static bool StatFileFd(char const * const msg, int const iFd, std::string const // higher-level code will generate more meaningful messages, // even translated this would be meaningless for users return _error->Errno("fstat", "Unable to determine %s for fd %i", msg, iFd); - ispipe = S_ISFIFO(Buf.st_mode); + if (FileName.empty() == false) + ispipe = S_ISFIFO(Buf.st_mode); } // for compressor pipes st_size is undefined and at 'best' zero @@ -2118,10 +2126,8 @@ bool Popen(const char* Args[], FileFd &Fd, pid_t &Child, FileFd::OpenMode Mode) int Pipe[2] = {-1, -1}; if(pipe(Pipe) != 0) - { return _error->Errno("pipe", _("Failed to create subprocess IPC")); - return NULL; - } + std::set<int> keep_fds; keep_fds.insert(Pipe[0]); keep_fds.insert(Pipe[1]); @@ -2164,3 +2170,92 @@ bool Popen(const char* Args[], FileFd &Fd, pid_t &Child, FileFd::OpenMode Mode) return true; } + +bool DropPrivs() +{ + // uid will be 0 in the end, but gid might be different anyway + uid_t old_uid = getuid(); + gid_t old_gid = getgid(); + + if (old_uid != 0) + return true; + if(_config->FindB("Debug::NoDropPrivs", false) == true) + return true; + + const std::string toUser = _config->Find("APT::Sandbox::User", "_apt"); + struct passwd *pw = getpwnam(toUser.c_str()); + if (pw == NULL) + return _error->Error("No user %s, can not drop rights", toUser.c_str()); + +#if __gnu_linux__ + // see prctl(2), needs linux3.5 + int ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0,0, 0); + if(ret < 0) + _error->Warning("PR_SET_NO_NEW_PRIVS failed with %i", ret); +#endif + // Do not change the order here, it might break things + if (setgroups(1, &pw->pw_gid)) + return _error->Errno("setgroups", "Failed to setgroups"); + + if (setegid(pw->pw_gid) != 0) + return _error->Errno("setegid", "Failed to setegid"); + + if (setgid(pw->pw_gid) != 0) + return _error->Errno("setgid", "Failed to setgid"); + + if (setuid(pw->pw_uid) != 0) + return _error->Errno("setuid", "Failed to setuid"); + + // the seteuid() is probably uneeded (at least thats what the linux + // man-page says about setuid(2)) but we cargo culted it anyway + if (seteuid(pw->pw_uid) != 0) + return _error->Errno("seteuid", "Failed to seteuid"); + + // Verify that the user has only a single group, and the correct one + gid_t groups[1]; + if (getgroups(1, groups) != 1) + return _error->Errno("getgroups", "Could not get new groups"); + if (groups[0] != pw->pw_gid) + return _error->Error("Could not switch group"); + + // Verify that gid, egid, uid, and euid changed + if (getgid() != pw->pw_gid) + return _error->Error("Could not switch group"); + if (getegid() != pw->pw_gid) + return _error->Error("Could not switch effective group"); + if (getuid() != pw->pw_uid) + return _error->Error("Could not switch user"); + if (geteuid() != pw->pw_uid) + return _error->Error("Could not switch effective user"); + +#ifdef HAVE_GETRESUID + // verify that the saved set-user-id was changed as well + uid_t ruid = 0; + uid_t euid = 0; + uid_t suid = 0; + if (getresuid(&ruid, &euid, &suid)) + return _error->Errno("getresuid", "Could not get saved set-user-ID"); + if (suid != pw->pw_uid) + return _error->Error("Could not switch saved set-user-ID"); +#endif + +#ifdef HAVE_GETRESGID + // verify that the saved set-group-id was changed as well + gid_t rgid = 0; + gid_t egid = 0; + gid_t sgid = 0; + if (getresgid(&rgid, &egid, &sgid)) + return _error->Errno("getresuid", "Could not get saved set-group-ID"); + if (sgid != pw->pw_gid) + return _error->Error("Could not switch saved set-group-ID"); +#endif + + // Check that uid and gid changes do not work anymore + if (pw->pw_gid != old_gid && (setgid(old_gid) != -1 || setegid(old_gid) != -1)) + return _error->Error("Could restore a gid to root, privilege dropping did not work"); + + if (pw->pw_uid != old_uid && (setuid(old_uid) != -1 || seteuid(old_uid) != -1)) + return _error->Error("Could restore a uid to root, privilege dropping did not work"); + + return true; +} diff --git a/apt-pkg/contrib/fileutl.h b/apt-pkg/contrib/fileutl.h index 0b4d94885..9dd29eb9e 100644 --- a/apt-pkg/contrib/fileutl.h +++ b/apt-pkg/contrib/fileutl.h @@ -85,7 +85,9 @@ class FileFd bool Skip(unsigned long long To); bool Truncate(unsigned long long To); unsigned long long Tell(); + // the size of the file content (compressed files will be uncompressed first) unsigned long long Size(); + // the size of the file itself unsigned long long FileSize(); time_t ModificationTime(); @@ -193,9 +195,23 @@ pid_t ExecFork(std::set<int> keep_fds); void MergeKeepFdsFromConfiguration(std::set<int> &keep_fds); bool ExecWait(pid_t Pid,const char *Name,bool Reap = false); + // check if the given file starts with a PGP cleartext signature bool StartsWithGPGClearTextSignature(std::string const &FileName); +/** + * \brief Drop privileges + * + * Drop the privileges to the user _apt (or the one specified in + * APT::Sandbox::User). This does not set the supplementary group + * ids up correctly, it only uses the default group. Also prevent + * the process from gaining any new privileges afterwards, at least + * on Linux. + * + * \return true on success, false on failure with _error set + */ +bool DropPrivs(); + // File string manipulators std::string flNotDir(std::string File); std::string flNotFile(std::string File); diff --git a/apt-pkg/contrib/gpgv.cc b/apt-pkg/contrib/gpgv.cc index f24dd9640..9d798cca9 100644 --- a/apt-pkg/contrib/gpgv.cc +++ b/apt-pkg/contrib/gpgv.cc @@ -32,50 +32,30 @@ static char * GenerateTemporaryFileTemplate(const char *basename) /*{{{*/ /*}}}*/ // ExecGPGV - returns the command needed for verify /*{{{*/ // --------------------------------------------------------------------- -/* Generating the commandline for calling gpgv is somehow complicated as +/* Generating the commandline for calling gpg is somehow complicated as we need to add multiple keyrings and user supplied options. - Also, as gpgv has no options to enforce a certain reduced style of + Also, as gpg has no options to enforce a certain reduced style of clear-signed files (=the complete content of the file is signed and the content isn't encoded) we do a divide and conquer approach here - and split up the clear-signed file in message and signature for gpgv + and split up the clear-signed file in message and signature for gpg. + And as a cherry on the cake, we use our apt-key wrapper to do part + of the lifting in regards to merging keyrings. Fun for the whole family. */ void ExecGPGV(std::string const &File, std::string const &FileGPG, int const &statusfd, int fd[2]) { #define EINTERNAL 111 - std::string const gpgvpath = _config->Find("Dir::Bin::gpg", "/usr/bin/gpgv"); - // FIXME: remove support for deprecated APT::GPGV setting - std::string const trustedFile = _config->Find("APT::GPGV::TrustedKeyring", _config->FindFile("Dir::Etc::Trusted")); - std::string const trustedPath = _config->FindDir("Dir::Etc::TrustedParts"); + std::string const aptkey = _config->FindFile("Dir::Bin::apt-key", "/usr/bin/apt-key"); bool const Debug = _config->FindB("Debug::Acquire::gpgv", false); - if (Debug == true) - { - std::clog << "gpgv path: " << gpgvpath << std::endl; - std::clog << "Keyring file: " << trustedFile << std::endl; - std::clog << "Keyring path: " << trustedPath << std::endl; - } - - std::vector<std::string> keyrings; - if (DirectoryExists(trustedPath)) - keyrings = GetListOfFilesInDir(trustedPath, "gpg", false, true); - if (RealFileExists(trustedFile) == true) - keyrings.push_back(trustedFile); - std::vector<const char *> Args; - Args.reserve(30); - - if (keyrings.empty() == true) - { - // TRANSLATOR: %s is the trusted keyring parts directory - ioprintf(std::cerr, _("No keyring installed in %s."), - _config->FindDir("Dir::Etc::TrustedParts").c_str()); - exit(EINTERNAL); - } + Args.reserve(10); - Args.push_back(gpgvpath.c_str()); - Args.push_back("--ignore-time-conflict"); + Args.push_back(aptkey.c_str()); + Args.push_back("--quiet"); + Args.push_back("--readonly"); + Args.push_back("verify"); char statusfdstr[10]; if (statusfd != -1) @@ -85,13 +65,6 @@ void ExecGPGV(std::string const &File, std::string const &FileGPG, Args.push_back(statusfdstr); } - for (std::vector<std::string>::const_iterator K = keyrings.begin(); - K != keyrings.end(); ++K) - { - Args.push_back("--keyring"); - Args.push_back(K->c_str()); - } - Configuration::Item const *Opts; Opts = _config->Tree("Acquire::gpgv::Options"); if (Opts != 0) @@ -160,7 +133,7 @@ void ExecGPGV(std::string const &File, std::string const &FileGPG, if (Debug == true) { - std::clog << "Preparing to exec: " << gpgvpath; + std::clog << "Preparing to exec: "; for (std::vector<const char *>::const_iterator a = Args.begin(); *a != NULL; ++a) std::clog << " " << *a; std::clog << std::endl; @@ -168,7 +141,7 @@ void ExecGPGV(std::string const &File, std::string const &FileGPG, if (statusfd != -1) { - int const nullfd = open("/dev/null", O_RDONLY); + int const nullfd = open("/dev/null", O_WRONLY); close(fd[0]); // Redirect output to /dev/null; we read from the status fd if (statusfd != STDOUT_FILENO) @@ -185,7 +158,7 @@ void ExecGPGV(std::string const &File, std::string const &FileGPG, if (releaseSignature == DETACHED) { - execvp(gpgvpath.c_str(), (char **) &Args[0]); + execvp(Args[0], (char **) &Args[0]); ioprintf(std::cerr, "Couldn't execute %s to check %s", Args[0], File.c_str()); exit(EINTERNAL); } @@ -205,7 +178,7 @@ void ExecGPGV(std::string const &File, std::string const &FileGPG, { if (statusfd != -1) dup2(fd[1], statusfd); - execvp(gpgvpath.c_str(), (char **) &Args[0]); + execvp(Args[0], (char **) &Args[0]); ioprintf(std::cerr, "Couldn't execute %s to check %s", Args[0], File.c_str()); UNLINK_EXIT(EINTERNAL); } @@ -216,7 +189,7 @@ void ExecGPGV(std::string const &File, std::string const &FileGPG, { if (errno == EINTR) continue; - ioprintf(std::cerr, _("Waited for %s but it wasn't there"), "gpgv"); + ioprintf(std::cerr, _("Waited for %s but it wasn't there"), "apt-key"); UNLINK_EXIT(EINTERNAL); } #undef UNLINK_EXIT @@ -229,14 +202,14 @@ void ExecGPGV(std::string const &File, std::string const &FileGPG, // check if it exit'ed normally … if (WIFEXITED(Status) == false) { - ioprintf(std::cerr, _("Sub-process %s exited unexpectedly"), "gpgv"); + ioprintf(std::cerr, _("Sub-process %s exited unexpectedly"), "apt-key"); exit(EINTERNAL); } // … and with a good exit code if (WEXITSTATUS(Status) != 0) { - ioprintf(std::cerr, _("Sub-process %s returned an error code (%u)"), "gpgv", WEXITSTATUS(Status)); + ioprintf(std::cerr, _("Sub-process %s returned an error code (%u)"), "apt-key", WEXITSTATUS(Status)); exit(WEXITSTATUS(Status)); } diff --git a/apt-pkg/contrib/hashes.cc b/apt-pkg/contrib/hashes.cc index 199e395f6..417982343 100644 --- a/apt-pkg/contrib/hashes.cc +++ b/apt-pkg/contrib/hashes.cc @@ -209,11 +209,11 @@ bool HashStringList::operator==(HashStringList const &other) const /*{{{*/ std::string const forcedType = _config->Find("Acquire::ForceHash", ""); if (forcedType.empty() == false) { - HashString const * const hs = other.find(forcedType); + HashString const * const hs = find(forcedType); HashString const * const ohs = other.find(forcedType); if (hs == NULL || ohs == NULL) return false; - return hs == ohs; + return *hs == *ohs; } short matches = 0; for (const_iterator hs = begin(); hs != end(); ++hs) diff --git a/apt-pkg/contrib/macros.h b/apt-pkg/contrib/macros.h index b268ce24c..a0573398d 100644 --- a/apt-pkg/contrib/macros.h +++ b/apt-pkg/contrib/macros.h @@ -138,7 +138,7 @@ // Non-ABI-Breaks should only increase RELEASE number. // See also buildlib/libversion.mak #define APT_PKG_MAJOR 4 -#define APT_PKG_MINOR 13 +#define APT_PKG_MINOR 14 #define APT_PKG_RELEASE 0 #endif diff --git a/apt-pkg/contrib/proxy.cc b/apt-pkg/contrib/proxy.cc new file mode 100644 index 000000000..0c753131d --- /dev/null +++ b/apt-pkg/contrib/proxy.cc @@ -0,0 +1,86 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +/* ###################################################################### + + Proxy - Proxy releated functions + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#include<apt-pkg/configuration.h> +#include<apt-pkg/error.h> +#include<apt-pkg/fileutl.h> +#include<apt-pkg/strutl.h> + +#include<iostream> +#include <unistd.h> + +#include "proxy.h" + + +// AutoDetectProxy - auto detect proxy /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool AutoDetectProxy(URI &URL) +{ + // we support both http/https debug options + bool Debug = _config->FindB("Debug::Acquire::"+URL.Access,false); + + // the user already explicitly set a proxy for this host + if(_config->Find("Acquire::"+URL.Access+"::proxy::"+URL.Host, "") != "") + return true; + + // option is "Acquire::http::Proxy-Auto-Detect" but we allow the old + // name without the dash ("-") + std::string AutoDetectProxyCmd = _config->Find("Acquire::"+URL.Access+"::Proxy-Auto-Detect", + _config->Find("Acquire::"+URL.Access+"::ProxyAutoDetect")); + + if (AutoDetectProxyCmd.empty()) + return true; + + if (Debug) + std::clog << "Using auto proxy detect command: " << AutoDetectProxyCmd << std::endl; + + int Pipes[2] = {-1,-1}; + if (pipe(Pipes) != 0) + return _error->Errno("pipe", "Failed to create Pipe"); + + pid_t Process = ExecFork(); + if (Process == 0) + { + close(Pipes[0]); + dup2(Pipes[1],STDOUT_FILENO); + SetCloseExec(STDOUT_FILENO,false); + + std::string foo = URL; + const char *Args[4]; + Args[0] = AutoDetectProxyCmd.c_str(); + Args[1] = foo.c_str(); + Args[2] = 0; + execv(Args[0],(char **)Args); + std::cerr << "Failed to exec method " << Args[0] << std::endl; + _exit(100); + } + char buf[512]; + int InFd = Pipes[0]; + close(Pipes[1]); + int res = read(InFd, buf, sizeof(buf)-1); + ExecWait(Process, "ProxyAutoDetect", true); + + if (res < 0) + return _error->Errno("read", "Failed to read"); + if (res == 0) + return _error->Warning("ProxyAutoDetect returned no data"); + + // add trailing \0 + buf[res] = 0; + + if (Debug) + std::clog << "auto detect command returned: '" << buf << "'" << std::endl; + + if (strstr(buf, URL.Access.c_str()) == buf) + _config->Set("Acquire::"+URL.Access+"::proxy::"+URL.Host, _strstrip(buf)); + + return true; +} + /*}}}*/ diff --git a/apt-pkg/contrib/proxy.h b/apt-pkg/contrib/proxy.h new file mode 100644 index 000000000..2cbcd07b4 --- /dev/null +++ b/apt-pkg/contrib/proxy.h @@ -0,0 +1,16 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +/* ###################################################################### + + Proxy - Proxy operations + + ##################################################################### */ + /*}}}*/ +#ifndef PKGLIB_PROXY_H +#define PKGLIB_PROXY_H + +class URI; +bool AutoDetectProxy(URI &URL); + + +#endif diff --git a/apt-pkg/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc index 2100ee47b..aad358a55 100644 --- a/apt-pkg/contrib/strutl.cc +++ b/apt-pkg/contrib/strutl.cc @@ -45,14 +45,26 @@ using namespace std; // --------------------------------------------------------------------- namespace APT { namespace String { -std::string Strip(const std::string &s) +std::string Strip(const std::string &str) { - size_t start = s.find_first_not_of(" \t\n"); - // only whitespace - if (start == string::npos) + // ensure we have at least one character + if (str.empty() == true) + return str; + + char const * const s = str.c_str(); + size_t start = 0; + for (; isspace(s[start]) != 0; ++start) + ; // find the first not-space + + // string contains only whitespaces + if (s[start] == '\0') return ""; - size_t end = s.find_last_not_of(" \t\n"); - return s.substr(start, end-start+1); + + size_t end = str.length() - 1; + for (; isspace(s[end]) != 0; --end) + ; // find the last not-space + + return str.substr(start, end - start + 1); } bool Endswith(const std::string &s, const std::string &end) @@ -62,6 +74,13 @@ bool Endswith(const std::string &s, const std::string &end) return (s.substr(s.size() - end.size(), s.size()) == end); } +bool Startswith(const std::string &s, const std::string &start) +{ + if (start.size() > s.size()) + return false; + return (s.substr(0, start.size()) == start); +} + } } /*}}}*/ @@ -434,23 +453,30 @@ string TimeToStr(unsigned long Sec) /* This replaces all occurrences of Subst with Contents in Str. */ string SubstVar(const string &Str,const string &Subst,const string &Contents) { + if (Subst.empty() == true) + return Str; + string::size_type Pos = 0; string::size_type OldPos = 0; string Temp; - - while (OldPos < Str.length() && + + while (OldPos < Str.length() && (Pos = Str.find(Subst,OldPos)) != string::npos) { - Temp += string(Str,OldPos,Pos) + Contents; - OldPos = Pos + Subst.length(); + if (OldPos != Pos) + Temp.append(Str, OldPos, Pos - OldPos); + if (Contents.empty() == false) + Temp.append(Contents); + OldPos = Pos + Subst.length(); } - + if (OldPos == 0) return Str; - + + if (OldPos >= Str.length()) + return Temp; return Temp + string(Str,OldPos); } - string SubstVar(string Str,const struct SubstVar *Vars) { for (; Vars->Subst != 0; Vars++) @@ -697,9 +723,12 @@ string LookupTag(const string &Message,const char *Tag,const char *Default) then returns the result. Several varients on true/false are checked. */ int StringToBool(const string &Text,int Default) { - char *End; - int Res = strtol(Text.c_str(),&End,0); - if (End != Text.c_str() && Res >= 0 && Res <= 1) + char *ParseEnd; + int Res = strtol(Text.c_str(),&ParseEnd,0); + // ensure that the entire string was converted by strtol to avoid + // failures on "apt-cache show -a 0ad" where the "0" is converted + const char *TextEnd = Text.c_str()+Text.size(); + if (ParseEnd == TextEnd && Res >= 0 && Res <= 1) return Res; // Check for positives @@ -1039,7 +1068,7 @@ bool StrToNum(const char *Str,unsigned long long &Res,unsigned Len,unsigned Base // --------------------------------------------------------------------- /* This is used in decoding the 256bit encoded fixed length fields in tar files */ -bool Base256ToNum(const char *Str,unsigned long &Res,unsigned int Len) +bool Base256ToNum(const char *Str,unsigned long long &Res,unsigned int Len) { if ((Str[0] & 0x80) == 0) return false; @@ -1052,6 +1081,23 @@ bool Base256ToNum(const char *Str,unsigned long &Res,unsigned int Len) } } /*}}}*/ +// Base256ToNum - Convert a fixed length binary to a number /*{{{*/ +// --------------------------------------------------------------------- +/* This is used in decoding the 256bit encoded fixed length fields in + tar files */ +bool Base256ToNum(const char *Str,unsigned long &Res,unsigned int Len) +{ + unsigned long long Num; + bool rc; + + rc = Base256ToNum(Str, Num, Len); + Res = Num; + if (Res != Num) + return false; + + return rc; +} + /*}}}*/ // HexDigit - Convert a hex character into an integer /*{{{*/ // --------------------------------------------------------------------- /* Helper for Hex2Num */ diff --git a/apt-pkg/contrib/strutl.h b/apt-pkg/contrib/strutl.h index 185cdc3fc..e20ddca9c 100644 --- a/apt-pkg/contrib/strutl.h +++ b/apt-pkg/contrib/strutl.h @@ -40,6 +40,7 @@ namespace APT { namespace String { std::string Strip(const std::string &s); bool Endswith(const std::string &s, const std::string &ending); + bool Startswith(const std::string &s, const std::string &starting); } } @@ -72,6 +73,7 @@ bool ReadMessages(int Fd, std::vector<std::string> &List); bool StrToNum(const char *Str,unsigned long &Res,unsigned Len,unsigned Base = 0); bool StrToNum(const char *Str,unsigned long long &Res,unsigned Len,unsigned Base = 0); bool Base256ToNum(const char *Str,unsigned long &Res,unsigned int Len); +bool Base256ToNum(const char *Str,unsigned long long &Res,unsigned int Len); bool Hex2Num(const std::string &Str,unsigned char *Num,unsigned int Length); // input changing string split @@ -151,9 +153,9 @@ inline const char *DeNull(const char *s) {return (s == 0?"(null)":s);} class URI { void CopyFrom(const std::string &From); - + public: - + std::string Access; std::string User; std::string Password; |