2 Unix SMB/CIFS implementation.
4 Convert a server info struct into the form for PAC and NETLOGON replies
6 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2011
7 Copyright (C) Stefan Metzmacher <metze@samba.org> 2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "librpc/gen_ndr/auth.h"
25 #include "libcli/security/security.h"
26 #include "auth/auth_sam_reply.h"
28 /* Returns true if this SID belongs in SamBaseInfo, otherwise false. */
29 static bool is_base_sid(const struct auth_SidAttr
*sid
,
30 const struct dom_sid
*domain_sid
)
32 if (sid
->attrs
& SE_GROUP_RESOURCE
) {
34 * Resource groups don't belong in the base
35 * RIDs, they're handled elsewhere.
41 * This SID belongs in the base structure only if it's in the account's
44 return dom_sid_in_domain(domain_sid
, &sid
->sid
);
47 /* Stores a SID in a previously allocated array. */
48 static NTSTATUS
store_extra_sid(struct netr_SidAttr
*sids
,
50 const uint32_t allocated_sids
,
51 const struct auth_SidAttr
*sid
)
53 /* Check we aren't about to overflow our allocation. */
54 if (*sidcount
>= allocated_sids
) {
55 return NT_STATUS_INVALID_PARAMETER
;
58 sids
[*sidcount
].sid
= dom_sid_dup(sids
, &sid
->sid
);
59 if (sids
[*sidcount
].sid
== NULL
) {
60 return NT_STATUS_NO_MEMORY
;
62 sids
[*sidcount
].attributes
= sid
->attrs
;
69 * Stores a resource SID in a previously allocated array, either Extra SIDs or
70 * Resource SIDs. Any SID within the domain of the first SID so added is stored
71 * there, while remaining SIDs are stored in Extra SIDs.
73 static NTSTATUS
store_resource_sid(struct netr_SidAttr
*sids
,
75 const uint32_t allocated_sids
,
76 const struct auth_SidAttr
*sid
,
77 struct PAC_DOMAIN_GROUP_MEMBERSHIP
*resource_groups
,
78 const uint32_t allocated_resource_groups
)
82 struct dom_sid
*resource_domain
= NULL
;
85 if (resource_groups
== NULL
) {
86 return NT_STATUS_INVALID_PARAMETER
;
89 /* Split the SID into domain and RID. */
90 status
= dom_sid_split_rid(resource_groups
, &sid
->sid
, &resource_domain
, &rid
);
91 if (!NT_STATUS_IS_OK(status
)) {
95 if (resource_groups
->domain_sid
== NULL
) {
97 * There is no domain SID set. Set it to the domain of this SID.
99 resource_groups
->domain_sid
= resource_domain
;
102 * A domain SID has already been set. Check whether this SID's
105 * Assuming that resource SIDs have been obtained with
106 * dsdb_expand_nested_groups(), they should all be within the
107 * same domain (ours), so unless something has gone horribly
108 * wrong, we should always find that they match.
110 bool match
= dom_sid_equal(resource_groups
->domain_sid
, resource_domain
);
111 talloc_free(resource_domain
);
114 * It doesn't match, so we can't store this SID here. It
115 * will have to go in Extra SIDs.
117 return store_extra_sid(sids
, sidcount
, allocated_sids
, sid
);
121 /* Store the SID in Resource SIDs. */
123 /* Check we aren't about to overflow our allocation. */
124 if (resource_groups
->groups
.count
>= allocated_resource_groups
) {
125 return NT_STATUS_INVALID_PARAMETER
;
128 resource_groups
->groups
.rids
[resource_groups
->groups
.count
].rid
= rid
;
129 resource_groups
->groups
.rids
[resource_groups
->groups
.count
].attributes
= sid
->attrs
;
130 resource_groups
->groups
.count
++;
136 * Stores a SID in a previously allocated array, or excludes it if we are not
137 * storing resource groups. It will be placed in either Extra SIDs or Resource
138 * SIDs, depending on which is appropriate.
140 static NTSTATUS
store_sid(struct netr_SidAttr
*sids
,
142 const uint32_t allocated_sids
,
143 const struct auth_SidAttr
*sid
,
144 struct PAC_DOMAIN_GROUP_MEMBERSHIP
*resource_groups
,
145 const uint32_t allocated_resource_groups
,
146 const enum auth_group_inclusion group_inclusion
)
148 /* See if it's a resource SID. */
149 if (sid
->attrs
& SE_GROUP_RESOURCE
) {
151 * If this is the SID of a resource group, determine whether it
152 * should be included or filtered out.
154 switch (group_inclusion
) {
155 case AUTH_INCLUDE_RESOURCE_GROUPS
:
156 /* Include this SID in Extra SIDs. */
158 case AUTH_INCLUDE_RESOURCE_GROUPS_COMPRESSED
:
160 * Try to include this SID in Resource Groups. If this
161 * can't be arranged, we shall fall back to Extra
164 return store_resource_sid(sids
,
169 allocated_resource_groups
);
170 case AUTH_EXCLUDE_RESOURCE_GROUPS
:
171 /* Ignore this SID. */
174 /* This means we have a bug. */
175 DBG_ERR("invalid group inclusion parameter: %u\n", group_inclusion
);
176 return NT_STATUS_INVALID_PARAMETER
;
180 /* Just store the SID in Extra SIDs. */
181 return store_extra_sid(sids
,
187 static NTSTATUS
auth_convert_user_info_dc_sambaseinfo(TALLOC_CTX
*mem_ctx
,
188 const struct auth_user_info_dc
*user_info_dc
,
189 struct netr_SamBaseInfo
*sam
)
192 const struct auth_user_info
*info
;
196 if (user_info_dc
->num_sids
> PRIMARY_USER_SID_INDEX
) {
197 status
= dom_sid_split_rid(sam
, &user_info_dc
->sids
[PRIMARY_USER_SID_INDEX
].sid
,
198 &sam
->domain_sid
, &sam
->rid
);
199 if (!NT_STATUS_IS_OK(status
)) {
203 return NT_STATUS_INVALID_PARAMETER
;
206 if (user_info_dc
->num_sids
> PRIMARY_GROUP_SID_INDEX
) {
207 status
= dom_sid_split_rid(NULL
, &user_info_dc
->sids
[PRIMARY_GROUP_SID_INDEX
].sid
,
208 NULL
, &sam
->primary_gid
);
209 if (!NT_STATUS_IS_OK(status
)) {
213 /* if we have to encode something like SYSTEM (with no
214 * second SID in the token) then this is the only
216 sam
->primary_gid
= sam
->rid
;
219 info
= user_info_dc
->info
;
221 sam
->logon_time
= info
->last_logon
;
222 sam
->logoff_time
= info
->last_logoff
;
223 sam
->kickoff_time
= info
->acct_expiry
;
224 sam
->last_password_change
= info
->last_password_change
;
225 sam
->allow_password_change
= info
->allow_password_change
;
226 sam
->force_password_change
= info
->force_password_change
;
228 #define _COPY_STRING_TALLOC(src_name, dst_name) do { \
229 if (info->src_name != NULL) {\
230 sam->dst_name.string = talloc_strdup(mem_ctx, info->src_name); \
231 if (sam->dst_name.string == NULL) { \
232 return NT_STATUS_NO_MEMORY; \
236 _COPY_STRING_TALLOC(account_name
, account_name
);
237 _COPY_STRING_TALLOC(full_name
, full_name
);
238 _COPY_STRING_TALLOC(logon_script
, logon_script
);
239 _COPY_STRING_TALLOC(profile_path
, profile_path
);
240 _COPY_STRING_TALLOC(home_directory
, home_directory
);
241 _COPY_STRING_TALLOC(home_drive
, home_drive
);
242 _COPY_STRING_TALLOC(logon_server
, logon_server
);
243 _COPY_STRING_TALLOC(domain_name
, logon_domain
);
244 #undef _COPY_STRING_TALLOC
246 sam
->logon_count
= info
->logon_count
;
247 sam
->bad_password_count
= info
->bad_password_count
;
248 sam
->groups
.count
= 0;
249 sam
->groups
.rids
= NULL
;
251 if (user_info_dc
->num_sids
> REMAINING_SIDS_INDEX
) {
253 sam
->groups
.rids
= talloc_array(mem_ctx
, struct samr_RidWithAttribute
,
254 user_info_dc
->num_sids
);
256 if (sam
->groups
.rids
== NULL
)
257 return NT_STATUS_NO_MEMORY
;
259 for (i
=REMAINING_SIDS_INDEX
; i
<user_info_dc
->num_sids
; i
++) {
260 struct auth_SidAttr
*group_sid
= &user_info_dc
->sids
[i
];
262 bool belongs_in_base
= is_base_sid(group_sid
, sam
->domain_sid
);
263 if (!belongs_in_base
) {
264 /* We handle this elsewhere */
267 sam
->groups
.rids
[sam
->groups
.count
].rid
=
268 group_sid
->sid
.sub_auths
[group_sid
->sid
.num_auths
-1];
270 sam
->groups
.rids
[sam
->groups
.count
].attributes
= group_sid
->attrs
;
271 sam
->groups
.count
+= 1;
274 if (sam
->groups
.count
== 0) {
275 TALLOC_FREE(sam
->groups
.rids
);
279 sam
->user_flags
= info
->user_flags
; /* w2k3 uses NETLOGON_EXTRA_SIDS | NETLOGON_NTLMV2_ENABLED */
280 sam
->acct_flags
= user_info_dc
->info
->acct_flags
;
281 sam
->sub_auth_status
= 0;
282 sam
->last_successful_logon
= 0;
283 sam
->last_failed_logon
= 0;
284 sam
->failed_logon_count
= 0;
287 ZERO_STRUCT(sam
->key
);
288 if (user_info_dc
->user_session_key
.length
== sizeof(sam
->key
.key
)) {
289 memcpy(sam
->key
.key
, user_info_dc
->user_session_key
.data
, sizeof(sam
->key
.key
));
292 ZERO_STRUCT(sam
->LMSessKey
);
293 if (user_info_dc
->lm_session_key
.length
== sizeof(sam
->LMSessKey
.key
)) {
294 memcpy(sam
->LMSessKey
.key
, user_info_dc
->lm_session_key
.data
,
295 sizeof(sam
->LMSessKey
.key
));
301 /* Note that the validity of the _sam6 and resource_groups structures is only as
302 * long as the user_info_dc it was generated from */
303 NTSTATUS
auth_convert_user_info_dc_saminfo6(TALLOC_CTX
*mem_ctx
,
304 const struct auth_user_info_dc
*user_info_dc
,
305 enum auth_group_inclusion group_inclusion
,
306 struct netr_SamInfo6
**_sam6
,
307 struct PAC_DOMAIN_GROUP_MEMBERSHIP
**_resource_groups
)
310 struct netr_SamInfo6
*sam6
= NULL
;
311 struct PAC_DOMAIN_GROUP_MEMBERSHIP
*resource_groups
= NULL
;
314 const uint32_t allocated_sids
= user_info_dc
->num_sids
;
315 uint32_t allocated_resource_groups
= 0;
317 sam6
= talloc_zero(mem_ctx
, struct netr_SamInfo6
);
319 return NT_STATUS_NO_MEMORY
;
322 if (_resource_groups
== NULL
) {
323 if (group_inclusion
== AUTH_INCLUDE_RESOURCE_GROUPS_COMPRESSED
) {
324 DBG_ERR("_resource_groups parameter not provided to receive resource groups!\n");
326 return NT_STATUS_INVALID_PARAMETER
;
328 } else if (group_inclusion
== AUTH_INCLUDE_RESOURCE_GROUPS_COMPRESSED
) {
329 *_resource_groups
= NULL
;
331 /* Allocate resource groups structure. */
332 resource_groups
= talloc_zero(mem_ctx
, struct PAC_DOMAIN_GROUP_MEMBERSHIP
);
333 if (resource_groups
== NULL
) {
335 return NT_STATUS_NO_MEMORY
;
339 * Allocate enough space to store user_info_dc->num_sids
340 * RIDs in the worst case.
342 allocated_resource_groups
= user_info_dc
->num_sids
;
343 resource_groups
->groups
.rids
= talloc_zero_array(resource_groups
,
344 struct samr_RidWithAttribute
,
345 allocated_resource_groups
);
346 if (resource_groups
->groups
.rids
== NULL
) {
348 TALLOC_FREE(resource_groups
);
349 return NT_STATUS_NO_MEMORY
;
352 /* No resource groups will be provided. */
353 *_resource_groups
= NULL
;
356 status
= auth_convert_user_info_dc_sambaseinfo(sam6
,
359 if (!NT_STATUS_IS_OK(status
)) {
361 TALLOC_FREE(resource_groups
);
366 * Allocate enough space to store user_info_dc->num_sids SIDs in the
369 sam6
->sids
= talloc_zero_array(sam6
, struct netr_SidAttr
,
371 if (sam6
->sids
== NULL
) {
373 TALLOC_FREE(resource_groups
);
374 return NT_STATUS_NO_MEMORY
;
377 /* We don't put the user and group SIDs in there */
378 for (i
=REMAINING_SIDS_INDEX
; i
<user_info_dc
->num_sids
; i
++) {
379 struct auth_SidAttr
*group_sid
= &user_info_dc
->sids
[i
];
380 bool belongs_in_base
= is_base_sid(group_sid
, sam6
->base
.domain_sid
);
381 if (belongs_in_base
) {
382 /* We already handled this in the base. */
386 status
= store_sid(sam6
->sids
,
391 allocated_resource_groups
,
393 if (!NT_STATUS_IS_OK(status
)) {
395 TALLOC_FREE(resource_groups
);
399 if (sam6
->sidcount
) {
400 sam6
->base
.user_flags
|= NETLOGON_EXTRA_SIDS
;
402 sam6
->base
.user_flags
&= ~NETLOGON_EXTRA_SIDS
;
403 TALLOC_FREE(sam6
->sids
);
406 if (user_info_dc
->info
->dns_domain_name
!= NULL
) {
407 sam6
->dns_domainname
.string
= talloc_strdup(sam6
,
408 user_info_dc
->info
->dns_domain_name
);
409 if (sam6
->dns_domainname
.string
== NULL
) {
411 TALLOC_FREE(resource_groups
);
412 return NT_STATUS_NO_MEMORY
;
416 if (user_info_dc
->info
->user_principal_name
!= NULL
) {
417 sam6
->principal_name
.string
= talloc_strdup(sam6
,
418 user_info_dc
->info
->user_principal_name
);
419 if (sam6
->principal_name
.string
== NULL
) {
421 TALLOC_FREE(resource_groups
);
422 return NT_STATUS_NO_MEMORY
;
427 if (resource_groups
!= NULL
) {
428 if (resource_groups
->groups
.count
> 0) {
429 *_resource_groups
= resource_groups
;
431 TALLOC_FREE(resource_groups
);
437 /* Note that the validity of the _sam2 structure is only as long as
438 * the user_info_dc it was generated from */
439 NTSTATUS
auth_convert_user_info_dc_saminfo2(TALLOC_CTX
*mem_ctx
,
440 const struct auth_user_info_dc
*user_info_dc
,
441 enum auth_group_inclusion group_inclusion
,
442 struct netr_SamInfo2
**_sam2
)
445 struct netr_SamInfo6
*sam6
= NULL
;
446 struct netr_SamInfo2
*sam2
= NULL
;
448 sam2
= talloc_zero(mem_ctx
, struct netr_SamInfo2
);
450 return NT_STATUS_NO_MEMORY
;
453 status
= auth_convert_user_info_dc_saminfo6(sam2
, user_info_dc
,
454 group_inclusion
, &sam6
,
456 if (!NT_STATUS_IS_OK(status
)) {
460 sam2
->base
= sam6
->base
;
462 * We have nowhere to put sam6->sids, so we follow Windows here and drop
463 * it. Any resource groups it happened to be contain are lost.
465 sam2
->base
.user_flags
&= ~NETLOGON_EXTRA_SIDS
;
466 TALLOC_FREE(sam6
->sids
);
472 /* Note that the validity of the _sam3 structure is only as long as
473 * the user_info_dc it was generated from */
474 NTSTATUS
auth_convert_user_info_dc_saminfo3(TALLOC_CTX
*mem_ctx
,
475 const struct auth_user_info_dc
*user_info_dc
,
476 enum auth_group_inclusion group_inclusion
,
477 struct netr_SamInfo3
**_sam3
,
478 struct PAC_DOMAIN_GROUP_MEMBERSHIP
**_resource_groups
)
481 struct netr_SamInfo6
*sam6
= NULL
;
482 struct netr_SamInfo3
*sam3
= NULL
;
484 sam3
= talloc_zero(mem_ctx
, struct netr_SamInfo3
);
486 return NT_STATUS_NO_MEMORY
;
489 status
= auth_convert_user_info_dc_saminfo6(sam3
, user_info_dc
,
490 group_inclusion
, &sam6
,
492 if (!NT_STATUS_IS_OK(status
)) {
496 sam3
->base
= sam6
->base
;
497 sam3
->sidcount
= sam6
->sidcount
;
498 sam3
->sids
= sam6
->sids
;
505 * Make a user_info struct from the info3 or similar returned by a domain logon.
507 * The netr_SamInfo3 is also a key structure in the source3 auth subsystem
510 NTSTATUS
make_user_info_SamBaseInfo(TALLOC_CTX
*mem_ctx
,
511 const char *account_name
,
512 const struct netr_SamBaseInfo
*base
,
514 struct auth_user_info
**_user_info
)
516 struct auth_user_info
*info
;
518 info
= talloc_zero(mem_ctx
, struct auth_user_info
);
520 return NT_STATUS_NO_MEMORY
;
523 if (base
->account_name
.string
) {
524 info
->account_name
= talloc_strdup(info
, base
->account_name
.string
);
526 info
->account_name
= talloc_strdup(info
, account_name
);
528 if (info
->account_name
== NULL
) {
530 return NT_STATUS_NO_MEMORY
;
533 if (base
->logon_domain
.string
) {
534 info
->domain_name
= talloc_strdup(info
, base
->logon_domain
.string
);
535 if (info
->domain_name
== NULL
) {
537 return NT_STATUS_NO_MEMORY
;
541 if (base
->full_name
.string
) {
542 info
->full_name
= talloc_strdup(info
, base
->full_name
.string
);
543 if (info
->full_name
== NULL
) {
545 return NT_STATUS_NO_MEMORY
;
548 if (base
->logon_script
.string
) {
549 info
->logon_script
= talloc_strdup(info
, base
->logon_script
.string
);
550 if (info
->logon_script
== NULL
) {
552 return NT_STATUS_NO_MEMORY
;
555 if (base
->profile_path
.string
) {
556 info
->profile_path
= talloc_strdup(info
, base
->profile_path
.string
);
557 if (info
->profile_path
== NULL
) {
559 return NT_STATUS_NO_MEMORY
;
562 if (base
->home_directory
.string
) {
563 info
->home_directory
= talloc_strdup(info
, base
->home_directory
.string
);
564 if (info
->home_directory
== NULL
) {
566 return NT_STATUS_NO_MEMORY
;
569 if (base
->home_drive
.string
) {
570 info
->home_drive
= talloc_strdup(info
, base
->home_drive
.string
);
571 if (info
->home_drive
== NULL
) {
573 return NT_STATUS_NO_MEMORY
;
576 if (base
->logon_server
.string
) {
577 info
->logon_server
= talloc_strdup(info
, base
->logon_server
.string
);
578 if (info
->logon_server
== NULL
) {
580 return NT_STATUS_NO_MEMORY
;
583 info
->last_logon
= base
->logon_time
;
584 info
->last_logoff
= base
->logoff_time
;
585 info
->acct_expiry
= base
->kickoff_time
;
586 info
->last_password_change
= base
->last_password_change
;
587 info
->allow_password_change
= base
->allow_password_change
;
588 info
->force_password_change
= base
->force_password_change
;
589 info
->logon_count
= base
->logon_count
;
590 info
->bad_password_count
= base
->bad_password_count
;
591 info
->acct_flags
= base
->acct_flags
;
593 info
->user_flags
= base
->user_flags
;
594 if (!authenticated
) {
596 * We only consider the user authenticated if NETLOGON_GUEST is
597 * not set, and authenticated is set
599 info
->user_flags
|= NETLOGON_GUEST
;
606 struct auth_user_info
*auth_user_info_copy(TALLOC_CTX
*mem_ctx
,
607 const struct auth_user_info
*src
)
609 struct auth_user_info
*dst
= NULL
;
611 dst
= talloc_zero(mem_ctx
, struct auth_user_info
);
617 #define _COPY_STRING(_mem, _str) do { \
618 if ((_str) != NULL) { \
619 (_str) = talloc_strdup((_mem), (_str)); \
620 if ((_str) == NULL) { \
626 _COPY_STRING(dst
, dst
->account_name
);
627 _COPY_STRING(dst
, dst
->user_principal_name
);
628 _COPY_STRING(dst
, dst
->domain_name
);
629 _COPY_STRING(dst
, dst
->dns_domain_name
);
630 _COPY_STRING(dst
, dst
->full_name
);
631 _COPY_STRING(dst
, dst
->logon_script
);
632 _COPY_STRING(dst
, dst
->profile_path
);
633 _COPY_STRING(dst
, dst
->home_directory
);
634 _COPY_STRING(dst
, dst
->home_drive
);
635 _COPY_STRING(dst
, dst
->logon_server
);
642 * Make a user_info_dc struct from the info3 returned by a domain logon
644 NTSTATUS
make_user_info_dc_netlogon_validation(TALLOC_CTX
*mem_ctx
,
645 const char *account_name
,
646 uint16_t validation_level
,
647 const union netr_Validation
*validation
,
649 struct auth_user_info_dc
**_user_info_dc
)
652 struct auth_user_info_dc
*user_info_dc
= NULL
;
653 const struct netr_SamBaseInfo
*base
= NULL
;
654 uint32_t sidcount
= 0;
655 const struct netr_SidAttr
*sids
= NULL
;
656 const char *dns_domainname
= NULL
;
657 const char *principal
= NULL
;
660 switch (validation_level
) {
662 if (!validation
|| !validation
->sam2
) {
663 return NT_STATUS_INVALID_PARAMETER
;
665 base
= &validation
->sam2
->base
;
668 if (!validation
|| !validation
->sam3
) {
669 return NT_STATUS_INVALID_PARAMETER
;
671 base
= &validation
->sam3
->base
;
672 sidcount
= validation
->sam3
->sidcount
;
673 sids
= validation
->sam3
->sids
;
676 if (!validation
|| !validation
->sam6
) {
677 return NT_STATUS_INVALID_PARAMETER
;
679 base
= &validation
->sam6
->base
;
680 sidcount
= validation
->sam6
->sidcount
;
681 sids
= validation
->sam6
->sids
;
682 dns_domainname
= validation
->sam6
->dns_domainname
.string
;
683 principal
= validation
->sam6
->principal_name
.string
;
686 return NT_STATUS_INVALID_LEVEL
;
689 user_info_dc
= talloc_zero(mem_ctx
, struct auth_user_info_dc
);
690 if (user_info_dc
== NULL
) {
691 return NT_STATUS_NO_MEMORY
;
695 Here is where we should check the list of
696 trusted domains, and verify that the SID
699 if (!base
->domain_sid
) {
700 DEBUG(0, ("Cannot operate on a Netlogon Validation without a domain SID\n"));
701 talloc_free(user_info_dc
);
702 return NT_STATUS_INVALID_PARAMETER
;
705 /* The IDL layer would be a better place to check this, but to
706 * guard the integer addition below, we double-check */
707 if (base
->groups
.count
> 65535) {
708 talloc_free(user_info_dc
);
709 return NT_STATUS_INVALID_PARAMETER
;
712 user_info_dc
->num_sids
= PRIMARY_SIDS_COUNT
;
714 user_info_dc
->sids
= talloc_array(user_info_dc
, struct auth_SidAttr
, user_info_dc
->num_sids
+ base
->groups
.count
);
715 if (user_info_dc
->sids
== NULL
) {
716 talloc_free(user_info_dc
);
717 return NT_STATUS_NO_MEMORY
;
720 user_info_dc
->sids
[PRIMARY_USER_SID_INDEX
].sid
= *base
->domain_sid
;
721 if (!sid_append_rid(&user_info_dc
->sids
[PRIMARY_USER_SID_INDEX
].sid
, base
->rid
)) {
722 talloc_free(user_info_dc
);
723 return NT_STATUS_INVALID_PARAMETER
;
725 user_info_dc
->sids
[PRIMARY_USER_SID_INDEX
].attrs
= SE_GROUP_DEFAULT_FLAGS
;
727 user_info_dc
->sids
[PRIMARY_GROUP_SID_INDEX
].sid
= *base
->domain_sid
;
728 if (!sid_append_rid(&user_info_dc
->sids
[PRIMARY_GROUP_SID_INDEX
].sid
, base
->primary_gid
)) {
729 talloc_free(user_info_dc
);
730 return NT_STATUS_INVALID_PARAMETER
;
733 * This attribute value might be wrong if the primary group is a
734 * resource group. But a resource group is not meant to be in a primary
735 * group in the first place, and besides, these attributes will never
736 * make their way into a PAC.
738 user_info_dc
->sids
[PRIMARY_GROUP_SID_INDEX
].attrs
= SE_GROUP_DEFAULT_FLAGS
;
740 for (i
= 0; i
< base
->groups
.count
; i
++) {
741 user_info_dc
->sids
[user_info_dc
->num_sids
].sid
= *base
->domain_sid
;
742 if (!sid_append_rid(&user_info_dc
->sids
[user_info_dc
->num_sids
].sid
, base
->groups
.rids
[i
].rid
)) {
743 talloc_free(user_info_dc
);
744 return NT_STATUS_INVALID_PARAMETER
;
746 user_info_dc
->sids
[user_info_dc
->num_sids
].attrs
= base
->groups
.rids
[i
].attributes
;
747 user_info_dc
->num_sids
++;
750 /* Copy 'other' sids. We need to do sid filtering here to
751 prevent possible elevation of privileges. See:
753 http://www.microsoft.com/windows2000/techinfo/administration/security/sidfilter.asp
757 * The IDL layer would be a better place to check this, but to
758 * guard the integer addition below, we double-check
760 if (sidcount
> UINT16_MAX
) {
761 talloc_free(user_info_dc
);
762 return NT_STATUS_INVALID_PARAMETER
;
766 struct auth_SidAttr
*dgrps
= user_info_dc
->sids
;
769 dgrps_count
= user_info_dc
->num_sids
+ sidcount
;
770 dgrps
= talloc_realloc(user_info_dc
, dgrps
, struct auth_SidAttr
,
773 talloc_free(user_info_dc
);
774 return NT_STATUS_NO_MEMORY
;
777 for (i
= 0; i
< sidcount
; i
++) {
779 dgrps
[user_info_dc
->num_sids
].sid
= *sids
[i
].sid
;
780 dgrps
[user_info_dc
->num_sids
].attrs
= sids
[i
].attributes
;
781 user_info_dc
->num_sids
++;
785 user_info_dc
->sids
= dgrps
;
787 /* Where are the 'global' sids?... */
790 status
= make_user_info_SamBaseInfo(user_info_dc
, account_name
, base
, authenticated
, &user_info_dc
->info
);
791 if (!NT_STATUS_IS_OK(status
)) {
792 talloc_free(user_info_dc
);
796 if (dns_domainname
!= NULL
) {
797 user_info_dc
->info
->dns_domain_name
= talloc_strdup(user_info_dc
->info
,
799 if (user_info_dc
->info
->dns_domain_name
== NULL
) {
800 talloc_free(user_info_dc
);
801 return NT_STATUS_NO_MEMORY
;
805 if (principal
!= NULL
) {
806 user_info_dc
->info
->user_principal_name
= talloc_strdup(user_info_dc
->info
,
808 if (user_info_dc
->info
->user_principal_name
== NULL
) {
809 talloc_free(user_info_dc
);
810 return NT_STATUS_NO_MEMORY
;
814 /* ensure we are never given NULL session keys */
816 if (all_zero(base
->key
.key
, sizeof(base
->key
.key
))) {
817 user_info_dc
->user_session_key
= data_blob(NULL
, 0);
819 user_info_dc
->user_session_key
= data_blob_talloc(user_info_dc
, base
->key
.key
, sizeof(base
->key
.key
));
820 if (user_info_dc
->user_session_key
.data
== NULL
) {
821 talloc_free(user_info_dc
);
822 return NT_STATUS_NO_MEMORY
;
826 if (all_zero(base
->LMSessKey
.key
, sizeof(base
->LMSessKey
.key
))) {
827 user_info_dc
->lm_session_key
= data_blob(NULL
, 0);
829 user_info_dc
->lm_session_key
= data_blob_talloc(user_info_dc
, base
->LMSessKey
.key
, sizeof(base
->LMSessKey
.key
));
830 if (user_info_dc
->lm_session_key
.data
== NULL
) {
831 talloc_free(user_info_dc
);
832 return NT_STATUS_NO_MEMORY
;
836 *_user_info_dc
= user_info_dc
;
841 * Make a user_info_dc struct from the PAC_LOGON_INFO supplied in the krb5
842 * logon. For group_inclusion, pass AUTH_INCLUDE_RESOURCE_GROUPS if SIDs from
843 * the resource groups are to be included in the resulting structure, and pass
844 * AUTH_EXCLUDE_RESOURCE_GROUPS otherwise.
846 NTSTATUS
make_user_info_dc_pac(TALLOC_CTX
*mem_ctx
,
847 const struct PAC_LOGON_INFO
*pac_logon_info
,
848 const struct PAC_UPN_DNS_INFO
*pac_upn_dns_info
,
849 const enum auth_group_inclusion group_inclusion
,
850 struct auth_user_info_dc
**_user_info_dc
)
854 union netr_Validation validation
;
855 struct auth_user_info_dc
*user_info_dc
;
856 const struct PAC_DOMAIN_GROUP_MEMBERSHIP
*rg
= NULL
;
859 validation
.sam3
= discard_const_p(struct netr_SamInfo3
, &pac_logon_info
->info3
);
861 nt_status
= make_user_info_dc_netlogon_validation(mem_ctx
, "", 3, &validation
,
862 true, /* This user was authenticated */
864 if (!NT_STATUS_IS_OK(nt_status
)) {
868 if (pac_logon_info
->info3
.base
.user_flags
& NETLOGON_RESOURCE_GROUPS
) {
869 switch (group_inclusion
) {
870 case AUTH_INCLUDE_RESOURCE_GROUPS
:
871 /* Take resource groups from the PAC. */
872 rg
= &pac_logon_info
->resource_groups
;
874 case AUTH_EXCLUDE_RESOURCE_GROUPS
:
876 * The PAC is from a TGT, or we don't want to process
877 * its resource groups.
881 DBG_ERR("invalid group inclusion parameter: %u\n", group_inclusion
);
882 talloc_free(user_info_dc
);
883 return NT_STATUS_INVALID_PARAMETER
;
887 if (rg
!= NULL
&& rg
->groups
.count
> 0) {
888 /* The IDL layer would be a better place to check this, but to
889 * guard the integer addition below, we double-check */
890 if (rg
->groups
.count
> 65535) {
891 talloc_free(user_info_dc
);
892 return NT_STATUS_INVALID_PARAMETER
;
896 Here is where we should check the list of
897 trusted domains, and verify that the SID
900 if (rg
->domain_sid
== NULL
) {
901 talloc_free(user_info_dc
);
902 DEBUG(0, ("Cannot operate on a PAC without a resource domain SID\n"));
903 return NT_STATUS_INVALID_PARAMETER
;
906 sidcount
= user_info_dc
->num_sids
+ rg
->groups
.count
;
908 = talloc_realloc(user_info_dc
, user_info_dc
->sids
, struct auth_SidAttr
, sidcount
);
909 if (user_info_dc
->sids
== NULL
) {
910 TALLOC_FREE(user_info_dc
);
911 return NT_STATUS_NO_MEMORY
;
914 for (i
= 0; i
< rg
->groups
.count
; i
++) {
917 user_info_dc
->sids
[user_info_dc
->num_sids
].sid
= *rg
->domain_sid
;
918 ok
= sid_append_rid(&user_info_dc
->sids
[user_info_dc
->num_sids
].sid
,
919 rg
->groups
.rids
[i
].rid
);
921 talloc_free(user_info_dc
);
922 return NT_STATUS_INVALID_PARAMETER
;
924 user_info_dc
->sids
[user_info_dc
->num_sids
].attrs
= rg
->groups
.rids
[i
].attributes
;
925 user_info_dc
->num_sids
++;
929 if (pac_upn_dns_info
!= NULL
) {
930 if (pac_upn_dns_info
->upn_name
!= NULL
) {
931 user_info_dc
->info
->user_principal_name
=
932 talloc_strdup(user_info_dc
->info
,
933 pac_upn_dns_info
->upn_name
);
934 if (user_info_dc
->info
->user_principal_name
== NULL
) {
935 talloc_free(user_info_dc
);
936 return NT_STATUS_NO_MEMORY
;
940 user_info_dc
->info
->dns_domain_name
=
941 talloc_strdup(user_info_dc
->info
,
942 pac_upn_dns_info
->dns_domain_name
);
943 if (user_info_dc
->info
->dns_domain_name
== NULL
) {
944 talloc_free(user_info_dc
);
945 return NT_STATUS_NO_MEMORY
;
948 if (pac_upn_dns_info
->flags
& PAC_UPN_DNS_FLAG_CONSTRUCTED
) {
949 user_info_dc
->info
->user_principal_constructed
= true;
953 *_user_info_dc
= user_info_dc
;