2 Unix SMB/CIFS implementation.
3 Authentication utility functions
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Andrew Bartlett 2001-2011
6 Copyright (C) Jeremy Allison 2000-2001
7 Copyright (C) Rafal Szczesniak 2002
8 Copyright (C) Volker Lendecke 2006-2008
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include "lib/util_unixsids.h"
27 #include "../libcli/auth/libcli_auth.h"
28 #include "../lib/crypto/arcfour.h"
29 #include "rpc_client/init_lsa.h"
30 #include "../libcli/security/security.h"
31 #include "../lib/util/util_pw.h"
32 #include "lib/winbind_util.h"
34 #include "../librpc/gen_ndr/ndr_auth.h"
35 #include "../auth/auth_sam_reply.h"
36 #include "../librpc/gen_ndr/idmap.h"
37 #include "lib/param/loadparm.h"
38 #include "../lib/tsocket/tsocket.h"
41 #define DBGC_CLASS DBGC_AUTH
43 /****************************************************************************
44 Create a UNIX user on demand.
45 ****************************************************************************/
47 static int _smb_create_user(const char *domain
, const char *unix_username
, const char *homedir
)
49 TALLOC_CTX
*ctx
= talloc_tos();
53 add_script
= lp_add_user_script(ctx
);
54 if (!add_script
|| !*add_script
) {
57 add_script
= talloc_all_string_sub(ctx
,
65 add_script
= talloc_all_string_sub(ctx
,
74 add_script
= talloc_all_string_sub(ctx
,
82 ret
= smbrun(add_script
, NULL
, NULL
);
85 ("smb_create_user: Running the command `%s' gave %d\n",
90 /****************************************************************************
91 Create an auth_usersupplied_data structure after appropriate mapping.
92 ****************************************************************************/
94 NTSTATUS
make_user_info_map(TALLOC_CTX
*mem_ctx
,
95 struct auth_usersupplied_info
**user_info
,
97 const char *client_domain
,
98 const char *workstation_name
,
99 const struct tsocket_address
*remote_address
,
100 const struct tsocket_address
*local_address
,
101 const char *service_description
,
102 const DATA_BLOB
*lm_pwd
,
103 const DATA_BLOB
*nt_pwd
,
104 const struct samr_Password
*lm_interactive_pwd
,
105 const struct samr_Password
*nt_interactive_pwd
,
106 const char *plaintext
,
107 enum auth_password_state password_state
)
112 char *internal_username
= NULL
;
114 was_mapped
= map_username(talloc_tos(), smb_name
, &internal_username
);
115 if (!internal_username
) {
116 return NT_STATUS_NO_MEMORY
;
119 DEBUG(5, ("Mapping user [%s]\\[%s] from workstation [%s]\n",
120 client_domain
, smb_name
, workstation_name
));
123 * We let the auth stack canonicalize, username
126 domain
= client_domain
;
128 result
= make_user_info(mem_ctx
, user_info
, smb_name
, internal_username
,
129 client_domain
, domain
, workstation_name
,
130 remote_address
, local_address
,
131 service_description
, lm_pwd
, nt_pwd
,
132 lm_interactive_pwd
, nt_interactive_pwd
,
133 plaintext
, password_state
);
134 if (NT_STATUS_IS_OK(result
)) {
135 /* We have tried mapping */
136 (*user_info
)->mapped_state
= true;
137 /* did we actually map the user to a different name? */
138 (*user_info
)->was_mapped
= was_mapped
;
143 /****************************************************************************
144 Create an auth_usersupplied_data, making the DATA_BLOBs here.
145 Decrypt and encrypt the passwords.
146 ****************************************************************************/
148 bool make_user_info_netlogon_network(TALLOC_CTX
*mem_ctx
,
149 struct auth_usersupplied_info
**user_info
,
150 const char *smb_name
,
151 const char *client_domain
,
152 const char *workstation_name
,
153 const struct tsocket_address
*remote_address
,
154 const struct tsocket_address
*local_address
,
155 uint32_t logon_parameters
,
156 const uchar
*lm_network_pwd
,
158 const uchar
*nt_network_pwd
,
163 DATA_BLOB lm_blob
= data_blob(lm_network_pwd
, lm_pwd_len
);
164 DATA_BLOB nt_blob
= data_blob(nt_network_pwd
, nt_pwd_len
);
166 status
= make_user_info_map(mem_ctx
, user_info
,
167 smb_name
, client_domain
,
172 lm_pwd_len
? &lm_blob
: NULL
,
173 nt_pwd_len
? &nt_blob
: NULL
,
175 AUTH_PASSWORD_RESPONSE
);
177 if (NT_STATUS_IS_OK(status
)) {
178 (*user_info
)->logon_parameters
= logon_parameters
;
180 ret
= NT_STATUS_IS_OK(status
) ? true : false;
182 data_blob_free(&lm_blob
);
183 data_blob_free(&nt_blob
);
187 /****************************************************************************
188 Create an auth_usersupplied_data, making the DATA_BLOBs here.
189 Decrypt and encrypt the passwords.
190 ****************************************************************************/
192 bool make_user_info_netlogon_interactive(TALLOC_CTX
*mem_ctx
,
193 struct auth_usersupplied_info
**user_info
,
194 const char *smb_name
,
195 const char *client_domain
,
196 const char *workstation_name
,
197 const struct tsocket_address
*remote_address
,
198 const struct tsocket_address
*local_address
,
199 uint32_t logon_parameters
,
201 const uchar lm_interactive_pwd
[16],
202 const uchar nt_interactive_pwd
[16])
204 struct samr_Password lm_pwd
;
205 struct samr_Password nt_pwd
;
206 unsigned char local_lm_response
[24];
207 unsigned char local_nt_response
[24];
209 if (lm_interactive_pwd
)
210 memcpy(lm_pwd
.hash
, lm_interactive_pwd
, sizeof(lm_pwd
.hash
));
212 if (nt_interactive_pwd
)
213 memcpy(nt_pwd
.hash
, nt_interactive_pwd
, sizeof(nt_pwd
.hash
));
215 if (lm_interactive_pwd
)
216 SMBOWFencrypt(lm_pwd
.hash
, chal
,
219 if (nt_interactive_pwd
)
220 SMBOWFencrypt(nt_pwd
.hash
, chal
,
226 DATA_BLOB local_lm_blob
= data_blob_null
;
227 DATA_BLOB local_nt_blob
= data_blob_null
;
229 if (lm_interactive_pwd
) {
230 local_lm_blob
= data_blob(local_lm_response
,
231 sizeof(local_lm_response
));
234 if (nt_interactive_pwd
) {
235 local_nt_blob
= data_blob(local_nt_response
,
236 sizeof(local_nt_response
));
239 nt_status
= make_user_info_map(
242 smb_name
, client_domain
, workstation_name
,
246 lm_interactive_pwd
? &local_lm_blob
: NULL
,
247 nt_interactive_pwd
? &local_nt_blob
: NULL
,
248 lm_interactive_pwd
? &lm_pwd
: NULL
,
249 nt_interactive_pwd
? &nt_pwd
: NULL
,
250 NULL
, AUTH_PASSWORD_HASH
);
252 if (NT_STATUS_IS_OK(nt_status
)) {
253 (*user_info
)->logon_parameters
= logon_parameters
;
256 ret
= NT_STATUS_IS_OK(nt_status
) ? true : false;
257 data_blob_free(&local_lm_blob
);
258 data_blob_free(&local_nt_blob
);
264 /****************************************************************************
265 Create an auth_usersupplied_data structure
266 ****************************************************************************/
268 bool make_user_info_for_reply(TALLOC_CTX
*mem_ctx
,
269 struct auth_usersupplied_info
**user_info
,
270 const char *smb_name
,
271 const char *client_domain
,
272 const struct tsocket_address
*remote_address
,
273 const struct tsocket_address
*local_address
,
274 const char *service_description
,
275 const uint8_t chal
[8],
276 DATA_BLOB plaintext_password
)
279 DATA_BLOB local_lm_blob
;
280 DATA_BLOB local_nt_blob
;
281 NTSTATUS ret
= NT_STATUS_UNSUCCESSFUL
;
282 char *plaintext_password_string
;
284 * Not encrypted - do so.
287 DEBUG(5,("make_user_info_for_reply: User passwords not in encrypted "
289 if (plaintext_password
.data
&& plaintext_password
.length
) {
290 unsigned char local_lm_response
[24];
292 #ifdef DEBUG_PASSWORD
293 DEBUG(10,("Unencrypted password (len %d):\n",
294 (int)plaintext_password
.length
));
295 dump_data(100, plaintext_password
.data
,
296 plaintext_password
.length
);
299 SMBencrypt( (const char *)plaintext_password
.data
,
300 (const uchar
*)chal
, local_lm_response
);
301 local_lm_blob
= data_blob(local_lm_response
, 24);
303 /* We can't do an NT hash here, as the password needs to be
305 local_nt_blob
= data_blob_null
;
307 local_lm_blob
= data_blob_null
;
308 local_nt_blob
= data_blob_null
;
311 plaintext_password_string
= talloc_strndup(talloc_tos(),
312 (const char *)plaintext_password
.data
,
313 plaintext_password
.length
);
314 if (!plaintext_password_string
) {
318 ret
= make_user_info(mem_ctx
,
319 user_info
, smb_name
, smb_name
, client_domain
, client_domain
,
320 get_remote_machine_name(),
324 local_lm_blob
.data
? &local_lm_blob
: NULL
,
325 local_nt_blob
.data
? &local_nt_blob
: NULL
,
327 plaintext_password_string
,
328 AUTH_PASSWORD_PLAIN
);
330 if (plaintext_password_string
) {
331 memset(plaintext_password_string
, '\0', strlen(plaintext_password_string
));
332 talloc_free(plaintext_password_string
);
335 data_blob_free(&local_lm_blob
);
336 return NT_STATUS_IS_OK(ret
) ? true : false;
339 /****************************************************************************
340 Create an auth_usersupplied_data structure
341 ****************************************************************************/
343 NTSTATUS
make_user_info_for_reply_enc(TALLOC_CTX
*mem_ctx
,
344 struct auth_usersupplied_info
**user_info
,
345 const char *smb_name
,
346 const char *client_domain
,
347 const struct tsocket_address
*remote_address
,
348 const struct tsocket_address
*local_address
,
349 const char *service_description
,
350 DATA_BLOB lm_resp
, DATA_BLOB nt_resp
)
352 bool allow_raw
= lp_raw_ntlmv2_auth();
354 if (!allow_raw
&& nt_resp
.length
>= 48) {
356 * NTLMv2_RESPONSE has at least 48 bytes
357 * and should only be supported via NTLMSSP.
359 DEBUG(2,("Rejecting raw NTLMv2 authentication with "
360 "user [%s\\%s] from[%s]\n",
361 client_domain
, smb_name
,
362 tsocket_address_string(remote_address
, mem_ctx
)));
363 return NT_STATUS_INVALID_PARAMETER
;
366 return make_user_info(mem_ctx
,
367 user_info
, smb_name
, smb_name
,
368 client_domain
, client_domain
,
369 get_remote_machine_name(),
373 lm_resp
.data
&& (lm_resp
.length
> 0) ? &lm_resp
: NULL
,
374 nt_resp
.data
&& (nt_resp
.length
> 0) ? &nt_resp
: NULL
,
376 AUTH_PASSWORD_RESPONSE
);
379 /****************************************************************************
380 Create a guest user_info blob, for anonymous authentication.
381 ****************************************************************************/
383 bool make_user_info_guest(TALLOC_CTX
*mem_ctx
,
384 const struct tsocket_address
*remote_address
,
385 const struct tsocket_address
*local_address
,
386 const char *service_description
,
387 struct auth_usersupplied_info
**user_info
)
391 nt_status
= make_user_info(mem_ctx
,
402 AUTH_PASSWORD_RESPONSE
);
404 return NT_STATUS_IS_OK(nt_status
) ? true : false;
407 static NTSTATUS
log_nt_token(struct security_token
*token
)
409 TALLOC_CTX
*frame
= talloc_stackframe();
414 if ((lp_log_nt_token_command(frame
) == NULL
) ||
415 (strlen(lp_log_nt_token_command(frame
)) == 0)) {
420 group_sidstr
= talloc_strdup(frame
, "");
421 for (i
=1; i
<token
->num_sids
; i
++) {
422 group_sidstr
= talloc_asprintf(
423 frame
, "%s %s", group_sidstr
,
424 sid_string_talloc(frame
, &token
->sids
[i
]));
427 command
= talloc_string_sub(
428 frame
, lp_log_nt_token_command(frame
),
429 "%s", sid_string_talloc(frame
, &token
->sids
[0]));
430 command
= talloc_string_sub(frame
, command
, "%t", group_sidstr
);
432 if (command
== NULL
) {
434 return NT_STATUS_NO_MEMORY
;
437 DEBUG(8, ("running command: [%s]\n", command
));
438 if (smbrun(command
, NULL
, NULL
) != 0) {
439 DEBUG(0, ("Could not log NT token\n"));
441 return NT_STATUS_ACCESS_DENIED
;
449 * Create the token to use from server_info->info3 and
450 * server_info->sids (the info3/sam groups). Find the unix gids.
453 NTSTATUS
create_local_token(TALLOC_CTX
*mem_ctx
,
454 const struct auth_serversupplied_info
*server_info
,
455 DATA_BLOB
*session_key
,
456 const char *smb_username
, /* for ->sanitized_username, for %U subs */
457 struct auth_session_info
**session_info_out
)
459 struct security_token
*t
;
462 struct dom_sid tmp_sid
;
463 struct auth_session_info
*session_info
;
467 /* Ensure we can't possible take a code path leading to a
470 return NT_STATUS_LOGON_FAILURE
;
473 session_info
= talloc_zero(mem_ctx
, struct auth_session_info
);
475 return NT_STATUS_NO_MEMORY
;
478 session_info
->unix_token
= talloc_zero(session_info
, struct security_unix_token
);
479 if (!session_info
->unix_token
) {
480 TALLOC_FREE(session_info
);
481 return NT_STATUS_NO_MEMORY
;
484 session_info
->unix_token
->uid
= server_info
->utok
.uid
;
485 session_info
->unix_token
->gid
= server_info
->utok
.gid
;
487 session_info
->unix_info
= talloc_zero(session_info
, struct auth_user_info_unix
);
488 if (!session_info
->unix_info
) {
489 TALLOC_FREE(session_info
);
490 return NT_STATUS_NO_MEMORY
;
493 session_info
->unix_info
->unix_name
= talloc_strdup(session_info
, server_info
->unix_name
);
494 if (!session_info
->unix_info
->unix_name
) {
495 TALLOC_FREE(session_info
);
496 return NT_STATUS_NO_MEMORY
;
499 /* This is a potentially untrusted username for use in %U */
500 alpha_strcpy(tmp
, smb_username
, ". _-$", sizeof(tmp
));
501 session_info
->unix_info
->sanitized_username
=
502 talloc_strdup(session_info
->unix_info
, tmp
);
505 data_blob_free(&session_info
->session_key
);
506 session_info
->session_key
= data_blob_talloc(session_info
,
508 session_key
->length
);
509 if (!session_info
->session_key
.data
&& session_key
->length
) {
510 return NT_STATUS_NO_MEMORY
;
513 session_info
->session_key
= data_blob_talloc( session_info
, server_info
->session_key
.data
,
514 server_info
->session_key
.length
);
517 /* We need to populate session_info->info with the information found in server_info->info3 */
518 status
= make_user_info_SamBaseInfo(session_info
, "", &server_info
->info3
->base
,
519 server_info
->guest
== false,
520 &session_info
->info
);
521 if (!NT_STATUS_IS_OK(status
)) {
522 DEBUG(0, ("conversion of info3 into auth_user_info failed!\n"));
523 TALLOC_FREE(session_info
);
527 if (server_info
->security_token
) {
528 /* Just copy the token, it has already been finalised
529 * (nasty hack to support a cached guest/system session_info
532 session_info
->security_token
= dup_nt_token(session_info
, server_info
->security_token
);
533 if (!session_info
->security_token
) {
534 TALLOC_FREE(session_info
);
535 return NT_STATUS_NO_MEMORY
;
538 session_info
->unix_token
->ngroups
= server_info
->utok
.ngroups
;
539 if (server_info
->utok
.ngroups
!= 0) {
540 session_info
->unix_token
->groups
= (gid_t
*)talloc_memdup(
541 session_info
->unix_token
, server_info
->utok
.groups
,
542 sizeof(gid_t
)*session_info
->unix_token
->ngroups
);
544 session_info
->unix_token
->groups
= NULL
;
547 *session_info_out
= session_info
;
552 * If winbind is not around, we can not make much use of the SIDs the
553 * domain controller provided us with. Likewise if the user name was
554 * mapped to some local unix user.
557 if (((lp_server_role() == ROLE_DOMAIN_MEMBER
) && !winbind_ping()) ||
558 (server_info
->nss_token
)) {
559 char *found_username
= NULL
;
560 status
= create_token_from_username(session_info
,
561 server_info
->unix_name
,
563 &session_info
->unix_token
->uid
,
564 &session_info
->unix_token
->gid
,
566 &session_info
->security_token
);
567 if (NT_STATUS_IS_OK(status
)) {
568 session_info
->unix_info
->unix_name
= found_username
;
571 status
= create_local_nt_token_from_info3(session_info
,
575 &session_info
->security_token
);
578 if (!NT_STATUS_IS_OK(status
)) {
582 /* Convert the SIDs to gids. */
584 session_info
->unix_token
->ngroups
= 0;
585 session_info
->unix_token
->groups
= NULL
;
587 t
= session_info
->security_token
;
589 ids
= talloc_array(talloc_tos(), struct unixid
,
592 return NT_STATUS_NO_MEMORY
;
595 if (!sids_to_unixids(t
->sids
, t
->num_sids
, ids
)) {
597 return NT_STATUS_NO_MEMORY
;
600 for (i
=0; i
<t
->num_sids
; i
++) {
602 if (i
== 0 && ids
[i
].type
!= ID_TYPE_BOTH
) {
606 if (ids
[i
].type
!= ID_TYPE_GID
&&
607 ids
[i
].type
!= ID_TYPE_BOTH
) {
608 DEBUG(10, ("Could not convert SID %s to gid, "
610 sid_string_dbg(&t
->sids
[i
])));
613 if (!add_gid_to_array_unique(session_info
->unix_token
,
615 &session_info
->unix_token
->groups
,
616 &session_info
->unix_token
->ngroups
)) {
617 return NT_STATUS_NO_MEMORY
;
622 * Add the "Unix Group" SID for each gid to catch mapped groups
623 * and their Unix equivalent. This is to solve the backwards
624 * compatibility problem of 'valid users = +ntadmin' where
625 * ntadmin has been paired with "Domain Admins" in the group
626 * mapping table. Otherwise smb.conf would need to be changed
627 * to 'valid user = "Domain Admins"'. --jerry
629 * For consistency we also add the "Unix User" SID,
630 * so that the complete unix token is represented within
634 uid_to_unix_users_sid(session_info
->unix_token
->uid
, &tmp_sid
);
636 add_sid_to_array_unique(session_info
->security_token
, &tmp_sid
,
637 &session_info
->security_token
->sids
,
638 &session_info
->security_token
->num_sids
);
640 for ( i
=0; i
<session_info
->unix_token
->ngroups
; i
++ ) {
641 gid_to_unix_groups_sid(session_info
->unix_token
->groups
[i
], &tmp_sid
);
642 add_sid_to_array_unique(session_info
->security_token
, &tmp_sid
,
643 &session_info
->security_token
->sids
,
644 &session_info
->security_token
->num_sids
);
647 security_token_debug(DBGC_AUTH
, 10, session_info
->security_token
);
648 debug_unix_user_token(DBGC_AUTH
, 10,
649 session_info
->unix_token
->uid
,
650 session_info
->unix_token
->gid
,
651 session_info
->unix_token
->ngroups
,
652 session_info
->unix_token
->groups
);
654 status
= log_nt_token(session_info
->security_token
);
655 if (!NT_STATUS_IS_OK(status
)) {
659 *session_info_out
= session_info
;
663 /***************************************************************************
664 Make (and fill) a server_info struct from a 'struct passwd' by conversion
666 ***************************************************************************/
668 NTSTATUS
make_server_info_pw(TALLOC_CTX
*mem_ctx
,
669 const char *unix_username
,
670 const struct passwd
*pwd
,
671 struct auth_serversupplied_info
**server_info
)
674 TALLOC_CTX
*tmp_ctx
= NULL
;
675 struct auth_serversupplied_info
*result
;
677 tmp_ctx
= talloc_stackframe();
678 if (tmp_ctx
== NULL
) {
679 return NT_STATUS_NO_MEMORY
;
682 result
= make_server_info(tmp_ctx
);
683 if (result
== NULL
) {
684 status
= NT_STATUS_NO_MEMORY
;
688 status
= passwd_to_SamInfo3(result
,
693 if (!NT_STATUS_IS_OK(status
)) {
697 result
->unix_name
= talloc_strdup(result
, unix_username
);
698 if (result
->unix_name
== NULL
) {
699 status
= NT_STATUS_NO_MEMORY
;
703 result
->utok
.uid
= pwd
->pw_uid
;
704 result
->utok
.gid
= pwd
->pw_gid
;
706 *server_info
= talloc_steal(mem_ctx
, result
);
707 status
= NT_STATUS_OK
;
709 talloc_free(tmp_ctx
);
714 static NTSTATUS
get_system_info3(TALLOC_CTX
*mem_ctx
,
715 struct netr_SamInfo3
*info3
)
719 /* Set account name */
720 init_lsa_String(&info3
->base
.account_name
, "SYSTEM");
722 /* Set domain name */
723 init_lsa_StringLarge(&info3
->base
.logon_domain
, "NT AUTHORITY");
726 status
= dom_sid_split_rid(mem_ctx
, &global_sid_System
,
727 &info3
->base
.domain_sid
,
729 if (!NT_STATUS_IS_OK(status
)) {
733 /* Primary gid is the same */
734 info3
->base
.primary_gid
= info3
->base
.rid
;
739 static NTSTATUS
get_guest_info3(TALLOC_CTX
*mem_ctx
,
740 struct netr_SamInfo3
*info3
)
742 const char *guest_account
= lp_guest_account();
743 struct dom_sid domain_sid
;
747 pwd
= Get_Pwnam_alloc(mem_ctx
, guest_account
);
749 DEBUG(0,("SamInfo3_for_guest: Unable to locate guest "
750 "account [%s]!\n", guest_account
));
751 return NT_STATUS_NO_SUCH_USER
;
754 /* Set account name */
755 tmp
= talloc_strdup(mem_ctx
, pwd
->pw_name
);
757 return NT_STATUS_NO_MEMORY
;
759 init_lsa_String(&info3
->base
.account_name
, tmp
);
761 /* Set domain name */
762 tmp
= talloc_strdup(mem_ctx
, get_global_sam_name());
764 return NT_STATUS_NO_MEMORY
;
766 init_lsa_StringLarge(&info3
->base
.logon_domain
, tmp
);
769 sid_copy(&domain_sid
, get_global_sam_sid());
771 info3
->base
.domain_sid
= dom_sid_dup(mem_ctx
, &domain_sid
);
772 if (info3
->base
.domain_sid
== NULL
) {
773 return NT_STATUS_NO_MEMORY
;
777 info3
->base
.rid
= DOMAIN_RID_GUEST
;
780 info3
->base
.primary_gid
= DOMAIN_RID_GUESTS
;
783 info3
->base
.user_flags
= NETLOGON_GUEST
;
789 /***************************************************************************
790 Make (and fill) a user_info struct for a guest login.
791 This *must* succeed for smbd to start. If there is no mapping entry for
792 the guest gid, then create one.
794 The resulting structure is a 'session_info' because
795 create_local_token() has already been called on it. This is quite
796 nasty, as the auth subsystem isn't expect this, but the behavior is
798 ***************************************************************************/
800 static NTSTATUS
make_new_session_info_guest(struct auth_session_info
**session_info
, struct auth_serversupplied_info
**server_info
)
802 const char *guest_account
= lp_guest_account();
803 const char *domain
= lp_netbios_name();
804 struct netr_SamInfo3 info3
;
808 tmp_ctx
= talloc_stackframe();
809 if (tmp_ctx
== NULL
) {
810 return NT_STATUS_NO_MEMORY
;
815 status
= get_guest_info3(tmp_ctx
, &info3
);
816 if (!NT_STATUS_IS_OK(status
)) {
817 DEBUG(0, ("get_guest_info3 failed with %s\n",
822 status
= make_server_info_info3(tmp_ctx
,
827 if (!NT_STATUS_IS_OK(status
)) {
828 DEBUG(0, ("make_server_info_info3 failed with %s\n",
833 (*server_info
)->guest
= true;
835 /* This should not be done here (we should produce a server
836 * info, and later construct a session info from it), but for
837 * now this does not change the previous behavior */
838 status
= create_local_token(tmp_ctx
, *server_info
, NULL
,
839 (*server_info
)->info3
->base
.account_name
.string
,
841 if (!NT_STATUS_IS_OK(status
)) {
842 DEBUG(0, ("create_local_token failed: %s\n",
846 talloc_steal(NULL
, *session_info
);
847 talloc_steal(NULL
, *server_info
);
849 /* annoying, but the Guest really does have a session key, and it is
851 (*session_info
)->session_key
= data_blob_talloc_zero(NULL
, 16);
853 status
= NT_STATUS_OK
;
855 TALLOC_FREE(tmp_ctx
);
859 /***************************************************************************
860 Make (and fill) a auth_session_info struct for a system user login.
861 This *must* succeed for smbd to start.
862 ***************************************************************************/
864 static NTSTATUS
make_new_session_info_system(TALLOC_CTX
*mem_ctx
,
865 struct auth_session_info
**session_info
)
868 struct auth_serversupplied_info
*server_info
;
871 tmp_ctx
= talloc_stackframe();
872 if (tmp_ctx
== NULL
) {
873 return NT_STATUS_NO_MEMORY
;
876 server_info
= make_server_info(tmp_ctx
);
878 status
= NT_STATUS_NO_MEMORY
;
879 DEBUG(0, ("failed making server_info\n"));
883 server_info
->info3
= talloc_zero(server_info
, struct netr_SamInfo3
);
884 if (!server_info
->info3
) {
885 status
= NT_STATUS_NO_MEMORY
;
886 DEBUG(0, ("talloc failed setting info3\n"));
890 status
= get_system_info3(server_info
, server_info
->info3
);
891 if (!NT_STATUS_IS_OK(status
)) {
892 DEBUG(0, ("Failed creating system info3 with %s\n",
897 server_info
->utok
.uid
= sec_initial_uid();
898 server_info
->utok
.gid
= sec_initial_gid();
899 server_info
->unix_name
= talloc_asprintf(server_info
,
900 "NT AUTHORITY%cSYSTEM",
901 *lp_winbind_separator());
903 if (!server_info
->unix_name
) {
904 status
= NT_STATUS_NO_MEMORY
;
905 DEBUG(0, ("talloc_asprintf failed setting unix_name\n"));
909 server_info
->security_token
= talloc_zero(server_info
, struct security_token
);
910 if (!server_info
->security_token
) {
911 status
= NT_STATUS_NO_MEMORY
;
912 DEBUG(0, ("talloc failed setting security token\n"));
916 status
= add_sid_to_array_unique(server_info
->security_token
->sids
,
918 &server_info
->security_token
->sids
,
919 &server_info
->security_token
->num_sids
);
920 if (!NT_STATUS_IS_OK(status
)) {
924 /* SYSTEM has all privilages */
925 server_info
->security_token
->privilege_mask
= ~0;
927 /* Now turn the server_info into a session_info with the full token etc */
928 status
= create_local_token(mem_ctx
, server_info
, NULL
, "SYSTEM", session_info
);
929 talloc_free(server_info
);
931 if (!NT_STATUS_IS_OK(status
)) {
932 DEBUG(0, ("create_local_token failed: %s\n",
937 talloc_steal(mem_ctx
, *session_info
);
940 TALLOC_FREE(tmp_ctx
);
944 /****************************************************************************
945 Fake a auth_session_info just from a username (as a
946 session_info structure, with create_local_token() already called on
948 ****************************************************************************/
950 NTSTATUS
make_session_info_from_username(TALLOC_CTX
*mem_ctx
,
951 const char *username
,
953 struct auth_session_info
**session_info
)
957 struct auth_serversupplied_info
*result
;
960 tmp_ctx
= talloc_stackframe();
961 if (tmp_ctx
== NULL
) {
962 return NT_STATUS_NO_MEMORY
;
965 pwd
= Get_Pwnam_alloc(tmp_ctx
, username
);
967 status
= NT_STATUS_NO_SUCH_USER
;
971 status
= make_server_info_pw(tmp_ctx
, pwd
->pw_name
, pwd
, &result
);
972 if (!NT_STATUS_IS_OK(status
)) {
976 result
->nss_token
= true;
977 result
->guest
= is_guest
;
979 /* Now turn the server_info into a session_info with the full token etc */
980 status
= create_local_token(mem_ctx
,
987 talloc_free(tmp_ctx
);
992 /* This function MUST only used to create the cached server_info for
995 * This is a lossy conversion. Variables known to be lost so far
998 * - nss_token (not needed because the only read doesn't happen
999 * for the GUEST user, as this routine populates ->security_token
1001 * - extra (not needed because the guest account must have valid RIDs per the output of get_guest_info3())
1003 * - The 'server_info' parameter allows the missing 'info3' to be copied across.
1005 static struct auth_serversupplied_info
*copy_session_info_serverinfo_guest(TALLOC_CTX
*mem_ctx
,
1006 const struct auth_session_info
*src
,
1007 struct auth_serversupplied_info
*server_info
)
1009 struct auth_serversupplied_info
*dst
;
1011 dst
= make_server_info(mem_ctx
);
1016 /* This element must be provided to convert back to an auth_serversupplied_info */
1017 SMB_ASSERT(src
->unix_info
);
1020 dst
->system
= false;
1022 /* This element must be provided to convert back to an
1023 * auth_serversupplied_info. This needs to be from the
1024 * auth_session_info because the group values in particular
1025 * may change during create_local_token() processing */
1026 SMB_ASSERT(src
->unix_token
);
1027 dst
->utok
.uid
= src
->unix_token
->uid
;
1028 dst
->utok
.gid
= src
->unix_token
->gid
;
1029 dst
->utok
.ngroups
= src
->unix_token
->ngroups
;
1030 if (src
->unix_token
->ngroups
!= 0) {
1031 dst
->utok
.groups
= (gid_t
*)talloc_memdup(
1032 dst
, src
->unix_token
->groups
,
1033 sizeof(gid_t
)*dst
->utok
.ngroups
);
1035 dst
->utok
.groups
= NULL
;
1038 /* We must have a security_token as otherwise the lossy
1039 * conversion without nss_token would cause create_local_token
1040 * to take the wrong path */
1041 SMB_ASSERT(src
->security_token
);
1043 dst
->security_token
= dup_nt_token(dst
, src
->security_token
);
1044 if (!dst
->security_token
) {
1049 dst
->session_key
= data_blob_talloc( dst
, src
->session_key
.data
,
1050 src
->session_key
.length
);
1052 /* This is OK because this functions is only used for the
1053 * GUEST account, which has all-zero keys for both values */
1054 dst
->lm_session_key
= data_blob_talloc(dst
, src
->session_key
.data
,
1055 src
->session_key
.length
);
1057 dst
->info3
= copy_netr_SamInfo3(dst
, server_info
->info3
);
1063 dst
->unix_name
= talloc_strdup(dst
, src
->unix_info
->unix_name
);
1064 if (!dst
->unix_name
) {
1072 struct auth_session_info
*copy_session_info(TALLOC_CTX
*mem_ctx
,
1073 const struct auth_session_info
*src
)
1075 struct auth_session_info
*dst
;
1077 enum ndr_err_code ndr_err
;
1079 ndr_err
= ndr_push_struct_blob(
1080 &blob
, talloc_tos(), src
,
1081 (ndr_push_flags_fn_t
)ndr_push_auth_session_info
);
1082 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1083 DEBUG(0, ("copy_session_info(): ndr_push_auth_session_info failed: "
1084 "%s\n", ndr_errstr(ndr_err
)));
1088 dst
= talloc(mem_ctx
, struct auth_session_info
);
1090 DEBUG(0, ("talloc failed\n"));
1091 TALLOC_FREE(blob
.data
);
1095 ndr_err
= ndr_pull_struct_blob(
1097 (ndr_pull_flags_fn_t
)ndr_pull_auth_session_info
);
1098 TALLOC_FREE(blob
.data
);
1100 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1101 DEBUG(0, ("copy_session_info(): ndr_pull_auth_session_info failed: "
1102 "%s\n", ndr_errstr(ndr_err
)));
1111 * Set a new session key. Used in the rpc server where we have to override the
1112 * SMB level session key with SystemLibraryDTC
1115 bool session_info_set_session_key(struct auth_session_info
*info
,
1116 DATA_BLOB session_key
)
1118 TALLOC_FREE(info
->session_key
.data
);
1120 info
->session_key
= data_blob_talloc(
1121 info
, session_key
.data
, session_key
.length
);
1123 return (info
->session_key
.data
!= NULL
);
1126 static struct auth_session_info
*guest_info
= NULL
;
1128 static struct auth_serversupplied_info
*guest_server_info
= NULL
;
1130 bool init_guest_info(void)
1132 if (guest_info
!= NULL
)
1135 return NT_STATUS_IS_OK(make_new_session_info_guest(&guest_info
, &guest_server_info
));
1138 NTSTATUS
make_server_info_guest(TALLOC_CTX
*mem_ctx
,
1139 struct auth_serversupplied_info
**server_info
)
1141 /* This is trickier than it would appear to need to be because
1142 * we are trying to avoid certain costly operations when the
1143 * structure is converted to a 'auth_session_info' again in
1144 * create_local_token() */
1145 *server_info
= copy_session_info_serverinfo_guest(mem_ctx
, guest_info
, guest_server_info
);
1146 return (*server_info
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
1149 NTSTATUS
make_session_info_guest(TALLOC_CTX
*mem_ctx
,
1150 struct auth_session_info
**session_info
)
1152 *session_info
= copy_session_info(mem_ctx
, guest_info
);
1153 return (*session_info
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
1156 static struct auth_session_info
*system_info
= NULL
;
1158 NTSTATUS
init_system_session_info(void)
1160 if (system_info
!= NULL
)
1161 return NT_STATUS_OK
;
1163 return make_new_session_info_system(NULL
, &system_info
);
1166 NTSTATUS
make_session_info_system(TALLOC_CTX
*mem_ctx
,
1167 struct auth_session_info
**session_info
)
1169 if (system_info
== NULL
) return NT_STATUS_UNSUCCESSFUL
;
1170 *session_info
= copy_session_info(mem_ctx
, system_info
);
1171 return (*session_info
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
1174 const struct auth_session_info
*get_session_info_system(void)
1179 /***************************************************************************
1180 Purely internal function for make_server_info_info3
1181 ***************************************************************************/
1183 static NTSTATUS
check_account(TALLOC_CTX
*mem_ctx
, const char *domain
,
1184 const char *username
, char **found_username
,
1185 struct passwd
**pwd
,
1186 bool *username_was_mapped
)
1188 char *orig_dom_user
= NULL
;
1189 char *dom_user
= NULL
;
1190 char *lower_username
= NULL
;
1191 char *real_username
= NULL
;
1192 struct passwd
*passwd
;
1194 lower_username
= talloc_strdup(mem_ctx
, username
);
1195 if (!lower_username
) {
1196 return NT_STATUS_NO_MEMORY
;
1198 if (!strlower_m( lower_username
)) {
1199 return NT_STATUS_INVALID_PARAMETER
;
1202 orig_dom_user
= talloc_asprintf(mem_ctx
,
1205 *lp_winbind_separator(),
1207 if (!orig_dom_user
) {
1208 return NT_STATUS_NO_MEMORY
;
1211 /* Get the passwd struct. Try to create the account if necessary. */
1213 *username_was_mapped
= map_username(mem_ctx
, orig_dom_user
, &dom_user
);
1215 return NT_STATUS_NO_MEMORY
;
1218 passwd
= smb_getpwnam(mem_ctx
, dom_user
, &real_username
, true );
1220 DEBUG(3, ("Failed to find authenticated user %s via "
1221 "getpwnam(), denying access.\n", dom_user
));
1222 return NT_STATUS_NO_SUCH_USER
;
1225 if (!real_username
) {
1226 return NT_STATUS_NO_MEMORY
;
1231 /* This is pointless -- there is no support for differing
1232 unix and windows names. Make sure to always store the
1233 one we actually looked up and succeeded. Have I mentioned
1234 why I hate the 'winbind use default domain' parameter?
1237 *found_username
= talloc_strdup( mem_ctx
, real_username
);
1239 return NT_STATUS_OK
;
1242 /****************************************************************************
1243 Wrapper to allow the getpwnam() call to strip the domain name and
1244 try again in case a local UNIX user is already there. Also run through
1245 the username if we fallback to the username only.
1246 ****************************************************************************/
1248 struct passwd
*smb_getpwnam( TALLOC_CTX
*mem_ctx
, const char *domuser
,
1249 char **p_save_username
, bool create
)
1251 struct passwd
*pw
= NULL
;
1253 char *username
= NULL
;
1255 /* we only save a copy of the username it has been mangled
1256 by winbindd use default domain */
1257 *p_save_username
= NULL
;
1259 /* don't call map_username() here since it has to be done higher
1260 up the stack so we don't call it multiple times */
1262 username
= talloc_strdup(mem_ctx
, domuser
);
1267 p
= strchr_m( username
, *lp_winbind_separator() );
1269 /* code for a DOMAIN\user string */
1272 pw
= Get_Pwnam_alloc( mem_ctx
, domuser
);
1274 /* make sure we get the case of the username correct */
1275 /* work around 'winbind use default domain = yes' */
1277 if ( lp_winbind_use_default_domain() &&
1278 !strchr_m( pw
->pw_name
, *lp_winbind_separator() ) ) {
1281 /* split the domain and username into 2 strings */
1285 *p_save_username
= talloc_asprintf(mem_ctx
,
1288 *lp_winbind_separator(),
1290 if (!*p_save_username
) {
1295 *p_save_username
= talloc_strdup(mem_ctx
, pw
->pw_name
);
1302 /* setup for lookup of just the username */
1303 /* remember that p and username are overlapping memory */
1306 username
= talloc_strdup(mem_ctx
, p
);
1312 /* just lookup a plain username */
1314 pw
= Get_Pwnam_alloc(mem_ctx
, username
);
1316 /* Create local user if requested but only if winbindd
1317 is not running. We need to protect against cases
1318 where winbindd is failing and then prematurely
1319 creating users in /etc/passwd */
1321 if ( !pw
&& create
&& !winbind_ping() ) {
1322 /* Don't add a machine account. */
1323 if (username
[strlen(username
)-1] == '$')
1326 _smb_create_user(NULL
, username
, NULL
);
1327 pw
= Get_Pwnam_alloc(mem_ctx
, username
);
1330 /* one last check for a valid passwd struct */
1333 *p_save_username
= talloc_strdup(mem_ctx
, pw
->pw_name
);
1338 /***************************************************************************
1339 Make a server_info struct from the info3 returned by a domain logon
1340 ***************************************************************************/
1342 NTSTATUS
make_server_info_info3(TALLOC_CTX
*mem_ctx
,
1343 const char *sent_nt_username
,
1345 struct auth_serversupplied_info
**server_info
,
1346 const struct netr_SamInfo3
*info3
)
1348 NTSTATUS nt_status
= NT_STATUS_OK
;
1349 char *found_username
= NULL
;
1350 const char *nt_domain
;
1351 const char *nt_username
;
1352 struct dom_sid user_sid
;
1353 struct dom_sid group_sid
;
1354 bool username_was_mapped
;
1356 struct auth_serversupplied_info
*result
;
1357 TALLOC_CTX
*tmp_ctx
= talloc_stackframe();
1360 Here is where we should check the list of
1361 trusted domains, and verify that the SID
1365 if (!sid_compose(&user_sid
, info3
->base
.domain_sid
, info3
->base
.rid
)) {
1366 nt_status
= NT_STATUS_INVALID_PARAMETER
;
1370 if (!sid_compose(&group_sid
, info3
->base
.domain_sid
,
1371 info3
->base
.primary_gid
)) {
1372 nt_status
= NT_STATUS_INVALID_PARAMETER
;
1376 nt_username
= talloc_strdup(tmp_ctx
, info3
->base
.account_name
.string
);
1378 /* If the server didn't give us one, just use the one we sent
1380 nt_username
= sent_nt_username
;
1383 nt_domain
= talloc_strdup(mem_ctx
, info3
->base
.logon_domain
.string
);
1385 /* If the server didn't give us one, just use the one we sent
1390 /* If getpwnam() fails try the add user script (2.2.x behavior).
1392 We use the _unmapped_ username here in an attempt to provide
1393 consistent username mapping behavior between kerberos and NTLM[SSP]
1394 authentication in domain mode security. I.E. Username mapping
1395 should be applied to the fully qualified username
1396 (e.g. DOMAIN\user) and not just the login name. Yes this means we
1397 called map_username() unnecessarily in make_user_info_map() but
1398 that is how the current code is designed. Making the change here
1399 is the least disruptive place. -- jerry */
1401 /* this call will try to create the user if necessary */
1403 nt_status
= check_account(tmp_ctx
,
1408 &username_was_mapped
);
1410 if (!NT_STATUS_IS_OK(nt_status
)) {
1411 /* Handle 'map to guest = Bad Uid */
1412 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_NO_SUCH_USER
) &&
1413 (lp_security() == SEC_ADS
|| lp_security() == SEC_DOMAIN
) &&
1414 lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID
) {
1415 DBG_NOTICE("Try to map %s to guest account",
1417 nt_status
= make_server_info_guest(tmp_ctx
, &result
);
1418 if (NT_STATUS_IS_OK(nt_status
)) {
1419 *server_info
= talloc_move(mem_ctx
, &result
);
1425 result
= make_server_info(tmp_ctx
);
1426 if (result
== NULL
) {
1427 DEBUG(4, ("make_server_info failed!\n"));
1428 nt_status
= NT_STATUS_NO_MEMORY
;
1432 result
->unix_name
= talloc_strdup(result
, found_username
);
1434 /* copy in the info3 */
1435 result
->info3
= copy_netr_SamInfo3(result
, info3
);
1436 if (result
->info3
== NULL
) {
1437 nt_status
= NT_STATUS_NO_MEMORY
;
1441 /* Fill in the unix info we found on the way */
1443 result
->utok
.uid
= pwd
->pw_uid
;
1444 result
->utok
.gid
= pwd
->pw_gid
;
1446 /* ensure we are never given NULL session keys */
1448 if (all_zero(info3
->base
.key
.key
, sizeof(info3
->base
.key
.key
))) {
1449 result
->session_key
= data_blob_null
;
1451 result
->session_key
= data_blob_talloc(
1452 result
, info3
->base
.key
.key
,
1453 sizeof(info3
->base
.key
.key
));
1456 if (all_zero(info3
->base
.LMSessKey
.key
,
1457 sizeof(info3
->base
.LMSessKey
.key
))) {
1458 result
->lm_session_key
= data_blob_null
;
1460 result
->lm_session_key
= data_blob_talloc(
1461 result
, info3
->base
.LMSessKey
.key
,
1462 sizeof(info3
->base
.LMSessKey
.key
));
1465 result
->nss_token
|= username_was_mapped
;
1467 result
->guest
= (info3
->base
.user_flags
& NETLOGON_GUEST
);
1469 *server_info
= talloc_move(mem_ctx
, &result
);
1471 nt_status
= NT_STATUS_OK
;
1473 talloc_free(tmp_ctx
);
1478 /*****************************************************************************
1479 Make a server_info struct from the wbcAuthUserInfo returned by a domain logon
1480 ******************************************************************************/
1482 NTSTATUS
make_server_info_wbcAuthUserInfo(TALLOC_CTX
*mem_ctx
,
1483 const char *sent_nt_username
,
1485 const struct wbcAuthUserInfo
*info
,
1486 struct auth_serversupplied_info
**server_info
)
1488 struct netr_SamInfo3 info3
;
1489 struct netr_SamInfo6
*info6
;
1491 info6
= wbcAuthUserInfo_to_netr_SamInfo6(mem_ctx
, info
);
1493 return NT_STATUS_NO_MEMORY
;
1496 info3
.base
= info6
->base
;
1497 info3
.sidcount
= info6
->sidcount
;
1498 info3
.sids
= info6
->sids
;
1500 return make_server_info_info3(mem_ctx
,
1501 sent_nt_username
, domain
,
1502 server_info
, &info3
);
1506 * Verify whether or not given domain is trusted.
1508 * @param domain_name name of the domain to be verified
1509 * @return true if domain is one of the trusted ones or
1510 * false if otherwise
1513 bool is_trusted_domain(const char* dom_name
)
1515 struct dom_sid trustdom_sid
;
1518 /* no trusted domains for a standalone server */
1520 if ( lp_server_role() == ROLE_STANDALONE
)
1523 if (dom_name
== NULL
|| dom_name
[0] == '\0') {
1527 if (strequal(dom_name
, get_global_sam_name())) {
1531 /* if we are a DC, then check for a direct trust relationships */
1535 DEBUG (5,("is_trusted_domain: Checking for domain trust with "
1536 "[%s]\n", dom_name
));
1537 ret
= pdb_get_trusteddom_pw(dom_name
, NULL
, NULL
, NULL
);
1545 /* If winbind is around, ask it */
1547 result
= wb_is_trusted_domain(dom_name
);
1549 if (result
== WBC_ERR_SUCCESS
) {
1553 if (result
== WBC_ERR_DOMAIN_NOT_FOUND
) {
1554 /* winbind could not find the domain */
1558 DEBUG(10, ("wb_is_trusted_domain returned error: %s\n",
1559 wbcErrorString(result
)));
1561 /* The only other possible result is that winbind is not up
1562 and running. We need to update the trustdom_cache
1565 update_trustdom_cache();
1568 /* now the trustdom cache should be available a DC could still
1569 * have a transitive trust so fall back to the cache of trusted
1570 * domains (like a domain member would use */
1572 if ( trustdom_cache_fetch(dom_name
, &trustdom_sid
) ) {
1582 on a logon error possibly map the error to success if "map to guest"
1585 NTSTATUS
do_map_to_guest_server_info(TALLOC_CTX
*mem_ctx
,
1589 struct auth_serversupplied_info
**server_info
)
1591 user
= user
? user
: "";
1592 domain
= domain
? domain
: "";
1594 if (NT_STATUS_EQUAL(status
, NT_STATUS_NO_SUCH_USER
)) {
1595 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER
) ||
1596 (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD
)) {
1597 DEBUG(3,("No such user %s [%s] - using guest account\n",
1599 return make_server_info_guest(mem_ctx
, server_info
);
1601 } else if (NT_STATUS_EQUAL(status
, NT_STATUS_WRONG_PASSWORD
)) {
1602 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD
) {
1603 DEBUG(3,("Registered username %s for guest access\n",
1605 return make_server_info_guest(mem_ctx
, server_info
);
1613 Extract session key from a session info and return it in a blob
1614 if intent is KEY_USE_16BYTES, truncate it to 16 bytes
1616 See sections 3.2.4.15 and 3.3.4.2 of MS-SMB
1617 Also see https://lists.samba.org/archive/cifs-protocol/2012-January/002265.html for details
1619 Note that returned session_key is referencing the original key, it is supposed to be
1620 short-lived. If original session_info->session_key is gone, the reference will be broken.
1622 NTSTATUS
session_extract_session_key(const struct auth_session_info
*session_info
, DATA_BLOB
*session_key
, enum session_key_use_intent intent
)
1625 if (session_key
== NULL
|| session_info
== NULL
) {
1626 return NT_STATUS_INVALID_PARAMETER
;
1629 if (session_info
->session_key
.length
== 0) {
1630 return NT_STATUS_NO_USER_SESSION_KEY
;
1633 *session_key
= session_info
->session_key
;
1634 if (intent
== KEY_USE_16BYTES
) {
1635 session_key
->length
= MIN(session_info
->session_key
.length
, 16);
1637 return NT_STATUS_OK
;