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
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
->last_logon
= info
->last_logon
;
63 sam
->last_logoff
= info
->last_logoff
;
64 sam
->acct_expiry
= 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 sam
->acct_flags
= user_info_dc
->info
->acct_flags
;
106 sam
->logon_server
.string
= user_info_dc
->info
->logon_server
;
107 sam
->domain
.string
= user_info_dc
->info
->domain_name
;
109 ZERO_STRUCT(sam
->unknown
);
111 ZERO_STRUCT(sam
->key
);
112 if (user_info_dc
->user_session_key
.length
== sizeof(sam
->key
.key
)) {
113 memcpy(sam
->key
.key
, user_info_dc
->user_session_key
.data
, sizeof(sam
->key
.key
));
116 ZERO_STRUCT(sam
->LMSessKey
);
117 if (user_info_dc
->lm_session_key
.length
== sizeof(sam
->LMSessKey
.key
)) {
118 memcpy(sam
->LMSessKey
.key
, user_info_dc
->lm_session_key
.data
,
119 sizeof(sam
->LMSessKey
.key
));
127 /* Note that the validity of the _sam3 structure is only as long as
128 * the user_info_dc it was generated from */
129 NTSTATUS
auth_convert_user_info_dc_saminfo3(TALLOC_CTX
*mem_ctx
,
130 struct auth_user_info_dc
*user_info_dc
,
131 struct netr_SamInfo3
**_sam3
)
133 struct netr_SamBaseInfo
*sam
;
134 struct netr_SamInfo3
*sam3
= talloc_zero(mem_ctx
, struct netr_SamInfo3
);
137 NT_STATUS_HAVE_NO_MEMORY(sam3
);
139 status
= auth_convert_user_info_dc_sambaseinfo(sam3
, user_info_dc
, &sam
);
140 if (!NT_STATUS_IS_OK(status
)) {
149 sam3
->sids
= talloc_array(sam
, struct netr_SidAttr
,
150 user_info_dc
->num_sids
);
151 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(sam3
->sids
, sam3
);
153 /* We don't put the user and group SIDs in there */
154 for (i
=2; i
<user_info_dc
->num_sids
; i
++) {
155 if (dom_sid_in_domain(sam
->domain_sid
, &user_info_dc
->sids
[i
])) {
158 sam3
->sids
[sam3
->sidcount
].sid
= dom_sid_dup(sam3
->sids
, &user_info_dc
->sids
[i
]);
159 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(sam3
->sids
[sam3
->sidcount
].sid
, sam3
);
160 sam3
->sids
[sam3
->sidcount
].attributes
=
161 SE_GROUP_MANDATORY
| SE_GROUP_ENABLED_BY_DEFAULT
| SE_GROUP_ENABLED
;
164 if (sam3
->sidcount
) {
165 sam3
->base
.user_flags
|= NETLOGON_EXTRA_SIDS
;
175 * Make a user_info_dc struct from the info3 returned by a domain logon
177 NTSTATUS
make_user_info_dc_netlogon_validation(TALLOC_CTX
*mem_ctx
,
178 const char *account_name
,
179 uint16_t validation_level
,
180 union netr_Validation
*validation
,
181 struct auth_user_info_dc
**_user_info_dc
)
183 struct auth_user_info_dc
*user_info_dc
;
184 struct auth_user_info
*info
;
185 struct netr_SamBaseInfo
*base
= NULL
;
188 switch (validation_level
) {
190 if (!validation
|| !validation
->sam2
) {
191 return NT_STATUS_INVALID_PARAMETER
;
193 base
= &validation
->sam2
->base
;
196 if (!validation
|| !validation
->sam3
) {
197 return NT_STATUS_INVALID_PARAMETER
;
199 base
= &validation
->sam3
->base
;
202 if (!validation
|| !validation
->sam6
) {
203 return NT_STATUS_INVALID_PARAMETER
;
205 base
= &validation
->sam6
->base
;
208 return NT_STATUS_INVALID_LEVEL
;
211 user_info_dc
= talloc(mem_ctx
, struct auth_user_info_dc
);
212 NT_STATUS_HAVE_NO_MEMORY(user_info_dc
);
215 Here is where we should check the list of
216 trusted domains, and verify that the SID
219 if (!base
->domain_sid
) {
220 DEBUG(0, ("Cannot operate on a Netlogon Validation without a domain SID"));
221 return NT_STATUS_INVALID_PARAMETER
;
224 /* The IDL layer would be a better place to check this, but to
225 * guard the integer addition below, we double-check */
226 if (base
->groups
.count
> 65535) {
227 return NT_STATUS_INVALID_PARAMETER
;
230 user_info_dc
->num_sids
= 2;
232 user_info_dc
->sids
= talloc_array(user_info_dc
, struct dom_sid
, user_info_dc
->num_sids
+ base
->groups
.count
);
233 NT_STATUS_HAVE_NO_MEMORY(user_info_dc
->sids
);
235 user_info_dc
->sids
[PRIMARY_USER_SID_INDEX
] = *base
->domain_sid
;
236 if (!sid_append_rid(&user_info_dc
->sids
[PRIMARY_USER_SID_INDEX
], base
->rid
)) {
237 return NT_STATUS_INVALID_PARAMETER
;
240 user_info_dc
->sids
[PRIMARY_GROUP_SID_INDEX
] = *base
->domain_sid
;
241 if (!sid_append_rid(&user_info_dc
->sids
[PRIMARY_GROUP_SID_INDEX
], base
->primary_gid
)) {
242 return NT_STATUS_INVALID_PARAMETER
;
245 for (i
= 0; i
< base
->groups
.count
; i
++) {
246 user_info_dc
->sids
[user_info_dc
->num_sids
] = *base
->domain_sid
;
247 if (!sid_append_rid(&user_info_dc
->sids
[user_info_dc
->num_sids
], base
->groups
.rids
[i
].rid
)) {
248 return NT_STATUS_INVALID_PARAMETER
;
250 user_info_dc
->num_sids
++;
253 /* Copy 'other' sids. We need to do sid filtering here to
254 prevent possible elevation of privileges. See:
256 http://www.microsoft.com/windows2000/techinfo/administration/security/sidfilter.asp
259 if (validation_level
== 3) {
260 struct dom_sid
*dgrps
= user_info_dc
->sids
;
263 /* The IDL layer would be a better place to check this, but to
264 * guard the integer addition below, we double-check */
265 if (validation
->sam3
->sidcount
> 65535) {
266 return NT_STATUS_INVALID_PARAMETER
;
269 sidcount
= user_info_dc
->num_sids
+ validation
->sam3
->sidcount
;
270 if (validation
->sam3
->sidcount
> 0) {
271 dgrps
= talloc_realloc(user_info_dc
, dgrps
, struct dom_sid
, sidcount
);
272 NT_STATUS_HAVE_NO_MEMORY(dgrps
);
274 for (i
= 0; i
< validation
->sam3
->sidcount
; i
++) {
275 if (validation
->sam3
->sids
[i
].sid
) {
276 dgrps
[user_info_dc
->num_sids
] = *validation
->sam3
->sids
[i
].sid
;
277 user_info_dc
->num_sids
++;
282 user_info_dc
->sids
= dgrps
;
284 /* Where are the 'global' sids?... */
287 user_info_dc
->info
= info
= talloc_zero(user_info_dc
, struct auth_user_info
);
288 NT_STATUS_HAVE_NO_MEMORY(user_info_dc
->info
);
290 if (base
->account_name
.string
) {
291 info
->account_name
= talloc_reference(info
, base
->account_name
.string
);
293 info
->account_name
= talloc_strdup(info
, account_name
);
294 NT_STATUS_HAVE_NO_MEMORY(info
->account_name
);
297 info
->domain_name
= talloc_reference(info
, base
->domain
.string
);
298 info
->full_name
= talloc_reference(info
, base
->full_name
.string
);
299 info
->logon_script
= talloc_reference(info
, base
->logon_script
.string
);
300 info
->profile_path
= talloc_reference(info
, base
->profile_path
.string
);
301 info
->home_directory
= talloc_reference(info
, base
->home_directory
.string
);
302 info
->home_drive
= talloc_reference(info
, base
->home_drive
.string
);
303 info
->logon_server
= talloc_reference(info
, base
->logon_server
.string
);
304 info
->last_logon
= base
->last_logon
;
305 info
->last_logoff
= base
->last_logoff
;
306 info
->acct_expiry
= base
->acct_expiry
;
307 info
->last_password_change
= base
->last_password_change
;
308 info
->allow_password_change
= base
->allow_password_change
;
309 info
->force_password_change
= base
->force_password_change
;
310 info
->logon_count
= base
->logon_count
;
311 info
->bad_password_count
= base
->bad_password_count
;
312 info
->acct_flags
= base
->acct_flags
;
314 info
->authenticated
= true;
316 /* ensure we are never given NULL session keys */
318 if (all_zero(base
->key
.key
, sizeof(base
->key
.key
))) {
319 user_info_dc
->user_session_key
= data_blob(NULL
, 0);
321 user_info_dc
->user_session_key
= data_blob_talloc(user_info_dc
, base
->key
.key
, sizeof(base
->key
.key
));
322 NT_STATUS_HAVE_NO_MEMORY(user_info_dc
->user_session_key
.data
);
325 if (all_zero(base
->LMSessKey
.key
, sizeof(base
->LMSessKey
.key
))) {
326 user_info_dc
->lm_session_key
= data_blob(NULL
, 0);
328 user_info_dc
->lm_session_key
= data_blob_talloc(user_info_dc
, base
->LMSessKey
.key
, sizeof(base
->LMSessKey
.key
));
329 NT_STATUS_HAVE_NO_MEMORY(user_info_dc
->lm_session_key
.data
);
332 *_user_info_dc
= user_info_dc
;
337 * Make a user_info_dc struct from the PAC_LOGON_INFO supplied in the krb5 logon
339 NTSTATUS
make_user_info_dc_pac(TALLOC_CTX
*mem_ctx
,
340 struct PAC_LOGON_INFO
*pac_logon_info
,
341 struct auth_user_info_dc
**_user_info_dc
)
345 union netr_Validation validation
;
346 struct auth_user_info_dc
*user_info_dc
;
348 validation
.sam3
= &pac_logon_info
->info3
;
350 nt_status
= make_user_info_dc_netlogon_validation(mem_ctx
, "", 3, &validation
, &user_info_dc
);
351 if (!NT_STATUS_IS_OK(nt_status
)) {
355 if (pac_logon_info
->res_groups
.count
> 0) {
357 /* The IDL layer would be a better place to check this, but to
358 * guard the integer addition below, we double-check */
359 if (pac_logon_info
->res_groups
.count
> 65535) {
360 talloc_free(user_info_dc
);
361 return NT_STATUS_INVALID_PARAMETER
;
365 Here is where we should check the list of
366 trusted domains, and verify that the SID
369 if (!pac_logon_info
->res_group_dom_sid
) {
370 DEBUG(0, ("Cannot operate on a PAC without a resource domain SID"));
371 return NT_STATUS_INVALID_PARAMETER
;
374 sidcount
= user_info_dc
->num_sids
+ pac_logon_info
->res_groups
.count
;
376 = talloc_realloc(user_info_dc
, user_info_dc
->sids
, struct dom_sid
, sidcount
);
377 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(user_info_dc
->sids
, user_info_dc
);
379 for (i
= 0; pac_logon_info
->res_group_dom_sid
&& i
< pac_logon_info
->res_groups
.count
; i
++) {
380 user_info_dc
->sids
[user_info_dc
->num_sids
] = *pac_logon_info
->res_group_dom_sid
;
381 if (!sid_append_rid(&user_info_dc
->sids
[user_info_dc
->num_sids
],
382 pac_logon_info
->res_groups
.rids
[i
].rid
)) {
383 return NT_STATUS_INVALID_PARAMETER
;
385 user_info_dc
->num_sids
++;
388 *_user_info_dc
= user_info_dc
;