pop3: Added support for sasl plain text authentication
authorSteve Holme <steve_holme@hotmail.com>
Thu, 31 May 2012 19:45:53 +0000 (20:45 +0100)
committerSteve Holme <steve_holme@hotmail.com>
Thu, 31 May 2012 19:45:53 +0000 (20:45 +0100)
lib/pop3.c
lib/pop3.h

index d3b84f3..38cde50 100644 (file)
  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  * KIND, either express or implied.
  *
+ * RFC1734 POP3 Authentication
  * RFC1939 POP3 protocol
  * RFC2384 POP URL Scheme
  * RFC2595 Using TLS with IMAP, POP3 and ACAP
+ * RFC4616 PLAIN authentication
  *
  ***************************************************************************/
 
@@ -279,6 +281,8 @@ static void state(struct connectdata *conn, pop3state newstate)
     "SERVERGREET",
     "STARTTLS",
     "AUTH",
+    "AUTH_PLAIN",
+    "AUTH_FINAL",
     "USER",
     "PASS",
     "COMMAND",
@@ -301,6 +305,7 @@ static CURLcode pop3_state_auth(struct connectdata *conn)
   struct pop3_conn *pop3c = &conn->proto.pop3c;
 
   pop3c->authmechs = 0;         /* No known authentication mechanisms yet */
+  pop3c->authused = 0;          /* Clear the authentication mechanism used */
 
   /* send AUTH */
   result = Curl_pp_sendf(&pop3c->pp, "AUTH");
@@ -329,6 +334,35 @@ static CURLcode pop3_state_user(struct connectdata *conn)
   return CURLE_OK;
 }
 
+static CURLcode pop3_authenticate(struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  struct pop3_conn *pop3c = &conn->proto.pop3c;
+  const char *mech = NULL;
+  pop3state authstate = POP3_STOP;
+
+  /* Check supported authentication mechanisms by decreasing order of
+     security */
+  if(pop3c->authmechs & SASL_AUTH_PLAIN) {
+    mech = "PLAIN";
+    authstate = POP3_AUTH_PLAIN;
+    pop3c->authused = SASL_AUTH_PLAIN;
+  }
+  else {
+    infof(conn->data, "No known SASL auth mechanisms supported!\n");
+    result = CURLE_LOGIN_DENIED;      /* Other mechanisms not supported */
+  }
+
+  if(!result) {
+    result = Curl_pp_sendf(&pop3c->pp, "AUTH %s", mech);
+
+    if(!result)
+      state(conn, authstate);
+  }
+
+  return result;
+}
+
 /* For the POP3 "protocol connect" and "doing" phases only */
 static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks,
                         int numsocks)
@@ -408,12 +442,72 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn,
 }
 
 /* For AUTH responses */
-static CURLcode pop3_state_auth_resp(struct connectdata *conn)
+static CURLcode pop3_state_auth_resp(struct connectdata *conn,
+                                     int pop3code,
+                                     pop3state instate)
+{
+  CURLcode result = CURLE_OK;
+
+  (void)instate; /* no use for this yet */
+
+  if(pop3code != '+')
+    result = pop3_state_user(conn);
+  else
+    result = pop3_authenticate(conn);
+
+  return result;
+}
+
+/* For AUTH PLAIN responses */
+static CURLcode pop3_state_auth_plain_resp(struct connectdata *conn,
+                                           int pop3code,
+                                           pop3state instate)
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data = conn->data;
+  size_t len = 0;
+  char *plainauth = NULL;
+
+  (void)instate; /* no use for this yet */
+
+  if(pop3code != '+') {
+    failf(data, "Access denied. %c", pop3code);
+    result = CURLE_LOGIN_DENIED;
+  }
+  else {
+    result = Curl_sasl_create_plain_message(conn->data, conn->user,
+                                            conn->passwd, &plainauth, &len);
+
+    if(!result) {
+      if(plainauth) {
+        result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", plainauth);
+
+        if(!result)
+          state(conn, POP3_AUTH_FINAL);
+      }
+      Curl_safefree(plainauth);
+    }
+  }
+
+  return result;
+}
+
+/* For final responses in the AUTH sequence */
+static CURLcode pop3_state_auth_final_resp(struct connectdata *conn,
+                                           int pop3code,
+                                           pop3state instate)
 {
   CURLcode result = CURLE_OK;
+  struct SessionHandle *data = conn->data;
+
+  (void)instate; /* no use for this yet */
+
+  if(pop3code != '+') {
+    failf(data, "Authentication failed: %d", pop3code);
+    result = CURLE_LOGIN_DENIED;
+  }
 
-  /* Proceed with clear text authentication as we used to for now */
-  result = pop3_state_user(conn);
+  state(conn, POP3_STOP);  /* End of connect phase */
 
   return result;
 }
@@ -460,7 +554,7 @@ static CURLcode pop3_state_pass_resp(struct connectdata *conn,
     result = CURLE_LOGIN_DENIED;
   }
 
-  state(conn, POP3_STOP);
+  state(conn, POP3_STOP);  /* End of connect phase */
 
   return result;
 }
@@ -587,7 +681,15 @@ static CURLcode pop3_statemach_act(struct connectdata *conn)
       break;
 
     case POP3_AUTH:
-      result = pop3_state_auth_resp(conn);
+      result = pop3_state_auth_resp(conn, pop3code, pop3c->state);
+      break;
+
+    case POP3_AUTH_PLAIN:
+      result = pop3_state_auth_plain_resp(conn, pop3code, pop3c->state);
+      break;
+
+    case POP3_AUTH_FINAL:
+      result = pop3_state_auth_final_resp(conn, pop3code, pop3c->state);
       break;
 
     case POP3_USER:
index 000284d..953fce7 100644 (file)
@@ -31,6 +31,8 @@ typedef enum {
                         a connect */
   POP3_STARTTLS,
   POP3_AUTH,
+  POP3_AUTH_PLAIN,
+  POP3_AUTH_FINAL,
   POP3_USER,
   POP3_PASS,
   POP3_COMMAND,
@@ -48,6 +50,7 @@ struct pop3_conn {
                         received thus far */
   size_t strip;      /* number of bytes from the start to ignore as non-body */
   unsigned int authmechs; /* Accepted authentication methods */
+  unsigned int authused;  /* Authentication method used for the connection */
   pop3state state;   /* always use pop3.c:state() to change state! */
 };