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 NTSTATUS
auth_convert_user_info_dc_sambaseinfo(TALLOC_CTX
*mem_ctx
,
29 struct auth_user_info_dc
*user_info_dc
,
30 struct netr_SamBaseInfo
**_sam
)
33 struct auth_user_info
*info
;
34 struct netr_SamBaseInfo
*sam
= talloc_zero(mem_ctx
, struct netr_SamBaseInfo
);
35 NT_STATUS_HAVE_NO_MEMORY(sam
);
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 sam
->account_name
.string
= info
->account_name
;
70 sam
->full_name
.string
= info
->full_name
;
71 sam
->logon_script
.string
= info
->logon_script
;
72 sam
->profile_path
.string
= info
->profile_path
;
73 sam
->home_directory
.string
= info
->home_directory
;
74 sam
->home_drive
.string
= info
->home_drive
;
76 sam
->logon_count
= info
->logon_count
;
77 sam
->bad_password_count
= info
->bad_password_count
;
78 sam
->groups
.count
= 0;
79 sam
->groups
.rids
= NULL
;
81 if (user_info_dc
->num_sids
> 2) {
83 sam
->groups
.rids
= talloc_array(sam
, struct samr_RidWithAttribute
,
84 user_info_dc
->num_sids
);
86 if (sam
->groups
.rids
== NULL
)
87 return NT_STATUS_NO_MEMORY
;
89 for (i
=2; i
<user_info_dc
->num_sids
; i
++) {
90 struct dom_sid
*group_sid
= &user_info_dc
->sids
[i
];
91 if (!dom_sid_in_domain(sam
->domain_sid
, group_sid
)) {
92 /* We handle this elsewhere */
95 sam
->groups
.rids
[sam
->groups
.count
].rid
=
96 group_sid
->sub_auths
[group_sid
->num_auths
-1];
98 sam
->groups
.rids
[sam
->groups
.count
].attributes
=
99 SE_GROUP_MANDATORY
| SE_GROUP_ENABLED_BY_DEFAULT
| SE_GROUP_ENABLED
;
100 sam
->groups
.count
+= 1;
104 sam
->user_flags
= 0; /* w2k3 uses NETLOGON_EXTRA_SIDS | NETLOGON_NTLMV2_ENABLED */
105 if (!user_info_dc
->info
->authenticated
) {
106 sam
->user_flags
|= NETLOGON_GUEST
;
108 sam
->acct_flags
= user_info_dc
->info
->acct_flags
;
109 sam
->logon_server
.string
= user_info_dc
->info
->logon_server
;
110 sam
->logon_domain
.string
= user_info_dc
->info
->domain_name
;
111 sam
->sub_auth_status
= 0;
112 sam
->last_successful_logon
= 0;
113 sam
->last_failed_logon
= 0;
114 sam
->failed_logon_count
= 0;
117 ZERO_STRUCT(sam
->key
);
118 if (user_info_dc
->user_session_key
.length
== sizeof(sam
->key
.key
)) {
119 memcpy(sam
->key
.key
, user_info_dc
->user_session_key
.data
, sizeof(sam
->key
.key
));
122 ZERO_STRUCT(sam
->LMSessKey
);
123 if (user_info_dc
->lm_session_key
.length
== sizeof(sam
->LMSessKey
.key
)) {
124 memcpy(sam
->LMSessKey
.key
, user_info_dc
->lm_session_key
.data
,
125 sizeof(sam
->LMSessKey
.key
));
133 /* Note that the validity of the _sam3 structure is only as long as
134 * the user_info_dc it was generated from */
135 NTSTATUS
auth_convert_user_info_dc_saminfo3(TALLOC_CTX
*mem_ctx
,
136 struct auth_user_info_dc
*user_info_dc
,
137 struct netr_SamInfo3
**_sam3
)
139 struct netr_SamBaseInfo
*sam
;
140 struct netr_SamInfo3
*sam3
= talloc_zero(mem_ctx
, struct netr_SamInfo3
);
143 NT_STATUS_HAVE_NO_MEMORY(sam3
);
145 status
= auth_convert_user_info_dc_sambaseinfo(sam3
, user_info_dc
, &sam
);
146 if (!NT_STATUS_IS_OK(status
)) {
155 sam3
->sids
= talloc_array(sam
, struct netr_SidAttr
,
156 user_info_dc
->num_sids
);
157 if (sam3
->sids
== NULL
) {
159 return NT_STATUS_NO_MEMORY
;
162 /* We don't put the user and group SIDs in there */
163 for (i
=2; i
<user_info_dc
->num_sids
; i
++) {
164 if (dom_sid_in_domain(sam
->domain_sid
, &user_info_dc
->sids
[i
])) {
167 sam3
->sids
[sam3
->sidcount
].sid
= dom_sid_dup(sam3
->sids
, &user_info_dc
->sids
[i
]);
168 if (sam3
->sids
[sam3
->sidcount
].sid
== NULL
) {
170 return NT_STATUS_NO_MEMORY
;
172 sam3
->sids
[sam3
->sidcount
].attributes
=
173 SE_GROUP_MANDATORY
| SE_GROUP_ENABLED_BY_DEFAULT
| SE_GROUP_ENABLED
;
176 if (sam3
->sidcount
) {
177 sam3
->base
.user_flags
|= NETLOGON_EXTRA_SIDS
;
187 * Make a user_info struct from the info3 or similar returned by a domain logon.
189 * The netr_SamInfo3 is also a key structure in the source3 auth subsystem
192 NTSTATUS
make_user_info_SamBaseInfo(TALLOC_CTX
*mem_ctx
,
193 const char *account_name
,
194 struct netr_SamBaseInfo
*base
,
196 struct auth_user_info
**_user_info
)
198 struct auth_user_info
*info
;
200 info
= talloc_zero(mem_ctx
, struct auth_user_info
);
201 NT_STATUS_HAVE_NO_MEMORY(info
);
203 if (base
->account_name
.string
) {
204 info
->account_name
= talloc_strdup(info
, base
->account_name
.string
);
206 info
->account_name
= talloc_strdup(info
, account_name
);
208 NT_STATUS_HAVE_NO_MEMORY(info
->account_name
);
210 if (base
->logon_domain
.string
) {
211 info
->domain_name
= talloc_strdup(info
, base
->logon_domain
.string
);
212 NT_STATUS_HAVE_NO_MEMORY(info
->domain_name
);
215 if (base
->full_name
.string
) {
216 info
->full_name
= talloc_strdup(info
, base
->full_name
.string
);
217 NT_STATUS_HAVE_NO_MEMORY(info
->full_name
);
219 if (base
->logon_script
.string
) {
220 info
->logon_script
= talloc_strdup(info
, base
->logon_script
.string
);
221 NT_STATUS_HAVE_NO_MEMORY(info
->logon_script
);
223 if (base
->profile_path
.string
) {
224 info
->profile_path
= talloc_strdup(info
, base
->profile_path
.string
);
225 NT_STATUS_HAVE_NO_MEMORY(info
->profile_path
);
227 if (base
->home_directory
.string
) {
228 info
->home_directory
= talloc_strdup(info
, base
->home_directory
.string
);
229 NT_STATUS_HAVE_NO_MEMORY(info
->home_directory
);
231 if (base
->home_drive
.string
) {
232 info
->home_drive
= talloc_strdup(info
, base
->home_drive
.string
);
233 NT_STATUS_HAVE_NO_MEMORY(info
->home_drive
);
235 if (base
->logon_server
.string
) {
236 info
->logon_server
= talloc_strdup(info
, base
->logon_server
.string
);
237 NT_STATUS_HAVE_NO_MEMORY(info
->logon_server
);
239 info
->last_logon
= base
->logon_time
;
240 info
->last_logoff
= base
->logoff_time
;
241 info
->acct_expiry
= base
->kickoff_time
;
242 info
->last_password_change
= base
->last_password_change
;
243 info
->allow_password_change
= base
->allow_password_change
;
244 info
->force_password_change
= base
->force_password_change
;
245 info
->logon_count
= base
->logon_count
;
246 info
->bad_password_count
= base
->bad_password_count
;
247 info
->acct_flags
= base
->acct_flags
;
249 /* Only set authenticated if both NETLOGON_GUEST is not set, and authenticated is set */
250 info
->authenticated
= (authenticated
&& (!(base
->user_flags
& NETLOGON_GUEST
)));
257 * Make a user_info_dc struct from the info3 returned by a domain logon
259 NTSTATUS
make_user_info_dc_netlogon_validation(TALLOC_CTX
*mem_ctx
,
260 const char *account_name
,
261 uint16_t validation_level
,
262 union netr_Validation
*validation
,
264 struct auth_user_info_dc
**_user_info_dc
)
267 struct auth_user_info_dc
*user_info_dc
;
268 struct netr_SamBaseInfo
*base
= NULL
;
271 switch (validation_level
) {
273 if (!validation
|| !validation
->sam2
) {
274 return NT_STATUS_INVALID_PARAMETER
;
276 base
= &validation
->sam2
->base
;
279 if (!validation
|| !validation
->sam3
) {
280 return NT_STATUS_INVALID_PARAMETER
;
282 base
= &validation
->sam3
->base
;
285 if (!validation
|| !validation
->sam6
) {
286 return NT_STATUS_INVALID_PARAMETER
;
288 base
= &validation
->sam6
->base
;
291 return NT_STATUS_INVALID_LEVEL
;
294 user_info_dc
= talloc(mem_ctx
, struct auth_user_info_dc
);
295 NT_STATUS_HAVE_NO_MEMORY(user_info_dc
);
298 Here is where we should check the list of
299 trusted domains, and verify that the SID
302 if (!base
->domain_sid
) {
303 DEBUG(0, ("Cannot operate on a Netlogon Validation without a domain SID"));
304 return NT_STATUS_INVALID_PARAMETER
;
307 /* The IDL layer would be a better place to check this, but to
308 * guard the integer addition below, we double-check */
309 if (base
->groups
.count
> 65535) {
310 return NT_STATUS_INVALID_PARAMETER
;
313 user_info_dc
->num_sids
= 2;
315 user_info_dc
->sids
= talloc_array(user_info_dc
, struct dom_sid
, user_info_dc
->num_sids
+ base
->groups
.count
);
316 NT_STATUS_HAVE_NO_MEMORY(user_info_dc
->sids
);
318 user_info_dc
->sids
[PRIMARY_USER_SID_INDEX
] = *base
->domain_sid
;
319 if (!sid_append_rid(&user_info_dc
->sids
[PRIMARY_USER_SID_INDEX
], base
->rid
)) {
320 return NT_STATUS_INVALID_PARAMETER
;
323 user_info_dc
->sids
[PRIMARY_GROUP_SID_INDEX
] = *base
->domain_sid
;
324 if (!sid_append_rid(&user_info_dc
->sids
[PRIMARY_GROUP_SID_INDEX
], base
->primary_gid
)) {
325 return NT_STATUS_INVALID_PARAMETER
;
328 for (i
= 0; i
< base
->groups
.count
; i
++) {
329 user_info_dc
->sids
[user_info_dc
->num_sids
] = *base
->domain_sid
;
330 if (!sid_append_rid(&user_info_dc
->sids
[user_info_dc
->num_sids
], base
->groups
.rids
[i
].rid
)) {
331 return NT_STATUS_INVALID_PARAMETER
;
333 user_info_dc
->num_sids
++;
336 /* Copy 'other' sids. We need to do sid filtering here to
337 prevent possible elevation of privileges. See:
339 http://www.microsoft.com/windows2000/techinfo/administration/security/sidfilter.asp
342 if (validation_level
== 3) {
343 struct dom_sid
*dgrps
= user_info_dc
->sids
;
346 /* The IDL layer would be a better place to check this, but to
347 * guard the integer addition below, we double-check */
348 if (validation
->sam3
->sidcount
> 65535) {
349 return NT_STATUS_INVALID_PARAMETER
;
352 sidcount
= user_info_dc
->num_sids
+ validation
->sam3
->sidcount
;
353 if (validation
->sam3
->sidcount
> 0) {
354 dgrps
= talloc_realloc(user_info_dc
, dgrps
, struct dom_sid
, sidcount
);
355 NT_STATUS_HAVE_NO_MEMORY(dgrps
);
357 for (i
= 0; i
< validation
->sam3
->sidcount
; i
++) {
358 if (validation
->sam3
->sids
[i
].sid
) {
359 dgrps
[user_info_dc
->num_sids
] = *validation
->sam3
->sids
[i
].sid
;
360 user_info_dc
->num_sids
++;
365 user_info_dc
->sids
= dgrps
;
367 /* Where are the 'global' sids?... */
370 status
= make_user_info_SamBaseInfo(user_info_dc
, account_name
, base
, authenticated
, &user_info_dc
->info
);
371 if (!NT_STATUS_IS_OK(status
)) {
375 /* ensure we are never given NULL session keys */
377 if (all_zero(base
->key
.key
, sizeof(base
->key
.key
))) {
378 user_info_dc
->user_session_key
= data_blob(NULL
, 0);
380 user_info_dc
->user_session_key
= data_blob_talloc(user_info_dc
, base
->key
.key
, sizeof(base
->key
.key
));
381 NT_STATUS_HAVE_NO_MEMORY(user_info_dc
->user_session_key
.data
);
384 if (all_zero(base
->LMSessKey
.key
, sizeof(base
->LMSessKey
.key
))) {
385 user_info_dc
->lm_session_key
= data_blob(NULL
, 0);
387 user_info_dc
->lm_session_key
= data_blob_talloc(user_info_dc
, base
->LMSessKey
.key
, sizeof(base
->LMSessKey
.key
));
388 NT_STATUS_HAVE_NO_MEMORY(user_info_dc
->lm_session_key
.data
);
391 *_user_info_dc
= user_info_dc
;
396 * Make a user_info_dc struct from the PAC_LOGON_INFO supplied in the krb5 logon
398 NTSTATUS
make_user_info_dc_pac(TALLOC_CTX
*mem_ctx
,
399 struct PAC_LOGON_INFO
*pac_logon_info
,
400 struct auth_user_info_dc
**_user_info_dc
)
404 union netr_Validation validation
;
405 struct auth_user_info_dc
*user_info_dc
;
407 validation
.sam3
= &pac_logon_info
->info3
;
409 nt_status
= make_user_info_dc_netlogon_validation(mem_ctx
, "", 3, &validation
,
410 true, /* This user was authenticated */
412 if (!NT_STATUS_IS_OK(nt_status
)) {
416 if (pac_logon_info
->res_groups
.count
> 0) {
418 /* The IDL layer would be a better place to check this, but to
419 * guard the integer addition below, we double-check */
420 if (pac_logon_info
->res_groups
.count
> 65535) {
421 talloc_free(user_info_dc
);
422 return NT_STATUS_INVALID_PARAMETER
;
426 Here is where we should check the list of
427 trusted domains, and verify that the SID
430 if (!pac_logon_info
->res_group_dom_sid
) {
431 DEBUG(0, ("Cannot operate on a PAC without a resource domain SID"));
432 return NT_STATUS_INVALID_PARAMETER
;
435 sidcount
= user_info_dc
->num_sids
+ pac_logon_info
->res_groups
.count
;
437 = talloc_realloc(user_info_dc
, user_info_dc
->sids
, struct dom_sid
, sidcount
);
438 if (user_info_dc
->sids
== NULL
) {
439 TALLOC_FREE(user_info_dc
);
440 return NT_STATUS_NO_MEMORY
;
443 for (i
= 0; pac_logon_info
->res_group_dom_sid
&& i
< pac_logon_info
->res_groups
.count
; i
++) {
444 user_info_dc
->sids
[user_info_dc
->num_sids
] = *pac_logon_info
->res_group_dom_sid
;
445 if (!sid_append_rid(&user_info_dc
->sids
[user_info_dc
->num_sids
],
446 pac_logon_info
->res_groups
.rids
[i
].rid
)) {
447 return NT_STATUS_INVALID_PARAMETER
;
449 user_info_dc
->num_sids
++;
452 *_user_info_dc
= user_info_dc
;