blob: a3dc0d7cafc3d52c015f762647c19f61e2fa8671 [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 */
Jeff Layton14fbf502008-11-14 13:53:46 -0500147 read_lock(&cifs_tcp_ses_lock);
148 list_for_each(tmp, &server->smb_ses_list) {
149 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
150 ses->need_reconnect = true;
151 ses->ipc_tid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 }
Jeff Layton14fbf502008-11-14 13:53:46 -0500153 read_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 list_for_each(tmp, &GlobalTreeConnectionList) {
155 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000156 if ((tcon->ses) && (tcon->ses->server == server))
Steve French3b795212008-11-13 19:45:32 +0000157 tcon->need_reconnect = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 /* do not want to be sending data on a socket we are freeing */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000160 down(&server->tcpSem);
161 if (server->ssocket) {
Steve French467a8f82007-06-27 22:41:32 +0000162 cFYI(1, ("State: 0x%x Flags: 0x%lx", server->ssocket->state,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 server->ssocket->flags));
Trond Myklebust91cf45f2007-11-12 18:10:39 -0800164 kernel_sock_shutdown(server->ssocket, SHUT_WR);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000165 cFYI(1, ("Post shutdown state: 0x%x Flags: 0x%lx",
Steve French467a8f82007-06-27 22:41:32 +0000166 server->ssocket->state,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 server->ssocket->flags));
168 sock_release(server->ssocket);
169 server->ssocket = NULL;
170 }
171
172 spin_lock(&GlobalMid_Lock);
173 list_for_each(tmp, &server->pending_mid_q) {
174 mid_entry = list_entry(tmp, struct
175 mid_q_entry,
176 qhead);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000177 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French09d1db52005-04-28 22:41:08 -0700178 /* Mark other intransit requests as needing
179 retry so we do not immediately mark the
180 session bad again (ie after we reconnect
181 below) as they timeout too */
Steve Frenchad8b15f2008-08-08 21:10:16 +0000182 mid_entry->midState = MID_RETRY_NEEDED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 }
184 }
185 spin_unlock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000186 up(&server->tcpSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187
Jeff Layton469ee612008-10-16 18:46:39 +0000188 while ((server->tcpStatus != CifsExiting) &&
189 (server->tcpStatus != CifsGood)) {
Steve French6c3d8902006-07-31 22:46:20 +0000190 try_to_freeze();
Steve French3ec332e2008-11-14 03:35:10 +0000191 if (server->addr.sockAddr6.sin6_family == AF_INET6) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000192 rc = ipv6_connect(&server->addr.sockAddr6,
Steve Frenchedf1ae42008-10-29 00:47:57 +0000193 &server->ssocket, server->noautotune);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000195 rc = ipv4_connect(&server->addr.sockAddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 &server->ssocket,
Steve Frencha10faeb22005-08-22 21:38:31 -0700197 server->workstation_RFC1001_name,
Steve Frenchedf1ae42008-10-29 00:47:57 +0000198 server->server_RFC1001_name,
199 server->noblocksnd, server->noautotune);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000201 if (rc) {
202 cFYI(1, ("reconnect error %d", rc));
Steve French0cb766a2005-04-28 22:41:11 -0700203 msleep(3000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 } else {
205 atomic_inc(&tcpSesReconnectCount);
206 spin_lock(&GlobalMid_Lock);
Jeff Layton469ee612008-10-16 18:46:39 +0000207 if (server->tcpStatus != CifsExiting)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 server->tcpStatus = CifsGood;
Steve Frenchad009ac2005-04-28 22:41:05 -0700209 server->sequence_number = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000210 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 /* atomic_set(&server->inFlight,0);*/
212 wake_up(&server->response_q);
213 }
214 }
215 return rc;
216}
217
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000218/*
Steve Frenche4eb2952005-04-28 22:41:09 -0700219 return codes:
220 0 not a transact2, or all data present
221 >0 transact2 with that much data missing
222 -EINVAL = invalid transact2
223
224 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000225static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize)
Steve Frenche4eb2952005-04-28 22:41:09 -0700226{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000227 struct smb_t2_rsp *pSMBt;
228 int total_data_size;
Steve Frenche4eb2952005-04-28 22:41:09 -0700229 int data_in_this_rsp;
230 int remaining;
231
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000232 if (pSMB->Command != SMB_COM_TRANSACTION2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700233 return 0;
234
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000235 /* check for plausible wct, bcc and t2 data and parm sizes */
236 /* check for parm and data offset going beyond end of smb */
237 if (pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
Steve French467a8f82007-06-27 22:41:32 +0000238 cFYI(1, ("invalid transact2 word count"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700239 return -EINVAL;
240 }
241
242 pSMBt = (struct smb_t2_rsp *)pSMB;
243
244 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
245 data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
246
247 remaining = total_data_size - data_in_this_rsp;
248
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000249 if (remaining == 0)
Steve Frenche4eb2952005-04-28 22:41:09 -0700250 return 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000251 else if (remaining < 0) {
Steve French467a8f82007-06-27 22:41:32 +0000252 cFYI(1, ("total data %d smaller than data in frame %d",
Steve Frenche4eb2952005-04-28 22:41:09 -0700253 total_data_size, data_in_this_rsp));
254 return -EINVAL;
255 } else {
Steve French467a8f82007-06-27 22:41:32 +0000256 cFYI(1, ("missing %d bytes from transact2, check next response",
Steve Frenche4eb2952005-04-28 22:41:09 -0700257 remaining));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000258 if (total_data_size > maxBufSize) {
259 cERROR(1, ("TotalDataSize %d is over maximum buffer %d",
260 total_data_size, maxBufSize));
261 return -EINVAL;
Steve Frenche4eb2952005-04-28 22:41:09 -0700262 }
263 return remaining;
264 }
265}
266
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000267static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
Steve Frenche4eb2952005-04-28 22:41:09 -0700268{
269 struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
270 struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
271 int total_data_size;
272 int total_in_buf;
273 int remaining;
274 int total_in_buf2;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000275 char *data_area_of_target;
276 char *data_area_of_buf2;
Steve Frenche4eb2952005-04-28 22:41:09 -0700277 __u16 byte_count;
278
279 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
280
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000281 if (total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
Steve French63135e02007-07-17 17:34:02 +0000282 cFYI(1, ("total data size of primary and secondary t2 differ"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700283 }
284
285 total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
286
287 remaining = total_data_size - total_in_buf;
Steve French50c2f752007-07-13 00:33:32 +0000288
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000289 if (remaining < 0)
Steve Frenche4eb2952005-04-28 22:41:09 -0700290 return -EINVAL;
291
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000292 if (remaining == 0) /* nothing to do, ignore */
Steve Frenche4eb2952005-04-28 22:41:09 -0700293 return 0;
Steve French50c2f752007-07-13 00:33:32 +0000294
Steve Frenche4eb2952005-04-28 22:41:09 -0700295 total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000296 if (remaining < total_in_buf2) {
Steve French467a8f82007-06-27 22:41:32 +0000297 cFYI(1, ("transact2 2nd response contains too much data"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700298 }
299
300 /* find end of first SMB data area */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000301 data_area_of_target = (char *)&pSMBt->hdr.Protocol +
Steve Frenche4eb2952005-04-28 22:41:09 -0700302 le16_to_cpu(pSMBt->t2_rsp.DataOffset);
303 /* validate target area */
304
305 data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000306 le16_to_cpu(pSMB2->t2_rsp.DataOffset);
Steve Frenche4eb2952005-04-28 22:41:09 -0700307
308 data_area_of_target += total_in_buf;
309
310 /* copy second buffer into end of first buffer */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000311 memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2);
Steve Frenche4eb2952005-04-28 22:41:09 -0700312 total_in_buf += total_in_buf2;
313 pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
314 byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
315 byte_count += total_in_buf2;
316 BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
317
Steve French70ca7342005-09-22 16:32:06 -0700318 byte_count = pTargetSMB->smb_buf_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700319 byte_count += total_in_buf2;
320
321 /* BB also add check that we are not beyond maximum buffer size */
Steve French50c2f752007-07-13 00:33:32 +0000322
Steve French70ca7342005-09-22 16:32:06 -0700323 pTargetSMB->smb_buf_length = byte_count;
Steve Frenche4eb2952005-04-28 22:41:09 -0700324
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000325 if (remaining == total_in_buf2) {
Steve French467a8f82007-06-27 22:41:32 +0000326 cFYI(1, ("found the last secondary response"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700327 return 0; /* we are done */
328 } else /* more responses to go */
329 return 1;
330
331}
332
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333static int
334cifs_demultiplex_thread(struct TCP_Server_Info *server)
335{
336 int length;
337 unsigned int pdu_length, total_read;
338 struct smb_hdr *smb_buffer = NULL;
Steve Frenchb8643e12005-04-28 22:41:07 -0700339 struct smb_hdr *bigbuf = NULL;
340 struct smb_hdr *smallbuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 struct msghdr smb_msg;
342 struct kvec iov;
343 struct socket *csocket = server->ssocket;
344 struct list_head *tmp;
345 struct cifsSesInfo *ses;
346 struct task_struct *task_to_wake = NULL;
347 struct mid_q_entry *mid_entry;
Steve French70ca7342005-09-22 16:32:06 -0700348 char temp;
Steve French4b18f2a2008-04-29 00:06:05 +0000349 bool isLargeBuf = false;
350 bool isMultiRsp;
Steve Frenche4eb2952005-04-28 22:41:09 -0700351 int reconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 current->flags |= PF_MEMALLOC;
Pavel Emelyanovba25f9d2007-10-18 23:40:40 -0700354 cFYI(1, ("Demultiplex PID: %d", task_pid_nr(current)));
Jeff Layton93d0ec82008-08-02 08:00:48 -0400355
356 length = atomic_inc_return(&tcpSesAllocCount);
357 if (length > 1)
Steve French26f57362007-08-30 22:09:15 +0000358 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
359 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360
Rafael J. Wysocki83144182007-07-17 04:03:35 -0700361 set_freezable();
Jeff Layton469ee612008-10-16 18:46:39 +0000362 while (server->tcpStatus != CifsExiting) {
Steve Frenchede13272005-08-30 20:10:14 -0700363 if (try_to_freeze())
364 continue;
Steve Frenchb8643e12005-04-28 22:41:07 -0700365 if (bigbuf == NULL) {
366 bigbuf = cifs_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000367 if (!bigbuf) {
368 cERROR(1, ("No memory for large SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700369 msleep(3000);
370 /* retry will check if exiting */
371 continue;
372 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000373 } else if (isLargeBuf) {
374 /* we are reusing a dirty large buf, clear its start */
Steve French26f57362007-08-30 22:09:15 +0000375 memset(bigbuf, 0, sizeof(struct smb_hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700377
378 if (smallbuf == NULL) {
379 smallbuf = cifs_small_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000380 if (!smallbuf) {
381 cERROR(1, ("No memory for SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700382 msleep(1000);
383 /* retry will check if exiting */
384 continue;
385 }
386 /* beginning of smb buffer is cleared in our buf_get */
387 } else /* if existing small buf clear beginning */
Steve French26f57362007-08-30 22:09:15 +0000388 memset(smallbuf, 0, sizeof(struct smb_hdr));
Steve Frenchb8643e12005-04-28 22:41:07 -0700389
Steve French4b18f2a2008-04-29 00:06:05 +0000390 isLargeBuf = false;
391 isMultiRsp = false;
Steve Frenchb8643e12005-04-28 22:41:07 -0700392 smb_buffer = smallbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 iov.iov_base = smb_buffer;
394 iov.iov_len = 4;
395 smb_msg.msg_control = NULL;
396 smb_msg.msg_controllen = 0;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000397 pdu_length = 4; /* enough to get RFC1001 header */
398incomplete_rcv:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 length =
400 kernel_recvmsg(csocket, &smb_msg,
Steve Frenchf01d5e12007-08-30 21:13:31 +0000401 &iov, 1, pdu_length, 0 /* BB other flags? */);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402
Jeff Layton469ee612008-10-16 18:46:39 +0000403 if (server->tcpStatus == CifsExiting) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 break;
405 } else if (server->tcpStatus == CifsNeedReconnect) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000406 cFYI(1, ("Reconnect after server stopped responding"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 cifs_reconnect(server);
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000408 cFYI(1, ("call to reconnect done"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 csocket = server->ssocket;
410 continue;
411 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700412 msleep(1); /* minimum sleep to prevent looping
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 allowing socket to clear and app threads to set
414 tcpStatus CifsNeedReconnect if server hung */
Steve Frenchc527c8a2008-11-03 20:46:21 +0000415 if (pdu_length < 4) {
416 iov.iov_base = (4 - pdu_length) +
417 (char *)smb_buffer;
418 iov.iov_len = pdu_length;
419 smb_msg.msg_control = NULL;
420 smb_msg.msg_controllen = 0;
Steve Frenchc18c7322007-10-17 18:01:11 +0000421 goto incomplete_rcv;
Steve Frenchc527c8a2008-11-03 20:46:21 +0000422 } else
Steve Frenchc18c7322007-10-17 18:01:11 +0000423 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 } else if (length <= 0) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000425 if (server->tcpStatus == CifsNew) {
426 cFYI(1, ("tcp session abend after SMBnegprot"));
Steve French09d1db52005-04-28 22:41:08 -0700427 /* some servers kill the TCP session rather than
428 returning an SMB negprot error, in which
429 case reconnecting here is not going to help,
430 and so simply return error to mount */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 break;
432 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000433 if (!try_to_freeze() && (length == -EINTR)) {
Steve French467a8f82007-06-27 22:41:32 +0000434 cFYI(1, ("cifsd thread killed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 break;
436 }
Steve French467a8f82007-06-27 22:41:32 +0000437 cFYI(1, ("Reconnect after unexpected peek error %d",
Steve French57337e42005-04-28 22:41:10 -0700438 length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 cifs_reconnect(server);
440 csocket = server->ssocket;
441 wake_up(&server->response_q);
442 continue;
Petr Tesarik2a974682007-11-20 02:24:08 +0000443 } else if (length < pdu_length) {
444 cFYI(1, ("requested %d bytes but only got %d bytes",
445 pdu_length, length));
Steve Frenchf01d5e12007-08-30 21:13:31 +0000446 pdu_length -= length;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000447 msleep(1);
448 goto incomplete_rcv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 }
Steve French67010fb2005-04-28 22:41:09 -0700450
Steve French70ca7342005-09-22 16:32:06 -0700451 /* The right amount was read from socket - 4 bytes */
452 /* so we can now interpret the length field */
Steve French46810cb2005-04-28 22:41:09 -0700453
Steve French70ca7342005-09-22 16:32:06 -0700454 /* the first byte big endian of the length field,
455 is actually not part of the length but the type
456 with the most common, zero, as regular data */
457 temp = *((char *) smb_buffer);
458
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000459 /* Note that FC 1001 length is big endian on the wire,
Steve French70ca7342005-09-22 16:32:06 -0700460 but we convert it here so it is always manipulated
461 as host byte order */
Harvey Harrison5ca33c62008-07-23 17:45:58 -0700462 pdu_length = be32_to_cpu((__force __be32)smb_buffer->smb_buf_length);
Steve French70ca7342005-09-22 16:32:06 -0700463 smb_buffer->smb_buf_length = pdu_length;
Steve French46810cb2005-04-28 22:41:09 -0700464
Steve French467a8f82007-06-27 22:41:32 +0000465 cFYI(1, ("rfc1002 length 0x%x", pdu_length+4));
Steve French70ca7342005-09-22 16:32:06 -0700466
467 if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000468 continue;
Steve French70ca7342005-09-22 16:32:06 -0700469 } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
Steve French467a8f82007-06-27 22:41:32 +0000470 cFYI(1, ("Good RFC 1002 session rsp"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700471 continue;
Steve French70ca7342005-09-22 16:32:06 -0700472 } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000473 /* we get this from Windows 98 instead of
Steve French46810cb2005-04-28 22:41:09 -0700474 an error on SMB negprot response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000475 cFYI(1, ("Negative RFC1002 Session Response Error 0x%x)",
Steve French70ca7342005-09-22 16:32:06 -0700476 pdu_length));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000477 if (server->tcpStatus == CifsNew) {
478 /* if nack on negprot (rather than
Steve French46810cb2005-04-28 22:41:09 -0700479 ret of smb negprot error) reconnecting
480 not going to help, ret error to mount */
481 break;
482 } else {
483 /* give server a second to
484 clean up before reconnect attempt */
485 msleep(1000);
486 /* always try 445 first on reconnect
487 since we get NACK on some if we ever
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000488 connected to port 139 (the NACK is
Steve French46810cb2005-04-28 22:41:09 -0700489 since we do not begin with RFC1001
490 session initialize frame) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000491 server->addr.sockAddr.sin_port =
Steve French46810cb2005-04-28 22:41:09 -0700492 htons(CIFS_PORT);
493 cifs_reconnect(server);
494 csocket = server->ssocket;
495 wake_up(&server->response_q);
496 continue;
497 }
Steve French70ca7342005-09-22 16:32:06 -0700498 } else if (temp != (char) 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000499 cERROR(1, ("Unknown RFC 1002 frame"));
Steve French70ca7342005-09-22 16:32:06 -0700500 cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
501 length);
Steve French46810cb2005-04-28 22:41:09 -0700502 cifs_reconnect(server);
503 csocket = server->ssocket;
504 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700505 }
506
507 /* else we have an SMB response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000508 if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French26f57362007-08-30 22:09:15 +0000509 (pdu_length < sizeof(struct smb_hdr) - 1 - 4)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700510 cERROR(1, ("Invalid size SMB length %d pdu_length %d",
Steve French46810cb2005-04-28 22:41:09 -0700511 length, pdu_length+4));
Steve Frenche4eb2952005-04-28 22:41:09 -0700512 cifs_reconnect(server);
513 csocket = server->ssocket;
514 wake_up(&server->response_q);
515 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000516 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700517
518 /* else length ok */
519 reconnect = 0;
520
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000521 if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
Steve French4b18f2a2008-04-29 00:06:05 +0000522 isLargeBuf = true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700523 memcpy(bigbuf, smallbuf, 4);
524 smb_buffer = bigbuf;
525 }
526 length = 0;
527 iov.iov_base = 4 + (char *)smb_buffer;
528 iov.iov_len = pdu_length;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000529 for (total_read = 0; total_read < pdu_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700530 total_read += length) {
531 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
532 pdu_length - total_read, 0);
Jeff Layton469ee612008-10-16 18:46:39 +0000533 if ((server->tcpStatus == CifsExiting) ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700534 (length == -EINTR)) {
535 /* then will exit */
536 reconnect = 2;
537 break;
538 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700539 cifs_reconnect(server);
540 csocket = server->ssocket;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000541 /* Reconnect wakes up rspns q */
Steve Frenche4eb2952005-04-28 22:41:09 -0700542 /* Now we will reread sock */
543 reconnect = 1;
544 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000545 } else if ((length == -ERESTARTSYS) ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700546 (length == -EAGAIN)) {
547 msleep(1); /* minimum sleep to prevent looping,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000548 allowing socket to clear and app
Steve Frenche4eb2952005-04-28 22:41:09 -0700549 threads to set tcpStatus
550 CifsNeedReconnect if server hung*/
Steve Frenchc18c7322007-10-17 18:01:11 +0000551 length = 0;
Steve French46810cb2005-04-28 22:41:09 -0700552 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700553 } else if (length <= 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000554 cERROR(1, ("Received no data, expecting %d",
Steve Frenche4eb2952005-04-28 22:41:09 -0700555 pdu_length - total_read));
556 cifs_reconnect(server);
557 csocket = server->ssocket;
558 reconnect = 1;
559 break;
Steve French46810cb2005-04-28 22:41:09 -0700560 }
561 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000562 if (reconnect == 2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700563 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000564 else if (reconnect == 1)
Steve Frenche4eb2952005-04-28 22:41:09 -0700565 continue;
566
567 length += 4; /* account for rfc1002 hdr */
Steve French50c2f752007-07-13 00:33:32 +0000568
Steve Frenche4eb2952005-04-28 22:41:09 -0700569
570 dump_smb(smb_buffer, length);
Steve French184ed212006-02-24 06:15:11 +0000571 if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700572 cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
Steve Frenche4eb2952005-04-28 22:41:09 -0700573 continue;
574 }
575
576
577 task_to_wake = NULL;
578 spin_lock(&GlobalMid_Lock);
579 list_for_each(tmp, &server->pending_mid_q) {
580 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
581
Steve French50c2f752007-07-13 00:33:32 +0000582 if ((mid_entry->mid == smb_buffer->Mid) &&
Steve Frenche4eb2952005-04-28 22:41:09 -0700583 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
584 (mid_entry->command == smb_buffer->Command)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000585 if (check2ndT2(smb_buffer,server->maxBuf) > 0) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700586 /* We have a multipart transact2 resp */
Steve French4b18f2a2008-04-29 00:06:05 +0000587 isMultiRsp = true;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000588 if (mid_entry->resp_buf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700589 /* merge response - fix up 1st*/
Steve French50c2f752007-07-13 00:33:32 +0000590 if (coalesce_t2(smb_buffer,
Steve Frenche4eb2952005-04-28 22:41:09 -0700591 mid_entry->resp_buf)) {
Steve French4b18f2a2008-04-29 00:06:05 +0000592 mid_entry->multiRsp =
593 true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700594 break;
595 } else {
596 /* all parts received */
Steve French4b18f2a2008-04-29 00:06:05 +0000597 mid_entry->multiEnd =
598 true;
Steve French50c2f752007-07-13 00:33:32 +0000599 goto multi_t2_fnd;
Steve Frenche4eb2952005-04-28 22:41:09 -0700600 }
601 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000602 if (!isLargeBuf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700603 cERROR(1,("1st trans2 resp needs bigbuf"));
604 /* BB maybe we can fix this up, switch
Steve French50c2f752007-07-13 00:33:32 +0000605 to already allocated large buffer? */
Steve Frenche4eb2952005-04-28 22:41:09 -0700606 } else {
Steve Frenchcd634992005-04-28 22:41:10 -0700607 /* Have first buffer */
Steve Frenche4eb2952005-04-28 22:41:09 -0700608 mid_entry->resp_buf =
609 smb_buffer;
Steve French4b18f2a2008-04-29 00:06:05 +0000610 mid_entry->largeBuf =
611 true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700612 bigbuf = NULL;
613 }
614 }
615 break;
Steve French50c2f752007-07-13 00:33:32 +0000616 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700617 mid_entry->resp_buf = smb_buffer;
Steve French4b18f2a2008-04-29 00:06:05 +0000618 mid_entry->largeBuf = isLargeBuf;
Steve Frenche4eb2952005-04-28 22:41:09 -0700619multi_t2_fnd:
620 task_to_wake = mid_entry->tsk;
621 mid_entry->midState = MID_RESPONSE_RECEIVED;
Steve French1047abc2005-10-11 19:58:06 -0700622#ifdef CONFIG_CIFS_STATS2
623 mid_entry->when_received = jiffies;
624#endif
Steve French3a5ff612006-07-14 22:37:11 +0000625 /* so we do not time out requests to server
626 which is still responding (since server could
627 be busy but not dead) */
628 server->lstrp = jiffies;
Steve Frenche4eb2952005-04-28 22:41:09 -0700629 break;
630 }
631 }
632 spin_unlock(&GlobalMid_Lock);
633 if (task_to_wake) {
Steve Frenchcd634992005-04-28 22:41:10 -0700634 /* Was previous buf put in mpx struct for multi-rsp? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000635 if (!isMultiRsp) {
Steve Frenchcd634992005-04-28 22:41:10 -0700636 /* smb buffer will be freed by user thread */
Steve French26f57362007-08-30 22:09:15 +0000637 if (isLargeBuf)
Steve Frenchcd634992005-04-28 22:41:10 -0700638 bigbuf = NULL;
Steve French26f57362007-08-30 22:09:15 +0000639 else
Steve Frenchcd634992005-04-28 22:41:10 -0700640 smallbuf = NULL;
641 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700642 wake_up_process(task_to_wake);
Steve French4b18f2a2008-04-29 00:06:05 +0000643 } else if (!is_valid_oplock_break(smb_buffer, server) &&
644 !isMultiRsp) {
Steve French50c2f752007-07-13 00:33:32 +0000645 cERROR(1, ("No task to wake, unknown frame received! "
646 "NumMids %d", midCount.counter));
647 cifs_dump_mem("Received Data is: ", (char *)smb_buffer,
Steve French70ca7342005-09-22 16:32:06 -0700648 sizeof(struct smb_hdr));
Steve French39798772006-05-31 22:40:51 +0000649#ifdef CONFIG_CIFS_DEBUG2
650 cifs_dump_detail(smb_buffer);
651 cifs_dump_mids(server);
652#endif /* CIFS_DEBUG2 */
Steve French50c2f752007-07-13 00:33:32 +0000653
Steve Frenche4eb2952005-04-28 22:41:09 -0700654 }
655 } /* end while !EXITING */
656
Jeff Laytone7ddee92008-11-14 13:44:38 -0500657 /* take it off the list, if it's not already */
658 write_lock(&cifs_tcp_ses_lock);
659 list_del_init(&server->tcp_ses_list);
660 write_unlock(&cifs_tcp_ses_lock);
661
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 spin_lock(&GlobalMid_Lock);
663 server->tcpStatus = CifsExiting;
Steve Frenche691b9d2008-05-11 15:53:33 +0000664 spin_unlock(&GlobalMid_Lock);
Steve Frenchdbdbb872008-06-10 21:21:56 +0000665 wake_up_all(&server->response_q);
Steve Frenche691b9d2008-05-11 15:53:33 +0000666
Steve French31ca3bc2005-04-28 22:41:11 -0700667 /* check if we have blocked requests that need to free */
668 /* Note that cifs_max_pending is normally 50, but
669 can be set at module install time to as little as two */
Steve Frenche691b9d2008-05-11 15:53:33 +0000670 spin_lock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000671 if (atomic_read(&server->inFlight) >= cifs_max_pending)
Steve French31ca3bc2005-04-28 22:41:11 -0700672 atomic_set(&server->inFlight, cifs_max_pending - 1);
673 /* We do not want to set the max_pending too low or we
674 could end up with the counter going negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +0000676 /* Although there should not be any requests blocked on
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700678 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 to the same server - they now will see the session is in exit state
680 and get out of SendReceive. */
681 wake_up_all(&server->request_q);
682 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700683 msleep(125);
Steve French50c2f752007-07-13 00:33:32 +0000684
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000685 if (server->ssocket) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 sock_release(csocket);
687 server->ssocket = NULL;
688 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700689 /* buffer usuallly freed in free_mid - need to free it here on exit */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +0000690 cifs_buf_release(bigbuf);
691 if (smallbuf) /* no sense logging a debug message if NULL */
Steve Frenchb8643e12005-04-28 22:41:07 -0700692 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693
Jeff Layton14fbf502008-11-14 13:53:46 -0500694 /*
695 * BB: we shouldn't have to do any of this. It shouldn't be
696 * possible to exit from the thread with active SMB sessions
697 */
698 read_lock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700700 /* loop through server session structures attached to this and
701 mark them dead */
Jeff Layton14fbf502008-11-14 13:53:46 -0500702 list_for_each(tmp, &server->smb_ses_list) {
703 ses = list_entry(tmp, struct cifsSesInfo,
704 smb_ses_list);
705 ses->status = CifsExiting;
706 ses->server = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 }
Jeff Layton14fbf502008-11-14 13:53:46 -0500708 read_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 } else {
Steve French31ca3bc2005-04-28 22:41:11 -0700710 /* although we can not zero the server struct pointer yet,
711 since there are active requests which may depnd on them,
712 mark the corresponding SMB sessions as exiting too */
Jeff Layton14fbf502008-11-14 13:53:46 -0500713 list_for_each(tmp, &server->smb_ses_list) {
Steve French31ca3bc2005-04-28 22:41:11 -0700714 ses = list_entry(tmp, struct cifsSesInfo,
Jeff Layton14fbf502008-11-14 13:53:46 -0500715 smb_ses_list);
716 ses->status = CifsExiting;
Steve French31ca3bc2005-04-28 22:41:11 -0700717 }
718
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 spin_lock(&GlobalMid_Lock);
720 list_for_each(tmp, &server->pending_mid_q) {
721 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
722 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French50c2f752007-07-13 00:33:32 +0000723 cFYI(1, ("Clearing Mid 0x%x - waking up ",
724 mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 task_to_wake = mid_entry->tsk;
Steve French26f57362007-08-30 22:09:15 +0000726 if (task_to_wake)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 wake_up_process(task_to_wake);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 }
729 }
730 spin_unlock(&GlobalMid_Lock);
Jeff Layton14fbf502008-11-14 13:53:46 -0500731 read_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700733 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 }
735
Steve Frenchf1914012005-08-18 09:37:34 -0700736 if (!list_empty(&server->pending_mid_q)) {
Steve French50c2f752007-07-13 00:33:32 +0000737 /* mpx threads have not exited yet give them
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700739 /* due to delays on oplock break requests, we need
740 to wait at least 45 seconds before giving up
741 on a request getting a response and going ahead
742 and killing cifsd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve French31ca3bc2005-04-28 22:41:11 -0700744 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 /* if threads still have not exited they are probably never
746 coming home not much else we can do but free the memory */
747 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748
Steve French31ca3bc2005-04-28 22:41:11 -0700749 /* last chance to mark ses pointers invalid
750 if there are any pointing to this (e.g
Steve French50c2f752007-07-13 00:33:32 +0000751 if a crazy root user tried to kill cifsd
Steve French31ca3bc2005-04-28 22:41:11 -0700752 kernel thread explicitly this might happen) */
Jeff Layton14fbf502008-11-14 13:53:46 -0500753 /* BB: This shouldn't be necessary, see above */
754 read_lock(&cifs_tcp_ses_lock);
755 list_for_each(tmp, &server->smb_ses_list) {
756 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
757 ses->server = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700758 }
Jeff Layton14fbf502008-11-14 13:53:46 -0500759 read_unlock(&cifs_tcp_ses_lock);
Steve French31ca3bc2005-04-28 22:41:11 -0700760
Jeff Laytonc359cf32007-11-16 22:22:06 +0000761 kfree(server->hostname);
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -0400762 task_to_wake = xchg(&server->tsk, NULL);
Steve French31ca3bc2005-04-28 22:41:11 -0700763 kfree(server);
Jeff Layton93d0ec82008-08-02 08:00:48 -0400764
765 length = atomic_dec_return(&tcpSesAllocCount);
Steve French26f57362007-08-30 22:09:15 +0000766 if (length > 0)
767 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
768 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +0000769
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -0400770 /* if server->tsk was NULL then wait for a signal before exiting */
771 if (!task_to_wake) {
772 set_current_state(TASK_INTERRUPTIBLE);
773 while (!signal_pending(current)) {
774 schedule();
775 set_current_state(TASK_INTERRUPTIBLE);
776 }
777 set_current_state(TASK_RUNNING);
778 }
779
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 return 0;
781}
782
Jeff Laytonc359cf32007-11-16 22:22:06 +0000783/* extract the host portion of the UNC string */
784static char *
785extract_hostname(const char *unc)
786{
787 const char *src;
788 char *dst, *delim;
789 unsigned int len;
790
791 /* skip double chars at beginning of string */
792 /* BB: check validity of these bytes? */
793 src = unc + 2;
794
795 /* delimiter between hostname and sharename is always '\\' now */
796 delim = strchr(src, '\\');
797 if (!delim)
798 return ERR_PTR(-EINVAL);
799
800 len = delim - src;
801 dst = kmalloc((len + 1), GFP_KERNEL);
802 if (dst == NULL)
803 return ERR_PTR(-ENOMEM);
804
805 memcpy(dst, src, len);
806 dst[len] = '\0';
807
808 return dst;
809}
810
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811static int
Steve French50c2f752007-07-13 00:33:32 +0000812cifs_parse_mount_options(char *options, const char *devname,
813 struct smb_vol *vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814{
815 char *value;
816 char *data;
817 unsigned int temp_len, i, j;
818 char separator[2];
819
820 separator[0] = ',';
Steve French50c2f752007-07-13 00:33:32 +0000821 separator[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822
Linus Torvalds12e36b22006-10-13 08:09:29 -0700823 if (Local_System_Name[0] != 0)
Steve French50c2f752007-07-13 00:33:32 +0000824 memcpy(vol->source_rfc1001_name, Local_System_Name, 15);
Steve French2cd646a2006-09-28 19:43:08 +0000825 else {
Linus Torvalds12e36b22006-10-13 08:09:29 -0700826 char *nodename = utsname()->nodename;
Steve French50c2f752007-07-13 00:33:32 +0000827 int n = strnlen(nodename, 15);
828 memset(vol->source_rfc1001_name, 0x20, 15);
829 for (i = 0; i < n; i++) {
Steve French2cd646a2006-09-28 19:43:08 +0000830 /* does not have to be perfect mapping since field is
831 informational, only used for servers that do not support
832 port 445 and it can be overridden at mount time */
Linus Torvalds12e36b22006-10-13 08:09:29 -0700833 vol->source_rfc1001_name[i] = toupper(nodename[i]);
Steve French2cd646a2006-09-28 19:43:08 +0000834 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 }
836 vol->source_rfc1001_name[15] = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -0700837 /* null target name indicates to use *SMBSERVR default called name
838 if we end up sending RFC1001 session initialize */
839 vol->target_rfc1001_name[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 vol->linux_uid = current->uid; /* current->euid instead? */
841 vol->linux_gid = current->gid;
842 vol->dir_mode = S_IRWXUGO;
843 /* 2767 perms indicate mandatory locking support */
Steve French7505e052007-11-01 18:03:01 +0000844 vol->file_mode = (S_IRWXUGO | S_ISGID) & (~S_IXGRP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845
846 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
Steve French4b18f2a2008-04-29 00:06:05 +0000847 vol->rw = true;
Jeremy Allisonac670552005-06-22 17:26:35 -0700848 /* default is always to request posix paths. */
849 vol->posix_paths = 1;
850
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 if (!options)
852 return 1;
853
Steve French50c2f752007-07-13 00:33:32 +0000854 if (strncmp(options, "sep=", 4) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000855 if (options[4] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 separator[0] = options[4];
857 options += 5;
858 } else {
Steve French467a8f82007-06-27 22:41:32 +0000859 cFYI(1, ("Null separator not allowed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 }
861 }
Steve French50c2f752007-07-13 00:33:32 +0000862
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 while ((data = strsep(&options, separator)) != NULL) {
864 if (!*data)
865 continue;
866 if ((value = strchr(data, '=')) != NULL)
867 *value++ = '\0';
868
Steve French50c2f752007-07-13 00:33:32 +0000869 /* Have to parse this before we parse for "user" */
870 if (strnicmp(data, "user_xattr", 10) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 vol->no_xattr = 0;
Steve French50c2f752007-07-13 00:33:32 +0000872 } else if (strnicmp(data, "nouser_xattr", 12) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 vol->no_xattr = 1;
874 } else if (strnicmp(data, "user", 4) == 0) {
Steve French4b952a92006-10-30 21:46:13 +0000875 if (!value) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 printk(KERN_WARNING
877 "CIFS: invalid or missing username\n");
878 return 1; /* needs_arg; */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000879 } else if (!*value) {
Steve French4b952a92006-10-30 21:46:13 +0000880 /* null user, ie anonymous, authentication */
881 vol->nullauth = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 }
883 if (strnlen(value, 200) < 200) {
884 vol->username = value;
885 } else {
886 printk(KERN_WARNING "CIFS: username too long\n");
887 return 1;
888 }
889 } else if (strnicmp(data, "pass", 4) == 0) {
890 if (!value) {
891 vol->password = NULL;
892 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000893 } else if (value[0] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 /* check if string begins with double comma
895 since that would mean the password really
896 does start with a comma, and would not
897 indicate an empty string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000898 if (value[1] != separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 vol->password = NULL;
900 continue;
901 }
902 }
903 temp_len = strlen(value);
904 /* removed password length check, NTLM passwords
905 can be arbitrarily long */
906
Steve French50c2f752007-07-13 00:33:32 +0000907 /* if comma in password, the string will be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 prematurely null terminated. Commas in password are
909 specified across the cifs mount interface by a double
910 comma ie ,, and a comma used as in other cases ie ','
911 as a parameter delimiter/separator is single and due
912 to the strsep above is temporarily zeroed. */
913
914 /* NB: password legally can have multiple commas and
915 the only illegal character in a password is null */
916
Steve French50c2f752007-07-13 00:33:32 +0000917 if ((value[temp_len] == 0) &&
Steve French09d1db52005-04-28 22:41:08 -0700918 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 /* reinsert comma */
920 value[temp_len] = separator[0];
Steve French50c2f752007-07-13 00:33:32 +0000921 temp_len += 2; /* move after second comma */
922 while (value[temp_len] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 if (value[temp_len] == separator[0]) {
Steve French50c2f752007-07-13 00:33:32 +0000924 if (value[temp_len+1] ==
Steve French09d1db52005-04-28 22:41:08 -0700925 separator[0]) {
926 /* skip second comma */
927 temp_len++;
Steve French50c2f752007-07-13 00:33:32 +0000928 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 /* single comma indicating start
930 of next parm */
931 break;
932 }
933 }
934 temp_len++;
935 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000936 if (value[temp_len] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 options = NULL;
938 } else {
939 value[temp_len] = 0;
940 /* point option to start of next parm */
941 options = value + temp_len + 1;
942 }
Steve French50c2f752007-07-13 00:33:32 +0000943 /* go from value to value + temp_len condensing
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 double commas to singles. Note that this ends up
945 allocating a few bytes too many, which is ok */
Pekka Enberge915fc42005-09-06 15:18:35 -0700946 vol->password = kzalloc(temp_len, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000947 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000948 printk(KERN_WARNING "CIFS: no memory "
949 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700950 return 1;
951 }
Steve French50c2f752007-07-13 00:33:32 +0000952 for (i = 0, j = 0; i < temp_len; i++, j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 vol->password[j] = value[i];
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000954 if (value[i] == separator[0]
Steve French09d1db52005-04-28 22:41:08 -0700955 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 /* skip second comma */
957 i++;
958 }
959 }
960 vol->password[j] = 0;
961 } else {
Pekka Enberge915fc42005-09-06 15:18:35 -0700962 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000963 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000964 printk(KERN_WARNING "CIFS: no memory "
965 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700966 return 1;
967 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 strcpy(vol->password, value);
969 }
970 } else if (strnicmp(data, "ip", 2) == 0) {
971 if (!value || !*value) {
972 vol->UNCip = NULL;
973 } else if (strnlen(value, 35) < 35) {
974 vol->UNCip = value;
975 } else {
Steve French50c2f752007-07-13 00:33:32 +0000976 printk(KERN_WARNING "CIFS: ip address "
977 "too long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 return 1;
979 }
Steve French50c2f752007-07-13 00:33:32 +0000980 } else if (strnicmp(data, "sec", 3) == 0) {
981 if (!value || !*value) {
982 cERROR(1, ("no security value specified"));
983 continue;
984 } else if (strnicmp(value, "krb5i", 5) == 0) {
985 vol->secFlg |= CIFSSEC_MAY_KRB5 |
Steve French189acaa2006-06-23 02:33:48 +0000986 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800987 } else if (strnicmp(value, "krb5p", 5) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000988 /* vol->secFlg |= CIFSSEC_MUST_SEAL |
989 CIFSSEC_MAY_KRB5; */
990 cERROR(1, ("Krb5 cifs privacy not supported"));
Steve Frenchbf820672005-12-01 22:32:42 -0800991 return 1;
992 } else if (strnicmp(value, "krb5", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000993 vol->secFlg |= CIFSSEC_MAY_KRB5;
Steve Frenchbf820672005-12-01 22:32:42 -0800994 } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000995 vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
Steve French189acaa2006-06-23 02:33:48 +0000996 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800997 } else if (strnicmp(value, "ntlmv2", 6) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000998 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve Frenchbf820672005-12-01 22:32:42 -0800999 } else if (strnicmp(value, "ntlmi", 5) == 0) {
Steve French750d1152006-06-27 06:28:30 +00001000 vol->secFlg |= CIFSSEC_MAY_NTLM |
Steve French189acaa2006-06-23 02:33:48 +00001001 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -08001002 } else if (strnicmp(value, "ntlm", 4) == 0) {
1003 /* ntlm is default so can be turned off too */
Steve French750d1152006-06-27 06:28:30 +00001004 vol->secFlg |= CIFSSEC_MAY_NTLM;
Steve Frenchbf820672005-12-01 22:32:42 -08001005 } else if (strnicmp(value, "nontlm", 6) == 0) {
Steve French189acaa2006-06-23 02:33:48 +00001006 /* BB is there a better way to do this? */
Steve French750d1152006-06-27 06:28:30 +00001007 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve French189acaa2006-06-23 02:33:48 +00001008#ifdef CONFIG_CIFS_WEAK_PW_HASH
1009 } else if (strnicmp(value, "lanman", 6) == 0) {
Steve French50c2f752007-07-13 00:33:32 +00001010 vol->secFlg |= CIFSSEC_MAY_LANMAN;
Steve French189acaa2006-06-23 02:33:48 +00001011#endif
Steve Frenchbf820672005-12-01 22:32:42 -08001012 } else if (strnicmp(value, "none", 4) == 0) {
Steve French189acaa2006-06-23 02:33:48 +00001013 vol->nullauth = 1;
Steve French50c2f752007-07-13 00:33:32 +00001014 } else {
1015 cERROR(1, ("bad security option: %s", value));
1016 return 1;
1017 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 } else if ((strnicmp(data, "unc", 3) == 0)
1019 || (strnicmp(data, "target", 6) == 0)
1020 || (strnicmp(data, "path", 4) == 0)) {
1021 if (!value || !*value) {
Steve French50c2f752007-07-13 00:33:32 +00001022 printk(KERN_WARNING "CIFS: invalid path to "
1023 "network resource\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 return 1; /* needs_arg; */
1025 }
1026 if ((temp_len = strnlen(value, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001027 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001028 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001030 strcpy(vol->UNC, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 if (strncmp(vol->UNC, "//", 2) == 0) {
1032 vol->UNC[0] = '\\';
1033 vol->UNC[1] = '\\';
Steve French50c2f752007-07-13 00:33:32 +00001034 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 printk(KERN_WARNING
Steve French50c2f752007-07-13 00:33:32 +00001036 "CIFS: UNC Path does not begin "
1037 "with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 return 1;
1039 }
1040 } else {
1041 printk(KERN_WARNING "CIFS: UNC name too long\n");
1042 return 1;
1043 }
1044 } else if ((strnicmp(data, "domain", 3) == 0)
1045 || (strnicmp(data, "workgroup", 5) == 0)) {
1046 if (!value || !*value) {
1047 printk(KERN_WARNING "CIFS: invalid domain name\n");
1048 return 1; /* needs_arg; */
1049 }
1050 /* BB are there cases in which a comma can be valid in
1051 a domain name and need special handling? */
Steve French39798772006-05-31 22:40:51 +00001052 if (strnlen(value, 256) < 256) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 vol->domainname = value;
1054 cFYI(1, ("Domain name set"));
1055 } else {
Steve French50c2f752007-07-13 00:33:32 +00001056 printk(KERN_WARNING "CIFS: domain name too "
1057 "long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 return 1;
1059 }
Steve French50c2f752007-07-13 00:33:32 +00001060 } else if (strnicmp(data, "prefixpath", 10) == 0) {
1061 if (!value || !*value) {
1062 printk(KERN_WARNING
1063 "CIFS: invalid path prefix\n");
1064 return 1; /* needs_argument */
1065 }
1066 if ((temp_len = strnlen(value, 1024)) < 1024) {
Steve French4523cc32007-04-30 20:13:06 +00001067 if (value[0] != '/')
Steve French2fe87f02006-09-21 07:02:52 +00001068 temp_len++; /* missing leading slash */
Steve French50c2f752007-07-13 00:33:32 +00001069 vol->prepath = kmalloc(temp_len+1, GFP_KERNEL);
1070 if (vol->prepath == NULL)
1071 return 1;
Steve French4523cc32007-04-30 20:13:06 +00001072 if (value[0] != '/') {
Steve French2fe87f02006-09-21 07:02:52 +00001073 vol->prepath[0] = '/';
Steve French50c2f752007-07-13 00:33:32 +00001074 strcpy(vol->prepath+1, value);
Steve French2fe87f02006-09-21 07:02:52 +00001075 } else
Steve French50c2f752007-07-13 00:33:32 +00001076 strcpy(vol->prepath, value);
1077 cFYI(1, ("prefix path %s", vol->prepath));
1078 } else {
1079 printk(KERN_WARNING "CIFS: prefix too long\n");
1080 return 1;
1081 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 } else if (strnicmp(data, "iocharset", 9) == 0) {
1083 if (!value || !*value) {
Steve French63135e02007-07-17 17:34:02 +00001084 printk(KERN_WARNING "CIFS: invalid iocharset "
1085 "specified\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 return 1; /* needs_arg; */
1087 }
1088 if (strnlen(value, 65) < 65) {
Steve French50c2f752007-07-13 00:33:32 +00001089 if (strnicmp(value, "default", 7))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 vol->iocharset = value;
Steve French50c2f752007-07-13 00:33:32 +00001091 /* if iocharset not set then load_nls_default
1092 is used by caller */
1093 cFYI(1, ("iocharset set to %s", value));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 } else {
Steve French63135e02007-07-17 17:34:02 +00001095 printk(KERN_WARNING "CIFS: iocharset name "
1096 "too long.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 return 1;
1098 }
1099 } else if (strnicmp(data, "uid", 3) == 0) {
1100 if (value && *value) {
1101 vol->linux_uid =
1102 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001103 vol->override_uid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 }
1105 } else if (strnicmp(data, "gid", 3) == 0) {
1106 if (value && *value) {
1107 vol->linux_gid =
1108 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001109 vol->override_gid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 }
1111 } else if (strnicmp(data, "file_mode", 4) == 0) {
1112 if (value && *value) {
1113 vol->file_mode =
1114 simple_strtoul(value, &value, 0);
1115 }
1116 } else if (strnicmp(data, "dir_mode", 4) == 0) {
1117 if (value && *value) {
1118 vol->dir_mode =
1119 simple_strtoul(value, &value, 0);
1120 }
1121 } else if (strnicmp(data, "dirmode", 4) == 0) {
1122 if (value && *value) {
1123 vol->dir_mode =
1124 simple_strtoul(value, &value, 0);
1125 }
1126 } else if (strnicmp(data, "port", 4) == 0) {
1127 if (value && *value) {
1128 vol->port =
1129 simple_strtoul(value, &value, 0);
1130 }
1131 } else if (strnicmp(data, "rsize", 5) == 0) {
1132 if (value && *value) {
1133 vol->rsize =
1134 simple_strtoul(value, &value, 0);
1135 }
1136 } else if (strnicmp(data, "wsize", 5) == 0) {
1137 if (value && *value) {
1138 vol->wsize =
1139 simple_strtoul(value, &value, 0);
1140 }
1141 } else if (strnicmp(data, "sockopt", 5) == 0) {
1142 if (value && *value) {
1143 vol->sockopt =
1144 simple_strtoul(value, &value, 0);
1145 }
1146 } else if (strnicmp(data, "netbiosname", 4) == 0) {
1147 if (!value || !*value || (*value == ' ')) {
Steve French63135e02007-07-17 17:34:02 +00001148 cFYI(1, ("invalid (empty) netbiosname"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 } else {
Steve French50c2f752007-07-13 00:33:32 +00001150 memset(vol->source_rfc1001_name, 0x20, 15);
1151 for (i = 0; i < 15; i++) {
1152 /* BB are there cases in which a comma can be
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 valid in this workstation netbios name (and need
1154 special handling)? */
1155
1156 /* We do not uppercase netbiosname for user */
Steve French50c2f752007-07-13 00:33:32 +00001157 if (value[i] == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 break;
Steve French50c2f752007-07-13 00:33:32 +00001159 else
1160 vol->source_rfc1001_name[i] =
1161 value[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 }
1163 /* The string has 16th byte zero still from
1164 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001165 if ((i == 15) && (value[i] != 0))
1166 printk(KERN_WARNING "CIFS: netbiosname"
1167 " longer than 15 truncated.\n");
Steve Frencha10faeb22005-08-22 21:38:31 -07001168 }
1169 } else if (strnicmp(data, "servern", 7) == 0) {
1170 /* servernetbiosname specified override *SMBSERVER */
1171 if (!value || !*value || (*value == ' ')) {
Steve French467a8f82007-06-27 22:41:32 +00001172 cFYI(1, ("empty server netbiosname specified"));
Steve Frencha10faeb22005-08-22 21:38:31 -07001173 } else {
1174 /* last byte, type, is 0x20 for servr type */
Steve French50c2f752007-07-13 00:33:32 +00001175 memset(vol->target_rfc1001_name, 0x20, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001176
Steve French50c2f752007-07-13 00:33:32 +00001177 for (i = 0; i < 15; i++) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001178 /* BB are there cases in which a comma can be
Steve French50c2f752007-07-13 00:33:32 +00001179 valid in this workstation netbios name
1180 (and need special handling)? */
Steve Frencha10faeb22005-08-22 21:38:31 -07001181
Steve French50c2f752007-07-13 00:33:32 +00001182 /* user or mount helper must uppercase
1183 the netbiosname */
1184 if (value[i] == 0)
Steve Frencha10faeb22005-08-22 21:38:31 -07001185 break;
1186 else
Steve French50c2f752007-07-13 00:33:32 +00001187 vol->target_rfc1001_name[i] =
1188 value[i];
Steve Frencha10faeb22005-08-22 21:38:31 -07001189 }
1190 /* The string has 16th byte zero still from
1191 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001192 if ((i == 15) && (value[i] != 0))
1193 printk(KERN_WARNING "CIFS: server net"
1194 "biosname longer than 15 truncated.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 }
1196 } else if (strnicmp(data, "credentials", 4) == 0) {
1197 /* ignore */
1198 } else if (strnicmp(data, "version", 3) == 0) {
1199 /* ignore */
Steve French50c2f752007-07-13 00:33:32 +00001200 } else if (strnicmp(data, "guest", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 /* ignore */
1202 } else if (strnicmp(data, "rw", 2) == 0) {
Steve French4b18f2a2008-04-29 00:06:05 +00001203 vol->rw = true;
Steve Frenchedf1ae42008-10-29 00:47:57 +00001204 } else if (strnicmp(data, "noblocksend", 11) == 0) {
1205 vol->noblocksnd = 1;
1206 } else if (strnicmp(data, "noautotune", 10) == 0) {
1207 vol->noautotune = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 } else if ((strnicmp(data, "suid", 4) == 0) ||
1209 (strnicmp(data, "nosuid", 6) == 0) ||
1210 (strnicmp(data, "exec", 4) == 0) ||
1211 (strnicmp(data, "noexec", 6) == 0) ||
1212 (strnicmp(data, "nodev", 5) == 0) ||
1213 (strnicmp(data, "noauto", 6) == 0) ||
1214 (strnicmp(data, "dev", 3) == 0)) {
1215 /* The mount tool or mount.cifs helper (if present)
Steve French50c2f752007-07-13 00:33:32 +00001216 uses these opts to set flags, and the flags are read
1217 by the kernel vfs layer before we get here (ie
1218 before read super) so there is no point trying to
1219 parse these options again and set anything and it
1220 is ok to just ignore them */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 continue;
1222 } else if (strnicmp(data, "ro", 2) == 0) {
Steve French4b18f2a2008-04-29 00:06:05 +00001223 vol->rw = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 } else if (strnicmp(data, "hard", 4) == 0) {
1225 vol->retry = 1;
1226 } else if (strnicmp(data, "soft", 4) == 0) {
1227 vol->retry = 0;
1228 } else if (strnicmp(data, "perm", 4) == 0) {
1229 vol->noperm = 0;
1230 } else if (strnicmp(data, "noperm", 6) == 0) {
1231 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001232 } else if (strnicmp(data, "mapchars", 8) == 0) {
1233 vol->remap = 1;
1234 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1235 vol->remap = 0;
Steve French50c2f752007-07-13 00:33:32 +00001236 } else if (strnicmp(data, "sfu", 3) == 0) {
1237 vol->sfu_emul = 1;
1238 } else if (strnicmp(data, "nosfu", 5) == 0) {
1239 vol->sfu_emul = 0;
Steve French2c1b8612008-10-16 18:35:21 +00001240 } else if (strnicmp(data, "nodfs", 5) == 0) {
1241 vol->nodfs = 1;
Jeremy Allisonac670552005-06-22 17:26:35 -07001242 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1243 vol->posix_paths = 1;
1244 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1245 vol->posix_paths = 0;
Steve Frenchc18c8422007-07-18 23:21:09 +00001246 } else if (strnicmp(data, "nounix", 6) == 0) {
1247 vol->no_linux_ext = 1;
1248 } else if (strnicmp(data, "nolinux", 7) == 0) {
1249 vol->no_linux_ext = 1;
Steve French50c2f752007-07-13 00:33:32 +00001250 } else if ((strnicmp(data, "nocase", 6) == 0) ||
Steve Frencha10faeb22005-08-22 21:38:31 -07001251 (strnicmp(data, "ignorecase", 10) == 0)) {
Steve French50c2f752007-07-13 00:33:32 +00001252 vol->nocase = 1;
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001253 } else if (strnicmp(data, "brl", 3) == 0) {
1254 vol->nobrl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001255 } else if ((strnicmp(data, "nobrl", 5) == 0) ||
Steve French1c955182005-08-30 20:58:07 -07001256 (strnicmp(data, "nolock", 6) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001257 vol->nobrl = 1;
Steve Frenchd3485d32005-08-19 11:04:29 -07001258 /* turn off mandatory locking in mode
1259 if remote locking is turned off since the
1260 local vfs will do advisory */
Steve French50c2f752007-07-13 00:33:32 +00001261 if (vol->file_mode ==
1262 (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
Steve Frenchd3485d32005-08-19 11:04:29 -07001263 vol->file_mode = S_IALLUGO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 } else if (strnicmp(data, "setuids", 7) == 0) {
1265 vol->setuids = 1;
1266 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1267 vol->setuids = 0;
Jeff Laytond0a9c072008-05-12 22:23:49 +00001268 } else if (strnicmp(data, "dynperm", 7) == 0) {
1269 vol->dynperm = true;
1270 } else if (strnicmp(data, "nodynperm", 9) == 0) {
1271 vol->dynperm = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 } else if (strnicmp(data, "nohard", 6) == 0) {
1273 vol->retry = 0;
1274 } else if (strnicmp(data, "nosoft", 6) == 0) {
1275 vol->retry = 1;
1276 } else if (strnicmp(data, "nointr", 6) == 0) {
1277 vol->intr = 0;
1278 } else if (strnicmp(data, "intr", 4) == 0) {
1279 vol->intr = 1;
Steve French50c2f752007-07-13 00:33:32 +00001280 } else if (strnicmp(data, "serverino", 7) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 vol->server_ino = 1;
Steve French50c2f752007-07-13 00:33:32 +00001282 } else if (strnicmp(data, "noserverino", 9) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 vol->server_ino = 0;
Steve French50c2f752007-07-13 00:33:32 +00001284 } else if (strnicmp(data, "cifsacl", 7) == 0) {
Steve French0a4b92c2006-01-12 15:44:21 -08001285 vol->cifs_acl = 1;
1286 } else if (strnicmp(data, "nocifsacl", 9) == 0) {
1287 vol->cifs_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001288 } else if (strnicmp(data, "acl", 3) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 vol->no_psx_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001290 } else if (strnicmp(data, "noacl", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 vol->no_psx_acl = 1;
Steve French84210e92008-10-23 04:42:37 +00001292#ifdef CONFIG_CIFS_EXPERIMENTAL
1293 } else if (strnicmp(data, "locallease", 6) == 0) {
1294 vol->local_lease = 1;
1295#endif
Steve French50c2f752007-07-13 00:33:32 +00001296 } else if (strnicmp(data, "sign", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +00001297 vol->secFlg |= CIFSSEC_MUST_SIGN;
Steve French95b1cb92008-05-15 16:44:38 +00001298 } else if (strnicmp(data, "seal", 4) == 0) {
1299 /* we do not do the following in secFlags because seal
1300 is a per tree connection (mount) not a per socket
1301 or per-smb connection option in the protocol */
1302 /* vol->secFlg |= CIFSSEC_MUST_SEAL; */
1303 vol->seal = 1;
Steve French50c2f752007-07-13 00:33:32 +00001304 } else if (strnicmp(data, "direct", 6) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001306 } else if (strnicmp(data, "forcedirectio", 13) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001308 } else if (strnicmp(data, "in6_addr", 8) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 if (!value || !*value) {
1310 vol->in6_addr = NULL;
1311 } else if (strnlen(value, 49) == 48) {
1312 vol->in6_addr = value;
1313 } else {
Steve French50c2f752007-07-13 00:33:32 +00001314 printk(KERN_WARNING "CIFS: ip v6 address not "
1315 "48 characters long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 return 1;
1317 }
1318 } else if (strnicmp(data, "noac", 4) == 0) {
Steve French50c2f752007-07-13 00:33:32 +00001319 printk(KERN_WARNING "CIFS: Mount option noac not "
1320 "supported. Instead set "
1321 "/proc/fs/cifs/LookupCacheEnabled to 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 } else
Steve French50c2f752007-07-13 00:33:32 +00001323 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",
1324 data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 }
1326 if (vol->UNC == NULL) {
Steve French4523cc32007-04-30 20:13:06 +00001327 if (devname == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001328 printk(KERN_WARNING "CIFS: Missing UNC name for mount "
1329 "target\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 return 1;
1331 }
1332 if ((temp_len = strnlen(devname, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001333 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001334 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001336 strcpy(vol->UNC, devname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 if (strncmp(vol->UNC, "//", 2) == 0) {
1338 vol->UNC[0] = '\\';
1339 vol->UNC[1] = '\\';
1340 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Steve French50c2f752007-07-13 00:33:32 +00001341 printk(KERN_WARNING "CIFS: UNC Path does not "
1342 "begin with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 return 1;
1344 }
Igor Mammedov7c5e6282008-05-08 20:48:42 +00001345 value = strpbrk(vol->UNC+2, "/\\");
1346 if (value)
1347 *value = '\\';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 } else {
1349 printk(KERN_WARNING "CIFS: UNC name too long\n");
1350 return 1;
1351 }
1352 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001353 if (vol->UNCip == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 vol->UNCip = &vol->UNC[2];
1355
1356 return 0;
1357}
1358
Jeff Laytone7ddee92008-11-14 13:44:38 -05001359static struct TCP_Server_Info *
1360cifs_find_tcp_session(struct sockaddr *addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361{
1362 struct list_head *tmp;
Jeff Laytone7ddee92008-11-14 13:44:38 -05001363 struct TCP_Server_Info *server;
1364 struct sockaddr_in *addr4 = (struct sockaddr_in *) addr;
1365 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366
Jeff Laytone7ddee92008-11-14 13:44:38 -05001367 write_lock(&cifs_tcp_ses_lock);
1368 list_for_each(tmp, &cifs_tcp_ses_list) {
1369 server = list_entry(tmp, struct TCP_Server_Info,
1370 tcp_ses_list);
Jeff Laytone7ddee92008-11-14 13:44:38 -05001371 /*
1372 * the demux thread can exit on its own while still in CifsNew
1373 * so don't accept any sockets in that state. Since the
1374 * tcpStatus never changes back to CifsNew it's safe to check
1375 * for this without a lock.
1376 */
1377 if (server->tcpStatus == CifsNew)
Cyrill Gorcunov1b20d672008-05-09 18:17:21 +00001378 continue;
Steve French50c2f752007-07-13 00:33:32 +00001379
Jeff Laytone7ddee92008-11-14 13:44:38 -05001380 if (addr->sa_family == AF_INET &&
1381 (addr4->sin_addr.s_addr !=
1382 server->addr.sockAddr.sin_addr.s_addr))
1383 continue;
1384 else if (addr->sa_family == AF_INET6 &&
1385 memcmp(&server->addr.sockAddr6.sin6_addr,
1386 &addr6->sin6_addr, sizeof(addr6->sin6_addr)))
1387 continue;
Steve French50c2f752007-07-13 00:33:32 +00001388
Jeff Laytone7ddee92008-11-14 13:44:38 -05001389 ++server->srv_count;
1390 write_unlock(&cifs_tcp_ses_lock);
Steve Frenchd82c2df2008-11-15 00:07:26 +00001391 cFYI(1, ("Existing tcp session with server found"));
Jeff Laytone7ddee92008-11-14 13:44:38 -05001392 return server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 }
Jeff Laytone7ddee92008-11-14 13:44:38 -05001394 write_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 return NULL;
1396}
1397
Jeff Layton14fbf502008-11-14 13:53:46 -05001398static void
Jeff Laytone7ddee92008-11-14 13:44:38 -05001399cifs_put_tcp_session(struct TCP_Server_Info *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400{
Jeff Laytone7ddee92008-11-14 13:44:38 -05001401 struct task_struct *task;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402
Jeff Laytone7ddee92008-11-14 13:44:38 -05001403 write_lock(&cifs_tcp_ses_lock);
1404 if (--server->srv_count > 0) {
1405 write_unlock(&cifs_tcp_ses_lock);
1406 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 }
Steve Frenchdea570e02008-05-06 22:05:51 +00001408
Jeff Laytone7ddee92008-11-14 13:44:38 -05001409 list_del_init(&server->tcp_ses_list);
1410 write_unlock(&cifs_tcp_ses_lock);
1411
1412 spin_lock(&GlobalMid_Lock);
1413 server->tcpStatus = CifsExiting;
1414 spin_unlock(&GlobalMid_Lock);
1415
1416 task = xchg(&server->tsk, NULL);
1417 if (task)
1418 force_sig(SIGKILL, task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419}
1420
Jeff Layton14fbf502008-11-14 13:53:46 -05001421static struct cifsSesInfo *
1422cifs_find_smb_ses(struct TCP_Server_Info *server, char *username)
1423{
1424 struct list_head *tmp;
1425 struct cifsSesInfo *ses;
1426
1427 write_lock(&cifs_tcp_ses_lock);
1428 list_for_each(tmp, &server->smb_ses_list) {
1429 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
1430 if (strncmp(ses->userName, username, MAX_USERNAME_SIZE))
1431 continue;
1432
1433 ++ses->ses_count;
1434 write_unlock(&cifs_tcp_ses_lock);
1435 return ses;
1436 }
1437 write_unlock(&cifs_tcp_ses_lock);
1438 return NULL;
1439}
1440
1441static void
1442cifs_put_smb_ses(struct cifsSesInfo *ses)
1443{
1444 int xid;
1445 struct TCP_Server_Info *server = ses->server;
1446
1447 write_lock(&cifs_tcp_ses_lock);
1448 if (--ses->ses_count > 0) {
1449 write_unlock(&cifs_tcp_ses_lock);
1450 return;
1451 }
1452
1453 list_del_init(&ses->smb_ses_list);
1454 write_unlock(&cifs_tcp_ses_lock);
1455
1456 if (ses->status == CifsGood) {
1457 xid = GetXid();
1458 CIFSSMBLogoff(xid, ses);
1459 _FreeXid(xid);
1460 }
1461 sesInfoFree(ses);
1462 cifs_put_tcp_session(server);
1463}
1464
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465int
Steve French50c2f752007-07-13 00:33:32 +00001466get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
1467 const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
Steve French366781c2008-01-25 10:12:41 +00001468 struct dfs_info3_param **preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469{
1470 char *temp_unc;
1471 int rc = 0;
1472
1473 *pnum_referrals = 0;
Steve French366781c2008-01-25 10:12:41 +00001474 *preferrals = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475
1476 if (pSesInfo->ipc_tid == 0) {
1477 temp_unc = kmalloc(2 /* for slashes */ +
Steve French50c2f752007-07-13 00:33:32 +00001478 strnlen(pSesInfo->serverName,
1479 SERVER_NAME_LEN_WITH_NULL * 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 + 1 + 4 /* slash IPC$ */ + 2,
1481 GFP_KERNEL);
1482 if (temp_unc == NULL)
1483 return -ENOMEM;
1484 temp_unc[0] = '\\';
1485 temp_unc[1] = '\\';
1486 strcpy(temp_unc + 2, pSesInfo->serverName);
1487 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1488 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1489 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00001490 ("CIFS Tcon rc = %d ipc_tid = %d", rc, pSesInfo->ipc_tid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 kfree(temp_unc);
1492 }
1493 if (rc == 0)
Steve Frenchc2cf07d2008-05-15 06:20:02 +00001494 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001495 pnum_referrals, nls_codepage, remap);
Steve French366781c2008-01-25 10:12:41 +00001496 /* BB map targetUNCs to dfs_info3 structures, here or
1497 in CIFSGetDFSRefer BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498
1499 return rc;
1500}
1501
Jeff Layton09e50d52008-07-23 10:11:19 -04001502#ifdef CONFIG_DEBUG_LOCK_ALLOC
1503static struct lock_class_key cifs_key[2];
1504static struct lock_class_key cifs_slock_key[2];
1505
1506static inline void
1507cifs_reclassify_socket4(struct socket *sock)
1508{
1509 struct sock *sk = sock->sk;
1510 BUG_ON(sock_owned_by_user(sk));
1511 sock_lock_init_class_and_name(sk, "slock-AF_INET-CIFS",
1512 &cifs_slock_key[0], "sk_lock-AF_INET-CIFS", &cifs_key[0]);
1513}
1514
1515static inline void
1516cifs_reclassify_socket6(struct socket *sock)
1517{
1518 struct sock *sk = sock->sk;
1519 BUG_ON(sock_owned_by_user(sk));
1520 sock_lock_init_class_and_name(sk, "slock-AF_INET6-CIFS",
1521 &cifs_slock_key[1], "sk_lock-AF_INET6-CIFS", &cifs_key[1]);
1522}
1523#else
1524static inline void
1525cifs_reclassify_socket4(struct socket *sock)
1526{
1527}
1528
1529static inline void
1530cifs_reclassify_socket6(struct socket *sock)
1531{
1532}
1533#endif
1534
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535/* See RFC1001 section 14 on representation of Netbios names */
Steve French50c2f752007-07-13 00:33:32 +00001536static void rfc1002mangle(char *target, char *source, unsigned int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537{
Steve French50c2f752007-07-13 00:33:32 +00001538 unsigned int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539
Steve French50c2f752007-07-13 00:33:32 +00001540 for (i = 0, j = 0; i < (length); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 /* mask a nibble at a time and encode */
1542 target[j] = 'A' + (0x0F & (source[i] >> 4));
1543 target[j+1] = 'A' + (0x0F & source[i]);
Steve French50c2f752007-07-13 00:33:32 +00001544 j += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 }
1546
1547}
1548
1549
1550static int
Steve French50c2f752007-07-13 00:33:32 +00001551ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
Steve Frenchedf1ae42008-10-29 00:47:57 +00001552 char *netbios_name, char *target_name,
1553 bool noblocksnd, bool noautotune)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554{
1555 int rc = 0;
1556 int connected = 0;
1557 __be16 orig_port = 0;
1558
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001559 if (*csocket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001560 rc = sock_create_kern(PF_INET, SOCK_STREAM,
1561 IPPROTO_TCP, csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001563 cERROR(1, ("Error %d creating socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 *csocket = NULL;
1565 return rc;
1566 } else {
1567 /* BB other socket options to set KEEPALIVE, NODELAY? */
Steve French467a8f82007-06-27 22:41:32 +00001568 cFYI(1, ("Socket created"));
Steve French50c2f752007-07-13 00:33:32 +00001569 (*csocket)->sk->sk_allocation = GFP_NOFS;
Jeff Layton09e50d52008-07-23 10:11:19 -04001570 cifs_reclassify_socket4(*csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 }
1572 }
1573
1574 psin_server->sin_family = AF_INET;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001575 if (psin_server->sin_port) { /* user overrode default port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 rc = (*csocket)->ops->connect(*csocket,
1577 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001578 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 if (rc >= 0)
1580 connected = 1;
Steve French50c2f752007-07-13 00:33:32 +00001581 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001583 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001584 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 later if fall back ports fail this time */
1586 orig_port = psin_server->sin_port;
1587
1588 /* do not retry on the same port we just failed on */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001589 if (psin_server->sin_port != htons(CIFS_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 psin_server->sin_port = htons(CIFS_PORT);
1591
1592 rc = (*csocket)->ops->connect(*csocket,
1593 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001594 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 if (rc >= 0)
1596 connected = 1;
1597 }
1598 }
1599 if (!connected) {
1600 psin_server->sin_port = htons(RFC1001_PORT);
1601 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
Steve French50c2f752007-07-13 00:33:32 +00001602 psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001603 sizeof(struct sockaddr_in), 0);
Steve French50c2f752007-07-13 00:33:32 +00001604 if (rc >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 connected = 1;
1606 }
1607
1608 /* give up here - unless we want to retry on different
1609 protocol families some day */
1610 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001611 if (orig_port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 psin_server->sin_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001613 cFYI(1, ("Error %d connecting to server via ipv4", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 sock_release(*csocket);
1615 *csocket = NULL;
1616 return rc;
1617 }
Steve French50c2f752007-07-13 00:33:32 +00001618 /* Eventually check for other socket options to change from
1619 the default. sock_setsockopt not used because it expects
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 user space buffer */
Steve French50c2f752007-07-13 00:33:32 +00001621 cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",
1622 (*csocket)->sk->sk_sndbuf,
Steve Frenchb387eae2005-10-10 14:21:15 -07001623 (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchedf1ae42008-10-29 00:47:57 +00001625 if (!noblocksnd)
1626 (*csocket)->sk->sk_sndtimeo = 3 * HZ;
1627
Steve Frenchb387eae2005-10-10 14:21:15 -07001628 /* make the bufsizes depend on wsize/rsize and max requests */
Steve Frenchedf1ae42008-10-29 00:47:57 +00001629 if (noautotune) {
1630 if ((*csocket)->sk->sk_sndbuf < (200 * 1024))
1631 (*csocket)->sk->sk_sndbuf = 200 * 1024;
1632 if ((*csocket)->sk->sk_rcvbuf < (140 * 1024))
1633 (*csocket)->sk->sk_rcvbuf = 140 * 1024;
1634 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635
1636 /* send RFC1001 sessinit */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001637 if (psin_server->sin_port == htons(RFC1001_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 /* some servers require RFC1001 sessinit before sending
Steve French50c2f752007-07-13 00:33:32 +00001639 negprot - BB check reconnection in case where second
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 sessinit is sent but no second negprot */
Steve French50c2f752007-07-13 00:33:32 +00001641 struct rfc1002_session_packet *ses_init_buf;
1642 struct smb_hdr *smb_buf;
1643 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
1644 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001645 if (ses_init_buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 ses_init_buf->trailer.session_req.called_len = 32;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001647 if (target_name && (target_name[0] != 0)) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001648 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1649 target_name, 16);
1650 } else {
1651 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
Steve French50c2f752007-07-13 00:33:32 +00001652 DEFAULT_CIFS_CALLED_NAME, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001653 }
1654
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 ses_init_buf->trailer.session_req.calling_len = 32;
1656 /* calling name ends in null (byte 16) from old smb
1657 convention. */
Steve French50c2f752007-07-13 00:33:32 +00001658 if (netbios_name && (netbios_name[0] != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
Steve French50c2f752007-07-13 00:33:32 +00001660 netbios_name, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661 } else {
1662 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
Steve French50c2f752007-07-13 00:33:32 +00001663 "LINUX_CIFS_CLNT", 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 }
1665 ses_init_buf->trailer.session_req.scope1 = 0;
1666 ses_init_buf->trailer.session_req.scope2 = 0;
1667 smb_buf = (struct smb_hdr *)ses_init_buf;
1668 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1669 smb_buf->smb_buf_length = 0x81000044;
1670 rc = smb_send(*csocket, smb_buf, 0x44,
Steve Frenchedf1ae42008-10-29 00:47:57 +00001671 (struct sockaddr *)psin_server, noblocksnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 kfree(ses_init_buf);
Steve French50c2f752007-07-13 00:33:32 +00001673 msleep(1); /* RFC1001 layer in at least one server
Steve French083d3a22006-03-03 09:53:36 +00001674 requires very short break before negprot
1675 presumably because not expecting negprot
1676 to follow so fast. This is a simple
Steve French50c2f752007-07-13 00:33:32 +00001677 solution that works without
Steve French083d3a22006-03-03 09:53:36 +00001678 complicating the code and causes no
1679 significant slowing down on mount
1680 for everyone else */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 }
Steve French50c2f752007-07-13 00:33:32 +00001682 /* else the negprot may still work without this
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 even though malloc failed */
Steve French50c2f752007-07-13 00:33:32 +00001684
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 }
Steve French50c2f752007-07-13 00:33:32 +00001686
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 return rc;
1688}
1689
1690static int
Steve Frenchedf1ae42008-10-29 00:47:57 +00001691ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket,
1692 bool noblocksnd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693{
1694 int rc = 0;
1695 int connected = 0;
1696 __be16 orig_port = 0;
1697
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001698 if (*csocket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001699 rc = sock_create_kern(PF_INET6, SOCK_STREAM,
1700 IPPROTO_TCP, csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001702 cERROR(1, ("Error %d creating ipv6 socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 *csocket = NULL;
1704 return rc;
1705 } else {
1706 /* BB other socket options to set KEEPALIVE, NODELAY? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001707 cFYI(1, ("ipv6 Socket created"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 (*csocket)->sk->sk_allocation = GFP_NOFS;
Jeff Layton09e50d52008-07-23 10:11:19 -04001709 cifs_reclassify_socket6(*csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 }
1711 }
1712
1713 psin_server->sin6_family = AF_INET6;
1714
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001715 if (psin_server->sin6_port) { /* user overrode default port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 rc = (*csocket)->ops->connect(*csocket,
1717 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001718 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 if (rc >= 0)
1720 connected = 1;
Steve French50c2f752007-07-13 00:33:32 +00001721 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001723 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001724 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 later if fall back ports fail this time */
1726
1727 orig_port = psin_server->sin6_port;
1728 /* do not retry on the same port we just failed on */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001729 if (psin_server->sin6_port != htons(CIFS_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 psin_server->sin6_port = htons(CIFS_PORT);
1731
1732 rc = (*csocket)->ops->connect(*csocket,
1733 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001734 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 if (rc >= 0)
1736 connected = 1;
1737 }
1738 }
1739 if (!connected) {
1740 psin_server->sin6_port = htons(RFC1001_PORT);
1741 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001742 psin_server, sizeof(struct sockaddr_in6), 0);
Steve French50c2f752007-07-13 00:33:32 +00001743 if (rc >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 connected = 1;
1745 }
1746
1747 /* give up here - unless we want to retry on different
1748 protocol families some day */
1749 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001750 if (orig_port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 psin_server->sin6_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001752 cFYI(1, ("Error %d connecting to server via ipv6", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 sock_release(*csocket);
1754 *csocket = NULL;
1755 return rc;
1756 }
Steve French50c2f752007-07-13 00:33:32 +00001757 /* Eventually check for other socket options to change from
1758 the default. sock_setsockopt not used because it expects
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 user space buffer */
1760 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchedf1ae42008-10-29 00:47:57 +00001761 if (!noblocksnd)
1762 (*csocket)->sk->sk_sndtimeo = 3 * HZ;
1763
Steve French50c2f752007-07-13 00:33:32 +00001764
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 return rc;
1766}
1767
Steve French50c2f752007-07-13 00:33:32 +00001768void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
1769 struct super_block *sb, struct smb_vol *vol_info)
Steve French8af18972007-02-14 04:42:51 +00001770{
1771 /* if we are reconnecting then should we check to see if
1772 * any requested capabilities changed locally e.g. via
1773 * remount but we can not do much about it here
1774 * if they have (even if we could detect it by the following)
1775 * Perhaps we could add a backpointer to array of sb from tcon
1776 * or if we change to make all sb to same share the same
1777 * sb as NFS - then we only have one backpointer to sb.
1778 * What if we wanted to mount the server share twice once with
1779 * and once without posixacls or posix paths? */
1780 __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001781
Steve Frenchc18c8422007-07-18 23:21:09 +00001782 if (vol_info && vol_info->no_linux_ext) {
1783 tcon->fsUnixInfo.Capability = 0;
1784 tcon->unix_ext = 0; /* Unix Extensions disabled */
1785 cFYI(1, ("Linux protocol extensions disabled"));
1786 return;
1787 } else if (vol_info)
1788 tcon->unix_ext = 1; /* Unix Extensions supported */
1789
1790 if (tcon->unix_ext == 0) {
1791 cFYI(1, ("Unix extensions disabled so not set on reconnect"));
1792 return;
1793 }
Steve French50c2f752007-07-13 00:33:32 +00001794
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001795 if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
Steve French8af18972007-02-14 04:42:51 +00001796 __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001797
Steve French8af18972007-02-14 04:42:51 +00001798 /* check for reconnect case in which we do not
1799 want to change the mount behavior if we can avoid it */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001800 if (vol_info == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001801 /* turn off POSIX ACL and PATHNAMES if not set
Steve French8af18972007-02-14 04:42:51 +00001802 originally at mount time */
1803 if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
1804 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00001805 if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
1806 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
1807 cERROR(1, ("POSIXPATH support change"));
Steve French8af18972007-02-14 04:42:51 +00001808 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00001809 } else if ((cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
1810 cERROR(1, ("possible reconnect error"));
1811 cERROR(1,
1812 ("server disabled POSIX path support"));
1813 }
Steve French8af18972007-02-14 04:42:51 +00001814 }
Steve French50c2f752007-07-13 00:33:32 +00001815
Steve French8af18972007-02-14 04:42:51 +00001816 cap &= CIFS_UNIX_CAP_MASK;
Steve French75865f8c2007-06-24 18:30:48 +00001817 if (vol_info && vol_info->no_psx_acl)
Steve French8af18972007-02-14 04:42:51 +00001818 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00001819 else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001820 cFYI(1, ("negotiated posix acl support"));
1821 if (sb)
Steve French8af18972007-02-14 04:42:51 +00001822 sb->s_flags |= MS_POSIXACL;
1823 }
1824
Steve French75865f8c2007-06-24 18:30:48 +00001825 if (vol_info && vol_info->posix_paths == 0)
Steve French8af18972007-02-14 04:42:51 +00001826 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00001827 else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001828 cFYI(1, ("negotiate posix pathnames"));
Steve French75865f8c2007-06-24 18:30:48 +00001829 if (sb)
Steve French50c2f752007-07-13 00:33:32 +00001830 CIFS_SB(sb)->mnt_cifs_flags |=
Steve French8af18972007-02-14 04:42:51 +00001831 CIFS_MOUNT_POSIX_PATHS;
1832 }
Steve French50c2f752007-07-13 00:33:32 +00001833
Steve French984acfe2007-04-26 16:42:50 +00001834 /* We might be setting the path sep back to a different
1835 form if we are reconnecting and the server switched its
Steve French50c2f752007-07-13 00:33:32 +00001836 posix path capability for this share */
Steve French75865f8c2007-06-24 18:30:48 +00001837 if (sb && (CIFS_SB(sb)->prepathlen > 0))
Steve French984acfe2007-04-26 16:42:50 +00001838 CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
Steve French75865f8c2007-06-24 18:30:48 +00001839
1840 if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
1841 if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
1842 CIFS_SB(sb)->rsize = 127 * 1024;
Steve French90c81e02008-02-12 20:32:36 +00001843 cFYI(DBG2,
1844 ("larger reads not supported by srv"));
Steve French75865f8c2007-06-24 18:30:48 +00001845 }
1846 }
Steve French50c2f752007-07-13 00:33:32 +00001847
1848
1849 cFYI(1, ("Negotiate caps 0x%x", (int)cap));
Steve French8af18972007-02-14 04:42:51 +00001850#ifdef CONFIG_CIFS_DEBUG2
Steve French75865f8c2007-06-24 18:30:48 +00001851 if (cap & CIFS_UNIX_FCNTL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001852 cFYI(1, ("FCNTL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001853 if (cap & CIFS_UNIX_EXTATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001854 cFYI(1, ("EXTATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001855 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001856 cFYI(1, ("POSIX path cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001857 if (cap & CIFS_UNIX_XATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001858 cFYI(1, ("XATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001859 if (cap & CIFS_UNIX_POSIX_ACL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001860 cFYI(1, ("POSIX ACL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001861 if (cap & CIFS_UNIX_LARGE_READ_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001862 cFYI(1, ("very large read cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001863 if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001864 cFYI(1, ("very large write cap"));
Steve French8af18972007-02-14 04:42:51 +00001865#endif /* CIFS_DEBUG2 */
1866 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
Steve French442aa312007-09-24 20:25:46 +00001867 if (vol_info == NULL) {
Steve French5a44b312007-09-20 15:16:24 +00001868 cFYI(1, ("resetting capabilities failed"));
Steve French442aa312007-09-24 20:25:46 +00001869 } else
Steve French5a44b312007-09-20 15:16:24 +00001870 cERROR(1, ("Negotiating Unix capabilities "
1871 "with the server failed. Consider "
1872 "mounting with the Unix Extensions\n"
1873 "disabled, if problems are found, "
1874 "by specifying the nounix mount "
Steve French2224f4e2007-09-20 15:37:29 +00001875 "option."));
Steve French5a44b312007-09-20 15:16:24 +00001876
Steve French8af18972007-02-14 04:42:51 +00001877 }
1878 }
1879}
1880
Steve French03a143c2008-02-14 06:38:30 +00001881static void
1882convert_delimiter(char *path, char delim)
1883{
1884 int i;
Steve Frenchc2d68ea2008-02-15 19:20:18 +00001885 char old_delim;
Steve French03a143c2008-02-14 06:38:30 +00001886
1887 if (path == NULL)
1888 return;
1889
Steve French582d21e2008-05-13 04:54:12 +00001890 if (delim == '/')
Steve Frenchc2d68ea2008-02-15 19:20:18 +00001891 old_delim = '\\';
1892 else
1893 old_delim = '/';
1894
Steve French03a143c2008-02-14 06:38:30 +00001895 for (i = 0; path[i] != '\0'; i++) {
Steve Frenchc2d68ea2008-02-15 19:20:18 +00001896 if (path[i] == old_delim)
Steve French03a143c2008-02-14 06:38:30 +00001897 path[i] = delim;
1898 }
1899}
1900
Steve French3b795212008-11-13 19:45:32 +00001901static void setup_cifs_sb(struct smb_vol *pvolume_info,
1902 struct cifs_sb_info *cifs_sb)
1903{
1904 if (pvolume_info->rsize > CIFSMaxBufSize) {
1905 cERROR(1, ("rsize %d too large, using MaxBufSize",
1906 pvolume_info->rsize));
1907 cifs_sb->rsize = CIFSMaxBufSize;
1908 } else if ((pvolume_info->rsize) &&
1909 (pvolume_info->rsize <= CIFSMaxBufSize))
1910 cifs_sb->rsize = pvolume_info->rsize;
1911 else /* default */
1912 cifs_sb->rsize = CIFSMaxBufSize;
1913
1914 if (pvolume_info->wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
1915 cERROR(1, ("wsize %d too large, using 4096 instead",
1916 pvolume_info->wsize));
1917 cifs_sb->wsize = 4096;
1918 } else if (pvolume_info->wsize)
1919 cifs_sb->wsize = pvolume_info->wsize;
1920 else
1921 cifs_sb->wsize = min_t(const int,
1922 PAGEVEC_SIZE * PAGE_CACHE_SIZE,
1923 127*1024);
1924 /* old default of CIFSMaxBufSize was too small now
1925 that SMB Write2 can send multiple pages in kvec.
1926 RFC1001 does not describe what happens when frame
1927 bigger than 128K is sent so use that as max in
1928 conjunction with 52K kvec constraint on arch with 4K
1929 page size */
1930
1931 if (cifs_sb->rsize < 2048) {
1932 cifs_sb->rsize = 2048;
1933 /* Windows ME may prefer this */
1934 cFYI(1, ("readsize set to minimum: 2048"));
1935 }
1936 /* calculate prepath */
1937 cifs_sb->prepath = pvolume_info->prepath;
1938 if (cifs_sb->prepath) {
1939 cifs_sb->prepathlen = strlen(cifs_sb->prepath);
1940 /* we can not convert the / to \ in the path
1941 separators in the prefixpath yet because we do not
1942 know (until reset_cifs_unix_caps is called later)
1943 whether POSIX PATH CAP is available. We normalize
1944 the / to \ after reset_cifs_unix_caps is called */
1945 pvolume_info->prepath = NULL;
1946 } else
1947 cifs_sb->prepathlen = 0;
1948 cifs_sb->mnt_uid = pvolume_info->linux_uid;
1949 cifs_sb->mnt_gid = pvolume_info->linux_gid;
1950 cifs_sb->mnt_file_mode = pvolume_info->file_mode;
1951 cifs_sb->mnt_dir_mode = pvolume_info->dir_mode;
1952 cFYI(1, ("file mode: 0x%x dir mode: 0x%x",
1953 cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode));
1954
1955 if (pvolume_info->noperm)
1956 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
1957 if (pvolume_info->setuids)
1958 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
1959 if (pvolume_info->server_ino)
1960 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
1961 if (pvolume_info->remap)
1962 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
1963 if (pvolume_info->no_xattr)
1964 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
1965 if (pvolume_info->sfu_emul)
1966 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
1967 if (pvolume_info->nobrl)
1968 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
1969 if (pvolume_info->cifs_acl)
1970 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
1971 if (pvolume_info->override_uid)
1972 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
1973 if (pvolume_info->override_gid)
1974 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
1975 if (pvolume_info->dynperm)
1976 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
1977 if (pvolume_info->direct_io) {
1978 cFYI(1, ("mounting share using direct i/o"));
1979 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
1980 }
1981
1982 if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm))
1983 cERROR(1, ("mount option dynperm ignored if cifsacl "
1984 "mount option supported"));
1985}
1986
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987int
1988cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1989 char *mount_data, const char *devname)
1990{
1991 int rc = 0;
1992 int xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 struct socket *csocket = NULL;
Steve French3ec332e2008-11-14 03:35:10 +00001994 struct sockaddr addr;
1995 struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr;
1996 struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 struct smb_vol volume_info;
1998 struct cifsSesInfo *pSesInfo = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 struct cifsTconInfo *tcon = NULL;
2000 struct TCP_Server_Info *srvTcp = NULL;
2001
2002 xid = GetXid();
2003
2004/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
Steve French50c2f752007-07-13 00:33:32 +00002005
Steve French3ec332e2008-11-14 03:35:10 +00002006 memset(&addr, 0, sizeof(struct sockaddr));
Steve French50c2f752007-07-13 00:33:32 +00002007 memset(&volume_info, 0, sizeof(struct smb_vol));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002009 rc = -EINVAL;
2010 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 }
2012
Jeff Layton8426c392007-05-05 03:27:49 +00002013 if (volume_info.nullauth) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002014 cFYI(1, ("null user"));
Jeff Layton9b8f5f52007-11-09 23:25:04 +00002015 volume_info.username = "";
Jeff Layton8426c392007-05-05 03:27:49 +00002016 } else if (volume_info.username) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 /* BB fixme parse for domain name here */
Steve French467a8f82007-06-27 22:41:32 +00002018 cFYI(1, ("Username: %s", volume_info.username));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 } else {
Steve Frenchbf820672005-12-01 22:32:42 -08002020 cifserror("No username specified");
Steve French50c2f752007-07-13 00:33:32 +00002021 /* In userspace mount helper we can get user name from alternate
2022 locations such as env variables and files on disk */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002023 rc = -EINVAL;
2024 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025 }
2026
2027 if (volume_info.UNCip && volume_info.UNC) {
Steve French50c2f752007-07-13 00:33:32 +00002028 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,
Steve French3ec332e2008-11-14 03:35:10 +00002029 &sin_server->sin_addr.s_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002031 if (rc <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 /* not ipv4 address, try ipv6 */
Steve French50c2f752007-07-13 00:33:32 +00002033 rc = cifs_inet_pton(AF_INET6, volume_info.UNCip,
Steve French3ec332e2008-11-14 03:35:10 +00002034 &sin_server6->sin6_addr.in6_u);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002035 if (rc > 0)
Steve French3ec332e2008-11-14 03:35:10 +00002036 addr.sa_family = AF_INET6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 } else {
Steve French3ec332e2008-11-14 03:35:10 +00002038 addr.sa_family = AF_INET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 }
Steve French50c2f752007-07-13 00:33:32 +00002040
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002041 if (rc <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042 /* we failed translating address */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002043 rc = -EINVAL;
2044 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 }
2046
2047 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
2048 /* success */
2049 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002050 } else if (volume_info.UNCip) {
2051 /* BB using ip addr as server name to connect to the
2052 DFS root below */
2053 cERROR(1, ("Connecting to DFS root not implemented yet"));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002054 rc = -EINVAL;
2055 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056 } else /* which servers DFS root would we conect to */ {
2057 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00002058 ("CIFS mount error: No UNC path (e.g. -o "
2059 "unc=//192.168.1.100/public) specified"));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002060 rc = -EINVAL;
2061 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 }
2063
2064 /* this is needed for ASCII cp to Unicode converts */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002065 if (volume_info.iocharset == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066 cifs_sb->local_nls = load_nls_default();
2067 /* load_nls_default can not return null */
2068 } else {
2069 cifs_sb->local_nls = load_nls(volume_info.iocharset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002070 if (cifs_sb->local_nls == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002071 cERROR(1, ("CIFS mount error: iocharset %s not found",
2072 volume_info.iocharset));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002073 rc = -ELIBACC;
2074 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075 }
2076 }
2077
Jeff Laytone7ddee92008-11-14 13:44:38 -05002078 srvTcp = cifs_find_tcp_session(&addr);
Steve Frenchd82c2df2008-11-15 00:07:26 +00002079 if (!srvTcp) { /* create socket */
Steve French3ec332e2008-11-14 03:35:10 +00002080 if (addr.sa_family == AF_INET6) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002081 cFYI(1, ("attempting ipv6 connect"));
Steve French5858ae42007-04-25 11:59:10 +00002082 /* BB should we allow ipv6 on port 139? */
2083 /* other OS never observed in Wild doing 139 with v6 */
Steve French3ec332e2008-11-14 03:35:10 +00002084 sin_server6->sin6_port = htons(volume_info.port);
2085 rc = ipv6_connect(sin_server6, &csocket,
Steve Frenchedf1ae42008-10-29 00:47:57 +00002086 volume_info.noblocksnd);
Steve French3ec332e2008-11-14 03:35:10 +00002087 } else {
2088 sin_server->sin_port = htons(volume_info.port);
2089 rc = ipv4_connect(sin_server, &csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -07002090 volume_info.source_rfc1001_name,
Steve Frenchedf1ae42008-10-29 00:47:57 +00002091 volume_info.target_rfc1001_name,
2092 volume_info.noblocksnd,
2093 volume_info.noautotune);
Steve French3ec332e2008-11-14 03:35:10 +00002094 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095 if (rc < 0) {
Steve French3ec332e2008-11-14 03:35:10 +00002096 cERROR(1, ("Error connecting to socket. "
Steve French50c2f752007-07-13 00:33:32 +00002097 "Aborting operation"));
Steve French4523cc32007-04-30 20:13:06 +00002098 if (csocket != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099 sock_release(csocket);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002100 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 }
2102
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00002103 srvTcp = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
2104 if (!srvTcp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 rc = -ENOMEM;
2106 sock_release(csocket);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002107 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 } else {
Steve Frenchedf1ae42008-10-29 00:47:57 +00002109 srvTcp->noblocksnd = volume_info.noblocksnd;
2110 srvTcp->noautotune = volume_info.noautotune;
Steve French3ec332e2008-11-14 03:35:10 +00002111 if (addr.sa_family == AF_INET6)
2112 memcpy(&srvTcp->addr.sockAddr6, sin_server6,
2113 sizeof(struct sockaddr_in6));
2114 else
2115 memcpy(&srvTcp->addr.sockAddr, sin_server,
2116 sizeof(struct sockaddr_in));
Steve French50c2f752007-07-13 00:33:32 +00002117 atomic_set(&srvTcp->inFlight, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 /* BB Add code for ipv6 case too */
2119 srvTcp->ssocket = csocket;
Jeff Laytonc359cf32007-11-16 22:22:06 +00002120 srvTcp->hostname = extract_hostname(volume_info.UNC);
2121 if (IS_ERR(srvTcp->hostname)) {
2122 rc = PTR_ERR(srvTcp->hostname);
2123 sock_release(csocket);
2124 goto out;
2125 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 init_waitqueue_head(&srvTcp->response_q);
2127 init_waitqueue_head(&srvTcp->request_q);
2128 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
2129 /* at this point we are the only ones with the pointer
2130 to the struct since the kernel thread not created yet
2131 so no need to spinlock this init of tcpStatus */
2132 srvTcp->tcpStatus = CifsNew;
2133 init_MUTEX(&srvTcp->tcpSem);
Igor Mammedovaaf737a2007-04-03 19:16:43 +00002134 srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd");
Steve French8840dee2007-11-16 23:05:52 +00002135 if (IS_ERR(srvTcp->tsk)) {
Igor Mammedovaaf737a2007-04-03 19:16:43 +00002136 rc = PTR_ERR(srvTcp->tsk);
Steve French50c2f752007-07-13 00:33:32 +00002137 cERROR(1, ("error %d create cifsd thread", rc));
Igor Mammedovaaf737a2007-04-03 19:16:43 +00002138 srvTcp->tsk = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139 sock_release(csocket);
Jeff Laytonc359cf32007-11-16 22:22:06 +00002140 kfree(srvTcp->hostname);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002141 goto out;
Steve Frenchf1914012005-08-18 09:37:34 -07002142 }
Steve Frenchf1914012005-08-18 09:37:34 -07002143 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002144 memcpy(srvTcp->workstation_RFC1001_name,
2145 volume_info.source_rfc1001_name, 16);
2146 memcpy(srvTcp->server_RFC1001_name,
2147 volume_info.target_rfc1001_name, 16);
Steve Frenchad009ac2005-04-28 22:41:05 -07002148 srvTcp->sequence_number = 0;
Jeff Laytone7ddee92008-11-14 13:44:38 -05002149 INIT_LIST_HEAD(&srvTcp->tcp_ses_list);
Jeff Layton14fbf502008-11-14 13:53:46 -05002150 INIT_LIST_HEAD(&srvTcp->smb_ses_list);
Jeff Laytone7ddee92008-11-14 13:44:38 -05002151 ++srvTcp->srv_count;
2152 write_lock(&cifs_tcp_ses_lock);
2153 list_add(&srvTcp->tcp_ses_list,
2154 &cifs_tcp_ses_list);
2155 write_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156 }
2157 }
2158
Jeff Layton14fbf502008-11-14 13:53:46 -05002159 pSesInfo = cifs_find_smb_ses(srvTcp, volume_info.username);
2160 if (pSesInfo) {
Jeff Layton1d9a8852007-12-31 01:37:11 +00002161 cFYI(1, ("Existing smb sess found (status=%d)",
2162 pSesInfo->status));
Jeff Layton14fbf502008-11-14 13:53:46 -05002163 /*
2164 * The existing SMB session already has a reference to srvTcp,
2165 * so we can put back the extra one we got before
2166 */
2167 cifs_put_tcp_session(srvTcp);
2168
Steve French88e7d702008-01-03 17:37:09 +00002169 down(&pSesInfo->sesSem);
Steve French3b795212008-11-13 19:45:32 +00002170 if (pSesInfo->need_reconnect) {
Jeff Layton1d9a8852007-12-31 01:37:11 +00002171 cFYI(1, ("Session needs reconnect"));
Jeff Layton1d9a8852007-12-31 01:37:11 +00002172 rc = cifs_setup_session(xid, pSesInfo,
2173 cifs_sb->local_nls);
Jeff Layton1d9a8852007-12-31 01:37:11 +00002174 }
Steve French88e7d702008-01-03 17:37:09 +00002175 up(&pSesInfo->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176 } else if (!rc) {
Steve Frenchbf820672005-12-01 22:32:42 -08002177 cFYI(1, ("Existing smb sess not found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178 pSesInfo = sesInfoAlloc();
Jeff Layton14fbf502008-11-14 13:53:46 -05002179 if (pSesInfo == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180 rc = -ENOMEM;
Jeff Layton14fbf502008-11-14 13:53:46 -05002181 goto mount_fail_check;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 }
2183
Jeff Layton14fbf502008-11-14 13:53:46 -05002184 /* new SMB session uses our srvTcp ref */
2185 pSesInfo->server = srvTcp;
2186 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
2187 NIPQUAD(sin_server->sin_addr.s_addr));
2188
2189 write_lock(&cifs_tcp_ses_lock);
2190 list_add(&pSesInfo->smb_ses_list, &srvTcp->smb_ses_list);
2191 write_unlock(&cifs_tcp_ses_lock);
2192
2193 /* volume_info.password freed at unmount */
2194 if (volume_info.password) {
2195 pSesInfo->password = volume_info.password;
2196 /* set to NULL to prevent freeing on exit */
2197 volume_info.password = NULL;
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002198 }
Jeff Layton14fbf502008-11-14 13:53:46 -05002199 if (volume_info.username)
2200 strncpy(pSesInfo->userName, volume_info.username,
2201 MAX_USERNAME_SIZE);
2202 if (volume_info.domainname) {
2203 int len = strlen(volume_info.domainname);
2204 pSesInfo->domainName = kmalloc(len + 1, GFP_KERNEL);
2205 if (pSesInfo->domainName)
2206 strcpy(pSesInfo->domainName,
2207 volume_info.domainname);
2208 }
2209 pSesInfo->linux_uid = volume_info.linux_uid;
2210 pSesInfo->overrideSecFlg = volume_info.secFlg;
2211 down(&pSesInfo->sesSem);
2212
2213 /* BB FIXME need to pass vol->secFlgs BB */
2214 rc = cifs_setup_session(xid, pSesInfo,
2215 cifs_sb->local_nls);
2216 up(&pSesInfo->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217 }
Steve French50c2f752007-07-13 00:33:32 +00002218
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 /* search for existing tcon to this server share */
2220 if (!rc) {
Steve French3b795212008-11-13 19:45:32 +00002221 setup_cifs_sb(&volume_info, cifs_sb);
Steve French27adb442008-05-23 19:43:29 +00002222
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223 if (tcon) {
Steve Frenchbf820672005-12-01 22:32:42 -08002224 cFYI(1, ("Found match on UNC path"));
Steve French95b1cb92008-05-15 16:44:38 +00002225 if (tcon->seal != volume_info.seal)
2226 cERROR(1, ("transport encryption setting "
2227 "conflicts with existing tid"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 } else {
2229 tcon = tconInfoAlloc();
Steve French3b795212008-11-13 19:45:32 +00002230 if (tcon == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231 rc = -ENOMEM;
Steve French3b795212008-11-13 19:45:32 +00002232 goto mount_fail_check;
2233 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234
Steve French3b795212008-11-13 19:45:32 +00002235 /* check for null share name ie connect to dfs root */
2236
2237 /* BB check if works for exactly length 3 strings */
2238 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
2239 && (strchr(volume_info.UNC + 3, '/') == NULL)) {
2240 /* rc = connect_to_dfs_path(...) */
2241 cFYI(1, ("DFS root not supported"));
2242 rc = -ENODEV;
2243 goto mount_fail_check;
2244 } else {
2245 /* BB Do we need to wrap sesSem around
2246 * this TCon call and Unix SetFS as
2247 * we do on SessSetup and reconnect? */
2248 rc = CIFSTCon(xid, pSesInfo, volume_info.UNC,
2249 tcon, cifs_sb->local_nls);
2250 cFYI(1, ("CIFS Tcon rc = %d", rc));
2251 if (volume_info.nodfs) {
2252 tcon->Flags &= ~SMB_SHARE_IS_IN_DFS;
2253 cFYI(1, ("DFS disabled (%d)",
2254 tcon->Flags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 }
2256 }
Jeff Layton14fbf502008-11-14 13:53:46 -05002257 if (rc)
Steve French3b795212008-11-13 19:45:32 +00002258 goto mount_fail_check;
Jeff Layton14fbf502008-11-14 13:53:46 -05002259 tcon->seal = volume_info.seal;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 }
Steve French3b795212008-11-13 19:45:32 +00002261
2262 /* we can have only one retry value for a connection
2263 to a share so for resources mounted more than once
2264 to the same server share the last value passed in
2265 for the retry flag is used */
2266 tcon->retry = volume_info.retry;
2267 tcon->nocase = volume_info.nocase;
2268 tcon->local_lease = volume_info.local_lease;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 }
Steve French4523cc32007-04-30 20:13:06 +00002270 if (pSesInfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
2272 sb->s_maxbytes = (u64) 1 << 63;
2273 } else
2274 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
2275 }
2276
Steve French8af18972007-02-14 04:42:51 +00002277 /* BB FIXME fix time_gran to be larger for LANMAN sessions */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278 sb->s_time_gran = 100;
2279
Steve French3b795212008-11-13 19:45:32 +00002280mount_fail_check:
Jeff Layton14fbf502008-11-14 13:53:46 -05002281 /* on error free sesinfo and tcon struct if needed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282 if (rc) {
Jeff Laytone7ddee92008-11-14 13:44:38 -05002283 /* If find_unc succeeded then rc == 0 so we can not end */
2284 /* up accidently freeing someone elses tcon struct */
2285 if (tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286 tconInfoFree(tcon);
Jeff Laytone7ddee92008-11-14 13:44:38 -05002287
Jeff Layton14fbf502008-11-14 13:53:46 -05002288 /* should also end up putting our tcp session ref if needed */
2289 if (pSesInfo)
2290 cifs_put_smb_ses(pSesInfo);
2291 else
2292 cifs_put_tcp_session(srvTcp);
Steve Frenchd82c2df2008-11-15 00:07:26 +00002293 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294 }
Steve Frenchd82c2df2008-11-15 00:07:26 +00002295 atomic_inc(&tcon->useCount);
2296 cifs_sb->tcon = tcon;
2297 tcon->ses = pSesInfo;
2298
2299 /* do not care if following two calls succeed - informational */
2300 if (!tcon->ipc) {
2301 CIFSSMBQFSDeviceInfo(xid, tcon);
2302 CIFSSMBQFSAttributeInfo(xid, tcon);
2303 }
2304
2305 /* tell server which Unix caps we support */
2306 if (tcon->ses->capabilities & CAP_UNIX)
2307 /* reset of caps checks mount to see if unix extensions
2308 disabled for just this mount */
2309 reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
2310 else
2311 tcon->unix_ext = 0; /* server does not support them */
2312
2313 /* convert forward to back slashes in prepath here if needed */
2314 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
2315 convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb));
2316
2317 if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
2318 cifs_sb->rsize = 1024 * 127;
2319 cFYI(DBG2, ("no very large read support, rsize now 127K"));
2320 }
2321 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
2322 cifs_sb->wsize = min(cifs_sb->wsize,
2323 (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
2324 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
2325 cifs_sb->rsize = min(cifs_sb->rsize,
2326 (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327
2328 /* volume_info.password is freed above when existing session found
2329 (in which case it is not needed anymore) but when new sesion is created
2330 the password ptr is put in the new session structure (in which case the
2331 password will be freed at unmount time) */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002332out:
2333 /* zero out password before freeing */
2334 if (volume_info.password != NULL) {
2335 memset(volume_info.password, 0, strlen(volume_info.password));
2336 kfree(volume_info.password);
2337 }
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002338 kfree(volume_info.UNC);
Steve French2fe87f02006-09-21 07:02:52 +00002339 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 FreeXid(xid);
2341 return rc;
2342}
2343
2344static int
2345CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French7c7b25b2006-06-01 19:20:10 +00002346 char session_key[CIFS_SESS_KEY_SIZE],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347 const struct nls_table *nls_codepage)
2348{
2349 struct smb_hdr *smb_buffer;
2350 struct smb_hdr *smb_buffer_response;
2351 SESSION_SETUP_ANDX *pSMB;
2352 SESSION_SETUP_ANDX *pSMBr;
2353 char *bcc_ptr;
2354 char *user;
2355 char *domain;
2356 int rc = 0;
2357 int remaining_words = 0;
2358 int bytes_returned = 0;
2359 int len;
2360 __u32 capabilities;
2361 __u16 count;
2362
Steve Frencheeac8042006-01-13 21:34:58 -08002363 cFYI(1, ("In sesssetup"));
Steve French4523cc32007-04-30 20:13:06 +00002364 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365 return -EINVAL;
2366 user = ses->userName;
2367 domain = ses->domainName;
2368 smb_buffer = cifs_buf_get();
Steve French582d21e2008-05-13 04:54:12 +00002369
2370 if (smb_buffer == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371 return -ENOMEM;
Steve French582d21e2008-05-13 04:54:12 +00002372
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373 smb_buffer_response = smb_buffer;
2374 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2375
2376 /* send SMBsessionSetup here */
2377 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2378 NULL /* no tCon exists yet */ , 13 /* wct */ );
2379
Steve French1982c342005-08-17 12:38:22 -07002380 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381 pSMB->req_no_secext.AndXCommand = 0xFF;
2382 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2383 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2384
Steve French50c2f752007-07-13 00:33:32 +00002385 if (ses->server->secMode &
2386 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2388
2389 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2390 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
2391 if (ses->capabilities & CAP_UNICODE) {
2392 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2393 capabilities |= CAP_UNICODE;
2394 }
2395 if (ses->capabilities & CAP_STATUS32) {
2396 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2397 capabilities |= CAP_STATUS32;
2398 }
2399 if (ses->capabilities & CAP_DFS) {
2400 smb_buffer->Flags2 |= SMBFLG2_DFS;
2401 capabilities |= CAP_DFS;
2402 }
2403 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
2404
Steve French50c2f752007-07-13 00:33:32 +00002405 pSMB->req_no_secext.CaseInsensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002406 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407
2408 pSMB->req_no_secext.CaseSensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002409 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410 bcc_ptr = pByteArea(smb_buffer);
Steve French7c7b25b2006-06-01 19:20:10 +00002411 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2412 bcc_ptr += CIFS_SESS_KEY_SIZE;
2413 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2414 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415
2416 if (ses->capabilities & CAP_UNICODE) {
2417 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
2418 *bcc_ptr = 0;
2419 bcc_ptr++;
2420 }
Steve French4523cc32007-04-30 20:13:06 +00002421 if (user == NULL)
Steve French39798772006-05-31 22:40:51 +00002422 bytes_returned = 0; /* skip null user */
Steve French50c2f752007-07-13 00:33:32 +00002423 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424 bytes_returned =
Steve French50c2f752007-07-13 00:33:32 +00002425 cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426 nls_codepage);
2427 /* convert number of 16 bit words to bytes */
2428 bcc_ptr += 2 * bytes_returned;
2429 bcc_ptr += 2; /* trailing null */
2430 if (domain == NULL)
2431 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002432 cifs_strtoUCS((__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433 "CIFS_LINUX_DOM", 32, nls_codepage);
2434 else
2435 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002436 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437 nls_codepage);
2438 bcc_ptr += 2 * bytes_returned;
2439 bcc_ptr += 2;
2440 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002441 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 32, nls_codepage);
2443 bcc_ptr += 2 * bytes_returned;
2444 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002445 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446 32, nls_codepage);
2447 bcc_ptr += 2 * bytes_returned;
2448 bcc_ptr += 2;
2449 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002450 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451 64, nls_codepage);
2452 bcc_ptr += 2 * bytes_returned;
2453 bcc_ptr += 2;
2454 } else {
Steve French50c2f752007-07-13 00:33:32 +00002455 if (user != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456 strncpy(bcc_ptr, user, 200);
2457 bcc_ptr += strnlen(user, 200);
2458 }
2459 *bcc_ptr = 0;
2460 bcc_ptr++;
2461 if (domain == NULL) {
2462 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2463 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2464 } else {
2465 strncpy(bcc_ptr, domain, 64);
2466 bcc_ptr += strnlen(domain, 64);
2467 *bcc_ptr = 0;
2468 bcc_ptr++;
2469 }
2470 strcpy(bcc_ptr, "Linux version ");
2471 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002472 strcpy(bcc_ptr, utsname()->release);
2473 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2475 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2476 }
2477 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2478 smb_buffer->smb_buf_length += count;
2479 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2480
2481 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00002482 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483 if (rc) {
2484/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2485 } else if ((smb_buffer_response->WordCount == 3)
2486 || (smb_buffer_response->WordCount == 4)) {
2487 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2488 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2489 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002490 cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */
2491 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format
2492 (little endian) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493 cFYI(1, ("UID = %d ", ses->Suid));
Steve French50c2f752007-07-13 00:33:32 +00002494 /* response can have either 3 or 4 word count - Samba sends 3 */
2495 bcc_ptr = pByteArea(smb_buffer_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 if ((pSMBr->resp.hdr.WordCount == 3)
2497 || ((pSMBr->resp.hdr.WordCount == 4)
2498 && (blob_len < pSMBr->resp.ByteCount))) {
2499 if (pSMBr->resp.hdr.WordCount == 4)
2500 bcc_ptr += blob_len;
2501
2502 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2503 if ((long) (bcc_ptr) % 2) {
2504 remaining_words =
Steve French50c2f752007-07-13 00:33:32 +00002505 (BCC(smb_buffer_response) - 1) / 2;
2506 /* Unicode strings must be word
2507 aligned */
2508 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509 } else {
2510 remaining_words =
2511 BCC(smb_buffer_response) / 2;
2512 }
2513 len =
2514 UniStrnlen((wchar_t *) bcc_ptr,
2515 remaining_words - 1);
2516/* We look for obvious messed up bcc or strings in response so we do not go off
2517 the end since (at least) WIN2K and Windows XP have a major bug in not null
2518 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002519 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002520 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002521 ses->serverOS = kzalloc(2 * (len + 1),
2522 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002523 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002524 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525 cifs_strfromUCS_le(ses->serverOS,
Steve French50c2f752007-07-13 00:33:32 +00002526 (__le16 *)bcc_ptr,
2527 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528 bcc_ptr += 2 * (len + 1);
2529 remaining_words -= len + 1;
2530 ses->serverOS[2 * len] = 0;
2531 ses->serverOS[1 + (2 * len)] = 0;
2532 if (remaining_words > 0) {
2533 len = UniStrnlen((wchar_t *)bcc_ptr,
2534 remaining_words-1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002535 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002536 ses->serverNOS = kzalloc(2 * (len + 1),
2537 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002538 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002539 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540 cifs_strfromUCS_le(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002541 (__le16 *)bcc_ptr,
2542 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543 bcc_ptr += 2 * (len + 1);
2544 ses->serverNOS[2 * len] = 0;
2545 ses->serverNOS[1 + (2 * len)] = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002546 if (strncmp(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002547 "NT LAN Manager 4", 16) == 0) {
Steve French467a8f82007-06-27 22:41:32 +00002548 cFYI(1, ("NT4 server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549 ses->flags |= CIFS_SES_NT4;
2550 }
2551 remaining_words -= len + 1;
2552 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002553 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Steve French50c2f752007-07-13 00:33:32 +00002554 /* last string is not always null terminated
2555 (for e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002556 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002557 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558 ses->serverDomain =
Steve French50c2f752007-07-13 00:33:32 +00002559 kzalloc(2*(len+1),
2560 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002561 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002562 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563 cifs_strfromUCS_le(ses->serverDomain,
Steve French50c2f752007-07-13 00:33:32 +00002564 (__le16 *)bcc_ptr,
2565 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 bcc_ptr += 2 * (len + 1);
2567 ses->serverDomain[2*len] = 0;
2568 ses->serverDomain[1+(2*len)] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002569 } else { /* else no more room so create
2570 dummy domain string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002571 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002572 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002573 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002574 kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002575 }
Steve French50c2f752007-07-13 00:33:32 +00002576 } else { /* no room so create dummy domain
2577 and NOS string */
2578
Steve French433dc242005-04-28 22:41:08 -07002579 /* if these kcallocs fail not much we
2580 can do, but better to not fail the
2581 sesssetup itself */
Steve Frenchcd49b492006-06-26 04:22:36 +00002582 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002584 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002585 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002587 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 }
2589 } else { /* ASCII */
2590 len = strnlen(bcc_ptr, 1024);
2591 if (((long) bcc_ptr + len) - (long)
2592 pByteArea(smb_buffer_response)
2593 <= BCC(smb_buffer_response)) {
Steve Frenchcd49b492006-06-26 04:22:36 +00002594 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002595 ses->serverOS = kzalloc(len + 1,
2596 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002597 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002598 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002599 strncpy(ses->serverOS, bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600
2601 bcc_ptr += len;
Steve French50c2f752007-07-13 00:33:32 +00002602 /* null terminate the string */
2603 bcc_ptr[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 bcc_ptr++;
2605
2606 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002607 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002608 ses->serverNOS = kzalloc(len + 1,
2609 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002610 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002611 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 strncpy(ses->serverNOS, bcc_ptr, len);
2613 bcc_ptr += len;
2614 bcc_ptr[0] = 0;
2615 bcc_ptr++;
2616
2617 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002618 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002619 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002620 ses->serverDomain = kzalloc(len + 1,
2621 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002622 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002623 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002624 strncpy(ses->serverDomain, bcc_ptr,
2625 len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626 bcc_ptr += len;
2627 bcc_ptr[0] = 0;
2628 bcc_ptr++;
2629 } else
2630 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00002631 ("Variable field of length %d "
2632 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 len));
2634 }
2635 } else {
2636 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00002637 (" Security Blob Length extends beyond "
2638 "end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 }
2640 } else {
2641 cERROR(1,
2642 (" Invalid Word count %d: ",
2643 smb_buffer_response->WordCount));
2644 rc = -EIO;
2645 }
Steve French433dc242005-04-28 22:41:08 -07002646sesssetup_nomem: /* do not return an error on nomem for the info strings,
2647 since that could make reconnection harder, and
2648 reconnection might be needed to free memory */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00002649 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650
2651 return rc;
2652}
2653
2654static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
Steve French4b18f2a2008-04-29 00:06:05 +00002656 struct cifsSesInfo *ses, bool *pNTLMv2_flag,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 const struct nls_table *nls_codepage)
2658{
2659 struct smb_hdr *smb_buffer;
2660 struct smb_hdr *smb_buffer_response;
2661 SESSION_SETUP_ANDX *pSMB;
2662 SESSION_SETUP_ANDX *pSMBr;
2663 char *bcc_ptr;
2664 char *domain;
2665 int rc = 0;
2666 int remaining_words = 0;
2667 int bytes_returned = 0;
2668 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002669 int SecurityBlobLength = sizeof(NEGOTIATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670 PNEGOTIATE_MESSAGE SecurityBlob;
2671 PCHALLENGE_MESSAGE SecurityBlob2;
2672 __u32 negotiate_flags, capabilities;
2673 __u16 count;
2674
Steve French12b3b8f2006-02-09 21:12:47 +00002675 cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002676 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 return -EINVAL;
2678 domain = ses->domainName;
Steve French4b18f2a2008-04-29 00:06:05 +00002679 *pNTLMv2_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 smb_buffer = cifs_buf_get();
2681 if (smb_buffer == NULL) {
2682 return -ENOMEM;
2683 }
2684 smb_buffer_response = smb_buffer;
2685 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2686 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2687
2688 /* send SMBsessionSetup here */
2689 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2690 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002691
2692 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2694 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2695
2696 pSMB->req.AndXCommand = 0xFF;
2697 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2698 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2699
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002700 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2702
2703 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2704 CAP_EXTENDED_SECURITY;
2705 if (ses->capabilities & CAP_UNICODE) {
2706 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2707 capabilities |= CAP_UNICODE;
2708 }
2709 if (ses->capabilities & CAP_STATUS32) {
2710 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2711 capabilities |= CAP_STATUS32;
2712 }
2713 if (ses->capabilities & CAP_DFS) {
2714 smb_buffer->Flags2 |= SMBFLG2_DFS;
2715 capabilities |= CAP_DFS;
2716 }
2717 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2718
2719 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2720 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2721 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2722 SecurityBlob->MessageType = NtLmNegotiate;
2723 negotiate_flags =
2724 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
Steve French12b3b8f2006-02-09 21:12:47 +00002725 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
2726 NTLMSSP_NEGOTIATE_56 |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002728 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002730/* if (ntlmv2_support)
Steve French39798772006-05-31 22:40:51 +00002731 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 /* setup pointers to domain name and workstation name */
2733 bcc_ptr += SecurityBlobLength;
2734
2735 SecurityBlob->WorkstationName.Buffer = 0;
2736 SecurityBlob->WorkstationName.Length = 0;
2737 SecurityBlob->WorkstationName.MaximumLength = 0;
2738
Steve French12b3b8f2006-02-09 21:12:47 +00002739 /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent
2740 along with username on auth request (ie the response to challenge) */
2741 SecurityBlob->DomainName.Buffer = 0;
2742 SecurityBlob->DomainName.Length = 0;
2743 SecurityBlob->DomainName.MaximumLength = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 if (ses->capabilities & CAP_UNICODE) {
2745 if ((long) bcc_ptr % 2) {
2746 *bcc_ptr = 0;
2747 bcc_ptr++;
2748 }
2749
2750 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002751 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 32, nls_codepage);
2753 bcc_ptr += 2 * bytes_returned;
2754 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002755 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 nls_codepage);
2757 bcc_ptr += 2 * bytes_returned;
2758 bcc_ptr += 2; /* null terminate Linux version */
2759 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002760 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 64, nls_codepage);
2762 bcc_ptr += 2 * bytes_returned;
2763 *(bcc_ptr + 1) = 0;
2764 *(bcc_ptr + 2) = 0;
2765 bcc_ptr += 2; /* null terminate network opsys string */
2766 *(bcc_ptr + 1) = 0;
2767 *(bcc_ptr + 2) = 0;
2768 bcc_ptr += 2; /* null domain */
2769 } else { /* ASCII */
2770 strcpy(bcc_ptr, "Linux version ");
2771 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002772 strcpy(bcc_ptr, utsname()->release);
2773 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2775 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2776 bcc_ptr++; /* empty domain field */
2777 *bcc_ptr = 0;
2778 }
2779 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2780 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2781 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2782 smb_buffer->smb_buf_length += count;
2783 pSMB->req.ByteCount = cpu_to_le16(count);
2784
2785 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00002786 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787
2788 if (smb_buffer_response->Status.CifsError ==
2789 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2790 rc = 0;
2791
2792 if (rc) {
2793/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2794 } else if ((smb_buffer_response->WordCount == 3)
2795 || (smb_buffer_response->WordCount == 4)) {
2796 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2797 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2798
2799 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002800 cFYI(1, (" Guest login"));
2801 /* Do we want to set anything in SesInfo struct when guest login? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802
Steve French50c2f752007-07-13 00:33:32 +00002803 bcc_ptr = pByteArea(smb_buffer_response);
2804 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002805
2806 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2807 if (SecurityBlob2->MessageType != NtLmChallenge) {
2808 cFYI(1,
2809 ("Unexpected NTLMSSP message type received %d",
2810 SecurityBlob2->MessageType));
2811 } else if (ses) {
Steve French50c2f752007-07-13 00:33:32 +00002812 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
Steve French12b3b8f2006-02-09 21:12:47 +00002813 cFYI(1, ("UID = %d", ses->Suid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814 if ((pSMBr->resp.hdr.WordCount == 3)
2815 || ((pSMBr->resp.hdr.WordCount == 4)
2816 && (blob_len <
2817 pSMBr->resp.ByteCount))) {
2818
2819 if (pSMBr->resp.hdr.WordCount == 4) {
2820 bcc_ptr += blob_len;
Steve French12b3b8f2006-02-09 21:12:47 +00002821 cFYI(1, ("Security Blob Length %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822 blob_len));
2823 }
2824
Steve French12b3b8f2006-02-09 21:12:47 +00002825 cFYI(1, ("NTLMSSP Challenge rcvd"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826
2827 memcpy(ses->server->cryptKey,
2828 SecurityBlob2->Challenge,
2829 CIFS_CRYPTO_KEY_SIZE);
Steve French50c2f752007-07-13 00:33:32 +00002830 if (SecurityBlob2->NegotiateFlags &
Steve French12b3b8f2006-02-09 21:12:47 +00002831 cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
Steve French4b18f2a2008-04-29 00:06:05 +00002832 *pNTLMv2_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833
Steve French50c2f752007-07-13 00:33:32 +00002834 if ((SecurityBlob2->NegotiateFlags &
2835 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836 || (sign_CIFS_PDUs > 1))
Steve French50c2f752007-07-13 00:33:32 +00002837 ses->server->secMode |=
2838 SECMODE_SIGN_REQUIRED;
2839 if ((SecurityBlob2->NegotiateFlags &
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
Steve French50c2f752007-07-13 00:33:32 +00002841 ses->server->secMode |=
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842 SECMODE_SIGN_ENABLED;
2843
2844 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2845 if ((long) (bcc_ptr) % 2) {
2846 remaining_words =
2847 (BCC(smb_buffer_response)
2848 - 1) / 2;
Steve French50c2f752007-07-13 00:33:32 +00002849 /* Must word align unicode strings */
2850 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851 } else {
2852 remaining_words =
2853 BCC
2854 (smb_buffer_response) / 2;
2855 }
2856 len =
2857 UniStrnlen((wchar_t *) bcc_ptr,
2858 remaining_words - 1);
2859/* We look for obvious messed up bcc or strings in response so we do not go off
2860 the end since (at least) WIN2K and Windows XP have a major bug in not null
2861 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002862 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002863 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002865 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002867 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868 bcc_ptr, len,
2869 nls_codepage);
2870 bcc_ptr += 2 * (len + 1);
2871 remaining_words -= len + 1;
2872 ses->serverOS[2 * len] = 0;
2873 ses->serverOS[1 + (2 * len)] = 0;
2874 if (remaining_words > 0) {
2875 len = UniStrnlen((wchar_t *)
2876 bcc_ptr,
2877 remaining_words
2878 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002879 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002881 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882 GFP_KERNEL);
2883 cifs_strfromUCS_le(ses->
2884 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002885 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886 bcc_ptr,
2887 len,
2888 nls_codepage);
2889 bcc_ptr += 2 * (len + 1);
2890 ses->serverNOS[2 * len] = 0;
2891 ses->serverNOS[1 +
2892 (2 * len)] = 0;
2893 remaining_words -= len + 1;
2894 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00002895 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2896 /* last string not always null terminated
2897 (for e.g. for Windows XP & 2000) */
Steve Frenchcd49b492006-06-26 04:22:36 +00002898 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002900 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901 (len +
2902 1),
2903 GFP_KERNEL);
2904 cifs_strfromUCS_le
Steve Frenche89dc922005-11-11 15:18:19 -08002905 (ses->serverDomain,
2906 (__le16 *)bcc_ptr,
2907 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908 bcc_ptr +=
2909 2 * (len + 1);
Steve Frenche89dc922005-11-11 15:18:19 -08002910 ses->serverDomain[2*len]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911 = 0;
Steve Frenche89dc922005-11-11 15:18:19 -08002912 ses->serverDomain
2913 [1 + (2 * len)]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914 = 0;
2915 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002916 else {
Steve Frenchcd49b492006-06-26 04:22:36 +00002917 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002919 kzalloc(2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920 GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002921 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922 } else { /* no room so create dummy domain and NOS string */
Steve Frenchcd49b492006-06-26 04:22:36 +00002923 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002925 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002926 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002928 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929 }
2930 } else { /* ASCII */
2931 len = strnlen(bcc_ptr, 1024);
2932 if (((long) bcc_ptr + len) - (long)
2933 pByteArea(smb_buffer_response)
2934 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002935 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002936 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002938 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939 GFP_KERNEL);
2940 strncpy(ses->serverOS,
2941 bcc_ptr, len);
2942
2943 bcc_ptr += len;
2944 bcc_ptr[0] = 0; /* null terminate string */
2945 bcc_ptr++;
2946
2947 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002948 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002950 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951 GFP_KERNEL);
2952 strncpy(ses->serverNOS, bcc_ptr, len);
2953 bcc_ptr += len;
2954 bcc_ptr[0] = 0;
2955 bcc_ptr++;
2956
2957 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002958 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002960 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +00002962 strncpy(ses->serverDomain,
2963 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964 bcc_ptr += len;
2965 bcc_ptr[0] = 0;
2966 bcc_ptr++;
2967 } else
2968 cFYI(1,
Steve French63135e02007-07-17 17:34:02 +00002969 ("field of length %d "
2970 "extends beyond end of smb",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971 len));
2972 }
2973 } else {
Steve French50c2f752007-07-13 00:33:32 +00002974 cERROR(1, ("Security Blob Length extends beyond"
2975 " end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976 }
2977 } else {
2978 cERROR(1, ("No session structure passed in."));
2979 }
2980 } else {
2981 cERROR(1,
Steve French5815449d2006-02-14 01:36:20 +00002982 (" Invalid Word count %d:",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983 smb_buffer_response->WordCount));
2984 rc = -EIO;
2985 }
2986
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00002987 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988
2989 return rc;
2990}
2991static int
2992CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French4b18f2a2008-04-29 00:06:05 +00002993 char *ntlm_session_key, bool ntlmv2_flag,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002994 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995{
2996 struct smb_hdr *smb_buffer;
2997 struct smb_hdr *smb_buffer_response;
2998 SESSION_SETUP_ANDX *pSMB;
2999 SESSION_SETUP_ANDX *pSMBr;
3000 char *bcc_ptr;
3001 char *user;
3002 char *domain;
3003 int rc = 0;
3004 int remaining_words = 0;
3005 int bytes_returned = 0;
3006 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003007 int SecurityBlobLength = sizeof(AUTHENTICATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008 PAUTHENTICATE_MESSAGE SecurityBlob;
3009 __u32 negotiate_flags, capabilities;
3010 __u16 count;
3011
3012 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003013 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014 return -EINVAL;
3015 user = ses->userName;
3016 domain = ses->domainName;
3017 smb_buffer = cifs_buf_get();
3018 if (smb_buffer == NULL) {
3019 return -ENOMEM;
3020 }
3021 smb_buffer_response = smb_buffer;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003022 pSMB = (SESSION_SETUP_ANDX *)smb_buffer;
3023 pSMBr = (SESSION_SETUP_ANDX *)smb_buffer_response;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024
3025 /* send SMBsessionSetup here */
3026 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
3027 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07003028
3029 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
3031 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
3032 pSMB->req.AndXCommand = 0xFF;
3033 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
3034 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
3035
3036 pSMB->req.hdr.Uid = ses->Suid;
3037
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003038 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3040
3041 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003042 CAP_EXTENDED_SECURITY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043 if (ses->capabilities & CAP_UNICODE) {
3044 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3045 capabilities |= CAP_UNICODE;
3046 }
3047 if (ses->capabilities & CAP_STATUS32) {
3048 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3049 capabilities |= CAP_STATUS32;
3050 }
3051 if (ses->capabilities & CAP_DFS) {
3052 smb_buffer->Flags2 |= SMBFLG2_DFS;
3053 capabilities |= CAP_DFS;
3054 }
3055 pSMB->req.Capabilities = cpu_to_le32(capabilities);
3056
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003057 bcc_ptr = (char *)&pSMB->req.SecurityBlob;
3058 SecurityBlob = (PAUTHENTICATE_MESSAGE)bcc_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
3060 SecurityBlob->MessageType = NtLmAuthenticate;
3061 bcc_ptr += SecurityBlobLength;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003062 negotiate_flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
3063 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
3064 0x80000000 | NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003065 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003067 if (ntlmv2_flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
3069
3070/* setup pointers to domain name and workstation name */
3071
3072 SecurityBlob->WorkstationName.Buffer = 0;
3073 SecurityBlob->WorkstationName.Length = 0;
3074 SecurityBlob->WorkstationName.MaximumLength = 0;
3075 SecurityBlob->SessionKey.Length = 0;
3076 SecurityBlob->SessionKey.MaximumLength = 0;
3077 SecurityBlob->SessionKey.Buffer = 0;
3078
3079 SecurityBlob->LmChallengeResponse.Length = 0;
3080 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
3081 SecurityBlob->LmChallengeResponse.Buffer = 0;
3082
3083 SecurityBlob->NtChallengeResponse.Length =
Steve French7c7b25b2006-06-01 19:20:10 +00003084 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085 SecurityBlob->NtChallengeResponse.MaximumLength =
Steve French7c7b25b2006-06-01 19:20:10 +00003086 cpu_to_le16(CIFS_SESS_KEY_SIZE);
3087 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088 SecurityBlob->NtChallengeResponse.Buffer =
3089 cpu_to_le32(SecurityBlobLength);
Steve French7c7b25b2006-06-01 19:20:10 +00003090 SecurityBlobLength += CIFS_SESS_KEY_SIZE;
3091 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092
3093 if (ses->capabilities & CAP_UNICODE) {
3094 if (domain == NULL) {
3095 SecurityBlob->DomainName.Buffer = 0;
3096 SecurityBlob->DomainName.Length = 0;
3097 SecurityBlob->DomainName.MaximumLength = 0;
3098 } else {
Steve French77159b42007-08-31 01:10:17 +00003099 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00003101 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003103 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104 SecurityBlob->DomainName.Buffer =
3105 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003106 bcc_ptr += ln;
3107 SecurityBlobLength += ln;
3108 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109 }
3110 if (user == NULL) {
3111 SecurityBlob->UserName.Buffer = 0;
3112 SecurityBlob->UserName.Length = 0;
3113 SecurityBlob->UserName.MaximumLength = 0;
3114 } else {
Steve French77159b42007-08-31 01:10:17 +00003115 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00003117 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118 SecurityBlob->UserName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003119 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120 SecurityBlob->UserName.Buffer =
3121 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003122 bcc_ptr += ln;
3123 SecurityBlobLength += ln;
3124 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125 }
3126
Steve French63135e02007-07-17 17:34:02 +00003127 /* SecurityBlob->WorkstationName.Length =
3128 cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129 SecurityBlob->WorkstationName.Length *= 2;
Steve French63135e02007-07-17 17:34:02 +00003130 SecurityBlob->WorkstationName.MaximumLength =
3131 cpu_to_le16(SecurityBlob->WorkstationName.Length);
3132 SecurityBlob->WorkstationName.Buffer =
3133 cpu_to_le32(SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134 bcc_ptr += SecurityBlob->WorkstationName.Length;
3135 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
Steve French63135e02007-07-17 17:34:02 +00003136 SecurityBlob->WorkstationName.Length =
3137 cpu_to_le16(SecurityBlob->WorkstationName.Length); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138
3139 if ((long) bcc_ptr % 2) {
3140 *bcc_ptr = 0;
3141 bcc_ptr++;
3142 }
3143 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003144 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003145 32, nls_codepage);
3146 bcc_ptr += 2 * bytes_returned;
3147 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003148 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149 nls_codepage);
3150 bcc_ptr += 2 * bytes_returned;
3151 bcc_ptr += 2; /* null term version string */
3152 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003153 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154 64, nls_codepage);
3155 bcc_ptr += 2 * bytes_returned;
3156 *(bcc_ptr + 1) = 0;
3157 *(bcc_ptr + 2) = 0;
3158 bcc_ptr += 2; /* null terminate network opsys string */
3159 *(bcc_ptr + 1) = 0;
3160 *(bcc_ptr + 2) = 0;
3161 bcc_ptr += 2; /* null domain */
3162 } else { /* ASCII */
3163 if (domain == NULL) {
3164 SecurityBlob->DomainName.Buffer = 0;
3165 SecurityBlob->DomainName.Length = 0;
3166 SecurityBlob->DomainName.MaximumLength = 0;
3167 } else {
Steve French77159b42007-08-31 01:10:17 +00003168 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
3170 strncpy(bcc_ptr, domain, 63);
Steve French77159b42007-08-31 01:10:17 +00003171 ln = strnlen(domain, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003173 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003174 SecurityBlob->DomainName.Buffer =
3175 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003176 bcc_ptr += ln;
3177 SecurityBlobLength += ln;
3178 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179 }
3180 if (user == NULL) {
3181 SecurityBlob->UserName.Buffer = 0;
3182 SecurityBlob->UserName.Length = 0;
3183 SecurityBlob->UserName.MaximumLength = 0;
3184 } else {
Steve French77159b42007-08-31 01:10:17 +00003185 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186 strncpy(bcc_ptr, user, 63);
Steve French77159b42007-08-31 01:10:17 +00003187 ln = strnlen(user, 64);
3188 SecurityBlob->UserName.MaximumLength = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189 SecurityBlob->UserName.Buffer =
Steve French77159b42007-08-31 01:10:17 +00003190 cpu_to_le32(SecurityBlobLength);
3191 bcc_ptr += ln;
3192 SecurityBlobLength += ln;
3193 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194 }
3195 /* BB fill in our workstation name if known BB */
3196
3197 strcpy(bcc_ptr, "Linux version ");
3198 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003199 strcpy(bcc_ptr, utsname()->release);
3200 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
3202 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
3203 bcc_ptr++; /* null domain */
3204 *bcc_ptr = 0;
3205 }
3206 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
3207 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
3208 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
3209 smb_buffer->smb_buf_length += count;
3210 pSMB->req.ByteCount = cpu_to_le16(count);
3211
3212 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00003213 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214 if (rc) {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003215/* rc = map_smb_to_linux_error(smb_buffer_response) done in SendReceive now */
3216 } else if ((smb_buffer_response->WordCount == 3) ||
3217 (smb_buffer_response->WordCount == 4)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218 __u16 action = le16_to_cpu(pSMBr->resp.Action);
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003219 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00003221 cFYI(1, (" Guest login")); /* BB Should we set anything
3222 in SesInfo struct ? */
3223/* if (SecurityBlob2->MessageType != NtLm??) {
3224 cFYI("Unexpected message type on auth response is %d"));
3225 } */
3226
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227 if (ses) {
3228 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003229 ("Check challenge UID %d vs auth response UID %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230 ses->Suid, smb_buffer_response->Uid));
Steve French50c2f752007-07-13 00:33:32 +00003231 /* UID left in wire format */
3232 ses->Suid = smb_buffer_response->Uid;
3233 bcc_ptr = pByteArea(smb_buffer_response);
3234 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235 if ((pSMBr->resp.hdr.WordCount == 3)
3236 || ((pSMBr->resp.hdr.WordCount == 4)
3237 && (blob_len <
3238 pSMBr->resp.ByteCount))) {
3239 if (pSMBr->resp.hdr.WordCount == 4) {
3240 bcc_ptr +=
3241 blob_len;
3242 cFYI(1,
3243 ("Security Blob Length %d ",
3244 blob_len));
3245 }
3246
3247 cFYI(1,
3248 ("NTLMSSP response to Authenticate "));
3249
3250 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3251 if ((long) (bcc_ptr) % 2) {
3252 remaining_words =
3253 (BCC(smb_buffer_response)
3254 - 1) / 2;
3255 bcc_ptr++; /* Unicode strings must be word aligned */
3256 } else {
3257 remaining_words = BCC(smb_buffer_response) / 2;
3258 }
Steve French77159b42007-08-31 01:10:17 +00003259 len = UniStrnlen((wchar_t *) bcc_ptr,
3260 remaining_words - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003261/* We look for obvious messed up bcc or strings in response so we do not go off
3262 the end since (at least) WIN2K and Windows XP have a major bug in not null
3263 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003264 if (ses->serverOS)
Steve French08775832006-05-30 18:08:26 +00003265 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003267 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003268 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003269 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003270 bcc_ptr, len,
3271 nls_codepage);
3272 bcc_ptr += 2 * (len + 1);
3273 remaining_words -= len + 1;
3274 ses->serverOS[2 * len] = 0;
3275 ses->serverOS[1 + (2 * len)] = 0;
3276 if (remaining_words > 0) {
3277 len = UniStrnlen((wchar_t *)
3278 bcc_ptr,
3279 remaining_words
3280 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00003281 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003283 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003284 GFP_KERNEL);
3285 cifs_strfromUCS_le(ses->
3286 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003287 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288 bcc_ptr,
3289 len,
3290 nls_codepage);
3291 bcc_ptr += 2 * (len + 1);
3292 ses->serverNOS[2 * len] = 0;
3293 ses->serverNOS[1+(2*len)] = 0;
3294 remaining_words -= len + 1;
3295 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00003296 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297 /* last string not always null terminated (e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003298 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003299 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003300 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003301 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302 (len +
3303 1),
3304 GFP_KERNEL);
3305 cifs_strfromUCS_le
3306 (ses->
3307 serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08003308 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003309 bcc_ptr, len,
3310 nls_codepage);
3311 bcc_ptr +=
3312 2 * (len + 1);
3313 ses->
3314 serverDomain[2
3315 * len]
3316 = 0;
3317 ses->
3318 serverDomain[1
3319 +
3320 (2
3321 *
3322 len)]
3323 = 0;
3324 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003325 else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003326 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003327 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003328 ses->serverDomain = kzalloc(2,GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00003329 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003330 } else { /* no room so create dummy domain and NOS string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003331 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003332 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003333 ses->serverDomain = kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00003334 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003335 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336 }
3337 } else { /* ASCII */
3338 len = strnlen(bcc_ptr, 1024);
Steve French50c2f752007-07-13 00:33:32 +00003339 if (((long) bcc_ptr + len) -
3340 (long) pByteArea(smb_buffer_response)
Steve French63135e02007-07-17 17:34:02 +00003341 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003342 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00003343 kfree(ses->serverOS);
Steve French77159b42007-08-31 01:10:17 +00003344 ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345 strncpy(ses->serverOS,bcc_ptr, len);
3346
3347 bcc_ptr += len;
3348 bcc_ptr[0] = 0; /* null terminate the string */
3349 bcc_ptr++;
3350
3351 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003352 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00003353 ses->serverNOS = kzalloc(len+1,
3354 GFP_KERNEL);
Steve French63135e02007-07-17 17:34:02 +00003355 strncpy(ses->serverNOS,
3356 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003357 bcc_ptr += len;
3358 bcc_ptr[0] = 0;
3359 bcc_ptr++;
3360
3361 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003362 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003363 kfree(ses->serverDomain);
Steve French63135e02007-07-17 17:34:02 +00003364 ses->serverDomain =
3365 kzalloc(len+1,
3366 GFP_KERNEL);
3367 strncpy(ses->serverDomain,
3368 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369 bcc_ptr += len;
3370 bcc_ptr[0] = 0;
3371 bcc_ptr++;
3372 } else
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003373 cFYI(1, ("field of length %d "
Steve French63135e02007-07-17 17:34:02 +00003374 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375 len));
3376 }
3377 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003378 cERROR(1, ("Security Blob extends beyond end "
Steve French63135e02007-07-17 17:34:02 +00003379 "of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380 }
3381 } else {
3382 cERROR(1, ("No session structure passed in."));
3383 }
3384 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003385 cERROR(1, ("Invalid Word count %d: ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386 smb_buffer_response->WordCount));
3387 rc = -EIO;
3388 }
3389
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003390 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003391
3392 return rc;
3393}
3394
3395int
3396CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3397 const char *tree, struct cifsTconInfo *tcon,
3398 const struct nls_table *nls_codepage)
3399{
3400 struct smb_hdr *smb_buffer;
3401 struct smb_hdr *smb_buffer_response;
3402 TCONX_REQ *pSMB;
3403 TCONX_RSP *pSMBr;
3404 unsigned char *bcc_ptr;
3405 int rc = 0;
3406 int length;
3407 __u16 count;
3408
3409 if (ses == NULL)
3410 return -EIO;
3411
3412 smb_buffer = cifs_buf_get();
3413 if (smb_buffer == NULL) {
3414 return -ENOMEM;
3415 }
3416 smb_buffer_response = smb_buffer;
3417
3418 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3419 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003420
3421 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422 smb_buffer->Uid = ses->Suid;
3423 pSMB = (TCONX_REQ *) smb_buffer;
3424 pSMBr = (TCONX_RSP *) smb_buffer_response;
3425
3426 pSMB->AndXCommand = 0xFF;
3427 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428 bcc_ptr = &pSMB->Password[0];
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003429 if ((ses->server->secMode) & SECMODE_USER) {
Steve Frencheeac8042006-01-13 21:34:58 -08003430 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00003431 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08003432 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00003433 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08003434 } else {
Steve French7c7b25b2006-06-01 19:20:10 +00003435 pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08003436 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
3437 specified as required (when that support is added to
3438 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00003439 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08003440 by Samba (not sure whether other servers allow
3441 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00003442#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French50c2f752007-07-13 00:33:32 +00003443 if ((extended_security & CIFSSEC_MAY_LANMAN) &&
Steve French7c7b25b2006-06-01 19:20:10 +00003444 (ses->server->secType == LANMAN))
3445 calc_lanman_hash(ses, bcc_ptr);
3446 else
3447#endif /* CIFS_WEAK_PW_HASH */
Steve Frencheeac8042006-01-13 21:34:58 -08003448 SMBNTencrypt(ses->password,
3449 ses->server->cryptKey,
3450 bcc_ptr);
3451
Steve French7c7b25b2006-06-01 19:20:10 +00003452 bcc_ptr += CIFS_SESS_KEY_SIZE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003453 if (ses->capabilities & CAP_UNICODE) {
Steve French7c7b25b2006-06-01 19:20:10 +00003454 /* must align unicode strings */
3455 *bcc_ptr = 0; /* null byte password */
3456 bcc_ptr++;
3457 }
Steve Frencheeac8042006-01-13 21:34:58 -08003458 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459
Steve French50c2f752007-07-13 00:33:32 +00003460 if (ses->server->secMode &
Steve Frencha878fb22006-05-30 18:04:19 +00003461 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3463
3464 if (ses->capabilities & CAP_STATUS32) {
3465 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3466 }
3467 if (ses->capabilities & CAP_DFS) {
3468 smb_buffer->Flags2 |= SMBFLG2_DFS;
3469 }
3470 if (ses->capabilities & CAP_UNICODE) {
3471 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3472 length =
Steve French50c2f752007-07-13 00:33:32 +00003473 cifs_strtoUCS((__le16 *) bcc_ptr, tree,
3474 6 /* max utf8 char length in bytes */ *
Steve Frencha878fb22006-05-30 18:04:19 +00003475 (/* server len*/ + 256 /* share len */), nls_codepage);
3476 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477 bcc_ptr += 2; /* skip trailing null */
3478 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479 strcpy(bcc_ptr, tree);
3480 bcc_ptr += strlen(tree) + 1;
3481 }
3482 strcpy(bcc_ptr, "?????");
3483 bcc_ptr += strlen("?????");
3484 bcc_ptr += 1;
3485 count = bcc_ptr - &pSMB->Password[0];
3486 pSMB->hdr.smb_buf_length += count;
3487 pSMB->ByteCount = cpu_to_le16(count);
3488
Steve French133672e2007-11-13 22:41:37 +00003489 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
3490 CIFS_STD_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491
3492 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3493 /* above now done in SendReceive */
3494 if ((rc == 0) && (tcon != NULL)) {
3495 tcon->tidStatus = CifsGood;
Steve French3b795212008-11-13 19:45:32 +00003496 tcon->need_reconnect = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497 tcon->tid = smb_buffer_response->Tid;
3498 bcc_ptr = pByteArea(smb_buffer_response);
3499 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
Steve French50c2f752007-07-13 00:33:32 +00003500 /* skip service field (NB: this field is always ASCII) */
Steve French7f8ed422007-09-28 22:28:55 +00003501 if (length == 3) {
3502 if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') &&
3503 (bcc_ptr[2] == 'C')) {
3504 cFYI(1, ("IPC connection"));
3505 tcon->ipc = 1;
3506 }
3507 } else if (length == 2) {
3508 if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) {
3509 /* the most common case */
3510 cFYI(1, ("disk share connection"));
3511 }
3512 }
Steve French50c2f752007-07-13 00:33:32 +00003513 bcc_ptr += length + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3515 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3516 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3517 if ((bcc_ptr + (2 * length)) -
3518 pByteArea(smb_buffer_response) <=
3519 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003520 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003522 kzalloc(length + 2, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003523 if (tcon->nativeFileSystem)
3524 cifs_strfromUCS_le(
3525 tcon->nativeFileSystem,
3526 (__le16 *) bcc_ptr,
3527 length, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528 bcc_ptr += 2 * length;
3529 bcc_ptr[0] = 0; /* null terminate the string */
3530 bcc_ptr[1] = 0;
3531 bcc_ptr += 2;
3532 }
Steve French50c2f752007-07-13 00:33:32 +00003533 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003534 } else {
3535 length = strnlen(bcc_ptr, 1024);
3536 if ((bcc_ptr + length) -
3537 pByteArea(smb_buffer_response) <=
3538 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003539 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003540 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003541 kzalloc(length + 1, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003542 if (tcon->nativeFileSystem)
3543 strncpy(tcon->nativeFileSystem, bcc_ptr,
3544 length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003545 }
Steve French50c2f752007-07-13 00:33:32 +00003546 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003547 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003548 if ((smb_buffer_response->WordCount == 3) ||
Steve French1a4e15a2006-10-12 21:33:51 +00003549 (smb_buffer_response->WordCount == 7))
3550 /* field is in same location */
Steve French39798772006-05-31 22:40:51 +00003551 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3552 else
3553 tcon->Flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3555 } else if ((rc == 0) && tcon == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00003556 /* all we need to save for IPC$ connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557 ses->ipc_tid = smb_buffer_response->Tid;
3558 }
3559
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003560 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003561 return rc;
3562}
3563
3564int
3565cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3566{
3567 int rc = 0;
3568 int xid;
3569 struct cifsSesInfo *ses = NULL;
Steve French50c2f752007-07-13 00:33:32 +00003570 char *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003571
3572 xid = GetXid();
3573
3574 if (cifs_sb->tcon) {
3575 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3576 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3577 if (rc == -EBUSY) {
3578 FreeXid(xid);
3579 return 0;
3580 }
Steve French5d941ca2008-04-15 18:40:48 +00003581 DeleteTconOplockQEntries(cifs_sb->tcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582 tconInfoFree(cifs_sb->tcon);
Jeff Layton14fbf502008-11-14 13:53:46 -05003583 cifs_put_smb_ses(ses);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584 }
Steve French50c2f752007-07-13 00:33:32 +00003585
Linus Torvalds1da177e2005-04-16 15:20:36 -07003586 cifs_sb->tcon = NULL;
Steve French2fe87f02006-09-21 07:02:52 +00003587 tmp = cifs_sb->prepath;
3588 cifs_sb->prepathlen = 0;
3589 cifs_sb->prepath = NULL;
3590 kfree(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591
3592 FreeXid(xid);
Steve French88e7d702008-01-03 17:37:09 +00003593 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003594}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003595
3596int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
Steve French50c2f752007-07-13 00:33:32 +00003597 struct nls_table *nls_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598{
3599 int rc = 0;
Steve French7c7b25b2006-06-01 19:20:10 +00003600 char ntlm_session_key[CIFS_SESS_KEY_SIZE];
Steve French4b18f2a2008-04-29 00:06:05 +00003601 bool ntlmv2_flag = false;
Steve Frenchad009ac2005-04-28 22:41:05 -07003602 int first_time = 0;
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003603 struct TCP_Server_Info *server = pSesInfo->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003604
3605 /* what if server changes its buffer size after dropping the session? */
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003606 if (server->maxBuf == 0) /* no need to send on reconnect */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607 rc = CIFSSMBNegotiate(xid, pSesInfo);
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003608 if (rc == -EAGAIN) {
3609 /* retry only once on 1st time connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve French50c2f752007-07-13 00:33:32 +00003611 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612 rc = -EHOSTDOWN;
3613 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003614 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615 spin_lock(&GlobalMid_Lock);
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003616 if (server->tcpStatus != CifsExiting)
3617 server->tcpStatus = CifsGood;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003618 else
3619 rc = -EHOSTDOWN;
3620 spin_unlock(&GlobalMid_Lock);
3621
3622 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003623 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003624 }
Steve French26b994f2008-08-06 05:11:33 +00003625
3626 if (rc)
3627 goto ss_err_exit;
3628
3629 pSesInfo->flags = 0;
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003630 pSesInfo->capabilities = server->capabilities;
Steve French26b994f2008-08-06 05:11:33 +00003631 if (linuxExtEnabled == 0)
3632 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003633 /* pSesInfo->sequence_number = 0;*/
Steve French26b994f2008-08-06 05:11:33 +00003634 cFYI(1, ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003635 server->secMode, server->capabilities, server->timeAdj));
3636
Steve French26b994f2008-08-06 05:11:33 +00003637 if (experimEnabled < 2)
3638 rc = CIFS_SessSetup(xid, pSesInfo, first_time, nls_info);
3639 else if (extended_security
3640 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003641 && (server->secType == NTLMSSP)) {
Steve French26b994f2008-08-06 05:11:33 +00003642 rc = -EOPNOTSUPP;
3643 } else if (extended_security
3644 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003645 && (server->secType == RawNTLMSSP)) {
Steve French26b994f2008-08-06 05:11:33 +00003646 cFYI(1, ("NTLMSSP sesssetup"));
3647 rc = CIFSNTLMSSPNegotiateSessSetup(xid, pSesInfo, &ntlmv2_flag,
3648 nls_info);
3649 if (!rc) {
3650 if (ntlmv2_flag) {
3651 char *v2_response;
3652 cFYI(1, ("more secure NTLM ver2 hash"));
3653 if (CalcNTLMv2_partial_mac_key(pSesInfo,
3654 nls_info)) {
3655 rc = -ENOMEM;
3656 goto ss_err_exit;
3657 } else
3658 v2_response = kmalloc(16 + 64 /* blob*/,
3659 GFP_KERNEL);
3660 if (v2_response) {
3661 CalcNTLMv2_response(pSesInfo,
3662 v2_response);
3663 /* if (first_time)
3664 cifs_calculate_ntlmv2_mac_key */
3665 kfree(v2_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666 /* BB Put dummy sig in SessSetup PDU? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003667 } else {
Steve French26b994f2008-08-06 05:11:33 +00003668 rc = -ENOMEM;
3669 goto ss_err_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670 }
Steve French26b994f2008-08-06 05:11:33 +00003671
3672 } else {
3673 SMBNTencrypt(pSesInfo->password,
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003674 server->cryptKey,
Steve French26b994f2008-08-06 05:11:33 +00003675 ntlm_session_key);
3676
3677 if (first_time)
3678 cifs_calculate_mac_key(
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003679 &server->mac_signing_key,
Steve French26b994f2008-08-06 05:11:33 +00003680 ntlm_session_key,
3681 pSesInfo->password);
3682 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683 /* for better security the weaker lanman hash not sent
3684 in AuthSessSetup so we no longer calculate it */
3685
Steve French26b994f2008-08-06 05:11:33 +00003686 rc = CIFSNTLMSSPAuthSessSetup(xid, pSesInfo,
3687 ntlm_session_key,
3688 ntlmv2_flag,
3689 nls_info);
3690 }
3691 } else { /* old style NTLM 0.12 session setup */
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003692 SMBNTencrypt(pSesInfo->password, server->cryptKey,
Steve French26b994f2008-08-06 05:11:33 +00003693 ntlm_session_key);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003694
Steve French26b994f2008-08-06 05:11:33 +00003695 if (first_time)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003696 cifs_calculate_mac_key(&server->mac_signing_key,
3697 ntlm_session_key,
3698 pSesInfo->password);
Steve Frenchad009ac2005-04-28 22:41:05 -07003699
Steve French26b994f2008-08-06 05:11:33 +00003700 rc = CIFSSessSetup(xid, pSesInfo, ntlm_session_key, nls_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003701 }
Steve French26b994f2008-08-06 05:11:33 +00003702 if (rc) {
3703 cERROR(1, ("Send error in SessSetup = %d", rc));
3704 } else {
3705 cFYI(1, ("CIFS Session Established successfully"));
Jeff Layton469ee612008-10-16 18:46:39 +00003706 spin_lock(&GlobalMid_Lock);
Steve French26b994f2008-08-06 05:11:33 +00003707 pSesInfo->status = CifsGood;
Steve French3b795212008-11-13 19:45:32 +00003708 pSesInfo->need_reconnect = false;
Jeff Layton469ee612008-10-16 18:46:39 +00003709 spin_unlock(&GlobalMid_Lock);
Steve French26b994f2008-08-06 05:11:33 +00003710 }
3711
Linus Torvalds1da177e2005-04-16 15:20:36 -07003712ss_err_exit:
3713 return rc;
3714}
3715