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