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 /* FIXME: do we really still need this ? */
27 static int server_info_dtor(struct auth_serversupplied_info
*server_info
)
29 TALLOC_FREE(server_info
->info3
);
30 ZERO_STRUCTP(server_info
);
34 /***************************************************************************
35 Make a server_info struct. Free with TALLOC_FREE().
36 ***************************************************************************/
38 struct auth_serversupplied_info
*make_server_info(TALLOC_CTX
*mem_ctx
)
40 struct auth_serversupplied_info
*result
;
42 result
= TALLOC_ZERO_P(mem_ctx
, struct auth_serversupplied_info
);
44 DEBUG(0, ("talloc failed\n"));
48 talloc_set_destructor(result
, server_info_dtor
);
50 /* Initialise the uid and gid values to something non-zero
51 which may save us from giving away root access if there
52 is a bug in allocating these fields. */
54 result
->utok
.uid
= -1;
55 result
->utok
.gid
= -1;
59 /****************************************************************************
60 inits a netr_SamInfo2 structure from an auth_serversupplied_info. sam2 must
61 already be initialized and is used as the talloc parent for its members.
62 *****************************************************************************/
64 NTSTATUS
serverinfo_to_SamInfo2(struct auth_serversupplied_info
*server_info
,
65 uint8_t *pipe_session_key
,
66 size_t pipe_session_key_len
,
67 struct netr_SamInfo2
*sam2
)
69 struct netr_SamInfo3
*info3
;
71 info3
= copy_netr_SamInfo3(sam2
, server_info
->info3
);
73 return NT_STATUS_NO_MEMORY
;
76 if (server_info
->user_session_key
.length
) {
77 memcpy(info3
->base
.key
.key
,
78 server_info
->user_session_key
.data
,
79 MIN(sizeof(info3
->base
.key
.key
),
80 server_info
->user_session_key
.length
));
81 if (pipe_session_key
) {
82 arcfour_crypt(info3
->base
.key
.key
,
83 pipe_session_key
, 16);
86 if (server_info
->lm_session_key
.length
) {
87 memcpy(info3
->base
.LMSessKey
.key
,
88 server_info
->lm_session_key
.data
,
89 MIN(sizeof(info3
->base
.LMSessKey
.key
),
90 server_info
->lm_session_key
.length
));
91 if (pipe_session_key
) {
92 arcfour_crypt(info3
->base
.LMSessKey
.key
,
97 sam2
->base
= info3
->base
;
102 /****************************************************************************
103 inits a netr_SamInfo3 structure from an auth_serversupplied_info. sam3 must
104 already be initialized and is used as the talloc parent for its members.
105 *****************************************************************************/
107 NTSTATUS
serverinfo_to_SamInfo3(struct auth_serversupplied_info
*server_info
,
108 uint8_t *pipe_session_key
,
109 size_t pipe_session_key_len
,
110 struct netr_SamInfo3
*sam3
)
112 struct netr_SamInfo3
*info3
;
114 info3
= copy_netr_SamInfo3(sam3
, server_info
->info3
);
116 return NT_STATUS_NO_MEMORY
;
119 if (server_info
->user_session_key
.length
) {
120 memcpy(info3
->base
.key
.key
,
121 server_info
->user_session_key
.data
,
122 MIN(sizeof(info3
->base
.key
.key
),
123 server_info
->user_session_key
.length
));
124 if (pipe_session_key
) {
125 arcfour_crypt(info3
->base
.key
.key
,
126 pipe_session_key
, 16);
129 if (server_info
->lm_session_key
.length
) {
130 memcpy(info3
->base
.LMSessKey
.key
,
131 server_info
->lm_session_key
.data
,
132 MIN(sizeof(info3
->base
.LMSessKey
.key
),
133 server_info
->lm_session_key
.length
));
134 if (pipe_session_key
) {
135 arcfour_crypt(info3
->base
.LMSessKey
.key
,
136 pipe_session_key
, 8);
140 sam3
->base
= info3
->base
;
148 /****************************************************************************
149 inits a netr_SamInfo6 structure from an auth_serversupplied_info. sam6 must
150 already be initialized and is used as the talloc parent for its members.
151 *****************************************************************************/
153 NTSTATUS
serverinfo_to_SamInfo6(struct auth_serversupplied_info
*server_info
,
154 uint8_t *pipe_session_key
,
155 size_t pipe_session_key_len
,
156 struct netr_SamInfo6
*sam6
)
158 struct pdb_domain_info
*dominfo
;
159 struct netr_SamInfo3
*info3
;
161 if ((pdb_capabilities() & PDB_CAP_ADS
) == 0) {
162 DEBUG(10,("Not adding validation info level 6 "
163 "without ADS passdb backend\n"));
164 return NT_STATUS_INVALID_INFO_CLASS
;
167 dominfo
= pdb_get_domain_info(sam6
);
168 if (dominfo
== NULL
) {
169 return NT_STATUS_NO_MEMORY
;
172 info3
= copy_netr_SamInfo3(sam6
, server_info
->info3
);
174 return NT_STATUS_NO_MEMORY
;
177 if (server_info
->user_session_key
.length
) {
178 memcpy(info3
->base
.key
.key
,
179 server_info
->user_session_key
.data
,
180 MIN(sizeof(info3
->base
.key
.key
),
181 server_info
->user_session_key
.length
));
182 if (pipe_session_key
) {
183 arcfour_crypt(info3
->base
.key
.key
,
184 pipe_session_key
, 16);
187 if (server_info
->lm_session_key
.length
) {
188 memcpy(info3
->base
.LMSessKey
.key
,
189 server_info
->lm_session_key
.data
,
190 MIN(sizeof(info3
->base
.LMSessKey
.key
),
191 server_info
->lm_session_key
.length
));
192 if (pipe_session_key
) {
193 arcfour_crypt(info3
->base
.LMSessKey
.key
,
194 pipe_session_key
, 8);
198 sam6
->base
= info3
->base
;
203 sam6
->dns_domainname
.string
= talloc_strdup(sam6
, dominfo
->dns_domain
);
204 if (sam6
->dns_domainname
.string
== NULL
) {
205 return NT_STATUS_NO_MEMORY
;
208 sam6
->principle
.string
= talloc_asprintf(sam6
, "%s@%s",
209 sam6
->base
.account_name
.string
,
210 sam6
->dns_domainname
.string
);
211 if (sam6
->principle
.string
== NULL
) {
212 return NT_STATUS_NO_MEMORY
;
218 static NTSTATUS
sids_to_samr_RidWithAttributeArray(
220 struct samr_RidWithAttributeArray
*groups
,
221 const struct dom_sid
*domain_sid
,
222 const struct dom_sid
*sids
,
228 groups
->rids
= talloc_array(mem_ctx
,
229 struct samr_RidWithAttribute
, num_sids
);
231 return NT_STATUS_NO_MEMORY
;
234 for (i
= 0; i
< num_sids
; i
++) {
235 ok
= sid_peek_check_rid(domain_sid
, &sids
[i
],
236 &groups
->rids
[i
].rid
);
239 groups
->rids
[i
].attributes
= SE_GROUP_MANDATORY
|
240 SE_GROUP_ENABLED_BY_DEFAULT
|
249 #define RET_NOMEM(ptr) do { \
251 TALLOC_FREE(info3); \
252 return NT_STATUS_NO_MEMORY; \
255 NTSTATUS
samu_to_SamInfo3(TALLOC_CTX
*mem_ctx
,
257 const char *login_server
,
258 struct netr_SamInfo3
**_info3
)
260 struct netr_SamInfo3
*info3
;
261 const struct dom_sid
*user_sid
;
262 const struct dom_sid
*group_sid
;
263 struct dom_sid domain_sid
;
264 struct dom_sid
*group_sids
;
265 size_t num_group_sids
;
271 user_sid
= pdb_get_user_sid(samu
);
272 group_sid
= pdb_get_group_sid(samu
);
274 if (!user_sid
|| !group_sid
) {
275 DEBUG(1, ("Sam account is missing sids!\n"));
276 return NT_STATUS_UNSUCCESSFUL
;
279 info3
= talloc_zero(mem_ctx
, struct netr_SamInfo3
);
281 return NT_STATUS_NO_MEMORY
;
284 unix_to_nt_time(&info3
->base
.last_logon
, pdb_get_logon_time(samu
));
285 unix_to_nt_time(&info3
->base
.last_logoff
, get_time_t_max());
286 unix_to_nt_time(&info3
->base
.acct_expiry
, get_time_t_max());
287 unix_to_nt_time(&info3
->base
.last_password_change
,
288 pdb_get_pass_last_set_time(samu
));
289 unix_to_nt_time(&info3
->base
.allow_password_change
,
290 pdb_get_pass_can_change_time(samu
));
291 unix_to_nt_time(&info3
->base
.force_password_change
,
292 pdb_get_pass_must_change_time(samu
));
294 tmp
= pdb_get_username(samu
);
296 info3
->base
.account_name
.string
= talloc_strdup(info3
, tmp
);
297 RET_NOMEM(info3
->base
.account_name
.string
);
299 tmp
= pdb_get_fullname(samu
);
301 info3
->base
.full_name
.string
= talloc_strdup(info3
, tmp
);
302 RET_NOMEM(info3
->base
.full_name
.string
);
304 tmp
= pdb_get_logon_script(samu
);
306 info3
->base
.logon_script
.string
= talloc_strdup(info3
, tmp
);
307 RET_NOMEM(info3
->base
.logon_script
.string
);
310 info3
->base
.profile_path
.string
= talloc_strdup(info3
, tmp
);
311 RET_NOMEM(info3
->base
.profile_path
.string
);
314 info3
->base
.home_directory
.string
= talloc_strdup(info3
, tmp
);
315 RET_NOMEM(info3
->base
.home_directory
.string
);
318 info3
->base
.home_drive
.string
= talloc_strdup(info3
, tmp
);
319 RET_NOMEM(info3
->base
.home_drive
.string
);
322 info3
->base
.logon_count
= pdb_get_logon_count(samu
);
323 info3
->base
.bad_password_count
= pdb_get_bad_password_count(samu
);
325 sid_copy(&domain_sid
, user_sid
);
326 sid_split_rid(&domain_sid
, &info3
->base
.rid
);
328 ok
= sid_peek_check_rid(&domain_sid
, group_sid
,
329 &info3
->base
.primary_gid
);
331 DEBUG(1, ("The primary group sid domain does not"
332 "match user sid domain for user: %s\n",
333 pdb_get_username(samu
)));
335 return NT_STATUS_UNSUCCESSFUL
;
338 status
= pdb_enum_group_memberships(mem_ctx
, samu
,
341 if (!NT_STATUS_IS_OK(status
)) {
342 DEBUG(1, ("Failed to get groups from sam account.\n"));
347 status
= sids_to_samr_RidWithAttributeArray(info3
,
352 if (!NT_STATUS_IS_OK(status
)) {
357 /* We don't need sids and gids after the conversion */
358 TALLOC_FREE(group_sids
);
362 /* FIXME: should we add other flags ? */
363 info3
->base
.user_flags
= NETLOGON_EXTRA_SIDS
;
366 info3
->base
.logon_server
.string
= talloc_strdup(info3
, login_server
);
367 RET_NOMEM(info3
->base
.logon_server
.string
);
370 info3
->base
.domain
.string
= talloc_strdup(info3
,
371 pdb_get_domain(samu
));
372 RET_NOMEM(info3
->base
.domain
.string
);
374 info3
->base
.domain_sid
= sid_dup_talloc(info3
, &domain_sid
);
375 RET_NOMEM(info3
->base
.domain_sid
);
377 info3
->base
.acct_flags
= pdb_get_acct_ctrl(samu
);
385 #define RET_NOMEM(ptr) do { \
387 TALLOC_FREE(info3); \
391 struct netr_SamInfo3
*copy_netr_SamInfo3(TALLOC_CTX
*mem_ctx
,
392 struct netr_SamInfo3
*orig
)
394 struct netr_SamInfo3
*info3
;
397 info3
= talloc_zero(mem_ctx
, struct netr_SamInfo3
);
398 if (!info3
) return NULL
;
400 /* first copy all, then realloc pointers */
401 info3
->base
= orig
->base
;
403 if (orig
->base
.account_name
.string
) {
404 info3
->base
.account_name
.string
=
405 talloc_strdup(info3
, orig
->base
.account_name
.string
);
406 RET_NOMEM(info3
->base
.account_name
.string
);
408 if (orig
->base
.full_name
.string
) {
409 info3
->base
.full_name
.string
=
410 talloc_strdup(info3
, orig
->base
.full_name
.string
);
411 RET_NOMEM(info3
->base
.full_name
.string
);
413 if (orig
->base
.logon_script
.string
) {
414 info3
->base
.logon_script
.string
=
415 talloc_strdup(info3
, orig
->base
.logon_script
.string
);
416 RET_NOMEM(info3
->base
.logon_script
.string
);
418 if (orig
->base
.profile_path
.string
) {
419 info3
->base
.profile_path
.string
=
420 talloc_strdup(info3
, orig
->base
.profile_path
.string
);
421 RET_NOMEM(info3
->base
.profile_path
.string
);
423 if (orig
->base
.home_directory
.string
) {
424 info3
->base
.home_directory
.string
=
425 talloc_strdup(info3
, orig
->base
.home_directory
.string
);
426 RET_NOMEM(info3
->base
.home_directory
.string
);
428 if (orig
->base
.home_drive
.string
) {
429 info3
->base
.home_drive
.string
=
430 talloc_strdup(info3
, orig
->base
.home_drive
.string
);
431 RET_NOMEM(info3
->base
.home_drive
.string
);
434 if (orig
->base
.groups
.count
) {
435 info3
->base
.groups
.rids
= (struct samr_RidWithAttribute
*)
436 talloc_memdup(info3
, orig
->base
.groups
.rids
,
437 (sizeof(struct samr_RidWithAttribute
) *
438 orig
->base
.groups
.count
));
439 RET_NOMEM(info3
->base
.groups
.rids
);
442 if (orig
->base
.logon_server
.string
) {
443 info3
->base
.logon_server
.string
=
444 talloc_strdup(info3
, orig
->base
.logon_server
.string
);
445 RET_NOMEM(info3
->base
.logon_server
.string
);
447 if (orig
->base
.domain
.string
) {
448 info3
->base
.domain
.string
=
449 talloc_strdup(info3
, orig
->base
.domain
.string
);
450 RET_NOMEM(info3
->base
.domain
.string
);
453 if (orig
->base
.domain_sid
) {
454 info3
->base
.domain_sid
= sid_dup_talloc(info3
, orig
->base
.domain_sid
);
455 RET_NOMEM(info3
->base
.domain_sid
);
458 if (orig
->sidcount
) {
459 info3
->sids
= talloc_array(info3
, struct netr_SidAttr
,
461 RET_NOMEM(info3
->sids
);
462 for (i
= 0; i
< orig
->sidcount
; i
++) {
463 info3
->sids
[i
].sid
= sid_dup_talloc(info3
->sids
,
465 RET_NOMEM(info3
->sids
[i
].sid
);
472 static NTSTATUS
wbcsids_to_samr_RidWithAttributeArray(
474 struct samr_RidWithAttributeArray
*groups
,
475 const struct dom_sid
*domain_sid
,
476 const struct wbcSidWithAttr
*sids
,
482 groups
->rids
= talloc_array(mem_ctx
,
483 struct samr_RidWithAttribute
, num_sids
);
485 return NT_STATUS_NO_MEMORY
;
488 /* a wbcDomainSid is the same as a dom_sid */
489 for (i
= 0; i
< num_sids
; i
++) {
490 ok
= sid_peek_check_rid(domain_sid
,
491 (const struct dom_sid
*)&sids
[i
].sid
,
492 &groups
->rids
[i
].rid
);
495 groups
->rids
[i
].attributes
= SE_GROUP_MANDATORY
|
496 SE_GROUP_ENABLED_BY_DEFAULT
|
504 struct netr_SamInfo3
*wbcAuthUserInfo_to_netr_SamInfo3(TALLOC_CTX
*mem_ctx
,
505 const struct wbcAuthUserInfo
*info
)
507 struct netr_SamInfo3
*info3
;
508 struct dom_sid user_sid
;
509 struct dom_sid group_sid
;
510 struct dom_sid domain_sid
;
514 memcpy(&user_sid
, &info
->sids
[0].sid
, sizeof(user_sid
));
515 memcpy(&group_sid
, &info
->sids
[1].sid
, sizeof(group_sid
));
517 info3
= talloc_zero(mem_ctx
, struct netr_SamInfo3
);
518 if (!info3
) return NULL
;
520 info3
->base
.last_logon
= info
->logon_time
;
521 info3
->base
.last_logoff
= info
->logoff_time
;
522 info3
->base
.acct_expiry
= info
->kickoff_time
;
523 info3
->base
.last_password_change
= info
->pass_last_set_time
;
524 info3
->base
.allow_password_change
= info
->pass_can_change_time
;
525 info3
->base
.force_password_change
= info
->pass_must_change_time
;
527 if (info
->account_name
) {
528 info3
->base
.account_name
.string
=
529 talloc_strdup(info3
, info
->account_name
);
530 RET_NOMEM(info3
->base
.account_name
.string
);
532 if (info
->full_name
) {
533 info3
->base
.full_name
.string
=
534 talloc_strdup(info3
, info
->full_name
);
535 RET_NOMEM(info3
->base
.full_name
.string
);
537 if (info
->logon_script
) {
538 info3
->base
.logon_script
.string
=
539 talloc_strdup(info3
, info
->logon_script
);
540 RET_NOMEM(info3
->base
.logon_script
.string
);
542 if (info
->profile_path
) {
543 info3
->base
.profile_path
.string
=
544 talloc_strdup(info3
, info
->profile_path
);
545 RET_NOMEM(info3
->base
.profile_path
.string
);
547 if (info
->home_directory
) {
548 info3
->base
.home_directory
.string
=
549 talloc_strdup(info3
, info
->home_directory
);
550 RET_NOMEM(info3
->base
.home_directory
.string
);
552 if (info
->home_drive
) {
553 info3
->base
.home_drive
.string
=
554 talloc_strdup(info3
, info
->home_drive
);
555 RET_NOMEM(info3
->base
.home_drive
.string
);
558 info3
->base
.logon_count
= info
->logon_count
;
559 info3
->base
.bad_password_count
= info
->bad_password_count
;
561 sid_copy(&domain_sid
, &user_sid
);
562 sid_split_rid(&domain_sid
, &info3
->base
.rid
);
564 ok
= sid_peek_check_rid(&domain_sid
, &group_sid
,
565 &info3
->base
.primary_gid
);
567 DEBUG(1, ("The primary group sid domain does not"
568 "match user sid domain for user: %s\n",
569 info
->account_name
));
574 status
= wbcsids_to_samr_RidWithAttributeArray(info3
,
579 if (!NT_STATUS_IS_OK(status
)) {
584 info3
->base
.user_flags
= info
->user_flags
;
585 memcpy(info3
->base
.key
.key
, info
->user_session_key
, 16);
587 if (info
->logon_server
) {
588 info3
->base
.logon_server
.string
=
589 talloc_strdup(info3
, info
->logon_server
);
590 RET_NOMEM(info3
->base
.logon_server
.string
);
592 if (info
->domain_name
) {
593 info3
->base
.domain
.string
=
594 talloc_strdup(info3
, info
->domain_name
);
595 RET_NOMEM(info3
->base
.domain
.string
);
598 info3
->base
.domain_sid
= sid_dup_talloc(info3
, &domain_sid
);
599 RET_NOMEM(info3
->base
.domain_sid
);
601 memcpy(info3
->base
.LMSessKey
.key
, info
->lm_session_key
, 8);
602 info3
->base
.acct_flags
= info
->acct_flags
;