1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 24 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 25 */ 26 27 /* 28 * NT Lan Manager Security Support Provider (NTLMSSP) 29 * 30 * Based on information from the "Davenport NTLM" page: 31 * http://davenport.sourceforge.net/ntlm.html 32 */ 33 34 35 #include <errno.h> 36 #include <stdio.h> 37 #include <stddef.h> 38 #include <stdlib.h> 39 #include <unistd.h> 40 #include <strings.h> 41 #include <netdb.h> 42 #include <libintl.h> 43 #include <xti.h> 44 #include <assert.h> 45 46 #include <sys/types.h> 47 #include <sys/time.h> 48 #include <sys/byteorder.h> 49 #include <sys/socket.h> 50 #include <sys/fcntl.h> 51 52 #include <netinet/in.h> 53 #include <netinet/tcp.h> 54 #include <arpa/inet.h> 55 56 #include <netsmb/smb.h> 57 #include <netsmb/smb_lib.h> 58 #include <netsmb/mchain.h> 59 60 #include "private.h" 61 #include "charsets.h" 62 #include "spnego.h" 63 #include "derparse.h" 64 #include "ssp.h" 65 #include "ntlm.h" 66 #include "ntlmssp.h" 67 68 typedef struct ntlmssp_state { 69 uint32_t ss_flags; 70 char *ss_target_name; 71 struct mbuf *ss_target_info; 72 } ntlmssp_state_t; 73 74 /* 75 * So called "security buffer". 76 * A lot like an RPC string. 77 */ 78 struct sec_buf { 79 uint16_t sb_length; 80 uint16_t sb_maxlen; 81 uint32_t sb_offset; 82 }; 83 #define ID_SZ 8 84 static const char ntlmssp_id[ID_SZ] = "NTLMSSP"; 85 86 /* 87 * Get a "security buffer" (header part) 88 */ 89 static int 90 md_get_sb_hdr(struct mbdata *mbp, struct sec_buf *sb) 91 { 92 int err; 93 94 (void) md_get_uint16le(mbp, &sb->sb_length); 95 (void) md_get_uint16le(mbp, &sb->sb_maxlen); 96 err = md_get_uint32le(mbp, &sb->sb_offset); 97 98 return (err); 99 } 100 101 /* 102 * Get a "security buffer" (data part), where 103 * the data is delivered as an mbuf. 104 */ 105 static int 106 md_get_sb_data(struct mbdata *mbp, struct sec_buf *sb, struct mbuf **mp) 107 { 108 struct mbdata tmp_mb; 109 int err; 110 111 /* 112 * Setup tmp_mb to point to the start of the header. 113 * This is a dup ref - do NOT free it. 114 */ 115 mb_initm(&tmp_mb, mbp->mb_top); 116 117 /* Skip data up to the offset. */ 118 err = md_get_mem(&tmp_mb, NULL, sb->sb_offset, MB_MSYSTEM); 119 if (err) 120 return (err); 121 122 /* Get the data (as an mbuf). */ 123 err = md_get_mbuf(&tmp_mb, sb->sb_maxlen, mp); 124 125 return (err); 126 } 127 128 /* 129 * Put a "security buffer" (header part) 130 */ 131 static int 132 mb_put_sb_hdr(struct mbdata *mbp, struct sec_buf *sb) 133 { 134 int err; 135 136 (void) mb_put_uint16le(mbp, sb->sb_length); 137 (void) mb_put_uint16le(mbp, sb->sb_maxlen); 138 err = mb_put_uint32le(mbp, sb->sb_offset); 139 140 return (err); 141 } 142 143 /* 144 * Put a "security buffer" (data part), where 145 * the data is an mbuf. Note: consumes m. 146 */ 147 static int 148 mb_put_sb_data(struct mbdata *mbp, struct sec_buf *sb, struct mbuf *m) 149 { 150 int cnt0, err; 151 152 sb->sb_offset = cnt0 = mbp->mb_count; 153 err = mb_put_mbuf(mbp, m); 154 sb->sb_maxlen = sb->sb_length = mbp->mb_count - cnt0; 155 156 return (err); 157 } 158 159 /* 160 * Put a "security buffer" (data part), where 161 * the data is a string (OEM or unicode). 162 * 163 * The string is NOT null terminated. 164 */ 165 static int 166 mb_put_sb_string(struct mbdata *mbp, struct sec_buf *sb, 167 const char *s, int unicode) 168 { 169 int err, trim; 170 struct mbdata tmp_mb; 171 172 /* 173 * Put the string into a temp. mbuf, 174 * then chop off the null terminator 175 * before appending to caller's mbp. 176 */ 177 err = mb_init(&tmp_mb); 178 if (err) 179 return (err); 180 err = mb_put_string(&tmp_mb, s, unicode); 181 if (err) 182 return (err); 183 184 trim = (unicode) ? 2 : 1; 185 if (tmp_mb.mb_cur->m_len < trim) 186 return (EFAULT); 187 tmp_mb.mb_cur->m_len -= trim; 188 189 err = mb_put_sb_data(mbp, sb, tmp_mb.mb_top); 190 /* 191 * Note: tmp_mb.mb_top is consumed, 192 * so do NOT free it (no mb_done) 193 */ 194 return (err); 195 } 196 197 /* 198 * Build a Type 1 message 199 * 200 * This message has a header section containing offsets to 201 * data later in the message. We use the common trick of 202 * building it in two parts and then concatenatening. 203 */ 204 int 205 ntlmssp_put_type1(struct ssp_ctx *sp, struct mbdata *out_mb) 206 { 207 struct type1hdr { 208 char h_id[ID_SZ]; 209 uint32_t h_type; 210 uint32_t h_flags; 211 struct sec_buf h_cldom; 212 struct sec_buf h_wksta; 213 } hdr; 214 struct mbdata mb2; /* 2nd part */ 215 int err; 216 struct smb_ctx *ctx = sp->smb_ctx; 217 ntlmssp_state_t *ssp_st = sp->sp_private; 218 char *ucdom = NULL; 219 char *ucwks = NULL; 220 221 if ((err = mb_init(&mb2)) != 0) 222 return (err); 223 mb2.mb_count = sizeof (hdr); 224 225 /* 226 * Initialize the negotiation flags, and 227 * save what we sent. For reference: 228 * [MS-NLMP] spec. (also ntlmssp.h) 229 */ 230 ssp_st->ss_flags = 231 NTLMSSP_REQUEST_TARGET | 232 NTLMSSP_NEGOTIATE_NTLM | 233 NTLMSSP_NEGOTIATE_TARGET_INFO | 234 NTLMSSP_NEGOTIATE_128 | 235 NTLMSSP_NEGOTIATE_56; 236 237 if (ctx->ct_hflags2 & SMB_FLAGS2_UNICODE) 238 ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_UNICODE; 239 else 240 ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_OEM; 241 242 if (ctx->ct_vcflags & SMBV_WILL_SIGN) { 243 ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; 244 ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE; 245 } 246 247 if (ctx->ct_authflags & SMB_AT_NTLM2) 248 ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY; 249 if (ctx->ct_authflags & SMB_AT_NTLM1) 250 ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_LM_KEY; 251 252 bcopy(ntlmssp_id, &hdr.h_id, ID_SZ); 253 hdr.h_type = 1; /* Type 1 */ 254 hdr.h_flags = ssp_st->ss_flags; 255 256 /* 257 * Put the client domain, client name strings. 258 * These are always in OEM format, upper-case. 259 */ 260 ucdom = utf8_str_toupper(ctx->ct_domain); 261 ucwks = utf8_str_toupper(ctx->ct_locname); 262 if (ucdom == NULL || ucwks == NULL) { 263 err = ENOMEM; 264 goto out; 265 } 266 err = mb_put_sb_string(&mb2, &hdr.h_cldom, ucdom, 0); 267 if (err) 268 goto out; 269 err = mb_put_sb_string(&mb2, &hdr.h_wksta, ucwks, 0); 270 if (err) 271 goto out; 272 273 /* 274 * Marshal the header (in LE order) 275 * then concatenate the 2nd part. 276 */ 277 (void) mb_put_mem(out_mb, &hdr.h_id, ID_SZ, MB_MSYSTEM); 278 (void) mb_put_uint32le(out_mb, hdr.h_type); 279 (void) mb_put_uint32le(out_mb, hdr.h_flags); 280 (void) mb_put_sb_hdr(out_mb, &hdr.h_cldom); 281 (void) mb_put_sb_hdr(out_mb, &hdr.h_wksta); 282 283 err = mb_put_mbuf(out_mb, mb2.mb_top); 284 285 out: 286 free(ucdom); 287 free(ucwks); 288 289 return (err); 290 } 291 292 /* 293 * Parse a Type 2 message 294 */ 295 int 296 ntlmssp_get_type2(struct ssp_ctx *sp, struct mbdata *in_mb) 297 { 298 struct type2hdr { 299 char h_id[ID_SZ]; 300 uint32_t h_type; 301 struct sec_buf h_target_name; 302 uint32_t h_flags; 303 uint8_t h_challenge[8]; 304 uint32_t h_context[2]; /* optional */ 305 struct sec_buf h_target_info; /* optional */ 306 } hdr; 307 struct mbdata top_mb, tmp_mb; 308 struct mbuf *m; 309 int err, uc; 310 int min_hdr_sz = offsetof(struct type2hdr, h_context); 311 struct smb_ctx *ctx = sp->smb_ctx; 312 ntlmssp_state_t *ssp_st = sp->sp_private; 313 char *buf = NULL; 314 315 if (m_totlen(in_mb->mb_top) < min_hdr_sz) { 316 err = EBADRPC; 317 goto out; 318 } 319 320 /* 321 * Save the mbdata pointers before we consume anything. 322 * Careful to NOT free this (would be dup. free) 323 * We use this below to find data based on offsets 324 * from the start of the header. 325 */ 326 top_mb = *in_mb; 327 328 /* Parse the fixed size header stuff. */ 329 bzero(&hdr, sizeof (hdr)); 330 (void) md_get_mem(in_mb, &hdr.h_id, ID_SZ, MB_MSYSTEM); 331 (void) md_get_uint32le(in_mb, &hdr.h_type); 332 if (hdr.h_type != 2) { 333 err = EPROTO; 334 goto out; 335 } 336 (void) md_get_sb_hdr(in_mb, &hdr.h_target_name); 337 (void) md_get_uint32le(in_mb, &hdr.h_flags); 338 (void) md_get_mem(in_mb, &hdr.h_challenge, NTLM_CHAL_SZ, MB_MSYSTEM); 339 340 /* 341 * Save flags, challenge for later. 342 */ 343 ssp_st->ss_flags = hdr.h_flags; 344 uc = hdr.h_flags & NTLMSSP_NEGOTIATE_UNICODE; 345 bcopy(&hdr.h_challenge, ctx->ct_ntlm_chal, NTLM_CHAL_SZ); 346 347 /* 348 * Now find out if the optional parts are there. 349 */ 350 if ((m_totlen(top_mb.mb_top) > sizeof (hdr)) && 351 (hdr.h_target_name.sb_offset >= sizeof (hdr))) { 352 (void) md_get_uint32le(in_mb, &hdr.h_context[0]); 353 (void) md_get_uint32le(in_mb, &hdr.h_context[1]); 354 (void) md_get_sb_hdr(in_mb, &hdr.h_target_info); 355 } 356 357 /* 358 * Get the target name string. First get a copy of 359 * the data from the offset/length indicated in the 360 * security buffer header; then parse the string. 361 */ 362 err = md_get_sb_data(&top_mb, &hdr.h_target_name, &m); 363 if (err) 364 goto out; 365 mb_initm(&tmp_mb, m); 366 err = md_get_string(&tmp_mb, &ssp_st->ss_target_name, uc); 367 mb_done(&tmp_mb); 368 369 /* 370 * Get the target info blob, if present. 371 */ 372 if (hdr.h_target_info.sb_offset >= sizeof (hdr)) { 373 err = md_get_sb_data(&top_mb, &hdr.h_target_info, 374 &ssp_st->ss_target_info); 375 } 376 377 out: 378 if (buf != NULL) 379 free(buf); 380 381 return (err); 382 } 383 384 /* 385 * Build a Type 3 message 386 * 387 * This message has a header section containing offsets to 388 * data later in the message. We use the common trick of 389 * building it in two parts and then concatenatening. 390 */ 391 int 392 ntlmssp_put_type3(struct ssp_ctx *sp, struct mbdata *out_mb) 393 { 394 struct type3hdr { 395 char h_id[ID_SZ]; 396 uint32_t h_type; 397 struct sec_buf h_lm_resp; 398 struct sec_buf h_nt_resp; 399 struct sec_buf h_domain; 400 struct sec_buf h_user; 401 struct sec_buf h_wksta; 402 struct sec_buf h_ssn_key; 403 uint32_t h_flags; 404 } hdr; 405 struct mbdata lm_mbc; /* LM response */ 406 struct mbdata nt_mbc; /* NT response */ 407 struct mbdata ti_mbc; /* target info */ 408 struct mbdata mb2; /* payload */ 409 int err, uc; 410 struct smb_ctx *ctx = sp->smb_ctx; 411 ntlmssp_state_t *ssp_st = sp->sp_private; 412 413 bzero(&hdr, sizeof (hdr)); 414 bzero(&lm_mbc, sizeof (lm_mbc)); 415 bzero(&nt_mbc, sizeof (nt_mbc)); 416 bzero(&ti_mbc, sizeof (ti_mbc)); 417 bzero(&mb2, sizeof (mb2)); 418 419 /* 420 * Fill in the NTLMSSP header, etc. 421 */ 422 if ((err = mb_init(&mb2)) != 0) 423 goto out; 424 mb2.mb_count = sizeof (hdr); 425 uc = ssp_st->ss_flags & NTLMSSP_NEGOTIATE_UNICODE; 426 427 bcopy(ntlmssp_id, &hdr.h_id, ID_SZ); 428 hdr.h_type = 3; /* Type 3 */ 429 hdr.h_flags = ssp_st->ss_flags; 430 431 /* 432 * Put the LMv2,NTLMv2 responses, or 433 * possibly LM, NTLM (v1) responses. 434 */ 435 if (ctx->ct_authflags & SMB_AT_NTLM2) { 436 /* Build the NTLMv2 "target info" blob. */ 437 err = ntlm_build_target_info(ctx, 438 ssp_st->ss_target_info, &ti_mbc); 439 if (err) 440 goto out; 441 err = ntlm_put_v2_responses(ctx, &ti_mbc, 442 &lm_mbc, &nt_mbc); 443 } else { 444 err = ntlm_put_v1_responses(ctx, 445 &lm_mbc, &nt_mbc); 446 } 447 if (err) 448 goto out; 449 450 err = mb_put_sb_data(&mb2, &hdr.h_lm_resp, lm_mbc.mb_top); 451 lm_mbc.mb_top = NULL; /* consumed */ 452 if (err) 453 goto out; 454 err = mb_put_sb_data(&mb2, &hdr.h_nt_resp, nt_mbc.mb_top); 455 nt_mbc.mb_top = NULL; /* consumed */ 456 if (err) 457 goto out; 458 459 /* 460 * Put the "target" (domain), user, workstation 461 */ 462 err = mb_put_sb_string(&mb2, &hdr.h_domain, ctx->ct_domain, uc); 463 if (err) 464 goto out; 465 err = mb_put_sb_string(&mb2, &hdr.h_user, ctx->ct_user, uc); 466 if (err) 467 goto out; 468 err = mb_put_sb_string(&mb2, &hdr.h_wksta, ctx->ct_locname, uc); 469 if (err) 470 goto out; 471 472 /* 473 * Put the "Random Session Key". We don't set 474 * NTLMSSP_NEGOTIATE_KEY_EXCH, so it's empty. 475 * (In-line mb_put_sb_data here.) 476 */ 477 hdr.h_ssn_key.sb_maxlen = hdr.h_ssn_key.sb_length = 0; 478 hdr.h_ssn_key.sb_offset = mb2.mb_count; 479 480 /* 481 * Marshal the header (in LE order) 482 * then concatenate the 2nd part. 483 */ 484 (void) mb_put_mem(out_mb, &hdr.h_id, ID_SZ, MB_MSYSTEM); 485 (void) mb_put_uint32le(out_mb, hdr.h_type); 486 487 (void) mb_put_sb_hdr(out_mb, &hdr.h_lm_resp); 488 (void) mb_put_sb_hdr(out_mb, &hdr.h_nt_resp); 489 490 (void) mb_put_sb_hdr(out_mb, &hdr.h_domain); 491 (void) mb_put_sb_hdr(out_mb, &hdr.h_user); 492 (void) mb_put_sb_hdr(out_mb, &hdr.h_wksta); 493 494 (void) mb_put_sb_hdr(out_mb, &hdr.h_ssn_key); 495 (void) mb_put_uint32le(out_mb, hdr.h_flags); 496 497 err = mb_put_mbuf(out_mb, mb2.mb_top); 498 mb2.mb_top = NULL; /* consumed */ 499 500 out: 501 mb_done(&mb2); 502 mb_done(&lm_mbc); 503 mb_done(&nt_mbc); 504 mb_done(&ti_mbc); 505 506 return (err); 507 } 508 509 /* 510 * ntlmssp_final 511 * 512 * Called after successful authentication. 513 * Setup the MAC key for signing. 514 */ 515 int 516 ntlmssp_final(struct ssp_ctx *sp) 517 { 518 struct smb_ctx *ctx = sp->smb_ctx; 519 int err = 0; 520 521 /* 522 * MAC_key is just the session key, but 523 * Only on the first successful auth. 524 */ 525 if ((ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) && 526 (ctx->ct_mackey == NULL)) { 527 ctx->ct_mackeylen = NTLM_HASH_SZ; 528 ctx->ct_mackey = malloc(ctx->ct_mackeylen); 529 if (ctx->ct_mackey == NULL) { 530 ctx->ct_mackeylen = 0; 531 err = ENOMEM; 532 goto out; 533 } 534 memcpy(ctx->ct_mackey, ctx->ct_ssn_key, NTLM_HASH_SZ); 535 /* 536 * Apparently, the server used seq. no. zero 537 * for our previous message, so next is two. 538 */ 539 ctx->ct_mac_seqno = 2; 540 } 541 542 out: 543 return (err); 544 } 545 546 /* 547 * ntlmssp_next_token 548 * 549 * See ssp.c: ssp_ctx_next_token 550 */ 551 int 552 ntlmssp_next_token(struct ssp_ctx *sp, struct mbdata *in_mb, 553 struct mbdata *out_mb) 554 { 555 int err; 556 557 if (out_mb == NULL) { 558 /* final call on successful auth. */ 559 err = ntlmssp_final(sp); 560 goto out; 561 } 562 563 /* Will build an ouptut token. */ 564 err = mb_init(out_mb); 565 if (err) 566 goto out; 567 568 /* 569 * When called with in_mb == NULL, it means 570 * this is the first call for this session, 571 * so put a Type 1 (initialize) token. 572 */ 573 if (in_mb == NULL) { 574 err = ntlmssp_put_type1(sp, out_mb); 575 goto out; 576 } 577 578 /* 579 * This is not the first call, so 580 * parse the response token we received. 581 * It should be a Type 2 (challenge). 582 * Then put a Type 3 (authenticate) 583 */ 584 err = ntlmssp_get_type2(sp, in_mb); 585 if (err) 586 goto out; 587 588 err = ntlmssp_put_type3(sp, out_mb); 589 590 out: 591 if (err) 592 DPRINT("ret: %d", err); 593 return (err); 594 } 595 596 /* 597 * ntlmssp_ctx_destroy 598 * 599 * Destroy mechanism-specific data. 600 */ 601 void 602 ntlmssp_destroy(struct ssp_ctx *sp) 603 { 604 ntlmssp_state_t *ssp_st; 605 606 ssp_st = sp->sp_private; 607 if (ssp_st != NULL) { 608 sp->sp_private = NULL; 609 free(ssp_st->ss_target_name); 610 m_freem(ssp_st->ss_target_info); 611 free(ssp_st); 612 } 613 } 614 615 /* 616 * ntlmssp_init_clnt 617 * 618 * Initialize a new NTLMSSP client context. 619 */ 620 int 621 ntlmssp_init_client(struct ssp_ctx *sp) 622 { 623 ntlmssp_state_t *ssp_st; 624 625 if ((sp->smb_ctx->ct_authflags & 626 (SMB_AT_NTLM2 | SMB_AT_NTLM1)) == 0) { 627 DPRINT("No NTLM authflags"); 628 return (ENOTSUP); 629 } 630 631 ssp_st = calloc(1, sizeof (*ssp_st)); 632 if (ssp_st == NULL) 633 return (ENOMEM); 634 635 sp->sp_nexttok = ntlmssp_next_token; 636 sp->sp_destroy = ntlmssp_destroy; 637 sp->sp_private = ssp_st; 638 639 return (0); 640 } 641