4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
25 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
32 #include <smbsrv/string.h>
33 #include <smbsrv/libsmb.h>
34 #include <netsmb/spnego.h> /* libsmbfs */
37 #define NTLM_CHAL_SZ SMBAUTH_CHAL_SZ /* challenge size */
40 * Compute the combined (server+client) challenge per. [MS-NLMP 3.3.1]
41 * MD5(concat(ServerChallenge,ClientChallenge))
44 smb_auth_ntlm2_mkchallenge(char *result
,
45 const char *srv_chal
, const char *clnt_chal
)
48 uchar_t challenges
[2 * NTLM_CHAL_SZ
];
49 uchar_t digest
[SMBAUTH_HASH_SZ
];
52 * challenges = ConcatenationOf(ServerChallenge, ClientChallenge)
54 (void) memcpy(challenges
, srv_chal
, NTLM_CHAL_SZ
);
55 (void) memcpy(challenges
+ NTLM_CHAL_SZ
, clnt_chal
, NTLM_CHAL_SZ
);
58 * digest = MD5(challenges)
61 MD5Update(&context
, challenges
, sizeof (challenges
));
62 MD5Final(digest
, &context
);
65 * result = digest[0..7]
67 (void) memcpy(result
, digest
, NTLM_CHAL_SZ
);
71 smb_auth_ntlm2_kxkey(unsigned char *result
, const char *srv_chal
,
72 const char *clnt_chal
, unsigned char *ssn_base_key
)
74 uchar_t challenges
[2 * NTLM_CHAL_SZ
];
77 * challenges = ConcatenationOf(ServerChallenge, ClientChallenge)
79 (void) memcpy(challenges
, srv_chal
, NTLM_CHAL_SZ
);
80 (void) memcpy(challenges
+ NTLM_CHAL_SZ
, clnt_chal
, NTLM_CHAL_SZ
);
82 /* HMAC_MD5(SessionBaseKey, concat(...)) */
83 /* SMBAUTH_HMACT64 args: D, Dsz, K, Ksz, digest */
84 (void) SMBAUTH_HMACT64(challenges
, sizeof (challenges
),
85 ssn_base_key
, SMBAUTH_HASH_SZ
, result
);
89 * smb_auth_qnd_unicode
91 * Quick and dirty unicode conversion!
92 * Returns the length of dst in bytes.
95 smb_auth_qnd_unicode(smb_wchar_t
*dst
, const char *src
, int length
)
101 if ((count
= oemtoucs(dst
, src
, length
, OEM_CPG_1252
)) == 0) {
102 for (i
= 0; i
< length
; ++i
) {
103 new_char
= (smb_wchar_t
)src
[i
] & 0xff;
104 dst
[i
] = LE_IN16(&new_char
);
110 return (count
* sizeof (smb_wchar_t
));
116 * Converts the given LM password to all uppercase.
117 * The standard strupr cannot
118 * be used here because lm_pwd doesn't have to be
122 smb_auth_lmupr(unsigned char *lm_pwd
)
124 unsigned char *p
= lm_pwd
;
127 for (i
= 0; (*p
) && (i
< SMBAUTH_LM_PWD_SZ
); i
++) {
128 if (smb_isascii(*p
)) {
129 *p
= smb_toupper(*p
);
138 * Source: Implementing CIFS (Chris Hertel)
140 * 1. The password, as entered by user, is either padded with nulls
141 * or trimmed to 14 bytes.
142 * . Note that the 14-byte result string is not handled as a
143 * nul-terminated string.
144 * . The given password is OEM not Unicode
146 * 2. The 14-byte password is converted to all uppercase
148 * 3. The result is used as key to encrypt the KGS magic string to
149 * make a 16-byte hash.
152 smb_auth_lm_hash(const char *password
, unsigned char *lm_hash
)
154 unsigned char lm_pwd
[SMBAUTH_LM_PWD_SZ
];
156 bzero((void *)lm_pwd
, SMBAUTH_LM_PWD_SZ
);
157 (void) strncpy((char *)lm_pwd
, password
, SMBAUTH_LM_PWD_SZ
);
158 smb_auth_lmupr(lm_pwd
);
160 return (smb_auth_DES(lm_hash
, SMBAUTH_HASH_SZ
, lm_pwd
,
161 SMBAUTH_LM_PWD_SZ
, (unsigned char *)SMBAUTH_LM_MAGIC_STR
,
162 sizeof (SMBAUTH_LM_MAGIC_STR
)));
166 * smb_auth_lm_response
168 * Create a LM response from the given LM hash and challenge.
170 * Returns SMBAUTH_FAILURE if any problems occur, SMBAUTH_SUCCESS if
174 smb_auth_lm_response(unsigned char *hash
,
175 unsigned char *challenge
, /* NTLM_CHAL_SZ */
176 unsigned char *lm_rsp
)
178 unsigned char S21
[21];
181 * 14-byte LM Hash should be padded with 5 nul bytes to create
182 * a 21-byte string to be used in producing LM response
184 bzero(&S21
[SMBAUTH_HASH_SZ
], 5);
185 bcopy(hash
, S21
, SMBAUTH_HASH_SZ
);
187 /* padded LM Hash -> LM Response */
188 return (smb_auth_DES(lm_rsp
, SMBAUTH_LM_RESP_SZ
, S21
, 21,
189 challenge
, NTLM_CHAL_SZ
));
195 * Make NTLM Hash (using MD4) from the given password.
196 * The result will contain a 16-byte NTLM hash.
199 smb_auth_ntlm_hash(const char *password
, unsigned char *hash
)
201 smb_wchar_t
*unicode_password
;
202 int length
, unicode_len
;
205 if (password
== NULL
|| hash
== NULL
)
206 return (SMBAUTH_FAILURE
);
208 length
= strlen(password
);
209 unicode_len
= (length
+ 1) * sizeof (smb_wchar_t
);
210 unicode_password
= malloc(unicode_len
);
212 if (unicode_password
== NULL
)
213 return (SMBAUTH_FAILURE
);
215 length
= smb_auth_qnd_unicode(unicode_password
, password
, length
);
216 rc
= smb_auth_md4(hash
, (unsigned char *)unicode_password
, length
);
218 (void) memset(unicode_password
, 0, unicode_len
);
219 free(unicode_password
);
225 * smb_auth_ntlm_response
227 * Make LM/NTLM response from the given LM/NTLM Hash and given
231 smb_auth_ntlm_response(unsigned char *hash
,
232 unsigned char *challenge
, /* NTLM_CHAL_SZ */
233 unsigned char *ntlm_rsp
)
235 unsigned char S21
[21];
237 bcopy(hash
, S21
, SMBAUTH_HASH_SZ
);
238 bzero(&S21
[SMBAUTH_HASH_SZ
], 5);
239 if (smb_auth_DES((unsigned char *)ntlm_rsp
, SMBAUTH_LM_RESP_SZ
,
240 S21
, 21, challenge
, NTLM_CHAL_SZ
) == SMBAUTH_FAILURE
)
242 return (SMBAUTH_LM_RESP_SZ
);
246 * smb_auth_ntlmv2_hash
248 * The NTLM v2 hash will be created from the given NTLM hash, username,
249 * and the NETBIOS name of the domain.
251 * The NTLMv2 hash will be returned via the ntlmv2_hash parameter which
252 * will be used in the calculation of the NTLMv2 and LMv2 responses.
255 smb_auth_ntlmv2_hash(unsigned char *ntlm_hash
,
258 unsigned char *ntlmv2_hash
)
265 if (username
== NULL
|| ntdomain
== NULL
)
266 return (SMBAUTH_FAILURE
);
268 (void) smb_strupr(username
);
270 data_len
= strlen(username
) + strlen(ntdomain
);
271 buf
= (unsigned char *)malloc((data_len
+ 1) * sizeof (char));
273 return (SMBAUTH_FAILURE
);
275 (void) snprintf((char *)buf
, data_len
+ 1, "%s%s", username
, ntdomain
);
276 data
= (smb_wchar_t
*)malloc((data_len
+ 1) * sizeof (smb_wchar_t
));
279 return (SMBAUTH_FAILURE
);
282 data_len
= smb_auth_qnd_unicode(data
, (char *)buf
, data_len
);
283 rc
= SMBAUTH_HMACT64((unsigned char *)data
, data_len
, ntlm_hash
,
284 SMBAUTH_HASH_SZ
, ntlmv2_hash
);
292 * smb_auth_v2_response
294 * Caculates either the LMv2 or NTLMv2 response.
296 * Same algorithm is used for calculating both LMv2 or NTLMv2 responses.
297 * This routine will return NTLMv2 response if the data blob information
298 * is passed in as the clnt_data. Otherwise, it will return LMv2 response
299 * with the 8-byte client challenge(a.k.a blip) as the clnt_data.
301 * (LM/NTLM)v2 response is the hmac-md5 hash of the specified data
302 * (server challenge + NTLMv2 data blob or LMv2 client challenge)
303 * using the NTLMv2 hash as the key.
305 * Returns the size of the corresponding v2 response upon success.
306 * Otherwise, returns -1 on error.
309 smb_auth_v2_response(
311 unsigned char *srv_challenge
, /* NTLM_CHAL_SZ */
312 unsigned char *clnt_data
, int clen
,
313 unsigned char *v2_rsp
)
315 unsigned char *hmac_data
;
316 int slen
= NTLM_CHAL_SZ
;
318 hmac_data
= malloc(NTLM_CHAL_SZ
+ clen
);
323 (void) memcpy(hmac_data
, srv_challenge
, slen
);
324 (void) memcpy(&hmac_data
[slen
], clnt_data
, clen
);
325 if (SMBAUTH_HMACT64(hmac_data
, slen
+ clen
, (unsigned char *)hash
,
326 SMBAUTH_HASH_SZ
, (unsigned char *)v2_rsp
) != SMBAUTH_SUCCESS
)
328 (void) memcpy(&v2_rsp
[SMBAUTH_HASH_SZ
], clnt_data
, clen
);
331 return (SMBAUTH_HASH_SZ
+ clen
);
337 unsigned char *challenge
,
338 unsigned char *lm_hash
,
339 unsigned char *lm_resp
)
341 unsigned char ok_resp
[SMBAUTH_LM_RESP_SZ
];
344 rc
= smb_auth_lm_response(lm_hash
, challenge
, ok_resp
);
345 if (rc
!= SMBAUTH_SUCCESS
)
348 return (bcmp(ok_resp
, lm_resp
, SMBAUTH_LM_RESP_SZ
) == 0);
352 smb_ntlm_password_ok(
353 unsigned char *challenge
,
354 unsigned char *ntlm_hash
,
355 unsigned char *nt_resp
,
356 unsigned char *session_key
)
358 unsigned char ok_resp
[SMBAUTH_LM_RESP_SZ
];
362 rc
= smb_auth_ntlm_response(ntlm_hash
, challenge
, ok_resp
);
363 if (rc
!= SMBAUTH_LM_RESP_SZ
)
366 ok
= (bcmp(ok_resp
, nt_resp
, SMBAUTH_LM_RESP_SZ
) == 0);
367 if (ok
&& (session_key
)) {
368 rc
= smb_auth_md4(session_key
, ntlm_hash
, SMBAUTH_HASH_SZ
);
369 if (rc
!= SMBAUTH_SUCCESS
)
376 smb_ntlmv2_password_ok(
377 unsigned char *challenge
,
378 unsigned char *ntlm_hash
,
379 unsigned char *passwd
,
383 uchar_t
*session_key
)
385 unsigned char *clnt_blob
;
387 unsigned char ntlmv2_hash
[SMBAUTH_HASH_SZ
];
388 unsigned char *ntlmv2_resp
;
389 boolean_t ok
= B_FALSE
;
394 clnt_blob_len
= pwdlen
- SMBAUTH_HASH_SZ
;
395 clnt_blob
= &passwd
[SMBAUTH_HASH_SZ
];
397 if ((dest
[1] = strdup(domain
)) == NULL
)
399 (void) smb_strupr(dest
[1]);
403 * 15.5.2 The NTLMv2 Password Hash, pg. 279, of the "Implementing CIFS"
405 * The NTLMv2 Hash is created from:
407 * - user's username, and
408 * - the name of the logon destination(i.e. the NetBIOS name of either
409 * the SMB server or NT Domain against which the user is trying to
412 * Experiments show this is not exactly the case.
413 * For Windows Server 2003, the domain name needs to be included and
414 * converted to uppercase. For Vista, the domain name needs to be
415 * included also, but leave the case alone. And in some cases it needs
416 * to be empty. All three variants are tried here.
419 ntlmv2_resp
= (unsigned char *)malloc(SMBAUTH_HASH_SZ
+ clnt_blob_len
);
420 if (ntlmv2_resp
== NULL
) {
425 for (i
= 0; i
< (sizeof (dest
) / sizeof (char *)); i
++) {
426 if (smb_auth_ntlmv2_hash(ntlm_hash
, username
, dest
[i
],
427 ntlmv2_hash
) != SMBAUTH_SUCCESS
)
430 if (smb_auth_v2_response(ntlmv2_hash
, challenge
,
431 clnt_blob
, clnt_blob_len
, ntlmv2_resp
) < 0)
434 ok
= (bcmp(passwd
, ntlmv2_resp
, pwdlen
) == 0);
435 if (ok
&& session_key
) {
436 rc
= SMBAUTH_HMACT64(ntlmv2_resp
,
437 SMBAUTH_HASH_SZ
, ntlmv2_hash
,
438 SMBAUTH_SESSION_KEY_SZ
, session_key
);
439 if (rc
!= SMBAUTH_SUCCESS
) {
452 smb_lmv2_password_ok(
453 unsigned char *srv_challenge
,
454 unsigned char *ntlm_hash
,
455 unsigned char *passwd
,
459 unsigned char *clnt_challenge
;
460 unsigned char ntlmv2_hash
[SMBAUTH_HASH_SZ
];
461 unsigned char lmv2_resp
[SMBAUTH_LM_RESP_SZ
];
462 boolean_t ok
= B_FALSE
;
466 clnt_challenge
= &passwd
[SMBAUTH_HASH_SZ
];
468 if ((dest
[1] = strdup(domain
)) == NULL
)
470 (void) smb_strupr(dest
[1]);
474 * 15.5.2 The NTLMv2 Password Hash, pg. 279, of the "Implementing CIFS"
476 * The NTLMv2 Hash is created from:
478 * - user's username, and
479 * - the name of the logon destination(i.e. the NetBIOS name of either
480 * the SMB server or NT Domain against which the suer is trying to
483 * Experiments show this is not exactly the case.
484 * For Windows Server 2003, the domain name needs to be included and
485 * converted to uppercase. For Vista, the domain name needs to be
486 * included also, but leave the case alone. And in some cases it needs
487 * to be empty. All three variants are tried here.
490 for (i
= 0; i
< (sizeof (dest
) / sizeof (char *)); i
++) {
491 if (smb_auth_ntlmv2_hash(ntlm_hash
, username
, dest
[i
],
492 ntlmv2_hash
) != SMBAUTH_SUCCESS
)
495 if (smb_auth_v2_response(ntlmv2_hash
, srv_challenge
,
496 clnt_challenge
, SMBAUTH_CHAL_SZ
,
500 ok
= (bcmp(passwd
, lmv2_resp
, SMBAUTH_LM_RESP_SZ
) == 0);
512 * Validates given NTLMv2 (or NTLM, LMv2, LM) client responses against
513 * the stored user's password, passed in smbpw. Try those in the order
514 * strongest to weakest, stopping at a point determined by the configured
515 * lmauth_level (LM Compatibility Level).
522 unsigned char *challenge
,
524 unsigned char *nt_resp
,
526 unsigned char *lm_resp
,
528 uchar_t
*session_key
)
531 boolean_t ok
= B_FALSE
;
533 if (smb_config_getnum(SMB_CI_LM_LEVEL
, &lmlevel
) != SMBD_SMF_OK
)
539 if (clen
!= NTLM_CHAL_SZ
)
543 * Accept NTLMv2 at any LM level (0-5).
545 if (nt_len
> SMBAUTH_LM_RESP_SZ
) {
546 ok
= smb_ntlmv2_password_ok(challenge
,
547 smbpw
->pw_nthash
, nt_resp
, nt_len
,
548 domain
, username
, session_key
);
557 * Accept NTLM at levels 0-4
559 if (nt_len
== SMBAUTH_LM_RESP_SZ
) {
560 ok
= smb_ntlm_password_ok(challenge
, smbpw
->pw_nthash
,
561 nt_resp
, session_key
);
571 * Accept LM/LMv2 auth at levels 0-3
573 if (lm_len
!= SMBAUTH_LM_RESP_SZ
)
576 (void) smb_auth_md4(session_key
, smbpw
->pw_nthash
,
578 ok
= smb_lmv2_password_ok(challenge
, smbpw
->pw_nthash
,
579 lm_resp
, domain
, username
);
582 ok
= smb_lm_password_ok(challenge
, smbpw
->pw_lmhash
, lm_resp
);
590 * smb_gen_random_passwd(buf, len)
591 * Generate a random password of length len-1, and store it in buf,
592 * null terminated. This is used as a machine account password,
593 * which we set when we join a domain.
595 * [MS-DISO] A machine password is an ASCII string of randomly chosen
596 * characters. Each character's ASCII code is between 32 and 122 inclusive.
597 * That's space through 'z'.
601 smb_gen_random_passwd(char *buf
, size_t len
)
603 const uchar_t start
= ' ';
604 const uchar_t modulus
= 'z' - ' ' + 1;
608 /* Last byte is the null. */
611 /* Temporarily put random data in the caller's buffer. */
614 /* Convert the random data to printable characters. */
615 for (i
= 0; i
< len
; i
++) {
616 /* need unsigned math */
618 t
= (t
% modulus
) + start
;
619 assert(' ' <= t
&& t
<= 'z');