s3:libnet_join: remember r->out.krb5_salt in libnet_join_derive_salting_principal()
[Samba.git] / source4 / ldap_server / ldap_extended.c
blob2d4a5345460fd88f40e12c6c723b8f7440b9665f
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's a SASL bind in progress
116 * (see rfc4513 section 3.1.1)
118 if (call->conn->sockets.tls) {
119 (*errstr) = talloc_asprintf(reply, "START-TLS: TLS is already enabled on this LDAP session");
120 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
123 if (call->conn->sockets.sasl) {
124 (*errstr) = talloc_asprintf(reply, "START-TLS: SASL is already enabled on this LDAP session");
125 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
128 if (call->conn->pending_calls != NULL) {
129 (*errstr) = talloc_asprintf(reply, "START-TLS: pending requests on this LDAP session");
130 return NT_STATUS_LDAP(LDAP_BUSY);
133 context = talloc(call, struct ldapsrv_starttls_postprocess_context);
134 NT_STATUS_HAVE_NO_MEMORY(context);
136 context->conn = call->conn;
138 call->postprocess_send = ldapsrv_starttls_postprocess_send;
139 call->postprocess_recv = ldapsrv_starttls_postprocess_recv;
140 call->postprocess_private = context;
142 reply->msg->r.ExtendedResponse.response.resultcode = LDAP_SUCCESS;
143 reply->msg->r.ExtendedResponse.response.errormessage = NULL;
145 ldapsrv_queue_reply(call, reply);
146 return NT_STATUS_OK;
149 struct ldapsrv_extended_operation {
150 const char *oid;
151 NTSTATUS (*fn)(struct ldapsrv_call *call, struct ldapsrv_reply *reply, const char **errorstr);
154 static struct ldapsrv_extended_operation extended_ops[] = {
156 .oid = LDB_EXTENDED_START_TLS_OID,
157 .fn = ldapsrv_StartTLS,
159 .oid = NULL,
160 .fn = NULL,
164 NTSTATUS ldapsrv_ExtendedRequest(struct ldapsrv_call *call)
166 struct ldap_ExtendedRequest *req = &call->request->r.ExtendedRequest;
167 struct ldapsrv_reply *reply;
168 int result = LDAP_PROTOCOL_ERROR;
169 const char *error_str = NULL;
170 NTSTATUS status = NT_STATUS_OK;
171 unsigned int i;
173 DEBUG(10, ("Extended\n"));
175 reply = ldapsrv_init_reply(call, LDAP_TAG_ExtendedResponse);
176 NT_STATUS_HAVE_NO_MEMORY(reply);
178 ZERO_STRUCT(reply->msg->r);
179 reply->msg->r.ExtendedResponse.oid = talloc_steal(reply, req->oid);
180 reply->msg->r.ExtendedResponse.response.resultcode = LDAP_PROTOCOL_ERROR;
181 reply->msg->r.ExtendedResponse.response.errormessage = NULL;
183 for (i=0; extended_ops[i].oid; i++) {
184 if (strcmp(extended_ops[i].oid,req->oid) != 0) continue;
187 * if the backend function returns an error we
188 * need to send the reply otherwise the reply is already
189 * send and we need to return directly
191 status = extended_ops[i].fn(call, reply, &error_str);
192 if (NT_STATUS_IS_OK(status)) {
193 return status;
196 if (NT_STATUS_IS_LDAP(status)) {
197 result = NT_STATUS_LDAP_CODE(status);
198 } else {
199 result = LDAP_OPERATIONS_ERROR;
200 error_str = talloc_asprintf(reply, "Extended Operation(%s) failed: %s",
201 req->oid, nt_errstr(status));
204 /* if we haven't found the oid, then status is still NT_STATUS_OK */
205 if (NT_STATUS_IS_OK(status)) {
206 error_str = talloc_asprintf(reply, "Extended Operation(%s) not supported",
207 req->oid);
210 reply->msg->r.ExtendedResponse.response.resultcode = result;
211 reply->msg->r.ExtendedResponse.response.errormessage = error_str;
213 ldapsrv_queue_reply(call, reply);
214 return NT_STATUS_OK;