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
->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 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
->domain
.string
= user_info_dc
->info
->domain_name
;
112 ZERO_STRUCT(sam
->unknown
);
114 ZERO_STRUCT(sam
->key
);
115 if (user_info_dc
->user_session_key
.length
== sizeof(sam
->key
.key
)) {
116 memcpy(sam
->key
.key
, user_info_dc
->user_session_key
.data
, sizeof(sam
->key
.key
));
119 ZERO_STRUCT(sam
->LMSessKey
);
120 if (user_info_dc
->lm_session_key
.length
== sizeof(sam
->LMSessKey
.key
)) {
121 memcpy(sam
->LMSessKey
.key
, user_info_dc
->lm_session_key
.data
,
122 sizeof(sam
->LMSessKey
.key
));
130 /* Note that the validity of the _sam3 structure is only as long as
131 * the user_info_dc it was generated from */
132 NTSTATUS
auth_convert_user_info_dc_saminfo3(TALLOC_CTX
*mem_ctx
,
133 struct auth_user_info_dc
*user_info_dc
,
134 struct netr_SamInfo3
**_sam3
)
136 struct netr_SamBaseInfo
*sam
;
137 struct netr_SamInfo3
*sam3
= talloc_zero(mem_ctx
, struct netr_SamInfo3
);
140 NT_STATUS_HAVE_NO_MEMORY(sam3
);
142 status
= auth_convert_user_info_dc_sambaseinfo(sam3
, user_info_dc
, &sam
);
143 if (!NT_STATUS_IS_OK(status
)) {
152 sam3
->sids
= talloc_array(sam
, struct netr_SidAttr
,
153 user_info_dc
->num_sids
);
154 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(sam3
->sids
, sam3
);
156 /* We don't put the user and group SIDs in there */
157 for (i
=2; i
<user_info_dc
->num_sids
; i
++) {
158 if (dom_sid_in_domain(sam
->domain_sid
, &user_info_dc
->sids
[i
])) {
161 sam3
->sids
[sam3
->sidcount
].sid
= dom_sid_dup(sam3
->sids
, &user_info_dc
->sids
[i
]);
162 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(sam3
->sids
[sam3
->sidcount
].sid
, sam3
);
163 sam3
->sids
[sam3
->sidcount
].attributes
=
164 SE_GROUP_MANDATORY
| SE_GROUP_ENABLED_BY_DEFAULT
| SE_GROUP_ENABLED
;
167 if (sam3
->sidcount
) {
168 sam3
->base
.user_flags
|= NETLOGON_EXTRA_SIDS
;
178 * Make a user_info struct from the info3 or similar returned by a domain logon.
180 * The netr_SamInfo3 is also a key structure in the source3 auth subsystem
183 NTSTATUS
make_user_info_SamBaseInfo(TALLOC_CTX
*mem_ctx
,
184 const char *account_name
,
185 struct netr_SamBaseInfo
*base
,
187 struct auth_user_info
**_user_info
)
189 struct auth_user_info
*info
;
191 info
= talloc_zero(mem_ctx
, struct auth_user_info
);
192 NT_STATUS_HAVE_NO_MEMORY(info
);
194 if (base
->account_name
.string
) {
195 info
->account_name
= talloc_strdup(info
, base
->account_name
.string
);
197 info
->account_name
= talloc_strdup(info
, account_name
);
199 NT_STATUS_HAVE_NO_MEMORY(info
->account_name
);
201 if (base
->domain
.string
) {
202 info
->domain_name
= talloc_strdup(info
, base
->domain
.string
);
203 NT_STATUS_HAVE_NO_MEMORY(info
->domain_name
);
206 if (base
->full_name
.string
) {
207 info
->full_name
= talloc_strdup(info
, base
->full_name
.string
);
208 NT_STATUS_HAVE_NO_MEMORY(info
->full_name
);
210 if (base
->logon_script
.string
) {
211 info
->logon_script
= talloc_strdup(info
, base
->logon_script
.string
);
212 NT_STATUS_HAVE_NO_MEMORY(info
->logon_script
);
214 if (base
->profile_path
.string
) {
215 info
->profile_path
= talloc_strdup(info
, base
->profile_path
.string
);
216 NT_STATUS_HAVE_NO_MEMORY(info
->profile_path
);
218 if (base
->home_directory
.string
) {
219 info
->home_directory
= talloc_strdup(info
, base
->home_directory
.string
);
220 NT_STATUS_HAVE_NO_MEMORY(info
->home_directory
);
222 if (base
->home_drive
.string
) {
223 info
->home_drive
= talloc_strdup(info
, base
->home_drive
.string
);
224 NT_STATUS_HAVE_NO_MEMORY(info
->home_drive
);
226 if (base
->logon_server
.string
) {
227 info
->logon_server
= talloc_strdup(info
, base
->logon_server
.string
);
228 NT_STATUS_HAVE_NO_MEMORY(info
->logon_server
);
230 info
->last_logon
= base
->last_logon
;
231 info
->last_logoff
= base
->last_logoff
;
232 info
->acct_expiry
= base
->acct_expiry
;
233 info
->last_password_change
= base
->last_password_change
;
234 info
->allow_password_change
= base
->allow_password_change
;
235 info
->force_password_change
= base
->force_password_change
;
236 info
->logon_count
= base
->logon_count
;
237 info
->bad_password_count
= base
->bad_password_count
;
238 info
->acct_flags
= base
->acct_flags
;
240 /* Only set authenticated if both NETLOGON_GUEST is not set, and authenticated is set */
241 info
->authenticated
= (authenticated
&& (!(base
->user_flags
& NETLOGON_GUEST
)));
248 * Make a user_info_dc struct from the info3 returned by a domain logon
250 NTSTATUS
make_user_info_dc_netlogon_validation(TALLOC_CTX
*mem_ctx
,
251 const char *account_name
,
252 uint16_t validation_level
,
253 union netr_Validation
*validation
,
255 struct auth_user_info_dc
**_user_info_dc
)
258 struct auth_user_info_dc
*user_info_dc
;
259 struct netr_SamBaseInfo
*base
= NULL
;
262 switch (validation_level
) {
264 if (!validation
|| !validation
->sam2
) {
265 return NT_STATUS_INVALID_PARAMETER
;
267 base
= &validation
->sam2
->base
;
270 if (!validation
|| !validation
->sam3
) {
271 return NT_STATUS_INVALID_PARAMETER
;
273 base
= &validation
->sam3
->base
;
276 if (!validation
|| !validation
->sam6
) {
277 return NT_STATUS_INVALID_PARAMETER
;
279 base
= &validation
->sam6
->base
;
282 return NT_STATUS_INVALID_LEVEL
;
285 user_info_dc
= talloc(mem_ctx
, struct auth_user_info_dc
);
286 NT_STATUS_HAVE_NO_MEMORY(user_info_dc
);
289 Here is where we should check the list of
290 trusted domains, and verify that the SID
293 if (!base
->domain_sid
) {
294 DEBUG(0, ("Cannot operate on a Netlogon Validation without a domain SID"));
295 return NT_STATUS_INVALID_PARAMETER
;
298 /* The IDL layer would be a better place to check this, but to
299 * guard the integer addition below, we double-check */
300 if (base
->groups
.count
> 65535) {
301 return NT_STATUS_INVALID_PARAMETER
;
304 user_info_dc
->num_sids
= 2;
306 user_info_dc
->sids
= talloc_array(user_info_dc
, struct dom_sid
, user_info_dc
->num_sids
+ base
->groups
.count
);
307 NT_STATUS_HAVE_NO_MEMORY(user_info_dc
->sids
);
309 user_info_dc
->sids
[PRIMARY_USER_SID_INDEX
] = *base
->domain_sid
;
310 if (!sid_append_rid(&user_info_dc
->sids
[PRIMARY_USER_SID_INDEX
], base
->rid
)) {
311 return NT_STATUS_INVALID_PARAMETER
;
314 user_info_dc
->sids
[PRIMARY_GROUP_SID_INDEX
] = *base
->domain_sid
;
315 if (!sid_append_rid(&user_info_dc
->sids
[PRIMARY_GROUP_SID_INDEX
], base
->primary_gid
)) {
316 return NT_STATUS_INVALID_PARAMETER
;
319 for (i
= 0; i
< base
->groups
.count
; i
++) {
320 user_info_dc
->sids
[user_info_dc
->num_sids
] = *base
->domain_sid
;
321 if (!sid_append_rid(&user_info_dc
->sids
[user_info_dc
->num_sids
], base
->groups
.rids
[i
].rid
)) {
322 return NT_STATUS_INVALID_PARAMETER
;
324 user_info_dc
->num_sids
++;
327 /* Copy 'other' sids. We need to do sid filtering here to
328 prevent possible elevation of privileges. See:
330 http://www.microsoft.com/windows2000/techinfo/administration/security/sidfilter.asp
333 if (validation_level
== 3) {
334 struct dom_sid
*dgrps
= user_info_dc
->sids
;
337 /* The IDL layer would be a better place to check this, but to
338 * guard the integer addition below, we double-check */
339 if (validation
->sam3
->sidcount
> 65535) {
340 return NT_STATUS_INVALID_PARAMETER
;
343 sidcount
= user_info_dc
->num_sids
+ validation
->sam3
->sidcount
;
344 if (validation
->sam3
->sidcount
> 0) {
345 dgrps
= talloc_realloc(user_info_dc
, dgrps
, struct dom_sid
, sidcount
);
346 NT_STATUS_HAVE_NO_MEMORY(dgrps
);
348 for (i
= 0; i
< validation
->sam3
->sidcount
; i
++) {
349 if (validation
->sam3
->sids
[i
].sid
) {
350 dgrps
[user_info_dc
->num_sids
] = *validation
->sam3
->sids
[i
].sid
;
351 user_info_dc
->num_sids
++;
356 user_info_dc
->sids
= dgrps
;
358 /* Where are the 'global' sids?... */
361 status
= make_user_info_SamBaseInfo(user_info_dc
, account_name
, base
, authenticated
, &user_info_dc
->info
);
362 if (!NT_STATUS_IS_OK(status
)) {
366 /* ensure we are never given NULL session keys */
368 if (all_zero(base
->key
.key
, sizeof(base
->key
.key
))) {
369 user_info_dc
->user_session_key
= data_blob(NULL
, 0);
371 user_info_dc
->user_session_key
= data_blob_talloc(user_info_dc
, base
->key
.key
, sizeof(base
->key
.key
));
372 NT_STATUS_HAVE_NO_MEMORY(user_info_dc
->user_session_key
.data
);
375 if (all_zero(base
->LMSessKey
.key
, sizeof(base
->LMSessKey
.key
))) {
376 user_info_dc
->lm_session_key
= data_blob(NULL
, 0);
378 user_info_dc
->lm_session_key
= data_blob_talloc(user_info_dc
, base
->LMSessKey
.key
, sizeof(base
->LMSessKey
.key
));
379 NT_STATUS_HAVE_NO_MEMORY(user_info_dc
->lm_session_key
.data
);
382 *_user_info_dc
= user_info_dc
;
387 * Make a user_info_dc struct from the PAC_LOGON_INFO supplied in the krb5 logon
389 NTSTATUS
make_user_info_dc_pac(TALLOC_CTX
*mem_ctx
,
390 struct PAC_LOGON_INFO
*pac_logon_info
,
391 struct auth_user_info_dc
**_user_info_dc
)
395 union netr_Validation validation
;
396 struct auth_user_info_dc
*user_info_dc
;
398 validation
.sam3
= &pac_logon_info
->info3
;
400 nt_status
= make_user_info_dc_netlogon_validation(mem_ctx
, "", 3, &validation
,
401 true, /* This user was authenticated */
403 if (!NT_STATUS_IS_OK(nt_status
)) {
407 if (pac_logon_info
->res_groups
.count
> 0) {
409 /* The IDL layer would be a better place to check this, but to
410 * guard the integer addition below, we double-check */
411 if (pac_logon_info
->res_groups
.count
> 65535) {
412 talloc_free(user_info_dc
);
413 return NT_STATUS_INVALID_PARAMETER
;
417 Here is where we should check the list of
418 trusted domains, and verify that the SID
421 if (!pac_logon_info
->res_group_dom_sid
) {
422 DEBUG(0, ("Cannot operate on a PAC without a resource domain SID"));
423 return NT_STATUS_INVALID_PARAMETER
;
426 sidcount
= user_info_dc
->num_sids
+ pac_logon_info
->res_groups
.count
;
428 = talloc_realloc(user_info_dc
, user_info_dc
->sids
, struct dom_sid
, sidcount
);
429 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(user_info_dc
->sids
, user_info_dc
);
431 for (i
= 0; pac_logon_info
->res_group_dom_sid
&& i
< pac_logon_info
->res_groups
.count
; i
++) {
432 user_info_dc
->sids
[user_info_dc
->num_sids
] = *pac_logon_info
->res_group_dom_sid
;
433 if (!sid_append_rid(&user_info_dc
->sids
[user_info_dc
->num_sids
],
434 pac_logon_info
->res_groups
.rids
[i
].rid
)) {
435 return NT_STATUS_INVALID_PARAMETER
;
437 user_info_dc
->num_sids
++;
440 *_user_info_dc
= user_info_dc
;