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
> PRIMARY_GROUP_SID_INDEX
) {
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
=PRIMARY_GROUP_SID_INDEX
; 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
)));
336 struct auth_user_info
*auth_user_info_copy(TALLOC_CTX
*mem_ctx
,
337 const struct auth_user_info
*src
)
339 struct auth_user_info
*dst
= NULL
;
341 dst
= talloc_zero(mem_ctx
, struct auth_user_info
);
347 #define _COPY_STRING(_mem, _str) do { \
348 if ((_str) != NULL) { \
349 (_str) = talloc_strdup((_mem), (_str)); \
350 if ((_str) == NULL) { \
356 _COPY_STRING(dst
, dst
->account_name
);
357 _COPY_STRING(dst
, dst
->user_principal_name
);
358 _COPY_STRING(dst
, dst
->domain_name
);
359 _COPY_STRING(dst
, dst
->dns_domain_name
);
360 _COPY_STRING(dst
, dst
->full_name
);
361 _COPY_STRING(dst
, dst
->logon_script
);
362 _COPY_STRING(dst
, dst
->profile_path
);
363 _COPY_STRING(dst
, dst
->home_directory
);
364 _COPY_STRING(dst
, dst
->home_drive
);
365 _COPY_STRING(dst
, dst
->logon_server
);
372 * Make a user_info_dc struct from the info3 returned by a domain logon
374 NTSTATUS
make_user_info_dc_netlogon_validation(TALLOC_CTX
*mem_ctx
,
375 const char *account_name
,
376 uint16_t validation_level
,
377 const union netr_Validation
*validation
,
379 struct auth_user_info_dc
**_user_info_dc
)
382 struct auth_user_info_dc
*user_info_dc
= NULL
;
383 const struct netr_SamBaseInfo
*base
= NULL
;
384 uint32_t sidcount
= 0;
385 const struct netr_SidAttr
*sids
= NULL
;
386 const char *dns_domainname
= NULL
;
387 const char *principal
= NULL
;
390 switch (validation_level
) {
392 if (!validation
|| !validation
->sam2
) {
393 return NT_STATUS_INVALID_PARAMETER
;
395 base
= &validation
->sam2
->base
;
398 if (!validation
|| !validation
->sam3
) {
399 return NT_STATUS_INVALID_PARAMETER
;
401 base
= &validation
->sam3
->base
;
402 sidcount
= validation
->sam3
->sidcount
;
403 sids
= validation
->sam3
->sids
;
406 if (!validation
|| !validation
->sam6
) {
407 return NT_STATUS_INVALID_PARAMETER
;
409 base
= &validation
->sam6
->base
;
410 sidcount
= validation
->sam6
->sidcount
;
411 sids
= validation
->sam6
->sids
;
412 dns_domainname
= validation
->sam6
->dns_domainname
.string
;
413 principal
= validation
->sam6
->principal_name
.string
;
416 return NT_STATUS_INVALID_LEVEL
;
419 user_info_dc
= talloc(mem_ctx
, struct auth_user_info_dc
);
420 NT_STATUS_HAVE_NO_MEMORY(user_info_dc
);
423 Here is where we should check the list of
424 trusted domains, and verify that the SID
427 if (!base
->domain_sid
) {
428 DEBUG(0, ("Cannot operate on a Netlogon Validation without a domain SID"));
429 return NT_STATUS_INVALID_PARAMETER
;
432 /* The IDL layer would be a better place to check this, but to
433 * guard the integer addition below, we double-check */
434 if (base
->groups
.count
> 65535) {
435 return NT_STATUS_INVALID_PARAMETER
;
438 user_info_dc
->num_sids
= 2;
440 user_info_dc
->sids
= talloc_array(user_info_dc
, struct dom_sid
, user_info_dc
->num_sids
+ base
->groups
.count
);
441 NT_STATUS_HAVE_NO_MEMORY(user_info_dc
->sids
);
443 user_info_dc
->sids
[PRIMARY_USER_SID_INDEX
] = *base
->domain_sid
;
444 if (!sid_append_rid(&user_info_dc
->sids
[PRIMARY_USER_SID_INDEX
], base
->rid
)) {
445 return NT_STATUS_INVALID_PARAMETER
;
448 user_info_dc
->sids
[PRIMARY_GROUP_SID_INDEX
] = *base
->domain_sid
;
449 if (!sid_append_rid(&user_info_dc
->sids
[PRIMARY_GROUP_SID_INDEX
], base
->primary_gid
)) {
450 return NT_STATUS_INVALID_PARAMETER
;
453 for (i
= 0; i
< base
->groups
.count
; i
++) {
454 /* Skip primary group, already added above */
455 if (base
->groups
.rids
[i
].rid
== base
->primary_gid
) {
458 user_info_dc
->sids
[user_info_dc
->num_sids
] = *base
->domain_sid
;
459 if (!sid_append_rid(&user_info_dc
->sids
[user_info_dc
->num_sids
], base
->groups
.rids
[i
].rid
)) {
460 return NT_STATUS_INVALID_PARAMETER
;
462 user_info_dc
->num_sids
++;
465 /* Copy 'other' sids. We need to do sid filtering here to
466 prevent possible elevation of privileges. See:
468 http://www.microsoft.com/windows2000/techinfo/administration/security/sidfilter.asp
472 * The IDL layer would be a better place to check this, but to
473 * guard the integer addition below, we double-check
475 if (sidcount
> UINT16_MAX
) {
476 return NT_STATUS_INVALID_PARAMETER
;
480 struct dom_sid
*dgrps
= user_info_dc
->sids
;
483 dgrps_count
= user_info_dc
->num_sids
+ sidcount
;
484 dgrps
= talloc_realloc(user_info_dc
, dgrps
, struct dom_sid
,
487 return NT_STATUS_NO_MEMORY
;
490 for (i
= 0; i
< sidcount
; i
++) {
492 dgrps
[user_info_dc
->num_sids
] = *sids
[i
].sid
;
493 user_info_dc
->num_sids
++;
497 user_info_dc
->sids
= dgrps
;
499 /* Where are the 'global' sids?... */
502 status
= make_user_info_SamBaseInfo(user_info_dc
, account_name
, base
, authenticated
, &user_info_dc
->info
);
503 if (!NT_STATUS_IS_OK(status
)) {
507 if (dns_domainname
!= NULL
) {
508 user_info_dc
->info
->dns_domain_name
= talloc_strdup(user_info_dc
->info
,
510 if (user_info_dc
->info
->dns_domain_name
== NULL
) {
511 return NT_STATUS_NO_MEMORY
;
515 if (principal
!= NULL
) {
516 user_info_dc
->info
->user_principal_name
= talloc_strdup(user_info_dc
->info
,
518 if (user_info_dc
->info
->user_principal_name
== NULL
) {
519 return NT_STATUS_NO_MEMORY
;
523 /* ensure we are never given NULL session keys */
525 if (all_zero(base
->key
.key
, sizeof(base
->key
.key
))) {
526 user_info_dc
->user_session_key
= data_blob(NULL
, 0);
528 user_info_dc
->user_session_key
= data_blob_talloc(user_info_dc
, base
->key
.key
, sizeof(base
->key
.key
));
529 NT_STATUS_HAVE_NO_MEMORY(user_info_dc
->user_session_key
.data
);
532 if (all_zero(base
->LMSessKey
.key
, sizeof(base
->LMSessKey
.key
))) {
533 user_info_dc
->lm_session_key
= data_blob(NULL
, 0);
535 user_info_dc
->lm_session_key
= data_blob_talloc(user_info_dc
, base
->LMSessKey
.key
, sizeof(base
->LMSessKey
.key
));
536 NT_STATUS_HAVE_NO_MEMORY(user_info_dc
->lm_session_key
.data
);
539 *_user_info_dc
= user_info_dc
;
544 * Make a user_info_dc struct from the PAC_LOGON_INFO supplied in the krb5 logon
546 NTSTATUS
make_user_info_dc_pac(TALLOC_CTX
*mem_ctx
,
547 const struct PAC_LOGON_INFO
*pac_logon_info
,
548 const struct PAC_UPN_DNS_INFO
*pac_upn_dns_info
,
549 struct auth_user_info_dc
**_user_info_dc
)
553 union netr_Validation validation
;
554 struct auth_user_info_dc
*user_info_dc
;
555 const struct PAC_DOMAIN_GROUP_MEMBERSHIP
*rg
= NULL
;
558 rg
= &pac_logon_info
->resource_groups
;
560 validation
.sam3
= discard_const_p(struct netr_SamInfo3
, &pac_logon_info
->info3
);
562 nt_status
= make_user_info_dc_netlogon_validation(mem_ctx
, "", 3, &validation
,
563 true, /* This user was authenticated */
565 if (!NT_STATUS_IS_OK(nt_status
)) {
569 if (pac_logon_info
->info3
.base
.user_flags
& NETLOGON_RESOURCE_GROUPS
) {
570 rg
= &pac_logon_info
->resource_groups
;
574 *_user_info_dc
= user_info_dc
;
578 if (rg
->groups
.count
> 0) {
579 /* The IDL layer would be a better place to check this, but to
580 * guard the integer addition below, we double-check */
581 if (rg
->groups
.count
> 65535) {
582 talloc_free(user_info_dc
);
583 return NT_STATUS_INVALID_PARAMETER
;
587 Here is where we should check the list of
588 trusted domains, and verify that the SID
591 if (rg
->domain_sid
== NULL
) {
592 talloc_free(user_info_dc
);
593 DEBUG(0, ("Cannot operate on a PAC without a resource domain SID"));
594 return NT_STATUS_INVALID_PARAMETER
;
597 sidcount
= user_info_dc
->num_sids
+ rg
->groups
.count
;
599 = talloc_realloc(user_info_dc
, user_info_dc
->sids
, struct dom_sid
, sidcount
);
600 if (user_info_dc
->sids
== NULL
) {
601 TALLOC_FREE(user_info_dc
);
602 return NT_STATUS_NO_MEMORY
;
605 for (i
= 0; i
< rg
->groups
.count
; i
++) {
608 user_info_dc
->sids
[user_info_dc
->num_sids
] = *rg
->domain_sid
;
609 ok
= sid_append_rid(&user_info_dc
->sids
[user_info_dc
->num_sids
],
610 rg
->groups
.rids
[i
].rid
);
612 return NT_STATUS_INVALID_PARAMETER
;
614 user_info_dc
->num_sids
++;
618 if (pac_upn_dns_info
!= NULL
) {
619 user_info_dc
->info
->user_principal_name
=
620 talloc_strdup(user_info_dc
->info
,
621 pac_upn_dns_info
->upn_name
);
622 if (user_info_dc
->info
->user_principal_name
== NULL
) {
623 return NT_STATUS_NO_MEMORY
;
626 user_info_dc
->info
->dns_domain_name
=
627 talloc_strdup(user_info_dc
->info
,
628 pac_upn_dns_info
->dns_domain_name
);
629 if (user_info_dc
->info
->dns_domain_name
== NULL
) {
630 return NT_STATUS_NO_MEMORY
;
633 if (pac_upn_dns_info
->flags
& PAC_UPN_DNS_FLAG_CONSTRUCTED
) {
634 user_info_dc
->info
->user_principal_constructed
= true;
638 *_user_info_dc
= user_info_dc
;