* is particularly useful for servers that respond to multiple names. */
#define SASL_GSS_LOCAL_NAME 20
-typedef struct sasl_channel_bindings {
+typedef struct sasl_channel_binding {
char *type;
int critical;
unsigned long len;
unsigned char *data;
-} sasl_channel_bindings;
+} sasl_channel_binding;
-#define SASL_CHANNEL_BINDINGS 21
+#define SASL_CHANNEL_BINDING 21
/* set property in SASL connection state
* returns:
/* for additions which don't require a version upgrade; set to 0 */
void *gss_creds;
- void *chanbindingstype;
- void *chanbindingsdata;
+ void *chanbindingtype;
+ void *chanbindingdata;
void *spare_ptr4;
/* Canonicalize a user name from on-wire to internal format
#define SASL_CB_FLAG_NONE 0 /* client did not support CB */
#define SASL_CB_FLAG_USED 1 /* client supports and used CB */
#define SASL_CB_FLAG_WANT 2 /* client supports CB, thinks server does not */
-
- int chanbindingsflag;
- int chanbindingslen;
+ int chanbindingflag;
+#define SASL_CB_PRESENT(params) ((params)->chanbindingtype != NULL && (params)->chanbindinglen)
+ int chanbindinglen;
int spare_int3;
/* flags field as passed to sasl_client_new */
#define SASL_FEAT_GSS_FRAMING 0x0040
/* Underlying mechanism supports channel binding */
-#define SASL_FEAT_CHANNEL_BINDINGS 0x0080
+#define SASL_FEAT_CHANNEL_BINDING 0x0080
/* client plug-in features */
#define SASL_FEAT_NEEDSERVERFQDN 0x0001
/* for additions which don't require a version upgrade; set to 0 */
void *gss_creds;
- void *chanbindingstype;
- void *chanbindingsdata;
+ void *chanbindingtype;
+ void *chanbindingdata;
void *spare_ptr4;
int (*spare_fptr1)();
int (*spare_fptr2)();
- int chanbindingscrit;
- int chanbindingslen;
+ int chanbindingcrit;
+ int chanbindinglen;
int spare_int3;
/* flags field as passed to sasl_server_new */
#include <sasl.h>
#include <prop.h>
#include <ctype.h>
+#include <stdio.h>
#include "saslint.h"
struct proppool
return 1; /* we have all the prompts */
}
-static inline int sasl_is_plus_mech(const char *mech)
-{
- size_t len = strlen(mech);
- const char *p;
-
- if (len < 5)
- return 0;
-
- p = &mech[len - 5];
-
- return (strcmp(p, "-PLUS") == 0);
-}
-
/* select a mechanism for a connection
* mechlist -- mechanisms server has available (punctuation ignored)
* secret -- optional secret from previous session
minssf = conn->props.min_ssf - conn->external.ssf;
}
+ c_conn->cparams->chanbindingflag = SASL_CB_FLAG_NONE;
+
/* parse mechlist */
list_len = strlen(mechlist);
/* foreach in client list */
for (m = cmechlist->mech_list; m != NULL; m = m->next) {
- int myflags;
-
- /* Is this the mechanism the server is suggesting? */
- if (strcasecmp(m->m.plug->mech_name, name))
- continue; /* no */
+ int myflags, plus;
+
+ if (!_sasl_is_equal_mech(name, m->m.plug->mech_name, &plus))
+ continue;
/* Do we have the prompts for it? */
if (!have_prompts(conn, m->m.plug))
break;
}
- /* If client requires channel binding, prefer -PLUS mech */
- if (c_conn->cparams->chanbindingslen != 0) {
- if (sasl_is_plus_mech(name))
- c_conn->cparams->chanbindingsflag = SASL_CB_FLAG_USED;
- else
- c_conn->cparams->chanbindingsflag = SASL_CB_FLAG_WANT;
- } else {
- c_conn->cparams->chanbindingsflag = SASL_CB_FLAG_NONE;
- }
-
#ifdef PREFER_MECH
if (strcasecmp(m->m.plug->mech_name, PREFER_MECH) &&
bestm && m->m.plug->max_ssf <= bestssf) {
break;
}
+ if (SASL_CB_PRESENT(c_conn->cparams)) {
+ if (plus)
+ c_conn->cparams->chanbindingflag = SASL_CB_FLAG_USED;
+ else
+ c_conn->cparams->chanbindingflag = SASL_CB_FLAG_WANT;
+ }
+
if (mech) {
*mech = m->m.plug->mech_name;
}
printf ("%cNEED_SERVER_FQDN", delimiter);
delimiter = '|';
}
+
+ if (m->plug->features & SASL_FEAT_GSS_FRAMING) {
+ printf ("%cGSS_FRAMING", delimiter);
+ delimiter = '|';
+ }
+
+ if (m->plug->features & SASL_FEAT_CHANNEL_BINDING) {
+ printf ("%cCHANNEL_BINDING", delimiter);
+ delimiter = '|';
+ }
}
/* Delay loading is not supported for the client side plugins:
else
((sasl_client_conn_t *)conn)->cparams->gss_creds = (void *)value;
break;
- case SASL_CHANNEL_BINDINGS: {
- struct sasl_channel_bindings *cb = (struct sasl_channel_bindings *)value;
+ case SASL_CHANNEL_BINDING: {
+ struct sasl_channel_binding *cb = (struct sasl_channel_binding *)value;
if (conn->type == SASL_CONN_SERVER) {
- int cb_flag;
-
- ((sasl_server_conn_t *)conn)->sparams->chanbindingstype = cb->type;
- ((sasl_server_conn_t *)conn)->sparams->chanbindingscrit = cb->critical;
- ((sasl_server_conn_t *)conn)->sparams->chanbindingsdata = cb->data;
- ((sasl_server_conn_t *)conn)->sparams->chanbindingslen = cb->len;
+ ((sasl_server_conn_t *)conn)->sparams->chanbindingtype = cb->type;
+ ((sasl_server_conn_t *)conn)->sparams->chanbindingcrit = cb->critical;
+ ((sasl_server_conn_t *)conn)->sparams->chanbindingdata = cb->data;
+ ((sasl_server_conn_t *)conn)->sparams->chanbindinglen = cb->len;
} else {
- ((sasl_client_conn_t *)conn)->cparams->chanbindingstype = cb->type;
- ((sasl_client_conn_t *)conn)->cparams->chanbindingsdata = cb->data;
- ((sasl_client_conn_t *)conn)->cparams->chanbindingslen = cb->len;
+ ((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;
}
break;
}
PARAMERROR(conn);
}
+int _sasl_is_equal_mech(const char *req_mech,
+ const char *plug_mech,
+ int *plus)
+{
+ size_t len = strlen(req_mech);
+ size_t n;
+
+ if (len > 5 &&
+ strcasecmp(&req_mech[len - 5], "-PLUS") == 0) {
+ n = len - 5;
+ *plus = 1;
+ } else {
+ n = len;
+ *plus = 0;
+ }
+
+ return (strncasecmp(req_mech, plug_mech, n) == 0);
+}
#ifndef WIN32
static char *
extern sasl_allocation_utils_t _sasl_allocation_utils;
extern sasl_mutex_utils_t _sasl_mutex_utils;
+extern int _sasl_is_equal_mech(const char *req_mech,
+ const char *plug_mech,
+ int *plus);
+
/*
* checkpw.c
*/
int result;
context_list_t *cur, **prev;
mechanism_t *m;
+ int plus = 0;
if (_sasl_server_active==0) return SASL_NOTINIT;
if(serverout) *serverout = NULL;
if(serveroutlen) *serveroutlen = 0;
- while (m!=NULL)
- {
- if ( strcasecmp(mech, m->m.plug->mech_name)==0)
- {
+ while (m != NULL) {
+ if (_sasl_is_equal_mech(mech, m->m.plug->mech_name, &plus))
break;
- }
- m=m->next;
+
+ m = m->next;
}
if (m==NULL) {
size_t resultlen;
int flag;
const char *mysep;
+ sasl_server_conn_t *s_conn = (sasl_server_conn_t *) conn; /* cast */
/* if there hasn't been a sasl_sever_init() fail */
if (_sasl_server_active==0) return SASL_NOTINIT;
INTERROR(conn, SASL_NOMECH);
resultlen = (prefix ? strlen(prefix) : 0)
- + (strlen(mysep) * (mechlist->mech_length - 1))
- + mech_names_len()
+ + (strlen(mysep) * (mechlist->mech_length - 1) * 2)
+ + (mech_names_len() * 2) /* including -PLUS variant */
+ + (mechlist->mech_length * (sizeof("-PLUS") - 1))
+ (suffix ? strlen(suffix) : 0)
+ 1;
ret = _buf_alloc(&conn->mechlist_buf,
/* now print the mechanism name */
strcat(conn->mechlist_buf, listptr->m.plug->mech_name);
+
+ /* advertise -PLUS variant if mechanism and application support CB */
+ if ((listptr->m.plug->features & SASL_FEAT_CHANNEL_BINDING) &&
+ SASL_CB_PRESENT(s_conn->sparams)) {
+ if (pcount != NULL)
+ (*pcount)++;
+ strcat(conn->mechlist_buf, mysep);
+ strcat(conn->mechlist_buf, listptr->m.plug->mech_name);
+ strcat(conn->mechlist_buf, "-PLUS");
+ }
}
listptr = listptr->next;
printf ("%cNEED_GETSECRET", delimiter);
delimiter = '|';
}
+
+ if (m->plug->features & SASL_FEAT_GSS_FRAMING) {
+ printf ("%cGSS_FRAMING", delimiter);
+ delimiter = '|';
+ }
+
+ if (m->plug->features & SASL_FEAT_CHANNEL_BINDING) {
+ printf ("%cCHANNEL_BINDING", delimiter);
+ delimiter = '|';
+ }
}
if (m->f) {
void usage(void)
{
- fprintf(stderr, "usage: client [-p port] [-s service] [-m mech] host\n");
+ fprintf(stderr, "usage: client [-c] [-p port] [-s service] [-m mech] host\n");
exit(EX_USAGE);
}
int salen;
int niflags, error;
struct sockaddr_storage local_ip, remote_ip;
- sasl_channel_bindings cb;
+ int cb_flag = 0;
+ sasl_channel_binding cb;
- while ((c = getopt(argc, argv, "p:s:m:")) != EOF) {
+ while ((c = getopt(argc, argv, "cp:s:m:")) != EOF) {
switch(c) {
+ case 'c':
+ cb_flag = 1;
+ break;
+
case 'p':
port = optarg;
break;
r = sasl_client_new(service, host, localaddr, remoteaddr, NULL, 0, &conn);
if (r != SASL_OK) saslfail(r, "allocating connection state");
- cb.type = "sasl-sample";
- cb.critical = 0;
- cb.data = "this is a test of channel bindings";
- cb.len = strlen(cb.data);
+ if (cb_flag) {
+ cb.type = "sasl-sample";
+ cb.data = "this is a test of channel binding";
+ cb.len = strlen(cb.data);
- sasl_setprop(conn, SASL_CHANNEL_BINDINGS, &cb);
+ sasl_setprop(conn, SASL_CHANNEL_BINDING, &cb);
+ }
/* set external properties here
sasl_setprop(conn, SASL_SSF_EXTERNAL, &extprops); */
int nfds, fd = -1;
FILE *in, *out;
fd_set readfds;
- sasl_channel_bindings cb;
+ sasl_channel_binding cb;
FD_ZERO(&readfds);
for (i = 1; i <= l[0]; i++)
cb.type = "sasl-sample";
cb.critical = 0;
- cb.data = "this is a test of channel bindings";
+ cb.data = "this is a test of channel binding";
cb.len = strlen(cb.data);
- sasl_setprop(conn, SASL_CHANNEL_BINDINGS, &cb);
+ sasl_setprop(conn, SASL_CHANNEL_BINDING, &cb);
/* set external properties here
sasl_setprop(conn, SASL_SSF_EXTERNAL, &extprops); */