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]
23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
28 * NETR SamLogon and SamLogoff RPC client functions.
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>
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
*,
59 static boolean_t
netr_isadmin(struct netr_validation_info3
*);
60 static uint32_t netr_setup_domain_groups(struct netr_validation_info3
*,
62 static uint32_t netr_setup_token_info3(struct netr_validation_info3
*,
64 static uint32_t netr_setup_token_wingrps(struct netr_validation_info3
*,
68 * Shared with netr_auth.c
70 extern netr_info_t netr_global_info
;
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
;
78 * Helper for Kerberos authentication
81 smb_decode_krb5_pac(smb_token_t
*token
, char *data
, uint_t len
)
83 struct krb5_validation_info info
;
85 uint32_t status
= NT_STATUS_NO_MEMORY
;
88 bzero(&info
, sizeof (info
));
90 /* Need to keep this until we're done with &info */
91 nbuf
= ndr_buf_init(&TYPEINFO(netr_interface
));
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
;
102 status
= netr_setup_token_info3(&info
.info3
, token
);
104 /* Deal with the "resource groups"? */
115 * Code factored out of netr_setup_token()
118 netr_setup_token_info3(struct netr_validation_info3
*info3
,
123 domsid
= (smb_sid_t
*)info3
->LogonDomainId
;
125 token
->tkn_user
.i_sid
= smb_sid_splice(domsid
,
127 if (token
->tkn_user
.i_sid
== NULL
)
130 token
->tkn_primary_grp
.i_sid
= smb_sid_splice(domsid
,
131 info3
->PrimaryGroupId
);
132 if (token
->tkn_primary_grp
.i_sid
== NULL
)
135 if (info3
->EffectiveName
.str
) {
136 token
->tkn_account_name
=
137 strdup((char *)info3
->EffectiveName
.str
);
138 if (token
->tkn_account_name
== NULL
)
142 if (info3
->LogonDomainName
.str
) {
143 token
->tkn_domain_name
=
144 strdup((char *)info3
->LogonDomainName
.str
);
145 if (token
->tkn_domain_name
== NULL
)
149 return (netr_setup_token_wingrps(info3
, token
));
151 return (NT_STATUS_INSUFF_SERVER_RESOURCES
);
155 * Abort impending domain logon requests.
158 smb_logon_abort(void)
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
);
169 * This is the entry point for authenticating domain users.
171 * If we are not going to attempt to authenticate the user,
172 * this function must return without updating the status.
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.
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.
183 int smb_netr_logon_retries
= 3;
185 smb_logon_domain(smb_logon_t
*user_info
, smb_token_t
*token
)
189 int retries
= smb_netr_logon_retries
;
191 if (user_info
->lg_secmode
!= SMB_SECMODE_DOMAIN
)
194 if (user_info
->lg_domain_type
== SMB_DOMAIN_LOCAL
)
197 while (--retries
> 0) {
199 if (!smb_domain_getinfo(&di
)) {
200 syslog(LOG_ERR
, "logon DC getinfo failed");
201 status
= NT_STATUS_NO_LOGON_SERVERS
;
205 (void) mutex_lock(&netlogon_mutex
);
206 while (netlogon_busy
&& !netlogon_abort
)
207 (void) cond_wait(&netlogon_cv
, &netlogon_mutex
);
209 if (netlogon_abort
) {
210 (void) mutex_unlock(&netlogon_mutex
);
211 status
= NT_STATUS_REQUEST_ABORTED
;
215 netlogon_busy
= B_TRUE
;
216 (void) mutex_unlock(&netlogon_mutex
);
218 status
= netlogon_logon(user_info
, token
, &di
);
220 (void) mutex_lock(&netlogon_mutex
);
221 netlogon_busy
= B_FALSE
;
223 status
= NT_STATUS_REQUEST_ABORTED
;
224 (void) cond_signal(&netlogon_cv
);
225 (void) mutex_unlock(&netlogon_mutex
);
228 case NT_STATUS_BAD_NETWORK_PATH
:
229 case NT_STATUS_BAD_NETWORK_NAME
:
230 case RPC_NT_SERVER_TOO_BUSY
:
232 * May retry with a new DC, or if we're
233 * out of retries, will return...
235 status
= NT_STATUS_NO_LOGON_SERVERS
;
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
;
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.
258 netlogon_logon(smb_logon_t
*user_info
, smb_token_t
*token
, smb_domainex_t
*di
)
260 char server
[MAXHOSTNAMELEN
];
261 mlsvc_handle_t netr_handle
;
263 boolean_t did_reauth
= B_FALSE
;
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.
269 status
= netr_open(di
->d_dci
.dc_name
, di
->d_primary
.di_nbname
,
272 syslog(LOG_ERR
, "netlogon remote open failed (%s)",
273 xlate_nt_status(status
));
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();
287 if ((netr_global_info
.flags
& NETR_FLG_VALID
) == 0 ||
288 !smb_match_netlogon_seqnum()) {
290 * This does netr_server_req_challenge() and
291 * netr_server_authenticate2(), updating the
292 * current netlogon sequence number.
294 status
= netlogon_auth(di
->d_dci
.dc_name
, &netr_handle
,
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
);
304 netr_global_info
.flags
|= NETR_FLG_VALID
;
307 status
= netr_server_samlogon(&netr_handle
,
308 &netr_global_info
, di
->d_dci
.dc_name
, user_info
, token
);
310 if (status
== NT_STATUS_INSUFFICIENT_LOGON_INFO
) {
312 /* Call netlogon_auth() again, just once. */
316 status
= NT_STATUS_DOMAIN_TRUST_INCONSISTENT
;
319 (void) netr_close(&netr_handle
);
325 * Helper for mlsvc_netlogon
327 * Call netlogon_auth with appropriate locks etc.
328 * Serialize like smb_logon_domain does for
329 * netlogon_logon / netlogon_auth
332 smb_netlogon_check(char *server
, char *domain
)
334 mlsvc_handle_t netr_handle
;
337 (void) mutex_lock(&netlogon_mutex
);
338 while (netlogon_busy
)
339 (void) cond_wait(&netlogon_cv
, &netlogon_mutex
);
341 netlogon_busy
= B_TRUE
;
342 (void) mutex_unlock(&netlogon_mutex
);
345 * This section like netlogon_logon(), but only does
346 * one pass and no netr_server_samlogon call.
349 status
= netr_open(server
, domain
,
352 syslog(LOG_ERR
, "netlogon remote open failed (%s)",
353 xlate_nt_status(status
));
357 if ((netr_global_info
.flags
& NETR_FLG_VALID
) == 0 ||
358 !smb_match_netlogon_seqnum()) {
360 * This does netr_server_req_challenge() and
361 * netr_server_authenticate2(), updating the
362 * current netlogon sequence number.
364 status
= netlogon_auth(server
, &netr_handle
,
367 syslog(LOG_ERR
, "netlogon remote auth failed (%s)",
368 xlate_nt_status(status
));
370 netr_global_info
.flags
|= NETR_FLG_VALID
;
374 (void) netr_close(&netr_handle
);
377 (void) mutex_lock(&netlogon_mutex
);
378 netlogon_busy
= B_FALSE
;
379 (void) cond_signal(&netlogon_cv
);
380 (void) mutex_unlock(&netlogon_mutex
);
386 netr_setup_token(struct netr_validation_info3
*info3
, smb_logon_t
*user_info
,
387 netr_info_t
*netr_info
, smb_token_t
*token
)
389 char *username
, *domain
;
390 unsigned char rc4key
[SMBAUTH_SESSION_KEY_SZ
];
393 char nbdomain
[NETBIOS_NAME_SZ
];
395 domsid
= (smb_sid_t
*)info3
->LogonDomainId
;
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
);
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
);
406 username
= (info3
->EffectiveName
.str
)
407 ? (char *)info3
->EffectiveName
.str
: user_info
->lg_e_username
;
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
;
414 (void) smb_getdomainname(nbdomain
, sizeof (nbdomain
));
419 token
->tkn_account_name
= strdup(username
);
421 token
->tkn_domain_name
= strdup(domain
);
423 if (token
->tkn_account_name
== NULL
|| token
->tkn_domain_name
== NULL
)
424 return (NT_STATUS_NO_MEMORY
);
426 status
= netr_setup_token_wingrps(info3
, token
);
427 if (status
!= NT_STATUS_SUCCESS
)
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.
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
);
448 return (NT_STATUS_SUCCESS
);
452 * netr_server_samlogon
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.
459 * Returns an NT status. There are numerous possibilities here.
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
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
)
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
;
490 bzero(&arg
, sizeof (struct netr_SamLogon
));
491 opnum
= NETR_OPNUM_SamLogon
;
494 * Should we get the server and hostname from netr_info?
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
);
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
);
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
);
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
;
523 heap
= ndr_rpc_get_heap(netr_handle
);
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
;
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
);
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
;
544 ndr_rpc_release(netr_handle
);
545 return (NT_STATUS_INVALID_PARAMETER
);
548 rc
= ndr_rpc_call(netr_handle
, opnum
, &arg
);
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
);
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.
562 (void) netr_validate_chain(netr_info
, arg
.ret_auth
);
564 status
= netr_validate_chain(netr_info
, arg
.ret_auth
);
565 if (status
== NT_STATUS_INSUFFICIENT_LOGON_INFO
) {
566 ndr_rpc_release(netr_handle
);
570 info3
= arg
.ru
.info3
;
571 status
= netr_setup_token(info3
, user_info
, netr_info
, token
);
574 ndr_rpc_release(netr_handle
);
579 * netr_interactive_samlogon
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
586 netr_interactive_samlogon(netr_info_t
*netr_info
, smb_logon_t
*user_info
,
587 struct netr_logon_info1
*info1
)
589 BYTE key
[NETR_OWF_PASSWORD_SZ
];
591 (void) memcpy(&info1
->lm_owf_password
,
592 user_info
->lg_lm_password
.val
, sizeof (netr_owf_password_t
));
594 (void) memcpy(&info1
->nt_owf_password
,
595 user_info
->lg_nt_password
.val
, sizeof (netr_owf_password_t
));
597 (void) memset(key
, 0, NETR_OWF_PASSWORD_SZ
);
598 (void) memcpy(key
, netr_info
->session_key
.key
,
599 netr_info
->session_key
.len
);
601 rand_hash((unsigned char *)&info1
->lm_owf_password
,
602 NETR_OWF_PASSWORD_SZ
, key
, NETR_OWF_PASSWORD_SZ
);
604 rand_hash((unsigned char *)&info1
->nt_owf_password
,
605 NETR_OWF_PASSWORD_SZ
, key
, NETR_OWF_PASSWORD_SZ
);
609 * netr_network_samlogon
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.
618 netr_network_samlogon(ndr_heap_t
*heap
, netr_info_t
*netr_info
,
619 smb_logon_t
*user_info
, struct netr_logon_info2
*info2
)
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);
628 bzero(info2
->lm_challenge
.data
, 8);
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
);
635 bzero(&info2
->nt_response
, sizeof (netr_vcbuf_t
));
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
);
642 bzero(&info2
->lm_response
, sizeof (netr_vcbuf_t
));
647 * netr_setup_authenticator
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.
653 * NewCredential = Cred(SessionKey, OldCredential, time);
655 * The timestamp, which is used as a random seed, is stored in both
656 * the request and return authenticators.
658 * If any difficulties occur using the cryptographic framework, the
659 * function returns SMBAUTH_FAILURE. Otherwise SMBAUTH_SUCCESS is
663 netr_setup_authenticator(netr_info_t
*netr_info
,
664 struct netr_authenticator
*auth
, struct netr_authenticator
*ret_auth
)
666 bzero(auth
, sizeof (struct netr_authenticator
));
668 netr_info
->timestamp
= time(0);
669 auth
->timestamp
= netr_info
->timestamp
;
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
);
678 bzero(ret_auth
, sizeof (struct netr_authenticator
));
679 ret_auth
->timestamp
= netr_info
->timestamp
;
682 return (SMBAUTH_SUCCESS
);
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
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.
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.
701 * Returns NT_STATUS_SUCCESS if the server returned a valid credential.
702 * Otherwise we retirm NT_STATUS_UNSUCCESSFUL.
705 netr_validate_chain(netr_info_t
*netr_info
, struct netr_authenticator
*auth
)
708 uint32_t result
= NT_STATUS_SUCCESS
;
711 ++netr_info
->timestamp
;
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
);
718 if (&auth
->credential
== 0) {
720 * If the validation fails, destroy the credential chain.
721 * This should trigger a new authentication chain.
723 bzero(netr_info
, sizeof (netr_info_t
));
724 return (NT_STATUS_INSUFFICIENT_LOGON_INFO
);
727 result
= memcmp(&cred
, &auth
->credential
, sizeof (netr_cred_t
));
730 * If the validation fails, destroy the credential chain.
731 * This should trigger a new authentication chain.
733 bzero(netr_info
, sizeof (netr_info_t
));
734 result
= NT_STATUS_UNSUCCESSFUL
;
737 * Otherwise generate the next step in the chain.
739 /*LINTED E_BAD_PTR_CAST_ALIGN*/
740 dwp
= (uint32_t *)&netr_info
->client_credential
;
741 dwp
[0] += netr_info
->timestamp
;
743 netr_info
->flags
|= NETR_FLG_VALID
;
750 * netr_invalidate_chain
752 * Mark the credential chain as invalid so that it will be recreated
753 * on the next attempt.
756 netr_invalidate_chain(void)
758 netr_global_info
.flags
&= ~NETR_FLG_VALID
;
762 * netr_setup_identity
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.
768 * I don't know what logon_id is, it seems to be a unique identifier.
769 * Increment it before each use.
772 netr_setup_identity(ndr_heap_t
*heap
, smb_logon_t
*user_info
,
773 netr_logon_id_t
*identity
)
775 static mutex_t logon_id_mutex
;
776 static uint32_t logon_id
;
778 (void) mutex_lock(&logon_id_mutex
);
784 user_info
->lg_logon_id
= logon_id
;
786 (void) mutex_unlock(&logon_id_mutex
);
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
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;
799 ndr_heap_mkvcs(heap
, user_info
->lg_domain
,
800 (ndr_vcstr_t
*)&identity
->domain_name
);
802 ndr_heap_mkvcs(heap
, user_info
->lg_username
,
803 (ndr_vcstr_t
*)&identity
->username
);
806 * Some systems prefix the client workstation name with \\.
807 * It doesn't seem to make any difference whether it's there
810 ndr_heap_mkvcs(heap
, user_info
->lg_workstation
,
811 (ndr_vcstr_t
*)&identity
->workstation
);
815 * Sets up domain, local and well-known group membership for the given
816 * token. Two assumptions have been made here:
818 * a) token already contains a valid user SID so that group
819 * memberships can be established
821 * b) token belongs to a domain user
824 netr_setup_token_wingrps(struct netr_validation_info3
*info3
,
831 tkn_grps
.i_ids
= NULL
;
833 status
= netr_setup_domain_groups(info3
, &tkn_grps
);
834 if (status
!= NT_STATUS_SUCCESS
) {
835 smb_ids_free(&tkn_grps
);
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
);
845 if (netr_isadmin(info3
))
846 token
->tkn_flags
|= SMB_ATF_ADMIN
;
848 status
= smb_wka_token_groups(token
->tkn_flags
, &tkn_grps
);
849 if (status
== NT_STATUS_SUCCESS
)
850 token
->tkn_win_grps
= tkn_grps
;
852 smb_ids_free(&tkn_grps
);
858 * Converts groups information in the returned structure by domain controller
859 * (info3) to an internal representation (gids)
862 netr_setup_domain_groups(struct netr_validation_info3
*info3
, smb_ids_t
*gids
)
864 smb_sid_t
*domain_sid
;
868 if ((i
= info3
->GroupCount
) == 0)
870 i
+= info3
->SidCount
;
872 total_cnt
= gids
->i_cnt
+ i
;
874 gids
->i_ids
= reallocarray(gids
->i_ids
, total_cnt
, sizeof (smb_id_t
));
875 if (gids
->i_ids
== NULL
)
876 return (NT_STATUS_NO_MEMORY
);
878 domain_sid
= (smb_sid_t
*)info3
->LogonDomainId
;
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
);
886 ids
->i_attrs
= info3
->GroupIds
[i
].attributes
;
889 if (info3
->GroupCount
== 0) {
891 * if there's no global group should add the primary group.
893 ids
->i_sid
= smb_sid_splice(domain_sid
, info3
->PrimaryGroupId
);
894 if (ids
->i_sid
== NULL
)
895 return (NT_STATUS_NO_MEMORY
);
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
);
908 ids
->i_attrs
= info3
->ExtraSids
[i
].attributes
;
911 return (NT_STATUS_SUCCESS
);
915 * Determines if the given user is the domain Administrator or a
916 * member of Domain Admins
919 netr_isadmin(struct netr_validation_info3
*info3
)
924 if (!smb_domain_lookup_sid((smb_sid_t
*)info3
->LogonDomainId
, &di
))
927 if (di
.di_type
!= SMB_DOMAIN_PRIMARY
)
930 if ((info3
->UserId
== DOMAIN_USER_RID_ADMIN
) ||
931 (info3
->PrimaryGroupId
== DOMAIN_GROUP_RID_ADMINS
))
934 for (i
= 0; i
< info3
->GroupCount
; i
++)
935 if (info3
->GroupIds
[i
].rid
== DOMAIN_GROUP_RID_ADMINS
)