xref: /openbmc/linux/fs/smb/client/sess.c (revision 36db6e8484ed455bbb320d89a119378897ae991c)
138c8a9a5SSteve French // SPDX-License-Identifier: LGPL-2.1
238c8a9a5SSteve French /*
338c8a9a5SSteve French  *
438c8a9a5SSteve French  *   SMB/CIFS session setup handling routines
538c8a9a5SSteve French  *
638c8a9a5SSteve French  *   Copyright (c) International Business Machines  Corp., 2006, 2009
738c8a9a5SSteve French  *   Author(s): Steve French (sfrench@us.ibm.com)
838c8a9a5SSteve French  *
938c8a9a5SSteve French  */
1038c8a9a5SSteve French 
1138c8a9a5SSteve French #include "cifspdu.h"
1238c8a9a5SSteve French #include "cifsglob.h"
1338c8a9a5SSteve French #include "cifsproto.h"
1438c8a9a5SSteve French #include "cifs_unicode.h"
1538c8a9a5SSteve French #include "cifs_debug.h"
1638c8a9a5SSteve French #include "ntlmssp.h"
1738c8a9a5SSteve French #include "nterr.h"
1838c8a9a5SSteve French #include <linux/utsname.h>
1938c8a9a5SSteve French #include <linux/slab.h>
2038c8a9a5SSteve French #include <linux/version.h>
2138c8a9a5SSteve French #include "cifsfs.h"
2238c8a9a5SSteve French #include "cifs_spnego.h"
2338c8a9a5SSteve French #include "smb2proto.h"
2438c8a9a5SSteve French #include "fs_context.h"
2538c8a9a5SSteve French 
2638c8a9a5SSteve French static int
27739bf98cSShyam Prasad N cifs_ses_add_channel(struct cifs_ses *ses,
2838c8a9a5SSteve French 		     struct cifs_server_iface *iface);
2938c8a9a5SSteve French 
3038c8a9a5SSteve French bool
is_server_using_iface(struct TCP_Server_Info * server,struct cifs_server_iface * iface)3138c8a9a5SSteve French is_server_using_iface(struct TCP_Server_Info *server,
3238c8a9a5SSteve French 		      struct cifs_server_iface *iface)
3338c8a9a5SSteve French {
3438c8a9a5SSteve French 	struct sockaddr_in *i4 = (struct sockaddr_in *)&iface->sockaddr;
3538c8a9a5SSteve French 	struct sockaddr_in6 *i6 = (struct sockaddr_in6 *)&iface->sockaddr;
3638c8a9a5SSteve French 	struct sockaddr_in *s4 = (struct sockaddr_in *)&server->dstaddr;
3738c8a9a5SSteve French 	struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)&server->dstaddr;
3838c8a9a5SSteve French 
3938c8a9a5SSteve French 	if (server->dstaddr.ss_family != iface->sockaddr.ss_family)
4038c8a9a5SSteve French 		return false;
4138c8a9a5SSteve French 	if (server->dstaddr.ss_family == AF_INET) {
4238c8a9a5SSteve French 		if (s4->sin_addr.s_addr != i4->sin_addr.s_addr)
4338c8a9a5SSteve French 			return false;
4438c8a9a5SSteve French 	} else if (server->dstaddr.ss_family == AF_INET6) {
4538c8a9a5SSteve French 		if (memcmp(&s6->sin6_addr, &i6->sin6_addr,
4638c8a9a5SSteve French 			   sizeof(i6->sin6_addr)) != 0)
4738c8a9a5SSteve French 			return false;
4838c8a9a5SSteve French 	} else {
4938c8a9a5SSteve French 		/* unknown family.. */
5038c8a9a5SSteve French 		return false;
5138c8a9a5SSteve French 	}
5238c8a9a5SSteve French 	return true;
5338c8a9a5SSteve French }
5438c8a9a5SSteve French 
is_ses_using_iface(struct cifs_ses * ses,struct cifs_server_iface * iface)5538c8a9a5SSteve French bool is_ses_using_iface(struct cifs_ses *ses, struct cifs_server_iface *iface)
5638c8a9a5SSteve French {
5738c8a9a5SSteve French 	int i;
5838c8a9a5SSteve French 
5938c8a9a5SSteve French 	spin_lock(&ses->chan_lock);
6038c8a9a5SSteve French 	for (i = 0; i < ses->chan_count; i++) {
6138c8a9a5SSteve French 		if (ses->chans[i].iface == iface) {
6238c8a9a5SSteve French 			spin_unlock(&ses->chan_lock);
6338c8a9a5SSteve French 			return true;
6438c8a9a5SSteve French 		}
6538c8a9a5SSteve French 	}
6638c8a9a5SSteve French 	spin_unlock(&ses->chan_lock);
6738c8a9a5SSteve French 	return false;
6838c8a9a5SSteve French }
6938c8a9a5SSteve French 
7038c8a9a5SSteve French /* channel helper functions. assumed that chan_lock is held by caller. */
7138c8a9a5SSteve French 
72c395f798SShyam Prasad N int
cifs_ses_get_chan_index(struct cifs_ses * ses,struct TCP_Server_Info * server)7338c8a9a5SSteve French cifs_ses_get_chan_index(struct cifs_ses *ses,
7438c8a9a5SSteve French 			struct TCP_Server_Info *server)
7538c8a9a5SSteve French {
7638c8a9a5SSteve French 	unsigned int i;
7738c8a9a5SSteve French 
782b1f28eeSShyam Prasad N 	/* if the channel is waiting for termination */
79824c15adSSteve French 	if (server && server->terminate)
802b1f28eeSShyam Prasad N 		return CIFS_INVAL_CHAN_INDEX;
812b1f28eeSShyam Prasad N 
8238c8a9a5SSteve French 	for (i = 0; i < ses->chan_count; i++) {
8338c8a9a5SSteve French 		if (ses->chans[i].server == server)
8438c8a9a5SSteve French 			return i;
8538c8a9a5SSteve French 	}
8638c8a9a5SSteve French 
8738c8a9a5SSteve French 	/* If we didn't find the channel, it is likely a bug */
8838c8a9a5SSteve French 	if (server)
8938c8a9a5SSteve French 		cifs_dbg(VFS, "unable to get chan index for server: 0x%llx",
9038c8a9a5SSteve French 			 server->conn_id);
91c395f798SShyam Prasad N 	return CIFS_INVAL_CHAN_INDEX;
9238c8a9a5SSteve French }
9338c8a9a5SSteve French 
9438c8a9a5SSteve French void
cifs_chan_set_in_reconnect(struct cifs_ses * ses,struct TCP_Server_Info * server)9538c8a9a5SSteve French cifs_chan_set_in_reconnect(struct cifs_ses *ses,
9638c8a9a5SSteve French 			     struct TCP_Server_Info *server)
9738c8a9a5SSteve French {
98c395f798SShyam Prasad N 	int chan_index = cifs_ses_get_chan_index(ses, server);
99c395f798SShyam Prasad N 
100c395f798SShyam Prasad N 	if (chan_index == CIFS_INVAL_CHAN_INDEX)
101c395f798SShyam Prasad N 		return;
10238c8a9a5SSteve French 
10338c8a9a5SSteve French 	ses->chans[chan_index].in_reconnect = true;
10438c8a9a5SSteve French }
10538c8a9a5SSteve French 
10638c8a9a5SSteve French void
cifs_chan_clear_in_reconnect(struct cifs_ses * ses,struct TCP_Server_Info * server)10738c8a9a5SSteve French cifs_chan_clear_in_reconnect(struct cifs_ses *ses,
10838c8a9a5SSteve French 			     struct TCP_Server_Info *server)
10938c8a9a5SSteve French {
11038c8a9a5SSteve French 	unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
111210c8b9dSSteve French 
112c395f798SShyam Prasad N 	if (chan_index == CIFS_INVAL_CHAN_INDEX)
113c395f798SShyam Prasad N 		return;
11438c8a9a5SSteve French 
11538c8a9a5SSteve French 	ses->chans[chan_index].in_reconnect = false;
11638c8a9a5SSteve French }
11738c8a9a5SSteve French 
11838c8a9a5SSteve French bool
cifs_chan_in_reconnect(struct cifs_ses * ses,struct TCP_Server_Info * server)11938c8a9a5SSteve French cifs_chan_in_reconnect(struct cifs_ses *ses,
12038c8a9a5SSteve French 			  struct TCP_Server_Info *server)
12138c8a9a5SSteve French {
12238c8a9a5SSteve French 	unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
123210c8b9dSSteve French 
124c395f798SShyam Prasad N 	if (chan_index == CIFS_INVAL_CHAN_INDEX)
125c395f798SShyam Prasad N 		return true;	/* err on the safer side */
12638c8a9a5SSteve French 
12738c8a9a5SSteve French 	return CIFS_CHAN_IN_RECONNECT(ses, chan_index);
12838c8a9a5SSteve French }
12938c8a9a5SSteve French 
13038c8a9a5SSteve French void
cifs_chan_set_need_reconnect(struct cifs_ses * ses,struct TCP_Server_Info * server)13138c8a9a5SSteve French cifs_chan_set_need_reconnect(struct cifs_ses *ses,
13238c8a9a5SSteve French 			     struct TCP_Server_Info *server)
13338c8a9a5SSteve French {
13438c8a9a5SSteve French 	unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
135210c8b9dSSteve French 
136c395f798SShyam Prasad N 	if (chan_index == CIFS_INVAL_CHAN_INDEX)
137c395f798SShyam Prasad N 		return;
13838c8a9a5SSteve French 
13938c8a9a5SSteve French 	set_bit(chan_index, &ses->chans_need_reconnect);
14038c8a9a5SSteve French 	cifs_dbg(FYI, "Set reconnect bitmask for chan %u; now 0x%lx\n",
14138c8a9a5SSteve French 		 chan_index, ses->chans_need_reconnect);
14238c8a9a5SSteve French }
14338c8a9a5SSteve French 
14438c8a9a5SSteve French void
cifs_chan_clear_need_reconnect(struct cifs_ses * ses,struct TCP_Server_Info * server)14538c8a9a5SSteve French cifs_chan_clear_need_reconnect(struct cifs_ses *ses,
14638c8a9a5SSteve French 			       struct TCP_Server_Info *server)
14738c8a9a5SSteve French {
14838c8a9a5SSteve French 	unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
149210c8b9dSSteve French 
150c395f798SShyam Prasad N 	if (chan_index == CIFS_INVAL_CHAN_INDEX)
151c395f798SShyam Prasad N 		return;
15238c8a9a5SSteve French 
15338c8a9a5SSteve French 	clear_bit(chan_index, &ses->chans_need_reconnect);
15438c8a9a5SSteve French 	cifs_dbg(FYI, "Cleared reconnect bitmask for chan %u; now 0x%lx\n",
15538c8a9a5SSteve French 		 chan_index, ses->chans_need_reconnect);
15638c8a9a5SSteve French }
15738c8a9a5SSteve French 
15838c8a9a5SSteve French bool
cifs_chan_needs_reconnect(struct cifs_ses * ses,struct TCP_Server_Info * server)15938c8a9a5SSteve French cifs_chan_needs_reconnect(struct cifs_ses *ses,
16038c8a9a5SSteve French 			  struct TCP_Server_Info *server)
16138c8a9a5SSteve French {
16238c8a9a5SSteve French 	unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
163210c8b9dSSteve French 
164c395f798SShyam Prasad N 	if (chan_index == CIFS_INVAL_CHAN_INDEX)
165c395f798SShyam Prasad N 		return true;	/* err on the safer side */
16638c8a9a5SSteve French 
16738c8a9a5SSteve French 	return CIFS_CHAN_NEEDS_RECONNECT(ses, chan_index);
16838c8a9a5SSteve French }
16938c8a9a5SSteve French 
17038c8a9a5SSteve French bool
cifs_chan_is_iface_active(struct cifs_ses * ses,struct TCP_Server_Info * server)17138c8a9a5SSteve French cifs_chan_is_iface_active(struct cifs_ses *ses,
17238c8a9a5SSteve French 			  struct TCP_Server_Info *server)
17338c8a9a5SSteve French {
17438c8a9a5SSteve French 	unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
175210c8b9dSSteve French 
176c395f798SShyam Prasad N 	if (chan_index == CIFS_INVAL_CHAN_INDEX)
177c395f798SShyam Prasad N 		return true;	/* err on the safer side */
17838c8a9a5SSteve French 
17938c8a9a5SSteve French 	return ses->chans[chan_index].iface &&
18038c8a9a5SSteve French 		ses->chans[chan_index].iface->is_active;
18138c8a9a5SSteve French }
18238c8a9a5SSteve French 
18338c8a9a5SSteve French /* returns number of channels added */
cifs_try_adding_channels(struct cifs_ses * ses)184739bf98cSShyam Prasad N int cifs_try_adding_channels(struct cifs_ses *ses)
18538c8a9a5SSteve French {
18638c8a9a5SSteve French 	struct TCP_Server_Info *server = ses->server;
18738c8a9a5SSteve French 	int old_chan_count, new_chan_count;
18838c8a9a5SSteve French 	int left;
18938c8a9a5SSteve French 	int rc = 0;
19038c8a9a5SSteve French 	int tries = 0;
1911cd8c353SShyam Prasad N 	size_t iface_weight = 0, iface_min_speed = 0;
19238c8a9a5SSteve French 	struct cifs_server_iface *iface = NULL, *niface = NULL;
1931cd8c353SShyam Prasad N 	struct cifs_server_iface *last_iface = NULL;
19438c8a9a5SSteve French 
19538c8a9a5SSteve French 	spin_lock(&ses->chan_lock);
19638c8a9a5SSteve French 
19738c8a9a5SSteve French 	new_chan_count = old_chan_count = ses->chan_count;
19838c8a9a5SSteve French 	left = ses->chan_max - ses->chan_count;
19938c8a9a5SSteve French 
20038c8a9a5SSteve French 	if (left <= 0) {
20138c8a9a5SSteve French 		spin_unlock(&ses->chan_lock);
20238c8a9a5SSteve French 		cifs_dbg(FYI,
20338c8a9a5SSteve French 			 "ses already at max_channels (%zu), nothing to open\n",
20438c8a9a5SSteve French 			 ses->chan_max);
20538c8a9a5SSteve French 		return 0;
20638c8a9a5SSteve French 	}
20738c8a9a5SSteve French 
20838c8a9a5SSteve French 	if (server->dialect < SMB30_PROT_ID) {
20938c8a9a5SSteve French 		spin_unlock(&ses->chan_lock);
21038c8a9a5SSteve French 		cifs_dbg(VFS, "multichannel is not supported on this protocol version, use 3.0 or above\n");
21138c8a9a5SSteve French 		return 0;
21238c8a9a5SSteve French 	}
21338c8a9a5SSteve French 
21438c8a9a5SSteve French 	if (!(server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL)) {
21538c8a9a5SSteve French 		spin_unlock(&ses->chan_lock);
21638c8a9a5SSteve French 		cifs_server_dbg(VFS, "no multichannel support\n");
21738c8a9a5SSteve French 		return 0;
21838c8a9a5SSteve French 	}
21938c8a9a5SSteve French 	spin_unlock(&ses->chan_lock);
22038c8a9a5SSteve French 
22138c8a9a5SSteve French 	while (left > 0) {
22238c8a9a5SSteve French 
22338c8a9a5SSteve French 		tries++;
22438c8a9a5SSteve French 		if (tries > 3*ses->chan_max) {
2251cd8c353SShyam Prasad N 			cifs_dbg(VFS, "too many channel open attempts (%d channels left to open)\n",
22638c8a9a5SSteve French 				 left);
22738c8a9a5SSteve French 			break;
22838c8a9a5SSteve French 		}
22938c8a9a5SSteve French 
23038c8a9a5SSteve French 		spin_lock(&ses->iface_lock);
23138c8a9a5SSteve French 		if (!ses->iface_count) {
23238c8a9a5SSteve French 			spin_unlock(&ses->iface_lock);
233997b0c26SShyam Prasad N 			cifs_dbg(ONCE, "server %s does not advertise interfaces\n",
2341cd8c353SShyam Prasad N 				      ses->server->hostname);
23538c8a9a5SSteve French 			break;
23638c8a9a5SSteve French 		}
23738c8a9a5SSteve French 
2381cd8c353SShyam Prasad N 		if (!iface)
2391cd8c353SShyam Prasad N 			iface = list_first_entry(&ses->iface_list, struct cifs_server_iface,
2401cd8c353SShyam Prasad N 						 iface_head);
2411cd8c353SShyam Prasad N 		last_iface = list_last_entry(&ses->iface_list, struct cifs_server_iface,
2421cd8c353SShyam Prasad N 					     iface_head);
2431cd8c353SShyam Prasad N 		iface_min_speed = last_iface->speed;
2441cd8c353SShyam Prasad N 
24538c8a9a5SSteve French 		list_for_each_entry_safe_from(iface, niface, &ses->iface_list,
24638c8a9a5SSteve French 				    iface_head) {
2471cd8c353SShyam Prasad N 			/* do not mix rdma and non-rdma interfaces */
2481cd8c353SShyam Prasad N 			if (iface->rdma_capable != ses->server->rdma)
2491cd8c353SShyam Prasad N 				continue;
2501cd8c353SShyam Prasad N 
25138c8a9a5SSteve French 			/* skip ifaces that are unusable */
25238c8a9a5SSteve French 			if (!iface->is_active ||
25338c8a9a5SSteve French 			    (is_ses_using_iface(ses, iface) &&
2541cd8c353SShyam Prasad N 			     !iface->rss_capable))
25538c8a9a5SSteve French 				continue;
2561cd8c353SShyam Prasad N 
2571cd8c353SShyam Prasad N 			/* check if we already allocated enough channels */
2581cd8c353SShyam Prasad N 			iface_weight = iface->speed / iface_min_speed;
2591cd8c353SShyam Prasad N 
2601cd8c353SShyam Prasad N 			if (iface->weight_fulfilled >= iface_weight)
2611cd8c353SShyam Prasad N 				continue;
26238c8a9a5SSteve French 
26338c8a9a5SSteve French 			/* take ref before unlock */
26438c8a9a5SSteve French 			kref_get(&iface->refcount);
26538c8a9a5SSteve French 
26638c8a9a5SSteve French 			spin_unlock(&ses->iface_lock);
267739bf98cSShyam Prasad N 			rc = cifs_ses_add_channel(ses, iface);
26838c8a9a5SSteve French 			spin_lock(&ses->iface_lock);
26938c8a9a5SSteve French 
27038c8a9a5SSteve French 			if (rc) {
27138c8a9a5SSteve French 				cifs_dbg(VFS, "failed to open extra channel on iface:%pIS rc=%d\n",
27238c8a9a5SSteve French 					 &iface->sockaddr,
27338c8a9a5SSteve French 					 rc);
27438c8a9a5SSteve French 				kref_put(&iface->refcount, release_iface);
275cff97d68SShyam Prasad N 				/* failure to add chan should increase weight */
276cff97d68SShyam Prasad N 				iface->weight_fulfilled++;
27738c8a9a5SSteve French 				continue;
27838c8a9a5SSteve French 			}
27938c8a9a5SSteve French 
2801cd8c353SShyam Prasad N 			iface->num_channels++;
2811cd8c353SShyam Prasad N 			iface->weight_fulfilled++;
2821cd8c353SShyam Prasad N 			cifs_dbg(VFS, "successfully opened new channel on iface:%pIS\n",
28338c8a9a5SSteve French 				 &iface->sockaddr);
28438c8a9a5SSteve French 			break;
28538c8a9a5SSteve French 		}
2861cd8c353SShyam Prasad N 
2871cd8c353SShyam Prasad N 		/* reached end of list. reset weight_fulfilled and start over */
2881cd8c353SShyam Prasad N 		if (list_entry_is_head(iface, &ses->iface_list, iface_head)) {
2891cd8c353SShyam Prasad N 			list_for_each_entry(iface, &ses->iface_list, iface_head)
2901cd8c353SShyam Prasad N 				iface->weight_fulfilled = 0;
2911cd8c353SShyam Prasad N 			spin_unlock(&ses->iface_lock);
2921cd8c353SShyam Prasad N 			iface = NULL;
2931cd8c353SShyam Prasad N 			continue;
2941cd8c353SShyam Prasad N 		}
29538c8a9a5SSteve French 		spin_unlock(&ses->iface_lock);
29638c8a9a5SSteve French 
29738c8a9a5SSteve French 		left--;
29838c8a9a5SSteve French 		new_chan_count++;
29938c8a9a5SSteve French 	}
30038c8a9a5SSteve French 
30138c8a9a5SSteve French 	return new_chan_count - old_chan_count;
30238c8a9a5SSteve French }
30338c8a9a5SSteve French 
30438c8a9a5SSteve French /*
3053e161536SShyam Prasad N  * called when multichannel is disabled by the server.
3063e161536SShyam Prasad N  * this always gets called from smb2_reconnect
3073e161536SShyam Prasad N  * and cannot get called in parallel threads.
3083e161536SShyam Prasad N  */
3093e161536SShyam Prasad N void
cifs_disable_secondary_channels(struct cifs_ses * ses)3103e161536SShyam Prasad N cifs_disable_secondary_channels(struct cifs_ses *ses)
3113e161536SShyam Prasad N {
3123e161536SShyam Prasad N 	int i, chan_count;
3133e161536SShyam Prasad N 	struct TCP_Server_Info *server;
3143e161536SShyam Prasad N 	struct cifs_server_iface *iface;
3153e161536SShyam Prasad N 
3163e161536SShyam Prasad N 	spin_lock(&ses->chan_lock);
3173e161536SShyam Prasad N 	chan_count = ses->chan_count;
3183e161536SShyam Prasad N 	if (chan_count == 1)
3193e161536SShyam Prasad N 		goto done;
3203e161536SShyam Prasad N 
3213e161536SShyam Prasad N 	ses->chan_count = 1;
3223e161536SShyam Prasad N 
3233e161536SShyam Prasad N 	/* for all secondary channels reset the need reconnect bit */
3243e161536SShyam Prasad N 	ses->chans_need_reconnect &= 1;
3253e161536SShyam Prasad N 
3263e161536SShyam Prasad N 	for (i = 1; i < chan_count; i++) {
3273e161536SShyam Prasad N 		iface = ses->chans[i].iface;
3283e161536SShyam Prasad N 		server = ses->chans[i].server;
3293e161536SShyam Prasad N 
33030b1d564SShyam Prasad N 		/*
33130b1d564SShyam Prasad N 		 * remove these references first, since we need to unlock
33230b1d564SShyam Prasad N 		 * the chan_lock here, since iface_lock is a higher lock
33330b1d564SShyam Prasad N 		 */
33430b1d564SShyam Prasad N 		ses->chans[i].iface = NULL;
33530b1d564SShyam Prasad N 		ses->chans[i].server = NULL;
33630b1d564SShyam Prasad N 		spin_unlock(&ses->chan_lock);
33730b1d564SShyam Prasad N 
3383e161536SShyam Prasad N 		if (iface) {
3393e161536SShyam Prasad N 			spin_lock(&ses->iface_lock);
3403e161536SShyam Prasad N 			iface->num_channels--;
3413e161536SShyam Prasad N 			if (iface->weight_fulfilled)
3423e161536SShyam Prasad N 				iface->weight_fulfilled--;
343a7b537b3SRitvik Budhiraja 			kref_put(&iface->refcount, release_iface);
3443e161536SShyam Prasad N 			spin_unlock(&ses->iface_lock);
3453e161536SShyam Prasad N 		}
3463e161536SShyam Prasad N 
34730b1d564SShyam Prasad N 		if (server) {
34830b1d564SShyam Prasad N 			if (!server->terminate) {
3493e161536SShyam Prasad N 				server->terminate = true;
3503e161536SShyam Prasad N 				cifs_signal_cifsd_for_reconnect(server, false);
3513e161536SShyam Prasad N 			}
3523e161536SShyam Prasad N 			cifs_put_tcp_session(server, false);
3533e161536SShyam Prasad N 		}
3543e161536SShyam Prasad N 
35530b1d564SShyam Prasad N 		spin_lock(&ses->chan_lock);
3563e161536SShyam Prasad N 	}
3573e161536SShyam Prasad N 
3583e161536SShyam Prasad N done:
3593e161536SShyam Prasad N 	spin_unlock(&ses->chan_lock);
3603e161536SShyam Prasad N }
3613e161536SShyam Prasad N 
3623e161536SShyam Prasad N /*
36338c8a9a5SSteve French  * update the iface for the channel if necessary.
36438c8a9a5SSteve French  * Must be called with chan_lock held.
36538c8a9a5SSteve French  */
3660845cb6bSDan Carpenter void
cifs_chan_update_iface(struct cifs_ses * ses,struct TCP_Server_Info * server)36738c8a9a5SSteve French cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
36838c8a9a5SSteve French {
36938c8a9a5SSteve French 	unsigned int chan_index;
3701cd8c353SShyam Prasad N 	size_t iface_weight = 0, iface_min_speed = 0;
37138c8a9a5SSteve French 	struct cifs_server_iface *iface = NULL;
37238c8a9a5SSteve French 	struct cifs_server_iface *old_iface = NULL;
3731cd8c353SShyam Prasad N 	struct cifs_server_iface *last_iface = NULL;
374d0b5a680SShyam Prasad N 	struct sockaddr_storage ss;
37538c8a9a5SSteve French 
37638c8a9a5SSteve French 	spin_lock(&ses->chan_lock);
37738c8a9a5SSteve French 	chan_index = cifs_ses_get_chan_index(ses, server);
378c395f798SShyam Prasad N 	if (chan_index == CIFS_INVAL_CHAN_INDEX) {
37938c8a9a5SSteve French 		spin_unlock(&ses->chan_lock);
3800845cb6bSDan Carpenter 		return;
38138c8a9a5SSteve French 	}
38238c8a9a5SSteve French 
38338c8a9a5SSteve French 	if (ses->chans[chan_index].iface) {
38438c8a9a5SSteve French 		old_iface = ses->chans[chan_index].iface;
38538c8a9a5SSteve French 		if (old_iface->is_active) {
38638c8a9a5SSteve French 			spin_unlock(&ses->chan_lock);
3870845cb6bSDan Carpenter 			return;
38838c8a9a5SSteve French 		}
38938c8a9a5SSteve French 	}
39038c8a9a5SSteve French 	spin_unlock(&ses->chan_lock);
39138c8a9a5SSteve French 
392d0b5a680SShyam Prasad N 	spin_lock(&server->srv_lock);
393d0b5a680SShyam Prasad N 	ss = server->dstaddr;
394d0b5a680SShyam Prasad N 	spin_unlock(&server->srv_lock);
395d0b5a680SShyam Prasad N 
39638c8a9a5SSteve French 	spin_lock(&ses->iface_lock);
3971cd8c353SShyam Prasad N 	if (!ses->iface_count) {
3981cd8c353SShyam Prasad N 		spin_unlock(&ses->iface_lock);
399997b0c26SShyam Prasad N 		cifs_dbg(ONCE, "server %s does not advertise interfaces\n", ses->server->hostname);
4000845cb6bSDan Carpenter 		return;
4011cd8c353SShyam Prasad N 	}
4021cd8c353SShyam Prasad N 
4031cd8c353SShyam Prasad N 	last_iface = list_last_entry(&ses->iface_list, struct cifs_server_iface,
4041cd8c353SShyam Prasad N 				     iface_head);
4051cd8c353SShyam Prasad N 	iface_min_speed = last_iface->speed;
4061cd8c353SShyam Prasad N 
40738c8a9a5SSteve French 	/* then look for a new one */
40838c8a9a5SSteve French 	list_for_each_entry(iface, &ses->iface_list, iface_head) {
409d0b5a680SShyam Prasad N 		if (!chan_index) {
410d0b5a680SShyam Prasad N 			/* if we're trying to get the updated iface for primary channel */
411d0b5a680SShyam Prasad N 			if (!cifs_match_ipaddr((struct sockaddr *) &ss,
412d0b5a680SShyam Prasad N 					       (struct sockaddr *) &iface->sockaddr))
413d0b5a680SShyam Prasad N 				continue;
414d0b5a680SShyam Prasad N 
415d0b5a680SShyam Prasad N 			kref_get(&iface->refcount);
416d0b5a680SShyam Prasad N 			break;
417d0b5a680SShyam Prasad N 		}
418d0b5a680SShyam Prasad N 
4191cd8c353SShyam Prasad N 		/* do not mix rdma and non-rdma interfaces */
4201cd8c353SShyam Prasad N 		if (iface->rdma_capable != server->rdma)
4211cd8c353SShyam Prasad N 			continue;
4221cd8c353SShyam Prasad N 
42338c8a9a5SSteve French 		if (!iface->is_active ||
42438c8a9a5SSteve French 		    (is_ses_using_iface(ses, iface) &&
42538c8a9a5SSteve French 		     !iface->rss_capable)) {
42638c8a9a5SSteve French 			continue;
42738c8a9a5SSteve French 		}
4281cd8c353SShyam Prasad N 
4291cd8c353SShyam Prasad N 		/* check if we already allocated enough channels */
4301cd8c353SShyam Prasad N 		iface_weight = iface->speed / iface_min_speed;
4311cd8c353SShyam Prasad N 
4321cd8c353SShyam Prasad N 		if (iface->weight_fulfilled >= iface_weight)
4331cd8c353SShyam Prasad N 			continue;
4341cd8c353SShyam Prasad N 
43538c8a9a5SSteve French 		kref_get(&iface->refcount);
43638c8a9a5SSteve French 		break;
43738c8a9a5SSteve French 	}
43838c8a9a5SSteve French 
43938c8a9a5SSteve French 	if (list_entry_is_head(iface, &ses->iface_list, iface_head)) {
44038c8a9a5SSteve French 		iface = NULL;
44138c8a9a5SSteve French 		cifs_dbg(FYI, "unable to find a suitable iface\n");
44238c8a9a5SSteve French 	}
44338c8a9a5SSteve French 
444db3a3e6fSShyam Prasad N 	if (!iface) {
445d53fcb48SSteve French 		if (!chan_index)
446d0b5a680SShyam Prasad N 			cifs_dbg(FYI, "unable to get the interface matching: %pIS\n",
447d0b5a680SShyam Prasad N 				 &ss);
448d53fcb48SSteve French 		else {
449d53fcb48SSteve French 			cifs_dbg(FYI, "unable to find another interface to replace: %pIS\n",
450d53fcb48SSteve French 				 &old_iface->sockaddr);
451d53fcb48SSteve French 		}
452d53fcb48SSteve French 
453d0b5a680SShyam Prasad N 		spin_unlock(&ses->iface_lock);
4540845cb6bSDan Carpenter 		return;
455d0b5a680SShyam Prasad N 	}
456d0b5a680SShyam Prasad N 
45738c8a9a5SSteve French 	/* now drop the ref to the current iface */
458db3a3e6fSShyam Prasad N 	if (old_iface) {
45938c8a9a5SSteve French 		cifs_dbg(FYI, "replacing iface: %pIS with %pIS\n",
46038c8a9a5SSteve French 			 &old_iface->sockaddr,
46138c8a9a5SSteve French 			 &iface->sockaddr);
4621cd8c353SShyam Prasad N 
4631cd8c353SShyam Prasad N 		old_iface->num_channels--;
4641cd8c353SShyam Prasad N 		if (old_iface->weight_fulfilled)
4651cd8c353SShyam Prasad N 			old_iface->weight_fulfilled--;
4661cd8c353SShyam Prasad N 		iface->num_channels++;
4671cd8c353SShyam Prasad N 		iface->weight_fulfilled++;
4681cd8c353SShyam Prasad N 
46938c8a9a5SSteve French 		kref_put(&old_iface->refcount, release_iface);
470d0b5a680SShyam Prasad N 	} else if (!chan_index) {
471d0b5a680SShyam Prasad N 		/* special case: update interface for primary channel */
472d0b5a680SShyam Prasad N 		cifs_dbg(FYI, "referencing primary channel iface: %pIS\n",
473d0b5a680SShyam Prasad N 			 &iface->sockaddr);
474d0b5a680SShyam Prasad N 		iface->num_channels++;
475d0b5a680SShyam Prasad N 		iface->weight_fulfilled++;
476db3a3e6fSShyam Prasad N 	}
47738c8a9a5SSteve French 	spin_unlock(&ses->iface_lock);
47838c8a9a5SSteve French 
47938c8a9a5SSteve French 	spin_lock(&ses->chan_lock);
48038c8a9a5SSteve French 	chan_index = cifs_ses_get_chan_index(ses, server);
481c395f798SShyam Prasad N 	if (chan_index == CIFS_INVAL_CHAN_INDEX) {
482c395f798SShyam Prasad N 		spin_unlock(&ses->chan_lock);
4830845cb6bSDan Carpenter 		return;
484c395f798SShyam Prasad N 	}
485c395f798SShyam Prasad N 
48638c8a9a5SSteve French 	ses->chans[chan_index].iface = iface;
48738c8a9a5SSteve French 	spin_unlock(&ses->chan_lock);
48838c8a9a5SSteve French }
48938c8a9a5SSteve French 
49038c8a9a5SSteve French /*
49138c8a9a5SSteve French  * If server is a channel of ses, return the corresponding enclosing
49238c8a9a5SSteve French  * cifs_chan otherwise return NULL.
49338c8a9a5SSteve French  */
49438c8a9a5SSteve French struct cifs_chan *
cifs_ses_find_chan(struct cifs_ses * ses,struct TCP_Server_Info * server)49538c8a9a5SSteve French cifs_ses_find_chan(struct cifs_ses *ses, struct TCP_Server_Info *server)
49638c8a9a5SSteve French {
49738c8a9a5SSteve French 	int i;
49838c8a9a5SSteve French 
49938c8a9a5SSteve French 	spin_lock(&ses->chan_lock);
50038c8a9a5SSteve French 	for (i = 0; i < ses->chan_count; i++) {
50138c8a9a5SSteve French 		if (ses->chans[i].server == server) {
50238c8a9a5SSteve French 			spin_unlock(&ses->chan_lock);
50338c8a9a5SSteve French 			return &ses->chans[i];
50438c8a9a5SSteve French 		}
50538c8a9a5SSteve French 	}
50638c8a9a5SSteve French 	spin_unlock(&ses->chan_lock);
50738c8a9a5SSteve French 	return NULL;
50838c8a9a5SSteve French }
50938c8a9a5SSteve French 
51038c8a9a5SSteve French static int
cifs_ses_add_channel(struct cifs_ses * ses,struct cifs_server_iface * iface)511739bf98cSShyam Prasad N cifs_ses_add_channel(struct cifs_ses *ses,
51238c8a9a5SSteve French 		     struct cifs_server_iface *iface)
51338c8a9a5SSteve French {
51438c8a9a5SSteve French 	struct TCP_Server_Info *chan_server;
51538c8a9a5SSteve French 	struct cifs_chan *chan;
51669a4e06cSPaulo Alcantara 	struct smb3_fs_context *ctx;
51738c8a9a5SSteve French 	static const char unc_fmt[] = "\\%s\\foo";
51838c8a9a5SSteve French 	struct sockaddr_in *ipv4 = (struct sockaddr_in *)&iface->sockaddr;
51938c8a9a5SSteve French 	struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)&iface->sockaddr;
52069a4e06cSPaulo Alcantara 	size_t len;
52138c8a9a5SSteve French 	int rc;
52238c8a9a5SSteve French 	unsigned int xid = get_xid();
52338c8a9a5SSteve French 
52438c8a9a5SSteve French 	if (iface->sockaddr.ss_family == AF_INET)
52538c8a9a5SSteve French 		cifs_dbg(FYI, "adding channel to ses %p (speed:%zu bps rdma:%s ip:%pI4)\n",
52638c8a9a5SSteve French 			 ses, iface->speed, iface->rdma_capable ? "yes" : "no",
52738c8a9a5SSteve French 			 &ipv4->sin_addr);
52838c8a9a5SSteve French 	else
52938c8a9a5SSteve French 		cifs_dbg(FYI, "adding channel to ses %p (speed:%zu bps rdma:%s ip:%pI6)\n",
53038c8a9a5SSteve French 			 ses, iface->speed, iface->rdma_capable ? "yes" : "no",
53138c8a9a5SSteve French 			 &ipv6->sin6_addr);
53238c8a9a5SSteve French 
53338c8a9a5SSteve French 	/*
53438c8a9a5SSteve French 	 * Setup a ctx with mostly the same info as the existing
53538c8a9a5SSteve French 	 * session and overwrite it with the requested iface data.
53638c8a9a5SSteve French 	 *
53738c8a9a5SSteve French 	 * We need to setup at least the fields used for negprot and
53838c8a9a5SSteve French 	 * sesssetup.
53938c8a9a5SSteve French 	 *
54038c8a9a5SSteve French 	 * We only need the ctx here, so we can reuse memory from
54138c8a9a5SSteve French 	 * the session and server without caring about memory
54238c8a9a5SSteve French 	 * management.
54338c8a9a5SSteve French 	 */
54469a4e06cSPaulo Alcantara 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
54569a4e06cSPaulo Alcantara 	if (!ctx) {
54669a4e06cSPaulo Alcantara 		rc = -ENOMEM;
54769a4e06cSPaulo Alcantara 		goto out_free_xid;
54869a4e06cSPaulo Alcantara 	}
54938c8a9a5SSteve French 
55038c8a9a5SSteve French 	/* Always make new connection for now (TODO?) */
55169a4e06cSPaulo Alcantara 	ctx->nosharesock = true;
55238c8a9a5SSteve French 
55338c8a9a5SSteve French 	/* Auth */
55469a4e06cSPaulo Alcantara 	ctx->domainauto = ses->domainAuto;
55569a4e06cSPaulo Alcantara 	ctx->domainname = ses->domainName;
55638c8a9a5SSteve French 
55738c8a9a5SSteve French 	/* no hostname for extra channels */
55869a4e06cSPaulo Alcantara 	ctx->server_hostname = "";
55938c8a9a5SSteve French 
56069a4e06cSPaulo Alcantara 	ctx->username = ses->user_name;
56169a4e06cSPaulo Alcantara 	ctx->password = ses->password;
56269a4e06cSPaulo Alcantara 	ctx->sectype = ses->sectype;
56369a4e06cSPaulo Alcantara 	ctx->sign = ses->sign;
56438c8a9a5SSteve French 
56538c8a9a5SSteve French 	/* UNC and paths */
56638c8a9a5SSteve French 	/* XXX: Use ses->server->hostname? */
56769a4e06cSPaulo Alcantara 	len = sizeof(unc_fmt) + SERVER_NAME_LEN_WITH_NULL;
56869a4e06cSPaulo Alcantara 	ctx->UNC = kzalloc(len, GFP_KERNEL);
56969a4e06cSPaulo Alcantara 	if (!ctx->UNC) {
57069a4e06cSPaulo Alcantara 		rc = -ENOMEM;
57169a4e06cSPaulo Alcantara 		goto out_free_ctx;
57269a4e06cSPaulo Alcantara 	}
57369a4e06cSPaulo Alcantara 	scnprintf(ctx->UNC, len, unc_fmt, ses->ip_addr);
57469a4e06cSPaulo Alcantara 	ctx->prepath = "";
57538c8a9a5SSteve French 
57638c8a9a5SSteve French 	/* Reuse same version as master connection */
57769a4e06cSPaulo Alcantara 	ctx->vals = ses->server->vals;
57869a4e06cSPaulo Alcantara 	ctx->ops = ses->server->ops;
57938c8a9a5SSteve French 
58069a4e06cSPaulo Alcantara 	ctx->noblocksnd = ses->server->noblocksnd;
58169a4e06cSPaulo Alcantara 	ctx->noautotune = ses->server->noautotune;
58269a4e06cSPaulo Alcantara 	ctx->sockopt_tcp_nodelay = ses->server->tcp_nodelay;
58369a4e06cSPaulo Alcantara 	ctx->echo_interval = ses->server->echo_interval / HZ;
58469a4e06cSPaulo Alcantara 	ctx->max_credits = ses->server->max_credits;
58538c8a9a5SSteve French 
58638c8a9a5SSteve French 	/*
58738c8a9a5SSteve French 	 * This will be used for encoding/decoding user/domain/pw
58838c8a9a5SSteve French 	 * during sess setup auth.
58938c8a9a5SSteve French 	 */
590739bf98cSShyam Prasad N 	ctx->local_nls = ses->local_nls;
59138c8a9a5SSteve French 
59238c8a9a5SSteve French 	/* Use RDMA if possible */
59369a4e06cSPaulo Alcantara 	ctx->rdma = iface->rdma_capable;
59469a4e06cSPaulo Alcantara 	memcpy(&ctx->dstaddr, &iface->sockaddr, sizeof(ctx->dstaddr));
59538c8a9a5SSteve French 
59638c8a9a5SSteve French 	/* reuse master con client guid */
59769a4e06cSPaulo Alcantara 	memcpy(&ctx->client_guid, ses->server->client_guid,
59869a4e06cSPaulo Alcantara 	       sizeof(ctx->client_guid));
59969a4e06cSPaulo Alcantara 	ctx->use_client_guid = true;
60038c8a9a5SSteve French 
60169a4e06cSPaulo Alcantara 	chan_server = cifs_get_tcp_session(ctx, ses->server);
60238c8a9a5SSteve French 
60338c8a9a5SSteve French 	spin_lock(&ses->chan_lock);
60438c8a9a5SSteve French 	chan = &ses->chans[ses->chan_count];
60538c8a9a5SSteve French 	chan->server = chan_server;
60638c8a9a5SSteve French 	if (IS_ERR(chan->server)) {
60738c8a9a5SSteve French 		rc = PTR_ERR(chan->server);
60838c8a9a5SSteve French 		chan->server = NULL;
60938c8a9a5SSteve French 		spin_unlock(&ses->chan_lock);
61038c8a9a5SSteve French 		goto out;
61138c8a9a5SSteve French 	}
61238c8a9a5SSteve French 	chan->iface = iface;
61338c8a9a5SSteve French 	ses->chan_count++;
61438c8a9a5SSteve French 	atomic_set(&ses->chan_seq, 0);
61538c8a9a5SSteve French 
61638c8a9a5SSteve French 	/* Mark this channel as needing connect/setup */
61738c8a9a5SSteve French 	cifs_chan_set_need_reconnect(ses, chan->server);
61838c8a9a5SSteve French 
61938c8a9a5SSteve French 	spin_unlock(&ses->chan_lock);
62038c8a9a5SSteve French 
62138c8a9a5SSteve French 	mutex_lock(&ses->session_mutex);
62238c8a9a5SSteve French 	/*
62338c8a9a5SSteve French 	 * We need to allocate the server crypto now as we will need
62438c8a9a5SSteve French 	 * to sign packets before we generate the channel signing key
62538c8a9a5SSteve French 	 * (we sign with the session key)
62638c8a9a5SSteve French 	 */
62738c8a9a5SSteve French 	rc = smb311_crypto_shash_allocate(chan->server);
62838c8a9a5SSteve French 	if (rc) {
62938c8a9a5SSteve French 		cifs_dbg(VFS, "%s: crypto alloc failed\n", __func__);
63038c8a9a5SSteve French 		mutex_unlock(&ses->session_mutex);
63138c8a9a5SSteve French 		goto out;
63238c8a9a5SSteve French 	}
63338c8a9a5SSteve French 
63438c8a9a5SSteve French 	rc = cifs_negotiate_protocol(xid, ses, chan->server);
63538c8a9a5SSteve French 	if (!rc)
636739bf98cSShyam Prasad N 		rc = cifs_setup_session(xid, ses, chan->server, ses->local_nls);
63738c8a9a5SSteve French 
63838c8a9a5SSteve French 	mutex_unlock(&ses->session_mutex);
63938c8a9a5SSteve French 
64038c8a9a5SSteve French out:
64138c8a9a5SSteve French 	if (rc && chan->server) {
6423e161536SShyam Prasad N 		cifs_put_tcp_session(chan->server, 0);
64338c8a9a5SSteve French 
64438c8a9a5SSteve French 		spin_lock(&ses->chan_lock);
6453e161536SShyam Prasad N 
64638c8a9a5SSteve French 		/* we rely on all bits beyond chan_count to be clear */
64738c8a9a5SSteve French 		cifs_chan_clear_need_reconnect(ses, chan->server);
64838c8a9a5SSteve French 		ses->chan_count--;
64938c8a9a5SSteve French 		/*
65038c8a9a5SSteve French 		 * chan_count should never reach 0 as at least the primary
65138c8a9a5SSteve French 		 * channel is always allocated
65238c8a9a5SSteve French 		 */
65338c8a9a5SSteve French 		WARN_ON(ses->chan_count < 1);
65438c8a9a5SSteve French 		spin_unlock(&ses->chan_lock);
65538c8a9a5SSteve French 	}
65638c8a9a5SSteve French 
65769a4e06cSPaulo Alcantara 	kfree(ctx->UNC);
65869a4e06cSPaulo Alcantara out_free_ctx:
65969a4e06cSPaulo Alcantara 	kfree(ctx);
66069a4e06cSPaulo Alcantara out_free_xid:
66138c8a9a5SSteve French 	free_xid(xid);
66238c8a9a5SSteve French 	return rc;
66338c8a9a5SSteve French }
66438c8a9a5SSteve French 
66538c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
cifs_ssetup_hdr(struct cifs_ses * ses,struct TCP_Server_Info * server,SESSION_SETUP_ANDX * pSMB)66638c8a9a5SSteve French static __u32 cifs_ssetup_hdr(struct cifs_ses *ses,
66738c8a9a5SSteve French 			     struct TCP_Server_Info *server,
66838c8a9a5SSteve French 			     SESSION_SETUP_ANDX *pSMB)
66938c8a9a5SSteve French {
67038c8a9a5SSteve French 	__u32 capabilities = 0;
67138c8a9a5SSteve French 
67238c8a9a5SSteve French 	/* init fields common to all four types of SessSetup */
67338c8a9a5SSteve French 	/* Note that offsets for first seven fields in req struct are same  */
67438c8a9a5SSteve French 	/*	in CIFS Specs so does not matter which of 3 forms of struct */
67538c8a9a5SSteve French 	/*	that we use in next few lines                               */
67638c8a9a5SSteve French 	/* Note that header is initialized to zero in header_assemble */
67738c8a9a5SSteve French 	pSMB->req.AndXCommand = 0xFF;
67838c8a9a5SSteve French 	pSMB->req.MaxBufferSize = cpu_to_le16(min_t(u32,
67938c8a9a5SSteve French 					CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4,
68038c8a9a5SSteve French 					USHRT_MAX));
68138c8a9a5SSteve French 	pSMB->req.MaxMpxCount = cpu_to_le16(server->maxReq);
68238c8a9a5SSteve French 	pSMB->req.VcNumber = cpu_to_le16(1);
68338c8a9a5SSteve French 
68438c8a9a5SSteve French 	/* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */
68538c8a9a5SSteve French 
686210c8b9dSSteve French 	/* BB verify whether signing required on neg or just auth frame (and NTLM case) */
68738c8a9a5SSteve French 
68838c8a9a5SSteve French 	capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
68938c8a9a5SSteve French 			CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
69038c8a9a5SSteve French 
69138c8a9a5SSteve French 	if (server->sign)
69238c8a9a5SSteve French 		pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
69338c8a9a5SSteve French 
69438c8a9a5SSteve French 	if (ses->capabilities & CAP_UNICODE) {
69538c8a9a5SSteve French 		pSMB->req.hdr.Flags2 |= SMBFLG2_UNICODE;
69638c8a9a5SSteve French 		capabilities |= CAP_UNICODE;
69738c8a9a5SSteve French 	}
69838c8a9a5SSteve French 	if (ses->capabilities & CAP_STATUS32) {
69938c8a9a5SSteve French 		pSMB->req.hdr.Flags2 |= SMBFLG2_ERR_STATUS;
70038c8a9a5SSteve French 		capabilities |= CAP_STATUS32;
70138c8a9a5SSteve French 	}
70238c8a9a5SSteve French 	if (ses->capabilities & CAP_DFS) {
70338c8a9a5SSteve French 		pSMB->req.hdr.Flags2 |= SMBFLG2_DFS;
70438c8a9a5SSteve French 		capabilities |= CAP_DFS;
70538c8a9a5SSteve French 	}
70638c8a9a5SSteve French 	if (ses->capabilities & CAP_UNIX)
70738c8a9a5SSteve French 		capabilities |= CAP_UNIX;
70838c8a9a5SSteve French 
70938c8a9a5SSteve French 	return capabilities;
71038c8a9a5SSteve French }
71138c8a9a5SSteve French 
71238c8a9a5SSteve French static void
unicode_oslm_strings(char ** pbcc_area,const struct nls_table * nls_cp)71338c8a9a5SSteve French unicode_oslm_strings(char **pbcc_area, const struct nls_table *nls_cp)
71438c8a9a5SSteve French {
71538c8a9a5SSteve French 	char *bcc_ptr = *pbcc_area;
71638c8a9a5SSteve French 	int bytes_ret = 0;
71738c8a9a5SSteve French 
71838c8a9a5SSteve French 	/* Copy OS version */
71938c8a9a5SSteve French 	bytes_ret = cifs_strtoUTF16((__le16 *)bcc_ptr, "Linux version ", 32,
72038c8a9a5SSteve French 				    nls_cp);
72138c8a9a5SSteve French 	bcc_ptr += 2 * bytes_ret;
72238c8a9a5SSteve French 	bytes_ret = cifs_strtoUTF16((__le16 *) bcc_ptr, init_utsname()->release,
72338c8a9a5SSteve French 				    32, nls_cp);
72438c8a9a5SSteve French 	bcc_ptr += 2 * bytes_ret;
72538c8a9a5SSteve French 	bcc_ptr += 2; /* trailing null */
72638c8a9a5SSteve French 
72738c8a9a5SSteve French 	bytes_ret = cifs_strtoUTF16((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
72838c8a9a5SSteve French 				    32, nls_cp);
72938c8a9a5SSteve French 	bcc_ptr += 2 * bytes_ret;
73038c8a9a5SSteve French 	bcc_ptr += 2; /* trailing null */
73138c8a9a5SSteve French 
73238c8a9a5SSteve French 	*pbcc_area = bcc_ptr;
73338c8a9a5SSteve French }
73438c8a9a5SSteve French 
unicode_domain_string(char ** pbcc_area,struct cifs_ses * ses,const struct nls_table * nls_cp)73538c8a9a5SSteve French static void unicode_domain_string(char **pbcc_area, struct cifs_ses *ses,
73638c8a9a5SSteve French 				   const struct nls_table *nls_cp)
73738c8a9a5SSteve French {
73838c8a9a5SSteve French 	char *bcc_ptr = *pbcc_area;
73938c8a9a5SSteve French 	int bytes_ret = 0;
74038c8a9a5SSteve French 
74138c8a9a5SSteve French 	/* copy domain */
74238c8a9a5SSteve French 	if (ses->domainName == NULL) {
743210c8b9dSSteve French 		/*
744210c8b9dSSteve French 		 * Sending null domain better than using a bogus domain name (as
745210c8b9dSSteve French 		 * we did briefly in 2.6.18) since server will use its default
746210c8b9dSSteve French 		 */
74738c8a9a5SSteve French 		*bcc_ptr = 0;
74838c8a9a5SSteve French 		*(bcc_ptr+1) = 0;
74938c8a9a5SSteve French 		bytes_ret = 0;
75038c8a9a5SSteve French 	} else
75138c8a9a5SSteve French 		bytes_ret = cifs_strtoUTF16((__le16 *) bcc_ptr, ses->domainName,
75238c8a9a5SSteve French 					    CIFS_MAX_DOMAINNAME_LEN, nls_cp);
75338c8a9a5SSteve French 	bcc_ptr += 2 * bytes_ret;
75438c8a9a5SSteve French 	bcc_ptr += 2;  /* account for null terminator */
75538c8a9a5SSteve French 
75638c8a9a5SSteve French 	*pbcc_area = bcc_ptr;
75738c8a9a5SSteve French }
75838c8a9a5SSteve French 
unicode_ssetup_strings(char ** pbcc_area,struct cifs_ses * ses,const struct nls_table * nls_cp)75938c8a9a5SSteve French static void unicode_ssetup_strings(char **pbcc_area, struct cifs_ses *ses,
76038c8a9a5SSteve French 				   const struct nls_table *nls_cp)
76138c8a9a5SSteve French {
76238c8a9a5SSteve French 	char *bcc_ptr = *pbcc_area;
76338c8a9a5SSteve French 	int bytes_ret = 0;
76438c8a9a5SSteve French 
765210c8b9dSSteve French 	/* BB FIXME add check that strings less than 335 or will need to send as arrays */
76638c8a9a5SSteve French 
76738c8a9a5SSteve French 	/* copy user */
76838c8a9a5SSteve French 	if (ses->user_name == NULL) {
76938c8a9a5SSteve French 		/* null user mount */
77038c8a9a5SSteve French 		*bcc_ptr = 0;
77138c8a9a5SSteve French 		*(bcc_ptr+1) = 0;
77238c8a9a5SSteve French 	} else {
77338c8a9a5SSteve French 		bytes_ret = cifs_strtoUTF16((__le16 *) bcc_ptr, ses->user_name,
77438c8a9a5SSteve French 					    CIFS_MAX_USERNAME_LEN, nls_cp);
77538c8a9a5SSteve French 	}
77638c8a9a5SSteve French 	bcc_ptr += 2 * bytes_ret;
77738c8a9a5SSteve French 	bcc_ptr += 2; /* account for null termination */
77838c8a9a5SSteve French 
77938c8a9a5SSteve French 	unicode_domain_string(&bcc_ptr, ses, nls_cp);
78038c8a9a5SSteve French 	unicode_oslm_strings(&bcc_ptr, nls_cp);
78138c8a9a5SSteve French 
78238c8a9a5SSteve French 	*pbcc_area = bcc_ptr;
78338c8a9a5SSteve French }
78438c8a9a5SSteve French 
ascii_ssetup_strings(char ** pbcc_area,struct cifs_ses * ses,const struct nls_table * nls_cp)78538c8a9a5SSteve French static void ascii_ssetup_strings(char **pbcc_area, struct cifs_ses *ses,
78638c8a9a5SSteve French 				 const struct nls_table *nls_cp)
78738c8a9a5SSteve French {
78838c8a9a5SSteve French 	char *bcc_ptr = *pbcc_area;
78938c8a9a5SSteve French 	int len;
79038c8a9a5SSteve French 
79138c8a9a5SSteve French 	/* copy user */
79238c8a9a5SSteve French 	/* BB what about null user mounts - check that we do this BB */
79338c8a9a5SSteve French 	/* copy user */
79438c8a9a5SSteve French 	if (ses->user_name != NULL) {
79538c8a9a5SSteve French 		len = strscpy(bcc_ptr, ses->user_name, CIFS_MAX_USERNAME_LEN);
79638c8a9a5SSteve French 		if (WARN_ON_ONCE(len < 0))
79738c8a9a5SSteve French 			len = CIFS_MAX_USERNAME_LEN - 1;
79838c8a9a5SSteve French 		bcc_ptr += len;
79938c8a9a5SSteve French 	}
80038c8a9a5SSteve French 	/* else null user mount */
80138c8a9a5SSteve French 	*bcc_ptr = 0;
80238c8a9a5SSteve French 	bcc_ptr++; /* account for null termination */
80338c8a9a5SSteve French 
80438c8a9a5SSteve French 	/* copy domain */
80538c8a9a5SSteve French 	if (ses->domainName != NULL) {
80638c8a9a5SSteve French 		len = strscpy(bcc_ptr, ses->domainName, CIFS_MAX_DOMAINNAME_LEN);
80738c8a9a5SSteve French 		if (WARN_ON_ONCE(len < 0))
80838c8a9a5SSteve French 			len = CIFS_MAX_DOMAINNAME_LEN - 1;
80938c8a9a5SSteve French 		bcc_ptr += len;
810cc3035d0SSteve French 	} /* else we send a null domain name so server will default to its own domain */
81138c8a9a5SSteve French 	*bcc_ptr = 0;
81238c8a9a5SSteve French 	bcc_ptr++;
81338c8a9a5SSteve French 
81438c8a9a5SSteve French 	/* BB check for overflow here */
81538c8a9a5SSteve French 
81638c8a9a5SSteve French 	strcpy(bcc_ptr, "Linux version ");
81738c8a9a5SSteve French 	bcc_ptr += strlen("Linux version ");
81838c8a9a5SSteve French 	strcpy(bcc_ptr, init_utsname()->release);
81938c8a9a5SSteve French 	bcc_ptr += strlen(init_utsname()->release) + 1;
82038c8a9a5SSteve French 
82138c8a9a5SSteve French 	strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
82238c8a9a5SSteve French 	bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
82338c8a9a5SSteve French 
82438c8a9a5SSteve French 	*pbcc_area = bcc_ptr;
82538c8a9a5SSteve French }
82638c8a9a5SSteve French 
82738c8a9a5SSteve French static void
decode_unicode_ssetup(char ** pbcc_area,int bleft,struct cifs_ses * ses,const struct nls_table * nls_cp)82838c8a9a5SSteve French decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifs_ses *ses,
82938c8a9a5SSteve French 		      const struct nls_table *nls_cp)
83038c8a9a5SSteve French {
83138c8a9a5SSteve French 	int len;
83238c8a9a5SSteve French 	char *data = *pbcc_area;
83338c8a9a5SSteve French 
83438c8a9a5SSteve French 	cifs_dbg(FYI, "bleft %d\n", bleft);
83538c8a9a5SSteve French 
83638c8a9a5SSteve French 	kfree(ses->serverOS);
83738c8a9a5SSteve French 	ses->serverOS = cifs_strndup_from_utf16(data, bleft, true, nls_cp);
83838c8a9a5SSteve French 	cifs_dbg(FYI, "serverOS=%s\n", ses->serverOS);
83938c8a9a5SSteve French 	len = (UniStrnlen((wchar_t *) data, bleft / 2) * 2) + 2;
84038c8a9a5SSteve French 	data += len;
84138c8a9a5SSteve French 	bleft -= len;
84238c8a9a5SSteve French 	if (bleft <= 0)
84338c8a9a5SSteve French 		return;
84438c8a9a5SSteve French 
84538c8a9a5SSteve French 	kfree(ses->serverNOS);
84638c8a9a5SSteve French 	ses->serverNOS = cifs_strndup_from_utf16(data, bleft, true, nls_cp);
84738c8a9a5SSteve French 	cifs_dbg(FYI, "serverNOS=%s\n", ses->serverNOS);
84838c8a9a5SSteve French 	len = (UniStrnlen((wchar_t *) data, bleft / 2) * 2) + 2;
84938c8a9a5SSteve French 	data += len;
85038c8a9a5SSteve French 	bleft -= len;
85138c8a9a5SSteve French 	if (bleft <= 0)
85238c8a9a5SSteve French 		return;
85338c8a9a5SSteve French 
85438c8a9a5SSteve French 	kfree(ses->serverDomain);
85538c8a9a5SSteve French 	ses->serverDomain = cifs_strndup_from_utf16(data, bleft, true, nls_cp);
85638c8a9a5SSteve French 	cifs_dbg(FYI, "serverDomain=%s\n", ses->serverDomain);
85738c8a9a5SSteve French 
85838c8a9a5SSteve French 	return;
85938c8a9a5SSteve French }
86038c8a9a5SSteve French 
decode_ascii_ssetup(char ** pbcc_area,__u16 bleft,struct cifs_ses * ses,const struct nls_table * nls_cp)86138c8a9a5SSteve French static void decode_ascii_ssetup(char **pbcc_area, __u16 bleft,
86238c8a9a5SSteve French 				struct cifs_ses *ses,
86338c8a9a5SSteve French 				const struct nls_table *nls_cp)
86438c8a9a5SSteve French {
86538c8a9a5SSteve French 	int len;
86638c8a9a5SSteve French 	char *bcc_ptr = *pbcc_area;
86738c8a9a5SSteve French 
86838c8a9a5SSteve French 	cifs_dbg(FYI, "decode sessetup ascii. bleft %d\n", bleft);
86938c8a9a5SSteve French 
87038c8a9a5SSteve French 	len = strnlen(bcc_ptr, bleft);
87138c8a9a5SSteve French 	if (len >= bleft)
87238c8a9a5SSteve French 		return;
87338c8a9a5SSteve French 
87438c8a9a5SSteve French 	kfree(ses->serverOS);
87538c8a9a5SSteve French 
87638c8a9a5SSteve French 	ses->serverOS = kmalloc(len + 1, GFP_KERNEL);
87738c8a9a5SSteve French 	if (ses->serverOS) {
87838c8a9a5SSteve French 		memcpy(ses->serverOS, bcc_ptr, len);
87938c8a9a5SSteve French 		ses->serverOS[len] = 0;
88038c8a9a5SSteve French 		if (strncmp(ses->serverOS, "OS/2", 4) == 0)
88138c8a9a5SSteve French 			cifs_dbg(FYI, "OS/2 server\n");
88238c8a9a5SSteve French 	}
88338c8a9a5SSteve French 
88438c8a9a5SSteve French 	bcc_ptr += len + 1;
88538c8a9a5SSteve French 	bleft -= len + 1;
88638c8a9a5SSteve French 
88738c8a9a5SSteve French 	len = strnlen(bcc_ptr, bleft);
88838c8a9a5SSteve French 	if (len >= bleft)
88938c8a9a5SSteve French 		return;
89038c8a9a5SSteve French 
89138c8a9a5SSteve French 	kfree(ses->serverNOS);
89238c8a9a5SSteve French 
89338c8a9a5SSteve French 	ses->serverNOS = kmalloc(len + 1, GFP_KERNEL);
89438c8a9a5SSteve French 	if (ses->serverNOS) {
89538c8a9a5SSteve French 		memcpy(ses->serverNOS, bcc_ptr, len);
89638c8a9a5SSteve French 		ses->serverNOS[len] = 0;
89738c8a9a5SSteve French 	}
89838c8a9a5SSteve French 
89938c8a9a5SSteve French 	bcc_ptr += len + 1;
90038c8a9a5SSteve French 	bleft -= len + 1;
90138c8a9a5SSteve French 
90238c8a9a5SSteve French 	len = strnlen(bcc_ptr, bleft);
90338c8a9a5SSteve French 	if (len > bleft)
90438c8a9a5SSteve French 		return;
90538c8a9a5SSteve French 
906cc3035d0SSteve French 	/*
907cc3035d0SSteve French 	 * No domain field in LANMAN case. Domain is
908cc3035d0SSteve French 	 * returned by old servers in the SMB negprot response
909cc3035d0SSteve French 	 *
910cc3035d0SSteve French 	 * BB For newer servers which do not support Unicode,
911cc3035d0SSteve French 	 * but thus do return domain here, we could add parsing
912cc3035d0SSteve French 	 * for it later, but it is not very important
913cc3035d0SSteve French 	 */
91438c8a9a5SSteve French 	cifs_dbg(FYI, "ascii: bytes left %d\n", bleft);
91538c8a9a5SSteve French }
91638c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
91738c8a9a5SSteve French 
decode_ntlmssp_challenge(char * bcc_ptr,int blob_len,struct cifs_ses * ses)91838c8a9a5SSteve French int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
91938c8a9a5SSteve French 				    struct cifs_ses *ses)
92038c8a9a5SSteve French {
92138c8a9a5SSteve French 	unsigned int tioffset; /* challenge message target info area */
92238c8a9a5SSteve French 	unsigned int tilen; /* challenge message target info area length  */
92338c8a9a5SSteve French 	CHALLENGE_MESSAGE *pblob = (CHALLENGE_MESSAGE *)bcc_ptr;
92438c8a9a5SSteve French 	__u32 server_flags;
92538c8a9a5SSteve French 
92638c8a9a5SSteve French 	if (blob_len < sizeof(CHALLENGE_MESSAGE)) {
92738c8a9a5SSteve French 		cifs_dbg(VFS, "challenge blob len %d too small\n", blob_len);
92838c8a9a5SSteve French 		return -EINVAL;
92938c8a9a5SSteve French 	}
93038c8a9a5SSteve French 
93138c8a9a5SSteve French 	if (memcmp(pblob->Signature, "NTLMSSP", 8)) {
93238c8a9a5SSteve French 		cifs_dbg(VFS, "blob signature incorrect %s\n",
93338c8a9a5SSteve French 			 pblob->Signature);
93438c8a9a5SSteve French 		return -EINVAL;
93538c8a9a5SSteve French 	}
93638c8a9a5SSteve French 	if (pblob->MessageType != NtLmChallenge) {
93738c8a9a5SSteve French 		cifs_dbg(VFS, "Incorrect message type %d\n",
93838c8a9a5SSteve French 			 pblob->MessageType);
93938c8a9a5SSteve French 		return -EINVAL;
94038c8a9a5SSteve French 	}
94138c8a9a5SSteve French 
94238c8a9a5SSteve French 	server_flags = le32_to_cpu(pblob->NegotiateFlags);
94338c8a9a5SSteve French 	cifs_dbg(FYI, "%s: negotiate=0x%08x challenge=0x%08x\n", __func__,
94438c8a9a5SSteve French 		 ses->ntlmssp->client_flags, server_flags);
94538c8a9a5SSteve French 
94638c8a9a5SSteve French 	if ((ses->ntlmssp->client_flags & (NTLMSSP_NEGOTIATE_SEAL | NTLMSSP_NEGOTIATE_SIGN)) &&
94738c8a9a5SSteve French 	    (!(server_flags & NTLMSSP_NEGOTIATE_56) && !(server_flags & NTLMSSP_NEGOTIATE_128))) {
94838c8a9a5SSteve French 		cifs_dbg(VFS, "%s: requested signing/encryption but server did not return either 56-bit or 128-bit session key size\n",
94938c8a9a5SSteve French 			 __func__);
95038c8a9a5SSteve French 		return -EINVAL;
95138c8a9a5SSteve French 	}
95238c8a9a5SSteve French 	if (!(server_flags & NTLMSSP_NEGOTIATE_NTLM) && !(server_flags & NTLMSSP_NEGOTIATE_EXTENDED_SEC)) {
95338c8a9a5SSteve French 		cifs_dbg(VFS, "%s: server does not seem to support either NTLMv1 or NTLMv2\n", __func__);
95438c8a9a5SSteve French 		return -EINVAL;
95538c8a9a5SSteve French 	}
95638c8a9a5SSteve French 	if (ses->server->sign && !(server_flags & NTLMSSP_NEGOTIATE_SIGN)) {
95738c8a9a5SSteve French 		cifs_dbg(VFS, "%s: forced packet signing but server does not seem to support it\n",
95838c8a9a5SSteve French 			 __func__);
95938c8a9a5SSteve French 		return -EOPNOTSUPP;
96038c8a9a5SSteve French 	}
96138c8a9a5SSteve French 	if ((ses->ntlmssp->client_flags & NTLMSSP_NEGOTIATE_KEY_XCH) &&
96238c8a9a5SSteve French 	    !(server_flags & NTLMSSP_NEGOTIATE_KEY_XCH))
96338c8a9a5SSteve French 		pr_warn_once("%s: authentication has been weakened as server does not support key exchange\n",
96438c8a9a5SSteve French 			     __func__);
96538c8a9a5SSteve French 
96638c8a9a5SSteve French 	ses->ntlmssp->server_flags = server_flags;
96738c8a9a5SSteve French 
96838c8a9a5SSteve French 	memcpy(ses->ntlmssp->cryptkey, pblob->Challenge, CIFS_CRYPTO_KEY_SIZE);
969cc3035d0SSteve French 	/*
970cc3035d0SSteve French 	 * In particular we can examine sign flags
971cc3035d0SSteve French 	 *
972cc3035d0SSteve French 	 * BB spec says that if AvId field of MsvAvTimestamp is populated then
973cc3035d0SSteve French 	 * we must set the MIC field of the AUTHENTICATE_MESSAGE
974cc3035d0SSteve French 	 */
97538c8a9a5SSteve French 
97638c8a9a5SSteve French 	tioffset = le32_to_cpu(pblob->TargetInfoArray.BufferOffset);
97738c8a9a5SSteve French 	tilen = le16_to_cpu(pblob->TargetInfoArray.Length);
97838c8a9a5SSteve French 	if (tioffset > blob_len || tioffset + tilen > blob_len) {
97938c8a9a5SSteve French 		cifs_dbg(VFS, "tioffset + tilen too high %u + %u\n",
98038c8a9a5SSteve French 			 tioffset, tilen);
98138c8a9a5SSteve French 		return -EINVAL;
98238c8a9a5SSteve French 	}
98338c8a9a5SSteve French 	if (tilen) {
98438c8a9a5SSteve French 		kfree_sensitive(ses->auth_key.response);
98538c8a9a5SSteve French 		ses->auth_key.response = kmemdup(bcc_ptr + tioffset, tilen,
98638c8a9a5SSteve French 						 GFP_KERNEL);
98738c8a9a5SSteve French 		if (!ses->auth_key.response) {
98838c8a9a5SSteve French 			cifs_dbg(VFS, "Challenge target info alloc failure\n");
98938c8a9a5SSteve French 			return -ENOMEM;
99038c8a9a5SSteve French 		}
99138c8a9a5SSteve French 		ses->auth_key.len = tilen;
99238c8a9a5SSteve French 	}
99338c8a9a5SSteve French 
99438c8a9a5SSteve French 	return 0;
99538c8a9a5SSteve French }
99638c8a9a5SSteve French 
size_of_ntlmssp_blob(struct cifs_ses * ses,int base_size)99738c8a9a5SSteve French static int size_of_ntlmssp_blob(struct cifs_ses *ses, int base_size)
99838c8a9a5SSteve French {
99938c8a9a5SSteve French 	int sz = base_size + ses->auth_key.len
100038c8a9a5SSteve French 		- CIFS_SESS_KEY_SIZE + CIFS_CPHTXT_SIZE + 2;
100138c8a9a5SSteve French 
100238c8a9a5SSteve French 	if (ses->domainName)
100338c8a9a5SSteve French 		sz += sizeof(__le16) * strnlen(ses->domainName, CIFS_MAX_DOMAINNAME_LEN);
100438c8a9a5SSteve French 	else
100538c8a9a5SSteve French 		sz += sizeof(__le16);
100638c8a9a5SSteve French 
100738c8a9a5SSteve French 	if (ses->user_name)
100838c8a9a5SSteve French 		sz += sizeof(__le16) * strnlen(ses->user_name, CIFS_MAX_USERNAME_LEN);
100938c8a9a5SSteve French 	else
101038c8a9a5SSteve French 		sz += sizeof(__le16);
101138c8a9a5SSteve French 
101238c8a9a5SSteve French 	if (ses->workstation_name[0])
101338c8a9a5SSteve French 		sz += sizeof(__le16) * strnlen(ses->workstation_name,
101438c8a9a5SSteve French 					       ntlmssp_workstation_name_size(ses));
101538c8a9a5SSteve French 	else
101638c8a9a5SSteve French 		sz += sizeof(__le16);
101738c8a9a5SSteve French 
101838c8a9a5SSteve French 	return sz;
101938c8a9a5SSteve French }
102038c8a9a5SSteve French 
cifs_security_buffer_from_str(SECURITY_BUFFER * pbuf,char * str_value,int str_length,unsigned char * pstart,unsigned char ** pcur,const struct nls_table * nls_cp)102138c8a9a5SSteve French static inline void cifs_security_buffer_from_str(SECURITY_BUFFER *pbuf,
102238c8a9a5SSteve French 						 char *str_value,
102338c8a9a5SSteve French 						 int str_length,
102438c8a9a5SSteve French 						 unsigned char *pstart,
102538c8a9a5SSteve French 						 unsigned char **pcur,
102638c8a9a5SSteve French 						 const struct nls_table *nls_cp)
102738c8a9a5SSteve French {
102838c8a9a5SSteve French 	unsigned char *tmp = pstart;
102938c8a9a5SSteve French 	int len;
103038c8a9a5SSteve French 
103138c8a9a5SSteve French 	if (!pbuf)
103238c8a9a5SSteve French 		return;
103338c8a9a5SSteve French 
103438c8a9a5SSteve French 	if (!pcur)
103538c8a9a5SSteve French 		pcur = &tmp;
103638c8a9a5SSteve French 
103738c8a9a5SSteve French 	if (!str_value) {
103838c8a9a5SSteve French 		pbuf->BufferOffset = cpu_to_le32(*pcur - pstart);
103938c8a9a5SSteve French 		pbuf->Length = 0;
104038c8a9a5SSteve French 		pbuf->MaximumLength = 0;
104138c8a9a5SSteve French 		*pcur += sizeof(__le16);
104238c8a9a5SSteve French 	} else {
104338c8a9a5SSteve French 		len = cifs_strtoUTF16((__le16 *)*pcur,
104438c8a9a5SSteve French 				      str_value,
104538c8a9a5SSteve French 				      str_length,
104638c8a9a5SSteve French 				      nls_cp);
104738c8a9a5SSteve French 		len *= sizeof(__le16);
104838c8a9a5SSteve French 		pbuf->BufferOffset = cpu_to_le32(*pcur - pstart);
104938c8a9a5SSteve French 		pbuf->Length = cpu_to_le16(len);
105038c8a9a5SSteve French 		pbuf->MaximumLength = cpu_to_le16(len);
105138c8a9a5SSteve French 		*pcur += len;
105238c8a9a5SSteve French 	}
105338c8a9a5SSteve French }
105438c8a9a5SSteve French 
105538c8a9a5SSteve French /* BB Move to ntlmssp.c eventually */
105638c8a9a5SSteve French 
build_ntlmssp_negotiate_blob(unsigned char ** pbuffer,u16 * buflen,struct cifs_ses * ses,struct TCP_Server_Info * server,const struct nls_table * nls_cp)105738c8a9a5SSteve French int build_ntlmssp_negotiate_blob(unsigned char **pbuffer,
105838c8a9a5SSteve French 				 u16 *buflen,
105938c8a9a5SSteve French 				 struct cifs_ses *ses,
106038c8a9a5SSteve French 				 struct TCP_Server_Info *server,
106138c8a9a5SSteve French 				 const struct nls_table *nls_cp)
106238c8a9a5SSteve French {
106338c8a9a5SSteve French 	int rc = 0;
106438c8a9a5SSteve French 	NEGOTIATE_MESSAGE *sec_blob;
106538c8a9a5SSteve French 	__u32 flags;
106638c8a9a5SSteve French 	unsigned char *tmp;
106738c8a9a5SSteve French 	int len;
106838c8a9a5SSteve French 
106938c8a9a5SSteve French 	len = size_of_ntlmssp_blob(ses, sizeof(NEGOTIATE_MESSAGE));
107038c8a9a5SSteve French 	*pbuffer = kmalloc(len, GFP_KERNEL);
107138c8a9a5SSteve French 	if (!*pbuffer) {
107238c8a9a5SSteve French 		rc = -ENOMEM;
107338c8a9a5SSteve French 		cifs_dbg(VFS, "Error %d during NTLMSSP allocation\n", rc);
107438c8a9a5SSteve French 		*buflen = 0;
107538c8a9a5SSteve French 		goto setup_ntlm_neg_ret;
107638c8a9a5SSteve French 	}
107738c8a9a5SSteve French 	sec_blob = (NEGOTIATE_MESSAGE *)*pbuffer;
107838c8a9a5SSteve French 
107938c8a9a5SSteve French 	memset(*pbuffer, 0, sizeof(NEGOTIATE_MESSAGE));
108038c8a9a5SSteve French 	memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8);
108138c8a9a5SSteve French 	sec_blob->MessageType = NtLmNegotiate;
108238c8a9a5SSteve French 
108338c8a9a5SSteve French 	/* BB is NTLMV2 session security format easier to use here? */
108438c8a9a5SSteve French 	flags = NTLMSSP_NEGOTIATE_56 |	NTLMSSP_REQUEST_TARGET |
108538c8a9a5SSteve French 		NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
108638c8a9a5SSteve French 		NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC |
108738c8a9a5SSteve French 		NTLMSSP_NEGOTIATE_ALWAYS_SIGN | NTLMSSP_NEGOTIATE_SEAL |
108838c8a9a5SSteve French 		NTLMSSP_NEGOTIATE_SIGN;
108938c8a9a5SSteve French 	if (!server->session_estab || ses->ntlmssp->sesskey_per_smbsess)
109038c8a9a5SSteve French 		flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
109138c8a9a5SSteve French 
109238c8a9a5SSteve French 	tmp = *pbuffer + sizeof(NEGOTIATE_MESSAGE);
109338c8a9a5SSteve French 	ses->ntlmssp->client_flags = flags;
109438c8a9a5SSteve French 	sec_blob->NegotiateFlags = cpu_to_le32(flags);
109538c8a9a5SSteve French 
109638c8a9a5SSteve French 	/* these fields should be null in negotiate phase MS-NLMP 3.1.5.1.1 */
109738c8a9a5SSteve French 	cifs_security_buffer_from_str(&sec_blob->DomainName,
109838c8a9a5SSteve French 				      NULL,
109938c8a9a5SSteve French 				      CIFS_MAX_DOMAINNAME_LEN,
110038c8a9a5SSteve French 				      *pbuffer, &tmp,
110138c8a9a5SSteve French 				      nls_cp);
110238c8a9a5SSteve French 
110338c8a9a5SSteve French 	cifs_security_buffer_from_str(&sec_blob->WorkstationName,
110438c8a9a5SSteve French 				      NULL,
110538c8a9a5SSteve French 				      CIFS_MAX_WORKSTATION_LEN,
110638c8a9a5SSteve French 				      *pbuffer, &tmp,
110738c8a9a5SSteve French 				      nls_cp);
110838c8a9a5SSteve French 
110938c8a9a5SSteve French 	*buflen = tmp - *pbuffer;
111038c8a9a5SSteve French setup_ntlm_neg_ret:
111138c8a9a5SSteve French 	return rc;
111238c8a9a5SSteve French }
111338c8a9a5SSteve French 
111438c8a9a5SSteve French /*
111538c8a9a5SSteve French  * Build ntlmssp blob with additional fields, such as version,
111638c8a9a5SSteve French  * supported by modern servers. For safety limit to SMB3 or later
111738c8a9a5SSteve French  * See notes in MS-NLMP Section 2.2.2.1 e.g.
111838c8a9a5SSteve French  */
build_ntlmssp_smb3_negotiate_blob(unsigned char ** pbuffer,u16 * buflen,struct cifs_ses * ses,struct TCP_Server_Info * server,const struct nls_table * nls_cp)111938c8a9a5SSteve French int build_ntlmssp_smb3_negotiate_blob(unsigned char **pbuffer,
112038c8a9a5SSteve French 				 u16 *buflen,
112138c8a9a5SSteve French 				 struct cifs_ses *ses,
112238c8a9a5SSteve French 				 struct TCP_Server_Info *server,
112338c8a9a5SSteve French 				 const struct nls_table *nls_cp)
112438c8a9a5SSteve French {
112538c8a9a5SSteve French 	int rc = 0;
112638c8a9a5SSteve French 	struct negotiate_message *sec_blob;
112738c8a9a5SSteve French 	__u32 flags;
112838c8a9a5SSteve French 	unsigned char *tmp;
112938c8a9a5SSteve French 	int len;
113038c8a9a5SSteve French 
113138c8a9a5SSteve French 	len = size_of_ntlmssp_blob(ses, sizeof(struct negotiate_message));
113238c8a9a5SSteve French 	*pbuffer = kmalloc(len, GFP_KERNEL);
113338c8a9a5SSteve French 	if (!*pbuffer) {
113438c8a9a5SSteve French 		rc = -ENOMEM;
113538c8a9a5SSteve French 		cifs_dbg(VFS, "Error %d during NTLMSSP allocation\n", rc);
113638c8a9a5SSteve French 		*buflen = 0;
113738c8a9a5SSteve French 		goto setup_ntlm_smb3_neg_ret;
113838c8a9a5SSteve French 	}
113938c8a9a5SSteve French 	sec_blob = (struct negotiate_message *)*pbuffer;
114038c8a9a5SSteve French 
114138c8a9a5SSteve French 	memset(*pbuffer, 0, sizeof(struct negotiate_message));
114238c8a9a5SSteve French 	memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8);
114338c8a9a5SSteve French 	sec_blob->MessageType = NtLmNegotiate;
114438c8a9a5SSteve French 
114538c8a9a5SSteve French 	/* BB is NTLMV2 session security format easier to use here? */
114638c8a9a5SSteve French 	flags = NTLMSSP_NEGOTIATE_56 |	NTLMSSP_REQUEST_TARGET |
114738c8a9a5SSteve French 		NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
114838c8a9a5SSteve French 		NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC |
114938c8a9a5SSteve French 		NTLMSSP_NEGOTIATE_ALWAYS_SIGN | NTLMSSP_NEGOTIATE_SEAL |
115038c8a9a5SSteve French 		NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_VERSION;
115138c8a9a5SSteve French 	if (!server->session_estab || ses->ntlmssp->sesskey_per_smbsess)
115238c8a9a5SSteve French 		flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
115338c8a9a5SSteve French 
115438c8a9a5SSteve French 	sec_blob->Version.ProductMajorVersion = LINUX_VERSION_MAJOR;
115538c8a9a5SSteve French 	sec_blob->Version.ProductMinorVersion = LINUX_VERSION_PATCHLEVEL;
115638c8a9a5SSteve French 	sec_blob->Version.ProductBuild = cpu_to_le16(SMB3_PRODUCT_BUILD);
115738c8a9a5SSteve French 	sec_blob->Version.NTLMRevisionCurrent = NTLMSSP_REVISION_W2K3;
115838c8a9a5SSteve French 
115938c8a9a5SSteve French 	tmp = *pbuffer + sizeof(struct negotiate_message);
116038c8a9a5SSteve French 	ses->ntlmssp->client_flags = flags;
116138c8a9a5SSteve French 	sec_blob->NegotiateFlags = cpu_to_le32(flags);
116238c8a9a5SSteve French 
116338c8a9a5SSteve French 	/* these fields should be null in negotiate phase MS-NLMP 3.1.5.1.1 */
116438c8a9a5SSteve French 	cifs_security_buffer_from_str(&sec_blob->DomainName,
116538c8a9a5SSteve French 				      NULL,
116638c8a9a5SSteve French 				      CIFS_MAX_DOMAINNAME_LEN,
116738c8a9a5SSteve French 				      *pbuffer, &tmp,
116838c8a9a5SSteve French 				      nls_cp);
116938c8a9a5SSteve French 
117038c8a9a5SSteve French 	cifs_security_buffer_from_str(&sec_blob->WorkstationName,
117138c8a9a5SSteve French 				      NULL,
117238c8a9a5SSteve French 				      CIFS_MAX_WORKSTATION_LEN,
117338c8a9a5SSteve French 				      *pbuffer, &tmp,
117438c8a9a5SSteve French 				      nls_cp);
117538c8a9a5SSteve French 
117638c8a9a5SSteve French 	*buflen = tmp - *pbuffer;
117738c8a9a5SSteve French setup_ntlm_smb3_neg_ret:
117838c8a9a5SSteve French 	return rc;
117938c8a9a5SSteve French }
118038c8a9a5SSteve French 
118138c8a9a5SSteve French 
118219826558SSteve French /* See MS-NLMP 2.2.1.3 */
build_ntlmssp_auth_blob(unsigned char ** pbuffer,u16 * buflen,struct cifs_ses * ses,struct TCP_Server_Info * server,const struct nls_table * nls_cp)118338c8a9a5SSteve French int build_ntlmssp_auth_blob(unsigned char **pbuffer,
118438c8a9a5SSteve French 					u16 *buflen,
118538c8a9a5SSteve French 				   struct cifs_ses *ses,
118638c8a9a5SSteve French 				   struct TCP_Server_Info *server,
118738c8a9a5SSteve French 				   const struct nls_table *nls_cp)
118838c8a9a5SSteve French {
118938c8a9a5SSteve French 	int rc;
119038c8a9a5SSteve French 	AUTHENTICATE_MESSAGE *sec_blob;
119138c8a9a5SSteve French 	__u32 flags;
119238c8a9a5SSteve French 	unsigned char *tmp;
119338c8a9a5SSteve French 	int len;
119438c8a9a5SSteve French 
119538c8a9a5SSteve French 	rc = setup_ntlmv2_rsp(ses, nls_cp);
119638c8a9a5SSteve French 	if (rc) {
119738c8a9a5SSteve French 		cifs_dbg(VFS, "Error %d during NTLMSSP authentication\n", rc);
119838c8a9a5SSteve French 		*buflen = 0;
119938c8a9a5SSteve French 		goto setup_ntlmv2_ret;
120038c8a9a5SSteve French 	}
120138c8a9a5SSteve French 
120238c8a9a5SSteve French 	len = size_of_ntlmssp_blob(ses, sizeof(AUTHENTICATE_MESSAGE));
120338c8a9a5SSteve French 	*pbuffer = kmalloc(len, GFP_KERNEL);
120438c8a9a5SSteve French 	if (!*pbuffer) {
120538c8a9a5SSteve French 		rc = -ENOMEM;
120638c8a9a5SSteve French 		cifs_dbg(VFS, "Error %d during NTLMSSP allocation\n", rc);
120738c8a9a5SSteve French 		*buflen = 0;
120838c8a9a5SSteve French 		goto setup_ntlmv2_ret;
120938c8a9a5SSteve French 	}
121038c8a9a5SSteve French 	sec_blob = (AUTHENTICATE_MESSAGE *)*pbuffer;
121138c8a9a5SSteve French 
121238c8a9a5SSteve French 	memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8);
121338c8a9a5SSteve French 	sec_blob->MessageType = NtLmAuthenticate;
121438c8a9a5SSteve French 
12156bd52f41SMeetakshi Setiya 	/* send version information in ntlmssp authenticate also */
121638c8a9a5SSteve French 	flags = ses->ntlmssp->server_flags | NTLMSSP_REQUEST_TARGET |
12176bd52f41SMeetakshi Setiya 		NTLMSSP_NEGOTIATE_TARGET_INFO | NTLMSSP_NEGOTIATE_VERSION |
12186bd52f41SMeetakshi Setiya 		NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED;
12196bd52f41SMeetakshi Setiya 
12206bd52f41SMeetakshi Setiya 	sec_blob->Version.ProductMajorVersion = LINUX_VERSION_MAJOR;
12216bd52f41SMeetakshi Setiya 	sec_blob->Version.ProductMinorVersion = LINUX_VERSION_PATCHLEVEL;
12226bd52f41SMeetakshi Setiya 	sec_blob->Version.ProductBuild = cpu_to_le16(SMB3_PRODUCT_BUILD);
12236bd52f41SMeetakshi Setiya 	sec_blob->Version.NTLMRevisionCurrent = NTLMSSP_REVISION_W2K3;
12246bd52f41SMeetakshi Setiya 
122538c8a9a5SSteve French 	tmp = *pbuffer + sizeof(AUTHENTICATE_MESSAGE);
122638c8a9a5SSteve French 	sec_blob->NegotiateFlags = cpu_to_le32(flags);
122738c8a9a5SSteve French 
122838c8a9a5SSteve French 	sec_blob->LmChallengeResponse.BufferOffset =
122938c8a9a5SSteve French 				cpu_to_le32(sizeof(AUTHENTICATE_MESSAGE));
123038c8a9a5SSteve French 	sec_blob->LmChallengeResponse.Length = 0;
123138c8a9a5SSteve French 	sec_blob->LmChallengeResponse.MaximumLength = 0;
123238c8a9a5SSteve French 
123338c8a9a5SSteve French 	sec_blob->NtChallengeResponse.BufferOffset =
123438c8a9a5SSteve French 				cpu_to_le32(tmp - *pbuffer);
123538c8a9a5SSteve French 	if (ses->user_name != NULL) {
123638c8a9a5SSteve French 		memcpy(tmp, ses->auth_key.response + CIFS_SESS_KEY_SIZE,
123738c8a9a5SSteve French 				ses->auth_key.len - CIFS_SESS_KEY_SIZE);
123838c8a9a5SSteve French 		tmp += ses->auth_key.len - CIFS_SESS_KEY_SIZE;
123938c8a9a5SSteve French 
124038c8a9a5SSteve French 		sec_blob->NtChallengeResponse.Length =
124138c8a9a5SSteve French 				cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE);
124238c8a9a5SSteve French 		sec_blob->NtChallengeResponse.MaximumLength =
124338c8a9a5SSteve French 				cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE);
124438c8a9a5SSteve French 	} else {
124538c8a9a5SSteve French 		/*
124638c8a9a5SSteve French 		 * don't send an NT Response for anonymous access
124738c8a9a5SSteve French 		 */
124838c8a9a5SSteve French 		sec_blob->NtChallengeResponse.Length = 0;
124938c8a9a5SSteve French 		sec_blob->NtChallengeResponse.MaximumLength = 0;
125038c8a9a5SSteve French 	}
125138c8a9a5SSteve French 
125238c8a9a5SSteve French 	cifs_security_buffer_from_str(&sec_blob->DomainName,
125338c8a9a5SSteve French 				      ses->domainName,
125438c8a9a5SSteve French 				      CIFS_MAX_DOMAINNAME_LEN,
125538c8a9a5SSteve French 				      *pbuffer, &tmp,
125638c8a9a5SSteve French 				      nls_cp);
125738c8a9a5SSteve French 
125838c8a9a5SSteve French 	cifs_security_buffer_from_str(&sec_blob->UserName,
125938c8a9a5SSteve French 				      ses->user_name,
126038c8a9a5SSteve French 				      CIFS_MAX_USERNAME_LEN,
126138c8a9a5SSteve French 				      *pbuffer, &tmp,
126238c8a9a5SSteve French 				      nls_cp);
126338c8a9a5SSteve French 
126438c8a9a5SSteve French 	cifs_security_buffer_from_str(&sec_blob->WorkstationName,
126538c8a9a5SSteve French 				      ses->workstation_name,
126638c8a9a5SSteve French 				      ntlmssp_workstation_name_size(ses),
126738c8a9a5SSteve French 				      *pbuffer, &tmp,
126838c8a9a5SSteve French 				      nls_cp);
126938c8a9a5SSteve French 
127038c8a9a5SSteve French 	if ((ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_KEY_XCH) &&
127138c8a9a5SSteve French 	    (!ses->server->session_estab || ses->ntlmssp->sesskey_per_smbsess) &&
127238c8a9a5SSteve French 	    !calc_seckey(ses)) {
127338c8a9a5SSteve French 		memcpy(tmp, ses->ntlmssp->ciphertext, CIFS_CPHTXT_SIZE);
127438c8a9a5SSteve French 		sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - *pbuffer);
127538c8a9a5SSteve French 		sec_blob->SessionKey.Length = cpu_to_le16(CIFS_CPHTXT_SIZE);
127638c8a9a5SSteve French 		sec_blob->SessionKey.MaximumLength =
127738c8a9a5SSteve French 				cpu_to_le16(CIFS_CPHTXT_SIZE);
127838c8a9a5SSteve French 		tmp += CIFS_CPHTXT_SIZE;
127938c8a9a5SSteve French 	} else {
128038c8a9a5SSteve French 		sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - *pbuffer);
128138c8a9a5SSteve French 		sec_blob->SessionKey.Length = 0;
128238c8a9a5SSteve French 		sec_blob->SessionKey.MaximumLength = 0;
128338c8a9a5SSteve French 	}
128438c8a9a5SSteve French 
128538c8a9a5SSteve French 	*buflen = tmp - *pbuffer;
128638c8a9a5SSteve French setup_ntlmv2_ret:
128738c8a9a5SSteve French 	return rc;
128838c8a9a5SSteve French }
128938c8a9a5SSteve French 
129038c8a9a5SSteve French enum securityEnum
cifs_select_sectype(struct TCP_Server_Info * server,enum securityEnum requested)129138c8a9a5SSteve French cifs_select_sectype(struct TCP_Server_Info *server, enum securityEnum requested)
129238c8a9a5SSteve French {
129338c8a9a5SSteve French 	switch (server->negflavor) {
129438c8a9a5SSteve French 	case CIFS_NEGFLAVOR_EXTENDED:
129538c8a9a5SSteve French 		switch (requested) {
129638c8a9a5SSteve French 		case Kerberos:
129738c8a9a5SSteve French 		case RawNTLMSSP:
1298*7dc9abfaSSteve French 		case IAKerb:
129938c8a9a5SSteve French 			return requested;
130038c8a9a5SSteve French 		case Unspecified:
130138c8a9a5SSteve French 			if (server->sec_ntlmssp &&
130238c8a9a5SSteve French 			    (global_secflags & CIFSSEC_MAY_NTLMSSP))
130338c8a9a5SSteve French 				return RawNTLMSSP;
1304*7dc9abfaSSteve French 			if ((server->sec_kerberos || server->sec_mskerberos || server->sec_iakerb) &&
130538c8a9a5SSteve French 			    (global_secflags & CIFSSEC_MAY_KRB5))
130638c8a9a5SSteve French 				return Kerberos;
130738c8a9a5SSteve French 			fallthrough;
130838c8a9a5SSteve French 		default:
130938c8a9a5SSteve French 			return Unspecified;
131038c8a9a5SSteve French 		}
131138c8a9a5SSteve French 	case CIFS_NEGFLAVOR_UNENCAP:
131238c8a9a5SSteve French 		switch (requested) {
131338c8a9a5SSteve French 		case NTLMv2:
131438c8a9a5SSteve French 			return requested;
131538c8a9a5SSteve French 		case Unspecified:
131638c8a9a5SSteve French 			if (global_secflags & CIFSSEC_MAY_NTLMV2)
131738c8a9a5SSteve French 				return NTLMv2;
131838c8a9a5SSteve French 			break;
131938c8a9a5SSteve French 		default:
132038c8a9a5SSteve French 			break;
132138c8a9a5SSteve French 		}
132238c8a9a5SSteve French 		fallthrough;
132338c8a9a5SSteve French 	default:
132438c8a9a5SSteve French 		return Unspecified;
132538c8a9a5SSteve French 	}
132638c8a9a5SSteve French }
132738c8a9a5SSteve French 
132838c8a9a5SSteve French struct sess_data {
132938c8a9a5SSteve French 	unsigned int xid;
133038c8a9a5SSteve French 	struct cifs_ses *ses;
133138c8a9a5SSteve French 	struct TCP_Server_Info *server;
133238c8a9a5SSteve French 	struct nls_table *nls_cp;
133338c8a9a5SSteve French 	void (*func)(struct sess_data *);
133438c8a9a5SSteve French 	int result;
133538c8a9a5SSteve French 
133638c8a9a5SSteve French 	/* we will send the SMB in three pieces:
133738c8a9a5SSteve French 	 * a fixed length beginning part, an optional
133838c8a9a5SSteve French 	 * SPNEGO blob (which can be zero length), and a
133938c8a9a5SSteve French 	 * last part which will include the strings
134038c8a9a5SSteve French 	 * and rest of bcc area. This allows us to avoid
134138c8a9a5SSteve French 	 * a large buffer 17K allocation
134238c8a9a5SSteve French 	 */
134338c8a9a5SSteve French 	int buf0_type;
134438c8a9a5SSteve French 	struct kvec iov[3];
134538c8a9a5SSteve French };
134638c8a9a5SSteve French 
134738c8a9a5SSteve French #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
sess_alloc_buffer(struct sess_data * sess_data,int wct)134838c8a9a5SSteve French static int
134938c8a9a5SSteve French sess_alloc_buffer(struct sess_data *sess_data, int wct)
135038c8a9a5SSteve French {
135138c8a9a5SSteve French 	int rc;
135238c8a9a5SSteve French 	struct cifs_ses *ses = sess_data->ses;
135338c8a9a5SSteve French 	struct smb_hdr *smb_buf;
135438c8a9a5SSteve French 
135538c8a9a5SSteve French 	rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses,
135638c8a9a5SSteve French 				  (void **)&smb_buf);
135738c8a9a5SSteve French 
135838c8a9a5SSteve French 	if (rc)
135938c8a9a5SSteve French 		return rc;
136038c8a9a5SSteve French 
136138c8a9a5SSteve French 	sess_data->iov[0].iov_base = (char *)smb_buf;
136238c8a9a5SSteve French 	sess_data->iov[0].iov_len = be32_to_cpu(smb_buf->smb_buf_length) + 4;
136338c8a9a5SSteve French 	/*
136438c8a9a5SSteve French 	 * This variable will be used to clear the buffer
136538c8a9a5SSteve French 	 * allocated above in case of any error in the calling function.
136638c8a9a5SSteve French 	 */
136738c8a9a5SSteve French 	sess_data->buf0_type = CIFS_SMALL_BUFFER;
136838c8a9a5SSteve French 
136938c8a9a5SSteve French 	/* 2000 big enough to fit max user, domain, NOS name etc. */
137038c8a9a5SSteve French 	sess_data->iov[2].iov_base = kmalloc(2000, GFP_KERNEL);
137138c8a9a5SSteve French 	if (!sess_data->iov[2].iov_base) {
137238c8a9a5SSteve French 		rc = -ENOMEM;
137338c8a9a5SSteve French 		goto out_free_smb_buf;
137438c8a9a5SSteve French 	}
137538c8a9a5SSteve French 
137638c8a9a5SSteve French 	return 0;
137738c8a9a5SSteve French 
137838c8a9a5SSteve French out_free_smb_buf:
137938c8a9a5SSteve French 	cifs_small_buf_release(smb_buf);
138038c8a9a5SSteve French 	sess_data->iov[0].iov_base = NULL;
138138c8a9a5SSteve French 	sess_data->iov[0].iov_len = 0;
138238c8a9a5SSteve French 	sess_data->buf0_type = CIFS_NO_BUFFER;
138338c8a9a5SSteve French 	return rc;
138438c8a9a5SSteve French }
138538c8a9a5SSteve French 
sess_free_buffer(struct sess_data * sess_data)138638c8a9a5SSteve French static void
138738c8a9a5SSteve French sess_free_buffer(struct sess_data *sess_data)
138838c8a9a5SSteve French {
138938c8a9a5SSteve French 	struct kvec *iov = sess_data->iov;
139038c8a9a5SSteve French 
139138c8a9a5SSteve French 	/*
139238c8a9a5SSteve French 	 * Zero the session data before freeing, as it might contain sensitive info (keys, etc).
139338c8a9a5SSteve French 	 * Note that iov[1] is already freed by caller.
139438c8a9a5SSteve French 	 */
139538c8a9a5SSteve French 	if (sess_data->buf0_type != CIFS_NO_BUFFER && iov[0].iov_base)
139638c8a9a5SSteve French 		memzero_explicit(iov[0].iov_base, iov[0].iov_len);
139738c8a9a5SSteve French 
139838c8a9a5SSteve French 	free_rsp_buf(sess_data->buf0_type, iov[0].iov_base);
139938c8a9a5SSteve French 	sess_data->buf0_type = CIFS_NO_BUFFER;
140038c8a9a5SSteve French 	kfree_sensitive(iov[2].iov_base);
140138c8a9a5SSteve French }
140238c8a9a5SSteve French 
sess_establish_session(struct sess_data * sess_data)140338c8a9a5SSteve French static int
140438c8a9a5SSteve French sess_establish_session(struct sess_data *sess_data)
140538c8a9a5SSteve French {
140638c8a9a5SSteve French 	struct cifs_ses *ses = sess_data->ses;
140738c8a9a5SSteve French 	struct TCP_Server_Info *server = sess_data->server;
140838c8a9a5SSteve French 
140938c8a9a5SSteve French 	cifs_server_lock(server);
141038c8a9a5SSteve French 	if (!server->session_estab) {
141138c8a9a5SSteve French 		if (server->sign) {
141238c8a9a5SSteve French 			server->session_key.response =
141338c8a9a5SSteve French 				kmemdup(ses->auth_key.response,
141438c8a9a5SSteve French 				ses->auth_key.len, GFP_KERNEL);
141538c8a9a5SSteve French 			if (!server->session_key.response) {
141638c8a9a5SSteve French 				cifs_server_unlock(server);
141738c8a9a5SSteve French 				return -ENOMEM;
141838c8a9a5SSteve French 			}
141938c8a9a5SSteve French 			server->session_key.len =
142038c8a9a5SSteve French 						ses->auth_key.len;
142138c8a9a5SSteve French 		}
142238c8a9a5SSteve French 		server->sequence_number = 0x2;
142338c8a9a5SSteve French 		server->session_estab = true;
142438c8a9a5SSteve French 	}
142538c8a9a5SSteve French 	cifs_server_unlock(server);
142638c8a9a5SSteve French 
142738c8a9a5SSteve French 	cifs_dbg(FYI, "CIFS session established successfully\n");
142838c8a9a5SSteve French 	return 0;
142938c8a9a5SSteve French }
143038c8a9a5SSteve French 
sess_sendreceive(struct sess_data * sess_data)143138c8a9a5SSteve French static int
143238c8a9a5SSteve French sess_sendreceive(struct sess_data *sess_data)
143338c8a9a5SSteve French {
143438c8a9a5SSteve French 	int rc;
143538c8a9a5SSteve French 	struct smb_hdr *smb_buf = (struct smb_hdr *) sess_data->iov[0].iov_base;
143638c8a9a5SSteve French 	__u16 count;
143738c8a9a5SSteve French 	struct kvec rsp_iov = { NULL, 0 };
143838c8a9a5SSteve French 
143938c8a9a5SSteve French 	count = sess_data->iov[1].iov_len + sess_data->iov[2].iov_len;
144038c8a9a5SSteve French 	be32_add_cpu(&smb_buf->smb_buf_length, count);
144138c8a9a5SSteve French 	put_bcc(count, smb_buf);
144238c8a9a5SSteve French 
144338c8a9a5SSteve French 	rc = SendReceive2(sess_data->xid, sess_data->ses,
144438c8a9a5SSteve French 			  sess_data->iov, 3 /* num_iovecs */,
144538c8a9a5SSteve French 			  &sess_data->buf0_type,
144638c8a9a5SSteve French 			  CIFS_LOG_ERROR, &rsp_iov);
144738c8a9a5SSteve French 	cifs_small_buf_release(sess_data->iov[0].iov_base);
144838c8a9a5SSteve French 	memcpy(&sess_data->iov[0], &rsp_iov, sizeof(struct kvec));
144938c8a9a5SSteve French 
145038c8a9a5SSteve French 	return rc;
145138c8a9a5SSteve French }
145238c8a9a5SSteve French 
sess_auth_ntlmv2(struct sess_data * sess_data)145338c8a9a5SSteve French static void
145438c8a9a5SSteve French sess_auth_ntlmv2(struct sess_data *sess_data)
145538c8a9a5SSteve French {
145638c8a9a5SSteve French 	int rc = 0;
145738c8a9a5SSteve French 	struct smb_hdr *smb_buf;
145838c8a9a5SSteve French 	SESSION_SETUP_ANDX *pSMB;
145938c8a9a5SSteve French 	char *bcc_ptr;
146038c8a9a5SSteve French 	struct cifs_ses *ses = sess_data->ses;
146138c8a9a5SSteve French 	struct TCP_Server_Info *server = sess_data->server;
146238c8a9a5SSteve French 	__u32 capabilities;
146338c8a9a5SSteve French 	__u16 bytes_remaining;
146438c8a9a5SSteve French 
146538c8a9a5SSteve French 	/* old style NTLM sessionsetup */
146638c8a9a5SSteve French 	/* wct = 13 */
146738c8a9a5SSteve French 	rc = sess_alloc_buffer(sess_data, 13);
146838c8a9a5SSteve French 	if (rc)
146938c8a9a5SSteve French 		goto out;
147038c8a9a5SSteve French 
147138c8a9a5SSteve French 	pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
147238c8a9a5SSteve French 	bcc_ptr = sess_data->iov[2].iov_base;
147338c8a9a5SSteve French 	capabilities = cifs_ssetup_hdr(ses, server, pSMB);
147438c8a9a5SSteve French 
147538c8a9a5SSteve French 	pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
147638c8a9a5SSteve French 
147738c8a9a5SSteve French 	/* LM2 password would be here if we supported it */
147838c8a9a5SSteve French 	pSMB->req_no_secext.CaseInsensitivePasswordLength = 0;
147938c8a9a5SSteve French 
148038c8a9a5SSteve French 	if (ses->user_name != NULL) {
148138c8a9a5SSteve French 		/* calculate nlmv2 response and session key */
148238c8a9a5SSteve French 		rc = setup_ntlmv2_rsp(ses, sess_data->nls_cp);
148338c8a9a5SSteve French 		if (rc) {
148438c8a9a5SSteve French 			cifs_dbg(VFS, "Error %d during NTLMv2 authentication\n", rc);
148538c8a9a5SSteve French 			goto out;
148638c8a9a5SSteve French 		}
148738c8a9a5SSteve French 
148838c8a9a5SSteve French 		memcpy(bcc_ptr, ses->auth_key.response + CIFS_SESS_KEY_SIZE,
148938c8a9a5SSteve French 				ses->auth_key.len - CIFS_SESS_KEY_SIZE);
149038c8a9a5SSteve French 		bcc_ptr += ses->auth_key.len - CIFS_SESS_KEY_SIZE;
149138c8a9a5SSteve French 
149238c8a9a5SSteve French 		/* set case sensitive password length after tilen may get
149338c8a9a5SSteve French 		 * assigned, tilen is 0 otherwise.
149438c8a9a5SSteve French 		 */
149538c8a9a5SSteve French 		pSMB->req_no_secext.CaseSensitivePasswordLength =
149638c8a9a5SSteve French 			cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE);
149738c8a9a5SSteve French 	} else {
149838c8a9a5SSteve French 		pSMB->req_no_secext.CaseSensitivePasswordLength = 0;
149938c8a9a5SSteve French 	}
150038c8a9a5SSteve French 
150138c8a9a5SSteve French 	if (ses->capabilities & CAP_UNICODE) {
150238c8a9a5SSteve French 		if (!IS_ALIGNED(sess_data->iov[0].iov_len, 2)) {
150338c8a9a5SSteve French 			*bcc_ptr = 0;
150438c8a9a5SSteve French 			bcc_ptr++;
150538c8a9a5SSteve French 		}
150638c8a9a5SSteve French 		unicode_ssetup_strings(&bcc_ptr, ses, sess_data->nls_cp);
150738c8a9a5SSteve French 	} else {
150838c8a9a5SSteve French 		ascii_ssetup_strings(&bcc_ptr, ses, sess_data->nls_cp);
150938c8a9a5SSteve French 	}
151038c8a9a5SSteve French 
151138c8a9a5SSteve French 
151238c8a9a5SSteve French 	sess_data->iov[2].iov_len = (long) bcc_ptr -
151338c8a9a5SSteve French 			(long) sess_data->iov[2].iov_base;
151438c8a9a5SSteve French 
151538c8a9a5SSteve French 	rc = sess_sendreceive(sess_data);
151638c8a9a5SSteve French 	if (rc)
151738c8a9a5SSteve French 		goto out;
151838c8a9a5SSteve French 
151938c8a9a5SSteve French 	pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
152038c8a9a5SSteve French 	smb_buf = (struct smb_hdr *)sess_data->iov[0].iov_base;
152138c8a9a5SSteve French 
152238c8a9a5SSteve French 	if (smb_buf->WordCount != 3) {
152338c8a9a5SSteve French 		rc = -EIO;
152438c8a9a5SSteve French 		cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount);
152538c8a9a5SSteve French 		goto out;
152638c8a9a5SSteve French 	}
152738c8a9a5SSteve French 
152838c8a9a5SSteve French 	if (le16_to_cpu(pSMB->resp.Action) & GUEST_LOGIN)
152938c8a9a5SSteve French 		cifs_dbg(FYI, "Guest login\n"); /* BB mark SesInfo struct? */
153038c8a9a5SSteve French 
153138c8a9a5SSteve French 	ses->Suid = smb_buf->Uid;   /* UID left in wire format (le) */
153238c8a9a5SSteve French 	cifs_dbg(FYI, "UID = %llu\n", ses->Suid);
153338c8a9a5SSteve French 
153438c8a9a5SSteve French 	bytes_remaining = get_bcc(smb_buf);
153538c8a9a5SSteve French 	bcc_ptr = pByteArea(smb_buf);
153638c8a9a5SSteve French 
153738c8a9a5SSteve French 	/* BB check if Unicode and decode strings */
153838c8a9a5SSteve French 	if (bytes_remaining == 0) {
153938c8a9a5SSteve French 		/* no string area to decode, do nothing */
154038c8a9a5SSteve French 	} else if (smb_buf->Flags2 & SMBFLG2_UNICODE) {
154138c8a9a5SSteve French 		/* unicode string area must be word-aligned */
154238c8a9a5SSteve French 		if (!IS_ALIGNED((unsigned long)bcc_ptr - (unsigned long)smb_buf, 2)) {
154338c8a9a5SSteve French 			++bcc_ptr;
154438c8a9a5SSteve French 			--bytes_remaining;
154538c8a9a5SSteve French 		}
154638c8a9a5SSteve French 		decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses,
154738c8a9a5SSteve French 				      sess_data->nls_cp);
154838c8a9a5SSteve French 	} else {
154938c8a9a5SSteve French 		decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses,
155038c8a9a5SSteve French 				    sess_data->nls_cp);
155138c8a9a5SSteve French 	}
155238c8a9a5SSteve French 
155338c8a9a5SSteve French 	rc = sess_establish_session(sess_data);
155438c8a9a5SSteve French out:
155538c8a9a5SSteve French 	sess_data->result = rc;
155638c8a9a5SSteve French 	sess_data->func = NULL;
155738c8a9a5SSteve French 	sess_free_buffer(sess_data);
155838c8a9a5SSteve French 	kfree_sensitive(ses->auth_key.response);
155938c8a9a5SSteve French 	ses->auth_key.response = NULL;
156038c8a9a5SSteve French }
156138c8a9a5SSteve French 
156238c8a9a5SSteve French #ifdef CONFIG_CIFS_UPCALL
sess_auth_kerberos(struct sess_data * sess_data)156338c8a9a5SSteve French static void
156438c8a9a5SSteve French sess_auth_kerberos(struct sess_data *sess_data)
156538c8a9a5SSteve French {
156638c8a9a5SSteve French 	int rc = 0;
156738c8a9a5SSteve French 	struct smb_hdr *smb_buf;
156838c8a9a5SSteve French 	SESSION_SETUP_ANDX *pSMB;
156938c8a9a5SSteve French 	char *bcc_ptr;
157038c8a9a5SSteve French 	struct cifs_ses *ses = sess_data->ses;
157138c8a9a5SSteve French 	struct TCP_Server_Info *server = sess_data->server;
157238c8a9a5SSteve French 	__u32 capabilities;
157338c8a9a5SSteve French 	__u16 bytes_remaining;
157438c8a9a5SSteve French 	struct key *spnego_key = NULL;
157538c8a9a5SSteve French 	struct cifs_spnego_msg *msg;
157638c8a9a5SSteve French 	u16 blob_len;
157738c8a9a5SSteve French 
157838c8a9a5SSteve French 	/* extended security */
157938c8a9a5SSteve French 	/* wct = 12 */
158038c8a9a5SSteve French 	rc = sess_alloc_buffer(sess_data, 12);
158138c8a9a5SSteve French 	if (rc)
158238c8a9a5SSteve French 		goto out;
158338c8a9a5SSteve French 
158438c8a9a5SSteve French 	pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
158538c8a9a5SSteve French 	bcc_ptr = sess_data->iov[2].iov_base;
158638c8a9a5SSteve French 	capabilities = cifs_ssetup_hdr(ses, server, pSMB);
158738c8a9a5SSteve French 
158838c8a9a5SSteve French 	spnego_key = cifs_get_spnego_key(ses, server);
158938c8a9a5SSteve French 	if (IS_ERR(spnego_key)) {
159038c8a9a5SSteve French 		rc = PTR_ERR(spnego_key);
159138c8a9a5SSteve French 		spnego_key = NULL;
159238c8a9a5SSteve French 		goto out;
159338c8a9a5SSteve French 	}
159438c8a9a5SSteve French 
159538c8a9a5SSteve French 	msg = spnego_key->payload.data[0];
159638c8a9a5SSteve French 	/*
159738c8a9a5SSteve French 	 * check version field to make sure that cifs.upcall is
159838c8a9a5SSteve French 	 * sending us a response in an expected form
159938c8a9a5SSteve French 	 */
160038c8a9a5SSteve French 	if (msg->version != CIFS_SPNEGO_UPCALL_VERSION) {
160138c8a9a5SSteve French 		cifs_dbg(VFS, "incorrect version of cifs.upcall (expected %d but got %d)\n",
160238c8a9a5SSteve French 			 CIFS_SPNEGO_UPCALL_VERSION, msg->version);
160338c8a9a5SSteve French 		rc = -EKEYREJECTED;
160438c8a9a5SSteve French 		goto out_put_spnego_key;
160538c8a9a5SSteve French 	}
160638c8a9a5SSteve French 
160738c8a9a5SSteve French 	kfree_sensitive(ses->auth_key.response);
160838c8a9a5SSteve French 	ses->auth_key.response = kmemdup(msg->data, msg->sesskey_len,
160938c8a9a5SSteve French 					 GFP_KERNEL);
161038c8a9a5SSteve French 	if (!ses->auth_key.response) {
161138c8a9a5SSteve French 		cifs_dbg(VFS, "Kerberos can't allocate (%u bytes) memory\n",
161238c8a9a5SSteve French 			 msg->sesskey_len);
161338c8a9a5SSteve French 		rc = -ENOMEM;
161438c8a9a5SSteve French 		goto out_put_spnego_key;
161538c8a9a5SSteve French 	}
161638c8a9a5SSteve French 	ses->auth_key.len = msg->sesskey_len;
161738c8a9a5SSteve French 
161838c8a9a5SSteve French 	pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
161938c8a9a5SSteve French 	capabilities |= CAP_EXTENDED_SECURITY;
162038c8a9a5SSteve French 	pSMB->req.Capabilities = cpu_to_le32(capabilities);
162138c8a9a5SSteve French 	sess_data->iov[1].iov_base = msg->data + msg->sesskey_len;
162238c8a9a5SSteve French 	sess_data->iov[1].iov_len = msg->secblob_len;
162338c8a9a5SSteve French 	pSMB->req.SecurityBlobLength = cpu_to_le16(sess_data->iov[1].iov_len);
162438c8a9a5SSteve French 
162538c8a9a5SSteve French 	if (ses->capabilities & CAP_UNICODE) {
162638c8a9a5SSteve French 		/* unicode strings must be word aligned */
162738c8a9a5SSteve French 		if (!IS_ALIGNED(sess_data->iov[0].iov_len + sess_data->iov[1].iov_len, 2)) {
162838c8a9a5SSteve French 			*bcc_ptr = 0;
162938c8a9a5SSteve French 			bcc_ptr++;
163038c8a9a5SSteve French 		}
163138c8a9a5SSteve French 		unicode_oslm_strings(&bcc_ptr, sess_data->nls_cp);
163238c8a9a5SSteve French 		unicode_domain_string(&bcc_ptr, ses, sess_data->nls_cp);
163338c8a9a5SSteve French 	} else {
163438c8a9a5SSteve French 		/* BB: is this right? */
163538c8a9a5SSteve French 		ascii_ssetup_strings(&bcc_ptr, ses, sess_data->nls_cp);
163638c8a9a5SSteve French 	}
163738c8a9a5SSteve French 
163838c8a9a5SSteve French 	sess_data->iov[2].iov_len = (long) bcc_ptr -
163938c8a9a5SSteve French 			(long) sess_data->iov[2].iov_base;
164038c8a9a5SSteve French 
164138c8a9a5SSteve French 	rc = sess_sendreceive(sess_data);
164238c8a9a5SSteve French 	if (rc)
164338c8a9a5SSteve French 		goto out_put_spnego_key;
164438c8a9a5SSteve French 
164538c8a9a5SSteve French 	pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
164638c8a9a5SSteve French 	smb_buf = (struct smb_hdr *)sess_data->iov[0].iov_base;
164738c8a9a5SSteve French 
164838c8a9a5SSteve French 	if (smb_buf->WordCount != 4) {
164938c8a9a5SSteve French 		rc = -EIO;
165038c8a9a5SSteve French 		cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount);
165138c8a9a5SSteve French 		goto out_put_spnego_key;
165238c8a9a5SSteve French 	}
165338c8a9a5SSteve French 
165438c8a9a5SSteve French 	if (le16_to_cpu(pSMB->resp.Action) & GUEST_LOGIN)
165538c8a9a5SSteve French 		cifs_dbg(FYI, "Guest login\n"); /* BB mark SesInfo struct? */
165638c8a9a5SSteve French 
165738c8a9a5SSteve French 	ses->Suid = smb_buf->Uid;   /* UID left in wire format (le) */
165838c8a9a5SSteve French 	cifs_dbg(FYI, "UID = %llu\n", ses->Suid);
165938c8a9a5SSteve French 
166038c8a9a5SSteve French 	bytes_remaining = get_bcc(smb_buf);
166138c8a9a5SSteve French 	bcc_ptr = pByteArea(smb_buf);
166238c8a9a5SSteve French 
166338c8a9a5SSteve French 	blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength);
166438c8a9a5SSteve French 	if (blob_len > bytes_remaining) {
166538c8a9a5SSteve French 		cifs_dbg(VFS, "bad security blob length %d\n",
166638c8a9a5SSteve French 				blob_len);
166738c8a9a5SSteve French 		rc = -EINVAL;
166838c8a9a5SSteve French 		goto out_put_spnego_key;
166938c8a9a5SSteve French 	}
167038c8a9a5SSteve French 	bcc_ptr += blob_len;
167138c8a9a5SSteve French 	bytes_remaining -= blob_len;
167238c8a9a5SSteve French 
167338c8a9a5SSteve French 	/* BB check if Unicode and decode strings */
167438c8a9a5SSteve French 	if (bytes_remaining == 0) {
167538c8a9a5SSteve French 		/* no string area to decode, do nothing */
167638c8a9a5SSteve French 	} else if (smb_buf->Flags2 & SMBFLG2_UNICODE) {
167738c8a9a5SSteve French 		/* unicode string area must be word-aligned */
167838c8a9a5SSteve French 		if (!IS_ALIGNED((unsigned long)bcc_ptr - (unsigned long)smb_buf, 2)) {
167938c8a9a5SSteve French 			++bcc_ptr;
168038c8a9a5SSteve French 			--bytes_remaining;
168138c8a9a5SSteve French 		}
168238c8a9a5SSteve French 		decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses,
168338c8a9a5SSteve French 				      sess_data->nls_cp);
168438c8a9a5SSteve French 	} else {
168538c8a9a5SSteve French 		decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses,
168638c8a9a5SSteve French 				    sess_data->nls_cp);
168738c8a9a5SSteve French 	}
168838c8a9a5SSteve French 
168938c8a9a5SSteve French 	rc = sess_establish_session(sess_data);
169038c8a9a5SSteve French out_put_spnego_key:
169138c8a9a5SSteve French 	key_invalidate(spnego_key);
169238c8a9a5SSteve French 	key_put(spnego_key);
169338c8a9a5SSteve French out:
169438c8a9a5SSteve French 	sess_data->result = rc;
169538c8a9a5SSteve French 	sess_data->func = NULL;
169638c8a9a5SSteve French 	sess_free_buffer(sess_data);
169738c8a9a5SSteve French 	kfree_sensitive(ses->auth_key.response);
169838c8a9a5SSteve French 	ses->auth_key.response = NULL;
169938c8a9a5SSteve French }
170038c8a9a5SSteve French 
170138c8a9a5SSteve French #endif /* ! CONFIG_CIFS_UPCALL */
170238c8a9a5SSteve French 
170338c8a9a5SSteve French /*
170438c8a9a5SSteve French  * The required kvec buffers have to be allocated before calling this
170538c8a9a5SSteve French  * function.
170638c8a9a5SSteve French  */
_sess_auth_rawntlmssp_assemble_req(struct sess_data * sess_data)170738c8a9a5SSteve French static int
170838c8a9a5SSteve French _sess_auth_rawntlmssp_assemble_req(struct sess_data *sess_data)
170938c8a9a5SSteve French {
171038c8a9a5SSteve French 	SESSION_SETUP_ANDX *pSMB;
171138c8a9a5SSteve French 	struct cifs_ses *ses = sess_data->ses;
171238c8a9a5SSteve French 	struct TCP_Server_Info *server = sess_data->server;
171338c8a9a5SSteve French 	__u32 capabilities;
171438c8a9a5SSteve French 	char *bcc_ptr;
171538c8a9a5SSteve French 
171638c8a9a5SSteve French 	pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
171738c8a9a5SSteve French 
171838c8a9a5SSteve French 	capabilities = cifs_ssetup_hdr(ses, server, pSMB);
171938c8a9a5SSteve French 	if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) {
172038c8a9a5SSteve French 		cifs_dbg(VFS, "NTLMSSP requires Unicode support\n");
172138c8a9a5SSteve French 		return -ENOSYS;
172238c8a9a5SSteve French 	}
172338c8a9a5SSteve French 
172438c8a9a5SSteve French 	pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
172538c8a9a5SSteve French 	capabilities |= CAP_EXTENDED_SECURITY;
172638c8a9a5SSteve French 	pSMB->req.Capabilities |= cpu_to_le32(capabilities);
172738c8a9a5SSteve French 
172838c8a9a5SSteve French 	bcc_ptr = sess_data->iov[2].iov_base;
172938c8a9a5SSteve French 	/* unicode strings must be word aligned */
173038c8a9a5SSteve French 	if (!IS_ALIGNED(sess_data->iov[0].iov_len + sess_data->iov[1].iov_len, 2)) {
173138c8a9a5SSteve French 		*bcc_ptr = 0;
173238c8a9a5SSteve French 		bcc_ptr++;
173338c8a9a5SSteve French 	}
173438c8a9a5SSteve French 	unicode_oslm_strings(&bcc_ptr, sess_data->nls_cp);
173538c8a9a5SSteve French 
173638c8a9a5SSteve French 	sess_data->iov[2].iov_len = (long) bcc_ptr -
173738c8a9a5SSteve French 					(long) sess_data->iov[2].iov_base;
173838c8a9a5SSteve French 
173938c8a9a5SSteve French 	return 0;
174038c8a9a5SSteve French }
174138c8a9a5SSteve French 
174238c8a9a5SSteve French static void
174338c8a9a5SSteve French sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data);
174438c8a9a5SSteve French 
sess_auth_rawntlmssp_negotiate(struct sess_data * sess_data)174538c8a9a5SSteve French static void
174638c8a9a5SSteve French sess_auth_rawntlmssp_negotiate(struct sess_data *sess_data)
174738c8a9a5SSteve French {
174838c8a9a5SSteve French 	int rc;
174938c8a9a5SSteve French 	struct smb_hdr *smb_buf;
175038c8a9a5SSteve French 	SESSION_SETUP_ANDX *pSMB;
175138c8a9a5SSteve French 	struct cifs_ses *ses = sess_data->ses;
175238c8a9a5SSteve French 	struct TCP_Server_Info *server = sess_data->server;
175338c8a9a5SSteve French 	__u16 bytes_remaining;
175438c8a9a5SSteve French 	char *bcc_ptr;
175538c8a9a5SSteve French 	unsigned char *ntlmsspblob = NULL;
175638c8a9a5SSteve French 	u16 blob_len;
175738c8a9a5SSteve French 
175838c8a9a5SSteve French 	cifs_dbg(FYI, "rawntlmssp session setup negotiate phase\n");
175938c8a9a5SSteve French 
176038c8a9a5SSteve French 	/*
176138c8a9a5SSteve French 	 * if memory allocation is successful, caller of this function
176238c8a9a5SSteve French 	 * frees it.
176338c8a9a5SSteve French 	 */
176438c8a9a5SSteve French 	ses->ntlmssp = kmalloc(sizeof(struct ntlmssp_auth), GFP_KERNEL);
176538c8a9a5SSteve French 	if (!ses->ntlmssp) {
176638c8a9a5SSteve French 		rc = -ENOMEM;
176738c8a9a5SSteve French 		goto out;
176838c8a9a5SSteve French 	}
176938c8a9a5SSteve French 	ses->ntlmssp->sesskey_per_smbsess = false;
177038c8a9a5SSteve French 
177138c8a9a5SSteve French 	/* wct = 12 */
177238c8a9a5SSteve French 	rc = sess_alloc_buffer(sess_data, 12);
177338c8a9a5SSteve French 	if (rc)
177438c8a9a5SSteve French 		goto out;
177538c8a9a5SSteve French 
177638c8a9a5SSteve French 	pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
177738c8a9a5SSteve French 
177838c8a9a5SSteve French 	/* Build security blob before we assemble the request */
177938c8a9a5SSteve French 	rc = build_ntlmssp_negotiate_blob(&ntlmsspblob,
178038c8a9a5SSteve French 				     &blob_len, ses, server,
178138c8a9a5SSteve French 				     sess_data->nls_cp);
178238c8a9a5SSteve French 	if (rc)
178338c8a9a5SSteve French 		goto out_free_ntlmsspblob;
178438c8a9a5SSteve French 
178538c8a9a5SSteve French 	sess_data->iov[1].iov_len = blob_len;
178638c8a9a5SSteve French 	sess_data->iov[1].iov_base = ntlmsspblob;
178738c8a9a5SSteve French 	pSMB->req.SecurityBlobLength = cpu_to_le16(blob_len);
178838c8a9a5SSteve French 
178938c8a9a5SSteve French 	rc = _sess_auth_rawntlmssp_assemble_req(sess_data);
179038c8a9a5SSteve French 	if (rc)
179138c8a9a5SSteve French 		goto out_free_ntlmsspblob;
179238c8a9a5SSteve French 
179338c8a9a5SSteve French 	rc = sess_sendreceive(sess_data);
179438c8a9a5SSteve French 
179538c8a9a5SSteve French 	pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
179638c8a9a5SSteve French 	smb_buf = (struct smb_hdr *)sess_data->iov[0].iov_base;
179738c8a9a5SSteve French 
179838c8a9a5SSteve French 	/* If true, rc here is expected and not an error */
179938c8a9a5SSteve French 	if (sess_data->buf0_type != CIFS_NO_BUFFER &&
180038c8a9a5SSteve French 	    smb_buf->Status.CifsError ==
180138c8a9a5SSteve French 			cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
180238c8a9a5SSteve French 		rc = 0;
180338c8a9a5SSteve French 
180438c8a9a5SSteve French 	if (rc)
180538c8a9a5SSteve French 		goto out_free_ntlmsspblob;
180638c8a9a5SSteve French 
180738c8a9a5SSteve French 	cifs_dbg(FYI, "rawntlmssp session setup challenge phase\n");
180838c8a9a5SSteve French 
180938c8a9a5SSteve French 	if (smb_buf->WordCount != 4) {
181038c8a9a5SSteve French 		rc = -EIO;
181138c8a9a5SSteve French 		cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount);
181238c8a9a5SSteve French 		goto out_free_ntlmsspblob;
181338c8a9a5SSteve French 	}
181438c8a9a5SSteve French 
181538c8a9a5SSteve French 	ses->Suid = smb_buf->Uid;   /* UID left in wire format (le) */
181638c8a9a5SSteve French 	cifs_dbg(FYI, "UID = %llu\n", ses->Suid);
181738c8a9a5SSteve French 
181838c8a9a5SSteve French 	bytes_remaining = get_bcc(smb_buf);
181938c8a9a5SSteve French 	bcc_ptr = pByteArea(smb_buf);
182038c8a9a5SSteve French 
182138c8a9a5SSteve French 	blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength);
182238c8a9a5SSteve French 	if (blob_len > bytes_remaining) {
182338c8a9a5SSteve French 		cifs_dbg(VFS, "bad security blob length %d\n",
182438c8a9a5SSteve French 				blob_len);
182538c8a9a5SSteve French 		rc = -EINVAL;
182638c8a9a5SSteve French 		goto out_free_ntlmsspblob;
182738c8a9a5SSteve French 	}
182838c8a9a5SSteve French 
182938c8a9a5SSteve French 	rc = decode_ntlmssp_challenge(bcc_ptr, blob_len, ses);
183038c8a9a5SSteve French 
183138c8a9a5SSteve French out_free_ntlmsspblob:
183238c8a9a5SSteve French 	kfree_sensitive(ntlmsspblob);
183338c8a9a5SSteve French out:
183438c8a9a5SSteve French 	sess_free_buffer(sess_data);
183538c8a9a5SSteve French 
183638c8a9a5SSteve French 	if (!rc) {
183738c8a9a5SSteve French 		sess_data->func = sess_auth_rawntlmssp_authenticate;
183838c8a9a5SSteve French 		return;
183938c8a9a5SSteve French 	}
184038c8a9a5SSteve French 
184138c8a9a5SSteve French 	/* Else error. Cleanup */
184238c8a9a5SSteve French 	kfree_sensitive(ses->auth_key.response);
184338c8a9a5SSteve French 	ses->auth_key.response = NULL;
184438c8a9a5SSteve French 	kfree_sensitive(ses->ntlmssp);
184538c8a9a5SSteve French 	ses->ntlmssp = NULL;
184638c8a9a5SSteve French 
184738c8a9a5SSteve French 	sess_data->func = NULL;
184838c8a9a5SSteve French 	sess_data->result = rc;
184938c8a9a5SSteve French }
185038c8a9a5SSteve French 
sess_auth_rawntlmssp_authenticate(struct sess_data * sess_data)185138c8a9a5SSteve French static void
185238c8a9a5SSteve French sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data)
185338c8a9a5SSteve French {
185438c8a9a5SSteve French 	int rc;
185538c8a9a5SSteve French 	struct smb_hdr *smb_buf;
185638c8a9a5SSteve French 	SESSION_SETUP_ANDX *pSMB;
185738c8a9a5SSteve French 	struct cifs_ses *ses = sess_data->ses;
185838c8a9a5SSteve French 	struct TCP_Server_Info *server = sess_data->server;
185938c8a9a5SSteve French 	__u16 bytes_remaining;
186038c8a9a5SSteve French 	char *bcc_ptr;
186138c8a9a5SSteve French 	unsigned char *ntlmsspblob = NULL;
186238c8a9a5SSteve French 	u16 blob_len;
186338c8a9a5SSteve French 
186438c8a9a5SSteve French 	cifs_dbg(FYI, "rawntlmssp session setup authenticate phase\n");
186538c8a9a5SSteve French 
186638c8a9a5SSteve French 	/* wct = 12 */
186738c8a9a5SSteve French 	rc = sess_alloc_buffer(sess_data, 12);
186838c8a9a5SSteve French 	if (rc)
186938c8a9a5SSteve French 		goto out;
187038c8a9a5SSteve French 
187138c8a9a5SSteve French 	/* Build security blob before we assemble the request */
187238c8a9a5SSteve French 	pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
187338c8a9a5SSteve French 	smb_buf = (struct smb_hdr *)pSMB;
187438c8a9a5SSteve French 	rc = build_ntlmssp_auth_blob(&ntlmsspblob,
187538c8a9a5SSteve French 					&blob_len, ses, server,
187638c8a9a5SSteve French 					sess_data->nls_cp);
187738c8a9a5SSteve French 	if (rc)
187838c8a9a5SSteve French 		goto out_free_ntlmsspblob;
187938c8a9a5SSteve French 	sess_data->iov[1].iov_len = blob_len;
188038c8a9a5SSteve French 	sess_data->iov[1].iov_base = ntlmsspblob;
188138c8a9a5SSteve French 	pSMB->req.SecurityBlobLength = cpu_to_le16(blob_len);
188238c8a9a5SSteve French 	/*
188338c8a9a5SSteve French 	 * Make sure that we tell the server that we are using
188438c8a9a5SSteve French 	 * the uid that it just gave us back on the response
188538c8a9a5SSteve French 	 * (challenge)
188638c8a9a5SSteve French 	 */
188738c8a9a5SSteve French 	smb_buf->Uid = ses->Suid;
188838c8a9a5SSteve French 
188938c8a9a5SSteve French 	rc = _sess_auth_rawntlmssp_assemble_req(sess_data);
189038c8a9a5SSteve French 	if (rc)
189138c8a9a5SSteve French 		goto out_free_ntlmsspblob;
189238c8a9a5SSteve French 
189338c8a9a5SSteve French 	rc = sess_sendreceive(sess_data);
189438c8a9a5SSteve French 	if (rc)
189538c8a9a5SSteve French 		goto out_free_ntlmsspblob;
189638c8a9a5SSteve French 
189738c8a9a5SSteve French 	pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
189838c8a9a5SSteve French 	smb_buf = (struct smb_hdr *)sess_data->iov[0].iov_base;
189938c8a9a5SSteve French 	if (smb_buf->WordCount != 4) {
190038c8a9a5SSteve French 		rc = -EIO;
190138c8a9a5SSteve French 		cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount);
190238c8a9a5SSteve French 		goto out_free_ntlmsspblob;
190338c8a9a5SSteve French 	}
190438c8a9a5SSteve French 
190538c8a9a5SSteve French 	if (le16_to_cpu(pSMB->resp.Action) & GUEST_LOGIN)
190638c8a9a5SSteve French 		cifs_dbg(FYI, "Guest login\n"); /* BB mark SesInfo struct? */
190738c8a9a5SSteve French 
190838c8a9a5SSteve French 	if (ses->Suid != smb_buf->Uid) {
190938c8a9a5SSteve French 		ses->Suid = smb_buf->Uid;
191038c8a9a5SSteve French 		cifs_dbg(FYI, "UID changed! new UID = %llu\n", ses->Suid);
191138c8a9a5SSteve French 	}
191238c8a9a5SSteve French 
191338c8a9a5SSteve French 	bytes_remaining = get_bcc(smb_buf);
191438c8a9a5SSteve French 	bcc_ptr = pByteArea(smb_buf);
191538c8a9a5SSteve French 	blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength);
191638c8a9a5SSteve French 	if (blob_len > bytes_remaining) {
191738c8a9a5SSteve French 		cifs_dbg(VFS, "bad security blob length %d\n",
191838c8a9a5SSteve French 				blob_len);
191938c8a9a5SSteve French 		rc = -EINVAL;
192038c8a9a5SSteve French 		goto out_free_ntlmsspblob;
192138c8a9a5SSteve French 	}
192238c8a9a5SSteve French 	bcc_ptr += blob_len;
192338c8a9a5SSteve French 	bytes_remaining -= blob_len;
192438c8a9a5SSteve French 
192538c8a9a5SSteve French 
192638c8a9a5SSteve French 	/* BB check if Unicode and decode strings */
192738c8a9a5SSteve French 	if (bytes_remaining == 0) {
192838c8a9a5SSteve French 		/* no string area to decode, do nothing */
192938c8a9a5SSteve French 	} else if (smb_buf->Flags2 & SMBFLG2_UNICODE) {
193038c8a9a5SSteve French 		/* unicode string area must be word-aligned */
193138c8a9a5SSteve French 		if (!IS_ALIGNED((unsigned long)bcc_ptr - (unsigned long)smb_buf, 2)) {
193238c8a9a5SSteve French 			++bcc_ptr;
193338c8a9a5SSteve French 			--bytes_remaining;
193438c8a9a5SSteve French 		}
193538c8a9a5SSteve French 		decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses,
193638c8a9a5SSteve French 				      sess_data->nls_cp);
193738c8a9a5SSteve French 	} else {
193838c8a9a5SSteve French 		decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses,
193938c8a9a5SSteve French 				    sess_data->nls_cp);
194038c8a9a5SSteve French 	}
194138c8a9a5SSteve French 
194238c8a9a5SSteve French out_free_ntlmsspblob:
194338c8a9a5SSteve French 	kfree_sensitive(ntlmsspblob);
194438c8a9a5SSteve French out:
194538c8a9a5SSteve French 	sess_free_buffer(sess_data);
194638c8a9a5SSteve French 
194738c8a9a5SSteve French 	if (!rc)
194838c8a9a5SSteve French 		rc = sess_establish_session(sess_data);
194938c8a9a5SSteve French 
195038c8a9a5SSteve French 	/* Cleanup */
195138c8a9a5SSteve French 	kfree_sensitive(ses->auth_key.response);
195238c8a9a5SSteve French 	ses->auth_key.response = NULL;
195338c8a9a5SSteve French 	kfree_sensitive(ses->ntlmssp);
195438c8a9a5SSteve French 	ses->ntlmssp = NULL;
195538c8a9a5SSteve French 
195638c8a9a5SSteve French 	sess_data->func = NULL;
195738c8a9a5SSteve French 	sess_data->result = rc;
195838c8a9a5SSteve French }
select_sec(struct sess_data * sess_data)195938c8a9a5SSteve French 
196038c8a9a5SSteve French static int select_sec(struct sess_data *sess_data)
196138c8a9a5SSteve French {
196238c8a9a5SSteve French 	int type;
196338c8a9a5SSteve French 	struct cifs_ses *ses = sess_data->ses;
196438c8a9a5SSteve French 	struct TCP_Server_Info *server = sess_data->server;
196538c8a9a5SSteve French 
196638c8a9a5SSteve French 	type = cifs_select_sectype(server, ses->sectype);
196738c8a9a5SSteve French 	cifs_dbg(FYI, "sess setup type %d\n", type);
196838c8a9a5SSteve French 	if (type == Unspecified) {
196938c8a9a5SSteve French 		cifs_dbg(VFS, "Unable to select appropriate authentication method!\n");
197038c8a9a5SSteve French 		return -EINVAL;
197138c8a9a5SSteve French 	}
197238c8a9a5SSteve French 
197338c8a9a5SSteve French 	switch (type) {
197438c8a9a5SSteve French 	case NTLMv2:
197538c8a9a5SSteve French 		sess_data->func = sess_auth_ntlmv2;
197638c8a9a5SSteve French 		break;
197738c8a9a5SSteve French 	case Kerberos:
197838c8a9a5SSteve French #ifdef CONFIG_CIFS_UPCALL
197938c8a9a5SSteve French 		sess_data->func = sess_auth_kerberos;
198038c8a9a5SSteve French 		break;
198138c8a9a5SSteve French #else
198238c8a9a5SSteve French 		cifs_dbg(VFS, "Kerberos negotiated but upcall support disabled!\n");
198338c8a9a5SSteve French 		return -ENOSYS;
198438c8a9a5SSteve French #endif /* CONFIG_CIFS_UPCALL */
198538c8a9a5SSteve French 	case RawNTLMSSP:
198638c8a9a5SSteve French 		sess_data->func = sess_auth_rawntlmssp_negotiate;
198738c8a9a5SSteve French 		break;
198838c8a9a5SSteve French 	default:
198938c8a9a5SSteve French 		cifs_dbg(VFS, "secType %d not supported!\n", type);
199038c8a9a5SSteve French 		return -ENOSYS;
199138c8a9a5SSteve French 	}
199238c8a9a5SSteve French 
199338c8a9a5SSteve French 	return 0;
199438c8a9a5SSteve French }
CIFS_SessSetup(const unsigned int xid,struct cifs_ses * ses,struct TCP_Server_Info * server,const struct nls_table * nls_cp)199538c8a9a5SSteve French 
199638c8a9a5SSteve French int CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
199738c8a9a5SSteve French 		   struct TCP_Server_Info *server,
199838c8a9a5SSteve French 		   const struct nls_table *nls_cp)
199938c8a9a5SSteve French {
200038c8a9a5SSteve French 	int rc = 0;
200138c8a9a5SSteve French 	struct sess_data *sess_data;
200238c8a9a5SSteve French 
200338c8a9a5SSteve French 	if (ses == NULL) {
200438c8a9a5SSteve French 		WARN(1, "%s: ses == NULL!", __func__);
200538c8a9a5SSteve French 		return -EINVAL;
200638c8a9a5SSteve French 	}
200738c8a9a5SSteve French 
200838c8a9a5SSteve French 	sess_data = kzalloc(sizeof(struct sess_data), GFP_KERNEL);
200938c8a9a5SSteve French 	if (!sess_data)
201038c8a9a5SSteve French 		return -ENOMEM;
201138c8a9a5SSteve French 
201238c8a9a5SSteve French 	sess_data->xid = xid;
201338c8a9a5SSteve French 	sess_data->ses = ses;
201438c8a9a5SSteve French 	sess_data->server = server;
201538c8a9a5SSteve French 	sess_data->buf0_type = CIFS_NO_BUFFER;
201638c8a9a5SSteve French 	sess_data->nls_cp = (struct nls_table *) nls_cp;
201738c8a9a5SSteve French 
201838c8a9a5SSteve French 	rc = select_sec(sess_data);
201938c8a9a5SSteve French 	if (rc)
202038c8a9a5SSteve French 		goto out;
202138c8a9a5SSteve French 
202238c8a9a5SSteve French 	while (sess_data->func)
202338c8a9a5SSteve French 		sess_data->func(sess_data);
202438c8a9a5SSteve French 
202538c8a9a5SSteve French 	/* Store result before we free sess_data */
202638c8a9a5SSteve French 	rc = sess_data->result;
202738c8a9a5SSteve French 
202838c8a9a5SSteve French out:
202938c8a9a5SSteve French 	kfree_sensitive(sess_data);
203038c8a9a5SSteve French 	return rc;
203138c8a9a5SSteve French }
203238c8a9a5SSteve French #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
2033