You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

196 lines
5.1 KiB

  1. // -*- mode: cpp; mode: fold -*-
  2. // Description /*{{{*/
  3. /* ######################################################################
  4. netrc file parser - returns the login and password of a give host in
  5. a specified netrc-type file
  6. Originally written by Daniel Stenberg, <daniel@haxx.se>, et al. and
  7. placed into the Public Domain, do with it what you will.
  8. ##################################################################### */
  9. /*}}}*/
  10. #include <config.h>
  11. #include <apt-pkg/configuration.h>
  12. #include <apt-pkg/error.h>
  13. #include <apt-pkg/fileutl.h>
  14. #include <apt-pkg/strutl.h>
  15. #include <iostream>
  16. #include "netrc.h"
  17. /* Get user and password from .netrc when given a machine name */
  18. bool MaybeAddAuth(FileFd &NetRCFile, URI &Uri)
  19. {
  20. if (Uri.User.empty() == false || Uri.Password.empty() == false)
  21. return true;
  22. if (NetRCFile.IsOpen() == false || NetRCFile.Failed())
  23. return false;
  24. auto const Debug = _config->FindB("Debug::Acquire::netrc", false);
  25. std::string lookfor;
  26. if (Uri.Port != 0)
  27. strprintf(lookfor, "%s:%i%s", Uri.Host.c_str(), Uri.Port, Uri.Path.c_str());
  28. else
  29. lookfor.append(Uri.Host).append(Uri.Path);
  30. enum
  31. {
  32. NO,
  33. MACHINE,
  34. GOOD_MACHINE,
  35. LOGIN,
  36. PASSWORD
  37. } active_token = NO;
  38. std::string line;
  39. while (NetRCFile.Eof() == false || line.empty() == false)
  40. {
  41. if (line.empty())
  42. {
  43. if (NetRCFile.ReadLine(line) == false)
  44. break;
  45. else if (line.empty())
  46. continue;
  47. }
  48. auto tokenend = line.find_first_of("\t ");
  49. std::string token;
  50. if (tokenend != std::string::npos)
  51. {
  52. token = line.substr(0, tokenend);
  53. line.erase(0, tokenend + 1);
  54. }
  55. else
  56. std::swap(line, token);
  57. if (token.empty())
  58. continue;
  59. switch (active_token)
  60. {
  61. case NO:
  62. if (token == "machine")
  63. active_token = MACHINE;
  64. break;
  65. case MACHINE:
  66. if (token.find('/') == std::string::npos)
  67. {
  68. if (Uri.Port != 0 && Uri.Host == token)
  69. active_token = GOOD_MACHINE;
  70. else if (lookfor.compare(0, lookfor.length() - Uri.Path.length(), token) == 0)
  71. active_token = GOOD_MACHINE;
  72. else
  73. active_token = NO;
  74. }
  75. else
  76. {
  77. if (APT::String::Startswith(lookfor, token))
  78. active_token = GOOD_MACHINE;
  79. else
  80. active_token = NO;
  81. }
  82. break;
  83. case GOOD_MACHINE:
  84. if (token == "login")
  85. active_token = LOGIN;
  86. else if (token == "password")
  87. active_token = PASSWORD;
  88. else if (token == "machine")
  89. {
  90. if (Debug)
  91. std::clog << "MaybeAddAuth: Found matching host adding '" << Uri.User << "' and '" << Uri.Password << "' for "
  92. << (std::string)Uri << " from " << NetRCFile.Name() << std::endl;
  93. return true;
  94. }
  95. break;
  96. case LOGIN:
  97. std::swap(Uri.User, token);
  98. active_token = GOOD_MACHINE;
  99. break;
  100. case PASSWORD:
  101. std::swap(Uri.Password, token);
  102. active_token = GOOD_MACHINE;
  103. break;
  104. }
  105. }
  106. if (active_token == GOOD_MACHINE)
  107. {
  108. if (Debug)
  109. std::clog << "MaybeAddAuth: Found matching host adding '" << Uri.User << "' and '" << Uri.Password << "' for "
  110. << (std::string)Uri << " from " << NetRCFile.Name() << std::endl;
  111. return true;
  112. }
  113. else if (active_token == NO)
  114. {
  115. if (Debug)
  116. std::clog << "MaybeAddAuth: Found no matching host for "
  117. << (std::string)Uri << " from " << NetRCFile.Name() << std::endl;
  118. return true;
  119. }
  120. else if (Debug)
  121. {
  122. std::clog << "MaybeAddAuth: Found no matching host (syntax error: token:";
  123. switch (active_token)
  124. {
  125. case NO: std::clog << "NO"; break;
  126. case MACHINE: std::clog << "MACHINE"; break;
  127. case GOOD_MACHINE: std::clog << "GOOD_MACHINE"; break;
  128. case LOGIN: std::clog << "LOGIN"; break;
  129. case PASSWORD: std::clog << "PASSWORD"; break;
  130. }
  131. std::clog << ") for " << (std::string)Uri << " from " << NetRCFile.Name() << std::endl;
  132. }
  133. return false;
  134. }
  135. void maybe_add_auth(URI &Uri, std::string NetRCFile)
  136. {
  137. if (FileExists(NetRCFile) == false)
  138. return;
  139. FileFd fd;
  140. if (fd.Open(NetRCFile, FileFd::ReadOnly))
  141. MaybeAddAuth(fd, Uri);
  142. }
  143. /* Check if we are authorized. */
  144. bool IsAuthorized(pkgCache::PkgFileIterator const I, std::vector<std::unique_ptr<FileFd>> &authconfs)
  145. {
  146. if (authconfs.empty())
  147. {
  148. _error->PushToStack();
  149. auto const netrc = _config->FindFile("Dir::Etc::netrc");
  150. if (not netrc.empty())
  151. {
  152. authconfs.emplace_back(new FileFd());
  153. authconfs.back()->Open(netrc, FileFd::ReadOnly);
  154. }
  155. auto const netrcparts = _config->FindDir("Dir::Etc::netrcparts");
  156. if (not netrcparts.empty())
  157. {
  158. for (auto const &netrc : GetListOfFilesInDir(netrcparts, "conf", true, true))
  159. {
  160. authconfs.emplace_back(new FileFd());
  161. authconfs.back()->Open(netrc, FileFd::ReadOnly);
  162. }
  163. }
  164. _error->RevertToStack();
  165. }
  166. // FIXME: Use the full base url
  167. URI uri(std::string("http://") + I.Site() + "/");
  168. for (auto &authconf : authconfs)
  169. {
  170. if (not authconf->IsOpen())
  171. continue;
  172. if (not authconf->Seek(0))
  173. continue;
  174. MaybeAddAuth(*authconf, uri);
  175. if (not uri.User.empty() || not uri.Password.empty())
  176. return true;
  177. }
  178. return false;
  179. }