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 2015 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 #define NETLOGON_ATTEMPTS 2
51 static uint32_t netlogon_logon(smb_logon_t
*, smb_token_t
*);
52 static uint32_t netr_server_samlogon(mlsvc_handle_t
*, netr_info_t
*, char *,
53 smb_logon_t
*, smb_token_t
*);
54 static void netr_invalidate_chain(void);
55 static void netr_interactive_samlogon(netr_info_t
*, smb_logon_t
*,
56 struct netr_logon_info1
*);
57 static void netr_network_samlogon(ndr_heap_t
*, netr_info_t
*,
58 smb_logon_t
*, struct netr_logon_info2
*);
59 static void netr_setup_identity(ndr_heap_t
*, smb_logon_t
*,
61 static boolean_t
netr_isadmin(struct netr_validation_info3
*);
62 static uint32_t netr_setup_domain_groups(struct netr_validation_info3
*,
64 static uint32_t netr_setup_token_info3(struct netr_validation_info3
*,
66 static uint32_t netr_setup_token_wingrps(struct netr_validation_info3
*,
70 * Shared with netr_auth.c
72 extern netr_info_t netr_global_info
;
74 static mutex_t netlogon_mutex
;
75 static cond_t netlogon_cv
;
76 static boolean_t netlogon_busy
= B_FALSE
;
77 static boolean_t netlogon_abort
= B_FALSE
;
80 * Helper for Kerberos authentication
83 smb_decode_krb5_pac(smb_token_t
*token
, char *data
, uint_t len
)
85 struct krb5_validation_info info
;
87 uint32_t status
= NT_STATUS_NO_MEMORY
;
90 bzero(&info
, sizeof (info
));
92 /* Need to keep this until we're done with &info */
93 nbuf
= ndr_buf_init(&TYPEINFO(netr_interface
));
97 rc
= ndr_buf_decode(nbuf
, NDR_PTYPE_PAC
,
98 NETR_OPNUM_decode_krb5_pac
, data
, len
, &info
);
99 if (rc
!= NDR_DRC_OK
) {
100 status
= RPC_NT_PROTOCOL_ERROR
;
104 status
= netr_setup_token_info3(&info
.info3
, token
);
106 /* Deal with the "resource groups"? */
117 * Code factored out of netr_setup_token()
120 netr_setup_token_info3(struct netr_validation_info3
*info3
,
125 domsid
= (smb_sid_t
*)info3
->LogonDomainId
;
127 token
->tkn_user
.i_sid
= smb_sid_splice(domsid
,
129 if (token
->tkn_user
.i_sid
== NULL
)
132 token
->tkn_primary_grp
.i_sid
= smb_sid_splice(domsid
,
133 info3
->PrimaryGroupId
);
134 if (token
->tkn_primary_grp
.i_sid
== NULL
)
137 if (info3
->EffectiveName
.str
) {
138 token
->tkn_account_name
=
139 strdup((char *)info3
->EffectiveName
.str
);
140 if (token
->tkn_account_name
== NULL
)
144 if (info3
->LogonDomainName
.str
) {
145 token
->tkn_domain_name
=
146 strdup((char *)info3
->LogonDomainName
.str
);
147 if (token
->tkn_domain_name
== NULL
)
151 return (netr_setup_token_wingrps(info3
, token
));
153 return (NT_STATUS_INSUFF_SERVER_RESOURCES
);
157 * Abort impending domain logon requests.
160 smb_logon_abort(void)
162 (void) mutex_lock(&netlogon_mutex
);
163 if (netlogon_busy
&& !netlogon_abort
)
164 syslog(LOG_DEBUG
, "logon abort");
165 netlogon_abort
= B_TRUE
;
166 (void) cond_broadcast(&netlogon_cv
);
167 (void) mutex_unlock(&netlogon_mutex
);
171 * This is the entry point for authenticating domain users.
173 * If we are not going to attempt to authenticate the user,
174 * this function must return without updating the status.
176 * If the user is successfully authenticated, we build an
177 * access token and the status will be NT_STATUS_SUCCESS.
178 * Otherwise, the token contents are invalid.
181 smb_logon_domain(smb_logon_t
*user_info
, smb_token_t
*token
)
186 if (user_info
->lg_secmode
!= SMB_SECMODE_DOMAIN
)
189 if (user_info
->lg_domain_type
== SMB_DOMAIN_LOCAL
)
192 for (i
= 0; i
< NETLOGON_ATTEMPTS
; ++i
) {
193 (void) mutex_lock(&netlogon_mutex
);
194 while (netlogon_busy
&& !netlogon_abort
)
195 (void) cond_wait(&netlogon_cv
, &netlogon_mutex
);
197 if (netlogon_abort
) {
198 (void) mutex_unlock(&netlogon_mutex
);
199 user_info
->lg_status
= NT_STATUS_REQUEST_ABORTED
;
203 netlogon_busy
= B_TRUE
;
204 (void) mutex_unlock(&netlogon_mutex
);
206 status
= netlogon_logon(user_info
, token
);
208 (void) mutex_lock(&netlogon_mutex
);
209 netlogon_busy
= B_FALSE
;
211 status
= NT_STATUS_REQUEST_ABORTED
;
212 (void) cond_signal(&netlogon_cv
);
213 (void) mutex_unlock(&netlogon_mutex
);
215 if (status
!= NT_STATUS_CANT_ACCESS_DOMAIN_INFO
)
219 if (status
!= NT_STATUS_SUCCESS
)
220 syslog(LOG_INFO
, "logon[%s\\%s]: %s", user_info
->lg_e_domain
,
221 user_info
->lg_e_username
, xlate_nt_status(status
));
223 user_info
->lg_status
= status
;
227 netlogon_logon(smb_logon_t
*user_info
, smb_token_t
*token
)
229 char resource_domain
[SMB_PI_MAX_DOMAIN
];
230 char server
[MAXHOSTNAMELEN
];
231 mlsvc_handle_t netr_handle
;
236 (void) smb_getdomainname(resource_domain
, SMB_PI_MAX_DOMAIN
);
238 /* Avoid interfering with DC discovery. */
239 if (smb_ddiscover_wait() != 0 ||
240 !smb_domain_getinfo(&di
)) {
241 netr_invalidate_chain();
242 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO
);
246 if (netr_open(di
.d_dci
.dc_name
, di
.d_primary
.di_nbname
,
248 return (NT_STATUS_OPEN_FAILED
);
250 if (di
.d_dci
.dc_name
[0] != '\0' &&
251 (*netr_global_info
.server
!= '\0')) {
252 (void) snprintf(server
, sizeof (server
),
253 "\\\\%s", di
.d_dci
.dc_name
);
254 if (strncasecmp(netr_global_info
.server
,
255 server
, strlen(server
)) != 0)
256 netr_invalidate_chain();
259 if ((netr_global_info
.flags
& NETR_FLG_VALID
) == 0 ||
260 !smb_match_netlogon_seqnum()) {
261 status
= netlogon_auth(di
.d_dci
.dc_name
, &netr_handle
,
265 (void) netr_close(&netr_handle
);
266 return (NT_STATUS_LOGON_FAILURE
);
269 netr_global_info
.flags
|= NETR_FLG_VALID
;
272 status
= netr_server_samlogon(&netr_handle
,
273 &netr_global_info
, di
.d_dci
.dc_name
, user_info
, token
);
275 (void) netr_close(&netr_handle
);
276 } while (status
== NT_STATUS_INSUFFICIENT_LOGON_INFO
&& retries
++ < 3);
279 status
= NT_STATUS_LOGON_FAILURE
;
285 netr_setup_token(struct netr_validation_info3
*info3
, smb_logon_t
*user_info
,
286 netr_info_t
*netr_info
, smb_token_t
*token
)
288 char *username
, *domain
;
289 unsigned char rc4key
[SMBAUTH_SESSION_KEY_SZ
];
292 char nbdomain
[NETBIOS_NAME_SZ
];
294 domsid
= (smb_sid_t
*)info3
->LogonDomainId
;
296 token
->tkn_user
.i_sid
= smb_sid_splice(domsid
, info3
->UserId
);
297 if (token
->tkn_user
.i_sid
== NULL
)
298 return (NT_STATUS_NO_MEMORY
);
300 token
->tkn_primary_grp
.i_sid
= smb_sid_splice(domsid
,
301 info3
->PrimaryGroupId
);
302 if (token
->tkn_primary_grp
.i_sid
== NULL
)
303 return (NT_STATUS_NO_MEMORY
);
305 username
= (info3
->EffectiveName
.str
)
306 ? (char *)info3
->EffectiveName
.str
: user_info
->lg_e_username
;
308 if (info3
->LogonDomainName
.str
) {
309 domain
= (char *)info3
->LogonDomainName
.str
;
310 } else if (*user_info
->lg_e_domain
!= '\0') {
311 domain
= user_info
->lg_e_domain
;
313 (void) smb_getdomainname(nbdomain
, sizeof (nbdomain
));
318 token
->tkn_account_name
= strdup(username
);
320 token
->tkn_domain_name
= strdup(domain
);
322 if (token
->tkn_account_name
== NULL
|| token
->tkn_domain_name
== NULL
)
323 return (NT_STATUS_NO_MEMORY
);
325 status
= netr_setup_token_wingrps(info3
, token
);
326 if (status
!= NT_STATUS_SUCCESS
)
330 * The UserSessionKey in NetrSamLogon RPC is obfuscated using the
331 * session key obtained in the NETLOGON credential chain.
332 * An 8 byte session key is zero extended to 16 bytes. This 16 byte
333 * key is the key to the RC4 algorithm. The RC4 byte stream is
334 * exclusively ored with the 16 byte UserSessionKey to recover
335 * the the clear form.
337 if ((token
->tkn_ssnkey
.val
= malloc(SMBAUTH_SESSION_KEY_SZ
)) == NULL
)
338 return (NT_STATUS_NO_MEMORY
);
339 token
->tkn_ssnkey
.len
= SMBAUTH_SESSION_KEY_SZ
;
340 bzero(rc4key
, SMBAUTH_SESSION_KEY_SZ
);
341 bcopy(netr_info
->session_key
.key
, rc4key
, netr_info
->session_key
.len
);
342 bcopy(info3
->UserSessionKey
.data
, token
->tkn_ssnkey
.val
,
343 SMBAUTH_SESSION_KEY_SZ
);
344 rand_hash((unsigned char *)token
->tkn_ssnkey
.val
,
345 SMBAUTH_SESSION_KEY_SZ
, rc4key
, SMBAUTH_SESSION_KEY_SZ
);
347 return (NT_STATUS_SUCCESS
);
351 * netr_server_samlogon
353 * NetrServerSamLogon RPC: interactive or network. It is assumed that
354 * we have already authenticated with the PDC. If everything works,
355 * we build a user info structure and return it, where the caller will
356 * probably build an access token.
358 * Returns an NT status. There are numerous possibilities here.
360 * NT_STATUS_INVALID_INFO_CLASS
361 * NT_STATUS_INVALID_PARAMETER
362 * NT_STATUS_ACCESS_DENIED
363 * NT_STATUS_PASSWORD_MUST_CHANGE
364 * NT_STATUS_NO_SUCH_USER
365 * NT_STATUS_WRONG_PASSWORD
366 * NT_STATUS_LOGON_FAILURE
367 * NT_STATUS_ACCOUNT_RESTRICTION
368 * NT_STATUS_INVALID_LOGON_HOURS
369 * NT_STATUS_INVALID_WORKSTATION
370 * NT_STATUS_INTERNAL_ERROR
371 * NT_STATUS_PASSWORD_EXPIRED
372 * NT_STATUS_ACCOUNT_DISABLED
375 netr_server_samlogon(mlsvc_handle_t
*netr_handle
, netr_info_t
*netr_info
,
376 char *server
, smb_logon_t
*user_info
, smb_token_t
*token
)
378 struct netr_SamLogon arg
;
379 struct netr_authenticator auth
;
380 struct netr_authenticator ret_auth
;
381 struct netr_logon_info1 info1
;
382 struct netr_logon_info2 info2
;
383 struct netr_validation_info3
*info3
;
389 bzero(&arg
, sizeof (struct netr_SamLogon
));
390 opnum
= NETR_OPNUM_SamLogon
;
393 * Should we get the server and hostname from netr_info?
396 len
= strlen(server
) + 4;
397 arg
.servername
= ndr_rpc_malloc(netr_handle
, len
);
398 arg
.hostname
= ndr_rpc_malloc(netr_handle
, NETBIOS_NAME_SZ
);
399 if (arg
.servername
== NULL
|| arg
.hostname
== NULL
) {
400 ndr_rpc_release(netr_handle
);
401 return (NT_STATUS_INTERNAL_ERROR
);
404 (void) snprintf((char *)arg
.servername
, len
, "\\\\%s", server
);
405 if (smb_getnetbiosname((char *)arg
.hostname
, NETBIOS_NAME_SZ
) != 0) {
406 ndr_rpc_release(netr_handle
);
407 return (NT_STATUS_INTERNAL_ERROR
);
410 rc
= netr_setup_authenticator(netr_info
, &auth
, &ret_auth
);
411 if (rc
!= SMBAUTH_SUCCESS
) {
412 ndr_rpc_release(netr_handle
);
413 return (NT_STATUS_INTERNAL_ERROR
);
417 arg
.ret_auth
= &ret_auth
;
418 arg
.validation_level
= NETR_VALIDATION_LEVEL3
;
419 arg
.logon_info
.logon_level
= user_info
->lg_level
;
420 arg
.logon_info
.switch_value
= user_info
->lg_level
;
422 heap
= ndr_rpc_get_heap(netr_handle
);
424 switch (user_info
->lg_level
) {
425 case NETR_INTERACTIVE_LOGON
:
426 netr_setup_identity(heap
, user_info
, &info1
.identity
);
427 netr_interactive_samlogon(netr_info
, user_info
, &info1
);
428 arg
.logon_info
.ru
.info1
= &info1
;
431 case NETR_NETWORK_LOGON
:
432 if (user_info
->lg_challenge_key
.len
< 8 ||
433 user_info
->lg_challenge_key
.val
== NULL
) {
434 ndr_rpc_release(netr_handle
);
435 return (NT_STATUS_INVALID_PARAMETER
);
437 netr_setup_identity(heap
, user_info
, &info2
.identity
);
438 netr_network_samlogon(heap
, netr_info
, user_info
, &info2
);
439 arg
.logon_info
.ru
.info2
= &info2
;
443 ndr_rpc_release(netr_handle
);
444 return (NT_STATUS_INVALID_PARAMETER
);
447 rc
= ndr_rpc_call(netr_handle
, opnum
, &arg
);
449 bzero(netr_info
, sizeof (netr_info_t
));
450 status
= NT_STATUS_INVALID_PARAMETER
;
451 } else if (arg
.status
!= 0) {
452 status
= NT_SC_VALUE(arg
.status
);
455 * We need to validate the chain even though we have
456 * a non-zero status. If the status is ACCESS_DENIED
457 * this will trigger a new credential chain. However,
458 * a valid credential is returned with some status
459 * codes; for example, WRONG_PASSWORD.
461 (void) netr_validate_chain(netr_info
, arg
.ret_auth
);
463 status
= netr_validate_chain(netr_info
, arg
.ret_auth
);
464 if (status
== NT_STATUS_INSUFFICIENT_LOGON_INFO
) {
465 ndr_rpc_release(netr_handle
);
469 info3
= arg
.ru
.info3
;
470 status
= netr_setup_token(info3
, user_info
, netr_info
, token
);
473 ndr_rpc_release(netr_handle
);
478 * netr_interactive_samlogon
480 * Set things up for an interactive SamLogon. Copy the NT and LM
481 * passwords to the logon structure and hash them with the session
485 netr_interactive_samlogon(netr_info_t
*netr_info
, smb_logon_t
*user_info
,
486 struct netr_logon_info1
*info1
)
488 BYTE key
[NETR_OWF_PASSWORD_SZ
];
490 (void) memcpy(&info1
->lm_owf_password
,
491 user_info
->lg_lm_password
.val
, sizeof (netr_owf_password_t
));
493 (void) memcpy(&info1
->nt_owf_password
,
494 user_info
->lg_nt_password
.val
, sizeof (netr_owf_password_t
));
496 (void) memset(key
, 0, NETR_OWF_PASSWORD_SZ
);
497 (void) memcpy(key
, netr_info
->session_key
.key
,
498 netr_info
->session_key
.len
);
500 rand_hash((unsigned char *)&info1
->lm_owf_password
,
501 NETR_OWF_PASSWORD_SZ
, key
, NETR_OWF_PASSWORD_SZ
);
503 rand_hash((unsigned char *)&info1
->nt_owf_password
,
504 NETR_OWF_PASSWORD_SZ
, key
, NETR_OWF_PASSWORD_SZ
);
508 * netr_network_samlogon
510 * Set things up for a network SamLogon. We provide a copy of the random
511 * challenge, that we sent to the client, to the domain controller. This
512 * is the key that the client will have used to encrypt the NT and LM
513 * passwords. Note that Windows 9x clients may not provide both passwords.
517 netr_network_samlogon(ndr_heap_t
*heap
, netr_info_t
*netr_info
,
518 smb_logon_t
*user_info
, struct netr_logon_info2
*info2
)
522 if (user_info
->lg_challenge_key
.len
>= 8 &&
523 user_info
->lg_challenge_key
.val
!= 0) {
524 bcopy(user_info
->lg_challenge_key
.val
,
525 info2
->lm_challenge
.data
, 8);
527 bzero(info2
->lm_challenge
.data
, 8);
530 if ((len
= user_info
->lg_nt_password
.len
) != 0) {
531 ndr_heap_mkvcb(heap
, user_info
->lg_nt_password
.val
, len
,
532 (ndr_vcbuf_t
*)&info2
->nt_response
);
534 bzero(&info2
->nt_response
, sizeof (netr_vcbuf_t
));
537 if ((len
= user_info
->lg_lm_password
.len
) != 0) {
538 ndr_heap_mkvcb(heap
, user_info
->lg_lm_password
.val
, len
,
539 (ndr_vcbuf_t
*)&info2
->lm_response
);
541 bzero(&info2
->lm_response
, sizeof (netr_vcbuf_t
));
546 * netr_setup_authenticator
548 * Set up the request and return authenticators. A new credential is
549 * generated from the session key, the current client credential and
550 * the current time, i.e.
552 * NewCredential = Cred(SessionKey, OldCredential, time);
554 * The timestamp, which is used as a random seed, is stored in both
555 * the request and return authenticators.
557 * If any difficulties occur using the cryptographic framework, the
558 * function returns SMBAUTH_FAILURE. Otherwise SMBAUTH_SUCCESS is
562 netr_setup_authenticator(netr_info_t
*netr_info
,
563 struct netr_authenticator
*auth
, struct netr_authenticator
*ret_auth
)
565 bzero(auth
, sizeof (struct netr_authenticator
));
567 netr_info
->timestamp
= time(0);
568 auth
->timestamp
= netr_info
->timestamp
;
570 if (netr_gen_credentials(netr_info
->session_key
.key
,
571 &netr_info
->client_credential
,
572 netr_info
->timestamp
,
573 (netr_cred_t
*)&auth
->credential
) != SMBAUTH_SUCCESS
)
574 return (SMBAUTH_FAILURE
);
577 bzero(ret_auth
, sizeof (struct netr_authenticator
));
578 ret_auth
->timestamp
= netr_info
->timestamp
;
581 return (SMBAUTH_SUCCESS
);
585 * Validate the returned credentials and update the credential chain.
586 * The server returns an updated client credential rather than a new
587 * server credential. The server uses (timestamp + 1) when generating
590 * Generate the new seed for the credential chain. The new seed is
591 * formed by adding (timestamp + 1) to the current client credential.
592 * The only quirk is the uint32_t style addition.
594 * Returns NT_STATUS_INSUFFICIENT_LOGON_INFO if auth->credential is a
595 * NULL pointer. The Authenticator field of the SamLogon response packet
596 * sent by the Samba 3 PDC always return NULL pointer if the received
597 * SamLogon request is not immediately followed by the ServerReqChallenge
598 * and ServerAuthenticate2 requests.
600 * Returns NT_STATUS_SUCCESS if the server returned a valid credential.
601 * Otherwise we retirm NT_STATUS_UNSUCCESSFUL.
604 netr_validate_chain(netr_info_t
*netr_info
, struct netr_authenticator
*auth
)
607 uint32_t result
= NT_STATUS_SUCCESS
;
610 ++netr_info
->timestamp
;
612 if (netr_gen_credentials(netr_info
->session_key
.key
,
613 &netr_info
->client_credential
,
614 netr_info
->timestamp
, &cred
) != SMBAUTH_SUCCESS
)
615 return (NT_STATUS_INTERNAL_ERROR
);
617 if (&auth
->credential
== 0) {
619 * If the validation fails, destroy the credential chain.
620 * This should trigger a new authentication chain.
622 bzero(netr_info
, sizeof (netr_info_t
));
623 return (NT_STATUS_INSUFFICIENT_LOGON_INFO
);
626 result
= memcmp(&cred
, &auth
->credential
, sizeof (netr_cred_t
));
629 * If the validation fails, destroy the credential chain.
630 * This should trigger a new authentication chain.
632 bzero(netr_info
, sizeof (netr_info_t
));
633 result
= NT_STATUS_UNSUCCESSFUL
;
636 * Otherwise generate the next step in the chain.
638 /*LINTED E_BAD_PTR_CAST_ALIGN*/
639 dwp
= (uint32_t *)&netr_info
->client_credential
;
640 dwp
[0] += netr_info
->timestamp
;
642 netr_info
->flags
|= NETR_FLG_VALID
;
649 * netr_invalidate_chain
651 * Mark the credential chain as invalid so that it will be recreated
652 * on the next attempt.
655 netr_invalidate_chain(void)
657 netr_global_info
.flags
&= ~NETR_FLG_VALID
;
661 * netr_setup_identity
663 * Set up the client identity information. All of this information is
664 * specifically related to the client user and workstation attempting
665 * to access this system. It may not be in our primary domain.
667 * I don't know what logon_id is, it seems to be a unique identifier.
668 * Increment it before each use.
671 netr_setup_identity(ndr_heap_t
*heap
, smb_logon_t
*user_info
,
672 netr_logon_id_t
*identity
)
674 static mutex_t logon_id_mutex
;
675 static uint32_t logon_id
;
677 (void) mutex_lock(&logon_id_mutex
);
683 user_info
->lg_logon_id
= logon_id
;
685 (void) mutex_unlock(&logon_id_mutex
);
688 * [MS-APDS] 3.1.5.2 "NTLM Network Logon" says to set
689 * ParameterControl to the 'E' + 'K' bits. Those are:
690 * (1 << 5) | (1 << 11), a.k.a
692 identity
->parameter_control
=
693 MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT
|
694 MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT
;
695 identity
->logon_id
.LowPart
= logon_id
;
696 identity
->logon_id
.HighPart
= 0;
698 ndr_heap_mkvcs(heap
, user_info
->lg_domain
,
699 (ndr_vcstr_t
*)&identity
->domain_name
);
701 ndr_heap_mkvcs(heap
, user_info
->lg_username
,
702 (ndr_vcstr_t
*)&identity
->username
);
705 * Some systems prefix the client workstation name with \\.
706 * It doesn't seem to make any difference whether it's there
709 ndr_heap_mkvcs(heap
, user_info
->lg_workstation
,
710 (ndr_vcstr_t
*)&identity
->workstation
);
714 * Sets up domain, local and well-known group membership for the given
715 * token. Two assumptions have been made here:
717 * a) token already contains a valid user SID so that group
718 * memberships can be established
720 * b) token belongs to a domain user
723 netr_setup_token_wingrps(struct netr_validation_info3
*info3
,
730 tkn_grps
.i_ids
= NULL
;
732 status
= netr_setup_domain_groups(info3
, &tkn_grps
);
733 if (status
!= NT_STATUS_SUCCESS
) {
734 smb_ids_free(&tkn_grps
);
738 status
= smb_sam_usr_groups(token
->tkn_user
.i_sid
, &tkn_grps
);
739 if (status
!= NT_STATUS_SUCCESS
) {
740 smb_ids_free(&tkn_grps
);
744 if (netr_isadmin(info3
))
745 token
->tkn_flags
|= SMB_ATF_ADMIN
;
747 status
= smb_wka_token_groups(token
->tkn_flags
, &tkn_grps
);
748 if (status
== NT_STATUS_SUCCESS
)
749 token
->tkn_win_grps
= tkn_grps
;
751 smb_ids_free(&tkn_grps
);
757 * Converts groups information in the returned structure by domain controller
758 * (info3) to an internal representation (gids)
761 netr_setup_domain_groups(struct netr_validation_info3
*info3
, smb_ids_t
*gids
)
763 smb_sid_t
*domain_sid
;
767 if ((i
= info3
->GroupCount
) == 0)
769 i
+= info3
->SidCount
;
771 total_cnt
= gids
->i_cnt
+ i
;
773 gids
->i_ids
= reallocarray(gids
->i_ids
, total_cnt
, sizeof (smb_id_t
));
774 if (gids
->i_ids
== NULL
)
775 return (NT_STATUS_NO_MEMORY
);
777 domain_sid
= (smb_sid_t
*)info3
->LogonDomainId
;
779 ids
= gids
->i_ids
+ gids
->i_cnt
;
780 for (i
= 0; i
< info3
->GroupCount
; i
++, gids
->i_cnt
++, ids
++) {
781 ids
->i_sid
= smb_sid_splice(domain_sid
, info3
->GroupIds
[i
].rid
);
782 if (ids
->i_sid
== NULL
)
783 return (NT_STATUS_NO_MEMORY
);
785 ids
->i_attrs
= info3
->GroupIds
[i
].attributes
;
788 if (info3
->GroupCount
== 0) {
790 * if there's no global group should add the primary group.
792 ids
->i_sid
= smb_sid_splice(domain_sid
, info3
->PrimaryGroupId
);
793 if (ids
->i_sid
== NULL
)
794 return (NT_STATUS_NO_MEMORY
);
801 /* Add the extra SIDs */
802 for (i
= 0; i
< info3
->SidCount
; i
++, gids
->i_cnt
++, ids
++) {
803 ids
->i_sid
= smb_sid_dup((smb_sid_t
*)info3
->ExtraSids
[i
].sid
);
804 if (ids
->i_sid
== NULL
)
805 return (NT_STATUS_NO_MEMORY
);
807 ids
->i_attrs
= info3
->ExtraSids
[i
].attributes
;
810 return (NT_STATUS_SUCCESS
);
814 * Determines if the given user is the domain Administrator or a
815 * member of Domain Admins
818 netr_isadmin(struct netr_validation_info3
*info3
)
823 if (!smb_domain_lookup_sid((smb_sid_t
*)info3
->LogonDomainId
, &di
))
826 if (di
.di_type
!= SMB_DOMAIN_PRIMARY
)
829 if ((info3
->UserId
== DOMAIN_USER_RID_ADMIN
) ||
830 (info3
->PrimaryGroupId
== DOMAIN_GROUP_RID_ADMINS
))
833 for (i
= 0; i
< info3
->GroupCount
; i
++)
834 if (info3
->GroupIds
[i
].rid
== DOMAIN_GROUP_RID_ADMINS
)