5917 User-mode SMB server
[unleashed.git] / usr / src / uts / common / fs / smbsrv / smb_session_setup_andx.c
blob7eabad75136fc726dbfb0f0b345c3c6f0495f103
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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>
27 #include <sys/sid.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 *);
38 #ifdef _KERNEL
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);
41 #endif /* _KERNEL */
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
55 * LM fields.
57 * If the Native LM cannot be determined, default to Windows NT.
59 smb_sdrc_t
60 smb_pre_session_setup_andx(smb_request_t *sr)
62 smb_arg_sessionsetup_t *sinfo;
63 char *native_os;
64 char *native_lm;
65 uint32_t junk_sesskey;
66 uint16_t maxbufsize;
67 uint16_t vcnumber;
68 int rc = 0;
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);
79 if (rc != 0)
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",
86 sr,
87 sinfo->ssi_cipwlen, sinfo->ssi_cipwd,
88 sinfo->ssi_cspwlen, sinfo->ssi_cspwd,
89 &sinfo->ssi_user,
90 &sinfo->ssi_domain,
91 &native_os);
92 if (rc != 0)
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);
102 else
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);
109 } else {
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);
114 if (rc != 0)
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,
119 sinfo->ssi_cipwd);
120 if (rc != 0)
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);
145 void
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
164 * connection.
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
173 smb_sdrc_t
174 smb_com_session_setup_andx(smb_request_t *sr)
176 smb_arg_sessionsetup_t *sinfo = sr->sr_ssetup;
177 int rc;
179 if (smb_authenticate(sr, sinfo) != 0)
180 return (SDRC_ERROR);
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",
193 sr->andx_com,
194 -1, /* andx_off */
195 sinfo->ssi_guest ? 1 : 0,
196 VAR_BCC,
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);
205 static int
206 smb_authenticate(smb_request_t *sr, smb_arg_sessionsetup_t *sinfo)
208 int rc;
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);
213 return (-1);
216 rc = smb_authenticate_core(sr, sinfo);
217 smb_threshold_exit(&sv->sv_ssetup_ct);
218 return (rc);
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.
229 static int
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;
238 uint32_t privileges;
239 cred_t *cr;
240 char *buf = NULL;
241 char *p;
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;
252 } else {
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) {
263 *p = '\0';
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);
281 } else {
282 need_lookup = B_TRUE;
285 if (user != NULL) {
286 sinfo->ssi_guest = SMB_USER_IS_GUEST(user);
287 sr->user_cr = user->u_cred;
288 sr->smb_uid = user->u_uid;
289 sr->uid_user = user;
290 return (0);
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);
313 return (-1);
316 if (need_lookup) {
317 user = smb_session_dup_user(sr->session,
318 token->tkn_domain_name, token->tkn_account_name);
319 if (user != NULL) {
320 sinfo->ssi_guest = SMB_USER_IS_GUEST(user);
321 sr->user_cr = user->u_cred;
322 sr->smb_uid = user->u_uid;
323 sr->uid_user = user;
324 smb_token_free(token);
325 return (0);
329 if ((cr = smb_cred_create(token)) == NULL) {
330 smb_token_free(token);
331 smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_HANDLE);
332 return (-1);
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);
340 crfree(cr);
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);
351 if (user == NULL) {
352 smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_HANDLE);
353 return (-1);
356 sinfo->ssi_guest = SMB_USER_IS_GUEST(user);
357 sr->user_cr = user->u_cred;
358 sr->smb_uid = user->u_uid;
359 sr->uid_user = user;
360 return (0);
363 #ifdef _KERNEL
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.
374 cred_t *
375 smb_cred_create(smb_token_t *token)
377 ksid_t ksid;
378 ksidlist_t *ksidlist = NULL;
379 smb_posix_grps_t *posix_grps;
380 cred_t *cr;
381 gid_t gid;
383 ASSERT(token);
384 ASSERT(token->tkn_posix_grps);
385 posix_grps = token->tkn_posix_grps;
387 cr = crget();
388 ASSERT(cr != NULL);
390 if (!IDMAP_ID_IS_EPHEMERAL(token->tkn_user.i_id) &&
391 (posix_grps->pg_ngrps != 0)) {
392 gid = posix_grps->pg_grps[0];
393 } else {
394 gid = token->tkn_primary_grp.i_id;
397 if (crsetugid(cr, token->tkn_user.i_id, gid) != 0) {
398 crfree(cr);
399 return (NULL);
402 if (crsetgroups(cr, posix_grps->pg_ngrps, posix_grps->pg_grps) != 0) {
403 crfree(cr);
404 return (NULL);
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)) {
424 (void) crsetpriv(cr,
425 PRIV_FILE_CHOWN,
426 PRIV_FILE_DAC_READ,
427 PRIV_FILE_DAC_SEARCH,
428 PRIV_FILE_DAC_WRITE,
429 PRIV_FILE_OWNER,
430 NULL);
433 return (cr);
437 * Initialize the ksid based on the given smb_id_t.
439 static void
440 smb_cred_set_sid(smb_id_t *id, ksid_t *ksid)
442 char sidstr[SMB_SID_STRSZ];
443 int rc;
445 ASSERT(id);
446 ASSERT(id->i_sid);
448 ksid->ks_id = id->i_id;
449 smb_sid_tostr(id->i_sid, sidstr);
450 rc = smb_sid_splitstr(sidstr, &ksid->ks_rid);
451 ASSERT(rc == 0);
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.
460 static ksidlist_t *
461 smb_cred_set_sidlist(smb_ids_t *token_grps)
463 int i;
464 ksidlist_t *lp;
466 lp = kmem_zalloc(KSIDLIST_MEM(token_grps->i_cnt), KM_SLEEP);
467 lp->ksl_ref = 1;
468 lp->ksl_nsid = token_grps->i_cnt;
469 lp->ksl_neid = 0;
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)
474 lp->ksl_neid++;
477 return (lp);
479 #endif /* _KERNEL */
482 * Convert access token privileges to local definitions.
484 static uint32_t
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;
501 return (privileges);