xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c (revision 9fb67ea305c66b6a297583b9b0db6796b0dfe497)
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 2010 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <netinet/in.h>
29 #include <smbsrv/smb_kproto.h>
30 #include <smbsrv/smb_token.h>
31 
32 typedef struct smb_sessionsetup_info {
33 	char		*ssi_user;
34 	char		*ssi_domain;
35 	char		*ssi_native_os;
36 	char		*ssi_native_lm;
37 	uint16_t	ssi_cipwlen;
38 	uint8_t		*ssi_cipwd;
39 	uint16_t	ssi_cspwlen;
40 	uint8_t		*ssi_cspwd;
41 	uint16_t	ssi_maxbufsize;
42 	uint16_t	ssi_maxmpxcount;
43 	uint16_t	ssi_vcnumber;
44 	uint32_t	ssi_capabilities;
45 	uint32_t	ssi_sesskey;
46 } smb_sessionsetup_info_t;
47 
48 #define	SMB_AUTH_FAILED	-1
49 #define	SMB_AUTH_USER	0
50 #define	SMB_AUTH_GUEST	1
51 
52 static int smb_authenticate(smb_request_t *, smb_sessionsetup_info_t *,
53     smb_session_key_t **);
54 
55 smb_sdrc_t
56 smb_pre_session_setup_andx(smb_request_t *sr)
57 {
58 	DTRACE_SMB_1(op__SessionSetupX__start, smb_request_t *, sr);
59 	return (SDRC_SUCCESS);
60 }
61 
62 void
63 smb_post_session_setup_andx(smb_request_t *sr)
64 {
65 	DTRACE_SMB_1(op__SessionSetupX__done, smb_request_t *, sr);
66 }
67 
68 smb_sdrc_t
69 smb_com_session_setup_andx(smb_request_t *sr)
70 {
71 	smb_sessionsetup_info_t	sinfo;
72 	smb_session_key_t	*session_key = NULL;
73 	char			ipaddr_buf[INET6_ADDRSTRLEN];
74 	int			native_lm;
75 	int			auth_res;
76 	int			rc;
77 
78 	bzero(&sinfo, sizeof (smb_sessionsetup_info_t));
79 
80 	if (sr->session->dialect >= NT_LM_0_12) {
81 		rc = smbsr_decode_vwv(sr, "b.wwwwlww4.l", &sr->andx_com,
82 		    &sr->andx_off, &sinfo.ssi_maxbufsize,
83 		    &sinfo.ssi_maxmpxcount, &sinfo.ssi_vcnumber,
84 		    &sinfo.ssi_sesskey, &sinfo.ssi_cipwlen,
85 		    &sinfo.ssi_cspwlen, &sinfo.ssi_capabilities);
86 
87 		if (rc != 0)
88 			return (SDRC_ERROR);
89 
90 		sinfo.ssi_cipwd = smb_srm_zalloc(sr, sinfo.ssi_cipwlen + 1);
91 		sinfo.ssi_cspwd = smb_srm_zalloc(sr, sinfo.ssi_cspwlen + 1);
92 
93 		/*
94 		 * The padding between the Native OS and Native LM is a
95 		 * bit strange. On NT4.0, there is a 2 byte pad between
96 		 * the OS (Windows NT 1381) and LM (Windows NT 4.0).
97 		 * On Windows 2000, there is no padding between the OS
98 		 * (Windows 2000 2195) and LM (Windows 2000 5.0).
99 		 *
100 		 * If the padding is removed from this decode string
101 		 * the NT4.0 LM comes out as an empty string.
102 		 *
103 		 * So if the client's native OS is Win NT we consider
104 		 * the padding otherwise we don't.
105 		 */
106 		rc = smbsr_decode_data(sr, "%#c#cuuu",
107 		    sr,
108 		    sinfo.ssi_cipwlen, sinfo.ssi_cipwd,
109 		    sinfo.ssi_cspwlen, sinfo.ssi_cspwd,
110 		    &sinfo.ssi_user,
111 		    &sinfo.ssi_domain,
112 		    &sinfo.ssi_native_os);
113 
114 		if (rc != 0)
115 			return (SDRC_ERROR);
116 
117 		sinfo.ssi_cipwd[sinfo.ssi_cipwlen] = 0;
118 		sinfo.ssi_cspwd[sinfo.ssi_cspwlen] = 0;
119 
120 		sr->session->native_os =
121 		    smbnative_os_value(sinfo.ssi_native_os);
122 
123 		if (sr->session->native_os == NATIVE_OS_WINNT)
124 			rc = smbsr_decode_data(sr, "%,u", sr,
125 			    &sinfo.ssi_native_lm);
126 		else
127 			rc = smbsr_decode_data(sr, "%u", sr,
128 			    &sinfo.ssi_native_lm);
129 
130 		/*
131 		 * If the Native Lanman cannot be determined,
132 		 * default to Windows NT.
133 		 */
134 		if (rc != 0 || sinfo.ssi_native_lm == NULL)
135 			sinfo.ssi_native_lm = "NT LAN Manager 4.0";
136 	} else {
137 		rc = smbsr_decode_vwv(sr, "b.wwwwlw4.", &sr->andx_com,
138 		    &sr->andx_off, &sinfo.ssi_maxbufsize,
139 		    &sinfo.ssi_maxmpxcount,
140 		    &sinfo.ssi_vcnumber, &sinfo.ssi_sesskey,
141 		    &sinfo.ssi_cipwlen);
142 
143 		if (rc != 0)
144 			return (SDRC_ERROR);
145 
146 		sinfo.ssi_cipwd = smb_srm_zalloc(sr, sinfo.ssi_cipwlen + 1);
147 		rc = smbsr_decode_data(sr, "%#c", sr, sinfo.ssi_cipwlen,
148 		    sinfo.ssi_cipwd);
149 		if (rc != 0)
150 			return (SDRC_ERROR);
151 
152 		sinfo.ssi_cipwd[sinfo.ssi_cipwlen] = 0;
153 
154 		/*
155 		 * Despite the CIFS/1.0 spec, the rest of this message is
156 		 * not always present. We need to try to get the account
157 		 * name and the primary domain but we don't care about the
158 		 * the native OS or native LanMan fields.
159 		 */
160 		if (smbsr_decode_data(sr, "%u", sr, &sinfo.ssi_user) != 0)
161 			sinfo.ssi_user = "";
162 
163 		if (smbsr_decode_data(sr, "%u", sr, &sinfo.ssi_domain) != 0)
164 			sinfo.ssi_domain = "";
165 
166 		sr->session->native_os = NATIVE_OS_WINNT;
167 		sinfo.ssi_native_lm = "NT LAN Manager 4.0";
168 	}
169 
170 	/*
171 	 * If the sinfo.ssi_vcnumber is zero, we can discard any
172 	 * other connections associated with this client.
173 	 */
174 	sr->session->vcnumber = sinfo.ssi_vcnumber;
175 	if (sinfo.ssi_vcnumber == 0)
176 		smb_server_reconnection_check(sr->sr_server, sr->session);
177 
178 	auth_res = smb_authenticate(sr, &sinfo, &session_key);
179 	if (auth_res == SMB_AUTH_FAILED)
180 		return (SDRC_ERROR);
181 
182 	native_lm = smbnative_lm_value(sinfo.ssi_native_lm);
183 	if (native_lm == NATIVE_LM_WIN2000)
184 		sinfo.ssi_capabilities |= CAP_LARGE_FILES |
185 		    CAP_LARGE_READX | CAP_LARGE_WRITEX;
186 
187 	sr->session->smb_msg_size = sinfo.ssi_maxbufsize;
188 	sr->session->capabilities = sinfo.ssi_capabilities;
189 
190 	/*
191 	 * Check to see if SMB signing is enable, but if it is already turned
192 	 * on leave it.
193 	 * The first authenticated logon provides the MAC key and sequence
194 	 * numbers for signing all further session on the
195 	 * same network connection.
196 	 */
197 	if (!(sr->session->signing.flags & SMB_SIGNING_ENABLED) &&
198 	    (sr->session->secmode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) &&
199 	    (sr->smb_flg2 & SMB_FLAGS2_SMB_SECURITY_SIGNATURE) &&
200 	    session_key)
201 		smb_sign_init(sr, session_key, (char *)sinfo.ssi_cspwd,
202 		    sinfo.ssi_cspwlen);
203 
204 	if (!(sr->smb_flg2 & SMB_FLAGS2_SMB_SECURITY_SIGNATURE) &&
205 	    (sr->sr_cfg->skc_signing_required)) {
206 		(void) smb_inet_ntop(&sr->session->ipaddr, ipaddr_buf,
207 		    SMB_IPSTRLEN(sr->session->ipaddr.a_family));
208 		cmn_err(CE_NOTE,
209 		    "SmbSessonSetupX: client %s is not capable of signing",
210 		    ipaddr_buf);
211 		smbsr_error(sr, NT_STATUS_LOGON_FAILURE,
212 		    ERRDOS, ERROR_LOGON_FAILURE);
213 		return (SDRC_ERROR);
214 	}
215 
216 	rc = smbsr_encode_result(sr, 3, VAR_BCC, "bb.www%uuu",
217 	    3,
218 	    sr->andx_com,
219 	    -1,			/* andx_off */
220 	    (auth_res == SMB_AUTH_GUEST) ? 1 : 0,
221 	    VAR_BCC,
222 	    sr,
223 	    smbnative_os_str(&sr->sr_cfg->skc_version),
224 	    smbnative_lm_str(&sr->sr_cfg->skc_version),
225 	    sr->sr_cfg->skc_nbdomain);
226 
227 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
228 }
229 
230 /*
231  * Tries to authenticate the connected user.
232  *
233  * It first tries to see if the user has already been authenticated.
234  * If a match is found, the user structure in the session is duplicated
235  * and the function returns. Otherwise, user information is passed to
236  * smbd for authentication. If smbd can authenticate the user an access
237  * token structure is returned. A cred_t and user structure is created
238  * based on the returned access token.
239  */
240 static int
241 smb_authenticate(smb_request_t *sr, smb_sessionsetup_info_t *sinfo,
242     smb_session_key_t **session_key)
243 {
244 	char		*hostname = sr->sr_cfg->skc_hostname;
245 	int		security = sr->sr_cfg->skc_secmode;
246 	smb_token_t	*usr_token = NULL;
247 	smb_user_t	*user = NULL;
248 	smb_logon_t	user_info;
249 	boolean_t	need_lookup = B_FALSE;
250 	uint32_t	privileges;
251 	cred_t		*cr;
252 	char		*buf = NULL;
253 	char		*p;
254 
255 	bzero(&user_info, sizeof (smb_logon_t));
256 
257 	if ((*sinfo->ssi_user == '\0') &&
258 	    (sinfo->ssi_cspwlen == 0) &&
259 	    (sinfo->ssi_cipwlen == 0 ||
260 	    (sinfo->ssi_cipwlen == 1 && *sinfo->ssi_cipwd == '\0'))) {
261 		user_info.lg_e_username = "anonymous";
262 		user_info.lg_flags |= SMB_ATF_ANON;
263 	} else {
264 		user_info.lg_e_username = sinfo->ssi_user;
265 	}
266 	user_info.lg_e_domain = sinfo->ssi_domain;
267 
268 	/*
269 	 * Handle user@domain format.
270 	 *
271 	 * We need to extract the user and domain names but
272 	 * should keep the request data as is. This is important
273 	 * for some forms of authentication.
274 	 */
275 	if (*sinfo->ssi_domain == '\0') {
276 		buf = smb_mem_strdup(sinfo->ssi_user);
277 		if ((p = strchr(buf, '@')) != NULL) {
278 			*p = '\0';
279 			user_info.lg_e_username = buf;
280 			user_info.lg_e_domain = p + 1;
281 		}
282 	}
283 
284 	/*
285 	 * See if this user has already been authenticated.
286 	 *
287 	 * If no domain name is provided we cannot determine whether
288 	 * this is a local or domain user when server is operating
289 	 * in domain mode, so lookup will be done after authentication.
290 	 */
291 	if (security == SMB_SECMODE_WORKGRP) {
292 		user = smb_session_dup_user(sr->session, hostname,
293 		    user_info.lg_e_username);
294 	} else if (*user_info.lg_e_domain != '\0') {
295 		user = smb_session_dup_user(sr->session, user_info.lg_e_domain,
296 		    user_info.lg_e_username);
297 	} else {
298 		need_lookup = B_TRUE;
299 	}
300 
301 	if (user != NULL) {
302 		sr->user_cr = user->u_cred;
303 		sr->smb_uid = user->u_uid;
304 		sr->uid_user = user;
305 
306 		smb_mem_free(buf);
307 
308 		return ((user->u_flags & SMB_USER_FLAG_GUEST)
309 		    ? SMB_AUTH_GUEST : SMB_AUTH_USER);
310 	}
311 
312 	user_info.lg_level = NETR_NETWORK_LOGON;
313 	user_info.lg_domain = sinfo->ssi_domain;
314 	user_info.lg_username = sinfo->ssi_user;
315 	user_info.lg_workstation = sr->session->workstation;
316 	user_info.lg_clnt_ipaddr = sr->session->ipaddr;
317 	user_info.lg_local_ipaddr = sr->session->local_ipaddr;
318 	user_info.lg_local_port = sr->session->s_local_port;
319 	user_info.lg_challenge_key.val = sr->session->challenge_key;
320 	user_info.lg_challenge_key.len = sr->session->challenge_len;
321 	user_info.lg_nt_password.val = sinfo->ssi_cspwd;
322 	user_info.lg_nt_password.len = sinfo->ssi_cspwlen;
323 	user_info.lg_lm_password.val = sinfo->ssi_cipwd;
324 	user_info.lg_lm_password.len = sinfo->ssi_cipwlen;
325 	user_info.lg_native_os = sr->session->native_os;
326 	user_info.lg_native_lm = smbnative_lm_value(sinfo->ssi_native_lm);
327 
328 	DTRACE_PROBE1(smb__sessionsetup__clntinfo, smb_logon_t *,
329 	    &user_info);
330 
331 	usr_token = smb_get_token(&user_info);
332 
333 	smb_mem_free(buf);
334 
335 	if (usr_token == NULL) {
336 		smbsr_error(sr, 0, ERRSRV, ERRbadpw);
337 		return (SMB_AUTH_FAILED);
338 	}
339 
340 	if (need_lookup) {
341 		user = smb_session_dup_user(sr->session,
342 		    usr_token->tkn_domain_name, usr_token->tkn_account_name);
343 
344 		if (user != NULL) {
345 			sr->user_cr = user->u_cred;
346 			sr->smb_uid = user->u_uid;
347 			sr->uid_user = user;
348 
349 			smb_token_free(usr_token);
350 			return ((user->u_flags & SMB_USER_FLAG_GUEST)
351 			    ? SMB_AUTH_GUEST : SMB_AUTH_USER);
352 		}
353 	}
354 
355 	if (usr_token->tkn_session_key) {
356 		*session_key = smb_srm_zalloc(sr, sizeof (smb_session_key_t));
357 		(void) memcpy(*session_key, usr_token->tkn_session_key,
358 		    sizeof (smb_session_key_t));
359 	}
360 
361 	if ((cr = smb_cred_create(usr_token, &privileges)) != NULL) {
362 		user = smb_user_login(sr->session, cr,
363 		    usr_token->tkn_domain_name,
364 		    usr_token->tkn_account_name,
365 		    usr_token->tkn_flags,
366 		    privileges,
367 		    usr_token->tkn_audit_sid);
368 
369 		smb_cred_rele(user->u_cred);
370 		if (user->u_privcred)
371 			smb_cred_rele(user->u_privcred);
372 	}
373 
374 	smb_token_free(usr_token);
375 
376 	if (user == NULL) {
377 		smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_HANDLE);
378 		return (SMB_AUTH_FAILED);
379 	}
380 
381 	sr->user_cr = user->u_cred;
382 	sr->smb_uid = user->u_uid;
383 	sr->uid_user = user;
384 
385 	return ((user->u_flags & SMB_USER_FLAG_GUEST)
386 	    ? SMB_AUTH_GUEST : SMB_AUTH_USER);
387 }
388