ctdb-scripts: Move connection tracking to 10.interface
[samba4-gss.git] / source4 / ldap_server / ldap_extended.c
blobb4ea49169885d7189006ab122884e79731a83ecc
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 "samba/service_stream.h"
25 #include "../lib/util/tevent_ntstatus.h"
26 #include "librpc/gen_ndr/auth.h"
27 #include "libcli/security/security_token.h"
29 #undef DBGC_CLASS
30 #define DBGC_CLASS DBGC_LDAPSRV
32 struct ldapsrv_starttls_postprocess_context {
33 struct ldapsrv_connection *conn;
36 struct ldapsrv_starttls_postprocess_state {
37 struct ldapsrv_connection *conn;
40 static void ldapsrv_starttls_postprocess_done(struct tevent_req *subreq);
42 static struct tevent_req *ldapsrv_starttls_postprocess_send(TALLOC_CTX *mem_ctx,
43 struct tevent_context *ev,
44 void *private_data)
46 struct ldapsrv_starttls_postprocess_context *context =
47 talloc_get_type_abort(private_data,
48 struct ldapsrv_starttls_postprocess_context);
49 struct ldapsrv_connection *conn = context->conn;
50 struct tevent_req *req;
51 struct ldapsrv_starttls_postprocess_state *state;
52 struct tevent_req *subreq;
54 req = tevent_req_create(mem_ctx, &state,
55 struct ldapsrv_starttls_postprocess_state);
56 if (req == NULL) {
57 return NULL;
60 state->conn = conn;
62 subreq = tstream_tls_accept_send(conn,
63 conn->connection->event.ctx,
64 conn->sockets.raw,
65 conn->service->tls_params);
66 if (tevent_req_nomem(subreq, req)) {
67 return tevent_req_post(req, ev);
69 tevent_req_set_callback(subreq, ldapsrv_starttls_postprocess_done, req);
71 return req;
74 static void ldapsrv_starttls_postprocess_done(struct tevent_req *subreq)
76 struct tevent_req *req =
77 tevent_req_callback_data(subreq,
78 struct tevent_req);
79 struct ldapsrv_starttls_postprocess_state *state =
80 tevent_req_data(req,
81 struct ldapsrv_starttls_postprocess_state);
82 struct ldapsrv_connection *conn = state->conn;
83 int ret;
84 int sys_errno;
86 ret = tstream_tls_accept_recv(subreq, &sys_errno,
87 conn, &conn->sockets.tls);
88 TALLOC_FREE(subreq);
89 if (ret == -1) {
90 NTSTATUS status = map_nt_error_from_unix_common(sys_errno);
92 DEBUG(1,("ldapsrv_starttls_postprocess_done: accept_tls_loop: "
93 "tstream_tls_accept_recv() - %d:%s => %s\n",
94 sys_errno, strerror(sys_errno), nt_errstr(status)));
96 tevent_req_nterror(req, status);
97 return;
100 conn->sockets.active = conn->sockets.tls;
102 tevent_req_done(req);
105 static NTSTATUS ldapsrv_starttls_postprocess_recv(struct tevent_req *req)
107 return tevent_req_simple_recv_ntstatus(req);
110 static NTSTATUS ldapsrv_StartTLS(struct ldapsrv_call *call,
111 struct ldapsrv_reply *reply,
112 const char **errstr)
114 struct ldapsrv_starttls_postprocess_context *context;
116 (*errstr) = NULL;
119 * TODO: give LDAP_OPERATIONS_ERROR also when
120 * there's a SASL bind in progress
121 * (see rfc4513 section 3.1.1)
123 if (call->conn->sockets.tls) {
124 (*errstr) = talloc_asprintf(reply, "START-TLS: TLS is already enabled on this LDAP session");
125 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
128 if (call->conn->sockets.sasl) {
129 (*errstr) = talloc_asprintf(reply, "START-TLS: SASL is already enabled on this LDAP session");
130 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
133 if (call->conn->pending_calls != NULL) {
134 (*errstr) = talloc_asprintf(reply, "START-TLS: pending requests on this LDAP session");
135 return NT_STATUS_LDAP(LDAP_BUSY);
138 context = talloc(call, struct ldapsrv_starttls_postprocess_context);
139 NT_STATUS_HAVE_NO_MEMORY(context);
141 context->conn = call->conn;
143 call->postprocess_send = ldapsrv_starttls_postprocess_send;
144 call->postprocess_recv = ldapsrv_starttls_postprocess_recv;
145 call->postprocess_private = context;
147 reply->msg->r.ExtendedResponse.response.resultcode = LDAP_SUCCESS;
148 reply->msg->r.ExtendedResponse.response.errormessage = NULL;
150 ldapsrv_queue_reply(call, reply);
151 return NT_STATUS_OK;
154 struct ldapsrv_extended_operation {
155 const char *oid;
156 NTSTATUS (*fn)(struct ldapsrv_call *call, struct ldapsrv_reply *reply, const char **errorstr);
159 static NTSTATUS ldapsrv_whoami(struct ldapsrv_call *call,
160 struct ldapsrv_reply *reply,
161 const char **errstr)
163 struct ldapsrv_connection *conn = call->conn;
164 struct auth_session_info *session_info = conn->session_info;
165 struct ldap_ExtendedResponse *ext_resp =
166 &reply->msg->r.ExtendedResponse;
168 *errstr = NULL;
170 if (!security_token_is_anonymous(session_info->security_token)) {
171 struct auth_user_info *uinfo = session_info->info;
172 DATA_BLOB *value = talloc_zero(call, DATA_BLOB);
174 if (value == NULL) {
175 goto nomem;
178 value->data = (uint8_t *)talloc_asprintf(value,
179 "u:%s\\%s",
180 uinfo->domain_name,
181 uinfo->account_name);
182 if (value->data == NULL) {
183 goto nomem;
185 value->length = talloc_get_size(value->data) - 1;
187 ext_resp->value = value;
190 ext_resp->response.resultcode = LDAP_SUCCESS;
191 ext_resp->response.errormessage = NULL;
193 ldapsrv_queue_reply(call, reply);
195 return NT_STATUS_OK;
196 nomem:
197 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
201 static struct ldapsrv_extended_operation extended_ops[] = {
203 .oid = LDB_EXTENDED_START_TLS_OID,
204 .fn = ldapsrv_StartTLS,
206 .oid = LDB_EXTENDED_WHOAMI_OID,
207 .fn = ldapsrv_whoami,
210 .oid = NULL,
211 .fn = NULL,
215 NTSTATUS ldapsrv_ExtendedRequest(struct ldapsrv_call *call)
217 struct ldap_ExtendedRequest *req = &call->request->r.ExtendedRequest;
218 struct ldapsrv_reply *reply;
219 int result = LDAP_PROTOCOL_ERROR;
220 const char *error_str = NULL;
221 NTSTATUS status = NT_STATUS_OK;
222 unsigned int i;
224 DEBUG(10, ("Extended\n"));
226 reply = ldapsrv_init_reply(call, LDAP_TAG_ExtendedResponse);
227 NT_STATUS_HAVE_NO_MEMORY(reply);
229 ZERO_STRUCT(reply->msg->r);
230 reply->msg->r.ExtendedResponse.oid = talloc_steal(reply, req->oid);
231 reply->msg->r.ExtendedResponse.response.resultcode = LDAP_PROTOCOL_ERROR;
232 reply->msg->r.ExtendedResponse.response.errormessage = NULL;
234 for (i=0; extended_ops[i].oid; i++) {
235 if (strcmp(extended_ops[i].oid,req->oid) != 0) continue;
238 * if the backend function returns an error we
239 * need to send the reply otherwise the reply is already
240 * sent and we need to return directly
242 status = extended_ops[i].fn(call, reply, &error_str);
243 if (NT_STATUS_IS_OK(status)) {
244 return status;
247 if (NT_STATUS_IS_LDAP(status)) {
248 result = NT_STATUS_LDAP_CODE(status);
249 } else {
250 result = LDAP_OPERATIONS_ERROR;
251 error_str = talloc_asprintf(reply, "Extended Operation(%s) failed: %s",
252 req->oid, nt_errstr(status));
255 /* if we haven't found the oid, then status is still NT_STATUS_OK */
256 if (NT_STATUS_IS_OK(status)) {
257 error_str = talloc_asprintf(reply, "Extended Operation(%s) not supported",
258 req->oid);
261 reply->msg->r.ExtendedResponse.response.resultcode = result;
262 reply->msg->r.ExtendedResponse.response.errormessage = error_str;
264 ldapsrv_queue_reply(call, reply);
265 return NT_STATUS_OK;