[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#212732: support redirects and interactive authentication (Progeny)



Package: apt
Version: 0.5.9
Severity: wishlist
Tags: patch

The patch below adds interactive authentication and redirect support to
apt's http method.

There are changes to apt-pkg in this patch:

 - New acquire method messages: 103 Redirect and 404 Authenticate from
the method, and 604 Authenticated to the method.

 - New acquire status method: Authenticate.  Called by apt when
authentication is needed.  The default implementation simply returns
false, which triggers apt's old behavior when asked to authenticate.

There is also an Authenticate implementation for acqprogress, which
enables interactive authentication for apt-get.

To my knowledge, all apt frontends should build without problems with
these changes.

Index: methods/http.cc
===================================================================
--- methods/http.cc (.../tags/apt-debian-0.5.9)	(revision 37)
+++ methods/http.cc
(.../branches/apt-resolve-0.5.9-redir-auth)	(revision 37)
@@ -40,6 +40,7 @@
 #include <errno.h>
 #include <string.h>
 #include <iostream>
+#include <map>
 
 // Internet stuff
 #include <netdb.h>
@@ -56,6 +57,7 @@
 time_t HttpMethod::FailTime = 0;
 unsigned long PipelineDepth = 10;
 unsigned long TimeOut = 120;
+bool ChokePipe = true;
 bool Debug = false;
 
 // CircleBuf::CircleBuf - Circular input buffer				/*{{{*/
@@ -591,6 +593,31 @@
       return true;
    }
 
+   if (stringcasecmp(Tag,"Location:") == 0)
+   {
+      Location = Val;
+      return true;
+   }
+
+   if (stringcasecmp(Tag,"WWW-Authenticate:") == 0 ||
+       stringcasecmp(Tag,"Proxy-Authenticate:") == 0)
+   {
+      string::size_type SplitPoint = Val.find(' ');
+      string AuthType = Val.substr(0, SplitPoint);
+      string RealmStr = Val.substr(SplitPoint + 1, 
+				   Val.length() - SplitPoint - 1);
+      SplitPoint = RealmStr.find('=');
+      string FoundRealm = RealmStr.substr(SplitPoint, 
+					  RealmStr.length() - SplitPoint);
+
+      if (stringcasecmp(Tag,"WWW-Authenticate:") == 0)
+	 Realm = FoundRealm;
+      else
+	 ProxyRealm = FoundRealm;
+
+      return true;
+   }
+
    return true;
 }
 									/*}}}*/
@@ -853,7 +880,8 @@
      1 - IMS hit
      3 - Unrecoverable error 
      4 - Error with error content page
-     5 - Unrecoverable non-server error (close the connection) */
+     5 - Unrecoverable non-server error (close the connection)
+     6 - Try again with a new or changed URI  */
 int HttpMethod::DealWithHeaders(FetchResult &Res,ServerState *Srv)
 {
    // Not Modified
@@ -864,7 +892,96 @@
       Res.LastModified = Queue->LastModified;
       return 1;
    }
