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
34static int smb_authenticate(smb_request_t *, smb_arg_sessionsetup_t *,
35    smb_session_key_t **);
36static int smb_authenticate_core(smb_request_t *, smb_arg_sessionsetup_t *,
37    smb_session_key_t **);
38static cred_t *smb_cred_create(smb_token_t *);
39static void smb_cred_set_sid(smb_id_t *id, ksid_t *ksid);
40static ksidlist_t *smb_cred_set_sidlist(smb_ids_t *token_grps);
41static 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 */
59smb_sdrc_t
60smb_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
138pre_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
144void
145smb_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 */
175smb_sdrc_t
176smb_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
231static int
232smb_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 */
256static int
257smb_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 */
400static cred_t *
401smb_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 */
451static void
452smb_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 */
472static ksidlist_t *
473smb_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 */
495static uint32_t
496smb_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