From: Luke Howard Date: Mon, 27 Sep 2010 00:26:10 +0000 (+0200) Subject: complete moving logic to server X-Git-Url: http://www.project-moonshot.org/gitweb/?p=cyrus-sasl.git;a=commitdiff_plain;h=83ab9112023c5e09098e7eb7687e545d56c43b08 complete moving logic to server --- diff --git a/lib/client.c b/lib/client.c index 4c35519..2f627c1 100644 --- a/lib/client.c +++ b/lib/client.c @@ -390,6 +390,72 @@ static int have_prompts(sasl_conn_t *conn, return 1; /* we have all the prompts */ } +static int +_mech_plus_p(const char *mech, size_t len) +{ + return (len > 5 && strncasecmp(&mech[len - 5], "-PLUS", 5) == 0); +} + +/* + * Order PLUS mechanisms first. Returns NUL separated list of + * *count items. + */ +static int +_sasl_client_order_mechs(const sasl_utils_t *utils, + const char *mechs, + int has_cb_data, + char **ordered_mechs, + size_t *count, + int *server_can_cb) +{ + char *list, *listp; + size_t i; + const char *p, *start = NULL; + + *count = 0; + *server_can_cb = 0; + + listp = list = utils->malloc(strlen(mechs) + 1); + if (list == NULL) + return SASL_NOMEM; + + if (has_cb_data) { + for (start = p = mechs, i = 0; *p != '\0'; p++) { + if (isspace(*p) || p[1] == '\0') { + size_t len = p - start + 1; + + if (_mech_plus_p(start, len)) { + memcpy(listp, start, len); + listp[len] = '\0'; + listp += len + 1; + (*count)++; + *server_can_cb = 1; + } + start = p + 1; + } + } + } + + for (start = p = mechs, i = 0; *p != '\0'; p++) { + if (isspace(*p) || p[1] == '\0') { + size_t len = p - start + 1; + + if (!_mech_plus_p(start, len)) { + memcpy(listp, start, len); + listp[len] = '\0'; + listp += len + 1; + (*count)++; + } + start = p + 1; + } + } + + *listp = '\0'; + *ordered_mechs = list; + + return SASL_OK; +} + /* select a mechanism for a connection * mechlist -- mechanisms server has available (punctuation ignored) * secret -- optional secret from previous session @@ -421,12 +487,11 @@ int sasl_client_start(sasl_conn_t *conn, const char **mech) { sasl_client_conn_t *c_conn= (sasl_client_conn_t *) conn; - char name[SASL_MECHNAMEMAX + 1]; + char *ordered_mechs = NULL, *name; cmechanism_t *m=NULL,*bestm=NULL; - size_t pos=0,place; - size_t list_len; + size_t i, list_len; sasl_ssf_t bestssf = 0, minssf = 0; - int result; + int result, server_can_cb = 0; if(_sasl_client_active==0) return SASL_NOTINIT; @@ -451,33 +516,22 @@ int sasl_client_start(sasl_conn_t *conn, minssf = conn->props.min_ssf - conn->external.ssf; } - c_conn->cparams->chanbindingflag = SASL_CB_FLAG_NONE; - - /* parse mechlist */ - list_len = strlen(mechlist); - - while (poscparams->utils, + mechlist, + SASL_CB_PRESENT(c_conn->cparams), + &ordered_mechs, + &list_len, + &server_can_cb); + if (result != 0) + return result; + + /* If we have CB and the server supports it, we should use it */ + if (SASL_CB_PRESENT(c_conn->cparams) && server_can_cb) + c_conn->cparams->chanbindingflag = SASL_CB_FLAG_WANT; + else + c_conn->cparams->chanbindingflag = SASL_CB_FLAG_NONE; + for (i = 0, name = ordered_mechs; i < list_len; i++) { /* foreach in client list */ for (m = cmechlist->mech_list; m != NULL; m = m->next) { int myflags, plus; @@ -556,12 +610,9 @@ int sasl_client_start(sasl_conn_t *conn, 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; - } + /* Prefer server advertised CB mechanisms */ + if (SASL_CB_PRESENT(c_conn->cparams) && plus) + c_conn->cparams->chanbindingflag = SASL_CB_FLAG_USED; if (mech) { *mech = m->m.plug->mech_name; @@ -570,6 +621,7 @@ int sasl_client_start(sasl_conn_t *conn, bestm = m; break; } + name += strlen(name) + 1; } if (bestm == NULL) { @@ -616,6 +668,8 @@ int sasl_client_start(sasl_conn_t *conn, result = SASL_CONTINUE; done: + if (ordered_mechs != NULL) + c_conn->cparams->utils->free(ordered_mechs); RETURN(conn, result); } diff --git a/lib/common.c b/lib/common.c index 9a8e8ce..620395a 100644 --- a/lib/common.c +++ b/lib/common.c @@ -1213,9 +1213,9 @@ int sasl_setprop(sasl_conn_t *conn, int propnum, const void *value) if (conn->type == SASL_CONN_SERVER) { ((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; + ((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; diff --git a/lib/server.c b/lib/server.c index 4cdf456..f4a50bd 100644 --- a/lib/server.c +++ b/lib/server.c @@ -1462,7 +1462,7 @@ int sasl_server_step(sasl_conn_t *conn, } else if (conn->oparams.chanbindingflag == SASL_CB_FLAG_WANT && SASL_CB_PRESENT(s_conn->sparams)) { sasl_seterror(conn, 0, - "client incorrectly determined server had no channel binding"); + "client incorrectly assumed server had no channel binding"); ret = SASL_BADAUTH; } else if (conn->oparams.user == NULL || conn->oparams.authid == NULL) { sasl_seterror(conn, 0, @@ -1567,25 +1567,34 @@ int _sasl_server_listmech(sasl_conn_t *conn, for (lup = 0; lup < mechlist->mech_length; lup++) { /* currently, we don't use the "user" parameter for anything */ if (mech_permitted(conn, listptr) == SASL_OK) { - if (pcount != NULL) + /* + * If the server would never succeed in the authentication of + * he non-PLUS-variant due to policy reasons, it MUST advertise + * only the PLUS-variant. + */ + if (!s_conn->sparams->chanbindingcrit) { + if (pcount != NULL) (*pcount)++; - - /* print separator */ - if (flag) { - strcat(conn->mechlist_buf, mysep); - } else { - flag = 1; - } - - /* now print the mechanism name */ - strcat(conn->mechlist_buf, listptr->m.plug->mech_name); - - /* advertise -PLUS variant if mechanism and application support CB */ + if (flag) + strcat(conn->mechlist_buf, mysep); + else + flag = 1; + strcat(conn->mechlist_buf, listptr->m.plug->mech_name); + } + /* + * If the server cannot support channel binding, it SHOULD + * advertise only the non-PLUS-variant. Here, supporting channel + * binding means the underlying SASL mechanism supports it and + * the application has set some channel binding data. + */ if ((listptr->m.plug->features & SASL_FEAT_CHANNEL_BINDING) && SASL_CB_PRESENT(s_conn->sparams)) { if (pcount != NULL) (*pcount)++; - strcat(conn->mechlist_buf, mysep); + if (flag) + strcat(conn->mechlist_buf, mysep); + else + flag = 1; strcat(conn->mechlist_buf, listptr->m.plug->mech_name); strcat(conn->mechlist_buf, "-PLUS"); } diff --git a/plugins/gs2.c b/plugins/gs2.c index fefa9af..85f2c30 100644 --- a/plugins/gs2.c +++ b/plugins/gs2.c @@ -62,9 +62,9 @@ #include "gs2_token.h" #define GS2_CB_FLAG_MASK 0x0F -#define GS2_CB_FLAG_P SASL_CB_FLAG_USED -#define GS2_CB_FLAG_N SASL_CB_FLAG_NONE -#define GS2_CB_FLAG_Y SASL_CB_FLAG_WANT +#define GS2_CB_FLAG_P 0x01 +#define GS2_CB_FLAG_N 0x02 +#define GS2_CB_FLAG_Y 0x03 #define GS2_NONSTD_FLAG 0x10 typedef struct context { @@ -487,7 +487,7 @@ gs2_server_mech_step(void *conn_context, oparams->chanbindingflag = SASL_CB_FLAG_USED; break; case GS2_CB_FLAG_Y: - oparams->chanbindingflag == SASL_CB_FLAG_WANT; + oparams->chanbindingflag = SASL_CB_FLAG_WANT; break; } diff --git a/sample/server.c b/sample/server.c index 2b4f72d..fec6355 100644 --- a/sample/server.c +++ b/sample/server.c @@ -322,9 +322,14 @@ int main(int argc, char *argv[]) int *l, maxfd=0; int r, i; sasl_conn_t *conn; + int cb_flag = 0; - 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; @@ -441,7 +446,7 @@ int main(int argc, char *argv[]) if (r != SASL_OK) saslfail(r, "allocating connection state"); cb.type = "sasl-sample"; - cb.critical = 0; + cb.critical = cb_flag; cb.data = "this is a test of channel binding"; cb.len = strlen(cb.data);