-   
+
+   /* Redirect
+    *
+    * Note that it is only OK for us to treat all redirection the same
+    * because we *always* use GET, not other HTTP methods.  There are
+    * three redirection codes for which it is not appropriate that we
+    * redirect.  Pass on those codes so the error handling kicks in.
+    */
+   if ((Srv->Result > 300 && Srv->Result < 400)
+       && (Srv->Result != 300       // Multiple Choices
+           && Srv->Result != 304    // Not Modified
+           && Srv->Result != 306))  // (Not part of HTTP/1.1, reserved)
+   {
+      if (!Srv->Location.empty())
+      {
+         NextURI = Srv->Location;
+         return 6;
+      }
+      else
+	 return 3;
+   }
+
+   // Authentication
+   if (Srv->Result == 401)
+   {
+      string Description;
+      string AuthUser, AuthPass;
+      vector<AuthRec>::iterator CurrentAuth;
+      URI ParsedURI(Queue->Uri);
+
+      // Have we had to log in to this site before?
+      if (ParsedURI.User.empty())
+      {
+	 for (CurrentAuth = AuthList.begin(); CurrentAuth != AuthList.end();
+	      CurrentAuth++)
+	    if (CurrentAuth->Host == Srv->ServerName.Host &&
+		CurrentAuth->Realm == Srv->Realm)
+	    {
+	       AuthUser = CurrentAuth->User;
+	       AuthPass = CurrentAuth->Password;
+	       break;
+	    }
+      }
+      else
+	 CurrentAuth = AuthList.end();
+
+      // Nope - get username and password
+      if (CurrentAuth == AuthList.end())
+      {
+	 Description = ParsedURI.Host + ":" + Srv->Realm;
+
+#ifdef WITH_SSL
+	 if (ParsedURI.Access == "https")
+	    Description += string(" (secure)");
+#endif
+
+	 if (NeedAuth(Description, AuthUser, AuthPass) == true)
+	 {
+	    // Got new credentials; save them
+	    AuthRec NewAuthInfo;
+
+	    NewAuthInfo.Host = Srv->ServerName.Host;
+	    NewAuthInfo.Realm = Srv->Realm;
+	    NewAuthInfo.User = AuthUser;
+	    NewAuthInfo.Password = AuthPass;
+
+	    for (CurrentAuth = AuthList.begin(); CurrentAuth !=
AuthList.end();
+		 CurrentAuth++)
+	       if (CurrentAuth->Host == Srv->ServerName.Host &&
+		   CurrentAuth->Realm == Srv->Realm)
+	       {
+		  *CurrentAuth = NewAuthInfo;
+		  break;
+	       }
+	    
+	    if (CurrentAuth == AuthList.end())
+	       AuthList.push_back(NewAuthInfo);
+	 }
+	 else
+	    // Interactive auth failed
+	    return 4;
+      }
+
+      // Try the same URI again, with credentials this time
+      ParsedURI.User = AuthUser;
+      ParsedURI.Password = AuthPass;
+      NextURI = ParsedURI;
+      return 6;
+   }
+
    /* We have a reply we dont handle. This should indicate a perm
server
       failure */
    if (Srv->Result < 200 || Srv->Result >= 300)
@@ -956,10 +1073,21 @@
       // If pipelining is disabled, we only queue 1 request
       if (Server->Pipeline == false && Depth >= 0)
 	 break;
+
+      // If we're choking the pipeline, we only queue 1 request
+      if (ChokePipe == true && Depth >= 0)
+      {
+	 ChokePipe = false;
+	 break;
+      }
       
       // Make sure we stick with the same server
       if (Server->Comp(I->Uri) == false)
+      {
+	 ChokePipe = true;
 	 break;
+      }
+
       if (QueueBack == I)
 	 Tail = true;
       if (Tail == true)
