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