xref: /illumos-gate/usr/src/lib/smbsrv/libmlsvc/common/netr_logon.c (revision 856f710c9dc323b39da5935194d7928ffb99b67f)
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 /*
23  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
25  */
26 
27 /*
28  * NETR SamLogon and SamLogoff RPC client functions.
29  */
30 
31 #include <stdio.h>
32 #include <strings.h>
33 #include <stdlib.h>
34 #include <time.h>
35 #include <alloca.h>
36 #include <unistd.h>
37 #include <netdb.h>
38 #include <thread.h>
39 
40 #include <libmlrpc/libmlrpc.h>
41 #include <smbsrv/libsmb.h>
42 #include <smbsrv/libmlsvc.h>
43 #include <smbsrv/ndl/netlogon.ndl>
44 #include <smbsrv/netrauth.h>
45 #include <smbsrv/smbinfo.h>
46 #include <smbsrv/smb_token.h>
47 #include <mlsvc.h>
48 
49 static uint32_t netlogon_logon(smb_logon_t *, smb_token_t *, smb_domainex_t *);
50 static uint32_t netr_server_samlogon(mlsvc_handle_t *, netr_info_t *, char *,
51     smb_logon_t *, smb_token_t *);
52 static void netr_invalidate_chain(void);
53 static void netr_interactive_samlogon(netr_info_t *, smb_logon_t *,
54     struct netr_logon_info1 *);
55 static void netr_network_samlogon(ndr_heap_t *, netr_info_t *,
56     smb_logon_t *, struct netr_logon_info2 *);
57 static void netr_setup_identity(ndr_heap_t *, smb_logon_t *,
58     netr_logon_id_t *);
59 static boolean_t netr_isadmin(struct netr_validation_info3 *);
60 static uint32_t netr_setup_domain_groups(struct netr_validation_info3 *,
61     smb_ids_t *);
62 static uint32_t netr_setup_token_info3(struct netr_validation_info3 *,
63     smb_token_t *);
64 static uint32_t netr_setup_token_wingrps(struct netr_validation_info3 *,
65     smb_token_t *);
66 
67 /*
68  * Shared with netr_auth.c
69  */
70 extern netr_info_t netr_global_info;
71 
72 static mutex_t netlogon_mutex;
73 static cond_t netlogon_cv;
74 static boolean_t netlogon_busy = B_FALSE;
75 static boolean_t netlogon_abort = B_FALSE;
76 
77 /*
78  * Helper for Kerberos authentication
79  */
80 uint32_t
81 smb_decode_krb5_pac(smb_token_t *token, char *data, uint_t len)
82 {
83 	struct krb5_validation_info info;
84 	ndr_buf_t *nbuf;
85 	uint32_t status = NT_STATUS_NO_MEMORY;
86 	int rc;
87 
88 	bzero(&info, sizeof (info));
89 
90 	/* Need to keep this until we're done with &info */
91 	nbuf = ndr_buf_init(&TYPEINFO(netr_interface));
92 	if (nbuf == NULL)
93 		goto out;
94 
95 	rc = ndr_buf_decode(nbuf, NDR_PTYPE_PAC,
96 	    NETR_OPNUM_decode_krb5_pac, data, len, &info);
97 	if (rc != NDR_DRC_OK) {
98 		status = RPC_NT_PROTOCOL_ERROR;
99 		goto out;
100 	}
101 
102 	status = netr_setup_token_info3(&info.info3, token);
103 
104 	/* Deal with the "resource groups"? */
105 
106 
107 out:
108 	if (nbuf != NULL)
109 		ndr_buf_fini(nbuf);
110 
111 	return (status);
112 }
113 
114 /*
115  * Code factored out of netr_setup_token()
116  */
117 static uint32_t
118 netr_setup_token_info3(struct netr_validation_info3 *info3,
119     smb_token_t *token)
120 {
121 	smb_sid_t *domsid;
122 
123 	domsid = (smb_sid_t *)info3->LogonDomainId;
124 
125 	token->tkn_user.i_sid = smb_sid_splice(domsid,
126 	    info3->UserId);
127 	if (token->tkn_user.i_sid == NULL)
128 		goto errout;
129 
130 	token->tkn_primary_grp.i_sid = smb_sid_splice(domsid,
131 	    info3->PrimaryGroupId);
132 	if (token->tkn_primary_grp.i_sid == NULL)
133 		goto errout;
134 
135 	if (info3->EffectiveName.str) {
136 		token->tkn_account_name =
137 		    strdup((char *)info3->EffectiveName.str);
138 		if (token->tkn_account_name == NULL)
139 			goto errout;
140 	}
141 
142 	if (info3->LogonDomainName.str) {
143 		token->tkn_domain_name =
144 		    strdup((char *)info3->LogonDomainName.str);
145 		if (token->tkn_domain_name == NULL)
146 			goto errout;
147 	}
148 
149 	return (netr_setup_token_wingrps(info3, token));
150 errout:
151 	return (NT_STATUS_INSUFF_SERVER_RESOURCES);
152 }
153 
154 /*
155  * Abort impending domain logon requests.
156  */
157 void
158 smb_logon_abort(void)
159 {
160 	(void) mutex_lock(&netlogon_mutex);
161 	if (netlogon_busy && !netlogon_abort)
162 		syslog(LOG_DEBUG, "logon abort");
163 	netlogon_abort = B_TRUE;
164 	(void) cond_broadcast(&netlogon_cv);
165 	(void) mutex_unlock(&netlogon_mutex);
166 }
167 
168 /*
169  * This is the entry point for authenticating domain users.
170  *
171  * If we are not going to attempt to authenticate the user,
172  * this function must return without updating the status.
173  *
174  * If the user is successfully authenticated, we build an
175  * access token and the status will be NT_STATUS_SUCCESS.
176  * Otherwise, the token contents are invalid.
177  *
178  * This will retry a few times for errors indicating that the
179  * current DC might have gone off-line or become too busy etc.
180  * With such errors, smb_ddiscover_bad_dc is called and then
181  * the smb_domain_getinfo call here waits for new DC info.
182  */
183 int smb_netr_logon_retries = 3;
184 void
185 smb_logon_domain(smb_logon_t *user_info, smb_token_t *token)
186 {
187 	smb_domainex_t	di;
188 	uint32_t	status;
189 	int		retries = smb_netr_logon_retries;
190 
191 	if (user_info->lg_secmode != SMB_SECMODE_DOMAIN)
192 		return;
193 
194 	if (user_info->lg_domain_type == SMB_DOMAIN_LOCAL)
195 		return;
196 
197 	while (--retries > 0) {
198 
199 		if (!smb_domain_getinfo(&di)) {
200 			syslog(LOG_ERR, "logon DC getinfo failed");
201 			status = NT_STATUS_NO_LOGON_SERVERS;
202 			goto out;
203 		}
204 
205 		(void) mutex_lock(&netlogon_mutex);
206 		while (netlogon_busy && !netlogon_abort)
207 			(void) cond_wait(&netlogon_cv, &netlogon_mutex);
208 
209 		if (netlogon_abort) {
210 			(void) mutex_unlock(&netlogon_mutex);
211 			status = NT_STATUS_REQUEST_ABORTED;
212 			goto out;
213 		}
214 
215 		netlogon_busy = B_TRUE;
216 		(void) mutex_unlock(&netlogon_mutex);
217 
218 		status = netlogon_logon(user_info, token, &di);
219 
220 		(void) mutex_lock(&netlogon_mutex);
221 		netlogon_busy = B_FALSE;
222 		if (netlogon_abort)
223 			status = NT_STATUS_REQUEST_ABORTED;
224 		(void) cond_signal(&netlogon_cv);
225 		(void) mutex_unlock(&netlogon_mutex);
226 
227 		switch (status) {
228 		case NT_STATUS_BAD_NETWORK_PATH:
229 		case NT_STATUS_BAD_NETWORK_NAME:
230 		case RPC_NT_SERVER_TOO_BUSY:
231 			/*
232 			 * May retry with a new DC, or if we're
233 			 * out of retries, will return...
234 			 */
235 			status = NT_STATUS_NO_LOGON_SERVERS;
236 			break;
237 		default:
238 			goto out;
239 		}
240 	}
241 
242 out:
243 	if (status != NT_STATUS_SUCCESS)
244 		syslog(LOG_INFO, "logon[%s\\%s]: %s", user_info->lg_e_domain,
245 		    user_info->lg_e_username, xlate_nt_status(status));
246 	user_info->lg_status = status;
247 }
248 
249 /*
250  * Run a netr_server_samlogon call, dealing with the possible need to
251  * re-establish the NetLogon credential chain.  If that fails, return
252  * NT_STATUS_DOMAIN_TRUST_INCONSISTENT indicating the machine account
253  * needs it's password reset (or whatever).  Other errors are from the
254  * netr_server_samlogon() call including the many possibilities listed
255  * above that function.
256  */
257 static uint32_t
258 netlogon_logon(smb_logon_t *user_info, smb_token_t *token, smb_domainex_t *di)
259 {
260 	char server[MAXHOSTNAMELEN];
261 	mlsvc_handle_t netr_handle;
262 	uint32_t status;
263 	boolean_t did_reauth = B_FALSE;
264 
265 	/*
266 	 * This netr_open call does the work to connect to the DC,
267 	 * get the IPC share, open the named pipe, RPC bind, etc.
268 	 */
269 	status = netr_open(di->d_dci.dc_name, di->d_primary.di_nbname,
270 	    &netr_handle);
271 	if (status != 0) {
272 		syslog(LOG_ERR, "netlogon remote open failed (%s)",
273 		    xlate_nt_status(status));
274 		return (status);
275 	}
276 
277 	if (di->d_dci.dc_name[0] != '\0' &&
278 	    (*netr_global_info.server != '\0')) {
279 		(void) snprintf(server, sizeof (server),
280 		    "\\\\%s", di->d_dci.dc_name);
281 		if (strncasecmp(netr_global_info.server,
282 		    server, strlen(server)) != 0)
283 			netr_invalidate_chain();
284 	}
285 
286 reauth:
287 	if ((netr_global_info.flags & NETR_FLG_VALID) == 0 ||
288 	    !smb_match_netlogon_seqnum()) {
289 		/*
290 		 * This does netr_server_req_challenge() and
291 		 * netr_server_authenticate2(), updating the
292 		 * current netlogon sequence number.
293 		 */
294 		status = netlogon_auth(di->d_dci.dc_name, &netr_handle,
295 		    NETR_FLG_NULL);
296 
297 		if (status != 0) {
298 			syslog(LOG_ERR, "netlogon remote auth failed (%s)",
299 			    xlate_nt_status(status));
300 			(void) netr_close(&netr_handle);
301 			return (NT_STATUS_DOMAIN_TRUST_INCONSISTENT);
302 		}
303 
304 		netr_global_info.flags |= NETR_FLG_VALID;
305 	}
306 
307 	status = netr_server_samlogon(&netr_handle,
308 	    &netr_global_info, di->d_dci.dc_name, user_info, token);
309 
310 	if (status == NT_STATUS_INSUFFICIENT_LOGON_INFO) {
311 		if (!did_reauth) {
312 			/* Call netlogon_auth() again, just once. */
313 			did_reauth = B_TRUE;
314 			goto reauth;
315 		}
316 		status = NT_STATUS_DOMAIN_TRUST_INCONSISTENT;
317 	}
318 
319 	(void) netr_close(&netr_handle);
320 
321 	return (status);
322 }
323 
324 /*
325  * Helper for mlsvc_netlogon
326  *
327  * Call netlogon_auth with appropriate locks etc.
328  * Serialize like smb_logon_domain does for
329  * netlogon_logon / netlogon_auth
330  */
331 uint32_t
332 smb_netlogon_check(char *server, char *domain)
333 {
334 	mlsvc_handle_t netr_handle;
335 	uint32_t	status;
336 
337 	(void) mutex_lock(&netlogon_mutex);
338 	while (netlogon_busy)
339 		(void) cond_wait(&netlogon_cv, &netlogon_mutex);
340 
341 	netlogon_busy = B_TRUE;
342 	(void) mutex_unlock(&netlogon_mutex);
343 
344 	/*
345 	 * This section like netlogon_logon(), but only does
346 	 * one pass and no netr_server_samlogon call.
347 	 */
348 
349 	status = netr_open(server, domain,
350 	    &netr_handle);
351 	if (status != 0) {
352 		syslog(LOG_ERR, "netlogon remote open failed (%s)",
353 		    xlate_nt_status(status));
354 		goto unlock_out;
355 	}
356 
357 	if ((netr_global_info.flags & NETR_FLG_VALID) == 0 ||
358 	    !smb_match_netlogon_seqnum()) {
359 		/*
360 		 * This does netr_server_req_challenge() and
361 		 * netr_server_authenticate2(), updating the
362 		 * current netlogon sequence number.
363 		 */
364 		status = netlogon_auth(server, &netr_handle,
365 		    NETR_FLG_NULL);
366 		if (status != 0) {
367 			syslog(LOG_ERR, "netlogon remote auth failed (%s)",
368 			    xlate_nt_status(status));
369 		} else {
370 			netr_global_info.flags |= NETR_FLG_VALID;
371 		}
372 	}
373 
374 	(void) netr_close(&netr_handle);
375 
376 unlock_out:
377 	(void) mutex_lock(&netlogon_mutex);
378 	netlogon_busy = B_FALSE;
379 	(void) cond_signal(&netlogon_cv);
380 	(void) mutex_unlock(&netlogon_mutex);
381 
382 	return (status);
383 }
384 
385 static uint32_t
386 netr_setup_token(struct netr_validation_info3 *info3, smb_logon_t *user_info,
387     netr_info_t *netr_info, smb_token_t *token)
388 {
389 	char *username, *domain;
390 	unsigned char rc4key[SMBAUTH_SESSION_KEY_SZ];
391 	smb_sid_t *domsid;
392 	uint32_t status;
393 	char nbdomain[NETBIOS_NAME_SZ];
394 
395 	domsid = (smb_sid_t *)info3->LogonDomainId;
396 
397 	token->tkn_user.i_sid = smb_sid_splice(domsid, info3->UserId);
398 	if (token->tkn_user.i_sid == NULL)
399 		return (NT_STATUS_NO_MEMORY);
400 
401 	token->tkn_primary_grp.i_sid = smb_sid_splice(domsid,
402 	    info3->PrimaryGroupId);
403 	if (token->tkn_primary_grp.i_sid == NULL)
404 		return (NT_STATUS_NO_MEMORY);
405 
406 	username = (info3->EffectiveName.str)
407 	    ? (char *)info3->EffectiveName.str : user_info->lg_e_username;
408 
409 	if (info3->LogonDomainName.str) {
410 		domain = (char *)info3->LogonDomainName.str;
411 	} else if (*user_info->lg_e_domain != '\0') {
412 		domain = user_info->lg_e_domain;
413 	} else {
414 		(void) smb_getdomainname(nbdomain, sizeof (nbdomain));
415 		domain = nbdomain;
416 	}
417 
418 	if (username)
419 		token->tkn_account_name = strdup(username);
420 	if (domain)
421 		token->tkn_domain_name = strdup(domain);
422 
423 	if (token->tkn_account_name == NULL || token->tkn_domain_name == NULL)
424 		return (NT_STATUS_NO_MEMORY);
425 
426 	status = netr_setup_token_wingrps(info3, token);
427 	if (status != NT_STATUS_SUCCESS)
428 		return (status);
429 
430 	/*
431 	 * The UserSessionKey in NetrSamLogon RPC is obfuscated using the
432 	 * session key obtained in the NETLOGON credential chain.
433 	 * An 8 byte session key is zero extended to 16 bytes. This 16 byte
434 	 * key is the key to the RC4 algorithm. The RC4 byte stream is
435 	 * exclusively ored with the 16 byte UserSessionKey to recover
436 	 * the the clear form.
437 	 */
438 	if ((token->tkn_ssnkey.val = malloc(SMBAUTH_SESSION_KEY_SZ)) == NULL)
439 		return (NT_STATUS_NO_MEMORY);
440 	token->tkn_ssnkey.len = SMBAUTH_SESSION_KEY_SZ;
441 	bzero(rc4key, SMBAUTH_SESSION_KEY_SZ);
442 	bcopy(netr_info->session_key.key, rc4key, netr_info->session_key.len);
443 	bcopy(info3->UserSessionKey.data, token->tkn_ssnkey.val,
444 	    SMBAUTH_SESSION_KEY_SZ);
445 	rand_hash((unsigned char *)token->tkn_ssnkey.val,
446 	    SMBAUTH_SESSION_KEY_SZ, rc4key, SMBAUTH_SESSION_KEY_SZ);
447 
448 	return (NT_STATUS_SUCCESS);
449 }
450 
451 /*
452  * netr_server_samlogon
453  *
454  * NetrServerSamLogon RPC: interactive or network. It is assumed that
455  * we have already authenticated with the PDC. If everything works,
456  * we build a user info structure and return it, where the caller will
457  * probably build an access token.
458  *
459  * Returns an NT status. There are numerous possibilities here.
460  * For example:
461  *	NT_STATUS_INVALID_INFO_CLASS
462  *	NT_STATUS_INVALID_PARAMETER
463  *	NT_STATUS_ACCESS_DENIED
464  *	NT_STATUS_PASSWORD_MUST_CHANGE
465  *	NT_STATUS_NO_SUCH_USER
466  *	NT_STATUS_WRONG_PASSWORD
467  *	NT_STATUS_LOGON_FAILURE
468  *	NT_STATUS_ACCOUNT_RESTRICTION
469  *	NT_STATUS_INVALID_LOGON_HOURS
470  *	NT_STATUS_INVALID_WORKSTATION
471  *	NT_STATUS_INTERNAL_ERROR
472  *	NT_STATUS_PASSWORD_EXPIRED
473  *	NT_STATUS_ACCOUNT_DISABLED
474  */
475 uint32_t
476 netr_server_samlogon(mlsvc_handle_t *netr_handle, netr_info_t *netr_info,
477     char *server, smb_logon_t *user_info, smb_token_t *token)
478 {
479 	struct netr_SamLogon arg;
480 	struct netr_authenticator auth;
481 	struct netr_authenticator ret_auth;
482 	struct netr_logon_info1 info1;
483 	struct netr_logon_info2 info2;
484 	struct netr_validation_info3 *info3;
485 	ndr_heap_t *heap;
486 	int opnum;
487 	int rc, len;
488 	uint32_t status;
489 
490 	bzero(&arg, sizeof (struct netr_SamLogon));
491 	opnum = NETR_OPNUM_SamLogon;
492 
493 	/*
494 	 * Should we get the server and hostname from netr_info?
495 	 */
496 
497 	len = strlen(server) + 4;
498 	arg.servername = ndr_rpc_malloc(netr_handle, len);
499 	arg.hostname = ndr_rpc_malloc(netr_handle, NETBIOS_NAME_SZ);
500 	if (arg.servername == NULL || arg.hostname == NULL) {
501 		ndr_rpc_release(netr_handle);
502 		return (NT_STATUS_INTERNAL_ERROR);
503 	}
504 
505 	(void) snprintf((char *)arg.servername, len, "\\\\%s", server);
506 	if (smb_getnetbiosname((char *)arg.hostname, NETBIOS_NAME_SZ) != 0) {
507 		ndr_rpc_release(netr_handle);
508 		return (NT_STATUS_INTERNAL_ERROR);
509 	}
510 
511 	rc = netr_setup_authenticator(netr_info, &auth, &ret_auth);
512 	if (rc != SMBAUTH_SUCCESS) {
513 		ndr_rpc_release(netr_handle);
514 		return (NT_STATUS_INTERNAL_ERROR);
515 	}
516 
517 	arg.auth = &auth;
518 	arg.ret_auth = &ret_auth;
519 	arg.validation_level = NETR_VALIDATION_LEVEL3;
520 	arg.logon_info.logon_level = user_info->lg_level;
521 	arg.logon_info.switch_value = user_info->lg_level;
522 
523 	heap = ndr_rpc_get_heap(netr_handle);
524 
525 	switch (user_info->lg_level) {
526 	case NETR_INTERACTIVE_LOGON:
527 		netr_setup_identity(heap, user_info, &info1.identity);
528 		netr_interactive_samlogon(netr_info, user_info, &info1);
529 		arg.logon_info.ru.info1 = &info1;
530 		break;
531 
532 	case NETR_NETWORK_LOGON:
533 		if (user_info->lg_challenge_key.len < 8 ||
534 		    user_info->lg_challenge_key.val == NULL) {
535 			ndr_rpc_release(netr_handle);
536 			return (NT_STATUS_INVALID_PARAMETER);
537 		}
538 		netr_setup_identity(heap, user_info, &info2.identity);
539 		netr_network_samlogon(heap, netr_info, user_info, &info2);
540 		arg.logon_info.ru.info2 = &info2;
541 		break;
542 
543 	default:
544 		ndr_rpc_release(netr_handle);
545 		return (NT_STATUS_INVALID_PARAMETER);
546 	}
547 
548 	rc = ndr_rpc_call(netr_handle, opnum, &arg);
549 	if (rc != 0) {
550 		bzero(netr_info, sizeof (netr_info_t));
551 		status = NT_STATUS_INVALID_PARAMETER;
552 	} else if (arg.status != 0) {
553 		status = NT_SC_VALUE(arg.status);
554 
555 		/*
556 		 * We need to validate the chain even though we have
557 		 * a non-zero status. If the status is ACCESS_DENIED
558 		 * this will trigger a new credential chain. However,
559 		 * a valid credential is returned with some status
560 		 * codes; for example, WRONG_PASSWORD.
561 		 */
562 		(void) netr_validate_chain(netr_info, arg.ret_auth);
563 	} else {
564 		status = netr_validate_chain(netr_info, arg.ret_auth);
565 		if (status == NT_STATUS_INSUFFICIENT_LOGON_INFO) {
566 			ndr_rpc_release(netr_handle);
567 			return (status);
568 		}
569 
570 		info3 = arg.ru.info3;
571 		status = netr_setup_token(info3, user_info, netr_info, token);
572 	}
573 
574 	ndr_rpc_release(netr_handle);
575 	return (status);
576 }
577 
578 /*
579  * netr_interactive_samlogon
580  *
581  * Set things up for an interactive SamLogon. Copy the NT and LM
582  * passwords to the logon structure and hash them with the session
583  * key.
584  */
585 static void
586 netr_interactive_samlogon(netr_info_t *netr_info, smb_logon_t *user_info,
587     struct netr_logon_info1 *info1)
588 {
589 	BYTE key[NETR_OWF_PASSWORD_SZ];
590 
591 	(void) memcpy(&info1->lm_owf_password,
592 	    user_info->lg_lm_password.val, sizeof (netr_owf_password_t));
593 
594 	(void) memcpy(&info1->nt_owf_password,
595 	    user_info->lg_nt_password.val, sizeof (netr_owf_password_t));
596 
597 	(void) memset(key, 0, NETR_OWF_PASSWORD_SZ);
598 	(void) memcpy(key, netr_info->session_key.key,
599 	    netr_info->session_key.len);
600 
601 	rand_hash((unsigned char *)&info1->lm_owf_password,
602 	    NETR_OWF_PASSWORD_SZ, key, NETR_OWF_PASSWORD_SZ);
603 
604 	rand_hash((unsigned char *)&info1->nt_owf_password,
605 	    NETR_OWF_PASSWORD_SZ, key, NETR_OWF_PASSWORD_SZ);
606 }
607 
608 /*
609  * netr_network_samlogon
610  *
611  * Set things up for a network SamLogon.  We provide a copy of the random
612  * challenge, that we sent to the client, to the domain controller.  This
613  * is the key that the client will have used to encrypt the NT and LM
614  * passwords.  Note that Windows 9x clients may not provide both passwords.
615  */
616 /*ARGSUSED*/
617 static void
618 netr_network_samlogon(ndr_heap_t *heap, netr_info_t *netr_info,
619     smb_logon_t *user_info, struct netr_logon_info2 *info2)
620 {
621 	uint32_t len;
622 
623 	if (user_info->lg_challenge_key.len >= 8 &&
624 	    user_info->lg_challenge_key.val != 0) {
625 		bcopy(user_info->lg_challenge_key.val,
626 		    info2->lm_challenge.data, 8);
627 	} else {
628 		bzero(info2->lm_challenge.data, 8);
629 	}
630 
631 	if ((len = user_info->lg_nt_password.len) != 0) {
632 		ndr_heap_mkvcb(heap, user_info->lg_nt_password.val, len,
633 		    (ndr_vcbuf_t *)&info2->nt_response);
634 	} else {
635 		bzero(&info2->nt_response, sizeof (netr_vcbuf_t));
636 	}
637 
638 	if ((len = user_info->lg_lm_password.len) != 0) {
639 		ndr_heap_mkvcb(heap, user_info->lg_lm_password.val, len,
640 		    (ndr_vcbuf_t *)&info2->lm_response);
641 	} else {
642 		bzero(&info2->lm_response, sizeof (netr_vcbuf_t));
643 	}
644 }
645 
646 /*
647  * netr_setup_authenticator
648  *
649  * Set up the request and return authenticators. A new credential is
650  * generated from the session key, the current client credential and
651  * the current time, i.e.
652  *
653  *		NewCredential = Cred(SessionKey, OldCredential, time);
654  *
655  * The timestamp, which is used as a random seed, is stored in both
656  * the request and return authenticators.
657  *
658  * If any difficulties occur using the cryptographic framework, the
659  * function returns SMBAUTH_FAILURE.  Otherwise SMBAUTH_SUCCESS is
660  * returned.
661  */
662 int
663 netr_setup_authenticator(netr_info_t *netr_info,
664     struct netr_authenticator *auth, struct netr_authenticator *ret_auth)
665 {
666 	bzero(auth, sizeof (struct netr_authenticator));
667 
668 	netr_info->timestamp = time(0);
669 	auth->timestamp = netr_info->timestamp;
670 
671 	if (netr_gen_credentials(netr_info->session_key.key,
672 	    &netr_info->client_credential,
673 	    netr_info->timestamp,
674 	    (netr_cred_t *)&auth->credential) != SMBAUTH_SUCCESS)
675 		return (SMBAUTH_FAILURE);
676 
677 	if (ret_auth) {
678 		bzero(ret_auth, sizeof (struct netr_authenticator));
679 		ret_auth->timestamp = netr_info->timestamp;
680 	}
681 
682 	return (SMBAUTH_SUCCESS);
683 }
684 
685 /*
686  * Validate the returned credentials and update the credential chain.
687  * The server returns an updated client credential rather than a new
688  * server credential.  The server uses (timestamp + 1) when generating
689  * the credential.
690  *
691  * Generate the new seed for the credential chain. The new seed is
692  * formed by adding (timestamp + 1) to the current client credential.
693  * The only quirk is the uint32_t style addition.
694  *
695  * Returns NT_STATUS_INSUFFICIENT_LOGON_INFO if auth->credential is a
696  * NULL pointer. The Authenticator field of the SamLogon response packet
697  * sent by the Samba 3 PDC always return NULL pointer if the received
698  * SamLogon request is not immediately followed by the ServerReqChallenge
699  * and ServerAuthenticate2 requests.
700  *
701  * Returns NT_STATUS_SUCCESS if the server returned a valid credential.
702  * Otherwise we retirm NT_STATUS_UNSUCCESSFUL.
703  */
704 uint32_t
705 netr_validate_chain(netr_info_t *netr_info, struct netr_authenticator *auth)
706 {
707 	netr_cred_t cred;
708 	uint32_t result = NT_STATUS_SUCCESS;
709 	uint32_t *dwp;
710 
711 	++netr_info->timestamp;
712 
713 	if (netr_gen_credentials(netr_info->session_key.key,
714 	    &netr_info->client_credential,
715 	    netr_info->timestamp, &cred) != SMBAUTH_SUCCESS)
716 		return (NT_STATUS_INTERNAL_ERROR);
717 
718 	if (&auth->credential == 0) {
719 		/*
720 		 * If the validation fails, destroy the credential chain.
721 		 * This should trigger a new authentication chain.
722 		 */
723 		bzero(netr_info, sizeof (netr_info_t));
724 		return (NT_STATUS_INSUFFICIENT_LOGON_INFO);
725 	}
726 
727 	result = memcmp(&cred, &auth->credential, sizeof (netr_cred_t));
728 	if (result != 0) {
729 		/*
730 		 * If the validation fails, destroy the credential chain.
731 		 * This should trigger a new authentication chain.
732 		 */
733 		bzero(netr_info, sizeof (netr_info_t));
734 		result = NT_STATUS_UNSUCCESSFUL;
735 	} else {
736 		/*
737 		 * Otherwise generate the next step in the chain.
738 		 */
739 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
740 		dwp = (uint32_t *)&netr_info->client_credential;
741 		dwp[0] += netr_info->timestamp;
742 
743 		netr_info->flags |= NETR_FLG_VALID;
744 	}
745 
746 	return (result);
747 }
748 
749 /*
750  * netr_invalidate_chain
751  *
752  * Mark the credential chain as invalid so that it will be recreated
753  * on the next attempt.
754  */
755 static void
756 netr_invalidate_chain(void)
757 {
758 	netr_global_info.flags &= ~NETR_FLG_VALID;
759 }
760 
761 /*
762  * netr_setup_identity
763  *
764  * Set up the client identity information. All of this information is
765  * specifically related to the client user and workstation attempting
766  * to access this system. It may not be in our primary domain.
767  *
768  * I don't know what logon_id is, it seems to be a unique identifier.
769  * Increment it before each use.
770  */
771 static void
772 netr_setup_identity(ndr_heap_t *heap, smb_logon_t *user_info,
773     netr_logon_id_t *identity)
774 {
775 	static mutex_t logon_id_mutex;
776 	static uint32_t logon_id;
777 
778 	(void) mutex_lock(&logon_id_mutex);
779 
780 	if (logon_id == 0)
781 		logon_id = 0xDCD0;
782 
783 	++logon_id;
784 	user_info->lg_logon_id = logon_id;
785 
786 	(void) mutex_unlock(&logon_id_mutex);
787 
788 	/*
789 	 * [MS-APDS] 3.1.5.2 "NTLM Network Logon" says to set
790 	 * ParameterControl to the 'E' + 'K' bits.  Those are:
791 	 * (1 << 5) | (1 << 11), a.k.a
792 	 */
793 	identity->parameter_control =
794 	    MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT |
795 	    MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT;
796 	identity->logon_id.LowPart = logon_id;
797 	identity->logon_id.HighPart = 0;
798 
799 	ndr_heap_mkvcs(heap, user_info->lg_domain,
800 	    (ndr_vcstr_t *)&identity->domain_name);
801 
802 	ndr_heap_mkvcs(heap, user_info->lg_username,
803 	    (ndr_vcstr_t *)&identity->username);
804 
805 	/*
806 	 * Some systems prefix the client workstation name with \\.
807 	 * It doesn't seem to make any difference whether it's there
808 	 * or not.
809 	 */
810 	ndr_heap_mkvcs(heap, user_info->lg_workstation,
811 	    (ndr_vcstr_t *)&identity->workstation);
812 }
813 
814 /*
815  * Sets up domain, local and well-known group membership for the given
816  * token. Two assumptions have been made here:
817  *
818  *   a) token already contains a valid user SID so that group
819  *      memberships can be established
820  *
821  *   b) token belongs to a domain user
822  */
823 static uint32_t
824 netr_setup_token_wingrps(struct netr_validation_info3 *info3,
825     smb_token_t *token)
826 {
827 	smb_ids_t tkn_grps;
828 	uint32_t status;
829 
830 	tkn_grps.i_cnt = 0;
831 	tkn_grps.i_ids = NULL;
832 
833 	status = netr_setup_domain_groups(info3, &tkn_grps);
834 	if (status != NT_STATUS_SUCCESS) {
835 		smb_ids_free(&tkn_grps);
836 		return (status);
837 	}
838 
839 	status = smb_sam_usr_groups(token->tkn_user.i_sid, &tkn_grps);
840 	if (status != NT_STATUS_SUCCESS) {
841 		smb_ids_free(&tkn_grps);
842 		return (status);
843 	}
844 
845 	if (netr_isadmin(info3))
846 		token->tkn_flags |= SMB_ATF_ADMIN;
847 
848 	status = smb_wka_token_groups(token->tkn_flags, &tkn_grps);
849 	if (status == NT_STATUS_SUCCESS)
850 		token->tkn_win_grps = tkn_grps;
851 	else
852 		smb_ids_free(&tkn_grps);
853 
854 	return (status);
855 }
856 
857 /*
858  * Converts groups information in the returned structure by domain controller
859  * (info3) to an internal representation (gids)
860  */
861 static uint32_t
862 netr_setup_domain_groups(struct netr_validation_info3 *info3, smb_ids_t *gids)
863 {
864 	smb_sid_t *domain_sid;
865 	smb_id_t *ids;
866 	int i, total_cnt;
867 
868 	if ((i = info3->GroupCount) == 0)
869 		i++;
870 	i += info3->SidCount;
871 
872 	total_cnt = gids->i_cnt + i;
873 
874 	gids->i_ids = realloc(gids->i_ids, total_cnt * sizeof (smb_id_t));
875 	if (gids->i_ids == NULL)
876 		return (NT_STATUS_NO_MEMORY);
877 
878 	domain_sid = (smb_sid_t *)info3->LogonDomainId;
879 
880 	ids = gids->i_ids + gids->i_cnt;
881 	for (i = 0; i < info3->GroupCount; i++, gids->i_cnt++, ids++) {
882 		ids->i_sid = smb_sid_splice(domain_sid, info3->GroupIds[i].rid);
883 		if (ids->i_sid == NULL)
884 			return (NT_STATUS_NO_MEMORY);
885 
886 		ids->i_attrs = info3->GroupIds[i].attributes;
887 	}
888 
889 	if (info3->GroupCount == 0) {
890 		/*
891 		 * if there's no global group should add the primary group.
892 		 */
893 		ids->i_sid = smb_sid_splice(domain_sid, info3->PrimaryGroupId);
894 		if (ids->i_sid == NULL)
895 			return (NT_STATUS_NO_MEMORY);
896 
897 		ids->i_attrs = 0x7;
898 		gids->i_cnt++;
899 		ids++;
900 	}
901 
902 	/* Add the extra SIDs */
903 	for (i = 0; i < info3->SidCount; i++, gids->i_cnt++, ids++) {
904 		ids->i_sid = smb_sid_dup((smb_sid_t *)info3->ExtraSids[i].sid);
905 		if (ids->i_sid == NULL)
906 			return (NT_STATUS_NO_MEMORY);
907 
908 		ids->i_attrs = info3->ExtraSids[i].attributes;
909 	}
910 
911 	return (NT_STATUS_SUCCESS);
912 }
913 
914 /*
915  * Determines if the given user is the domain Administrator or a
916  * member of Domain Admins
917  */
918 static boolean_t
919 netr_isadmin(struct netr_validation_info3 *info3)
920 {
921 	smb_domain_t di;
922 	int i;
923 
924 	if (!smb_domain_lookup_sid((smb_sid_t *)info3->LogonDomainId, &di))
925 		return (B_FALSE);
926 
927 	if (di.di_type != SMB_DOMAIN_PRIMARY)
928 		return (B_FALSE);
929 
930 	if ((info3->UserId == DOMAIN_USER_RID_ADMIN) ||
931 	    (info3->PrimaryGroupId == DOMAIN_GROUP_RID_ADMINS))
932 		return (B_TRUE);
933 
934 	for (i = 0; i < info3->GroupCount; i++)
935 		if (info3->GroupIds[i].rid == DOMAIN_GROUP_RID_ADMINS)
936 			return (B_TRUE);
937 
938 	return (B_FALSE);
939 }
940