qpid-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From astitc...@apache.org
Subject [1/2] qpid-proton git commit: PROTON-868: Finished off default implementation of SASL - Client ANONYMOUS and PLAIN - Server ANONYMOUS only - Refactored out all the general SASL code into sasl.c leaving only the cyrus specific code in cyrus_sasl.c - Cre
Date Wed, 06 May 2015 21:00:07 GMT
Repository: qpid-proton
Updated Branches:
  refs/heads/master 136e33a4b -> 6dd8084b0


PROTON-868: Finished off default implementation of SASL
- Client ANONYMOUS and PLAIN
- Server ANONYMOUS only
- Refactored out all the general SASL code into sasl.c
  leaving only the cyrus specific code in cyrus_sasl.c
- Created new default implementation in none_sasl.c


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/df8e9ac5
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/df8e9ac5
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/df8e9ac5

Branch: refs/heads/master
Commit: df8e9ac5a0d811cc72d6095a9d337a91ade333b9
Parents: 136e33a
Author: Andrew Stitcher <astitcher@apache.org>
Authored: Tue Apr 28 00:28:55 2015 -0400
Committer: Andrew Stitcher <astitcher@apache.org>
Committed: Wed May 6 16:01:11 2015 -0400

----------------------------------------------------------------------
 proton-c/src/engine/engine-internal.h |   3 -
 proton-c/src/sasl/cyrus_sasl.c        | 864 +++++++----------------------
 proton-c/src/sasl/none_sasl.c         | 433 +++------------
 proton-c/src/sasl/sasl-internal.h     |  56 +-
 proton-c/src/sasl/sasl.c              | 475 +++++++++++++++-
 proton-c/src/ssl/ssl-internal.h       |   2 +
 6 files changed, 798 insertions(+), 1035 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/df8e9ac5/proton-c/src/engine/engine-internal.h
----------------------------------------------------------------------
diff --git a/proton-c/src/engine/engine-internal.h b/proton-c/src/engine/engine-internal.h
index 035d5be..748efbb 100644
--- a/proton-c/src/engine/engine-internal.h
+++ b/proton-c/src/engine/engine-internal.h
@@ -97,9 +97,6 @@ typedef struct {
   bool disp;
 } pn_session_state_t;
 
