blob: 71b7661e2260229efc1fa8eadd7ebf187a5ec8a7 [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 */
92 bool seal:1; /* request transport encryption on share */
Steve French84210e92008-10-23 04:42:37 +000093 bool nodfs:1; /* Do not request DFS, even if available */
94 bool local_lease:1; /* check leases only on local system, not remote */
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 unsigned int rsize;
96 unsigned int wsize;
97 unsigned int sockopt;
98 unsigned short int port;
Steve Frenchfb8c4b12007-07-10 01:16:18 +000099 char *prepath;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100};
101
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000102static int ipv4_connect(struct sockaddr_in *psin_server,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 struct socket **csocket,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000104 char *netb_name,
105 char *server_netb_name);
106static int ipv6_connect(struct sockaddr_in6 *psin_server,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 struct socket **csocket);
108
109
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000110 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 * cifs tcp session reconnection
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000112 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 * mark tcp session as reconnecting so temporarily locked
114 * mark all smb sessions as reconnecting for tcp session
115 * reconnect tcp session
116 * wake up waiters on reconnection? - (not needed currently)
117 */
118
Steve French2cd646a2006-09-28 19:43:08 +0000119static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120cifs_reconnect(struct TCP_Server_Info *server)
121{
122 int rc = 0;
123 struct list_head *tmp;
124 struct cifsSesInfo *ses;
125 struct cifsTconInfo *tcon;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000126 struct mid_q_entry *mid_entry;
Steve French50c2f752007-07-13 00:33:32 +0000127
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 spin_lock(&GlobalMid_Lock);
Jeff Layton469ee612008-10-16 18:46:39 +0000129 if (server->tcpStatus == CifsExiting) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000130 /* the demux thread will exit normally
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131 next time through the loop */
132 spin_unlock(&GlobalMid_Lock);
133 return rc;
134 } else
135 server->tcpStatus = CifsNeedReconnect;
136 spin_unlock(&GlobalMid_Lock);
137 server->maxBuf = 0;
138
Steve Frenche4eb2952005-04-28 22:41:09 -0700139 cFYI(1, ("Reconnecting tcp session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140
141 /* before reconnecting the tcp session, mark the smb session (uid)
142 and the tid bad so they are not used until reconnected */
143 read_lock(&GlobalSMBSeslock);
144 list_for_each(tmp, &GlobalSMBSessionList) {
145 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
146 if (ses->server) {
147 if (ses->server == server) {
148 ses->status = CifsNeedReconnect;
149 ses->ipc_tid = 0;
150 }
151 }
152 /* else tcp and smb sessions need reconnection */
153 }
154 list_for_each(tmp, &GlobalTreeConnectionList) {
155 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000156 if ((tcon->ses) && (tcon->ses->server == server))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 tcon->tidStatus = CifsNeedReconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 }
159 read_unlock(&GlobalSMBSeslock);
160 /* do not want to be sending data on a socket we are freeing */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000161 down(&server->tcpSem);
162 if (server->ssocket) {
Steve French467a8f82007-06-27 22:41:32 +0000163 cFYI(1, ("State: 0x%x Flags: 0x%lx", server->ssocket->state,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 server->ssocket->flags));
Trond Myklebust91cf45f2007-11-12 18:10:39 -0800165 kernel_sock_shutdown(server->ssocket, SHUT_WR);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000166 cFYI(1, ("Post shutdown state: 0x%x Flags: 0x%lx",
Steve French467a8f82007-06-27 22:41:32 +0000167 server->ssocket->state,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 server->ssocket->flags));
169 sock_release(server->ssocket);
170 server->ssocket = NULL;
171 }
172
173 spin_lock(&GlobalMid_Lock);
174 list_for_each(tmp, &server->pending_mid_q) {
175 mid_entry = list_entry(tmp, struct
176 mid_q_entry,
177 qhead);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000178 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French09d1db52005-04-28 22:41:08 -0700179 /* Mark other intransit requests as needing
180 retry so we do not immediately mark the
181 session bad again (ie after we reconnect
182 below) as they timeout too */
Steve Frenchad8b15f2008-08-08 21:10:16 +0000183 mid_entry->midState = MID_RETRY_NEEDED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 }
185 }
186 spin_unlock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000187 up(&server->tcpSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188
Jeff Layton469ee612008-10-16 18:46:39 +0000189 while ((server->tcpStatus != CifsExiting) &&
190 (server->tcpStatus != CifsGood)) {
Steve French6c3d8902006-07-31 22:46:20 +0000191 try_to_freeze();
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000192 if (server->protocolType == IPV6) {
193 rc = ipv6_connect(&server->addr.sockAddr6,
194 &server->ssocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000196 rc = ipv4_connect(&server->addr.sockAddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 &server->ssocket,
Steve Frencha10faeb22005-08-22 21:38:31 -0700198 server->workstation_RFC1001_name,
199 server->server_RFC1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000201 if (rc) {
202 cFYI(1, ("reconnect error %d", rc));
Steve French0cb766a2005-04-28 22:41:11 -0700203 msleep(3000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 } else {
205 atomic_inc(&tcpSesReconnectCount);
206 spin_lock(&GlobalMid_Lock);
Jeff Layton469ee612008-10-16 18:46:39 +0000207 if (server->tcpStatus != CifsExiting)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 server->tcpStatus = CifsGood;
Steve Frenchad009ac2005-04-28 22:41:05 -0700209 server->sequence_number = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000210 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 /* atomic_set(&server->inFlight,0);*/
212 wake_up(&server->response_q);
213 }
214 }
215 return rc;
216}
217
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000218/*
Steve Frenche4eb2952005-04-28 22:41:09 -0700219 return codes:
220 0 not a transact2, or all data present
221 >0 transact2 with that much data missing
222 -EINVAL = invalid transact2
223
224 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000225static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize)
Steve Frenche4eb2952005-04-28 22:41:09 -0700226{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000227 struct smb_t2_rsp *pSMBt;
228 int total_data_size;
Steve Frenche4eb2952005-04-28 22:41:09 -0700229 int data_in_this_rsp;
230 int remaining;
231
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000232 if (pSMB->Command != SMB_COM_TRANSACTION2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700233 return 0;
234
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000235 /* check for plausible wct, bcc and t2 data and parm sizes */
236 /* check for parm and data offset going beyond end of smb */
237 if (pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
Steve French467a8f82007-06-27 22:41:32 +0000238 cFYI(1, ("invalid transact2 word count"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700239 return -EINVAL;
240 }
241
242 pSMBt = (struct smb_t2_rsp *)pSMB;
243
244 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
245 data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
246
247 remaining = total_data_size - data_in_this_rsp;
248
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000249 if (remaining == 0)
Steve Frenche4eb2952005-04-28 22:41:09 -0700250 return 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000251 else if (remaining < 0) {
Steve French467a8f82007-06-27 22:41:32 +0000252 cFYI(1, ("total data %d smaller than data in frame %d",
Steve Frenche4eb2952005-04-28 22:41:09 -0700253 total_data_size, data_in_this_rsp));
254 return -EINVAL;
255 } else {
Steve French467a8f82007-06-27 22:41:32 +0000256 cFYI(1, ("missing %d bytes from transact2, check next response",
Steve Frenche4eb2952005-04-28 22:41:09 -0700257 remaining));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000258 if (total_data_size > maxBufSize) {
259 cERROR(1, ("TotalDataSize %d is over maximum buffer %d",
260 total_data_size, maxBufSize));
261 return -EINVAL;
Steve Frenche4eb2952005-04-28 22:41:09 -0700262 }
263 return remaining;
264 }
265}
266
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000267static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
Steve Frenche4eb2952005-04-28 22:41:09 -0700268{
269 struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
270 struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
271 int total_data_size;
272 int total_in_buf;
273 int remaining;
274 int total_in_buf2;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000275 char *data_area_of_target;
276 char *data_area_of_buf2;
Steve Frenche4eb2952005-04-28 22:41:09 -0700277 __u16 byte_count;
278
279 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
280
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000281 if (total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
Steve French63135e02007-07-17 17:34:02 +0000282 cFYI(1, ("total data size of primary and secondary t2 differ"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700283 }
284
285 total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
286
287 remaining = total_data_size - total_in_buf;
Steve French50c2f752007-07-13 00:33:32 +0000288
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000289 if (remaining < 0)
Steve Frenche4eb2952005-04-28 22:41:09 -0700290 return -EINVAL;
291
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000292 if (remaining == 0) /* nothing to do, ignore */
Steve Frenche4eb2952005-04-28 22:41:09 -0700293 return 0;
Steve French50c2f752007-07-13 00:33:32 +0000294
Steve Frenche4eb2952005-04-28 22:41:09 -0700295 total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000296 if (remaining < total_in_buf2) {
Steve French467a8f82007-06-27 22:41:32 +0000297 cFYI(1, ("transact2 2nd response contains too much data"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700298 }
299
300 /* find end of first SMB data area */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000301 data_area_of_target = (char *)&pSMBt->hdr.Protocol +
Steve Frenche4eb2952005-04-28 22:41:09 -0700302 le16_to_cpu(pSMBt->t2_rsp.DataOffset);
303 /* validate target area */
304
305 data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000306 le16_to_cpu(pSMB2->t2_rsp.DataOffset);
Steve Frenche4eb2952005-04-28 22:41:09 -0700307
308 data_area_of_target += total_in_buf;
309
310 /* copy second buffer into end of first buffer */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000311 memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2);
Steve Frenche4eb2952005-04-28 22:41:09 -0700312 total_in_buf += total_in_buf2;
313 pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
314 byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
315 byte_count += total_in_buf2;
316 BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
317
Steve French70ca7342005-09-22 16:32:06 -0700318 byte_count = pTargetSMB->smb_buf_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700319 byte_count += total_in_buf2;
320
321 /* BB also add check that we are not beyond maximum buffer size */
Steve French50c2f752007-07-13 00:33:32 +0000322
Steve French70ca7342005-09-22 16:32:06 -0700323 pTargetSMB->smb_buf_length = byte_count;
Steve Frenche4eb2952005-04-28 22:41:09 -0700324
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000325 if (remaining == total_in_buf2) {
Steve French467a8f82007-06-27 22:41:32 +0000326 cFYI(1, ("found the last secondary response"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700327 return 0; /* we are done */
328 } else /* more responses to go */
329 return 1;
330
331}
332
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333static int
334cifs_demultiplex_thread(struct TCP_Server_Info *server)
335{
336 int length;
337 unsigned int pdu_length, total_read;
338 struct smb_hdr *smb_buffer = NULL;
Steve Frenchb8643e12005-04-28 22:41:07 -0700339 struct smb_hdr *bigbuf = NULL;
340 struct smb_hdr *smallbuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 struct msghdr smb_msg;
342 struct kvec iov;
343 struct socket *csocket = server->ssocket;
344 struct list_head *tmp;
345 struct cifsSesInfo *ses;
346 struct task_struct *task_to_wake = NULL;
347 struct mid_q_entry *mid_entry;
Steve French70ca7342005-09-22 16:32:06 -0700348 char temp;
Steve French4b18f2a2008-04-29 00:06:05 +0000349 bool isLargeBuf = false;
350 bool isMultiRsp;
Steve Frenche4eb2952005-04-28 22:41:09 -0700351 int reconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 current->flags |= PF_MEMALLOC;
Pavel Emelyanovba25f9d2007-10-18 23:40:40 -0700354 cFYI(1, ("Demultiplex PID: %d", task_pid_nr(current)));
Jeff Layton93d0ec82008-08-02 08:00:48 -0400355
356 length = atomic_inc_return(&tcpSesAllocCount);
357 if (length > 1)
Steve French26f57362007-08-30 22:09:15 +0000358 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
359 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360
Rafael J. Wysocki83144182007-07-17 04:03:35 -0700361 set_freezable();
Jeff Layton469ee612008-10-16 18:46:39 +0000362 while (server->tcpStatus != CifsExiting) {
Steve Frenchede13272005-08-30 20:10:14 -0700363 if (try_to_freeze())
364 continue;
Steve Frenchb8643e12005-04-28 22:41:07 -0700365 if (bigbuf == NULL) {
366 bigbuf = cifs_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000367 if (!bigbuf) {
368 cERROR(1, ("No memory for large SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700369 msleep(3000);
370 /* retry will check if exiting */
371 continue;
372 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000373 } else if (isLargeBuf) {
374 /* we are reusing a dirty large buf, clear its start */
Steve French26f57362007-08-30 22:09:15 +0000375 memset(bigbuf, 0, sizeof(struct smb_hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700377
378 if (smallbuf == NULL) {
379 smallbuf = cifs_small_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000380 if (!smallbuf) {
381 cERROR(1, ("No memory for SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700382 msleep(1000);
383 /* retry will check if exiting */
384 continue;
385 }
386 /* beginning of smb buffer is cleared in our buf_get */
387 } else /* if existing small buf clear beginning */
Steve French26f57362007-08-30 22:09:15 +0000388 memset(smallbuf, 0, sizeof(struct smb_hdr));
Steve Frenchb8643e12005-04-28 22:41:07 -0700389
Steve French4b18f2a2008-04-29 00:06:05 +0000390 isLargeBuf = false;
391 isMultiRsp = false;
Steve Frenchb8643e12005-04-28 22:41:07 -0700392 smb_buffer = smallbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 iov.iov_base = smb_buffer;
394 iov.iov_len = 4;
395 smb_msg.msg_control = NULL;
396 smb_msg.msg_controllen = 0;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000397 pdu_length = 4; /* enough to get RFC1001 header */
398incomplete_rcv:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 length =
400 kernel_recvmsg(csocket, &smb_msg,
Steve Frenchf01d5e12007-08-30 21:13:31 +0000401 &iov, 1, pdu_length, 0 /* BB other flags? */);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402
Jeff Layton469ee612008-10-16 18:46:39 +0000403 if (server->tcpStatus == CifsExiting) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 break;
405 } else if (server->tcpStatus == CifsNeedReconnect) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000406 cFYI(1, ("Reconnect after server stopped responding"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 cifs_reconnect(server);
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000408 cFYI(1, ("call to reconnect done"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 csocket = server->ssocket;
410 continue;
411 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700412 msleep(1); /* minimum sleep to prevent looping
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 allowing socket to clear and app threads to set
414 tcpStatus CifsNeedReconnect if server hung */
Steve Frenchc18c7322007-10-17 18:01:11 +0000415 if (pdu_length < 4)
416 goto incomplete_rcv;
417 else
418 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 } else if (length <= 0) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000420 if (server->tcpStatus == CifsNew) {
421 cFYI(1, ("tcp session abend after SMBnegprot"));
Steve French09d1db52005-04-28 22:41:08 -0700422 /* some servers kill the TCP session rather than
423 returning an SMB negprot error, in which
424 case reconnecting here is not going to help,
425 and so simply return error to mount */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 break;
427 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000428 if (!try_to_freeze() && (length == -EINTR)) {
Steve French467a8f82007-06-27 22:41:32 +0000429 cFYI(1, ("cifsd thread killed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 break;
431 }
Steve French467a8f82007-06-27 22:41:32 +0000432 cFYI(1, ("Reconnect after unexpected peek error %d",
Steve French57337e42005-04-28 22:41:10 -0700433 length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 cifs_reconnect(server);
435 csocket = server->ssocket;
436 wake_up(&server->response_q);
437 continue;
Petr Tesarik2a974682007-11-20 02:24:08 +0000438 } else if (length < pdu_length) {
439 cFYI(1, ("requested %d bytes but only got %d bytes",
440 pdu_length, length));
Steve Frenchf01d5e12007-08-30 21:13:31 +0000441 pdu_length -= length;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000442 msleep(1);
443 goto incomplete_rcv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 }
Steve French67010fb2005-04-28 22:41:09 -0700445
Steve French70ca7342005-09-22 16:32:06 -0700446 /* The right amount was read from socket - 4 bytes */
447 /* so we can now interpret the length field */
Steve French46810cb2005-04-28 22:41:09 -0700448
Steve French70ca7342005-09-22 16:32:06 -0700449 /* the first byte big endian of the length field,
450 is actually not part of the length but the type
451 with the most common, zero, as regular data */
452 temp = *((char *) smb_buffer);
453
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000454 /* Note that FC 1001 length is big endian on the wire,
Steve French70ca7342005-09-22 16:32:06 -0700455 but we convert it here so it is always manipulated
456 as host byte order */
Harvey Harrison5ca33c62008-07-23 17:45:58 -0700457 pdu_length = be32_to_cpu((__force __be32)smb_buffer->smb_buf_length);
Steve French70ca7342005-09-22 16:32:06 -0700458 smb_buffer->smb_buf_length = pdu_length;
Steve French46810cb2005-04-28 22:41:09 -0700459
Steve French467a8f82007-06-27 22:41:32 +0000460 cFYI(1, ("rfc1002 length 0x%x", pdu_length+4));
Steve French70ca7342005-09-22 16:32:06 -0700461
462 if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000463 continue;
Steve French70ca7342005-09-22 16:32:06 -0700464 } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
Steve French467a8f82007-06-27 22:41:32 +0000465 cFYI(1, ("Good RFC 1002 session rsp"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700466 continue;
Steve French70ca7342005-09-22 16:32:06 -0700467 } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000468 /* we get this from Windows 98 instead of
Steve French46810cb2005-04-28 22:41:09 -0700469 an error on SMB negprot response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000470 cFYI(1, ("Negative RFC1002 Session Response Error 0x%x)",
Steve French70ca7342005-09-22 16:32:06 -0700471 pdu_length));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000472 if (server->tcpStatus == CifsNew) {
473 /* if nack on negprot (rather than
Steve French46810cb2005-04-28 22:41:09 -0700474 ret of smb negprot error) reconnecting
475 not going to help, ret error to mount */
476 break;
477 } else {
478 /* give server a second to
479 clean up before reconnect attempt */
480 msleep(1000);
481 /* always try 445 first on reconnect
482 since we get NACK on some if we ever
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000483 connected to port 139 (the NACK is
Steve French46810cb2005-04-28 22:41:09 -0700484 since we do not begin with RFC1001
485 session initialize frame) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000486 server->addr.sockAddr.sin_port =
Steve French46810cb2005-04-28 22:41:09 -0700487 htons(CIFS_PORT);
488 cifs_reconnect(server);
489 csocket = server->ssocket;
490 wake_up(&server->response_q);
491 continue;
492 }
Steve French70ca7342005-09-22 16:32:06 -0700493 } else if (temp != (char) 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000494 cERROR(1, ("Unknown RFC 1002 frame"));
Steve French70ca7342005-09-22 16:32:06 -0700495 cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
496 length);
Steve French46810cb2005-04-28 22:41:09 -0700497 cifs_reconnect(server);
498 csocket = server->ssocket;
499 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700500 }
501
502 /* else we have an SMB response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000503 if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French26f57362007-08-30 22:09:15 +0000504 (pdu_length < sizeof(struct smb_hdr) - 1 - 4)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700505 cERROR(1, ("Invalid size SMB length %d pdu_length %d",
Steve French46810cb2005-04-28 22:41:09 -0700506 length, pdu_length+4));
Steve Frenche4eb2952005-04-28 22:41:09 -0700507 cifs_reconnect(server);
508 csocket = server->ssocket;
509 wake_up(&server->response_q);
510 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000511 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700512
513 /* else length ok */
514 reconnect = 0;
515
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000516 if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
Steve French4b18f2a2008-04-29 00:06:05 +0000517 isLargeBuf = true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700518 memcpy(bigbuf, smallbuf, 4);
519 smb_buffer = bigbuf;
520 }
521 length = 0;
522 iov.iov_base = 4 + (char *)smb_buffer;
523 iov.iov_len = pdu_length;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000524 for (total_read = 0; total_read < pdu_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700525 total_read += length) {
526 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
527 pdu_length - total_read, 0);
Jeff Layton469ee612008-10-16 18:46:39 +0000528 if ((server->tcpStatus == CifsExiting) ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700529 (length == -EINTR)) {
530 /* then will exit */
531 reconnect = 2;
532 break;
533 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700534 cifs_reconnect(server);
535 csocket = server->ssocket;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000536 /* Reconnect wakes up rspns q */
Steve Frenche4eb2952005-04-28 22:41:09 -0700537 /* Now we will reread sock */
538 reconnect = 1;
539 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000540 } else if ((length == -ERESTARTSYS) ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700541 (length == -EAGAIN)) {
542 msleep(1); /* minimum sleep to prevent looping,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000543 allowing socket to clear and app
Steve Frenche4eb2952005-04-28 22:41:09 -0700544 threads to set tcpStatus
545 CifsNeedReconnect if server hung*/
Steve Frenchc18c7322007-10-17 18:01:11 +0000546 length = 0;
Steve French46810cb2005-04-28 22:41:09 -0700547 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700548 } else if (length <= 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000549 cERROR(1, ("Received no data, expecting %d",
Steve Frenche4eb2952005-04-28 22:41:09 -0700550 pdu_length - total_read));
551 cifs_reconnect(server);
552 csocket = server->ssocket;
553 reconnect = 1;
554 break;
Steve French46810cb2005-04-28 22:41:09 -0700555 }
556 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000557 if (reconnect == 2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700558 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000559 else if (reconnect == 1)
Steve Frenche4eb2952005-04-28 22:41:09 -0700560 continue;
561
562 length += 4; /* account for rfc1002 hdr */
Steve French50c2f752007-07-13 00:33:32 +0000563
Steve Frenche4eb2952005-04-28 22:41:09 -0700564
565 dump_smb(smb_buffer, length);
Steve French184ed212006-02-24 06:15:11 +0000566 if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700567 cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
Steve Frenche4eb2952005-04-28 22:41:09 -0700568 continue;
569 }
570
571
572 task_to_wake = NULL;
573 spin_lock(&GlobalMid_Lock);
574 list_for_each(tmp, &server->pending_mid_q) {
575 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
576
Steve French50c2f752007-07-13 00:33:32 +0000577 if ((mid_entry->mid == smb_buffer->Mid) &&
Steve Frenche4eb2952005-04-28 22:41:09 -0700578 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
579 (mid_entry->command == smb_buffer->Command)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000580 if (check2ndT2(smb_buffer,server->maxBuf) > 0) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700581 /* We have a multipart transact2 resp */
Steve French4b18f2a2008-04-29 00:06:05 +0000582 isMultiRsp = true;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000583 if (mid_entry->resp_buf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700584 /* merge response - fix up 1st*/
Steve French50c2f752007-07-13 00:33:32 +0000585 if (coalesce_t2(smb_buffer,
Steve Frenche4eb2952005-04-28 22:41:09 -0700586 mid_entry->resp_buf)) {
Steve French4b18f2a2008-04-29 00:06:05 +0000587 mid_entry->multiRsp =
588 true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700589 break;
590 } else {
591 /* all parts received */
Steve French4b18f2a2008-04-29 00:06:05 +0000592 mid_entry->multiEnd =
593 true;
Steve French50c2f752007-07-13 00:33:32 +0000594 goto multi_t2_fnd;
Steve Frenche4eb2952005-04-28 22:41:09 -0700595 }
596 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000597 if (!isLargeBuf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700598 cERROR(1,("1st trans2 resp needs bigbuf"));
599 /* BB maybe we can fix this up, switch
Steve French50c2f752007-07-13 00:33:32 +0000600 to already allocated large buffer? */
Steve Frenche4eb2952005-04-28 22:41:09 -0700601 } else {
Steve Frenchcd634992005-04-28 22:41:10 -0700602 /* Have first buffer */
Steve Frenche4eb2952005-04-28 22:41:09 -0700603 mid_entry->resp_buf =
604 smb_buffer;
Steve French4b18f2a2008-04-29 00:06:05 +0000605 mid_entry->largeBuf =
606 true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700607 bigbuf = NULL;
608 }
609 }
610 break;
Steve French50c2f752007-07-13 00:33:32 +0000611 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700612 mid_entry->resp_buf = smb_buffer;
Steve French4b18f2a2008-04-29 00:06:05 +0000613 mid_entry->largeBuf = isLargeBuf;
Steve Frenche4eb2952005-04-28 22:41:09 -0700614multi_t2_fnd:
615 task_to_wake = mid_entry->tsk;
616 mid_entry->midState = MID_RESPONSE_RECEIVED;
Steve French1047abc2005-10-11 19:58:06 -0700617#ifdef CONFIG_CIFS_STATS2
618 mid_entry->when_received = jiffies;
619#endif
Steve French3a5ff612006-07-14 22:37:11 +0000620 /* so we do not time out requests to server
621 which is still responding (since server could
622 be busy but not dead) */
623 server->lstrp = jiffies;
Steve Frenche4eb2952005-04-28 22:41:09 -0700624 break;
625 }
626 }
627 spin_unlock(&GlobalMid_Lock);
628 if (task_to_wake) {
Steve Frenchcd634992005-04-28 22:41:10 -0700629 /* Was previous buf put in mpx struct for multi-rsp? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000630 if (!isMultiRsp) {
Steve Frenchcd634992005-04-28 22:41:10 -0700631 /* smb buffer will be freed by user thread */
Steve French26f57362007-08-30 22:09:15 +0000632 if (isLargeBuf)
Steve Frenchcd634992005-04-28 22:41:10 -0700633 bigbuf = NULL;
Steve French26f57362007-08-30 22:09:15 +0000634 else
Steve Frenchcd634992005-04-28 22:41:10 -0700635 smallbuf = NULL;
636 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700637 wake_up_process(task_to_wake);
Steve French4b18f2a2008-04-29 00:06:05 +0000638 } else if (!is_valid_oplock_break(smb_buffer, server) &&
639 !isMultiRsp) {
Steve French50c2f752007-07-13 00:33:32 +0000640 cERROR(1, ("No task to wake, unknown frame received! "
641 "NumMids %d", midCount.counter));
642 cifs_dump_mem("Received Data is: ", (char *)smb_buffer,
Steve French70ca7342005-09-22 16:32:06 -0700643 sizeof(struct smb_hdr));
Steve French39798772006-05-31 22:40:51 +0000644#ifdef CONFIG_CIFS_DEBUG2
645 cifs_dump_detail(smb_buffer);
646 cifs_dump_mids(server);
647#endif /* CIFS_DEBUG2 */
Steve French50c2f752007-07-13 00:33:32 +0000648
Steve Frenche4eb2952005-04-28 22:41:09 -0700649 }
650 } /* end while !EXITING */
651
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 spin_lock(&GlobalMid_Lock);
653 server->tcpStatus = CifsExiting;
Steve Frenche691b9d2008-05-11 15:53:33 +0000654 spin_unlock(&GlobalMid_Lock);
Steve Frenchdbdbb872008-06-10 21:21:56 +0000655 wake_up_all(&server->response_q);
Steve Frenche691b9d2008-05-11 15:53:33 +0000656
Steve French31ca3bc2005-04-28 22:41:11 -0700657 /* check if we have blocked requests that need to free */
658 /* Note that cifs_max_pending is normally 50, but
659 can be set at module install time to as little as two */
Steve Frenche691b9d2008-05-11 15:53:33 +0000660 spin_lock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000661 if (atomic_read(&server->inFlight) >= cifs_max_pending)
Steve French31ca3bc2005-04-28 22:41:11 -0700662 atomic_set(&server->inFlight, cifs_max_pending - 1);
663 /* We do not want to set the max_pending too low or we
664 could end up with the counter going negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +0000666 /* Although there should not be any requests blocked on
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700668 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 to the same server - they now will see the session is in exit state
670 and get out of SendReceive. */
671 wake_up_all(&server->request_q);
672 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700673 msleep(125);
Steve French50c2f752007-07-13 00:33:32 +0000674
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000675 if (server->ssocket) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 sock_release(csocket);
677 server->ssocket = NULL;
678 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700679 /* buffer usuallly freed in free_mid - need to free it here on exit */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +0000680 cifs_buf_release(bigbuf);
681 if (smallbuf) /* no sense logging a debug message if NULL */
Steve Frenchb8643e12005-04-28 22:41:07 -0700682 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683
684 read_lock(&GlobalSMBSeslock);
685 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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 list_for_each(tmp, &GlobalSMBSessionList) {
689 ses =
690 list_entry(tmp, struct cifsSesInfo,
691 cifsSessionList);
692 if (ses->server == server) {
693 ses->status = CifsExiting;
694 ses->server = NULL;
695 }
696 }
697 read_unlock(&GlobalSMBSeslock);
698 } else {
Steve French31ca3bc2005-04-28 22:41:11 -0700699 /* although we can not zero the server struct pointer yet,
700 since there are active requests which may depnd on them,
701 mark the corresponding SMB sessions as exiting too */
702 list_for_each(tmp, &GlobalSMBSessionList) {
703 ses = list_entry(tmp, struct cifsSesInfo,
704 cifsSessionList);
Steve French26f57362007-08-30 22:09:15 +0000705 if (ses->server == server)
Steve French31ca3bc2005-04-28 22:41:11 -0700706 ses->status = CifsExiting;
Steve French31ca3bc2005-04-28 22:41:11 -0700707 }
708
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 spin_lock(&GlobalMid_Lock);
710 list_for_each(tmp, &server->pending_mid_q) {
711 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
712 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French50c2f752007-07-13 00:33:32 +0000713 cFYI(1, ("Clearing Mid 0x%x - waking up ",
714 mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 task_to_wake = mid_entry->tsk;
Steve French26f57362007-08-30 22:09:15 +0000716 if (task_to_wake)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 wake_up_process(task_to_wake);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 }
719 }
720 spin_unlock(&GlobalMid_Lock);
721 read_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700723 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 }
725
Steve Frenchf1914012005-08-18 09:37:34 -0700726 if (!list_empty(&server->pending_mid_q)) {
Steve French50c2f752007-07-13 00:33:32 +0000727 /* mpx threads have not exited yet give them
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700729 /* due to delays on oplock break requests, we need
730 to wait at least 45 seconds before giving up
731 on a request getting a response and going ahead
732 and killing cifsd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve French31ca3bc2005-04-28 22:41:11 -0700734 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 /* if threads still have not exited they are probably never
736 coming home not much else we can do but free the memory */
737 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738
Steve French31ca3bc2005-04-28 22:41:11 -0700739 /* last chance to mark ses pointers invalid
740 if there are any pointing to this (e.g
Steve French50c2f752007-07-13 00:33:32 +0000741 if a crazy root user tried to kill cifsd
Steve French31ca3bc2005-04-28 22:41:11 -0700742 kernel thread explicitly this might happen) */
Jeff Layton93d0ec82008-08-02 08:00:48 -0400743 write_lock(&GlobalSMBSeslock);
Steve French31ca3bc2005-04-28 22:41:11 -0700744 list_for_each(tmp, &GlobalSMBSessionList) {
745 ses = list_entry(tmp, struct cifsSesInfo,
746 cifsSessionList);
Steve French26f57362007-08-30 22:09:15 +0000747 if (ses->server == server)
Steve French31ca3bc2005-04-28 22:41:11 -0700748 ses->server = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700749 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 write_unlock(&GlobalSMBSeslock);
Steve French31ca3bc2005-04-28 22:41:11 -0700751
Jeff Laytonc359cf32007-11-16 22:22:06 +0000752 kfree(server->hostname);
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -0400753 task_to_wake = xchg(&server->tsk, NULL);
Steve French31ca3bc2005-04-28 22:41:11 -0700754 kfree(server);
Jeff Layton93d0ec82008-08-02 08:00:48 -0400755
756 length = atomic_dec_return(&tcpSesAllocCount);
Steve French26f57362007-08-30 22:09:15 +0000757 if (length > 0)
758 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
759 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +0000760
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -0400761 /* if server->tsk was NULL then wait for a signal before exiting */
762 if (!task_to_wake) {
763 set_current_state(TASK_INTERRUPTIBLE);
764 while (!signal_pending(current)) {
765 schedule();
766 set_current_state(TASK_INTERRUPTIBLE);
767 }
768 set_current_state(TASK_RUNNING);
769 }
770
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 return 0;
772}
773
Jeff Laytonc359cf32007-11-16 22:22:06 +0000774/* extract the host portion of the UNC string */
775static char *
776extract_hostname(const char *unc)
777{
778 const char *src;
779 char *dst, *delim;
780 unsigned int len;
781
782 /* skip double chars at beginning of string */
783 /* BB: check validity of these bytes? */
784 src = unc + 2;
785
786 /* delimiter between hostname and sharename is always '\\' now */
787 delim = strchr(src, '\\');
788 if (!delim)
789 return ERR_PTR(-EINVAL);
790
791 len = delim - src;
792 dst = kmalloc((len + 1), GFP_KERNEL);
793 if (dst == NULL)
794 return ERR_PTR(-ENOMEM);
795
796 memcpy(dst, src, len);
797 dst[len] = '\0';
798
799 return dst;
800}
801
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802static int
Steve French50c2f752007-07-13 00:33:32 +0000803cifs_parse_mount_options(char *options, const char *devname,
804 struct smb_vol *vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805{
806 char *value;
807 char *data;
808 unsigned int temp_len, i, j;
809 char separator[2];
810
811 separator[0] = ',';
Steve French50c2f752007-07-13 00:33:32 +0000812 separator[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813
Linus Torvalds12e36b22006-10-13 08:09:29 -0700814 if (Local_System_Name[0] != 0)
Steve French50c2f752007-07-13 00:33:32 +0000815 memcpy(vol->source_rfc1001_name, Local_System_Name, 15);
Steve French2cd646a2006-09-28 19:43:08 +0000816 else {
Linus Torvalds12e36b22006-10-13 08:09:29 -0700817 char *nodename = utsname()->nodename;
Steve French50c2f752007-07-13 00:33:32 +0000818 int n = strnlen(nodename, 15);
819 memset(vol->source_rfc1001_name, 0x20, 15);
820 for (i = 0; i < n; i++) {
Steve French2cd646a2006-09-28 19:43:08 +0000821 /* does not have to be perfect mapping since field is
822 informational, only used for servers that do not support
823 port 445 and it can be overridden at mount time */
Linus Torvalds12e36b22006-10-13 08:09:29 -0700824 vol->source_rfc1001_name[i] = toupper(nodename[i]);
Steve French2cd646a2006-09-28 19:43:08 +0000825 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 }
827 vol->source_rfc1001_name[15] = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -0700828 /* null target name indicates to use *SMBSERVR default called name
829 if we end up sending RFC1001 session initialize */
830 vol->target_rfc1001_name[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 vol->linux_uid = current->uid; /* current->euid instead? */
832 vol->linux_gid = current->gid;
833 vol->dir_mode = S_IRWXUGO;
834 /* 2767 perms indicate mandatory locking support */
Steve French7505e052007-11-01 18:03:01 +0000835 vol->file_mode = (S_IRWXUGO | S_ISGID) & (~S_IXGRP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836
837 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
Steve French4b18f2a2008-04-29 00:06:05 +0000838 vol->rw = true;
Jeremy Allisonac670552005-06-22 17:26:35 -0700839 /* default is always to request posix paths. */
840 vol->posix_paths = 1;
841
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 if (!options)
843 return 1;
844
Steve French50c2f752007-07-13 00:33:32 +0000845 if (strncmp(options, "sep=", 4) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000846 if (options[4] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 separator[0] = options[4];
848 options += 5;
849 } else {
Steve French467a8f82007-06-27 22:41:32 +0000850 cFYI(1, ("Null separator not allowed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 }
852 }
Steve French50c2f752007-07-13 00:33:32 +0000853
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 while ((data = strsep(&options, separator)) != NULL) {
855 if (!*data)
856 continue;
857 if ((value = strchr(data, '=')) != NULL)
858 *value++ = '\0';
859
Steve French50c2f752007-07-13 00:33:32 +0000860 /* Have to parse this before we parse for "user" */
861 if (strnicmp(data, "user_xattr", 10) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 vol->no_xattr = 0;
Steve French50c2f752007-07-13 00:33:32 +0000863 } else if (strnicmp(data, "nouser_xattr", 12) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 vol->no_xattr = 1;
865 } else if (strnicmp(data, "user", 4) == 0) {
Steve French4b952a92006-10-30 21:46:13 +0000866 if (!value) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 printk(KERN_WARNING
868 "CIFS: invalid or missing username\n");
869 return 1; /* needs_arg; */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000870 } else if (!*value) {
Steve French4b952a92006-10-30 21:46:13 +0000871 /* null user, ie anonymous, authentication */
872 vol->nullauth = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 }
874 if (strnlen(value, 200) < 200) {
875 vol->username = value;
876 } else {
877 printk(KERN_WARNING "CIFS: username too long\n");
878 return 1;
879 }
880 } else if (strnicmp(data, "pass", 4) == 0) {
881 if (!value) {
882 vol->password = NULL;
883 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000884 } else if (value[0] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 /* check if string begins with double comma
886 since that would mean the password really
887 does start with a comma, and would not
888 indicate an empty string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000889 if (value[1] != separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 vol->password = NULL;
891 continue;
892 }
893 }
894 temp_len = strlen(value);
895 /* removed password length check, NTLM passwords
896 can be arbitrarily long */
897
Steve French50c2f752007-07-13 00:33:32 +0000898 /* if comma in password, the string will be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 prematurely null terminated. Commas in password are
900 specified across the cifs mount interface by a double
901 comma ie ,, and a comma used as in other cases ie ','
902 as a parameter delimiter/separator is single and due
903 to the strsep above is temporarily zeroed. */
904
905 /* NB: password legally can have multiple commas and
906 the only illegal character in a password is null */
907
Steve French50c2f752007-07-13 00:33:32 +0000908 if ((value[temp_len] == 0) &&
Steve French09d1db52005-04-28 22:41:08 -0700909 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 /* reinsert comma */
911 value[temp_len] = separator[0];
Steve French50c2f752007-07-13 00:33:32 +0000912 temp_len += 2; /* move after second comma */
913 while (value[temp_len] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 if (value[temp_len] == separator[0]) {
Steve French50c2f752007-07-13 00:33:32 +0000915 if (value[temp_len+1] ==
Steve French09d1db52005-04-28 22:41:08 -0700916 separator[0]) {
917 /* skip second comma */
918 temp_len++;
Steve French50c2f752007-07-13 00:33:32 +0000919 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 /* single comma indicating start
921 of next parm */
922 break;
923 }
924 }
925 temp_len++;
926 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000927 if (value[temp_len] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 options = NULL;
929 } else {
930 value[temp_len] = 0;
931 /* point option to start of next parm */
932 options = value + temp_len + 1;
933 }
Steve French50c2f752007-07-13 00:33:32 +0000934 /* go from value to value + temp_len condensing
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 double commas to singles. Note that this ends up
936 allocating a few bytes too many, which is ok */
Pekka Enberge915fc42005-09-06 15:18:35 -0700937 vol->password = kzalloc(temp_len, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000938 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000939 printk(KERN_WARNING "CIFS: no memory "
940 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700941 return 1;
942 }
Steve French50c2f752007-07-13 00:33:32 +0000943 for (i = 0, j = 0; i < temp_len; i++, j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 vol->password[j] = value[i];
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000945 if (value[i] == separator[0]
Steve French09d1db52005-04-28 22:41:08 -0700946 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 /* skip second comma */
948 i++;
949 }
950 }
951 vol->password[j] = 0;
952 } else {
Pekka Enberge915fc42005-09-06 15:18:35 -0700953 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000954 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000955 printk(KERN_WARNING "CIFS: no memory "
956 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700957 return 1;
958 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 strcpy(vol->password, value);
960 }
961 } else if (strnicmp(data, "ip", 2) == 0) {
962 if (!value || !*value) {
963 vol->UNCip = NULL;
964 } else if (strnlen(value, 35) < 35) {
965 vol->UNCip = value;
966 } else {
Steve French50c2f752007-07-13 00:33:32 +0000967 printk(KERN_WARNING "CIFS: ip address "
968 "too long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 return 1;
970 }
Steve French50c2f752007-07-13 00:33:32 +0000971 } else if (strnicmp(data, "sec", 3) == 0) {
972 if (!value || !*value) {
973 cERROR(1, ("no security value specified"));
974 continue;
975 } else if (strnicmp(value, "krb5i", 5) == 0) {
976 vol->secFlg |= CIFSSEC_MAY_KRB5 |
Steve French189acaa2006-06-23 02:33:48 +0000977 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800978 } else if (strnicmp(value, "krb5p", 5) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000979 /* vol->secFlg |= CIFSSEC_MUST_SEAL |
980 CIFSSEC_MAY_KRB5; */
981 cERROR(1, ("Krb5 cifs privacy not supported"));
Steve Frenchbf820672005-12-01 22:32:42 -0800982 return 1;
983 } else if (strnicmp(value, "krb5", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000984 vol->secFlg |= CIFSSEC_MAY_KRB5;
Steve Frenchbf820672005-12-01 22:32:42 -0800985 } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000986 vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
Steve French189acaa2006-06-23 02:33:48 +0000987 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800988 } else if (strnicmp(value, "ntlmv2", 6) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000989 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve Frenchbf820672005-12-01 22:32:42 -0800990 } else if (strnicmp(value, "ntlmi", 5) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000991 vol->secFlg |= CIFSSEC_MAY_NTLM |
Steve French189acaa2006-06-23 02:33:48 +0000992 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800993 } else if (strnicmp(value, "ntlm", 4) == 0) {
994 /* ntlm is default so can be turned off too */
Steve French750d1152006-06-27 06:28:30 +0000995 vol->secFlg |= CIFSSEC_MAY_NTLM;
Steve Frenchbf820672005-12-01 22:32:42 -0800996 } else if (strnicmp(value, "nontlm", 6) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000997 /* BB is there a better way to do this? */
Steve French750d1152006-06-27 06:28:30 +0000998 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve French189acaa2006-06-23 02:33:48 +0000999#ifdef CONFIG_CIFS_WEAK_PW_HASH
1000 } else if (strnicmp(value, "lanman", 6) == 0) {
Steve French50c2f752007-07-13 00:33:32 +00001001 vol->secFlg |= CIFSSEC_MAY_LANMAN;
Steve French189acaa2006-06-23 02:33:48 +00001002#endif
Steve Frenchbf820672005-12-01 22:32:42 -08001003 } else if (strnicmp(value, "none", 4) == 0) {
Steve French189acaa2006-06-23 02:33:48 +00001004 vol->nullauth = 1;
Steve French50c2f752007-07-13 00:33:32 +00001005 } else {
1006 cERROR(1, ("bad security option: %s", value));
1007 return 1;
1008 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 } else if ((strnicmp(data, "unc", 3) == 0)
1010 || (strnicmp(data, "target", 6) == 0)
1011 || (strnicmp(data, "path", 4) == 0)) {
1012 if (!value || !*value) {
Steve French50c2f752007-07-13 00:33:32 +00001013 printk(KERN_WARNING "CIFS: invalid path to "
1014 "network resource\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 return 1; /* needs_arg; */
1016 }
1017 if ((temp_len = strnlen(value, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001018 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001019 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001021 strcpy(vol->UNC, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 if (strncmp(vol->UNC, "//", 2) == 0) {
1023 vol->UNC[0] = '\\';
1024 vol->UNC[1] = '\\';
Steve French50c2f752007-07-13 00:33:32 +00001025 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 printk(KERN_WARNING
Steve French50c2f752007-07-13 00:33:32 +00001027 "CIFS: UNC Path does not begin "
1028 "with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 return 1;
1030 }
1031 } else {
1032 printk(KERN_WARNING "CIFS: UNC name too long\n");
1033 return 1;
1034 }
1035 } else if ((strnicmp(data, "domain", 3) == 0)
1036 || (strnicmp(data, "workgroup", 5) == 0)) {
1037 if (!value || !*value) {
1038 printk(KERN_WARNING "CIFS: invalid domain name\n");
1039 return 1; /* needs_arg; */
1040 }
1041 /* BB are there cases in which a comma can be valid in
1042 a domain name and need special handling? */
Steve French39798772006-05-31 22:40:51 +00001043 if (strnlen(value, 256) < 256) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 vol->domainname = value;
1045 cFYI(1, ("Domain name set"));
1046 } else {
Steve French50c2f752007-07-13 00:33:32 +00001047 printk(KERN_WARNING "CIFS: domain name too "
1048 "long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 return 1;
1050 }
Steve French50c2f752007-07-13 00:33:32 +00001051 } else if (strnicmp(data, "prefixpath", 10) == 0) {
1052 if (!value || !*value) {
1053 printk(KERN_WARNING
1054 "CIFS: invalid path prefix\n");
1055 return 1; /* needs_argument */
1056 }
1057 if ((temp_len = strnlen(value, 1024)) < 1024) {
Steve French4523cc32007-04-30 20:13:06 +00001058 if (value[0] != '/')
Steve French2fe87f02006-09-21 07:02:52 +00001059 temp_len++; /* missing leading slash */
Steve French50c2f752007-07-13 00:33:32 +00001060 vol->prepath = kmalloc(temp_len+1, GFP_KERNEL);
1061 if (vol->prepath == NULL)
1062 return 1;
Steve French4523cc32007-04-30 20:13:06 +00001063 if (value[0] != '/') {
Steve French2fe87f02006-09-21 07:02:52 +00001064 vol->prepath[0] = '/';
Steve French50c2f752007-07-13 00:33:32 +00001065 strcpy(vol->prepath+1, value);
Steve French2fe87f02006-09-21 07:02:52 +00001066 } else
Steve French50c2f752007-07-13 00:33:32 +00001067 strcpy(vol->prepath, value);
1068 cFYI(1, ("prefix path %s", vol->prepath));
1069 } else {
1070 printk(KERN_WARNING "CIFS: prefix too long\n");
1071 return 1;
1072 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 } else if (strnicmp(data, "iocharset", 9) == 0) {
1074 if (!value || !*value) {
Steve French63135e02007-07-17 17:34:02 +00001075 printk(KERN_WARNING "CIFS: invalid iocharset "
1076 "specified\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 return 1; /* needs_arg; */
1078 }
1079 if (strnlen(value, 65) < 65) {
Steve French50c2f752007-07-13 00:33:32 +00001080 if (strnicmp(value, "default", 7))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 vol->iocharset = value;
Steve French50c2f752007-07-13 00:33:32 +00001082 /* if iocharset not set then load_nls_default
1083 is used by caller */
1084 cFYI(1, ("iocharset set to %s", value));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 } else {
Steve French63135e02007-07-17 17:34:02 +00001086 printk(KERN_WARNING "CIFS: iocharset name "
1087 "too long.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 return 1;
1089 }
1090 } else if (strnicmp(data, "uid", 3) == 0) {
1091 if (value && *value) {
1092 vol->linux_uid =
1093 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001094 vol->override_uid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 }
1096 } else if (strnicmp(data, "gid", 3) == 0) {
1097 if (value && *value) {
1098 vol->linux_gid =
1099 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001100 vol->override_gid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 }
1102 } else if (strnicmp(data, "file_mode", 4) == 0) {
1103 if (value && *value) {
1104 vol->file_mode =
1105 simple_strtoul(value, &value, 0);
1106 }
1107 } else if (strnicmp(data, "dir_mode", 4) == 0) {
1108 if (value && *value) {
1109 vol->dir_mode =
1110 simple_strtoul(value, &value, 0);
1111 }
1112 } else if (strnicmp(data, "dirmode", 4) == 0) {
1113 if (value && *value) {
1114 vol->dir_mode =
1115 simple_strtoul(value, &value, 0);
1116 }
1117 } else if (strnicmp(data, "port", 4) == 0) {
1118 if (value && *value) {
1119 vol->port =
1120 simple_strtoul(value, &value, 0);
1121 }
1122 } else if (strnicmp(data, "rsize", 5) == 0) {
1123 if (value && *value) {
1124 vol->rsize =
1125 simple_strtoul(value, &value, 0);
1126 }
1127 } else if (strnicmp(data, "wsize", 5) == 0) {
1128 if (value && *value) {
1129 vol->wsize =
1130 simple_strtoul(value, &value, 0);
1131 }
1132 } else if (strnicmp(data, "sockopt", 5) == 0) {
1133 if (value && *value) {
1134 vol->sockopt =
1135 simple_strtoul(value, &value, 0);
1136 }
1137 } else if (strnicmp(data, "netbiosname", 4) == 0) {
1138 if (!value || !*value || (*value == ' ')) {
Steve French63135e02007-07-17 17:34:02 +00001139 cFYI(1, ("invalid (empty) netbiosname"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 } else {
Steve French50c2f752007-07-13 00:33:32 +00001141 memset(vol->source_rfc1001_name, 0x20, 15);
1142 for (i = 0; i < 15; i++) {
1143 /* BB are there cases in which a comma can be
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 valid in this workstation netbios name (and need
1145 special handling)? */
1146
1147 /* We do not uppercase netbiosname for user */
Steve French50c2f752007-07-13 00:33:32 +00001148 if (value[i] == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 break;
Steve French50c2f752007-07-13 00:33:32 +00001150 else
1151 vol->source_rfc1001_name[i] =
1152 value[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 }
1154 /* The string has 16th byte zero still from
1155 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001156 if ((i == 15) && (value[i] != 0))
1157 printk(KERN_WARNING "CIFS: netbiosname"
1158 " longer than 15 truncated.\n");
Steve Frencha10faeb22005-08-22 21:38:31 -07001159 }
1160 } else if (strnicmp(data, "servern", 7) == 0) {
1161 /* servernetbiosname specified override *SMBSERVER */
1162 if (!value || !*value || (*value == ' ')) {
Steve French467a8f82007-06-27 22:41:32 +00001163 cFYI(1, ("empty server netbiosname specified"));
Steve Frencha10faeb22005-08-22 21:38:31 -07001164 } else {
1165 /* last byte, type, is 0x20 for servr type */
Steve French50c2f752007-07-13 00:33:32 +00001166 memset(vol->target_rfc1001_name, 0x20, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001167
Steve French50c2f752007-07-13 00:33:32 +00001168 for (i = 0; i < 15; i++) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001169 /* BB are there cases in which a comma can be
Steve French50c2f752007-07-13 00:33:32 +00001170 valid in this workstation netbios name
1171 (and need special handling)? */
Steve Frencha10faeb22005-08-22 21:38:31 -07001172
Steve French50c2f752007-07-13 00:33:32 +00001173 /* user or mount helper must uppercase
1174 the netbiosname */
1175 if (value[i] == 0)
Steve Frencha10faeb22005-08-22 21:38:31 -07001176 break;
1177 else
Steve French50c2f752007-07-13 00:33:32 +00001178 vol->target_rfc1001_name[i] =
1179 value[i];
Steve Frencha10faeb22005-08-22 21:38:31 -07001180 }
1181 /* The string has 16th byte zero still from
1182 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001183 if ((i == 15) && (value[i] != 0))
1184 printk(KERN_WARNING "CIFS: server net"
1185 "biosname longer than 15 truncated.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 }
1187 } else if (strnicmp(data, "credentials", 4) == 0) {
1188 /* ignore */
1189 } else if (strnicmp(data, "version", 3) == 0) {
1190 /* ignore */
Steve French50c2f752007-07-13 00:33:32 +00001191 } else if (strnicmp(data, "guest", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 /* ignore */
1193 } else if (strnicmp(data, "rw", 2) == 0) {
Steve French4b18f2a2008-04-29 00:06:05 +00001194 vol->rw = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 } else if ((strnicmp(data, "suid", 4) == 0) ||
1196 (strnicmp(data, "nosuid", 6) == 0) ||
1197 (strnicmp(data, "exec", 4) == 0) ||
1198 (strnicmp(data, "noexec", 6) == 0) ||
1199 (strnicmp(data, "nodev", 5) == 0) ||
1200 (strnicmp(data, "noauto", 6) == 0) ||
1201 (strnicmp(data, "dev", 3) == 0)) {
1202 /* The mount tool or mount.cifs helper (if present)
Steve French50c2f752007-07-13 00:33:32 +00001203 uses these opts to set flags, and the flags are read
1204 by the kernel vfs layer before we get here (ie
1205 before read super) so there is no point trying to
1206 parse these options again and set anything and it
1207 is ok to just ignore them */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 continue;
1209 } else if (strnicmp(data, "ro", 2) == 0) {
Steve French4b18f2a2008-04-29 00:06:05 +00001210 vol->rw = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 } else if (strnicmp(data, "hard", 4) == 0) {
1212 vol->retry = 1;
1213 } else if (strnicmp(data, "soft", 4) == 0) {
1214 vol->retry = 0;
1215 } else if (strnicmp(data, "perm", 4) == 0) {
1216 vol->noperm = 0;
1217 } else if (strnicmp(data, "noperm", 6) == 0) {
1218 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001219 } else if (strnicmp(data, "mapchars", 8) == 0) {
1220 vol->remap = 1;
1221 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1222 vol->remap = 0;
Steve French50c2f752007-07-13 00:33:32 +00001223 } else if (strnicmp(data, "sfu", 3) == 0) {
1224 vol->sfu_emul = 1;
1225 } else if (strnicmp(data, "nosfu", 5) == 0) {
1226 vol->sfu_emul = 0;
Steve French2c1b8612008-10-16 18:35:21 +00001227 } else if (strnicmp(data, "nodfs", 5) == 0) {
1228 vol->nodfs = 1;
Jeremy Allisonac670552005-06-22 17:26:35 -07001229 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1230 vol->posix_paths = 1;
1231 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1232 vol->posix_paths = 0;
Steve Frenchc18c8422007-07-18 23:21:09 +00001233 } else if (strnicmp(data, "nounix", 6) == 0) {
1234 vol->no_linux_ext = 1;
1235 } else if (strnicmp(data, "nolinux", 7) == 0) {
1236 vol->no_linux_ext = 1;
Steve French50c2f752007-07-13 00:33:32 +00001237 } else if ((strnicmp(data, "nocase", 6) == 0) ||
Steve Frencha10faeb22005-08-22 21:38:31 -07001238 (strnicmp(data, "ignorecase", 10) == 0)) {
Steve French50c2f752007-07-13 00:33:32 +00001239 vol->nocase = 1;
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001240 } else if (strnicmp(data, "brl", 3) == 0) {
1241 vol->nobrl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001242 } else if ((strnicmp(data, "nobrl", 5) == 0) ||
Steve French1c955182005-08-30 20:58:07 -07001243 (strnicmp(data, "nolock", 6) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001244 vol->nobrl = 1;
Steve Frenchd3485d32005-08-19 11:04:29 -07001245 /* turn off mandatory locking in mode
1246 if remote locking is turned off since the
1247 local vfs will do advisory */
Steve French50c2f752007-07-13 00:33:32 +00001248 if (vol->file_mode ==
1249 (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
Steve Frenchd3485d32005-08-19 11:04:29 -07001250 vol->file_mode = S_IALLUGO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 } else if (strnicmp(data, "setuids", 7) == 0) {
1252 vol->setuids = 1;
1253 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1254 vol->setuids = 0;
Jeff Laytond0a9c072008-05-12 22:23:49 +00001255 } else if (strnicmp(data, "dynperm", 7) == 0) {
1256 vol->dynperm = true;
1257 } else if (strnicmp(data, "nodynperm", 9) == 0) {
1258 vol->dynperm = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 } else if (strnicmp(data, "nohard", 6) == 0) {
1260 vol->retry = 0;
1261 } else if (strnicmp(data, "nosoft", 6) == 0) {
1262 vol->retry = 1;
1263 } else if (strnicmp(data, "nointr", 6) == 0) {
1264 vol->intr = 0;
1265 } else if (strnicmp(data, "intr", 4) == 0) {
1266 vol->intr = 1;
Steve French50c2f752007-07-13 00:33:32 +00001267 } else if (strnicmp(data, "serverino", 7) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 vol->server_ino = 1;
Steve French50c2f752007-07-13 00:33:32 +00001269 } else if (strnicmp(data, "noserverino", 9) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 vol->server_ino = 0;
Steve French50c2f752007-07-13 00:33:32 +00001271 } else if (strnicmp(data, "cifsacl", 7) == 0) {
Steve French0a4b92c2006-01-12 15:44:21 -08001272 vol->cifs_acl = 1;
1273 } else if (strnicmp(data, "nocifsacl", 9) == 0) {
1274 vol->cifs_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001275 } else if (strnicmp(data, "acl", 3) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 vol->no_psx_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001277 } else if (strnicmp(data, "noacl", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 vol->no_psx_acl = 1;
Steve French84210e92008-10-23 04:42:37 +00001279#ifdef CONFIG_CIFS_EXPERIMENTAL
1280 } else if (strnicmp(data, "locallease", 6) == 0) {
1281 vol->local_lease = 1;
1282#endif
Steve French50c2f752007-07-13 00:33:32 +00001283 } else if (strnicmp(data, "sign", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +00001284 vol->secFlg |= CIFSSEC_MUST_SIGN;
Steve French95b1cb92008-05-15 16:44:38 +00001285 } else if (strnicmp(data, "seal", 4) == 0) {
1286 /* we do not do the following in secFlags because seal
1287 is a per tree connection (mount) not a per socket
1288 or per-smb connection option in the protocol */
1289 /* vol->secFlg |= CIFSSEC_MUST_SEAL; */
1290 vol->seal = 1;
Steve French50c2f752007-07-13 00:33:32 +00001291 } else if (strnicmp(data, "direct", 6) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001293 } else if (strnicmp(data, "forcedirectio", 13) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001295 } else if (strnicmp(data, "in6_addr", 8) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 if (!value || !*value) {
1297 vol->in6_addr = NULL;
1298 } else if (strnlen(value, 49) == 48) {
1299 vol->in6_addr = value;
1300 } else {
Steve French50c2f752007-07-13 00:33:32 +00001301 printk(KERN_WARNING "CIFS: ip v6 address not "
1302 "48 characters long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 return 1;
1304 }
1305 } else if (strnicmp(data, "noac", 4) == 0) {
Steve French50c2f752007-07-13 00:33:32 +00001306 printk(KERN_WARNING "CIFS: Mount option noac not "
1307 "supported. Instead set "
1308 "/proc/fs/cifs/LookupCacheEnabled to 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 } else
Steve French50c2f752007-07-13 00:33:32 +00001310 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",
1311 data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 }
1313 if (vol->UNC == NULL) {
Steve French4523cc32007-04-30 20:13:06 +00001314 if (devname == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001315 printk(KERN_WARNING "CIFS: Missing UNC name for mount "
1316 "target\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 return 1;
1318 }
1319 if ((temp_len = strnlen(devname, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001320 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001321 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001323 strcpy(vol->UNC, devname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 if (strncmp(vol->UNC, "//", 2) == 0) {
1325 vol->UNC[0] = '\\';
1326 vol->UNC[1] = '\\';
1327 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Steve French50c2f752007-07-13 00:33:32 +00001328 printk(KERN_WARNING "CIFS: UNC Path does not "
1329 "begin with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 return 1;
1331 }
Igor Mammedov7c5e6282008-05-08 20:48:42 +00001332 value = strpbrk(vol->UNC+2, "/\\");
1333 if (value)
1334 *value = '\\';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 } else {
1336 printk(KERN_WARNING "CIFS: UNC name too long\n");
1337 return 1;
1338 }
1339 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001340 if (vol->UNCip == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 vol->UNCip = &vol->UNC[2];
1342
1343 return 0;
1344}
1345
1346static struct cifsSesInfo *
Steve French50c2f752007-07-13 00:33:32 +00001347cifs_find_tcp_session(struct in_addr *target_ip_addr,
Cyrill Gorcunov1b20d672008-05-09 18:17:21 +00001348 struct in6_addr *target_ip6_addr,
1349 char *userName, struct TCP_Server_Info **psrvTcp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350{
1351 struct list_head *tmp;
1352 struct cifsSesInfo *ses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353
Cyrill Gorcunov1b20d672008-05-09 18:17:21 +00001354 *psrvTcp = NULL;
1355
1356 read_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 list_for_each(tmp, &GlobalSMBSessionList) {
1358 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
Cyrill Gorcunov1b20d672008-05-09 18:17:21 +00001359 if (!ses->server)
1360 continue;
Steve French50c2f752007-07-13 00:33:32 +00001361
Cyrill Gorcunov1b20d672008-05-09 18:17:21 +00001362 if (target_ip_addr &&
1363 ses->server->addr.sockAddr.sin_addr.s_addr != target_ip_addr->s_addr)
1364 continue;
1365 else if (target_ip6_addr &&
1366 memcmp(&ses->server->addr.sockAddr6.sin6_addr,
1367 target_ip6_addr, sizeof(*target_ip6_addr)))
1368 continue;
Jeff Layton02eadef2008-05-09 21:26:11 +00001369 /* BB lock server and tcp session; increment use count here?? */
Steve French50c2f752007-07-13 00:33:32 +00001370
Cyrill Gorcunov1b20d672008-05-09 18:17:21 +00001371 /* found a match on the TCP session */
1372 *psrvTcp = ses->server;
1373
1374 /* BB check if reconnection needed */
1375 if (strncmp(ses->userName, userName, MAX_USERNAME_SIZE) == 0) {
1376 read_unlock(&GlobalSMBSeslock);
1377 /* Found exact match on both TCP and
1378 SMB sessions */
1379 return ses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 }
1381 /* else tcp and smb sessions need reconnection */
1382 }
1383 read_unlock(&GlobalSMBSeslock);
Cyrill Gorcunov1b20d672008-05-09 18:17:21 +00001384
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 return NULL;
1386}
1387
1388static struct cifsTconInfo *
1389find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
1390{
1391 struct list_head *tmp;
1392 struct cifsTconInfo *tcon;
Steve Frenchdea570e02008-05-06 22:05:51 +00001393 __be32 old_ip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394
1395 read_lock(&GlobalSMBSeslock);
Steve Frenchdea570e02008-05-06 22:05:51 +00001396
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 list_for_each(tmp, &GlobalTreeConnectionList) {
Steve Frenche466e482006-08-15 13:07:18 +00001398 cFYI(1, ("Next tcon"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
Steve Frenchdea570e02008-05-06 22:05:51 +00001400 if (!tcon->ses || !tcon->ses->server)
1401 continue;
1402
1403 old_ip = tcon->ses->server->addr.sockAddr.sin_addr.s_addr;
1404 cFYI(1, ("old ip addr: %x == new ip %x ?",
1405 old_ip, new_target_ip_addr));
1406
1407 if (old_ip != new_target_ip_addr)
1408 continue;
1409
1410 /* BB lock tcon, server, tcp session and increment use count? */
1411 /* found a match on the TCP session */
1412 /* BB check if reconnection needed */
1413 cFYI(1, ("IP match, old UNC: %s new: %s",
1414 tcon->treeName, uncName));
1415
1416 if (strncmp(tcon->treeName, uncName, MAX_TREE_SIZE))
1417 continue;
1418
1419 cFYI(1, ("and old usr: %s new: %s",
1420 tcon->treeName, uncName));
1421
1422 if (strncmp(tcon->ses->userName, userName, MAX_USERNAME_SIZE))
1423 continue;
1424
1425 /* matched smb session (user name) */
1426 read_unlock(&GlobalSMBSeslock);
1427 return tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 }
Steve Frenchdea570e02008-05-06 22:05:51 +00001429
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 read_unlock(&GlobalSMBSeslock);
1431 return NULL;
1432}
1433
1434int
Steve French50c2f752007-07-13 00:33:32 +00001435get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
1436 const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
Steve French366781c2008-01-25 10:12:41 +00001437 struct dfs_info3_param **preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438{
1439 char *temp_unc;
1440 int rc = 0;
1441
1442 *pnum_referrals = 0;
Steve French366781c2008-01-25 10:12:41 +00001443 *preferrals = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444
1445 if (pSesInfo->ipc_tid == 0) {
1446 temp_unc = kmalloc(2 /* for slashes */ +
Steve French50c2f752007-07-13 00:33:32 +00001447 strnlen(pSesInfo->serverName,
1448 SERVER_NAME_LEN_WITH_NULL * 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 + 1 + 4 /* slash IPC$ */ + 2,
1450 GFP_KERNEL);
1451 if (temp_unc == NULL)
1452 return -ENOMEM;
1453 temp_unc[0] = '\\';
1454 temp_unc[1] = '\\';
1455 strcpy(temp_unc + 2, pSesInfo->serverName);
1456 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1457 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1458 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00001459 ("CIFS Tcon rc = %d ipc_tid = %d", rc, pSesInfo->ipc_tid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 kfree(temp_unc);
1461 }
1462 if (rc == 0)
Steve Frenchc2cf07d2008-05-15 06:20:02 +00001463 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001464 pnum_referrals, nls_codepage, remap);
Steve French366781c2008-01-25 10:12:41 +00001465 /* BB map targetUNCs to dfs_info3 structures, here or
1466 in CIFSGetDFSRefer BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467
1468 return rc;
1469}
1470
Jeff Layton09e50d52008-07-23 10:11:19 -04001471#ifdef CONFIG_DEBUG_LOCK_ALLOC
1472static struct lock_class_key cifs_key[2];
1473static struct lock_class_key cifs_slock_key[2];
1474
1475static inline void
1476cifs_reclassify_socket4(struct socket *sock)
1477{
1478 struct sock *sk = sock->sk;
1479 BUG_ON(sock_owned_by_user(sk));
1480 sock_lock_init_class_and_name(sk, "slock-AF_INET-CIFS",
1481 &cifs_slock_key[0], "sk_lock-AF_INET-CIFS", &cifs_key[0]);
1482}
1483
1484static inline void
1485cifs_reclassify_socket6(struct socket *sock)
1486{
1487 struct sock *sk = sock->sk;
1488 BUG_ON(sock_owned_by_user(sk));
1489 sock_lock_init_class_and_name(sk, "slock-AF_INET6-CIFS",
1490 &cifs_slock_key[1], "sk_lock-AF_INET6-CIFS", &cifs_key[1]);
1491}
1492#else
1493static inline void
1494cifs_reclassify_socket4(struct socket *sock)
1495{
1496}
1497
1498static inline void
1499cifs_reclassify_socket6(struct socket *sock)
1500{
1501}
1502#endif
1503
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504/* See RFC1001 section 14 on representation of Netbios names */
Steve French50c2f752007-07-13 00:33:32 +00001505static void rfc1002mangle(char *target, char *source, unsigned int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506{
Steve French50c2f752007-07-13 00:33:32 +00001507 unsigned int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508
Steve French50c2f752007-07-13 00:33:32 +00001509 for (i = 0, j = 0; i < (length); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 /* mask a nibble at a time and encode */
1511 target[j] = 'A' + (0x0F & (source[i] >> 4));
1512 target[j+1] = 'A' + (0x0F & source[i]);
Steve French50c2f752007-07-13 00:33:32 +00001513 j += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 }
1515
1516}
1517
1518
1519static int
Steve French50c2f752007-07-13 00:33:32 +00001520ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
1521 char *netbios_name, char *target_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522{
1523 int rc = 0;
1524 int connected = 0;
1525 __be16 orig_port = 0;
1526
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001527 if (*csocket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001528 rc = sock_create_kern(PF_INET, SOCK_STREAM,
1529 IPPROTO_TCP, csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001531 cERROR(1, ("Error %d creating socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 *csocket = NULL;
1533 return rc;
1534 } else {
1535 /* BB other socket options to set KEEPALIVE, NODELAY? */
Steve French467a8f82007-06-27 22:41:32 +00001536 cFYI(1, ("Socket created"));
Steve French50c2f752007-07-13 00:33:32 +00001537 (*csocket)->sk->sk_allocation = GFP_NOFS;
Jeff Layton09e50d52008-07-23 10:11:19 -04001538 cifs_reclassify_socket4(*csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 }
1540 }
1541
1542 psin_server->sin_family = AF_INET;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001543 if (psin_server->sin_port) { /* user overrode default port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 rc = (*csocket)->ops->connect(*csocket,
1545 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001546 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 if (rc >= 0)
1548 connected = 1;
Steve French50c2f752007-07-13 00:33:32 +00001549 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001551 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001552 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 later if fall back ports fail this time */
1554 orig_port = psin_server->sin_port;
1555
1556 /* do not retry on the same port we just failed on */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001557 if (psin_server->sin_port != htons(CIFS_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 psin_server->sin_port = htons(CIFS_PORT);
1559
1560 rc = (*csocket)->ops->connect(*csocket,
1561 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001562 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 if (rc >= 0)
1564 connected = 1;
1565 }
1566 }
1567 if (!connected) {
1568 psin_server->sin_port = htons(RFC1001_PORT);
1569 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
Steve French50c2f752007-07-13 00:33:32 +00001570 psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001571 sizeof(struct sockaddr_in), 0);
Steve French50c2f752007-07-13 00:33:32 +00001572 if (rc >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 connected = 1;
1574 }
1575
1576 /* give up here - unless we want to retry on different
1577 protocol families some day */
1578 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001579 if (orig_port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 psin_server->sin_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001581 cFYI(1, ("Error %d connecting to server via ipv4", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 sock_release(*csocket);
1583 *csocket = NULL;
1584 return rc;
1585 }
Steve French50c2f752007-07-13 00:33:32 +00001586 /* Eventually check for other socket options to change from
1587 the default. sock_setsockopt not used because it expects
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 user space buffer */
Steve French50c2f752007-07-13 00:33:32 +00001589 cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",
1590 (*csocket)->sk->sk_sndbuf,
Steve Frenchb387eae2005-10-10 14:21:15 -07001591 (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchb387eae2005-10-10 14:21:15 -07001593 /* make the bufsizes depend on wsize/rsize and max requests */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001594 if ((*csocket)->sk->sk_sndbuf < (200 * 1024))
Steve Frenchb387eae2005-10-10 14:21:15 -07001595 (*csocket)->sk->sk_sndbuf = 200 * 1024;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001596 if ((*csocket)->sk->sk_rcvbuf < (140 * 1024))
Steve Frenchb387eae2005-10-10 14:21:15 -07001597 (*csocket)->sk->sk_rcvbuf = 140 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598
1599 /* send RFC1001 sessinit */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001600 if (psin_server->sin_port == htons(RFC1001_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 /* some servers require RFC1001 sessinit before sending
Steve French50c2f752007-07-13 00:33:32 +00001602 negprot - BB check reconnection in case where second
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 sessinit is sent but no second negprot */
Steve French50c2f752007-07-13 00:33:32 +00001604 struct rfc1002_session_packet *ses_init_buf;
1605 struct smb_hdr *smb_buf;
1606 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
1607 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001608 if (ses_init_buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 ses_init_buf->trailer.session_req.called_len = 32;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001610 if (target_name && (target_name[0] != 0)) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001611 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1612 target_name, 16);
1613 } else {
1614 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
Steve French50c2f752007-07-13 00:33:32 +00001615 DEFAULT_CIFS_CALLED_NAME, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001616 }
1617
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 ses_init_buf->trailer.session_req.calling_len = 32;
1619 /* calling name ends in null (byte 16) from old smb
1620 convention. */
Steve French50c2f752007-07-13 00:33:32 +00001621 if (netbios_name && (netbios_name[0] != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
Steve French50c2f752007-07-13 00:33:32 +00001623 netbios_name, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 } else {
1625 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
Steve French50c2f752007-07-13 00:33:32 +00001626 "LINUX_CIFS_CLNT", 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 }
1628 ses_init_buf->trailer.session_req.scope1 = 0;
1629 ses_init_buf->trailer.session_req.scope2 = 0;
1630 smb_buf = (struct smb_hdr *)ses_init_buf;
1631 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1632 smb_buf->smb_buf_length = 0x81000044;
1633 rc = smb_send(*csocket, smb_buf, 0x44,
1634 (struct sockaddr *)psin_server);
1635 kfree(ses_init_buf);
Steve French50c2f752007-07-13 00:33:32 +00001636 msleep(1); /* RFC1001 layer in at least one server
Steve French083d3a22006-03-03 09:53:36 +00001637 requires very short break before negprot
1638 presumably because not expecting negprot
1639 to follow so fast. This is a simple
Steve French50c2f752007-07-13 00:33:32 +00001640 solution that works without
Steve French083d3a22006-03-03 09:53:36 +00001641 complicating the code and causes no
1642 significant slowing down on mount
1643 for everyone else */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 }
Steve French50c2f752007-07-13 00:33:32 +00001645 /* else the negprot may still work without this
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 even though malloc failed */
Steve French50c2f752007-07-13 00:33:32 +00001647
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 }
Steve French50c2f752007-07-13 00:33:32 +00001649
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 return rc;
1651}
1652
1653static int
1654ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1655{
1656 int rc = 0;
1657 int connected = 0;
1658 __be16 orig_port = 0;
1659
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001660 if (*csocket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001661 rc = sock_create_kern(PF_INET6, SOCK_STREAM,
1662 IPPROTO_TCP, csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001664 cERROR(1, ("Error %d creating ipv6 socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 *csocket = NULL;
1666 return rc;
1667 } else {
1668 /* BB other socket options to set KEEPALIVE, NODELAY? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001669 cFYI(1, ("ipv6 Socket created"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 (*csocket)->sk->sk_allocation = GFP_NOFS;
Jeff Layton09e50d52008-07-23 10:11:19 -04001671 cifs_reclassify_socket6(*csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 }
1673 }
1674
1675 psin_server->sin6_family = AF_INET6;
1676
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001677 if (psin_server->sin6_port) { /* user overrode default port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 rc = (*csocket)->ops->connect(*csocket,
1679 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001680 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 if (rc >= 0)
1682 connected = 1;
Steve French50c2f752007-07-13 00:33:32 +00001683 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001685 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001686 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 later if fall back ports fail this time */
1688
1689 orig_port = psin_server->sin6_port;
1690 /* do not retry on the same port we just failed on */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001691 if (psin_server->sin6_port != htons(CIFS_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 psin_server->sin6_port = htons(CIFS_PORT);
1693
1694 rc = (*csocket)->ops->connect(*csocket,
1695 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001696 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 if (rc >= 0)
1698 connected = 1;
1699 }
1700 }
1701 if (!connected) {
1702 psin_server->sin6_port = htons(RFC1001_PORT);
1703 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001704 psin_server, sizeof(struct sockaddr_in6), 0);
Steve French50c2f752007-07-13 00:33:32 +00001705 if (rc >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 connected = 1;
1707 }
1708
1709 /* give up here - unless we want to retry on different
1710 protocol families some day */
1711 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001712 if (orig_port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 psin_server->sin6_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001714 cFYI(1, ("Error %d connecting to server via ipv6", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 sock_release(*csocket);
1716 *csocket = NULL;
1717 return rc;
1718 }
Steve French50c2f752007-07-13 00:33:32 +00001719 /* Eventually check for other socket options to change from
1720 the default. sock_setsockopt not used because it expects
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 user space buffer */
1722 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve French50c2f752007-07-13 00:33:32 +00001723
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 return rc;
1725}
1726
Steve French50c2f752007-07-13 00:33:32 +00001727void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
1728 struct super_block *sb, struct smb_vol *vol_info)
Steve French8af18972007-02-14 04:42:51 +00001729{
1730 /* if we are reconnecting then should we check to see if
1731 * any requested capabilities changed locally e.g. via
1732 * remount but we can not do much about it here
1733 * if they have (even if we could detect it by the following)
1734 * Perhaps we could add a backpointer to array of sb from tcon
1735 * or if we change to make all sb to same share the same
1736 * sb as NFS - then we only have one backpointer to sb.
1737 * What if we wanted to mount the server share twice once with
1738 * and once without posixacls or posix paths? */
1739 __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001740
Steve Frenchc18c8422007-07-18 23:21:09 +00001741 if (vol_info && vol_info->no_linux_ext) {
1742 tcon->fsUnixInfo.Capability = 0;
1743 tcon->unix_ext = 0; /* Unix Extensions disabled */
1744 cFYI(1, ("Linux protocol extensions disabled"));
1745 return;
1746 } else if (vol_info)
1747 tcon->unix_ext = 1; /* Unix Extensions supported */
1748
1749 if (tcon->unix_ext == 0) {
1750 cFYI(1, ("Unix extensions disabled so not set on reconnect"));
1751 return;
1752 }
Steve French50c2f752007-07-13 00:33:32 +00001753
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001754 if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
Steve French8af18972007-02-14 04:42:51 +00001755 __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001756
Steve French8af18972007-02-14 04:42:51 +00001757 /* check for reconnect case in which we do not
1758 want to change the mount behavior if we can avoid it */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001759 if (vol_info == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001760 /* turn off POSIX ACL and PATHNAMES if not set
Steve French8af18972007-02-14 04:42:51 +00001761 originally at mount time */
1762 if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
1763 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00001764 if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
1765 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
1766 cERROR(1, ("POSIXPATH support change"));
Steve French8af18972007-02-14 04:42:51 +00001767 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00001768 } else if ((cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
1769 cERROR(1, ("possible reconnect error"));
1770 cERROR(1,
1771 ("server disabled POSIX path support"));
1772 }
Steve French8af18972007-02-14 04:42:51 +00001773 }
Steve French50c2f752007-07-13 00:33:32 +00001774
Steve French8af18972007-02-14 04:42:51 +00001775 cap &= CIFS_UNIX_CAP_MASK;
Steve French75865f8c2007-06-24 18:30:48 +00001776 if (vol_info && vol_info->no_psx_acl)
Steve French8af18972007-02-14 04:42:51 +00001777 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00001778 else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001779 cFYI(1, ("negotiated posix acl support"));
1780 if (sb)
Steve French8af18972007-02-14 04:42:51 +00001781 sb->s_flags |= MS_POSIXACL;
1782 }
1783
Steve French75865f8c2007-06-24 18:30:48 +00001784 if (vol_info && vol_info->posix_paths == 0)
Steve French8af18972007-02-14 04:42:51 +00001785 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00001786 else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001787 cFYI(1, ("negotiate posix pathnames"));
Steve French75865f8c2007-06-24 18:30:48 +00001788 if (sb)
Steve French50c2f752007-07-13 00:33:32 +00001789 CIFS_SB(sb)->mnt_cifs_flags |=
Steve French8af18972007-02-14 04:42:51 +00001790 CIFS_MOUNT_POSIX_PATHS;
1791 }
Steve French50c2f752007-07-13 00:33:32 +00001792
Steve French984acfe2007-04-26 16:42:50 +00001793 /* We might be setting the path sep back to a different
1794 form if we are reconnecting and the server switched its
Steve French50c2f752007-07-13 00:33:32 +00001795 posix path capability for this share */
Steve French75865f8c2007-06-24 18:30:48 +00001796 if (sb && (CIFS_SB(sb)->prepathlen > 0))
Steve French984acfe2007-04-26 16:42:50 +00001797 CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
Steve French75865f8c2007-06-24 18:30:48 +00001798
1799 if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
1800 if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
1801 CIFS_SB(sb)->rsize = 127 * 1024;
Steve French90c81e02008-02-12 20:32:36 +00001802 cFYI(DBG2,
1803 ("larger reads not supported by srv"));
Steve French75865f8c2007-06-24 18:30:48 +00001804 }
1805 }
Steve French50c2f752007-07-13 00:33:32 +00001806
1807
1808 cFYI(1, ("Negotiate caps 0x%x", (int)cap));
Steve French8af18972007-02-14 04:42:51 +00001809#ifdef CONFIG_CIFS_DEBUG2
Steve French75865f8c2007-06-24 18:30:48 +00001810 if (cap & CIFS_UNIX_FCNTL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001811 cFYI(1, ("FCNTL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001812 if (cap & CIFS_UNIX_EXTATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001813 cFYI(1, ("EXTATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001814 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001815 cFYI(1, ("POSIX path cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001816 if (cap & CIFS_UNIX_XATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001817 cFYI(1, ("XATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001818 if (cap & CIFS_UNIX_POSIX_ACL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001819 cFYI(1, ("POSIX ACL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001820 if (cap & CIFS_UNIX_LARGE_READ_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001821 cFYI(1, ("very large read cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001822 if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001823 cFYI(1, ("very large write cap"));
Steve French8af18972007-02-14 04:42:51 +00001824#endif /* CIFS_DEBUG2 */
1825 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
Steve French442aa312007-09-24 20:25:46 +00001826 if (vol_info == NULL) {
Steve French5a44b312007-09-20 15:16:24 +00001827 cFYI(1, ("resetting capabilities failed"));
Steve French442aa312007-09-24 20:25:46 +00001828 } else
Steve French5a44b312007-09-20 15:16:24 +00001829 cERROR(1, ("Negotiating Unix capabilities "
1830 "with the server failed. Consider "
1831 "mounting with the Unix Extensions\n"
1832 "disabled, if problems are found, "
1833 "by specifying the nounix mount "
Steve French2224f4e2007-09-20 15:37:29 +00001834 "option."));
Steve French5a44b312007-09-20 15:16:24 +00001835
Steve French8af18972007-02-14 04:42:51 +00001836 }
1837 }
1838}
1839
Steve French03a143c2008-02-14 06:38:30 +00001840static void
1841convert_delimiter(char *path, char delim)
1842{
1843 int i;
Steve Frenchc2d68ea2008-02-15 19:20:18 +00001844 char old_delim;
Steve French03a143c2008-02-14 06:38:30 +00001845
1846 if (path == NULL)
1847 return;
1848
Steve French582d21e2008-05-13 04:54:12 +00001849 if (delim == '/')
Steve Frenchc2d68ea2008-02-15 19:20:18 +00001850 old_delim = '\\';
1851 else
1852 old_delim = '/';
1853
Steve French03a143c2008-02-14 06:38:30 +00001854 for (i = 0; path[i] != '\0'; i++) {
Steve Frenchc2d68ea2008-02-15 19:20:18 +00001855 if (path[i] == old_delim)
Steve French03a143c2008-02-14 06:38:30 +00001856 path[i] = delim;
1857 }
1858}
1859
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -04001860static void
1861kill_cifsd(struct TCP_Server_Info *server)
1862{
1863 struct task_struct *task;
1864
1865 task = xchg(&server->tsk, NULL);
1866 if (task)
1867 force_sig(SIGKILL, task);
1868}
1869
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870int
1871cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1872 char *mount_data, const char *devname)
1873{
1874 int rc = 0;
1875 int xid;
1876 int address_type = AF_INET;
1877 struct socket *csocket = NULL;
1878 struct sockaddr_in sin_server;
1879 struct sockaddr_in6 sin_server6;
1880 struct smb_vol volume_info;
1881 struct cifsSesInfo *pSesInfo = NULL;
1882 struct cifsSesInfo *existingCifsSes = NULL;
1883 struct cifsTconInfo *tcon = NULL;
1884 struct TCP_Server_Info *srvTcp = NULL;
1885
1886 xid = GetXid();
1887
1888/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
Steve French50c2f752007-07-13 00:33:32 +00001889
1890 memset(&volume_info, 0, sizeof(struct smb_vol));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001892 rc = -EINVAL;
1893 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 }
1895
Jeff Layton8426c392007-05-05 03:27:49 +00001896 if (volume_info.nullauth) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001897 cFYI(1, ("null user"));
Jeff Layton9b8f5f52007-11-09 23:25:04 +00001898 volume_info.username = "";
Jeff Layton8426c392007-05-05 03:27:49 +00001899 } else if (volume_info.username) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900 /* BB fixme parse for domain name here */
Steve French467a8f82007-06-27 22:41:32 +00001901 cFYI(1, ("Username: %s", volume_info.username));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902 } else {
Steve Frenchbf820672005-12-01 22:32:42 -08001903 cifserror("No username specified");
Steve French50c2f752007-07-13 00:33:32 +00001904 /* In userspace mount helper we can get user name from alternate
1905 locations such as env variables and files on disk */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001906 rc = -EINVAL;
1907 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 }
1909
1910 if (volume_info.UNCip && volume_info.UNC) {
Steve French50c2f752007-07-13 00:33:32 +00001911 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,
1912 &sin_server.sin_addr.s_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001914 if (rc <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 /* not ipv4 address, try ipv6 */
Steve French50c2f752007-07-13 00:33:32 +00001916 rc = cifs_inet_pton(AF_INET6, volume_info.UNCip,
1917 &sin_server6.sin6_addr.in6_u);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001918 if (rc > 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 address_type = AF_INET6;
1920 } else {
1921 address_type = AF_INET;
1922 }
Steve French50c2f752007-07-13 00:33:32 +00001923
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001924 if (rc <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 /* we failed translating address */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001926 rc = -EINVAL;
1927 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 }
1929
1930 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1931 /* success */
1932 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00001933 } else if (volume_info.UNCip) {
1934 /* BB using ip addr as server name to connect to the
1935 DFS root below */
1936 cERROR(1, ("Connecting to DFS root not implemented yet"));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001937 rc = -EINVAL;
1938 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 } else /* which servers DFS root would we conect to */ {
1940 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00001941 ("CIFS mount error: No UNC path (e.g. -o "
1942 "unc=//192.168.1.100/public) specified"));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001943 rc = -EINVAL;
1944 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 }
1946
1947 /* this is needed for ASCII cp to Unicode converts */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001948 if (volume_info.iocharset == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 cifs_sb->local_nls = load_nls_default();
1950 /* load_nls_default can not return null */
1951 } else {
1952 cifs_sb->local_nls = load_nls(volume_info.iocharset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001953 if (cifs_sb->local_nls == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001954 cERROR(1, ("CIFS mount error: iocharset %s not found",
1955 volume_info.iocharset));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001956 rc = -ELIBACC;
1957 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 }
1959 }
1960
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001961 if (address_type == AF_INET)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1963 NULL /* no ipv6 addr */,
1964 volume_info.username, &srvTcp);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001965 else if (address_type == AF_INET6) {
1966 cFYI(1, ("looking for ipv6 address"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1968 &sin_server6.sin6_addr,
1969 volume_info.username, &srvTcp);
Steve French5858ae42007-04-25 11:59:10 +00001970 } else {
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001971 rc = -EINVAL;
1972 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 }
1974
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975 if (srvTcp) {
Steve French50c2f752007-07-13 00:33:32 +00001976 cFYI(1, ("Existing tcp session with server found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 } else { /* create socket */
Steve French4523cc32007-04-30 20:13:06 +00001978 if (volume_info.port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 sin_server.sin_port = htons(volume_info.port);
1980 else
1981 sin_server.sin_port = 0;
Steve French5858ae42007-04-25 11:59:10 +00001982 if (address_type == AF_INET6) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001983 cFYI(1, ("attempting ipv6 connect"));
Steve French5858ae42007-04-25 11:59:10 +00001984 /* BB should we allow ipv6 on port 139? */
1985 /* other OS never observed in Wild doing 139 with v6 */
Steve French50c2f752007-07-13 00:33:32 +00001986 rc = ipv6_connect(&sin_server6, &csocket);
1987 } else
1988 rc = ipv4_connect(&sin_server, &csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -07001989 volume_info.source_rfc1001_name,
1990 volume_info.target_rfc1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001992 cERROR(1, ("Error connecting to IPv4 socket. "
1993 "Aborting operation"));
Steve French4523cc32007-04-30 20:13:06 +00001994 if (csocket != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 sock_release(csocket);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001996 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 }
1998
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00001999 srvTcp = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
2000 if (!srvTcp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 rc = -ENOMEM;
2002 sock_release(csocket);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002003 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 } else {
Steve French50c2f752007-07-13 00:33:32 +00002005 memcpy(&srvTcp->addr.sockAddr, &sin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002006 sizeof(struct sockaddr_in));
Steve French50c2f752007-07-13 00:33:32 +00002007 atomic_set(&srvTcp->inFlight, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 /* BB Add code for ipv6 case too */
2009 srvTcp->ssocket = csocket;
2010 srvTcp->protocolType = IPV4;
Jeff Laytonc359cf32007-11-16 22:22:06 +00002011 srvTcp->hostname = extract_hostname(volume_info.UNC);
2012 if (IS_ERR(srvTcp->hostname)) {
2013 rc = PTR_ERR(srvTcp->hostname);
2014 sock_release(csocket);
2015 goto out;
2016 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 init_waitqueue_head(&srvTcp->response_q);
2018 init_waitqueue_head(&srvTcp->request_q);
2019 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
2020 /* at this point we are the only ones with the pointer
2021 to the struct since the kernel thread not created yet
2022 so no need to spinlock this init of tcpStatus */
2023 srvTcp->tcpStatus = CifsNew;
2024 init_MUTEX(&srvTcp->tcpSem);
Igor Mammedovaaf737a2007-04-03 19:16:43 +00002025 srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd");
Steve French8840dee2007-11-16 23:05:52 +00002026 if (IS_ERR(srvTcp->tsk)) {
Igor Mammedovaaf737a2007-04-03 19:16:43 +00002027 rc = PTR_ERR(srvTcp->tsk);
Steve French50c2f752007-07-13 00:33:32 +00002028 cERROR(1, ("error %d create cifsd thread", rc));
Igor Mammedovaaf737a2007-04-03 19:16:43 +00002029 srvTcp->tsk = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030 sock_release(csocket);
Jeff Laytonc359cf32007-11-16 22:22:06 +00002031 kfree(srvTcp->hostname);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002032 goto out;
Steve Frenchf1914012005-08-18 09:37:34 -07002033 }
Steve Frenchf1914012005-08-18 09:37:34 -07002034 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002035 memcpy(srvTcp->workstation_RFC1001_name,
2036 volume_info.source_rfc1001_name, 16);
2037 memcpy(srvTcp->server_RFC1001_name,
2038 volume_info.target_rfc1001_name, 16);
Steve Frenchad009ac2005-04-28 22:41:05 -07002039 srvTcp->sequence_number = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 }
2041 }
2042
2043 if (existingCifsSes) {
2044 pSesInfo = existingCifsSes;
Jeff Layton1d9a8852007-12-31 01:37:11 +00002045 cFYI(1, ("Existing smb sess found (status=%d)",
2046 pSesInfo->status));
Steve French88e7d702008-01-03 17:37:09 +00002047 down(&pSesInfo->sesSem);
Jeff Layton1d9a8852007-12-31 01:37:11 +00002048 if (pSesInfo->status == CifsNeedReconnect) {
2049 cFYI(1, ("Session needs reconnect"));
Jeff Layton1d9a8852007-12-31 01:37:11 +00002050 rc = cifs_setup_session(xid, pSesInfo,
2051 cifs_sb->local_nls);
Jeff Layton1d9a8852007-12-31 01:37:11 +00002052 }
Steve French88e7d702008-01-03 17:37:09 +00002053 up(&pSesInfo->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 } else if (!rc) {
Steve Frenchbf820672005-12-01 22:32:42 -08002055 cFYI(1, ("Existing smb sess not found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056 pSesInfo = sesInfoAlloc();
2057 if (pSesInfo == NULL)
2058 rc = -ENOMEM;
2059 else {
2060 pSesInfo->server = srvTcp;
2061 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
2062 NIPQUAD(sin_server.sin_addr.s_addr));
2063 }
2064
Steve French50c2f752007-07-13 00:33:32 +00002065 if (!rc) {
2066 /* volume_info.password freed at unmount */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002067 if (volume_info.password) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 pSesInfo->password = volume_info.password;
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002069 /* set to NULL to prevent freeing on exit */
2070 volume_info.password = NULL;
2071 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072 if (volume_info.username)
2073 strncpy(pSesInfo->userName,
Steve French50c2f752007-07-13 00:33:32 +00002074 volume_info.username,
2075 MAX_USERNAME_SIZE);
Steve French39798772006-05-31 22:40:51 +00002076 if (volume_info.domainname) {
2077 int len = strlen(volume_info.domainname);
Steve French50c2f752007-07-13 00:33:32 +00002078 pSesInfo->domainName =
Steve French39798772006-05-31 22:40:51 +00002079 kmalloc(len + 1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00002080 if (pSesInfo->domainName)
Steve French39798772006-05-31 22:40:51 +00002081 strcpy(pSesInfo->domainName,
2082 volume_info.domainname);
2083 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084 pSesInfo->linux_uid = volume_info.linux_uid;
Steve French750d1152006-06-27 06:28:30 +00002085 pSesInfo->overrideSecFlg = volume_info.secFlg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086 down(&pSesInfo->sesSem);
Steve French189acaa2006-06-23 02:33:48 +00002087 /* BB FIXME need to pass vol->secFlgs BB */
Steve French50c2f752007-07-13 00:33:32 +00002088 rc = cifs_setup_session(xid, pSesInfo,
2089 cifs_sb->local_nls);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090 up(&pSesInfo->sesSem);
Steve French4523cc32007-04-30 20:13:06 +00002091 if (!rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092 atomic_inc(&srvTcp->socketUseCount);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002093 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 }
Steve French50c2f752007-07-13 00:33:32 +00002095
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 /* search for existing tcon to this server share */
2097 if (!rc) {
Steve French4523cc32007-04-30 20:13:06 +00002098 if (volume_info.rsize > CIFSMaxBufSize) {
Steve French50c2f752007-07-13 00:33:32 +00002099 cERROR(1, ("rsize %d too large, using MaxBufSize",
Steve French0ae0efa2005-10-10 10:57:19 -07002100 volume_info.rsize));
2101 cifs_sb->rsize = CIFSMaxBufSize;
Steve French75865f8c2007-06-24 18:30:48 +00002102 } else if ((volume_info.rsize) &&
2103 (volume_info.rsize <= CIFSMaxBufSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104 cifs_sb->rsize = volume_info.rsize;
Steve French0ae0efa2005-10-10 10:57:19 -07002105 else /* default */
2106 cifs_sb->rsize = CIFSMaxBufSize;
2107
Steve French4523cc32007-04-30 20:13:06 +00002108 if (volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
Steve French50c2f752007-07-13 00:33:32 +00002109 cERROR(1, ("wsize %d too large, using 4096 instead",
Steve French0ae0efa2005-10-10 10:57:19 -07002110 volume_info.wsize));
2111 cifs_sb->wsize = 4096;
Steve French4523cc32007-04-30 20:13:06 +00002112 } else if (volume_info.wsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 cifs_sb->wsize = volume_info.wsize;
2114 else
Steve French50c2f752007-07-13 00:33:32 +00002115 cifs_sb->wsize =
Steve French1877c9e2006-01-27 18:36:11 -08002116 min_t(const int, PAGEVEC_SIZE * PAGE_CACHE_SIZE,
2117 127*1024);
Steve French17cbbaf2006-01-24 20:26:48 -08002118 /* old default of CIFSMaxBufSize was too small now
Steve French50c2f752007-07-13 00:33:32 +00002119 that SMB Write2 can send multiple pages in kvec.
Steve French17cbbaf2006-01-24 20:26:48 -08002120 RFC1001 does not describe what happens when frame
2121 bigger than 128K is sent so use that as max in
2122 conjunction with 52K kvec constraint on arch with 4K
2123 page size */
2124
Steve French4523cc32007-04-30 20:13:06 +00002125 if (cifs_sb->rsize < 2048) {
Steve French50c2f752007-07-13 00:33:32 +00002126 cifs_sb->rsize = 2048;
Steve French6cec2ae2006-02-22 17:31:52 -06002127 /* Windows ME may prefer this */
Steve French467a8f82007-06-27 22:41:32 +00002128 cFYI(1, ("readsize set to minimum: 2048"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129 }
Steve French2fe87f02006-09-21 07:02:52 +00002130 /* calculate prepath */
2131 cifs_sb->prepath = volume_info.prepath;
Steve French4523cc32007-04-30 20:13:06 +00002132 if (cifs_sb->prepath) {
Steve French2fe87f02006-09-21 07:02:52 +00002133 cifs_sb->prepathlen = strlen(cifs_sb->prepath);
Steve French03a143c2008-02-14 06:38:30 +00002134 /* we can not convert the / to \ in the path
2135 separators in the prefixpath yet because we do not
2136 know (until reset_cifs_unix_caps is called later)
2137 whether POSIX PATH CAP is available. We normalize
2138 the / to \ after reset_cifs_unix_caps is called */
Steve French2fe87f02006-09-21 07:02:52 +00002139 volume_info.prepath = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002140 } else
Steve French2fe87f02006-09-21 07:02:52 +00002141 cifs_sb->prepathlen = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142 cifs_sb->mnt_uid = volume_info.linux_uid;
2143 cifs_sb->mnt_gid = volume_info.linux_gid;
2144 cifs_sb->mnt_file_mode = volume_info.file_mode;
2145 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
Steve French467a8f82007-06-27 22:41:32 +00002146 cFYI(1, ("file mode: 0x%x dir mode: 0x%x",
2147 cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148
Steve French4523cc32007-04-30 20:13:06 +00002149 if (volume_info.noperm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
Steve French4523cc32007-04-30 20:13:06 +00002151 if (volume_info.setuids)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
Steve French4523cc32007-04-30 20:13:06 +00002153 if (volume_info.server_ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
Steve French4523cc32007-04-30 20:13:06 +00002155 if (volume_info.remap)
Steve French6a0b4822005-04-28 22:41:05 -07002156 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
Steve French4523cc32007-04-30 20:13:06 +00002157 if (volume_info.no_xattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
Steve French4523cc32007-04-30 20:13:06 +00002159 if (volume_info.sfu_emul)
Steve Frenchd7245c22005-07-14 18:25:12 -05002160 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
Steve French4523cc32007-04-30 20:13:06 +00002161 if (volume_info.nobrl)
Steve Frenchc46fa8a2005-08-18 20:49:57 -07002162 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Steve French4523cc32007-04-30 20:13:06 +00002163 if (volume_info.cifs_acl)
Steve French0a4b92c2006-01-12 15:44:21 -08002164 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
Steve French4523cc32007-04-30 20:13:06 +00002165 if (volume_info.override_uid)
2166 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
2167 if (volume_info.override_gid)
2168 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
Jeff Laytond0a9c072008-05-12 22:23:49 +00002169 if (volume_info.dynperm)
2170 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
Steve French4523cc32007-04-30 20:13:06 +00002171 if (volume_info.direct_io) {
Steve French467a8f82007-06-27 22:41:32 +00002172 cFYI(1, ("mounting share using direct i/o"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
2174 }
2175
Steve French27adb442008-05-23 19:43:29 +00002176 if ((volume_info.cifs_acl) && (volume_info.dynperm))
2177 cERROR(1, ("mount option dynperm ignored if cifsacl "
2178 "mount option supported"));
2179
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180 tcon =
2181 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
2182 volume_info.username);
2183 if (tcon) {
Steve Frenchbf820672005-12-01 22:32:42 -08002184 cFYI(1, ("Found match on UNC path"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185 /* we can have only one retry value for a connection
2186 to a share so for resources mounted more than once
Steve French50c2f752007-07-13 00:33:32 +00002187 to the same server share the last value passed in
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188 for the retry flag is used */
2189 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07002190 tcon->nocase = volume_info.nocase;
Steve French84210e92008-10-23 04:42:37 +00002191 tcon->local_lease = volume_info.local_lease;
Steve French95b1cb92008-05-15 16:44:38 +00002192 if (tcon->seal != volume_info.seal)
2193 cERROR(1, ("transport encryption setting "
2194 "conflicts with existing tid"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 } else {
2196 tcon = tconInfoAlloc();
2197 if (tcon == NULL)
2198 rc = -ENOMEM;
2199 else {
Steve French50c2f752007-07-13 00:33:32 +00002200 /* check for null share name ie connecting to
Steve French8af18972007-02-14 04:42:51 +00002201 * dfs root */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202
Steve French50c2f752007-07-13 00:33:32 +00002203 /* BB check if this works for exactly length
Steve French8af18972007-02-14 04:42:51 +00002204 * three strings */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
2206 && (strchr(volume_info.UNC + 3, '/') ==
2207 NULL)) {
Steve French646dd532008-05-15 01:50:56 +00002208/* rc = connect_to_dfs_path(xid, pSesInfo,
Steve French8af18972007-02-14 04:42:51 +00002209 "", cifs_sb->local_nls,
Steve French50c2f752007-07-13 00:33:32 +00002210 cifs_sb->mnt_cifs_flags &
Steve French646dd532008-05-15 01:50:56 +00002211 CIFS_MOUNT_MAP_SPECIAL_CHR);*/
2212 cFYI(1, ("DFS root not supported"));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002213 rc = -ENODEV;
2214 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 } else {
Steve French8af18972007-02-14 04:42:51 +00002216 /* BB Do we need to wrap sesSem around
2217 * this TCon call and Unix SetFS as
2218 * we do on SessSetup and reconnect? */
Steve French50c2f752007-07-13 00:33:32 +00002219 rc = CIFSTCon(xid, pSesInfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 volume_info.UNC,
2221 tcon, cifs_sb->local_nls);
2222 cFYI(1, ("CIFS Tcon rc = %d", rc));
Steve French2c1b8612008-10-16 18:35:21 +00002223 if (volume_info.nodfs) {
2224 tcon->Flags &=
2225 ~SMB_SHARE_IS_IN_DFS;
2226 cFYI(1, ("DFS disabled (%d)",
2227 tcon->Flags));
2228 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 }
2230 if (!rc) {
2231 atomic_inc(&pSesInfo->inUse);
2232 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07002233 tcon->nocase = volume_info.nocase;
Steve French95b1cb92008-05-15 16:44:38 +00002234 tcon->seal = volume_info.seal;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235 }
2236 }
2237 }
2238 }
Steve French4523cc32007-04-30 20:13:06 +00002239 if (pSesInfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
2241 sb->s_maxbytes = (u64) 1 << 63;
2242 } else
2243 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
2244 }
2245
Steve French8af18972007-02-14 04:42:51 +00002246 /* BB FIXME fix time_gran to be larger for LANMAN sessions */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 sb->s_time_gran = 100;
2248
2249/* on error free sesinfo and tcon struct if needed */
2250 if (rc) {
2251 /* if session setup failed, use count is zero but
2252 we still need to free cifsd thread */
Steve French4523cc32007-04-30 20:13:06 +00002253 if (atomic_read(&srvTcp->socketUseCount) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 spin_lock(&GlobalMid_Lock);
2255 srvTcp->tcpStatus = CifsExiting;
2256 spin_unlock(&GlobalMid_Lock);
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -04002257 kill_cifsd(srvTcp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 }
2259 /* If find_unc succeeded then rc == 0 so we can not end */
2260 if (tcon) /* up accidently freeing someone elses tcon struct */
2261 tconInfoFree(tcon);
2262 if (existingCifsSes == NULL) {
2263 if (pSesInfo) {
Steve French50c2f752007-07-13 00:33:32 +00002264 if ((pSesInfo->server) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265 (pSesInfo->status == CifsGood)) {
2266 int temp_rc;
2267 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
2268 /* if the socketUseCount is now zero */
Steve French4523cc32007-04-30 20:13:06 +00002269 if ((temp_rc == -ESHUTDOWN) &&
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -04002270 (pSesInfo->server))
2271 kill_cifsd(pSesInfo->server);
Steve Frencha0136892007-10-04 20:05:09 +00002272 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273 cFYI(1, ("No session or bad tcon"));
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -04002274 if (pSesInfo->server) {
Jeff Layton469ee612008-10-16 18:46:39 +00002275 spin_lock(&GlobalMid_Lock);
2276 srvTcp->tcpStatus = CifsExiting;
2277 spin_unlock(&GlobalMid_Lock);
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -04002278 kill_cifsd(pSesInfo->server);
Steve Frencha0136892007-10-04 20:05:09 +00002279 }
2280 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281 sesInfoFree(pSesInfo);
2282 /* pSesInfo = NULL; */
2283 }
2284 }
2285 } else {
2286 atomic_inc(&tcon->useCount);
2287 cifs_sb->tcon = tcon;
2288 tcon->ses = pSesInfo;
2289
Steve French82940a42006-03-02 03:24:57 +00002290 /* do not care if following two calls succeed - informational */
Steve French7f8ed422007-09-28 22:28:55 +00002291 if (!tcon->ipc) {
2292 CIFSSMBQFSDeviceInfo(xid, tcon);
2293 CIFSSMBQFSAttributeInfo(xid, tcon);
2294 }
Steve French50c2f752007-07-13 00:33:32 +00002295
Steve French8af18972007-02-14 04:42:51 +00002296 /* tell server which Unix caps we support */
2297 if (tcon->ses->capabilities & CAP_UNIX)
Steve Frenchc18c8422007-07-18 23:21:09 +00002298 /* reset of caps checks mount to see if unix extensions
2299 disabled for just this mount */
Steve French8af18972007-02-14 04:42:51 +00002300 reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
Steve Frenchc18c8422007-07-18 23:21:09 +00002301 else
2302 tcon->unix_ext = 0; /* server does not support them */
2303
Steve French03a143c2008-02-14 06:38:30 +00002304 /* convert forward to back slashes in prepath here if needed */
Igor Mammedov11b6d642008-02-15 19:06:04 +00002305 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
2306 convert_delimiter(cifs_sb->prepath,
2307 CIFS_DIR_SEP(cifs_sb));
Steve French03a143c2008-02-14 06:38:30 +00002308
Steve Frenchc18c8422007-07-18 23:21:09 +00002309 if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
Steve French75865f8c2007-06-24 18:30:48 +00002310 cifs_sb->rsize = 1024 * 127;
Steve French90c81e02008-02-12 20:32:36 +00002311 cFYI(DBG2,
2312 ("no very large read support, rsize now 127K"));
Steve French75865f8c2007-06-24 18:30:48 +00002313 }
Steve French3e844692005-10-03 13:37:24 -07002314 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
2315 cifs_sb->wsize = min(cifs_sb->wsize,
2316 (tcon->ses->server->maxBuf -
2317 MAX_CIFS_HDR_SIZE));
Steve French0ae0efa2005-10-10 10:57:19 -07002318 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
Steve French50c2f752007-07-13 00:33:32 +00002319 cifs_sb->rsize = min(cifs_sb->rsize,
2320 (tcon->ses->server->maxBuf -
2321 MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322 }
2323
2324 /* volume_info.password is freed above when existing session found
2325 (in which case it is not needed anymore) but when new sesion is created
2326 the password ptr is put in the new session structure (in which case the
2327 password will be freed at unmount time) */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002328out:
2329 /* zero out password before freeing */
2330 if (volume_info.password != NULL) {
2331 memset(volume_info.password, 0, strlen(volume_info.password));
2332 kfree(volume_info.password);
2333 }
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002334 kfree(volume_info.UNC);
Steve French2fe87f02006-09-21 07:02:52 +00002335 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336 FreeXid(xid);
2337 return rc;
2338}
2339
2340static int
2341CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French7c7b25b2006-06-01 19:20:10 +00002342 char session_key[CIFS_SESS_KEY_SIZE],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343 const struct nls_table *nls_codepage)
2344{
2345 struct smb_hdr *smb_buffer;
2346 struct smb_hdr *smb_buffer_response;
2347 SESSION_SETUP_ANDX *pSMB;
2348 SESSION_SETUP_ANDX *pSMBr;
2349 char *bcc_ptr;
2350 char *user;
2351 char *domain;
2352 int rc = 0;
2353 int remaining_words = 0;
2354 int bytes_returned = 0;
2355 int len;
2356 __u32 capabilities;
2357 __u16 count;
2358
Steve Frencheeac8042006-01-13 21:34:58 -08002359 cFYI(1, ("In sesssetup"));
Steve French4523cc32007-04-30 20:13:06 +00002360 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361 return -EINVAL;
2362 user = ses->userName;
2363 domain = ses->domainName;
2364 smb_buffer = cifs_buf_get();
Steve French582d21e2008-05-13 04:54:12 +00002365
2366 if (smb_buffer == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367 return -ENOMEM;
Steve French582d21e2008-05-13 04:54:12 +00002368
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369 smb_buffer_response = smb_buffer;
2370 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2371
2372 /* send SMBsessionSetup here */
2373 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2374 NULL /* no tCon exists yet */ , 13 /* wct */ );
2375
Steve French1982c342005-08-17 12:38:22 -07002376 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377 pSMB->req_no_secext.AndXCommand = 0xFF;
2378 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2379 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2380
Steve French50c2f752007-07-13 00:33:32 +00002381 if (ses->server->secMode &
2382 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2384
2385 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2386 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
2387 if (ses->capabilities & CAP_UNICODE) {
2388 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2389 capabilities |= CAP_UNICODE;
2390 }
2391 if (ses->capabilities & CAP_STATUS32) {
2392 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2393 capabilities |= CAP_STATUS32;
2394 }
2395 if (ses->capabilities & CAP_DFS) {
2396 smb_buffer->Flags2 |= SMBFLG2_DFS;
2397 capabilities |= CAP_DFS;
2398 }
2399 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
2400
Steve French50c2f752007-07-13 00:33:32 +00002401 pSMB->req_no_secext.CaseInsensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002402 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403
2404 pSMB->req_no_secext.CaseSensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002405 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406 bcc_ptr = pByteArea(smb_buffer);
Steve French7c7b25b2006-06-01 19:20:10 +00002407 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2408 bcc_ptr += CIFS_SESS_KEY_SIZE;
2409 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2410 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411
2412 if (ses->capabilities & CAP_UNICODE) {
2413 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
2414 *bcc_ptr = 0;
2415 bcc_ptr++;
2416 }
Steve French4523cc32007-04-30 20:13:06 +00002417 if (user == NULL)
Steve French39798772006-05-31 22:40:51 +00002418 bytes_returned = 0; /* skip null user */
Steve French50c2f752007-07-13 00:33:32 +00002419 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420 bytes_returned =
Steve French50c2f752007-07-13 00:33:32 +00002421 cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 nls_codepage);
2423 /* convert number of 16 bit words to bytes */
2424 bcc_ptr += 2 * bytes_returned;
2425 bcc_ptr += 2; /* trailing null */
2426 if (domain == NULL)
2427 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002428 cifs_strtoUCS((__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429 "CIFS_LINUX_DOM", 32, nls_codepage);
2430 else
2431 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002432 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433 nls_codepage);
2434 bcc_ptr += 2 * bytes_returned;
2435 bcc_ptr += 2;
2436 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002437 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438 32, nls_codepage);
2439 bcc_ptr += 2 * bytes_returned;
2440 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002441 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 32, nls_codepage);
2443 bcc_ptr += 2 * bytes_returned;
2444 bcc_ptr += 2;
2445 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002446 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447 64, nls_codepage);
2448 bcc_ptr += 2 * bytes_returned;
2449 bcc_ptr += 2;
2450 } else {
Steve French50c2f752007-07-13 00:33:32 +00002451 if (user != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452 strncpy(bcc_ptr, user, 200);
2453 bcc_ptr += strnlen(user, 200);
2454 }
2455 *bcc_ptr = 0;
2456 bcc_ptr++;
2457 if (domain == NULL) {
2458 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2459 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2460 } else {
2461 strncpy(bcc_ptr, domain, 64);
2462 bcc_ptr += strnlen(domain, 64);
2463 *bcc_ptr = 0;
2464 bcc_ptr++;
2465 }
2466 strcpy(bcc_ptr, "Linux version ");
2467 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002468 strcpy(bcc_ptr, utsname()->release);
2469 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2471 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2472 }
2473 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2474 smb_buffer->smb_buf_length += count;
2475 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2476
2477 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00002478 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479 if (rc) {
2480/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2481 } else if ((smb_buffer_response->WordCount == 3)
2482 || (smb_buffer_response->WordCount == 4)) {
2483 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2484 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2485 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002486 cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */
2487 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format
2488 (little endian) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489 cFYI(1, ("UID = %d ", ses->Suid));
Steve French50c2f752007-07-13 00:33:32 +00002490 /* response can have either 3 or 4 word count - Samba sends 3 */
2491 bcc_ptr = pByteArea(smb_buffer_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 if ((pSMBr->resp.hdr.WordCount == 3)
2493 || ((pSMBr->resp.hdr.WordCount == 4)
2494 && (blob_len < pSMBr->resp.ByteCount))) {
2495 if (pSMBr->resp.hdr.WordCount == 4)
2496 bcc_ptr += blob_len;
2497
2498 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2499 if ((long) (bcc_ptr) % 2) {
2500 remaining_words =
Steve French50c2f752007-07-13 00:33:32 +00002501 (BCC(smb_buffer_response) - 1) / 2;
2502 /* Unicode strings must be word
2503 aligned */
2504 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505 } else {
2506 remaining_words =
2507 BCC(smb_buffer_response) / 2;
2508 }
2509 len =
2510 UniStrnlen((wchar_t *) bcc_ptr,
2511 remaining_words - 1);
2512/* We look for obvious messed up bcc or strings in response so we do not go off
2513 the end since (at least) WIN2K and Windows XP have a major bug in not null
2514 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002515 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002516 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002517 ses->serverOS = kzalloc(2 * (len + 1),
2518 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002519 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002520 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 cifs_strfromUCS_le(ses->serverOS,
Steve French50c2f752007-07-13 00:33:32 +00002522 (__le16 *)bcc_ptr,
2523 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524 bcc_ptr += 2 * (len + 1);
2525 remaining_words -= len + 1;
2526 ses->serverOS[2 * len] = 0;
2527 ses->serverOS[1 + (2 * len)] = 0;
2528 if (remaining_words > 0) {
2529 len = UniStrnlen((wchar_t *)bcc_ptr,
2530 remaining_words-1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002531 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002532 ses->serverNOS = kzalloc(2 * (len + 1),
2533 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002534 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002535 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536 cifs_strfromUCS_le(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002537 (__le16 *)bcc_ptr,
2538 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539 bcc_ptr += 2 * (len + 1);
2540 ses->serverNOS[2 * len] = 0;
2541 ses->serverNOS[1 + (2 * len)] = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002542 if (strncmp(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002543 "NT LAN Manager 4", 16) == 0) {
Steve French467a8f82007-06-27 22:41:32 +00002544 cFYI(1, ("NT4 server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545 ses->flags |= CIFS_SES_NT4;
2546 }
2547 remaining_words -= len + 1;
2548 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002549 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Steve French50c2f752007-07-13 00:33:32 +00002550 /* last string is not always null terminated
2551 (for e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002552 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002553 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554 ses->serverDomain =
Steve French50c2f752007-07-13 00:33:32 +00002555 kzalloc(2*(len+1),
2556 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002557 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002558 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559 cifs_strfromUCS_le(ses->serverDomain,
Steve French50c2f752007-07-13 00:33:32 +00002560 (__le16 *)bcc_ptr,
2561 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562 bcc_ptr += 2 * (len + 1);
2563 ses->serverDomain[2*len] = 0;
2564 ses->serverDomain[1+(2*len)] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002565 } else { /* else no more room so create
2566 dummy domain string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002567 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002568 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002569 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002570 kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002571 }
Steve French50c2f752007-07-13 00:33:32 +00002572 } else { /* no room so create dummy domain
2573 and NOS string */
2574
Steve French433dc242005-04-28 22:41:08 -07002575 /* if these kcallocs fail not much we
2576 can do, but better to not fail the
2577 sesssetup itself */
Steve Frenchcd49b492006-06-26 04:22:36 +00002578 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002580 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002581 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002583 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584 }
2585 } else { /* ASCII */
2586 len = strnlen(bcc_ptr, 1024);
2587 if (((long) bcc_ptr + len) - (long)
2588 pByteArea(smb_buffer_response)
2589 <= BCC(smb_buffer_response)) {
Steve Frenchcd49b492006-06-26 04:22:36 +00002590 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002591 ses->serverOS = kzalloc(len + 1,
2592 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002593 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002594 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002595 strncpy(ses->serverOS, bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596
2597 bcc_ptr += len;
Steve French50c2f752007-07-13 00:33:32 +00002598 /* null terminate the string */
2599 bcc_ptr[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600 bcc_ptr++;
2601
2602 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002603 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002604 ses->serverNOS = kzalloc(len + 1,
2605 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002606 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002607 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 strncpy(ses->serverNOS, bcc_ptr, len);
2609 bcc_ptr += len;
2610 bcc_ptr[0] = 0;
2611 bcc_ptr++;
2612
2613 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002614 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002615 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002616 ses->serverDomain = kzalloc(len + 1,
2617 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002618 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002619 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002620 strncpy(ses->serverDomain, bcc_ptr,
2621 len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622 bcc_ptr += len;
2623 bcc_ptr[0] = 0;
2624 bcc_ptr++;
2625 } else
2626 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00002627 ("Variable field of length %d "
2628 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629 len));
2630 }
2631 } else {
2632 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00002633 (" Security Blob Length extends beyond "
2634 "end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 }
2636 } else {
2637 cERROR(1,
2638 (" Invalid Word count %d: ",
2639 smb_buffer_response->WordCount));
2640 rc = -EIO;
2641 }
Steve French433dc242005-04-28 22:41:08 -07002642sesssetup_nomem: /* do not return an error on nomem for the info strings,
2643 since that could make reconnection harder, and
2644 reconnection might be needed to free memory */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00002645 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646
2647 return rc;
2648}
2649
2650static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
Steve French4b18f2a2008-04-29 00:06:05 +00002652 struct cifsSesInfo *ses, bool *pNTLMv2_flag,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 const struct nls_table *nls_codepage)
2654{
2655 struct smb_hdr *smb_buffer;
2656 struct smb_hdr *smb_buffer_response;
2657 SESSION_SETUP_ANDX *pSMB;
2658 SESSION_SETUP_ANDX *pSMBr;
2659 char *bcc_ptr;
2660 char *domain;
2661 int rc = 0;
2662 int remaining_words = 0;
2663 int bytes_returned = 0;
2664 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002665 int SecurityBlobLength = sizeof(NEGOTIATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666 PNEGOTIATE_MESSAGE SecurityBlob;
2667 PCHALLENGE_MESSAGE SecurityBlob2;
2668 __u32 negotiate_flags, capabilities;
2669 __u16 count;
2670
Steve French12b3b8f2006-02-09 21:12:47 +00002671 cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002672 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673 return -EINVAL;
2674 domain = ses->domainName;
Steve French4b18f2a2008-04-29 00:06:05 +00002675 *pNTLMv2_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676 smb_buffer = cifs_buf_get();
2677 if (smb_buffer == NULL) {
2678 return -ENOMEM;
2679 }
2680 smb_buffer_response = smb_buffer;
2681 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2682 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2683
2684 /* send SMBsessionSetup here */
2685 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2686 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002687
2688 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2690 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2691
2692 pSMB->req.AndXCommand = 0xFF;
2693 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2694 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2695
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002696 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2698
2699 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2700 CAP_EXTENDED_SECURITY;
2701 if (ses->capabilities & CAP_UNICODE) {
2702 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2703 capabilities |= CAP_UNICODE;
2704 }
2705 if (ses->capabilities & CAP_STATUS32) {
2706 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2707 capabilities |= CAP_STATUS32;
2708 }
2709 if (ses->capabilities & CAP_DFS) {
2710 smb_buffer->Flags2 |= SMBFLG2_DFS;
2711 capabilities |= CAP_DFS;
2712 }
2713 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2714
2715 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2716 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2717 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2718 SecurityBlob->MessageType = NtLmNegotiate;
2719 negotiate_flags =
2720 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
Steve French12b3b8f2006-02-09 21:12:47 +00002721 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
2722 NTLMSSP_NEGOTIATE_56 |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002724 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002726/* if (ntlmv2_support)
Steve French39798772006-05-31 22:40:51 +00002727 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728 /* setup pointers to domain name and workstation name */
2729 bcc_ptr += SecurityBlobLength;
2730
2731 SecurityBlob->WorkstationName.Buffer = 0;
2732 SecurityBlob->WorkstationName.Length = 0;
2733 SecurityBlob->WorkstationName.MaximumLength = 0;
2734
Steve French12b3b8f2006-02-09 21:12:47 +00002735 /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent
2736 along with username on auth request (ie the response to challenge) */
2737 SecurityBlob->DomainName.Buffer = 0;
2738 SecurityBlob->DomainName.Length = 0;
2739 SecurityBlob->DomainName.MaximumLength = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740 if (ses->capabilities & CAP_UNICODE) {
2741 if ((long) bcc_ptr % 2) {
2742 *bcc_ptr = 0;
2743 bcc_ptr++;
2744 }
2745
2746 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002747 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 32, nls_codepage);
2749 bcc_ptr += 2 * bytes_returned;
2750 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002751 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 nls_codepage);
2753 bcc_ptr += 2 * bytes_returned;
2754 bcc_ptr += 2; /* null terminate Linux version */
2755 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002756 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 64, nls_codepage);
2758 bcc_ptr += 2 * bytes_returned;
2759 *(bcc_ptr + 1) = 0;
2760 *(bcc_ptr + 2) = 0;
2761 bcc_ptr += 2; /* null terminate network opsys string */
2762 *(bcc_ptr + 1) = 0;
2763 *(bcc_ptr + 2) = 0;
2764 bcc_ptr += 2; /* null domain */
2765 } else { /* ASCII */
2766 strcpy(bcc_ptr, "Linux version ");
2767 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002768 strcpy(bcc_ptr, utsname()->release);
2769 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2771 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2772 bcc_ptr++; /* empty domain field */
2773 *bcc_ptr = 0;
2774 }
2775 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2776 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2777 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2778 smb_buffer->smb_buf_length += count;
2779 pSMB->req.ByteCount = cpu_to_le16(count);
2780
2781 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00002782 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783
2784 if (smb_buffer_response->Status.CifsError ==
2785 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2786 rc = 0;
2787
2788 if (rc) {
2789/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2790 } else if ((smb_buffer_response->WordCount == 3)
2791 || (smb_buffer_response->WordCount == 4)) {
2792 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2793 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2794
2795 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002796 cFYI(1, (" Guest login"));
2797 /* Do we want to set anything in SesInfo struct when guest login? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798
Steve French50c2f752007-07-13 00:33:32 +00002799 bcc_ptr = pByteArea(smb_buffer_response);
2800 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801
2802 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2803 if (SecurityBlob2->MessageType != NtLmChallenge) {
2804 cFYI(1,
2805 ("Unexpected NTLMSSP message type received %d",
2806 SecurityBlob2->MessageType));
2807 } else if (ses) {
Steve French50c2f752007-07-13 00:33:32 +00002808 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
Steve French12b3b8f2006-02-09 21:12:47 +00002809 cFYI(1, ("UID = %d", ses->Suid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 if ((pSMBr->resp.hdr.WordCount == 3)
2811 || ((pSMBr->resp.hdr.WordCount == 4)
2812 && (blob_len <
2813 pSMBr->resp.ByteCount))) {
2814
2815 if (pSMBr->resp.hdr.WordCount == 4) {
2816 bcc_ptr += blob_len;
Steve French12b3b8f2006-02-09 21:12:47 +00002817 cFYI(1, ("Security Blob Length %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818 blob_len));
2819 }
2820
Steve French12b3b8f2006-02-09 21:12:47 +00002821 cFYI(1, ("NTLMSSP Challenge rcvd"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822
2823 memcpy(ses->server->cryptKey,
2824 SecurityBlob2->Challenge,
2825 CIFS_CRYPTO_KEY_SIZE);
Steve French50c2f752007-07-13 00:33:32 +00002826 if (SecurityBlob2->NegotiateFlags &
Steve French12b3b8f2006-02-09 21:12:47 +00002827 cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
Steve French4b18f2a2008-04-29 00:06:05 +00002828 *pNTLMv2_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829
Steve French50c2f752007-07-13 00:33:32 +00002830 if ((SecurityBlob2->NegotiateFlags &
2831 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 || (sign_CIFS_PDUs > 1))
Steve French50c2f752007-07-13 00:33:32 +00002833 ses->server->secMode |=
2834 SECMODE_SIGN_REQUIRED;
2835 if ((SecurityBlob2->NegotiateFlags &
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
Steve French50c2f752007-07-13 00:33:32 +00002837 ses->server->secMode |=
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838 SECMODE_SIGN_ENABLED;
2839
2840 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2841 if ((long) (bcc_ptr) % 2) {
2842 remaining_words =
2843 (BCC(smb_buffer_response)
2844 - 1) / 2;
Steve French50c2f752007-07-13 00:33:32 +00002845 /* Must word align unicode strings */
2846 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847 } else {
2848 remaining_words =
2849 BCC
2850 (smb_buffer_response) / 2;
2851 }
2852 len =
2853 UniStrnlen((wchar_t *) bcc_ptr,
2854 remaining_words - 1);
2855/* We look for obvious messed up bcc or strings in response so we do not go off
2856 the end since (at least) WIN2K and Windows XP have a major bug in not null
2857 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002858 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002859 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002861 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002863 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864 bcc_ptr, len,
2865 nls_codepage);
2866 bcc_ptr += 2 * (len + 1);
2867 remaining_words -= len + 1;
2868 ses->serverOS[2 * len] = 0;
2869 ses->serverOS[1 + (2 * len)] = 0;
2870 if (remaining_words > 0) {
2871 len = UniStrnlen((wchar_t *)
2872 bcc_ptr,
2873 remaining_words
2874 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002875 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002877 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878 GFP_KERNEL);
2879 cifs_strfromUCS_le(ses->
2880 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002881 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882 bcc_ptr,
2883 len,
2884 nls_codepage);
2885 bcc_ptr += 2 * (len + 1);
2886 ses->serverNOS[2 * len] = 0;
2887 ses->serverNOS[1 +
2888 (2 * len)] = 0;
2889 remaining_words -= len + 1;
2890 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00002891 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2892 /* last string not always null terminated
2893 (for e.g. for Windows XP & 2000) */
Steve Frenchcd49b492006-06-26 04:22:36 +00002894 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002896 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897 (len +
2898 1),
2899 GFP_KERNEL);
2900 cifs_strfromUCS_le
Steve Frenche89dc922005-11-11 15:18:19 -08002901 (ses->serverDomain,
2902 (__le16 *)bcc_ptr,
2903 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904 bcc_ptr +=
2905 2 * (len + 1);
Steve Frenche89dc922005-11-11 15:18:19 -08002906 ses->serverDomain[2*len]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907 = 0;
Steve Frenche89dc922005-11-11 15:18:19 -08002908 ses->serverDomain
2909 [1 + (2 * len)]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910 = 0;
2911 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002912 else {
Steve Frenchcd49b492006-06-26 04:22:36 +00002913 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002915 kzalloc(2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916 GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002917 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918 } else { /* no room so create dummy domain and NOS string */
Steve Frenchcd49b492006-06-26 04:22:36 +00002919 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002921 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002922 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002924 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925 }
2926 } else { /* ASCII */
2927 len = strnlen(bcc_ptr, 1024);
2928 if (((long) bcc_ptr + len) - (long)
2929 pByteArea(smb_buffer_response)
2930 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002931 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002932 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002934 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935 GFP_KERNEL);
2936 strncpy(ses->serverOS,
2937 bcc_ptr, len);
2938
2939 bcc_ptr += len;
2940 bcc_ptr[0] = 0; /* null terminate string */
2941 bcc_ptr++;
2942
2943 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002944 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002946 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947 GFP_KERNEL);
2948 strncpy(ses->serverNOS, bcc_ptr, len);
2949 bcc_ptr += len;
2950 bcc_ptr[0] = 0;
2951 bcc_ptr++;
2952
2953 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002954 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002956 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +00002958 strncpy(ses->serverDomain,
2959 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 bcc_ptr += len;
2961 bcc_ptr[0] = 0;
2962 bcc_ptr++;
2963 } else
2964 cFYI(1,
Steve French63135e02007-07-17 17:34:02 +00002965 ("field of length %d "
2966 "extends beyond end of smb",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967 len));
2968 }
2969 } else {
Steve French50c2f752007-07-13 00:33:32 +00002970 cERROR(1, ("Security Blob Length extends beyond"
2971 " end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972 }
2973 } else {
2974 cERROR(1, ("No session structure passed in."));
2975 }
2976 } else {
2977 cERROR(1,
Steve French5815449d2006-02-14 01:36:20 +00002978 (" Invalid Word count %d:",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979 smb_buffer_response->WordCount));
2980 rc = -EIO;
2981 }
2982
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00002983 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984
2985 return rc;
2986}
2987static int
2988CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French4b18f2a2008-04-29 00:06:05 +00002989 char *ntlm_session_key, bool ntlmv2_flag,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002990 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991{
2992 struct smb_hdr *smb_buffer;
2993 struct smb_hdr *smb_buffer_response;
2994 SESSION_SETUP_ANDX *pSMB;
2995 SESSION_SETUP_ANDX *pSMBr;
2996 char *bcc_ptr;
2997 char *user;
2998 char *domain;
2999 int rc = 0;
3000 int remaining_words = 0;
3001 int bytes_returned = 0;
3002 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003003 int SecurityBlobLength = sizeof(AUTHENTICATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004 PAUTHENTICATE_MESSAGE SecurityBlob;
3005 __u32 negotiate_flags, capabilities;
3006 __u16 count;
3007
3008 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003009 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 return -EINVAL;
3011 user = ses->userName;
3012 domain = ses->domainName;
3013 smb_buffer = cifs_buf_get();
3014 if (smb_buffer == NULL) {
3015 return -ENOMEM;
3016 }
3017 smb_buffer_response = smb_buffer;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003018 pSMB = (SESSION_SETUP_ANDX *)smb_buffer;
3019 pSMBr = (SESSION_SETUP_ANDX *)smb_buffer_response;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020
3021 /* send SMBsessionSetup here */
3022 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
3023 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07003024
3025 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
3027 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
3028 pSMB->req.AndXCommand = 0xFF;
3029 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
3030 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
3031
3032 pSMB->req.hdr.Uid = ses->Suid;
3033
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003034 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3036
3037 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003038 CAP_EXTENDED_SECURITY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039 if (ses->capabilities & CAP_UNICODE) {
3040 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3041 capabilities |= CAP_UNICODE;
3042 }
3043 if (ses->capabilities & CAP_STATUS32) {
3044 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3045 capabilities |= CAP_STATUS32;
3046 }
3047 if (ses->capabilities & CAP_DFS) {
3048 smb_buffer->Flags2 |= SMBFLG2_DFS;
3049 capabilities |= CAP_DFS;
3050 }
3051 pSMB->req.Capabilities = cpu_to_le32(capabilities);
3052
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003053 bcc_ptr = (char *)&pSMB->req.SecurityBlob;
3054 SecurityBlob = (PAUTHENTICATE_MESSAGE)bcc_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
3056 SecurityBlob->MessageType = NtLmAuthenticate;
3057 bcc_ptr += SecurityBlobLength;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003058 negotiate_flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
3059 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
3060 0x80000000 | NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003061 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003063 if (ntlmv2_flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
3065
3066/* setup pointers to domain name and workstation name */
3067
3068 SecurityBlob->WorkstationName.Buffer = 0;
3069 SecurityBlob->WorkstationName.Length = 0;
3070 SecurityBlob->WorkstationName.MaximumLength = 0;
3071 SecurityBlob->SessionKey.Length = 0;
3072 SecurityBlob->SessionKey.MaximumLength = 0;
3073 SecurityBlob->SessionKey.Buffer = 0;
3074
3075 SecurityBlob->LmChallengeResponse.Length = 0;
3076 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
3077 SecurityBlob->LmChallengeResponse.Buffer = 0;
3078
3079 SecurityBlob->NtChallengeResponse.Length =
Steve French7c7b25b2006-06-01 19:20:10 +00003080 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081 SecurityBlob->NtChallengeResponse.MaximumLength =
Steve French7c7b25b2006-06-01 19:20:10 +00003082 cpu_to_le16(CIFS_SESS_KEY_SIZE);
3083 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084 SecurityBlob->NtChallengeResponse.Buffer =
3085 cpu_to_le32(SecurityBlobLength);
Steve French7c7b25b2006-06-01 19:20:10 +00003086 SecurityBlobLength += CIFS_SESS_KEY_SIZE;
3087 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088
3089 if (ses->capabilities & CAP_UNICODE) {
3090 if (domain == NULL) {
3091 SecurityBlob->DomainName.Buffer = 0;
3092 SecurityBlob->DomainName.Length = 0;
3093 SecurityBlob->DomainName.MaximumLength = 0;
3094 } else {
Steve French77159b42007-08-31 01:10:17 +00003095 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00003097 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003099 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100 SecurityBlob->DomainName.Buffer =
3101 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003102 bcc_ptr += ln;
3103 SecurityBlobLength += ln;
3104 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105 }
3106 if (user == NULL) {
3107 SecurityBlob->UserName.Buffer = 0;
3108 SecurityBlob->UserName.Length = 0;
3109 SecurityBlob->UserName.MaximumLength = 0;
3110 } else {
Steve French77159b42007-08-31 01:10:17 +00003111 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00003113 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114 SecurityBlob->UserName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003115 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116 SecurityBlob->UserName.Buffer =
3117 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003118 bcc_ptr += ln;
3119 SecurityBlobLength += ln;
3120 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121 }
3122
Steve French63135e02007-07-17 17:34:02 +00003123 /* SecurityBlob->WorkstationName.Length =
3124 cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125 SecurityBlob->WorkstationName.Length *= 2;
Steve French63135e02007-07-17 17:34:02 +00003126 SecurityBlob->WorkstationName.MaximumLength =
3127 cpu_to_le16(SecurityBlob->WorkstationName.Length);
3128 SecurityBlob->WorkstationName.Buffer =
3129 cpu_to_le32(SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130 bcc_ptr += SecurityBlob->WorkstationName.Length;
3131 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
Steve French63135e02007-07-17 17:34:02 +00003132 SecurityBlob->WorkstationName.Length =
3133 cpu_to_le16(SecurityBlob->WorkstationName.Length); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134
3135 if ((long) bcc_ptr % 2) {
3136 *bcc_ptr = 0;
3137 bcc_ptr++;
3138 }
3139 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003140 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003141 32, nls_codepage);
3142 bcc_ptr += 2 * bytes_returned;
3143 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003144 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003145 nls_codepage);
3146 bcc_ptr += 2 * bytes_returned;
3147 bcc_ptr += 2; /* null term version string */
3148 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003149 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150 64, nls_codepage);
3151 bcc_ptr += 2 * bytes_returned;
3152 *(bcc_ptr + 1) = 0;
3153 *(bcc_ptr + 2) = 0;
3154 bcc_ptr += 2; /* null terminate network opsys string */
3155 *(bcc_ptr + 1) = 0;
3156 *(bcc_ptr + 2) = 0;
3157 bcc_ptr += 2; /* null domain */
3158 } else { /* ASCII */
3159 if (domain == NULL) {
3160 SecurityBlob->DomainName.Buffer = 0;
3161 SecurityBlob->DomainName.Length = 0;
3162 SecurityBlob->DomainName.MaximumLength = 0;
3163 } else {
Steve French77159b42007-08-31 01:10:17 +00003164 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
3166 strncpy(bcc_ptr, domain, 63);
Steve French77159b42007-08-31 01:10:17 +00003167 ln = strnlen(domain, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003169 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170 SecurityBlob->DomainName.Buffer =
3171 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003172 bcc_ptr += ln;
3173 SecurityBlobLength += ln;
3174 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003175 }
3176 if (user == NULL) {
3177 SecurityBlob->UserName.Buffer = 0;
3178 SecurityBlob->UserName.Length = 0;
3179 SecurityBlob->UserName.MaximumLength = 0;
3180 } else {
Steve French77159b42007-08-31 01:10:17 +00003181 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182 strncpy(bcc_ptr, user, 63);
Steve French77159b42007-08-31 01:10:17 +00003183 ln = strnlen(user, 64);
3184 SecurityBlob->UserName.MaximumLength = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185 SecurityBlob->UserName.Buffer =
Steve French77159b42007-08-31 01:10:17 +00003186 cpu_to_le32(SecurityBlobLength);
3187 bcc_ptr += ln;
3188 SecurityBlobLength += ln;
3189 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190 }
3191 /* BB fill in our workstation name if known BB */
3192
3193 strcpy(bcc_ptr, "Linux version ");
3194 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003195 strcpy(bcc_ptr, utsname()->release);
3196 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
3198 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
3199 bcc_ptr++; /* null domain */
3200 *bcc_ptr = 0;
3201 }
3202 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
3203 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
3204 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
3205 smb_buffer->smb_buf_length += count;
3206 pSMB->req.ByteCount = cpu_to_le16(count);
3207
3208 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00003209 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210 if (rc) {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003211/* rc = map_smb_to_linux_error(smb_buffer_response) done in SendReceive now */
3212 } else if ((smb_buffer_response->WordCount == 3) ||
3213 (smb_buffer_response->WordCount == 4)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214 __u16 action = le16_to_cpu(pSMBr->resp.Action);
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003215 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003216 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00003217 cFYI(1, (" Guest login")); /* BB Should we set anything
3218 in SesInfo struct ? */
3219/* if (SecurityBlob2->MessageType != NtLm??) {
3220 cFYI("Unexpected message type on auth response is %d"));
3221 } */
3222
Linus Torvalds1da177e2005-04-16 15:20:36 -07003223 if (ses) {
3224 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003225 ("Check challenge UID %d vs auth response UID %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226 ses->Suid, smb_buffer_response->Uid));
Steve French50c2f752007-07-13 00:33:32 +00003227 /* UID left in wire format */
3228 ses->Suid = smb_buffer_response->Uid;
3229 bcc_ptr = pByteArea(smb_buffer_response);
3230 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003231 if ((pSMBr->resp.hdr.WordCount == 3)
3232 || ((pSMBr->resp.hdr.WordCount == 4)
3233 && (blob_len <
3234 pSMBr->resp.ByteCount))) {
3235 if (pSMBr->resp.hdr.WordCount == 4) {
3236 bcc_ptr +=
3237 blob_len;
3238 cFYI(1,
3239 ("Security Blob Length %d ",
3240 blob_len));
3241 }
3242
3243 cFYI(1,
3244 ("NTLMSSP response to Authenticate "));
3245
3246 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3247 if ((long) (bcc_ptr) % 2) {
3248 remaining_words =
3249 (BCC(smb_buffer_response)
3250 - 1) / 2;
3251 bcc_ptr++; /* Unicode strings must be word aligned */
3252 } else {
3253 remaining_words = BCC(smb_buffer_response) / 2;
3254 }
Steve French77159b42007-08-31 01:10:17 +00003255 len = UniStrnlen((wchar_t *) bcc_ptr,
3256 remaining_words - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003257/* We look for obvious messed up bcc or strings in response so we do not go off
3258 the end since (at least) WIN2K and Windows XP have a major bug in not null
3259 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003260 if (ses->serverOS)
Steve French08775832006-05-30 18:08:26 +00003261 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003262 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003263 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003265 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266 bcc_ptr, len,
3267 nls_codepage);
3268 bcc_ptr += 2 * (len + 1);
3269 remaining_words -= len + 1;
3270 ses->serverOS[2 * len] = 0;
3271 ses->serverOS[1 + (2 * len)] = 0;
3272 if (remaining_words > 0) {
3273 len = UniStrnlen((wchar_t *)
3274 bcc_ptr,
3275 remaining_words
3276 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00003277 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003278 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003279 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280 GFP_KERNEL);
3281 cifs_strfromUCS_le(ses->
3282 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003283 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003284 bcc_ptr,
3285 len,
3286 nls_codepage);
3287 bcc_ptr += 2 * (len + 1);
3288 ses->serverNOS[2 * len] = 0;
3289 ses->serverNOS[1+(2*len)] = 0;
3290 remaining_words -= len + 1;
3291 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00003292 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003293 /* last string not always null terminated (e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003294 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003295 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003297 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298 (len +
3299 1),
3300 GFP_KERNEL);
3301 cifs_strfromUCS_le
3302 (ses->
3303 serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08003304 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305 bcc_ptr, len,
3306 nls_codepage);
3307 bcc_ptr +=
3308 2 * (len + 1);
3309 ses->
3310 serverDomain[2
3311 * len]
3312 = 0;
3313 ses->
3314 serverDomain[1
3315 +
3316 (2
3317 *
3318 len)]
3319 = 0;
3320 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003321 else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003322 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003323 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003324 ses->serverDomain = kzalloc(2,GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00003325 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326 } else { /* no room so create dummy domain and NOS string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003327 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003328 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003329 ses->serverDomain = kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00003330 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003331 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332 }
3333 } else { /* ASCII */
3334 len = strnlen(bcc_ptr, 1024);
Steve French50c2f752007-07-13 00:33:32 +00003335 if (((long) bcc_ptr + len) -
3336 (long) pByteArea(smb_buffer_response)
Steve French63135e02007-07-17 17:34:02 +00003337 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003338 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00003339 kfree(ses->serverOS);
Steve French77159b42007-08-31 01:10:17 +00003340 ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341 strncpy(ses->serverOS,bcc_ptr, len);
3342
3343 bcc_ptr += len;
3344 bcc_ptr[0] = 0; /* null terminate the string */
3345 bcc_ptr++;
3346
3347 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003348 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00003349 ses->serverNOS = kzalloc(len+1,
3350 GFP_KERNEL);
Steve French63135e02007-07-17 17:34:02 +00003351 strncpy(ses->serverNOS,
3352 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 bcc_ptr += len;
3354 bcc_ptr[0] = 0;
3355 bcc_ptr++;
3356
3357 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003358 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003359 kfree(ses->serverDomain);
Steve French63135e02007-07-17 17:34:02 +00003360 ses->serverDomain =
3361 kzalloc(len+1,
3362 GFP_KERNEL);
3363 strncpy(ses->serverDomain,
3364 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365 bcc_ptr += len;
3366 bcc_ptr[0] = 0;
3367 bcc_ptr++;
3368 } else
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003369 cFYI(1, ("field of length %d "
Steve French63135e02007-07-17 17:34:02 +00003370 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371 len));
3372 }
3373 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003374 cERROR(1, ("Security Blob extends beyond end "
Steve French63135e02007-07-17 17:34:02 +00003375 "of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003376 }
3377 } else {
3378 cERROR(1, ("No session structure passed in."));
3379 }
3380 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003381 cERROR(1, ("Invalid Word count %d: ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003382 smb_buffer_response->WordCount));
3383 rc = -EIO;
3384 }
3385
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003386 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387
3388 return rc;
3389}
3390
3391int
3392CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3393 const char *tree, struct cifsTconInfo *tcon,
3394 const struct nls_table *nls_codepage)
3395{
3396 struct smb_hdr *smb_buffer;
3397 struct smb_hdr *smb_buffer_response;
3398 TCONX_REQ *pSMB;
3399 TCONX_RSP *pSMBr;
3400 unsigned char *bcc_ptr;
3401 int rc = 0;
3402 int length;
3403 __u16 count;
3404
3405 if (ses == NULL)
3406 return -EIO;
3407
3408 smb_buffer = cifs_buf_get();
3409 if (smb_buffer == NULL) {
3410 return -ENOMEM;
3411 }
3412 smb_buffer_response = smb_buffer;
3413
3414 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3415 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003416
3417 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418 smb_buffer->Uid = ses->Suid;
3419 pSMB = (TCONX_REQ *) smb_buffer;
3420 pSMBr = (TCONX_RSP *) smb_buffer_response;
3421
3422 pSMB->AndXCommand = 0xFF;
3423 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424 bcc_ptr = &pSMB->Password[0];
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003425 if ((ses->server->secMode) & SECMODE_USER) {
Steve Frencheeac8042006-01-13 21:34:58 -08003426 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00003427 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08003428 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00003429 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08003430 } else {
Steve French7c7b25b2006-06-01 19:20:10 +00003431 pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08003432 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
3433 specified as required (when that support is added to
3434 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00003435 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08003436 by Samba (not sure whether other servers allow
3437 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00003438#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French50c2f752007-07-13 00:33:32 +00003439 if ((extended_security & CIFSSEC_MAY_LANMAN) &&
Steve French7c7b25b2006-06-01 19:20:10 +00003440 (ses->server->secType == LANMAN))
3441 calc_lanman_hash(ses, bcc_ptr);
3442 else
3443#endif /* CIFS_WEAK_PW_HASH */
Steve Frencheeac8042006-01-13 21:34:58 -08003444 SMBNTencrypt(ses->password,
3445 ses->server->cryptKey,
3446 bcc_ptr);
3447
Steve French7c7b25b2006-06-01 19:20:10 +00003448 bcc_ptr += CIFS_SESS_KEY_SIZE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003449 if (ses->capabilities & CAP_UNICODE) {
Steve French7c7b25b2006-06-01 19:20:10 +00003450 /* must align unicode strings */
3451 *bcc_ptr = 0; /* null byte password */
3452 bcc_ptr++;
3453 }
Steve Frencheeac8042006-01-13 21:34:58 -08003454 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003455
Steve French50c2f752007-07-13 00:33:32 +00003456 if (ses->server->secMode &
Steve Frencha878fb22006-05-30 18:04:19 +00003457 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3459
3460 if (ses->capabilities & CAP_STATUS32) {
3461 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3462 }
3463 if (ses->capabilities & CAP_DFS) {
3464 smb_buffer->Flags2 |= SMBFLG2_DFS;
3465 }
3466 if (ses->capabilities & CAP_UNICODE) {
3467 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3468 length =
Steve French50c2f752007-07-13 00:33:32 +00003469 cifs_strtoUCS((__le16 *) bcc_ptr, tree,
3470 6 /* max utf8 char length in bytes */ *
Steve Frencha878fb22006-05-30 18:04:19 +00003471 (/* server len*/ + 256 /* share len */), nls_codepage);
3472 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003473 bcc_ptr += 2; /* skip trailing null */
3474 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475 strcpy(bcc_ptr, tree);
3476 bcc_ptr += strlen(tree) + 1;
3477 }
3478 strcpy(bcc_ptr, "?????");
3479 bcc_ptr += strlen("?????");
3480 bcc_ptr += 1;
3481 count = bcc_ptr - &pSMB->Password[0];
3482 pSMB->hdr.smb_buf_length += count;
3483 pSMB->ByteCount = cpu_to_le16(count);
3484
Steve French133672e2007-11-13 22:41:37 +00003485 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
3486 CIFS_STD_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487
3488 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3489 /* above now done in SendReceive */
3490 if ((rc == 0) && (tcon != NULL)) {
3491 tcon->tidStatus = CifsGood;
3492 tcon->tid = smb_buffer_response->Tid;
3493 bcc_ptr = pByteArea(smb_buffer_response);
3494 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
Steve French50c2f752007-07-13 00:33:32 +00003495 /* skip service field (NB: this field is always ASCII) */
Steve French7f8ed422007-09-28 22:28:55 +00003496 if (length == 3) {
3497 if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') &&
3498 (bcc_ptr[2] == 'C')) {
3499 cFYI(1, ("IPC connection"));
3500 tcon->ipc = 1;
3501 }
3502 } else if (length == 2) {
3503 if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) {
3504 /* the most common case */
3505 cFYI(1, ("disk share connection"));
3506 }
3507 }
Steve French50c2f752007-07-13 00:33:32 +00003508 bcc_ptr += length + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003509 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3510 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3511 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3512 if ((bcc_ptr + (2 * length)) -
3513 pByteArea(smb_buffer_response) <=
3514 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003515 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003517 kzalloc(length + 2, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003518 if (tcon->nativeFileSystem)
3519 cifs_strfromUCS_le(
3520 tcon->nativeFileSystem,
3521 (__le16 *) bcc_ptr,
3522 length, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523 bcc_ptr += 2 * length;
3524 bcc_ptr[0] = 0; /* null terminate the string */
3525 bcc_ptr[1] = 0;
3526 bcc_ptr += 2;
3527 }
Steve French50c2f752007-07-13 00:33:32 +00003528 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003529 } else {
3530 length = strnlen(bcc_ptr, 1024);
3531 if ((bcc_ptr + length) -
3532 pByteArea(smb_buffer_response) <=
3533 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003534 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003536 kzalloc(length + 1, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003537 if (tcon->nativeFileSystem)
3538 strncpy(tcon->nativeFileSystem, bcc_ptr,
3539 length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003540 }
Steve French50c2f752007-07-13 00:33:32 +00003541 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003543 if ((smb_buffer_response->WordCount == 3) ||
Steve French1a4e15a2006-10-12 21:33:51 +00003544 (smb_buffer_response->WordCount == 7))
3545 /* field is in same location */
Steve French39798772006-05-31 22:40:51 +00003546 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3547 else
3548 tcon->Flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003549 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3550 } else if ((rc == 0) && tcon == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00003551 /* all we need to save for IPC$ connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552 ses->ipc_tid = smb_buffer_response->Tid;
3553 }
3554
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003555 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003556 return rc;
3557}
3558
3559int
3560cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3561{
3562 int rc = 0;
3563 int xid;
3564 struct cifsSesInfo *ses = NULL;
Steve French50c2f752007-07-13 00:33:32 +00003565 char *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566
3567 xid = GetXid();
3568
3569 if (cifs_sb->tcon) {
3570 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3571 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3572 if (rc == -EBUSY) {
3573 FreeXid(xid);
3574 return 0;
3575 }
Steve French5d941ca2008-04-15 18:40:48 +00003576 DeleteTconOplockQEntries(cifs_sb->tcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577 tconInfoFree(cifs_sb->tcon);
3578 if ((ses) && (ses->server)) {
3579 /* save off task so we do not refer to ses later */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580 cFYI(1, ("About to do SMBLogoff "));
3581 rc = CIFSSMBLogoff(xid, ses);
3582 if (rc == -EBUSY) {
3583 FreeXid(xid);
3584 return 0;
3585 } else if (rc == -ESHUTDOWN) {
Steve French467a8f82007-06-27 22:41:32 +00003586 cFYI(1, ("Waking up socket by sending signal"));
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -04003587 if (ses->server)
3588 kill_cifsd(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589 rc = 0;
3590 } /* else - we have an smb session
3591 left on this socket do not kill cifsd */
3592 } else
3593 cFYI(1, ("No session or bad tcon"));
3594 }
Steve French50c2f752007-07-13 00:33:32 +00003595
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596 cifs_sb->tcon = NULL;
Steve French2fe87f02006-09-21 07:02:52 +00003597 tmp = cifs_sb->prepath;
3598 cifs_sb->prepathlen = 0;
3599 cifs_sb->prepath = NULL;
3600 kfree(tmp);
Nishanth Aravamudan041e0e32005-09-10 00:27:23 -07003601 if (ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602 sesInfoFree(ses);
3603
3604 FreeXid(xid);
Steve French88e7d702008-01-03 17:37:09 +00003605 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003606}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607
3608int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
Steve French50c2f752007-07-13 00:33:32 +00003609 struct nls_table *nls_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610{
3611 int rc = 0;
Steve French7c7b25b2006-06-01 19:20:10 +00003612 char ntlm_session_key[CIFS_SESS_KEY_SIZE];
Steve French4b18f2a2008-04-29 00:06:05 +00003613 bool ntlmv2_flag = false;
Steve Frenchad009ac2005-04-28 22:41:05 -07003614 int first_time = 0;
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003615 struct TCP_Server_Info *server = pSesInfo->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616
3617 /* what if server changes its buffer size after dropping the session? */
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003618 if (server->maxBuf == 0) /* no need to send on reconnect */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003619 rc = CIFSSMBNegotiate(xid, pSesInfo);
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003620 if (rc == -EAGAIN) {
3621 /* retry only once on 1st time connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003622 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve French50c2f752007-07-13 00:33:32 +00003623 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003624 rc = -EHOSTDOWN;
3625 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003626 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627 spin_lock(&GlobalMid_Lock);
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003628 if (server->tcpStatus != CifsExiting)
3629 server->tcpStatus = CifsGood;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630 else
3631 rc = -EHOSTDOWN;
3632 spin_unlock(&GlobalMid_Lock);
3633
3634 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003635 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636 }
Steve French26b994f2008-08-06 05:11:33 +00003637
3638 if (rc)
3639 goto ss_err_exit;
3640
3641 pSesInfo->flags = 0;
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003642 pSesInfo->capabilities = server->capabilities;
Steve French26b994f2008-08-06 05:11:33 +00003643 if (linuxExtEnabled == 0)
3644 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003645 /* pSesInfo->sequence_number = 0;*/
Steve French26b994f2008-08-06 05:11:33 +00003646 cFYI(1, ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003647 server->secMode, server->capabilities, server->timeAdj));
3648
Steve French26b994f2008-08-06 05:11:33 +00003649 if (experimEnabled < 2)
3650 rc = CIFS_SessSetup(xid, pSesInfo, first_time, nls_info);
3651 else if (extended_security
3652 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003653 && (server->secType == NTLMSSP)) {
Steve French26b994f2008-08-06 05:11:33 +00003654 rc = -EOPNOTSUPP;
3655 } else if (extended_security
3656 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003657 && (server->secType == RawNTLMSSP)) {
Steve French26b994f2008-08-06 05:11:33 +00003658 cFYI(1, ("NTLMSSP sesssetup"));
3659 rc = CIFSNTLMSSPNegotiateSessSetup(xid, pSesInfo, &ntlmv2_flag,
3660 nls_info);
3661 if (!rc) {
3662 if (ntlmv2_flag) {
3663 char *v2_response;
3664 cFYI(1, ("more secure NTLM ver2 hash"));
3665 if (CalcNTLMv2_partial_mac_key(pSesInfo,
3666 nls_info)) {
3667 rc = -ENOMEM;
3668 goto ss_err_exit;
3669 } else
3670 v2_response = kmalloc(16 + 64 /* blob*/,
3671 GFP_KERNEL);
3672 if (v2_response) {
3673 CalcNTLMv2_response(pSesInfo,
3674 v2_response);
3675 /* if (first_time)
3676 cifs_calculate_ntlmv2_mac_key */
3677 kfree(v2_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678 /* BB Put dummy sig in SessSetup PDU? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003679 } else {
Steve French26b994f2008-08-06 05:11:33 +00003680 rc = -ENOMEM;
3681 goto ss_err_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003682 }
Steve French26b994f2008-08-06 05:11:33 +00003683
3684 } else {
3685 SMBNTencrypt(pSesInfo->password,
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003686 server->cryptKey,
Steve French26b994f2008-08-06 05:11:33 +00003687 ntlm_session_key);
3688
3689 if (first_time)
3690 cifs_calculate_mac_key(
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003691 &server->mac_signing_key,
Steve French26b994f2008-08-06 05:11:33 +00003692 ntlm_session_key,
3693 pSesInfo->password);
3694 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695 /* for better security the weaker lanman hash not sent
3696 in AuthSessSetup so we no longer calculate it */
3697
Steve French26b994f2008-08-06 05:11:33 +00003698 rc = CIFSNTLMSSPAuthSessSetup(xid, pSesInfo,
3699 ntlm_session_key,
3700 ntlmv2_flag,
3701 nls_info);
3702 }
3703 } else { /* old style NTLM 0.12 session setup */
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003704 SMBNTencrypt(pSesInfo->password, server->cryptKey,
Steve French26b994f2008-08-06 05:11:33 +00003705 ntlm_session_key);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706
Steve French26b994f2008-08-06 05:11:33 +00003707 if (first_time)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003708 cifs_calculate_mac_key(&server->mac_signing_key,
3709 ntlm_session_key,
3710 pSesInfo->password);
Steve Frenchad009ac2005-04-28 22:41:05 -07003711
Steve French26b994f2008-08-06 05:11:33 +00003712 rc = CIFSSessSetup(xid, pSesInfo, ntlm_session_key, nls_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003713 }
Steve French26b994f2008-08-06 05:11:33 +00003714 if (rc) {
3715 cERROR(1, ("Send error in SessSetup = %d", rc));
3716 } else {
3717 cFYI(1, ("CIFS Session Established successfully"));
Jeff Layton469ee612008-10-16 18:46:39 +00003718 spin_lock(&GlobalMid_Lock);
Steve French26b994f2008-08-06 05:11:33 +00003719 pSesInfo->status = CifsGood;
Jeff Layton469ee612008-10-16 18:46:39 +00003720 spin_unlock(&GlobalMid_Lock);
Steve French26b994f2008-08-06 05:11:33 +00003721 }
3722
Linus Torvalds1da177e2005-04-16 15:20:36 -07003723ss_err_exit:
3724 return rc;
3725}
3726