@@ -994,12 +1122,17 @@
 /* */
 int HttpMethod::Loop()
 {
+   typedef vector<string> StringVector;
+   typedef vector<string>::iterator StringVectorIterator;
+   map<string, StringVector> Redirected;
+
    signal(SIGTERM,SigTerm);
    signal(SIGINT,SigTerm);
    
    Server = 0;
    
    int FailCounter = 0;
+
    while (1)
    {      
       // We have no commands, wait for some to arrive
@@ -1164,6 +1297,46 @@
 	    File = 0;
 	    break;
 	 }
+
+	 // Try again with a new URL
+	 case 6:
+	 {
+	    // Clear rest of response if there is content
+	    if (Server->HaveContent)
+	    {
+	       File = new FileFd("/dev/null",FileFd::WriteExists);
+	       Server->RunData();
+	       delete File;
+	       File = 0;
+	    }
+
+	    /* Detect redirect loops.  No more redirects are allowed
+	       after the same URI is seen twice in a queue item. */
+	    StringVector &R = Redirected[Queue->DestFile];
+	    bool StopRedirects = false;
+	    if (R.size() == 0)
+	       R.push_back(Queue->Uri);
+	    else if (R[0] == "STOP")
+	       StopRedirects = true;
+	    else
+	    {
+	       for (StringVectorIterator I = R.begin();	I != R.end(); I++)
+		  if (Queue->Uri == *I)
+		  {
+		     R[0] = "STOP";
+		     break;
+		  }
+
+	       R.push_back(Queue->Uri);
+	    }
+
+	    if (StopRedirects == false)
+	       Redirect(NextURI);
+	    else
+	       Fail();
+
+	    break;
+	 }
 	 
 	 default:
 	 Fail(_("Internal error"));
Index: methods/http.h
===================================================================
--- methods/http.h (.../tags/apt-debian-0.5.9)	(revision 37)
+++ methods/http.h (.../branches/apt-resolve-0.5.9-redir-auth)	(revision
37)
@@ -94,6 +94,8 @@
    enum {Chunked,Stream,Closes} Encoding;
    enum {Header, Data} State;
    bool Persistent;
+   string Location;
+   string Realm, ProxyRealm;
    
    // This is a Persistent attribute of the server itself.
    bool Pipeline;
@@ -123,6 +125,14 @@
 
 class HttpMethod : public pkgAcqMethod
 {
+   struct AuthRec
+   {
+      string Host;
+      string Realm;
+      string User;
+      string Password;
+   };
+
    void SendReq(FetchItem *Itm,CircleBuf &Out);
    bool Go(bool ToFile,ServerState *Srv);
    bool Flush(ServerState *Srv);
@@ -137,6 +147,9 @@
    static int FailFd;
    static time_t FailTime;
    static void SigTerm(int);
+
+   string NextURI;
+   vector<AuthRec> AuthList;
    
    public:
    friend class ServerState;
Index: apt-pkg/acquire.h
===================================================================
--- apt-pkg/acquire.h (.../tags/apt-debian-0.5.9)	(revision 37)
+++ apt-pkg/acquire.h
(.../branches/apt-resolve-0.5.9-redir-auth)	(revision 37)
@@ -267,6 +267,9 @@
    
    // Called to change media
    virtual bool MediaChange(string Media,string Drive) = 0;
+
+   // Called to authenticate
+   virtual bool Authenticate(string Desc,string &User,string &Pass);
    
    // Each of these is called by the workers when an event occures
    virtual void IMSHit(pkgAcquire::ItemDesc &/*Itm*/) {};
Index: apt-pkg/acquire-worker.h
===================================================================
--- apt-pkg/acquire-worker.h (.../tags/apt-debian-0.5.9)	(revision 37)
+++ apt-pkg/acquire-worker.h
(.../branches/apt-resolve-0.5.9-redir-auth)	(revision 37)
@@ -62,6 +62,7 @@
    bool Capabilities(string Message);
    bool SendConfiguration();
    bool MediaChange(string Message);
+   bool Authenticate(string Message);
    
    bool MethodFailure();
    void ItemDone();
Index: apt-pkg/acquire-worker.cc
===================================================================
--- apt-pkg/acquire-worker.cc (.../tags/apt-debian-0.5.9)	(revision 37)
+++ apt-pkg/acquire-worker.cc
(.../branches/apt-resolve-0.5.9-redir-auth)	(revision 37)
@@ -221,6 +221,20 @@
 	 case 102:
 	 Status = LookupTag(Message,"Message");
 	 break;
+
+	 // 103 Redirect
+	 case 103:
+	 {
+	    if (Itm == 0)
+	    {
+	       _error->Error("Method gave invalid 103 Redirect message");
+	       break;
+	    }
+
+	    string NewURI = LookupTag(Message,"New-URI",URI.c_str());
+	    Itm->URI = NewURI;
+	    break;
+	 }
 	    
 	 // 200 URI Start
 	 case 200:
@@ -324,6 +338,11 @@
 	 case 403:
 	 MediaChange(Message); 
 	 break;
+
+	 // 404 Authenticate
+	 case 404:
+	 Authenticate(Message);
+	 break;
       }      
    }
    return true;
@@ -388,6 +407,34 @@
    return true;
 }
 									/*}}}*/
