diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/pop3.c | 93 | ||||
| -rw-r--r-- | lib/pop3.h | 2 | 
2 files changed, 91 insertions, 4 deletions
diff --git a/lib/pop3.c b/lib/pop3.c index ae540378f..2f47fd1a9 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -79,6 +79,7 @@  #include "url.h"  #include "rawstr.h"  #include "strtoofft.h" +#include "curl_sasl.h"  #define _MPRINTF_REPLACE /* use our functions only */  #include <curl/mprintf.h> @@ -208,11 +209,15 @@ static const struct Curl_handler Curl_handler_pop3s_proxy = {  #endif  /* Function that checks for an ending pop3 status code at the start of the -   given string */ +   given string, but also detects the allowed authentication mechanisms +   according to the AUTH response. */  static int pop3_endofresp(struct pingpong *pp, int *resp)  {    char *line = pp->linestart_resp;    size_t len = pp->nread_resp; +  struct connectdata *conn = pp->conn; +  struct pop3_conn *pop3c = &conn->proto.pop3c; +  size_t wordlen;    if((len < 3 || memcmp("+OK", line, 3)) &&       (len < 4 || memcmp("-ERR", line, 4))) @@ -220,6 +225,46 @@ static int pop3_endofresp(struct pingpong *pp, int *resp)    *resp = line[1]; /* O or E */ +  if(pop3c->state == POP3_AUTH && len >= 3 && !memcmp(line, "+OK", 3)) { +    line += 3; +    len -= 3; + +    for(;;) { +      while(len && +            (*line == ' ' || *line == '\t' || +             *line == '\r' || *line == '\n')) { +        line++; +        len--; +      } + +      if(!len || *line == '.') +        break; + +      for(wordlen = 0; wordlen < len && line[wordlen] != ' ' && +            line[wordlen] != '\t' && line[wordlen] != '\r' && +            line[wordlen] != '\n';) +        wordlen++; + +      if(wordlen == 5 && !memcmp(line, "LOGIN", 5)) +        pop3c->authmechs |= SASL_AUTH_LOGIN; +      else if(wordlen == 5 && !memcmp(line, "PLAIN", 5)) +        pop3c->authmechs |= SASL_AUTH_PLAIN; +      else if(wordlen == 8 && !memcmp(line, "CRAM-MD5", 8)) +        pop3c->authmechs |= SASL_AUTH_CRAM_MD5; +      else if(wordlen == 10 && !memcmp(line, "DIGEST-MD5", 10)) +        pop3c->authmechs |= SASL_AUTH_DIGEST_MD5; +      else if(wordlen == 6 && !memcmp(line, "GSSAPI", 6)) +        pop3c->authmechs |= SASL_AUTH_GSSAPI; +      else if(wordlen == 8 && !memcmp(line, "EXTERNAL", 8)) +        pop3c->authmechs |= SASL_AUTH_EXTERNAL; +      else if(wordlen == 4 && !memcmp(line, "NTLM", 4)) +        pop3c->authmechs |= SASL_AUTH_NTLM; + +      line += wordlen; +      len -= wordlen; +    } +  } +    return TRUE;  } @@ -231,6 +276,7 @@ static void state(struct connectdata *conn, pop3state newstate)    static const char * const names[]={      "STOP",      "SERVERGREET", +    "AUTH",      "USER",      "PASS",      "STARTTLS", @@ -248,6 +294,24 @@ static void state(struct connectdata *conn, pop3state newstate)    pop3c->state = newstate;  } +static CURLcode pop3_state_auth(struct connectdata *conn) +{ +  CURLcode result; +  struct pop3_conn *pop3c = &conn->proto.pop3c; + +  pop3c->authmechs = 0;         /* No known authentication mechanisms yet */ + +  /* send AUTH */ +  result = Curl_pp_sendf(&pop3c->pp, "AUTH"); + +  if(result) +    return result; + +  state(conn, POP3_AUTH); + +  return CURLE_OK; +} +  static CURLcode pop3_state_user(struct connectdata *conn)  {    CURLcode result; @@ -303,7 +367,7 @@ static CURLcode pop3_state_servergreet_resp(struct connectdata *conn,      state(conn, POP3_STARTTLS);    }    else -    result = pop3_state_user(conn); +    result = pop3_state_auth(conn);    return result;  } @@ -325,14 +389,14 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn,        state(conn, POP3_STOP);      }      else -      result = pop3_state_user(conn); +      result = pop3_state_auth(conn);    }    else {      /* Curl_ssl_connect is BLOCKING */      result = Curl_ssl_connect(conn, FIRSTSOCKET);      if(CURLE_OK == result) {        pop3_to_pop3s(conn); -      result = pop3_state_user(conn); +      result = pop3_state_auth(conn);      }      else {        state(conn, POP3_STOP); @@ -342,6 +406,23 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn,    return result;  } +/* For AUTH responses */ +static CURLcode pop3_state_auth_resp(struct connectdata *conn, +                                     int pop3code, +                                     pop3state instate) +{ +  CURLcode result = CURLE_OK; +  struct SessionHandle *data = conn->data; +  struct FTP *pop3 = data->state.proto.pop3; + +  (void)instate; /* no use for this yet */ + +  /* Proceed with clear text authentication as we used to for now */ +  result = pop3_state_user(conn); + +  return result; +} +  /* For USER responses */  static CURLcode pop3_state_user_resp(struct connectdata *conn,                                       int pop3code, @@ -506,6 +587,10 @@ static CURLcode pop3_statemach_act(struct connectdata *conn)        result = pop3_state_servergreet_resp(conn, pop3code, pop3c->state);        break; +    case POP3_AUTH: +      result = pop3_state_auth_resp(conn, pop3code, pop3c->state); +      break; +      case POP3_USER:        result = pop3_state_user_resp(conn, pop3code, pop3c->state);        break; diff --git a/lib/pop3.h b/lib/pop3.h index 99b514e4c..01701e4d7 100644 --- a/lib/pop3.h +++ b/lib/pop3.h @@ -29,6 +29,7 @@ typedef enum {    POP3_STOP,         /* do nothing state, stops the state machine */    POP3_SERVERGREET,  /* waiting for the initial greeting immediately after                          a connect */ +  POP3_AUTH,    POP3_USER,    POP3_PASS,    POP3_STARTTLS, @@ -46,6 +47,7 @@ struct pop3_conn {    size_t eob;        /* number of bytes of the EOB (End Of Body) that has been                          received thus far */    size_t strip;      /* number of bytes from the start to ignore as non-body */ +  unsigned int authmechs; /* Accepted authentication methods */    pop3state state;   /* always use pop3.c:state() to change state! */  };  | 
