You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by as...@apache.org on 2015/05/06 23:00:07 UTC
[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
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 <as...@apache.org>
Authored: Tue Apr 28 00:28:55 2015 -0400
Committer: Andrew Stitcher <as...@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
[2/2] qpid-proton git commit: NO-JIRA: We can now refactor the SASL
bypass flags back into the SASL struct
Posted by as...@apache.org.
NO-JIRA: We can now refactor the SASL bypass flags back into the SASL struct
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/6dd8084b
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/6dd8084b
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/6dd8084b
Branch: refs/heads/master
Commit: 6dd8084b0de28ccdd51121137f3a60d3182e7bae
Parents: df8e9ac
Author: Andrew Stitcher <as...@apache.org>
Authored: Wed May 6 13:31:07 2015 -0400
Committer: Andrew Stitcher <as...@apache.org>
Committed: Wed May 6 16:18:57 2015 -0400
----------------------------------------------------------------------
proton-c/src/engine/engine-internal.h | 4 ----
proton-c/src/sasl/sasl-internal.h | 2 ++
proton-c/src/sasl/sasl.c | 14 ++++++++------
proton-c/src/transport/transport.c | 3 ---
4 files changed, 10 insertions(+), 13 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6dd8084b/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 748efbb..4b24a02 100644
--- a/proton-c/src/engine/engine-internal.h
+++ b/proton-c/src/engine/engine-internal.h
@@ -197,10 +197,6 @@ struct pn_transport_t {
bool encrypted;
bool referenced;
-
- // Temporarily here until refactor
- bool sasl_input_bypass;
- bool sasl_output_bypass;
};
struct pn_connection_t {
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6dd8084b/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 b2d30c8..19fc7ce 100644
--- a/proton-c/src/sasl/sasl-internal.h
+++ b/proton-c/src/sasl/sasl-internal.h
@@ -68,6 +68,8 @@ struct pni_sasl_t {
enum pni_sasl_state desired_state;
enum pni_sasl_state last_state;
bool client;
+ bool input_bypass;
+ bool output_bypass;
bool halt;
};
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6dd8084b/proton-c/src/sasl/sasl.c
----------------------------------------------------------------------
diff --git a/proton-c/src/sasl/sasl.c b/proton-c/src/sasl/sasl.c
index 2b59460..01eeb88 100644
--- a/proton-c/src/sasl/sasl.c
+++ b/proton-c/src/sasl/sasl.c
@@ -114,12 +114,12 @@ static ssize_t pn_input_read_sasl(pn_transport_t* transport, unsigned int layer,
return PN_EOS;
}
- if (!transport->sasl_input_bypass) {
+ if (!transport->sasl->input_bypass) {
ssize_t n = pn_sasl_input(transport, bytes, available);
if (n != PN_EOS) return n;
- transport->sasl_input_bypass = true;
- if (transport->sasl_output_bypass)
+ transport->sasl->input_bypass = true;
+ if (transport->sasl->output_bypass)
transport->io_layers[layer] = &pni_passthru_layer;
}
return pni_passthru_layer.process_input(transport, layer, bytes, available );
@@ -141,7 +141,7 @@ static ssize_t pn_output_write_sasl_header(pn_transport_t *transport, unsigned i
static ssize_t pn_output_write_sasl(pn_transport_t* transport, unsigned int layer, char* bytes, size_t available)
{
- if (!transport->sasl_output_bypass) {
+ if (!transport->sasl->output_bypass) {
// this accounts for when pn_do_error is invoked, e.g. by idle timeout
ssize_t n;
if (transport->close_sent) {
@@ -151,8 +151,8 @@ static ssize_t pn_output_write_sasl(pn_transport_t* transport, unsigned int laye
}
if (n != PN_EOS) return n;
- transport->sasl_output_bypass = true;
- if (transport->sasl_input_bypass)
+ transport->sasl->output_bypass = true;
+ if (transport->sasl->input_bypass)
transport->io_layers[layer] = &pni_passthru_layer;
}
return pni_passthru_layer.process_output(transport, layer, bytes, available );
@@ -368,6 +368,8 @@ pn_sasl_t *pn_sasl(pn_transport_t *transport)
sasl->cyrus_out.start = NULL;
sasl->desired_state = SASL_NONE;
sasl->last_state = SASL_NONE;
+ sasl->input_bypass = false;
+ sasl->output_bypass = false;
sasl->halt = false;
transport->sasl = sasl;
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6dd8084b/proton-c/src/transport/transport.c
----------------------------------------------------------------------
diff --git a/proton-c/src/transport/transport.c b/proton-c/src/transport/transport.c
index f6c3c19..46d6364 100644
--- a/proton-c/src/transport/transport.c
+++ b/proton-c/src/transport/transport.c
@@ -411,9 +411,6 @@ static void pn_transport_initialize(void *object)
transport->referenced = true;
- transport->sasl_input_bypass = false;
- transport->sasl_output_bypass = false;
-
transport->trace = (pn_env_bool("PN_TRACE_RAW") ? PN_TRACE_RAW : PN_TRACE_OFF) |
(pn_env_bool("PN_TRACE_FRM") ? PN_TRACE_FRM : PN_TRACE_OFF) |
(pn_env_bool("PN_TRACE_DRV") ? PN_TRACE_DRV : PN_TRACE_OFF);
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org