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'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
);
145 struct ldapsrv_extended_operation
{
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
,
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
;
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 if (NT_STATUS_IS_OK(status
)) {
192 if (NT_STATUS_IS_LDAP(status
)) {
193 result
= NT_STATUS_LDAP_CODE(status
);
195 result
= LDAP_OPERATIONS_ERROR
;
196 error_str
= talloc_asprintf(reply
, "Extended Operation(%s) failed: %s",
197 req
->oid
, nt_errstr(status
));
200 /* if we haven't found the oid, then status is still NT_STATUS_OK */
201 if (NT_STATUS_IS_OK(status
)) {
202 error_str
= talloc_asprintf(reply
, "Extended Operation(%s) not supported",
206 reply
->msg
->r
.ExtendedResponse
.response
.resultcode
= result
;
207 reply
->msg
->r
.ExtendedResponse
.response
.errormessage
= error_str
;
209 ldapsrv_queue_reply(call
, reply
);