sasl_conn_t *php_mongo_saslstart(mongo_con_manager *manager, mongo_connection *con, mongo_server_options *options, mongo_server_def *server_def, sasl_conn_t *conn, char **out_payload, int *out_payload_len, int32_t *conversation_id, char **error_message) { const char *raw_payload; char encoded_payload[4096]; unsigned int raw_payload_len, encoded_payload_len; int result; char *mechanism_list = "GSSAPI"; const char *mechanism_selected; sasl_interact_t *client_interact=NULL; result = sasl_client_start(conn, mechanism_list, &client_interact, &raw_payload, &raw_payload_len, &mechanism_selected); if (is_sasl_failure(conn, result, error_message)) { return NULL; } if (result != SASL_CONTINUE) { *error_message = strdup("Could not negotiate SASL mechanism"); return NULL; } mechanism_selected = "GSSAPI"; result = sasl_encode64(raw_payload, raw_payload_len, encoded_payload, sizeof(encoded_payload), &encoded_payload_len); if (is_sasl_failure(conn, result, error_message)) { return NULL; } if (!mongo_connection_authenticate_saslstart(manager, con, options, server_def, (char *)mechanism_selected, encoded_payload, encoded_payload_len + 1, out_payload, out_payload_len, conversation_id, error_message)) { return NULL; } return conn; }
static bool _mongoc_sasl_start (mongoc_sasl_t *sasl, uint8_t *outbuf, uint32_t outbufmax, uint32_t *outbuflen, bson_error_t *error) { const char *service_name = "mongodb"; const char *service_host = ""; const char *mechanism = NULL; const char *raw = NULL; unsigned raw_len = 0; int status; BSON_ASSERT (sasl); BSON_ASSERT (outbuf); BSON_ASSERT (outbufmax); BSON_ASSERT (outbuflen); if (sasl->service_name) { service_name = sasl->service_name; } if (sasl->service_host) { service_host = sasl->service_host; } status = sasl_client_new (service_name, service_host, NULL, NULL, sasl->callbacks, 0, &sasl->conn); if (_mongoc_sasl_is_failure (status, error)) { return false; } status = sasl_client_start (sasl->conn, sasl->mechanism, &sasl->interact, &raw, &raw_len, &mechanism); if (_mongoc_sasl_is_failure (status, error)) { return false; } if ((0 != strcasecmp (mechanism, "GSSAPI")) && (0 != strcasecmp (mechanism, "PLAIN"))) { bson_set_error (error, MONGOC_ERROR_SASL, SASL_NOMECH, "SASL Failure: invalid mechanism \"%s\"", mechanism); return false; } status = sasl_encode64 (raw, raw_len, (char *)outbuf, outbufmax, outbuflen); if (_mongoc_sasl_is_failure (status, error)) { return false; } return true; }
static int cyrussasl_sasl_client_start(lua_State *l) { int numargs = lua_gettop(l); int err; struct _sasl_ctx *ctx = NULL; const char *mechlist = NULL; const char *mechout = NULL; const char *data = NULL; size_t len; unsigned outlen; if (numargs != 2) { lua_pushstring(l, "usage: " "(err, data, mech) = cyrussasl.client_start(conn, mechlist)"); lua_error(l); return 0; } /* Pull arguments off of the stack... */ ctx = get_context(l, 1); /* Allow the mechlist to be NULL. */ if ( lua_type(l, 2) == LUA_TNIL ) { mechlist = NULL; } else { mechlist = tolstring(l, 2, &len); } err = sasl_client_start( ctx->conn, /* saved sasl connection */ mechlist, /* mech, which the client chose */ NULL, /* prompt_need */ &data, /* data return */ &outlen, /* data length return */ &mechout /* chosen mechanism return */ ); /* Form the reply and push onto the stack */ lua_pushinteger(l, err); /* SASL_CONTINUE, SASL_OK, et al */ if (data) { lua_pushlstring(l, data, outlen); /* server's reply to the client */ } else { lua_pushnil(l); } lua_pushstring(l, mechout); /* chosen mech */ return 3; /* returning 3 items on Lua stack */ }
int virNetSASLSessionClientStart(virNetSASLSessionPtr sasl, const char *mechlist, sasl_interact_t **prompt_need, const char **clientout, size_t *clientoutlen, const char **mech) { unsigned outlen = 0; int err; int ret = -1; VIR_DEBUG("sasl=%p mechlist=%s prompt_need=%p clientout=%p clientoutlen=%p mech=%p", sasl, mechlist, prompt_need, clientout, clientoutlen, mech); virObjectLock(sasl); err = sasl_client_start(sasl->conn, mechlist, prompt_need, clientout, &outlen, mech); *clientoutlen = outlen; switch (err) { case SASL_OK: if (virNetSASLSessionUpdateBufSize(sasl) < 0) goto cleanup; ret = VIR_NET_SASL_COMPLETE; break; case SASL_CONTINUE: ret = VIR_NET_SASL_CONTINUE; break; case SASL_INTERACT: ret = VIR_NET_SASL_INTERACT; break; default: virReportError(VIR_ERR_AUTH_FAILED, _("Failed to start SASL negotiation: %d (%s)"), err, sasl_errdetail(sasl->conn)); break; } cleanup: virObjectUnlock(sasl); return ret; }
POP3_SASL_STATE_E Pop3SaslWrapper::SaslStep(string& auth_str) { int sasl_result; const char* out = NULL; unsigned int outlen = 0; if(init == false) { string mechlist = sasl_data.mech; const char *mechusing; do { sasl_result = sasl_client_start(conn, mechlist.c_str(), &client_interact, &out, &outlen, &mechusing); }while(sasl_result == SASL_INTERACT); if(sasl_result != SASL_CONTINUE) { //Log Error POP3_SASL_DEBUG("SASL-Error 4 - \n"); return POP3_SASL_ERROR; } init = true; auth_str.assign(out, outlen); return POP3_SASL_OK; } do { sasl_result = sasl_client_step(conn, auth_str.c_str(), auth_str.length(), &client_interact, &out, &outlen); POP3_DEBUG_INFO1("sasl_result : %d\n", sasl_result); }while(sasl_result == SASL_INTERACT); if(sasl_result != SASL_OK && sasl_result != SASL_CONTINUE) { //Log Error POP3_SASL_DEBUG("SASL-Error 5 -- \n"); return POP3_SASL_ERROR; } auth_str.assign(out, outlen); return POP3_SASL_OK; }
int main(void) { char *method="xoauth"; sasl_conn_t* saslconn; sasl_interact_t *interaction; char* pc; unsigned olen; char* mech; int rc; rc = my_sasl_start(); if (rc != SASL_OK) { fprintf(stderr, "SASL: INIT FAIL\n"); goto end; } printf("here 0\n"); rc = sasl_client_new("IMAP", "imap.gmail.com", "1.1.1.1;993", "2.2.2.2;12345", NULL, SASL_SUCCESS_DATA, &saslconn); if (rc != SASL_OK) { fprintf(stderr, "SASL: NEW FAIL\n"); goto end; } printf("here1\n"); rc = sasl_client_start (saslconn, method, &interaction, &pc, &olen, &mech); if (rc != SASL_OK) { fprintf(stderr, "SASL: START FAIL\n"); goto end; } end: printf("end\n"); }
/* Evaluates the challenge data and generates a response. */ uint8_t* TSaslClient::evaluateChallengeOrResponse( const uint8_t* challenge, const uint32_t len, uint32_t *resLen) { sasl_interact_t* client_interact=NULL; uint8_t* out=NULL; uint32_t outlen=0; uint32_t result; char* mechUsing; if (!clientStarted) { result=sasl_client_start(conn, mechList.c_str(), &client_interact, /* filled in if an interaction is needed */ (const char**)&out, /* filled in on success */ &outlen, /* filled in on success */ (const char**)&mechUsing); clientStarted = true; chosenMech = mechUsing; } else { if (len > 0) { result=sasl_client_step(conn, /* our context */ (const char*)challenge, /* the data from the server */ len, /* its length */ &client_interact, /* this should be unallocated and NULL */ (const char**)&out, /* filled in on success */ &outlen); /* filled in on success */ } else { result = SASL_CONTINUE; } } if (result == SASL_OK) { authComplete = true; } else if (result != SASL_CONTINUE) { throw SaslClientImplException(sasl_errdetail(conn)); } *resLen = outlen; return (uint8_t*)out; }
static void sasl_list_mech_response_handler(libcouchbase_server_t *server, protocol_binary_response_header *res) { const char *data; const char *chosenmech; unsigned int len; protocol_binary_request_no_extras req; size_t keylen; size_t bodysize; assert(ntohs(res->response.status) == PROTOCOL_BINARY_RESPONSE_SUCCESS); if (sasl_client_start(server->sasl_conn, (const char *)(res + 1), NULL, &data, &len, &chosenmech) != SASL_OK) { // @fixme! abort(); } keylen = strlen(chosenmech); bodysize = keylen + len; memset(&req, 0, sizeof(req)); req.message.header.request.magic = PROTOCOL_BINARY_REQ; req.message.header.request.opcode = PROTOCOL_BINARY_CMD_SASL_AUTH; req.message.header.request.keylen = ntohs((uint16_t)keylen); req.message.header.request.datatype = PROTOCOL_BINARY_RAW_BYTES; req.message.header.request.bodylen = ntohl((uint32_t)(bodysize)); libcouchbase_server_buffer_start_packet(server, &server->output, req.bytes, sizeof(req.bytes)); libcouchbase_server_buffer_write_packet(server, &server->output, chosenmech, keylen); libcouchbase_server_buffer_write_packet(server, &server->output, data, len); libcouchbase_server_buffer_end_packet(server, &server->output); // send the data and add it to libevent.. libcouchbase_server_event_handler(0, EV_WRITE, server); }
static int pni_wrap_client_start(pni_sasl_t *sasl, const char *mechs, const char **mechusing) { int result; sasl_interact_t *client_interact=NULL; const char *out; unsigned outlen; sasl_conn_t *cyrus_conn = (sasl_conn_t*)sasl->impl_context; do { 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->bytes_out.start = out; sasl->bytes_out.size = outlen; return result; }
int mailpop3_auth(mailpop3 * f, const char * auth_type, const char * server_fqdn, const char * local_ip_port, const char * remote_ip_port, const char * login, const char * auth_name, const char * password, const char * realm) { #ifdef USE_SASL int r; char command[POP3_STRING_SIZE]; sasl_callback_t sasl_callback[5]; const char * sasl_out; unsigned sasl_out_len; const char * mechusing; sasl_secret_t * secret; int res; size_t len; char * encoded; unsigned int encoded_len; unsigned int max_encoded; sasl_callback[0].id = SASL_CB_GETREALM; sasl_callback[0].proc = sasl_getrealm; sasl_callback[0].context = f; sasl_callback[1].id = SASL_CB_USER; sasl_callback[1].proc = sasl_getsimple; sasl_callback[1].context = f; sasl_callback[2].id = SASL_CB_AUTHNAME; sasl_callback[2].proc = sasl_getsimple; sasl_callback[2].context = f; sasl_callback[3].id = SASL_CB_PASS; sasl_callback[3].proc = sasl_getsecret; sasl_callback[3].context = f; sasl_callback[4].id = SASL_CB_LIST_END; sasl_callback[4].proc = NULL; sasl_callback[4].context = NULL; len = strlen(password); secret = malloc(sizeof(* secret) + len); if (secret == NULL) { res = MAILPOP3_ERROR_MEMORY; goto err; } secret->len = len; memcpy(secret->data, password, len + 1); f->pop3_sasl.sasl_server_fqdn = server_fqdn; f->pop3_sasl.sasl_login = login; f->pop3_sasl.sasl_auth_name = auth_name; f->pop3_sasl.sasl_password = password; f->pop3_sasl.sasl_realm = realm; f->pop3_sasl.sasl_secret = secret; /* init SASL */ if (f->pop3_sasl.sasl_conn != NULL) { sasl_dispose((sasl_conn_t **) &f->pop3_sasl.sasl_conn); f->pop3_sasl.sasl_conn = NULL; } else { mailsasl_ref(); } r = sasl_client_new("pop", server_fqdn, local_ip_port, remote_ip_port, sasl_callback, 0, (sasl_conn_t **) &f->pop3_sasl.sasl_conn); if (r != SASL_OK) { res = MAILPOP3_ERROR_BAD_USER; goto free_secret; } r = sasl_client_start(f->pop3_sasl.sasl_conn, auth_type, NULL, &sasl_out, &sasl_out_len, &mechusing); if ((r != SASL_CONTINUE) && (r != SASL_OK)) { res = MAILPOP3_ERROR_BAD_USER; goto free_sasl_conn; } snprintf(command, POP3_STRING_SIZE, "AUTH %s\r\n", auth_type); r = send_command(f, command); if (r == -1) { res = MAILPOP3_ERROR_STREAM; goto free_sasl_conn; } while (1) { char * response; response = read_line(f); r = parse_auth(f, response); switch (r) { case RESPONSE_OK: f->pop3_state = POP3_STATE_TRANSACTION; res = MAILPOP3_NO_ERROR; goto free_sasl_conn; case RESPONSE_ERR: res = MAILPOP3_ERROR_BAD_USER; goto free_sasl_conn; case RESPONSE_AUTH_CONT: { size_t response_len; char * decoded; unsigned int decoded_len; unsigned int max_decoded; int got_response; got_response = 1; if (* f->pop3_response == '\0') got_response = 0; if (got_response) { char * p; p = strchr(f->pop3_response, '\r'); if (p != NULL) { * p = '\0'; } p = strchr(f->pop3_response, '\n'); if (p != NULL) { * p = '\0'; } response_len = strlen(f->pop3_response); max_decoded = response_len * 3 / 4; decoded = malloc(max_decoded + 1); if (decoded == NULL) { res = MAILPOP3_ERROR_MEMORY; goto free_sasl_conn; } r = sasl_decode64(f->pop3_response, response_len, decoded, max_decoded + 1, &decoded_len); if (r != SASL_OK) { free(decoded); res = MAILPOP3_ERROR_MEMORY; goto free_sasl_conn; } r = sasl_client_step(f->pop3_sasl.sasl_conn, decoded, decoded_len, NULL, &sasl_out, &sasl_out_len); free(decoded); if ((r != SASL_CONTINUE) && (r != SASL_OK)) { res = MAILPOP3_ERROR_BAD_USER; goto free_sasl_conn; } } max_encoded = ((sasl_out_len + 2) / 3) * 4; encoded = malloc(max_encoded + 1); if (encoded == NULL) { res = MAILPOP3_ERROR_MEMORY; goto free_sasl_conn; } r = sasl_encode64(sasl_out, sasl_out_len, encoded, max_encoded + 1, &encoded_len); if (r != SASL_OK) { free(encoded); res = MAILPOP3_ERROR_MEMORY; goto free_sasl_conn; } snprintf(command, POP3_STRING_SIZE, "%s\r\n", encoded); r = send_command(f, command); free(encoded); if (r == -1) { res = MAILPOP3_ERROR_STREAM; goto free_sasl_conn; } } break; } } f->pop3_state = POP3_STATE_TRANSACTION; res = MAILPOP3_NO_ERROR; free_sasl_conn: sasl_dispose((sasl_conn_t **) &f->pop3_sasl.sasl_conn); f->pop3_sasl.sasl_conn = NULL; mailsasl_unref(); free_secret: free(f->pop3_sasl.sasl_secret); f->pop3_sasl.sasl_secret = NULL; err: return res; #else return MAILPOP3_ERROR_BAD_USER; #endif }
/* imap_auth_sasl: Default authenticator if available. */ imap_auth_res_t imap_auth_sasl (IMAP_DATA* idata, const char* method) { sasl_conn_t* saslconn; sasl_interact_t* interaction = NULL; int rc, irc; char buf[HUGE_STRING]; const char* mech; const char *pc = NULL; unsigned int len, olen; unsigned char client_start; if (mutt_sasl_client_new (idata->conn, &saslconn) < 0) { dprint (1, (debugfile, "imap_auth_sasl: Error allocating SASL connection.\n")); return IMAP_AUTH_FAILURE; } rc = SASL_FAIL; /* If the user hasn't specified a method, use any available */ if (!method) { method = idata->capstr; /* hack for SASL ANONYMOUS support: * 1. Fetch username. If it's "" or "anonymous" then * 2. attempt sasl_client_start with only "AUTH=ANONYMOUS" capability * 3. if sasl_client_start fails, fall through... */ if (mutt_account_getuser (&idata->conn->account)) return IMAP_AUTH_FAILURE; if (mutt_bit_isset (idata->capabilities, AUTH_ANON) && (!idata->conn->account.user[0] || !ascii_strncmp (idata->conn->account.user, "anonymous", 9))) rc = sasl_client_start (saslconn, "AUTH=ANONYMOUS", NULL, &pc, &olen, &mech); } else if (!ascii_strcasecmp ("login", method) && !strstr (NONULL (idata->capstr), "AUTH=LOGIN")) /* do not use SASL login for regular IMAP login (#3556) */ return IMAP_AUTH_UNAVAIL; if (rc != SASL_OK && rc != SASL_CONTINUE) do { rc = sasl_client_start (saslconn, method, &interaction, &pc, &olen, &mech); if (rc == SASL_INTERACT) mutt_sasl_interact (interaction); } while (rc == SASL_INTERACT); client_start = (olen > 0); if (rc != SASL_OK && rc != SASL_CONTINUE) { if (method) dprint (2, (debugfile, "imap_auth_sasl: %s unavailable\n", method)); else dprint (1, (debugfile, "imap_auth_sasl: Failure starting authentication exchange. No shared mechanisms?\n")); /* SASL doesn't support LOGIN, so fall back */ return IMAP_AUTH_UNAVAIL; } mutt_message (_("Authenticating (%s)..."), mech); snprintf (buf, sizeof (buf), "AUTHENTICATE %s", mech); if (mutt_bit_isset (idata->capabilities, SASL_IR) && client_start) { len = mutt_strlen (buf); buf[len++] = ' '; if (sasl_encode64 (pc, olen, buf + len, sizeof (buf) - len, &olen) != SASL_OK) { dprint (1, (debugfile, "imap_auth_sasl: error base64-encoding client response.\n")); goto bail; } client_start = olen = 0; } imap_cmd_start (idata, buf); irc = IMAP_CMD_CONTINUE; /* looping protocol */ while (rc == SASL_CONTINUE || olen > 0) { do irc = imap_cmd_step (idata); while (irc == IMAP_CMD_CONTINUE); if (irc == IMAP_CMD_BAD || irc == IMAP_CMD_NO) goto bail; if (irc == IMAP_CMD_RESPOND) { /* Exchange incorrectly returns +\r\n instead of + \r\n */ if (idata->buf[1] == '\0') { buf[0] = '\0'; len = 0; } else if (sasl_decode64 (idata->buf+2, strlen (idata->buf+2), buf, LONG_STRING-1, &len) != SASL_OK) { dprint (1, (debugfile, "imap_auth_sasl: error base64-decoding server response.\n")); goto bail; } } /* client-start is only available with the SASL-IR extension, but * SASL 2.1 seems to want to use it regardless, at least for DIGEST * fast reauth. Override if the server sent an initial continuation */ if (!client_start || buf[0]) { do { rc = sasl_client_step (saslconn, buf, len, &interaction, &pc, &olen); if (rc == SASL_INTERACT) mutt_sasl_interact (interaction); } while (rc == SASL_INTERACT); } else client_start = 0; /* send out response, or line break if none needed */ if (olen) { if (sasl_encode64 (pc, olen, buf, sizeof (buf), &olen) != SASL_OK) { dprint (1, (debugfile, "imap_auth_sasl: error base64-encoding client response.\n")); goto bail; } } if (irc == IMAP_CMD_RESPOND) { strfcpy (buf + olen, "\r\n", sizeof (buf) - olen); mutt_socket_write (idata->conn, buf); } /* If SASL has errored out, send an abort string to the server */ if (rc < 0) { mutt_socket_write (idata->conn, "*\r\n"); dprint (1, (debugfile, "imap_auth_sasl: sasl_client_step error %d\n",rc)); } olen = 0; } while (irc != IMAP_CMD_OK) if ((irc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE) break; if (rc != SASL_OK) goto bail; if (imap_code (idata->buf)) { mutt_sasl_setup_conn (idata->conn, saslconn); return IMAP_AUTH_SUCCESS; } bail: sasl_dispose (&saslconn); if (method) { dprint (2, (debugfile, "imap_auth_sasl: %s failed\n", method)); return IMAP_AUTH_UNAVAIL; } mutt_error _("SASL authentication failed."); mutt_sleep(2); return IMAP_AUTH_FAILURE; }
int auth_sasl(char *mechlist, isieve_t *obj, const char **mechusing, sasl_ssf_t *ssf, char **errstr) { sasl_interact_t *client_interact=NULL; int saslresult=SASL_INTERACT; const char *out; unsigned int outlen; char *in; unsigned int inlen; char inbase64[2048]; unsigned int inbase64len; imt_stat status = STAT_CONT; if(!mechlist || !obj || !mechusing) return -1; /* call sasl client start */ while (saslresult==SASL_INTERACT) { saslresult=sasl_client_start(obj->conn, mechlist, &client_interact, &out, &outlen, mechusing); if (saslresult==SASL_INTERACT) fillin_interactions(client_interact); /* fill in prompts */ } if ((saslresult!=SASL_OK) && (saslresult!=SASL_CONTINUE)) return saslresult; if (out!=NULL) { prot_printf(obj->pout,"AUTHENTICATE \"%s\" ",*mechusing); sasl_encode64(out, outlen, inbase64, sizeof(inbase64), &inbase64len); prot_printf(obj->pout, "{%d+}\r\n",inbase64len); prot_write(obj->pout,inbase64,inbase64len); prot_printf(obj->pout,"\r\n"); } else { prot_printf(obj->pout,"AUTHENTICATE \"%s\"\r\n",*mechusing); } prot_flush(obj->pout); inlen = 0; /* get reply */ status=getauthline(obj,&in,&inlen, errstr); while (status==STAT_CONT) { saslresult=SASL_INTERACT; while (saslresult==SASL_INTERACT) { saslresult=sasl_client_step(obj->conn, in, inlen, &client_interact, &out,&outlen); if (saslresult==SASL_INTERACT) fillin_interactions(client_interact); /* fill in prompts */ } /* check if sasl suceeded */ if (saslresult<SASL_OK) { /* send cancel notice */ prot_printf(obj->pout, "*\r\n"); prot_flush(obj->pout); /* eat the auth line that confirms that we canceled */ if(getauthline(obj,&in,&inlen,errstr) != STAT_NO) { *errstr = xstrdup("protocol error"); } else { *errstr = xstrdup(sasl_errstring(saslresult,NULL,NULL)); } return saslresult; } /* send to server */ sasl_encode64(out, outlen, inbase64, sizeof(inbase64), &inbase64len); prot_printf(obj->pout, "{%d+}\r\n",inbase64len); prot_flush(obj->pout); prot_write(obj->pout,inbase64,inbase64len); prot_flush(obj->pout); prot_printf(obj->pout,"\r\n"); prot_flush(obj->pout); /* get reply */ status=getauthline(obj,&in,&inlen, errstr); } if(status == STAT_OK) { /* do we have a last send? */ if(in) { saslresult=sasl_client_step(obj->conn, in, inlen, &client_interact, &out, &outlen); if(saslresult != SASL_OK) return -1; } if (ssf) { const void *ssfp; saslresult = sasl_getprop(obj->conn, SASL_SSF, &ssfp); if(saslresult != SASL_OK) return -1; *ssf = *((sasl_ssf_t *) ssfp); } /* turn on layer if need be */ prot_setsasl(obj->pin, obj->conn); prot_setsasl(obj->pout, obj->conn); /* There wasn't a last send, or we are already OK */ return 0; } else { /* Error */ return -1; } }
/** * Initialize and start SASL authentication. * * Returns 0 on successful init and -1 on error. * * Locality: broker thread */ int rd_kafka_sasl_client_new (rd_kafka_transport_t *rktrans, char *errstr, int errstr_size) { int r; rd_kafka_broker_t *rkb = rktrans->rktrans_rkb; rd_kafka_t *rk = rkb->rkb_rk; char *hostname, *t; sasl_callback_t callbacks[16] = { // { SASL_CB_GETOPT, (void *)rd_kafka_sasl_cb_getopt, rktrans }, { SASL_CB_LOG, (void *)rd_kafka_sasl_cb_log, rktrans }, { SASL_CB_AUTHNAME, (void *)rd_kafka_sasl_cb_getsimple, rktrans }, { SASL_CB_PASS, (void *)rd_kafka_sasl_cb_getsecret, rktrans }, { SASL_CB_ECHOPROMPT, (void *)rd_kafka_sasl_cb_chalprompt, rktrans }, { SASL_CB_GETREALM, (void *)rd_kafka_sasl_cb_getrealm, rktrans }, { SASL_CB_CANON_USER, (void *)rd_kafka_sasl_cb_canon, rktrans }, { SASL_CB_LIST_END } }; /* SASL_CB_USER is needed for PLAIN but breaks GSSAPI */ if (!strcmp(rk->rk_conf.sasl.service_name, "PLAIN")) { int endidx; /* Find end of callbacks array */ for (endidx = 0 ; callbacks[endidx].id != SASL_CB_LIST_END ; endidx++) ; callbacks[endidx].id = SASL_CB_USER; callbacks[endidx].proc = (void *)rd_kafka_sasl_cb_getsimple; endidx++; callbacks[endidx].id = SASL_CB_LIST_END; } rd_strdupa(&hostname, rktrans->rktrans_rkb->rkb_nodename); if ((t = strchr(hostname, ':'))) *t = '\0'; /* remove ":port" */ rd_rkb_dbg(rkb, SECURITY, "SASL", "Initializing SASL client: service name %s, " "hostname %s, mechanisms %s", rk->rk_conf.sasl.service_name, hostname, rk->rk_conf.sasl.mechanisms); /* Acquire or refresh ticket if kinit is configured */ rd_kafka_sasl_kinit_refresh(rkb); r = sasl_client_new(rk->rk_conf.sasl.service_name, hostname, NULL, NULL, /* no local & remote IP checks */ callbacks, 0, &rktrans->rktrans_sasl.conn); if (r != SASL_OK) { rd_snprintf(errstr, errstr_size, "%s", sasl_errstring(r, NULL, NULL)); return -1; } if (rk->rk_conf.debug & RD_KAFKA_DBG_SECURITY) { const char *avail_mechs; sasl_listmech(rktrans->rktrans_sasl.conn, NULL, NULL, " ", NULL, &avail_mechs, NULL, NULL); rd_rkb_dbg(rkb, SECURITY, "SASL", "My supported SASL mechanisms: %s", avail_mechs); } rd_kafka_transport_poll_set(rktrans, POLLIN); do { const char *out; unsigned int outlen; const char *mech = NULL; r = sasl_client_start(rktrans->rktrans_sasl.conn, rk->rk_conf.sasl.mechanisms, NULL, &out, &outlen, &mech); if (r >= 0) if (rd_kafka_sasl_send(rktrans, out, outlen, errstr, errstr_size)) return -1; } while (r == SASL_INTERACT); if (r == SASL_OK) { /* PLAIN is appearantly done here, but we still need to make sure * the PLAIN frame is sent and we get a response back (but we must * not pass the response to libsasl or it will fail). */ rktrans->rktrans_sasl.complete = 1; return 0; } else if (r != SASL_CONTINUE) { rd_snprintf(errstr, errstr_size, "SASL handshake failed (start (%d)): %s", r, sasl_errdetail(rktrans->rktrans_sasl.conn)); return -1; } return 0; }
EXPORT_SYM const char * hdfs_namenode_authenticate_full(struct hdfs_namenode *n, const char *username, const char *real_user) { const char *error = NULL; struct hdfs_object *header; struct hdfs_heap_buf hbuf = { 0 }; char *inh = NULL, preamble[12]; size_t preamble_len; _lock(&n->nn_lock); ASSERT(!n->nn_authed); ASSERT(n->nn_sock != -1); memset(preamble, 0, sizeof(preamble)); if (n->nn_proto == HDFS_NN_v1) { sprintf(preamble, "hrpc\x04%c", (n->nn_kerb == HDFS_NO_KERB)? 0x50 : 0x51); preamble_len = 6; header = hdfs_authheader_new_ext(n->nn_proto, username, real_user, HDFS_NO_KERB); } else if (n->nn_proto == HDFS_NN_v2) { /* HDFSv2 has used both version 7 (2.0.0-2.0.2) and 8 (2.0.3+). */ sprintf(preamble, "hrpc%c%c", 8 /* XXX Configurable? */, (n->nn_kerb == HDFS_NO_KERB)? 0x50 : 0x51); /* There is a zero at the end: */ preamble_len = 7; header = hdfs_authheader_new_ext(n->nn_proto, username, real_user, n->nn_kerb); } else if (n->nn_proto == HDFS_NN_v2_2) { memcpy(preamble, "hrpc\x09", 5); preamble[5] = 0; preamble[6] = (n->nn_kerb == HDFS_NO_KERB)? 0 : -33; preamble_len = 7; header = hdfs_authheader_new_ext(n->nn_proto, username, real_user, n->nn_kerb); _authheader_set_clientid(header, n->nn_client_id); } else { ASSERT(false); } // Serialize the connection header object (I am speaking ClientProtocol // and this is my username) hdfs_object_serialize(&hbuf, header); hdfs_object_free(header); if (n->nn_kerb == HDFS_NO_KERB) { // Prefix the header object with the protocol preamble hbuf.buf = realloc(hbuf.buf, hbuf.size + preamble_len); ASSERT(hbuf.buf); memmove(hbuf.buf + preamble_len, hbuf.buf, hbuf.used); memcpy(hbuf.buf, preamble, preamble_len); hbuf.used += preamble_len; hbuf.size += preamble_len; } else { /* * XXX This is probably totally wrong for HDFSv2+. They start * using protobufs at this point to wrap the SASL packets. * * To be fair, it's probably broken for HDFSv1 too :). I need * to find a kerberized HDFS to test against. */ int r; sasl_interact_t *interactions = NULL; const char *out, *mechusing; unsigned outlen; struct iovec iov[3]; uint32_t inlen; const uint32_t SWITCH_TO_SIMPLE_AUTH = (uint32_t)-1; uint8_t in[4], zero[4] = { 0 }; do { r = sasl_client_start(n->nn_sasl_ctx, "GSSAPI", &interactions, &out, &outlen, &mechusing); if (r == SASL_INTERACT) _sasl_interacts(interactions); } while (r == SASL_INTERACT); if (r != SASL_CONTINUE) { error = sasl_errstring(r, NULL, NULL); goto out; } // Send prefix, first auth token _be32enc(in, outlen); iov[0].iov_base = preamble; iov[0].iov_len = preamble_len; iov[1].iov_base = in; iov[1].iov_len = 4; iov[2].iov_base = __DECONST(void *, out); iov[2].iov_len = outlen; error = _writev_all(n->nn_sock, iov, 3); if (error) goto out; do { // read success / error status error = _read_all(n->nn_sock, in, 4); if (error) goto out; if (memcmp(in, zero, 4)) { // error. exception will be next on the wire, // but let's skip it. error = "Got error from server, bailing"; goto out; } // read token len error = _read_all(n->nn_sock, in, 4); if (error) goto out; inlen = _be32dec(in); if (inlen == SWITCH_TO_SIMPLE_AUTH) { if (n->nn_kerb == HDFS_REQUIRE_KERB) { error = "Server tried to drop kerberos but " "client requires it"; goto out; } goto send_header; } // read token if (inh) free(inh); inh = NULL; if (inlen > 0) { inh = malloc(inlen); ASSERT(inh); error = _read_all(n->nn_sock, inh, inlen); if (error) goto out; } out = NULL; outlen = 0; r = sasl_client_step(n->nn_sasl_ctx, inh, inlen, &interactions, &out, &outlen); if (r == SASL_INTERACT) _sasl_interacts(interactions); if (r == SASL_CONTINUE || (r == SASL_OK && out != NULL)) { _be32enc(in, outlen); iov[0].iov_base = in; iov[0].iov_len = 4; iov[1].iov_base = __DECONST(void *, out); iov[1].iov_len = outlen; error = _writev_all(n->nn_sock, iov, 2); if (error) goto out; } } while (r == SASL_INTERACT || r == SASL_CONTINUE); if (r != SASL_OK) { error = sasl_errstring(r, NULL, NULL); goto out; } // sasl connection established n->nn_sasl_ssf = _getssf(n->nn_sasl_ctx); send_header: if (n->nn_sasl_ssf > 0) _sasl_encode_inplace(n->nn_sasl_ctx, &hbuf); } // send auth header error = _write_all(n->nn_sock, hbuf.buf, hbuf.used); n->nn_authed = true; out: if (inh) free(inh); _unlock(&n->nn_lock); free(hbuf.buf); return error; }
int clientTryAgain() { if(step == 0) { const char *clientout, *m; unsigned int clientoutlen; need = 0; QString list = methodsToString(mechlist); int r; while(1) { if(need) params.extractHave(need); if(in_sendFirst) r = sasl_client_start(con, list.toLatin1().data(), &need, &clientout, &clientoutlen, &m); else r = sasl_client_start(con, list.toLatin1().data(), &need, NULL, NULL, &m); if(r != SASL_INTERACT) break; params.applyInteract(need); if(params.missingAny()) return NeedParams; } if(r != SASL_OK && r != SASL_CONTINUE) { err = saslErrorCond(r); return Error; } out_mech = m; if(in_sendFirst && clientout) { out_clientInit = makeByteArray(clientout, clientoutlen); out_useClientInit = true; } else out_useClientInit = false; ++step; if(r == SASL_OK) { getssfparams(); return Success; } return Continue; } else { const char *clientout; unsigned int clientoutlen; int r; while(1) { if(need) params.extractHave(need); //QByteArray cs(in_buf.data(), in_buf.size()); //printf("sasl_client_step(con, {%s}, %d, &need, &clientout, &clientoutlen);\n", cs.data(), in_buf.size()); r = sasl_client_step(con, in_buf.data(), in_buf.size(), &need, &clientout, &clientoutlen); //printf("returned: %d\n", r); if(r != SASL_INTERACT) break; params.applyInteract(need); if(params.missingAny()) return NeedParams; } if(r != SASL_OK && r != SASL_CONTINUE) { err = saslErrorCond(r); return Error; } out_buf = makeByteArray(clientout, clientoutlen); if(r == SASL_OK) { getssfparams(); return Success; } return Continue; } }
static bool _mongoc_cyrus_start (mongoc_cyrus_t *sasl, uint8_t *outbuf, uint32_t outbufmax, uint32_t *outbuflen, bson_error_t *error) { const char *service_name = "mongodb"; const char *service_host = ""; const char *mechanism = NULL; const char *raw = NULL; unsigned raw_len = 0; int status; BSON_ASSERT (sasl); BSON_ASSERT (outbuf); BSON_ASSERT (outbufmax); BSON_ASSERT (outbuflen); if (sasl->credentials.service_name) { service_name = sasl->credentials.service_name; } if (sasl->credentials.service_host) { service_host = sasl->credentials.service_host; } status = sasl_client_new ( service_name, service_host, NULL, NULL, sasl->callbacks, 0, &sasl->conn); TRACE ("Created new sasl client %s", status == SASL_OK ? "successfully" : "UNSUCCESSFULLY"); if (_mongoc_cyrus_is_failure (status, error)) { return false; } status = sasl_client_start (sasl->conn, sasl->credentials.mechanism, &sasl->interact, &raw, &raw_len, &mechanism); TRACE ("Started the sasl client %s", status == SASL_CONTINUE ? "successfully" : "UNSUCCESSFULLY"); if (_mongoc_cyrus_is_failure (status, error)) { return false; } if ((0 != strcasecmp (mechanism, "GSSAPI")) && (0 != strcasecmp (mechanism, "PLAIN"))) { bson_set_error (error, MONGOC_ERROR_SASL, SASL_NOMECH, "SASL Failure: invalid mechanism \"%s\"", mechanism); return false; } status = sasl_encode64 (raw, raw_len, (char *) outbuf, outbufmax, outbuflen); if (_mongoc_cyrus_is_failure (status, error)) { return false; } return true; }
int mailesmtp_auth_sasl(mailsmtp * session, const char * auth_type, const char * server_fqdn, const char * local_ip_port, const char * remote_ip_port, const char * login, const char * auth_name, const char * password, const char * realm) { #ifdef USE_SASL int r; char command[SMTP_STRING_SIZE]; sasl_callback_t sasl_callback[5]; const char * sasl_out; unsigned sasl_out_len; const char * mechusing; sasl_secret_t * secret; int res; size_t len; char * encoded; unsigned int encoded_len; unsigned int max_encoded; sasl_callback[0].id = SASL_CB_GETREALM; sasl_callback[0].proc = (int (*)(void)) sasl_getrealm; sasl_callback[0].context = session; sasl_callback[1].id = SASL_CB_USER; sasl_callback[1].proc = (int (*)(void)) sasl_getsimple; sasl_callback[1].context = session; sasl_callback[2].id = SASL_CB_AUTHNAME; sasl_callback[2].proc = (int (*)(void)) sasl_getsimple; sasl_callback[2].context = session; sasl_callback[3].id = SASL_CB_PASS; sasl_callback[3].proc = (int (*)(void)) sasl_getsecret; sasl_callback[3].context = session; sasl_callback[4].id = SASL_CB_LIST_END; sasl_callback[4].proc = NULL; sasl_callback[4].context = NULL; len = strlen(password); secret = malloc(sizeof(* secret) + len); if (secret == NULL) { res = MAILSMTP_ERROR_MEMORY; goto err; } secret->len = len; memcpy(secret->data, password, len + 1); session->smtp_sasl.sasl_server_fqdn = server_fqdn; session->smtp_sasl.sasl_login = login; session->smtp_sasl.sasl_auth_name = auth_name; session->smtp_sasl.sasl_password = password; session->smtp_sasl.sasl_realm = realm; session->smtp_sasl.sasl_secret = secret; /* init SASL */ if (session->smtp_sasl.sasl_conn != NULL) { sasl_dispose((sasl_conn_t **) &session->smtp_sasl.sasl_conn); session->smtp_sasl.sasl_conn = NULL; } else { mailsasl_ref(); } r = sasl_client_new("smtp", server_fqdn, local_ip_port, remote_ip_port, sasl_callback, 0, (sasl_conn_t **) &session->smtp_sasl.sasl_conn); if (r != SASL_OK) { res = MAILSMTP_ERROR_AUTH_LOGIN; goto free_secret; } r = sasl_client_start(session->smtp_sasl.sasl_conn, auth_type, NULL, &sasl_out, &sasl_out_len, &mechusing); if ((r != SASL_CONTINUE) && (r != SASL_OK)) { res = MAILSMTP_ERROR_AUTH_LOGIN; goto free_sasl_conn; } if (sasl_out_len != 0) { max_encoded = ((sasl_out_len + 2) / 3) * 4; encoded = malloc(max_encoded + 1); if (encoded == NULL) { res = MAILSMTP_ERROR_MEMORY; goto free_sasl_conn; } r = sasl_encode64(sasl_out, sasl_out_len, encoded, max_encoded + 1, &encoded_len); if (r != SASL_OK) { free(encoded); res = MAILSMTP_ERROR_MEMORY; goto free_sasl_conn; } snprintf(command, SMTP_STRING_SIZE, "AUTH %s %s\r\n", auth_type, encoded); free(encoded); } else { snprintf(command, SMTP_STRING_SIZE, "AUTH %s\r\n", auth_type); } r = send_command_private(session, command, 0); if (r == -1) { res = MAILSMTP_ERROR_STREAM; goto free_sasl_conn; } while (1) { r = read_response(session); switch (r) { case 220: case 235: res = MAILSMTP_NO_ERROR; goto free_sasl_conn; case 535: res = MAILSMTP_ERROR_AUTH_LOGIN; goto free_sasl_conn; case 553: case 554: res = MAILSMTP_ERROR_AUTH_AUTHENTICATION_FAILED; goto free_sasl_conn; case 334: { size_t response_len; char * decoded; unsigned int decoded_len; unsigned int max_decoded; char * p; p = strchr(session->response, '\r'); if (p != NULL) { * p = '\0'; } p = strchr(session->response, '\n'); if (p != NULL) { * p = '\0'; } response_len = strlen(session->response); max_decoded = response_len * 3 / 4; decoded = malloc(max_decoded + 1); if (decoded == NULL) { res = MAILSMTP_ERROR_MEMORY; goto free_sasl_conn; } r = sasl_decode64(session->response, response_len, decoded, max_decoded + 1, &decoded_len); if (r != SASL_OK) { free(decoded); res = MAILSMTP_ERROR_MEMORY; goto free_sasl_conn; } r = sasl_client_step(session->smtp_sasl.sasl_conn, decoded, decoded_len, NULL, &sasl_out, &sasl_out_len); free(decoded); if ((r != SASL_CONTINUE) && (r != SASL_OK)) { res = MAILSMTP_ERROR_AUTH_LOGIN; goto free_sasl_conn; } max_encoded = ((sasl_out_len + 2) / 3) * 4; encoded = malloc(max_encoded + 1); if (encoded == NULL) { res = MAILSMTP_ERROR_MEMORY; goto free_sasl_conn; } r = sasl_encode64(sasl_out, sasl_out_len, encoded, max_encoded + 1, &encoded_len); if (r != SASL_OK) { free(encoded); res = MAILSMTP_ERROR_MEMORY; goto free_sasl_conn; } snprintf(command, SMTP_STRING_SIZE, "%s\r\n", encoded); r = send_command(session, command); free(encoded); if (r == -1) { res = MAILSMTP_ERROR_STREAM; goto free_sasl_conn; } } break; default: res = auth_map_errors(r); goto free_sasl_conn; } } res = MAILSMTP_NO_ERROR; free_sasl_conn: sasl_dispose((sasl_conn_t **) &session->smtp_sasl.sasl_conn); session->smtp_sasl.sasl_conn = NULL; mailsasl_unref(); free_secret: free(session->smtp_sasl.sasl_secret); session->smtp_sasl.sasl_secret = NULL; err: return res; #else return MAILSMTP_ERROR_NOT_IMPLEMENTED; #endif }
static int nsldapi_sasl_do_bind( LDAP *ld, const char *dn, const char *mechs, unsigned flags, LDAP_SASL_INTERACT_PROC *callback, void *defaults, LDAPControl **sctrl, LDAPControl **cctrl, LDAPControl ***rctrl ) { sasl_interact_t *prompts = NULL; sasl_conn_t *ctx = NULL; sasl_ssf_t *ssf = NULL; const char *mech = NULL; int saslrc, rc; struct berval ccred; unsigned credlen; int stepnum = 1; char *sasl_username = NULL; if (rctrl) { /* init to NULL so we can call ldap_controls_free below */ *rctrl = NULL; } if (NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3) { LDAP_SET_LDERRNO( ld, LDAP_NOT_SUPPORTED, NULL, NULL ); return( LDAP_NOT_SUPPORTED ); } /* shouldn't happen */ if (callback == NULL) { return( LDAP_LOCAL_ERROR ); } if ( (rc = nsldapi_sasl_open(ld, NULL, &ctx, 0)) != LDAP_SUCCESS ) { return( rc ); } ccred.bv_val = NULL; ccred.bv_len = 0; LDAPDebug(LDAP_DEBUG_TRACE, "Starting SASL/%s authentication\n", (mechs ? mechs : ""), 0, 0 ); do { saslrc = sasl_client_start( ctx, mechs, &prompts, (const char **)&ccred.bv_val, &credlen, &mech ); LDAPDebug(LDAP_DEBUG_TRACE, "Doing step %d of client start for SASL/%s authentication\n", stepnum, (mech ? mech : ""), 0 ); stepnum++; if( saslrc == SASL_INTERACT && (callback)(ld, flags, defaults, prompts) != LDAP_SUCCESS ) { break; } } while ( saslrc == SASL_INTERACT ); ccred.bv_len = credlen; if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) { return( nsldapi_sasl_cvterrno( ld, saslrc, nsldapi_strdup( sasl_errdetail( ctx ) ) ) ); } stepnum = 1; do { struct berval *scred; int clientstepnum = 1; scred = NULL; if (rctrl) { /* if we're looping again, we need to free any controls set during the previous loop */ /* NOTE that this assumes we only care about the controls returned by the last call to nsldapi_sasl_bind_s - if we care about _all_ controls, we will have to figure out some way to append them each loop go round */ ldap_controls_free(*rctrl); *rctrl = NULL; } LDAPDebug(LDAP_DEBUG_TRACE, "Doing step %d of bind for SASL/%s authentication\n", stepnum, (mech ? mech : ""), 0 ); stepnum++; /* notify server of a sasl bind step */ rc = nsldapi_sasl_bind_s(ld, dn, mech, &ccred, sctrl, cctrl, &scred, rctrl); if ( ccred.bv_val != NULL ) { ccred.bv_val = NULL; } if ( rc != LDAP_SUCCESS && rc != LDAP_SASL_BIND_IN_PROGRESS ) { ber_bvfree( scred ); return( rc ); } if( rc == LDAP_SUCCESS && saslrc == SASL_OK ) { /* we're done, no need to step */ if( scred ) { if ( scred->bv_len == 0 ) { /* MS AD sends back empty screds */ LDAPDebug(LDAP_DEBUG_ANY, "SASL BIND complete - ignoring empty credential response\n", 0, 0, 0); ber_bvfree( scred ); } else { /* but server provided us with data! */ LDAPDebug(LDAP_DEBUG_TRACE, "SASL BIND complete but invalid because server responded with credentials - length [%u]\n", scred->bv_len, 0, 0); ber_bvfree( scred ); LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, "Error during SASL handshake - invalid server credential response" ); return( LDAP_LOCAL_ERROR ); } } break; } /* perform the next step of the sasl bind */ do { LDAPDebug(LDAP_DEBUG_TRACE, "Doing client step %d of bind step %d for SASL/%s authentication\n", clientstepnum, stepnum, (mech ? mech : "") ); clientstepnum++; saslrc = sasl_client_step( ctx, (scred == NULL) ? NULL : scred->bv_val, (scred == NULL) ? 0 : scred->bv_len, &prompts, (const char **)&ccred.bv_val, &credlen ); if( saslrc == SASL_INTERACT && (callback)(ld, flags, defaults, prompts) != LDAP_SUCCESS ) { break; } } while ( saslrc == SASL_INTERACT ); ccred.bv_len = credlen; ber_bvfree( scred ); if ( (saslrc != SASL_OK) && (saslrc != SASL_CONTINUE) ) { return( nsldapi_sasl_cvterrno( ld, saslrc, nsldapi_strdup( sasl_errdetail( ctx ) ) ) ); } } while ( rc == LDAP_SASL_BIND_IN_PROGRESS ); if ( rc != LDAP_SUCCESS ) { return( rc ); } if ( saslrc != SASL_OK ) { return( nsldapi_sasl_cvterrno( ld, saslrc, nsldapi_strdup( sasl_errdetail( ctx ) ) ) ); } saslrc = sasl_getprop( ctx, SASL_USERNAME, (const void **) &sasl_username ); if ( (saslrc == SASL_OK) && sasl_username ) { LDAPDebug(LDAP_DEBUG_TRACE, "SASL identity: %s\n", sasl_username, 0, 0); } saslrc = sasl_getprop( ctx, SASL_SSF, (const void **) &ssf ); if( saslrc == SASL_OK ) { if( ssf && *ssf ) { LDAPDebug(LDAP_DEBUG_TRACE, "SASL install encryption, for SSF: %lu\n", (unsigned long) *ssf, 0, 0 ); nsldapi_sasl_install( ld, NULL ); } } return( rc ); }
static int login(struct backend *s, const char *userid, sasl_callback_t *cb, const char **status, int noauth __attribute__((unused))) { int r = 0; socklen_t addrsize; struct sockaddr_storage saddr_l, saddr_r; char remoteip[60], localip[60]; static struct buf buf = BUF_INITIALIZER; sasl_security_properties_t secprops = { 0, 0xFF, PROT_BUFSIZE, 0, NULL, NULL }; /* default secprops */ const char *mech_conf, *pass, *clientout = NULL; struct auth_scheme_t *scheme = NULL; unsigned need_tls = 0, tls_done = 0, auth_done = 0, clientoutlen; hdrcache_t hdrs = NULL; if (status) *status = NULL; /* set the IP addresses */ addrsize = sizeof(struct sockaddr_storage); if (getpeername(s->sock, (struct sockaddr *) &saddr_r, &addrsize) || iptostring((struct sockaddr *) &saddr_r, addrsize, remoteip, 60)) { if (status) *status = "Failed to get remote IP address"; return SASL_FAIL; } addrsize = sizeof(struct sockaddr_storage); if (getsockname(s->sock, (struct sockaddr *) &saddr_l, &addrsize) || iptostring((struct sockaddr *) &saddr_l, addrsize, localip, 60)) { if (status) *status = "Failed to get local IP address"; return SASL_FAIL; } /* Create callbacks, if necessary */ if (!cb) { buf_setmap(&buf, s->hostname, strcspn(s->hostname, ".")); buf_appendcstr(&buf, "_password"); pass = config_getoverflowstring(buf_cstring(&buf), NULL); if (!pass) pass = config_getstring(IMAPOPT_PROXY_PASSWORD); cb = mysasl_callbacks(NULL, /* userid */ config_getstring(IMAPOPT_PROXY_AUTHNAME), config_getstring(IMAPOPT_PROXY_REALM), pass); s->sasl_cb = cb; } /* Create SASL context */ r = sasl_client_new(s->prot->sasl_service, s->hostname, localip, remoteip, cb, SASL_USAGE_FLAGS, &s->saslconn); if (r != SASL_OK) goto done; r = sasl_setprop(s->saslconn, SASL_SEC_PROPS, &secprops); if (r != SASL_OK) goto done; /* Get SASL mechanism list. We can force a particular mechanism using a <shorthost>_mechs option */ buf_setmap(&buf, s->hostname, strcspn(s->hostname, ".")); buf_appendcstr(&buf, "_mechs"); if (!(mech_conf = config_getoverflowstring(buf_cstring(&buf), NULL))) { mech_conf = config_getstring(IMAPOPT_FORCE_SASL_CLIENT_MECH); } do { unsigned code; const char **hdr, *errstr, *serverin; char base64[BASE64_BUF_SIZE+1]; unsigned int serverinlen; struct body_t resp_body; #ifdef SASL_HTTP_REQUEST sasl_http_request_t httpreq = { "OPTIONS", /* Method */ "*", /* URI */ (u_char *) "", /* Empty body */ 0, /* Zero-length body */ 0 }; /* Persistent cxn? */ #endif /* Base64 encode any client response, if necessary */ if (clientout && scheme && (scheme->flags & AUTH_BASE64)) { r = sasl_encode64(clientout, clientoutlen, base64, BASE64_BUF_SIZE, &clientoutlen); if (r != SASL_OK) break; clientout = base64; } /* Send Authorization and/or Upgrade request to server */ prot_puts(s->out, "OPTIONS * HTTP/1.1\r\n"); prot_printf(s->out, "Host: %s\r\n", s->hostname); prot_printf(s->out, "User-Agent: %s\r\n", buf_cstring(&serverinfo)); if (scheme) { prot_printf(s->out, "Authorization: %s %s\r\n", scheme->name, clientout ? clientout : ""); prot_printf(s->out, "Authorize-As: %s\r\n", userid ? userid : "anonymous"); } else { prot_printf(s->out, "Upgrade: %s\r\n", TLS_VERSION); if (need_tls) { prot_puts(s->out, "Connection: Upgrade\r\n"); need_tls = 0; } prot_puts(s->out, "Authorization: \r\n"); } prot_puts(s->out, "\r\n"); prot_flush(s->out); serverin = clientout = NULL; serverinlen = clientoutlen = 0; /* Read response(s) from backend until final response or error */ do { resp_body.flags = BODY_DISCARD; r = http_read_response(s, METH_OPTIONS, &code, NULL, &hdrs, &resp_body, &errstr); if (r) { if (status) *status = errstr; break; } if (code == 101) { /* Switching Protocols */ if (tls_done) { r = HTTP_BAD_GATEWAY; if (status) *status = "TLS already active"; break; } else if (backend_starttls(s, NULL, NULL, NULL)) { r = HTTP_SERVER_ERROR; if (status) *status = "Unable to start TLS"; break; } else tls_done = 1; } } while (code < 200); switch (code) { default: /* Failure */ if (!r) { r = HTTP_BAD_GATEWAY; if (status) { buf_reset(&buf); buf_printf(&buf, "Unexpected status code from backend: %u", code); *status = buf_cstring(&buf); } } break; case 426: /* Upgrade Required */ if (tls_done) { r = HTTP_BAD_GATEWAY; if (status) *status = "TLS already active"; } else need_tls = 1; break; case 200: /* OK */ if (scheme->recv_success && (serverin = scheme->recv_success(hdrs))) { /* Process success data */ serverinlen = strlen(serverin); goto challenge; } break; case 401: /* Unauthorized */ if (auth_done) { r = SASL_BADAUTH; break; } if (!serverin) { int i = 0; hdr = spool_getheader(hdrs, "WWW-Authenticate"); if (!scheme) { unsigned avail_auth_schemes = 0; const char *mech = NULL; size_t len; /* Compare authentication schemes offered in * WWW-Authenticate header(s) to what we support */ buf_reset(&buf); for (i = 0; hdr && hdr[i]; i++) { len = strcspn(hdr[i], " "); for (scheme = auth_schemes; scheme->name; scheme++) { if (!strncmp(scheme->name, hdr[i], len) && !((scheme->flags & AUTH_NEED_PERSIST) && (resp_body.flags & BODY_CLOSE))) { /* Tag the scheme as available */ avail_auth_schemes |= (1 << scheme->idx); /* Add SASL-based schemes to SASL mech list */ if (scheme->saslmech) { if (buf_len(&buf)) buf_putc(&buf, ' '); buf_appendcstr(&buf, scheme->saslmech); } break; } } } /* If we have a mech_conf, use it */ if (mech_conf && buf_len(&buf)) { char *conf = xstrdup(mech_conf); char *newmechlist = intersect_mechlists(conf, (char *) buf_cstring(&buf)); if (newmechlist) { buf_setcstr(&buf, newmechlist); free(newmechlist); } else { syslog(LOG_DEBUG, "%s did not offer %s", s->hostname, mech_conf); buf_reset(&buf); } free(conf); } #ifdef SASL_HTTP_REQUEST /* Set HTTP request as specified above (REQUIRED) */ httpreq.non_persist = (resp_body.flags & BODY_CLOSE); sasl_setprop(s->saslconn, SASL_HTTP_REQUEST, &httpreq); #endif /* Try to start SASL exchange using available mechs */ r = sasl_client_start(s->saslconn, buf_cstring(&buf), NULL, /* no prompts */ NULL, NULL, /* no initial resp */ &mech); if (mech) { /* Find auth scheme associated with chosen SASL mech */ for (scheme = auth_schemes; scheme->name; scheme++) { if (scheme->saslmech && !strcmp(scheme->saslmech, mech)) break; } } else { /* No matching SASL mechs - try Basic */ scheme = &auth_schemes[AUTH_BASIC]; if (!(avail_auth_schemes & (1 << scheme->idx))) { need_tls = !tls_done; break; /* case 401 */ } } /* Find the associated WWW-Authenticate header */ for (i = 0; hdr && hdr[i]; i++) { len = strcspn(hdr[i], " "); if (!strncmp(scheme->name, hdr[i], len)) break; } } /* Get server challenge, if any */ if (hdr) { const char *p = strchr(hdr[i], ' '); serverin = p ? ++p : ""; serverinlen = strlen(serverin); } } challenge: if (serverin) { /* Perform the next step in the auth exchange */ if (scheme->idx == AUTH_BASIC) { /* Don't care about "realm" in server challenge */ const char *authid = callback_getdata(s->saslconn, cb, SASL_CB_AUTHNAME); pass = callback_getdata(s->saslconn, cb, SASL_CB_PASS); buf_reset(&buf); buf_printf(&buf, "%s:%s", authid, pass); clientout = buf_cstring(&buf); clientoutlen = buf_len(&buf); auth_done = 1; } else { /* Base64 decode any server challenge, if necessary */ if (serverin && (scheme->flags & AUTH_BASE64)) { r = sasl_decode64(serverin, serverinlen, base64, BASE64_BUF_SIZE, &serverinlen); if (r != SASL_OK) break; /* case 401 */ serverin = base64; } /* SASL mech (Digest, Negotiate, NTLM) */ r = sasl_client_step(s->saslconn, serverin, serverinlen, NULL, /* no prompts */ &clientout, &clientoutlen); if (r == SASL_OK) auth_done = 1; } } break; /* case 401 */ } } while (need_tls || clientout); done: if (hdrs) spool_free_hdrcache(hdrs); if (r && status && !*status) *status = sasl_errstring(r, NULL, NULL); return r; }
static int smtp_auth_sasl (CONNECTION* conn, const char* mechlist) { sasl_conn_t* saslconn; sasl_interact_t* interaction = NULL; const char* mech; const char* data = NULL; unsigned int len; char buf[HUGE_STRING]; int rc, saslrc; if (mutt_sasl_client_new (conn, &saslconn) < 0) return SMTP_AUTH_FAIL; do { rc = sasl_client_start (saslconn, mechlist, &interaction, &data, &len, &mech); if (rc == SASL_INTERACT) mutt_sasl_interact (interaction); } while (rc == SASL_INTERACT); if (rc != SASL_OK && rc != SASL_CONTINUE) { dprint (2, (debugfile, "smtp_auth_sasl: %s unavailable\n", mech)); sasl_dispose (&saslconn); return SMTP_AUTH_UNAVAIL; } if (!option(OPTNOCURSES)) mutt_message (_("Authenticating (%s)..."), mech); snprintf (buf, sizeof (buf), "AUTH %s", mech); if (len) { safe_strcat (buf, sizeof (buf), " "); if (sasl_encode64 (data, len, buf + mutt_strlen (buf), sizeof (buf) - mutt_strlen (buf), &len) != SASL_OK) { dprint (1, (debugfile, "smtp_auth_sasl: error base64-encoding client response.\n")); goto fail; } } safe_strcat (buf, sizeof (buf), "\r\n"); do { if (mutt_socket_write (conn, buf) < 0) goto fail; if ((rc = mutt_socket_readln (buf, sizeof (buf), conn)) < 0) goto fail; if (smtp_code (buf, rc, &rc) < 0) goto fail; if (rc != smtp_ready) break; if (sasl_decode64 (buf+4, strlen (buf+4), buf, sizeof (buf), &len) != SASL_OK) { dprint (1, (debugfile, "smtp_auth_sasl: error base64-decoding server response.\n")); goto fail; } do { saslrc = sasl_client_step (saslconn, buf, len, &interaction, &data, &len); if (saslrc == SASL_INTERACT) mutt_sasl_interact (interaction); } while (saslrc == SASL_INTERACT); if (len) { if (sasl_encode64 (data, len, buf, sizeof (buf), &len) != SASL_OK) { dprint (1, (debugfile, "smtp_auth_sasl: error base64-encoding client response.\n")); goto fail; } } strfcpy (buf + len, "\r\n", sizeof (buf) - len); } while (rc == smtp_ready && saslrc != SASL_FAIL); if (smtp_success (rc)) { mutt_sasl_setup_conn (conn, saslconn); return SMTP_AUTH_SUCCESS; } fail: sasl_dispose (&saslconn); return SMTP_AUTH_FAIL; }
static JabberSaslState jabber_auth_start_cyrus(JabberStream *js, xmlnode **reply, char **error) { PurpleAccount *account; const char *clientout = NULL; char *enc_out; unsigned coutlen = 0; sasl_security_properties_t secprops; gboolean again; gboolean plaintext = TRUE; /* Set up security properties and options */ secprops.min_ssf = 0; secprops.security_flags = SASL_SEC_NOANONYMOUS; account = purple_connection_get_account(js->gc); if (!jabber_stream_is_ssl(js)) { secprops.max_ssf = -1; secprops.maxbufsize = 4096; plaintext = purple_account_get_bool(account, "auth_plain_in_clear", FALSE); if (!plaintext) secprops.security_flags |= SASL_SEC_NOPLAINTEXT; } else { secprops.max_ssf = 0; secprops.maxbufsize = 0; plaintext = TRUE; } secprops.property_names = 0; secprops.property_values = 0; do { again = FALSE; js->sasl_state = sasl_client_new("xmpp", js->serverFQDN, NULL, NULL, js->sasl_cb, 0, &js->sasl); if (js->sasl_state==SASL_OK) { sasl_setprop(js->sasl, SASL_SEC_PROPS, &secprops); purple_debug_info("sasl", "Mechs found: %s\n", js->sasl_mechs->str); js->sasl_state = sasl_client_start(js->sasl, js->sasl_mechs->str, NULL, &clientout, &coutlen, &js->current_mech); } switch (js->sasl_state) { /* Success */ case SASL_OK: case SASL_CONTINUE: break; case SASL_NOMECH: /* No mechanisms have offered to help */ /* Firstly, if we don't have a password try * to get one */ if (!purple_account_get_password(account)) { purple_account_request_password(account, G_CALLBACK(auth_pass_cb), G_CALLBACK(auth_no_pass_cb), js->gc); return JABBER_SASL_STATE_CONTINUE; /* If we've got a password, but aren't sending * it in plaintext, see if we can turn on * plaintext auth */ /* XXX Should we just check for PLAIN/LOGIN being offered mechanisms? */ } else if (!plaintext) { char *msg = g_strdup_printf(_("%s may require plaintext authentication over an unencrypted connection. Allow this and continue authentication?"), purple_account_get_username(account)); purple_request_yes_no(js->gc, _("Plaintext Authentication"), _("Plaintext Authentication"), msg, 1, account, NULL, NULL, account, allow_cyrus_plaintext_auth, disallow_plaintext_auth); g_free(msg); return JABBER_SASL_STATE_CONTINUE; } else js->auth_fail_count++; if (js->auth_fail_count == 1 && (js->sasl_mechs->str && g_str_equal(js->sasl_mechs->str, "GSSAPI"))) { /* If we tried GSSAPI first, it failed, and it was the only method we had to try, try jabber:iq:auth * for compatibility with iChat 10.5 Server and other jabberd based servers. * * iChat Server 10.5 and certain other corporate servers offer SASL GSSAPI by default, which is often * not configured on the client side, and expects a fallback to jabber:iq:auth when it (predictably) fails. * * Note: xep-0078 points out that using jabber:iq:auth after a sasl failure is wrong. However, * I believe this refers to actual authentication failure, not a simple lack of concordant mechanisms. * Doing otherwise means that simply compiling with SASL support renders the client unable to connect to servers * which would connect without issue otherwise. -evands */ js->auth_mech = NULL; jabber_auth_start_old(js); return JABBER_SASL_STATE_CONTINUE; } break; /* Fatal errors. Give up and go home */ case SASL_BADPARAM: case SASL_NOMEM: *error = g_strdup(_("SASL authentication failed")); break; /* For everything else, fail the mechanism and try again */ default: purple_debug_info("sasl", "sasl_state is %d, failing the mech and trying again\n", js->sasl_state); js->auth_fail_count++; /* * DAA: is this right? * The manpage says that "mech" will contain the chosen mechanism on success. * Presumably, if we get here that isn't the case and we shouldn't try again? * I suspect that this never happens. */ /* * SXW: Yes, this is right. What this handles is the situation where a * mechanism, say GSSAPI, is tried. If that mechanism fails, it may be * due to mechanism specific issues, so we want to try one of the other * supported mechanisms. This code handles that case */ if (js->current_mech && *js->current_mech) { char *pos; if ((pos = strstr(js->sasl_mechs->str, js->current_mech))) { g_string_erase(js->sasl_mechs, pos-js->sasl_mechs->str, strlen(js->current_mech)); } /* Remove space which separated this mech from the next */ if ((js->sasl_mechs->str)[0] == ' ') { g_string_erase(js->sasl_mechs, 0, 1); } again = TRUE; } sasl_dispose(&js->sasl); } } while (again); if (js->sasl_state == SASL_CONTINUE || js->sasl_state == SASL_OK) { xmlnode *auth = xmlnode_new("auth"); xmlnode_set_namespace(auth, NS_XMPP_SASL); xmlnode_set_attrib(auth, "mechanism", js->current_mech); xmlnode_set_attrib(auth, "xmlns:ga", "http://www.google.com/talk/protocol/auth"); xmlnode_set_attrib(auth, "ga:client-uses-full-bind-result", "true"); if (clientout) { if (coutlen == 0) { xmlnode_insert_data(auth, "=", -1); } else { enc_out = purple_base64_encode((unsigned char*)clientout, coutlen); xmlnode_insert_data(auth, enc_out, -1); g_free(enc_out); } } *reply = auth; return JABBER_SASL_STATE_CONTINUE; } else { return JABBER_SASL_STATE_FAIL; } }