* is particularly useful for servers that respond to multiple names. */
#define SASL_GSS_LOCAL_NAME 20
+/* Channel binding information. Memory is managed by the caller. */
typedef struct sasl_channel_binding {
- char *type;
+ const char *name;
int critical;
unsigned long len;
- unsigned char *data;
-} sasl_channel_binding;
+ const unsigned char *data;
+} sasl_channel_binding_t;
#define SASL_CHANNEL_BINDING 21
void *client_creds;
/* for additions which don't require a version upgrade; set to 0 */
- void *gss_peer_name;
- void *gss_local_name;
- void *spare_ptr4;
+ const void *gss_peer_name;
+ const void *gss_local_name;
+ const char *cbindingname; /* channel binding name from packet */
int (*spare_fptr1)();
int (*spare_fptr2)();
- int chanbindingflag;
+ unsigned int cbindingdisp; /* channel binding disposition from client */
int spare_int2;
int spare_int3;
int spare_int4;
SASL_INFO_LIST_END
} sasl_info_callback_stage_t;
+/******************************
+ * Channel binding macros **
+ ******************************/
+
+/* TRUE if channel binding is non-NULL */
+#define SASL_CB_DISP_NONE 0x00 /* client did not support CB */
+#define SASL_CB_DISP_USED 0x01 /* client supports CB, thinks server does not */
+#define SASL_CB_DISP_WANT 0x02 /* client supports and used CB */
+#define SASL_CB_PRESENT(params) ((params)->cbinding != NULL)
+#define SASL_CB_CRITICAL(params) (SASL_CB_PRESENT(params) && \
+ (params)->cbinding->critical)
/******************************
* Client Mechanism Functions *
sasl_ssf_t external_ssf; /* external SSF active */
/* for additions which don't require a version upgrade; set to 0 */
- void *gss_creds;
- void *chanbindingtype;
- void *chanbindingdata;
+ const void *gss_creds; /* GSS credential handle */
+ const sasl_channel_binding_t *cbinding; /* client channel binding */
+ void *spare_ptr3;
void *spare_ptr4;
/* Canonicalize a user name from on-wire to internal format
int (*spare_fptr1)();
-#define SASL_CB_FLAG_NONE 0x00 /* client did not support CB */
-#define SASL_CB_FLAG_USED 0x01 /* client supports CB, thinks server does not */
-#define SASL_CB_FLAG_WANT 0x02 /* client supports and used CB */
-#define SASL_CB_FLAG_CRIT 0x10 /* client requires CB */
- int chanbindingflags;
-#define SASL_CB_PRESENT(params) ((params)->chanbindingtype != NULL && (params)->chanbindinglen)
- int chanbindinglen;
+ unsigned int cbindingdisp;
+ unsigned int spare_int2;
int spare_int3;
/* flags field as passed to sasl_client_new */
struct propctx *propctx;
/* for additions which don't require a version upgrade; set to 0 */
- void *gss_creds;
- void *chanbindingtype;
- void *chanbindingdata;
+ const void *gss_creds; /* GSS credential handle */
+ const sasl_channel_binding_t *cbinding; /* server channel binding */
+ void *spare_ptr3;
void *spare_ptr4;
int (*spare_fptr1)();
int (*spare_fptr2)();
- int chanbindinglen;
- int chanbindingcrit;
+ int spare_int1;
+ int spare_int2;
int spare_int3;
/* flags field as passed to sasl_server_new */
void *rock
)
{
- char delimiter;
-
if (stage == SASL_INFO_LIST_START) {
printf ("List of auxprop plugins follows\n");
return;
cmechanism_t *m=NULL,*bestm=NULL;
size_t i, list_len;
sasl_ssf_t bestssf = 0, minssf = 0;
- int result, server_can_cb = 0, cb_flag;
+ int result, server_can_cb = 0;
+ unsigned int cbindingdisp = 0;
if(_sasl_client_active==0) return SASL_NOTINIT;
goto done;
if (SASL_CB_PRESENT(c_conn->cparams)) {
- if (server_can_cb == 0 &&
- (c_conn->cparams->chanbindingflags & SASL_CB_FLAG_CRIT)) {
+ if (server_can_cb == 0 && SASL_CB_CRITICAL(c_conn->cparams)) {
result = SASL_NOMECH;
goto done;
} else {
- cb_flag = SASL_CB_FLAG_WANT;
+ cbindingdisp = SASL_CB_DISP_WANT;
}
} else {
- cb_flag = SASL_CB_FLAG_NONE;
+ cbindingdisp = SASL_CB_DISP_NONE;
}
for (i = 0, name = ordered_mechs; i < list_len; i++) {
}
/* Prefer server advertised CB mechanisms */
- if (SASL_CB_PRESENT(c_conn->cparams) && plus)
- cb_flag = SASL_CB_FLAG_USED;
+ if (SASL_CB_PRESENT(c_conn->cparams) && plus) {
+ cbindingdisp = SASL_CB_DISP_USED;
+ }
if (mech) {
*mech = m->m.plug->mech_name;
c_conn->cparams->external_ssf = conn->external.ssf;
c_conn->cparams->props = conn->props;
- c_conn->cparams->chanbindingflags |= cb_flag;
+ c_conn->cparams->cbindingdisp = cbindingdisp;
c_conn->mech = bestm;
/* init that plugin */
((sasl_client_conn_t *)conn)->cparams->gss_creds = (void *)value;
break;
case SASL_CHANNEL_BINDING: {
- struct sasl_channel_binding *cb = (struct sasl_channel_binding *)value;
+ const struct sasl_channel_binding *cb = (const struct sasl_channel_binding *)value;
- if (conn->type == SASL_CONN_SERVER) {
- ((sasl_server_conn_t *)conn)->sparams->chanbindingtype = cb->type;
- ((sasl_server_conn_t *)conn)->sparams->chanbindingdata = cb->data;
- ((sasl_server_conn_t *)conn)->sparams->chanbindinglen = cb->len;
- ((sasl_server_conn_t *)conn)->sparams->chanbindingcrit = cb->critical;
- } else {
- ((sasl_client_conn_t *)conn)->cparams->chanbindingtype = cb->type;
- ((sasl_client_conn_t *)conn)->cparams->chanbindingdata = cb->data;
- ((sasl_client_conn_t *)conn)->cparams->chanbindinglen = cb->len;
- if (cb->critical != 0)
- ((sasl_client_conn_t *)conn)->cparams->chanbindingflags |= SASL_CB_FLAG_CRIT;
- else
- ((sasl_client_conn_t *)conn)->cparams->chanbindingflags &= ~(SASL_CB_FLAG_CRIT);
- }
+ if (conn->type == SASL_CONN_SERVER)
+ ((sasl_server_conn_t *)conn)->sparams->cbinding = cb;
+ else
+ ((sasl_client_conn_t *)conn)->cparams->cbinding = cb;
break;
}
default:
}
/* Validate channel bindings */
- if (conn->oparams.chanbindingflag == SASL_CB_FLAG_NONE &&
- s_conn->sparams->chanbindingcrit) {
- sasl_seterror(conn, 0,
- "server requires channel binding but client provided none");
- ret = SASL_BADAUTH;
- } else if (conn->oparams.chanbindingflag == SASL_CB_FLAG_WANT &&
- SASL_CB_PRESENT(s_conn->sparams)) {
- sasl_seterror(conn, 0,
- "client incorrectly assumed server had no channel binding");
- ret = SASL_BADAUTH;
- } else if (conn->oparams.user == NULL || conn->oparams.authid == NULL) {
+ switch (conn->oparams.cbindingdisp) {
+ case SASL_CB_DISP_NONE:
+ if (SASL_CB_CRITICAL(s_conn->sparams)) {
+ sasl_seterror(conn, 0,
+ "server requires channel binding but client provided none");
+ ret = SASL_BADAUTH;
+ }
+ break;
+ case SASL_CB_DISP_WANT:
+ if (SASL_CB_PRESENT(s_conn->sparams)) {
+ sasl_seterror(conn, 0,
+ "client incorrectly assumed server had no channel binding");
+ ret = SASL_BADAUTH;
+ }
+ break;
+ case SASL_CB_DISP_USED:
+ if (!SASL_CB_PRESENT(s_conn->sparams)) {
+ sasl_seterror(conn, 0,
+ "client provided channel binding but server had none");
+ ret = SASL_BADAUTH;
+ } else if (strcmp(conn->oparams.cbindingname,
+ s_conn->sparams->cbinding->name) != 0) {
+ sasl_seterror(conn, 0,
+ "client channel binding %s does not match server %s",
+ conn->oparams.cbindingname, s_conn->sparams->cbinding->name);
+ ret = SASL_BADAUTH;
+ }
+ break;
+ }
+
+ if (ret == SASL_OK &&
+ (conn->oparams.user == NULL || conn->oparams.authid == NULL)) {
sasl_seterror(conn, 0,
"mech did not call canon_user for both authzid " \
"and authid");
* he non-PLUS-variant due to policy reasons, it MUST advertise
* only the PLUS-variant.
*/
- if (!s_conn->sparams->chanbindingcrit) {
+ if (!SASL_CB_PRESENT(s_conn->sparams) ||
+ !SASL_CB_CRITICAL(s_conn->sparams)) {
if (pcount != NULL)
(*pcount)++;
if (flag)
int niflags, error;
struct sockaddr_storage local_ip, remote_ip;
int cb_flag = 0;
- sasl_channel_binding cb;
+ sasl_channel_binding_t cb;
while ((c = getopt(argc, argv, "cp:s:m:")) != EOF) {
switch(c) {
if (r != SASL_OK) saslfail(r, "allocating connection state");
if (cb_flag) {
- cb.type = "sasl-sample";
+ cb.name = "sasl-sample";
cb.data = "this is a test of channel binding";
cb.len = strlen(cb.data);
int nfds, fd = -1;
FILE *in, *out;
fd_set readfds;
- sasl_channel_binding cb;
+ sasl_channel_binding_t cb;
FD_ZERO(&readfds);
for (i = 1; i <= l[0]; i++)
NULL, 0, &conn);
if (r != SASL_OK) saslfail(r, "allocating connection state");
- cb.type = "sasl-sample";
+ cb.name = "sasl-sample";
cb.critical = cb_flag;
cb.data = "this is a test of channel binding";
cb.len = strlen(cb.data);