+// Worker::Authenticate - Request authentication       			/*{{{*/
+//
---------------------------------------------------------------------
+/* */
+bool pkgAcquire::Worker::Authenticate(string Message)
+{
+   string User, Pass;
+   if (Log == 0 || Log->Authenticate(LookupTag(Message,"Description"),
+				     User,Pass) == false)
+   {
+      char S[300];
+      snprintf(S,sizeof(S),"604 Authenticated\nFailed: true\n\n");
+      if (Debug == true)
+	 clog << " -> " << Access << ':' << QuoteString(S,"\n") << endl;
+      OutQueue += S;
+      OutReady = true;
+      return true;
+   }
+
+   char S[300];
+   snprintf(S,sizeof(S),"604 Authenticated\nUser: %s\nPassword:
%s\n\n",
+	    User.c_str(), Pass.c_str());
+   if (Debug == true)
+      clog << " -> " << Access << ':' << QuoteString(S,"\n") << endl;
+   OutQueue += S;
+   OutReady = true;
+   return true;
+}
+									/*}}}*/
 // Worker::SendConfiguration - Send the config to the method		/*{{{*/
 //
---------------------------------------------------------------------
 /* */
Index: apt-pkg/acquire-method.cc
===================================================================
--- apt-pkg/acquire-method.cc (.../tags/apt-debian-0.5.9)	(revision 37)
+++ apt-pkg/acquire-method.cc
(.../branches/apt-resolve-0.5.9-redir-auth)	(revision 37)
@@ -26,6 +26,7 @@
 #include <apt-pkg/hashes.h>
 
 #include <iostream>
+#include <sstream>
 #include <stdarg.h>
 #include <stdio.h>
 #include <unistd.h>
