15331Samw /*
25331Samw * CDDL HEADER START
35331Samw *
45331Samw * The contents of this file are subject to the terms of the
55331Samw * Common Development and Distribution License (the "License").
65331Samw * You may not use this file except in compliance with the License.
75331Samw *
85331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95331Samw * or http://www.opensolaris.org/os/licensing.
105331Samw * See the License for the specific language governing permissions
115331Samw * and limitations under the License.
125331Samw *
135331Samw * When distributing Covered Code, include this CDDL HEADER in each
145331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155331Samw * If applicable, add the following below this CDDL HEADER, with the
165331Samw * fields enclosed by brackets "[]" replaced with your own identifying
175331Samw * information: Portions Copyright [yyyy] [name of copyright owner]
185331Samw *
195331Samw * CDDL HEADER END
205331Samw */
215331Samw /*
229832Samw@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
235331Samw * Use is subject to license terms.
245331Samw */
255331Samw
265331Samw #include <strings.h>
275331Samw #include <stdlib.h>
28*10966SJordan.Brown@Sun.COM #include <smbsrv/string.h>
295331Samw #include <smbsrv/libsmb.h>
305331Samw
315331Samw extern void randomize(char *data, unsigned len);
325331Samw static uint64_t unix_micro_to_nt_time(struct timeval *unix_time);
335331Samw
345331Samw /*
355331Samw * smb_auth_qnd_unicode
365331Samw *
375331Samw * Quick and dirty unicode conversion!
385331Samw * Returns the length of dst in bytes.
395331Samw */
405331Samw int
smb_auth_qnd_unicode(smb_wchar_t * dst,const char * src,int length)41*10966SJordan.Brown@Sun.COM smb_auth_qnd_unicode(smb_wchar_t *dst, const char *src, int length)
425331Samw {
435331Samw int i;
44*10966SJordan.Brown@Sun.COM unsigned int count;
45*10966SJordan.Brown@Sun.COM smb_wchar_t new_char;
465331Samw
47*10966SJordan.Brown@Sun.COM if ((count = oemtoucs(dst, src, length, OEM_CPG_1252)) == 0) {
485331Samw for (i = 0; i < length; ++i) {
49*10966SJordan.Brown@Sun.COM new_char = (smb_wchar_t)src[i] & 0xff;
505331Samw dst[i] = LE_IN16(&new_char);
515331Samw }
525331Samw dst[i] = 0;
535331Samw count = length;
545331Samw }
555331Samw
56*10966SJordan.Brown@Sun.COM return (count * sizeof (smb_wchar_t));
575331Samw }
585331Samw
595331Samw /*
605331Samw * smb_auth_lmupr
615331Samw *
625331Samw * Converts the given LM password to all uppercase.
635331Samw * The standard strupr cannot
645331Samw * be used here because lm_pwd doesn't have to be
655331Samw * nul terminated.
665331Samw */
675331Samw static void
smb_auth_lmupr(unsigned char * lm_pwd)685331Samw smb_auth_lmupr(unsigned char *lm_pwd)
695331Samw {
705331Samw unsigned char *p = lm_pwd;
715331Samw int i;
725331Samw
735331Samw for (i = 0; (*p) && (i < SMBAUTH_LM_PWD_SZ); i++) {
74*10966SJordan.Brown@Sun.COM if (smb_isascii(*p)) {
75*10966SJordan.Brown@Sun.COM *p = smb_toupper(*p);
765331Samw p++;
775331Samw }
785331Samw }
795331Samw }
805331Samw
815331Samw /*
825331Samw * smb_auth_lm_hash
835331Samw *
845331Samw * Source: Implementing CIFS (Chris Hertel)
855331Samw *
865331Samw * 1. The password, as entered by user, is either padded with nulls
875331Samw * or trimmed to 14 bytes.
885331Samw * . Note that the 14-byte result string is not handled as a
895331Samw * nul-terminated string.
905331Samw * . The given password is OEM not Unicode
915331Samw *
925331Samw * 2. The 14-byte password is converted to all uppercase
935331Samw *
945331Samw * 3. The result is used as key to encrypt the KGS magic string to
955331Samw * make a 16-byte hash.
965331Samw */
975331Samw int
smb_auth_lm_hash(const char * password,unsigned char * lm_hash)989832Samw@Sun.COM smb_auth_lm_hash(const char *password, unsigned char *lm_hash)
995331Samw {
1005331Samw unsigned char lm_pwd[SMBAUTH_LM_PWD_SZ];
1015331Samw
1025331Samw bzero((void *)lm_pwd, SMBAUTH_LM_PWD_SZ);
1035331Samw (void) strncpy((char *)lm_pwd, password, SMBAUTH_LM_PWD_SZ);
1045331Samw smb_auth_lmupr(lm_pwd);
1055331Samw
1065331Samw return (smb_auth_DES(lm_hash, SMBAUTH_HASH_SZ, lm_pwd,
1075331Samw SMBAUTH_LM_PWD_SZ, (unsigned char *)SMBAUTH_LM_MAGIC_STR,
1085331Samw sizeof (SMBAUTH_LM_MAGIC_STR)));
1095331Samw }
1105331Samw
1115331Samw /*
1125331Samw * smb_auth_lm_response
1135331Samw *
1145331Samw * Create a LM response from the given LM hash and challenge.
1155331Samw *
1165331Samw * Returns SMBAUTH_FAILURE if any problems occur, SMBAUTH_SUCCESS if
1175331Samw * all goes well.
1185331Samw */
1195331Samw static int
smb_auth_lm_response(unsigned char * hash,unsigned char * challenge,int clen,unsigned char * lm_rsp)1205331Samw smb_auth_lm_response(unsigned char *hash,
1215331Samw unsigned char *challenge, int clen,
1225331Samw unsigned char *lm_rsp)
1235331Samw {
1245331Samw unsigned char S21[21];
1255331Samw
1265331Samw /*
1275331Samw * 14-byte LM Hash should be padded with 5 nul bytes to create
1285331Samw * a 21-byte string to be used in producing LM response
1295331Samw */
1305331Samw bzero(&S21[SMBAUTH_HASH_SZ], 5);
1315331Samw bcopy(hash, S21, SMBAUTH_HASH_SZ);
1325331Samw
1335331Samw /* padded LM Hash -> LM Response */
1345331Samw return (smb_auth_DES(lm_rsp, SMBAUTH_LM_RESP_SZ, S21, 21,
1355331Samw challenge, clen));
1365331Samw }
1375331Samw
1385331Samw /*
1395331Samw * smb_auth_ntlm_hash
1405331Samw *
1415331Samw * Make NTLM Hash (using MD4) from the given password.
1425331Samw * The result will contain a 16-byte NTLM hash.
1435331Samw */
1445331Samw int
smb_auth_ntlm_hash(const char * password,unsigned char * hash)1459832Samw@Sun.COM smb_auth_ntlm_hash(const char *password, unsigned char *hash)
1465331Samw {
147*10966SJordan.Brown@Sun.COM smb_wchar_t *unicode_password;
1485331Samw int length;
1495331Samw int rc;
1505331Samw
1515331Samw if (password == NULL || hash == NULL)
1525331Samw return (SMBAUTH_FAILURE);
1535331Samw
1545331Samw length = strlen(password);
155*10966SJordan.Brown@Sun.COM unicode_password = (smb_wchar_t *)
156*10966SJordan.Brown@Sun.COM malloc((length + 1) * sizeof (smb_wchar_t));
1575331Samw
1585331Samw if (unicode_password == NULL)
1595331Samw return (SMBAUTH_FAILURE);
1605331Samw
1615331Samw length = smb_auth_qnd_unicode(unicode_password, password, length);
1625331Samw rc = smb_auth_md4(hash, (unsigned char *)unicode_password, length);
1635331Samw
1645331Samw free(unicode_password);
1655331Samw return (rc);
1665331Samw }
1675331Samw
1685331Samw /*
1695331Samw * smb_auth_ntlm_response
1705331Samw *
1715331Samw * Make LM/NTLM response from the given LM/NTLM Hash and given
1725331Samw * challenge.
1735331Samw */
1745331Samw static int
smb_auth_ntlm_response(unsigned char * hash,unsigned char * challenge,int clen,unsigned char * ntlm_rsp)1755331Samw smb_auth_ntlm_response(unsigned char *hash,
1765331Samw unsigned char *challenge, int clen,
1775331Samw unsigned char *ntlm_rsp)
1785331Samw {
1795331Samw unsigned char S21[21];
1805331Samw
1815331Samw bcopy(hash, S21, SMBAUTH_HASH_SZ);
1825331Samw bzero(&S21[SMBAUTH_HASH_SZ], 5);
1835331Samw if (smb_auth_DES((unsigned char *)ntlm_rsp, SMBAUTH_LM_RESP_SZ,
1845331Samw S21, 21, challenge, clen) == SMBAUTH_FAILURE)
1855331Samw return (0);
1865331Samw return (SMBAUTH_LM_RESP_SZ);
1875331Samw }
1885331Samw
1895331Samw /*
1905331Samw * smb_auth_gen_data_blob
1915331Samw *
1925331Samw * Fill the NTLMv2 data blob structure with information as described in
1935331Samw * "Implementing CIFS, The Common Internet File System". (pg. 282)
1945331Samw */
1955331Samw static void
smb_auth_gen_data_blob(smb_auth_data_blob_t * blob,char * ntdomain)1965331Samw smb_auth_gen_data_blob(smb_auth_data_blob_t *blob, char *ntdomain)
1975331Samw {
1985331Samw struct timeval now;
1995331Samw
2005331Samw (void) memset(blob->ndb_signature, 1, 2);
2015331Samw (void) memset(&blob->ndb_signature[2], 0, 2);
2025331Samw (void) memset(blob->ndb_reserved, 0, sizeof (blob->ndb_reserved));
2035331Samw
2045331Samw (void) gettimeofday(&now, 0);
2055331Samw blob->ndb_timestamp = unix_micro_to_nt_time(&now);
2065331Samw randomize((char *)blob->ndb_clnt_challenge,
2075331Samw SMBAUTH_V2_CLNT_CHALLENGE_SZ);
2085331Samw (void) memset(blob->ndb_unknown, 0, sizeof (blob->ndb_unknown));
2095331Samw blob->ndb_names[0].nne_len = smb_auth_qnd_unicode(
2105331Samw blob->ndb_names[0].nne_name, ntdomain, strlen(ntdomain));
2115331Samw blob->ndb_names[0].nne_type = SMBAUTH_NAME_TYPE_DOMAIN_NETBIOS;
2125331Samw blob->ndb_names[1].nne_len = 0;
2135331Samw blob->ndb_names[1].nne_type = SMBAUTH_NAME_TYPE_LIST_END;
2145331Samw *blob->ndb_names[1].nne_name = 0;
2155331Samw (void) memset(blob->ndb_unknown2, 0, sizeof (blob->ndb_unknown2));
2165331Samw }
2175331Samw
2185331Samw /*
2195331Samw * smb_auth_memcpy
2205331Samw *
2215331Samw * It increments the pointer to the destination buffer for the easy of
2225331Samw * concatenation.
2235331Samw */
2245331Samw static void
smb_auth_memcpy(unsigned char ** dstbuf,unsigned char * srcbuf,int srcbuf_len)2255331Samw smb_auth_memcpy(unsigned char **dstbuf,
2265331Samw unsigned char *srcbuf,
2275331Samw int srcbuf_len)
2285331Samw {
2295331Samw (void) memcpy(*dstbuf, srcbuf, srcbuf_len);
2305331Samw *dstbuf += srcbuf_len;
2315331Samw }
2325331Samw
2335331Samw /*
2345331Samw * smb_auth_blob_to_string
2355331Samw *
2365331Samw * Prepare the data blob string which will be used in NTLMv2 response
2375331Samw * generation.
2385331Samw *
2395331Samw * Assumption: Caller must allocate big enough buffer to prevent buffer
2405331Samw * overrun.
2415331Samw *
2425331Samw * Returns the len of the data blob string.
2435331Samw */
2445331Samw static int
smb_auth_blob_to_string(smb_auth_data_blob_t * blob,unsigned char * data_blob)2455331Samw smb_auth_blob_to_string(smb_auth_data_blob_t *blob, unsigned char *data_blob)
2465331Samw {
2475331Samw unsigned char *bufp = data_blob;
2485331Samw
2495331Samw smb_auth_memcpy(&bufp, blob->ndb_signature,
2505331Samw sizeof (blob->ndb_signature));
2515331Samw smb_auth_memcpy(&bufp, blob->ndb_reserved,
2525331Samw sizeof (blob->ndb_reserved));
2535331Samw smb_auth_memcpy(&bufp, (unsigned char *)&blob->ndb_timestamp,
2545331Samw sizeof (blob->ndb_timestamp));
2555331Samw smb_auth_memcpy(&bufp, blob->ndb_clnt_challenge,
2565331Samw SMBAUTH_V2_CLNT_CHALLENGE_SZ);
2575331Samw smb_auth_memcpy(&bufp, blob->ndb_unknown, sizeof (blob->ndb_unknown));
2585331Samw smb_auth_memcpy(&bufp, (unsigned char *)&blob->ndb_names[0].nne_type,
2595331Samw sizeof (blob->ndb_names[0].nne_type));
2605331Samw smb_auth_memcpy(&bufp, (unsigned char *)&blob->ndb_names[0].nne_len,
2615331Samw sizeof (blob->ndb_names[0].nne_len));
2625331Samw smb_auth_memcpy(&bufp, (unsigned char *)blob->ndb_names[0].nne_name,
2635331Samw blob->ndb_names[0].nne_len);
2645331Samw smb_auth_memcpy(&bufp, (unsigned char *)&blob->ndb_names[1].nne_type,
2655331Samw sizeof (blob->ndb_names[1].nne_type));
2665331Samw smb_auth_memcpy(&bufp, (unsigned char *)&blob->ndb_names[1].nne_len,
2675331Samw sizeof (blob->ndb_names[1].nne_len));
2685331Samw smb_auth_memcpy(&bufp, blob->ndb_unknown2, sizeof (blob->ndb_unknown2));
2695331Samw
2705331Samw /*LINTED E_PTRDIFF_OVERFLOW*/
2715331Samw return (bufp - data_blob);
2725331Samw }
2735331Samw
2745331Samw /*
2755331Samw * smb_auth_ntlmv2_hash
2765331Samw *
2775331Samw * The NTLM v2 hash will be created from the given NTLM hash, username,
2785331Samw * and the NETBIOS name of the domain.
2795331Samw *
2805331Samw * The NTLMv2 hash will be returned via the ntlmv2_hash parameter which
2815331Samw * will be used in the calculation of the NTLMv2 and LMv2 responses.
2825331Samw */
2836600Sas200622 int
smb_auth_ntlmv2_hash(unsigned char * ntlm_hash,char * username,char * ntdomain,unsigned char * ntlmv2_hash)2845331Samw smb_auth_ntlmv2_hash(unsigned char *ntlm_hash,
2857348SJose.Borrego@Sun.COM char *username,
2867348SJose.Borrego@Sun.COM char *ntdomain,
2877348SJose.Borrego@Sun.COM unsigned char *ntlmv2_hash)
2885331Samw {
289*10966SJordan.Brown@Sun.COM smb_wchar_t *data;
2905331Samw int data_len;
2915331Samw unsigned char *buf;
2925331Samw int rc;
2935331Samw
2945331Samw if (username == NULL || ntdomain == NULL)
2955331Samw return (SMBAUTH_FAILURE);
2965331Samw
297*10966SJordan.Brown@Sun.COM (void) smb_strupr(username);
2985331Samw
2995331Samw data_len = strlen(username) + strlen(ntdomain);
3005331Samw buf = (unsigned char *)malloc((data_len + 1) * sizeof (char));
3015331Samw if (buf == NULL)
3025331Samw return (SMBAUTH_FAILURE);
3035331Samw
3045331Samw (void) snprintf((char *)buf, data_len + 1, "%s%s", username, ntdomain);
305*10966SJordan.Brown@Sun.COM data = (smb_wchar_t *)malloc((data_len + 1) * sizeof (smb_wchar_t));
3065331Samw if (data == NULL) {
3075331Samw free(buf);
3085331Samw return (SMBAUTH_FAILURE);
3095331Samw }
3105331Samw
3115331Samw data_len = smb_auth_qnd_unicode(data, (char *)buf, data_len);
3125331Samw rc = SMBAUTH_HMACT64((unsigned char *)data, data_len, ntlm_hash,
3135331Samw SMBAUTH_HASH_SZ, ntlmv2_hash);
3145331Samw
3155331Samw free(buf);
3165331Samw free(data);
3175331Samw return (rc);
3185331Samw }
3195331Samw
3205331Samw /*
3215331Samw * smb_auth_v2_response
3225331Samw *
3235331Samw * Caculates either the LMv2 or NTLMv2 response.
3245331Samw *
3255331Samw * Same algorithm is used for calculating both LMv2 or NTLMv2 responses.
3265331Samw * This routine will return NTLMv2 response if the data blob information
3275331Samw * is passed in as the clnt_data. Otherwise, it will return LMv2 response
3285331Samw * with the 8-byte client challenge(a.k.a blip) as the clnt_data.
3295331Samw *
3305331Samw * (LM/NTLM)v2 response is the hmac-md5 hash of the specified data
3315331Samw * (server challenge + NTLMv2 data blob or LMv2 client challenge)
3325331Samw * using the NTLMv2 hash as the key.
3335331Samw *
3345331Samw * Returns the size of the corresponding v2 response upon success.
3355331Samw * Otherwise, returns -1 on error.
3365331Samw */
3375331Samw static int
smb_auth_v2_response(unsigned char * hash,unsigned char * srv_challenge,int slen,unsigned char * clnt_data,int clen,unsigned char * v2_rsp)3385331Samw smb_auth_v2_response(
3395331Samw unsigned char *hash,
3405331Samw unsigned char *srv_challenge, int slen,
3415331Samw unsigned char *clnt_data, int clen,
3425331Samw unsigned char *v2_rsp)
3435331Samw {
3445331Samw unsigned char *hmac_data;
3455331Samw
3465331Samw hmac_data = (unsigned char *)malloc((slen + clen) * sizeof (char));
3475331Samw if (!hmac_data) {
3485331Samw return (-1);
3495331Samw }
3505331Samw
3515331Samw (void) memcpy(hmac_data, srv_challenge, slen);
3525331Samw (void) memcpy(&hmac_data[slen], clnt_data, clen);
3535331Samw if (SMBAUTH_HMACT64(hmac_data, slen + clen, (unsigned char *)hash,
3545331Samw SMBAUTH_HASH_SZ, (unsigned char *)v2_rsp) != SMBAUTH_SUCCESS)
3555331Samw return (-1);
3565331Samw (void) memcpy(&v2_rsp[SMBAUTH_HASH_SZ], clnt_data, clen);
3575331Samw
3585331Samw free(hmac_data);
3595331Samw return (SMBAUTH_HASH_SZ + clen);
3605331Samw }
3615331Samw
3625331Samw /*
3635331Samw * smb_auth_set_info
3645331Samw *
3655331Samw * Fill the smb_auth_info instance with either NTLM or NTLMv2 related
3665331Samw * authentication information based on the LMCompatibilityLevel.
3675331Samw *
3685331Samw * If the LMCompatibilityLevel equals 2, the SMB Redirector will perform
3695331Samw * NTLM challenge/response authentication which requires the NTLM hash and
3705331Samw * NTLM response.
3715331Samw *
3725331Samw * If the LMCompatibilityLevel is 3 or above, the SMB Redirector will
3735331Samw * perfrom NTLMv2 challenge/response authenticatoin which requires the
3745331Samw * NTLM hash, NTLMv2 hash, NTLMv2 response and LMv2 response.
3755331Samw *
3765331Samw * Returns -1 on error. Otherwise, returns 0 upon success.
3775331Samw */
3785331Samw int
smb_auth_set_info(char * username,char * password,unsigned char * ntlm_hash,char * domain,unsigned char * srv_challenge_key,int srv_challenge_len,int lmcomp_lvl,smb_auth_info_t * auth)3795331Samw smb_auth_set_info(char *username,
3805331Samw char *password,
3815331Samw unsigned char *ntlm_hash,
3825331Samw char *domain,
3835331Samw unsigned char *srv_challenge_key,
3845331Samw int srv_challenge_len,
3855331Samw int lmcomp_lvl,
3865331Samw smb_auth_info_t *auth)
3875331Samw {
3885331Samw unsigned short blob_len;
3895331Samw unsigned char blob_buf[SMBAUTH_BLOB_MAXLEN];
3905331Samw int rc;
3915772Sas200622 char *uppercase_dom;
3925331Samw
3935331Samw auth->lmcompatibility_lvl = lmcomp_lvl;
3945331Samw if (lmcomp_lvl == 2) {
3955331Samw auth->ci_len = 0;
3965331Samw *auth->ci = 0;
3975331Samw if (!ntlm_hash) {
3985331Samw if (smb_auth_ntlm_hash(password, auth->hash) !=
3995331Samw SMBAUTH_SUCCESS)
4005331Samw return (-1);
4015331Samw } else {
4025331Samw (void) memcpy(auth->hash, ntlm_hash, SMBAUTH_HASH_SZ);
4035331Samw }
4045331Samw
4055331Samw auth->cs_len = smb_auth_ntlm_response(auth->hash,
4065331Samw srv_challenge_key, srv_challenge_len, auth->cs);
4075331Samw } else {
4085331Samw if (!ntlm_hash) {
4095331Samw if (smb_auth_ntlm_hash(password, auth->hash) !=
4105331Samw SMBAUTH_SUCCESS)
4115331Samw return (-1);
4125331Samw } else {
4135331Samw (void) memcpy(auth->hash, ntlm_hash, SMBAUTH_HASH_SZ);
4145331Samw }
4155331Samw
4165772Sas200622 if (!domain)
4175772Sas200622 return (-1);
4185772Sas200622
4195772Sas200622 if ((uppercase_dom = strdup(domain)) == NULL)
4205331Samw return (-1);
4215331Samw
422*10966SJordan.Brown@Sun.COM (void) smb_strupr(uppercase_dom);
4235772Sas200622
4245772Sas200622 if (smb_auth_ntlmv2_hash(auth->hash, username,
4255772Sas200622 uppercase_dom, auth->hash_v2) != SMBAUTH_SUCCESS) {
4265772Sas200622 free(uppercase_dom);
4275772Sas200622 return (-1);
4285772Sas200622 }
4295772Sas200622
4305331Samw /* generate data blob */
4315772Sas200622 smb_auth_gen_data_blob(&auth->data_blob, uppercase_dom);
4325772Sas200622 free(uppercase_dom);
4335331Samw blob_len = smb_auth_blob_to_string(&auth->data_blob, blob_buf);
4345331Samw
4355331Samw /* generate NTLMv2 response */
4365331Samw rc = smb_auth_v2_response(auth->hash_v2, srv_challenge_key,
4375331Samw srv_challenge_len, blob_buf, blob_len, auth->cs);
4385331Samw
4395331Samw if (rc < 0)
4405331Samw return (-1);
4415331Samw
4425331Samw auth->cs_len = rc;
4435331Samw
4445331Samw /* generate LMv2 response */
4455331Samw rc = smb_auth_v2_response(auth->hash_v2, srv_challenge_key,
4465331Samw srv_challenge_len, auth->data_blob.ndb_clnt_challenge,
4475331Samw SMBAUTH_V2_CLNT_CHALLENGE_SZ, auth->ci);
4485331Samw
4495331Samw if (rc < 0)
4505331Samw return (-1);
4515331Samw
4525331Samw auth->ci_len = rc;
4535331Samw }
4545331Samw
4555331Samw return (0);
4565331Samw }
4575331Samw
4585331Samw /*
4595331Samw * smb_auth_gen_session_key
4605331Samw *
4615331Samw * Generate the NTLM user session key if LMCompatibilityLevel is 2 or
4625331Samw * NTLMv2 user session key if LMCompatibilityLevel is 3 or above.
4635331Samw *
4645331Samw * NTLM_Session_Key = MD4(NTLM_Hash);
4655331Samw *
4665331Samw * NTLMv2_Session_Key = HMAC_MD5(NTLMv2Hash, 16, NTLMv2_HMAC, 16)
4675331Samw *
4685331Samw * Prior to calling this function, the auth instance should be set
4695331Samw * via smb_auth_set_info().
4705331Samw *
4715331Samw * Returns the appropriate session key.
4725331Samw */
4735331Samw int
smb_auth_gen_session_key(smb_auth_info_t * auth,unsigned char * session_key)4745331Samw smb_auth_gen_session_key(smb_auth_info_t *auth, unsigned char *session_key)
4755331Samw {
4765331Samw int rc;
4775331Samw
4785331Samw if (auth->lmcompatibility_lvl == 2)
4795331Samw rc = smb_auth_md4(session_key, auth->hash, SMBAUTH_HASH_SZ);
4805331Samw else
4815331Samw rc = SMBAUTH_HMACT64((unsigned char *)auth->cs,
4825331Samw SMBAUTH_HASH_SZ, (unsigned char *)auth->hash_v2,
4835331Samw SMBAUTH_SESSION_KEY_SZ, session_key);
4845331Samw
4855331Samw return (rc);
4865331Samw }
4875331Samw
4885331Samw /* 100's of ns between 1/1/1970 and 1/1/1601 */
4895331Samw #define NT_TIME_BIAS (134774LL * 24LL * 60LL * 60LL * 10000000LL)
4905331Samw
4915331Samw static uint64_t
unix_micro_to_nt_time(struct timeval * unix_time)4925331Samw unix_micro_to_nt_time(struct timeval *unix_time)
4935331Samw {
4945331Samw uint64_t nt_time;
4955331Samw
4965331Samw nt_time = unix_time->tv_sec;
4975331Samw nt_time *= 10000000; /* seconds to 100ns */
4985331Samw nt_time += unix_time->tv_usec * 10;
4995331Samw return (nt_time + NT_TIME_BIAS);
5005331Samw }
5015331Samw
5025331Samw static boolean_t
smb_lm_password_ok(unsigned char * challenge,uint32_t clen,unsigned char * lm_hash,unsigned char * passwd)5035331Samw smb_lm_password_ok(
5045331Samw unsigned char *challenge,
5055331Samw uint32_t clen,
5065331Samw unsigned char *lm_hash,
5075331Samw unsigned char *passwd)
5085331Samw {
5095331Samw unsigned char lm_resp[SMBAUTH_LM_RESP_SZ];
5105331Samw int rc;
5115331Samw
5125331Samw rc = smb_auth_lm_response(lm_hash, challenge, clen, lm_resp);
5135331Samw if (rc != SMBAUTH_SUCCESS)
5145331Samw return (B_FALSE);
5155331Samw
5165331Samw return (bcmp(lm_resp, passwd, SMBAUTH_LM_RESP_SZ) == 0);
5175331Samw }
5185331Samw
5195331Samw static boolean_t
smb_ntlm_password_ok(unsigned char * challenge,uint32_t clen,unsigned char * ntlm_hash,unsigned char * passwd,unsigned char * session_key)5205331Samw smb_ntlm_password_ok(
5215331Samw unsigned char *challenge,
5225331Samw uint32_t clen,
5235331Samw unsigned char *ntlm_hash,
5247348SJose.Borrego@Sun.COM unsigned char *passwd,
5257348SJose.Borrego@Sun.COM unsigned char *session_key)
5265331Samw {
5275331Samw unsigned char ntlm_resp[SMBAUTH_LM_RESP_SZ];
5285331Samw int rc;
5297348SJose.Borrego@Sun.COM boolean_t ok;
5305331Samw
5315331Samw rc = smb_auth_ntlm_response(ntlm_hash, challenge, clen, ntlm_resp);
5325331Samw if (rc != SMBAUTH_LM_RESP_SZ)
5335331Samw return (B_FALSE);
5345331Samw
5357348SJose.Borrego@Sun.COM ok = (bcmp(ntlm_resp, passwd, SMBAUTH_LM_RESP_SZ) == 0);
5367348SJose.Borrego@Sun.COM if (ok && (session_key)) {
5377348SJose.Borrego@Sun.COM rc = smb_auth_md4(session_key, ntlm_hash, SMBAUTH_HASH_SZ);
5387348SJose.Borrego@Sun.COM if (rc != SMBAUTH_SUCCESS)
5397348SJose.Borrego@Sun.COM ok = B_FALSE;
5407348SJose.Borrego@Sun.COM }
5417348SJose.Borrego@Sun.COM return (ok);
5425331Samw }
5435331Samw
5445331Samw static boolean_t
smb_ntlmv2_password_ok(unsigned char * challenge,uint32_t clen,unsigned char * ntlm_hash,unsigned char * passwd,int pwdlen,char * domain,char * username,uchar_t * session_key)5455331Samw smb_ntlmv2_password_ok(
5465331Samw unsigned char *challenge,
5475331Samw uint32_t clen,
5485331Samw unsigned char *ntlm_hash,
5495331Samw unsigned char *passwd,
5505331Samw int pwdlen,
5515772Sas200622 char *domain,
5527348SJose.Borrego@Sun.COM char *username,
5537348SJose.Borrego@Sun.COM uchar_t *session_key)
5545331Samw {
5555331Samw unsigned char *clnt_blob;
5565331Samw int clnt_blob_len;
5575331Samw unsigned char ntlmv2_hash[SMBAUTH_HASH_SZ];
5585331Samw unsigned char *ntlmv2_resp;
5595772Sas200622 boolean_t ok = B_FALSE;
5605772Sas200622 char *dest[3];
5615772Sas200622 int i;
5627348SJose.Borrego@Sun.COM int rc;
5635331Samw
5645331Samw clnt_blob_len = pwdlen - SMBAUTH_HASH_SZ;
5655331Samw clnt_blob = &passwd[SMBAUTH_HASH_SZ];
5665772Sas200622 dest[0] = domain;
5675772Sas200622 if ((dest[1] = strdup(domain)) == NULL)
5685772Sas200622 return (B_FALSE);
569*10966SJordan.Brown@Sun.COM (void) smb_strupr(dest[1]);
5705772Sas200622 dest[2] = "";
5715331Samw
5725331Samw /*
5735331Samw * 15.5.2 The NTLMv2 Password Hash, pg. 279, of the "Implementing CIFS"
5745331Samw *
5755772Sas200622 * The NTLMv2 Hash is created from:
5765331Samw * - NTLM hash
5775331Samw * - user's username, and
5785331Samw * - the name of the logon destination(i.e. the NetBIOS name of either
5795772Sas200622 * the SMB server or NT Domain against which the user is trying to
5805331Samw * authenticate.
5815331Samw *
5825772Sas200622 * Experiments show this is not exactly the case.
5835772Sas200622 * For Windows Server 2003, the domain name needs to be included and
5845772Sas200622 * converted to uppercase. For Vista, the domain name needs to be
5855772Sas200622 * included also, but leave the case alone. And in some cases it needs
5865772Sas200622 * to be empty. All three variants are tried here.
5875331Samw */
5885772Sas200622
5895772Sas200622 ntlmv2_resp = (unsigned char *)malloc(SMBAUTH_HASH_SZ + clnt_blob_len);
5905772Sas200622 if (ntlmv2_resp == NULL) {
5915772Sas200622 free(dest[1]);
5925331Samw return (B_FALSE);
5935331Samw }
5945331Samw
5955772Sas200622 for (i = 0; i < (sizeof (dest) / sizeof (char *)); i++) {
5965772Sas200622 if (smb_auth_ntlmv2_hash(ntlm_hash, username, dest[i],
5975772Sas200622 ntlmv2_hash) != SMBAUTH_SUCCESS)
5985772Sas200622 break;
5995331Samw
6005772Sas200622 if (smb_auth_v2_response(ntlmv2_hash, challenge,
6015772Sas200622 clen, clnt_blob, clnt_blob_len, ntlmv2_resp) < 0)
6025772Sas200622 break;
6035772Sas200622
6045772Sas200622 ok = (bcmp(passwd, ntlmv2_resp, pwdlen) == 0);
6057348SJose.Borrego@Sun.COM if (ok && session_key) {
6067348SJose.Borrego@Sun.COM rc = SMBAUTH_HMACT64(ntlmv2_resp,
6077348SJose.Borrego@Sun.COM SMBAUTH_HASH_SZ, ntlmv2_hash,
6087348SJose.Borrego@Sun.COM SMBAUTH_SESSION_KEY_SZ, session_key);
6097348SJose.Borrego@Sun.COM if (rc != SMBAUTH_SUCCESS) {
6107348SJose.Borrego@Sun.COM ok = B_FALSE;
6117348SJose.Borrego@Sun.COM }
6125772Sas200622 break;
6137348SJose.Borrego@Sun.COM }
6145331Samw }
6155331Samw
6165772Sas200622 free(dest[1]);
6175331Samw free(ntlmv2_resp);
6185331Samw return (ok);
6195331Samw }
6205331Samw
6215772Sas200622 static boolean_t
smb_lmv2_password_ok(unsigned char * challenge,uint32_t clen,unsigned char * ntlm_hash,unsigned char * passwd,char * domain,char * username)6225331Samw smb_lmv2_password_ok(
6235331Samw unsigned char *challenge,
6245331Samw uint32_t clen,
6255331Samw unsigned char *ntlm_hash,
6265331Samw unsigned char *passwd,
6275772Sas200622 char *domain,
6285331Samw char *username)
6295331Samw {
6305331Samw unsigned char *clnt_challenge;
6315331Samw unsigned char ntlmv2_hash[SMBAUTH_HASH_SZ];
6325331Samw unsigned char lmv2_resp[SMBAUTH_LM_RESP_SZ];
6335772Sas200622 boolean_t ok = B_FALSE;
6345772Sas200622 char *dest[3];
6355772Sas200622 int i;
6365331Samw
6375331Samw clnt_challenge = &passwd[SMBAUTH_HASH_SZ];
6385772Sas200622 dest[0] = domain;
6395772Sas200622 if ((dest[1] = strdup(domain)) == NULL)
6405772Sas200622 return (B_FALSE);
641*10966SJordan.Brown@Sun.COM (void) smb_strupr(dest[1]);
6425772Sas200622 dest[2] = "";
6435331Samw
6445331Samw /*
6455331Samw * 15.5.2 The NTLMv2 Password Hash, pg. 279, of the "Implementing CIFS"
6465331Samw *
6475331Samw * The NTLMv2 Hash is created from:
6485331Samw * - NTLM hash
6495331Samw * - user's username, and
6505331Samw * - the name of the logon destination(i.e. the NetBIOS name of either
6515331Samw * the SMB server or NT Domain against which the suer is trying to
6525331Samw * authenticate.
6535331Samw *
6545772Sas200622 * Experiments show this is not exactly the case.
6555772Sas200622 * For Windows Server 2003, the domain name needs to be included and
6565772Sas200622 * converted to uppercase. For Vista, the domain name needs to be
6575772Sas200622 * included also, but leave the case alone. And in some cases it needs
6585772Sas200622 * to be empty. All three variants are tried here.
6595331Samw */
6605772Sas200622
6615772Sas200622 for (i = 0; i < (sizeof (dest) / sizeof (char *)); i++) {
6625772Sas200622 if (smb_auth_ntlmv2_hash(ntlm_hash, username, dest[i],
6635772Sas200622 ntlmv2_hash) != SMBAUTH_SUCCESS)
6645772Sas200622 break;
6655772Sas200622
6665772Sas200622 if (smb_auth_v2_response(ntlmv2_hash, challenge,
6675772Sas200622 clen, clnt_challenge, SMBAUTH_V2_CLNT_CHALLENGE_SZ,
6685772Sas200622 lmv2_resp) < 0)
6695772Sas200622 break;
6705772Sas200622
6715772Sas200622 ok = (bcmp(passwd, lmv2_resp, SMBAUTH_LM_RESP_SZ) == 0);
6727348SJose.Borrego@Sun.COM if (ok)
6735772Sas200622 break;
6745331Samw }
6755331Samw
6765772Sas200622 free(dest[1]);
6775772Sas200622 return (ok);
6785331Samw }
6795331Samw
6805331Samw /*
6815331Samw * smb_auth_validate_lm
6825331Samw *
6835331Samw * Validates given LM/LMv2 client response, passed in passwd arg, against
6845331Samw * stored user's password, passed in smbpw
6855331Samw *
6865331Samw * If LM level <=3 server accepts LM responses, otherwise LMv2
6875331Samw */
6885331Samw boolean_t
smb_auth_validate_lm(unsigned char * challenge,uint32_t clen,smb_passwd_t * smbpw,unsigned char * passwd,int pwdlen,char * domain,char * username)6895331Samw smb_auth_validate_lm(
6905331Samw unsigned char *challenge,
6915331Samw uint32_t clen,
6925331Samw smb_passwd_t *smbpw,
6935331Samw unsigned char *passwd,
6945331Samw int pwdlen,
6955772Sas200622 char *domain,
6965331Samw char *username)
6975331Samw {
6985331Samw boolean_t ok = B_FALSE;
6995772Sas200622 int64_t lmlevel;
7005331Samw
7015331Samw if (pwdlen != SMBAUTH_LM_RESP_SZ)
7025331Samw return (B_FALSE);
7035331Samw
7045772Sas200622 if (smb_config_getnum(SMB_CI_LM_LEVEL, &lmlevel) != SMBD_SMF_OK)
7055772Sas200622 return (B_FALSE);
7065331Samw
7075331Samw if (lmlevel <= 3) {
7085331Samw ok = smb_lm_password_ok(challenge, clen, smbpw->pw_lmhash,
7095331Samw passwd);
7105331Samw }
7115331Samw
7125331Samw if (!ok)
7135331Samw ok = smb_lmv2_password_ok(challenge, clen, smbpw->pw_nthash,
7145772Sas200622 passwd, domain, username);
7155331Samw
7165331Samw return (ok);
7175331Samw }
7185331Samw
7195331Samw /*
7205331Samw * smb_auth_validate_nt
7215331Samw *
7225331Samw * Validates given NTLM/NTLMv2 client response, passed in passwd arg, against
7235331Samw * stored user's password, passed in smbpw
7245331Samw *
7255331Samw * If LM level <=4 server accepts NTLM/NTLMv2 responses, otherwise only NTLMv2
7265331Samw */
7275331Samw boolean_t
smb_auth_validate_nt(unsigned char * challenge,uint32_t clen,smb_passwd_t * smbpw,unsigned char * passwd,int pwdlen,char * domain,char * username,uchar_t * session_key)7285331Samw smb_auth_validate_nt(
7295331Samw unsigned char *challenge,
7305331Samw uint32_t clen,
7315331Samw smb_passwd_t *smbpw,
7325331Samw unsigned char *passwd,
7335331Samw int pwdlen,
7345772Sas200622 char *domain,
7357348SJose.Borrego@Sun.COM char *username,
7367348SJose.Borrego@Sun.COM uchar_t *session_key)
7375331Samw {
7385772Sas200622 int64_t lmlevel;
7395331Samw boolean_t ok;
7405331Samw
7415772Sas200622 if (smb_config_getnum(SMB_CI_LM_LEVEL, &lmlevel) != SMBD_SMF_OK)
7425772Sas200622 return (B_FALSE);
7435331Samw
7445331Samw if ((lmlevel == 5) && (pwdlen <= SMBAUTH_LM_RESP_SZ))
7455331Samw return (B_FALSE);
7465331Samw
7475331Samw if (pwdlen > SMBAUTH_LM_RESP_SZ)
7485331Samw ok = smb_ntlmv2_password_ok(challenge, clen,
7497348SJose.Borrego@Sun.COM smbpw->pw_nthash, passwd, pwdlen,
7507348SJose.Borrego@Sun.COM domain, username, session_key);
7515331Samw else
7525331Samw ok = smb_ntlm_password_ok(challenge, clen,
7537348SJose.Borrego@Sun.COM smbpw->pw_nthash, passwd, session_key);
7545331Samw
7555331Samw return (ok);
7565331Samw }
757