2 Unix SMB/CIFS implementation.
3 Authentication utility functions
4 Copyright (C) Volker Lendecke 2010
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "../lib/crypto/arcfour.h"
24 #define DBGC_CLASS DBGC_AUTH
26 static int server_info_dtor(struct auth_serversupplied_info
*server_info
)
28 TALLOC_FREE(server_info
->sam_account
);
29 ZERO_STRUCTP(server_info
);
33 /***************************************************************************
34 Make a server_info struct. Free with TALLOC_FREE().
35 ***************************************************************************/
37 struct auth_serversupplied_info
*make_server_info(TALLOC_CTX
*mem_ctx
)
39 struct auth_serversupplied_info
*result
;
41 result
= TALLOC_ZERO_P(mem_ctx
, struct auth_serversupplied_info
);
43 DEBUG(0, ("talloc failed\n"));
47 talloc_set_destructor(result
, server_info_dtor
);
49 /* Initialise the uid and gid values to something non-zero
50 which may save us from giving away root access if there
51 is a bug in allocating these fields. */
53 result
->utok
.uid
= -1;
54 result
->utok
.gid
= -1;
58 /*******************************************************************
59 gets a domain user's groups from their already-calculated NT_USER_TOKEN
60 ********************************************************************/
62 static NTSTATUS
nt_token_to_group_list(TALLOC_CTX
*mem_ctx
,
63 const struct dom_sid
*domain_sid
,
65 const struct dom_sid
*sids
,
67 struct samr_RidWithAttribute
**pgids
)
74 for (i
=0; i
<num_sids
; i
++) {
75 struct samr_RidWithAttribute gid
;
76 if (!sid_peek_check_rid(domain_sid
, &sids
[i
], &gid
.rid
)) {
79 gid
.attributes
= (SE_GROUP_MANDATORY
|SE_GROUP_ENABLED_BY_DEFAULT
|
81 ADD_TO_ARRAY(mem_ctx
, struct samr_RidWithAttribute
,
82 gid
, pgids
, numgroups
);
84 return NT_STATUS_NO_MEMORY
;
90 /****************************************************************************
91 inits a netr_SamBaseInfo structure from an auth_serversupplied_info.
92 *****************************************************************************/
94 static NTSTATUS
serverinfo_to_SamInfo_base(TALLOC_CTX
*mem_ctx
,
95 struct auth_serversupplied_info
*server_info
,
96 uint8_t *pipe_session_key
,
97 size_t pipe_session_key_len
,
98 struct netr_SamBaseInfo
*base
)
101 struct samr_RidWithAttribute
*gids
= NULL
;
102 const struct dom_sid
*user_sid
= NULL
;
103 const struct dom_sid
*group_sid
= NULL
;
104 struct dom_sid domain_sid
;
105 uint32 user_rid
, group_rid
;
111 struct netr_UserSessionKey user_session_key
;
112 struct netr_LMSessionKey lm_session_key
;
114 NTTIME last_logon
, last_logoff
, acct_expiry
, last_password_change
;
115 NTTIME allow_password_change
, force_password_change
;
116 struct samr_RidWithAttributeArray groups
;
118 struct dom_sid2
*sid
= NULL
;
120 ZERO_STRUCT(user_session_key
);
121 ZERO_STRUCT(lm_session_key
);
123 sampw
= server_info
->sam_account
;
125 user_sid
= pdb_get_user_sid(sampw
);
126 group_sid
= pdb_get_group_sid(sampw
);
128 if (pipe_session_key
&& pipe_session_key_len
!= 16) {
129 DEBUG(0,("serverinfo_to_SamInfo3: invalid "
130 "pipe_session_key_len[%zu] != 16\n",
131 pipe_session_key_len
));
132 return NT_STATUS_INTERNAL_ERROR
;
135 if ((user_sid
== NULL
) || (group_sid
== NULL
)) {
136 DEBUG(1, ("_netr_LogonSamLogon: User without group or user SID\n"));
137 return NT_STATUS_UNSUCCESSFUL
;
140 sid_copy(&domain_sid
, user_sid
);
141 sid_split_rid(&domain_sid
, &user_rid
);
143 sid
= sid_dup_talloc(mem_ctx
, &domain_sid
);
145 return NT_STATUS_NO_MEMORY
;
148 if (!sid_peek_check_rid(&domain_sid
, group_sid
, &group_rid
)) {
149 DEBUG(1, ("_netr_LogonSamLogon: user %s\\%s has user sid "
150 "%s\n but group sid %s.\n"
151 "The conflicting domain portions are not "
152 "supported for NETLOGON calls\n",
153 pdb_get_domain(sampw
),
154 pdb_get_username(sampw
),
155 sid_string_dbg(user_sid
),
156 sid_string_dbg(group_sid
)));
157 return NT_STATUS_UNSUCCESSFUL
;
160 if(server_info
->login_server
) {
161 my_name
= server_info
->login_server
;
163 my_name
= global_myname();
166 status
= nt_token_to_group_list(mem_ctx
, &domain_sid
,
167 server_info
->num_sids
,
171 if (!NT_STATUS_IS_OK(status
)) {
175 if (server_info
->user_session_key
.length
) {
176 memcpy(user_session_key
.key
,
177 server_info
->user_session_key
.data
,
178 MIN(sizeof(user_session_key
.key
),
179 server_info
->user_session_key
.length
));
180 if (pipe_session_key
) {
181 arcfour_crypt(user_session_key
.key
, pipe_session_key
, 16);
184 if (server_info
->lm_session_key
.length
) {
185 memcpy(lm_session_key
.key
,
186 server_info
->lm_session_key
.data
,
187 MIN(sizeof(lm_session_key
.key
),
188 server_info
->lm_session_key
.length
));
189 if (pipe_session_key
) {
190 arcfour_crypt(lm_session_key
.key
, pipe_session_key
, 8);
194 groups
.count
= num_gids
;
195 groups
.rids
= TALLOC_ARRAY(mem_ctx
, struct samr_RidWithAttribute
, groups
.count
);
197 return NT_STATUS_NO_MEMORY
;
200 for (i
=0; i
< groups
.count
; i
++) {
201 groups
.rids
[i
].rid
= gids
[i
].rid
;
202 groups
.rids
[i
].attributes
= gids
[i
].attributes
;
205 unix_to_nt_time(&last_logon
, pdb_get_logon_time(sampw
));
206 unix_to_nt_time(&last_logoff
, get_time_t_max());
207 unix_to_nt_time(&acct_expiry
, get_time_t_max());
208 unix_to_nt_time(&last_password_change
, pdb_get_pass_last_set_time(sampw
));
209 unix_to_nt_time(&allow_password_change
, pdb_get_pass_can_change_time(sampw
));
210 unix_to_nt_time(&force_password_change
, pdb_get_pass_must_change_time(sampw
));
212 base
->last_logon
= last_logon
;
213 base
->last_logoff
= last_logoff
;
214 base
->acct_expiry
= acct_expiry
;
215 base
->last_password_change
= last_password_change
;
216 base
->allow_password_change
= allow_password_change
;
217 base
->force_password_change
= force_password_change
;
218 base
->account_name
.string
= talloc_strdup(mem_ctx
, pdb_get_username(sampw
));
219 base
->full_name
.string
= talloc_strdup(mem_ctx
, pdb_get_fullname(sampw
));
220 base
->logon_script
.string
= talloc_strdup(mem_ctx
, pdb_get_logon_script(sampw
));
221 base
->profile_path
.string
= talloc_strdup(mem_ctx
, pdb_get_profile_path(sampw
));
222 base
->home_directory
.string
= talloc_strdup(mem_ctx
, pdb_get_homedir(sampw
));
223 base
->home_drive
.string
= talloc_strdup(mem_ctx
, pdb_get_dir_drive(sampw
));
224 base
->logon_count
= 0; /* ?? */
225 base
->bad_password_count
= 0; /* ?? */
226 base
->rid
= user_rid
;
227 base
->primary_gid
= group_rid
;
228 base
->groups
= groups
;
229 base
->user_flags
= NETLOGON_EXTRA_SIDS
;
230 base
->key
= user_session_key
;
231 base
->logon_server
.string
= talloc_strdup(mem_ctx
, my_name
);
232 base
->domain
.string
= talloc_strdup(mem_ctx
, pdb_get_domain(sampw
));
233 base
->domain_sid
= sid
;
234 base
->LMSessKey
= lm_session_key
;
235 base
->acct_flags
= pdb_get_acct_ctrl(sampw
);
237 ZERO_STRUCT(user_session_key
);
238 ZERO_STRUCT(lm_session_key
);
243 /****************************************************************************
244 inits a netr_SamInfo2 structure from an auth_serversupplied_info. sam2 must
245 already be initialized and is used as the talloc parent for its members.
246 *****************************************************************************/
248 NTSTATUS
serverinfo_to_SamInfo2(struct auth_serversupplied_info
*server_info
,
249 uint8_t *pipe_session_key
,
250 size_t pipe_session_key_len
,
251 struct netr_SamInfo2
*sam2
)
255 status
= serverinfo_to_SamInfo_base(sam2
,
258 pipe_session_key_len
,
260 if (!NT_STATUS_IS_OK(status
)) {
267 /****************************************************************************
268 inits a netr_SamInfo3 structure from an auth_serversupplied_info. sam3 must
269 already be initialized and is used as the talloc parent for its members.
270 *****************************************************************************/
272 NTSTATUS
serverinfo_to_SamInfo3(struct auth_serversupplied_info
*server_info
,
273 uint8_t *pipe_session_key
,
274 size_t pipe_session_key_len
,
275 struct netr_SamInfo3
*sam3
)
279 status
= serverinfo_to_SamInfo_base(sam3
,
282 pipe_session_key_len
,
284 if (!NT_STATUS_IS_OK(status
)) {
294 /****************************************************************************
295 inits a netr_SamInfo6 structure from an auth_serversupplied_info. sam6 must
296 already be initialized and is used as the talloc parent for its members.
297 *****************************************************************************/
299 NTSTATUS
serverinfo_to_SamInfo6(struct auth_serversupplied_info
*server_info
,
300 uint8_t *pipe_session_key
,
301 size_t pipe_session_key_len
,
302 struct netr_SamInfo6
*sam6
)
305 struct pdb_domain_info
*dominfo
;
307 if ((pdb_capabilities() & PDB_CAP_ADS
) == 0) {
308 DEBUG(10,("Not adding validation info level 6 "
309 "without ADS passdb backend\n"));
310 return NT_STATUS_INVALID_INFO_CLASS
;
313 dominfo
= pdb_get_domain_info(sam6
);
314 if (dominfo
== NULL
) {
315 return NT_STATUS_NO_MEMORY
;
318 status
= serverinfo_to_SamInfo_base(sam6
,
321 pipe_session_key_len
,
323 if (!NT_STATUS_IS_OK(status
)) {
330 sam6
->dns_domainname
.string
= talloc_strdup(sam6
, dominfo
->dns_domain
);
331 if (sam6
->dns_domainname
.string
== NULL
) {
332 return NT_STATUS_NO_MEMORY
;
335 sam6
->principle
.string
= talloc_asprintf(sam6
, "%s@%s",
336 pdb_get_username(server_info
->sam_account
),
337 sam6
->dns_domainname
.string
);
338 if (sam6
->principle
.string
== NULL
) {
339 return NT_STATUS_NO_MEMORY
;
345 static NTSTATUS
sids_to_samr_RidWithAttributeArray(
347 struct samr_RidWithAttributeArray
*groups
,
348 const struct dom_sid
*domain_sid
,
349 const struct dom_sid
*sids
,
355 groups
->rids
= talloc_array(mem_ctx
,
356 struct samr_RidWithAttribute
, num_sids
);
358 return NT_STATUS_NO_MEMORY
;
361 for (i
= 0; i
< num_sids
; i
++) {
362 ok
= sid_peek_check_rid(domain_sid
, &sids
[i
],
363 &groups
->rids
[i
].rid
);
366 groups
->rids
[i
].attributes
= SE_GROUP_MANDATORY
|
367 SE_GROUP_ENABLED_BY_DEFAULT
|
376 #define RET_NOMEM(ptr) do { \
378 TALLOC_FREE(info3); \
379 return NT_STATUS_NO_MEMORY; \
382 NTSTATUS
samu_to_SamInfo3(TALLOC_CTX
*mem_ctx
,
384 const char *login_server
,
385 struct netr_SamInfo3
**_info3
)
387 struct netr_SamInfo3
*info3
;
388 const struct dom_sid
*user_sid
;
389 const struct dom_sid
*group_sid
;
390 struct dom_sid domain_sid
;
391 struct dom_sid
*group_sids
;
392 size_t num_group_sids
;
398 user_sid
= pdb_get_user_sid(samu
);
399 group_sid
= pdb_get_group_sid(samu
);
401 if (!user_sid
|| !group_sid
) {
402 DEBUG(1, ("Sam account is missing sids!\n"));
403 return NT_STATUS_UNSUCCESSFUL
;
406 info3
= talloc_zero(mem_ctx
, struct netr_SamInfo3
);
408 return NT_STATUS_NO_MEMORY
;
411 unix_to_nt_time(&info3
->base
.last_logon
, pdb_get_logon_time(samu
));
412 unix_to_nt_time(&info3
->base
.last_logoff
, get_time_t_max());
413 unix_to_nt_time(&info3
->base
.acct_expiry
, get_time_t_max());
414 unix_to_nt_time(&info3
->base
.last_password_change
,
415 pdb_get_pass_last_set_time(samu
));
416 unix_to_nt_time(&info3
->base
.allow_password_change
,
417 pdb_get_pass_can_change_time(samu
));
418 unix_to_nt_time(&info3
->base
.force_password_change
,
419 pdb_get_pass_must_change_time(samu
));
421 tmp
= pdb_get_username(samu
);
423 info3
->base
.account_name
.string
= talloc_strdup(info3
, tmp
);
424 RET_NOMEM(info3
->base
.account_name
.string
);
426 tmp
= pdb_get_fullname(samu
);
428 info3
->base
.full_name
.string
= talloc_strdup(info3
, tmp
);
429 RET_NOMEM(info3
->base
.full_name
.string
);
431 tmp
= pdb_get_logon_script(samu
);
433 info3
->base
.logon_script
.string
= talloc_strdup(info3
, tmp
);
434 RET_NOMEM(info3
->base
.logon_script
.string
);
437 info3
->base
.profile_path
.string
= talloc_strdup(info3
, tmp
);
438 RET_NOMEM(info3
->base
.profile_path
.string
);
441 info3
->base
.home_directory
.string
= talloc_strdup(info3
, tmp
);
442 RET_NOMEM(info3
->base
.home_directory
.string
);
445 info3
->base
.home_drive
.string
= talloc_strdup(info3
, tmp
);
446 RET_NOMEM(info3
->base
.home_drive
.string
);
449 info3
->base
.logon_count
= pdb_get_logon_count(samu
);
450 info3
->base
.bad_password_count
= pdb_get_bad_password_count(samu
);
452 sid_copy(&domain_sid
, user_sid
);
453 sid_split_rid(&domain_sid
, &info3
->base
.rid
);
455 ok
= sid_peek_check_rid(&domain_sid
, group_sid
,
456 &info3
->base
.primary_gid
);
458 DEBUG(1, ("The primary group sid domain does not"
459 "match user sid domain for user: %s\n",
460 pdb_get_username(samu
)));
462 return NT_STATUS_UNSUCCESSFUL
;
465 status
= pdb_enum_group_memberships(mem_ctx
, samu
,
468 if (!NT_STATUS_IS_OK(status
)) {
469 DEBUG(1, ("Failed to get groups from sam account.\n"));
474 status
= sids_to_samr_RidWithAttributeArray(info3
,
479 if (!NT_STATUS_IS_OK(status
)) {
484 /* We don't need sids and gids after the conversion */
485 TALLOC_FREE(group_sids
);
489 /* FIXME: should we add other flags ? */
490 info3
->base
.user_flags
= NETLOGON_EXTRA_SIDS
;
493 info3
->base
.logon_server
.string
= talloc_strdup(info3
, login_server
);
494 RET_NOMEM(info3
->base
.logon_server
.string
);
497 info3
->base
.domain
.string
= talloc_strdup(info3
,
498 pdb_get_domain(samu
));
499 RET_NOMEM(info3
->base
.domain
.string
);
501 info3
->base
.domain_sid
= sid_dup_talloc(info3
, &domain_sid
);
502 RET_NOMEM(info3
->base
.domain_sid
);
504 info3
->base
.acct_flags
= pdb_get_acct_ctrl(samu
);
512 #define RET_NOMEM(ptr) do { \
514 TALLOC_FREE(info3); \
518 struct netr_SamInfo3
*copy_netr_SamInfo3(TALLOC_CTX
*mem_ctx
,
519 struct netr_SamInfo3
*orig
)
521 struct netr_SamInfo3
*info3
;
523 info3
= talloc(mem_ctx
, struct netr_SamInfo3
);
524 if (!info3
) return NULL
;
526 /* first copy all, then realloc pointers */
527 info3
->base
= orig
->base
;
529 info3
->base
.account_name
.string
=
530 talloc_strdup(info3
, orig
->base
.account_name
.string
);
531 RET_NOMEM(info3
->base
.account_name
.string
);
532 info3
->base
.full_name
.string
=
533 talloc_strdup(info3
, orig
->base
.full_name
.string
);
534 RET_NOMEM(info3
->base
.full_name
.string
);
535 info3
->base
.logon_script
.string
=
536 talloc_strdup(info3
, orig
->base
.logon_script
.string
);
537 RET_NOMEM(info3
->base
.logon_script
.string
);
538 info3
->base
.profile_path
.string
=
539 talloc_strdup(info3
, orig
->base
.profile_path
.string
);
540 RET_NOMEM(info3
->base
.profile_path
.string
);
541 info3
->base
.home_directory
.string
=
542 talloc_strdup(info3
, orig
->base
.home_directory
.string
);
543 RET_NOMEM(info3
->base
.home_directory
.string
);
544 info3
->base
.home_drive
.string
=
545 talloc_strdup(info3
, orig
->base
.home_drive
.string
);
546 RET_NOMEM(info3
->base
.home_drive
.string
);
548 info3
->base
.groups
.rids
=
549 talloc_memdup(info3
, orig
->base
.groups
.rids
,
550 (sizeof(struct samr_RidWithAttribute
) *
551 orig
->base
.groups
.count
));
552 RET_NOMEM(info3
->base
.groups
.rids
);
554 info3
->base
.logon_server
.string
=
555 talloc_strdup(info3
, orig
->base
.logon_server
.string
);
556 RET_NOMEM(info3
->base
.logon_server
.string
);
557 info3
->base
.domain
.string
=
558 talloc_strdup(info3
, orig
->base
.domain
.string
);
559 RET_NOMEM(info3
->base
.domain
.string
);
561 info3
->base
.domain_sid
= sid_dup_talloc(info3
, orig
->base
.domain_sid
);
562 RET_NOMEM(info3
->base
.domain_sid
);
564 info3
->sids
= talloc_memdup(info3
, orig
->sids
,
565 (sizeof(struct netr_SidAttr
) *
567 RET_NOMEM(info3
->sids
);