void step(const std::string& data) { if (status != STEPPING) { AuthenticationErrorMessage message; message.set_error("Unexpected authentication 'step' received"); send(pid, message); status = ERROR; promise.fail(message.error()); return; } LOG(INFO) << "Received SASL authentication step"; const char* output = NULL; unsigned length = 0; int result = sasl_server_step( connection, data.length() == 0 ? NULL : data.data(), data.length(), &output, &length); handle(result, output, length); }
/* (err, data) = cyrussasl.server_step(conn, data) * * Arguments: * conn: the return result from a previous call to server_new * data: any data that the client might have sent from the previous step. * Note that data may still be an empty string or nil. (Like the * argument of the same name to server_start.) * * Return values: * err: the (integer) SASL error code reflecting the state of the attempt * (e.g. SASL_OK, SASL_CONTINUE, SASL_BADMECH, ...) * data: data that the server wants to send to the client in order * to continue the authN attempt. Returned as a Lua string object. */ static int cyrussasl_sasl_server_step(lua_State *l) { int numargs = lua_gettop(l); int err; struct _sasl_ctx *ctx = NULL; const char *data = NULL; size_t len; unsigned outlen; if (numargs != 2) { lua_pushstring(l, "usage: (err, data) = cyrussasl.server_step(conn, data)"); lua_error(l); return 0; } ctx = get_context(l, 1); data = tolstring(l, 2, &len); err = sasl_server_step( ctx->conn, data, len, &data, &outlen ); /* 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); } return 2; /* returning 2 items on Lua stack */ }
static int pni_wrap_server_step(pni_sasl_t *sasl, const pn_bytes_t *in) { int result; const char *out; unsigned outlen; sasl_conn_t *cyrus_conn = (sasl_conn_t*)sasl->impl_context; result = sasl_server_step(cyrus_conn, in->start, in->size, &out, &outlen); sasl->bytes_out.start = out; sasl->bytes_out.size = outlen; return result; }
int virNetSASLSessionServerStep(virNetSASLSessionPtr sasl, const char *clientin, size_t clientinlen, const char **serverout, size_t *serveroutlen) { unsigned inlen = clientinlen; unsigned outlen = 0; int err; int ret = -1; virObjectLock(sasl); err = sasl_server_step(sasl->conn, clientin, inlen, serverout, &outlen); *serveroutlen = 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; }
uint8_t* TSaslServer::evaluateChallengeOrResponse(const uint8_t* response, const uint32_t len, uint32_t* resLen) { uint8_t* out = NULL; uint32_t outlen = 0; uint32_t result; if (!serverStarted) { result = sasl_server_start(conn, (const char *)response, NULL, 0, (const char **)&out, &outlen); } else { result = sasl_server_step(conn, (const char*)response, len, (const char**)&out, &outlen); } if (result == SASL_OK) { authComplete = true; } else if (result != SASL_CONTINUE) { throw SaslServerImplException(sasl_errdetail(conn)); } serverStarted = true; *resLen = outlen; return out; }
static int __pmAuthServerNegotiation(int fd, int ssf, __pmHashCtl *attrs) { int sts, saslsts; int pinned, length, count; char *payload, *offset; sasl_conn_t *sasl_conn; __pmPDU *pb; if (pmDebugOptions.auth) fprintf(stderr, "__pmAuthServerNegotiation(fd=%d, ssf=%d)\n", fd, ssf); if ((sasl_conn = (sasl_conn_t *)__pmGetUserAuthData(fd)) == NULL) return -EINVAL; /* setup all the security properties for this connection */ if ((sts = __pmAuthServerSetProperties(sasl_conn, ssf)) < 0) return sts; saslsts = sasl_listmech(sasl_conn, NULL, NULL, " ", NULL, (const char **)&payload, (unsigned int *)&length, &count); if (saslsts != SASL_OK && saslsts != SASL_CONTINUE) { pmNotifyErr(LOG_ERR, "Generating client mechanism list: %s", sasl_errstring(saslsts, NULL, NULL)); return __pmSecureSocketsError(saslsts); } if (pmDebugOptions.auth) fprintf(stderr, "__pmAuthServerNegotiation - sending mechanism list " "(%d items, %d bytes): \"%s\"\n", count, length, payload); if ((sts = __pmSendAuth(fd, FROM_ANON, 0, payload, length)) < 0) return sts; if (pmDebugOptions.auth) fprintf(stderr, "__pmAuthServerNegotiation - wait for mechanism\n"); sts = pinned = __pmGetPDU(fd, ANY_SIZE, TIMEOUT_DEFAULT, &pb); if (sts == PDU_AUTH) { sts = __pmDecodeAuth(pb, &count, &payload, &length); if (sts >= 0) { for (count = 0; count < length; count++) { if (payload[count] == '\0') break; } if (count < length) { /* found an initial response */ length = length - count - 1; offset = payload + count + 1; } else { length = 0; offset = NULL; } saslsts = sasl_server_start(sasl_conn, payload, offset, length, (const char **)&payload, (unsigned int *)&length); if (saslsts != SASL_OK && saslsts != SASL_CONTINUE) { sts = __pmSecureSocketsError(saslsts); if (pmDebugOptions.auth) fprintf(stderr, "sasl_server_start failed: %d (%s)\n", saslsts, pmErrStr(sts)); } else { if (pmDebugOptions.auth) fprintf(stderr, "sasl_server_start success: sts=%s\n", saslsts == SASL_CONTINUE ? "continue" : "ok"); } } } else if (sts == PDU_ERROR) __pmDecodeError(pb, &sts); else if (sts != PM_ERR_TIMEOUT) sts = PM_ERR_IPC; if (pinned > 0) __pmUnpinPDUBuf(pb); if (sts < 0) return sts; if (pmDebugOptions.auth) fprintf(stderr, "__pmAuthServerNegotiation method negotiated\n"); while (saslsts == SASL_CONTINUE) { if (!payload) { pmNotifyErr(LOG_ERR, "No SASL data to send"); sts = -EINVAL; break; } if ((sts = __pmSendAuth(fd, FROM_ANON, 0, payload, length)) < 0) break; if (pmDebugOptions.auth) fprintf(stderr, "__pmAuthServerNegotiation awaiting response\n"); sts = pinned = __pmGetPDU(fd, ANY_SIZE, TIMEOUT_DEFAULT, &pb); if (sts == PDU_AUTH) { sts = __pmDecodeAuth(pb, &count, &payload, &length); if (sts >= 0) { sts = saslsts = sasl_server_step(sasl_conn, payload, length, (const char **)&payload, (unsigned int *)&length); if (sts != SASL_OK && sts != SASL_CONTINUE) { sts = __pmSecureSocketsError(sts); break; } if (pmDebugOptions.auth) { fprintf(stderr, "__pmAuthServerNegotiation" " step recv (%d bytes)\n", length); } } } else if (sts == PDU_ERROR) __pmDecodeError(pb, &sts); else if (sts != PM_ERR_TIMEOUT) sts = PM_ERR_IPC; if (pinned > 0) __pmUnpinPDUBuf(pb); if (sts < 0) break; } if (sts < 0) { if (pmDebugOptions.auth) fprintf(stderr, "__pmAuthServerNegotiation loop failed: %d\n", sts); return sts; } return __pmAuthServerSetAttributes(sasl_conn, attrs); }
int auth_cyrus_sasl_server(auth_instance *ablock, uschar *data) { auth_cyrus_sasl_options_block *ob = (auth_cyrus_sasl_options_block *)(ablock->options_block); uschar *output, *out2, *input, *clear, *hname; uschar *debug = NULL; /* Stops compiler complaining */ sasl_callback_t cbs[] = {{SASL_CB_LIST_END, NULL, NULL}}; sasl_conn_t *conn; char * realm_expanded = NULL; int rc, firsttime = 1, clen, *negotiated_ssf_ptr = NULL, negotiated_ssf; unsigned int inlen, outlen; input = data; inlen = Ustrlen(data); HDEBUG(D_auth) debug = string_copy(data); hname = expand_string(ob->server_hostname); if (hname && ob->server_realm) realm_expanded = CS expand_string(ob->server_realm); if (!hname || !realm_expanded && ob->server_realm) { auth_defer_msg = expand_string_message; return DEFER; } if (inlen) { if ((clen = b64decode(input, &clear)) < 0) return BAD64; input = clear; inlen = clen; } if ((rc = sasl_server_init(cbs, "exim")) != SASL_OK) { auth_defer_msg = US"couldn't initialise Cyrus SASL library"; return DEFER; } rc = sasl_server_new(CS ob->server_service, CS hname, realm_expanded, NULL, NULL, NULL, 0, &conn); HDEBUG(D_auth) debug_printf("Initialised Cyrus SASL server connection; service=\"%s\" fqdn=\"%s\" realm=\"%s\"\n", ob->server_service, hname, realm_expanded); if (rc != SASL_OK ) { auth_defer_msg = US"couldn't initialise Cyrus SASL connection"; sasl_done(); return DEFER; } if (tls_in.cipher) { if ((rc = sasl_setprop(conn, SASL_SSF_EXTERNAL, (sasl_ssf_t *) &tls_in.bits)) != SASL_OK) { HDEBUG(D_auth) debug_printf("Cyrus SASL EXTERNAL SSF set %d failed: %s\n", tls_in.bits, sasl_errstring(rc, NULL, NULL)); auth_defer_msg = US"couldn't set Cyrus SASL EXTERNAL SSF"; sasl_done(); return DEFER; } else HDEBUG(D_auth) debug_printf("Cyrus SASL set EXTERNAL SSF to %d\n", tls_in.bits); } else HDEBUG(D_auth) debug_printf("Cyrus SASL: no TLS, no EXTERNAL SSF set\n"); /* So sasl_setprop() documents non-shorted IPv6 addresses which is incredibly annoying; looking at cyrus-imapd-2.3.x source, the IP address is constructed with their iptostring() function, which just wraps getnameinfo(..., NI_NUMERICHOST|NI_NUMERICSERV), which is equivalent to the inet_ntop which we wrap in our host_ntoa() function. So the docs are too strict and we shouldn't worry about :: contractions. */ /* Set properties for remote and local host-ip;port */ for (int i = 0; i < 2; ++i) { struct sockaddr_storage ss; int (*query)(int, struct sockaddr *, socklen_t *); int propnum, port; const uschar *label; uschar *address, *address_port; const char *s_err; socklen_t sslen; if (i) { query = &getpeername; propnum = SASL_IPREMOTEPORT; label = CUS"peer"; } else { query = &getsockname; propnum = SASL_IPLOCALPORT; label = CUS"local"; } sslen = sizeof(ss); if ((rc = query(fileno(smtp_in), (struct sockaddr *) &ss, &sslen)) < 0) { HDEBUG(D_auth) debug_printf("Failed to get %s address information: %s\n", label, strerror(errno)); break; } address = host_ntoa(-1, &ss, NULL, &port); address_port = string_sprintf("%s;%d", address, port); if ((rc = sasl_setprop(conn, propnum, address_port)) != SASL_OK) { s_err = sasl_errdetail(conn); HDEBUG(D_auth) debug_printf("Failed to set %s SASL property: [%d] %s\n", label, rc, s_err ? s_err : "<unknown reason>"); break; } HDEBUG(D_auth) debug_printf("Cyrus SASL set %s hostport to: %s\n", label, address_port); } for (rc = SASL_CONTINUE; rc == SASL_CONTINUE; ) { if (firsttime) { firsttime = 0; HDEBUG(D_auth) debug_printf("Calling sasl_server_start(%s,\"%s\")\n", ob->server_mech, debug); rc = sasl_server_start(conn, CS ob->server_mech, inlen?CS input:NULL, inlen, (const char **)(&output), &outlen); } else { /* make sure that we have a null-terminated string */ out2 = string_copyn(output, outlen); if ((rc = auth_get_data(&input, out2, outlen)) != OK) { /* we couldn't get the data, so free up the library before * returning whatever error we get */ sasl_dispose(&conn); sasl_done(); return rc; } inlen = Ustrlen(input); HDEBUG(D_auth) debug = string_copy(input); if (inlen) { if ((clen = b64decode(input, &clear)) < 0) { sasl_dispose(&conn); sasl_done(); return BAD64; } input = clear; inlen = clen; } HDEBUG(D_auth) debug_printf("Calling sasl_server_step(\"%s\")\n", debug); rc = sasl_server_step(conn, CS input, inlen, (const char **)(&output), &outlen); } if (rc == SASL_BADPROT) { sasl_dispose(&conn); sasl_done(); return UNEXPECTED; } if (rc == SASL_CONTINUE) continue; /* Get the username and copy it into $auth1 and $1. The former is now the preferred variable; the latter is the original variable. */ if ((sasl_getprop(conn, SASL_USERNAME, (const void **)(&out2))) != SASL_OK) { HDEBUG(D_auth) debug_printf("Cyrus SASL library will not tell us the username: %s\n", sasl_errstring(rc, NULL, NULL)); log_write(0, LOG_REJECT, "%s authenticator (%s):\n " "Cyrus SASL username fetch problem: %s", ablock->name, ob->server_mech, sasl_errstring(rc, NULL, NULL)); sasl_dispose(&conn); sasl_done(); return FAIL; } auth_vars[0] = expand_nstring[1] = string_copy(out2); expand_nlength[1] = Ustrlen(out2); expand_nmax = 1; switch (rc) { case SASL_FAIL: case SASL_BUFOVER: case SASL_BADMAC: case SASL_BADAUTH: case SASL_NOAUTHZ: case SASL_ENCRYPT: case SASL_EXPIRED: case SASL_DISABLED: case SASL_NOUSER: /* these are considered permanent failure codes */ HDEBUG(D_auth) debug_printf("Cyrus SASL permanent failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL)); log_write(0, LOG_REJECT, "%s authenticator (%s):\n " "Cyrus SASL permanent failure: %s", ablock->name, ob->server_mech, sasl_errstring(rc, NULL, NULL)); sasl_dispose(&conn); sasl_done(); return FAIL; case SASL_NOMECH: /* this is a temporary failure, because the mechanism is not * available for this user. If it wasn't available at all, we * shouldn't have got here in the first place... */ HDEBUG(D_auth) debug_printf("Cyrus SASL temporary failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL)); auth_defer_msg = string_sprintf("Cyrus SASL: mechanism %s not available", ob->server_mech); sasl_dispose(&conn); sasl_done(); return DEFER; case SASL_OK: HDEBUG(D_auth) debug_printf("Cyrus SASL %s authentication succeeded for %s\n", ob->server_mech, auth_vars[0]); if ((rc = sasl_getprop(conn, SASL_SSF, (const void **)(&negotiated_ssf_ptr)))!= SASL_OK) { HDEBUG(D_auth) debug_printf("Cyrus SASL library will not tell us the SSF: %s\n", sasl_errstring(rc, NULL, NULL)); log_write(0, LOG_REJECT, "%s authenticator (%s):\n " "Cyrus SASL SSF value not available: %s", ablock->name, ob->server_mech, sasl_errstring(rc, NULL, NULL)); sasl_dispose(&conn); sasl_done(); return FAIL; } negotiated_ssf = *negotiated_ssf_ptr; HDEBUG(D_auth) debug_printf("Cyrus SASL %s negotiated SSF: %d\n", ob->server_mech, negotiated_ssf); if (negotiated_ssf > 0) { HDEBUG(D_auth) debug_printf("Exim does not implement SASL wrapping (needed for SSF %d).\n", negotiated_ssf); log_write(0, LOG_REJECT, "%s authenticator (%s):\n " "Cyrus SASL SSF %d not supported by Exim", ablock->name, ob->server_mech, negotiated_ssf); sasl_dispose(&conn); sasl_done(); return FAIL; } /* close down the connection, freeing up library's memory */ sasl_dispose(&conn); sasl_done(); /* Expand server_condition as an authorization check */ return auth_check_serv_cond(ablock); default: /* Anything else is a temporary failure, and we'll let SASL print out * the error string for us */ HDEBUG(D_auth) debug_printf("Cyrus SASL temporary failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL)); auth_defer_msg = string_sprintf("Cyrus SASL: %s", sasl_errstring(rc, NULL, NULL)); sasl_dispose(&conn); sasl_done(); return DEFER; } } /* NOTREACHED */ return 0; /* Stop compiler complaints */ }
/* 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); }
/* do the sasl negotiation; return -1 if it fails */ int mysasl_negotiate(FILE *in, FILE *out, sasl_conn_t *conn) { char buf[8192]; char chosenmech[128]; const char *data; int len; int r = SASL_FAIL; const char *userid; #ifdef HAVE_GSS_GET_NAME_ATTRIBUTE gss_name_t peer = GSS_C_NO_NAME; #endif /* generate the capability list */ if (mech) { dprintf(2, "forcing use of mechanism %s\n", mech); data = strdup(mech); len = strlen(data); } else { int count; dprintf(1, "generating client mechanism list... "); r = sasl_listmech(conn, NULL, NULL, " ", NULL, &data, (unsigned int *)&len, &count); if (r != SASL_OK) saslfail(r, "generating mechanism list"); dprintf(1, "%d mechanisms\n", count); } /* send capability list to client */ send_string(out, data, len); dprintf(1, "waiting for client mechanism...\n"); len = recv_string(in, chosenmech, sizeof chosenmech); if (len <= 0) { printf("client didn't choose mechanism\n"); fputc('N', out); /* send NO to client */ fflush(out); return -1; } if (mech && strcasecmp(mech, chosenmech)) { printf("client didn't choose mandatory mechanism\n"); fputc('N', out); /* send NO to client */ fflush(out); return -1; } len = recv_string(in, buf, sizeof(buf)); if(len != 1) { saslerr(r, "didn't receive first-send parameter correctly"); fprintf(stderr, "%s\n", sasl_errdetail(conn)); fputc('N', out); fflush(out); return -1; } if(buf[0] == 'Y') { /* receive initial response (if any) */ len = recv_string(in, buf, sizeof(buf)); /* start libsasl negotiation */ r = sasl_server_start(conn, chosenmech, buf, len, &data, (unsigned int *)&len); } else { r = sasl_server_start(conn, chosenmech, NULL, 0, &data, (unsigned int *)&len); } if (r != SASL_OK && r != SASL_CONTINUE) { saslerr(r, "starting SASL negotiation"); fprintf(stderr, "%s\n", sasl_errdetail(conn)); fputc('N', out); /* send NO to client */ fflush(out); return -1; } while (r == SASL_CONTINUE) { if (data) { dprintf(2, "sending response length %d...\n", len); fputc('C', out); /* send CONTINUE to client */ send_string(out, data, len); } else { dprintf(2, "sending null response...\n"); fputc('C', out); /* send CONTINUE to client */ send_string(out, "", 0); } dprintf(1, "waiting for client reply...\n"); len = recv_string(in, buf, sizeof buf); if (len < 0) { printf("client disconnected\n"); return -1; } r = sasl_server_step(conn, buf, len, &data, (unsigned int *)&len); if (r != SASL_OK && r != SASL_CONTINUE) { saslerr(r, "performing SASL negotiation"); fprintf(stderr, "%s\n", sasl_errdetail(conn)); fputc('N', out); /* send NO to client */ fflush(out); return -1; } } if (r != SASL_OK) { saslerr(r, "incorrect authentication"); fprintf(stderr, "%s\n", sasl_errdetail(conn)); fputc('N', out); /* send NO to client */ fflush(out); return -1; } fputc('O', out); /* send OK to client */ fflush(out); dprintf(1, "negotiation complete\n"); r = sasl_getprop(conn, SASL_USERNAME, (const void **) &userid); printf("successful authentication '%s'\n", userid); #ifdef HAVE_GSS_GET_NAME_ATTRIBUTE r = sasl_getprop(conn, SASL_GSS_PEER_NAME, (const void **) &peer); if (peer != GSS_C_NO_NAME) { OM_uint32 minor; enumerateAttributes(&minor, peer, 1); } #endif return 0; }
static svn_error_t *try_auth(svn_ra_svn_conn_t *conn, sasl_conn_t *sasl_ctx, apr_pool_t *pool, server_baton_t *b, svn_boolean_t *success) { const char *out, *mech; const svn_string_t *arg = NULL, *in; unsigned int outlen; int result; svn_boolean_t use_base64; *success = FALSE; /* Read the client's chosen mech and the initial token. */ SVN_ERR(svn_ra_svn_read_tuple(conn, pool, "w(?s)", &mech, &in)); if (strcmp(mech, "EXTERNAL") == 0 && !in) in = svn_string_create(b->tunnel_user, pool); else if (in) in = svn_base64_decode_string(in, pool); /* For CRAM-MD5, we don't base64-encode stuff. */ use_base64 = (strcmp(mech, "CRAM-MD5") != 0); result = sasl_server_start(sasl_ctx, mech, in ? in->data : NULL, in ? in->len : 0, &out, &outlen); if (result != SASL_OK && result != SASL_CONTINUE) return fail_auth(conn, pool, sasl_ctx); while (result == SASL_CONTINUE) { svn_ra_svn_item_t *item; arg = svn_string_ncreate(out, outlen, pool); /* Encode what we send to the client. */ if (use_base64) arg = svn_base64_encode_string2(arg, TRUE, pool); SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "w(s)", "step", arg)); /* Read and decode the client response. */ SVN_ERR(svn_ra_svn_read_item(conn, pool, &item)); if (item->kind != SVN_RA_SVN_STRING) return SVN_NO_ERROR; in = item->u.string; if (use_base64) in = svn_base64_decode_string(in, pool); result = sasl_server_step(sasl_ctx, in->data, in->len, &out, &outlen); } if (result != SASL_OK) return fail_auth(conn, pool, sasl_ctx); /* Send our last response, if necessary. */ if (outlen) arg = svn_base64_encode_string2(svn_string_ncreate(out, outlen, pool), TRUE, pool); else arg = NULL; *success = TRUE; SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "w(?s)", "success", arg)); return SVN_NO_ERROR; }
RedsSaslError reds_sasl_handle_auth_step(RedsStream *stream, AsyncReadDone read_cb, void *opaque) { const char *serverout; unsigned int serveroutlen; int err; char *clientdata = NULL; RedsSASL *sasl = &stream->priv->sasl; uint32_t datalen = sasl->len; /* NB, distinction of NULL vs "" is *critical* in SASL */ if (datalen) { clientdata = sasl->data; clientdata[datalen - 1] = '\0'; /* Wire includes '\0', but make sure */ datalen--; /* Don't count NULL byte when passing to _start() */ } spice_debug("Step using SASL Data %p (%d bytes)", clientdata, datalen); err = sasl_server_step(sasl->conn, clientdata, datalen, &serverout, &serveroutlen); if (err != SASL_OK && err != SASL_CONTINUE) { spice_warning("sasl step failed %d (%s)", err, sasl_errdetail(sasl->conn)); return REDS_SASL_ERROR_GENERIC; } if (serveroutlen > SASL_DATA_MAX_LEN) { spice_warning("sasl step reply data too long %d", serveroutlen); return REDS_SASL_ERROR_INVALID_DATA; } spice_debug("SASL return data %d bytes, %p", serveroutlen, serverout); if (serveroutlen) { serveroutlen += 1; reds_stream_write_all(stream, &serveroutlen, sizeof(uint32_t)); reds_stream_write_all(stream, serverout, serveroutlen); } else { reds_stream_write_all(stream, &serveroutlen, sizeof(uint32_t)); } /* Whether auth is complete */ reds_stream_write_u8(stream, err == SASL_CONTINUE ? 0 : 1); if (err == SASL_CONTINUE) { spice_debug("%s", "Authentication must continue (step)"); /* Wait for step length */ reds_stream_async_read(stream, (uint8_t *)&sasl->len, sizeof(uint32_t), read_cb, opaque); return REDS_SASL_ERROR_CONTINUE; } else { int ssf; if (auth_sasl_check_ssf(sasl, &ssf) == 0) { spice_warning("Authentication rejected for weak SSF"); goto authreject; } spice_debug("Authentication successful"); reds_stream_write_u32(stream, SPICE_LINK_ERR_OK); /* Accept auth */ /* * Delay writing in SSF encoded until now */ sasl->runSSF = ssf; reds_stream_disable_writev(stream); /* make sure writev isn't called directly anymore */ return REDS_SASL_ERROR_OK; } authreject: reds_stream_write_u32(stream, 1); /* Reject auth */ reds_stream_write_u32(stream, sizeof("Authentication failed")); reds_stream_write_all(stream, "Authentication failed", sizeof("Authentication failed")); return REDS_SASL_ERROR_AUTH_FAILED; }
int serverTryAgain() { if(step == 0) { if(!ca_skip) { const char *clientin = 0; unsigned int clientinlen = 0; if(in_useClientInit) { clientin = in_clientInit.data(); clientinlen = in_clientInit.size(); } const char *serverout; unsigned int serveroutlen; ca_flag = false; int r = sasl_server_start(con, in_mech.toLatin1().data(), clientin, clientinlen, &serverout, &serveroutlen); if(r != SASL_OK && r != SASL_CONTINUE) { err = saslErrorCond(r); return Error; } out_buf = makeByteArray(serverout, serveroutlen); last_r = r; if(ca_flag && !ca_done) { ca_done = true; ca_skip = true; return AuthCheck; } } ca_skip = false; ++step; if(last_r == SASL_OK) { getssfparams(); return Success; } return Continue; } else { if(!ca_skip) { const char *serverout; unsigned int serveroutlen; int r = sasl_server_step(con, in_buf.data(), in_buf.size(), &serverout, &serveroutlen); if(r != SASL_OK && r != SASL_CONTINUE) { err = saslErrorCond(r); return Error; } if(r == SASL_OK) out_buf.resize(0); else out_buf = makeByteArray(serverout, serveroutlen); last_r = r; if(ca_flag && !ca_done) { ca_done = true; ca_skip = true; return AuthCheck; } } ca_skip = false; if(last_r == SASL_OK) { getssfparams(); return Success; } return Continue; } }
int auth_cyrus_sasl_server(auth_instance *ablock, uschar *data) { auth_cyrus_sasl_options_block *ob = (auth_cyrus_sasl_options_block *)(ablock->options_block); uschar *output, *out2, *input, *clear, *hname; uschar *debug = NULL; /* Stops compiler complaining */ sasl_callback_t cbs[]={{SASL_CB_LIST_END, NULL, NULL}}; sasl_conn_t *conn; int rc, firsttime=1, clen; unsigned int inlen, outlen; input=data; inlen=Ustrlen(data); HDEBUG(D_auth) debug=string_copy(data); hname=expand_string(ob->server_hostname); if(hname == NULL) { auth_defer_msg = expand_string_message; return DEFER; } if(inlen) { clen=auth_b64decode(input, &clear); if(clen < 0) { return BAD64; } input=clear; inlen=clen; } rc=sasl_server_init(cbs, "exim"); if (rc != SASL_OK) { auth_defer_msg = US"couldn't initialise Cyrus SASL library"; return DEFER; } rc=sasl_server_new(CS ob->server_service, CS hname, CS ob->server_realm, NULL, NULL, NULL, 0, &conn); if( rc != SASL_OK ) { auth_defer_msg = US"couldn't initialise Cyrus SASL connection"; sasl_done(); return DEFER; } rc=SASL_CONTINUE; while(rc==SASL_CONTINUE) { if(firsttime) { firsttime=0; HDEBUG(D_auth) debug_printf("Calling sasl_server_start(%s,\"%s\")\n", ob->server_mech, debug); rc=sasl_server_start(conn, CS ob->server_mech, inlen?CS input:NULL, inlen, (const char **)(&output), &outlen); } else { /* make sure that we have a null-terminated string */ out2=store_get(outlen+1); memcpy(out2,output,outlen); out2[outlen]='\0'; if((rc=auth_get_data(&input, out2, outlen))!=OK) { /* we couldn't get the data, so free up the library before * returning whatever error we get */ sasl_dispose(&conn); sasl_done(); return rc; } inlen=Ustrlen(input); HDEBUG(D_auth) debug=string_copy(input); if(inlen) { clen=auth_b64decode(input, &clear); if(clen < 0) { sasl_dispose(&conn); sasl_done(); return BAD64; } input=clear; inlen=clen; } HDEBUG(D_auth) debug_printf("Calling sasl_server_step(\"%s\")\n", debug); rc=sasl_server_step(conn, CS input, inlen, (const char **)(&output), &outlen); } if(rc==SASL_BADPROT) { sasl_dispose(&conn); sasl_done(); return UNEXPECTED; } else if( rc==SASL_FAIL || rc==SASL_BUFOVER || rc==SASL_BADMAC || rc==SASL_BADAUTH || rc==SASL_NOAUTHZ || rc==SASL_ENCRYPT || rc==SASL_EXPIRED || rc==SASL_DISABLED || rc==SASL_NOUSER ) { /* these are considered permanent failure codes */ HDEBUG(D_auth) debug_printf("Cyrus SASL permanent failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL)); log_write(0, LOG_REJECT, "%s authenticator (%s):\n " "Cyrus SASL permanent failure: %s", ablock->name, ob->server_mech, sasl_errstring(rc, NULL, NULL)); sasl_dispose(&conn); sasl_done(); return FAIL; } else if(rc==SASL_NOMECH) { /* this is a temporary failure, because the mechanism is not * available for this user. If it wasn't available at all, we * shouldn't have got here in the first place... */ HDEBUG(D_auth) debug_printf("Cyrus SASL temporary failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL)); auth_defer_msg = string_sprintf("Cyrus SASL: mechanism %s not available", ob->server_mech); sasl_dispose(&conn); sasl_done(); return DEFER; } else if(!(rc==SASL_OK || rc==SASL_CONTINUE)) { /* Anything else is a temporary failure, and we'll let SASL print out * the error string for us */ HDEBUG(D_auth) debug_printf("Cyrus SASL temporary failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL)); auth_defer_msg = string_sprintf("Cyrus SASL: %s", sasl_errstring(rc, NULL, NULL)); sasl_dispose(&conn); sasl_done(); return DEFER; } else if(rc==SASL_OK) { /* Get the username and copy it into $auth1 and $1. The former is now the preferred variable; the latter is the original variable. */ rc = sasl_getprop(conn, SASL_USERNAME, (const void **)(&out2)); auth_vars[0] = expand_nstring[1] = string_copy(out2); expand_nlength[1] = Ustrlen(expand_nstring[1]); expand_nmax = 1; HDEBUG(D_auth) debug_printf("Cyrus SASL %s authentication succeeded for %s\n", ob->server_mech, out2); /* close down the connection, freeing up library's memory */ sasl_dispose(&conn); sasl_done(); /* Expand server_condition as an authorization check */ return auth_check_serv_cond(ablock); } } /* NOTREACHED */ return 0; /* Stop compiler complaints */ }
int ArgusAuthenticateClient (struct ArgusClientData *client) { int retn = 1; #ifdef ARGUS_SASL unsigned int rlen = 0; int len, mechnum = 0; char buf[8192], chosenmech[512]; const char *data; sasl_conn_t *conn = NULL; // int SASLOpts = (SASL_SEC_NOPLAINTEXT | SASL_SEC_NOANONYMOUS); FILE *in, *out; conn = client->sasl_conn; if ((retn = sasl_listmech(conn, NULL, "{", ", ", "}", &data, &rlen, &mechnum)) != SASL_OK) ArgusLog (LOG_ERR, "ArgusAuthenticateClient: Error generating mechanism list"); if ((in = fdopen (client->fd, "r")) < 0) ArgusLog (LOG_ERR, "ArgusAuthenticateClient: fdopen() error %s", strerror(errno)); if ((out = fdopen (client->fd, "w")) < 0) ArgusLog (LOG_ERR, "ArgusAuthenticateClient: fdopen() error %s", strerror(errno)); ArgusSendSaslString (out, data, rlen, SASL_OK); if ((len = ArgusGetSaslString (in, chosenmech, sizeof(chosenmech))) <= 0) { #ifdef ARGUSDEBUG ArgusDebug (2, "ArgusAuthenticateClient: Error ArgusGetSaslString returned %d\n", len); #endif return 0; } if ((len = ArgusGetSaslString (in, buf, sizeof(buf))) <= 0) { #ifdef ARGUSDEBUG ArgusDebug (2, "ArgusAuthenticateClient: Error ArgusGetSaslString returned %d\n", len); #endif return 0; } if (*buf == 'Y') { if ((len = ArgusGetSaslString (in, buf, sizeof(buf))) <= 0) { #ifdef ARGUSDEBUG ArgusDebug (2, "ArgusAuthenticateClient: Error ArgusGetSaslString returned %d\n", len); #endif return 0; } retn = sasl_server_start(conn, chosenmech, buf, len, &data, &rlen); } else { retn = sasl_server_start(conn, chosenmech, NULL, 0, &data, &rlen); } if ((retn != SASL_OK) && (retn != SASL_CONTINUE)) { sprintf (buf, "%s", sasl_errstring(retn, NULL, NULL)); #ifdef ARGUSDEBUG ArgusDebug (2, "ArgusAuthenticateClient: Error starting SASL negotiation"); #endif ArgusSendSaslString(out, buf, strlen(buf), retn); return 0; } while (retn == SASL_CONTINUE) { if (data) { #ifdef ARGUSDEBUG ArgusDebug(2, "sending response length %d...\n", rlen); #endif ArgusSendSaslString(out, data, rlen, retn); } else { #ifdef ARGUSDEBUG ArgusDebug(2, "no data to send? ...\n"); #endif } #ifdef ARGUSDEBUG ArgusDebug(2, "waiting for client reply...\n"); #endif len = ArgusGetSaslString(in, buf, sizeof(buf)); if (len < 0) { #ifdef ARGUSDEBUG ArgusDebug(2, "client disconnected ...\n"); #endif return 0; } retn = sasl_server_step(conn, buf, len, &data, &rlen); if ((retn != SASL_OK) && (retn != SASL_CONTINUE)) { sprintf (buf, "%s", sasl_errstring(retn, NULL, NULL)); #ifdef ARGUSDEBUG ArgusDebug(2, "Authentication failed %s\n", sasl_errstring(retn, NULL, NULL)); #endif ArgusSendSaslString(out, buf, strlen(buf), retn); return 0; } } if (retn == SASL_OK) ArgusSendSaslString(out, NULL, 0, SASL_OK); #endif #ifdef ARGUSDEBUG ArgusDebug (1, "ArgusAuthenticateClient() returning %d\n", retn); #endif return (retn); }
static int protocol_client_auth_sasl_step(VncState *vs, uint8_t *data, size_t len) { uint32_t datalen = len; const char *serverout; unsigned int serveroutlen; int err; char *clientdata = NULL; /* NB, distinction of NULL vs "" is *critical* in SASL */ if (datalen) { clientdata = (char*)data; clientdata[datalen-1] = '\0'; /* Wire includes '\0', but make sure */ datalen--; /* Don't count NULL byte when passing to _start() */ } VNC_DEBUG("Step using SASL Data %p (%d bytes)\n", clientdata, datalen); err = sasl_server_step(vs->sasl.conn, clientdata, datalen, &serverout, &serveroutlen); if (err != SASL_OK && err != SASL_CONTINUE) { VNC_DEBUG("sasl step failed %d (%s)\n", err, sasl_errdetail(vs->sasl.conn)); sasl_dispose(&vs->sasl.conn); vs->sasl.conn = NULL; goto authabort; } if (serveroutlen > SASL_DATA_MAX_LEN) { VNC_DEBUG("sasl step reply data too long %d\n", serveroutlen); sasl_dispose(&vs->sasl.conn); vs->sasl.conn = NULL; goto authabort; } VNC_DEBUG("SASL return data %d bytes, nil; %d\n", serveroutlen, serverout ? 0 : 1); if (serveroutlen) { vnc_write_u32(vs, serveroutlen + 1); vnc_write(vs, serverout, serveroutlen + 1); } else { vnc_write_u32(vs, 0); } /* Whether auth is complete */ vnc_write_u8(vs, err == SASL_CONTINUE ? 0 : 1); if (err == SASL_CONTINUE) { VNC_DEBUG("%s", "Authentication must continue\n"); /* Wait for step length */ vnc_read_when(vs, protocol_client_auth_sasl_step_len, 4); } else { if (!vnc_auth_sasl_check_ssf(vs)) { VNC_DEBUG("Authentication rejected for weak SSF %p\n", vs->ioc); goto authreject; } /* Check username whitelist ACL */ if (vnc_auth_sasl_check_access(vs) < 0) { VNC_DEBUG("Authentication rejected for ACL %p\n", vs->ioc); goto authreject; } VNC_DEBUG("Authentication successful %p\n", vs->ioc); vnc_write_u32(vs, 0); /* Accept auth */ /* * Delay writing in SSF encoded mode until pending output * buffer is written */ if (vs->sasl.runSSF) vs->sasl.waitWriteSSF = vs->output.offset; start_client_init(vs); } return 0; authreject: vnc_write_u32(vs, 1); /* Reject auth */ vnc_write_u32(vs, sizeof("Authentication failed")); vnc_write(vs, "Authentication failed", sizeof("Authentication failed")); vnc_flush(vs); vnc_client_error(vs); return -1; authabort: vnc_client_error(vs); return -1; }
/* * Continue next SASL negotiation with client. */ DWORD VmDirSASLSessionStep( PVDIR_SASL_BIND_INFO pSaslBindInfo, PVDIR_BIND_REQ pBindReq, PVDIR_BERVALUE pBervSaslReply, PVDIR_LDAP_RESULT pResult ) { DWORD dwError = 0; PVOID pOutBlob = NULL; unsigned iRespLen = 0; PCSTR pszRespBlob = NULL; dwError = sasl_server_step( pSaslBindInfo->pSaslCtx, pBindReq->cred.lberbv.bv_val, (unsigned) pBindReq->cred.lberbv.bv_len, &pszRespBlob, &iRespLen); if (dwError == SASL_OK) { dwError = _VmDirSASLGetCtxProps(pSaslBindInfo); BAIL_ON_VMDIR_ERROR(dwError); dwError = LDAP_SUCCESS; pSaslBindInfo->saslStatus = SASL_STATUS_DONE; } else if (dwError == SASL_CONTINUE) { pSaslBindInfo->saslStatus = SASL_STATUS_IN_PROGRESS; if (iRespLen > 0) { dwError = VmDirAllocateAndCopyMemory((PVOID)pszRespBlob, iRespLen, &pOutBlob); BAIL_ON_VMDIR_ERROR(dwError); pBervSaslReply->lberbv.bv_val = pOutBlob; pBervSaslReply->lberbv.bv_len = iRespLen; pBervSaslReply->bOwnBvVal = TRUE; } else { pBervSaslReply->lberbv.bv_len = 0; pBervSaslReply->lberbv.bv_val = ""; pBervSaslReply->bOwnBvVal = FALSE; } dwError = LDAP_SUCCESS; pResult->errCode = LDAP_SASL_BIND_IN_PROGRESS; pResult->replyInfo.type = REP_SASL; } else { BAIL_ON_SASL_ERROR(dwError); } cleanup: return dwError; error: VMDIR_SAFE_FREE_MEMORY(pOutBlob); pBervSaslReply->lberbv.bv_val = NULL; pBervSaslReply->lberbv.bv_len = 0; pBervSaslReply->bOwnBvVal = FALSE; goto cleanup; sasl_error: VMDIR_LOG_ERROR( VMDIR_LOG_MASK_ALL, "SASLSessionStep: sasl error (%d)(%s)", dwError, VDIR_SAFE_STRING(sasl_errdetail(pSaslBindInfo->pSaslCtx)) ); dwError = _VmDirSASLToLDAPError(dwError); if (dwError == LDAP_INVALID_CREDENTIALS ) { _VmDirSASLGetCtxProps(pSaslBindInfo); // ignore error } goto error; }