Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : ads tls wrapping code
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 "includes.h"
21 : #include "ads.h"
22 : #include "lib/param/param.h"
23 : #include "../source4/lib/tls/tls.h"
24 :
25 0 : void ndr_print_ads_tlswrap_struct(struct ndr_print *ndr, const char *name, const struct ads_tlswrap *r)
26 : {
27 0 : ndr_print_struct(ndr, name, "tlswrap");
28 0 : ndr->depth++;
29 0 : ndr_print_ptr(ndr, "mem_ctx", r->mem_ctx);
30 0 : ndr_print_timeval(ndr, "endtime", &r->endtime);
31 : #ifdef HAVE_ADS
32 0 : ndr_print_ptr(ndr, "sbiod", r->sbiod);
33 0 : ndr_print_ptr(ndr, "tls_params", r->tls_params);
34 0 : ndr_print_ptr(ndr, "tls_sync", r->tls_sync);
35 : #endif /* HAVE_ADS */
36 0 : ndr->depth--;
37 0 : }
38 :
39 : #ifdef HAVE_ADS
40 :
41 24 : static int ads_tlswrap_setup(Sockbuf_IO_Desc *sbiod, void *arg)
42 : {
43 24 : struct ads_tlswrap *wrap = (struct ads_tlswrap *)arg;
44 :
45 24 : wrap->sbiod = sbiod;
46 :
47 24 : sbiod->sbiod_pvt = wrap;
48 :
49 24 : return 0;
50 : }
51 :
52 24 : static int ads_tlswrap_remove(Sockbuf_IO_Desc *sbiod)
53 : {
54 24 : struct ads_tlswrap *wrap =
55 : (struct ads_tlswrap *)sbiod->sbiod_pvt;
56 :
57 24 : wrap->sbiod = NULL;
58 :
59 24 : return 0;
60 : }
61 :
62 224 : static ssize_t ads_tlswrap_send_function(gnutls_transport_ptr_t ptr,
63 : const uint8_t *buf, size_t size)
64 : {
65 224 : struct ads_tlswrap *wrap = (struct ads_tlswrap *)ptr;
66 :
67 224 : if (wrap->endtime.tv_sec != 0) {
68 96 : if (timeval_expired(&wrap->endtime)) {
69 0 : errno = ECONNRESET;
70 0 : return -1;
71 : }
72 : }
73 :
74 224 : return LBER_SBIOD_WRITE_NEXT(wrap->sbiod, discard_const(buf), size);
75 : }
76 :
77 504 : static ssize_t ads_tlswrap_recv_function(gnutls_transport_ptr_t ptr,
78 : uint8_t *buf, size_t size)
79 : {
80 504 : struct ads_tlswrap *wrap = (struct ads_tlswrap *)ptr;
81 :
82 504 : if (wrap->endtime.tv_sec != 0) {
83 360 : if (timeval_expired(&wrap->endtime)) {
84 0 : errno = ECONNRESET;
85 0 : return -1;
86 : }
87 : }
88 :
89 504 : return LBER_SBIOD_READ_NEXT(wrap->sbiod, buf, size);
90 : }
91 :
92 240 : static ber_slen_t ads_tlswrap_read(Sockbuf_IO_Desc *sbiod,
93 : void *buf, ber_len_t len)
94 : {
95 240 : struct ads_tlswrap *wrap =
96 : (struct ads_tlswrap *)sbiod->sbiod_pvt;
97 :
98 240 : return tstream_tls_sync_read(wrap->tls_sync, buf, len);
99 : }
100 :
101 96 : static ber_slen_t ads_tlswrap_write(Sockbuf_IO_Desc *sbiod,
102 : void *buf, ber_len_t len)
103 : {
104 96 : struct ads_tlswrap *wrap =
105 : (struct ads_tlswrap *)sbiod->sbiod_pvt;
106 :
107 96 : return tstream_tls_sync_write(wrap->tls_sync, buf, len);
108 : }
109 :
110 192 : static int ads_tlswrap_ctrl(Sockbuf_IO_Desc *sbiod, int opt, void *arg)
111 : {
112 192 : struct ads_tlswrap *wrap =
113 : (struct ads_tlswrap *)sbiod->sbiod_pvt;
114 0 : int ret;
115 :
116 192 : switch (opt) {
117 192 : case LBER_SB_OPT_DATA_READY:
118 192 : if (tstream_tls_sync_pending(wrap->tls_sync) > 0) {
119 48 : return 1;
120 : }
121 :
122 144 : ret = LBER_SBIOD_CTRL_NEXT(sbiod, opt, arg);
123 144 : break;
124 0 : default:
125 0 : ret = LBER_SBIOD_CTRL_NEXT(sbiod, opt, arg);
126 0 : break;
127 : }
128 :
129 144 : return ret;
130 : }
131 :
132 24 : static int ads_tlswrap_close(Sockbuf_IO_Desc *sbiod)
133 : {
134 24 : struct ads_tlswrap *wrap =
135 : (struct ads_tlswrap *)sbiod->sbiod_pvt;
136 :
137 24 : TALLOC_FREE(wrap->tls_sync);
138 24 : TALLOC_FREE(wrap->tls_params);
139 :
140 24 : return 0;
141 : }
142 :
143 : static const Sockbuf_IO ads_tlswrap_sockbuf_io = {
144 : ads_tlswrap_setup, /* sbi_setup */
145 : ads_tlswrap_remove, /* sbi_remove */
146 : ads_tlswrap_ctrl, /* sbi_ctrl */
147 : ads_tlswrap_read, /* sbi_read */
148 : ads_tlswrap_write, /* sbi_write */
149 : ads_tlswrap_close /* sbi_close */
150 : };
151 :
152 24 : ADS_STATUS ads_setup_tls_wrapping(struct ads_tlswrap *wrap,
153 : LDAP *ld,
154 : const char *server_name)
155 : {
156 24 : TALLOC_CTX *frame = talloc_stackframe();
157 24 : Sockbuf_IO *io = discard_const_p(Sockbuf_IO, &ads_tlswrap_sockbuf_io);
158 24 : Sockbuf *sb = NULL;
159 24 : struct loadparm_context *lp_ctx = NULL;
160 0 : ADS_STATUS status;
161 0 : NTSTATUS ntstatus;
162 0 : unsigned to;
163 0 : int rc;
164 :
165 24 : rc = ldap_get_option(ld, LDAP_OPT_SOCKBUF, &sb);
166 24 : status = ADS_ERROR_LDAP(rc);
167 24 : if (!ADS_ERR_OK(status)) {
168 0 : TALLOC_FREE(frame);
169 0 : return status;
170 : }
171 :
172 24 : lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers());
173 24 : if (lp_ctx == NULL) {
174 0 : TALLOC_FREE(frame);
175 0 : return ADS_ERROR(LDAP_NO_MEMORY);
176 : }
177 :
178 24 : ntstatus = tstream_tls_params_client_lpcfg(wrap->mem_ctx,
179 : lp_ctx,
180 : server_name,
181 : &wrap->tls_params);
182 24 : if (!NT_STATUS_IS_OK(ntstatus)) {
183 0 : TALLOC_FREE(frame);
184 0 : return ADS_ERROR_NT(ntstatus);
185 : }
186 :
187 : /* setup the real wrapping callbacks */
188 24 : rc = ber_sockbuf_add_io(sb, io, LBER_SBIOD_LEVEL_TRANSPORT, wrap);
189 24 : status = ADS_ERROR_LDAP(rc);
190 24 : if (!ADS_ERR_OK(status)) {
191 0 : TALLOC_FREE(frame);
192 0 : return status;
193 : }
194 :
195 24 : to = lpcfg_ldap_connection_timeout(lp_ctx);
196 24 : wrap->endtime = timeval_current_ofs(to, 0);
197 24 : ntstatus = tstream_tls_sync_setup(wrap->tls_params,
198 : wrap,
199 : ads_tlswrap_send_function,
200 : ads_tlswrap_recv_function,
201 24 : wrap->mem_ctx,
202 : &wrap->tls_sync);
203 24 : wrap->endtime = timeval_zero();
204 24 : if (!NT_STATUS_IS_OK(ntstatus)) {
205 0 : ber_sockbuf_remove_io(sb, io, LBER_SBIOD_LEVEL_TRANSPORT);
206 0 : TALLOC_FREE(frame);
207 0 : return ADS_ERROR_NT(ntstatus);
208 : }
209 :
210 24 : TALLOC_FREE(frame);
211 24 : return ADS_SUCCESS;
212 : }
213 :
214 354 : const DATA_BLOB *ads_tls_channel_bindings(struct ads_tlswrap *wrap)
215 : {
216 354 : if (wrap->tls_sync == NULL) {
217 306 : return NULL;
218 : }
219 :
220 48 : return tstream_tls_sync_channel_bindings(wrap->tls_sync);
221 : }
222 : #else
223 0 : ADS_STATUS ads_setup_tls_wrapping(struct ads_tlswrap *wrap,
224 : LDAP *ld,
225 : const char *server_name)
226 : {
227 0 : return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
228 : }
229 0 : const DATA_BLOB *ads_tls_channel_bindings(struct ads_tlswrap *wrap)
230 : {
231 0 : return NULL;
232 : }
233 : #endif /* HAVE_ADS */
|