Coverage Report

Created: 2025-12-31 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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 */