1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <strings.h>
27 #include <stdlib.h>
28 #include <smbsrv/string.h>
29 #include <smbsrv/libsmb.h>
30
31 extern void randomize(char *data, unsigned len);
32 static uint64_t unix_micro_to_nt_time(struct timeval *unix_time);
33
34 /*
35 * smb_auth_qnd_unicode
36 *
37 * Quick and dirty unicode conversion!
38 * Returns the length of dst in bytes.
39 */
40 int
smb_auth_qnd_unicode(smb_wchar_t * dst,const char * src,int length)41 smb_auth_qnd_unicode(smb_wchar_t *dst, const char *src, int length)
42 {
43 int i;
44 unsigned int count;
45 smb_wchar_t new_char;
46
47 if ((count = oemtoucs(dst, src, length, OEM_CPG_1252)) == 0) {
48 for (i = 0; i < length; ++i) {
49 new_char = (smb_wchar_t)src[i] & 0xff;
50 dst[i] = LE_IN16(&new_char);
51 }
52 dst[i] = 0;
53 count = length;
54 }
55
56 return (count * sizeof (smb_wchar_t));
57 }
58
59 /*
60 * smb_auth_lmupr
61 *
62 * Converts the given LM password to all uppercase.
63 * The standard strupr cannot
64 * be used here because lm_pwd doesn't have to be
65 * nul terminated.
66 */
67 static void
smb_auth_lmupr(unsigned char * lm_pwd)68 smb_auth_lmupr(unsigned char *lm_pwd)
69 {
70 unsigned char *p = lm_pwd;
71 int i;
72
73 for (i = 0; (*p) && (i < SMBAUTH_LM_PWD_SZ); i++) {
74 if (smb_isascii(*p)) {
75 *p = smb_toupper(*p);
76 p++;
77 }
78 }
79 }
80
81 /*
82 * smb_auth_lm_hash
83 *
84 * Source: Implementing CIFS (Chris Hertel)
85 *
86 * 1. The password, as entered by user, is either padded with nulls
87 * or trimmed to 14 bytes.
88 * . Note that the 14-byte result string is not handled as a
89 * nul-terminated string.
90 * . The given password is OEM not Unicode
91 *
92 * 2. The 14-byte password is converted to all uppercase
93 *
94 * 3. The result is used as key to encrypt the KGS magic string to
95 * make a 16-byte hash.
96 */
97 int
smb_auth_lm_hash(const char * password,unsigned char * lm_hash)98 smb_auth_lm_hash(const char *password, unsigned char *lm_hash)
99 {
100 unsigned char lm_pwd[SMBAUTH_LM_PWD_SZ];
101
102 bzero((void *)lm_pwd, SMBAUTH_LM_PWD_SZ);
103 (void) strncpy((char *)lm_pwd, password, SMBAUTH_LM_PWD_SZ);
104 smb_auth_lmupr(lm_pwd);
105
106 return (smb_auth_DES(lm_hash, SMBAUTH_HASH_SZ, lm_pwd,
107 SMBAUTH_LM_PWD_SZ, (unsigned char *)SMBAUTH_LM_MAGIC_STR,
108 sizeof (SMBAUTH_LM_MAGIC_STR)));
109 }
110
111 /*
112 * smb_auth_lm_response
113 *
114 * Create a LM response from the given LM hash and challenge.
115 *
116 * Returns SMBAUTH_FAILURE if any problems occur, SMBAUTH_SUCCESS if
117 * all goes well.
118 */
119 static int
smb_auth_lm_response(unsigned char * hash,unsigned char * challenge,int clen,unsigned char * lm_rsp)120 smb_auth_lm_response(unsigned char *hash,
121 unsigned char *challenge, int clen,
122 unsigned char *lm_rsp)
123 {
124 unsigned char S21[21];
125
126 /*
127 * 14-byte LM Hash should be padded with 5 nul bytes to create
128 * a 21-byte string to be used in producing LM response
129 */
130 bzero(&S21[SMBAUTH_HASH_SZ], 5);
131 bcopy(hash, S21, SMBAUTH_HASH_SZ);
132
133 /* padded LM Hash -> LM Response */
134 return (smb_auth_DES(lm_rsp, SMBAUTH_LM_RESP_SZ, S21, 21,
135 challenge, clen));
136 }
137
138 /*
139 * smb_auth_ntlm_hash
140 *
141 * Make NTLM Hash (using MD4) from the given password.
142 * The result will contain a 16-byte NTLM hash.
143 */
144 int
smb_auth_ntlm_hash(const char * password,unsigned char * hash)145 smb_auth_ntlm_hash(const char *password, unsigned char *hash)
146 {
147 smb_wchar_t *unicode_password;
148 int length;
149 int rc;
150
151 if (password == NULL || hash == NULL)
152 return (SMBAUTH_FAILURE);
153
154 length = strlen(password);
155 unicode_password = (smb_wchar_t *)
156 malloc((length + 1) * sizeof (smb_wchar_t));
157
158 if (unicode_password == NULL)
159 return (SMBAUTH_FAILURE);
160
161 length = smb_auth_qnd_unicode(unicode_password, password, length);
162 rc = smb_auth_md4(hash, (unsigned char *)unicode_password, length);
163
164 free(unicode_password);
165 return (rc);
166 }
167
168 /*
169 * smb_auth_ntlm_response
170 *
171 * Make LM/NTLM response from the given LM/NTLM Hash and given
172 * challenge.
173 */
174 static int
smb_auth_ntlm_response(unsigned char * hash,unsigned char * challenge,int clen,unsigned char * ntlm_rsp)175 smb_auth_ntlm_response(unsigned char *hash,
176 unsigned char *challenge, int clen,
177 unsigned char *ntlm_rsp)
178 {
179 unsigned char S21[21];
180
181 bcopy(hash, S21, SMBAUTH_HASH_SZ);
182 bzero(&S21[SMBAUTH_HASH_SZ], 5);
183 if (smb_auth_DES((unsigned char *)ntlm_rsp, SMBAUTH_LM_RESP_SZ,
184 S21, 21, challenge, clen) == SMBAUTH_FAILURE)
185 return (0);
186 return (SMBAUTH_LM_RESP_SZ);
187 }
188
189 /*
190 * smb_auth_gen_data_blob
191 *
192 * Fill the NTLMv2 data blob structure with information as described in
193 * "Implementing CIFS, The Common Internet File System". (pg. 282)
194 */
195 static void
smb_auth_gen_data_blob(smb_auth_data_blob_t * blob,char * ntdomain)196 smb_auth_gen_data_blob(smb_auth_data_blob_t *blob, char *ntdomain)
197 {
198 struct timeval now;
199
200 (void) memset(blob->ndb_signature, 1, 2);
201 (void) memset(&blob->ndb_signature[2], 0, 2);
202 (void) memset(blob->ndb_reserved, 0, sizeof (blob->ndb_reserved));
203
204 (void) gettimeofday(&now, 0);
205 blob->ndb_timestamp = unix_micro_to_nt_time(&now);
206 randomize((char *)blob->ndb_clnt_challenge,
207 SMBAUTH_V2_CLNT_CHALLENGE_SZ);
208 (void) memset(blob->ndb_unknown, 0, sizeof (blob->ndb_unknown));
209 blob->ndb_names[0].nne_len = smb_auth_qnd_unicode(
210 blob->ndb_names[0].nne_name, ntdomain, strlen(ntdomain));
211 blob->ndb_names[0].nne_type = SMBAUTH_NAME_TYPE_DOMAIN_NETBIOS;
212 blob->ndb_names[1].nne_len = 0;
213 blob->ndb_names[1].nne_type = SMBAUTH_NAME_TYPE_LIST_END;
214 *blob->ndb_names[1].nne_name = 0;
215 (void) memset(blob->ndb_unknown2, 0, sizeof (blob->ndb_unknown2));
216 }
217
218 /*
219 * smb_auth_memcpy
220 *
221 * It increments the pointer to the destination buffer for the easy of
222 * concatenation.
223 */
224 static void
smb_auth_memcpy(unsigned char ** dstbuf,unsigned char * srcbuf,int srcbuf_len)225 smb_auth_memcpy(unsigned char **dstbuf,
226 unsigned char *srcbuf,
227 int srcbuf_len)
228 {
229 (void) memcpy(*dstbuf, srcbuf, srcbuf_len);
230 *dstbuf += srcbuf_len;
231 }
232
233 /*
234 * smb_auth_blob_to_string
235 *
236 * Prepare the data blob string which will be used in NTLMv2 response
237 * generation.
238 *
239 * Assumption: Caller must allocate big enough buffer to prevent buffer
240 * overrun.
241 *
242 * Returns the len of the data blob string.
243 */
244 static int
smb_auth_blob_to_string(smb_auth_data_blob_t * blob,unsigned char * data_blob)245 smb_auth_blob_to_string(smb_auth_data_blob_t *blob, unsigned char *data_blob)
246 {
247 unsigned char *bufp = data_blob;
248
249 smb_auth_memcpy(&bufp, blob->ndb_signature,
250 sizeof (blob->ndb_signature));
251 smb_auth_memcpy(&bufp, blob->ndb_reserved,
252 sizeof (blob->ndb_reserved));
253 smb_auth_memcpy(&bufp, (unsigned char *)&blob->ndb_timestamp,
254 sizeof (blob->ndb_timestamp));
255 smb_auth_memcpy(&bufp, blob->ndb_clnt_challenge,
256 SMBAUTH_V2_CLNT_CHALLENGE_SZ);
257 smb_auth_memcpy(&bufp, blob->ndb_unknown, sizeof (blob->ndb_unknown));
258 smb_auth_memcpy(&bufp, (unsigned char *)&blob->ndb_names[0].nne_type,
259 sizeof (blob->ndb_names[0].nne_type));
260 smb_auth_memcpy(&bufp, (unsigned char *)&blob->ndb_names[0].nne_len,
261 sizeof (blob->ndb_names[0].nne_len));
262 smb_auth_memcpy(&bufp, (unsigned char *)blob->ndb_names[0].nne_name,
263 blob->ndb_names[0].nne_len);
264 smb_auth_memcpy(&bufp, (unsigned char *)&blob->ndb_names[1].nne_type,
265 sizeof (blob->ndb_names[1].nne_type));
266 smb_auth_memcpy(&bufp, (unsigned char *)&blob->ndb_names[1].nne_len,
267 sizeof (blob->ndb_names[1].nne_len));
268 smb_auth_memcpy(&bufp, blob->ndb_unknown2, sizeof (blob->ndb_unknown2));
269
270 /*LINTED E_PTRDIFF_OVERFLOW*/
271 return (bufp - data_blob);
272 }
273
274 /*
275 * smb_auth_ntlmv2_hash
276 *
277 * The NTLM v2 hash will be created from the given NTLM hash, username,
278 * and the NETBIOS name of the domain.
279 *
280 * The NTLMv2 hash will be returned via the ntlmv2_hash parameter which
281 * will be used in the calculation of the NTLMv2 and LMv2 responses.
282 */
283 int
smb_auth_ntlmv2_hash(unsigned char * ntlm_hash,char * username,char * ntdomain,unsigned char * ntlmv2_hash)284 smb_auth_ntlmv2_hash(unsigned char *ntlm_hash,
285 char *username,
286 char *ntdomain,
287 unsigned char *ntlmv2_hash)
288 {
289 smb_wchar_t *data;
290 int data_len;
291 unsigned char *buf;
292 int rc;
293
294 if (username == NULL || ntdomain == NULL)
295 return (SMBAUTH_FAILURE);
296
297 (void) smb_strupr(username);
298
299 data_len = strlen(username) + strlen(ntdomain);
300 buf = (unsigned char *)malloc((data_len + 1) * sizeof (char));
301 if (buf == NULL)
302 return (SMBAUTH_FAILURE);
303
304 (void) snprintf((char *)buf, data_len + 1, "%s%s", username, ntdomain);
305 data = (smb_wchar_t *)malloc((data_len + 1) * sizeof (smb_wchar_t));
306 if (data == NULL) {
307 free(buf);
308 return (SMBAUTH_FAILURE);
309 }
310
311 data_len = smb_auth_qnd_unicode(data, (char *)buf, data_len);
312 rc = SMBAUTH_HMACT64((unsigned char *)data, data_len, ntlm_hash,
313 SMBAUTH_HASH_SZ, ntlmv2_hash);
314
315 free(buf);
316 free(data);
317 return (rc);
318 }
319
320 /*
321 * smb_auth_v2_response
322 *
323 * Caculates either the LMv2 or NTLMv2 response.
324 *
325 * Same algorithm is used for calculating both LMv2 or NTLMv2 responses.
326 * This routine will return NTLMv2 response if the data blob information
327 * is passed in as the clnt_data. Otherwise, it will return LMv2 response
328 * with the 8-byte client challenge(a.k.a blip) as the clnt_data.
329 *
330 * (LM/NTLM)v2 response is the hmac-md5 hash of the specified data
331 * (server challenge + NTLMv2 data blob or LMv2 client challenge)
332 * using the NTLMv2 hash as the key.
333 *
334 * Returns the size of the corresponding v2 response upon success.
335 * Otherwise, returns -1 on error.
336 */
337 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)338 smb_auth_v2_response(
339 unsigned char *hash,
340 unsigned char *srv_challenge, int slen,
341 unsigned char *clnt_data, int clen,
342 unsigned char *v2_rsp)
343 {
344 unsigned char *hmac_data;
345
346 hmac_data = (unsigned char *)malloc((slen + clen) * sizeof (char));
347 if (!hmac_data) {
348 return (-1);
349 }
350
351 (void) memcpy(hmac_data, srv_challenge, slen);
352 (void) memcpy(&hmac_data[slen], clnt_data, clen);
353 if (SMBAUTH_HMACT64(hmac_data, slen + clen, (unsigned char *)hash,
354 SMBAUTH_HASH_SZ, (unsigned char *)v2_rsp) != SMBAUTH_SUCCESS)
355 return (-1);
356 (void) memcpy(&v2_rsp[SMBAUTH_HASH_SZ], clnt_data, clen);
357
358 free(hmac_data);
359 return (SMBAUTH_HASH_SZ + clen);
360 }
361
362 /*
363 * smb_auth_set_info
364 *
365 * Fill the smb_auth_info instance with either NTLM or NTLMv2 related
366 * authentication information based on the LMCompatibilityLevel.
367 *
368 * If the LMCompatibilityLevel equals 2, the SMB Redirector will perform
369 * NTLM challenge/response authentication which requires the NTLM hash and
370 * NTLM response.
371 *
372 * If the LMCompatibilityLevel is 3 or above, the SMB Redirector will
373 * perfrom NTLMv2 challenge/response authenticatoin which requires the
374 * NTLM hash, NTLMv2 hash, NTLMv2 response and LMv2 response.
375 *
376 * Returns -1 on error. Otherwise, returns 0 upon success.
377 */
378 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)379 smb_auth_set_info(char *username,
380 char *password,
381 unsigned char *ntlm_hash,
382 char *domain,
383 unsigned char *srv_challenge_key,
384 int srv_challenge_len,
385 int lmcomp_lvl,
386 smb_auth_info_t *auth)
387 {
388 unsigned short blob_len;
389 unsigned char blob_buf[SMBAUTH_BLOB_MAXLEN];
390 int rc;
391 char *uppercase_dom;
392
393 auth->lmcompatibility_lvl = lmcomp_lvl;
394 if (lmcomp_lvl == 2) {
395 auth->ci_len = 0;
396 *auth->ci = 0;
397 if (!ntlm_hash) {
398 if (smb_auth_ntlm_hash(password, auth->hash) !=
399 SMBAUTH_SUCCESS)
400 return (-1);
401 } else {
402 (void) memcpy(auth->hash, ntlm_hash, SMBAUTH_HASH_SZ);
403 }
404
405 auth->cs_len = smb_auth_ntlm_response(auth->hash,
406 srv_challenge_key, srv_challenge_len, auth->cs);
407 } else {
408 if (!ntlm_hash) {
409 if (smb_auth_ntlm_hash(password, auth->hash) !=
410 SMBAUTH_SUCCESS)
411 return (-1);
412 } else {
413 (void) memcpy(auth->hash, ntlm_hash, SMBAUTH_HASH_SZ);
414 }
415
416 if (!domain)
417 return (-1);
418
419 if ((uppercase_dom = strdup(domain)) == NULL)
420 return (-1);
421
422 (void) smb_strupr(uppercase_dom);
423
424 if (smb_auth_ntlmv2_hash(auth->hash, username,
425 uppercase_dom, auth->hash_v2) != SMBAUTH_SUCCESS) {
426 free(uppercase_dom);
427 return (-1);
428 }
429
430 /* generate data blob */
431 smb_auth_gen_data_blob(&auth->data_blob, uppercase_dom);
432 free(uppercase_dom);
433 blob_len = smb_auth_blob_to_string(&auth->data_blob, blob_buf);
434
435 /* generate NTLMv2 response */
436 rc = smb_auth_v2_response(auth->hash_v2, srv_challenge_key,
437 srv_challenge_len, blob_buf, blob_len, auth->cs);
438
439 if (rc < 0)
440 return (-1);
441
442 auth->cs_len = rc;
443
444 /* generate LMv2 response */
445 rc = smb_auth_v2_response(auth->hash_v2, srv_challenge_key,
446 srv_challenge_len, auth->data_blob.ndb_clnt_challenge,
447 SMBAUTH_V2_CLNT_CHALLENGE_SZ, auth->ci);
448
449 if (rc < 0)
450 return (-1);
451
452 auth->ci_len = rc;
453 }
454
455 return (0);
456 }
457
458 /*
459 * smb_auth_gen_session_key
460 *
461 * Generate the NTLM user session key if LMCompatibilityLevel is 2 or
462 * NTLMv2 user session key if LMCompatibilityLevel is 3 or above.
463 *
464 * NTLM_Session_Key = MD4(NTLM_Hash);
465 *
466 * NTLMv2_Session_Key = HMAC_MD5(NTLMv2Hash, 16, NTLMv2_HMAC, 16)
467 *
468 * Prior to calling this function, the auth instance should be set
469 * via smb_auth_set_info().
470 *
471 * Returns the appropriate session key.
472 */
473 int
smb_auth_gen_session_key(smb_auth_info_t * auth,unsigned char * session_key)474 smb_auth_gen_session_key(smb_auth_info_t *auth, unsigned char *session_key)
475 {
476 int rc;
477
478 if (auth->lmcompatibility_lvl == 2)
479 rc = smb_auth_md4(session_key, auth->hash, SMBAUTH_HASH_SZ);
480 else
481 rc = SMBAUTH_HMACT64((unsigned char *)auth->cs,
482 SMBAUTH_HASH_SZ, (unsigned char *)auth->hash_v2,
483 SMBAUTH_SESSION_KEY_SZ, session_key);
484
485 return (rc);
486 }
487
488 /* 100's of ns between 1/1/1970 and 1/1/1601 */
489 #define NT_TIME_BIAS (134774LL * 24LL * 60LL * 60LL * 10000000LL)
490
491 static uint64_t
unix_micro_to_nt_time(struct timeval * unix_time)492 unix_micro_to_nt_time(struct timeval *unix_time)
493 {
494 uint64_t nt_time;
495
496 nt_time = unix_time->tv_sec;
497 nt_time *= 10000000; /* seconds to 100ns */
498 nt_time += unix_time->tv_usec * 10;
499 return (nt_time + NT_TIME_BIAS);
500 }
501
502 static boolean_t
smb_lm_password_ok(unsigned char * challenge,uint32_t clen,unsigned char * lm_hash,unsigned char * passwd)503 smb_lm_password_ok(
504 unsigned char *challenge,
505 uint32_t clen,
506 unsigned char *lm_hash,
507 unsigned char *passwd)
508 {
509 unsigned char lm_resp[SMBAUTH_LM_RESP_SZ];
510 int rc;
511
512 rc = smb_auth_lm_response(lm_hash, challenge, clen, lm_resp);
513 if (rc != SMBAUTH_SUCCESS)
514 return (B_FALSE);
515
516 return (bcmp(lm_resp, passwd, SMBAUTH_LM_RESP_SZ) == 0);
517 }
518
519 static boolean_t
smb_ntlm_password_ok(unsigned char * challenge,uint32_t clen,unsigned char * ntlm_hash,unsigned char * passwd,unsigned char * session_key)520 smb_ntlm_password_ok(
521 unsigned char *challenge,
522 uint32_t clen,
523 unsigned char *ntlm_hash,
524 unsigned char *passwd,
525 unsigned char *session_key)
526 {
527 unsigned char ntlm_resp[SMBAUTH_LM_RESP_SZ];
528 int rc;
529 boolean_t ok;
530
531 rc = smb_auth_ntlm_response(ntlm_hash, challenge, clen, ntlm_resp);
532 if (rc != SMBAUTH_LM_RESP_SZ)
533 return (B_FALSE);
534
535 ok = (bcmp(ntlm_resp, passwd, SMBAUTH_LM_RESP_SZ) == 0);
536 if (ok && (session_key)) {
537 rc = smb_auth_md4(session_key, ntlm_hash, SMBAUTH_HASH_SZ);
538 if (rc != SMBAUTH_SUCCESS)
539 ok = B_FALSE;
540 }
541 return (ok);
542 }
543
544 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)545 smb_ntlmv2_password_ok(
546 unsigned char *challenge,
547 uint32_t clen,
548 unsigned char *ntlm_hash,
549 unsigned char *passwd,
550 int pwdlen,
551 char *domain,
552 char *username,
553 uchar_t *session_key)
554 {
555 unsigned char *clnt_blob;
556 int clnt_blob_len;
557 unsigned char ntlmv2_hash[SMBAUTH_HASH_SZ];
558 unsigned char *ntlmv2_resp;
559 boolean_t ok = B_FALSE;
560 char *dest[3];
561 int i;
562 int rc;
563
564 clnt_blob_len = pwdlen - SMBAUTH_HASH_SZ;
565 clnt_blob = &passwd[SMBAUTH_HASH_SZ];
566 dest[0] = domain;
567 if ((dest[1] = strdup(domain)) == NULL)
568 return (B_FALSE);
569 (void) smb_strupr(dest[1]);
570 dest[2] = "";
571
572 /*
573 * 15.5.2 The NTLMv2 Password Hash, pg. 279, of the "Implementing CIFS"
574 *
575 * The NTLMv2 Hash is created from:
576 * - NTLM hash
577 * - user's username, and
578 * - the name of the logon destination(i.e. the NetBIOS name of either
579 * the SMB server or NT Domain against which the user is trying to
580 * authenticate.
581 *
582 * Experiments show this is not exactly the case.
583 * For Windows Server 2003, the domain name needs to be included and
584 * converted to uppercase. For Vista, the domain name needs to be
585 * included also, but leave the case alone. And in some cases it needs
586 * to be empty. All three variants are tried here.
587 */
588
589 ntlmv2_resp = (unsigned char *)malloc(SMBAUTH_HASH_SZ + clnt_blob_len);
590 if (ntlmv2_resp == NULL) {
591 free(dest[1]);
592 return (B_FALSE);
593 }
594
595 for (i = 0; i < (sizeof (dest) / sizeof (char *)); i++) {
596 if (smb_auth_ntlmv2_hash(ntlm_hash, username, dest[i],
597 ntlmv2_hash) != SMBAUTH_SUCCESS)
598 break;
599
600 if (smb_auth_v2_response(ntlmv2_hash, challenge,
601 clen, clnt_blob, clnt_blob_len, ntlmv2_resp) < 0)
602 break;
603
604 ok = (bcmp(passwd, ntlmv2_resp, pwdlen) == 0);
605 if (ok && session_key) {
606 rc = SMBAUTH_HMACT64(ntlmv2_resp,
607 SMBAUTH_HASH_SZ, ntlmv2_hash,
608 SMBAUTH_SESSION_KEY_SZ, session_key);
609 if (rc != SMBAUTH_SUCCESS) {
610 ok = B_FALSE;
611 }
612 break;
613 }
614 }
615
616 free(dest[1]);
617 free(ntlmv2_resp);
618 return (ok);
619 }
620
621 static boolean_t
smb_lmv2_password_ok(unsigned char * challenge,uint32_t clen,unsigned char * ntlm_hash,unsigned char * passwd,char * domain,char * username)622 smb_lmv2_password_ok(
623 unsigned char *challenge,
624 uint32_t clen,
625 unsigned char *ntlm_hash,
626 unsigned char *passwd,
627 char *domain,
628 char *username)
629 {
630 unsigned char *clnt_challenge;
631 unsigned char ntlmv2_hash[SMBAUTH_HASH_SZ];
632 unsigned char lmv2_resp[SMBAUTH_LM_RESP_SZ];
633 boolean_t ok = B_FALSE;
634 char *dest[3];
635 int i;
636
637 clnt_challenge = &passwd[SMBAUTH_HASH_SZ];
638 dest[0] = domain;
639 if ((dest[1] = strdup(domain)) == NULL)
640 return (B_FALSE);
641 (void) smb_strupr(dest[1]);
642 dest[2] = "";
643
644 /*
645 * 15.5.2 The NTLMv2 Password Hash, pg. 279, of the "Implementing CIFS"
646 *
647 * The NTLMv2 Hash is created from:
648 * - NTLM hash
649 * - user's username, and
650 * - the name of the logon destination(i.e. the NetBIOS name of either
651 * the SMB server or NT Domain against which the suer is trying to
652 * authenticate.
653 *
654 * Experiments show this is not exactly the case.
655 * For Windows Server 2003, the domain name needs to be included and
656 * converted to uppercase. For Vista, the domain name needs to be
657 * included also, but leave the case alone. And in some cases it needs
658 * to be empty. All three variants are tried here.
659 */
660
661 for (i = 0; i < (sizeof (dest) / sizeof (char *)); i++) {
662 if (smb_auth_ntlmv2_hash(ntlm_hash, username, dest[i],
663 ntlmv2_hash) != SMBAUTH_SUCCESS)
664 break;
665
666 if (smb_auth_v2_response(ntlmv2_hash, challenge,
667 clen, clnt_challenge, SMBAUTH_V2_CLNT_CHALLENGE_SZ,
668 lmv2_resp) < 0)
669 break;
670
671 ok = (bcmp(passwd, lmv2_resp, SMBAUTH_LM_RESP_SZ) == 0);
672 if (ok)
673 break;
674 }
675
676 free(dest[1]);
677 return (ok);
678 }
679
680 /*
681 * smb_auth_validate_lm
682 *
683 * Validates given LM/LMv2 client response, passed in passwd arg, against
684 * stored user's password, passed in smbpw
685 *
686 * If LM level <=3 server accepts LM responses, otherwise LMv2
687 */
688 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)689 smb_auth_validate_lm(
690 unsigned char *challenge,
691 uint32_t clen,
692 smb_passwd_t *smbpw,
693 unsigned char *passwd,
694 int pwdlen,
695 char *domain,
696 char *username)
697 {
698 boolean_t ok = B_FALSE;
699 int64_t lmlevel;
700
701 if (pwdlen != SMBAUTH_LM_RESP_SZ)
702 return (B_FALSE);
703
704 if (smb_config_getnum(SMB_CI_LM_LEVEL, &lmlevel) != SMBD_SMF_OK)
705 return (B_FALSE);
706
707 if (lmlevel <= 3) {
708 ok = smb_lm_password_ok(challenge, clen, smbpw->pw_lmhash,
709 passwd);
710 }
711
712 if (!ok)
713 ok = smb_lmv2_password_ok(challenge, clen, smbpw->pw_nthash,
714 passwd, domain, username);
715
716 return (ok);
717 }
718
719 /*
720 * smb_auth_validate_nt
721 *
722 * Validates given NTLM/NTLMv2 client response, passed in passwd arg, against
723 * stored user's password, passed in smbpw
724 *
725 * If LM level <=4 server accepts NTLM/NTLMv2 responses, otherwise only NTLMv2
726 */
727 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)728 smb_auth_validate_nt(
729 unsigned char *challenge,
730 uint32_t clen,
731 smb_passwd_t *smbpw,
732 unsigned char *passwd,
733 int pwdlen,
734 char *domain,
735 char *username,
736 uchar_t *session_key)
737 {
738 int64_t lmlevel;
739 boolean_t ok;
740
741 if (smb_config_getnum(SMB_CI_LM_LEVEL, &lmlevel) != SMBD_SMF_OK)
742 return (B_FALSE);
743
744 if ((lmlevel == 5) && (pwdlen <= SMBAUTH_LM_RESP_SZ))
745 return (B_FALSE);
746
747 if (pwdlen > SMBAUTH_LM_RESP_SZ)
748 ok = smb_ntlmv2_password_ok(challenge, clen,
749 smbpw->pw_nthash, passwd, pwdlen,
750 domain, username, session_key);
751 else
752 ok = smb_ntlm_password_ok(challenge, clen,
753 smbpw->pw_nthash, passwd, session_key);
754
755 return (ok);
756 }
757