s3:libads: move ads->auth.time_offset to ads->config.time_offset
[Samba.git] / source3 / lib / tldap_tls_connect.c
blobdaf33dba3401b9bd3f8a198f2b597365eef15605
1 /*
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/>.
20 #include "replace.h"
21 #include "tldap.h"
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(
41 TALLOC_CTX *mem_ctx,
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);
52 if (req == NULL) {
53 return NULL;
55 state->ev = ev;
56 state->ctx = ctx;
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,
77 state->ev,
78 state->ctx,
79 start_tls_oid,
80 NULL, /* in_blob */
81 NULL, /* sctrls */
82 0, /* num_sctrls */
83 NULL, /* cctrls */
84 0); /* num_cctrls */
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,
90 req);
92 return req;
95 tldap_tls_connect_crypto_start(req);
96 if (!tevent_req_is_in_progress(req)) {
97 return tevent_req_post(req, ev);
100 return req;
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);
109 TLDAPRC rc;
111 rc = tldap_extended_recv(subreq, state, NULL, NULL);
112 TALLOC_FREE(subreq);
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);
117 return;
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;
132 NTSTATUS status;
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);
138 return;
141 status = tstream_tls_params_client_lpcfg(state,
142 state->lp_ctx,
143 state->peer_name,
144 &tls_params);
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);
149 return;
152 subreq = tstream_tls_connect_send(state,
153 state->ev,
154 plain_stream,
155 tls_params);
156 if (tevent_req_nomem(subreq, req)) {
157 return;
159 tevent_req_set_callback(subreq,
160 tldap_tls_connect_crypto_done,
161 req);
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;
171 int ret;
172 int error;
174 ret = tstream_tls_connect_recv(subreq, &error, state, &tls_stream);
175 TALLOC_FREE(subreq);
176 if (ret != 0) {
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);
180 return;
183 tldap_set_tls_tstream(state->ctx, &tls_stream);
185 tevent_req_done(req);
188 TLDAPRC tldap_tls_connect_recv(struct tevent_req *req)
190 TLDAPRC rc;
192 if (tevent_req_is_ldap_error(req, &rc)) {
193 return 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);
210 if (ev == NULL) {
211 goto fail;
213 req = tldap_tls_connect_send(frame,
215 ctx,
216 lp_ctx,
217 peer_name);
218 if (req == NULL) {
219 goto fail;
221 if (!tevent_req_poll(req, ev)) {
222 rc = TLDAP_OPERATIONS_ERROR;
223 goto fail;
225 rc = tldap_tls_connect_recv(req);
226 fail:
227 TALLOC_FREE(frame);
228 return rc;