1/* 2 Unix SMB/CIFS implementation. 3 4 RFC2478 Compliant SPNEGO implementation 5 6 Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003 7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005 8 Copyright (C) Stefan Metzmacher <metze@samba.org> 2004-2008 9 10 This program is free software; you can redistribute it and/or modify 11 it under the terms of the GNU General Public License as published by 12 the Free Software Foundation; either version 3 of the License, or 13 (at your option) any later version. 14 15 This program is distributed in the hope that it will be useful, 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 GNU General Public License for more details. 19 20 21 You should have received a copy of the GNU General Public License 22 along with this program. If not, see <http://www.gnu.org/licenses/>. 23*/ 24 25#include "includes.h" 26#include "../libcli/auth/spnego.h" 27#include "librpc/gen_ndr/ndr_dcerpc.h" 28#include "auth/credentials/credentials.h" 29#include "auth/gensec/gensec.h" 30#include "auth/gensec/gensec_proto.h" 31 32enum spnego_state_position { 33 SPNEGO_SERVER_START, 34 SPNEGO_CLIENT_START, 35 SPNEGO_SERVER_TARG, 36 SPNEGO_CLIENT_TARG, 37 SPNEGO_FALLBACK, 38 SPNEGO_DONE 39}; 40 41struct spnego_state { 42 enum spnego_message_type expected_packet; 43 enum spnego_state_position state_position; 44 struct gensec_security *sub_sec_security; 45 bool no_response_expected; 46 47 const char *neg_oid; 48 49 DATA_BLOB mech_types; 50}; 51 52 53static NTSTATUS gensec_spnego_client_start(struct gensec_security *gensec_security) 54{ 55 struct spnego_state *spnego_state; 56 57 spnego_state = talloc(gensec_security, struct spnego_state); 58 if (!spnego_state) { 59 return NT_STATUS_NO_MEMORY; 60 } 61 62 spnego_state->expected_packet = SPNEGO_NEG_TOKEN_INIT; 63 spnego_state->state_position = SPNEGO_CLIENT_START; 64 spnego_state->sub_sec_security = NULL; 65 spnego_state->no_response_expected = false; 66 spnego_state->mech_types = data_blob(NULL, 0); 67 68 gensec_security->private_data = spnego_state; 69 return NT_STATUS_OK; 70} 71 72static NTSTATUS gensec_spnego_server_start(struct gensec_security *gensec_security) 73{ 74 struct spnego_state *spnego_state; 75 76 spnego_state = talloc(gensec_security, struct spnego_state); 77 if (!spnego_state) { 78 return NT_STATUS_NO_MEMORY; 79 } 80 81 spnego_state->expected_packet = SPNEGO_NEG_TOKEN_INIT; 82 spnego_state->state_position = SPNEGO_SERVER_START; 83 spnego_state->sub_sec_security = NULL; 84 spnego_state->no_response_expected = false; 85 spnego_state->mech_types = data_blob(NULL, 0); 86 87 gensec_security->private_data = spnego_state; 88 return NT_STATUS_OK; 89} 90 91/* 92 wrappers for the spnego_*() functions 93*/ 94static NTSTATUS gensec_spnego_unseal_packet(struct gensec_security *gensec_security, 95 TALLOC_CTX *mem_ctx, 96 uint8_t *data, size_t length, 97 const uint8_t *whole_pdu, size_t pdu_length, 98 const DATA_BLOB *sig) 99{ 100 struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data; 101 102 if (spnego_state->state_position != SPNEGO_DONE 103 && spnego_state->state_position != SPNEGO_FALLBACK) { 104 return NT_STATUS_INVALID_PARAMETER; 105 } 106 107 return gensec_unseal_packet(spnego_state->sub_sec_security, 108 mem_ctx, 109 data, length, 110 whole_pdu, pdu_length, 111 sig); 112} 113 114static NTSTATUS gensec_spnego_check_packet(struct gensec_security *gensec_security, 115 TALLOC_CTX *mem_ctx, 116 const uint8_t *data, size_t length, 117 const uint8_t *whole_pdu, size_t pdu_length, 118 const DATA_BLOB *sig) 119{ 120 struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data; 121 122 if (spnego_state->state_position != SPNEGO_DONE 123 && spnego_state->state_position != SPNEGO_FALLBACK) { 124 return NT_STATUS_INVALID_PARAMETER; 125 } 126 127 return gensec_check_packet(spnego_state->sub_sec_security, 128 mem_ctx, 129 data, length, 130 whole_pdu, pdu_length, 131 sig); 132} 133 134static NTSTATUS gensec_spnego_seal_packet(struct gensec_security *gensec_security, 135 TALLOC_CTX *mem_ctx, 136 uint8_t *data, size_t length, 137 const uint8_t *whole_pdu, size_t pdu_length, 138 DATA_BLOB *sig) 139{ 140 struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data; 141 142 if (spnego_state->state_position != SPNEGO_DONE 143 && spnego_state->state_position != SPNEGO_FALLBACK) { 144 return NT_STATUS_INVALID_PARAMETER; 145 } 146 147 return gensec_seal_packet(spnego_state->sub_sec_security, 148 mem_ctx, 149 data, length, 150 whole_pdu, pdu_length, 151 sig); 152} 153 154static NTSTATUS gensec_spnego_sign_packet(struct gensec_security *gensec_security, 155 TALLOC_CTX *mem_ctx, 156 const uint8_t *data, size_t length, 157 const uint8_t *whole_pdu, size_t pdu_length, 158 DATA_BLOB *sig) 159{ 160 struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data; 161 162 if (spnego_state->state_position != SPNEGO_DONE 163 && spnego_state->state_position != SPNEGO_FALLBACK) { 164 return NT_STATUS_INVALID_PARAMETER; 165 } 166 167 return gensec_sign_packet(spnego_state->sub_sec_security, 168 mem_ctx, 169 data, length, 170 whole_pdu, pdu_length, 171 sig); 172} 173 174static NTSTATUS gensec_spnego_wrap(struct gensec_security *gensec_security, 175 TALLOC_CTX *mem_ctx, 176 const DATA_BLOB *in, 177 DATA_BLOB *out) 178{ 179 struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data; 180 181 if (spnego_state->state_position != SPNEGO_DONE 182 && spnego_state->state_position != SPNEGO_FALLBACK) { 183 DEBUG(1, ("gensec_spnego_wrap: wrong state for wrap\n")); 184 return NT_STATUS_INVALID_PARAMETER; 185 } 186 187 return gensec_wrap(spnego_state->sub_sec_security, 188 mem_ctx, in, out); 189} 190 191static NTSTATUS gensec_spnego_unwrap(struct gensec_security *gensec_security, 192 TALLOC_CTX *mem_ctx, 193 const DATA_BLOB *in, 194 DATA_BLOB *out) 195{ 196 struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data; 197 198 if (spnego_state->state_position != SPNEGO_DONE 199 && spnego_state->state_position != SPNEGO_FALLBACK) { 200 DEBUG(1, ("gensec_spnego_unwrap: wrong state for unwrap\n")); 201 return NT_STATUS_INVALID_PARAMETER; 202 } 203 204 return gensec_unwrap(spnego_state->sub_sec_security, 205 mem_ctx, in, out); 206} 207 208static NTSTATUS gensec_spnego_wrap_packets(struct gensec_security *gensec_security, 209 TALLOC_CTX *mem_ctx, 210 const DATA_BLOB *in, 211 DATA_BLOB *out, 212 size_t *len_processed) 213{ 214 struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data; 215 216 if (spnego_state->state_position != SPNEGO_DONE 217 && spnego_state->state_position != SPNEGO_FALLBACK) { 218 DEBUG(1, ("gensec_spnego_wrap: wrong state for wrap\n")); 219 return NT_STATUS_INVALID_PARAMETER; 220 } 221 222 return gensec_wrap_packets(spnego_state->sub_sec_security, 223 mem_ctx, in, out, 224 len_processed); 225} 226 227static NTSTATUS gensec_spnego_packet_full_request(struct gensec_security *gensec_security, 228 DATA_BLOB blob, size_t *size) 229{ 230 struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data; 231 232 if (spnego_state->state_position != SPNEGO_DONE 233 && spnego_state->state_position != SPNEGO_FALLBACK) { 234 DEBUG(1, ("gensec_spnego_unwrap: wrong state for unwrap\n")); 235 return NT_STATUS_INVALID_PARAMETER; 236 } 237 238 return gensec_packet_full_request(spnego_state->sub_sec_security, 239 blob, size); 240} 241 242static NTSTATUS gensec_spnego_unwrap_packets(struct gensec_security *gensec_security, 243 TALLOC_CTX *mem_ctx, 244 const DATA_BLOB *in, 245 DATA_BLOB *out, 246 size_t *len_processed) 247{ 248 struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data; 249 250 if (spnego_state->state_position != SPNEGO_DONE 251 && spnego_state->state_position != SPNEGO_FALLBACK) { 252 DEBUG(1, ("gensec_spnego_unwrap: wrong state for unwrap\n")); 253 return NT_STATUS_INVALID_PARAMETER; 254 } 255 256 return gensec_unwrap_packets(spnego_state->sub_sec_security, 257 mem_ctx, in, out, 258 len_processed); 259} 260 261static size_t gensec_spnego_sig_size(struct gensec_security *gensec_security, size_t data_size) 262{ 263 struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data; 264 265 if (spnego_state->state_position != SPNEGO_DONE 266 && spnego_state->state_position != SPNEGO_FALLBACK) { 267 return 0; 268 } 269 270 return gensec_sig_size(spnego_state->sub_sec_security, data_size); 271} 272 273static size_t gensec_spnego_max_input_size(struct gensec_security *gensec_security) 274{ 275 struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data; 276 277 if (spnego_state->state_position != SPNEGO_DONE 278 && spnego_state->state_position != SPNEGO_FALLBACK) { 279 return 0; 280 } 281 282 return gensec_max_input_size(spnego_state->sub_sec_security); 283} 284 285static size_t gensec_spnego_max_wrapped_size(struct gensec_security *gensec_security) 286{ 287 struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data; 288 289 if (spnego_state->state_position != SPNEGO_DONE 290 && spnego_state->state_position != SPNEGO_FALLBACK) { 291 return 0; 292 } 293 294 return gensec_max_wrapped_size(spnego_state->sub_sec_security); 295} 296 297static NTSTATUS gensec_spnego_session_key(struct gensec_security *gensec_security, 298 DATA_BLOB *session_key) 299{ 300 struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data; 301 if (!spnego_state->sub_sec_security) { 302 return NT_STATUS_INVALID_PARAMETER; 303 } 304 305 return gensec_session_key(spnego_state->sub_sec_security, 306 session_key); 307} 308 309static NTSTATUS gensec_spnego_session_info(struct gensec_security *gensec_security, 310 struct auth_session_info **session_info) 311{ 312 struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data; 313 if (!spnego_state->sub_sec_security) { 314 return NT_STATUS_INVALID_PARAMETER; 315 } 316 317 return gensec_session_info(spnego_state->sub_sec_security, 318 session_info); 319} 320 321/** Fallback to another GENSEC mechanism, based on magic strings 322 * 323 * This is the 'fallback' case, where we don't get SPNEGO, and have to 324 * try all the other options (and hope they all have a magic string 325 * they check) 326*/ 327 328static NTSTATUS gensec_spnego_server_try_fallback(struct gensec_security *gensec_security, 329 struct spnego_state *spnego_state, 330 TALLOC_CTX *out_mem_ctx, 331 const DATA_BLOB in, DATA_BLOB *out) 332{ 333 int i,j; 334 struct gensec_security_ops **all_ops 335 = gensec_security_mechs(gensec_security, out_mem_ctx); 336 for (i=0; all_ops[i]; i++) { 337 bool is_spnego; 338 NTSTATUS nt_status; 339 340 if (gensec_security != NULL && 341 !gensec_security_ops_enabled(all_ops[i], gensec_security)) 342 continue; 343 344 if (!all_ops[i]->oid) { 345 continue; 346 } 347 348 is_spnego = false; 349 for (j=0; all_ops[i]->oid[j]; j++) { 350 if (strcasecmp(GENSEC_OID_SPNEGO,all_ops[i]->oid[j]) == 0) { 351 is_spnego = true; 352 } 353 } 354 if (is_spnego) { 355 continue; 356 } 357 358 if (!all_ops[i]->magic) { 359 continue; 360 } 361 362 nt_status = all_ops[i]->magic(gensec_security, &in); 363 if (!NT_STATUS_IS_OK(nt_status)) { 364 continue; 365 } 366 367 spnego_state->state_position = SPNEGO_FALLBACK; 368 369 nt_status = gensec_subcontext_start(spnego_state, 370 gensec_security, 371 &spnego_state->sub_sec_security); 372 373 if (!NT_STATUS_IS_OK(nt_status)) { 374 return nt_status; 375 } 376 /* select the sub context */ 377 nt_status = gensec_start_mech_by_ops(spnego_state->sub_sec_security, 378 all_ops[i]); 379 if (!NT_STATUS_IS_OK(nt_status)) { 380 return nt_status; 381 } 382 nt_status = gensec_update(spnego_state->sub_sec_security, 383 out_mem_ctx, in, out); 384 return nt_status; 385 } 386 DEBUG(1, ("Failed to parse SPNEGO request\n")); 387 return NT_STATUS_INVALID_PARAMETER; 388 389} 390 391/* 392 Parse the netTokenInit, either from the client, to the server, or 393 from the server to the client. 394*/ 395 396static NTSTATUS gensec_spnego_parse_negTokenInit(struct gensec_security *gensec_security, 397 struct spnego_state *spnego_state, 398 TALLOC_CTX *out_mem_ctx, 399 const char **mechType, 400 const DATA_BLOB unwrapped_in, DATA_BLOB *unwrapped_out) 401{ 402 int i; 403 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER; 404 DATA_BLOB null_data_blob = data_blob(NULL,0); 405 bool ok; 406 407 const struct gensec_security_ops_wrapper *all_sec 408 = gensec_security_by_oid_list(gensec_security, 409 out_mem_ctx, 410 mechType, 411 GENSEC_OID_SPNEGO); 412 413 ok = spnego_write_mech_types(spnego_state, 414 mechType, 415 &spnego_state->mech_types); 416 if (!ok) { 417 DEBUG(1, ("SPNEGO: Failed to write mechTypes\n")); 418 return NT_STATUS_NO_MEMORY; 419 } 420 421 if (spnego_state->state_position == SPNEGO_SERVER_START) { 422 for (i=0; all_sec && all_sec[i].op; i++) { 423 /* optomisitic token */ 424 if (strcmp(all_sec[i].oid, mechType[0]) == 0) { 425 nt_status = gensec_subcontext_start(spnego_state, 426 gensec_security, 427 &spnego_state->sub_sec_security); 428 if (!NT_STATUS_IS_OK(nt_status)) { 429 return nt_status; 430 } 431 /* select the sub context */ 432 nt_status = gensec_start_mech_by_ops(spnego_state->sub_sec_security, 433 all_sec[i].op); 434 if (!NT_STATUS_IS_OK(nt_status)) { 435 talloc_free(spnego_state->sub_sec_security); 436 spnego_state->sub_sec_security = NULL; 437 break; 438 } 439 440 nt_status = gensec_update(spnego_state->sub_sec_security, 441 out_mem_ctx, 442 unwrapped_in, 443 unwrapped_out); 444 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER) || 445 NT_STATUS_EQUAL(nt_status, NT_STATUS_CANT_ACCESS_DOMAIN_INFO)) { 446 /* Pretend we never started it (lets the first run find some incompatible demand) */ 447 448 DEBUG(1, ("SPNEGO(%s) NEG_TOKEN_INIT failed to parse contents: %s\n", 449 spnego_state->sub_sec_security->ops->name, nt_errstr(nt_status))); 450 talloc_free(spnego_state->sub_sec_security); 451 spnego_state->sub_sec_security = NULL; 452 break; 453 } 454 455 spnego_state->neg_oid = all_sec[i].oid; 456 break; 457 } 458 } 459 } 460 461 /* Having tried any optomisitc token from the client (if we 462 * were the server), if we didn't get anywhere, walk our list 463 * in our preference order */ 464 465 if (!spnego_state->sub_sec_security) { 466 for (i=0; all_sec && all_sec[i].op; i++) { 467 nt_status = gensec_subcontext_start(spnego_state, 468 gensec_security, 469 &spnego_state->sub_sec_security); 470 if (!NT_STATUS_IS_OK(nt_status)) { 471 return nt_status; 472 } 473 /* select the sub context */ 474 nt_status = gensec_start_mech_by_ops(spnego_state->sub_sec_security, 475 all_sec[i].op); 476 if (!NT_STATUS_IS_OK(nt_status)) { 477 talloc_free(spnego_state->sub_sec_security); 478 spnego_state->sub_sec_security = NULL; 479 continue; 480 } 481 482 spnego_state->neg_oid = all_sec[i].oid; 483 484 /* only get the helping start blob for the first OID */ 485 nt_status = gensec_update(spnego_state->sub_sec_security, 486 out_mem_ctx, 487 null_data_blob, 488 unwrapped_out); 489 490 /* it is likely that a NULL input token will 491 * not be liked by most server mechs, but if 492 * we are in the client, we want the first 493 * update packet to be able to abort the use 494 * of this mech */ 495 if (spnego_state->state_position != SPNEGO_SERVER_START) { 496 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER) || 497 NT_STATUS_EQUAL(nt_status, NT_STATUS_CANT_ACCESS_DOMAIN_INFO)) { 498 /* Pretend we never started it (lets the first run find some incompatible demand) */ 499 500 DEBUG(1, ("SPNEGO(%s) NEG_TOKEN_INIT failed to parse: %s\n", 501 spnego_state->sub_sec_security->ops->name, nt_errstr(nt_status))); 502 talloc_free(spnego_state->sub_sec_security); 503 spnego_state->sub_sec_security = NULL; 504 continue; 505 } 506 } 507 508 break; 509 } 510 } 511 512 if (spnego_state->sub_sec_security) { 513 /* it is likely that a NULL input token will 514 * not be liked by most server mechs, but this 515 * does the right thing in the CIFS client. 516 * just push us along the merry-go-round 517 * again, and hope for better luck next 518 * time */ 519 520 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) { 521 *unwrapped_out = data_blob(NULL, 0); 522 nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED; 523 } 524 525 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER) 526 && !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) 527 && !NT_STATUS_IS_OK(nt_status)) { 528 DEBUG(1, ("SPNEGO(%s) NEG_TOKEN_INIT failed: %s\n", 529 spnego_state->sub_sec_security->ops->name, nt_errstr(nt_status))); 530 talloc_free(spnego_state->sub_sec_security); 531 spnego_state->sub_sec_security = NULL; 532 533 /* We started the mech correctly, and the 534 * input from the other side was valid. 535 * Return the error (say bad password, invalid 536 * ticket) */ 537 return nt_status; 538 } 539 540 541 return nt_status; /* OK, INVALID_PARAMETER ore MORE PROCESSING */ 542 } 543 544 DEBUG(1, ("SPNEGO: Could not find a suitable mechtype in NEG_TOKEN_INIT\n")); 545 /* we could re-negotiate here, but it would only work 546 * if the client or server lied about what it could 547 * support the first time. Lets keep this code to 548 * reality */ 549 550 return nt_status; 551} 552 553/** create a negTokenInit 554 * 555 * This is the same packet, no matter if the client or server sends it first, but it is always the first packet 556*/ 557static NTSTATUS gensec_spnego_create_negTokenInit(struct gensec_security *gensec_security, 558 struct spnego_state *spnego_state, 559 TALLOC_CTX *out_mem_ctx, 560 const DATA_BLOB in, DATA_BLOB *out) 561{ 562 int i; 563 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER; 564 DATA_BLOB null_data_blob = data_blob(NULL,0); 565 const char **mechTypes = NULL; 566 DATA_BLOB unwrapped_out = data_blob(NULL, 0); 567 const struct gensec_security_ops_wrapper *all_sec; 568 const char *principal = NULL; 569 570 mechTypes = gensec_security_oids(gensec_security, 571 out_mem_ctx, GENSEC_OID_SPNEGO); 572 573 all_sec = gensec_security_by_oid_list(gensec_security, 574 out_mem_ctx, 575 mechTypes, 576 GENSEC_OID_SPNEGO); 577 for (i=0; all_sec && all_sec[i].op; i++) { 578 struct spnego_data spnego_out; 579 const char **send_mech_types; 580 bool ok; 581 582 nt_status = gensec_subcontext_start(spnego_state, 583 gensec_security, 584 &spnego_state->sub_sec_security); 585 if (!NT_STATUS_IS_OK(nt_status)) { 586 return nt_status; 587 } 588 /* select the sub context */ 589 nt_status = gensec_start_mech_by_ops(spnego_state->sub_sec_security, 590 all_sec[i].op); 591 if (!NT_STATUS_IS_OK(nt_status)) { 592 talloc_free(spnego_state->sub_sec_security); 593 spnego_state->sub_sec_security = NULL; 594 continue; 595 } 596 597 /* In the client, try and produce the first (optimistic) packet */ 598 if (spnego_state->state_position == SPNEGO_CLIENT_START) { 599 nt_status = gensec_update(spnego_state->sub_sec_security, 600 out_mem_ctx, 601 null_data_blob, 602 &unwrapped_out); 603 604 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) 605 && !NT_STATUS_IS_OK(nt_status)) { 606 DEBUG(1, ("SPNEGO(%s) creating NEG_TOKEN_INIT failed: %s\n", 607 spnego_state->sub_sec_security->ops->name, nt_errstr(nt_status))); 608 talloc_free(spnego_state->sub_sec_security); 609 spnego_state->sub_sec_security = NULL; 610 /* Pretend we never started it (lets the first run find some incompatible demand) */ 611 612 continue; 613 } 614 } 615 616 spnego_out.type = SPNEGO_NEG_TOKEN_INIT; 617 618 send_mech_types = gensec_security_oids_from_ops_wrapped(out_mem_ctx, 619 &all_sec[i]); 620 621 ok = spnego_write_mech_types(spnego_state, 622 send_mech_types, 623 &spnego_state->mech_types); 624 if (!ok) { 625 DEBUG(1, ("SPNEGO: Failed to write mechTypes\n")); 626 return NT_STATUS_NO_MEMORY; 627 } 628 629 /* List the remaining mechs as options */ 630 spnego_out.negTokenInit.mechTypes = send_mech_types; 631 spnego_out.negTokenInit.reqFlags = null_data_blob; 632 spnego_out.negTokenInit.reqFlagsPadding = 0; 633 634 if (spnego_state->state_position == SPNEGO_SERVER_START) { 635 /* server credentials */ 636 struct cli_credentials *creds = gensec_get_credentials(gensec_security); 637 if (creds) { 638 principal = cli_credentials_get_principal(creds, out_mem_ctx); 639 } 640 } 641 if (principal) { 642 spnego_out.negTokenInit.mechListMIC 643 = data_blob_string_const(principal); 644 } else { 645 spnego_out.negTokenInit.mechListMIC = null_data_blob; 646 } 647 648 spnego_out.negTokenInit.mechToken = unwrapped_out; 649 650 if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) { 651 DEBUG(1, ("Failed to write NEG_TOKEN_INIT\n")); 652 return NT_STATUS_INVALID_PARAMETER; 653 } 654 655 /* set next state */ 656 spnego_state->neg_oid = all_sec[i].oid; 657 658 if (NT_STATUS_IS_OK(nt_status)) { 659 spnego_state->no_response_expected = true; 660 } 661 662 return NT_STATUS_MORE_PROCESSING_REQUIRED; 663 } 664 talloc_free(spnego_state->sub_sec_security); 665 spnego_state->sub_sec_security = NULL; 666 667 DEBUG(1, ("Failed to setup SPNEGO negTokenInit request: %s\n", nt_errstr(nt_status))); 668 return NT_STATUS_INVALID_PARAMETER; 669} 670 671 672/** create a server negTokenTarg 673 * 674 * This is the case, where the client is the first one who sends data 675*/ 676 677static NTSTATUS gensec_spnego_server_negTokenTarg(struct gensec_security *gensec_security, 678 struct spnego_state *spnego_state, 679 TALLOC_CTX *out_mem_ctx, 680 NTSTATUS nt_status, 681 const DATA_BLOB unwrapped_out, 682 DATA_BLOB mech_list_mic, 683 DATA_BLOB *out) 684{ 685 struct spnego_data spnego_out; 686 DATA_BLOB null_data_blob = data_blob(NULL, 0); 687 688 /* compose reply */ 689 spnego_out.type = SPNEGO_NEG_TOKEN_TARG; 690 spnego_out.negTokenTarg.responseToken = unwrapped_out; 691 spnego_out.negTokenTarg.mechListMIC = null_data_blob; 692 spnego_out.negTokenTarg.supportedMech = NULL; 693 694 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { 695 spnego_out.negTokenTarg.supportedMech = spnego_state->neg_oid; 696 spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE; 697 spnego_state->state_position = SPNEGO_SERVER_TARG; 698 } else if (NT_STATUS_IS_OK(nt_status)) { 699 if (unwrapped_out.data) { 700 spnego_out.negTokenTarg.supportedMech = spnego_state->neg_oid; 701 } 702 spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_COMPLETED; 703 spnego_out.negTokenTarg.mechListMIC = mech_list_mic; 704 spnego_state->state_position = SPNEGO_DONE; 705 } else { 706 spnego_out.negTokenTarg.negResult = SPNEGO_REJECT; 707 DEBUG(2, ("SPNEGO login failed: %s\n", nt_errstr(nt_status))); 708 spnego_state->state_position = SPNEGO_DONE; 709 } 710 711 if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) { 712 DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_TARG\n")); 713 return NT_STATUS_INVALID_PARAMETER; 714 } 715 716 spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG; 717 718 return nt_status; 719} 720 721 722static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, 723 const DATA_BLOB in, DATA_BLOB *out) 724{ 725 struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data; 726 DATA_BLOB null_data_blob = data_blob(NULL, 0); 727 DATA_BLOB mech_list_mic = data_blob(NULL, 0); 728 DATA_BLOB unwrapped_out = data_blob(NULL, 0); 729 struct spnego_data spnego_out; 730 struct spnego_data spnego; 731 732 ssize_t len; 733 734 *out = data_blob(NULL, 0); 735 736 if (!out_mem_ctx) { 737 out_mem_ctx = spnego_state; 738 } 739 740 /* and switch into the state machine */ 741 742 switch (spnego_state->state_position) { 743 case SPNEGO_FALLBACK: 744 return gensec_update(spnego_state->sub_sec_security, 745 out_mem_ctx, in, out); 746 case SPNEGO_SERVER_START: 747 { 748 NTSTATUS nt_status; 749 if (in.length) { 750 751 len = spnego_read_data(gensec_security, in, &spnego); 752 if (len == -1) { 753 return gensec_spnego_server_try_fallback(gensec_security, spnego_state, 754 out_mem_ctx, in, out); 755 } 756 /* client sent NegTargetInit, we send NegTokenTarg */ 757 758 /* OK, so it's real SPNEGO, check the packet's the one we expect */ 759 if (spnego.type != spnego_state->expected_packet) { 760 DEBUG(1, ("Invalid SPNEGO request: %d, expected %d\n", spnego.type, 761 spnego_state->expected_packet)); 762 dump_data(1, in.data, in.length); 763 spnego_free_data(&spnego); 764 return NT_STATUS_INVALID_PARAMETER; 765 } 766 767 nt_status = gensec_spnego_parse_negTokenInit(gensec_security, 768 spnego_state, 769 out_mem_ctx, 770 spnego.negTokenInit.mechTypes, 771 spnego.negTokenInit.mechToken, 772 &unwrapped_out); 773 774 nt_status = gensec_spnego_server_negTokenTarg(gensec_security, 775 spnego_state, 776 out_mem_ctx, 777 nt_status, 778 unwrapped_out, 779 null_data_blob, 780 out); 781 782 spnego_free_data(&spnego); 783 784 return nt_status; 785 } else { 786 nt_status = gensec_spnego_create_negTokenInit(gensec_security, spnego_state, 787 out_mem_ctx, in, out); 788 spnego_state->state_position = SPNEGO_SERVER_START; 789 spnego_state->expected_packet = SPNEGO_NEG_TOKEN_INIT; 790 return nt_status; 791 } 792 } 793 794 case SPNEGO_CLIENT_START: 795 { 796 /* The server offers a list of mechanisms */ 797 798 const char *my_mechs[] = {NULL, NULL}; 799 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER; 800 801 if (!in.length) { 802 /* client to produce negTokenInit */ 803 nt_status = gensec_spnego_create_negTokenInit(gensec_security, spnego_state, 804 out_mem_ctx, in, out); 805 spnego_state->state_position = SPNEGO_CLIENT_TARG; 806 spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG; 807 return nt_status; 808 } 809 810 len = spnego_read_data(gensec_security, in, &spnego); 811 812 if (len == -1) { 813 DEBUG(1, ("Invalid SPNEGO request:\n")); 814 dump_data(1, in.data, in.length); 815 return NT_STATUS_INVALID_PARAMETER; 816 } 817 818 /* OK, so it's real SPNEGO, check the packet's the one we expect */ 819 if (spnego.type != spnego_state->expected_packet) { 820 DEBUG(1, ("Invalid SPNEGO request: %d, expected %d\n", spnego.type, 821 spnego_state->expected_packet)); 822 dump_data(1, in.data, in.length); 823 spnego_free_data(&spnego); 824 return NT_STATUS_INVALID_PARAMETER; 825 } 826 827 if (spnego.negTokenInit.targetPrincipal) { 828 DEBUG(5, ("Server claims it's principal name is %s\n", spnego.negTokenInit.targetPrincipal)); 829 gensec_set_target_principal(gensec_security, spnego.negTokenInit.targetPrincipal); 830 } 831 832 nt_status = gensec_spnego_parse_negTokenInit(gensec_security, 833 spnego_state, 834 out_mem_ctx, 835 spnego.negTokenInit.mechTypes, 836 spnego.negTokenInit.mechToken, 837 &unwrapped_out); 838 839 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(nt_status)) { 840 spnego_free_data(&spnego); 841 return nt_status; 842 } 843 844 my_mechs[0] = spnego_state->neg_oid; 845 /* compose reply */ 846 spnego_out.type = SPNEGO_NEG_TOKEN_INIT; 847 spnego_out.negTokenInit.mechTypes = my_mechs; 848 spnego_out.negTokenInit.reqFlags = null_data_blob; 849 spnego_out.negTokenInit.reqFlagsPadding = 0; 850 spnego_out.negTokenInit.mechListMIC = null_data_blob; 851 spnego_out.negTokenInit.mechToken = unwrapped_out; 852 853 if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) { 854 DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_INIT\n")); 855 return NT_STATUS_INVALID_PARAMETER; 856 } 857 858 /* set next state */ 859 spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG; 860 spnego_state->state_position = SPNEGO_CLIENT_TARG; 861 862 if (NT_STATUS_IS_OK(nt_status)) { 863 spnego_state->no_response_expected = true; 864 } 865 866 spnego_free_data(&spnego); 867 return NT_STATUS_MORE_PROCESSING_REQUIRED; 868 } 869 case SPNEGO_SERVER_TARG: 870 { 871 NTSTATUS nt_status; 872 bool new_spnego = false; 873 874 if (!in.length) { 875 return NT_STATUS_INVALID_PARAMETER; 876 } 877 878 len = spnego_read_data(gensec_security, in, &spnego); 879 880 if (len == -1) { 881 DEBUG(1, ("Invalid SPNEGO request:\n")); 882 dump_data(1, in.data, in.length); 883 return NT_STATUS_INVALID_PARAMETER; 884 } 885 886 /* OK, so it's real SPNEGO, check the packet's the one we expect */ 887 if (spnego.type != spnego_state->expected_packet) { 888 DEBUG(1, ("Invalid SPNEGO request: %d, expected %d\n", spnego.type, 889 spnego_state->expected_packet)); 890 dump_data(1, in.data, in.length); 891 spnego_free_data(&spnego); 892 return NT_STATUS_INVALID_PARAMETER; 893 } 894 895 if (!spnego_state->sub_sec_security) { 896 DEBUG(1, ("SPNEGO: Did not setup a mech in NEG_TOKEN_INIT\n")); 897 spnego_free_data(&spnego); 898 return NT_STATUS_INVALID_PARAMETER; 899 } 900 901 nt_status = gensec_update(spnego_state->sub_sec_security, 902 out_mem_ctx, 903 spnego.negTokenTarg.responseToken, 904 &unwrapped_out); 905 if (NT_STATUS_IS_OK(nt_status) && spnego.negTokenTarg.mechListMIC.length > 0) { 906 new_spnego = true; 907 nt_status = gensec_check_packet(spnego_state->sub_sec_security, 908 out_mem_ctx, 909 spnego_state->mech_types.data, 910 spnego_state->mech_types.length, 911 spnego_state->mech_types.data, 912 spnego_state->mech_types.length, 913 &spnego.negTokenTarg.mechListMIC); 914 if (!NT_STATUS_IS_OK(nt_status)) { 915 DEBUG(2,("GENSEC SPNEGO: failed to verify mechListMIC: %s\n", 916 nt_errstr(nt_status))); 917 } 918 } 919 if (NT_STATUS_IS_OK(nt_status) && new_spnego) { 920 nt_status = gensec_sign_packet(spnego_state->sub_sec_security, 921 out_mem_ctx, 922 spnego_state->mech_types.data, 923 spnego_state->mech_types.length, 924 spnego_state->mech_types.data, 925 spnego_state->mech_types.length, 926 &mech_list_mic); 927 if (!NT_STATUS_IS_OK(nt_status)) { 928 DEBUG(2,("GENSEC SPNEGO: failed to sign mechListMIC: %s\n", 929 nt_errstr(nt_status))); 930 } 931 } 932 933 nt_status = gensec_spnego_server_negTokenTarg(gensec_security, 934 spnego_state, 935 out_mem_ctx, 936 nt_status, 937 unwrapped_out, 938 mech_list_mic, 939 out); 940 941 spnego_free_data(&spnego); 942 943 return nt_status; 944 } 945 case SPNEGO_CLIENT_TARG: 946 { 947 NTSTATUS nt_status; 948 if (!in.length) { 949 return NT_STATUS_INVALID_PARAMETER; 950 } 951 952 len = spnego_read_data(gensec_security, in, &spnego); 953 954 if (len == -1) { 955 DEBUG(1, ("Invalid SPNEGO request:\n")); 956 dump_data(1, in.data, in.length); 957 return NT_STATUS_INVALID_PARAMETER; 958 } 959 960 /* OK, so it's real SPNEGO, check the packet's the one we expect */ 961 if (spnego.type != spnego_state->expected_packet) { 962 DEBUG(1, ("Invalid SPNEGO request: %d, expected %d\n", spnego.type, 963 spnego_state->expected_packet)); 964 dump_data(1, in.data, in.length); 965 spnego_free_data(&spnego); 966 return NT_STATUS_INVALID_PARAMETER; 967 } 968 969 if (spnego.negTokenTarg.negResult == SPNEGO_REJECT) { 970 spnego_free_data(&spnego); 971 return NT_STATUS_ACCESS_DENIED; 972 } 973 974 /* Server didn't like our choice of mech, and chose something else */ 975 if ((spnego.negTokenTarg.negResult == SPNEGO_ACCEPT_INCOMPLETE) && 976 spnego.negTokenTarg.supportedMech && 977 strcmp(spnego.negTokenTarg.supportedMech, spnego_state->neg_oid) != 0) { 978 DEBUG(3,("GENSEC SPNEGO: client preferred mech (%s) not accepted, server wants: %s\n", 979 gensec_get_name_by_oid(gensec_security, spnego.negTokenTarg.supportedMech), 980 gensec_get_name_by_oid(gensec_security, spnego_state->neg_oid))); 981 982 talloc_free(spnego_state->sub_sec_security); 983 nt_status = gensec_subcontext_start(spnego_state, 984 gensec_security, 985 &spnego_state->sub_sec_security); 986 if (!NT_STATUS_IS_OK(nt_status)) { 987 spnego_free_data(&spnego); 988 return nt_status; 989 } 990 /* select the sub context */ 991 nt_status = gensec_start_mech_by_oid(spnego_state->sub_sec_security, 992 spnego.negTokenTarg.supportedMech); 993 if (!NT_STATUS_IS_OK(nt_status)) { 994 spnego_free_data(&spnego); 995 return nt_status; 996 } 997 998 nt_status = gensec_update(spnego_state->sub_sec_security, 999 out_mem_ctx, 1000 spnego.negTokenTarg.responseToken, 1001 &unwrapped_out); 1002 spnego_state->neg_oid = talloc_strdup(spnego_state, spnego.negTokenTarg.supportedMech); 1003 } else if (spnego_state->no_response_expected) { 1004 if (spnego.negTokenTarg.negResult != SPNEGO_ACCEPT_COMPLETED) { 1005 DEBUG(3,("GENSEC SPNEGO: client GENSEC accepted, but server rejected (bad password?)\n")); 1006 nt_status = NT_STATUS_INVALID_PARAMETER; 1007 } else if (spnego.negTokenTarg.responseToken.length) { 1008 DEBUG(2,("GENSEC SPNEGO: client GENSEC accepted, but server continued negotiation!\n")); 1009 nt_status = NT_STATUS_INVALID_PARAMETER; 1010 } else { 1011 nt_status = NT_STATUS_OK; 1012 } 1013 if (NT_STATUS_IS_OK(nt_status) && spnego.negTokenTarg.mechListMIC.length > 0) { 1014 nt_status = gensec_check_packet(spnego_state->sub_sec_security, 1015 out_mem_ctx, 1016 spnego_state->mech_types.data, 1017 spnego_state->mech_types.length, 1018 spnego_state->mech_types.data, 1019 spnego_state->mech_types.length, 1020 &spnego.negTokenTarg.mechListMIC); 1021 if (!NT_STATUS_IS_OK(nt_status)) { 1022 DEBUG(2,("GENSEC SPNEGO: failed to verify mechListMIC: %s\n", 1023 nt_errstr(nt_status))); 1024 } 1025 } 1026 } else { 1027 bool new_spnego = false; 1028 1029 nt_status = gensec_update(spnego_state->sub_sec_security, 1030 out_mem_ctx, 1031 spnego.negTokenTarg.responseToken, 1032 &unwrapped_out); 1033 1034 if (NT_STATUS_IS_OK(nt_status) 1035 && spnego.negTokenTarg.negResult != SPNEGO_ACCEPT_COMPLETED) { 1036 new_spnego = gensec_have_feature(spnego_state->sub_sec_security, 1037 GENSEC_FEATURE_NEW_SPNEGO); 1038 } 1039 if (NT_STATUS_IS_OK(nt_status) && new_spnego) { 1040 nt_status = gensec_sign_packet(spnego_state->sub_sec_security, 1041 out_mem_ctx, 1042 spnego_state->mech_types.data, 1043 spnego_state->mech_types.length, 1044 spnego_state->mech_types.data, 1045 spnego_state->mech_types.length, 1046 &mech_list_mic); 1047 if (!NT_STATUS_IS_OK(nt_status)) { 1048 DEBUG(2,("GENSEC SPNEGO: failed to sign mechListMIC: %s\n", 1049 nt_errstr(nt_status))); 1050 } 1051 } 1052 if (NT_STATUS_IS_OK(nt_status)) { 1053 spnego_state->no_response_expected = true; 1054 } 1055 } 1056 1057 spnego_free_data(&spnego); 1058 1059 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) 1060 && !NT_STATUS_IS_OK(nt_status)) { 1061 DEBUG(1, ("SPNEGO(%s) login failed: %s\n", 1062 spnego_state->sub_sec_security->ops->name, 1063 nt_errstr(nt_status))); 1064 return nt_status; 1065 } 1066 1067 if (unwrapped_out.length || mech_list_mic.length) { 1068 /* compose reply */ 1069 spnego_out.type = SPNEGO_NEG_TOKEN_TARG; 1070 spnego_out.negTokenTarg.negResult = SPNEGO_NONE_RESULT; 1071 spnego_out.negTokenTarg.supportedMech = NULL; 1072 spnego_out.negTokenTarg.responseToken = unwrapped_out; 1073 spnego_out.negTokenTarg.mechListMIC = mech_list_mic; 1074 1075 if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) { 1076 DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_TARG\n")); 1077 return NT_STATUS_INVALID_PARAMETER; 1078 } 1079 1080 spnego_state->state_position = SPNEGO_CLIENT_TARG; 1081 nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED; 1082 } else { 1083 1084 /* all done - server has accepted, and we agree */ 1085 *out = null_data_blob; 1086 1087 if (spnego.negTokenTarg.negResult != SPNEGO_ACCEPT_COMPLETED) { 1088 /* unless of course it did not accept */ 1089 DEBUG(1,("gensec_update ok but not accepted\n")); 1090 nt_status = NT_STATUS_INVALID_PARAMETER; 1091 } 1092 1093 spnego_state->state_position = SPNEGO_DONE; 1094 } 1095 1096 return nt_status; 1097 } 1098 case SPNEGO_DONE: 1099 /* We should not be called after we are 'done' */ 1100 return NT_STATUS_INVALID_PARAMETER; 1101 } 1102 return NT_STATUS_INVALID_PARAMETER; 1103} 1104 1105static void gensec_spnego_want_feature(struct gensec_security *gensec_security, 1106 uint32_t feature) 1107{ 1108 struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data; 1109 1110 if (!spnego_state || !spnego_state->sub_sec_security) { 1111 gensec_security->want_features |= feature; 1112 return; 1113 } 1114 1115 gensec_want_feature(spnego_state->sub_sec_security, 1116 feature); 1117} 1118 1119static bool gensec_spnego_have_feature(struct gensec_security *gensec_security, 1120 uint32_t feature) 1121{ 1122 struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data; 1123 if (!spnego_state->sub_sec_security) { 1124 return false; 1125 } 1126 1127 return gensec_have_feature(spnego_state->sub_sec_security, 1128 feature); 1129} 1130 1131static const char *gensec_spnego_oids[] = { 1132 GENSEC_OID_SPNEGO, 1133 NULL 1134}; 1135 1136static const struct gensec_security_ops gensec_spnego_security_ops = { 1137 .name = "spnego", 1138 .sasl_name = "GSS-SPNEGO", 1139 .auth_type = DCERPC_AUTH_TYPE_SPNEGO, 1140 .oid = gensec_spnego_oids, 1141 .client_start = gensec_spnego_client_start, 1142 .server_start = gensec_spnego_server_start, 1143 .update = gensec_spnego_update, 1144 .seal_packet = gensec_spnego_seal_packet, 1145 .sign_packet = gensec_spnego_sign_packet, 1146 .sig_size = gensec_spnego_sig_size, 1147 .max_wrapped_size = gensec_spnego_max_wrapped_size, 1148 .max_input_size = gensec_spnego_max_input_size, 1149 .check_packet = gensec_spnego_check_packet, 1150 .unseal_packet = gensec_spnego_unseal_packet, 1151 .packet_full_request = gensec_spnego_packet_full_request, 1152 .wrap = gensec_spnego_wrap, 1153 .unwrap = gensec_spnego_unwrap, 1154 .wrap_packets = gensec_spnego_wrap_packets, 1155 .unwrap_packets = gensec_spnego_unwrap_packets, 1156 .session_key = gensec_spnego_session_key, 1157 .session_info = gensec_spnego_session_info, 1158 .want_feature = gensec_spnego_want_feature, 1159 .have_feature = gensec_spnego_have_feature, 1160 .enabled = true, 1161 .priority = GENSEC_SPNEGO 1162}; 1163 1164_PUBLIC_ NTSTATUS gensec_spnego_init(void) 1165{ 1166 NTSTATUS ret; 1167 ret = gensec_register(&gensec_spnego_security_ops); 1168 if (!NT_STATUS_IS_OK(ret)) { 1169 DEBUG(0,("Failed to register '%s' gensec backend!\n", 1170 gensec_spnego_security_ops.name)); 1171 return ret; 1172 } 1173 1174 return ret; 1175} 1176