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