utils: Fix up 14a533680245
[samba4-gss.git] / auth / auth_sam_reply.c
blob8c0ebe5f156c5599dc47cf4d435e8a325738da6c
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 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 if (info == NULL) {
520 return NT_STATUS_NO_MEMORY;
523 if (base->account_name.string) {
524 info->account_name = talloc_strdup(info, base->account_name.string);
525 } else {
526 info->account_name = talloc_strdup(info, account_name);
528 if (info->account_name == NULL) {
529 talloc_free(info);
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) {
536 talloc_free(info);
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) {
544 talloc_free(info);
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) {
551 talloc_free(info);
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) {
558 talloc_free(info);
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) {
565 talloc_free(info);
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) {
572 talloc_free(info);
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) {
579 talloc_free(info);
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;
602 *_user_info = info;
603 return NT_STATUS_OK;
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);
612 if (dst == NULL) {
613 return NULL;
616 *dst = *src;
617 #define _COPY_STRING(_mem, _str) do { \
618 if ((_str) != NULL) { \
619 (_str) = talloc_strdup((_mem), (_str)); \
620 if ((_str) == NULL) { \
621 TALLOC_FREE(dst); \
622 return NULL; \
625 } while(0)
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);
636 #undef _COPY_STRING
638 return dst;
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,
648 bool authenticated,
649 struct auth_user_info_dc **_user_info_dc)
651 NTSTATUS status;
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;
658 uint32_t i;
660 switch (validation_level) {
661 case 2:
662 if (!validation || !validation->sam2) {
663 return NT_STATUS_INVALID_PARAMETER;
665 base = &validation->sam2->base;
666 break;
667 case 3:
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;
674 break;
675 case 6:
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;
684 break;
685 default:
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
697 matches.
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;
765 if (sidcount > 0) {
766 struct auth_SidAttr *dgrps = user_info_dc->sids;
767 size_t dgrps_count;
769 dgrps_count = user_info_dc->num_sids + sidcount;
770 dgrps = talloc_realloc(user_info_dc, dgrps, struct auth_SidAttr,
771 dgrps_count);
772 if (dgrps == NULL) {
773 talloc_free(user_info_dc);
774 return NT_STATUS_NO_MEMORY;
777 for (i = 0; i < sidcount; i++) {
778 if (sids[i].sid) {
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);
793 return status;
796 if (dns_domainname != NULL) {
797 user_info_dc->info->dns_domain_name = talloc_strdup(user_info_dc->info,
798 dns_domainname);
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,
807 principal);
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);
818 } else {
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);
828 } else {
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;
837 return NT_STATUS_OK;
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)
852 uint32_t i;
853 NTSTATUS nt_status;
854 union netr_Validation validation;
855 struct auth_user_info_dc *user_info_dc;
856 const struct PAC_DOMAIN_GROUP_MEMBERSHIP *rg = NULL;
857 size_t sidcount;
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 */
863 &user_info_dc);
864 if (!NT_STATUS_IS_OK(nt_status)) {
865 return 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;
873 break;
874 case AUTH_EXCLUDE_RESOURCE_GROUPS:
876 * The PAC is from a TGT, or we don't want to process
877 * its resource groups.
879 break;
880 default:
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
898 matches.
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;
907 user_info_dc->sids
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++) {
915 bool ok;
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);
920 if (!ok) {
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;
954 return NT_STATUS_OK;