build: Make "samba4" public libraries provided (mostly) for OpenChange private
[samba.git] / auth / auth_sam_reply.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Convert a server info struct into the form for PAC and NETLOGON replies
5
6    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2011
7    Copyright (C) Stefan Metzmacher <metze@samba.org>  2005
8
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.
13
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.
18
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/>.
21 */
22
23 #include "includes.h"
24 #include "librpc/gen_ndr/auth.h"
25 #include "libcli/security/security.h"
26 #include "auth/auth_sam_reply.h"
27
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)
31 {
32         if (sid->attrs & SE_GROUP_RESOURCE) {
33                 /*
34                  * Resource groups don't belong in the base
35                  * RIDs, they're handled elsewhere.
36                  */
37                 return false;
38         }
39
40         /*
41          * This SID belongs in the base structure only if it's in the account's
42          * domain.
43          */
44         return dom_sid_in_domain(domain_sid, &sid->sid);
45 }
46
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)
52 {
53         /* Check we aren't about to overflow our allocation. */
54         if (*sidcount >= allocated_sids) {
55                 return NT_STATUS_INVALID_PARAMETER;
56         }
57
58         sids[*sidcount].sid = dom_sid_dup(sids, &sid->sid);
59         if (sids[*sidcount].sid == NULL) {
60                 return NT_STATUS_NO_MEMORY;
61         }
62         sids[*sidcount].attributes = sid->attrs;
63         *sidcount += 1;
64
65         return NT_STATUS_OK;
66 }
67
68 /*
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.
72  */
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)
79 {
80         NTSTATUS status;
81
82         struct dom_sid *resource_domain = NULL;
83         uint32_t rid;
84
85         if (resource_groups == NULL) {
86                 return NT_STATUS_INVALID_PARAMETER;
87         }
88
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;
93         }
94
95         if (resource_groups->domain_sid == NULL) {
96                 /*
97                  * There is no domain SID set. Set it to the domain of this SID.
98                  */
99                 resource_groups->domain_sid = resource_domain;
100         } else {
101                 /*
102                  * A domain SID has already been set. Check whether this SID's
103                  * domain matches.
104                  *
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.
109                  */
110                 bool match = dom_sid_equal(resource_groups->domain_sid, resource_domain);
111                 talloc_free(resource_domain);
112                 if (!match) {
113                         /*
114                          * It doesn't match, so we can't store this SID here. It
115                          * will have to go in Extra SIDs.
116                          */
117                         return store_extra_sid(sids, sidcount, allocated_sids, sid);
118                 }
119         }
120
121         /* Store the SID in Resource SIDs. */
122
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;
126         }
127
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++;
131
132         return NT_STATUS_OK;
133 }
134
135 /*
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.
139  */
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)
147 {
148         /* See if it's a resource SID. */
149         if (sid->attrs & SE_GROUP_RESOURCE) {
150                 /*
151                  * If this is the SID of a resource group, determine whether it
152                  * should be included or filtered out.
153                  */
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:
159                         /*
160                          * Try to include this SID in Resource Groups. If this
161                          * can't be arranged, we shall fall back to Extra
162                          * SIDs.
163                          */
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;
177                 }
178         }
179
180         /* Just store the SID in Extra SIDs. */
181         return store_extra_sid(sids,
182                                sidcount,
183                                allocated_sids,
184                                sid);
185 }
186
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)
190 {
191         NTSTATUS status;
192         const struct auth_user_info *info;
193
194         ZERO_STRUCTP(sam);
195
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;
201                 }
202         } else {
203                 return NT_STATUS_INVALID_PARAMETER;
204         }
205
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;
211                 }
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;
217         }
218
219         info = user_info_dc->info;
220
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;
227
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; \
233                 } \
234         } \
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
245
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;
250
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);
255
256                 if (sam->groups.rids == NULL)
257                         return NT_STATUS_NO_MEMORY;
258
259                 for (i=REMAINING_SIDS_INDEX; i<user_info_dc->num_sids; i++) {
260                         struct auth_SidAttr *group_sid = &user_info_dc->sids[i];
261
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;
266                         }
267                         sam->groups.rids[sam->groups.count].rid =
268                                 group_sid->sid.sub_auths[group_sid->sid.num_auths-1];
269
270                         sam->groups.rids[sam->groups.count].attributes = group_sid->attrs;
271                         sam->groups.count += 1;
272                 }
273
274                 if (sam->groups.count == 0) {
275                         TALLOC_FREE(sam->groups.rids);
276                 }
277         }
278
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;
286
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));
290         }
291
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));
296         }
297
298         return NT_STATUS_OK;
299 }
300
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)
308 {
309         NTSTATUS status;
310         struct netr_SamInfo6 *sam6 = NULL;
311         struct PAC_DOMAIN_GROUP_MEMBERSHIP *resource_groups = NULL;
312         size_t i;
313
314         const uint32_t allocated_sids = user_info_dc->num_sids;
315         uint32_t allocated_resource_groups = 0;
316
317         sam6 = talloc_zero(mem_ctx, struct netr_SamInfo6);
318         if (sam6 == NULL) {
319                 return NT_STATUS_NO_MEMORY;
320         }
321
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;
327                 }
328         } else if (group_inclusion == AUTH_INCLUDE_RESOURCE_GROUPS_COMPRESSED) {
329                 *_resource_groups = NULL;
330
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;
336                 }
337
338                 /*
339                  * Allocate enough space to store user_info_dc->num_sids
340                  * RIDs in the worst case.
341                  */
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;
350                 }
351         } else {
352                 /* No resource groups will be provided. */
353                 *_resource_groups = NULL;
354         }
355
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;
363         }
364
365         /*
366          * Allocate enough space to store user_info_dc->num_sids SIDs in the
367          * worst case.
368          */
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;
375         }
376
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;
384                 }
385
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;
397                 }
398         }
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);
404         }
405
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;
413                 }
414         }
415
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;
423                 }
424         }
425
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);
432                 }
433         }
434         return NT_STATUS_OK;
435 }
436
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)
443 {
444         NTSTATUS status;
445         struct netr_SamInfo6 *sam6 = NULL;
446         struct netr_SamInfo2 *sam2 = NULL;
447
448         sam2 = talloc_zero(mem_ctx, struct netr_SamInfo2);
449         if (sam2 == NULL) {
450                 return NT_STATUS_NO_MEMORY;
451         }
452
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;
459         }
460         sam2->base      = sam6->base;
461         /*
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.
464          */
465         sam2->base.user_flags &= ~NETLOGON_EXTRA_SIDS;
466         TALLOC_FREE(sam6->sids);
467
468         *_sam2 = sam2;
469         return NT_STATUS_OK;
470 }
471
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)
479 {
480         NTSTATUS status;
481         struct netr_SamInfo6 *sam6 = NULL;
482         struct netr_SamInfo3 *sam3 = NULL;
483
484         sam3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
485         if (sam3 == NULL) {
486                 return NT_STATUS_NO_MEMORY;
487         }
488
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;
495         }
496         sam3->base      = sam6->base;
497         sam3->sidcount  = sam6->sidcount;
498         sam3->sids      = sam6->sids;
499
500         *_sam3 = sam3;
501         return NT_STATUS_OK;
502 }
503
504 /**
505  * Make a user_info struct from the info3 or similar returned by a domain logon.
506  *
507  * The netr_SamInfo3 is also a key structure in the source3 auth subsystem
508  */
509
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)
515 {
516         struct auth_user_info *info;
517
518         info = talloc_zero(mem_ctx, struct auth_user_info);
519         if (info == NULL) {
520                 return NT_STATUS_NO_MEMORY;
521         }
522
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);
527         }
528         if (info->account_name == NULL) {
529                 talloc_free(info);
530                 return NT_STATUS_NO_MEMORY;
531         }
532
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;
538                 }
539         }
540
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;
546                 }
547         }
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;
553                 }
554         }
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;
560                 }
561         }
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;
567                 }
568         }
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;
574                 }
575         }
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;
581                 }
582         }
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;
592
593         info->user_flags = base->user_flags;
594         if (!authenticated) {
595                 /*
596                  * We only consider the user authenticated if NETLOGON_GUEST is
597                  * not set, and authenticated is set
598                  */
599                 info->user_flags |= NETLOGON_GUEST;
600         }
601
602         *_user_info = info;
603         return NT_STATUS_OK;
604 }
605
606 struct auth_user_info *auth_user_info_copy(TALLOC_CTX *mem_ctx,
607                                            const struct auth_user_info *src)
608 {
609         struct auth_user_info *dst = NULL;
610
611         dst = talloc_zero(mem_ctx, struct auth_user_info);
612         if (dst == NULL) {
613                 return NULL;
614         }
615
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; \
623                 } \
624         } \
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
637
638         return dst;
639 }
640
641 /**
642  * Make a user_info_dc struct from the info3 returned by a domain logon
643  */
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)
650 {
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;
659
660         switch (validation_level) {
661         case 2:
662                 if (!validation || !validation->sam2) {
663                         return NT_STATUS_INVALID_PARAMETER;
664                 }
665                 base = &validation->sam2->base;
666                 break;
667         case 3:
668                 if (!validation || !validation->sam3) {
669                         return NT_STATUS_INVALID_PARAMETER;
670                 }
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;
678                 }
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;
687         }
688
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;
692         }
693
694         /*
695            Here is where we should check the list of
696            trusted domains, and verify that the SID
697            matches.
698         */
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;
703         }
704
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;
710         }
711
712         user_info_dc->num_sids = PRIMARY_SIDS_COUNT;
713
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;
718         }
719
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;
724         }
725         user_info_dc->sids[PRIMARY_USER_SID_INDEX].attrs = SE_GROUP_DEFAULT_FLAGS;
726
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;
731         }
732         /*
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.
737          */
738         user_info_dc->sids[PRIMARY_GROUP_SID_INDEX].attrs = SE_GROUP_DEFAULT_FLAGS;
739
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;
745                 }
746                 user_info_dc->sids[user_info_dc->num_sids].attrs = base->groups.rids[i].attributes;
747                 user_info_dc->num_sids++;
748         }
749
750         /* Copy 'other' sids.  We need to do sid filtering here to
751            prevent possible elevation of privileges.  See:
752
753            http://www.microsoft.com/windows2000/techinfo/administration/security/sidfilter.asp
754          */
755
756         /*
757          * The IDL layer would be a better place to check this, but to
758          * guard the integer addition below, we double-check
759          */
760         if (sidcount > UINT16_MAX) {
761                 talloc_free(user_info_dc);
762                 return NT_STATUS_INVALID_PARAMETER;
763         }
764
765         if (sidcount > 0) {
766                 struct auth_SidAttr *dgrps = user_info_dc->sids;
767                 size_t dgrps_count;
768
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;
775                 }
776
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++;
782                         }
783                 }
784
785                 user_info_dc->sids = dgrps;
786
787                 /* Where are the 'global' sids?... */
788         }
789
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;
794         }
795
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;
802                 }
803         }
804
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;
811                 }
812         }
813
814         /* ensure we are never given NULL session keys */
815
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;
823                 }
824         }
825
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;
833                 }
834         }
835
836         *_user_info_dc = user_info_dc;
837         return NT_STATUS_OK;
838 }
839
840 /**
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.
845  */
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)
851 {
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;
858
859         validation.sam3 = discard_const_p(struct netr_SamInfo3, &pac_logon_info->info3);
860
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;
866         }
867
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:
875                         /*
876                          * The PAC is from a TGT, or we don't want to process
877                          * its resource groups.
878                          */
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;
884                 }
885         }
886
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;
893                 }
894
895                 /*
896                   Here is where we should check the list of
897                   trusted domains, and verify that the SID
898                   matches.
899                 */
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;
904                 }
905
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;
912                 }
913
914                 for (i = 0; i < rg->groups.count; i++) {
915                         bool ok;
916
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;
923                         }
924                         user_info_dc->sids[user_info_dc->num_sids].attrs = rg->groups.rids[i].attributes;
925                         user_info_dc->num_sids++;
926                 }
927         }
928
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;
937                         }
938                 }
939
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;
946                 }
947
948                 if (pac_upn_dns_info->flags & PAC_UPN_DNS_FLAG_CONSTRUCTED) {
949                         user_info_dc->info->user_principal_constructed = true;
950                 }
951         }
952
953         *_user_info_dc = user_info_dc;
954         return NT_STATUS_OK;
955 }