blob: a0314259f94de548681197e58b2b5fab0bae16f1 [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 */
Steve Frenchedf1ae42008-10-29 00:47:57 +000095 bool noblocksnd:1;
96 bool noautotune:1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 unsigned int rsize;
98 unsigned int wsize;
99 unsigned int sockopt;
100 unsigned short int port;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000101 char *prepath;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102};
103
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000104static int ipv4_connect(struct sockaddr_in *psin_server,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 struct socket **csocket,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000106 char *netb_name,
Steve Frenchedf1ae42008-10-29 00:47:57 +0000107 char *server_netb_name,
108 bool noblocksnd,
109 bool nosndbuf); /* ipv6 never set sndbuf size */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000110static int ipv6_connect(struct sockaddr_in6 *psin_server,
Steve Frenchedf1ae42008-10-29 00:47:57 +0000111 struct socket **csocket, bool noblocksnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112
113
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000114 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 * cifs tcp session reconnection
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000116 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 * mark tcp session as reconnecting so temporarily locked
118 * mark all smb sessions as reconnecting for tcp session
119 * reconnect tcp session
120 * wake up waiters on reconnection? - (not needed currently)
121 */
122
Steve French2cd646a2006-09-28 19:43:08 +0000123static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124cifs_reconnect(struct TCP_Server_Info *server)
125{
126 int rc = 0;
127 struct list_head *tmp;
128 struct cifsSesInfo *ses;
129 struct cifsTconInfo *tcon;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000130 struct mid_q_entry *mid_entry;
Steve French50c2f752007-07-13 00:33:32 +0000131
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 spin_lock(&GlobalMid_Lock);
Jeff Layton469ee612008-10-16 18:46:39 +0000133 if (server->tcpStatus == CifsExiting) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000134 /* the demux thread will exit normally
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 next time through the loop */
136 spin_unlock(&GlobalMid_Lock);
137 return rc;
138 } else
139 server->tcpStatus = CifsNeedReconnect;
140 spin_unlock(&GlobalMid_Lock);
141 server->maxBuf = 0;
142
Steve Frenche4eb2952005-04-28 22:41:09 -0700143 cFYI(1, ("Reconnecting tcp session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144
145 /* before reconnecting the tcp session, mark the smb session (uid)
146 and the tid bad so they are not used until reconnected */
147 read_lock(&GlobalSMBSeslock);
148 list_for_each(tmp, &GlobalSMBSessionList) {
149 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
150 if (ses->server) {
151 if (ses->server == server) {
Steve French3b795212008-11-13 19:45:32 +0000152 ses->need_reconnect = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 ses->ipc_tid = 0;
154 }
155 }
156 /* else tcp and smb sessions need reconnection */
157 }
158 list_for_each(tmp, &GlobalTreeConnectionList) {
159 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000160 if ((tcon->ses) && (tcon->ses->server == server))
Steve French3b795212008-11-13 19:45:32 +0000161 tcon->need_reconnect = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 }
163 read_unlock(&GlobalSMBSeslock);
164 /* do not want to be sending data on a socket we are freeing */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000165 down(&server->tcpSem);
166 if (server->ssocket) {
Steve French467a8f82007-06-27 22:41:32 +0000167 cFYI(1, ("State: 0x%x Flags: 0x%lx", server->ssocket->state,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 server->ssocket->flags));
Trond Myklebust91cf45f2007-11-12 18:10:39 -0800169 kernel_sock_shutdown(server->ssocket, SHUT_WR);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000170 cFYI(1, ("Post shutdown state: 0x%x Flags: 0x%lx",
Steve French467a8f82007-06-27 22:41:32 +0000171 server->ssocket->state,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 server->ssocket->flags));
173 sock_release(server->ssocket);
174 server->ssocket = NULL;
175 }
176
177 spin_lock(&GlobalMid_Lock);
178 list_for_each(tmp, &server->pending_mid_q) {
179 mid_entry = list_entry(tmp, struct
180 mid_q_entry,
181 qhead);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000182 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French09d1db52005-04-28 22:41:08 -0700183 /* Mark other intransit requests as needing
184 retry so we do not immediately mark the
185 session bad again (ie after we reconnect
186 below) as they timeout too */
Steve Frenchad8b15f2008-08-08 21:10:16 +0000187 mid_entry->midState = MID_RETRY_NEEDED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 }
189 }
190 spin_unlock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000191 up(&server->tcpSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192
Jeff Layton469ee612008-10-16 18:46:39 +0000193 while ((server->tcpStatus != CifsExiting) &&
194 (server->tcpStatus != CifsGood)) {
Steve French6c3d8902006-07-31 22:46:20 +0000195 try_to_freeze();
Steve French3ec332e2008-11-14 03:35:10 +0000196 if (server->addr.sockAddr6.sin6_family == AF_INET6) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000197 rc = ipv6_connect(&server->addr.sockAddr6,
Steve Frenchedf1ae42008-10-29 00:47:57 +0000198 &server->ssocket, server->noautotune);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000200 rc = ipv4_connect(&server->addr.sockAddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 &server->ssocket,
Steve Frencha10faeb22005-08-22 21:38:31 -0700202 server->workstation_RFC1001_name,
Steve Frenchedf1ae42008-10-29 00:47:57 +0000203 server->server_RFC1001_name,
204 server->noblocksnd, server->noautotune);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000206 if (rc) {
207 cFYI(1, ("reconnect error %d", rc));
Steve French0cb766a2005-04-28 22:41:11 -0700208 msleep(3000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 } else {
210 atomic_inc(&tcpSesReconnectCount);
211 spin_lock(&GlobalMid_Lock);
Jeff Layton469ee612008-10-16 18:46:39 +0000212 if (server->tcpStatus != CifsExiting)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 server->tcpStatus = CifsGood;
Steve Frenchad009ac2005-04-28 22:41:05 -0700214 server->sequence_number = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000215 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 /* atomic_set(&server->inFlight,0);*/
217 wake_up(&server->response_q);
218 }
219 }
220 return rc;
221}
222
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000223/*
Steve Frenche4eb2952005-04-28 22:41:09 -0700224 return codes:
225 0 not a transact2, or all data present
226 >0 transact2 with that much data missing
227 -EINVAL = invalid transact2
228
229 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000230static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize)
Steve Frenche4eb2952005-04-28 22:41:09 -0700231{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000232 struct smb_t2_rsp *pSMBt;
233 int total_data_size;
Steve Frenche4eb2952005-04-28 22:41:09 -0700234 int data_in_this_rsp;
235 int remaining;
236
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000237 if (pSMB->Command != SMB_COM_TRANSACTION2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700238 return 0;
239
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000240 /* check for plausible wct, bcc and t2 data and parm sizes */
241 /* check for parm and data offset going beyond end of smb */
242 if (pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
Steve French467a8f82007-06-27 22:41:32 +0000243 cFYI(1, ("invalid transact2 word count"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700244 return -EINVAL;
245 }
246
247 pSMBt = (struct smb_t2_rsp *)pSMB;
248
249 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
250 data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
251
252 remaining = total_data_size - data_in_this_rsp;
253
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000254 if (remaining == 0)
Steve Frenche4eb2952005-04-28 22:41:09 -0700255 return 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000256 else if (remaining < 0) {
Steve French467a8f82007-06-27 22:41:32 +0000257 cFYI(1, ("total data %d smaller than data in frame %d",
Steve Frenche4eb2952005-04-28 22:41:09 -0700258 total_data_size, data_in_this_rsp));
259 return -EINVAL;
260 } else {
Steve French467a8f82007-06-27 22:41:32 +0000261 cFYI(1, ("missing %d bytes from transact2, check next response",
Steve Frenche4eb2952005-04-28 22:41:09 -0700262 remaining));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000263 if (total_data_size > maxBufSize) {
264 cERROR(1, ("TotalDataSize %d is over maximum buffer %d",
265 total_data_size, maxBufSize));
266 return -EINVAL;
Steve Frenche4eb2952005-04-28 22:41:09 -0700267 }
268 return remaining;
269 }
270}
271
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000272static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
Steve Frenche4eb2952005-04-28 22:41:09 -0700273{
274 struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
275 struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
276 int total_data_size;
277 int total_in_buf;
278 int remaining;
279 int total_in_buf2;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000280 char *data_area_of_target;
281 char *data_area_of_buf2;
Steve Frenche4eb2952005-04-28 22:41:09 -0700282 __u16 byte_count;
283
284 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
285
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000286 if (total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
Steve French63135e02007-07-17 17:34:02 +0000287 cFYI(1, ("total data size of primary and secondary t2 differ"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700288 }
289
290 total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
291
292 remaining = total_data_size - total_in_buf;
Steve French50c2f752007-07-13 00:33:32 +0000293
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000294 if (remaining < 0)
Steve Frenche4eb2952005-04-28 22:41:09 -0700295 return -EINVAL;
296
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000297 if (remaining == 0) /* nothing to do, ignore */
Steve Frenche4eb2952005-04-28 22:41:09 -0700298 return 0;
Steve French50c2f752007-07-13 00:33:32 +0000299
Steve Frenche4eb2952005-04-28 22:41:09 -0700300 total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000301 if (remaining < total_in_buf2) {
Steve French467a8f82007-06-27 22:41:32 +0000302 cFYI(1, ("transact2 2nd response contains too much data"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700303 }
304
305 /* find end of first SMB data area */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000306 data_area_of_target = (char *)&pSMBt->hdr.Protocol +
Steve Frenche4eb2952005-04-28 22:41:09 -0700307 le16_to_cpu(pSMBt->t2_rsp.DataOffset);
308 /* validate target area */
309
310 data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000311 le16_to_cpu(pSMB2->t2_rsp.DataOffset);
Steve Frenche4eb2952005-04-28 22:41:09 -0700312
313 data_area_of_target += total_in_buf;
314
315 /* copy second buffer into end of first buffer */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000316 memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2);
Steve Frenche4eb2952005-04-28 22:41:09 -0700317 total_in_buf += total_in_buf2;
318 pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
319 byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
320 byte_count += total_in_buf2;
321 BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
322
Steve French70ca7342005-09-22 16:32:06 -0700323 byte_count = pTargetSMB->smb_buf_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700324 byte_count += total_in_buf2;
325
326 /* BB also add check that we are not beyond maximum buffer size */
Steve French50c2f752007-07-13 00:33:32 +0000327
Steve French70ca7342005-09-22 16:32:06 -0700328 pTargetSMB->smb_buf_length = byte_count;
Steve Frenche4eb2952005-04-28 22:41:09 -0700329
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000330 if (remaining == total_in_buf2) {
Steve French467a8f82007-06-27 22:41:32 +0000331 cFYI(1, ("found the last secondary response"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700332 return 0; /* we are done */
333 } else /* more responses to go */
334 return 1;
335
336}
337
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338static int
339cifs_demultiplex_thread(struct TCP_Server_Info *server)
340{
341 int length;
342 unsigned int pdu_length, total_read;
343 struct smb_hdr *smb_buffer = NULL;
Steve Frenchb8643e12005-04-28 22:41:07 -0700344 struct smb_hdr *bigbuf = NULL;
345 struct smb_hdr *smallbuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 struct msghdr smb_msg;
347 struct kvec iov;
348 struct socket *csocket = server->ssocket;
349 struct list_head *tmp;
350 struct cifsSesInfo *ses;
351 struct task_struct *task_to_wake = NULL;
352 struct mid_q_entry *mid_entry;
Steve French70ca7342005-09-22 16:32:06 -0700353 char temp;
Steve French4b18f2a2008-04-29 00:06:05 +0000354 bool isLargeBuf = false;
355 bool isMultiRsp;
Steve Frenche4eb2952005-04-28 22:41:09 -0700356 int reconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 current->flags |= PF_MEMALLOC;
Pavel Emelyanovba25f9d2007-10-18 23:40:40 -0700359 cFYI(1, ("Demultiplex PID: %d", task_pid_nr(current)));
Jeff Layton93d0ec82008-08-02 08:00:48 -0400360
361 length = atomic_inc_return(&tcpSesAllocCount);
362 if (length > 1)
Steve French26f57362007-08-30 22:09:15 +0000363 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
364 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
Rafael J. Wysocki83144182007-07-17 04:03:35 -0700366 set_freezable();
Jeff Layton469ee612008-10-16 18:46:39 +0000367 while (server->tcpStatus != CifsExiting) {
Steve Frenchede13272005-08-30 20:10:14 -0700368 if (try_to_freeze())
369 continue;
Steve Frenchb8643e12005-04-28 22:41:07 -0700370 if (bigbuf == NULL) {
371 bigbuf = cifs_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000372 if (!bigbuf) {
373 cERROR(1, ("No memory for large SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700374 msleep(3000);
375 /* retry will check if exiting */
376 continue;
377 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000378 } else if (isLargeBuf) {
379 /* we are reusing a dirty large buf, clear its start */
Steve French26f57362007-08-30 22:09:15 +0000380 memset(bigbuf, 0, sizeof(struct smb_hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700382
383 if (smallbuf == NULL) {
384 smallbuf = cifs_small_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000385 if (!smallbuf) {
386 cERROR(1, ("No memory for SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700387 msleep(1000);
388 /* retry will check if exiting */
389 continue;
390 }
391 /* beginning of smb buffer is cleared in our buf_get */
392 } else /* if existing small buf clear beginning */
Steve French26f57362007-08-30 22:09:15 +0000393 memset(smallbuf, 0, sizeof(struct smb_hdr));
Steve Frenchb8643e12005-04-28 22:41:07 -0700394
Steve French4b18f2a2008-04-29 00:06:05 +0000395 isLargeBuf = false;
396 isMultiRsp = false;
Steve Frenchb8643e12005-04-28 22:41:07 -0700397 smb_buffer = smallbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 iov.iov_base = smb_buffer;
399 iov.iov_len = 4;
400 smb_msg.msg_control = NULL;
401 smb_msg.msg_controllen = 0;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000402 pdu_length = 4; /* enough to get RFC1001 header */
403incomplete_rcv:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 length =
405 kernel_recvmsg(csocket, &smb_msg,
Steve Frenchf01d5e12007-08-30 21:13:31 +0000406 &iov, 1, pdu_length, 0 /* BB other flags? */);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407
Jeff Layton469ee612008-10-16 18:46:39 +0000408 if (server->tcpStatus == CifsExiting) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 break;
410 } else if (server->tcpStatus == CifsNeedReconnect) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000411 cFYI(1, ("Reconnect after server stopped responding"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 cifs_reconnect(server);
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000413 cFYI(1, ("call to reconnect done"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 csocket = server->ssocket;
415 continue;
416 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700417 msleep(1); /* minimum sleep to prevent looping
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 allowing socket to clear and app threads to set
419 tcpStatus CifsNeedReconnect if server hung */
Steve Frenchc527c8a2008-11-03 20:46:21 +0000420 if (pdu_length < 4) {
421 iov.iov_base = (4 - pdu_length) +
422 (char *)smb_buffer;
423 iov.iov_len = pdu_length;
424 smb_msg.msg_control = NULL;
425 smb_msg.msg_controllen = 0;
Steve Frenchc18c7322007-10-17 18:01:11 +0000426 goto incomplete_rcv;
Steve Frenchc527c8a2008-11-03 20:46:21 +0000427 } else
Steve Frenchc18c7322007-10-17 18:01:11 +0000428 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 } else if (length <= 0) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000430 if (server->tcpStatus == CifsNew) {
431 cFYI(1, ("tcp session abend after SMBnegprot"));
Steve French09d1db52005-04-28 22:41:08 -0700432 /* some servers kill the TCP session rather than
433 returning an SMB negprot error, in which
434 case reconnecting here is not going to help,
435 and so simply return error to mount */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 break;
437 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000438 if (!try_to_freeze() && (length == -EINTR)) {
Steve French467a8f82007-06-27 22:41:32 +0000439 cFYI(1, ("cifsd thread killed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 break;
441 }
Steve French467a8f82007-06-27 22:41:32 +0000442 cFYI(1, ("Reconnect after unexpected peek error %d",
Steve French57337e42005-04-28 22:41:10 -0700443 length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 cifs_reconnect(server);
445 csocket = server->ssocket;
446 wake_up(&server->response_q);
447 continue;
Petr Tesarik2a974682007-11-20 02:24:08 +0000448 } else if (length < pdu_length) {
449 cFYI(1, ("requested %d bytes but only got %d bytes",
450 pdu_length, length));
Steve Frenchf01d5e12007-08-30 21:13:31 +0000451 pdu_length -= length;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000452 msleep(1);
453 goto incomplete_rcv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 }
Steve French67010fb2005-04-28 22:41:09 -0700455
Steve French70ca7342005-09-22 16:32:06 -0700456 /* The right amount was read from socket - 4 bytes */
457 /* so we can now interpret the length field */
Steve French46810cb2005-04-28 22:41:09 -0700458
Steve French70ca7342005-09-22 16:32:06 -0700459 /* the first byte big endian of the length field,
460 is actually not part of the length but the type
461 with the most common, zero, as regular data */
462 temp = *((char *) smb_buffer);
463
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000464 /* Note that FC 1001 length is big endian on the wire,
Steve French70ca7342005-09-22 16:32:06 -0700465 but we convert it here so it is always manipulated
466 as host byte order */
Harvey Harrison5ca33c62008-07-23 17:45:58 -0700467 pdu_length = be32_to_cpu((__force __be32)smb_buffer->smb_buf_length);
Steve French70ca7342005-09-22 16:32:06 -0700468 smb_buffer->smb_buf_length = pdu_length;
Steve French46810cb2005-04-28 22:41:09 -0700469
Steve French467a8f82007-06-27 22:41:32 +0000470 cFYI(1, ("rfc1002 length 0x%x", pdu_length+4));
Steve French70ca7342005-09-22 16:32:06 -0700471
472 if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000473 continue;
Steve French70ca7342005-09-22 16:32:06 -0700474 } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
Steve French467a8f82007-06-27 22:41:32 +0000475 cFYI(1, ("Good RFC 1002 session rsp"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700476 continue;
Steve French70ca7342005-09-22 16:32:06 -0700477 } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000478 /* we get this from Windows 98 instead of
Steve French46810cb2005-04-28 22:41:09 -0700479 an error on SMB negprot response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000480 cFYI(1, ("Negative RFC1002 Session Response Error 0x%x)",
Steve French70ca7342005-09-22 16:32:06 -0700481 pdu_length));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000482 if (server->tcpStatus == CifsNew) {
483 /* if nack on negprot (rather than
Steve French46810cb2005-04-28 22:41:09 -0700484 ret of smb negprot error) reconnecting
485 not going to help, ret error to mount */
486 break;
487 } else {
488 /* give server a second to
489 clean up before reconnect attempt */
490 msleep(1000);
491 /* always try 445 first on reconnect
492 since we get NACK on some if we ever
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000493 connected to port 139 (the NACK is
Steve French46810cb2005-04-28 22:41:09 -0700494 since we do not begin with RFC1001
495 session initialize frame) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000496 server->addr.sockAddr.sin_port =
Steve French46810cb2005-04-28 22:41:09 -0700497 htons(CIFS_PORT);
498 cifs_reconnect(server);
499 csocket = server->ssocket;
500 wake_up(&server->response_q);
501 continue;
502 }
Steve French70ca7342005-09-22 16:32:06 -0700503 } else if (temp != (char) 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000504 cERROR(1, ("Unknown RFC 1002 frame"));
Steve French70ca7342005-09-22 16:32:06 -0700505 cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
506 length);
Steve French46810cb2005-04-28 22:41:09 -0700507 cifs_reconnect(server);
508 csocket = server->ssocket;
509 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700510 }
511
512 /* else we have an SMB response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000513 if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French26f57362007-08-30 22:09:15 +0000514 (pdu_length < sizeof(struct smb_hdr) - 1 - 4)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700515 cERROR(1, ("Invalid size SMB length %d pdu_length %d",
Steve French46810cb2005-04-28 22:41:09 -0700516 length, pdu_length+4));
Steve Frenche4eb2952005-04-28 22:41:09 -0700517 cifs_reconnect(server);
518 csocket = server->ssocket;
519 wake_up(&server->response_q);
520 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000521 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700522
523 /* else length ok */
524 reconnect = 0;
525
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000526 if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
Steve French4b18f2a2008-04-29 00:06:05 +0000527 isLargeBuf = true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700528 memcpy(bigbuf, smallbuf, 4);
529 smb_buffer = bigbuf;
530 }
531 length = 0;
532 iov.iov_base = 4 + (char *)smb_buffer;
533 iov.iov_len = pdu_length;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000534 for (total_read = 0; total_read < pdu_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700535 total_read += length) {
536 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
537 pdu_length - total_read, 0);
Jeff Layton469ee612008-10-16 18:46:39 +0000538 if ((server->tcpStatus == CifsExiting) ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700539 (length == -EINTR)) {
540 /* then will exit */
541 reconnect = 2;
542 break;
543 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700544 cifs_reconnect(server);
545 csocket = server->ssocket;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000546 /* Reconnect wakes up rspns q */
Steve Frenche4eb2952005-04-28 22:41:09 -0700547 /* Now we will reread sock */
548 reconnect = 1;
549 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000550 } else if ((length == -ERESTARTSYS) ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700551 (length == -EAGAIN)) {
552 msleep(1); /* minimum sleep to prevent looping,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000553 allowing socket to clear and app
Steve Frenche4eb2952005-04-28 22:41:09 -0700554 threads to set tcpStatus
555 CifsNeedReconnect if server hung*/
Steve Frenchc18c7322007-10-17 18:01:11 +0000556 length = 0;
Steve French46810cb2005-04-28 22:41:09 -0700557 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700558 } else if (length <= 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000559 cERROR(1, ("Received no data, expecting %d",
Steve Frenche4eb2952005-04-28 22:41:09 -0700560 pdu_length - total_read));
561 cifs_reconnect(server);
562 csocket = server->ssocket;
563 reconnect = 1;
564 break;
Steve French46810cb2005-04-28 22:41:09 -0700565 }
566 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000567 if (reconnect == 2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700568 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000569 else if (reconnect == 1)
Steve Frenche4eb2952005-04-28 22:41:09 -0700570 continue;
571
572 length += 4; /* account for rfc1002 hdr */
Steve French50c2f752007-07-13 00:33:32 +0000573
Steve Frenche4eb2952005-04-28 22:41:09 -0700574
575 dump_smb(smb_buffer, length);
Steve French184ed212006-02-24 06:15:11 +0000576 if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700577 cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
Steve Frenche4eb2952005-04-28 22:41:09 -0700578 continue;
579 }
580
581
582 task_to_wake = NULL;
583 spin_lock(&GlobalMid_Lock);
584 list_for_each(tmp, &server->pending_mid_q) {
585 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
586
Steve French50c2f752007-07-13 00:33:32 +0000587 if ((mid_entry->mid == smb_buffer->Mid) &&
Steve Frenche4eb2952005-04-28 22:41:09 -0700588 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
589 (mid_entry->command == smb_buffer->Command)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000590 if (check2ndT2(smb_buffer,server->maxBuf) > 0) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700591 /* We have a multipart transact2 resp */
Steve French4b18f2a2008-04-29 00:06:05 +0000592 isMultiRsp = true;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000593 if (mid_entry->resp_buf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700594 /* merge response - fix up 1st*/
Steve French50c2f752007-07-13 00:33:32 +0000595 if (coalesce_t2(smb_buffer,
Steve Frenche4eb2952005-04-28 22:41:09 -0700596 mid_entry->resp_buf)) {
Steve French4b18f2a2008-04-29 00:06:05 +0000597 mid_entry->multiRsp =
598 true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700599 break;
600 } else {
601 /* all parts received */
Steve French4b18f2a2008-04-29 00:06:05 +0000602 mid_entry->multiEnd =
603 true;
Steve French50c2f752007-07-13 00:33:32 +0000604 goto multi_t2_fnd;
Steve Frenche4eb2952005-04-28 22:41:09 -0700605 }
606 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000607 if (!isLargeBuf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700608 cERROR(1,("1st trans2 resp needs bigbuf"));
609 /* BB maybe we can fix this up, switch
Steve French50c2f752007-07-13 00:33:32 +0000610 to already allocated large buffer? */
Steve Frenche4eb2952005-04-28 22:41:09 -0700611 } else {
Steve Frenchcd634992005-04-28 22:41:10 -0700612 /* Have first buffer */
Steve Frenche4eb2952005-04-28 22:41:09 -0700613 mid_entry->resp_buf =
614 smb_buffer;
Steve French4b18f2a2008-04-29 00:06:05 +0000615 mid_entry->largeBuf =
616 true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700617 bigbuf = NULL;
618 }
619 }
620 break;
Steve French50c2f752007-07-13 00:33:32 +0000621 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700622 mid_entry->resp_buf = smb_buffer;
Steve French4b18f2a2008-04-29 00:06:05 +0000623 mid_entry->largeBuf = isLargeBuf;
Steve Frenche4eb2952005-04-28 22:41:09 -0700624multi_t2_fnd:
625 task_to_wake = mid_entry->tsk;
626 mid_entry->midState = MID_RESPONSE_RECEIVED;
Steve French1047abc2005-10-11 19:58:06 -0700627#ifdef CONFIG_CIFS_STATS2
628 mid_entry->when_received = jiffies;
629#endif
Steve French3a5ff612006-07-14 22:37:11 +0000630 /* so we do not time out requests to server
631 which is still responding (since server could
632 be busy but not dead) */
633 server->lstrp = jiffies;
Steve Frenche4eb2952005-04-28 22:41:09 -0700634 break;
635 }
636 }
637 spin_unlock(&GlobalMid_Lock);
638 if (task_to_wake) {
Steve Frenchcd634992005-04-28 22:41:10 -0700639 /* Was previous buf put in mpx struct for multi-rsp? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000640 if (!isMultiRsp) {
Steve Frenchcd634992005-04-28 22:41:10 -0700641 /* smb buffer will be freed by user thread */
Steve French26f57362007-08-30 22:09:15 +0000642 if (isLargeBuf)
Steve Frenchcd634992005-04-28 22:41:10 -0700643 bigbuf = NULL;
Steve French26f57362007-08-30 22:09:15 +0000644 else
Steve Frenchcd634992005-04-28 22:41:10 -0700645 smallbuf = NULL;
646 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700647 wake_up_process(task_to_wake);
Steve French4b18f2a2008-04-29 00:06:05 +0000648 } else if (!is_valid_oplock_break(smb_buffer, server) &&
649 !isMultiRsp) {
Steve French50c2f752007-07-13 00:33:32 +0000650 cERROR(1, ("No task to wake, unknown frame received! "
651 "NumMids %d", midCount.counter));
652 cifs_dump_mem("Received Data is: ", (char *)smb_buffer,
Steve French70ca7342005-09-22 16:32:06 -0700653 sizeof(struct smb_hdr));
Steve French39798772006-05-31 22:40:51 +0000654#ifdef CONFIG_CIFS_DEBUG2
655 cifs_dump_detail(smb_buffer);
656 cifs_dump_mids(server);
657#endif /* CIFS_DEBUG2 */
Steve French50c2f752007-07-13 00:33:32 +0000658
Steve Frenche4eb2952005-04-28 22:41:09 -0700659 }
660 } /* end while !EXITING */
661
Jeff Laytone7ddee92008-11-14 13:44:38 -0500662 /* take it off the list, if it's not already */
663 write_lock(&cifs_tcp_ses_lock);
664 list_del_init(&server->tcp_ses_list);
665 write_unlock(&cifs_tcp_ses_lock);
666
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 spin_lock(&GlobalMid_Lock);
668 server->tcpStatus = CifsExiting;
Steve Frenche691b9d2008-05-11 15:53:33 +0000669 spin_unlock(&GlobalMid_Lock);
Steve Frenchdbdbb872008-06-10 21:21:56 +0000670 wake_up_all(&server->response_q);
Steve Frenche691b9d2008-05-11 15:53:33 +0000671
Steve French31ca3bc2005-04-28 22:41:11 -0700672 /* check if we have blocked requests that need to free */
673 /* Note that cifs_max_pending is normally 50, but
674 can be set at module install time to as little as two */
Steve Frenche691b9d2008-05-11 15:53:33 +0000675 spin_lock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000676 if (atomic_read(&server->inFlight) >= cifs_max_pending)
Steve French31ca3bc2005-04-28 22:41:11 -0700677 atomic_set(&server->inFlight, cifs_max_pending - 1);
678 /* We do not want to set the max_pending too low or we
679 could end up with the counter going negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +0000681 /* Although there should not be any requests blocked on
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700683 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 to the same server - they now will see the session is in exit state
685 and get out of SendReceive. */
686 wake_up_all(&server->request_q);
687 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700688 msleep(125);
Steve French50c2f752007-07-13 00:33:32 +0000689
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000690 if (server->ssocket) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 sock_release(csocket);
692 server->ssocket = NULL;
693 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700694 /* buffer usuallly freed in free_mid - need to free it here on exit */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +0000695 cifs_buf_release(bigbuf);
696 if (smallbuf) /* no sense logging a debug message if NULL */
Steve Frenchb8643e12005-04-28 22:41:07 -0700697 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698
699 read_lock(&GlobalSMBSeslock);
700 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700701 /* loop through server session structures attached to this and
702 mark them dead */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 list_for_each(tmp, &GlobalSMBSessionList) {
704 ses =
705 list_entry(tmp, struct cifsSesInfo,
706 cifsSessionList);
707 if (ses->server == server) {
708 ses->status = CifsExiting;
709 ses->server = NULL;
710 }
711 }
712 read_unlock(&GlobalSMBSeslock);
713 } else {
Steve French31ca3bc2005-04-28 22:41:11 -0700714 /* although we can not zero the server struct pointer yet,
715 since there are active requests which may depnd on them,
716 mark the corresponding SMB sessions as exiting too */
717 list_for_each(tmp, &GlobalSMBSessionList) {
718 ses = list_entry(tmp, struct cifsSesInfo,
719 cifsSessionList);
Steve French26f57362007-08-30 22:09:15 +0000720 if (ses->server == server)
Steve French31ca3bc2005-04-28 22:41:11 -0700721 ses->status = CifsExiting;
Steve French31ca3bc2005-04-28 22:41:11 -0700722 }
723
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 spin_lock(&GlobalMid_Lock);
725 list_for_each(tmp, &server->pending_mid_q) {
726 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
727 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French50c2f752007-07-13 00:33:32 +0000728 cFYI(1, ("Clearing Mid 0x%x - waking up ",
729 mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 task_to_wake = mid_entry->tsk;
Steve French26f57362007-08-30 22:09:15 +0000731 if (task_to_wake)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 wake_up_process(task_to_wake);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 }
734 }
735 spin_unlock(&GlobalMid_Lock);
736 read_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700738 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 }
740
Steve Frenchf1914012005-08-18 09:37:34 -0700741 if (!list_empty(&server->pending_mid_q)) {
Steve French50c2f752007-07-13 00:33:32 +0000742 /* mpx threads have not exited yet give them
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700744 /* due to delays on oplock break requests, we need
745 to wait at least 45 seconds before giving up
746 on a request getting a response and going ahead
747 and killing cifsd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve French31ca3bc2005-04-28 22:41:11 -0700749 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 /* if threads still have not exited they are probably never
751 coming home not much else we can do but free the memory */
752 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753
Steve French31ca3bc2005-04-28 22:41:11 -0700754 /* last chance to mark ses pointers invalid
755 if there are any pointing to this (e.g
Steve French50c2f752007-07-13 00:33:32 +0000756 if a crazy root user tried to kill cifsd
Steve French31ca3bc2005-04-28 22:41:11 -0700757 kernel thread explicitly this might happen) */
Jeff Layton93d0ec82008-08-02 08:00:48 -0400758 write_lock(&GlobalSMBSeslock);
Steve French31ca3bc2005-04-28 22:41:11 -0700759 list_for_each(tmp, &GlobalSMBSessionList) {
760 ses = list_entry(tmp, struct cifsSesInfo,
761 cifsSessionList);
Steve French26f57362007-08-30 22:09:15 +0000762 if (ses->server == server)
Steve French31ca3bc2005-04-28 22:41:11 -0700763 ses->server = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700764 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 write_unlock(&GlobalSMBSeslock);
Steve French31ca3bc2005-04-28 22:41:11 -0700766
Jeff Laytonc359cf32007-11-16 22:22:06 +0000767 kfree(server->hostname);
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -0400768 task_to_wake = xchg(&server->tsk, NULL);
Steve French31ca3bc2005-04-28 22:41:11 -0700769 kfree(server);
Jeff Layton93d0ec82008-08-02 08:00:48 -0400770
771 length = atomic_dec_return(&tcpSesAllocCount);
Steve French26f57362007-08-30 22:09:15 +0000772 if (length > 0)
773 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
774 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +0000775
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -0400776 /* if server->tsk was NULL then wait for a signal before exiting */
777 if (!task_to_wake) {
778 set_current_state(TASK_INTERRUPTIBLE);
779 while (!signal_pending(current)) {
780 schedule();
781 set_current_state(TASK_INTERRUPTIBLE);
782 }
783 set_current_state(TASK_RUNNING);
784 }
785
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 return 0;
787}
788
Jeff Laytonc359cf32007-11-16 22:22:06 +0000789/* extract the host portion of the UNC string */
790static char *
791extract_hostname(const char *unc)
792{
793 const char *src;
794 char *dst, *delim;
795 unsigned int len;
796
797 /* skip double chars at beginning of string */
798 /* BB: check validity of these bytes? */
799 src = unc + 2;
800
801 /* delimiter between hostname and sharename is always '\\' now */
802 delim = strchr(src, '\\');
803 if (!delim)
804 return ERR_PTR(-EINVAL);
805
806 len = delim - src;
807 dst = kmalloc((len + 1), GFP_KERNEL);
808 if (dst == NULL)
809 return ERR_PTR(-ENOMEM);
810
811 memcpy(dst, src, len);
812 dst[len] = '\0';
813
814 return dst;
815}
816
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817static int
Steve French50c2f752007-07-13 00:33:32 +0000818cifs_parse_mount_options(char *options, const char *devname,
819 struct smb_vol *vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820{
821 char *value;
822 char *data;
823 unsigned int temp_len, i, j;
824 char separator[2];
825
826 separator[0] = ',';
Steve French50c2f752007-07-13 00:33:32 +0000827 separator[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828
Linus Torvalds12e36b22006-10-13 08:09:29 -0700829 if (Local_System_Name[0] != 0)
Steve French50c2f752007-07-13 00:33:32 +0000830 memcpy(vol->source_rfc1001_name, Local_System_Name, 15);
Steve French2cd646a2006-09-28 19:43:08 +0000831 else {
Linus Torvalds12e36b22006-10-13 08:09:29 -0700832 char *nodename = utsname()->nodename;
Steve French50c2f752007-07-13 00:33:32 +0000833 int n = strnlen(nodename, 15);
834 memset(vol->source_rfc1001_name, 0x20, 15);
835 for (i = 0; i < n; i++) {
Steve French2cd646a2006-09-28 19:43:08 +0000836 /* does not have to be perfect mapping since field is
837 informational, only used for servers that do not support
838 port 445 and it can be overridden at mount time */
Linus Torvalds12e36b22006-10-13 08:09:29 -0700839 vol->source_rfc1001_name[i] = toupper(nodename[i]);
Steve French2cd646a2006-09-28 19:43:08 +0000840 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 }
842 vol->source_rfc1001_name[15] = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -0700843 /* null target name indicates to use *SMBSERVR default called name
844 if we end up sending RFC1001 session initialize */
845 vol->target_rfc1001_name[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 vol->linux_uid = current->uid; /* current->euid instead? */
847 vol->linux_gid = current->gid;
848 vol->dir_mode = S_IRWXUGO;
849 /* 2767 perms indicate mandatory locking support */
Steve French7505e052007-11-01 18:03:01 +0000850 vol->file_mode = (S_IRWXUGO | S_ISGID) & (~S_IXGRP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851
852 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
Steve French4b18f2a2008-04-29 00:06:05 +0000853 vol->rw = true;
Jeremy Allisonac670552005-06-22 17:26:35 -0700854 /* default is always to request posix paths. */
855 vol->posix_paths = 1;
856
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 if (!options)
858 return 1;
859
Steve French50c2f752007-07-13 00:33:32 +0000860 if (strncmp(options, "sep=", 4) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000861 if (options[4] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 separator[0] = options[4];
863 options += 5;
864 } else {
Steve French467a8f82007-06-27 22:41:32 +0000865 cFYI(1, ("Null separator not allowed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 }
867 }
Steve French50c2f752007-07-13 00:33:32 +0000868
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 while ((data = strsep(&options, separator)) != NULL) {
870 if (!*data)
871 continue;
872 if ((value = strchr(data, '=')) != NULL)
873 *value++ = '\0';
874
Steve French50c2f752007-07-13 00:33:32 +0000875 /* Have to parse this before we parse for "user" */
876 if (strnicmp(data, "user_xattr", 10) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 vol->no_xattr = 0;
Steve French50c2f752007-07-13 00:33:32 +0000878 } else if (strnicmp(data, "nouser_xattr", 12) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 vol->no_xattr = 1;
880 } else if (strnicmp(data, "user", 4) == 0) {
Steve French4b952a92006-10-30 21:46:13 +0000881 if (!value) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 printk(KERN_WARNING
883 "CIFS: invalid or missing username\n");
884 return 1; /* needs_arg; */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000885 } else if (!*value) {
Steve French4b952a92006-10-30 21:46:13 +0000886 /* null user, ie anonymous, authentication */
887 vol->nullauth = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 }
889 if (strnlen(value, 200) < 200) {
890 vol->username = value;
891 } else {
892 printk(KERN_WARNING "CIFS: username too long\n");
893 return 1;
894 }
895 } else if (strnicmp(data, "pass", 4) == 0) {
896 if (!value) {
897 vol->password = NULL;
898 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000899 } else if (value[0] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 /* check if string begins with double comma
901 since that would mean the password really
902 does start with a comma, and would not
903 indicate an empty string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000904 if (value[1] != separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 vol->password = NULL;
906 continue;
907 }
908 }
909 temp_len = strlen(value);
910 /* removed password length check, NTLM passwords
911 can be arbitrarily long */
912
Steve French50c2f752007-07-13 00:33:32 +0000913 /* if comma in password, the string will be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 prematurely null terminated. Commas in password are
915 specified across the cifs mount interface by a double
916 comma ie ,, and a comma used as in other cases ie ','
917 as a parameter delimiter/separator is single and due
918 to the strsep above is temporarily zeroed. */
919
920 /* NB: password legally can have multiple commas and
921 the only illegal character in a password is null */
922
Steve French50c2f752007-07-13 00:33:32 +0000923 if ((value[temp_len] == 0) &&
Steve French09d1db52005-04-28 22:41:08 -0700924 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 /* reinsert comma */
926 value[temp_len] = separator[0];
Steve French50c2f752007-07-13 00:33:32 +0000927 temp_len += 2; /* move after second comma */
928 while (value[temp_len] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 if (value[temp_len] == separator[0]) {
Steve French50c2f752007-07-13 00:33:32 +0000930 if (value[temp_len+1] ==
Steve French09d1db52005-04-28 22:41:08 -0700931 separator[0]) {
932 /* skip second comma */
933 temp_len++;
Steve French50c2f752007-07-13 00:33:32 +0000934 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 /* single comma indicating start
936 of next parm */
937 break;
938 }
939 }
940 temp_len++;
941 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000942 if (value[temp_len] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 options = NULL;
944 } else {
945 value[temp_len] = 0;
946 /* point option to start of next parm */
947 options = value + temp_len + 1;
948 }
Steve French50c2f752007-07-13 00:33:32 +0000949 /* go from value to value + temp_len condensing
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 double commas to singles. Note that this ends up
951 allocating a few bytes too many, which is ok */
Pekka Enberge915fc42005-09-06 15:18:35 -0700952 vol->password = kzalloc(temp_len, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000953 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000954 printk(KERN_WARNING "CIFS: no memory "
955 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700956 return 1;
957 }
Steve French50c2f752007-07-13 00:33:32 +0000958 for (i = 0, j = 0; i < temp_len; i++, j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 vol->password[j] = value[i];
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000960 if (value[i] == separator[0]
Steve French09d1db52005-04-28 22:41:08 -0700961 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 /* skip second comma */
963 i++;
964 }
965 }
966 vol->password[j] = 0;
967 } else {
Pekka Enberge915fc42005-09-06 15:18:35 -0700968 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000969 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000970 printk(KERN_WARNING "CIFS: no memory "
971 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700972 return 1;
973 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 strcpy(vol->password, value);
975 }
976 } else if (strnicmp(data, "ip", 2) == 0) {
977 if (!value || !*value) {
978 vol->UNCip = NULL;
979 } else if (strnlen(value, 35) < 35) {
980 vol->UNCip = value;
981 } else {
Steve French50c2f752007-07-13 00:33:32 +0000982 printk(KERN_WARNING "CIFS: ip address "
983 "too long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 return 1;
985 }
Steve French50c2f752007-07-13 00:33:32 +0000986 } else if (strnicmp(data, "sec", 3) == 0) {
987 if (!value || !*value) {
988 cERROR(1, ("no security value specified"));
989 continue;
990 } else if (strnicmp(value, "krb5i", 5) == 0) {
991 vol->secFlg |= CIFSSEC_MAY_KRB5 |
Steve French189acaa2006-06-23 02:33:48 +0000992 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800993 } else if (strnicmp(value, "krb5p", 5) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000994 /* vol->secFlg |= CIFSSEC_MUST_SEAL |
995 CIFSSEC_MAY_KRB5; */
996 cERROR(1, ("Krb5 cifs privacy not supported"));
Steve Frenchbf820672005-12-01 22:32:42 -0800997 return 1;
998 } else if (strnicmp(value, "krb5", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000999 vol->secFlg |= CIFSSEC_MAY_KRB5;
Steve Frenchbf820672005-12-01 22:32:42 -08001000 } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
Steve French750d1152006-06-27 06:28:30 +00001001 vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
Steve French189acaa2006-06-23 02:33:48 +00001002 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -08001003 } else if (strnicmp(value, "ntlmv2", 6) == 0) {
Steve French750d1152006-06-27 06:28:30 +00001004 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve Frenchbf820672005-12-01 22:32:42 -08001005 } else if (strnicmp(value, "ntlmi", 5) == 0) {
Steve French750d1152006-06-27 06:28:30 +00001006 vol->secFlg |= CIFSSEC_MAY_NTLM |
Steve French189acaa2006-06-23 02:33:48 +00001007 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -08001008 } else if (strnicmp(value, "ntlm", 4) == 0) {
1009 /* ntlm is default so can be turned off too */
Steve French750d1152006-06-27 06:28:30 +00001010 vol->secFlg |= CIFSSEC_MAY_NTLM;
Steve Frenchbf820672005-12-01 22:32:42 -08001011 } else if (strnicmp(value, "nontlm", 6) == 0) {
Steve French189acaa2006-06-23 02:33:48 +00001012 /* BB is there a better way to do this? */
Steve French750d1152006-06-27 06:28:30 +00001013 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve French189acaa2006-06-23 02:33:48 +00001014#ifdef CONFIG_CIFS_WEAK_PW_HASH
1015 } else if (strnicmp(value, "lanman", 6) == 0) {
Steve French50c2f752007-07-13 00:33:32 +00001016 vol->secFlg |= CIFSSEC_MAY_LANMAN;
Steve French189acaa2006-06-23 02:33:48 +00001017#endif
Steve Frenchbf820672005-12-01 22:32:42 -08001018 } else if (strnicmp(value, "none", 4) == 0) {
Steve French189acaa2006-06-23 02:33:48 +00001019 vol->nullauth = 1;
Steve French50c2f752007-07-13 00:33:32 +00001020 } else {
1021 cERROR(1, ("bad security option: %s", value));
1022 return 1;
1023 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 } else if ((strnicmp(data, "unc", 3) == 0)
1025 || (strnicmp(data, "target", 6) == 0)
1026 || (strnicmp(data, "path", 4) == 0)) {
1027 if (!value || !*value) {
Steve French50c2f752007-07-13 00:33:32 +00001028 printk(KERN_WARNING "CIFS: invalid path to "
1029 "network resource\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 return 1; /* needs_arg; */
1031 }
1032 if ((temp_len = strnlen(value, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001033 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001034 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001036 strcpy(vol->UNC, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 if (strncmp(vol->UNC, "//", 2) == 0) {
1038 vol->UNC[0] = '\\';
1039 vol->UNC[1] = '\\';
Steve French50c2f752007-07-13 00:33:32 +00001040 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 printk(KERN_WARNING
Steve French50c2f752007-07-13 00:33:32 +00001042 "CIFS: UNC Path does not begin "
1043 "with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 return 1;
1045 }
1046 } else {
1047 printk(KERN_WARNING "CIFS: UNC name too long\n");
1048 return 1;
1049 }
1050 } else if ((strnicmp(data, "domain", 3) == 0)
1051 || (strnicmp(data, "workgroup", 5) == 0)) {
1052 if (!value || !*value) {
1053 printk(KERN_WARNING "CIFS: invalid domain name\n");
1054 return 1; /* needs_arg; */
1055 }
1056 /* BB are there cases in which a comma can be valid in
1057 a domain name and need special handling? */
Steve French39798772006-05-31 22:40:51 +00001058 if (strnlen(value, 256) < 256) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 vol->domainname = value;
1060 cFYI(1, ("Domain name set"));
1061 } else {
Steve French50c2f752007-07-13 00:33:32 +00001062 printk(KERN_WARNING "CIFS: domain name too "
1063 "long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 return 1;
1065 }
Steve French50c2f752007-07-13 00:33:32 +00001066 } else if (strnicmp(data, "prefixpath", 10) == 0) {
1067 if (!value || !*value) {
1068 printk(KERN_WARNING
1069 "CIFS: invalid path prefix\n");
1070 return 1; /* needs_argument */
1071 }
1072 if ((temp_len = strnlen(value, 1024)) < 1024) {
Steve French4523cc32007-04-30 20:13:06 +00001073 if (value[0] != '/')
Steve French2fe87f02006-09-21 07:02:52 +00001074 temp_len++; /* missing leading slash */
Steve French50c2f752007-07-13 00:33:32 +00001075 vol->prepath = kmalloc(temp_len+1, GFP_KERNEL);
1076 if (vol->prepath == NULL)
1077 return 1;
Steve French4523cc32007-04-30 20:13:06 +00001078 if (value[0] != '/') {
Steve French2fe87f02006-09-21 07:02:52 +00001079 vol->prepath[0] = '/';
Steve French50c2f752007-07-13 00:33:32 +00001080 strcpy(vol->prepath+1, value);
Steve French2fe87f02006-09-21 07:02:52 +00001081 } else
Steve French50c2f752007-07-13 00:33:32 +00001082 strcpy(vol->prepath, value);
1083 cFYI(1, ("prefix path %s", vol->prepath));
1084 } else {
1085 printk(KERN_WARNING "CIFS: prefix too long\n");
1086 return 1;
1087 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 } else if (strnicmp(data, "iocharset", 9) == 0) {
1089 if (!value || !*value) {
Steve French63135e02007-07-17 17:34:02 +00001090 printk(KERN_WARNING "CIFS: invalid iocharset "
1091 "specified\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 return 1; /* needs_arg; */
1093 }
1094 if (strnlen(value, 65) < 65) {
Steve French50c2f752007-07-13 00:33:32 +00001095 if (strnicmp(value, "default", 7))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 vol->iocharset = value;
Steve French50c2f752007-07-13 00:33:32 +00001097 /* if iocharset not set then load_nls_default
1098 is used by caller */
1099 cFYI(1, ("iocharset set to %s", value));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 } else {
Steve French63135e02007-07-17 17:34:02 +00001101 printk(KERN_WARNING "CIFS: iocharset name "
1102 "too long.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 return 1;
1104 }
1105 } else if (strnicmp(data, "uid", 3) == 0) {
1106 if (value && *value) {
1107 vol->linux_uid =
1108 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001109 vol->override_uid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 }
1111 } else if (strnicmp(data, "gid", 3) == 0) {
1112 if (value && *value) {
1113 vol->linux_gid =
1114 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001115 vol->override_gid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 }
1117 } else if (strnicmp(data, "file_mode", 4) == 0) {
1118 if (value && *value) {
1119 vol->file_mode =
1120 simple_strtoul(value, &value, 0);
1121 }
1122 } else if (strnicmp(data, "dir_mode", 4) == 0) {
1123 if (value && *value) {
1124 vol->dir_mode =
1125 simple_strtoul(value, &value, 0);
1126 }
1127 } else if (strnicmp(data, "dirmode", 4) == 0) {
1128 if (value && *value) {
1129 vol->dir_mode =
1130 simple_strtoul(value, &value, 0);
1131 }
1132 } else if (strnicmp(data, "port", 4) == 0) {
1133 if (value && *value) {
1134 vol->port =
1135 simple_strtoul(value, &value, 0);
1136 }
1137 } else if (strnicmp(data, "rsize", 5) == 0) {
1138 if (value && *value) {
1139 vol->rsize =
1140 simple_strtoul(value, &value, 0);
1141 }
1142 } else if (strnicmp(data, "wsize", 5) == 0) {
1143 if (value && *value) {
1144 vol->wsize =
1145 simple_strtoul(value, &value, 0);
1146 }
1147 } else if (strnicmp(data, "sockopt", 5) == 0) {
1148 if (value && *value) {
1149 vol->sockopt =
1150 simple_strtoul(value, &value, 0);
1151 }
1152 } else if (strnicmp(data, "netbiosname", 4) == 0) {
1153 if (!value || !*value || (*value == ' ')) {
Steve French63135e02007-07-17 17:34:02 +00001154 cFYI(1, ("invalid (empty) netbiosname"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 } else {
Steve French50c2f752007-07-13 00:33:32 +00001156 memset(vol->source_rfc1001_name, 0x20, 15);
1157 for (i = 0; i < 15; i++) {
1158 /* BB are there cases in which a comma can be
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 valid in this workstation netbios name (and need
1160 special handling)? */
1161
1162 /* We do not uppercase netbiosname for user */
Steve French50c2f752007-07-13 00:33:32 +00001163 if (value[i] == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 break;
Steve French50c2f752007-07-13 00:33:32 +00001165 else
1166 vol->source_rfc1001_name[i] =
1167 value[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 }
1169 /* The string has 16th byte zero still from
1170 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001171 if ((i == 15) && (value[i] != 0))
1172 printk(KERN_WARNING "CIFS: netbiosname"
1173 " longer than 15 truncated.\n");
Steve Frencha10faeb22005-08-22 21:38:31 -07001174 }
1175 } else if (strnicmp(data, "servern", 7) == 0) {
1176 /* servernetbiosname specified override *SMBSERVER */
1177 if (!value || !*value || (*value == ' ')) {
Steve French467a8f82007-06-27 22:41:32 +00001178 cFYI(1, ("empty server netbiosname specified"));
Steve Frencha10faeb22005-08-22 21:38:31 -07001179 } else {
1180 /* last byte, type, is 0x20 for servr type */
Steve French50c2f752007-07-13 00:33:32 +00001181 memset(vol->target_rfc1001_name, 0x20, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001182
Steve French50c2f752007-07-13 00:33:32 +00001183 for (i = 0; i < 15; i++) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001184 /* BB are there cases in which a comma can be
Steve French50c2f752007-07-13 00:33:32 +00001185 valid in this workstation netbios name
1186 (and need special handling)? */
Steve Frencha10faeb22005-08-22 21:38:31 -07001187
Steve French50c2f752007-07-13 00:33:32 +00001188 /* user or mount helper must uppercase
1189 the netbiosname */
1190 if (value[i] == 0)
Steve Frencha10faeb22005-08-22 21:38:31 -07001191 break;
1192 else
Steve French50c2f752007-07-13 00:33:32 +00001193 vol->target_rfc1001_name[i] =
1194 value[i];
Steve Frencha10faeb22005-08-22 21:38:31 -07001195 }
1196 /* The string has 16th byte zero still from
1197 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001198 if ((i == 15) && (value[i] != 0))
1199 printk(KERN_WARNING "CIFS: server net"
1200 "biosname longer than 15 truncated.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 }
1202 } else if (strnicmp(data, "credentials", 4) == 0) {
1203 /* ignore */
1204 } else if (strnicmp(data, "version", 3) == 0) {
1205 /* ignore */
Steve French50c2f752007-07-13 00:33:32 +00001206 } else if (strnicmp(data, "guest", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 /* ignore */
1208 } else if (strnicmp(data, "rw", 2) == 0) {
Steve French4b18f2a2008-04-29 00:06:05 +00001209 vol->rw = true;
Steve Frenchedf1ae42008-10-29 00:47:57 +00001210 } else if (strnicmp(data, "noblocksend", 11) == 0) {
1211 vol->noblocksnd = 1;
1212 } else if (strnicmp(data, "noautotune", 10) == 0) {
1213 vol->noautotune = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 } else if ((strnicmp(data, "suid", 4) == 0) ||
1215 (strnicmp(data, "nosuid", 6) == 0) ||
1216 (strnicmp(data, "exec", 4) == 0) ||
1217 (strnicmp(data, "noexec", 6) == 0) ||
1218 (strnicmp(data, "nodev", 5) == 0) ||
1219 (strnicmp(data, "noauto", 6) == 0) ||
1220 (strnicmp(data, "dev", 3) == 0)) {
1221 /* The mount tool or mount.cifs helper (if present)
Steve French50c2f752007-07-13 00:33:32 +00001222 uses these opts to set flags, and the flags are read
1223 by the kernel vfs layer before we get here (ie
1224 before read super) so there is no point trying to
1225 parse these options again and set anything and it
1226 is ok to just ignore them */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 continue;
1228 } else if (strnicmp(data, "ro", 2) == 0) {
Steve French4b18f2a2008-04-29 00:06:05 +00001229 vol->rw = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 } else if (strnicmp(data, "hard", 4) == 0) {
1231 vol->retry = 1;
1232 } else if (strnicmp(data, "soft", 4) == 0) {
1233 vol->retry = 0;
1234 } else if (strnicmp(data, "perm", 4) == 0) {
1235 vol->noperm = 0;
1236 } else if (strnicmp(data, "noperm", 6) == 0) {
1237 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001238 } else if (strnicmp(data, "mapchars", 8) == 0) {
1239 vol->remap = 1;
1240 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1241 vol->remap = 0;
Steve French50c2f752007-07-13 00:33:32 +00001242 } else if (strnicmp(data, "sfu", 3) == 0) {
1243 vol->sfu_emul = 1;
1244 } else if (strnicmp(data, "nosfu", 5) == 0) {
1245 vol->sfu_emul = 0;
Steve French2c1b8612008-10-16 18:35:21 +00001246 } else if (strnicmp(data, "nodfs", 5) == 0) {
1247 vol->nodfs = 1;
Jeremy Allisonac670552005-06-22 17:26:35 -07001248 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1249 vol->posix_paths = 1;
1250 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1251 vol->posix_paths = 0;
Steve Frenchc18c8422007-07-18 23:21:09 +00001252 } else if (strnicmp(data, "nounix", 6) == 0) {
1253 vol->no_linux_ext = 1;
1254 } else if (strnicmp(data, "nolinux", 7) == 0) {
1255 vol->no_linux_ext = 1;
Steve French50c2f752007-07-13 00:33:32 +00001256 } else if ((strnicmp(data, "nocase", 6) == 0) ||
Steve Frencha10faeb22005-08-22 21:38:31 -07001257 (strnicmp(data, "ignorecase", 10) == 0)) {
Steve French50c2f752007-07-13 00:33:32 +00001258 vol->nocase = 1;
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001259 } else if (strnicmp(data, "brl", 3) == 0) {
1260 vol->nobrl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001261 } else if ((strnicmp(data, "nobrl", 5) == 0) ||
Steve French1c955182005-08-30 20:58:07 -07001262 (strnicmp(data, "nolock", 6) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001263 vol->nobrl = 1;
Steve Frenchd3485d32005-08-19 11:04:29 -07001264 /* turn off mandatory locking in mode
1265 if remote locking is turned off since the
1266 local vfs will do advisory */
Steve French50c2f752007-07-13 00:33:32 +00001267 if (vol->file_mode ==
1268 (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
Steve Frenchd3485d32005-08-19 11:04:29 -07001269 vol->file_mode = S_IALLUGO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 } else if (strnicmp(data, "setuids", 7) == 0) {
1271 vol->setuids = 1;
1272 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1273 vol->setuids = 0;
Jeff Laytond0a9c072008-05-12 22:23:49 +00001274 } else if (strnicmp(data, "dynperm", 7) == 0) {
1275 vol->dynperm = true;
1276 } else if (strnicmp(data, "nodynperm", 9) == 0) {
1277 vol->dynperm = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 } else if (strnicmp(data, "nohard", 6) == 0) {
1279 vol->retry = 0;
1280 } else if (strnicmp(data, "nosoft", 6) == 0) {
1281 vol->retry = 1;
1282 } else if (strnicmp(data, "nointr", 6) == 0) {
1283 vol->intr = 0;
1284 } else if (strnicmp(data, "intr", 4) == 0) {
1285 vol->intr = 1;
Steve French50c2f752007-07-13 00:33:32 +00001286 } else if (strnicmp(data, "serverino", 7) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 vol->server_ino = 1;
Steve French50c2f752007-07-13 00:33:32 +00001288 } else if (strnicmp(data, "noserverino", 9) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 vol->server_ino = 0;
Steve French50c2f752007-07-13 00:33:32 +00001290 } else if (strnicmp(data, "cifsacl", 7) == 0) {
Steve French0a4b92c2006-01-12 15:44:21 -08001291 vol->cifs_acl = 1;
1292 } else if (strnicmp(data, "nocifsacl", 9) == 0) {
1293 vol->cifs_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001294 } else if (strnicmp(data, "acl", 3) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 vol->no_psx_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001296 } else if (strnicmp(data, "noacl", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 vol->no_psx_acl = 1;
Steve French84210e92008-10-23 04:42:37 +00001298#ifdef CONFIG_CIFS_EXPERIMENTAL
1299 } else if (strnicmp(data, "locallease", 6) == 0) {
1300 vol->local_lease = 1;
1301#endif
Steve French50c2f752007-07-13 00:33:32 +00001302 } else if (strnicmp(data, "sign", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +00001303 vol->secFlg |= CIFSSEC_MUST_SIGN;
Steve French95b1cb92008-05-15 16:44:38 +00001304 } else if (strnicmp(data, "seal", 4) == 0) {
1305 /* we do not do the following in secFlags because seal
1306 is a per tree connection (mount) not a per socket
1307 or per-smb connection option in the protocol */
1308 /* vol->secFlg |= CIFSSEC_MUST_SEAL; */
1309 vol->seal = 1;
Steve French50c2f752007-07-13 00:33:32 +00001310 } else if (strnicmp(data, "direct", 6) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001312 } else if (strnicmp(data, "forcedirectio", 13) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001314 } else if (strnicmp(data, "in6_addr", 8) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 if (!value || !*value) {
1316 vol->in6_addr = NULL;
1317 } else if (strnlen(value, 49) == 48) {
1318 vol->in6_addr = value;
1319 } else {
Steve French50c2f752007-07-13 00:33:32 +00001320 printk(KERN_WARNING "CIFS: ip v6 address not "
1321 "48 characters long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 return 1;
1323 }
1324 } else if (strnicmp(data, "noac", 4) == 0) {
Steve French50c2f752007-07-13 00:33:32 +00001325 printk(KERN_WARNING "CIFS: Mount option noac not "
1326 "supported. Instead set "
1327 "/proc/fs/cifs/LookupCacheEnabled to 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 } else
Steve French50c2f752007-07-13 00:33:32 +00001329 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",
1330 data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 }
1332 if (vol->UNC == NULL) {
Steve French4523cc32007-04-30 20:13:06 +00001333 if (devname == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001334 printk(KERN_WARNING "CIFS: Missing UNC name for mount "
1335 "target\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 return 1;
1337 }
1338 if ((temp_len = strnlen(devname, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001339 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001340 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001342 strcpy(vol->UNC, devname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 if (strncmp(vol->UNC, "//", 2) == 0) {
1344 vol->UNC[0] = '\\';
1345 vol->UNC[1] = '\\';
1346 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Steve French50c2f752007-07-13 00:33:32 +00001347 printk(KERN_WARNING "CIFS: UNC Path does not "
1348 "begin with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 return 1;
1350 }
Igor Mammedov7c5e6282008-05-08 20:48:42 +00001351 value = strpbrk(vol->UNC+2, "/\\");
1352 if (value)
1353 *value = '\\';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 } else {
1355 printk(KERN_WARNING "CIFS: UNC name too long\n");
1356 return 1;
1357 }
1358 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001359 if (vol->UNCip == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 vol->UNCip = &vol->UNC[2];
1361
1362 return 0;
1363}
1364
Jeff Laytone7ddee92008-11-14 13:44:38 -05001365static struct TCP_Server_Info *
1366cifs_find_tcp_session(struct sockaddr *addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367{
1368 struct list_head *tmp;
Jeff Laytone7ddee92008-11-14 13:44:38 -05001369 struct TCP_Server_Info *server;
1370 struct sockaddr_in *addr4 = (struct sockaddr_in *) addr;
1371 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372
Jeff Laytone7ddee92008-11-14 13:44:38 -05001373 write_lock(&cifs_tcp_ses_lock);
1374 list_for_each(tmp, &cifs_tcp_ses_list) {
1375 server = list_entry(tmp, struct TCP_Server_Info,
1376 tcp_ses_list);
Cyrill Gorcunov1b20d672008-05-09 18:17:21 +00001377
Jeff Laytone7ddee92008-11-14 13:44:38 -05001378 /*
1379 * the demux thread can exit on its own while still in CifsNew
1380 * so don't accept any sockets in that state. Since the
1381 * tcpStatus never changes back to CifsNew it's safe to check
1382 * for this without a lock.
1383 */
1384 if (server->tcpStatus == CifsNew)
Cyrill Gorcunov1b20d672008-05-09 18:17:21 +00001385 continue;
Steve French50c2f752007-07-13 00:33:32 +00001386
Jeff Laytone7ddee92008-11-14 13:44:38 -05001387 if (addr->sa_family == AF_INET &&
1388 (addr4->sin_addr.s_addr !=
1389 server->addr.sockAddr.sin_addr.s_addr))
1390 continue;
1391 else if (addr->sa_family == AF_INET6 &&
1392 memcmp(&server->addr.sockAddr6.sin6_addr,
1393 &addr6->sin6_addr, sizeof(addr6->sin6_addr)))
1394 continue;
Steve French50c2f752007-07-13 00:33:32 +00001395
Jeff Laytone7ddee92008-11-14 13:44:38 -05001396 ++server->srv_count;
1397 write_unlock(&cifs_tcp_ses_lock);
1398 return server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 }
Jeff Laytone7ddee92008-11-14 13:44:38 -05001400 write_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 return NULL;
1402}
1403
Jeff Laytone7ddee92008-11-14 13:44:38 -05001404void
1405cifs_put_tcp_session(struct TCP_Server_Info *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406{
Jeff Laytone7ddee92008-11-14 13:44:38 -05001407 struct task_struct *task;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408
Jeff Laytone7ddee92008-11-14 13:44:38 -05001409 write_lock(&cifs_tcp_ses_lock);
1410 if (--server->srv_count > 0) {
1411 write_unlock(&cifs_tcp_ses_lock);
1412 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 }
Steve Frenchdea570e02008-05-06 22:05:51 +00001414
Jeff Laytone7ddee92008-11-14 13:44:38 -05001415 list_del_init(&server->tcp_ses_list);
1416 write_unlock(&cifs_tcp_ses_lock);
1417
1418 spin_lock(&GlobalMid_Lock);
1419 server->tcpStatus = CifsExiting;
1420 spin_unlock(&GlobalMid_Lock);
1421
1422 task = xchg(&server->tsk, NULL);
1423 if (task)
1424 force_sig(SIGKILL, task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425}
1426
1427int
Steve French50c2f752007-07-13 00:33:32 +00001428get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
1429 const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
Steve French366781c2008-01-25 10:12:41 +00001430 struct dfs_info3_param **preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431{
1432 char *temp_unc;
1433 int rc = 0;
1434
1435 *pnum_referrals = 0;
Steve French366781c2008-01-25 10:12:41 +00001436 *preferrals = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437
1438 if (pSesInfo->ipc_tid == 0) {
1439 temp_unc = kmalloc(2 /* for slashes */ +
Steve French50c2f752007-07-13 00:33:32 +00001440 strnlen(pSesInfo->serverName,
1441 SERVER_NAME_LEN_WITH_NULL * 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 + 1 + 4 /* slash IPC$ */ + 2,
1443 GFP_KERNEL);
1444 if (temp_unc == NULL)
1445 return -ENOMEM;
1446 temp_unc[0] = '\\';
1447 temp_unc[1] = '\\';
1448 strcpy(temp_unc + 2, pSesInfo->serverName);
1449 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1450 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1451 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00001452 ("CIFS Tcon rc = %d ipc_tid = %d", rc, pSesInfo->ipc_tid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 kfree(temp_unc);
1454 }
1455 if (rc == 0)
Steve Frenchc2cf07d2008-05-15 06:20:02 +00001456 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001457 pnum_referrals, nls_codepage, remap);
Steve French366781c2008-01-25 10:12:41 +00001458 /* BB map targetUNCs to dfs_info3 structures, here or
1459 in CIFSGetDFSRefer BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460
1461 return rc;
1462}
1463
Jeff Layton09e50d52008-07-23 10:11:19 -04001464#ifdef CONFIG_DEBUG_LOCK_ALLOC
1465static struct lock_class_key cifs_key[2];
1466static struct lock_class_key cifs_slock_key[2];
1467
1468static inline void
1469cifs_reclassify_socket4(struct socket *sock)
1470{
1471 struct sock *sk = sock->sk;
1472 BUG_ON(sock_owned_by_user(sk));
1473 sock_lock_init_class_and_name(sk, "slock-AF_INET-CIFS",
1474 &cifs_slock_key[0], "sk_lock-AF_INET-CIFS", &cifs_key[0]);
1475}
1476
1477static inline void
1478cifs_reclassify_socket6(struct socket *sock)
1479{
1480 struct sock *sk = sock->sk;
1481 BUG_ON(sock_owned_by_user(sk));
1482 sock_lock_init_class_and_name(sk, "slock-AF_INET6-CIFS",
1483 &cifs_slock_key[1], "sk_lock-AF_INET6-CIFS", &cifs_key[1]);
1484}
1485#else
1486static inline void
1487cifs_reclassify_socket4(struct socket *sock)
1488{
1489}
1490
1491static inline void
1492cifs_reclassify_socket6(struct socket *sock)
1493{
1494}
1495#endif
1496
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497/* See RFC1001 section 14 on representation of Netbios names */
Steve French50c2f752007-07-13 00:33:32 +00001498static void rfc1002mangle(char *target, char *source, unsigned int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499{
Steve French50c2f752007-07-13 00:33:32 +00001500 unsigned int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501
Steve French50c2f752007-07-13 00:33:32 +00001502 for (i = 0, j = 0; i < (length); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 /* mask a nibble at a time and encode */
1504 target[j] = 'A' + (0x0F & (source[i] >> 4));
1505 target[j+1] = 'A' + (0x0F & source[i]);
Steve French50c2f752007-07-13 00:33:32 +00001506 j += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 }
1508
1509}
1510
1511
1512static int
Steve French50c2f752007-07-13 00:33:32 +00001513ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
Steve Frenchedf1ae42008-10-29 00:47:57 +00001514 char *netbios_name, char *target_name,
1515 bool noblocksnd, bool noautotune)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516{
1517 int rc = 0;
1518 int connected = 0;
1519 __be16 orig_port = 0;
1520
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001521 if (*csocket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001522 rc = sock_create_kern(PF_INET, SOCK_STREAM,
1523 IPPROTO_TCP, csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001525 cERROR(1, ("Error %d creating socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 *csocket = NULL;
1527 return rc;
1528 } else {
1529 /* BB other socket options to set KEEPALIVE, NODELAY? */
Steve French467a8f82007-06-27 22:41:32 +00001530 cFYI(1, ("Socket created"));
Steve French50c2f752007-07-13 00:33:32 +00001531 (*csocket)->sk->sk_allocation = GFP_NOFS;
Jeff Layton09e50d52008-07-23 10:11:19 -04001532 cifs_reclassify_socket4(*csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 }
1534 }
1535
1536 psin_server->sin_family = AF_INET;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001537 if (psin_server->sin_port) { /* user overrode default port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 rc = (*csocket)->ops->connect(*csocket,
1539 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001540 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 if (rc >= 0)
1542 connected = 1;
Steve French50c2f752007-07-13 00:33:32 +00001543 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001545 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001546 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 later if fall back ports fail this time */
1548 orig_port = psin_server->sin_port;
1549
1550 /* do not retry on the same port we just failed on */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001551 if (psin_server->sin_port != htons(CIFS_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 psin_server->sin_port = htons(CIFS_PORT);
1553
1554 rc = (*csocket)->ops->connect(*csocket,
1555 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001556 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 if (rc >= 0)
1558 connected = 1;
1559 }
1560 }
1561 if (!connected) {
1562 psin_server->sin_port = htons(RFC1001_PORT);
1563 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
Steve French50c2f752007-07-13 00:33:32 +00001564 psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001565 sizeof(struct sockaddr_in), 0);
Steve French50c2f752007-07-13 00:33:32 +00001566 if (rc >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 connected = 1;
1568 }
1569
1570 /* give up here - unless we want to retry on different
1571 protocol families some day */
1572 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001573 if (orig_port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 psin_server->sin_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001575 cFYI(1, ("Error %d connecting to server via ipv4", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 sock_release(*csocket);
1577 *csocket = NULL;
1578 return rc;
1579 }
Steve French50c2f752007-07-13 00:33:32 +00001580 /* Eventually check for other socket options to change from
1581 the default. sock_setsockopt not used because it expects
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 user space buffer */
Steve French50c2f752007-07-13 00:33:32 +00001583 cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",
1584 (*csocket)->sk->sk_sndbuf,
Steve Frenchb387eae2005-10-10 14:21:15 -07001585 (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchedf1ae42008-10-29 00:47:57 +00001587 if (!noblocksnd)
1588 (*csocket)->sk->sk_sndtimeo = 3 * HZ;
1589
Steve Frenchb387eae2005-10-10 14:21:15 -07001590 /* make the bufsizes depend on wsize/rsize and max requests */
Steve Frenchedf1ae42008-10-29 00:47:57 +00001591 if (noautotune) {
1592 if ((*csocket)->sk->sk_sndbuf < (200 * 1024))
1593 (*csocket)->sk->sk_sndbuf = 200 * 1024;
1594 if ((*csocket)->sk->sk_rcvbuf < (140 * 1024))
1595 (*csocket)->sk->sk_rcvbuf = 140 * 1024;
1596 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597
1598 /* send RFC1001 sessinit */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001599 if (psin_server->sin_port == htons(RFC1001_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 /* some servers require RFC1001 sessinit before sending
Steve French50c2f752007-07-13 00:33:32 +00001601 negprot - BB check reconnection in case where second
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 sessinit is sent but no second negprot */
Steve French50c2f752007-07-13 00:33:32 +00001603 struct rfc1002_session_packet *ses_init_buf;
1604 struct smb_hdr *smb_buf;
1605 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
1606 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001607 if (ses_init_buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 ses_init_buf->trailer.session_req.called_len = 32;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001609 if (target_name && (target_name[0] != 0)) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001610 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1611 target_name, 16);
1612 } else {
1613 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
Steve French50c2f752007-07-13 00:33:32 +00001614 DEFAULT_CIFS_CALLED_NAME, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001615 }
1616
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 ses_init_buf->trailer.session_req.calling_len = 32;
1618 /* calling name ends in null (byte 16) from old smb
1619 convention. */
Steve French50c2f752007-07-13 00:33:32 +00001620 if (netbios_name && (netbios_name[0] != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
Steve French50c2f752007-07-13 00:33:32 +00001622 netbios_name, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 } else {
1624 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
Steve French50c2f752007-07-13 00:33:32 +00001625 "LINUX_CIFS_CLNT", 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 }
1627 ses_init_buf->trailer.session_req.scope1 = 0;
1628 ses_init_buf->trailer.session_req.scope2 = 0;
1629 smb_buf = (struct smb_hdr *)ses_init_buf;
1630 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1631 smb_buf->smb_buf_length = 0x81000044;
1632 rc = smb_send(*csocket, smb_buf, 0x44,
Steve Frenchedf1ae42008-10-29 00:47:57 +00001633 (struct sockaddr *)psin_server, noblocksnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 kfree(ses_init_buf);
Steve French50c2f752007-07-13 00:33:32 +00001635 msleep(1); /* RFC1001 layer in at least one server
Steve French083d3a22006-03-03 09:53:36 +00001636 requires very short break before negprot
1637 presumably because not expecting negprot
1638 to follow so fast. This is a simple
Steve French50c2f752007-07-13 00:33:32 +00001639 solution that works without
Steve French083d3a22006-03-03 09:53:36 +00001640 complicating the code and causes no
1641 significant slowing down on mount
1642 for everyone else */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 }
Steve French50c2f752007-07-13 00:33:32 +00001644 /* else the negprot may still work without this
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 even though malloc failed */
Steve French50c2f752007-07-13 00:33:32 +00001646
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 }
Steve French50c2f752007-07-13 00:33:32 +00001648
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 return rc;
1650}
1651
1652static int
Steve Frenchedf1ae42008-10-29 00:47:57 +00001653ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket,
1654 bool noblocksnd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655{
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 Frenchedf1ae42008-10-29 00:47:57 +00001723 if (!noblocksnd)
1724 (*csocket)->sk->sk_sndtimeo = 3 * HZ;
1725
Steve French50c2f752007-07-13 00:33:32 +00001726
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 return rc;
1728}
1729
Steve French50c2f752007-07-13 00:33:32 +00001730void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
1731 struct super_block *sb, struct smb_vol *vol_info)
Steve French8af18972007-02-14 04:42:51 +00001732{
1733 /* if we are reconnecting then should we check to see if
1734 * any requested capabilities changed locally e.g. via
1735 * remount but we can not do much about it here
1736 * if they have (even if we could detect it by the following)
1737 * Perhaps we could add a backpointer to array of sb from tcon
1738 * or if we change to make all sb to same share the same
1739 * sb as NFS - then we only have one backpointer to sb.
1740 * What if we wanted to mount the server share twice once with
1741 * and once without posixacls or posix paths? */
1742 __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001743
Steve Frenchc18c8422007-07-18 23:21:09 +00001744 if (vol_info && vol_info->no_linux_ext) {
1745 tcon->fsUnixInfo.Capability = 0;
1746 tcon->unix_ext = 0; /* Unix Extensions disabled */
1747 cFYI(1, ("Linux protocol extensions disabled"));
1748 return;
1749 } else if (vol_info)
1750 tcon->unix_ext = 1; /* Unix Extensions supported */
1751
1752 if (tcon->unix_ext == 0) {
1753 cFYI(1, ("Unix extensions disabled so not set on reconnect"));
1754 return;
1755 }
Steve French50c2f752007-07-13 00:33:32 +00001756
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001757 if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
Steve French8af18972007-02-14 04:42:51 +00001758 __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001759
Steve French8af18972007-02-14 04:42:51 +00001760 /* check for reconnect case in which we do not
1761 want to change the mount behavior if we can avoid it */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001762 if (vol_info == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001763 /* turn off POSIX ACL and PATHNAMES if not set
Steve French8af18972007-02-14 04:42:51 +00001764 originally at mount time */
1765 if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
1766 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00001767 if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
1768 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
1769 cERROR(1, ("POSIXPATH support change"));
Steve French8af18972007-02-14 04:42:51 +00001770 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00001771 } else if ((cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
1772 cERROR(1, ("possible reconnect error"));
1773 cERROR(1,
1774 ("server disabled POSIX path support"));
1775 }
Steve French8af18972007-02-14 04:42:51 +00001776 }
Steve French50c2f752007-07-13 00:33:32 +00001777
Steve French8af18972007-02-14 04:42:51 +00001778 cap &= CIFS_UNIX_CAP_MASK;
Steve French75865f8c2007-06-24 18:30:48 +00001779 if (vol_info && vol_info->no_psx_acl)
Steve French8af18972007-02-14 04:42:51 +00001780 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00001781 else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001782 cFYI(1, ("negotiated posix acl support"));
1783 if (sb)
Steve French8af18972007-02-14 04:42:51 +00001784 sb->s_flags |= MS_POSIXACL;
1785 }
1786
Steve French75865f8c2007-06-24 18:30:48 +00001787 if (vol_info && vol_info->posix_paths == 0)
Steve French8af18972007-02-14 04:42:51 +00001788 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00001789 else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001790 cFYI(1, ("negotiate posix pathnames"));
Steve French75865f8c2007-06-24 18:30:48 +00001791 if (sb)
Steve French50c2f752007-07-13 00:33:32 +00001792 CIFS_SB(sb)->mnt_cifs_flags |=
Steve French8af18972007-02-14 04:42:51 +00001793 CIFS_MOUNT_POSIX_PATHS;
1794 }
Steve French50c2f752007-07-13 00:33:32 +00001795
Steve French984acfe2007-04-26 16:42:50 +00001796 /* We might be setting the path sep back to a different
1797 form if we are reconnecting and the server switched its
Steve French50c2f752007-07-13 00:33:32 +00001798 posix path capability for this share */
Steve French75865f8c2007-06-24 18:30:48 +00001799 if (sb && (CIFS_SB(sb)->prepathlen > 0))
Steve French984acfe2007-04-26 16:42:50 +00001800 CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
Steve French75865f8c2007-06-24 18:30:48 +00001801
1802 if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
1803 if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
1804 CIFS_SB(sb)->rsize = 127 * 1024;
Steve French90c81e02008-02-12 20:32:36 +00001805 cFYI(DBG2,
1806 ("larger reads not supported by srv"));
Steve French75865f8c2007-06-24 18:30:48 +00001807 }
1808 }
Steve French50c2f752007-07-13 00:33:32 +00001809
1810
1811 cFYI(1, ("Negotiate caps 0x%x", (int)cap));
Steve French8af18972007-02-14 04:42:51 +00001812#ifdef CONFIG_CIFS_DEBUG2
Steve French75865f8c2007-06-24 18:30:48 +00001813 if (cap & CIFS_UNIX_FCNTL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001814 cFYI(1, ("FCNTL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001815 if (cap & CIFS_UNIX_EXTATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001816 cFYI(1, ("EXTATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001817 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001818 cFYI(1, ("POSIX path cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001819 if (cap & CIFS_UNIX_XATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001820 cFYI(1, ("XATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001821 if (cap & CIFS_UNIX_POSIX_ACL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001822 cFYI(1, ("POSIX ACL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001823 if (cap & CIFS_UNIX_LARGE_READ_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001824 cFYI(1, ("very large read cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001825 if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001826 cFYI(1, ("very large write cap"));
Steve French8af18972007-02-14 04:42:51 +00001827#endif /* CIFS_DEBUG2 */
1828 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
Steve French442aa312007-09-24 20:25:46 +00001829 if (vol_info == NULL) {
Steve French5a44b312007-09-20 15:16:24 +00001830 cFYI(1, ("resetting capabilities failed"));
Steve French442aa312007-09-24 20:25:46 +00001831 } else
Steve French5a44b312007-09-20 15:16:24 +00001832 cERROR(1, ("Negotiating Unix capabilities "
1833 "with the server failed. Consider "
1834 "mounting with the Unix Extensions\n"
1835 "disabled, if problems are found, "
1836 "by specifying the nounix mount "
Steve French2224f4e2007-09-20 15:37:29 +00001837 "option."));
Steve French5a44b312007-09-20 15:16:24 +00001838
Steve French8af18972007-02-14 04:42:51 +00001839 }
1840 }
1841}
1842
Steve French03a143c2008-02-14 06:38:30 +00001843static void
1844convert_delimiter(char *path, char delim)
1845{
1846 int i;
Steve Frenchc2d68ea2008-02-15 19:20:18 +00001847 char old_delim;
Steve French03a143c2008-02-14 06:38:30 +00001848
1849 if (path == NULL)
1850 return;
1851
Steve French582d21e2008-05-13 04:54:12 +00001852 if (delim == '/')
Steve Frenchc2d68ea2008-02-15 19:20:18 +00001853 old_delim = '\\';
1854 else
1855 old_delim = '/';
1856
Steve French03a143c2008-02-14 06:38:30 +00001857 for (i = 0; path[i] != '\0'; i++) {
Steve Frenchc2d68ea2008-02-15 19:20:18 +00001858 if (path[i] == old_delim)
Steve French03a143c2008-02-14 06:38:30 +00001859 path[i] = delim;
1860 }
1861}
1862
Steve French3b795212008-11-13 19:45:32 +00001863static void setup_cifs_sb(struct smb_vol *pvolume_info,
1864 struct cifs_sb_info *cifs_sb)
1865{
1866 if (pvolume_info->rsize > CIFSMaxBufSize) {
1867 cERROR(1, ("rsize %d too large, using MaxBufSize",
1868 pvolume_info->rsize));
1869 cifs_sb->rsize = CIFSMaxBufSize;
1870 } else if ((pvolume_info->rsize) &&
1871 (pvolume_info->rsize <= CIFSMaxBufSize))
1872 cifs_sb->rsize = pvolume_info->rsize;
1873 else /* default */
1874 cifs_sb->rsize = CIFSMaxBufSize;
1875
1876 if (pvolume_info->wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
1877 cERROR(1, ("wsize %d too large, using 4096 instead",
1878 pvolume_info->wsize));
1879 cifs_sb->wsize = 4096;
1880 } else if (pvolume_info->wsize)
1881 cifs_sb->wsize = pvolume_info->wsize;
1882 else
1883 cifs_sb->wsize = min_t(const int,
1884 PAGEVEC_SIZE * PAGE_CACHE_SIZE,
1885 127*1024);
1886 /* old default of CIFSMaxBufSize was too small now
1887 that SMB Write2 can send multiple pages in kvec.
1888 RFC1001 does not describe what happens when frame
1889 bigger than 128K is sent so use that as max in
1890 conjunction with 52K kvec constraint on arch with 4K
1891 page size */
1892
1893 if (cifs_sb->rsize < 2048) {
1894 cifs_sb->rsize = 2048;
1895 /* Windows ME may prefer this */
1896 cFYI(1, ("readsize set to minimum: 2048"));
1897 }
1898 /* calculate prepath */
1899 cifs_sb->prepath = pvolume_info->prepath;
1900 if (cifs_sb->prepath) {
1901 cifs_sb->prepathlen = strlen(cifs_sb->prepath);
1902 /* we can not convert the / to \ in the path
1903 separators in the prefixpath yet because we do not
1904 know (until reset_cifs_unix_caps is called later)
1905 whether POSIX PATH CAP is available. We normalize
1906 the / to \ after reset_cifs_unix_caps is called */
1907 pvolume_info->prepath = NULL;
1908 } else
1909 cifs_sb->prepathlen = 0;
1910 cifs_sb->mnt_uid = pvolume_info->linux_uid;
1911 cifs_sb->mnt_gid = pvolume_info->linux_gid;
1912 cifs_sb->mnt_file_mode = pvolume_info->file_mode;
1913 cifs_sb->mnt_dir_mode = pvolume_info->dir_mode;
1914 cFYI(1, ("file mode: 0x%x dir mode: 0x%x",
1915 cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode));
1916
1917 if (pvolume_info->noperm)
1918 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
1919 if (pvolume_info->setuids)
1920 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
1921 if (pvolume_info->server_ino)
1922 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
1923 if (pvolume_info->remap)
1924 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
1925 if (pvolume_info->no_xattr)
1926 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
1927 if (pvolume_info->sfu_emul)
1928 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
1929 if (pvolume_info->nobrl)
1930 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
1931 if (pvolume_info->cifs_acl)
1932 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
1933 if (pvolume_info->override_uid)
1934 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
1935 if (pvolume_info->override_gid)
1936 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
1937 if (pvolume_info->dynperm)
1938 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
1939 if (pvolume_info->direct_io) {
1940 cFYI(1, ("mounting share using direct i/o"));
1941 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
1942 }
1943
1944 if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm))
1945 cERROR(1, ("mount option dynperm ignored if cifsacl "
1946 "mount option supported"));
1947}
1948
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949int
1950cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1951 char *mount_data, const char *devname)
1952{
1953 int rc = 0;
1954 int xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 struct socket *csocket = NULL;
Steve French3ec332e2008-11-14 03:35:10 +00001956 struct sockaddr addr;
1957 struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr;
1958 struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 struct smb_vol volume_info;
1960 struct cifsSesInfo *pSesInfo = NULL;
1961 struct cifsSesInfo *existingCifsSes = NULL;
1962 struct cifsTconInfo *tcon = NULL;
1963 struct TCP_Server_Info *srvTcp = NULL;
1964
1965 xid = GetXid();
1966
1967/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
Steve French50c2f752007-07-13 00:33:32 +00001968
Steve French3ec332e2008-11-14 03:35:10 +00001969 memset(&addr, 0, sizeof(struct sockaddr));
Steve French50c2f752007-07-13 00:33:32 +00001970 memset(&volume_info, 0, sizeof(struct smb_vol));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001972 rc = -EINVAL;
1973 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974 }
1975
Jeff Layton8426c392007-05-05 03:27:49 +00001976 if (volume_info.nullauth) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001977 cFYI(1, ("null user"));
Jeff Layton9b8f5f52007-11-09 23:25:04 +00001978 volume_info.username = "";
Jeff Layton8426c392007-05-05 03:27:49 +00001979 } else if (volume_info.username) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 /* BB fixme parse for domain name here */
Steve French467a8f82007-06-27 22:41:32 +00001981 cFYI(1, ("Username: %s", volume_info.username));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 } else {
Steve Frenchbf820672005-12-01 22:32:42 -08001983 cifserror("No username specified");
Steve French50c2f752007-07-13 00:33:32 +00001984 /* In userspace mount helper we can get user name from alternate
1985 locations such as env variables and files on disk */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001986 rc = -EINVAL;
1987 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 }
1989
1990 if (volume_info.UNCip && volume_info.UNC) {
Steve French50c2f752007-07-13 00:33:32 +00001991 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,
Steve French3ec332e2008-11-14 03:35:10 +00001992 &sin_server->sin_addr.s_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001994 if (rc <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 /* not ipv4 address, try ipv6 */
Steve French50c2f752007-07-13 00:33:32 +00001996 rc = cifs_inet_pton(AF_INET6, volume_info.UNCip,
Steve French3ec332e2008-11-14 03:35:10 +00001997 &sin_server6->sin6_addr.in6_u);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001998 if (rc > 0)
Steve French3ec332e2008-11-14 03:35:10 +00001999 addr.sa_family = AF_INET6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 } else {
Steve French3ec332e2008-11-14 03:35:10 +00002001 addr.sa_family = AF_INET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 }
Steve French50c2f752007-07-13 00:33:32 +00002003
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002004 if (rc <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 /* we failed translating address */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002006 rc = -EINVAL;
2007 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 }
2009
2010 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
2011 /* success */
2012 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002013 } else if (volume_info.UNCip) {
2014 /* BB using ip addr as server name to connect to the
2015 DFS root below */
2016 cERROR(1, ("Connecting to DFS root not implemented yet"));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002017 rc = -EINVAL;
2018 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 } else /* which servers DFS root would we conect to */ {
2020 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00002021 ("CIFS mount error: No UNC path (e.g. -o "
2022 "unc=//192.168.1.100/public) specified"));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002023 rc = -EINVAL;
2024 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025 }
2026
2027 /* this is needed for ASCII cp to Unicode converts */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002028 if (volume_info.iocharset == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 cifs_sb->local_nls = load_nls_default();
2030 /* load_nls_default can not return null */
2031 } else {
2032 cifs_sb->local_nls = load_nls(volume_info.iocharset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002033 if (cifs_sb->local_nls == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002034 cERROR(1, ("CIFS mount error: iocharset %s not found",
2035 volume_info.iocharset));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002036 rc = -ELIBACC;
2037 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 }
2039 }
2040
Jeff Laytone7ddee92008-11-14 13:44:38 -05002041 srvTcp = cifs_find_tcp_session(&addr);
2042 if (srvTcp) {
2043 cFYI(1, ("Existing tcp session with server found"));
2044 } else { /* create socket */
Steve French3ec332e2008-11-14 03:35:10 +00002045 if (addr.sa_family == AF_INET6) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002046 cFYI(1, ("attempting ipv6 connect"));
Steve French5858ae42007-04-25 11:59:10 +00002047 /* BB should we allow ipv6 on port 139? */
2048 /* other OS never observed in Wild doing 139 with v6 */
Steve French3ec332e2008-11-14 03:35:10 +00002049 sin_server6->sin6_port = htons(volume_info.port);
2050 rc = ipv6_connect(sin_server6, &csocket,
Steve Frenchedf1ae42008-10-29 00:47:57 +00002051 volume_info.noblocksnd);
Steve French3ec332e2008-11-14 03:35:10 +00002052 } else {
2053 sin_server->sin_port = htons(volume_info.port);
2054 rc = ipv4_connect(sin_server, &csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -07002055 volume_info.source_rfc1001_name,
Steve Frenchedf1ae42008-10-29 00:47:57 +00002056 volume_info.target_rfc1001_name,
2057 volume_info.noblocksnd,
2058 volume_info.noautotune);
Steve French3ec332e2008-11-14 03:35:10 +00002059 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060 if (rc < 0) {
Steve French3ec332e2008-11-14 03:35:10 +00002061 cERROR(1, ("Error connecting to socket. "
Steve French50c2f752007-07-13 00:33:32 +00002062 "Aborting operation"));
Steve French4523cc32007-04-30 20:13:06 +00002063 if (csocket != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 sock_release(csocket);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002065 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066 }
2067
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00002068 srvTcp = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
2069 if (!srvTcp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 rc = -ENOMEM;
2071 sock_release(csocket);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002072 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073 } else {
Steve Frenchedf1ae42008-10-29 00:47:57 +00002074 srvTcp->noblocksnd = volume_info.noblocksnd;
2075 srvTcp->noautotune = volume_info.noautotune;
Steve French3ec332e2008-11-14 03:35:10 +00002076 if (addr.sa_family == AF_INET6)
2077 memcpy(&srvTcp->addr.sockAddr6, sin_server6,
2078 sizeof(struct sockaddr_in6));
2079 else
2080 memcpy(&srvTcp->addr.sockAddr, sin_server,
2081 sizeof(struct sockaddr_in));
Steve French50c2f752007-07-13 00:33:32 +00002082 atomic_set(&srvTcp->inFlight, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083 /* BB Add code for ipv6 case too */
2084 srvTcp->ssocket = csocket;
Jeff Laytonc359cf32007-11-16 22:22:06 +00002085 srvTcp->hostname = extract_hostname(volume_info.UNC);
2086 if (IS_ERR(srvTcp->hostname)) {
2087 rc = PTR_ERR(srvTcp->hostname);
2088 sock_release(csocket);
2089 goto out;
2090 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 init_waitqueue_head(&srvTcp->response_q);
2092 init_waitqueue_head(&srvTcp->request_q);
2093 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
2094 /* at this point we are the only ones with the pointer
2095 to the struct since the kernel thread not created yet
2096 so no need to spinlock this init of tcpStatus */
2097 srvTcp->tcpStatus = CifsNew;
2098 init_MUTEX(&srvTcp->tcpSem);
Igor Mammedovaaf737a2007-04-03 19:16:43 +00002099 srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd");
Steve French8840dee2007-11-16 23:05:52 +00002100 if (IS_ERR(srvTcp->tsk)) {
Igor Mammedovaaf737a2007-04-03 19:16:43 +00002101 rc = PTR_ERR(srvTcp->tsk);
Steve French50c2f752007-07-13 00:33:32 +00002102 cERROR(1, ("error %d create cifsd thread", rc));
Igor Mammedovaaf737a2007-04-03 19:16:43 +00002103 srvTcp->tsk = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104 sock_release(csocket);
Jeff Laytonc359cf32007-11-16 22:22:06 +00002105 kfree(srvTcp->hostname);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002106 goto out;
Steve Frenchf1914012005-08-18 09:37:34 -07002107 }
Steve Frenchf1914012005-08-18 09:37:34 -07002108 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002109 memcpy(srvTcp->workstation_RFC1001_name,
2110 volume_info.source_rfc1001_name, 16);
2111 memcpy(srvTcp->server_RFC1001_name,
2112 volume_info.target_rfc1001_name, 16);
Steve Frenchad009ac2005-04-28 22:41:05 -07002113 srvTcp->sequence_number = 0;
Jeff Laytone7ddee92008-11-14 13:44:38 -05002114 INIT_LIST_HEAD(&srvTcp->tcp_ses_list);
2115 ++srvTcp->srv_count;
2116 write_lock(&cifs_tcp_ses_lock);
2117 list_add(&srvTcp->tcp_ses_list,
2118 &cifs_tcp_ses_list);
2119 write_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 }
2121 }
2122
2123 if (existingCifsSes) {
2124 pSesInfo = existingCifsSes;
Jeff Layton1d9a8852007-12-31 01:37:11 +00002125 cFYI(1, ("Existing smb sess found (status=%d)",
2126 pSesInfo->status));
Steve French88e7d702008-01-03 17:37:09 +00002127 down(&pSesInfo->sesSem);
Steve French3b795212008-11-13 19:45:32 +00002128 if (pSesInfo->need_reconnect) {
Jeff Layton1d9a8852007-12-31 01:37:11 +00002129 cFYI(1, ("Session needs reconnect"));
Jeff Layton1d9a8852007-12-31 01:37:11 +00002130 rc = cifs_setup_session(xid, pSesInfo,
2131 cifs_sb->local_nls);
Jeff Layton1d9a8852007-12-31 01:37:11 +00002132 }
Steve French88e7d702008-01-03 17:37:09 +00002133 up(&pSesInfo->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134 } else if (!rc) {
Steve Frenchbf820672005-12-01 22:32:42 -08002135 cFYI(1, ("Existing smb sess not found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136 pSesInfo = sesInfoAlloc();
2137 if (pSesInfo == NULL)
2138 rc = -ENOMEM;
2139 else {
2140 pSesInfo->server = srvTcp;
2141 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
Steve French3ec332e2008-11-14 03:35:10 +00002142 NIPQUAD(sin_server->sin_addr.s_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143 }
2144
Steve French50c2f752007-07-13 00:33:32 +00002145 if (!rc) {
2146 /* volume_info.password freed at unmount */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002147 if (volume_info.password) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148 pSesInfo->password = volume_info.password;
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002149 /* set to NULL to prevent freeing on exit */
2150 volume_info.password = NULL;
2151 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152 if (volume_info.username)
2153 strncpy(pSesInfo->userName,
Steve French50c2f752007-07-13 00:33:32 +00002154 volume_info.username,
2155 MAX_USERNAME_SIZE);
Steve French39798772006-05-31 22:40:51 +00002156 if (volume_info.domainname) {
2157 int len = strlen(volume_info.domainname);
Steve French50c2f752007-07-13 00:33:32 +00002158 pSesInfo->domainName =
Steve French39798772006-05-31 22:40:51 +00002159 kmalloc(len + 1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00002160 if (pSesInfo->domainName)
Steve French39798772006-05-31 22:40:51 +00002161 strcpy(pSesInfo->domainName,
2162 volume_info.domainname);
2163 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 pSesInfo->linux_uid = volume_info.linux_uid;
Steve French750d1152006-06-27 06:28:30 +00002165 pSesInfo->overrideSecFlg = volume_info.secFlg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 down(&pSesInfo->sesSem);
Steve French189acaa2006-06-23 02:33:48 +00002167 /* BB FIXME need to pass vol->secFlgs BB */
Steve French50c2f752007-07-13 00:33:32 +00002168 rc = cifs_setup_session(xid, pSesInfo,
2169 cifs_sb->local_nls);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170 up(&pSesInfo->sesSem);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002171 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172 }
Steve French50c2f752007-07-13 00:33:32 +00002173
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174 /* search for existing tcon to this server share */
2175 if (!rc) {
Steve French3b795212008-11-13 19:45:32 +00002176 setup_cifs_sb(&volume_info, cifs_sb);
Steve French27adb442008-05-23 19:43:29 +00002177
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178 if (tcon) {
Steve Frenchbf820672005-12-01 22:32:42 -08002179 cFYI(1, ("Found match on UNC path"));
Steve French95b1cb92008-05-15 16:44:38 +00002180 if (tcon->seal != volume_info.seal)
2181 cERROR(1, ("transport encryption setting "
2182 "conflicts with existing tid"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 } else {
2184 tcon = tconInfoAlloc();
Steve French3b795212008-11-13 19:45:32 +00002185 if (tcon == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186 rc = -ENOMEM;
Steve French3b795212008-11-13 19:45:32 +00002187 goto mount_fail_check;
2188 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189
Steve French3b795212008-11-13 19:45:32 +00002190 /* check for null share name ie connect to dfs root */
2191
2192 /* BB check if works for exactly length 3 strings */
2193 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
2194 && (strchr(volume_info.UNC + 3, '/') == NULL)) {
2195 /* rc = connect_to_dfs_path(...) */
2196 cFYI(1, ("DFS root not supported"));
2197 rc = -ENODEV;
2198 goto mount_fail_check;
2199 } else {
2200 /* BB Do we need to wrap sesSem around
2201 * this TCon call and Unix SetFS as
2202 * we do on SessSetup and reconnect? */
2203 rc = CIFSTCon(xid, pSesInfo, volume_info.UNC,
2204 tcon, cifs_sb->local_nls);
2205 cFYI(1, ("CIFS Tcon rc = %d", rc));
2206 if (volume_info.nodfs) {
2207 tcon->Flags &= ~SMB_SHARE_IS_IN_DFS;
2208 cFYI(1, ("DFS disabled (%d)",
2209 tcon->Flags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210 }
2211 }
Steve French3b795212008-11-13 19:45:32 +00002212 if (!rc) {
2213 atomic_inc(&pSesInfo->inUse);
2214 tcon->seal = volume_info.seal;
2215 } else
2216 goto mount_fail_check;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217 }
Steve French3b795212008-11-13 19:45:32 +00002218
2219 /* we can have only one retry value for a connection
2220 to a share so for resources mounted more than once
2221 to the same server share the last value passed in
2222 for the retry flag is used */
2223 tcon->retry = volume_info.retry;
2224 tcon->nocase = volume_info.nocase;
2225 tcon->local_lease = volume_info.local_lease;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226 }
Steve French4523cc32007-04-30 20:13:06 +00002227 if (pSesInfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
2229 sb->s_maxbytes = (u64) 1 << 63;
2230 } else
2231 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
2232 }
2233
Steve French8af18972007-02-14 04:42:51 +00002234 /* BB FIXME fix time_gran to be larger for LANMAN sessions */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235 sb->s_time_gran = 100;
2236
2237/* on error free sesinfo and tcon struct if needed */
Steve French3b795212008-11-13 19:45:32 +00002238mount_fail_check:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239 if (rc) {
Jeff Laytone7ddee92008-11-14 13:44:38 -05002240 /* If find_unc succeeded then rc == 0 so we can not end */
2241 /* up accidently freeing someone elses tcon struct */
2242 if (tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 tconInfoFree(tcon);
Jeff Laytone7ddee92008-11-14 13:44:38 -05002244
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245 if (existingCifsSes == NULL) {
2246 if (pSesInfo) {
Steve French50c2f752007-07-13 00:33:32 +00002247 if ((pSesInfo->server) &&
Jeff Laytone7ddee92008-11-14 13:44:38 -05002248 (pSesInfo->status == CifsGood))
2249 CIFSSMBLogoff(xid, pSesInfo);
2250 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 cFYI(1, ("No session or bad tcon"));
Jeff Laytone7ddee92008-11-14 13:44:38 -05002252 if (pSesInfo->server)
2253 cifs_put_tcp_session(
2254 pSesInfo->server);
Steve Frencha0136892007-10-04 20:05:09 +00002255 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256 sesInfoFree(pSesInfo);
2257 /* pSesInfo = NULL; */
2258 }
2259 }
2260 } else {
2261 atomic_inc(&tcon->useCount);
2262 cifs_sb->tcon = tcon;
2263 tcon->ses = pSesInfo;
2264
Steve French82940a42006-03-02 03:24:57 +00002265 /* do not care if following two calls succeed - informational */
Steve French7f8ed422007-09-28 22:28:55 +00002266 if (!tcon->ipc) {
2267 CIFSSMBQFSDeviceInfo(xid, tcon);
2268 CIFSSMBQFSAttributeInfo(xid, tcon);
2269 }
Steve French50c2f752007-07-13 00:33:32 +00002270
Steve French8af18972007-02-14 04:42:51 +00002271 /* tell server which Unix caps we support */
2272 if (tcon->ses->capabilities & CAP_UNIX)
Steve Frenchc18c8422007-07-18 23:21:09 +00002273 /* reset of caps checks mount to see if unix extensions
2274 disabled for just this mount */
Steve French8af18972007-02-14 04:42:51 +00002275 reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
Steve Frenchc18c8422007-07-18 23:21:09 +00002276 else
2277 tcon->unix_ext = 0; /* server does not support them */
2278
Steve French03a143c2008-02-14 06:38:30 +00002279 /* convert forward to back slashes in prepath here if needed */
Igor Mammedov11b6d642008-02-15 19:06:04 +00002280 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
2281 convert_delimiter(cifs_sb->prepath,
2282 CIFS_DIR_SEP(cifs_sb));
Steve French03a143c2008-02-14 06:38:30 +00002283
Steve Frenchc18c8422007-07-18 23:21:09 +00002284 if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
Steve French75865f8c2007-06-24 18:30:48 +00002285 cifs_sb->rsize = 1024 * 127;
Steve French90c81e02008-02-12 20:32:36 +00002286 cFYI(DBG2,
2287 ("no very large read support, rsize now 127K"));
Steve French75865f8c2007-06-24 18:30:48 +00002288 }
Steve French3e844692005-10-03 13:37:24 -07002289 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
2290 cifs_sb->wsize = min(cifs_sb->wsize,
2291 (tcon->ses->server->maxBuf -
2292 MAX_CIFS_HDR_SIZE));
Steve French0ae0efa2005-10-10 10:57:19 -07002293 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
Steve French50c2f752007-07-13 00:33:32 +00002294 cifs_sb->rsize = min(cifs_sb->rsize,
2295 (tcon->ses->server->maxBuf -
2296 MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297 }
2298
2299 /* volume_info.password is freed above when existing session found
2300 (in which case it is not needed anymore) but when new sesion is created
2301 the password ptr is put in the new session structure (in which case the
2302 password will be freed at unmount time) */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002303out:
2304 /* zero out password before freeing */
2305 if (volume_info.password != NULL) {
2306 memset(volume_info.password, 0, strlen(volume_info.password));
2307 kfree(volume_info.password);
2308 }
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002309 kfree(volume_info.UNC);
Steve French2fe87f02006-09-21 07:02:52 +00002310 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311 FreeXid(xid);
2312 return rc;
2313}
2314
2315static int
2316CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French7c7b25b2006-06-01 19:20:10 +00002317 char session_key[CIFS_SESS_KEY_SIZE],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318 const struct nls_table *nls_codepage)
2319{
2320 struct smb_hdr *smb_buffer;
2321 struct smb_hdr *smb_buffer_response;
2322 SESSION_SETUP_ANDX *pSMB;
2323 SESSION_SETUP_ANDX *pSMBr;
2324 char *bcc_ptr;
2325 char *user;
2326 char *domain;
2327 int rc = 0;
2328 int remaining_words = 0;
2329 int bytes_returned = 0;
2330 int len;
2331 __u32 capabilities;
2332 __u16 count;
2333
Steve Frencheeac8042006-01-13 21:34:58 -08002334 cFYI(1, ("In sesssetup"));
Steve French4523cc32007-04-30 20:13:06 +00002335 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336 return -EINVAL;
2337 user = ses->userName;
2338 domain = ses->domainName;
2339 smb_buffer = cifs_buf_get();
Steve French582d21e2008-05-13 04:54:12 +00002340
2341 if (smb_buffer == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342 return -ENOMEM;
Steve French582d21e2008-05-13 04:54:12 +00002343
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344 smb_buffer_response = smb_buffer;
2345 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2346
2347 /* send SMBsessionSetup here */
2348 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2349 NULL /* no tCon exists yet */ , 13 /* wct */ );
2350
Steve French1982c342005-08-17 12:38:22 -07002351 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 pSMB->req_no_secext.AndXCommand = 0xFF;
2353 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2354 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2355
Steve French50c2f752007-07-13 00:33:32 +00002356 if (ses->server->secMode &
2357 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2359
2360 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2361 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
2362 if (ses->capabilities & CAP_UNICODE) {
2363 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2364 capabilities |= CAP_UNICODE;
2365 }
2366 if (ses->capabilities & CAP_STATUS32) {
2367 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2368 capabilities |= CAP_STATUS32;
2369 }
2370 if (ses->capabilities & CAP_DFS) {
2371 smb_buffer->Flags2 |= SMBFLG2_DFS;
2372 capabilities |= CAP_DFS;
2373 }
2374 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
2375
Steve French50c2f752007-07-13 00:33:32 +00002376 pSMB->req_no_secext.CaseInsensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002377 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378
2379 pSMB->req_no_secext.CaseSensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002380 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381 bcc_ptr = pByteArea(smb_buffer);
Steve French7c7b25b2006-06-01 19:20:10 +00002382 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2383 bcc_ptr += CIFS_SESS_KEY_SIZE;
2384 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2385 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386
2387 if (ses->capabilities & CAP_UNICODE) {
2388 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
2389 *bcc_ptr = 0;
2390 bcc_ptr++;
2391 }
Steve French4523cc32007-04-30 20:13:06 +00002392 if (user == NULL)
Steve French39798772006-05-31 22:40:51 +00002393 bytes_returned = 0; /* skip null user */
Steve French50c2f752007-07-13 00:33:32 +00002394 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395 bytes_returned =
Steve French50c2f752007-07-13 00:33:32 +00002396 cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397 nls_codepage);
2398 /* convert number of 16 bit words to bytes */
2399 bcc_ptr += 2 * bytes_returned;
2400 bcc_ptr += 2; /* trailing null */
2401 if (domain == NULL)
2402 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002403 cifs_strtoUCS((__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 "CIFS_LINUX_DOM", 32, nls_codepage);
2405 else
2406 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002407 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 nls_codepage);
2409 bcc_ptr += 2 * bytes_returned;
2410 bcc_ptr += 2;
2411 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002412 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413 32, nls_codepage);
2414 bcc_ptr += 2 * bytes_returned;
2415 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002416 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417 32, nls_codepage);
2418 bcc_ptr += 2 * bytes_returned;
2419 bcc_ptr += 2;
2420 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002421 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 64, nls_codepage);
2423 bcc_ptr += 2 * bytes_returned;
2424 bcc_ptr += 2;
2425 } else {
Steve French50c2f752007-07-13 00:33:32 +00002426 if (user != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427 strncpy(bcc_ptr, user, 200);
2428 bcc_ptr += strnlen(user, 200);
2429 }
2430 *bcc_ptr = 0;
2431 bcc_ptr++;
2432 if (domain == NULL) {
2433 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2434 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2435 } else {
2436 strncpy(bcc_ptr, domain, 64);
2437 bcc_ptr += strnlen(domain, 64);
2438 *bcc_ptr = 0;
2439 bcc_ptr++;
2440 }
2441 strcpy(bcc_ptr, "Linux version ");
2442 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002443 strcpy(bcc_ptr, utsname()->release);
2444 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2446 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2447 }
2448 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2449 smb_buffer->smb_buf_length += count;
2450 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2451
2452 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00002453 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454 if (rc) {
2455/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2456 } else if ((smb_buffer_response->WordCount == 3)
2457 || (smb_buffer_response->WordCount == 4)) {
2458 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2459 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2460 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002461 cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */
2462 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format
2463 (little endian) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 cFYI(1, ("UID = %d ", ses->Suid));
Steve French50c2f752007-07-13 00:33:32 +00002465 /* response can have either 3 or 4 word count - Samba sends 3 */
2466 bcc_ptr = pByteArea(smb_buffer_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467 if ((pSMBr->resp.hdr.WordCount == 3)
2468 || ((pSMBr->resp.hdr.WordCount == 4)
2469 && (blob_len < pSMBr->resp.ByteCount))) {
2470 if (pSMBr->resp.hdr.WordCount == 4)
2471 bcc_ptr += blob_len;
2472
2473 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2474 if ((long) (bcc_ptr) % 2) {
2475 remaining_words =
Steve French50c2f752007-07-13 00:33:32 +00002476 (BCC(smb_buffer_response) - 1) / 2;
2477 /* Unicode strings must be word
2478 aligned */
2479 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480 } else {
2481 remaining_words =
2482 BCC(smb_buffer_response) / 2;
2483 }
2484 len =
2485 UniStrnlen((wchar_t *) bcc_ptr,
2486 remaining_words - 1);
2487/* We look for obvious messed up bcc or strings in response so we do not go off
2488 the end since (at least) WIN2K and Windows XP have a major bug in not null
2489 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002490 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002491 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002492 ses->serverOS = kzalloc(2 * (len + 1),
2493 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002494 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002495 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 cifs_strfromUCS_le(ses->serverOS,
Steve French50c2f752007-07-13 00:33:32 +00002497 (__le16 *)bcc_ptr,
2498 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499 bcc_ptr += 2 * (len + 1);
2500 remaining_words -= len + 1;
2501 ses->serverOS[2 * len] = 0;
2502 ses->serverOS[1 + (2 * len)] = 0;
2503 if (remaining_words > 0) {
2504 len = UniStrnlen((wchar_t *)bcc_ptr,
2505 remaining_words-1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002506 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002507 ses->serverNOS = kzalloc(2 * (len + 1),
2508 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002509 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002510 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511 cifs_strfromUCS_le(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002512 (__le16 *)bcc_ptr,
2513 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 bcc_ptr += 2 * (len + 1);
2515 ses->serverNOS[2 * len] = 0;
2516 ses->serverNOS[1 + (2 * len)] = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002517 if (strncmp(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002518 "NT LAN Manager 4", 16) == 0) {
Steve French467a8f82007-06-27 22:41:32 +00002519 cFYI(1, ("NT4 server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520 ses->flags |= CIFS_SES_NT4;
2521 }
2522 remaining_words -= len + 1;
2523 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002524 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Steve French50c2f752007-07-13 00:33:32 +00002525 /* last string is not always null terminated
2526 (for e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002527 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002528 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 ses->serverDomain =
Steve French50c2f752007-07-13 00:33:32 +00002530 kzalloc(2*(len+1),
2531 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002532 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002533 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534 cifs_strfromUCS_le(ses->serverDomain,
Steve French50c2f752007-07-13 00:33:32 +00002535 (__le16 *)bcc_ptr,
2536 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537 bcc_ptr += 2 * (len + 1);
2538 ses->serverDomain[2*len] = 0;
2539 ses->serverDomain[1+(2*len)] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002540 } else { /* else no more room so create
2541 dummy domain string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002542 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002543 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002544 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002545 kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002546 }
Steve French50c2f752007-07-13 00:33:32 +00002547 } else { /* no room so create dummy domain
2548 and NOS string */
2549
Steve French433dc242005-04-28 22:41:08 -07002550 /* if these kcallocs fail not much we
2551 can do, but better to not fail the
2552 sesssetup itself */
Steve Frenchcd49b492006-06-26 04:22:36 +00002553 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002555 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002556 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002558 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559 }
2560 } else { /* ASCII */
2561 len = strnlen(bcc_ptr, 1024);
2562 if (((long) bcc_ptr + len) - (long)
2563 pByteArea(smb_buffer_response)
2564 <= BCC(smb_buffer_response)) {
Steve Frenchcd49b492006-06-26 04:22:36 +00002565 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002566 ses->serverOS = kzalloc(len + 1,
2567 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002568 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002569 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002570 strncpy(ses->serverOS, bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571
2572 bcc_ptr += len;
Steve French50c2f752007-07-13 00:33:32 +00002573 /* null terminate the string */
2574 bcc_ptr[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 bcc_ptr++;
2576
2577 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002578 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002579 ses->serverNOS = kzalloc(len + 1,
2580 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002581 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002582 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583 strncpy(ses->serverNOS, bcc_ptr, len);
2584 bcc_ptr += len;
2585 bcc_ptr[0] = 0;
2586 bcc_ptr++;
2587
2588 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002589 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002590 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002591 ses->serverDomain = kzalloc(len + 1,
2592 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002593 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002594 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002595 strncpy(ses->serverDomain, bcc_ptr,
2596 len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 bcc_ptr += len;
2598 bcc_ptr[0] = 0;
2599 bcc_ptr++;
2600 } else
2601 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00002602 ("Variable field of length %d "
2603 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 len));
2605 }
2606 } else {
2607 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00002608 (" Security Blob Length extends beyond "
2609 "end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610 }
2611 } else {
2612 cERROR(1,
2613 (" Invalid Word count %d: ",
2614 smb_buffer_response->WordCount));
2615 rc = -EIO;
2616 }
Steve French433dc242005-04-28 22:41:08 -07002617sesssetup_nomem: /* do not return an error on nomem for the info strings,
2618 since that could make reconnection harder, and
2619 reconnection might be needed to free memory */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00002620 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621
2622 return rc;
2623}
2624
2625static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
Steve French4b18f2a2008-04-29 00:06:05 +00002627 struct cifsSesInfo *ses, bool *pNTLMv2_flag,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 const struct nls_table *nls_codepage)
2629{
2630 struct smb_hdr *smb_buffer;
2631 struct smb_hdr *smb_buffer_response;
2632 SESSION_SETUP_ANDX *pSMB;
2633 SESSION_SETUP_ANDX *pSMBr;
2634 char *bcc_ptr;
2635 char *domain;
2636 int rc = 0;
2637 int remaining_words = 0;
2638 int bytes_returned = 0;
2639 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002640 int SecurityBlobLength = sizeof(NEGOTIATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 PNEGOTIATE_MESSAGE SecurityBlob;
2642 PCHALLENGE_MESSAGE SecurityBlob2;
2643 __u32 negotiate_flags, capabilities;
2644 __u16 count;
2645
Steve French12b3b8f2006-02-09 21:12:47 +00002646 cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002647 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 return -EINVAL;
2649 domain = ses->domainName;
Steve French4b18f2a2008-04-29 00:06:05 +00002650 *pNTLMv2_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 smb_buffer = cifs_buf_get();
2652 if (smb_buffer == NULL) {
2653 return -ENOMEM;
2654 }
2655 smb_buffer_response = smb_buffer;
2656 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2657 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2658
2659 /* send SMBsessionSetup here */
2660 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2661 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002662
2663 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2665 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2666
2667 pSMB->req.AndXCommand = 0xFF;
2668 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2669 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2670
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002671 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2673
2674 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2675 CAP_EXTENDED_SECURITY;
2676 if (ses->capabilities & CAP_UNICODE) {
2677 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2678 capabilities |= CAP_UNICODE;
2679 }
2680 if (ses->capabilities & CAP_STATUS32) {
2681 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2682 capabilities |= CAP_STATUS32;
2683 }
2684 if (ses->capabilities & CAP_DFS) {
2685 smb_buffer->Flags2 |= SMBFLG2_DFS;
2686 capabilities |= CAP_DFS;
2687 }
2688 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2689
2690 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2691 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2692 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2693 SecurityBlob->MessageType = NtLmNegotiate;
2694 negotiate_flags =
2695 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
Steve French12b3b8f2006-02-09 21:12:47 +00002696 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
2697 NTLMSSP_NEGOTIATE_56 |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002699 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002701/* if (ntlmv2_support)
Steve French39798772006-05-31 22:40:51 +00002702 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 /* setup pointers to domain name and workstation name */
2704 bcc_ptr += SecurityBlobLength;
2705
2706 SecurityBlob->WorkstationName.Buffer = 0;
2707 SecurityBlob->WorkstationName.Length = 0;
2708 SecurityBlob->WorkstationName.MaximumLength = 0;
2709
Steve French12b3b8f2006-02-09 21:12:47 +00002710 /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent
2711 along with username on auth request (ie the response to challenge) */
2712 SecurityBlob->DomainName.Buffer = 0;
2713 SecurityBlob->DomainName.Length = 0;
2714 SecurityBlob->DomainName.MaximumLength = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 if (ses->capabilities & CAP_UNICODE) {
2716 if ((long) bcc_ptr % 2) {
2717 *bcc_ptr = 0;
2718 bcc_ptr++;
2719 }
2720
2721 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002722 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 32, nls_codepage);
2724 bcc_ptr += 2 * bytes_returned;
2725 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002726 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 nls_codepage);
2728 bcc_ptr += 2 * bytes_returned;
2729 bcc_ptr += 2; /* null terminate Linux version */
2730 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002731 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 64, nls_codepage);
2733 bcc_ptr += 2 * bytes_returned;
2734 *(bcc_ptr + 1) = 0;
2735 *(bcc_ptr + 2) = 0;
2736 bcc_ptr += 2; /* null terminate network opsys string */
2737 *(bcc_ptr + 1) = 0;
2738 *(bcc_ptr + 2) = 0;
2739 bcc_ptr += 2; /* null domain */
2740 } else { /* ASCII */
2741 strcpy(bcc_ptr, "Linux version ");
2742 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002743 strcpy(bcc_ptr, utsname()->release);
2744 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2746 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2747 bcc_ptr++; /* empty domain field */
2748 *bcc_ptr = 0;
2749 }
2750 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2751 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2752 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2753 smb_buffer->smb_buf_length += count;
2754 pSMB->req.ByteCount = cpu_to_le16(count);
2755
2756 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00002757 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758
2759 if (smb_buffer_response->Status.CifsError ==
2760 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2761 rc = 0;
2762
2763 if (rc) {
2764/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2765 } else if ((smb_buffer_response->WordCount == 3)
2766 || (smb_buffer_response->WordCount == 4)) {
2767 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2768 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2769
2770 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002771 cFYI(1, (" Guest login"));
2772 /* Do we want to set anything in SesInfo struct when guest login? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773
Steve French50c2f752007-07-13 00:33:32 +00002774 bcc_ptr = pByteArea(smb_buffer_response);
2775 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776
2777 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2778 if (SecurityBlob2->MessageType != NtLmChallenge) {
2779 cFYI(1,
2780 ("Unexpected NTLMSSP message type received %d",
2781 SecurityBlob2->MessageType));
2782 } else if (ses) {
Steve French50c2f752007-07-13 00:33:32 +00002783 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
Steve French12b3b8f2006-02-09 21:12:47 +00002784 cFYI(1, ("UID = %d", ses->Suid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 if ((pSMBr->resp.hdr.WordCount == 3)
2786 || ((pSMBr->resp.hdr.WordCount == 4)
2787 && (blob_len <
2788 pSMBr->resp.ByteCount))) {
2789
2790 if (pSMBr->resp.hdr.WordCount == 4) {
2791 bcc_ptr += blob_len;
Steve French12b3b8f2006-02-09 21:12:47 +00002792 cFYI(1, ("Security Blob Length %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793 blob_len));
2794 }
2795
Steve French12b3b8f2006-02-09 21:12:47 +00002796 cFYI(1, ("NTLMSSP Challenge rcvd"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797
2798 memcpy(ses->server->cryptKey,
2799 SecurityBlob2->Challenge,
2800 CIFS_CRYPTO_KEY_SIZE);
Steve French50c2f752007-07-13 00:33:32 +00002801 if (SecurityBlob2->NegotiateFlags &
Steve French12b3b8f2006-02-09 21:12:47 +00002802 cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
Steve French4b18f2a2008-04-29 00:06:05 +00002803 *pNTLMv2_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804
Steve French50c2f752007-07-13 00:33:32 +00002805 if ((SecurityBlob2->NegotiateFlags &
2806 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807 || (sign_CIFS_PDUs > 1))
Steve French50c2f752007-07-13 00:33:32 +00002808 ses->server->secMode |=
2809 SECMODE_SIGN_REQUIRED;
2810 if ((SecurityBlob2->NegotiateFlags &
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
Steve French50c2f752007-07-13 00:33:32 +00002812 ses->server->secMode |=
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 SECMODE_SIGN_ENABLED;
2814
2815 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2816 if ((long) (bcc_ptr) % 2) {
2817 remaining_words =
2818 (BCC(smb_buffer_response)
2819 - 1) / 2;
Steve French50c2f752007-07-13 00:33:32 +00002820 /* Must word align unicode strings */
2821 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822 } else {
2823 remaining_words =
2824 BCC
2825 (smb_buffer_response) / 2;
2826 }
2827 len =
2828 UniStrnlen((wchar_t *) bcc_ptr,
2829 remaining_words - 1);
2830/* We look for obvious messed up bcc or strings in response so we do not go off
2831 the end since (at least) WIN2K and Windows XP have a major bug in not null
2832 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002833 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002834 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002836 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002838 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839 bcc_ptr, len,
2840 nls_codepage);
2841 bcc_ptr += 2 * (len + 1);
2842 remaining_words -= len + 1;
2843 ses->serverOS[2 * len] = 0;
2844 ses->serverOS[1 + (2 * len)] = 0;
2845 if (remaining_words > 0) {
2846 len = UniStrnlen((wchar_t *)
2847 bcc_ptr,
2848 remaining_words
2849 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002850 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002852 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853 GFP_KERNEL);
2854 cifs_strfromUCS_le(ses->
2855 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002856 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857 bcc_ptr,
2858 len,
2859 nls_codepage);
2860 bcc_ptr += 2 * (len + 1);
2861 ses->serverNOS[2 * len] = 0;
2862 ses->serverNOS[1 +
2863 (2 * len)] = 0;
2864 remaining_words -= len + 1;
2865 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00002866 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2867 /* last string not always null terminated
2868 (for e.g. for Windows XP & 2000) */
Steve Frenchcd49b492006-06-26 04:22:36 +00002869 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002871 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872 (len +
2873 1),
2874 GFP_KERNEL);
2875 cifs_strfromUCS_le
Steve Frenche89dc922005-11-11 15:18:19 -08002876 (ses->serverDomain,
2877 (__le16 *)bcc_ptr,
2878 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 bcc_ptr +=
2880 2 * (len + 1);
Steve Frenche89dc922005-11-11 15:18:19 -08002881 ses->serverDomain[2*len]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882 = 0;
Steve Frenche89dc922005-11-11 15:18:19 -08002883 ses->serverDomain
2884 [1 + (2 * len)]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885 = 0;
2886 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002887 else {
Steve Frenchcd49b492006-06-26 04:22:36 +00002888 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002890 kzalloc(2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002892 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893 } else { /* no room so create dummy domain and NOS string */
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, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002897 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002899 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002900 }
2901 } else { /* ASCII */
2902 len = strnlen(bcc_ptr, 1024);
2903 if (((long) bcc_ptr + len) - (long)
2904 pByteArea(smb_buffer_response)
2905 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002906 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002907 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002909 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910 GFP_KERNEL);
2911 strncpy(ses->serverOS,
2912 bcc_ptr, len);
2913
2914 bcc_ptr += len;
2915 bcc_ptr[0] = 0; /* null terminate string */
2916 bcc_ptr++;
2917
2918 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002919 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002921 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922 GFP_KERNEL);
2923 strncpy(ses->serverNOS, bcc_ptr, len);
2924 bcc_ptr += len;
2925 bcc_ptr[0] = 0;
2926 bcc_ptr++;
2927
2928 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002929 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002931 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +00002933 strncpy(ses->serverDomain,
2934 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935 bcc_ptr += len;
2936 bcc_ptr[0] = 0;
2937 bcc_ptr++;
2938 } else
2939 cFYI(1,
Steve French63135e02007-07-17 17:34:02 +00002940 ("field of length %d "
2941 "extends beyond end of smb",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942 len));
2943 }
2944 } else {
Steve French50c2f752007-07-13 00:33:32 +00002945 cERROR(1, ("Security Blob Length extends beyond"
2946 " end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947 }
2948 } else {
2949 cERROR(1, ("No session structure passed in."));
2950 }
2951 } else {
2952 cERROR(1,
Steve French5815449d2006-02-14 01:36:20 +00002953 (" Invalid Word count %d:",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954 smb_buffer_response->WordCount));
2955 rc = -EIO;
2956 }
2957
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00002958 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959
2960 return rc;
2961}
2962static int
2963CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French4b18f2a2008-04-29 00:06:05 +00002964 char *ntlm_session_key, bool ntlmv2_flag,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002965 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966{
2967 struct smb_hdr *smb_buffer;
2968 struct smb_hdr *smb_buffer_response;
2969 SESSION_SETUP_ANDX *pSMB;
2970 SESSION_SETUP_ANDX *pSMBr;
2971 char *bcc_ptr;
2972 char *user;
2973 char *domain;
2974 int rc = 0;
2975 int remaining_words = 0;
2976 int bytes_returned = 0;
2977 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002978 int SecurityBlobLength = sizeof(AUTHENTICATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979 PAUTHENTICATE_MESSAGE SecurityBlob;
2980 __u32 negotiate_flags, capabilities;
2981 __u16 count;
2982
2983 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002984 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985 return -EINVAL;
2986 user = ses->userName;
2987 domain = ses->domainName;
2988 smb_buffer = cifs_buf_get();
2989 if (smb_buffer == NULL) {
2990 return -ENOMEM;
2991 }
2992 smb_buffer_response = smb_buffer;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002993 pSMB = (SESSION_SETUP_ANDX *)smb_buffer;
2994 pSMBr = (SESSION_SETUP_ANDX *)smb_buffer_response;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995
2996 /* send SMBsessionSetup here */
2997 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2998 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002999
3000 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
3002 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
3003 pSMB->req.AndXCommand = 0xFF;
3004 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
3005 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
3006
3007 pSMB->req.hdr.Uid = ses->Suid;
3008
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003009 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3011
3012 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003013 CAP_EXTENDED_SECURITY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014 if (ses->capabilities & CAP_UNICODE) {
3015 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3016 capabilities |= CAP_UNICODE;
3017 }
3018 if (ses->capabilities & CAP_STATUS32) {
3019 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3020 capabilities |= CAP_STATUS32;
3021 }
3022 if (ses->capabilities & CAP_DFS) {
3023 smb_buffer->Flags2 |= SMBFLG2_DFS;
3024 capabilities |= CAP_DFS;
3025 }
3026 pSMB->req.Capabilities = cpu_to_le32(capabilities);
3027
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003028 bcc_ptr = (char *)&pSMB->req.SecurityBlob;
3029 SecurityBlob = (PAUTHENTICATE_MESSAGE)bcc_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
3031 SecurityBlob->MessageType = NtLmAuthenticate;
3032 bcc_ptr += SecurityBlobLength;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003033 negotiate_flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
3034 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
3035 0x80000000 | NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003036 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003038 if (ntlmv2_flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
3040
3041/* setup pointers to domain name and workstation name */
3042
3043 SecurityBlob->WorkstationName.Buffer = 0;
3044 SecurityBlob->WorkstationName.Length = 0;
3045 SecurityBlob->WorkstationName.MaximumLength = 0;
3046 SecurityBlob->SessionKey.Length = 0;
3047 SecurityBlob->SessionKey.MaximumLength = 0;
3048 SecurityBlob->SessionKey.Buffer = 0;
3049
3050 SecurityBlob->LmChallengeResponse.Length = 0;
3051 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
3052 SecurityBlob->LmChallengeResponse.Buffer = 0;
3053
3054 SecurityBlob->NtChallengeResponse.Length =
Steve French7c7b25b2006-06-01 19:20:10 +00003055 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056 SecurityBlob->NtChallengeResponse.MaximumLength =
Steve French7c7b25b2006-06-01 19:20:10 +00003057 cpu_to_le16(CIFS_SESS_KEY_SIZE);
3058 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059 SecurityBlob->NtChallengeResponse.Buffer =
3060 cpu_to_le32(SecurityBlobLength);
Steve French7c7b25b2006-06-01 19:20:10 +00003061 SecurityBlobLength += CIFS_SESS_KEY_SIZE;
3062 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063
3064 if (ses->capabilities & CAP_UNICODE) {
3065 if (domain == NULL) {
3066 SecurityBlob->DomainName.Buffer = 0;
3067 SecurityBlob->DomainName.Length = 0;
3068 SecurityBlob->DomainName.MaximumLength = 0;
3069 } else {
Steve French77159b42007-08-31 01:10:17 +00003070 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00003072 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003074 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075 SecurityBlob->DomainName.Buffer =
3076 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003077 bcc_ptr += ln;
3078 SecurityBlobLength += ln;
3079 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080 }
3081 if (user == NULL) {
3082 SecurityBlob->UserName.Buffer = 0;
3083 SecurityBlob->UserName.Length = 0;
3084 SecurityBlob->UserName.MaximumLength = 0;
3085 } else {
Steve French77159b42007-08-31 01:10:17 +00003086 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00003088 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089 SecurityBlob->UserName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003090 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091 SecurityBlob->UserName.Buffer =
3092 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003093 bcc_ptr += ln;
3094 SecurityBlobLength += ln;
3095 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096 }
3097
Steve French63135e02007-07-17 17:34:02 +00003098 /* SecurityBlob->WorkstationName.Length =
3099 cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100 SecurityBlob->WorkstationName.Length *= 2;
Steve French63135e02007-07-17 17:34:02 +00003101 SecurityBlob->WorkstationName.MaximumLength =
3102 cpu_to_le16(SecurityBlob->WorkstationName.Length);
3103 SecurityBlob->WorkstationName.Buffer =
3104 cpu_to_le32(SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105 bcc_ptr += SecurityBlob->WorkstationName.Length;
3106 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
Steve French63135e02007-07-17 17:34:02 +00003107 SecurityBlob->WorkstationName.Length =
3108 cpu_to_le16(SecurityBlob->WorkstationName.Length); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109
3110 if ((long) bcc_ptr % 2) {
3111 *bcc_ptr = 0;
3112 bcc_ptr++;
3113 }
3114 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003115 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116 32, nls_codepage);
3117 bcc_ptr += 2 * bytes_returned;
3118 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003119 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120 nls_codepage);
3121 bcc_ptr += 2 * bytes_returned;
3122 bcc_ptr += 2; /* null term version string */
3123 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003124 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125 64, nls_codepage);
3126 bcc_ptr += 2 * bytes_returned;
3127 *(bcc_ptr + 1) = 0;
3128 *(bcc_ptr + 2) = 0;
3129 bcc_ptr += 2; /* null terminate network opsys string */
3130 *(bcc_ptr + 1) = 0;
3131 *(bcc_ptr + 2) = 0;
3132 bcc_ptr += 2; /* null domain */
3133 } else { /* ASCII */
3134 if (domain == NULL) {
3135 SecurityBlob->DomainName.Buffer = 0;
3136 SecurityBlob->DomainName.Length = 0;
3137 SecurityBlob->DomainName.MaximumLength = 0;
3138 } else {
Steve French77159b42007-08-31 01:10:17 +00003139 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
3141 strncpy(bcc_ptr, domain, 63);
Steve French77159b42007-08-31 01:10:17 +00003142 ln = strnlen(domain, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003144 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003145 SecurityBlob->DomainName.Buffer =
3146 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003147 bcc_ptr += ln;
3148 SecurityBlobLength += ln;
3149 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150 }
3151 if (user == NULL) {
3152 SecurityBlob->UserName.Buffer = 0;
3153 SecurityBlob->UserName.Length = 0;
3154 SecurityBlob->UserName.MaximumLength = 0;
3155 } else {
Steve French77159b42007-08-31 01:10:17 +00003156 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003157 strncpy(bcc_ptr, user, 63);
Steve French77159b42007-08-31 01:10:17 +00003158 ln = strnlen(user, 64);
3159 SecurityBlob->UserName.MaximumLength = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160 SecurityBlob->UserName.Buffer =
Steve French77159b42007-08-31 01:10:17 +00003161 cpu_to_le32(SecurityBlobLength);
3162 bcc_ptr += ln;
3163 SecurityBlobLength += ln;
3164 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165 }
3166 /* BB fill in our workstation name if known BB */
3167
3168 strcpy(bcc_ptr, "Linux version ");
3169 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003170 strcpy(bcc_ptr, utsname()->release);
3171 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
3173 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
3174 bcc_ptr++; /* null domain */
3175 *bcc_ptr = 0;
3176 }
3177 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
3178 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
3179 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
3180 smb_buffer->smb_buf_length += count;
3181 pSMB->req.ByteCount = cpu_to_le16(count);
3182
3183 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00003184 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185 if (rc) {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003186/* rc = map_smb_to_linux_error(smb_buffer_response) done in SendReceive now */
3187 } else if ((smb_buffer_response->WordCount == 3) ||
3188 (smb_buffer_response->WordCount == 4)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189 __u16 action = le16_to_cpu(pSMBr->resp.Action);
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003190 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00003192 cFYI(1, (" Guest login")); /* BB Should we set anything
3193 in SesInfo struct ? */
3194/* if (SecurityBlob2->MessageType != NtLm??) {
3195 cFYI("Unexpected message type on auth response is %d"));
3196 } */
3197
Linus Torvalds1da177e2005-04-16 15:20:36 -07003198 if (ses) {
3199 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003200 ("Check challenge UID %d vs auth response UID %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201 ses->Suid, smb_buffer_response->Uid));
Steve French50c2f752007-07-13 00:33:32 +00003202 /* UID left in wire format */
3203 ses->Suid = smb_buffer_response->Uid;
3204 bcc_ptr = pByteArea(smb_buffer_response);
3205 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003206 if ((pSMBr->resp.hdr.WordCount == 3)
3207 || ((pSMBr->resp.hdr.WordCount == 4)
3208 && (blob_len <
3209 pSMBr->resp.ByteCount))) {
3210 if (pSMBr->resp.hdr.WordCount == 4) {
3211 bcc_ptr +=
3212 blob_len;
3213 cFYI(1,
3214 ("Security Blob Length %d ",
3215 blob_len));
3216 }
3217
3218 cFYI(1,
3219 ("NTLMSSP response to Authenticate "));
3220
3221 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3222 if ((long) (bcc_ptr) % 2) {
3223 remaining_words =
3224 (BCC(smb_buffer_response)
3225 - 1) / 2;
3226 bcc_ptr++; /* Unicode strings must be word aligned */
3227 } else {
3228 remaining_words = BCC(smb_buffer_response) / 2;
3229 }
Steve French77159b42007-08-31 01:10:17 +00003230 len = UniStrnlen((wchar_t *) bcc_ptr,
3231 remaining_words - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232/* We look for obvious messed up bcc or strings in response so we do not go off
3233 the end since (at least) WIN2K and Windows XP have a major bug in not null
3234 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003235 if (ses->serverOS)
Steve French08775832006-05-30 18:08:26 +00003236 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003238 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003239 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003240 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241 bcc_ptr, len,
3242 nls_codepage);
3243 bcc_ptr += 2 * (len + 1);
3244 remaining_words -= len + 1;
3245 ses->serverOS[2 * len] = 0;
3246 ses->serverOS[1 + (2 * len)] = 0;
3247 if (remaining_words > 0) {
3248 len = UniStrnlen((wchar_t *)
3249 bcc_ptr,
3250 remaining_words
3251 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00003252 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003254 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255 GFP_KERNEL);
3256 cifs_strfromUCS_le(ses->
3257 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003258 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003259 bcc_ptr,
3260 len,
3261 nls_codepage);
3262 bcc_ptr += 2 * (len + 1);
3263 ses->serverNOS[2 * len] = 0;
3264 ses->serverNOS[1+(2*len)] = 0;
3265 remaining_words -= len + 1;
3266 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00003267 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003268 /* last string not always null terminated (e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003269 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003270 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003272 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003273 (len +
3274 1),
3275 GFP_KERNEL);
3276 cifs_strfromUCS_le
3277 (ses->
3278 serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08003279 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280 bcc_ptr, len,
3281 nls_codepage);
3282 bcc_ptr +=
3283 2 * (len + 1);
3284 ses->
3285 serverDomain[2
3286 * len]
3287 = 0;
3288 ses->
3289 serverDomain[1
3290 +
3291 (2
3292 *
3293 len)]
3294 = 0;
3295 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003296 else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003297 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003298 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003299 ses->serverDomain = kzalloc(2,GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00003300 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301 } else { /* no room so create dummy domain and NOS string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003302 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003303 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003304 ses->serverDomain = kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00003305 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003306 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003307 }
3308 } else { /* ASCII */
3309 len = strnlen(bcc_ptr, 1024);
Steve French50c2f752007-07-13 00:33:32 +00003310 if (((long) bcc_ptr + len) -
3311 (long) pByteArea(smb_buffer_response)
Steve French63135e02007-07-17 17:34:02 +00003312 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003313 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00003314 kfree(ses->serverOS);
Steve French77159b42007-08-31 01:10:17 +00003315 ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316 strncpy(ses->serverOS,bcc_ptr, len);
3317
3318 bcc_ptr += len;
3319 bcc_ptr[0] = 0; /* null terminate the string */
3320 bcc_ptr++;
3321
3322 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003323 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00003324 ses->serverNOS = kzalloc(len+1,
3325 GFP_KERNEL);
Steve French63135e02007-07-17 17:34:02 +00003326 strncpy(ses->serverNOS,
3327 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328 bcc_ptr += len;
3329 bcc_ptr[0] = 0;
3330 bcc_ptr++;
3331
3332 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003333 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003334 kfree(ses->serverDomain);
Steve French63135e02007-07-17 17:34:02 +00003335 ses->serverDomain =
3336 kzalloc(len+1,
3337 GFP_KERNEL);
3338 strncpy(ses->serverDomain,
3339 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340 bcc_ptr += len;
3341 bcc_ptr[0] = 0;
3342 bcc_ptr++;
3343 } else
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003344 cFYI(1, ("field of length %d "
Steve French63135e02007-07-17 17:34:02 +00003345 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346 len));
3347 }
3348 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003349 cERROR(1, ("Security Blob extends beyond end "
Steve French63135e02007-07-17 17:34:02 +00003350 "of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351 }
3352 } else {
3353 cERROR(1, ("No session structure passed in."));
3354 }
3355 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003356 cERROR(1, ("Invalid Word count %d: ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003357 smb_buffer_response->WordCount));
3358 rc = -EIO;
3359 }
3360
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003361 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003362
3363 return rc;
3364}
3365
3366int
3367CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3368 const char *tree, struct cifsTconInfo *tcon,
3369 const struct nls_table *nls_codepage)
3370{
3371 struct smb_hdr *smb_buffer;
3372 struct smb_hdr *smb_buffer_response;
3373 TCONX_REQ *pSMB;
3374 TCONX_RSP *pSMBr;
3375 unsigned char *bcc_ptr;
3376 int rc = 0;
3377 int length;
3378 __u16 count;
3379
3380 if (ses == NULL)
3381 return -EIO;
3382
3383 smb_buffer = cifs_buf_get();
3384 if (smb_buffer == NULL) {
3385 return -ENOMEM;
3386 }
3387 smb_buffer_response = smb_buffer;
3388
3389 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3390 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003391
3392 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003393 smb_buffer->Uid = ses->Suid;
3394 pSMB = (TCONX_REQ *) smb_buffer;
3395 pSMBr = (TCONX_RSP *) smb_buffer_response;
3396
3397 pSMB->AndXCommand = 0xFF;
3398 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399 bcc_ptr = &pSMB->Password[0];
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003400 if ((ses->server->secMode) & SECMODE_USER) {
Steve Frencheeac8042006-01-13 21:34:58 -08003401 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00003402 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08003403 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00003404 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08003405 } else {
Steve French7c7b25b2006-06-01 19:20:10 +00003406 pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08003407 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
3408 specified as required (when that support is added to
3409 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00003410 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08003411 by Samba (not sure whether other servers allow
3412 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00003413#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French50c2f752007-07-13 00:33:32 +00003414 if ((extended_security & CIFSSEC_MAY_LANMAN) &&
Steve French7c7b25b2006-06-01 19:20:10 +00003415 (ses->server->secType == LANMAN))
3416 calc_lanman_hash(ses, bcc_ptr);
3417 else
3418#endif /* CIFS_WEAK_PW_HASH */
Steve Frencheeac8042006-01-13 21:34:58 -08003419 SMBNTencrypt(ses->password,
3420 ses->server->cryptKey,
3421 bcc_ptr);
3422
Steve French7c7b25b2006-06-01 19:20:10 +00003423 bcc_ptr += CIFS_SESS_KEY_SIZE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003424 if (ses->capabilities & CAP_UNICODE) {
Steve French7c7b25b2006-06-01 19:20:10 +00003425 /* must align unicode strings */
3426 *bcc_ptr = 0; /* null byte password */
3427 bcc_ptr++;
3428 }
Steve Frencheeac8042006-01-13 21:34:58 -08003429 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430
Steve French50c2f752007-07-13 00:33:32 +00003431 if (ses->server->secMode &
Steve Frencha878fb22006-05-30 18:04:19 +00003432 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3434
3435 if (ses->capabilities & CAP_STATUS32) {
3436 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3437 }
3438 if (ses->capabilities & CAP_DFS) {
3439 smb_buffer->Flags2 |= SMBFLG2_DFS;
3440 }
3441 if (ses->capabilities & CAP_UNICODE) {
3442 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3443 length =
Steve French50c2f752007-07-13 00:33:32 +00003444 cifs_strtoUCS((__le16 *) bcc_ptr, tree,
3445 6 /* max utf8 char length in bytes */ *
Steve Frencha878fb22006-05-30 18:04:19 +00003446 (/* server len*/ + 256 /* share len */), nls_codepage);
3447 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448 bcc_ptr += 2; /* skip trailing null */
3449 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450 strcpy(bcc_ptr, tree);
3451 bcc_ptr += strlen(tree) + 1;
3452 }
3453 strcpy(bcc_ptr, "?????");
3454 bcc_ptr += strlen("?????");
3455 bcc_ptr += 1;
3456 count = bcc_ptr - &pSMB->Password[0];
3457 pSMB->hdr.smb_buf_length += count;
3458 pSMB->ByteCount = cpu_to_le16(count);
3459
Steve French133672e2007-11-13 22:41:37 +00003460 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
3461 CIFS_STD_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462
3463 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3464 /* above now done in SendReceive */
3465 if ((rc == 0) && (tcon != NULL)) {
3466 tcon->tidStatus = CifsGood;
Steve French3b795212008-11-13 19:45:32 +00003467 tcon->need_reconnect = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 tcon->tid = smb_buffer_response->Tid;
3469 bcc_ptr = pByteArea(smb_buffer_response);
3470 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
Steve French50c2f752007-07-13 00:33:32 +00003471 /* skip service field (NB: this field is always ASCII) */
Steve French7f8ed422007-09-28 22:28:55 +00003472 if (length == 3) {
3473 if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') &&
3474 (bcc_ptr[2] == 'C')) {
3475 cFYI(1, ("IPC connection"));
3476 tcon->ipc = 1;
3477 }
3478 } else if (length == 2) {
3479 if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) {
3480 /* the most common case */
3481 cFYI(1, ("disk share connection"));
3482 }
3483 }
Steve French50c2f752007-07-13 00:33:32 +00003484 bcc_ptr += length + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003485 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3486 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3487 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3488 if ((bcc_ptr + (2 * length)) -
3489 pByteArea(smb_buffer_response) <=
3490 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003491 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003493 kzalloc(length + 2, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003494 if (tcon->nativeFileSystem)
3495 cifs_strfromUCS_le(
3496 tcon->nativeFileSystem,
3497 (__le16 *) bcc_ptr,
3498 length, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499 bcc_ptr += 2 * length;
3500 bcc_ptr[0] = 0; /* null terminate the string */
3501 bcc_ptr[1] = 0;
3502 bcc_ptr += 2;
3503 }
Steve French50c2f752007-07-13 00:33:32 +00003504 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003505 } else {
3506 length = strnlen(bcc_ptr, 1024);
3507 if ((bcc_ptr + length) -
3508 pByteArea(smb_buffer_response) <=
3509 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003510 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003511 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003512 kzalloc(length + 1, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003513 if (tcon->nativeFileSystem)
3514 strncpy(tcon->nativeFileSystem, bcc_ptr,
3515 length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516 }
Steve French50c2f752007-07-13 00:33:32 +00003517 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003519 if ((smb_buffer_response->WordCount == 3) ||
Steve French1a4e15a2006-10-12 21:33:51 +00003520 (smb_buffer_response->WordCount == 7))
3521 /* field is in same location */
Steve French39798772006-05-31 22:40:51 +00003522 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3523 else
3524 tcon->Flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3526 } else if ((rc == 0) && tcon == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00003527 /* all we need to save for IPC$ connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528 ses->ipc_tid = smb_buffer_response->Tid;
3529 }
3530
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003531 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532 return rc;
3533}
3534
3535int
3536cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3537{
3538 int rc = 0;
3539 int xid;
3540 struct cifsSesInfo *ses = NULL;
Steve French50c2f752007-07-13 00:33:32 +00003541 char *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542
3543 xid = GetXid();
3544
3545 if (cifs_sb->tcon) {
3546 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3547 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3548 if (rc == -EBUSY) {
3549 FreeXid(xid);
3550 return 0;
3551 }
Steve French5d941ca2008-04-15 18:40:48 +00003552 DeleteTconOplockQEntries(cifs_sb->tcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003553 tconInfoFree(cifs_sb->tcon);
3554 if ((ses) && (ses->server)) {
3555 /* save off task so we do not refer to ses later */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003556 cFYI(1, ("About to do SMBLogoff "));
3557 rc = CIFSSMBLogoff(xid, ses);
3558 if (rc == -EBUSY) {
3559 FreeXid(xid);
3560 return 0;
Jeff Laytone7ddee92008-11-14 13:44:38 -05003561 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562 } else
3563 cFYI(1, ("No session or bad tcon"));
3564 }
Steve French50c2f752007-07-13 00:33:32 +00003565
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566 cifs_sb->tcon = NULL;
Steve French2fe87f02006-09-21 07:02:52 +00003567 tmp = cifs_sb->prepath;
3568 cifs_sb->prepathlen = 0;
3569 cifs_sb->prepath = NULL;
3570 kfree(tmp);
Nishanth Aravamudan041e0e32005-09-10 00:27:23 -07003571 if (ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572 sesInfoFree(ses);
3573
3574 FreeXid(xid);
Steve French88e7d702008-01-03 17:37:09 +00003575 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003576}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577
3578int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
Steve French50c2f752007-07-13 00:33:32 +00003579 struct nls_table *nls_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580{
3581 int rc = 0;
Steve French7c7b25b2006-06-01 19:20:10 +00003582 char ntlm_session_key[CIFS_SESS_KEY_SIZE];
Steve French4b18f2a2008-04-29 00:06:05 +00003583 bool ntlmv2_flag = false;
Steve Frenchad009ac2005-04-28 22:41:05 -07003584 int first_time = 0;
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003585 struct TCP_Server_Info *server = pSesInfo->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003586
3587 /* what if server changes its buffer size after dropping the session? */
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003588 if (server->maxBuf == 0) /* no need to send on reconnect */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589 rc = CIFSSMBNegotiate(xid, pSesInfo);
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003590 if (rc == -EAGAIN) {
3591 /* retry only once on 1st time connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve French50c2f752007-07-13 00:33:32 +00003593 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594 rc = -EHOSTDOWN;
3595 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003596 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597 spin_lock(&GlobalMid_Lock);
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003598 if (server->tcpStatus != CifsExiting)
3599 server->tcpStatus = CifsGood;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600 else
3601 rc = -EHOSTDOWN;
3602 spin_unlock(&GlobalMid_Lock);
3603
3604 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003605 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606 }
Steve French26b994f2008-08-06 05:11:33 +00003607
3608 if (rc)
3609 goto ss_err_exit;
3610
3611 pSesInfo->flags = 0;
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003612 pSesInfo->capabilities = server->capabilities;
Steve French26b994f2008-08-06 05:11:33 +00003613 if (linuxExtEnabled == 0)
3614 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003615 /* pSesInfo->sequence_number = 0;*/
Steve French26b994f2008-08-06 05:11:33 +00003616 cFYI(1, ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003617 server->secMode, server->capabilities, server->timeAdj));
3618
Steve French26b994f2008-08-06 05:11:33 +00003619 if (experimEnabled < 2)
3620 rc = CIFS_SessSetup(xid, pSesInfo, first_time, nls_info);
3621 else if (extended_security
3622 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003623 && (server->secType == NTLMSSP)) {
Steve French26b994f2008-08-06 05:11:33 +00003624 rc = -EOPNOTSUPP;
3625 } else if (extended_security
3626 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003627 && (server->secType == RawNTLMSSP)) {
Steve French26b994f2008-08-06 05:11:33 +00003628 cFYI(1, ("NTLMSSP sesssetup"));
3629 rc = CIFSNTLMSSPNegotiateSessSetup(xid, pSesInfo, &ntlmv2_flag,
3630 nls_info);
3631 if (!rc) {
3632 if (ntlmv2_flag) {
3633 char *v2_response;
3634 cFYI(1, ("more secure NTLM ver2 hash"));
3635 if (CalcNTLMv2_partial_mac_key(pSesInfo,
3636 nls_info)) {
3637 rc = -ENOMEM;
3638 goto ss_err_exit;
3639 } else
3640 v2_response = kmalloc(16 + 64 /* blob*/,
3641 GFP_KERNEL);
3642 if (v2_response) {
3643 CalcNTLMv2_response(pSesInfo,
3644 v2_response);
3645 /* if (first_time)
3646 cifs_calculate_ntlmv2_mac_key */
3647 kfree(v2_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003648 /* BB Put dummy sig in SessSetup PDU? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003649 } else {
Steve French26b994f2008-08-06 05:11:33 +00003650 rc = -ENOMEM;
3651 goto ss_err_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003652 }
Steve French26b994f2008-08-06 05:11:33 +00003653
3654 } else {
3655 SMBNTencrypt(pSesInfo->password,
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003656 server->cryptKey,
Steve French26b994f2008-08-06 05:11:33 +00003657 ntlm_session_key);
3658
3659 if (first_time)
3660 cifs_calculate_mac_key(
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003661 &server->mac_signing_key,
Steve French26b994f2008-08-06 05:11:33 +00003662 ntlm_session_key,
3663 pSesInfo->password);
3664 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665 /* for better security the weaker lanman hash not sent
3666 in AuthSessSetup so we no longer calculate it */
3667
Steve French26b994f2008-08-06 05:11:33 +00003668 rc = CIFSNTLMSSPAuthSessSetup(xid, pSesInfo,
3669 ntlm_session_key,
3670 ntlmv2_flag,
3671 nls_info);
3672 }
3673 } else { /* old style NTLM 0.12 session setup */
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003674 SMBNTencrypt(pSesInfo->password, server->cryptKey,
Steve French26b994f2008-08-06 05:11:33 +00003675 ntlm_session_key);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676
Steve French26b994f2008-08-06 05:11:33 +00003677 if (first_time)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003678 cifs_calculate_mac_key(&server->mac_signing_key,
3679 ntlm_session_key,
3680 pSesInfo->password);
Steve Frenchad009ac2005-04-28 22:41:05 -07003681
Steve French26b994f2008-08-06 05:11:33 +00003682 rc = CIFSSessSetup(xid, pSesInfo, ntlm_session_key, nls_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683 }
Steve French26b994f2008-08-06 05:11:33 +00003684 if (rc) {
3685 cERROR(1, ("Send error in SessSetup = %d", rc));
3686 } else {
3687 cFYI(1, ("CIFS Session Established successfully"));
Jeff Layton469ee612008-10-16 18:46:39 +00003688 spin_lock(&GlobalMid_Lock);
Steve French26b994f2008-08-06 05:11:33 +00003689 pSesInfo->status = CifsGood;
Steve French3b795212008-11-13 19:45:32 +00003690 pSesInfo->need_reconnect = false;
Jeff Layton469ee612008-10-16 18:46:39 +00003691 spin_unlock(&GlobalMid_Lock);
Steve French26b994f2008-08-06 05:11:33 +00003692 }
3693
Linus Torvalds1da177e2005-04-16 15:20:36 -07003694ss_err_exit:
3695 return rc;
3696}
3697