blob: e93da7ad90023da625f304a752fc4db559be9b5f [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
Igor Mammedovaaf737a2007-04-03 19:16:43 +0000367 while (!kthread_should_stop()) {
Steve Frenchede13272005-08-30 20:10:14 -0700368 if (try_to_freeze())
369 continue;
Steve Frenchb8643e12005-04-28 22:41:07 -0700370 if (bigbuf == NULL) {
371 bigbuf = cifs_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000372 if (!bigbuf) {
373 cERROR(1, ("No memory for large SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700374 msleep(3000);
375 /* retry will check if exiting */
376 continue;
377 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000378 } else if (isLargeBuf) {
379 /* we are reusing a dirty large buf, clear its start */
Steve Frenchb8643e12005-04-28 22:41:07 -0700380 memset(bigbuf, 0, sizeof (struct smb_hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700382
383 if (smallbuf == NULL) {
384 smallbuf = cifs_small_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000385 if (!smallbuf) {
386 cERROR(1, ("No memory for SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700387 msleep(1000);
388 /* retry will check if exiting */
389 continue;
390 }
391 /* beginning of smb buffer is cleared in our buf_get */
392 } else /* if existing small buf clear beginning */
393 memset(smallbuf, 0, sizeof (struct smb_hdr));
394
395 isLargeBuf = FALSE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700396 isMultiRsp = FALSE;
Steve Frenchb8643e12005-04-28 22:41:07 -0700397 smb_buffer = smallbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 iov.iov_base = smb_buffer;
399 iov.iov_len = 4;
400 smb_msg.msg_control = NULL;
401 smb_msg.msg_controllen = 0;
402 length =
403 kernel_recvmsg(csocket, &smb_msg,
404 &iov, 1, 4, 0 /* BB see socket.h flags */);
405
Igor Mammedovaaf737a2007-04-03 19:16:43 +0000406 if ( kthread_should_stop() ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 break;
408 } else if (server->tcpStatus == CifsNeedReconnect) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000409 cFYI(1, ("Reconnect after server stopped responding"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 cifs_reconnect(server);
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000411 cFYI(1, ("call to reconnect done"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 csocket = server->ssocket;
413 continue;
414 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700415 msleep(1); /* minimum sleep to prevent looping
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 allowing socket to clear and app threads to set
417 tcpStatus CifsNeedReconnect if server hung */
418 continue;
419 } else if (length <= 0) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000420 if (server->tcpStatus == CifsNew) {
421 cFYI(1, ("tcp session abend after SMBnegprot"));
Steve French09d1db52005-04-28 22:41:08 -0700422 /* some servers kill the TCP session rather than
423 returning an SMB negprot error, in which
424 case reconnecting here is not going to help,
425 and so simply return error to mount */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 break;
427 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000428 if (!try_to_freeze() && (length == -EINTR)) {
Steve French467a8f82007-06-27 22:41:32 +0000429 cFYI(1, ("cifsd thread killed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 break;
431 }
Steve French467a8f82007-06-27 22:41:32 +0000432 cFYI(1, ("Reconnect after unexpected peek error %d",
Steve French57337e42005-04-28 22:41:10 -0700433 length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 cifs_reconnect(server);
435 csocket = server->ssocket;
436 wake_up(&server->response_q);
437 continue;
Steve French46810cb2005-04-28 22:41:09 -0700438 } else if (length < 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 cFYI(1,
Steve French57337e42005-04-28 22:41:10 -0700440 ("Frame under four bytes received (%d bytes long)",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 length));
442 cifs_reconnect(server);
443 csocket = server->ssocket;
444 wake_up(&server->response_q);
445 continue;
446 }
Steve French67010fb2005-04-28 22:41:09 -0700447
Steve French70ca7342005-09-22 16:32:06 -0700448 /* The right amount was read from socket - 4 bytes */
449 /* so we can now interpret the length field */
Steve French46810cb2005-04-28 22:41:09 -0700450
Steve French70ca7342005-09-22 16:32:06 -0700451 /* the first byte big endian of the length field,
452 is actually not part of the length but the type
453 with the most common, zero, as regular data */
454 temp = *((char *) smb_buffer);
455
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000456 /* Note that FC 1001 length is big endian on the wire,
Steve French70ca7342005-09-22 16:32:06 -0700457 but we convert it here so it is always manipulated
458 as host byte order */
Steve French46810cb2005-04-28 22:41:09 -0700459 pdu_length = ntohl(smb_buffer->smb_buf_length);
Steve French70ca7342005-09-22 16:32:06 -0700460 smb_buffer->smb_buf_length = pdu_length;
Steve French46810cb2005-04-28 22:41:09 -0700461
Steve French467a8f82007-06-27 22:41:32 +0000462 cFYI(1, ("rfc1002 length 0x%x", pdu_length+4));
Steve French70ca7342005-09-22 16:32:06 -0700463
464 if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000465 continue;
Steve French70ca7342005-09-22 16:32:06 -0700466 } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
Steve French467a8f82007-06-27 22:41:32 +0000467 cFYI(1, ("Good RFC 1002 session rsp"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700468 continue;
Steve French70ca7342005-09-22 16:32:06 -0700469 } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000470 /* we get this from Windows 98 instead of
Steve French46810cb2005-04-28 22:41:09 -0700471 an error on SMB negprot response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000472 cFYI(1, ("Negative RFC1002 Session Response Error 0x%x)",
Steve French70ca7342005-09-22 16:32:06 -0700473 pdu_length));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000474 if (server->tcpStatus == CifsNew) {
475 /* if nack on negprot (rather than
Steve French46810cb2005-04-28 22:41:09 -0700476 ret of smb negprot error) reconnecting
477 not going to help, ret error to mount */
478 break;
479 } else {
480 /* give server a second to
481 clean up before reconnect attempt */
482 msleep(1000);
483 /* always try 445 first on reconnect
484 since we get NACK on some if we ever
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000485 connected to port 139 (the NACK is
Steve French46810cb2005-04-28 22:41:09 -0700486 since we do not begin with RFC1001
487 session initialize frame) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000488 server->addr.sockAddr.sin_port =
Steve French46810cb2005-04-28 22:41:09 -0700489 htons(CIFS_PORT);
490 cifs_reconnect(server);
491 csocket = server->ssocket;
492 wake_up(&server->response_q);
493 continue;
494 }
Steve French70ca7342005-09-22 16:32:06 -0700495 } else if (temp != (char) 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000496 cERROR(1, ("Unknown RFC 1002 frame"));
Steve French70ca7342005-09-22 16:32:06 -0700497 cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
498 length);
Steve French46810cb2005-04-28 22:41:09 -0700499 cifs_reconnect(server);
500 csocket = server->ssocket;
501 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700502 }
503
504 /* else we have an SMB response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000505 if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French46810cb2005-04-28 22:41:09 -0700506 (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700507 cERROR(1, ("Invalid size SMB length %d pdu_length %d",
Steve French46810cb2005-04-28 22:41:09 -0700508 length, pdu_length+4));
Steve Frenche4eb2952005-04-28 22:41:09 -0700509 cifs_reconnect(server);
510 csocket = server->ssocket;
511 wake_up(&server->response_q);
512 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000513 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700514
515 /* else length ok */
516 reconnect = 0;
517
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000518 if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700519 isLargeBuf = TRUE;
520 memcpy(bigbuf, smallbuf, 4);
521 smb_buffer = bigbuf;
522 }
523 length = 0;
524 iov.iov_base = 4 + (char *)smb_buffer;
525 iov.iov_len = pdu_length;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000526 for (total_read = 0; total_read < pdu_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700527 total_read += length) {
528 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
529 pdu_length - total_read, 0);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000530 if ( kthread_should_stop() ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700531 (length == -EINTR)) {
532 /* then will exit */
533 reconnect = 2;
534 break;
535 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700536 cifs_reconnect(server);
537 csocket = server->ssocket;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000538 /* Reconnect wakes up rspns q */
Steve Frenche4eb2952005-04-28 22:41:09 -0700539 /* Now we will reread sock */
540 reconnect = 1;
541 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000542 } else if ((length == -ERESTARTSYS) ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700543 (length == -EAGAIN)) {
544 msleep(1); /* minimum sleep to prevent looping,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000545 allowing socket to clear and app
Steve Frenche4eb2952005-04-28 22:41:09 -0700546 threads to set tcpStatus
547 CifsNeedReconnect if server hung*/
Steve French46810cb2005-04-28 22:41:09 -0700548 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700549 } else if (length <= 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000550 cERROR(1, ("Received no data, expecting %d",
Steve Frenche4eb2952005-04-28 22:41:09 -0700551 pdu_length - total_read));
552 cifs_reconnect(server);
553 csocket = server->ssocket;
554 reconnect = 1;
555 break;
Steve French46810cb2005-04-28 22:41:09 -0700556 }
557 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000558 if (reconnect == 2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700559 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000560 else if (reconnect == 1)
Steve Frenche4eb2952005-04-28 22:41:09 -0700561 continue;
562
563 length += 4; /* account for rfc1002 hdr */
Steve French50c2f752007-07-13 00:33:32 +0000564
Steve Frenche4eb2952005-04-28 22:41:09 -0700565
566 dump_smb(smb_buffer, length);
Steve French184ed212006-02-24 06:15:11 +0000567 if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700568 cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
Steve Frenche4eb2952005-04-28 22:41:09 -0700569 continue;
570 }
571
572
573 task_to_wake = NULL;
574 spin_lock(&GlobalMid_Lock);
575 list_for_each(tmp, &server->pending_mid_q) {
576 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
577
Steve French50c2f752007-07-13 00:33:32 +0000578 if ((mid_entry->mid == smb_buffer->Mid) &&
Steve Frenche4eb2952005-04-28 22:41:09 -0700579 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
580 (mid_entry->command == smb_buffer->Command)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000581 if (check2ndT2(smb_buffer,server->maxBuf) > 0) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700582 /* We have a multipart transact2 resp */
Steve Frenchcd634992005-04-28 22:41:10 -0700583 isMultiRsp = TRUE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000584 if (mid_entry->resp_buf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700585 /* merge response - fix up 1st*/
Steve French50c2f752007-07-13 00:33:32 +0000586 if (coalesce_t2(smb_buffer,
Steve Frenche4eb2952005-04-28 22:41:09 -0700587 mid_entry->resp_buf)) {
Steve French39798772006-05-31 22:40:51 +0000588 mid_entry->multiRsp = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700589 break;
590 } else {
591 /* all parts received */
Steve French39798772006-05-31 22:40:51 +0000592 mid_entry->multiEnd = 1;
Steve French50c2f752007-07-13 00:33:32 +0000593 goto multi_t2_fnd;
Steve Frenche4eb2952005-04-28 22:41:09 -0700594 }
595 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000596 if (!isLargeBuf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700597 cERROR(1,("1st trans2 resp needs bigbuf"));
598 /* BB maybe we can fix this up, switch
Steve French50c2f752007-07-13 00:33:32 +0000599 to already allocated large buffer? */
Steve Frenche4eb2952005-04-28 22:41:09 -0700600 } else {
Steve Frenchcd634992005-04-28 22:41:10 -0700601 /* Have first buffer */
Steve Frenche4eb2952005-04-28 22:41:09 -0700602 mid_entry->resp_buf =
603 smb_buffer;
604 mid_entry->largeBuf = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700605 bigbuf = NULL;
606 }
607 }
608 break;
Steve French50c2f752007-07-13 00:33:32 +0000609 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700610 mid_entry->resp_buf = smb_buffer;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000611 if (isLargeBuf)
Steve Frenche4eb2952005-04-28 22:41:09 -0700612 mid_entry->largeBuf = 1;
613 else
614 mid_entry->largeBuf = 0;
615multi_t2_fnd:
616 task_to_wake = mid_entry->tsk;
617 mid_entry->midState = MID_RESPONSE_RECEIVED;
Steve French1047abc2005-10-11 19:58:06 -0700618#ifdef CONFIG_CIFS_STATS2
619 mid_entry->when_received = jiffies;
620#endif
Steve French3a5ff612006-07-14 22:37:11 +0000621 /* so we do not time out requests to server
622 which is still responding (since server could
623 be busy but not dead) */
624 server->lstrp = jiffies;
Steve Frenche4eb2952005-04-28 22:41:09 -0700625 break;
626 }
627 }
628 spin_unlock(&GlobalMid_Lock);
629 if (task_to_wake) {
Steve Frenchcd634992005-04-28 22:41:10 -0700630 /* Was previous buf put in mpx struct for multi-rsp? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000631 if (!isMultiRsp) {
Steve Frenchcd634992005-04-28 22:41:10 -0700632 /* smb buffer will be freed by user thread */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000633 if (isLargeBuf) {
Steve Frenchcd634992005-04-28 22:41:10 -0700634 bigbuf = NULL;
635 } else
636 smallbuf = NULL;
637 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700638 wake_up_process(task_to_wake);
Steve Frenchd7c8c942006-03-03 10:43:49 +0000639 } else if ((is_valid_oplock_break(smb_buffer, server) == FALSE)
Steve French50c2f752007-07-13 00:33:32 +0000640 && (isMultiRsp == FALSE)) {
641 cERROR(1, ("No task to wake, unknown frame received! "
642 "NumMids %d", midCount.counter));
643 cifs_dump_mem("Received Data is: ", (char *)smb_buffer,
Steve French70ca7342005-09-22 16:32:06 -0700644 sizeof(struct smb_hdr));
Steve French39798772006-05-31 22:40:51 +0000645#ifdef CONFIG_CIFS_DEBUG2
646 cifs_dump_detail(smb_buffer);
647 cifs_dump_mids(server);
648#endif /* CIFS_DEBUG2 */
Steve French50c2f752007-07-13 00:33:32 +0000649
Steve Frenche4eb2952005-04-28 22:41:09 -0700650 }
651 } /* end while !EXITING */
652
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 spin_lock(&GlobalMid_Lock);
654 server->tcpStatus = CifsExiting;
655 server->tsk = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700656 /* check if we have blocked requests that need to free */
657 /* Note that cifs_max_pending is normally 50, but
658 can be set at module install time to as little as two */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000659 if (atomic_read(&server->inFlight) >= cifs_max_pending)
Steve French31ca3bc2005-04-28 22:41:11 -0700660 atomic_set(&server->inFlight, cifs_max_pending - 1);
661 /* We do not want to set the max_pending too low or we
662 could end up with the counter going negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +0000664 /* Although there should not be any requests blocked on
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700666 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 to the same server - they now will see the session is in exit state
668 and get out of SendReceive. */
669 wake_up_all(&server->request_q);
670 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700671 msleep(125);
Steve French50c2f752007-07-13 00:33:32 +0000672
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000673 if (server->ssocket) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 sock_release(csocket);
675 server->ssocket = NULL;
676 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700677 /* buffer usuallly freed in free_mid - need to free it here on exit */
678 if (bigbuf != NULL)
679 cifs_buf_release(bigbuf);
680 if (smallbuf != NULL)
681 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682
683 read_lock(&GlobalSMBSeslock);
684 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700685 /* loop through server session structures attached to this and
686 mark them dead */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 list_for_each(tmp, &GlobalSMBSessionList) {
688 ses =
689 list_entry(tmp, struct cifsSesInfo,
690 cifsSessionList);
691 if (ses->server == server) {
692 ses->status = CifsExiting;
693 ses->server = NULL;
694 }
695 }
696 read_unlock(&GlobalSMBSeslock);
697 } else {
Steve French31ca3bc2005-04-28 22:41:11 -0700698 /* although we can not zero the server struct pointer yet,
699 since there are active requests which may depnd on them,
700 mark the corresponding SMB sessions as exiting too */
701 list_for_each(tmp, &GlobalSMBSessionList) {
702 ses = list_entry(tmp, struct cifsSesInfo,
703 cifsSessionList);
704 if (ses->server == server) {
705 ses->status = CifsExiting;
706 }
707 }
708
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 spin_lock(&GlobalMid_Lock);
710 list_for_each(tmp, &server->pending_mid_q) {
711 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
712 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French50c2f752007-07-13 00:33:32 +0000713 cFYI(1, ("Clearing Mid 0x%x - waking up ",
714 mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 task_to_wake = mid_entry->tsk;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000716 if (task_to_wake) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 wake_up_process(task_to_wake);
718 }
719 }
720 }
721 spin_unlock(&GlobalMid_Lock);
722 read_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700724 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 }
726
Steve Frenchf1914012005-08-18 09:37:34 -0700727 if (!list_empty(&server->pending_mid_q)) {
Steve French50c2f752007-07-13 00:33:32 +0000728 /* mpx threads have not exited yet give them
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700730 /* due to delays on oplock break requests, we need
731 to wait at least 45 seconds before giving up
732 on a request getting a response and going ahead
733 and killing cifsd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve French31ca3bc2005-04-28 22:41:11 -0700735 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 /* if threads still have not exited they are probably never
737 coming home not much else we can do but free the memory */
738 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739
740 write_lock(&GlobalSMBSeslock);
741 atomic_dec(&tcpSesAllocCount);
742 length = tcpSesAllocCount.counter;
Steve French31ca3bc2005-04-28 22:41:11 -0700743
744 /* last chance to mark ses pointers invalid
745 if there are any pointing to this (e.g
Steve French50c2f752007-07-13 00:33:32 +0000746 if a crazy root user tried to kill cifsd
Steve French31ca3bc2005-04-28 22:41:11 -0700747 kernel thread explicitly this might happen) */
748 list_for_each(tmp, &GlobalSMBSessionList) {
749 ses = list_entry(tmp, struct cifsSesInfo,
750 cifsSessionList);
751 if (ses->server == server) {
752 ses->server = NULL;
753 }
754 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 write_unlock(&GlobalSMBSeslock);
Steve French31ca3bc2005-04-28 22:41:11 -0700756
757 kfree(server);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000758 if (length > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 mempool_resize(cifs_req_poolp,
760 length + cifs_min_rcv,
761 GFP_KERNEL);
762 }
Steve French50c2f752007-07-13 00:33:32 +0000763
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 return 0;
765}
766
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767static int
Steve French50c2f752007-07-13 00:33:32 +0000768cifs_parse_mount_options(char *options, const char *devname,
769 struct smb_vol *vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770{
771 char *value;
772 char *data;
773 unsigned int temp_len, i, j;
774 char separator[2];
775
776 separator[0] = ',';
Steve French50c2f752007-07-13 00:33:32 +0000777 separator[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778
Linus Torvalds12e36b22006-10-13 08:09:29 -0700779 if (Local_System_Name[0] != 0)
Steve French50c2f752007-07-13 00:33:32 +0000780 memcpy(vol->source_rfc1001_name, Local_System_Name, 15);
Steve French2cd646a2006-09-28 19:43:08 +0000781 else {
Linus Torvalds12e36b22006-10-13 08:09:29 -0700782 char *nodename = utsname()->nodename;
Steve French50c2f752007-07-13 00:33:32 +0000783 int n = strnlen(nodename, 15);
784 memset(vol->source_rfc1001_name, 0x20, 15);
785 for (i = 0; i < n; i++) {
Steve French2cd646a2006-09-28 19:43:08 +0000786 /* does not have to be perfect mapping since field is
787 informational, only used for servers that do not support
788 port 445 and it can be overridden at mount time */
Linus Torvalds12e36b22006-10-13 08:09:29 -0700789 vol->source_rfc1001_name[i] = toupper(nodename[i]);
Steve French2cd646a2006-09-28 19:43:08 +0000790 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 }
792 vol->source_rfc1001_name[15] = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -0700793 /* null target name indicates to use *SMBSERVR default called name
794 if we end up sending RFC1001 session initialize */
795 vol->target_rfc1001_name[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 vol->linux_uid = current->uid; /* current->euid instead? */
797 vol->linux_gid = current->gid;
798 vol->dir_mode = S_IRWXUGO;
799 /* 2767 perms indicate mandatory locking support */
800 vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);
801
802 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
803 vol->rw = TRUE;
Jeremy Allisonac670552005-06-22 17:26:35 -0700804 /* default is always to request posix paths. */
805 vol->posix_paths = 1;
806
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 if (!options)
808 return 1;
809
Steve French50c2f752007-07-13 00:33:32 +0000810 if (strncmp(options, "sep=", 4) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000811 if (options[4] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 separator[0] = options[4];
813 options += 5;
814 } else {
Steve French467a8f82007-06-27 22:41:32 +0000815 cFYI(1, ("Null separator not allowed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 }
817 }
Steve French50c2f752007-07-13 00:33:32 +0000818
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 while ((data = strsep(&options, separator)) != NULL) {
820 if (!*data)
821 continue;
822 if ((value = strchr(data, '=')) != NULL)
823 *value++ = '\0';
824
Steve French50c2f752007-07-13 00:33:32 +0000825 /* Have to parse this before we parse for "user" */
826 if (strnicmp(data, "user_xattr", 10) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 vol->no_xattr = 0;
Steve French50c2f752007-07-13 00:33:32 +0000828 } else if (strnicmp(data, "nouser_xattr", 12) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 vol->no_xattr = 1;
830 } else if (strnicmp(data, "user", 4) == 0) {
Steve French4b952a92006-10-30 21:46:13 +0000831 if (!value) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 printk(KERN_WARNING
833 "CIFS: invalid or missing username\n");
834 return 1; /* needs_arg; */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000835 } else if (!*value) {
Steve French4b952a92006-10-30 21:46:13 +0000836 /* null user, ie anonymous, authentication */
837 vol->nullauth = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 }
839 if (strnlen(value, 200) < 200) {
840 vol->username = value;
841 } else {
842 printk(KERN_WARNING "CIFS: username too long\n");
843 return 1;
844 }
845 } else if (strnicmp(data, "pass", 4) == 0) {
846 if (!value) {
847 vol->password = NULL;
848 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000849 } else if (value[0] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 /* check if string begins with double comma
851 since that would mean the password really
852 does start with a comma, and would not
853 indicate an empty string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000854 if (value[1] != separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 vol->password = NULL;
856 continue;
857 }
858 }
859 temp_len = strlen(value);
860 /* removed password length check, NTLM passwords
861 can be arbitrarily long */
862
Steve French50c2f752007-07-13 00:33:32 +0000863 /* if comma in password, the string will be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 prematurely null terminated. Commas in password are
865 specified across the cifs mount interface by a double
866 comma ie ,, and a comma used as in other cases ie ','
867 as a parameter delimiter/separator is single and due
868 to the strsep above is temporarily zeroed. */
869
870 /* NB: password legally can have multiple commas and
871 the only illegal character in a password is null */
872
Steve French50c2f752007-07-13 00:33:32 +0000873 if ((value[temp_len] == 0) &&
Steve French09d1db52005-04-28 22:41:08 -0700874 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 /* reinsert comma */
876 value[temp_len] = separator[0];
Steve French50c2f752007-07-13 00:33:32 +0000877 temp_len += 2; /* move after second comma */
878 while (value[temp_len] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 if (value[temp_len] == separator[0]) {
Steve French50c2f752007-07-13 00:33:32 +0000880 if (value[temp_len+1] ==
Steve French09d1db52005-04-28 22:41:08 -0700881 separator[0]) {
882 /* skip second comma */
883 temp_len++;
Steve French50c2f752007-07-13 00:33:32 +0000884 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 /* single comma indicating start
886 of next parm */
887 break;
888 }
889 }
890 temp_len++;
891 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000892 if (value[temp_len] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 options = NULL;
894 } else {
895 value[temp_len] = 0;
896 /* point option to start of next parm */
897 options = value + temp_len + 1;
898 }
Steve French50c2f752007-07-13 00:33:32 +0000899 /* go from value to value + temp_len condensing
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 double commas to singles. Note that this ends up
901 allocating a few bytes too many, which is ok */
Pekka Enberge915fc42005-09-06 15:18:35 -0700902 vol->password = kzalloc(temp_len, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000903 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000904 printk(KERN_WARNING "CIFS: no memory "
905 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700906 return 1;
907 }
Steve French50c2f752007-07-13 00:33:32 +0000908 for (i = 0, j = 0; i < temp_len; i++, j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 vol->password[j] = value[i];
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000910 if (value[i] == separator[0]
Steve French09d1db52005-04-28 22:41:08 -0700911 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 /* skip second comma */
913 i++;
914 }
915 }
916 vol->password[j] = 0;
917 } else {
Pekka Enberge915fc42005-09-06 15:18:35 -0700918 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000919 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000920 printk(KERN_WARNING "CIFS: no memory "
921 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700922 return 1;
923 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 strcpy(vol->password, value);
925 }
926 } else if (strnicmp(data, "ip", 2) == 0) {
927 if (!value || !*value) {
928 vol->UNCip = NULL;
929 } else if (strnlen(value, 35) < 35) {
930 vol->UNCip = value;
931 } else {
Steve French50c2f752007-07-13 00:33:32 +0000932 printk(KERN_WARNING "CIFS: ip address "
933 "too long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 return 1;
935 }
Steve French50c2f752007-07-13 00:33:32 +0000936 } else if (strnicmp(data, "sec", 3) == 0) {
937 if (!value || !*value) {
938 cERROR(1, ("no security value specified"));
939 continue;
940 } else if (strnicmp(value, "krb5i", 5) == 0) {
941 vol->secFlg |= CIFSSEC_MAY_KRB5 |
Steve French189acaa2006-06-23 02:33:48 +0000942 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800943 } else if (strnicmp(value, "krb5p", 5) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000944 /* vol->secFlg |= CIFSSEC_MUST_SEAL |
945 CIFSSEC_MAY_KRB5; */
946 cERROR(1, ("Krb5 cifs privacy not supported"));
Steve Frenchbf820672005-12-01 22:32:42 -0800947 return 1;
948 } else if (strnicmp(value, "krb5", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000949 vol->secFlg |= CIFSSEC_MAY_KRB5;
Steve Frenchbf820672005-12-01 22:32:42 -0800950 } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000951 vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
Steve French189acaa2006-06-23 02:33:48 +0000952 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800953 } else if (strnicmp(value, "ntlmv2", 6) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000954 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve Frenchbf820672005-12-01 22:32:42 -0800955 } else if (strnicmp(value, "ntlmi", 5) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000956 vol->secFlg |= CIFSSEC_MAY_NTLM |
Steve French189acaa2006-06-23 02:33:48 +0000957 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800958 } else if (strnicmp(value, "ntlm", 4) == 0) {
959 /* ntlm is default so can be turned off too */
Steve French750d1152006-06-27 06:28:30 +0000960 vol->secFlg |= CIFSSEC_MAY_NTLM;
Steve Frenchbf820672005-12-01 22:32:42 -0800961 } else if (strnicmp(value, "nontlm", 6) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000962 /* BB is there a better way to do this? */
Steve French750d1152006-06-27 06:28:30 +0000963 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve French189acaa2006-06-23 02:33:48 +0000964#ifdef CONFIG_CIFS_WEAK_PW_HASH
965 } else if (strnicmp(value, "lanman", 6) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000966 vol->secFlg |= CIFSSEC_MAY_LANMAN;
Steve French189acaa2006-06-23 02:33:48 +0000967#endif
Steve Frenchbf820672005-12-01 22:32:42 -0800968 } else if (strnicmp(value, "none", 4) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000969 vol->nullauth = 1;
Steve French50c2f752007-07-13 00:33:32 +0000970 } else {
971 cERROR(1, ("bad security option: %s", value));
972 return 1;
973 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 } else if ((strnicmp(data, "unc", 3) == 0)
975 || (strnicmp(data, "target", 6) == 0)
976 || (strnicmp(data, "path", 4) == 0)) {
977 if (!value || !*value) {
Steve French50c2f752007-07-13 00:33:32 +0000978 printk(KERN_WARNING "CIFS: invalid path to "
979 "network resource\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 return 1; /* needs_arg; */
981 }
982 if ((temp_len = strnlen(value, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +0000983 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +0000984 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 return 1;
Steve French50c2f752007-07-13 00:33:32 +0000986 strcpy(vol->UNC, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 if (strncmp(vol->UNC, "//", 2) == 0) {
988 vol->UNC[0] = '\\';
989 vol->UNC[1] = '\\';
Steve French50c2f752007-07-13 00:33:32 +0000990 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 printk(KERN_WARNING
Steve French50c2f752007-07-13 00:33:32 +0000992 "CIFS: UNC Path does not begin "
993 "with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 return 1;
995 }
996 } else {
997 printk(KERN_WARNING "CIFS: UNC name too long\n");
998 return 1;
999 }
1000 } else if ((strnicmp(data, "domain", 3) == 0)
1001 || (strnicmp(data, "workgroup", 5) == 0)) {
1002 if (!value || !*value) {
1003 printk(KERN_WARNING "CIFS: invalid domain name\n");
1004 return 1; /* needs_arg; */
1005 }
1006 /* BB are there cases in which a comma can be valid in
1007 a domain name and need special handling? */
Steve French39798772006-05-31 22:40:51 +00001008 if (strnlen(value, 256) < 256) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 vol->domainname = value;
1010 cFYI(1, ("Domain name set"));
1011 } else {
Steve French50c2f752007-07-13 00:33:32 +00001012 printk(KERN_WARNING "CIFS: domain name too "
1013 "long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 return 1;
1015 }
Steve French50c2f752007-07-13 00:33:32 +00001016 } else if (strnicmp(data, "prefixpath", 10) == 0) {
1017 if (!value || !*value) {
1018 printk(KERN_WARNING
1019 "CIFS: invalid path prefix\n");
1020 return 1; /* needs_argument */
1021 }
1022 if ((temp_len = strnlen(value, 1024)) < 1024) {
Steve French4523cc32007-04-30 20:13:06 +00001023 if (value[0] != '/')
Steve French2fe87f02006-09-21 07:02:52 +00001024 temp_len++; /* missing leading slash */
Steve French50c2f752007-07-13 00:33:32 +00001025 vol->prepath = kmalloc(temp_len+1, GFP_KERNEL);
1026 if (vol->prepath == NULL)
1027 return 1;
Steve French4523cc32007-04-30 20:13:06 +00001028 if (value[0] != '/') {
Steve French2fe87f02006-09-21 07:02:52 +00001029 vol->prepath[0] = '/';
Steve French50c2f752007-07-13 00:33:32 +00001030 strcpy(vol->prepath+1, value);
Steve French2fe87f02006-09-21 07:02:52 +00001031 } else
Steve French50c2f752007-07-13 00:33:32 +00001032 strcpy(vol->prepath, value);
1033 cFYI(1, ("prefix path %s", vol->prepath));
1034 } else {
1035 printk(KERN_WARNING "CIFS: prefix too long\n");
1036 return 1;
1037 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 } else if (strnicmp(data, "iocharset", 9) == 0) {
1039 if (!value || !*value) {
Steve French63135e02007-07-17 17:34:02 +00001040 printk(KERN_WARNING "CIFS: invalid iocharset "
1041 "specified\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 return 1; /* needs_arg; */
1043 }
1044 if (strnlen(value, 65) < 65) {
Steve French50c2f752007-07-13 00:33:32 +00001045 if (strnicmp(value, "default", 7))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 vol->iocharset = value;
Steve French50c2f752007-07-13 00:33:32 +00001047 /* if iocharset not set then load_nls_default
1048 is used by caller */
1049 cFYI(1, ("iocharset set to %s", value));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 } else {
Steve French63135e02007-07-17 17:34:02 +00001051 printk(KERN_WARNING "CIFS: iocharset name "
1052 "too long.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 return 1;
1054 }
1055 } else if (strnicmp(data, "uid", 3) == 0) {
1056 if (value && *value) {
1057 vol->linux_uid =
1058 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001059 vol->override_uid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 }
1061 } else if (strnicmp(data, "gid", 3) == 0) {
1062 if (value && *value) {
1063 vol->linux_gid =
1064 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001065 vol->override_gid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 }
1067 } else if (strnicmp(data, "file_mode", 4) == 0) {
1068 if (value && *value) {
1069 vol->file_mode =
1070 simple_strtoul(value, &value, 0);
1071 }
1072 } else if (strnicmp(data, "dir_mode", 4) == 0) {
1073 if (value && *value) {
1074 vol->dir_mode =
1075 simple_strtoul(value, &value, 0);
1076 }
1077 } else if (strnicmp(data, "dirmode", 4) == 0) {
1078 if (value && *value) {
1079 vol->dir_mode =
1080 simple_strtoul(value, &value, 0);
1081 }
1082 } else if (strnicmp(data, "port", 4) == 0) {
1083 if (value && *value) {
1084 vol->port =
1085 simple_strtoul(value, &value, 0);
1086 }
1087 } else if (strnicmp(data, "rsize", 5) == 0) {
1088 if (value && *value) {
1089 vol->rsize =
1090 simple_strtoul(value, &value, 0);
1091 }
1092 } else if (strnicmp(data, "wsize", 5) == 0) {
1093 if (value && *value) {
1094 vol->wsize =
1095 simple_strtoul(value, &value, 0);
1096 }
1097 } else if (strnicmp(data, "sockopt", 5) == 0) {
1098 if (value && *value) {
1099 vol->sockopt =
1100 simple_strtoul(value, &value, 0);
1101 }
1102 } else if (strnicmp(data, "netbiosname", 4) == 0) {
1103 if (!value || !*value || (*value == ' ')) {
Steve French63135e02007-07-17 17:34:02 +00001104 cFYI(1, ("invalid (empty) netbiosname"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 } else {
Steve French50c2f752007-07-13 00:33:32 +00001106 memset(vol->source_rfc1001_name, 0x20, 15);
1107 for (i = 0; i < 15; i++) {
1108 /* BB are there cases in which a comma can be
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 valid in this workstation netbios name (and need
1110 special handling)? */
1111
1112 /* We do not uppercase netbiosname for user */
Steve French50c2f752007-07-13 00:33:32 +00001113 if (value[i] == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 break;
Steve French50c2f752007-07-13 00:33:32 +00001115 else
1116 vol->source_rfc1001_name[i] =
1117 value[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 }
1119 /* The string has 16th byte zero still from
1120 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001121 if ((i == 15) && (value[i] != 0))
1122 printk(KERN_WARNING "CIFS: netbiosname"
1123 " longer than 15 truncated.\n");
Steve Frencha10faeb22005-08-22 21:38:31 -07001124 }
1125 } else if (strnicmp(data, "servern", 7) == 0) {
1126 /* servernetbiosname specified override *SMBSERVER */
1127 if (!value || !*value || (*value == ' ')) {
Steve French467a8f82007-06-27 22:41:32 +00001128 cFYI(1, ("empty server netbiosname specified"));
Steve Frencha10faeb22005-08-22 21:38:31 -07001129 } else {
1130 /* last byte, type, is 0x20 for servr type */
Steve French50c2f752007-07-13 00:33:32 +00001131 memset(vol->target_rfc1001_name, 0x20, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001132
Steve French50c2f752007-07-13 00:33:32 +00001133 for (i = 0; i < 15; i++) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001134 /* BB are there cases in which a comma can be
Steve French50c2f752007-07-13 00:33:32 +00001135 valid in this workstation netbios name
1136 (and need special handling)? */
Steve Frencha10faeb22005-08-22 21:38:31 -07001137
Steve French50c2f752007-07-13 00:33:32 +00001138 /* user or mount helper must uppercase
1139 the netbiosname */
1140 if (value[i] == 0)
Steve Frencha10faeb22005-08-22 21:38:31 -07001141 break;
1142 else
Steve French50c2f752007-07-13 00:33:32 +00001143 vol->target_rfc1001_name[i] =
1144 value[i];
Steve Frencha10faeb22005-08-22 21:38:31 -07001145 }
1146 /* The string has 16th byte zero still from
1147 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001148 if ((i == 15) && (value[i] != 0))
1149 printk(KERN_WARNING "CIFS: server net"
1150 "biosname longer than 15 truncated.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 }
1152 } else if (strnicmp(data, "credentials", 4) == 0) {
1153 /* ignore */
1154 } else if (strnicmp(data, "version", 3) == 0) {
1155 /* ignore */
Steve French50c2f752007-07-13 00:33:32 +00001156 } else if (strnicmp(data, "guest", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 /* ignore */
1158 } else if (strnicmp(data, "rw", 2) == 0) {
1159 vol->rw = TRUE;
1160 } else if ((strnicmp(data, "suid", 4) == 0) ||
1161 (strnicmp(data, "nosuid", 6) == 0) ||
1162 (strnicmp(data, "exec", 4) == 0) ||
1163 (strnicmp(data, "noexec", 6) == 0) ||
1164 (strnicmp(data, "nodev", 5) == 0) ||
1165 (strnicmp(data, "noauto", 6) == 0) ||
1166 (strnicmp(data, "dev", 3) == 0)) {
1167 /* The mount tool or mount.cifs helper (if present)
Steve French50c2f752007-07-13 00:33:32 +00001168 uses these opts to set flags, and the flags are read
1169 by the kernel vfs layer before we get here (ie
1170 before read super) so there is no point trying to
1171 parse these options again and set anything and it
1172 is ok to just ignore them */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 continue;
1174 } else if (strnicmp(data, "ro", 2) == 0) {
1175 vol->rw = FALSE;
1176 } else if (strnicmp(data, "hard", 4) == 0) {
1177 vol->retry = 1;
1178 } else if (strnicmp(data, "soft", 4) == 0) {
1179 vol->retry = 0;
1180 } else if (strnicmp(data, "perm", 4) == 0) {
1181 vol->noperm = 0;
1182 } else if (strnicmp(data, "noperm", 6) == 0) {
1183 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001184 } else if (strnicmp(data, "mapchars", 8) == 0) {
1185 vol->remap = 1;
1186 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1187 vol->remap = 0;
Steve French50c2f752007-07-13 00:33:32 +00001188 } else if (strnicmp(data, "sfu", 3) == 0) {
1189 vol->sfu_emul = 1;
1190 } else if (strnicmp(data, "nosfu", 5) == 0) {
1191 vol->sfu_emul = 0;
Jeremy Allisonac670552005-06-22 17:26:35 -07001192 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1193 vol->posix_paths = 1;
1194 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1195 vol->posix_paths = 0;
Steve Frenchc18c8422007-07-18 23:21:09 +00001196 } else if (strnicmp(data, "nounix", 6) == 0) {
1197 vol->no_linux_ext = 1;
1198 } else if (strnicmp(data, "nolinux", 7) == 0) {
1199 vol->no_linux_ext = 1;
Steve French50c2f752007-07-13 00:33:32 +00001200 } else if ((strnicmp(data, "nocase", 6) == 0) ||
Steve Frencha10faeb22005-08-22 21:38:31 -07001201 (strnicmp(data, "ignorecase", 10) == 0)) {
Steve French50c2f752007-07-13 00:33:32 +00001202 vol->nocase = 1;
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001203 } else if (strnicmp(data, "brl", 3) == 0) {
1204 vol->nobrl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001205 } else if ((strnicmp(data, "nobrl", 5) == 0) ||
Steve French1c955182005-08-30 20:58:07 -07001206 (strnicmp(data, "nolock", 6) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001207 vol->nobrl = 1;
Steve Frenchd3485d32005-08-19 11:04:29 -07001208 /* turn off mandatory locking in mode
1209 if remote locking is turned off since the
1210 local vfs will do advisory */
Steve French50c2f752007-07-13 00:33:32 +00001211 if (vol->file_mode ==
1212 (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
Steve Frenchd3485d32005-08-19 11:04:29 -07001213 vol->file_mode = S_IALLUGO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 } else if (strnicmp(data, "setuids", 7) == 0) {
1215 vol->setuids = 1;
1216 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1217 vol->setuids = 0;
1218 } else if (strnicmp(data, "nohard", 6) == 0) {
1219 vol->retry = 0;
1220 } else if (strnicmp(data, "nosoft", 6) == 0) {
1221 vol->retry = 1;
1222 } else if (strnicmp(data, "nointr", 6) == 0) {
1223 vol->intr = 0;
1224 } else if (strnicmp(data, "intr", 4) == 0) {
1225 vol->intr = 1;
Steve French50c2f752007-07-13 00:33:32 +00001226 } else if (strnicmp(data, "serverino", 7) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 vol->server_ino = 1;
Steve French50c2f752007-07-13 00:33:32 +00001228 } else if (strnicmp(data, "noserverino", 9) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 vol->server_ino = 0;
Steve French50c2f752007-07-13 00:33:32 +00001230 } else if (strnicmp(data, "cifsacl", 7) == 0) {
Steve French0a4b92c2006-01-12 15:44:21 -08001231 vol->cifs_acl = 1;
1232 } else if (strnicmp(data, "nocifsacl", 9) == 0) {
1233 vol->cifs_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001234 } else if (strnicmp(data, "acl", 3) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 vol->no_psx_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001236 } else if (strnicmp(data, "noacl", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 vol->no_psx_acl = 1;
Steve French50c2f752007-07-13 00:33:32 +00001238 } else if (strnicmp(data, "sign", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +00001239 vol->secFlg |= CIFSSEC_MUST_SIGN;
1240/* } else if (strnicmp(data, "seal",4) == 0) {
1241 vol->secFlg |= CIFSSEC_MUST_SEAL; */
Steve French50c2f752007-07-13 00:33:32 +00001242 } else if (strnicmp(data, "direct", 6) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001244 } else if (strnicmp(data, "forcedirectio", 13) == 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, "in6_addr", 8) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 if (!value || !*value) {
1248 vol->in6_addr = NULL;
1249 } else if (strnlen(value, 49) == 48) {
1250 vol->in6_addr = value;
1251 } else {
Steve French50c2f752007-07-13 00:33:32 +00001252 printk(KERN_WARNING "CIFS: ip v6 address not "
1253 "48 characters long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 return 1;
1255 }
1256 } else if (strnicmp(data, "noac", 4) == 0) {
Steve French50c2f752007-07-13 00:33:32 +00001257 printk(KERN_WARNING "CIFS: Mount option noac not "
1258 "supported. Instead set "
1259 "/proc/fs/cifs/LookupCacheEnabled to 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 } else
Steve French50c2f752007-07-13 00:33:32 +00001261 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",
1262 data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 }
1264 if (vol->UNC == NULL) {
Steve French4523cc32007-04-30 20:13:06 +00001265 if (devname == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001266 printk(KERN_WARNING "CIFS: Missing UNC name for mount "
1267 "target\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 return 1;
1269 }
1270 if ((temp_len = strnlen(devname, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001271 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001272 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001274 strcpy(vol->UNC, devname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 if (strncmp(vol->UNC, "//", 2) == 0) {
1276 vol->UNC[0] = '\\';
1277 vol->UNC[1] = '\\';
1278 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Steve French50c2f752007-07-13 00:33:32 +00001279 printk(KERN_WARNING "CIFS: UNC Path does not "
1280 "begin with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 return 1;
1282 }
1283 } else {
1284 printk(KERN_WARNING "CIFS: UNC name too long\n");
1285 return 1;
1286 }
1287 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001288 if (vol->UNCip == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 vol->UNCip = &vol->UNC[2];
1290
1291 return 0;
1292}
1293
1294static struct cifsSesInfo *
Steve French50c2f752007-07-13 00:33:32 +00001295cifs_find_tcp_session(struct in_addr *target_ip_addr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 struct in6_addr *target_ip6_addr,
1297 char *userName, struct TCP_Server_Info **psrvTcp)
1298{
1299 struct list_head *tmp;
1300 struct cifsSesInfo *ses;
1301 *psrvTcp = NULL;
1302 read_lock(&GlobalSMBSeslock);
1303
1304 list_for_each(tmp, &GlobalSMBSessionList) {
1305 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
1306 if (ses->server) {
Steve French50c2f752007-07-13 00:33:32 +00001307 if ((target_ip_addr &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 (ses->server->addr.sockAddr.sin_addr.s_addr
1309 == target_ip_addr->s_addr)) || (target_ip6_addr
1310 && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
Steve French50c2f752007-07-13 00:33:32 +00001311 target_ip6_addr, sizeof(*target_ip6_addr)))) {
1312 /* BB lock server and tcp session and increment
1313 use count here?? */
1314
1315 /* found a match on the TCP session */
1316 *psrvTcp = ses->server;
1317
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 /* BB check if reconnection needed */
1319 if (strncmp
1320 (ses->userName, userName,
1321 MAX_USERNAME_SIZE) == 0){
1322 read_unlock(&GlobalSMBSeslock);
Steve French50c2f752007-07-13 00:33:32 +00001323 /* Found exact match on both TCP and
1324 SMB sessions */
1325 return ses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 }
1327 }
1328 }
1329 /* else tcp and smb sessions need reconnection */
1330 }
1331 read_unlock(&GlobalSMBSeslock);
1332 return NULL;
1333}
1334
1335static struct cifsTconInfo *
1336find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
1337{
1338 struct list_head *tmp;
1339 struct cifsTconInfo *tcon;
1340
1341 read_lock(&GlobalSMBSeslock);
1342 list_for_each(tmp, &GlobalTreeConnectionList) {
Steve Frenche466e482006-08-15 13:07:18 +00001343 cFYI(1, ("Next tcon"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
1345 if (tcon->ses) {
1346 if (tcon->ses->server) {
1347 cFYI(1,
Steve Frenche466e482006-08-15 13:07:18 +00001348 ("old ip addr: %x == new ip %x ?",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 tcon->ses->server->addr.sockAddr.sin_addr.
1350 s_addr, new_target_ip_addr));
1351 if (tcon->ses->server->addr.sockAddr.sin_addr.
1352 s_addr == new_target_ip_addr) {
Steve Frenche466e482006-08-15 13:07:18 +00001353 /* BB lock tcon, server and tcp session and increment use count here? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 /* found a match on the TCP session */
1355 /* BB check if reconnection needed */
Steve French50c2f752007-07-13 00:33:32 +00001356 cFYI(1,
1357 ("IP match, old UNC: %s new: %s",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 tcon->treeName, uncName));
1359 if (strncmp
1360 (tcon->treeName, uncName,
1361 MAX_TREE_SIZE) == 0) {
1362 cFYI(1,
Steve Frenche466e482006-08-15 13:07:18 +00001363 ("and old usr: %s new: %s",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 tcon->treeName, uncName));
1365 if (strncmp
1366 (tcon->ses->userName,
1367 userName,
1368 MAX_USERNAME_SIZE) == 0) {
1369 read_unlock(&GlobalSMBSeslock);
Steve Frenche466e482006-08-15 13:07:18 +00001370 /* matched smb session
1371 (user name */
1372 return tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 }
1374 }
1375 }
1376 }
1377 }
1378 }
1379 read_unlock(&GlobalSMBSeslock);
1380 return NULL;
1381}
1382
1383int
1384connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
Steve French737b7582005-04-28 22:41:06 -07001385 const char *old_path, const struct nls_table *nls_codepage,
1386 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387{
1388 unsigned char *referrals = NULL;
1389 unsigned int num_referrals;
1390 int rc = 0;
1391
Steve French50c2f752007-07-13 00:33:32 +00001392 rc = get_dfs_path(xid, pSesInfo, old_path, nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001393 &num_referrals, &referrals, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394
1395 /* BB Add in code to: if valid refrl, if not ip address contact
Steve French50c2f752007-07-13 00:33:32 +00001396 the helper that resolves tcp names, mount to it, try to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 tcon to it unmount it if fail */
1398
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001399 kfree(referrals);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400
1401 return rc;
1402}
1403
1404int
Steve French50c2f752007-07-13 00:33:32 +00001405get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
1406 const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
1407 unsigned char **preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408{
1409 char *temp_unc;
1410 int rc = 0;
1411
1412 *pnum_referrals = 0;
1413
1414 if (pSesInfo->ipc_tid == 0) {
1415 temp_unc = kmalloc(2 /* for slashes */ +
Steve French50c2f752007-07-13 00:33:32 +00001416 strnlen(pSesInfo->serverName,
1417 SERVER_NAME_LEN_WITH_NULL * 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 + 1 + 4 /* slash IPC$ */ + 2,
1419 GFP_KERNEL);
1420 if (temp_unc == NULL)
1421 return -ENOMEM;
1422 temp_unc[0] = '\\';
1423 temp_unc[1] = '\\';
1424 strcpy(temp_unc + 2, pSesInfo->serverName);
1425 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1426 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1427 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00001428 ("CIFS Tcon rc = %d ipc_tid = %d", rc, pSesInfo->ipc_tid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429 kfree(temp_unc);
1430 }
1431 if (rc == 0)
1432 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001433 pnum_referrals, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434
1435 return rc;
1436}
1437
1438/* See RFC1001 section 14 on representation of Netbios names */
Steve French50c2f752007-07-13 00:33:32 +00001439static void rfc1002mangle(char *target, char *source, unsigned int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440{
Steve French50c2f752007-07-13 00:33:32 +00001441 unsigned int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442
Steve French50c2f752007-07-13 00:33:32 +00001443 for (i = 0, j = 0; i < (length); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 /* mask a nibble at a time and encode */
1445 target[j] = 'A' + (0x0F & (source[i] >> 4));
1446 target[j+1] = 'A' + (0x0F & source[i]);
Steve French50c2f752007-07-13 00:33:32 +00001447 j += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 }
1449
1450}
1451
1452
1453static int
Steve French50c2f752007-07-13 00:33:32 +00001454ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
1455 char *netbios_name, char *target_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456{
1457 int rc = 0;
1458 int connected = 0;
1459 __be16 orig_port = 0;
1460
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001461 if (*csocket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001462 rc = sock_create_kern(PF_INET, SOCK_STREAM,
1463 IPPROTO_TCP, csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001465 cERROR(1, ("Error %d creating socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 *csocket = NULL;
1467 return rc;
1468 } else {
1469 /* BB other socket options to set KEEPALIVE, NODELAY? */
Steve French467a8f82007-06-27 22:41:32 +00001470 cFYI(1, ("Socket created"));
Steve French50c2f752007-07-13 00:33:32 +00001471 (*csocket)->sk->sk_allocation = GFP_NOFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 }
1473 }
1474
1475 psin_server->sin_family = AF_INET;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001476 if (psin_server->sin_port) { /* user overrode default port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 rc = (*csocket)->ops->connect(*csocket,
1478 (struct sockaddr *) psin_server,
Steve French50c2f752007-07-13 00:33:32 +00001479 sizeof (struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 if (rc >= 0)
1481 connected = 1;
Steve French50c2f752007-07-13 00:33:32 +00001482 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001484 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001485 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 later if fall back ports fail this time */
1487 orig_port = psin_server->sin_port;
1488
1489 /* do not retry on the same port we just failed on */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001490 if (psin_server->sin_port != htons(CIFS_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 psin_server->sin_port = htons(CIFS_PORT);
1492
1493 rc = (*csocket)->ops->connect(*csocket,
1494 (struct sockaddr *) psin_server,
Steve French50c2f752007-07-13 00:33:32 +00001495 sizeof (struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 if (rc >= 0)
1497 connected = 1;
1498 }
1499 }
1500 if (!connected) {
1501 psin_server->sin_port = htons(RFC1001_PORT);
1502 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
Steve French50c2f752007-07-13 00:33:32 +00001503 psin_server,
1504 sizeof (struct sockaddr_in), 0);
1505 if (rc >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 connected = 1;
1507 }
1508
1509 /* give up here - unless we want to retry on different
1510 protocol families some day */
1511 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001512 if (orig_port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 psin_server->sin_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001514 cFYI(1, ("Error %d connecting to server via ipv4", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 sock_release(*csocket);
1516 *csocket = NULL;
1517 return rc;
1518 }
Steve French50c2f752007-07-13 00:33:32 +00001519 /* Eventually check for other socket options to change from
1520 the default. sock_setsockopt not used because it expects
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 user space buffer */
Steve French50c2f752007-07-13 00:33:32 +00001522 cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",
1523 (*csocket)->sk->sk_sndbuf,
Steve Frenchb387eae2005-10-10 14:21:15 -07001524 (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchb387eae2005-10-10 14:21:15 -07001526 /* make the bufsizes depend on wsize/rsize and max requests */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001527 if ((*csocket)->sk->sk_sndbuf < (200 * 1024))
Steve Frenchb387eae2005-10-10 14:21:15 -07001528 (*csocket)->sk->sk_sndbuf = 200 * 1024;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001529 if ((*csocket)->sk->sk_rcvbuf < (140 * 1024))
Steve Frenchb387eae2005-10-10 14:21:15 -07001530 (*csocket)->sk->sk_rcvbuf = 140 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531
1532 /* send RFC1001 sessinit */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001533 if (psin_server->sin_port == htons(RFC1001_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 /* some servers require RFC1001 sessinit before sending
Steve French50c2f752007-07-13 00:33:32 +00001535 negprot - BB check reconnection in case where second
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 sessinit is sent but no second negprot */
Steve French50c2f752007-07-13 00:33:32 +00001537 struct rfc1002_session_packet *ses_init_buf;
1538 struct smb_hdr *smb_buf;
1539 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
1540 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001541 if (ses_init_buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 ses_init_buf->trailer.session_req.called_len = 32;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001543 if (target_name && (target_name[0] != 0)) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001544 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1545 target_name, 16);
1546 } else {
1547 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
Steve French50c2f752007-07-13 00:33:32 +00001548 DEFAULT_CIFS_CALLED_NAME, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001549 }
1550
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 ses_init_buf->trailer.session_req.calling_len = 32;
1552 /* calling name ends in null (byte 16) from old smb
1553 convention. */
Steve French50c2f752007-07-13 00:33:32 +00001554 if (netbios_name && (netbios_name[0] != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
Steve French50c2f752007-07-13 00:33:32 +00001556 netbios_name, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 } else {
1558 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
Steve French50c2f752007-07-13 00:33:32 +00001559 "LINUX_CIFS_CLNT", 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 }
1561 ses_init_buf->trailer.session_req.scope1 = 0;
1562 ses_init_buf->trailer.session_req.scope2 = 0;
1563 smb_buf = (struct smb_hdr *)ses_init_buf;
1564 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1565 smb_buf->smb_buf_length = 0x81000044;
1566 rc = smb_send(*csocket, smb_buf, 0x44,
1567 (struct sockaddr *)psin_server);
1568 kfree(ses_init_buf);
Steve French50c2f752007-07-13 00:33:32 +00001569 msleep(1); /* RFC1001 layer in at least one server
Steve French083d3a22006-03-03 09:53:36 +00001570 requires very short break before negprot
1571 presumably because not expecting negprot
1572 to follow so fast. This is a simple
Steve French50c2f752007-07-13 00:33:32 +00001573 solution that works without
Steve French083d3a22006-03-03 09:53:36 +00001574 complicating the code and causes no
1575 significant slowing down on mount
1576 for everyone else */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 }
Steve French50c2f752007-07-13 00:33:32 +00001578 /* else the negprot may still work without this
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 even though malloc failed */
Steve French50c2f752007-07-13 00:33:32 +00001580
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 }
Steve French50c2f752007-07-13 00:33:32 +00001582
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 return rc;
1584}
1585
1586static int
1587ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1588{
1589 int rc = 0;
1590 int connected = 0;
1591 __be16 orig_port = 0;
1592
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001593 if (*csocket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001594 rc = sock_create_kern(PF_INET6, SOCK_STREAM,
1595 IPPROTO_TCP, csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001597 cERROR(1, ("Error %d creating ipv6 socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 *csocket = NULL;
1599 return rc;
1600 } else {
1601 /* BB other socket options to set KEEPALIVE, NODELAY? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001602 cFYI(1, ("ipv6 Socket created"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 (*csocket)->sk->sk_allocation = GFP_NOFS;
1604 }
1605 }
1606
1607 psin_server->sin6_family = AF_INET6;
1608
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001609 if (psin_server->sin6_port) { /* user overrode default port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 rc = (*csocket)->ops->connect(*csocket,
1611 (struct sockaddr *) psin_server,
Steve French50c2f752007-07-13 00:33:32 +00001612 sizeof (struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613 if (rc >= 0)
1614 connected = 1;
Steve French50c2f752007-07-13 00:33:32 +00001615 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001617 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001618 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 later if fall back ports fail this time */
1620
1621 orig_port = psin_server->sin6_port;
1622 /* do not retry on the same port we just failed on */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001623 if (psin_server->sin6_port != htons(CIFS_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 psin_server->sin6_port = htons(CIFS_PORT);
1625
1626 rc = (*csocket)->ops->connect(*csocket,
1627 (struct sockaddr *) psin_server,
Steve French50c2f752007-07-13 00:33:32 +00001628 sizeof (struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 if (rc >= 0)
1630 connected = 1;
1631 }
1632 }
1633 if (!connected) {
1634 psin_server->sin6_port = htons(RFC1001_PORT);
1635 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
Steve French50c2f752007-07-13 00:33:32 +00001636 psin_server, sizeof (struct sockaddr_in6), 0);
1637 if (rc >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 connected = 1;
1639 }
1640
1641 /* give up here - unless we want to retry on different
1642 protocol families some day */
1643 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001644 if (orig_port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 psin_server->sin6_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001646 cFYI(1, ("Error %d connecting to server via ipv6", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 sock_release(*csocket);
1648 *csocket = NULL;
1649 return rc;
1650 }
Steve French50c2f752007-07-13 00:33:32 +00001651 /* Eventually check for other socket options to change from
1652 the default. sock_setsockopt not used because it expects
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 user space buffer */
1654 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve French50c2f752007-07-13 00:33:32 +00001655
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 return rc;
1657}
1658
Steve French50c2f752007-07-13 00:33:32 +00001659void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
1660 struct super_block *sb, struct smb_vol *vol_info)
Steve French8af18972007-02-14 04:42:51 +00001661{
1662 /* if we are reconnecting then should we check to see if
1663 * any requested capabilities changed locally e.g. via
1664 * remount but we can not do much about it here
1665 * if they have (even if we could detect it by the following)
1666 * Perhaps we could add a backpointer to array of sb from tcon
1667 * or if we change to make all sb to same share the same
1668 * sb as NFS - then we only have one backpointer to sb.
1669 * What if we wanted to mount the server share twice once with
1670 * and once without posixacls or posix paths? */
1671 __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001672
Steve Frenchc18c8422007-07-18 23:21:09 +00001673 if (vol_info && vol_info->no_linux_ext) {
1674 tcon->fsUnixInfo.Capability = 0;
1675 tcon->unix_ext = 0; /* Unix Extensions disabled */
1676 cFYI(1, ("Linux protocol extensions disabled"));
1677 return;
1678 } else if (vol_info)
1679 tcon->unix_ext = 1; /* Unix Extensions supported */
1680
1681 if (tcon->unix_ext == 0) {
1682 cFYI(1, ("Unix extensions disabled so not set on reconnect"));
1683 return;
1684 }
Steve French50c2f752007-07-13 00:33:32 +00001685
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001686 if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
Steve French8af18972007-02-14 04:42:51 +00001687 __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001688
Steve French8af18972007-02-14 04:42:51 +00001689 /* check for reconnect case in which we do not
1690 want to change the mount behavior if we can avoid it */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001691 if (vol_info == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001692 /* turn off POSIX ACL and PATHNAMES if not set
Steve French8af18972007-02-14 04:42:51 +00001693 originally at mount time */
1694 if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
1695 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
1696 if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0)
1697 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French8af18972007-02-14 04:42:51 +00001698 }
Steve French50c2f752007-07-13 00:33:32 +00001699
Steve French8af18972007-02-14 04:42:51 +00001700 cap &= CIFS_UNIX_CAP_MASK;
Steve French75865f8c2007-06-24 18:30:48 +00001701 if (vol_info && vol_info->no_psx_acl)
Steve French8af18972007-02-14 04:42:51 +00001702 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00001703 else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001704 cFYI(1, ("negotiated posix acl support"));
1705 if (sb)
Steve French8af18972007-02-14 04:42:51 +00001706 sb->s_flags |= MS_POSIXACL;
1707 }
1708
Steve French75865f8c2007-06-24 18:30:48 +00001709 if (vol_info && vol_info->posix_paths == 0)
Steve French8af18972007-02-14 04:42:51 +00001710 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00001711 else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001712 cFYI(1, ("negotiate posix pathnames"));
Steve French75865f8c2007-06-24 18:30:48 +00001713 if (sb)
Steve French50c2f752007-07-13 00:33:32 +00001714 CIFS_SB(sb)->mnt_cifs_flags |=
Steve French8af18972007-02-14 04:42:51 +00001715 CIFS_MOUNT_POSIX_PATHS;
1716 }
Steve French50c2f752007-07-13 00:33:32 +00001717
Steve French984acfe2007-04-26 16:42:50 +00001718 /* We might be setting the path sep back to a different
1719 form if we are reconnecting and the server switched its
Steve French50c2f752007-07-13 00:33:32 +00001720 posix path capability for this share */
Steve French75865f8c2007-06-24 18:30:48 +00001721 if (sb && (CIFS_SB(sb)->prepathlen > 0))
Steve French984acfe2007-04-26 16:42:50 +00001722 CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
Steve French75865f8c2007-06-24 18:30:48 +00001723
1724 if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
1725 if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
1726 CIFS_SB(sb)->rsize = 127 * 1024;
1727#ifdef CONFIG_CIFS_DEBUG2
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001728 cFYI(1, ("larger reads not supported by srv"));
Steve French75865f8c2007-06-24 18:30:48 +00001729#endif
1730 }
1731 }
Steve French50c2f752007-07-13 00:33:32 +00001732
1733
1734 cFYI(1, ("Negotiate caps 0x%x", (int)cap));
Steve French8af18972007-02-14 04:42:51 +00001735#ifdef CONFIG_CIFS_DEBUG2
Steve French75865f8c2007-06-24 18:30:48 +00001736 if (cap & CIFS_UNIX_FCNTL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001737 cFYI(1, ("FCNTL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001738 if (cap & CIFS_UNIX_EXTATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001739 cFYI(1, ("EXTATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001740 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001741 cFYI(1, ("POSIX path cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001742 if (cap & CIFS_UNIX_XATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001743 cFYI(1, ("XATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001744 if (cap & CIFS_UNIX_POSIX_ACL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001745 cFYI(1, ("POSIX ACL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001746 if (cap & CIFS_UNIX_LARGE_READ_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001747 cFYI(1, ("very large read cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001748 if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001749 cFYI(1, ("very large write cap"));
Steve French8af18972007-02-14 04:42:51 +00001750#endif /* CIFS_DEBUG2 */
1751 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001752 cFYI(1, ("setting capabilities failed"));
Steve French8af18972007-02-14 04:42:51 +00001753 }
1754 }
1755}
1756
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757int
1758cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1759 char *mount_data, const char *devname)
1760{
1761 int rc = 0;
1762 int xid;
1763 int address_type = AF_INET;
1764 struct socket *csocket = NULL;
1765 struct sockaddr_in sin_server;
1766 struct sockaddr_in6 sin_server6;
1767 struct smb_vol volume_info;
1768 struct cifsSesInfo *pSesInfo = NULL;
1769 struct cifsSesInfo *existingCifsSes = NULL;
1770 struct cifsTconInfo *tcon = NULL;
1771 struct TCP_Server_Info *srvTcp = NULL;
1772
1773 xid = GetXid();
1774
1775/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
Steve French50c2f752007-07-13 00:33:32 +00001776
1777 memset(&volume_info, 0, sizeof(struct smb_vol));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001779 kfree(volume_info.UNC);
1780 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001781 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 FreeXid(xid);
1783 return -EINVAL;
1784 }
1785
Jeff Layton8426c392007-05-05 03:27:49 +00001786 if (volume_info.nullauth) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001787 cFYI(1, ("null user"));
Jeff Layton8426c392007-05-05 03:27:49 +00001788 volume_info.username = NULL;
1789 } else if (volume_info.username) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 /* BB fixme parse for domain name here */
Steve French467a8f82007-06-27 22:41:32 +00001791 cFYI(1, ("Username: %s", volume_info.username));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 } else {
Steve Frenchbf820672005-12-01 22:32:42 -08001793 cifserror("No username specified");
Steve French50c2f752007-07-13 00:33:32 +00001794 /* In userspace mount helper we can get user name from alternate
1795 locations such as env variables and files on disk */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001796 kfree(volume_info.UNC);
1797 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001798 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 FreeXid(xid);
1800 return -EINVAL;
1801 }
1802
1803 if (volume_info.UNCip && volume_info.UNC) {
Steve French50c2f752007-07-13 00:33:32 +00001804 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,
1805 &sin_server.sin_addr.s_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001807 if (rc <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 /* not ipv4 address, try ipv6 */
Steve French50c2f752007-07-13 00:33:32 +00001809 rc = cifs_inet_pton(AF_INET6, volume_info.UNCip,
1810 &sin_server6.sin6_addr.in6_u);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001811 if (rc > 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 address_type = AF_INET6;
1813 } else {
1814 address_type = AF_INET;
1815 }
Steve French50c2f752007-07-13 00:33:32 +00001816
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001817 if (rc <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 /* we failed translating address */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001819 kfree(volume_info.UNC);
1820 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001821 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 FreeXid(xid);
1823 return -EINVAL;
1824 }
1825
1826 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1827 /* success */
1828 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00001829 } else if (volume_info.UNCip) {
1830 /* BB using ip addr as server name to connect to the
1831 DFS root below */
1832 cERROR(1, ("Connecting to DFS root not implemented yet"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001833 kfree(volume_info.UNC);
1834 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001835 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 FreeXid(xid);
1837 return -EINVAL;
1838 } else /* which servers DFS root would we conect to */ {
1839 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00001840 ("CIFS mount error: No UNC path (e.g. -o "
1841 "unc=//192.168.1.100/public) specified"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001842 kfree(volume_info.UNC);
1843 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001844 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 FreeXid(xid);
1846 return -EINVAL;
1847 }
1848
1849 /* this is needed for ASCII cp to Unicode converts */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001850 if (volume_info.iocharset == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 cifs_sb->local_nls = load_nls_default();
1852 /* load_nls_default can not return null */
1853 } else {
1854 cifs_sb->local_nls = load_nls(volume_info.iocharset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001855 if (cifs_sb->local_nls == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001856 cERROR(1, ("CIFS mount error: iocharset %s not found",
1857 volume_info.iocharset));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001858 kfree(volume_info.UNC);
1859 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001860 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 FreeXid(xid);
1862 return -ELIBACC;
1863 }
1864 }
1865
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001866 if (address_type == AF_INET)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1868 NULL /* no ipv6 addr */,
1869 volume_info.username, &srvTcp);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001870 else if (address_type == AF_INET6) {
1871 cFYI(1, ("looking for ipv6 address"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1873 &sin_server6.sin6_addr,
1874 volume_info.username, &srvTcp);
Steve French5858ae42007-04-25 11:59:10 +00001875 } else {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001876 kfree(volume_info.UNC);
1877 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001878 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 FreeXid(xid);
1880 return -EINVAL;
1881 }
1882
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 if (srvTcp) {
Steve French50c2f752007-07-13 00:33:32 +00001884 cFYI(1, ("Existing tcp session with server found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 } else { /* create socket */
Steve French4523cc32007-04-30 20:13:06 +00001886 if (volume_info.port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 sin_server.sin_port = htons(volume_info.port);
1888 else
1889 sin_server.sin_port = 0;
Steve French5858ae42007-04-25 11:59:10 +00001890 if (address_type == AF_INET6) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001891 cFYI(1, ("attempting ipv6 connect"));
Steve French5858ae42007-04-25 11:59:10 +00001892 /* BB should we allow ipv6 on port 139? */
1893 /* other OS never observed in Wild doing 139 with v6 */
Steve French50c2f752007-07-13 00:33:32 +00001894 rc = ipv6_connect(&sin_server6, &csocket);
1895 } else
1896 rc = ipv4_connect(&sin_server, &csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -07001897 volume_info.source_rfc1001_name,
1898 volume_info.target_rfc1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001900 cERROR(1, ("Error connecting to IPv4 socket. "
1901 "Aborting operation"));
Steve French4523cc32007-04-30 20:13:06 +00001902 if (csocket != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001904 kfree(volume_info.UNC);
1905 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001906 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 FreeXid(xid);
1908 return rc;
1909 }
1910
1911 srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
1912 if (srvTcp == NULL) {
1913 rc = -ENOMEM;
1914 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001915 kfree(volume_info.UNC);
1916 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001917 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 FreeXid(xid);
1919 return rc;
1920 } else {
1921 memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
Steve French50c2f752007-07-13 00:33:32 +00001922 memcpy(&srvTcp->addr.sockAddr, &sin_server,
1923 sizeof (struct sockaddr_in));
1924 atomic_set(&srvTcp->inFlight, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 /* BB Add code for ipv6 case too */
1926 srvTcp->ssocket = csocket;
1927 srvTcp->protocolType = IPV4;
1928 init_waitqueue_head(&srvTcp->response_q);
1929 init_waitqueue_head(&srvTcp->request_q);
1930 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1931 /* at this point we are the only ones with the pointer
1932 to the struct since the kernel thread not created yet
1933 so no need to spinlock this init of tcpStatus */
1934 srvTcp->tcpStatus = CifsNew;
1935 init_MUTEX(&srvTcp->tcpSem);
Igor Mammedovaaf737a2007-04-03 19:16:43 +00001936 srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd");
Steve French4523cc32007-04-30 20:13:06 +00001937 if ( IS_ERR(srvTcp->tsk) ) {
Igor Mammedovaaf737a2007-04-03 19:16:43 +00001938 rc = PTR_ERR(srvTcp->tsk);
Steve French50c2f752007-07-13 00:33:32 +00001939 cERROR(1, ("error %d create cifsd thread", rc));
Igor Mammedovaaf737a2007-04-03 19:16:43 +00001940 srvTcp->tsk = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001942 kfree(volume_info.UNC);
1943 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001944 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 FreeXid(xid);
1946 return rc;
Steve Frenchf1914012005-08-18 09:37:34 -07001947 }
1948 wait_for_completion(&cifsd_complete);
1949 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00001950 memcpy(srvTcp->workstation_RFC1001_name,
1951 volume_info.source_rfc1001_name, 16);
1952 memcpy(srvTcp->server_RFC1001_name,
1953 volume_info.target_rfc1001_name, 16);
Steve Frenchad009ac2005-04-28 22:41:05 -07001954 srvTcp->sequence_number = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 }
1956 }
1957
1958 if (existingCifsSes) {
1959 pSesInfo = existingCifsSes;
Steve Frenchbf820672005-12-01 22:32:42 -08001960 cFYI(1, ("Existing smb sess found"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001961 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 /* volume_info.UNC freed at end of function */
1963 } else if (!rc) {
Steve Frenchbf820672005-12-01 22:32:42 -08001964 cFYI(1, ("Existing smb sess not found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 pSesInfo = sesInfoAlloc();
1966 if (pSesInfo == NULL)
1967 rc = -ENOMEM;
1968 else {
1969 pSesInfo->server = srvTcp;
1970 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1971 NIPQUAD(sin_server.sin_addr.s_addr));
1972 }
1973
Steve French50c2f752007-07-13 00:33:32 +00001974 if (!rc) {
1975 /* volume_info.password freed at unmount */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 if (volume_info.password)
1977 pSesInfo->password = volume_info.password;
1978 if (volume_info.username)
1979 strncpy(pSesInfo->userName,
Steve French50c2f752007-07-13 00:33:32 +00001980 volume_info.username,
1981 MAX_USERNAME_SIZE);
Steve French39798772006-05-31 22:40:51 +00001982 if (volume_info.domainname) {
1983 int len = strlen(volume_info.domainname);
Steve French50c2f752007-07-13 00:33:32 +00001984 pSesInfo->domainName =
Steve French39798772006-05-31 22:40:51 +00001985 kmalloc(len + 1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001986 if (pSesInfo->domainName)
Steve French39798772006-05-31 22:40:51 +00001987 strcpy(pSesInfo->domainName,
1988 volume_info.domainname);
1989 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 pSesInfo->linux_uid = volume_info.linux_uid;
Steve French750d1152006-06-27 06:28:30 +00001991 pSesInfo->overrideSecFlg = volume_info.secFlg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 down(&pSesInfo->sesSem);
Steve French189acaa2006-06-23 02:33:48 +00001993 /* BB FIXME need to pass vol->secFlgs BB */
Steve French50c2f752007-07-13 00:33:32 +00001994 rc = cifs_setup_session(xid, pSesInfo,
1995 cifs_sb->local_nls);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 up(&pSesInfo->sesSem);
Steve French4523cc32007-04-30 20:13:06 +00001997 if (!rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 atomic_inc(&srvTcp->socketUseCount);
1999 } else
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002000 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 }
Steve French50c2f752007-07-13 00:33:32 +00002002
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 /* search for existing tcon to this server share */
2004 if (!rc) {
Steve French4523cc32007-04-30 20:13:06 +00002005 if (volume_info.rsize > CIFSMaxBufSize) {
Steve French50c2f752007-07-13 00:33:32 +00002006 cERROR(1, ("rsize %d too large, using MaxBufSize",
Steve French0ae0efa2005-10-10 10:57:19 -07002007 volume_info.rsize));
2008 cifs_sb->rsize = CIFSMaxBufSize;
Steve French75865f8c2007-06-24 18:30:48 +00002009 } else if ((volume_info.rsize) &&
2010 (volume_info.rsize <= CIFSMaxBufSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 cifs_sb->rsize = volume_info.rsize;
Steve French0ae0efa2005-10-10 10:57:19 -07002012 else /* default */
2013 cifs_sb->rsize = CIFSMaxBufSize;
2014
Steve French4523cc32007-04-30 20:13:06 +00002015 if (volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
Steve French50c2f752007-07-13 00:33:32 +00002016 cERROR(1, ("wsize %d too large, using 4096 instead",
Steve French0ae0efa2005-10-10 10:57:19 -07002017 volume_info.wsize));
2018 cifs_sb->wsize = 4096;
Steve French4523cc32007-04-30 20:13:06 +00002019 } else if (volume_info.wsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 cifs_sb->wsize = volume_info.wsize;
2021 else
Steve French50c2f752007-07-13 00:33:32 +00002022 cifs_sb->wsize =
Steve French1877c9e2006-01-27 18:36:11 -08002023 min_t(const int, PAGEVEC_SIZE * PAGE_CACHE_SIZE,
2024 127*1024);
Steve French17cbbaf2006-01-24 20:26:48 -08002025 /* old default of CIFSMaxBufSize was too small now
Steve French50c2f752007-07-13 00:33:32 +00002026 that SMB Write2 can send multiple pages in kvec.
Steve French17cbbaf2006-01-24 20:26:48 -08002027 RFC1001 does not describe what happens when frame
2028 bigger than 128K is sent so use that as max in
2029 conjunction with 52K kvec constraint on arch with 4K
2030 page size */
2031
Steve French4523cc32007-04-30 20:13:06 +00002032 if (cifs_sb->rsize < 2048) {
Steve French50c2f752007-07-13 00:33:32 +00002033 cifs_sb->rsize = 2048;
Steve French6cec2ae2006-02-22 17:31:52 -06002034 /* Windows ME may prefer this */
Steve French467a8f82007-06-27 22:41:32 +00002035 cFYI(1, ("readsize set to minimum: 2048"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 }
Steve French2fe87f02006-09-21 07:02:52 +00002037 /* calculate prepath */
2038 cifs_sb->prepath = volume_info.prepath;
Steve French4523cc32007-04-30 20:13:06 +00002039 if (cifs_sb->prepath) {
Steve French2fe87f02006-09-21 07:02:52 +00002040 cifs_sb->prepathlen = strlen(cifs_sb->prepath);
2041 cifs_sb->prepath[0] = CIFS_DIR_SEP(cifs_sb);
2042 volume_info.prepath = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002043 } else
Steve French2fe87f02006-09-21 07:02:52 +00002044 cifs_sb->prepathlen = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 cifs_sb->mnt_uid = volume_info.linux_uid;
2046 cifs_sb->mnt_gid = volume_info.linux_gid;
2047 cifs_sb->mnt_file_mode = volume_info.file_mode;
2048 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
Steve French467a8f82007-06-27 22:41:32 +00002049 cFYI(1, ("file mode: 0x%x dir mode: 0x%x",
2050 cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051
Steve French4523cc32007-04-30 20:13:06 +00002052 if (volume_info.noperm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
Steve French4523cc32007-04-30 20:13:06 +00002054 if (volume_info.setuids)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
Steve French4523cc32007-04-30 20:13:06 +00002056 if (volume_info.server_ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
Steve French4523cc32007-04-30 20:13:06 +00002058 if (volume_info.remap)
Steve French6a0b4822005-04-28 22:41:05 -07002059 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
Steve French4523cc32007-04-30 20:13:06 +00002060 if (volume_info.no_xattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
Steve French4523cc32007-04-30 20:13:06 +00002062 if (volume_info.sfu_emul)
Steve Frenchd7245c22005-07-14 18:25:12 -05002063 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
Steve French4523cc32007-04-30 20:13:06 +00002064 if (volume_info.nobrl)
Steve Frenchc46fa8a2005-08-18 20:49:57 -07002065 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Steve French4523cc32007-04-30 20:13:06 +00002066 if (volume_info.cifs_acl)
Steve French0a4b92c2006-01-12 15:44:21 -08002067 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
Steve French4523cc32007-04-30 20:13:06 +00002068 if (volume_info.override_uid)
2069 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
2070 if (volume_info.override_gid)
2071 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
2072 if (volume_info.direct_io) {
Steve French467a8f82007-06-27 22:41:32 +00002073 cFYI(1, ("mounting share using direct i/o"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
2075 }
2076
2077 tcon =
2078 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
2079 volume_info.username);
2080 if (tcon) {
Steve Frenchbf820672005-12-01 22:32:42 -08002081 cFYI(1, ("Found match on UNC path"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082 /* we can have only one retry value for a connection
2083 to a share so for resources mounted more than once
Steve French50c2f752007-07-13 00:33:32 +00002084 to the same server share the last value passed in
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 for the retry flag is used */
2086 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07002087 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088 } else {
2089 tcon = tconInfoAlloc();
2090 if (tcon == NULL)
2091 rc = -ENOMEM;
2092 else {
Steve French50c2f752007-07-13 00:33:32 +00002093 /* check for null share name ie connecting to
Steve French8af18972007-02-14 04:42:51 +00002094 * dfs root */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095
Steve French50c2f752007-07-13 00:33:32 +00002096 /* BB check if this works for exactly length
Steve French8af18972007-02-14 04:42:51 +00002097 * three strings */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
2099 && (strchr(volume_info.UNC + 3, '/') ==
2100 NULL)) {
Steve French737b7582005-04-28 22:41:06 -07002101 rc = connect_to_dfs_path(xid, pSesInfo,
Steve French8af18972007-02-14 04:42:51 +00002102 "", cifs_sb->local_nls,
Steve French50c2f752007-07-13 00:33:32 +00002103 cifs_sb->mnt_cifs_flags &
Steve French8af18972007-02-14 04:42:51 +00002104 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002105 kfree(volume_info.UNC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106 FreeXid(xid);
2107 return -ENODEV;
2108 } else {
Steve French8af18972007-02-14 04:42:51 +00002109 /* BB Do we need to wrap sesSem around
2110 * this TCon call and Unix SetFS as
2111 * we do on SessSetup and reconnect? */
Steve French50c2f752007-07-13 00:33:32 +00002112 rc = CIFSTCon(xid, pSesInfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 volume_info.UNC,
2114 tcon, cifs_sb->local_nls);
2115 cFYI(1, ("CIFS Tcon rc = %d", rc));
2116 }
2117 if (!rc) {
2118 atomic_inc(&pSesInfo->inUse);
2119 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07002120 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121 }
2122 }
2123 }
2124 }
Steve French4523cc32007-04-30 20:13:06 +00002125 if (pSesInfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
2127 sb->s_maxbytes = (u64) 1 << 63;
2128 } else
2129 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
2130 }
2131
Steve French8af18972007-02-14 04:42:51 +00002132 /* BB FIXME fix time_gran to be larger for LANMAN sessions */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 sb->s_time_gran = 100;
2134
2135/* on error free sesinfo and tcon struct if needed */
2136 if (rc) {
2137 /* if session setup failed, use count is zero but
2138 we still need to free cifsd thread */
Steve French4523cc32007-04-30 20:13:06 +00002139 if (atomic_read(&srvTcp->socketUseCount) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140 spin_lock(&GlobalMid_Lock);
2141 srvTcp->tcpStatus = CifsExiting;
2142 spin_unlock(&GlobalMid_Lock);
Steve French4523cc32007-04-30 20:13:06 +00002143 if (srvTcp->tsk) {
Steve French28356a12007-05-23 14:45:36 +00002144 struct task_struct *tsk;
2145 /* If we could verify that kthread_stop would
2146 always wake up processes blocked in
2147 tcp in recv_mesg then we could remove the
2148 send_sig call */
Steve French50c2f752007-07-13 00:33:32 +00002149 force_sig(SIGKILL, srvTcp->tsk);
Steve French28356a12007-05-23 14:45:36 +00002150 tsk = srvTcp->tsk;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002151 if (tsk)
Steve Frenchf7f7c312007-05-24 02:29:51 +00002152 kthread_stop(tsk);
Steve Frenchf1914012005-08-18 09:37:34 -07002153 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 }
2155 /* If find_unc succeeded then rc == 0 so we can not end */
2156 if (tcon) /* up accidently freeing someone elses tcon struct */
2157 tconInfoFree(tcon);
2158 if (existingCifsSes == NULL) {
2159 if (pSesInfo) {
Steve French50c2f752007-07-13 00:33:32 +00002160 if ((pSesInfo->server) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161 (pSesInfo->status == CifsGood)) {
2162 int temp_rc;
2163 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
2164 /* if the socketUseCount is now zero */
Steve French4523cc32007-04-30 20:13:06 +00002165 if ((temp_rc == -ESHUTDOWN) &&
Steve French50c2f752007-07-13 00:33:32 +00002166 (pSesInfo->server) &&
Jeff5d9c7202007-06-25 22:16:35 +00002167 (pSesInfo->server->tsk)) {
Steve French28356a12007-05-23 14:45:36 +00002168 struct task_struct *tsk;
Jeff5d9c7202007-06-25 22:16:35 +00002169 force_sig(SIGKILL,
2170 pSesInfo->server->tsk);
Steve French28356a12007-05-23 14:45:36 +00002171 tsk = pSesInfo->server->tsk;
Steve Frenchf7f7c312007-05-24 02:29:51 +00002172 if (tsk)
Steve French28356a12007-05-23 14:45:36 +00002173 kthread_stop(tsk);
Steve Frenchf1914012005-08-18 09:37:34 -07002174 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 } else
2176 cFYI(1, ("No session or bad tcon"));
2177 sesInfoFree(pSesInfo);
2178 /* pSesInfo = NULL; */
2179 }
2180 }
2181 } else {
2182 atomic_inc(&tcon->useCount);
2183 cifs_sb->tcon = tcon;
2184 tcon->ses = pSesInfo;
2185
Steve French82940a42006-03-02 03:24:57 +00002186 /* do not care if following two calls succeed - informational */
Steve French737b7582005-04-28 22:41:06 -07002187 CIFSSMBQFSDeviceInfo(xid, tcon);
2188 CIFSSMBQFSAttributeInfo(xid, tcon);
Steve French50c2f752007-07-13 00:33:32 +00002189
Steve French8af18972007-02-14 04:42:51 +00002190 /* tell server which Unix caps we support */
2191 if (tcon->ses->capabilities & CAP_UNIX)
Steve Frenchc18c8422007-07-18 23:21:09 +00002192 /* reset of caps checks mount to see if unix extensions
2193 disabled for just this mount */
Steve French8af18972007-02-14 04:42:51 +00002194 reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
Steve Frenchc18c8422007-07-18 23:21:09 +00002195 else
2196 tcon->unix_ext = 0; /* server does not support them */
2197
2198 if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
Steve French75865f8c2007-06-24 18:30:48 +00002199 cifs_sb->rsize = 1024 * 127;
2200#ifdef CONFIG_CIFS_DEBUG2
Steve Frenchc18c8422007-07-18 23:21:09 +00002201 cFYI(1, ("no very large read support, rsize now 127K"));
Steve French75865f8c2007-06-24 18:30:48 +00002202#endif
Steve French75865f8c2007-06-24 18:30:48 +00002203 }
Steve French3e844692005-10-03 13:37:24 -07002204 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
2205 cifs_sb->wsize = min(cifs_sb->wsize,
2206 (tcon->ses->server->maxBuf -
2207 MAX_CIFS_HDR_SIZE));
Steve French0ae0efa2005-10-10 10:57:19 -07002208 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
Steve French50c2f752007-07-13 00:33:32 +00002209 cifs_sb->rsize = min(cifs_sb->rsize,
2210 (tcon->ses->server->maxBuf -
2211 MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212 }
2213
2214 /* volume_info.password is freed above when existing session found
2215 (in which case it is not needed anymore) but when new sesion is created
2216 the password ptr is put in the new session structure (in which case the
2217 password will be freed at unmount time) */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002218 kfree(volume_info.UNC);
Steve French2fe87f02006-09-21 07:02:52 +00002219 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 FreeXid(xid);
2221 return rc;
2222}
2223
2224static int
2225CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French7c7b25b2006-06-01 19:20:10 +00002226 char session_key[CIFS_SESS_KEY_SIZE],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227 const struct nls_table *nls_codepage)
2228{
2229 struct smb_hdr *smb_buffer;
2230 struct smb_hdr *smb_buffer_response;
2231 SESSION_SETUP_ANDX *pSMB;
2232 SESSION_SETUP_ANDX *pSMBr;
2233 char *bcc_ptr;
2234 char *user;
2235 char *domain;
2236 int rc = 0;
2237 int remaining_words = 0;
2238 int bytes_returned = 0;
2239 int len;
2240 __u32 capabilities;
2241 __u16 count;
2242
Steve Frencheeac8042006-01-13 21:34:58 -08002243 cFYI(1, ("In sesssetup"));
Steve French4523cc32007-04-30 20:13:06 +00002244 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245 return -EINVAL;
2246 user = ses->userName;
2247 domain = ses->domainName;
2248 smb_buffer = cifs_buf_get();
2249 if (smb_buffer == NULL) {
2250 return -ENOMEM;
2251 }
2252 smb_buffer_response = smb_buffer;
2253 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2254
2255 /* send SMBsessionSetup here */
2256 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2257 NULL /* no tCon exists yet */ , 13 /* wct */ );
2258
Steve French1982c342005-08-17 12:38:22 -07002259 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 pSMB->req_no_secext.AndXCommand = 0xFF;
2261 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2262 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2263
Steve French50c2f752007-07-13 00:33:32 +00002264 if (ses->server->secMode &
2265 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2267
2268 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2269 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
2270 if (ses->capabilities & CAP_UNICODE) {
2271 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2272 capabilities |= CAP_UNICODE;
2273 }
2274 if (ses->capabilities & CAP_STATUS32) {
2275 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2276 capabilities |= CAP_STATUS32;
2277 }
2278 if (ses->capabilities & CAP_DFS) {
2279 smb_buffer->Flags2 |= SMBFLG2_DFS;
2280 capabilities |= CAP_DFS;
2281 }
2282 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
2283
Steve French50c2f752007-07-13 00:33:32 +00002284 pSMB->req_no_secext.CaseInsensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002285 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286
2287 pSMB->req_no_secext.CaseSensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002288 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289 bcc_ptr = pByteArea(smb_buffer);
Steve French7c7b25b2006-06-01 19:20:10 +00002290 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2291 bcc_ptr += CIFS_SESS_KEY_SIZE;
2292 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2293 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294
2295 if (ses->capabilities & CAP_UNICODE) {
2296 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
2297 *bcc_ptr = 0;
2298 bcc_ptr++;
2299 }
Steve French4523cc32007-04-30 20:13:06 +00002300 if (user == NULL)
Steve French39798772006-05-31 22:40:51 +00002301 bytes_returned = 0; /* skip null user */
Steve French50c2f752007-07-13 00:33:32 +00002302 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 bytes_returned =
Steve French50c2f752007-07-13 00:33:32 +00002304 cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305 nls_codepage);
2306 /* convert number of 16 bit words to bytes */
2307 bcc_ptr += 2 * bytes_returned;
2308 bcc_ptr += 2; /* trailing null */
2309 if (domain == NULL)
2310 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002311 cifs_strtoUCS((__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 "CIFS_LINUX_DOM", 32, nls_codepage);
2313 else
2314 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002315 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316 nls_codepage);
2317 bcc_ptr += 2 * bytes_returned;
2318 bcc_ptr += 2;
2319 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002320 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321 32, nls_codepage);
2322 bcc_ptr += 2 * bytes_returned;
2323 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002324 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325 32, nls_codepage);
2326 bcc_ptr += 2 * bytes_returned;
2327 bcc_ptr += 2;
2328 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002329 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002330 64, nls_codepage);
2331 bcc_ptr += 2 * bytes_returned;
2332 bcc_ptr += 2;
2333 } else {
Steve French50c2f752007-07-13 00:33:32 +00002334 if (user != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335 strncpy(bcc_ptr, user, 200);
2336 bcc_ptr += strnlen(user, 200);
2337 }
2338 *bcc_ptr = 0;
2339 bcc_ptr++;
2340 if (domain == NULL) {
2341 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2342 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2343 } else {
2344 strncpy(bcc_ptr, domain, 64);
2345 bcc_ptr += strnlen(domain, 64);
2346 *bcc_ptr = 0;
2347 bcc_ptr++;
2348 }
2349 strcpy(bcc_ptr, "Linux version ");
2350 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002351 strcpy(bcc_ptr, utsname()->release);
2352 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2354 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2355 }
2356 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2357 smb_buffer->smb_buf_length += count;
2358 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2359
2360 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2361 &bytes_returned, 1);
2362 if (rc) {
2363/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2364 } else if ((smb_buffer_response->WordCount == 3)
2365 || (smb_buffer_response->WordCount == 4)) {
2366 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2367 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2368 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002369 cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */
2370 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format
2371 (little endian) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 cFYI(1, ("UID = %d ", ses->Suid));
Steve French50c2f752007-07-13 00:33:32 +00002373 /* response can have either 3 or 4 word count - Samba sends 3 */
2374 bcc_ptr = pByteArea(smb_buffer_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375 if ((pSMBr->resp.hdr.WordCount == 3)
2376 || ((pSMBr->resp.hdr.WordCount == 4)
2377 && (blob_len < pSMBr->resp.ByteCount))) {
2378 if (pSMBr->resp.hdr.WordCount == 4)
2379 bcc_ptr += blob_len;
2380
2381 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2382 if ((long) (bcc_ptr) % 2) {
2383 remaining_words =
Steve French50c2f752007-07-13 00:33:32 +00002384 (BCC(smb_buffer_response) - 1) / 2;
2385 /* Unicode strings must be word
2386 aligned */
2387 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388 } else {
2389 remaining_words =
2390 BCC(smb_buffer_response) / 2;
2391 }
2392 len =
2393 UniStrnlen((wchar_t *) bcc_ptr,
2394 remaining_words - 1);
2395/* We look for obvious messed up bcc or strings in response so we do not go off
2396 the end since (at least) WIN2K and Windows XP have a major bug in not null
2397 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002398 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002399 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002400 ses->serverOS = kzalloc(2 * (len + 1),
2401 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002402 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002403 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 cifs_strfromUCS_le(ses->serverOS,
Steve French50c2f752007-07-13 00:33:32 +00002405 (__le16 *)bcc_ptr,
2406 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407 bcc_ptr += 2 * (len + 1);
2408 remaining_words -= len + 1;
2409 ses->serverOS[2 * len] = 0;
2410 ses->serverOS[1 + (2 * len)] = 0;
2411 if (remaining_words > 0) {
2412 len = UniStrnlen((wchar_t *)bcc_ptr,
2413 remaining_words-1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002414 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002415 ses->serverNOS = kzalloc(2 * (len + 1),
2416 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002417 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002418 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419 cifs_strfromUCS_le(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002420 (__le16 *)bcc_ptr,
2421 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 bcc_ptr += 2 * (len + 1);
2423 ses->serverNOS[2 * len] = 0;
2424 ses->serverNOS[1 + (2 * len)] = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002425 if (strncmp(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002426 "NT LAN Manager 4", 16) == 0) {
Steve French467a8f82007-06-27 22:41:32 +00002427 cFYI(1, ("NT4 server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428 ses->flags |= CIFS_SES_NT4;
2429 }
2430 remaining_words -= len + 1;
2431 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002432 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Steve French50c2f752007-07-13 00:33:32 +00002433 /* last string is not always null terminated
2434 (for e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002435 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002436 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437 ses->serverDomain =
Steve French50c2f752007-07-13 00:33:32 +00002438 kzalloc(2*(len+1),
2439 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002440 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002441 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 cifs_strfromUCS_le(ses->serverDomain,
Steve French50c2f752007-07-13 00:33:32 +00002443 (__le16 *)bcc_ptr,
2444 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445 bcc_ptr += 2 * (len + 1);
2446 ses->serverDomain[2*len] = 0;
2447 ses->serverDomain[1+(2*len)] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002448 } else { /* else no more room so create
2449 dummy domain string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002450 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002451 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002452 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002453 kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002454 }
Steve French50c2f752007-07-13 00:33:32 +00002455 } else { /* no room so create dummy domain
2456 and NOS string */
2457
Steve French433dc242005-04-28 22:41:08 -07002458 /* if these kcallocs fail not much we
2459 can do, but better to not fail the
2460 sesssetup itself */
Steve Frenchcd49b492006-06-26 04:22:36 +00002461 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002463 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002464 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002466 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467 }
2468 } else { /* ASCII */
2469 len = strnlen(bcc_ptr, 1024);
2470 if (((long) bcc_ptr + len) - (long)
2471 pByteArea(smb_buffer_response)
2472 <= BCC(smb_buffer_response)) {
Steve Frenchcd49b492006-06-26 04:22:36 +00002473 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002474 ses->serverOS = kzalloc(len + 1,
2475 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002476 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002477 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002478 strncpy(ses->serverOS, bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479
2480 bcc_ptr += len;
Steve French50c2f752007-07-13 00:33:32 +00002481 /* null terminate the string */
2482 bcc_ptr[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483 bcc_ptr++;
2484
2485 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002486 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002487 ses->serverNOS = kzalloc(len + 1,
2488 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002489 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002490 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 strncpy(ses->serverNOS, bcc_ptr, len);
2492 bcc_ptr += len;
2493 bcc_ptr[0] = 0;
2494 bcc_ptr++;
2495
2496 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002497 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002498 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002499 ses->serverDomain = kzalloc(len + 1,
2500 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002501 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002502 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002503 strncpy(ses->serverDomain, bcc_ptr,
2504 len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505 bcc_ptr += len;
2506 bcc_ptr[0] = 0;
2507 bcc_ptr++;
2508 } else
2509 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00002510 ("Variable field of length %d "
2511 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512 len));
2513 }
2514 } else {
2515 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00002516 (" Security Blob Length extends beyond "
2517 "end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518 }
2519 } else {
2520 cERROR(1,
2521 (" Invalid Word count %d: ",
2522 smb_buffer_response->WordCount));
2523 rc = -EIO;
2524 }
Steve French433dc242005-04-28 22:41:08 -07002525sesssetup_nomem: /* do not return an error on nomem for the info strings,
2526 since that could make reconnection harder, and
2527 reconnection might be needed to free memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528 if (smb_buffer)
2529 cifs_buf_release(smb_buffer);
2530
2531 return rc;
2532}
2533
2534static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
Steve French50c2f752007-07-13 00:33:32 +00002536 struct cifsSesInfo *ses, int *pNTLMv2_flag,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537 const struct nls_table *nls_codepage)
2538{
2539 struct smb_hdr *smb_buffer;
2540 struct smb_hdr *smb_buffer_response;
2541 SESSION_SETUP_ANDX *pSMB;
2542 SESSION_SETUP_ANDX *pSMBr;
2543 char *bcc_ptr;
2544 char *domain;
2545 int rc = 0;
2546 int remaining_words = 0;
2547 int bytes_returned = 0;
2548 int len;
2549 int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
2550 PNEGOTIATE_MESSAGE SecurityBlob;
2551 PCHALLENGE_MESSAGE SecurityBlob2;
2552 __u32 negotiate_flags, capabilities;
2553 __u16 count;
2554
Steve French12b3b8f2006-02-09 21:12:47 +00002555 cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002556 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557 return -EINVAL;
2558 domain = ses->domainName;
2559 *pNTLMv2_flag = FALSE;
2560 smb_buffer = cifs_buf_get();
2561 if (smb_buffer == NULL) {
2562 return -ENOMEM;
2563 }
2564 smb_buffer_response = smb_buffer;
2565 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2566 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2567
2568 /* send SMBsessionSetup here */
2569 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2570 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002571
2572 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2574 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2575
2576 pSMB->req.AndXCommand = 0xFF;
2577 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2578 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2579
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002580 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2582
2583 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2584 CAP_EXTENDED_SECURITY;
2585 if (ses->capabilities & CAP_UNICODE) {
2586 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2587 capabilities |= CAP_UNICODE;
2588 }
2589 if (ses->capabilities & CAP_STATUS32) {
2590 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2591 capabilities |= CAP_STATUS32;
2592 }
2593 if (ses->capabilities & CAP_DFS) {
2594 smb_buffer->Flags2 |= SMBFLG2_DFS;
2595 capabilities |= CAP_DFS;
2596 }
2597 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2598
2599 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2600 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2601 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2602 SecurityBlob->MessageType = NtLmNegotiate;
2603 negotiate_flags =
2604 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
Steve French12b3b8f2006-02-09 21:12:47 +00002605 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
2606 NTLMSSP_NEGOTIATE_56 |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002608 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002610/* if (ntlmv2_support)
Steve French39798772006-05-31 22:40:51 +00002611 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 /* setup pointers to domain name and workstation name */
2613 bcc_ptr += SecurityBlobLength;
2614
2615 SecurityBlob->WorkstationName.Buffer = 0;
2616 SecurityBlob->WorkstationName.Length = 0;
2617 SecurityBlob->WorkstationName.MaximumLength = 0;
2618
Steve French12b3b8f2006-02-09 21:12:47 +00002619 /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent
2620 along with username on auth request (ie the response to challenge) */
2621 SecurityBlob->DomainName.Buffer = 0;
2622 SecurityBlob->DomainName.Length = 0;
2623 SecurityBlob->DomainName.MaximumLength = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 if (ses->capabilities & CAP_UNICODE) {
2625 if ((long) bcc_ptr % 2) {
2626 *bcc_ptr = 0;
2627 bcc_ptr++;
2628 }
2629
2630 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002631 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632 32, nls_codepage);
2633 bcc_ptr += 2 * bytes_returned;
2634 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002635 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 nls_codepage);
2637 bcc_ptr += 2 * bytes_returned;
2638 bcc_ptr += 2; /* null terminate Linux version */
2639 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002640 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 64, nls_codepage);
2642 bcc_ptr += 2 * bytes_returned;
2643 *(bcc_ptr + 1) = 0;
2644 *(bcc_ptr + 2) = 0;
2645 bcc_ptr += 2; /* null terminate network opsys string */
2646 *(bcc_ptr + 1) = 0;
2647 *(bcc_ptr + 2) = 0;
2648 bcc_ptr += 2; /* null domain */
2649 } else { /* ASCII */
2650 strcpy(bcc_ptr, "Linux version ");
2651 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002652 strcpy(bcc_ptr, utsname()->release);
2653 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2655 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2656 bcc_ptr++; /* empty domain field */
2657 *bcc_ptr = 0;
2658 }
2659 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2660 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2661 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2662 smb_buffer->smb_buf_length += count;
2663 pSMB->req.ByteCount = cpu_to_le16(count);
2664
2665 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2666 &bytes_returned, 1);
2667
2668 if (smb_buffer_response->Status.CifsError ==
2669 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2670 rc = 0;
2671
2672 if (rc) {
2673/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2674 } else if ((smb_buffer_response->WordCount == 3)
2675 || (smb_buffer_response->WordCount == 4)) {
2676 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2677 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2678
2679 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002680 cFYI(1, (" Guest login"));
2681 /* Do we want to set anything in SesInfo struct when guest login? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682
Steve French50c2f752007-07-13 00:33:32 +00002683 bcc_ptr = pByteArea(smb_buffer_response);
2684 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685
2686 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2687 if (SecurityBlob2->MessageType != NtLmChallenge) {
2688 cFYI(1,
2689 ("Unexpected NTLMSSP message type received %d",
2690 SecurityBlob2->MessageType));
2691 } else if (ses) {
Steve French50c2f752007-07-13 00:33:32 +00002692 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
Steve French12b3b8f2006-02-09 21:12:47 +00002693 cFYI(1, ("UID = %d", ses->Suid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 if ((pSMBr->resp.hdr.WordCount == 3)
2695 || ((pSMBr->resp.hdr.WordCount == 4)
2696 && (blob_len <
2697 pSMBr->resp.ByteCount))) {
2698
2699 if (pSMBr->resp.hdr.WordCount == 4) {
2700 bcc_ptr += blob_len;
Steve French12b3b8f2006-02-09 21:12:47 +00002701 cFYI(1, ("Security Blob Length %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702 blob_len));
2703 }
2704
Steve French12b3b8f2006-02-09 21:12:47 +00002705 cFYI(1, ("NTLMSSP Challenge rcvd"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706
2707 memcpy(ses->server->cryptKey,
2708 SecurityBlob2->Challenge,
2709 CIFS_CRYPTO_KEY_SIZE);
Steve French50c2f752007-07-13 00:33:32 +00002710 if (SecurityBlob2->NegotiateFlags &
Steve French12b3b8f2006-02-09 21:12:47 +00002711 cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712 *pNTLMv2_flag = TRUE;
2713
Steve French50c2f752007-07-13 00:33:32 +00002714 if ((SecurityBlob2->NegotiateFlags &
2715 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716 || (sign_CIFS_PDUs > 1))
Steve French50c2f752007-07-13 00:33:32 +00002717 ses->server->secMode |=
2718 SECMODE_SIGN_REQUIRED;
2719 if ((SecurityBlob2->NegotiateFlags &
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
Steve French50c2f752007-07-13 00:33:32 +00002721 ses->server->secMode |=
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722 SECMODE_SIGN_ENABLED;
2723
2724 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2725 if ((long) (bcc_ptr) % 2) {
2726 remaining_words =
2727 (BCC(smb_buffer_response)
2728 - 1) / 2;
Steve French50c2f752007-07-13 00:33:32 +00002729 /* Must word align unicode strings */
2730 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731 } else {
2732 remaining_words =
2733 BCC
2734 (smb_buffer_response) / 2;
2735 }
2736 len =
2737 UniStrnlen((wchar_t *) bcc_ptr,
2738 remaining_words - 1);
2739/* We look for obvious messed up bcc or strings in response so we do not go off
2740 the end since (at least) WIN2K and Windows XP have a major bug in not null
2741 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002742 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002743 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002745 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002747 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 bcc_ptr, len,
2749 nls_codepage);
2750 bcc_ptr += 2 * (len + 1);
2751 remaining_words -= len + 1;
2752 ses->serverOS[2 * len] = 0;
2753 ses->serverOS[1 + (2 * len)] = 0;
2754 if (remaining_words > 0) {
2755 len = UniStrnlen((wchar_t *)
2756 bcc_ptr,
2757 remaining_words
2758 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002759 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002761 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762 GFP_KERNEL);
2763 cifs_strfromUCS_le(ses->
2764 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002765 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 bcc_ptr,
2767 len,
2768 nls_codepage);
2769 bcc_ptr += 2 * (len + 1);
2770 ses->serverNOS[2 * len] = 0;
2771 ses->serverNOS[1 +
2772 (2 * len)] = 0;
2773 remaining_words -= len + 1;
2774 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00002775 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2776 /* last string not always null terminated
2777 (for e.g. for Windows XP & 2000) */
Steve Frenchcd49b492006-06-26 04:22:36 +00002778 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002780 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 (len +
2782 1),
2783 GFP_KERNEL);
2784 cifs_strfromUCS_le
Steve Frenche89dc922005-11-11 15:18:19 -08002785 (ses->serverDomain,
2786 (__le16 *)bcc_ptr,
2787 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 bcc_ptr +=
2789 2 * (len + 1);
Steve Frenche89dc922005-11-11 15:18:19 -08002790 ses->serverDomain[2*len]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 = 0;
Steve Frenche89dc922005-11-11 15:18:19 -08002792 ses->serverDomain
2793 [1 + (2 * len)]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 = 0;
2795 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002796 else {
Steve Frenchcd49b492006-06-26 04:22:36 +00002797 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002799 kzalloc(2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002801 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 } else { /* no room so create dummy domain and NOS string */
Steve Frenchcd49b492006-06-26 04:22:36 +00002803 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002805 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002806 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002808 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 }
2810 } else { /* ASCII */
2811 len = strnlen(bcc_ptr, 1024);
2812 if (((long) bcc_ptr + len) - (long)
2813 pByteArea(smb_buffer_response)
2814 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002815 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002816 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002818 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819 GFP_KERNEL);
2820 strncpy(ses->serverOS,
2821 bcc_ptr, len);
2822
2823 bcc_ptr += len;
2824 bcc_ptr[0] = 0; /* null terminate string */
2825 bcc_ptr++;
2826
2827 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002828 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002830 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831 GFP_KERNEL);
2832 strncpy(ses->serverNOS, bcc_ptr, len);
2833 bcc_ptr += len;
2834 bcc_ptr[0] = 0;
2835 bcc_ptr++;
2836
2837 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002838 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002840 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +00002842 strncpy(ses->serverDomain,
2843 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844 bcc_ptr += len;
2845 bcc_ptr[0] = 0;
2846 bcc_ptr++;
2847 } else
2848 cFYI(1,
Steve French63135e02007-07-17 17:34:02 +00002849 ("field of length %d "
2850 "extends beyond end of smb",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851 len));
2852 }
2853 } else {
Steve French50c2f752007-07-13 00:33:32 +00002854 cERROR(1, ("Security Blob Length extends beyond"
2855 " end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856 }
2857 } else {
2858 cERROR(1, ("No session structure passed in."));
2859 }
2860 } else {
2861 cERROR(1,
Steve French5815449d2006-02-14 01:36:20 +00002862 (" Invalid Word count %d:",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863 smb_buffer_response->WordCount));
2864 rc = -EIO;
2865 }
2866
2867 if (smb_buffer)
2868 cifs_buf_release(smb_buffer);
2869
2870 return rc;
2871}
2872static int
2873CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2874 char *ntlm_session_key, int ntlmv2_flag,
2875 const struct nls_table *nls_codepage)
2876{
2877 struct smb_hdr *smb_buffer;
2878 struct smb_hdr *smb_buffer_response;
2879 SESSION_SETUP_ANDX *pSMB;
2880 SESSION_SETUP_ANDX *pSMBr;
2881 char *bcc_ptr;
2882 char *user;
2883 char *domain;
2884 int rc = 0;
2885 int remaining_words = 0;
2886 int bytes_returned = 0;
2887 int len;
2888 int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2889 PAUTHENTICATE_MESSAGE SecurityBlob;
2890 __u32 negotiate_flags, capabilities;
2891 __u16 count;
2892
2893 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002894 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895 return -EINVAL;
2896 user = ses->userName;
2897 domain = ses->domainName;
2898 smb_buffer = cifs_buf_get();
2899 if (smb_buffer == NULL) {
2900 return -ENOMEM;
2901 }
2902 smb_buffer_response = smb_buffer;
2903 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2904 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2905
2906 /* send SMBsessionSetup here */
2907 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2908 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002909
2910 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2912 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2913 pSMB->req.AndXCommand = 0xFF;
2914 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2915 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2916
2917 pSMB->req.hdr.Uid = ses->Suid;
2918
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002919 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2921
2922 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2923 CAP_EXTENDED_SECURITY;
2924 if (ses->capabilities & CAP_UNICODE) {
2925 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2926 capabilities |= CAP_UNICODE;
2927 }
2928 if (ses->capabilities & CAP_STATUS32) {
2929 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2930 capabilities |= CAP_STATUS32;
2931 }
2932 if (ses->capabilities & CAP_DFS) {
2933 smb_buffer->Flags2 |= SMBFLG2_DFS;
2934 capabilities |= CAP_DFS;
2935 }
2936 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2937
2938 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2939 SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2940 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2941 SecurityBlob->MessageType = NtLmAuthenticate;
2942 bcc_ptr += SecurityBlobLength;
Steve French50c2f752007-07-13 00:33:32 +00002943 negotiate_flags =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2945 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2946 0x80000000 | NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002947 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002949 if (ntlmv2_flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2951
2952/* setup pointers to domain name and workstation name */
2953
2954 SecurityBlob->WorkstationName.Buffer = 0;
2955 SecurityBlob->WorkstationName.Length = 0;
2956 SecurityBlob->WorkstationName.MaximumLength = 0;
2957 SecurityBlob->SessionKey.Length = 0;
2958 SecurityBlob->SessionKey.MaximumLength = 0;
2959 SecurityBlob->SessionKey.Buffer = 0;
2960
2961 SecurityBlob->LmChallengeResponse.Length = 0;
2962 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2963 SecurityBlob->LmChallengeResponse.Buffer = 0;
2964
2965 SecurityBlob->NtChallengeResponse.Length =
Steve French7c7b25b2006-06-01 19:20:10 +00002966 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967 SecurityBlob->NtChallengeResponse.MaximumLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002968 cpu_to_le16(CIFS_SESS_KEY_SIZE);
2969 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 SecurityBlob->NtChallengeResponse.Buffer =
2971 cpu_to_le32(SecurityBlobLength);
Steve French7c7b25b2006-06-01 19:20:10 +00002972 SecurityBlobLength += CIFS_SESS_KEY_SIZE;
2973 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974
2975 if (ses->capabilities & CAP_UNICODE) {
2976 if (domain == NULL) {
2977 SecurityBlob->DomainName.Buffer = 0;
2978 SecurityBlob->DomainName.Length = 0;
2979 SecurityBlob->DomainName.MaximumLength = 0;
2980 } else {
2981 __u16 len =
Steve Frenche89dc922005-11-11 15:18:19 -08002982 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983 nls_codepage);
2984 len *= 2;
2985 SecurityBlob->DomainName.MaximumLength =
2986 cpu_to_le16(len);
2987 SecurityBlob->DomainName.Buffer =
2988 cpu_to_le32(SecurityBlobLength);
2989 bcc_ptr += len;
2990 SecurityBlobLength += len;
2991 SecurityBlob->DomainName.Length =
2992 cpu_to_le16(len);
2993 }
2994 if (user == NULL) {
2995 SecurityBlob->UserName.Buffer = 0;
2996 SecurityBlob->UserName.Length = 0;
2997 SecurityBlob->UserName.MaximumLength = 0;
2998 } else {
2999 __u16 len =
Steve Frenche89dc922005-11-11 15:18:19 -08003000 cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001 nls_codepage);
3002 len *= 2;
3003 SecurityBlob->UserName.MaximumLength =
3004 cpu_to_le16(len);
3005 SecurityBlob->UserName.Buffer =
3006 cpu_to_le32(SecurityBlobLength);
3007 bcc_ptr += len;
3008 SecurityBlobLength += len;
3009 SecurityBlob->UserName.Length =
3010 cpu_to_le16(len);
3011 }
3012
Steve French63135e02007-07-17 17:34:02 +00003013 /* SecurityBlob->WorkstationName.Length =
3014 cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015 SecurityBlob->WorkstationName.Length *= 2;
Steve French63135e02007-07-17 17:34:02 +00003016 SecurityBlob->WorkstationName.MaximumLength =
3017 cpu_to_le16(SecurityBlob->WorkstationName.Length);
3018 SecurityBlob->WorkstationName.Buffer =
3019 cpu_to_le32(SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020 bcc_ptr += SecurityBlob->WorkstationName.Length;
3021 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
Steve French63135e02007-07-17 17:34:02 +00003022 SecurityBlob->WorkstationName.Length =
3023 cpu_to_le16(SecurityBlob->WorkstationName.Length); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024
3025 if ((long) bcc_ptr % 2) {
3026 *bcc_ptr = 0;
3027 bcc_ptr++;
3028 }
3029 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003030 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 32, nls_codepage);
3032 bcc_ptr += 2 * bytes_returned;
3033 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003034 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035 nls_codepage);
3036 bcc_ptr += 2 * bytes_returned;
3037 bcc_ptr += 2; /* null term version string */
3038 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003039 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003040 64, nls_codepage);
3041 bcc_ptr += 2 * bytes_returned;
3042 *(bcc_ptr + 1) = 0;
3043 *(bcc_ptr + 2) = 0;
3044 bcc_ptr += 2; /* null terminate network opsys string */
3045 *(bcc_ptr + 1) = 0;
3046 *(bcc_ptr + 2) = 0;
3047 bcc_ptr += 2; /* null domain */
3048 } else { /* ASCII */
3049 if (domain == NULL) {
3050 SecurityBlob->DomainName.Buffer = 0;
3051 SecurityBlob->DomainName.Length = 0;
3052 SecurityBlob->DomainName.MaximumLength = 0;
3053 } else {
3054 __u16 len;
3055 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
3056 strncpy(bcc_ptr, domain, 63);
3057 len = strnlen(domain, 64);
3058 SecurityBlob->DomainName.MaximumLength =
3059 cpu_to_le16(len);
3060 SecurityBlob->DomainName.Buffer =
3061 cpu_to_le32(SecurityBlobLength);
3062 bcc_ptr += len;
3063 SecurityBlobLength += len;
3064 SecurityBlob->DomainName.Length = cpu_to_le16(len);
3065 }
3066 if (user == NULL) {
3067 SecurityBlob->UserName.Buffer = 0;
3068 SecurityBlob->UserName.Length = 0;
3069 SecurityBlob->UserName.MaximumLength = 0;
3070 } else {
3071 __u16 len;
3072 strncpy(bcc_ptr, user, 63);
3073 len = strnlen(user, 64);
3074 SecurityBlob->UserName.MaximumLength =
3075 cpu_to_le16(len);
3076 SecurityBlob->UserName.Buffer =
3077 cpu_to_le32(SecurityBlobLength);
3078 bcc_ptr += len;
3079 SecurityBlobLength += len;
3080 SecurityBlob->UserName.Length = cpu_to_le16(len);
3081 }
3082 /* BB fill in our workstation name if known BB */
3083
3084 strcpy(bcc_ptr, "Linux version ");
3085 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003086 strcpy(bcc_ptr, utsname()->release);
3087 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
3089 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
3090 bcc_ptr++; /* null domain */
3091 *bcc_ptr = 0;
3092 }
3093 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
3094 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
3095 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
3096 smb_buffer->smb_buf_length += count;
3097 pSMB->req.ByteCount = cpu_to_le16(count);
3098
3099 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
3100 &bytes_returned, 1);
3101 if (rc) {
3102/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
3103 } else if ((smb_buffer_response->WordCount == 3)
3104 || (smb_buffer_response->WordCount == 4)) {
3105 __u16 action = le16_to_cpu(pSMBr->resp.Action);
3106 __u16 blob_len =
3107 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
3108 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00003109 cFYI(1, (" Guest login")); /* BB Should we set anything
3110 in SesInfo struct ? */
3111/* if (SecurityBlob2->MessageType != NtLm??) {
3112 cFYI("Unexpected message type on auth response is %d"));
3113 } */
3114
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115 if (ses) {
3116 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003117 ("Check challenge UID %d vs auth response UID %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118 ses->Suid, smb_buffer_response->Uid));
Steve French50c2f752007-07-13 00:33:32 +00003119 /* UID left in wire format */
3120 ses->Suid = smb_buffer_response->Uid;
3121 bcc_ptr = pByteArea(smb_buffer_response);
3122 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 if ((pSMBr->resp.hdr.WordCount == 3)
3124 || ((pSMBr->resp.hdr.WordCount == 4)
3125 && (blob_len <
3126 pSMBr->resp.ByteCount))) {
3127 if (pSMBr->resp.hdr.WordCount == 4) {
3128 bcc_ptr +=
3129 blob_len;
3130 cFYI(1,
3131 ("Security Blob Length %d ",
3132 blob_len));
3133 }
3134
3135 cFYI(1,
3136 ("NTLMSSP response to Authenticate "));
3137
3138 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3139 if ((long) (bcc_ptr) % 2) {
3140 remaining_words =
3141 (BCC(smb_buffer_response)
3142 - 1) / 2;
3143 bcc_ptr++; /* Unicode strings must be word aligned */
3144 } else {
3145 remaining_words = BCC(smb_buffer_response) / 2;
3146 }
3147 len =
3148 UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
3149/* We look for obvious messed up bcc or strings in response so we do not go off
3150 the end since (at least) WIN2K and Windows XP have a major bug in not null
3151 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003152 if (ses->serverOS)
Steve French08775832006-05-30 18:08:26 +00003153 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003155 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003157 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158 bcc_ptr, len,
3159 nls_codepage);
3160 bcc_ptr += 2 * (len + 1);
3161 remaining_words -= len + 1;
3162 ses->serverOS[2 * len] = 0;
3163 ses->serverOS[1 + (2 * len)] = 0;
3164 if (remaining_words > 0) {
3165 len = UniStrnlen((wchar_t *)
3166 bcc_ptr,
3167 remaining_words
3168 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00003169 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003171 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172 GFP_KERNEL);
3173 cifs_strfromUCS_le(ses->
3174 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003175 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176 bcc_ptr,
3177 len,
3178 nls_codepage);
3179 bcc_ptr += 2 * (len + 1);
3180 ses->serverNOS[2 * len] = 0;
3181 ses->serverNOS[1+(2*len)] = 0;
3182 remaining_words -= len + 1;
3183 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00003184 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185 /* last string not always null terminated (e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003186 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003187 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003189 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190 (len +
3191 1),
3192 GFP_KERNEL);
3193 cifs_strfromUCS_le
3194 (ses->
3195 serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08003196 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197 bcc_ptr, len,
3198 nls_codepage);
3199 bcc_ptr +=
3200 2 * (len + 1);
3201 ses->
3202 serverDomain[2
3203 * len]
3204 = 0;
3205 ses->
3206 serverDomain[1
3207 +
3208 (2
3209 *
3210 len)]
3211 = 0;
3212 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003213 else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003214 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003215 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003216 ses->serverDomain = kzalloc(2,GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00003217 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218 } else { /* no room so create dummy domain and NOS string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003219 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003220 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003221 ses->serverDomain = kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00003222 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003223 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224 }
3225 } else { /* ASCII */
3226 len = strnlen(bcc_ptr, 1024);
Steve French50c2f752007-07-13 00:33:32 +00003227 if (((long) bcc_ptr + len) -
3228 (long) pByteArea(smb_buffer_response)
Steve French63135e02007-07-17 17:34:02 +00003229 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003230 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00003231 kfree(ses->serverOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003232 ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233 strncpy(ses->serverOS,bcc_ptr, len);
3234
3235 bcc_ptr += len;
3236 bcc_ptr[0] = 0; /* null terminate the string */
3237 bcc_ptr++;
3238
3239 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003240 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00003241 ses->serverNOS = kzalloc(len+1,
3242 GFP_KERNEL);
Steve French63135e02007-07-17 17:34:02 +00003243 strncpy(ses->serverNOS,
3244 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003245 bcc_ptr += len;
3246 bcc_ptr[0] = 0;
3247 bcc_ptr++;
3248
3249 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003250 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003251 kfree(ses->serverDomain);
Steve French63135e02007-07-17 17:34:02 +00003252 ses->serverDomain =
3253 kzalloc(len+1,
3254 GFP_KERNEL);
3255 strncpy(ses->serverDomain,
3256 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003257 bcc_ptr += len;
3258 bcc_ptr[0] = 0;
3259 bcc_ptr++;
3260 } else
3261 cFYI(1,
Steve French63135e02007-07-17 17:34:02 +00003262 ("field of length %d "
3263 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264 len));
3265 }
3266 } else {
3267 cERROR(1,
Steve French63135e02007-07-17 17:34:02 +00003268 (" Security Blob extends beyond end "
3269 "of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003270 }
3271 } else {
3272 cERROR(1, ("No session structure passed in."));
3273 }
3274 } else {
3275 cERROR(1,
3276 (" Invalid Word count %d: ",
3277 smb_buffer_response->WordCount));
3278 rc = -EIO;
3279 }
3280
3281 if (smb_buffer)
3282 cifs_buf_release(smb_buffer);
3283
3284 return rc;
3285}
3286
3287int
3288CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3289 const char *tree, struct cifsTconInfo *tcon,
3290 const struct nls_table *nls_codepage)
3291{
3292 struct smb_hdr *smb_buffer;
3293 struct smb_hdr *smb_buffer_response;
3294 TCONX_REQ *pSMB;
3295 TCONX_RSP *pSMBr;
3296 unsigned char *bcc_ptr;
3297 int rc = 0;
3298 int length;
3299 __u16 count;
3300
3301 if (ses == NULL)
3302 return -EIO;
3303
3304 smb_buffer = cifs_buf_get();
3305 if (smb_buffer == NULL) {
3306 return -ENOMEM;
3307 }
3308 smb_buffer_response = smb_buffer;
3309
3310 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3311 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003312
3313 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314 smb_buffer->Uid = ses->Suid;
3315 pSMB = (TCONX_REQ *) smb_buffer;
3316 pSMBr = (TCONX_RSP *) smb_buffer_response;
3317
3318 pSMB->AndXCommand = 0xFF;
3319 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003320 bcc_ptr = &pSMB->Password[0];
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003321 if ((ses->server->secMode) & SECMODE_USER) {
Steve Frencheeac8042006-01-13 21:34:58 -08003322 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00003323 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08003324 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00003325 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08003326 } else {
Steve French7c7b25b2006-06-01 19:20:10 +00003327 pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08003328 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
3329 specified as required (when that support is added to
3330 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00003331 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08003332 by Samba (not sure whether other servers allow
3333 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00003334#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French50c2f752007-07-13 00:33:32 +00003335 if ((extended_security & CIFSSEC_MAY_LANMAN) &&
Steve French7c7b25b2006-06-01 19:20:10 +00003336 (ses->server->secType == LANMAN))
3337 calc_lanman_hash(ses, bcc_ptr);
3338 else
3339#endif /* CIFS_WEAK_PW_HASH */
Steve Frencheeac8042006-01-13 21:34:58 -08003340 SMBNTencrypt(ses->password,
3341 ses->server->cryptKey,
3342 bcc_ptr);
3343
Steve French7c7b25b2006-06-01 19:20:10 +00003344 bcc_ptr += CIFS_SESS_KEY_SIZE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003345 if (ses->capabilities & CAP_UNICODE) {
Steve French7c7b25b2006-06-01 19:20:10 +00003346 /* must align unicode strings */
3347 *bcc_ptr = 0; /* null byte password */
3348 bcc_ptr++;
3349 }
Steve Frencheeac8042006-01-13 21:34:58 -08003350 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351
Steve French50c2f752007-07-13 00:33:32 +00003352 if (ses->server->secMode &
Steve Frencha878fb22006-05-30 18:04:19 +00003353 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3355
3356 if (ses->capabilities & CAP_STATUS32) {
3357 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3358 }
3359 if (ses->capabilities & CAP_DFS) {
3360 smb_buffer->Flags2 |= SMBFLG2_DFS;
3361 }
3362 if (ses->capabilities & CAP_UNICODE) {
3363 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3364 length =
Steve French50c2f752007-07-13 00:33:32 +00003365 cifs_strtoUCS((__le16 *) bcc_ptr, tree,
3366 6 /* max utf8 char length in bytes */ *
Steve Frencha878fb22006-05-30 18:04:19 +00003367 (/* server len*/ + 256 /* share len */), nls_codepage);
3368 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369 bcc_ptr += 2; /* skip trailing null */
3370 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371 strcpy(bcc_ptr, tree);
3372 bcc_ptr += strlen(tree) + 1;
3373 }
3374 strcpy(bcc_ptr, "?????");
3375 bcc_ptr += strlen("?????");
3376 bcc_ptr += 1;
3377 count = bcc_ptr - &pSMB->Password[0];
3378 pSMB->hdr.smb_buf_length += count;
3379 pSMB->ByteCount = cpu_to_le16(count);
3380
3381 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
3382
3383 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3384 /* above now done in SendReceive */
3385 if ((rc == 0) && (tcon != NULL)) {
3386 tcon->tidStatus = CifsGood;
3387 tcon->tid = smb_buffer_response->Tid;
3388 bcc_ptr = pByteArea(smb_buffer_response);
3389 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
Steve French50c2f752007-07-13 00:33:32 +00003390 /* skip service field (NB: this field is always ASCII) */
3391 bcc_ptr += length + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3393 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3394 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3395 if ((bcc_ptr + (2 * length)) -
3396 pByteArea(smb_buffer_response) <=
3397 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003398 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003400 kzalloc(length + 2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401 cifs_strfromUCS_le(tcon->nativeFileSystem,
Steve Frenche89dc922005-11-11 15:18:19 -08003402 (__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003403 length, nls_codepage);
3404 bcc_ptr += 2 * length;
3405 bcc_ptr[0] = 0; /* null terminate the string */
3406 bcc_ptr[1] = 0;
3407 bcc_ptr += 2;
3408 }
Steve French50c2f752007-07-13 00:33:32 +00003409 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003410 } else {
3411 length = strnlen(bcc_ptr, 1024);
3412 if ((bcc_ptr + length) -
3413 pByteArea(smb_buffer_response) <=
3414 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003415 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003417 kzalloc(length + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418 strncpy(tcon->nativeFileSystem, bcc_ptr,
3419 length);
3420 }
Steve French50c2f752007-07-13 00:33:32 +00003421 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003423 if ((smb_buffer_response->WordCount == 3) ||
Steve French1a4e15a2006-10-12 21:33:51 +00003424 (smb_buffer_response->WordCount == 7))
3425 /* field is in same location */
Steve French39798772006-05-31 22:40:51 +00003426 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3427 else
3428 tcon->Flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3430 } else if ((rc == 0) && tcon == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00003431 /* all we need to save for IPC$ connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003432 ses->ipc_tid = smb_buffer_response->Tid;
3433 }
3434
3435 if (smb_buffer)
3436 cifs_buf_release(smb_buffer);
3437 return rc;
3438}
3439
3440int
3441cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3442{
3443 int rc = 0;
3444 int xid;
3445 struct cifsSesInfo *ses = NULL;
3446 struct task_struct *cifsd_task;
Steve French50c2f752007-07-13 00:33:32 +00003447 char *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448
3449 xid = GetXid();
3450
3451 if (cifs_sb->tcon) {
3452 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3453 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3454 if (rc == -EBUSY) {
3455 FreeXid(xid);
3456 return 0;
3457 }
3458 tconInfoFree(cifs_sb->tcon);
3459 if ((ses) && (ses->server)) {
3460 /* save off task so we do not refer to ses later */
3461 cifsd_task = ses->server->tsk;
3462 cFYI(1, ("About to do SMBLogoff "));
3463 rc = CIFSSMBLogoff(xid, ses);
3464 if (rc == -EBUSY) {
3465 FreeXid(xid);
3466 return 0;
3467 } else if (rc == -ESHUTDOWN) {
Steve French467a8f82007-06-27 22:41:32 +00003468 cFYI(1, ("Waking up socket by sending signal"));
Steve Frenchf7f7c312007-05-24 02:29:51 +00003469 if (cifsd_task) {
Steve French50c2f752007-07-13 00:33:32 +00003470 force_sig(SIGKILL, cifsd_task);
Igor Mammedovaaf737a2007-04-03 19:16:43 +00003471 kthread_stop(cifsd_task);
Steve Frenchf1914012005-08-18 09:37:34 -07003472 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003473 rc = 0;
3474 } /* else - we have an smb session
3475 left on this socket do not kill cifsd */
3476 } else
3477 cFYI(1, ("No session or bad tcon"));
3478 }
Steve French50c2f752007-07-13 00:33:32 +00003479
Linus Torvalds1da177e2005-04-16 15:20:36 -07003480 cifs_sb->tcon = NULL;
Steve French2fe87f02006-09-21 07:02:52 +00003481 tmp = cifs_sb->prepath;
3482 cifs_sb->prepathlen = 0;
3483 cifs_sb->prepath = NULL;
3484 kfree(tmp);
Nishanth Aravamudan041e0e32005-09-10 00:27:23 -07003485 if (ses)
3486 schedule_timeout_interruptible(msecs_to_jiffies(500));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487 if (ses)
3488 sesInfoFree(ses);
3489
3490 FreeXid(xid);
Steve French50c2f752007-07-13 00:33:32 +00003491 return rc; /* BB check if we should always return zero here */
3492}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493
3494int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
Steve French50c2f752007-07-13 00:33:32 +00003495 struct nls_table *nls_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496{
3497 int rc = 0;
Steve French7c7b25b2006-06-01 19:20:10 +00003498 char ntlm_session_key[CIFS_SESS_KEY_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499 int ntlmv2_flag = FALSE;
Steve Frenchad009ac2005-04-28 22:41:05 -07003500 int first_time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501
3502 /* what if server changes its buffer size after dropping the session? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003503 if (pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003505 if (rc == -EAGAIN) /* retry only once on 1st time connection */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve French50c2f752007-07-13 00:33:32 +00003507 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003508 rc = -EHOSTDOWN;
3509 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003510 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003511 spin_lock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003512 if (pSesInfo->server->tcpStatus != CifsExiting)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003513 pSesInfo->server->tcpStatus = CifsGood;
3514 else
3515 rc = -EHOSTDOWN;
3516 spin_unlock(&GlobalMid_Lock);
3517
3518 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003519 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520 }
3521 if (!rc) {
Steve French9ac00b72006-09-30 04:13:17 +00003522 pSesInfo->flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523 pSesInfo->capabilities = pSesInfo->server->capabilities;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003524 if (linuxExtEnabled == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003526 /* pSesInfo->sequence_number = 0;*/
Steve French50c2f752007-07-13 00:33:32 +00003527 cFYI(1,
3528 ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003529 pSesInfo->server->secMode,
3530 pSesInfo->server->capabilities,
Steve French175ec9e2006-09-30 01:07:38 +00003531 pSesInfo->server->timeAdj));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003532 if (experimEnabled < 2)
Steve French39798772006-05-31 22:40:51 +00003533 rc = CIFS_SessSetup(xid, pSesInfo,
3534 first_time, nls_info);
Steve French189acaa2006-06-23 02:33:48 +00003535 else if (extended_security
Steve French50c2f752007-07-13 00:33:32 +00003536 && (pSesInfo->capabilities
Steve French175ec9e2006-09-30 01:07:38 +00003537 & CAP_EXTENDED_SECURITY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003538 && (pSesInfo->server->secType == NTLMSSP)) {
Steve French189acaa2006-06-23 02:33:48 +00003539 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003540 } else if (extended_security
3541 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3542 && (pSesInfo->server->secType == RawNTLMSSP)) {
Steve French5815449d2006-02-14 01:36:20 +00003543 cFYI(1, ("NTLMSSP sesssetup"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3545 pSesInfo,
3546 &ntlmv2_flag,
3547 nls_info);
3548 if (!rc) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003549 if (ntlmv2_flag) {
Steve French50c2f752007-07-13 00:33:32 +00003550 char *v2_response;
Steve French467a8f82007-06-27 22:41:32 +00003551 cFYI(1, ("more secure NTLM ver2 hash"));
Steve French50c2f752007-07-13 00:33:32 +00003552 if (CalcNTLMv2_partial_mac_key(pSesInfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003553 nls_info)) {
3554 rc = -ENOMEM;
3555 goto ss_err_exit;
3556 } else
3557 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003558 if (v2_response) {
Steve French50c2f752007-07-13 00:33:32 +00003559 CalcNTLMv2_response(pSesInfo,
3560 v2_response);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003561 /* if (first_time)
Steve French50c2f752007-07-13 00:33:32 +00003562 cifs_calculate_ntlmv2_mac_key(
3563 pSesInfo->server->mac_signing_key,
3564 response, ntlm_session_key,*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565 kfree(v2_response);
3566 /* BB Put dummy sig in SessSetup PDU? */
3567 } else {
3568 rc = -ENOMEM;
3569 goto ss_err_exit;
3570 }
3571
3572 } else {
3573 SMBNTencrypt(pSesInfo->password,
3574 pSesInfo->server->cryptKey,
3575 ntlm_session_key);
3576
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003577 if (first_time)
Steve Frenchad009ac2005-04-28 22:41:05 -07003578 cifs_calculate_mac_key(
Steve Frenchb609f062007-07-09 07:55:14 +00003579 &pSesInfo->server->mac_signing_key,
Steve Frenchad009ac2005-04-28 22:41:05 -07003580 ntlm_session_key,
3581 pSesInfo->password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582 }
3583 /* for better security the weaker lanman hash not sent
3584 in AuthSessSetup so we no longer calculate it */
3585
3586 rc = CIFSNTLMSSPAuthSessSetup(xid,
3587 pSesInfo,
3588 ntlm_session_key,
3589 ntlmv2_flag,
3590 nls_info);
3591 }
3592 } else { /* old style NTLM 0.12 session setup */
3593 SMBNTencrypt(pSesInfo->password,
3594 pSesInfo->server->cryptKey,
3595 ntlm_session_key);
3596
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003597 if (first_time)
Steve Frenchad009ac2005-04-28 22:41:05 -07003598 cifs_calculate_mac_key(
Steve Frenchb609f062007-07-09 07:55:14 +00003599 &pSesInfo->server->mac_signing_key,
Steve Frenchad009ac2005-04-28 22:41:05 -07003600 ntlm_session_key, pSesInfo->password);
3601
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602 rc = CIFSSessSetup(xid, pSesInfo,
3603 ntlm_session_key, nls_info);
3604 }
3605 if (rc) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003606 cERROR(1, ("Send error in SessSetup = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607 } else {
Steve French467a8f82007-06-27 22:41:32 +00003608 cFYI(1, ("CIFS Session Established successfully"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609 pSesInfo->status = CifsGood;
3610 }
3611 }
3612ss_err_exit:
3613 return rc;
3614}
3615