2 * Unix SMB/CIFS implementation.
3 * tls based tldap connect
4 * Copyright (C) Stefan Metzmacher 2024
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/>.
22 #include "tldap_tls_connect.h"
23 #include "lib/util/samba_util.h"
24 #include "lib/util/debug.h"
25 #include "lib/param/param.h"
26 #include "../libcli/util/ntstatus.h"
27 #include "../source4/lib/tls/tls.h"
29 struct tldap_tls_connect_state
{
30 struct tevent_context
*ev
;
31 struct tldap_context
*ctx
;
32 struct loadparm_context
*lp_ctx
;
33 const char *peer_name
;
36 static void tldap_tls_connect_starttls_done(struct tevent_req
*subreq
);
37 static void tldap_tls_connect_crypto_start(struct tevent_req
*req
);
38 static void tldap_tls_connect_crypto_done(struct tevent_req
*subreq
);
40 struct tevent_req
*tldap_tls_connect_send(
42 struct tevent_context
*ev
,
43 struct tldap_context
*ctx
,
44 struct loadparm_context
*lp_ctx
,
45 const char *peer_name
)
47 struct tevent_req
*req
= NULL
;
48 struct tldap_tls_connect_state
*state
= NULL
;
50 req
= tevent_req_create(mem_ctx
, &state
,
51 struct tldap_tls_connect_state
);
57 state
->lp_ctx
= lp_ctx
;
58 state
->peer_name
= peer_name
;
60 if (!tldap_connection_ok(ctx
)) {
61 DBG_ERR("tldap_connection_ok() => false\n");
62 tevent_req_ldap_error(req
, TLDAP_CONNECT_ERROR
);
63 return tevent_req_post(req
, ev
);
66 if (tldap_has_gensec_tstream(ctx
)) {
67 DBG_ERR("tldap_has_gensec_tstream() => true\n");
68 tevent_req_ldap_error(req
, TLDAP_LOCAL_ERROR
);
69 return tevent_req_post(req
, ev
);
72 if (tldap_get_starttls_needed(ctx
)) {
73 struct tevent_req
*subreq
= NULL
;
74 static const char *start_tls_oid
= "1.3.6.1.4.1.1466.20037";
76 subreq
= tldap_extended_send(state
,
85 if (tevent_req_nomem(subreq
, req
)) {
86 return tevent_req_post(req
, ev
);
88 tevent_req_set_callback(subreq
,
89 tldap_tls_connect_starttls_done
,
95 tldap_tls_connect_crypto_start(req
);
96 if (!tevent_req_is_in_progress(req
)) {
97 return tevent_req_post(req
, ev
);
103 static void tldap_tls_connect_starttls_done(struct tevent_req
*subreq
)
105 struct tevent_req
*req
= tevent_req_callback_data(
106 subreq
, struct tevent_req
);
107 struct tldap_tls_connect_state
*state
= tevent_req_data(
108 req
, struct tldap_tls_connect_state
);
111 rc
= tldap_extended_recv(subreq
, state
, NULL
, NULL
);
113 if (!TLDAP_RC_IS_SUCCESS(rc
)) {
114 DBG_ERR("tldap_extended_recv(STARTTLS, %s): %s\n",
115 state
->peer_name
, tldap_rc2string(rc
));
116 tevent_req_ldap_error(req
, rc
);
120 tldap_set_starttls_needed(state
->ctx
, false);
122 tldap_tls_connect_crypto_start(req
);
125 static void tldap_tls_connect_crypto_start(struct tevent_req
*req
)
127 struct tldap_tls_connect_state
*state
= tevent_req_data(
128 req
, struct tldap_tls_connect_state
);
129 struct tstream_context
*plain_stream
= NULL
;
130 struct tstream_tls_params
*tls_params
= NULL
;
131 struct tevent_req
*subreq
= NULL
;
134 plain_stream
= tldap_get_plain_tstream(state
->ctx
);
135 if (plain_stream
== NULL
) {
136 DBG_ERR("tldap_get_plain_tstream() = NULL\n");
137 tevent_req_ldap_error(req
, TLDAP_LOCAL_ERROR
);
141 status
= tstream_tls_params_client_lpcfg(state
,
145 if (!NT_STATUS_IS_OK(status
)) {
146 DBG_ERR("tstream_tls_params_client_lpcfg(%s): %s\n",
147 state
->peer_name
, nt_errstr(status
));
148 tevent_req_ldap_error(req
, TLDAP_LOCAL_ERROR
);
152 subreq
= tstream_tls_connect_send(state
,
156 if (tevent_req_nomem(subreq
, req
)) {
159 tevent_req_set_callback(subreq
,
160 tldap_tls_connect_crypto_done
,
164 static void tldap_tls_connect_crypto_done(struct tevent_req
*subreq
)
166 struct tevent_req
*req
= tevent_req_callback_data(
167 subreq
, struct tevent_req
);
168 struct tldap_tls_connect_state
*state
= tevent_req_data(
169 req
, struct tldap_tls_connect_state
);
170 struct tstream_context
*tls_stream
= NULL
;
174 ret
= tstream_tls_connect_recv(subreq
, &error
, state
, &tls_stream
);
177 DBG_ERR("tstream_tls_connect_recv(%s): %d %d\n",
178 state
->peer_name
, ret
, error
);
179 tevent_req_ldap_error(req
, TLDAP_CONNECT_ERROR
);
183 tldap_set_tls_tstream(state
->ctx
, &tls_stream
);
185 tevent_req_done(req
);
188 TLDAPRC
tldap_tls_connect_recv(struct tevent_req
*req
)
192 if (tevent_req_is_ldap_error(req
, &rc
)) {
196 return TLDAP_SUCCESS
;
199 TLDAPRC
tldap_tls_connect(
200 struct tldap_context
*ctx
,
201 struct loadparm_context
*lp_ctx
,
202 const char *peer_name
)
204 TALLOC_CTX
*frame
= talloc_stackframe();
205 struct tevent_context
*ev
;
206 struct tevent_req
*req
;
207 TLDAPRC rc
= TLDAP_NO_MEMORY
;
209 ev
= samba_tevent_context_init(frame
);
213 req
= tldap_tls_connect_send(frame
,
221 if (!tevent_req_poll(req
, ev
)) {
222 rc
= TLDAP_OPERATIONS_ERROR
;
225 rc
= tldap_tls_connect_recv(req
);