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 "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 struct ldapsrv_starttls_postprocess_context
{
30 struct ldapsrv_connection
*conn
;
33 struct ldapsrv_starttls_postprocess_state
{
34 struct ldapsrv_connection
*conn
;
37 static void ldapsrv_starttls_postprocess_done(struct tevent_req
*subreq
);
39 static struct tevent_req
*ldapsrv_starttls_postprocess_send(TALLOC_CTX
*mem_ctx
,
40 struct tevent_context
*ev
,
43 struct ldapsrv_starttls_postprocess_context
*context
=
44 talloc_get_type_abort(private_data
,
45 struct ldapsrv_starttls_postprocess_context
);
46 struct ldapsrv_connection
*conn
= context
->conn
;
47 struct tevent_req
*req
;
48 struct ldapsrv_starttls_postprocess_state
*state
;
49 struct tevent_req
*subreq
;
51 req
= tevent_req_create(mem_ctx
, &state
,
52 struct ldapsrv_starttls_postprocess_state
);
59 subreq
= tstream_tls_accept_send(conn
,
60 conn
->connection
->event
.ctx
,
62 conn
->service
->tls_params
);
63 if (tevent_req_nomem(subreq
, req
)) {
64 return tevent_req_post(req
, ev
);
66 tevent_req_set_callback(subreq
, ldapsrv_starttls_postprocess_done
, req
);
71 static void ldapsrv_starttls_postprocess_done(struct tevent_req
*subreq
)
73 struct tevent_req
*req
=
74 tevent_req_callback_data(subreq
,
76 struct ldapsrv_starttls_postprocess_state
*state
=
78 struct ldapsrv_starttls_postprocess_state
);
79 struct ldapsrv_connection
*conn
= state
->conn
;
83 ret
= tstream_tls_accept_recv(subreq
, &sys_errno
,
84 conn
, &conn
->sockets
.tls
);
87 NTSTATUS status
= map_nt_error_from_unix_common(sys_errno
);
89 DEBUG(1,("ldapsrv_starttls_postprocess_done: accept_tls_loop: "
90 "tstream_tls_accept_recv() - %d:%s => %s\n",
91 sys_errno
, strerror(sys_errno
), nt_errstr(status
)));
93 tevent_req_nterror(req
, status
);
97 conn
->sockets
.active
= conn
->sockets
.tls
;
102 static NTSTATUS
ldapsrv_starttls_postprocess_recv(struct tevent_req
*req
)
104 return tevent_req_simple_recv_ntstatus(req
);
107 static NTSTATUS
ldapsrv_StartTLS(struct ldapsrv_call
*call
,
108 struct ldapsrv_reply
*reply
,
111 struct ldapsrv_starttls_postprocess_context
*context
;
116 * TODO: give LDAP_OPERATIONS_ERROR also when
117 * there's a SASL bind in progress
118 * (see rfc4513 section 3.1.1)
120 if (call
->conn
->sockets
.tls
) {
121 (*errstr
) = talloc_asprintf(reply
, "START-TLS: TLS is already enabled on this LDAP session");
122 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR
);
125 if (call
->conn
->sockets
.sasl
) {
126 (*errstr
) = talloc_asprintf(reply
, "START-TLS: SASL is already enabled on this LDAP session");
127 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR
);
130 if (call
->conn
->pending_calls
!= NULL
) {
131 (*errstr
) = talloc_asprintf(reply
, "START-TLS: pending requests on this LDAP session");
132 return NT_STATUS_LDAP(LDAP_BUSY
);
135 context
= talloc(call
, struct ldapsrv_starttls_postprocess_context
);
136 NT_STATUS_HAVE_NO_MEMORY(context
);
138 context
->conn
= call
->conn
;
140 call
->postprocess_send
= ldapsrv_starttls_postprocess_send
;
141 call
->postprocess_recv
= ldapsrv_starttls_postprocess_recv
;
142 call
->postprocess_private
= context
;
144 reply
->msg
->r
.ExtendedResponse
.response
.resultcode
= LDAP_SUCCESS
;
145 reply
->msg
->r
.ExtendedResponse
.response
.errormessage
= NULL
;
147 ldapsrv_queue_reply(call
, reply
);
151 struct ldapsrv_extended_operation
{
153 NTSTATUS (*fn
)(struct ldapsrv_call
*call
, struct ldapsrv_reply
*reply
, const char **errorstr
);
156 static NTSTATUS
ldapsrv_whoami(struct ldapsrv_call
*call
,
157 struct ldapsrv_reply
*reply
,
160 struct ldapsrv_connection
*conn
= call
->conn
;
161 struct auth_session_info
*session_info
= conn
->session_info
;
162 struct ldap_ExtendedResponse
*ext_resp
=
163 &reply
->msg
->r
.ExtendedResponse
;
167 if (!security_token_is_anonymous(session_info
->security_token
)) {
168 struct auth_user_info
*uinfo
= session_info
->info
;
169 DATA_BLOB
*value
= talloc_zero(call
, DATA_BLOB
);
175 value
->data
= (uint8_t *)talloc_asprintf(value
,
178 uinfo
->account_name
);
179 if (value
->data
== NULL
) {
182 value
->length
= talloc_get_size(value
->data
) - 1;
184 ext_resp
->value
= value
;
187 ext_resp
->response
.resultcode
= LDAP_SUCCESS
;
188 ext_resp
->response
.errormessage
= NULL
;
190 ldapsrv_queue_reply(call
, reply
);
194 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR
);
198 static struct ldapsrv_extended_operation extended_ops
[] = {
200 .oid
= LDB_EXTENDED_START_TLS_OID
,
201 .fn
= ldapsrv_StartTLS
,
203 .oid
= LDB_EXTENDED_WHOAMI_OID
,
204 .fn
= ldapsrv_whoami
,
212 NTSTATUS
ldapsrv_ExtendedRequest(struct ldapsrv_call
*call
)
214 struct ldap_ExtendedRequest
*req
= &call
->request
->r
.ExtendedRequest
;
215 struct ldapsrv_reply
*reply
;
216 int result
= LDAP_PROTOCOL_ERROR
;
217 const char *error_str
= NULL
;
218 NTSTATUS status
= NT_STATUS_OK
;
221 DEBUG(10, ("Extended\n"));
223 reply
= ldapsrv_init_reply(call
, LDAP_TAG_ExtendedResponse
);
224 NT_STATUS_HAVE_NO_MEMORY(reply
);
226 ZERO_STRUCT(reply
->msg
->r
);
227 reply
->msg
->r
.ExtendedResponse
.oid
= talloc_steal(reply
, req
->oid
);
228 reply
->msg
->r
.ExtendedResponse
.response
.resultcode
= LDAP_PROTOCOL_ERROR
;
229 reply
->msg
->r
.ExtendedResponse
.response
.errormessage
= NULL
;
231 for (i
=0; extended_ops
[i
].oid
; i
++) {
232 if (strcmp(extended_ops
[i
].oid
,req
->oid
) != 0) continue;
235 * if the backend function returns an error we
236 * need to send the reply otherwise the reply is already
237 * sent and we need to return directly
239 status
= extended_ops
[i
].fn(call
, reply
, &error_str
);
240 if (NT_STATUS_IS_OK(status
)) {
244 if (NT_STATUS_IS_LDAP(status
)) {
245 result
= NT_STATUS_LDAP_CODE(status
);
247 result
= LDAP_OPERATIONS_ERROR
;
248 error_str
= talloc_asprintf(reply
, "Extended Operation(%s) failed: %s",
249 req
->oid
, nt_errstr(status
));
252 /* if we haven't found the oid, then status is still NT_STATUS_OK */
253 if (NT_STATUS_IS_OK(status
)) {
254 error_str
= talloc_asprintf(reply
, "Extended Operation(%s) not supported",
258 reply
->msg
->r
.ExtendedResponse
.response
.resultcode
= result
;
259 reply
->msg
->r
.ExtendedResponse
.response
.errormessage
= error_str
;
261 ldapsrv_queue_reply(call
, reply
);