blob: f1a7e63ab58fff3c9f6e4757961b121d40f9dd8f [file] [log] [blame]
Steve French929be902021-06-18 00:31:49 -05001// SPDX-License-Identifier: LGPL-2.1
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
3 * fs/cifs/connect.c
4 *
Steve French1080ef72011-02-24 18:07:19 +00005 * Copyright (C) International Business Machines Corp., 2002,2011
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 * Author(s): Steve French (sfrench@us.ibm.com)
7 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 */
9#include <linux/fs.h>
10#include <linux/net.h>
11#include <linux/string.h>
Eric Biggersdc920272020-03-08 22:58:20 -070012#include <linux/sched/mm.h>
Ingo Molnar3f07c012017-02-08 18:51:30 +010013#include <linux/sched/signal.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include <linux/list.h>
15#include <linux/wait.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090016#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/pagemap.h>
18#include <linux/ctype.h>
19#include <linux/utsname.h>
20#include <linux/mempool.h>
Steve Frenchb8643e12005-04-28 22:41:07 -070021#include <linux/delay.h>
Steve Frenchf1914012005-08-18 09:37:34 -070022#include <linux/completion.h>
Igor Mammedovaaf737a2007-04-03 19:16:43 +000023#include <linux/kthread.h>
Steve French0ae0efa2005-10-10 10:57:19 -070024#include <linux/pagevec.h>
Nigel Cunningham7dfb7102006-12-06 20:34:23 -080025#include <linux/freezer.h>
Igor Mammedov5c2503a2009-04-21 19:31:05 +040026#include <linux/namei.h>
Andrew Lunnc6e970a2017-03-28 23:45:06 +020027#include <linux/uuid.h>
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080028#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <asm/processor.h>
Jeff Layton50b64e32009-06-02 06:55:20 -040030#include <linux/inet.h>
Paul Gortmaker143cb492011-07-01 14:23:34 -040031#include <linux/module.h>
Jeff Layton8a8798a2012-01-17 16:09:15 -050032#include <keys/user-type.h>
Steve French0e2beda2009-01-30 21:24:41 +000033#include <net/ipv6.h>
Sachin Prabhu8830d7e2012-03-23 14:40:56 -040034#include <linux/parser.h>
Christoph Hellwig2f8b5442016-11-01 07:40:13 -060035#include <linux/bvec.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include "cifspdu.h"
37#include "cifsglob.h"
38#include "cifsproto.h"
39#include "cifs_unicode.h"
40#include "cifs_debug.h"
41#include "cifs_fs_sb.h"
42#include "ntlmssp.h"
43#include "nterr.h"
44#include "rfc1002pdu.h"
Suresh Jayaraman488f1d2d2010-07-05 18:12:15 +053045#include "fscache.h"
Pavel Shilovsky53e0e112016-11-04 11:50:31 -070046#include "smb2proto.h"
Long Li2f894642017-11-22 17:38:34 -070047#include "smbdirect.h"
Paulo Alcantara1c780222018-11-14 16:24:03 -020048#include "dns_resolve.h"
49#ifdef CONFIG_CIFS_DFS_UPCALL
50#include "dfs_cache.h"
51#endif
Ronnie Sahlberg5c6e5aa2020-10-21 10:37:11 +100052#include "fs_context.h"
Samuel Cabrerobf80e5d2020-11-30 19:02:51 +010053#include "cifs_swn.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
Linus Torvalds1da177e2005-04-16 15:20:36 -070055extern mempool_t *cifs_req_poolp;
Steve Frenchf92a7202018-05-24 04:11:07 -050056extern bool disable_legacy_dialects;
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
Jeff Layton2de970f2010-10-06 19:51:12 -040058/* FIXME: should these be tunable? */
Jeff Layton9d002df2010-10-06 19:51:11 -040059#define TLINK_ERROR_EXPIRE (1 * HZ)
Jeff Layton2de970f2010-10-06 19:51:12 -040060#define TLINK_IDLE_EXPIRE (600 * HZ)
Jeff Layton9d002df2010-10-06 19:51:11 -040061
Rohith Surabattula8e670f72020-09-18 05:37:28 +000062/* Drop the connection to not overload the server */
63#define NUM_STATUS_IO_TIMEOUT 5
64
Pavel Shilovskya9f1b852010-12-13 19:08:35 +030065static int ip_connect(struct TCP_Server_Info *server);
66static int generic_ip_connect(struct TCP_Server_Info *server);
Jeff Laytonb647c352010-10-28 11:16:44 -040067static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink);
Jeff Layton2de970f2010-10-06 19:51:12 -040068static void cifs_prune_tlinks(struct work_struct *work);
Paulo Alcantara93d5cb52018-11-14 17:13:25 -020069
Paulo Alcantara28eb24f2018-11-20 15:16:36 -020070/*
71 * Resolve hostname and set ip addr in tcp ses. Useful for hostnames that may
72 * get their ip addresses changed at some point.
73 *
74 * This should be called with server->srv_mutex held.
75 */
Samuel Cabrero7d6535b2020-11-30 19:02:55 +010076static int reconn_set_ipaddr_from_hostname(struct TCP_Server_Info *server)
Paulo Alcantara28eb24f2018-11-20 15:16:36 -020077{
78 int rc;
79 int len;
80 char *unc, *ipaddr = NULL;
Shyam Prasad N506c1da2021-05-18 15:05:50 +000081 time64_t expiry, now;
82 unsigned long ttl = SMB_DNS_RESOLVE_INTERVAL_DEFAULT;
Paulo Alcantara28eb24f2018-11-20 15:16:36 -020083
84 if (!server->hostname)
85 return -EINVAL;
86
87 len = strlen(server->hostname) + 3;
88
89 unc = kmalloc(len, GFP_KERNEL);
90 if (!unc) {
91 cifs_dbg(FYI, "%s: failed to create UNC path\n", __func__);
92 return -ENOMEM;
93 }
Ronnie Sahlberg74ea5f92019-02-09 09:51:11 +100094 scnprintf(unc, len, "\\\\%s", server->hostname);
Paulo Alcantara28eb24f2018-11-20 15:16:36 -020095
Shyam Prasad N506c1da2021-05-18 15:05:50 +000096 rc = dns_resolve_server_name_to_ip(unc, &ipaddr, &expiry);
Paulo Alcantara28eb24f2018-11-20 15:16:36 -020097 kfree(unc);
98
99 if (rc < 0) {
100 cifs_dbg(FYI, "%s: failed to resolve server part of %s to IP: %d\n",
101 __func__, server->hostname, rc);
Shyam Prasad N506c1da2021-05-18 15:05:50 +0000102 goto requeue_resolve;
Paulo Alcantara28eb24f2018-11-20 15:16:36 -0200103 }
104
Ronnie Sahlbergfada37f2020-04-21 12:37:39 +1000105 spin_lock(&cifs_tcp_ses_lock);
Paulo Alcantara28eb24f2018-11-20 15:16:36 -0200106 rc = cifs_convert_address((struct sockaddr *)&server->dstaddr, ipaddr,
107 strlen(ipaddr));
Ronnie Sahlbergfada37f2020-04-21 12:37:39 +1000108 spin_unlock(&cifs_tcp_ses_lock);
Paulo Alcantara28eb24f2018-11-20 15:16:36 -0200109 kfree(ipaddr);
110
Shyam Prasad N506c1da2021-05-18 15:05:50 +0000111 /* rc == 1 means success here */
112 if (rc) {
113 now = ktime_get_real_seconds();
114 if (expiry && expiry > now)
115 /*
116 * To make sure we don't use the cached entry, retry 1s
117 * after expiry.
118 */
119 ttl = (expiry - now + 1);
120 }
121 rc = !rc ? -1 : 0;
122
123requeue_resolve:
124 cifs_dbg(FYI, "%s: next dns resolution scheduled for %lu seconds in the future\n",
125 __func__, ttl);
126 mod_delayed_work(cifsiod_wq, &server->resolve, (ttl * HZ));
127
128 return rc;
129}
130
131
132static void cifs_resolve_server(struct work_struct *work)
133{
134 int rc;
135 struct TCP_Server_Info *server = container_of(work,
136 struct TCP_Server_Info, resolve.work);
137
138 mutex_lock(&server->srv_mutex);
139
140 /*
141 * Resolve the hostname again to make sure that IP address is up-to-date.
142 */
143 rc = reconn_set_ipaddr_from_hostname(server);
144 if (rc) {
145 cifs_dbg(FYI, "%s: failed to resolve hostname: %d\n",
146 __func__, rc);
147 }
148
149 mutex_unlock(&server->srv_mutex);
Paulo Alcantara28eb24f2018-11-20 15:16:36 -0200150}
Paulo Alcantara28eb24f2018-11-20 15:16:36 -0200151
Shyam Prasad N4e456b32021-03-31 14:35:24 +0000152#ifdef CONFIG_CIFS_DFS_UPCALL
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200153/* These functions must be called with server->srv_mutex held */
Paulo Alcantara7d397a02020-07-21 09:36:40 -0300154static void reconn_set_next_dfs_target(struct TCP_Server_Info *server,
155 struct cifs_sb_info *cifs_sb,
156 struct dfs_cache_tgt_list *tgt_list,
157 struct dfs_cache_tgt_iterator **tgt_it)
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200158{
159 const char *name;
Samuel Cabrero7d6535b2020-11-30 19:02:55 +0100160 int rc;
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200161
Paulo Alcantara7d397a02020-07-21 09:36:40 -0300162 if (!cifs_sb || !cifs_sb->origin_fullpath)
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200163 return;
164
165 if (!*tgt_it) {
166 *tgt_it = dfs_cache_get_tgt_iterator(tgt_list);
167 } else {
168 *tgt_it = dfs_cache_get_next_tgt(tgt_list, *tgt_it);
169 if (!*tgt_it)
170 *tgt_it = dfs_cache_get_tgt_iterator(tgt_list);
171 }
172
173 cifs_dbg(FYI, "%s: UNC: %s\n", __func__, cifs_sb->origin_fullpath);
174
175 name = dfs_cache_get_tgt_name(*tgt_it);
176
177 kfree(server->hostname);
178
179 server->hostname = extract_hostname(name);
Dan Carpenter84288172019-01-05 15:25:29 +0300180 if (IS_ERR(server->hostname)) {
181 cifs_dbg(FYI,
182 "%s: failed to extract hostname from target: %ld\n",
183 __func__, PTR_ERR(server->hostname));
Samuel Cabrero0bf1baf2020-12-18 10:29:49 +0100184 return;
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200185 }
Samuel Cabrero7d6535b2020-11-30 19:02:55 +0100186
187 rc = reconn_set_ipaddr_from_hostname(server);
188 if (rc) {
189 cifs_dbg(FYI, "%s: failed to resolve hostname: %d\n",
190 __func__, rc);
191 }
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200192}
193
194static inline int reconn_setup_dfs_targets(struct cifs_sb_info *cifs_sb,
Paulo Alcantarabaf3f082020-05-19 15:38:29 -0300195 struct dfs_cache_tgt_list *tl)
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200196{
197 if (!cifs_sb->origin_fullpath)
198 return -EOPNOTSUPP;
199 return dfs_cache_noreq_find(cifs_sb->origin_fullpath + 1, NULL, tl);
200}
201#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202
Jeff Laytond5c56052008-12-01 18:42:33 -0500203/*
204 * cifs tcp session reconnection
205 *
206 * mark tcp session as reconnecting so temporarily locked
207 * mark all smb sessions as reconnecting for tcp session
208 * reconnect tcp session
209 * wake up waiters on reconnection? - (not needed currently)
210 */
Pavel Shilovsky28ea5292012-05-23 16:18:00 +0400211int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212cifs_reconnect(struct TCP_Server_Info *server)
213{
214 int rc = 0;
Jeff Laytonf1987b42008-11-15 11:12:47 -0500215 struct list_head *tmp, *tmp2;
Steve French96daf2b2011-05-27 04:34:02 +0000216 struct cifs_ses *ses;
217 struct cifs_tcon *tcon;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000218 struct mid_q_entry *mid_entry;
Jeff Layton3c1105d2011-05-22 07:09:13 -0400219 struct list_head retry_list;
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200220#ifdef CONFIG_CIFS_DFS_UPCALL
Paulo Alcantara (SUSE)8354d882019-11-22 12:30:51 -0300221 struct super_block *sb = NULL;
Paulo Alcantara23324402018-11-20 14:37:18 -0200222 struct cifs_sb_info *cifs_sb = NULL;
223 struct dfs_cache_tgt_list tgt_list = {0};
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200224 struct dfs_cache_tgt_iterator *tgt_it = NULL;
225#endif
Steve French50c2f752007-07-13 00:33:32 +0000226
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 spin_lock(&GlobalMid_Lock);
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200228 server->nr_targets = 1;
229#ifdef CONFIG_CIFS_DFS_UPCALL
Ronnie Sahlberg61cabc72019-06-14 13:02:29 +1000230 spin_unlock(&GlobalMid_Lock);
Paulo Alcantara (SUSE)bacd7042020-02-20 19:49:34 -0300231 sb = cifs_get_tcp_super(server);
Paulo Alcantara (SUSE)8354d882019-11-22 12:30:51 -0300232 if (IS_ERR(sb)) {
233 rc = PTR_ERR(sb);
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200234 cifs_dbg(FYI, "%s: will not do DFS failover: rc = %d\n",
235 __func__, rc);
Paulo Alcantara (SUSE)8354d882019-11-22 12:30:51 -0300236 sb = NULL;
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200237 } else {
Paulo Alcantara (SUSE)8354d882019-11-22 12:30:51 -0300238 cifs_sb = CIFS_SB(sb);
Paulo Alcantarabaf3f082020-05-19 15:38:29 -0300239 rc = reconn_setup_dfs_targets(cifs_sb, &tgt_list);
Paulo Alcantaraa5293032020-07-21 09:36:41 -0300240 if (rc) {
241 cifs_sb = NULL;
242 if (rc != -EOPNOTSUPP) {
243 cifs_server_dbg(VFS, "%s: no target servers for DFS failover\n",
244 __func__);
245 }
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200246 } else {
247 server->nr_targets = dfs_cache_get_nr_tgts(&tgt_list);
248 }
249 }
250 cifs_dbg(FYI, "%s: will retry %d target(s)\n", __func__,
251 server->nr_targets);
Ronnie Sahlberg61cabc72019-06-14 13:02:29 +1000252 spin_lock(&GlobalMid_Lock);
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200253#endif
Jeff Layton469ee612008-10-16 18:46:39 +0000254 if (server->tcpStatus == CifsExiting) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000255 /* the demux thread will exit normally
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 next time through the loop */
257 spin_unlock(&GlobalMid_Lock);
Paulo Alcantara (SUSE)8354d882019-11-22 12:30:51 -0300258#ifdef CONFIG_CIFS_DFS_UPCALL
259 dfs_cache_free_tgts(&tgt_list);
Paulo Alcantara (SUSE)bacd7042020-02-20 19:49:34 -0300260 cifs_put_tcp_super(sb);
Paulo Alcantara (SUSE)8354d882019-11-22 12:30:51 -0300261#endif
Stefan Metzmachere2e87512020-02-24 14:31:02 -0600262 wake_up(&server->response_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 return rc;
264 } else
265 server->tcpStatus = CifsNeedReconnect;
266 spin_unlock(&GlobalMid_Lock);
267 server->maxBuf = 0;
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400268 server->max_read = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269
Steve French6e4d3bb2018-09-22 11:25:04 -0500270 cifs_dbg(FYI, "Mark tcp session as need reconnect\n");
Shyam Prasad N6d82c272021-02-03 23:20:46 -0800271 trace_smb3_reconnect(server->CurrentMid, server->conn_id, server->hostname);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272
273 /* before reconnecting the tcp session, mark the smb session (uid)
274 and the tid bad so they are not used until reconnected */
Joe Perchesf96637b2013-05-04 22:12:25 -0500275 cifs_dbg(FYI, "%s: marking sessions and tcons for reconnect\n",
276 __func__);
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530277 spin_lock(&cifs_tcp_ses_lock);
Jeff Layton14fbf502008-11-14 13:53:46 -0500278 list_for_each(tmp, &server->smb_ses_list) {
Steve French96daf2b2011-05-27 04:34:02 +0000279 ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
Jeff Layton14fbf502008-11-14 13:53:46 -0500280 ses->need_reconnect = true;
Jeff Laytonf1987b42008-11-15 11:12:47 -0500281 list_for_each(tmp2, &ses->tcon_list) {
Steve French96daf2b2011-05-27 04:34:02 +0000282 tcon = list_entry(tmp2, struct cifs_tcon, tcon_list);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500283 tcon->need_reconnect = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 }
Aurelien Aptelb327a712018-01-24 13:46:10 +0100285 if (ses->tcon_ipc)
286 ses->tcon_ipc->need_reconnect = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530288 spin_unlock(&cifs_tcp_ses_lock);
Jeff Layton2b84a36c2011-01-11 07:24:21 -0500289
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 /* do not want to be sending data on a socket we are freeing */
Joe Perchesf96637b2013-05-04 22:12:25 -0500291 cifs_dbg(FYI, "%s: tearing down socket\n", __func__);
Jeff Layton72ca5452008-12-01 07:09:36 -0500292 mutex_lock(&server->srv_mutex);
Long Li1d2a4f52019-05-13 21:01:28 -0700293 if (server->ssocket) {
294 cifs_dbg(FYI, "State: 0x%x Flags: 0x%lx\n",
295 server->ssocket->state, server->ssocket->flags);
296 kernel_sock_shutdown(server->ssocket, SHUT_WR);
297 cifs_dbg(FYI, "Post shutdown state: 0x%x Flags: 0x%lx\n",
298 server->ssocket->state, server->ssocket->flags);
299 sock_release(server->ssocket);
300 server->ssocket = NULL;
301 }
302 server->sequence_number = 0;
303 server->session_estab = false;
304 kfree(server->session_key.response);
305 server->session_key.response = NULL;
306 server->session_key.len = 0;
307 server->lstrp = jiffies;
Long Li214bab42019-04-05 21:36:35 +0000308
309 /* mark submitted MIDs for retry and issue callback */
310 INIT_LIST_HEAD(&retry_list);
311 cifs_dbg(FYI, "%s: moving mids to private list\n", __func__);
312 spin_lock(&GlobalMid_Lock);
313 list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
314 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
Pavel Shilovskyabe57072019-10-22 08:41:42 -0700315 kref_get(&mid_entry->refcount);
Long Li214bab42019-04-05 21:36:35 +0000316 if (mid_entry->mid_state == MID_REQUEST_SUBMITTED)
317 mid_entry->mid_state = MID_RETRY_NEEDED;
318 list_move(&mid_entry->qhead, &retry_list);
Pavel Shilovskyabe57072019-10-22 08:41:42 -0700319 mid_entry->mid_flags |= MID_DELETED;
Long Li214bab42019-04-05 21:36:35 +0000320 }
321 spin_unlock(&GlobalMid_Lock);
Long Li1d2a4f52019-05-13 21:01:28 -0700322 mutex_unlock(&server->srv_mutex);
Long Li214bab42019-04-05 21:36:35 +0000323
324 cifs_dbg(FYI, "%s: issuing mid callbacks\n", __func__);
325 list_for_each_safe(tmp, tmp2, &retry_list) {
326 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
327 list_del_init(&mid_entry->qhead);
328 mid_entry->callback(mid_entry);
Pavel Shilovskyabe57072019-10-22 08:41:42 -0700329 cifs_mid_q_entry_release(mid_entry);
Long Li214bab42019-04-05 21:36:35 +0000330 }
331
Long Li1d2a4f52019-05-13 21:01:28 -0700332 if (cifs_rdma_enabled(server)) {
333 mutex_lock(&server->srv_mutex);
Long Li050b8c32019-04-04 11:35:42 -0500334 smbd_destroy(server);
Long Li1d2a4f52019-05-13 21:01:28 -0700335 mutex_unlock(&server->srv_mutex);
336 }
Jeff Layton3c1105d2011-05-22 07:09:13 -0400337
Jeff Layton7fdbaa12011-06-10 16:14:57 -0400338 do {
Steve French6c3d8902006-07-31 22:46:20 +0000339 try_to_freeze();
Pavel Shilovskya9f1b852010-12-13 19:08:35 +0300340
Jeff Layton73e216a2013-09-05 08:38:10 -0400341 mutex_lock(&server->srv_mutex);
Samuel Cabrero121d9472020-11-30 19:02:56 +0100342
Samuel Cabrero121d9472020-11-30 19:02:56 +0100343
Aurelien Aptelb7fd0fa2021-04-09 16:31:37 +0200344 if (!cifs_swn_set_server_dstaddr(server)) {
Paulo Alcantaraaaa3aef2020-05-19 15:38:27 -0300345#ifdef CONFIG_CIFS_DFS_UPCALL
Shyam Prasad N4e456b32021-03-31 14:35:24 +0000346 if (cifs_sb && cifs_sb->origin_fullpath)
Samuel Cabrero121d9472020-11-30 19:02:56 +0100347 /*
348 * Set up next DFS target server (if any) for reconnect. If DFS
349 * feature is disabled, then we will retry last server we
350 * connected to before.
351 */
352 reconn_set_next_dfs_target(server, cifs_sb, &tgt_list, &tgt_it);
Shyam Prasad N4e456b32021-03-31 14:35:24 +0000353 else {
Samuel Cabrero121d9472020-11-30 19:02:56 +0100354#endif
Shyam Prasad N4e456b32021-03-31 14:35:24 +0000355 /*
356 * Resolve the hostname again to make sure that IP address is up-to-date.
357 */
358 rc = reconn_set_ipaddr_from_hostname(server);
359 if (rc) {
360 cifs_dbg(FYI, "%s: failed to resolve hostname: %d\n",
361 __func__, rc);
362 }
363
364#ifdef CONFIG_CIFS_DFS_UPCALL
365 }
366#endif
367
Samuel Cabrero121d9472020-11-30 19:02:56 +0100368
Samuel Cabrero121d9472020-11-30 19:02:56 +0100369 }
Paulo Alcantaraaaa3aef2020-05-19 15:38:27 -0300370
Long Li781a8052017-11-22 17:38:36 -0700371 if (cifs_rdma_enabled(server))
372 rc = smbd_reconnect(server);
373 else
374 rc = generic_ip_connect(server);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000375 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500376 cifs_dbg(FYI, "reconnect error %d\n", rc);
Federico Sauter4afe2602015-03-17 17:45:28 +0100377 mutex_unlock(&server->srv_mutex);
Steve French0cb766a2005-04-28 22:41:11 -0700378 msleep(3000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 } else {
380 atomic_inc(&tcpSesReconnectCount);
Pavel Shilovsky335b7b62019-01-16 11:12:41 -0800381 set_credits(server, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 spin_lock(&GlobalMid_Lock);
Jeff Layton469ee612008-10-16 18:46:39 +0000383 if (server->tcpStatus != CifsExiting)
Steve Frenchfd88ce92011-04-12 01:01:14 +0000384 server->tcpStatus = CifsNeedNegotiate;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000385 spin_unlock(&GlobalMid_Lock);
Aurelien Aptelb7fd0fa2021-04-09 16:31:37 +0200386 cifs_swn_reset_server_dstaddr(server);
Federico Sauter4afe2602015-03-17 17:45:28 +0100387 mutex_unlock(&server->srv_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 }
Jeff Layton7fdbaa12011-06-10 16:14:57 -0400389 } while (server->tcpStatus == CifsNeedReconnect);
Jeff Layton2b84a36c2011-01-11 07:24:21 -0500390
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200391#ifdef CONFIG_CIFS_DFS_UPCALL
392 if (tgt_it) {
393 rc = dfs_cache_noreq_update_tgthint(cifs_sb->origin_fullpath + 1,
394 tgt_it);
395 if (rc) {
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +1000396 cifs_server_dbg(VFS, "%s: failed to update DFS target hint: rc = %d\n",
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200397 __func__, rc);
398 }
Paulo Alcantara23324402018-11-20 14:37:18 -0200399 dfs_cache_free_tgts(&tgt_list);
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200400 }
Paulo Alcantara (SUSE)8354d882019-11-22 12:30:51 -0300401
Paulo Alcantara (SUSE)bacd7042020-02-20 19:49:34 -0300402 cifs_put_tcp_super(sb);
Paulo Alcantara93d5cb52018-11-14 17:13:25 -0200403#endif
Sachin Prabhub8c60012016-10-20 19:52:24 -0400404 if (server->tcpStatus == CifsNeedNegotiate)
405 mod_delayed_work(cifsiod_wq, &server->echo, 0);
406
Stefan Metzmachere2e87512020-02-24 14:31:02 -0600407 wake_up(&server->response_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 return rc;
409}
410
Jeff Laytonc74093b2011-01-11 07:24:23 -0500411static void
412cifs_echo_request(struct work_struct *work)
413{
414 int rc;
415 struct TCP_Server_Info *server = container_of(work,
416 struct TCP_Server_Info, echo.work);
Sachin Prabhub8c60012016-10-20 19:52:24 -0400417
418 /*
419 * We cannot send an echo if it is disabled.
420 * Also, no need to ping if we got a response recently.
Jeff Layton247ec9b2011-02-04 17:09:50 -0500421 */
Steve French4fcd1812016-06-22 20:12:05 -0500422
423 if (server->tcpStatus == CifsNeedReconnect ||
Sachin Prabhub8c60012016-10-20 19:52:24 -0400424 server->tcpStatus == CifsExiting ||
425 server->tcpStatus == CifsNew ||
Pavel Shilovskyf6d76172012-05-25 14:47:16 +0400426 (server->ops->can_echo && !server->ops->can_echo(server)) ||
Shyam Prasad N5b2abda2021-05-01 16:17:07 +0000427 time_before(jiffies, server->lstrp + server->echo_interval - HZ))
Jeff Laytonc74093b2011-01-11 07:24:23 -0500428 goto requeue_echo;
429
Pavel Shilovskyf6d76172012-05-25 14:47:16 +0400430 rc = server->ops->echo ? server->ops->echo(server) : -ENOSYS;
Jeff Laytonc74093b2011-01-11 07:24:23 -0500431 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500432 cifs_dbg(FYI, "Unable to send echo request to server: %s\n",
433 server->hostname);
Jeff Laytonc74093b2011-01-11 07:24:23 -0500434
Samuel Cabrero21077c62020-11-30 19:02:54 +0100435 /* Check witness registrations */
436 cifs_swn_check();
Samuel Cabrero21077c62020-11-30 19:02:54 +0100437
Jeff Laytonc74093b2011-01-11 07:24:23 -0500438requeue_echo:
Sachin Prabhub8c60012016-10-20 19:52:24 -0400439 queue_delayed_work(cifsiod_wq, &server->echo, server->echo_interval);
Jeff Laytonc74093b2011-01-11 07:24:23 -0500440}
441
Pavel Shilovsky3d9c2472011-08-01 13:19:40 +0400442static bool
Jeff Layton2a37ef92011-10-19 15:29:23 -0400443allocate_buffers(struct TCP_Server_Info *server)
Pavel Shilovsky3d9c2472011-08-01 13:19:40 +0400444{
Jeff Layton2a37ef92011-10-19 15:29:23 -0400445 if (!server->bigbuf) {
446 server->bigbuf = (char *)cifs_buf_get();
447 if (!server->bigbuf) {
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +1000448 cifs_server_dbg(VFS, "No memory for large SMB response\n");
Pavel Shilovsky3d9c2472011-08-01 13:19:40 +0400449 msleep(3000);
450 /* retry will check if exiting */
451 return false;
452 }
Jeff Layton2a37ef92011-10-19 15:29:23 -0400453 } else if (server->large_buf) {
Pavel Shilovsky3d9c2472011-08-01 13:19:40 +0400454 /* we are reusing a dirty large buf, clear its start */
Pavel Shilovsky1887f602012-05-17 12:45:31 +0400455 memset(server->bigbuf, 0, HEADER_SIZE(server));
Pavel Shilovsky3d9c2472011-08-01 13:19:40 +0400456 }
457
Jeff Layton2a37ef92011-10-19 15:29:23 -0400458 if (!server->smallbuf) {
459 server->smallbuf = (char *)cifs_small_buf_get();
460 if (!server->smallbuf) {
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +1000461 cifs_server_dbg(VFS, "No memory for SMB response\n");
Pavel Shilovsky3d9c2472011-08-01 13:19:40 +0400462 msleep(1000);
463 /* retry will check if exiting */
464 return false;
465 }
466 /* beginning of smb buffer is cleared in our buf_get */
467 } else {
468 /* if existing small buf clear beginning */
Pavel Shilovsky1887f602012-05-17 12:45:31 +0400469 memset(server->smallbuf, 0, HEADER_SIZE(server));
Pavel Shilovsky3d9c2472011-08-01 13:19:40 +0400470 }
471
Pavel Shilovsky3d9c2472011-08-01 13:19:40 +0400472 return true;
473}
474
Jeff Laytonba749e62011-10-11 06:41:32 -0400475static bool
476server_unresponsive(struct TCP_Server_Info *server)
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400477{
Pavel Shilovsky6dae51a2012-02-21 16:50:23 +0300478 /*
Ronnie Sahlbergf2caf902019-07-06 06:52:46 +1000479 * We need to wait 3 echo intervals to make sure we handle such
Pavel Shilovsky6dae51a2012-02-21 16:50:23 +0300480 * situations right:
481 * 1s client sends a normal SMB request
Ronnie Sahlbergbecc2ba2019-07-24 11:43:49 +1000482 * 2s client gets a response
Pavel Shilovsky6dae51a2012-02-21 16:50:23 +0300483 * 30s echo workqueue job pops, and decides we got a response recently
484 * and don't need to send another
485 * ...
486 * 65s kernel_recvmsg times out, and we see that we haven't gotten
487 * a response in >60s.
488 */
Samuel Cabrero76e75272017-07-11 12:44:39 +0200489 if ((server->tcpStatus == CifsGood ||
490 server->tcpStatus == CifsNeedNegotiate) &&
Shyam Prasad Nf4916642021-04-29 07:53:18 +0000491 (!server->ops->can_echo || server->ops->can_echo(server)) &&
Ronnie Sahlbergf2caf902019-07-06 06:52:46 +1000492 time_after(jiffies, server->lstrp + 3 * server->echo_interval)) {
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +1000493 cifs_server_dbg(VFS, "has not responded in %lu seconds. Reconnecting...\n",
494 (3 * server->echo_interval) / HZ);
Jeff Laytonba749e62011-10-11 06:41:32 -0400495 cifs_reconnect(server);
Jeff Laytonba749e62011-10-11 06:41:32 -0400496 return true;
497 }
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400498
Jeff Laytonba749e62011-10-11 06:41:32 -0400499 return false;
500}
501
Pavel Shilovskyef68e832019-01-18 17:25:36 -0800502static inline bool
503zero_credits(struct TCP_Server_Info *server)
504{
505 int val;
506
507 spin_lock(&server->req_lock);
508 val = server->credits + server->echo_credits + server->oplock_credits;
509 if (server->in_flight == 0 && val == 0) {
510 spin_unlock(&server->req_lock);
511 return true;
512 }
513 spin_unlock(&server->req_lock);
514 return false;
515}
516
Al Viro71335662016-01-09 19:54:50 -0500517static int
518cifs_readv_from_socket(struct TCP_Server_Info *server, struct msghdr *smb_msg)
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400519{
Jeff Laytona52c1eb2011-10-11 06:41:32 -0400520 int length = 0;
521 int total_read;
Jeff Layton42c4dfc2011-10-19 15:28:17 -0400522
Al Viro71335662016-01-09 19:54:50 -0500523 smb_msg->msg_control = NULL;
524 smb_msg->msg_controllen = 0;
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400525
Al Viro71335662016-01-09 19:54:50 -0500526 for (total_read = 0; msg_data_left(smb_msg); total_read += length) {
Jeff Layton95edcff2011-12-01 20:22:41 -0500527 try_to_freeze();
528
Pavel Shilovskyef68e832019-01-18 17:25:36 -0800529 /* reconnect if no credits and no requests in flight */
530 if (zero_credits(server)) {
531 cifs_reconnect(server);
532 return -ECONNABORTED;
533 }
534
Al Viro71335662016-01-09 19:54:50 -0500535 if (server_unresponsive(server))
536 return -ECONNABORTED;
Long Li2fef1372017-11-22 17:38:41 -0700537 if (cifs_rdma_enabled(server) && server->smbd_conn)
538 length = smbd_recv(server->smbd_conn, smb_msg);
539 else
540 length = sock_recvmsg(server->ssocket, smb_msg, 0);
Al Viro71335662016-01-09 19:54:50 -0500541
542 if (server->tcpStatus == CifsExiting)
543 return -ESHUTDOWN;
544
545 if (server->tcpStatus == CifsNeedReconnect) {
546 cifs_reconnect(server);
547 return -ECONNABORTED;
Jeff Laytonba749e62011-10-11 06:41:32 -0400548 }
549
Al Viro71335662016-01-09 19:54:50 -0500550 if (length == -ERESTARTSYS ||
551 length == -EAGAIN ||
552 length == -EINTR) {
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400553 /*
554 * Minimum sleep to prevent looping, allowing socket
555 * to clear and app threads to set tcpStatus
556 * CifsNeedReconnect if server hung.
557 */
558 usleep_range(1000, 2000);
559 length = 0;
Jeff Laytona52c1eb2011-10-11 06:41:32 -0400560 continue;
Al Viro71335662016-01-09 19:54:50 -0500561 }
562
563 if (length <= 0) {
Al Viro09aab882015-11-13 03:00:17 -0500564 cifs_dbg(FYI, "Received no data or error: %d\n", length);
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400565 cifs_reconnect(server);
Al Viro71335662016-01-09 19:54:50 -0500566 return -ECONNABORTED;
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400567 }
568 }
Jeff Laytona52c1eb2011-10-11 06:41:32 -0400569 return total_read;
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400570}
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400571
Jeff Laytone28bc5b2011-10-19 15:30:07 -0400572int
573cifs_read_from_socket(struct TCP_Server_Info *server, char *buf,
574 unsigned int to_read)
Jeff Layton42c4dfc2011-10-19 15:28:17 -0400575{
Al Viro71335662016-01-09 19:54:50 -0500576 struct msghdr smb_msg;
577 struct kvec iov = {.iov_base = buf, .iov_len = to_read};
David Howellsaa563d72018-10-20 00:57:56 +0100578 iov_iter_kvec(&smb_msg.msg_iter, READ, &iov, 1, to_read);
Jeff Layton42c4dfc2011-10-19 15:28:17 -0400579
Al Viro71335662016-01-09 19:54:50 -0500580 return cifs_readv_from_socket(server, &smb_msg);
581}
Jeff Layton42c4dfc2011-10-19 15:28:17 -0400582
David Howellscf0604a2021-02-04 00:15:21 -0600583ssize_t
584cifs_discard_from_socket(struct TCP_Server_Info *server, size_t to_read)
585{
586 struct msghdr smb_msg;
587
588 /*
589 * iov_iter_discard already sets smb_msg.type and count and iov_offset
590 * and cifs_readv_from_socket sets msg_control and msg_controllen
591 * so little to initialize in struct msghdr
592 */
593 smb_msg.msg_name = NULL;
594 smb_msg.msg_namelen = 0;
595 iov_iter_discard(&smb_msg.msg_iter, READ, to_read);
596
597 return cifs_readv_from_socket(server, &smb_msg);
598}
599
Al Viro71335662016-01-09 19:54:50 -0500600int
601cifs_read_page_from_socket(struct TCP_Server_Info *server, struct page *page,
Long Li1dbe3462018-05-30 12:47:55 -0700602 unsigned int page_offset, unsigned int to_read)
Al Viro71335662016-01-09 19:54:50 -0500603{
604 struct msghdr smb_msg;
Long Li1dbe3462018-05-30 12:47:55 -0700605 struct bio_vec bv = {
606 .bv_page = page, .bv_len = to_read, .bv_offset = page_offset};
David Howellsaa563d72018-10-20 00:57:56 +0100607 iov_iter_bvec(&smb_msg.msg_iter, READ, &bv, 1, to_read);
Al Viro71335662016-01-09 19:54:50 -0500608 return cifs_readv_from_socket(server, &smb_msg);
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400609}
610
Pavel Shilovsky98bac622011-08-01 13:19:42 +0400611static bool
Jeff Laytonfe11e4c2011-10-11 06:41:32 -0400612is_smb_response(struct TCP_Server_Info *server, unsigned char type)
Pavel Shilovsky98bac622011-08-01 13:19:42 +0400613{
Pavel Shilovsky98bac622011-08-01 13:19:42 +0400614 /*
615 * The first byte big endian of the length field,
616 * is actually not part of the length but the type
617 * with the most common, zero, as regular data.
618 */
Jeff Laytonfe11e4c2011-10-11 06:41:32 -0400619 switch (type) {
620 case RFC1002_SESSION_MESSAGE:
621 /* Regular SMB response */
622 return true;
623 case RFC1002_SESSION_KEEP_ALIVE:
Joe Perchesf96637b2013-05-04 22:12:25 -0500624 cifs_dbg(FYI, "RFC 1002 session keep alive\n");
Jeff Laytonfe11e4c2011-10-11 06:41:32 -0400625 break;
626 case RFC1002_POSITIVE_SESSION_RESPONSE:
Joe Perchesf96637b2013-05-04 22:12:25 -0500627 cifs_dbg(FYI, "RFC 1002 positive session response\n");
Jeff Laytonfe11e4c2011-10-11 06:41:32 -0400628 break;
629 case RFC1002_NEGATIVE_SESSION_RESPONSE:
Pavel Shilovsky98bac622011-08-01 13:19:42 +0400630 /*
631 * We get this from Windows 98 instead of an error on
632 * SMB negprot response.
633 */
Joe Perchesf96637b2013-05-04 22:12:25 -0500634 cifs_dbg(FYI, "RFC 1002 negative session response\n");
Pavel Shilovsky98bac622011-08-01 13:19:42 +0400635 /* give server a second to clean up */
636 msleep(1000);
637 /*
638 * Always try 445 first on reconnect since we get NACK
639 * on some if we ever connected to port 139 (the NACK
640 * is since we do not begin with RFC1001 session
641 * initialize frame).
642 */
Jeff Laytonfe11e4c2011-10-11 06:41:32 -0400643 cifs_set_port((struct sockaddr *)&server->dstaddr, CIFS_PORT);
Pavel Shilovsky98bac622011-08-01 13:19:42 +0400644 cifs_reconnect(server);
Jeff Laytonfe11e4c2011-10-11 06:41:32 -0400645 break;
646 default:
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +1000647 cifs_server_dbg(VFS, "RFC 1002 unknown response type 0x%x\n", type);
Pavel Shilovsky98bac622011-08-01 13:19:42 +0400648 cifs_reconnect(server);
Pavel Shilovsky98bac622011-08-01 13:19:42 +0400649 }
650
Jeff Laytonfe11e4c2011-10-11 06:41:32 -0400651 return false;
Pavel Shilovsky98bac622011-08-01 13:19:42 +0400652}
653
Jeff Laytone28bc5b2011-10-19 15:30:07 -0400654void
655dequeue_mid(struct mid_q_entry *mid, bool malformed)
Jeff Laytonea1f4502011-10-19 15:29:05 -0400656{
657#ifdef CONFIG_CIFS_STATS2
658 mid->when_received = jiffies;
659#endif
660 spin_lock(&GlobalMid_Lock);
661 if (!malformed)
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -0400662 mid->mid_state = MID_RESPONSE_RECEIVED;
Jeff Laytonea1f4502011-10-19 15:29:05 -0400663 else
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -0400664 mid->mid_state = MID_RESPONSE_MALFORMED;
Ronnie Sahlbergddf83af2018-08-30 10:12:59 +1000665 /*
666 * Trying to handle/dequeue a mid after the send_recv()
667 * function has finished processing it is a bug.
668 */
669 if (mid->mid_flags & MID_DELETED)
Joe Perchesa0a30362020-04-14 22:42:53 -0700670 pr_warn_once("trying to dequeue a deleted mid\n");
Pavel Shilovskyabe57072019-10-22 08:41:42 -0700671 else {
Ronnie Sahlbergddf83af2018-08-30 10:12:59 +1000672 list_del_init(&mid->qhead);
Pavel Shilovskyabe57072019-10-22 08:41:42 -0700673 mid->mid_flags |= MID_DELETED;
674 }
Jeff Laytonea1f4502011-10-19 15:29:05 -0400675 spin_unlock(&GlobalMid_Lock);
676}
677
Pavel Shilovsky86a79642019-11-21 11:35:13 -0800678static unsigned int
679smb2_get_credits_from_hdr(char *buffer, struct TCP_Server_Info *server)
680{
681 struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buffer;
682
683 /*
684 * SMB1 does not use credits.
685 */
686 if (server->vals->header_preamble_size)
687 return 0;
688
689 return le16_to_cpu(shdr->CreditRequest);
690}
691
Jeff Laytonc8054eb2011-10-19 15:29:31 -0400692static void
693handle_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server,
Pavel Shilovskyd4e48542012-03-23 14:28:02 -0400694 char *buf, int malformed)
Jeff Laytonea1f4502011-10-19 15:29:05 -0400695{
Pavel Shilovsky316cf942012-05-23 14:31:03 +0400696 if (server->ops->check_trans2 &&
697 server->ops->check_trans2(mid, server, buf, malformed))
Jeff Laytonc8054eb2011-10-19 15:29:31 -0400698 return;
Pavel Shilovsky86a79642019-11-21 11:35:13 -0800699 mid->credits_received = smb2_get_credits_from_hdr(buf, server);
Jeff Laytonea1f4502011-10-19 15:29:05 -0400700 mid->resp_buf = buf;
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -0400701 mid->large_buf = server->large_buf;
Jeff Layton2a37ef92011-10-19 15:29:23 -0400702 /* Was previous buf put in mpx struct for multi-rsp? */
703 if (!mid->multiRsp) {
704 /* smb buffer will be freed by user thread */
705 if (server->large_buf)
706 server->bigbuf = NULL;
707 else
708 server->smallbuf = NULL;
709 }
Jeff Laytonffc00e22011-10-19 15:29:13 -0400710 dequeue_mid(mid, malformed);
Pavel Shilovskyad69bae2011-08-01 13:19:43 +0400711}
712
Pavel Shilovsky762dfd12011-08-01 13:19:44 +0400713static void clean_demultiplex_info(struct TCP_Server_Info *server)
714{
715 int length;
716
717 /* take it off the list, if it's not already */
718 spin_lock(&cifs_tcp_ses_lock);
719 list_del_init(&server->tcp_ses_list);
720 spin_unlock(&cifs_tcp_ses_lock);
721
Paulo Alcantara21225332020-11-28 16:54:02 -0300722 cancel_delayed_work_sync(&server->echo);
Shyam Prasad N506c1da2021-05-18 15:05:50 +0000723 cancel_delayed_work_sync(&server->resolve);
Paulo Alcantara21225332020-11-28 16:54:02 -0300724
Pavel Shilovsky762dfd12011-08-01 13:19:44 +0400725 spin_lock(&GlobalMid_Lock);
726 server->tcpStatus = CifsExiting;
727 spin_unlock(&GlobalMid_Lock);
728 wake_up_all(&server->response_q);
729
Pavel Shilovsky2d86dbc2012-02-06 15:59:18 +0400730 /* check if we have blocked requests that need to free */
Pavel Shilovskyfc40f9c2012-02-17 17:09:12 +0300731 spin_lock(&server->req_lock);
Pavel Shilovsky2d86dbc2012-02-06 15:59:18 +0400732 if (server->credits <= 0)
733 server->credits = 1;
Pavel Shilovskyfc40f9c2012-02-17 17:09:12 +0300734 spin_unlock(&server->req_lock);
Pavel Shilovsky762dfd12011-08-01 13:19:44 +0400735 /*
736 * Although there should not be any requests blocked on this queue it
737 * can not hurt to be paranoid and try to wake up requests that may
738 * haven been blocked when more than 50 at time were on the wire to the
739 * same server - they now will see the session is in exit state and get
740 * out of SendReceive.
741 */
742 wake_up_all(&server->request_q);
743 /* give those requests time to exit */
744 msleep(125);
Long Li050b8c32019-04-04 11:35:42 -0500745 if (cifs_rdma_enabled(server))
746 smbd_destroy(server);
Pavel Shilovsky762dfd12011-08-01 13:19:44 +0400747 if (server->ssocket) {
748 sock_release(server->ssocket);
749 server->ssocket = NULL;
750 }
751
752 if (!list_empty(&server->pending_mid_q)) {
753 struct list_head dispose_list;
754 struct mid_q_entry *mid_entry;
755 struct list_head *tmp, *tmp2;
756
757 INIT_LIST_HEAD(&dispose_list);
758 spin_lock(&GlobalMid_Lock);
759 list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
760 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
Paulo Alcantarabf1bc6942021-03-08 12:00:47 -0300761 cifs_dbg(FYI, "Clearing mid %llu\n", mid_entry->mid);
Pavel Shilovskyabe57072019-10-22 08:41:42 -0700762 kref_get(&mid_entry->refcount);
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -0400763 mid_entry->mid_state = MID_SHUTDOWN;
Pavel Shilovsky762dfd12011-08-01 13:19:44 +0400764 list_move(&mid_entry->qhead, &dispose_list);
Pavel Shilovskyabe57072019-10-22 08:41:42 -0700765 mid_entry->mid_flags |= MID_DELETED;
Pavel Shilovsky762dfd12011-08-01 13:19:44 +0400766 }
767 spin_unlock(&GlobalMid_Lock);
768
769 /* now walk dispose list and issue callbacks */
770 list_for_each_safe(tmp, tmp2, &dispose_list) {
771 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
Paulo Alcantarabf1bc6942021-03-08 12:00:47 -0300772 cifs_dbg(FYI, "Callback mid %llu\n", mid_entry->mid);
Pavel Shilovsky762dfd12011-08-01 13:19:44 +0400773 list_del_init(&mid_entry->qhead);
774 mid_entry->callback(mid_entry);
Pavel Shilovskyabe57072019-10-22 08:41:42 -0700775 cifs_mid_q_entry_release(mid_entry);
Pavel Shilovsky762dfd12011-08-01 13:19:44 +0400776 }
777 /* 1/8th of sec is more than enough time for them to exit */
778 msleep(125);
779 }
780
781 if (!list_empty(&server->pending_mid_q)) {
782 /*
783 * mpx threads have not exited yet give them at least the smb
784 * send timeout time for long ops.
785 *
786 * Due to delays on oplock break requests, we need to wait at
787 * least 45 seconds before giving up on a request getting a
788 * response and going ahead and killing cifsd.
789 */
Joe Perchesf96637b2013-05-04 22:12:25 -0500790 cifs_dbg(FYI, "Wait for exit from demultiplex thread\n");
Pavel Shilovsky762dfd12011-08-01 13:19:44 +0400791 msleep(46000);
792 /*
793 * If threads still have not exited they are probably never
794 * coming home not much else we can do but free the memory.
795 */
796 }
797
798 kfree(server->hostname);
799 kfree(server);
800
801 length = atomic_dec_return(&tcpSesAllocCount);
802 if (length > 0)
David Rientjes11d83362015-04-14 15:48:21 -0700803 mempool_resize(cifs_req_poolp, length + cifs_min_rcv);
Pavel Shilovsky762dfd12011-08-01 13:19:44 +0400804}
805
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400806static int
Jeff Laytone9097ab2011-10-19 15:29:40 -0400807standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
808{
809 int length;
810 char *buf = server->smallbuf;
Ronnie Sahlberg2e964672018-04-09 18:06:26 +1000811 unsigned int pdu_length = server->pdu_size;
Jeff Laytone9097ab2011-10-19 15:29:40 -0400812
813 /* make sure this will fit in a large buffer */
Ronnie Sahlberg93012bf2018-03-31 11:45:31 +1100814 if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server) -
815 server->vals->header_preamble_size) {
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +1000816 cifs_server_dbg(VFS, "SMB response too long (%u bytes)\n", pdu_length);
Jeff Laytone9097ab2011-10-19 15:29:40 -0400817 cifs_reconnect(server);
Pavel Shilovsky3fabaa22014-07-10 09:55:52 +0400818 return -ECONNABORTED;
Jeff Laytone9097ab2011-10-19 15:29:40 -0400819 }
820
821 /* switch to large buffer if too big for a small one */
822 if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
823 server->large_buf = true;
Pavel Shilovskyd4e48542012-03-23 14:28:02 -0400824 memcpy(server->bigbuf, buf, server->total_read);
Jeff Laytone9097ab2011-10-19 15:29:40 -0400825 buf = server->bigbuf;
Jeff Laytone9097ab2011-10-19 15:29:40 -0400826 }
827
828 /* now read the rest */
Pavel Shilovsky1887f602012-05-17 12:45:31 +0400829 length = cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1,
Ronnie Sahlberg93012bf2018-03-31 11:45:31 +1100830 pdu_length - HEADER_SIZE(server) + 1
831 + server->vals->header_preamble_size);
832
Jeff Laytone9097ab2011-10-19 15:29:40 -0400833 if (length < 0)
834 return length;
835 server->total_read += length;
836
Pavel Shilovskyd4e48542012-03-23 14:28:02 -0400837 dump_smb(buf, server->total_read);
Jeff Laytone9097ab2011-10-19 15:29:40 -0400838
Pavel Shilovsky4326ed22016-11-17 15:24:46 -0800839 return cifs_handle_standard(server, mid);
840}
841
842int
843cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
844{
845 char *buf = server->large_buf ? server->bigbuf : server->smallbuf;
846 int length;
847
Jeff Laytone9097ab2011-10-19 15:29:40 -0400848 /*
849 * We know that we received enough to get to the MID as we
850 * checked the pdu_length earlier. Now check to see
851 * if the rest of the header is OK. We borrow the length
852 * var for the rest of the loop to avoid a new stack var.
853 *
854 * 48 bytes is enough to display the header and a little bit
855 * into the payload for debugging purposes.
856 */
Steve French373512e2015-12-18 13:05:30 -0600857 length = server->ops->check_message(buf, server->total_read, server);
Jeff Laytone9097ab2011-10-19 15:29:40 -0400858 if (length != 0)
859 cifs_dump_mem("Bad SMB: ", buf,
860 min_t(unsigned int, server->total_read, 48));
861
Pavel Shilovsky511c54a2017-07-08 14:32:00 -0700862 if (server->ops->is_session_expired &&
863 server->ops->is_session_expired(buf)) {
864 cifs_reconnect(server);
Pavel Shilovsky511c54a2017-07-08 14:32:00 -0700865 return -1;
866 }
867
Pavel Shilovsky2e44b282012-09-18 16:20:33 -0700868 if (server->ops->is_status_pending &&
Pavel Shilovsky66265f12019-01-23 17:11:16 -0800869 server->ops->is_status_pending(buf, server))
Pavel Shilovsky2e44b282012-09-18 16:20:33 -0700870 return -1;
871
Jeff Laytonff4fa4a2012-02-07 06:31:05 -0500872 if (!mid)
873 return length;
Jeff Laytone9097ab2011-10-19 15:29:40 -0400874
Pavel Shilovskyd4e48542012-03-23 14:28:02 -0400875 handle_mid(mid, server, buf, length);
Jeff Laytonff4fa4a2012-02-07 06:31:05 -0500876 return 0;
Jeff Laytone9097ab2011-10-19 15:29:40 -0400877}
878
Ronnie Sahlbergeca00452019-02-05 12:56:44 +1000879static void
880smb2_add_credits_from_hdr(char *buffer, struct TCP_Server_Info *server)
881{
882 struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buffer;
Shyam Prasad N6d82c272021-02-03 23:20:46 -0800883 int scredits, in_flight;
Ronnie Sahlbergeca00452019-02-05 12:56:44 +1000884
885 /*
886 * SMB1 does not use credits.
887 */
888 if (server->vals->header_preamble_size)
889 return;
890
891 if (shdr->CreditRequest) {
892 spin_lock(&server->req_lock);
893 server->credits += le16_to_cpu(shdr->CreditRequest);
Shyam Prasad N6d82c272021-02-03 23:20:46 -0800894 scredits = server->credits;
895 in_flight = server->in_flight;
Ronnie Sahlbergeca00452019-02-05 12:56:44 +1000896 spin_unlock(&server->req_lock);
897 wake_up(&server->request_q);
Shyam Prasad Ncd7b6992020-11-12 08:56:49 -0800898
899 trace_smb3_add_credits(server->CurrentMid,
Shyam Prasad N6d82c272021-02-03 23:20:46 -0800900 server->conn_id, server->hostname, scredits,
901 le16_to_cpu(shdr->CreditRequest), in_flight);
Shyam Prasad Ncd7b6992020-11-12 08:56:49 -0800902 cifs_server_dbg(FYI, "%s: added %u credits total=%d\n",
903 __func__, le16_to_cpu(shdr->CreditRequest),
904 scredits);
Ronnie Sahlbergeca00452019-02-05 12:56:44 +1000905 }
906}
907
908
Jeff Laytone9097ab2011-10-19 15:29:40 -0400909static int
Al Viro7c97c202011-06-21 08:51:28 -0400910cifs_demultiplex_thread(void *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911{
Ronnie Sahlbergb24df3e2018-08-08 15:07:45 +1000912 int i, num_mids, length;
Al Viro7c97c202011-06-21 08:51:28 -0400913 struct TCP_Server_Info *server = p;
Jeff Layton2a37ef92011-10-19 15:29:23 -0400914 unsigned int pdu_length;
Ronnie Sahlberg8ce79ec2018-06-01 10:53:08 +1000915 unsigned int next_offset;
Jeff Layton2a37ef92011-10-19 15:29:23 -0400916 char *buf = NULL;
Steve Frencha5c3e1c2014-09-16 04:16:19 -0500917 struct task_struct *task_to_wake = NULL;
Ronnie Sahlbergb24df3e2018-08-08 15:07:45 +1000918 struct mid_q_entry *mids[MAX_COMPOUND];
919 char *bufs[MAX_COMPOUND];
Rohith Surabattula8e670f72020-09-18 05:37:28 +0000920 unsigned int noreclaim_flag, num_io_timeout = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921
Eric Biggersdc920272020-03-08 22:58:20 -0700922 noreclaim_flag = memalloc_noreclaim_save();
Joe Perchesf96637b2013-05-04 22:12:25 -0500923 cifs_dbg(FYI, "Demultiplex PID: %d\n", task_pid_nr(current));
Jeff Layton93d0ec82008-08-02 08:00:48 -0400924
925 length = atomic_inc_return(&tcpSesAllocCount);
926 if (length > 1)
David Rientjes11d83362015-04-14 15:48:21 -0700927 mempool_resize(cifs_req_poolp, length + cifs_min_rcv);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928
Rafael J. Wysocki83144182007-07-17 04:03:35 -0700929 set_freezable();
Eric W. Biederman33da8e72019-08-16 12:33:54 -0500930 allow_kernel_signal(SIGKILL);
Jeff Layton469ee612008-10-16 18:46:39 +0000931 while (server->tcpStatus != CifsExiting) {
Steve Frenchede13272005-08-30 20:10:14 -0700932 if (try_to_freeze())
933 continue;
Steve Frenchb8643e12005-04-28 22:41:07 -0700934
Jeff Layton2a37ef92011-10-19 15:29:23 -0400935 if (!allocate_buffers(server))
Pavel Shilovsky3d9c2472011-08-01 13:19:40 +0400936 continue;
Steve Frenchb8643e12005-04-28 22:41:07 -0700937
Jeff Layton2a37ef92011-10-19 15:29:23 -0400938 server->large_buf = false;
Jeff Layton2a37ef92011-10-19 15:29:23 -0400939 buf = server->smallbuf;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000940 pdu_length = 4; /* enough to get RFC1001 header */
Steve Frenchfda35942011-01-20 18:06:34 +0000941
Jeff Laytone28bc5b2011-10-19 15:30:07 -0400942 length = cifs_read_from_socket(server, buf, pdu_length);
Jeff Laytona52c1eb2011-10-11 06:41:32 -0400943 if (length < 0)
Steve Frenchfda35942011-01-20 18:06:34 +0000944 continue;
Ronnie Sahlberg977b6172018-06-01 10:53:02 +1000945
946 if (server->vals->header_preamble_size == 0)
947 server->total_read = 0;
948 else
949 server->total_read = length;
Steve French67010fb2005-04-28 22:41:09 -0700950
Pavel Shilovsky98bac622011-08-01 13:19:42 +0400951 /*
952 * The right amount was read from socket - 4 bytes,
953 * so we can now interpret the length field.
954 */
Pavel Shilovskyd4e48542012-03-23 14:28:02 -0400955 pdu_length = get_rfc1002_length(buf);
Steve French46810cb2005-04-28 22:41:09 -0700956
Joe Perchesf96637b2013-05-04 22:12:25 -0500957 cifs_dbg(FYI, "RFC1002 header 0x%x\n", pdu_length);
Jeff Laytonfe11e4c2011-10-11 06:41:32 -0400958 if (!is_smb_response(server, buf[0]))
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000959 continue;
Ronnie Sahlberg8ce79ec2018-06-01 10:53:08 +1000960next_pdu:
961 server->pdu_size = pdu_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700962
Jeff Layton89482a52011-10-19 15:28:57 -0400963 /* make sure we have enough to get to the MID */
Ronnie Sahlberg8ce79ec2018-06-01 10:53:08 +1000964 if (server->pdu_size < HEADER_SIZE(server) - 1 -
Ronnie Sahlberg93012bf2018-03-31 11:45:31 +1100965 server->vals->header_preamble_size) {
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +1000966 cifs_server_dbg(VFS, "SMB response too short (%u bytes)\n",
Ronnie Sahlberg8ce79ec2018-06-01 10:53:08 +1000967 server->pdu_size);
Jeff Layton89482a52011-10-19 15:28:57 -0400968 cifs_reconnect(server);
Jeff Layton89482a52011-10-19 15:28:57 -0400969 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700970 }
Pavel Shilovskye7015fb2011-08-01 13:19:41 +0400971
Jeff Layton89482a52011-10-19 15:28:57 -0400972 /* read down to the MID */
Ronnie Sahlberg93012bf2018-03-31 11:45:31 +1100973 length = cifs_read_from_socket(server,
974 buf + server->vals->header_preamble_size,
975 HEADER_SIZE(server) - 1
976 - server->vals->header_preamble_size);
Jeff Layton89482a52011-10-19 15:28:57 -0400977 if (length < 0)
978 continue;
Jeff Layton2a37ef92011-10-19 15:29:23 -0400979 server->total_read += length;
Jeff Layton89482a52011-10-19 15:28:57 -0400980
Ronnie Sahlberg8ce79ec2018-06-01 10:53:08 +1000981 if (server->ops->next_header) {
982 next_offset = server->ops->next_header(buf);
983 if (next_offset)
984 server->pdu_size = next_offset;
985 }
986
Ronnie Sahlbergb24df3e2018-08-08 15:07:45 +1000987 memset(mids, 0, sizeof(mids));
988 memset(bufs, 0, sizeof(bufs));
989 num_mids = 0;
990
Pavel Shilovsky9bb17e02016-11-17 15:24:34 -0800991 if (server->ops->is_transform_hdr &&
992 server->ops->receive_transform &&
993 server->ops->is_transform_hdr(buf)) {
994 length = server->ops->receive_transform(server,
Ronnie Sahlbergb24df3e2018-08-08 15:07:45 +1000995 mids,
996 bufs,
997 &num_mids);
Pavel Shilovsky9bb17e02016-11-17 15:24:34 -0800998 } else {
Ronnie Sahlbergb24df3e2018-08-08 15:07:45 +1000999 mids[0] = server->ops->find_mid(server, buf);
1000 bufs[0] = buf;
Steve French7af929d2018-10-02 18:54:09 -05001001 num_mids = 1;
Jeff Laytonc8054eb2011-10-19 15:29:31 -04001002
Ronnie Sahlbergb24df3e2018-08-08 15:07:45 +10001003 if (!mids[0] || !mids[0]->receive)
1004 length = standard_receive3(server, mids[0]);
Pavel Shilovsky9bb17e02016-11-17 15:24:34 -08001005 else
Ronnie Sahlbergb24df3e2018-08-08 15:07:45 +10001006 length = mids[0]->receive(server, mids[0]);
Pavel Shilovsky9bb17e02016-11-17 15:24:34 -08001007 }
Jeff Layton44d22d82011-10-19 15:29:49 -04001008
Lars Persson696e4202018-06-25 14:05:25 +02001009 if (length < 0) {
Ronnie Sahlbergb24df3e2018-08-08 15:07:45 +10001010 for (i = 0; i < num_mids; i++)
1011 if (mids[i])
1012 cifs_mid_q_entry_release(mids[i]);
Steve Frenche4eb2952005-04-28 22:41:09 -07001013 continue;
Lars Persson696e4202018-06-25 14:05:25 +02001014 }
Steve Frenche4eb2952005-04-28 22:41:09 -07001015
Rohith Surabattula8e670f72020-09-18 05:37:28 +00001016 if (server->ops->is_status_io_timeout &&
1017 server->ops->is_status_io_timeout(buf)) {
1018 num_io_timeout++;
1019 if (num_io_timeout > NUM_STATUS_IO_TIMEOUT) {
1020 cifs_reconnect(server);
1021 num_io_timeout = 0;
1022 continue;
1023 }
1024 }
1025
Steve Frenchfda35942011-01-20 18:06:34 +00001026 server->lstrp = jiffies;
Ronnie Sahlbergb24df3e2018-08-08 15:07:45 +10001027
1028 for (i = 0; i < num_mids; i++) {
1029 if (mids[i] != NULL) {
1030 mids[i]->resp_buf_size = server->pdu_size;
Sachin Prabhu38bd4902017-03-03 15:41:38 -08001031
Rohith Surabattula9e550b02021-02-16 10:40:45 +00001032 if (bufs[i] && server->ops->is_network_name_deleted)
1033 server->ops->is_network_name_deleted(bufs[i],
1034 server);
1035
Ronnie Sahlbergb24df3e2018-08-08 15:07:45 +10001036 if (!mids[i]->multiRsp || mids[i]->multiEnd)
1037 mids[i]->callback(mids[i]);
Lars Persson696e4202018-06-25 14:05:25 +02001038
Ronnie Sahlbergb24df3e2018-08-08 15:07:45 +10001039 cifs_mid_q_entry_release(mids[i]);
1040 } else if (server->ops->is_oplock_break &&
1041 server->ops->is_oplock_break(bufs[i],
1042 server)) {
Ronnie Sahlbergeca00452019-02-05 12:56:44 +10001043 smb2_add_credits_from_hdr(bufs[i], server);
Ronnie Sahlbergb24df3e2018-08-08 15:07:45 +10001044 cifs_dbg(FYI, "Received oplock break\n");
1045 } else {
Joe Perchesa0a30362020-04-14 22:42:53 -07001046 cifs_server_dbg(VFS, "No task to wake, unknown frame received! NumMids %d\n",
1047 atomic_read(&midCount));
Ronnie Sahlbergb24df3e2018-08-08 15:07:45 +10001048 cifs_dump_mem("Received Data is: ", bufs[i],
1049 HEADER_SIZE(server));
Ronnie Sahlberg3e272572019-07-06 06:43:08 +10001050 smb2_add_credits_from_hdr(bufs[i], server);
Steve French39798772006-05-31 22:40:51 +00001051#ifdef CONFIG_CIFS_DEBUG2
Ronnie Sahlbergb24df3e2018-08-08 15:07:45 +10001052 if (server->ops->dump_detail)
1053 server->ops->dump_detail(bufs[i],
1054 server);
1055 cifs_dump_mids(server);
Steve French39798772006-05-31 22:40:51 +00001056#endif /* CIFS_DEBUG2 */
Ronnie Sahlbergb24df3e2018-08-08 15:07:45 +10001057 }
Ronnie Sahlberg8ce79ec2018-06-01 10:53:08 +10001058 }
Ronnie Sahlbergb24df3e2018-08-08 15:07:45 +10001059
Ronnie Sahlberg8ce79ec2018-06-01 10:53:08 +10001060 if (pdu_length > server->pdu_size) {
1061 if (!allocate_buffers(server))
1062 continue;
1063 pdu_length -= server->pdu_size;
1064 server->total_read = 0;
1065 server->large_buf = false;
1066 buf = server->smallbuf;
1067 goto next_pdu;
Steve Frenche4eb2952005-04-28 22:41:09 -07001068 }
1069 } /* end while !EXITING */
1070
Justin P. Mattockfd62cb72011-02-24 22:15:02 -08001071 /* buffer usually freed in free_mid - need to free it here on exit */
Jeff Layton2a37ef92011-10-19 15:29:23 -04001072 cifs_buf_release(server->bigbuf);
1073 if (server->smallbuf) /* no sense logging a debug message if NULL */
1074 cifs_small_buf_release(server->smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075
Steve Frencha5c3e1c2014-09-16 04:16:19 -05001076 task_to_wake = xchg(&server->tsk, NULL);
Pavel Shilovsky762dfd12011-08-01 13:19:44 +04001077 clean_demultiplex_info(server);
Steve Frencha5c3e1c2014-09-16 04:16:19 -05001078
1079 /* if server->tsk was NULL then wait for a signal before exiting */
1080 if (!task_to_wake) {
1081 set_current_state(TASK_INTERRUPTIBLE);
1082 while (!signal_pending(current)) {
1083 schedule();
1084 set_current_state(TASK_INTERRUPTIBLE);
1085 }
1086 set_current_state(TASK_RUNNING);
1087 }
1088
Eric Biggersdc920272020-03-08 22:58:20 -07001089 memalloc_noreclaim_restore(noreclaim_flag);
Jeff Layton0468a2c2008-12-01 07:09:35 -05001090 module_put_and_exit(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091}
1092
Steve Frenchbc044992020-12-11 19:48:26 -06001093/**
1094 * Returns true if srcaddr isn't specified and rhs isn't specified, or
1095 * if srcaddr is specified and matches the IP address of the rhs argument
Ben Greear3eb9a882010-09-01 17:06:02 -07001096 */
Paulo Alcantarae4af35f2020-05-19 15:38:28 -03001097bool
1098cifs_match_ipaddr(struct sockaddr *srcaddr, struct sockaddr *rhs)
Ben Greear3eb9a882010-09-01 17:06:02 -07001099{
1100 switch (srcaddr->sa_family) {
1101 case AF_UNSPEC:
1102 return (rhs->sa_family == AF_UNSPEC);
1103 case AF_INET: {
1104 struct sockaddr_in *saddr4 = (struct sockaddr_in *)srcaddr;
1105 struct sockaddr_in *vaddr4 = (struct sockaddr_in *)rhs;
1106 return (saddr4->sin_addr.s_addr == vaddr4->sin_addr.s_addr);
1107 }
1108 case AF_INET6: {
1109 struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)srcaddr;
Nickolai Zeldoviche3e27752013-01-16 21:36:17 -05001110 struct sockaddr_in6 *vaddr6 = (struct sockaddr_in6 *)rhs;
Ben Greear3eb9a882010-09-01 17:06:02 -07001111 return ipv6_addr_equal(&saddr6->sin6_addr, &vaddr6->sin6_addr);
1112 }
1113 default:
1114 WARN_ON(1);
1115 return false; /* don't expect to be here */
1116 }
1117}
1118
Pavel Shilovsky4b886132010-12-13 22:18:07 +03001119/*
1120 * If no port is specified in addr structure, we try to match with 445 port
1121 * and if it fails - with 139 ports. It should be called only if address
1122 * families of server and addr are equal.
1123 */
1124static bool
1125match_port(struct TCP_Server_Info *server, struct sockaddr *addr)
1126{
Steve French6da97912011-03-13 18:55:55 +00001127 __be16 port, *sport;
Pavel Shilovsky4b886132010-12-13 22:18:07 +03001128
Long Li3b249112019-05-15 14:09:04 -07001129 /* SMBDirect manages its own ports, don't match it here */
1130 if (server->rdma)
1131 return true;
1132
Pavel Shilovsky4b886132010-12-13 22:18:07 +03001133 switch (addr->sa_family) {
1134 case AF_INET:
1135 sport = &((struct sockaddr_in *) &server->dstaddr)->sin_port;
1136 port = ((struct sockaddr_in *) addr)->sin_port;
1137 break;
1138 case AF_INET6:
1139 sport = &((struct sockaddr_in6 *) &server->dstaddr)->sin6_port;
1140 port = ((struct sockaddr_in6 *) addr)->sin6_port;
1141 break;
1142 default:
1143 WARN_ON(1);
1144 return false;
1145 }
1146
1147 if (!port) {
1148 port = htons(CIFS_PORT);
1149 if (port == *sport)
1150 return true;
1151
1152 port = htons(RFC1001_PORT);
1153 }
1154
1155 return port == *sport;
1156}
Ben Greear3eb9a882010-09-01 17:06:02 -07001157
1158static bool
1159match_address(struct TCP_Server_Info *server, struct sockaddr *addr,
1160 struct sockaddr *srcaddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161{
Jeff Layton45151482010-07-06 20:43:02 -04001162 switch (addr->sa_family) {
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03001163 case AF_INET: {
1164 struct sockaddr_in *addr4 = (struct sockaddr_in *)addr;
1165 struct sockaddr_in *srv_addr4 =
1166 (struct sockaddr_in *)&server->dstaddr;
1167
1168 if (addr4->sin_addr.s_addr != srv_addr4->sin_addr.s_addr)
Jeff Layton45151482010-07-06 20:43:02 -04001169 return false;
Jeff Layton45151482010-07-06 20:43:02 -04001170 break;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03001171 }
1172 case AF_INET6: {
1173 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
1174 struct sockaddr_in6 *srv_addr6 =
1175 (struct sockaddr_in6 *)&server->dstaddr;
1176
Jeff Layton45151482010-07-06 20:43:02 -04001177 if (!ipv6_addr_equal(&addr6->sin6_addr,
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03001178 &srv_addr6->sin6_addr))
Jeff Layton45151482010-07-06 20:43:02 -04001179 return false;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03001180 if (addr6->sin6_scope_id != srv_addr6->sin6_scope_id)
Jeff Layton45151482010-07-06 20:43:02 -04001181 return false;
Jeff Layton45151482010-07-06 20:43:02 -04001182 break;
1183 }
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03001184 default:
1185 WARN_ON(1);
1186 return false; /* don't expect to be here */
1187 }
Jeff Layton45151482010-07-06 20:43:02 -04001188
Paulo Alcantarae4af35f2020-05-19 15:38:28 -03001189 if (!cifs_match_ipaddr(srcaddr, (struct sockaddr *)&server->srcaddr))
Ben Greear3eb9a882010-09-01 17:06:02 -07001190 return false;
1191
Jeff Layton45151482010-07-06 20:43:02 -04001192 return true;
1193}
1194
Jeff Laytondaf5b0b2010-07-06 20:43:02 -04001195static bool
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001196match_security(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
Jeff Laytondaf5b0b2010-07-06 20:43:02 -04001197{
Jeff Layton3f618222013-06-12 19:52:14 -05001198 /*
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001199 * The select_sectype function should either return the ctx->sectype
Jeff Layton3f618222013-06-12 19:52:14 -05001200 * that was specified, or "Unspecified" if that sectype was not
1201 * compatible with the given NEGOTIATE request.
1202 */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001203 if (server->ops->select_sectype(server, ctx->sectype)
Sachin Prabhuef65aae2017-01-18 15:35:57 +05301204 == Unspecified)
Jeff Laytondaf5b0b2010-07-06 20:43:02 -04001205 return false;
Jeff Laytondaf5b0b2010-07-06 20:43:02 -04001206
Jeff Layton3f618222013-06-12 19:52:14 -05001207 /*
1208 * Now check if signing mode is acceptable. No need to check
1209 * global_secflags at this point since if MUST_SIGN is set then
1210 * the server->sign had better be too.
1211 */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001212 if (ctx->sign && !server->sign)
Jeff Layton38d77c52013-05-26 07:01:00 -04001213 return false;
Jeff Laytondaf5b0b2010-07-06 20:43:02 -04001214
1215 return true;
1216}
1217
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001218static int match_server(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00001219{
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001220 struct sockaddr *addr = (struct sockaddr *)&ctx->dstaddr;
Jeff Layton9fa114f2012-11-26 11:09:57 -05001221
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001222 if (ctx->nosharesock)
Jeff Laytona0b3df52013-05-24 07:40:59 -04001223 return 0;
1224
Steve French43cdae82019-06-13 14:26:49 -05001225 /* If multidialect negotiation see if existing sessions match one */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001226 if (strcmp(ctx->vals->version_string, SMB3ANY_VERSION_STRING) == 0) {
Steve French43cdae82019-06-13 14:26:49 -05001227 if (server->vals->protocol_id < SMB30_PROT_ID)
1228 return 0;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001229 } else if (strcmp(ctx->vals->version_string,
Steve French43cdae82019-06-13 14:26:49 -05001230 SMBDEFAULT_VERSION_STRING) == 0) {
1231 if (server->vals->protocol_id < SMB21_PROT_ID)
1232 return 0;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001233 } else if ((server->vals != ctx->vals) || (server->ops != ctx->ops))
Jeff Layton23db65f2012-05-15 12:20:51 -04001234 return 0;
1235
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00001236 if (!net_eq(cifs_net_ns(server), current->nsproxy->net_ns))
1237 return 0;
1238
1239 if (!match_address(server, addr,
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001240 (struct sockaddr *)&ctx->srcaddr))
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00001241 return 0;
1242
1243 if (!match_port(server, addr))
1244 return 0;
1245
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001246 if (!match_security(server, ctx))
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00001247 return 0;
1248
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001249 if (server->echo_interval != ctx->echo_interval * HZ)
Steve Frenchadfeb3e2015-12-18 12:31:36 -06001250 return 0;
1251
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001252 if (server->rdma != ctx->rdma)
Long Li8339dd32017-11-07 01:54:55 -07001253 return 0;
1254
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001255 if (server->ignore_signature != ctx->ignore_signature)
Steve French4f5c10f2019-09-03 21:18:49 -05001256 return 0;
1257
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001258 if (server->min_offload != ctx->min_offload)
Steve French563317e2019-09-08 23:22:02 -05001259 return 0;
1260
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00001261 return 1;
1262}
1263
Paulo Alcantara54be1f62018-11-14 16:01:21 -02001264struct TCP_Server_Info *
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001265cifs_find_tcp_session(struct smb3_fs_context *ctx)
Jeff Layton45151482010-07-06 20:43:02 -04001266{
Jeff Laytone7ddee92008-11-14 13:44:38 -05001267 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301269 spin_lock(&cifs_tcp_ses_lock);
Jeff Layton45151482010-07-06 20:43:02 -04001270 list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
Paulo Alcantara (SUSE)3345bb42019-12-04 11:25:06 -03001271 /*
1272 * Skip ses channels since they're only handled in lower layers
1273 * (e.g. cifs_send_recv).
1274 */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001275 if (server->is_channel || !match_server(server, ctx))
Jeff Laytondaf5b0b2010-07-06 20:43:02 -04001276 continue;
1277
Jeff Laytone7ddee92008-11-14 13:44:38 -05001278 ++server->srv_count;
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301279 spin_unlock(&cifs_tcp_ses_lock);
Joe Perchesf96637b2013-05-04 22:12:25 -05001280 cifs_dbg(FYI, "Existing tcp session with server found\n");
Jeff Laytone7ddee92008-11-14 13:44:38 -05001281 return server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301283 spin_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 return NULL;
1285}
1286
Pavel Shilovsky53e0e112016-11-04 11:50:31 -07001287void
1288cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289{
Steve Frencha5c3e1c2014-09-16 04:16:19 -05001290 struct task_struct *task;
1291
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301292 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -05001293 if (--server->srv_count > 0) {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301294 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -05001295 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 }
Steve Frenchdea570e02008-05-06 22:05:51 +00001297
Rob Landleyf1d0c992011-01-22 15:44:05 -06001298 put_net(cifs_net_ns(server));
1299
Jeff Laytone7ddee92008-11-14 13:44:38 -05001300 list_del_init(&server->tcp_ses_list);
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301301 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -05001302
Jeff Laytonc74093b2011-01-11 07:24:23 -05001303 cancel_delayed_work_sync(&server->echo);
Shyam Prasad N506c1da2021-05-18 15:05:50 +00001304 cancel_delayed_work_sync(&server->resolve);
Jeff Laytonc74093b2011-01-11 07:24:23 -05001305
Pavel Shilovsky53e0e112016-11-04 11:50:31 -07001306 if (from_reconnect)
1307 /*
1308 * Avoid deadlock here: reconnect work calls
1309 * cifs_put_tcp_session() at its end. Need to be sure
1310 * that reconnect work does nothing with server pointer after
1311 * that step.
1312 */
1313 cancel_delayed_work(&server->reconnect);
1314 else
1315 cancel_delayed_work_sync(&server->reconnect);
Pavel Shilovsky53e0e112016-11-04 11:50:31 -07001316
Jeff Laytone7ddee92008-11-14 13:44:38 -05001317 spin_lock(&GlobalMid_Lock);
1318 server->tcpStatus = CifsExiting;
1319 spin_unlock(&GlobalMid_Lock);
1320
Pavel Shilovsky026e93d2016-11-03 16:47:37 -07001321 cifs_crypto_secmech_release(server);
Suresh Jayaraman488f1d2d2010-07-05 18:12:15 +05301322 cifs_fscache_release_client_cookie(server);
1323
Shirish Pargaonkar21e73392010-10-21 06:42:55 -05001324 kfree(server->session_key.response);
1325 server->session_key.response = NULL;
1326 server->session_key.len = 0;
Steve Frencha5c3e1c2014-09-16 04:16:19 -05001327
1328 task = xchg(&server->tsk, NULL);
1329 if (task)
Eric W. Biederman72abe3b2019-05-15 12:33:50 -05001330 send_sig(SIGKILL, task, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331}
1332
Aurelien Apteld70e9fa2019-09-20 06:31:10 +02001333struct TCP_Server_Info *
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001334cifs_get_tcp_session(struct smb3_fs_context *ctx)
Jeff Layton63c038c2008-12-01 18:41:46 -05001335{
1336 struct TCP_Server_Info *tcp_ses = NULL;
Jeff Layton63c038c2008-12-01 18:41:46 -05001337 int rc;
1338
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001339 cifs_dbg(FYI, "UNC: %s\n", ctx->UNC);
Jeff Layton63c038c2008-12-01 18:41:46 -05001340
1341 /* see if we already have a matching tcp_ses */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001342 tcp_ses = cifs_find_tcp_session(ctx);
Jeff Layton63c038c2008-12-01 18:41:46 -05001343 if (tcp_ses)
1344 return tcp_ses;
1345
1346 tcp_ses = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
1347 if (!tcp_ses) {
1348 rc = -ENOMEM;
1349 goto out_err;
1350 }
1351
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001352 tcp_ses->ops = ctx->ops;
1353 tcp_ses->vals = ctx->vals;
Rob Landleyf1d0c992011-01-22 15:44:05 -06001354 cifs_set_net_ns(tcp_ses, get_net(current->nsproxy->net_ns));
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001355 tcp_ses->hostname = extract_hostname(ctx->UNC);
Jeff Layton63c038c2008-12-01 18:41:46 -05001356 if (IS_ERR(tcp_ses->hostname)) {
1357 rc = PTR_ERR(tcp_ses->hostname);
Shirish Pargaonkarf7c5445a2010-10-26 18:10:24 -05001358 goto out_err_crypto_release;
Jeff Layton63c038c2008-12-01 18:41:46 -05001359 }
1360
Shyam Prasad N6d82c272021-02-03 23:20:46 -08001361 tcp_ses->conn_id = atomic_inc_return(&tcpSesNextId);
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001362 tcp_ses->noblockcnt = ctx->rootfs;
1363 tcp_ses->noblocksnd = ctx->noblocksnd || ctx->rootfs;
1364 tcp_ses->noautotune = ctx->noautotune;
1365 tcp_ses->tcp_nodelay = ctx->sockopt_tcp_nodelay;
1366 tcp_ses->rdma = ctx->rdma;
Pavel Shilovskyfc40f9c2012-02-17 17:09:12 +03001367 tcp_ses->in_flight = 0;
Steve French1b63f182019-09-09 22:57:11 -05001368 tcp_ses->max_in_flight = 0;
Pavel Shilovsky2d86dbc2012-02-06 15:59:18 +04001369 tcp_ses->credits = 1;
Jeff Layton63c038c2008-12-01 18:41:46 -05001370 init_waitqueue_head(&tcp_ses->response_q);
1371 init_waitqueue_head(&tcp_ses->request_q);
1372 INIT_LIST_HEAD(&tcp_ses->pending_mid_q);
1373 mutex_init(&tcp_ses->srv_mutex);
1374 memcpy(tcp_ses->workstation_RFC1001_name,
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001375 ctx->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
Jeff Layton63c038c2008-12-01 18:41:46 -05001376 memcpy(tcp_ses->server_RFC1001_name,
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001377 ctx->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
Shirish Pargaonkar5d0d2882010-10-13 18:15:00 -05001378 tcp_ses->session_estab = false;
Jeff Layton63c038c2008-12-01 18:41:46 -05001379 tcp_ses->sequence_number = 0;
Pavel Shilovsky5b964852019-01-18 11:30:26 -08001380 tcp_ses->reconnect_instance = 1;
Steve Frenchfda35942011-01-20 18:06:34 +00001381 tcp_ses->lstrp = jiffies;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001382 tcp_ses->compress_algorithm = cpu_to_le16(ctx->compression);
Jeff Layton58fa0152012-05-01 17:41:16 -04001383 spin_lock_init(&tcp_ses->req_lock);
Jeff Layton63c038c2008-12-01 18:41:46 -05001384 INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
1385 INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
Jeff Laytonc74093b2011-01-11 07:24:23 -05001386 INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request);
Shyam Prasad N506c1da2021-05-18 15:05:50 +00001387 INIT_DELAYED_WORK(&tcp_ses->resolve, cifs_resolve_server);
Pavel Shilovsky53e0e112016-11-04 11:50:31 -07001388 INIT_DELAYED_WORK(&tcp_ses->reconnect, smb2_reconnect_server);
1389 mutex_init(&tcp_ses->reconnect_mutex);
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001390 memcpy(&tcp_ses->srcaddr, &ctx->srcaddr,
Jeff Layton9fa114f2012-11-26 11:09:57 -05001391 sizeof(tcp_ses->srcaddr));
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001392 memcpy(&tcp_ses->dstaddr, &ctx->dstaddr,
Jeff Layton9fa114f2012-11-26 11:09:57 -05001393 sizeof(tcp_ses->dstaddr));
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001394 if (ctx->use_client_guid)
1395 memcpy(tcp_ses->client_guid, ctx->client_guid,
Aurelien Aptelbcc88802019-09-20 04:32:20 +02001396 SMB2_CLIENT_GUID_SIZE);
1397 else
1398 generate_random_uuid(tcp_ses->client_guid);
Jeff Layton63c038c2008-12-01 18:41:46 -05001399 /*
1400 * at this point we are the only ones with the pointer
1401 * to the struct since the kernel thread not created yet
1402 * no need to spinlock this init of tcpStatus or srv_count
1403 */
1404 tcp_ses->tcpStatus = CifsNew;
1405 ++tcp_ses->srv_count;
1406
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001407 if (ctx->echo_interval >= SMB_ECHO_INTERVAL_MIN &&
1408 ctx->echo_interval <= SMB_ECHO_INTERVAL_MAX)
1409 tcp_ses->echo_interval = ctx->echo_interval * HZ;
Steve Frenchadfeb3e2015-12-18 12:31:36 -06001410 else
1411 tcp_ses->echo_interval = SMB_ECHO_INTERVAL_DEFAULT * HZ;
Long Li2f894642017-11-22 17:38:34 -07001412 if (tcp_ses->rdma) {
1413#ifndef CONFIG_CIFS_SMB_DIRECT
1414 cifs_dbg(VFS, "CONFIG_CIFS_SMB_DIRECT is not enabled\n");
1415 rc = -ENOENT;
1416 goto out_err_crypto_release;
1417#endif
1418 tcp_ses->smbd_conn = smbd_get_connection(
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001419 tcp_ses, (struct sockaddr *)&ctx->dstaddr);
Long Li2f894642017-11-22 17:38:34 -07001420 if (tcp_ses->smbd_conn) {
1421 cifs_dbg(VFS, "RDMA transport established\n");
1422 rc = 0;
1423 goto smbd_connected;
1424 } else {
1425 rc = -ENOENT;
1426 goto out_err_crypto_release;
1427 }
1428 }
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03001429 rc = ip_connect(tcp_ses);
Jeff Layton63c038c2008-12-01 18:41:46 -05001430 if (rc < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001431 cifs_dbg(VFS, "Error connecting to socket. Aborting operation.\n");
Shirish Pargaonkarf7c5445a2010-10-26 18:10:24 -05001432 goto out_err_crypto_release;
Jeff Layton63c038c2008-12-01 18:41:46 -05001433 }
Long Li2f894642017-11-22 17:38:34 -07001434smbd_connected:
Jeff Layton63c038c2008-12-01 18:41:46 -05001435 /*
1436 * since we're in a cifs function already, we know that
1437 * this will succeed. No need for try_module_get().
1438 */
1439 __module_get(THIS_MODULE);
Al Viro7c97c202011-06-21 08:51:28 -04001440 tcp_ses->tsk = kthread_run(cifs_demultiplex_thread,
Jeff Layton63c038c2008-12-01 18:41:46 -05001441 tcp_ses, "cifsd");
1442 if (IS_ERR(tcp_ses->tsk)) {
1443 rc = PTR_ERR(tcp_ses->tsk);
Joe Perchesf96637b2013-05-04 22:12:25 -05001444 cifs_dbg(VFS, "error %d create cifsd thread\n", rc);
Jeff Layton63c038c2008-12-01 18:41:46 -05001445 module_put(THIS_MODULE);
Shirish Pargaonkarf7c5445a2010-10-26 18:10:24 -05001446 goto out_err_crypto_release;
Jeff Layton63c038c2008-12-01 18:41:46 -05001447 }
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001448 tcp_ses->min_offload = ctx->min_offload;
Steve French01cf3082021-07-01 12:22:47 -05001449 /*
1450 * at this point we are the only ones with the pointer
1451 * to the struct since the kernel thread not created yet
1452 * no need to spinlock this update of tcpStatus
1453 */
Steve Frenchfd88ce92011-04-12 01:01:14 +00001454 tcp_ses->tcpStatus = CifsNeedNegotiate;
Jeff Layton63c038c2008-12-01 18:41:46 -05001455
Aurelien Aptela249cc82021-03-04 17:42:21 +00001456 if ((ctx->max_credits < 20) || (ctx->max_credits > 60000))
1457 tcp_ses->max_credits = SMB2_MAX_CREDITS_AVAILABLE;
1458 else
1459 tcp_ses->max_credits = ctx->max_credits;
1460
Paulo Alcantara93d5cb52018-11-14 17:13:25 -02001461 tcp_ses->nr_targets = 1;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001462 tcp_ses->ignore_signature = ctx->ignore_signature;
Jeff Layton63c038c2008-12-01 18:41:46 -05001463 /* thread spawned, put it on the list */
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301464 spin_lock(&cifs_tcp_ses_lock);
Jeff Layton63c038c2008-12-01 18:41:46 -05001465 list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list);
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301466 spin_unlock(&cifs_tcp_ses_lock);
Jeff Layton63c038c2008-12-01 18:41:46 -05001467
Suresh Jayaraman488f1d2d2010-07-05 18:12:15 +05301468 cifs_fscache_get_client_cookie(tcp_ses);
1469
Jeff Laytonc74093b2011-01-11 07:24:23 -05001470 /* queue echo request delayed work */
Steve Frenchadfeb3e2015-12-18 12:31:36 -06001471 queue_delayed_work(cifsiod_wq, &tcp_ses->echo, tcp_ses->echo_interval);
Jeff Laytonc74093b2011-01-11 07:24:23 -05001472
Shyam Prasad N506c1da2021-05-18 15:05:50 +00001473 /* queue dns resolution delayed work */
1474 cifs_dbg(FYI, "%s: next dns resolution scheduled for %d seconds in the future\n",
1475 __func__, SMB_DNS_RESOLVE_INTERVAL_DEFAULT);
1476
1477 queue_delayed_work(cifsiod_wq, &tcp_ses->resolve, (SMB_DNS_RESOLVE_INTERVAL_DEFAULT * HZ));
1478
Jeff Layton63c038c2008-12-01 18:41:46 -05001479 return tcp_ses;
1480
Shirish Pargaonkarf7c5445a2010-10-26 18:10:24 -05001481out_err_crypto_release:
Pavel Shilovsky026e93d2016-11-03 16:47:37 -07001482 cifs_crypto_secmech_release(tcp_ses);
Shirish Pargaonkard2b91522010-10-21 14:25:08 -05001483
Rob Landleyf1d0c992011-01-22 15:44:05 -06001484 put_net(cifs_net_ns(tcp_ses));
1485
Jeff Layton63c038c2008-12-01 18:41:46 -05001486out_err:
1487 if (tcp_ses) {
Steve French8347a5c2009-10-06 18:31:29 +00001488 if (!IS_ERR(tcp_ses->hostname))
1489 kfree(tcp_ses->hostname);
Jeff Layton63c038c2008-12-01 18:41:46 -05001490 if (tcp_ses->ssocket)
1491 sock_release(tcp_ses->ssocket);
1492 kfree(tcp_ses);
1493 }
1494 return ERR_PTR(rc);
1495}
1496
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001497static int match_session(struct cifs_ses *ses, struct smb3_fs_context *ctx)
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00001498{
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001499 if (ctx->sectype != Unspecified &&
1500 ctx->sectype != ses->sectype)
Jeff Layton3f618222013-06-12 19:52:14 -05001501 return 0;
1502
Aurelien Aptelbcc88802019-09-20 04:32:20 +02001503 /*
1504 * If an existing session is limited to less channels than
1505 * requested, it should not be reused
1506 */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001507 if (ses->chan_max < ctx->max_channels)
Aurelien Aptelbcc88802019-09-20 04:32:20 +02001508 return 0;
1509
Jeff Layton3f618222013-06-12 19:52:14 -05001510 switch (ses->sectype) {
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00001511 case Kerberos:
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001512 if (!uid_eq(ctx->cred_uid, ses->cred_uid))
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00001513 return 0;
1514 break;
1515 default:
Jeff Layton04febab2012-01-17 16:09:15 -05001516 /* NULL username means anonymous session */
1517 if (ses->user_name == NULL) {
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001518 if (!ctx->nullauth)
Jeff Layton04febab2012-01-17 16:09:15 -05001519 return 0;
1520 break;
1521 }
1522
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00001523 /* anything else takes username/password */
Jeff Layton04febab2012-01-17 16:09:15 -05001524 if (strncmp(ses->user_name,
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001525 ctx->username ? ctx->username : "",
Scott Lovenberg8c3a2b42013-08-09 08:47:17 -04001526 CIFS_MAX_USERNAME_LEN))
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00001527 return 0;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001528 if ((ctx->username && strlen(ctx->username) != 0) &&
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00001529 ses->password != NULL &&
1530 strncmp(ses->password,
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001531 ctx->password ? ctx->password : "",
Scott Lovenberg8c3a2b42013-08-09 08:47:17 -04001532 CIFS_MAX_PASSWORD_LEN))
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00001533 return 0;
1534 }
1535 return 1;
1536}
1537
Aurelien Aptelb327a712018-01-24 13:46:10 +01001538/**
1539 * cifs_setup_ipc - helper to setup the IPC tcon for the session
1540 *
1541 * A new IPC connection is made and stored in the session
1542 * tcon_ipc. The IPC tcon has the same lifetime as the session.
1543 */
1544static int
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001545cifs_setup_ipc(struct cifs_ses *ses, struct smb3_fs_context *ctx)
Aurelien Aptelb327a712018-01-24 13:46:10 +01001546{
1547 int rc = 0, xid;
1548 struct cifs_tcon *tcon;
Aurelien Aptelb327a712018-01-24 13:46:10 +01001549 char unc[SERVER_NAME_LENGTH + sizeof("//x/IPC$")] = {0};
1550 bool seal = false;
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +10001551 struct TCP_Server_Info *server = ses->server;
Aurelien Aptelb327a712018-01-24 13:46:10 +01001552
1553 /*
1554 * If the mount request that resulted in the creation of the
1555 * session requires encryption, force IPC to be encrypted too.
1556 */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001557 if (ctx->seal) {
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +10001558 if (server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION)
Aurelien Aptelb327a712018-01-24 13:46:10 +01001559 seal = true;
1560 else {
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +10001561 cifs_server_dbg(VFS,
Aurelien Aptelb327a712018-01-24 13:46:10 +01001562 "IPC: server doesn't support encryption\n");
1563 return -EOPNOTSUPP;
1564 }
1565 }
1566
1567 tcon = tconInfoAlloc();
1568 if (tcon == NULL)
1569 return -ENOMEM;
1570
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +10001571 scnprintf(unc, sizeof(unc), "\\\\%s\\IPC$", server->hostname);
Aurelien Aptelb327a712018-01-24 13:46:10 +01001572
Aurelien Aptelb327a712018-01-24 13:46:10 +01001573 xid = get_xid();
1574 tcon->ses = ses;
1575 tcon->ipc = true;
1576 tcon->seal = seal;
Ronnie Sahlberg6fd4ea82020-12-14 16:40:21 +10001577 rc = server->ops->tree_connect(xid, ses, unc, tcon, ctx->local_nls);
Aurelien Aptelb327a712018-01-24 13:46:10 +01001578 free_xid(xid);
1579
1580 if (rc) {
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +10001581 cifs_server_dbg(VFS, "failed to connect to IPC (rc=%d)\n", rc);
Aurelien Aptelb327a712018-01-24 13:46:10 +01001582 tconInfoFree(tcon);
1583 goto out;
1584 }
1585
1586 cifs_dbg(FYI, "IPC tcon rc = %d ipc tid = %d\n", rc, tcon->tid);
1587
1588 ses->tcon_ipc = tcon;
1589out:
Aurelien Aptelb327a712018-01-24 13:46:10 +01001590 return rc;
1591}
1592
1593/**
1594 * cifs_free_ipc - helper to release the session IPC tcon
1595 *
Paulo Alcantaraf3191fc2021-06-04 19:25:27 -03001596 * Needs to be called everytime a session is destroyed.
1597 *
1598 * On session close, the IPC is closed and the server must release all tcons of the session.
1599 * No need to send a tree disconnect here.
1600 *
1601 * Besides, it will make the server to not close durable and resilient files on session close, as
1602 * specified in MS-SMB2 3.3.5.6 Receiving an SMB2 LOGOFF Request.
Aurelien Aptelb327a712018-01-24 13:46:10 +01001603 */
1604static int
1605cifs_free_ipc(struct cifs_ses *ses)
1606{
Aurelien Aptelb327a712018-01-24 13:46:10 +01001607 struct cifs_tcon *tcon = ses->tcon_ipc;
1608
1609 if (tcon == NULL)
1610 return 0;
1611
Aurelien Aptelb327a712018-01-24 13:46:10 +01001612 tconInfoFree(tcon);
1613 ses->tcon_ipc = NULL;
Paulo Alcantaraf3191fc2021-06-04 19:25:27 -03001614 return 0;
Aurelien Aptelb327a712018-01-24 13:46:10 +01001615}
1616
Steve French96daf2b2011-05-27 04:34:02 +00001617static struct cifs_ses *
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001618cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619{
Steve French96daf2b2011-05-27 04:34:02 +00001620 struct cifs_ses *ses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301622 spin_lock(&cifs_tcp_ses_lock);
Jeff Layton4ff67b72010-07-06 20:43:02 -04001623 list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
Shirish Pargaonkar7f485582013-10-12 10:06:03 -05001624 if (ses->status == CifsExiting)
1625 continue;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001626 if (!match_session(ses, ctx))
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00001627 continue;
Jeff Layton14fbf502008-11-14 13:53:46 -05001628 ++ses->ses_count;
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301629 spin_unlock(&cifs_tcp_ses_lock);
Jeff Layton14fbf502008-11-14 13:53:46 -05001630 return ses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301632 spin_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 return NULL;
1634}
1635
Paulo Alcantara (SUSE)50720102019-03-19 16:54:29 -03001636void cifs_put_smb_ses(struct cifs_ses *ses)
Jeff Layton14fbf502008-11-14 13:53:46 -05001637{
Shirish Pargaonkar7f485582013-10-12 10:06:03 -05001638 unsigned int rc, xid;
Jeff Layton14fbf502008-11-14 13:53:46 -05001639 struct TCP_Server_Info *server = ses->server;
Joe Perchesf96637b2013-05-04 22:12:25 -05001640 cifs_dbg(FYI, "%s: ses_count=%d\n", __func__, ses->ses_count);
Shirish Pargaonkar7f485582013-10-12 10:06:03 -05001641
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301642 spin_lock(&cifs_tcp_ses_lock);
Shirish Pargaonkar7f485582013-10-12 10:06:03 -05001643 if (ses->status == CifsExiting) {
1644 spin_unlock(&cifs_tcp_ses_lock);
1645 return;
1646 }
Paulo Alcantarac9f71102021-06-04 19:25:29 -03001647
1648 cifs_dbg(FYI, "%s: ses_count=%d\n", __func__, ses->ses_count);
1649 cifs_dbg(FYI, "%s: ses ipc: %s\n", __func__, ses->tcon_ipc ? ses->tcon_ipc->treeName : "NONE");
1650
Jeff Layton14fbf502008-11-14 13:53:46 -05001651 if (--ses->ses_count > 0) {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301652 spin_unlock(&cifs_tcp_ses_lock);
Jeff Layton14fbf502008-11-14 13:53:46 -05001653 return;
1654 }
Steve French0060a4f2021-06-24 15:28:04 -05001655 spin_unlock(&cifs_tcp_ses_lock);
1656
1657 spin_lock(&GlobalMid_Lock);
Shirish Pargaonkar7f485582013-10-12 10:06:03 -05001658 if (ses->status == CifsGood)
1659 ses->status = CifsExiting;
Steve French0060a4f2021-06-24 15:28:04 -05001660 spin_unlock(&GlobalMid_Lock);
Jeff Layton14fbf502008-11-14 13:53:46 -05001661
Aurelien Aptelb327a712018-01-24 13:46:10 +01001662 cifs_free_ipc(ses);
1663
Shirish Pargaonkar7f485582013-10-12 10:06:03 -05001664 if (ses->status == CifsExiting && server->ops->logoff) {
1665 xid = get_xid();
1666 rc = server->ops->logoff(xid, ses);
1667 if (rc)
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +10001668 cifs_server_dbg(VFS, "%s: Session Logoff failure rc=%d\n",
Shirish Pargaonkar7f485582013-10-12 10:06:03 -05001669 __func__, rc);
1670 _free_xid(xid);
1671 }
1672
1673 spin_lock(&cifs_tcp_ses_lock);
Jeff Layton14fbf502008-11-14 13:53:46 -05001674 list_del_init(&ses->smb_ses_list);
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301675 spin_unlock(&cifs_tcp_ses_lock);
Jeff Layton14fbf502008-11-14 13:53:46 -05001676
Aurelien Apteld70e9fa2019-09-20 06:31:10 +02001677 /* close any extra channels */
1678 if (ses->chan_count > 1) {
1679 int i;
1680
1681 for (i = 1; i < ses->chan_count; i++)
1682 cifs_put_tcp_session(ses->chans[i].server, 0);
1683 }
1684
Jeff Layton14fbf502008-11-14 13:53:46 -05001685 sesInfoFree(ses);
Pavel Shilovsky53e0e112016-11-04 11:50:31 -07001686 cifs_put_tcp_session(server, 0);
Jeff Layton14fbf502008-11-14 13:53:46 -05001687}
1688
Jeff Layton8a8798a2012-01-17 16:09:15 -05001689#ifdef CONFIG_KEYS
1690
Chen Gang057d6332013-07-19 09:01:36 +08001691/* strlen("cifs:a:") + CIFS_MAX_DOMAINNAME_LEN + 1 */
1692#define CIFSCREDS_DESC_SIZE (7 + CIFS_MAX_DOMAINNAME_LEN + 1)
Jeff Layton8a8798a2012-01-17 16:09:15 -05001693
1694/* Populate username and pw fields from keyring if possible */
1695static int
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001696cifs_set_cifscreds(struct smb3_fs_context *ctx, struct cifs_ses *ses)
Jeff Layton8a8798a2012-01-17 16:09:15 -05001697{
1698 int rc = 0;
Ronnie Sahlbergf2aee322019-08-22 08:09:50 +10001699 int is_domain = 0;
David Howells146aa8b2015-10-21 14:04:48 +01001700 const char *delim, *payload;
1701 char *desc;
Jeff Layton8a8798a2012-01-17 16:09:15 -05001702 ssize_t len;
1703 struct key *key;
1704 struct TCP_Server_Info *server = ses->server;
1705 struct sockaddr_in *sa;
1706 struct sockaddr_in6 *sa6;
David Howells146aa8b2015-10-21 14:04:48 +01001707 const struct user_key_payload *upayload;
Jeff Layton8a8798a2012-01-17 16:09:15 -05001708
1709 desc = kmalloc(CIFSCREDS_DESC_SIZE, GFP_KERNEL);
1710 if (!desc)
1711 return -ENOMEM;
1712
1713 /* try to find an address key first */
1714 switch (server->dstaddr.ss_family) {
1715 case AF_INET:
1716 sa = (struct sockaddr_in *)&server->dstaddr;
1717 sprintf(desc, "cifs:a:%pI4", &sa->sin_addr.s_addr);
1718 break;
1719 case AF_INET6:
1720 sa6 = (struct sockaddr_in6 *)&server->dstaddr;
1721 sprintf(desc, "cifs:a:%pI6c", &sa6->sin6_addr.s6_addr);
1722 break;
1723 default:
Joe Perchesf96637b2013-05-04 22:12:25 -05001724 cifs_dbg(FYI, "Bad ss_family (%hu)\n",
1725 server->dstaddr.ss_family);
Jeff Layton8a8798a2012-01-17 16:09:15 -05001726 rc = -EINVAL;
1727 goto out_err;
1728 }
1729
Joe Perchesf96637b2013-05-04 22:12:25 -05001730 cifs_dbg(FYI, "%s: desc=%s\n", __func__, desc);
Linus Torvalds028db3e2019-07-10 18:43:43 -07001731 key = request_key(&key_type_logon, desc, "");
Jeff Layton8a8798a2012-01-17 16:09:15 -05001732 if (IS_ERR(key)) {
1733 if (!ses->domainName) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001734 cifs_dbg(FYI, "domainName is NULL\n");
Jeff Layton8a8798a2012-01-17 16:09:15 -05001735 rc = PTR_ERR(key);
1736 goto out_err;
1737 }
1738
1739 /* didn't work, try to find a domain key */
1740 sprintf(desc, "cifs:d:%s", ses->domainName);
Joe Perchesf96637b2013-05-04 22:12:25 -05001741 cifs_dbg(FYI, "%s: desc=%s\n", __func__, desc);
Linus Torvalds028db3e2019-07-10 18:43:43 -07001742 key = request_key(&key_type_logon, desc, "");
Jeff Layton8a8798a2012-01-17 16:09:15 -05001743 if (IS_ERR(key)) {
1744 rc = PTR_ERR(key);
1745 goto out_err;
1746 }
Ronnie Sahlbergf2aee322019-08-22 08:09:50 +10001747 is_domain = 1;
Jeff Layton8a8798a2012-01-17 16:09:15 -05001748 }
1749
1750 down_read(&key->sem);
David Howells0837e492017-03-01 15:11:23 +00001751 upayload = user_key_payload_locked(key);
Jeff Layton8a8798a2012-01-17 16:09:15 -05001752 if (IS_ERR_OR_NULL(upayload)) {
Jeff Layton4edc53c2012-02-07 06:30:51 -05001753 rc = upayload ? PTR_ERR(upayload) : -EINVAL;
Jeff Layton8a8798a2012-01-17 16:09:15 -05001754 goto out_key_put;
1755 }
1756
1757 /* find first : in payload */
David Howells146aa8b2015-10-21 14:04:48 +01001758 payload = upayload->data;
Jeff Layton8a8798a2012-01-17 16:09:15 -05001759 delim = strnchr(payload, upayload->datalen, ':');
Joe Perchesf96637b2013-05-04 22:12:25 -05001760 cifs_dbg(FYI, "payload=%s\n", payload);
Jeff Layton8a8798a2012-01-17 16:09:15 -05001761 if (!delim) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001762 cifs_dbg(FYI, "Unable to find ':' in payload (datalen=%d)\n",
1763 upayload->datalen);
Jeff Layton8a8798a2012-01-17 16:09:15 -05001764 rc = -EINVAL;
1765 goto out_key_put;
1766 }
1767
1768 len = delim - payload;
Scott Lovenberg8c3a2b42013-08-09 08:47:17 -04001769 if (len > CIFS_MAX_USERNAME_LEN || len <= 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001770 cifs_dbg(FYI, "Bad value from username search (len=%zd)\n",
1771 len);
Jeff Layton8a8798a2012-01-17 16:09:15 -05001772 rc = -EINVAL;
1773 goto out_key_put;
1774 }
1775
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001776 ctx->username = kstrndup(payload, len, GFP_KERNEL);
1777 if (!ctx->username) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001778 cifs_dbg(FYI, "Unable to allocate %zd bytes for username\n",
1779 len);
Jeff Layton8a8798a2012-01-17 16:09:15 -05001780 rc = -ENOMEM;
1781 goto out_key_put;
1782 }
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001783 cifs_dbg(FYI, "%s: username=%s\n", __func__, ctx->username);
Jeff Layton8a8798a2012-01-17 16:09:15 -05001784
1785 len = key->datalen - (len + 1);
Scott Lovenberg8c3a2b42013-08-09 08:47:17 -04001786 if (len > CIFS_MAX_PASSWORD_LEN || len <= 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001787 cifs_dbg(FYI, "Bad len for password search (len=%zd)\n", len);
Jeff Layton8a8798a2012-01-17 16:09:15 -05001788 rc = -EINVAL;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001789 kfree(ctx->username);
1790 ctx->username = NULL;
Jeff Layton8a8798a2012-01-17 16:09:15 -05001791 goto out_key_put;
1792 }
1793
1794 ++delim;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001795 ctx->password = kstrndup(delim, len, GFP_KERNEL);
1796 if (!ctx->password) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001797 cifs_dbg(FYI, "Unable to allocate %zd bytes for password\n",
1798 len);
Jeff Layton8a8798a2012-01-17 16:09:15 -05001799 rc = -ENOMEM;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001800 kfree(ctx->username);
1801 ctx->username = NULL;
Jeff Layton8a8798a2012-01-17 16:09:15 -05001802 goto out_key_put;
1803 }
1804
Ronnie Sahlbergf2aee322019-08-22 08:09:50 +10001805 /*
1806 * If we have a domain key then we must set the domainName in the
1807 * for the request.
1808 */
1809 if (is_domain && ses->domainName) {
Al Viro8d767222021-03-05 15:02:34 -05001810 ctx->domainname = kstrdup(ses->domainName, GFP_KERNEL);
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001811 if (!ctx->domainname) {
Joe Perchesa0a30362020-04-14 22:42:53 -07001812 cifs_dbg(FYI, "Unable to allocate %zd bytes for domain\n",
1813 len);
Ronnie Sahlbergf2aee322019-08-22 08:09:50 +10001814 rc = -ENOMEM;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001815 kfree(ctx->username);
1816 ctx->username = NULL;
1817 kfree_sensitive(ctx->password);
1818 ctx->password = NULL;
Ronnie Sahlbergf2aee322019-08-22 08:09:50 +10001819 goto out_key_put;
1820 }
1821 }
1822
Jeff Layton8a8798a2012-01-17 16:09:15 -05001823out_key_put:
1824 up_read(&key->sem);
1825 key_put(key);
1826out_err:
1827 kfree(desc);
Joe Perchesf96637b2013-05-04 22:12:25 -05001828 cifs_dbg(FYI, "%s: returning %d\n", __func__, rc);
Jeff Layton8a8798a2012-01-17 16:09:15 -05001829 return rc;
1830}
1831#else /* ! CONFIG_KEYS */
1832static inline int
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001833cifs_set_cifscreds(struct smb3_fs_context *ctx __attribute__((unused)),
Jeff Layton8a8798a2012-01-17 16:09:15 -05001834 struct cifs_ses *ses __attribute__((unused)))
1835{
1836 return -ENOSYS;
1837}
1838#endif /* CONFIG_KEYS */
1839
Aurelien Aptel4a1360d2018-01-25 18:47:52 +01001840/**
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001841 * cifs_get_smb_ses - get a session matching @ctx data from @server
Aurelien Aptel4a1360d2018-01-25 18:47:52 +01001842 *
1843 * This function assumes it is being called from cifs_mount() where we
1844 * already got a server reference (server refcount +1). See
1845 * cifs_get_tcon() for refcount explanations.
1846 */
Paulo Alcantara (SUSE)50720102019-03-19 16:54:29 -03001847struct cifs_ses *
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001848cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
Jeff Layton36988c72010-04-24 07:57:43 -04001849{
Pavel Shilovsky286170a2012-05-25 10:43:58 +04001850 int rc = -ENOMEM;
1851 unsigned int xid;
Steve French96daf2b2011-05-27 04:34:02 +00001852 struct cifs_ses *ses;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03001853 struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr;
1854 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr;
Jeff Layton36988c72010-04-24 07:57:43 -04001855
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001856 xid = get_xid();
Jeff Layton36988c72010-04-24 07:57:43 -04001857
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001858 ses = cifs_find_smb_ses(server, ctx);
Jeff Layton36988c72010-04-24 07:57:43 -04001859 if (ses) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001860 cifs_dbg(FYI, "Existing smb sess found (status=%d)\n",
1861 ses->status);
Jeff Layton36988c72010-04-24 07:57:43 -04001862
Jeff Layton36988c72010-04-24 07:57:43 -04001863 mutex_lock(&ses->session_mutex);
Jeff Layton198b5682010-04-24 07:57:48 -04001864 rc = cifs_negotiate_protocol(xid, ses);
1865 if (rc) {
1866 mutex_unlock(&ses->session_mutex);
1867 /* problem -- put our ses reference */
1868 cifs_put_smb_ses(ses);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001869 free_xid(xid);
Jeff Layton198b5682010-04-24 07:57:48 -04001870 return ERR_PTR(rc);
1871 }
Jeff Layton36988c72010-04-24 07:57:43 -04001872 if (ses->need_reconnect) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001873 cifs_dbg(FYI, "Session needs reconnect\n");
Jeff Layton36988c72010-04-24 07:57:43 -04001874 rc = cifs_setup_session(xid, ses,
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001875 ctx->local_nls);
Jeff Layton36988c72010-04-24 07:57:43 -04001876 if (rc) {
1877 mutex_unlock(&ses->session_mutex);
1878 /* problem -- put our reference */
1879 cifs_put_smb_ses(ses);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001880 free_xid(xid);
Jeff Layton36988c72010-04-24 07:57:43 -04001881 return ERR_PTR(rc);
1882 }
1883 }
1884 mutex_unlock(&ses->session_mutex);
Jeff Layton460cf342010-09-14 11:38:24 -04001885
1886 /* existing SMB ses has a server reference already */
Pavel Shilovsky53e0e112016-11-04 11:50:31 -07001887 cifs_put_tcp_session(server, 0);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001888 free_xid(xid);
Jeff Layton36988c72010-04-24 07:57:43 -04001889 return ses;
1890 }
1891
Joe Perchesf96637b2013-05-04 22:12:25 -05001892 cifs_dbg(FYI, "Existing smb sess not found\n");
Jeff Layton36988c72010-04-24 07:57:43 -04001893 ses = sesInfoAlloc();
1894 if (ses == NULL)
1895 goto get_ses_fail;
1896
1897 /* new SMB session uses our server ref */
1898 ses->server = server;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03001899 if (server->dstaddr.ss_family == AF_INET6)
Steve Frenchb438fcf2021-02-20 19:24:11 -06001900 sprintf(ses->ip_addr, "%pI6", &addr6->sin6_addr);
Jeff Layton36988c72010-04-24 07:57:43 -04001901 else
Steve Frenchb438fcf2021-02-20 19:24:11 -06001902 sprintf(ses->ip_addr, "%pI4", &addr->sin_addr);
Jeff Layton36988c72010-04-24 07:57:43 -04001903
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001904 if (ctx->username) {
1905 ses->user_name = kstrdup(ctx->username, GFP_KERNEL);
Steve French8727c8a2011-02-25 01:11:56 -06001906 if (!ses->user_name)
1907 goto get_ses_fail;
1908 }
Jeff Layton36988c72010-04-24 07:57:43 -04001909
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001910 /* ctx->password freed at unmount */
1911 if (ctx->password) {
1912 ses->password = kstrdup(ctx->password, GFP_KERNEL);
Jeff Layton36988c72010-04-24 07:57:43 -04001913 if (!ses->password)
1914 goto get_ses_fail;
1915 }
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001916 if (ctx->domainname) {
1917 ses->domainName = kstrdup(ctx->domainname, GFP_KERNEL);
Shirish Pargaonkard3686d52010-10-28 09:53:07 -05001918 if (!ses->domainName)
1919 goto get_ses_fail;
Jeff Layton36988c72010-04-24 07:57:43 -04001920 }
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001921 if (ctx->domainauto)
1922 ses->domainAuto = ctx->domainauto;
1923 ses->cred_uid = ctx->cred_uid;
1924 ses->linux_uid = ctx->linux_uid;
Steve Frenchd9b94202011-04-12 01:24:57 +00001925
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001926 ses->sectype = ctx->sectype;
1927 ses->sign = ctx->sign;
Jeff Layton36988c72010-04-24 07:57:43 -04001928 mutex_lock(&ses->session_mutex);
Aurelien Apteld70e9fa2019-09-20 06:31:10 +02001929
1930 /* add server as first channel */
1931 ses->chans[0].server = server;
1932 ses->chan_count = 1;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001933 ses->chan_max = ctx->multichannel ? ctx->max_channels:1;
Aurelien Apteld70e9fa2019-09-20 06:31:10 +02001934
Jeff Layton198b5682010-04-24 07:57:48 -04001935 rc = cifs_negotiate_protocol(xid, ses);
1936 if (!rc)
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001937 rc = cifs_setup_session(xid, ses, ctx->local_nls);
Aurelien Apteld70e9fa2019-09-20 06:31:10 +02001938
1939 /* each channel uses a different signing key */
1940 memcpy(ses->chans[0].signkey, ses->smb3signingkey,
1941 sizeof(ses->smb3signingkey));
1942
Jeff Layton36988c72010-04-24 07:57:43 -04001943 mutex_unlock(&ses->session_mutex);
Steve Frenchc8e56f12010-09-08 21:10:58 +00001944 if (rc)
Jeff Layton36988c72010-04-24 07:57:43 -04001945 goto get_ses_fail;
1946
Aurelien Apteld70e9fa2019-09-20 06:31:10 +02001947 /* success, put it on the list and add it as first channel */
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301948 spin_lock(&cifs_tcp_ses_lock);
Jeff Layton36988c72010-04-24 07:57:43 -04001949 list_add(&ses->smb_ses_list, &server->smb_ses_list);
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301950 spin_unlock(&cifs_tcp_ses_lock);
Jeff Layton36988c72010-04-24 07:57:43 -04001951
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001952 free_xid(xid);
Aurelien Aptelb327a712018-01-24 13:46:10 +01001953
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001954 cifs_setup_ipc(ses, ctx);
Aurelien Aptelb327a712018-01-24 13:46:10 +01001955
Jeff Layton36988c72010-04-24 07:57:43 -04001956 return ses;
1957
1958get_ses_fail:
1959 sesInfoFree(ses);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001960 free_xid(xid);
Jeff Layton36988c72010-04-24 07:57:43 -04001961 return ERR_PTR(rc);
1962}
1963
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001964static int match_tcon(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00001965{
1966 if (tcon->tidStatus == CifsExiting)
1967 return 0;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001968 if (strncmp(tcon->treeName, ctx->UNC, MAX_TREE_SIZE))
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00001969 return 0;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001970 if (tcon->seal != ctx->seal)
Pavel Shilovskyae6f8dd2016-11-17 13:59:23 -08001971 return 0;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001972 if (tcon->snapshot_time != ctx->snapshot_time)
Pavel Shilovskyae6f8dd2016-11-17 13:59:23 -08001973 return 0;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001974 if (tcon->handle_timeout != ctx->handle_timeout)
Steve Frenchca567eb2019-03-29 16:31:07 -05001975 return 0;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001976 if (tcon->no_lease != ctx->no_lease)
Steve French3e7a02d2019-09-11 21:46:20 -05001977 return 0;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001978 if (tcon->nodelete != ctx->nodelete)
Steve French82e93672020-05-19 03:06:57 -05001979 return 0;
Pavel Shilovsky37bb04e2011-05-05 09:55:11 +00001980 return 1;
1981}
1982
Steve French96daf2b2011-05-27 04:34:02 +00001983static struct cifs_tcon *
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001984cifs_find_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985{
1986 struct list_head *tmp;
Steve French96daf2b2011-05-27 04:34:02 +00001987 struct cifs_tcon *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301989 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytonf1987b42008-11-15 11:12:47 -05001990 list_for_each(tmp, &ses->tcon_list) {
Steve French96daf2b2011-05-27 04:34:02 +00001991 tcon = list_entry(tmp, struct cifs_tcon, tcon_list);
Paulo Alcantaraf3c852b2021-06-04 19:25:33 -03001992
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06001993 if (!match_tcon(tcon, ctx))
Jeff Laytonf1987b42008-11-15 11:12:47 -05001994 continue;
Jeff Laytonf1987b42008-11-15 11:12:47 -05001995 ++tcon->tc_count;
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301996 spin_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 return tcon;
1998 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05301999 spin_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 return NULL;
2001}
2002
Pavel Shilovsky53e0e112016-11-04 11:50:31 -07002003void
Steve French96daf2b2011-05-27 04:34:02 +00002004cifs_put_tcon(struct cifs_tcon *tcon)
Jeff Laytonf1987b42008-11-15 11:12:47 -05002005{
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +04002006 unsigned int xid;
Aurelien Aptelb327a712018-01-24 13:46:10 +01002007 struct cifs_ses *ses;
Jeff Laytonf1987b42008-11-15 11:12:47 -05002008
Aurelien Aptelb327a712018-01-24 13:46:10 +01002009 /*
2010 * IPC tcon share the lifetime of their session and are
2011 * destroyed in the session put function
2012 */
2013 if (tcon == NULL || tcon->ipc)
2014 return;
2015
2016 ses = tcon->ses;
Joe Perchesf96637b2013-05-04 22:12:25 -05002017 cifs_dbg(FYI, "%s: tc_count=%d\n", __func__, tcon->tc_count);
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05302018 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytonf1987b42008-11-15 11:12:47 -05002019 if (--tcon->tc_count > 0) {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05302020 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytonf1987b42008-11-15 11:12:47 -05002021 return;
2022 }
2023
Samuel Cabrerobf80e5d2020-11-30 19:02:51 +01002024 if (tcon->use_witness) {
2025 int rc;
2026
2027 rc = cifs_swn_unregister(tcon);
2028 if (rc < 0) {
2029 cifs_dbg(VFS, "%s: Failed to unregister for witness notifications: %d\n",
2030 __func__, rc);
2031 }
2032 }
Samuel Cabrero0ac4e292020-12-11 22:59:29 -06002033
Jeff Laytonf1987b42008-11-15 11:12:47 -05002034 list_del_init(&tcon->tcon_list);
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05302035 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytonf1987b42008-11-15 11:12:47 -05002036
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002037 xid = get_xid();
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +04002038 if (ses->server->ops->tree_disconnect)
2039 ses->server->ops->tree_disconnect(xid, tcon);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002040 _free_xid(xid);
Jeff Laytonf1987b42008-11-15 11:12:47 -05002041
Suresh Jayaramand03382c2010-07-05 18:12:27 +05302042 cifs_fscache_release_super_cookie(tcon);
Steve French9f841592010-07-23 20:37:53 +00002043 tconInfoFree(tcon);
Jeff Laytonf1987b42008-11-15 11:12:47 -05002044 cifs_put_smb_ses(ses);
2045}
2046
Aurelien Aptel4a1360d2018-01-25 18:47:52 +01002047/**
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002048 * cifs_get_tcon - get a tcon matching @ctx data from @ses
Aurelien Aptel4a1360d2018-01-25 18:47:52 +01002049 *
2050 * - tcon refcount is the number of mount points using the tcon.
2051 * - ses refcount is the number of tcon using the session.
2052 *
2053 * 1. This function assumes it is being called from cifs_mount() where
2054 * we already got a session reference (ses refcount +1).
2055 *
2056 * 2. Since we're in the context of adding a mount point, the end
2057 * result should be either:
2058 *
2059 * a) a new tcon already allocated with refcount=1 (1 mount point) and
2060 * its session refcount incremented (1 new tcon). This +1 was
2061 * already done in (1).
2062 *
2063 * b) an existing tcon with refcount+1 (add a mount point to it) and
2064 * identical ses refcount (no new tcon). Because of (1) we need to
2065 * decrement the ses refcount.
2066 */
Steve French96daf2b2011-05-27 04:34:02 +00002067static struct cifs_tcon *
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002068cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx)
Jeff Laytond00c28d2010-04-24 07:57:44 -04002069{
2070 int rc, xid;
Steve French96daf2b2011-05-27 04:34:02 +00002071 struct cifs_tcon *tcon;
Jeff Laytond00c28d2010-04-24 07:57:44 -04002072
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002073 tcon = cifs_find_tcon(ses, ctx);
Jeff Laytond00c28d2010-04-24 07:57:44 -04002074 if (tcon) {
Aurelien Aptel4a1360d2018-01-25 18:47:52 +01002075 /*
2076 * tcon has refcount already incremented but we need to
2077 * decrement extra ses reference gotten by caller (case b)
2078 */
Joe Perchesf96637b2013-05-04 22:12:25 -05002079 cifs_dbg(FYI, "Found match on UNC path\n");
Jeff Laytond00c28d2010-04-24 07:57:44 -04002080 cifs_put_smb_ses(ses);
Jeff Laytond00c28d2010-04-24 07:57:44 -04002081 return tcon;
2082 }
2083
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +04002084 if (!ses->server->ops->tree_connect) {
2085 rc = -ENOSYS;
2086 goto out_fail;
2087 }
2088
Jeff Laytond00c28d2010-04-24 07:57:44 -04002089 tcon = tconInfoAlloc();
2090 if (tcon == NULL) {
2091 rc = -ENOMEM;
2092 goto out_fail;
2093 }
2094
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002095 if (ctx->snapshot_time) {
Steve French8b217fe2016-11-11 22:36:20 -06002096 if (ses->server->vals->protocol_id == 0) {
2097 cifs_dbg(VFS,
2098 "Use SMB2 or later for snapshot mount option\n");
2099 rc = -EOPNOTSUPP;
2100 goto out_fail;
2101 } else
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002102 tcon->snapshot_time = ctx->snapshot_time;
Steve French8b217fe2016-11-11 22:36:20 -06002103 }
2104
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002105 if (ctx->handle_timeout) {
Steve Frenchca567eb2019-03-29 16:31:07 -05002106 if (ses->server->vals->protocol_id == 0) {
2107 cifs_dbg(VFS,
2108 "Use SMB2.1 or later for handle timeout option\n");
2109 rc = -EOPNOTSUPP;
2110 goto out_fail;
2111 } else
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002112 tcon->handle_timeout = ctx->handle_timeout;
Steve Frenchca567eb2019-03-29 16:31:07 -05002113 }
2114
Jeff Laytond00c28d2010-04-24 07:57:44 -04002115 tcon->ses = ses;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002116 if (ctx->password) {
2117 tcon->password = kstrdup(ctx->password, GFP_KERNEL);
Jeff Laytond00c28d2010-04-24 07:57:44 -04002118 if (!tcon->password) {
2119 rc = -ENOMEM;
2120 goto out_fail;
2121 }
2122 }
2123
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002124 if (ctx->seal) {
Steve French23657ad2018-04-22 15:14:58 -05002125 if (ses->server->vals->protocol_id == 0) {
2126 cifs_dbg(VFS,
2127 "SMB3 or later required for encryption\n");
2128 rc = -EOPNOTSUPP;
2129 goto out_fail;
2130 } else if (tcon->ses->server->capabilities &
2131 SMB2_GLOBAL_CAP_ENCRYPTION)
2132 tcon->seal = true;
2133 else {
2134 cifs_dbg(VFS, "Encryption is not supported on share\n");
2135 rc = -EOPNOTSUPP;
2136 goto out_fail;
2137 }
2138 }
2139
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002140 if (ctx->linux_ext) {
Steve French8505c8b2018-06-18 14:01:59 -05002141 if (ses->server->posix_ext_supported) {
Steve Frenchb3266142018-05-20 23:41:10 -05002142 tcon->posix_extensions = true;
Joe Perchesa0a30362020-04-14 22:42:53 -07002143 pr_warn_once("SMB3.11 POSIX Extensions are experimental\n");
Steve French8505c8b2018-06-18 14:01:59 -05002144 } else {
Joe Perchesa0a30362020-04-14 22:42:53 -07002145 cifs_dbg(VFS, "Server does not support mounting with posix SMB3.11 extensions\n");
Steve French8505c8b2018-06-18 14:01:59 -05002146 rc = -EOPNOTSUPP;
2147 goto out_fail;
Steve French2fbb5642018-06-12 12:11:31 -05002148 }
Steve Frenchb3266142018-05-20 23:41:10 -05002149 }
Steve Frenchb3266142018-05-20 23:41:10 -05002150
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +04002151 /*
2152 * BB Do we need to wrap session_mutex around this TCon call and Unix
2153 * SetFS as we do on SessSetup and reconnect?
2154 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002155 xid = get_xid();
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002156 rc = ses->server->ops->tree_connect(xid, ses, ctx->UNC, tcon,
2157 ctx->local_nls);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002158 free_xid(xid);
Joe Perchesf96637b2013-05-04 22:12:25 -05002159 cifs_dbg(FYI, "Tcon rc = %d\n", rc);
Jeff Laytond00c28d2010-04-24 07:57:44 -04002160 if (rc)
2161 goto out_fail;
2162
Steve Frenchb618f002015-11-03 09:15:03 -06002163 tcon->use_persistent = false;
2164 /* check if SMB2 or later, CIFS does not support persistent handles */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002165 if (ctx->persistent) {
Steve Frenchb618f002015-11-03 09:15:03 -06002166 if (ses->server->vals->protocol_id == 0) {
2167 cifs_dbg(VFS,
2168 "SMB3 or later required for persistent handles\n");
2169 rc = -EOPNOTSUPP;
2170 goto out_fail;
2171 } else if (ses->server->capabilities &
2172 SMB2_GLOBAL_CAP_PERSISTENT_HANDLES)
2173 tcon->use_persistent = true;
2174 else /* persistent handles requested but not supported */ {
2175 cifs_dbg(VFS,
2176 "Persistent handles not supported on share\n");
2177 rc = -EOPNOTSUPP;
2178 goto out_fail;
2179 }
2180 } else if ((tcon->capabilities & SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY)
2181 && (ses->server->capabilities & SMB2_GLOBAL_CAP_PERSISTENT_HANDLES)
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002182 && (ctx->nopersistent == false)) {
Steve Frenchb618f002015-11-03 09:15:03 -06002183 cifs_dbg(FYI, "enabling persistent handles\n");
2184 tcon->use_persistent = true;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002185 } else if (ctx->resilient) {
Steve French592fafe2015-11-03 10:08:53 -06002186 if (ses->server->vals->protocol_id == 0) {
2187 cifs_dbg(VFS,
2188 "SMB2.1 or later required for resilient handles\n");
2189 rc = -EOPNOTSUPP;
2190 goto out_fail;
2191 }
2192 tcon->use_resilient = true;
Steve Frenchb618f002015-11-03 09:15:03 -06002193 }
Aurelien Aptelb7fd0fa2021-04-09 16:31:37 +02002194
Samuel Cabrero0ac4e292020-12-11 22:59:29 -06002195 tcon->use_witness = false;
Aurelien Aptelb7fd0fa2021-04-09 16:31:37 +02002196 if (IS_ENABLED(CONFIG_CIFS_SWN_UPCALL) && ctx->witness) {
Samuel Cabrero0ac4e292020-12-11 22:59:29 -06002197 if (ses->server->vals->protocol_id >= SMB30_PROT_ID) {
2198 if (tcon->capabilities & SMB2_SHARE_CAP_CLUSTER) {
Samuel Cabrerobf80e5d2020-11-30 19:02:51 +01002199 /*
2200 * Set witness in use flag in first place
2201 * to retry registration in the echo task
2202 */
Samuel Cabrero0ac4e292020-12-11 22:59:29 -06002203 tcon->use_witness = true;
Samuel Cabrerobf80e5d2020-11-30 19:02:51 +01002204 /* And try to register immediately */
2205 rc = cifs_swn_register(tcon);
2206 if (rc < 0) {
2207 cifs_dbg(VFS, "Failed to register for witness notifications: %d\n", rc);
2208 goto out_fail;
2209 }
Samuel Cabrero0ac4e292020-12-11 22:59:29 -06002210 } else {
2211 /* TODO: try to extend for non-cluster uses (eg multichannel) */
2212 cifs_dbg(VFS, "witness requested on mount but no CLUSTER capability on share\n");
2213 rc = -EOPNOTSUPP;
2214 goto out_fail;
2215 }
2216 } else {
2217 cifs_dbg(VFS, "SMB3 or later required for witness option\n");
2218 rc = -EOPNOTSUPP;
2219 goto out_fail;
2220 }
2221 }
Steve Frenchb618f002015-11-03 09:15:03 -06002222
Steve Frenchcae53f72019-09-03 17:49:46 -05002223 /* If the user really knows what they are doing they can override */
2224 if (tcon->share_flags & SMB2_SHAREFLAG_NO_CACHING) {
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002225 if (ctx->cache_ro)
Steve Frenchcae53f72019-09-03 17:49:46 -05002226 cifs_dbg(VFS, "cache=ro requested on mount but NO_CACHING flag set on share\n");
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002227 else if (ctx->cache_rw)
Steve Frenchcae53f72019-09-03 17:49:46 -05002228 cifs_dbg(VFS, "cache=singleclient requested on mount but NO_CACHING flag set on share\n");
2229 }
2230
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002231 if (ctx->no_lease) {
Kenneth D'souza8fd6e1d2020-05-18 13:01:34 +05302232 if (ses->server->vals->protocol_id == 0) {
2233 cifs_dbg(VFS,
2234 "SMB2 or later required for nolease option\n");
2235 rc = -EOPNOTSUPP;
2236 goto out_fail;
2237 } else
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002238 tcon->no_lease = ctx->no_lease;
Kenneth D'souza8fd6e1d2020-05-18 13:01:34 +05302239 }
2240
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +04002241 /*
2242 * We can have only one retry value for a connection to a share so for
2243 * resources mounted more than once to the same server share the last
2244 * value passed in for the retry flag is used.
2245 */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002246 tcon->retry = ctx->retry;
2247 tcon->nocase = ctx->nocase;
Steve French3c6e65e2020-10-21 00:15:42 -05002248 if (ses->server->capabilities & SMB2_GLOBAL_CAP_DIRECTORY_LEASING)
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002249 tcon->nohandlecache = ctx->nohandlecache;
Steve French3c6e65e2020-10-21 00:15:42 -05002250 else
Jiapeng Zhong2be449f2021-01-14 17:09:20 +08002251 tcon->nohandlecache = true;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002252 tcon->nodelete = ctx->nodelete;
2253 tcon->local_lease = ctx->local_lease;
Pavel Shilovsky233839b2012-09-19 06:22:45 -07002254 INIT_LIST_HEAD(&tcon->pending_opens);
Jeff Laytond00c28d2010-04-24 07:57:44 -04002255
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05302256 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytond00c28d2010-04-24 07:57:44 -04002257 list_add(&tcon->tcon_list, &ses->tcon_list);
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05302258 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytond00c28d2010-04-24 07:57:44 -04002259
Suresh Jayaramand03382c2010-07-05 18:12:27 +05302260 cifs_fscache_get_super_cookie(tcon);
2261
Jeff Laytond00c28d2010-04-24 07:57:44 -04002262 return tcon;
2263
2264out_fail:
2265 tconInfoFree(tcon);
2266 return ERR_PTR(rc);
2267}
2268
Jeff Layton9d002df2010-10-06 19:51:11 -04002269void
2270cifs_put_tlink(struct tcon_link *tlink)
2271{
2272 if (!tlink || IS_ERR(tlink))
2273 return;
2274
2275 if (!atomic_dec_and_test(&tlink->tl_count) ||
2276 test_bit(TCON_LINK_IN_TREE, &tlink->tl_flags)) {
2277 tlink->tl_time = jiffies;
2278 return;
2279 }
2280
2281 if (!IS_ERR(tlink_tcon(tlink)))
2282 cifs_put_tcon(tlink_tcon(tlink));
2283 kfree(tlink);
2284 return;
2285}
Jeff Laytond00c28d2010-04-24 07:57:44 -04002286
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002287static int
2288compare_mount_options(struct super_block *sb, struct cifs_mnt_data *mnt_data)
2289{
2290 struct cifs_sb_info *old = CIFS_SB(sb);
2291 struct cifs_sb_info *new = mnt_data->cifs_sb;
Paulo Alcantara (SUSE)29fbeb72019-06-18 16:16:02 -03002292 unsigned int oldflags = old->mnt_cifs_flags & CIFS_MOUNT_MASK;
2293 unsigned int newflags = new->mnt_cifs_flags & CIFS_MOUNT_MASK;
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002294
2295 if ((sb->s_flags & CIFS_MS_MASK) != (mnt_data->flags & CIFS_MS_MASK))
2296 return 0;
2297
Paulo Alcantara (SUSE)29fbeb72019-06-18 16:16:02 -03002298 if (old->mnt_cifs_serverino_autodisabled)
2299 newflags &= ~CIFS_MOUNT_SERVER_INUM;
2300
2301 if (oldflags != newflags)
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002302 return 0;
2303
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002304 /*
Jeff Layton5eba8ab2011-10-19 15:30:26 -04002305 * We want to share sb only if we don't specify an r/wsize or
2306 * specified r/wsize is greater than or equal to existing one.
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002307 */
Ronnie Sahlberg522aa3b2020-12-14 16:40:17 +10002308 if (new->ctx->wsize && new->ctx->wsize < old->ctx->wsize)
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002309 return 0;
2310
Ronnie Sahlberg522aa3b2020-12-14 16:40:17 +10002311 if (new->ctx->rsize && new->ctx->rsize < old->ctx->rsize)
Jeff Layton5eba8ab2011-10-19 15:30:26 -04002312 return 0;
2313
Ronnie Sahlberg8401e932020-12-12 13:40:50 -06002314 if (!uid_eq(old->ctx->linux_uid, new->ctx->linux_uid) ||
2315 !gid_eq(old->ctx->linux_gid, new->ctx->linux_gid))
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002316 return 0;
2317
Ronnie Sahlberg8401e932020-12-12 13:40:50 -06002318 if (old->ctx->file_mode != new->ctx->file_mode ||
2319 old->ctx->dir_mode != new->ctx->dir_mode)
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002320 return 0;
2321
2322 if (strcmp(old->local_nls->charset, new->local_nls->charset))
2323 return 0;
2324
Steve French57804642021-02-24 12:12:53 -06002325 if (old->ctx->acregmax != new->ctx->acregmax)
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002326 return 0;
Steve French4c9f9482021-02-23 15:50:57 -06002327 if (old->ctx->acdirmax != new->ctx->acdirmax)
2328 return 0;
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002329
2330 return 1;
2331}
2332
Sachin Prabhuc1d8b242016-07-29 22:38:20 +01002333static int
2334match_prepath(struct super_block *sb, struct cifs_mnt_data *mnt_data)
2335{
2336 struct cifs_sb_info *old = CIFS_SB(sb);
2337 struct cifs_sb_info *new = mnt_data->cifs_sb;
Ronnie Sahlbergfe129262020-01-22 11:07:56 +10002338 bool old_set = (old->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) &&
2339 old->prepath;
2340 bool new_set = (new->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) &&
2341 new->prepath;
Sachin Prabhuc1d8b242016-07-29 22:38:20 +01002342
Sachin Prabhucd8c4292017-04-26 14:05:46 +01002343 if (old_set && new_set && !strcmp(new->prepath, old->prepath))
Sachin Prabhuc1d8b242016-07-29 22:38:20 +01002344 return 1;
Sachin Prabhucd8c4292017-04-26 14:05:46 +01002345 else if (!old_set && !new_set)
2346 return 1;
2347
Sachin Prabhuc1d8b242016-07-29 22:38:20 +01002348 return 0;
2349}
2350
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002351int
2352cifs_match_super(struct super_block *sb, void *data)
2353{
2354 struct cifs_mnt_data *mnt_data = (struct cifs_mnt_data *)data;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002355 struct smb3_fs_context *ctx;
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002356 struct cifs_sb_info *cifs_sb;
2357 struct TCP_Server_Info *tcp_srv;
Steve French96daf2b2011-05-27 04:34:02 +00002358 struct cifs_ses *ses;
2359 struct cifs_tcon *tcon;
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002360 struct tcon_link *tlink;
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002361 int rc = 0;
2362
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002363 spin_lock(&cifs_tcp_ses_lock);
2364 cifs_sb = CIFS_SB(sb);
2365 tlink = cifs_get_tlink(cifs_sb_master_tlink(cifs_sb));
2366 if (IS_ERR(tlink)) {
2367 spin_unlock(&cifs_tcp_ses_lock);
2368 return rc;
2369 }
2370 tcon = tlink_tcon(tlink);
2371 ses = tcon->ses;
2372 tcp_srv = ses->server;
2373
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002374 ctx = mnt_data->ctx;
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002375
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002376 if (!match_server(tcp_srv, ctx) ||
2377 !match_session(ses, ctx) ||
2378 !match_tcon(tcon, ctx) ||
Sachin Prabhuc1d8b242016-07-29 22:38:20 +01002379 !match_prepath(sb, mnt_data)) {
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002380 rc = 0;
2381 goto out;
2382 }
2383
2384 rc = compare_mount_options(sb, mnt_data);
2385out:
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002386 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytonf484b5d02011-07-11 10:16:34 -04002387 cifs_put_tlink(tlink);
Pavel Shilovsky25c7f412011-05-26 23:35:47 +04002388 return rc;
2389}
2390
Jeff Layton09e50d52008-07-23 10:11:19 -04002391#ifdef CONFIG_DEBUG_LOCK_ALLOC
2392static struct lock_class_key cifs_key[2];
2393static struct lock_class_key cifs_slock_key[2];
2394
2395static inline void
2396cifs_reclassify_socket4(struct socket *sock)
2397{
2398 struct sock *sk = sock->sk;
Hannes Frederic Sowafafc4e12016-04-08 15:11:27 +02002399 BUG_ON(!sock_allow_reclassification(sk));
Jeff Layton09e50d52008-07-23 10:11:19 -04002400 sock_lock_init_class_and_name(sk, "slock-AF_INET-CIFS",
2401 &cifs_slock_key[0], "sk_lock-AF_INET-CIFS", &cifs_key[0]);
2402}
2403
2404static inline void
2405cifs_reclassify_socket6(struct socket *sock)
2406{
2407 struct sock *sk = sock->sk;
Hannes Frederic Sowafafc4e12016-04-08 15:11:27 +02002408 BUG_ON(!sock_allow_reclassification(sk));
Jeff Layton09e50d52008-07-23 10:11:19 -04002409 sock_lock_init_class_and_name(sk, "slock-AF_INET6-CIFS",
2410 &cifs_slock_key[1], "sk_lock-AF_INET6-CIFS", &cifs_key[1]);
2411}
2412#else
2413static inline void
2414cifs_reclassify_socket4(struct socket *sock)
2415{
2416}
2417
2418static inline void
2419cifs_reclassify_socket6(struct socket *sock)
2420{
2421}
2422#endif
2423
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424/* See RFC1001 section 14 on representation of Netbios names */
Steve French50c2f752007-07-13 00:33:32 +00002425static void rfc1002mangle(char *target, char *source, unsigned int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426{
Steve French50c2f752007-07-13 00:33:32 +00002427 unsigned int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428
Steve French50c2f752007-07-13 00:33:32 +00002429 for (i = 0, j = 0; i < (length); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430 /* mask a nibble at a time and encode */
2431 target[j] = 'A' + (0x0F & (source[i] >> 4));
2432 target[j+1] = 'A' + (0x0F & source[i]);
Steve French50c2f752007-07-13 00:33:32 +00002433 j += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434 }
2435
2436}
2437
Ben Greear3eb9a882010-09-01 17:06:02 -07002438static int
2439bind_socket(struct TCP_Server_Info *server)
2440{
2441 int rc = 0;
2442 if (server->srcaddr.ss_family != AF_UNSPEC) {
2443 /* Bind to the specified local IP address */
2444 struct socket *socket = server->ssocket;
2445 rc = socket->ops->bind(socket,
2446 (struct sockaddr *) &server->srcaddr,
2447 sizeof(server->srcaddr));
2448 if (rc < 0) {
2449 struct sockaddr_in *saddr4;
2450 struct sockaddr_in6 *saddr6;
2451 saddr4 = (struct sockaddr_in *)&server->srcaddr;
2452 saddr6 = (struct sockaddr_in6 *)&server->srcaddr;
2453 if (saddr6->sin6_family == AF_INET6)
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +10002454 cifs_server_dbg(VFS, "Failed to bind to: %pI6c, error: %d\n",
Joe Perchesf96637b2013-05-04 22:12:25 -05002455 &saddr6->sin6_addr, rc);
Ben Greear3eb9a882010-09-01 17:06:02 -07002456 else
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +10002457 cifs_server_dbg(VFS, "Failed to bind to: %pI4, error: %d\n",
Joe Perchesf96637b2013-05-04 22:12:25 -05002458 &saddr4->sin_addr.s_addr, rc);
Ben Greear3eb9a882010-09-01 17:06:02 -07002459 }
2460 }
2461 return rc;
2462}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463
2464static int
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002465ip_rfc1001_connect(struct TCP_Server_Info *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466{
2467 int rc = 0;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002468 /*
2469 * some servers require RFC1001 sessinit before sending
2470 * negprot - BB check reconnection in case where second
2471 * sessinit is sent but no second negprot
2472 */
2473 struct rfc1002_session_packet *ses_init_buf;
2474 struct smb_hdr *smb_buf;
2475 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
2476 GFP_KERNEL);
2477 if (ses_init_buf) {
2478 ses_init_buf->trailer.session_req.called_len = 32;
2479
Colin Ian King997152f2016-01-25 16:25:54 +00002480 if (server->server_RFC1001_name[0] != 0)
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002481 rfc1002mangle(ses_init_buf->trailer.
2482 session_req.called_name,
2483 server->server_RFC1001_name,
2484 RFC1001_NAME_LEN_WITH_NULL);
2485 else
2486 rfc1002mangle(ses_init_buf->trailer.
2487 session_req.called_name,
2488 DEFAULT_CIFS_CALLED_NAME,
2489 RFC1001_NAME_LEN_WITH_NULL);
2490
2491 ses_init_buf->trailer.session_req.calling_len = 32;
2492
2493 /*
2494 * calling name ends in null (byte 16) from old smb
2495 * convention.
2496 */
Steve Frenchc85c35f2015-03-27 01:15:02 -05002497 if (server->workstation_RFC1001_name[0] != 0)
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002498 rfc1002mangle(ses_init_buf->trailer.
2499 session_req.calling_name,
2500 server->workstation_RFC1001_name,
2501 RFC1001_NAME_LEN_WITH_NULL);
2502 else
2503 rfc1002mangle(ses_init_buf->trailer.
2504 session_req.calling_name,
2505 "LINUX_CIFS_CLNT",
2506 RFC1001_NAME_LEN_WITH_NULL);
2507
2508 ses_init_buf->trailer.session_req.scope1 = 0;
2509 ses_init_buf->trailer.session_req.scope2 = 0;
2510 smb_buf = (struct smb_hdr *)ses_init_buf;
2511
2512 /* sizeof RFC1002_SESSION_REQUEST with no scope */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002513 smb_buf->smb_buf_length = cpu_to_be32(0x81000044);
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002514 rc = smb_send(server, smb_buf, 0x44);
2515 kfree(ses_init_buf);
2516 /*
2517 * RFC1001 layer in at least one server
2518 * requires very short break before negprot
2519 * presumably because not expecting negprot
2520 * to follow so fast. This is a simple
2521 * solution that works without
2522 * complicating the code and causes no
2523 * significant slowing down on mount
2524 * for everyone else
2525 */
2526 usleep_range(1000, 2000);
2527 }
2528 /*
2529 * else the negprot may still work without this
2530 * even though malloc failed
2531 */
2532
2533 return rc;
2534}
2535
2536static int
2537generic_ip_connect(struct TCP_Server_Info *server)
2538{
2539 int rc = 0;
Steve French6da97912011-03-13 18:55:55 +00002540 __be16 sport;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002541 int slen, sfamily;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002542 struct socket *socket = server->ssocket;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002543 struct sockaddr *saddr;
2544
2545 saddr = (struct sockaddr *) &server->dstaddr;
2546
2547 if (server->dstaddr.ss_family == AF_INET6) {
Samuel Cabrerodef6e1d2020-10-16 11:54:55 +02002548 struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)&server->dstaddr;
2549
2550 sport = ipv6->sin6_port;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002551 slen = sizeof(struct sockaddr_in6);
2552 sfamily = AF_INET6;
Samuel Cabrerodef6e1d2020-10-16 11:54:55 +02002553 cifs_dbg(FYI, "%s: connecting to [%pI6]:%d\n", __func__, &ipv6->sin6_addr,
2554 ntohs(sport));
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002555 } else {
Samuel Cabrerodef6e1d2020-10-16 11:54:55 +02002556 struct sockaddr_in *ipv4 = (struct sockaddr_in *)&server->dstaddr;
2557
2558 sport = ipv4->sin_port;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002559 slen = sizeof(struct sockaddr_in);
2560 sfamily = AF_INET;
Samuel Cabrerodef6e1d2020-10-16 11:54:55 +02002561 cifs_dbg(FYI, "%s: connecting to %pI4:%d\n", __func__, &ipv4->sin_addr,
2562 ntohs(sport));
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002563 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002565 if (socket == NULL) {
Rob Landleyf1d0c992011-01-22 15:44:05 -06002566 rc = __sock_create(cifs_net_ns(server), sfamily, SOCK_STREAM,
2567 IPPROTO_TCP, &socket, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568 if (rc < 0) {
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +10002569 cifs_server_dbg(VFS, "Error %d creating socket\n", rc);
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002570 server->ssocket = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572 }
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002573
2574 /* BB other socket options to set KEEPALIVE, NODELAY? */
Joe Perchesf96637b2013-05-04 22:12:25 -05002575 cifs_dbg(FYI, "Socket created\n");
Jeff Laytonbcf4b102008-12-01 18:42:15 -05002576 server->ssocket = socket;
2577 socket->sk->sk_allocation = GFP_NOFS;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002578 if (sfamily == AF_INET6)
2579 cifs_reclassify_socket6(socket);
2580 else
2581 cifs_reclassify_socket4(socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582 }
2583
Ben Greear3eb9a882010-09-01 17:06:02 -07002584 rc = bind_socket(server);
2585 if (rc < 0)
2586 return rc;
2587
Jeff Laytond5c56052008-12-01 18:42:33 -05002588 /*
2589 * Eventually check for other socket options to change from
2590 * the default. sock_setsockopt not used because it expects
2591 * user space buffer
2592 */
2593 socket->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchda505c32009-01-19 03:49:35 +00002594 socket->sk->sk_sndtimeo = 5 * HZ;
Steve French6a5fa2362010-01-01 01:28:43 +00002595
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002596 /* make the bufsizes depend on wsize/rsize and max requests */
2597 if (server->noautotune) {
2598 if (socket->sk->sk_sndbuf < (200 * 1024))
2599 socket->sk->sk_sndbuf = 200 * 1024;
2600 if (socket->sk->sk_rcvbuf < (140 * 1024))
2601 socket->sk->sk_rcvbuf = 140 * 1024;
2602 }
2603
Christoph Hellwig12abc5e2020-05-28 07:12:19 +02002604 if (server->tcp_nodelay)
2605 tcp_sock_set_nodelay(socket->sk);
Steve French6a5fa2362010-01-01 01:28:43 +00002606
Joe Perchesf96637b2013-05-04 22:12:25 -05002607 cifs_dbg(FYI, "sndbuf %d rcvbuf %d rcvtimeo 0x%lx\n",
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002608 socket->sk->sk_sndbuf,
2609 socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo);
2610
Paulo Alcantara (SUSE)8eecd1c2019-07-16 19:04:50 -03002611 rc = socket->ops->connect(socket, saddr, slen,
2612 server->noblockcnt ? O_NONBLOCK : 0);
Paulo Alcantara (SUSE)d532cc72019-10-10 12:31:58 -03002613 /*
2614 * When mounting SMB root file systems, we do not want to block in
2615 * connect. Otherwise bail out and then let cifs_reconnect() perform
2616 * reconnect failover - if possible.
2617 */
2618 if (server->noblockcnt && rc == -EINPROGRESS)
Paulo Alcantara (SUSE)8eecd1c2019-07-16 19:04:50 -03002619 rc = 0;
Jeff Laytonee1b3ea2011-06-21 07:18:26 -04002620 if (rc < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002621 cifs_dbg(FYI, "Error %d connecting to server\n", rc);
Jeff Laytonee1b3ea2011-06-21 07:18:26 -04002622 sock_release(socket);
2623 server->ssocket = NULL;
2624 return rc;
2625 }
2626
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002627 if (sport == htons(RFC1001_PORT))
2628 rc = ip_rfc1001_connect(server);
Steve French50c2f752007-07-13 00:33:32 +00002629
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 return rc;
2631}
2632
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002633static int
2634ip_connect(struct TCP_Server_Info *server)
2635{
Steve French6da97912011-03-13 18:55:55 +00002636 __be16 *sport;
Pavel Shilovskya9f1b852010-12-13 19:08:35 +03002637 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr;
2638 struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr;
2639
2640 if (server->dstaddr.ss_family == AF_INET6)
2641 sport = &addr6->sin6_port;
2642 else
2643 sport = &addr->sin_port;
2644
2645 if (*sport == 0) {
2646 int rc;
2647
2648 /* try with 445 port at first */
2649 *sport = htons(CIFS_PORT);
2650
2651 rc = generic_ip_connect(server);
2652 if (rc >= 0)
2653 return rc;
2654
2655 /* if it failed, try with 139 port */
2656 *sport = htons(RFC1001_PORT);
2657 }
2658
2659 return generic_ip_connect(server);
2660}
2661
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002662void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon,
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002663 struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
Steve French8af18972007-02-14 04:42:51 +00002664{
Steve Frenchbc044992020-12-11 19:48:26 -06002665 /*
2666 * If we are reconnecting then should we check to see if
Steve French8af18972007-02-14 04:42:51 +00002667 * any requested capabilities changed locally e.g. via
2668 * remount but we can not do much about it here
2669 * if they have (even if we could detect it by the following)
2670 * Perhaps we could add a backpointer to array of sb from tcon
2671 * or if we change to make all sb to same share the same
2672 * sb as NFS - then we only have one backpointer to sb.
2673 * What if we wanted to mount the server share twice once with
Steve Frenchbc044992020-12-11 19:48:26 -06002674 * and once without posixacls or posix paths?
2675 */
Steve French8af18972007-02-14 04:42:51 +00002676 __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00002677
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002678 if (ctx && ctx->no_linux_ext) {
Steve Frenchc18c8422007-07-18 23:21:09 +00002679 tcon->fsUnixInfo.Capability = 0;
2680 tcon->unix_ext = 0; /* Unix Extensions disabled */
Joe Perchesf96637b2013-05-04 22:12:25 -05002681 cifs_dbg(FYI, "Linux protocol extensions disabled\n");
Steve Frenchc18c8422007-07-18 23:21:09 +00002682 return;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002683 } else if (ctx)
Steve Frenchc18c8422007-07-18 23:21:09 +00002684 tcon->unix_ext = 1; /* Unix Extensions supported */
2685
Jiapeng Zhong16a78852021-01-14 18:02:23 +08002686 if (!tcon->unix_ext) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002687 cifs_dbg(FYI, "Unix extensions disabled so not set on reconnect\n");
Steve Frenchc18c8422007-07-18 23:21:09 +00002688 return;
2689 }
Steve French50c2f752007-07-13 00:33:32 +00002690
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002691 if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
Steve French8af18972007-02-14 04:42:51 +00002692 __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Joe Perchesf96637b2013-05-04 22:12:25 -05002693 cifs_dbg(FYI, "unix caps which server supports %lld\n", cap);
Steve Frenchbc044992020-12-11 19:48:26 -06002694 /*
2695 * check for reconnect case in which we do not
2696 * want to change the mount behavior if we can avoid it
2697 */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002698 if (ctx == NULL) {
Steve Frenchbc044992020-12-11 19:48:26 -06002699 /*
2700 * turn off POSIX ACL and PATHNAMES if not set
2701 * originally at mount time
2702 */
Steve French8af18972007-02-14 04:42:51 +00002703 if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
2704 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00002705 if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
2706 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Joe Perchesf96637b2013-05-04 22:12:25 -05002707 cifs_dbg(VFS, "POSIXPATH support change\n");
Steve French8af18972007-02-14 04:42:51 +00002708 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00002709 } else if ((cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002710 cifs_dbg(VFS, "possible reconnect error\n");
2711 cifs_dbg(VFS, "server disabled POSIX path support\n");
Igor Mammedov11b6d642008-02-15 19:06:04 +00002712 }
Steve French8af18972007-02-14 04:42:51 +00002713 }
Steve French50c2f752007-07-13 00:33:32 +00002714
Steve French6848b732011-05-26 18:38:54 +00002715 if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP)
Joe Perchesf96637b2013-05-04 22:12:25 -05002716 cifs_dbg(VFS, "per-share encryption not supported yet\n");
Steve French6848b732011-05-26 18:38:54 +00002717
Steve French8af18972007-02-14 04:42:51 +00002718 cap &= CIFS_UNIX_CAP_MASK;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002719 if (ctx && ctx->no_psx_acl)
Steve French8af18972007-02-14 04:42:51 +00002720 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00002721 else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002722 cifs_dbg(FYI, "negotiated posix acl support\n");
Al Viro2c6292a2011-06-17 09:05:48 -04002723 if (cifs_sb)
2724 cifs_sb->mnt_cifs_flags |=
2725 CIFS_MOUNT_POSIXACL;
Steve French8af18972007-02-14 04:42:51 +00002726 }
2727
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002728 if (ctx && ctx->posix_paths == 0)
Steve French8af18972007-02-14 04:42:51 +00002729 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00002730 else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002731 cifs_dbg(FYI, "negotiate posix pathnames\n");
Al Viro2c6292a2011-06-17 09:05:48 -04002732 if (cifs_sb)
2733 cifs_sb->mnt_cifs_flags |=
Steve French8af18972007-02-14 04:42:51 +00002734 CIFS_MOUNT_POSIX_PATHS;
2735 }
Steve French50c2f752007-07-13 00:33:32 +00002736
Joe Perchesf96637b2013-05-04 22:12:25 -05002737 cifs_dbg(FYI, "Negotiate caps 0x%x\n", (int)cap);
Steve French8af18972007-02-14 04:42:51 +00002738#ifdef CONFIG_CIFS_DEBUG2
Steve French75865f8c2007-06-24 18:30:48 +00002739 if (cap & CIFS_UNIX_FCNTL_CAP)
Joe Perchesf96637b2013-05-04 22:12:25 -05002740 cifs_dbg(FYI, "FCNTL cap\n");
Steve French75865f8c2007-06-24 18:30:48 +00002741 if (cap & CIFS_UNIX_EXTATTR_CAP)
Joe Perchesf96637b2013-05-04 22:12:25 -05002742 cifs_dbg(FYI, "EXTATTR cap\n");
Steve French75865f8c2007-06-24 18:30:48 +00002743 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Joe Perchesf96637b2013-05-04 22:12:25 -05002744 cifs_dbg(FYI, "POSIX path cap\n");
Steve French75865f8c2007-06-24 18:30:48 +00002745 if (cap & CIFS_UNIX_XATTR_CAP)
Joe Perchesf96637b2013-05-04 22:12:25 -05002746 cifs_dbg(FYI, "XATTR cap\n");
Steve French75865f8c2007-06-24 18:30:48 +00002747 if (cap & CIFS_UNIX_POSIX_ACL_CAP)
Joe Perchesf96637b2013-05-04 22:12:25 -05002748 cifs_dbg(FYI, "POSIX ACL cap\n");
Steve French75865f8c2007-06-24 18:30:48 +00002749 if (cap & CIFS_UNIX_LARGE_READ_CAP)
Joe Perchesf96637b2013-05-04 22:12:25 -05002750 cifs_dbg(FYI, "very large read cap\n");
Steve French75865f8c2007-06-24 18:30:48 +00002751 if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
Joe Perchesf96637b2013-05-04 22:12:25 -05002752 cifs_dbg(FYI, "very large write cap\n");
Steve French6848b732011-05-26 18:38:54 +00002753 if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP)
Joe Perchesf96637b2013-05-04 22:12:25 -05002754 cifs_dbg(FYI, "transport encryption cap\n");
Steve French6848b732011-05-26 18:38:54 +00002755 if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP)
Joe Perchesf96637b2013-05-04 22:12:25 -05002756 cifs_dbg(FYI, "mandatory transport encryption cap\n");
Steve French8af18972007-02-14 04:42:51 +00002757#endif /* CIFS_DEBUG2 */
2758 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002759 if (ctx == NULL)
Joe Perchesf96637b2013-05-04 22:12:25 -05002760 cifs_dbg(FYI, "resetting capabilities failed\n");
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002761 else
Joe Perchesf96637b2013-05-04 22:12:25 -05002762 cifs_dbg(VFS, "Negotiating Unix capabilities with the server failed. Consider mounting with the Unix Extensions disabled if problems are found by specifying the nounix mount option.\n");
Steve French5a44b312007-09-20 15:16:24 +00002763
Steve French8af18972007-02-14 04:42:51 +00002764 }
2765 }
2766}
2767
Ronnie Sahlberg51acd202020-12-14 16:40:24 +10002768int cifs_setup_cifs_sb(struct cifs_sb_info *cifs_sb)
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -04002769{
Ronnie Sahlberg51acd202020-12-14 16:40:24 +10002770 struct smb3_fs_context *ctx = cifs_sb->ctx;
2771
Jeff Layton2de970f2010-10-06 19:51:12 -04002772 INIT_DELAYED_WORK(&cifs_sb->prune_tlinks, cifs_prune_tlinks);
2773
Al Viro2ced6f62011-06-17 09:20:04 -04002774 spin_lock_init(&cifs_sb->tlink_tree_lock);
2775 cifs_sb->tlink_tree = RB_ROOT;
2776
Frank Sorensonf52aa792020-02-12 15:31:48 -06002777 cifs_dbg(FYI, "file mode: %04ho dir mode: %04ho\n",
Ronnie Sahlberg51acd202020-12-14 16:40:24 +10002778 ctx->file_mode, ctx->dir_mode);
Steve French3b795212008-11-13 19:45:32 +00002779
Ronnie Sahlberg387ec582020-12-14 16:40:20 +10002780 /* this is needed for ASCII cp to Unicode converts */
2781 if (ctx->iocharset == NULL) {
2782 /* load_nls_default cannot return null */
2783 cifs_sb->local_nls = load_nls_default();
2784 } else {
2785 cifs_sb->local_nls = load_nls(ctx->iocharset);
2786 if (cifs_sb->local_nls == NULL) {
2787 cifs_dbg(VFS, "CIFS mount error: iocharset %s not found\n",
2788 ctx->iocharset);
2789 return -ELIBACC;
2790 }
2791 }
2792 ctx->local_nls = cifs_sb->local_nls;
Suresh Jayaraman6d20e842010-12-01 14:42:28 +05302793
Ronnie Sahlberg2d39f502020-12-14 16:40:25 +10002794 smb3_update_mnt_flags(cifs_sb);
2795
2796 if (ctx->direct_io)
Joe Perchesf96637b2013-05-04 22:12:25 -05002797 cifs_dbg(FYI, "mounting share using direct i/o\n");
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002798 if (ctx->cache_ro) {
Steve French83bbfa72019-08-27 23:58:54 -05002799 cifs_dbg(VFS, "mounting share with read only caching. Ensure that the share will not be modified while in use.\n");
2800 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_RO_CACHE;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002801 } else if (ctx->cache_rw) {
Steve French41e033f2019-08-30 02:12:41 -05002802 cifs_dbg(VFS, "mounting share in single client RW caching mode. Ensure that no other systems will be accessing the share.\n");
2803 cifs_sb->mnt_cifs_flags |= (CIFS_MOUNT_RO_CACHE |
2804 CIFS_MOUNT_RW_CACHE);
Steve French83bbfa72019-08-27 23:58:54 -05002805 }
Steve French3b795212008-11-13 19:45:32 +00002806
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002807 if ((ctx->cifs_acl) && (ctx->dynperm))
Joe Perchesf96637b2013-05-04 22:12:25 -05002808 cifs_dbg(VFS, "mount option dynperm ignored if cifsacl mount option supported\n");
Sachin Prabhu4214ebf2016-07-29 22:38:19 +01002809
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002810 if (ctx->prepath) {
2811 cifs_sb->prepath = kstrdup(ctx->prepath, GFP_KERNEL);
Sachin Prabhu4214ebf2016-07-29 22:38:19 +01002812 if (cifs_sb->prepath == NULL)
2813 return -ENOMEM;
Shyam Prasad Na738c932021-02-11 03:26:54 -08002814 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
Sachin Prabhu4214ebf2016-07-29 22:38:19 +01002815 }
2816
2817 return 0;
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -04002818}
2819
Paulo Alcantara56c762e2018-11-14 13:03:14 -02002820/* Release all succeed connections */
2821static inline void mount_put_conns(struct cifs_sb_info *cifs_sb,
2822 unsigned int xid,
2823 struct TCP_Server_Info *server,
2824 struct cifs_ses *ses, struct cifs_tcon *tcon)
2825{
2826 int rc = 0;
2827
2828 if (tcon)
2829 cifs_put_tcon(tcon);
2830 else if (ses)
2831 cifs_put_smb_ses(ses);
2832 else if (server)
2833 cifs_put_tcp_session(server, 0);
2834 cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_POSIX_PATHS;
2835 free_xid(xid);
2836}
2837
2838/* Get connections for tcp, ses and tcon */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002839static int mount_get_conns(struct smb3_fs_context *ctx, struct cifs_sb_info *cifs_sb,
Paulo Alcantara56c762e2018-11-14 13:03:14 -02002840 unsigned int *xid,
2841 struct TCP_Server_Info **nserver,
2842 struct cifs_ses **nses, struct cifs_tcon **ntcon)
2843{
2844 int rc = 0;
2845 struct TCP_Server_Info *server;
2846 struct cifs_ses *ses;
2847 struct cifs_tcon *tcon;
2848
2849 *nserver = NULL;
2850 *nses = NULL;
2851 *ntcon = NULL;
2852
2853 *xid = get_xid();
2854
2855 /* get a reference to a tcp session */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002856 server = cifs_get_tcp_session(ctx);
Paulo Alcantara56c762e2018-11-14 13:03:14 -02002857 if (IS_ERR(server)) {
2858 rc = PTR_ERR(server);
2859 return rc;
2860 }
2861
2862 *nserver = server;
2863
Paulo Alcantara56c762e2018-11-14 13:03:14 -02002864 /* get a reference to a SMB session */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002865 ses = cifs_get_smb_ses(server, ctx);
Paulo Alcantara56c762e2018-11-14 13:03:14 -02002866 if (IS_ERR(ses)) {
2867 rc = PTR_ERR(ses);
2868 return rc;
2869 }
2870
2871 *nses = ses;
2872
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002873 if ((ctx->persistent == true) && (!(ses->server->capabilities &
Paulo Alcantara56c762e2018-11-14 13:03:14 -02002874 SMB2_GLOBAL_CAP_PERSISTENT_HANDLES))) {
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +10002875 cifs_server_dbg(VFS, "persistent handles not supported by server\n");
Paulo Alcantara56c762e2018-11-14 13:03:14 -02002876 return -EOPNOTSUPP;
2877 }
2878
2879 /* search for existing tcon to this server share */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002880 tcon = cifs_get_tcon(ses, ctx);
Paulo Alcantara56c762e2018-11-14 13:03:14 -02002881 if (IS_ERR(tcon)) {
2882 rc = PTR_ERR(tcon);
2883 return rc;
2884 }
2885
2886 *ntcon = tcon;
2887
2888 /* if new SMB3.11 POSIX extensions are supported do not remap / and \ */
2889 if (tcon->posix_extensions)
2890 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
2891
2892 /* tell server which Unix caps we support */
2893 if (cap_unix(tcon->ses)) {
2894 /*
2895 * reset of caps checks mount to see if unix extensions disabled
2896 * for just this mount.
2897 */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002898 reset_cifs_unix_caps(*xid, tcon, cifs_sb, ctx);
Paulo Alcantara56c762e2018-11-14 13:03:14 -02002899 if ((tcon->ses->server->tcpStatus == CifsNeedReconnect) &&
2900 (le64_to_cpu(tcon->fsUnixInfo.Capability) &
2901 CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP))
2902 return -EACCES;
2903 } else
2904 tcon->unix_ext = 0; /* server does not support them */
2905
2906 /* do not care if a following call succeed - informational */
Steve French1981eba2019-08-29 22:33:38 -05002907 if (!tcon->pipe && server->ops->qfs_tcon) {
Amir Goldstein0f060932020-02-03 21:46:43 +02002908 server->ops->qfs_tcon(*xid, tcon, cifs_sb);
Steve French1981eba2019-08-29 22:33:38 -05002909 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RO_CACHE) {
2910 if (tcon->fsDevInfo.DeviceCharacteristics &
Steve French52870d52019-10-01 21:25:46 -05002911 cpu_to_le32(FILE_READ_ONLY_DEVICE))
Steve French1981eba2019-08-29 22:33:38 -05002912 cifs_dbg(VFS, "mounted to read only share\n");
Steve French41e033f2019-08-30 02:12:41 -05002913 else if ((cifs_sb->mnt_cifs_flags &
2914 CIFS_MOUNT_RW_CACHE) == 0)
Steve French1981eba2019-08-29 22:33:38 -05002915 cifs_dbg(VFS, "read only mount of RW share\n");
Steve French41e033f2019-08-30 02:12:41 -05002916 /* no need to log a RW mount of a typical RW share */
Steve French1981eba2019-08-29 22:33:38 -05002917 }
2918 }
Paulo Alcantara56c762e2018-11-14 13:03:14 -02002919
Ronnie Sahlberg522aa3b2020-12-14 16:40:17 +10002920 /*
2921 * Clamp the rsize/wsize mount arguments if they are too big for the server
Steve French0c2b5f72020-12-15 13:28:50 -06002922 * and set the rsize/wsize to the negotiated values if not passed in by
2923 * the user on mount
Ronnie Sahlberg522aa3b2020-12-14 16:40:17 +10002924 */
Steve French0c2b5f72020-12-15 13:28:50 -06002925 if ((cifs_sb->ctx->wsize == 0) ||
2926 (cifs_sb->ctx->wsize > server->ops->negotiate_wsize(tcon, ctx)))
Ronnie Sahlberg522aa3b2020-12-14 16:40:17 +10002927 cifs_sb->ctx->wsize = server->ops->negotiate_wsize(tcon, ctx);
Steve French0c2b5f72020-12-15 13:28:50 -06002928 if ((cifs_sb->ctx->rsize == 0) ||
2929 (cifs_sb->ctx->rsize > server->ops->negotiate_rsize(tcon, ctx)))
Ronnie Sahlberg522aa3b2020-12-14 16:40:17 +10002930 cifs_sb->ctx->rsize = server->ops->negotiate_rsize(tcon, ctx);
Paulo Alcantara56c762e2018-11-14 13:03:14 -02002931
2932 return 0;
2933}
2934
2935static int mount_setup_tlink(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
2936 struct cifs_tcon *tcon)
2937{
2938 struct tcon_link *tlink;
2939
2940 /* hang the tcon off of the superblock */
2941 tlink = kzalloc(sizeof(*tlink), GFP_KERNEL);
2942 if (tlink == NULL)
2943 return -ENOMEM;
2944
2945 tlink->tl_uid = ses->linux_uid;
2946 tlink->tl_tcon = tcon;
2947 tlink->tl_time = jiffies;
2948 set_bit(TCON_LINK_MASTER, &tlink->tl_flags);
2949 set_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
2950
2951 cifs_sb->master_tlink = tlink;
2952 spin_lock(&cifs_sb->tlink_tree_lock);
2953 tlink_rb_insert(&cifs_sb->tlink_tree, tlink);
2954 spin_unlock(&cifs_sb->tlink_tree_lock);
2955
2956 queue_delayed_work(cifsiod_wq, &cifs_sb->prune_tlinks,
2957 TLINK_IDLE_EXPIRE);
2958 return 0;
2959}
Jeff Laytonb9bce2e2011-07-06 08:10:39 -04002960
Steve French2d6d5892009-04-09 00:36:44 +00002961#ifdef CONFIG_CIFS_DFS_UPCALL
Steve French6d3ea7e2012-11-28 22:34:41 -06002962/*
2963 * cifs_build_path_to_root returns full path to root when we do not have an
Steve French201023c2021-02-15 11:03:45 -06002964 * existing connection (tcon)
Steve French6d3ea7e2012-11-28 22:34:41 -06002965 */
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002966static char *
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002967build_unc_path_to_root(const struct smb3_fs_context *ctx,
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02002968 const struct cifs_sb_info *cifs_sb, bool useppath)
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002969{
Jeff Laytonb2a0fa12011-07-06 08:10:36 -04002970 char *full_path, *pos;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002971 unsigned int pplen = useppath && ctx->prepath ?
2972 strlen(ctx->prepath) + 1 : 0;
2973 unsigned int unc_len = strnlen(ctx->UNC, MAX_TREE_SIZE + 1);
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002974
Ronnie Sahlberg340625e2019-08-27 09:30:14 +10002975 if (unc_len > MAX_TREE_SIZE)
2976 return ERR_PTR(-EINVAL);
2977
Jeff Laytonb2a0fa12011-07-06 08:10:36 -04002978 full_path = kmalloc(unc_len + pplen + 1, GFP_KERNEL);
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002979 if (full_path == NULL)
2980 return ERR_PTR(-ENOMEM);
2981
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002982 memcpy(full_path, ctx->UNC, unc_len);
Jeff Laytonb2a0fa12011-07-06 08:10:36 -04002983 pos = full_path + unc_len;
2984
2985 if (pplen) {
Jeff Layton1fc29ba2013-05-31 10:00:18 -04002986 *pos = CIFS_DIR_SEP(cifs_sb);
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06002987 memcpy(pos + 1, ctx->prepath, pplen);
Jeff Laytonb2a0fa12011-07-06 08:10:36 -04002988 pos += pplen;
2989 }
2990
2991 *pos = '\0'; /* add trailing null */
Steve Frenchf87d39d2011-05-27 03:50:55 +00002992 convert_delimiter(full_path, CIFS_DIR_SEP(cifs_sb));
Joe Perchesf96637b2013-05-04 22:12:25 -05002993 cifs_dbg(FYI, "%s: full_path=%s\n", __func__, full_path);
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04002994 return full_path;
2995}
Sean Finneydd613942011-04-11 13:19:30 +00002996
Paulo Alcantara1c780222018-11-14 16:24:03 -02002997/**
2998 * expand_dfs_referral - Perform a dfs referral query and update the cifs_sb
2999 *
Ronnie Sahlberga2a52a82020-11-10 09:12:31 +10003000 * If a referral is found, cifs_sb->ctx->mount_options will be (re-)allocated
Sean Finney046462a2011-04-11 13:19:33 +00003001 * to a string containing updated options for the submount. Otherwise it
3002 * will be left untouched.
Sean Finneydd613942011-04-11 13:19:30 +00003003 *
3004 * Returns the rc from get_dfs_path to the caller, which can be used to
3005 * determine whether there were referrals.
3006 */
3007static int
Pavel Shilovskyb669f332012-05-27 20:21:53 +04003008expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses,
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003009 struct smb3_fs_context *ctx, struct cifs_sb_info *cifs_sb,
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003010 char *ref_path)
Sean Finneydd613942011-04-11 13:19:30 +00003011{
3012 int rc;
Paulo Alcantara1c780222018-11-14 16:24:03 -02003013 struct dfs_info3_param referral = {0};
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003014 char *full_path = NULL, *mdata = NULL;
Sean Finneydd613942011-04-11 13:19:30 +00003015
Aurelien Aptel83930722018-09-20 18:10:25 -07003016 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS)
3017 return -EREMOTE;
3018
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003019 full_path = build_unc_path_to_root(ctx, cifs_sb, true);
Sean Finneydd613942011-04-11 13:19:30 +00003020 if (IS_ERR(full_path))
3021 return PTR_ERR(full_path);
3022
Paulo Alcantara1c780222018-11-14 16:24:03 -02003023 rc = dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb),
3024 ref_path, &referral, NULL);
3025 if (!rc) {
Ronnie Sahlberg0d4873f2021-01-28 21:35:10 -06003026 char *fake_devname = NULL;
3027
Ronnie Sahlberga2a52a82020-11-10 09:12:31 +10003028 mdata = cifs_compose_mount_options(cifs_sb->ctx->mount_options,
Ronnie Sahlberg0d4873f2021-01-28 21:35:10 -06003029 full_path + 1, &referral,
3030 &fake_devname);
Paulo Alcantara1c780222018-11-14 16:24:03 -02003031 free_dfs_info_param(&referral);
Sean Finney046462a2011-04-11 13:19:33 +00003032
Sean Finneydd613942011-04-11 13:19:30 +00003033 if (IS_ERR(mdata)) {
3034 rc = PTR_ERR(mdata);
3035 mdata = NULL;
Jeff Laytonb9bce2e2011-07-06 08:10:39 -04003036 } else {
Ronnie Sahlbergabd4af42021-02-08 16:48:31 +10003037 /*
3038 * We can not clear out the whole structure since we
3039 * no longer have an explicit function to parse
3040 * a mount-string. Instead we need to clear out the
3041 * individual fields that are no longer valid.
3042 */
3043 kfree(ctx->prepath);
3044 ctx->prepath = NULL;
Ronnie Sahlberg0d4873f2021-01-28 21:35:10 -06003045 rc = cifs_setup_volume_info(ctx, mdata, fake_devname);
Sean Finneydd613942011-04-11 13:19:30 +00003046 }
Ronnie Sahlberg0d4873f2021-01-28 21:35:10 -06003047 kfree(fake_devname);
Ronnie Sahlberga2a52a82020-11-10 09:12:31 +10003048 kfree(cifs_sb->ctx->mount_options);
3049 cifs_sb->ctx->mount_options = mdata;
Sean Finneydd613942011-04-11 13:19:30 +00003050 }
3051 kfree(full_path);
3052 return rc;
3053}
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003054
Paulo Alcantarac870a8e2021-06-04 19:25:30 -03003055static int get_next_dfs_tgt(struct dfs_cache_tgt_list *tgt_list,
3056 struct dfs_cache_tgt_iterator **tgt_it)
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003057{
3058 if (!*tgt_it)
3059 *tgt_it = dfs_cache_get_tgt_iterator(tgt_list);
3060 else
3061 *tgt_it = dfs_cache_get_next_tgt(tgt_list, *tgt_it);
3062 return !*tgt_it ? -EHOSTDOWN : 0;
3063}
3064
3065static int update_vol_info(const struct dfs_cache_tgt_iterator *tgt_it,
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003066 struct smb3_fs_context *fake_ctx, struct smb3_fs_context *ctx)
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003067{
3068 const char *tgt = dfs_cache_get_tgt_name(tgt_it);
3069 int len = strlen(tgt) + 2;
3070 char *new_unc;
3071
3072 new_unc = kmalloc(len, GFP_KERNEL);
3073 if (!new_unc)
3074 return -ENOMEM;
Ronnie Sahlberg74ea5f92019-02-09 09:51:11 +10003075 scnprintf(new_unc, len, "\\%s", tgt);
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003076
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003077 kfree(ctx->UNC);
3078 ctx->UNC = new_unc;
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003079
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003080 if (fake_ctx->prepath) {
3081 kfree(ctx->prepath);
3082 ctx->prepath = fake_ctx->prepath;
3083 fake_ctx->prepath = NULL;
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003084 }
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003085 memcpy(&ctx->dstaddr, &fake_ctx->dstaddr, sizeof(ctx->dstaddr));
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003086
3087 return 0;
3088}
3089
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003090static int do_dfs_failover(const char *path, const char *full_path, struct cifs_sb_info *cifs_sb,
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003091 struct smb3_fs_context *ctx, struct cifs_ses *root_ses,
3092 unsigned int *xid, struct TCP_Server_Info **server,
3093 struct cifs_ses **ses, struct cifs_tcon **tcon)
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003094{
3095 int rc;
Paulo Alcantarac870a8e2021-06-04 19:25:30 -03003096 char *npath = NULL;
Paulo Alcantara85132222021-02-24 20:59:21 -03003097 struct dfs_cache_tgt_list tgt_list = {0};
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003098 struct dfs_cache_tgt_iterator *tgt_it = NULL;
Paulo Alcantara85132222021-02-24 20:59:21 -03003099 struct smb3_fs_context tmp_ctx = {NULL};
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003100
3101 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS)
3102 return -EOPNOTSUPP;
3103
Paulo Alcantarac870a8e2021-06-04 19:25:30 -03003104 npath = dfs_cache_canonical_path(path, cifs_sb->local_nls, cifs_remap(cifs_sb));
3105 if (IS_ERR(npath))
3106 return PTR_ERR(npath);
Paulo Alcantara85132222021-02-24 20:59:21 -03003107
Paulo Alcantarac870a8e2021-06-04 19:25:30 -03003108 cifs_dbg(FYI, "%s: path=%s full_path=%s\n", __func__, npath, full_path);
3109
3110 rc = dfs_cache_noreq_find(npath, NULL, &tgt_list);
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003111 if (rc)
Paulo Alcantarac870a8e2021-06-04 19:25:30 -03003112 goto out;
Paulo Alcantara85132222021-02-24 20:59:21 -03003113 /*
3114 * We use a 'tmp_ctx' here because we need pass it down to the mount_{get,put} functions to
3115 * test connection against new DFS targets.
3116 */
3117 rc = smb3_fs_context_dup(&tmp_ctx, ctx);
3118 if (rc)
3119 goto out;
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003120
3121 for (;;) {
Paulo Alcantara85132222021-02-24 20:59:21 -03003122 struct dfs_info3_param ref = {0};
3123 char *fake_devname = NULL, *mdata = NULL;
3124
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003125 /* Get next DFS target server - if any */
Paulo Alcantarac870a8e2021-06-04 19:25:30 -03003126 rc = get_next_dfs_tgt(&tgt_list, &tgt_it);
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003127 if (rc)
3128 break;
Paulo Alcantara85132222021-02-24 20:59:21 -03003129
Paulo Alcantarac870a8e2021-06-04 19:25:30 -03003130 rc = dfs_cache_get_tgt_referral(npath, tgt_it, &ref);
Paulo Alcantara85132222021-02-24 20:59:21 -03003131 if (rc)
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003132 break;
Paulo Alcantara85132222021-02-24 20:59:21 -03003133
3134 cifs_dbg(FYI, "%s: old ctx: UNC=%s prepath=%s\n", __func__, tmp_ctx.UNC,
3135 tmp_ctx.prepath);
3136
3137 mdata = cifs_compose_mount_options(cifs_sb->ctx->mount_options, full_path + 1, &ref,
3138 &fake_devname);
3139 free_dfs_info_param(&ref);
3140
3141 if (IS_ERR(mdata)) {
3142 rc = PTR_ERR(mdata);
3143 mdata = NULL;
3144 } else
3145 rc = cifs_setup_volume_info(&tmp_ctx, mdata, fake_devname);
3146
3147 kfree(mdata);
3148 kfree(fake_devname);
3149
3150 if (rc)
3151 break;
3152
3153 cifs_dbg(FYI, "%s: new ctx: UNC=%s prepath=%s\n", __func__, tmp_ctx.UNC,
3154 tmp_ctx.prepath);
3155
3156 mount_put_conns(cifs_sb, *xid, *server, *ses, *tcon);
3157 rc = mount_get_conns(&tmp_ctx, cifs_sb, xid, server, ses, tcon);
3158 if (!rc || (*server && *ses)) {
3159 /*
3160 * We were able to connect to new target server. Update current context with
3161 * new target server.
3162 */
3163 rc = update_vol_info(tgt_it, &tmp_ctx, ctx);
3164 break;
3165 }
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003166 }
3167 if (!rc) {
Paulo Alcantara85132222021-02-24 20:59:21 -03003168 cifs_dbg(FYI, "%s: final ctx: UNC=%s prepath=%s\n", __func__, tmp_ctx.UNC,
3169 tmp_ctx.prepath);
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003170 /*
Paulo Alcantara85132222021-02-24 20:59:21 -03003171 * Update DFS target hint in DFS referral cache with the target server we
3172 * successfully reconnected to.
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003173 */
Paulo Alcantara85132222021-02-24 20:59:21 -03003174 rc = dfs_cache_update_tgthint(*xid, root_ses ? root_ses : *ses, cifs_sb->local_nls,
3175 cifs_remap(cifs_sb), path, tgt_it);
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003176 }
Paulo Alcantara85132222021-02-24 20:59:21 -03003177
3178out:
Paulo Alcantarac870a8e2021-06-04 19:25:30 -03003179 kfree(npath);
Paulo Alcantara85132222021-02-24 20:59:21 -03003180 smb3_cleanup_fs_context_contents(&tmp_ctx);
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003181 dfs_cache_free_tgts(&tgt_list);
3182 return rc;
3183}
Steve French2d6d5892009-04-09 00:36:44 +00003184#endif
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04003185
Ronnie Sahlberg24e0a1e2020-12-10 00:06:02 -06003186/* TODO: all callers to this are broken. We are not parsing mount_options here
3187 * we should pass a clone of the original context?
3188 */
Paulo Alcantara (SUSE)50720102019-03-19 16:54:29 -03003189int
Ronnie Sahlberg0d4873f2021-01-28 21:35:10 -06003190cifs_setup_volume_info(struct smb3_fs_context *ctx, const char *mntopts, const char *devname)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191{
Paulo Alcantara5c1acf32021-05-03 11:55:26 -03003192 int rc;
Sean Finneydd613942011-04-11 13:19:30 +00003193
Paulo Alcantara5c1acf32021-05-03 11:55:26 -03003194 if (devname) {
3195 cifs_dbg(FYI, "%s: devname=%s\n", __func__, devname);
3196 rc = smb3_parse_devname(devname, ctx);
3197 if (rc) {
3198 cifs_dbg(VFS, "%s: failed to parse %s: %d\n", __func__, devname, rc);
3199 return rc;
3200 }
3201 }
Ronnie Sahlberg0d4873f2021-01-28 21:35:10 -06003202
3203 if (mntopts) {
3204 char *ip;
3205
Ronnie Sahlberg0d4873f2021-01-28 21:35:10 -06003206 rc = smb3_parse_opt(mntopts, "ip", &ip);
Paulo Alcantara5c1acf32021-05-03 11:55:26 -03003207 if (rc) {
3208 cifs_dbg(VFS, "%s: failed to parse ip options: %d\n", __func__, rc);
3209 return rc;
3210 }
3211
3212 rc = cifs_convert_address((struct sockaddr *)&ctx->dstaddr, ip, strlen(ip));
3213 kfree(ip);
3214 if (!rc) {
Ronnie Sahlberg0d4873f2021-01-28 21:35:10 -06003215 cifs_dbg(VFS, "%s: failed to convert ip address\n", __func__);
3216 return -EINVAL;
3217 }
3218 }
3219
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003220 if (ctx->nullauth) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003221 cifs_dbg(FYI, "Anonymous login\n");
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003222 kfree(ctx->username);
3223 ctx->username = NULL;
3224 } else if (ctx->username) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003225 /* BB fixme parse for domain name here */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003226 cifs_dbg(FYI, "Username: %s\n", ctx->username);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227 } else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003228 cifs_dbg(VFS, "No username specified\n");
Steve French50c2f752007-07-13 00:33:32 +00003229 /* In userspace mount helper we can get user name from alternate
3230 locations such as env variables and files on disk */
Jeff Layton04db79b2011-07-06 08:10:38 -04003231 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232 }
3233
Paulo Alcantara5c1acf32021-05-03 11:55:26 -03003234 return 0;
Jeff Layton04db79b2011-07-06 08:10:38 -04003235}
3236
Aurelien Aptela6b50582016-05-25 19:59:09 +02003237static int
3238cifs_are_all_path_components_accessible(struct TCP_Server_Info *server,
3239 unsigned int xid,
3240 struct cifs_tcon *tcon,
3241 struct cifs_sb_info *cifs_sb,
Ronnie Sahlbergce465bf2019-07-11 13:46:58 +10003242 char *full_path,
3243 int added_treename)
Aurelien Aptela6b50582016-05-25 19:59:09 +02003244{
3245 int rc;
3246 char *s;
3247 char sep, tmp;
Ronnie Sahlbergce465bf2019-07-11 13:46:58 +10003248 int skip = added_treename ? 1 : 0;
Aurelien Aptela6b50582016-05-25 19:59:09 +02003249
3250 sep = CIFS_DIR_SEP(cifs_sb);
3251 s = full_path;
3252
3253 rc = server->ops->is_path_accessible(xid, tcon, cifs_sb, "");
3254 while (rc == 0) {
3255 /* skip separators */
3256 while (*s == sep)
3257 s++;
3258 if (!*s)
3259 break;
3260 /* next separator */
3261 while (*s && *s != sep)
3262 s++;
Ronnie Sahlbergce465bf2019-07-11 13:46:58 +10003263 /*
3264 * if the treename is added, we then have to skip the first
3265 * part within the separators
3266 */
3267 if (skip) {
3268 skip = 0;
3269 continue;
3270 }
Aurelien Aptela6b50582016-05-25 19:59:09 +02003271 /*
3272 * temporarily null-terminate the path at the end of
3273 * the current component
3274 */
3275 tmp = *s;
3276 *s = 0;
3277 rc = server->ops->is_path_accessible(xid, tcon, cifs_sb,
3278 full_path);
3279 *s = tmp;
3280 }
3281 return rc;
3282}
3283
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003284/*
3285 * Check if path is remote (e.g. a DFS share). Return -EREMOTE if it is,
3286 * otherwise 0.
3287 */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003288static int is_path_remote(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx,
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003289 const unsigned int xid,
3290 struct TCP_Server_Info *server,
3291 struct cifs_tcon *tcon)
Pavel Shilovsky724d9f12011-05-05 09:55:12 +00003292{
Jeff Layton1daaae82012-03-21 06:30:40 -04003293 int rc;
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003294 char *full_path;
3295
3296 if (!server->ops->is_path_accessible)
3297 return -EOPNOTSUPP;
3298
3299 /*
3300 * cifs_build_path_to_root works only when we have a valid tcon
3301 */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003302 full_path = cifs_build_path_to_root(ctx, cifs_sb, tcon,
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003303 tcon->Flags & SMB_SHARE_IS_IN_DFS);
3304 if (full_path == NULL)
3305 return -ENOMEM;
3306
3307 cifs_dbg(FYI, "%s: full_path: %s\n", __func__, full_path);
3308
3309 rc = server->ops->is_path_accessible(xid, tcon, cifs_sb,
3310 full_path);
3311 if (rc != 0 && rc != -EREMOTE) {
3312 kfree(full_path);
3313 return rc;
3314 }
3315
3316 if (rc != -EREMOTE) {
3317 rc = cifs_are_all_path_components_accessible(server, xid, tcon,
Ronnie Sahlbergce465bf2019-07-11 13:46:58 +10003318 cifs_sb, full_path, tcon->Flags & SMB_SHARE_IS_IN_DFS);
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003319 if (rc != 0) {
Joe Perchesa0a30362020-04-14 22:42:53 -07003320 cifs_server_dbg(VFS, "cannot query dirs between root and final path, enabling CIFS_MOUNT_USE_PREFIX_PATH\n");
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003321 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
3322 rc = 0;
3323 }
3324 }
3325
3326 kfree(full_path);
3327 return rc;
3328}
3329
3330#ifdef CONFIG_CIFS_DFS_UPCALL
Paulo Alcantarac9f71102021-06-04 19:25:29 -03003331static void set_root_ses(struct cifs_sb_info *cifs_sb, const uuid_t *mount_id, struct cifs_ses *ses,
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003332 struct cifs_ses **root_ses)
Paulo Alcantara (SUSE)5bb30a42019-11-22 12:30:56 -03003333{
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003334 if (ses) {
3335 spin_lock(&cifs_tcp_ses_lock);
3336 ses->ses_count++;
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003337 spin_unlock(&cifs_tcp_ses_lock);
Paulo Alcantarac9f71102021-06-04 19:25:29 -03003338 dfs_cache_add_refsrv_session(mount_id, ses);
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003339 }
3340 *root_ses = ses;
3341}
3342
Paulo Alcantaraff2c54a2021-02-24 20:59:22 -03003343/* Set up next dfs prefix path in @dfs_path */
3344static int next_dfs_prepath(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx,
3345 const unsigned int xid, struct TCP_Server_Info *server,
3346 struct cifs_tcon *tcon, char **dfs_path)
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003347{
Paulo Alcantaraff2c54a2021-02-24 20:59:22 -03003348 char *path, *npath;
3349 int added_treename = is_tcon_dfs(tcon);
3350 int rc;
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003351
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003352 path = cifs_build_path_to_root(ctx, cifs_sb, tcon, added_treename);
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003353 if (!path)
3354 return -ENOMEM;
3355
Paulo Alcantaraff2c54a2021-02-24 20:59:22 -03003356 rc = is_path_remote(cifs_sb, ctx, xid, server, tcon);
3357 if (rc == -EREMOTE) {
3358 struct smb3_fs_context v = {NULL};
3359 /* if @path contains a tree name, skip it in the prefix path */
3360 if (added_treename) {
3361 rc = smb3_parse_devname(path, &v);
3362 if (rc)
3363 goto out;
3364 npath = build_unc_path_to_root(&v, cifs_sb, true);
3365 smb3_cleanup_fs_context_contents(&v);
3366 } else {
3367 v.UNC = ctx->UNC;
3368 v.prepath = path + 1;
3369 npath = build_unc_path_to_root(&v, cifs_sb, true);
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003370 }
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003371
Paulo Alcantaraff2c54a2021-02-24 20:59:22 -03003372 if (IS_ERR(npath)) {
3373 rc = PTR_ERR(npath);
3374 goto out;
3375 }
3376
3377 kfree(*dfs_path);
3378 *dfs_path = npath;
3379 rc = -EREMOTE;
3380 }
3381
3382out:
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003383 kfree(path);
3384 return rc;
Paulo Alcantara (SUSE)5bb30a42019-11-22 12:30:56 -03003385}
3386
Paulo Alcantara5ff28362021-02-24 20:59:23 -03003387/* Check if resolved targets can handle any DFS referrals */
Paulo Alcantarac870a8e2021-06-04 19:25:30 -03003388static int is_referral_server(const char *ref_path, struct cifs_sb_info *cifs_sb,
3389 struct cifs_tcon *tcon, bool *ref_server)
Paulo Alcantara5ff28362021-02-24 20:59:23 -03003390{
3391 int rc;
3392 struct dfs_info3_param ref = {0};
3393
Paulo Alcantarac870a8e2021-06-04 19:25:30 -03003394 cifs_dbg(FYI, "%s: ref_path=%s\n", __func__, ref_path);
3395
Paulo Alcantara5ff28362021-02-24 20:59:23 -03003396 if (is_tcon_dfs(tcon)) {
3397 *ref_server = true;
3398 } else {
Paulo Alcantarac870a8e2021-06-04 19:25:30 -03003399 char *npath;
Paulo Alcantara5ff28362021-02-24 20:59:23 -03003400
Paulo Alcantarac870a8e2021-06-04 19:25:30 -03003401 npath = dfs_cache_canonical_path(ref_path, cifs_sb->local_nls, cifs_remap(cifs_sb));
3402 if (IS_ERR(npath))
3403 return PTR_ERR(npath);
3404
3405 rc = dfs_cache_noreq_find(npath, &ref, NULL);
3406 kfree(npath);
Paulo Alcantara5ff28362021-02-24 20:59:23 -03003407 if (rc) {
3408 cifs_dbg(VFS, "%s: dfs_cache_noreq_find: failed (rc=%d)\n", __func__, rc);
3409 return rc;
3410 }
3411 cifs_dbg(FYI, "%s: ref.flags=0x%x\n", __func__, ref.flags);
3412 /*
3413 * Check if all targets are capable of handling DFS referrals as per
3414 * MS-DFSC 2.2.4 RESP_GET_DFS_REFERRAL.
3415 */
3416 *ref_server = !!(ref.flags & DFSREF_REFERRAL_SERVER);
3417 free_dfs_info_param(&ref);
3418 }
3419 return 0;
3420}
3421
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003422int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003423{
3424 int rc = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003425 unsigned int xid;
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003426 struct TCP_Server_Info *server = NULL;
3427 struct cifs_ses *ses = NULL, *root_ses = NULL;
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003428 struct cifs_tcon *tcon = NULL;
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003429 int count = 0;
Paulo Alcantarac9f71102021-06-04 19:25:29 -03003430 uuid_t mount_id = {0};
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003431 char *ref_path = NULL, *full_path = NULL;
3432 char *oldmnt = NULL;
Paulo Alcantara5ff28362021-02-24 20:59:23 -03003433 bool ref_server = false;
Al Virodd854462011-06-17 08:24:42 -04003434
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003435 rc = mount_get_conns(ctx, cifs_sb, &xid, &server, &ses, &tcon);
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003436 /*
Paulo Alcantarad01132a2021-02-24 20:59:24 -03003437 * If called with 'nodfs' mount option, then skip DFS resolving. Otherwise unconditionally
3438 * try to get an DFS referral (even cached) to determine whether it is an DFS mount.
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003439 *
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003440 * Skip prefix path to provide support for DFS referrals from w2k8 servers which don't seem
3441 * to respond with PATH_NOT_COVERED to requests that include the prefix.
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003442 */
Paulo Alcantarad01132a2021-02-24 20:59:24 -03003443 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS) ||
3444 dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb), ctx->UNC + 1, NULL,
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003445 NULL)) {
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003446 if (rc)
3447 goto error;
3448 /* Check if it is fully accessible and then mount it */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003449 rc = is_path_remote(cifs_sb, ctx, xid, server, tcon);
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003450 if (!rc)
3451 goto out;
3452 if (rc != -EREMOTE)
3453 goto error;
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003454 }
Paulo Alcantarac9f71102021-06-04 19:25:29 -03003455
Paulo Alcantaraf3c852b2021-06-04 19:25:33 -03003456 ctx->nosharesock = true;
3457
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003458 /* Get path of DFS root */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003459 ref_path = build_unc_path_to_root(ctx, cifs_sb, false);
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003460 if (IS_ERR(ref_path)) {
3461 rc = PTR_ERR(ref_path);
3462 ref_path = NULL;
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003463 goto error;
3464 }
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003465
Paulo Alcantarac9f71102021-06-04 19:25:29 -03003466 uuid_gen(&mount_id);
3467 set_root_ses(cifs_sb, &mount_id, ses, &root_ses);
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003468 do {
3469 /* Save full path of last DFS path we used to resolve final target server */
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003470 kfree(full_path);
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003471 full_path = build_unc_path_to_root(ctx, cifs_sb, !!count);
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003472 if (IS_ERR(full_path)) {
3473 rc = PTR_ERR(full_path);
Dan Carpenter20b135e2020-08-05 12:52:07 +03003474 full_path = NULL;
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003475 break;
3476 }
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003477 /* Chase referral */
Ronnie Sahlberga2a52a82020-11-10 09:12:31 +10003478 oldmnt = cifs_sb->ctx->mount_options;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003479 rc = expand_dfs_referral(xid, root_ses, ctx, cifs_sb, ref_path + 1);
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003480 if (rc)
3481 break;
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003482 /* Connect to new DFS target only if we were redirected */
Ronnie Sahlberga2a52a82020-11-10 09:12:31 +10003483 if (oldmnt != cifs_sb->ctx->mount_options) {
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003484 mount_put_conns(cifs_sb, xid, server, ses, tcon);
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003485 rc = mount_get_conns(ctx, cifs_sb, &xid, &server, &ses, &tcon);
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04003486 }
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003487 if (rc && !server && !ses) {
3488 /* Failed to connect. Try to connect to other targets in the referral. */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003489 rc = do_dfs_failover(ref_path + 1, full_path, cifs_sb, ctx, root_ses, &xid,
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003490 &server, &ses, &tcon);
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003491 }
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003492 if (rc == -EACCES || rc == -EOPNOTSUPP || !server || !ses)
3493 break;
3494 if (!tcon)
3495 continue;
Paulo Alcantara5ff28362021-02-24 20:59:23 -03003496
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003497 /* Make sure that requests go through new root servers */
Paulo Alcantarac870a8e2021-06-04 19:25:30 -03003498 rc = is_referral_server(ref_path + 1, cifs_sb, tcon, &ref_server);
Paulo Alcantara5ff28362021-02-24 20:59:23 -03003499 if (rc)
3500 break;
Paulo Alcantarac9f71102021-06-04 19:25:29 -03003501 if (ref_server)
3502 set_root_ses(cifs_sb, &mount_id, ses, &root_ses);
Paulo Alcantara5ff28362021-02-24 20:59:23 -03003503
Paulo Alcantaraff2c54a2021-02-24 20:59:22 -03003504 /* Get next dfs path and then continue chasing them if -EREMOTE */
3505 rc = next_dfs_prepath(cifs_sb, ctx, xid, server, tcon, &ref_path);
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003506 /* Prevent recursion on broken link referrals */
3507 if (rc == -EREMOTE && ++count > MAX_NESTED_LINKS)
3508 rc = -ELOOP;
3509 } while (rc == -EREMOTE);
Igor Mammedov1bfe73c2009-04-01 17:54:42 +04003510
Steve French162004a2021-06-23 19:32:24 -05003511 if (rc || !tcon)
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003512 goto error;
Paulo Alcantarac9f71102021-06-04 19:25:29 -03003513
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003514 kfree(ref_path);
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003515 /*
3516 * Store DFS full path in both superblock and tree connect structures.
3517 *
3518 * For DFS root mounts, the prefix path (cifs_sb->prepath) is preserved during reconnect so
3519 * only the root path is set in cifs_sb->origin_fullpath and tcon->dfs_path. And for DFS
3520 * links, the prefix path is included in both and may be changed during reconnect. See
3521 * cifs_tree_connect().
3522 */
Paulo Alcantarac870a8e2021-06-04 19:25:30 -03003523 ref_path = dfs_cache_canonical_path(full_path, cifs_sb->local_nls, cifs_remap(cifs_sb));
3524 kfree(full_path);
3525 full_path = NULL;
3526
3527 if (IS_ERR(ref_path)) {
3528 rc = PTR_ERR(ref_path);
3529 ref_path = NULL;
3530 goto error;
3531 }
3532 cifs_sb->origin_fullpath = ref_path;
3533
3534 ref_path = kstrdup(cifs_sb->origin_fullpath, GFP_KERNEL);
3535 if (!ref_path) {
Paulo Alcantara93d5cb52018-11-14 17:13:25 -02003536 rc = -ENOMEM;
3537 goto error;
3538 }
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003539 spin_lock(&cifs_tcp_ses_lock);
Paulo Alcantarac870a8e2021-06-04 19:25:30 -03003540 tcon->dfs_path = ref_path;
3541 ref_path = NULL;
Paulo Alcantara93d5cb52018-11-14 17:13:25 -02003542 spin_unlock(&cifs_tcp_ses_lock);
3543
Aurelien Aptel5fc7fcd2018-11-16 16:13:25 +01003544 /*
3545 * After reconnecting to a different server, unique ids won't
3546 * match anymore, so we disable serverino. This prevents
3547 * dentry revalidation to think the dentry are stale (ESTALE).
3548 */
3549 cifs_autodisable_serverino(cifs_sb);
Paulo Alcantara (SUSE)bacd7042020-02-20 19:49:34 -03003550 /*
3551 * Force the use of prefix path to support failover on DFS paths that
3552 * resolve to targets that have different prefix paths.
3553 */
3554 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
3555 kfree(cifs_sb->prepath);
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003556 cifs_sb->prepath = ctx->prepath;
3557 ctx->prepath = NULL;
Paulo Alcantarac9f71102021-06-04 19:25:29 -03003558 uuid_copy(&cifs_sb->dfs_mount_id, &mount_id);
Paulo Alcantara (SUSE)bacd7042020-02-20 19:49:34 -03003559
Jeff Layton70fe7dc2007-11-16 22:21:07 +00003560out:
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003561 free_xid(xid);
Ronnie Sahlberg387ec582020-12-14 16:40:20 +10003562 cifs_try_adding_channels(cifs_sb, ses);
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003563 return mount_setup_tlink(cifs_sb, ses, tcon);
3564
3565error:
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003566 kfree(ref_path);
Paulo Alcantara4a367dc2018-11-14 16:53:52 -02003567 kfree(full_path);
Paulo Alcantara7efd0812020-07-21 09:36:44 -03003568 kfree(cifs_sb->origin_fullpath);
Paulo Alcantarac9f71102021-06-04 19:25:29 -03003569 dfs_cache_put_refsrv_sessions(&mount_id);
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003570 mount_put_conns(cifs_sb, xid, server, ses, tcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003571 return rc;
3572}
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003573#else
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003574int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003575{
3576 int rc = 0;
3577 unsigned int xid;
3578 struct cifs_ses *ses;
3579 struct cifs_tcon *tcon;
3580 struct TCP_Server_Info *server;
3581
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003582 rc = mount_get_conns(ctx, cifs_sb, &xid, &server, &ses, &tcon);
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003583 if (rc)
3584 goto error;
3585
3586 if (tcon) {
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003587 rc = is_path_remote(cifs_sb, ctx, xid, server, tcon);
Paulo Alcantara56c762e2018-11-14 13:03:14 -02003588 if (rc == -EREMOTE)
3589 rc = -EOPNOTSUPP;
3590 if (rc)
3591 goto error;
3592 }
3593
3594 free_xid(xid);
3595
3596 return mount_setup_tlink(cifs_sb, ses, tcon);
3597
3598error:
3599 mount_put_conns(cifs_sb, xid, server, ses, tcon);
3600 return rc;
3601}
3602#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603
Jeff Layton8d1bca32011-06-11 21:17:10 -04003604/*
Aurelien Aptelb327a712018-01-24 13:46:10 +01003605 * Issue a TREE_CONNECT request.
Jeff Layton8d1bca32011-06-11 21:17:10 -04003606 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +04003608CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
Steve French96daf2b2011-05-27 04:34:02 +00003609 const char *tree, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610 const struct nls_table *nls_codepage)
3611{
3612 struct smb_hdr *smb_buffer;
3613 struct smb_hdr *smb_buffer_response;
3614 TCONX_REQ *pSMB;
3615 TCONX_RSP *pSMBr;
3616 unsigned char *bcc_ptr;
3617 int rc = 0;
Jeff Layton690c5222011-01-20 13:36:51 -05003618 int length;
3619 __u16 bytes_left, count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620
3621 if (ses == NULL)
3622 return -EIO;
3623
3624 smb_buffer = cifs_buf_get();
Steve Frenchca43e3b2009-09-01 17:20:50 +00003625 if (smb_buffer == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626 return -ENOMEM;
Steve Frenchca43e3b2009-09-01 17:20:50 +00003627
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628 smb_buffer_response = smb_buffer;
3629
3630 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3631 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003632
Pavel Shilovsky88257362012-05-23 14:01:59 +04003633 smb_buffer->Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634 smb_buffer->Uid = ses->Suid;
3635 pSMB = (TCONX_REQ *) smb_buffer;
3636 pSMBr = (TCONX_RSP *) smb_buffer_response;
3637
3638 pSMB->AndXCommand = 0xFF;
3639 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003640 bcc_ptr = &pSMB->Password[0];
Aurelien Aptelb327a712018-01-24 13:46:10 +01003641 if (tcon->pipe || (ses->server->sec_mode & SECMODE_USER)) {
Steve Frencheeac8042006-01-13 21:34:58 -08003642 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00003643 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08003644 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00003645 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08003646 } else {
Shirish Pargaonkar540b2e32011-01-18 22:33:54 -06003647 pSMB->PasswordLength = cpu_to_le16(CIFS_AUTH_RESP_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08003648 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
3649 specified as required (when that support is added to
3650 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00003651 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08003652 by Samba (not sure whether other servers allow
3653 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00003654#ifdef CONFIG_CIFS_WEAK_PW_HASH
Jeff Layton04912d62010-04-24 07:57:45 -04003655 if ((global_secflags & CIFSSEC_MAY_LANMAN) &&
Jeff Layton3f618222013-06-12 19:52:14 -05003656 (ses->sectype == LANMAN))
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -05003657 calc_lanman_hash(tcon->password, ses->server->cryptkey,
Steve French96daf2b2011-05-27 04:34:02 +00003658 ses->server->sec_mode &
Jeff Layton4e53a3f2008-12-05 20:41:21 -05003659 SECMODE_PW_ENCRYPT ? true : false,
3660 bcc_ptr);
Steve French7c7b25b2006-06-01 19:20:10 +00003661 else
3662#endif /* CIFS_WEAK_PW_HASH */
Shirish Pargaonkaree2c9252011-01-27 09:58:04 -06003663 rc = SMBNTencrypt(tcon->password, ses->server->cryptkey,
Shirish Pargaonkar9ef59922011-10-20 13:21:59 -05003664 bcc_ptr, nls_codepage);
Steve Frenchf3a31a22015-03-26 19:23:20 -05003665 if (rc) {
3666 cifs_dbg(FYI, "%s Can't generate NTLM rsp. Error: %d\n",
3667 __func__, rc);
3668 cifs_buf_release(smb_buffer);
3669 return rc;
3670 }
Steve Frencheeac8042006-01-13 21:34:58 -08003671
Shirish Pargaonkar540b2e32011-01-18 22:33:54 -06003672 bcc_ptr += CIFS_AUTH_RESP_SIZE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003673 if (ses->capabilities & CAP_UNICODE) {
Steve French7c7b25b2006-06-01 19:20:10 +00003674 /* must align unicode strings */
3675 *bcc_ptr = 0; /* null byte password */
3676 bcc_ptr++;
3677 }
Steve Frencheeac8042006-01-13 21:34:58 -08003678 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003679
Jeff Layton38d77c52013-05-26 07:01:00 -04003680 if (ses->server->sign)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3682
3683 if (ses->capabilities & CAP_STATUS32) {
3684 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3685 }
3686 if (ses->capabilities & CAP_DFS) {
3687 smb_buffer->Flags2 |= SMBFLG2_DFS;
3688 }
3689 if (ses->capabilities & CAP_UNICODE) {
3690 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3691 length =
Steve Frenchacbbb762012-01-18 22:32:33 -06003692 cifs_strtoUTF16((__le16 *) bcc_ptr, tree,
Steve French50c2f752007-07-13 00:33:32 +00003693 6 /* max utf8 char length in bytes */ *
Steve Frencha878fb22006-05-30 18:04:19 +00003694 (/* server len*/ + 256 /* share len */), nls_codepage);
3695 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003696 bcc_ptr += 2; /* skip trailing null */
3697 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003698 strcpy(bcc_ptr, tree);
3699 bcc_ptr += strlen(tree) + 1;
3700 }
3701 strcpy(bcc_ptr, "?????");
3702 bcc_ptr += strlen("?????");
3703 bcc_ptr += 1;
3704 count = bcc_ptr - &pSMB->Password[0];
Qinglang Miao1a0e7f72020-07-25 16:56:01 +08003705 be32_add_cpu(&pSMB->hdr.smb_buf_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706 pSMB->ByteCount = cpu_to_le16(count);
3707
Steve French133672e2007-11-13 22:41:37 +00003708 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
Jeff Layton77499812011-01-11 07:24:23 -05003709 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003710
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711 /* above now done in SendReceive */
Aurelien Aptelb327a712018-01-24 13:46:10 +01003712 if (rc == 0) {
Steve French0e0d2cf2009-05-01 05:27:32 +00003713 bool is_unicode;
3714
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715 tcon->tidStatus = CifsGood;
Steve French3b795212008-11-13 19:45:32 +00003716 tcon->need_reconnect = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003717 tcon->tid = smb_buffer_response->Tid;
3718 bcc_ptr = pByteArea(smb_buffer_response);
Jeff Layton690c5222011-01-20 13:36:51 -05003719 bytes_left = get_bcc(smb_buffer_response);
Jeff Laytoncc20c032009-04-30 07:16:21 -04003720 length = strnlen(bcc_ptr, bytes_left - 2);
Steve French0e0d2cf2009-05-01 05:27:32 +00003721 if (smb_buffer->Flags2 & SMBFLG2_UNICODE)
3722 is_unicode = true;
3723 else
3724 is_unicode = false;
3725
Jeff Laytoncc20c032009-04-30 07:16:21 -04003726
Steve French50c2f752007-07-13 00:33:32 +00003727 /* skip service field (NB: this field is always ASCII) */
Steve French7f8ed422007-09-28 22:28:55 +00003728 if (length == 3) {
3729 if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') &&
3730 (bcc_ptr[2] == 'C')) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003731 cifs_dbg(FYI, "IPC connection\n");
Aurelien Aptelb327a712018-01-24 13:46:10 +01003732 tcon->ipc = true;
3733 tcon->pipe = true;
Steve French7f8ed422007-09-28 22:28:55 +00003734 }
3735 } else if (length == 2) {
3736 if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) {
3737 /* the most common case */
Joe Perchesf96637b2013-05-04 22:12:25 -05003738 cifs_dbg(FYI, "disk share connection\n");
Steve French7f8ed422007-09-28 22:28:55 +00003739 }
3740 }
Steve French50c2f752007-07-13 00:33:32 +00003741 bcc_ptr += length + 1;
Jeff Laytoncc20c032009-04-30 07:16:21 -04003742 bytes_left -= (length + 1);
Zhao Hongjiang46b51d02013-06-24 01:57:47 -05003743 strlcpy(tcon->treeName, tree, sizeof(tcon->treeName));
Jeff Laytoncc20c032009-04-30 07:16:21 -04003744
3745 /* mostly informational -- no need to fail on error here */
Jeff Layton90a98b22009-07-20 13:40:52 -04003746 kfree(tcon->nativeFileSystem);
Steve Frenchacbbb762012-01-18 22:32:33 -06003747 tcon->nativeFileSystem = cifs_strndup_from_utf16(bcc_ptr,
Steve French0e0d2cf2009-05-01 05:27:32 +00003748 bytes_left, is_unicode,
Jeff Laytoncc20c032009-04-30 07:16:21 -04003749 nls_codepage);
3750
Joe Perchesf96637b2013-05-04 22:12:25 -05003751 cifs_dbg(FYI, "nativeFileSystem=%s\n", tcon->nativeFileSystem);
Jeff Laytoncc20c032009-04-30 07:16:21 -04003752
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003753 if ((smb_buffer_response->WordCount == 3) ||
Steve French1a4e15a2006-10-12 21:33:51 +00003754 (smb_buffer_response->WordCount == 7))
3755 /* field is in same location */
Steve French39798772006-05-31 22:40:51 +00003756 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3757 else
3758 tcon->Flags = 0;
Joe Perchesf96637b2013-05-04 22:12:25 -05003759 cifs_dbg(FYI, "Tcon flags: 0x%x\n", tcon->Flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003760 }
3761
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003762 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003763 return rc;
3764}
3765
Al Viro2e32cf52013-10-03 12:53:37 -04003766static void delayed_free(struct rcu_head *p)
3767{
Ronnie Sahlbergd17abdf72020-11-10 08:59:26 +10003768 struct cifs_sb_info *cifs_sb = container_of(p, struct cifs_sb_info, rcu);
3769
3770 unload_nls(cifs_sb->local_nls);
Ronnie Sahlbergc741cba2020-12-14 16:40:16 +10003771 smb3_cleanup_fs_context(cifs_sb->ctx);
Ronnie Sahlbergd17abdf72020-11-10 08:59:26 +10003772 kfree(cifs_sb);
Al Viro2e32cf52013-10-03 12:53:37 -04003773}
3774
Al Viro2a9b9952011-06-17 09:27:16 -04003775void
3776cifs_umount(struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777{
Jeff Laytonb647c352010-10-28 11:16:44 -04003778 struct rb_root *root = &cifs_sb->tlink_tree;
3779 struct rb_node *node;
3780 struct tcon_link *tlink;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003781
Jeff Layton2de970f2010-10-06 19:51:12 -04003782 cancel_delayed_work_sync(&cifs_sb->prune_tlinks);
3783
Jeff Laytonb647c352010-10-28 11:16:44 -04003784 spin_lock(&cifs_sb->tlink_tree_lock);
3785 while ((node = rb_first(root))) {
3786 tlink = rb_entry(node, struct tcon_link, tl_rbnode);
3787 cifs_get_tlink(tlink);
3788 clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
3789 rb_erase(node, root);
Steve French50c2f752007-07-13 00:33:32 +00003790
Jeff Laytonb647c352010-10-28 11:16:44 -04003791 spin_unlock(&cifs_sb->tlink_tree_lock);
3792 cifs_put_tlink(tlink);
3793 spin_lock(&cifs_sb->tlink_tree_lock);
3794 }
3795 spin_unlock(&cifs_sb->tlink_tree_lock);
Jeff Layton9d002df2010-10-06 19:51:11 -04003796
Aurelien Aptela6b50582016-05-25 19:59:09 +02003797 kfree(cifs_sb->prepath);
Paulo Alcantara93d5cb52018-11-14 17:13:25 -02003798#ifdef CONFIG_CIFS_DFS_UPCALL
Paulo Alcantarac9f71102021-06-04 19:25:29 -03003799 dfs_cache_put_refsrv_sessions(&cifs_sb->dfs_mount_id);
Paulo Alcantara93d5cb52018-11-14 17:13:25 -02003800 kfree(cifs_sb->origin_fullpath);
3801#endif
Al Viro2e32cf52013-10-03 12:53:37 -04003802 call_rcu(&cifs_sb->rcu, delayed_free);
Steve French50c2f752007-07-13 00:33:32 +00003803}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003804
Pavel Shilovsky286170a2012-05-25 10:43:58 +04003805int
3806cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003807{
3808 int rc = 0;
Aurelien Aptelf6a6bf72019-09-20 06:22:14 +02003809 struct TCP_Server_Info *server = cifs_ses_server(ses);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003810
Pavel Shilovsky286170a2012-05-25 10:43:58 +04003811 if (!server->ops->need_neg || !server->ops->negotiate)
3812 return -ENOSYS;
3813
Jeff Layton198b5682010-04-24 07:57:48 -04003814 /* only send once per connect */
Pavel Shilovsky286170a2012-05-25 10:43:58 +04003815 if (!server->ops->need_neg(server))
Jeff Layton198b5682010-04-24 07:57:48 -04003816 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817
Pavel Shilovsky286170a2012-05-25 10:43:58 +04003818 rc = server->ops->negotiate(xid, ses);
Jeff Layton198b5682010-04-24 07:57:48 -04003819 if (rc == 0) {
3820 spin_lock(&GlobalMid_Lock);
Jeff Layton7fdbaa12011-06-10 16:14:57 -04003821 if (server->tcpStatus == CifsNeedNegotiate)
Jeff Layton198b5682010-04-24 07:57:48 -04003822 server->tcpStatus = CifsGood;
3823 else
3824 rc = -EHOSTDOWN;
3825 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003826 }
Steve French26b994f2008-08-06 05:11:33 +00003827
Jeff Layton198b5682010-04-24 07:57:48 -04003828 return rc;
3829}
Steve French26b994f2008-08-06 05:11:33 +00003830
Pavel Shilovsky58c45c52012-05-25 10:54:49 +04003831int
3832cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
3833 struct nls_table *nls_info)
Jeff Layton198b5682010-04-24 07:57:48 -04003834{
Pavel Shilovsky58c45c52012-05-25 10:54:49 +04003835 int rc = -ENOSYS;
Aurelien Aptelf6a6bf72019-09-20 06:22:14 +02003836 struct TCP_Server_Info *server = cifs_ses_server(ses);
Jeff Layton198b5682010-04-24 07:57:48 -04003837
Aurelien Apteld70e9fa2019-09-20 06:31:10 +02003838 if (!ses->binding) {
3839 ses->capabilities = server->capabilities;
YANG LIed6b1922021-01-11 17:15:28 +08003840 if (!linuxExtEnabled)
Aurelien Apteld70e9fa2019-09-20 06:31:10 +02003841 ses->capabilities &= (~server->vals->cap_unix);
3842
3843 if (ses->auth_key.response) {
3844 cifs_dbg(FYI, "Free previous auth_key.response = %p\n",
3845 ses->auth_key.response);
3846 kfree(ses->auth_key.response);
3847 ses->auth_key.response = NULL;
3848 ses->auth_key.len = 0;
3849 }
3850 }
Steve French20418ac2009-04-30 16:13:32 +00003851
Joe Perchesf96637b2013-05-04 22:12:25 -05003852 cifs_dbg(FYI, "Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d\n",
Steve French96daf2b2011-05-27 04:34:02 +00003853 server->sec_mode, server->capabilities, server->timeAdj);
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003854
Pavel Shilovsky58c45c52012-05-25 10:54:49 +04003855 if (server->ops->sess_setup)
3856 rc = server->ops->sess_setup(xid, ses, nls_info);
3857
Shirish Pargaonkard4e63bd2013-08-29 08:35:09 -05003858 if (rc)
Ronnie Sahlbergafe6f652019-08-28 17:15:35 +10003859 cifs_server_dbg(VFS, "Send error in SessSetup = %d\n", rc);
Shirish Pargaonkar21e73392010-10-21 06:42:55 -05003860
Linus Torvalds1da177e2005-04-16 15:20:36 -07003861 return rc;
3862}
3863
Jeff Layton8a8798a2012-01-17 16:09:15 -05003864static int
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003865cifs_set_vol_auth(struct smb3_fs_context *ctx, struct cifs_ses *ses)
Jeff Layton8a8798a2012-01-17 16:09:15 -05003866{
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003867 ctx->sectype = ses->sectype;
Jeff Layton3f618222013-06-12 19:52:14 -05003868
3869 /* krb5 is special, since we don't need username or pw */
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003870 if (ctx->sectype == Kerberos)
Jeff Layton8a8798a2012-01-17 16:09:15 -05003871 return 0;
Jeff Layton8a8798a2012-01-17 16:09:15 -05003872
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003873 return cifs_set_cifscreds(ctx, ses);
Jeff Layton8a8798a2012-01-17 16:09:15 -05003874}
3875
Steve French96daf2b2011-05-27 04:34:02 +00003876static struct cifs_tcon *
Eric W. Biederman6d4a0832013-02-06 01:48:56 -08003877cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid)
Jeff Layton9d002df2010-10-06 19:51:11 -04003878{
Jeff Layton8a8798a2012-01-17 16:09:15 -05003879 int rc;
Steve French96daf2b2011-05-27 04:34:02 +00003880 struct cifs_tcon *master_tcon = cifs_sb_master_tcon(cifs_sb);
3881 struct cifs_ses *ses;
3882 struct cifs_tcon *tcon = NULL;
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003883 struct smb3_fs_context *ctx;
Jeff Layton9d002df2010-10-06 19:51:11 -04003884
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003885 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
3886 if (ctx == NULL)
Dan Carpenter803ab972012-01-24 11:39:22 +03003887 return ERR_PTR(-ENOMEM);
Jeff Layton9d002df2010-10-06 19:51:11 -04003888
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003889 ctx->local_nls = cifs_sb->local_nls;
3890 ctx->linux_uid = fsuid;
3891 ctx->cred_uid = fsuid;
3892 ctx->UNC = master_tcon->treeName;
3893 ctx->retry = master_tcon->retry;
3894 ctx->nocase = master_tcon->nocase;
3895 ctx->nohandlecache = master_tcon->nohandlecache;
3896 ctx->local_lease = master_tcon->local_lease;
3897 ctx->no_lease = master_tcon->no_lease;
3898 ctx->resilient = master_tcon->use_resilient;
3899 ctx->persistent = master_tcon->use_persistent;
3900 ctx->handle_timeout = master_tcon->handle_timeout;
3901 ctx->no_linux_ext = !master_tcon->unix_ext;
3902 ctx->linux_ext = master_tcon->posix_extensions;
3903 ctx->sectype = master_tcon->ses->sectype;
3904 ctx->sign = master_tcon->ses->sign;
3905 ctx->seal = master_tcon->seal;
Samuel Cabrero0ac4e292020-12-11 22:59:29 -06003906 ctx->witness = master_tcon->use_witness;
Jeff Layton9d002df2010-10-06 19:51:11 -04003907
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003908 rc = cifs_set_vol_auth(ctx, master_tcon->ses);
Jeff Layton8a8798a2012-01-17 16:09:15 -05003909 if (rc) {
3910 tcon = ERR_PTR(rc);
3911 goto out;
3912 }
Jeff Layton9d002df2010-10-06 19:51:11 -04003913
3914 /* get a reference for the same TCP session */
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05303915 spin_lock(&cifs_tcp_ses_lock);
Jeff Layton9d002df2010-10-06 19:51:11 -04003916 ++master_tcon->ses->server->srv_count;
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +05303917 spin_unlock(&cifs_tcp_ses_lock);
Jeff Layton9d002df2010-10-06 19:51:11 -04003918
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003919 ses = cifs_get_smb_ses(master_tcon->ses->server, ctx);
Jeff Layton9d002df2010-10-06 19:51:11 -04003920 if (IS_ERR(ses)) {
Steve French96daf2b2011-05-27 04:34:02 +00003921 tcon = (struct cifs_tcon *)ses;
Pavel Shilovsky53e0e112016-11-04 11:50:31 -07003922 cifs_put_tcp_session(master_tcon->ses->server, 0);
Jeff Layton9d002df2010-10-06 19:51:11 -04003923 goto out;
3924 }
3925
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003926 tcon = cifs_get_tcon(ses, ctx);
Jeff Layton9d002df2010-10-06 19:51:11 -04003927 if (IS_ERR(tcon)) {
3928 cifs_put_smb_ses(ses);
3929 goto out;
3930 }
3931
Pavel Shilovsky29e20f92012-07-13 13:58:14 +04003932 if (cap_unix(ses))
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003933 reset_cifs_unix_caps(0, tcon, NULL, ctx);
Steve Frenchb3266142018-05-20 23:41:10 -05003934
Jeff Layton9d002df2010-10-06 19:51:11 -04003935out:
Ronnie Sahlberg3fa1c6d2020-12-09 23:07:12 -06003936 kfree(ctx->username);
3937 kfree_sensitive(ctx->password);
3938 kfree(ctx);
Jeff Layton9d002df2010-10-06 19:51:11 -04003939
3940 return tcon;
3941}
3942
Steve French96daf2b2011-05-27 04:34:02 +00003943struct cifs_tcon *
Jeff Layton9d002df2010-10-06 19:51:11 -04003944cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb)
3945{
3946 return tlink_tcon(cifs_sb_master_tlink(cifs_sb));
3947}
3948
Jeff Laytonb647c352010-10-28 11:16:44 -04003949/* find and return a tlink with given uid */
3950static struct tcon_link *
Eric W. Biederman6d4a0832013-02-06 01:48:56 -08003951tlink_rb_search(struct rb_root *root, kuid_t uid)
Jeff Laytonb647c352010-10-28 11:16:44 -04003952{
3953 struct rb_node *node = root->rb_node;
3954 struct tcon_link *tlink;
3955
3956 while (node) {
3957 tlink = rb_entry(node, struct tcon_link, tl_rbnode);
3958
Eric W. Biederman6d4a0832013-02-06 01:48:56 -08003959 if (uid_gt(tlink->tl_uid, uid))
Jeff Laytonb647c352010-10-28 11:16:44 -04003960 node = node->rb_left;
Eric W. Biederman6d4a0832013-02-06 01:48:56 -08003961 else if (uid_lt(tlink->tl_uid, uid))
Jeff Laytonb647c352010-10-28 11:16:44 -04003962 node = node->rb_right;
3963 else
3964 return tlink;
3965 }
3966 return NULL;
3967}
3968
3969/* insert a tcon_link into the tree */
3970static void
3971tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink)
3972{
3973 struct rb_node **new = &(root->rb_node), *parent = NULL;
3974 struct tcon_link *tlink;
3975
3976 while (*new) {
3977 tlink = rb_entry(*new, struct tcon_link, tl_rbnode);
3978 parent = *new;
3979
Eric W. Biederman6d4a0832013-02-06 01:48:56 -08003980 if (uid_gt(tlink->tl_uid, new_tlink->tl_uid))
Jeff Laytonb647c352010-10-28 11:16:44 -04003981 new = &((*new)->rb_left);
3982 else
3983 new = &((*new)->rb_right);
3984 }
3985
3986 rb_link_node(&new_tlink->tl_rbnode, parent, new);
3987 rb_insert_color(&new_tlink->tl_rbnode, root);
3988}
3989
Jeff Layton9d002df2010-10-06 19:51:11 -04003990/*
3991 * Find or construct an appropriate tcon given a cifs_sb and the fsuid of the
3992 * current task.
3993 *
3994 * If the superblock doesn't refer to a multiuser mount, then just return
3995 * the master tcon for the mount.
3996 *
Suresh Jayaraman6ef933a2010-11-03 10:53:49 +05303997 * First, search the rbtree for an existing tcon for this fsuid. If one
Jeff Layton9d002df2010-10-06 19:51:11 -04003998 * exists, then check to see if it's pending construction. If it is then wait
3999 * for construction to complete. Once it's no longer pending, check to see if
4000 * it failed and either return an error or retry construction, depending on
4001 * the timeout.
4002 *
4003 * If one doesn't exist then insert a new tcon_link struct into the tree and
4004 * try to construct a new one.
4005 */
4006struct tcon_link *
4007cifs_sb_tlink(struct cifs_sb_info *cifs_sb)
4008{
4009 int ret;
Eric W. Biederman6d4a0832013-02-06 01:48:56 -08004010 kuid_t fsuid = current_fsuid();
Jeff Layton9d002df2010-10-06 19:51:11 -04004011 struct tcon_link *tlink, *newtlink;
4012
4013 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
4014 return cifs_get_tlink(cifs_sb_master_tlink(cifs_sb));
4015
4016 spin_lock(&cifs_sb->tlink_tree_lock);
Jeff Laytonb647c352010-10-28 11:16:44 -04004017 tlink = tlink_rb_search(&cifs_sb->tlink_tree, fsuid);
Jeff Layton9d002df2010-10-06 19:51:11 -04004018 if (tlink)
4019 cifs_get_tlink(tlink);
4020 spin_unlock(&cifs_sb->tlink_tree_lock);
4021
4022 if (tlink == NULL) {
4023 newtlink = kzalloc(sizeof(*tlink), GFP_KERNEL);
4024 if (newtlink == NULL)
4025 return ERR_PTR(-ENOMEM);
Jeff Laytonb647c352010-10-28 11:16:44 -04004026 newtlink->tl_uid = fsuid;
Jeff Layton9d002df2010-10-06 19:51:11 -04004027 newtlink->tl_tcon = ERR_PTR(-EACCES);
4028 set_bit(TCON_LINK_PENDING, &newtlink->tl_flags);
4029 set_bit(TCON_LINK_IN_TREE, &newtlink->tl_flags);
4030 cifs_get_tlink(newtlink);
4031
Jeff Layton9d002df2010-10-06 19:51:11 -04004032 spin_lock(&cifs_sb->tlink_tree_lock);
4033 /* was one inserted after previous search? */
Jeff Laytonb647c352010-10-28 11:16:44 -04004034 tlink = tlink_rb_search(&cifs_sb->tlink_tree, fsuid);
Jeff Layton9d002df2010-10-06 19:51:11 -04004035 if (tlink) {
4036 cifs_get_tlink(tlink);
4037 spin_unlock(&cifs_sb->tlink_tree_lock);
Jeff Layton9d002df2010-10-06 19:51:11 -04004038 kfree(newtlink);
4039 goto wait_for_construction;
4040 }
Jeff Layton9d002df2010-10-06 19:51:11 -04004041 tlink = newtlink;
Jeff Laytonb647c352010-10-28 11:16:44 -04004042 tlink_rb_insert(&cifs_sb->tlink_tree, tlink);
4043 spin_unlock(&cifs_sb->tlink_tree_lock);
Jeff Layton9d002df2010-10-06 19:51:11 -04004044 } else {
4045wait_for_construction:
4046 ret = wait_on_bit(&tlink->tl_flags, TCON_LINK_PENDING,
Jeff Layton9d002df2010-10-06 19:51:11 -04004047 TASK_INTERRUPTIBLE);
4048 if (ret) {
4049 cifs_put_tlink(tlink);
NeilBrown74316202014-07-07 15:16:04 +10004050 return ERR_PTR(-ERESTARTSYS);
Jeff Layton9d002df2010-10-06 19:51:11 -04004051 }
4052
4053 /* if it's good, return it */
4054 if (!IS_ERR(tlink->tl_tcon))
4055 return tlink;
4056
4057 /* return error if we tried this already recently */
4058 if (time_before(jiffies, tlink->tl_time + TLINK_ERROR_EXPIRE)) {
4059 cifs_put_tlink(tlink);
4060 return ERR_PTR(-EACCES);
4061 }
4062
4063 if (test_and_set_bit(TCON_LINK_PENDING, &tlink->tl_flags))
4064 goto wait_for_construction;
4065 }
4066
4067 tlink->tl_tcon = cifs_construct_tcon(cifs_sb, fsuid);
4068 clear_bit(TCON_LINK_PENDING, &tlink->tl_flags);
4069 wake_up_bit(&tlink->tl_flags, TCON_LINK_PENDING);
4070
4071 if (IS_ERR(tlink->tl_tcon)) {
4072 cifs_put_tlink(tlink);
4073 return ERR_PTR(-EACCES);
4074 }
4075
4076 return tlink;
4077}
Jeff Layton2de970f2010-10-06 19:51:12 -04004078
4079/*
4080 * periodic workqueue job that scans tcon_tree for a superblock and closes
4081 * out tcons.
4082 */
4083static void
4084cifs_prune_tlinks(struct work_struct *work)
4085{
4086 struct cifs_sb_info *cifs_sb = container_of(work, struct cifs_sb_info,
4087 prune_tlinks.work);
Jeff Laytonb647c352010-10-28 11:16:44 -04004088 struct rb_root *root = &cifs_sb->tlink_tree;
Colin Ian King37e12f52018-01-17 09:52:39 +00004089 struct rb_node *node;
Jeff Laytonb647c352010-10-28 11:16:44 -04004090 struct rb_node *tmp;
4091 struct tcon_link *tlink;
Jeff Layton2de970f2010-10-06 19:51:12 -04004092
Jeff Laytonb647c352010-10-28 11:16:44 -04004093 /*
4094 * Because we drop the spinlock in the loop in order to put the tlink
4095 * it's not guarded against removal of links from the tree. The only
4096 * places that remove entries from the tree are this function and
4097 * umounts. Because this function is non-reentrant and is canceled
4098 * before umount can proceed, this is safe.
4099 */
4100 spin_lock(&cifs_sb->tlink_tree_lock);
4101 node = rb_first(root);
4102 while (node != NULL) {
4103 tmp = node;
4104 node = rb_next(tmp);
4105 tlink = rb_entry(tmp, struct tcon_link, tl_rbnode);
4106
4107 if (test_bit(TCON_LINK_MASTER, &tlink->tl_flags) ||
4108 atomic_read(&tlink->tl_count) != 0 ||
4109 time_after(tlink->tl_time + TLINK_IDLE_EXPIRE, jiffies))
4110 continue;
4111
4112 cifs_get_tlink(tlink);
4113 clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
4114 rb_erase(tmp, root);
4115
Jeff Layton2de970f2010-10-06 19:51:12 -04004116 spin_unlock(&cifs_sb->tlink_tree_lock);
Jeff Laytonb647c352010-10-28 11:16:44 -04004117 cifs_put_tlink(tlink);
4118 spin_lock(&cifs_sb->tlink_tree_lock);
4119 }
4120 spin_unlock(&cifs_sb->tlink_tree_lock);
Jeff Layton2de970f2010-10-06 19:51:12 -04004121
Jeff Laytonda472fc2012-03-23 14:40:53 -04004122 queue_delayed_work(cifsiod_wq, &cifs_sb->prune_tlinks,
Jeff Layton2de970f2010-10-06 19:51:12 -04004123 TLINK_IDLE_EXPIRE);
4124}
Stefan Metzmacher565674d2020-07-21 09:36:38 -03004125
4126#ifdef CONFIG_CIFS_DFS_UPCALL
4127int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const struct nls_table *nlsc)
4128{
4129 int rc;
4130 struct TCP_Server_Info *server = tcon->ses->server;
4131 const struct smb_version_operations *ops = server->ops;
4132 struct dfs_cache_tgt_list tl;
4133 struct dfs_cache_tgt_iterator *it = NULL;
4134 char *tree;
4135 const char *tcp_host;
4136 size_t tcp_host_len;
4137 const char *dfs_host;
4138 size_t dfs_host_len;
Paulo Alcantara7548e1d2020-07-21 09:36:42 -03004139 char *share = NULL, *prefix = NULL;
Paulo Alcantara11375a52020-07-21 09:36:43 -03004140 struct dfs_info3_param ref = {0};
4141 bool isroot;
Stefan Metzmacher565674d2020-07-21 09:36:38 -03004142
4143 tree = kzalloc(MAX_TREE_SIZE, GFP_KERNEL);
4144 if (!tree)
4145 return -ENOMEM;
4146
4147 if (!tcon->dfs_path) {
4148 if (tcon->ipc) {
4149 scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$", server->hostname);
4150 rc = ops->tree_connect(xid, tcon->ses, tree, tcon, nlsc);
4151 } else {
4152 rc = ops->tree_connect(xid, tcon->ses, tcon->treeName, tcon, nlsc);
4153 }
4154 goto out;
4155 }
4156
Paulo Alcantara11375a52020-07-21 09:36:43 -03004157 rc = dfs_cache_noreq_find(tcon->dfs_path + 1, &ref, &tl);
Stefan Metzmacher565674d2020-07-21 09:36:38 -03004158 if (rc)
4159 goto out;
Paulo Alcantara11375a52020-07-21 09:36:43 -03004160 isroot = ref.server_type == DFS_TYPE_ROOT;
4161 free_dfs_info_param(&ref);
Stefan Metzmacher565674d2020-07-21 09:36:38 -03004162
4163 extract_unc_hostname(server->hostname, &tcp_host, &tcp_host_len);
4164
4165 for (it = dfs_cache_get_tgt_iterator(&tl); it; it = dfs_cache_get_next_tgt(&tl, it)) {
Stefan Metzmacher565674d2020-07-21 09:36:38 -03004166 bool target_match;
4167
Paulo Alcantara7548e1d2020-07-21 09:36:42 -03004168 kfree(share);
4169 kfree(prefix);
Colin Ian Kingc6a80e12020-07-31 18:13:42 +01004170 share = NULL;
4171 prefix = NULL;
Paulo Alcantara7548e1d2020-07-21 09:36:42 -03004172
4173 rc = dfs_cache_get_tgt_share(tcon->dfs_path + 1, it, &share, &prefix);
Stefan Metzmacher565674d2020-07-21 09:36:38 -03004174 if (rc) {
4175 cifs_dbg(VFS, "%s: failed to parse target share %d\n",
4176 __func__, rc);
4177 continue;
4178 }
4179
4180 extract_unc_hostname(share, &dfs_host, &dfs_host_len);
4181
4182 if (dfs_host_len != tcp_host_len
4183 || strncasecmp(dfs_host, tcp_host, dfs_host_len) != 0) {
4184 cifs_dbg(FYI, "%s: %.*s doesn't match %.*s\n", __func__, (int)dfs_host_len,
4185 dfs_host, (int)tcp_host_len, tcp_host);
4186
4187 rc = match_target_ip(server, dfs_host, dfs_host_len, &target_match);
4188 if (rc) {
4189 cifs_dbg(VFS, "%s: failed to match target ip: %d\n", __func__, rc);
4190 break;
4191 }
4192
4193 if (!target_match) {
4194 cifs_dbg(FYI, "%s: skipping target\n", __func__);
4195 continue;
4196 }
4197 }
4198
4199 if (tcon->ipc) {
Paulo Alcantara7548e1d2020-07-21 09:36:42 -03004200 scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$", share);
Stefan Metzmacher565674d2020-07-21 09:36:38 -03004201 rc = ops->tree_connect(xid, tcon->ses, tree, tcon, nlsc);
4202 } else {
Paulo Alcantara7548e1d2020-07-21 09:36:42 -03004203 scnprintf(tree, MAX_TREE_SIZE, "\\%s", share);
Stefan Metzmacher565674d2020-07-21 09:36:38 -03004204 rc = ops->tree_connect(xid, tcon->ses, tree, tcon, nlsc);
Paulo Alcantara11375a52020-07-21 09:36:43 -03004205 /* Only handle prefix paths of DFS link targets */
4206 if (!rc && !isroot) {
Paulo Alcantara7548e1d2020-07-21 09:36:42 -03004207 rc = update_super_prepath(tcon, prefix);
Stefan Metzmacher565674d2020-07-21 09:36:38 -03004208 break;
4209 }
4210 }
4211 if (rc == -EREMOTE)
4212 break;
4213 }
4214
Paulo Alcantara7548e1d2020-07-21 09:36:42 -03004215 kfree(share);
4216 kfree(prefix);
4217
Stefan Metzmacher565674d2020-07-21 09:36:38 -03004218 if (!rc) {
4219 if (it)
4220 rc = dfs_cache_noreq_update_tgthint(tcon->dfs_path + 1, it);
4221 else
4222 rc = -ENOENT;
4223 }
4224 dfs_cache_free_tgts(&tl);
4225out:
4226 kfree(tree);
4227 return rc;
4228}
4229#else
4230int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const struct nls_table *nlsc)
4231{
4232 const struct smb_version_operations *ops = tcon->ses->server->ops;
4233
4234 return ops->tree_connect(xid, tcon->ses, tcon->treeName, tcon, nlsc);
4235}
4236#endif