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