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; }
int php_mongo_io_authenticate_plain(mongo_con_manager *manager, mongo_connection *con, mongo_server_options *options, mongo_server_def *server_def, char **error_message) { char step_payload[4096]; char *out, *plain; char *mechanism = "PLAIN"; unsigned int step_payload_len, plain_len; int outlen; int32_t step_conversation_id; int result; plain_len = spprintf(&plain, 0, "%c%s%c%s", '\0', server_def->username, '\0', server_def->password); result = sasl_encode64(plain, plain_len, step_payload, sizeof(step_payload), &step_payload_len); if (result != SASL_OK) { *error_message = strdup("SASL authentication: Could not base64 encode payload"); efree(plain); return 0; } efree(plain); if (!mongo_connection_authenticate_saslstart(manager, con, options, server_def, mechanism, step_payload, step_payload_len + 1, &out, &outlen, &step_conversation_id, error_message)) { return 0; } free(out); return 1; }
bson_bool_t _mongoc_sasl_step (mongoc_sasl_t *sasl, const bson_uint8_t *inbuf, bson_uint32_t inbuflen, bson_uint8_t *outbuf, bson_uint32_t outbufmax, bson_uint32_t *outbuflen, bson_error_t *error) { const char *raw = NULL; unsigned rawlen = 0; int status; BSON_ASSERT (sasl); BSON_ASSERT (inbuf); BSON_ASSERT (outbuf); BSON_ASSERT (outbuflen); BSON_ASSERT (*outbuflen); sasl->step++; if (sasl->step == 1) { return _mongoc_sasl_start (sasl, outbuf, outbufmax, outbuflen, error); } else if (sasl->step >= 10) { bson_set_error (error, MONGOC_ERROR_SASL, SASL_NOTDONE, "SASL Failure: maximum steps detected"); return FALSE; } if (!inbuflen) { bson_set_error (error, MONGOC_ERROR_SASL, MONGOC_ERROR_CLIENT_AUTHENTICATE, "SASL Failure: no payload provided from server."); return FALSE; } status = sasl_decode64 ((char *)inbuf, inbuflen, (char *)outbuf, outbufmax, outbuflen); if (_mongoc_sasl_is_failure (status, error)) { return FALSE; } status = sasl_client_step (sasl->conn, (char *)outbuf, *outbuflen, &sasl->interact, &raw, &rawlen); if (_mongoc_sasl_is_failure (status, error)) { return FALSE; } status = sasl_encode64 (raw, rawlen, (char *)outbuf, outbufmax, outbuflen); if (_mongoc_sasl_is_failure (status, error)) { return FALSE; } return TRUE; }
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; }
/* * encode a string into Base 64 */ DWORD VmEncodeToBase64( PBYTE pInput, DWORD dwInputLen, PBYTE *ppBase64Encoded, DWORD *pDwEncodedLen ) { DWORD dwError = 0; DWORD dwBase64EncodedBufferLen = 0; DWORD dwBase64EncodedByteLen = 0; PBYTE pBase64Encoded = NULL; if (!pInput || !ppBase64Encoded) { dwError = VM_COMMON_ERROR_INVALID_PARAMETER; BAIL_ON_VM_COMMON_ERROR(dwError); } dwBase64EncodedBufferLen = VM_COMMON_GET_BASE64_ENCODE_LEN(dwInputLen); dwError = VmAllocateMemory(dwBase64EncodedBufferLen, (PVOID *)&pBase64Encoded ); BAIL_ON_VM_COMMON_ERROR(dwError); dwError = sasl_encode64((PCSTR)pInput, dwInputLen, (PSTR)pBase64Encoded, dwBase64EncodedBufferLen, &dwBase64EncodedByteLen ); BAIL_ON_VM_COMMON_ERROR(dwError); *ppBase64Encoded = pBase64Encoded; *pDwEncodedLen = dwBase64EncodedByteLen; cleanup: return dwError; error: VM_COMMON_SAFE_FREE_MEMORY(pBase64Encoded); if (ppBase64Encoded) { *ppBase64Encoded = NULL; } if (pDwEncodedLen) { *pDwEncodedLen = 0; } goto cleanup; }
int php_mongo_saslcontinue(mongo_con_manager *manager, mongo_connection *con, mongo_server_options *options, mongo_server_def *server_def, sasl_conn_t *conn, char *step_payload, int step_payload_len, int32_t conversation_id, char **error_message) { sasl_interact_t *client_interact=NULL; /* * Snippet from sasl.h: * 4. client calls sasl_client_step() * 4b. If SASL error, goto 7 or 3 * 4c. If SASL_OK, continue or goto 6 if last server response was success */ do { char base_payload[4096], payload[4096]; unsigned int base_payload_len, payload_len; const char *out; unsigned int outlen; unsigned char done = 0; int result; step_payload_len--; /* Remove the \0 from the string */ result = sasl_decode64(step_payload, step_payload_len, base_payload, sizeof(base_payload), &base_payload_len); if (is_sasl_failure(conn, result, error_message)) { return 0; } result = sasl_client_step(conn, (const char *)base_payload, base_payload_len, &client_interact, &out, &outlen); if (is_sasl_failure(conn, result, error_message)) { return 0; } result = sasl_encode64(out, outlen, payload, sizeof(base_payload), &payload_len); if (is_sasl_failure(conn, result, error_message)) { return 0; } if (!mongo_connection_authenticate_saslcontinue(manager, con, options, server_def, conversation_id, payload, payload_len + 1, &step_payload, &step_payload_len, &done, error_message)) { return 0; } if (done) { break; } } while (1); return 1; }
/* b64data = cyrussasl.encode64(data) * * A convenience method to use the Cyrus SASL library implementation of base64 * encoding data. Takes, and returns, a Lua string object. Since Lua strings * may contain true 8-bit data (including '\0'), the length of the data is * obtained by examining the length of the string. */ static int cyrussasl_sasl_encode64(lua_State *l) { unsigned len_out; int alloclen; char *buf = NULL; const char *data = NULL; size_t len; int err; int numargs = lua_gettop(l); if (numargs != 1) { lua_pushstring(l, "usage: b64data = cyrussasl.encode64(data)"); lua_error(l); return 0; } len = 0; data = tolstring(l, 1, &len); /* Allocate a new buffer that will accommodate the data in its most-possibly- * expanded state. */ alloclen = ((len / 3) + 1) * 4 + 1; buf = malloc(alloclen); if (!buf) { lua_pushstring(l, "malloc failed"); lua_error(l); return 0; } err = sasl_encode64(data, len, buf, alloclen, &len_out); if ( err != SASL_OK ) { free(buf); lua_pushstring(l, "sasl_encode64 failed"); lua_error(l); return 0; } lua_pushlstring(l, buf, len_out); free(buf); return 1; }
static int xsasl_cyrus_server_auth_response(int sasl_status, SERVEROUT_TYPE serverout, unsigned serveroutlen, VSTRING *reply) { const char *myname = "xsasl_cyrus_server_auth_response"; unsigned enc_length; unsigned enc_length_out; /* * Encode the server first/next non-error response; otherwise return the * unencoded error text that corresponds to the SASL error status. * * Regarding the hairy expression below: output from sasl_encode64() comes * in multiples of four bytes for each triple of input bytes, plus four * bytes for any incomplete last triple, plus one byte for the null * terminator. */ if (sasl_status == SASL_OK) { vstring_strcpy(reply, ""); return (XSASL_AUTH_DONE); } else if (sasl_status == SASL_CONTINUE) { if (msg_verbose) msg_info("%s: uncoded server challenge: %.*s", myname, (int) serveroutlen, serverout); enc_length = ((serveroutlen + 2) / 3) * 4 + 1; VSTRING_RESET(reply); /* Fix 200512 */ VSTRING_SPACE(reply, enc_length); if ((sasl_status = sasl_encode64(serverout, serveroutlen, STR(reply), vstring_avail(reply), &enc_length_out)) != SASL_OK) msg_panic("%s: sasl_encode64 botch: %s", myname, xsasl_cyrus_strerror(sasl_status)); return (XSASL_AUTH_MORE); } else { if (sasl_status == SASL_NOUSER) /* privacy */ sasl_status = SASL_BADAUTH; vstring_strcpy(reply, xsasl_cyrus_strerror(sasl_status)); return (XSASL_AUTH_FAIL); } }
int php_mongo_saslcontinue(mongo_con_manager *manager, mongo_connection *con, mongo_server_options *options, mongo_server_def *server_def, sasl_conn_t *conn, char *step_payload, int step_payload_len, int32_t conversation_id, char **error_message) { int result; sasl_interact_t *client_interact=NULL; do { char base_payload[4096], payload[4096]; unsigned int base_payload_len, payload_len; unsigned char done; const char *out; unsigned int outlen; result = sasl_decode64(step_payload, step_payload_len, base_payload, sizeof(base_payload), &base_payload_len); if (is_sasl_failure(conn, result, error_message)) { return result; } result = sasl_client_step(conn, (const char *)base_payload, base_payload_len, &client_interact, &out, &outlen); if (is_sasl_failure(conn, result, error_message)) { return result; } /* TODO : Deal with interaction */ if (result == SASL_OK) { /* We are all done */ break; } result = sasl_encode64(out, outlen, payload, sizeof(base_payload), &payload_len); if (is_sasl_failure(conn, result, error_message)) { return result; } if (!mongo_connection_authenticate_saslcontinue(manager, con, options, server_def, conversation_id, payload, payload_len + 1, &step_payload, &step_payload_len, &done, (char **)&error_message)) { *error_message = strdup("saslStart failed miserably"); return result; } } while (result == SASL_INTERACT || result == SASL_CONTINUE); return result; }
/* NOTE: success_data will need to be free()d by the caller */ int saslserver(sasl_conn_t *conn, const char *mech, const char *init_resp, const char *resp_prefix, const char *continuation, const char *empty_chal, struct protstream *pin, struct protstream *pout, int *sasl_result, char **success_data) { char base64[BASE64_BUF_SIZE+1]; char *clientin = NULL; unsigned int clientinlen = 0; const char *serverout = NULL; unsigned int serveroutlen = 0; int r = SASL_OK; if (success_data) *success_data = NULL; /* initial response */ if (init_resp) { clientin = base64; if (!strcmp(init_resp, "=")) { /* zero-length initial response */ base64[0] = '\0'; } else { r = sasl_decode64(init_resp, strlen(init_resp), clientin, BASE64_BUF_SIZE, &clientinlen); } } /* start the exchange */ if (r == SASL_OK) r = sasl_server_start(conn, mech, clientin, clientinlen, &serverout, &serveroutlen); while (r == SASL_CONTINUE) { char *p; /* send the challenge to the client */ if (serveroutlen) { r = sasl_encode64(serverout, serveroutlen, base64, BASE64_BUF_SIZE, NULL); if (r != SASL_OK) break; serverout = base64; } else { serverout = empty_chal; } prot_printf(pout, "%s%s\r\n", continuation, serverout); prot_flush(pout); /* get response from the client */ if (!prot_fgets(base64, BASE64_BUF_SIZE, pin) || strncasecmp(base64, resp_prefix, strlen(resp_prefix))) { if (sasl_result) *sasl_result = SASL_FAIL; return IMAP_SASL_PROTERR; } /* trim CRLF */ p = base64 + strlen(base64) - 1; if (p >= base64 && *p == '\n') *p-- = '\0'; if (p >= base64 && *p == '\r') *p-- = '\0'; /* trim prefix */ p = base64 + strlen(resp_prefix); /* check if client cancelled */ if (p[0] == '*') { if(sasl_result) *sasl_result = SASL_BADPROT; return IMAP_SASL_CANCEL; } /* decode the response */ clientin = base64; r = sasl_decode64(p, strlen(p), clientin, BASE64_BUF_SIZE, &clientinlen); if (r != SASL_OK) break; /* do the next step */ r = sasl_server_step(conn, clientin, clientinlen, &serverout, &serveroutlen); } /* success data */ if (r == SASL_OK && serverout && success_data) { r = sasl_encode64(serverout, serveroutlen, base64, BASE64_BUF_SIZE, NULL); if (r == SASL_OK) *success_data = (char *) xstrdup(base64); } if (sasl_result) *sasl_result = r; return (r == SASL_OK ? 0 : IMAP_SASL_FAIL); }
/** * Send connections to nuauth: between 1 and #CONN_MAX connections * in a big packet of format: * [ nu_header + nu_authfield_ipv6 * N ] */ int send_user_pckt(nuauth_session_t * session, conn_t * carray[CONN_MAX]) { char data[PACKET_SIZE]; char *pointer; unsigned int item; struct nu_header *header; struct nu_authreq *authreq; struct nu_authfield_ipv6 *authfield; struct nu_authfield_app *appfield; unsigned len; const char *appname; char *app_ptr; session->timestamp_last_sent = time(NULL); memset(data, 0, sizeof data); header = (struct nu_header *) data; header->proto = PROTO_VERSION; header->msg_type = USER_REQUEST; header->option = 0; header->length = sizeof(struct nu_header); pointer = (char *) (header + 1); for (item = 0; ((item < CONN_MAX) && carray[item] != NULL); item++) { #if DEBUG printf("adding one authreq\n"); #endif #ifdef LINUX /* get application name from inode */ appname = prg_cache_get(carray[item]->inode); #else appname = "UNKNOWN"; #endif header->length += sizeof(struct nu_authreq) + sizeof(struct nu_authfield_ipv6); authreq = (struct nu_authreq *) pointer; authreq->packet_seq = session->packet_seq++; authreq->packet_length = sizeof(struct nu_authreq) + sizeof(struct nu_authfield_ipv6); authfield = (struct nu_authfield_ipv6 *) (authreq + 1); authfield->type = IPV6_FIELD; authfield->option = 0; authfield->src = carray[item]->ip_src; authfield->dst = carray[item]->ip_dst; authfield->proto = carray[item]->protocol; authfield->flags = 0; authfield->FUSE = 0; #ifdef _I386__ENDIAN_H_ #ifdef __DARWIN_LITTLE_ENDIAN authfield->sport = carray[item]->port_src; authfield->dport = carray[item]->port_dst; #else authfield->sport = htons(carray[item]->port_src); authfield->dport = htons(carray[item]->port_dst); #endif /* DARWIN LITTLE ENDIAN */ #else authfield->sport = htons(carray[item]->port_src); authfield->dport = htons(carray[item]->port_dst); #endif /* I386 ENDIAN */ /* application field */ appfield = (struct nu_authfield_app *) (authfield + 1); appfield->type = APP_FIELD; appfield->option = APP_TYPE_NAME; app_ptr = (char *) (appfield + 1); sasl_encode64(appname, strlen(appname), app_ptr, PROGNAME_BASE64_WIDTH, &len); appfield->length = sizeof(struct nu_authfield_app) + len; authreq->packet_length += appfield->length; /* glue piece together on data if packet is not too long */ header->length += appfield->length; if (session->hash) { struct nu_authfield_app *sigfield; const char *appsig; appsig = prg_cache_getsig(session->hash, carray[item]->inode); sigfield = (struct nu_authfield_app *) ((char*)appfield + appfield->length); sigfield->type = HASH_FIELD; sigfield->option = 0; app_ptr = (char *) (sigfield + 1); memcpy(app_ptr, appsig, strlen(appsig)); sigfield->length = sizeof(struct nu_authfield_app) + strlen(appsig); authreq->packet_length += sigfield->length; /* glue piece together on data if packet is not too long */ header->length += sigfield->length; sigfield->length = htons(sigfield->length); } assert(header->length < PACKET_SIZE); pointer += authreq->packet_length; appfield->length = htons(appfield->length); authreq->packet_length = htons(authreq->packet_length); authfield->length = htons(sizeof(struct nu_authfield_ipv6)); } header->length = htons(header->length); if (session->debug_mode) { log_printf(DEBUG_LEVEL_INFO, "[+] Send %u new connection(s) to nuauth\n", item); } /* and send it */ #if XXX if (session->tls) { if (gnutls_record_send (session->tls, data, pointer - data) <= 0) { log_printf(DEBUG_LEVEL_CRITICAL, "write failed\n"); return 0; } } #else if (ufwissl_write(session->ufwissl, (char*)data, pointer - data) < 0) { log_printf(DEBUG_LEVEL_CRITICAL, "write failed\n"); return 0; } #endif return 1; }
static int xsasl_cyrus_client_next(XSASL_CLIENT *xp, const char *server_reply, VSTRING *client_reply) { const char *myname = "xsasl_cyrus_client_next"; XSASL_CYRUS_CLIENT *client = (XSASL_CYRUS_CLIENT *) xp; unsigned enc_length; unsigned enc_length_out; CLIENTOUT_TYPE clientout; unsigned clientoutlen; unsigned serverinlen; int sasl_status; /* * Process a server challenge. */ serverinlen = strlen(server_reply); VSTRING_RESET(client->decoded); /* Fix 200512 */ VSTRING_SPACE(client->decoded, serverinlen); if ((sasl_status = SASL_DECODE64(server_reply, serverinlen, STR(client->decoded), vstring_avail(client->decoded), &enc_length)) != SASL_OK) { vstring_strcpy(client_reply, xsasl_cyrus_strerror(sasl_status)); return (XSASL_AUTH_FORM); } if (msg_verbose) msg_info("%s: decoded challenge: %.*s", myname, (int) enc_length, STR(client->decoded)); sasl_status = sasl_client_step(client->sasl_conn, STR(client->decoded), enc_length, NO_SASL_INTERACTION, &clientout, &clientoutlen); if (sasl_status != SASL_OK && sasl_status != SASL_CONTINUE) { vstring_strcpy(client_reply, xsasl_cyrus_strerror(sasl_status)); return (XSASL_AUTH_FAIL); } /* * Send a client response. */ if (clientoutlen > 0) { if (msg_verbose) msg_info("%s: uncoded client response %.*s", myname, (int) clientoutlen, clientout); enc_length = ENCODE64_LENGTH(clientoutlen) + 1; VSTRING_RESET(client_reply); /* Fix 200512 */ VSTRING_SPACE(client_reply, enc_length); if ((sasl_status = sasl_encode64(clientout, clientoutlen, STR(client_reply), vstring_avail(client_reply), &enc_length_out)) != SASL_OK) msg_panic("%s: sasl_encode64 botch: %s", myname, xsasl_cyrus_strerror(sasl_status)); #if SASL_VERSION_MAJOR < 2 /* SASL version 1 doesn't free memory that it allocates. */ free(clientout); #endif } else { /* XXX Can't happen. */ vstring_strcpy(client_reply, ""); } return (XSASL_AUTH_OK); }
static int xsasl_cyrus_client_first(XSASL_CLIENT *xp, const char *mechanism_list, const char *username, const char *password, const char **mechanism, VSTRING *init_resp) { const char *myname = "xsasl_cyrus_client_first"; XSASL_CYRUS_CLIENT *client = (XSASL_CYRUS_CLIENT *) xp; unsigned enc_length; unsigned enc_length_out; CLIENTOUT_TYPE clientout; unsigned clientoutlen; int sasl_status; #define NO_SASL_SECRET 0 #define NO_SASL_INTERACTION 0 /* * Save the username and password for the call-backs. */ if (client->username) myfree(client->username); client->username = mystrdup(username); if (client->password) myfree(client->password); client->password = mystrdup(password); /* * Start the client side authentication protocol. */ sasl_status = SASL_CLIENT_START((sasl_conn_t *) client->sasl_conn, mechanism_list, NO_SASL_SECRET, NO_SASL_INTERACTION, &clientout, &clientoutlen, mechanism); if (sasl_status != SASL_OK && sasl_status != SASL_CONTINUE) { vstring_strcpy(init_resp, xsasl_cyrus_strerror(sasl_status)); return (XSASL_AUTH_FAIL); } /* * Generate the AUTH command and the optional initial client response. * sasl_encode64() produces four bytes for each complete or incomplete * triple of input bytes. Allocate an extra byte for string termination. */ #define ENCODE64_LENGTH(n) ((((n) + 2) / 3) * 4) if (clientoutlen > 0) { if (msg_verbose) { escape(client->decoded, clientout, clientoutlen); msg_info("%s: uncoded initial reply: %s", myname, STR(client->decoded)); } enc_length = ENCODE64_LENGTH(clientoutlen) + 1; VSTRING_RESET(init_resp); /* Fix 200512 */ VSTRING_SPACE(init_resp, enc_length); if ((sasl_status = sasl_encode64(clientout, clientoutlen, STR(init_resp), vstring_avail(init_resp), &enc_length_out)) != SASL_OK) msg_panic("%s: sasl_encode64 botch: %s", myname, xsasl_cyrus_strerror(sasl_status)); VSTRING_AT_OFFSET(init_resp, enc_length_out); /* XXX */ #if SASL_VERSION_MAJOR < 2 /* SASL version 1 doesn't free memory that it allocates. */ free(clientout); #endif } else { vstring_strcpy(init_resp, ""); } return (XSASL_AUTH_OK); }
krb5_error_code srp_make_enc_keyblock( srp_gss_ctx_id_t srp_context_handle) { char *srp_session_key_str = NULL; unsigned char *hmac_key = NULL; int b64_alloc_len = 0; unsigned char *ptr_expanded_key = NULL; unsigned char expanded_session_key[SRP_EXPAND_KEY_LEN] = {0}; unsigned char srp_session_key[SRP_EXPAND_SESSION_KEY_LEN] = {0}; int srp_session_key_len = sizeof(srp_session_key); unsigned char iv_data[AES_BLOCK_SIZE] = {0}; int iv_data_len = sizeof(iv_data); int b64_session_key_len = 0; krb5_error_code krb5_err = KRB5_BAD_ENCTYPE; if (!srp_context_handle->srp_session_key || srp_context_handle->srp_session_key_len == 0) { krb5_err = GSS_S_DEFECTIVE_TOKEN; goto error; } srp_print_hex(srp_context_handle->srp_session_key, srp_context_handle->srp_session_key_len, "srp_make_enc_keyblock: SRP-negotiated session key "); /* Expand SRP session key to obtain more bytes for IV/session key */ krb5_err = srp_expand_session_key( srp_context_handle->srp_session_key, srp_context_handle->srp_session_key_len, srp_context_handle->upn_name, /* salt */ (int) strlen(srp_context_handle->upn_name), /* salt length */ SRP_EXPAND_KEY_ITER, sizeof(expanded_session_key), expanded_session_key); if (krb5_err) { goto error; } /* Carve up parts of the expanded key for various purposes */ ptr_expanded_key = expanded_session_key; /* Initialization vector */ memcpy(iv_data, ptr_expanded_key, iv_data_len); ptr_expanded_key += iv_data_len; srp_print_hex(iv_data, iv_data_len, "srp_make_enc_keyblock: got initialization vector "); /* SRP "derived session" key */ memcpy(srp_session_key, ptr_expanded_key, srp_session_key_len); ptr_expanded_key += sizeof(srp_session_key); /* HMAC key, remaining 16 bytes */ hmac_key = ptr_expanded_key; srp_print_hex(srp_session_key, srp_session_key_len, "srp_make_enc_keyblock: got derived session key"); /* Build b64 encoded string of SRP session key */ b64_alloc_len = (srp_session_key_len + 2) / 3 * 4 + 1; srp_session_key_str = calloc(b64_alloc_len, sizeof(char)); if (!srp_session_key_str) { krb5_err = ENOMEM; goto error; } krb5_err = sasl_encode64( srp_session_key, srp_session_key_len, srp_session_key_str, b64_alloc_len, &b64_session_key_len); if (krb5_err) { krb5_err = ENOMEM; goto error; } srp_session_key_str[b64_session_key_len] = '\0'; srp_context_handle->keyblock = calloc(1, sizeof(krb5_keyblock)); if (!srp_context_handle->keyblock) { krb5_err = ENOMEM; goto error; } /* Generate encryption key from SRP shared key */ krb5_err = srp_gen_keyblock( srp_context_handle->krb5_ctx, SRP_ENC_KEYTYPE, srp_session_key_str, srp_context_handle->upn_name, srp_context_handle->keyblock); if (krb5_err) { goto error; } srp_print_hex(srp_context_handle->keyblock->contents, srp_context_handle->keyblock->length, "srp_make_enc_keyblock: keyblock value"); memset(srp_context_handle->aes_encrypt_iv, 0, iv_data_len); memcpy(srp_context_handle->aes_encrypt_iv, iv_data, iv_data_len); memset(srp_context_handle->aes_decrypt_iv, 0, iv_data_len); memcpy(srp_context_handle->aes_decrypt_iv, iv_data, iv_data_len); AES_set_encrypt_key( srp_context_handle->keyblock->contents, srp_context_handle->keyblock->length * 8, &srp_context_handle->aes_encrypt_key); AES_set_decrypt_key( srp_context_handle->keyblock->contents, srp_context_handle->keyblock->length * 8, &srp_context_handle->aes_decrypt_key); if (srp_init_hmac(&srp_context_handle->hmac_ctx, hmac_key, SRP_EXPAND_HMAC_KEY)) { krb5_err = ENOMEM; goto error; } error: if (krb5_err) { if (srp_context_handle->keyblock) { free(srp_context_handle->keyblock); } } if (srp_session_key_str) { free(srp_session_key_str); } return krb5_err; }
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; } }
bool _mongoc_cyrus_step (mongoc_cyrus_t *sasl, const uint8_t *inbuf, uint32_t inbuflen, uint8_t *outbuf, uint32_t outbufmax, uint32_t *outbuflen, bson_error_t *error) { const char *raw = NULL; unsigned rawlen = 0; int status; BSON_ASSERT (sasl); BSON_ASSERT (inbuf); BSON_ASSERT (outbuf); BSON_ASSERT (outbuflen); TRACE ("Running %d, inbuflen: %" PRIu32, sasl->step, inbuflen); sasl->step++; if (sasl->step == 1) { return _mongoc_cyrus_start (sasl, outbuf, outbufmax, outbuflen, error); } else if (sasl->step >= 10) { bson_set_error (error, MONGOC_ERROR_SASL, SASL_NOTDONE, "SASL Failure: maximum steps detected"); return false; } TRACE ("Running %d, inbuflen: %" PRIu32, sasl->step, inbuflen); if (!inbuflen) { bson_set_error (error, MONGOC_ERROR_SASL, MONGOC_ERROR_CLIENT_AUTHENTICATE, "SASL Failure: no payload provided from server: %s", sasl_errdetail (sasl->conn)); return false; } status = sasl_decode64 ( (char *) inbuf, inbuflen, (char *) outbuf, outbufmax, outbuflen); if (_mongoc_cyrus_is_failure (status, error)) { return false; } TRACE ("%s", "Running client_step"); status = sasl_client_step ( sasl->conn, (char *) outbuf, *outbuflen, &sasl->interact, &raw, &rawlen); TRACE ("%s sent a client step", status == SASL_OK ? "Successfully" : "UNSUCCESSFULLY"); if (_mongoc_cyrus_is_failure (status, error)) { return false; } status = sasl_encode64 (raw, rawlen, (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 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; }
HIDDEN int ws_start_channel(struct transaction_t *txn, const char *protocol, int (*data_cb)(struct buf *inbuf, struct buf *outbuf, struct buf *logbuf, void **rock)) { int r; const char **hdr, *accept = NULL; wslay_event_context_ptr ev; struct ws_context *ctx; struct wslay_event_callbacks callbacks = { recv_cb, send_cb, NULL, NULL, NULL, NULL, on_msg_recv_cb }; /* Check for supported WebSocket version */ hdr = spool_getheader(txn->req_hdrs, "Sec-WebSocket-Version"); if (!hdr) { txn->error.desc = "Missing WebSocket version"; return HTTP_BAD_REQUEST; } else if (hdr[1]) { txn->error.desc = "Multiple WebSocket versions"; return HTTP_BAD_REQUEST; } else if (strcmp(hdr[0], WS_VERSION)) { txn->error.desc = "Unsupported WebSocket version"; return HTTP_UPGRADE; } if (protocol) { /* Check for supported WebSocket subprotocol */ int i, found = 0; hdr = spool_getheader(txn->req_hdrs, "Sec-WebSocket-Protocol"); if (!hdr) { txn->error.desc = "Missing WebSocket protocol"; return HTTP_BAD_REQUEST; } for (i = 0; !found && hdr[i]; i++) { tok_t tok = TOK_INITIALIZER(hdr[i], ",", TOK_TRIMLEFT|TOK_TRIMRIGHT); char *token; while ((token = tok_next(&tok))) { if (!strcmp(token, protocol)) { found = 1; break; } } tok_fini(&tok); } if (!found) { txn->error.desc = "Unsupported WebSocket protocol"; return HTTP_BAD_REQUEST; } } if (txn->flags.ver == VER_1_1) { unsigned char sha1buf[SHA1_DIGEST_LENGTH]; /* Check for WebSocket client key */ hdr = spool_getheader(txn->req_hdrs, "Sec-WebSocket-Key"); if (!hdr) { txn->error.desc = "Missing WebSocket client key"; return HTTP_BAD_REQUEST; } else if (hdr[1]) { txn->error.desc = "Multiple WebSocket client keys"; return HTTP_BAD_REQUEST; } else if (strlen(hdr[0]) != WS_CKEY_LEN) { txn->error.desc = "Invalid WebSocket client key"; return HTTP_BAD_REQUEST; } /* Create WebSocket accept key */ buf_setcstr(&txn->buf, hdr[0]); buf_appendcstr(&txn->buf, WS_GUID); xsha1((u_char *) buf_base(&txn->buf), buf_len(&txn->buf), sha1buf); buf_ensure(&txn->buf, WS_AKEY_LEN+1); accept = buf_base(&txn->buf); r = sasl_encode64((char *) sha1buf, SHA1_DIGEST_LENGTH, (char *) accept, WS_AKEY_LEN+1, NULL); if (r != SASL_OK) syslog(LOG_WARNING, "sasl_encode64: %d", r); } /* Create server context */ r = wslay_event_context_server_init(&ev, &callbacks, txn); if (r) { syslog(LOG_WARNING, "wslay_event_context_init: %s", wslay_strerror(r)); return HTTP_SERVER_ERROR; } /* Create channel context */ ctx = xzmalloc(sizeof(struct ws_context)); ctx->event = ev; ctx->accept = accept; ctx->protocol = protocol; ctx->data_cb = data_cb; txn->ws_ctx = ctx; /* Check for supported WebSocket extensions */ parse_extensions(txn); /* Prepare log buffer */ /* Add client data */ buf_printf(&ctx->log, "%s", txn->conn->clienthost); if (httpd_userid) buf_printf(&ctx->log, " as \"%s\"", httpd_userid); if ((hdr = spool_getheader(txn->req_hdrs, "User-Agent"))) { buf_printf(&ctx->log, " with \"%s\"", hdr[0]); if ((hdr = spool_getheader(txn->req_hdrs, "X-Client"))) buf_printf(&ctx->log, " by \"%s\"", hdr[0]); else if ((hdr = spool_getheader(txn->req_hdrs, "X-Requested-With"))) buf_printf(&ctx->log, " by \"%s\"", hdr[0]); } /* Add request-line */ buf_printf(&ctx->log, "; \"WebSocket/%s via %s\"", protocol ? protocol : "echo" , txn->req_line.ver); ctx->log_tail = buf_len(&ctx->log); /* Tell client that WebSocket negotiation has succeeded */ if (txn->conn->sess_ctx) { /* Treat WS data as chunked response */ txn->flags.te = TE_CHUNKED; response_header(HTTP_OK, txn); /* Force the response to the client immediately */ prot_flush(httpd_out); } else response_header(HTTP_SWITCH_PROT, txn); /* Set connection as non-blocking */ prot_NONBLOCK(txn->conn->pin); /* Don't do telemetry logging in prot layer */ prot_setlog(txn->conn->pin, PROT_NO_FD); prot_setlog(txn->conn->pout, PROT_NO_FD); return 0; }
int ArgusSendSaslString(FILE *f, const char *s, int l, int mode) { char *buf = NULL, *ptr = NULL, error[128]; unsigned int al, len; int result, size, tsize; switch (mode) { case SASL_OK: { if ((s == NULL) || (l == 0)) { ptr = "D: "; tsize = 3; break; } } case SASL_CONTINUE: { ptr = "S: "; tsize = 3; break; } default: { sprintf (error, "E: [%d]", mode); ptr = error; tsize = strlen(error); break; } } if (ferror(f)) clearerr(f); while ((size = fwrite(ptr, 1, tsize, f)) != tsize) { if (size >= 0) { tsize -= size; ptr += size; } else { if (ferror(f)) ArgusLog (LOG_ERR, "ArgusSendSaslString: error %d", ferror(f)); } } if (l > 0) { al = (((l / 3) + 1) * 4) + 1; if ((buf = malloc(al)) == NULL) ArgusLog (LOG_ERR, "malloc: error %s", strerror(errno)); if ((ptr = buf) != NULL) { result = sasl_encode64(s, l, buf, al, &len); if (result == SASL_OK) { tsize = len; while ((size = fwrite(ptr, 1, tsize, f)) != tsize) { if (size >= 0) { tsize -= size; ptr += size; } else { if (ferror(f)) ArgusLog (LOG_ERR, "ArgusSendSaslString: error %d", ferror(f)); } } } } free(buf); } ptr = "\n"; tsize = 1; while ((size = fwrite(ptr, 1, tsize, f)) != tsize) { if (size >= 0) { tsize -= size; ptr += size; } else { if (ferror(f)) ArgusLog (LOG_ERR, "ArgusSendSaslString: error %d", ferror(f)); } } fflush(f); #ifdef ARGUSDEBUG ArgusDebug (2, "ArgusSendSaslString(0x%x, 0x%x, %d) %s", f, s, l, s); #endif return len; }
/* * mgmt_config_save2scf() saves main configuration to scf * See also : mgmt_get_main_config() */ Boolean_t mgmt_config_save2scf() { targ_scf_t *h = NULL; scf_property_t *prop = NULL; scf_value_t *value = NULL; scf_iter_t *iter = NULL; char pgname[64]; char passcode[32]; unsigned int outlen; tgt_node_t *n = NULL; tgt_node_t *pn = NULL; tgt_node_t *tn = NULL; scf_transaction_t *tx = NULL; secret_list_t *sl_head; secret_list_t *sl_tail; h = mgmt_handle_init(); if (h == NULL) return (False); prop = scf_property_create(h->t_handle); value = scf_value_create(h->t_handle); iter = scf_iter_create(h->t_handle); (void) pthread_mutex_lock(&scf_conf_mutex); if (mgmt_transaction_start(h, "iscsitgt", "basic") == True) { scf_pg_delete(h->t_pg); mgmt_transaction_end(h); } if (mgmt_transaction_start(h, "passwords", "application") == True) { scf_pg_delete(h->t_pg); mgmt_transaction_end(h); } if (scf_iter_service_pgs_typed(iter, h->t_service, "configuration") == -1) { goto error; } tx = scf_transaction_create(h->t_handle); while (scf_iter_next_pg(iter, h->t_pg) > 0) { scf_transaction_start(tx, h->t_pg); scf_pg_delete(h->t_pg); scf_transaction_commit(tx); } scf_transaction_reset(tx); scf_transaction_destroy(tx); sl_head = (secret_list_t *)calloc(1, sizeof (secret_list_t)); sl_tail = sl_head; if (mgmt_transaction_start(h, "iscsitgt", "basic") == True) { for (n = main_config->x_child; n; n = n->x_sibling) { if (strcmp(n->x_name, XML_ELEMENT_CHAPSECRET) == 0) { sl_tail->next = (secret_list_t *) calloc(1, sizeof (secret_list_t)); sl_tail = sl_tail->next; sl_tail->name = strdup("main"); sl_tail->secret = strdup(n->x_value); continue; } /* so does the radius server secret */ if (strcmp(n->x_name, XML_ELEMENT_RAD_SECRET) == 0) { sl_tail->next = (secret_list_t *) calloc(1, sizeof (secret_list_t)); sl_tail = sl_tail->next; sl_tail->name = strdup("radius"); sl_tail->secret = strdup(n->x_value); continue; } if (n->x_child == NULL) { new_property(h, n); } } new_property(h, main_config->x_attr); n = tgt_node_alloc(ISCSI_MODIFY_AUTHNAME, String, ISCSI_AUTH_MODIFY); new_property(h, n); tgt_node_free(n); n = tgt_node_alloc(ISCSI_VALUE_AUTHNAME, String, ISCSI_AUTH_VALUE); new_property(h, n); tgt_node_free(n); mgmt_transaction_end(h); } /* now update target/initiator/tpgt information */ for (n = main_config->x_child; n; n = n->x_sibling) { if (n->x_child == NULL) continue; snprintf(pgname, sizeof (pgname), "%s_%s", n->x_name, n->x_value); if (mgmt_transaction_start(h, pgname, "configuration") == True) { for (pn = n->x_child; pn; pn = pn->x_sibling) { if (strcmp(pn->x_name, XML_ELEMENT_CHAPSECRET) == 0) { sl_tail->next = (secret_list_t *) calloc(1, sizeof (secret_list_t)); sl_tail = sl_tail->next; sl_tail->name = (char *) calloc(1, strlen(n->x_value) + 3); snprintf(sl_tail->name, strlen(n->x_value) + 3, "I_%s", n->x_value); sl_tail->secret = strdup(pn->x_value); continue; } if (pn->x_child == NULL) { /* normal property */ new_property(h, pn); } else { /* pn -> xxx-list */ new_value_list(h, pn); } tn = tgt_node_alloc(ISCSI_MODIFY_AUTHNAME, String, ISCSI_AUTH_MODIFY); new_property(h, tn); tgt_node_free(tn); tn = tgt_node_alloc(ISCSI_VALUE_AUTHNAME, String, ISCSI_AUTH_VALUE); new_property(h, tn); tgt_node_free(tn); } mgmt_transaction_end(h); } } if (mgmt_transaction_start(h, "passwords", "application") == True) { while (sl_head != NULL) { /* Here we use sl_tail as a temporari var */ sl_tail = sl_head->next; if (sl_head->name) { /* max length of encoded passwd is 24B */ sasl_encode64(sl_head->secret, strlen(sl_head->secret), passcode, sizeof (passcode), &outlen); n = tgt_node_alloc(sl_head->name, String, passcode); new_property(h, n); tgt_node_free(n); } if (sl_head->name) free(sl_head->name); if (sl_head->secret) free(sl_head->secret); free(sl_head); sl_head = sl_tail; } n = tgt_node_alloc(ISCSI_READ_AUTHNAME, String, ISCSI_AUTH_READ); new_property(h, n); tgt_node_free(n); n = tgt_node_alloc(ISCSI_VALUE_AUTHNAME, String, ISCSI_AUTH_VALUE); new_property(h, n); tgt_node_free(n); n = tgt_node_alloc(ISCSI_MODIFY_AUTHNAME, String, ISCSI_AUTH_MODIFY); new_property(h, n); tgt_node_free(n); mgmt_transaction_end(h); } if (smf_refresh_instance(SA_TARGET_SVC_INSTANCE_FMRI) != 0) goto error; (void) pthread_mutex_unlock(&scf_conf_mutex); scf_iter_destroy(iter); scf_value_destroy(value); scf_property_destroy(prop); return (True); error: (void) pthread_mutex_unlock(&scf_conf_mutex); scf_iter_destroy(iter); scf_value_destroy(value); scf_property_destroy(prop); mgmt_handle_fini(h); return (False); }
/* 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; }
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 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 }
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; }