@@ -133,24 +134,22 @@
 {
    if (Queue == 0)
       abort();
-   
-   char S[1024] = "";
-   char *End = S;
-   
-   End += snprintf(S,sizeof(S),"200 URI Start\nURI:
%s\n",Queue->Uri.c_str());
+
+   ostringstream s;
+
+   s << "200 URI Start\nURI: " << Queue->Uri << "\n";
    if (Res.Size != 0)
-      End += snprintf(End,sizeof(S)-4 - (End - S),"Size:
%lu\n",Res.Size);
-   
+      s << "Size: " << Res.Size << "\n";
+
    if (Res.LastModified != 0)
-      End += snprintf(End,sizeof(S)-4 - (End - S),"Last-Modified:
%s\n",
-		      TimeRFC1123(Res.LastModified).c_str());
-   
+      s << "Last-Modified: " << TimeRFC1123(Res.LastModified) << "\n";
+
    if (Res.ResumePoint != 0)
-      End += snprintf(End,sizeof(S)-4 - (End - S),"Resume-Point:
%lu\n",
-		      Res.ResumePoint);
-      
-   strcat(End,"\n");
-   if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
+      s << "Resume-Point: " << Res.ResumePoint << "\n";
+
+   s << "\n";
+   string S = s.str();
+   if (write(STDOUT_FILENO,S.c_str(),S.size()) != (ssize_t)S.size())
       exit(100);
 }
 									/*}}}*/
@@ -161,60 +160,54 @@
 {
    if (Queue == 0)
       abort();
-   
-   char S[1024] = "";
-   char *End = S;
-   
-   End += snprintf(S,sizeof(S),"201 URI Done\nURI:
%s\n",Queue->Uri.c_str());
 
+   ostringstream s;
+
+   s << "201 URI Done\nURI: " << Queue->Uri << "\n";
+
    if (Res.Filename.empty() == false)
-      End += snprintf(End,sizeof(S)-50 - (End - S),"Filename:
%s\n",Res.Filename.c_str());
-   
+      s << "Filename: " << Res.Filename << "\n";
+
    if (Res.Size != 0)
-      End += snprintf(End,sizeof(S)-50 - (End - S),"Size:
%lu\n",Res.Size);
-   
+      s << "Size: " << Res.Size << "\n";
+
    if (Res.LastModified != 0)
-      End += snprintf(End,sizeof(S)-50 - (End - S),"Last-Modified:
%s\n",
-		      TimeRFC1123(Res.LastModified).c_str());
+      s << "Last-Modified: " << TimeRFC1123(Res.LastModified) << "\n";
 
    if (Res.MD5Sum.empty() == false)
-      End += snprintf(End,sizeof(S)-50 - (End - S),"MD5-Hash:
%s\n",Res.MD5Sum.c_str());
+      s << "MD5-Hash: " << Res.MD5Sum << "\n";
    if (Res.SHA1Sum.empty() == false)
-      End += snprintf(End,sizeof(S)-50 - (End - S),"SHA1-Hash:
%s\n",Res.SHA1Sum.c_str());
+      s << "SHA1-Hash: " << Res.SHA1Sum << "\n";
 
    if (Res.ResumePoint != 0)
-      End += snprintf(End,sizeof(S)-50 - (End - S),"Resume-Point:
%lu\n",
-		      Res.ResumePoint);
+      s << "Resume-Point: " << Res.ResumePoint << "\n";
 
    if (Res.IMSHit == true)
-      strcat(End,"IMS-Hit: true\n");
-   End = S + strlen(S);
-   
+      s << "IMS-Hit: true\n";
+
    if (Alt != 0)
    {
       if (Alt->Filename.empty() == false)
-	 End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-Filename:
%s\n",Alt->Filename.c_str());
+	 s << "Alt-Filename: " << Alt->Filename << "\n";
       
       if (Alt->Size != 0)
-	 End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-Size:
%lu\n",Alt->Size);
+	 s << "Alt-Size: " << Alt->Size << "\n";
       
       if (Alt->LastModified != 0)
-	 End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-Last-Modified:
%s\n",
-			 TimeRFC1123(Alt->LastModified).c_str());
+	 s << "Alt-Last-Modified: " << TimeRFC1123(Alt->LastModified) << "\n";
       
       if (Alt->MD5Sum.empty() == false)
-	 End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-MD5-Hash: %s\n",
-			 Alt->MD5Sum.c_str());
+	 s << "Alt-MD5-Hash: " << Alt->MD5Sum << "\n";
       if (Alt->SHA1Sum.empty() == false)
-	 End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-SHA1-Hash: %s\n",
-			 Alt->SHA1Sum.c_str());
+	 s << "Alt-SHA1-Hash: " << Alt->SHA1Sum << "\n";
       
       if (Alt->IMSHit == true)
-	 strcat(End,"Alt-IMS-Hit: true\n");
+	 s << "Alt-IMS-Hit: true\n";
    }
-   
-   strcat(End,"\n");
-   if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
+
+   s << "\n";
+   string S = s.str();
+   if (write(STDOUT_FILENO,S.c_str(),S.size()) != (ssize_t)S.size())
       exit(100);
 
    // Dequeue
@@ -278,6 +271,66 @@
    }   
 }
 									/*}}}*/
+// AcqMethod::NeedAuth - Request authentication				/*{{{*/
+//
---------------------------------------------------------------------
+/* This sends a 404 Authenticate message to the APT and waits for it
+   to be ackd */
+bool pkgAcqMethod::NeedAuth(string Description,string &User,string
&Pass)
+{
+   char S[1024];
+   snprintf(S,sizeof(S),"404 Authenticate\nDescription: %s\n\n",
+	    Description.c_str());
+
+   if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
+      exit(100);
+   
+   vector<string> MyMessages;
+   
+   /* Here we read messages until we find a 604, each non 604 message
is
+      appended to the main message list for later processing */
+   while (1)
+   {
+      if (WaitFd(STDIN_FILENO) == false)
+	 return false;
+      
+      if (ReadMessages(STDIN_FILENO,MyMessages) == false)
+	 return false;
+
+      string Message = MyMessages.front();
+      MyMessages.erase(MyMessages.begin());
+      
+      // Fetch the message number
+      char *End;
+      int Number = strtol(Message.c_str(),&End,10);
+      if (End == Message.c_str())
+      {	 
+	 cerr << "Malformed message!" << endl;
+	 exit(100);
+      }
+
+      // Change ack
+      if (Number == 604)
+      {
+	 while (MyMessages.empty() == false)
+	 {
+	    Messages.push_back(MyMessages.front());
+	    MyMessages.erase(MyMessages.begin());
+	 }
+
+	 if (StringToBool(LookupTag(Message,"Fail"),false) == false)
+	 {
+	    User = LookupTag(Message,"User");
+	    Pass = LookupTag(Message,"Password");
+	    return true;
+	 }
+	 else
+	    return false;
+      }
+      
+      Messages.push_back(Message);
+   }   
+}
+									/*}}}*/
 // AcqMethod::Configuration - Handle the configuration message		/*{{{*/
 //
---------------------------------------------------------------------
 /* This parses each configuration entry and puts it into the _config 
@@ -423,19 +476,52 @@
    va_list args;
    va_start(args,Format);
 
+   ostringstream s;
+   s << "102 Status\nURI: " << CurrentURI << "\nMessage: ";
+
    // sprintf the description
-   char S[1024];
-   unsigned int Len = snprintf(S,sizeof(S)-4,"102 Status\nURI: %s\n"
-			       "Message: ",CurrentURI.c_str());
+   char Buf[1024];
+   vsnprintf(Buf,sizeof(Buf)-4,Format,args);
+   s << Buf << "\n\n";
 
-   vsnprintf(S+Len,sizeof(S)-4-Len,Format,args);
-   strcat(S,"\n\n");
-   
-   if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
+   string S = s.str();
+   if (write(STDOUT_FILENO,S.c_str(),S.size()) != (ssize_t)S.size())
       exit(100);
 }
 									/*}}}*/
+// AcqMethod::Redirect - Send a redirect message			/*{{{*/
+//
---------------------------------------------------------------------
+/* This method sends the redirect message and also manipulates the
queue
+   to keep the pipeline synchronized. */
+void pkgAcqMethod::Redirect(const string &NewURI)
+{
+   string CurrentURI = "<UNKNOWN>";
+   if (Queue != 0)
+      CurrentURI = Queue->Uri;
 
+   ostringstream s;
+   s << "103 Redirect\nURI: " << CurrentURI << "\nNew-URI: " << NewURI 
+     << "\n\n";
+
+   string S = s.str();
+   if (write(STDOUT_FILENO,S.c_str(),S.size()) != (ssize_t)S.size())
+      exit(100);
+
+   // Change the URI for the request.
+   Queue->Uri = NewURI;
+
+   /* To keep the pipeline synchronized, move the current request to
+      the end of the queue, past the end of the current pipeline. */
+   FetchItem *I;
+   for (I = Queue; I->Next != 0; I = I->Next) ;
+   I->Next = Queue;
+   Queue = Queue->Next;
+   I->Next->Next = 0;
+   if (QueueBack == 0)
+      QueueBack = I->Next;
+}
+									/*}}}*/
+
 // AcqMethod::FetchResult::FetchResult - Constructor			/*{{{*/
 //
---------------------------------------------------------------------
 /* */
Index: apt-pkg/acquire-method.h
===================================================================
--- apt-pkg/acquire-method.h (.../tags/apt-debian-0.5.9)	(revision 37)
+++ apt-pkg/acquire-method.h
(.../branches/apt-resolve-0.5.9-redir-auth)	(revision 37)
@@ -66,6 +66,7 @@
    void URIStart(FetchResult &Res);
    void URIDone(FetchResult &Res,FetchResult *Alt = 0);
    bool MediaFail(string Required,string Drive);
+   bool NeedAuth(string Description,string &User,string &Pass);
    virtual void Exit() {};
 
    public:
@@ -77,7 +78,8 @@
 
    void Log(const char *Format,...);
    void Status(const char *Format,...);
-   
+   void Redirect(const string &NewURI);
+
    int Run(bool Single = false);
    inline void SetFailExtraMsg(string Msg) {FailExtra = Msg;};
    
Index: apt-pkg/acquire.cc
===================================================================
--- apt-pkg/acquire.cc (.../tags/apt-debian-0.5.9)	(revision 37)
+++ apt-pkg/acquire.cc
(.../branches/apt-resolve-0.5.9-redir-auth)	(revision 37)
@@ -848,3 +848,13 @@
    FetchedBytes += Size - Resume;
 }
 									/*}}}*/
+// AcquireStatus::Authenticate - Called to authenticate			/*{{{*/
+//
---------------------------------------------------------------------
+/* This is used to fetch a username and password from the user */
+bool pkgAcquireStatus::Authenticate(string Desc,string &User,string
&Pass)
+{
+   /* The default behavior for all clients is to refuse to authenticate
+      interactively; this preserves backwards compatibility. */
+   return false;
+}
+									/*}}}*/
Index: cmdline/acqprogress.h
===================================================================
--- cmdline/acqprogress.h (.../tags/apt-debian-0.5.9)	(revision 37)
+++ cmdline/acqprogress.h
(.../branches/apt-resolve-0.5.9-redir-auth)	(revision 37)
@@ -22,6 +22,7 @@
    public:
    
    virtual bool MediaChange(string Media,string Drive);
+   virtual bool Authenticate(string Desc,string &User,string &Pass);
    virtual void IMSHit(pkgAcquire::ItemDesc &Itm);
    virtual void Fetch(pkgAcquire::ItemDesc &Itm);
    virtual void Done(pkgAcquire::ItemDesc &Itm);
Index: cmdline/acqprogress.cc
===================================================================
--- cmdline/acqprogress.cc (.../tags/apt-debian-0.5.9)	(revision 37)
+++ cmdline/acqprogress.cc
(.../branches/apt-resolve-0.5.9-redir-auth)	(revision 37)
@@ -18,6 +18,8 @@
     
 #include <stdio.h>
 #include <signal.h>
+#include <termios.h>
+#include <unistd.h>
 #include <iostream>
 									/*}}}*/
 
@@ -281,3 +283,59 @@
    return true;
 }
 									/*}}}*/
+// AcqTextStatus::Authenticate - Authenticate the user			/*{{{*/
+//
---------------------------------------------------------------------
+/* Prompt for a username and password */
+bool AcqTextStatus::Authenticate(string Desc,string &User,string &Pass)
+{
+   if (Quiet > 0)
+      return false;
+
+   cout << '\r' << BlankLine << '\r';
+
+   ioprintf(cout,_("Please login to %s\nUsername: "), Desc.c_str());
+   cout << flush;
+
+   char S[1024];
+   char C = 0;
+   size_t idx = 0;
+   while (C != '\n' && C != '\r' && idx < (sizeof(S) - 1))
+   {
+      read(STDIN_FILENO,&C,1);
+      S[idx++] = C;
+   }
+   S[--idx] = '\0';
+   User = S;
+
+   ioprintf(cout,_("Password: "));
+   cout << flush;
+
+   // Turn off echo for entering the password
+   struct termios TermIO;
+   tcgetattr(STDIN_FILENO, &TermIO);
+
+   struct termios TermIO_noecho;
+   TermIO_noecho = TermIO;
+   TermIO_noecho.c_lflag &= !ECHO;
+   tcsetattr(STDIN_FILENO, TCSANOW, &TermIO_noecho);
+
+   C = 0;
+   idx = 0;
+   while (C != '\n' && C != '\r' && idx < (sizeof(S) - 1))
+   {
+      read(STDIN_FILENO,&C,1);
+      S[idx++] = C;
+   }
+   S[--idx] = '\0';
+   Pass = S;
+
+   // Turn echo back on
+   tcsetattr(STDIN_FILENO, TCSANOW, &TermIO);
+
+   ioprintf(cout,_("\n"));
+   cout << flush;
+   
+   Update = true;
+   return true;
+}
+									/*}}}*/




Reply to: