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"
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
,
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
);
62 subreq
= tstream_tls_accept_send(conn
,
63 conn
->connection
->event
.ctx
,
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
);
74 static void ldapsrv_starttls_postprocess_done(struct tevent_req
*subreq
)
76 struct tevent_req
*req
=
77 tevent_req_callback_data(subreq
,
79 struct ldapsrv_starttls_postprocess_state
*state
=
81 struct ldapsrv_starttls_postprocess_state
);
82 struct ldapsrv_connection
*conn
= state
->conn
;
86 ret
= tstream_tls_accept_recv(subreq
, &sys_errno
,
87 conn
, &conn
->sockets
.tls
);
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
);
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
,
114 struct ldapsrv_starttls_postprocess_context
*context
;
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
);
154 struct ldapsrv_extended_operation
{
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
,
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
;
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
);
178 value
->data
= (uint8_t *)talloc_asprintf(value
,
181 uinfo
->account_name
);
182 if (value
->data
== NULL
) {
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
);
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
,
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
;
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
)) {
247 if (NT_STATUS_IS_LDAP(status
)) {
248 result
= NT_STATUS_LDAP_CODE(status
);
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",
261 reply
->msg
->r
.ExtendedResponse
.response
.resultcode
= result
;
262 reply
->msg
->r
.ExtendedResponse
.response
.errormessage
= error_str
;
264 ldapsrv_queue_reply(call
, reply
);