2 Unix SMB/CIFS implementation.
4 Convert a server info struct into the form for PAC and NETLOGON replies
6 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2011
7 Copyright (C) Stefan Metzmacher <metze@samba.org> 2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "librpc/gen_ndr/auth.h"
25 #include "libcli/security/security.h"
26 #include "auth/auth_sam_reply.h"
28 static NTSTATUS
auth_convert_user_info_dc_sambaseinfo(TALLOC_CTX
*mem_ctx
,
29 const struct auth_user_info_dc
*user_info_dc
,
30 struct netr_SamBaseInfo
*sam
)
33 const struct auth_user_info
*info
;
37 if (user_info_dc
->num_sids
> PRIMARY_USER_SID_INDEX
) {
38 status
= dom_sid_split_rid(sam
, &user_info_dc
->sids
[PRIMARY_USER_SID_INDEX
],
39 &sam
->domain_sid
, &sam
->rid
);
40 if (!NT_STATUS_IS_OK(status
)) {
44 return NT_STATUS_INVALID_PARAMETER
;
47 if (user_info_dc
->num_sids
> PRIMARY_GROUP_SID_INDEX
) {
48 status
= dom_sid_split_rid(NULL
, &user_info_dc
->sids
[PRIMARY_GROUP_SID_INDEX
],
49 NULL
, &sam
->primary_gid
);
50 if (!NT_STATUS_IS_OK(status
)) {
54 /* if we have to encode something like SYSTEM (with no
55 * second SID in the token) then this is the only
57 sam
->primary_gid
= sam
->rid
;
60 info
= user_info_dc
->info
;
62 sam
->logon_time
= info
->last_logon
;
63 sam
->logoff_time
= info
->last_logoff
;
64 sam
->kickoff_time
= info
->acct_expiry
;
65 sam
->last_password_change
= info
->last_password_change
;
66 sam
->allow_password_change
= info
->allow_password_change
;
67 sam
->force_password_change
= info
->force_password_change
;
69 #define _COPY_STRING_TALLOC(src_name, dst_name) do { \
70 if (info->src_name != NULL) {\
71 sam->dst_name.string = talloc_strdup(mem_ctx, info->src_name); \
72 if (sam->dst_name.string == NULL) { \
73 return NT_STATUS_NO_MEMORY; \
77 _COPY_STRING_TALLOC(account_name
, account_name
);
78 _COPY_STRING_TALLOC(full_name
, full_name
);
79 _COPY_STRING_TALLOC(logon_script
, logon_script
);
80 _COPY_STRING_TALLOC(profile_path
, profile_path
);
81 _COPY_STRING_TALLOC(home_directory
, home_directory
);
82 _COPY_STRING_TALLOC(home_drive
, home_drive
);
83 _COPY_STRING_TALLOC(logon_server
, logon_server
);
84 _COPY_STRING_TALLOC(domain_name
, logon_domain
);
85 #undef _COPY_STRING_TALLOC
87 sam
->logon_count
= info
->logon_count
;
88 sam
->bad_password_count
= info
->bad_password_count
;
89 sam
->groups
.count
= 0;
90 sam
->groups
.rids
= NULL
;
92 if (user_info_dc
->num_sids
> 2) {
94 sam
->groups
.rids
= talloc_array(mem_ctx
, struct samr_RidWithAttribute
,
95 user_info_dc
->num_sids
);
97 if (sam
->groups
.rids
== NULL
)
98 return NT_STATUS_NO_MEMORY
;
100 for (i
=2; i
<user_info_dc
->num_sids
; i
++) {
101 struct dom_sid
*group_sid
= &user_info_dc
->sids
[i
];
102 if (!dom_sid_in_domain(sam
->domain_sid
, group_sid
)) {
103 /* We handle this elsewhere */
106 sam
->groups
.rids
[sam
->groups
.count
].rid
=
107 group_sid
->sub_auths
[group_sid
->num_auths
-1];
109 sam
->groups
.rids
[sam
->groups
.count
].attributes
=
110 SE_GROUP_MANDATORY
| SE_GROUP_ENABLED_BY_DEFAULT
| SE_GROUP_ENABLED
;
111 sam
->groups
.count
+= 1;
115 sam
->user_flags
= 0; /* w2k3 uses NETLOGON_EXTRA_SIDS | NETLOGON_NTLMV2_ENABLED */
116 if (!user_info_dc
->info
->authenticated
) {
117 sam
->user_flags
|= NETLOGON_GUEST
;
119 sam
->acct_flags
= user_info_dc
->info
->acct_flags
;
120 sam
->sub_auth_status
= 0;
121 sam
->last_successful_logon
= 0;
122 sam
->last_failed_logon
= 0;
123 sam
->failed_logon_count
= 0;
126 ZERO_STRUCT(sam
->key
);
127 if (user_info_dc
->user_session_key
.length
== sizeof(sam
->key
.key
)) {
128 memcpy(sam
->key
.key
, user_info_dc
->user_session_key
.data
, sizeof(sam
->key
.key
));
131 ZERO_STRUCT(sam
->LMSessKey
);
132 if (user_info_dc
->lm_session_key
.length
== sizeof(sam
->LMSessKey
.key
)) {
133 memcpy(sam
->LMSessKey
.key
, user_info_dc
->lm_session_key
.data
,
134 sizeof(sam
->LMSessKey
.key
));
140 /* Note that the validity of the _sam6 structure is only as long as
141 * the user_info_dc it was generated from */
142 NTSTATUS
auth_convert_user_info_dc_saminfo6(TALLOC_CTX
*mem_ctx
,
143 const struct auth_user_info_dc
*user_info_dc
,
144 struct netr_SamInfo6
**_sam6
)
147 struct netr_SamInfo6
*sam6
= NULL
;
150 sam6
= talloc_zero(mem_ctx
, struct netr_SamInfo6
);
152 return NT_STATUS_NO_MEMORY
;
155 status
= auth_convert_user_info_dc_sambaseinfo(sam6
,
158 if (!NT_STATUS_IS_OK(status
)) {
163 sam6
->sids
= talloc_array(sam6
, struct netr_SidAttr
,
164 user_info_dc
->num_sids
);
165 if (sam6
->sids
== NULL
) {
167 return NT_STATUS_NO_MEMORY
;
170 /* We don't put the user and group SIDs in there */
171 for (i
=2; i
<user_info_dc
->num_sids
; i
++) {
172 if (dom_sid_in_domain(sam6
->base
.domain_sid
, &user_info_dc
->sids
[i
])) {
175 sam6
->sids
[sam6
->sidcount
].sid
= dom_sid_dup(sam6
->sids
, &user_info_dc
->sids
[i
]);
176 if (sam6
->sids
[sam6
->sidcount
].sid
== NULL
) {
178 return NT_STATUS_NO_MEMORY
;
180 sam6
->sids
[sam6
->sidcount
].attributes
=
181 SE_GROUP_MANDATORY
| SE_GROUP_ENABLED_BY_DEFAULT
| SE_GROUP_ENABLED
;
184 if (sam6
->sidcount
) {
185 sam6
->base
.user_flags
|= NETLOGON_EXTRA_SIDS
;
190 if (user_info_dc
->info
->dns_domain_name
!= NULL
) {
191 sam6
->dns_domainname
.string
= talloc_strdup(sam6
,
192 user_info_dc
->info
->dns_domain_name
);
193 if (sam6
->dns_domainname
.string
== NULL
) {
195 return NT_STATUS_NO_MEMORY
;
199 if (user_info_dc
->info
->user_principal_name
!= NULL
) {
200 sam6
->principal_name
.string
= talloc_strdup(sam6
,
201 user_info_dc
->info
->user_principal_name
);
202 if (sam6
->principal_name
.string
== NULL
) {
204 return NT_STATUS_NO_MEMORY
;
212 /* Note that the validity of the _sam2 structure is only as long as
213 * the user_info_dc it was generated from */
214 NTSTATUS
auth_convert_user_info_dc_saminfo2(TALLOC_CTX
*mem_ctx
,
215 const struct auth_user_info_dc
*user_info_dc
,
216 struct netr_SamInfo2
**_sam2
)
219 struct netr_SamInfo6
*sam6
= NULL
;
220 struct netr_SamInfo2
*sam2
= NULL
;
222 sam2
= talloc_zero(mem_ctx
, struct netr_SamInfo2
);
224 return NT_STATUS_NO_MEMORY
;
227 status
= auth_convert_user_info_dc_saminfo6(sam2
, user_info_dc
, &sam6
);
228 if (!NT_STATUS_IS_OK(status
)) {
232 sam2
->base
= sam6
->base
;
238 /* Note that the validity of the _sam3 structure is only as long as
239 * the user_info_dc it was generated from */
240 NTSTATUS
auth_convert_user_info_dc_saminfo3(TALLOC_CTX
*mem_ctx
,
241 const struct auth_user_info_dc
*user_info_dc
,
242 struct netr_SamInfo3
**_sam3
)
245 struct netr_SamInfo6
*sam6
= NULL
;
246 struct netr_SamInfo3
*sam3
= NULL
;
248 sam3
= talloc_zero(mem_ctx
, struct netr_SamInfo3
);
250 return NT_STATUS_NO_MEMORY
;
253 status
= auth_convert_user_info_dc_saminfo6(sam3
, user_info_dc
, &sam6
);
254 if (!NT_STATUS_IS_OK(status
)) {
258 sam3
->base
= sam6
->base
;
259 sam3
->sidcount
= sam6
->sidcount
;
260 sam3
->sids
= sam6
->sids
;
267 * Make a user_info struct from the info3 or similar returned by a domain logon.
269 * The netr_SamInfo3 is also a key structure in the source3 auth subsystem
272 NTSTATUS
make_user_info_SamBaseInfo(TALLOC_CTX
*mem_ctx
,
273 const char *account_name
,
274 const struct netr_SamBaseInfo
*base
,
276 struct auth_user_info
**_user_info
)
278 struct auth_user_info
*info
;
280 info
= talloc_zero(mem_ctx
, struct auth_user_info
);
281 NT_STATUS_HAVE_NO_MEMORY(info
);
283 if (base
->account_name
.string
) {
284 info
->account_name
= talloc_strdup(info
, base
->account_name
.string
);
286 info
->account_name
= talloc_strdup(info
, account_name
);
288 NT_STATUS_HAVE_NO_MEMORY(info
->account_name
);
290 if (base
->logon_domain
.string
) {
291 info
->domain_name
= talloc_strdup(info
, base
->logon_domain
.string
);
292 NT_STATUS_HAVE_NO_MEMORY(info
->domain_name
);
295 if (base
->full_name
.string
) {
296 info
->full_name
= talloc_strdup(info
, base
->full_name
.string
);
297 NT_STATUS_HAVE_NO_MEMORY(info
->full_name
);
299 if (base
->logon_script
.string
) {
300 info
->logon_script
= talloc_strdup(info
, base
->logon_script
.string
);
301 NT_STATUS_HAVE_NO_MEMORY(info
->logon_script
);
303 if (base
->profile_path
.string
) {
304 info
->profile_path
= talloc_strdup(info
, base
->profile_path
.string
);
305 NT_STATUS_HAVE_NO_MEMORY(info
->profile_path
);
307 if (base
->home_directory
.string
) {
308 info
->home_directory
= talloc_strdup(info
, base
->home_directory
.string
);
309 NT_STATUS_HAVE_NO_MEMORY(info
->home_directory
);
311 if (base
->home_drive
.string
) {
312 info
->home_drive
= talloc_strdup(info
, base
->home_drive
.string
);
313 NT_STATUS_HAVE_NO_MEMORY(info
->home_drive
);
315 if (base
->logon_server
.string
) {
316 info
->logon_server
= talloc_strdup(info
, base
->logon_server
.string
);
317 NT_STATUS_HAVE_NO_MEMORY(info
->logon_server
);
319 info
->last_logon
= base
->logon_time
;
320 info
->last_logoff
= base
->logoff_time
;
321 info
->acct_expiry
= base
->kickoff_time
;
322 info
->last_password_change
= base
->last_password_change
;
323 info
->allow_password_change
= base
->allow_password_change
;
324 info
->force_password_change
= base
->force_password_change
;
325 info
->logon_count
= base
->logon_count
;
326 info
->bad_password_count
= base
->bad_password_count
;
327 info
->acct_flags
= base
->acct_flags
;
329 /* Only set authenticated if both NETLOGON_GUEST is not set, and authenticated is set */
330 info
->authenticated
= (authenticated
&& (!(base
->user_flags
& NETLOGON_GUEST
)));
337 * Make a user_info_dc struct from the info3 returned by a domain logon
339 NTSTATUS
make_user_info_dc_netlogon_validation(TALLOC_CTX
*mem_ctx
,
340 const char *account_name
,
341 uint16_t validation_level
,
342 const union netr_Validation
*validation
,
344 struct auth_user_info_dc
**_user_info_dc
)
347 struct auth_user_info_dc
*user_info_dc
= NULL
;
348 const struct netr_SamBaseInfo
*base
= NULL
;
349 uint32_t sidcount
= 0;
350 const struct netr_SidAttr
*sids
= NULL
;
351 const char *dns_domainname
= NULL
;
352 const char *principal
= NULL
;
355 switch (validation_level
) {
357 if (!validation
|| !validation
->sam2
) {
358 return NT_STATUS_INVALID_PARAMETER
;
360 base
= &validation
->sam2
->base
;
363 if (!validation
|| !validation
->sam3
) {
364 return NT_STATUS_INVALID_PARAMETER
;
366 base
= &validation
->sam3
->base
;
367 sidcount
= validation
->sam3
->sidcount
;
368 sids
= validation
->sam3
->sids
;
371 if (!validation
|| !validation
->sam6
) {
372 return NT_STATUS_INVALID_PARAMETER
;
374 base
= &validation
->sam6
->base
;
375 sidcount
= validation
->sam6
->sidcount
;
376 sids
= validation
->sam6
->sids
;
377 dns_domainname
= validation
->sam6
->dns_domainname
.string
;
378 principal
= validation
->sam6
->principal_name
.string
;
381 return NT_STATUS_INVALID_LEVEL
;
384 user_info_dc
= talloc(mem_ctx
, struct auth_user_info_dc
);
385 NT_STATUS_HAVE_NO_MEMORY(user_info_dc
);
388 Here is where we should check the list of
389 trusted domains, and verify that the SID
392 if (!base
->domain_sid
) {
393 DEBUG(0, ("Cannot operate on a Netlogon Validation without a domain SID"));
394 return NT_STATUS_INVALID_PARAMETER
;
397 /* The IDL layer would be a better place to check this, but to
398 * guard the integer addition below, we double-check */
399 if (base
->groups
.count
> 65535) {
400 return NT_STATUS_INVALID_PARAMETER
;
403 user_info_dc
->num_sids
= 2;
405 user_info_dc
->sids
= talloc_array(user_info_dc
, struct dom_sid
, user_info_dc
->num_sids
+ base
->groups
.count
);
406 NT_STATUS_HAVE_NO_MEMORY(user_info_dc
->sids
);
408 user_info_dc
->sids
[PRIMARY_USER_SID_INDEX
] = *base
->domain_sid
;
409 if (!sid_append_rid(&user_info_dc
->sids
[PRIMARY_USER_SID_INDEX
], base
->rid
)) {
410 return NT_STATUS_INVALID_PARAMETER
;
413 user_info_dc
->sids
[PRIMARY_GROUP_SID_INDEX
] = *base
->domain_sid
;
414 if (!sid_append_rid(&user_info_dc
->sids
[PRIMARY_GROUP_SID_INDEX
], base
->primary_gid
)) {
415 return NT_STATUS_INVALID_PARAMETER
;
418 for (i
= 0; i
< base
->groups
.count
; i
++) {
419 user_info_dc
->sids
[user_info_dc
->num_sids
] = *base
->domain_sid
;
420 if (!sid_append_rid(&user_info_dc
->sids
[user_info_dc
->num_sids
], base
->groups
.rids
[i
].rid
)) {
421 return NT_STATUS_INVALID_PARAMETER
;
423 user_info_dc
->num_sids
++;
426 /* Copy 'other' sids. We need to do sid filtering here to
427 prevent possible elevation of privileges. See:
429 http://www.microsoft.com/windows2000/techinfo/administration/security/sidfilter.asp
433 * The IDL layer would be a better place to check this, but to
434 * guard the integer addition below, we double-check
436 if (sidcount
> UINT16_MAX
) {
437 return NT_STATUS_INVALID_PARAMETER
;
441 struct dom_sid
*dgrps
= user_info_dc
->sids
;
444 dgrps_count
= user_info_dc
->num_sids
+ sidcount
;
445 dgrps
= talloc_realloc(user_info_dc
, dgrps
, struct dom_sid
,
448 return NT_STATUS_NO_MEMORY
;
451 for (i
= 0; i
< sidcount
; i
++) {
453 dgrps
[user_info_dc
->num_sids
] = *sids
[i
].sid
;
454 user_info_dc
->num_sids
++;
458 user_info_dc
->sids
= dgrps
;
460 /* Where are the 'global' sids?... */
463 status
= make_user_info_SamBaseInfo(user_info_dc
, account_name
, base
, authenticated
, &user_info_dc
->info
);
464 if (!NT_STATUS_IS_OK(status
)) {
468 if (dns_domainname
!= NULL
) {
469 user_info_dc
->info
->dns_domain_name
= talloc_strdup(user_info_dc
->info
,
471 if (user_info_dc
->info
->dns_domain_name
== NULL
) {
472 return NT_STATUS_NO_MEMORY
;
476 if (principal
!= NULL
) {
477 user_info_dc
->info
->user_principal_name
= talloc_strdup(user_info_dc
->info
,
479 if (user_info_dc
->info
->user_principal_name
== NULL
) {
480 return NT_STATUS_NO_MEMORY
;
484 /* ensure we are never given NULL session keys */
486 if (all_zero(base
->key
.key
, sizeof(base
->key
.key
))) {
487 user_info_dc
->user_session_key
= data_blob(NULL
, 0);
489 user_info_dc
->user_session_key
= data_blob_talloc(user_info_dc
, base
->key
.key
, sizeof(base
->key
.key
));
490 NT_STATUS_HAVE_NO_MEMORY(user_info_dc
->user_session_key
.data
);
493 if (all_zero(base
->LMSessKey
.key
, sizeof(base
->LMSessKey
.key
))) {
494 user_info_dc
->lm_session_key
= data_blob(NULL
, 0);
496 user_info_dc
->lm_session_key
= data_blob_talloc(user_info_dc
, base
->LMSessKey
.key
, sizeof(base
->LMSessKey
.key
));
497 NT_STATUS_HAVE_NO_MEMORY(user_info_dc
->lm_session_key
.data
);
500 *_user_info_dc
= user_info_dc
;
505 * Make a user_info_dc struct from the PAC_LOGON_INFO supplied in the krb5 logon
507 NTSTATUS
make_user_info_dc_pac(TALLOC_CTX
*mem_ctx
,
508 const struct PAC_LOGON_INFO
*pac_logon_info
,
509 const struct PAC_UPN_DNS_INFO
*pac_upn_dns_info
,
510 struct auth_user_info_dc
**_user_info_dc
)
514 union netr_Validation validation
;
515 struct auth_user_info_dc
*user_info_dc
;
516 const struct PAC_DOMAIN_GROUP_MEMBERSHIP
*rg
= NULL
;
519 rg
= &pac_logon_info
->resource_groups
;
521 validation
.sam3
= discard_const_p(struct netr_SamInfo3
, &pac_logon_info
->info3
);
523 nt_status
= make_user_info_dc_netlogon_validation(mem_ctx
, "", 3, &validation
,
524 true, /* This user was authenticated */
526 if (!NT_STATUS_IS_OK(nt_status
)) {
530 if (pac_logon_info
->info3
.base
.user_flags
& NETLOGON_RESOURCE_GROUPS
) {
531 rg
= &pac_logon_info
->resource_groups
;
535 *_user_info_dc
= user_info_dc
;
539 if (rg
->groups
.count
> 0) {
540 /* The IDL layer would be a better place to check this, but to
541 * guard the integer addition below, we double-check */
542 if (rg
->groups
.count
> 65535) {
543 talloc_free(user_info_dc
);
544 return NT_STATUS_INVALID_PARAMETER
;
548 Here is where we should check the list of
549 trusted domains, and verify that the SID
552 if (rg
->domain_sid
== NULL
) {
553 talloc_free(user_info_dc
);
554 DEBUG(0, ("Cannot operate on a PAC without a resource domain SID"));
555 return NT_STATUS_INVALID_PARAMETER
;
558 sidcount
= user_info_dc
->num_sids
+ rg
->groups
.count
;
560 = talloc_realloc(user_info_dc
, user_info_dc
->sids
, struct dom_sid
, sidcount
);
561 if (user_info_dc
->sids
== NULL
) {
562 TALLOC_FREE(user_info_dc
);
563 return NT_STATUS_NO_MEMORY
;
566 for (i
= 0; i
< rg
->groups
.count
; i
++) {
569 user_info_dc
->sids
[user_info_dc
->num_sids
] = *rg
->domain_sid
;
570 ok
= sid_append_rid(&user_info_dc
->sids
[user_info_dc
->num_sids
],
571 rg
->groups
.rids
[i
].rid
);
573 return NT_STATUS_INVALID_PARAMETER
;
575 user_info_dc
->num_sids
++;
579 if (pac_upn_dns_info
!= NULL
) {
580 user_info_dc
->info
->user_principal_name
=
581 talloc_strdup(user_info_dc
->info
,
582 pac_upn_dns_info
->upn_name
);
583 if (user_info_dc
->info
->user_principal_name
== NULL
) {
584 return NT_STATUS_NO_MEMORY
;
587 user_info_dc
->info
->dns_domain_name
=
588 talloc_strdup(user_info_dc
->info
,
589 pac_upn_dns_info
->dns_domain_name
);
590 if (user_info_dc
->info
->dns_domain_name
== NULL
) {
591 return NT_STATUS_NO_MEMORY
;
594 if (pac_upn_dns_info
->flags
& PAC_UPN_DNS_FLAG_CONSTRUCTED
) {
595 user_info_dc
->info
->user_principal_constructed
= true;
599 *_user_info_dc
= user_info_dc
;