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 cred_t *smb_cred_create(smb_token_t *);
37 static void smb_cred_set_sid(smb_id_t *id, ksid_t *ksid);
38 static ksidlist_t *smb_cred_set_sidlist(smb_ids_t *token_grps);
39 static uint32_t smb_priv_xlate(smb_token_t *);
40 
41 /*
42  * In NTLM 0.12, the padding between the Native OS and Native LM is a bit
43  * strange.  On NT4.0, there is a 2 byte pad between the OS (Windows NT 1381)
44  * and LM (Windows NT 4.0).  On Windows 2000, there is no padding between
45  * the OS (Windows 2000 2195) and LM (Windows 2000 5.0).
46  * If the padding is removed from the decode string the NT4.0 LM comes out
47  * as an empty string.  So if the client's native OS is Win NT we consider
48  * the padding otherwise we don't.
49  *
50  * For Pre-NTLM 0.12, despite the CIFS/1.0 spec, the user and domain are
51  * not always present in the message.  We try to get the account name and
52  * the primary domain but we don't care about the the native OS or native
53  * LM fields.
54  *
55  * If the Native LM cannot be determined, default to Windows NT.
56  */
57 smb_sdrc_t
58 smb_pre_session_setup_andx(smb_request_t *sr)
59 {
60 	smb_arg_sessionsetup_t	*sinfo;
61 	char			*native_os;
62 	char			*native_lm;
63 	uint16_t		maxbufsize;
64 	uint16_t		vcnumber;
65 	int			rc = 0;
66 
67 	sinfo = smb_srm_zalloc(sr, sizeof (smb_arg_sessionsetup_t));
68 	sr->sr_ssetup = sinfo;
69 
70 	if (sr->session->dialect >= NT_LM_0_12) {
71 		rc = smbsr_decode_vwv(sr, "b.wwwwlww4.l", &sr->andx_com,
72 		    &sr->andx_off, &maxbufsize,
73 		    &sinfo->ssi_maxmpxcount, &vcnumber,
74 		    &sinfo->ssi_sesskey, &sinfo->ssi_cipwlen,
75 		    &sinfo->ssi_cspwlen, &sinfo->ssi_capabilities);
76 		if (rc != 0)
77 			goto pre_session_setup_andx_done;
78 
79 		sinfo->ssi_cipwd = smb_srm_zalloc(sr, sinfo->ssi_cipwlen + 1);
80 		sinfo->ssi_cspwd = smb_srm_zalloc(sr, sinfo->ssi_cspwlen + 1);
81 
82 		rc = smbsr_decode_data(sr, "%#c#cuuu",
83 		    sr,
84 		    sinfo->ssi_cipwlen, sinfo->ssi_cipwd,
85 		    sinfo->ssi_cspwlen, sinfo->ssi_cspwd,
86 		    &sinfo->ssi_user,
87 		    &sinfo->ssi_domain,
88 		    &native_os);
89 		if (rc != 0)
90 			goto pre_session_setup_andx_done;
91 
92 		sinfo->ssi_cipwd[sinfo->ssi_cipwlen] = 0;
93 		sinfo->ssi_cspwd[sinfo->ssi_cspwlen] = 0;
94 
95 		sr->session->native_os = smbnative_os_value(native_os);
96 
97 		if (sr->session->native_os == NATIVE_OS_WINNT)
98 			rc = smbsr_decode_data(sr, "%,u", sr, &native_lm);
99 		else
100 			rc = smbsr_decode_data(sr, "%u", sr, &native_lm);
101 
102 		if (rc != 0 || native_lm == NULL)
103 			native_lm = "NT LAN Manager 4.0";
104 
105 		sr->session->native_lm = smbnative_lm_value(native_lm);
106 	} else {
107 		rc = smbsr_decode_vwv(sr, "b.wwwwlw4.", &sr->andx_com,
108 		    &sr->andx_off, &maxbufsize,
109 		    &sinfo->ssi_maxmpxcount, &vcnumber,
110 		    &sinfo->ssi_sesskey, &sinfo->ssi_cipwlen);
111 		if (rc != 0)
112 			goto pre_session_setup_andx_done;
113 
114 		sinfo->ssi_cipwd = smb_srm_zalloc(sr, sinfo->ssi_cipwlen + 1);
115 		rc = smbsr_decode_data(sr, "%#c", sr, sinfo->ssi_cipwlen,
116 		    sinfo->ssi_cipwd);
117 		if (rc != 0)
118 			goto pre_session_setup_andx_done;
119 
120 		sinfo->ssi_cipwd[sinfo->ssi_cipwlen] = 0;
121 
122 		if (smbsr_decode_data(sr, "%u", sr, &sinfo->ssi_user) != 0)
123 			sinfo->ssi_user = "";
124 
125 		if (smbsr_decode_data(sr, "%u", sr, &sinfo->ssi_domain) != 0)
126 			sinfo->ssi_domain = "";
127 
128 		native_lm = "NT LAN Manager 4.0";
129 		sr->session->native_os = NATIVE_OS_WINNT;
130 		sr->session->native_lm = smbnative_lm_value(native_lm);
131 	}
132 
133 	sr->session->vcnumber = vcnumber;
134 	sr->session->smb_msg_size = maxbufsize;
135 
136 pre_session_setup_andx_done:
137 	DTRACE_SMB_2(op__SessionSetupX__start, smb_request_t *, sr,
138 	    smb_arg_sessionsetup_t, sinfo);
139 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
140 }
141 
142 void
143 smb_post_session_setup_andx(smb_request_t *sr)
144 {
145 	smb_arg_sessionsetup_t	*sinfo = sr->sr_ssetup;
146 
147 	DTRACE_SMB_2(op__SessionSetupX__done, smb_request_t *, sr,
148 	    smb_arg_sessionsetup_t, sinfo);
149 
150 	if (sinfo->ssi_cipwd != NULL)
151 		bzero(sinfo->ssi_cipwd, sinfo->ssi_cipwlen + 1);
152 
153 	if (sinfo->ssi_cspwd != NULL)
154 		bzero(sinfo->ssi_cspwd, sinfo->ssi_cspwlen + 1);
155 }
156 
157 /*
158  * If the vcnumber is zero, discard any other connections associated with
159  * this client.
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 (sr->session->vcnumber == 0)
182 		smb_server_reconnection_check(sr->sr_server, sr->session);
183 
184 	if (smb_authenticate(sr, sinfo, &session_key) != 0)
185 		return (SDRC_ERROR);
186 
187 	if (sr->session->native_lm == NATIVE_LM_WIN2000)
188 		sinfo->ssi_capabilities |= CAP_LARGE_FILES |
189 		    CAP_LARGE_READX | CAP_LARGE_WRITEX;
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 /*
227  * Authenticate a user.  If the user has already been authenticated on
228  * this session, we can simply dup the user and return.
229  *
230  * Otherwise, the user information is passed to smbd for authentication.
231  * If smbd can authenticate the user an access token is returned and we
232  * generate a cred and new user based on the token.
233  */
234 static int
235 smb_authenticate(smb_request_t *sr, smb_arg_sessionsetup_t *sinfo,
236     smb_session_key_t **session_key)
237 {
238 	char		*hostname = sr->sr_cfg->skc_hostname;
239 	int		security = sr->sr_cfg->skc_secmode;
240 	smb_token_t	*token = NULL;
241 	smb_user_t	*user = NULL;
242 	smb_logon_t	user_info;
243 	boolean_t	need_lookup = B_FALSE;
244 	uint32_t	privileges;
245 	cred_t		*cr;
246 	char		*buf = NULL;
247 	char		*p;
248 
249 	bzero(&user_info, sizeof (smb_logon_t));
250 	user_info.lg_e_domain = sinfo->ssi_domain;
251 
252 	if ((*sinfo->ssi_user == '\0') &&
253 	    (sinfo->ssi_cspwlen == 0) &&
254 	    (sinfo->ssi_cipwlen == 0 ||
255 	    (sinfo->ssi_cipwlen == 1 && *sinfo->ssi_cipwd == '\0'))) {
256 		user_info.lg_e_username = "anonymous";
257 		user_info.lg_flags |= SMB_ATF_ANON;
258 	} else {
259 		user_info.lg_e_username = sinfo->ssi_user;
260 	}
261 
262 	/*
263 	 * Handle user@domain format.  We need to retain the original
264 	 * data as this is important in some forms of authentication.
265 	 */
266 	if (*sinfo->ssi_domain == '\0') {
267 		buf = smb_srm_strdup(sr, sinfo->ssi_user);
268 		if ((p = strchr(buf, '@')) != NULL) {
269 			*p = '\0';
270 			user_info.lg_e_username = buf;
271 			user_info.lg_e_domain = p + 1;
272 		}
273 	}
274 
275 	/*
276 	 * If no domain name has been provided in domain mode we cannot
277 	 * determine if this is a local user or a domain user without
278 	 * obtaining an access token.  So we postpone the lookup until
279 	 * after authentication.
280 	 */
281 	if (security == SMB_SECMODE_WORKGRP) {
282 		user = smb_session_dup_user(sr->session, hostname,
283 		    user_info.lg_e_username);
284 	} else if (*user_info.lg_e_domain != '\0') {
285 		user = smb_session_dup_user(sr->session, user_info.lg_e_domain,
286 		    user_info.lg_e_username);
287 	} else {
288 		need_lookup = B_TRUE;
289 	}
290 
291 	if (user != NULL) {
292 		sinfo->ssi_guest = SMB_USER_IS_GUEST(user);
293 		sr->user_cr = user->u_cred;
294 		sr->smb_uid = user->u_uid;
295 		sr->uid_user = user;
296 		return (0);
297 	}
298 
299 	user_info.lg_level = NETR_NETWORK_LOGON;
300 	user_info.lg_domain = sinfo->ssi_domain;
301 	user_info.lg_username = sinfo->ssi_user;
302 	user_info.lg_workstation = sr->session->workstation;
303 	user_info.lg_clnt_ipaddr = sr->session->ipaddr;
304 	user_info.lg_local_ipaddr = sr->session->local_ipaddr;
305 	user_info.lg_local_port = sr->session->s_local_port;
306 	user_info.lg_challenge_key.val = sr->session->challenge_key;
307 	user_info.lg_challenge_key.len = sr->session->challenge_len;
308 	user_info.lg_nt_password.val = sinfo->ssi_cspwd;
309 	user_info.lg_nt_password.len = sinfo->ssi_cspwlen;
310 	user_info.lg_lm_password.val = sinfo->ssi_cipwd;
311 	user_info.lg_lm_password.len = sinfo->ssi_cipwlen;
312 	user_info.lg_native_os = sr->session->native_os;
313 	user_info.lg_native_lm = sr->session->native_lm;
314 
315 	DTRACE_PROBE1(smb__sessionsetup__clntinfo, smb_logon_t *, &user_info);
316 
317 	if ((token = smb_get_token(&user_info)) == NULL) {
318 		smbsr_error(sr, 0, ERRSRV, ERRbadpw);
319 		return (-1);
320 	}
321 
322 	if (need_lookup) {
323 		user = smb_session_dup_user(sr->session,
324 		    token->tkn_domain_name, token->tkn_account_name);
325 		if (user != NULL) {
326 			sinfo->ssi_guest = SMB_USER_IS_GUEST(user);
327 			sr->user_cr = user->u_cred;
328 			sr->smb_uid = user->u_uid;
329 			sr->uid_user = user;
330 			smb_token_free(token);
331 			return (0);
332 		}
333 	}
334 
335 	if (token->tkn_session_key) {
336 		*session_key = smb_srm_zalloc(sr, sizeof (smb_session_key_t));
337 		bcopy(token->tkn_session_key, *session_key,
338 		    sizeof (smb_session_key_t));
339 	}
340 
341 	if ((cr = smb_cred_create(token)) == NULL) {
342 		smb_token_free(token);
343 		smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_HANDLE);
344 		return (-1);
345 	}
346 
347 	privileges = smb_priv_xlate(token);
348 
349 	user = smb_user_login(sr->session, cr,
350 	    token->tkn_domain_name, token->tkn_account_name,
351 	    token->tkn_flags, privileges, token->tkn_audit_sid);
352 
353 	crfree(cr);
354 	smb_token_free(token);
355 
356 	if (user == NULL) {
357 		smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_HANDLE);
358 		return (-1);
359 	}
360 
361 	sinfo->ssi_guest = SMB_USER_IS_GUEST(user);
362 	sr->user_cr = user->u_cred;
363 	sr->smb_uid = user->u_uid;
364 	sr->uid_user = user;
365 	return (0);
366 }
367 
368 /*
369  * Allocate a Solaris cred and initialize it based on the access token.
370  *
371  * If the user can be mapped to a non-ephemeral ID, the cred gid is set
372  * to the Solaris user's primary group.
373  *
374  * If the mapped UID is ephemeral, or the primary group could not be
375  * obtained, the cred gid is set to whatever Solaris group is mapped
376  * to the token's primary group.
377  */
378 static cred_t *
379 smb_cred_create(smb_token_t *token)
380 {
381 	ksid_t			ksid;
382 	ksidlist_t		*ksidlist = NULL;
383 	smb_posix_grps_t	*posix_grps;
384 	cred_t			*cr;
385 	gid_t			gid;
386 
387 	ASSERT(token);
388 	ASSERT(token->tkn_posix_grps);
389 	posix_grps = token->tkn_posix_grps;
390 
391 	cr = crget();
392 	ASSERT(cr != NULL);
393 
394 	if (!IDMAP_ID_IS_EPHEMERAL(token->tkn_user.i_id) &&
395 	    (posix_grps->pg_ngrps != 0)) {
396 		gid = posix_grps->pg_grps[0];
397 	} else {
398 		gid = token->tkn_primary_grp.i_id;
399 	}
400 
401 	if (crsetugid(cr, token->tkn_user.i_id, gid) != 0) {
402 		crfree(cr);
403 		return (NULL);
404 	}
405 
406 	if (crsetgroups(cr, posix_grps->pg_ngrps, posix_grps->pg_grps) != 0) {
407 		crfree(cr);
408 		return (NULL);
409 	}
410 
411 	smb_cred_set_sid(&token->tkn_user, &ksid);
412 	crsetsid(cr, &ksid, KSID_USER);
413 	smb_cred_set_sid(&token->tkn_primary_grp, &ksid);
414 	crsetsid(cr, &ksid, KSID_GROUP);
415 	smb_cred_set_sid(&token->tkn_owner, &ksid);
416 	crsetsid(cr, &ksid, KSID_OWNER);
417 	ksidlist = smb_cred_set_sidlist(&token->tkn_win_grps);
418 	crsetsidlist(cr, ksidlist);
419 
420 	if (smb_token_query_privilege(token, SE_TAKE_OWNERSHIP_LUID))
421 		(void) crsetpriv(cr, PRIV_FILE_CHOWN, NULL);
422 
423 	return (cr);
424 }
425 
426 /*
427  * Initialize the ksid based on the given smb_id_t.
428  */
429 static void
430 smb_cred_set_sid(smb_id_t *id, ksid_t *ksid)
431 {
432 	char sidstr[SMB_SID_STRSZ];
433 	int rc;
434 
435 	ASSERT(id);
436 	ASSERT(id->i_sid);
437 
438 	ksid->ks_id = id->i_id;
439 	smb_sid_tostr(id->i_sid, sidstr);
440 	rc = smb_sid_splitstr(sidstr, &ksid->ks_rid);
441 	ASSERT(rc == 0);
442 
443 	ksid->ks_attr = id->i_attrs;
444 	ksid->ks_domain = ksid_lookupdomain(sidstr);
445 }
446 
447 /*
448  * Allocate and initialize the ksidlist based on the access token group list.
449  */
450 static ksidlist_t *
451 smb_cred_set_sidlist(smb_ids_t *token_grps)
452 {
453 	int i;
454 	ksidlist_t *lp;
455 
456 	lp = kmem_zalloc(KSIDLIST_MEM(token_grps->i_cnt), KM_SLEEP);
457 	lp->ksl_ref = 1;
458 	lp->ksl_nsid = token_grps->i_cnt;
459 	lp->ksl_neid = 0;
460 
461 	for (i = 0; i < lp->ksl_nsid; i++) {
462 		smb_cred_set_sid(&token_grps->i_ids[i], &lp->ksl_sids[i]);
463 		if (lp->ksl_sids[i].ks_id > IDMAP_WK__MAX_GID)
464 			lp->ksl_neid++;
465 	}
466 
467 	return (lp);
468 }
469 
470 /*
471  * Convert access token privileges to local definitions.
472  */
473 static uint32_t
474 smb_priv_xlate(smb_token_t *token)
475 {
476 	uint32_t	privileges = 0;
477 
478 	if (smb_token_query_privilege(token, SE_BACKUP_LUID))
479 		privileges |= SMB_USER_PRIV_BACKUP;
480 
481 	if (smb_token_query_privilege(token, SE_RESTORE_LUID))
482 		privileges |= SMB_USER_PRIV_RESTORE;
483 
484 	if (smb_token_query_privilege(token, SE_TAKE_OWNERSHIP_LUID))
485 		privileges |= SMB_USER_PRIV_TAKE_OWNERSHIP;
486 
487 	if (smb_token_query_privilege(token, SE_SECURITY_LUID))
488 		privileges |= SMB_USER_PRIV_SECURITY;
489 
490 	return (privileges);
491 }
492