Line data Source code
1 : /*
2 : * Unix SMB/CIFS implementation.
3 : * tls based tldap connect
4 : * Copyright (C) Stefan Metzmacher 2024
5 : *
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.
10 : *
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.
15 : *
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/>.
18 : */
19 :
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"
28 :
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;
34 : };
35 :
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);
39 :
40 4 : 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)
46 : {
47 4 : struct tevent_req *req = NULL;
48 4 : struct tldap_tls_connect_state *state = NULL;
49 :
50 4 : req = tevent_req_create(mem_ctx, &state,
51 : struct tldap_tls_connect_state);
52 4 : if (req == NULL) {
53 0 : return NULL;
54 : }
55 4 : state->ev = ev;
56 4 : state->ctx = ctx;
57 4 : state->lp_ctx = lp_ctx;
58 4 : state->peer_name = peer_name;
59 :
60 4 : if (!tldap_connection_ok(ctx)) {
61 0 : DBG_ERR("tldap_connection_ok() => false\n");
62 0 : tevent_req_ldap_error(req, TLDAP_CONNECT_ERROR);
63 0 : return tevent_req_post(req, ev);
64 : }
65 :
66 4 : if (tldap_has_gensec_tstream(ctx)) {
67 0 : DBG_ERR("tldap_has_gensec_tstream() => true\n");
68 0 : tevent_req_ldap_error(req, TLDAP_LOCAL_ERROR);
69 0 : return tevent_req_post(req, ev);
70 : }
71 :
72 4 : if (tldap_get_starttls_needed(ctx)) {
73 2 : struct tevent_req *subreq = NULL;
74 0 : static const char *start_tls_oid = "1.3.6.1.4.1.1466.20037";
75 :
76 2 : subreq = tldap_extended_send(state,
77 2 : state->ev,
78 2 : 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 2 : if (tevent_req_nomem(subreq, req)) {
86 0 : return tevent_req_post(req, ev);
87 : }
88 2 : tevent_req_set_callback(subreq,
89 : tldap_tls_connect_starttls_done,
90 : req);
91 :
92 2 : return req;
93 : }
94 :
95 2 : tldap_tls_connect_crypto_start(req);
96 2 : if (!tevent_req_is_in_progress(req)) {
97 0 : return tevent_req_post(req, ev);
98 : }
99 :
100 2 : return req;
101 : }
102 :
103 2 : static void tldap_tls_connect_starttls_done(struct tevent_req *subreq)
104 : {
105 2 : struct tevent_req *req = tevent_req_callback_data(
106 : subreq, struct tevent_req);
107 2 : struct tldap_tls_connect_state *state = tevent_req_data(
108 : req, struct tldap_tls_connect_state);
109 0 : TLDAPRC rc;
110 :
111 2 : rc = tldap_extended_recv(subreq, state, NULL, NULL);
112 2 : TALLOC_FREE(subreq);
113 2 : if (!TLDAP_RC_IS_SUCCESS(rc)) {
114 0 : DBG_ERR("tldap_extended_recv(STARTTLS, %s): %s\n",
115 : state->peer_name, tldap_rc2string(rc));
116 0 : tevent_req_ldap_error(req, rc);
117 0 : return;
118 : }
119 :
120 2 : tldap_set_starttls_needed(state->ctx, false);
121 :
122 2 : tldap_tls_connect_crypto_start(req);
123 : }
124 :
125 4 : static void tldap_tls_connect_crypto_start(struct tevent_req *req)
126 : {
127 4 : struct tldap_tls_connect_state *state = tevent_req_data(
128 : req, struct tldap_tls_connect_state);
129 4 : struct tstream_context *plain_stream = NULL;
130 4 : struct tstream_tls_params *tls_params = NULL;
131 4 : struct tevent_req *subreq = NULL;
132 0 : NTSTATUS status;
133 :
134 4 : plain_stream = tldap_get_plain_tstream(state->ctx);
135 4 : if (plain_stream == NULL) {
136 0 : DBG_ERR("tldap_get_plain_tstream() = NULL\n");
137 0 : tevent_req_ldap_error(req, TLDAP_LOCAL_ERROR);
138 0 : return;
139 : }
140 :
141 4 : status = tstream_tls_params_client_lpcfg(state,
142 : state->lp_ctx,
143 : state->peer_name,
144 : &tls_params);
145 4 : if (!NT_STATUS_IS_OK(status)) {
146 0 : DBG_ERR("tstream_tls_params_client_lpcfg(%s): %s\n",
147 : state->peer_name, nt_errstr(status));
148 0 : tevent_req_ldap_error(req, TLDAP_LOCAL_ERROR);
149 0 : return;
150 : }
151 :
152 4 : subreq = tstream_tls_connect_send(state,
153 : state->ev,
154 : plain_stream,
155 : tls_params);
156 4 : if (tevent_req_nomem(subreq, req)) {
157 0 : return;
158 : }
159 4 : tevent_req_set_callback(subreq,
160 : tldap_tls_connect_crypto_done,
161 : req);
162 : }
163 :
164 4 : static void tldap_tls_connect_crypto_done(struct tevent_req *subreq)
165 : {
166 4 : struct tevent_req *req = tevent_req_callback_data(
167 : subreq, struct tevent_req);
168 4 : struct tldap_tls_connect_state *state = tevent_req_data(
169 : req, struct tldap_tls_connect_state);
170 4 : struct tstream_context *tls_stream = NULL;
171 0 : int ret;
172 0 : int error;
173 :
174 4 : ret = tstream_tls_connect_recv(subreq, &error, state, &tls_stream);
175 4 : TALLOC_FREE(subreq);
176 4 : if (ret != 0) {
177 0 : DBG_ERR("tstream_tls_connect_recv(%s): %d %d\n",
178 : state->peer_name, ret, error);
179 0 : tevent_req_ldap_error(req, TLDAP_CONNECT_ERROR);
180 0 : return;
181 : }
182 :
183 4 : tldap_set_tls_tstream(state->ctx, &tls_stream);
184 :
185 4 : tevent_req_done(req);
186 : }
187 :
188 4 : TLDAPRC tldap_tls_connect_recv(struct tevent_req *req)
189 : {
190 0 : TLDAPRC rc;
191 :
192 4 : if (tevent_req_is_ldap_error(req, &rc)) {
193 0 : return rc;
194 : }
195 :
196 4 : return TLDAP_SUCCESS;
197 : }
198 :
199 4 : TLDAPRC tldap_tls_connect(
200 : struct tldap_context *ctx,
201 : struct loadparm_context *lp_ctx,
202 : const char *peer_name)
203 : {
204 4 : TALLOC_CTX *frame = talloc_stackframe();
205 0 : struct tevent_context *ev;
206 0 : struct tevent_req *req;
207 4 : TLDAPRC rc = TLDAP_NO_MEMORY;
208 :
209 4 : ev = samba_tevent_context_init(frame);
210 4 : if (ev == NULL) {
211 0 : goto fail;
212 : }
213 4 : req = tldap_tls_connect_send(frame,
214 : ev,
215 : ctx,
216 : lp_ctx,
217 : peer_name);
218 4 : if (req == NULL) {
219 0 : goto fail;
220 : }
221 4 : if (!tevent_req_poll(req, ev)) {
222 0 : rc = TLDAP_OPERATIONS_ERROR;
223 0 : goto fail;
224 : }
225 4 : rc = tldap_tls_connect_recv(req);
226 4 : fail:
227 4 : TALLOC_FREE(frame);
228 4 : return rc;
229 : }
|