blob: 5f2ec1946776c743203f35d35c53a724b901bbd1 [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 French083d3a2c2006-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 French083d3a2c2006-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 Frenchfb8c4b12007-07-10 01:16:18 +00001745 cFYI(1, ("setting capabilities failed"));
Steve French8af18972007-02-14 04:42:51 +00001746 }
1747 }
1748}
1749
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750int
1751cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1752 char *mount_data, const char *devname)
1753{
1754 int rc = 0;
1755 int xid;
1756 int address_type = AF_INET;
1757 struct socket *csocket = NULL;
1758 struct sockaddr_in sin_server;
1759 struct sockaddr_in6 sin_server6;
1760 struct smb_vol volume_info;
1761 struct cifsSesInfo *pSesInfo = NULL;
1762 struct cifsSesInfo *existingCifsSes = NULL;
1763 struct cifsTconInfo *tcon = NULL;
1764 struct TCP_Server_Info *srvTcp = NULL;
1765
1766 xid = GetXid();
1767
1768/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
Steve French50c2f752007-07-13 00:33:32 +00001769
1770 memset(&volume_info, 0, sizeof(struct smb_vol));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001772 kfree(volume_info.UNC);
1773 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001774 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 FreeXid(xid);
1776 return -EINVAL;
1777 }
1778
Jeff Layton8426c392007-05-05 03:27:49 +00001779 if (volume_info.nullauth) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001780 cFYI(1, ("null user"));
Jeff Layton8426c392007-05-05 03:27:49 +00001781 volume_info.username = NULL;
1782 } else if (volume_info.username) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 /* BB fixme parse for domain name here */
Steve French467a8f82007-06-27 22:41:32 +00001784 cFYI(1, ("Username: %s", volume_info.username));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 } else {
Steve Frenchbf820672005-12-01 22:32:42 -08001786 cifserror("No username specified");
Steve French50c2f752007-07-13 00:33:32 +00001787 /* In userspace mount helper we can get user name from alternate
1788 locations such as env variables and files on disk */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001789 kfree(volume_info.UNC);
1790 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001791 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 FreeXid(xid);
1793 return -EINVAL;
1794 }
1795
1796 if (volume_info.UNCip && volume_info.UNC) {
Steve French50c2f752007-07-13 00:33:32 +00001797 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,
1798 &sin_server.sin_addr.s_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001800 if (rc <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 /* not ipv4 address, try ipv6 */
Steve French50c2f752007-07-13 00:33:32 +00001802 rc = cifs_inet_pton(AF_INET6, volume_info.UNCip,
1803 &sin_server6.sin6_addr.in6_u);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001804 if (rc > 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 address_type = AF_INET6;
1806 } else {
1807 address_type = AF_INET;
1808 }
Steve French50c2f752007-07-13 00:33:32 +00001809
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001810 if (rc <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 /* we failed translating address */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001812 kfree(volume_info.UNC);
1813 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001814 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 FreeXid(xid);
1816 return -EINVAL;
1817 }
1818
1819 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1820 /* success */
1821 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00001822 } else if (volume_info.UNCip) {
1823 /* BB using ip addr as server name to connect to the
1824 DFS root below */
1825 cERROR(1, ("Connecting to DFS root not implemented yet"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001826 kfree(volume_info.UNC);
1827 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001828 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829 FreeXid(xid);
1830 return -EINVAL;
1831 } else /* which servers DFS root would we conect to */ {
1832 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00001833 ("CIFS mount error: No UNC path (e.g. -o "
1834 "unc=//192.168.1.100/public) specified"));
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 }
1841
1842 /* this is needed for ASCII cp to Unicode converts */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001843 if (volume_info.iocharset == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 cifs_sb->local_nls = load_nls_default();
1845 /* load_nls_default can not return null */
1846 } else {
1847 cifs_sb->local_nls = load_nls(volume_info.iocharset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001848 if (cifs_sb->local_nls == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001849 cERROR(1, ("CIFS mount error: iocharset %s not found",
1850 volume_info.iocharset));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001851 kfree(volume_info.UNC);
1852 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001853 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 FreeXid(xid);
1855 return -ELIBACC;
1856 }
1857 }
1858
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001859 if (address_type == AF_INET)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1861 NULL /* no ipv6 addr */,
1862 volume_info.username, &srvTcp);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001863 else if (address_type == AF_INET6) {
1864 cFYI(1, ("looking for ipv6 address"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1866 &sin_server6.sin6_addr,
1867 volume_info.username, &srvTcp);
Steve French5858ae42007-04-25 11:59:10 +00001868 } else {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001869 kfree(volume_info.UNC);
1870 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001871 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 FreeXid(xid);
1873 return -EINVAL;
1874 }
1875
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 if (srvTcp) {
Steve French50c2f752007-07-13 00:33:32 +00001877 cFYI(1, ("Existing tcp session with server found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 } else { /* create socket */
Steve French4523cc32007-04-30 20:13:06 +00001879 if (volume_info.port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 sin_server.sin_port = htons(volume_info.port);
1881 else
1882 sin_server.sin_port = 0;
Steve French5858ae42007-04-25 11:59:10 +00001883 if (address_type == AF_INET6) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001884 cFYI(1, ("attempting ipv6 connect"));
Steve French5858ae42007-04-25 11:59:10 +00001885 /* BB should we allow ipv6 on port 139? */
1886 /* other OS never observed in Wild doing 139 with v6 */
Steve French50c2f752007-07-13 00:33:32 +00001887 rc = ipv6_connect(&sin_server6, &csocket);
1888 } else
1889 rc = ipv4_connect(&sin_server, &csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -07001890 volume_info.source_rfc1001_name,
1891 volume_info.target_rfc1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001893 cERROR(1, ("Error connecting to IPv4 socket. "
1894 "Aborting operation"));
Steve French4523cc32007-04-30 20:13:06 +00001895 if (csocket != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001897 kfree(volume_info.UNC);
1898 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001899 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900 FreeXid(xid);
1901 return rc;
1902 }
1903
1904 srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
1905 if (srvTcp == NULL) {
1906 rc = -ENOMEM;
1907 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001908 kfree(volume_info.UNC);
1909 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001910 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 FreeXid(xid);
1912 return rc;
1913 } else {
1914 memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
Steve French50c2f752007-07-13 00:33:32 +00001915 memcpy(&srvTcp->addr.sockAddr, &sin_server,
1916 sizeof (struct sockaddr_in));
1917 atomic_set(&srvTcp->inFlight, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 /* BB Add code for ipv6 case too */
1919 srvTcp->ssocket = csocket;
1920 srvTcp->protocolType = IPV4;
1921 init_waitqueue_head(&srvTcp->response_q);
1922 init_waitqueue_head(&srvTcp->request_q);
1923 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1924 /* at this point we are the only ones with the pointer
1925 to the struct since the kernel thread not created yet
1926 so no need to spinlock this init of tcpStatus */
1927 srvTcp->tcpStatus = CifsNew;
1928 init_MUTEX(&srvTcp->tcpSem);
Igor Mammedovaaf737a2007-04-03 19:16:43 +00001929 srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd");
Steve French4523cc32007-04-30 20:13:06 +00001930 if ( IS_ERR(srvTcp->tsk) ) {
Igor Mammedovaaf737a2007-04-03 19:16:43 +00001931 rc = PTR_ERR(srvTcp->tsk);
Steve French50c2f752007-07-13 00:33:32 +00001932 cERROR(1, ("error %d create cifsd thread", rc));
Igor Mammedovaaf737a2007-04-03 19:16:43 +00001933 srvTcp->tsk = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001935 kfree(volume_info.UNC);
1936 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001937 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 FreeXid(xid);
1939 return rc;
Steve Frenchf1914012005-08-18 09:37:34 -07001940 }
1941 wait_for_completion(&cifsd_complete);
1942 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00001943 memcpy(srvTcp->workstation_RFC1001_name,
1944 volume_info.source_rfc1001_name, 16);
1945 memcpy(srvTcp->server_RFC1001_name,
1946 volume_info.target_rfc1001_name, 16);
Steve Frenchad009ac2005-04-28 22:41:05 -07001947 srvTcp->sequence_number = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 }
1949 }
1950
1951 if (existingCifsSes) {
1952 pSesInfo = existingCifsSes;
Steve Frenchbf820672005-12-01 22:32:42 -08001953 cFYI(1, ("Existing smb sess found"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001954 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 /* volume_info.UNC freed at end of function */
1956 } else if (!rc) {
Steve Frenchbf820672005-12-01 22:32:42 -08001957 cFYI(1, ("Existing smb sess not found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 pSesInfo = sesInfoAlloc();
1959 if (pSesInfo == NULL)
1960 rc = -ENOMEM;
1961 else {
1962 pSesInfo->server = srvTcp;
1963 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1964 NIPQUAD(sin_server.sin_addr.s_addr));
1965 }
1966
Steve French50c2f752007-07-13 00:33:32 +00001967 if (!rc) {
1968 /* volume_info.password freed at unmount */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969 if (volume_info.password)
1970 pSesInfo->password = volume_info.password;
1971 if (volume_info.username)
1972 strncpy(pSesInfo->userName,
Steve French50c2f752007-07-13 00:33:32 +00001973 volume_info.username,
1974 MAX_USERNAME_SIZE);
Steve French39798772006-05-31 22:40:51 +00001975 if (volume_info.domainname) {
1976 int len = strlen(volume_info.domainname);
Steve French50c2f752007-07-13 00:33:32 +00001977 pSesInfo->domainName =
Steve French39798772006-05-31 22:40:51 +00001978 kmalloc(len + 1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001979 if (pSesInfo->domainName)
Steve French39798772006-05-31 22:40:51 +00001980 strcpy(pSesInfo->domainName,
1981 volume_info.domainname);
1982 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983 pSesInfo->linux_uid = volume_info.linux_uid;
Steve French750d1152006-06-27 06:28:30 +00001984 pSesInfo->overrideSecFlg = volume_info.secFlg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 down(&pSesInfo->sesSem);
Steve French189acaa2006-06-23 02:33:48 +00001986 /* BB FIXME need to pass vol->secFlgs BB */
Steve French50c2f752007-07-13 00:33:32 +00001987 rc = cifs_setup_session(xid, pSesInfo,
1988 cifs_sb->local_nls);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989 up(&pSesInfo->sesSem);
Steve French4523cc32007-04-30 20:13:06 +00001990 if (!rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 atomic_inc(&srvTcp->socketUseCount);
1992 } else
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001993 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 }
Steve French50c2f752007-07-13 00:33:32 +00001995
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 /* search for existing tcon to this server share */
1997 if (!rc) {
Steve French4523cc32007-04-30 20:13:06 +00001998 if (volume_info.rsize > CIFSMaxBufSize) {
Steve French50c2f752007-07-13 00:33:32 +00001999 cERROR(1, ("rsize %d too large, using MaxBufSize",
Steve French0ae0efa2005-10-10 10:57:19 -07002000 volume_info.rsize));
2001 cifs_sb->rsize = CIFSMaxBufSize;
Steve French75865f8c2007-06-24 18:30:48 +00002002 } else if ((volume_info.rsize) &&
2003 (volume_info.rsize <= CIFSMaxBufSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 cifs_sb->rsize = volume_info.rsize;
Steve French0ae0efa2005-10-10 10:57:19 -07002005 else /* default */
2006 cifs_sb->rsize = CIFSMaxBufSize;
2007
Steve French4523cc32007-04-30 20:13:06 +00002008 if (volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
Steve French50c2f752007-07-13 00:33:32 +00002009 cERROR(1, ("wsize %d too large, using 4096 instead",
Steve French0ae0efa2005-10-10 10:57:19 -07002010 volume_info.wsize));
2011 cifs_sb->wsize = 4096;
Steve French4523cc32007-04-30 20:13:06 +00002012 } else if (volume_info.wsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013 cifs_sb->wsize = volume_info.wsize;
2014 else
Steve French50c2f752007-07-13 00:33:32 +00002015 cifs_sb->wsize =
Steve French1877c9e2006-01-27 18:36:11 -08002016 min_t(const int, PAGEVEC_SIZE * PAGE_CACHE_SIZE,
2017 127*1024);
Steve French17cbbaf2006-01-24 20:26:48 -08002018 /* old default of CIFSMaxBufSize was too small now
Steve French50c2f752007-07-13 00:33:32 +00002019 that SMB Write2 can send multiple pages in kvec.
Steve French17cbbaf2006-01-24 20:26:48 -08002020 RFC1001 does not describe what happens when frame
2021 bigger than 128K is sent so use that as max in
2022 conjunction with 52K kvec constraint on arch with 4K
2023 page size */
2024
Steve French4523cc32007-04-30 20:13:06 +00002025 if (cifs_sb->rsize < 2048) {
Steve French50c2f752007-07-13 00:33:32 +00002026 cifs_sb->rsize = 2048;
Steve French6cec2ae2006-02-22 17:31:52 -06002027 /* Windows ME may prefer this */
Steve French467a8f82007-06-27 22:41:32 +00002028 cFYI(1, ("readsize set to minimum: 2048"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 }
Steve French2fe87f02006-09-21 07:02:52 +00002030 /* calculate prepath */
2031 cifs_sb->prepath = volume_info.prepath;
Steve French4523cc32007-04-30 20:13:06 +00002032 if (cifs_sb->prepath) {
Steve French2fe87f02006-09-21 07:02:52 +00002033 cifs_sb->prepathlen = strlen(cifs_sb->prepath);
2034 cifs_sb->prepath[0] = CIFS_DIR_SEP(cifs_sb);
2035 volume_info.prepath = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002036 } else
Steve French2fe87f02006-09-21 07:02:52 +00002037 cifs_sb->prepathlen = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 cifs_sb->mnt_uid = volume_info.linux_uid;
2039 cifs_sb->mnt_gid = volume_info.linux_gid;
2040 cifs_sb->mnt_file_mode = volume_info.file_mode;
2041 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
Steve French467a8f82007-06-27 22:41:32 +00002042 cFYI(1, ("file mode: 0x%x dir mode: 0x%x",
2043 cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044
Steve French4523cc32007-04-30 20:13:06 +00002045 if (volume_info.noperm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
Steve French4523cc32007-04-30 20:13:06 +00002047 if (volume_info.setuids)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
Steve French4523cc32007-04-30 20:13:06 +00002049 if (volume_info.server_ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
Steve French4523cc32007-04-30 20:13:06 +00002051 if (volume_info.remap)
Steve French6a0b4822005-04-28 22:41:05 -07002052 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
Steve French4523cc32007-04-30 20:13:06 +00002053 if (volume_info.no_xattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
Steve French4523cc32007-04-30 20:13:06 +00002055 if (volume_info.sfu_emul)
Steve Frenchd7245c22005-07-14 18:25:12 -05002056 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
Steve French4523cc32007-04-30 20:13:06 +00002057 if (volume_info.nobrl)
Steve Frenchc46fa8a2005-08-18 20:49:57 -07002058 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Steve French4523cc32007-04-30 20:13:06 +00002059 if (volume_info.cifs_acl)
Steve French0a4b92c2006-01-12 15:44:21 -08002060 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
Steve French4523cc32007-04-30 20:13:06 +00002061 if (volume_info.override_uid)
2062 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
2063 if (volume_info.override_gid)
2064 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
2065 if (volume_info.direct_io) {
Steve French467a8f82007-06-27 22:41:32 +00002066 cFYI(1, ("mounting share using direct i/o"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
2068 }
2069
2070 tcon =
2071 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
2072 volume_info.username);
2073 if (tcon) {
Steve Frenchbf820672005-12-01 22:32:42 -08002074 cFYI(1, ("Found match on UNC path"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075 /* we can have only one retry value for a connection
2076 to a share so for resources mounted more than once
Steve French50c2f752007-07-13 00:33:32 +00002077 to the same server share the last value passed in
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078 for the retry flag is used */
2079 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07002080 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081 } else {
2082 tcon = tconInfoAlloc();
2083 if (tcon == NULL)
2084 rc = -ENOMEM;
2085 else {
Steve French50c2f752007-07-13 00:33:32 +00002086 /* check for null share name ie connecting to
Steve French8af18972007-02-14 04:42:51 +00002087 * dfs root */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088
Steve French50c2f752007-07-13 00:33:32 +00002089 /* BB check if this works for exactly length
Steve French8af18972007-02-14 04:42:51 +00002090 * three strings */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
2092 && (strchr(volume_info.UNC + 3, '/') ==
2093 NULL)) {
Steve French737b7582005-04-28 22:41:06 -07002094 rc = connect_to_dfs_path(xid, pSesInfo,
Steve French8af18972007-02-14 04:42:51 +00002095 "", cifs_sb->local_nls,
Steve French50c2f752007-07-13 00:33:32 +00002096 cifs_sb->mnt_cifs_flags &
Steve French8af18972007-02-14 04:42:51 +00002097 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002098 kfree(volume_info.UNC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099 FreeXid(xid);
2100 return -ENODEV;
2101 } else {
Steve French8af18972007-02-14 04:42:51 +00002102 /* BB Do we need to wrap sesSem around
2103 * this TCon call and Unix SetFS as
2104 * we do on SessSetup and reconnect? */
Steve French50c2f752007-07-13 00:33:32 +00002105 rc = CIFSTCon(xid, pSesInfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106 volume_info.UNC,
2107 tcon, cifs_sb->local_nls);
2108 cFYI(1, ("CIFS Tcon rc = %d", rc));
2109 }
2110 if (!rc) {
2111 atomic_inc(&pSesInfo->inUse);
2112 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07002113 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114 }
2115 }
2116 }
2117 }
Steve French4523cc32007-04-30 20:13:06 +00002118 if (pSesInfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
2120 sb->s_maxbytes = (u64) 1 << 63;
2121 } else
2122 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
2123 }
2124
Steve French8af18972007-02-14 04:42:51 +00002125 /* BB FIXME fix time_gran to be larger for LANMAN sessions */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 sb->s_time_gran = 100;
2127
2128/* on error free sesinfo and tcon struct if needed */
2129 if (rc) {
2130 /* if session setup failed, use count is zero but
2131 we still need to free cifsd thread */
Steve French4523cc32007-04-30 20:13:06 +00002132 if (atomic_read(&srvTcp->socketUseCount) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 spin_lock(&GlobalMid_Lock);
2134 srvTcp->tcpStatus = CifsExiting;
2135 spin_unlock(&GlobalMid_Lock);
Steve French4523cc32007-04-30 20:13:06 +00002136 if (srvTcp->tsk) {
Steve French28356a12007-05-23 14:45:36 +00002137 struct task_struct *tsk;
2138 /* If we could verify that kthread_stop would
2139 always wake up processes blocked in
2140 tcp in recv_mesg then we could remove the
2141 send_sig call */
Steve French50c2f752007-07-13 00:33:32 +00002142 force_sig(SIGKILL, srvTcp->tsk);
Steve French28356a12007-05-23 14:45:36 +00002143 tsk = srvTcp->tsk;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002144 if (tsk)
Steve Frenchf7f7c312007-05-24 02:29:51 +00002145 kthread_stop(tsk);
Steve Frenchf1914012005-08-18 09:37:34 -07002146 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147 }
2148 /* If find_unc succeeded then rc == 0 so we can not end */
2149 if (tcon) /* up accidently freeing someone elses tcon struct */
2150 tconInfoFree(tcon);
2151 if (existingCifsSes == NULL) {
2152 if (pSesInfo) {
Steve French50c2f752007-07-13 00:33:32 +00002153 if ((pSesInfo->server) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 (pSesInfo->status == CifsGood)) {
2155 int temp_rc;
2156 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
2157 /* if the socketUseCount is now zero */
Steve French4523cc32007-04-30 20:13:06 +00002158 if ((temp_rc == -ESHUTDOWN) &&
Steve French50c2f752007-07-13 00:33:32 +00002159 (pSesInfo->server) &&
Jeff5d9c7202007-06-25 22:16:35 +00002160 (pSesInfo->server->tsk)) {
Steve French28356a12007-05-23 14:45:36 +00002161 struct task_struct *tsk;
Jeff5d9c7202007-06-25 22:16:35 +00002162 force_sig(SIGKILL,
2163 pSesInfo->server->tsk);
Steve French28356a12007-05-23 14:45:36 +00002164 tsk = pSesInfo->server->tsk;
Steve Frenchf7f7c312007-05-24 02:29:51 +00002165 if (tsk)
Steve French28356a12007-05-23 14:45:36 +00002166 kthread_stop(tsk);
Steve Frenchf1914012005-08-18 09:37:34 -07002167 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168 } else
2169 cFYI(1, ("No session or bad tcon"));
2170 sesInfoFree(pSesInfo);
2171 /* pSesInfo = NULL; */
2172 }
2173 }
2174 } else {
2175 atomic_inc(&tcon->useCount);
2176 cifs_sb->tcon = tcon;
2177 tcon->ses = pSesInfo;
2178
Steve French82940a42006-03-02 03:24:57 +00002179 /* do not care if following two calls succeed - informational */
Steve French737b7582005-04-28 22:41:06 -07002180 CIFSSMBQFSDeviceInfo(xid, tcon);
2181 CIFSSMBQFSAttributeInfo(xid, tcon);
Steve French50c2f752007-07-13 00:33:32 +00002182
Steve French8af18972007-02-14 04:42:51 +00002183 /* tell server which Unix caps we support */
2184 if (tcon->ses->capabilities & CAP_UNIX)
Steve Frenchc18c8422007-07-18 23:21:09 +00002185 /* reset of caps checks mount to see if unix extensions
2186 disabled for just this mount */
Steve French8af18972007-02-14 04:42:51 +00002187 reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
Steve Frenchc18c8422007-07-18 23:21:09 +00002188 else
2189 tcon->unix_ext = 0; /* server does not support them */
2190
2191 if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
Steve French75865f8c2007-06-24 18:30:48 +00002192 cifs_sb->rsize = 1024 * 127;
2193#ifdef CONFIG_CIFS_DEBUG2
Steve Frenchc18c8422007-07-18 23:21:09 +00002194 cFYI(1, ("no very large read support, rsize now 127K"));
Steve French75865f8c2007-06-24 18:30:48 +00002195#endif
Steve French75865f8c2007-06-24 18:30:48 +00002196 }
Steve French3e844692005-10-03 13:37:24 -07002197 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
2198 cifs_sb->wsize = min(cifs_sb->wsize,
2199 (tcon->ses->server->maxBuf -
2200 MAX_CIFS_HDR_SIZE));
Steve French0ae0efa2005-10-10 10:57:19 -07002201 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
Steve French50c2f752007-07-13 00:33:32 +00002202 cifs_sb->rsize = min(cifs_sb->rsize,
2203 (tcon->ses->server->maxBuf -
2204 MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 }
2206
2207 /* volume_info.password is freed above when existing session found
2208 (in which case it is not needed anymore) but when new sesion is created
2209 the password ptr is put in the new session structure (in which case the
2210 password will be freed at unmount time) */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002211 kfree(volume_info.UNC);
Steve French2fe87f02006-09-21 07:02:52 +00002212 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213 FreeXid(xid);
2214 return rc;
2215}
2216
2217static int
2218CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French7c7b25b2006-06-01 19:20:10 +00002219 char session_key[CIFS_SESS_KEY_SIZE],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 const struct nls_table *nls_codepage)
2221{
2222 struct smb_hdr *smb_buffer;
2223 struct smb_hdr *smb_buffer_response;
2224 SESSION_SETUP_ANDX *pSMB;
2225 SESSION_SETUP_ANDX *pSMBr;
2226 char *bcc_ptr;
2227 char *user;
2228 char *domain;
2229 int rc = 0;
2230 int remaining_words = 0;
2231 int bytes_returned = 0;
2232 int len;
2233 __u32 capabilities;
2234 __u16 count;
2235
Steve Frencheeac8042006-01-13 21:34:58 -08002236 cFYI(1, ("In sesssetup"));
Steve French4523cc32007-04-30 20:13:06 +00002237 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 return -EINVAL;
2239 user = ses->userName;
2240 domain = ses->domainName;
2241 smb_buffer = cifs_buf_get();
2242 if (smb_buffer == NULL) {
2243 return -ENOMEM;
2244 }
2245 smb_buffer_response = smb_buffer;
2246 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2247
2248 /* send SMBsessionSetup here */
2249 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2250 NULL /* no tCon exists yet */ , 13 /* wct */ );
2251
Steve French1982c342005-08-17 12:38:22 -07002252 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 pSMB->req_no_secext.AndXCommand = 0xFF;
2254 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2255 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2256
Steve French50c2f752007-07-13 00:33:32 +00002257 if (ses->server->secMode &
2258 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2260
2261 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2262 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
2263 if (ses->capabilities & CAP_UNICODE) {
2264 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2265 capabilities |= CAP_UNICODE;
2266 }
2267 if (ses->capabilities & CAP_STATUS32) {
2268 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2269 capabilities |= CAP_STATUS32;
2270 }
2271 if (ses->capabilities & CAP_DFS) {
2272 smb_buffer->Flags2 |= SMBFLG2_DFS;
2273 capabilities |= CAP_DFS;
2274 }
2275 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
2276
Steve French50c2f752007-07-13 00:33:32 +00002277 pSMB->req_no_secext.CaseInsensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002278 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279
2280 pSMB->req_no_secext.CaseSensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002281 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282 bcc_ptr = pByteArea(smb_buffer);
Steve French7c7b25b2006-06-01 19:20:10 +00002283 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2284 bcc_ptr += CIFS_SESS_KEY_SIZE;
2285 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2286 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287
2288 if (ses->capabilities & CAP_UNICODE) {
2289 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
2290 *bcc_ptr = 0;
2291 bcc_ptr++;
2292 }
Steve French4523cc32007-04-30 20:13:06 +00002293 if (user == NULL)
Steve French39798772006-05-31 22:40:51 +00002294 bytes_returned = 0; /* skip null user */
Steve French50c2f752007-07-13 00:33:32 +00002295 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296 bytes_returned =
Steve French50c2f752007-07-13 00:33:32 +00002297 cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298 nls_codepage);
2299 /* convert number of 16 bit words to bytes */
2300 bcc_ptr += 2 * bytes_returned;
2301 bcc_ptr += 2; /* trailing null */
2302 if (domain == NULL)
2303 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002304 cifs_strtoUCS((__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305 "CIFS_LINUX_DOM", 32, nls_codepage);
2306 else
2307 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002308 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 nls_codepage);
2310 bcc_ptr += 2 * bytes_returned;
2311 bcc_ptr += 2;
2312 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002313 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314 32, nls_codepage);
2315 bcc_ptr += 2 * bytes_returned;
2316 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002317 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318 32, 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, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 64, nls_codepage);
2324 bcc_ptr += 2 * bytes_returned;
2325 bcc_ptr += 2;
2326 } else {
Steve French50c2f752007-07-13 00:33:32 +00002327 if (user != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 strncpy(bcc_ptr, user, 200);
2329 bcc_ptr += strnlen(user, 200);
2330 }
2331 *bcc_ptr = 0;
2332 bcc_ptr++;
2333 if (domain == NULL) {
2334 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2335 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2336 } else {
2337 strncpy(bcc_ptr, domain, 64);
2338 bcc_ptr += strnlen(domain, 64);
2339 *bcc_ptr = 0;
2340 bcc_ptr++;
2341 }
2342 strcpy(bcc_ptr, "Linux version ");
2343 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002344 strcpy(bcc_ptr, utsname()->release);
2345 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2347 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2348 }
2349 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2350 smb_buffer->smb_buf_length += count;
2351 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2352
2353 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2354 &bytes_returned, 1);
2355 if (rc) {
2356/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2357 } else if ((smb_buffer_response->WordCount == 3)
2358 || (smb_buffer_response->WordCount == 4)) {
2359 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2360 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2361 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002362 cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */
2363 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format
2364 (little endian) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365 cFYI(1, ("UID = %d ", ses->Suid));
Steve French50c2f752007-07-13 00:33:32 +00002366 /* response can have either 3 or 4 word count - Samba sends 3 */
2367 bcc_ptr = pByteArea(smb_buffer_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368 if ((pSMBr->resp.hdr.WordCount == 3)
2369 || ((pSMBr->resp.hdr.WordCount == 4)
2370 && (blob_len < pSMBr->resp.ByteCount))) {
2371 if (pSMBr->resp.hdr.WordCount == 4)
2372 bcc_ptr += blob_len;
2373
2374 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2375 if ((long) (bcc_ptr) % 2) {
2376 remaining_words =
Steve French50c2f752007-07-13 00:33:32 +00002377 (BCC(smb_buffer_response) - 1) / 2;
2378 /* Unicode strings must be word
2379 aligned */
2380 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381 } else {
2382 remaining_words =
2383 BCC(smb_buffer_response) / 2;
2384 }
2385 len =
2386 UniStrnlen((wchar_t *) bcc_ptr,
2387 remaining_words - 1);
2388/* We look for obvious messed up bcc or strings in response so we do not go off
2389 the end since (at least) WIN2K and Windows XP have a major bug in not null
2390 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002391 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002392 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002393 ses->serverOS = kzalloc(2 * (len + 1),
2394 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002395 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002396 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397 cifs_strfromUCS_le(ses->serverOS,
Steve French50c2f752007-07-13 00:33:32 +00002398 (__le16 *)bcc_ptr,
2399 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400 bcc_ptr += 2 * (len + 1);
2401 remaining_words -= len + 1;
2402 ses->serverOS[2 * len] = 0;
2403 ses->serverOS[1 + (2 * len)] = 0;
2404 if (remaining_words > 0) {
2405 len = UniStrnlen((wchar_t *)bcc_ptr,
2406 remaining_words-1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002407 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002408 ses->serverNOS = kzalloc(2 * (len + 1),
2409 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002410 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002411 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 cifs_strfromUCS_le(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002413 (__le16 *)bcc_ptr,
2414 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 bcc_ptr += 2 * (len + 1);
2416 ses->serverNOS[2 * len] = 0;
2417 ses->serverNOS[1 + (2 * len)] = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002418 if (strncmp(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002419 "NT LAN Manager 4", 16) == 0) {
Steve French467a8f82007-06-27 22:41:32 +00002420 cFYI(1, ("NT4 server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421 ses->flags |= CIFS_SES_NT4;
2422 }
2423 remaining_words -= len + 1;
2424 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002425 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Steve French50c2f752007-07-13 00:33:32 +00002426 /* last string is not always null terminated
2427 (for e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002428 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002429 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430 ses->serverDomain =
Steve French50c2f752007-07-13 00:33:32 +00002431 kzalloc(2*(len+1),
2432 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002433 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002434 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435 cifs_strfromUCS_le(ses->serverDomain,
Steve French50c2f752007-07-13 00:33:32 +00002436 (__le16 *)bcc_ptr,
2437 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438 bcc_ptr += 2 * (len + 1);
2439 ses->serverDomain[2*len] = 0;
2440 ses->serverDomain[1+(2*len)] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002441 } else { /* else no more room so create
2442 dummy domain string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002443 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002444 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002445 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002446 kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002447 }
Steve French50c2f752007-07-13 00:33:32 +00002448 } else { /* no room so create dummy domain
2449 and NOS string */
2450
Steve French433dc242005-04-28 22:41:08 -07002451 /* if these kcallocs fail not much we
2452 can do, but better to not fail the
2453 sesssetup itself */
Steve Frenchcd49b492006-06-26 04:22:36 +00002454 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002456 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002457 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002459 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460 }
2461 } else { /* ASCII */
2462 len = strnlen(bcc_ptr, 1024);
2463 if (((long) bcc_ptr + len) - (long)
2464 pByteArea(smb_buffer_response)
2465 <= BCC(smb_buffer_response)) {
Steve Frenchcd49b492006-06-26 04:22:36 +00002466 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002467 ses->serverOS = kzalloc(len + 1,
2468 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002469 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002470 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002471 strncpy(ses->serverOS, bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472
2473 bcc_ptr += len;
Steve French50c2f752007-07-13 00:33:32 +00002474 /* null terminate the string */
2475 bcc_ptr[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476 bcc_ptr++;
2477
2478 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002479 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002480 ses->serverNOS = kzalloc(len + 1,
2481 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002482 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002483 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484 strncpy(ses->serverNOS, bcc_ptr, len);
2485 bcc_ptr += len;
2486 bcc_ptr[0] = 0;
2487 bcc_ptr++;
2488
2489 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002490 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002491 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002492 ses->serverDomain = kzalloc(len + 1,
2493 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002494 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002495 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002496 strncpy(ses->serverDomain, bcc_ptr,
2497 len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498 bcc_ptr += len;
2499 bcc_ptr[0] = 0;
2500 bcc_ptr++;
2501 } else
2502 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00002503 ("Variable field of length %d "
2504 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505 len));
2506 }
2507 } else {
2508 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00002509 (" Security Blob Length extends beyond "
2510 "end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511 }
2512 } else {
2513 cERROR(1,
2514 (" Invalid Word count %d: ",
2515 smb_buffer_response->WordCount));
2516 rc = -EIO;
2517 }
Steve French433dc242005-04-28 22:41:08 -07002518sesssetup_nomem: /* do not return an error on nomem for the info strings,
2519 since that could make reconnection harder, and
2520 reconnection might be needed to free memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 if (smb_buffer)
2522 cifs_buf_release(smb_buffer);
2523
2524 return rc;
2525}
2526
2527static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
Steve French50c2f752007-07-13 00:33:32 +00002529 struct cifsSesInfo *ses, int *pNTLMv2_flag,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530 const struct nls_table *nls_codepage)
2531{
2532 struct smb_hdr *smb_buffer;
2533 struct smb_hdr *smb_buffer_response;
2534 SESSION_SETUP_ANDX *pSMB;
2535 SESSION_SETUP_ANDX *pSMBr;
2536 char *bcc_ptr;
2537 char *domain;
2538 int rc = 0;
2539 int remaining_words = 0;
2540 int bytes_returned = 0;
2541 int len;
2542 int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
2543 PNEGOTIATE_MESSAGE SecurityBlob;
2544 PCHALLENGE_MESSAGE SecurityBlob2;
2545 __u32 negotiate_flags, capabilities;
2546 __u16 count;
2547
Steve French12b3b8f2006-02-09 21:12:47 +00002548 cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002549 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550 return -EINVAL;
2551 domain = ses->domainName;
2552 *pNTLMv2_flag = FALSE;
2553 smb_buffer = cifs_buf_get();
2554 if (smb_buffer == NULL) {
2555 return -ENOMEM;
2556 }
2557 smb_buffer_response = smb_buffer;
2558 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2559 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2560
2561 /* send SMBsessionSetup here */
2562 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2563 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002564
2565 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2567 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2568
2569 pSMB->req.AndXCommand = 0xFF;
2570 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2571 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2572
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002573 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2575
2576 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2577 CAP_EXTENDED_SECURITY;
2578 if (ses->capabilities & CAP_UNICODE) {
2579 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2580 capabilities |= CAP_UNICODE;
2581 }
2582 if (ses->capabilities & CAP_STATUS32) {
2583 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2584 capabilities |= CAP_STATUS32;
2585 }
2586 if (ses->capabilities & CAP_DFS) {
2587 smb_buffer->Flags2 |= SMBFLG2_DFS;
2588 capabilities |= CAP_DFS;
2589 }
2590 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2591
2592 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2593 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2594 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2595 SecurityBlob->MessageType = NtLmNegotiate;
2596 negotiate_flags =
2597 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
Steve French12b3b8f2006-02-09 21:12:47 +00002598 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
2599 NTLMSSP_NEGOTIATE_56 |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002601 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002603/* if (ntlmv2_support)
Steve French39798772006-05-31 22:40:51 +00002604 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605 /* setup pointers to domain name and workstation name */
2606 bcc_ptr += SecurityBlobLength;
2607
2608 SecurityBlob->WorkstationName.Buffer = 0;
2609 SecurityBlob->WorkstationName.Length = 0;
2610 SecurityBlob->WorkstationName.MaximumLength = 0;
2611
Steve French12b3b8f2006-02-09 21:12:47 +00002612 /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent
2613 along with username on auth request (ie the response to challenge) */
2614 SecurityBlob->DomainName.Buffer = 0;
2615 SecurityBlob->DomainName.Length = 0;
2616 SecurityBlob->DomainName.MaximumLength = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617 if (ses->capabilities & CAP_UNICODE) {
2618 if ((long) bcc_ptr % 2) {
2619 *bcc_ptr = 0;
2620 bcc_ptr++;
2621 }
2622
2623 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002624 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625 32, nls_codepage);
2626 bcc_ptr += 2 * bytes_returned;
2627 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002628 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629 nls_codepage);
2630 bcc_ptr += 2 * bytes_returned;
2631 bcc_ptr += 2; /* null terminate Linux version */
2632 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002633 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634 64, nls_codepage);
2635 bcc_ptr += 2 * bytes_returned;
2636 *(bcc_ptr + 1) = 0;
2637 *(bcc_ptr + 2) = 0;
2638 bcc_ptr += 2; /* null terminate network opsys string */
2639 *(bcc_ptr + 1) = 0;
2640 *(bcc_ptr + 2) = 0;
2641 bcc_ptr += 2; /* null domain */
2642 } else { /* ASCII */
2643 strcpy(bcc_ptr, "Linux version ");
2644 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002645 strcpy(bcc_ptr, utsname()->release);
2646 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2648 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2649 bcc_ptr++; /* empty domain field */
2650 *bcc_ptr = 0;
2651 }
2652 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2653 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2654 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2655 smb_buffer->smb_buf_length += count;
2656 pSMB->req.ByteCount = cpu_to_le16(count);
2657
2658 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2659 &bytes_returned, 1);
2660
2661 if (smb_buffer_response->Status.CifsError ==
2662 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2663 rc = 0;
2664
2665 if (rc) {
2666/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2667 } else if ((smb_buffer_response->WordCount == 3)
2668 || (smb_buffer_response->WordCount == 4)) {
2669 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2670 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2671
2672 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002673 cFYI(1, (" Guest login"));
2674 /* Do we want to set anything in SesInfo struct when guest login? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675
Steve French50c2f752007-07-13 00:33:32 +00002676 bcc_ptr = pByteArea(smb_buffer_response);
2677 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678
2679 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2680 if (SecurityBlob2->MessageType != NtLmChallenge) {
2681 cFYI(1,
2682 ("Unexpected NTLMSSP message type received %d",
2683 SecurityBlob2->MessageType));
2684 } else if (ses) {
Steve French50c2f752007-07-13 00:33:32 +00002685 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
Steve French12b3b8f2006-02-09 21:12:47 +00002686 cFYI(1, ("UID = %d", ses->Suid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687 if ((pSMBr->resp.hdr.WordCount == 3)
2688 || ((pSMBr->resp.hdr.WordCount == 4)
2689 && (blob_len <
2690 pSMBr->resp.ByteCount))) {
2691
2692 if (pSMBr->resp.hdr.WordCount == 4) {
2693 bcc_ptr += blob_len;
Steve French12b3b8f2006-02-09 21:12:47 +00002694 cFYI(1, ("Security Blob Length %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695 blob_len));
2696 }
2697
Steve French12b3b8f2006-02-09 21:12:47 +00002698 cFYI(1, ("NTLMSSP Challenge rcvd"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699
2700 memcpy(ses->server->cryptKey,
2701 SecurityBlob2->Challenge,
2702 CIFS_CRYPTO_KEY_SIZE);
Steve French50c2f752007-07-13 00:33:32 +00002703 if (SecurityBlob2->NegotiateFlags &
Steve French12b3b8f2006-02-09 21:12:47 +00002704 cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705 *pNTLMv2_flag = TRUE;
2706
Steve French50c2f752007-07-13 00:33:32 +00002707 if ((SecurityBlob2->NegotiateFlags &
2708 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 || (sign_CIFS_PDUs > 1))
Steve French50c2f752007-07-13 00:33:32 +00002710 ses->server->secMode |=
2711 SECMODE_SIGN_REQUIRED;
2712 if ((SecurityBlob2->NegotiateFlags &
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
Steve French50c2f752007-07-13 00:33:32 +00002714 ses->server->secMode |=
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 SECMODE_SIGN_ENABLED;
2716
2717 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2718 if ((long) (bcc_ptr) % 2) {
2719 remaining_words =
2720 (BCC(smb_buffer_response)
2721 - 1) / 2;
Steve French50c2f752007-07-13 00:33:32 +00002722 /* Must word align unicode strings */
2723 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 } else {
2725 remaining_words =
2726 BCC
2727 (smb_buffer_response) / 2;
2728 }
2729 len =
2730 UniStrnlen((wchar_t *) bcc_ptr,
2731 remaining_words - 1);
2732/* We look for obvious messed up bcc or strings in response so we do not go off
2733 the end since (at least) WIN2K and Windows XP have a major bug in not null
2734 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002735 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002736 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002738 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002740 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 bcc_ptr, len,
2742 nls_codepage);
2743 bcc_ptr += 2 * (len + 1);
2744 remaining_words -= len + 1;
2745 ses->serverOS[2 * len] = 0;
2746 ses->serverOS[1 + (2 * len)] = 0;
2747 if (remaining_words > 0) {
2748 len = UniStrnlen((wchar_t *)
2749 bcc_ptr,
2750 remaining_words
2751 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002752 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002754 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 GFP_KERNEL);
2756 cifs_strfromUCS_le(ses->
2757 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002758 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 bcc_ptr,
2760 len,
2761 nls_codepage);
2762 bcc_ptr += 2 * (len + 1);
2763 ses->serverNOS[2 * len] = 0;
2764 ses->serverNOS[1 +
2765 (2 * len)] = 0;
2766 remaining_words -= len + 1;
2767 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00002768 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2769 /* last string not always null terminated
2770 (for e.g. for Windows XP & 2000) */
Steve Frenchcd49b492006-06-26 04:22:36 +00002771 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002773 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 (len +
2775 1),
2776 GFP_KERNEL);
2777 cifs_strfromUCS_le
Steve Frenche89dc922005-11-11 15:18:19 -08002778 (ses->serverDomain,
2779 (__le16 *)bcc_ptr,
2780 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 bcc_ptr +=
2782 2 * (len + 1);
Steve Frenche89dc922005-11-11 15:18:19 -08002783 ses->serverDomain[2*len]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784 = 0;
Steve Frenche89dc922005-11-11 15:18:19 -08002785 ses->serverDomain
2786 [1 + (2 * len)]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787 = 0;
2788 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002789 else {
Steve Frenchcd49b492006-06-26 04:22:36 +00002790 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002792 kzalloc(2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793 GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002794 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795 } else { /* no room so create dummy domain and NOS string */
Steve Frenchcd49b492006-06-26 04:22:36 +00002796 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002798 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002799 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002801 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 }
2803 } else { /* ASCII */
2804 len = strnlen(bcc_ptr, 1024);
2805 if (((long) bcc_ptr + len) - (long)
2806 pByteArea(smb_buffer_response)
2807 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002808 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002809 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002811 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812 GFP_KERNEL);
2813 strncpy(ses->serverOS,
2814 bcc_ptr, len);
2815
2816 bcc_ptr += len;
2817 bcc_ptr[0] = 0; /* null terminate string */
2818 bcc_ptr++;
2819
2820 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002821 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002823 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824 GFP_KERNEL);
2825 strncpy(ses->serverNOS, bcc_ptr, len);
2826 bcc_ptr += len;
2827 bcc_ptr[0] = 0;
2828 bcc_ptr++;
2829
2830 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002831 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002833 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +00002835 strncpy(ses->serverDomain,
2836 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 bcc_ptr += len;
2838 bcc_ptr[0] = 0;
2839 bcc_ptr++;
2840 } else
2841 cFYI(1,
Steve French63135e02007-07-17 17:34:02 +00002842 ("field of length %d "
2843 "extends beyond end of smb",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844 len));
2845 }
2846 } else {
Steve French50c2f752007-07-13 00:33:32 +00002847 cERROR(1, ("Security Blob Length extends beyond"
2848 " end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849 }
2850 } else {
2851 cERROR(1, ("No session structure passed in."));
2852 }
2853 } else {
2854 cERROR(1,
Steve French5815449d2006-02-14 01:36:20 +00002855 (" Invalid Word count %d:",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856 smb_buffer_response->WordCount));
2857 rc = -EIO;
2858 }
2859
2860 if (smb_buffer)
2861 cifs_buf_release(smb_buffer);
2862
2863 return rc;
2864}
2865static int
2866CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
2867 char *ntlm_session_key, int ntlmv2_flag,
2868 const struct nls_table *nls_codepage)
2869{
2870 struct smb_hdr *smb_buffer;
2871 struct smb_hdr *smb_buffer_response;
2872 SESSION_SETUP_ANDX *pSMB;
2873 SESSION_SETUP_ANDX *pSMBr;
2874 char *bcc_ptr;
2875 char *user;
2876 char *domain;
2877 int rc = 0;
2878 int remaining_words = 0;
2879 int bytes_returned = 0;
2880 int len;
2881 int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
2882 PAUTHENTICATE_MESSAGE SecurityBlob;
2883 __u32 negotiate_flags, capabilities;
2884 __u16 count;
2885
2886 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002887 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888 return -EINVAL;
2889 user = ses->userName;
2890 domain = ses->domainName;
2891 smb_buffer = cifs_buf_get();
2892 if (smb_buffer == NULL) {
2893 return -ENOMEM;
2894 }
2895 smb_buffer_response = smb_buffer;
2896 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2897 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2898
2899 /* send SMBsessionSetup here */
2900 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2901 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002902
2903 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2905 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2906 pSMB->req.AndXCommand = 0xFF;
2907 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2908 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2909
2910 pSMB->req.hdr.Uid = ses->Suid;
2911
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002912 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2914
2915 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2916 CAP_EXTENDED_SECURITY;
2917 if (ses->capabilities & CAP_UNICODE) {
2918 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2919 capabilities |= CAP_UNICODE;
2920 }
2921 if (ses->capabilities & CAP_STATUS32) {
2922 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2923 capabilities |= CAP_STATUS32;
2924 }
2925 if (ses->capabilities & CAP_DFS) {
2926 smb_buffer->Flags2 |= SMBFLG2_DFS;
2927 capabilities |= CAP_DFS;
2928 }
2929 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2930
2931 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2932 SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
2933 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2934 SecurityBlob->MessageType = NtLmAuthenticate;
2935 bcc_ptr += SecurityBlobLength;
Steve French50c2f752007-07-13 00:33:32 +00002936 negotiate_flags =
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2938 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2939 0x80000000 | NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002940 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002941 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002942 if (ntlmv2_flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2944
2945/* setup pointers to domain name and workstation name */
2946
2947 SecurityBlob->WorkstationName.Buffer = 0;
2948 SecurityBlob->WorkstationName.Length = 0;
2949 SecurityBlob->WorkstationName.MaximumLength = 0;
2950 SecurityBlob->SessionKey.Length = 0;
2951 SecurityBlob->SessionKey.MaximumLength = 0;
2952 SecurityBlob->SessionKey.Buffer = 0;
2953
2954 SecurityBlob->LmChallengeResponse.Length = 0;
2955 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2956 SecurityBlob->LmChallengeResponse.Buffer = 0;
2957
2958 SecurityBlob->NtChallengeResponse.Length =
Steve French7c7b25b2006-06-01 19:20:10 +00002959 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 SecurityBlob->NtChallengeResponse.MaximumLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002961 cpu_to_le16(CIFS_SESS_KEY_SIZE);
2962 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963 SecurityBlob->NtChallengeResponse.Buffer =
2964 cpu_to_le32(SecurityBlobLength);
Steve French7c7b25b2006-06-01 19:20:10 +00002965 SecurityBlobLength += CIFS_SESS_KEY_SIZE;
2966 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967
2968 if (ses->capabilities & CAP_UNICODE) {
2969 if (domain == NULL) {
2970 SecurityBlob->DomainName.Buffer = 0;
2971 SecurityBlob->DomainName.Length = 0;
2972 SecurityBlob->DomainName.MaximumLength = 0;
2973 } else {
Steve French77159b42007-08-31 01:10:17 +00002974 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00002976 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00002978 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979 SecurityBlob->DomainName.Buffer =
2980 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00002981 bcc_ptr += ln;
2982 SecurityBlobLength += ln;
2983 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 }
2985 if (user == NULL) {
2986 SecurityBlob->UserName.Buffer = 0;
2987 SecurityBlob->UserName.Length = 0;
2988 SecurityBlob->UserName.MaximumLength = 0;
2989 } else {
Steve French77159b42007-08-31 01:10:17 +00002990 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00002992 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993 SecurityBlob->UserName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00002994 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995 SecurityBlob->UserName.Buffer =
2996 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00002997 bcc_ptr += ln;
2998 SecurityBlobLength += ln;
2999 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003000 }
3001
Steve French63135e02007-07-17 17:34:02 +00003002 /* SecurityBlob->WorkstationName.Length =
3003 cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004 SecurityBlob->WorkstationName.Length *= 2;
Steve French63135e02007-07-17 17:34:02 +00003005 SecurityBlob->WorkstationName.MaximumLength =
3006 cpu_to_le16(SecurityBlob->WorkstationName.Length);
3007 SecurityBlob->WorkstationName.Buffer =
3008 cpu_to_le32(SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009 bcc_ptr += SecurityBlob->WorkstationName.Length;
3010 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
Steve French63135e02007-07-17 17:34:02 +00003011 SecurityBlob->WorkstationName.Length =
3012 cpu_to_le16(SecurityBlob->WorkstationName.Length); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013
3014 if ((long) bcc_ptr % 2) {
3015 *bcc_ptr = 0;
3016 bcc_ptr++;
3017 }
3018 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003019 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020 32, nls_codepage);
3021 bcc_ptr += 2 * bytes_returned;
3022 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003023 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 nls_codepage);
3025 bcc_ptr += 2 * bytes_returned;
3026 bcc_ptr += 2; /* null term version string */
3027 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003028 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029 64, nls_codepage);
3030 bcc_ptr += 2 * bytes_returned;
3031 *(bcc_ptr + 1) = 0;
3032 *(bcc_ptr + 2) = 0;
3033 bcc_ptr += 2; /* null terminate network opsys string */
3034 *(bcc_ptr + 1) = 0;
3035 *(bcc_ptr + 2) = 0;
3036 bcc_ptr += 2; /* null domain */
3037 } else { /* ASCII */
3038 if (domain == NULL) {
3039 SecurityBlob->DomainName.Buffer = 0;
3040 SecurityBlob->DomainName.Length = 0;
3041 SecurityBlob->DomainName.MaximumLength = 0;
3042 } else {
Steve French77159b42007-08-31 01:10:17 +00003043 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
3045 strncpy(bcc_ptr, domain, 63);
Steve French77159b42007-08-31 01:10:17 +00003046 ln = strnlen(domain, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003047 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003048 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003049 SecurityBlob->DomainName.Buffer =
3050 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003051 bcc_ptr += ln;
3052 SecurityBlobLength += ln;
3053 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054 }
3055 if (user == NULL) {
3056 SecurityBlob->UserName.Buffer = 0;
3057 SecurityBlob->UserName.Length = 0;
3058 SecurityBlob->UserName.MaximumLength = 0;
3059 } else {
Steve French77159b42007-08-31 01:10:17 +00003060 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061 strncpy(bcc_ptr, user, 63);
Steve French77159b42007-08-31 01:10:17 +00003062 ln = strnlen(user, 64);
3063 SecurityBlob->UserName.MaximumLength = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 SecurityBlob->UserName.Buffer =
Steve French77159b42007-08-31 01:10:17 +00003065 cpu_to_le32(SecurityBlobLength);
3066 bcc_ptr += ln;
3067 SecurityBlobLength += ln;
3068 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069 }
3070 /* BB fill in our workstation name if known BB */
3071
3072 strcpy(bcc_ptr, "Linux version ");
3073 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003074 strcpy(bcc_ptr, utsname()->release);
3075 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003076 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
3077 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
3078 bcc_ptr++; /* null domain */
3079 *bcc_ptr = 0;
3080 }
3081 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
3082 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
3083 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
3084 smb_buffer->smb_buf_length += count;
3085 pSMB->req.ByteCount = cpu_to_le16(count);
3086
3087 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
3088 &bytes_returned, 1);
3089 if (rc) {
3090/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
3091 } else if ((smb_buffer_response->WordCount == 3)
3092 || (smb_buffer_response->WordCount == 4)) {
3093 __u16 action = le16_to_cpu(pSMBr->resp.Action);
3094 __u16 blob_len =
3095 le16_to_cpu(pSMBr->resp.SecurityBlobLength);
3096 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00003097 cFYI(1, (" Guest login")); /* BB Should we set anything
3098 in SesInfo struct ? */
3099/* if (SecurityBlob2->MessageType != NtLm??) {
3100 cFYI("Unexpected message type on auth response is %d"));
3101 } */
3102
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103 if (ses) {
3104 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003105 ("Check challenge UID %d vs auth response UID %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003106 ses->Suid, smb_buffer_response->Uid));
Steve French50c2f752007-07-13 00:33:32 +00003107 /* UID left in wire format */
3108 ses->Suid = smb_buffer_response->Uid;
3109 bcc_ptr = pByteArea(smb_buffer_response);
3110 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111 if ((pSMBr->resp.hdr.WordCount == 3)
3112 || ((pSMBr->resp.hdr.WordCount == 4)
3113 && (blob_len <
3114 pSMBr->resp.ByteCount))) {
3115 if (pSMBr->resp.hdr.WordCount == 4) {
3116 bcc_ptr +=
3117 blob_len;
3118 cFYI(1,
3119 ("Security Blob Length %d ",
3120 blob_len));
3121 }
3122
3123 cFYI(1,
3124 ("NTLMSSP response to Authenticate "));
3125
3126 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3127 if ((long) (bcc_ptr) % 2) {
3128 remaining_words =
3129 (BCC(smb_buffer_response)
3130 - 1) / 2;
3131 bcc_ptr++; /* Unicode strings must be word aligned */
3132 } else {
3133 remaining_words = BCC(smb_buffer_response) / 2;
3134 }
Steve French77159b42007-08-31 01:10:17 +00003135 len = UniStrnlen((wchar_t *) bcc_ptr,
3136 remaining_words - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137/* We look for obvious messed up bcc or strings in response so we do not go off
3138 the end since (at least) WIN2K and Windows XP have a major bug in not null
3139 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003140 if (ses->serverOS)
Steve French08775832006-05-30 18:08:26 +00003141 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003143 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003145 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146 bcc_ptr, len,
3147 nls_codepage);
3148 bcc_ptr += 2 * (len + 1);
3149 remaining_words -= len + 1;
3150 ses->serverOS[2 * len] = 0;
3151 ses->serverOS[1 + (2 * len)] = 0;
3152 if (remaining_words > 0) {
3153 len = UniStrnlen((wchar_t *)
3154 bcc_ptr,
3155 remaining_words
3156 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00003157 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003159 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160 GFP_KERNEL);
3161 cifs_strfromUCS_le(ses->
3162 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003163 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164 bcc_ptr,
3165 len,
3166 nls_codepage);
3167 bcc_ptr += 2 * (len + 1);
3168 ses->serverNOS[2 * len] = 0;
3169 ses->serverNOS[1+(2*len)] = 0;
3170 remaining_words -= len + 1;
3171 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00003172 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173 /* last string not always null terminated (e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003174 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003175 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003177 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003178 (len +
3179 1),
3180 GFP_KERNEL);
3181 cifs_strfromUCS_le
3182 (ses->
3183 serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08003184 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185 bcc_ptr, len,
3186 nls_codepage);
3187 bcc_ptr +=
3188 2 * (len + 1);
3189 ses->
3190 serverDomain[2
3191 * len]
3192 = 0;
3193 ses->
3194 serverDomain[1
3195 +
3196 (2
3197 *
3198 len)]
3199 = 0;
3200 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003201 else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003202 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003203 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003204 ses->serverDomain = kzalloc(2,GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00003205 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003206 } else { /* no room so create dummy domain and NOS string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003207 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003208 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003209 ses->serverDomain = kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00003210 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003211 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212 }
3213 } else { /* ASCII */
3214 len = strnlen(bcc_ptr, 1024);
Steve French50c2f752007-07-13 00:33:32 +00003215 if (((long) bcc_ptr + len) -
3216 (long) pByteArea(smb_buffer_response)
Steve French63135e02007-07-17 17:34:02 +00003217 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003218 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00003219 kfree(ses->serverOS);
Steve French77159b42007-08-31 01:10:17 +00003220 ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003221 strncpy(ses->serverOS,bcc_ptr, len);
3222
3223 bcc_ptr += len;
3224 bcc_ptr[0] = 0; /* null terminate the string */
3225 bcc_ptr++;
3226
3227 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003228 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00003229 ses->serverNOS = kzalloc(len+1,
3230 GFP_KERNEL);
Steve French63135e02007-07-17 17:34:02 +00003231 strncpy(ses->serverNOS,
3232 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233 bcc_ptr += len;
3234 bcc_ptr[0] = 0;
3235 bcc_ptr++;
3236
3237 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003238 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003239 kfree(ses->serverDomain);
Steve French63135e02007-07-17 17:34:02 +00003240 ses->serverDomain =
3241 kzalloc(len+1,
3242 GFP_KERNEL);
3243 strncpy(ses->serverDomain,
3244 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003245 bcc_ptr += len;
3246 bcc_ptr[0] = 0;
3247 bcc_ptr++;
3248 } else
3249 cFYI(1,
Steve French63135e02007-07-17 17:34:02 +00003250 ("field of length %d "
3251 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003252 len));
3253 }
3254 } else {
3255 cERROR(1,
Steve French63135e02007-07-17 17:34:02 +00003256 (" Security Blob extends beyond end "
3257 "of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258 }
3259 } else {
3260 cERROR(1, ("No session structure passed in."));
3261 }
3262 } else {
3263 cERROR(1,
3264 (" Invalid Word count %d: ",
3265 smb_buffer_response->WordCount));
3266 rc = -EIO;
3267 }
3268
3269 if (smb_buffer)
3270 cifs_buf_release(smb_buffer);
3271
3272 return rc;
3273}
3274
3275int
3276CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3277 const char *tree, struct cifsTconInfo *tcon,
3278 const struct nls_table *nls_codepage)
3279{
3280 struct smb_hdr *smb_buffer;
3281 struct smb_hdr *smb_buffer_response;
3282 TCONX_REQ *pSMB;
3283 TCONX_RSP *pSMBr;
3284 unsigned char *bcc_ptr;
3285 int rc = 0;
3286 int length;
3287 __u16 count;
3288
3289 if (ses == NULL)
3290 return -EIO;
3291
3292 smb_buffer = cifs_buf_get();
3293 if (smb_buffer == NULL) {
3294 return -ENOMEM;
3295 }
3296 smb_buffer_response = smb_buffer;
3297
3298 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3299 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003300
3301 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302 smb_buffer->Uid = ses->Suid;
3303 pSMB = (TCONX_REQ *) smb_buffer;
3304 pSMBr = (TCONX_RSP *) smb_buffer_response;
3305
3306 pSMB->AndXCommand = 0xFF;
3307 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308 bcc_ptr = &pSMB->Password[0];
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003309 if ((ses->server->secMode) & SECMODE_USER) {
Steve Frencheeac8042006-01-13 21:34:58 -08003310 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00003311 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08003312 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00003313 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08003314 } else {
Steve French7c7b25b2006-06-01 19:20:10 +00003315 pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08003316 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
3317 specified as required (when that support is added to
3318 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00003319 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08003320 by Samba (not sure whether other servers allow
3321 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00003322#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French50c2f752007-07-13 00:33:32 +00003323 if ((extended_security & CIFSSEC_MAY_LANMAN) &&
Steve French7c7b25b2006-06-01 19:20:10 +00003324 (ses->server->secType == LANMAN))
3325 calc_lanman_hash(ses, bcc_ptr);
3326 else
3327#endif /* CIFS_WEAK_PW_HASH */
Steve Frencheeac8042006-01-13 21:34:58 -08003328 SMBNTencrypt(ses->password,
3329 ses->server->cryptKey,
3330 bcc_ptr);
3331
Steve French7c7b25b2006-06-01 19:20:10 +00003332 bcc_ptr += CIFS_SESS_KEY_SIZE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003333 if (ses->capabilities & CAP_UNICODE) {
Steve French7c7b25b2006-06-01 19:20:10 +00003334 /* must align unicode strings */
3335 *bcc_ptr = 0; /* null byte password */
3336 bcc_ptr++;
3337 }
Steve Frencheeac8042006-01-13 21:34:58 -08003338 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339
Steve French50c2f752007-07-13 00:33:32 +00003340 if (ses->server->secMode &
Steve Frencha878fb22006-05-30 18:04:19 +00003341 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003342 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3343
3344 if (ses->capabilities & CAP_STATUS32) {
3345 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3346 }
3347 if (ses->capabilities & CAP_DFS) {
3348 smb_buffer->Flags2 |= SMBFLG2_DFS;
3349 }
3350 if (ses->capabilities & CAP_UNICODE) {
3351 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3352 length =
Steve French50c2f752007-07-13 00:33:32 +00003353 cifs_strtoUCS((__le16 *) bcc_ptr, tree,
3354 6 /* max utf8 char length in bytes */ *
Steve Frencha878fb22006-05-30 18:04:19 +00003355 (/* server len*/ + 256 /* share len */), nls_codepage);
3356 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003357 bcc_ptr += 2; /* skip trailing null */
3358 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359 strcpy(bcc_ptr, tree);
3360 bcc_ptr += strlen(tree) + 1;
3361 }
3362 strcpy(bcc_ptr, "?????");
3363 bcc_ptr += strlen("?????");
3364 bcc_ptr += 1;
3365 count = bcc_ptr - &pSMB->Password[0];
3366 pSMB->hdr.smb_buf_length += count;
3367 pSMB->ByteCount = cpu_to_le16(count);
3368
3369 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
3370
3371 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3372 /* above now done in SendReceive */
3373 if ((rc == 0) && (tcon != NULL)) {
3374 tcon->tidStatus = CifsGood;
3375 tcon->tid = smb_buffer_response->Tid;
3376 bcc_ptr = pByteArea(smb_buffer_response);
3377 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
Steve French50c2f752007-07-13 00:33:32 +00003378 /* skip service field (NB: this field is always ASCII) */
3379 bcc_ptr += length + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3381 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3382 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3383 if ((bcc_ptr + (2 * length)) -
3384 pByteArea(smb_buffer_response) <=
3385 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003386 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003388 kzalloc(length + 2, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003389 if (tcon->nativeFileSystem)
3390 cifs_strfromUCS_le(
3391 tcon->nativeFileSystem,
3392 (__le16 *) bcc_ptr,
3393 length, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394 bcc_ptr += 2 * length;
3395 bcc_ptr[0] = 0; /* null terminate the string */
3396 bcc_ptr[1] = 0;
3397 bcc_ptr += 2;
3398 }
Steve French50c2f752007-07-13 00:33:32 +00003399 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 } else {
3401 length = strnlen(bcc_ptr, 1024);
3402 if ((bcc_ptr + length) -
3403 pByteArea(smb_buffer_response) <=
3404 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003405 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003407 kzalloc(length + 1, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003408 if (tcon->nativeFileSystem)
3409 strncpy(tcon->nativeFileSystem, bcc_ptr,
3410 length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411 }
Steve French50c2f752007-07-13 00:33:32 +00003412 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003413 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003414 if ((smb_buffer_response->WordCount == 3) ||
Steve French1a4e15a2006-10-12 21:33:51 +00003415 (smb_buffer_response->WordCount == 7))
3416 /* field is in same location */
Steve French39798772006-05-31 22:40:51 +00003417 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3418 else
3419 tcon->Flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3421 } else if ((rc == 0) && tcon == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00003422 /* all we need to save for IPC$ connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423 ses->ipc_tid = smb_buffer_response->Tid;
3424 }
3425
3426 if (smb_buffer)
3427 cifs_buf_release(smb_buffer);
3428 return rc;
3429}
3430
3431int
3432cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3433{
3434 int rc = 0;
3435 int xid;
3436 struct cifsSesInfo *ses = NULL;
3437 struct task_struct *cifsd_task;
Steve French50c2f752007-07-13 00:33:32 +00003438 char *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439
3440 xid = GetXid();
3441
3442 if (cifs_sb->tcon) {
3443 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3444 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3445 if (rc == -EBUSY) {
3446 FreeXid(xid);
3447 return 0;
3448 }
3449 tconInfoFree(cifs_sb->tcon);
3450 if ((ses) && (ses->server)) {
3451 /* save off task so we do not refer to ses later */
3452 cifsd_task = ses->server->tsk;
3453 cFYI(1, ("About to do SMBLogoff "));
3454 rc = CIFSSMBLogoff(xid, ses);
3455 if (rc == -EBUSY) {
3456 FreeXid(xid);
3457 return 0;
3458 } else if (rc == -ESHUTDOWN) {
Steve French467a8f82007-06-27 22:41:32 +00003459 cFYI(1, ("Waking up socket by sending signal"));
Steve Frenchf7f7c312007-05-24 02:29:51 +00003460 if (cifsd_task) {
Steve French50c2f752007-07-13 00:33:32 +00003461 force_sig(SIGKILL, cifsd_task);
Igor Mammedovaaf737a2007-04-03 19:16:43 +00003462 kthread_stop(cifsd_task);
Steve Frenchf1914012005-08-18 09:37:34 -07003463 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464 rc = 0;
3465 } /* else - we have an smb session
3466 left on this socket do not kill cifsd */
3467 } else
3468 cFYI(1, ("No session or bad tcon"));
3469 }
Steve French50c2f752007-07-13 00:33:32 +00003470
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471 cifs_sb->tcon = NULL;
Steve French2fe87f02006-09-21 07:02:52 +00003472 tmp = cifs_sb->prepath;
3473 cifs_sb->prepathlen = 0;
3474 cifs_sb->prepath = NULL;
3475 kfree(tmp);
Nishanth Aravamudan041e0e32005-09-10 00:27:23 -07003476 if (ses)
3477 schedule_timeout_interruptible(msecs_to_jiffies(500));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478 if (ses)
3479 sesInfoFree(ses);
3480
3481 FreeXid(xid);
Steve French50c2f752007-07-13 00:33:32 +00003482 return rc; /* BB check if we should always return zero here */
3483}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484
3485int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
Steve French50c2f752007-07-13 00:33:32 +00003486 struct nls_table *nls_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487{
3488 int rc = 0;
Steve French7c7b25b2006-06-01 19:20:10 +00003489 char ntlm_session_key[CIFS_SESS_KEY_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490 int ntlmv2_flag = FALSE;
Steve Frenchad009ac2005-04-28 22:41:05 -07003491 int first_time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492
3493 /* what if server changes its buffer size after dropping the session? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003494 if (pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003496 if (rc == -EAGAIN) /* retry only once on 1st time connection */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve French50c2f752007-07-13 00:33:32 +00003498 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499 rc = -EHOSTDOWN;
3500 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003501 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502 spin_lock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003503 if (pSesInfo->server->tcpStatus != CifsExiting)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504 pSesInfo->server->tcpStatus = CifsGood;
3505 else
3506 rc = -EHOSTDOWN;
3507 spin_unlock(&GlobalMid_Lock);
3508
3509 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003510 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003511 }
3512 if (!rc) {
Steve French9ac00b72006-09-30 04:13:17 +00003513 pSesInfo->flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514 pSesInfo->capabilities = pSesInfo->server->capabilities;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003515 if (linuxExtEnabled == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003517 /* pSesInfo->sequence_number = 0;*/
Steve French50c2f752007-07-13 00:33:32 +00003518 cFYI(1,
3519 ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520 pSesInfo->server->secMode,
3521 pSesInfo->server->capabilities,
Steve French175ec9e2006-09-30 01:07:38 +00003522 pSesInfo->server->timeAdj));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003523 if (experimEnabled < 2)
Steve French39798772006-05-31 22:40:51 +00003524 rc = CIFS_SessSetup(xid, pSesInfo,
3525 first_time, nls_info);
Steve French189acaa2006-06-23 02:33:48 +00003526 else if (extended_security
Steve French50c2f752007-07-13 00:33:32 +00003527 && (pSesInfo->capabilities
Steve French175ec9e2006-09-30 01:07:38 +00003528 & CAP_EXTENDED_SECURITY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003529 && (pSesInfo->server->secType == NTLMSSP)) {
Steve French189acaa2006-06-23 02:33:48 +00003530 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531 } else if (extended_security
3532 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3533 && (pSesInfo->server->secType == RawNTLMSSP)) {
Steve French5815449d2006-02-14 01:36:20 +00003534 cFYI(1, ("NTLMSSP sesssetup"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3536 pSesInfo,
3537 &ntlmv2_flag,
3538 nls_info);
3539 if (!rc) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003540 if (ntlmv2_flag) {
Steve French50c2f752007-07-13 00:33:32 +00003541 char *v2_response;
Steve French467a8f82007-06-27 22:41:32 +00003542 cFYI(1, ("more secure NTLM ver2 hash"));
Steve French50c2f752007-07-13 00:33:32 +00003543 if (CalcNTLMv2_partial_mac_key(pSesInfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544 nls_info)) {
3545 rc = -ENOMEM;
3546 goto ss_err_exit;
3547 } else
3548 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003549 if (v2_response) {
Steve French50c2f752007-07-13 00:33:32 +00003550 CalcNTLMv2_response(pSesInfo,
3551 v2_response);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003552 /* if (first_time)
Steve French50c2f752007-07-13 00:33:32 +00003553 cifs_calculate_ntlmv2_mac_key(
3554 pSesInfo->server->mac_signing_key,
3555 response, ntlm_session_key,*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003556 kfree(v2_response);
3557 /* BB Put dummy sig in SessSetup PDU? */
3558 } else {
3559 rc = -ENOMEM;
3560 goto ss_err_exit;
3561 }
3562
3563 } else {
3564 SMBNTencrypt(pSesInfo->password,
3565 pSesInfo->server->cryptKey,
3566 ntlm_session_key);
3567
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003568 if (first_time)
Steve Frenchad009ac2005-04-28 22:41:05 -07003569 cifs_calculate_mac_key(
Steve Frenchb609f062007-07-09 07:55:14 +00003570 &pSesInfo->server->mac_signing_key,
Steve Frenchad009ac2005-04-28 22:41:05 -07003571 ntlm_session_key,
3572 pSesInfo->password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003573 }
3574 /* for better security the weaker lanman hash not sent
3575 in AuthSessSetup so we no longer calculate it */
3576
3577 rc = CIFSNTLMSSPAuthSessSetup(xid,
3578 pSesInfo,
3579 ntlm_session_key,
3580 ntlmv2_flag,
3581 nls_info);
3582 }
3583 } else { /* old style NTLM 0.12 session setup */
3584 SMBNTencrypt(pSesInfo->password,
3585 pSesInfo->server->cryptKey,
3586 ntlm_session_key);
3587
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003588 if (first_time)
Steve Frenchad009ac2005-04-28 22:41:05 -07003589 cifs_calculate_mac_key(
Steve Frenchb609f062007-07-09 07:55:14 +00003590 &pSesInfo->server->mac_signing_key,
Steve Frenchad009ac2005-04-28 22:41:05 -07003591 ntlm_session_key, pSesInfo->password);
3592
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593 rc = CIFSSessSetup(xid, pSesInfo,
3594 ntlm_session_key, nls_info);
3595 }
3596 if (rc) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003597 cERROR(1, ("Send error in SessSetup = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598 } else {
Steve French467a8f82007-06-27 22:41:32 +00003599 cFYI(1, ("CIFS Session Established successfully"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600 pSesInfo->status = CifsGood;
3601 }
3602 }
3603ss_err_exit:
3604 return rc;
3605}
3606