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 2011 Nexenta Systems, Inc.  All rights reserved.
23  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. 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     smb_session_key_t **);
37 static int smb_authenticate_core(smb_request_t *, smb_arg_sessionsetup_t *,
38     smb_session_key_t **);
39 static cred_t *smb_cred_create(smb_token_t *);
40 static void smb_cred_set_sid(smb_id_t *id, ksid_t *ksid);
41 static ksidlist_t *smb_cred_set_sidlist(smb_ids_t *token_grps);
42 static uint32_t smb_priv_xlate(smb_token_t *);
43 
44 /*
45  * In NTLM 0.12, the padding between the Native OS and Native LM is a bit
46  * strange.  On NT4.0, there is a 2 byte pad between the OS (Windows NT 1381)
47  * and LM (Windows NT 4.0).  On Windows 2000, there is no padding between
48  * the OS (Windows 2000 2195) and LM (Windows 2000 5.0).
49  * If the padding is removed from the decode string the NT4.0 LM comes out
50  * as an empty string.  So if the client's native OS is Win NT we consider
51  * the padding otherwise we don't.
52  *
53  * For Pre-NTLM 0.12, despite the CIFS/1.0 spec, the user and domain are
54  * not always present in the message.  We try to get the account name and
55  * the primary domain but we don't care about the the native OS or native
56  * LM fields.
57  *
58  * If the Native LM cannot be determined, default to Windows NT.
59  */
60 smb_sdrc_t
61 smb_pre_session_setup_andx(smb_request_t *sr)
62 {
63 	smb_arg_sessionsetup_t	*sinfo;
64 	char			*native_os;
65 	char			*native_lm;
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 		    &sinfo->ssi_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 		    &sinfo->ssi_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 	smb_session_key_t	*session_key = NULL;
178 	char			ipaddr_buf[INET6_ADDRSTRLEN];
179 	int			rc;
180 
181 	if (smb_authenticate(sr, sinfo, &session_key) != 0)
182 		return (SDRC_ERROR);
183 
184 	if (sr->session->native_lm == NATIVE_LM_WIN2000)
185 		sinfo->ssi_capabilities |= CAP_LARGE_FILES |
186 		    CAP_LARGE_READX | CAP_LARGE_WRITEX;
187 
188 	if (!smb_oplock_levelII)
189 		sr->session->capabilities &= ~CAP_LEVEL_II_OPLOCKS;
190 
191 	sr->session->capabilities = sinfo->ssi_capabilities;
192 
193 	if (!(sr->session->signing.flags & SMB_SIGNING_ENABLED) &&
194 	    (sr->session->secmode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) &&
195 	    (sr->smb_flg2 & SMB_FLAGS2_SMB_SECURITY_SIGNATURE) &&
196 	    session_key)
197 		smb_sign_init(sr, session_key, (char *)sinfo->ssi_cspwd,
198 		    sinfo->ssi_cspwlen);
199 
200 	if (!(sr->smb_flg2 & SMB_FLAGS2_SMB_SECURITY_SIGNATURE) &&
201 	    (sr->sr_cfg->skc_signing_required)) {
202 		(void) smb_inet_ntop(&sr->session->ipaddr, ipaddr_buf,
203 		    SMB_IPSTRLEN(sr->session->ipaddr.a_family));
204 		cmn_err(CE_NOTE,
205 		    "SmbSessonSetupX: client %s does not support signing",
206 		    ipaddr_buf);
207 		smbsr_error(sr, NT_STATUS_LOGON_FAILURE,
208 		    ERRDOS, ERROR_LOGON_FAILURE);
209 		return (SDRC_ERROR);
210 	}
211 
212 	rc = smbsr_encode_result(sr, 3, VAR_BCC, "bb.www%uuu",
213 	    3,
214 	    sr->andx_com,
215 	    -1,			/* andx_off */
216 	    sinfo->ssi_guest ? 1 : 0,
217 	    VAR_BCC,
218 	    sr,
219 	    smbnative_os_str(&sr->sr_cfg->skc_version),
220 	    smbnative_lm_str(&sr->sr_cfg->skc_version),
221 	    sr->sr_cfg->skc_nbdomain);
222 
223 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
224 }
225 
226 static int
227 smb_authenticate(smb_request_t *sr, smb_arg_sessionsetup_t *sinfo,
228     smb_session_key_t **session_key)
229 {
230 	int		rc;
231 	smb_server_t	*sv = sr->sr_server;
232 
233 	if (smb_threshold_enter(&sv->sv_ssetup_ct) != 0) {
234 		smbsr_error(sr, RPC_NT_SERVER_TOO_BUSY, 0, 0);
235 		return (-1);
236 	}
237 
238 	rc = smb_authenticate_core(sr, sinfo, session_key);
239 	smb_threshold_exit(&sv->sv_ssetup_ct, sv);
240 	return (rc);
241 }
242 
243 /*
244  * Authenticate a user.  If the user has already been authenticated on
245  * this session, we can simply dup the user and return.
246  *
247  * Otherwise, the user information is passed to smbd for authentication.
248  * If smbd can authenticate the user an access token is returned and we
249  * generate a cred and new user based on the token.
250  */
251 static int
252 smb_authenticate_core(smb_request_t *sr, smb_arg_sessionsetup_t *sinfo,
253     smb_session_key_t **session_key)
254 {
255 	char		*hostname = sr->sr_cfg->skc_hostname;
256 	int		security = sr->sr_cfg->skc_secmode;
257 	smb_token_t	*token = NULL;
258 	smb_user_t	*user = NULL;
259 	smb_logon_t	user_info;
260 	boolean_t	need_lookup = B_FALSE;
261 	uint32_t	privileges;
262 	cred_t		*cr;
263 	char		*buf = NULL;
264 	char		*p;
265 
266 	bzero(&user_info, sizeof (smb_logon_t));
267 	user_info.lg_e_domain = sinfo->ssi_domain;
268 
269 	if ((*sinfo->ssi_user == '\0') &&
270 	    (sinfo->ssi_cspwlen == 0) &&
271 	    (sinfo->ssi_cipwlen == 0 ||
272 	    (sinfo->ssi_cipwlen == 1 && *sinfo->ssi_cipwd == '\0'))) {
273 		user_info.lg_e_username = "anonymous";
274 		user_info.lg_flags |= SMB_ATF_ANON;
275 	} else {
276 		user_info.lg_e_username = sinfo->ssi_user;
277 	}
278 
279 	/*
280 	 * Handle user@domain format.  We need to retain the original
281 	 * data as this is important in some forms of authentication.
282 	 */
283 	if (*sinfo->ssi_domain == '\0') {
284 		buf = smb_srm_strdup(sr, sinfo->ssi_user);
285 		if ((p = strchr(buf, '@')) != NULL) {
286 			*p = '\0';
287 			user_info.lg_e_username = buf;
288 			user_info.lg_e_domain = p + 1;
289 		}
290 	}
291 
292 	/*
293 	 * If no domain name has been provided in domain mode we cannot
294 	 * determine if this is a local user or a domain user without
295 	 * obtaining an access token.  So we postpone the lookup until
296 	 * after authentication.
297 	 */
298 	if (security == SMB_SECMODE_WORKGRP) {
299 		user = smb_session_dup_user(sr->session, hostname,
300 		    user_info.lg_e_username);
301 	} else if (*user_info.lg_e_domain != '\0') {
302 		user = smb_session_dup_user(sr->session, user_info.lg_e_domain,
303 		    user_info.lg_e_username);
304 	} else {
305 		need_lookup = B_TRUE;
306 	}
307 
308 	if (user != NULL) {
309 		sinfo->ssi_guest = SMB_USER_IS_GUEST(user);
310 		sr->user_cr = user->u_cred;
311 		sr->smb_uid = user->u_uid;
312 		sr->uid_user = user;
313 		return (0);
314 	}
315 
316 	user_info.lg_level = NETR_NETWORK_LOGON;
317 	user_info.lg_domain = sinfo->ssi_domain;
318 	user_info.lg_username = sinfo->ssi_user;
319 	user_info.lg_workstation = sr->session->workstation;
320 	user_info.lg_clnt_ipaddr = sr->session->ipaddr;
321 	user_info.lg_local_ipaddr = sr->session->local_ipaddr;
322 	user_info.lg_local_port = sr->session->s_local_port;
323 	user_info.lg_challenge_key.val = sr->session->challenge_key;
324 	user_info.lg_challenge_key.len = sr->session->challenge_len;
325 	user_info.lg_nt_password.val = sinfo->ssi_cspwd;
326 	user_info.lg_nt_password.len = sinfo->ssi_cspwlen;
327 	user_info.lg_lm_password.val = sinfo->ssi_cipwd;
328 	user_info.lg_lm_password.len = sinfo->ssi_cipwlen;
329 	user_info.lg_native_os = sr->session->native_os;
330 	user_info.lg_native_lm = sr->session->native_lm;
331 
332 	DTRACE_PROBE1(smb__sessionsetup__clntinfo, smb_logon_t *, &user_info);
333 
334 	if ((token = smb_get_token(&user_info)) == NULL) {
335 		smbsr_error(sr, 0, ERRSRV, ERRbadpw);
336 		return (-1);
337 	}
338 
339 	if (need_lookup) {
340 		user = smb_session_dup_user(sr->session,
341 		    token->tkn_domain_name, token->tkn_account_name);
342 		if (user != NULL) {
343 			sinfo->ssi_guest = SMB_USER_IS_GUEST(user);
344 			sr->user_cr = user->u_cred;
345 			sr->smb_uid = user->u_uid;
346 			sr->uid_user = user;
347 			smb_token_free(token);
348 			return (0);
349 		}
350 	}
351 
352 	if (token->tkn_session_key) {
353 		*session_key = smb_srm_zalloc(sr, sizeof (smb_session_key_t));
354 		bcopy(token->tkn_session_key, *session_key,
355 		    sizeof (smb_session_key_t));
356 	}
357 
358 	if ((cr = smb_cred_create(token)) == NULL) {
359 		smb_token_free(token);
360 		smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_HANDLE);
361 		return (-1);
362 	}
363 
364 	privileges = smb_priv_xlate(token);
365 
366 	user = smb_user_login(sr->session, cr,
367 	    token->tkn_domain_name, token->tkn_account_name,
368 	    token->tkn_flags, privileges, token->tkn_audit_sid);
369 
370 	crfree(cr);
371 	smb_token_free(token);
372 
373 	if (user == NULL) {
374 		smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_HANDLE);
375 		return (-1);
376 	}
377 
378 	sinfo->ssi_guest = SMB_USER_IS_GUEST(user);
379 	sr->user_cr = user->u_cred;
380 	sr->smb_uid = user->u_uid;
381 	sr->uid_user = user;
382 	return (0);
383 }
384 
385 /*
386  * Allocate a Solaris cred and initialize it based on the access token.
387  *
388  * If the user can be mapped to a non-ephemeral ID, the cred gid is set
389  * to the Solaris user's primary group.
390  *
391  * If the mapped UID is ephemeral, or the primary group could not be
392  * obtained, the cred gid is set to whatever Solaris group is mapped
393  * to the token's primary group.
394  */
395 static cred_t *
396 smb_cred_create(smb_token_t *token)
397 {
398 	ksid_t			ksid;
399 	ksidlist_t		*ksidlist = NULL;
400 	smb_posix_grps_t	*posix_grps;
401 	cred_t			*cr;
402 	gid_t			gid;
403 
404 	ASSERT(token);
405 	ASSERT(token->tkn_posix_grps);
406 	posix_grps = token->tkn_posix_grps;
407 
408 	cr = crget();
409 	ASSERT(cr != NULL);
410 
411 	if (!IDMAP_ID_IS_EPHEMERAL(token->tkn_user.i_id) &&
412 	    (posix_grps->pg_ngrps != 0)) {
413 		gid = posix_grps->pg_grps[0];
414 	} else {
415 		gid = token->tkn_primary_grp.i_id;
416 	}
417 
418 	if (crsetugid(cr, token->tkn_user.i_id, gid) != 0) {
419 		crfree(cr);
420 		return (NULL);
421 	}
422 
423 	if (crsetgroups(cr, posix_grps->pg_ngrps, posix_grps->pg_grps) != 0) {
424 		crfree(cr);
425 		return (NULL);
426 	}
427 
428 	smb_cred_set_sid(&token->tkn_user, &ksid);
429 	crsetsid(cr, &ksid, KSID_USER);
430 	smb_cred_set_sid(&token->tkn_primary_grp, &ksid);
431 	crsetsid(cr, &ksid, KSID_GROUP);
432 	smb_cred_set_sid(&token->tkn_owner, &ksid);
433 	crsetsid(cr, &ksid, KSID_OWNER);
434 	ksidlist = smb_cred_set_sidlist(&token->tkn_win_grps);
435 	crsetsidlist(cr, ksidlist);
436 
437 	if (smb_token_query_privilege(token, SE_TAKE_OWNERSHIP_LUID))
438 		(void) crsetpriv(cr, PRIV_FILE_CHOWN, NULL);
439 
440 	return (cr);
441 }
442 
443 /*
444  * Initialize the ksid based on the given smb_id_t.
445  */
446 static void
447 smb_cred_set_sid(smb_id_t *id, ksid_t *ksid)
448 {
449 	char sidstr[SMB_SID_STRSZ];
450 	int rc;
451 
452 	ASSERT(id);
453 	ASSERT(id->i_sid);
454 
455 	ksid->ks_id = id->i_id;
456 	smb_sid_tostr(id->i_sid, sidstr);
457 	rc = smb_sid_splitstr(sidstr, &ksid->ks_rid);
458 	ASSERT(rc == 0);
459 
460 	ksid->ks_attr = id->i_attrs;
461 	ksid->ks_domain = ksid_lookupdomain(sidstr);
462 }
463 
464 /*
465  * Allocate and initialize the ksidlist based on the access token group list.
466  */
467 static ksidlist_t *
468 smb_cred_set_sidlist(smb_ids_t *token_grps)
469 {
470 	int i;
471 	ksidlist_t *lp;
472 
473 	lp = kmem_zalloc(KSIDLIST_MEM(token_grps->i_cnt), KM_SLEEP);
474 	lp->ksl_ref = 1;
475 	lp->ksl_nsid = token_grps->i_cnt;
476 	lp->ksl_neid = 0;
477 
478 	for (i = 0; i < lp->ksl_nsid; i++) {
479 		smb_cred_set_sid(&token_grps->i_ids[i], &lp->ksl_sids[i]);
480 		if (lp->ksl_sids[i].ks_id > IDMAP_WK__MAX_GID)
481 			lp->ksl_neid++;
482 	}
483 
484 	return (lp);
485 }
486 
487 /*
488  * Convert access token privileges to local definitions.
489  */
490 static uint32_t
491 smb_priv_xlate(smb_token_t *token)
492 {
493 	uint32_t	privileges = 0;
494 
495 	if (smb_token_query_privilege(token, SE_BACKUP_LUID))
496 		privileges |= SMB_USER_PRIV_BACKUP;
497 
498 	if (smb_token_query_privilege(token, SE_RESTORE_LUID))
499 		privileges |= SMB_USER_PRIV_RESTORE;
500 
501 	if (smb_token_query_privilege(token, SE_TAKE_OWNERSHIP_LUID))
502 		privileges |= SMB_USER_PRIV_TAKE_OWNERSHIP;
503 
504 	if (smb_token_query_privilege(token, SE_SECURITY_LUID))
505 		privileges |= SMB_USER_PRIV_SECURITY;
506 
507 	return (privileges);
508 }
509