Remove the tortured logic in another_ldap_try() and turn it into
[Samba/gebeck_regimport.git] / source4 / ldap_server / ldap_extended.c
blob5cfa2d3b16fa68269d15ad0232897c820bc3bfb2
1 /*
2 Unix SMB/CIFS implementation.
3 LDAP server
4 Copyright (C) Stefan Metzmacher 2004
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "ldap_server/ldap_server.h"
22 #include "../lib/util/dlinklist.h"
23 #include "lib/tls/tls.h"
24 #include "smbd/service_stream.h"
25 #include "../lib/util/tevent_ntstatus.h"
27 struct ldapsrv_starttls_postprocess_context {
28 struct ldapsrv_connection *conn;
31 struct ldapsrv_starttls_postprocess_state {
32 struct ldapsrv_connection *conn;
35 static void ldapsrv_starttls_postprocess_done(struct tevent_req *subreq);
37 static struct tevent_req *ldapsrv_starttls_postprocess_send(TALLOC_CTX *mem_ctx,
38 struct tevent_context *ev,
39 void *private_data)
41 struct ldapsrv_starttls_postprocess_context *context =
42 talloc_get_type_abort(private_data,
43 struct ldapsrv_starttls_postprocess_context);
44 struct ldapsrv_connection *conn = context->conn;
45 struct tevent_req *req;
46 struct ldapsrv_starttls_postprocess_state *state;
47 struct tevent_req *subreq;
49 req = tevent_req_create(mem_ctx, &state,
50 struct ldapsrv_starttls_postprocess_state);
51 if (req == NULL) {
52 return NULL;
55 state->conn = conn;
57 subreq = tstream_tls_accept_send(conn,
58 conn->connection->event.ctx,
59 conn->sockets.raw,
60 conn->service->tls_params);
61 if (tevent_req_nomem(subreq, req)) {
62 return tevent_req_post(req, ev);
64 tevent_req_set_callback(subreq, ldapsrv_starttls_postprocess_done, req);
66 return req;
69 static void ldapsrv_starttls_postprocess_done(struct tevent_req *subreq)
71 struct tevent_req *req =
72 tevent_req_callback_data(subreq,
73 struct tevent_req);
74 struct ldapsrv_starttls_postprocess_state *state =
75 tevent_req_data(req,
76 struct ldapsrv_starttls_postprocess_state);
77 struct ldapsrv_connection *conn = state->conn;
78 int ret;
79 int sys_errno;
81 ret = tstream_tls_accept_recv(subreq, &sys_errno,
82 conn, &conn->sockets.tls);
83 TALLOC_FREE(subreq);
84 if (ret == -1) {
85 NTSTATUS status = map_nt_error_from_unix_common(sys_errno);
87 DEBUG(1,("ldapsrv_starttls_postprocess_done: accept_tls_loop: "
88 "tstream_tls_accept_recv() - %d:%s => %s",
89 sys_errno, strerror(sys_errno), nt_errstr(status)));
91 tevent_req_nterror(req, status);
92 return;
95 conn->sockets.active = conn->sockets.tls;
97 tevent_req_done(req);
100 static NTSTATUS ldapsrv_starttls_postprocess_recv(struct tevent_req *req)
102 return tevent_req_simple_recv_ntstatus(req);
105 static NTSTATUS ldapsrv_StartTLS(struct ldapsrv_call *call,
106 struct ldapsrv_reply *reply,
107 const char **errstr)
109 struct ldapsrv_starttls_postprocess_context *context;
111 (*errstr) = NULL;
114 * TODO: give LDAP_OPERATIONS_ERROR also when
115 * there're pending requests or there's
116 * a SASL bind in progress
117 * (see rfc4513 section 3.1.1)
119 if (call->conn->sockets.tls) {
120 (*errstr) = talloc_asprintf(reply, "START-TLS: TLS is already enabled on this LDAP session");
121 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
124 if (call->conn->sockets.sasl) {
125 (*errstr) = talloc_asprintf(reply, "START-TLS: SASL is already enabled on this LDAP session");
126 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
129 context = talloc(call, struct ldapsrv_starttls_postprocess_context);
130 NT_STATUS_HAVE_NO_MEMORY(context);
132 context->conn = call->conn;
134 call->postprocess_send = ldapsrv_starttls_postprocess_send;
135 call->postprocess_recv = ldapsrv_starttls_postprocess_recv;
136 call->postprocess_private = context;
138 reply->msg->r.ExtendedResponse.response.resultcode = LDAP_SUCCESS;
139 reply->msg->r.ExtendedResponse.response.errormessage = NULL;
141 ldapsrv_queue_reply(call, reply);
142 return NT_STATUS_OK;
145 struct ldapsrv_extended_operation {
146 const char *oid;
147 NTSTATUS (*fn)(struct ldapsrv_call *call, struct ldapsrv_reply *reply, const char **errorstr);
150 static struct ldapsrv_extended_operation extended_ops[] = {
152 .oid = LDB_EXTENDED_START_TLS_OID,
153 .fn = ldapsrv_StartTLS,
155 .oid = NULL,
156 .fn = NULL,
160 NTSTATUS ldapsrv_ExtendedRequest(struct ldapsrv_call *call)
162 struct ldap_ExtendedRequest *req = &call->request->r.ExtendedRequest;
163 struct ldapsrv_reply *reply;
164 int result = LDAP_PROTOCOL_ERROR;
165 const char *error_str = NULL;
166 NTSTATUS status = NT_STATUS_OK;
167 unsigned int i;
169 DEBUG(10, ("Extended\n"));
171 reply = ldapsrv_init_reply(call, LDAP_TAG_ExtendedResponse);
172 NT_STATUS_HAVE_NO_MEMORY(reply);
174 ZERO_STRUCT(reply->msg->r);
175 reply->msg->r.ExtendedResponse.oid = talloc_steal(reply, req->oid);
176 reply->msg->r.ExtendedResponse.response.resultcode = LDAP_PROTOCOL_ERROR;
177 reply->msg->r.ExtendedResponse.response.errormessage = NULL;
179 for (i=0; extended_ops[i].oid; i++) {
180 if (strcmp(extended_ops[i].oid,req->oid) != 0) continue;
183 * if the backend function returns an error we
184 * need to send the reply otherwise the reply is already
185 * send and we need to return directly
187 status = extended_ops[i].fn(call, reply, &error_str);
188 NT_STATUS_IS_OK_RETURN(status);
190 if (NT_STATUS_IS_LDAP(status)) {
191 result = NT_STATUS_LDAP_CODE(status);
192 } else {
193 result = LDAP_OPERATIONS_ERROR;
194 error_str = talloc_asprintf(reply, "Extended Operation(%s) failed: %s",
195 req->oid, nt_errstr(status));
198 /* if we haven't found the oid, then status is still NT_STATUS_OK */
199 if (NT_STATUS_IS_OK(status)) {
200 error_str = talloc_asprintf(reply, "Extended Operation(%s) not supported",
201 req->oid);
204 reply->msg->r.ExtendedResponse.response.resultcode = result;
205 reply->msg->r.ExtendedResponse.response.errormessage = error_str;
207 ldapsrv_queue_reply(call, reply);
208 return NT_STATUS_OK;