2 Unix SMB/CIFS implementation.
4 Copyright (C) Stefan Metzmacher 2007
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/>.
23 void ndr_print_ads_saslwrap_struct(struct ndr_print
*ndr
, const char *name
, const struct ads_saslwrap
*r
)
25 ndr_print_struct(ndr
, name
, "saslwrap");
27 ndr_print_uint16(ndr
, "wrap_type", r
->wrap_type
);
28 #ifdef HAVE_LDAP_SASL_WRAPPING
29 ndr_print_ptr(ndr
, "sbiod", r
->sbiod
);
30 #endif /* HAVE_LDAP_SASL_WRAPPING */
31 ndr_print_ptr(ndr
, "mem_ctx", r
->mem_ctx
);
32 ndr_print_ptr(ndr
, "wrap_ops", r
->wrap_ops
);
33 ndr_print_ptr(ndr
, "wrap_private_data", r
->wrap_private_data
);
34 ndr_print_struct(ndr
, name
, "in");
36 ndr_print_uint32(ndr
, "ofs", r
->in
.ofs
);
37 ndr_print_uint32(ndr
, "needed", r
->in
.needed
);
38 ndr_print_uint32(ndr
, "left", r
->in
.left
);
39 ndr_print_uint32(ndr
, "max_wrapped", r
->in
.max_wrapped
);
40 ndr_print_uint32(ndr
, "min_wrapped", r
->in
.min_wrapped
);
41 ndr_print_uint32(ndr
, "size", r
->in
.size
);
42 ndr_print_array_uint8(ndr
, "buf", r
->in
.buf
, r
->in
.size
);
44 ndr_print_struct(ndr
, name
, "out");
46 ndr_print_uint32(ndr
, "ofs", r
->out
.ofs
);
47 ndr_print_uint32(ndr
, "left", r
->out
.left
);
48 ndr_print_uint32(ndr
, "max_unwrapped", r
->out
.max_unwrapped
);
49 ndr_print_uint32(ndr
, "sig_size", r
->out
.sig_size
);
50 ndr_print_uint32(ndr
, "size", r
->out
.size
);
51 ndr_print_array_uint8(ndr
, "buf", r
->out
.buf
, r
->out
.size
);
55 #ifdef HAVE_LDAP_SASL_WRAPPING
57 static int ads_saslwrap_setup(Sockbuf_IO_Desc
*sbiod
, void *arg
)
59 struct ads_saslwrap
*wrap
= (struct ads_saslwrap
*)arg
;
63 sbiod
->sbiod_pvt
= wrap
;
68 static int ads_saslwrap_remove(Sockbuf_IO_Desc
*sbiod
)
73 static ber_slen_t
ads_saslwrap_prepare_inbuf(struct ads_saslwrap
*wrap
)
78 wrap
->in
.size
= 4 + wrap
->in
.min_wrapped
;
79 wrap
->in
.buf
= talloc_array(wrap
->mem_ctx
,
80 uint8_t, wrap
->in
.size
);
88 static ber_slen_t
ads_saslwrap_grow_inbuf(struct ads_saslwrap
*wrap
)
90 if (wrap
->in
.size
== (4 + wrap
->in
.needed
)) {
94 wrap
->in
.size
= 4 + wrap
->in
.needed
;
95 wrap
->in
.buf
= talloc_realloc(wrap
->mem_ctx
,
97 uint8_t, wrap
->in
.size
);
105 static void ads_saslwrap_shrink_inbuf(struct ads_saslwrap
*wrap
)
107 talloc_free(wrap
->in
.buf
);
116 static ber_slen_t
ads_saslwrap_read(Sockbuf_IO_Desc
*sbiod
,
117 void *buf
, ber_len_t len
)
119 struct ads_saslwrap
*wrap
=
120 (struct ads_saslwrap
*)sbiod
->sbiod_pvt
;
123 /* If ofs < 4 it means we don't have read the length header yet */
124 if (wrap
->in
.ofs
< 4) {
125 ret
= ads_saslwrap_prepare_inbuf(wrap
);
126 if (ret
< 0) return ret
;
128 ret
= LBER_SBIOD_READ_NEXT(sbiod
,
129 wrap
->in
.buf
+ wrap
->in
.ofs
,
131 if (ret
<= 0) return ret
;
134 if (wrap
->in
.ofs
< 4) goto eagain
;
136 wrap
->in
.needed
= RIVAL(wrap
->in
.buf
, 0);
137 if (wrap
->in
.needed
> wrap
->in
.max_wrapped
) {
141 if (wrap
->in
.needed
< wrap
->in
.min_wrapped
) {
146 ret
= ads_saslwrap_grow_inbuf(wrap
);
147 if (ret
< 0) return ret
;
151 * if there's more data needed from the remote end,
152 * we need to read more
154 if (wrap
->in
.needed
> 0) {
155 ret
= LBER_SBIOD_READ_NEXT(sbiod
,
156 wrap
->in
.buf
+ wrap
->in
.ofs
,
158 if (ret
<= 0) return ret
;
160 wrap
->in
.needed
-= ret
;
162 if (wrap
->in
.needed
> 0) goto eagain
;
166 * if we have a complete packet and have not yet unwrapped it
167 * we need to call the mech specific unwrap() hook
169 if (wrap
->in
.needed
== 0 && wrap
->in
.left
== 0) {
171 status
= wrap
->wrap_ops
->unwrap(wrap
);
172 if (!ADS_ERR_OK(status
)) {
179 * if we have unwrapped data give it to the caller
181 if (wrap
->in
.left
> 0) {
182 ret
= MIN(wrap
->in
.left
, len
);
183 memcpy(buf
, wrap
->in
.buf
+ wrap
->in
.ofs
, ret
);
185 wrap
->in
.left
-= ret
;
188 * if no more is left shrink the inbuf,
189 * this will trigger reading a new SASL packet
190 * from the remote stream in the next call
192 if (wrap
->in
.left
== 0) {
193 ads_saslwrap_shrink_inbuf(wrap
);
200 * if we don't have anything for the caller yet,
201 * tell him to ask again
208 static ber_slen_t
ads_saslwrap_prepare_outbuf(struct ads_saslwrap
*wrap
,
213 wrap
->out
.size
= 4 + wrap
->out
.sig_size
+ len
;
214 wrap
->out
.buf
= talloc_array(wrap
->mem_ctx
,
215 uint8_t, wrap
->out
.size
);
216 if (!wrap
->out
.buf
) {
223 static void ads_saslwrap_shrink_outbuf(struct ads_saslwrap
*wrap
)
225 talloc_free(wrap
->out
.buf
);
227 wrap
->out
.buf
= NULL
;
233 static ber_slen_t
ads_saslwrap_write(Sockbuf_IO_Desc
*sbiod
,
234 void *buf
, ber_len_t len
)
236 struct ads_saslwrap
*wrap
=
237 (struct ads_saslwrap
*)sbiod
->sbiod_pvt
;
238 ber_slen_t ret
, rlen
;
240 /* if the buffer is empty, we need to wrap in incoming buffer */
241 if (wrap
->out
.left
== 0) {
249 rlen
= MIN(len
, wrap
->out
.max_unwrapped
);
251 ret
= ads_saslwrap_prepare_outbuf(wrap
, rlen
);
252 if (ret
< 0) return ret
;
254 status
= wrap
->wrap_ops
->wrap(wrap
, (uint8_t *)buf
, rlen
);
255 if (!ADS_ERR_OK(status
)) {
260 RSIVAL(wrap
->out
.buf
, 0, wrap
->out
.left
- 4);
265 ret
= LBER_SBIOD_WRITE_NEXT(sbiod
,
266 wrap
->out
.buf
+ wrap
->out
.ofs
,
268 if (ret
<= 0) return ret
;
269 wrap
->out
.ofs
+= ret
;
270 wrap
->out
.left
-= ret
;
272 if (wrap
->out
.left
== 0) {
273 ads_saslwrap_shrink_outbuf(wrap
);
276 if (rlen
> 0) return rlen
;
282 static int ads_saslwrap_ctrl(Sockbuf_IO_Desc
*sbiod
, int opt
, void *arg
)
284 struct ads_saslwrap
*wrap
=
285 (struct ads_saslwrap
*)sbiod
->sbiod_pvt
;
289 case LBER_SB_OPT_DATA_READY
:
290 if (wrap
->in
.left
> 0) {
293 ret
= LBER_SBIOD_CTRL_NEXT(sbiod
, opt
, arg
);
296 ret
= LBER_SBIOD_CTRL_NEXT(sbiod
, opt
, arg
);
303 static int ads_saslwrap_close(Sockbuf_IO_Desc
*sbiod
)
308 static const Sockbuf_IO ads_saslwrap_sockbuf_io
= {
309 ads_saslwrap_setup
, /* sbi_setup */
310 ads_saslwrap_remove
, /* sbi_remove */
311 ads_saslwrap_ctrl
, /* sbi_ctrl */
312 ads_saslwrap_read
, /* sbi_read */
313 ads_saslwrap_write
, /* sbi_write */
314 ads_saslwrap_close
/* sbi_close */
317 ADS_STATUS
ads_setup_sasl_wrapping(struct ads_saslwrap
*wrap
, LDAP
*ld
,
318 const struct ads_saslwrap_ops
*ops
,
323 Sockbuf_IO
*io
= discard_const_p(Sockbuf_IO
, &ads_saslwrap_sockbuf_io
);
326 rc
= ldap_get_option(ld
, LDAP_OPT_SOCKBUF
, &sb
);
327 status
= ADS_ERROR_LDAP(rc
);
328 if (!ADS_ERR_OK(status
)) {
332 /* setup the real wrapping callbacks */
333 rc
= ber_sockbuf_add_io(sb
, io
, LBER_SBIOD_LEVEL_TRANSPORT
, wrap
);
334 status
= ADS_ERROR_LDAP(rc
);
335 if (!ADS_ERR_OK(status
)) {
339 wrap
->wrap_ops
= ops
;
340 wrap
->wrap_private_data
= private_data
;
345 ADS_STATUS
ads_setup_sasl_wrapping(struct ads_saslwrap
*wrap
, LDAP
*ld
,
346 const struct ads_saslwrap_ops
*ops
,
349 return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED
);
351 #endif /* HAVE_LDAP_SASL_WRAPPING */