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
) {
252 state
->wrapped
.asked_for_blob
= true;
254 msg_len
= RIVAL(state
->wrapped
.hdr
, 0);
256 if (msg_len
> 0x00FFFFFF) {
266 state
->wrapped
.blob
= data_blob_talloc(state
, NULL
, msg_len
);
267 if (state
->wrapped
.blob
.data
== NULL
) {
271 vector
[0].iov_base
= (char *)state
->wrapped
.blob
.data
;
272 vector
[0].iov_len
= state
->wrapped
.blob
.length
;
284 static void tstream_gensec_readv_wrapped_done(struct tevent_req
*subreq
)
286 struct tevent_req
*req
=
287 tevent_req_callback_data(subreq
,
289 struct tstream_gensec_readv_state
*state
=
291 struct tstream_gensec_readv_state
);
292 struct tstream_gensec
*tgss
=
293 tstream_context_data(state
->stream
,
294 struct tstream_gensec
);
299 ret
= tstream_readv_pdu_recv(subreq
, &sys_errno
);
302 tgss
->error
= sys_errno
;
303 tevent_req_error(req
, sys_errno
);
307 status
= gensec_unwrap(tgss
->gensec_security
,
309 &state
->wrapped
.blob
,
310 &tgss
->read
.unwrapped
);
311 if (!NT_STATUS_IS_OK(status
)) {
313 tevent_req_error(req
, tgss
->error
);
317 data_blob_free(&state
->wrapped
.blob
);
319 talloc_steal(tgss
, tgss
->read
.unwrapped
.data
);
320 tgss
->read
.left
= tgss
->read
.unwrapped
.length
;
323 tstream_gensec_readv_wrapped_next(req
);
326 static int tstream_gensec_readv_recv(struct tevent_req
*req
, int *perrno
)
328 struct tstream_gensec_readv_state
*state
=
330 struct tstream_gensec_readv_state
);
333 ret
= tsocket_simple_int_recv(req
, perrno
);
338 tevent_req_received(req
);
342 struct tstream_gensec_writev_state
{
343 struct tevent_context
*ev
;
344 struct tstream_context
*stream
;
346 struct iovec
*vector
;
364 static void tstream_gensec_writev_wrapped_next(struct tevent_req
*req
);
366 static struct tevent_req
*tstream_gensec_writev_send(TALLOC_CTX
*mem_ctx
,
367 struct tevent_context
*ev
,
368 struct tstream_context
*stream
,
369 const struct iovec
*vector
,
372 struct tstream_gensec
*tgss
=
373 tstream_context_data(stream
,
374 struct tstream_gensec
);
375 struct tevent_req
*req
;
376 struct tstream_gensec_writev_state
*state
;
381 req
= tevent_req_create(mem_ctx
, &state
,
382 struct tstream_gensec_writev_state
);
387 if (tgss
->error
!= 0) {
388 tevent_req_error(req
, tgss
->error
);
389 return tevent_req_post(req
, ev
);
393 state
->stream
= stream
;
397 * we make a copy of the vector so we can change the structure
399 state
->vector
= talloc_array(state
, struct iovec
, count
);
400 if (tevent_req_nomem(state
->vector
, req
)) {
401 return tevent_req_post(req
, ev
);
403 memcpy(state
->vector
, vector
, sizeof(struct iovec
) * count
);
404 state
->count
= count
;
407 for (i
= 0; i
< count
; i
++) {
409 * the generic tstream code makes sure that
412 total
+= vector
[i
].iov_len
;
416 * We may need to send data in chunks.
418 chunk
= MIN(total
, tgss
->write
.max_unwrapped_size
);
420 state
->unwrapped
.blob
= data_blob_talloc(state
, NULL
, chunk
);
421 if (tevent_req_nomem(state
->unwrapped
.blob
.data
, req
)) {
422 return tevent_req_post(req
, ev
);
425 tstream_gensec_writev_wrapped_next(req
);
426 if (!tevent_req_is_in_progress(req
)) {
427 return tevent_req_post(req
, ev
);
433 static void tstream_gensec_writev_wrapped_done(struct tevent_req
*subreq
);
435 static void tstream_gensec_writev_wrapped_next(struct tevent_req
*req
)
437 struct tstream_gensec_writev_state
*state
=
439 struct tstream_gensec_writev_state
);
440 struct tstream_gensec
*tgss
=
441 tstream_context_data(state
->stream
,
442 struct tstream_gensec
);
443 struct tevent_req
*subreq
;
446 data_blob_free(&state
->wrapped
.blob
);
448 state
->unwrapped
.left
= state
->unwrapped
.blob
.length
;
449 state
->unwrapped
.ofs
= 0;
452 * first fill our buffer
454 while (state
->unwrapped
.left
> 0 && state
->count
> 0) {
455 uint8_t *base
= (uint8_t *)state
->vector
[0].iov_base
;
456 size_t len
= MIN(state
->unwrapped
.left
, state
->vector
[0].iov_len
);
458 memcpy(state
->unwrapped
.blob
.data
+ state
->unwrapped
.ofs
, base
, len
);
461 state
->vector
[0].iov_base
= (char *) base
;
462 state
->vector
[0].iov_len
-= len
;
464 state
->unwrapped
.ofs
+= len
;
465 state
->unwrapped
.left
-= len
;
467 if (state
->vector
[0].iov_len
== 0) {
475 if (state
->unwrapped
.ofs
== 0) {
476 tevent_req_done(req
);
480 state
->unwrapped
.blob
.length
= state
->unwrapped
.ofs
;
482 status
= gensec_wrap(tgss
->gensec_security
,
484 &state
->unwrapped
.blob
,
485 &state
->wrapped
.blob
);
486 if (!NT_STATUS_IS_OK(status
)) {
488 tevent_req_error(req
, tgss
->error
);
492 RSIVAL(state
->wrapped
.hdr
, 0, state
->wrapped
.blob
.length
);
494 state
->wrapped
.iov
[0].iov_base
= (void *)state
->wrapped
.hdr
;
495 state
->wrapped
.iov
[0].iov_len
= sizeof(state
->wrapped
.hdr
);
496 state
->wrapped
.iov
[1].iov_base
= (void *)state
->wrapped
.blob
.data
;
497 state
->wrapped
.iov
[1].iov_len
= state
->wrapped
.blob
.length
;
499 subreq
= tstream_writev_send(state
, state
->ev
,
501 state
->wrapped
.iov
, 2);
502 if (tevent_req_nomem(subreq
, req
)) {
505 tevent_req_set_callback(subreq
,
506 tstream_gensec_writev_wrapped_done
,
510 static void tstream_gensec_writev_wrapped_done(struct tevent_req
*subreq
)
512 struct tevent_req
*req
=
513 tevent_req_callback_data(subreq
,
515 struct tstream_gensec_writev_state
*state
=
517 struct tstream_gensec_writev_state
);
518 struct tstream_gensec
*tgss
=
519 tstream_context_data(state
->stream
,
520 struct tstream_gensec
);
524 ret
= tstream_writev_recv(subreq
, &sys_errno
);
527 tgss
->error
= sys_errno
;
528 tevent_req_error(req
, sys_errno
);
532 tstream_gensec_writev_wrapped_next(req
);
535 static int tstream_gensec_writev_recv(struct tevent_req
*req
,
538 struct tstream_gensec_writev_state
*state
=
540 struct tstream_gensec_writev_state
);
543 ret
= tsocket_simple_int_recv(req
, perrno
);
548 tevent_req_received(req
);
552 struct tstream_gensec_disconnect_state
{
556 static struct tevent_req
*tstream_gensec_disconnect_send(TALLOC_CTX
*mem_ctx
,
557 struct tevent_context
*ev
,
558 struct tstream_context
*stream
)
560 struct tstream_gensec
*tgss
=
561 tstream_context_data(stream
,
562 struct tstream_gensec
);
563 struct tevent_req
*req
;
564 struct tstream_gensec_disconnect_state
*state
;
566 req
= tevent_req_create(mem_ctx
, &state
,
567 struct tstream_gensec_disconnect_state
);
572 if (tgss
->error
!= 0) {
573 tevent_req_error(req
, tgss
->error
);
574 return tevent_req_post(req
, ev
);
578 * The caller is responsible to do the real disconnect
579 * on the plain stream!
581 tgss
->plain_stream
= NULL
;
582 tgss
->error
= ENOTCONN
;
584 tevent_req_done(req
);
585 return tevent_req_post(req
, ev
);
588 static int tstream_gensec_disconnect_recv(struct tevent_req
*req
,
593 ret
= tsocket_simple_int_recv(req
, perrno
);
595 tevent_req_received(req
);
599 static const struct tstream_context_ops tstream_gensec_ops
= {
602 .pending_bytes
= tstream_gensec_pending_bytes
,
604 .readv_send
= tstream_gensec_readv_send
,
605 .readv_recv
= tstream_gensec_readv_recv
,
607 .writev_send
= tstream_gensec_writev_send
,
608 .writev_recv
= tstream_gensec_writev_recv
,
610 .disconnect_send
= tstream_gensec_disconnect_send
,
611 .disconnect_recv
= tstream_gensec_disconnect_recv
,