1/* 2 Unix SMB/CIFS implementation. 3 4 Copyright (C) Stefan Metzmacher 2009 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 "system/network.h" 22#include "../util/tevent_unix.h" 23#include "../lib/tsocket/tsocket.h" 24#include "../lib/tsocket/tsocket_internal.h" 25#include "../librpc/gen_ndr/ndr_named_pipe_auth.h" 26#include "../libcli/named_pipe_auth/npa_tstream.h" 27#include "libcli/raw/smb.h" 28 29static const struct tstream_context_ops tstream_npa_ops; 30 31struct tstream_npa { 32 struct tstream_context *unix_stream; 33 34 uint16_t file_type; 35 36 struct iovec pending; 37}; 38 39struct tstream_npa_connect_state { 40 struct { 41 struct tevent_context *ev; 42 struct smb_iconv_convenience *smb_iconv_c; 43 } caller; 44 45 const char *unix_path; 46 struct tsocket_address *unix_laddr; 47 struct tsocket_address *unix_raddr; 48 struct tstream_context *unix_stream; 49 50 struct named_pipe_auth_req auth_req; 51 DATA_BLOB auth_req_blob; 52 struct iovec auth_req_iov; 53 54 struct named_pipe_auth_rep auth_rep; 55 DATA_BLOB auth_rep_blob; 56}; 57 58static void tstream_npa_connect_unix_done(struct tevent_req *subreq); 59 60struct tevent_req *tstream_npa_connect_send(TALLOC_CTX *mem_ctx, 61 struct tevent_context *ev, 62 struct smb_iconv_convenience *smb_iconv_c, 63 const char *directory, 64 const char *npipe, 65 const struct tsocket_address *client, 66 const char *client_name_in, 67 const struct tsocket_address *server, 68 const char *server_name, 69 const struct netr_SamInfo3 *sam_info3, 70 DATA_BLOB session_key, 71 DATA_BLOB delegated_creds) 72{ 73 struct tevent_req *req; 74 struct tstream_npa_connect_state *state; 75 struct tevent_req *subreq; 76 int ret; 77 enum ndr_err_code ndr_err; 78 79 req = tevent_req_create(mem_ctx, &state, 80 struct tstream_npa_connect_state); 81 if (!req) { 82 return NULL; 83 } 84 85 state->caller.ev = ev; 86 state->caller.smb_iconv_c = smb_iconv_c; 87 88 state->unix_path = talloc_asprintf(state, "%s/%s", 89 directory, 90 npipe); 91 if (tevent_req_nomem(state->unix_path, req)) { 92 goto post; 93 } 94 95 ret = tsocket_address_unix_from_path(state, 96 "", 97 &state->unix_laddr); 98 if (ret == -1) { 99 tevent_req_error(req, errno); 100 goto post; 101 } 102 103 ret = tsocket_address_unix_from_path(state, 104 state->unix_path, 105 &state->unix_raddr); 106 if (ret == -1) { 107 tevent_req_error(req, errno); 108 goto post; 109 } 110 111 ZERO_STRUCT(state->auth_req); 112 if (client) { 113 struct named_pipe_auth_req_info3 *info3; 114 115 if (!server) { 116 tevent_req_error(req, EINVAL); 117 goto post; 118 } 119 120 state->auth_req.level = 3; 121 info3 = &state->auth_req.info.info3; 122 123 info3->client_name = client_name_in; 124 info3->client_addr = tsocket_address_inet_addr_string(client, state); 125 if (!info3->client_addr) { 126 /* errno might be EINVAL */ 127 tevent_req_error(req, errno); 128 goto post; 129 } 130 info3->client_port = tsocket_address_inet_port(client); 131 if (!info3->client_name) { 132 info3->client_name = info3->client_addr; 133 } 134 135 info3->server_addr = tsocket_address_inet_addr_string(server, state); 136 if (!info3->server_addr) { 137 /* errno might be EINVAL */ 138 tevent_req_error(req, errno); 139 goto post; 140 } 141 info3->server_port = tsocket_address_inet_port(server); 142 if (!info3->server_name) { 143 info3->server_name = info3->server_addr; 144 } 145 146 info3->sam_info3 = discard_const_p(struct netr_SamInfo3, sam_info3); 147 info3->session_key_length = session_key.length; 148 info3->session_key = session_key.data; 149 info3->gssapi_delegated_creds_length = delegated_creds.length; 150 info3->gssapi_delegated_creds = delegated_creds.data; 151 152 } else if (sam_info3) { 153 state->auth_req.level = 1; 154 state->auth_req.info.info1 = *sam_info3; 155 } else { 156 state->auth_req.level = 0; 157 } 158 159 if (DEBUGLVL(10)) { 160 NDR_PRINT_DEBUG(named_pipe_auth_req, &state->auth_req); 161 } 162 163 ndr_err = ndr_push_struct_blob(&state->auth_req_blob, 164 state, smb_iconv_c, &state->auth_req, 165 (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_req); 166 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 167 tevent_req_error(req, EINVAL); 168 goto post; 169 } 170 171 state->auth_req_iov.iov_base = state->auth_req_blob.data; 172 state->auth_req_iov.iov_len = state->auth_req_blob.length; 173 174 subreq = tstream_unix_connect_send(state, 175 state->caller.ev, 176 state->unix_laddr, 177 state->unix_raddr); 178 if (tevent_req_nomem(subreq, req)) { 179 goto post; 180 } 181 tevent_req_set_callback(subreq, tstream_npa_connect_unix_done, req); 182 183 return req; 184 185post: 186 tevent_req_post(req, ev); 187 return req; 188} 189 190static void tstream_npa_connect_writev_done(struct tevent_req *subreq); 191 192static void tstream_npa_connect_unix_done(struct tevent_req *subreq) 193{ 194 struct tevent_req *req = 195 tevent_req_callback_data(subreq, 196 struct tevent_req); 197 struct tstream_npa_connect_state *state = 198 tevent_req_data(req, 199 struct tstream_npa_connect_state); 200 int ret; 201 int sys_errno; 202 203 ret = tstream_unix_connect_recv(subreq, &sys_errno, 204 state, &state->unix_stream); 205 TALLOC_FREE(subreq); 206 if (ret == -1) { 207 tevent_req_error(req, sys_errno); 208 return; 209 } 210 211 subreq = tstream_writev_send(state, 212 state->caller.ev, 213 state->unix_stream, 214 &state->auth_req_iov, 1); 215 if (tevent_req_nomem(subreq, req)) { 216 return; 217 } 218 tevent_req_set_callback(subreq, tstream_npa_connect_writev_done, req); 219} 220 221static int tstream_npa_connect_next_vector(struct tstream_context *unix_stream, 222 void *private_data, 223 TALLOC_CTX *mem_ctx, 224 struct iovec **_vector, 225 size_t *_count); 226static void tstream_npa_connect_readv_done(struct tevent_req *subreq); 227 228static void tstream_npa_connect_writev_done(struct tevent_req *subreq) 229{ 230 struct tevent_req *req = 231 tevent_req_callback_data(subreq, 232 struct tevent_req); 233 struct tstream_npa_connect_state *state = 234 tevent_req_data(req, 235 struct tstream_npa_connect_state); 236 int ret; 237 int sys_errno; 238 239 ret = tstream_writev_recv(subreq, &sys_errno); 240 TALLOC_FREE(subreq); 241 if (ret == -1) { 242 tevent_req_error(req, sys_errno); 243 return; 244 } 245 246 state->auth_rep_blob = data_blob_const(NULL, 0); 247 248 subreq = tstream_readv_pdu_send(state, state->caller.ev, 249 state->unix_stream, 250 tstream_npa_connect_next_vector, 251 state); 252 if (tevent_req_nomem(subreq, req)) { 253 return; 254 } 255 tevent_req_set_callback(subreq, tstream_npa_connect_readv_done, req); 256} 257 258static int tstream_npa_connect_next_vector(struct tstream_context *unix_stream, 259 void *private_data, 260 TALLOC_CTX *mem_ctx, 261 struct iovec **_vector, 262 size_t *_count) 263{ 264 struct tstream_npa_connect_state *state = talloc_get_type_abort(private_data, 265 struct tstream_npa_connect_state); 266 struct iovec *vector; 267 size_t count; 268 off_t ofs = 0; 269 270 if (state->auth_rep_blob.length == 0) { 271 state->auth_rep_blob = data_blob_talloc(state, NULL, 4); 272 if (!state->auth_rep_blob.data) { 273 return -1; 274 } 275 } else if (state->auth_rep_blob.length == 4) { 276 uint32_t msg_len; 277 278 ofs = 4; 279 280 msg_len = RIVAL(state->auth_rep_blob.data, 0); 281 282 if (msg_len > 0x00FFFFFF) { 283 errno = EMSGSIZE; 284 return -1; 285 } 286 287 if (msg_len == 0) { 288 errno = EMSGSIZE; 289 return -1; 290 } 291 292 msg_len += ofs; 293 294 state->auth_rep_blob.data = talloc_realloc(state, 295 state->auth_rep_blob.data, 296 uint8_t, msg_len); 297 if (!state->auth_rep_blob.data) { 298 return -1; 299 } 300 state->auth_rep_blob.length = msg_len; 301 } else { 302 *_vector = NULL; 303 *_count = 0; 304 return 0; 305 } 306 307 /* we need to get a message header */ 308 vector = talloc_array(mem_ctx, struct iovec, 1); 309 if (!vector) { 310 return -1; 311 } 312 vector[0].iov_base = state->auth_rep_blob.data + ofs; 313 vector[0].iov_len = state->auth_rep_blob.length - ofs; 314 count = 1; 315 316 *_vector = vector; 317 *_count = count; 318 return 0; 319} 320 321static void tstream_npa_connect_readv_done(struct tevent_req *subreq) 322{ 323 struct tevent_req *req = 324 tevent_req_callback_data(subreq, 325 struct tevent_req); 326 struct tstream_npa_connect_state *state = 327 tevent_req_data(req, 328 struct tstream_npa_connect_state); 329 int ret; 330 int sys_errno; 331 enum ndr_err_code ndr_err; 332 333 ret = tstream_readv_pdu_recv(subreq, &sys_errno); 334 TALLOC_FREE(subreq); 335 if (ret == -1) { 336 tevent_req_error(req, sys_errno); 337 return; 338 } 339 340 DEBUG(10,("name_pipe_auth_rep(client)[%u]\n", 341 (uint32_t)state->auth_rep_blob.length)); 342 dump_data(11, state->auth_rep_blob.data, state->auth_rep_blob.length); 343 344 ndr_err = ndr_pull_struct_blob( 345 &state->auth_rep_blob, state, 346 state->caller.smb_iconv_c, &state->auth_rep, 347 (ndr_pull_flags_fn_t)ndr_pull_named_pipe_auth_rep); 348 349 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 350 DEBUG(0, ("ndr_pull_named_pipe_auth_rep failed: %s\n", 351 ndr_map_error2string(ndr_err))); 352 tevent_req_error(req, EIO); 353 return; 354 } 355 356 if (DEBUGLVL(10)) { 357 NDR_PRINT_DEBUG(named_pipe_auth_rep, &state->auth_rep); 358 } 359 360 if (state->auth_rep.length < 16) { 361 DEBUG(0, ("req invalid length: %u < 16\n", 362 state->auth_rep.length)); 363 tevent_req_error(req, EIO); 364 return; 365 } 366 367 if (strcmp(NAMED_PIPE_AUTH_MAGIC, state->auth_rep.magic) != 0) { 368 DEBUG(0, ("req invalid magic: %s != %s\n", 369 state->auth_rep.magic, NAMED_PIPE_AUTH_MAGIC)); 370 tevent_req_error(req, EIO); 371 return; 372 } 373 374 if (!NT_STATUS_IS_OK(state->auth_rep.status)) { 375 DEBUG(0, ("req failed: %s\n", 376 nt_errstr(state->auth_rep.status))); 377 tevent_req_error(req, EACCES); 378 return; 379 } 380 381 if (state->auth_rep.level != state->auth_req.level) { 382 DEBUG(0, ("req invalid level: %u != %u\n", 383 state->auth_rep.level, state->auth_req.level)); 384 tevent_req_error(req, EIO); 385 return; 386 } 387 388 tevent_req_done(req); 389} 390 391int _tstream_npa_connect_recv(struct tevent_req *req, 392 int *perrno, 393 TALLOC_CTX *mem_ctx, 394 struct tstream_context **_stream, 395 uint16_t *_file_type, 396 uint16_t *_device_state, 397 uint64_t *_allocation_size, 398 const char *location) 399{ 400 struct tstream_npa_connect_state *state = 401 tevent_req_data(req, 402 struct tstream_npa_connect_state); 403 struct tstream_context *stream; 404 struct tstream_npa *npas; 405 uint16_t device_state = 0; 406 uint64_t allocation_size = 0; 407 408 if (tevent_req_is_unix_error(req, perrno)) { 409 tevent_req_received(req); 410 return -1; 411 } 412 413 stream = tstream_context_create(mem_ctx, 414 &tstream_npa_ops, 415 &npas, 416 struct tstream_npa, 417 location); 418 if (!stream) { 419 return -1; 420 } 421 ZERO_STRUCTP(npas); 422 423 npas->unix_stream = talloc_move(stream, &state->unix_stream); 424 switch (state->auth_rep.level) { 425 case 0: 426 case 1: 427 npas->file_type = FILE_TYPE_BYTE_MODE_PIPE; 428 device_state = 0x00ff; 429 allocation_size = 2048; 430 break; 431 case 2: 432 npas->file_type = state->auth_rep.info.info2.file_type; 433 device_state = state->auth_rep.info.info2.device_state; 434 allocation_size = state->auth_rep.info.info2.allocation_size; 435 break; 436 case 3: 437 npas->file_type = state->auth_rep.info.info3.file_type; 438 device_state = state->auth_rep.info.info3.device_state; 439 allocation_size = state->auth_rep.info.info3.allocation_size; 440 break; 441 } 442 443 *_stream = stream; 444 *_file_type = npas->file_type; 445 *_device_state = device_state; 446 *_allocation_size = allocation_size; 447 tevent_req_received(req); 448 return 0; 449} 450 451static ssize_t tstream_npa_pending_bytes(struct tstream_context *stream) 452{ 453 struct tstream_npa *npas = tstream_context_data(stream, 454 struct tstream_npa); 455 ssize_t ret; 456 457 if (!npas->unix_stream) { 458 errno = ENOTCONN; 459 return -1; 460 } 461 462 switch (npas->file_type) { 463 case FILE_TYPE_BYTE_MODE_PIPE: 464 ret = tstream_pending_bytes(npas->unix_stream); 465 break; 466 467 case FILE_TYPE_MESSAGE_MODE_PIPE: 468 ret = npas->pending.iov_len; 469 break; 470 471 default: 472 ret = -1; 473 } 474 475 return ret; 476} 477 478struct tstream_npa_readv_state { 479 struct tstream_context *stream; 480 481 struct iovec *vector; 482 size_t count; 483 484 /* the header for message mode */ 485 uint8_t hdr[2]; 486 bool wait_for_hdr; 487 488 int ret; 489}; 490 491static void tstream_npa_readv_byte_mode_handler(struct tevent_req *subreq); 492static int tstream_npa_readv_next_vector(struct tstream_context *stream, 493 void *private_data, 494 TALLOC_CTX *mem_ctx, 495 struct iovec **_vector, 496 size_t *_count); 497static void tstream_npa_readv_msg_mode_handler(struct tevent_req *subreq); 498 499static struct tevent_req *tstream_npa_readv_send(TALLOC_CTX *mem_ctx, 500 struct tevent_context *ev, 501 struct tstream_context *stream, 502 struct iovec *vector, 503 size_t count) 504{ 505 struct tevent_req *req; 506 struct tstream_npa_readv_state *state; 507 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa); 508 struct tevent_req *subreq; 509 off_t ofs; 510 size_t left; 511 uint8_t *pbase; 512 513 req = tevent_req_create(mem_ctx, &state, 514 struct tstream_npa_readv_state); 515 if (!req) { 516 return NULL; 517 } 518 519 state->stream = stream; 520 state->ret = 0; 521 522 if (!npas->unix_stream) { 523 tevent_req_error(req, ENOTCONN); 524 goto post; 525 } 526 527 switch (npas->file_type) { 528 case FILE_TYPE_BYTE_MODE_PIPE: 529 state->vector = vector; 530 state->count = count; 531 532 subreq = tstream_readv_send(state, 533 ev, 534 npas->unix_stream, 535 state->vector, 536 state->count); 537 if (tevent_req_nomem(subreq,req)) { 538 goto post; 539 } 540 tevent_req_set_callback(subreq, 541 tstream_npa_readv_byte_mode_handler, 542 req); 543 544 return req; 545 546 case FILE_TYPE_MESSAGE_MODE_PIPE: 547 /* 548 * we make a copy of the vector and prepend a header 549 * with the length 550 */ 551 state->vector = talloc_array(state, struct iovec, count); 552 if (tevent_req_nomem(state->vector, req)) { 553 goto post; 554 } 555 memcpy(state->vector, vector, sizeof(struct iovec)*count); 556 state->count = count; 557 558 /* 559 * copy the pending buffer first 560 */ 561 ofs = 0; 562 left = npas->pending.iov_len; 563 pbase = (uint8_t *)npas->pending.iov_base; 564 565 while (left > 0 && state->count > 0) { 566 uint8_t *base; 567 base = (uint8_t *)state->vector[0].iov_base; 568 if (left < state->vector[0].iov_len) { 569 memcpy(base, pbase + ofs, left); 570 571 base += left; 572 state->vector[0].iov_base = base; 573 state->vector[0].iov_len -= left; 574 575 ofs += left; 576 left = 0; 577 TALLOC_FREE(pbase); 578 ZERO_STRUCT(npas->pending); 579 break; 580 } 581 memcpy(base, pbase + ofs, state->vector[0].iov_len); 582 583 ofs += state->vector[0].iov_len; 584 left -= state->vector[0].iov_len; 585 state->vector += 1; 586 state->count -= 1; 587 588 if (left == 0) { 589 TALLOC_FREE(pbase); 590 ZERO_STRUCT(npas->pending); 591 break; 592 } 593 } 594 595 if (left > 0) { 596 memmove(pbase, pbase + ofs, left); 597 npas->pending.iov_base = pbase; 598 npas->pending.iov_len = left; 599 /* 600 * this cannot fail and even if it 601 * fails we can handle it 602 */ 603 pbase = talloc_realloc(npas, pbase, uint8_t, left); 604 if (pbase) { 605 npas->pending.iov_base = pbase; 606 } 607 pbase = NULL; 608 } 609 610 state->ret += ofs; 611 612 if (state->count == 0) { 613 tevent_req_done(req); 614 goto post; 615 } 616 617 ZERO_STRUCT(state->hdr); 618 state->wait_for_hdr = false; 619 620 subreq = tstream_readv_pdu_send(state, 621 ev, 622 npas->unix_stream, 623 tstream_npa_readv_next_vector, 624 state); 625 if (tevent_req_nomem(subreq, req)) { 626 goto post; 627 } 628 tevent_req_set_callback(subreq, 629 tstream_npa_readv_msg_mode_handler, 630 req); 631 632 return req; 633 } 634 635 /* this can't happen */ 636 tevent_req_error(req, EINVAL); 637 goto post; 638 639 post: 640 tevent_req_post(req, ev); 641 return req; 642} 643 644static void tstream_npa_readv_byte_mode_handler(struct tevent_req *subreq) 645{ 646 struct tevent_req *req = tevent_req_callback_data(subreq, 647 struct tevent_req); 648 struct tstream_npa_readv_state *state = tevent_req_data(req, 649 struct tstream_npa_readv_state); 650 int ret; 651 int sys_errno; 652 653 ret = tstream_readv_recv(subreq, &sys_errno); 654 TALLOC_FREE(subreq); 655 if (ret == -1) { 656 tevent_req_error(req, sys_errno); 657 return; 658 } 659 660 state->ret = ret; 661 662 tevent_req_done(req); 663} 664 665static int tstream_npa_readv_next_vector(struct tstream_context *unix_stream, 666 void *private_data, 667 TALLOC_CTX *mem_ctx, 668 struct iovec **_vector, 669 size_t *_count) 670{ 671 struct tstream_npa_readv_state *state = talloc_get_type_abort(private_data, 672 struct tstream_npa_readv_state); 673 struct tstream_npa *npas = tstream_context_data(state->stream, 674 struct tstream_npa); 675 struct iovec *vector; 676 size_t count; 677 uint16_t msg_len; 678 size_t left; 679 680 if (state->count == 0) { 681 *_vector = NULL; 682 *_count = 0; 683 return 0; 684 } 685 686 if (!state->wait_for_hdr) { 687 /* we need to get a message header */ 688 vector = talloc_array(mem_ctx, struct iovec, 1); 689 if (!vector) { 690 return -1; 691 } 692 ZERO_STRUCT(state->hdr); 693 vector[0].iov_base = state->hdr; 694 vector[0].iov_len = sizeof(state->hdr); 695 696 count = 1; 697 698 state->wait_for_hdr = true; 699 700 *_vector = vector; 701 *_count = count; 702 return 0; 703 } 704 705 /* and now fill the callers buffers and maybe the pending buffer */ 706 state->wait_for_hdr = false; 707 708 msg_len = SVAL(state->hdr, 0); 709 710 if (msg_len == 0) { 711 errno = EIO; 712 return -1; 713 } 714 715 state->wait_for_hdr = false; 716 717 /* +1 because we may need to fill the pending buffer */ 718 vector = talloc_array(mem_ctx, struct iovec, state->count + 1); 719 if (!vector) { 720 return -1; 721 } 722 723 count = 0; 724 left = msg_len; 725 while (left > 0 && state->count > 0) { 726 if (left < state->vector[0].iov_len) { 727 uint8_t *base; 728 base = (uint8_t *)state->vector[0].iov_base; 729 vector[count].iov_base = base; 730 vector[count].iov_len = left; 731 count++; 732 base += left; 733 state->vector[0].iov_base = base; 734 state->vector[0].iov_len -= left; 735 break; 736 } 737 vector[count] = state->vector[0]; 738 count++; 739 left -= state->vector[0].iov_len; 740 state->vector += 1; 741 state->count -= 1; 742 } 743 744 if (left > 0) { 745 /* 746 * if the message if longer than the buffers the caller 747 * requested, we need to consume the rest of the message 748 * into the pending buffer, where the next readv can 749 * be served from. 750 */ 751 npas->pending.iov_base = talloc_array(npas, uint8_t, left); 752 if (!npas->pending.iov_base) { 753 return -1; 754 } 755 npas->pending.iov_len = left; 756 757 vector[count] = npas->pending; 758 count++; 759 } 760 761 state->ret += (msg_len - left); 762 763 *_vector = vector; 764 *_count = count; 765 return 0; 766} 767 768static void tstream_npa_readv_msg_mode_handler(struct tevent_req *subreq) 769{ 770 struct tevent_req *req = tevent_req_callback_data(subreq, 771 struct tevent_req); 772 int ret; 773 int sys_errno; 774 775 ret = tstream_readv_pdu_recv(subreq, &sys_errno); 776 TALLOC_FREE(subreq); 777 if (ret == -1) { 778 tevent_req_error(req, sys_errno); 779 return; 780 } 781 782 /* 783 * we do not set state->ret here as ret includes the headr size. 784 * we set it in tstream_npa_readv_pdu_next_vector() 785 */ 786 787 tevent_req_done(req); 788} 789 790static int tstream_npa_readv_recv(struct tevent_req *req, 791 int *perrno) 792{ 793 struct tstream_npa_readv_state *state = tevent_req_data(req, 794 struct tstream_npa_readv_state); 795 int ret; 796 797 ret = tsocket_simple_int_recv(req, perrno); 798 if (ret == 0) { 799 ret = state->ret; 800 } 801 802 tevent_req_received(req); 803 return ret; 804} 805 806struct tstream_npa_writev_state { 807 const struct iovec *vector; 808 size_t count; 809 810 /* the header for message mode */ 811 uint8_t hdr[2]; 812 813 int ret; 814}; 815 816static void tstream_npa_writev_handler(struct tevent_req *subreq); 817 818static struct tevent_req *tstream_npa_writev_send(TALLOC_CTX *mem_ctx, 819 struct tevent_context *ev, 820 struct tstream_context *stream, 821 const struct iovec *vector, 822 size_t count) 823{ 824 struct tevent_req *req; 825 struct tstream_npa_writev_state *state; 826 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa); 827 struct tevent_req *subreq; 828 size_t msg_len; 829 size_t i; 830 struct iovec *new_vector; 831 832 req = tevent_req_create(mem_ctx, &state, 833 struct tstream_npa_writev_state); 834 if (!req) { 835 return NULL; 836 } 837 838 state->ret = 0; 839 840 if (!npas->unix_stream) { 841 tevent_req_error(req, ENOTCONN); 842 goto post; 843 } 844 845 switch (npas->file_type) { 846 case FILE_TYPE_BYTE_MODE_PIPE: 847 state->vector = vector; 848 state->count = count; 849 break; 850 851 case FILE_TYPE_MESSAGE_MODE_PIPE: 852 /* 853 * we make a copy of the vector and prepend a header 854 * with the length 855 */ 856 new_vector = talloc_array(state, struct iovec, count + 1); 857 if (tevent_req_nomem(new_vector, req)) { 858 goto post; 859 } 860 new_vector[0].iov_base = state->hdr; 861 new_vector[0].iov_len = sizeof(state->hdr); 862 memcpy(new_vector + 1, vector, sizeof(struct iovec)*count); 863 864 state->vector = new_vector; 865 state->count = count + 1; 866 867 msg_len = 0; 868 for (i=0; i < count; i++) { 869 msg_len += vector[i].iov_len; 870 } 871 872 if (msg_len > UINT16_MAX) { 873 tevent_req_error(req, EMSGSIZE); 874 goto post; 875 } 876 877 SSVAL(state->hdr, 0, msg_len); 878 break; 879 } 880 881 subreq = tstream_writev_send(state, 882 ev, 883 npas->unix_stream, 884 state->vector, 885 state->count); 886 if (tevent_req_nomem(subreq, req)) { 887 goto post; 888 } 889 tevent_req_set_callback(subreq, tstream_npa_writev_handler, req); 890 891 return req; 892 893 post: 894 tevent_req_post(req, ev); 895 return req; 896} 897 898static void tstream_npa_writev_handler(struct tevent_req *subreq) 899{ 900 struct tevent_req *req = tevent_req_callback_data(subreq, 901 struct tevent_req); 902 struct tstream_npa_writev_state *state = tevent_req_data(req, 903 struct tstream_npa_writev_state); 904 int ret; 905 int sys_errno; 906 907 ret = tstream_writev_recv(subreq, &sys_errno); 908 TALLOC_FREE(subreq); 909 if (ret == -1) { 910 tevent_req_error(req, sys_errno); 911 return; 912 } 913 914 state->ret = ret; 915 916 tevent_req_done(req); 917} 918 919static int tstream_npa_writev_recv(struct tevent_req *req, 920 int *perrno) 921{ 922 struct tstream_npa_writev_state *state = tevent_req_data(req, 923 struct tstream_npa_writev_state); 924 int ret; 925 926 ret = tsocket_simple_int_recv(req, perrno); 927 if (ret == 0) { 928 ret = state->ret; 929 } 930 931 tevent_req_received(req); 932 return ret; 933} 934 935struct tstream_npa_disconnect_state { 936 struct tstream_context *stream; 937}; 938 939static void tstream_npa_disconnect_handler(struct tevent_req *subreq); 940 941static struct tevent_req *tstream_npa_disconnect_send(TALLOC_CTX *mem_ctx, 942 struct tevent_context *ev, 943 struct tstream_context *stream) 944{ 945 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa); 946 struct tevent_req *req; 947 struct tstream_npa_disconnect_state *state; 948 struct tevent_req *subreq; 949 950 req = tevent_req_create(mem_ctx, &state, 951 struct tstream_npa_disconnect_state); 952 if (req == NULL) { 953 return NULL; 954 } 955 956 state->stream = stream; 957 958 if (!npas->unix_stream) { 959 tevent_req_error(req, ENOTCONN); 960 goto post; 961 } 962 963 subreq = tstream_disconnect_send(state, 964 ev, 965 npas->unix_stream); 966 if (tevent_req_nomem(subreq, req)) { 967 goto post; 968 } 969 tevent_req_set_callback(subreq, tstream_npa_disconnect_handler, req); 970 971 return req; 972 973post: 974 tevent_req_post(req, ev); 975 return req; 976} 977 978static void tstream_npa_disconnect_handler(struct tevent_req *subreq) 979{ 980 struct tevent_req *req = tevent_req_callback_data(subreq, 981 struct tevent_req); 982 struct tstream_npa_disconnect_state *state = tevent_req_data(req, 983 struct tstream_npa_disconnect_state); 984 struct tstream_context *stream = state->stream; 985 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa); 986 int ret; 987 int sys_errno; 988 989 ret = tstream_disconnect_recv(subreq, &sys_errno); 990 TALLOC_FREE(subreq); 991 if (ret == -1) { 992 tevent_req_error(req, sys_errno); 993 return; 994 } 995 996 TALLOC_FREE(npas->unix_stream); 997 998 tevent_req_done(req); 999} 1000 1001static int tstream_npa_disconnect_recv(struct tevent_req *req, 1002 int *perrno) 1003{ 1004 int ret; 1005 1006 ret = tsocket_simple_int_recv(req, perrno); 1007 1008 tevent_req_received(req); 1009 return ret; 1010} 1011 1012static const struct tstream_context_ops tstream_npa_ops = { 1013 .name = "npa", 1014 1015 .pending_bytes = tstream_npa_pending_bytes, 1016 1017 .readv_send = tstream_npa_readv_send, 1018 .readv_recv = tstream_npa_readv_recv, 1019 1020 .writev_send = tstream_npa_writev_send, 1021 .writev_recv = tstream_npa_writev_recv, 1022 1023 .disconnect_send = tstream_npa_disconnect_send, 1024 .disconnect_recv = tstream_npa_disconnect_recv, 1025}; 1026 1027int _tstream_npa_existing_socket(TALLOC_CTX *mem_ctx, 1028 int fd, 1029 uint16_t file_type, 1030 struct tstream_context **_stream, 1031 const char *location) 1032{ 1033 struct tstream_context *stream; 1034 struct tstream_npa *npas; 1035 int ret; 1036 1037 switch (file_type) { 1038 case FILE_TYPE_BYTE_MODE_PIPE: 1039 break; 1040 case FILE_TYPE_MESSAGE_MODE_PIPE: 1041 break; 1042 default: 1043 errno = EINVAL; 1044 return -1; 1045 } 1046 1047 stream = tstream_context_create(mem_ctx, 1048 &tstream_npa_ops, 1049 &npas, 1050 struct tstream_npa, 1051 location); 1052 if (!stream) { 1053 return -1; 1054 } 1055 ZERO_STRUCTP(npas); 1056 1057 npas->file_type = file_type; 1058 1059 ret = tstream_bsd_existing_socket(stream, fd, 1060 &npas->unix_stream); 1061 if (ret == -1) { 1062 int saved_errno = errno; 1063 talloc_free(stream); 1064 errno = saved_errno; 1065 return -1; 1066 } 1067 1068 *_stream = stream; 1069 return 0; 1070} 1071 1072