4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
26 #include <sys/types.h>
28 #include <sys/priv_names.h>
29 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <smbsrv/smb_idmap.h>
32 #include <smbsrv/smb_kproto.h>
33 #include <smbsrv/smb_token.h>
35 static int smb_authenticate(smb_request_t
*, smb_arg_sessionsetup_t
*);
36 static int smb_authenticate_core(smb_request_t
*, smb_arg_sessionsetup_t
*);
37 static uint32_t smb_priv_xlate(smb_token_t
*);
39 static void smb_cred_set_sid(smb_id_t
*id
, ksid_t
*ksid
);
40 static ksidlist_t
*smb_cred_set_sidlist(smb_ids_t
*token_grps
);
44 * In NTLM 0.12, the padding between the Native OS and Native LM is a bit
45 * strange. On NT4.0, there is a 2 byte pad between the OS (Windows NT 1381)
46 * and LM (Windows NT 4.0). On Windows 2000, there is no padding between
47 * the OS (Windows 2000 2195) and LM (Windows 2000 5.0).
48 * If the padding is removed from the decode string the NT4.0 LM comes out
49 * as an empty string. So if the client's native OS is Win NT we consider
50 * the padding otherwise we don't.
52 * For Pre-NTLM 0.12, despite the CIFS/1.0 spec, the user and domain are
53 * not always present in the message. We try to get the account name and
54 * the primary domain but we don't care about the the native OS or native
57 * If the Native LM cannot be determined, default to Windows NT.
60 smb_pre_session_setup_andx(smb_request_t
*sr
)
62 smb_arg_sessionsetup_t
*sinfo
;
65 uint32_t junk_sesskey
;
70 sinfo
= smb_srm_zalloc(sr
, sizeof (smb_arg_sessionsetup_t
));
71 sr
->sr_ssetup
= sinfo
;
73 if (sr
->session
->dialect
>= NT_LM_0_12
) {
74 rc
= smbsr_decode_vwv(sr
, "b.wwwwlww4.l", &sr
->andx_com
,
75 &sr
->andx_off
, &maxbufsize
,
76 &sinfo
->ssi_maxmpxcount
, &vcnumber
,
77 &junk_sesskey
, &sinfo
->ssi_cipwlen
,
78 &sinfo
->ssi_cspwlen
, &sinfo
->ssi_capabilities
);
80 goto pre_session_setup_andx_done
;
82 sinfo
->ssi_cipwd
= smb_srm_zalloc(sr
, sinfo
->ssi_cipwlen
+ 1);
83 sinfo
->ssi_cspwd
= smb_srm_zalloc(sr
, sinfo
->ssi_cspwlen
+ 1);
85 rc
= smbsr_decode_data(sr
, "%#c#cuuu",
87 sinfo
->ssi_cipwlen
, sinfo
->ssi_cipwd
,
88 sinfo
->ssi_cspwlen
, sinfo
->ssi_cspwd
,
93 goto pre_session_setup_andx_done
;
95 sinfo
->ssi_cipwd
[sinfo
->ssi_cipwlen
] = 0;
96 sinfo
->ssi_cspwd
[sinfo
->ssi_cspwlen
] = 0;
98 sr
->session
->native_os
= smbnative_os_value(native_os
);
100 if (sr
->session
->native_os
== NATIVE_OS_WINNT
)
101 rc
= smbsr_decode_data(sr
, "%,u", sr
, &native_lm
);
103 rc
= smbsr_decode_data(sr
, "%u", sr
, &native_lm
);
105 if (rc
!= 0 || native_lm
== NULL
)
106 native_lm
= "NT LAN Manager 4.0";
108 sr
->session
->native_lm
= smbnative_lm_value(native_lm
);
110 rc
= smbsr_decode_vwv(sr
, "b.wwwwlw4.", &sr
->andx_com
,
111 &sr
->andx_off
, &maxbufsize
,
112 &sinfo
->ssi_maxmpxcount
, &vcnumber
,
113 &junk_sesskey
, &sinfo
->ssi_cipwlen
);
115 goto pre_session_setup_andx_done
;
117 sinfo
->ssi_cipwd
= smb_srm_zalloc(sr
, sinfo
->ssi_cipwlen
+ 1);
118 rc
= smbsr_decode_data(sr
, "%#c", sr
, sinfo
->ssi_cipwlen
,
121 goto pre_session_setup_andx_done
;
123 sinfo
->ssi_cipwd
[sinfo
->ssi_cipwlen
] = 0;
125 if (smbsr_decode_data(sr
, "%u", sr
, &sinfo
->ssi_user
) != 0)
126 sinfo
->ssi_user
= "";
128 if (smbsr_decode_data(sr
, "%u", sr
, &sinfo
->ssi_domain
) != 0)
129 sinfo
->ssi_domain
= "";
131 native_lm
= "NT LAN Manager 4.0";
132 sr
->session
->native_os
= NATIVE_OS_WINNT
;
133 sr
->session
->native_lm
= smbnative_lm_value(native_lm
);
136 sr
->session
->vcnumber
= vcnumber
;
137 sr
->session
->smb_msg_size
= maxbufsize
;
139 pre_session_setup_andx_done
:
140 DTRACE_SMB_2(op__SessionSetupX__start
, smb_request_t
*, sr
,
141 smb_arg_sessionsetup_t
, sinfo
);
142 return ((rc
== 0) ? SDRC_SUCCESS
: SDRC_ERROR
);
146 smb_post_session_setup_andx(smb_request_t
*sr
)
148 smb_arg_sessionsetup_t
*sinfo
= sr
->sr_ssetup
;
150 DTRACE_SMB_2(op__SessionSetupX__done
, smb_request_t
*, sr
,
151 smb_arg_sessionsetup_t
, sinfo
);
153 if (sinfo
->ssi_cipwd
!= NULL
)
154 bzero(sinfo
->ssi_cipwd
, sinfo
->ssi_cipwlen
+ 1);
156 if (sinfo
->ssi_cspwd
!= NULL
)
157 bzero(sinfo
->ssi_cspwd
, sinfo
->ssi_cspwlen
+ 1);
161 * If signing has not already been enabled on this session check to see if
162 * it should be enabled. The first authenticated logon provides the MAC
163 * key and sequence numbers for signing all subsequent sessions on the same
166 * NT systems use different native OS and native LanMan values dependent on
167 * whether they are acting as a client or a server. NT 4.0 server responds
168 * with the following values:
170 * NativeOS: Windows NT 4.0
171 * NativeLM: NT LAN Manager 4.0
174 smb_com_session_setup_andx(smb_request_t
*sr
)
176 smb_arg_sessionsetup_t
*sinfo
= sr
->sr_ssetup
;
179 if (smb_authenticate(sr
, sinfo
) != 0)
182 if (sr
->session
->native_lm
== NATIVE_LM_WIN2000
)
183 sinfo
->ssi_capabilities
|= CAP_LARGE_FILES
|
184 CAP_LARGE_READX
| CAP_LARGE_WRITEX
;
186 if (!smb_oplock_levelII
)
187 sr
->session
->capabilities
&= ~CAP_LEVEL_II_OPLOCKS
;
189 sr
->session
->capabilities
= sinfo
->ssi_capabilities
;
191 rc
= smbsr_encode_result(sr
, 3, VAR_BCC
, "bb.www%uuu",
195 sinfo
->ssi_guest
? 1 : 0,
198 smbnative_os_str(&sr
->sr_cfg
->skc_version
),
199 smbnative_lm_str(&sr
->sr_cfg
->skc_version
),
200 sr
->sr_cfg
->skc_nbdomain
);
202 return ((rc
== 0) ? SDRC_SUCCESS
: SDRC_ERROR
);
206 smb_authenticate(smb_request_t
*sr
, smb_arg_sessionsetup_t
*sinfo
)
209 smb_server_t
*sv
= sr
->sr_server
;
211 if (smb_threshold_enter(&sv
->sv_ssetup_ct
) != 0) {
212 smbsr_error(sr
, RPC_NT_SERVER_TOO_BUSY
, 0, 0);
216 rc
= smb_authenticate_core(sr
, sinfo
);
217 smb_threshold_exit(&sv
->sv_ssetup_ct
);
222 * Authenticate a user. If the user has already been authenticated on
223 * this session, we can simply dup the user and return.
225 * Otherwise, the user information is passed to smbd for authentication.
226 * If smbd can authenticate the user an access token is returned and we
227 * generate a cred and new user based on the token.
230 smb_authenticate_core(smb_request_t
*sr
, smb_arg_sessionsetup_t
*sinfo
)
232 char *hostname
= sr
->sr_cfg
->skc_hostname
;
233 int security
= sr
->sr_cfg
->skc_secmode
;
234 smb_token_t
*token
= NULL
;
235 smb_user_t
*user
= NULL
;
236 smb_logon_t user_info
;
237 boolean_t need_lookup
= B_FALSE
;
243 bzero(&user_info
, sizeof (smb_logon_t
));
244 user_info
.lg_e_domain
= sinfo
->ssi_domain
;
246 if ((*sinfo
->ssi_user
== '\0') &&
247 (sinfo
->ssi_cspwlen
== 0) &&
248 (sinfo
->ssi_cipwlen
== 0 ||
249 (sinfo
->ssi_cipwlen
== 1 && *sinfo
->ssi_cipwd
== '\0'))) {
250 user_info
.lg_e_username
= "anonymous";
251 user_info
.lg_flags
|= SMB_ATF_ANON
;
253 user_info
.lg_e_username
= sinfo
->ssi_user
;
257 * Handle user@domain format. We need to retain the original
258 * data as this is important in some forms of authentication.
260 if (*sinfo
->ssi_domain
== '\0') {
261 buf
= smb_srm_strdup(sr
, sinfo
->ssi_user
);
262 if ((p
= strchr(buf
, '@')) != NULL
) {
264 user_info
.lg_e_username
= buf
;
265 user_info
.lg_e_domain
= p
+ 1;
270 * If no domain name has been provided in domain mode we cannot
271 * determine if this is a local user or a domain user without
272 * obtaining an access token. So we postpone the lookup until
273 * after authentication.
275 if (security
== SMB_SECMODE_WORKGRP
) {
276 user
= smb_session_dup_user(sr
->session
, hostname
,
277 user_info
.lg_e_username
);
278 } else if (*user_info
.lg_e_domain
!= '\0') {
279 user
= smb_session_dup_user(sr
->session
, user_info
.lg_e_domain
,
280 user_info
.lg_e_username
);
282 need_lookup
= B_TRUE
;
286 sinfo
->ssi_guest
= SMB_USER_IS_GUEST(user
);
287 sr
->user_cr
= user
->u_cred
;
288 sr
->smb_uid
= user
->u_uid
;
293 user_info
.lg_level
= NETR_NETWORK_LOGON
;
294 user_info
.lg_domain
= sinfo
->ssi_domain
;
295 user_info
.lg_username
= sinfo
->ssi_user
;
296 user_info
.lg_workstation
= sr
->session
->workstation
;
297 user_info
.lg_clnt_ipaddr
= sr
->session
->ipaddr
;
298 user_info
.lg_local_ipaddr
= sr
->session
->local_ipaddr
;
299 user_info
.lg_local_port
= sr
->session
->s_local_port
;
300 user_info
.lg_challenge_key
.val
= sr
->session
->challenge_key
;
301 user_info
.lg_challenge_key
.len
= sr
->session
->challenge_len
;
302 user_info
.lg_nt_password
.val
= sinfo
->ssi_cspwd
;
303 user_info
.lg_nt_password
.len
= sinfo
->ssi_cspwlen
;
304 user_info
.lg_lm_password
.val
= sinfo
->ssi_cipwd
;
305 user_info
.lg_lm_password
.len
= sinfo
->ssi_cipwlen
;
306 user_info
.lg_native_os
= sr
->session
->native_os
;
307 user_info
.lg_native_lm
= sr
->session
->native_lm
;
309 DTRACE_PROBE1(smb__sessionsetup__clntinfo
, smb_logon_t
*, &user_info
);
311 if ((token
= smb_get_token(sr
->session
, &user_info
)) == NULL
) {
312 smbsr_error(sr
, 0, ERRSRV
, ERRbadpw
);
317 user
= smb_session_dup_user(sr
->session
,
318 token
->tkn_domain_name
, token
->tkn_account_name
);
320 sinfo
->ssi_guest
= SMB_USER_IS_GUEST(user
);
321 sr
->user_cr
= user
->u_cred
;
322 sr
->smb_uid
= user
->u_uid
;
324 smb_token_free(token
);
329 if ((cr
= smb_cred_create(token
)) == NULL
) {
330 smb_token_free(token
);
331 smbsr_error(sr
, 0, ERRDOS
, ERROR_INVALID_HANDLE
);
335 privileges
= smb_priv_xlate(token
);
337 user
= smb_user_login(sr
->session
, cr
,
338 token
->tkn_domain_name
, token
->tkn_account_name
,
339 token
->tkn_flags
, privileges
, token
->tkn_audit_sid
);
343 * Save the session key, and (maybe) enable signing,
344 * but only for real logon (not ANON or GUEST).
346 if ((token
->tkn_flags
& (SMB_ATF_GUEST
| SMB_ATF_ANON
)) == 0)
347 (void) smb_sign_begin(sr
, token
);
349 smb_token_free(token
);
352 smbsr_error(sr
, 0, ERRDOS
, ERROR_INVALID_HANDLE
);
356 sinfo
->ssi_guest
= SMB_USER_IS_GUEST(user
);
357 sr
->user_cr
= user
->u_cred
;
358 sr
->smb_uid
= user
->u_uid
;
365 * Allocate a Solaris cred and initialize it based on the access token.
367 * If the user can be mapped to a non-ephemeral ID, the cred gid is set
368 * to the Solaris user's primary group.
370 * If the mapped UID is ephemeral, or the primary group could not be
371 * obtained, the cred gid is set to whatever Solaris group is mapped
372 * to the token's primary group.
375 smb_cred_create(smb_token_t
*token
)
378 ksidlist_t
*ksidlist
= NULL
;
379 smb_posix_grps_t
*posix_grps
;
384 ASSERT(token
->tkn_posix_grps
);
385 posix_grps
= token
->tkn_posix_grps
;
390 if (!IDMAP_ID_IS_EPHEMERAL(token
->tkn_user
.i_id
) &&
391 (posix_grps
->pg_ngrps
!= 0)) {
392 gid
= posix_grps
->pg_grps
[0];
394 gid
= token
->tkn_primary_grp
.i_id
;
397 if (crsetugid(cr
, token
->tkn_user
.i_id
, gid
) != 0) {
402 if (crsetgroups(cr
, posix_grps
->pg_ngrps
, posix_grps
->pg_grps
) != 0) {
407 smb_cred_set_sid(&token
->tkn_user
, &ksid
);
408 crsetsid(cr
, &ksid
, KSID_USER
);
409 smb_cred_set_sid(&token
->tkn_primary_grp
, &ksid
);
410 crsetsid(cr
, &ksid
, KSID_GROUP
);
411 smb_cred_set_sid(&token
->tkn_owner
, &ksid
);
412 crsetsid(cr
, &ksid
, KSID_OWNER
);
413 ksidlist
= smb_cred_set_sidlist(&token
->tkn_win_grps
);
414 crsetsidlist(cr
, ksidlist
);
417 * In the AD world, "take ownership privilege" is very much
418 * like having Unix "root" privileges. It's normally given
419 * to members of the "Administrators" group, which normally
420 * includes the the local Administrator (like root) and when
421 * joined to a domain, "Domain Admins".
423 if (smb_token_query_privilege(token
, SE_TAKE_OWNERSHIP_LUID
)) {
427 PRIV_FILE_DAC_SEARCH
,
437 * Initialize the ksid based on the given smb_id_t.
440 smb_cred_set_sid(smb_id_t
*id
, ksid_t
*ksid
)
442 char sidstr
[SMB_SID_STRSZ
];
448 ksid
->ks_id
= id
->i_id
;
449 smb_sid_tostr(id
->i_sid
, sidstr
);
450 rc
= smb_sid_splitstr(sidstr
, &ksid
->ks_rid
);
453 ksid
->ks_attr
= id
->i_attrs
;
454 ksid
->ks_domain
= ksid_lookupdomain(sidstr
);
458 * Allocate and initialize the ksidlist based on the access token group list.
461 smb_cred_set_sidlist(smb_ids_t
*token_grps
)
466 lp
= kmem_zalloc(KSIDLIST_MEM(token_grps
->i_cnt
), KM_SLEEP
);
468 lp
->ksl_nsid
= token_grps
->i_cnt
;
471 for (i
= 0; i
< lp
->ksl_nsid
; i
++) {
472 smb_cred_set_sid(&token_grps
->i_ids
[i
], &lp
->ksl_sids
[i
]);
473 if (lp
->ksl_sids
[i
].ks_id
> IDMAP_WK__MAX_GID
)
482 * Convert access token privileges to local definitions.
485 smb_priv_xlate(smb_token_t
*token
)
487 uint32_t privileges
= 0;
489 if (smb_token_query_privilege(token
, SE_BACKUP_LUID
))
490 privileges
|= SMB_USER_PRIV_BACKUP
;
492 if (smb_token_query_privilege(token
, SE_RESTORE_LUID
))
493 privileges
|= SMB_USER_PRIV_RESTORE
;
495 if (smb_token_query_privilege(token
, SE_TAKE_OWNERSHIP_LUID
))
496 privileges
|= SMB_USER_PRIV_TAKE_OWNERSHIP
;
498 if (smb_token_query_privilege(token
, SE_SECURITY_LUID
))
499 privileges
|= SMB_USER_PRIV_SECURITY
;