blob: 8af993f8d0ccfc2689c3f81c20bfe7d4c59d4168 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/connect.c
3 *
Steve French75865f8c2007-06-24 18:30:48 +00004 * Copyright (C) International Business Machines Corp., 2002,2007
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
Steve Frenchf1914012005-08-18 09:37:34 -070052static DECLARE_COMPLETION(cifsd_complete);
53
Linus Torvalds1da177e2005-04-16 15:20:36 -070054extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
55 unsigned char *p24);
56
57extern mempool_t *cifs_req_poolp;
58
59struct smb_vol {
60 char *username;
61 char *password;
62 char *domainname;
63 char *UNC;
64 char *UNCip;
65 char *in6_addr; /* ipv6 address as human readable form of in6_addr */
66 char *iocharset; /* local code page for mapping to and from Unicode */
67 char source_rfc1001_name[16]; /* netbios name of client */
Steve Frencha10faeb22005-08-22 21:38:31 -070068 char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 uid_t linux_uid;
70 gid_t linux_gid;
71 mode_t file_mode;
72 mode_t dir_mode;
Steve French189acaa2006-06-23 02:33:48 +000073 unsigned secFlg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 unsigned rw:1;
75 unsigned retry:1;
76 unsigned intr:1;
77 unsigned setuids:1;
Steve French4523cc32007-04-30 20:13:06 +000078 unsigned override_uid:1;
79 unsigned override_gid:1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 unsigned noperm:1;
81 unsigned no_psx_acl:1; /* set if posix acl support should be disabled */
Steve French0a4b92c2006-01-12 15:44:21 -080082 unsigned cifs_acl:1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 unsigned no_xattr:1; /* set if xattr (EA) support should be disabled*/
84 unsigned server_ino:1; /* use inode numbers from server ie UniqueId */
85 unsigned direct_io:1;
Steve French6a0b4822005-04-28 22:41:05 -070086 unsigned remap:1; /* set to remap seven reserved chars in filenames */
Jeremy Allisonac670552005-06-22 17:26:35 -070087 unsigned posix_paths:1; /* unset to not ask for posix pathnames. */
Steve Frenchc18c8422007-07-18 23:21:09 +000088 unsigned no_linux_ext:1;
Steve Frenchd7245c22005-07-14 18:25:12 -050089 unsigned sfu_emul:1;
Steve Frenchbf820672005-12-01 22:32:42 -080090 unsigned nullauth:1; /* attempt to authenticate with null user */
Steve Frenchc46fa8a2005-08-18 20:49:57 -070091 unsigned nocase; /* request case insensitive filenames */
92 unsigned nobrl; /* disable sending byte range locks to srv */
Linus Torvalds1da177e2005-04-16 15:20:36 -070093 unsigned int rsize;
94 unsigned int wsize;
95 unsigned int sockopt;
96 unsigned short int port;
Steve Frenchfb8c4b12007-07-10 01:16:18 +000097 char *prepath;
Linus Torvalds1da177e2005-04-16 15:20:36 -070098};
99
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000100static int ipv4_connect(struct sockaddr_in *psin_server,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 struct socket **csocket,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000102 char *netb_name,
103 char *server_netb_name);
104static int ipv6_connect(struct sockaddr_in6 *psin_server,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 struct socket **csocket);
106
107
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000108 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 * cifs tcp session reconnection
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000110 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 * mark tcp session as reconnecting so temporarily locked
112 * mark all smb sessions as reconnecting for tcp session
113 * reconnect tcp session
114 * wake up waiters on reconnection? - (not needed currently)
115 */
116
Steve French2cd646a2006-09-28 19:43:08 +0000117static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118cifs_reconnect(struct TCP_Server_Info *server)
119{
120 int rc = 0;
121 struct list_head *tmp;
122 struct cifsSesInfo *ses;
123 struct cifsTconInfo *tcon;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000124 struct mid_q_entry *mid_entry;
Steve French50c2f752007-07-13 00:33:32 +0000125
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126 spin_lock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000127 if ( kthread_should_stop() ) {
128 /* the demux thread will exit normally
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 next time through the loop */
130 spin_unlock(&GlobalMid_Lock);
131 return rc;
132 } else
133 server->tcpStatus = CifsNeedReconnect;
134 spin_unlock(&GlobalMid_Lock);
135 server->maxBuf = 0;
136
Steve Frenche4eb2952005-04-28 22:41:09 -0700137 cFYI(1, ("Reconnecting tcp session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138
139 /* before reconnecting the tcp session, mark the smb session (uid)
140 and the tid bad so they are not used until reconnected */
141 read_lock(&GlobalSMBSeslock);
142 list_for_each(tmp, &GlobalSMBSessionList) {
143 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
144 if (ses->server) {
145 if (ses->server == server) {
146 ses->status = CifsNeedReconnect;
147 ses->ipc_tid = 0;
148 }
149 }
150 /* else tcp and smb sessions need reconnection */
151 }
152 list_for_each(tmp, &GlobalTreeConnectionList) {
153 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000154 if ((tcon) && (tcon->ses) && (tcon->ses->server == server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 tcon->tidStatus = CifsNeedReconnect;
156 }
157 }
158 read_unlock(&GlobalSMBSeslock);
159 /* 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));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000164 server->ssocket->ops->shutdown(server->ssocket, SEND_SHUTDOWN);
165 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 Frenchfb8c4b12007-07-10 01:16:18 +0000177 if (mid_entry) {
178 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French09d1db52005-04-28 22:41:08 -0700179 /* Mark other intransit requests as needing
180 retry so we do not immediately mark the
181 session bad again (ie after we reconnect
182 below) as they timeout too */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 mid_entry->midState = MID_RETRY_NEEDED;
184 }
185 }
186 }
187 spin_unlock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000188 up(&server->tcpSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000190 while ( (!kthread_should_stop()) && (server->tcpStatus != CifsGood)) {
Steve French6c3d8902006-07-31 22:46:20 +0000191 try_to_freeze();
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000192 if (server->protocolType == IPV6) {
193 rc = ipv6_connect(&server->addr.sockAddr6,
194 &server->ssocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000196 rc = ipv4_connect(&server->addr.sockAddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 &server->ssocket,
Steve Frencha10faeb22005-08-22 21:38:31 -0700198 server->workstation_RFC1001_name,
199 server->server_RFC1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000201 if (rc) {
202 cFYI(1, ("reconnect error %d", rc));
Steve French0cb766a2005-04-28 22:41:11 -0700203 msleep(3000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 } else {
205 atomic_inc(&tcpSesReconnectCount);
206 spin_lock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000207 if ( !kthread_should_stop() )
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 Frenchb8643e12005-04-28 22:41:07 -0700349 int isLargeBuf = FALSE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700350 int isMultiRsp;
351 int reconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 current->flags |= PF_MEMALLOC;
354 server->tsk = current; /* save process info to wake at shutdown */
355 cFYI(1, ("Demultiplex PID: %d", current->pid));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000356 write_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 atomic_inc(&tcpSesAllocCount);
358 length = tcpSesAllocCount.counter;
359 write_unlock(&GlobalSMBSeslock);
Steve Frenchf1914012005-08-18 09:37:34 -0700360 complete(&cifsd_complete);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000361 if (length > 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 mempool_resize(cifs_req_poolp,
363 length + cifs_min_rcv,
364 GFP_KERNEL);
365 }
366
Rafael J. Wysocki83144182007-07-17 04:03:35 -0700367 set_freezable();
Igor Mammedovaaf737a2007-04-03 19:16:43 +0000368 while (!kthread_should_stop()) {
Steve Frenchede13272005-08-30 20:10:14 -0700369 if (try_to_freeze())
370 continue;
Steve Frenchb8643e12005-04-28 22:41:07 -0700371 if (bigbuf == NULL) {
372 bigbuf = cifs_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000373 if (!bigbuf) {
374 cERROR(1, ("No memory for large SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700375 msleep(3000);
376 /* retry will check if exiting */
377 continue;
378 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000379 } else if (isLargeBuf) {
380 /* we are reusing a dirty large buf, clear its start */
Steve Frenchb8643e12005-04-28 22:41:07 -0700381 memset(bigbuf, 0, sizeof (struct smb_hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700383
384 if (smallbuf == NULL) {
385 smallbuf = cifs_small_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000386 if (!smallbuf) {
387 cERROR(1, ("No memory for SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700388 msleep(1000);
389 /* retry will check if exiting */
390 continue;
391 }
392 /* beginning of smb buffer is cleared in our buf_get */
393 } else /* if existing small buf clear beginning */
394 memset(smallbuf, 0, sizeof (struct smb_hdr));
395
396 isLargeBuf = FALSE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700397 isMultiRsp = FALSE;
Steve Frenchb8643e12005-04-28 22:41:07 -0700398 smb_buffer = smallbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 iov.iov_base = smb_buffer;
400 iov.iov_len = 4;
401 smb_msg.msg_control = NULL;
402 smb_msg.msg_controllen = 0;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000403 pdu_length = 4; /* enough to get RFC1001 header */
404incomplete_rcv:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 length =
406 kernel_recvmsg(csocket, &smb_msg,
Steve Frenchf01d5e12007-08-30 21:13:31 +0000407 &iov, 1, pdu_length, 0 /* BB other flags? */);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408
Igor Mammedovaaf737a2007-04-03 19:16:43 +0000409 if ( kthread_should_stop() ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 break;
411 } else if (server->tcpStatus == CifsNeedReconnect) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000412 cFYI(1, ("Reconnect after server stopped responding"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 cifs_reconnect(server);
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000414 cFYI(1, ("call to reconnect done"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 csocket = server->ssocket;
416 continue;
417 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700418 msleep(1); /* minimum sleep to prevent looping
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 allowing socket to clear and app threads to set
420 tcpStatus CifsNeedReconnect if server hung */
421 continue;
422 } else if (length <= 0) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000423 if (server->tcpStatus == CifsNew) {
424 cFYI(1, ("tcp session abend after SMBnegprot"));
Steve French09d1db52005-04-28 22:41:08 -0700425 /* some servers kill the TCP session rather than
426 returning an SMB negprot error, in which
427 case reconnecting here is not going to help,
428 and so simply return error to mount */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 break;
430 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000431 if (!try_to_freeze() && (length == -EINTR)) {
Steve French467a8f82007-06-27 22:41:32 +0000432 cFYI(1, ("cifsd thread killed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 break;
434 }
Steve French467a8f82007-06-27 22:41:32 +0000435 cFYI(1, ("Reconnect after unexpected peek error %d",
Steve French57337e42005-04-28 22:41:10 -0700436 length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 cifs_reconnect(server);
438 csocket = server->ssocket;
439 wake_up(&server->response_q);
440 continue;
Steve French46810cb2005-04-28 22:41:09 -0700441 } else if (length < 4) {
Steve Frenchf01d5e12007-08-30 21:13:31 +0000442 cFYI(1, ("less than four bytes received (%d bytes)",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 length));
Steve Frenchf01d5e12007-08-30 21:13:31 +0000444 pdu_length -= length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 cifs_reconnect(server);
Steve Frenchf01d5e12007-08-30 21:13:31 +0000446 msleep(1);
447 goto incomplete_rcv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 }
Steve French67010fb2005-04-28 22:41:09 -0700449
Steve French70ca7342005-09-22 16:32:06 -0700450 /* The right amount was read from socket - 4 bytes */
451 /* so we can now interpret the length field */
Steve French46810cb2005-04-28 22:41:09 -0700452
Steve French70ca7342005-09-22 16:32:06 -0700453 /* the first byte big endian of the length field,
454 is actually not part of the length but the type
455 with the most common, zero, as regular data */
456 temp = *((char *) smb_buffer);
457
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000458 /* Note that FC 1001 length is big endian on the wire,
Steve French70ca7342005-09-22 16:32:06 -0700459 but we convert it here so it is always manipulated
460 as host byte order */
Steve French46810cb2005-04-28 22:41:09 -0700461 pdu_length = ntohl(smb_buffer->smb_buf_length);
Steve French70ca7342005-09-22 16:32:06 -0700462 smb_buffer->smb_buf_length = pdu_length;
Steve French46810cb2005-04-28 22:41:09 -0700463
Steve French467a8f82007-06-27 22:41:32 +0000464 cFYI(1, ("rfc1002 length 0x%x", pdu_length+4));
Steve French70ca7342005-09-22 16:32:06 -0700465
466 if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000467 continue;
Steve French70ca7342005-09-22 16:32:06 -0700468 } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
Steve French467a8f82007-06-27 22:41:32 +0000469 cFYI(1, ("Good RFC 1002 session rsp"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700470 continue;
Steve French70ca7342005-09-22 16:32:06 -0700471 } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000472 /* we get this from Windows 98 instead of
Steve French46810cb2005-04-28 22:41:09 -0700473 an error on SMB negprot response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000474 cFYI(1, ("Negative RFC1002 Session Response Error 0x%x)",
Steve French70ca7342005-09-22 16:32:06 -0700475 pdu_length));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000476 if (server->tcpStatus == CifsNew) {
477 /* if nack on negprot (rather than
Steve French46810cb2005-04-28 22:41:09 -0700478 ret of smb negprot error) reconnecting
479 not going to help, ret error to mount */
480 break;
481 } else {
482 /* give server a second to
483 clean up before reconnect attempt */
484 msleep(1000);
485 /* always try 445 first on reconnect
486 since we get NACK on some if we ever
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000487 connected to port 139 (the NACK is
Steve French46810cb2005-04-28 22:41:09 -0700488 since we do not begin with RFC1001
489 session initialize frame) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000490 server->addr.sockAddr.sin_port =
Steve French46810cb2005-04-28 22:41:09 -0700491 htons(CIFS_PORT);
492 cifs_reconnect(server);
493 csocket = server->ssocket;
494 wake_up(&server->response_q);
495 continue;
496 }
Steve French70ca7342005-09-22 16:32:06 -0700497 } else if (temp != (char) 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000498 cERROR(1, ("Unknown RFC 1002 frame"));
Steve French70ca7342005-09-22 16:32:06 -0700499 cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
500 length);
Steve French46810cb2005-04-28 22:41:09 -0700501 cifs_reconnect(server);
502 csocket = server->ssocket;
503 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700504 }
505
506 /* else we have an SMB response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000507 if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French46810cb2005-04-28 22:41:09 -0700508 (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700509 cERROR(1, ("Invalid size SMB length %d pdu_length %d",
Steve French46810cb2005-04-28 22:41:09 -0700510 length, pdu_length+4));
Steve Frenche4eb2952005-04-28 22:41:09 -0700511 cifs_reconnect(server);
512 csocket = server->ssocket;
513 wake_up(&server->response_q);
514 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000515 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700516
517 /* else length ok */
518 reconnect = 0;
519
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000520 if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700521 isLargeBuf = TRUE;
522 memcpy(bigbuf, smallbuf, 4);
523 smb_buffer = bigbuf;
524 }
525 length = 0;
526 iov.iov_base = 4 + (char *)smb_buffer;
527 iov.iov_len = pdu_length;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000528 for (total_read = 0; total_read < pdu_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700529 total_read += length) {
530 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
531 pdu_length - total_read, 0);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000532 if ( kthread_should_stop() ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700533 (length == -EINTR)) {
534 /* then will exit */
535 reconnect = 2;
536 break;
537 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700538 cifs_reconnect(server);
539 csocket = server->ssocket;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000540 /* Reconnect wakes up rspns q */
Steve Frenche4eb2952005-04-28 22:41:09 -0700541 /* Now we will reread sock */
542 reconnect = 1;
543 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000544 } else if ((length == -ERESTARTSYS) ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700545 (length == -EAGAIN)) {
546 msleep(1); /* minimum sleep to prevent looping,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000547 allowing socket to clear and app
Steve Frenche4eb2952005-04-28 22:41:09 -0700548 threads to set tcpStatus
549 CifsNeedReconnect if server hung*/
Steve French46810cb2005-04-28 22:41:09 -0700550 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700551 } else if (length <= 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000552 cERROR(1, ("Received no data, expecting %d",
Steve Frenche4eb2952005-04-28 22:41:09 -0700553 pdu_length - total_read));
554 cifs_reconnect(server);
555 csocket = server->ssocket;
556 reconnect = 1;
557 break;
Steve French46810cb2005-04-28 22:41:09 -0700558 }
559 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000560 if (reconnect == 2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700561 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000562 else if (reconnect == 1)
Steve Frenche4eb2952005-04-28 22:41:09 -0700563 continue;
564
565 length += 4; /* account for rfc1002 hdr */
Steve French50c2f752007-07-13 00:33:32 +0000566
Steve Frenche4eb2952005-04-28 22:41:09 -0700567
568 dump_smb(smb_buffer, length);
Steve French184ed212006-02-24 06:15:11 +0000569 if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700570 cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
Steve Frenche4eb2952005-04-28 22:41:09 -0700571 continue;
572 }
573
574
575 task_to_wake = NULL;
576 spin_lock(&GlobalMid_Lock);
577 list_for_each(tmp, &server->pending_mid_q) {
578 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
579
Steve French50c2f752007-07-13 00:33:32 +0000580 if ((mid_entry->mid == smb_buffer->Mid) &&
Steve Frenche4eb2952005-04-28 22:41:09 -0700581 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
582 (mid_entry->command == smb_buffer->Command)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000583 if (check2ndT2(smb_buffer,server->maxBuf) > 0) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700584 /* We have a multipart transact2 resp */
Steve Frenchcd634992005-04-28 22:41:10 -0700585 isMultiRsp = TRUE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000586 if (mid_entry->resp_buf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700587 /* merge response - fix up 1st*/
Steve French50c2f752007-07-13 00:33:32 +0000588 if (coalesce_t2(smb_buffer,
Steve Frenche4eb2952005-04-28 22:41:09 -0700589 mid_entry->resp_buf)) {
Steve French39798772006-05-31 22:40:51 +0000590 mid_entry->multiRsp = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700591 break;
592 } else {
593 /* all parts received */
Steve French39798772006-05-31 22:40:51 +0000594 mid_entry->multiEnd = 1;
Steve French50c2f752007-07-13 00:33:32 +0000595 goto multi_t2_fnd;
Steve Frenche4eb2952005-04-28 22:41:09 -0700596 }
597 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000598 if (!isLargeBuf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700599 cERROR(1,("1st trans2 resp needs bigbuf"));
600 /* BB maybe we can fix this up, switch
Steve French50c2f752007-07-13 00:33:32 +0000601 to already allocated large buffer? */
Steve Frenche4eb2952005-04-28 22:41:09 -0700602 } else {
Steve Frenchcd634992005-04-28 22:41:10 -0700603 /* Have first buffer */
Steve Frenche4eb2952005-04-28 22:41:09 -0700604 mid_entry->resp_buf =
605 smb_buffer;
606 mid_entry->largeBuf = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700607 bigbuf = NULL;
608 }
609 }
610 break;
Steve French50c2f752007-07-13 00:33:32 +0000611 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700612 mid_entry->resp_buf = smb_buffer;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000613 if (isLargeBuf)
Steve Frenche4eb2952005-04-28 22:41:09 -0700614 mid_entry->largeBuf = 1;
615 else
616 mid_entry->largeBuf = 0;
617multi_t2_fnd:
618 task_to_wake = mid_entry->tsk;
619 mid_entry->midState = MID_RESPONSE_RECEIVED;
Steve French1047abc2005-10-11 19:58:06 -0700620#ifdef CONFIG_CIFS_STATS2
621 mid_entry->when_received = jiffies;
622#endif
Steve French3a5ff612006-07-14 22:37:11 +0000623 /* so we do not time out requests to server
624 which is still responding (since server could
625 be busy but not dead) */
626 server->lstrp = jiffies;
Steve Frenche4eb2952005-04-28 22:41:09 -0700627 break;
628 }
629 }
630 spin_unlock(&GlobalMid_Lock);
631 if (task_to_wake) {
Steve Frenchcd634992005-04-28 22:41:10 -0700632 /* Was previous buf put in mpx struct for multi-rsp? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000633 if (!isMultiRsp) {
Steve Frenchcd634992005-04-28 22:41:10 -0700634 /* smb buffer will be freed by user thread */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000635 if (isLargeBuf) {
Steve Frenchcd634992005-04-28 22:41:10 -0700636 bigbuf = NULL;
637 } else
638 smallbuf = NULL;
639 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700640 wake_up_process(task_to_wake);
Steve Frenchd7c8c942006-03-03 10:43:49 +0000641 } else if ((is_valid_oplock_break(smb_buffer, server) == FALSE)
Steve French50c2f752007-07-13 00:33:32 +0000642 && (isMultiRsp == FALSE)) {
643 cERROR(1, ("No task to wake, unknown frame received! "
644 "NumMids %d", midCount.counter));
645 cifs_dump_mem("Received Data is: ", (char *)smb_buffer,
Steve French70ca7342005-09-22 16:32:06 -0700646 sizeof(struct smb_hdr));
Steve French39798772006-05-31 22:40:51 +0000647#ifdef CONFIG_CIFS_DEBUG2
648 cifs_dump_detail(smb_buffer);
649 cifs_dump_mids(server);
650#endif /* CIFS_DEBUG2 */
Steve French50c2f752007-07-13 00:33:32 +0000651
Steve Frenche4eb2952005-04-28 22:41:09 -0700652 }
653 } /* end while !EXITING */
654
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 spin_lock(&GlobalMid_Lock);
656 server->tcpStatus = CifsExiting;
657 server->tsk = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700658 /* check if we have blocked requests that need to free */
659 /* Note that cifs_max_pending is normally 50, but
660 can be set at module install time to as little as two */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000661 if (atomic_read(&server->inFlight) >= cifs_max_pending)
Steve French31ca3bc2005-04-28 22:41:11 -0700662 atomic_set(&server->inFlight, cifs_max_pending - 1);
663 /* We do not want to set the max_pending too low or we
664 could end up with the counter going negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +0000666 /* Although there should not be any requests blocked on
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700668 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 to the same server - they now will see the session is in exit state
670 and get out of SendReceive. */
671 wake_up_all(&server->request_q);
672 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700673 msleep(125);
Steve French50c2f752007-07-13 00:33:32 +0000674
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000675 if (server->ssocket) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 sock_release(csocket);
677 server->ssocket = NULL;
678 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700679 /* buffer usuallly freed in free_mid - need to free it here on exit */
680 if (bigbuf != NULL)
681 cifs_buf_release(bigbuf);
682 if (smallbuf != NULL)
683 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684
685 read_lock(&GlobalSMBSeslock);
686 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700687 /* loop through server session structures attached to this and
688 mark them dead */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 list_for_each(tmp, &GlobalSMBSessionList) {
690 ses =
691 list_entry(tmp, struct cifsSesInfo,
692 cifsSessionList);
693 if (ses->server == server) {
694 ses->status = CifsExiting;
695 ses->server = NULL;
696 }
697 }
698 read_unlock(&GlobalSMBSeslock);
699 } else {
Steve French31ca3bc2005-04-28 22:41:11 -0700700 /* although we can not zero the server struct pointer yet,
701 since there are active requests which may depnd on them,
702 mark the corresponding SMB sessions as exiting too */
703 list_for_each(tmp, &GlobalSMBSessionList) {
704 ses = list_entry(tmp, struct cifsSesInfo,
705 cifsSessionList);
706 if (ses->server == server) {
707 ses->status = CifsExiting;
708 }
709 }
710
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 spin_lock(&GlobalMid_Lock);
712 list_for_each(tmp, &server->pending_mid_q) {
713 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
714 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French50c2f752007-07-13 00:33:32 +0000715 cFYI(1, ("Clearing Mid 0x%x - waking up ",
716 mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 task_to_wake = mid_entry->tsk;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000718 if (task_to_wake) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 wake_up_process(task_to_wake);
720 }
721 }
722 }
723 spin_unlock(&GlobalMid_Lock);
724 read_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700726 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 }
728
Steve Frenchf1914012005-08-18 09:37:34 -0700729 if (!list_empty(&server->pending_mid_q)) {
Steve French50c2f752007-07-13 00:33:32 +0000730 /* mpx threads have not exited yet give them
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700732 /* due to delays on oplock break requests, we need
733 to wait at least 45 seconds before giving up
734 on a request getting a response and going ahead
735 and killing cifsd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve French31ca3bc2005-04-28 22:41:11 -0700737 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 /* if threads still have not exited they are probably never
739 coming home not much else we can do but free the memory */
740 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741
742 write_lock(&GlobalSMBSeslock);
743 atomic_dec(&tcpSesAllocCount);
744 length = tcpSesAllocCount.counter;
Steve French31ca3bc2005-04-28 22:41:11 -0700745
746 /* last chance to mark ses pointers invalid
747 if there are any pointing to this (e.g
Steve French50c2f752007-07-13 00:33:32 +0000748 if a crazy root user tried to kill cifsd
Steve French31ca3bc2005-04-28 22:41:11 -0700749 kernel thread explicitly this might happen) */
750 list_for_each(tmp, &GlobalSMBSessionList) {
751 ses = list_entry(tmp, struct cifsSesInfo,
752 cifsSessionList);
753 if (ses->server == server) {
754 ses->server = NULL;
755 }
756 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 write_unlock(&GlobalSMBSeslock);
Steve French31ca3bc2005-04-28 22:41:11 -0700758
759 kfree(server);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000760 if (length > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 mempool_resize(cifs_req_poolp,
762 length + cifs_min_rcv,
763 GFP_KERNEL);
764 }
Steve French50c2f752007-07-13 00:33:32 +0000765
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 return 0;
767}
768
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769static int
Steve French50c2f752007-07-13 00:33:32 +0000770cifs_parse_mount_options(char *options, const char *devname,
771 struct smb_vol *vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772{
773 char *value;
774 char *data;
775 unsigned int temp_len, i, j;
776 char separator[2];
777
778 separator[0] = ',';
Steve French50c2f752007-07-13 00:33:32 +0000779 separator[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780
Linus Torvalds12e36b22006-10-13 08:09:29 -0700781 if (Local_System_Name[0] != 0)
Steve French50c2f752007-07-13 00:33:32 +0000782 memcpy(vol->source_rfc1001_name, Local_System_Name, 15);
Steve French2cd646a2006-09-28 19:43:08 +0000783 else {
Linus Torvalds12e36b22006-10-13 08:09:29 -0700784 char *nodename = utsname()->nodename;
Steve French50c2f752007-07-13 00:33:32 +0000785 int n = strnlen(nodename, 15);
786 memset(vol->source_rfc1001_name, 0x20, 15);
787 for (i = 0; i < n; i++) {
Steve French2cd646a2006-09-28 19:43:08 +0000788 /* does not have to be perfect mapping since field is
789 informational, only used for servers that do not support
790 port 445 and it can be overridden at mount time */
Linus Torvalds12e36b22006-10-13 08:09:29 -0700791 vol->source_rfc1001_name[i] = toupper(nodename[i]);
Steve French2cd646a2006-09-28 19:43:08 +0000792 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 }
794 vol->source_rfc1001_name[15] = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -0700795 /* null target name indicates to use *SMBSERVR default called name
796 if we end up sending RFC1001 session initialize */
797 vol->target_rfc1001_name[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 vol->linux_uid = current->uid; /* current->euid instead? */
799 vol->linux_gid = current->gid;
800 vol->dir_mode = S_IRWXUGO;
801 /* 2767 perms indicate mandatory locking support */
802 vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);
803
804 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
805 vol->rw = TRUE;
Jeremy Allisonac670552005-06-22 17:26:35 -0700806 /* default is always to request posix paths. */
807 vol->posix_paths = 1;
808
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 if (!options)
810 return 1;
811
Steve French50c2f752007-07-13 00:33:32 +0000812 if (strncmp(options, "sep=", 4) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000813 if (options[4] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 separator[0] = options[4];
815 options += 5;
816 } else {
Steve French467a8f82007-06-27 22:41:32 +0000817 cFYI(1, ("Null separator not allowed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 }
819 }
Steve French50c2f752007-07-13 00:33:32 +0000820
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 while ((data = strsep(&options, separator)) != NULL) {
822 if (!*data)
823 continue;
824 if ((value = strchr(data, '=')) != NULL)
825 *value++ = '\0';
826
Steve French50c2f752007-07-13 00:33:32 +0000827 /* Have to parse this before we parse for "user" */
828 if (strnicmp(data, "user_xattr", 10) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 vol->no_xattr = 0;
Steve French50c2f752007-07-13 00:33:32 +0000830 } else if (strnicmp(data, "nouser_xattr", 12) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 vol->no_xattr = 1;
832 } else if (strnicmp(data, "user", 4) == 0) {
Steve French4b952a92006-10-30 21:46:13 +0000833 if (!value) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 printk(KERN_WARNING
835 "CIFS: invalid or missing username\n");
836 return 1; /* needs_arg; */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000837 } else if (!*value) {
Steve French4b952a92006-10-30 21:46:13 +0000838 /* null user, ie anonymous, authentication */
839 vol->nullauth = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 }
841 if (strnlen(value, 200) < 200) {
842 vol->username = value;
843 } else {
844 printk(KERN_WARNING "CIFS: username too long\n");
845 return 1;
846 }
847 } else if (strnicmp(data, "pass", 4) == 0) {
848 if (!value) {
849 vol->password = NULL;
850 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000851 } else if (value[0] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 /* check if string begins with double comma
853 since that would mean the password really
854 does start with a comma, and would not
855 indicate an empty string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000856 if (value[1] != separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 vol->password = NULL;
858 continue;
859 }
860 }
861 temp_len = strlen(value);
862 /* removed password length check, NTLM passwords
863 can be arbitrarily long */
864
Steve French50c2f752007-07-13 00:33:32 +0000865 /* if comma in password, the string will be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 prematurely null terminated. Commas in password are
867 specified across the cifs mount interface by a double
868 comma ie ,, and a comma used as in other cases ie ','
869 as a parameter delimiter/separator is single and due
870 to the strsep above is temporarily zeroed. */
871
872 /* NB: password legally can have multiple commas and
873 the only illegal character in a password is null */
874
Steve French50c2f752007-07-13 00:33:32 +0000875 if ((value[temp_len] == 0) &&
Steve French09d1db52005-04-28 22:41:08 -0700876 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 /* reinsert comma */
878 value[temp_len] = separator[0];
Steve French50c2f752007-07-13 00:33:32 +0000879 temp_len += 2; /* move after second comma */
880 while (value[temp_len] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 if (value[temp_len] == separator[0]) {
Steve French50c2f752007-07-13 00:33:32 +0000882 if (value[temp_len+1] ==
Steve French09d1db52005-04-28 22:41:08 -0700883 separator[0]) {
884 /* skip second comma */
885 temp_len++;
Steve French50c2f752007-07-13 00:33:32 +0000886 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 /* single comma indicating start
888 of next parm */
889 break;
890 }
891 }
892 temp_len++;
893 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000894 if (value[temp_len] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 options = NULL;
896 } else {
897 value[temp_len] = 0;
898 /* point option to start of next parm */
899 options = value + temp_len + 1;
900 }
Steve French50c2f752007-07-13 00:33:32 +0000901 /* go from value to value + temp_len condensing
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 double commas to singles. Note that this ends up
903 allocating a few bytes too many, which is ok */
Pekka Enberge915fc42005-09-06 15:18:35 -0700904 vol->password = kzalloc(temp_len, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000905 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000906 printk(KERN_WARNING "CIFS: no memory "
907 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700908 return 1;
909 }
Steve French50c2f752007-07-13 00:33:32 +0000910 for (i = 0, j = 0; i < temp_len; i++, j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 vol->password[j] = value[i];
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000912 if (value[i] == separator[0]
Steve French09d1db52005-04-28 22:41:08 -0700913 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 /* skip second comma */
915 i++;
916 }
917 }
918 vol->password[j] = 0;
919 } else {
Pekka Enberge915fc42005-09-06 15:18:35 -0700920 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000921 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000922 printk(KERN_WARNING "CIFS: no memory "
923 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700924 return 1;
925 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 strcpy(vol->password, value);
927 }
928 } else if (strnicmp(data, "ip", 2) == 0) {
929 if (!value || !*value) {
930 vol->UNCip = NULL;
931 } else if (strnlen(value, 35) < 35) {
932 vol->UNCip = value;
933 } else {
Steve French50c2f752007-07-13 00:33:32 +0000934 printk(KERN_WARNING "CIFS: ip address "
935 "too long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 return 1;
937 }
Steve French50c2f752007-07-13 00:33:32 +0000938 } else if (strnicmp(data, "sec", 3) == 0) {
939 if (!value || !*value) {
940 cERROR(1, ("no security value specified"));
941 continue;
942 } else if (strnicmp(value, "krb5i", 5) == 0) {
943 vol->secFlg |= CIFSSEC_MAY_KRB5 |
Steve French189acaa2006-06-23 02:33:48 +0000944 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800945 } else if (strnicmp(value, "krb5p", 5) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000946 /* vol->secFlg |= CIFSSEC_MUST_SEAL |
947 CIFSSEC_MAY_KRB5; */
948 cERROR(1, ("Krb5 cifs privacy not supported"));
Steve Frenchbf820672005-12-01 22:32:42 -0800949 return 1;
950 } else if (strnicmp(value, "krb5", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000951 vol->secFlg |= CIFSSEC_MAY_KRB5;
Steve Frenchbf820672005-12-01 22:32:42 -0800952 } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000953 vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
Steve French189acaa2006-06-23 02:33:48 +0000954 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800955 } else if (strnicmp(value, "ntlmv2", 6) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000956 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve Frenchbf820672005-12-01 22:32:42 -0800957 } else if (strnicmp(value, "ntlmi", 5) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000958 vol->secFlg |= CIFSSEC_MAY_NTLM |
Steve French189acaa2006-06-23 02:33:48 +0000959 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800960 } else if (strnicmp(value, "ntlm", 4) == 0) {
961 /* ntlm is default so can be turned off too */
Steve French750d1152006-06-27 06:28:30 +0000962 vol->secFlg |= CIFSSEC_MAY_NTLM;
Steve Frenchbf820672005-12-01 22:32:42 -0800963 } else if (strnicmp(value, "nontlm", 6) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000964 /* BB is there a better way to do this? */
Steve French750d1152006-06-27 06:28:30 +0000965 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve French189acaa2006-06-23 02:33:48 +0000966#ifdef CONFIG_CIFS_WEAK_PW_HASH
967 } else if (strnicmp(value, "lanman", 6) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000968 vol->secFlg |= CIFSSEC_MAY_LANMAN;
Steve French189acaa2006-06-23 02:33:48 +0000969#endif
Steve Frenchbf820672005-12-01 22:32:42 -0800970 } else if (strnicmp(value, "none", 4) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000971 vol->nullauth = 1;
Steve French50c2f752007-07-13 00:33:32 +0000972 } else {
973 cERROR(1, ("bad security option: %s", value));
974 return 1;
975 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 } else if ((strnicmp(data, "unc", 3) == 0)
977 || (strnicmp(data, "target", 6) == 0)
978 || (strnicmp(data, "path", 4) == 0)) {
979 if (!value || !*value) {
Steve French50c2f752007-07-13 00:33:32 +0000980 printk(KERN_WARNING "CIFS: invalid path to "
981 "network resource\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 return 1; /* needs_arg; */
983 }
984 if ((temp_len = strnlen(value, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +0000985 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +0000986 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 return 1;
Steve French50c2f752007-07-13 00:33:32 +0000988 strcpy(vol->UNC, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 if (strncmp(vol->UNC, "//", 2) == 0) {
990 vol->UNC[0] = '\\';
991 vol->UNC[1] = '\\';
Steve French50c2f752007-07-13 00:33:32 +0000992 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 printk(KERN_WARNING
Steve French50c2f752007-07-13 00:33:32 +0000994 "CIFS: UNC Path does not begin "
995 "with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 return 1;
997 }
998 } else {
999 printk(KERN_WARNING "CIFS: UNC name too long\n");
1000 return 1;
1001 }
1002 } else if ((strnicmp(data, "domain", 3) == 0)
1003 || (strnicmp(data, "workgroup", 5) == 0)) {
1004 if (!value || !*value) {
1005 printk(KERN_WARNING "CIFS: invalid domain name\n");
1006 return 1; /* needs_arg; */
1007 }
1008 /* BB are there cases in which a comma can be valid in
1009 a domain name and need special handling? */
Steve French39798772006-05-31 22:40:51 +00001010 if (strnlen(value, 256) < 256) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 vol->domainname = value;
1012 cFYI(1, ("Domain name set"));
1013 } else {
Steve French50c2f752007-07-13 00:33:32 +00001014 printk(KERN_WARNING "CIFS: domain name too "
1015 "long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 return 1;
1017 }
Steve French50c2f752007-07-13 00:33:32 +00001018 } else if (strnicmp(data, "prefixpath", 10) == 0) {
1019 if (!value || !*value) {
1020 printk(KERN_WARNING
1021 "CIFS: invalid path prefix\n");
1022 return 1; /* needs_argument */
1023 }
1024 if ((temp_len = strnlen(value, 1024)) < 1024) {
Steve French4523cc32007-04-30 20:13:06 +00001025 if (value[0] != '/')
Steve French2fe87f02006-09-21 07:02:52 +00001026 temp_len++; /* missing leading slash */
Steve French50c2f752007-07-13 00:33:32 +00001027 vol->prepath = kmalloc(temp_len+1, GFP_KERNEL);
1028 if (vol->prepath == NULL)
1029 return 1;
Steve French4523cc32007-04-30 20:13:06 +00001030 if (value[0] != '/') {
Steve French2fe87f02006-09-21 07:02:52 +00001031 vol->prepath[0] = '/';
Steve French50c2f752007-07-13 00:33:32 +00001032 strcpy(vol->prepath+1, value);
Steve French2fe87f02006-09-21 07:02:52 +00001033 } else
Steve French50c2f752007-07-13 00:33:32 +00001034 strcpy(vol->prepath, value);
1035 cFYI(1, ("prefix path %s", vol->prepath));
1036 } else {
1037 printk(KERN_WARNING "CIFS: prefix too long\n");
1038 return 1;
1039 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 } else if (strnicmp(data, "iocharset", 9) == 0) {
1041 if (!value || !*value) {
Steve French63135e02007-07-17 17:34:02 +00001042 printk(KERN_WARNING "CIFS: invalid iocharset "
1043 "specified\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 return 1; /* needs_arg; */
1045 }
1046 if (strnlen(value, 65) < 65) {
Steve French50c2f752007-07-13 00:33:32 +00001047 if (strnicmp(value, "default", 7))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 vol->iocharset = value;
Steve French50c2f752007-07-13 00:33:32 +00001049 /* if iocharset not set then load_nls_default
1050 is used by caller */
1051 cFYI(1, ("iocharset set to %s", value));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 } else {
Steve French63135e02007-07-17 17:34:02 +00001053 printk(KERN_WARNING "CIFS: iocharset name "
1054 "too long.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 return 1;
1056 }
1057 } else if (strnicmp(data, "uid", 3) == 0) {
1058 if (value && *value) {
1059 vol->linux_uid =
1060 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001061 vol->override_uid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 }
1063 } else if (strnicmp(data, "gid", 3) == 0) {
1064 if (value && *value) {
1065 vol->linux_gid =
1066 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001067 vol->override_gid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 }
1069 } else if (strnicmp(data, "file_mode", 4) == 0) {
1070 if (value && *value) {
1071 vol->file_mode =
1072 simple_strtoul(value, &value, 0);
1073 }
1074 } else if (strnicmp(data, "dir_mode", 4) == 0) {
1075 if (value && *value) {
1076 vol->dir_mode =
1077 simple_strtoul(value, &value, 0);
1078 }
1079 } else if (strnicmp(data, "dirmode", 4) == 0) {
1080 if (value && *value) {
1081 vol->dir_mode =
1082 simple_strtoul(value, &value, 0);
1083 }
1084 } else if (strnicmp(data, "port", 4) == 0) {
1085 if (value && *value) {
1086 vol->port =
1087 simple_strtoul(value, &value, 0);
1088 }
1089 } else if (strnicmp(data, "rsize", 5) == 0) {
1090 if (value && *value) {
1091 vol->rsize =
1092 simple_strtoul(value, &value, 0);
1093 }
1094 } else if (strnicmp(data, "wsize", 5) == 0) {
1095 if (value && *value) {
1096 vol->wsize =
1097 simple_strtoul(value, &value, 0);
1098 }
1099 } else if (strnicmp(data, "sockopt", 5) == 0) {
1100 if (value && *value) {
1101 vol->sockopt =
1102 simple_strtoul(value, &value, 0);
1103 }
1104 } else if (strnicmp(data, "netbiosname", 4) == 0) {
1105 if (!value || !*value || (*value == ' ')) {
Steve French63135e02007-07-17 17:34:02 +00001106 cFYI(1, ("invalid (empty) netbiosname"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 } else {
Steve French50c2f752007-07-13 00:33:32 +00001108 memset(vol->source_rfc1001_name, 0x20, 15);
1109 for (i = 0; i < 15; i++) {
1110 /* BB are there cases in which a comma can be
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 valid in this workstation netbios name (and need
1112 special handling)? */
1113
1114 /* We do not uppercase netbiosname for user */
Steve French50c2f752007-07-13 00:33:32 +00001115 if (value[i] == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 break;
Steve French50c2f752007-07-13 00:33:32 +00001117 else
1118 vol->source_rfc1001_name[i] =
1119 value[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 }
1121 /* The string has 16th byte zero still from
1122 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001123 if ((i == 15) && (value[i] != 0))
1124 printk(KERN_WARNING "CIFS: netbiosname"
1125 " longer than 15 truncated.\n");
Steve Frencha10faeb22005-08-22 21:38:31 -07001126 }
1127 } else if (strnicmp(data, "servern", 7) == 0) {
1128 /* servernetbiosname specified override *SMBSERVER */
1129 if (!value || !*value || (*value == ' ')) {
Steve French467a8f82007-06-27 22:41:32 +00001130 cFYI(1, ("empty server netbiosname specified"));
Steve Frencha10faeb22005-08-22 21:38:31 -07001131 } else {
1132 /* last byte, type, is 0x20 for servr type */
Steve French50c2f752007-07-13 00:33:32 +00001133 memset(vol->target_rfc1001_name, 0x20, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001134
Steve French50c2f752007-07-13 00:33:32 +00001135 for (i = 0; i < 15; i++) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001136 /* BB are there cases in which a comma can be
Steve French50c2f752007-07-13 00:33:32 +00001137 valid in this workstation netbios name
1138 (and need special handling)? */
Steve Frencha10faeb22005-08-22 21:38:31 -07001139
Steve French50c2f752007-07-13 00:33:32 +00001140 /* user or mount helper must uppercase
1141 the netbiosname */
1142 if (value[i] == 0)
Steve Frencha10faeb22005-08-22 21:38:31 -07001143 break;
1144 else
Steve French50c2f752007-07-13 00:33:32 +00001145 vol->target_rfc1001_name[i] =
1146 value[i];
Steve Frencha10faeb22005-08-22 21:38:31 -07001147 }
1148 /* The string has 16th byte zero still from
1149 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001150 if ((i == 15) && (value[i] != 0))
1151 printk(KERN_WARNING "CIFS: server net"
1152 "biosname longer than 15 truncated.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 }
1154 } else if (strnicmp(data, "credentials", 4) == 0) {
1155 /* ignore */
1156 } else if (strnicmp(data, "version", 3) == 0) {
1157 /* ignore */
Steve French50c2f752007-07-13 00:33:32 +00001158 } else if (strnicmp(data, "guest", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 /* ignore */
1160 } else if (strnicmp(data, "rw", 2) == 0) {
1161 vol->rw = TRUE;
1162 } else if ((strnicmp(data, "suid", 4) == 0) ||
1163 (strnicmp(data, "nosuid", 6) == 0) ||
1164 (strnicmp(data, "exec", 4) == 0) ||
1165 (strnicmp(data, "noexec", 6) == 0) ||
1166 (strnicmp(data, "nodev", 5) == 0) ||
1167 (strnicmp(data, "noauto", 6) == 0) ||
1168 (strnicmp(data, "dev", 3) == 0)) {
1169 /* The mount tool or mount.cifs helper (if present)
Steve French50c2f752007-07-13 00:33:32 +00001170 uses these opts to set flags, and the flags are read
1171 by the kernel vfs layer before we get here (ie
1172 before read super) so there is no point trying to
1173 parse these options again and set anything and it
1174 is ok to just ignore them */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 continue;
1176 } else if (strnicmp(data, "ro", 2) == 0) {
1177 vol->rw = FALSE;
1178 } else if (strnicmp(data, "hard", 4) == 0) {
1179 vol->retry = 1;
1180 } else if (strnicmp(data, "soft", 4) == 0) {
1181 vol->retry = 0;
1182 } else if (strnicmp(data, "perm", 4) == 0) {
1183 vol->noperm = 0;
1184 } else if (strnicmp(data, "noperm", 6) == 0) {
1185 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001186 } else if (strnicmp(data, "mapchars", 8) == 0) {
1187 vol->remap = 1;
1188 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1189 vol->remap = 0;
Steve French50c2f752007-07-13 00:33:32 +00001190 } else if (strnicmp(data, "sfu", 3) == 0) {
1191 vol->sfu_emul = 1;
1192 } else if (strnicmp(data, "nosfu", 5) == 0) {
1193 vol->sfu_emul = 0;
Jeremy Allisonac670552005-06-22 17:26:35 -07001194 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1195 vol->posix_paths = 1;
1196 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1197 vol->posix_paths = 0;
Steve Frenchc18c8422007-07-18 23:21:09 +00001198 } else if (strnicmp(data, "nounix", 6) == 0) {
1199 vol->no_linux_ext = 1;
1200 } else if (strnicmp(data, "nolinux", 7) == 0) {
1201 vol->no_linux_ext = 1;
Steve French50c2f752007-07-13 00:33:32 +00001202 } else if ((strnicmp(data, "nocase", 6) == 0) ||
Steve Frencha10faeb22005-08-22 21:38:31 -07001203 (strnicmp(data, "ignorecase", 10) == 0)) {
Steve French50c2f752007-07-13 00:33:32 +00001204 vol->nocase = 1;
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001205 } else if (strnicmp(data, "brl", 3) == 0) {
1206 vol->nobrl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001207 } else if ((strnicmp(data, "nobrl", 5) == 0) ||
Steve French1c955182005-08-30 20:58:07 -07001208 (strnicmp(data, "nolock", 6) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001209 vol->nobrl = 1;
Steve Frenchd3485d32005-08-19 11:04:29 -07001210 /* turn off mandatory locking in mode
1211 if remote locking is turned off since the
1212 local vfs will do advisory */
Steve French50c2f752007-07-13 00:33:32 +00001213 if (vol->file_mode ==
1214 (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
Steve Frenchd3485d32005-08-19 11:04:29 -07001215 vol->file_mode = S_IALLUGO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 } else if (strnicmp(data, "setuids", 7) == 0) {
1217 vol->setuids = 1;
1218 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1219 vol->setuids = 0;
1220 } else if (strnicmp(data, "nohard", 6) == 0) {
1221 vol->retry = 0;
1222 } else if (strnicmp(data, "nosoft", 6) == 0) {
1223 vol->retry = 1;
1224 } else if (strnicmp(data, "nointr", 6) == 0) {
1225 vol->intr = 0;
1226 } else if (strnicmp(data, "intr", 4) == 0) {
1227 vol->intr = 1;
Steve French50c2f752007-07-13 00:33:32 +00001228 } else if (strnicmp(data, "serverino", 7) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 vol->server_ino = 1;
Steve French50c2f752007-07-13 00:33:32 +00001230 } else if (strnicmp(data, "noserverino", 9) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 vol->server_ino = 0;
Steve French50c2f752007-07-13 00:33:32 +00001232 } else if (strnicmp(data, "cifsacl", 7) == 0) {
Steve French0a4b92c2006-01-12 15:44:21 -08001233 vol->cifs_acl = 1;
1234 } else if (strnicmp(data, "nocifsacl", 9) == 0) {
1235 vol->cifs_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001236 } else if (strnicmp(data, "acl", 3) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 vol->no_psx_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001238 } else if (strnicmp(data, "noacl", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 vol->no_psx_acl = 1;
Steve French50c2f752007-07-13 00:33:32 +00001240 } else if (strnicmp(data, "sign", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +00001241 vol->secFlg |= CIFSSEC_MUST_SIGN;
1242/* } else if (strnicmp(data, "seal",4) == 0) {
1243 vol->secFlg |= CIFSSEC_MUST_SEAL; */
Steve French50c2f752007-07-13 00:33:32 +00001244 } else if (strnicmp(data, "direct", 6) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001246 } else if (strnicmp(data, "forcedirectio", 13) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001248 } else if (strnicmp(data, "in6_addr", 8) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 if (!value || !*value) {
1250 vol->in6_addr = NULL;
1251 } else if (strnlen(value, 49) == 48) {
1252 vol->in6_addr = value;
1253 } else {
Steve French50c2f752007-07-13 00:33:32 +00001254 printk(KERN_WARNING "CIFS: ip v6 address not "
1255 "48 characters long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 return 1;
1257 }
1258 } else if (strnicmp(data, "noac", 4) == 0) {
Steve French50c2f752007-07-13 00:33:32 +00001259 printk(KERN_WARNING "CIFS: Mount option noac not "
1260 "supported. Instead set "
1261 "/proc/fs/cifs/LookupCacheEnabled to 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 } else
Steve French50c2f752007-07-13 00:33:32 +00001263 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",
1264 data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 }
1266 if (vol->UNC == NULL) {
Steve French4523cc32007-04-30 20:13:06 +00001267 if (devname == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001268 printk(KERN_WARNING "CIFS: Missing UNC name for mount "
1269 "target\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 return 1;
1271 }
1272 if ((temp_len = strnlen(devname, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001273 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001274 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001276 strcpy(vol->UNC, devname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 if (strncmp(vol->UNC, "//", 2) == 0) {
1278 vol->UNC[0] = '\\';
1279 vol->UNC[1] = '\\';
1280 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Steve French50c2f752007-07-13 00:33:32 +00001281 printk(KERN_WARNING "CIFS: UNC Path does not "
1282 "begin with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 return 1;
1284 }
1285 } else {
1286 printk(KERN_WARNING "CIFS: UNC name too long\n");
1287 return 1;
1288 }
1289 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001290 if (vol->UNCip == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 vol->UNCip = &vol->UNC[2];
1292
1293 return 0;
1294}
1295
1296static struct cifsSesInfo *
Steve French50c2f752007-07-13 00:33:32 +00001297cifs_find_tcp_session(struct in_addr *target_ip_addr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 struct in6_addr *target_ip6_addr,
1299 char *userName, struct TCP_Server_Info **psrvTcp)
1300{
1301 struct list_head *tmp;
1302 struct cifsSesInfo *ses;
1303 *psrvTcp = NULL;
1304 read_lock(&GlobalSMBSeslock);
1305
1306 list_for_each(tmp, &GlobalSMBSessionList) {
1307 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
1308 if (ses->server) {
Steve French50c2f752007-07-13 00:33:32 +00001309 if ((target_ip_addr &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 (ses->server->addr.sockAddr.sin_addr.s_addr
1311 == target_ip_addr->s_addr)) || (target_ip6_addr
1312 && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
Steve French50c2f752007-07-13 00:33:32 +00001313 target_ip6_addr, sizeof(*target_ip6_addr)))) {
1314 /* BB lock server and tcp session and increment
1315 use count here?? */
1316
1317 /* found a match on the TCP session */
1318 *psrvTcp = ses->server;
1319
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 /* BB check if reconnection needed */
1321 if (strncmp
1322 (ses->userName, userName,
1323 MAX_USERNAME_SIZE) == 0){
1324 read_unlock(&GlobalSMBSeslock);
Steve French50c2f752007-07-13 00:33:32 +00001325 /* Found exact match on both TCP and
1326 SMB sessions */
1327 return ses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 }
1329 }
1330 }
1331 /* else tcp and smb sessions need reconnection */
1332 }
1333 read_unlock(&GlobalSMBSeslock);
1334 return NULL;
1335}
1336
1337static struct cifsTconInfo *
1338find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
1339{
1340 struct list_head *tmp;
1341 struct cifsTconInfo *tcon;
1342
1343 read_lock(&GlobalSMBSeslock);
1344 list_for_each(tmp, &GlobalTreeConnectionList) {
Steve Frenche466e482006-08-15 13:07:18 +00001345 cFYI(1, ("Next tcon"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
1347 if (tcon->ses) {
1348 if (tcon->ses->server) {
1349 cFYI(1,
Steve Frenche466e482006-08-15 13:07:18 +00001350 ("old ip addr: %x == new ip %x ?",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 tcon->ses->server->addr.sockAddr.sin_addr.
1352 s_addr, new_target_ip_addr));
1353 if (tcon->ses->server->addr.sockAddr.sin_addr.
1354 s_addr == new_target_ip_addr) {
Steve Frenche466e482006-08-15 13:07:18 +00001355 /* BB lock tcon, server and tcp session and increment use count here? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 /* found a match on the TCP session */
1357 /* BB check if reconnection needed */
Steve French50c2f752007-07-13 00:33:32 +00001358 cFYI(1,
1359 ("IP match, old UNC: %s new: %s",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 tcon->treeName, uncName));
1361 if (strncmp
1362 (tcon->treeName, uncName,
1363 MAX_TREE_SIZE) == 0) {
1364 cFYI(1,
Steve Frenche466e482006-08-15 13:07:18 +00001365 ("and old usr: %s new: %s",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 tcon->treeName, uncName));
1367 if (strncmp
1368 (tcon->ses->userName,
1369 userName,
1370 MAX_USERNAME_SIZE) == 0) {
1371 read_unlock(&GlobalSMBSeslock);
Steve Frenche466e482006-08-15 13:07:18 +00001372 /* matched smb session
1373 (user name */
1374 return tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 }
1376 }
1377 }
1378 }
1379 }
1380 }
1381 read_unlock(&GlobalSMBSeslock);
1382 return NULL;
1383}
1384
1385int
1386connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
Steve French737b7582005-04-28 22:41:06 -07001387 const char *old_path, const struct nls_table *nls_codepage,
1388 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389{
1390 unsigned char *referrals = NULL;
1391 unsigned int num_referrals;
1392 int rc = 0;
1393
Steve French50c2f752007-07-13 00:33:32 +00001394 rc = get_dfs_path(xid, pSesInfo, old_path, nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001395 &num_referrals, &referrals, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396
1397 /* BB Add in code to: if valid refrl, if not ip address contact
Steve French50c2f752007-07-13 00:33:32 +00001398 the helper that resolves tcp names, mount to it, try to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 tcon to it unmount it if fail */
1400
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001401 kfree(referrals);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402
1403 return rc;
1404}
1405
1406int
Steve French50c2f752007-07-13 00:33:32 +00001407get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
1408 const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
1409 unsigned char **preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410{
1411 char *temp_unc;
1412 int rc = 0;
1413
1414 *pnum_referrals = 0;
1415
1416 if (pSesInfo->ipc_tid == 0) {
1417 temp_unc = kmalloc(2 /* for slashes */ +
Steve French50c2f752007-07-13 00:33:32 +00001418 strnlen(pSesInfo->serverName,
1419 SERVER_NAME_LEN_WITH_NULL * 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 + 1 + 4 /* slash IPC$ */ + 2,
1421 GFP_KERNEL);
1422 if (temp_unc == NULL)
1423 return -ENOMEM;
1424 temp_unc[0] = '\\';
1425 temp_unc[1] = '\\';
1426 strcpy(temp_unc + 2, pSesInfo->serverName);
1427 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1428 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1429 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00001430 ("CIFS Tcon rc = %d ipc_tid = %d", rc, pSesInfo->ipc_tid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 kfree(temp_unc);
1432 }
1433 if (rc == 0)
1434 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001435 pnum_referrals, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436
1437 return rc;
1438}
1439
1440/* See RFC1001 section 14 on representation of Netbios names */
Steve French50c2f752007-07-13 00:33:32 +00001441static void rfc1002mangle(char *target, char *source, unsigned int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442{
Steve French50c2f752007-07-13 00:33:32 +00001443 unsigned int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444
Steve French50c2f752007-07-13 00:33:32 +00001445 for (i = 0, j = 0; i < (length); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 /* mask a nibble at a time and encode */
1447 target[j] = 'A' + (0x0F & (source[i] >> 4));
1448 target[j+1] = 'A' + (0x0F & source[i]);
Steve French50c2f752007-07-13 00:33:32 +00001449 j += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 }
1451
1452}
1453
1454
1455static int
Steve French50c2f752007-07-13 00:33:32 +00001456ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
1457 char *netbios_name, char *target_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458{
1459 int rc = 0;
1460 int connected = 0;
1461 __be16 orig_port = 0;
1462
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001463 if (*csocket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001464 rc = sock_create_kern(PF_INET, SOCK_STREAM,
1465 IPPROTO_TCP, csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001467 cERROR(1, ("Error %d creating socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 *csocket = NULL;
1469 return rc;
1470 } else {
1471 /* BB other socket options to set KEEPALIVE, NODELAY? */
Steve French467a8f82007-06-27 22:41:32 +00001472 cFYI(1, ("Socket created"));
Steve French50c2f752007-07-13 00:33:32 +00001473 (*csocket)->sk->sk_allocation = GFP_NOFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 }
1475 }
1476
1477 psin_server->sin_family = AF_INET;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001478 if (psin_server->sin_port) { /* user overrode default port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 rc = (*csocket)->ops->connect(*csocket,
1480 (struct sockaddr *) psin_server,
Steve French50c2f752007-07-13 00:33:32 +00001481 sizeof (struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 if (rc >= 0)
1483 connected = 1;
Steve French50c2f752007-07-13 00:33:32 +00001484 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001486 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001487 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 later if fall back ports fail this time */
1489 orig_port = psin_server->sin_port;
1490
1491 /* do not retry on the same port we just failed on */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001492 if (psin_server->sin_port != htons(CIFS_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 psin_server->sin_port = htons(CIFS_PORT);
1494
1495 rc = (*csocket)->ops->connect(*csocket,
1496 (struct sockaddr *) psin_server,
Steve French50c2f752007-07-13 00:33:32 +00001497 sizeof (struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 if (rc >= 0)
1499 connected = 1;
1500 }
1501 }
1502 if (!connected) {
1503 psin_server->sin_port = htons(RFC1001_PORT);
1504 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
Steve French50c2f752007-07-13 00:33:32 +00001505 psin_server,
1506 sizeof (struct sockaddr_in), 0);
1507 if (rc >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 connected = 1;
1509 }
1510
1511 /* give up here - unless we want to retry on different
1512 protocol families some day */
1513 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001514 if (orig_port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 psin_server->sin_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001516 cFYI(1, ("Error %d connecting to server via ipv4", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 sock_release(*csocket);
1518 *csocket = NULL;
1519 return rc;
1520 }
Steve French50c2f752007-07-13 00:33:32 +00001521 /* Eventually check for other socket options to change from
1522 the default. sock_setsockopt not used because it expects
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 user space buffer */
Steve French50c2f752007-07-13 00:33:32 +00001524 cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",
1525 (*csocket)->sk->sk_sndbuf,
Steve Frenchb387eae2005-10-10 14:21:15 -07001526 (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchb387eae2005-10-10 14:21:15 -07001528 /* make the bufsizes depend on wsize/rsize and max requests */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001529 if ((*csocket)->sk->sk_sndbuf < (200 * 1024))
Steve Frenchb387eae2005-10-10 14:21:15 -07001530 (*csocket)->sk->sk_sndbuf = 200 * 1024;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001531 if ((*csocket)->sk->sk_rcvbuf < (140 * 1024))
Steve Frenchb387eae2005-10-10 14:21:15 -07001532 (*csocket)->sk->sk_rcvbuf = 140 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533
1534 /* send RFC1001 sessinit */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001535 if (psin_server->sin_port == htons(RFC1001_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 /* some servers require RFC1001 sessinit before sending
Steve French50c2f752007-07-13 00:33:32 +00001537 negprot - BB check reconnection in case where second
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 sessinit is sent but no second negprot */
Steve French50c2f752007-07-13 00:33:32 +00001539 struct rfc1002_session_packet *ses_init_buf;
1540 struct smb_hdr *smb_buf;
1541 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
1542 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001543 if (ses_init_buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 ses_init_buf->trailer.session_req.called_len = 32;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001545 if (target_name && (target_name[0] != 0)) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001546 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1547 target_name, 16);
1548 } else {
1549 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
Steve French50c2f752007-07-13 00:33:32 +00001550 DEFAULT_CIFS_CALLED_NAME, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001551 }
1552
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 ses_init_buf->trailer.session_req.calling_len = 32;
1554 /* calling name ends in null (byte 16) from old smb
1555 convention. */
Steve French50c2f752007-07-13 00:33:32 +00001556 if (netbios_name && (netbios_name[0] != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
Steve French50c2f752007-07-13 00:33:32 +00001558 netbios_name, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 } else {
1560 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
Steve French50c2f752007-07-13 00:33:32 +00001561 "LINUX_CIFS_CLNT", 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 }
1563 ses_init_buf->trailer.session_req.scope1 = 0;
1564 ses_init_buf->trailer.session_req.scope2 = 0;
1565 smb_buf = (struct smb_hdr *)ses_init_buf;
1566 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1567 smb_buf->smb_buf_length = 0x81000044;
1568 rc = smb_send(*csocket, smb_buf, 0x44,
1569 (struct sockaddr *)psin_server);
1570 kfree(ses_init_buf);
Steve French50c2f752007-07-13 00:33:32 +00001571 msleep(1); /* RFC1001 layer in at least one server
Steve French083d3a22006-03-03 09:53:36 +00001572 requires very short break before negprot
1573 presumably because not expecting negprot
1574 to follow so fast. This is a simple
Steve French50c2f752007-07-13 00:33:32 +00001575 solution that works without
Steve French083d3a22006-03-03 09:53:36 +00001576 complicating the code and causes no
1577 significant slowing down on mount
1578 for everyone else */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 }
Steve French50c2f752007-07-13 00:33:32 +00001580 /* else the negprot may still work without this
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 even though malloc failed */
Steve French50c2f752007-07-13 00:33:32 +00001582
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 }
Steve French50c2f752007-07-13 00:33:32 +00001584
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 return rc;
1586}
1587
1588static int
1589ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1590{
1591 int rc = 0;
1592 int connected = 0;
1593 __be16 orig_port = 0;
1594
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001595 if (*csocket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001596 rc = sock_create_kern(PF_INET6, SOCK_STREAM,
1597 IPPROTO_TCP, csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001599 cERROR(1, ("Error %d creating ipv6 socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 *csocket = NULL;
1601 return rc;
1602 } else {
1603 /* BB other socket options to set KEEPALIVE, NODELAY? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001604 cFYI(1, ("ipv6 Socket created"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 (*csocket)->sk->sk_allocation = GFP_NOFS;
1606 }
1607 }
1608
1609 psin_server->sin6_family = AF_INET6;
1610
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001611 if (psin_server->sin6_port) { /* user overrode default port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 rc = (*csocket)->ops->connect(*csocket,
1613 (struct sockaddr *) psin_server,
Steve French50c2f752007-07-13 00:33:32 +00001614 sizeof (struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 if (rc >= 0)
1616 connected = 1;
Steve French50c2f752007-07-13 00:33:32 +00001617 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001619 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001620 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 later if fall back ports fail this time */
1622
1623 orig_port = psin_server->sin6_port;
1624 /* do not retry on the same port we just failed on */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001625 if (psin_server->sin6_port != htons(CIFS_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 psin_server->sin6_port = htons(CIFS_PORT);
1627
1628 rc = (*csocket)->ops->connect(*csocket,
1629 (struct sockaddr *) psin_server,
Steve French50c2f752007-07-13 00:33:32 +00001630 sizeof (struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 if (rc >= 0)
1632 connected = 1;
1633 }
1634 }
1635 if (!connected) {
1636 psin_server->sin6_port = htons(RFC1001_PORT);
1637 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
Steve French50c2f752007-07-13 00:33:32 +00001638 psin_server, sizeof (struct sockaddr_in6), 0);
1639 if (rc >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 connected = 1;
1641 }
1642
1643 /* give up here - unless we want to retry on different
1644 protocol families some day */
1645 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001646 if (orig_port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 psin_server->sin6_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001648 cFYI(1, ("Error %d connecting to server via ipv6", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 sock_release(*csocket);
1650 *csocket = NULL;
1651 return rc;
1652 }
Steve French50c2f752007-07-13 00:33:32 +00001653 /* Eventually check for other socket options to change from
1654 the default. sock_setsockopt not used because it expects
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 user space buffer */
1656 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve French50c2f752007-07-13 00:33:32 +00001657
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 return rc;
1659}
1660
Steve French50c2f752007-07-13 00:33:32 +00001661void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
1662 struct super_block *sb, struct smb_vol *vol_info)
Steve French8af18972007-02-14 04:42:51 +00001663{
1664 /* if we are reconnecting then should we check to see if
1665 * any requested capabilities changed locally e.g. via
1666 * remount but we can not do much about it here
1667 * if they have (even if we could detect it by the following)
1668 * Perhaps we could add a backpointer to array of sb from tcon
1669 * or if we change to make all sb to same share the same
1670 * sb as NFS - then we only have one backpointer to sb.
1671 * What if we wanted to mount the server share twice once with
1672 * and once without posixacls or posix paths? */
1673 __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001674
Steve Frenchc18c8422007-07-18 23:21:09 +00001675 if (vol_info && vol_info->no_linux_ext) {
1676 tcon->fsUnixInfo.Capability = 0;
1677 tcon->unix_ext = 0; /* Unix Extensions disabled */
1678 cFYI(1, ("Linux protocol extensions disabled"));
1679 return;
1680 } else if (vol_info)
1681 tcon->unix_ext = 1; /* Unix Extensions supported */
1682
1683 if (tcon->unix_ext == 0) {
1684 cFYI(1, ("Unix extensions disabled so not set on reconnect"));
1685 return;
1686 }
Steve French50c2f752007-07-13 00:33:32 +00001687
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001688 if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
Steve French8af18972007-02-14 04:42:51 +00001689 __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001690
Steve French8af18972007-02-14 04:42:51 +00001691 /* check for reconnect case in which we do not
1692 want to change the mount behavior if we can avoid it */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001693 if (vol_info == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001694 /* turn off POSIX ACL and PATHNAMES if not set
Steve French8af18972007-02-14 04:42:51 +00001695 originally at mount time */
1696 if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
1697 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
1698 if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0)
1699 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French8af18972007-02-14 04:42:51 +00001700 }
Steve French50c2f752007-07-13 00:33:32 +00001701
Steve French8af18972007-02-14 04:42:51 +00001702 cap &= CIFS_UNIX_CAP_MASK;
Steve French75865f8c2007-06-24 18:30:48 +00001703 if (vol_info && vol_info->no_psx_acl)
Steve French8af18972007-02-14 04:42:51 +00001704 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00001705 else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001706 cFYI(1, ("negotiated posix acl support"));
1707 if (sb)
Steve French8af18972007-02-14 04:42:51 +00001708 sb->s_flags |= MS_POSIXACL;
1709 }
1710
Steve French75865f8c2007-06-24 18:30:48 +00001711 if (vol_info && vol_info->posix_paths == 0)
Steve French8af18972007-02-14 04:42:51 +00001712 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00001713 else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001714 cFYI(1, ("negotiate posix pathnames"));
Steve French75865f8c2007-06-24 18:30:48 +00001715 if (sb)
Steve French50c2f752007-07-13 00:33:32 +00001716 CIFS_SB(sb)->mnt_cifs_flags |=
Steve French8af18972007-02-14 04:42:51 +00001717 CIFS_MOUNT_POSIX_PATHS;
1718 }
Steve French50c2f752007-07-13 00:33:32 +00001719
Steve French984acfe2007-04-26 16:42:50 +00001720 /* We might be setting the path sep back to a different
1721 form if we are reconnecting and the server switched its
Steve French50c2f752007-07-13 00:33:32 +00001722 posix path capability for this share */
Steve French75865f8c2007-06-24 18:30:48 +00001723 if (sb && (CIFS_SB(sb)->prepathlen > 0))
Steve French984acfe2007-04-26 16:42:50 +00001724 CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
Steve French75865f8c2007-06-24 18:30:48 +00001725
1726 if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
1727 if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
1728 CIFS_SB(sb)->rsize = 127 * 1024;
1729#ifdef CONFIG_CIFS_DEBUG2
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001730 cFYI(1, ("larger reads not supported by srv"));
Steve French75865f8c2007-06-24 18:30:48 +00001731#endif
1732 }
1733 }
Steve French50c2f752007-07-13 00:33:32 +00001734
1735
1736 cFYI(1, ("Negotiate caps 0x%x", (int)cap));
Steve French8af18972007-02-14 04:42:51 +00001737#ifdef CONFIG_CIFS_DEBUG2
Steve French75865f8c2007-06-24 18:30:48 +00001738 if (cap & CIFS_UNIX_FCNTL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001739 cFYI(1, ("FCNTL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001740 if (cap & CIFS_UNIX_EXTATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001741 cFYI(1, ("EXTATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001742 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001743 cFYI(1, ("POSIX path cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001744 if (cap & CIFS_UNIX_XATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001745 cFYI(1, ("XATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001746 if (cap & CIFS_UNIX_POSIX_ACL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001747 cFYI(1, ("POSIX ACL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001748 if (cap & CIFS_UNIX_LARGE_READ_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001749 cFYI(1, ("very large read cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001750 if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001751 cFYI(1, ("very large write cap"));
Steve French8af18972007-02-14 04:42:51 +00001752#endif /* CIFS_DEBUG2 */
1753 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001754 cFYI(1, ("setting capabilities failed"));
Steve French8af18972007-02-14 04:42:51 +00001755 }
1756 }
1757}
1758
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759int
1760cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1761 char *mount_data, const char *devname)
1762{
1763 int rc = 0;
1764 int xid;
1765 int address_type = AF_INET;
1766 struct socket *csocket = NULL;
1767 struct sockaddr_in sin_server;
1768 struct sockaddr_in6 sin_server6;
1769 struct smb_vol volume_info;
1770 struct cifsSesInfo *pSesInfo = NULL;
1771 struct cifsSesInfo *existingCifsSes = NULL;
1772 struct cifsTconInfo *tcon = NULL;
1773 struct TCP_Server_Info *srvTcp = NULL;
1774
1775 xid = GetXid();
1776
1777/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
Steve French50c2f752007-07-13 00:33:32 +00001778
1779 memset(&volume_info, 0, sizeof(struct smb_vol));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001781 kfree(volume_info.UNC);
1782 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001783 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784 FreeXid(xid);
1785 return -EINVAL;
1786 }
1787
Jeff Layton8426c392007-05-05 03:27:49 +00001788 if (volume_info.nullauth) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001789 cFYI(1, ("null user"));
Jeff Layton8426c392007-05-05 03:27:49 +00001790 volume_info.username = NULL;
1791 } else if (volume_info.username) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 /* BB fixme parse for domain name here */
Steve French467a8f82007-06-27 22:41:32 +00001793 cFYI(1, ("Username: %s", volume_info.username));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 } else {
Steve Frenchbf820672005-12-01 22:32:42 -08001795 cifserror("No username specified");
Steve French50c2f752007-07-13 00:33:32 +00001796 /* In userspace mount helper we can get user name from alternate
1797 locations such as env variables and files on disk */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001798 kfree(volume_info.UNC);
1799 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001800 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 FreeXid(xid);
1802 return -EINVAL;
1803 }
1804
1805 if (volume_info.UNCip && volume_info.UNC) {
Steve French50c2f752007-07-13 00:33:32 +00001806 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,
1807 &sin_server.sin_addr.s_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001809 if (rc <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 /* not ipv4 address, try ipv6 */
Steve French50c2f752007-07-13 00:33:32 +00001811 rc = cifs_inet_pton(AF_INET6, volume_info.UNCip,
1812 &sin_server6.sin6_addr.in6_u);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001813 if (rc > 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814 address_type = AF_INET6;
1815 } else {
1816 address_type = AF_INET;
1817 }
Steve French50c2f752007-07-13 00:33:32 +00001818
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001819 if (rc <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 /* we failed translating address */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001821 kfree(volume_info.UNC);
1822 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001823 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 FreeXid(xid);
1825 return -EINVAL;
1826 }
1827
1828 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1829 /* success */
1830 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00001831 } else if (volume_info.UNCip) {
1832 /* BB using ip addr as server name to connect to the
1833 DFS root below */
1834 cERROR(1, ("Connecting to DFS root not implemented yet"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001835 kfree(volume_info.UNC);
1836 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001837 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 FreeXid(xid);
1839 return -EINVAL;
1840 } else /* which servers DFS root would we conect to */ {
1841 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00001842 ("CIFS mount error: No UNC path (e.g. -o "
1843 "unc=//192.168.1.100/public) specified"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001844 kfree(volume_info.UNC);
1845 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001846 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 FreeXid(xid);
1848 return -EINVAL;
1849 }
1850
1851 /* this is needed for ASCII cp to Unicode converts */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001852 if (volume_info.iocharset == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 cifs_sb->local_nls = load_nls_default();
1854 /* load_nls_default can not return null */
1855 } else {
1856 cifs_sb->local_nls = load_nls(volume_info.iocharset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001857 if (cifs_sb->local_nls == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001858 cERROR(1, ("CIFS mount error: iocharset %s not found",
1859 volume_info.iocharset));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001860 kfree(volume_info.UNC);
1861 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001862 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 FreeXid(xid);
1864 return -ELIBACC;
1865 }
1866 }
1867
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001868 if (address_type == AF_INET)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1870 NULL /* no ipv6 addr */,
1871 volume_info.username, &srvTcp);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001872 else if (address_type == AF_INET6) {
1873 cFYI(1, ("looking for ipv6 address"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1875 &sin_server6.sin6_addr,
1876 volume_info.username, &srvTcp);
Steve French5858ae42007-04-25 11:59:10 +00001877 } else {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001878 kfree(volume_info.UNC);
1879 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001880 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 FreeXid(xid);
1882 return -EINVAL;
1883 }
1884
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 if (srvTcp) {
Steve French50c2f752007-07-13 00:33:32 +00001886 cFYI(1, ("Existing tcp session with server found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 } else { /* create socket */
Steve French4523cc32007-04-30 20:13:06 +00001888 if (volume_info.port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 sin_server.sin_port = htons(volume_info.port);
1890 else
1891 sin_server.sin_port = 0;
Steve French5858ae42007-04-25 11:59:10 +00001892 if (address_type == AF_INET6) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001893 cFYI(1, ("attempting ipv6 connect"));
Steve French5858ae42007-04-25 11:59:10 +00001894 /* BB should we allow ipv6 on port 139? */
1895 /* other OS never observed in Wild doing 139 with v6 */
Steve French50c2f752007-07-13 00:33:32 +00001896 rc = ipv6_connect(&sin_server6, &csocket);
1897 } else
1898 rc = ipv4_connect(&sin_server, &csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -07001899 volume_info.source_rfc1001_name,
1900 volume_info.target_rfc1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001902 cERROR(1, ("Error connecting to IPv4 socket. "
1903 "Aborting operation"));
Steve French4523cc32007-04-30 20:13:06 +00001904 if (csocket != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001906 kfree(volume_info.UNC);
1907 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001908 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 FreeXid(xid);
1910 return rc;
1911 }
1912
1913 srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
1914 if (srvTcp == NULL) {
1915 rc = -ENOMEM;
1916 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001917 kfree(volume_info.UNC);
1918 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001919 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 FreeXid(xid);
1921 return rc;
1922 } else {
1923 memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
Steve French50c2f752007-07-13 00:33:32 +00001924 memcpy(&srvTcp->addr.sockAddr, &sin_server,
1925 sizeof (struct sockaddr_in));
1926 atomic_set(&srvTcp->inFlight, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 /* BB Add code for ipv6 case too */
1928 srvTcp->ssocket = csocket;
1929 srvTcp->protocolType = IPV4;
1930 init_waitqueue_head(&srvTcp->response_q);
1931 init_waitqueue_head(&srvTcp->request_q);
1932 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1933 /* at this point we are the only ones with the pointer
1934 to the struct since the kernel thread not created yet
1935 so no need to spinlock this init of tcpStatus */
1936 srvTcp->tcpStatus = CifsNew;
1937 init_MUTEX(&srvTcp->tcpSem);
Igor Mammedovaaf737a2007-04-03 19:16:43 +00001938 srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd");
Steve French4523cc32007-04-30 20:13:06 +00001939 if ( IS_ERR(srvTcp->tsk) ) {
Igor Mammedovaaf737a2007-04-03 19:16:43 +00001940 rc = PTR_ERR(srvTcp->tsk);
Steve French50c2f752007-07-13 00:33:32 +00001941 cERROR(1, ("error %d create cifsd thread", rc));
Igor Mammedovaaf737a2007-04-03 19:16:43 +00001942 srvTcp->tsk = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001944 kfree(volume_info.UNC);
1945 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001946 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 FreeXid(xid);
1948 return rc;
Steve Frenchf1914012005-08-18 09:37:34 -07001949 }
1950 wait_for_completion(&cifsd_complete);
1951 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00001952 memcpy(srvTcp->workstation_RFC1001_name,
1953 volume_info.source_rfc1001_name, 16);
1954 memcpy(srvTcp->server_RFC1001_name,
1955 volume_info.target_rfc1001_name, 16);
Steve Frenchad009ac2005-04-28 22:41:05 -07001956 srvTcp->sequence_number = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957 }
1958 }
1959
1960 if (existingCifsSes) {
1961 pSesInfo = existingCifsSes;
Steve Frenchbf820672005-12-01 22:32:42 -08001962 cFYI(1, ("Existing smb sess found"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001963 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 /* volume_info.UNC freed at end of function */
1965 } else if (!rc) {
Steve Frenchbf820672005-12-01 22:32:42 -08001966 cFYI(1, ("Existing smb sess not found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 pSesInfo = sesInfoAlloc();
1968 if (pSesInfo == NULL)
1969 rc = -ENOMEM;
1970 else {
1971 pSesInfo->server = srvTcp;
1972 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1973 NIPQUAD(sin_server.sin_addr.s_addr));
1974 }
1975
Steve French50c2f752007-07-13 00:33:32 +00001976 if (!rc) {
1977 /* volume_info.password freed at unmount */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978 if (volume_info.password)
1979 pSesInfo->password = volume_info.password;
1980 if (volume_info.username)
1981 strncpy(pSesInfo->userName,
Steve French50c2f752007-07-13 00:33:32 +00001982 volume_info.username,
1983 MAX_USERNAME_SIZE);
Steve French39798772006-05-31 22:40:51 +00001984 if (volume_info.domainname) {
1985 int len = strlen(volume_info.domainname);
Steve French50c2f752007-07-13 00:33:32 +00001986 pSesInfo->domainName =
Steve French39798772006-05-31 22:40:51 +00001987 kmalloc(len + 1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001988 if (pSesInfo->domainName)
Steve French39798772006-05-31 22:40:51 +00001989 strcpy(pSesInfo->domainName,
1990 volume_info.domainname);
1991 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 pSesInfo->linux_uid = volume_info.linux_uid;
Steve French750d1152006-06-27 06:28:30 +00001993 pSesInfo->overrideSecFlg = volume_info.secFlg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 down(&pSesInfo->sesSem);
Steve French189acaa2006-06-23 02:33:48 +00001995 /* BB FIXME need to pass vol->secFlgs BB */
Steve French50c2f752007-07-13 00:33:32 +00001996 rc = cifs_setup_session(xid, pSesInfo,
1997 cifs_sb->local_nls);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 up(&pSesInfo->sesSem);
Steve French4523cc32007-04-30 20:13:06 +00001999 if (!rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 atomic_inc(&srvTcp->socketUseCount);
2001 } else
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002002 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 }
Steve French50c2f752007-07-13 00:33:32 +00002004
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 /* search for existing tcon to this server share */
2006 if (!rc) {
Steve French4523cc32007-04-30 20:13:06 +00002007 if (volume_info.rsize > CIFSMaxBufSize) {
Steve French50c2f752007-07-13 00:33:32 +00002008 cERROR(1, ("rsize %d too large, using MaxBufSize",
Steve French0ae0efa2005-10-10 10:57:19 -07002009 volume_info.rsize));
2010 cifs_sb->rsize = CIFSMaxBufSize;
Steve French75865f8c2007-06-24 18:30:48 +00002011 } else if ((volume_info.rsize) &&
2012 (volume_info.rsize <= CIFSMaxBufSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013 cifs_sb->rsize = volume_info.rsize;
Steve French0ae0efa2005-10-10 10:57:19 -07002014 else /* default */
2015 cifs_sb->rsize = CIFSMaxBufSize;
2016
Steve French4523cc32007-04-30 20:13:06 +00002017 if (volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
Steve French50c2f752007-07-13 00:33:32 +00002018 cERROR(1, ("wsize %d too large, using 4096 instead",
Steve French0ae0efa2005-10-10 10:57:19 -07002019 volume_info.wsize));
2020 cifs_sb->wsize = 4096;
Steve French4523cc32007-04-30 20:13:06 +00002021 } else if (volume_info.wsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 cifs_sb->wsize = volume_info.wsize;
2023 else
Steve French50c2f752007-07-13 00:33:32 +00002024 cifs_sb->wsize =
Steve French1877c9e2006-01-27 18:36:11 -08002025 min_t(const int, PAGEVEC_SIZE * PAGE_CACHE_SIZE,
2026 127*1024);
Steve French17cbbaf2006-01-24 20:26:48 -08002027 /* old default of CIFSMaxBufSize was too small now
Steve French50c2f752007-07-13 00:33:32 +00002028 that SMB Write2 can send multiple pages in kvec.
Steve French17cbbaf2006-01-24 20:26:48 -08002029 RFC1001 does not describe what happens when frame
2030 bigger than 128K is sent so use that as max in
2031 conjunction with 52K kvec constraint on arch with 4K
2032 page size */
2033
Steve French4523cc32007-04-30 20:13:06 +00002034 if (cifs_sb->rsize < 2048) {
Steve French50c2f752007-07-13 00:33:32 +00002035 cifs_sb->rsize = 2048;
Steve French6cec2ae2006-02-22 17:31:52 -06002036 /* Windows ME may prefer this */
Steve French467a8f82007-06-27 22:41:32 +00002037 cFYI(1, ("readsize set to minimum: 2048"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 }
Steve French2fe87f02006-09-21 07:02:52 +00002039 /* calculate prepath */
2040 cifs_sb->prepath = volume_info.prepath;
Steve French4523cc32007-04-30 20:13:06 +00002041 if (cifs_sb->prepath) {
Steve French2fe87f02006-09-21 07:02:52 +00002042 cifs_sb->prepathlen = strlen(cifs_sb->prepath);
2043 cifs_sb->prepath[0] = CIFS_DIR_SEP(cifs_sb);
2044 volume_info.prepath = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002045 } else
Steve French2fe87f02006-09-21 07:02:52 +00002046 cifs_sb->prepathlen = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 cifs_sb->mnt_uid = volume_info.linux_uid;
2048 cifs_sb->mnt_gid = volume_info.linux_gid;
2049 cifs_sb->mnt_file_mode = volume_info.file_mode;
2050 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
Steve French467a8f82007-06-27 22:41:32 +00002051 cFYI(1, ("file mode: 0x%x dir mode: 0x%x",
2052 cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053
Steve French4523cc32007-04-30 20:13:06 +00002054 if (volume_info.noperm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
Steve French4523cc32007-04-30 20:13:06 +00002056 if (volume_info.setuids)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
Steve French4523cc32007-04-30 20:13:06 +00002058 if (volume_info.server_ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
Steve French4523cc32007-04-30 20:13:06 +00002060 if (volume_info.remap)
Steve French6a0b4822005-04-28 22:41:05 -07002061 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
Steve French4523cc32007-04-30 20:13:06 +00002062 if (volume_info.no_xattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
Steve French4523cc32007-04-30 20:13:06 +00002064 if (volume_info.sfu_emul)
Steve Frenchd7245c22005-07-14 18:25:12 -05002065 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
Steve French4523cc32007-04-30 20:13:06 +00002066 if (volume_info.nobrl)
Steve Frenchc46fa8a2005-08-18 20:49:57 -07002067 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Steve French4523cc32007-04-30 20:13:06 +00002068 if (volume_info.cifs_acl)
Steve French0a4b92c2006-01-12 15:44:21 -08002069 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
Steve French4523cc32007-04-30 20:13:06 +00002070 if (volume_info.override_uid)
2071 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
2072 if (volume_info.override_gid)
2073 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
2074 if (volume_info.direct_io) {
Steve French467a8f82007-06-27 22:41:32 +00002075 cFYI(1, ("mounting share using direct i/o"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
2077 }
2078
2079 tcon =
2080 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
2081 volume_info.username);
2082 if (tcon) {
Steve Frenchbf820672005-12-01 22:32:42 -08002083 cFYI(1, ("Found match on UNC path"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084 /* we can have only one retry value for a connection
2085 to a share so for resources mounted more than once
Steve French50c2f752007-07-13 00:33:32 +00002086 to the same server share the last value passed in
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087 for the retry flag is used */
2088 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07002089 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090 } else {
2091 tcon = tconInfoAlloc();
2092 if (tcon == NULL)
2093 rc = -ENOMEM;
2094 else {
Steve French50c2f752007-07-13 00:33:32 +00002095 /* check for null share name ie connecting to
Steve French8af18972007-02-14 04:42:51 +00002096 * dfs root */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097
Steve French50c2f752007-07-13 00:33:32 +00002098 /* BB check if this works for exactly length
Steve French8af18972007-02-14 04:42:51 +00002099 * three strings */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
2101 && (strchr(volume_info.UNC + 3, '/') ==
2102 NULL)) {
Steve French737b7582005-04-28 22:41:06 -07002103 rc = connect_to_dfs_path(xid, pSesInfo,
Steve French8af18972007-02-14 04:42:51 +00002104 "", cifs_sb->local_nls,
Steve French50c2f752007-07-13 00:33:32 +00002105 cifs_sb->mnt_cifs_flags &
Steve French8af18972007-02-14 04:42:51 +00002106 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002107 kfree(volume_info.UNC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 FreeXid(xid);
2109 return -ENODEV;
2110 } else {
Steve French8af18972007-02-14 04:42:51 +00002111 /* BB Do we need to wrap sesSem around
2112 * this TCon call and Unix SetFS as
2113 * we do on SessSetup and reconnect? */
Steve French50c2f752007-07-13 00:33:32 +00002114 rc = CIFSTCon(xid, pSesInfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 volume_info.UNC,
2116 tcon, cifs_sb->local_nls);
2117 cFYI(1, ("CIFS Tcon rc = %d", rc));
2118 }
2119 if (!rc) {
2120 atomic_inc(&pSesInfo->inUse);
2121 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07002122 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123 }
2124 }
2125 }
2126 }
Steve French4523cc32007-04-30 20:13:06 +00002127 if (pSesInfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
2129 sb->s_maxbytes = (u64) 1 << 63;
2130 } else
2131 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
2132 }
2133
Steve French8af18972007-02-14 04:42:51 +00002134 /* BB FIXME fix time_gran to be larger for LANMAN sessions */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135 sb->s_time_gran = 100;
2136
2137/* on error free sesinfo and tcon struct if needed */
2138 if (rc) {
2139 /* if session setup failed, use count is zero but
2140 we still need to free cifsd thread */
Steve French4523cc32007-04-30 20:13:06 +00002141 if (atomic_read(&srvTcp->socketUseCount) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142 spin_lock(&GlobalMid_Lock);
2143 srvTcp->tcpStatus = CifsExiting;
2144 spin_unlock(&GlobalMid_Lock);
Steve French4523cc32007-04-30 20:13:06 +00002145 if (srvTcp->tsk) {
Steve French28356a12007-05-23 14:45:36 +00002146 struct task_struct *tsk;
2147 /* If we could verify that kthread_stop would
2148 always wake up processes blocked in
2149 tcp in recv_mesg then we could remove the
2150 send_sig call */
Steve French50c2f752007-07-13 00:33:32 +00002151 force_sig(SIGKILL, srvTcp->tsk);
Steve French28356a12007-05-23 14:45:36 +00002152 tsk = srvTcp->tsk;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002153 if (tsk)
Steve Frenchf7f7c312007-05-24 02:29:51 +00002154 kthread_stop(tsk);
Steve Frenchf1914012005-08-18 09:37:34 -07002155 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156 }
2157 /* If find_unc succeeded then rc == 0 so we can not end */
2158 if (tcon) /* up accidently freeing someone elses tcon struct */
2159 tconInfoFree(tcon);
2160 if (existingCifsSes == NULL) {
2161 if (pSesInfo) {
Steve French50c2f752007-07-13 00:33:32 +00002162 if ((pSesInfo->server) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163 (pSesInfo->status == CifsGood)) {
2164 int temp_rc;
2165 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
2166 /* if the socketUseCount is now zero */
Steve French4523cc32007-04-30 20:13:06 +00002167 if ((temp_rc == -ESHUTDOWN) &&
Steve French50c2f752007-07-13 00:33:32 +00002168 (pSesInfo->server) &&
Jeff5d9c7202007-06-25 22:16:35 +00002169 (pSesInfo->server->tsk)) {
Steve French28356a12007-05-23 14:45:36 +00002170 struct task_struct *tsk;
Jeff5d9c7202007-06-25 22:16:35 +00002171 force_sig(SIGKILL,
2172 pSesInfo->server->tsk);
Steve French28356a12007-05-23 14:45:36 +00002173 tsk = pSesInfo->server->tsk;
Steve Frenchf7f7c312007-05-24 02:29:51 +00002174 if (tsk)
Steve French28356a12007-05-23 14:45:36 +00002175 kthread_stop(tsk);
Steve Frenchf1914012005-08-18 09:37:34 -07002176 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 } else
2178 cFYI(1, ("No session or bad tcon"));
2179 sesInfoFree(pSesInfo);
2180 /* pSesInfo = NULL; */
2181 }
2182 }
2183 } else {
2184 atomic_inc(&tcon->useCount);
2185 cifs_sb->tcon = tcon;
2186 tcon->ses = pSesInfo;
2187
Steve French82940a42006-03-02 03:24:57 +00002188 /* do not care if following two calls succeed - informational */
Steve French737b7582005-04-28 22:41:06 -07002189 CIFSSMBQFSDeviceInfo(xid, tcon);
2190 CIFSSMBQFSAttributeInfo(xid, tcon);
Steve French50c2f752007-07-13 00:33:32 +00002191
Steve French8af18972007-02-14 04:42:51 +00002192 /* tell server which Unix caps we support */
2193 if (tcon->ses->capabilities & CAP_UNIX)
Steve Frenchc18c8422007-07-18 23:21:09 +00002194 /* reset of caps checks mount to see if unix extensions
2195 disabled for just this mount */
Steve French8af18972007-02-14 04:42:51 +00002196 reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
Steve Frenchc18c8422007-07-18 23:21:09 +00002197 else
2198 tcon->unix_ext = 0; /* server does not support them */
2199
2200 if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
Steve French75865f8c2007-06-24 18:30:48 +00002201 cifs_sb->rsize = 1024 * 127;
2202#ifdef CONFIG_CIFS_DEBUG2
Steve Frenchc18c8422007-07-18 23:21:09 +00002203 cFYI(1, ("no very large read support, rsize now 127K"));
Steve French75865f8c2007-06-24 18:30:48 +00002204#endif
Steve French75865f8c2007-06-24 18:30:48 +00002205 }
Steve French3e844692005-10-03 13:37:24 -07002206 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
2207 cifs_sb->wsize = min(cifs_sb->wsize,
2208 (tcon->ses->server->maxBuf -
2209 MAX_CIFS_HDR_SIZE));
Steve French0ae0efa2005-10-10 10:57:19 -07002210 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
Steve French50c2f752007-07-13 00:33:32 +00002211 cifs_sb->rsize = min(cifs_sb->rsize,
2212 (tcon->ses->server->maxBuf -
2213 MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 }
2215
2216 /* volume_info.password is freed above when existing session found
2217 (in which case it is not needed anymore) but when new sesion is created
2218 the password ptr is put in the new session structure (in which case the
2219 password will be freed at unmount time) */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002220 kfree(volume_info.UNC);
Steve French2fe87f02006-09-21 07:02:52 +00002221 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 FreeXid(xid);
2223 return rc;
2224}
2225
2226static int
2227CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French7c7b25b2006-06-01 19:20:10 +00002228 char session_key[CIFS_SESS_KEY_SIZE],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 const struct nls_table *nls_codepage)
2230{
2231 struct smb_hdr *smb_buffer;
2232 struct smb_hdr *smb_buffer_response;
2233 SESSION_SETUP_ANDX *pSMB;
2234 SESSION_SETUP_ANDX *pSMBr;
2235 char *bcc_ptr;
2236 char *user;
2237 char *domain;
2238 int rc = 0;
2239 int remaining_words = 0;
2240 int bytes_returned = 0;
2241 int len;
2242 __u32 capabilities;
2243 __u16 count;
2244
Steve Frencheeac8042006-01-13 21:34:58 -08002245 cFYI(1, ("In sesssetup"));
Steve French4523cc32007-04-30 20:13:06 +00002246 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 return -EINVAL;
2248 user = ses->userName;
2249 domain = ses->domainName;
2250 smb_buffer = cifs_buf_get();
2251 if (smb_buffer == NULL) {
2252 return -ENOMEM;
2253 }
2254 smb_buffer_response = smb_buffer;
2255 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2256
2257 /* send SMBsessionSetup here */
2258 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2259 NULL /* no tCon exists yet */ , 13 /* wct */ );
2260
Steve French1982c342005-08-17 12:38:22 -07002261 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 pSMB->req_no_secext.AndXCommand = 0xFF;
2263 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2264 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2265
Steve French50c2f752007-07-13 00:33:32 +00002266 if (ses->server->secMode &
2267 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2269
2270 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2271 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
2272 if (ses->capabilities & CAP_UNICODE) {
2273 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2274 capabilities |= CAP_UNICODE;
2275 }
2276 if (ses->capabilities & CAP_STATUS32) {
2277 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2278 capabilities |= CAP_STATUS32;
2279 }
2280 if (ses->capabilities & CAP_DFS) {
2281 smb_buffer->Flags2 |= SMBFLG2_DFS;
2282 capabilities |= CAP_DFS;
2283 }
2284 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
2285
Steve French50c2f752007-07-13 00:33:32 +00002286 pSMB->req_no_secext.CaseInsensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002287 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288
2289 pSMB->req_no_secext.CaseSensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002290 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291 bcc_ptr = pByteArea(smb_buffer);
Steve French7c7b25b2006-06-01 19:20:10 +00002292 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2293 bcc_ptr += CIFS_SESS_KEY_SIZE;
2294 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2295 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296
2297 if (ses->capabilities & CAP_UNICODE) {
2298 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
2299 *bcc_ptr = 0;
2300 bcc_ptr++;
2301 }
Steve French4523cc32007-04-30 20:13:06 +00002302 if (user == NULL)
Steve French39798772006-05-31 22:40:51 +00002303 bytes_returned = 0; /* skip null user */
Steve French50c2f752007-07-13 00:33:32 +00002304 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305 bytes_returned =
Steve French50c2f752007-07-13 00:33:32 +00002306 cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 nls_codepage);
2308 /* convert number of 16 bit words to bytes */
2309 bcc_ptr += 2 * bytes_returned;
2310 bcc_ptr += 2; /* trailing null */
2311 if (domain == NULL)
2312 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002313 cifs_strtoUCS((__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314 "CIFS_LINUX_DOM", 32, nls_codepage);
2315 else
2316 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002317 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318 nls_codepage);
2319 bcc_ptr += 2 * bytes_returned;
2320 bcc_ptr += 2;
2321 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002322 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 32, nls_codepage);
2324 bcc_ptr += 2 * bytes_returned;
2325 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002326 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327 32, nls_codepage);
2328 bcc_ptr += 2 * bytes_returned;
2329 bcc_ptr += 2;
2330 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002331 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332 64, nls_codepage);
2333 bcc_ptr += 2 * bytes_returned;
2334 bcc_ptr += 2;
2335 } else {
Steve French50c2f752007-07-13 00:33:32 +00002336 if (user != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337 strncpy(bcc_ptr, user, 200);
2338 bcc_ptr += strnlen(user, 200);
2339 }
2340 *bcc_ptr = 0;
2341 bcc_ptr++;
2342 if (domain == NULL) {
2343 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2344 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2345 } else {
2346 strncpy(bcc_ptr, domain, 64);
2347 bcc_ptr += strnlen(domain, 64);
2348 *bcc_ptr = 0;
2349 bcc_ptr++;
2350 }
2351 strcpy(bcc_ptr, "Linux version ");
2352 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002353 strcpy(bcc_ptr, utsname()->release);
2354 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2356 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2357 }
2358 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2359 smb_buffer->smb_buf_length += count;
2360 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2361
2362 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2363 &bytes_returned, 1);
2364 if (rc) {
2365/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2366 } else if ((smb_buffer_response->WordCount == 3)
2367 || (smb_buffer_response->WordCount == 4)) {
2368 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2369 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2370 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002371 cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */
2372 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format
2373 (little endian) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374 cFYI(1, ("UID = %d ", ses->Suid));
Steve French50c2f752007-07-13 00:33:32 +00002375 /* response can have either 3 or 4 word count - Samba sends 3 */
2376 bcc_ptr = pByteArea(smb_buffer_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377 if ((pSMBr->resp.hdr.WordCount == 3)
2378 || ((pSMBr->resp.hdr.WordCount == 4)
2379 && (blob_len < pSMBr->resp.ByteCount))) {
2380 if (pSMBr->resp.hdr.WordCount == 4)
2381 bcc_ptr += blob_len;
2382
2383 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2384 if ((long) (bcc_ptr) % 2) {
2385 remaining_words =
Steve French50c2f752007-07-13 00:33:32 +00002386 (BCC(smb_buffer_response) - 1) / 2;
2387 /* Unicode strings must be word
2388 aligned */
2389 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 } else {
2391 remaining_words =
2392 BCC(smb_buffer_response) / 2;
2393 }
2394 len =
2395 UniStrnlen((wchar_t *) bcc_ptr,
2396 remaining_words - 1);
2397/* We look for obvious messed up bcc or strings in response so we do not go off
2398 the end since (at least) WIN2K and Windows XP have a major bug in not null
2399 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002400 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002401 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002402 ses->serverOS = kzalloc(2 * (len + 1),
2403 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002404 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002405 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406 cifs_strfromUCS_le(ses->serverOS,
Steve French50c2f752007-07-13 00:33:32 +00002407 (__le16 *)bcc_ptr,
2408 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 bcc_ptr += 2 * (len + 1);
2410 remaining_words -= len + 1;
2411 ses->serverOS[2 * len] = 0;
2412 ses->serverOS[1 + (2 * len)] = 0;
2413 if (remaining_words > 0) {
2414 len = UniStrnlen((wchar_t *)bcc_ptr,
2415 remaining_words-1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002416 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002417 ses->serverNOS = kzalloc(2 * (len + 1),
2418 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002419 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002420 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421 cifs_strfromUCS_le(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002422 (__le16 *)bcc_ptr,
2423 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424 bcc_ptr += 2 * (len + 1);
2425 ses->serverNOS[2 * len] = 0;
2426 ses->serverNOS[1 + (2 * len)] = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002427 if (strncmp(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002428 "NT LAN Manager 4", 16) == 0) {
Steve French467a8f82007-06-27 22:41:32 +00002429 cFYI(1, ("NT4 server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430 ses->flags |= CIFS_SES_NT4;
2431 }
2432 remaining_words -= len + 1;
2433 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002434 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Steve French50c2f752007-07-13 00:33:32 +00002435 /* last string is not always null terminated
2436 (for e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002437 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002438 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439 ses->serverDomain =
Steve French50c2f752007-07-13 00:33:32 +00002440 kzalloc(2*(len+1),
2441 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002442 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002443 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444 cifs_strfromUCS_le(ses->serverDomain,
Steve French50c2f752007-07-13 00:33:32 +00002445 (__le16 *)bcc_ptr,
2446 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447 bcc_ptr += 2 * (len + 1);
2448 ses->serverDomain[2*len] = 0;
2449 ses->serverDomain[1+(2*len)] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002450 } else { /* else no more room so create
2451 dummy domain string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002452 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002453 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002454 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002455 kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002456 }
Steve French50c2f752007-07-13 00:33:32 +00002457 } else { /* no room so create dummy domain
2458 and NOS string */
2459
Steve French433dc242005-04-28 22:41:08 -07002460 /* if these kcallocs fail not much we
2461 can do, but better to not fail the
2462 sesssetup itself */
Steve Frenchcd49b492006-06-26 04:22:36 +00002463 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002465 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002466 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002468 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469 }
2470 } else { /* ASCII */
2471 len = strnlen(bcc_ptr, 1024);
2472 if (((long) bcc_ptr + len) - (long)
2473 pByteArea(smb_buffer_response)
2474 <= BCC(smb_buffer_response)) {
Steve Frenchcd49b492006-06-26 04:22:36 +00002475 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002476 ses->serverOS = kzalloc(len + 1,
2477 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002478 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002479 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002480 strncpy(ses->serverOS, bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481
2482 bcc_ptr += len;
Steve French50c2f752007-07-13 00:33:32 +00002483 /* null terminate the string */
2484 bcc_ptr[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485 bcc_ptr++;
2486
2487 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002488 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002489 ses->serverNOS = kzalloc(len + 1,
2490 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002491 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002492 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493 strncpy(ses->serverNOS, bcc_ptr, len);
2494 bcc_ptr += len;
2495 bcc_ptr[0] = 0;
2496 bcc_ptr++;
2497
2498 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002499 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002500 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002501 ses->serverDomain = kzalloc(len + 1,
2502 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002503 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002504 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002505 strncpy(ses->serverDomain, bcc_ptr,
2506 len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507 bcc_ptr += len;
2508 bcc_ptr[0] = 0;
2509 bcc_ptr++;
2510 } else
2511 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00002512 ("Variable field of length %d "
2513 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 len));
2515 }
2516 } else {
2517 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00002518 (" Security Blob Length extends beyond "
2519 "end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520 }
2521 } else {
2522 cERROR(1,
2523 (" Invalid Word count %d: ",
2524 smb_buffer_response->WordCount));
2525 rc = -EIO;
2526 }
Steve French433dc242005-04-28 22:41:08 -07002527sesssetup_nomem: /* do not return an error on nomem for the info strings,
2528 since that could make reconnection harder, and
2529 reconnection might be needed to free memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530 if (smb_buffer)
2531 cifs_buf_release(smb_buffer);
2532
2533 return rc;
2534}
2535
2536static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
Steve French50c2f752007-07-13 00:33:32 +00002538 struct cifsSesInfo *ses, int *pNTLMv2_flag,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539 const struct nls_table *nls_codepage)
2540{
2541 struct smb_hdr *smb_buffer;
2542 struct smb_hdr *smb_buffer_response;
2543 SESSION_SETUP_ANDX *pSMB;
2544 SESSION_SETUP_ANDX *pSMBr;
2545 char *bcc_ptr;
2546 char *domain;
2547 int rc = 0;
2548 int remaining_words = 0;
2549 int bytes_returned = 0;
2550 int len;
2551 int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
2552 PNEGOTIATE_MESSAGE SecurityBlob;
2553 PCHALLENGE_MESSAGE SecurityBlob2;
2554 __u32 negotiate_flags, capabilities;
2555 __u16 count;
2556
Steve French12b3b8f2006-02-09 21:12:47 +00002557 cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002558 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559 return -EINVAL;
2560 domain = ses->domainName;
2561 *pNTLMv2_flag = FALSE;
2562 smb_buffer = cifs_buf_get();
2563 if (smb_buffer == NULL) {
2564 return -ENOMEM;
2565 }
2566 smb_buffer_response = smb_buffer;
2567 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2568 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2569
2570 /* send SMBsessionSetup here */
2571 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2572 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002573
2574 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2576 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2577
2578 pSMB->req.AndXCommand = 0xFF;
2579 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2580 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2581
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002582 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2584
2585 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2586 CAP_EXTENDED_SECURITY;
2587 if (ses->capabilities & CAP_UNICODE) {
2588 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2589 capabilities |= CAP_UNICODE;
2590 }
2591 if (ses->capabilities & CAP_STATUS32) {
2592 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2593 capabilities |= CAP_STATUS32;
2594 }
2595 if (ses->capabilities & CAP_DFS) {
2596 smb_buffer->Flags2 |= SMBFLG2_DFS;
2597 capabilities |= CAP_DFS;
2598 }
2599 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2600
2601 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2602 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2603 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2604 SecurityBlob->MessageType = NtLmNegotiate;
2605 negotiate_flags =
2606 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
Steve French12b3b8f2006-02-09 21:12:47 +00002607 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
2608 NTLMSSP_NEGOTIATE_56 |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002610 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002612/* if (ntlmv2_support)
Steve French39798772006-05-31 22:40:51 +00002613 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 /* setup pointers to domain name and workstation name */
2615 bcc_ptr += SecurityBlobLength;
2616
2617 SecurityBlob->WorkstationName.Buffer = 0;
2618 SecurityBlob->WorkstationName.Length = 0;
2619 SecurityBlob->WorkstationName.MaximumLength = 0;
2620
Steve French12b3b8f2006-02-09 21:12:47 +00002621 /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent
2622 along with username on auth request (ie the response to challenge) */
2623 SecurityBlob->DomainName.Buffer = 0;
2624 SecurityBlob->DomainName.Length = 0;
2625 SecurityBlob->DomainName.MaximumLength = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626 if (ses->capabilities & CAP_UNICODE) {
2627 if ((long) bcc_ptr % 2) {
2628 *bcc_ptr = 0;
2629 bcc_ptr++;
2630 }
2631
2632 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002633 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634 32, nls_codepage);
2635 bcc_ptr += 2 * bytes_returned;
2636 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002637 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 nls_codepage);
2639 bcc_ptr += 2 * bytes_returned;
2640 bcc_ptr += 2; /* null terminate Linux version */
2641 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002642 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 64, nls_codepage);
2644 bcc_ptr += 2 * bytes_returned;
2645 *(bcc_ptr + 1) = 0;
2646 *(bcc_ptr + 2) = 0;
2647 bcc_ptr += 2; /* null terminate network opsys string */
2648 *(bcc_ptr + 1) = 0;
2649 *(bcc_ptr + 2) = 0;
2650 bcc_ptr += 2; /* null domain */
2651 } else { /* ASCII */
2652 strcpy(bcc_ptr, "Linux version ");
2653 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002654 strcpy(bcc_ptr, utsname()->release);
2655 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2657 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2658 bcc_ptr++; /* empty domain field */
2659 *bcc_ptr = 0;
2660 }
2661 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2662 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2663 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2664 smb_buffer->smb_buf_length += count;
2665 pSMB->req.ByteCount = cpu_to_le16(count);
2666
2667 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2668 &bytes_returned, 1);
2669
2670 if (smb_buffer_response->Status.CifsError ==
2671 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2672 rc = 0;
2673
2674 if (rc) {
2675/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2676 } else if ((smb_buffer_response->WordCount == 3)
2677 || (smb_buffer_response->WordCount == 4)) {
2678 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2679 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2680
2681 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002682 cFYI(1, (" Guest login"));
2683 /* Do we want to set anything in SesInfo struct when guest login? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684
Steve French50c2f752007-07-13 00:33:32 +00002685 bcc_ptr = pByteArea(smb_buffer_response);
2686 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687
2688 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2689 if (SecurityBlob2->MessageType != NtLmChallenge) {
2690 cFYI(1,
2691 ("Unexpected NTLMSSP message type received %d",
2692 SecurityBlob2->MessageType));
2693 } else if (ses) {
Steve French50c2f752007-07-13 00:33:32 +00002694 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
Steve French12b3b8f2006-02-09 21:12:47 +00002695 cFYI(1, ("UID = %d", ses->Suid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696 if ((pSMBr->resp.hdr.WordCount == 3)
2697 || ((pSMBr->resp.hdr.WordCount == 4)
2698 && (blob_len <
2699 pSMBr->resp.ByteCount))) {
2700
2701 if (pSMBr->resp.hdr.WordCount == 4) {
2702 bcc_ptr += blob_len;
Steve French12b3b8f2006-02-09 21:12:47 +00002703 cFYI(1, ("Security Blob Length %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 blob_len));
2705 }
2706
Steve French12b3b8f2006-02-09 21:12:47 +00002707 cFYI(1, ("NTLMSSP Challenge rcvd"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708
2709 memcpy(ses->server->cryptKey,
2710 SecurityBlob2->Challenge,
2711 CIFS_CRYPTO_KEY_SIZE);
Steve French50c2f752007-07-13 00:33:32 +00002712 if (SecurityBlob2->NegotiateFlags &
Steve French12b3b8f2006-02-09 21:12:47 +00002713 cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 *pNTLMv2_flag = TRUE;
2715
Steve French50c2f752007-07-13 00:33:32 +00002716 if ((SecurityBlob2->NegotiateFlags &
2717 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 || (sign_CIFS_PDUs > 1))
Steve French50c2f752007-07-13 00:33:32 +00002719 ses->server->secMode |=
2720 SECMODE_SIGN_REQUIRED;
2721 if ((SecurityBlob2->NegotiateFlags &
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
Steve French50c2f752007-07-13 00:33:32 +00002723 ses->server->secMode |=
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 SECMODE_SIGN_ENABLED;
2725
2726 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2727 if ((long) (bcc_ptr) % 2) {
2728 remaining_words =
2729 (BCC(smb_buffer_response)
2730 - 1) / 2;
Steve French50c2f752007-07-13 00:33:32 +00002731 /* Must word align unicode strings */
2732 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 } else {
2734 remaining_words =
2735 BCC
2736 (smb_buffer_response) / 2;
2737 }
2738 len =
2739 UniStrnlen((wchar_t *) bcc_ptr,
2740 remaining_words - 1);
2741/* We look for obvious messed up bcc or strings in response so we do not go off
2742 the end since (at least) WIN2K and Windows XP have a major bug in not null
2743 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002744 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002745 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002747 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002749 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750 bcc_ptr, len,
2751 nls_codepage);
2752 bcc_ptr += 2 * (len + 1);
2753 remaining_words -= len + 1;
2754 ses->serverOS[2 * len] = 0;
2755 ses->serverOS[1 + (2 * len)] = 0;
2756 if (remaining_words > 0) {
2757 len = UniStrnlen((wchar_t *)
2758 bcc_ptr,
2759 remaining_words
2760 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002761 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002763 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 GFP_KERNEL);
2765 cifs_strfromUCS_le(ses->
2766 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002767 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 bcc_ptr,
2769 len,
2770 nls_codepage);
2771 bcc_ptr += 2 * (len + 1);
2772 ses->serverNOS[2 * len] = 0;
2773 ses->serverNOS[1 +
2774 (2 * len)] = 0;
2775 remaining_words -= len + 1;
2776 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00002777 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2778 /* last string not always null terminated
2779 (for e.g. for Windows XP & 2000) */
Steve Frenchcd49b492006-06-26 04:22:36 +00002780 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002782 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783 (len +
2784 1),
2785 GFP_KERNEL);
2786 cifs_strfromUCS_le
Steve Frenche89dc922005-11-11 15:18:19 -08002787 (ses->serverDomain,
2788 (__le16 *)bcc_ptr,
2789 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790 bcc_ptr +=
2791 2 * (len + 1);
Steve Frenche89dc922005-11-11 15:18:19 -08002792 ses->serverDomain[2*len]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793 = 0;
Steve Frenche89dc922005-11-11 15:18:19 -08002794 ses->serverDomain
2795 [1 + (2 * len)]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 = 0;
2797 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002798 else {
Steve Frenchcd49b492006-06-26 04:22:36 +00002799 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002801 kzalloc(2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002803 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804 } else { /* no room so create dummy domain and NOS string */
Steve Frenchcd49b492006-06-26 04:22:36 +00002805 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002807 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002808 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002810 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811 }
2812 } else { /* ASCII */
2813 len = strnlen(bcc_ptr, 1024);
2814 if (((long) bcc_ptr + len) - (long)
2815 pByteArea(smb_buffer_response)
2816 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002817 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002818 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002820 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821 GFP_KERNEL);
2822 strncpy(ses->serverOS,
2823 bcc_ptr, len);
2824
2825 bcc_ptr += len;
2826 bcc_ptr[0] = 0; /* null terminate string */
2827 bcc_ptr++;
2828
2829 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002830 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002832 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833 GFP_KERNEL);
2834 strncpy(ses->serverNOS, bcc_ptr, len);
2835 bcc_ptr += len;
2836 bcc_ptr[0] = 0;
2837 bcc_ptr++;
2838
2839 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002840 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002842 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +00002844 strncpy(ses->serverDomain,
2845 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846 bcc_ptr += len;
2847 bcc_ptr[0] = 0;
2848 bcc_ptr++;
2849 } else
2850 cFYI(1,
Steve French63135e02007-07-17 17:34:02 +00002851 ("field of length %d "
2852 "extends beyond end of smb",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853 len));
2854 }
2855 } else {
Steve French50c2f752007-07-13 00:33:32 +00002856 cERROR(1, ("Security Blob Length extends beyond"
2857 " end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858 }
2859 } else {
2860 cERROR(1, ("No session structure passed in."));
2861 }
2862 } else {
2863 cERROR(1,
Steve French5815449d2006-02-14 01:36:20 +00002864 (" Invalid Word count %d:",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 smb_buffer_response->WordCount));
2866 rc = -EIO;
2867 }
2868
2869 if (smb_buffer)
2870 cifs_buf_release(smb_buffer);
2871
2872 return rc;
2873}
2874static int
2875CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2876 char *ntlm_session_key, int ntlmv2_flag,
2877 const struct nls_table *nls_codepage)
2878{
2879 struct smb_hdr *smb_buffer;
2880 struct smb_hdr *smb_buffer_response;
2881 SESSION_SETUP_ANDX *pSMB;
2882 SESSION_SETUP_ANDX *pSMBr;
2883 char *bcc_ptr;
2884 char *user;
2885 char *domain;
2886 int rc = 0;
2887 int remaining_words = 0;
2888 int bytes_returned = 0;
2889 int len;
2890 int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2891 PAUTHENTICATE_MESSAGE SecurityBlob;
2892 __u32 negotiate_flags, capabilities;
2893 __u16 count;
2894
2895 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002896 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897 return -EINVAL;
2898 user = ses->userName;
2899 domain = ses->domainName;
2900 smb_buffer = cifs_buf_get();
2901 if (smb_buffer == NULL) {
2902 return -ENOMEM;
2903 }
2904 smb_buffer_response = smb_buffer;
2905 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2906 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2907
2908 /* send SMBsessionSetup here */
2909 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2910 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002911
2912 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2914 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2915 pSMB->req.AndXCommand = 0xFF;
2916 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2917 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2918
2919 pSMB->req.hdr.Uid = ses->Suid;
2920
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002921 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2923
2924 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2925 CAP_EXTENDED_SECURITY;
2926 if (ses->capabilities & CAP_UNICODE) {
2927 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2928 capabilities |= CAP_UNICODE;
2929 }
2930 if (ses->capabilities & CAP_STATUS32) {
2931 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2932 capabilities |= CAP_STATUS32;
2933 }
2934 if (ses->capabilities & CAP_DFS) {
2935 smb_buffer->Flags2 |= SMBFLG2_DFS;
2936 capabilities |= CAP_DFS;
2937 }
2938 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2939
2940 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2941 SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2942 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2943 SecurityBlob->MessageType = NtLmAuthenticate;
2944 bcc_ptr += SecurityBlobLength;
Steve French50c2f752007-07-13 00:33:32 +00002945 negotiate_flags =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2947 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2948 0x80000000 | NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002949 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002951 if (ntlmv2_flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2953
2954/* setup pointers to domain name and workstation name */
2955
2956 SecurityBlob->WorkstationName.Buffer = 0;
2957 SecurityBlob->WorkstationName.Length = 0;
2958 SecurityBlob->WorkstationName.MaximumLength = 0;
2959 SecurityBlob->SessionKey.Length = 0;
2960 SecurityBlob->SessionKey.MaximumLength = 0;
2961 SecurityBlob->SessionKey.Buffer = 0;
2962
2963 SecurityBlob->LmChallengeResponse.Length = 0;
2964 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2965 SecurityBlob->LmChallengeResponse.Buffer = 0;
2966
2967 SecurityBlob->NtChallengeResponse.Length =
Steve French7c7b25b2006-06-01 19:20:10 +00002968 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969 SecurityBlob->NtChallengeResponse.MaximumLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002970 cpu_to_le16(CIFS_SESS_KEY_SIZE);
2971 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972 SecurityBlob->NtChallengeResponse.Buffer =
2973 cpu_to_le32(SecurityBlobLength);
Steve French7c7b25b2006-06-01 19:20:10 +00002974 SecurityBlobLength += CIFS_SESS_KEY_SIZE;
2975 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976
2977 if (ses->capabilities & CAP_UNICODE) {
2978 if (domain == NULL) {
2979 SecurityBlob->DomainName.Buffer = 0;
2980 SecurityBlob->DomainName.Length = 0;
2981 SecurityBlob->DomainName.MaximumLength = 0;
2982 } else {
2983 __u16 len =
Steve Frenche89dc922005-11-11 15:18:19 -08002984 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985 nls_codepage);
2986 len *= 2;
2987 SecurityBlob->DomainName.MaximumLength =
2988 cpu_to_le16(len);
2989 SecurityBlob->DomainName.Buffer =
2990 cpu_to_le32(SecurityBlobLength);
2991 bcc_ptr += len;
2992 SecurityBlobLength += len;
2993 SecurityBlob->DomainName.Length =
2994 cpu_to_le16(len);
2995 }
2996 if (user == NULL) {
2997 SecurityBlob->UserName.Buffer = 0;
2998 SecurityBlob->UserName.Length = 0;
2999 SecurityBlob->UserName.MaximumLength = 0;
3000 } else {
3001 __u16 len =
Steve Frenche89dc922005-11-11 15:18:19 -08003002 cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003 nls_codepage);
3004 len *= 2;
3005 SecurityBlob->UserName.MaximumLength =
3006 cpu_to_le16(len);
3007 SecurityBlob->UserName.Buffer =
3008 cpu_to_le32(SecurityBlobLength);
3009 bcc_ptr += len;
3010 SecurityBlobLength += len;
3011 SecurityBlob->UserName.Length =
3012 cpu_to_le16(len);
3013 }
3014
Steve French63135e02007-07-17 17:34:02 +00003015 /* SecurityBlob->WorkstationName.Length =
3016 cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017 SecurityBlob->WorkstationName.Length *= 2;
Steve French63135e02007-07-17 17:34:02 +00003018 SecurityBlob->WorkstationName.MaximumLength =
3019 cpu_to_le16(SecurityBlob->WorkstationName.Length);
3020 SecurityBlob->WorkstationName.Buffer =
3021 cpu_to_le32(SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022 bcc_ptr += SecurityBlob->WorkstationName.Length;
3023 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
Steve French63135e02007-07-17 17:34:02 +00003024 SecurityBlob->WorkstationName.Length =
3025 cpu_to_le16(SecurityBlob->WorkstationName.Length); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026
3027 if ((long) bcc_ptr % 2) {
3028 *bcc_ptr = 0;
3029 bcc_ptr++;
3030 }
3031 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003032 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033 32, nls_codepage);
3034 bcc_ptr += 2 * bytes_returned;
3035 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003036 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037 nls_codepage);
3038 bcc_ptr += 2 * bytes_returned;
3039 bcc_ptr += 2; /* null term version string */
3040 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003041 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 64, nls_codepage);
3043 bcc_ptr += 2 * bytes_returned;
3044 *(bcc_ptr + 1) = 0;
3045 *(bcc_ptr + 2) = 0;
3046 bcc_ptr += 2; /* null terminate network opsys string */
3047 *(bcc_ptr + 1) = 0;
3048 *(bcc_ptr + 2) = 0;
3049 bcc_ptr += 2; /* null domain */
3050 } else { /* ASCII */
3051 if (domain == NULL) {
3052 SecurityBlob->DomainName.Buffer = 0;
3053 SecurityBlob->DomainName.Length = 0;
3054 SecurityBlob->DomainName.MaximumLength = 0;
3055 } else {
3056 __u16 len;
3057 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
3058 strncpy(bcc_ptr, domain, 63);
3059 len = strnlen(domain, 64);
3060 SecurityBlob->DomainName.MaximumLength =
3061 cpu_to_le16(len);
3062 SecurityBlob->DomainName.Buffer =
3063 cpu_to_le32(SecurityBlobLength);
3064 bcc_ptr += len;
3065 SecurityBlobLength += len;
3066 SecurityBlob->DomainName.Length = cpu_to_le16(len);
3067 }
3068 if (user == NULL) {
3069 SecurityBlob->UserName.Buffer = 0;
3070 SecurityBlob->UserName.Length = 0;
3071 SecurityBlob->UserName.MaximumLength = 0;
3072 } else {
3073 __u16 len;
3074 strncpy(bcc_ptr, user, 63);
3075 len = strnlen(user, 64);
3076 SecurityBlob->UserName.MaximumLength =
3077 cpu_to_le16(len);
3078 SecurityBlob->UserName.Buffer =
3079 cpu_to_le32(SecurityBlobLength);
3080 bcc_ptr += len;
3081 SecurityBlobLength += len;
3082 SecurityBlob->UserName.Length = cpu_to_le16(len);
3083 }
3084 /* BB fill in our workstation name if known BB */
3085
3086 strcpy(bcc_ptr, "Linux version ");
3087 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003088 strcpy(bcc_ptr, utsname()->release);
3089 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
3091 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
3092 bcc_ptr++; /* null domain */
3093 *bcc_ptr = 0;
3094 }
3095 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
3096 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
3097 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
3098 smb_buffer->smb_buf_length += count;
3099 pSMB->req.ByteCount = cpu_to_le16(count);
3100
3101 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
3102 &bytes_returned, 1);
3103 if (rc) {
3104/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
3105 } else if ((smb_buffer_response->WordCount == 3)
3106 || (smb_buffer_response->WordCount == 4)) {
3107 __u16 action = le16_to_cpu(pSMBr->resp.Action);
3108 __u16 blob_len =
3109 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
3110 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00003111 cFYI(1, (" Guest login")); /* BB Should we set anything
3112 in SesInfo struct ? */
3113/* if (SecurityBlob2->MessageType != NtLm??) {
3114 cFYI("Unexpected message type on auth response is %d"));
3115 } */
3116
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117 if (ses) {
3118 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003119 ("Check challenge UID %d vs auth response UID %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120 ses->Suid, smb_buffer_response->Uid));
Steve French50c2f752007-07-13 00:33:32 +00003121 /* UID left in wire format */
3122 ses->Suid = smb_buffer_response->Uid;
3123 bcc_ptr = pByteArea(smb_buffer_response);
3124 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125 if ((pSMBr->resp.hdr.WordCount == 3)
3126 || ((pSMBr->resp.hdr.WordCount == 4)
3127 && (blob_len <
3128 pSMBr->resp.ByteCount))) {
3129 if (pSMBr->resp.hdr.WordCount == 4) {
3130 bcc_ptr +=
3131 blob_len;
3132 cFYI(1,
3133 ("Security Blob Length %d ",
3134 blob_len));
3135 }
3136
3137 cFYI(1,
3138 ("NTLMSSP response to Authenticate "));
3139
3140 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3141 if ((long) (bcc_ptr) % 2) {
3142 remaining_words =
3143 (BCC(smb_buffer_response)
3144 - 1) / 2;
3145 bcc_ptr++; /* Unicode strings must be word aligned */
3146 } else {
3147 remaining_words = BCC(smb_buffer_response) / 2;
3148 }
3149 len =
3150 UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
3151/* We look for obvious messed up bcc or strings in response so we do not go off
3152 the end since (at least) WIN2K and Windows XP have a major bug in not null
3153 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003154 if (ses->serverOS)
Steve French08775832006-05-30 18:08:26 +00003155 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003157 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003159 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160 bcc_ptr, len,
3161 nls_codepage);
3162 bcc_ptr += 2 * (len + 1);
3163 remaining_words -= len + 1;
3164 ses->serverOS[2 * len] = 0;
3165 ses->serverOS[1 + (2 * len)] = 0;
3166 if (remaining_words > 0) {
3167 len = UniStrnlen((wchar_t *)
3168 bcc_ptr,
3169 remaining_words
3170 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00003171 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003173 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003174 GFP_KERNEL);
3175 cifs_strfromUCS_le(ses->
3176 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003177 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003178 bcc_ptr,
3179 len,
3180 nls_codepage);
3181 bcc_ptr += 2 * (len + 1);
3182 ses->serverNOS[2 * len] = 0;
3183 ses->serverNOS[1+(2*len)] = 0;
3184 remaining_words -= len + 1;
3185 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00003186 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003187 /* last string not always null terminated (e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003188 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003189 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003191 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192 (len +
3193 1),
3194 GFP_KERNEL);
3195 cifs_strfromUCS_le
3196 (ses->
3197 serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08003198 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199 bcc_ptr, len,
3200 nls_codepage);
3201 bcc_ptr +=
3202 2 * (len + 1);
3203 ses->
3204 serverDomain[2
3205 * len]
3206 = 0;
3207 ses->
3208 serverDomain[1
3209 +
3210 (2
3211 *
3212 len)]
3213 = 0;
3214 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003215 else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003216 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003217 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003218 ses->serverDomain = kzalloc(2,GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00003219 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220 } else { /* no room so create dummy domain and NOS string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003221 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003222 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003223 ses->serverDomain = kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00003224 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003225 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226 }
3227 } else { /* ASCII */
3228 len = strnlen(bcc_ptr, 1024);
Steve French50c2f752007-07-13 00:33:32 +00003229 if (((long) bcc_ptr + len) -
3230 (long) pByteArea(smb_buffer_response)
Steve French63135e02007-07-17 17:34:02 +00003231 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003232 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00003233 kfree(ses->serverOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003234 ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235 strncpy(ses->serverOS,bcc_ptr, len);
3236
3237 bcc_ptr += len;
3238 bcc_ptr[0] = 0; /* null terminate the string */
3239 bcc_ptr++;
3240
3241 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003242 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00003243 ses->serverNOS = kzalloc(len+1,
3244 GFP_KERNEL);
Steve French63135e02007-07-17 17:34:02 +00003245 strncpy(ses->serverNOS,
3246 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247 bcc_ptr += len;
3248 bcc_ptr[0] = 0;
3249 bcc_ptr++;
3250
3251 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003252 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003253 kfree(ses->serverDomain);
Steve French63135e02007-07-17 17:34:02 +00003254 ses->serverDomain =
3255 kzalloc(len+1,
3256 GFP_KERNEL);
3257 strncpy(ses->serverDomain,
3258 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003259 bcc_ptr += len;
3260 bcc_ptr[0] = 0;
3261 bcc_ptr++;
3262 } else
3263 cFYI(1,
Steve French63135e02007-07-17 17:34:02 +00003264 ("field of length %d "
3265 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266 len));
3267 }
3268 } else {
3269 cERROR(1,
Steve French63135e02007-07-17 17:34:02 +00003270 (" Security Blob extends beyond end "
3271 "of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003272 }
3273 } else {
3274 cERROR(1, ("No session structure passed in."));
3275 }
3276 } else {
3277 cERROR(1,
3278 (" Invalid Word count %d: ",
3279 smb_buffer_response->WordCount));
3280 rc = -EIO;
3281 }
3282
3283 if (smb_buffer)
3284 cifs_buf_release(smb_buffer);
3285
3286 return rc;
3287}
3288
3289int
3290CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3291 const char *tree, struct cifsTconInfo *tcon,
3292 const struct nls_table *nls_codepage)
3293{
3294 struct smb_hdr *smb_buffer;
3295 struct smb_hdr *smb_buffer_response;
3296 TCONX_REQ *pSMB;
3297 TCONX_RSP *pSMBr;
3298 unsigned char *bcc_ptr;
3299 int rc = 0;
3300 int length;
3301 __u16 count;
3302
3303 if (ses == NULL)
3304 return -EIO;
3305
3306 smb_buffer = cifs_buf_get();
3307 if (smb_buffer == NULL) {
3308 return -ENOMEM;
3309 }
3310 smb_buffer_response = smb_buffer;
3311
3312 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3313 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003314
3315 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316 smb_buffer->Uid = ses->Suid;
3317 pSMB = (TCONX_REQ *) smb_buffer;
3318 pSMBr = (TCONX_RSP *) smb_buffer_response;
3319
3320 pSMB->AndXCommand = 0xFF;
3321 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003322 bcc_ptr = &pSMB->Password[0];
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003323 if ((ses->server->secMode) & SECMODE_USER) {
Steve Frencheeac8042006-01-13 21:34:58 -08003324 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00003325 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08003326 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00003327 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08003328 } else {
Steve French7c7b25b2006-06-01 19:20:10 +00003329 pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08003330 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
3331 specified as required (when that support is added to
3332 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00003333 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08003334 by Samba (not sure whether other servers allow
3335 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00003336#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French50c2f752007-07-13 00:33:32 +00003337 if ((extended_security & CIFSSEC_MAY_LANMAN) &&
Steve French7c7b25b2006-06-01 19:20:10 +00003338 (ses->server->secType == LANMAN))
3339 calc_lanman_hash(ses, bcc_ptr);
3340 else
3341#endif /* CIFS_WEAK_PW_HASH */
Steve Frencheeac8042006-01-13 21:34:58 -08003342 SMBNTencrypt(ses->password,
3343 ses->server->cryptKey,
3344 bcc_ptr);
3345
Steve French7c7b25b2006-06-01 19:20:10 +00003346 bcc_ptr += CIFS_SESS_KEY_SIZE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003347 if (ses->capabilities & CAP_UNICODE) {
Steve French7c7b25b2006-06-01 19:20:10 +00003348 /* must align unicode strings */
3349 *bcc_ptr = 0; /* null byte password */
3350 bcc_ptr++;
3351 }
Steve Frencheeac8042006-01-13 21:34:58 -08003352 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353
Steve French50c2f752007-07-13 00:33:32 +00003354 if (ses->server->secMode &
Steve Frencha878fb22006-05-30 18:04:19 +00003355 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003356 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3357
3358 if (ses->capabilities & CAP_STATUS32) {
3359 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3360 }
3361 if (ses->capabilities & CAP_DFS) {
3362 smb_buffer->Flags2 |= SMBFLG2_DFS;
3363 }
3364 if (ses->capabilities & CAP_UNICODE) {
3365 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3366 length =
Steve French50c2f752007-07-13 00:33:32 +00003367 cifs_strtoUCS((__le16 *) bcc_ptr, tree,
3368 6 /* max utf8 char length in bytes */ *
Steve Frencha878fb22006-05-30 18:04:19 +00003369 (/* server len*/ + 256 /* share len */), nls_codepage);
3370 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371 bcc_ptr += 2; /* skip trailing null */
3372 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373 strcpy(bcc_ptr, tree);
3374 bcc_ptr += strlen(tree) + 1;
3375 }
3376 strcpy(bcc_ptr, "?????");
3377 bcc_ptr += strlen("?????");
3378 bcc_ptr += 1;
3379 count = bcc_ptr - &pSMB->Password[0];
3380 pSMB->hdr.smb_buf_length += count;
3381 pSMB->ByteCount = cpu_to_le16(count);
3382
3383 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
3384
3385 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3386 /* above now done in SendReceive */
3387 if ((rc == 0) && (tcon != NULL)) {
3388 tcon->tidStatus = CifsGood;
3389 tcon->tid = smb_buffer_response->Tid;
3390 bcc_ptr = pByteArea(smb_buffer_response);
3391 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
Steve French50c2f752007-07-13 00:33:32 +00003392 /* skip service field (NB: this field is always ASCII) */
3393 bcc_ptr += length + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3395 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3396 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3397 if ((bcc_ptr + (2 * length)) -
3398 pByteArea(smb_buffer_response) <=
3399 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003400 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003402 kzalloc(length + 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003403 cifs_strfromUCS_le(tcon->nativeFileSystem,
Steve Frenche89dc922005-11-11 15:18:19 -08003404 (__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405 length, nls_codepage);
3406 bcc_ptr += 2 * length;
3407 bcc_ptr[0] = 0; /* null terminate the string */
3408 bcc_ptr[1] = 0;
3409 bcc_ptr += 2;
3410 }
Steve French50c2f752007-07-13 00:33:32 +00003411 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412 } else {
3413 length = strnlen(bcc_ptr, 1024);
3414 if ((bcc_ptr + length) -
3415 pByteArea(smb_buffer_response) <=
3416 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003417 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003419 kzalloc(length + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420 strncpy(tcon->nativeFileSystem, bcc_ptr,
3421 length);
3422 }
Steve French50c2f752007-07-13 00:33:32 +00003423 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003425 if ((smb_buffer_response->WordCount == 3) ||
Steve French1a4e15a2006-10-12 21:33:51 +00003426 (smb_buffer_response->WordCount == 7))
3427 /* field is in same location */
Steve French39798772006-05-31 22:40:51 +00003428 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3429 else
3430 tcon->Flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3432 } else if ((rc == 0) && tcon == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00003433 /* all we need to save for IPC$ connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434 ses->ipc_tid = smb_buffer_response->Tid;
3435 }
3436
3437 if (smb_buffer)
3438 cifs_buf_release(smb_buffer);
3439 return rc;
3440}
3441
3442int
3443cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3444{
3445 int rc = 0;
3446 int xid;
3447 struct cifsSesInfo *ses = NULL;
3448 struct task_struct *cifsd_task;
Steve French50c2f752007-07-13 00:33:32 +00003449 char *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450
3451 xid = GetXid();
3452
3453 if (cifs_sb->tcon) {
3454 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3455 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3456 if (rc == -EBUSY) {
3457 FreeXid(xid);
3458 return 0;
3459 }
3460 tconInfoFree(cifs_sb->tcon);
3461 if ((ses) && (ses->server)) {
3462 /* save off task so we do not refer to ses later */
3463 cifsd_task = ses->server->tsk;
3464 cFYI(1, ("About to do SMBLogoff "));
3465 rc = CIFSSMBLogoff(xid, ses);
3466 if (rc == -EBUSY) {
3467 FreeXid(xid);
3468 return 0;
3469 } else if (rc == -ESHUTDOWN) {
Steve French467a8f82007-06-27 22:41:32 +00003470 cFYI(1, ("Waking up socket by sending signal"));
Steve Frenchf7f7c312007-05-24 02:29:51 +00003471 if (cifsd_task) {
Steve French50c2f752007-07-13 00:33:32 +00003472 force_sig(SIGKILL, cifsd_task);
Igor Mammedovaaf737a2007-04-03 19:16:43 +00003473 kthread_stop(cifsd_task);
Steve Frenchf1914012005-08-18 09:37:34 -07003474 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475 rc = 0;
3476 } /* else - we have an smb session
3477 left on this socket do not kill cifsd */
3478 } else
3479 cFYI(1, ("No session or bad tcon"));
3480 }
Steve French50c2f752007-07-13 00:33:32 +00003481
Linus Torvalds1da177e2005-04-16 15:20:36 -07003482 cifs_sb->tcon = NULL;
Steve French2fe87f02006-09-21 07:02:52 +00003483 tmp = cifs_sb->prepath;
3484 cifs_sb->prepathlen = 0;
3485 cifs_sb->prepath = NULL;
3486 kfree(tmp);
Nishanth Aravamudan041e0e32005-09-10 00:27:23 -07003487 if (ses)
3488 schedule_timeout_interruptible(msecs_to_jiffies(500));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003489 if (ses)
3490 sesInfoFree(ses);
3491
3492 FreeXid(xid);
Steve French50c2f752007-07-13 00:33:32 +00003493 return rc; /* BB check if we should always return zero here */
3494}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495
3496int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
Steve French50c2f752007-07-13 00:33:32 +00003497 struct nls_table *nls_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498{
3499 int rc = 0;
Steve French7c7b25b2006-06-01 19:20:10 +00003500 char ntlm_session_key[CIFS_SESS_KEY_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501 int ntlmv2_flag = FALSE;
Steve Frenchad009ac2005-04-28 22:41:05 -07003502 int first_time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503
3504 /* what if server changes its buffer size after dropping the session? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003505 if (pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003507 if (rc == -EAGAIN) /* retry only once on 1st time connection */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003508 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve French50c2f752007-07-13 00:33:32 +00003509 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003510 rc = -EHOSTDOWN;
3511 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003512 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003513 spin_lock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003514 if (pSesInfo->server->tcpStatus != CifsExiting)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515 pSesInfo->server->tcpStatus = CifsGood;
3516 else
3517 rc = -EHOSTDOWN;
3518 spin_unlock(&GlobalMid_Lock);
3519
3520 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003521 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522 }
3523 if (!rc) {
Steve French9ac00b72006-09-30 04:13:17 +00003524 pSesInfo->flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525 pSesInfo->capabilities = pSesInfo->server->capabilities;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003526 if (linuxExtEnabled == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003528 /* pSesInfo->sequence_number = 0;*/
Steve French50c2f752007-07-13 00:33:32 +00003529 cFYI(1,
3530 ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531 pSesInfo->server->secMode,
3532 pSesInfo->server->capabilities,
Steve French175ec9e2006-09-30 01:07:38 +00003533 pSesInfo->server->timeAdj));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003534 if (experimEnabled < 2)
Steve French39798772006-05-31 22:40:51 +00003535 rc = CIFS_SessSetup(xid, pSesInfo,
3536 first_time, nls_info);
Steve French189acaa2006-06-23 02:33:48 +00003537 else if (extended_security
Steve French50c2f752007-07-13 00:33:32 +00003538 && (pSesInfo->capabilities
Steve French175ec9e2006-09-30 01:07:38 +00003539 & CAP_EXTENDED_SECURITY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003540 && (pSesInfo->server->secType == NTLMSSP)) {
Steve French189acaa2006-06-23 02:33:48 +00003541 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542 } else if (extended_security
3543 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3544 && (pSesInfo->server->secType == RawNTLMSSP)) {
Steve French5815449d2006-02-14 01:36:20 +00003545 cFYI(1, ("NTLMSSP sesssetup"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3547 pSesInfo,
3548 &ntlmv2_flag,
3549 nls_info);
3550 if (!rc) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003551 if (ntlmv2_flag) {
Steve French50c2f752007-07-13 00:33:32 +00003552 char *v2_response;
Steve French467a8f82007-06-27 22:41:32 +00003553 cFYI(1, ("more secure NTLM ver2 hash"));
Steve French50c2f752007-07-13 00:33:32 +00003554 if (CalcNTLMv2_partial_mac_key(pSesInfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555 nls_info)) {
3556 rc = -ENOMEM;
3557 goto ss_err_exit;
3558 } else
3559 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003560 if (v2_response) {
Steve French50c2f752007-07-13 00:33:32 +00003561 CalcNTLMv2_response(pSesInfo,
3562 v2_response);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003563 /* if (first_time)
Steve French50c2f752007-07-13 00:33:32 +00003564 cifs_calculate_ntlmv2_mac_key(
3565 pSesInfo->server->mac_signing_key,
3566 response, ntlm_session_key,*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003567 kfree(v2_response);
3568 /* BB Put dummy sig in SessSetup PDU? */
3569 } else {
3570 rc = -ENOMEM;
3571 goto ss_err_exit;
3572 }
3573
3574 } else {
3575 SMBNTencrypt(pSesInfo->password,
3576 pSesInfo->server->cryptKey,
3577 ntlm_session_key);
3578
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003579 if (first_time)
Steve Frenchad009ac2005-04-28 22:41:05 -07003580 cifs_calculate_mac_key(
Steve Frenchb609f062007-07-09 07:55:14 +00003581 &pSesInfo->server->mac_signing_key,
Steve Frenchad009ac2005-04-28 22:41:05 -07003582 ntlm_session_key,
3583 pSesInfo->password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584 }
3585 /* for better security the weaker lanman hash not sent
3586 in AuthSessSetup so we no longer calculate it */
3587
3588 rc = CIFSNTLMSSPAuthSessSetup(xid,
3589 pSesInfo,
3590 ntlm_session_key,
3591 ntlmv2_flag,
3592 nls_info);
3593 }
3594 } else { /* old style NTLM 0.12 session setup */
3595 SMBNTencrypt(pSesInfo->password,
3596 pSesInfo->server->cryptKey,
3597 ntlm_session_key);
3598
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003599 if (first_time)
Steve Frenchad009ac2005-04-28 22:41:05 -07003600 cifs_calculate_mac_key(
Steve Frenchb609f062007-07-09 07:55:14 +00003601 &pSesInfo->server->mac_signing_key,
Steve Frenchad009ac2005-04-28 22:41:05 -07003602 ntlm_session_key, pSesInfo->password);
3603
Linus Torvalds1da177e2005-04-16 15:20:36 -07003604 rc = CIFSSessSetup(xid, pSesInfo,
3605 ntlm_session_key, nls_info);
3606 }
3607 if (rc) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003608 cERROR(1, ("Send error in SessSetup = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609 } else {
Steve French467a8f82007-06-27 22:41:32 +00003610 cFYI(1, ("CIFS Session Established successfully"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003611 pSesInfo->status = CifsGood;
3612 }
3613 }
3614ss_err_exit:
3615 return rc;
3616}
3617