1/* 2 Unix SMB/CIFS implementation. 3 FS info functions 4 Copyright (C) Stefan (metze) Metzmacher 2003 5 Copyright (C) Jeremy Allison 2007 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program. If not, see <http://www.gnu.org/licenses/>. 19*/ 20 21#include "includes.h" 22#include "../libcli/auth/spnego.h" 23 24/**************************************************************************** 25 Get UNIX extensions version info. 26****************************************************************************/ 27 28struct cli_unix_extensions_version_state { 29 uint16_t setup[1]; 30 uint8_t param[2]; 31 uint16_t major, minor; 32 uint32_t caplow, caphigh; 33}; 34 35static void cli_unix_extensions_version_done(struct tevent_req *subreq); 36 37struct tevent_req *cli_unix_extensions_version_send(TALLOC_CTX *mem_ctx, 38 struct tevent_context *ev, 39 struct cli_state *cli) 40{ 41 struct tevent_req *req, *subreq; 42 struct cli_unix_extensions_version_state *state; 43 44 req = tevent_req_create(mem_ctx, &state, 45 struct cli_unix_extensions_version_state); 46 if (req == NULL) { 47 return NULL; 48 } 49 SSVAL(state->setup, 0, TRANSACT2_QFSINFO); 50 SSVAL(state->param, 0, SMB_QUERY_CIFS_UNIX_INFO); 51 52 subreq = cli_trans_send(state, ev, cli, SMBtrans2, 53 NULL, 0, 0, 0, 54 state->setup, 1, 0, 55 state->param, 2, 0, 56 NULL, 0, 560); 57 if (tevent_req_nomem(subreq, req)) { 58 return tevent_req_post(req, ev); 59 } 60 tevent_req_set_callback(subreq, cli_unix_extensions_version_done, req); 61 return req; 62} 63 64static void cli_unix_extensions_version_done(struct tevent_req *subreq) 65{ 66 struct tevent_req *req = tevent_req_callback_data( 67 subreq, struct tevent_req); 68 struct cli_unix_extensions_version_state *state = tevent_req_data( 69 req, struct cli_unix_extensions_version_state); 70 uint8_t *data; 71 uint32_t num_data; 72 NTSTATUS status; 73 74 status = cli_trans_recv(subreq, state, NULL, NULL, NULL, NULL, 75 &data, &num_data); 76 TALLOC_FREE(subreq); 77 if (!NT_STATUS_IS_OK(status)) { 78 tevent_req_nterror(req, status); 79 return; 80 } 81 if (num_data < 12) { 82 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); 83 return; 84 } 85 86 state->major = SVAL(data, 0); 87 state->minor = SVAL(data, 2); 88 state->caplow = IVAL(data, 4); 89 state->caphigh = IVAL(data, 8); 90 TALLOC_FREE(data); 91 tevent_req_done(req); 92} 93 94NTSTATUS cli_unix_extensions_version_recv(struct tevent_req *req, 95 uint16_t *pmajor, uint16_t *pminor, 96 uint32_t *pcaplow, 97 uint32_t *pcaphigh) 98{ 99 struct cli_unix_extensions_version_state *state = tevent_req_data( 100 req, struct cli_unix_extensions_version_state); 101 NTSTATUS status; 102 103 if (tevent_req_is_nterror(req, &status)) { 104 return status; 105 } 106 *pmajor = state->major; 107 *pminor = state->minor; 108 *pcaplow = state->caplow; 109 *pcaphigh = state->caphigh; 110 return NT_STATUS_OK; 111} 112 113NTSTATUS cli_unix_extensions_version(struct cli_state *cli, uint16 *pmajor, 114 uint16 *pminor, uint32 *pcaplow, 115 uint32 *pcaphigh) 116{ 117 TALLOC_CTX *frame = talloc_stackframe(); 118 struct event_context *ev; 119 struct tevent_req *req; 120 NTSTATUS status = NT_STATUS_OK; 121 122 if (cli_has_async_calls(cli)) { 123 /* 124 * Can't use sync call while an async call is in flight 125 */ 126 status = NT_STATUS_INVALID_PARAMETER; 127 goto fail; 128 } 129 130 ev = event_context_init(frame); 131 if (ev == NULL) { 132 status = NT_STATUS_NO_MEMORY; 133 goto fail; 134 } 135 136 req = cli_unix_extensions_version_send(frame, ev, cli); 137 if (req == NULL) { 138 status = NT_STATUS_NO_MEMORY; 139 goto fail; 140 } 141 142 if (!tevent_req_poll(req, ev)) { 143 status = map_nt_error_from_unix(errno); 144 goto fail; 145 } 146 147 status = cli_unix_extensions_version_recv(req, pmajor, pminor, pcaplow, 148 pcaphigh); 149 if (NT_STATUS_IS_OK(status)) { 150 cli->posix_capabilities = *pcaplow; 151 } 152 fail: 153 TALLOC_FREE(frame); 154 if (!NT_STATUS_IS_OK(status)) { 155 cli_set_error(cli, status); 156 } 157 return status; 158} 159 160/**************************************************************************** 161 Set UNIX extensions capabilities. 162****************************************************************************/ 163 164bool cli_set_unix_extensions_capabilities(struct cli_state *cli, uint16 major, uint16 minor, 165 uint32 caplow, uint32 caphigh) 166{ 167 bool ret = False; 168 uint16 setup; 169 char param[4]; 170 char data[12]; 171 char *rparam=NULL, *rdata=NULL; 172 unsigned int rparam_count=0, rdata_count=0; 173 174 setup = TRANSACT2_SETFSINFO; 175 176 SSVAL(param,0,0); 177 SSVAL(param,2,SMB_SET_CIFS_UNIX_INFO); 178 179 SSVAL(data,0,major); 180 SSVAL(data,2,minor); 181 SIVAL(data,4,caplow); 182 SIVAL(data,8,caphigh); 183 184 if (!cli_send_trans(cli, SMBtrans2, 185 NULL, 186 0, 0, 187 &setup, 1, 0, 188 param, 4, 0, 189 data, 12, 560)) { 190 goto cleanup; 191 } 192 193 if (!cli_receive_trans(cli, SMBtrans2, 194 &rparam, &rparam_count, 195 &rdata, &rdata_count)) { 196 goto cleanup; 197 } 198 199 if (cli_is_error(cli)) { 200 ret = False; 201 goto cleanup; 202 } else { 203 ret = True; 204 } 205 206cleanup: 207 SAFE_FREE(rparam); 208 SAFE_FREE(rdata); 209 210 return ret; 211} 212 213bool cli_get_fs_attr_info(struct cli_state *cli, uint32 *fs_attr) 214{ 215 bool ret = False; 216 uint16 setup; 217 char param[2]; 218 char *rparam=NULL, *rdata=NULL; 219 unsigned int rparam_count=0, rdata_count=0; 220 221 if (!cli||!fs_attr) 222 smb_panic("cli_get_fs_attr_info() called with NULL Pionter!"); 223 224 setup = TRANSACT2_QFSINFO; 225 226 SSVAL(param,0,SMB_QUERY_FS_ATTRIBUTE_INFO); 227 228 if (!cli_send_trans(cli, SMBtrans2, 229 NULL, 230 0, 0, 231 &setup, 1, 0, 232 param, 2, 0, 233 NULL, 0, 560)) { 234 goto cleanup; 235 } 236 237 if (!cli_receive_trans(cli, SMBtrans2, 238 &rparam, &rparam_count, 239 &rdata, &rdata_count)) { 240 goto cleanup; 241 } 242 243 if (cli_is_error(cli)) { 244 ret = False; 245 goto cleanup; 246 } else { 247 ret = True; 248 } 249 250 if (rdata_count < 12) { 251 goto cleanup; 252 } 253 254 *fs_attr = IVAL(rdata,0); 255 256 /* todo: but not yet needed 257 * return the other stuff 258 */ 259 260cleanup: 261 SAFE_FREE(rparam); 262 SAFE_FREE(rdata); 263 264 return ret; 265} 266 267bool cli_get_fs_volume_info_old(struct cli_state *cli, fstring volume_name, uint32 *pserial_number) 268{ 269 bool ret = False; 270 uint16 setup; 271 char param[2]; 272 char *rparam=NULL, *rdata=NULL; 273 unsigned int rparam_count=0, rdata_count=0; 274 unsigned char nlen; 275 276 setup = TRANSACT2_QFSINFO; 277 278 SSVAL(param,0,SMB_INFO_VOLUME); 279 280 if (!cli_send_trans(cli, SMBtrans2, 281 NULL, 282 0, 0, 283 &setup, 1, 0, 284 param, 2, 0, 285 NULL, 0, 560)) { 286 goto cleanup; 287 } 288 289 if (!cli_receive_trans(cli, SMBtrans2, 290 &rparam, &rparam_count, 291 &rdata, &rdata_count)) { 292 goto cleanup; 293 } 294 295 if (cli_is_error(cli)) { 296 ret = False; 297 goto cleanup; 298 } else { 299 ret = True; 300 } 301 302 if (rdata_count < 5) { 303 goto cleanup; 304 } 305 306 if (pserial_number) { 307 *pserial_number = IVAL(rdata,0); 308 } 309 nlen = CVAL(rdata,l2_vol_cch); 310 clistr_pull(cli->inbuf, volume_name, rdata + l2_vol_szVolLabel, 311 sizeof(fstring), nlen, STR_NOALIGN); 312 313 /* todo: but not yet needed 314 * return the other stuff 315 */ 316 317cleanup: 318 SAFE_FREE(rparam); 319 SAFE_FREE(rdata); 320 321 return ret; 322} 323 324bool cli_get_fs_volume_info(struct cli_state *cli, fstring volume_name, uint32 *pserial_number, time_t *pdate) 325{ 326 bool ret = False; 327 uint16 setup; 328 char param[2]; 329 char *rparam=NULL, *rdata=NULL; 330 unsigned int rparam_count=0, rdata_count=0; 331 unsigned int nlen; 332 333 setup = TRANSACT2_QFSINFO; 334 335 SSVAL(param,0,SMB_QUERY_FS_VOLUME_INFO); 336 337 if (!cli_send_trans(cli, SMBtrans2, 338 NULL, 339 0, 0, 340 &setup, 1, 0, 341 param, 2, 0, 342 NULL, 0, 560)) { 343 goto cleanup; 344 } 345 346 if (!cli_receive_trans(cli, SMBtrans2, 347 &rparam, &rparam_count, 348 &rdata, &rdata_count)) { 349 goto cleanup; 350 } 351 352 if (cli_is_error(cli)) { 353 ret = False; 354 goto cleanup; 355 } else { 356 ret = True; 357 } 358 359 if (rdata_count < 19) { 360 goto cleanup; 361 } 362 363 if (pdate) { 364 struct timespec ts; 365 ts = interpret_long_date(rdata); 366 *pdate = ts.tv_sec; 367 } 368 if (pserial_number) { 369 *pserial_number = IVAL(rdata,8); 370 } 371 nlen = IVAL(rdata,12); 372 clistr_pull(cli->inbuf, volume_name, rdata + 18, sizeof(fstring), 373 nlen, STR_UNICODE); 374 375 /* todo: but not yet needed 376 * return the other stuff 377 */ 378 379cleanup: 380 SAFE_FREE(rparam); 381 SAFE_FREE(rdata); 382 383 return ret; 384} 385 386bool cli_get_fs_full_size_info(struct cli_state *cli, 387 uint64_t *total_allocation_units, 388 uint64_t *caller_allocation_units, 389 uint64_t *actual_allocation_units, 390 uint64_t *sectors_per_allocation_unit, 391 uint64_t *bytes_per_sector) 392{ 393 bool ret = False; 394 uint16 setup; 395 char param[2]; 396 char *rparam=NULL, *rdata=NULL; 397 unsigned int rparam_count=0, rdata_count=0; 398 399 setup = TRANSACT2_QFSINFO; 400 401 SSVAL(param,0,SMB_FS_FULL_SIZE_INFORMATION); 402 403 if (!cli_send_trans(cli, SMBtrans2, 404 NULL, 405 0, 0, 406 &setup, 1, 0, 407 param, 2, 0, 408 NULL, 0, 560)) { 409 goto cleanup; 410 } 411 412 if (!cli_receive_trans(cli, SMBtrans2, 413 &rparam, &rparam_count, 414 &rdata, &rdata_count)) { 415 goto cleanup; 416 } 417 418 if (cli_is_error(cli)) { 419 ret = False; 420 goto cleanup; 421 } else { 422 ret = True; 423 } 424 425 if (rdata_count != 32) { 426 goto cleanup; 427 } 428 429 if (total_allocation_units) { 430 *total_allocation_units = BIG_UINT(rdata, 0); 431 } 432 if (caller_allocation_units) { 433 *caller_allocation_units = BIG_UINT(rdata,8); 434 } 435 if (actual_allocation_units) { 436 *actual_allocation_units = BIG_UINT(rdata,16); 437 } 438 if (sectors_per_allocation_unit) { 439 *sectors_per_allocation_unit = IVAL(rdata,24); 440 } 441 if (bytes_per_sector) { 442 *bytes_per_sector = IVAL(rdata,28); 443 } 444 445cleanup: 446 SAFE_FREE(rparam); 447 SAFE_FREE(rdata); 448 449 return ret; 450} 451 452bool cli_get_posix_fs_info(struct cli_state *cli, 453 uint32 *optimal_transfer_size, 454 uint32 *block_size, 455 uint64_t *total_blocks, 456 uint64_t *blocks_available, 457 uint64_t *user_blocks_available, 458 uint64_t *total_file_nodes, 459 uint64_t *free_file_nodes, 460 uint64_t *fs_identifier) 461{ 462 bool ret = False; 463 uint16 setup; 464 char param[2]; 465 char *rparam=NULL, *rdata=NULL; 466 unsigned int rparam_count=0, rdata_count=0; 467 468 setup = TRANSACT2_QFSINFO; 469 470 SSVAL(param,0,SMB_QUERY_POSIX_FS_INFO); 471 472 if (!cli_send_trans(cli, SMBtrans2, 473 NULL, 474 0, 0, 475 &setup, 1, 0, 476 param, 2, 0, 477 NULL, 0, 560)) { 478 goto cleanup; 479 } 480 481 if (!cli_receive_trans(cli, SMBtrans2, 482 &rparam, &rparam_count, 483 &rdata, &rdata_count)) { 484 goto cleanup; 485 } 486 487 if (cli_is_error(cli)) { 488 ret = False; 489 goto cleanup; 490 } else { 491 ret = True; 492 } 493 494 if (rdata_count != 56) { 495 goto cleanup; 496 } 497 498 if (optimal_transfer_size) { 499 *optimal_transfer_size = IVAL(rdata, 0); 500 } 501 if (block_size) { 502 *block_size = IVAL(rdata,4); 503 } 504 if (total_blocks) { 505 *total_blocks = BIG_UINT(rdata,8); 506 } 507 if (blocks_available) { 508 *blocks_available = BIG_UINT(rdata,16); 509 } 510 if (user_blocks_available) { 511 *user_blocks_available = BIG_UINT(rdata,24); 512 } 513 if (total_file_nodes) { 514 *total_file_nodes = BIG_UINT(rdata,32); 515 } 516 if (free_file_nodes) { 517 *free_file_nodes = BIG_UINT(rdata,40); 518 } 519 if (fs_identifier) { 520 *fs_identifier = BIG_UINT(rdata,48); 521 } 522 523cleanup: 524 SAFE_FREE(rparam); 525 SAFE_FREE(rdata); 526 527 return ret; 528} 529 530 531/****************************************************************************** 532 Send/receive the request encryption blob. 533******************************************************************************/ 534 535static NTSTATUS enc_blob_send_receive(struct cli_state *cli, DATA_BLOB *in, DATA_BLOB *out, DATA_BLOB *param_out) 536{ 537 uint16 setup; 538 char param[4]; 539 char *rparam=NULL, *rdata=NULL; 540 unsigned int rparam_count=0, rdata_count=0; 541 NTSTATUS status = NT_STATUS_OK; 542 543 setup = TRANSACT2_SETFSINFO; 544 545 SSVAL(param,0,0); 546 SSVAL(param,2,SMB_REQUEST_TRANSPORT_ENCRYPTION); 547 548 if (!cli_send_trans(cli, SMBtrans2, 549 NULL, 550 0, 0, 551 &setup, 1, 0, 552 param, 4, 0, 553 (char *)in->data, in->length, CLI_BUFFER_SIZE)) { 554 status = cli_nt_error(cli); 555 goto out; 556 } 557 558 if (!cli_receive_trans(cli, SMBtrans2, 559 &rparam, &rparam_count, 560 &rdata, &rdata_count)) { 561 status = cli_nt_error(cli); 562 goto out; 563 } 564 565 if (cli_is_error(cli)) { 566 status = cli_nt_error(cli); 567 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { 568 goto out; 569 } 570 } 571 572 *out = data_blob(rdata, rdata_count); 573 *param_out = data_blob(rparam, rparam_count); 574 575 out: 576 577 SAFE_FREE(rparam); 578 SAFE_FREE(rdata); 579 return status; 580} 581 582/****************************************************************************** 583 Make a client state struct. 584******************************************************************************/ 585 586static struct smb_trans_enc_state *make_cli_enc_state(enum smb_trans_enc_type smb_enc_type) 587{ 588 struct smb_trans_enc_state *es = NULL; 589 es = SMB_MALLOC_P(struct smb_trans_enc_state); 590 if (!es) { 591 return NULL; 592 } 593 ZERO_STRUCTP(es); 594 es->smb_enc_type = smb_enc_type; 595 596#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5) 597 if (smb_enc_type == SMB_TRANS_ENC_GSS) { 598 es->s.gss_state = SMB_MALLOC_P(struct smb_tran_enc_state_gss); 599 if (!es->s.gss_state) { 600 SAFE_FREE(es); 601 return NULL; 602 } 603 ZERO_STRUCTP(es->s.gss_state); 604 } 605#endif 606 return es; 607} 608 609/****************************************************************************** 610 Start a raw ntlmssp encryption. 611******************************************************************************/ 612 613NTSTATUS cli_raw_ntlm_smb_encryption_start(struct cli_state *cli, 614 const char *user, 615 const char *pass, 616 const char *domain) 617{ 618 DATA_BLOB blob_in = data_blob_null; 619 DATA_BLOB blob_out = data_blob_null; 620 DATA_BLOB param_out = data_blob_null; 621 NTSTATUS status = NT_STATUS_UNSUCCESSFUL; 622 struct smb_trans_enc_state *es = make_cli_enc_state(SMB_TRANS_ENC_NTLM); 623 624 if (!es) { 625 return NT_STATUS_NO_MEMORY; 626 } 627 status = ntlmssp_client_start(&es->s.ntlmssp_state); 628 if (!NT_STATUS_IS_OK(status)) { 629 goto fail; 630 } 631 632 ntlmssp_want_feature(es->s.ntlmssp_state, NTLMSSP_FEATURE_SESSION_KEY); 633 es->s.ntlmssp_state->neg_flags |= (NTLMSSP_NEGOTIATE_SIGN|NTLMSSP_NEGOTIATE_SEAL); 634 635 if (!NT_STATUS_IS_OK(status = ntlmssp_set_username(es->s.ntlmssp_state, user))) { 636 goto fail; 637 } 638 if (!NT_STATUS_IS_OK(status = ntlmssp_set_domain(es->s.ntlmssp_state, domain))) { 639 goto fail; 640 } 641 if (!NT_STATUS_IS_OK(status = ntlmssp_set_password(es->s.ntlmssp_state, pass))) { 642 goto fail; 643 } 644 645 do { 646 status = ntlmssp_update(es->s.ntlmssp_state, blob_in, &blob_out); 647 data_blob_free(&blob_in); 648 data_blob_free(¶m_out); 649 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) || NT_STATUS_IS_OK(status)) { 650 NTSTATUS trans_status = enc_blob_send_receive(cli, 651 &blob_out, 652 &blob_in, 653 ¶m_out); 654 if (!NT_STATUS_EQUAL(trans_status, 655 NT_STATUS_MORE_PROCESSING_REQUIRED) && 656 !NT_STATUS_IS_OK(trans_status)) { 657 status = trans_status; 658 } else { 659 if (param_out.length == 2) { 660 es->enc_ctx_num = SVAL(param_out.data, 0); 661 } 662 } 663 } 664 data_blob_free(&blob_out); 665 } while (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)); 666 667 data_blob_free(&blob_in); 668 669 if (NT_STATUS_IS_OK(status)) { 670 /* Replace the old state, if any. */ 671 if (cli->trans_enc_state) { 672 common_free_encryption_state(&cli->trans_enc_state); 673 } 674 cli->trans_enc_state = es; 675 cli->trans_enc_state->enc_on = True; 676 es = NULL; 677 } 678 679 fail: 680 681 common_free_encryption_state(&es); 682 return status; 683} 684 685#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5) 686 687#ifndef SMB_GSS_REQUIRED_FLAGS 688#define SMB_GSS_REQUIRED_FLAGS (GSS_C_CONF_FLAG|GSS_C_INTEG_FLAG|GSS_C_MUTUAL_FLAG|GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG) 689#endif 690 691/****************************************************************************** 692 Get client gss blob to send to a server. 693******************************************************************************/ 694 695static NTSTATUS make_cli_gss_blob(struct smb_trans_enc_state *es, 696 const char *service, 697 const char *host, 698 NTSTATUS status_in, 699 DATA_BLOB spnego_blob_in, 700 DATA_BLOB *p_blob_out) 701{ 702 const char *krb_mechs[] = {OID_KERBEROS5, NULL}; 703 OM_uint32 ret; 704 OM_uint32 min; 705 gss_name_t srv_name; 706 gss_buffer_desc input_name; 707 gss_buffer_desc *p_tok_in; 708 gss_buffer_desc tok_out, tok_in; 709 DATA_BLOB blob_out = data_blob_null; 710 DATA_BLOB blob_in = data_blob_null; 711 char *host_princ_s = NULL; 712 OM_uint32 ret_flags = 0; 713 NTSTATUS status = NT_STATUS_OK; 714 715 gss_OID_desc nt_hostbased_service = 716 {10, CONST_DISCARD(char *,"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04")}; 717 718 memset(&tok_out, '\0', sizeof(tok_out)); 719 720 /* Get a ticket for the service@host */ 721 if (asprintf(&host_princ_s, "%s@%s", service, host) == -1) { 722 return NT_STATUS_NO_MEMORY; 723 } 724 725 input_name.value = host_princ_s; 726 input_name.length = strlen(host_princ_s) + 1; 727 728 ret = gss_import_name(&min, 729 &input_name, 730 &nt_hostbased_service, 731 &srv_name); 732 733 if (ret != GSS_S_COMPLETE) { 734 SAFE_FREE(host_princ_s); 735 return map_nt_error_from_gss(ret, min); 736 } 737 738 if (spnego_blob_in.length == 0) { 739 p_tok_in = GSS_C_NO_BUFFER; 740 } else { 741 /* Remove the SPNEGO wrapper */ 742 if (!spnego_parse_auth_response(spnego_blob_in, status_in, OID_KERBEROS5, &blob_in)) { 743 status = NT_STATUS_UNSUCCESSFUL; 744 goto fail; 745 } 746 tok_in.value = blob_in.data; 747 tok_in.length = blob_in.length; 748 p_tok_in = &tok_in; 749 } 750 751 ret = gss_init_sec_context(&min, 752 GSS_C_NO_CREDENTIAL, /* Use our default cred. */ 753 &es->s.gss_state->gss_ctx, 754 srv_name, 755 GSS_C_NO_OID, /* default OID. */ 756 GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG, 757 GSS_C_INDEFINITE, /* requested ticket lifetime. */ 758 NULL, /* no channel bindings */ 759 p_tok_in, 760 NULL, /* ignore mech type */ 761 &tok_out, 762 &ret_flags, 763 NULL); /* ignore time_rec */ 764 765 status = map_nt_error_from_gss(ret, min); 766 if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED)) { 767 ADS_STATUS adss = ADS_ERROR_GSS(ret, min); 768 DEBUG(10,("make_cli_gss_blob: gss_init_sec_context failed with %s\n", 769 ads_errstr(adss))); 770 goto fail; 771 } 772 773 if ((ret_flags & SMB_GSS_REQUIRED_FLAGS) != SMB_GSS_REQUIRED_FLAGS) { 774 status = NT_STATUS_ACCESS_DENIED; 775 } 776 777 blob_out = data_blob(tok_out.value, tok_out.length); 778 779 /* Wrap in an SPNEGO wrapper */ 780 *p_blob_out = gen_negTokenTarg(krb_mechs, blob_out); 781 782 fail: 783 784 data_blob_free(&blob_out); 785 data_blob_free(&blob_in); 786 SAFE_FREE(host_princ_s); 787 gss_release_name(&min, &srv_name); 788 if (tok_out.value) { 789 gss_release_buffer(&min, &tok_out); 790 } 791 return status; 792} 793 794/****************************************************************************** 795 Start a SPNEGO gssapi encryption context. 796******************************************************************************/ 797 798NTSTATUS cli_gss_smb_encryption_start(struct cli_state *cli) 799{ 800 DATA_BLOB blob_recv = data_blob_null; 801 DATA_BLOB blob_send = data_blob_null; 802 DATA_BLOB param_out = data_blob_null; 803 NTSTATUS status = NT_STATUS_UNSUCCESSFUL; 804 fstring fqdn; 805 const char *servicename; 806 struct smb_trans_enc_state *es = make_cli_enc_state(SMB_TRANS_ENC_GSS); 807 808 if (!es) { 809 return NT_STATUS_NO_MEMORY; 810 } 811 812 name_to_fqdn(fqdn, cli->desthost); 813 strlower_m(fqdn); 814 815 servicename = "cifs"; 816 status = make_cli_gss_blob(es, servicename, fqdn, NT_STATUS_OK, blob_recv, &blob_send); 817 if (!NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED)) { 818 servicename = "host"; 819 status = make_cli_gss_blob(es, servicename, fqdn, NT_STATUS_OK, blob_recv, &blob_send); 820 if (!NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED)) { 821 goto fail; 822 } 823 } 824 825 do { 826 data_blob_free(&blob_recv); 827 status = enc_blob_send_receive(cli, &blob_send, &blob_recv, ¶m_out); 828 if (param_out.length == 2) { 829 es->enc_ctx_num = SVAL(param_out.data, 0); 830 } 831 data_blob_free(&blob_send); 832 status = make_cli_gss_blob(es, servicename, fqdn, status, blob_recv, &blob_send); 833 } while (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)); 834 data_blob_free(&blob_recv); 835 836 if (NT_STATUS_IS_OK(status)) { 837 /* Replace the old state, if any. */ 838 if (cli->trans_enc_state) { 839 common_free_encryption_state(&cli->trans_enc_state); 840 } 841 cli->trans_enc_state = es; 842 cli->trans_enc_state->enc_on = True; 843 es = NULL; 844 } 845 846 fail: 847 848 common_free_encryption_state(&es); 849 return status; 850} 851#else 852NTSTATUS cli_gss_smb_encryption_start(struct cli_state *cli) 853{ 854 return NT_STATUS_NOT_SUPPORTED; 855} 856#endif 857 858/******************************************************************** 859 Ensure a connection is encrypted. 860********************************************************************/ 861 862NTSTATUS cli_force_encryption(struct cli_state *c, 863 const char *username, 864 const char *password, 865 const char *domain) 866{ 867 uint16 major, minor; 868 uint32 caplow, caphigh; 869 NTSTATUS status; 870 871 if (!SERVER_HAS_UNIX_CIFS(c)) { 872 return NT_STATUS_NOT_SUPPORTED; 873 } 874 875 status = cli_unix_extensions_version(c, &major, &minor, &caplow, 876 &caphigh); 877 if (!NT_STATUS_IS_OK(status)) { 878 DEBUG(10, ("cli_force_encryption: cli_unix_extensions_version " 879 "returned %s\n", nt_errstr(status))); 880 return NT_STATUS_UNKNOWN_REVISION; 881 } 882 883 if (!(caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP)) { 884 return NT_STATUS_UNSUPPORTED_COMPRESSION; 885 } 886 887 if (c->use_kerberos) { 888 return cli_gss_smb_encryption_start(c); 889 } 890 return cli_raw_ntlm_smb_encryption_start(c, 891 username, 892 password, 893 domain); 894} 895