-#include <proton/sasl.h>
-#include <proton/ssl.h>
-
 typedef struct pn_io_layer_t {
   ssize_t (*process_input)(struct pn_transport_t *transport, unsigned int layer, const char *, size_t);
   ssize_t (*process_output)(struct pn_transport_t *transport, unsigned int layer, char *, size_t);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/df8e9ac5/proton-c/src/sasl/cyrus_sasl.c
----------------------------------------------------------------------
diff --git a/proton-c/src/sasl/cyrus_sasl.c b/proton-c/src/sasl/cyrus_sasl.c
index 58d6c9b..a12f8c0 100644
--- a/proton-c/src/sasl/cyrus_sasl.c
+++ b/proton-c/src/sasl/cyrus_sasl.c
@@ -21,10 +21,7 @@
 
 #include "sasl-internal.h"
 
-#include "protocol.h"
-#include "dispatch_actions.h"
 #include "engine/engine-internal.h"
-#include "proton/codec.h"
 
 #include <sasl/sasl.h>
 
@@ -37,145 +34,8 @@
 # define sasl_server_done()
 #endif
 
-enum pni_sasl_state {
-  SASL_NONE,
-  SASL_POSTED_INIT,
-  SASL_POSTED_MECHANISMS,
-  SASL_POSTED_RESPONSE,
-  SASL_POSTED_CHALLENGE,
-  SASL_PRETEND_OUTCOME,
-  SASL_RECVED_OUTCOME,
-  SASL_POSTED_OUTCOME
-};
-
-struct pni_sasl_t {
-    // Client selected mechanism
-    char *selected_mechanism;
-    char *included_mechanisms;
-    const char *username;
-    char *password;
-    const char *config_name;
-    char *config_dir;
-    const char *remote_fqdn;
-    sasl_conn_t *cyrus_conn;
-    pn_sasl_outcome_t outcome;
-    pn_bytes_t cyrus_out;
-    enum pni_sasl_state desired_state;
-    enum pni_sasl_state last_state;
-    bool client;
-    bool halt;
-};
-
-static bool pni_sasl_is_server_state(enum pni_sasl_state state)
-{
-  return state==SASL_NONE
-      || state==SASL_POSTED_MECHANISMS
-      || state==SASL_POSTED_CHALLENGE
-      || state==SASL_POSTED_OUTCOME;
-}
-
-static bool pni_sasl_is_client_state(enum pni_sasl_state state)
-{
-  return state==SASL_NONE
-      || state==SASL_POSTED_INIT
-      || state==SASL_POSTED_RESPONSE
-      || state==SASL_PRETEND_OUTCOME
-      || state==SASL_RECVED_OUTCOME;
-}
-
-static bool pni_sasl_is_final_input_state(pni_sasl_t *sasl)
-{
-  enum pni_sasl_state last_state = sasl->last_state;
-  enum pni_sasl_state desired_state = sasl->desired_state;
-  return last_state==SASL_RECVED_OUTCOME
-      || desired_state==SASL_POSTED_OUTCOME;
-}
-
-static bool pni_sasl_is_final_output_state(pni_sasl_t *sasl)
-{
-  enum pni_sasl_state last_state = sasl->last_state;
-  return last_state==SASL_PRETEND_OUTCOME
-      || last_state==SASL_RECVED_OUTCOME
-      || last_state==SASL_POSTED_OUTCOME;
-}
-
 static const char *amqp_service = "amqp";
 
-static inline pn_transport_t *get_transport_internal(pn_sasl_t *sasl)
-{
-    // The external pn_sasl_t is really a pointer to the internal pni_transport_t
-    return ((pn_transport_t *)sasl);
-}
-
-static inline pni_sasl_t *get_sasl_internal(pn_sasl_t *sasl)
-{
-    // The external pn_sasl_t is really a pointer to the internal pni_transport_t
-    return sasl ? ((pn_transport_t *)sasl)->sasl : NULL;
-}
-
-static void pni_emit(pn_transport_t *transport)
-{
-  if (transport->connection && transport->connection->collector) {
-    pn_collector_t *collector = transport->connection->collector;
-    pn_collector_put(collector, PN_OBJECT, transport, PN_TRANSPORT);
-  }
-}
-
-// Look for symbol in the mech include list - not particlarly efficient,
-// but probably not used enough to matter.
-//
-// Note that if there is no inclusion list then every mech is implicitly included.
-static bool pni_included_mech(const char *included_mech_list, pn_bytes_t s)
-{
-  if (!included_mech_list) return true;
-
-  const char * end_list = included_mech_list+strlen(included_mech_list);
-  size_t len = s.size;
-  const char *c = included_mech_list;
-  while (c!=NULL) {
-    // If there are not enough chars left in the list no matches
-    if ((ptrdiff_t)len > end_list-c) return false;
-
-    // Is word equal with a space or end of string afterwards?
-    if (strncasecmp(c, s.start, len)==0 && (c[len]==' ' || c[len]==0) ) return true;
-
-    c = strchr(c, ' ');
-    c = c ? c+1 : NULL;
-  }
-  return false;
-}
-
-// This takes a space separated list and zero terminates it in place
-// whilst adding pointers to the existing strings in a string array.
-// This means that you can't free the original storage until you have
-// finished with the resulting list.
-static void pni_split_mechs(char *mechlist, const char* included_mechs, char *mechs[], int *count)
-{
-  char *start = mechlist;
-  char *end = start;
-
-  while (*end) {
-    if (*end == ' ') {
-      if (start != end) {
-        *end = '\0';
-        if (pni_included_mech(included_mechs, pn_bytes(end-start, start))) {
-          mechs[(*count)++] = start;
-        }
-      }
-      end++;
-      start = end;
-    } else {
-      end++;
-    }
-  }
-
-  if (start != end) {
-    if (pni_included_mech(included_mechs, pn_bytes(end-start, start))) {
-      mechs[(*count)++] = start;
-    }
-  }
-}
-
 static bool pni_check_sasl_result(sasl_conn_t *conn, int r, pn_transport_t *logger)
 {
     if (r!=SASL_OK) {
@@ -208,604 +68,290 @@ static void pni_cyrus_interact(pni_sasl_t *sasl, sasl_interact_t *interact)
   }
 }
 
-static void pni_sasl_set_desired_state(pn_transport_t *transport, enum pni_sasl_state desired_state)
+int pni_sasl_impl_list_mechs(pn_transport_t *transport, char **mechlist)
 {
   pni_sasl_t *sasl = transport->sasl;
-  if (sasl->last_state > desired_state) {
-    pn_transport_logf(transport, "Trying to send SASL frame (%d), but illegal: already in later state (%d)", desired_state, sasl->last_state);
-  } else if (sasl->client && !pni_sasl_is_client_state(desired_state)) {
-    pn_transport_logf(transport, "Trying to send server SASL frame (%d) on a client", desired_state);
-  } else if (!sasl->client && !pni_sasl_is_server_state(desired_state)) {
-    pn_transport_logf(transport, "Trying to send client SASL frame (%d) on a server", desired_state);
-  } else {
-    // If we need to repeat CHALLENGE or RESPONSE frames adjust current state to seem
-    // like they haven't been sent yet
-    if (sasl->last_state==desired_state && desired_state==SASL_POSTED_RESPONSE) {
-      sasl->last_state = SASL_POSTED_INIT;
-    }
-    if (sasl->last_state==desired_state && desired_state==SASL_POSTED_CHALLENGE) {
-      sasl->last_state = SASL_POSTED_MECHANISMS;
-    }
-    sasl->desired_state = desired_state;
-  }
-}
-
-// Post SASL frame
-static void pni_post_sasl_frame(pn_transport_t *transport)
-{
-  pni_sasl_t *sasl = transport->sasl;
-  pn_bytes_t out = sasl->cyrus_out;
-  enum pni_sasl_state desired_state = sasl->desired_state;
-  while (sasl->desired_state > sasl->last_state) {
-    switch (desired_state) {
-    case SASL_POSTED_INIT:
-      pn_post_frame(transport, SASL_FRAME_TYPE, 0, "DL[sz]", SASL_INIT, sasl->selected_mechanism,
-                    out.size, out.start);
-      pni_emit(transport);
-      break;
-    case SASL_PRETEND_OUTCOME:
-      if (sasl->last_state < SASL_POSTED_INIT) {
-        desired_state = SASL_POSTED_INIT;
-        continue;
+  sasl_conn_t *cyrus_conn = (sasl_conn_t*)sasl->impl_context;
+  int count = 0;
+  if (cyrus_conn) {
+    const char *result = NULL;
+
+    int r = sasl_listmech(cyrus_conn, NULL, "", " ", "", &result, NULL, &count);
+    if (pni_check_sasl_result(cyrus_conn, r, transport)) {
+      if (result && *result) {
+        *mechlist = strdup(result);
       }
-      break;
-    case SASL_POSTED_MECHANISMS: {
-      // TODO: Hardcoded limit of 16 mechanisms
-      char *mechs[16];
-      int count = 0;
-
-      char *mechlist = NULL;
-      if (sasl->cyrus_conn) {
-        const char *result = NULL;
-
-        int r = sasl_listmech(sasl->cyrus_conn, NULL, "", " ", "", &result, NULL, NULL);
-        if (pni_check_sasl_result(sasl->cyrus_conn, r, transport)) {
-          if (result && *result) {
-            mechlist = strdup(result);
-            pni_split_mechs(mechlist, sasl->included_mechanisms, mechs, &count);
-          }
-        }
-      }
-      pn_post_frame(transport, SASL_FRAME_TYPE, 0, "DL[@T[*s]]", SASL_MECHANISMS, PN_SYMBOL, count, mechs);
-      free(mechlist);
-      pni_emit(transport);
-      break;
     }
-    case SASL_POSTED_RESPONSE:
-      pn_post_frame(transport, SASL_FRAME_TYPE, 0, "DL[z]", SASL_RESPONSE, out.size, out.start);
-      pni_emit(transport);
-      break;
-    case SASL_POSTED_CHALLENGE:
-      if (sasl->last_state < SASL_POSTED_MECHANISMS) {
-        desired_state = SASL_POSTED_MECHANISMS;
-        continue;
-      }
-      pn_post_frame(transport, SASL_FRAME_TYPE, 0, "DL[z]", SASL_CHALLENGE, out.size, out.start);
-      pni_emit(transport);
-      break;
-    case SASL_POSTED_OUTCOME:
-      if (sasl->last_state < SASL_POSTED_MECHANISMS) {
-        desired_state = SASL_POSTED_MECHANISMS;
-        continue;
-      }
-      pn_post_frame(transport, SASL_FRAME_TYPE, 0, "DL[B]", SASL_OUTCOME, sasl->outcome);
-      pni_emit(transport);
-      break;
-    case SASL_NONE:
-    case SASL_RECVED_OUTCOME:
-      return;
-    }
-    sasl->last_state = desired_state;
-    desired_state = sasl->desired_state;
   }
+  return count;
 }
 
 // Set up callbacks to use interact
 static const sasl_callback_t pni_user_password_callbacks[] = {
-  {SASL_CB_USER, NULL, NULL},
-  {SASL_CB_AUTHNAME, NULL, NULL},
-  {SASL_CB_PASS, NULL, NULL},
-  {SASL_CB_LIST_END, NULL, NULL},
+    {SASL_CB_USER, NULL, NULL},
+    {SASL_CB_AUTHNAME, NULL, NULL},
+    {SASL_CB_PASS, NULL, NULL},
+    {SASL_CB_LIST_END, NULL, NULL},
 };
 
 static const sasl_callback_t pni_user_callbacks[] = {
-  {SASL_CB_USER, NULL, NULL},
-  {SASL_CB_AUTHNAME, NULL, NULL},
-  {SASL_CB_LIST_END, NULL, NULL},
+    {SASL_CB_USER, NULL, NULL},
+    {SASL_CB_AUTHNAME, NULL, NULL},
+    {SASL_CB_LIST_END, NULL, NULL},
 };
 
+bool pni_init_client(pn_transport_t* transport) {
+    int result;
+    pni_sasl_t *sasl = transport->sasl;
+
+    if (sasl->config_dir) {
+        result = sasl_set_path(SASL_PATH_TYPE_CONFIG, sasl->config_dir);
+        if (result!=SASL_OK) return false;
+    }
+
+    result = sasl_client_init(NULL);
+    if (result!=SASL_OK) return false;
+
+    const sasl_callback_t *callbacks = sasl->username ? sasl->password ? pni_user_password_callbacks : pni_user_callbacks : NULL;
+    result = sasl_client_new(amqp_service,
+                             sasl->remote_fqdn,
+                             NULL, NULL,
+                             callbacks, 0,
+                             (sasl_conn_t**)&sasl->impl_context);
+    if (result!=SASL_OK) return false;
+
+    return true;
+}
+
 static int pni_wrap_client_start(pni_sasl_t *sasl, const char *mechs, const char **mechusing)
 {
-  int result;
+    int result;
+    sasl_interact_t *client_interact=NULL;
+    const char *out;
+    unsigned outlen;
 
-  if (sasl->config_dir) {
-    result = sasl_set_path(SASL_PATH_TYPE_CONFIG, sasl->config_dir);
-    if (result!=SASL_OK) return result;
-  }
+    sasl_conn_t *cyrus_conn = (sasl_conn_t*)sasl->impl_context;
+    do {
 
-  result = sasl_client_init(NULL);
-  if (result!=SASL_OK) return result;
-
-  const sasl_callback_t *callbacks = sasl->username ? sasl->password ? pni_user_password_callbacks : pni_user_callbacks : NULL;
-  result = sasl_client_new(amqp_service,
-                           sasl->remote_fqdn,
-                           NULL, NULL,
-                           callbacks, 0,
-                           &sasl->cyrus_conn);
-  if (result!=SASL_OK) return result;
-
-  sasl_interact_t *client_interact=NULL;
-  const char *out;
-  unsigned outlen;
-
-  do {
-
-    result = sasl_client_start(sasl->cyrus_conn,
-                               mechs,
-                               &client_interact,
-                               &out, &outlen,
-                               mechusing);
-    if (result==SASL_INTERACT) {
-      pni_cyrus_interact(sasl, client_interact);
-    }
-  } while (result==SASL_INTERACT);
+        result = sasl_client_start(cyrus_conn,
+                                   mechs,
+                                   &client_interact,
+                                   &out, &outlen,
+                                   mechusing);
+        if (result==SASL_INTERACT) {
+            pni_cyrus_interact(sasl, client_interact);
+        }
+    } while (result==SASL_INTERACT);
 
-  sasl->cyrus_out.start = out;
-  sasl->cyrus_out.size = outlen;
-  return result;
+    sasl->cyrus_out.start = out;
+    sasl->cyrus_out.size = outlen;
+    return result;
 }
 
-static void pni_process_mechanisms(pn_transport_t *transport, const char *mechs, bool short_circuit)
+bool pni_process_mechanisms(pn_transport_t *transport, const char *mechs)
 {
-  pni_sasl_t *sasl = transport->sasl;
-  const char *mech_selected;
-  int result = pni_wrap_client_start(sasl, mechs, &mech_selected);
-  switch (result) {
-  case SASL_OK:
-  case SASL_CONTINUE:
-    sasl->selected_mechanism = strdup(mech_selected);
-    pni_sasl_set_desired_state(transport, short_circuit ? SASL_PRETEND_OUTCOME : SASL_POSTED_INIT);
-    break;
-  case SASL_NOMECH:
-  default:
-    pni_check_sasl_result(sasl->cyrus_conn, result, transport);
-    sasl->last_state = SASL_RECVED_OUTCOME;
-    sasl->halt = true;
-    pn_transport_close_tail(transport);
-    break;
-  }
+    pni_sasl_t *sasl = transport->sasl;
+    sasl_conn_t *cyrus_conn = (sasl_conn_t*)sasl->impl_context;
+    const char *mech_selected;
+    int result = pni_wrap_client_start(sasl, mechs, &mech_selected);
+    switch (result) {
+        case SASL_OK:
+        case SASL_CONTINUE:
+          sasl->selected_mechanism = strdup(mech_selected);
+          return true;
+        case SASL_NOMECH:
+        default:
+          pni_check_sasl_result(cyrus_conn, result, transport);
+          return false;
+    }
 }
 
 
 static int pni_wrap_client_step(pni_sasl_t *sasl, const pn_bytes_t *in)
 {
-  sasl_interact_t *client_interact=NULL;
-  const char *out;
-  unsigned outlen;
-
-  int result;
-  do {
+    sasl_conn_t *cyrus_conn = (sasl_conn_t*)sasl->impl_context;
+    sasl_interact_t *client_interact=NULL;
+    const char *out;
+    unsigned outlen;
 
-    result = sasl_client_step(sasl->cyrus_conn,
-                              in->start, in->size,
-                              &client_interact,
-                              &out, &outlen);
-    if (result==SASL_INTERACT) {
-      pni_cyrus_interact(sasl, client_interact);
-    }
-  } while (result==SASL_INTERACT);
+    int result;
+    do {
+
+        result = sasl_client_step(cyrus_conn,
+                                  in->start, in->size,
+                                  &client_interact,
+                                  &out, &outlen);
+        if (result==SASL_INTERACT) {
+            pni_cyrus_interact(sasl, client_interact);
+        }
+    } while (result==SASL_INTERACT);
 
-  sasl->cyrus_out.start = out;
-  sasl->cyrus_out.size = outlen;
-  return result;
+    sasl->cyrus_out.start = out;
+    sasl->cyrus_out.size = outlen;
+    return result;
 }
 
-static void pni_process_challenge(pn_transport_t *transport, const pn_bytes_t *recv)
+void pni_process_challenge(pn_transport_t *transport, const pn_bytes_t *recv)
 {
-  pni_sasl_t *sasl = transport->sasl;
-  int result = pni_wrap_client_step(sasl, recv);
-  switch (result) {
-  case SASL_OK:
-    // Authenticated
-    // TODO: Documented that we need to call sasl_client_step() again to be sure!;
-  case SASL_CONTINUE:
-    // Need to send a response
-    pni_sasl_set_desired_state(transport, SASL_POSTED_RESPONSE);
-    break;
-  default:
-    pni_check_sasl_result(sasl->cyrus_conn, result, transport);
-
-    // Failed somehow
-    sasl->halt = true;
-    pn_transport_close_tail(transport);
-    break;
-  }
+    pni_sasl_t *sasl = transport->sasl;
+    sasl_conn_t *cyrus_conn = (sasl_conn_t*)sasl->impl_context;
+    int result = pni_wrap_client_step(sasl, recv);
+    switch (result) {
+        case SASL_OK:
+            // Authenticated
+            // TODO: Documented that we need to call sasl_client_step() again to be sure!;
+        case SASL_CONTINUE:
+            // Need to send a response
+            pni_sasl_set_desired_state(transport, SASL_POSTED_RESPONSE);
+            break;
+        default:
+            pni_check_sasl_result(cyrus_conn, result, transport);
+
+            // Failed somehow
+            sasl->halt = true;
+            pn_transport_close_tail(transport);
+            break;
+    }
 }
 
 static int pni_wrap_server_new(pn_transport_t *transport)
 {
-  pni_sasl_t *sasl = transport->sasl;
-  int result;
+    pni_sasl_t *sasl = transport->sasl;
+    int result;
 
-  if (sasl->config_dir) {
-    result = sasl_set_path(SASL_PATH_TYPE_CONFIG, sasl->config_dir);
-    if (result!=SASL_OK) return result;
-  }
+    if (sasl->config_dir) {
+        result = sasl_set_path(SASL_PATH_TYPE_CONFIG, sasl->config_dir);
+        if (result!=SASL_OK) return result;
+    }
 
-  result = sasl_server_init(NULL, sasl->config_name);
-  if (result!=SASL_OK) return result;
+    result = sasl_server_init(NULL, sasl->config_name);
+    if (result!=SASL_OK) return result;
 
-  result = sasl_server_new(amqp_service, NULL, NULL, NULL, NULL, NULL, 0, &sasl->cyrus_conn);
-  if (result!=SASL_OK) return result;
+    result = sasl_server_new(amqp_service, NULL, NULL, NULL, NULL, NULL, 0, (sasl_conn_t**)&sasl->impl_context);
+    if (result!=SASL_OK) return result;
 
-  sasl_security_properties_t secprops = {0};
-  secprops.security_flags =
+    sasl_security_properties_t secprops = {0};
+    secprops.security_flags =
     SASL_SEC_NOPLAINTEXT |
     ( transport->auth_required ? SASL_SEC_NOANONYMOUS : 0 ) ;
+    sasl_conn_t *cyrus_conn = (sasl_conn_t*)sasl->impl_context;
 
-  result = sasl_setprop(sasl->cyrus_conn, SASL_SEC_PROPS, &secprops);
-  if (result!=SASL_OK) return result;
+    result = sasl_setprop(cyrus_conn, SASL_SEC_PROPS, &secprops);
+    if (result!=SASL_OK) return result;
 
-  // EXTERNAL not implemented yet
-#if 0
-  sasl_ssf_t ssf = 128;
-  result = sasl_setprop(sasl->cyrus_conn, SASL_SSF_EXTERNAL, &ssf);
-  if (result!=SASL_OK) return result;
+    // EXTERNAL not implemented yet
+    #if 0
+    sasl_ssf_t ssf = 128;
+    result = sasl_setprop(sasl->cyrus_conn, SASL_SSF_EXTERNAL, &ssf);
+    if (result!=SASL_OK) return result;
 
-  const char *extid = "user";
-  result = sasl_setprop(sasl->cyrus_conn, SASL_AUTH_EXTERNAL, extid);
-  if (result!=SASL_OK) return result;
-#endif
+    const char *extid = "user";
+    result = sasl_setprop(sasl->cyrus_conn, SASL_AUTH_EXTERNAL, extid);
+    if (result!=SASL_OK) return result;
+    #endif
 
-  return result;
+    return result;
 }
 
 static int pni_wrap_server_start(pni_sasl_t *sasl, const char *mech_selected, const pn_bytes_t *in)
 {
-  int result;
-  const char *out;
-  unsigned outlen;
-  result = sasl_server_start(sasl->cyrus_conn,
-                             mech_selected,
-                             in->start, in->size,
-                             &out, &outlen);
-
-  sasl->cyrus_out.start = out;
-  sasl->cyrus_out.size = outlen;
-  return result;
-}
-
-static void pni_process_server_result(pn_transport_t *transport, int result)
-{
-  pni_sasl_t *sasl = transport->sasl;
-  switch (result) {
-  case SASL_OK:
-    // Authenticated
-    sasl->outcome = PN_SASL_OK;
-    transport->authenticated = true;
-    // Get username from SASL
-    const void* value;
-    sasl_getprop(sasl->cyrus_conn, SASL_USERNAME, &value);
-    sasl->username = (const char*) value;
-    pn_transport_logf(transport, "Authenticated user: %s with mechanism %s", sasl->username, sasl->selected_mechanism);
-    pni_sasl_set_desired_state(transport, SASL_POSTED_OUTCOME);
-    break;
-  case SASL_CONTINUE:
-    // Need to send a challenge
-    pni_sasl_set_desired_state(transport, SASL_POSTED_CHALLENGE);
-    break;
-  default:
-    pni_check_sasl_result(sasl->cyrus_conn, result, transport);
-
-    // Failed to authenticate
-    sasl->outcome = PN_SASL_AUTH;
-    pni_sasl_set_desired_state(transport, SASL_POSTED_OUTCOME);
-    break;
-  }
-  pni_emit(transport);
-}
-
-static void pni_process_init(pn_transport_t *transport, const char *mechanism, const pn_bytes_t *recv)
-{
-  pni_sasl_t *sasl = transport->sasl;
-
-  int result = pni_wrap_server_start(sasl, mechanism, recv);
-  if (result==SASL_OK) {
-    // We need to filter out a supplied mech in in the inclusion list
-    // as the client could have used a mech that we support, but that
-    // wasn't on the list we sent.
-    if (!pni_included_mech(sasl->included_mechanisms, pn_bytes(strlen(mechanism), mechanism))) {
-      sasl_seterror(sasl->cyrus_conn, 0, "Client mechanism not in mechanism inclusion list.");
-      result = SASL_FAIL;
-    }
-  }
-  pni_process_server_result(transport, result);
-}
-
-static int pni_wrap_server_step(pni_sasl_t *sasl, const pn_bytes_t *in)
-{
     int result;
     const char *out;
     unsigned outlen;
-    result = sasl_server_step(sasl->cyrus_conn,
-                              in->start, in->size,
-                              &out, &outlen);
+    sasl_conn_t *cyrus_conn = (sasl_conn_t*)sasl->impl_context;
+    result = sasl_server_start(cyrus_conn,
+                               mech_selected,
+                               in->start, in->size,
+                               &out, &outlen);
 
     sasl->cyrus_out.start = out;
     sasl->cyrus_out.size = outlen;
     return result;
 }
 
-static void pni_process_response(pn_transport_t *transport, const pn_bytes_t *recv)
-{
-  pni_sasl_t *sasl = transport->sasl;
-  int result = pni_wrap_server_step(sasl, recv);
-  pni_process_server_result(transport, result);
-}
-
-pn_sasl_t *pn_sasl(pn_transport_t *transport)
-{
-  if (!transport->sasl) {
-    pni_sasl_t *sasl = (pni_sasl_t *) malloc(sizeof(pni_sasl_t));
-
-    const char *sasl_config_path = getenv("PN_SASL_CONFIG_PATH");
-
-    sasl->client = !transport->server;
-    sasl->selected_mechanism = NULL;
-    sasl->included_mechanisms = NULL;
-    sasl->username = NULL;
-    sasl->password = NULL;
-    sasl->config_name = sasl->client ? "proton-client" : "proton-server";
-    sasl->config_dir =  sasl_config_path ? strdup(sasl_config_path) : NULL;
-    sasl->remote_fqdn = NULL;
-    sasl->outcome = PN_SASL_NONE;
-    sasl->cyrus_conn = NULL;
-    sasl->cyrus_out.size = 0;
-    sasl->cyrus_out.start = NULL;
-    sasl->desired_state = SASL_NONE;
-    sasl->last_state = SASL_NONE;
-    sasl->halt = false;
-
-    transport->sasl = sasl;
-  }
-
-  // The actual external pn_sasl_t pointer is a pointer to its enclosing pn_transport_t
-  return (pn_sasl_t *)transport;
-}
-
-// This is a hack to tell us that
-// no actual negotiation is going to happen and we can go
-// straight to the AMQP layer; it can only work on the client side
-// As the server doesn't know if SASL is even active until it sees
-// the SASL header from the client first.
-static void pni_sasl_force_anonymous(pn_transport_t *transport)
-{
-  pni_sasl_t *sasl = transport->sasl;
-  if (sasl->client) {
-    // Pretend we got sasl mechanisms frame with just ANONYMOUS
-    pni_process_mechanisms(transport, "ANONYMOUS", true);
-  }
-  pni_emit(transport);
-}
-
-void pni_sasl_set_remote_hostname(pn_transport_t * transport, const char * fqdn)
-{
-  pni_sasl_t *sasl = transport->sasl;
-  sasl->remote_fqdn = fqdn;
-}
-
-void pni_sasl_set_user_password(pn_transport_t *transport, const char *user, const char *password)
-{
-  pni_sasl_t *sasl = transport->sasl;
-  sasl->username = user;
-  free(sasl->password);
-  sasl->password = password ? strdup(password) : NULL;
-}
-
-const char *pn_sasl_get_user(pn_sasl_t *sasl0)
-{
-    pni_sasl_t *sasl = get_sasl_internal(sasl0);
-    return sasl->username;
-}
-
-const char *pn_sasl_get_mech(pn_sasl_t *sasl0)
-{
-    pni_sasl_t *sasl = get_sasl_internal(sasl0);
-    return sasl->selected_mechanism;
-}
-
-void pn_sasl_allowed_mechs(pn_sasl_t *sasl0, const char *mechs)
+static void pni_process_server_result(pn_transport_t *transport, int result)
 {
-    pni_sasl_t *sasl = get_sasl_internal(sasl0);
-    free(sasl->included_mechanisms);
-    sasl->included_mechanisms = mechs ? strdup(mechs) : NULL;
-    if (strcmp(mechs, "ANONYMOUS")==0 ) {
-      pn_transport_t *transport = get_transport_internal(sasl0);
-      pni_sasl_force_anonymous(transport);
+    pni_sasl_t *sasl = transport->sasl;
+    sasl_conn_t *cyrus_conn = (sasl_conn_t*)sasl->impl_context;
+    switch (result) {
+        case SASL_OK:
+            // Authenticated
+            sasl->outcome = PN_SASL_OK;
+            transport->authenticated = true;
+            // Get username from SASL
+            const void* value;
+            sasl_getprop(cyrus_conn, SASL_USERNAME, &value);
+            sasl->username = (const char*) value;
+            pn_transport_logf(transport, "Authenticated user: %s with mechanism %s", sasl->username, sasl->selected_mechanism);
+            pni_sasl_set_desired_state(transport, SASL_POSTED_OUTCOME);
+            break;
+        case SASL_CONTINUE:
+            // Need to send a challenge
+            pni_sasl_set_desired_state(transport, SASL_POSTED_CHALLENGE);
+            break;
+        default:
+            pni_check_sasl_result(cyrus_conn, result, transport);
+
+            // Failed to authenticate
+            sasl->outcome = PN_SASL_AUTH;
+            pni_sasl_set_desired_state(transport, SASL_POSTED_OUTCOME);
+            break;
     }
 }
 
-void pn_sasl_config_name(pn_sasl_t *sasl0, const char *name)
-{
-    pni_sasl_t *sasl = get_sasl_internal(sasl0);
-    sasl->config_name = name;
-}
-
-void pn_sasl_config_path(pn_sasl_t *sasl0, const char *dir)
-{
-    pni_sasl_t *sasl = get_sasl_internal(sasl0);
-    free(sasl->config_dir);
-    sasl->config_dir = strdup(dir);
-}
-
-void pn_sasl_done(pn_sasl_t *sasl0, pn_sasl_outcome_t outcome)
+bool pni_init_server(pn_transport_t* transport)
 {
-  pni_sasl_t *sasl = get_sasl_internal(sasl0);
-  if (sasl) {
-    sasl->outcome = outcome;
-  }
+    int r = pni_wrap_server_new(transport);
+    sasl_conn_t *cyrus_conn = (sasl_conn_t*)transport->sasl->impl_context;
+    return pni_check_sasl_result(cyrus_conn, r, transport);
 }
 
-pn_sasl_outcome_t pn_sasl_outcome(pn_sasl_t *sasl0)
+void pni_process_init(pn_transport_t *transport, const char *mechanism, const pn_bytes_t *recv)
 {
-  pni_sasl_t *sasl = get_sasl_internal(sasl0);
-  return sasl ? sasl->outcome : PN_SASL_NONE;
-}
-
-void pn_sasl_free(pn_transport_t *transport)
-{
-  if (transport) {
     pni_sasl_t *sasl = transport->sasl;
-    if (sasl) {
-      free(sasl->selected_mechanism);
-      free(sasl->included_mechanisms);
-      free(sasl->password);
-      free(sasl->config_dir);
-
-      // CYRUS_SASL
-      if (sasl->cyrus_conn) {
-          sasl_dispose(&sasl->cyrus_conn);
-          if (sasl->client) {
-              sasl_client_done();
-          } else {
-              sasl_server_done();
-          }
-      }
-
-      free(sasl);
-    }
-  }
-}
-
-static void pni_sasl_server_init(pn_transport_t *transport)
-{
-  int r = pni_wrap_server_new(transport);
-
-  if (!pni_check_sasl_result(transport->sasl->cyrus_conn, r, transport)) {
-      return;
-  }
 
-  // Setup to send SASL mechanisms frame
-  pni_sasl_set_desired_state(transport, SASL_POSTED_MECHANISMS);
-}
-
-static void pn_sasl_process(pn_transport_t *transport)
-{
-  pni_sasl_t *sasl = transport->sasl;
-  if (!sasl->client) {
-    if (sasl->desired_state<SASL_POSTED_MECHANISMS) {
-      pni_sasl_server_init(transport);
+    int result = pni_wrap_server_start(sasl, mechanism, recv);
+    if (result==SASL_OK) {
+        // We need to filter out a supplied mech in in the inclusion list
+        // as the client could have used a mech that we support, but that
+        // wasn't on the list we sent.
+        if (!pni_included_mech(sasl->included_mechanisms, pn_bytes(strlen(mechanism), mechanism))) {
+            sasl_conn_t *cyrus_conn = (sasl_conn_t*)sasl->impl_context;
+            sasl_seterror(cyrus_conn, 0, "Client mechanism not in mechanism inclusion list.");
+            result = SASL_FAIL;
+        }
     }
-  }
+    pni_process_server_result(transport, result);
 }
 
-ssize_t pn_sasl_input(pn_transport_t *transport, const char *bytes, size_t available)
-{
-  pn_sasl_process(transport);
-
-  pni_sasl_t *sasl = transport->sasl;
-  ssize_t n = pn_dispatcher_input(transport, bytes, available, false, &sasl->halt);
-
-  if (n==0 && pni_sasl_is_final_input_state(sasl)) {
-    return PN_EOS;
-  }
-  return n;
-}
-
-ssize_t pn_sasl_output(pn_transport_t *transport, char *bytes, size_t size)
+static int pni_wrap_server_step(pni_sasl_t *sasl, const pn_bytes_t *in)
 {
-  pn_sasl_process(transport);
-
-  pni_post_sasl_frame(transport);
+    int result;
+    const char *out;
+    unsigned outlen;
+    sasl_conn_t *cyrus_conn = (sasl_conn_t*)sasl->impl_context;
+    result = sasl_server_step(cyrus_conn,
+                              in->start, in->size,
+                              &out, &outlen);
 
-  pni_sasl_t *sasl = transport->sasl;
-  if (transport->available == 0 && pni_sasl_is_final_output_state(sasl)) {
-    if (sasl->outcome != PN_SASL_OK && pni_sasl_is_final_input_state(sasl)) {
-      pn_transport_close_tail(transport);
-    }
-    return PN_EOS;
-  } else {
-    return pn_dispatcher_output(transport, bytes, size);
-  }
+    sasl->cyrus_out.start = out;
+    sasl->cyrus_out.size = outlen;
+    return result;
 }
 
-// Received Server side
-int pn_do_init(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
+void pni_process_response(pn_transport_t *transport, const pn_bytes_t *recv)
 {
-  pni_sasl_t *sasl = transport->sasl;
-  pn_bytes_t mech;
-  pn_bytes_t recv;
-  int err = pn_data_scan(args, "D.[sz]", &mech, &recv);
-  if (err) return err;
-  sasl->selected_mechanism = pn_strndup(mech.start, mech.size);
-
-  pni_process_init(transport, sasl->selected_mechanism, &recv);
-
-  return 0;
+    pni_sasl_t *sasl = transport->sasl;
+    int result = pni_wrap_server_step(sasl, recv);
+    pni_process_server_result(transport, result);
 }
 
-// Received client side
-int pn_do_mechanisms(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
+void pni_sasl_impl_free(pn_transport_t *transport)
 {
-  // If we already pretended we got the ANONYMOUS mech then ignore
-  if (transport->sasl->last_state==SASL_PRETEND_OUTCOME) return 0;
-
-  pn_string_t *mechs = pn_string("");
-
-  // This scanning relies on pn_data_scan leaving the pn_data_t cursors
-  // where they are after finishing the scan
-  int err = pn_data_scan(args, "D.[@[");
-  if (err) return err;
-
-  // Now keep checking for end of array and pull a symbol
-  while(pn_data_next(args)) {
-    pn_bytes_t s = pn_data_get_symbol(args);
-    if (pni_included_mech(transport->sasl->included_mechanisms, s)) {
-      pn_string_addf(mechs, "%*s ", (int)s.size, s.start);
+    sasl_dispose((sasl_conn_t**)&transport->sasl->impl_context);
+    if (transport->sasl->client) {
+        sasl_client_done();
+    } else {
+        sasl_server_done();
     }
-  }
-  pn_string_buffer(mechs)[pn_string_size(mechs)-1] = 0;
-
-  pni_process_mechanisms(transport, pn_string_get(mechs), false);
-
-  pn_free(mechs);
-  return 0;
-}
-
-// Received client side
-int pn_do_challenge(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
-{
-  pn_bytes_t recv;
-  int err = pn_data_scan(args, "D.[z]", &recv);
-  if (err) return err;
-
-  pni_process_challenge(transport, &recv);
-
-  return 0;
-}
-
-// Received server side
-int pn_do_response(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
-{
-  pn_bytes_t recv;
-  int err = pn_data_scan(args, "D.[z]", &recv);
-  if (err) return err;
-
-  pni_process_response(transport, &recv);
-
-  return 0;
-}
-
-// Received client side
-int pn_do_outcome(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
-{
-  pni_sasl_t *sasl = transport->sasl;
-  uint8_t outcome;
-  int err = pn_data_scan(args, "D.[B]", &outcome);
-  if (err) return err;
-  sasl->outcome = (pn_sasl_outcome_t) outcome;
-  sasl->last_state = SASL_RECVED_OUTCOME;
-  sasl->halt = true;
-  pni_emit(transport);
-  return 0;
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/df8e9ac5/proton-c/src/sasl/none_sasl.c
----------------------------------------------------------------------
diff --git a/proton-c/src/sasl/none_sasl.c b/proton-c/src/sasl/none_sasl.c
index ff962ac..6900654 100644
--- a/proton-c/src/sasl/none_sasl.c
+++ b/proton-c/src/sasl/none_sasl.c
@@ -19,408 +19,125 @@
  *
  */
 
-#include <assert.h>
-#include <proton/codec.h>
+#include "sasl-internal.h"
 
-#include "buffer.h"
-#include "protocol.h"
-#include "dispatch_actions.h"
-#include "util.h"
 #include "engine/engine-internal.h"
 
-struct pni_sasl_t {
-  char *selected_mechanism;
-  char *included_mechanisms;
-  const char *username;
-  char *password;
-  const char *remote_fqdn;
-  pn_buffer_t *send_data;
-  pn_buffer_t *recv_data;
-  pn_sasl_outcome_t outcome;
-  bool client;
-  bool sent_init;
-  bool rcvd_init;
-  bool sent_done;
-  bool rcvd_done;
-  bool halt;
-};
-
-static inline pn_transport_t *get_transport_internal(pn_sasl_t *sasl)
-{
-    // The external pn_sasl_t is really a pointer to the internal pni_transport_t
-    return ((pn_transport_t *)sasl);
-}
-
-static inline pni_sasl_t *get_sasl_internal(pn_sasl_t *sasl)
-{
-    // The external pn_sasl_t is really a pointer to the internal pni_transport_t
-    return sasl ? ((pn_transport_t *)sasl)->sasl : NULL;
-}
-
-static void pni_emit(pn_sasl_t *sasl) {
-  pn_transport_t *transport = get_transport_internal(sasl);
-  if (transport->connection && transport->connection->collector) {
-    pn_collector_t *collector = transport->connection->collector;
-    pn_collector_put(collector, PN_OBJECT, transport, PN_TRANSPORT);
-  }
-}
-
-pn_sasl_t *pn_sasl(pn_transport_t *transport)
-{
-  if (!transport->sasl) {
-    pni_sasl_t *sasl = (pni_sasl_t *) malloc(sizeof(pni_sasl_t));
-
-    sasl->client = !transport->server;
-    sasl->included_mechanisms = NULL;
-    sasl->selected_mechanism = NULL;
-    sasl->send_data = pn_buffer(16);
-    sasl->recv_data = pn_buffer(16);
-    sasl->outcome = PN_SASL_NONE;
-    sasl->sent_init = false;
-    sasl->rcvd_init = false;
-    sasl->sent_done = false;
-    sasl->rcvd_done = false;
-    sasl->halt = false;
-
-    transport->sasl = sasl;
-  }
-
-  // The actual external pn_sasl_t pointer is a pointer to its enclosing pn_transport_t
-  return (pn_sasl_t *)transport;
-}
-
-void pn_sasl_allowed_mechs(pn_sasl_t *sasl0, const char *mechs)
-{
-  pni_sasl_t *sasl = get_sasl_internal(sasl0);
-  if (!sasl) return;
-  free(sasl->included_mechanisms);
-  sasl->included_mechanisms = mechs ? pn_strdup(mechs) : NULL;
-  if (strcmp(mechs, "ANONYMOUS")==0 ) {
-    // If we do this on the client it is a hack to tell us that
-    // no actual negatiation is going to happen and we can go
-    // straight to the AMQP layer
-    if (sasl->client) {
-        sasl->rcvd_done = true;
-        sasl->sent_done = true;
-    }
-  }
-  pni_emit(sasl0);
-}
-
-ssize_t pn_sasl_send(pn_sasl_t *sasl0, const char *bytes, size_t size)
-{
-  pni_sasl_t *sasl = get_sasl_internal(sasl0);
-  if (sasl) {
-    if (pn_buffer_size(sasl->send_data)) {
-      // XXX: need better error
-      return PN_STATE_ERR;
-    }
-    int err = pn_buffer_append(sasl->send_data, bytes, size);
-    if (err) return err;
-    pni_emit(sasl0);
-    return size;
-  } else {
-    return PN_ARG_ERR;
-  }
-}
-
-size_t pn_sasl_pending(pn_sasl_t *sasl0)
-{
-  pni_sasl_t *sasl = get_sasl_internal(sasl0);
-  if (sasl && pn_buffer_size(sasl->recv_data)) {
-    return pn_buffer_size(sasl->recv_data);
-  } else {
-    return 0;
-  }
-}
-
-ssize_t pn_sasl_recv(pn_sasl_t *sasl0, char *bytes, size_t size)
-{
-  pni_sasl_t *sasl = get_sasl_internal(sasl0);
-  if (!sasl) return PN_ARG_ERR;
-
-  size_t bsize = pn_buffer_size(sasl->recv_data);
-  if (bsize) {
-    if (bsize > size) return PN_OVERFLOW;
-    pn_buffer_get(sasl->recv_data, 0, bsize, bytes);
-    pn_buffer_clear(sasl->recv_data);
-    return bsize;
-  } else {
-    return PN_EOS;
-  }
-}
-
-void pn_sasl_client(pn_sasl_t *sasl)
-{
-}
-
-void pn_sasl_server(pn_sasl_t *sasl0)
-{
-  pni_sasl_t *sasl = get_sasl_internal(sasl0);
-  if (sasl) {
-    sasl->client = false;
-  }
-}
-
-void pni_sasl_set_user_password(pn_transport_t *transport, const char *user, const char *password)
-{
-  pni_sasl_t *sasl = transport->sasl;
-  sasl->username = user;
-  sasl->password = password ? pn_strdup(password) : NULL;
-}
-
-const char *pn_sasl_get_user(pn_sasl_t *sasl0)
-{
-  return "anonymous";
-}
-
-const char *pn_sasl_get_mech(pn_sasl_t *sasl0)
-{
-  return "ANONYMOUS";
-}
-
-void pn_sasl_config_name(pn_sasl_t *sasl0, const char *name)
-{
-}
-
-void pn_sasl_config_path(pn_sasl_t *sasl0, const char *path)
-{
-}
-
-void pni_sasl_set_remote_hostname(pn_transport_t * transport, const char * fqdn)
-{
-  pni_sasl_t *sasl = transport->sasl;
-  sasl->remote_fqdn = fqdn;
-}
-
-void pn_sasl_plain(pn_sasl_t *sasl0, const char *username, const char *password)
+#if 0
+// TODO: skeleton to produce PLAIN init frame
+void pn_sasl_plain(pni_sasl_t *sasl, const char *username, const char *password)
 {
-  pni_sasl_t *sasl = get_sasl_internal(sasl0);
   if (!sasl) return;
 
   const char *user = username ? username : "";
   const char *pass = password ? password : "";
-  size_t usize = strlen(user);
-  size_t psize = strlen(pass);
-  size_t size = usize + psize + 2;
-  char *iresp = (char *) malloc(size);
 
-  iresp[0] = 0;
-  memmove(iresp + 1, user, usize);
-  iresp[usize + 1] = 0;
-  memmove(iresp + usize + 2, pass, psize);
-
-  pn_sasl_allowed_mechs(sasl0, "PLAIN");
-  pn_sasl_send(sasl0, iresp, size);
-  free(iresp);
 }
+#endif
+static const char ANONYMOUS[] = "ANONYMOUS";
+static const char PLAIN[] = "PLAIN";
 
-void pn_sasl_done(pn_sasl_t *sasl0, pn_sasl_outcome_t outcome)
+bool pni_init_server(pn_transport_t* transport)
 {
-  pni_sasl_t *sasl = get_sasl_internal(sasl0);
-  if (sasl) {
-    sasl->outcome = outcome;
-    pni_emit(sasl0);
-  }
+  return true;
 }
 
-pn_sasl_outcome_t pn_sasl_outcome(pn_sasl_t *sasl0)
+bool pni_init_client(pn_transport_t* transport)
 {
-  pni_sasl_t *sasl = get_sasl_internal(sasl0);
-  return sasl ? sasl->outcome : PN_SASL_NONE;
+  return true;
 }
 
-void pn_sasl_free(pn_transport_t *transport)
+void pni_sasl_impl_free(pn_transport_t *transport)
 {
-  if (transport) {
-    pni_sasl_t *sasl = transport->sasl;
-    if (sasl) {
-      free(sasl->included_mechanisms);
-      free(sasl->selected_mechanism);
-      pn_buffer_free(sasl->send_data);
-      pn_buffer_free(sasl->recv_data);
-      free(sasl);
-    }
-  }
+  free(transport->sasl->impl_context);
 }
 
-void pn_client_init(pn_transport_t *transport)
+// Client handles ANONYMOUS or PLAIN mechanisms if offered
+bool pni_process_mechanisms(pn_transport_t *transport, const char *mechs)
 {
-  pni_sasl_t *sasl = transport->sasl;
-  pn_buffer_memory_t bytes = pn_buffer_memory(sasl->send_data);
-  pn_post_frame(transport, SASL_FRAME_TYPE, 0, "DL[sz]", SASL_INIT, sasl->included_mechanisms,
-                bytes.size, bytes.start);
-  pn_buffer_clear(sasl->send_data);
-  pni_emit((pn_sasl_t *) transport);
-}
+  // Check whether offered ANONYMOUS or PLAIN
+  // Look for "PLAIN" in mechs
+  const char *found = strstr(mechs, PLAIN);
+  // Make sure that string is separated and terminated, allowed
+  // and we have a username and password
+  if (found && (found==mechs || found[-1]==' ') && (found[5]==0 || found[5]==' ') &&
+      pni_included_mech(transport->sasl->included_mechanisms, pn_bytes(5, found)) &&
+      transport->sasl->username && transport->sasl->password) {
+    transport->sasl->selected_mechanism = strdup(PLAIN);
+    size_t usize = strlen(transport->sasl->username);
+    size_t psize = strlen(transport->sasl->password);
+    size_t size = usize + psize + 2;
+    char *iresp = (char *) malloc(size);
+    if (!iresp) return false;
 
-void pni_sasl_server_init(pn_transport_t *transport)
-{
-  pni_sasl_t *sasl = transport->sasl;
-  // XXX
-  char *mechs[16];
-  int count = 0;
+    transport->sasl->impl_context = iresp;
 
-  if (sasl->included_mechanisms) {
-    char *start = sasl->included_mechanisms;
-    char *end = start;
+    iresp[0] = 0;
+    memmove(iresp + 1, transport->sasl->username, usize);
+    iresp[usize + 1] = 0;
+    memmove(iresp + usize + 2, transport->sasl->password, psize);
+    transport->sasl->cyrus_out.start = iresp;
+    transport->sasl->cyrus_out.size =  size;
 
-    while (*end) {
-      if (*end == ' ') {
-        if (start != end) {
-          *end = '\0';
-          mechs[count++] = start;
-        }
-        end++;
-        start = end;
-      } else {
-        end++;
-      }
-    }
+    // Zero out password and dealloc
+    free(memset(transport->sasl->password, 0, psize));
+    transport->sasl->password = NULL;
 
-    if (start != end) {
-      mechs[count++] = start;
-    }
+    return true;
   }
 
-  pn_post_frame(transport, SASL_FRAME_TYPE, 0, "DL[@T[*s]]", SASL_MECHANISMS, PN_SYMBOL, count, mechs);
-  pni_emit((pn_sasl_t *) transport);
-}
+  // Look for "ANONYMOUS" in mechs
+  found = strstr(mechs, ANONYMOUS);
+  // Make sure that string is separated and terminated and allowed
+  if (found && (found==mechs || found[-1]==' ') && (found[9]==0 || found[9]==' ') &&
+      pni_included_mech(transport->sasl->included_mechanisms, pn_bytes(9, found))) {
+    transport->sasl->selected_mechanism = strdup(ANONYMOUS);
+    if (transport->sasl->username) {
+      size_t size = strlen(transport->sasl->username);
+      char *iresp = (char *) malloc(size);
+      if (!iresp) return false;
 
-void pn_server_done(pn_sasl_t *sasl0)
-{
-  pn_transport_t *transport = get_transport_internal(sasl0);
-  pni_sasl_t *sasl = transport->sasl;
-  pn_post_frame(transport, SASL_FRAME_TYPE, 0, "DL[B]", SASL_OUTCOME, sasl->outcome);
-  pni_emit(sasl0);
-}
+      transport->sasl->impl_context = iresp;
 
-void pn_sasl_process(pn_transport_t *transport)
-{
-  pni_sasl_t *sasl = transport->sasl;
-  if (!sasl->sent_init) {
-    if (sasl->client) {
-      pn_client_init(transport);
+      memmove(iresp, transport->sasl->username, size);
+      transport->sasl->cyrus_out.start = iresp;
+      transport->sasl->cyrus_out.size =  size;
     } else {
-      pni_sasl_server_init(transport);
+      static const char anon[] = "anonymous";
+      transport->sasl->cyrus_out.start = anon;
+      transport->sasl->cyrus_out.size =  sizeof anon-1;
     }
-    sasl->sent_init = true;
-  }
-
-  if (pn_buffer_size(sasl->send_data)) {
-    pn_buffer_memory_t bytes = pn_buffer_memory(sasl->send_data);
-    pn_post_frame(transport, SASL_FRAME_TYPE, 0, "DL[z]", sasl->client ? SASL_RESPONSE : SASL_CHALLENGE,
-                  bytes.size, bytes.start);
-    pn_buffer_clear(sasl->send_data);
-    pni_emit((pn_sasl_t *) transport);
-  }
-
-  if (!sasl->client && sasl->outcome != PN_SASL_NONE && !sasl->sent_done) {
-    pn_server_done((pn_sasl_t *)transport);
-    sasl->sent_done = true;
-  }
-
-  // XXX: need to finish this check when challenge/response is complete
-  //      check for client is outome is received
-  //      check for server is that there are no pending frames (either init
-  //      or challenges) from client
-  if (!sasl->client && sasl->sent_done && sasl->rcvd_init) {
-    sasl->rcvd_done = true;
-    sasl->halt = true;
+    return true;
   }
+  return false;
 }
 
-ssize_t pn_sasl_input(pn_transport_t *transport, const char *bytes, size_t available)
+// Server will offer only ANONYMOUS
+int pni_sasl_impl_list_mechs(pn_transport_t *transport, char **mechlist)
 {
-  pni_sasl_t *sasl = transport->sasl;
-  ssize_t n = pn_dispatcher_input(transport, bytes, available, false, &sasl->halt);
-  if (n < 0) return n;
-
-  pn_sasl_process(transport);
-
-  if (sasl->rcvd_done) {
-    if (sasl->outcome == PN_SASL_OK) {
-      if (n) {
-        return n;
-      } else {
-        return PN_EOS;
-      }
-    } else {
-      // XXX: should probably do something better here
-      return PN_EOS;
-    }
-  } else {
-    return n;
-  }
+  *mechlist = strdup("ANONYMOUS");
+  return 1;
 }
 
-ssize_t pn_sasl_output(pn_transport_t *transport, char *bytes, size_t size)
+void pni_process_init(pn_transport_t *transport, const char *mechanism, const pn_bytes_t *recv)
 {
-  pn_sasl_process(transport);
-
-  pni_sasl_t *sasl = transport->sasl;
-  if (transport->available == 0 && sasl->sent_done) {
-    if (sasl->outcome == PN_SASL_OK) {
-      return PN_EOS;
-    } else {
-      // XXX: should probably do something better here
-      return PN_EOS;
-    }
+  // Check that mechanism is ANONYMOUS and it is allowed
+  if (strcmp(mechanism, "ANONYMOUS")==0 &&
+      pni_included_mech(transport->sasl->included_mechanisms, pn_bytes(sizeof(ANONYMOUS)-1, ANONYMOUS))) {
+    transport->sasl->username = "anonymous";
+    transport->sasl->outcome = PN_SASL_OK;
+    pni_sasl_set_desired_state(transport, SASL_POSTED_OUTCOME);
   } else {
-    return pn_dispatcher_output(transport, bytes, size);
+    transport->sasl->outcome = PN_SASL_AUTH;
+    pni_sasl_set_desired_state(transport, SASL_POSTED_OUTCOME);
   }
 }
 
-int pn_do_init(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
-{
-  pni_sasl_t *sasl = transport->sasl;
-  pn_bytes_t mech;
-  pn_bytes_t recv;
-  int err = pn_data_scan(args, "D.[sz]", &mech, &recv);
-  if (err) return err;
-  sasl->selected_mechanism = pn_strndup(mech.start, mech.size);
-  pn_buffer_append(sasl->recv_data, recv.start, recv.size);
-  sasl->rcvd_init = true;
-  return 0;
-}
-
-int pn_do_mechanisms(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
-{
-  pni_sasl_t *sasl = transport->sasl;
-  sasl->rcvd_init = true;
-  return 0;
-}
-
-int pn_do_recv(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
-{
-  pni_sasl_t *sasl = transport->sasl;
-  pn_bytes_t recv;
-  int err = pn_data_scan(args, "D.[z]", &recv);
-  if (err) return err;
-  pn_buffer_append(sasl->recv_data, recv.start, recv.size);
-  return 0;
-}
-
-int pn_do_challenge(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
-{
-  return pn_do_recv(transport, frame_type, channel, args, payload);
-}
-
-int pn_do_response(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
+/* The default implementation neither sends nor receives challenges or responses */
+void pni_process_challenge(pn_transport_t *transport, const pn_bytes_t *recv)
 {
-  return pn_do_recv(transport, frame_type, channel, args, payload);
 }
 
-int pn_do_outcome(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
+void pni_process_response(pn_transport_t *transport, const pn_bytes_t *recv)
 {
-  pni_sasl_t *sasl = transport->sasl;
-  uint8_t outcome;
-  int err = pn_data_scan(args, "D.[B]", &outcome);
-  if (err) return err;
-  sasl->outcome = (pn_sasl_outcome_t) outcome;
-  sasl->rcvd_done = true;
-  sasl->sent_done = true;
-  sasl->halt = true;
-  pni_emit((pn_sasl_t *) transport);
-  return 0;
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/df8e9ac5/proton-c/src/sasl/sasl-internal.h
----------------------------------------------------------------------
diff --git a/proton-c/src/sasl/sasl-internal.h b/proton-c/src/sasl/sasl-internal.h
index 965eff2..b2d30c8 100644
--- a/proton-c/src/sasl/sasl-internal.h
+++ b/proton-c/src/sasl/sasl-internal.h
@@ -23,18 +23,56 @@
 #define PROTON_SASL_INTERNAL_H 1
 
 #include "proton/types.h"
+#include "proton/sasl.h"
 
-/** Destructor for the given SASL layer.
- *
- * @param[in] sasl the SASL object to free. No longer valid on
- *                 return.
- */
+// SASL APIs used by transport code
 void pn_sasl_free(pn_transport_t *transport);
-
-ssize_t pn_sasl_input(pn_transport_t *transport, const char *bytes, size_t available);
-ssize_t pn_sasl_output(pn_transport_t *transport, char *bytes, size_t size);
-
 void pni_sasl_set_user_password(pn_transport_t *transport, const char *user, const char *password);
 void pni_sasl_set_remote_hostname(pn_transport_t *transport, const char* fqdn);
 
+// Internal SASL authenticator interface
+void pni_sasl_impl_free(pn_transport_t *transport);
+int pni_sasl_impl_list_mechs(pn_transport_t* transport, char** mechlist);
+bool pni_init_server(pn_transport_t* transport);
+void pni_process_init(pn_transport_t *transport, const char *mechanism, const pn_bytes_t *recv);
+void pni_process_response(pn_transport_t *transport, const pn_bytes_t *recv);
+
+bool pni_init_client(pn_transport_t* transport);
+bool pni_process_mechanisms(pn_transport_t *transport, const char *mechs);
+void pni_process_challenge(pn_transport_t *transport, const pn_bytes_t *recv);
+
+// Shared SASL API used by the actual SASL authenticators
+enum pni_sasl_state {
+  SASL_NONE,
+  SASL_POSTED_INIT,
+  SASL_POSTED_MECHANISMS,
+  SASL_POSTED_RESPONSE,
+  SASL_POSTED_CHALLENGE,
+  SASL_PRETEND_OUTCOME,
+  SASL_RECVED_OUTCOME,
+  SASL_POSTED_OUTCOME
+};
+
+struct pni_sasl_t {
+  void *impl_context;
+  // Client selected mechanism
+  char *selected_mechanism;
+  char *included_mechanisms;
+  const char *username;
+  char *password;
+  const char *config_name;
+  char *config_dir;
+  const char *remote_fqdn;
+  pn_sasl_outcome_t outcome;
+  pn_bytes_t cyrus_out;
+  enum pni_sasl_state desired_state;
+  enum pni_sasl_state last_state;
+  bool client;
+  bool halt;
+};
+
+void pni_split_mechs(char *mechlist, const char* included_mechs, char *mechs[], int *count);
+bool pni_included_mech(const char *included_mech_list, pn_bytes_t s);
+void pni_sasl_set_desired_state(pn_transport_t *transport, enum pni_sasl_state desired_state);
+
 #endif /* sasl-internal.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/df8e9ac5/proton-c/src/sasl/sasl.c
----------------------------------------------------------------------
diff --git a/proton-c/src/sasl/sasl.c b/proton-c/src/sasl/sasl.c
index 0c58b1f..2b59460 100644
--- a/proton-c/src/sasl/sasl.c
+++ b/proton-c/src/sasl/sasl.c
@@ -21,7 +21,10 @@
 
 #include "sasl-internal.h"
 
+#include "dispatch_actions.h"
 #include "engine/engine-internal.h"
+#include "protocol.h"
+#include "platform.h" // For strncasecmp on Windows
 #include "transport/autodetect.h"
 
 #include <assert.h>
@@ -32,12 +35,8 @@ static inline pn_transport_t *get_transport_internal(pn_sasl_t *sasl)
     return ((pn_transport_t *)sasl);
 }
 
-void pn_sasl_allow_skip(pn_sasl_t *sasl0, bool allow)
-{
-    if (!sasl0) return;
-    pn_transport_t *transport = get_transport_internal(sasl0);
-    pn_transport_require_auth(transport, !allow);
-}
+static ssize_t pn_sasl_input(pn_transport_t *transport, const char *bytes, size_t available);
+static ssize_t pn_sasl_output(pn_transport_t *transport, char *bytes, size_t size);
 
 static ssize_t pn_input_read_sasl_header(pn_transport_t* transport, unsigned int layer, const char* bytes, size_t available);
 static ssize_t pn_input_read_sasl(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available);
@@ -159,3 +158,467 @@ static ssize_t pn_output_write_sasl(pn_transport_t* transport, unsigned int laye
   return pni_passthru_layer.process_output(transport, layer, bytes, available );
 }
 
+static bool pni_sasl_is_server_state(enum pni_sasl_state state)
+{
+  return state==SASL_NONE
+      || state==SASL_POSTED_MECHANISMS
+      || state==SASL_POSTED_CHALLENGE
+      || state==SASL_POSTED_OUTCOME;
+}
+
+static bool pni_sasl_is_client_state(enum pni_sasl_state state)
+{
+  return state==SASL_NONE
+      || state==SASL_POSTED_INIT
+      || state==SASL_POSTED_RESPONSE
+      || state==SASL_PRETEND_OUTCOME
+      || state==SASL_RECVED_OUTCOME;
+}
+
+static bool pni_sasl_is_final_input_state(pni_sasl_t *sasl)
+{
+  enum pni_sasl_state last_state = sasl->last_state;
+  enum pni_sasl_state desired_state = sasl->desired_state;
+  return last_state==SASL_RECVED_OUTCOME
+      || desired_state==SASL_POSTED_OUTCOME;
+}
+
+static bool pni_sasl_is_final_output_state(pni_sasl_t *sasl)
+{
+  enum pni_sasl_state last_state = sasl->last_state;
+  return last_state==SASL_PRETEND_OUTCOME
+      || last_state==SASL_RECVED_OUTCOME
+      || last_state==SASL_POSTED_OUTCOME;
+}
+
+static inline pni_sasl_t *get_sasl_internal(pn_sasl_t *sasl)
+{
+    // The external pn_sasl_t is really a pointer to the internal pni_transport_t
+    return sasl ? ((pn_transport_t *)sasl)->sasl : NULL;
+}
+
+static void pni_emit(pn_transport_t *transport)
+{
+  if (transport->connection && transport->connection->collector) {
+    pn_collector_t *collector = transport->connection->collector;
+    pn_collector_put(collector, PN_OBJECT, transport, PN_TRANSPORT);
+  }
+}
+
+// Look for symbol in the mech include list - not particlarly efficient,
+// but probably not used enough to matter.
+//
+// Note that if there is no inclusion list then every mech is implicitly included.
+bool pni_included_mech(const char *included_mech_list, pn_bytes_t s)
+{
+  if (!included_mech_list) return true;
+
+  const char * end_list = included_mech_list+strlen(included_mech_list);
+  size_t len = s.size;
+  const char *c = included_mech_list;
+  while (c!=NULL) {
+    // If there are not enough chars left in the list no matches
+    if ((ptrdiff_t)len > end_list-c) return false;
+
+    // Is word equal with a space or end of string afterwards?
+    if (strncasecmp(c, s.start, len)==0 && (c[len]==' ' || c[len]==0) ) return true;
+
+    c = strchr(c, ' ');
+    c = c ? c+1 : NULL;
+  }
+  return false;
+}
+
+// This takes a space separated list and zero terminates it in place
+// whilst adding pointers to the existing strings in a string array.
+// This means that you can't free the original storage until you have
+// finished with the resulting list.
+void pni_split_mechs(char *mechlist, const char* included_mechs, char *mechs[], int *count)
+{
+  char *start = mechlist;
+  char *end = start;
+
+  while (*end) {
+    if (*end == ' ') {
+      if (start != end) {
+        *end = '\0';
+        if (pni_included_mech(included_mechs, pn_bytes(end-start, start))) {
+          mechs[(*count)++] = start;
+        }
+      }
+      end++;
+      start = end;
+    } else {
+      end++;
+    }
+  }
+
+  if (start != end) {
+    if (pni_included_mech(included_mechs, pn_bytes(end-start, start))) {
+      mechs[(*count)++] = start;
+    }
+  }
+}
+
+void pni_sasl_set_desired_state(pn_transport_t *transport, enum pni_sasl_state desired_state)
+{
+  pni_sasl_t *sasl = transport->sasl;
+  if (sasl->last_state > desired_state) {
+    pn_transport_logf(transport, "Trying to send SASL frame (%d), but illegal: already in later state (%d)", desired_state, sasl->last_state);
+  } else if (sasl->client && !pni_sasl_is_client_state(desired_state)) {
+    pn_transport_logf(transport, "Trying to send server SASL frame (%d) on a client", desired_state);
+  } else if (!sasl->client && !pni_sasl_is_server_state(desired_state)) {
+    pn_transport_logf(transport, "Trying to send client SASL frame (%d) on a server", desired_state);
+  } else {
+    // If we need to repeat CHALLENGE or RESPONSE frames adjust current state to seem
+    // like they haven't been sent yet
+    if (sasl->last_state==desired_state && desired_state==SASL_POSTED_RESPONSE) {
+      sasl->last_state = SASL_POSTED_INIT;
+    }
+    if (sasl->last_state==desired_state && desired_state==SASL_POSTED_CHALLENGE) {
+      sasl->last_state = SASL_POSTED_MECHANISMS;
+    }
+    sasl->desired_state = desired_state;
+    pni_emit(transport);
+  }
+}
+
+// Post SASL frame
+static void pni_post_sasl_frame(pn_transport_t *transport)
+{
+  pni_sasl_t *sasl = transport->sasl;
+  pn_bytes_t out = sasl->cyrus_out;
+  enum pni_sasl_state desired_state = sasl->desired_state;
+  while (sasl->desired_state > sasl->last_state) {
+    switch (desired_state) {
+    case SASL_POSTED_INIT:
+      pn_post_frame(transport, SASL_FRAME_TYPE, 0, "DL[sz]", SASL_INIT, sasl->selected_mechanism,
+                    out.size, out.start);
+      pni_emit(transport);
+      break;
+    case SASL_PRETEND_OUTCOME:
+      if (sasl->last_state < SASL_POSTED_INIT) {
+        desired_state = SASL_POSTED_INIT;
+        continue;
+      }
+      break;
+    case SASL_POSTED_MECHANISMS: {
+      // TODO: Hardcoded limit of 16 mechanisms
+      char *mechs[16];
+      char *mechlist = NULL;
+
+      int count = 0;
+      if (pni_sasl_impl_list_mechs(transport, &mechlist) > 0) {
+        pni_split_mechs(mechlist, sasl->included_mechanisms, mechs, &count);
+      }
+
+      pn_post_frame(transport, SASL_FRAME_TYPE, 0, "DL[@T[*s]]", SASL_MECHANISMS, PN_SYMBOL, count, mechs);
+      free(mechlist);
+      pni_emit(transport);
+      break;
+    }
+    case SASL_POSTED_RESPONSE:
+      pn_post_frame(transport, SASL_FRAME_TYPE, 0, "DL[z]", SASL_RESPONSE, out.size, out.start);
+      pni_emit(transport);
+      break;
+    case SASL_POSTED_CHALLENGE:
+      if (sasl->last_state < SASL_POSTED_MECHANISMS) {
+        desired_state = SASL_POSTED_MECHANISMS;
+        continue;
+      }
+      pn_post_frame(transport, SASL_FRAME_TYPE, 0, "DL[z]", SASL_CHALLENGE, out.size, out.start);
+      pni_emit(transport);
+      break;
+    case SASL_POSTED_OUTCOME:
+      if (sasl->last_state < SASL_POSTED_MECHANISMS) {
+        desired_state = SASL_POSTED_MECHANISMS;
+        continue;
+      }
+      pn_post_frame(transport, SASL_FRAME_TYPE, 0, "DL[B]", SASL_OUTCOME, sasl->outcome);
+      pni_emit(transport);
+      break;
+    case SASL_NONE:
+    case SASL_RECVED_OUTCOME:
+      return;
+    }
+    sasl->last_state = desired_state;
+    desired_state = sasl->desired_state;
+  }
+}
+
+pn_sasl_t *pn_sasl(pn_transport_t *transport)
+{
+  if (!transport->sasl) {
+    pni_sasl_t *sasl = (pni_sasl_t *) malloc(sizeof(pni_sasl_t));
+
+    const char *sasl_config_path = getenv("PN_SASL_CONFIG_PATH");
+
+    sasl->impl_context = NULL;
+    sasl->client = !transport->server;
+    sasl->selected_mechanism = NULL;
+    sasl->included_mechanisms = NULL;
+    sasl->username = NULL;
+    sasl->password = NULL;
+    sasl->config_name = sasl->client ? "proton-client" : "proton-server";
+    sasl->config_dir =  sasl_config_path ? strdup(sasl_config_path) : NULL;
+    sasl->remote_fqdn = NULL;
+    sasl->outcome = PN_SASL_NONE;
+    sasl->impl_context = NULL;
+    sasl->cyrus_out.size = 0;
+    sasl->cyrus_out.start = NULL;
+    sasl->desired_state = SASL_NONE;
+    sasl->last_state = SASL_NONE;
+    sasl->halt = false;
+
+    transport->sasl = sasl;
+  }
+
+  // The actual external pn_sasl_t pointer is a pointer to its enclosing pn_transport_t
+  return (pn_sasl_t *)transport;
+}
+
+// This is a hack to tell us that
+// no actual negotiation is going to happen and we can go
+// straight to the AMQP layer; it can only work on the client side
+// As the server doesn't know if SASL is even active until it sees
+// the SASL header from the client first.
+static void pni_sasl_force_anonymous(pn_transport_t *transport)
+{
+  pni_sasl_t *sasl = transport->sasl;
+  if (sasl->client) {
+    // Pretend we got sasl mechanisms frame with just ANONYMOUS
+    if (pni_init_client(transport) &&
+        pni_process_mechanisms(transport, "ANONYMOUS")) {
+      pni_sasl_set_desired_state(transport, SASL_PRETEND_OUTCOME);
+    } else {
+      sasl->last_state = SASL_RECVED_OUTCOME;
+      sasl->halt = true;
+      pn_transport_close_tail(transport);
+    }
+  }
+}
+
+void pni_sasl_set_remote_hostname(pn_transport_t * transport, const char * fqdn)
+{
+  pni_sasl_t *sasl = transport->sasl;
+  sasl->remote_fqdn = fqdn;
+}
+
+void pni_sasl_set_user_password(pn_transport_t *transport, const char *user, const char *password)
+{
+  pni_sasl_t *sasl = transport->sasl;
+  sasl->username = user;
+  free(sasl->password);
+  sasl->password = password ? strdup(password) : NULL;
+}
+
+const char *pn_sasl_get_user(pn_sasl_t *sasl0)
+{
+    pni_sasl_t *sasl = get_sasl_internal(sasl0);
+    return sasl->username;
+}
+
+const char *pn_sasl_get_mech(pn_sasl_t *sasl0)
+{
+    pni_sasl_t *sasl = get_sasl_internal(sasl0);
+    return sasl->selected_mechanism;
+}
+
+void pn_sasl_allowed_mechs(pn_sasl_t *sasl0, const char *mechs)
+{
+    pni_sasl_t *sasl = get_sasl_internal(sasl0);
+    free(sasl->included_mechanisms);
+    sasl->included_mechanisms = mechs ? strdup(mechs) : NULL;
+    if (strcmp(mechs, "ANONYMOUS")==0 ) {
+      pn_transport_t *transport = get_transport_internal(sasl0);
+      pni_sasl_force_anonymous(transport);
+    }
+}
+
+void pn_sasl_config_name(pn_sasl_t *sasl0, const char *name)
+{
+    pni_sasl_t *sasl = get_sasl_internal(sasl0);
+    sasl->config_name = name;
+}
+
+void pn_sasl_config_path(pn_sasl_t *sasl0, const char *dir)
+{
+    pni_sasl_t *sasl = get_sasl_internal(sasl0);
+    free(sasl->config_dir);
+    sasl->config_dir = strdup(dir);
+}
+
+void pn_sasl_done(pn_sasl_t *sasl0, pn_sasl_outcome_t outcome)
+{
+  pni_sasl_t *sasl = get_sasl_internal(sasl0);
+  if (sasl) {
+    sasl->outcome = outcome;
+  }
+}
+
+pn_sasl_outcome_t pn_sasl_outcome(pn_sasl_t *sasl0)
+{
+  pni_sasl_t *sasl = get_sasl_internal(sasl0);
+  return sasl ? sasl->outcome : PN_SASL_NONE;
+}
+
+void pn_sasl_free(pn_transport_t *transport)
+{
+  if (transport) {
+    pni_sasl_t *sasl = transport->sasl;
+    if (sasl) {
+      free(sasl->selected_mechanism);
+      free(sasl->included_mechanisms);
+      free(sasl->password);
+      free(sasl->config_dir);
+
+      // CYRUS_SASL
+      if (sasl->impl_context) {
+          pni_sasl_impl_free(transport);
+      }
+
+      free(sasl);
+    }
+  }
+}
+
+static void pni_sasl_server_init(pn_transport_t *transport)
+{
+  if (!pni_init_server(transport)) return;
+
+  // Setup to send SASL mechanisms frame
+  pni_sasl_set_desired_state(transport, SASL_POSTED_MECHANISMS);
+}
+
+static void pn_sasl_process(pn_transport_t *transport)
+{
+  pni_sasl_t *sasl = transport->sasl;
+  if (!sasl->client) {
+    if (sasl->desired_state<SASL_POSTED_MECHANISMS) {
+      pni_sasl_server_init(transport);
+    }
+  }
+}
+
+ssize_t pn_sasl_input(pn_transport_t *transport, const char *bytes, size_t available)
+{
+  pn_sasl_process(transport);
+
+  pni_sasl_t *sasl = transport->sasl;
+  ssize_t n = pn_dispatcher_input(transport, bytes, available, false, &sasl->halt);
+
+  if (n==0 && pni_sasl_is_final_input_state(sasl)) {
+    return PN_EOS;
+  }
+  return n;
+}
+
+ssize_t pn_sasl_output(pn_transport_t *transport, char *bytes, size_t size)
+{
+  pn_sasl_process(transport);
+
+  pni_post_sasl_frame(transport);
+
+  pni_sasl_t *sasl = transport->sasl;
+  if (transport->available == 0 && pni_sasl_is_final_output_state(sasl)) {
+    if (sasl->outcome != PN_SASL_OK && pni_sasl_is_final_input_state(sasl)) {
+      pn_transport_close_tail(transport);
+    }
+    return PN_EOS;
+  } else {
+    return pn_dispatcher_output(transport, bytes, size);
+  }
+}
+
+// Received Server side
+int pn_do_init(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
+{
+  pni_sasl_t *sasl = transport->sasl;
+  pn_bytes_t mech;
+  pn_bytes_t recv;
+  int err = pn_data_scan(args, "D.[sz]", &mech, &recv);
+  if (err) return err;
+  sasl->selected_mechanism = pn_strndup(mech.start, mech.size);
+
+  pni_process_init(transport, sasl->selected_mechanism, &recv);
+
+  return 0;
+}
+
+// Received client side
+int pn_do_mechanisms(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
+{
+  pni_sasl_t *sasl = transport->sasl;
+
+  // If we already pretended we got the ANONYMOUS mech then ignore
+  if (sasl->last_state==SASL_PRETEND_OUTCOME) return 0;
+
+  // This scanning relies on pn_data_scan leaving the pn_data_t cursors
+  // where they are after finishing the scan
+  int err = pn_data_scan(args, "D.[@[");
+  if (err) return err;
+
+  pn_string_t *mechs = pn_string("");
+
+  // Now keep checking for end of array and pull a symbol
+  while(pn_data_next(args)) {
+    pn_bytes_t s = pn_data_get_symbol(args);
+    if (pni_included_mech(transport->sasl->included_mechanisms, s)) {
+      pn_string_addf(mechs, "%*s ", (int)s.size, s.start);
+    }
+  }
+  pn_string_buffer(mechs)[pn_string_size(mechs)-1] = 0;
+
+  if (pni_init_client(transport) &&
+      pni_process_mechanisms(transport, pn_string_get(mechs))) {
+    pni_sasl_set_desired_state(transport, SASL_POSTED_INIT);
+  } else {
+    sasl->last_state = SASL_RECVED_OUTCOME;
+    sasl->halt = true;
+    pn_transport_close_tail(transport);
+  }
+
+  pn_free(mechs);
+  return 0;
+}
+
+// Received client side
+int pn_do_challenge(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
+{
+  pn_bytes_t recv;
+  int err = pn_data_scan(args, "D.[z]", &recv);
+  if (err) return err;
+
+  pni_process_challenge(transport, &recv);
+
+  return 0;
+}
+
+// Received server side
+int pn_do_response(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
+{
+  pn_bytes_t recv;
+  int err = pn_data_scan(args, "D.[z]", &recv);
+  if (err) return err;
+
+  pni_process_response(transport, &recv);
+
+  return 0;
+}
+
+// Received client side
+int pn_do_outcome(pn_transport_t *transport, uint8_t frame_type, uint16_t channel, pn_data_t *args, const pn_bytes_t *payload)
+{
+  uint8_t outcome;
+  int err = pn_data_scan(args, "D.[B]", &outcome);
+  if (err) return err;
+
+  pni_sasl_t *sasl = transport->sasl;
+  sasl->outcome = (pn_sasl_outcome_t) outcome;
+  sasl->last_state = SASL_RECVED_OUTCOME;
+  sasl->halt = true;
+
+  return 0;
+}
+
+

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/df8e9ac5/proton-c/src/ssl/ssl-internal.h
----------------------------------------------------------------------
diff --git a/proton-c/src/ssl/ssl-internal.h b/proton-c/src/ssl/ssl-internal.h
index f9687d0..3d9e163 100644
--- a/proton-c/src/ssl/ssl-internal.h
+++ b/proton-c/src/ssl/ssl-internal.h
@@ -21,6 +21,8 @@
  *
  */
 
+#include "proton/ssl.h"
+
 /** @file
  * Internal API for SSL/TLS support in the Driver Layer.
  *


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


Mime
View raw message