#include "includes.h"
-NTSTATUS ldapsrv_BindRequest(struct ldapsrv_call *call)
+static NTSTATUS ldapsrv_BindSimple(struct ldapsrv_call *call)
{
struct ldap_BindRequest *req = &call->request.r.BindRequest;
struct ldapsrv_reply *reply;
struct ldap_BindResponse *resp;
- DEBUG(10, ("BindRequest dn: %s\n",req->dn));
+ DEBUG(10, ("BindSimple dn: %s\n",req->dn));
reply = ldapsrv_init_reply(call, LDAP_TAG_BindResponse);
if (!reply) {
return ldapsrv_queue_reply(call, reply);
}
+static NTSTATUS ldapsrv_BindSASL(struct ldapsrv_call *call)
+{
+ struct ldap_BindRequest *req = &call->request.r.BindRequest;
+ struct ldapsrv_reply *reply;
+ struct ldap_BindResponse *resp;
+ int result;
+ const char *errstr;
+ NTSTATUS status = NT_STATUS_OK;
+ NTSTATUS sasl_status;
+ BOOL ret;
+
+ DEBUG(10, ("BindSASL dn: %s\n",req->dn));
+
+ if (!call->conn->gensec) {
+ call->conn->session_info = NULL;
+
+ status = gensec_server_start(call->conn, &call->conn->gensec);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status)));
+ return status;
+ }
+
+ gensec_want_feature(call->conn->gensec, GENSEC_WANT_SIGN|GENSEC_WANT_SEAL);
+
+ status = gensec_start_mech_by_sasl_name(call->conn->gensec, req->creds.SASL.mechanism);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to start GENSEC SASL[%s] server code: %s\n",
+ req->creds.SASL.mechanism, nt_errstr(status)));
+ goto reply;
+ }
+ }
+
+reply:
+ reply = ldapsrv_init_reply(call, LDAP_TAG_BindResponse);
+ if (!reply) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ resp = &reply->msg.r.BindResponse;
+
+ if (NT_STATUS_IS_OK(status)) {
+ status = gensec_update(call->conn->gensec, reply,
+ req->creds.SASL.secblob, &resp->SASL.secblob);
+ }
+
+ if (NT_STATUS_EQUAL(NT_STATUS_MORE_PROCESSING_REQUIRED, status)) {
+ result = LDAP_SASL_BIND_IN_PROGRESS;
+ errstr = NULL;
+ } else if (NT_STATUS_IS_OK(status)) {
+ result = LDAP_SUCCESS;
+ errstr = NULL;
+ } else {
+ result = 49;
+ errstr = talloc_asprintf(reply, "SASL:[%s]: %s", req->creds.SASL.mechanism, nt_errstr(status));
+ }
+
+ resp->response.resultcode = result;
+ resp->response.dn = NULL;
+ resp->response.errormessage = errstr;
+ resp->response.referral = NULL;
+
+ sasl_status = status;
+ status = ldapsrv_queue_reply(call, reply);
+ if (!NT_STATUS_IS_OK(sasl_status) || !NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = ldapsrv_do_responses(call->conn);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ ret = ldapsrv_append_to_buf(&call->conn->sasl_out_buffer, call->conn->out_buffer.data, call->conn->out_buffer.length);
+ if (!ret) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ ldapsrv_consumed_from_buf(&call->conn->out_buffer, call->conn->out_buffer.length);
+
+ status = gensec_session_info(call->conn->gensec, &call->conn->session_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ //debug_session_info(0, 0, call->conn->session_info);
+
+ return status;
+}
+
+NTSTATUS ldapsrv_BindRequest(struct ldapsrv_call *call)
+{
+ struct ldap_BindRequest *req = &call->request.r.BindRequest;
+ struct ldapsrv_reply *reply;
+ struct ldap_BindResponse *resp;
+
+ switch (req->mechanism) {
+ case LDAP_AUTH_MECH_SIMPLE:
+ return ldapsrv_BindSimple(call);
+ case LDAP_AUTH_MECH_SASL:
+ return ldapsrv_BindSASL(call);
+ }
+
+ reply = ldapsrv_init_reply(call, LDAP_TAG_BindResponse);
+ if (!reply) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ resp = &reply->msg.r.BindResponse;
+ resp->response.resultcode = 7;
+ resp->response.dn = NULL;
+ resp->response.errormessage = talloc_asprintf(reply, "Bad AuthenticationChoice [%d]", req->mechanism);
+ resp->response.referral = NULL;
+ resp->SASL.secblob = data_blob(NULL, 0);
+
+ return ldapsrv_queue_reply(call, reply);
+}
+
NTSTATUS ldapsrv_UnbindRequest(struct ldapsrv_call *call)
{
-/* struct ldap_UnbindRequest *req = &call->request->r.UnbindRequest;*/
DEBUG(10, ("UnbindRequest\n"));
return NT_STATUS_OK;
}
that a read(2) holds a complete request that is then thrown away
completely. */
-static void consumed_from_buf(struct rw_buffer *buf,
+void ldapsrv_consumed_from_buf(struct rw_buffer *buf,
size_t length)
{
memcpy(buf->data, buf->data+length, buf->length-length);
*out_length = buf->length;
}
-static BOOL append_to_buf(struct rw_buffer *buf, uint8_t *data, size_t length)
+BOOL ldapsrv_append_to_buf(struct rw_buffer *buf, uint8_t *data, size_t length)
{
buf->data = realloc(buf->data, buf->length+length);
return False;
}
- ret = append_to_buf(buf, tmp_blob.data, tmp_blob.length);
+ ret = ldapsrv_append_to_buf(buf, tmp_blob.data, tmp_blob.length);
talloc_free(tmp_blob.data);
struct socket_context *sock = conn->connection->socket;
TALLOC_CTX *mem_ctx;
- if (!conn->gensec ||
+ if (!conn->gensec || !conn->session_info ||
!(gensec_have_feature(conn->gensec, GENSEC_WANT_SIGN) &&
gensec_have_feature(conn->gensec, GENSEC_WANT_SEAL))) {
return read_into_buf(sock, &conn->in_buffer);
return False;
}
- ret = append_to_buf(&conn->sasl_in_buffer, tmp_blob.data, tmp_blob.length);
+ ret = ldapsrv_append_to_buf(&conn->sasl_in_buffer, tmp_blob.data, tmp_blob.length);
if (!ret) {
talloc_free(mem_ctx);
return False;
}
}
- ret = append_to_buf(&conn->in_buffer, tmp_blob.data, tmp_blob.length);
+ ret = ldapsrv_append_to_buf(&conn->in_buffer, tmp_blob.data, tmp_blob.length);
if (!ret) {
talloc_free(mem_ctx);
return False;
}
- consumed_from_buf(&conn->sasl_in_buffer, 4 + sasl_length);
+ ldapsrv_consumed_from_buf(&conn->sasl_in_buffer, 4 + sasl_length);
talloc_free(mem_ctx);
return ret;
return False;
}
- consumed_from_buf(buf, sendlen);
+ ldapsrv_consumed_from_buf(buf, sendlen);
return True;
}
struct socket_context *sock = conn->connection->socket;
TALLOC_CTX *mem_ctx;
- if (!conn->gensec ||
+ if (!conn->gensec || !conn->session_info ||
!(gensec_have_feature(conn->gensec, GENSEC_WANT_SIGN) &&
gensec_have_feature(conn->gensec, GENSEC_WANT_SEAL))) {
return write_from_buf(sock, &conn->out_buffer);
tmp_blob.data = conn->out_buffer.data;
tmp_blob.length = conn->out_buffer.length;
+ if (tmp_blob.length == 0) {
+ goto nodata;
+ }
+
if (gensec_have_feature(conn->gensec, GENSEC_WANT_SEAL)) {
status = gensec_seal_packet(conn->gensec, mem_ctx,
tmp_blob.data, tmp_blob.length,
memcpy(sasl.data + 4, creds.data, creds.length);
memcpy(sasl.data + 4 + creds.length, tmp_blob.data, tmp_blob.length);
- ret = append_to_buf(&conn->sasl_out_buffer, sasl.data, sasl.length);
+ ret = ldapsrv_append_to_buf(&conn->sasl_out_buffer, sasl.data, sasl.length);
if (!ret) {
talloc_free(mem_ctx);
return False;
}
- consumed_from_buf(&conn->out_buffer, tmp_blob.length);
+ ldapsrv_consumed_from_buf(&conn->out_buffer, tmp_blob.length);
+nodata:
+ tmp_blob.data = conn->sasl_out_buffer.data;
+ tmp_blob.length = conn->sasl_out_buffer.length;
status = socket_send(sock, mem_ctx, &tmp_blob, &sendlen, 0);
if (!NT_STATUS_IS_OK(status)) {
return False;
}
- consumed_from_buf(&conn->sasl_out_buffer, sendlen);
+ ldapsrv_consumed_from_buf(&conn->sasl_out_buffer, sendlen);
talloc_free(mem_ctx);
return True;
}
-static BOOL ldap_append_to_buf(struct ldap_message *msg, struct rw_buffer *buf)
+static BOOL ldap_encode_to_buf(struct ldap_message *msg, struct rw_buffer *buf)
{
DATA_BLOB blob;
BOOL res;
if (!ldap_encode(msg, &blob))
return False;
- res = append_to_buf(buf, blob.data, blob.length);
+ res = ldapsrv_append_to_buf(buf, blob.data, blob.length);
data_blob_free(&blob);
return res;
}
-static NTSTATUS ldapsrv_do_responses(struct ldapsrv_connection *conn)
+NTSTATUS ldapsrv_do_responses(struct ldapsrv_connection *conn)
{
struct ldapsrv_call *call, *next_call = NULL;
struct ldapsrv_reply *reply, *next_reply = NULL;
for (call=conn->calls; call; call=next_call) {
for (reply=call->replies; reply; reply=next_reply) {
- if (!ldap_append_to_buf(&reply->msg, &conn->out_buffer)) {
+ if (!ldap_encode_to_buf(&reply->msg, &conn->out_buffer)) {
return NT_STATUS_FOOBAR;
}
next_reply = reply->next;
return NT_STATUS_OK;
}
+NTSTATUS ldapsrv_flush_responses(struct ldapsrv_connection *conn)
+{
+ return NT_STATUS_OK;
+}
+
/*
called when a LDAP socket becomes readable
*/
ZERO_STRUCTP(call);
call->state = LDAPSRV_CALL_STATE_NEW;
call->conn = ldap_conn;
- /* TODO: we should use talloc_reference() here */
- call->session_info = ldap_conn->session_info;
call->request.mem_ctx = call;
if (!ldap_decode(&data, &call->request)) {
DLIST_ADD_END(ldap_conn->calls, call,
struct ldapsrv_call *);
- consumed_from_buf(&ldap_conn->in_buffer, msg_length);
+ ldapsrv_consumed_from_buf(&ldap_conn->in_buffer, msg_length);
status = ldapsrv_do_call(call);
if (!NT_STATUS_IS_OK(status)) {