2 Unix SMB/CIFS implementation.
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/>.
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
,
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
);
57 subreq
= tstream_tls_accept_send(conn
,
58 conn
->connection
->event
.ctx
,
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
);
69 static void ldapsrv_starttls_postprocess_done(struct tevent_req
*subreq
)
71 struct tevent_req
*req
=
72 tevent_req_callback_data(subreq
,
74 struct ldapsrv_starttls_postprocess_state
*state
=
76 struct ldapsrv_starttls_postprocess_state
);
77 struct ldapsrv_connection
*conn
= state
->conn
;
81 ret
= tstream_tls_accept_recv(subreq
, &sys_errno
,
82 conn
, &conn
->sockets
.tls
);
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
);
95 conn
->sockets
.active
= conn
->sockets
.tls
;
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
,
109 struct ldapsrv_starttls_postprocess_context
*context
;
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
);
149 struct ldapsrv_extended_operation
{
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
,
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
;
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
)) {
196 if (NT_STATUS_IS_LDAP(status
)) {
197 result
= NT_STATUS_LDAP_CODE(status
);
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",
210 reply
->msg
->r
.ExtendedResponse
.response
.resultcode
= result
;
211 reply
->msg
->r
.ExtendedResponse
.response
.errormessage
= error_str
;
213 ldapsrv_queue_reply(call
, reply
);