blob: 3a84a375cb6f4d535443232ed0ae408611a917d6 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/connect.c
3 *
Steve French366781c2008-01-25 10:12:41 +00004 * Copyright (C) International Business Machines Corp., 2002,2008
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * This library is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published
9 * by the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
15 * the GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library; if not, write to the Free Software
Steve Frenchfb8c4b12007-07-10 01:16:18 +000019 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Linus Torvalds1da177e2005-04-16 15:20:36 -070020 */
21#include <linux/fs.h>
22#include <linux/net.h>
23#include <linux/string.h>
24#include <linux/list.h>
25#include <linux/wait.h>
26#include <linux/ipv6.h>
27#include <linux/pagemap.h>
28#include <linux/ctype.h>
29#include <linux/utsname.h>
30#include <linux/mempool.h>
Steve Frenchb8643e12005-04-28 22:41:07 -070031#include <linux/delay.h>
Steve Frenchf1914012005-08-18 09:37:34 -070032#include <linux/completion.h>
Igor Mammedovaaf737a2007-04-03 19:16:43 +000033#include <linux/kthread.h>
Steve French0ae0efa2005-10-10 10:57:19 -070034#include <linux/pagevec.h>
Nigel Cunningham7dfb7102006-12-06 20:34:23 -080035#include <linux/freezer.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <asm/uaccess.h>
37#include <asm/processor.h>
38#include "cifspdu.h"
39#include "cifsglob.h"
40#include "cifsproto.h"
41#include "cifs_unicode.h"
42#include "cifs_debug.h"
43#include "cifs_fs_sb.h"
44#include "ntlmssp.h"
45#include "nterr.h"
46#include "rfc1002pdu.h"
Steve Frencha2653eb2005-11-10 15:33:38 -080047#include "cn_cifs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
49#define CIFS_PORT 445
50#define RFC1001_PORT 139
51
Linus Torvalds1da177e2005-04-16 15:20:36 -070052extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
53 unsigned char *p24);
54
55extern mempool_t *cifs_req_poolp;
56
57struct smb_vol {
58 char *username;
59 char *password;
60 char *domainname;
61 char *UNC;
62 char *UNCip;
Steve French95b1cb92008-05-15 16:44:38 +000063 char *in6_addr; /* ipv6 address as human readable form of in6_addr */
Linus Torvalds1da177e2005-04-16 15:20:36 -070064 char *iocharset; /* local code page for mapping to and from Unicode */
65 char source_rfc1001_name[16]; /* netbios name of client */
Steve Frencha10faeb22005-08-22 21:38:31 -070066 char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 uid_t linux_uid;
68 gid_t linux_gid;
69 mode_t file_mode;
70 mode_t dir_mode;
Steve French189acaa2006-06-23 02:33:48 +000071 unsigned secFlg;
Steve French4b18f2a2008-04-29 00:06:05 +000072 bool rw:1;
73 bool retry:1;
74 bool intr:1;
75 bool setuids:1;
76 bool override_uid:1;
77 bool override_gid:1;
Jeff Laytond0a9c072008-05-12 22:23:49 +000078 bool dynperm:1;
Steve French4b18f2a2008-04-29 00:06:05 +000079 bool noperm:1;
80 bool no_psx_acl:1; /* set if posix acl support should be disabled */
81 bool cifs_acl:1;
82 bool no_xattr:1; /* set if xattr (EA) support should be disabled*/
83 bool server_ino:1; /* use inode numbers from server ie UniqueId */
84 bool direct_io:1;
Steve French95b1cb92008-05-15 16:44:38 +000085 bool remap:1; /* set to remap seven reserved chars in filenames */
86 bool posix_paths:1; /* unset to not ask for posix pathnames. */
Steve French4b18f2a2008-04-29 00:06:05 +000087 bool no_linux_ext:1;
88 bool sfu_emul:1;
Steve French95b1cb92008-05-15 16:44:38 +000089 bool nullauth:1; /* attempt to authenticate with null user */
90 bool nocase:1; /* request case insensitive filenames */
91 bool nobrl:1; /* disable sending byte range locks to srv */
Steve French13a6e422008-12-02 17:24:33 +000092 bool mand_lock:1; /* send mandatory not posix byte range lock reqs */
Steve French95b1cb92008-05-15 16:44:38 +000093 bool seal:1; /* request transport encryption on share */
Steve French84210e92008-10-23 04:42:37 +000094 bool nodfs:1; /* Do not request DFS, even if available */
95 bool local_lease:1; /* check leases only on local system, not remote */
Steve Frenchedf1ae42008-10-29 00:47:57 +000096 bool noblocksnd:1;
97 bool noautotune:1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070098 unsigned int rsize;
99 unsigned int wsize;
100 unsigned int sockopt;
101 unsigned short int port;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000102 char *prepath;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103};
104
Jeff Laytonbcf4b102008-12-01 18:42:15 -0500105static int ipv4_connect(struct TCP_Server_Info *server);
Jeff Laytond5c56052008-12-01 18:42:33 -0500106static int ipv6_connect(struct TCP_Server_Info *server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107
Jeff Laytond5c56052008-12-01 18:42:33 -0500108/*
109 * cifs tcp session reconnection
110 *
111 * mark tcp session as reconnecting so temporarily locked
112 * mark all smb sessions as reconnecting for tcp session
113 * reconnect tcp session
114 * wake up waiters on reconnection? - (not needed currently)
115 */
Steve French2cd646a2006-09-28 19:43:08 +0000116static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117cifs_reconnect(struct TCP_Server_Info *server)
118{
119 int rc = 0;
Jeff Laytonf1987b42008-11-15 11:12:47 -0500120 struct list_head *tmp, *tmp2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 struct cifsSesInfo *ses;
122 struct cifsTconInfo *tcon;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000123 struct mid_q_entry *mid_entry;
Steve French50c2f752007-07-13 00:33:32 +0000124
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 spin_lock(&GlobalMid_Lock);
Jeff Layton469ee612008-10-16 18:46:39 +0000126 if (server->tcpStatus == CifsExiting) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000127 /* the demux thread will exit normally
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 next time through the loop */
129 spin_unlock(&GlobalMid_Lock);
130 return rc;
131 } else
132 server->tcpStatus = CifsNeedReconnect;
133 spin_unlock(&GlobalMid_Lock);
134 server->maxBuf = 0;
135
Steve Frenche4eb2952005-04-28 22:41:09 -0700136 cFYI(1, ("Reconnecting tcp session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137
138 /* before reconnecting the tcp session, mark the smb session (uid)
139 and the tid bad so they are not used until reconnected */
Jeff Layton14fbf502008-11-14 13:53:46 -0500140 read_lock(&cifs_tcp_ses_lock);
141 list_for_each(tmp, &server->smb_ses_list) {
142 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
143 ses->need_reconnect = true;
144 ses->ipc_tid = 0;
Jeff Laytonf1987b42008-11-15 11:12:47 -0500145 list_for_each(tmp2, &ses->tcon_list) {
146 tcon = list_entry(tmp2, struct cifsTconInfo, tcon_list);
147 tcon->need_reconnect = true;
148 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 }
Jeff Layton14fbf502008-11-14 13:53:46 -0500150 read_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 /* do not want to be sending data on a socket we are freeing */
Jeff Layton72ca5452008-12-01 07:09:36 -0500152 mutex_lock(&server->srv_mutex);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000153 if (server->ssocket) {
Steve French467a8f82007-06-27 22:41:32 +0000154 cFYI(1, ("State: 0x%x Flags: 0x%lx", server->ssocket->state,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 server->ssocket->flags));
Trond Myklebust91cf45f2007-11-12 18:10:39 -0800156 kernel_sock_shutdown(server->ssocket, SHUT_WR);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000157 cFYI(1, ("Post shutdown state: 0x%x Flags: 0x%lx",
Steve French467a8f82007-06-27 22:41:32 +0000158 server->ssocket->state,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 server->ssocket->flags));
160 sock_release(server->ssocket);
161 server->ssocket = NULL;
162 }
163
164 spin_lock(&GlobalMid_Lock);
165 list_for_each(tmp, &server->pending_mid_q) {
166 mid_entry = list_entry(tmp, struct
167 mid_q_entry,
168 qhead);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000169 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French09d1db52005-04-28 22:41:08 -0700170 /* Mark other intransit requests as needing
171 retry so we do not immediately mark the
172 session bad again (ie after we reconnect
173 below) as they timeout too */
Steve Frenchad8b15f2008-08-08 21:10:16 +0000174 mid_entry->midState = MID_RETRY_NEEDED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 }
176 }
177 spin_unlock(&GlobalMid_Lock);
Jeff Layton72ca5452008-12-01 07:09:36 -0500178 mutex_unlock(&server->srv_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179
Jeff Layton469ee612008-10-16 18:46:39 +0000180 while ((server->tcpStatus != CifsExiting) &&
181 (server->tcpStatus != CifsGood)) {
Steve French6c3d8902006-07-31 22:46:20 +0000182 try_to_freeze();
Jeff Laytonbcf4b102008-12-01 18:42:15 -0500183 if (server->addr.sockAddr6.sin6_family == AF_INET6)
Jeff Laytond5c56052008-12-01 18:42:33 -0500184 rc = ipv6_connect(server);
Jeff Laytonbcf4b102008-12-01 18:42:15 -0500185 else
186 rc = ipv4_connect(server);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000187 if (rc) {
188 cFYI(1, ("reconnect error %d", rc));
Steve French0cb766a2005-04-28 22:41:11 -0700189 msleep(3000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 } else {
191 atomic_inc(&tcpSesReconnectCount);
192 spin_lock(&GlobalMid_Lock);
Jeff Layton469ee612008-10-16 18:46:39 +0000193 if (server->tcpStatus != CifsExiting)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 server->tcpStatus = CifsGood;
Steve Frenchad009ac2005-04-28 22:41:05 -0700195 server->sequence_number = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000196 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 /* atomic_set(&server->inFlight,0);*/
198 wake_up(&server->response_q);
199 }
200 }
201 return rc;
202}
203
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000204/*
Steve Frenche4eb2952005-04-28 22:41:09 -0700205 return codes:
206 0 not a transact2, or all data present
207 >0 transact2 with that much data missing
208 -EINVAL = invalid transact2
209
210 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000211static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize)
Steve Frenche4eb2952005-04-28 22:41:09 -0700212{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000213 struct smb_t2_rsp *pSMBt;
214 int total_data_size;
Steve Frenche4eb2952005-04-28 22:41:09 -0700215 int data_in_this_rsp;
216 int remaining;
217
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000218 if (pSMB->Command != SMB_COM_TRANSACTION2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700219 return 0;
220
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000221 /* check for plausible wct, bcc and t2 data and parm sizes */
222 /* check for parm and data offset going beyond end of smb */
223 if (pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
Steve French467a8f82007-06-27 22:41:32 +0000224 cFYI(1, ("invalid transact2 word count"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700225 return -EINVAL;
226 }
227
228 pSMBt = (struct smb_t2_rsp *)pSMB;
229
230 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
231 data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
232
233 remaining = total_data_size - data_in_this_rsp;
234
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000235 if (remaining == 0)
Steve Frenche4eb2952005-04-28 22:41:09 -0700236 return 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000237 else if (remaining < 0) {
Steve French467a8f82007-06-27 22:41:32 +0000238 cFYI(1, ("total data %d smaller than data in frame %d",
Steve Frenche4eb2952005-04-28 22:41:09 -0700239 total_data_size, data_in_this_rsp));
240 return -EINVAL;
241 } else {
Steve French467a8f82007-06-27 22:41:32 +0000242 cFYI(1, ("missing %d bytes from transact2, check next response",
Steve Frenche4eb2952005-04-28 22:41:09 -0700243 remaining));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000244 if (total_data_size > maxBufSize) {
245 cERROR(1, ("TotalDataSize %d is over maximum buffer %d",
246 total_data_size, maxBufSize));
247 return -EINVAL;
Steve Frenche4eb2952005-04-28 22:41:09 -0700248 }
249 return remaining;
250 }
251}
252
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000253static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
Steve Frenche4eb2952005-04-28 22:41:09 -0700254{
255 struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
256 struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
257 int total_data_size;
258 int total_in_buf;
259 int remaining;
260 int total_in_buf2;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000261 char *data_area_of_target;
262 char *data_area_of_buf2;
Steve Frenche4eb2952005-04-28 22:41:09 -0700263 __u16 byte_count;
264
265 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
266
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000267 if (total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
Steve French63135e02007-07-17 17:34:02 +0000268 cFYI(1, ("total data size of primary and secondary t2 differ"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700269 }
270
271 total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
272
273 remaining = total_data_size - total_in_buf;
Steve French50c2f752007-07-13 00:33:32 +0000274
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000275 if (remaining < 0)
Steve Frenche4eb2952005-04-28 22:41:09 -0700276 return -EINVAL;
277
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000278 if (remaining == 0) /* nothing to do, ignore */
Steve Frenche4eb2952005-04-28 22:41:09 -0700279 return 0;
Steve French50c2f752007-07-13 00:33:32 +0000280
Steve Frenche4eb2952005-04-28 22:41:09 -0700281 total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000282 if (remaining < total_in_buf2) {
Steve French467a8f82007-06-27 22:41:32 +0000283 cFYI(1, ("transact2 2nd response contains too much data"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700284 }
285
286 /* find end of first SMB data area */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000287 data_area_of_target = (char *)&pSMBt->hdr.Protocol +
Steve Frenche4eb2952005-04-28 22:41:09 -0700288 le16_to_cpu(pSMBt->t2_rsp.DataOffset);
289 /* validate target area */
290
291 data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000292 le16_to_cpu(pSMB2->t2_rsp.DataOffset);
Steve Frenche4eb2952005-04-28 22:41:09 -0700293
294 data_area_of_target += total_in_buf;
295
296 /* copy second buffer into end of first buffer */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000297 memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2);
Steve Frenche4eb2952005-04-28 22:41:09 -0700298 total_in_buf += total_in_buf2;
299 pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
300 byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
301 byte_count += total_in_buf2;
302 BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
303
Steve French70ca7342005-09-22 16:32:06 -0700304 byte_count = pTargetSMB->smb_buf_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700305 byte_count += total_in_buf2;
306
307 /* BB also add check that we are not beyond maximum buffer size */
Steve French50c2f752007-07-13 00:33:32 +0000308
Steve French70ca7342005-09-22 16:32:06 -0700309 pTargetSMB->smb_buf_length = byte_count;
Steve Frenche4eb2952005-04-28 22:41:09 -0700310
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000311 if (remaining == total_in_buf2) {
Steve French467a8f82007-06-27 22:41:32 +0000312 cFYI(1, ("found the last secondary response"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700313 return 0; /* we are done */
314 } else /* more responses to go */
315 return 1;
316
317}
318
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319static int
320cifs_demultiplex_thread(struct TCP_Server_Info *server)
321{
322 int length;
323 unsigned int pdu_length, total_read;
324 struct smb_hdr *smb_buffer = NULL;
Steve Frenchb8643e12005-04-28 22:41:07 -0700325 struct smb_hdr *bigbuf = NULL;
326 struct smb_hdr *smallbuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 struct msghdr smb_msg;
328 struct kvec iov;
329 struct socket *csocket = server->ssocket;
330 struct list_head *tmp;
331 struct cifsSesInfo *ses;
332 struct task_struct *task_to_wake = NULL;
333 struct mid_q_entry *mid_entry;
Steve French70ca7342005-09-22 16:32:06 -0700334 char temp;
Steve French4b18f2a2008-04-29 00:06:05 +0000335 bool isLargeBuf = false;
336 bool isMultiRsp;
Steve Frenche4eb2952005-04-28 22:41:09 -0700337 int reconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 current->flags |= PF_MEMALLOC;
Pavel Emelyanovba25f9d2007-10-18 23:40:40 -0700340 cFYI(1, ("Demultiplex PID: %d", task_pid_nr(current)));
Jeff Layton93d0ec82008-08-02 08:00:48 -0400341
342 length = atomic_inc_return(&tcpSesAllocCount);
343 if (length > 1)
Steve French26f57362007-08-30 22:09:15 +0000344 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
345 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346
Rafael J. Wysocki83144182007-07-17 04:03:35 -0700347 set_freezable();
Jeff Layton469ee612008-10-16 18:46:39 +0000348 while (server->tcpStatus != CifsExiting) {
Steve Frenchede13272005-08-30 20:10:14 -0700349 if (try_to_freeze())
350 continue;
Steve Frenchb8643e12005-04-28 22:41:07 -0700351 if (bigbuf == NULL) {
352 bigbuf = cifs_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000353 if (!bigbuf) {
354 cERROR(1, ("No memory for large SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700355 msleep(3000);
356 /* retry will check if exiting */
357 continue;
358 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000359 } else if (isLargeBuf) {
360 /* we are reusing a dirty large buf, clear its start */
Steve French26f57362007-08-30 22:09:15 +0000361 memset(bigbuf, 0, sizeof(struct smb_hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700363
364 if (smallbuf == NULL) {
365 smallbuf = cifs_small_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000366 if (!smallbuf) {
367 cERROR(1, ("No memory for SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700368 msleep(1000);
369 /* retry will check if exiting */
370 continue;
371 }
372 /* beginning of smb buffer is cleared in our buf_get */
373 } else /* if existing small buf clear beginning */
Steve French26f57362007-08-30 22:09:15 +0000374 memset(smallbuf, 0, sizeof(struct smb_hdr));
Steve Frenchb8643e12005-04-28 22:41:07 -0700375
Steve French4b18f2a2008-04-29 00:06:05 +0000376 isLargeBuf = false;
377 isMultiRsp = false;
Steve Frenchb8643e12005-04-28 22:41:07 -0700378 smb_buffer = smallbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 iov.iov_base = smb_buffer;
380 iov.iov_len = 4;
381 smb_msg.msg_control = NULL;
382 smb_msg.msg_controllen = 0;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000383 pdu_length = 4; /* enough to get RFC1001 header */
384incomplete_rcv:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 length =
386 kernel_recvmsg(csocket, &smb_msg,
Steve Frenchf01d5e12007-08-30 21:13:31 +0000387 &iov, 1, pdu_length, 0 /* BB other flags? */);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388
Jeff Layton469ee612008-10-16 18:46:39 +0000389 if (server->tcpStatus == CifsExiting) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 break;
391 } else if (server->tcpStatus == CifsNeedReconnect) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000392 cFYI(1, ("Reconnect after server stopped responding"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 cifs_reconnect(server);
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000394 cFYI(1, ("call to reconnect done"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 csocket = server->ssocket;
396 continue;
397 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700398 msleep(1); /* minimum sleep to prevent looping
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 allowing socket to clear and app threads to set
400 tcpStatus CifsNeedReconnect if server hung */
Steve Frenchc527c8a2008-11-03 20:46:21 +0000401 if (pdu_length < 4) {
402 iov.iov_base = (4 - pdu_length) +
403 (char *)smb_buffer;
404 iov.iov_len = pdu_length;
405 smb_msg.msg_control = NULL;
406 smb_msg.msg_controllen = 0;
Steve Frenchc18c7322007-10-17 18:01:11 +0000407 goto incomplete_rcv;
Steve Frenchc527c8a2008-11-03 20:46:21 +0000408 } else
Steve Frenchc18c7322007-10-17 18:01:11 +0000409 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 } else if (length <= 0) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000411 if (server->tcpStatus == CifsNew) {
412 cFYI(1, ("tcp session abend after SMBnegprot"));
Steve French09d1db52005-04-28 22:41:08 -0700413 /* some servers kill the TCP session rather than
414 returning an SMB negprot error, in which
415 case reconnecting here is not going to help,
416 and so simply return error to mount */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 break;
418 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000419 if (!try_to_freeze() && (length == -EINTR)) {
Steve French467a8f82007-06-27 22:41:32 +0000420 cFYI(1, ("cifsd thread killed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 break;
422 }
Steve French467a8f82007-06-27 22:41:32 +0000423 cFYI(1, ("Reconnect after unexpected peek error %d",
Steve French57337e42005-04-28 22:41:10 -0700424 length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 cifs_reconnect(server);
426 csocket = server->ssocket;
427 wake_up(&server->response_q);
428 continue;
Petr Tesarik2a974682007-11-20 02:24:08 +0000429 } else if (length < pdu_length) {
430 cFYI(1, ("requested %d bytes but only got %d bytes",
431 pdu_length, length));
Steve Frenchf01d5e12007-08-30 21:13:31 +0000432 pdu_length -= length;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000433 msleep(1);
434 goto incomplete_rcv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 }
Steve French67010fb2005-04-28 22:41:09 -0700436
Steve French70ca7342005-09-22 16:32:06 -0700437 /* The right amount was read from socket - 4 bytes */
438 /* so we can now interpret the length field */
Steve French46810cb2005-04-28 22:41:09 -0700439
Steve French70ca7342005-09-22 16:32:06 -0700440 /* the first byte big endian of the length field,
441 is actually not part of the length but the type
442 with the most common, zero, as regular data */
443 temp = *((char *) smb_buffer);
444
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000445 /* Note that FC 1001 length is big endian on the wire,
Steve French70ca7342005-09-22 16:32:06 -0700446 but we convert it here so it is always manipulated
447 as host byte order */
Harvey Harrison5ca33c62008-07-23 17:45:58 -0700448 pdu_length = be32_to_cpu((__force __be32)smb_buffer->smb_buf_length);
Steve French70ca7342005-09-22 16:32:06 -0700449 smb_buffer->smb_buf_length = pdu_length;
Steve French46810cb2005-04-28 22:41:09 -0700450
Steve French467a8f82007-06-27 22:41:32 +0000451 cFYI(1, ("rfc1002 length 0x%x", pdu_length+4));
Steve French70ca7342005-09-22 16:32:06 -0700452
453 if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000454 continue;
Steve French70ca7342005-09-22 16:32:06 -0700455 } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
Steve French467a8f82007-06-27 22:41:32 +0000456 cFYI(1, ("Good RFC 1002 session rsp"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700457 continue;
Steve French70ca7342005-09-22 16:32:06 -0700458 } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000459 /* we get this from Windows 98 instead of
Steve French46810cb2005-04-28 22:41:09 -0700460 an error on SMB negprot response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000461 cFYI(1, ("Negative RFC1002 Session Response Error 0x%x)",
Steve French70ca7342005-09-22 16:32:06 -0700462 pdu_length));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000463 if (server->tcpStatus == CifsNew) {
464 /* if nack on negprot (rather than
Steve French46810cb2005-04-28 22:41:09 -0700465 ret of smb negprot error) reconnecting
466 not going to help, ret error to mount */
467 break;
468 } else {
469 /* give server a second to
470 clean up before reconnect attempt */
471 msleep(1000);
472 /* always try 445 first on reconnect
473 since we get NACK on some if we ever
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000474 connected to port 139 (the NACK is
Steve French46810cb2005-04-28 22:41:09 -0700475 since we do not begin with RFC1001
476 session initialize frame) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000477 server->addr.sockAddr.sin_port =
Steve French46810cb2005-04-28 22:41:09 -0700478 htons(CIFS_PORT);
479 cifs_reconnect(server);
480 csocket = server->ssocket;
481 wake_up(&server->response_q);
482 continue;
483 }
Steve French70ca7342005-09-22 16:32:06 -0700484 } else if (temp != (char) 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000485 cERROR(1, ("Unknown RFC 1002 frame"));
Steve French70ca7342005-09-22 16:32:06 -0700486 cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
487 length);
Steve French46810cb2005-04-28 22:41:09 -0700488 cifs_reconnect(server);
489 csocket = server->ssocket;
490 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700491 }
492
493 /* else we have an SMB response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000494 if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French26f57362007-08-30 22:09:15 +0000495 (pdu_length < sizeof(struct smb_hdr) - 1 - 4)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700496 cERROR(1, ("Invalid size SMB length %d pdu_length %d",
Steve French46810cb2005-04-28 22:41:09 -0700497 length, pdu_length+4));
Steve Frenche4eb2952005-04-28 22:41:09 -0700498 cifs_reconnect(server);
499 csocket = server->ssocket;
500 wake_up(&server->response_q);
501 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000502 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700503
504 /* else length ok */
505 reconnect = 0;
506
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000507 if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
Steve French4b18f2a2008-04-29 00:06:05 +0000508 isLargeBuf = true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700509 memcpy(bigbuf, smallbuf, 4);
510 smb_buffer = bigbuf;
511 }
512 length = 0;
513 iov.iov_base = 4 + (char *)smb_buffer;
514 iov.iov_len = pdu_length;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000515 for (total_read = 0; total_read < pdu_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700516 total_read += length) {
517 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
518 pdu_length - total_read, 0);
Jeff Layton469ee612008-10-16 18:46:39 +0000519 if ((server->tcpStatus == CifsExiting) ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700520 (length == -EINTR)) {
521 /* then will exit */
522 reconnect = 2;
523 break;
524 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700525 cifs_reconnect(server);
526 csocket = server->ssocket;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000527 /* Reconnect wakes up rspns q */
Steve Frenche4eb2952005-04-28 22:41:09 -0700528 /* Now we will reread sock */
529 reconnect = 1;
530 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000531 } else if ((length == -ERESTARTSYS) ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700532 (length == -EAGAIN)) {
533 msleep(1); /* minimum sleep to prevent looping,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000534 allowing socket to clear and app
Steve Frenche4eb2952005-04-28 22:41:09 -0700535 threads to set tcpStatus
536 CifsNeedReconnect if server hung*/
Steve Frenchc18c7322007-10-17 18:01:11 +0000537 length = 0;
Steve French46810cb2005-04-28 22:41:09 -0700538 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700539 } else if (length <= 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000540 cERROR(1, ("Received no data, expecting %d",
Steve Frenche4eb2952005-04-28 22:41:09 -0700541 pdu_length - total_read));
542 cifs_reconnect(server);
543 csocket = server->ssocket;
544 reconnect = 1;
545 break;
Steve French46810cb2005-04-28 22:41:09 -0700546 }
547 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000548 if (reconnect == 2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700549 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000550 else if (reconnect == 1)
Steve Frenche4eb2952005-04-28 22:41:09 -0700551 continue;
552
553 length += 4; /* account for rfc1002 hdr */
Steve French50c2f752007-07-13 00:33:32 +0000554
Steve Frenche4eb2952005-04-28 22:41:09 -0700555
556 dump_smb(smb_buffer, length);
Steve French184ed212006-02-24 06:15:11 +0000557 if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700558 cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
Steve Frenche4eb2952005-04-28 22:41:09 -0700559 continue;
560 }
561
562
563 task_to_wake = NULL;
564 spin_lock(&GlobalMid_Lock);
565 list_for_each(tmp, &server->pending_mid_q) {
566 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
567
Steve French50c2f752007-07-13 00:33:32 +0000568 if ((mid_entry->mid == smb_buffer->Mid) &&
Steve Frenche4eb2952005-04-28 22:41:09 -0700569 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
570 (mid_entry->command == smb_buffer->Command)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000571 if (check2ndT2(smb_buffer,server->maxBuf) > 0) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700572 /* We have a multipart transact2 resp */
Steve French4b18f2a2008-04-29 00:06:05 +0000573 isMultiRsp = true;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000574 if (mid_entry->resp_buf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700575 /* merge response - fix up 1st*/
Steve French50c2f752007-07-13 00:33:32 +0000576 if (coalesce_t2(smb_buffer,
Steve Frenche4eb2952005-04-28 22:41:09 -0700577 mid_entry->resp_buf)) {
Steve French4b18f2a2008-04-29 00:06:05 +0000578 mid_entry->multiRsp =
579 true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700580 break;
581 } else {
582 /* all parts received */
Steve French4b18f2a2008-04-29 00:06:05 +0000583 mid_entry->multiEnd =
584 true;
Steve French50c2f752007-07-13 00:33:32 +0000585 goto multi_t2_fnd;
Steve Frenche4eb2952005-04-28 22:41:09 -0700586 }
587 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000588 if (!isLargeBuf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700589 cERROR(1,("1st trans2 resp needs bigbuf"));
590 /* BB maybe we can fix this up, switch
Steve French50c2f752007-07-13 00:33:32 +0000591 to already allocated large buffer? */
Steve Frenche4eb2952005-04-28 22:41:09 -0700592 } else {
Steve Frenchcd634992005-04-28 22:41:10 -0700593 /* Have first buffer */
Steve Frenche4eb2952005-04-28 22:41:09 -0700594 mid_entry->resp_buf =
595 smb_buffer;
Steve French4b18f2a2008-04-29 00:06:05 +0000596 mid_entry->largeBuf =
597 true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700598 bigbuf = NULL;
599 }
600 }
601 break;
Steve French50c2f752007-07-13 00:33:32 +0000602 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700603 mid_entry->resp_buf = smb_buffer;
Steve French4b18f2a2008-04-29 00:06:05 +0000604 mid_entry->largeBuf = isLargeBuf;
Steve Frenche4eb2952005-04-28 22:41:09 -0700605multi_t2_fnd:
606 task_to_wake = mid_entry->tsk;
607 mid_entry->midState = MID_RESPONSE_RECEIVED;
Steve French1047abc2005-10-11 19:58:06 -0700608#ifdef CONFIG_CIFS_STATS2
609 mid_entry->when_received = jiffies;
610#endif
Steve French3a5ff612006-07-14 22:37:11 +0000611 /* so we do not time out requests to server
612 which is still responding (since server could
613 be busy but not dead) */
614 server->lstrp = jiffies;
Steve Frenche4eb2952005-04-28 22:41:09 -0700615 break;
616 }
617 }
618 spin_unlock(&GlobalMid_Lock);
619 if (task_to_wake) {
Steve Frenchcd634992005-04-28 22:41:10 -0700620 /* Was previous buf put in mpx struct for multi-rsp? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000621 if (!isMultiRsp) {
Steve Frenchcd634992005-04-28 22:41:10 -0700622 /* smb buffer will be freed by user thread */
Steve French26f57362007-08-30 22:09:15 +0000623 if (isLargeBuf)
Steve Frenchcd634992005-04-28 22:41:10 -0700624 bigbuf = NULL;
Steve French26f57362007-08-30 22:09:15 +0000625 else
Steve Frenchcd634992005-04-28 22:41:10 -0700626 smallbuf = NULL;
627 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700628 wake_up_process(task_to_wake);
Steve French4b18f2a2008-04-29 00:06:05 +0000629 } else if (!is_valid_oplock_break(smb_buffer, server) &&
630 !isMultiRsp) {
Steve French50c2f752007-07-13 00:33:32 +0000631 cERROR(1, ("No task to wake, unknown frame received! "
632 "NumMids %d", midCount.counter));
633 cifs_dump_mem("Received Data is: ", (char *)smb_buffer,
Steve French70ca7342005-09-22 16:32:06 -0700634 sizeof(struct smb_hdr));
Steve French39798772006-05-31 22:40:51 +0000635#ifdef CONFIG_CIFS_DEBUG2
636 cifs_dump_detail(smb_buffer);
637 cifs_dump_mids(server);
638#endif /* CIFS_DEBUG2 */
Steve French50c2f752007-07-13 00:33:32 +0000639
Steve Frenche4eb2952005-04-28 22:41:09 -0700640 }
641 } /* end while !EXITING */
642
Jeff Laytone7ddee92008-11-14 13:44:38 -0500643 /* take it off the list, if it's not already */
644 write_lock(&cifs_tcp_ses_lock);
645 list_del_init(&server->tcp_ses_list);
646 write_unlock(&cifs_tcp_ses_lock);
647
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 spin_lock(&GlobalMid_Lock);
649 server->tcpStatus = CifsExiting;
Steve Frenche691b9d2008-05-11 15:53:33 +0000650 spin_unlock(&GlobalMid_Lock);
Steve Frenchdbdbb872008-06-10 21:21:56 +0000651 wake_up_all(&server->response_q);
Steve Frenche691b9d2008-05-11 15:53:33 +0000652
Steve French31ca3bc2005-04-28 22:41:11 -0700653 /* check if we have blocked requests that need to free */
654 /* Note that cifs_max_pending is normally 50, but
655 can be set at module install time to as little as two */
Steve Frenche691b9d2008-05-11 15:53:33 +0000656 spin_lock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000657 if (atomic_read(&server->inFlight) >= cifs_max_pending)
Steve French31ca3bc2005-04-28 22:41:11 -0700658 atomic_set(&server->inFlight, cifs_max_pending - 1);
659 /* We do not want to set the max_pending too low or we
660 could end up with the counter going negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +0000662 /* Although there should not be any requests blocked on
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700664 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 to the same server - they now will see the session is in exit state
666 and get out of SendReceive. */
667 wake_up_all(&server->request_q);
668 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700669 msleep(125);
Steve French50c2f752007-07-13 00:33:32 +0000670
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000671 if (server->ssocket) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 sock_release(csocket);
673 server->ssocket = NULL;
674 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700675 /* buffer usuallly freed in free_mid - need to free it here on exit */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +0000676 cifs_buf_release(bigbuf);
677 if (smallbuf) /* no sense logging a debug message if NULL */
Steve Frenchb8643e12005-04-28 22:41:07 -0700678 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679
Jeff Layton14fbf502008-11-14 13:53:46 -0500680 /*
681 * BB: we shouldn't have to do any of this. It shouldn't be
682 * possible to exit from the thread with active SMB sessions
683 */
684 read_lock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700686 /* loop through server session structures attached to this and
687 mark them dead */
Jeff Layton14fbf502008-11-14 13:53:46 -0500688 list_for_each(tmp, &server->smb_ses_list) {
689 ses = list_entry(tmp, struct cifsSesInfo,
690 smb_ses_list);
691 ses->status = CifsExiting;
692 ses->server = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 }
Jeff Layton14fbf502008-11-14 13:53:46 -0500694 read_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 } else {
Steve French31ca3bc2005-04-28 22:41:11 -0700696 /* although we can not zero the server struct pointer yet,
697 since there are active requests which may depnd on them,
698 mark the corresponding SMB sessions as exiting too */
Jeff Layton14fbf502008-11-14 13:53:46 -0500699 list_for_each(tmp, &server->smb_ses_list) {
Steve French31ca3bc2005-04-28 22:41:11 -0700700 ses = list_entry(tmp, struct cifsSesInfo,
Jeff Layton14fbf502008-11-14 13:53:46 -0500701 smb_ses_list);
702 ses->status = CifsExiting;
Steve French31ca3bc2005-04-28 22:41:11 -0700703 }
704
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 spin_lock(&GlobalMid_Lock);
706 list_for_each(tmp, &server->pending_mid_q) {
707 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
708 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French50c2f752007-07-13 00:33:32 +0000709 cFYI(1, ("Clearing Mid 0x%x - waking up ",
710 mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 task_to_wake = mid_entry->tsk;
Steve French26f57362007-08-30 22:09:15 +0000712 if (task_to_wake)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 wake_up_process(task_to_wake);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 }
715 }
716 spin_unlock(&GlobalMid_Lock);
Jeff Layton14fbf502008-11-14 13:53:46 -0500717 read_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700719 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 }
721
Steve Frenchf1914012005-08-18 09:37:34 -0700722 if (!list_empty(&server->pending_mid_q)) {
Steve French50c2f752007-07-13 00:33:32 +0000723 /* mpx threads have not exited yet give them
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700725 /* due to delays on oplock break requests, we need
726 to wait at least 45 seconds before giving up
727 on a request getting a response and going ahead
728 and killing cifsd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve French31ca3bc2005-04-28 22:41:11 -0700730 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 /* if threads still have not exited they are probably never
732 coming home not much else we can do but free the memory */
733 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734
Steve French31ca3bc2005-04-28 22:41:11 -0700735 /* last chance to mark ses pointers invalid
736 if there are any pointing to this (e.g
Steve French50c2f752007-07-13 00:33:32 +0000737 if a crazy root user tried to kill cifsd
Steve French31ca3bc2005-04-28 22:41:11 -0700738 kernel thread explicitly this might happen) */
Jeff Layton14fbf502008-11-14 13:53:46 -0500739 /* BB: This shouldn't be necessary, see above */
740 read_lock(&cifs_tcp_ses_lock);
741 list_for_each(tmp, &server->smb_ses_list) {
742 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
743 ses->server = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700744 }
Jeff Layton14fbf502008-11-14 13:53:46 -0500745 read_unlock(&cifs_tcp_ses_lock);
Steve French31ca3bc2005-04-28 22:41:11 -0700746
Jeff Laytonc359cf32007-11-16 22:22:06 +0000747 kfree(server->hostname);
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -0400748 task_to_wake = xchg(&server->tsk, NULL);
Steve French31ca3bc2005-04-28 22:41:11 -0700749 kfree(server);
Jeff Layton93d0ec82008-08-02 08:00:48 -0400750
751 length = atomic_dec_return(&tcpSesAllocCount);
Steve French26f57362007-08-30 22:09:15 +0000752 if (length > 0)
753 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
754 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +0000755
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -0400756 /* if server->tsk was NULL then wait for a signal before exiting */
757 if (!task_to_wake) {
758 set_current_state(TASK_INTERRUPTIBLE);
759 while (!signal_pending(current)) {
760 schedule();
761 set_current_state(TASK_INTERRUPTIBLE);
762 }
763 set_current_state(TASK_RUNNING);
764 }
765
Jeff Layton0468a2c2008-12-01 07:09:35 -0500766 module_put_and_exit(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767}
768
Jeff Laytonc359cf32007-11-16 22:22:06 +0000769/* extract the host portion of the UNC string */
770static char *
771extract_hostname(const char *unc)
772{
773 const char *src;
774 char *dst, *delim;
775 unsigned int len;
776
777 /* skip double chars at beginning of string */
778 /* BB: check validity of these bytes? */
779 src = unc + 2;
780
781 /* delimiter between hostname and sharename is always '\\' now */
782 delim = strchr(src, '\\');
783 if (!delim)
784 return ERR_PTR(-EINVAL);
785
786 len = delim - src;
787 dst = kmalloc((len + 1), GFP_KERNEL);
788 if (dst == NULL)
789 return ERR_PTR(-ENOMEM);
790
791 memcpy(dst, src, len);
792 dst[len] = '\0';
793
794 return dst;
795}
796
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797static int
Steve French50c2f752007-07-13 00:33:32 +0000798cifs_parse_mount_options(char *options, const char *devname,
799 struct smb_vol *vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800{
801 char *value;
802 char *data;
803 unsigned int temp_len, i, j;
804 char separator[2];
805
806 separator[0] = ',';
Steve French50c2f752007-07-13 00:33:32 +0000807 separator[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808
Linus Torvalds12e36b22006-10-13 08:09:29 -0700809 if (Local_System_Name[0] != 0)
Steve French50c2f752007-07-13 00:33:32 +0000810 memcpy(vol->source_rfc1001_name, Local_System_Name, 15);
Steve French2cd646a2006-09-28 19:43:08 +0000811 else {
Linus Torvalds12e36b22006-10-13 08:09:29 -0700812 char *nodename = utsname()->nodename;
Steve French50c2f752007-07-13 00:33:32 +0000813 int n = strnlen(nodename, 15);
814 memset(vol->source_rfc1001_name, 0x20, 15);
815 for (i = 0; i < n; i++) {
Steve French2cd646a2006-09-28 19:43:08 +0000816 /* does not have to be perfect mapping since field is
817 informational, only used for servers that do not support
818 port 445 and it can be overridden at mount time */
Linus Torvalds12e36b22006-10-13 08:09:29 -0700819 vol->source_rfc1001_name[i] = toupper(nodename[i]);
Steve French2cd646a2006-09-28 19:43:08 +0000820 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 }
822 vol->source_rfc1001_name[15] = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -0700823 /* null target name indicates to use *SMBSERVR default called name
824 if we end up sending RFC1001 session initialize */
825 vol->target_rfc1001_name[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 vol->linux_uid = current->uid; /* current->euid instead? */
827 vol->linux_gid = current->gid;
828 vol->dir_mode = S_IRWXUGO;
829 /* 2767 perms indicate mandatory locking support */
Steve French7505e052007-11-01 18:03:01 +0000830 vol->file_mode = (S_IRWXUGO | S_ISGID) & (~S_IXGRP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831
832 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
Steve French4b18f2a2008-04-29 00:06:05 +0000833 vol->rw = true;
Jeremy Allisonac670552005-06-22 17:26:35 -0700834 /* default is always to request posix paths. */
835 vol->posix_paths = 1;
836
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 if (!options)
838 return 1;
839
Steve French50c2f752007-07-13 00:33:32 +0000840 if (strncmp(options, "sep=", 4) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000841 if (options[4] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 separator[0] = options[4];
843 options += 5;
844 } else {
Steve French467a8f82007-06-27 22:41:32 +0000845 cFYI(1, ("Null separator not allowed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 }
847 }
Steve French50c2f752007-07-13 00:33:32 +0000848
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 while ((data = strsep(&options, separator)) != NULL) {
850 if (!*data)
851 continue;
852 if ((value = strchr(data, '=')) != NULL)
853 *value++ = '\0';
854
Steve French50c2f752007-07-13 00:33:32 +0000855 /* Have to parse this before we parse for "user" */
856 if (strnicmp(data, "user_xattr", 10) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 vol->no_xattr = 0;
Steve French50c2f752007-07-13 00:33:32 +0000858 } else if (strnicmp(data, "nouser_xattr", 12) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 vol->no_xattr = 1;
860 } else if (strnicmp(data, "user", 4) == 0) {
Steve French4b952a92006-10-30 21:46:13 +0000861 if (!value) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 printk(KERN_WARNING
863 "CIFS: invalid or missing username\n");
864 return 1; /* needs_arg; */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000865 } else if (!*value) {
Steve French4b952a92006-10-30 21:46:13 +0000866 /* null user, ie anonymous, authentication */
867 vol->nullauth = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 }
869 if (strnlen(value, 200) < 200) {
870 vol->username = value;
871 } else {
872 printk(KERN_WARNING "CIFS: username too long\n");
873 return 1;
874 }
875 } else if (strnicmp(data, "pass", 4) == 0) {
876 if (!value) {
877 vol->password = NULL;
878 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000879 } else if (value[0] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 /* check if string begins with double comma
881 since that would mean the password really
882 does start with a comma, and would not
883 indicate an empty string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000884 if (value[1] != separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 vol->password = NULL;
886 continue;
887 }
888 }
889 temp_len = strlen(value);
890 /* removed password length check, NTLM passwords
891 can be arbitrarily long */
892
Steve French50c2f752007-07-13 00:33:32 +0000893 /* if comma in password, the string will be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 prematurely null terminated. Commas in password are
895 specified across the cifs mount interface by a double
896 comma ie ,, and a comma used as in other cases ie ','
897 as a parameter delimiter/separator is single and due
898 to the strsep above is temporarily zeroed. */
899
900 /* NB: password legally can have multiple commas and
901 the only illegal character in a password is null */
902
Steve French50c2f752007-07-13 00:33:32 +0000903 if ((value[temp_len] == 0) &&
Steve French09d1db52005-04-28 22:41:08 -0700904 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 /* reinsert comma */
906 value[temp_len] = separator[0];
Steve French50c2f752007-07-13 00:33:32 +0000907 temp_len += 2; /* move after second comma */
908 while (value[temp_len] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 if (value[temp_len] == separator[0]) {
Steve French50c2f752007-07-13 00:33:32 +0000910 if (value[temp_len+1] ==
Steve French09d1db52005-04-28 22:41:08 -0700911 separator[0]) {
912 /* skip second comma */
913 temp_len++;
Steve French50c2f752007-07-13 00:33:32 +0000914 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 /* single comma indicating start
916 of next parm */
917 break;
918 }
919 }
920 temp_len++;
921 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000922 if (value[temp_len] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 options = NULL;
924 } else {
925 value[temp_len] = 0;
926 /* point option to start of next parm */
927 options = value + temp_len + 1;
928 }
Steve French50c2f752007-07-13 00:33:32 +0000929 /* go from value to value + temp_len condensing
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 double commas to singles. Note that this ends up
931 allocating a few bytes too many, which is ok */
Pekka Enberge915fc42005-09-06 15:18:35 -0700932 vol->password = kzalloc(temp_len, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000933 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000934 printk(KERN_WARNING "CIFS: no memory "
935 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700936 return 1;
937 }
Steve French50c2f752007-07-13 00:33:32 +0000938 for (i = 0, j = 0; i < temp_len; i++, j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 vol->password[j] = value[i];
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000940 if (value[i] == separator[0]
Steve French09d1db52005-04-28 22:41:08 -0700941 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 /* skip second comma */
943 i++;
944 }
945 }
946 vol->password[j] = 0;
947 } else {
Pekka Enberge915fc42005-09-06 15:18:35 -0700948 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000949 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000950 printk(KERN_WARNING "CIFS: no memory "
951 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700952 return 1;
953 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 strcpy(vol->password, value);
955 }
956 } else if (strnicmp(data, "ip", 2) == 0) {
957 if (!value || !*value) {
958 vol->UNCip = NULL;
959 } else if (strnlen(value, 35) < 35) {
960 vol->UNCip = value;
961 } else {
Steve French50c2f752007-07-13 00:33:32 +0000962 printk(KERN_WARNING "CIFS: ip address "
963 "too long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 return 1;
965 }
Steve French50c2f752007-07-13 00:33:32 +0000966 } else if (strnicmp(data, "sec", 3) == 0) {
967 if (!value || !*value) {
968 cERROR(1, ("no security value specified"));
969 continue;
970 } else if (strnicmp(value, "krb5i", 5) == 0) {
971 vol->secFlg |= CIFSSEC_MAY_KRB5 |
Steve French189acaa2006-06-23 02:33:48 +0000972 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800973 } else if (strnicmp(value, "krb5p", 5) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000974 /* vol->secFlg |= CIFSSEC_MUST_SEAL |
975 CIFSSEC_MAY_KRB5; */
976 cERROR(1, ("Krb5 cifs privacy not supported"));
Steve Frenchbf820672005-12-01 22:32:42 -0800977 return 1;
978 } else if (strnicmp(value, "krb5", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000979 vol->secFlg |= CIFSSEC_MAY_KRB5;
Steve Frenchbf820672005-12-01 22:32:42 -0800980 } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000981 vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
Steve French189acaa2006-06-23 02:33:48 +0000982 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800983 } else if (strnicmp(value, "ntlmv2", 6) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000984 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve Frenchbf820672005-12-01 22:32:42 -0800985 } else if (strnicmp(value, "ntlmi", 5) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000986 vol->secFlg |= CIFSSEC_MAY_NTLM |
Steve French189acaa2006-06-23 02:33:48 +0000987 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800988 } else if (strnicmp(value, "ntlm", 4) == 0) {
989 /* ntlm is default so can be turned off too */
Steve French750d1152006-06-27 06:28:30 +0000990 vol->secFlg |= CIFSSEC_MAY_NTLM;
Steve Frenchbf820672005-12-01 22:32:42 -0800991 } else if (strnicmp(value, "nontlm", 6) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000992 /* BB is there a better way to do this? */
Steve French750d1152006-06-27 06:28:30 +0000993 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve French189acaa2006-06-23 02:33:48 +0000994#ifdef CONFIG_CIFS_WEAK_PW_HASH
995 } else if (strnicmp(value, "lanman", 6) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000996 vol->secFlg |= CIFSSEC_MAY_LANMAN;
Steve French189acaa2006-06-23 02:33:48 +0000997#endif
Steve Frenchbf820672005-12-01 22:32:42 -0800998 } else if (strnicmp(value, "none", 4) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000999 vol->nullauth = 1;
Steve French50c2f752007-07-13 00:33:32 +00001000 } else {
1001 cERROR(1, ("bad security option: %s", value));
1002 return 1;
1003 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 } else if ((strnicmp(data, "unc", 3) == 0)
1005 || (strnicmp(data, "target", 6) == 0)
1006 || (strnicmp(data, "path", 4) == 0)) {
1007 if (!value || !*value) {
Steve French50c2f752007-07-13 00:33:32 +00001008 printk(KERN_WARNING "CIFS: invalid path to "
1009 "network resource\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 return 1; /* needs_arg; */
1011 }
1012 if ((temp_len = strnlen(value, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001013 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001014 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001016 strcpy(vol->UNC, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 if (strncmp(vol->UNC, "//", 2) == 0) {
1018 vol->UNC[0] = '\\';
1019 vol->UNC[1] = '\\';
Steve French50c2f752007-07-13 00:33:32 +00001020 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 printk(KERN_WARNING
Steve French50c2f752007-07-13 00:33:32 +00001022 "CIFS: UNC Path does not begin "
1023 "with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 return 1;
1025 }
1026 } else {
1027 printk(KERN_WARNING "CIFS: UNC name too long\n");
1028 return 1;
1029 }
1030 } else if ((strnicmp(data, "domain", 3) == 0)
1031 || (strnicmp(data, "workgroup", 5) == 0)) {
1032 if (!value || !*value) {
1033 printk(KERN_WARNING "CIFS: invalid domain name\n");
1034 return 1; /* needs_arg; */
1035 }
1036 /* BB are there cases in which a comma can be valid in
1037 a domain name and need special handling? */
Steve French39798772006-05-31 22:40:51 +00001038 if (strnlen(value, 256) < 256) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 vol->domainname = value;
1040 cFYI(1, ("Domain name set"));
1041 } else {
Steve French50c2f752007-07-13 00:33:32 +00001042 printk(KERN_WARNING "CIFS: domain name too "
1043 "long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 return 1;
1045 }
Steve French50c2f752007-07-13 00:33:32 +00001046 } else if (strnicmp(data, "prefixpath", 10) == 0) {
1047 if (!value || !*value) {
1048 printk(KERN_WARNING
1049 "CIFS: invalid path prefix\n");
1050 return 1; /* needs_argument */
1051 }
1052 if ((temp_len = strnlen(value, 1024)) < 1024) {
Steve French4523cc32007-04-30 20:13:06 +00001053 if (value[0] != '/')
Steve French2fe87f02006-09-21 07:02:52 +00001054 temp_len++; /* missing leading slash */
Steve French50c2f752007-07-13 00:33:32 +00001055 vol->prepath = kmalloc(temp_len+1, GFP_KERNEL);
1056 if (vol->prepath == NULL)
1057 return 1;
Steve French4523cc32007-04-30 20:13:06 +00001058 if (value[0] != '/') {
Steve French2fe87f02006-09-21 07:02:52 +00001059 vol->prepath[0] = '/';
Steve French50c2f752007-07-13 00:33:32 +00001060 strcpy(vol->prepath+1, value);
Steve French2fe87f02006-09-21 07:02:52 +00001061 } else
Steve French50c2f752007-07-13 00:33:32 +00001062 strcpy(vol->prepath, value);
1063 cFYI(1, ("prefix path %s", vol->prepath));
1064 } else {
1065 printk(KERN_WARNING "CIFS: prefix too long\n");
1066 return 1;
1067 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 } else if (strnicmp(data, "iocharset", 9) == 0) {
1069 if (!value || !*value) {
Steve French63135e02007-07-17 17:34:02 +00001070 printk(KERN_WARNING "CIFS: invalid iocharset "
1071 "specified\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 return 1; /* needs_arg; */
1073 }
1074 if (strnlen(value, 65) < 65) {
Steve French50c2f752007-07-13 00:33:32 +00001075 if (strnicmp(value, "default", 7))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 vol->iocharset = value;
Steve French50c2f752007-07-13 00:33:32 +00001077 /* if iocharset not set then load_nls_default
1078 is used by caller */
1079 cFYI(1, ("iocharset set to %s", value));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 } else {
Steve French63135e02007-07-17 17:34:02 +00001081 printk(KERN_WARNING "CIFS: iocharset name "
1082 "too long.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 return 1;
1084 }
1085 } else if (strnicmp(data, "uid", 3) == 0) {
1086 if (value && *value) {
1087 vol->linux_uid =
1088 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001089 vol->override_uid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 }
1091 } else if (strnicmp(data, "gid", 3) == 0) {
1092 if (value && *value) {
1093 vol->linux_gid =
1094 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001095 vol->override_gid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 }
1097 } else if (strnicmp(data, "file_mode", 4) == 0) {
1098 if (value && *value) {
1099 vol->file_mode =
1100 simple_strtoul(value, &value, 0);
1101 }
1102 } else if (strnicmp(data, "dir_mode", 4) == 0) {
1103 if (value && *value) {
1104 vol->dir_mode =
1105 simple_strtoul(value, &value, 0);
1106 }
1107 } else if (strnicmp(data, "dirmode", 4) == 0) {
1108 if (value && *value) {
1109 vol->dir_mode =
1110 simple_strtoul(value, &value, 0);
1111 }
1112 } else if (strnicmp(data, "port", 4) == 0) {
1113 if (value && *value) {
1114 vol->port =
1115 simple_strtoul(value, &value, 0);
1116 }
1117 } else if (strnicmp(data, "rsize", 5) == 0) {
1118 if (value && *value) {
1119 vol->rsize =
1120 simple_strtoul(value, &value, 0);
1121 }
1122 } else if (strnicmp(data, "wsize", 5) == 0) {
1123 if (value && *value) {
1124 vol->wsize =
1125 simple_strtoul(value, &value, 0);
1126 }
1127 } else if (strnicmp(data, "sockopt", 5) == 0) {
1128 if (value && *value) {
1129 vol->sockopt =
1130 simple_strtoul(value, &value, 0);
1131 }
1132 } else if (strnicmp(data, "netbiosname", 4) == 0) {
1133 if (!value || !*value || (*value == ' ')) {
Steve French63135e02007-07-17 17:34:02 +00001134 cFYI(1, ("invalid (empty) netbiosname"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 } else {
Steve French50c2f752007-07-13 00:33:32 +00001136 memset(vol->source_rfc1001_name, 0x20, 15);
1137 for (i = 0; i < 15; i++) {
1138 /* BB are there cases in which a comma can be
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 valid in this workstation netbios name (and need
1140 special handling)? */
1141
1142 /* We do not uppercase netbiosname for user */
Steve French50c2f752007-07-13 00:33:32 +00001143 if (value[i] == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 break;
Steve French50c2f752007-07-13 00:33:32 +00001145 else
1146 vol->source_rfc1001_name[i] =
1147 value[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 }
1149 /* The string has 16th byte zero still from
1150 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001151 if ((i == 15) && (value[i] != 0))
1152 printk(KERN_WARNING "CIFS: netbiosname"
1153 " longer than 15 truncated.\n");
Steve Frencha10faeb22005-08-22 21:38:31 -07001154 }
1155 } else if (strnicmp(data, "servern", 7) == 0) {
1156 /* servernetbiosname specified override *SMBSERVER */
1157 if (!value || !*value || (*value == ' ')) {
Steve French467a8f82007-06-27 22:41:32 +00001158 cFYI(1, ("empty server netbiosname specified"));
Steve Frencha10faeb22005-08-22 21:38:31 -07001159 } else {
1160 /* last byte, type, is 0x20 for servr type */
Steve French50c2f752007-07-13 00:33:32 +00001161 memset(vol->target_rfc1001_name, 0x20, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001162
Steve French50c2f752007-07-13 00:33:32 +00001163 for (i = 0; i < 15; i++) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001164 /* BB are there cases in which a comma can be
Steve French50c2f752007-07-13 00:33:32 +00001165 valid in this workstation netbios name
1166 (and need special handling)? */
Steve Frencha10faeb22005-08-22 21:38:31 -07001167
Steve French50c2f752007-07-13 00:33:32 +00001168 /* user or mount helper must uppercase
1169 the netbiosname */
1170 if (value[i] == 0)
Steve Frencha10faeb22005-08-22 21:38:31 -07001171 break;
1172 else
Steve French50c2f752007-07-13 00:33:32 +00001173 vol->target_rfc1001_name[i] =
1174 value[i];
Steve Frencha10faeb22005-08-22 21:38:31 -07001175 }
1176 /* The string has 16th byte zero still from
1177 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001178 if ((i == 15) && (value[i] != 0))
1179 printk(KERN_WARNING "CIFS: server net"
1180 "biosname longer than 15 truncated.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 }
1182 } else if (strnicmp(data, "credentials", 4) == 0) {
1183 /* ignore */
1184 } else if (strnicmp(data, "version", 3) == 0) {
1185 /* ignore */
Steve French50c2f752007-07-13 00:33:32 +00001186 } else if (strnicmp(data, "guest", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 /* ignore */
1188 } else if (strnicmp(data, "rw", 2) == 0) {
Steve French4b18f2a2008-04-29 00:06:05 +00001189 vol->rw = true;
Steve Frenchedf1ae42008-10-29 00:47:57 +00001190 } else if (strnicmp(data, "noblocksend", 11) == 0) {
1191 vol->noblocksnd = 1;
1192 } else if (strnicmp(data, "noautotune", 10) == 0) {
1193 vol->noautotune = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 } else if ((strnicmp(data, "suid", 4) == 0) ||
1195 (strnicmp(data, "nosuid", 6) == 0) ||
1196 (strnicmp(data, "exec", 4) == 0) ||
1197 (strnicmp(data, "noexec", 6) == 0) ||
1198 (strnicmp(data, "nodev", 5) == 0) ||
1199 (strnicmp(data, "noauto", 6) == 0) ||
1200 (strnicmp(data, "dev", 3) == 0)) {
1201 /* The mount tool or mount.cifs helper (if present)
Steve French50c2f752007-07-13 00:33:32 +00001202 uses these opts to set flags, and the flags are read
1203 by the kernel vfs layer before we get here (ie
1204 before read super) so there is no point trying to
1205 parse these options again and set anything and it
1206 is ok to just ignore them */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 continue;
1208 } else if (strnicmp(data, "ro", 2) == 0) {
Steve French4b18f2a2008-04-29 00:06:05 +00001209 vol->rw = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 } else if (strnicmp(data, "hard", 4) == 0) {
1211 vol->retry = 1;
1212 } else if (strnicmp(data, "soft", 4) == 0) {
1213 vol->retry = 0;
1214 } else if (strnicmp(data, "perm", 4) == 0) {
1215 vol->noperm = 0;
1216 } else if (strnicmp(data, "noperm", 6) == 0) {
1217 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001218 } else if (strnicmp(data, "mapchars", 8) == 0) {
1219 vol->remap = 1;
1220 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1221 vol->remap = 0;
Steve French50c2f752007-07-13 00:33:32 +00001222 } else if (strnicmp(data, "sfu", 3) == 0) {
1223 vol->sfu_emul = 1;
1224 } else if (strnicmp(data, "nosfu", 5) == 0) {
1225 vol->sfu_emul = 0;
Steve French2c1b8612008-10-16 18:35:21 +00001226 } else if (strnicmp(data, "nodfs", 5) == 0) {
1227 vol->nodfs = 1;
Jeremy Allisonac670552005-06-22 17:26:35 -07001228 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1229 vol->posix_paths = 1;
1230 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1231 vol->posix_paths = 0;
Steve Frenchc18c8422007-07-18 23:21:09 +00001232 } else if (strnicmp(data, "nounix", 6) == 0) {
1233 vol->no_linux_ext = 1;
1234 } else if (strnicmp(data, "nolinux", 7) == 0) {
1235 vol->no_linux_ext = 1;
Steve French50c2f752007-07-13 00:33:32 +00001236 } else if ((strnicmp(data, "nocase", 6) == 0) ||
Steve Frencha10faeb22005-08-22 21:38:31 -07001237 (strnicmp(data, "ignorecase", 10) == 0)) {
Steve French50c2f752007-07-13 00:33:32 +00001238 vol->nocase = 1;
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001239 } else if (strnicmp(data, "brl", 3) == 0) {
1240 vol->nobrl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001241 } else if ((strnicmp(data, "nobrl", 5) == 0) ||
Steve French1c955182005-08-30 20:58:07 -07001242 (strnicmp(data, "nolock", 6) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001243 vol->nobrl = 1;
Steve Frenchd3485d32005-08-19 11:04:29 -07001244 /* turn off mandatory locking in mode
1245 if remote locking is turned off since the
1246 local vfs will do advisory */
Steve French50c2f752007-07-13 00:33:32 +00001247 if (vol->file_mode ==
1248 (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
Steve Frenchd3485d32005-08-19 11:04:29 -07001249 vol->file_mode = S_IALLUGO;
Steve French13a6e422008-12-02 17:24:33 +00001250 } else if (strnicmp(data, "forcemandatorylock", 9) == 0) {
1251 /* will take the shorter form "forcemand" as well */
1252 /* This mount option will force use of mandatory
1253 (DOS/Windows style) byte range locks, instead of
1254 using posix advisory byte range locks, even if the
1255 Unix extensions are available and posix locks would
1256 be supported otherwise. If Unix extensions are not
1257 negotiated this has no effect since mandatory locks
1258 would be used (mandatory locks is all that those
1259 those servers support) */
1260 vol->mand_lock = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 } else if (strnicmp(data, "setuids", 7) == 0) {
1262 vol->setuids = 1;
1263 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1264 vol->setuids = 0;
Jeff Laytond0a9c072008-05-12 22:23:49 +00001265 } else if (strnicmp(data, "dynperm", 7) == 0) {
1266 vol->dynperm = true;
1267 } else if (strnicmp(data, "nodynperm", 9) == 0) {
1268 vol->dynperm = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 } else if (strnicmp(data, "nohard", 6) == 0) {
1270 vol->retry = 0;
1271 } else if (strnicmp(data, "nosoft", 6) == 0) {
1272 vol->retry = 1;
1273 } else if (strnicmp(data, "nointr", 6) == 0) {
1274 vol->intr = 0;
1275 } else if (strnicmp(data, "intr", 4) == 0) {
1276 vol->intr = 1;
Steve French50c2f752007-07-13 00:33:32 +00001277 } else if (strnicmp(data, "serverino", 7) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 vol->server_ino = 1;
Steve French50c2f752007-07-13 00:33:32 +00001279 } else if (strnicmp(data, "noserverino", 9) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 vol->server_ino = 0;
Steve French50c2f752007-07-13 00:33:32 +00001281 } else if (strnicmp(data, "cifsacl", 7) == 0) {
Steve French0a4b92c2006-01-12 15:44:21 -08001282 vol->cifs_acl = 1;
1283 } else if (strnicmp(data, "nocifsacl", 9) == 0) {
1284 vol->cifs_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001285 } else if (strnicmp(data, "acl", 3) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 vol->no_psx_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001287 } else if (strnicmp(data, "noacl", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 vol->no_psx_acl = 1;
Steve French84210e92008-10-23 04:42:37 +00001289#ifdef CONFIG_CIFS_EXPERIMENTAL
1290 } else if (strnicmp(data, "locallease", 6) == 0) {
1291 vol->local_lease = 1;
1292#endif
Steve French50c2f752007-07-13 00:33:32 +00001293 } else if (strnicmp(data, "sign", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +00001294 vol->secFlg |= CIFSSEC_MUST_SIGN;
Steve French95b1cb92008-05-15 16:44:38 +00001295 } else if (strnicmp(data, "seal", 4) == 0) {
1296 /* we do not do the following in secFlags because seal
1297 is a per tree connection (mount) not a per socket
1298 or per-smb connection option in the protocol */
1299 /* vol->secFlg |= CIFSSEC_MUST_SEAL; */
1300 vol->seal = 1;
Steve French50c2f752007-07-13 00:33:32 +00001301 } else if (strnicmp(data, "direct", 6) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001303 } else if (strnicmp(data, "forcedirectio", 13) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001305 } else if (strnicmp(data, "in6_addr", 8) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 if (!value || !*value) {
1307 vol->in6_addr = NULL;
1308 } else if (strnlen(value, 49) == 48) {
1309 vol->in6_addr = value;
1310 } else {
Steve French50c2f752007-07-13 00:33:32 +00001311 printk(KERN_WARNING "CIFS: ip v6 address not "
1312 "48 characters long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 return 1;
1314 }
1315 } else if (strnicmp(data, "noac", 4) == 0) {
Steve French50c2f752007-07-13 00:33:32 +00001316 printk(KERN_WARNING "CIFS: Mount option noac not "
1317 "supported. Instead set "
1318 "/proc/fs/cifs/LookupCacheEnabled to 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 } else
Steve French50c2f752007-07-13 00:33:32 +00001320 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",
1321 data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 }
1323 if (vol->UNC == NULL) {
Steve French4523cc32007-04-30 20:13:06 +00001324 if (devname == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001325 printk(KERN_WARNING "CIFS: Missing UNC name for mount "
1326 "target\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 return 1;
1328 }
1329 if ((temp_len = strnlen(devname, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001330 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001331 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001333 strcpy(vol->UNC, devname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 if (strncmp(vol->UNC, "//", 2) == 0) {
1335 vol->UNC[0] = '\\';
1336 vol->UNC[1] = '\\';
1337 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Steve French50c2f752007-07-13 00:33:32 +00001338 printk(KERN_WARNING "CIFS: UNC Path does not "
1339 "begin with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 return 1;
1341 }
Igor Mammedov7c5e6282008-05-08 20:48:42 +00001342 value = strpbrk(vol->UNC+2, "/\\");
1343 if (value)
1344 *value = '\\';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 } else {
1346 printk(KERN_WARNING "CIFS: UNC name too long\n");
1347 return 1;
1348 }
1349 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001350 if (vol->UNCip == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 vol->UNCip = &vol->UNC[2];
1352
1353 return 0;
1354}
1355
Jeff Laytone7ddee92008-11-14 13:44:38 -05001356static struct TCP_Server_Info *
1357cifs_find_tcp_session(struct sockaddr *addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358{
1359 struct list_head *tmp;
Jeff Laytone7ddee92008-11-14 13:44:38 -05001360 struct TCP_Server_Info *server;
1361 struct sockaddr_in *addr4 = (struct sockaddr_in *) addr;
1362 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363
Jeff Laytone7ddee92008-11-14 13:44:38 -05001364 write_lock(&cifs_tcp_ses_lock);
1365 list_for_each(tmp, &cifs_tcp_ses_list) {
1366 server = list_entry(tmp, struct TCP_Server_Info,
1367 tcp_ses_list);
Jeff Laytone7ddee92008-11-14 13:44:38 -05001368 /*
1369 * the demux thread can exit on its own while still in CifsNew
1370 * so don't accept any sockets in that state. Since the
1371 * tcpStatus never changes back to CifsNew it's safe to check
1372 * for this without a lock.
1373 */
1374 if (server->tcpStatus == CifsNew)
Cyrill Gorcunov1b20d672008-05-09 18:17:21 +00001375 continue;
Steve French50c2f752007-07-13 00:33:32 +00001376
Jeff Laytone7ddee92008-11-14 13:44:38 -05001377 if (addr->sa_family == AF_INET &&
1378 (addr4->sin_addr.s_addr !=
1379 server->addr.sockAddr.sin_addr.s_addr))
1380 continue;
1381 else if (addr->sa_family == AF_INET6 &&
1382 memcmp(&server->addr.sockAddr6.sin6_addr,
1383 &addr6->sin6_addr, sizeof(addr6->sin6_addr)))
1384 continue;
Steve French50c2f752007-07-13 00:33:32 +00001385
Jeff Laytone7ddee92008-11-14 13:44:38 -05001386 ++server->srv_count;
1387 write_unlock(&cifs_tcp_ses_lock);
Steve Frenchd82c2df2008-11-15 00:07:26 +00001388 cFYI(1, ("Existing tcp session with server found"));
Jeff Laytone7ddee92008-11-14 13:44:38 -05001389 return server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 }
Jeff Laytone7ddee92008-11-14 13:44:38 -05001391 write_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 return NULL;
1393}
1394
Jeff Layton14fbf502008-11-14 13:53:46 -05001395static void
Jeff Laytone7ddee92008-11-14 13:44:38 -05001396cifs_put_tcp_session(struct TCP_Server_Info *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397{
Jeff Laytone7ddee92008-11-14 13:44:38 -05001398 struct task_struct *task;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399
Jeff Laytone7ddee92008-11-14 13:44:38 -05001400 write_lock(&cifs_tcp_ses_lock);
1401 if (--server->srv_count > 0) {
1402 write_unlock(&cifs_tcp_ses_lock);
1403 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 }
Steve Frenchdea570e02008-05-06 22:05:51 +00001405
Jeff Laytone7ddee92008-11-14 13:44:38 -05001406 list_del_init(&server->tcp_ses_list);
1407 write_unlock(&cifs_tcp_ses_lock);
1408
1409 spin_lock(&GlobalMid_Lock);
1410 server->tcpStatus = CifsExiting;
1411 spin_unlock(&GlobalMid_Lock);
1412
1413 task = xchg(&server->tsk, NULL);
1414 if (task)
1415 force_sig(SIGKILL, task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416}
1417
Jeff Layton63c038c2008-12-01 18:41:46 -05001418static struct TCP_Server_Info *
1419cifs_get_tcp_session(struct smb_vol *volume_info)
1420{
1421 struct TCP_Server_Info *tcp_ses = NULL;
1422 struct sockaddr addr;
1423 struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr;
1424 struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr;
1425 int rc;
1426
1427 memset(&addr, 0, sizeof(struct sockaddr));
1428
1429 if (volume_info->UNCip && volume_info->UNC) {
1430 rc = cifs_inet_pton(AF_INET, volume_info->UNCip,
1431 &sin_server->sin_addr.s_addr);
1432
1433 if (rc <= 0) {
1434 /* not ipv4 address, try ipv6 */
1435 rc = cifs_inet_pton(AF_INET6, volume_info->UNCip,
1436 &sin_server6->sin6_addr.in6_u);
1437 if (rc > 0)
1438 addr.sa_family = AF_INET6;
1439 } else {
1440 addr.sa_family = AF_INET;
1441 }
1442
1443 if (rc <= 0) {
1444 /* we failed translating address */
1445 rc = -EINVAL;
1446 goto out_err;
1447 }
1448
1449 cFYI(1, ("UNC: %s ip: %s", volume_info->UNC,
1450 volume_info->UNCip));
1451 } else if (volume_info->UNCip) {
1452 /* BB using ip addr as tcp_ses name to connect to the
1453 DFS root below */
1454 cERROR(1, ("Connecting to DFS root not implemented yet"));
1455 rc = -EINVAL;
1456 goto out_err;
1457 } else /* which tcp_sess DFS root would we conect to */ {
1458 cERROR(1,
1459 ("CIFS mount error: No UNC path (e.g. -o "
1460 "unc=//192.168.1.100/public) specified"));
1461 rc = -EINVAL;
1462 goto out_err;
1463 }
1464
1465 /* see if we already have a matching tcp_ses */
1466 tcp_ses = cifs_find_tcp_session(&addr);
1467 if (tcp_ses)
1468 return tcp_ses;
1469
1470 tcp_ses = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
1471 if (!tcp_ses) {
1472 rc = -ENOMEM;
1473 goto out_err;
1474 }
1475
1476 tcp_ses->hostname = extract_hostname(volume_info->UNC);
1477 if (IS_ERR(tcp_ses->hostname)) {
1478 rc = PTR_ERR(tcp_ses->hostname);
1479 goto out_err;
1480 }
1481
1482 tcp_ses->noblocksnd = volume_info->noblocksnd;
1483 tcp_ses->noautotune = volume_info->noautotune;
1484 atomic_set(&tcp_ses->inFlight, 0);
1485 init_waitqueue_head(&tcp_ses->response_q);
1486 init_waitqueue_head(&tcp_ses->request_q);
1487 INIT_LIST_HEAD(&tcp_ses->pending_mid_q);
1488 mutex_init(&tcp_ses->srv_mutex);
1489 memcpy(tcp_ses->workstation_RFC1001_name,
1490 volume_info->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
1491 memcpy(tcp_ses->server_RFC1001_name,
1492 volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
1493 tcp_ses->sequence_number = 0;
1494 INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
1495 INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
1496
1497 /*
1498 * at this point we are the only ones with the pointer
1499 * to the struct since the kernel thread not created yet
1500 * no need to spinlock this init of tcpStatus or srv_count
1501 */
1502 tcp_ses->tcpStatus = CifsNew;
1503 ++tcp_ses->srv_count;
1504
1505 if (addr.sa_family == AF_INET6) {
1506 cFYI(1, ("attempting ipv6 connect"));
1507 /* BB should we allow ipv6 on port 139? */
1508 /* other OS never observed in Wild doing 139 with v6 */
1509 memcpy(&tcp_ses->addr.sockAddr6, sin_server6,
1510 sizeof(struct sockaddr_in6));
1511 sin_server6->sin6_port = htons(volume_info->port);
Jeff Laytond5c56052008-12-01 18:42:33 -05001512 rc = ipv6_connect(tcp_ses);
Jeff Layton63c038c2008-12-01 18:41:46 -05001513 } else {
1514 memcpy(&tcp_ses->addr.sockAddr, sin_server,
1515 sizeof(struct sockaddr_in));
1516 sin_server->sin_port = htons(volume_info->port);
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001517 rc = ipv4_connect(tcp_ses);
Jeff Layton63c038c2008-12-01 18:41:46 -05001518 }
1519 if (rc < 0) {
1520 cERROR(1, ("Error connecting to socket. Aborting operation"));
1521 goto out_err;
1522 }
1523
1524 /*
1525 * since we're in a cifs function already, we know that
1526 * this will succeed. No need for try_module_get().
1527 */
1528 __module_get(THIS_MODULE);
1529 tcp_ses->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread,
1530 tcp_ses, "cifsd");
1531 if (IS_ERR(tcp_ses->tsk)) {
1532 rc = PTR_ERR(tcp_ses->tsk);
1533 cERROR(1, ("error %d create cifsd thread", rc));
1534 module_put(THIS_MODULE);
1535 goto out_err;
1536 }
1537
1538 /* thread spawned, put it on the list */
1539 write_lock(&cifs_tcp_ses_lock);
1540 list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list);
1541 write_unlock(&cifs_tcp_ses_lock);
1542
1543 return tcp_ses;
1544
1545out_err:
1546 if (tcp_ses) {
1547 kfree(tcp_ses->hostname);
1548 if (tcp_ses->ssocket)
1549 sock_release(tcp_ses->ssocket);
1550 kfree(tcp_ses);
1551 }
1552 return ERR_PTR(rc);
1553}
1554
Jeff Layton14fbf502008-11-14 13:53:46 -05001555static struct cifsSesInfo *
1556cifs_find_smb_ses(struct TCP_Server_Info *server, char *username)
1557{
1558 struct list_head *tmp;
1559 struct cifsSesInfo *ses;
1560
1561 write_lock(&cifs_tcp_ses_lock);
1562 list_for_each(tmp, &server->smb_ses_list) {
1563 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
1564 if (strncmp(ses->userName, username, MAX_USERNAME_SIZE))
1565 continue;
1566
1567 ++ses->ses_count;
1568 write_unlock(&cifs_tcp_ses_lock);
1569 return ses;
1570 }
1571 write_unlock(&cifs_tcp_ses_lock);
1572 return NULL;
1573}
1574
1575static void
1576cifs_put_smb_ses(struct cifsSesInfo *ses)
1577{
1578 int xid;
1579 struct TCP_Server_Info *server = ses->server;
1580
1581 write_lock(&cifs_tcp_ses_lock);
1582 if (--ses->ses_count > 0) {
1583 write_unlock(&cifs_tcp_ses_lock);
1584 return;
1585 }
1586
1587 list_del_init(&ses->smb_ses_list);
1588 write_unlock(&cifs_tcp_ses_lock);
1589
1590 if (ses->status == CifsGood) {
1591 xid = GetXid();
1592 CIFSSMBLogoff(xid, ses);
1593 _FreeXid(xid);
1594 }
1595 sesInfoFree(ses);
1596 cifs_put_tcp_session(server);
1597}
1598
Jeff Laytonf1987b42008-11-15 11:12:47 -05001599static struct cifsTconInfo *
1600cifs_find_tcon(struct cifsSesInfo *ses, const char *unc)
1601{
1602 struct list_head *tmp;
1603 struct cifsTconInfo *tcon;
1604
1605 write_lock(&cifs_tcp_ses_lock);
1606 list_for_each(tmp, &ses->tcon_list) {
1607 tcon = list_entry(tmp, struct cifsTconInfo, tcon_list);
1608 if (tcon->tidStatus == CifsExiting)
1609 continue;
1610 if (strncmp(tcon->treeName, unc, MAX_TREE_SIZE))
1611 continue;
1612
1613 ++tcon->tc_count;
1614 write_unlock(&cifs_tcp_ses_lock);
1615 return tcon;
1616 }
1617 write_unlock(&cifs_tcp_ses_lock);
1618 return NULL;
1619}
1620
1621static void
1622cifs_put_tcon(struct cifsTconInfo *tcon)
1623{
1624 int xid;
1625 struct cifsSesInfo *ses = tcon->ses;
1626
1627 write_lock(&cifs_tcp_ses_lock);
1628 if (--tcon->tc_count > 0) {
1629 write_unlock(&cifs_tcp_ses_lock);
1630 return;
1631 }
1632
1633 list_del_init(&tcon->tcon_list);
1634 write_unlock(&cifs_tcp_ses_lock);
1635
1636 xid = GetXid();
1637 CIFSSMBTDis(xid, tcon);
1638 _FreeXid(xid);
1639
1640 DeleteTconOplockQEntries(tcon);
1641 tconInfoFree(tcon);
1642 cifs_put_smb_ses(ses);
1643}
1644
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645int
Steve French50c2f752007-07-13 00:33:32 +00001646get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
1647 const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
Steve French366781c2008-01-25 10:12:41 +00001648 struct dfs_info3_param **preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649{
1650 char *temp_unc;
1651 int rc = 0;
1652
1653 *pnum_referrals = 0;
Steve French366781c2008-01-25 10:12:41 +00001654 *preferrals = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655
1656 if (pSesInfo->ipc_tid == 0) {
1657 temp_unc = kmalloc(2 /* for slashes */ +
Steve French50c2f752007-07-13 00:33:32 +00001658 strnlen(pSesInfo->serverName,
1659 SERVER_NAME_LEN_WITH_NULL * 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 + 1 + 4 /* slash IPC$ */ + 2,
1661 GFP_KERNEL);
1662 if (temp_unc == NULL)
1663 return -ENOMEM;
1664 temp_unc[0] = '\\';
1665 temp_unc[1] = '\\';
1666 strcpy(temp_unc + 2, pSesInfo->serverName);
1667 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1668 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1669 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00001670 ("CIFS Tcon rc = %d ipc_tid = %d", rc, pSesInfo->ipc_tid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 kfree(temp_unc);
1672 }
1673 if (rc == 0)
Steve Frenchc2cf07d2008-05-15 06:20:02 +00001674 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001675 pnum_referrals, nls_codepage, remap);
Steve French366781c2008-01-25 10:12:41 +00001676 /* BB map targetUNCs to dfs_info3 structures, here or
1677 in CIFSGetDFSRefer BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678
1679 return rc;
1680}
1681
Jeff Layton09e50d52008-07-23 10:11:19 -04001682#ifdef CONFIG_DEBUG_LOCK_ALLOC
1683static struct lock_class_key cifs_key[2];
1684static struct lock_class_key cifs_slock_key[2];
1685
1686static inline void
1687cifs_reclassify_socket4(struct socket *sock)
1688{
1689 struct sock *sk = sock->sk;
1690 BUG_ON(sock_owned_by_user(sk));
1691 sock_lock_init_class_and_name(sk, "slock-AF_INET-CIFS",
1692 &cifs_slock_key[0], "sk_lock-AF_INET-CIFS", &cifs_key[0]);
1693}
1694
1695static inline void
1696cifs_reclassify_socket6(struct socket *sock)
1697{
1698 struct sock *sk = sock->sk;
1699 BUG_ON(sock_owned_by_user(sk));
1700 sock_lock_init_class_and_name(sk, "slock-AF_INET6-CIFS",
1701 &cifs_slock_key[1], "sk_lock-AF_INET6-CIFS", &cifs_key[1]);
1702}
1703#else
1704static inline void
1705cifs_reclassify_socket4(struct socket *sock)
1706{
1707}
1708
1709static inline void
1710cifs_reclassify_socket6(struct socket *sock)
1711{
1712}
1713#endif
1714
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715/* See RFC1001 section 14 on representation of Netbios names */
Steve French50c2f752007-07-13 00:33:32 +00001716static void rfc1002mangle(char *target, char *source, unsigned int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717{
Steve French50c2f752007-07-13 00:33:32 +00001718 unsigned int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719
Steve French50c2f752007-07-13 00:33:32 +00001720 for (i = 0, j = 0; i < (length); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 /* mask a nibble at a time and encode */
1722 target[j] = 'A' + (0x0F & (source[i] >> 4));
1723 target[j+1] = 'A' + (0x0F & source[i]);
Steve French50c2f752007-07-13 00:33:32 +00001724 j += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 }
1726
1727}
1728
1729
1730static int
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001731ipv4_connect(struct TCP_Server_Info *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732{
1733 int rc = 0;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001734 bool connected = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 __be16 orig_port = 0;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001736 struct socket *socket = server->ssocket;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001738 if (socket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001739 rc = sock_create_kern(PF_INET, SOCK_STREAM,
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001740 IPPROTO_TCP, &socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001742 cERROR(1, ("Error %d creating socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 }
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001745
1746 /* BB other socket options to set KEEPALIVE, NODELAY? */
1747 cFYI(1, ("Socket created"));
1748 server->ssocket = socket;
1749 socket->sk->sk_allocation = GFP_NOFS;
1750 cifs_reclassify_socket4(socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 }
1752
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001753 /* user overrode default port */
1754 if (server->addr.sockAddr.sin_port) {
1755 rc = socket->ops->connect(socket, (struct sockaddr *)
1756 &server->addr.sockAddr,
1757 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 if (rc >= 0)
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001759 connected = true;
Steve French50c2f752007-07-13 00:33:32 +00001760 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001762 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001763 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 later if fall back ports fail this time */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001765 orig_port = server->addr.sockAddr.sin_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766
1767 /* do not retry on the same port we just failed on */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001768 if (server->addr.sockAddr.sin_port != htons(CIFS_PORT)) {
1769 server->addr.sockAddr.sin_port = htons(CIFS_PORT);
1770 rc = socket->ops->connect(socket,
1771 (struct sockaddr *)
1772 &server->addr.sockAddr,
1773 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 if (rc >= 0)
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001775 connected = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 }
1777 }
1778 if (!connected) {
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001779 server->addr.sockAddr.sin_port = htons(RFC1001_PORT);
1780 rc = socket->ops->connect(socket, (struct sockaddr *)
1781 &server->addr.sockAddr,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001782 sizeof(struct sockaddr_in), 0);
Steve French50c2f752007-07-13 00:33:32 +00001783 if (rc >= 0)
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001784 connected = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 }
1786
1787 /* give up here - unless we want to retry on different
1788 protocol families some day */
1789 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001790 if (orig_port)
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001791 server->addr.sockAddr.sin_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001792 cFYI(1, ("Error %d connecting to server via ipv4", rc));
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001793 sock_release(socket);
1794 server->ssocket = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 return rc;
1796 }
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001797
1798
1799 /*
1800 * Eventually check for other socket options to change from
1801 * the default. sock_setsockopt not used because it expects
1802 * user space buffer
1803 */
1804 socket->sk->sk_rcvtimeo = 7 * HZ;
1805 socket->sk->sk_sndtimeo = 3 * HZ;
Steve Frenchedf1ae42008-10-29 00:47:57 +00001806
Steve Frenchb387eae2005-10-10 14:21:15 -07001807 /* make the bufsizes depend on wsize/rsize and max requests */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001808 if (server->noautotune) {
1809 if (socket->sk->sk_sndbuf < (200 * 1024))
1810 socket->sk->sk_sndbuf = 200 * 1024;
1811 if (socket->sk->sk_rcvbuf < (140 * 1024))
1812 socket->sk->sk_rcvbuf = 140 * 1024;
Steve Frenchedf1ae42008-10-29 00:47:57 +00001813 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001815 cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",
1816 socket->sk->sk_sndbuf,
1817 socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo));
1818
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 /* send RFC1001 sessinit */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001820 if (server->addr.sockAddr.sin_port == htons(RFC1001_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 /* some servers require RFC1001 sessinit before sending
Steve French50c2f752007-07-13 00:33:32 +00001822 negprot - BB check reconnection in case where second
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 sessinit is sent but no second negprot */
Steve French50c2f752007-07-13 00:33:32 +00001824 struct rfc1002_session_packet *ses_init_buf;
1825 struct smb_hdr *smb_buf;
1826 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
1827 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001828 if (ses_init_buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829 ses_init_buf->trailer.session_req.called_len = 32;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001830 if (server->server_RFC1001_name &&
1831 server->server_RFC1001_name[0] != 0)
Jeff Layton8ecaf672008-12-01 15:23:50 -05001832 rfc1002mangle(ses_init_buf->trailer.
1833 session_req.called_name,
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001834 server->server_RFC1001_name,
Jeff Layton8ecaf672008-12-01 15:23:50 -05001835 RFC1001_NAME_LEN_WITH_NULL);
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001836 else
Jeff Layton8ecaf672008-12-01 15:23:50 -05001837 rfc1002mangle(ses_init_buf->trailer.
1838 session_req.called_name,
1839 DEFAULT_CIFS_CALLED_NAME,
1840 RFC1001_NAME_LEN_WITH_NULL);
Steve Frencha10faeb22005-08-22 21:38:31 -07001841
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 ses_init_buf->trailer.session_req.calling_len = 32;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001843
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 /* calling name ends in null (byte 16) from old smb
1845 convention. */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001846 if (server->workstation_RFC1001_name &&
1847 server->workstation_RFC1001_name[0] != 0)
Jeff Layton8ecaf672008-12-01 15:23:50 -05001848 rfc1002mangle(ses_init_buf->trailer.
1849 session_req.calling_name,
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001850 server->workstation_RFC1001_name,
Jeff Layton8ecaf672008-12-01 15:23:50 -05001851 RFC1001_NAME_LEN_WITH_NULL);
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001852 else
Jeff Layton8ecaf672008-12-01 15:23:50 -05001853 rfc1002mangle(ses_init_buf->trailer.
1854 session_req.calling_name,
1855 "LINUX_CIFS_CLNT",
1856 RFC1001_NAME_LEN_WITH_NULL);
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001857
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 ses_init_buf->trailer.session_req.scope1 = 0;
1859 ses_init_buf->trailer.session_req.scope2 = 0;
1860 smb_buf = (struct smb_hdr *)ses_init_buf;
1861 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1862 smb_buf->smb_buf_length = 0x81000044;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001863 rc = smb_send(socket, smb_buf, 0x44,
1864 (struct sockaddr *) &server->addr.sockAddr,
1865 server->noblocksnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 kfree(ses_init_buf);
Steve French50c2f752007-07-13 00:33:32 +00001867 msleep(1); /* RFC1001 layer in at least one server
Steve French083d3a22006-03-03 09:53:36 +00001868 requires very short break before negprot
1869 presumably because not expecting negprot
1870 to follow so fast. This is a simple
Steve French50c2f752007-07-13 00:33:32 +00001871 solution that works without
Steve French083d3a22006-03-03 09:53:36 +00001872 complicating the code and causes no
1873 significant slowing down on mount
1874 for everyone else */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 }
Steve French50c2f752007-07-13 00:33:32 +00001876 /* else the negprot may still work without this
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 even though malloc failed */
Steve French50c2f752007-07-13 00:33:32 +00001878
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 }
Steve French50c2f752007-07-13 00:33:32 +00001880
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 return rc;
1882}
1883
1884static int
Jeff Laytond5c56052008-12-01 18:42:33 -05001885ipv6_connect(struct TCP_Server_Info *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886{
1887 int rc = 0;
Jeff Laytond5c56052008-12-01 18:42:33 -05001888 bool connected = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 __be16 orig_port = 0;
Jeff Laytond5c56052008-12-01 18:42:33 -05001890 struct socket *socket = server->ssocket;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891
Jeff Laytond5c56052008-12-01 18:42:33 -05001892 if (socket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001893 rc = sock_create_kern(PF_INET6, SOCK_STREAM,
Jeff Laytond5c56052008-12-01 18:42:33 -05001894 IPPROTO_TCP, &socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001896 cERROR(1, ("Error %d creating ipv6 socket", rc));
Jeff Laytond5c56052008-12-01 18:42:33 -05001897 socket = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 }
Jeff Laytond5c56052008-12-01 18:42:33 -05001900
1901 /* BB other socket options to set KEEPALIVE, NODELAY? */
1902 cFYI(1, ("ipv6 Socket created"));
1903 server->ssocket = socket;
1904 socket->sk->sk_allocation = GFP_NOFS;
1905 cifs_reclassify_socket6(socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 }
1907
Jeff Laytond5c56052008-12-01 18:42:33 -05001908 /* user overrode default port */
1909 if (server->addr.sockAddr6.sin6_port) {
1910 rc = socket->ops->connect(socket,
1911 (struct sockaddr *) &server->addr.sockAddr6,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001912 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 if (rc >= 0)
Jeff Laytond5c56052008-12-01 18:42:33 -05001914 connected = true;
Steve French50c2f752007-07-13 00:33:32 +00001915 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001917 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001918 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 later if fall back ports fail this time */
1920
Jeff Laytond5c56052008-12-01 18:42:33 -05001921 orig_port = server->addr.sockAddr6.sin6_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 /* do not retry on the same port we just failed on */
Jeff Laytond5c56052008-12-01 18:42:33 -05001923 if (server->addr.sockAddr6.sin6_port != htons(CIFS_PORT)) {
1924 server->addr.sockAddr6.sin6_port = htons(CIFS_PORT);
1925 rc = socket->ops->connect(socket, (struct sockaddr *)
1926 &server->addr.sockAddr6,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001927 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 if (rc >= 0)
Jeff Laytond5c56052008-12-01 18:42:33 -05001929 connected = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 }
1931 }
1932 if (!connected) {
Jeff Laytond5c56052008-12-01 18:42:33 -05001933 server->addr.sockAddr6.sin6_port = htons(RFC1001_PORT);
1934 rc = socket->ops->connect(socket, (struct sockaddr *)
1935 &server->addr.sockAddr6,
1936 sizeof(struct sockaddr_in6), 0);
Steve French50c2f752007-07-13 00:33:32 +00001937 if (rc >= 0)
Jeff Laytond5c56052008-12-01 18:42:33 -05001938 connected = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 }
1940
1941 /* give up here - unless we want to retry on different
1942 protocol families some day */
1943 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001944 if (orig_port)
Jeff Laytond5c56052008-12-01 18:42:33 -05001945 server->addr.sockAddr6.sin6_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001946 cFYI(1, ("Error %d connecting to server via ipv6", rc));
Jeff Laytond5c56052008-12-01 18:42:33 -05001947 sock_release(socket);
1948 server->ssocket = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 return rc;
1950 }
Steve Frenchedf1ae42008-10-29 00:47:57 +00001951
Jeff Laytond5c56052008-12-01 18:42:33 -05001952 /*
1953 * Eventually check for other socket options to change from
1954 * the default. sock_setsockopt not used because it expects
1955 * user space buffer
1956 */
1957 socket->sk->sk_rcvtimeo = 7 * HZ;
1958 socket->sk->sk_sndtimeo = 3 * HZ;
1959 server->ssocket = socket;
Steve French50c2f752007-07-13 00:33:32 +00001960
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 return rc;
1962}
1963
Steve French50c2f752007-07-13 00:33:32 +00001964void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
1965 struct super_block *sb, struct smb_vol *vol_info)
Steve French8af18972007-02-14 04:42:51 +00001966{
1967 /* if we are reconnecting then should we check to see if
1968 * any requested capabilities changed locally e.g. via
1969 * remount but we can not do much about it here
1970 * if they have (even if we could detect it by the following)
1971 * Perhaps we could add a backpointer to array of sb from tcon
1972 * or if we change to make all sb to same share the same
1973 * sb as NFS - then we only have one backpointer to sb.
1974 * What if we wanted to mount the server share twice once with
1975 * and once without posixacls or posix paths? */
1976 __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001977
Steve Frenchc18c8422007-07-18 23:21:09 +00001978 if (vol_info && vol_info->no_linux_ext) {
1979 tcon->fsUnixInfo.Capability = 0;
1980 tcon->unix_ext = 0; /* Unix Extensions disabled */
1981 cFYI(1, ("Linux protocol extensions disabled"));
1982 return;
1983 } else if (vol_info)
1984 tcon->unix_ext = 1; /* Unix Extensions supported */
1985
1986 if (tcon->unix_ext == 0) {
1987 cFYI(1, ("Unix extensions disabled so not set on reconnect"));
1988 return;
1989 }
Steve French50c2f752007-07-13 00:33:32 +00001990
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001991 if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
Steve French8af18972007-02-14 04:42:51 +00001992 __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001993
Steve French8af18972007-02-14 04:42:51 +00001994 /* check for reconnect case in which we do not
1995 want to change the mount behavior if we can avoid it */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001996 if (vol_info == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001997 /* turn off POSIX ACL and PATHNAMES if not set
Steve French8af18972007-02-14 04:42:51 +00001998 originally at mount time */
1999 if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
2000 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00002001 if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
2002 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
2003 cERROR(1, ("POSIXPATH support change"));
Steve French8af18972007-02-14 04:42:51 +00002004 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00002005 } else if ((cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
2006 cERROR(1, ("possible reconnect error"));
2007 cERROR(1,
2008 ("server disabled POSIX path support"));
2009 }
Steve French8af18972007-02-14 04:42:51 +00002010 }
Steve French50c2f752007-07-13 00:33:32 +00002011
Steve French8af18972007-02-14 04:42:51 +00002012 cap &= CIFS_UNIX_CAP_MASK;
Steve French75865f8c2007-06-24 18:30:48 +00002013 if (vol_info && vol_info->no_psx_acl)
Steve French8af18972007-02-14 04:42:51 +00002014 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00002015 else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002016 cFYI(1, ("negotiated posix acl support"));
2017 if (sb)
Steve French8af18972007-02-14 04:42:51 +00002018 sb->s_flags |= MS_POSIXACL;
2019 }
2020
Steve French75865f8c2007-06-24 18:30:48 +00002021 if (vol_info && vol_info->posix_paths == 0)
Steve French8af18972007-02-14 04:42:51 +00002022 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00002023 else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002024 cFYI(1, ("negotiate posix pathnames"));
Steve French75865f8c2007-06-24 18:30:48 +00002025 if (sb)
Steve French50c2f752007-07-13 00:33:32 +00002026 CIFS_SB(sb)->mnt_cifs_flags |=
Steve French8af18972007-02-14 04:42:51 +00002027 CIFS_MOUNT_POSIX_PATHS;
2028 }
Steve French50c2f752007-07-13 00:33:32 +00002029
Steve French984acfe2007-04-26 16:42:50 +00002030 /* We might be setting the path sep back to a different
2031 form if we are reconnecting and the server switched its
Steve French50c2f752007-07-13 00:33:32 +00002032 posix path capability for this share */
Steve French75865f8c2007-06-24 18:30:48 +00002033 if (sb && (CIFS_SB(sb)->prepathlen > 0))
Steve French984acfe2007-04-26 16:42:50 +00002034 CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
Steve French75865f8c2007-06-24 18:30:48 +00002035
2036 if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
2037 if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
2038 CIFS_SB(sb)->rsize = 127 * 1024;
Steve French90c81e02008-02-12 20:32:36 +00002039 cFYI(DBG2,
2040 ("larger reads not supported by srv"));
Steve French75865f8c2007-06-24 18:30:48 +00002041 }
2042 }
Steve French50c2f752007-07-13 00:33:32 +00002043
2044
2045 cFYI(1, ("Negotiate caps 0x%x", (int)cap));
Steve French8af18972007-02-14 04:42:51 +00002046#ifdef CONFIG_CIFS_DEBUG2
Steve French75865f8c2007-06-24 18:30:48 +00002047 if (cap & CIFS_UNIX_FCNTL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002048 cFYI(1, ("FCNTL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002049 if (cap & CIFS_UNIX_EXTATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002050 cFYI(1, ("EXTATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002051 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002052 cFYI(1, ("POSIX path cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002053 if (cap & CIFS_UNIX_XATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002054 cFYI(1, ("XATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002055 if (cap & CIFS_UNIX_POSIX_ACL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002056 cFYI(1, ("POSIX ACL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002057 if (cap & CIFS_UNIX_LARGE_READ_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002058 cFYI(1, ("very large read cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002059 if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002060 cFYI(1, ("very large write cap"));
Steve French8af18972007-02-14 04:42:51 +00002061#endif /* CIFS_DEBUG2 */
2062 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
Steve French442aa312007-09-24 20:25:46 +00002063 if (vol_info == NULL) {
Steve French5a44b312007-09-20 15:16:24 +00002064 cFYI(1, ("resetting capabilities failed"));
Steve French442aa312007-09-24 20:25:46 +00002065 } else
Steve French5a44b312007-09-20 15:16:24 +00002066 cERROR(1, ("Negotiating Unix capabilities "
2067 "with the server failed. Consider "
2068 "mounting with the Unix Extensions\n"
2069 "disabled, if problems are found, "
2070 "by specifying the nounix mount "
Steve French2224f4e2007-09-20 15:37:29 +00002071 "option."));
Steve French5a44b312007-09-20 15:16:24 +00002072
Steve French8af18972007-02-14 04:42:51 +00002073 }
2074 }
2075}
2076
Steve French03a143c2008-02-14 06:38:30 +00002077static void
2078convert_delimiter(char *path, char delim)
2079{
2080 int i;
Steve Frenchc2d68ea2008-02-15 19:20:18 +00002081 char old_delim;
Steve French03a143c2008-02-14 06:38:30 +00002082
2083 if (path == NULL)
2084 return;
2085
Steve French582d21e2008-05-13 04:54:12 +00002086 if (delim == '/')
Steve Frenchc2d68ea2008-02-15 19:20:18 +00002087 old_delim = '\\';
2088 else
2089 old_delim = '/';
2090
Steve French03a143c2008-02-14 06:38:30 +00002091 for (i = 0; path[i] != '\0'; i++) {
Steve Frenchc2d68ea2008-02-15 19:20:18 +00002092 if (path[i] == old_delim)
Steve French03a143c2008-02-14 06:38:30 +00002093 path[i] = delim;
2094 }
2095}
2096
Steve French3b795212008-11-13 19:45:32 +00002097static void setup_cifs_sb(struct smb_vol *pvolume_info,
2098 struct cifs_sb_info *cifs_sb)
2099{
2100 if (pvolume_info->rsize > CIFSMaxBufSize) {
2101 cERROR(1, ("rsize %d too large, using MaxBufSize",
2102 pvolume_info->rsize));
2103 cifs_sb->rsize = CIFSMaxBufSize;
2104 } else if ((pvolume_info->rsize) &&
2105 (pvolume_info->rsize <= CIFSMaxBufSize))
2106 cifs_sb->rsize = pvolume_info->rsize;
2107 else /* default */
2108 cifs_sb->rsize = CIFSMaxBufSize;
2109
2110 if (pvolume_info->wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
2111 cERROR(1, ("wsize %d too large, using 4096 instead",
2112 pvolume_info->wsize));
2113 cifs_sb->wsize = 4096;
2114 } else if (pvolume_info->wsize)
2115 cifs_sb->wsize = pvolume_info->wsize;
2116 else
2117 cifs_sb->wsize = min_t(const int,
2118 PAGEVEC_SIZE * PAGE_CACHE_SIZE,
2119 127*1024);
2120 /* old default of CIFSMaxBufSize was too small now
2121 that SMB Write2 can send multiple pages in kvec.
2122 RFC1001 does not describe what happens when frame
2123 bigger than 128K is sent so use that as max in
2124 conjunction with 52K kvec constraint on arch with 4K
2125 page size */
2126
2127 if (cifs_sb->rsize < 2048) {
2128 cifs_sb->rsize = 2048;
2129 /* Windows ME may prefer this */
2130 cFYI(1, ("readsize set to minimum: 2048"));
2131 }
2132 /* calculate prepath */
2133 cifs_sb->prepath = pvolume_info->prepath;
2134 if (cifs_sb->prepath) {
2135 cifs_sb->prepathlen = strlen(cifs_sb->prepath);
2136 /* we can not convert the / to \ in the path
2137 separators in the prefixpath yet because we do not
2138 know (until reset_cifs_unix_caps is called later)
2139 whether POSIX PATH CAP is available. We normalize
2140 the / to \ after reset_cifs_unix_caps is called */
2141 pvolume_info->prepath = NULL;
2142 } else
2143 cifs_sb->prepathlen = 0;
2144 cifs_sb->mnt_uid = pvolume_info->linux_uid;
2145 cifs_sb->mnt_gid = pvolume_info->linux_gid;
2146 cifs_sb->mnt_file_mode = pvolume_info->file_mode;
2147 cifs_sb->mnt_dir_mode = pvolume_info->dir_mode;
2148 cFYI(1, ("file mode: 0x%x dir mode: 0x%x",
2149 cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode));
2150
2151 if (pvolume_info->noperm)
2152 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
2153 if (pvolume_info->setuids)
2154 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
2155 if (pvolume_info->server_ino)
2156 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
2157 if (pvolume_info->remap)
2158 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
2159 if (pvolume_info->no_xattr)
2160 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
2161 if (pvolume_info->sfu_emul)
2162 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
2163 if (pvolume_info->nobrl)
2164 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Steve French13a6e422008-12-02 17:24:33 +00002165 if (pvolume_info->mand_lock)
2166 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOPOSIXBRL;
Steve French3b795212008-11-13 19:45:32 +00002167 if (pvolume_info->cifs_acl)
2168 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
2169 if (pvolume_info->override_uid)
2170 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
2171 if (pvolume_info->override_gid)
2172 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
2173 if (pvolume_info->dynperm)
2174 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
2175 if (pvolume_info->direct_io) {
2176 cFYI(1, ("mounting share using direct i/o"));
2177 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
2178 }
2179
2180 if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm))
2181 cERROR(1, ("mount option dynperm ignored if cifsacl "
2182 "mount option supported"));
2183}
2184
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185int
2186cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2187 char *mount_data, const char *devname)
2188{
2189 int rc = 0;
2190 int xid;
Jeff Layton7586b762008-12-01 18:41:49 -05002191 struct smb_vol *volume_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192 struct cifsSesInfo *pSesInfo = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193 struct cifsTconInfo *tcon = NULL;
2194 struct TCP_Server_Info *srvTcp = NULL;
2195
2196 xid = GetXid();
2197
Jeff Layton7586b762008-12-01 18:41:49 -05002198 volume_info = kzalloc(sizeof(struct smb_vol), GFP_KERNEL);
2199 if (!volume_info) {
2200 rc = -ENOMEM;
2201 goto out;
2202 }
Steve French50c2f752007-07-13 00:33:32 +00002203
Jeff Layton7586b762008-12-01 18:41:49 -05002204 if (cifs_parse_mount_options(mount_data, devname, volume_info)) {
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002205 rc = -EINVAL;
2206 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207 }
2208
Jeff Layton7586b762008-12-01 18:41:49 -05002209 if (volume_info->nullauth) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002210 cFYI(1, ("null user"));
Jeff Layton7586b762008-12-01 18:41:49 -05002211 volume_info->username = "";
2212 } else if (volume_info->username) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213 /* BB fixme parse for domain name here */
Jeff Layton7586b762008-12-01 18:41:49 -05002214 cFYI(1, ("Username: %s", volume_info->username));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 } else {
Steve Frenchbf820672005-12-01 22:32:42 -08002216 cifserror("No username specified");
Steve French50c2f752007-07-13 00:33:32 +00002217 /* In userspace mount helper we can get user name from alternate
2218 locations such as env variables and files on disk */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002219 rc = -EINVAL;
2220 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 }
2222
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223
2224 /* this is needed for ASCII cp to Unicode converts */
Jeff Layton7586b762008-12-01 18:41:49 -05002225 if (volume_info->iocharset == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226 cifs_sb->local_nls = load_nls_default();
2227 /* load_nls_default can not return null */
2228 } else {
Jeff Layton7586b762008-12-01 18:41:49 -05002229 cifs_sb->local_nls = load_nls(volume_info->iocharset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002230 if (cifs_sb->local_nls == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002231 cERROR(1, ("CIFS mount error: iocharset %s not found",
Jeff Layton7586b762008-12-01 18:41:49 -05002232 volume_info->iocharset));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002233 rc = -ELIBACC;
2234 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235 }
2236 }
2237
Jeff Layton63c038c2008-12-01 18:41:46 -05002238 /* get a reference to a tcp session */
Jeff Layton7586b762008-12-01 18:41:49 -05002239 srvTcp = cifs_get_tcp_session(volume_info);
Jeff Layton63c038c2008-12-01 18:41:46 -05002240 if (IS_ERR(srvTcp)) {
2241 rc = PTR_ERR(srvTcp);
2242 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 }
2244
Jeff Layton7586b762008-12-01 18:41:49 -05002245 pSesInfo = cifs_find_smb_ses(srvTcp, volume_info->username);
Jeff Layton14fbf502008-11-14 13:53:46 -05002246 if (pSesInfo) {
Jeff Layton1d9a8852007-12-31 01:37:11 +00002247 cFYI(1, ("Existing smb sess found (status=%d)",
2248 pSesInfo->status));
Jeff Layton14fbf502008-11-14 13:53:46 -05002249 /*
2250 * The existing SMB session already has a reference to srvTcp,
2251 * so we can put back the extra one we got before
2252 */
2253 cifs_put_tcp_session(srvTcp);
2254
Steve French88e7d702008-01-03 17:37:09 +00002255 down(&pSesInfo->sesSem);
Steve French3b795212008-11-13 19:45:32 +00002256 if (pSesInfo->need_reconnect) {
Jeff Layton1d9a8852007-12-31 01:37:11 +00002257 cFYI(1, ("Session needs reconnect"));
Jeff Layton1d9a8852007-12-31 01:37:11 +00002258 rc = cifs_setup_session(xid, pSesInfo,
2259 cifs_sb->local_nls);
Jeff Layton1d9a8852007-12-31 01:37:11 +00002260 }
Steve French88e7d702008-01-03 17:37:09 +00002261 up(&pSesInfo->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 } else if (!rc) {
Steve Frenchbf820672005-12-01 22:32:42 -08002263 cFYI(1, ("Existing smb sess not found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 pSesInfo = sesInfoAlloc();
Jeff Layton14fbf502008-11-14 13:53:46 -05002265 if (pSesInfo == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 rc = -ENOMEM;
Jeff Layton14fbf502008-11-14 13:53:46 -05002267 goto mount_fail_check;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268 }
2269
Jeff Layton14fbf502008-11-14 13:53:46 -05002270 /* new SMB session uses our srvTcp ref */
2271 pSesInfo->server = srvTcp;
Jeff Layton63c038c2008-12-01 18:41:46 -05002272 if (srvTcp->addr.sockAddr6.sin6_family == AF_INET6)
Jeff Layton8ecaf672008-12-01 15:23:50 -05002273 sprintf(pSesInfo->serverName, NIP6_FMT,
Jeff Layton63c038c2008-12-01 18:41:46 -05002274 NIP6(srvTcp->addr.sockAddr6.sin6_addr));
Jeff Layton8ecaf672008-12-01 15:23:50 -05002275 else
2276 sprintf(pSesInfo->serverName, NIPQUAD_FMT,
Jeff Layton63c038c2008-12-01 18:41:46 -05002277 NIPQUAD(srvTcp->addr.sockAddr.sin_addr.s_addr));
Jeff Layton14fbf502008-11-14 13:53:46 -05002278
2279 write_lock(&cifs_tcp_ses_lock);
2280 list_add(&pSesInfo->smb_ses_list, &srvTcp->smb_ses_list);
2281 write_unlock(&cifs_tcp_ses_lock);
2282
Jeff Layton7586b762008-12-01 18:41:49 -05002283 /* volume_info->password freed at unmount */
2284 if (volume_info->password) {
2285 pSesInfo->password = volume_info->password;
Jeff Layton14fbf502008-11-14 13:53:46 -05002286 /* set to NULL to prevent freeing on exit */
Jeff Layton7586b762008-12-01 18:41:49 -05002287 volume_info->password = NULL;
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002288 }
Jeff Layton7586b762008-12-01 18:41:49 -05002289 if (volume_info->username)
2290 strncpy(pSesInfo->userName, volume_info->username,
Jeff Layton14fbf502008-11-14 13:53:46 -05002291 MAX_USERNAME_SIZE);
Jeff Layton7586b762008-12-01 18:41:49 -05002292 if (volume_info->domainname) {
2293 int len = strlen(volume_info->domainname);
Jeff Layton14fbf502008-11-14 13:53:46 -05002294 pSesInfo->domainName = kmalloc(len + 1, GFP_KERNEL);
2295 if (pSesInfo->domainName)
2296 strcpy(pSesInfo->domainName,
Jeff Layton7586b762008-12-01 18:41:49 -05002297 volume_info->domainname);
Jeff Layton14fbf502008-11-14 13:53:46 -05002298 }
Jeff Layton7586b762008-12-01 18:41:49 -05002299 pSesInfo->linux_uid = volume_info->linux_uid;
2300 pSesInfo->overrideSecFlg = volume_info->secFlg;
Jeff Layton14fbf502008-11-14 13:53:46 -05002301 down(&pSesInfo->sesSem);
2302
2303 /* BB FIXME need to pass vol->secFlgs BB */
2304 rc = cifs_setup_session(xid, pSesInfo,
2305 cifs_sb->local_nls);
2306 up(&pSesInfo->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 }
Steve French50c2f752007-07-13 00:33:32 +00002308
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 /* search for existing tcon to this server share */
2310 if (!rc) {
Jeff Layton7586b762008-12-01 18:41:49 -05002311 setup_cifs_sb(volume_info, cifs_sb);
Steve French27adb442008-05-23 19:43:29 +00002312
Jeff Layton7586b762008-12-01 18:41:49 -05002313 tcon = cifs_find_tcon(pSesInfo, volume_info->UNC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314 if (tcon) {
Steve Frenchbf820672005-12-01 22:32:42 -08002315 cFYI(1, ("Found match on UNC path"));
Jeff Laytonf1987b42008-11-15 11:12:47 -05002316 /* existing tcon already has a reference */
2317 cifs_put_smb_ses(pSesInfo);
Jeff Layton7586b762008-12-01 18:41:49 -05002318 if (tcon->seal != volume_info->seal)
Steve Frenchab3f9922008-11-17 16:03:00 +00002319 cERROR(1, ("transport encryption setting "
2320 "conflicts with existing tid"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321 } else {
2322 tcon = tconInfoAlloc();
Steve French3b795212008-11-13 19:45:32 +00002323 if (tcon == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 rc = -ENOMEM;
Steve French3b795212008-11-13 19:45:32 +00002325 goto mount_fail_check;
2326 }
Steve Frenchab3f9922008-11-17 16:03:00 +00002327 tcon->ses = pSesInfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328
Steve French3b795212008-11-13 19:45:32 +00002329 /* check for null share name ie connect to dfs root */
Jeff Layton7586b762008-12-01 18:41:49 -05002330 if ((strchr(volume_info->UNC + 3, '\\') == NULL)
2331 && (strchr(volume_info->UNC + 3, '/') == NULL)) {
Steve French3b795212008-11-13 19:45:32 +00002332 /* rc = connect_to_dfs_path(...) */
2333 cFYI(1, ("DFS root not supported"));
2334 rc = -ENODEV;
2335 goto mount_fail_check;
2336 } else {
2337 /* BB Do we need to wrap sesSem around
2338 * this TCon call and Unix SetFS as
2339 * we do on SessSetup and reconnect? */
Jeff Layton7586b762008-12-01 18:41:49 -05002340 rc = CIFSTCon(xid, pSesInfo, volume_info->UNC,
Steve French3b795212008-11-13 19:45:32 +00002341 tcon, cifs_sb->local_nls);
2342 cFYI(1, ("CIFS Tcon rc = %d", rc));
Jeff Layton7586b762008-12-01 18:41:49 -05002343 if (volume_info->nodfs) {
Steve French3b795212008-11-13 19:45:32 +00002344 tcon->Flags &= ~SMB_SHARE_IS_IN_DFS;
2345 cFYI(1, ("DFS disabled (%d)",
2346 tcon->Flags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347 }
2348 }
Jeff Layton14fbf502008-11-14 13:53:46 -05002349 if (rc)
Steve French3b795212008-11-13 19:45:32 +00002350 goto mount_fail_check;
Jeff Layton7586b762008-12-01 18:41:49 -05002351 tcon->seal = volume_info->seal;
Jeff Laytonf1987b42008-11-15 11:12:47 -05002352 write_lock(&cifs_tcp_ses_lock);
2353 list_add(&tcon->tcon_list, &pSesInfo->tcon_list);
2354 write_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 }
Steve French3b795212008-11-13 19:45:32 +00002356
2357 /* we can have only one retry value for a connection
2358 to a share so for resources mounted more than once
2359 to the same server share the last value passed in
2360 for the retry flag is used */
Jeff Layton7586b762008-12-01 18:41:49 -05002361 tcon->retry = volume_info->retry;
2362 tcon->nocase = volume_info->nocase;
2363 tcon->local_lease = volume_info->local_lease;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364 }
Steve French4523cc32007-04-30 20:13:06 +00002365 if (pSesInfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
2367 sb->s_maxbytes = (u64) 1 << 63;
2368 } else
2369 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
2370 }
2371
Steve French8af18972007-02-14 04:42:51 +00002372 /* BB FIXME fix time_gran to be larger for LANMAN sessions */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373 sb->s_time_gran = 100;
2374
Steve French3b795212008-11-13 19:45:32 +00002375mount_fail_check:
Jeff Layton14fbf502008-11-14 13:53:46 -05002376 /* on error free sesinfo and tcon struct if needed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377 if (rc) {
Jeff Laytone7ddee92008-11-14 13:44:38 -05002378 /* If find_unc succeeded then rc == 0 so we can not end */
2379 /* up accidently freeing someone elses tcon struct */
2380 if (tcon)
Jeff Laytonf1987b42008-11-15 11:12:47 -05002381 cifs_put_tcon(tcon);
2382 else if (pSesInfo)
Jeff Layton14fbf502008-11-14 13:53:46 -05002383 cifs_put_smb_ses(pSesInfo);
2384 else
2385 cifs_put_tcp_session(srvTcp);
Steve Frenchd82c2df2008-11-15 00:07:26 +00002386 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387 }
Steve Frenchd82c2df2008-11-15 00:07:26 +00002388 cifs_sb->tcon = tcon;
Steve Frenchd82c2df2008-11-15 00:07:26 +00002389
2390 /* do not care if following two calls succeed - informational */
2391 if (!tcon->ipc) {
2392 CIFSSMBQFSDeviceInfo(xid, tcon);
2393 CIFSSMBQFSAttributeInfo(xid, tcon);
2394 }
2395
2396 /* tell server which Unix caps we support */
2397 if (tcon->ses->capabilities & CAP_UNIX)
2398 /* reset of caps checks mount to see if unix extensions
2399 disabled for just this mount */
Jeff Layton7586b762008-12-01 18:41:49 -05002400 reset_cifs_unix_caps(xid, tcon, sb, volume_info);
Steve Frenchd82c2df2008-11-15 00:07:26 +00002401 else
2402 tcon->unix_ext = 0; /* server does not support them */
2403
2404 /* convert forward to back slashes in prepath here if needed */
2405 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
2406 convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb));
2407
2408 if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
2409 cifs_sb->rsize = 1024 * 127;
2410 cFYI(DBG2, ("no very large read support, rsize now 127K"));
2411 }
2412 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
2413 cifs_sb->wsize = min(cifs_sb->wsize,
2414 (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
2415 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
2416 cifs_sb->rsize = min(cifs_sb->rsize,
2417 (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418
Jeff Layton7586b762008-12-01 18:41:49 -05002419 /* volume_info->password is freed above when existing session found
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420 (in which case it is not needed anymore) but when new sesion is created
2421 the password ptr is put in the new session structure (in which case the
2422 password will be freed at unmount time) */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002423out:
2424 /* zero out password before freeing */
Jeff Layton7586b762008-12-01 18:41:49 -05002425 if (volume_info) {
2426 if (volume_info->password != NULL) {
2427 memset(volume_info->password, 0,
2428 strlen(volume_info->password));
2429 kfree(volume_info->password);
2430 }
2431 kfree(volume_info->UNC);
2432 kfree(volume_info->prepath);
2433 kfree(volume_info);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002434 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435 FreeXid(xid);
2436 return rc;
2437}
2438
2439static int
2440CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French7c7b25b2006-06-01 19:20:10 +00002441 char session_key[CIFS_SESS_KEY_SIZE],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 const struct nls_table *nls_codepage)
2443{
2444 struct smb_hdr *smb_buffer;
2445 struct smb_hdr *smb_buffer_response;
2446 SESSION_SETUP_ANDX *pSMB;
2447 SESSION_SETUP_ANDX *pSMBr;
2448 char *bcc_ptr;
2449 char *user;
2450 char *domain;
2451 int rc = 0;
2452 int remaining_words = 0;
2453 int bytes_returned = 0;
2454 int len;
2455 __u32 capabilities;
2456 __u16 count;
2457
Steve Frencheeac8042006-01-13 21:34:58 -08002458 cFYI(1, ("In sesssetup"));
Steve French4523cc32007-04-30 20:13:06 +00002459 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460 return -EINVAL;
2461 user = ses->userName;
2462 domain = ses->domainName;
2463 smb_buffer = cifs_buf_get();
Steve French582d21e2008-05-13 04:54:12 +00002464
2465 if (smb_buffer == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466 return -ENOMEM;
Steve French582d21e2008-05-13 04:54:12 +00002467
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468 smb_buffer_response = smb_buffer;
2469 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2470
2471 /* send SMBsessionSetup here */
2472 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2473 NULL /* no tCon exists yet */ , 13 /* wct */ );
2474
Steve French1982c342005-08-17 12:38:22 -07002475 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476 pSMB->req_no_secext.AndXCommand = 0xFF;
2477 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2478 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2479
Steve French50c2f752007-07-13 00:33:32 +00002480 if (ses->server->secMode &
2481 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2483
2484 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2485 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
2486 if (ses->capabilities & CAP_UNICODE) {
2487 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2488 capabilities |= CAP_UNICODE;
2489 }
2490 if (ses->capabilities & CAP_STATUS32) {
2491 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2492 capabilities |= CAP_STATUS32;
2493 }
2494 if (ses->capabilities & CAP_DFS) {
2495 smb_buffer->Flags2 |= SMBFLG2_DFS;
2496 capabilities |= CAP_DFS;
2497 }
2498 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
2499
Steve French50c2f752007-07-13 00:33:32 +00002500 pSMB->req_no_secext.CaseInsensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002501 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502
2503 pSMB->req_no_secext.CaseSensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002504 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505 bcc_ptr = pByteArea(smb_buffer);
Steve French7c7b25b2006-06-01 19:20:10 +00002506 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2507 bcc_ptr += CIFS_SESS_KEY_SIZE;
2508 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2509 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510
2511 if (ses->capabilities & CAP_UNICODE) {
2512 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
2513 *bcc_ptr = 0;
2514 bcc_ptr++;
2515 }
Steve French4523cc32007-04-30 20:13:06 +00002516 if (user == NULL)
Steve French39798772006-05-31 22:40:51 +00002517 bytes_returned = 0; /* skip null user */
Steve French50c2f752007-07-13 00:33:32 +00002518 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519 bytes_returned =
Steve French50c2f752007-07-13 00:33:32 +00002520 cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 nls_codepage);
2522 /* convert number of 16 bit words to bytes */
2523 bcc_ptr += 2 * bytes_returned;
2524 bcc_ptr += 2; /* trailing null */
2525 if (domain == NULL)
2526 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002527 cifs_strtoUCS((__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528 "CIFS_LINUX_DOM", 32, nls_codepage);
2529 else
2530 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002531 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532 nls_codepage);
2533 bcc_ptr += 2 * bytes_returned;
2534 bcc_ptr += 2;
2535 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002536 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537 32, nls_codepage);
2538 bcc_ptr += 2 * bytes_returned;
2539 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002540 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541 32, nls_codepage);
2542 bcc_ptr += 2 * bytes_returned;
2543 bcc_ptr += 2;
2544 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002545 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546 64, nls_codepage);
2547 bcc_ptr += 2 * bytes_returned;
2548 bcc_ptr += 2;
2549 } else {
Steve French50c2f752007-07-13 00:33:32 +00002550 if (user != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551 strncpy(bcc_ptr, user, 200);
2552 bcc_ptr += strnlen(user, 200);
2553 }
2554 *bcc_ptr = 0;
2555 bcc_ptr++;
2556 if (domain == NULL) {
2557 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2558 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2559 } else {
2560 strncpy(bcc_ptr, domain, 64);
2561 bcc_ptr += strnlen(domain, 64);
2562 *bcc_ptr = 0;
2563 bcc_ptr++;
2564 }
2565 strcpy(bcc_ptr, "Linux version ");
2566 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002567 strcpy(bcc_ptr, utsname()->release);
2568 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2570 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2571 }
2572 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2573 smb_buffer->smb_buf_length += count;
2574 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2575
2576 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00002577 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578 if (rc) {
2579/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2580 } else if ((smb_buffer_response->WordCount == 3)
2581 || (smb_buffer_response->WordCount == 4)) {
2582 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2583 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2584 if (action & GUEST_LOGIN)
Steve French61e74802008-12-03 00:57:54 +00002585 cFYI(1, ("Guest login")); /* BB mark SesInfo struct? */
Steve French50c2f752007-07-13 00:33:32 +00002586 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format
2587 (little endian) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 cFYI(1, ("UID = %d ", ses->Suid));
Steve French50c2f752007-07-13 00:33:32 +00002589 /* response can have either 3 or 4 word count - Samba sends 3 */
2590 bcc_ptr = pByteArea(smb_buffer_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 if ((pSMBr->resp.hdr.WordCount == 3)
2592 || ((pSMBr->resp.hdr.WordCount == 4)
2593 && (blob_len < pSMBr->resp.ByteCount))) {
2594 if (pSMBr->resp.hdr.WordCount == 4)
2595 bcc_ptr += blob_len;
2596
2597 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2598 if ((long) (bcc_ptr) % 2) {
2599 remaining_words =
Steve French50c2f752007-07-13 00:33:32 +00002600 (BCC(smb_buffer_response) - 1) / 2;
2601 /* Unicode strings must be word
2602 aligned */
2603 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 } else {
2605 remaining_words =
2606 BCC(smb_buffer_response) / 2;
2607 }
2608 len =
2609 UniStrnlen((wchar_t *) bcc_ptr,
2610 remaining_words - 1);
2611/* We look for obvious messed up bcc or strings in response so we do not go off
2612 the end since (at least) WIN2K and Windows XP have a major bug in not null
2613 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002614 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002615 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002616 ses->serverOS = kzalloc(2 * (len + 1),
2617 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002618 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002619 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620 cifs_strfromUCS_le(ses->serverOS,
Steve French50c2f752007-07-13 00:33:32 +00002621 (__le16 *)bcc_ptr,
2622 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623 bcc_ptr += 2 * (len + 1);
2624 remaining_words -= len + 1;
2625 ses->serverOS[2 * len] = 0;
2626 ses->serverOS[1 + (2 * len)] = 0;
2627 if (remaining_words > 0) {
2628 len = UniStrnlen((wchar_t *)bcc_ptr,
2629 remaining_words-1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002630 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002631 ses->serverNOS = kzalloc(2 * (len + 1),
2632 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002633 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002634 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 cifs_strfromUCS_le(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002636 (__le16 *)bcc_ptr,
2637 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 bcc_ptr += 2 * (len + 1);
2639 ses->serverNOS[2 * len] = 0;
2640 ses->serverNOS[1 + (2 * len)] = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002641 if (strncmp(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002642 "NT LAN Manager 4", 16) == 0) {
Steve French467a8f82007-06-27 22:41:32 +00002643 cFYI(1, ("NT4 server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 ses->flags |= CIFS_SES_NT4;
2645 }
2646 remaining_words -= len + 1;
2647 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002648 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Steve French50c2f752007-07-13 00:33:32 +00002649 /* last string is not always null terminated
2650 (for e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002651 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002652 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 ses->serverDomain =
Steve French50c2f752007-07-13 00:33:32 +00002654 kzalloc(2*(len+1),
2655 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002656 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002657 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 cifs_strfromUCS_le(ses->serverDomain,
Steve French50c2f752007-07-13 00:33:32 +00002659 (__le16 *)bcc_ptr,
2660 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 bcc_ptr += 2 * (len + 1);
2662 ses->serverDomain[2*len] = 0;
2663 ses->serverDomain[1+(2*len)] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002664 } else { /* else no more room so create
2665 dummy domain string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002666 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002667 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002668 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002669 kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002670 }
Steve French50c2f752007-07-13 00:33:32 +00002671 } else { /* no room so create dummy domain
2672 and NOS string */
2673
Steve French433dc242005-04-28 22:41:08 -07002674 /* if these kcallocs fail not much we
2675 can do, but better to not fail the
2676 sesssetup itself */
Steve Frenchcd49b492006-06-26 04:22:36 +00002677 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002679 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002680 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002682 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 }
2684 } else { /* ASCII */
2685 len = strnlen(bcc_ptr, 1024);
2686 if (((long) bcc_ptr + len) - (long)
2687 pByteArea(smb_buffer_response)
2688 <= BCC(smb_buffer_response)) {
Steve Frenchcd49b492006-06-26 04:22:36 +00002689 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002690 ses->serverOS = kzalloc(len + 1,
2691 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002692 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002693 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002694 strncpy(ses->serverOS, bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695
2696 bcc_ptr += len;
Steve French50c2f752007-07-13 00:33:32 +00002697 /* null terminate the string */
2698 bcc_ptr[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 bcc_ptr++;
2700
2701 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002702 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002703 ses->serverNOS = kzalloc(len + 1,
2704 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002705 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002706 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 strncpy(ses->serverNOS, bcc_ptr, len);
2708 bcc_ptr += len;
2709 bcc_ptr[0] = 0;
2710 bcc_ptr++;
2711
2712 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002713 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002714 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002715 ses->serverDomain = kzalloc(len + 1,
2716 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002717 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002718 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002719 strncpy(ses->serverDomain, bcc_ptr,
2720 len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721 bcc_ptr += len;
2722 bcc_ptr[0] = 0;
2723 bcc_ptr++;
2724 } else
2725 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00002726 ("Variable field of length %d "
2727 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728 len));
2729 }
2730 } else {
Steve French61e74802008-12-03 00:57:54 +00002731 cERROR(1, ("Security Blob Length extends beyond "
Steve French50c2f752007-07-13 00:33:32 +00002732 "end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 }
2734 } else {
Steve French61e74802008-12-03 00:57:54 +00002735 cERROR(1, ("Invalid Word count %d: ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736 smb_buffer_response->WordCount));
2737 rc = -EIO;
2738 }
Steve French433dc242005-04-28 22:41:08 -07002739sesssetup_nomem: /* do not return an error on nomem for the info strings,
2740 since that could make reconnection harder, and
2741 reconnection might be needed to free memory */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00002742 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743
2744 return rc;
2745}
2746
2747static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
Steve French4b18f2a2008-04-29 00:06:05 +00002749 struct cifsSesInfo *ses, bool *pNTLMv2_flag,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750 const struct nls_table *nls_codepage)
2751{
2752 struct smb_hdr *smb_buffer;
2753 struct smb_hdr *smb_buffer_response;
2754 SESSION_SETUP_ANDX *pSMB;
2755 SESSION_SETUP_ANDX *pSMBr;
2756 char *bcc_ptr;
2757 char *domain;
2758 int rc = 0;
2759 int remaining_words = 0;
2760 int bytes_returned = 0;
2761 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002762 int SecurityBlobLength = sizeof(NEGOTIATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 PNEGOTIATE_MESSAGE SecurityBlob;
2764 PCHALLENGE_MESSAGE SecurityBlob2;
2765 __u32 negotiate_flags, capabilities;
2766 __u16 count;
2767
Steve French12b3b8f2006-02-09 21:12:47 +00002768 cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002769 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 return -EINVAL;
2771 domain = ses->domainName;
Steve French4b18f2a2008-04-29 00:06:05 +00002772 *pNTLMv2_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 smb_buffer = cifs_buf_get();
2774 if (smb_buffer == NULL) {
2775 return -ENOMEM;
2776 }
2777 smb_buffer_response = smb_buffer;
2778 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2779 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2780
2781 /* send SMBsessionSetup here */
2782 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2783 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002784
2785 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2787 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2788
2789 pSMB->req.AndXCommand = 0xFF;
2790 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2791 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2792
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002793 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2795
2796 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2797 CAP_EXTENDED_SECURITY;
2798 if (ses->capabilities & CAP_UNICODE) {
2799 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2800 capabilities |= CAP_UNICODE;
2801 }
2802 if (ses->capabilities & CAP_STATUS32) {
2803 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2804 capabilities |= CAP_STATUS32;
2805 }
2806 if (ses->capabilities & CAP_DFS) {
2807 smb_buffer->Flags2 |= SMBFLG2_DFS;
2808 capabilities |= CAP_DFS;
2809 }
2810 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2811
2812 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2813 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2814 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2815 SecurityBlob->MessageType = NtLmNegotiate;
2816 negotiate_flags =
2817 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
Steve French12b3b8f2006-02-09 21:12:47 +00002818 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
2819 NTLMSSP_NEGOTIATE_56 |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002821 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002823/* if (ntlmv2_support)
Steve French39798772006-05-31 22:40:51 +00002824 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 /* setup pointers to domain name and workstation name */
2826 bcc_ptr += SecurityBlobLength;
2827
2828 SecurityBlob->WorkstationName.Buffer = 0;
2829 SecurityBlob->WorkstationName.Length = 0;
2830 SecurityBlob->WorkstationName.MaximumLength = 0;
2831
Steve French12b3b8f2006-02-09 21:12:47 +00002832 /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent
2833 along with username on auth request (ie the response to challenge) */
2834 SecurityBlob->DomainName.Buffer = 0;
2835 SecurityBlob->DomainName.Length = 0;
2836 SecurityBlob->DomainName.MaximumLength = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 if (ses->capabilities & CAP_UNICODE) {
2838 if ((long) bcc_ptr % 2) {
2839 *bcc_ptr = 0;
2840 bcc_ptr++;
2841 }
2842
2843 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002844 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845 32, nls_codepage);
2846 bcc_ptr += 2 * bytes_returned;
2847 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002848 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849 nls_codepage);
2850 bcc_ptr += 2 * bytes_returned;
2851 bcc_ptr += 2; /* null terminate Linux version */
2852 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002853 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002854 64, nls_codepage);
2855 bcc_ptr += 2 * bytes_returned;
2856 *(bcc_ptr + 1) = 0;
2857 *(bcc_ptr + 2) = 0;
2858 bcc_ptr += 2; /* null terminate network opsys string */
2859 *(bcc_ptr + 1) = 0;
2860 *(bcc_ptr + 2) = 0;
2861 bcc_ptr += 2; /* null domain */
2862 } else { /* ASCII */
2863 strcpy(bcc_ptr, "Linux version ");
2864 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002865 strcpy(bcc_ptr, utsname()->release);
2866 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2868 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2869 bcc_ptr++; /* empty domain field */
2870 *bcc_ptr = 0;
2871 }
2872 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2873 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2874 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2875 smb_buffer->smb_buf_length += count;
2876 pSMB->req.ByteCount = cpu_to_le16(count);
2877
2878 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00002879 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880
2881 if (smb_buffer_response->Status.CifsError ==
2882 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2883 rc = 0;
2884
2885 if (rc) {
2886/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2887 } else if ((smb_buffer_response->WordCount == 3)
2888 || (smb_buffer_response->WordCount == 4)) {
2889 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2890 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2891
2892 if (action & GUEST_LOGIN)
Steve French61e74802008-12-03 00:57:54 +00002893 cFYI(1, ("Guest login"));
Steve French50c2f752007-07-13 00:33:32 +00002894 /* Do we want to set anything in SesInfo struct when guest login? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895
Steve French50c2f752007-07-13 00:33:32 +00002896 bcc_ptr = pByteArea(smb_buffer_response);
2897 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898
2899 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2900 if (SecurityBlob2->MessageType != NtLmChallenge) {
Steve French61e74802008-12-03 00:57:54 +00002901 cFYI(1, ("Unexpected NTLMSSP message type received %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902 SecurityBlob2->MessageType));
2903 } else if (ses) {
Steve French50c2f752007-07-13 00:33:32 +00002904 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
Steve French12b3b8f2006-02-09 21:12:47 +00002905 cFYI(1, ("UID = %d", ses->Suid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906 if ((pSMBr->resp.hdr.WordCount == 3)
2907 || ((pSMBr->resp.hdr.WordCount == 4)
2908 && (blob_len <
2909 pSMBr->resp.ByteCount))) {
2910
2911 if (pSMBr->resp.hdr.WordCount == 4) {
2912 bcc_ptr += blob_len;
Steve French12b3b8f2006-02-09 21:12:47 +00002913 cFYI(1, ("Security Blob Length %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914 blob_len));
2915 }
2916
Steve French12b3b8f2006-02-09 21:12:47 +00002917 cFYI(1, ("NTLMSSP Challenge rcvd"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918
2919 memcpy(ses->server->cryptKey,
2920 SecurityBlob2->Challenge,
2921 CIFS_CRYPTO_KEY_SIZE);
Steve French50c2f752007-07-13 00:33:32 +00002922 if (SecurityBlob2->NegotiateFlags &
Steve French12b3b8f2006-02-09 21:12:47 +00002923 cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
Steve French4b18f2a2008-04-29 00:06:05 +00002924 *pNTLMv2_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925
Steve French50c2f752007-07-13 00:33:32 +00002926 if ((SecurityBlob2->NegotiateFlags &
2927 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928 || (sign_CIFS_PDUs > 1))
Steve French50c2f752007-07-13 00:33:32 +00002929 ses->server->secMode |=
2930 SECMODE_SIGN_REQUIRED;
2931 if ((SecurityBlob2->NegotiateFlags &
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
Steve French50c2f752007-07-13 00:33:32 +00002933 ses->server->secMode |=
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934 SECMODE_SIGN_ENABLED;
2935
2936 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2937 if ((long) (bcc_ptr) % 2) {
2938 remaining_words =
2939 (BCC(smb_buffer_response)
2940 - 1) / 2;
Steve French50c2f752007-07-13 00:33:32 +00002941 /* Must word align unicode strings */
2942 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943 } else {
2944 remaining_words =
2945 BCC
2946 (smb_buffer_response) / 2;
2947 }
2948 len =
2949 UniStrnlen((wchar_t *) bcc_ptr,
2950 remaining_words - 1);
2951/* We look for obvious messed up bcc or strings in response so we do not go off
2952 the end since (at least) WIN2K and Windows XP have a major bug in not null
2953 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002954 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002955 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002957 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002959 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 bcc_ptr, len,
2961 nls_codepage);
2962 bcc_ptr += 2 * (len + 1);
2963 remaining_words -= len + 1;
2964 ses->serverOS[2 * len] = 0;
2965 ses->serverOS[1 + (2 * len)] = 0;
2966 if (remaining_words > 0) {
2967 len = UniStrnlen((wchar_t *)
2968 bcc_ptr,
2969 remaining_words
2970 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002971 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002973 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974 GFP_KERNEL);
2975 cifs_strfromUCS_le(ses->
2976 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002977 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978 bcc_ptr,
2979 len,
2980 nls_codepage);
2981 bcc_ptr += 2 * (len + 1);
2982 ses->serverNOS[2 * len] = 0;
2983 ses->serverNOS[1 +
2984 (2 * len)] = 0;
2985 remaining_words -= len + 1;
2986 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00002987 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2988 /* last string not always null terminated
2989 (for e.g. for Windows XP & 2000) */
Steve Frenchcd49b492006-06-26 04:22:36 +00002990 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002992 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993 (len +
2994 1),
2995 GFP_KERNEL);
2996 cifs_strfromUCS_le
Steve Frenche89dc922005-11-11 15:18:19 -08002997 (ses->serverDomain,
2998 (__le16 *)bcc_ptr,
2999 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003000 bcc_ptr +=
3001 2 * (len + 1);
Steve Frenche89dc922005-11-11 15:18:19 -08003002 ses->serverDomain[2*len]
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003 = 0;
Steve Frenche89dc922005-11-11 15:18:19 -08003004 ses->serverDomain
3005 [1 + (2 * len)]
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006 = 0;
3007 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003008 else {
Steve Frenchcd49b492006-06-26 04:22:36 +00003009 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003011 kzalloc(2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012 GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00003013 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014 } else { /* no room so create dummy domain and NOS string */
Steve Frenchcd49b492006-06-26 04:22:36 +00003015 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003017 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00003018 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003019 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003020 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021 }
3022 } else { /* ASCII */
3023 len = strnlen(bcc_ptr, 1024);
3024 if (((long) bcc_ptr + len) - (long)
3025 pByteArea(smb_buffer_response)
3026 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003027 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00003028 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003030 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 GFP_KERNEL);
3032 strncpy(ses->serverOS,
3033 bcc_ptr, len);
3034
3035 bcc_ptr += len;
3036 bcc_ptr[0] = 0; /* null terminate string */
3037 bcc_ptr++;
3038
3039 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003040 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003042 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043 GFP_KERNEL);
3044 strncpy(ses->serverNOS, bcc_ptr, len);
3045 bcc_ptr += len;
3046 bcc_ptr[0] = 0;
3047 bcc_ptr++;
3048
3049 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003050 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003052 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +00003054 strncpy(ses->serverDomain,
3055 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056 bcc_ptr += len;
3057 bcc_ptr[0] = 0;
3058 bcc_ptr++;
3059 } else
3060 cFYI(1,
Steve French63135e02007-07-17 17:34:02 +00003061 ("field of length %d "
3062 "extends beyond end of smb",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063 len));
3064 }
3065 } else {
Steve French50c2f752007-07-13 00:33:32 +00003066 cERROR(1, ("Security Blob Length extends beyond"
3067 " end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068 }
3069 } else {
3070 cERROR(1, ("No session structure passed in."));
3071 }
3072 } else {
Steve French61e74802008-12-03 00:57:54 +00003073 cERROR(1, ("Invalid Word count %d:",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003074 smb_buffer_response->WordCount));
3075 rc = -EIO;
3076 }
3077
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003078 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079
3080 return rc;
3081}
3082static int
3083CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French4b18f2a2008-04-29 00:06:05 +00003084 char *ntlm_session_key, bool ntlmv2_flag,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003085 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086{
3087 struct smb_hdr *smb_buffer;
3088 struct smb_hdr *smb_buffer_response;
3089 SESSION_SETUP_ANDX *pSMB;
3090 SESSION_SETUP_ANDX *pSMBr;
3091 char *bcc_ptr;
3092 char *user;
3093 char *domain;
3094 int rc = 0;
3095 int remaining_words = 0;
3096 int bytes_returned = 0;
3097 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003098 int SecurityBlobLength = sizeof(AUTHENTICATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099 PAUTHENTICATE_MESSAGE SecurityBlob;
3100 __u32 negotiate_flags, capabilities;
3101 __u16 count;
3102
3103 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003104 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105 return -EINVAL;
3106 user = ses->userName;
3107 domain = ses->domainName;
3108 smb_buffer = cifs_buf_get();
3109 if (smb_buffer == NULL) {
3110 return -ENOMEM;
3111 }
3112 smb_buffer_response = smb_buffer;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003113 pSMB = (SESSION_SETUP_ANDX *)smb_buffer;
3114 pSMBr = (SESSION_SETUP_ANDX *)smb_buffer_response;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115
3116 /* send SMBsessionSetup here */
3117 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
3118 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07003119
3120 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
3122 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
3123 pSMB->req.AndXCommand = 0xFF;
3124 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
3125 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
3126
3127 pSMB->req.hdr.Uid = ses->Suid;
3128
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003129 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3131
3132 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003133 CAP_EXTENDED_SECURITY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134 if (ses->capabilities & CAP_UNICODE) {
3135 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3136 capabilities |= CAP_UNICODE;
3137 }
3138 if (ses->capabilities & CAP_STATUS32) {
3139 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3140 capabilities |= CAP_STATUS32;
3141 }
3142 if (ses->capabilities & CAP_DFS) {
3143 smb_buffer->Flags2 |= SMBFLG2_DFS;
3144 capabilities |= CAP_DFS;
3145 }
3146 pSMB->req.Capabilities = cpu_to_le32(capabilities);
3147
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003148 bcc_ptr = (char *)&pSMB->req.SecurityBlob;
3149 SecurityBlob = (PAUTHENTICATE_MESSAGE)bcc_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
3151 SecurityBlob->MessageType = NtLmAuthenticate;
3152 bcc_ptr += SecurityBlobLength;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003153 negotiate_flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
3154 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
3155 0x80000000 | NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003156 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003157 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003158 if (ntlmv2_flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003159 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
3160
3161/* setup pointers to domain name and workstation name */
3162
3163 SecurityBlob->WorkstationName.Buffer = 0;
3164 SecurityBlob->WorkstationName.Length = 0;
3165 SecurityBlob->WorkstationName.MaximumLength = 0;
3166 SecurityBlob->SessionKey.Length = 0;
3167 SecurityBlob->SessionKey.MaximumLength = 0;
3168 SecurityBlob->SessionKey.Buffer = 0;
3169
3170 SecurityBlob->LmChallengeResponse.Length = 0;
3171 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
3172 SecurityBlob->LmChallengeResponse.Buffer = 0;
3173
3174 SecurityBlob->NtChallengeResponse.Length =
Steve French7c7b25b2006-06-01 19:20:10 +00003175 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176 SecurityBlob->NtChallengeResponse.MaximumLength =
Steve French7c7b25b2006-06-01 19:20:10 +00003177 cpu_to_le16(CIFS_SESS_KEY_SIZE);
3178 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179 SecurityBlob->NtChallengeResponse.Buffer =
3180 cpu_to_le32(SecurityBlobLength);
Steve French7c7b25b2006-06-01 19:20:10 +00003181 SecurityBlobLength += CIFS_SESS_KEY_SIZE;
3182 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003183
3184 if (ses->capabilities & CAP_UNICODE) {
3185 if (domain == NULL) {
3186 SecurityBlob->DomainName.Buffer = 0;
3187 SecurityBlob->DomainName.Length = 0;
3188 SecurityBlob->DomainName.MaximumLength = 0;
3189 } else {
Steve French77159b42007-08-31 01:10:17 +00003190 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00003192 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003194 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195 SecurityBlob->DomainName.Buffer =
3196 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003197 bcc_ptr += ln;
3198 SecurityBlobLength += ln;
3199 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200 }
3201 if (user == NULL) {
3202 SecurityBlob->UserName.Buffer = 0;
3203 SecurityBlob->UserName.Length = 0;
3204 SecurityBlob->UserName.MaximumLength = 0;
3205 } else {
Steve French77159b42007-08-31 01:10:17 +00003206 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00003208 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209 SecurityBlob->UserName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003210 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211 SecurityBlob->UserName.Buffer =
3212 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003213 bcc_ptr += ln;
3214 SecurityBlobLength += ln;
3215 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003216 }
3217
Steve French63135e02007-07-17 17:34:02 +00003218 /* SecurityBlob->WorkstationName.Length =
3219 cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220 SecurityBlob->WorkstationName.Length *= 2;
Steve French63135e02007-07-17 17:34:02 +00003221 SecurityBlob->WorkstationName.MaximumLength =
3222 cpu_to_le16(SecurityBlob->WorkstationName.Length);
3223 SecurityBlob->WorkstationName.Buffer =
3224 cpu_to_le32(SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003225 bcc_ptr += SecurityBlob->WorkstationName.Length;
3226 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
Steve French63135e02007-07-17 17:34:02 +00003227 SecurityBlob->WorkstationName.Length =
3228 cpu_to_le16(SecurityBlob->WorkstationName.Length); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003229
3230 if ((long) bcc_ptr % 2) {
3231 *bcc_ptr = 0;
3232 bcc_ptr++;
3233 }
3234 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003235 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236 32, nls_codepage);
3237 bcc_ptr += 2 * bytes_returned;
3238 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003239 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240 nls_codepage);
3241 bcc_ptr += 2 * bytes_returned;
3242 bcc_ptr += 2; /* null term version string */
3243 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003244 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003245 64, nls_codepage);
3246 bcc_ptr += 2 * bytes_returned;
3247 *(bcc_ptr + 1) = 0;
3248 *(bcc_ptr + 2) = 0;
3249 bcc_ptr += 2; /* null terminate network opsys string */
3250 *(bcc_ptr + 1) = 0;
3251 *(bcc_ptr + 2) = 0;
3252 bcc_ptr += 2; /* null domain */
3253 } else { /* ASCII */
3254 if (domain == NULL) {
3255 SecurityBlob->DomainName.Buffer = 0;
3256 SecurityBlob->DomainName.Length = 0;
3257 SecurityBlob->DomainName.MaximumLength = 0;
3258 } else {
Steve French77159b42007-08-31 01:10:17 +00003259 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
3261 strncpy(bcc_ptr, domain, 63);
Steve French77159b42007-08-31 01:10:17 +00003262 ln = strnlen(domain, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003263 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003264 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003265 SecurityBlob->DomainName.Buffer =
3266 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003267 bcc_ptr += ln;
3268 SecurityBlobLength += ln;
3269 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003270 }
3271 if (user == NULL) {
3272 SecurityBlob->UserName.Buffer = 0;
3273 SecurityBlob->UserName.Length = 0;
3274 SecurityBlob->UserName.MaximumLength = 0;
3275 } else {
Steve French77159b42007-08-31 01:10:17 +00003276 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003277 strncpy(bcc_ptr, user, 63);
Steve French77159b42007-08-31 01:10:17 +00003278 ln = strnlen(user, 64);
3279 SecurityBlob->UserName.MaximumLength = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280 SecurityBlob->UserName.Buffer =
Steve French77159b42007-08-31 01:10:17 +00003281 cpu_to_le32(SecurityBlobLength);
3282 bcc_ptr += ln;
3283 SecurityBlobLength += ln;
3284 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003285 }
3286 /* BB fill in our workstation name if known BB */
3287
3288 strcpy(bcc_ptr, "Linux version ");
3289 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003290 strcpy(bcc_ptr, utsname()->release);
3291 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003292 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
3293 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
3294 bcc_ptr++; /* null domain */
3295 *bcc_ptr = 0;
3296 }
3297 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
3298 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
3299 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
3300 smb_buffer->smb_buf_length += count;
3301 pSMB->req.ByteCount = cpu_to_le16(count);
3302
3303 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00003304 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305 if (rc) {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003306/* rc = map_smb_to_linux_error(smb_buffer_response) done in SendReceive now */
3307 } else if ((smb_buffer_response->WordCount == 3) ||
3308 (smb_buffer_response->WordCount == 4)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003309 __u16 action = le16_to_cpu(pSMBr->resp.Action);
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003310 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003311 if (action & GUEST_LOGIN)
Steve French61e74802008-12-03 00:57:54 +00003312 cFYI(1, ("Guest login")); /* BB Should we set anything
Steve French50c2f752007-07-13 00:33:32 +00003313 in SesInfo struct ? */
3314/* if (SecurityBlob2->MessageType != NtLm??) {
3315 cFYI("Unexpected message type on auth response is %d"));
3316 } */
3317
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318 if (ses) {
3319 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003320 ("Check challenge UID %d vs auth response UID %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321 ses->Suid, smb_buffer_response->Uid));
Steve French50c2f752007-07-13 00:33:32 +00003322 /* UID left in wire format */
3323 ses->Suid = smb_buffer_response->Uid;
3324 bcc_ptr = pByteArea(smb_buffer_response);
3325 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326 if ((pSMBr->resp.hdr.WordCount == 3)
3327 || ((pSMBr->resp.hdr.WordCount == 4)
3328 && (blob_len <
3329 pSMBr->resp.ByteCount))) {
3330 if (pSMBr->resp.hdr.WordCount == 4) {
3331 bcc_ptr +=
3332 blob_len;
3333 cFYI(1,
3334 ("Security Blob Length %d ",
3335 blob_len));
3336 }
3337
3338 cFYI(1,
3339 ("NTLMSSP response to Authenticate "));
3340
3341 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3342 if ((long) (bcc_ptr) % 2) {
3343 remaining_words =
3344 (BCC(smb_buffer_response)
3345 - 1) / 2;
3346 bcc_ptr++; /* Unicode strings must be word aligned */
3347 } else {
3348 remaining_words = BCC(smb_buffer_response) / 2;
3349 }
Steve French77159b42007-08-31 01:10:17 +00003350 len = UniStrnlen((wchar_t *) bcc_ptr,
3351 remaining_words - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352/* We look for obvious messed up bcc or strings in response so we do not go off
3353 the end since (at least) WIN2K and Windows XP have a major bug in not null
3354 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003355 if (ses->serverOS)
Steve French08775832006-05-30 18:08:26 +00003356 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003357 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003358 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003360 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003361 bcc_ptr, len,
3362 nls_codepage);
3363 bcc_ptr += 2 * (len + 1);
3364 remaining_words -= len + 1;
3365 ses->serverOS[2 * len] = 0;
3366 ses->serverOS[1 + (2 * len)] = 0;
3367 if (remaining_words > 0) {
3368 len = UniStrnlen((wchar_t *)
3369 bcc_ptr,
3370 remaining_words
3371 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00003372 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003374 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375 GFP_KERNEL);
3376 cifs_strfromUCS_le(ses->
3377 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003378 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003379 bcc_ptr,
3380 len,
3381 nls_codepage);
3382 bcc_ptr += 2 * (len + 1);
3383 ses->serverNOS[2 * len] = 0;
3384 ses->serverNOS[1+(2*len)] = 0;
3385 remaining_words -= len + 1;
3386 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00003387 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003388 /* last string not always null terminated (e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003389 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003390 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003391 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003392 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003393 (len +
3394 1),
3395 GFP_KERNEL);
3396 cifs_strfromUCS_le
3397 (ses->
3398 serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08003399 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 bcc_ptr, len,
3401 nls_codepage);
3402 bcc_ptr +=
3403 2 * (len + 1);
3404 ses->
3405 serverDomain[2
3406 * len]
3407 = 0;
3408 ses->
3409 serverDomain[1
3410 +
3411 (2
3412 *
3413 len)]
3414 = 0;
3415 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003416 else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003417 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003418 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003419 ses->serverDomain = kzalloc(2,GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00003420 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003421 } else { /* no room so create dummy domain and NOS string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003422 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003423 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003424 ses->serverDomain = kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00003425 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003426 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427 }
3428 } else { /* ASCII */
3429 len = strnlen(bcc_ptr, 1024);
Steve French50c2f752007-07-13 00:33:32 +00003430 if (((long) bcc_ptr + len) -
3431 (long) pByteArea(smb_buffer_response)
Steve French63135e02007-07-17 17:34:02 +00003432 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003433 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00003434 kfree(ses->serverOS);
Steve French77159b42007-08-31 01:10:17 +00003435 ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436 strncpy(ses->serverOS,bcc_ptr, len);
3437
3438 bcc_ptr += len;
3439 bcc_ptr[0] = 0; /* null terminate the string */
3440 bcc_ptr++;
3441
3442 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003443 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00003444 ses->serverNOS = kzalloc(len+1,
3445 GFP_KERNEL);
Steve French63135e02007-07-17 17:34:02 +00003446 strncpy(ses->serverNOS,
3447 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448 bcc_ptr += len;
3449 bcc_ptr[0] = 0;
3450 bcc_ptr++;
3451
3452 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003453 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003454 kfree(ses->serverDomain);
Steve French63135e02007-07-17 17:34:02 +00003455 ses->serverDomain =
3456 kzalloc(len+1,
3457 GFP_KERNEL);
3458 strncpy(ses->serverDomain,
3459 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460 bcc_ptr += len;
3461 bcc_ptr[0] = 0;
3462 bcc_ptr++;
3463 } else
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003464 cFYI(1, ("field of length %d "
Steve French63135e02007-07-17 17:34:02 +00003465 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466 len));
3467 }
3468 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003469 cERROR(1, ("Security Blob extends beyond end "
Steve French63135e02007-07-17 17:34:02 +00003470 "of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471 }
3472 } else {
3473 cERROR(1, ("No session structure passed in."));
3474 }
3475 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003476 cERROR(1, ("Invalid Word count %d: ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477 smb_buffer_response->WordCount));
3478 rc = -EIO;
3479 }
3480
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003481 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003482
3483 return rc;
3484}
3485
3486int
3487CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3488 const char *tree, struct cifsTconInfo *tcon,
3489 const struct nls_table *nls_codepage)
3490{
3491 struct smb_hdr *smb_buffer;
3492 struct smb_hdr *smb_buffer_response;
3493 TCONX_REQ *pSMB;
3494 TCONX_RSP *pSMBr;
3495 unsigned char *bcc_ptr;
3496 int rc = 0;
3497 int length;
3498 __u16 count;
3499
3500 if (ses == NULL)
3501 return -EIO;
3502
3503 smb_buffer = cifs_buf_get();
3504 if (smb_buffer == NULL) {
3505 return -ENOMEM;
3506 }
3507 smb_buffer_response = smb_buffer;
3508
3509 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3510 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003511
3512 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003513 smb_buffer->Uid = ses->Suid;
3514 pSMB = (TCONX_REQ *) smb_buffer;
3515 pSMBr = (TCONX_RSP *) smb_buffer_response;
3516
3517 pSMB->AndXCommand = 0xFF;
3518 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003519 bcc_ptr = &pSMB->Password[0];
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003520 if ((ses->server->secMode) & SECMODE_USER) {
Steve Frencheeac8042006-01-13 21:34:58 -08003521 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00003522 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08003523 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00003524 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08003525 } else {
Steve French7c7b25b2006-06-01 19:20:10 +00003526 pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08003527 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
3528 specified as required (when that support is added to
3529 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00003530 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08003531 by Samba (not sure whether other servers allow
3532 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00003533#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French50c2f752007-07-13 00:33:32 +00003534 if ((extended_security & CIFSSEC_MAY_LANMAN) &&
Steve French7c7b25b2006-06-01 19:20:10 +00003535 (ses->server->secType == LANMAN))
Jeff Layton4e53a3f2008-12-05 20:41:21 -05003536 calc_lanman_hash(ses->password, ses->server->cryptKey,
3537 ses->server->secMode &
3538 SECMODE_PW_ENCRYPT ? true : false,
3539 bcc_ptr);
Steve French7c7b25b2006-06-01 19:20:10 +00003540 else
3541#endif /* CIFS_WEAK_PW_HASH */
Steve Frencheeac8042006-01-13 21:34:58 -08003542 SMBNTencrypt(ses->password,
3543 ses->server->cryptKey,
3544 bcc_ptr);
3545
Steve French7c7b25b2006-06-01 19:20:10 +00003546 bcc_ptr += CIFS_SESS_KEY_SIZE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003547 if (ses->capabilities & CAP_UNICODE) {
Steve French7c7b25b2006-06-01 19:20:10 +00003548 /* must align unicode strings */
3549 *bcc_ptr = 0; /* null byte password */
3550 bcc_ptr++;
3551 }
Steve Frencheeac8042006-01-13 21:34:58 -08003552 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003553
Steve French50c2f752007-07-13 00:33:32 +00003554 if (ses->server->secMode &
Steve Frencha878fb22006-05-30 18:04:19 +00003555 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003556 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3557
3558 if (ses->capabilities & CAP_STATUS32) {
3559 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3560 }
3561 if (ses->capabilities & CAP_DFS) {
3562 smb_buffer->Flags2 |= SMBFLG2_DFS;
3563 }
3564 if (ses->capabilities & CAP_UNICODE) {
3565 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3566 length =
Steve French50c2f752007-07-13 00:33:32 +00003567 cifs_strtoUCS((__le16 *) bcc_ptr, tree,
3568 6 /* max utf8 char length in bytes */ *
Steve Frencha878fb22006-05-30 18:04:19 +00003569 (/* server len*/ + 256 /* share len */), nls_codepage);
3570 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003571 bcc_ptr += 2; /* skip trailing null */
3572 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003573 strcpy(bcc_ptr, tree);
3574 bcc_ptr += strlen(tree) + 1;
3575 }
3576 strcpy(bcc_ptr, "?????");
3577 bcc_ptr += strlen("?????");
3578 bcc_ptr += 1;
3579 count = bcc_ptr - &pSMB->Password[0];
3580 pSMB->hdr.smb_buf_length += count;
3581 pSMB->ByteCount = cpu_to_le16(count);
3582
Steve French133672e2007-11-13 22:41:37 +00003583 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
3584 CIFS_STD_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003585
3586 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3587 /* above now done in SendReceive */
3588 if ((rc == 0) && (tcon != NULL)) {
3589 tcon->tidStatus = CifsGood;
Steve French3b795212008-11-13 19:45:32 +00003590 tcon->need_reconnect = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591 tcon->tid = smb_buffer_response->Tid;
3592 bcc_ptr = pByteArea(smb_buffer_response);
3593 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
Steve French50c2f752007-07-13 00:33:32 +00003594 /* skip service field (NB: this field is always ASCII) */
Steve French7f8ed422007-09-28 22:28:55 +00003595 if (length == 3) {
3596 if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') &&
3597 (bcc_ptr[2] == 'C')) {
3598 cFYI(1, ("IPC connection"));
3599 tcon->ipc = 1;
3600 }
3601 } else if (length == 2) {
3602 if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) {
3603 /* the most common case */
3604 cFYI(1, ("disk share connection"));
3605 }
3606 }
Steve French50c2f752007-07-13 00:33:32 +00003607 bcc_ptr += length + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3609 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3610 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3611 if ((bcc_ptr + (2 * length)) -
3612 pByteArea(smb_buffer_response) <=
3613 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003614 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003616 kzalloc(length + 2, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003617 if (tcon->nativeFileSystem)
3618 cifs_strfromUCS_le(
3619 tcon->nativeFileSystem,
3620 (__le16 *) bcc_ptr,
3621 length, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003622 bcc_ptr += 2 * length;
3623 bcc_ptr[0] = 0; /* null terminate the string */
3624 bcc_ptr[1] = 0;
3625 bcc_ptr += 2;
3626 }
Steve French50c2f752007-07-13 00:33:32 +00003627 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628 } else {
3629 length = strnlen(bcc_ptr, 1024);
3630 if ((bcc_ptr + length) -
3631 pByteArea(smb_buffer_response) <=
3632 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003633 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003635 kzalloc(length + 1, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003636 if (tcon->nativeFileSystem)
3637 strncpy(tcon->nativeFileSystem, bcc_ptr,
3638 length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003639 }
Steve French50c2f752007-07-13 00:33:32 +00003640 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003641 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003642 if ((smb_buffer_response->WordCount == 3) ||
Steve French1a4e15a2006-10-12 21:33:51 +00003643 (smb_buffer_response->WordCount == 7))
3644 /* field is in same location */
Steve French39798772006-05-31 22:40:51 +00003645 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3646 else
3647 tcon->Flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003648 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3649 } else if ((rc == 0) && tcon == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00003650 /* all we need to save for IPC$ connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651 ses->ipc_tid = smb_buffer_response->Tid;
3652 }
3653
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003654 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003655 return rc;
3656}
3657
3658int
3659cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3660{
3661 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003662 char *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663
Jeff Laytonf1987b42008-11-15 11:12:47 -05003664 if (cifs_sb->tcon)
3665 cifs_put_tcon(cifs_sb->tcon);
Steve French50c2f752007-07-13 00:33:32 +00003666
Linus Torvalds1da177e2005-04-16 15:20:36 -07003667 cifs_sb->tcon = NULL;
Steve French2fe87f02006-09-21 07:02:52 +00003668 tmp = cifs_sb->prepath;
3669 cifs_sb->prepathlen = 0;
3670 cifs_sb->prepath = NULL;
3671 kfree(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003672
Steve French88e7d702008-01-03 17:37:09 +00003673 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003674}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003675
3676int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
Steve French50c2f752007-07-13 00:33:32 +00003677 struct nls_table *nls_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678{
3679 int rc = 0;
Steve French7c7b25b2006-06-01 19:20:10 +00003680 char ntlm_session_key[CIFS_SESS_KEY_SIZE];
Steve French4b18f2a2008-04-29 00:06:05 +00003681 bool ntlmv2_flag = false;
Steve Frenchad009ac2005-04-28 22:41:05 -07003682 int first_time = 0;
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003683 struct TCP_Server_Info *server = pSesInfo->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684
3685 /* what if server changes its buffer size after dropping the session? */
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003686 if (server->maxBuf == 0) /* no need to send on reconnect */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003687 rc = CIFSSMBNegotiate(xid, pSesInfo);
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003688 if (rc == -EAGAIN) {
3689 /* retry only once on 1st time connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003690 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve French50c2f752007-07-13 00:33:32 +00003691 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692 rc = -EHOSTDOWN;
3693 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003694 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695 spin_lock(&GlobalMid_Lock);
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003696 if (server->tcpStatus != CifsExiting)
3697 server->tcpStatus = CifsGood;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003698 else
3699 rc = -EHOSTDOWN;
3700 spin_unlock(&GlobalMid_Lock);
3701
3702 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003703 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003704 }
Steve French26b994f2008-08-06 05:11:33 +00003705
3706 if (rc)
3707 goto ss_err_exit;
3708
3709 pSesInfo->flags = 0;
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003710 pSesInfo->capabilities = server->capabilities;
Steve French26b994f2008-08-06 05:11:33 +00003711 if (linuxExtEnabled == 0)
3712 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003713 /* pSesInfo->sequence_number = 0;*/
Steve French26b994f2008-08-06 05:11:33 +00003714 cFYI(1, ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003715 server->secMode, server->capabilities, server->timeAdj));
3716
Steve French26b994f2008-08-06 05:11:33 +00003717 if (experimEnabled < 2)
3718 rc = CIFS_SessSetup(xid, pSesInfo, first_time, nls_info);
3719 else if (extended_security
3720 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003721 && (server->secType == NTLMSSP)) {
Steve French26b994f2008-08-06 05:11:33 +00003722 rc = -EOPNOTSUPP;
3723 } else if (extended_security
3724 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003725 && (server->secType == RawNTLMSSP)) {
Steve French26b994f2008-08-06 05:11:33 +00003726 cFYI(1, ("NTLMSSP sesssetup"));
3727 rc = CIFSNTLMSSPNegotiateSessSetup(xid, pSesInfo, &ntlmv2_flag,
3728 nls_info);
3729 if (!rc) {
3730 if (ntlmv2_flag) {
3731 char *v2_response;
3732 cFYI(1, ("more secure NTLM ver2 hash"));
3733 if (CalcNTLMv2_partial_mac_key(pSesInfo,
3734 nls_info)) {
3735 rc = -ENOMEM;
3736 goto ss_err_exit;
3737 } else
3738 v2_response = kmalloc(16 + 64 /* blob*/,
3739 GFP_KERNEL);
3740 if (v2_response) {
3741 CalcNTLMv2_response(pSesInfo,
3742 v2_response);
3743 /* if (first_time)
3744 cifs_calculate_ntlmv2_mac_key */
3745 kfree(v2_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003746 /* BB Put dummy sig in SessSetup PDU? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003747 } else {
Steve French26b994f2008-08-06 05:11:33 +00003748 rc = -ENOMEM;
3749 goto ss_err_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750 }
Steve French26b994f2008-08-06 05:11:33 +00003751
3752 } else {
3753 SMBNTencrypt(pSesInfo->password,
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003754 server->cryptKey,
Steve French26b994f2008-08-06 05:11:33 +00003755 ntlm_session_key);
3756
3757 if (first_time)
3758 cifs_calculate_mac_key(
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003759 &server->mac_signing_key,
Steve French26b994f2008-08-06 05:11:33 +00003760 ntlm_session_key,
3761 pSesInfo->password);
3762 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003763 /* for better security the weaker lanman hash not sent
3764 in AuthSessSetup so we no longer calculate it */
3765
Steve French26b994f2008-08-06 05:11:33 +00003766 rc = CIFSNTLMSSPAuthSessSetup(xid, pSesInfo,
3767 ntlm_session_key,
3768 ntlmv2_flag,
3769 nls_info);
3770 }
3771 } else { /* old style NTLM 0.12 session setup */
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003772 SMBNTencrypt(pSesInfo->password, server->cryptKey,
Steve French26b994f2008-08-06 05:11:33 +00003773 ntlm_session_key);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003774
Steve French26b994f2008-08-06 05:11:33 +00003775 if (first_time)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003776 cifs_calculate_mac_key(&server->mac_signing_key,
3777 ntlm_session_key,
3778 pSesInfo->password);
Steve Frenchad009ac2005-04-28 22:41:05 -07003779
Steve French26b994f2008-08-06 05:11:33 +00003780 rc = CIFSSessSetup(xid, pSesInfo, ntlm_session_key, nls_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003781 }
Steve French26b994f2008-08-06 05:11:33 +00003782 if (rc) {
3783 cERROR(1, ("Send error in SessSetup = %d", rc));
3784 } else {
3785 cFYI(1, ("CIFS Session Established successfully"));
Jeff Layton469ee612008-10-16 18:46:39 +00003786 spin_lock(&GlobalMid_Lock);
Steve French26b994f2008-08-06 05:11:33 +00003787 pSesInfo->status = CifsGood;
Steve French3b795212008-11-13 19:45:32 +00003788 pSesInfo->need_reconnect = false;
Jeff Layton469ee612008-10-16 18:46:39 +00003789 spin_unlock(&GlobalMid_Lock);
Steve French26b994f2008-08-06 05:11:33 +00003790 }
3791
Linus Torvalds1da177e2005-04-16 15:20:36 -07003792ss_err_exit:
3793 return rc;
3794}
3795