s3: smbd: Duplicate smb_file_link_information() hardlink handling as smb2_file_link_i...
[Samba.git] / auth / auth_sam_reply.c
blob8e0089eb8d138bb4247185c3677d8634b695c1d6
1 /*
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/>.
23 #include "includes.h"
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.
37 return false;
41 * This SID belongs in the base structure only if it's in the account's
42 * domain.
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,
49 uint32_t *sidcount,
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;
63 *sidcount += 1;
65 return NT_STATUS_OK;
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,
74 uint32_t *sidcount,
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)
80 NTSTATUS status;
82 struct dom_sid *resource_domain = NULL;
83 uint32_t rid;
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)) {
92 return 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;
100 } else {
102 * A domain SID has already been set. Check whether this SID's
103 * domain matches.
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);
112 if (!match) {
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++;
132 return NT_STATUS_OK;
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,
141 uint32_t *sidcount,
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. */
157 break;
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
162 * SIDs.
164 return store_resource_sid(sids,
165 sidcount,
166 allocated_sids,
167 sid,
168 resource_groups,
169 allocated_resource_groups);
170 case AUTH_EXCLUDE_RESOURCE_GROUPS:
171 /* Ignore this SID. */
172 return NT_STATUS_OK;
173 default:
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,
182 sidcount,
183 allocated_sids,
184 sid);
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)
191 NTSTATUS status;
192 const struct auth_user_info *info;
194 ZERO_STRUCTP(sam);
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)) {
200 return status;
202 } else {
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)) {
210 return status;
212 } else {
213 /* if we have to encode something like SYSTEM (with no
214 * second SID in the token) then this is the only
215 * choice */
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; \
235 } while(0)
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) {
252 size_t i;
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 */
265 continue;
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;
285 sam->reserved = 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));
298 return NT_STATUS_OK;
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)
309 NTSTATUS status;
310 struct netr_SamInfo6 *sam6 = NULL;
311 struct PAC_DOMAIN_GROUP_MEMBERSHIP *resource_groups = NULL;
312 size_t i;
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);
318 if (sam6 == NULL) {
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");
325 TALLOC_FREE(sam6);
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) {
334 TALLOC_FREE(sam6);
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) {
347 TALLOC_FREE(sam6);
348 TALLOC_FREE(resource_groups);
349 return NT_STATUS_NO_MEMORY;
351 } else {
352 /* No resource groups will be provided. */
353 *_resource_groups = NULL;
356 status = auth_convert_user_info_dc_sambaseinfo(sam6,
357 user_info_dc,
358 &sam6->base);
359 if (!NT_STATUS_IS_OK(status)) {
360 TALLOC_FREE(sam6);
361 TALLOC_FREE(resource_groups);
362 return status;
366 * Allocate enough space to store user_info_dc->num_sids SIDs in the
367 * worst case.
369 sam6->sids = talloc_zero_array(sam6, struct netr_SidAttr,
370 allocated_sids);
371 if (sam6->sids == NULL) {
372 TALLOC_FREE(sam6);
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. */
383 continue;
386 status = store_sid(sam6->sids,
387 &sam6->sidcount,
388 allocated_sids,
389 group_sid,
390 resource_groups,
391 allocated_resource_groups,
392 group_inclusion);
393 if (!NT_STATUS_IS_OK(status)) {
394 TALLOC_FREE(sam6);
395 TALLOC_FREE(resource_groups);
396 return status;
399 if (sam6->sidcount) {
400 sam6->base.user_flags |= NETLOGON_EXTRA_SIDS;
401 } else {
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) {
410 TALLOC_FREE(sam6);
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) {
420 TALLOC_FREE(sam6);
421 TALLOC_FREE(resource_groups);
422 return NT_STATUS_NO_MEMORY;
426 *_sam6 = sam6;
427 if (resource_groups != NULL) {
428 if (resource_groups->groups.count > 0) {
429 *_resource_groups = resource_groups;
430 } else {
431 TALLOC_FREE(resource_groups);
434 return NT_STATUS_OK;
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)
444 NTSTATUS status;
445 struct netr_SamInfo6 *sam6 = NULL;
446 struct netr_SamInfo2 *sam2 = NULL;
448 sam2 = talloc_zero(mem_ctx, struct netr_SamInfo2);
449 if (sam2 == NULL) {
450 return NT_STATUS_NO_MEMORY;
453 status = auth_convert_user_info_dc_saminfo6(sam2, user_info_dc,
454 group_inclusion, &sam6,
455 NULL);
456 if (!NT_STATUS_IS_OK(status)) {
457 TALLOC_FREE(sam2);
458 return 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);
468 *_sam2 = sam2;
469 return NT_STATUS_OK;
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)
480 NTSTATUS status;
481 struct netr_SamInfo6 *sam6 = NULL;
482 struct netr_SamInfo3 *sam3 = NULL;
484 sam3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
485 if (sam3 == NULL) {
486 return NT_STATUS_NO_MEMORY;
489 status = auth_convert_user_info_dc_saminfo6(sam3, user_info_dc,
490 group_inclusion, &sam6,
491 _resource_groups);
492 if (!NT_STATUS_IS_OK(status)) {
493 TALLOC_FREE(sam3);
494 return status;
496 sam3->base = sam6->base;
497 sam3->sidcount = sam6->sidcount;
498 sam3->sids = sam6->sids;
500 *_sam3 = sam3;
501 return NT_STATUS_OK;
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,
513 bool authenticated,
514 struct auth_user_info **_user_info)
516 struct auth_user_info *info;
518 info = talloc_zero(mem_ctx, struct auth_user_info);
519 NT_STATUS_HAVE_NO_MEMORY(info);
521 if (base->account_name.string) {
522 info->account_name = talloc_strdup(info, base->account_name.string);
523 } else {
524 info->account_name = talloc_strdup(info, account_name);
526 NT_STATUS_HAVE_NO_MEMORY(info->account_name);
528 if (base->logon_domain.string) {
529 info->domain_name = talloc_strdup(info, base->logon_domain.string);
530 NT_STATUS_HAVE_NO_MEMORY(info->domain_name);
533 if (base->full_name.string) {
534 info->full_name = talloc_strdup(info, base->full_name.string);
535 NT_STATUS_HAVE_NO_MEMORY(info->full_name);
537 if (base->logon_script.string) {
538 info->logon_script = talloc_strdup(info, base->logon_script.string);
539 NT_STATUS_HAVE_NO_MEMORY(info->logon_script);
541 if (base->profile_path.string) {
542 info->profile_path = talloc_strdup(info, base->profile_path.string);
543 NT_STATUS_HAVE_NO_MEMORY(info->profile_path);
545 if (base->home_directory.string) {
546 info->home_directory = talloc_strdup(info, base->home_directory.string);
547 NT_STATUS_HAVE_NO_MEMORY(info->home_directory);
549 if (base->home_drive.string) {
550 info->home_drive = talloc_strdup(info, base->home_drive.string);
551 NT_STATUS_HAVE_NO_MEMORY(info->home_drive);
553 if (base->logon_server.string) {
554 info->logon_server = talloc_strdup(info, base->logon_server.string);
555 NT_STATUS_HAVE_NO_MEMORY(info->logon_server);
557 info->last_logon = base->logon_time;
558 info->last_logoff = base->logoff_time;
559 info->acct_expiry = base->kickoff_time;
560 info->last_password_change = base->last_password_change;
561 info->allow_password_change = base->allow_password_change;
562 info->force_password_change = base->force_password_change;
563 info->logon_count = base->logon_count;
564 info->bad_password_count = base->bad_password_count;
565 info->acct_flags = base->acct_flags;
567 info->user_flags = base->user_flags;
568 if (!authenticated) {
570 * We only consider the user authenticated if NETLOGON_GUEST is
571 * not set, and authenticated is set
573 info->user_flags |= NETLOGON_GUEST;
576 *_user_info = info;
577 return NT_STATUS_OK;
580 struct auth_user_info *auth_user_info_copy(TALLOC_CTX *mem_ctx,
581 const struct auth_user_info *src)
583 struct auth_user_info *dst = NULL;
585 dst = talloc_zero(mem_ctx, struct auth_user_info);
586 if (dst == NULL) {
587 return NULL;
590 *dst = *src;
591 #define _COPY_STRING(_mem, _str) do { \
592 if ((_str) != NULL) { \
593 (_str) = talloc_strdup((_mem), (_str)); \
594 if ((_str) == NULL) { \
595 TALLOC_FREE(dst); \
596 return NULL; \
599 } while(0)
600 _COPY_STRING(dst, dst->account_name);
601 _COPY_STRING(dst, dst->user_principal_name);
602 _COPY_STRING(dst, dst->domain_name);
603 _COPY_STRING(dst, dst->dns_domain_name);
604 _COPY_STRING(dst, dst->full_name);
605 _COPY_STRING(dst, dst->logon_script);
606 _COPY_STRING(dst, dst->profile_path);
607 _COPY_STRING(dst, dst->home_directory);
608 _COPY_STRING(dst, dst->home_drive);
609 _COPY_STRING(dst, dst->logon_server);
610 #undef _COPY_STRING
612 return dst;
616 * Make a user_info_dc struct from the info3 returned by a domain logon
618 NTSTATUS make_user_info_dc_netlogon_validation(TALLOC_CTX *mem_ctx,
619 const char *account_name,
620 uint16_t validation_level,
621 const union netr_Validation *validation,
622 bool authenticated,
623 struct auth_user_info_dc **_user_info_dc)
625 NTSTATUS status;
626 struct auth_user_info_dc *user_info_dc = NULL;
627 const struct netr_SamBaseInfo *base = NULL;
628 uint32_t sidcount = 0;
629 const struct netr_SidAttr *sids = NULL;
630 const char *dns_domainname = NULL;
631 const char *principal = NULL;
632 uint32_t i;
634 switch (validation_level) {
635 case 2:
636 if (!validation || !validation->sam2) {
637 return NT_STATUS_INVALID_PARAMETER;
639 base = &validation->sam2->base;
640 break;
641 case 3:
642 if (!validation || !validation->sam3) {
643 return NT_STATUS_INVALID_PARAMETER;
645 base = &validation->sam3->base;
646 sidcount = validation->sam3->sidcount;
647 sids = validation->sam3->sids;
648 break;
649 case 6:
650 if (!validation || !validation->sam6) {
651 return NT_STATUS_INVALID_PARAMETER;
653 base = &validation->sam6->base;
654 sidcount = validation->sam6->sidcount;
655 sids = validation->sam6->sids;
656 dns_domainname = validation->sam6->dns_domainname.string;
657 principal = validation->sam6->principal_name.string;
658 break;
659 default:
660 return NT_STATUS_INVALID_LEVEL;
663 user_info_dc = talloc_zero(mem_ctx, struct auth_user_info_dc);
664 NT_STATUS_HAVE_NO_MEMORY(user_info_dc);
667 Here is where we should check the list of
668 trusted domains, and verify that the SID
669 matches.
671 if (!base->domain_sid) {
672 DEBUG(0, ("Cannot operate on a Netlogon Validation without a domain SID"));
673 return NT_STATUS_INVALID_PARAMETER;
676 /* The IDL layer would be a better place to check this, but to
677 * guard the integer addition below, we double-check */
678 if (base->groups.count > 65535) {
679 return NT_STATUS_INVALID_PARAMETER;
682 user_info_dc->num_sids = PRIMARY_SIDS_COUNT;
684 user_info_dc->sids = talloc_array(user_info_dc, struct auth_SidAttr, user_info_dc->num_sids + base->groups.count);
685 NT_STATUS_HAVE_NO_MEMORY(user_info_dc->sids);
687 user_info_dc->sids[PRIMARY_USER_SID_INDEX].sid = *base->domain_sid;
688 if (!sid_append_rid(&user_info_dc->sids[PRIMARY_USER_SID_INDEX].sid, base->rid)) {
689 return NT_STATUS_INVALID_PARAMETER;
691 user_info_dc->sids[PRIMARY_USER_SID_INDEX].attrs = SE_GROUP_DEFAULT_FLAGS;
693 user_info_dc->sids[PRIMARY_GROUP_SID_INDEX].sid = *base->domain_sid;
694 if (!sid_append_rid(&user_info_dc->sids[PRIMARY_GROUP_SID_INDEX].sid, base->primary_gid)) {
695 return NT_STATUS_INVALID_PARAMETER;
698 * This attribute value might be wrong if the primary group is a
699 * resource group. But a resource group is not meant to be in a primary
700 * group in the first place, and besides, these attributes will never
701 * make their way into a PAC.
703 user_info_dc->sids[PRIMARY_GROUP_SID_INDEX].attrs = SE_GROUP_DEFAULT_FLAGS;
705 for (i = 0; i < base->groups.count; i++) {
706 user_info_dc->sids[user_info_dc->num_sids].sid = *base->domain_sid;
707 if (!sid_append_rid(&user_info_dc->sids[user_info_dc->num_sids].sid, base->groups.rids[i].rid)) {
708 return NT_STATUS_INVALID_PARAMETER;
710 user_info_dc->sids[user_info_dc->num_sids].attrs = base->groups.rids[i].attributes;
711 user_info_dc->num_sids++;
714 /* Copy 'other' sids. We need to do sid filtering here to
715 prevent possible elevation of privileges. See:
717 http://www.microsoft.com/windows2000/techinfo/administration/security/sidfilter.asp
721 * The IDL layer would be a better place to check this, but to
722 * guard the integer addition below, we double-check
724 if (sidcount > UINT16_MAX) {
725 return NT_STATUS_INVALID_PARAMETER;
728 if (sidcount > 0) {
729 struct auth_SidAttr *dgrps = user_info_dc->sids;
730 size_t dgrps_count;
732 dgrps_count = user_info_dc->num_sids + sidcount;
733 dgrps = talloc_realloc(user_info_dc, dgrps, struct auth_SidAttr,
734 dgrps_count);
735 if (dgrps == NULL) {
736 return NT_STATUS_NO_MEMORY;
739 for (i = 0; i < sidcount; i++) {
740 if (sids[i].sid) {
741 dgrps[user_info_dc->num_sids].sid = *sids[i].sid;
742 dgrps[user_info_dc->num_sids].attrs = sids[i].attributes;
743 user_info_dc->num_sids++;
747 user_info_dc->sids = dgrps;
749 /* Where are the 'global' sids?... */
752 status = make_user_info_SamBaseInfo(user_info_dc, account_name, base, authenticated, &user_info_dc->info);
753 if (!NT_STATUS_IS_OK(status)) {
754 return status;
757 if (dns_domainname != NULL) {
758 user_info_dc->info->dns_domain_name = talloc_strdup(user_info_dc->info,
759 dns_domainname);
760 if (user_info_dc->info->dns_domain_name == NULL) {
761 return NT_STATUS_NO_MEMORY;
765 if (principal != NULL) {
766 user_info_dc->info->user_principal_name = talloc_strdup(user_info_dc->info,
767 principal);
768 if (user_info_dc->info->user_principal_name == NULL) {
769 return NT_STATUS_NO_MEMORY;
773 /* ensure we are never given NULL session keys */
775 if (all_zero(base->key.key, sizeof(base->key.key))) {
776 user_info_dc->user_session_key = data_blob(NULL, 0);
777 } else {
778 user_info_dc->user_session_key = data_blob_talloc(user_info_dc, base->key.key, sizeof(base->key.key));
779 NT_STATUS_HAVE_NO_MEMORY(user_info_dc->user_session_key.data);
782 if (all_zero(base->LMSessKey.key, sizeof(base->LMSessKey.key))) {
783 user_info_dc->lm_session_key = data_blob(NULL, 0);
784 } else {
785 user_info_dc->lm_session_key = data_blob_talloc(user_info_dc, base->LMSessKey.key, sizeof(base->LMSessKey.key));
786 NT_STATUS_HAVE_NO_MEMORY(user_info_dc->lm_session_key.data);
789 *_user_info_dc = user_info_dc;
790 return NT_STATUS_OK;
794 * Make a user_info_dc struct from the PAC_LOGON_INFO supplied in the krb5
795 * logon. For group_inclusion, pass AUTH_INCLUDE_RESOURCE_GROUPS if SIDs from
796 * the resource groups are to be included in the resulting structure, and pass
797 * AUTH_EXCLUDE_RESOURCE_GROUPS otherwise.
799 NTSTATUS make_user_info_dc_pac(TALLOC_CTX *mem_ctx,
800 const struct PAC_LOGON_INFO *pac_logon_info,
801 const struct PAC_UPN_DNS_INFO *pac_upn_dns_info,
802 const enum auth_group_inclusion group_inclusion,
803 struct auth_user_info_dc **_user_info_dc)
805 uint32_t i;
806 NTSTATUS nt_status;
807 union netr_Validation validation;
808 struct auth_user_info_dc *user_info_dc;
809 const struct PAC_DOMAIN_GROUP_MEMBERSHIP *rg = NULL;
810 size_t sidcount;
812 validation.sam3 = discard_const_p(struct netr_SamInfo3, &pac_logon_info->info3);
814 nt_status = make_user_info_dc_netlogon_validation(mem_ctx, "", 3, &validation,
815 true, /* This user was authenticated */
816 &user_info_dc);
817 if (!NT_STATUS_IS_OK(nt_status)) {
818 return nt_status;
821 if (pac_logon_info->info3.base.user_flags & NETLOGON_RESOURCE_GROUPS) {
822 switch (group_inclusion) {
823 case AUTH_INCLUDE_RESOURCE_GROUPS:
824 /* Take resource groups from the PAC. */
825 rg = &pac_logon_info->resource_groups;
826 break;
827 case AUTH_EXCLUDE_RESOURCE_GROUPS:
829 * The PAC is from a TGT, or we don't want to process
830 * its resource groups.
832 break;
833 default:
834 DBG_ERR("invalid group inclusion parameter: %u\n", group_inclusion);
835 return NT_STATUS_INVALID_PARAMETER;
839 if (rg != NULL && rg->groups.count > 0) {
840 /* The IDL layer would be a better place to check this, but to
841 * guard the integer addition below, we double-check */
842 if (rg->groups.count > 65535) {
843 talloc_free(user_info_dc);
844 return NT_STATUS_INVALID_PARAMETER;
848 Here is where we should check the list of
849 trusted domains, and verify that the SID
850 matches.
852 if (rg->domain_sid == NULL) {
853 talloc_free(user_info_dc);
854 DEBUG(0, ("Cannot operate on a PAC without a resource domain SID"));
855 return NT_STATUS_INVALID_PARAMETER;
858 sidcount = user_info_dc->num_sids + rg->groups.count;
859 user_info_dc->sids
860 = talloc_realloc(user_info_dc, user_info_dc->sids, struct auth_SidAttr, sidcount);
861 if (user_info_dc->sids == NULL) {
862 TALLOC_FREE(user_info_dc);
863 return NT_STATUS_NO_MEMORY;
866 for (i = 0; i < rg->groups.count; i++) {
867 bool ok;
869 user_info_dc->sids[user_info_dc->num_sids].sid = *rg->domain_sid;
870 ok = sid_append_rid(&user_info_dc->sids[user_info_dc->num_sids].sid,
871 rg->groups.rids[i].rid);
872 if (!ok) {
873 return NT_STATUS_INVALID_PARAMETER;
875 user_info_dc->sids[user_info_dc->num_sids].attrs = rg->groups.rids[i].attributes;
876 user_info_dc->num_sids++;
880 if (pac_upn_dns_info != NULL) {
881 if (pac_upn_dns_info->upn_name != NULL) {
882 user_info_dc->info->user_principal_name =
883 talloc_strdup(user_info_dc->info,
884 pac_upn_dns_info->upn_name);
885 if (user_info_dc->info->user_principal_name == NULL) {
886 return NT_STATUS_NO_MEMORY;
890 user_info_dc->info->dns_domain_name =
891 talloc_strdup(user_info_dc->info,
892 pac_upn_dns_info->dns_domain_name);
893 if (user_info_dc->info->dns_domain_name == NULL) {
894 return NT_STATUS_NO_MEMORY;
897 if (pac_upn_dns_info->flags & PAC_UPN_DNS_FLAG_CONSTRUCTED) {
898 user_info_dc->info->user_principal_constructed = true;
902 *_user_info_dc = user_info_dc;
903 return NT_STATUS_OK;