blob: 73ed9fcab821f2f50e8f2fe63835a80641f4b117 [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 */
676 if (bigbuf != NULL)
677 cifs_buf_release(bigbuf);
678 if (smallbuf != NULL)
679 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680
681 read_lock(&GlobalSMBSeslock);
682 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700683 /* loop through server session structures attached to this and
684 mark them dead */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 list_for_each(tmp, &GlobalSMBSessionList) {
686 ses =
687 list_entry(tmp, struct cifsSesInfo,
688 cifsSessionList);
689 if (ses->server == server) {
690 ses->status = CifsExiting;
691 ses->server = NULL;
692 }
693 }
694 read_unlock(&GlobalSMBSeslock);
695 } else {
Steve French31ca3bc2005-04-28 22:41:11 -0700696 /* although we can not zero the server struct pointer yet,
697 since there are active requests which may depnd on them,
698 mark the corresponding SMB sessions as exiting too */
699 list_for_each(tmp, &GlobalSMBSessionList) {
700 ses = list_entry(tmp, struct cifsSesInfo,
701 cifsSessionList);
Steve French26f57362007-08-30 22:09:15 +0000702 if (ses->server == server)
Steve French31ca3bc2005-04-28 22:41:11 -0700703 ses->status = CifsExiting;
Steve French31ca3bc2005-04-28 22:41:11 -0700704 }
705
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 spin_lock(&GlobalMid_Lock);
707 list_for_each(tmp, &server->pending_mid_q) {
708 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
709 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French50c2f752007-07-13 00:33:32 +0000710 cFYI(1, ("Clearing Mid 0x%x - waking up ",
711 mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 task_to_wake = mid_entry->tsk;
Steve French26f57362007-08-30 22:09:15 +0000713 if (task_to_wake)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 wake_up_process(task_to_wake);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 }
716 }
717 spin_unlock(&GlobalMid_Lock);
718 read_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700720 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 }
722
Steve Frenchf1914012005-08-18 09:37:34 -0700723 if (!list_empty(&server->pending_mid_q)) {
Steve French50c2f752007-07-13 00:33:32 +0000724 /* mpx threads have not exited yet give them
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700726 /* due to delays on oplock break requests, we need
727 to wait at least 45 seconds before giving up
728 on a request getting a response and going ahead
729 and killing cifsd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve French31ca3bc2005-04-28 22:41:11 -0700731 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 /* if threads still have not exited they are probably never
733 coming home not much else we can do but free the memory */
734 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735
736 write_lock(&GlobalSMBSeslock);
737 atomic_dec(&tcpSesAllocCount);
738 length = tcpSesAllocCount.counter;
Steve French31ca3bc2005-04-28 22:41:11 -0700739
740 /* last chance to mark ses pointers invalid
741 if there are any pointing to this (e.g
Steve French50c2f752007-07-13 00:33:32 +0000742 if a crazy root user tried to kill cifsd
Steve French31ca3bc2005-04-28 22:41:11 -0700743 kernel thread explicitly this might happen) */
744 list_for_each(tmp, &GlobalSMBSessionList) {
745 ses = list_entry(tmp, struct cifsSesInfo,
746 cifsSessionList);
Steve French26f57362007-08-30 22:09:15 +0000747 if (ses->server == server)
Steve French31ca3bc2005-04-28 22:41:11 -0700748 ses->server = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700749 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 write_unlock(&GlobalSMBSeslock);
Steve French31ca3bc2005-04-28 22:41:11 -0700751
752 kfree(server);
Steve French26f57362007-08-30 22:09:15 +0000753 if (length > 0)
754 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
755 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +0000756
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 return 0;
758}
759
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760static int
Steve French50c2f752007-07-13 00:33:32 +0000761cifs_parse_mount_options(char *options, const char *devname,
762 struct smb_vol *vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763{
764 char *value;
765 char *data;
766 unsigned int temp_len, i, j;
767 char separator[2];
768
769 separator[0] = ',';
Steve French50c2f752007-07-13 00:33:32 +0000770 separator[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771
Linus Torvalds12e36b22006-10-13 08:09:29 -0700772 if (Local_System_Name[0] != 0)
Steve French50c2f752007-07-13 00:33:32 +0000773 memcpy(vol->source_rfc1001_name, Local_System_Name, 15);
Steve French2cd646a2006-09-28 19:43:08 +0000774 else {
Linus Torvalds12e36b22006-10-13 08:09:29 -0700775 char *nodename = utsname()->nodename;
Steve French50c2f752007-07-13 00:33:32 +0000776 int n = strnlen(nodename, 15);
777 memset(vol->source_rfc1001_name, 0x20, 15);
778 for (i = 0; i < n; i++) {
Steve French2cd646a2006-09-28 19:43:08 +0000779 /* does not have to be perfect mapping since field is
780 informational, only used for servers that do not support
781 port 445 and it can be overridden at mount time */
Linus Torvalds12e36b22006-10-13 08:09:29 -0700782 vol->source_rfc1001_name[i] = toupper(nodename[i]);
Steve French2cd646a2006-09-28 19:43:08 +0000783 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 }
785 vol->source_rfc1001_name[15] = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -0700786 /* null target name indicates to use *SMBSERVR default called name
787 if we end up sending RFC1001 session initialize */
788 vol->target_rfc1001_name[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 vol->linux_uid = current->uid; /* current->euid instead? */
790 vol->linux_gid = current->gid;
791 vol->dir_mode = S_IRWXUGO;
792 /* 2767 perms indicate mandatory locking support */
793 vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);
794
795 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
796 vol->rw = TRUE;
Jeremy Allisonac670552005-06-22 17:26:35 -0700797 /* default is always to request posix paths. */
798 vol->posix_paths = 1;
799
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 if (!options)
801 return 1;
802
Steve French50c2f752007-07-13 00:33:32 +0000803 if (strncmp(options, "sep=", 4) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000804 if (options[4] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 separator[0] = options[4];
806 options += 5;
807 } else {
Steve French467a8f82007-06-27 22:41:32 +0000808 cFYI(1, ("Null separator not allowed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 }
810 }
Steve French50c2f752007-07-13 00:33:32 +0000811
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 while ((data = strsep(&options, separator)) != NULL) {
813 if (!*data)
814 continue;
815 if ((value = strchr(data, '=')) != NULL)
816 *value++ = '\0';
817
Steve French50c2f752007-07-13 00:33:32 +0000818 /* Have to parse this before we parse for "user" */
819 if (strnicmp(data, "user_xattr", 10) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 vol->no_xattr = 0;
Steve French50c2f752007-07-13 00:33:32 +0000821 } else if (strnicmp(data, "nouser_xattr", 12) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 vol->no_xattr = 1;
823 } else if (strnicmp(data, "user", 4) == 0) {
Steve French4b952a92006-10-30 21:46:13 +0000824 if (!value) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 printk(KERN_WARNING
826 "CIFS: invalid or missing username\n");
827 return 1; /* needs_arg; */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000828 } else if (!*value) {
Steve French4b952a92006-10-30 21:46:13 +0000829 /* null user, ie anonymous, authentication */
830 vol->nullauth = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 }
832 if (strnlen(value, 200) < 200) {
833 vol->username = value;
834 } else {
835 printk(KERN_WARNING "CIFS: username too long\n");
836 return 1;
837 }
838 } else if (strnicmp(data, "pass", 4) == 0) {
839 if (!value) {
840 vol->password = NULL;
841 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000842 } else if (value[0] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 /* check if string begins with double comma
844 since that would mean the password really
845 does start with a comma, and would not
846 indicate an empty string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000847 if (value[1] != separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 vol->password = NULL;
849 continue;
850 }
851 }
852 temp_len = strlen(value);
853 /* removed password length check, NTLM passwords
854 can be arbitrarily long */
855
Steve French50c2f752007-07-13 00:33:32 +0000856 /* if comma in password, the string will be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 prematurely null terminated. Commas in password are
858 specified across the cifs mount interface by a double
859 comma ie ,, and a comma used as in other cases ie ','
860 as a parameter delimiter/separator is single and due
861 to the strsep above is temporarily zeroed. */
862
863 /* NB: password legally can have multiple commas and
864 the only illegal character in a password is null */
865
Steve French50c2f752007-07-13 00:33:32 +0000866 if ((value[temp_len] == 0) &&
Steve French09d1db52005-04-28 22:41:08 -0700867 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 /* reinsert comma */
869 value[temp_len] = separator[0];
Steve French50c2f752007-07-13 00:33:32 +0000870 temp_len += 2; /* move after second comma */
871 while (value[temp_len] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 if (value[temp_len] == separator[0]) {
Steve French50c2f752007-07-13 00:33:32 +0000873 if (value[temp_len+1] ==
Steve French09d1db52005-04-28 22:41:08 -0700874 separator[0]) {
875 /* skip second comma */
876 temp_len++;
Steve French50c2f752007-07-13 00:33:32 +0000877 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 /* single comma indicating start
879 of next parm */
880 break;
881 }
882 }
883 temp_len++;
884 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000885 if (value[temp_len] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 options = NULL;
887 } else {
888 value[temp_len] = 0;
889 /* point option to start of next parm */
890 options = value + temp_len + 1;
891 }
Steve French50c2f752007-07-13 00:33:32 +0000892 /* go from value to value + temp_len condensing
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 double commas to singles. Note that this ends up
894 allocating a few bytes too many, which is ok */
Pekka Enberge915fc42005-09-06 15:18:35 -0700895 vol->password = kzalloc(temp_len, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000896 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000897 printk(KERN_WARNING "CIFS: no memory "
898 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700899 return 1;
900 }
Steve French50c2f752007-07-13 00:33:32 +0000901 for (i = 0, j = 0; i < temp_len; i++, j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 vol->password[j] = value[i];
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000903 if (value[i] == separator[0]
Steve French09d1db52005-04-28 22:41:08 -0700904 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 /* skip second comma */
906 i++;
907 }
908 }
909 vol->password[j] = 0;
910 } else {
Pekka Enberge915fc42005-09-06 15:18:35 -0700911 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000912 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000913 printk(KERN_WARNING "CIFS: no memory "
914 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700915 return 1;
916 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 strcpy(vol->password, value);
918 }
919 } else if (strnicmp(data, "ip", 2) == 0) {
920 if (!value || !*value) {
921 vol->UNCip = NULL;
922 } else if (strnlen(value, 35) < 35) {
923 vol->UNCip = value;
924 } else {
Steve French50c2f752007-07-13 00:33:32 +0000925 printk(KERN_WARNING "CIFS: ip address "
926 "too long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 return 1;
928 }
Steve French50c2f752007-07-13 00:33:32 +0000929 } else if (strnicmp(data, "sec", 3) == 0) {
930 if (!value || !*value) {
931 cERROR(1, ("no security value specified"));
932 continue;
933 } else if (strnicmp(value, "krb5i", 5) == 0) {
934 vol->secFlg |= CIFSSEC_MAY_KRB5 |
Steve French189acaa2006-06-23 02:33:48 +0000935 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800936 } else if (strnicmp(value, "krb5p", 5) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000937 /* vol->secFlg |= CIFSSEC_MUST_SEAL |
938 CIFSSEC_MAY_KRB5; */
939 cERROR(1, ("Krb5 cifs privacy not supported"));
Steve Frenchbf820672005-12-01 22:32:42 -0800940 return 1;
941 } else if (strnicmp(value, "krb5", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000942 vol->secFlg |= CIFSSEC_MAY_KRB5;
Steve Frenchbf820672005-12-01 22:32:42 -0800943 } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000944 vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
Steve French189acaa2006-06-23 02:33:48 +0000945 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800946 } else if (strnicmp(value, "ntlmv2", 6) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000947 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve Frenchbf820672005-12-01 22:32:42 -0800948 } else if (strnicmp(value, "ntlmi", 5) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000949 vol->secFlg |= CIFSSEC_MAY_NTLM |
Steve French189acaa2006-06-23 02:33:48 +0000950 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800951 } else if (strnicmp(value, "ntlm", 4) == 0) {
952 /* ntlm is default so can be turned off too */
Steve French750d1152006-06-27 06:28:30 +0000953 vol->secFlg |= CIFSSEC_MAY_NTLM;
Steve Frenchbf820672005-12-01 22:32:42 -0800954 } else if (strnicmp(value, "nontlm", 6) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000955 /* BB is there a better way to do this? */
Steve French750d1152006-06-27 06:28:30 +0000956 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve French189acaa2006-06-23 02:33:48 +0000957#ifdef CONFIG_CIFS_WEAK_PW_HASH
958 } else if (strnicmp(value, "lanman", 6) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000959 vol->secFlg |= CIFSSEC_MAY_LANMAN;
Steve French189acaa2006-06-23 02:33:48 +0000960#endif
Steve Frenchbf820672005-12-01 22:32:42 -0800961 } else if (strnicmp(value, "none", 4) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000962 vol->nullauth = 1;
Steve French50c2f752007-07-13 00:33:32 +0000963 } else {
964 cERROR(1, ("bad security option: %s", value));
965 return 1;
966 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 } else if ((strnicmp(data, "unc", 3) == 0)
968 || (strnicmp(data, "target", 6) == 0)
969 || (strnicmp(data, "path", 4) == 0)) {
970 if (!value || !*value) {
Steve French50c2f752007-07-13 00:33:32 +0000971 printk(KERN_WARNING "CIFS: invalid path to "
972 "network resource\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 return 1; /* needs_arg; */
974 }
975 if ((temp_len = strnlen(value, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +0000976 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +0000977 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 return 1;
Steve French50c2f752007-07-13 00:33:32 +0000979 strcpy(vol->UNC, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 if (strncmp(vol->UNC, "//", 2) == 0) {
981 vol->UNC[0] = '\\';
982 vol->UNC[1] = '\\';
Steve French50c2f752007-07-13 00:33:32 +0000983 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 printk(KERN_WARNING
Steve French50c2f752007-07-13 00:33:32 +0000985 "CIFS: UNC Path does not begin "
986 "with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 return 1;
988 }
989 } else {
990 printk(KERN_WARNING "CIFS: UNC name too long\n");
991 return 1;
992 }
993 } else if ((strnicmp(data, "domain", 3) == 0)
994 || (strnicmp(data, "workgroup", 5) == 0)) {
995 if (!value || !*value) {
996 printk(KERN_WARNING "CIFS: invalid domain name\n");
997 return 1; /* needs_arg; */
998 }
999 /* BB are there cases in which a comma can be valid in
1000 a domain name and need special handling? */
Steve French39798772006-05-31 22:40:51 +00001001 if (strnlen(value, 256) < 256) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 vol->domainname = value;
1003 cFYI(1, ("Domain name set"));
1004 } else {
Steve French50c2f752007-07-13 00:33:32 +00001005 printk(KERN_WARNING "CIFS: domain name too "
1006 "long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 return 1;
1008 }
Steve French50c2f752007-07-13 00:33:32 +00001009 } else if (strnicmp(data, "prefixpath", 10) == 0) {
1010 if (!value || !*value) {
1011 printk(KERN_WARNING
1012 "CIFS: invalid path prefix\n");
1013 return 1; /* needs_argument */
1014 }
1015 if ((temp_len = strnlen(value, 1024)) < 1024) {
Steve French4523cc32007-04-30 20:13:06 +00001016 if (value[0] != '/')
Steve French2fe87f02006-09-21 07:02:52 +00001017 temp_len++; /* missing leading slash */
Steve French50c2f752007-07-13 00:33:32 +00001018 vol->prepath = kmalloc(temp_len+1, GFP_KERNEL);
1019 if (vol->prepath == NULL)
1020 return 1;
Steve French4523cc32007-04-30 20:13:06 +00001021 if (value[0] != '/') {
Steve French2fe87f02006-09-21 07:02:52 +00001022 vol->prepath[0] = '/';
Steve French50c2f752007-07-13 00:33:32 +00001023 strcpy(vol->prepath+1, value);
Steve French2fe87f02006-09-21 07:02:52 +00001024 } else
Steve French50c2f752007-07-13 00:33:32 +00001025 strcpy(vol->prepath, value);
1026 cFYI(1, ("prefix path %s", vol->prepath));
1027 } else {
1028 printk(KERN_WARNING "CIFS: prefix too long\n");
1029 return 1;
1030 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 } else if (strnicmp(data, "iocharset", 9) == 0) {
1032 if (!value || !*value) {
Steve French63135e02007-07-17 17:34:02 +00001033 printk(KERN_WARNING "CIFS: invalid iocharset "
1034 "specified\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 return 1; /* needs_arg; */
1036 }
1037 if (strnlen(value, 65) < 65) {
Steve French50c2f752007-07-13 00:33:32 +00001038 if (strnicmp(value, "default", 7))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 vol->iocharset = value;
Steve French50c2f752007-07-13 00:33:32 +00001040 /* if iocharset not set then load_nls_default
1041 is used by caller */
1042 cFYI(1, ("iocharset set to %s", value));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 } else {
Steve French63135e02007-07-17 17:34:02 +00001044 printk(KERN_WARNING "CIFS: iocharset name "
1045 "too long.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 return 1;
1047 }
1048 } else if (strnicmp(data, "uid", 3) == 0) {
1049 if (value && *value) {
1050 vol->linux_uid =
1051 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001052 vol->override_uid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 }
1054 } else if (strnicmp(data, "gid", 3) == 0) {
1055 if (value && *value) {
1056 vol->linux_gid =
1057 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001058 vol->override_gid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 }
1060 } else if (strnicmp(data, "file_mode", 4) == 0) {
1061 if (value && *value) {
1062 vol->file_mode =
1063 simple_strtoul(value, &value, 0);
1064 }
1065 } else if (strnicmp(data, "dir_mode", 4) == 0) {
1066 if (value && *value) {
1067 vol->dir_mode =
1068 simple_strtoul(value, &value, 0);
1069 }
1070 } else if (strnicmp(data, "dirmode", 4) == 0) {
1071 if (value && *value) {
1072 vol->dir_mode =
1073 simple_strtoul(value, &value, 0);
1074 }
1075 } else if (strnicmp(data, "port", 4) == 0) {
1076 if (value && *value) {
1077 vol->port =
1078 simple_strtoul(value, &value, 0);
1079 }
1080 } else if (strnicmp(data, "rsize", 5) == 0) {
1081 if (value && *value) {
1082 vol->rsize =
1083 simple_strtoul(value, &value, 0);
1084 }
1085 } else if (strnicmp(data, "wsize", 5) == 0) {
1086 if (value && *value) {
1087 vol->wsize =
1088 simple_strtoul(value, &value, 0);
1089 }
1090 } else if (strnicmp(data, "sockopt", 5) == 0) {
1091 if (value && *value) {
1092 vol->sockopt =
1093 simple_strtoul(value, &value, 0);
1094 }
1095 } else if (strnicmp(data, "netbiosname", 4) == 0) {
1096 if (!value || !*value || (*value == ' ')) {
Steve French63135e02007-07-17 17:34:02 +00001097 cFYI(1, ("invalid (empty) netbiosname"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 } else {
Steve French50c2f752007-07-13 00:33:32 +00001099 memset(vol->source_rfc1001_name, 0x20, 15);
1100 for (i = 0; i < 15; i++) {
1101 /* BB are there cases in which a comma can be
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 valid in this workstation netbios name (and need
1103 special handling)? */
1104
1105 /* We do not uppercase netbiosname for user */
Steve French50c2f752007-07-13 00:33:32 +00001106 if (value[i] == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 break;
Steve French50c2f752007-07-13 00:33:32 +00001108 else
1109 vol->source_rfc1001_name[i] =
1110 value[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 }
1112 /* The string has 16th byte zero still from
1113 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001114 if ((i == 15) && (value[i] != 0))
1115 printk(KERN_WARNING "CIFS: netbiosname"
1116 " longer than 15 truncated.\n");
Steve Frencha10faeb22005-08-22 21:38:31 -07001117 }
1118 } else if (strnicmp(data, "servern", 7) == 0) {
1119 /* servernetbiosname specified override *SMBSERVER */
1120 if (!value || !*value || (*value == ' ')) {
Steve French467a8f82007-06-27 22:41:32 +00001121 cFYI(1, ("empty server netbiosname specified"));
Steve Frencha10faeb22005-08-22 21:38:31 -07001122 } else {
1123 /* last byte, type, is 0x20 for servr type */
Steve French50c2f752007-07-13 00:33:32 +00001124 memset(vol->target_rfc1001_name, 0x20, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001125
Steve French50c2f752007-07-13 00:33:32 +00001126 for (i = 0; i < 15; i++) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001127 /* BB are there cases in which a comma can be
Steve French50c2f752007-07-13 00:33:32 +00001128 valid in this workstation netbios name
1129 (and need special handling)? */
Steve Frencha10faeb22005-08-22 21:38:31 -07001130
Steve French50c2f752007-07-13 00:33:32 +00001131 /* user or mount helper must uppercase
1132 the netbiosname */
1133 if (value[i] == 0)
Steve Frencha10faeb22005-08-22 21:38:31 -07001134 break;
1135 else
Steve French50c2f752007-07-13 00:33:32 +00001136 vol->target_rfc1001_name[i] =
1137 value[i];
Steve Frencha10faeb22005-08-22 21:38:31 -07001138 }
1139 /* The string has 16th byte zero still from
1140 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001141 if ((i == 15) && (value[i] != 0))
1142 printk(KERN_WARNING "CIFS: server net"
1143 "biosname longer than 15 truncated.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 }
1145 } else if (strnicmp(data, "credentials", 4) == 0) {
1146 /* ignore */
1147 } else if (strnicmp(data, "version", 3) == 0) {
1148 /* ignore */
Steve French50c2f752007-07-13 00:33:32 +00001149 } else if (strnicmp(data, "guest", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 /* ignore */
1151 } else if (strnicmp(data, "rw", 2) == 0) {
1152 vol->rw = TRUE;
1153 } else if ((strnicmp(data, "suid", 4) == 0) ||
1154 (strnicmp(data, "nosuid", 6) == 0) ||
1155 (strnicmp(data, "exec", 4) == 0) ||
1156 (strnicmp(data, "noexec", 6) == 0) ||
1157 (strnicmp(data, "nodev", 5) == 0) ||
1158 (strnicmp(data, "noauto", 6) == 0) ||
1159 (strnicmp(data, "dev", 3) == 0)) {
1160 /* The mount tool or mount.cifs helper (if present)
Steve French50c2f752007-07-13 00:33:32 +00001161 uses these opts to set flags, and the flags are read
1162 by the kernel vfs layer before we get here (ie
1163 before read super) so there is no point trying to
1164 parse these options again and set anything and it
1165 is ok to just ignore them */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 continue;
1167 } else if (strnicmp(data, "ro", 2) == 0) {
1168 vol->rw = FALSE;
1169 } else if (strnicmp(data, "hard", 4) == 0) {
1170 vol->retry = 1;
1171 } else if (strnicmp(data, "soft", 4) == 0) {
1172 vol->retry = 0;
1173 } else if (strnicmp(data, "perm", 4) == 0) {
1174 vol->noperm = 0;
1175 } else if (strnicmp(data, "noperm", 6) == 0) {
1176 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001177 } else if (strnicmp(data, "mapchars", 8) == 0) {
1178 vol->remap = 1;
1179 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1180 vol->remap = 0;
Steve French50c2f752007-07-13 00:33:32 +00001181 } else if (strnicmp(data, "sfu", 3) == 0) {
1182 vol->sfu_emul = 1;
1183 } else if (strnicmp(data, "nosfu", 5) == 0) {
1184 vol->sfu_emul = 0;
Jeremy Allisonac670552005-06-22 17:26:35 -07001185 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1186 vol->posix_paths = 1;
1187 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1188 vol->posix_paths = 0;
Steve Frenchc18c8422007-07-18 23:21:09 +00001189 } else if (strnicmp(data, "nounix", 6) == 0) {
1190 vol->no_linux_ext = 1;
1191 } else if (strnicmp(data, "nolinux", 7) == 0) {
1192 vol->no_linux_ext = 1;
Steve French50c2f752007-07-13 00:33:32 +00001193 } else if ((strnicmp(data, "nocase", 6) == 0) ||
Steve Frencha10faeb22005-08-22 21:38:31 -07001194 (strnicmp(data, "ignorecase", 10) == 0)) {
Steve French50c2f752007-07-13 00:33:32 +00001195 vol->nocase = 1;
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001196 } else if (strnicmp(data, "brl", 3) == 0) {
1197 vol->nobrl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001198 } else if ((strnicmp(data, "nobrl", 5) == 0) ||
Steve French1c955182005-08-30 20:58:07 -07001199 (strnicmp(data, "nolock", 6) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001200 vol->nobrl = 1;
Steve Frenchd3485d32005-08-19 11:04:29 -07001201 /* turn off mandatory locking in mode
1202 if remote locking is turned off since the
1203 local vfs will do advisory */
Steve French50c2f752007-07-13 00:33:32 +00001204 if (vol->file_mode ==
1205 (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
Steve Frenchd3485d32005-08-19 11:04:29 -07001206 vol->file_mode = S_IALLUGO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 } else if (strnicmp(data, "setuids", 7) == 0) {
1208 vol->setuids = 1;
1209 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1210 vol->setuids = 0;
1211 } else if (strnicmp(data, "nohard", 6) == 0) {
1212 vol->retry = 0;
1213 } else if (strnicmp(data, "nosoft", 6) == 0) {
1214 vol->retry = 1;
1215 } else if (strnicmp(data, "nointr", 6) == 0) {
1216 vol->intr = 0;
1217 } else if (strnicmp(data, "intr", 4) == 0) {
1218 vol->intr = 1;
Steve French50c2f752007-07-13 00:33:32 +00001219 } else if (strnicmp(data, "serverino", 7) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 vol->server_ino = 1;
Steve French50c2f752007-07-13 00:33:32 +00001221 } else if (strnicmp(data, "noserverino", 9) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 vol->server_ino = 0;
Steve French50c2f752007-07-13 00:33:32 +00001223 } else if (strnicmp(data, "cifsacl", 7) == 0) {
Steve French0a4b92c2006-01-12 15:44:21 -08001224 vol->cifs_acl = 1;
1225 } else if (strnicmp(data, "nocifsacl", 9) == 0) {
1226 vol->cifs_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001227 } else if (strnicmp(data, "acl", 3) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 vol->no_psx_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001229 } else if (strnicmp(data, "noacl", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 vol->no_psx_acl = 1;
Steve French50c2f752007-07-13 00:33:32 +00001231 } else if (strnicmp(data, "sign", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +00001232 vol->secFlg |= CIFSSEC_MUST_SIGN;
1233/* } else if (strnicmp(data, "seal",4) == 0) {
1234 vol->secFlg |= CIFSSEC_MUST_SEAL; */
Steve French50c2f752007-07-13 00:33:32 +00001235 } else if (strnicmp(data, "direct", 6) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001237 } else if (strnicmp(data, "forcedirectio", 13) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001239 } else if (strnicmp(data, "in6_addr", 8) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 if (!value || !*value) {
1241 vol->in6_addr = NULL;
1242 } else if (strnlen(value, 49) == 48) {
1243 vol->in6_addr = value;
1244 } else {
Steve French50c2f752007-07-13 00:33:32 +00001245 printk(KERN_WARNING "CIFS: ip v6 address not "
1246 "48 characters long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 return 1;
1248 }
1249 } else if (strnicmp(data, "noac", 4) == 0) {
Steve French50c2f752007-07-13 00:33:32 +00001250 printk(KERN_WARNING "CIFS: Mount option noac not "
1251 "supported. Instead set "
1252 "/proc/fs/cifs/LookupCacheEnabled to 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 } else
Steve French50c2f752007-07-13 00:33:32 +00001254 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",
1255 data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 }
1257 if (vol->UNC == NULL) {
Steve French4523cc32007-04-30 20:13:06 +00001258 if (devname == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001259 printk(KERN_WARNING "CIFS: Missing UNC name for mount "
1260 "target\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 return 1;
1262 }
1263 if ((temp_len = strnlen(devname, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001264 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001265 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001267 strcpy(vol->UNC, devname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 if (strncmp(vol->UNC, "//", 2) == 0) {
1269 vol->UNC[0] = '\\';
1270 vol->UNC[1] = '\\';
1271 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Steve French50c2f752007-07-13 00:33:32 +00001272 printk(KERN_WARNING "CIFS: UNC Path does not "
1273 "begin with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 return 1;
1275 }
1276 } else {
1277 printk(KERN_WARNING "CIFS: UNC name too long\n");
1278 return 1;
1279 }
1280 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001281 if (vol->UNCip == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 vol->UNCip = &vol->UNC[2];
1283
1284 return 0;
1285}
1286
1287static struct cifsSesInfo *
Steve French50c2f752007-07-13 00:33:32 +00001288cifs_find_tcp_session(struct in_addr *target_ip_addr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 struct in6_addr *target_ip6_addr,
1290 char *userName, struct TCP_Server_Info **psrvTcp)
1291{
1292 struct list_head *tmp;
1293 struct cifsSesInfo *ses;
1294 *psrvTcp = NULL;
1295 read_lock(&GlobalSMBSeslock);
1296
1297 list_for_each(tmp, &GlobalSMBSessionList) {
1298 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
1299 if (ses->server) {
Steve French50c2f752007-07-13 00:33:32 +00001300 if ((target_ip_addr &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 (ses->server->addr.sockAddr.sin_addr.s_addr
1302 == target_ip_addr->s_addr)) || (target_ip6_addr
1303 && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
Steve French50c2f752007-07-13 00:33:32 +00001304 target_ip6_addr, sizeof(*target_ip6_addr)))) {
1305 /* BB lock server and tcp session and increment
1306 use count here?? */
1307
1308 /* found a match on the TCP session */
1309 *psrvTcp = ses->server;
1310
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 /* BB check if reconnection needed */
1312 if (strncmp
1313 (ses->userName, userName,
1314 MAX_USERNAME_SIZE) == 0){
1315 read_unlock(&GlobalSMBSeslock);
Steve French50c2f752007-07-13 00:33:32 +00001316 /* Found exact match on both TCP and
1317 SMB sessions */
1318 return ses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 }
1320 }
1321 }
1322 /* else tcp and smb sessions need reconnection */
1323 }
1324 read_unlock(&GlobalSMBSeslock);
1325 return NULL;
1326}
1327
1328static struct cifsTconInfo *
1329find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
1330{
1331 struct list_head *tmp;
1332 struct cifsTconInfo *tcon;
1333
1334 read_lock(&GlobalSMBSeslock);
1335 list_for_each(tmp, &GlobalTreeConnectionList) {
Steve Frenche466e482006-08-15 13:07:18 +00001336 cFYI(1, ("Next tcon"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
1338 if (tcon->ses) {
1339 if (tcon->ses->server) {
1340 cFYI(1,
Steve Frenche466e482006-08-15 13:07:18 +00001341 ("old ip addr: %x == new ip %x ?",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 tcon->ses->server->addr.sockAddr.sin_addr.
1343 s_addr, new_target_ip_addr));
1344 if (tcon->ses->server->addr.sockAddr.sin_addr.
1345 s_addr == new_target_ip_addr) {
Steve Frenche466e482006-08-15 13:07:18 +00001346 /* BB lock tcon, server and tcp session and increment use count here? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 /* found a match on the TCP session */
1348 /* BB check if reconnection needed */
Steve French50c2f752007-07-13 00:33:32 +00001349 cFYI(1,
1350 ("IP match, old UNC: %s new: %s",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 tcon->treeName, uncName));
1352 if (strncmp
1353 (tcon->treeName, uncName,
1354 MAX_TREE_SIZE) == 0) {
1355 cFYI(1,
Steve Frenche466e482006-08-15 13:07:18 +00001356 ("and old usr: %s new: %s",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 tcon->treeName, uncName));
1358 if (strncmp
1359 (tcon->ses->userName,
1360 userName,
1361 MAX_USERNAME_SIZE) == 0) {
1362 read_unlock(&GlobalSMBSeslock);
Steve Frenche466e482006-08-15 13:07:18 +00001363 /* matched smb session
1364 (user name */
1365 return tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 }
1367 }
1368 }
1369 }
1370 }
1371 }
1372 read_unlock(&GlobalSMBSeslock);
1373 return NULL;
1374}
1375
1376int
1377connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
Steve French737b7582005-04-28 22:41:06 -07001378 const char *old_path, const struct nls_table *nls_codepage,
1379 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380{
1381 unsigned char *referrals = NULL;
1382 unsigned int num_referrals;
1383 int rc = 0;
1384
Steve French50c2f752007-07-13 00:33:32 +00001385 rc = get_dfs_path(xid, pSesInfo, old_path, nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001386 &num_referrals, &referrals, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387
1388 /* BB Add in code to: if valid refrl, if not ip address contact
Steve French50c2f752007-07-13 00:33:32 +00001389 the helper that resolves tcp names, mount to it, try to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 tcon to it unmount it if fail */
1391
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001392 kfree(referrals);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393
1394 return rc;
1395}
1396
1397int
Steve French50c2f752007-07-13 00:33:32 +00001398get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
1399 const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
1400 unsigned char **preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401{
1402 char *temp_unc;
1403 int rc = 0;
1404
1405 *pnum_referrals = 0;
1406
1407 if (pSesInfo->ipc_tid == 0) {
1408 temp_unc = kmalloc(2 /* for slashes */ +
Steve French50c2f752007-07-13 00:33:32 +00001409 strnlen(pSesInfo->serverName,
1410 SERVER_NAME_LEN_WITH_NULL * 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 + 1 + 4 /* slash IPC$ */ + 2,
1412 GFP_KERNEL);
1413 if (temp_unc == NULL)
1414 return -ENOMEM;
1415 temp_unc[0] = '\\';
1416 temp_unc[1] = '\\';
1417 strcpy(temp_unc + 2, pSesInfo->serverName);
1418 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1419 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1420 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00001421 ("CIFS Tcon rc = %d ipc_tid = %d", rc, pSesInfo->ipc_tid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 kfree(temp_unc);
1423 }
1424 if (rc == 0)
1425 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001426 pnum_referrals, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427
1428 return rc;
1429}
1430
1431/* See RFC1001 section 14 on representation of Netbios names */
Steve French50c2f752007-07-13 00:33:32 +00001432static void rfc1002mangle(char *target, char *source, unsigned int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433{
Steve French50c2f752007-07-13 00:33:32 +00001434 unsigned int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435
Steve French50c2f752007-07-13 00:33:32 +00001436 for (i = 0, j = 0; i < (length); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 /* mask a nibble at a time and encode */
1438 target[j] = 'A' + (0x0F & (source[i] >> 4));
1439 target[j+1] = 'A' + (0x0F & source[i]);
Steve French50c2f752007-07-13 00:33:32 +00001440 j += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 }
1442
1443}
1444
1445
1446static int
Steve French50c2f752007-07-13 00:33:32 +00001447ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
1448 char *netbios_name, char *target_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449{
1450 int rc = 0;
1451 int connected = 0;
1452 __be16 orig_port = 0;
1453
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001454 if (*csocket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001455 rc = sock_create_kern(PF_INET, SOCK_STREAM,
1456 IPPROTO_TCP, csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001458 cERROR(1, ("Error %d creating socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 *csocket = NULL;
1460 return rc;
1461 } else {
1462 /* BB other socket options to set KEEPALIVE, NODELAY? */
Steve French467a8f82007-06-27 22:41:32 +00001463 cFYI(1, ("Socket created"));
Steve French50c2f752007-07-13 00:33:32 +00001464 (*csocket)->sk->sk_allocation = GFP_NOFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 }
1466 }
1467
1468 psin_server->sin_family = AF_INET;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001469 if (psin_server->sin_port) { /* user overrode default port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 rc = (*csocket)->ops->connect(*csocket,
1471 (struct sockaddr *) psin_server,
Steve French50c2f752007-07-13 00:33:32 +00001472 sizeof (struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 if (rc >= 0)
1474 connected = 1;
Steve French50c2f752007-07-13 00:33:32 +00001475 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001477 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001478 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 later if fall back ports fail this time */
1480 orig_port = psin_server->sin_port;
1481
1482 /* do not retry on the same port we just failed on */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001483 if (psin_server->sin_port != htons(CIFS_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 psin_server->sin_port = htons(CIFS_PORT);
1485
1486 rc = (*csocket)->ops->connect(*csocket,
1487 (struct sockaddr *) psin_server,
Steve French50c2f752007-07-13 00:33:32 +00001488 sizeof (struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 if (rc >= 0)
1490 connected = 1;
1491 }
1492 }
1493 if (!connected) {
1494 psin_server->sin_port = htons(RFC1001_PORT);
1495 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
Steve French50c2f752007-07-13 00:33:32 +00001496 psin_server,
1497 sizeof (struct sockaddr_in), 0);
1498 if (rc >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 connected = 1;
1500 }
1501
1502 /* give up here - unless we want to retry on different
1503 protocol families some day */
1504 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001505 if (orig_port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 psin_server->sin_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001507 cFYI(1, ("Error %d connecting to server via ipv4", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 sock_release(*csocket);
1509 *csocket = NULL;
1510 return rc;
1511 }
Steve French50c2f752007-07-13 00:33:32 +00001512 /* Eventually check for other socket options to change from
1513 the default. sock_setsockopt not used because it expects
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 user space buffer */
Steve French50c2f752007-07-13 00:33:32 +00001515 cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",
1516 (*csocket)->sk->sk_sndbuf,
Steve Frenchb387eae2005-10-10 14:21:15 -07001517 (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchb387eae2005-10-10 14:21:15 -07001519 /* make the bufsizes depend on wsize/rsize and max requests */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001520 if ((*csocket)->sk->sk_sndbuf < (200 * 1024))
Steve Frenchb387eae2005-10-10 14:21:15 -07001521 (*csocket)->sk->sk_sndbuf = 200 * 1024;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001522 if ((*csocket)->sk->sk_rcvbuf < (140 * 1024))
Steve Frenchb387eae2005-10-10 14:21:15 -07001523 (*csocket)->sk->sk_rcvbuf = 140 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524
1525 /* send RFC1001 sessinit */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001526 if (psin_server->sin_port == htons(RFC1001_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 /* some servers require RFC1001 sessinit before sending
Steve French50c2f752007-07-13 00:33:32 +00001528 negprot - BB check reconnection in case where second
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 sessinit is sent but no second negprot */
Steve French50c2f752007-07-13 00:33:32 +00001530 struct rfc1002_session_packet *ses_init_buf;
1531 struct smb_hdr *smb_buf;
1532 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
1533 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001534 if (ses_init_buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 ses_init_buf->trailer.session_req.called_len = 32;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001536 if (target_name && (target_name[0] != 0)) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001537 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1538 target_name, 16);
1539 } else {
1540 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
Steve French50c2f752007-07-13 00:33:32 +00001541 DEFAULT_CIFS_CALLED_NAME, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001542 }
1543
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 ses_init_buf->trailer.session_req.calling_len = 32;
1545 /* calling name ends in null (byte 16) from old smb
1546 convention. */
Steve French50c2f752007-07-13 00:33:32 +00001547 if (netbios_name && (netbios_name[0] != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
Steve French50c2f752007-07-13 00:33:32 +00001549 netbios_name, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 } else {
1551 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
Steve French50c2f752007-07-13 00:33:32 +00001552 "LINUX_CIFS_CLNT", 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 }
1554 ses_init_buf->trailer.session_req.scope1 = 0;
1555 ses_init_buf->trailer.session_req.scope2 = 0;
1556 smb_buf = (struct smb_hdr *)ses_init_buf;
1557 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1558 smb_buf->smb_buf_length = 0x81000044;
1559 rc = smb_send(*csocket, smb_buf, 0x44,
1560 (struct sockaddr *)psin_server);
1561 kfree(ses_init_buf);
Steve French50c2f752007-07-13 00:33:32 +00001562 msleep(1); /* RFC1001 layer in at least one server
Steve French083d3a22006-03-03 09:53:36 +00001563 requires very short break before negprot
1564 presumably because not expecting negprot
1565 to follow so fast. This is a simple
Steve French50c2f752007-07-13 00:33:32 +00001566 solution that works without
Steve French083d3a22006-03-03 09:53:36 +00001567 complicating the code and causes no
1568 significant slowing down on mount
1569 for everyone else */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 }
Steve French50c2f752007-07-13 00:33:32 +00001571 /* else the negprot may still work without this
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 even though malloc failed */
Steve French50c2f752007-07-13 00:33:32 +00001573
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 }
Steve French50c2f752007-07-13 00:33:32 +00001575
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 return rc;
1577}
1578
1579static int
1580ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1581{
1582 int rc = 0;
1583 int connected = 0;
1584 __be16 orig_port = 0;
1585
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001586 if (*csocket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001587 rc = sock_create_kern(PF_INET6, SOCK_STREAM,
1588 IPPROTO_TCP, csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001590 cERROR(1, ("Error %d creating ipv6 socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 *csocket = NULL;
1592 return rc;
1593 } else {
1594 /* BB other socket options to set KEEPALIVE, NODELAY? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001595 cFYI(1, ("ipv6 Socket created"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 (*csocket)->sk->sk_allocation = GFP_NOFS;
1597 }
1598 }
1599
1600 psin_server->sin6_family = AF_INET6;
1601
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001602 if (psin_server->sin6_port) { /* user overrode default port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 rc = (*csocket)->ops->connect(*csocket,
1604 (struct sockaddr *) psin_server,
Steve French50c2f752007-07-13 00:33:32 +00001605 sizeof (struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 if (rc >= 0)
1607 connected = 1;
Steve French50c2f752007-07-13 00:33:32 +00001608 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001610 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001611 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 later if fall back ports fail this time */
1613
1614 orig_port = psin_server->sin6_port;
1615 /* do not retry on the same port we just failed on */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001616 if (psin_server->sin6_port != htons(CIFS_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 psin_server->sin6_port = htons(CIFS_PORT);
1618
1619 rc = (*csocket)->ops->connect(*csocket,
1620 (struct sockaddr *) psin_server,
Steve French50c2f752007-07-13 00:33:32 +00001621 sizeof (struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 if (rc >= 0)
1623 connected = 1;
1624 }
1625 }
1626 if (!connected) {
1627 psin_server->sin6_port = htons(RFC1001_PORT);
1628 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
Steve French50c2f752007-07-13 00:33:32 +00001629 psin_server, sizeof (struct sockaddr_in6), 0);
1630 if (rc >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 connected = 1;
1632 }
1633
1634 /* give up here - unless we want to retry on different
1635 protocol families some day */
1636 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001637 if (orig_port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 psin_server->sin6_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001639 cFYI(1, ("Error %d connecting to server via ipv6", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 sock_release(*csocket);
1641 *csocket = NULL;
1642 return rc;
1643 }
Steve French50c2f752007-07-13 00:33:32 +00001644 /* Eventually check for other socket options to change from
1645 the default. sock_setsockopt not used because it expects
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 user space buffer */
1647 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve French50c2f752007-07-13 00:33:32 +00001648
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 return rc;
1650}
1651
Steve French50c2f752007-07-13 00:33:32 +00001652void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
1653 struct super_block *sb, struct smb_vol *vol_info)
Steve French8af18972007-02-14 04:42:51 +00001654{
1655 /* if we are reconnecting then should we check to see if
1656 * any requested capabilities changed locally e.g. via
1657 * remount but we can not do much about it here
1658 * if they have (even if we could detect it by the following)
1659 * Perhaps we could add a backpointer to array of sb from tcon
1660 * or if we change to make all sb to same share the same
1661 * sb as NFS - then we only have one backpointer to sb.
1662 * What if we wanted to mount the server share twice once with
1663 * and once without posixacls or posix paths? */
1664 __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001665
Steve Frenchc18c8422007-07-18 23:21:09 +00001666 if (vol_info && vol_info->no_linux_ext) {
1667 tcon->fsUnixInfo.Capability = 0;
1668 tcon->unix_ext = 0; /* Unix Extensions disabled */
1669 cFYI(1, ("Linux protocol extensions disabled"));
1670 return;
1671 } else if (vol_info)
1672 tcon->unix_ext = 1; /* Unix Extensions supported */
1673
1674 if (tcon->unix_ext == 0) {
1675 cFYI(1, ("Unix extensions disabled so not set on reconnect"));
1676 return;
1677 }
Steve French50c2f752007-07-13 00:33:32 +00001678
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001679 if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
Steve French8af18972007-02-14 04:42:51 +00001680 __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001681
Steve French8af18972007-02-14 04:42:51 +00001682 /* check for reconnect case in which we do not
1683 want to change the mount behavior if we can avoid it */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001684 if (vol_info == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001685 /* turn off POSIX ACL and PATHNAMES if not set
Steve French8af18972007-02-14 04:42:51 +00001686 originally at mount time */
1687 if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
1688 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
1689 if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0)
1690 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French8af18972007-02-14 04:42:51 +00001691 }
Steve French50c2f752007-07-13 00:33:32 +00001692
Steve French8af18972007-02-14 04:42:51 +00001693 cap &= CIFS_UNIX_CAP_MASK;
Steve French75865f8c2007-06-24 18:30:48 +00001694 if (vol_info && vol_info->no_psx_acl)
Steve French8af18972007-02-14 04:42:51 +00001695 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00001696 else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001697 cFYI(1, ("negotiated posix acl support"));
1698 if (sb)
Steve French8af18972007-02-14 04:42:51 +00001699 sb->s_flags |= MS_POSIXACL;
1700 }
1701
Steve French75865f8c2007-06-24 18:30:48 +00001702 if (vol_info && vol_info->posix_paths == 0)
Steve French8af18972007-02-14 04:42:51 +00001703 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00001704 else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001705 cFYI(1, ("negotiate posix pathnames"));
Steve French75865f8c2007-06-24 18:30:48 +00001706 if (sb)
Steve French50c2f752007-07-13 00:33:32 +00001707 CIFS_SB(sb)->mnt_cifs_flags |=
Steve French8af18972007-02-14 04:42:51 +00001708 CIFS_MOUNT_POSIX_PATHS;
1709 }
Steve French50c2f752007-07-13 00:33:32 +00001710
Steve French984acfe2007-04-26 16:42:50 +00001711 /* We might be setting the path sep back to a different
1712 form if we are reconnecting and the server switched its
Steve French50c2f752007-07-13 00:33:32 +00001713 posix path capability for this share */
Steve French75865f8c2007-06-24 18:30:48 +00001714 if (sb && (CIFS_SB(sb)->prepathlen > 0))
Steve French984acfe2007-04-26 16:42:50 +00001715 CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
Steve French75865f8c2007-06-24 18:30:48 +00001716
1717 if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
1718 if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
1719 CIFS_SB(sb)->rsize = 127 * 1024;
1720#ifdef CONFIG_CIFS_DEBUG2
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001721 cFYI(1, ("larger reads not supported by srv"));
Steve French75865f8c2007-06-24 18:30:48 +00001722#endif
1723 }
1724 }
Steve French50c2f752007-07-13 00:33:32 +00001725
1726
1727 cFYI(1, ("Negotiate caps 0x%x", (int)cap));
Steve French8af18972007-02-14 04:42:51 +00001728#ifdef CONFIG_CIFS_DEBUG2
Steve French75865f8c2007-06-24 18:30:48 +00001729 if (cap & CIFS_UNIX_FCNTL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001730 cFYI(1, ("FCNTL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001731 if (cap & CIFS_UNIX_EXTATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001732 cFYI(1, ("EXTATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001733 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001734 cFYI(1, ("POSIX path cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001735 if (cap & CIFS_UNIX_XATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001736 cFYI(1, ("XATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001737 if (cap & CIFS_UNIX_POSIX_ACL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001738 cFYI(1, ("POSIX ACL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001739 if (cap & CIFS_UNIX_LARGE_READ_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001740 cFYI(1, ("very large read cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001741 if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001742 cFYI(1, ("very large write cap"));
Steve French8af18972007-02-14 04:42:51 +00001743#endif /* CIFS_DEBUG2 */
1744 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
Steve French5a44b312007-09-20 15:16:24 +00001745 if (vol_info == NULL)
1746 cFYI(1, ("resetting capabilities failed"));
1747 else
1748 cERROR(1, ("Negotiating Unix capabilities "
1749 "with the server failed. Consider "
1750 "mounting with the Unix Extensions\n"
1751 "disabled, if problems are found, "
1752 "by specifying the nounix mount "
1753 "option.");
1754
Steve French8af18972007-02-14 04:42:51 +00001755 }
1756 }
1757}
1758
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759int
1760cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1761 char *mount_data, const char *devname)
1762{
1763 int rc = 0;
1764 int xid;
1765 int address_type = AF_INET;
1766 struct socket *csocket = NULL;
1767 struct sockaddr_in sin_server;
1768 struct sockaddr_in6 sin_server6;
1769 struct smb_vol volume_info;
1770 struct cifsSesInfo *pSesInfo = NULL;
1771 struct cifsSesInfo *existingCifsSes = NULL;
1772 struct cifsTconInfo *tcon = NULL;
1773 struct TCP_Server_Info *srvTcp = NULL;
1774
1775 xid = GetXid();
1776
1777/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
Steve French50c2f752007-07-13 00:33:32 +00001778
1779 memset(&volume_info, 0, sizeof(struct smb_vol));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001781 kfree(volume_info.UNC);
1782 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001783 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784 FreeXid(xid);
1785 return -EINVAL;
1786 }
1787
Jeff Layton8426c392007-05-05 03:27:49 +00001788 if (volume_info.nullauth) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001789 cFYI(1, ("null user"));
Jeff Layton8426c392007-05-05 03:27:49 +00001790 volume_info.username = NULL;
1791 } else if (volume_info.username) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 /* BB fixme parse for domain name here */
Steve French467a8f82007-06-27 22:41:32 +00001793 cFYI(1, ("Username: %s", volume_info.username));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 } else {
Steve Frenchbf820672005-12-01 22:32:42 -08001795 cifserror("No username specified");
Steve French50c2f752007-07-13 00:33:32 +00001796 /* In userspace mount helper we can get user name from alternate
1797 locations such as env variables and files on disk */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001798 kfree(volume_info.UNC);
1799 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001800 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 FreeXid(xid);
1802 return -EINVAL;
1803 }
1804
1805 if (volume_info.UNCip && volume_info.UNC) {
Steve French50c2f752007-07-13 00:33:32 +00001806 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,
1807 &sin_server.sin_addr.s_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001809 if (rc <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 /* not ipv4 address, try ipv6 */
Steve French50c2f752007-07-13 00:33:32 +00001811 rc = cifs_inet_pton(AF_INET6, volume_info.UNCip,
1812 &sin_server6.sin6_addr.in6_u);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001813 if (rc > 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814 address_type = AF_INET6;
1815 } else {
1816 address_type = AF_INET;
1817 }
Steve French50c2f752007-07-13 00:33:32 +00001818
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001819 if (rc <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 /* we failed translating address */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001821 kfree(volume_info.UNC);
1822 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001823 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 FreeXid(xid);
1825 return -EINVAL;
1826 }
1827
1828 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1829 /* success */
1830 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00001831 } else if (volume_info.UNCip) {
1832 /* BB using ip addr as server name to connect to the
1833 DFS root below */
1834 cERROR(1, ("Connecting to DFS root not implemented yet"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001835 kfree(volume_info.UNC);
1836 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001837 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 FreeXid(xid);
1839 return -EINVAL;
1840 } else /* which servers DFS root would we conect to */ {
1841 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00001842 ("CIFS mount error: No UNC path (e.g. -o "
1843 "unc=//192.168.1.100/public) specified"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001844 kfree(volume_info.UNC);
1845 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001846 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 FreeXid(xid);
1848 return -EINVAL;
1849 }
1850
1851 /* this is needed for ASCII cp to Unicode converts */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001852 if (volume_info.iocharset == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 cifs_sb->local_nls = load_nls_default();
1854 /* load_nls_default can not return null */
1855 } else {
1856 cifs_sb->local_nls = load_nls(volume_info.iocharset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001857 if (cifs_sb->local_nls == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001858 cERROR(1, ("CIFS mount error: iocharset %s not found",
1859 volume_info.iocharset));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001860 kfree(volume_info.UNC);
1861 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001862 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 FreeXid(xid);
1864 return -ELIBACC;
1865 }
1866 }
1867
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001868 if (address_type == AF_INET)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1870 NULL /* no ipv6 addr */,
1871 volume_info.username, &srvTcp);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001872 else if (address_type == AF_INET6) {
1873 cFYI(1, ("looking for ipv6 address"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1875 &sin_server6.sin6_addr,
1876 volume_info.username, &srvTcp);
Steve French5858ae42007-04-25 11:59:10 +00001877 } else {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001878 kfree(volume_info.UNC);
1879 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001880 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 FreeXid(xid);
1882 return -EINVAL;
1883 }
1884
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 if (srvTcp) {
Steve French50c2f752007-07-13 00:33:32 +00001886 cFYI(1, ("Existing tcp session with server found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 } else { /* create socket */
Steve French4523cc32007-04-30 20:13:06 +00001888 if (volume_info.port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 sin_server.sin_port = htons(volume_info.port);
1890 else
1891 sin_server.sin_port = 0;
Steve French5858ae42007-04-25 11:59:10 +00001892 if (address_type == AF_INET6) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001893 cFYI(1, ("attempting ipv6 connect"));
Steve French5858ae42007-04-25 11:59:10 +00001894 /* BB should we allow ipv6 on port 139? */
1895 /* other OS never observed in Wild doing 139 with v6 */
Steve French50c2f752007-07-13 00:33:32 +00001896 rc = ipv6_connect(&sin_server6, &csocket);
1897 } else
1898 rc = ipv4_connect(&sin_server, &csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -07001899 volume_info.source_rfc1001_name,
1900 volume_info.target_rfc1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001902 cERROR(1, ("Error connecting to IPv4 socket. "
1903 "Aborting operation"));
Steve French4523cc32007-04-30 20:13:06 +00001904 if (csocket != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001906 kfree(volume_info.UNC);
1907 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001908 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 FreeXid(xid);
1910 return rc;
1911 }
1912
1913 srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
1914 if (srvTcp == NULL) {
1915 rc = -ENOMEM;
1916 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001917 kfree(volume_info.UNC);
1918 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001919 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 FreeXid(xid);
1921 return rc;
1922 } else {
1923 memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
Steve French50c2f752007-07-13 00:33:32 +00001924 memcpy(&srvTcp->addr.sockAddr, &sin_server,
1925 sizeof (struct sockaddr_in));
1926 atomic_set(&srvTcp->inFlight, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 /* BB Add code for ipv6 case too */
1928 srvTcp->ssocket = csocket;
1929 srvTcp->protocolType = IPV4;
1930 init_waitqueue_head(&srvTcp->response_q);
1931 init_waitqueue_head(&srvTcp->request_q);
1932 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1933 /* at this point we are the only ones with the pointer
1934 to the struct since the kernel thread not created yet
1935 so no need to spinlock this init of tcpStatus */
1936 srvTcp->tcpStatus = CifsNew;
1937 init_MUTEX(&srvTcp->tcpSem);
Igor Mammedovaaf737a2007-04-03 19:16:43 +00001938 srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd");
Steve French4523cc32007-04-30 20:13:06 +00001939 if ( IS_ERR(srvTcp->tsk) ) {
Igor Mammedovaaf737a2007-04-03 19:16:43 +00001940 rc = PTR_ERR(srvTcp->tsk);
Steve French50c2f752007-07-13 00:33:32 +00001941 cERROR(1, ("error %d create cifsd thread", rc));
Igor Mammedovaaf737a2007-04-03 19:16:43 +00001942 srvTcp->tsk = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001944 kfree(volume_info.UNC);
1945 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001946 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 FreeXid(xid);
1948 return rc;
Steve Frenchf1914012005-08-18 09:37:34 -07001949 }
1950 wait_for_completion(&cifsd_complete);
1951 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00001952 memcpy(srvTcp->workstation_RFC1001_name,
1953 volume_info.source_rfc1001_name, 16);
1954 memcpy(srvTcp->server_RFC1001_name,
1955 volume_info.target_rfc1001_name, 16);
Steve Frenchad009ac2005-04-28 22:41:05 -07001956 srvTcp->sequence_number = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957 }
1958 }
1959
1960 if (existingCifsSes) {
1961 pSesInfo = existingCifsSes;
Steve Frenchbf820672005-12-01 22:32:42 -08001962 cFYI(1, ("Existing smb sess found"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001963 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 /* volume_info.UNC freed at end of function */
1965 } else if (!rc) {
Steve Frenchbf820672005-12-01 22:32:42 -08001966 cFYI(1, ("Existing smb sess not found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 pSesInfo = sesInfoAlloc();
1968 if (pSesInfo == NULL)
1969 rc = -ENOMEM;
1970 else {
1971 pSesInfo->server = srvTcp;
1972 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1973 NIPQUAD(sin_server.sin_addr.s_addr));
1974 }
1975
Steve French50c2f752007-07-13 00:33:32 +00001976 if (!rc) {
1977 /* volume_info.password freed at unmount */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978 if (volume_info.password)
1979 pSesInfo->password = volume_info.password;
1980 if (volume_info.username)
1981 strncpy(pSesInfo->userName,
Steve French50c2f752007-07-13 00:33:32 +00001982 volume_info.username,
1983 MAX_USERNAME_SIZE);
Steve French39798772006-05-31 22:40:51 +00001984 if (volume_info.domainname) {
1985 int len = strlen(volume_info.domainname);
Steve French50c2f752007-07-13 00:33:32 +00001986 pSesInfo->domainName =
Steve French39798772006-05-31 22:40:51 +00001987 kmalloc(len + 1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001988 if (pSesInfo->domainName)
Steve French39798772006-05-31 22:40:51 +00001989 strcpy(pSesInfo->domainName,
1990 volume_info.domainname);
1991 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 pSesInfo->linux_uid = volume_info.linux_uid;
Steve French750d1152006-06-27 06:28:30 +00001993 pSesInfo->overrideSecFlg = volume_info.secFlg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 down(&pSesInfo->sesSem);
Steve French189acaa2006-06-23 02:33:48 +00001995 /* BB FIXME need to pass vol->secFlgs BB */
Steve French50c2f752007-07-13 00:33:32 +00001996 rc = cifs_setup_session(xid, pSesInfo,
1997 cifs_sb->local_nls);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 up(&pSesInfo->sesSem);
Steve French4523cc32007-04-30 20:13:06 +00001999 if (!rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 atomic_inc(&srvTcp->socketUseCount);
2001 } else
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002002 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 }
Steve French50c2f752007-07-13 00:33:32 +00002004
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 /* search for existing tcon to this server share */
2006 if (!rc) {
Steve French4523cc32007-04-30 20:13:06 +00002007 if (volume_info.rsize > CIFSMaxBufSize) {
Steve French50c2f752007-07-13 00:33:32 +00002008 cERROR(1, ("rsize %d too large, using MaxBufSize",
Steve French0ae0efa2005-10-10 10:57:19 -07002009 volume_info.rsize));
2010 cifs_sb->rsize = CIFSMaxBufSize;
Steve French75865f8c2007-06-24 18:30:48 +00002011 } else if ((volume_info.rsize) &&
2012 (volume_info.rsize <= CIFSMaxBufSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013 cifs_sb->rsize = volume_info.rsize;
Steve French0ae0efa2005-10-10 10:57:19 -07002014 else /* default */
2015 cifs_sb->rsize = CIFSMaxBufSize;
2016
Steve French4523cc32007-04-30 20:13:06 +00002017 if (volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
Steve French50c2f752007-07-13 00:33:32 +00002018 cERROR(1, ("wsize %d too large, using 4096 instead",
Steve French0ae0efa2005-10-10 10:57:19 -07002019 volume_info.wsize));
2020 cifs_sb->wsize = 4096;
Steve French4523cc32007-04-30 20:13:06 +00002021 } else if (volume_info.wsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 cifs_sb->wsize = volume_info.wsize;
2023 else
Steve French50c2f752007-07-13 00:33:32 +00002024 cifs_sb->wsize =
Steve French1877c9e2006-01-27 18:36:11 -08002025 min_t(const int, PAGEVEC_SIZE * PAGE_CACHE_SIZE,
2026 127*1024);
Steve French17cbbaf2006-01-24 20:26:48 -08002027 /* old default of CIFSMaxBufSize was too small now
Steve French50c2f752007-07-13 00:33:32 +00002028 that SMB Write2 can send multiple pages in kvec.
Steve French17cbbaf2006-01-24 20:26:48 -08002029 RFC1001 does not describe what happens when frame
2030 bigger than 128K is sent so use that as max in
2031 conjunction with 52K kvec constraint on arch with 4K
2032 page size */
2033
Steve French4523cc32007-04-30 20:13:06 +00002034 if (cifs_sb->rsize < 2048) {
Steve French50c2f752007-07-13 00:33:32 +00002035 cifs_sb->rsize = 2048;
Steve French6cec2ae2006-02-22 17:31:52 -06002036 /* Windows ME may prefer this */
Steve French467a8f82007-06-27 22:41:32 +00002037 cFYI(1, ("readsize set to minimum: 2048"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 }
Steve French2fe87f02006-09-21 07:02:52 +00002039 /* calculate prepath */
2040 cifs_sb->prepath = volume_info.prepath;
Steve French4523cc32007-04-30 20:13:06 +00002041 if (cifs_sb->prepath) {
Steve French2fe87f02006-09-21 07:02:52 +00002042 cifs_sb->prepathlen = strlen(cifs_sb->prepath);
2043 cifs_sb->prepath[0] = CIFS_DIR_SEP(cifs_sb);
2044 volume_info.prepath = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002045 } else
Steve French2fe87f02006-09-21 07:02:52 +00002046 cifs_sb->prepathlen = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 cifs_sb->mnt_uid = volume_info.linux_uid;
2048 cifs_sb->mnt_gid = volume_info.linux_gid;
2049 cifs_sb->mnt_file_mode = volume_info.file_mode;
2050 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
Steve French467a8f82007-06-27 22:41:32 +00002051 cFYI(1, ("file mode: 0x%x dir mode: 0x%x",
2052 cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053
Steve French4523cc32007-04-30 20:13:06 +00002054 if (volume_info.noperm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
Steve French4523cc32007-04-30 20:13:06 +00002056 if (volume_info.setuids)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
Steve French4523cc32007-04-30 20:13:06 +00002058 if (volume_info.server_ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
Steve French4523cc32007-04-30 20:13:06 +00002060 if (volume_info.remap)
Steve French6a0b4822005-04-28 22:41:05 -07002061 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
Steve French4523cc32007-04-30 20:13:06 +00002062 if (volume_info.no_xattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
Steve French4523cc32007-04-30 20:13:06 +00002064 if (volume_info.sfu_emul)
Steve Frenchd7245c22005-07-14 18:25:12 -05002065 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
Steve French4523cc32007-04-30 20:13:06 +00002066 if (volume_info.nobrl)
Steve Frenchc46fa8a2005-08-18 20:49:57 -07002067 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Steve French4523cc32007-04-30 20:13:06 +00002068 if (volume_info.cifs_acl)
Steve French0a4b92c2006-01-12 15:44:21 -08002069 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
Steve French4523cc32007-04-30 20:13:06 +00002070 if (volume_info.override_uid)
2071 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
2072 if (volume_info.override_gid)
2073 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
2074 if (volume_info.direct_io) {
Steve French467a8f82007-06-27 22:41:32 +00002075 cFYI(1, ("mounting share using direct i/o"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
2077 }
2078
2079 tcon =
2080 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
2081 volume_info.username);
2082 if (tcon) {
Steve Frenchbf820672005-12-01 22:32:42 -08002083 cFYI(1, ("Found match on UNC path"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084 /* we can have only one retry value for a connection
2085 to a share so for resources mounted more than once
Steve French50c2f752007-07-13 00:33:32 +00002086 to the same server share the last value passed in
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087 for the retry flag is used */
2088 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07002089 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090 } else {
2091 tcon = tconInfoAlloc();
2092 if (tcon == NULL)
2093 rc = -ENOMEM;
2094 else {
Steve French50c2f752007-07-13 00:33:32 +00002095 /* check for null share name ie connecting to
Steve French8af18972007-02-14 04:42:51 +00002096 * dfs root */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097
Steve French50c2f752007-07-13 00:33:32 +00002098 /* BB check if this works for exactly length
Steve French8af18972007-02-14 04:42:51 +00002099 * three strings */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
2101 && (strchr(volume_info.UNC + 3, '/') ==
2102 NULL)) {
Steve French737b7582005-04-28 22:41:06 -07002103 rc = connect_to_dfs_path(xid, pSesInfo,
Steve French8af18972007-02-14 04:42:51 +00002104 "", cifs_sb->local_nls,
Steve French50c2f752007-07-13 00:33:32 +00002105 cifs_sb->mnt_cifs_flags &
Steve French8af18972007-02-14 04:42:51 +00002106 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002107 kfree(volume_info.UNC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 FreeXid(xid);
2109 return -ENODEV;
2110 } else {
Steve French8af18972007-02-14 04:42:51 +00002111 /* BB Do we need to wrap sesSem around
2112 * this TCon call and Unix SetFS as
2113 * we do on SessSetup and reconnect? */
Steve French50c2f752007-07-13 00:33:32 +00002114 rc = CIFSTCon(xid, pSesInfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 volume_info.UNC,
2116 tcon, cifs_sb->local_nls);
2117 cFYI(1, ("CIFS Tcon rc = %d", rc));
2118 }
2119 if (!rc) {
2120 atomic_inc(&pSesInfo->inUse);
2121 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07002122 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123 }
2124 }
2125 }
2126 }
Steve French4523cc32007-04-30 20:13:06 +00002127 if (pSesInfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
2129 sb->s_maxbytes = (u64) 1 << 63;
2130 } else
2131 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
2132 }
2133
Steve French8af18972007-02-14 04:42:51 +00002134 /* BB FIXME fix time_gran to be larger for LANMAN sessions */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135 sb->s_time_gran = 100;
2136
2137/* on error free sesinfo and tcon struct if needed */
2138 if (rc) {
2139 /* if session setup failed, use count is zero but
2140 we still need to free cifsd thread */
Steve French4523cc32007-04-30 20:13:06 +00002141 if (atomic_read(&srvTcp->socketUseCount) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142 spin_lock(&GlobalMid_Lock);
2143 srvTcp->tcpStatus = CifsExiting;
2144 spin_unlock(&GlobalMid_Lock);
Steve French4523cc32007-04-30 20:13:06 +00002145 if (srvTcp->tsk) {
Steve French28356a12007-05-23 14:45:36 +00002146 struct task_struct *tsk;
2147 /* If we could verify that kthread_stop would
2148 always wake up processes blocked in
2149 tcp in recv_mesg then we could remove the
2150 send_sig call */
Steve French50c2f752007-07-13 00:33:32 +00002151 force_sig(SIGKILL, srvTcp->tsk);
Steve French28356a12007-05-23 14:45:36 +00002152 tsk = srvTcp->tsk;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002153 if (tsk)
Steve Frenchf7f7c312007-05-24 02:29:51 +00002154 kthread_stop(tsk);
Steve Frenchf1914012005-08-18 09:37:34 -07002155 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156 }
2157 /* If find_unc succeeded then rc == 0 so we can not end */
2158 if (tcon) /* up accidently freeing someone elses tcon struct */
2159 tconInfoFree(tcon);
2160 if (existingCifsSes == NULL) {
2161 if (pSesInfo) {
Steve French50c2f752007-07-13 00:33:32 +00002162 if ((pSesInfo->server) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163 (pSesInfo->status == CifsGood)) {
2164 int temp_rc;
2165 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
2166 /* if the socketUseCount is now zero */
Steve French4523cc32007-04-30 20:13:06 +00002167 if ((temp_rc == -ESHUTDOWN) &&
Steve French50c2f752007-07-13 00:33:32 +00002168 (pSesInfo->server) &&
Jeff5d9c7202007-06-25 22:16:35 +00002169 (pSesInfo->server->tsk)) {
Steve French28356a12007-05-23 14:45:36 +00002170 struct task_struct *tsk;
Jeff5d9c7202007-06-25 22:16:35 +00002171 force_sig(SIGKILL,
2172 pSesInfo->server->tsk);
Steve French28356a12007-05-23 14:45:36 +00002173 tsk = pSesInfo->server->tsk;
Steve Frenchf7f7c312007-05-24 02:29:51 +00002174 if (tsk)
Steve French28356a12007-05-23 14:45:36 +00002175 kthread_stop(tsk);
Steve Frenchf1914012005-08-18 09:37:34 -07002176 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 } else
2178 cFYI(1, ("No session or bad tcon"));
2179 sesInfoFree(pSesInfo);
2180 /* pSesInfo = NULL; */
2181 }
2182 }
2183 } else {
2184 atomic_inc(&tcon->useCount);
2185 cifs_sb->tcon = tcon;
2186 tcon->ses = pSesInfo;
2187
Steve French82940a42006-03-02 03:24:57 +00002188 /* do not care if following two calls succeed - informational */
Steve French737b7582005-04-28 22:41:06 -07002189 CIFSSMBQFSDeviceInfo(xid, tcon);
2190 CIFSSMBQFSAttributeInfo(xid, tcon);
Steve French50c2f752007-07-13 00:33:32 +00002191
Steve French8af18972007-02-14 04:42:51 +00002192 /* tell server which Unix caps we support */
2193 if (tcon->ses->capabilities & CAP_UNIX)
Steve Frenchc18c8422007-07-18 23:21:09 +00002194 /* reset of caps checks mount to see if unix extensions
2195 disabled for just this mount */
Steve French8af18972007-02-14 04:42:51 +00002196 reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
Steve Frenchc18c8422007-07-18 23:21:09 +00002197 else
2198 tcon->unix_ext = 0; /* server does not support them */
2199
2200 if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
Steve French75865f8c2007-06-24 18:30:48 +00002201 cifs_sb->rsize = 1024 * 127;
2202#ifdef CONFIG_CIFS_DEBUG2
Steve Frenchc18c8422007-07-18 23:21:09 +00002203 cFYI(1, ("no very large read support, rsize now 127K"));
Steve French75865f8c2007-06-24 18:30:48 +00002204#endif
Steve French75865f8c2007-06-24 18:30:48 +00002205 }
Steve French3e844692005-10-03 13:37:24 -07002206 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
2207 cifs_sb->wsize = min(cifs_sb->wsize,
2208 (tcon->ses->server->maxBuf -
2209 MAX_CIFS_HDR_SIZE));
Steve French0ae0efa2005-10-10 10:57:19 -07002210 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
Steve French50c2f752007-07-13 00:33:32 +00002211 cifs_sb->rsize = min(cifs_sb->rsize,
2212 (tcon->ses->server->maxBuf -
2213 MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 }
2215
2216 /* volume_info.password is freed above when existing session found
2217 (in which case it is not needed anymore) but when new sesion is created
2218 the password ptr is put in the new session structure (in which case the
2219 password will be freed at unmount time) */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002220 kfree(volume_info.UNC);
Steve French2fe87f02006-09-21 07:02:52 +00002221 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 FreeXid(xid);
2223 return rc;
2224}
2225
2226static int
2227CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French7c7b25b2006-06-01 19:20:10 +00002228 char session_key[CIFS_SESS_KEY_SIZE],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 const struct nls_table *nls_codepage)
2230{
2231 struct smb_hdr *smb_buffer;
2232 struct smb_hdr *smb_buffer_response;
2233 SESSION_SETUP_ANDX *pSMB;
2234 SESSION_SETUP_ANDX *pSMBr;
2235 char *bcc_ptr;
2236 char *user;
2237 char *domain;
2238 int rc = 0;
2239 int remaining_words = 0;
2240 int bytes_returned = 0;
2241 int len;
2242 __u32 capabilities;
2243 __u16 count;
2244
Steve Frencheeac8042006-01-13 21:34:58 -08002245 cFYI(1, ("In sesssetup"));
Steve French4523cc32007-04-30 20:13:06 +00002246 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 return -EINVAL;
2248 user = ses->userName;
2249 domain = ses->domainName;
2250 smb_buffer = cifs_buf_get();
2251 if (smb_buffer == NULL) {
2252 return -ENOMEM;
2253 }
2254 smb_buffer_response = smb_buffer;
2255 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2256
2257 /* send SMBsessionSetup here */
2258 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2259 NULL /* no tCon exists yet */ , 13 /* wct */ );
2260
Steve French1982c342005-08-17 12:38:22 -07002261 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 pSMB->req_no_secext.AndXCommand = 0xFF;
2263 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2264 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2265
Steve French50c2f752007-07-13 00:33:32 +00002266 if (ses->server->secMode &
2267 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2269
2270 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2271 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
2272 if (ses->capabilities & CAP_UNICODE) {
2273 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2274 capabilities |= CAP_UNICODE;
2275 }
2276 if (ses->capabilities & CAP_STATUS32) {
2277 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2278 capabilities |= CAP_STATUS32;
2279 }
2280 if (ses->capabilities & CAP_DFS) {
2281 smb_buffer->Flags2 |= SMBFLG2_DFS;
2282 capabilities |= CAP_DFS;
2283 }
2284 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
2285
Steve French50c2f752007-07-13 00:33:32 +00002286 pSMB->req_no_secext.CaseInsensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002287 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288
2289 pSMB->req_no_secext.CaseSensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002290 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291 bcc_ptr = pByteArea(smb_buffer);
Steve French7c7b25b2006-06-01 19:20:10 +00002292 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2293 bcc_ptr += CIFS_SESS_KEY_SIZE;
2294 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2295 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296
2297 if (ses->capabilities & CAP_UNICODE) {
2298 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
2299 *bcc_ptr = 0;
2300 bcc_ptr++;
2301 }
Steve French4523cc32007-04-30 20:13:06 +00002302 if (user == NULL)
Steve French39798772006-05-31 22:40:51 +00002303 bytes_returned = 0; /* skip null user */
Steve French50c2f752007-07-13 00:33:32 +00002304 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305 bytes_returned =
Steve French50c2f752007-07-13 00:33:32 +00002306 cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 nls_codepage);
2308 /* convert number of 16 bit words to bytes */
2309 bcc_ptr += 2 * bytes_returned;
2310 bcc_ptr += 2; /* trailing null */
2311 if (domain == NULL)
2312 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002313 cifs_strtoUCS((__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314 "CIFS_LINUX_DOM", 32, nls_codepage);
2315 else
2316 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002317 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318 nls_codepage);
2319 bcc_ptr += 2 * bytes_returned;
2320 bcc_ptr += 2;
2321 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002322 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 32, nls_codepage);
2324 bcc_ptr += 2 * bytes_returned;
2325 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002326 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327 32, nls_codepage);
2328 bcc_ptr += 2 * bytes_returned;
2329 bcc_ptr += 2;
2330 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002331 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332 64, nls_codepage);
2333 bcc_ptr += 2 * bytes_returned;
2334 bcc_ptr += 2;
2335 } else {
Steve French50c2f752007-07-13 00:33:32 +00002336 if (user != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337 strncpy(bcc_ptr, user, 200);
2338 bcc_ptr += strnlen(user, 200);
2339 }
2340 *bcc_ptr = 0;
2341 bcc_ptr++;
2342 if (domain == NULL) {
2343 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2344 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2345 } else {
2346 strncpy(bcc_ptr, domain, 64);
2347 bcc_ptr += strnlen(domain, 64);
2348 *bcc_ptr = 0;
2349 bcc_ptr++;
2350 }
2351 strcpy(bcc_ptr, "Linux version ");
2352 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002353 strcpy(bcc_ptr, utsname()->release);
2354 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2356 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2357 }
2358 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2359 smb_buffer->smb_buf_length += count;
2360 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2361
2362 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2363 &bytes_returned, 1);
2364 if (rc) {
2365/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2366 } else if ((smb_buffer_response->WordCount == 3)
2367 || (smb_buffer_response->WordCount == 4)) {
2368 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2369 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2370 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002371 cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */
2372 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format
2373 (little endian) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374 cFYI(1, ("UID = %d ", ses->Suid));
Steve French50c2f752007-07-13 00:33:32 +00002375 /* response can have either 3 or 4 word count - Samba sends 3 */
2376 bcc_ptr = pByteArea(smb_buffer_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377 if ((pSMBr->resp.hdr.WordCount == 3)
2378 || ((pSMBr->resp.hdr.WordCount == 4)
2379 && (blob_len < pSMBr->resp.ByteCount))) {
2380 if (pSMBr->resp.hdr.WordCount == 4)
2381 bcc_ptr += blob_len;
2382
2383 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2384 if ((long) (bcc_ptr) % 2) {
2385 remaining_words =
Steve French50c2f752007-07-13 00:33:32 +00002386 (BCC(smb_buffer_response) - 1) / 2;
2387 /* Unicode strings must be word
2388 aligned */
2389 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 } else {
2391 remaining_words =
2392 BCC(smb_buffer_response) / 2;
2393 }
2394 len =
2395 UniStrnlen((wchar_t *) bcc_ptr,
2396 remaining_words - 1);
2397/* We look for obvious messed up bcc or strings in response so we do not go off
2398 the end since (at least) WIN2K and Windows XP have a major bug in not null
2399 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002400 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002401 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002402 ses->serverOS = kzalloc(2 * (len + 1),
2403 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002404 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002405 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406 cifs_strfromUCS_le(ses->serverOS,
Steve French50c2f752007-07-13 00:33:32 +00002407 (__le16 *)bcc_ptr,
2408 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 bcc_ptr += 2 * (len + 1);
2410 remaining_words -= len + 1;
2411 ses->serverOS[2 * len] = 0;
2412 ses->serverOS[1 + (2 * len)] = 0;
2413 if (remaining_words > 0) {
2414 len = UniStrnlen((wchar_t *)bcc_ptr,
2415 remaining_words-1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002416 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002417 ses->serverNOS = kzalloc(2 * (len + 1),
2418 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002419 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002420 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421 cifs_strfromUCS_le(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002422 (__le16 *)bcc_ptr,
2423 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424 bcc_ptr += 2 * (len + 1);
2425 ses->serverNOS[2 * len] = 0;
2426 ses->serverNOS[1 + (2 * len)] = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002427 if (strncmp(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002428 "NT LAN Manager 4", 16) == 0) {
Steve French467a8f82007-06-27 22:41:32 +00002429 cFYI(1, ("NT4 server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430 ses->flags |= CIFS_SES_NT4;
2431 }
2432 remaining_words -= len + 1;
2433 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002434 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Steve French50c2f752007-07-13 00:33:32 +00002435 /* last string is not always null terminated
2436 (for e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002437 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002438 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439 ses->serverDomain =
Steve French50c2f752007-07-13 00:33:32 +00002440 kzalloc(2*(len+1),
2441 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002442 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002443 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444 cifs_strfromUCS_le(ses->serverDomain,
Steve French50c2f752007-07-13 00:33:32 +00002445 (__le16 *)bcc_ptr,
2446 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447 bcc_ptr += 2 * (len + 1);
2448 ses->serverDomain[2*len] = 0;
2449 ses->serverDomain[1+(2*len)] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002450 } else { /* else no more room so create
2451 dummy domain string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002452 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002453 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002454 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002455 kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002456 }
Steve French50c2f752007-07-13 00:33:32 +00002457 } else { /* no room so create dummy domain
2458 and NOS string */
2459
Steve French433dc242005-04-28 22:41:08 -07002460 /* if these kcallocs fail not much we
2461 can do, but better to not fail the
2462 sesssetup itself */
Steve Frenchcd49b492006-06-26 04:22:36 +00002463 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002465 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002466 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002468 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469 }
2470 } else { /* ASCII */
2471 len = strnlen(bcc_ptr, 1024);
2472 if (((long) bcc_ptr + len) - (long)
2473 pByteArea(smb_buffer_response)
2474 <= BCC(smb_buffer_response)) {
Steve Frenchcd49b492006-06-26 04:22:36 +00002475 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002476 ses->serverOS = kzalloc(len + 1,
2477 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002478 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002479 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002480 strncpy(ses->serverOS, bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481
2482 bcc_ptr += len;
Steve French50c2f752007-07-13 00:33:32 +00002483 /* null terminate the string */
2484 bcc_ptr[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485 bcc_ptr++;
2486
2487 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002488 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002489 ses->serverNOS = kzalloc(len + 1,
2490 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002491 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002492 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493 strncpy(ses->serverNOS, bcc_ptr, len);
2494 bcc_ptr += len;
2495 bcc_ptr[0] = 0;
2496 bcc_ptr++;
2497
2498 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002499 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002500 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002501 ses->serverDomain = kzalloc(len + 1,
2502 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002503 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002504 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002505 strncpy(ses->serverDomain, bcc_ptr,
2506 len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507 bcc_ptr += len;
2508 bcc_ptr[0] = 0;
2509 bcc_ptr++;
2510 } else
2511 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00002512 ("Variable field of length %d "
2513 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 len));
2515 }
2516 } else {
2517 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00002518 (" Security Blob Length extends beyond "
2519 "end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520 }
2521 } else {
2522 cERROR(1,
2523 (" Invalid Word count %d: ",
2524 smb_buffer_response->WordCount));
2525 rc = -EIO;
2526 }
Steve French433dc242005-04-28 22:41:08 -07002527sesssetup_nomem: /* do not return an error on nomem for the info strings,
2528 since that could make reconnection harder, and
2529 reconnection might be needed to free memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530 if (smb_buffer)
2531 cifs_buf_release(smb_buffer);
2532
2533 return rc;
2534}
2535
2536static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
Steve French50c2f752007-07-13 00:33:32 +00002538 struct cifsSesInfo *ses, int *pNTLMv2_flag,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539 const struct nls_table *nls_codepage)
2540{
2541 struct smb_hdr *smb_buffer;
2542 struct smb_hdr *smb_buffer_response;
2543 SESSION_SETUP_ANDX *pSMB;
2544 SESSION_SETUP_ANDX *pSMBr;
2545 char *bcc_ptr;
2546 char *domain;
2547 int rc = 0;
2548 int remaining_words = 0;
2549 int bytes_returned = 0;
2550 int len;
2551 int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
2552 PNEGOTIATE_MESSAGE SecurityBlob;
2553 PCHALLENGE_MESSAGE SecurityBlob2;
2554 __u32 negotiate_flags, capabilities;
2555 __u16 count;
2556
Steve French12b3b8f2006-02-09 21:12:47 +00002557 cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002558 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559 return -EINVAL;
2560 domain = ses->domainName;
2561 *pNTLMv2_flag = FALSE;
2562 smb_buffer = cifs_buf_get();
2563 if (smb_buffer == NULL) {
2564 return -ENOMEM;
2565 }
2566 smb_buffer_response = smb_buffer;
2567 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2568 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2569
2570 /* send SMBsessionSetup here */
2571 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2572 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002573
2574 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2576 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2577
2578 pSMB->req.AndXCommand = 0xFF;
2579 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2580 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2581
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002582 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2584
2585 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2586 CAP_EXTENDED_SECURITY;
2587 if (ses->capabilities & CAP_UNICODE) {
2588 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2589 capabilities |= CAP_UNICODE;
2590 }
2591 if (ses->capabilities & CAP_STATUS32) {
2592 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2593 capabilities |= CAP_STATUS32;
2594 }
2595 if (ses->capabilities & CAP_DFS) {
2596 smb_buffer->Flags2 |= SMBFLG2_DFS;
2597 capabilities |= CAP_DFS;
2598 }
2599 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2600
2601 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2602 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2603 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2604 SecurityBlob->MessageType = NtLmNegotiate;
2605 negotiate_flags =
2606 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
Steve French12b3b8f2006-02-09 21:12:47 +00002607 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
2608 NTLMSSP_NEGOTIATE_56 |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002610 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002612/* if (ntlmv2_support)
Steve French39798772006-05-31 22:40:51 +00002613 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 /* setup pointers to domain name and workstation name */
2615 bcc_ptr += SecurityBlobLength;
2616
2617 SecurityBlob->WorkstationName.Buffer = 0;
2618 SecurityBlob->WorkstationName.Length = 0;
2619 SecurityBlob->WorkstationName.MaximumLength = 0;
2620
Steve French12b3b8f2006-02-09 21:12:47 +00002621 /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent
2622 along with username on auth request (ie the response to challenge) */
2623 SecurityBlob->DomainName.Buffer = 0;
2624 SecurityBlob->DomainName.Length = 0;
2625 SecurityBlob->DomainName.MaximumLength = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626 if (ses->capabilities & CAP_UNICODE) {
2627 if ((long) bcc_ptr % 2) {
2628 *bcc_ptr = 0;
2629 bcc_ptr++;
2630 }
2631
2632 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002633 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634 32, nls_codepage);
2635 bcc_ptr += 2 * bytes_returned;
2636 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002637 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 nls_codepage);
2639 bcc_ptr += 2 * bytes_returned;
2640 bcc_ptr += 2; /* null terminate Linux version */
2641 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002642 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 64, nls_codepage);
2644 bcc_ptr += 2 * bytes_returned;
2645 *(bcc_ptr + 1) = 0;
2646 *(bcc_ptr + 2) = 0;
2647 bcc_ptr += 2; /* null terminate network opsys string */
2648 *(bcc_ptr + 1) = 0;
2649 *(bcc_ptr + 2) = 0;
2650 bcc_ptr += 2; /* null domain */
2651 } else { /* ASCII */
2652 strcpy(bcc_ptr, "Linux version ");
2653 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002654 strcpy(bcc_ptr, utsname()->release);
2655 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2657 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2658 bcc_ptr++; /* empty domain field */
2659 *bcc_ptr = 0;
2660 }
2661 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2662 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2663 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2664 smb_buffer->smb_buf_length += count;
2665 pSMB->req.ByteCount = cpu_to_le16(count);
2666
2667 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2668 &bytes_returned, 1);
2669
2670 if (smb_buffer_response->Status.CifsError ==
2671 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2672 rc = 0;
2673
2674 if (rc) {
2675/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2676 } else if ((smb_buffer_response->WordCount == 3)
2677 || (smb_buffer_response->WordCount == 4)) {
2678 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2679 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2680
2681 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002682 cFYI(1, (" Guest login"));
2683 /* Do we want to set anything in SesInfo struct when guest login? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684
Steve French50c2f752007-07-13 00:33:32 +00002685 bcc_ptr = pByteArea(smb_buffer_response);
2686 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687
2688 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2689 if (SecurityBlob2->MessageType != NtLmChallenge) {
2690 cFYI(1,
2691 ("Unexpected NTLMSSP message type received %d",
2692 SecurityBlob2->MessageType));
2693 } else if (ses) {
Steve French50c2f752007-07-13 00:33:32 +00002694 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
Steve French12b3b8f2006-02-09 21:12:47 +00002695 cFYI(1, ("UID = %d", ses->Suid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696 if ((pSMBr->resp.hdr.WordCount == 3)
2697 || ((pSMBr->resp.hdr.WordCount == 4)
2698 && (blob_len <
2699 pSMBr->resp.ByteCount))) {
2700
2701 if (pSMBr->resp.hdr.WordCount == 4) {
2702 bcc_ptr += blob_len;
Steve French12b3b8f2006-02-09 21:12:47 +00002703 cFYI(1, ("Security Blob Length %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 blob_len));
2705 }
2706
Steve French12b3b8f2006-02-09 21:12:47 +00002707 cFYI(1, ("NTLMSSP Challenge rcvd"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708
2709 memcpy(ses->server->cryptKey,
2710 SecurityBlob2->Challenge,
2711 CIFS_CRYPTO_KEY_SIZE);
Steve French50c2f752007-07-13 00:33:32 +00002712 if (SecurityBlob2->NegotiateFlags &
Steve French12b3b8f2006-02-09 21:12:47 +00002713 cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 *pNTLMv2_flag = TRUE;
2715
Steve French50c2f752007-07-13 00:33:32 +00002716 if ((SecurityBlob2->NegotiateFlags &
2717 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 || (sign_CIFS_PDUs > 1))
Steve French50c2f752007-07-13 00:33:32 +00002719 ses->server->secMode |=
2720 SECMODE_SIGN_REQUIRED;
2721 if ((SecurityBlob2->NegotiateFlags &
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
Steve French50c2f752007-07-13 00:33:32 +00002723 ses->server->secMode |=
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 SECMODE_SIGN_ENABLED;
2725
2726 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2727 if ((long) (bcc_ptr) % 2) {
2728 remaining_words =
2729 (BCC(smb_buffer_response)
2730 - 1) / 2;
Steve French50c2f752007-07-13 00:33:32 +00002731 /* Must word align unicode strings */
2732 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 } else {
2734 remaining_words =
2735 BCC
2736 (smb_buffer_response) / 2;
2737 }
2738 len =
2739 UniStrnlen((wchar_t *) bcc_ptr,
2740 remaining_words - 1);
2741/* We look for obvious messed up bcc or strings in response so we do not go off
2742 the end since (at least) WIN2K and Windows XP have a major bug in not null
2743 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002744 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002745 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002747 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002749 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750 bcc_ptr, len,
2751 nls_codepage);
2752 bcc_ptr += 2 * (len + 1);
2753 remaining_words -= len + 1;
2754 ses->serverOS[2 * len] = 0;
2755 ses->serverOS[1 + (2 * len)] = 0;
2756 if (remaining_words > 0) {
2757 len = UniStrnlen((wchar_t *)
2758 bcc_ptr,
2759 remaining_words
2760 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002761 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002763 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 GFP_KERNEL);
2765 cifs_strfromUCS_le(ses->
2766 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002767 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 bcc_ptr,
2769 len,
2770 nls_codepage);
2771 bcc_ptr += 2 * (len + 1);
2772 ses->serverNOS[2 * len] = 0;
2773 ses->serverNOS[1 +
2774 (2 * len)] = 0;
2775 remaining_words -= len + 1;
2776 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00002777 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2778 /* last string not always null terminated
2779 (for e.g. for Windows XP & 2000) */
Steve Frenchcd49b492006-06-26 04:22:36 +00002780 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002782 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783 (len +
2784 1),
2785 GFP_KERNEL);
2786 cifs_strfromUCS_le
Steve Frenche89dc922005-11-11 15:18:19 -08002787 (ses->serverDomain,
2788 (__le16 *)bcc_ptr,
2789 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790 bcc_ptr +=
2791 2 * (len + 1);
Steve Frenche89dc922005-11-11 15:18:19 -08002792 ses->serverDomain[2*len]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793 = 0;
Steve Frenche89dc922005-11-11 15:18:19 -08002794 ses->serverDomain
2795 [1 + (2 * len)]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 = 0;
2797 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002798 else {
Steve Frenchcd49b492006-06-26 04:22:36 +00002799 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002801 kzalloc(2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002803 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804 } else { /* no room so create dummy domain and NOS string */
Steve Frenchcd49b492006-06-26 04:22:36 +00002805 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002807 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002808 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002810 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811 }
2812 } else { /* ASCII */
2813 len = strnlen(bcc_ptr, 1024);
2814 if (((long) bcc_ptr + len) - (long)
2815 pByteArea(smb_buffer_response)
2816 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002817 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002818 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002820 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821 GFP_KERNEL);
2822 strncpy(ses->serverOS,
2823 bcc_ptr, len);
2824
2825 bcc_ptr += len;
2826 bcc_ptr[0] = 0; /* null terminate string */
2827 bcc_ptr++;
2828
2829 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002830 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002832 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833 GFP_KERNEL);
2834 strncpy(ses->serverNOS, bcc_ptr, len);
2835 bcc_ptr += len;
2836 bcc_ptr[0] = 0;
2837 bcc_ptr++;
2838
2839 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002840 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002842 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +00002844 strncpy(ses->serverDomain,
2845 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846 bcc_ptr += len;
2847 bcc_ptr[0] = 0;
2848 bcc_ptr++;
2849 } else
2850 cFYI(1,
Steve French63135e02007-07-17 17:34:02 +00002851 ("field of length %d "
2852 "extends beyond end of smb",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853 len));
2854 }
2855 } else {
Steve French50c2f752007-07-13 00:33:32 +00002856 cERROR(1, ("Security Blob Length extends beyond"
2857 " end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858 }
2859 } else {
2860 cERROR(1, ("No session structure passed in."));
2861 }
2862 } else {
2863 cERROR(1,
Steve French5815449d2006-02-14 01:36:20 +00002864 (" Invalid Word count %d:",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 smb_buffer_response->WordCount));
2866 rc = -EIO;
2867 }
2868
2869 if (smb_buffer)
2870 cifs_buf_release(smb_buffer);
2871
2872 return rc;
2873}
2874static int
2875CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2876 char *ntlm_session_key, int ntlmv2_flag,
2877 const struct nls_table *nls_codepage)
2878{
2879 struct smb_hdr *smb_buffer;
2880 struct smb_hdr *smb_buffer_response;
2881 SESSION_SETUP_ANDX *pSMB;
2882 SESSION_SETUP_ANDX *pSMBr;
2883 char *bcc_ptr;
2884 char *user;
2885 char *domain;
2886 int rc = 0;
2887 int remaining_words = 0;
2888 int bytes_returned = 0;
2889 int len;
2890 int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2891 PAUTHENTICATE_MESSAGE SecurityBlob;
2892 __u32 negotiate_flags, capabilities;
2893 __u16 count;
2894
2895 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002896 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897 return -EINVAL;
2898 user = ses->userName;
2899 domain = ses->domainName;
2900 smb_buffer = cifs_buf_get();
2901 if (smb_buffer == NULL) {
2902 return -ENOMEM;
2903 }
2904 smb_buffer_response = smb_buffer;
2905 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2906 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2907
2908 /* send SMBsessionSetup here */
2909 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2910 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002911
2912 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2914 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2915 pSMB->req.AndXCommand = 0xFF;
2916 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2917 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2918
2919 pSMB->req.hdr.Uid = ses->Suid;
2920
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002921 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2923
2924 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2925 CAP_EXTENDED_SECURITY;
2926 if (ses->capabilities & CAP_UNICODE) {
2927 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2928 capabilities |= CAP_UNICODE;
2929 }
2930 if (ses->capabilities & CAP_STATUS32) {
2931 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2932 capabilities |= CAP_STATUS32;
2933 }
2934 if (ses->capabilities & CAP_DFS) {
2935 smb_buffer->Flags2 |= SMBFLG2_DFS;
2936 capabilities |= CAP_DFS;
2937 }
2938 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2939
2940 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2941 SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2942 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2943 SecurityBlob->MessageType = NtLmAuthenticate;
2944 bcc_ptr += SecurityBlobLength;
Steve French50c2f752007-07-13 00:33:32 +00002945 negotiate_flags =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2947 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2948 0x80000000 | NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002949 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002951 if (ntlmv2_flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2953
2954/* setup pointers to domain name and workstation name */
2955
2956 SecurityBlob->WorkstationName.Buffer = 0;
2957 SecurityBlob->WorkstationName.Length = 0;
2958 SecurityBlob->WorkstationName.MaximumLength = 0;
2959 SecurityBlob->SessionKey.Length = 0;
2960 SecurityBlob->SessionKey.MaximumLength = 0;
2961 SecurityBlob->SessionKey.Buffer = 0;
2962
2963 SecurityBlob->LmChallengeResponse.Length = 0;
2964 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2965 SecurityBlob->LmChallengeResponse.Buffer = 0;
2966
2967 SecurityBlob->NtChallengeResponse.Length =
Steve French7c7b25b2006-06-01 19:20:10 +00002968 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969 SecurityBlob->NtChallengeResponse.MaximumLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002970 cpu_to_le16(CIFS_SESS_KEY_SIZE);
2971 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972 SecurityBlob->NtChallengeResponse.Buffer =
2973 cpu_to_le32(SecurityBlobLength);
Steve French7c7b25b2006-06-01 19:20:10 +00002974 SecurityBlobLength += CIFS_SESS_KEY_SIZE;
2975 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976
2977 if (ses->capabilities & CAP_UNICODE) {
2978 if (domain == NULL) {
2979 SecurityBlob->DomainName.Buffer = 0;
2980 SecurityBlob->DomainName.Length = 0;
2981 SecurityBlob->DomainName.MaximumLength = 0;
2982 } else {
Steve French77159b42007-08-31 01:10:17 +00002983 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00002985 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00002987 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988 SecurityBlob->DomainName.Buffer =
2989 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00002990 bcc_ptr += ln;
2991 SecurityBlobLength += ln;
2992 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993 }
2994 if (user == NULL) {
2995 SecurityBlob->UserName.Buffer = 0;
2996 SecurityBlob->UserName.Length = 0;
2997 SecurityBlob->UserName.MaximumLength = 0;
2998 } else {
Steve French77159b42007-08-31 01:10:17 +00002999 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003000 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00003001 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002 SecurityBlob->UserName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003003 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004 SecurityBlob->UserName.Buffer =
3005 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003006 bcc_ptr += ln;
3007 SecurityBlobLength += ln;
3008 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009 }
3010
Steve French63135e02007-07-17 17:34:02 +00003011 /* SecurityBlob->WorkstationName.Length =
3012 cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013 SecurityBlob->WorkstationName.Length *= 2;
Steve French63135e02007-07-17 17:34:02 +00003014 SecurityBlob->WorkstationName.MaximumLength =
3015 cpu_to_le16(SecurityBlob->WorkstationName.Length);
3016 SecurityBlob->WorkstationName.Buffer =
3017 cpu_to_le32(SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018 bcc_ptr += SecurityBlob->WorkstationName.Length;
3019 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
Steve French63135e02007-07-17 17:34:02 +00003020 SecurityBlob->WorkstationName.Length =
3021 cpu_to_le16(SecurityBlob->WorkstationName.Length); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022
3023 if ((long) bcc_ptr % 2) {
3024 *bcc_ptr = 0;
3025 bcc_ptr++;
3026 }
3027 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003028 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029 32, nls_codepage);
3030 bcc_ptr += 2 * bytes_returned;
3031 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003032 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033 nls_codepage);
3034 bcc_ptr += 2 * bytes_returned;
3035 bcc_ptr += 2; /* null term version string */
3036 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003037 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038 64, nls_codepage);
3039 bcc_ptr += 2 * bytes_returned;
3040 *(bcc_ptr + 1) = 0;
3041 *(bcc_ptr + 2) = 0;
3042 bcc_ptr += 2; /* null terminate network opsys string */
3043 *(bcc_ptr + 1) = 0;
3044 *(bcc_ptr + 2) = 0;
3045 bcc_ptr += 2; /* null domain */
3046 } else { /* ASCII */
3047 if (domain == NULL) {
3048 SecurityBlob->DomainName.Buffer = 0;
3049 SecurityBlob->DomainName.Length = 0;
3050 SecurityBlob->DomainName.MaximumLength = 0;
3051 } else {
Steve French77159b42007-08-31 01:10:17 +00003052 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
3054 strncpy(bcc_ptr, domain, 63);
Steve French77159b42007-08-31 01:10:17 +00003055 ln = strnlen(domain, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003057 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058 SecurityBlob->DomainName.Buffer =
3059 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003060 bcc_ptr += ln;
3061 SecurityBlobLength += ln;
3062 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063 }
3064 if (user == NULL) {
3065 SecurityBlob->UserName.Buffer = 0;
3066 SecurityBlob->UserName.Length = 0;
3067 SecurityBlob->UserName.MaximumLength = 0;
3068 } else {
Steve French77159b42007-08-31 01:10:17 +00003069 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070 strncpy(bcc_ptr, user, 63);
Steve French77159b42007-08-31 01:10:17 +00003071 ln = strnlen(user, 64);
3072 SecurityBlob->UserName.MaximumLength = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073 SecurityBlob->UserName.Buffer =
Steve French77159b42007-08-31 01:10:17 +00003074 cpu_to_le32(SecurityBlobLength);
3075 bcc_ptr += ln;
3076 SecurityBlobLength += ln;
3077 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078 }
3079 /* BB fill in our workstation name if known BB */
3080
3081 strcpy(bcc_ptr, "Linux version ");
3082 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003083 strcpy(bcc_ptr, utsname()->release);
3084 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
3086 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
3087 bcc_ptr++; /* null domain */
3088 *bcc_ptr = 0;
3089 }
3090 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
3091 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
3092 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
3093 smb_buffer->smb_buf_length += count;
3094 pSMB->req.ByteCount = cpu_to_le16(count);
3095
3096 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
3097 &bytes_returned, 1);
3098 if (rc) {
3099/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
3100 } else if ((smb_buffer_response->WordCount == 3)
3101 || (smb_buffer_response->WordCount == 4)) {
3102 __u16 action = le16_to_cpu(pSMBr->resp.Action);
3103 __u16 blob_len =
3104 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
3105 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00003106 cFYI(1, (" Guest login")); /* BB Should we set anything
3107 in SesInfo struct ? */
3108/* if (SecurityBlob2->MessageType != NtLm??) {
3109 cFYI("Unexpected message type on auth response is %d"));
3110 } */
3111
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112 if (ses) {
3113 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003114 ("Check challenge UID %d vs auth response UID %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115 ses->Suid, smb_buffer_response->Uid));
Steve French50c2f752007-07-13 00:33:32 +00003116 /* UID left in wire format */
3117 ses->Suid = smb_buffer_response->Uid;
3118 bcc_ptr = pByteArea(smb_buffer_response);
3119 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120 if ((pSMBr->resp.hdr.WordCount == 3)
3121 || ((pSMBr->resp.hdr.WordCount == 4)
3122 && (blob_len <
3123 pSMBr->resp.ByteCount))) {
3124 if (pSMBr->resp.hdr.WordCount == 4) {
3125 bcc_ptr +=
3126 blob_len;
3127 cFYI(1,
3128 ("Security Blob Length %d ",
3129 blob_len));
3130 }
3131
3132 cFYI(1,
3133 ("NTLMSSP response to Authenticate "));
3134
3135 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3136 if ((long) (bcc_ptr) % 2) {
3137 remaining_words =
3138 (BCC(smb_buffer_response)
3139 - 1) / 2;
3140 bcc_ptr++; /* Unicode strings must be word aligned */
3141 } else {
3142 remaining_words = BCC(smb_buffer_response) / 2;
3143 }
Steve French77159b42007-08-31 01:10:17 +00003144 len = UniStrnlen((wchar_t *) bcc_ptr,
3145 remaining_words - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146/* We look for obvious messed up bcc or strings in response so we do not go off
3147 the end since (at least) WIN2K and Windows XP have a major bug in not null
3148 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003149 if (ses->serverOS)
Steve French08775832006-05-30 18:08:26 +00003150 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003152 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003154 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003155 bcc_ptr, len,
3156 nls_codepage);
3157 bcc_ptr += 2 * (len + 1);
3158 remaining_words -= len + 1;
3159 ses->serverOS[2 * len] = 0;
3160 ses->serverOS[1 + (2 * len)] = 0;
3161 if (remaining_words > 0) {
3162 len = UniStrnlen((wchar_t *)
3163 bcc_ptr,
3164 remaining_words
3165 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00003166 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003167 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003168 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169 GFP_KERNEL);
3170 cifs_strfromUCS_le(ses->
3171 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003172 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173 bcc_ptr,
3174 len,
3175 nls_codepage);
3176 bcc_ptr += 2 * (len + 1);
3177 ses->serverNOS[2 * len] = 0;
3178 ses->serverNOS[1+(2*len)] = 0;
3179 remaining_words -= len + 1;
3180 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00003181 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182 /* last string not always null terminated (e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003183 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003184 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003186 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003187 (len +
3188 1),
3189 GFP_KERNEL);
3190 cifs_strfromUCS_le
3191 (ses->
3192 serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08003193 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194 bcc_ptr, len,
3195 nls_codepage);
3196 bcc_ptr +=
3197 2 * (len + 1);
3198 ses->
3199 serverDomain[2
3200 * len]
3201 = 0;
3202 ses->
3203 serverDomain[1
3204 +
3205 (2
3206 *
3207 len)]
3208 = 0;
3209 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003210 else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003211 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003212 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003213 ses->serverDomain = kzalloc(2,GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00003214 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215 } else { /* no room so create dummy domain and NOS string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003216 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003217 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003218 ses->serverDomain = kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00003219 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003220 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003221 }
3222 } else { /* ASCII */
3223 len = strnlen(bcc_ptr, 1024);
Steve French50c2f752007-07-13 00:33:32 +00003224 if (((long) bcc_ptr + len) -
3225 (long) pByteArea(smb_buffer_response)
Steve French63135e02007-07-17 17:34:02 +00003226 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003227 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00003228 kfree(ses->serverOS);
Steve French77159b42007-08-31 01:10:17 +00003229 ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230 strncpy(ses->serverOS,bcc_ptr, len);
3231
3232 bcc_ptr += len;
3233 bcc_ptr[0] = 0; /* null terminate the string */
3234 bcc_ptr++;
3235
3236 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003237 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00003238 ses->serverNOS = kzalloc(len+1,
3239 GFP_KERNEL);
Steve French63135e02007-07-17 17:34:02 +00003240 strncpy(ses->serverNOS,
3241 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242 bcc_ptr += len;
3243 bcc_ptr[0] = 0;
3244 bcc_ptr++;
3245
3246 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003247 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003248 kfree(ses->serverDomain);
Steve French63135e02007-07-17 17:34:02 +00003249 ses->serverDomain =
3250 kzalloc(len+1,
3251 GFP_KERNEL);
3252 strncpy(ses->serverDomain,
3253 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003254 bcc_ptr += len;
3255 bcc_ptr[0] = 0;
3256 bcc_ptr++;
3257 } else
3258 cFYI(1,
Steve French63135e02007-07-17 17:34:02 +00003259 ("field of length %d "
3260 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003261 len));
3262 }
3263 } else {
3264 cERROR(1,
Steve French63135e02007-07-17 17:34:02 +00003265 (" Security Blob extends beyond end "
3266 "of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003267 }
3268 } else {
3269 cERROR(1, ("No session structure passed in."));
3270 }
3271 } else {
3272 cERROR(1,
3273 (" Invalid Word count %d: ",
3274 smb_buffer_response->WordCount));
3275 rc = -EIO;
3276 }
3277
3278 if (smb_buffer)
3279 cifs_buf_release(smb_buffer);
3280
3281 return rc;
3282}
3283
3284int
3285CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3286 const char *tree, struct cifsTconInfo *tcon,
3287 const struct nls_table *nls_codepage)
3288{
3289 struct smb_hdr *smb_buffer;
3290 struct smb_hdr *smb_buffer_response;
3291 TCONX_REQ *pSMB;
3292 TCONX_RSP *pSMBr;
3293 unsigned char *bcc_ptr;
3294 int rc = 0;
3295 int length;
3296 __u16 count;
3297
3298 if (ses == NULL)
3299 return -EIO;
3300
3301 smb_buffer = cifs_buf_get();
3302 if (smb_buffer == NULL) {
3303 return -ENOMEM;
3304 }
3305 smb_buffer_response = smb_buffer;
3306
3307 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3308 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003309
3310 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003311 smb_buffer->Uid = ses->Suid;
3312 pSMB = (TCONX_REQ *) smb_buffer;
3313 pSMBr = (TCONX_RSP *) smb_buffer_response;
3314
3315 pSMB->AndXCommand = 0xFF;
3316 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317 bcc_ptr = &pSMB->Password[0];
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003318 if ((ses->server->secMode) & SECMODE_USER) {
Steve Frencheeac8042006-01-13 21:34:58 -08003319 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00003320 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08003321 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00003322 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08003323 } else {
Steve French7c7b25b2006-06-01 19:20:10 +00003324 pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08003325 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
3326 specified as required (when that support is added to
3327 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00003328 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08003329 by Samba (not sure whether other servers allow
3330 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00003331#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French50c2f752007-07-13 00:33:32 +00003332 if ((extended_security & CIFSSEC_MAY_LANMAN) &&
Steve French7c7b25b2006-06-01 19:20:10 +00003333 (ses->server->secType == LANMAN))
3334 calc_lanman_hash(ses, bcc_ptr);
3335 else
3336#endif /* CIFS_WEAK_PW_HASH */
Steve Frencheeac8042006-01-13 21:34:58 -08003337 SMBNTencrypt(ses->password,
3338 ses->server->cryptKey,
3339 bcc_ptr);
3340
Steve French7c7b25b2006-06-01 19:20:10 +00003341 bcc_ptr += CIFS_SESS_KEY_SIZE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003342 if (ses->capabilities & CAP_UNICODE) {
Steve French7c7b25b2006-06-01 19:20:10 +00003343 /* must align unicode strings */
3344 *bcc_ptr = 0; /* null byte password */
3345 bcc_ptr++;
3346 }
Steve Frencheeac8042006-01-13 21:34:58 -08003347 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348
Steve French50c2f752007-07-13 00:33:32 +00003349 if (ses->server->secMode &
Steve Frencha878fb22006-05-30 18:04:19 +00003350 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3352
3353 if (ses->capabilities & CAP_STATUS32) {
3354 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3355 }
3356 if (ses->capabilities & CAP_DFS) {
3357 smb_buffer->Flags2 |= SMBFLG2_DFS;
3358 }
3359 if (ses->capabilities & CAP_UNICODE) {
3360 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3361 length =
Steve French50c2f752007-07-13 00:33:32 +00003362 cifs_strtoUCS((__le16 *) bcc_ptr, tree,
3363 6 /* max utf8 char length in bytes */ *
Steve Frencha878fb22006-05-30 18:04:19 +00003364 (/* server len*/ + 256 /* share len */), nls_codepage);
3365 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366 bcc_ptr += 2; /* skip trailing null */
3367 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368 strcpy(bcc_ptr, tree);
3369 bcc_ptr += strlen(tree) + 1;
3370 }
3371 strcpy(bcc_ptr, "?????");
3372 bcc_ptr += strlen("?????");
3373 bcc_ptr += 1;
3374 count = bcc_ptr - &pSMB->Password[0];
3375 pSMB->hdr.smb_buf_length += count;
3376 pSMB->ByteCount = cpu_to_le16(count);
3377
3378 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
3379
3380 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3381 /* above now done in SendReceive */
3382 if ((rc == 0) && (tcon != NULL)) {
3383 tcon->tidStatus = CifsGood;
3384 tcon->tid = smb_buffer_response->Tid;
3385 bcc_ptr = pByteArea(smb_buffer_response);
3386 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
Steve French50c2f752007-07-13 00:33:32 +00003387 /* skip service field (NB: this field is always ASCII) */
3388 bcc_ptr += length + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003389 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3390 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3391 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3392 if ((bcc_ptr + (2 * length)) -
3393 pByteArea(smb_buffer_response) <=
3394 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003395 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003397 kzalloc(length + 2, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003398 if (tcon->nativeFileSystem)
3399 cifs_strfromUCS_le(
3400 tcon->nativeFileSystem,
3401 (__le16 *) bcc_ptr,
3402 length, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003403 bcc_ptr += 2 * length;
3404 bcc_ptr[0] = 0; /* null terminate the string */
3405 bcc_ptr[1] = 0;
3406 bcc_ptr += 2;
3407 }
Steve French50c2f752007-07-13 00:33:32 +00003408 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003409 } else {
3410 length = strnlen(bcc_ptr, 1024);
3411 if ((bcc_ptr + length) -
3412 pByteArea(smb_buffer_response) <=
3413 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003414 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003416 kzalloc(length + 1, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003417 if (tcon->nativeFileSystem)
3418 strncpy(tcon->nativeFileSystem, bcc_ptr,
3419 length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420 }
Steve French50c2f752007-07-13 00:33:32 +00003421 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003423 if ((smb_buffer_response->WordCount == 3) ||
Steve French1a4e15a2006-10-12 21:33:51 +00003424 (smb_buffer_response->WordCount == 7))
3425 /* field is in same location */
Steve French39798772006-05-31 22:40:51 +00003426 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3427 else
3428 tcon->Flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3430 } else if ((rc == 0) && tcon == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00003431 /* all we need to save for IPC$ connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003432 ses->ipc_tid = smb_buffer_response->Tid;
3433 }
3434
3435 if (smb_buffer)
3436 cifs_buf_release(smb_buffer);
3437 return rc;
3438}
3439
3440int
3441cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3442{
3443 int rc = 0;
3444 int xid;
3445 struct cifsSesInfo *ses = NULL;
3446 struct task_struct *cifsd_task;
Steve French50c2f752007-07-13 00:33:32 +00003447 char *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448
3449 xid = GetXid();
3450
3451 if (cifs_sb->tcon) {
3452 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3453 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3454 if (rc == -EBUSY) {
3455 FreeXid(xid);
3456 return 0;
3457 }
3458 tconInfoFree(cifs_sb->tcon);
3459 if ((ses) && (ses->server)) {
3460 /* save off task so we do not refer to ses later */
3461 cifsd_task = ses->server->tsk;
3462 cFYI(1, ("About to do SMBLogoff "));
3463 rc = CIFSSMBLogoff(xid, ses);
3464 if (rc == -EBUSY) {
3465 FreeXid(xid);
3466 return 0;
3467 } else if (rc == -ESHUTDOWN) {
Steve French467a8f82007-06-27 22:41:32 +00003468 cFYI(1, ("Waking up socket by sending signal"));
Steve Frenchf7f7c312007-05-24 02:29:51 +00003469 if (cifsd_task) {
Steve French50c2f752007-07-13 00:33:32 +00003470 force_sig(SIGKILL, cifsd_task);
Igor Mammedovaaf737a2007-04-03 19:16:43 +00003471 kthread_stop(cifsd_task);
Steve Frenchf1914012005-08-18 09:37:34 -07003472 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003473 rc = 0;
3474 } /* else - we have an smb session
3475 left on this socket do not kill cifsd */
3476 } else
3477 cFYI(1, ("No session or bad tcon"));
3478 }
Steve French50c2f752007-07-13 00:33:32 +00003479
Linus Torvalds1da177e2005-04-16 15:20:36 -07003480 cifs_sb->tcon = NULL;
Steve French2fe87f02006-09-21 07:02:52 +00003481 tmp = cifs_sb->prepath;
3482 cifs_sb->prepathlen = 0;
3483 cifs_sb->prepath = NULL;
3484 kfree(tmp);
Nishanth Aravamudan041e0e32005-09-10 00:27:23 -07003485 if (ses)
3486 schedule_timeout_interruptible(msecs_to_jiffies(500));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487 if (ses)
3488 sesInfoFree(ses);
3489
3490 FreeXid(xid);
Steve French50c2f752007-07-13 00:33:32 +00003491 return rc; /* BB check if we should always return zero here */
3492}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493
3494int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
Steve French50c2f752007-07-13 00:33:32 +00003495 struct nls_table *nls_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496{
3497 int rc = 0;
Steve French7c7b25b2006-06-01 19:20:10 +00003498 char ntlm_session_key[CIFS_SESS_KEY_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499 int ntlmv2_flag = FALSE;
Steve Frenchad009ac2005-04-28 22:41:05 -07003500 int first_time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501
3502 /* what if server changes its buffer size after dropping the session? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003503 if (pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003505 if (rc == -EAGAIN) /* retry only once on 1st time connection */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve French50c2f752007-07-13 00:33:32 +00003507 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003508 rc = -EHOSTDOWN;
3509 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003510 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003511 spin_lock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003512 if (pSesInfo->server->tcpStatus != CifsExiting)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003513 pSesInfo->server->tcpStatus = CifsGood;
3514 else
3515 rc = -EHOSTDOWN;
3516 spin_unlock(&GlobalMid_Lock);
3517
3518 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003519 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520 }
3521 if (!rc) {
Steve French9ac00b72006-09-30 04:13:17 +00003522 pSesInfo->flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523 pSesInfo->capabilities = pSesInfo->server->capabilities;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003524 if (linuxExtEnabled == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003526 /* pSesInfo->sequence_number = 0;*/
Steve French50c2f752007-07-13 00:33:32 +00003527 cFYI(1,
3528 ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003529 pSesInfo->server->secMode,
3530 pSesInfo->server->capabilities,
Steve French175ec9e2006-09-30 01:07:38 +00003531 pSesInfo->server->timeAdj));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003532 if (experimEnabled < 2)
Steve French39798772006-05-31 22:40:51 +00003533 rc = CIFS_SessSetup(xid, pSesInfo,
3534 first_time, nls_info);
Steve French189acaa2006-06-23 02:33:48 +00003535 else if (extended_security
Steve French50c2f752007-07-13 00:33:32 +00003536 && (pSesInfo->capabilities
Steve French175ec9e2006-09-30 01:07:38 +00003537 & CAP_EXTENDED_SECURITY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003538 && (pSesInfo->server->secType == NTLMSSP)) {
Steve French189acaa2006-06-23 02:33:48 +00003539 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003540 } else if (extended_security
3541 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3542 && (pSesInfo->server->secType == RawNTLMSSP)) {
Steve French5815449d2006-02-14 01:36:20 +00003543 cFYI(1, ("NTLMSSP sesssetup"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3545 pSesInfo,
3546 &ntlmv2_flag,
3547 nls_info);
3548 if (!rc) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003549 if (ntlmv2_flag) {
Steve French50c2f752007-07-13 00:33:32 +00003550 char *v2_response;
Steve French467a8f82007-06-27 22:41:32 +00003551 cFYI(1, ("more secure NTLM ver2 hash"));
Steve French50c2f752007-07-13 00:33:32 +00003552 if (CalcNTLMv2_partial_mac_key(pSesInfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003553 nls_info)) {
3554 rc = -ENOMEM;
3555 goto ss_err_exit;
3556 } else
3557 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003558 if (v2_response) {
Steve French50c2f752007-07-13 00:33:32 +00003559 CalcNTLMv2_response(pSesInfo,
3560 v2_response);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003561 /* if (first_time)
Steve French50c2f752007-07-13 00:33:32 +00003562 cifs_calculate_ntlmv2_mac_key(
3563 pSesInfo->server->mac_signing_key,
3564 response, ntlm_session_key,*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565 kfree(v2_response);
3566 /* BB Put dummy sig in SessSetup PDU? */
3567 } else {
3568 rc = -ENOMEM;
3569 goto ss_err_exit;
3570 }
3571
3572 } else {
3573 SMBNTencrypt(pSesInfo->password,
3574 pSesInfo->server->cryptKey,
3575 ntlm_session_key);
3576
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003577 if (first_time)
Steve Frenchad009ac2005-04-28 22:41:05 -07003578 cifs_calculate_mac_key(
Steve Frenchb609f062007-07-09 07:55:14 +00003579 &pSesInfo->server->mac_signing_key,
Steve Frenchad009ac2005-04-28 22:41:05 -07003580 ntlm_session_key,
3581 pSesInfo->password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582 }
3583 /* for better security the weaker lanman hash not sent
3584 in AuthSessSetup so we no longer calculate it */
3585
3586 rc = CIFSNTLMSSPAuthSessSetup(xid,
3587 pSesInfo,
3588 ntlm_session_key,
3589 ntlmv2_flag,
3590 nls_info);
3591 }
3592 } else { /* old style NTLM 0.12 session setup */
3593 SMBNTencrypt(pSesInfo->password,
3594 pSesInfo->server->cryptKey,
3595 ntlm_session_key);
3596
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003597 if (first_time)
Steve Frenchad009ac2005-04-28 22:41:05 -07003598 cifs_calculate_mac_key(
Steve Frenchb609f062007-07-09 07:55:14 +00003599 &pSesInfo->server->mac_signing_key,
Steve Frenchad009ac2005-04-28 22:41:05 -07003600 ntlm_session_key, pSesInfo->password);
3601
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602 rc = CIFSSessSetup(xid, pSesInfo,
3603 ntlm_session_key, nls_info);
3604 }
3605 if (rc) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003606 cERROR(1, ("Send error in SessSetup = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607 } else {
Steve French467a8f82007-06-27 22:41:32 +00003608 cFYI(1, ("CIFS Session Established successfully"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609 pSesInfo->status = CifsGood;
3610 }
3611 }
3612ss_err_exit:
3613 return rc;
3614}
3615