2 Unix SMB/CIFS implementation.
4 tstream based generic authentication interface
6 Copyright (c) 2010 Stefan Metzmacher
7 Copyright (c) 2010 Andreas Schneider <asn@redhat.com>
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "system/network.h"
25 #include "auth/gensec/gensec.h"
26 #include "auth/gensec/gensec_proto.h"
27 #include "auth/gensec/gensec_tstream.h"
28 #include "lib/tsocket/tsocket.h"
29 #include "lib/tsocket/tsocket_internal.h"
30 #include "auth/gensec/gensec_toplevel_proto.h"
32 static const struct tstream_context_ops tstream_gensec_ops
;
34 struct tstream_gensec
{
35 struct tstream_context
*plain_stream
;
37 struct gensec_security
*gensec_security
;
42 size_t max_unwrapped_size
;
43 size_t max_wrapped_size
;
53 _PUBLIC_ NTSTATUS
_gensec_create_tstream(TALLOC_CTX
*mem_ctx
,
54 struct gensec_security
*gensec_security
,
55 struct tstream_context
*plain_stream
,
56 struct tstream_context
**_gensec_stream
,
59 struct tstream_context
*gensec_stream
;
60 struct tstream_gensec
*tgss
;
62 gensec_stream
= tstream_context_create(mem_ctx
,
65 struct tstream_gensec
,
67 if (gensec_stream
== NULL
) {
68 return NT_STATUS_NO_MEMORY
;
71 tgss
->plain_stream
= plain_stream
;
72 tgss
->gensec_security
= gensec_security
;
75 if (!gensec_have_feature(gensec_security
, GENSEC_FEATURE_SIGN
) &&
76 !gensec_have_feature(gensec_security
, GENSEC_FEATURE_SEAL
)) {
77 talloc_free(gensec_stream
);
78 return NT_STATUS_INVALID_PARAMETER
;
81 tgss
->write
.max_unwrapped_size
= gensec_max_input_size(gensec_security
);
82 tgss
->write
.max_wrapped_size
= gensec_max_wrapped_size(gensec_security
);
84 ZERO_STRUCT(tgss
->read
);
86 *_gensec_stream
= gensec_stream
;
90 static ssize_t
tstream_gensec_pending_bytes(struct tstream_context
*stream
)
92 struct tstream_gensec
*tgss
=
93 tstream_context_data(stream
,
94 struct tstream_gensec
);
96 if (tgss
->error
!= 0) {
101 return tgss
->read
.left
;
104 struct tstream_gensec_readv_state
{
105 struct tevent_context
*ev
;
106 struct tstream_context
*stream
;
108 struct iovec
*vector
;
121 static void tstream_gensec_readv_wrapped_next(struct tevent_req
*req
);
123 static struct tevent_req
*tstream_gensec_readv_send(TALLOC_CTX
*mem_ctx
,
124 struct tevent_context
*ev
,
125 struct tstream_context
*stream
,
126 struct iovec
*vector
,
129 struct tstream_gensec
*tgss
=
130 tstream_context_data(stream
,
131 struct tstream_gensec
);
132 struct tevent_req
*req
;
133 struct tstream_gensec_readv_state
*state
;
135 req
= tevent_req_create(mem_ctx
, &state
,
136 struct tstream_gensec_readv_state
);
141 if (tgss
->error
!= 0) {
142 tevent_req_error(req
, tgss
->error
);
143 return tevent_req_post(req
, ev
);
147 state
->stream
= stream
;
151 * we make a copy of the vector so we can change the structure
153 state
->vector
= talloc_array(state
, struct iovec
, count
);
154 if (tevent_req_nomem(state
->vector
, req
)) {
155 return tevent_req_post(req
, ev
);
157 memcpy(state
->vector
, vector
, sizeof(struct iovec
) * count
);
158 state
->count
= count
;
160 tstream_gensec_readv_wrapped_next(req
);
161 if (!tevent_req_is_in_progress(req
)) {
162 return tevent_req_post(req
, ev
);
168 static int tstream_gensec_readv_next_vector(struct tstream_context
*unix_stream
,
171 struct iovec
**_vector
,
173 static void tstream_gensec_readv_wrapped_done(struct tevent_req
*subreq
);
175 static void tstream_gensec_readv_wrapped_next(struct tevent_req
*req
)
177 struct tstream_gensec_readv_state
*state
=
179 struct tstream_gensec_readv_state
);
180 struct tstream_gensec
*tgss
=
181 tstream_context_data(state
->stream
,
182 struct tstream_gensec
);
183 struct tevent_req
*subreq
;
186 * copy the pending buffer first
188 while (tgss
->read
.left
> 0 && state
->count
> 0) {
189 uint8_t *base
= (uint8_t *)state
->vector
[0].iov_base
;
190 size_t len
= MIN(tgss
->read
.left
, state
->vector
[0].iov_len
);
192 memcpy(base
, tgss
->read
.unwrapped
.data
+ tgss
->read
.ofs
, len
);
195 state
->vector
[0].iov_base
= (char *) base
;
196 state
->vector
[0].iov_len
-= len
;
198 tgss
->read
.ofs
+= len
;
199 tgss
->read
.left
-= len
;
201 if (state
->vector
[0].iov_len
== 0) {
209 if (state
->count
== 0) {
210 tevent_req_done(req
);
214 data_blob_free(&tgss
->read
.unwrapped
);
215 ZERO_STRUCT(state
->wrapped
);
217 subreq
= tstream_readv_pdu_send(state
, state
->ev
,
219 tstream_gensec_readv_next_vector
,
221 if (tevent_req_nomem(subreq
, req
)) {
224 tevent_req_set_callback(subreq
, tstream_gensec_readv_wrapped_done
, req
);
227 static int tstream_gensec_readv_next_vector(struct tstream_context
*unix_stream
,
230 struct iovec
**_vector
,
233 struct tstream_gensec_readv_state
*state
=
234 talloc_get_type_abort(private_data
,
235 struct tstream_gensec_readv_state
);
236 struct iovec
*vector
;
239 /* we need to get a message header */
240 vector
= talloc_array(mem_ctx
, struct iovec
, count
);
245 if (!state
->wrapped
.asked_for_hdr
) {
246 state
->wrapped
.asked_for_hdr
= true;
247 vector
[0].iov_base
= (char *)state
->wrapped
.hdr
;
248 vector
[0].iov_len
= sizeof(state
->wrapped
.hdr
);
249 } else if (!state
->wrapped
.asked_for_blob
) {
250 state
->wrapped
.asked_for_blob
= true;
253 msg_len
= RIVAL(state
->wrapped
.hdr
, 0);
255 if (msg_len
> 0x00FFFFFF) {
265 state
->wrapped
.blob
= data_blob_talloc(state
, NULL
, msg_len
);
266 if (state
->wrapped
.blob
.data
== NULL
) {
270 vector
[0].iov_base
= (char *)state
->wrapped
.blob
.data
;
271 vector
[0].iov_len
= state
->wrapped
.blob
.length
;
283 static void tstream_gensec_readv_wrapped_done(struct tevent_req
*subreq
)
285 struct tevent_req
*req
=
286 tevent_req_callback_data(subreq
,
288 struct tstream_gensec_readv_state
*state
=
290 struct tstream_gensec_readv_state
);
291 struct tstream_gensec
*tgss
=
292 tstream_context_data(state
->stream
,
293 struct tstream_gensec
);
298 ret
= tstream_readv_pdu_recv(subreq
, &sys_errno
);
301 tgss
->error
= sys_errno
;
302 tevent_req_error(req
, sys_errno
);
306 status
= gensec_unwrap(tgss
->gensec_security
,
308 &state
->wrapped
.blob
,
309 &tgss
->read
.unwrapped
);
310 if (!NT_STATUS_IS_OK(status
)) {
312 tevent_req_error(req
, tgss
->error
);
316 data_blob_free(&state
->wrapped
.blob
);
318 talloc_steal(tgss
, tgss
->read
.unwrapped
.data
);
319 tgss
->read
.left
= tgss
->read
.unwrapped
.length
;
322 tstream_gensec_readv_wrapped_next(req
);
325 static int tstream_gensec_readv_recv(struct tevent_req
*req
, int *perrno
)
327 struct tstream_gensec_readv_state
*state
=
329 struct tstream_gensec_readv_state
);
332 ret
= tsocket_simple_int_recv(req
, perrno
);
337 tevent_req_received(req
);
341 struct tstream_gensec_writev_state
{
342 struct tevent_context
*ev
;
343 struct tstream_context
*stream
;
345 struct iovec
*vector
;
363 static void tstream_gensec_writev_wrapped_next(struct tevent_req
*req
);
365 static struct tevent_req
*tstream_gensec_writev_send(TALLOC_CTX
*mem_ctx
,
366 struct tevent_context
*ev
,
367 struct tstream_context
*stream
,
368 const struct iovec
*vector
,
371 struct tstream_gensec
*tgss
=
372 tstream_context_data(stream
,
373 struct tstream_gensec
);
374 struct tevent_req
*req
;
375 struct tstream_gensec_writev_state
*state
;
380 req
= tevent_req_create(mem_ctx
, &state
,
381 struct tstream_gensec_writev_state
);
386 if (tgss
->error
!= 0) {
387 tevent_req_error(req
, tgss
->error
);
388 return tevent_req_post(req
, ev
);
392 state
->stream
= stream
;
396 * we make a copy of the vector so we can change the structure
398 state
->vector
= talloc_array(state
, struct iovec
, count
);
399 if (tevent_req_nomem(state
->vector
, req
)) {
400 return tevent_req_post(req
, ev
);
402 memcpy(state
->vector
, vector
, sizeof(struct iovec
) * count
);
403 state
->count
= count
;
406 for (i
= 0; i
< count
; i
++) {
408 * the generic tstream code makes sure that
411 total
+= vector
[i
].iov_len
;
415 * We may need to send data in chunks.
417 chunk
= MIN(total
, tgss
->write
.max_unwrapped_size
);
419 state
->unwrapped
.blob
= data_blob_talloc(state
, NULL
, chunk
);
420 if (tevent_req_nomem(state
->unwrapped
.blob
.data
, req
)) {
421 return tevent_req_post(req
, ev
);
424 tstream_gensec_writev_wrapped_next(req
);
425 if (!tevent_req_is_in_progress(req
)) {
426 return tevent_req_post(req
, ev
);
432 static void tstream_gensec_writev_wrapped_done(struct tevent_req
*subreq
);
434 static void tstream_gensec_writev_wrapped_next(struct tevent_req
*req
)
436 struct tstream_gensec_writev_state
*state
=
438 struct tstream_gensec_writev_state
);
439 struct tstream_gensec
*tgss
=
440 tstream_context_data(state
->stream
,
441 struct tstream_gensec
);
442 struct tevent_req
*subreq
;
445 data_blob_free(&state
->wrapped
.blob
);
447 state
->unwrapped
.left
= state
->unwrapped
.blob
.length
;
448 state
->unwrapped
.ofs
= 0;
451 * first fill our buffer
453 while (state
->unwrapped
.left
> 0 && state
->count
> 0) {
454 uint8_t *base
= (uint8_t *)state
->vector
[0].iov_base
;
455 size_t len
= MIN(state
->unwrapped
.left
, state
->vector
[0].iov_len
);
457 memcpy(state
->unwrapped
.blob
.data
+ state
->unwrapped
.ofs
, base
, len
);
460 state
->vector
[0].iov_base
= (char *) base
;
461 state
->vector
[0].iov_len
-= len
;
463 state
->unwrapped
.ofs
+= len
;
464 state
->unwrapped
.left
-= len
;
466 if (state
->vector
[0].iov_len
== 0) {
474 if (state
->unwrapped
.ofs
== 0) {
475 tevent_req_done(req
);
479 state
->unwrapped
.blob
.length
= state
->unwrapped
.ofs
;
481 status
= gensec_wrap(tgss
->gensec_security
,
483 &state
->unwrapped
.blob
,
484 &state
->wrapped
.blob
);
485 if (!NT_STATUS_IS_OK(status
)) {
487 tevent_req_error(req
, tgss
->error
);
491 RSIVAL(state
->wrapped
.hdr
, 0, state
->wrapped
.blob
.length
);
493 state
->wrapped
.iov
[0].iov_base
= (void *)state
->wrapped
.hdr
;
494 state
->wrapped
.iov
[0].iov_len
= sizeof(state
->wrapped
.hdr
);
495 state
->wrapped
.iov
[1].iov_base
= (void *)state
->wrapped
.blob
.data
;
496 state
->wrapped
.iov
[1].iov_len
= state
->wrapped
.blob
.length
;
498 subreq
= tstream_writev_send(state
, state
->ev
,
500 state
->wrapped
.iov
, 2);
501 if (tevent_req_nomem(subreq
, req
)) {
504 tevent_req_set_callback(subreq
,
505 tstream_gensec_writev_wrapped_done
,
509 static void tstream_gensec_writev_wrapped_done(struct tevent_req
*subreq
)
511 struct tevent_req
*req
=
512 tevent_req_callback_data(subreq
,
514 struct tstream_gensec_writev_state
*state
=
516 struct tstream_gensec_writev_state
);
517 struct tstream_gensec
*tgss
=
518 tstream_context_data(state
->stream
,
519 struct tstream_gensec
);
523 ret
= tstream_writev_recv(subreq
, &sys_errno
);
526 tgss
->error
= sys_errno
;
527 tevent_req_error(req
, sys_errno
);
531 tstream_gensec_writev_wrapped_next(req
);
534 static int tstream_gensec_writev_recv(struct tevent_req
*req
,
537 struct tstream_gensec_writev_state
*state
=
539 struct tstream_gensec_writev_state
);
542 ret
= tsocket_simple_int_recv(req
, perrno
);
547 tevent_req_received(req
);
551 struct tstream_gensec_disconnect_state
{
555 static struct tevent_req
*tstream_gensec_disconnect_send(TALLOC_CTX
*mem_ctx
,
556 struct tevent_context
*ev
,
557 struct tstream_context
*stream
)
559 struct tstream_gensec
*tgss
=
560 tstream_context_data(stream
,
561 struct tstream_gensec
);
562 struct tevent_req
*req
;
563 struct tstream_gensec_disconnect_state
*state
;
565 req
= tevent_req_create(mem_ctx
, &state
,
566 struct tstream_gensec_disconnect_state
);
571 if (tgss
->error
!= 0) {
572 tevent_req_error(req
, tgss
->error
);
573 return tevent_req_post(req
, ev
);
577 * The caller is responsible to do the real disconnect
578 * on the plain stream!
580 tgss
->plain_stream
= NULL
;
581 tgss
->error
= ENOTCONN
;
583 tevent_req_done(req
);
584 return tevent_req_post(req
, ev
);
587 static int tstream_gensec_disconnect_recv(struct tevent_req
*req
,
592 ret
= tsocket_simple_int_recv(req
, perrno
);
594 tevent_req_received(req
);
598 static const struct tstream_context_ops tstream_gensec_ops
= {
601 .pending_bytes
= tstream_gensec_pending_bytes
,
603 .readv_send
= tstream_gensec_readv_send
,
604 .readv_recv
= tstream_gensec_readv_recv
,
606 .writev_send
= tstream_gensec_writev_send
,
607 .writev_recv
= tstream_gensec_writev_recv
,
609 .disconnect_send
= tstream_gensec_disconnect_send
,
610 .disconnect_recv
= tstream_gensec_disconnect_recv
,