xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c (revision 45818ee124adeaaf947698996b4f4c722afc6d1f)
1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
24  */
25 
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>
34 
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 */
42 
43 /*
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.
51  *
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.
56  *
57  * If the Native LM cannot be determined, default to Windows NT.
58  */
59 smb_sdrc_t
60 smb_pre_session_setup_andx(smb_request_t *sr)
61 {
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;
69 
70 	sinfo = smb_srm_zalloc(sr, sizeof (smb_arg_sessionsetup_t));
71 	sr->sr_ssetup = sinfo;
72 
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;
81 
82 		sinfo->ssi_cipwd = smb_srm_zalloc(sr, sinfo->ssi_cipwlen + 1);
83 		sinfo->ssi_cspwd = smb_srm_zalloc(sr, sinfo->ssi_cspwlen + 1);
84 
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;
94 
95 		sinfo->ssi_cipwd[sinfo->ssi_cipwlen] = 0;
96 		sinfo->ssi_cspwd[sinfo->ssi_cspwlen] = 0;
97 
98 		sr->session->native_os = smbnative_os_value(native_os);
99 
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);
104 
105 		if (rc != 0 || native_lm == NULL)
106 			native_lm = "NT LAN Manager 4.0";
107 
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;
116 
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;
122 
123 		sinfo->ssi_cipwd[sinfo->ssi_cipwlen] = 0;
124 
125 		if (smbsr_decode_data(sr, "%u", sr, &sinfo->ssi_user) != 0)
126 			sinfo->ssi_user = "";
127 
128 		if (smbsr_decode_data(sr, "%u", sr, &sinfo->ssi_domain) != 0)
129 			sinfo->ssi_domain = "";
130 
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);
134 	}
135 
136 	sr->session->vcnumber = vcnumber;
137 	sr->session->smb_msg_size = maxbufsize;
138 
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);
143 }
144 
145 void
146 smb_post_session_setup_andx(smb_request_t *sr)
147 {
148 	smb_arg_sessionsetup_t	*sinfo = sr->sr_ssetup;
149 
150 	DTRACE_SMB_2(op__SessionSetupX__done, smb_request_t *, sr,
151 	    smb_arg_sessionsetup_t, sinfo);
152 
153 	if (sinfo->ssi_cipwd != NULL)
154 		bzero(sinfo->ssi_cipwd, sinfo->ssi_cipwlen + 1);
155 
156 	if (sinfo->ssi_cspwd != NULL)
157 		bzero(sinfo->ssi_cspwd, sinfo->ssi_cspwlen + 1);
158 }
159 
160 /*
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.
165  *
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:
169  *
170  *      NativeOS:       Windows NT 4.0
171  *      NativeLM:       NT LAN Manager 4.0
172  */
173 smb_sdrc_t
174 smb_com_session_setup_andx(smb_request_t *sr)
175 {
176 	smb_arg_sessionsetup_t	*sinfo = sr->sr_ssetup;
177 	int			rc;
178 
179 	if (smb_authenticate(sr, sinfo) != 0)
180 		return (SDRC_ERROR);
181 
182 	if (sr->session->native_lm == NATIVE_LM_WIN2000)
183 		sinfo->ssi_capabilities |= CAP_LARGE_FILES |
184 		    CAP_LARGE_READX | CAP_LARGE_WRITEX;
185 
186 	if (!smb_oplock_levelII)
187 		sr->session->capabilities &= ~CAP_LEVEL_II_OPLOCKS;
188 
189 	sr->session->capabilities = sinfo->ssi_capabilities;
190 
191 	rc = smbsr_encode_result(sr, 3, VAR_BCC, "bb.www%uuu",
192 	    3,
193 	    sr->andx_com,
194 	    -1,			/* andx_off */
195 	    sinfo->ssi_guest ? 1 : 0,
196 	    VAR_BCC,
197 	    sr,
198 	    smbnative_os_str(&sr->sr_cfg->skc_version),
199 	    smbnative_lm_str(&sr->sr_cfg->skc_version),
200 	    sr->sr_cfg->skc_nbdomain);
201 
202 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
203 }
204 
205 static int
206 smb_authenticate(smb_request_t *sr, smb_arg_sessionsetup_t *sinfo)
207 {
208 	int		rc;
209 	smb_server_t	*sv = sr->sr_server;
210 
211 	if (smb_threshold_enter(&sv->sv_ssetup_ct) != 0) {
212 		smbsr_error(sr, RPC_NT_SERVER_TOO_BUSY, 0, 0);
213 		return (-1);
214 	}
215 
216 	rc = smb_authenticate_core(sr, sinfo);
217 	smb_threshold_exit(&sv->sv_ssetup_ct);
218 	return (rc);
219 }
220 
221 /*
222  * Authenticate a user.  If the user has already been authenticated on
223  * this session, we can simply dup the user and return.
224  *
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.
228  */
229 static int
230 smb_authenticate_core(smb_request_t *sr, smb_arg_sessionsetup_t *sinfo)
231 {
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;
242 
243 	bzero(&user_info, sizeof (smb_logon_t));
244 	user_info.lg_e_domain = sinfo->ssi_domain;
245 
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;
254 	}
255 
256 	/*
257 	 * Handle user@domain format.  We need to retain the original
258 	 * data as this is important in some forms of authentication.
259 	 */
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;
266 		}
267 	}
268 
269 	/*
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.
274 	 */
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;
283 	}
284 
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);
291 	}
292 
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;
308 
309 	DTRACE_PROBE1(smb__sessionsetup__clntinfo, smb_logon_t *, &user_info);
310 
311 	if ((token = smb_get_token(sr->session, &user_info)) == NULL) {
312 		smbsr_error(sr, 0, ERRSRV, ERRbadpw);
313 		return (-1);
314 	}
315 
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);
326 		}
327 	}
328 
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);
333 	}
334 
335 	privileges = smb_priv_xlate(token);
336 
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);
341 
342 	/*
343 	 * Save the session key, and (maybe) enable signing,
344 	 * but only for real logon (not ANON or GUEST).
345 	 */
346 	if ((token->tkn_flags & (SMB_ATF_GUEST | SMB_ATF_ANON)) == 0)
347 		(void) smb_sign_begin(sr, token);
348 
349 	smb_token_free(token);
350 
351 	if (user == NULL) {
352 		smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_HANDLE);
353 		return (-1);
354 	}
355 
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);
361 }
362 
363 #ifdef	_KERNEL
364 /*
365  * Allocate a Solaris cred and initialize it based on the access token.
366  *
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.
369  *
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.
373  */
374 cred_t *
375 smb_cred_create(smb_token_t *token)
376 {
377 	ksid_t			ksid;
378 	ksidlist_t		*ksidlist = NULL;
379 	smb_posix_grps_t	*posix_grps;
380 	cred_t			*cr;
381 	gid_t			gid;
382 
383 	ASSERT(token);
384 	ASSERT(token->tkn_posix_grps);
385 	posix_grps = token->tkn_posix_grps;
386 
387 	cr = crget();
388 	ASSERT(cr != NULL);
389 
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;
395 	}
396 
397 	if (crsetugid(cr, token->tkn_user.i_id, gid) != 0) {
398 		crfree(cr);
399 		return (NULL);
400 	}
401 
402 	if (crsetgroups(cr, posix_grps->pg_ngrps, posix_grps->pg_grps) != 0) {
403 		crfree(cr);
404 		return (NULL);
405 	}
406 
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);
415 
416 	/*
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".
422 	 */
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);
431 	}
432 
433 	return (cr);
434 }
435 
436 /*
437  * Initialize the ksid based on the given smb_id_t.
438  */
439 static void
440 smb_cred_set_sid(smb_id_t *id, ksid_t *ksid)
441 {
442 	char sidstr[SMB_SID_STRSZ];
443 	int rc;
444 
445 	ASSERT(id);
446 	ASSERT(id->i_sid);
447 
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);
452 
453 	ksid->ks_attr = id->i_attrs;
454 	ksid->ks_domain = ksid_lookupdomain(sidstr);
455 }
456 
457 /*
458  * Allocate and initialize the ksidlist based on the access token group list.
459  */
460 static ksidlist_t *
461 smb_cred_set_sidlist(smb_ids_t *token_grps)
462 {
463 	int i;
464 	ksidlist_t *lp;
465 
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;
470 
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++;
475 	}
476 
477 	return (lp);
478 }
479 #endif	/* _KERNEL */
480 
481 /*
482  * Convert access token privileges to local definitions.
483  */
484 static uint32_t
485 smb_priv_xlate(smb_token_t *token)
486 {
487 	uint32_t	privileges = 0;
488 
489 	if (smb_token_query_privilege(token, SE_BACKUP_LUID))
490 		privileges |= SMB_USER_PRIV_BACKUP;
491 
492 	if (smb_token_query_privilege(token, SE_RESTORE_LUID))
493 		privileges |= SMB_USER_PRIV_RESTORE;
494 
495 	if (smb_token_query_privilege(token, SE_TAKE_OWNERSHIP_LUID))
496 		privileges |= SMB_USER_PRIV_TAKE_OWNERSHIP;
497 
498 	if (smb_token_query_privilege(token, SE_SECURITY_LUID))
499 		privileges |= SMB_USER_PRIV_SECURITY;
500 
501 	return (privileges);
502 }
503