1/* NTLM SASL plugin 2 * Ken Murchison 3 * $Id: ntlm.c,v 1.6 2006/01/24 20:37:26 snsimon Exp $ 4 * 5 * References: 6 * http://www.innovation.ch/java/ntlm.html 7 * http://www.opengroup.org/comsource/techref2/NCH1222X.HTM 8 * http://www.ubiqx.org/cifs/rfc-draft/draft-leach-cifs-v1-spec-02.html 9 */ 10/* 11 * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 20 * 2. Redistributions in binary form must reproduce the above copyright 21 * notice, this list of conditions and the following disclaimer in 22 * the documentation and/or other materials provided with the 23 * distribution. 24 * 25 * 3. The name "Carnegie Mellon University" must not be used to 26 * endorse or promote products derived from this software without 27 * prior written permission. For permission or any other legal 28 * details, please contact 29 * Office of Technology Transfer 30 * Carnegie Mellon University 31 * 5000 Forbes Avenue 32 * Pittsburgh, PA 15213-3890 33 * (412) 268-4387, fax: (412) 268-7395 34 * tech-transfer@andrew.cmu.edu 35 * 36 * 4. Redistributions of any form whatsoever must retain the following 37 * acknowledgment: 38 * "This product includes software developed by Computing Services 39 * at Carnegie Mellon University (http://www.cmu.edu/computing/)." 40 * 41 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO 42 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 43 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE 44 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 45 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 46 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 47 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 48 */ 49 50#include <config.h> 51#include <stdio.h> 52#include <stdlib.h> 53#include <ctype.h> 54#include <errno.h> 55#include <limits.h> 56 57#ifdef WIN32 58# include <process.h> /* for getpid */ 59 typedef int pid_t; 60#else 61# include <unistd.h> 62# include <sys/types.h> 63# include <sys/socket.h> 64# include <sys/utsname.h> 65# include <netdb.h> 66 67#ifndef SYS_NMLN 68 struct utsname dummy; 69# define SYS_NMLN sizeof(dummy.sysname) 70#endif 71 72# define closesocket(sock) close(sock) 73 typedef int SOCKET; 74#endif /* WIN32 */ 75 76#include <openssl/md4.h> 77#include <openssl/md5.h> 78#include <openssl/hmac.h> 79#include <openssl/des.h> 80#include <openssl/opensslv.h> 81#if (OPENSSL_VERSION_NUMBER >= 0x0090700f) && \ 82 !defined(OPENSSL_ENABLE_OLD_DES_SUPPORT) 83# define des_cblock DES_cblock 84# define des_key_schedule DES_key_schedule 85# define des_set_odd_parity(k) \ 86 DES_set_odd_parity((k)) 87# define des_set_key(k,ks) \ 88 DES_set_key((k),&(ks)) 89# define des_key_sched(k,ks) \ 90 DES_key_sched((k),&(ks)) 91# define des_ecb_encrypt(i,o,k,e) \ 92 DES_ecb_encrypt((i),(o),&(k),(e)) 93#endif /* OpenSSL 0.9.7+ w/o old DES support */ 94 95#include <sasl.h> 96#define MD5_H /* suppress internal MD5 */ 97#include <saslplug.h> 98 99#include "plugin_common.h" 100 101/***************************** Common Section *****************************/ 102 103//static const char plugin_id[] = "$Id: ntlm.c,v 1.6 2006/01/24 20:37:26 snsimon Exp $"; 104 105#ifdef WIN32 106static ssize_t writev (SOCKET fd, const struct iovec *iov, size_t iovcnt); 107 108ssize_t writev (SOCKET fd, const struct iovec *iov, size_t iovcnt) 109{ 110 ssize_t nwritten; /* amount written */ 111 ssize_t nbytes; 112 size_t i; 113 114 nbytes = 0; 115 116 for (i = 0; i < iovcnt; i++) { 117 if ((nwritten = send (fd, iov[i].iov_base, iov[i].iov_len, 0)) == SOCKET_ERROR) { 118/* Unless socket is nonblocking, we should always write everything */ 119 return (-1); 120 } 121 122 nbytes += nwritten; 123 124 if (nwritten < iov[i].iov_len) { 125 break; 126 } 127 } 128 return (nbytes); 129} 130#endif /* WIN32 */ 131 132#ifndef UINT16_MAX 133#define UINT16_MAX 65535U 134#endif 135 136#if UINT_MAX == UINT16_MAX 137typedef unsigned int uint16; 138#elif USHRT_MAX == UINT16_MAX 139typedef unsigned short uint16; 140#else 141#error dont know what to use for uint16 142#endif 143 144#ifndef UINT32_MAX 145#define UINT32_MAX 4294967295U 146#endif 147 148#if UINT_MAX == UINT32_MAX 149typedef unsigned int uint32; 150#elif ULONG_MAX == UINT32_MAX 151typedef unsigned long uint32; 152#elif USHRT_MAX == UINT32_MAX 153typedef unsigned short uint32; 154#else 155#error dont know what to use for uint32 156#endif 157 158#define NTLM_SIGNATURE "NTLMSSP" 159 160enum { 161 NTLM_TYPE_REQUEST = 1, 162 NTLM_TYPE_CHALLENGE = 2, 163 NTLM_TYPE_RESPONSE = 3 164}; 165 166enum { 167 NTLM_USE_UNICODE = 0x00001, 168 NTLM_USE_ASCII = 0x00002, 169 NTLM_ASK_TARGET = 0x00004, 170 NTLM_AUTH_NTLM = 0x00200, 171 NTLM_ALWAYS_SIGN = 0x08000, 172 NTLM_TARGET_IS_DOMAIN = 0x10000, 173 NTLM_TARGET_IS_SERVER = 0x20000, 174 NTLM_FLAGS_MASK = 0x0ffff 175}; 176 177enum { 178 NTLM_NONCE_LENGTH = 8, 179 NTLM_HASH_LENGTH = 21, 180 NTLM_RESP_LENGTH = 24, 181 NTLM_SESSKEY_LENGTH = 16, 182}; 183 184enum { 185 NTLM_SIG_OFFSET = 0, 186 NTLM_TYPE_OFFSET = 8, 187 188 NTLM_TYPE1_FLAGS_OFFSET = 12, 189 NTLM_TYPE1_DOMAIN_OFFSET = 16, 190 NTLM_TYPE1_WORKSTN_OFFSET = 24, 191 NTLM_TYPE1_DATA_OFFSET = 32, 192 NTLM_TYPE1_MINSIZE = 16, 193 194 NTLM_TYPE2_TARGET_OFFSET = 12, 195 NTLM_TYPE2_FLAGS_OFFSET = 20, 196 NTLM_TYPE2_CHALLENGE_OFFSET = 24, 197 NTLM_TYPE2_CONTEXT_OFFSET = 32, 198 NTLM_TYPE2_TARGETINFO_OFFSET= 40, 199 NTLM_TYPE2_DATA_OFFSET = 48, 200 NTLM_TYPE2_MINSIZE = 32, 201 202 NTLM_TYPE3_LMRESP_OFFSET = 12, 203 NTLM_TYPE3_NTRESP_OFFSET = 20, 204 NTLM_TYPE3_DOMAIN_OFFSET = 28, 205 NTLM_TYPE3_USER_OFFSET = 36, 206 NTLM_TYPE3_WORKSTN_OFFSET = 44, 207 NTLM_TYPE3_SESSIONKEY_OFFSET= 52, 208 NTLM_TYPE3_FLAGS_OFFSET = 60, 209 NTLM_TYPE3_DATA_OFFSET = 64, 210 NTLM_TYPE3_MINSIZE = 52, 211 212 NTLM_BUFFER_LEN_OFFSET = 0, 213 NTLM_BUFFER_MAXLEN_OFFSET = 2, 214 NTLM_BUFFER_OFFSET_OFFSET = 4, 215 NTLM_BUFFER_SIZE = 8 216}; 217 218/* return the length of a string (even if it is NULL) */ 219#define xstrlen(s) (s ? strlen(s) : 0) 220 221/* machine-independent routines to convert to/from Intel byte-order */ 222#define htois(is, hs) \ 223 (is)[0] = hs & 0xff; \ 224 (is)[1] = hs >> 8 225 226#define itohs(is) \ 227 ((is)[0] | ((is)[1] << 8)) 228 229#define htoil(il, hl) \ 230 (il)[0] = hl & 0xff; \ 231 (il)[1] = (hl >> 8) & 0xff; \ 232 (il)[2] = (hl >> 16) & 0xff; \ 233 (il)[3] = hl >> 24 234 235#define itohl(il) \ 236 ((il)[0] | ((il)[1] << 8) | ((il)[2] << 16) | ((il)[3] << 24)) 237 238/* convert string to all upper case */ 239static const char *ucase(const char *str, size_t len) 240{ 241 char *cp = (char *) str; 242 243 if (!len) len = xstrlen(str); 244 245 while (len && cp && *cp) { 246 *cp = toupper((int) *cp); 247 cp++; 248 len--; 249 } 250 251 return (str); 252} 253 254/* copy src to dst as unicode (in Intel byte-order) */ 255static void to_unicode(u_char *dst, const char *src, int len) 256{ 257 for (; len; len--) { 258 *dst++ = *src++; 259 *dst++ = 0; 260 } 261} 262 263/* copy unicode src (in Intel byte-order) to dst */ 264static void from_unicode(char *dst, u_char *src, int len) 265{ 266 for (; len; len--) { 267 *dst++ = *src & 0x7f; 268 src += 2; 269 } 270} 271 272/* load a string into an NTLM buffer */ 273static void load_buffer(u_char *buf, const u_char *str, uint16 len, 274 int unicode, u_char *base, uint32 *offset) 275{ 276 if (len) { 277 if (unicode) { 278 to_unicode(base + *offset, str, len); 279 len *= 2; 280 } 281 else { 282 memcpy(base + *offset, str, len); 283 } 284 } 285 286 htois(buf + NTLM_BUFFER_LEN_OFFSET, len); 287 htois(buf + NTLM_BUFFER_MAXLEN_OFFSET, len); 288 htoil(buf + NTLM_BUFFER_OFFSET_OFFSET, *offset); 289 *offset += len; 290} 291 292/* unload a string from an NTLM buffer */ 293static int unload_buffer(const sasl_utils_t *utils, const u_char *buf, 294 u_char **str, unsigned *outlen, 295 int unicode, const u_char *base, unsigned msglen) 296{ 297 uint16 len = itohs(buf + NTLM_BUFFER_LEN_OFFSET); 298 299 if (len) { 300 uint32 offset; 301 302 *str = utils->malloc(len + 1); /* add 1 for NUL */ 303 if (*str == NULL) { 304 MEMERROR(utils); 305 return SASL_NOMEM; 306 } 307 308 offset = itohl(buf + NTLM_BUFFER_OFFSET_OFFSET); 309 310 /* sanity check */ 311 if (offset > msglen || len > (msglen - offset)) return SASL_BADPROT; 312 313 if (unicode) { 314 len /= 2; 315 from_unicode((char *) *str, (u_char *) base + offset, len); 316 } 317 else 318 memcpy(*str, base + offset, len); 319 320 (*str)[len] = '\0'; /* add NUL */ 321 } 322 else { 323 *str = NULL; 324 } 325 326 if (outlen) *outlen = len; 327 328 return SASL_OK; 329} 330 331/* 332 * NTLM encryption/authentication routines per section 2.10 of 333 * draft-leach-cifs-v1-spec-02 334 */ 335static void E(unsigned char *out, unsigned char *K, unsigned Klen, 336 unsigned char *D, unsigned Dlen) 337 338{ 339 unsigned k, d; 340 des_cblock K64; 341 des_key_schedule ks; 342 unsigned char *Dp; 343#define KEY_SIZE 7 344#define BLOCK_SIZE 8 345 346 for (k = 0; k < Klen; k += KEY_SIZE, K += KEY_SIZE) { 347 /* convert 56-bit key to 64-bit */ 348 K64[0] = K[0]; 349 K64[1] = ((K[0] << 7) & 0xFF) | (K[1] >> 1); 350 K64[2] = ((K[1] << 6) & 0xFF) | (K[2] >> 2); 351 K64[3] = ((K[2] << 5) & 0xFF) | (K[3] >> 3); 352 K64[4] = ((K[3] << 4) & 0xFF) | (K[4] >> 4); 353 K64[5] = ((K[4] << 3) & 0xFF) | (K[5] >> 5); 354 K64[6] = ((K[5] << 2) & 0xFF) | (K[6] >> 6); 355 K64[7] = (K[6] << 1) & 0xFF; 356 357 des_set_odd_parity(&K64); /* XXX is this necessary? */ 358 des_set_key(&K64, ks); 359 360 for (d = 0, Dp = D; d < Dlen; 361 d += BLOCK_SIZE, Dp += BLOCK_SIZE, out += BLOCK_SIZE) { 362 des_ecb_encrypt((void *) Dp, (void *) out, ks, DES_ENCRYPT); 363 } 364 } 365} 366 367static unsigned char *P16_lm(unsigned char *P16, sasl_secret_t *passwd, 368 const sasl_utils_t *utils __attribute__((unused)), 369 char **buf __attribute__((unused)), 370 unsigned *buflen __attribute__((unused)), 371 int *result) 372{ 373 char P14[14]; 374 unsigned char S8[] = { 0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 }; 375 376 strncpy(P14, (char *)passwd->data, sizeof(P14)); 377 ucase(P14, sizeof(P14)); 378 379 E(P16, P14, sizeof(P14), S8, sizeof(S8)); 380 *result = SASL_OK; 381 return P16; 382} 383 384static unsigned char *P16_nt(unsigned char *P16, sasl_secret_t *passwd, 385 const sasl_utils_t *utils, 386 char **buf, unsigned *buflen, int *result) 387{ 388 if (_plug_buf_alloc(utils, buf, buflen, 2 * passwd->len) != SASL_OK) { 389 SETERROR(utils, "cannot allocate P16_nt unicode buffer"); 390 *result = SASL_NOMEM; 391 } 392 else { 393 to_unicode(*buf, passwd->data, passwd->len); 394 MD4(*buf, 2 * passwd->len, P16); 395 *result = SASL_OK; 396 } 397 return P16; 398} 399 400static unsigned char *P21(unsigned char *P21, sasl_secret_t *passwd, 401 unsigned char * (*P16)(unsigned char *, 402 sasl_secret_t *, 403 const sasl_utils_t *, 404 char **, unsigned *, int *), 405 const sasl_utils_t *utils, 406 char **buf, unsigned *buflen, int *result) 407{ 408 memset(P16(P21, passwd, utils, buf, buflen, result) + 16, 0, 5); 409 return P21; 410} 411 412static unsigned char *P24(unsigned char *P24, unsigned char *P21, 413 unsigned char *C8) 414 415{ 416 E(P24, P21, NTLM_HASH_LENGTH, C8, NTLM_NONCE_LENGTH); 417 return P24; 418} 419 420static unsigned char *V2(unsigned char *V2, sasl_secret_t *passwd, 421 const char *authid, const char *target, 422 const unsigned char *challenge, 423 const unsigned char *blob, unsigned bloblen, 424 const sasl_utils_t *utils, 425 char **buf, unsigned *buflen, int *result) 426{ 427 HMAC_CTX ctx; 428 unsigned char hash[EVP_MAX_MD_SIZE]; 429 char *upper; 430 int len; 431 432 /* Allocate enough space for the unicode target */ 433 len = (int) (strlen(authid) + xstrlen(target)); 434 if (_plug_buf_alloc(utils, buf, buflen, 2 * len + 1) != SASL_OK) { 435 SETERROR(utils, "cannot allocate NTLMv2 hash"); 436 *result = SASL_NOMEM; 437 } 438 else { 439 /* NTLMv2hash = HMAC-MD5(NTLMhash, unicode(ucase(authid + domain))) */ 440 P16_nt(hash, passwd, utils, buf, buflen, result); 441 442 /* Use the tail end of the buffer for ucase() conversion */ 443 upper = *buf + len; 444 strcpy(upper, authid); 445 if (target) strcat(upper, target); 446 ucase(upper, len); 447 to_unicode(*buf, upper, len); 448 449 HMAC(EVP_md5(), hash, MD4_DIGEST_LENGTH, *buf, 2 * len, hash, &len); 450 451 /* V2 = HMAC-MD5(NTLMv2hash, challenge + blob) + blob */ 452 HMAC_Init(&ctx, hash, len, EVP_md5()); 453 HMAC_Update(&ctx, challenge, NTLM_NONCE_LENGTH); 454 HMAC_Update(&ctx, blob, bloblen); 455 HMAC_Final(&ctx, V2, &len); 456 HMAC_cleanup(&ctx); 457 458 /* the blob is concatenated outside of this function */ 459 460 *result = SASL_OK; 461 } 462 463 return V2; 464} 465 466/***************************** Server Section *****************************/ 467 468typedef struct server_context { 469 int state; 470 471 uint32 flags; 472 unsigned char nonce[NTLM_NONCE_LENGTH]; 473 474 /* per-step mem management */ 475 char *out_buf; 476 unsigned out_buf_len; 477 478 /* socket to remote authentication host */ 479 SOCKET sock; 480 481} server_context_t; 482 483#define N(a) (sizeof (a) / sizeof (a[0])) 484 485#define SMB_HDR_PROTOCOL "\xffSMB" 486 487typedef struct { 488 unsigned char protocol[4]; 489 unsigned char command; 490 uint32 status; 491 unsigned char flags; 492 uint16 flags2; 493 uint16 PidHigh; 494 unsigned char extra[10]; 495 uint16 tid; 496 uint16 pid; 497 uint16 uid; 498 uint16 mid; 499} SMB_Header; 500 501typedef struct { 502 uint16 dialect_index; 503 unsigned char security_mode; 504 uint16 max_mpx_count; 505 uint16 max_number_vcs; 506 uint32 max_buffer_size; 507 uint32 max_raw_size; 508 uint32 session_key; 509 uint32 capabilities; 510 uint32 system_time_low; 511 uint32 system_time_high; 512 uint16 server_time_zone; 513 unsigned char encryption_key_length; 514} SMB_NegProt_Resp; 515 516typedef struct { 517 unsigned char andx_command; 518 unsigned char andx_reserved; 519 uint16 andx_offset; 520 uint16 max_buffer_size; 521 uint16 max_mpx_count; 522 uint16 vc_number; 523 uint32 session_key; 524 uint16 case_insensitive_passwd_len; 525 uint16 case_sensitive_passwd_len; 526 uint32 reserved; 527 uint32 capabilities; 528} SMB_SessionSetup; 529 530typedef struct { 531 unsigned char andx_command; 532 unsigned char andx_reserved; 533 uint16 andx_offset; 534 uint16 action; 535} SMB_SessionSetup_Resp; 536 537enum { 538 NBT_SESSION_REQUEST = 0x81, 539 NBT_POSITIVE_SESSION_RESP = 0x82, 540 NBT_NEGATIVE_SESSION_RESP = 0x83, 541 NBT_ERR_NO_LISTEN_CALLED = 0x80, 542 NBT_ERR_NO_LISTEN_CALLING = 0x81, 543 NBT_ERR_CALLED_NOT_PRESENT = 0x82, 544 NBT_ERR_INSUFFICIENT_RESRC = 0x83, 545 NBT_ERR_UNSPECIFIED = 0x8F, 546 547 SMB_HDR_SIZE = 32, 548 549 SMB_COM_NEGOTIATE_PROTOCOL = 0x72, 550 SMB_COM_SESSION_SETUP_ANDX = 0x73, 551 SMB_COM_NONE = 0xFF, 552 553 SMB_FLAGS_SERVER_TO_REDIR = 0x80, 554 555 SMB_FLAGS2_ERR_STATUS = 0x4000, 556 SMB_FLAGS2_UNICODE = 0x8000, 557 558 SMB_NEGPROT_RESP_SIZE = 34, 559 560 SMB_SECURITY_MODE_USER = 0x1, 561 SMB_SECURITY_MODE_ENCRYPT = 0x2, 562 SMB_SECURITY_MODE_SIGN = 0x4, 563 SMB_SECURITY_MODE_SIGN_REQ = 0x8, 564 565 SMB_CAP_UNICODE = 0x0004, 566 SMB_CAP_STATUS32 = 0x0040, 567 SMB_CAP_EXTENDED_SECURITY = 0x80000000, 568 569 SMB_SESSION_SETUP_SIZE = 26, 570 SMB_SESSION_SETUP_RESP_SIZE = 6, 571 572 SMB_REQUEST_MODE_GUEST = 0x1 573}; 574 575static const char *SMB_DIALECTS[] = { 576#if 0 577 "\x02PC NETWORK PROGRAM 1.0", 578 "\x02PCLAN1.0", 579 "\x02MICROSOFT NETWORKS 1.03", 580 "\x02MICROSOFT NETWORKS 3.0", 581 "\x02LANMAN1.0", 582 "\x02Windows for Workgroups 3.1a", 583 "\x02LM1.2X002", 584 "\x02DOS LM1.2X002", 585 "\x02DOS LANLAM2.1", 586 "\x02LANMAN2.1", 587#endif 588 "\x02NT LM 0.12" 589}; 590 591static void load_smb_header(unsigned char buf[], SMB_Header *hdr) 592{ 593 unsigned char *p = buf; 594 595 memcpy(p, SMB_HDR_PROTOCOL, 4); p += 4; 596 *p++ = hdr->command; 597 htoil(p, hdr->status); p += 4; 598 *p++ = hdr->flags; 599 htois(p, hdr->flags2); p += 2; 600 htois(p, hdr->PidHigh); p += 2; 601 memcpy(p, hdr->extra, 10); p += 10; 602 htois(p, hdr->tid); p += 2; 603 htois(p, hdr->pid); p += 2; 604 htois(p, hdr->uid); p += 2; 605 htois(p, hdr->mid); 606} 607 608static void unload_smb_header(unsigned char buf[], SMB_Header *hdr) 609{ 610 unsigned char *p = buf; 611 612 memcpy(hdr->protocol, p, 4); p += 4; 613 hdr->command = *p++; 614 hdr->status = itohl(p); p += 4; 615 hdr->flags = *p++; 616 hdr->flags2 = itohs(p); p += 2; 617 hdr->PidHigh = itohs(p); p += 2; 618 memcpy(hdr->extra, p, 10); p += 10; 619 hdr->tid = itohs(p); p += 2; 620 hdr->pid = itohs(p); p += 2; 621 hdr->uid = itohs(p); p += 2; 622 hdr->mid = itohs(p); 623} 624 625static void unload_negprot_resp(unsigned char buf[], SMB_NegProt_Resp *resp) 626{ 627 unsigned char *p = buf; 628 629 resp->dialect_index = itohs(p); p += 2; 630 resp->security_mode = *p++; 631 resp->max_mpx_count = itohs(p); p += 2; 632 resp->max_number_vcs = itohs(p); p += 2; 633 resp->max_buffer_size = itohl(p); p += 4; 634 resp->max_raw_size = itohl(p); p += 4; 635 resp->session_key = itohl(p); p += 4; 636 resp->capabilities = itohl(p); p += 4; 637 resp->system_time_low = itohl(p); p += 4; 638 resp->system_time_high = itohl(p); p += 4; 639 resp->server_time_zone = itohs(p); p += 2; 640 resp->encryption_key_length = *p; 641} 642 643static void load_session_setup(unsigned char buf[], SMB_SessionSetup *setup) 644{ 645 unsigned char *p = buf; 646 647 *p++ = setup->andx_command; 648 *p++ = setup->andx_reserved; 649 htois(p, setup->andx_offset); p += 2; 650 htois(p, setup->max_buffer_size); p += 2; 651 htois(p, setup->max_mpx_count); p += 2; 652 htois(p, setup->vc_number); p += 2; 653 htoil(p, setup->session_key); p += 4; 654 htois(p, setup->case_insensitive_passwd_len); p += 2; 655 htois(p, setup->case_sensitive_passwd_len); p += 2; 656 htoil(p, setup->reserved); p += 4; 657 htoil(p, setup->capabilities); p += 4; 658} 659 660static void unload_session_setup_resp(unsigned char buf[], 661 SMB_SessionSetup_Resp *resp) 662{ 663 unsigned char *p = buf; 664 665 resp->andx_command = *p++; 666 resp->andx_reserved = *p++; 667 resp->andx_offset = itohs(p); p += 2; 668 resp->action = itohs(p); 669} 670 671/* 672 * Keep calling the writev() system call with 'fd', 'iov', and 'iovcnt' 673 * until all the data is written out or an error occurs. 674 */ 675static int retry_writev(SOCKET fd, struct iovec *iov, int iovcnt) 676{ 677 int n; 678 int i; 679 int written = 0; 680 static int iov_max = 681#ifdef MAXIOV 682 MAXIOV 683#else 684#ifdef IOV_MAX 685 IOV_MAX 686#else 687 8192 688#endif 689#endif 690 ; 691 692 for (;;) { 693 while (iovcnt && iov[0].iov_len == 0) { 694 iov++; 695 iovcnt--; 696 } 697 698 if (!iovcnt) return written; 699 700 n = writev(fd, iov, iovcnt > iov_max ? iov_max : iovcnt); 701 if (n == -1) { 702#ifndef WIN32 703 if (errno == EINVAL && iov_max > 10) { 704 iov_max /= 2; 705 continue; 706 } 707 if (errno == EINTR) continue; 708#endif 709 return -1; 710 } 711 712 written += n; 713 714 for (i = 0; i < iovcnt; i++) { 715 if ((int) iov[i].iov_len > n) { 716 iov[i].iov_base = (char *) iov[i].iov_base + n; 717 iov[i].iov_len -= n; 718 break; 719 } 720 n -= iov[i].iov_len; 721 iov[i].iov_len = 0; 722 } 723 724 if (i == iovcnt) return written; 725 } 726} 727 728/* 729 * Keep calling the read() system call with 'fd', 'buf', and 'nbyte' 730 * until all the data is read in or an error occurs. 731 */ 732static int retry_read(SOCKET fd, char *buf0, unsigned nbyte) 733{ 734 int n; 735 int nread = 0; 736 char *buf = buf0; 737 738 if (nbyte == 0) return 0; 739 740 for (;;) { 741/* Can't use read() on sockets on Windows, but recv works on all platforms */ 742 n = recv (fd, buf, nbyte, 0); 743 if (n == -1 || n == 0) { 744#ifndef WIN32 745 if (errno == EINTR || errno == EAGAIN) continue; 746#endif 747 return -1; 748 } 749 750 nread += n; 751 752 if (n >= (int) nbyte) return nread; 753 754 buf += n; 755 nbyte -= n; 756 } 757} 758 759static void make_netbios_name(const char *in, unsigned char out[]) 760{ 761 size_t i, j = 0, n; 762 763 /* create a NetBIOS name from the DNS name 764 * 765 * - use up to the first 16 chars of the first part of the hostname 766 * - convert to all uppercase 767 * - use the tail end of the output buffer as temp space 768 */ 769 n = strcspn(in, "."); 770 if (n > 16) n = 16; 771 strncpy((char *)out+18, in, n); 772 in = out+18; 773 ucase(in, n); 774 775 out[j++] = 0x20; 776 for (i = 0; i < n; i++) { 777 out[j++] = ((in[i] >> 4) & 0xf) + 0x41; 778 out[j++] = (in[i] & 0xf) + 0x41; 779 } 780 for (; i < 16; i++) { 781 out[j++] = ((0x20 >> 4) & 0xf) + 0x41; 782 out[j++] = (0x20 & 0xf) + 0x41; 783 } 784 out[j] = 0; 785} 786 787static SOCKET smb_connect_server(const sasl_utils_t *utils, const char *client, 788 const char *server) 789{ 790 struct addrinfo hints; 791 struct addrinfo *ai = NULL, *r; 792 SOCKET s = (SOCKET) -1; 793 int err; 794 char * error_str; 795#ifdef WIN32 796 DWORD saved_errno; 797#else 798 int saved_errno; 799#endif 800 int niflags; 801 char *port = "139"; 802 char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV]; 803 804 unsigned char called[34]; 805 unsigned char calling[34]; 806 struct iovec iov[3]; 807 uint32 pkt; 808 int rc; 809 810 memset(&hints, 0, sizeof(hints)); 811 hints.ai_family = PF_UNSPEC; 812 hints.ai_socktype = SOCK_STREAM; 813 hints.ai_flags = AI_CANONNAME; 814 if ((err = getaddrinfo(server, port, &hints, &ai)) != 0) { 815 utils->log(NULL, SASL_LOG_ERR, 816 "NTLM: getaddrinfo %s/%s: %s", 817 server, port, gai_strerror(err)); 818 return -1; 819 } 820 821 /* Make sure we have AF_INET or AF_INET6 addresses. */ 822 if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) { 823 utils->log(NULL, SASL_LOG_ERR, "NTLM: no IP address info for %s", 824 ai->ai_canonname ? ai->ai_canonname : server); 825 freeaddrinfo(ai); 826 return -1; 827 } 828 829 /* establish connection to authentication server */ 830 for (r = ai; r; r = r->ai_next) { 831 s = socket(r->ai_family, r->ai_socktype, r->ai_protocol); 832 if (s < 0) 833 continue; 834 if (connect(s, r->ai_addr, r->ai_addrlen) >= 0) 835 break; 836#ifdef WIN32 837 saved_errno = WSAGetLastError(); 838#else 839 saved_errno = errno; 840#endif 841 closesocket (s); 842 s = -1; 843 niflags = (NI_NUMERICHOST | NI_NUMERICSERV); 844#ifdef NI_WITHSCOPEID 845 if (r->ai_family == AF_INET6) 846 niflags |= NI_WITHSCOPEID; 847#endif 848 if (getnameinfo(r->ai_addr, r->ai_addrlen, hbuf, sizeof(hbuf), 849 pbuf, sizeof(pbuf), niflags) != 0) { 850 strcpy(hbuf, "unknown"); 851 strcpy(pbuf, "unknown"); 852 } 853 854 /* Can't use errno (and %m), as it doesn't contain 855 * the socket error on Windows */ 856 error_str = _plug_get_error_message (utils, saved_errno); 857 utils->log(NULL, SASL_LOG_WARN, "NTLM: connect %s[%s]/%s: %s", 858 ai->ai_canonname ? ai->ai_canonname : server, 859 hbuf, 860 pbuf, 861 error_str); 862 utils->free (error_str); 863 } 864 if (s < 0) { 865 if (getnameinfo(ai->ai_addr, ai->ai_addrlen, NULL, 0, 866 pbuf, sizeof(pbuf), NI_NUMERICSERV) != 0) { 867 strcpy(pbuf, "unknown"); 868 } 869 utils->log(NULL, SASL_LOG_ERR, "NTLM: couldn't connect to %s/%s", 870 ai->ai_canonname ? ai->ai_canonname : server, pbuf); 871 freeaddrinfo(ai); 872 return -1; 873 } 874 875 freeaddrinfo(ai); 876 877 /*** send NetBIOS session request ***/ 878 879 /* get length of data */ 880 pkt = sizeof(called) + sizeof(calling); 881 882 /* make sure length is less than 17 bits */ 883 if (pkt >= (1 << 17)) { 884 closesocket(s); 885 return -1; 886 } 887 888 /* prepend the packet type */ 889 pkt |= (NBT_SESSION_REQUEST << 24); 890 pkt = htonl(pkt); 891 892 /* XXX should determine the real NetBIOS name */ 893 make_netbios_name(server, called); 894 make_netbios_name(client, calling); 895 896 iov[0].iov_base = (void *) &pkt; 897 iov[0].iov_len = sizeof(pkt); 898 iov[1].iov_base = called; 899 iov[1].iov_len = sizeof(called); 900 iov[2].iov_base = calling; 901 iov[2].iov_len = sizeof(calling); 902 903 rc = retry_writev(s, iov, N(iov)); 904 if (rc == -1) { 905 utils->log(NULL, SASL_LOG_ERR, 906 "NTLM: error sending NetBIOS session request"); 907 closesocket(s); 908 return -1; 909 } 910 911 rc = retry_read(s, (char *) &pkt, sizeof(pkt)); 912 pkt = ntohl(pkt); 913 if (rc == -1 || pkt != (uint32) (NBT_POSITIVE_SESSION_RESP << 24)) { 914 unsigned char ec = NBT_ERR_UNSPECIFIED; 915 char *errstr; 916 917 retry_read(s, (char *) &ec, sizeof(ec)); 918 switch (ec) { 919 case NBT_ERR_NO_LISTEN_CALLED: 920 errstr = "Not listening on called name"; 921 break; 922 case NBT_ERR_NO_LISTEN_CALLING: 923 errstr = "Not listening for calling name"; 924 break; 925 case NBT_ERR_CALLED_NOT_PRESENT: 926 errstr = "Called name not present"; 927 break; 928 case NBT_ERR_INSUFFICIENT_RESRC: 929 errstr = "Called name present, but insufficient resources"; 930 break; 931 default: 932 errstr = "Unspecified error"; 933 } 934 utils->log(NULL, SASL_LOG_ERR, 935 "NTLM: negative NetBIOS session response: %s", errstr); 936 closesocket(s); 937 return -1; 938 } 939 940 return s; 941} 942 943static int smb_negotiate_protocol(const sasl_utils_t *utils, 944 server_context_t *text, char **domain) 945{ 946 SMB_Header hdr; 947 SMB_NegProt_Resp resp; 948 unsigned char hbuf[SMB_HDR_SIZE], *p; 949 unsigned char wordcount = 0; 950 unsigned char bc[sizeof(uint16)]; 951 uint16 bytecount; 952 uint32 len, nl; 953 int n_dialects = N(SMB_DIALECTS); 954 struct iovec iov[4+N(SMB_DIALECTS)]; 955 size_t i, n; 956 int rc; 957 pid_t current_pid; 958 959 /*** create a negotiate protocol request ***/ 960 961 /* create a header */ 962 memset(&hdr, 0, sizeof(hdr)); 963 hdr.command = SMB_COM_NEGOTIATE_PROTOCOL; 964#if 0 965 hdr.flags2 = SMB_FLAGS2_ERR_STATUS; 966 if (text->flags & NTLM_USE_UNICODE) hdr.flags2 |= SMB_FLAGS2_UNICODE; 967#endif 968 current_pid = getpid(); 969 if (sizeof(current_pid) <= 2) { 970 hdr.pid = (uint16) current_pid; 971 hdr.PidHigh = 0; 972 } else { 973 hdr.pid = (uint16) (((uint32) current_pid) & 0xFFFF); 974 hdr.PidHigh = (uint16) (((uint32) current_pid) >> 16); 975 } 976 977 load_smb_header(hbuf, &hdr); 978 979 /* put together all of the pieces of the request */ 980 n = 0; 981 iov[n].iov_base = (void *) &nl; 982 iov[n++].iov_len = sizeof(len); 983 iov[n].iov_base = hbuf; 984 iov[n++].iov_len = SMB_HDR_SIZE; 985 iov[n].iov_base = &wordcount; 986 iov[n++].iov_len = sizeof(wordcount); 987 iov[n].iov_base = (void *) &bc; 988 iov[n++].iov_len = sizeof(bc); 989 990 /* add our supported dialects */ 991 for (i = 0; i < n_dialects; i++) { 992 iov[n].iov_base = (char *) SMB_DIALECTS[i]; 993 iov[n++].iov_len = (long) strlen(SMB_DIALECTS[i]) + 1; 994 } 995 996 /* total up the lengths */ 997 len = bytecount = 0; 998 for (i = 1; i < 4; i++) len += iov[i].iov_len; 999 for (i = 4; i < n; i++) bytecount += (uint16) iov[i].iov_len; 1000 len += bytecount; 1001 nl = htonl(len); 1002 htois((char *) &bc, bytecount); 1003 1004 /* send it */ 1005 rc = retry_writev(text->sock, iov, n); 1006 if (rc == -1) { 1007 utils->log(NULL, SASL_LOG_ERR, 1008 "NTLM: error sending NEGPROT request"); 1009 return SASL_FAIL; 1010 } 1011 1012 /*** read the negotiate protocol response ***/ 1013 1014 /* read the total length */ 1015 rc = retry_read(text->sock, (char *) &nl, sizeof(nl)); 1016 if (rc < (int) sizeof(nl)) { 1017 utils->log(NULL, SASL_LOG_ERR, 1018 "NTLM: error reading NEGPROT response length"); 1019 return SASL_FAIL; 1020 } 1021 1022 /* read the data */ 1023 len = ntohl(nl); 1024 if (_plug_buf_alloc(utils, &text->out_buf, &text->out_buf_len, 1025 len) != SASL_OK) { 1026 SETERROR(utils, "cannot allocate NTLM NEGPROT response buffer"); 1027 return SASL_NOMEM; 1028 } 1029 1030 rc = retry_read(text->sock, text->out_buf, len); 1031 if (rc < (int) len) { 1032 utils->log(NULL, SASL_LOG_ERR, 1033 "NTLM: error reading NEGPROT response"); 1034 return SASL_FAIL; 1035 } 1036 p = text->out_buf; 1037 1038 /* parse the header */ 1039 if (len < SMB_HDR_SIZE) { 1040 utils->log(NULL, SASL_LOG_ERR, 1041 "NTLM: not enough data for NEGPROT response header"); 1042 return SASL_FAIL; 1043 } 1044 unload_smb_header(p, &hdr); 1045 p += SMB_HDR_SIZE; 1046 len -= SMB_HDR_SIZE; 1047 1048 /* sanity check the header */ 1049 if (memcmp(hdr.protocol, SMB_HDR_PROTOCOL, 4) /* correct protocol */ 1050 || hdr.command != SMB_COM_NEGOTIATE_PROTOCOL /* correct command */ 1051 || hdr.status /* no errors */ 1052 || !(hdr.flags & SMB_FLAGS_SERVER_TO_REDIR)) { /* response */ 1053 utils->log(NULL, SASL_LOG_ERR, 1054 "NTLM: error in NEGPROT response header: %ld", 1055 hdr.status); 1056 return SASL_FAIL; 1057 } 1058 1059 /* get the wordcount */ 1060 if (len < 1) { 1061 utils->log(NULL, SASL_LOG_ERR, 1062 "NTLM: not enough data for NEGPROT response wordcount"); 1063 return SASL_FAIL; 1064 } 1065 wordcount = *p++; 1066 len--; 1067 1068 /* parse the parameters */ 1069 if (wordcount != SMB_NEGPROT_RESP_SIZE / sizeof(uint16)) { 1070 utils->log(NULL, SASL_LOG_ERR, 1071 "NTLM: incorrect NEGPROT wordcount for NT LM 0.12"); 1072 return SASL_FAIL; 1073 } 1074 unload_negprot_resp(p, &resp); 1075 p += SMB_NEGPROT_RESP_SIZE; 1076 len -= SMB_NEGPROT_RESP_SIZE; 1077 1078 /* sanity check the parameters */ 1079 if (resp.dialect_index != 0 1080 || !(resp.security_mode & SMB_SECURITY_MODE_USER) 1081 || !(resp.security_mode & SMB_SECURITY_MODE_ENCRYPT) 1082 || resp.security_mode & SMB_SECURITY_MODE_SIGN_REQ 1083 || resp.capabilities & SMB_CAP_EXTENDED_SECURITY 1084 || resp.encryption_key_length != NTLM_NONCE_LENGTH) { 1085 utils->log(NULL, SASL_LOG_ERR, 1086 "NTLM: error in NEGPROT response parameters"); 1087 return SASL_FAIL; 1088 } 1089 1090 /* get the bytecount */ 1091 if (len < 2) { 1092 utils->log(NULL, SASL_LOG_ERR, 1093 "NTLM: not enough data for NEGPROT response bytecount"); 1094 return SASL_FAIL; 1095 } 1096 bytecount = itohs(p); 1097 p += 2; 1098 len -= 2; 1099 if (len != bytecount) { 1100 utils->log(NULL, SASL_LOG_ERR, 1101 "NTLM: incorrect bytecount for NEGPROT response data"); 1102 return SASL_FAIL; 1103 } 1104 1105 /* parse the data */ 1106 memcpy(text->nonce, p, resp.encryption_key_length); 1107 p += resp.encryption_key_length; 1108 len -= resp.encryption_key_length; 1109 1110 /* if client asked for target, send domain */ 1111 if (text->flags & NTLM_ASK_TARGET) { 1112 *domain = utils->malloc(len); 1113 if (domain == NULL) { 1114 MEMERROR(utils); 1115 return SASL_NOMEM; 1116 } 1117 memcpy(*domain, p, len); 1118 from_unicode(*domain, *domain, len); 1119 1120 text->flags |= NTLM_TARGET_IS_DOMAIN; 1121 } 1122 1123 return SASL_OK; 1124} 1125 1126static int smb_session_setup(const sasl_utils_t *utils, server_context_t *text, 1127 const char *authid, char *domain, 1128 unsigned char *lm_resp, unsigned lm_resp_len, 1129 unsigned char *nt_resp, unsigned nt_resp_len) 1130{ 1131 SMB_Header hdr; 1132 SMB_SessionSetup setup; 1133 SMB_SessionSetup_Resp resp; 1134 unsigned char hbuf[SMB_HDR_SIZE], sbuf[SMB_SESSION_SETUP_SIZE], *p; 1135 unsigned char wordcount = SMB_SESSION_SETUP_SIZE / sizeof(uint16); 1136 unsigned char bc[sizeof(uint16)]; 1137 uint16 bytecount; 1138 uint32 len, nl; 1139 struct iovec iov[12]; 1140 size_t i, n; 1141 int rc; 1142#if (defined(WIN32) || defined(__APPLE__)) 1143 char osbuf[80]; 1144#else 1145 char osbuf[2*SYS_NMLN+2]; 1146#endif 1147 char lanman[20]; 1148 pid_t current_pid; 1149 1150 /*** create a session setup request ***/ 1151 1152 /* create a header */ 1153 memset(&hdr, 0, sizeof(hdr)); 1154 hdr.command = SMB_COM_SESSION_SETUP_ANDX; 1155#if 0 1156 hdr.flags2 = SMB_FLAGS2_ERR_STATUS; 1157 if (text->flags & NTLM_USE_UNICODE) hdr.flags2 |= SMB_FLAGS2_UNICODE; 1158#endif 1159 current_pid = getpid(); 1160 if (sizeof(current_pid) <= 2) { 1161 hdr.pid = (uint16) current_pid; 1162 hdr.PidHigh = 0; 1163 } else { 1164 hdr.pid = (uint16) (((uint32) current_pid) & 0xFFFF); 1165 hdr.PidHigh = (uint16) (((uint32) current_pid) >> 16); 1166 } 1167 1168 load_smb_header(hbuf, &hdr); 1169 1170 /* create a the setup parameters */ 1171 memset(&setup, 0, sizeof(setup)); 1172 setup.andx_command = SMB_COM_NONE; 1173 setup.max_buffer_size = 0xFFFF; 1174 if (lm_resp) setup.case_insensitive_passwd_len = lm_resp_len; 1175 if (nt_resp) setup.case_sensitive_passwd_len = nt_resp_len; 1176#if 0 1177 if (text->flags & NTLM_USE_UNICODE) 1178 setup.capabilities = SMB_CAP_UNICODE; 1179#endif 1180 load_session_setup(sbuf, &setup); 1181 1182 _plug_snprintf_os_info (osbuf, sizeof(osbuf)); 1183 1184 snprintf(lanman, sizeof(lanman), "Cyrus SASL %u.%u.%u", 1185 SASL_VERSION_MAJOR, SASL_VERSION_MINOR, 1186 SASL_VERSION_STEP); 1187 1188 /* put together all of the pieces of the request */ 1189 n = 0; 1190 iov[n].iov_base = (void *) &nl; 1191 iov[n++].iov_len = sizeof(len); 1192 iov[n].iov_base = hbuf; 1193 iov[n++].iov_len = SMB_HDR_SIZE; 1194 iov[n].iov_base = &wordcount; 1195 iov[n++].iov_len = sizeof(wordcount); 1196 iov[n].iov_base = sbuf; 1197 iov[n++].iov_len = SMB_SESSION_SETUP_SIZE; 1198 iov[n].iov_base = (void *) &bc; 1199 iov[n++].iov_len = sizeof(bc); 1200 if (lm_resp) { 1201 iov[n].iov_base = lm_resp; 1202 iov[n++].iov_len = NTLM_RESP_LENGTH; 1203 } 1204 if (nt_resp) { 1205 iov[n].iov_base = nt_resp; 1206 iov[n++].iov_len = NTLM_RESP_LENGTH; 1207 } 1208 iov[n].iov_base = (char*) authid; 1209 iov[n++].iov_len = (long) strlen(authid) + 1; 1210 if (!domain) domain = ""; 1211 iov[n].iov_base = domain; 1212 iov[n++].iov_len = (long) strlen(domain) + 1; 1213 iov[n].iov_base = osbuf; 1214 iov[n++].iov_len = (long) strlen(osbuf) + 1; 1215 iov[n].iov_base = lanman; 1216 iov[n++].iov_len = (long) strlen(lanman) + 1; 1217 1218 /* total up the lengths */ 1219 len = bytecount = 0; 1220 for (i = 1; i < 5; i++) len += iov[i].iov_len; 1221 for (i = 5; i < n; i++) bytecount += (uint16) iov[i].iov_len; 1222 len += bytecount; 1223 nl = htonl(len); 1224 htois((char *) &bc, bytecount); 1225 1226 /* send it */ 1227 rc = retry_writev(text->sock, iov, n); 1228 if (rc == -1) { 1229 utils->log(NULL, SASL_LOG_ERR, 1230 "NTLM: error sending SESSIONSETUP request"); 1231 return SASL_FAIL; 1232 } 1233 1234 /*** read the session setup response ***/ 1235 1236 /* read the total length */ 1237 rc = retry_read(text->sock, (char *) &nl, sizeof(nl)); 1238 if (rc < (int) sizeof(nl)) { 1239 utils->log(NULL, SASL_LOG_ERR, 1240 "NTLM: error reading SESSIONSETUP response length"); 1241 return SASL_FAIL; 1242 } 1243 1244 /* read the data */ 1245 len = ntohl(nl); 1246 if (_plug_buf_alloc(utils, &text->out_buf, &text->out_buf_len, 1247 len) != SASL_OK) { 1248 SETERROR(utils, 1249 "cannot allocate NTLM SESSIONSETUP response buffer"); 1250 return SASL_NOMEM; 1251 } 1252 1253 rc = retry_read(text->sock, text->out_buf, len); 1254 if (rc < (int) len) { 1255 utils->log(NULL, SASL_LOG_ERR, 1256 "NTLM: error reading SESSIONSETUP response"); 1257 return SASL_FAIL; 1258 } 1259 p = text->out_buf; 1260 1261 /* parse the header */ 1262 if (len < SMB_HDR_SIZE) { 1263 utils->log(NULL, SASL_LOG_ERR, 1264 "NTLM: not enough data for SESSIONSETUP response header"); 1265 return SASL_FAIL; 1266 } 1267 unload_smb_header(p, &hdr); 1268 p += SMB_HDR_SIZE; 1269 len -= SMB_HDR_SIZE; 1270 1271 /* sanity check the header */ 1272 if (memcmp(hdr.protocol, SMB_HDR_PROTOCOL, 4) /* correct protocol */ 1273 || hdr.command != SMB_COM_SESSION_SETUP_ANDX /* correct command */ 1274 || !(hdr.flags & SMB_FLAGS_SERVER_TO_REDIR)) { /* response */ 1275 utils->log(NULL, SASL_LOG_ERR, 1276 "NTLM: error in SESSIONSETUP response header"); 1277 return SASL_FAIL; 1278 } 1279 1280 /* check auth success */ 1281 if (hdr.status) { 1282 utils->log(NULL, SASL_LOG_ERR, 1283 "NTLM: auth failure: %ld", hdr.status); 1284 return SASL_BADAUTH; 1285 } 1286 1287 /* get the wordcount */ 1288 if (len < 1) { 1289 utils->log(NULL, SASL_LOG_ERR, 1290 "NTLM: not enough data for SESSIONSETUP response wordcount"); 1291 return SASL_FAIL; 1292 } 1293 wordcount = *p++; 1294 len--; 1295 1296 /* parse the parameters */ 1297 if (wordcount < SMB_SESSION_SETUP_RESP_SIZE / sizeof(uint16)) { 1298 utils->log(NULL, SASL_LOG_ERR, 1299 "NTLM: incorrect SESSIONSETUP wordcount"); 1300 return SASL_FAIL; 1301 } 1302 unload_session_setup_resp(p, &resp); 1303 1304 /* check auth success */ 1305 if (resp.action & SMB_REQUEST_MODE_GUEST) { 1306 utils->log(NULL, SASL_LOG_ERR, 1307 "NTLM: authenticated as guest"); 1308 return SASL_BADAUTH; 1309 } 1310 1311 return SASL_OK; 1312} 1313 1314/* 1315 * Create a server challenge message (type 2) consisting of: 1316 * 1317 * signature (8 bytes) 1318 * message type (uint32) 1319 * target name (buffer) 1320 * flags (uint32) 1321 * challenge (8 bytes) 1322 * context (8 bytes) 1323 * target info (buffer) 1324 * data 1325 */ 1326static int create_challenge(const sasl_utils_t *utils, 1327 char **buf, unsigned *buflen, 1328 const char *target, uint32 flags, 1329 const u_char *nonce, unsigned *outlen) 1330{ 1331 uint32 offset = NTLM_TYPE2_DATA_OFFSET; 1332 u_char *base; 1333 1334 if (!nonce) { 1335 SETERROR(utils, "need nonce for NTLM challenge"); 1336 return SASL_FAIL; 1337 } 1338 1339 *outlen = offset + 2 * xstrlen(target); 1340 1341 if (_plug_buf_alloc(utils, buf, buflen, *outlen) != SASL_OK) { 1342 SETERROR(utils, "cannot allocate NTLM challenge"); 1343 return SASL_NOMEM; 1344 } 1345 1346 base = *buf; 1347 memset(base, 0, *outlen); 1348 memcpy(base + NTLM_SIG_OFFSET, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE)); 1349 htoil(base + NTLM_TYPE_OFFSET, NTLM_TYPE_CHALLENGE); 1350 load_buffer(base + NTLM_TYPE2_TARGET_OFFSET, 1351 ucase(target, 0), (uint16) xstrlen(target), flags & NTLM_USE_UNICODE, 1352 base, &offset); 1353 htoil(base + NTLM_TYPE2_FLAGS_OFFSET, flags); 1354 memcpy(base + NTLM_TYPE2_CHALLENGE_OFFSET, nonce, NTLM_NONCE_LENGTH); 1355 1356 return SASL_OK; 1357} 1358 1359static int ntlm_server_mech_new(void *glob_context __attribute__((unused)), 1360 sasl_server_params_t *sparams, 1361 const char *challenge __attribute__((unused)), 1362 unsigned challen __attribute__((unused)), 1363 void **conn_context) 1364{ 1365 server_context_t *text; 1366 const char *serv; 1367 unsigned int len; 1368 SOCKET sock = (SOCKET) -1; 1369 1370 sparams->utils->getopt(sparams->utils->getopt_context, 1371 "NTLM", "ntlm_server", &serv, &len); 1372 if (serv) { 1373 /* try to start a NetBIOS session with the server */ 1374 sock = smb_connect_server(sparams->utils, sparams->serverFQDN, serv); 1375 if (sock == (SOCKET) -1) return SASL_UNAVAIL; 1376 } 1377 1378 /* holds state are in */ 1379 text = sparams->utils->malloc(sizeof(server_context_t)); 1380 if (text == NULL) { 1381 MEMERROR( sparams->utils ); 1382 return SASL_NOMEM; 1383 } 1384 1385 memset(text, 0, sizeof(server_context_t)); 1386 1387 text->state = 1; 1388 text->sock = sock; 1389 1390 *conn_context = text; 1391 1392 return SASL_OK; 1393} 1394 1395static int ntlm_server_mech_step1(server_context_t *text, 1396 sasl_server_params_t *sparams, 1397 const char *clientin, 1398 unsigned clientinlen, 1399 const char **serverout, 1400 unsigned *serveroutlen, 1401 sasl_out_params_t *oparams __attribute__((unused))) 1402{ 1403 char *domain = NULL; 1404 int result; 1405 1406 if (!clientin || clientinlen < NTLM_TYPE1_MINSIZE || 1407 memcmp(clientin, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE)) || 1408 itohl(clientin + NTLM_TYPE_OFFSET) != NTLM_TYPE_REQUEST) { 1409 SETERROR(sparams->utils, "client didn't issue valid NTLM request"); 1410 return SASL_BADPROT; 1411 } 1412 1413 text->flags = itohl(clientin + NTLM_TYPE1_FLAGS_OFFSET); 1414 sparams->utils->log(NULL, SASL_LOG_DEBUG, 1415 "client flags: %x", text->flags); 1416 1417 text->flags &= NTLM_FLAGS_MASK; /* mask off the bits we don't support */ 1418 1419 /* if client can do Unicode, turn off ASCII */ 1420 if (text->flags & NTLM_USE_UNICODE) text->flags &= ~NTLM_USE_ASCII; 1421 1422 if (text->sock == -1) { 1423 /* generate challenge internally */ 1424 1425 /* if client asked for target, use FQDN as server target */ 1426 if (text->flags & NTLM_ASK_TARGET) { 1427 result = _plug_strdup(sparams->utils, sparams->serverFQDN, 1428 &domain, NULL); 1429 if (result != SASL_OK) return result; 1430 1431 text->flags |= NTLM_TARGET_IS_SERVER; 1432 } 1433 1434 /* generate a nonce */ 1435 sparams->utils->rand(sparams->utils->rpool, 1436 (char *) text->nonce, NTLM_NONCE_LENGTH); 1437 } 1438 else { 1439 /* proxy the response/challenge */ 1440 result = smb_negotiate_protocol(sparams->utils, text, &domain); 1441 if (result != SASL_OK) goto cleanup; 1442 } 1443 1444 result = create_challenge(sparams->utils, 1445 &text->out_buf, &text->out_buf_len, 1446 domain, text->flags, text->nonce, serveroutlen); 1447 if (result != SASL_OK) goto cleanup; 1448 1449 *serverout = text->out_buf; 1450 1451 text->state = 2; 1452 1453 result = SASL_CONTINUE; 1454 1455 cleanup: 1456 if (domain) sparams->utils->free(domain); 1457 1458 return result; 1459} 1460 1461static int ntlm_server_mech_step2(server_context_t *text, 1462 sasl_server_params_t *sparams, 1463 const char *clientin, 1464 unsigned clientinlen, 1465 const char **serverout __attribute__((unused)), 1466 unsigned *serveroutlen __attribute__((unused)), 1467 sasl_out_params_t *oparams) 1468{ 1469 unsigned char *lm_resp = NULL, *nt_resp = NULL; 1470 char *domain = NULL, *authid = NULL; 1471 unsigned lm_resp_len, nt_resp_len, domain_len, authid_len; 1472 int result; 1473 1474 if (!clientin || clientinlen < NTLM_TYPE3_MINSIZE || 1475 memcmp(clientin, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE)) || 1476 itohl(clientin + NTLM_TYPE_OFFSET) != NTLM_TYPE_RESPONSE) { 1477 SETERROR(sparams->utils, "client didn't issue valid NTLM response"); 1478 return SASL_BADPROT; 1479 } 1480 1481 result = unload_buffer(sparams->utils, (const u_char *)clientin + NTLM_TYPE3_LMRESP_OFFSET, 1482 (u_char **) &lm_resp, &lm_resp_len, 0, 1483 (const u_char *)clientin, clientinlen); 1484 if (result != SASL_OK) goto cleanup; 1485 1486 result = unload_buffer(sparams->utils, (const u_char *)clientin + NTLM_TYPE3_NTRESP_OFFSET, 1487 (u_char **) &nt_resp, &nt_resp_len, 0, 1488 (const u_char *)clientin, clientinlen); 1489 if (result != SASL_OK) goto cleanup; 1490 1491 result = unload_buffer(sparams->utils, (const u_char *)clientin + NTLM_TYPE3_DOMAIN_OFFSET, 1492 (u_char **) &domain, &domain_len, 1493 text->flags & NTLM_USE_UNICODE, 1494 (const u_char *)clientin, clientinlen); 1495 if (result != SASL_OK) goto cleanup; 1496 1497 result = unload_buffer(sparams->utils, (const u_char *)clientin + NTLM_TYPE3_USER_OFFSET, 1498 (u_char **) &authid, &authid_len, 1499 text->flags & NTLM_USE_UNICODE, 1500 (const u_char *)clientin, clientinlen); 1501 if (result != SASL_OK) goto cleanup; 1502 1503 /* require at least one response and an authid */ 1504 if ((!lm_resp && !nt_resp) || 1505 (lm_resp && lm_resp_len < NTLM_RESP_LENGTH) || 1506 (nt_resp && nt_resp_len < NTLM_RESP_LENGTH) || 1507 !authid) { 1508 SETERROR(sparams->utils, "client issued incorrect/nonexistent responses"); 1509 result = SASL_BADPROT; 1510 goto cleanup; 1511 } 1512 1513 sparams->utils->log(NULL, SASL_LOG_DEBUG, 1514 "client user: %s", authid); 1515 if (domain) sparams->utils->log(NULL, SASL_LOG_DEBUG, 1516 "client domain: %s", domain); 1517 1518 if (text->sock == -1) { 1519 /* verify the response internally */ 1520 1521 sasl_secret_t *password = NULL; 1522 size_t pass_len; 1523 const char *password_request[] = { SASL_AUX_PASSWORD, 1524 NULL }; 1525 struct propval auxprop_values[2]; 1526 unsigned char hash[NTLM_HASH_LENGTH]; 1527 unsigned char resp[NTLM_RESP_LENGTH]; 1528 1529 /* fetch user's password */ 1530 result = sparams->utils->prop_request(sparams->propctx, password_request); 1531 if (result != SASL_OK) goto cleanup; 1532 1533 /* this will trigger the getting of the aux properties */ 1534 result = sparams->canon_user(sparams->utils->conn, authid, authid_len, 1535 SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams); 1536 if (result != SASL_OK) goto cleanup; 1537 1538 result = sparams->utils->prop_getnames(sparams->propctx, 1539 password_request, 1540 auxprop_values); 1541 if (result < 0 || 1542 (!auxprop_values[0].name || !auxprop_values[0].values)) { 1543 /* We didn't find this username */ 1544 SETERROR(sparams->utils, "no secret in database"); 1545 result = sparams->transition ? SASL_TRANS : SASL_NOUSER; 1546 goto cleanup; 1547 } 1548 1549 pass_len = strlen(auxprop_values[0].values[0]); 1550 if (pass_len == 0) { 1551 SETERROR(sparams->utils, "empty secret"); 1552 result = SASL_FAIL; 1553 goto cleanup; 1554 } 1555 1556 password = sparams->utils->malloc(sizeof(sasl_secret_t) + pass_len); 1557 if (!password) { 1558 result = SASL_NOMEM; 1559 goto cleanup; 1560 } 1561 1562 password->len = pass_len; 1563 strncpy((char *)password->data, auxprop_values[0].values[0], pass_len + 1); 1564 1565 /* erase the plaintext password */ 1566 sparams->utils->prop_erase(sparams->propctx, password_request[0]); 1567 1568 /* calculate our own response(s) and compare with client's */ 1569 result = SASL_OK; 1570 if (nt_resp && (nt_resp_len > NTLM_RESP_LENGTH)) { 1571 /* Try NTv2 response */ 1572 sparams->utils->log(NULL, SASL_LOG_DEBUG, 1573 "calculating NTv2 response"); 1574 V2(resp, password, authid, domain, text->nonce, 1575 lm_resp + MD5_DIGEST_LENGTH, nt_resp_len - MD5_DIGEST_LENGTH, 1576 sparams->utils, &text->out_buf, &text->out_buf_len, 1577 &result); 1578 1579 /* No need to compare the blob */ 1580 if (memcmp(nt_resp, resp, MD5_DIGEST_LENGTH)) { 1581 SETERROR(sparams->utils, "incorrect NTLMv2 response"); 1582 result = SASL_BADAUTH; 1583 } 1584 } 1585 else if (nt_resp) { 1586 /* Try NT response */ 1587 sparams->utils->log(NULL, SASL_LOG_DEBUG, 1588 "calculating NT response"); 1589 P24(resp, P21(hash, password, P16_nt, sparams->utils, 1590 &text->out_buf, &text->out_buf_len, &result), 1591 text->nonce); 1592 if (memcmp(nt_resp, resp, NTLM_RESP_LENGTH)) { 1593 SETERROR(sparams->utils, "incorrect NTLM response"); 1594 result = SASL_BADAUTH; 1595 } 1596 } 1597 else if (lm_resp) { 1598 /* Try LMv2 response */ 1599 sparams->utils->log(NULL, SASL_LOG_DEBUG, 1600 "calculating LMv2 response"); 1601 V2(resp, password, authid, domain, text->nonce, 1602 lm_resp + MD5_DIGEST_LENGTH, lm_resp_len - MD5_DIGEST_LENGTH, 1603 sparams->utils, &text->out_buf, &text->out_buf_len, 1604 &result); 1605 1606 /* No need to compare the blob */ 1607 if (memcmp(lm_resp, resp, MD5_DIGEST_LENGTH)) { 1608 /* Try LM response */ 1609 sparams->utils->log(NULL, SASL_LOG_DEBUG, 1610 "calculating LM response"); 1611 P24(resp, P21(hash, password, P16_lm, sparams->utils, 1612 &text->out_buf, &text->out_buf_len, &result), 1613 text->nonce); 1614 if (memcmp(lm_resp, resp, NTLM_RESP_LENGTH)) { 1615 SETERROR(sparams->utils, "incorrect LMv1/v2 response"); 1616 result = SASL_BADAUTH; 1617 } 1618 } 1619 } 1620 1621 _plug_free_secret(sparams->utils, &password); 1622 1623 if (result != SASL_OK) goto cleanup; 1624 } 1625 else { 1626 /* proxy the response */ 1627 result = smb_session_setup(sparams->utils, text, authid, domain, 1628 lm_resp, lm_resp_len, nt_resp, nt_resp_len); 1629 if (result != SASL_OK) goto cleanup; 1630 1631 result = sparams->canon_user(sparams->utils->conn, authid, authid_len, 1632 SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams); 1633 if (result != SASL_OK) goto cleanup; 1634 } 1635 1636 /* set oparams */ 1637 oparams->doneflag = 1; 1638 oparams->mech_ssf = 0; 1639 oparams->maxoutbuf = 0; 1640 oparams->encode_context = NULL; 1641 oparams->encode = NULL; 1642 oparams->decode_context = NULL; 1643 oparams->decode = NULL; 1644 oparams->param_version = 0; 1645 1646 result = SASL_OK; 1647 1648 cleanup: 1649 if (lm_resp) sparams->utils->free(lm_resp); 1650 if (nt_resp) sparams->utils->free(nt_resp); 1651 if (domain) sparams->utils->free(domain); 1652 if (authid) sparams->utils->free(authid); 1653 1654 return result; 1655} 1656 1657static int ntlm_server_mech_step(void *conn_context, 1658 sasl_server_params_t *sparams, 1659 const char *clientin, 1660 unsigned clientinlen, 1661 const char **serverout, 1662 unsigned *serveroutlen, 1663 sasl_out_params_t *oparams) 1664{ 1665 server_context_t *text = (server_context_t *) conn_context; 1666 1667 *serverout = NULL; 1668 *serveroutlen = 0; 1669 1670 sparams->utils->log(NULL, SASL_LOG_DEBUG, 1671 "NTLM server step %d\n", text->state); 1672 1673 switch (text->state) { 1674 1675 case 1: 1676 return ntlm_server_mech_step1(text, sparams, clientin, clientinlen, 1677 serverout, serveroutlen, oparams); 1678 1679 case 2: 1680 return ntlm_server_mech_step2(text, sparams, clientin, clientinlen, 1681 serverout, serveroutlen, oparams); 1682 1683 default: 1684 sparams->utils->log(NULL, SASL_LOG_ERR, 1685 "Invalid NTLM server step %d\n", text->state); 1686 return SASL_FAIL; 1687 } 1688 1689 return SASL_FAIL; /* should never get here */ 1690} 1691 1692static void ntlm_server_mech_dispose(void *conn_context, 1693 const sasl_utils_t *utils) 1694{ 1695 server_context_t *text = (server_context_t *) conn_context; 1696 1697 if (!text) return; 1698 1699 if (text->out_buf) utils->free(text->out_buf); 1700 if (text->sock != -1) closesocket(text->sock); 1701 1702 utils->free(text); 1703} 1704 1705static sasl_server_plug_t ntlm_server_plugins[] = 1706{ 1707 { 1708 "NTLM", /* mech_name */ 1709 0, /* max_ssf */ 1710 SASL_SEC_NOPLAINTEXT 1711 | SASL_SEC_NOANONYMOUS, /* security_flags */ 1712 SASL_FEAT_WANT_CLIENT_FIRST, /* features */ 1713 NULL, /* glob_context */ 1714 &ntlm_server_mech_new, /* mech_new */ 1715 &ntlm_server_mech_step, /* mech_step */ 1716 &ntlm_server_mech_dispose, /* mech_dispose */ 1717 NULL, /* mech_free */ 1718 NULL, /* setpass */ 1719 NULL, /* user_query */ 1720 NULL, /* idle */ 1721 NULL, /* mech_avail */ 1722 NULL /* spare */ 1723 } 1724}; 1725 1726int ntlm_server_plug_init(sasl_utils_t *utils, 1727 int maxversion, 1728 int *out_version, 1729 sasl_server_plug_t **pluglist, 1730 int *plugcount) 1731{ 1732 if (maxversion < SASL_SERVER_PLUG_VERSION) { 1733 SETERROR(utils, "NTLM version mismatch"); 1734 return SASL_BADVERS; 1735 } 1736 1737 *out_version = SASL_SERVER_PLUG_VERSION; 1738 *pluglist = ntlm_server_plugins; 1739 *plugcount = 1; 1740 1741 return SASL_OK; 1742} 1743 1744/***************************** Client Section *****************************/ 1745 1746typedef struct client_context { 1747 int state; 1748 1749 /* per-step mem management */ 1750 char *out_buf; 1751 unsigned out_buf_len; 1752 1753} client_context_t; 1754 1755/* 1756 * Create a client request (type 1) consisting of: 1757 * 1758 * signature (8 bytes) 1759 * message type (uint32) 1760 * flags (uint32) 1761 * domain (buffer) 1762 * workstation (buffer) 1763 * data 1764 */ 1765static int create_request(const sasl_utils_t *utils, 1766 char **buf, unsigned *buflen, 1767 const char *domain, const char *wkstn, 1768 unsigned *outlen) 1769{ 1770 uint32 flags = ( NTLM_USE_UNICODE | NTLM_USE_ASCII | 1771 NTLM_ASK_TARGET | NTLM_AUTH_NTLM ); 1772 uint32 offset = NTLM_TYPE1_DATA_OFFSET; 1773 u_char *base; 1774 1775 *outlen = offset + xstrlen(domain) + xstrlen(wkstn); 1776 if (_plug_buf_alloc(utils, buf, buflen, *outlen) != SASL_OK) { 1777 SETERROR(utils, "cannot allocate NTLM request"); 1778 return SASL_NOMEM; 1779 } 1780 1781 base = (u_char *)*buf; 1782 memset(base, 0, *outlen); 1783 memcpy(base + NTLM_SIG_OFFSET, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE)); 1784 htoil(base + NTLM_TYPE_OFFSET, NTLM_TYPE_REQUEST); 1785 htoil(base + NTLM_TYPE1_FLAGS_OFFSET, flags); 1786 load_buffer(base + NTLM_TYPE1_DOMAIN_OFFSET, 1787 domain, (uint16) xstrlen(domain), 0, base, &offset); 1788 load_buffer(base + NTLM_TYPE1_WORKSTN_OFFSET, 1789 wkstn, (uint16) xstrlen(wkstn), 0, base, &offset); 1790 1791 return SASL_OK; 1792} 1793 1794/* 1795 * Create a client response (type 3) consisting of: 1796 * 1797 * signature (8 bytes) 1798 * message type (uint32) 1799 * LM/LMv2 response (buffer) 1800 * NTLM/NTLMv2 response (buffer) 1801 * domain (buffer) 1802 * user name (buffer) 1803 * workstation (buffer) 1804 * session key (buffer) 1805 * flags (uint32) 1806 * data 1807 */ 1808static int create_response(const sasl_utils_t *utils, 1809 char **buf, unsigned *buflen, 1810 const u_char *lm_resp, const u_char *nt_resp, 1811 const char *domain, const char *user, 1812 const char *wkstn, const u_char *key, 1813 uint32 flags, unsigned *outlen) 1814{ 1815 uint32 offset = NTLM_TYPE3_DATA_OFFSET; 1816 u_char *base; 1817 1818 if (!lm_resp && !nt_resp) { 1819 SETERROR(utils, "need at least one NT/LM response"); 1820 return SASL_FAIL; 1821 } 1822 1823 *outlen = offset + (flags & NTLM_USE_UNICODE ? 2 : 1) * 1824 (xstrlen(domain) + xstrlen(user) + xstrlen(wkstn)); 1825 if (lm_resp) *outlen += NTLM_RESP_LENGTH; 1826 if (nt_resp) *outlen += NTLM_RESP_LENGTH; 1827 if (key) *outlen += NTLM_SESSKEY_LENGTH; 1828 1829 if (_plug_buf_alloc(utils, buf, buflen, *outlen) != SASL_OK) { 1830 SETERROR(utils, "cannot allocate NTLM response"); 1831 return SASL_NOMEM; 1832 } 1833 1834 base = (u_char *)*buf; 1835 memset(base, 0, *outlen); 1836 memcpy(base + NTLM_SIG_OFFSET, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE)); 1837 htoil(base + NTLM_TYPE_OFFSET, NTLM_TYPE_RESPONSE); 1838 load_buffer(base + NTLM_TYPE3_LMRESP_OFFSET, 1839 lm_resp, lm_resp ? NTLM_RESP_LENGTH : 0, 0, base, &offset); 1840 load_buffer(base + NTLM_TYPE3_NTRESP_OFFSET, 1841 nt_resp, nt_resp ? NTLM_RESP_LENGTH : 0, 0, base, &offset); 1842 load_buffer(base + NTLM_TYPE3_DOMAIN_OFFSET, 1843 ucase(domain, 0), (uint16) xstrlen(domain), flags & NTLM_USE_UNICODE, 1844 base, &offset); 1845 load_buffer(base + NTLM_TYPE3_USER_OFFSET, 1846 user, (uint16) xstrlen(user), flags & NTLM_USE_UNICODE, base, &offset); 1847 load_buffer(base + NTLM_TYPE3_WORKSTN_OFFSET, 1848 ucase(wkstn, 0), (uint16) xstrlen(wkstn), flags & NTLM_USE_UNICODE, 1849 base, &offset); 1850 load_buffer(base + NTLM_TYPE3_SESSIONKEY_OFFSET, 1851 key, key ? NTLM_SESSKEY_LENGTH : 0, 0, base, &offset); 1852 htoil(base + NTLM_TYPE3_FLAGS_OFFSET, flags); 1853 1854 return SASL_OK; 1855} 1856 1857static int ntlm_client_mech_new(void *glob_context __attribute__((unused)), 1858 sasl_client_params_t *params, 1859 void **conn_context) 1860{ 1861 client_context_t *text; 1862 1863 /* holds state are in */ 1864 text = params->utils->malloc(sizeof(client_context_t)); 1865 if (text == NULL) { 1866 MEMERROR( params->utils ); 1867 return SASL_NOMEM; 1868 } 1869 1870 memset(text, 0, sizeof(client_context_t)); 1871 1872 text->state = 1; 1873 1874 *conn_context = text; 1875 1876 return SASL_OK; 1877} 1878 1879static int ntlm_client_mech_step1(client_context_t *text, 1880 sasl_client_params_t *params, 1881 const char *serverin __attribute__((unused)), 1882 unsigned serverinlen __attribute__((unused)), 1883 sasl_interact_t **prompt_need __attribute__((unused)), 1884 const char **clientout, 1885 unsigned *clientoutlen, 1886 sasl_out_params_t *oparams __attribute__((unused))) 1887{ 1888 int result; 1889 1890 /* check if sec layer strong enough */ 1891 if (params->props.min_ssf > params->external_ssf) { 1892 SETERROR(params->utils, "SSF requested of NTLM plugin"); 1893 return SASL_TOOWEAK; 1894 } 1895 1896 /* we don't care about domain or wkstn */ 1897 result = create_request(params->utils, &text->out_buf, &text->out_buf_len, 1898 NULL, NULL, clientoutlen); 1899 if (result != SASL_OK) return result; 1900 1901 *clientout = text->out_buf; 1902 1903 text->state = 2; 1904 1905 return SASL_CONTINUE; 1906} 1907 1908static int ntlm_client_mech_step2(client_context_t *text, 1909 sasl_client_params_t *params, 1910 const char *serverin, 1911 unsigned serverinlen, 1912 sasl_interact_t **prompt_need, 1913 const char **clientout, 1914 unsigned *clientoutlen, 1915 sasl_out_params_t *oparams) 1916{ 1917 const char *authid = NULL; 1918 sasl_secret_t *password = NULL; 1919 unsigned int free_password; /* set if we need to free password */ 1920 char *domain = NULL; 1921 int auth_result = SASL_OK; 1922 int pass_result = SASL_OK; 1923 uint32 flags = 0; 1924 unsigned char hash[NTLM_HASH_LENGTH]; 1925 unsigned char resp[NTLM_RESP_LENGTH], *lm_resp = NULL, *nt_resp = NULL; 1926 int result; 1927 const char *sendv2; 1928 1929 if (!serverin || serverinlen < NTLM_TYPE2_MINSIZE || 1930 memcmp(serverin, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE)) || 1931 itohl(serverin + NTLM_TYPE_OFFSET) != NTLM_TYPE_CHALLENGE) { 1932 SETERROR(params->utils, "server didn't issue valid NTLM challenge"); 1933 return SASL_BADPROT; 1934 } 1935 1936 /* try to get the authid */ 1937 if (oparams->authid == NULL) { 1938 auth_result = _plug_get_authid(params->utils, &authid, prompt_need); 1939 1940 if ((auth_result != SASL_OK) && (auth_result != SASL_INTERACT)) 1941 return auth_result; 1942 } 1943 1944 /* try to get the password */ 1945 if (password == NULL) { 1946 pass_result = _plug_get_password(params->utils, &password, 1947 &free_password, prompt_need); 1948 1949 if ((pass_result != SASL_OK) && (pass_result != SASL_INTERACT)) 1950 return pass_result; 1951 } 1952 1953 /* free prompts we got */ 1954 if (prompt_need && *prompt_need) { 1955 params->utils->free(*prompt_need); 1956 *prompt_need = NULL; 1957 } 1958 1959 /* if there are prompts not filled in */ 1960 if ((auth_result == SASL_INTERACT) || (pass_result == SASL_INTERACT)) { 1961 /* make the prompt list */ 1962 result = 1963 _plug_make_prompts(params->utils, prompt_need, 1964 NULL, NULL, 1965 auth_result == SASL_INTERACT ? 1966 "Please enter your authentication name" : NULL, 1967 NULL, 1968 pass_result == SASL_INTERACT ? 1969 "Please enter your password" : NULL, NULL, 1970 NULL, NULL, NULL, 1971 NULL, NULL, NULL); 1972 if (result != SASL_OK) goto cleanup; 1973 1974 return SASL_INTERACT; 1975 } 1976 1977 result = params->canon_user(params->utils->conn, authid, 0, 1978 SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams); 1979 if (result != SASL_OK) goto cleanup; 1980 1981 flags = itohl(serverin + NTLM_TYPE2_FLAGS_OFFSET); 1982 params->utils->log(NULL, SASL_LOG_DEBUG, 1983 "server flags: %x", flags); 1984 1985 flags &= NTLM_FLAGS_MASK; /* mask off the bits we don't support */ 1986 1987 result = unload_buffer(params->utils, (const u_char *)serverin + NTLM_TYPE2_TARGET_OFFSET, 1988 (u_char **) &domain, NULL, 1989 flags & NTLM_USE_UNICODE, 1990 (u_char *) serverin, serverinlen); 1991 if (result != SASL_OK) goto cleanup; 1992 params->utils->log(NULL, SASL_LOG_DEBUG, 1993 "server domain: %s", domain); 1994 1995 /* should we send a NTLMv2 response? */ 1996 params->utils->getopt(params->utils->getopt_context, 1997 "NTLM", "ntlm_v2", &sendv2, NULL); 1998 if (sendv2 && 1999 (*sendv2 == '1' || *sendv2 == 'y' || 2000 (*sendv2 == 'o' && *sendv2 == 'n') || *sendv2 == 't')) { 2001 2002 /* put the cnonce in place after the LMv2 HMAC */ 2003 char *cnonce = (char *)(resp + MD5_DIGEST_LENGTH); 2004 2005 params->utils->log(NULL, SASL_LOG_DEBUG, 2006 "calculating LMv2 response"); 2007 2008 params->utils->rand(params->utils->rpool, cnonce, NTLM_NONCE_LENGTH); 2009 2010 V2(resp, password, oparams->authid, domain, 2011 serverin + NTLM_TYPE2_CHALLENGE_OFFSET, cnonce, NTLM_NONCE_LENGTH, 2012 params->utils, &text->out_buf, &text->out_buf_len, &result); 2013 2014 lm_resp = resp; 2015 } 2016 else if (flags & NTLM_AUTH_NTLM) { 2017 params->utils->log(NULL, SASL_LOG_DEBUG, 2018 "calculating NT response"); 2019 P24(resp, P21(hash, password, P16_nt, params->utils, 2020 &text->out_buf, &text->out_buf_len, &result), 2021 (unsigned char *) serverin + NTLM_TYPE2_CHALLENGE_OFFSET); 2022 nt_resp = resp; 2023 } 2024 else { 2025 params->utils->log(NULL, SASL_LOG_DEBUG, 2026 "calculating LM response"); 2027 P24(resp, P21(hash, password, P16_lm, params->utils, 2028 &text->out_buf, &text->out_buf_len, &result), 2029 (unsigned char *) serverin + NTLM_TYPE2_CHALLENGE_OFFSET); 2030 lm_resp = resp; 2031 } 2032 if (result != SASL_OK) goto cleanup; 2033 2034 /* we don't care about workstn or session key */ 2035 result = create_response(params->utils, &text->out_buf, &text->out_buf_len, 2036 lm_resp, nt_resp, domain, oparams->authid, 2037 NULL, NULL, flags, clientoutlen); 2038 if (result != SASL_OK) goto cleanup; 2039 2040 *clientout = text->out_buf; 2041 2042 /* set oparams */ 2043 oparams->doneflag = 1; 2044 oparams->mech_ssf = 0; 2045 oparams->maxoutbuf = 0; 2046 oparams->encode_context = NULL; 2047 oparams->encode = NULL; 2048 oparams->decode_context = NULL; 2049 oparams->decode = NULL; 2050 oparams->param_version = 0; 2051 2052 result = SASL_OK; 2053 2054 cleanup: 2055 if (domain) params->utils->free(domain); 2056 if (free_password) _plug_free_secret(params->utils, &password); 2057 2058 return result; 2059} 2060 2061static int ntlm_client_mech_step(void *conn_context, 2062 sasl_client_params_t *params, 2063 const char *serverin, 2064 unsigned serverinlen, 2065 sasl_interact_t **prompt_need, 2066 const char **clientout, 2067 unsigned *clientoutlen, 2068 sasl_out_params_t *oparams) 2069{ 2070 client_context_t *text = (client_context_t *) conn_context; 2071 2072 *clientout = NULL; 2073 *clientoutlen = 0; 2074 2075 params->utils->log(NULL, SASL_LOG_DEBUG, 2076 "NTLM client step %d\n", text->state); 2077 2078 switch (text->state) { 2079 2080 case 1: 2081 return ntlm_client_mech_step1(text, params, serverin, serverinlen, 2082 prompt_need, clientout, clientoutlen, 2083 oparams); 2084 2085 case 2: 2086 return ntlm_client_mech_step2(text, params, serverin, serverinlen, 2087 prompt_need, clientout, clientoutlen, 2088 oparams); 2089 2090 default: 2091 params->utils->log(NULL, SASL_LOG_ERR, 2092 "Invalid NTLM client step %d\n", text->state); 2093 return SASL_FAIL; 2094 } 2095 2096 return SASL_FAIL; /* should never get here */ 2097} 2098 2099static void ntlm_client_mech_dispose(void *conn_context, 2100 const sasl_utils_t *utils) 2101{ 2102 client_context_t *text = (client_context_t *) conn_context; 2103 2104 if (!text) return; 2105 2106 if (text->out_buf) utils->free(text->out_buf); 2107 2108 utils->free(text); 2109} 2110 2111static sasl_client_plug_t ntlm_client_plugins[] = 2112{ 2113 { 2114 "NTLM", /* mech_name */ 2115 0, /* max_ssf */ 2116 SASL_SEC_NOPLAINTEXT 2117 | SASL_SEC_NOANONYMOUS, /* security_flags */ 2118 SASL_FEAT_WANT_CLIENT_FIRST, /* features */ 2119 NULL, /* required_prompts */ 2120 NULL, /* glob_context */ 2121 &ntlm_client_mech_new, /* mech_new */ 2122 &ntlm_client_mech_step, /* mech_step */ 2123 &ntlm_client_mech_dispose, /* mech_dispose */ 2124 NULL, /* mech_free */ 2125 NULL, /* idle */ 2126 NULL, /* spare */ 2127 NULL /* spare */ 2128 } 2129}; 2130 2131int ntlm_client_plug_init(sasl_utils_t *utils, 2132 int maxversion, 2133 int *out_version, 2134 sasl_client_plug_t **pluglist, 2135 int *plugcount) 2136{ 2137 if (maxversion < SASL_CLIENT_PLUG_VERSION) { 2138 SETERROR(utils, "NTLM version mismatch"); 2139 return SASL_BADVERS; 2140 } 2141 2142 *out_version = SASL_CLIENT_PLUG_VERSION; 2143 *pluglist = ntlm_client_plugins; 2144 *plugcount = 1; 2145 2146 return SASL_OK; 2147} 2148