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 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(sam3
->sids
, sam3
);
159 /* We don't put the user and group SIDs in there */
160 for (i
=2; i
<user_info_dc
->num_sids
; i
++) {
161 if (dom_sid_in_domain(sam
->domain_sid
, &user_info_dc
->sids
[i
])) {
164 sam3
->sids
[sam3
->sidcount
].sid
= dom_sid_dup(sam3
->sids
, &user_info_dc
->sids
[i
]);
165 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(sam3
->sids
[sam3
->sidcount
].sid
, sam3
);
166 sam3
->sids
[sam3
->sidcount
].attributes
=
167 SE_GROUP_MANDATORY
| SE_GROUP_ENABLED_BY_DEFAULT
| SE_GROUP_ENABLED
;
170 if (sam3
->sidcount
) {
171 sam3
->base
.user_flags
|= NETLOGON_EXTRA_SIDS
;
181 * Make a user_info struct from the info3 or similar returned by a domain logon.
183 * The netr_SamInfo3 is also a key structure in the source3 auth subsystem
186 NTSTATUS
make_user_info_SamBaseInfo(TALLOC_CTX
*mem_ctx
,
187 const char *account_name
,
188 struct netr_SamBaseInfo
*base
,
190 struct auth_user_info
**_user_info
)
192 struct auth_user_info
*info
;
194 info
= talloc_zero(mem_ctx
, struct auth_user_info
);
195 NT_STATUS_HAVE_NO_MEMORY(info
);
197 if (base
->account_name
.string
) {
198 info
->account_name
= talloc_strdup(info
, base
->account_name
.string
);
200 info
->account_name
= talloc_strdup(info
, account_name
);
202 NT_STATUS_HAVE_NO_MEMORY(info
->account_name
);
204 if (base
->logon_domain
.string
) {
205 info
->domain_name
= talloc_strdup(info
, base
->logon_domain
.string
);
206 NT_STATUS_HAVE_NO_MEMORY(info
->domain_name
);
209 if (base
->full_name
.string
) {
210 info
->full_name
= talloc_strdup(info
, base
->full_name
.string
);
211 NT_STATUS_HAVE_NO_MEMORY(info
->full_name
);
213 if (base
->logon_script
.string
) {
214 info
->logon_script
= talloc_strdup(info
, base
->logon_script
.string
);
215 NT_STATUS_HAVE_NO_MEMORY(info
->logon_script
);
217 if (base
->profile_path
.string
) {
218 info
->profile_path
= talloc_strdup(info
, base
->profile_path
.string
);
219 NT_STATUS_HAVE_NO_MEMORY(info
->profile_path
);
221 if (base
->home_directory
.string
) {
222 info
->home_directory
= talloc_strdup(info
, base
->home_directory
.string
);
223 NT_STATUS_HAVE_NO_MEMORY(info
->home_directory
);
225 if (base
->home_drive
.string
) {
226 info
->home_drive
= talloc_strdup(info
, base
->home_drive
.string
);
227 NT_STATUS_HAVE_NO_MEMORY(info
->home_drive
);
229 if (base
->logon_server
.string
) {
230 info
->logon_server
= talloc_strdup(info
, base
->logon_server
.string
);
231 NT_STATUS_HAVE_NO_MEMORY(info
->logon_server
);
233 info
->last_logon
= base
->logon_time
;
234 info
->last_logoff
= base
->logoff_time
;
235 info
->acct_expiry
= base
->kickoff_time
;
236 info
->last_password_change
= base
->last_password_change
;
237 info
->allow_password_change
= base
->allow_password_change
;
238 info
->force_password_change
= base
->force_password_change
;
239 info
->logon_count
= base
->logon_count
;
240 info
->bad_password_count
= base
->bad_password_count
;
241 info
->acct_flags
= base
->acct_flags
;
243 /* Only set authenticated if both NETLOGON_GUEST is not set, and authenticated is set */
244 info
->authenticated
= (authenticated
&& (!(base
->user_flags
& NETLOGON_GUEST
)));
251 * Make a user_info_dc struct from the info3 returned by a domain logon
253 NTSTATUS
make_user_info_dc_netlogon_validation(TALLOC_CTX
*mem_ctx
,
254 const char *account_name
,
255 uint16_t validation_level
,
256 union netr_Validation
*validation
,
258 struct auth_user_info_dc
**_user_info_dc
)
261 struct auth_user_info_dc
*user_info_dc
;
262 struct netr_SamBaseInfo
*base
= NULL
;
265 switch (validation_level
) {
267 if (!validation
|| !validation
->sam2
) {
268 return NT_STATUS_INVALID_PARAMETER
;
270 base
= &validation
->sam2
->base
;
273 if (!validation
|| !validation
->sam3
) {
274 return NT_STATUS_INVALID_PARAMETER
;
276 base
= &validation
->sam3
->base
;
279 if (!validation
|| !validation
->sam6
) {
280 return NT_STATUS_INVALID_PARAMETER
;
282 base
= &validation
->sam6
->base
;
285 return NT_STATUS_INVALID_LEVEL
;
288 user_info_dc
= talloc(mem_ctx
, struct auth_user_info_dc
);
289 NT_STATUS_HAVE_NO_MEMORY(user_info_dc
);
292 Here is where we should check the list of
293 trusted domains, and verify that the SID
296 if (!base
->domain_sid
) {
297 DEBUG(0, ("Cannot operate on a Netlogon Validation without a domain SID"));
298 return NT_STATUS_INVALID_PARAMETER
;
301 /* The IDL layer would be a better place to check this, but to
302 * guard the integer addition below, we double-check */
303 if (base
->groups
.count
> 65535) {
304 return NT_STATUS_INVALID_PARAMETER
;
307 user_info_dc
->num_sids
= 2;
309 user_info_dc
->sids
= talloc_array(user_info_dc
, struct dom_sid
, user_info_dc
->num_sids
+ base
->groups
.count
);
310 NT_STATUS_HAVE_NO_MEMORY(user_info_dc
->sids
);
312 user_info_dc
->sids
[PRIMARY_USER_SID_INDEX
] = *base
->domain_sid
;
313 if (!sid_append_rid(&user_info_dc
->sids
[PRIMARY_USER_SID_INDEX
], base
->rid
)) {
314 return NT_STATUS_INVALID_PARAMETER
;
317 user_info_dc
->sids
[PRIMARY_GROUP_SID_INDEX
] = *base
->domain_sid
;
318 if (!sid_append_rid(&user_info_dc
->sids
[PRIMARY_GROUP_SID_INDEX
], base
->primary_gid
)) {
319 return NT_STATUS_INVALID_PARAMETER
;
322 for (i
= 0; i
< base
->groups
.count
; i
++) {
323 user_info_dc
->sids
[user_info_dc
->num_sids
] = *base
->domain_sid
;
324 if (!sid_append_rid(&user_info_dc
->sids
[user_info_dc
->num_sids
], base
->groups
.rids
[i
].rid
)) {
325 return NT_STATUS_INVALID_PARAMETER
;
327 user_info_dc
->num_sids
++;
330 /* Copy 'other' sids. We need to do sid filtering here to
331 prevent possible elevation of privileges. See:
333 http://www.microsoft.com/windows2000/techinfo/administration/security/sidfilter.asp
336 if (validation_level
== 3) {
337 struct dom_sid
*dgrps
= user_info_dc
->sids
;
340 /* The IDL layer would be a better place to check this, but to
341 * guard the integer addition below, we double-check */
342 if (validation
->sam3
->sidcount
> 65535) {
343 return NT_STATUS_INVALID_PARAMETER
;
346 sidcount
= user_info_dc
->num_sids
+ validation
->sam3
->sidcount
;
347 if (validation
->sam3
->sidcount
> 0) {
348 dgrps
= talloc_realloc(user_info_dc
, dgrps
, struct dom_sid
, sidcount
);
349 NT_STATUS_HAVE_NO_MEMORY(dgrps
);
351 for (i
= 0; i
< validation
->sam3
->sidcount
; i
++) {
352 if (validation
->sam3
->sids
[i
].sid
) {
353 dgrps
[user_info_dc
->num_sids
] = *validation
->sam3
->sids
[i
].sid
;
354 user_info_dc
->num_sids
++;
359 user_info_dc
->sids
= dgrps
;
361 /* Where are the 'global' sids?... */
364 status
= make_user_info_SamBaseInfo(user_info_dc
, account_name
, base
, authenticated
, &user_info_dc
->info
);
365 if (!NT_STATUS_IS_OK(status
)) {
369 /* ensure we are never given NULL session keys */
371 if (all_zero(base
->key
.key
, sizeof(base
->key
.key
))) {
372 user_info_dc
->user_session_key
= data_blob(NULL
, 0);
374 user_info_dc
->user_session_key
= data_blob_talloc(user_info_dc
, base
->key
.key
, sizeof(base
->key
.key
));
375 NT_STATUS_HAVE_NO_MEMORY(user_info_dc
->user_session_key
.data
);
378 if (all_zero(base
->LMSessKey
.key
, sizeof(base
->LMSessKey
.key
))) {
379 user_info_dc
->lm_session_key
= data_blob(NULL
, 0);
381 user_info_dc
->lm_session_key
= data_blob_talloc(user_info_dc
, base
->LMSessKey
.key
, sizeof(base
->LMSessKey
.key
));
382 NT_STATUS_HAVE_NO_MEMORY(user_info_dc
->lm_session_key
.data
);
385 *_user_info_dc
= user_info_dc
;
390 * Make a user_info_dc struct from the PAC_LOGON_INFO supplied in the krb5 logon
392 NTSTATUS
make_user_info_dc_pac(TALLOC_CTX
*mem_ctx
,
393 struct PAC_LOGON_INFO
*pac_logon_info
,
394 struct auth_user_info_dc
**_user_info_dc
)
398 union netr_Validation validation
;
399 struct auth_user_info_dc
*user_info_dc
;
401 validation
.sam3
= &pac_logon_info
->info3
;
403 nt_status
= make_user_info_dc_netlogon_validation(mem_ctx
, "", 3, &validation
,
404 true, /* This user was authenticated */
406 if (!NT_STATUS_IS_OK(nt_status
)) {
410 if (pac_logon_info
->res_groups
.count
> 0) {
412 /* The IDL layer would be a better place to check this, but to
413 * guard the integer addition below, we double-check */
414 if (pac_logon_info
->res_groups
.count
> 65535) {
415 talloc_free(user_info_dc
);
416 return NT_STATUS_INVALID_PARAMETER
;
420 Here is where we should check the list of
421 trusted domains, and verify that the SID
424 if (!pac_logon_info
->res_group_dom_sid
) {
425 DEBUG(0, ("Cannot operate on a PAC without a resource domain SID"));
426 return NT_STATUS_INVALID_PARAMETER
;
429 sidcount
= user_info_dc
->num_sids
+ pac_logon_info
->res_groups
.count
;
431 = talloc_realloc(user_info_dc
, user_info_dc
->sids
, struct dom_sid
, sidcount
);
432 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(user_info_dc
->sids
, user_info_dc
);
434 for (i
= 0; pac_logon_info
->res_group_dom_sid
&& i
< pac_logon_info
->res_groups
.count
; i
++) {
435 user_info_dc
->sids
[user_info_dc
->num_sids
] = *pac_logon_info
->res_group_dom_sid
;
436 if (!sid_append_rid(&user_info_dc
->sids
[user_info_dc
->num_sids
],
437 pac_logon_info
->res_groups
.rids
[i
].rid
)) {
438 return NT_STATUS_INVALID_PARAMETER
;
440 user_info_dc
->num_sids
++;
443 *_user_info_dc
= user_info_dc
;