xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c (revision af28f636873b7156cfd73ceffa927658cca33fd0)
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  */
24 
25 #include <sys/types.h>
26 #include <sys/sid.h>
27 #include <sys/priv_names.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <smbsrv/smb_idmap.h>
31 #include <smbsrv/smb_kproto.h>
32 #include <smbsrv/smb_token.h>
33 
34 static int smb_authenticate(smb_request_t *, smb_arg_sessionsetup_t *,
35     smb_session_key_t **);
36 static int smb_authenticate_core(smb_request_t *, smb_arg_sessionsetup_t *,
37     smb_session_key_t **);
38 static cred_t *smb_cred_create(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);
41 static uint32_t smb_priv_xlate(smb_token_t *);
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 	uint16_t		maxbufsize;
66 	uint16_t		vcnumber;
67 	int			rc = 0;
68 
69 	sinfo = smb_srm_zalloc(sr, sizeof (smb_arg_sessionsetup_t));
70 	sr->sr_ssetup = sinfo;
71 
72 	if (sr->session->dialect >= NT_LM_0_12) {
73 		rc = smbsr_decode_vwv(sr, "b.wwwwlww4.l", &sr->andx_com,
74 		    &sr->andx_off, &maxbufsize,
75 		    &sinfo->ssi_maxmpxcount, &vcnumber,
76 		    &sinfo->ssi_sesskey, &sinfo->ssi_cipwlen,
77 		    &sinfo->ssi_cspwlen, &sinfo->ssi_capabilities);
78 		if (rc != 0)
79 			goto pre_session_setup_andx_done;
80 
81 		sinfo->ssi_cipwd = smb_srm_zalloc(sr, sinfo->ssi_cipwlen + 1);
82 		sinfo->ssi_cspwd = smb_srm_zalloc(sr, sinfo->ssi_cspwlen + 1);
83 
84 		rc = smbsr_decode_data(sr, "%#c#cuuu",
85 		    sr,
86 		    sinfo->ssi_cipwlen, sinfo->ssi_cipwd,
87 		    sinfo->ssi_cspwlen, sinfo->ssi_cspwd,
88 		    &sinfo->ssi_user,
89 		    &sinfo->ssi_domain,
90 		    &native_os);
91 		if (rc != 0)
92 			goto pre_session_setup_andx_done;
93 
94 		sinfo->ssi_cipwd[sinfo->ssi_cipwlen] = 0;
95 		sinfo->ssi_cspwd[sinfo->ssi_cspwlen] = 0;
96 
97 		sr->session->native_os = smbnative_os_value(native_os);
98 
99 		if (sr->session->native_os == NATIVE_OS_WINNT)
100 			rc = smbsr_decode_data(sr, "%,u", sr, &native_lm);
101 		else
102 			rc = smbsr_decode_data(sr, "%u", sr, &native_lm);
103 
104 		if (rc != 0 || native_lm == NULL)
105 			native_lm = "NT LAN Manager 4.0";
106 
107 		sr->session->native_lm = smbnative_lm_value(native_lm);
108 	} else {
109 		rc = smbsr_decode_vwv(sr, "b.wwwwlw4.", &sr->andx_com,
110 		    &sr->andx_off, &maxbufsize,
111 		    &sinfo->ssi_maxmpxcount, &vcnumber,
112 		    &sinfo->ssi_sesskey, &sinfo->ssi_cipwlen);
113 		if (rc != 0)
114 			goto pre_session_setup_andx_done;
115 
116 		sinfo->ssi_cipwd = smb_srm_zalloc(sr, sinfo->ssi_cipwlen + 1);
117 		rc = smbsr_decode_data(sr, "%#c", sr, sinfo->ssi_cipwlen,
118 		    sinfo->ssi_cipwd);
119 		if (rc != 0)
120 			goto pre_session_setup_andx_done;
121 
122 		sinfo->ssi_cipwd[sinfo->ssi_cipwlen] = 0;
123 
124 		if (smbsr_decode_data(sr, "%u", sr, &sinfo->ssi_user) != 0)
125 			sinfo->ssi_user = "";
126 
127 		if (smbsr_decode_data(sr, "%u", sr, &sinfo->ssi_domain) != 0)
128 			sinfo->ssi_domain = "";
129 
130 		native_lm = "NT LAN Manager 4.0";
131 		sr->session->native_os = NATIVE_OS_WINNT;
132 		sr->session->native_lm = smbnative_lm_value(native_lm);
133 	}
134 
135 	sr->session->vcnumber = vcnumber;
136 	sr->session->smb_msg_size = maxbufsize;
137 
138 pre_session_setup_andx_done:
139 	DTRACE_SMB_2(op__SessionSetupX__start, smb_request_t *, sr,
140 	    smb_arg_sessionsetup_t, sinfo);
141 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
142 }
143 
144 void
145 smb_post_session_setup_andx(smb_request_t *sr)
146 {
147 	smb_arg_sessionsetup_t	*sinfo = sr->sr_ssetup;
148 
149 	DTRACE_SMB_2(op__SessionSetupX__done, smb_request_t *, sr,
150 	    smb_arg_sessionsetup_t, sinfo);
151 
152 	if (sinfo->ssi_cipwd != NULL)
153 		bzero(sinfo->ssi_cipwd, sinfo->ssi_cipwlen + 1);
154 
155 	if (sinfo->ssi_cspwd != NULL)
156 		bzero(sinfo->ssi_cspwd, sinfo->ssi_cspwlen + 1);
157 }
158 
159 /*
160  * If the vcnumber is zero, discard any other connections associated with
161  * this client.
162  *
163  * If signing has not already been enabled on this session check to see if
164  * it should be enabled.  The first authenticated logon provides the MAC
165  * key and sequence numbers for signing all subsequent sessions on the same
166  * connection.
167  *
168  * NT systems use different native OS and native LanMan values dependent on
169  * whether they are acting as a client or a server.  NT 4.0 server responds
170  * with the following values:
171  *
172  *      NativeOS:       Windows NT 4.0
173  *      NativeLM:       NT LAN Manager 4.0
174  */
175 smb_sdrc_t
176 smb_com_session_setup_andx(smb_request_t *sr)
177 {
178 	smb_arg_sessionsetup_t	*sinfo = sr->sr_ssetup;
179 	smb_session_key_t	*session_key = NULL;
180 	char			ipaddr_buf[INET6_ADDRSTRLEN];
181 	int			rc;
182 
183 	if (sr->session->vcnumber == 0)
184 		smb_server_reconnection_check(sr->sr_server, sr->session);
185 
186 	if (smb_authenticate(sr, sinfo, &session_key) != 0)
187 		return (SDRC_ERROR);
188 
189 	if (sr->session->native_lm == NATIVE_LM_WIN2000)
190 		sinfo->ssi_capabilities |= CAP_LARGE_FILES |
191 		    CAP_LARGE_READX | CAP_LARGE_WRITEX;
192 
193 	if (!smb_oplock_levelII)
194 		sr->session->capabilities &= ~CAP_LEVEL_II_OPLOCKS;
195 
196 	sr->session->capabilities = sinfo->ssi_capabilities;
197 
198 	if (!(sr->session->signing.flags & SMB_SIGNING_ENABLED) &&
199 	    (sr->session->secmode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) &&
200 	    (sr->smb_flg2 & SMB_FLAGS2_SMB_SECURITY_SIGNATURE) &&
201 	    session_key)
202 		smb_sign_init(sr, session_key, (char *)sinfo->ssi_cspwd,
203 		    sinfo->ssi_cspwlen);
204 
205 	if (!(sr->smb_flg2 & SMB_FLAGS2_SMB_SECURITY_SIGNATURE) &&
206 	    (sr->sr_cfg->skc_signing_required)) {
207 		(void) smb_inet_ntop(&sr->session->ipaddr, ipaddr_buf,
208 		    SMB_IPSTRLEN(sr->session->ipaddr.a_family));
209 		cmn_err(CE_NOTE,
210 		    "SmbSessonSetupX: client %s does not support signing",
211 		    ipaddr_buf);
212 		smbsr_error(sr, NT_STATUS_LOGON_FAILURE,
213 		    ERRDOS, ERROR_LOGON_FAILURE);
214 		return (SDRC_ERROR);
215 	}
216 
217 	rc = smbsr_encode_result(sr, 3, VAR_BCC, "bb.www%uuu",
218 	    3,
219 	    sr->andx_com,
220 	    -1,			/* andx_off */
221 	    sinfo->ssi_guest ? 1 : 0,
222 	    VAR_BCC,
223 	    sr,
224 	    smbnative_os_str(&sr->sr_cfg->skc_version),
225 	    smbnative_lm_str(&sr->sr_cfg->skc_version),
226 	    sr->sr_cfg->skc_nbdomain);
227 
228 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
229 }
230 
231 static int
232 smb_authenticate(smb_request_t *sr, smb_arg_sessionsetup_t *sinfo,
233     smb_session_key_t **session_key)
234 {
235 	int		rc;
236 	smb_server_t	*sv = sr->sr_server;
237 
238 	if (smb_threshold_enter(&sv->sv_ssetup_ct) != 0) {
239 		smbsr_error(sr, RPC_NT_SERVER_TOO_BUSY, 0, 0);
240 		return (-1);
241 	}
242 
243 	rc = smb_authenticate_core(sr, sinfo, session_key);
244 	smb_threshold_exit(&sv->sv_ssetup_ct, sv);
245 	return (rc);
246 }
247 
248 /*
249  * Authenticate a user.  If the user has already been authenticated on
250  * this session, we can simply dup the user and return.
251  *
252  * Otherwise, the user information is passed to smbd for authentication.
253  * If smbd can authenticate the user an access token is returned and we
254  * generate a cred and new user based on the token.
255  */
256 static int
257 smb_authenticate_core(smb_request_t *sr, smb_arg_sessionsetup_t *sinfo,
258     smb_session_key_t **session_key)
259 {
260 	char		*hostname = sr->sr_cfg->skc_hostname;
261 	int		security = sr->sr_cfg->skc_secmode;
262 	smb_token_t	*token = NULL;
263 	smb_user_t	*user = NULL;
264 	smb_logon_t	user_info;
265 	boolean_t	need_lookup = B_FALSE;
266 	uint32_t	privileges;
267 	cred_t		*cr;
268 	char		*buf = NULL;
269 	char		*p;
270 
271 	bzero(&user_info, sizeof (smb_logon_t));
272 	user_info.lg_e_domain = sinfo->ssi_domain;
273 
274 	if ((*sinfo->ssi_user == '\0') &&
275 	    (sinfo->ssi_cspwlen == 0) &&
276 	    (sinfo->ssi_cipwlen == 0 ||
277 	    (sinfo->ssi_cipwlen == 1 && *sinfo->ssi_cipwd == '\0'))) {
278 		user_info.lg_e_username = "anonymous";
279 		user_info.lg_flags |= SMB_ATF_ANON;
280 	} else {
281 		user_info.lg_e_username = sinfo->ssi_user;
282 	}
283 
284 	/*
285 	 * Handle user@domain format.  We need to retain the original
286 	 * data as this is important in some forms of authentication.
287 	 */
288 	if (*sinfo->ssi_domain == '\0') {
289 		buf = smb_srm_strdup(sr, sinfo->ssi_user);
290 		if ((p = strchr(buf, '@')) != NULL) {
291 			*p = '\0';
292 			user_info.lg_e_username = buf;
293 			user_info.lg_e_domain = p + 1;
294 		}
295 	}
296 
297 	/*
298 	 * If no domain name has been provided in domain mode we cannot
299 	 * determine if this is a local user or a domain user without
300 	 * obtaining an access token.  So we postpone the lookup until
301 	 * after authentication.
302 	 */
303 	if (security == SMB_SECMODE_WORKGRP) {
304 		user = smb_session_dup_user(sr->session, hostname,
305 		    user_info.lg_e_username);
306 	} else if (*user_info.lg_e_domain != '\0') {
307 		user = smb_session_dup_user(sr->session, user_info.lg_e_domain,
308 		    user_info.lg_e_username);
309 	} else {
310 		need_lookup = B_TRUE;
311 	}
312 
313 	if (user != NULL) {
314 		sinfo->ssi_guest = SMB_USER_IS_GUEST(user);
315 		sr->user_cr = user->u_cred;
316 		sr->smb_uid = user->u_uid;
317 		sr->uid_user = user;
318 		return (0);
319 	}
320 
321 	user_info.lg_level = NETR_NETWORK_LOGON;
322 	user_info.lg_domain = sinfo->ssi_domain;
323 	user_info.lg_username = sinfo->ssi_user;
324 	user_info.lg_workstation = sr->session->workstation;
325 	user_info.lg_clnt_ipaddr = sr->session->ipaddr;
326 	user_info.lg_local_ipaddr = sr->session->local_ipaddr;
327 	user_info.lg_local_port = sr->session->s_local_port;
328 	user_info.lg_challenge_key.val = sr->session->challenge_key;
329 	user_info.lg_challenge_key.len = sr->session->challenge_len;
330 	user_info.lg_nt_password.val = sinfo->ssi_cspwd;
331 	user_info.lg_nt_password.len = sinfo->ssi_cspwlen;
332 	user_info.lg_lm_password.val = sinfo->ssi_cipwd;
333 	user_info.lg_lm_password.len = sinfo->ssi_cipwlen;
334 	user_info.lg_native_os = sr->session->native_os;
335 	user_info.lg_native_lm = sr->session->native_lm;
336 
337 	DTRACE_PROBE1(smb__sessionsetup__clntinfo, smb_logon_t *, &user_info);
338 
339 	if ((token = smb_get_token(&user_info)) == NULL) {
340 		smbsr_error(sr, 0, ERRSRV, ERRbadpw);
341 		return (-1);
342 	}
343 
344 	if (need_lookup) {
345 		user = smb_session_dup_user(sr->session,
346 		    token->tkn_domain_name, token->tkn_account_name);
347 		if (user != NULL) {
348 			sinfo->ssi_guest = SMB_USER_IS_GUEST(user);
349 			sr->user_cr = user->u_cred;
350 			sr->smb_uid = user->u_uid;
351 			sr->uid_user = user;
352 			smb_token_free(token);
353 			return (0);
354 		}
355 	}
356 
357 	if (token->tkn_session_key) {
358 		*session_key = smb_srm_zalloc(sr, sizeof (smb_session_key_t));
359 		bcopy(token->tkn_session_key, *session_key,
360 		    sizeof (smb_session_key_t));
361 	}
362 
363 	if ((cr = smb_cred_create(token)) == NULL) {
364 		smb_token_free(token);
365 		smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_HANDLE);
366 		return (-1);
367 	}
368 
369 	privileges = smb_priv_xlate(token);
370 
371 	user = smb_user_login(sr->session, cr,
372 	    token->tkn_domain_name, token->tkn_account_name,
373 	    token->tkn_flags, privileges, token->tkn_audit_sid);
374 
375 	crfree(cr);
376 	smb_token_free(token);
377 
378 	if (user == NULL) {
379 		smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_HANDLE);
380 		return (-1);
381 	}
382 
383 	sinfo->ssi_guest = SMB_USER_IS_GUEST(user);
384 	sr->user_cr = user->u_cred;
385 	sr->smb_uid = user->u_uid;
386 	sr->uid_user = user;
387 	return (0);
388 }
389 
390 /*
391  * Allocate a Solaris cred and initialize it based on the access token.
392  *
393  * If the user can be mapped to a non-ephemeral ID, the cred gid is set
394  * to the Solaris user's primary group.
395  *
396  * If the mapped UID is ephemeral, or the primary group could not be
397  * obtained, the cred gid is set to whatever Solaris group is mapped
398  * to the token's primary group.
399  */
400 static cred_t *
401 smb_cred_create(smb_token_t *token)
402 {
403 	ksid_t			ksid;
404 	ksidlist_t		*ksidlist = NULL;
405 	smb_posix_grps_t	*posix_grps;
406 	cred_t			*cr;
407 	gid_t			gid;
408 
409 	ASSERT(token);
410 	ASSERT(token->tkn_posix_grps);
411 	posix_grps = token->tkn_posix_grps;
412 
413 	cr = crget();
414 	ASSERT(cr != NULL);
415 
416 	if (!IDMAP_ID_IS_EPHEMERAL(token->tkn_user.i_id) &&
417 	    (posix_grps->pg_ngrps != 0)) {
418 		gid = posix_grps->pg_grps[0];
419 	} else {
420 		gid = token->tkn_primary_grp.i_id;
421 	}
422 
423 	if (crsetugid(cr, token->tkn_user.i_id, gid) != 0) {
424 		crfree(cr);
425 		return (NULL);
426 	}
427 
428 	if (crsetgroups(cr, posix_grps->pg_ngrps, posix_grps->pg_grps) != 0) {
429 		crfree(cr);
430 		return (NULL);
431 	}
432 
433 	smb_cred_set_sid(&token->tkn_user, &ksid);
434 	crsetsid(cr, &ksid, KSID_USER);
435 	smb_cred_set_sid(&token->tkn_primary_grp, &ksid);
436 	crsetsid(cr, &ksid, KSID_GROUP);
437 	smb_cred_set_sid(&token->tkn_owner, &ksid);
438 	crsetsid(cr, &ksid, KSID_OWNER);
439 	ksidlist = smb_cred_set_sidlist(&token->tkn_win_grps);
440 	crsetsidlist(cr, ksidlist);
441 
442 	if (smb_token_query_privilege(token, SE_TAKE_OWNERSHIP_LUID))
443 		(void) crsetpriv(cr, PRIV_FILE_CHOWN, NULL);
444 
445 	return (cr);
446 }
447 
448 /*
449  * Initialize the ksid based on the given smb_id_t.
450  */
451 static void
452 smb_cred_set_sid(smb_id_t *id, ksid_t *ksid)
453 {
454 	char sidstr[SMB_SID_STRSZ];
455 	int rc;
456 
457 	ASSERT(id);
458 	ASSERT(id->i_sid);
459 
460 	ksid->ks_id = id->i_id;
461 	smb_sid_tostr(id->i_sid, sidstr);
462 	rc = smb_sid_splitstr(sidstr, &ksid->ks_rid);
463 	ASSERT(rc == 0);
464 
465 	ksid->ks_attr = id->i_attrs;
466 	ksid->ks_domain = ksid_lookupdomain(sidstr);
467 }
468 
469 /*
470  * Allocate and initialize the ksidlist based on the access token group list.
471  */
472 static ksidlist_t *
473 smb_cred_set_sidlist(smb_ids_t *token_grps)
474 {
475 	int i;
476 	ksidlist_t *lp;
477 
478 	lp = kmem_zalloc(KSIDLIST_MEM(token_grps->i_cnt), KM_SLEEP);
479 	lp->ksl_ref = 1;
480 	lp->ksl_nsid = token_grps->i_cnt;
481 	lp->ksl_neid = 0;
482 
483 	for (i = 0; i < lp->ksl_nsid; i++) {
484 		smb_cred_set_sid(&token_grps->i_ids[i], &lp->ksl_sids[i]);
485 		if (lp->ksl_sids[i].ks_id > IDMAP_WK__MAX_GID)
486 			lp->ksl_neid++;
487 	}
488 
489 	return (lp);
490 }
491 
492 /*
493  * Convert access token privileges to local definitions.
494  */
495 static uint32_t
496 smb_priv_xlate(smb_token_t *token)
497 {
498 	uint32_t	privileges = 0;
499 
500 	if (smb_token_query_privilege(token, SE_BACKUP_LUID))
501 		privileges |= SMB_USER_PRIV_BACKUP;
502 
503 	if (smb_token_query_privilege(token, SE_RESTORE_LUID))
504 		privileges |= SMB_USER_PRIV_RESTORE;
505 
506 	if (smb_token_query_privilege(token, SE_TAKE_OWNERSHIP_LUID))
507 		privileges |= SMB_USER_PRIV_TAKE_OWNERSHIP;
508 
509 	if (smb_token_query_privilege(token, SE_SECURITY_LUID))
510 		privileges |= SMB_USER_PRIV_SECURITY;
511 
512 	return (privileges);
513 }
514