1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2015 Nexenta Systems, Inc. All rights reserved. 14 */ 15 16 /* 17 * SPNEGO back-end for NTLMSSP. See [MS-NLMP] 18 */ 19 20 #include <sys/types.h> 21 #include <sys/byteorder.h> 22 #include <strings.h> 23 #include "smbd.h" 24 #include "smbd_authsvc.h" 25 #include "netsmb/ntlmssp.h" 26 #include <assert.h> 27 28 /* A shorter alias for a crazy long name from [MS-NLMP] */ 29 #define NTLMSSP_NEGOTIATE_NTLM2 \ 30 NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY 31 32 /* Need this in a header somewhere */ 33 #ifdef _LITTLE_ENDIAN 34 /* little-endian values on little-endian */ 35 #define htolel(x) ((uint32_t)(x)) 36 #define letohl(x) ((uint32_t)(x)) 37 #else /* (BYTE_ORDER == LITTLE_ENDIAN) */ 38 /* little-endian values on big-endian (swap) */ 39 #define letohl(x) BSWAP_32(x) 40 #define htolel(x) BSWAP_32(x) 41 #endif /* (BYTE_ORDER == LITTLE_ENDIAN) */ 42 43 typedef struct ntlmssp_backend { 44 uint32_t expect_type; 45 uint32_t clnt_flags; 46 uint32_t srv_flags; 47 char srv_challenge[8]; 48 } ntlmssp_backend_t; 49 50 struct genhdr { 51 char h_id[8]; /* "NTLMSSP" */ 52 uint32_t h_type; 53 }; 54 55 struct sec_buf { 56 uint16_t sb_length; 57 uint16_t sb_maxlen; 58 uint32_t sb_offset; 59 }; 60 61 struct nego_hdr { 62 char h_id[8]; 63 uint32_t h_type; 64 uint32_t h_flags; 65 /* workstation domain, name (place holders) */ 66 uint16_t ws_dom[4]; 67 uint16_t ws_name[4]; 68 }; 69 70 struct auth_hdr { 71 char h_id[8]; 72 uint32_t h_type; 73 struct sec_buf h_lm_resp; 74 struct sec_buf h_nt_resp; 75 struct sec_buf h_domain; 76 struct sec_buf h_user; 77 struct sec_buf h_wksta; 78 struct sec_buf h_essn_key; /* encrypted session key */ 79 uint32_t h_flags; 80 /* Version struct (optional) */ 81 /* MIC hash (optional) */ 82 }; 83 84 /* Allow turning these off for debugging, etc. */ 85 int smbd_signing_enabled = 1; 86 87 int smbd_constant_challenge = 0; 88 static uint8_t constant_chal[8] = { 89 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 }; 90 91 static int smbd_ntlmssp_negotiate(authsvc_context_t *); 92 static int smbd_ntlmssp_authenticate(authsvc_context_t *); 93 static int encode_avpair_str(smb_msgbuf_t *, uint16_t, char *); 94 static int decode_secbuf_bin(smb_msgbuf_t *, struct sec_buf *, void **); 95 static int decode_secbuf_str(smb_msgbuf_t *, struct sec_buf *, char **); 96 97 /* 98 * Initialize this context for NTLMSSP, if possible. 99 */ 100 int 101 smbd_ntlmssp_init(authsvc_context_t *ctx) 102 { 103 ntlmssp_backend_t *be; 104 105 be = malloc(sizeof (*be)); 106 if (be == 0) 107 return (NT_STATUS_NO_MEMORY); 108 bzero(be, sizeof (*be)); 109 be->expect_type = NTLMSSP_MSGTYPE_NEGOTIATE; 110 ctx->ctx_backend = be; 111 112 return (0); 113 } 114 115 void 116 smbd_ntlmssp_fini(authsvc_context_t *ctx) 117 { 118 free(ctx->ctx_backend); 119 } 120 121 /* 122 * Handle an auth message 123 */ 124 int 125 smbd_ntlmssp_work(authsvc_context_t *ctx) 126 { 127 struct genhdr *ihdr = ctx->ctx_ibodybuf; 128 ntlmssp_backend_t *be = ctx->ctx_backend; 129 uint32_t mtype; 130 int rc; 131 132 if (ctx->ctx_ibodylen < sizeof (*ihdr)) 133 return (NT_STATUS_INVALID_PARAMETER); 134 135 if (bcmp(ihdr->h_id, "NTLMSSP", 8)) 136 return (NT_STATUS_INVALID_PARAMETER); 137 mtype = letohl(ihdr->h_type); 138 if (mtype != be->expect_type) 139 return (NT_STATUS_INVALID_PARAMETER); 140 141 switch (mtype) { 142 case NTLMSSP_MSGTYPE_NEGOTIATE: 143 ctx->ctx_orawtype = LSA_MTYPE_ES_CONT; 144 rc = smbd_ntlmssp_negotiate(ctx); 145 break; 146 case NTLMSSP_MSGTYPE_AUTHENTICATE: 147 ctx->ctx_orawtype = LSA_MTYPE_ES_DONE; 148 rc = smbd_ntlmssp_authenticate(ctx); 149 break; 150 151 default: 152 case NTLMSSP_MSGTYPE_CHALLENGE: 153 /* Sent by servers, not received. */ 154 rc = NT_STATUS_INVALID_PARAMETER; 155 break; 156 } 157 158 return (rc); 159 } 160 161 #if (MAXHOSTNAMELEN < NETBIOS_NAME_SZ) 162 #error "MAXHOSTNAMELEN < NETBIOS_NAME_SZ" 163 #endif 164 165 /* 166 * Handle an NTLMSSP_MSGTYPE_NEGOTIATE message, and reply 167 * with an NTLMSSP_MSGTYPE_CHALLENGE message. 168 * See: [MS-NLMP] 2.2.1.1, 3.2.5.1.1 169 */ 170 static int 171 smbd_ntlmssp_negotiate(authsvc_context_t *ctx) 172 { 173 char tmp_name[MAXHOSTNAMELEN]; 174 ntlmssp_backend_t *be = ctx->ctx_backend; 175 struct nego_hdr *ihdr = ctx->ctx_ibodybuf; 176 smb_msgbuf_t mb; 177 uint8_t *save_scan; 178 int secmode; 179 int mbflags; 180 int rc; 181 size_t var_start, var_end; 182 uint16_t var_size; 183 184 if (ctx->ctx_ibodylen < sizeof (*ihdr)) 185 return (NT_STATUS_INVALID_PARAMETER); 186 be->clnt_flags = letohl(ihdr->h_flags); 187 188 /* 189 * Looks like we can ignore ws_dom, ws_name. 190 * Otherwise would parse those here. 191 */ 192 193 secmode = smb_config_get_secmode(); 194 if (smbd_constant_challenge) { 195 (void) memcpy(be->srv_challenge, constant_chal, 196 sizeof (be->srv_challenge)); 197 } else { 198 randomize(be->srv_challenge, sizeof (be->srv_challenge)); 199 } 200 201 /* 202 * Compute srv_flags 203 */ 204 be->srv_flags = 205 NTLMSSP_REQUEST_TARGET | 206 NTLMSSP_NEGOTIATE_NTLM | 207 NTLMSSP_NEGOTIATE_TARGET_INFO; 208 be->srv_flags |= be->clnt_flags & ( 209 NTLMSSP_NEGOTIATE_NTLM2 | 210 NTLMSSP_NEGOTIATE_128 | 211 NTLMSSP_NEGOTIATE_KEY_EXCH | 212 NTLMSSP_NEGOTIATE_56); 213 214 if (smbd_signing_enabled) { 215 be->srv_flags |= be->clnt_flags & ( 216 NTLMSSP_NEGOTIATE_SIGN | 217 NTLMSSP_NEGOTIATE_SEAL | 218 NTLMSSP_NEGOTIATE_ALWAYS_SIGN); 219 } 220 221 if (be->clnt_flags & NTLMSSP_NEGOTIATE_UNICODE) 222 be->srv_flags |= NTLMSSP_NEGOTIATE_UNICODE; 223 else if (be->clnt_flags & NTLMSSP_NEGOTIATE_OEM) 224 be->srv_flags |= NTLMSSP_NEGOTIATE_OEM; 225 226 /* LM Key is mutually exclusive with NTLM2 */ 227 if ((be->srv_flags & NTLMSSP_NEGOTIATE_NTLM2) == 0 && 228 (be->clnt_flags & NTLMSSP_NEGOTIATE_LM_KEY) != 0) 229 be->srv_flags |= NTLMSSP_NEGOTIATE_LM_KEY; 230 231 /* Get our "target name" */ 232 if (secmode == SMB_SECMODE_DOMAIN) { 233 be->srv_flags |= NTLMSSP_TARGET_TYPE_DOMAIN; 234 rc = smb_getdomainname(tmp_name, NETBIOS_NAME_SZ); 235 } else { 236 be->srv_flags |= NTLMSSP_TARGET_TYPE_SERVER; 237 rc = smb_getnetbiosname(tmp_name, NETBIOS_NAME_SZ); 238 } 239 if (rc) 240 goto errout; 241 242 /* 243 * Build the NTLMSSP_MSGTYPE_CHALLENGE message. 244 */ 245 mbflags = SMB_MSGBUF_NOTERM; 246 if (be->srv_flags & NTLMSSP_NEGOTIATE_UNICODE) 247 mbflags |= SMB_MSGBUF_UNICODE; 248 smb_msgbuf_init(&mb, ctx->ctx_obodybuf, ctx->ctx_obodylen, mbflags); 249 250 /* 251 * Fixed size parts 252 */ 253 rc = smb_msgbuf_encode( 254 &mb, "8clwwll8cllwwl", /* offset, name (fmt) */ 255 "NTLMSSP", /* 0: signature (8c) */ 256 NTLMSSP_MSGTYPE_CHALLENGE, /* 8: type (l) */ 257 0, 0, 0, /* filled later: 12: target name (wwl) */ 258 be->srv_flags, /* 20: flags (l) */ 259 be->srv_challenge, /* 24: (8c) */ 260 0, 0, /* 32: reserved (ll) */ 261 0, 0, 0); /* filled later: 40: target info (wwl) */ 262 #define TARGET_NAME_OFFSET 12 263 #define TARGET_INFO_OFFSET 40 264 if (rc < 0) 265 goto errout; 266 267 /* 268 * Variable length parts. 269 * 270 * Target name 271 */ 272 var_start = smb_msgbuf_used(&mb); 273 rc = smb_msgbuf_encode(&mb, "u", tmp_name); 274 var_end = smb_msgbuf_used(&mb); 275 var_size = (uint16_t)(var_end - var_start); 276 if (rc < 0) 277 goto errout; 278 279 /* overwrite target name offset+lengths */ 280 save_scan = mb.scan; 281 mb.scan = mb.base + TARGET_NAME_OFFSET; 282 (void) smb_msgbuf_encode(&mb, "wwl", var_size, var_size, var_start); 283 mb.scan = save_scan; 284 285 /* 286 * Target info (AvPairList) 287 * 288 * These AV pairs are like our name/value pairs, but have 289 * numeric identifiers instead of names. There are many 290 * of these, but we put only the four expected by Windows: 291 * NetBIOS computer name 292 * NetBIOS domain name 293 * DNS computer name 294 * DNS domain name 295 * Note that "domain" above (even "DNS domain") refers to 296 * the AD domain of which we're a member, which may be 297 * _different_ from the configured DNS domain. 298 * 299 * Also note that in "workgroup" mode (not a domain member) 300 * all "domain" fields should be set to the same values as 301 * the "computer" fields ("bare" host name, not FQDN). 302 */ 303 var_start = smb_msgbuf_used(&mb); 304 305 /* NetBIOS Computer Name */ 306 if (smb_getnetbiosname(tmp_name, NETBIOS_NAME_SZ)) 307 goto errout; 308 if (encode_avpair_str(&mb, MsvAvNbComputerName, tmp_name) < 0) 309 goto errout; 310 311 if (secmode != SMB_SECMODE_DOMAIN) { 312 /* 313 * Workgroup mode. Set all to hostname. 314 * tmp_name = netbios hostname from above. 315 */ 316 if (encode_avpair_str(&mb, MsvAvNbDomainName, tmp_name) < 0) 317 goto errout; 318 /* 319 * Want the bare computer name here (not FQDN). 320 */ 321 if (smb_gethostname(tmp_name, MAXHOSTNAMELEN, SMB_CASE_LOWER)) 322 goto errout; 323 if (encode_avpair_str(&mb, MsvAvDnsComputerName, tmp_name) < 0) 324 goto errout; 325 if (encode_avpair_str(&mb, MsvAvDnsDomainName, tmp_name) < 0) 326 goto errout; 327 } else { 328 /* 329 * Domain mode. Use real host and domain values. 330 */ 331 332 /* NetBIOS Domain Name */ 333 if (smb_getdomainname(tmp_name, NETBIOS_NAME_SZ)) 334 goto errout; 335 if (encode_avpair_str(&mb, MsvAvNbDomainName, tmp_name) < 0) 336 goto errout; 337 338 /* DNS Computer Name */ 339 if (smb_getfqhostname(tmp_name, MAXHOSTNAMELEN)) 340 goto errout; 341 if (encode_avpair_str(&mb, MsvAvDnsComputerName, tmp_name) < 0) 342 goto errout; 343 344 /* DNS Domain Name */ 345 if (smb_getfqdomainname(tmp_name, MAXHOSTNAMELEN)) 346 goto errout; 347 if (encode_avpair_str(&mb, MsvAvDnsDomainName, tmp_name) < 0) 348 goto errout; 349 } 350 351 /* End marker */ 352 if (smb_msgbuf_encode(&mb, "ww", MsvAvEOL, 0) < 0) 353 goto errout; 354 var_end = smb_msgbuf_used(&mb); 355 var_size = (uint16_t)(var_end - var_start); 356 357 /* overwrite target offset+lengths */ 358 save_scan = mb.scan; 359 mb.scan = mb.base + TARGET_INFO_OFFSET; 360 (void) smb_msgbuf_encode(&mb, "wwl", var_size, var_size, var_start); 361 mb.scan = save_scan; 362 363 ctx->ctx_obodylen = smb_msgbuf_used(&mb); 364 smb_msgbuf_term(&mb); 365 366 be->expect_type = NTLMSSP_MSGTYPE_AUTHENTICATE; 367 368 return (0); 369 370 errout: 371 smb_msgbuf_term(&mb); 372 return (NT_STATUS_INTERNAL_ERROR); 373 } 374 375 static int 376 encode_avpair_str(smb_msgbuf_t *mb, uint16_t AvId, char *name) 377 { 378 int rc; 379 uint16_t len; 380 381 len = smb_wcequiv_strlen(name); 382 rc = smb_msgbuf_encode(mb, "wwU", AvId, len, name); 383 return (rc); 384 } 385 386 /* 387 * Handle an NTLMSSP_MSGTYPE_AUTHENTICATE message. 388 * See: [MS-NLMP] 2.2.1.3, 3.2.5.1.2 389 */ 390 static int 391 smbd_ntlmssp_authenticate(authsvc_context_t *ctx) 392 { 393 struct auth_hdr hdr; 394 smb_msgbuf_t mb; 395 smb_logon_t user_info; 396 smb_token_t *token = NULL; 397 ntlmssp_backend_t *be = ctx->ctx_backend; 398 void *lm_resp; 399 void *nt_resp; 400 char *domain; 401 char *user; 402 char *wksta; 403 void *essn_key; /* encrypted session key (optional) */ 404 int mbflags; 405 uint_t status = NT_STATUS_INTERNAL_ERROR; 406 char combined_challenge[SMBAUTH_CHAL_SZ]; 407 unsigned char kxkey[SMBAUTH_HASH_SZ]; 408 boolean_t ntlm_v1x = B_FALSE; 409 410 bzero(&user_info, sizeof (user_info)); 411 412 /* 413 * Parse the NTLMSSP_MSGTYPE_AUTHENTICATE message. 414 */ 415 if (ctx->ctx_ibodylen < sizeof (hdr)) 416 return (NT_STATUS_INVALID_PARAMETER); 417 mbflags = SMB_MSGBUF_NOTERM; 418 if (be->srv_flags & NTLMSSP_NEGOTIATE_UNICODE) 419 mbflags |= SMB_MSGBUF_UNICODE; 420 smb_msgbuf_init(&mb, ctx->ctx_ibodybuf, ctx->ctx_ibodylen, mbflags); 421 bzero(&hdr, sizeof (hdr)); 422 423 if (smb_msgbuf_decode(&mb, "12.") < 0) 424 goto errout; 425 if (decode_secbuf_bin(&mb, &hdr.h_lm_resp, &lm_resp) < 0) 426 goto errout; 427 if (decode_secbuf_bin(&mb, &hdr.h_nt_resp, &nt_resp) < 0) 428 goto errout; 429 if (decode_secbuf_str(&mb, &hdr.h_domain, &domain) < 0) 430 goto errout; 431 if (decode_secbuf_str(&mb, &hdr.h_user, &user) < 0) 432 goto errout; 433 if (decode_secbuf_str(&mb, &hdr.h_wksta, &wksta) < 0) 434 goto errout; 435 if (decode_secbuf_bin(&mb, &hdr.h_essn_key, &essn_key) < 0) 436 goto errout; 437 if (smb_msgbuf_decode(&mb, "l", &be->clnt_flags) < 0) 438 goto errout; 439 440 if (be->clnt_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) { 441 if (hdr.h_essn_key.sb_length < 16 || essn_key == NULL) 442 goto errout; 443 } 444 445 user_info.lg_level = NETR_NETWORK_LOGON; 446 user_info.lg_flags = 0; 447 448 user_info.lg_ntlm_flags = be->clnt_flags; 449 user_info.lg_username = (user) ? user : ""; 450 user_info.lg_domain = (domain) ? domain : ""; 451 user_info.lg_workstation = (wksta) ? wksta : ""; 452 453 user_info.lg_clnt_ipaddr = 454 ctx->ctx_clinfo.lci_clnt_ipaddr; 455 user_info.lg_local_port = 445; 456 457 user_info.lg_challenge_key.len = SMBAUTH_CHAL_SZ; 458 user_info.lg_challenge_key.val = (uint8_t *)be->srv_challenge; 459 460 user_info.lg_nt_password.len = hdr.h_nt_resp.sb_length; 461 user_info.lg_nt_password.val = nt_resp; 462 463 user_info.lg_lm_password.len = hdr.h_lm_resp.sb_length; 464 user_info.lg_lm_password.val = lm_resp; 465 466 user_info.lg_native_os = ctx->ctx_clinfo.lci_native_os; 467 user_info.lg_native_lm = ctx->ctx_clinfo.lci_native_lm; 468 469 /* 470 * If we're doing extended session security, the challenge 471 * this OWF was computed with is different. [MS-NLMP 3.3.1] 472 * It's: MD5(concat(ServerChallenge,ClientChallenge)) 473 * where the ClientChallenge is in the LM resp. field. 474 */ 475 if (user_info.lg_nt_password.len == SMBAUTH_LM_RESP_SZ && 476 user_info.lg_lm_password.len >= SMBAUTH_CHAL_SZ && 477 (be->clnt_flags & NTLMSSP_NEGOTIATE_NTLM2) != 0) { 478 smb_auth_ntlm2_mkchallenge(combined_challenge, 479 be->srv_challenge, lm_resp); 480 user_info.lg_challenge_key.val = 481 (uint8_t *)combined_challenge; 482 user_info.lg_lm_password.len = 0; 483 ntlm_v1x = B_TRUE; 484 } 485 486 /* 487 * This (indirectly) calls smb_auth_validate() to 488 * check that the client gave us a valid hash. 489 */ 490 token = smbd_user_auth_logon(&user_info); 491 if (token == NULL) { 492 status = NT_STATUS_ACCESS_DENIED; 493 goto errout; 494 } 495 496 if (token->tkn_ssnkey.val != NULL && 497 token->tkn_ssnkey.len == SMBAUTH_HASH_SZ) { 498 499 /* 500 * At this point, token->tkn_session_key is the 501 * "Session Base Key" [MS-NLMP] 3.2.5.1.2 502 * Compute the final session key. First need the 503 * "Key Exchange Key" [MS-NLMP] 3.4.5.1 504 */ 505 if (ntlm_v1x) { 506 smb_auth_ntlm2_kxkey(kxkey, 507 be->srv_challenge, lm_resp, 508 token->tkn_ssnkey.val); 509 } else { 510 /* KXKEY is the Session Base Key. */ 511 (void) memcpy(kxkey, token->tkn_ssnkey.val, 512 SMBAUTH_HASH_SZ); 513 } 514 515 /* 516 * If the client give us an encrypted session key, 517 * decrypt it (RC4) using the "key exchange key". 518 */ 519 if (be->clnt_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) { 520 /* RC4 args: result, key, data */ 521 (void) smb_auth_RC4(token->tkn_ssnkey.val, 522 SMBAUTH_HASH_SZ, kxkey, SMBAUTH_HASH_SZ, 523 essn_key, hdr.h_essn_key.sb_length); 524 } else { 525 /* Final key is the KXKEY */ 526 (void) memcpy(token->tkn_ssnkey.val, kxkey, 527 SMBAUTH_HASH_SZ); 528 } 529 } 530 531 ctx->ctx_token = token; 532 ctx->ctx_obodylen = 0; 533 534 smb_msgbuf_term(&mb); 535 return (0); 536 537 errout: 538 smb_msgbuf_term(&mb); 539 return (status); 540 } 541 542 static int 543 decode_secbuf_bin(smb_msgbuf_t *mb, struct sec_buf *sb, void **binp) 544 { 545 int rc; 546 547 *binp = NULL; 548 rc = smb_msgbuf_decode( 549 mb, "wwl", 550 &sb->sb_length, 551 &sb->sb_maxlen, 552 &sb->sb_offset); 553 if (rc < 0) 554 return (rc); 555 556 if (sb->sb_offset > mb->max) 557 return (SMB_MSGBUF_UNDERFLOW); 558 if (sb->sb_length > (mb->max - sb->sb_offset)) 559 return (SMB_MSGBUF_UNDERFLOW); 560 if (sb->sb_length == 0) 561 return (rc); 562 563 *binp = mb->base + sb->sb_offset; 564 return (0); 565 } 566 567 static int 568 decode_secbuf_str(smb_msgbuf_t *mb, struct sec_buf *sb, char **cpp) 569 { 570 uint8_t *save_scan; 571 int rc; 572 573 *cpp = NULL; 574 rc = smb_msgbuf_decode( 575 mb, "wwl", 576 &sb->sb_length, 577 &sb->sb_maxlen, 578 &sb->sb_offset); 579 if (rc < 0) 580 return (rc); 581 582 if (sb->sb_offset > mb->max) 583 return (SMB_MSGBUF_UNDERFLOW); 584 if (sb->sb_length > (mb->max - sb->sb_offset)) 585 return (SMB_MSGBUF_UNDERFLOW); 586 if (sb->sb_length == 0) 587 return (rc); 588 589 save_scan = mb->scan; 590 mb->scan = mb->base + sb->sb_offset; 591 rc = smb_msgbuf_decode(mb, "#u", (int)sb->sb_length, cpp); 592 mb->scan = save_scan; 593 594 return (rc); 595 } 596