blob: 44130e052e0bdaf73836d5b6e8b8d8cacf788305 [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);
Cyrill Gorcunov1b20d672008-05-09 18:17:21 +00001371
Jeff Laytone7ddee92008-11-14 13:44:38 -05001372 /*
1373 * the demux thread can exit on its own while still in CifsNew
1374 * so don't accept any sockets in that state. Since the
1375 * tcpStatus never changes back to CifsNew it's safe to check
1376 * for this without a lock.
1377 */
1378 if (server->tcpStatus == CifsNew)
Cyrill Gorcunov1b20d672008-05-09 18:17:21 +00001379 continue;
Steve French50c2f752007-07-13 00:33:32 +00001380
Jeff Laytone7ddee92008-11-14 13:44:38 -05001381 if (addr->sa_family == AF_INET &&
1382 (addr4->sin_addr.s_addr !=
1383 server->addr.sockAddr.sin_addr.s_addr))
1384 continue;
1385 else if (addr->sa_family == AF_INET6 &&
1386 memcmp(&server->addr.sockAddr6.sin6_addr,
1387 &addr6->sin6_addr, sizeof(addr6->sin6_addr)))
1388 continue;
Steve French50c2f752007-07-13 00:33:32 +00001389
Jeff Laytone7ddee92008-11-14 13:44:38 -05001390 ++server->srv_count;
1391 write_unlock(&cifs_tcp_ses_lock);
1392 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);
2079 if (srvTcp) {
2080 cFYI(1, ("Existing tcp session with server found"));
2081 } else { /* create socket */
Steve French3ec332e2008-11-14 03:35:10 +00002082 if (addr.sa_family == AF_INET6) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002083 cFYI(1, ("attempting ipv6 connect"));
Steve French5858ae42007-04-25 11:59:10 +00002084 /* BB should we allow ipv6 on port 139? */
2085 /* other OS never observed in Wild doing 139 with v6 */
Steve French3ec332e2008-11-14 03:35:10 +00002086 sin_server6->sin6_port = htons(volume_info.port);
2087 rc = ipv6_connect(sin_server6, &csocket,
Steve Frenchedf1ae42008-10-29 00:47:57 +00002088 volume_info.noblocksnd);
Steve French3ec332e2008-11-14 03:35:10 +00002089 } else {
2090 sin_server->sin_port = htons(volume_info.port);
2091 rc = ipv4_connect(sin_server, &csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -07002092 volume_info.source_rfc1001_name,
Steve Frenchedf1ae42008-10-29 00:47:57 +00002093 volume_info.target_rfc1001_name,
2094 volume_info.noblocksnd,
2095 volume_info.noautotune);
Steve French3ec332e2008-11-14 03:35:10 +00002096 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097 if (rc < 0) {
Steve French3ec332e2008-11-14 03:35:10 +00002098 cERROR(1, ("Error connecting to socket. "
Steve French50c2f752007-07-13 00:33:32 +00002099 "Aborting operation"));
Steve French4523cc32007-04-30 20:13:06 +00002100 if (csocket != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 sock_release(csocket);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002102 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103 }
2104
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00002105 srvTcp = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
2106 if (!srvTcp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 rc = -ENOMEM;
2108 sock_release(csocket);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002109 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 } else {
Steve Frenchedf1ae42008-10-29 00:47:57 +00002111 srvTcp->noblocksnd = volume_info.noblocksnd;
2112 srvTcp->noautotune = volume_info.noautotune;
Steve French3ec332e2008-11-14 03:35:10 +00002113 if (addr.sa_family == AF_INET6)
2114 memcpy(&srvTcp->addr.sockAddr6, sin_server6,
2115 sizeof(struct sockaddr_in6));
2116 else
2117 memcpy(&srvTcp->addr.sockAddr, sin_server,
2118 sizeof(struct sockaddr_in));
Steve French50c2f752007-07-13 00:33:32 +00002119 atomic_set(&srvTcp->inFlight, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 /* BB Add code for ipv6 case too */
2121 srvTcp->ssocket = csocket;
Jeff Laytonc359cf32007-11-16 22:22:06 +00002122 srvTcp->hostname = extract_hostname(volume_info.UNC);
2123 if (IS_ERR(srvTcp->hostname)) {
2124 rc = PTR_ERR(srvTcp->hostname);
2125 sock_release(csocket);
2126 goto out;
2127 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128 init_waitqueue_head(&srvTcp->response_q);
2129 init_waitqueue_head(&srvTcp->request_q);
2130 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
2131 /* at this point we are the only ones with the pointer
2132 to the struct since the kernel thread not created yet
2133 so no need to spinlock this init of tcpStatus */
2134 srvTcp->tcpStatus = CifsNew;
2135 init_MUTEX(&srvTcp->tcpSem);
Igor Mammedovaaf737a2007-04-03 19:16:43 +00002136 srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd");
Steve French8840dee2007-11-16 23:05:52 +00002137 if (IS_ERR(srvTcp->tsk)) {
Igor Mammedovaaf737a2007-04-03 19:16:43 +00002138 rc = PTR_ERR(srvTcp->tsk);
Steve French50c2f752007-07-13 00:33:32 +00002139 cERROR(1, ("error %d create cifsd thread", rc));
Igor Mammedovaaf737a2007-04-03 19:16:43 +00002140 srvTcp->tsk = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141 sock_release(csocket);
Jeff Laytonc359cf32007-11-16 22:22:06 +00002142 kfree(srvTcp->hostname);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002143 goto out;
Steve Frenchf1914012005-08-18 09:37:34 -07002144 }
Steve Frenchf1914012005-08-18 09:37:34 -07002145 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002146 memcpy(srvTcp->workstation_RFC1001_name,
2147 volume_info.source_rfc1001_name, 16);
2148 memcpy(srvTcp->server_RFC1001_name,
2149 volume_info.target_rfc1001_name, 16);
Steve Frenchad009ac2005-04-28 22:41:05 -07002150 srvTcp->sequence_number = 0;
Jeff Laytone7ddee92008-11-14 13:44:38 -05002151 INIT_LIST_HEAD(&srvTcp->tcp_ses_list);
Jeff Layton14fbf502008-11-14 13:53:46 -05002152 INIT_LIST_HEAD(&srvTcp->smb_ses_list);
Jeff Laytone7ddee92008-11-14 13:44:38 -05002153 ++srvTcp->srv_count;
2154 write_lock(&cifs_tcp_ses_lock);
2155 list_add(&srvTcp->tcp_ses_list,
2156 &cifs_tcp_ses_list);
2157 write_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 }
2159 }
2160
Jeff Layton14fbf502008-11-14 13:53:46 -05002161 pSesInfo = cifs_find_smb_ses(srvTcp, volume_info.username);
2162 if (pSesInfo) {
Jeff Layton1d9a8852007-12-31 01:37:11 +00002163 cFYI(1, ("Existing smb sess found (status=%d)",
2164 pSesInfo->status));
Jeff Layton14fbf502008-11-14 13:53:46 -05002165 /*
2166 * The existing SMB session already has a reference to srvTcp,
2167 * so we can put back the extra one we got before
2168 */
2169 cifs_put_tcp_session(srvTcp);
2170
Steve French88e7d702008-01-03 17:37:09 +00002171 down(&pSesInfo->sesSem);
Steve French3b795212008-11-13 19:45:32 +00002172 if (pSesInfo->need_reconnect) {
Jeff Layton1d9a8852007-12-31 01:37:11 +00002173 cFYI(1, ("Session needs reconnect"));
Jeff Layton1d9a8852007-12-31 01:37:11 +00002174 rc = cifs_setup_session(xid, pSesInfo,
2175 cifs_sb->local_nls);
Jeff Layton1d9a8852007-12-31 01:37:11 +00002176 }
Steve French88e7d702008-01-03 17:37:09 +00002177 up(&pSesInfo->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178 } else if (!rc) {
Steve Frenchbf820672005-12-01 22:32:42 -08002179 cFYI(1, ("Existing smb sess not found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180 pSesInfo = sesInfoAlloc();
Jeff Layton14fbf502008-11-14 13:53:46 -05002181 if (pSesInfo == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 rc = -ENOMEM;
Jeff Layton14fbf502008-11-14 13:53:46 -05002183 goto mount_fail_check;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 }
2185
Jeff Layton14fbf502008-11-14 13:53:46 -05002186 /* new SMB session uses our srvTcp ref */
2187 pSesInfo->server = srvTcp;
2188 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
2189 NIPQUAD(sin_server->sin_addr.s_addr));
2190
2191 write_lock(&cifs_tcp_ses_lock);
2192 list_add(&pSesInfo->smb_ses_list, &srvTcp->smb_ses_list);
2193 write_unlock(&cifs_tcp_ses_lock);
2194
2195 /* volume_info.password freed at unmount */
2196 if (volume_info.password) {
2197 pSesInfo->password = volume_info.password;
2198 /* set to NULL to prevent freeing on exit */
2199 volume_info.password = NULL;
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002200 }
Jeff Layton14fbf502008-11-14 13:53:46 -05002201 if (volume_info.username)
2202 strncpy(pSesInfo->userName, volume_info.username,
2203 MAX_USERNAME_SIZE);
2204 if (volume_info.domainname) {
2205 int len = strlen(volume_info.domainname);
2206 pSesInfo->domainName = kmalloc(len + 1, GFP_KERNEL);
2207 if (pSesInfo->domainName)
2208 strcpy(pSesInfo->domainName,
2209 volume_info.domainname);
2210 }
2211 pSesInfo->linux_uid = volume_info.linux_uid;
2212 pSesInfo->overrideSecFlg = volume_info.secFlg;
2213 down(&pSesInfo->sesSem);
2214
2215 /* BB FIXME need to pass vol->secFlgs BB */
2216 rc = cifs_setup_session(xid, pSesInfo,
2217 cifs_sb->local_nls);
2218 up(&pSesInfo->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 }
Steve French50c2f752007-07-13 00:33:32 +00002220
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 /* search for existing tcon to this server share */
2222 if (!rc) {
Steve French3b795212008-11-13 19:45:32 +00002223 setup_cifs_sb(&volume_info, cifs_sb);
Steve French27adb442008-05-23 19:43:29 +00002224
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225 if (tcon) {
Steve Frenchbf820672005-12-01 22:32:42 -08002226 cFYI(1, ("Found match on UNC path"));
Steve French95b1cb92008-05-15 16:44:38 +00002227 if (tcon->seal != volume_info.seal)
2228 cERROR(1, ("transport encryption setting "
2229 "conflicts with existing tid"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230 } else {
2231 tcon = tconInfoAlloc();
Steve French3b795212008-11-13 19:45:32 +00002232 if (tcon == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233 rc = -ENOMEM;
Steve French3b795212008-11-13 19:45:32 +00002234 goto mount_fail_check;
2235 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236
Steve French3b795212008-11-13 19:45:32 +00002237 /* check for null share name ie connect to dfs root */
2238
2239 /* BB check if works for exactly length 3 strings */
2240 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
2241 && (strchr(volume_info.UNC + 3, '/') == NULL)) {
2242 /* rc = connect_to_dfs_path(...) */
2243 cFYI(1, ("DFS root not supported"));
2244 rc = -ENODEV;
2245 goto mount_fail_check;
2246 } else {
2247 /* BB Do we need to wrap sesSem around
2248 * this TCon call and Unix SetFS as
2249 * we do on SessSetup and reconnect? */
2250 rc = CIFSTCon(xid, pSesInfo, volume_info.UNC,
2251 tcon, cifs_sb->local_nls);
2252 cFYI(1, ("CIFS Tcon rc = %d", rc));
2253 if (volume_info.nodfs) {
2254 tcon->Flags &= ~SMB_SHARE_IS_IN_DFS;
2255 cFYI(1, ("DFS disabled (%d)",
2256 tcon->Flags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 }
2258 }
Jeff Layton14fbf502008-11-14 13:53:46 -05002259 if (rc)
Steve French3b795212008-11-13 19:45:32 +00002260 goto mount_fail_check;
Jeff Layton14fbf502008-11-14 13:53:46 -05002261 tcon->seal = volume_info.seal;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 }
Steve French3b795212008-11-13 19:45:32 +00002263
2264 /* we can have only one retry value for a connection
2265 to a share so for resources mounted more than once
2266 to the same server share the last value passed in
2267 for the retry flag is used */
2268 tcon->retry = volume_info.retry;
2269 tcon->nocase = volume_info.nocase;
2270 tcon->local_lease = volume_info.local_lease;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 }
Steve French4523cc32007-04-30 20:13:06 +00002272 if (pSesInfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
2274 sb->s_maxbytes = (u64) 1 << 63;
2275 } else
2276 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
2277 }
2278
Steve French8af18972007-02-14 04:42:51 +00002279 /* BB FIXME fix time_gran to be larger for LANMAN sessions */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280 sb->s_time_gran = 100;
2281
Steve French3b795212008-11-13 19:45:32 +00002282mount_fail_check:
Jeff Layton14fbf502008-11-14 13:53:46 -05002283 /* on error free sesinfo and tcon struct if needed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284 if (rc) {
Jeff Laytone7ddee92008-11-14 13:44:38 -05002285 /* If find_unc succeeded then rc == 0 so we can not end */
2286 /* up accidently freeing someone elses tcon struct */
2287 if (tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 tconInfoFree(tcon);
Jeff Laytone7ddee92008-11-14 13:44:38 -05002289
Jeff Layton14fbf502008-11-14 13:53:46 -05002290 /* should also end up putting our tcp session ref if needed */
2291 if (pSesInfo)
2292 cifs_put_smb_ses(pSesInfo);
2293 else
2294 cifs_put_tcp_session(srvTcp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295 } else {
2296 atomic_inc(&tcon->useCount);
2297 cifs_sb->tcon = tcon;
2298 tcon->ses = pSesInfo;
2299
Steve French82940a42006-03-02 03:24:57 +00002300 /* do not care if following two calls succeed - informational */
Steve French7f8ed422007-09-28 22:28:55 +00002301 if (!tcon->ipc) {
2302 CIFSSMBQFSDeviceInfo(xid, tcon);
2303 CIFSSMBQFSAttributeInfo(xid, tcon);
2304 }
Steve French50c2f752007-07-13 00:33:32 +00002305
Steve French8af18972007-02-14 04:42:51 +00002306 /* tell server which Unix caps we support */
2307 if (tcon->ses->capabilities & CAP_UNIX)
Steve Frenchc18c8422007-07-18 23:21:09 +00002308 /* reset of caps checks mount to see if unix extensions
2309 disabled for just this mount */
Steve French8af18972007-02-14 04:42:51 +00002310 reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
Steve Frenchc18c8422007-07-18 23:21:09 +00002311 else
2312 tcon->unix_ext = 0; /* server does not support them */
2313
Steve French03a143c2008-02-14 06:38:30 +00002314 /* convert forward to back slashes in prepath here if needed */
Igor Mammedov11b6d642008-02-15 19:06:04 +00002315 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
2316 convert_delimiter(cifs_sb->prepath,
2317 CIFS_DIR_SEP(cifs_sb));
Steve French03a143c2008-02-14 06:38:30 +00002318
Steve Frenchc18c8422007-07-18 23:21:09 +00002319 if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
Steve French75865f8c2007-06-24 18:30:48 +00002320 cifs_sb->rsize = 1024 * 127;
Steve French90c81e02008-02-12 20:32:36 +00002321 cFYI(DBG2,
2322 ("no very large read support, rsize now 127K"));
Steve French75865f8c2007-06-24 18:30:48 +00002323 }
Steve French3e844692005-10-03 13:37:24 -07002324 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
2325 cifs_sb->wsize = min(cifs_sb->wsize,
2326 (tcon->ses->server->maxBuf -
2327 MAX_CIFS_HDR_SIZE));
Steve French0ae0efa2005-10-10 10:57:19 -07002328 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
Steve French50c2f752007-07-13 00:33:32 +00002329 cifs_sb->rsize = min(cifs_sb->rsize,
2330 (tcon->ses->server->maxBuf -
2331 MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332 }
2333
2334 /* volume_info.password is freed above when existing session found
2335 (in which case it is not needed anymore) but when new sesion is created
2336 the password ptr is put in the new session structure (in which case the
2337 password will be freed at unmount time) */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002338out:
2339 /* zero out password before freeing */
2340 if (volume_info.password != NULL) {
2341 memset(volume_info.password, 0, strlen(volume_info.password));
2342 kfree(volume_info.password);
2343 }
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002344 kfree(volume_info.UNC);
Steve French2fe87f02006-09-21 07:02:52 +00002345 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346 FreeXid(xid);
2347 return rc;
2348}
2349
2350static int
2351CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French7c7b25b2006-06-01 19:20:10 +00002352 char session_key[CIFS_SESS_KEY_SIZE],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 const struct nls_table *nls_codepage)
2354{
2355 struct smb_hdr *smb_buffer;
2356 struct smb_hdr *smb_buffer_response;
2357 SESSION_SETUP_ANDX *pSMB;
2358 SESSION_SETUP_ANDX *pSMBr;
2359 char *bcc_ptr;
2360 char *user;
2361 char *domain;
2362 int rc = 0;
2363 int remaining_words = 0;
2364 int bytes_returned = 0;
2365 int len;
2366 __u32 capabilities;
2367 __u16 count;
2368
Steve Frencheeac8042006-01-13 21:34:58 -08002369 cFYI(1, ("In sesssetup"));
Steve French4523cc32007-04-30 20:13:06 +00002370 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371 return -EINVAL;
2372 user = ses->userName;
2373 domain = ses->domainName;
2374 smb_buffer = cifs_buf_get();
Steve French582d21e2008-05-13 04:54:12 +00002375
2376 if (smb_buffer == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377 return -ENOMEM;
Steve French582d21e2008-05-13 04:54:12 +00002378
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379 smb_buffer_response = smb_buffer;
2380 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2381
2382 /* send SMBsessionSetup here */
2383 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2384 NULL /* no tCon exists yet */ , 13 /* wct */ );
2385
Steve French1982c342005-08-17 12:38:22 -07002386 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387 pSMB->req_no_secext.AndXCommand = 0xFF;
2388 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2389 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2390
Steve French50c2f752007-07-13 00:33:32 +00002391 if (ses->server->secMode &
2392 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2394
2395 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2396 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
2397 if (ses->capabilities & CAP_UNICODE) {
2398 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2399 capabilities |= CAP_UNICODE;
2400 }
2401 if (ses->capabilities & CAP_STATUS32) {
2402 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2403 capabilities |= CAP_STATUS32;
2404 }
2405 if (ses->capabilities & CAP_DFS) {
2406 smb_buffer->Flags2 |= SMBFLG2_DFS;
2407 capabilities |= CAP_DFS;
2408 }
2409 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
2410
Steve French50c2f752007-07-13 00:33:32 +00002411 pSMB->req_no_secext.CaseInsensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002412 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413
2414 pSMB->req_no_secext.CaseSensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002415 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416 bcc_ptr = pByteArea(smb_buffer);
Steve French7c7b25b2006-06-01 19:20:10 +00002417 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2418 bcc_ptr += CIFS_SESS_KEY_SIZE;
2419 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2420 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421
2422 if (ses->capabilities & CAP_UNICODE) {
2423 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
2424 *bcc_ptr = 0;
2425 bcc_ptr++;
2426 }
Steve French4523cc32007-04-30 20:13:06 +00002427 if (user == NULL)
Steve French39798772006-05-31 22:40:51 +00002428 bytes_returned = 0; /* skip null user */
Steve French50c2f752007-07-13 00:33:32 +00002429 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430 bytes_returned =
Steve French50c2f752007-07-13 00:33:32 +00002431 cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432 nls_codepage);
2433 /* convert number of 16 bit words to bytes */
2434 bcc_ptr += 2 * bytes_returned;
2435 bcc_ptr += 2; /* trailing null */
2436 if (domain == NULL)
2437 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002438 cifs_strtoUCS((__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439 "CIFS_LINUX_DOM", 32, nls_codepage);
2440 else
2441 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002442 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 nls_codepage);
2444 bcc_ptr += 2 * bytes_returned;
2445 bcc_ptr += 2;
2446 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002447 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448 32, nls_codepage);
2449 bcc_ptr += 2 * bytes_returned;
2450 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002451 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452 32, nls_codepage);
2453 bcc_ptr += 2 * bytes_returned;
2454 bcc_ptr += 2;
2455 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002456 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457 64, nls_codepage);
2458 bcc_ptr += 2 * bytes_returned;
2459 bcc_ptr += 2;
2460 } else {
Steve French50c2f752007-07-13 00:33:32 +00002461 if (user != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 strncpy(bcc_ptr, user, 200);
2463 bcc_ptr += strnlen(user, 200);
2464 }
2465 *bcc_ptr = 0;
2466 bcc_ptr++;
2467 if (domain == NULL) {
2468 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2469 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2470 } else {
2471 strncpy(bcc_ptr, domain, 64);
2472 bcc_ptr += strnlen(domain, 64);
2473 *bcc_ptr = 0;
2474 bcc_ptr++;
2475 }
2476 strcpy(bcc_ptr, "Linux version ");
2477 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002478 strcpy(bcc_ptr, utsname()->release);
2479 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2481 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2482 }
2483 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2484 smb_buffer->smb_buf_length += count;
2485 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2486
2487 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00002488 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489 if (rc) {
2490/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2491 } else if ((smb_buffer_response->WordCount == 3)
2492 || (smb_buffer_response->WordCount == 4)) {
2493 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2494 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2495 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002496 cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */
2497 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format
2498 (little endian) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499 cFYI(1, ("UID = %d ", ses->Suid));
Steve French50c2f752007-07-13 00:33:32 +00002500 /* response can have either 3 or 4 word count - Samba sends 3 */
2501 bcc_ptr = pByteArea(smb_buffer_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502 if ((pSMBr->resp.hdr.WordCount == 3)
2503 || ((pSMBr->resp.hdr.WordCount == 4)
2504 && (blob_len < pSMBr->resp.ByteCount))) {
2505 if (pSMBr->resp.hdr.WordCount == 4)
2506 bcc_ptr += blob_len;
2507
2508 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2509 if ((long) (bcc_ptr) % 2) {
2510 remaining_words =
Steve French50c2f752007-07-13 00:33:32 +00002511 (BCC(smb_buffer_response) - 1) / 2;
2512 /* Unicode strings must be word
2513 aligned */
2514 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 } else {
2516 remaining_words =
2517 BCC(smb_buffer_response) / 2;
2518 }
2519 len =
2520 UniStrnlen((wchar_t *) bcc_ptr,
2521 remaining_words - 1);
2522/* We look for obvious messed up bcc or strings in response so we do not go off
2523 the end since (at least) WIN2K and Windows XP have a major bug in not null
2524 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002525 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002526 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002527 ses->serverOS = kzalloc(2 * (len + 1),
2528 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002529 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002530 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531 cifs_strfromUCS_le(ses->serverOS,
Steve French50c2f752007-07-13 00:33:32 +00002532 (__le16 *)bcc_ptr,
2533 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534 bcc_ptr += 2 * (len + 1);
2535 remaining_words -= len + 1;
2536 ses->serverOS[2 * len] = 0;
2537 ses->serverOS[1 + (2 * len)] = 0;
2538 if (remaining_words > 0) {
2539 len = UniStrnlen((wchar_t *)bcc_ptr,
2540 remaining_words-1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002541 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002542 ses->serverNOS = kzalloc(2 * (len + 1),
2543 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002544 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002545 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546 cifs_strfromUCS_le(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002547 (__le16 *)bcc_ptr,
2548 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549 bcc_ptr += 2 * (len + 1);
2550 ses->serverNOS[2 * len] = 0;
2551 ses->serverNOS[1 + (2 * len)] = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002552 if (strncmp(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002553 "NT LAN Manager 4", 16) == 0) {
Steve French467a8f82007-06-27 22:41:32 +00002554 cFYI(1, ("NT4 server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555 ses->flags |= CIFS_SES_NT4;
2556 }
2557 remaining_words -= len + 1;
2558 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002559 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Steve French50c2f752007-07-13 00:33:32 +00002560 /* last string is not always null terminated
2561 (for e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002562 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002563 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564 ses->serverDomain =
Steve French50c2f752007-07-13 00:33:32 +00002565 kzalloc(2*(len+1),
2566 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002567 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002568 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569 cifs_strfromUCS_le(ses->serverDomain,
Steve French50c2f752007-07-13 00:33:32 +00002570 (__le16 *)bcc_ptr,
2571 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572 bcc_ptr += 2 * (len + 1);
2573 ses->serverDomain[2*len] = 0;
2574 ses->serverDomain[1+(2*len)] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002575 } else { /* else no more room so create
2576 dummy domain string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002577 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002578 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002579 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002580 kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002581 }
Steve French50c2f752007-07-13 00:33:32 +00002582 } else { /* no room so create dummy domain
2583 and NOS string */
2584
Steve French433dc242005-04-28 22:41:08 -07002585 /* if these kcallocs fail not much we
2586 can do, but better to not fail the
2587 sesssetup itself */
Steve Frenchcd49b492006-06-26 04:22:36 +00002588 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002590 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002591 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002593 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594 }
2595 } else { /* ASCII */
2596 len = strnlen(bcc_ptr, 1024);
2597 if (((long) bcc_ptr + len) - (long)
2598 pByteArea(smb_buffer_response)
2599 <= BCC(smb_buffer_response)) {
Steve Frenchcd49b492006-06-26 04:22:36 +00002600 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002601 ses->serverOS = kzalloc(len + 1,
2602 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002603 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002604 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002605 strncpy(ses->serverOS, bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606
2607 bcc_ptr += len;
Steve French50c2f752007-07-13 00:33:32 +00002608 /* null terminate the string */
2609 bcc_ptr[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610 bcc_ptr++;
2611
2612 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002613 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002614 ses->serverNOS = kzalloc(len + 1,
2615 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002616 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002617 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618 strncpy(ses->serverNOS, bcc_ptr, len);
2619 bcc_ptr += len;
2620 bcc_ptr[0] = 0;
2621 bcc_ptr++;
2622
2623 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002624 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002625 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002626 ses->serverDomain = kzalloc(len + 1,
2627 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002628 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002629 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002630 strncpy(ses->serverDomain, bcc_ptr,
2631 len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632 bcc_ptr += len;
2633 bcc_ptr[0] = 0;
2634 bcc_ptr++;
2635 } else
2636 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00002637 ("Variable field of length %d "
2638 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 len));
2640 }
2641 } else {
2642 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00002643 (" Security Blob Length extends beyond "
2644 "end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 }
2646 } else {
2647 cERROR(1,
2648 (" Invalid Word count %d: ",
2649 smb_buffer_response->WordCount));
2650 rc = -EIO;
2651 }
Steve French433dc242005-04-28 22:41:08 -07002652sesssetup_nomem: /* do not return an error on nomem for the info strings,
2653 since that could make reconnection harder, and
2654 reconnection might be needed to free memory */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00002655 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656
2657 return rc;
2658}
2659
2660static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
Steve French4b18f2a2008-04-29 00:06:05 +00002662 struct cifsSesInfo *ses, bool *pNTLMv2_flag,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 const struct nls_table *nls_codepage)
2664{
2665 struct smb_hdr *smb_buffer;
2666 struct smb_hdr *smb_buffer_response;
2667 SESSION_SETUP_ANDX *pSMB;
2668 SESSION_SETUP_ANDX *pSMBr;
2669 char *bcc_ptr;
2670 char *domain;
2671 int rc = 0;
2672 int remaining_words = 0;
2673 int bytes_returned = 0;
2674 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002675 int SecurityBlobLength = sizeof(NEGOTIATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676 PNEGOTIATE_MESSAGE SecurityBlob;
2677 PCHALLENGE_MESSAGE SecurityBlob2;
2678 __u32 negotiate_flags, capabilities;
2679 __u16 count;
2680
Steve French12b3b8f2006-02-09 21:12:47 +00002681 cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002682 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 return -EINVAL;
2684 domain = ses->domainName;
Steve French4b18f2a2008-04-29 00:06:05 +00002685 *pNTLMv2_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686 smb_buffer = cifs_buf_get();
2687 if (smb_buffer == NULL) {
2688 return -ENOMEM;
2689 }
2690 smb_buffer_response = smb_buffer;
2691 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2692 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2693
2694 /* send SMBsessionSetup here */
2695 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2696 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002697
2698 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2700 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2701
2702 pSMB->req.AndXCommand = 0xFF;
2703 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2704 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2705
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002706 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2708
2709 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2710 CAP_EXTENDED_SECURITY;
2711 if (ses->capabilities & CAP_UNICODE) {
2712 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2713 capabilities |= CAP_UNICODE;
2714 }
2715 if (ses->capabilities & CAP_STATUS32) {
2716 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2717 capabilities |= CAP_STATUS32;
2718 }
2719 if (ses->capabilities & CAP_DFS) {
2720 smb_buffer->Flags2 |= SMBFLG2_DFS;
2721 capabilities |= CAP_DFS;
2722 }
2723 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2724
2725 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2726 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2727 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2728 SecurityBlob->MessageType = NtLmNegotiate;
2729 negotiate_flags =
2730 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
Steve French12b3b8f2006-02-09 21:12:47 +00002731 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
2732 NTLMSSP_NEGOTIATE_56 |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002734 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002736/* if (ntlmv2_support)
Steve French39798772006-05-31 22:40:51 +00002737 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 /* setup pointers to domain name and workstation name */
2739 bcc_ptr += SecurityBlobLength;
2740
2741 SecurityBlob->WorkstationName.Buffer = 0;
2742 SecurityBlob->WorkstationName.Length = 0;
2743 SecurityBlob->WorkstationName.MaximumLength = 0;
2744
Steve French12b3b8f2006-02-09 21:12:47 +00002745 /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent
2746 along with username on auth request (ie the response to challenge) */
2747 SecurityBlob->DomainName.Buffer = 0;
2748 SecurityBlob->DomainName.Length = 0;
2749 SecurityBlob->DomainName.MaximumLength = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750 if (ses->capabilities & CAP_UNICODE) {
2751 if ((long) bcc_ptr % 2) {
2752 *bcc_ptr = 0;
2753 bcc_ptr++;
2754 }
2755
2756 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002757 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 32, nls_codepage);
2759 bcc_ptr += 2 * bytes_returned;
2760 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002761 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762 nls_codepage);
2763 bcc_ptr += 2 * bytes_returned;
2764 bcc_ptr += 2; /* null terminate Linux version */
2765 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002766 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767 64, nls_codepage);
2768 bcc_ptr += 2 * bytes_returned;
2769 *(bcc_ptr + 1) = 0;
2770 *(bcc_ptr + 2) = 0;
2771 bcc_ptr += 2; /* null terminate network opsys string */
2772 *(bcc_ptr + 1) = 0;
2773 *(bcc_ptr + 2) = 0;
2774 bcc_ptr += 2; /* null domain */
2775 } else { /* ASCII */
2776 strcpy(bcc_ptr, "Linux version ");
2777 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002778 strcpy(bcc_ptr, utsname()->release);
2779 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2781 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2782 bcc_ptr++; /* empty domain field */
2783 *bcc_ptr = 0;
2784 }
2785 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2786 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2787 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2788 smb_buffer->smb_buf_length += count;
2789 pSMB->req.ByteCount = cpu_to_le16(count);
2790
2791 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00002792 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793
2794 if (smb_buffer_response->Status.CifsError ==
2795 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2796 rc = 0;
2797
2798 if (rc) {
2799/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2800 } else if ((smb_buffer_response->WordCount == 3)
2801 || (smb_buffer_response->WordCount == 4)) {
2802 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2803 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2804
2805 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002806 cFYI(1, (" Guest login"));
2807 /* Do we want to set anything in SesInfo struct when guest login? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808
Steve French50c2f752007-07-13 00:33:32 +00002809 bcc_ptr = pByteArea(smb_buffer_response);
2810 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811
2812 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2813 if (SecurityBlob2->MessageType != NtLmChallenge) {
2814 cFYI(1,
2815 ("Unexpected NTLMSSP message type received %d",
2816 SecurityBlob2->MessageType));
2817 } else if (ses) {
Steve French50c2f752007-07-13 00:33:32 +00002818 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
Steve French12b3b8f2006-02-09 21:12:47 +00002819 cFYI(1, ("UID = %d", ses->Suid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820 if ((pSMBr->resp.hdr.WordCount == 3)
2821 || ((pSMBr->resp.hdr.WordCount == 4)
2822 && (blob_len <
2823 pSMBr->resp.ByteCount))) {
2824
2825 if (pSMBr->resp.hdr.WordCount == 4) {
2826 bcc_ptr += blob_len;
Steve French12b3b8f2006-02-09 21:12:47 +00002827 cFYI(1, ("Security Blob Length %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 blob_len));
2829 }
2830
Steve French12b3b8f2006-02-09 21:12:47 +00002831 cFYI(1, ("NTLMSSP Challenge rcvd"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832
2833 memcpy(ses->server->cryptKey,
2834 SecurityBlob2->Challenge,
2835 CIFS_CRYPTO_KEY_SIZE);
Steve French50c2f752007-07-13 00:33:32 +00002836 if (SecurityBlob2->NegotiateFlags &
Steve French12b3b8f2006-02-09 21:12:47 +00002837 cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
Steve French4b18f2a2008-04-29 00:06:05 +00002838 *pNTLMv2_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839
Steve French50c2f752007-07-13 00:33:32 +00002840 if ((SecurityBlob2->NegotiateFlags &
2841 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842 || (sign_CIFS_PDUs > 1))
Steve French50c2f752007-07-13 00:33:32 +00002843 ses->server->secMode |=
2844 SECMODE_SIGN_REQUIRED;
2845 if ((SecurityBlob2->NegotiateFlags &
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
Steve French50c2f752007-07-13 00:33:32 +00002847 ses->server->secMode |=
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848 SECMODE_SIGN_ENABLED;
2849
2850 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2851 if ((long) (bcc_ptr) % 2) {
2852 remaining_words =
2853 (BCC(smb_buffer_response)
2854 - 1) / 2;
Steve French50c2f752007-07-13 00:33:32 +00002855 /* Must word align unicode strings */
2856 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857 } else {
2858 remaining_words =
2859 BCC
2860 (smb_buffer_response) / 2;
2861 }
2862 len =
2863 UniStrnlen((wchar_t *) bcc_ptr,
2864 remaining_words - 1);
2865/* We look for obvious messed up bcc or strings in response so we do not go off
2866 the end since (at least) WIN2K and Windows XP have a major bug in not null
2867 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002868 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002869 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002871 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002873 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874 bcc_ptr, len,
2875 nls_codepage);
2876 bcc_ptr += 2 * (len + 1);
2877 remaining_words -= len + 1;
2878 ses->serverOS[2 * len] = 0;
2879 ses->serverOS[1 + (2 * len)] = 0;
2880 if (remaining_words > 0) {
2881 len = UniStrnlen((wchar_t *)
2882 bcc_ptr,
2883 remaining_words
2884 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002885 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002887 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888 GFP_KERNEL);
2889 cifs_strfromUCS_le(ses->
2890 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002891 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892 bcc_ptr,
2893 len,
2894 nls_codepage);
2895 bcc_ptr += 2 * (len + 1);
2896 ses->serverNOS[2 * len] = 0;
2897 ses->serverNOS[1 +
2898 (2 * len)] = 0;
2899 remaining_words -= len + 1;
2900 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00002901 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2902 /* last string not always null terminated
2903 (for e.g. for Windows XP & 2000) */
Steve Frenchcd49b492006-06-26 04:22:36 +00002904 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002906 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907 (len +
2908 1),
2909 GFP_KERNEL);
2910 cifs_strfromUCS_le
Steve Frenche89dc922005-11-11 15:18:19 -08002911 (ses->serverDomain,
2912 (__le16 *)bcc_ptr,
2913 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914 bcc_ptr +=
2915 2 * (len + 1);
Steve Frenche89dc922005-11-11 15:18:19 -08002916 ses->serverDomain[2*len]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917 = 0;
Steve Frenche89dc922005-11-11 15:18:19 -08002918 ses->serverDomain
2919 [1 + (2 * len)]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920 = 0;
2921 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002922 else {
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,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926 GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002927 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928 } else { /* no room so create dummy domain and NOS string */
Steve Frenchcd49b492006-06-26 04:22:36 +00002929 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002931 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002932 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002934 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935 }
2936 } else { /* ASCII */
2937 len = strnlen(bcc_ptr, 1024);
2938 if (((long) bcc_ptr + len) - (long)
2939 pByteArea(smb_buffer_response)
2940 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002941 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002942 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002944 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945 GFP_KERNEL);
2946 strncpy(ses->serverOS,
2947 bcc_ptr, len);
2948
2949 bcc_ptr += len;
2950 bcc_ptr[0] = 0; /* null terminate string */
2951 bcc_ptr++;
2952
2953 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002954 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002956 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 GFP_KERNEL);
2958 strncpy(ses->serverNOS, bcc_ptr, len);
2959 bcc_ptr += len;
2960 bcc_ptr[0] = 0;
2961 bcc_ptr++;
2962
2963 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002964 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002966 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +00002968 strncpy(ses->serverDomain,
2969 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 bcc_ptr += len;
2971 bcc_ptr[0] = 0;
2972 bcc_ptr++;
2973 } else
2974 cFYI(1,
Steve French63135e02007-07-17 17:34:02 +00002975 ("field of length %d "
2976 "extends beyond end of smb",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 len));
2978 }
2979 } else {
Steve French50c2f752007-07-13 00:33:32 +00002980 cERROR(1, ("Security Blob Length extends beyond"
2981 " end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982 }
2983 } else {
2984 cERROR(1, ("No session structure passed in."));
2985 }
2986 } else {
2987 cERROR(1,
Steve French5815449d2006-02-14 01:36:20 +00002988 (" Invalid Word count %d:",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989 smb_buffer_response->WordCount));
2990 rc = -EIO;
2991 }
2992
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00002993 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994
2995 return rc;
2996}
2997static int
2998CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French4b18f2a2008-04-29 00:06:05 +00002999 char *ntlm_session_key, bool ntlmv2_flag,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003000 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001{
3002 struct smb_hdr *smb_buffer;
3003 struct smb_hdr *smb_buffer_response;
3004 SESSION_SETUP_ANDX *pSMB;
3005 SESSION_SETUP_ANDX *pSMBr;
3006 char *bcc_ptr;
3007 char *user;
3008 char *domain;
3009 int rc = 0;
3010 int remaining_words = 0;
3011 int bytes_returned = 0;
3012 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003013 int SecurityBlobLength = sizeof(AUTHENTICATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014 PAUTHENTICATE_MESSAGE SecurityBlob;
3015 __u32 negotiate_flags, capabilities;
3016 __u16 count;
3017
3018 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003019 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020 return -EINVAL;
3021 user = ses->userName;
3022 domain = ses->domainName;
3023 smb_buffer = cifs_buf_get();
3024 if (smb_buffer == NULL) {
3025 return -ENOMEM;
3026 }
3027 smb_buffer_response = smb_buffer;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003028 pSMB = (SESSION_SETUP_ANDX *)smb_buffer;
3029 pSMBr = (SESSION_SETUP_ANDX *)smb_buffer_response;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030
3031 /* send SMBsessionSetup here */
3032 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
3033 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07003034
3035 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003036 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
3037 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
3038 pSMB->req.AndXCommand = 0xFF;
3039 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
3040 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
3041
3042 pSMB->req.hdr.Uid = ses->Suid;
3043
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003044 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3046
3047 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003048 CAP_EXTENDED_SECURITY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003049 if (ses->capabilities & CAP_UNICODE) {
3050 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3051 capabilities |= CAP_UNICODE;
3052 }
3053 if (ses->capabilities & CAP_STATUS32) {
3054 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3055 capabilities |= CAP_STATUS32;
3056 }
3057 if (ses->capabilities & CAP_DFS) {
3058 smb_buffer->Flags2 |= SMBFLG2_DFS;
3059 capabilities |= CAP_DFS;
3060 }
3061 pSMB->req.Capabilities = cpu_to_le32(capabilities);
3062
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003063 bcc_ptr = (char *)&pSMB->req.SecurityBlob;
3064 SecurityBlob = (PAUTHENTICATE_MESSAGE)bcc_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
3066 SecurityBlob->MessageType = NtLmAuthenticate;
3067 bcc_ptr += SecurityBlobLength;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003068 negotiate_flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
3069 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
3070 0x80000000 | NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003071 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003073 if (ntlmv2_flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003074 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
3075
3076/* setup pointers to domain name and workstation name */
3077
3078 SecurityBlob->WorkstationName.Buffer = 0;
3079 SecurityBlob->WorkstationName.Length = 0;
3080 SecurityBlob->WorkstationName.MaximumLength = 0;
3081 SecurityBlob->SessionKey.Length = 0;
3082 SecurityBlob->SessionKey.MaximumLength = 0;
3083 SecurityBlob->SessionKey.Buffer = 0;
3084
3085 SecurityBlob->LmChallengeResponse.Length = 0;
3086 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
3087 SecurityBlob->LmChallengeResponse.Buffer = 0;
3088
3089 SecurityBlob->NtChallengeResponse.Length =
Steve French7c7b25b2006-06-01 19:20:10 +00003090 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091 SecurityBlob->NtChallengeResponse.MaximumLength =
Steve French7c7b25b2006-06-01 19:20:10 +00003092 cpu_to_le16(CIFS_SESS_KEY_SIZE);
3093 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094 SecurityBlob->NtChallengeResponse.Buffer =
3095 cpu_to_le32(SecurityBlobLength);
Steve French7c7b25b2006-06-01 19:20:10 +00003096 SecurityBlobLength += CIFS_SESS_KEY_SIZE;
3097 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098
3099 if (ses->capabilities & CAP_UNICODE) {
3100 if (domain == NULL) {
3101 SecurityBlob->DomainName.Buffer = 0;
3102 SecurityBlob->DomainName.Length = 0;
3103 SecurityBlob->DomainName.MaximumLength = 0;
3104 } else {
Steve French77159b42007-08-31 01:10:17 +00003105 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003106 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00003107 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003108 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003109 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110 SecurityBlob->DomainName.Buffer =
3111 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003112 bcc_ptr += ln;
3113 SecurityBlobLength += ln;
3114 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115 }
3116 if (user == NULL) {
3117 SecurityBlob->UserName.Buffer = 0;
3118 SecurityBlob->UserName.Length = 0;
3119 SecurityBlob->UserName.MaximumLength = 0;
3120 } else {
Steve French77159b42007-08-31 01:10:17 +00003121 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00003123 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124 SecurityBlob->UserName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003125 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126 SecurityBlob->UserName.Buffer =
3127 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003128 bcc_ptr += ln;
3129 SecurityBlobLength += ln;
3130 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131 }
3132
Steve French63135e02007-07-17 17:34:02 +00003133 /* SecurityBlob->WorkstationName.Length =
3134 cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135 SecurityBlob->WorkstationName.Length *= 2;
Steve French63135e02007-07-17 17:34:02 +00003136 SecurityBlob->WorkstationName.MaximumLength =
3137 cpu_to_le16(SecurityBlob->WorkstationName.Length);
3138 SecurityBlob->WorkstationName.Buffer =
3139 cpu_to_le32(SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140 bcc_ptr += SecurityBlob->WorkstationName.Length;
3141 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
Steve French63135e02007-07-17 17:34:02 +00003142 SecurityBlob->WorkstationName.Length =
3143 cpu_to_le16(SecurityBlob->WorkstationName.Length); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144
3145 if ((long) bcc_ptr % 2) {
3146 *bcc_ptr = 0;
3147 bcc_ptr++;
3148 }
3149 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003150 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151 32, nls_codepage);
3152 bcc_ptr += 2 * bytes_returned;
3153 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003154 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003155 nls_codepage);
3156 bcc_ptr += 2 * bytes_returned;
3157 bcc_ptr += 2; /* null term version string */
3158 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003159 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160 64, nls_codepage);
3161 bcc_ptr += 2 * bytes_returned;
3162 *(bcc_ptr + 1) = 0;
3163 *(bcc_ptr + 2) = 0;
3164 bcc_ptr += 2; /* null terminate network opsys string */
3165 *(bcc_ptr + 1) = 0;
3166 *(bcc_ptr + 2) = 0;
3167 bcc_ptr += 2; /* null domain */
3168 } else { /* ASCII */
3169 if (domain == NULL) {
3170 SecurityBlob->DomainName.Buffer = 0;
3171 SecurityBlob->DomainName.Length = 0;
3172 SecurityBlob->DomainName.MaximumLength = 0;
3173 } else {
Steve French77159b42007-08-31 01:10:17 +00003174 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003175 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
3176 strncpy(bcc_ptr, domain, 63);
Steve French77159b42007-08-31 01:10:17 +00003177 ln = strnlen(domain, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003178 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003179 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180 SecurityBlob->DomainName.Buffer =
3181 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003182 bcc_ptr += ln;
3183 SecurityBlobLength += ln;
3184 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185 }
3186 if (user == NULL) {
3187 SecurityBlob->UserName.Buffer = 0;
3188 SecurityBlob->UserName.Length = 0;
3189 SecurityBlob->UserName.MaximumLength = 0;
3190 } else {
Steve French77159b42007-08-31 01:10:17 +00003191 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192 strncpy(bcc_ptr, user, 63);
Steve French77159b42007-08-31 01:10:17 +00003193 ln = strnlen(user, 64);
3194 SecurityBlob->UserName.MaximumLength = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195 SecurityBlob->UserName.Buffer =
Steve French77159b42007-08-31 01:10:17 +00003196 cpu_to_le32(SecurityBlobLength);
3197 bcc_ptr += ln;
3198 SecurityBlobLength += ln;
3199 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200 }
3201 /* BB fill in our workstation name if known BB */
3202
3203 strcpy(bcc_ptr, "Linux version ");
3204 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003205 strcpy(bcc_ptr, utsname()->release);
3206 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
3208 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
3209 bcc_ptr++; /* null domain */
3210 *bcc_ptr = 0;
3211 }
3212 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
3213 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
3214 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
3215 smb_buffer->smb_buf_length += count;
3216 pSMB->req.ByteCount = cpu_to_le16(count);
3217
3218 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00003219 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220 if (rc) {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003221/* rc = map_smb_to_linux_error(smb_buffer_response) done in SendReceive now */
3222 } else if ((smb_buffer_response->WordCount == 3) ||
3223 (smb_buffer_response->WordCount == 4)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224 __u16 action = le16_to_cpu(pSMBr->resp.Action);
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003225 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00003227 cFYI(1, (" Guest login")); /* BB Should we set anything
3228 in SesInfo struct ? */
3229/* if (SecurityBlob2->MessageType != NtLm??) {
3230 cFYI("Unexpected message type on auth response is %d"));
3231 } */
3232
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233 if (ses) {
3234 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003235 ("Check challenge UID %d vs auth response UID %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236 ses->Suid, smb_buffer_response->Uid));
Steve French50c2f752007-07-13 00:33:32 +00003237 /* UID left in wire format */
3238 ses->Suid = smb_buffer_response->Uid;
3239 bcc_ptr = pByteArea(smb_buffer_response);
3240 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241 if ((pSMBr->resp.hdr.WordCount == 3)
3242 || ((pSMBr->resp.hdr.WordCount == 4)
3243 && (blob_len <
3244 pSMBr->resp.ByteCount))) {
3245 if (pSMBr->resp.hdr.WordCount == 4) {
3246 bcc_ptr +=
3247 blob_len;
3248 cFYI(1,
3249 ("Security Blob Length %d ",
3250 blob_len));
3251 }
3252
3253 cFYI(1,
3254 ("NTLMSSP response to Authenticate "));
3255
3256 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3257 if ((long) (bcc_ptr) % 2) {
3258 remaining_words =
3259 (BCC(smb_buffer_response)
3260 - 1) / 2;
3261 bcc_ptr++; /* Unicode strings must be word aligned */
3262 } else {
3263 remaining_words = BCC(smb_buffer_response) / 2;
3264 }
Steve French77159b42007-08-31 01:10:17 +00003265 len = UniStrnlen((wchar_t *) bcc_ptr,
3266 remaining_words - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003267/* We look for obvious messed up bcc or strings in response so we do not go off
3268 the end since (at least) WIN2K and Windows XP have a major bug in not null
3269 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003270 if (ses->serverOS)
Steve French08775832006-05-30 18:08:26 +00003271 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003272 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003273 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003274 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003275 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276 bcc_ptr, len,
3277 nls_codepage);
3278 bcc_ptr += 2 * (len + 1);
3279 remaining_words -= len + 1;
3280 ses->serverOS[2 * len] = 0;
3281 ses->serverOS[1 + (2 * len)] = 0;
3282 if (remaining_words > 0) {
3283 len = UniStrnlen((wchar_t *)
3284 bcc_ptr,
3285 remaining_words
3286 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00003287 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003289 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290 GFP_KERNEL);
3291 cifs_strfromUCS_le(ses->
3292 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003293 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294 bcc_ptr,
3295 len,
3296 nls_codepage);
3297 bcc_ptr += 2 * (len + 1);
3298 ses->serverNOS[2 * len] = 0;
3299 ses->serverNOS[1+(2*len)] = 0;
3300 remaining_words -= len + 1;
3301 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00003302 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003303 /* last string not always null terminated (e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003304 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003305 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003306 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003307 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308 (len +
3309 1),
3310 GFP_KERNEL);
3311 cifs_strfromUCS_le
3312 (ses->
3313 serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08003314 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315 bcc_ptr, len,
3316 nls_codepage);
3317 bcc_ptr +=
3318 2 * (len + 1);
3319 ses->
3320 serverDomain[2
3321 * len]
3322 = 0;
3323 ses->
3324 serverDomain[1
3325 +
3326 (2
3327 *
3328 len)]
3329 = 0;
3330 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003331 else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003332 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003333 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003334 ses->serverDomain = kzalloc(2,GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00003335 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336 } else { /* no room so create dummy domain and NOS string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003337 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003338 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003339 ses->serverDomain = kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00003340 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003341 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003342 }
3343 } else { /* ASCII */
3344 len = strnlen(bcc_ptr, 1024);
Steve French50c2f752007-07-13 00:33:32 +00003345 if (((long) bcc_ptr + len) -
3346 (long) pByteArea(smb_buffer_response)
Steve French63135e02007-07-17 17:34:02 +00003347 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003348 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00003349 kfree(ses->serverOS);
Steve French77159b42007-08-31 01:10:17 +00003350 ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351 strncpy(ses->serverOS,bcc_ptr, len);
3352
3353 bcc_ptr += len;
3354 bcc_ptr[0] = 0; /* null terminate the string */
3355 bcc_ptr++;
3356
3357 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003358 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00003359 ses->serverNOS = kzalloc(len+1,
3360 GFP_KERNEL);
Steve French63135e02007-07-17 17:34:02 +00003361 strncpy(ses->serverNOS,
3362 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003363 bcc_ptr += len;
3364 bcc_ptr[0] = 0;
3365 bcc_ptr++;
3366
3367 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003368 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003369 kfree(ses->serverDomain);
Steve French63135e02007-07-17 17:34:02 +00003370 ses->serverDomain =
3371 kzalloc(len+1,
3372 GFP_KERNEL);
3373 strncpy(ses->serverDomain,
3374 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375 bcc_ptr += len;
3376 bcc_ptr[0] = 0;
3377 bcc_ptr++;
3378 } else
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003379 cFYI(1, ("field of length %d "
Steve French63135e02007-07-17 17:34:02 +00003380 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381 len));
3382 }
3383 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003384 cERROR(1, ("Security Blob extends beyond end "
Steve French63135e02007-07-17 17:34:02 +00003385 "of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386 }
3387 } else {
3388 cERROR(1, ("No session structure passed in."));
3389 }
3390 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003391 cERROR(1, ("Invalid Word count %d: ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392 smb_buffer_response->WordCount));
3393 rc = -EIO;
3394 }
3395
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003396 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397
3398 return rc;
3399}
3400
3401int
3402CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3403 const char *tree, struct cifsTconInfo *tcon,
3404 const struct nls_table *nls_codepage)
3405{
3406 struct smb_hdr *smb_buffer;
3407 struct smb_hdr *smb_buffer_response;
3408 TCONX_REQ *pSMB;
3409 TCONX_RSP *pSMBr;
3410 unsigned char *bcc_ptr;
3411 int rc = 0;
3412 int length;
3413 __u16 count;
3414
3415 if (ses == NULL)
3416 return -EIO;
3417
3418 smb_buffer = cifs_buf_get();
3419 if (smb_buffer == NULL) {
3420 return -ENOMEM;
3421 }
3422 smb_buffer_response = smb_buffer;
3423
3424 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3425 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003426
3427 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428 smb_buffer->Uid = ses->Suid;
3429 pSMB = (TCONX_REQ *) smb_buffer;
3430 pSMBr = (TCONX_RSP *) smb_buffer_response;
3431
3432 pSMB->AndXCommand = 0xFF;
3433 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434 bcc_ptr = &pSMB->Password[0];
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003435 if ((ses->server->secMode) & SECMODE_USER) {
Steve Frencheeac8042006-01-13 21:34:58 -08003436 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00003437 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08003438 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00003439 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08003440 } else {
Steve French7c7b25b2006-06-01 19:20:10 +00003441 pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08003442 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
3443 specified as required (when that support is added to
3444 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00003445 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08003446 by Samba (not sure whether other servers allow
3447 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00003448#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French50c2f752007-07-13 00:33:32 +00003449 if ((extended_security & CIFSSEC_MAY_LANMAN) &&
Steve French7c7b25b2006-06-01 19:20:10 +00003450 (ses->server->secType == LANMAN))
3451 calc_lanman_hash(ses, bcc_ptr);
3452 else
3453#endif /* CIFS_WEAK_PW_HASH */
Steve Frencheeac8042006-01-13 21:34:58 -08003454 SMBNTencrypt(ses->password,
3455 ses->server->cryptKey,
3456 bcc_ptr);
3457
Steve French7c7b25b2006-06-01 19:20:10 +00003458 bcc_ptr += CIFS_SESS_KEY_SIZE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003459 if (ses->capabilities & CAP_UNICODE) {
Steve French7c7b25b2006-06-01 19:20:10 +00003460 /* must align unicode strings */
3461 *bcc_ptr = 0; /* null byte password */
3462 bcc_ptr++;
3463 }
Steve Frencheeac8042006-01-13 21:34:58 -08003464 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003465
Steve French50c2f752007-07-13 00:33:32 +00003466 if (ses->server->secMode &
Steve Frencha878fb22006-05-30 18:04:19 +00003467 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3469
3470 if (ses->capabilities & CAP_STATUS32) {
3471 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3472 }
3473 if (ses->capabilities & CAP_DFS) {
3474 smb_buffer->Flags2 |= SMBFLG2_DFS;
3475 }
3476 if (ses->capabilities & CAP_UNICODE) {
3477 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3478 length =
Steve French50c2f752007-07-13 00:33:32 +00003479 cifs_strtoUCS((__le16 *) bcc_ptr, tree,
3480 6 /* max utf8 char length in bytes */ *
Steve Frencha878fb22006-05-30 18:04:19 +00003481 (/* server len*/ + 256 /* share len */), nls_codepage);
3482 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483 bcc_ptr += 2; /* skip trailing null */
3484 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003485 strcpy(bcc_ptr, tree);
3486 bcc_ptr += strlen(tree) + 1;
3487 }
3488 strcpy(bcc_ptr, "?????");
3489 bcc_ptr += strlen("?????");
3490 bcc_ptr += 1;
3491 count = bcc_ptr - &pSMB->Password[0];
3492 pSMB->hdr.smb_buf_length += count;
3493 pSMB->ByteCount = cpu_to_le16(count);
3494
Steve French133672e2007-11-13 22:41:37 +00003495 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
3496 CIFS_STD_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497
3498 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3499 /* above now done in SendReceive */
3500 if ((rc == 0) && (tcon != NULL)) {
3501 tcon->tidStatus = CifsGood;
Steve French3b795212008-11-13 19:45:32 +00003502 tcon->need_reconnect = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503 tcon->tid = smb_buffer_response->Tid;
3504 bcc_ptr = pByteArea(smb_buffer_response);
3505 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
Steve French50c2f752007-07-13 00:33:32 +00003506 /* skip service field (NB: this field is always ASCII) */
Steve French7f8ed422007-09-28 22:28:55 +00003507 if (length == 3) {
3508 if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') &&
3509 (bcc_ptr[2] == 'C')) {
3510 cFYI(1, ("IPC connection"));
3511 tcon->ipc = 1;
3512 }
3513 } else if (length == 2) {
3514 if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) {
3515 /* the most common case */
3516 cFYI(1, ("disk share connection"));
3517 }
3518 }
Steve French50c2f752007-07-13 00:33:32 +00003519 bcc_ptr += length + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3521 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3522 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3523 if ((bcc_ptr + (2 * length)) -
3524 pByteArea(smb_buffer_response) <=
3525 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003526 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003528 kzalloc(length + 2, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003529 if (tcon->nativeFileSystem)
3530 cifs_strfromUCS_le(
3531 tcon->nativeFileSystem,
3532 (__le16 *) bcc_ptr,
3533 length, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003534 bcc_ptr += 2 * length;
3535 bcc_ptr[0] = 0; /* null terminate the string */
3536 bcc_ptr[1] = 0;
3537 bcc_ptr += 2;
3538 }
Steve French50c2f752007-07-13 00:33:32 +00003539 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003540 } else {
3541 length = strnlen(bcc_ptr, 1024);
3542 if ((bcc_ptr + length) -
3543 pByteArea(smb_buffer_response) <=
3544 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003545 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003547 kzalloc(length + 1, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003548 if (tcon->nativeFileSystem)
3549 strncpy(tcon->nativeFileSystem, bcc_ptr,
3550 length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003551 }
Steve French50c2f752007-07-13 00:33:32 +00003552 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003553 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003554 if ((smb_buffer_response->WordCount == 3) ||
Steve French1a4e15a2006-10-12 21:33:51 +00003555 (smb_buffer_response->WordCount == 7))
3556 /* field is in same location */
Steve French39798772006-05-31 22:40:51 +00003557 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3558 else
3559 tcon->Flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3561 } else if ((rc == 0) && tcon == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00003562 /* all we need to save for IPC$ connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563 ses->ipc_tid = smb_buffer_response->Tid;
3564 }
3565
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003566 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003567 return rc;
3568}
3569
3570int
3571cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3572{
3573 int rc = 0;
3574 int xid;
3575 struct cifsSesInfo *ses = NULL;
Steve French50c2f752007-07-13 00:33:32 +00003576 char *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577
3578 xid = GetXid();
3579
3580 if (cifs_sb->tcon) {
3581 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3582 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3583 if (rc == -EBUSY) {
3584 FreeXid(xid);
3585 return 0;
3586 }
Steve French5d941ca2008-04-15 18:40:48 +00003587 DeleteTconOplockQEntries(cifs_sb->tcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588 tconInfoFree(cifs_sb->tcon);
Jeff Layton14fbf502008-11-14 13:53:46 -05003589 cifs_put_smb_ses(ses);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590 }
Steve French50c2f752007-07-13 00:33:32 +00003591
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592 cifs_sb->tcon = NULL;
Steve French2fe87f02006-09-21 07:02:52 +00003593 tmp = cifs_sb->prepath;
3594 cifs_sb->prepathlen = 0;
3595 cifs_sb->prepath = NULL;
3596 kfree(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597
3598 FreeXid(xid);
Steve French88e7d702008-01-03 17:37:09 +00003599 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003600}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003601
3602int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
Steve French50c2f752007-07-13 00:33:32 +00003603 struct nls_table *nls_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003604{
3605 int rc = 0;
Steve French7c7b25b2006-06-01 19:20:10 +00003606 char ntlm_session_key[CIFS_SESS_KEY_SIZE];
Steve French4b18f2a2008-04-29 00:06:05 +00003607 bool ntlmv2_flag = false;
Steve Frenchad009ac2005-04-28 22:41:05 -07003608 int first_time = 0;
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003609 struct TCP_Server_Info *server = pSesInfo->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610
3611 /* what if server changes its buffer size after dropping the session? */
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003612 if (server->maxBuf == 0) /* no need to send on reconnect */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613 rc = CIFSSMBNegotiate(xid, pSesInfo);
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003614 if (rc == -EAGAIN) {
3615 /* retry only once on 1st time connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve French50c2f752007-07-13 00:33:32 +00003617 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003618 rc = -EHOSTDOWN;
3619 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003620 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621 spin_lock(&GlobalMid_Lock);
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003622 if (server->tcpStatus != CifsExiting)
3623 server->tcpStatus = CifsGood;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003624 else
3625 rc = -EHOSTDOWN;
3626 spin_unlock(&GlobalMid_Lock);
3627
3628 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003629 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630 }
Steve French26b994f2008-08-06 05:11:33 +00003631
3632 if (rc)
3633 goto ss_err_exit;
3634
3635 pSesInfo->flags = 0;
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003636 pSesInfo->capabilities = server->capabilities;
Steve French26b994f2008-08-06 05:11:33 +00003637 if (linuxExtEnabled == 0)
3638 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003639 /* pSesInfo->sequence_number = 0;*/
Steve French26b994f2008-08-06 05:11:33 +00003640 cFYI(1, ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003641 server->secMode, server->capabilities, server->timeAdj));
3642
Steve French26b994f2008-08-06 05:11:33 +00003643 if (experimEnabled < 2)
3644 rc = CIFS_SessSetup(xid, pSesInfo, first_time, nls_info);
3645 else if (extended_security
3646 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003647 && (server->secType == NTLMSSP)) {
Steve French26b994f2008-08-06 05:11:33 +00003648 rc = -EOPNOTSUPP;
3649 } else if (extended_security
3650 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003651 && (server->secType == RawNTLMSSP)) {
Steve French26b994f2008-08-06 05:11:33 +00003652 cFYI(1, ("NTLMSSP sesssetup"));
3653 rc = CIFSNTLMSSPNegotiateSessSetup(xid, pSesInfo, &ntlmv2_flag,
3654 nls_info);
3655 if (!rc) {
3656 if (ntlmv2_flag) {
3657 char *v2_response;
3658 cFYI(1, ("more secure NTLM ver2 hash"));
3659 if (CalcNTLMv2_partial_mac_key(pSesInfo,
3660 nls_info)) {
3661 rc = -ENOMEM;
3662 goto ss_err_exit;
3663 } else
3664 v2_response = kmalloc(16 + 64 /* blob*/,
3665 GFP_KERNEL);
3666 if (v2_response) {
3667 CalcNTLMv2_response(pSesInfo,
3668 v2_response);
3669 /* if (first_time)
3670 cifs_calculate_ntlmv2_mac_key */
3671 kfree(v2_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003672 /* BB Put dummy sig in SessSetup PDU? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003673 } else {
Steve French26b994f2008-08-06 05:11:33 +00003674 rc = -ENOMEM;
3675 goto ss_err_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676 }
Steve French26b994f2008-08-06 05:11:33 +00003677
3678 } else {
3679 SMBNTencrypt(pSesInfo->password,
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003680 server->cryptKey,
Steve French26b994f2008-08-06 05:11:33 +00003681 ntlm_session_key);
3682
3683 if (first_time)
3684 cifs_calculate_mac_key(
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003685 &server->mac_signing_key,
Steve French26b994f2008-08-06 05:11:33 +00003686 ntlm_session_key,
3687 pSesInfo->password);
3688 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003689 /* for better security the weaker lanman hash not sent
3690 in AuthSessSetup so we no longer calculate it */
3691
Steve French26b994f2008-08-06 05:11:33 +00003692 rc = CIFSNTLMSSPAuthSessSetup(xid, pSesInfo,
3693 ntlm_session_key,
3694 ntlmv2_flag,
3695 nls_info);
3696 }
3697 } else { /* old style NTLM 0.12 session setup */
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003698 SMBNTencrypt(pSesInfo->password, server->cryptKey,
Steve French26b994f2008-08-06 05:11:33 +00003699 ntlm_session_key);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700
Steve French26b994f2008-08-06 05:11:33 +00003701 if (first_time)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003702 cifs_calculate_mac_key(&server->mac_signing_key,
3703 ntlm_session_key,
3704 pSesInfo->password);
Steve Frenchad009ac2005-04-28 22:41:05 -07003705
Steve French26b994f2008-08-06 05:11:33 +00003706 rc = CIFSSessSetup(xid, pSesInfo, ntlm_session_key, nls_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707 }
Steve French26b994f2008-08-06 05:11:33 +00003708 if (rc) {
3709 cERROR(1, ("Send error in SessSetup = %d", rc));
3710 } else {
3711 cFYI(1, ("CIFS Session Established successfully"));
Jeff Layton469ee612008-10-16 18:46:39 +00003712 spin_lock(&GlobalMid_Lock);
Steve French26b994f2008-08-06 05:11:33 +00003713 pSesInfo->status = CifsGood;
Steve French3b795212008-11-13 19:45:32 +00003714 pSesInfo->need_reconnect = false;
Jeff Layton469ee612008-10-16 18:46:39 +00003715 spin_unlock(&GlobalMid_Lock);
Steve French26b994f2008-08-06 05:11:33 +00003716 }
3717
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718ss_err_exit:
3719 return rc;
3720}
3721