blob: 494455ed4352687294a57993821834d6b0a37238 [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 French26f57362007-08-30 22:09:15 +0000127 if (kthread_should_stop()) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000128 /* 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 French26f57362007-08-30 22:09:15 +0000154 if ((tcon) && (tcon->ses) && (tcon->ses->server == server))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 tcon->tidStatus = CifsNeedReconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 }
157 read_unlock(&GlobalSMBSeslock);
158 /* do not want to be sending data on a socket we are freeing */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000159 down(&server->tcpSem);
160 if (server->ssocket) {
Steve French467a8f82007-06-27 22:41:32 +0000161 cFYI(1, ("State: 0x%x Flags: 0x%lx", server->ssocket->state,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 server->ssocket->flags));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000163 server->ssocket->ops->shutdown(server->ssocket, SEND_SHUTDOWN);
164 cFYI(1, ("Post shutdown state: 0x%x Flags: 0x%lx",
Steve French467a8f82007-06-27 22:41:32 +0000165 server->ssocket->state,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 server->ssocket->flags));
167 sock_release(server->ssocket);
168 server->ssocket = NULL;
169 }
170
171 spin_lock(&GlobalMid_Lock);
172 list_for_each(tmp, &server->pending_mid_q) {
173 mid_entry = list_entry(tmp, struct
174 mid_q_entry,
175 qhead);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000176 if (mid_entry) {
177 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French09d1db52005-04-28 22:41:08 -0700178 /* Mark other intransit requests as needing
179 retry so we do not immediately mark the
180 session bad again (ie after we reconnect
181 below) as they timeout too */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 mid_entry->midState = MID_RETRY_NEEDED;
183 }
184 }
185 }
186 spin_unlock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000187 up(&server->tcpSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188
Steve French26f57362007-08-30 22:09:15 +0000189 while ((!kthread_should_stop()) && (server->tcpStatus != CifsGood)) {
Steve French6c3d8902006-07-31 22:46:20 +0000190 try_to_freeze();
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000191 if (server->protocolType == IPV6) {
192 rc = ipv6_connect(&server->addr.sockAddr6,
193 &server->ssocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000195 rc = ipv4_connect(&server->addr.sockAddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 &server->ssocket,
Steve Frencha10faeb22005-08-22 21:38:31 -0700197 server->workstation_RFC1001_name,
198 server->server_RFC1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000200 if (rc) {
201 cFYI(1, ("reconnect error %d", rc));
Steve French0cb766a2005-04-28 22:41:11 -0700202 msleep(3000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 } else {
204 atomic_inc(&tcpSesReconnectCount);
205 spin_lock(&GlobalMid_Lock);
Steve French26f57362007-08-30 22:09:15 +0000206 if (!kthread_should_stop())
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 server->tcpStatus = CifsGood;
Steve Frenchad009ac2005-04-28 22:41:05 -0700208 server->sequence_number = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000209 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 /* atomic_set(&server->inFlight,0);*/
211 wake_up(&server->response_q);
212 }
213 }
214 return rc;
215}
216
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000217/*
Steve Frenche4eb2952005-04-28 22:41:09 -0700218 return codes:
219 0 not a transact2, or all data present
220 >0 transact2 with that much data missing
221 -EINVAL = invalid transact2
222
223 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000224static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize)
Steve Frenche4eb2952005-04-28 22:41:09 -0700225{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000226 struct smb_t2_rsp *pSMBt;
227 int total_data_size;
Steve Frenche4eb2952005-04-28 22:41:09 -0700228 int data_in_this_rsp;
229 int remaining;
230
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000231 if (pSMB->Command != SMB_COM_TRANSACTION2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700232 return 0;
233
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000234 /* check for plausible wct, bcc and t2 data and parm sizes */
235 /* check for parm and data offset going beyond end of smb */
236 if (pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
Steve French467a8f82007-06-27 22:41:32 +0000237 cFYI(1, ("invalid transact2 word count"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700238 return -EINVAL;
239 }
240
241 pSMBt = (struct smb_t2_rsp *)pSMB;
242
243 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
244 data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
245
246 remaining = total_data_size - data_in_this_rsp;
247
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000248 if (remaining == 0)
Steve Frenche4eb2952005-04-28 22:41:09 -0700249 return 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000250 else if (remaining < 0) {
Steve French467a8f82007-06-27 22:41:32 +0000251 cFYI(1, ("total data %d smaller than data in frame %d",
Steve Frenche4eb2952005-04-28 22:41:09 -0700252 total_data_size, data_in_this_rsp));
253 return -EINVAL;
254 } else {
Steve French467a8f82007-06-27 22:41:32 +0000255 cFYI(1, ("missing %d bytes from transact2, check next response",
Steve Frenche4eb2952005-04-28 22:41:09 -0700256 remaining));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000257 if (total_data_size > maxBufSize) {
258 cERROR(1, ("TotalDataSize %d is over maximum buffer %d",
259 total_data_size, maxBufSize));
260 return -EINVAL;
Steve Frenche4eb2952005-04-28 22:41:09 -0700261 }
262 return remaining;
263 }
264}
265
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000266static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
Steve Frenche4eb2952005-04-28 22:41:09 -0700267{
268 struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
269 struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
270 int total_data_size;
271 int total_in_buf;
272 int remaining;
273 int total_in_buf2;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000274 char *data_area_of_target;
275 char *data_area_of_buf2;
Steve Frenche4eb2952005-04-28 22:41:09 -0700276 __u16 byte_count;
277
278 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
279
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000280 if (total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
Steve French63135e02007-07-17 17:34:02 +0000281 cFYI(1, ("total data size of primary and secondary t2 differ"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700282 }
283
284 total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
285
286 remaining = total_data_size - total_in_buf;
Steve French50c2f752007-07-13 00:33:32 +0000287
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000288 if (remaining < 0)
Steve Frenche4eb2952005-04-28 22:41:09 -0700289 return -EINVAL;
290
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000291 if (remaining == 0) /* nothing to do, ignore */
Steve Frenche4eb2952005-04-28 22:41:09 -0700292 return 0;
Steve French50c2f752007-07-13 00:33:32 +0000293
Steve Frenche4eb2952005-04-28 22:41:09 -0700294 total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000295 if (remaining < total_in_buf2) {
Steve French467a8f82007-06-27 22:41:32 +0000296 cFYI(1, ("transact2 2nd response contains too much data"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700297 }
298
299 /* find end of first SMB data area */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000300 data_area_of_target = (char *)&pSMBt->hdr.Protocol +
Steve Frenche4eb2952005-04-28 22:41:09 -0700301 le16_to_cpu(pSMBt->t2_rsp.DataOffset);
302 /* validate target area */
303
304 data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000305 le16_to_cpu(pSMB2->t2_rsp.DataOffset);
Steve Frenche4eb2952005-04-28 22:41:09 -0700306
307 data_area_of_target += total_in_buf;
308
309 /* copy second buffer into end of first buffer */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000310 memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2);
Steve Frenche4eb2952005-04-28 22:41:09 -0700311 total_in_buf += total_in_buf2;
312 pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
313 byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
314 byte_count += total_in_buf2;
315 BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
316
Steve French70ca7342005-09-22 16:32:06 -0700317 byte_count = pTargetSMB->smb_buf_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700318 byte_count += total_in_buf2;
319
320 /* BB also add check that we are not beyond maximum buffer size */
Steve French50c2f752007-07-13 00:33:32 +0000321
Steve French70ca7342005-09-22 16:32:06 -0700322 pTargetSMB->smb_buf_length = byte_count;
Steve Frenche4eb2952005-04-28 22:41:09 -0700323
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000324 if (remaining == total_in_buf2) {
Steve French467a8f82007-06-27 22:41:32 +0000325 cFYI(1, ("found the last secondary response"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700326 return 0; /* we are done */
327 } else /* more responses to go */
328 return 1;
329
330}
331
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332static int
333cifs_demultiplex_thread(struct TCP_Server_Info *server)
334{
335 int length;
336 unsigned int pdu_length, total_read;
337 struct smb_hdr *smb_buffer = NULL;
Steve Frenchb8643e12005-04-28 22:41:07 -0700338 struct smb_hdr *bigbuf = NULL;
339 struct smb_hdr *smallbuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 struct msghdr smb_msg;
341 struct kvec iov;
342 struct socket *csocket = server->ssocket;
343 struct list_head *tmp;
344 struct cifsSesInfo *ses;
345 struct task_struct *task_to_wake = NULL;
346 struct mid_q_entry *mid_entry;
Steve French70ca7342005-09-22 16:32:06 -0700347 char temp;
Steve Frenchb8643e12005-04-28 22:41:07 -0700348 int isLargeBuf = FALSE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700349 int isMultiRsp;
350 int reconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 current->flags |= PF_MEMALLOC;
353 server->tsk = current; /* save process info to wake at shutdown */
354 cFYI(1, ("Demultiplex PID: %d", current->pid));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000355 write_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 atomic_inc(&tcpSesAllocCount);
357 length = tcpSesAllocCount.counter;
358 write_unlock(&GlobalSMBSeslock);
Steve Frenchf1914012005-08-18 09:37:34 -0700359 complete(&cifsd_complete);
Steve French26f57362007-08-30 22:09:15 +0000360 if (length > 1)
361 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
362 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363
Rafael J. Wysocki83144182007-07-17 04:03:35 -0700364 set_freezable();
Igor Mammedovaaf737a2007-04-03 19:16:43 +0000365 while (!kthread_should_stop()) {
Steve Frenchede13272005-08-30 20:10:14 -0700366 if (try_to_freeze())
367 continue;
Steve Frenchb8643e12005-04-28 22:41:07 -0700368 if (bigbuf == NULL) {
369 bigbuf = cifs_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000370 if (!bigbuf) {
371 cERROR(1, ("No memory for large SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700372 msleep(3000);
373 /* retry will check if exiting */
374 continue;
375 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000376 } else if (isLargeBuf) {
377 /* we are reusing a dirty large buf, clear its start */
Steve French26f57362007-08-30 22:09:15 +0000378 memset(bigbuf, 0, sizeof(struct smb_hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700380
381 if (smallbuf == NULL) {
382 smallbuf = cifs_small_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000383 if (!smallbuf) {
384 cERROR(1, ("No memory for SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700385 msleep(1000);
386 /* retry will check if exiting */
387 continue;
388 }
389 /* beginning of smb buffer is cleared in our buf_get */
390 } else /* if existing small buf clear beginning */
Steve French26f57362007-08-30 22:09:15 +0000391 memset(smallbuf, 0, sizeof(struct smb_hdr));
Steve Frenchb8643e12005-04-28 22:41:07 -0700392
393 isLargeBuf = FALSE;
Steve Frenche4eb2952005-04-28 22:41:09 -0700394 isMultiRsp = FALSE;
Steve Frenchb8643e12005-04-28 22:41:07 -0700395 smb_buffer = smallbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 iov.iov_base = smb_buffer;
397 iov.iov_len = 4;
398 smb_msg.msg_control = NULL;
399 smb_msg.msg_controllen = 0;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000400 pdu_length = 4; /* enough to get RFC1001 header */
401incomplete_rcv:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 length =
403 kernel_recvmsg(csocket, &smb_msg,
Steve Frenchf01d5e12007-08-30 21:13:31 +0000404 &iov, 1, pdu_length, 0 /* BB other flags? */);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405
Steve French26f57362007-08-30 22:09:15 +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) {
Steve Frenchf01d5e12007-08-30 21:13:31 +0000439 cFYI(1, ("less than four bytes received (%d bytes)",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 length));
Steve Frenchf01d5e12007-08-30 21:13:31 +0000441 pdu_length -= length;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000442 msleep(1);
443 goto incomplete_rcv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 }
Steve French67010fb2005-04-28 22:41:09 -0700445
Steve French70ca7342005-09-22 16:32:06 -0700446 /* The right amount was read from socket - 4 bytes */
447 /* so we can now interpret the length field */
Steve French46810cb2005-04-28 22:41:09 -0700448
Steve French70ca7342005-09-22 16:32:06 -0700449 /* the first byte big endian of the length field,
450 is actually not part of the length but the type
451 with the most common, zero, as regular data */
452 temp = *((char *) smb_buffer);
453
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000454 /* Note that FC 1001 length is big endian on the wire,
Steve French70ca7342005-09-22 16:32:06 -0700455 but we convert it here so it is always manipulated
456 as host byte order */
Steve French46810cb2005-04-28 22:41:09 -0700457 pdu_length = ntohl(smb_buffer->smb_buf_length);
Steve French70ca7342005-09-22 16:32:06 -0700458 smb_buffer->smb_buf_length = pdu_length;
Steve French46810cb2005-04-28 22:41:09 -0700459
Steve French467a8f82007-06-27 22:41:32 +0000460 cFYI(1, ("rfc1002 length 0x%x", pdu_length+4));
Steve French70ca7342005-09-22 16:32:06 -0700461
462 if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000463 continue;
Steve French70ca7342005-09-22 16:32:06 -0700464 } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
Steve French467a8f82007-06-27 22:41:32 +0000465 cFYI(1, ("Good RFC 1002 session rsp"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700466 continue;
Steve French70ca7342005-09-22 16:32:06 -0700467 } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000468 /* we get this from Windows 98 instead of
Steve French46810cb2005-04-28 22:41:09 -0700469 an error on SMB negprot response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000470 cFYI(1, ("Negative RFC1002 Session Response Error 0x%x)",
Steve French70ca7342005-09-22 16:32:06 -0700471 pdu_length));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000472 if (server->tcpStatus == CifsNew) {
473 /* if nack on negprot (rather than
Steve French46810cb2005-04-28 22:41:09 -0700474 ret of smb negprot error) reconnecting
475 not going to help, ret error to mount */
476 break;
477 } else {
478 /* give server a second to
479 clean up before reconnect attempt */
480 msleep(1000);
481 /* always try 445 first on reconnect
482 since we get NACK on some if we ever
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000483 connected to port 139 (the NACK is
Steve French46810cb2005-04-28 22:41:09 -0700484 since we do not begin with RFC1001
485 session initialize frame) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000486 server->addr.sockAddr.sin_port =
Steve French46810cb2005-04-28 22:41:09 -0700487 htons(CIFS_PORT);
488 cifs_reconnect(server);
489 csocket = server->ssocket;
490 wake_up(&server->response_q);
491 continue;
492 }
Steve French70ca7342005-09-22 16:32:06 -0700493 } else if (temp != (char) 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000494 cERROR(1, ("Unknown RFC 1002 frame"));
Steve French70ca7342005-09-22 16:32:06 -0700495 cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
496 length);
Steve French46810cb2005-04-28 22:41:09 -0700497 cifs_reconnect(server);
498 csocket = server->ssocket;
499 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700500 }
501
502 /* else we have an SMB response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000503 if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French26f57362007-08-30 22:09:15 +0000504 (pdu_length < sizeof(struct smb_hdr) - 1 - 4)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700505 cERROR(1, ("Invalid size SMB length %d pdu_length %d",
Steve French46810cb2005-04-28 22:41:09 -0700506 length, pdu_length+4));
Steve Frenche4eb2952005-04-28 22:41:09 -0700507 cifs_reconnect(server);
508 csocket = server->ssocket;
509 wake_up(&server->response_q);
510 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000511 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700512
513 /* else length ok */
514 reconnect = 0;
515
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000516 if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700517 isLargeBuf = TRUE;
518 memcpy(bigbuf, smallbuf, 4);
519 smb_buffer = bigbuf;
520 }
521 length = 0;
522 iov.iov_base = 4 + (char *)smb_buffer;
523 iov.iov_len = pdu_length;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000524 for (total_read = 0; total_read < pdu_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700525 total_read += length) {
526 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
527 pdu_length - total_read, 0);
Steve French26f57362007-08-30 22:09:15 +0000528 if (kthread_should_stop() ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700529 (length == -EINTR)) {
530 /* then will exit */
531 reconnect = 2;
532 break;
533 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700534 cifs_reconnect(server);
535 csocket = server->ssocket;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000536 /* Reconnect wakes up rspns q */
Steve Frenche4eb2952005-04-28 22:41:09 -0700537 /* Now we will reread sock */
538 reconnect = 1;
539 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000540 } else if ((length == -ERESTARTSYS) ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700541 (length == -EAGAIN)) {
542 msleep(1); /* minimum sleep to prevent looping,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000543 allowing socket to clear and app
Steve Frenche4eb2952005-04-28 22:41:09 -0700544 threads to set tcpStatus
545 CifsNeedReconnect if server hung*/
Steve French46810cb2005-04-28 22:41:09 -0700546 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700547 } else if (length <= 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000548 cERROR(1, ("Received no data, expecting %d",
Steve Frenche4eb2952005-04-28 22:41:09 -0700549 pdu_length - total_read));
550 cifs_reconnect(server);
551 csocket = server->ssocket;
552 reconnect = 1;
553 break;
Steve French46810cb2005-04-28 22:41:09 -0700554 }
555 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000556 if (reconnect == 2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700557 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000558 else if (reconnect == 1)
Steve Frenche4eb2952005-04-28 22:41:09 -0700559 continue;
560
561 length += 4; /* account for rfc1002 hdr */
Steve French50c2f752007-07-13 00:33:32 +0000562
Steve Frenche4eb2952005-04-28 22:41:09 -0700563
564 dump_smb(smb_buffer, length);
Steve French184ed212006-02-24 06:15:11 +0000565 if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700566 cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
Steve Frenche4eb2952005-04-28 22:41:09 -0700567 continue;
568 }
569
570
571 task_to_wake = NULL;
572 spin_lock(&GlobalMid_Lock);
573 list_for_each(tmp, &server->pending_mid_q) {
574 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
575
Steve French50c2f752007-07-13 00:33:32 +0000576 if ((mid_entry->mid == smb_buffer->Mid) &&
Steve Frenche4eb2952005-04-28 22:41:09 -0700577 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
578 (mid_entry->command == smb_buffer->Command)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000579 if (check2ndT2(smb_buffer,server->maxBuf) > 0) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700580 /* We have a multipart transact2 resp */
Steve Frenchcd634992005-04-28 22:41:10 -0700581 isMultiRsp = TRUE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000582 if (mid_entry->resp_buf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700583 /* merge response - fix up 1st*/
Steve French50c2f752007-07-13 00:33:32 +0000584 if (coalesce_t2(smb_buffer,
Steve Frenche4eb2952005-04-28 22:41:09 -0700585 mid_entry->resp_buf)) {
Steve French39798772006-05-31 22:40:51 +0000586 mid_entry->multiRsp = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700587 break;
588 } else {
589 /* all parts received */
Steve French39798772006-05-31 22:40:51 +0000590 mid_entry->multiEnd = 1;
Steve French50c2f752007-07-13 00:33:32 +0000591 goto multi_t2_fnd;
Steve Frenche4eb2952005-04-28 22:41:09 -0700592 }
593 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000594 if (!isLargeBuf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700595 cERROR(1,("1st trans2 resp needs bigbuf"));
596 /* BB maybe we can fix this up, switch
Steve French50c2f752007-07-13 00:33:32 +0000597 to already allocated large buffer? */
Steve Frenche4eb2952005-04-28 22:41:09 -0700598 } else {
Steve Frenchcd634992005-04-28 22:41:10 -0700599 /* Have first buffer */
Steve Frenche4eb2952005-04-28 22:41:09 -0700600 mid_entry->resp_buf =
601 smb_buffer;
602 mid_entry->largeBuf = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700603 bigbuf = NULL;
604 }
605 }
606 break;
Steve French50c2f752007-07-13 00:33:32 +0000607 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700608 mid_entry->resp_buf = smb_buffer;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000609 if (isLargeBuf)
Steve Frenche4eb2952005-04-28 22:41:09 -0700610 mid_entry->largeBuf = 1;
611 else
612 mid_entry->largeBuf = 0;
613multi_t2_fnd:
614 task_to_wake = mid_entry->tsk;
615 mid_entry->midState = MID_RESPONSE_RECEIVED;
Steve French1047abc2005-10-11 19:58:06 -0700616#ifdef CONFIG_CIFS_STATS2
617 mid_entry->when_received = jiffies;
618#endif
Steve French3a5ff612006-07-14 22:37:11 +0000619 /* so we do not time out requests to server
620 which is still responding (since server could
621 be busy but not dead) */
622 server->lstrp = jiffies;
Steve Frenche4eb2952005-04-28 22:41:09 -0700623 break;
624 }
625 }
626 spin_unlock(&GlobalMid_Lock);
627 if (task_to_wake) {
Steve Frenchcd634992005-04-28 22:41:10 -0700628 /* Was previous buf put in mpx struct for multi-rsp? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000629 if (!isMultiRsp) {
Steve Frenchcd634992005-04-28 22:41:10 -0700630 /* smb buffer will be freed by user thread */
Steve French26f57362007-08-30 22:09:15 +0000631 if (isLargeBuf)
Steve Frenchcd634992005-04-28 22:41:10 -0700632 bigbuf = NULL;
Steve French26f57362007-08-30 22:09:15 +0000633 else
Steve Frenchcd634992005-04-28 22:41:10 -0700634 smallbuf = NULL;
635 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700636 wake_up_process(task_to_wake);
Steve Frenchd7c8c942006-03-03 10:43:49 +0000637 } else if ((is_valid_oplock_break(smb_buffer, server) == FALSE)
Steve French50c2f752007-07-13 00:33:32 +0000638 && (isMultiRsp == FALSE)) {
639 cERROR(1, ("No task to wake, unknown frame received! "
640 "NumMids %d", midCount.counter));
641 cifs_dump_mem("Received Data is: ", (char *)smb_buffer,
Steve French70ca7342005-09-22 16:32:06 -0700642 sizeof(struct smb_hdr));
Steve French39798772006-05-31 22:40:51 +0000643#ifdef CONFIG_CIFS_DEBUG2
644 cifs_dump_detail(smb_buffer);
645 cifs_dump_mids(server);
646#endif /* CIFS_DEBUG2 */
Steve French50c2f752007-07-13 00:33:32 +0000647
Steve Frenche4eb2952005-04-28 22:41:09 -0700648 }
649 } /* end while !EXITING */
650
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 spin_lock(&GlobalMid_Lock);
652 server->tcpStatus = CifsExiting;
653 server->tsk = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700654 /* check if we have blocked requests that need to free */
655 /* Note that cifs_max_pending is normally 50, but
656 can be set at module install time to as little as two */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000657 if (atomic_read(&server->inFlight) >= cifs_max_pending)
Steve French31ca3bc2005-04-28 22:41:11 -0700658 atomic_set(&server->inFlight, cifs_max_pending - 1);
659 /* We do not want to set the max_pending too low or we
660 could end up with the counter going negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +0000662 /* Although there should not be any requests blocked on
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700664 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 to the same server - they now will see the session is in exit state
666 and get out of SendReceive. */
667 wake_up_all(&server->request_q);
668 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700669 msleep(125);
Steve French50c2f752007-07-13 00:33:32 +0000670
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000671 if (server->ssocket) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 sock_release(csocket);
673 server->ssocket = NULL;
674 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700675 /* buffer usuallly freed in free_mid - need to free it here on exit */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +0000676 cifs_buf_release(bigbuf);
677 if (smallbuf) /* no sense logging a debug message if NULL */
Steve Frenchb8643e12005-04-28 22:41:07 -0700678 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679
680 read_lock(&GlobalSMBSeslock);
681 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700682 /* loop through server session structures attached to this and
683 mark them dead */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 list_for_each(tmp, &GlobalSMBSessionList) {
685 ses =
686 list_entry(tmp, struct cifsSesInfo,
687 cifsSessionList);
688 if (ses->server == server) {
689 ses->status = CifsExiting;
690 ses->server = NULL;
691 }
692 }
693 read_unlock(&GlobalSMBSeslock);
694 } else {
Steve French31ca3bc2005-04-28 22:41:11 -0700695 /* although we can not zero the server struct pointer yet,
696 since there are active requests which may depnd on them,
697 mark the corresponding SMB sessions as exiting too */
698 list_for_each(tmp, &GlobalSMBSessionList) {
699 ses = list_entry(tmp, struct cifsSesInfo,
700 cifsSessionList);
Steve French26f57362007-08-30 22:09:15 +0000701 if (ses->server == server)
Steve French31ca3bc2005-04-28 22:41:11 -0700702 ses->status = CifsExiting;
Steve French31ca3bc2005-04-28 22:41:11 -0700703 }
704
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 spin_lock(&GlobalMid_Lock);
706 list_for_each(tmp, &server->pending_mid_q) {
707 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
708 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French50c2f752007-07-13 00:33:32 +0000709 cFYI(1, ("Clearing Mid 0x%x - waking up ",
710 mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 task_to_wake = mid_entry->tsk;
Steve French26f57362007-08-30 22:09:15 +0000712 if (task_to_wake)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 wake_up_process(task_to_wake);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 }
715 }
716 spin_unlock(&GlobalMid_Lock);
717 read_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700719 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 }
721
Steve Frenchf1914012005-08-18 09:37:34 -0700722 if (!list_empty(&server->pending_mid_q)) {
Steve French50c2f752007-07-13 00:33:32 +0000723 /* mpx threads have not exited yet give them
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700725 /* due to delays on oplock break requests, we need
726 to wait at least 45 seconds before giving up
727 on a request getting a response and going ahead
728 and killing cifsd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve French31ca3bc2005-04-28 22:41:11 -0700730 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 /* if threads still have not exited they are probably never
732 coming home not much else we can do but free the memory */
733 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734
735 write_lock(&GlobalSMBSeslock);
736 atomic_dec(&tcpSesAllocCount);
737 length = tcpSesAllocCount.counter;
Steve French31ca3bc2005-04-28 22:41:11 -0700738
739 /* last chance to mark ses pointers invalid
740 if there are any pointing to this (e.g
Steve French50c2f752007-07-13 00:33:32 +0000741 if a crazy root user tried to kill cifsd
Steve French31ca3bc2005-04-28 22:41:11 -0700742 kernel thread explicitly this might happen) */
743 list_for_each(tmp, &GlobalSMBSessionList) {
744 ses = list_entry(tmp, struct cifsSesInfo,
745 cifsSessionList);
Steve French26f57362007-08-30 22:09:15 +0000746 if (ses->server == server)
Steve French31ca3bc2005-04-28 22:41:11 -0700747 ses->server = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700748 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 write_unlock(&GlobalSMBSeslock);
Steve French31ca3bc2005-04-28 22:41:11 -0700750
751 kfree(server);
Steve French26f57362007-08-30 22:09:15 +0000752 if (length > 0)
753 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
754 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +0000755
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 return 0;
757}
758
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759static int
Steve French50c2f752007-07-13 00:33:32 +0000760cifs_parse_mount_options(char *options, const char *devname,
761 struct smb_vol *vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762{
763 char *value;
764 char *data;
765 unsigned int temp_len, i, j;
766 char separator[2];
767
768 separator[0] = ',';
Steve French50c2f752007-07-13 00:33:32 +0000769 separator[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770
Linus Torvalds12e36b22006-10-13 08:09:29 -0700771 if (Local_System_Name[0] != 0)
Steve French50c2f752007-07-13 00:33:32 +0000772 memcpy(vol->source_rfc1001_name, Local_System_Name, 15);
Steve French2cd646a2006-09-28 19:43:08 +0000773 else {
Linus Torvalds12e36b22006-10-13 08:09:29 -0700774 char *nodename = utsname()->nodename;
Steve French50c2f752007-07-13 00:33:32 +0000775 int n = strnlen(nodename, 15);
776 memset(vol->source_rfc1001_name, 0x20, 15);
777 for (i = 0; i < n; i++) {
Steve French2cd646a2006-09-28 19:43:08 +0000778 /* does not have to be perfect mapping since field is
779 informational, only used for servers that do not support
780 port 445 and it can be overridden at mount time */
Linus Torvalds12e36b22006-10-13 08:09:29 -0700781 vol->source_rfc1001_name[i] = toupper(nodename[i]);
Steve French2cd646a2006-09-28 19:43:08 +0000782 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 }
784 vol->source_rfc1001_name[15] = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -0700785 /* null target name indicates to use *SMBSERVR default called name
786 if we end up sending RFC1001 session initialize */
787 vol->target_rfc1001_name[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 vol->linux_uid = current->uid; /* current->euid instead? */
789 vol->linux_gid = current->gid;
790 vol->dir_mode = S_IRWXUGO;
791 /* 2767 perms indicate mandatory locking support */
792 vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);
793
794 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
795 vol->rw = TRUE;
Jeremy Allisonac670552005-06-22 17:26:35 -0700796 /* default is always to request posix paths. */
797 vol->posix_paths = 1;
798
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 if (!options)
800 return 1;
801
Steve French50c2f752007-07-13 00:33:32 +0000802 if (strncmp(options, "sep=", 4) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000803 if (options[4] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 separator[0] = options[4];
805 options += 5;
806 } else {
Steve French467a8f82007-06-27 22:41:32 +0000807 cFYI(1, ("Null separator not allowed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 }
809 }
Steve French50c2f752007-07-13 00:33:32 +0000810
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 while ((data = strsep(&options, separator)) != NULL) {
812 if (!*data)
813 continue;
814 if ((value = strchr(data, '=')) != NULL)
815 *value++ = '\0';
816
Steve French50c2f752007-07-13 00:33:32 +0000817 /* Have to parse this before we parse for "user" */
818 if (strnicmp(data, "user_xattr", 10) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 vol->no_xattr = 0;
Steve French50c2f752007-07-13 00:33:32 +0000820 } else if (strnicmp(data, "nouser_xattr", 12) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 vol->no_xattr = 1;
822 } else if (strnicmp(data, "user", 4) == 0) {
Steve French4b952a92006-10-30 21:46:13 +0000823 if (!value) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 printk(KERN_WARNING
825 "CIFS: invalid or missing username\n");
826 return 1; /* needs_arg; */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000827 } else if (!*value) {
Steve French4b952a92006-10-30 21:46:13 +0000828 /* null user, ie anonymous, authentication */
829 vol->nullauth = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 }
831 if (strnlen(value, 200) < 200) {
832 vol->username = value;
833 } else {
834 printk(KERN_WARNING "CIFS: username too long\n");
835 return 1;
836 }
837 } else if (strnicmp(data, "pass", 4) == 0) {
838 if (!value) {
839 vol->password = NULL;
840 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000841 } else if (value[0] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 /* check if string begins with double comma
843 since that would mean the password really
844 does start with a comma, and would not
845 indicate an empty string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000846 if (value[1] != separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 vol->password = NULL;
848 continue;
849 }
850 }
851 temp_len = strlen(value);
852 /* removed password length check, NTLM passwords
853 can be arbitrarily long */
854
Steve French50c2f752007-07-13 00:33:32 +0000855 /* if comma in password, the string will be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 prematurely null terminated. Commas in password are
857 specified across the cifs mount interface by a double
858 comma ie ,, and a comma used as in other cases ie ','
859 as a parameter delimiter/separator is single and due
860 to the strsep above is temporarily zeroed. */
861
862 /* NB: password legally can have multiple commas and
863 the only illegal character in a password is null */
864
Steve French50c2f752007-07-13 00:33:32 +0000865 if ((value[temp_len] == 0) &&
Steve French09d1db52005-04-28 22:41:08 -0700866 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 /* reinsert comma */
868 value[temp_len] = separator[0];
Steve French50c2f752007-07-13 00:33:32 +0000869 temp_len += 2; /* move after second comma */
870 while (value[temp_len] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 if (value[temp_len] == separator[0]) {
Steve French50c2f752007-07-13 00:33:32 +0000872 if (value[temp_len+1] ==
Steve French09d1db52005-04-28 22:41:08 -0700873 separator[0]) {
874 /* skip second comma */
875 temp_len++;
Steve French50c2f752007-07-13 00:33:32 +0000876 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 /* single comma indicating start
878 of next parm */
879 break;
880 }
881 }
882 temp_len++;
883 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000884 if (value[temp_len] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 options = NULL;
886 } else {
887 value[temp_len] = 0;
888 /* point option to start of next parm */
889 options = value + temp_len + 1;
890 }
Steve French50c2f752007-07-13 00:33:32 +0000891 /* go from value to value + temp_len condensing
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 double commas to singles. Note that this ends up
893 allocating a few bytes too many, which is ok */
Pekka Enberge915fc42005-09-06 15:18:35 -0700894 vol->password = kzalloc(temp_len, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000895 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000896 printk(KERN_WARNING "CIFS: no memory "
897 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700898 return 1;
899 }
Steve French50c2f752007-07-13 00:33:32 +0000900 for (i = 0, j = 0; i < temp_len; i++, j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 vol->password[j] = value[i];
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000902 if (value[i] == separator[0]
Steve French09d1db52005-04-28 22:41:08 -0700903 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 /* skip second comma */
905 i++;
906 }
907 }
908 vol->password[j] = 0;
909 } else {
Pekka Enberge915fc42005-09-06 15:18:35 -0700910 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000911 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000912 printk(KERN_WARNING "CIFS: no memory "
913 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700914 return 1;
915 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 strcpy(vol->password, value);
917 }
918 } else if (strnicmp(data, "ip", 2) == 0) {
919 if (!value || !*value) {
920 vol->UNCip = NULL;
921 } else if (strnlen(value, 35) < 35) {
922 vol->UNCip = value;
923 } else {
Steve French50c2f752007-07-13 00:33:32 +0000924 printk(KERN_WARNING "CIFS: ip address "
925 "too long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 return 1;
927 }
Steve French50c2f752007-07-13 00:33:32 +0000928 } else if (strnicmp(data, "sec", 3) == 0) {
929 if (!value || !*value) {
930 cERROR(1, ("no security value specified"));
931 continue;
932 } else if (strnicmp(value, "krb5i", 5) == 0) {
933 vol->secFlg |= CIFSSEC_MAY_KRB5 |
Steve French189acaa2006-06-23 02:33:48 +0000934 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800935 } else if (strnicmp(value, "krb5p", 5) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000936 /* vol->secFlg |= CIFSSEC_MUST_SEAL |
937 CIFSSEC_MAY_KRB5; */
938 cERROR(1, ("Krb5 cifs privacy not supported"));
Steve Frenchbf820672005-12-01 22:32:42 -0800939 return 1;
940 } else if (strnicmp(value, "krb5", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000941 vol->secFlg |= CIFSSEC_MAY_KRB5;
Steve Frenchbf820672005-12-01 22:32:42 -0800942 } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000943 vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
Steve French189acaa2006-06-23 02:33:48 +0000944 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800945 } else if (strnicmp(value, "ntlmv2", 6) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000946 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve Frenchbf820672005-12-01 22:32:42 -0800947 } else if (strnicmp(value, "ntlmi", 5) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000948 vol->secFlg |= CIFSSEC_MAY_NTLM |
Steve French189acaa2006-06-23 02:33:48 +0000949 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800950 } else if (strnicmp(value, "ntlm", 4) == 0) {
951 /* ntlm is default so can be turned off too */
Steve French750d1152006-06-27 06:28:30 +0000952 vol->secFlg |= CIFSSEC_MAY_NTLM;
Steve Frenchbf820672005-12-01 22:32:42 -0800953 } else if (strnicmp(value, "nontlm", 6) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000954 /* BB is there a better way to do this? */
Steve French750d1152006-06-27 06:28:30 +0000955 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve French189acaa2006-06-23 02:33:48 +0000956#ifdef CONFIG_CIFS_WEAK_PW_HASH
957 } else if (strnicmp(value, "lanman", 6) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000958 vol->secFlg |= CIFSSEC_MAY_LANMAN;
Steve French189acaa2006-06-23 02:33:48 +0000959#endif
Steve Frenchbf820672005-12-01 22:32:42 -0800960 } else if (strnicmp(value, "none", 4) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000961 vol->nullauth = 1;
Steve French50c2f752007-07-13 00:33:32 +0000962 } else {
963 cERROR(1, ("bad security option: %s", value));
964 return 1;
965 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 } else if ((strnicmp(data, "unc", 3) == 0)
967 || (strnicmp(data, "target", 6) == 0)
968 || (strnicmp(data, "path", 4) == 0)) {
969 if (!value || !*value) {
Steve French50c2f752007-07-13 00:33:32 +0000970 printk(KERN_WARNING "CIFS: invalid path to "
971 "network resource\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 return 1; /* needs_arg; */
973 }
974 if ((temp_len = strnlen(value, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +0000975 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +0000976 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 return 1;
Steve French50c2f752007-07-13 00:33:32 +0000978 strcpy(vol->UNC, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 if (strncmp(vol->UNC, "//", 2) == 0) {
980 vol->UNC[0] = '\\';
981 vol->UNC[1] = '\\';
Steve French50c2f752007-07-13 00:33:32 +0000982 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 printk(KERN_WARNING
Steve French50c2f752007-07-13 00:33:32 +0000984 "CIFS: UNC Path does not begin "
985 "with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 return 1;
987 }
988 } else {
989 printk(KERN_WARNING "CIFS: UNC name too long\n");
990 return 1;
991 }
992 } else if ((strnicmp(data, "domain", 3) == 0)
993 || (strnicmp(data, "workgroup", 5) == 0)) {
994 if (!value || !*value) {
995 printk(KERN_WARNING "CIFS: invalid domain name\n");
996 return 1; /* needs_arg; */
997 }
998 /* BB are there cases in which a comma can be valid in
999 a domain name and need special handling? */
Steve French39798772006-05-31 22:40:51 +00001000 if (strnlen(value, 256) < 256) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 vol->domainname = value;
1002 cFYI(1, ("Domain name set"));
1003 } else {
Steve French50c2f752007-07-13 00:33:32 +00001004 printk(KERN_WARNING "CIFS: domain name too "
1005 "long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 return 1;
1007 }
Steve French50c2f752007-07-13 00:33:32 +00001008 } else if (strnicmp(data, "prefixpath", 10) == 0) {
1009 if (!value || !*value) {
1010 printk(KERN_WARNING
1011 "CIFS: invalid path prefix\n");
1012 return 1; /* needs_argument */
1013 }
1014 if ((temp_len = strnlen(value, 1024)) < 1024) {
Steve French4523cc32007-04-30 20:13:06 +00001015 if (value[0] != '/')
Steve French2fe87f02006-09-21 07:02:52 +00001016 temp_len++; /* missing leading slash */
Steve French50c2f752007-07-13 00:33:32 +00001017 vol->prepath = kmalloc(temp_len+1, GFP_KERNEL);
1018 if (vol->prepath == NULL)
1019 return 1;
Steve French4523cc32007-04-30 20:13:06 +00001020 if (value[0] != '/') {
Steve French2fe87f02006-09-21 07:02:52 +00001021 vol->prepath[0] = '/';
Steve French50c2f752007-07-13 00:33:32 +00001022 strcpy(vol->prepath+1, value);
Steve French2fe87f02006-09-21 07:02:52 +00001023 } else
Steve French50c2f752007-07-13 00:33:32 +00001024 strcpy(vol->prepath, value);
1025 cFYI(1, ("prefix path %s", vol->prepath));
1026 } else {
1027 printk(KERN_WARNING "CIFS: prefix too long\n");
1028 return 1;
1029 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 } else if (strnicmp(data, "iocharset", 9) == 0) {
1031 if (!value || !*value) {
Steve French63135e02007-07-17 17:34:02 +00001032 printk(KERN_WARNING "CIFS: invalid iocharset "
1033 "specified\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 return 1; /* needs_arg; */
1035 }
1036 if (strnlen(value, 65) < 65) {
Steve French50c2f752007-07-13 00:33:32 +00001037 if (strnicmp(value, "default", 7))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 vol->iocharset = value;
Steve French50c2f752007-07-13 00:33:32 +00001039 /* if iocharset not set then load_nls_default
1040 is used by caller */
1041 cFYI(1, ("iocharset set to %s", value));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 } else {
Steve French63135e02007-07-17 17:34:02 +00001043 printk(KERN_WARNING "CIFS: iocharset name "
1044 "too long.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 return 1;
1046 }
1047 } else if (strnicmp(data, "uid", 3) == 0) {
1048 if (value && *value) {
1049 vol->linux_uid =
1050 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001051 vol->override_uid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 }
1053 } else if (strnicmp(data, "gid", 3) == 0) {
1054 if (value && *value) {
1055 vol->linux_gid =
1056 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001057 vol->override_gid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 }
1059 } else if (strnicmp(data, "file_mode", 4) == 0) {
1060 if (value && *value) {
1061 vol->file_mode =
1062 simple_strtoul(value, &value, 0);
1063 }
1064 } else if (strnicmp(data, "dir_mode", 4) == 0) {
1065 if (value && *value) {
1066 vol->dir_mode =
1067 simple_strtoul(value, &value, 0);
1068 }
1069 } else if (strnicmp(data, "dirmode", 4) == 0) {
1070 if (value && *value) {
1071 vol->dir_mode =
1072 simple_strtoul(value, &value, 0);
1073 }
1074 } else if (strnicmp(data, "port", 4) == 0) {
1075 if (value && *value) {
1076 vol->port =
1077 simple_strtoul(value, &value, 0);
1078 }
1079 } else if (strnicmp(data, "rsize", 5) == 0) {
1080 if (value && *value) {
1081 vol->rsize =
1082 simple_strtoul(value, &value, 0);
1083 }
1084 } else if (strnicmp(data, "wsize", 5) == 0) {
1085 if (value && *value) {
1086 vol->wsize =
1087 simple_strtoul(value, &value, 0);
1088 }
1089 } else if (strnicmp(data, "sockopt", 5) == 0) {
1090 if (value && *value) {
1091 vol->sockopt =
1092 simple_strtoul(value, &value, 0);
1093 }
1094 } else if (strnicmp(data, "netbiosname", 4) == 0) {
1095 if (!value || !*value || (*value == ' ')) {
Steve French63135e02007-07-17 17:34:02 +00001096 cFYI(1, ("invalid (empty) netbiosname"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 } else {
Steve French50c2f752007-07-13 00:33:32 +00001098 memset(vol->source_rfc1001_name, 0x20, 15);
1099 for (i = 0; i < 15; i++) {
1100 /* BB are there cases in which a comma can be
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 valid in this workstation netbios name (and need
1102 special handling)? */
1103
1104 /* We do not uppercase netbiosname for user */
Steve French50c2f752007-07-13 00:33:32 +00001105 if (value[i] == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 break;
Steve French50c2f752007-07-13 00:33:32 +00001107 else
1108 vol->source_rfc1001_name[i] =
1109 value[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 }
1111 /* The string has 16th byte zero still from
1112 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001113 if ((i == 15) && (value[i] != 0))
1114 printk(KERN_WARNING "CIFS: netbiosname"
1115 " longer than 15 truncated.\n");
Steve Frencha10faeb22005-08-22 21:38:31 -07001116 }
1117 } else if (strnicmp(data, "servern", 7) == 0) {
1118 /* servernetbiosname specified override *SMBSERVER */
1119 if (!value || !*value || (*value == ' ')) {
Steve French467a8f82007-06-27 22:41:32 +00001120 cFYI(1, ("empty server netbiosname specified"));
Steve Frencha10faeb22005-08-22 21:38:31 -07001121 } else {
1122 /* last byte, type, is 0x20 for servr type */
Steve French50c2f752007-07-13 00:33:32 +00001123 memset(vol->target_rfc1001_name, 0x20, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001124
Steve French50c2f752007-07-13 00:33:32 +00001125 for (i = 0; i < 15; i++) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001126 /* BB are there cases in which a comma can be
Steve French50c2f752007-07-13 00:33:32 +00001127 valid in this workstation netbios name
1128 (and need special handling)? */
Steve Frencha10faeb22005-08-22 21:38:31 -07001129
Steve French50c2f752007-07-13 00:33:32 +00001130 /* user or mount helper must uppercase
1131 the netbiosname */
1132 if (value[i] == 0)
Steve Frencha10faeb22005-08-22 21:38:31 -07001133 break;
1134 else
Steve French50c2f752007-07-13 00:33:32 +00001135 vol->target_rfc1001_name[i] =
1136 value[i];
Steve Frencha10faeb22005-08-22 21:38:31 -07001137 }
1138 /* The string has 16th byte zero still from
1139 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001140 if ((i == 15) && (value[i] != 0))
1141 printk(KERN_WARNING "CIFS: server net"
1142 "biosname longer than 15 truncated.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 }
1144 } else if (strnicmp(data, "credentials", 4) == 0) {
1145 /* ignore */
1146 } else if (strnicmp(data, "version", 3) == 0) {
1147 /* ignore */
Steve French50c2f752007-07-13 00:33:32 +00001148 } else if (strnicmp(data, "guest", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 /* ignore */
1150 } else if (strnicmp(data, "rw", 2) == 0) {
1151 vol->rw = TRUE;
1152 } else if ((strnicmp(data, "suid", 4) == 0) ||
1153 (strnicmp(data, "nosuid", 6) == 0) ||
1154 (strnicmp(data, "exec", 4) == 0) ||
1155 (strnicmp(data, "noexec", 6) == 0) ||
1156 (strnicmp(data, "nodev", 5) == 0) ||
1157 (strnicmp(data, "noauto", 6) == 0) ||
1158 (strnicmp(data, "dev", 3) == 0)) {
1159 /* The mount tool or mount.cifs helper (if present)
Steve French50c2f752007-07-13 00:33:32 +00001160 uses these opts to set flags, and the flags are read
1161 by the kernel vfs layer before we get here (ie
1162 before read super) so there is no point trying to
1163 parse these options again and set anything and it
1164 is ok to just ignore them */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 continue;
1166 } else if (strnicmp(data, "ro", 2) == 0) {
1167 vol->rw = FALSE;
1168 } else if (strnicmp(data, "hard", 4) == 0) {
1169 vol->retry = 1;
1170 } else if (strnicmp(data, "soft", 4) == 0) {
1171 vol->retry = 0;
1172 } else if (strnicmp(data, "perm", 4) == 0) {
1173 vol->noperm = 0;
1174 } else if (strnicmp(data, "noperm", 6) == 0) {
1175 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001176 } else if (strnicmp(data, "mapchars", 8) == 0) {
1177 vol->remap = 1;
1178 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1179 vol->remap = 0;
Steve French50c2f752007-07-13 00:33:32 +00001180 } else if (strnicmp(data, "sfu", 3) == 0) {
1181 vol->sfu_emul = 1;
1182 } else if (strnicmp(data, "nosfu", 5) == 0) {
1183 vol->sfu_emul = 0;
Jeremy Allisonac670552005-06-22 17:26:35 -07001184 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1185 vol->posix_paths = 1;
1186 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1187 vol->posix_paths = 0;
Steve Frenchc18c8422007-07-18 23:21:09 +00001188 } else if (strnicmp(data, "nounix", 6) == 0) {
1189 vol->no_linux_ext = 1;
1190 } else if (strnicmp(data, "nolinux", 7) == 0) {
1191 vol->no_linux_ext = 1;
Steve French50c2f752007-07-13 00:33:32 +00001192 } else if ((strnicmp(data, "nocase", 6) == 0) ||
Steve Frencha10faeb22005-08-22 21:38:31 -07001193 (strnicmp(data, "ignorecase", 10) == 0)) {
Steve French50c2f752007-07-13 00:33:32 +00001194 vol->nocase = 1;
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001195 } else if (strnicmp(data, "brl", 3) == 0) {
1196 vol->nobrl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001197 } else if ((strnicmp(data, "nobrl", 5) == 0) ||
Steve French1c955182005-08-30 20:58:07 -07001198 (strnicmp(data, "nolock", 6) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001199 vol->nobrl = 1;
Steve Frenchd3485d32005-08-19 11:04:29 -07001200 /* turn off mandatory locking in mode
1201 if remote locking is turned off since the
1202 local vfs will do advisory */
Steve French50c2f752007-07-13 00:33:32 +00001203 if (vol->file_mode ==
1204 (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
Steve Frenchd3485d32005-08-19 11:04:29 -07001205 vol->file_mode = S_IALLUGO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 } else if (strnicmp(data, "setuids", 7) == 0) {
1207 vol->setuids = 1;
1208 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1209 vol->setuids = 0;
1210 } else if (strnicmp(data, "nohard", 6) == 0) {
1211 vol->retry = 0;
1212 } else if (strnicmp(data, "nosoft", 6) == 0) {
1213 vol->retry = 1;
1214 } else if (strnicmp(data, "nointr", 6) == 0) {
1215 vol->intr = 0;
1216 } else if (strnicmp(data, "intr", 4) == 0) {
1217 vol->intr = 1;
Steve French50c2f752007-07-13 00:33:32 +00001218 } else if (strnicmp(data, "serverino", 7) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 vol->server_ino = 1;
Steve French50c2f752007-07-13 00:33:32 +00001220 } else if (strnicmp(data, "noserverino", 9) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 vol->server_ino = 0;
Steve French50c2f752007-07-13 00:33:32 +00001222 } else if (strnicmp(data, "cifsacl", 7) == 0) {
Steve French0a4b92c2006-01-12 15:44:21 -08001223 vol->cifs_acl = 1;
1224 } else if (strnicmp(data, "nocifsacl", 9) == 0) {
1225 vol->cifs_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001226 } else if (strnicmp(data, "acl", 3) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 vol->no_psx_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001228 } else if (strnicmp(data, "noacl", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 vol->no_psx_acl = 1;
Steve French50c2f752007-07-13 00:33:32 +00001230 } else if (strnicmp(data, "sign", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +00001231 vol->secFlg |= CIFSSEC_MUST_SIGN;
1232/* } else if (strnicmp(data, "seal",4) == 0) {
1233 vol->secFlg |= CIFSSEC_MUST_SEAL; */
Steve French50c2f752007-07-13 00:33:32 +00001234 } else if (strnicmp(data, "direct", 6) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001236 } else if (strnicmp(data, "forcedirectio", 13) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001238 } else if (strnicmp(data, "in6_addr", 8) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 if (!value || !*value) {
1240 vol->in6_addr = NULL;
1241 } else if (strnlen(value, 49) == 48) {
1242 vol->in6_addr = value;
1243 } else {
Steve French50c2f752007-07-13 00:33:32 +00001244 printk(KERN_WARNING "CIFS: ip v6 address not "
1245 "48 characters long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 return 1;
1247 }
1248 } else if (strnicmp(data, "noac", 4) == 0) {
Steve French50c2f752007-07-13 00:33:32 +00001249 printk(KERN_WARNING "CIFS: Mount option noac not "
1250 "supported. Instead set "
1251 "/proc/fs/cifs/LookupCacheEnabled to 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 } else
Steve French50c2f752007-07-13 00:33:32 +00001253 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",
1254 data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 }
1256 if (vol->UNC == NULL) {
Steve French4523cc32007-04-30 20:13:06 +00001257 if (devname == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001258 printk(KERN_WARNING "CIFS: Missing UNC name for mount "
1259 "target\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 return 1;
1261 }
1262 if ((temp_len = strnlen(devname, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001263 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001264 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001266 strcpy(vol->UNC, devname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 if (strncmp(vol->UNC, "//", 2) == 0) {
1268 vol->UNC[0] = '\\';
1269 vol->UNC[1] = '\\';
1270 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Steve French50c2f752007-07-13 00:33:32 +00001271 printk(KERN_WARNING "CIFS: UNC Path does not "
1272 "begin with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 return 1;
1274 }
1275 } else {
1276 printk(KERN_WARNING "CIFS: UNC name too long\n");
1277 return 1;
1278 }
1279 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001280 if (vol->UNCip == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 vol->UNCip = &vol->UNC[2];
1282
1283 return 0;
1284}
1285
1286static struct cifsSesInfo *
Steve French50c2f752007-07-13 00:33:32 +00001287cifs_find_tcp_session(struct in_addr *target_ip_addr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 struct in6_addr *target_ip6_addr,
1289 char *userName, struct TCP_Server_Info **psrvTcp)
1290{
1291 struct list_head *tmp;
1292 struct cifsSesInfo *ses;
1293 *psrvTcp = NULL;
1294 read_lock(&GlobalSMBSeslock);
1295
1296 list_for_each(tmp, &GlobalSMBSessionList) {
1297 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
1298 if (ses->server) {
Steve French50c2f752007-07-13 00:33:32 +00001299 if ((target_ip_addr &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 (ses->server->addr.sockAddr.sin_addr.s_addr
1301 == target_ip_addr->s_addr)) || (target_ip6_addr
1302 && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
Steve French50c2f752007-07-13 00:33:32 +00001303 target_ip6_addr, sizeof(*target_ip6_addr)))) {
1304 /* BB lock server and tcp session and increment
1305 use count here?? */
1306
1307 /* found a match on the TCP session */
1308 *psrvTcp = ses->server;
1309
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 /* BB check if reconnection needed */
1311 if (strncmp
1312 (ses->userName, userName,
1313 MAX_USERNAME_SIZE) == 0){
1314 read_unlock(&GlobalSMBSeslock);
Steve French50c2f752007-07-13 00:33:32 +00001315 /* Found exact match on both TCP and
1316 SMB sessions */
1317 return ses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 }
1319 }
1320 }
1321 /* else tcp and smb sessions need reconnection */
1322 }
1323 read_unlock(&GlobalSMBSeslock);
1324 return NULL;
1325}
1326
1327static struct cifsTconInfo *
1328find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
1329{
1330 struct list_head *tmp;
1331 struct cifsTconInfo *tcon;
1332
1333 read_lock(&GlobalSMBSeslock);
1334 list_for_each(tmp, &GlobalTreeConnectionList) {
Steve Frenche466e482006-08-15 13:07:18 +00001335 cFYI(1, ("Next tcon"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
1337 if (tcon->ses) {
1338 if (tcon->ses->server) {
1339 cFYI(1,
Steve Frenche466e482006-08-15 13:07:18 +00001340 ("old ip addr: %x == new ip %x ?",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 tcon->ses->server->addr.sockAddr.sin_addr.
1342 s_addr, new_target_ip_addr));
1343 if (tcon->ses->server->addr.sockAddr.sin_addr.
1344 s_addr == new_target_ip_addr) {
Steve Frenche466e482006-08-15 13:07:18 +00001345 /* BB lock tcon, server and tcp session and increment use count here? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 /* found a match on the TCP session */
1347 /* BB check if reconnection needed */
Steve French50c2f752007-07-13 00:33:32 +00001348 cFYI(1,
1349 ("IP match, old UNC: %s new: %s",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 tcon->treeName, uncName));
1351 if (strncmp
1352 (tcon->treeName, uncName,
1353 MAX_TREE_SIZE) == 0) {
1354 cFYI(1,
Steve Frenche466e482006-08-15 13:07:18 +00001355 ("and old usr: %s new: %s",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 tcon->treeName, uncName));
1357 if (strncmp
1358 (tcon->ses->userName,
1359 userName,
1360 MAX_USERNAME_SIZE) == 0) {
1361 read_unlock(&GlobalSMBSeslock);
Steve Frenche466e482006-08-15 13:07:18 +00001362 /* matched smb session
1363 (user name */
1364 return tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 }
1366 }
1367 }
1368 }
1369 }
1370 }
1371 read_unlock(&GlobalSMBSeslock);
1372 return NULL;
1373}
1374
1375int
1376connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
Steve French737b7582005-04-28 22:41:06 -07001377 const char *old_path, const struct nls_table *nls_codepage,
1378 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379{
1380 unsigned char *referrals = NULL;
1381 unsigned int num_referrals;
1382 int rc = 0;
1383
Steve French50c2f752007-07-13 00:33:32 +00001384 rc = get_dfs_path(xid, pSesInfo, old_path, nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001385 &num_referrals, &referrals, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386
1387 /* BB Add in code to: if valid refrl, if not ip address contact
Steve French50c2f752007-07-13 00:33:32 +00001388 the helper that resolves tcp names, mount to it, try to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 tcon to it unmount it if fail */
1390
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001391 kfree(referrals);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392
1393 return rc;
1394}
1395
1396int
Steve French50c2f752007-07-13 00:33:32 +00001397get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
1398 const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
1399 unsigned char **preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400{
1401 char *temp_unc;
1402 int rc = 0;
1403
1404 *pnum_referrals = 0;
1405
1406 if (pSesInfo->ipc_tid == 0) {
1407 temp_unc = kmalloc(2 /* for slashes */ +
Steve French50c2f752007-07-13 00:33:32 +00001408 strnlen(pSesInfo->serverName,
1409 SERVER_NAME_LEN_WITH_NULL * 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 + 1 + 4 /* slash IPC$ */ + 2,
1411 GFP_KERNEL);
1412 if (temp_unc == NULL)
1413 return -ENOMEM;
1414 temp_unc[0] = '\\';
1415 temp_unc[1] = '\\';
1416 strcpy(temp_unc + 2, pSesInfo->serverName);
1417 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1418 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1419 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00001420 ("CIFS Tcon rc = %d ipc_tid = %d", rc, pSesInfo->ipc_tid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 kfree(temp_unc);
1422 }
1423 if (rc == 0)
1424 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001425 pnum_referrals, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426
1427 return rc;
1428}
1429
1430/* See RFC1001 section 14 on representation of Netbios names */
Steve French50c2f752007-07-13 00:33:32 +00001431static void rfc1002mangle(char *target, char *source, unsigned int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432{
Steve French50c2f752007-07-13 00:33:32 +00001433 unsigned int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434
Steve French50c2f752007-07-13 00:33:32 +00001435 for (i = 0, j = 0; i < (length); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436 /* mask a nibble at a time and encode */
1437 target[j] = 'A' + (0x0F & (source[i] >> 4));
1438 target[j+1] = 'A' + (0x0F & source[i]);
Steve French50c2f752007-07-13 00:33:32 +00001439 j += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 }
1441
1442}
1443
1444
1445static int
Steve French50c2f752007-07-13 00:33:32 +00001446ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
1447 char *netbios_name, char *target_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448{
1449 int rc = 0;
1450 int connected = 0;
1451 __be16 orig_port = 0;
1452
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001453 if (*csocket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001454 rc = sock_create_kern(PF_INET, SOCK_STREAM,
1455 IPPROTO_TCP, csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001457 cERROR(1, ("Error %d creating socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 *csocket = NULL;
1459 return rc;
1460 } else {
1461 /* BB other socket options to set KEEPALIVE, NODELAY? */
Steve French467a8f82007-06-27 22:41:32 +00001462 cFYI(1, ("Socket created"));
Steve French50c2f752007-07-13 00:33:32 +00001463 (*csocket)->sk->sk_allocation = GFP_NOFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 }
1465 }
1466
1467 psin_server->sin_family = AF_INET;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001468 if (psin_server->sin_port) { /* user overrode default port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 rc = (*csocket)->ops->connect(*csocket,
1470 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001471 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 if (rc >= 0)
1473 connected = 1;
Steve French50c2f752007-07-13 00:33:32 +00001474 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001476 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001477 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 later if fall back ports fail this time */
1479 orig_port = psin_server->sin_port;
1480
1481 /* do not retry on the same port we just failed on */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001482 if (psin_server->sin_port != htons(CIFS_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 psin_server->sin_port = htons(CIFS_PORT);
1484
1485 rc = (*csocket)->ops->connect(*csocket,
1486 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001487 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 if (rc >= 0)
1489 connected = 1;
1490 }
1491 }
1492 if (!connected) {
1493 psin_server->sin_port = htons(RFC1001_PORT);
1494 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
Steve French50c2f752007-07-13 00:33:32 +00001495 psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001496 sizeof(struct sockaddr_in), 0);
Steve French50c2f752007-07-13 00:33:32 +00001497 if (rc >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 connected = 1;
1499 }
1500
1501 /* give up here - unless we want to retry on different
1502 protocol families some day */
1503 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001504 if (orig_port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 psin_server->sin_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001506 cFYI(1, ("Error %d connecting to server via ipv4", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 sock_release(*csocket);
1508 *csocket = NULL;
1509 return rc;
1510 }
Steve French50c2f752007-07-13 00:33:32 +00001511 /* Eventually check for other socket options to change from
1512 the default. sock_setsockopt not used because it expects
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 user space buffer */
Steve French50c2f752007-07-13 00:33:32 +00001514 cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",
1515 (*csocket)->sk->sk_sndbuf,
Steve Frenchb387eae2005-10-10 14:21:15 -07001516 (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchb387eae2005-10-10 14:21:15 -07001518 /* make the bufsizes depend on wsize/rsize and max requests */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001519 if ((*csocket)->sk->sk_sndbuf < (200 * 1024))
Steve Frenchb387eae2005-10-10 14:21:15 -07001520 (*csocket)->sk->sk_sndbuf = 200 * 1024;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001521 if ((*csocket)->sk->sk_rcvbuf < (140 * 1024))
Steve Frenchb387eae2005-10-10 14:21:15 -07001522 (*csocket)->sk->sk_rcvbuf = 140 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523
1524 /* send RFC1001 sessinit */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001525 if (psin_server->sin_port == htons(RFC1001_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 /* some servers require RFC1001 sessinit before sending
Steve French50c2f752007-07-13 00:33:32 +00001527 negprot - BB check reconnection in case where second
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 sessinit is sent but no second negprot */
Steve French50c2f752007-07-13 00:33:32 +00001529 struct rfc1002_session_packet *ses_init_buf;
1530 struct smb_hdr *smb_buf;
1531 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
1532 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001533 if (ses_init_buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 ses_init_buf->trailer.session_req.called_len = 32;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001535 if (target_name && (target_name[0] != 0)) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001536 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1537 target_name, 16);
1538 } else {
1539 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
Steve French50c2f752007-07-13 00:33:32 +00001540 DEFAULT_CIFS_CALLED_NAME, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001541 }
1542
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 ses_init_buf->trailer.session_req.calling_len = 32;
1544 /* calling name ends in null (byte 16) from old smb
1545 convention. */
Steve French50c2f752007-07-13 00:33:32 +00001546 if (netbios_name && (netbios_name[0] != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
Steve French50c2f752007-07-13 00:33:32 +00001548 netbios_name, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 } else {
1550 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
Steve French50c2f752007-07-13 00:33:32 +00001551 "LINUX_CIFS_CLNT", 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 }
1553 ses_init_buf->trailer.session_req.scope1 = 0;
1554 ses_init_buf->trailer.session_req.scope2 = 0;
1555 smb_buf = (struct smb_hdr *)ses_init_buf;
1556 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1557 smb_buf->smb_buf_length = 0x81000044;
1558 rc = smb_send(*csocket, smb_buf, 0x44,
1559 (struct sockaddr *)psin_server);
1560 kfree(ses_init_buf);
Steve French50c2f752007-07-13 00:33:32 +00001561 msleep(1); /* RFC1001 layer in at least one server
Steve French083d3a2c2006-03-03 09:53:36 +00001562 requires very short break before negprot
1563 presumably because not expecting negprot
1564 to follow so fast. This is a simple
Steve French50c2f752007-07-13 00:33:32 +00001565 solution that works without
Steve French083d3a2c2006-03-03 09:53:36 +00001566 complicating the code and causes no
1567 significant slowing down on mount
1568 for everyone else */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 }
Steve French50c2f752007-07-13 00:33:32 +00001570 /* else the negprot may still work without this
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 even though malloc failed */
Steve French50c2f752007-07-13 00:33:32 +00001572
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 }
Steve French50c2f752007-07-13 00:33:32 +00001574
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 return rc;
1576}
1577
1578static int
1579ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1580{
1581 int rc = 0;
1582 int connected = 0;
1583 __be16 orig_port = 0;
1584
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001585 if (*csocket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001586 rc = sock_create_kern(PF_INET6, SOCK_STREAM,
1587 IPPROTO_TCP, csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001589 cERROR(1, ("Error %d creating ipv6 socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 *csocket = NULL;
1591 return rc;
1592 } else {
1593 /* BB other socket options to set KEEPALIVE, NODELAY? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001594 cFYI(1, ("ipv6 Socket created"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 (*csocket)->sk->sk_allocation = GFP_NOFS;
1596 }
1597 }
1598
1599 psin_server->sin6_family = AF_INET6;
1600
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001601 if (psin_server->sin6_port) { /* user overrode default port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 rc = (*csocket)->ops->connect(*csocket,
1603 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001604 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 if (rc >= 0)
1606 connected = 1;
Steve French50c2f752007-07-13 00:33:32 +00001607 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001609 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001610 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 later if fall back ports fail this time */
1612
1613 orig_port = psin_server->sin6_port;
1614 /* do not retry on the same port we just failed on */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001615 if (psin_server->sin6_port != htons(CIFS_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 psin_server->sin6_port = htons(CIFS_PORT);
1617
1618 rc = (*csocket)->ops->connect(*csocket,
1619 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001620 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 if (rc >= 0)
1622 connected = 1;
1623 }
1624 }
1625 if (!connected) {
1626 psin_server->sin6_port = htons(RFC1001_PORT);
1627 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001628 psin_server, sizeof(struct sockaddr_in6), 0);
Steve French50c2f752007-07-13 00:33:32 +00001629 if (rc >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 connected = 1;
1631 }
1632
1633 /* give up here - unless we want to retry on different
1634 protocol families some day */
1635 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001636 if (orig_port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 psin_server->sin6_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001638 cFYI(1, ("Error %d connecting to server via ipv6", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 sock_release(*csocket);
1640 *csocket = NULL;
1641 return rc;
1642 }
Steve French50c2f752007-07-13 00:33:32 +00001643 /* Eventually check for other socket options to change from
1644 the default. sock_setsockopt not used because it expects
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 user space buffer */
1646 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve French50c2f752007-07-13 00:33:32 +00001647
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 return rc;
1649}
1650
Steve French50c2f752007-07-13 00:33:32 +00001651void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
1652 struct super_block *sb, struct smb_vol *vol_info)
Steve French8af18972007-02-14 04:42:51 +00001653{
1654 /* if we are reconnecting then should we check to see if
1655 * any requested capabilities changed locally e.g. via
1656 * remount but we can not do much about it here
1657 * if they have (even if we could detect it by the following)
1658 * Perhaps we could add a backpointer to array of sb from tcon
1659 * or if we change to make all sb to same share the same
1660 * sb as NFS - then we only have one backpointer to sb.
1661 * What if we wanted to mount the server share twice once with
1662 * and once without posixacls or posix paths? */
1663 __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001664
Steve Frenchc18c8422007-07-18 23:21:09 +00001665 if (vol_info && vol_info->no_linux_ext) {
1666 tcon->fsUnixInfo.Capability = 0;
1667 tcon->unix_ext = 0; /* Unix Extensions disabled */
1668 cFYI(1, ("Linux protocol extensions disabled"));
1669 return;
1670 } else if (vol_info)
1671 tcon->unix_ext = 1; /* Unix Extensions supported */
1672
1673 if (tcon->unix_ext == 0) {
1674 cFYI(1, ("Unix extensions disabled so not set on reconnect"));
1675 return;
1676 }
Steve French50c2f752007-07-13 00:33:32 +00001677
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001678 if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
Steve French8af18972007-02-14 04:42:51 +00001679 __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001680
Steve French8af18972007-02-14 04:42:51 +00001681 /* check for reconnect case in which we do not
1682 want to change the mount behavior if we can avoid it */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001683 if (vol_info == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001684 /* turn off POSIX ACL and PATHNAMES if not set
Steve French8af18972007-02-14 04:42:51 +00001685 originally at mount time */
1686 if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
1687 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
1688 if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0)
1689 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French8af18972007-02-14 04:42:51 +00001690 }
Steve French50c2f752007-07-13 00:33:32 +00001691
Steve French8af18972007-02-14 04:42:51 +00001692 cap &= CIFS_UNIX_CAP_MASK;
Steve French75865f8c2007-06-24 18:30:48 +00001693 if (vol_info && vol_info->no_psx_acl)
Steve French8af18972007-02-14 04:42:51 +00001694 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00001695 else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001696 cFYI(1, ("negotiated posix acl support"));
1697 if (sb)
Steve French8af18972007-02-14 04:42:51 +00001698 sb->s_flags |= MS_POSIXACL;
1699 }
1700
Steve French75865f8c2007-06-24 18:30:48 +00001701 if (vol_info && vol_info->posix_paths == 0)
Steve French8af18972007-02-14 04:42:51 +00001702 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00001703 else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001704 cFYI(1, ("negotiate posix pathnames"));
Steve French75865f8c2007-06-24 18:30:48 +00001705 if (sb)
Steve French50c2f752007-07-13 00:33:32 +00001706 CIFS_SB(sb)->mnt_cifs_flags |=
Steve French8af18972007-02-14 04:42:51 +00001707 CIFS_MOUNT_POSIX_PATHS;
1708 }
Steve French50c2f752007-07-13 00:33:32 +00001709
Steve French984acfe2007-04-26 16:42:50 +00001710 /* We might be setting the path sep back to a different
1711 form if we are reconnecting and the server switched its
Steve French50c2f752007-07-13 00:33:32 +00001712 posix path capability for this share */
Steve French75865f8c2007-06-24 18:30:48 +00001713 if (sb && (CIFS_SB(sb)->prepathlen > 0))
Steve French984acfe2007-04-26 16:42:50 +00001714 CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
Steve French75865f8c2007-06-24 18:30:48 +00001715
1716 if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
1717 if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
1718 CIFS_SB(sb)->rsize = 127 * 1024;
1719#ifdef CONFIG_CIFS_DEBUG2
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001720 cFYI(1, ("larger reads not supported by srv"));
Steve French75865f8c2007-06-24 18:30:48 +00001721#endif
1722 }
1723 }
Steve French50c2f752007-07-13 00:33:32 +00001724
1725
1726 cFYI(1, ("Negotiate caps 0x%x", (int)cap));
Steve French8af18972007-02-14 04:42:51 +00001727#ifdef CONFIG_CIFS_DEBUG2
Steve French75865f8c2007-06-24 18:30:48 +00001728 if (cap & CIFS_UNIX_FCNTL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001729 cFYI(1, ("FCNTL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001730 if (cap & CIFS_UNIX_EXTATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001731 cFYI(1, ("EXTATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001732 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001733 cFYI(1, ("POSIX path cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001734 if (cap & CIFS_UNIX_XATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001735 cFYI(1, ("XATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001736 if (cap & CIFS_UNIX_POSIX_ACL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001737 cFYI(1, ("POSIX ACL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001738 if (cap & CIFS_UNIX_LARGE_READ_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001739 cFYI(1, ("very large read cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001740 if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001741 cFYI(1, ("very large write cap"));
Steve French8af18972007-02-14 04:42:51 +00001742#endif /* CIFS_DEBUG2 */
1743 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
Steve French442aa312007-09-24 20:25:46 +00001744 if (vol_info == NULL) {
Steve French5a44b312007-09-20 15:16:24 +00001745 cFYI(1, ("resetting capabilities failed"));
Steve French442aa312007-09-24 20:25:46 +00001746 } else
Steve French5a44b312007-09-20 15:16:24 +00001747 cERROR(1, ("Negotiating Unix capabilities "
1748 "with the server failed. Consider "
1749 "mounting with the Unix Extensions\n"
1750 "disabled, if problems are found, "
1751 "by specifying the nounix mount "
Steve French2224f4e2007-09-20 15:37:29 +00001752 "option."));
Steve French5a44b312007-09-20 15:16:24 +00001753
Steve French8af18972007-02-14 04:42:51 +00001754 }
1755 }
1756}
1757
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758int
1759cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1760 char *mount_data, const char *devname)
1761{
1762 int rc = 0;
1763 int xid;
1764 int address_type = AF_INET;
1765 struct socket *csocket = NULL;
1766 struct sockaddr_in sin_server;
1767 struct sockaddr_in6 sin_server6;
1768 struct smb_vol volume_info;
1769 struct cifsSesInfo *pSesInfo = NULL;
1770 struct cifsSesInfo *existingCifsSes = NULL;
1771 struct cifsTconInfo *tcon = NULL;
1772 struct TCP_Server_Info *srvTcp = NULL;
1773
1774 xid = GetXid();
1775
1776/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
Steve French50c2f752007-07-13 00:33:32 +00001777
1778 memset(&volume_info, 0, sizeof(struct smb_vol));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001780 kfree(volume_info.UNC);
1781 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001782 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 FreeXid(xid);
1784 return -EINVAL;
1785 }
1786
Jeff Layton8426c392007-05-05 03:27:49 +00001787 if (volume_info.nullauth) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001788 cFYI(1, ("null user"));
Jeff Layton8426c392007-05-05 03:27:49 +00001789 volume_info.username = NULL;
1790 } else if (volume_info.username) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 /* BB fixme parse for domain name here */
Steve French467a8f82007-06-27 22:41:32 +00001792 cFYI(1, ("Username: %s", volume_info.username));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 } else {
Steve Frenchbf820672005-12-01 22:32:42 -08001794 cifserror("No username specified");
Steve French50c2f752007-07-13 00:33:32 +00001795 /* In userspace mount helper we can get user name from alternate
1796 locations such as env variables and files on disk */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001797 kfree(volume_info.UNC);
1798 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001799 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 FreeXid(xid);
1801 return -EINVAL;
1802 }
1803
1804 if (volume_info.UNCip && volume_info.UNC) {
Steve French50c2f752007-07-13 00:33:32 +00001805 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,
1806 &sin_server.sin_addr.s_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001808 if (rc <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 /* not ipv4 address, try ipv6 */
Steve French50c2f752007-07-13 00:33:32 +00001810 rc = cifs_inet_pton(AF_INET6, volume_info.UNCip,
1811 &sin_server6.sin6_addr.in6_u);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001812 if (rc > 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 address_type = AF_INET6;
1814 } else {
1815 address_type = AF_INET;
1816 }
Steve French50c2f752007-07-13 00:33:32 +00001817
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001818 if (rc <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 /* we failed translating address */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001820 kfree(volume_info.UNC);
1821 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001822 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 FreeXid(xid);
1824 return -EINVAL;
1825 }
1826
1827 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1828 /* success */
1829 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00001830 } else if (volume_info.UNCip) {
1831 /* BB using ip addr as server name to connect to the
1832 DFS root below */
1833 cERROR(1, ("Connecting to DFS root not implemented yet"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001834 kfree(volume_info.UNC);
1835 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001836 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 FreeXid(xid);
1838 return -EINVAL;
1839 } else /* which servers DFS root would we conect to */ {
1840 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00001841 ("CIFS mount error: No UNC path (e.g. -o "
1842 "unc=//192.168.1.100/public) specified"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001843 kfree(volume_info.UNC);
1844 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001845 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 FreeXid(xid);
1847 return -EINVAL;
1848 }
1849
1850 /* this is needed for ASCII cp to Unicode converts */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001851 if (volume_info.iocharset == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 cifs_sb->local_nls = load_nls_default();
1853 /* load_nls_default can not return null */
1854 } else {
1855 cifs_sb->local_nls = load_nls(volume_info.iocharset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001856 if (cifs_sb->local_nls == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001857 cERROR(1, ("CIFS mount error: iocharset %s not found",
1858 volume_info.iocharset));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001859 kfree(volume_info.UNC);
1860 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001861 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 FreeXid(xid);
1863 return -ELIBACC;
1864 }
1865 }
1866
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001867 if (address_type == AF_INET)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1869 NULL /* no ipv6 addr */,
1870 volume_info.username, &srvTcp);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001871 else if (address_type == AF_INET6) {
1872 cFYI(1, ("looking for ipv6 address"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1874 &sin_server6.sin6_addr,
1875 volume_info.username, &srvTcp);
Steve French5858ae42007-04-25 11:59:10 +00001876 } else {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001877 kfree(volume_info.UNC);
1878 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001879 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 FreeXid(xid);
1881 return -EINVAL;
1882 }
1883
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 if (srvTcp) {
Steve French50c2f752007-07-13 00:33:32 +00001885 cFYI(1, ("Existing tcp session with server found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 } else { /* create socket */
Steve French4523cc32007-04-30 20:13:06 +00001887 if (volume_info.port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 sin_server.sin_port = htons(volume_info.port);
1889 else
1890 sin_server.sin_port = 0;
Steve French5858ae42007-04-25 11:59:10 +00001891 if (address_type == AF_INET6) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001892 cFYI(1, ("attempting ipv6 connect"));
Steve French5858ae42007-04-25 11:59:10 +00001893 /* BB should we allow ipv6 on port 139? */
1894 /* other OS never observed in Wild doing 139 with v6 */
Steve French50c2f752007-07-13 00:33:32 +00001895 rc = ipv6_connect(&sin_server6, &csocket);
1896 } else
1897 rc = ipv4_connect(&sin_server, &csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -07001898 volume_info.source_rfc1001_name,
1899 volume_info.target_rfc1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001901 cERROR(1, ("Error connecting to IPv4 socket. "
1902 "Aborting operation"));
Steve French4523cc32007-04-30 20:13:06 +00001903 if (csocket != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001905 kfree(volume_info.UNC);
1906 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001907 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 FreeXid(xid);
1909 return rc;
1910 }
1911
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00001912 srvTcp = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
1913 if (!srvTcp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 rc = -ENOMEM;
1915 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001916 kfree(volume_info.UNC);
1917 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001918 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 FreeXid(xid);
1920 return rc;
1921 } else {
Steve French50c2f752007-07-13 00:33:32 +00001922 memcpy(&srvTcp->addr.sockAddr, &sin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001923 sizeof(struct sockaddr_in));
Steve French50c2f752007-07-13 00:33:32 +00001924 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 }
Steve Frencha0136892007-10-04 20:05:09 +00002175 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176 cFYI(1, ("No session or bad tcon"));
Steve Frencha0136892007-10-04 20:05:09 +00002177 if ((pSesInfo->server) &&
2178 (pSesInfo->server->tsk)) {
2179 struct task_struct *tsk;
2180 force_sig(SIGKILL,
2181 pSesInfo->server->tsk);
2182 tsk = pSesInfo->server->tsk;
2183 if (tsk)
2184 kthread_stop(tsk);
2185 }
2186 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187 sesInfoFree(pSesInfo);
2188 /* pSesInfo = NULL; */
2189 }
2190 }
2191 } else {
2192 atomic_inc(&tcon->useCount);
2193 cifs_sb->tcon = tcon;
2194 tcon->ses = pSesInfo;
2195
Steve French82940a42006-03-02 03:24:57 +00002196 /* do not care if following two calls succeed - informational */
Steve French7f8ed422007-09-28 22:28:55 +00002197 if (!tcon->ipc) {
2198 CIFSSMBQFSDeviceInfo(xid, tcon);
2199 CIFSSMBQFSAttributeInfo(xid, tcon);
2200 }
Steve French50c2f752007-07-13 00:33:32 +00002201
Steve French8af18972007-02-14 04:42:51 +00002202 /* tell server which Unix caps we support */
2203 if (tcon->ses->capabilities & CAP_UNIX)
Steve Frenchc18c8422007-07-18 23:21:09 +00002204 /* reset of caps checks mount to see if unix extensions
2205 disabled for just this mount */
Steve French8af18972007-02-14 04:42:51 +00002206 reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
Steve Frenchc18c8422007-07-18 23:21:09 +00002207 else
2208 tcon->unix_ext = 0; /* server does not support them */
2209
2210 if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
Steve French75865f8c2007-06-24 18:30:48 +00002211 cifs_sb->rsize = 1024 * 127;
2212#ifdef CONFIG_CIFS_DEBUG2
Steve Frenchc18c8422007-07-18 23:21:09 +00002213 cFYI(1, ("no very large read support, rsize now 127K"));
Steve French75865f8c2007-06-24 18:30:48 +00002214#endif
Steve French75865f8c2007-06-24 18:30:48 +00002215 }
Steve French3e844692005-10-03 13:37:24 -07002216 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
2217 cifs_sb->wsize = min(cifs_sb->wsize,
2218 (tcon->ses->server->maxBuf -
2219 MAX_CIFS_HDR_SIZE));
Steve French0ae0efa2005-10-10 10:57:19 -07002220 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
Steve French50c2f752007-07-13 00:33:32 +00002221 cifs_sb->rsize = min(cifs_sb->rsize,
2222 (tcon->ses->server->maxBuf -
2223 MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224 }
2225
2226 /* volume_info.password is freed above when existing session found
2227 (in which case it is not needed anymore) but when new sesion is created
2228 the password ptr is put in the new session structure (in which case the
2229 password will be freed at unmount time) */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002230 kfree(volume_info.UNC);
Steve French2fe87f02006-09-21 07:02:52 +00002231 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 FreeXid(xid);
2233 return rc;
2234}
2235
2236static int
2237CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French7c7b25b2006-06-01 19:20:10 +00002238 char session_key[CIFS_SESS_KEY_SIZE],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239 const struct nls_table *nls_codepage)
2240{
2241 struct smb_hdr *smb_buffer;
2242 struct smb_hdr *smb_buffer_response;
2243 SESSION_SETUP_ANDX *pSMB;
2244 SESSION_SETUP_ANDX *pSMBr;
2245 char *bcc_ptr;
2246 char *user;
2247 char *domain;
2248 int rc = 0;
2249 int remaining_words = 0;
2250 int bytes_returned = 0;
2251 int len;
2252 __u32 capabilities;
2253 __u16 count;
2254
Steve Frencheeac8042006-01-13 21:34:58 -08002255 cFYI(1, ("In sesssetup"));
Steve French4523cc32007-04-30 20:13:06 +00002256 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 return -EINVAL;
2258 user = ses->userName;
2259 domain = ses->domainName;
2260 smb_buffer = cifs_buf_get();
2261 if (smb_buffer == NULL) {
2262 return -ENOMEM;
2263 }
2264 smb_buffer_response = smb_buffer;
2265 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2266
2267 /* send SMBsessionSetup here */
2268 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2269 NULL /* no tCon exists yet */ , 13 /* wct */ );
2270
Steve French1982c342005-08-17 12:38:22 -07002271 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272 pSMB->req_no_secext.AndXCommand = 0xFF;
2273 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2274 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2275
Steve French50c2f752007-07-13 00:33:32 +00002276 if (ses->server->secMode &
2277 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2279
2280 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2281 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
2282 if (ses->capabilities & CAP_UNICODE) {
2283 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2284 capabilities |= CAP_UNICODE;
2285 }
2286 if (ses->capabilities & CAP_STATUS32) {
2287 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2288 capabilities |= CAP_STATUS32;
2289 }
2290 if (ses->capabilities & CAP_DFS) {
2291 smb_buffer->Flags2 |= SMBFLG2_DFS;
2292 capabilities |= CAP_DFS;
2293 }
2294 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
2295
Steve French50c2f752007-07-13 00:33:32 +00002296 pSMB->req_no_secext.CaseInsensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002297 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298
2299 pSMB->req_no_secext.CaseSensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002300 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 bcc_ptr = pByteArea(smb_buffer);
Steve French7c7b25b2006-06-01 19:20:10 +00002302 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2303 bcc_ptr += CIFS_SESS_KEY_SIZE;
2304 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2305 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306
2307 if (ses->capabilities & CAP_UNICODE) {
2308 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
2309 *bcc_ptr = 0;
2310 bcc_ptr++;
2311 }
Steve French4523cc32007-04-30 20:13:06 +00002312 if (user == NULL)
Steve French39798772006-05-31 22:40:51 +00002313 bytes_returned = 0; /* skip null user */
Steve French50c2f752007-07-13 00:33:32 +00002314 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315 bytes_returned =
Steve French50c2f752007-07-13 00:33:32 +00002316 cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317 nls_codepage);
2318 /* convert number of 16 bit words to bytes */
2319 bcc_ptr += 2 * bytes_returned;
2320 bcc_ptr += 2; /* trailing null */
2321 if (domain == NULL)
2322 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002323 cifs_strtoUCS((__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 "CIFS_LINUX_DOM", 32, nls_codepage);
2325 else
2326 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002327 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 nls_codepage);
2329 bcc_ptr += 2 * bytes_returned;
2330 bcc_ptr += 2;
2331 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002332 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 32, nls_codepage);
2334 bcc_ptr += 2 * bytes_returned;
2335 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002336 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337 32, nls_codepage);
2338 bcc_ptr += 2 * bytes_returned;
2339 bcc_ptr += 2;
2340 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002341 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342 64, nls_codepage);
2343 bcc_ptr += 2 * bytes_returned;
2344 bcc_ptr += 2;
2345 } else {
Steve French50c2f752007-07-13 00:33:32 +00002346 if (user != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347 strncpy(bcc_ptr, user, 200);
2348 bcc_ptr += strnlen(user, 200);
2349 }
2350 *bcc_ptr = 0;
2351 bcc_ptr++;
2352 if (domain == NULL) {
2353 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2354 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2355 } else {
2356 strncpy(bcc_ptr, domain, 64);
2357 bcc_ptr += strnlen(domain, 64);
2358 *bcc_ptr = 0;
2359 bcc_ptr++;
2360 }
2361 strcpy(bcc_ptr, "Linux version ");
2362 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002363 strcpy(bcc_ptr, utsname()->release);
2364 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2366 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2367 }
2368 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2369 smb_buffer->smb_buf_length += count;
2370 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2371
2372 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2373 &bytes_returned, 1);
2374 if (rc) {
2375/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2376 } else if ((smb_buffer_response->WordCount == 3)
2377 || (smb_buffer_response->WordCount == 4)) {
2378 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2379 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2380 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002381 cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */
2382 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format
2383 (little endian) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384 cFYI(1, ("UID = %d ", ses->Suid));
Steve French50c2f752007-07-13 00:33:32 +00002385 /* response can have either 3 or 4 word count - Samba sends 3 */
2386 bcc_ptr = pByteArea(smb_buffer_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387 if ((pSMBr->resp.hdr.WordCount == 3)
2388 || ((pSMBr->resp.hdr.WordCount == 4)
2389 && (blob_len < pSMBr->resp.ByteCount))) {
2390 if (pSMBr->resp.hdr.WordCount == 4)
2391 bcc_ptr += blob_len;
2392
2393 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2394 if ((long) (bcc_ptr) % 2) {
2395 remaining_words =
Steve French50c2f752007-07-13 00:33:32 +00002396 (BCC(smb_buffer_response) - 1) / 2;
2397 /* Unicode strings must be word
2398 aligned */
2399 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400 } else {
2401 remaining_words =
2402 BCC(smb_buffer_response) / 2;
2403 }
2404 len =
2405 UniStrnlen((wchar_t *) bcc_ptr,
2406 remaining_words - 1);
2407/* We look for obvious messed up bcc or strings in response so we do not go off
2408 the end since (at least) WIN2K and Windows XP have a major bug in not null
2409 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002410 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002411 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002412 ses->serverOS = kzalloc(2 * (len + 1),
2413 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002414 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002415 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416 cifs_strfromUCS_le(ses->serverOS,
Steve French50c2f752007-07-13 00:33:32 +00002417 (__le16 *)bcc_ptr,
2418 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419 bcc_ptr += 2 * (len + 1);
2420 remaining_words -= len + 1;
2421 ses->serverOS[2 * len] = 0;
2422 ses->serverOS[1 + (2 * len)] = 0;
2423 if (remaining_words > 0) {
2424 len = UniStrnlen((wchar_t *)bcc_ptr,
2425 remaining_words-1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002426 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002427 ses->serverNOS = kzalloc(2 * (len + 1),
2428 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002429 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002430 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431 cifs_strfromUCS_le(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002432 (__le16 *)bcc_ptr,
2433 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434 bcc_ptr += 2 * (len + 1);
2435 ses->serverNOS[2 * len] = 0;
2436 ses->serverNOS[1 + (2 * len)] = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002437 if (strncmp(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002438 "NT LAN Manager 4", 16) == 0) {
Steve French467a8f82007-06-27 22:41:32 +00002439 cFYI(1, ("NT4 server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440 ses->flags |= CIFS_SES_NT4;
2441 }
2442 remaining_words -= len + 1;
2443 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002444 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Steve French50c2f752007-07-13 00:33:32 +00002445 /* last string is not always null terminated
2446 (for e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002447 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002448 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449 ses->serverDomain =
Steve French50c2f752007-07-13 00:33:32 +00002450 kzalloc(2*(len+1),
2451 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002452 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002453 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454 cifs_strfromUCS_le(ses->serverDomain,
Steve French50c2f752007-07-13 00:33:32 +00002455 (__le16 *)bcc_ptr,
2456 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457 bcc_ptr += 2 * (len + 1);
2458 ses->serverDomain[2*len] = 0;
2459 ses->serverDomain[1+(2*len)] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002460 } else { /* else no more room so create
2461 dummy domain string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002462 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002463 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002464 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002465 kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002466 }
Steve French50c2f752007-07-13 00:33:32 +00002467 } else { /* no room so create dummy domain
2468 and NOS string */
2469
Steve French433dc242005-04-28 22:41:08 -07002470 /* if these kcallocs fail not much we
2471 can do, but better to not fail the
2472 sesssetup itself */
Steve Frenchcd49b492006-06-26 04:22:36 +00002473 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002475 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002476 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002478 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479 }
2480 } else { /* ASCII */
2481 len = strnlen(bcc_ptr, 1024);
2482 if (((long) bcc_ptr + len) - (long)
2483 pByteArea(smb_buffer_response)
2484 <= BCC(smb_buffer_response)) {
Steve Frenchcd49b492006-06-26 04:22:36 +00002485 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002486 ses->serverOS = kzalloc(len + 1,
2487 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002488 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002489 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002490 strncpy(ses->serverOS, bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491
2492 bcc_ptr += len;
Steve French50c2f752007-07-13 00:33:32 +00002493 /* null terminate the string */
2494 bcc_ptr[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495 bcc_ptr++;
2496
2497 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002498 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002499 ses->serverNOS = kzalloc(len + 1,
2500 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002501 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002502 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503 strncpy(ses->serverNOS, bcc_ptr, len);
2504 bcc_ptr += len;
2505 bcc_ptr[0] = 0;
2506 bcc_ptr++;
2507
2508 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002509 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002510 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002511 ses->serverDomain = kzalloc(len + 1,
2512 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002513 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002514 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002515 strncpy(ses->serverDomain, bcc_ptr,
2516 len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 bcc_ptr += len;
2518 bcc_ptr[0] = 0;
2519 bcc_ptr++;
2520 } else
2521 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00002522 ("Variable field of length %d "
2523 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524 len));
2525 }
2526 } else {
2527 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00002528 (" Security Blob Length extends beyond "
2529 "end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530 }
2531 } else {
2532 cERROR(1,
2533 (" Invalid Word count %d: ",
2534 smb_buffer_response->WordCount));
2535 rc = -EIO;
2536 }
Steve French433dc242005-04-28 22:41:08 -07002537sesssetup_nomem: /* do not return an error on nomem for the info strings,
2538 since that could make reconnection harder, and
2539 reconnection might be needed to free memory */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00002540 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541
2542 return rc;
2543}
2544
2545static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
Steve French50c2f752007-07-13 00:33:32 +00002547 struct cifsSesInfo *ses, int *pNTLMv2_flag,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548 const struct nls_table *nls_codepage)
2549{
2550 struct smb_hdr *smb_buffer;
2551 struct smb_hdr *smb_buffer_response;
2552 SESSION_SETUP_ANDX *pSMB;
2553 SESSION_SETUP_ANDX *pSMBr;
2554 char *bcc_ptr;
2555 char *domain;
2556 int rc = 0;
2557 int remaining_words = 0;
2558 int bytes_returned = 0;
2559 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002560 int SecurityBlobLength = sizeof(NEGOTIATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 PNEGOTIATE_MESSAGE SecurityBlob;
2562 PCHALLENGE_MESSAGE SecurityBlob2;
2563 __u32 negotiate_flags, capabilities;
2564 __u16 count;
2565
Steve French12b3b8f2006-02-09 21:12:47 +00002566 cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002567 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568 return -EINVAL;
2569 domain = ses->domainName;
2570 *pNTLMv2_flag = FALSE;
2571 smb_buffer = cifs_buf_get();
2572 if (smb_buffer == NULL) {
2573 return -ENOMEM;
2574 }
2575 smb_buffer_response = smb_buffer;
2576 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2577 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2578
2579 /* send SMBsessionSetup here */
2580 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2581 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002582
2583 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2585 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2586
2587 pSMB->req.AndXCommand = 0xFF;
2588 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2589 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2590
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002591 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2593
2594 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2595 CAP_EXTENDED_SECURITY;
2596 if (ses->capabilities & CAP_UNICODE) {
2597 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2598 capabilities |= CAP_UNICODE;
2599 }
2600 if (ses->capabilities & CAP_STATUS32) {
2601 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2602 capabilities |= CAP_STATUS32;
2603 }
2604 if (ses->capabilities & CAP_DFS) {
2605 smb_buffer->Flags2 |= SMBFLG2_DFS;
2606 capabilities |= CAP_DFS;
2607 }
2608 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2609
2610 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2611 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2612 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2613 SecurityBlob->MessageType = NtLmNegotiate;
2614 negotiate_flags =
2615 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
Steve French12b3b8f2006-02-09 21:12:47 +00002616 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
2617 NTLMSSP_NEGOTIATE_56 |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002619 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002621/* if (ntlmv2_support)
Steve French39798772006-05-31 22:40:51 +00002622 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623 /* setup pointers to domain name and workstation name */
2624 bcc_ptr += SecurityBlobLength;
2625
2626 SecurityBlob->WorkstationName.Buffer = 0;
2627 SecurityBlob->WorkstationName.Length = 0;
2628 SecurityBlob->WorkstationName.MaximumLength = 0;
2629
Steve French12b3b8f2006-02-09 21:12:47 +00002630 /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent
2631 along with username on auth request (ie the response to challenge) */
2632 SecurityBlob->DomainName.Buffer = 0;
2633 SecurityBlob->DomainName.Length = 0;
2634 SecurityBlob->DomainName.MaximumLength = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 if (ses->capabilities & CAP_UNICODE) {
2636 if ((long) bcc_ptr % 2) {
2637 *bcc_ptr = 0;
2638 bcc_ptr++;
2639 }
2640
2641 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002642 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 32, nls_codepage);
2644 bcc_ptr += 2 * bytes_returned;
2645 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002646 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 nls_codepage);
2648 bcc_ptr += 2 * bytes_returned;
2649 bcc_ptr += 2; /* null terminate Linux version */
2650 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002651 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 64, nls_codepage);
2653 bcc_ptr += 2 * bytes_returned;
2654 *(bcc_ptr + 1) = 0;
2655 *(bcc_ptr + 2) = 0;
2656 bcc_ptr += 2; /* null terminate network opsys string */
2657 *(bcc_ptr + 1) = 0;
2658 *(bcc_ptr + 2) = 0;
2659 bcc_ptr += 2; /* null domain */
2660 } else { /* ASCII */
2661 strcpy(bcc_ptr, "Linux version ");
2662 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002663 strcpy(bcc_ptr, utsname()->release);
2664 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2666 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2667 bcc_ptr++; /* empty domain field */
2668 *bcc_ptr = 0;
2669 }
2670 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2671 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2672 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2673 smb_buffer->smb_buf_length += count;
2674 pSMB->req.ByteCount = cpu_to_le16(count);
2675
2676 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2677 &bytes_returned, 1);
2678
2679 if (smb_buffer_response->Status.CifsError ==
2680 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2681 rc = 0;
2682
2683 if (rc) {
2684/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2685 } else if ((smb_buffer_response->WordCount == 3)
2686 || (smb_buffer_response->WordCount == 4)) {
2687 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2688 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2689
2690 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002691 cFYI(1, (" Guest login"));
2692 /* Do we want to set anything in SesInfo struct when guest login? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693
Steve French50c2f752007-07-13 00:33:32 +00002694 bcc_ptr = pByteArea(smb_buffer_response);
2695 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696
2697 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2698 if (SecurityBlob2->MessageType != NtLmChallenge) {
2699 cFYI(1,
2700 ("Unexpected NTLMSSP message type received %d",
2701 SecurityBlob2->MessageType));
2702 } else if (ses) {
Steve French50c2f752007-07-13 00:33:32 +00002703 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
Steve French12b3b8f2006-02-09 21:12:47 +00002704 cFYI(1, ("UID = %d", ses->Suid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705 if ((pSMBr->resp.hdr.WordCount == 3)
2706 || ((pSMBr->resp.hdr.WordCount == 4)
2707 && (blob_len <
2708 pSMBr->resp.ByteCount))) {
2709
2710 if (pSMBr->resp.hdr.WordCount == 4) {
2711 bcc_ptr += blob_len;
Steve French12b3b8f2006-02-09 21:12:47 +00002712 cFYI(1, ("Security Blob Length %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713 blob_len));
2714 }
2715
Steve French12b3b8f2006-02-09 21:12:47 +00002716 cFYI(1, ("NTLMSSP Challenge rcvd"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717
2718 memcpy(ses->server->cryptKey,
2719 SecurityBlob2->Challenge,
2720 CIFS_CRYPTO_KEY_SIZE);
Steve French50c2f752007-07-13 00:33:32 +00002721 if (SecurityBlob2->NegotiateFlags &
Steve French12b3b8f2006-02-09 21:12:47 +00002722 cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 *pNTLMv2_flag = TRUE;
2724
Steve French50c2f752007-07-13 00:33:32 +00002725 if ((SecurityBlob2->NegotiateFlags &
2726 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 || (sign_CIFS_PDUs > 1))
Steve French50c2f752007-07-13 00:33:32 +00002728 ses->server->secMode |=
2729 SECMODE_SIGN_REQUIRED;
2730 if ((SecurityBlob2->NegotiateFlags &
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
Steve French50c2f752007-07-13 00:33:32 +00002732 ses->server->secMode |=
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 SECMODE_SIGN_ENABLED;
2734
2735 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2736 if ((long) (bcc_ptr) % 2) {
2737 remaining_words =
2738 (BCC(smb_buffer_response)
2739 - 1) / 2;
Steve French50c2f752007-07-13 00:33:32 +00002740 /* Must word align unicode strings */
2741 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 } else {
2743 remaining_words =
2744 BCC
2745 (smb_buffer_response) / 2;
2746 }
2747 len =
2748 UniStrnlen((wchar_t *) bcc_ptr,
2749 remaining_words - 1);
2750/* We look for obvious messed up bcc or strings in response so we do not go off
2751 the end since (at least) WIN2K and Windows XP have a major bug in not null
2752 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002753 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002754 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002756 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002758 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 bcc_ptr, len,
2760 nls_codepage);
2761 bcc_ptr += 2 * (len + 1);
2762 remaining_words -= len + 1;
2763 ses->serverOS[2 * len] = 0;
2764 ses->serverOS[1 + (2 * len)] = 0;
2765 if (remaining_words > 0) {
2766 len = UniStrnlen((wchar_t *)
2767 bcc_ptr,
2768 remaining_words
2769 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002770 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002772 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 GFP_KERNEL);
2774 cifs_strfromUCS_le(ses->
2775 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002776 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 bcc_ptr,
2778 len,
2779 nls_codepage);
2780 bcc_ptr += 2 * (len + 1);
2781 ses->serverNOS[2 * len] = 0;
2782 ses->serverNOS[1 +
2783 (2 * len)] = 0;
2784 remaining_words -= len + 1;
2785 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00002786 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2787 /* last string not always null terminated
2788 (for e.g. for Windows XP & 2000) */
Steve Frenchcd49b492006-06-26 04:22:36 +00002789 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002791 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 (len +
2793 1),
2794 GFP_KERNEL);
2795 cifs_strfromUCS_le
Steve Frenche89dc922005-11-11 15:18:19 -08002796 (ses->serverDomain,
2797 (__le16 *)bcc_ptr,
2798 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 bcc_ptr +=
2800 2 * (len + 1);
Steve Frenche89dc922005-11-11 15:18:19 -08002801 ses->serverDomain[2*len]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 = 0;
Steve Frenche89dc922005-11-11 15:18:19 -08002803 ses->serverDomain
2804 [1 + (2 * len)]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002805 = 0;
2806 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002807 else {
Steve Frenchcd49b492006-06-26 04:22:36 +00002808 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002810 kzalloc(2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811 GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002812 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 } else { /* no room so create dummy domain and NOS string */
Steve Frenchcd49b492006-06-26 04:22:36 +00002814 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002816 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002817 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002819 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820 }
2821 } else { /* ASCII */
2822 len = strnlen(bcc_ptr, 1024);
2823 if (((long) bcc_ptr + len) - (long)
2824 pByteArea(smb_buffer_response)
2825 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002826 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002827 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002829 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830 GFP_KERNEL);
2831 strncpy(ses->serverOS,
2832 bcc_ptr, len);
2833
2834 bcc_ptr += len;
2835 bcc_ptr[0] = 0; /* null terminate string */
2836 bcc_ptr++;
2837
2838 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002839 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002841 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842 GFP_KERNEL);
2843 strncpy(ses->serverNOS, bcc_ptr, len);
2844 bcc_ptr += len;
2845 bcc_ptr[0] = 0;
2846 bcc_ptr++;
2847
2848 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002849 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002851 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +00002853 strncpy(ses->serverDomain,
2854 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 bcc_ptr += len;
2856 bcc_ptr[0] = 0;
2857 bcc_ptr++;
2858 } else
2859 cFYI(1,
Steve French63135e02007-07-17 17:34:02 +00002860 ("field of length %d "
2861 "extends beyond end of smb",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862 len));
2863 }
2864 } else {
Steve French50c2f752007-07-13 00:33:32 +00002865 cERROR(1, ("Security Blob Length extends beyond"
2866 " end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867 }
2868 } else {
2869 cERROR(1, ("No session structure passed in."));
2870 }
2871 } else {
2872 cERROR(1,
Steve French5815449d2006-02-14 01:36:20 +00002873 (" Invalid Word count %d:",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874 smb_buffer_response->WordCount));
2875 rc = -EIO;
2876 }
2877
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00002878 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879
2880 return rc;
2881}
2882static int
2883CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002884 char *ntlm_session_key, int ntlmv2_flag,
2885 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886{
2887 struct smb_hdr *smb_buffer;
2888 struct smb_hdr *smb_buffer_response;
2889 SESSION_SETUP_ANDX *pSMB;
2890 SESSION_SETUP_ANDX *pSMBr;
2891 char *bcc_ptr;
2892 char *user;
2893 char *domain;
2894 int rc = 0;
2895 int remaining_words = 0;
2896 int bytes_returned = 0;
2897 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002898 int SecurityBlobLength = sizeof(AUTHENTICATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 PAUTHENTICATE_MESSAGE SecurityBlob;
2900 __u32 negotiate_flags, capabilities;
2901 __u16 count;
2902
2903 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002904 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905 return -EINVAL;
2906 user = ses->userName;
2907 domain = ses->domainName;
2908 smb_buffer = cifs_buf_get();
2909 if (smb_buffer == NULL) {
2910 return -ENOMEM;
2911 }
2912 smb_buffer_response = smb_buffer;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002913 pSMB = (SESSION_SETUP_ANDX *)smb_buffer;
2914 pSMBr = (SESSION_SETUP_ANDX *)smb_buffer_response;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915
2916 /* send SMBsessionSetup here */
2917 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2918 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002919
2920 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2922 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2923 pSMB->req.AndXCommand = 0xFF;
2924 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2925 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2926
2927 pSMB->req.hdr.Uid = ses->Suid;
2928
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002929 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2931
2932 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002933 CAP_EXTENDED_SECURITY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934 if (ses->capabilities & CAP_UNICODE) {
2935 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2936 capabilities |= CAP_UNICODE;
2937 }
2938 if (ses->capabilities & CAP_STATUS32) {
2939 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2940 capabilities |= CAP_STATUS32;
2941 }
2942 if (ses->capabilities & CAP_DFS) {
2943 smb_buffer->Flags2 |= SMBFLG2_DFS;
2944 capabilities |= CAP_DFS;
2945 }
2946 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2947
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002948 bcc_ptr = (char *)&pSMB->req.SecurityBlob;
2949 SecurityBlob = (PAUTHENTICATE_MESSAGE)bcc_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2951 SecurityBlob->MessageType = NtLmAuthenticate;
2952 bcc_ptr += SecurityBlobLength;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002953 negotiate_flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2954 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2955 0x80000000 | NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002956 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002958 if (ntlmv2_flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2960
2961/* setup pointers to domain name and workstation name */
2962
2963 SecurityBlob->WorkstationName.Buffer = 0;
2964 SecurityBlob->WorkstationName.Length = 0;
2965 SecurityBlob->WorkstationName.MaximumLength = 0;
2966 SecurityBlob->SessionKey.Length = 0;
2967 SecurityBlob->SessionKey.MaximumLength = 0;
2968 SecurityBlob->SessionKey.Buffer = 0;
2969
2970 SecurityBlob->LmChallengeResponse.Length = 0;
2971 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2972 SecurityBlob->LmChallengeResponse.Buffer = 0;
2973
2974 SecurityBlob->NtChallengeResponse.Length =
Steve French7c7b25b2006-06-01 19:20:10 +00002975 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976 SecurityBlob->NtChallengeResponse.MaximumLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002977 cpu_to_le16(CIFS_SESS_KEY_SIZE);
2978 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979 SecurityBlob->NtChallengeResponse.Buffer =
2980 cpu_to_le32(SecurityBlobLength);
Steve French7c7b25b2006-06-01 19:20:10 +00002981 SecurityBlobLength += CIFS_SESS_KEY_SIZE;
2982 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983
2984 if (ses->capabilities & CAP_UNICODE) {
2985 if (domain == NULL) {
2986 SecurityBlob->DomainName.Buffer = 0;
2987 SecurityBlob->DomainName.Length = 0;
2988 SecurityBlob->DomainName.MaximumLength = 0;
2989 } else {
Steve French77159b42007-08-31 01:10:17 +00002990 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00002992 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00002994 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995 SecurityBlob->DomainName.Buffer =
2996 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00002997 bcc_ptr += ln;
2998 SecurityBlobLength += ln;
2999 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003000 }
3001 if (user == NULL) {
3002 SecurityBlob->UserName.Buffer = 0;
3003 SecurityBlob->UserName.Length = 0;
3004 SecurityBlob->UserName.MaximumLength = 0;
3005 } else {
Steve French77159b42007-08-31 01:10:17 +00003006 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00003008 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009 SecurityBlob->UserName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003010 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011 SecurityBlob->UserName.Buffer =
3012 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003013 bcc_ptr += ln;
3014 SecurityBlobLength += ln;
3015 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016 }
3017
Steve French63135e02007-07-17 17:34:02 +00003018 /* SecurityBlob->WorkstationName.Length =
3019 cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020 SecurityBlob->WorkstationName.Length *= 2;
Steve French63135e02007-07-17 17:34:02 +00003021 SecurityBlob->WorkstationName.MaximumLength =
3022 cpu_to_le16(SecurityBlob->WorkstationName.Length);
3023 SecurityBlob->WorkstationName.Buffer =
3024 cpu_to_le32(SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025 bcc_ptr += SecurityBlob->WorkstationName.Length;
3026 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
Steve French63135e02007-07-17 17:34:02 +00003027 SecurityBlob->WorkstationName.Length =
3028 cpu_to_le16(SecurityBlob->WorkstationName.Length); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029
3030 if ((long) bcc_ptr % 2) {
3031 *bcc_ptr = 0;
3032 bcc_ptr++;
3033 }
3034 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003035 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003036 32, nls_codepage);
3037 bcc_ptr += 2 * bytes_returned;
3038 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003039 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003040 nls_codepage);
3041 bcc_ptr += 2 * bytes_returned;
3042 bcc_ptr += 2; /* null term version string */
3043 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003044 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045 64, nls_codepage);
3046 bcc_ptr += 2 * bytes_returned;
3047 *(bcc_ptr + 1) = 0;
3048 *(bcc_ptr + 2) = 0;
3049 bcc_ptr += 2; /* null terminate network opsys string */
3050 *(bcc_ptr + 1) = 0;
3051 *(bcc_ptr + 2) = 0;
3052 bcc_ptr += 2; /* null domain */
3053 } else { /* ASCII */
3054 if (domain == NULL) {
3055 SecurityBlob->DomainName.Buffer = 0;
3056 SecurityBlob->DomainName.Length = 0;
3057 SecurityBlob->DomainName.MaximumLength = 0;
3058 } else {
Steve French77159b42007-08-31 01:10:17 +00003059 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
3061 strncpy(bcc_ptr, domain, 63);
Steve French77159b42007-08-31 01:10:17 +00003062 ln = strnlen(domain, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003064 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065 SecurityBlob->DomainName.Buffer =
3066 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003067 bcc_ptr += ln;
3068 SecurityBlobLength += ln;
3069 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070 }
3071 if (user == NULL) {
3072 SecurityBlob->UserName.Buffer = 0;
3073 SecurityBlob->UserName.Length = 0;
3074 SecurityBlob->UserName.MaximumLength = 0;
3075 } else {
Steve French77159b42007-08-31 01:10:17 +00003076 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077 strncpy(bcc_ptr, user, 63);
Steve French77159b42007-08-31 01:10:17 +00003078 ln = strnlen(user, 64);
3079 SecurityBlob->UserName.MaximumLength = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080 SecurityBlob->UserName.Buffer =
Steve French77159b42007-08-31 01:10:17 +00003081 cpu_to_le32(SecurityBlobLength);
3082 bcc_ptr += ln;
3083 SecurityBlobLength += ln;
3084 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085 }
3086 /* BB fill in our workstation name if known BB */
3087
3088 strcpy(bcc_ptr, "Linux version ");
3089 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003090 strcpy(bcc_ptr, utsname()->release);
3091 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
3093 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
3094 bcc_ptr++; /* null domain */
3095 *bcc_ptr = 0;
3096 }
3097 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
3098 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
3099 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
3100 smb_buffer->smb_buf_length += count;
3101 pSMB->req.ByteCount = cpu_to_le16(count);
3102
3103 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
3104 &bytes_returned, 1);
3105 if (rc) {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003106/* rc = map_smb_to_linux_error(smb_buffer_response) done in SendReceive now */
3107 } else if ((smb_buffer_response->WordCount == 3) ||
3108 (smb_buffer_response->WordCount == 4)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109 __u16 action = le16_to_cpu(pSMBr->resp.Action);
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003110 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00003112 cFYI(1, (" Guest login")); /* BB Should we set anything
3113 in SesInfo struct ? */
3114/* if (SecurityBlob2->MessageType != NtLm??) {
3115 cFYI("Unexpected message type on auth response is %d"));
3116 } */
3117
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118 if (ses) {
3119 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003120 ("Check challenge UID %d vs auth response UID %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121 ses->Suid, smb_buffer_response->Uid));
Steve French50c2f752007-07-13 00:33:32 +00003122 /* UID left in wire format */
3123 ses->Suid = smb_buffer_response->Uid;
3124 bcc_ptr = pByteArea(smb_buffer_response);
3125 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126 if ((pSMBr->resp.hdr.WordCount == 3)
3127 || ((pSMBr->resp.hdr.WordCount == 4)
3128 && (blob_len <
3129 pSMBr->resp.ByteCount))) {
3130 if (pSMBr->resp.hdr.WordCount == 4) {
3131 bcc_ptr +=
3132 blob_len;
3133 cFYI(1,
3134 ("Security Blob Length %d ",
3135 blob_len));
3136 }
3137
3138 cFYI(1,
3139 ("NTLMSSP response to Authenticate "));
3140
3141 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3142 if ((long) (bcc_ptr) % 2) {
3143 remaining_words =
3144 (BCC(smb_buffer_response)
3145 - 1) / 2;
3146 bcc_ptr++; /* Unicode strings must be word aligned */
3147 } else {
3148 remaining_words = BCC(smb_buffer_response) / 2;
3149 }
Steve French77159b42007-08-31 01:10:17 +00003150 len = UniStrnlen((wchar_t *) bcc_ptr,
3151 remaining_words - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003152/* We look for obvious messed up bcc or strings in response so we do not go off
3153 the end since (at least) WIN2K and Windows XP have a major bug in not null
3154 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003155 if (ses->serverOS)
Steve French08775832006-05-30 18:08:26 +00003156 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003157 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003158 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003159 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003160 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161 bcc_ptr, len,
3162 nls_codepage);
3163 bcc_ptr += 2 * (len + 1);
3164 remaining_words -= len + 1;
3165 ses->serverOS[2 * len] = 0;
3166 ses->serverOS[1 + (2 * len)] = 0;
3167 if (remaining_words > 0) {
3168 len = UniStrnlen((wchar_t *)
3169 bcc_ptr,
3170 remaining_words
3171 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00003172 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003174 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003175 GFP_KERNEL);
3176 cifs_strfromUCS_le(ses->
3177 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003178 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179 bcc_ptr,
3180 len,
3181 nls_codepage);
3182 bcc_ptr += 2 * (len + 1);
3183 ses->serverNOS[2 * len] = 0;
3184 ses->serverNOS[1+(2*len)] = 0;
3185 remaining_words -= len + 1;
3186 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00003187 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188 /* last string not always null terminated (e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003189 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003190 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003192 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193 (len +
3194 1),
3195 GFP_KERNEL);
3196 cifs_strfromUCS_le
3197 (ses->
3198 serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08003199 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200 bcc_ptr, len,
3201 nls_codepage);
3202 bcc_ptr +=
3203 2 * (len + 1);
3204 ses->
3205 serverDomain[2
3206 * len]
3207 = 0;
3208 ses->
3209 serverDomain[1
3210 +
3211 (2
3212 *
3213 len)]
3214 = 0;
3215 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003216 else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003217 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003218 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003219 ses->serverDomain = kzalloc(2,GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00003220 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003221 } else { /* no room so create dummy domain and NOS string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003222 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003223 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003224 ses->serverDomain = kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00003225 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003226 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227 }
3228 } else { /* ASCII */
3229 len = strnlen(bcc_ptr, 1024);
Steve French50c2f752007-07-13 00:33:32 +00003230 if (((long) bcc_ptr + len) -
3231 (long) pByteArea(smb_buffer_response)
Steve French63135e02007-07-17 17:34:02 +00003232 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003233 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00003234 kfree(ses->serverOS);
Steve French77159b42007-08-31 01:10:17 +00003235 ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236 strncpy(ses->serverOS,bcc_ptr, len);
3237
3238 bcc_ptr += len;
3239 bcc_ptr[0] = 0; /* null terminate the string */
3240 bcc_ptr++;
3241
3242 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003243 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00003244 ses->serverNOS = kzalloc(len+1,
3245 GFP_KERNEL);
Steve French63135e02007-07-17 17:34:02 +00003246 strncpy(ses->serverNOS,
3247 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248 bcc_ptr += len;
3249 bcc_ptr[0] = 0;
3250 bcc_ptr++;
3251
3252 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003253 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003254 kfree(ses->serverDomain);
Steve French63135e02007-07-17 17:34:02 +00003255 ses->serverDomain =
3256 kzalloc(len+1,
3257 GFP_KERNEL);
3258 strncpy(ses->serverDomain,
3259 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260 bcc_ptr += len;
3261 bcc_ptr[0] = 0;
3262 bcc_ptr++;
3263 } else
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003264 cFYI(1, ("field of length %d "
Steve French63135e02007-07-17 17:34:02 +00003265 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266 len));
3267 }
3268 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003269 cERROR(1, ("Security Blob extends beyond end "
Steve French63135e02007-07-17 17:34:02 +00003270 "of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271 }
3272 } else {
3273 cERROR(1, ("No session structure passed in."));
3274 }
3275 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003276 cERROR(1, ("Invalid Word count %d: ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003277 smb_buffer_response->WordCount));
3278 rc = -EIO;
3279 }
3280
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003281 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282
3283 return rc;
3284}
3285
3286int
3287CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3288 const char *tree, struct cifsTconInfo *tcon,
3289 const struct nls_table *nls_codepage)
3290{
3291 struct smb_hdr *smb_buffer;
3292 struct smb_hdr *smb_buffer_response;
3293 TCONX_REQ *pSMB;
3294 TCONX_RSP *pSMBr;
3295 unsigned char *bcc_ptr;
3296 int rc = 0;
3297 int length;
3298 __u16 count;
3299
3300 if (ses == NULL)
3301 return -EIO;
3302
3303 smb_buffer = cifs_buf_get();
3304 if (smb_buffer == NULL) {
3305 return -ENOMEM;
3306 }
3307 smb_buffer_response = smb_buffer;
3308
3309 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3310 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003311
3312 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003313 smb_buffer->Uid = ses->Suid;
3314 pSMB = (TCONX_REQ *) smb_buffer;
3315 pSMBr = (TCONX_RSP *) smb_buffer_response;
3316
3317 pSMB->AndXCommand = 0xFF;
3318 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319 bcc_ptr = &pSMB->Password[0];
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003320 if ((ses->server->secMode) & SECMODE_USER) {
Steve Frencheeac8042006-01-13 21:34:58 -08003321 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00003322 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08003323 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00003324 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08003325 } else {
Steve French7c7b25b2006-06-01 19:20:10 +00003326 pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08003327 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
3328 specified as required (when that support is added to
3329 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00003330 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08003331 by Samba (not sure whether other servers allow
3332 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00003333#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French50c2f752007-07-13 00:33:32 +00003334 if ((extended_security & CIFSSEC_MAY_LANMAN) &&
Steve French7c7b25b2006-06-01 19:20:10 +00003335 (ses->server->secType == LANMAN))
3336 calc_lanman_hash(ses, bcc_ptr);
3337 else
3338#endif /* CIFS_WEAK_PW_HASH */
Steve Frencheeac8042006-01-13 21:34:58 -08003339 SMBNTencrypt(ses->password,
3340 ses->server->cryptKey,
3341 bcc_ptr);
3342
Steve French7c7b25b2006-06-01 19:20:10 +00003343 bcc_ptr += CIFS_SESS_KEY_SIZE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003344 if (ses->capabilities & CAP_UNICODE) {
Steve French7c7b25b2006-06-01 19:20:10 +00003345 /* must align unicode strings */
3346 *bcc_ptr = 0; /* null byte password */
3347 bcc_ptr++;
3348 }
Steve Frencheeac8042006-01-13 21:34:58 -08003349 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003350
Steve French50c2f752007-07-13 00:33:32 +00003351 if (ses->server->secMode &
Steve Frencha878fb22006-05-30 18:04:19 +00003352 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3354
3355 if (ses->capabilities & CAP_STATUS32) {
3356 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3357 }
3358 if (ses->capabilities & CAP_DFS) {
3359 smb_buffer->Flags2 |= SMBFLG2_DFS;
3360 }
3361 if (ses->capabilities & CAP_UNICODE) {
3362 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3363 length =
Steve French50c2f752007-07-13 00:33:32 +00003364 cifs_strtoUCS((__le16 *) bcc_ptr, tree,
3365 6 /* max utf8 char length in bytes */ *
Steve Frencha878fb22006-05-30 18:04:19 +00003366 (/* server len*/ + 256 /* share len */), nls_codepage);
3367 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368 bcc_ptr += 2; /* skip trailing null */
3369 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370 strcpy(bcc_ptr, tree);
3371 bcc_ptr += strlen(tree) + 1;
3372 }
3373 strcpy(bcc_ptr, "?????");
3374 bcc_ptr += strlen("?????");
3375 bcc_ptr += 1;
3376 count = bcc_ptr - &pSMB->Password[0];
3377 pSMB->hdr.smb_buf_length += count;
3378 pSMB->ByteCount = cpu_to_le16(count);
3379
3380 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
3381
3382 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3383 /* above now done in SendReceive */
3384 if ((rc == 0) && (tcon != NULL)) {
3385 tcon->tidStatus = CifsGood;
3386 tcon->tid = smb_buffer_response->Tid;
3387 bcc_ptr = pByteArea(smb_buffer_response);
3388 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
Steve French50c2f752007-07-13 00:33:32 +00003389 /* skip service field (NB: this field is always ASCII) */
Steve French7f8ed422007-09-28 22:28:55 +00003390 if (length == 3) {
3391 if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') &&
3392 (bcc_ptr[2] == 'C')) {
3393 cFYI(1, ("IPC connection"));
3394 tcon->ipc = 1;
3395 }
3396 } else if (length == 2) {
3397 if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) {
3398 /* the most common case */
3399 cFYI(1, ("disk share connection"));
3400 }
3401 }
Steve French50c2f752007-07-13 00:33:32 +00003402 bcc_ptr += length + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003403 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3404 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3405 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3406 if ((bcc_ptr + (2 * length)) -
3407 pByteArea(smb_buffer_response) <=
3408 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003409 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003410 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003411 kzalloc(length + 2, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003412 if (tcon->nativeFileSystem)
3413 cifs_strfromUCS_le(
3414 tcon->nativeFileSystem,
3415 (__le16 *) bcc_ptr,
3416 length, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003417 bcc_ptr += 2 * length;
3418 bcc_ptr[0] = 0; /* null terminate the string */
3419 bcc_ptr[1] = 0;
3420 bcc_ptr += 2;
3421 }
Steve French50c2f752007-07-13 00:33:32 +00003422 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423 } else {
3424 length = strnlen(bcc_ptr, 1024);
3425 if ((bcc_ptr + length) -
3426 pByteArea(smb_buffer_response) <=
3427 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003428 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003430 kzalloc(length + 1, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003431 if (tcon->nativeFileSystem)
3432 strncpy(tcon->nativeFileSystem, bcc_ptr,
3433 length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434 }
Steve French50c2f752007-07-13 00:33:32 +00003435 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003437 if ((smb_buffer_response->WordCount == 3) ||
Steve French1a4e15a2006-10-12 21:33:51 +00003438 (smb_buffer_response->WordCount == 7))
3439 /* field is in same location */
Steve French39798772006-05-31 22:40:51 +00003440 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3441 else
3442 tcon->Flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3444 } else if ((rc == 0) && tcon == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00003445 /* all we need to save for IPC$ connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446 ses->ipc_tid = smb_buffer_response->Tid;
3447 }
3448
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003449 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450 return rc;
3451}
3452
3453int
3454cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3455{
3456 int rc = 0;
3457 int xid;
3458 struct cifsSesInfo *ses = NULL;
3459 struct task_struct *cifsd_task;
Steve French50c2f752007-07-13 00:33:32 +00003460 char *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461
3462 xid = GetXid();
3463
3464 if (cifs_sb->tcon) {
3465 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3466 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3467 if (rc == -EBUSY) {
3468 FreeXid(xid);
3469 return 0;
3470 }
3471 tconInfoFree(cifs_sb->tcon);
3472 if ((ses) && (ses->server)) {
3473 /* save off task so we do not refer to ses later */
3474 cifsd_task = ses->server->tsk;
3475 cFYI(1, ("About to do SMBLogoff "));
3476 rc = CIFSSMBLogoff(xid, ses);
3477 if (rc == -EBUSY) {
3478 FreeXid(xid);
3479 return 0;
3480 } else if (rc == -ESHUTDOWN) {
Steve French467a8f82007-06-27 22:41:32 +00003481 cFYI(1, ("Waking up socket by sending signal"));
Steve Frenchf7f7c312007-05-24 02:29:51 +00003482 if (cifsd_task) {
Steve French50c2f752007-07-13 00:33:32 +00003483 force_sig(SIGKILL, cifsd_task);
Igor Mammedovaaf737a2007-04-03 19:16:43 +00003484 kthread_stop(cifsd_task);
Steve Frenchf1914012005-08-18 09:37:34 -07003485 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486 rc = 0;
3487 } /* else - we have an smb session
3488 left on this socket do not kill cifsd */
3489 } else
3490 cFYI(1, ("No session or bad tcon"));
3491 }
Steve French50c2f752007-07-13 00:33:32 +00003492
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493 cifs_sb->tcon = NULL;
Steve French2fe87f02006-09-21 07:02:52 +00003494 tmp = cifs_sb->prepath;
3495 cifs_sb->prepathlen = 0;
3496 cifs_sb->prepath = NULL;
3497 kfree(tmp);
Nishanth Aravamudan041e0e32005-09-10 00:27:23 -07003498 if (ses)
3499 schedule_timeout_interruptible(msecs_to_jiffies(500));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500 if (ses)
3501 sesInfoFree(ses);
3502
3503 FreeXid(xid);
Steve French50c2f752007-07-13 00:33:32 +00003504 return rc; /* BB check if we should always return zero here */
3505}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506
3507int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
Steve French50c2f752007-07-13 00:33:32 +00003508 struct nls_table *nls_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003509{
3510 int rc = 0;
Steve French7c7b25b2006-06-01 19:20:10 +00003511 char ntlm_session_key[CIFS_SESS_KEY_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512 int ntlmv2_flag = FALSE;
Steve Frenchad009ac2005-04-28 22:41:05 -07003513 int first_time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514
3515 /* what if server changes its buffer size after dropping the session? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003516 if (pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003517 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003518 if (rc == -EAGAIN) /* retry only once on 1st time connection */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003519 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve French50c2f752007-07-13 00:33:32 +00003520 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521 rc = -EHOSTDOWN;
3522 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003523 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524 spin_lock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003525 if (pSesInfo->server->tcpStatus != CifsExiting)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003526 pSesInfo->server->tcpStatus = CifsGood;
3527 else
3528 rc = -EHOSTDOWN;
3529 spin_unlock(&GlobalMid_Lock);
3530
3531 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003532 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533 }
3534 if (!rc) {
Steve French9ac00b72006-09-30 04:13:17 +00003535 pSesInfo->flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003536 pSesInfo->capabilities = pSesInfo->server->capabilities;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003537 if (linuxExtEnabled == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003538 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003539 /* pSesInfo->sequence_number = 0;*/
Steve French50c2f752007-07-13 00:33:32 +00003540 cFYI(1,
3541 ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542 pSesInfo->server->secMode,
3543 pSesInfo->server->capabilities,
Steve French175ec9e2006-09-30 01:07:38 +00003544 pSesInfo->server->timeAdj));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003545 if (experimEnabled < 2)
Steve French39798772006-05-31 22:40:51 +00003546 rc = CIFS_SessSetup(xid, pSesInfo,
3547 first_time, nls_info);
Steve French189acaa2006-06-23 02:33:48 +00003548 else if (extended_security
Steve French50c2f752007-07-13 00:33:32 +00003549 && (pSesInfo->capabilities
Steve French175ec9e2006-09-30 01:07:38 +00003550 & CAP_EXTENDED_SECURITY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003551 && (pSesInfo->server->secType == NTLMSSP)) {
Steve French189acaa2006-06-23 02:33:48 +00003552 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003553 } else if (extended_security
3554 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3555 && (pSesInfo->server->secType == RawNTLMSSP)) {
Steve French5815449d2006-02-14 01:36:20 +00003556 cFYI(1, ("NTLMSSP sesssetup"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3558 pSesInfo,
3559 &ntlmv2_flag,
3560 nls_info);
3561 if (!rc) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003562 if (ntlmv2_flag) {
Steve French50c2f752007-07-13 00:33:32 +00003563 char *v2_response;
Steve French467a8f82007-06-27 22:41:32 +00003564 cFYI(1, ("more secure NTLM ver2 hash"));
Steve French50c2f752007-07-13 00:33:32 +00003565 if (CalcNTLMv2_partial_mac_key(pSesInfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566 nls_info)) {
3567 rc = -ENOMEM;
3568 goto ss_err_exit;
3569 } else
3570 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003571 if (v2_response) {
Steve French50c2f752007-07-13 00:33:32 +00003572 CalcNTLMv2_response(pSesInfo,
3573 v2_response);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003574 /* if (first_time)
Steve French50c2f752007-07-13 00:33:32 +00003575 cifs_calculate_ntlmv2_mac_key(
3576 pSesInfo->server->mac_signing_key,
3577 response, ntlm_session_key,*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003578 kfree(v2_response);
3579 /* BB Put dummy sig in SessSetup PDU? */
3580 } else {
3581 rc = -ENOMEM;
3582 goto ss_err_exit;
3583 }
3584
3585 } else {
3586 SMBNTencrypt(pSesInfo->password,
3587 pSesInfo->server->cryptKey,
3588 ntlm_session_key);
3589
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003590 if (first_time)
Steve Frenchad009ac2005-04-28 22:41:05 -07003591 cifs_calculate_mac_key(
Steve Frenchb609f062007-07-09 07:55:14 +00003592 &pSesInfo->server->mac_signing_key,
Steve Frenchad009ac2005-04-28 22:41:05 -07003593 ntlm_session_key,
3594 pSesInfo->password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003595 }
3596 /* for better security the weaker lanman hash not sent
3597 in AuthSessSetup so we no longer calculate it */
3598
3599 rc = CIFSNTLMSSPAuthSessSetup(xid,
3600 pSesInfo,
3601 ntlm_session_key,
3602 ntlmv2_flag,
3603 nls_info);
3604 }
3605 } else { /* old style NTLM 0.12 session setup */
3606 SMBNTencrypt(pSesInfo->password,
3607 pSesInfo->server->cryptKey,
3608 ntlm_session_key);
3609
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003610 if (first_time)
Steve Frenchad009ac2005-04-28 22:41:05 -07003611 cifs_calculate_mac_key(
Steve Frenchb609f062007-07-09 07:55:14 +00003612 &pSesInfo->server->mac_signing_key,
Steve Frenchad009ac2005-04-28 22:41:05 -07003613 ntlm_session_key, pSesInfo->password);
3614
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615 rc = CIFSSessSetup(xid, pSesInfo,
3616 ntlm_session_key, nls_info);
3617 }
3618 if (rc) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003619 cERROR(1, ("Send error in SessSetup = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620 } else {
Steve French467a8f82007-06-27 22:41:32 +00003621 cFYI(1, ("CIFS Session Established successfully"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003622 pSesInfo->status = CifsGood;
3623 }
3624 }
3625ss_err_exit:
3626 return rc;
3627}
3628