blob: c52a76ff4bb9db8c2625ed6213dc0a8b026664d6 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/connect.c
3 *
Steve French75865f82007-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));
Trond Myklebust91cf45f2007-11-12 18:10:39 -0800163 kernel_sock_shutdown(server->ssocket, SHUT_WR);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000164 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 */
Pavel Emelyanovba25f9d2007-10-18 23:40:40 -0700354 cFYI(1, ("Demultiplex PID: %d", task_pid_nr(current)));
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 */
Steve Frenchc18c7322007-10-17 18:01:11 +0000418 if (pdu_length < 4)
419 goto incomplete_rcv;
420 else
421 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 } else if (length <= 0) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000423 if (server->tcpStatus == CifsNew) {
424 cFYI(1, ("tcp session abend after SMBnegprot"));
Steve French09d1db52005-04-28 22:41:08 -0700425 /* some servers kill the TCP session rather than
426 returning an SMB negprot error, in which
427 case reconnecting here is not going to help,
428 and so simply return error to mount */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 break;
430 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000431 if (!try_to_freeze() && (length == -EINTR)) {
Steve French467a8f82007-06-27 22:41:32 +0000432 cFYI(1, ("cifsd thread killed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 break;
434 }
Steve French467a8f82007-06-27 22:41:32 +0000435 cFYI(1, ("Reconnect after unexpected peek error %d",
Steve French57337e42005-04-28 22:41:10 -0700436 length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 cifs_reconnect(server);
438 csocket = server->ssocket;
439 wake_up(&server->response_q);
440 continue;
Steve French46810cb2005-04-28 22:41:09 -0700441 } else if (length < 4) {
Steve Frenchf01d5e12007-08-30 21:13:31 +0000442 cFYI(1, ("less than four bytes received (%d bytes)",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 length));
Steve Frenchf01d5e12007-08-30 21:13:31 +0000444 pdu_length -= length;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000445 msleep(1);
446 goto incomplete_rcv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 }
Steve French67010fb2005-04-28 22:41:09 -0700448
Steve French70ca7342005-09-22 16:32:06 -0700449 /* The right amount was read from socket - 4 bytes */
450 /* so we can now interpret the length field */
Steve French46810cb2005-04-28 22:41:09 -0700451
Steve French70ca7342005-09-22 16:32:06 -0700452 /* the first byte big endian of the length field,
453 is actually not part of the length but the type
454 with the most common, zero, as regular data */
455 temp = *((char *) smb_buffer);
456
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000457 /* Note that FC 1001 length is big endian on the wire,
Steve French70ca7342005-09-22 16:32:06 -0700458 but we convert it here so it is always manipulated
459 as host byte order */
Steve French46810cb2005-04-28 22:41:09 -0700460 pdu_length = ntohl(smb_buffer->smb_buf_length);
Steve French70ca7342005-09-22 16:32:06 -0700461 smb_buffer->smb_buf_length = pdu_length;
Steve French46810cb2005-04-28 22:41:09 -0700462
Steve French467a8f82007-06-27 22:41:32 +0000463 cFYI(1, ("rfc1002 length 0x%x", pdu_length+4));
Steve French70ca7342005-09-22 16:32:06 -0700464
465 if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000466 continue;
Steve French70ca7342005-09-22 16:32:06 -0700467 } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
Steve French467a8f82007-06-27 22:41:32 +0000468 cFYI(1, ("Good RFC 1002 session rsp"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700469 continue;
Steve French70ca7342005-09-22 16:32:06 -0700470 } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000471 /* we get this from Windows 98 instead of
Steve French46810cb2005-04-28 22:41:09 -0700472 an error on SMB negprot response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000473 cFYI(1, ("Negative RFC1002 Session Response Error 0x%x)",
Steve French70ca7342005-09-22 16:32:06 -0700474 pdu_length));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000475 if (server->tcpStatus == CifsNew) {
476 /* if nack on negprot (rather than
Steve French46810cb2005-04-28 22:41:09 -0700477 ret of smb negprot error) reconnecting
478 not going to help, ret error to mount */
479 break;
480 } else {
481 /* give server a second to
482 clean up before reconnect attempt */
483 msleep(1000);
484 /* always try 445 first on reconnect
485 since we get NACK on some if we ever
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000486 connected to port 139 (the NACK is
Steve French46810cb2005-04-28 22:41:09 -0700487 since we do not begin with RFC1001
488 session initialize frame) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000489 server->addr.sockAddr.sin_port =
Steve French46810cb2005-04-28 22:41:09 -0700490 htons(CIFS_PORT);
491 cifs_reconnect(server);
492 csocket = server->ssocket;
493 wake_up(&server->response_q);
494 continue;
495 }
Steve French70ca7342005-09-22 16:32:06 -0700496 } else if (temp != (char) 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000497 cERROR(1, ("Unknown RFC 1002 frame"));
Steve French70ca7342005-09-22 16:32:06 -0700498 cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
499 length);
Steve French46810cb2005-04-28 22:41:09 -0700500 cifs_reconnect(server);
501 csocket = server->ssocket;
502 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700503 }
504
505 /* else we have an SMB response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000506 if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French26f57362007-08-30 22:09:15 +0000507 (pdu_length < sizeof(struct smb_hdr) - 1 - 4)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700508 cERROR(1, ("Invalid size SMB length %d pdu_length %d",
Steve French46810cb2005-04-28 22:41:09 -0700509 length, pdu_length+4));
Steve Frenche4eb2952005-04-28 22:41:09 -0700510 cifs_reconnect(server);
511 csocket = server->ssocket;
512 wake_up(&server->response_q);
513 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000514 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700515
516 /* else length ok */
517 reconnect = 0;
518
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000519 if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700520 isLargeBuf = TRUE;
521 memcpy(bigbuf, smallbuf, 4);
522 smb_buffer = bigbuf;
523 }
524 length = 0;
525 iov.iov_base = 4 + (char *)smb_buffer;
526 iov.iov_len = pdu_length;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000527 for (total_read = 0; total_read < pdu_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700528 total_read += length) {
529 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
530 pdu_length - total_read, 0);
Steve French26f57362007-08-30 22:09:15 +0000531 if (kthread_should_stop() ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700532 (length == -EINTR)) {
533 /* then will exit */
534 reconnect = 2;
535 break;
536 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700537 cifs_reconnect(server);
538 csocket = server->ssocket;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000539 /* Reconnect wakes up rspns q */
Steve Frenche4eb2952005-04-28 22:41:09 -0700540 /* Now we will reread sock */
541 reconnect = 1;
542 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000543 } else if ((length == -ERESTARTSYS) ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700544 (length == -EAGAIN)) {
545 msleep(1); /* minimum sleep to prevent looping,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000546 allowing socket to clear and app
Steve Frenche4eb2952005-04-28 22:41:09 -0700547 threads to set tcpStatus
548 CifsNeedReconnect if server hung*/
Steve Frenchc18c7322007-10-17 18:01:11 +0000549 length = 0;
Steve French46810cb2005-04-28 22:41:09 -0700550 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700551 } else if (length <= 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000552 cERROR(1, ("Received no data, expecting %d",
Steve Frenche4eb2952005-04-28 22:41:09 -0700553 pdu_length - total_read));
554 cifs_reconnect(server);
555 csocket = server->ssocket;
556 reconnect = 1;
557 break;
Steve French46810cb2005-04-28 22:41:09 -0700558 }
559 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000560 if (reconnect == 2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700561 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000562 else if (reconnect == 1)
Steve Frenche4eb2952005-04-28 22:41:09 -0700563 continue;
564
565 length += 4; /* account for rfc1002 hdr */
Steve French50c2f752007-07-13 00:33:32 +0000566
Steve Frenche4eb2952005-04-28 22:41:09 -0700567
568 dump_smb(smb_buffer, length);
Steve French184ed212006-02-24 06:15:11 +0000569 if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700570 cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
Steve Frenche4eb2952005-04-28 22:41:09 -0700571 continue;
572 }
573
574
575 task_to_wake = NULL;
576 spin_lock(&GlobalMid_Lock);
577 list_for_each(tmp, &server->pending_mid_q) {
578 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
579
Steve French50c2f752007-07-13 00:33:32 +0000580 if ((mid_entry->mid == smb_buffer->Mid) &&
Steve Frenche4eb2952005-04-28 22:41:09 -0700581 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
582 (mid_entry->command == smb_buffer->Command)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000583 if (check2ndT2(smb_buffer,server->maxBuf) > 0) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700584 /* We have a multipart transact2 resp */
Steve Frenchcd634992005-04-28 22:41:10 -0700585 isMultiRsp = TRUE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000586 if (mid_entry->resp_buf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700587 /* merge response - fix up 1st*/
Steve French50c2f752007-07-13 00:33:32 +0000588 if (coalesce_t2(smb_buffer,
Steve Frenche4eb2952005-04-28 22:41:09 -0700589 mid_entry->resp_buf)) {
Steve French39798772006-05-31 22:40:51 +0000590 mid_entry->multiRsp = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700591 break;
592 } else {
593 /* all parts received */
Steve French39798772006-05-31 22:40:51 +0000594 mid_entry->multiEnd = 1;
Steve French50c2f752007-07-13 00:33:32 +0000595 goto multi_t2_fnd;
Steve Frenche4eb2952005-04-28 22:41:09 -0700596 }
597 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000598 if (!isLargeBuf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700599 cERROR(1,("1st trans2 resp needs bigbuf"));
600 /* BB maybe we can fix this up, switch
Steve French50c2f752007-07-13 00:33:32 +0000601 to already allocated large buffer? */
Steve Frenche4eb2952005-04-28 22:41:09 -0700602 } else {
Steve Frenchcd634992005-04-28 22:41:10 -0700603 /* Have first buffer */
Steve Frenche4eb2952005-04-28 22:41:09 -0700604 mid_entry->resp_buf =
605 smb_buffer;
606 mid_entry->largeBuf = 1;
Steve Frenche4eb2952005-04-28 22:41:09 -0700607 bigbuf = NULL;
608 }
609 }
610 break;
Steve French50c2f752007-07-13 00:33:32 +0000611 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700612 mid_entry->resp_buf = smb_buffer;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000613 if (isLargeBuf)
Steve Frenche4eb2952005-04-28 22:41:09 -0700614 mid_entry->largeBuf = 1;
615 else
616 mid_entry->largeBuf = 0;
617multi_t2_fnd:
618 task_to_wake = mid_entry->tsk;
619 mid_entry->midState = MID_RESPONSE_RECEIVED;
Steve French1047abc2005-10-11 19:58:06 -0700620#ifdef CONFIG_CIFS_STATS2
621 mid_entry->when_received = jiffies;
622#endif
Steve French3a5ff612006-07-14 22:37:11 +0000623 /* so we do not time out requests to server
624 which is still responding (since server could
625 be busy but not dead) */
626 server->lstrp = jiffies;
Steve Frenche4eb2952005-04-28 22:41:09 -0700627 break;
628 }
629 }
630 spin_unlock(&GlobalMid_Lock);
631 if (task_to_wake) {
Steve Frenchcd634992005-04-28 22:41:10 -0700632 /* Was previous buf put in mpx struct for multi-rsp? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000633 if (!isMultiRsp) {
Steve Frenchcd634992005-04-28 22:41:10 -0700634 /* smb buffer will be freed by user thread */
Steve French26f57362007-08-30 22:09:15 +0000635 if (isLargeBuf)
Steve Frenchcd634992005-04-28 22:41:10 -0700636 bigbuf = NULL;
Steve French26f57362007-08-30 22:09:15 +0000637 else
Steve Frenchcd634992005-04-28 22:41:10 -0700638 smallbuf = NULL;
639 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700640 wake_up_process(task_to_wake);
Steve Frenchd7c8c942006-03-03 10:43:49 +0000641 } else if ((is_valid_oplock_break(smb_buffer, server) == FALSE)
Steve French50c2f752007-07-13 00:33:32 +0000642 && (isMultiRsp == FALSE)) {
643 cERROR(1, ("No task to wake, unknown frame received! "
644 "NumMids %d", midCount.counter));
645 cifs_dump_mem("Received Data is: ", (char *)smb_buffer,
Steve French70ca7342005-09-22 16:32:06 -0700646 sizeof(struct smb_hdr));
Steve French39798772006-05-31 22:40:51 +0000647#ifdef CONFIG_CIFS_DEBUG2
648 cifs_dump_detail(smb_buffer);
649 cifs_dump_mids(server);
650#endif /* CIFS_DEBUG2 */
Steve French50c2f752007-07-13 00:33:32 +0000651
Steve Frenche4eb2952005-04-28 22:41:09 -0700652 }
653 } /* end while !EXITING */
654
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 spin_lock(&GlobalMid_Lock);
656 server->tcpStatus = CifsExiting;
657 server->tsk = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700658 /* check if we have blocked requests that need to free */
659 /* Note that cifs_max_pending is normally 50, but
660 can be set at module install time to as little as two */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000661 if (atomic_read(&server->inFlight) >= cifs_max_pending)
Steve French31ca3bc2005-04-28 22:41:11 -0700662 atomic_set(&server->inFlight, cifs_max_pending - 1);
663 /* We do not want to set the max_pending too low or we
664 could end up with the counter going negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +0000666 /* Although there should not be any requests blocked on
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700668 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 to the same server - they now will see the session is in exit state
670 and get out of SendReceive. */
671 wake_up_all(&server->request_q);
672 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700673 msleep(125);
Steve French50c2f752007-07-13 00:33:32 +0000674
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000675 if (server->ssocket) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 sock_release(csocket);
677 server->ssocket = NULL;
678 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700679 /* buffer usuallly freed in free_mid - need to free it here on exit */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +0000680 cifs_buf_release(bigbuf);
681 if (smallbuf) /* no sense logging a debug message if NULL */
Steve Frenchb8643e12005-04-28 22:41:07 -0700682 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683
684 read_lock(&GlobalSMBSeslock);
685 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700686 /* loop through server session structures attached to this and
687 mark them dead */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 list_for_each(tmp, &GlobalSMBSessionList) {
689 ses =
690 list_entry(tmp, struct cifsSesInfo,
691 cifsSessionList);
692 if (ses->server == server) {
693 ses->status = CifsExiting;
694 ses->server = NULL;
695 }
696 }
697 read_unlock(&GlobalSMBSeslock);
698 } else {
Steve French31ca3bc2005-04-28 22:41:11 -0700699 /* although we can not zero the server struct pointer yet,
700 since there are active requests which may depnd on them,
701 mark the corresponding SMB sessions as exiting too */
702 list_for_each(tmp, &GlobalSMBSessionList) {
703 ses = list_entry(tmp, struct cifsSesInfo,
704 cifsSessionList);
Steve French26f57362007-08-30 22:09:15 +0000705 if (ses->server == server)
Steve French31ca3bc2005-04-28 22:41:11 -0700706 ses->status = CifsExiting;
Steve French31ca3bc2005-04-28 22:41:11 -0700707 }
708
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 spin_lock(&GlobalMid_Lock);
710 list_for_each(tmp, &server->pending_mid_q) {
711 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
712 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French50c2f752007-07-13 00:33:32 +0000713 cFYI(1, ("Clearing Mid 0x%x - waking up ",
714 mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 task_to_wake = mid_entry->tsk;
Steve French26f57362007-08-30 22:09:15 +0000716 if (task_to_wake)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 wake_up_process(task_to_wake);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 }
719 }
720 spin_unlock(&GlobalMid_Lock);
721 read_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700723 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 }
725
Steve Frenchf1914012005-08-18 09:37:34 -0700726 if (!list_empty(&server->pending_mid_q)) {
Steve French50c2f752007-07-13 00:33:32 +0000727 /* mpx threads have not exited yet give them
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700729 /* due to delays on oplock break requests, we need
730 to wait at least 45 seconds before giving up
731 on a request getting a response and going ahead
732 and killing cifsd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve French31ca3bc2005-04-28 22:41:11 -0700734 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 /* if threads still have not exited they are probably never
736 coming home not much else we can do but free the memory */
737 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738
739 write_lock(&GlobalSMBSeslock);
740 atomic_dec(&tcpSesAllocCount);
741 length = tcpSesAllocCount.counter;
Steve French31ca3bc2005-04-28 22:41:11 -0700742
743 /* last chance to mark ses pointers invalid
744 if there are any pointing to this (e.g
Steve French50c2f752007-07-13 00:33:32 +0000745 if a crazy root user tried to kill cifsd
Steve French31ca3bc2005-04-28 22:41:11 -0700746 kernel thread explicitly this might happen) */
747 list_for_each(tmp, &GlobalSMBSessionList) {
748 ses = list_entry(tmp, struct cifsSesInfo,
749 cifsSessionList);
Steve French26f57362007-08-30 22:09:15 +0000750 if (ses->server == server)
Steve French31ca3bc2005-04-28 22:41:11 -0700751 ses->server = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700752 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 write_unlock(&GlobalSMBSeslock);
Steve French31ca3bc2005-04-28 22:41:11 -0700754
755 kfree(server);
Steve French26f57362007-08-30 22:09:15 +0000756 if (length > 0)
757 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
758 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +0000759
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 return 0;
761}
762
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763static int
Steve French50c2f752007-07-13 00:33:32 +0000764cifs_parse_mount_options(char *options, const char *devname,
765 struct smb_vol *vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766{
767 char *value;
768 char *data;
769 unsigned int temp_len, i, j;
770 char separator[2];
771
772 separator[0] = ',';
Steve French50c2f752007-07-13 00:33:32 +0000773 separator[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774
Linus Torvalds12e36b22006-10-13 08:09:29 -0700775 if (Local_System_Name[0] != 0)
Steve French50c2f752007-07-13 00:33:32 +0000776 memcpy(vol->source_rfc1001_name, Local_System_Name, 15);
Steve French2cd646a2006-09-28 19:43:08 +0000777 else {
Linus Torvalds12e36b22006-10-13 08:09:29 -0700778 char *nodename = utsname()->nodename;
Steve French50c2f752007-07-13 00:33:32 +0000779 int n = strnlen(nodename, 15);
780 memset(vol->source_rfc1001_name, 0x20, 15);
781 for (i = 0; i < n; i++) {
Steve French2cd646a2006-09-28 19:43:08 +0000782 /* does not have to be perfect mapping since field is
783 informational, only used for servers that do not support
784 port 445 and it can be overridden at mount time */
Linus Torvalds12e36b22006-10-13 08:09:29 -0700785 vol->source_rfc1001_name[i] = toupper(nodename[i]);
Steve French2cd646a2006-09-28 19:43:08 +0000786 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 }
788 vol->source_rfc1001_name[15] = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -0700789 /* null target name indicates to use *SMBSERVR default called name
790 if we end up sending RFC1001 session initialize */
791 vol->target_rfc1001_name[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 vol->linux_uid = current->uid; /* current->euid instead? */
793 vol->linux_gid = current->gid;
794 vol->dir_mode = S_IRWXUGO;
795 /* 2767 perms indicate mandatory locking support */
Steve French7505e052007-11-01 18:03:01 +0000796 vol->file_mode = (S_IRWXUGO | S_ISGID) & (~S_IXGRP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
798 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
799 vol->rw = TRUE;
Jeremy Allisonac670552005-06-22 17:26:35 -0700800 /* default is always to request posix paths. */
801 vol->posix_paths = 1;
802
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 if (!options)
804 return 1;
805
Steve French50c2f752007-07-13 00:33:32 +0000806 if (strncmp(options, "sep=", 4) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000807 if (options[4] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 separator[0] = options[4];
809 options += 5;
810 } else {
Steve French467a8f82007-06-27 22:41:32 +0000811 cFYI(1, ("Null separator not allowed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 }
813 }
Steve French50c2f752007-07-13 00:33:32 +0000814
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 while ((data = strsep(&options, separator)) != NULL) {
816 if (!*data)
817 continue;
818 if ((value = strchr(data, '=')) != NULL)
819 *value++ = '\0';
820
Steve French50c2f752007-07-13 00:33:32 +0000821 /* Have to parse this before we parse for "user" */
822 if (strnicmp(data, "user_xattr", 10) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 vol->no_xattr = 0;
Steve French50c2f752007-07-13 00:33:32 +0000824 } else if (strnicmp(data, "nouser_xattr", 12) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 vol->no_xattr = 1;
826 } else if (strnicmp(data, "user", 4) == 0) {
Steve French4b952a92006-10-30 21:46:13 +0000827 if (!value) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 printk(KERN_WARNING
829 "CIFS: invalid or missing username\n");
830 return 1; /* needs_arg; */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000831 } else if (!*value) {
Steve French4b952a92006-10-30 21:46:13 +0000832 /* null user, ie anonymous, authentication */
833 vol->nullauth = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 }
835 if (strnlen(value, 200) < 200) {
836 vol->username = value;
837 } else {
838 printk(KERN_WARNING "CIFS: username too long\n");
839 return 1;
840 }
841 } else if (strnicmp(data, "pass", 4) == 0) {
842 if (!value) {
843 vol->password = NULL;
844 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000845 } else if (value[0] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 /* check if string begins with double comma
847 since that would mean the password really
848 does start with a comma, and would not
849 indicate an empty string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000850 if (value[1] != separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 vol->password = NULL;
852 continue;
853 }
854 }
855 temp_len = strlen(value);
856 /* removed password length check, NTLM passwords
857 can be arbitrarily long */
858
Steve French50c2f752007-07-13 00:33:32 +0000859 /* if comma in password, the string will be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 prematurely null terminated. Commas in password are
861 specified across the cifs mount interface by a double
862 comma ie ,, and a comma used as in other cases ie ','
863 as a parameter delimiter/separator is single and due
864 to the strsep above is temporarily zeroed. */
865
866 /* NB: password legally can have multiple commas and
867 the only illegal character in a password is null */
868
Steve French50c2f752007-07-13 00:33:32 +0000869 if ((value[temp_len] == 0) &&
Steve French09d1db52005-04-28 22:41:08 -0700870 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 /* reinsert comma */
872 value[temp_len] = separator[0];
Steve French50c2f752007-07-13 00:33:32 +0000873 temp_len += 2; /* move after second comma */
874 while (value[temp_len] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 if (value[temp_len] == separator[0]) {
Steve French50c2f752007-07-13 00:33:32 +0000876 if (value[temp_len+1] ==
Steve French09d1db52005-04-28 22:41:08 -0700877 separator[0]) {
878 /* skip second comma */
879 temp_len++;
Steve French50c2f752007-07-13 00:33:32 +0000880 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 /* single comma indicating start
882 of next parm */
883 break;
884 }
885 }
886 temp_len++;
887 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000888 if (value[temp_len] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 options = NULL;
890 } else {
891 value[temp_len] = 0;
892 /* point option to start of next parm */
893 options = value + temp_len + 1;
894 }
Steve French50c2f752007-07-13 00:33:32 +0000895 /* go from value to value + temp_len condensing
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 double commas to singles. Note that this ends up
897 allocating a few bytes too many, which is ok */
Pekka Enberge915fc42005-09-06 15:18:35 -0700898 vol->password = kzalloc(temp_len, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000899 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000900 printk(KERN_WARNING "CIFS: no memory "
901 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700902 return 1;
903 }
Steve French50c2f752007-07-13 00:33:32 +0000904 for (i = 0, j = 0; i < temp_len; i++, j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 vol->password[j] = value[i];
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000906 if (value[i] == separator[0]
Steve French09d1db52005-04-28 22:41:08 -0700907 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 /* skip second comma */
909 i++;
910 }
911 }
912 vol->password[j] = 0;
913 } else {
Pekka Enberge915fc42005-09-06 15:18:35 -0700914 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000915 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000916 printk(KERN_WARNING "CIFS: no memory "
917 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700918 return 1;
919 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 strcpy(vol->password, value);
921 }
922 } else if (strnicmp(data, "ip", 2) == 0) {
923 if (!value || !*value) {
924 vol->UNCip = NULL;
925 } else if (strnlen(value, 35) < 35) {
926 vol->UNCip = value;
927 } else {
Steve French50c2f752007-07-13 00:33:32 +0000928 printk(KERN_WARNING "CIFS: ip address "
929 "too long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 return 1;
931 }
Steve French50c2f752007-07-13 00:33:32 +0000932 } else if (strnicmp(data, "sec", 3) == 0) {
933 if (!value || !*value) {
934 cERROR(1, ("no security value specified"));
935 continue;
936 } else if (strnicmp(value, "krb5i", 5) == 0) {
937 vol->secFlg |= CIFSSEC_MAY_KRB5 |
Steve French189acaa2006-06-23 02:33:48 +0000938 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800939 } else if (strnicmp(value, "krb5p", 5) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000940 /* vol->secFlg |= CIFSSEC_MUST_SEAL |
941 CIFSSEC_MAY_KRB5; */
942 cERROR(1, ("Krb5 cifs privacy not supported"));
Steve Frenchbf820672005-12-01 22:32:42 -0800943 return 1;
944 } else if (strnicmp(value, "krb5", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000945 vol->secFlg |= CIFSSEC_MAY_KRB5;
Steve Frenchbf820672005-12-01 22:32:42 -0800946 } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000947 vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
Steve French189acaa2006-06-23 02:33:48 +0000948 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800949 } else if (strnicmp(value, "ntlmv2", 6) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000950 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve Frenchbf820672005-12-01 22:32:42 -0800951 } else if (strnicmp(value, "ntlmi", 5) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000952 vol->secFlg |= CIFSSEC_MAY_NTLM |
Steve French189acaa2006-06-23 02:33:48 +0000953 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800954 } else if (strnicmp(value, "ntlm", 4) == 0) {
955 /* ntlm is default so can be turned off too */
Steve French750d1152006-06-27 06:28:30 +0000956 vol->secFlg |= CIFSSEC_MAY_NTLM;
Steve Frenchbf820672005-12-01 22:32:42 -0800957 } else if (strnicmp(value, "nontlm", 6) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000958 /* BB is there a better way to do this? */
Steve French750d1152006-06-27 06:28:30 +0000959 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve French189acaa2006-06-23 02:33:48 +0000960#ifdef CONFIG_CIFS_WEAK_PW_HASH
961 } else if (strnicmp(value, "lanman", 6) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000962 vol->secFlg |= CIFSSEC_MAY_LANMAN;
Steve French189acaa2006-06-23 02:33:48 +0000963#endif
Steve Frenchbf820672005-12-01 22:32:42 -0800964 } else if (strnicmp(value, "none", 4) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000965 vol->nullauth = 1;
Steve French50c2f752007-07-13 00:33:32 +0000966 } else {
967 cERROR(1, ("bad security option: %s", value));
968 return 1;
969 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 } else if ((strnicmp(data, "unc", 3) == 0)
971 || (strnicmp(data, "target", 6) == 0)
972 || (strnicmp(data, "path", 4) == 0)) {
973 if (!value || !*value) {
Steve French50c2f752007-07-13 00:33:32 +0000974 printk(KERN_WARNING "CIFS: invalid path to "
975 "network resource\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 return 1; /* needs_arg; */
977 }
978 if ((temp_len = strnlen(value, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +0000979 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +0000980 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 return 1;
Steve French50c2f752007-07-13 00:33:32 +0000982 strcpy(vol->UNC, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 if (strncmp(vol->UNC, "//", 2) == 0) {
984 vol->UNC[0] = '\\';
985 vol->UNC[1] = '\\';
Steve French50c2f752007-07-13 00:33:32 +0000986 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 printk(KERN_WARNING
Steve French50c2f752007-07-13 00:33:32 +0000988 "CIFS: UNC Path does not begin "
989 "with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 return 1;
991 }
992 } else {
993 printk(KERN_WARNING "CIFS: UNC name too long\n");
994 return 1;
995 }
996 } else if ((strnicmp(data, "domain", 3) == 0)
997 || (strnicmp(data, "workgroup", 5) == 0)) {
998 if (!value || !*value) {
999 printk(KERN_WARNING "CIFS: invalid domain name\n");
1000 return 1; /* needs_arg; */
1001 }
1002 /* BB are there cases in which a comma can be valid in
1003 a domain name and need special handling? */
Steve French39798772006-05-31 22:40:51 +00001004 if (strnlen(value, 256) < 256) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 vol->domainname = value;
1006 cFYI(1, ("Domain name set"));
1007 } else {
Steve French50c2f752007-07-13 00:33:32 +00001008 printk(KERN_WARNING "CIFS: domain name too "
1009 "long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 return 1;
1011 }
Steve French50c2f752007-07-13 00:33:32 +00001012 } else if (strnicmp(data, "prefixpath", 10) == 0) {
1013 if (!value || !*value) {
1014 printk(KERN_WARNING
1015 "CIFS: invalid path prefix\n");
1016 return 1; /* needs_argument */
1017 }
1018 if ((temp_len = strnlen(value, 1024)) < 1024) {
Steve French4523cc32007-04-30 20:13:06 +00001019 if (value[0] != '/')
Steve French2fe87f02006-09-21 07:02:52 +00001020 temp_len++; /* missing leading slash */
Steve French50c2f752007-07-13 00:33:32 +00001021 vol->prepath = kmalloc(temp_len+1, GFP_KERNEL);
1022 if (vol->prepath == NULL)
1023 return 1;
Steve French4523cc32007-04-30 20:13:06 +00001024 if (value[0] != '/') {
Steve French2fe87f02006-09-21 07:02:52 +00001025 vol->prepath[0] = '/';
Steve French50c2f752007-07-13 00:33:32 +00001026 strcpy(vol->prepath+1, value);
Steve French2fe87f02006-09-21 07:02:52 +00001027 } else
Steve French50c2f752007-07-13 00:33:32 +00001028 strcpy(vol->prepath, value);
1029 cFYI(1, ("prefix path %s", vol->prepath));
1030 } else {
1031 printk(KERN_WARNING "CIFS: prefix too long\n");
1032 return 1;
1033 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 } else if (strnicmp(data, "iocharset", 9) == 0) {
1035 if (!value || !*value) {
Steve French63135e02007-07-17 17:34:02 +00001036 printk(KERN_WARNING "CIFS: invalid iocharset "
1037 "specified\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 return 1; /* needs_arg; */
1039 }
1040 if (strnlen(value, 65) < 65) {
Steve French50c2f752007-07-13 00:33:32 +00001041 if (strnicmp(value, "default", 7))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 vol->iocharset = value;
Steve French50c2f752007-07-13 00:33:32 +00001043 /* if iocharset not set then load_nls_default
1044 is used by caller */
1045 cFYI(1, ("iocharset set to %s", value));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 } else {
Steve French63135e02007-07-17 17:34:02 +00001047 printk(KERN_WARNING "CIFS: iocharset name "
1048 "too long.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 return 1;
1050 }
1051 } else if (strnicmp(data, "uid", 3) == 0) {
1052 if (value && *value) {
1053 vol->linux_uid =
1054 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001055 vol->override_uid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 }
1057 } else if (strnicmp(data, "gid", 3) == 0) {
1058 if (value && *value) {
1059 vol->linux_gid =
1060 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001061 vol->override_gid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 }
1063 } else if (strnicmp(data, "file_mode", 4) == 0) {
1064 if (value && *value) {
1065 vol->file_mode =
1066 simple_strtoul(value, &value, 0);
1067 }
1068 } else if (strnicmp(data, "dir_mode", 4) == 0) {
1069 if (value && *value) {
1070 vol->dir_mode =
1071 simple_strtoul(value, &value, 0);
1072 }
1073 } else if (strnicmp(data, "dirmode", 4) == 0) {
1074 if (value && *value) {
1075 vol->dir_mode =
1076 simple_strtoul(value, &value, 0);
1077 }
1078 } else if (strnicmp(data, "port", 4) == 0) {
1079 if (value && *value) {
1080 vol->port =
1081 simple_strtoul(value, &value, 0);
1082 }
1083 } else if (strnicmp(data, "rsize", 5) == 0) {
1084 if (value && *value) {
1085 vol->rsize =
1086 simple_strtoul(value, &value, 0);
1087 }
1088 } else if (strnicmp(data, "wsize", 5) == 0) {
1089 if (value && *value) {
1090 vol->wsize =
1091 simple_strtoul(value, &value, 0);
1092 }
1093 } else if (strnicmp(data, "sockopt", 5) == 0) {
1094 if (value && *value) {
1095 vol->sockopt =
1096 simple_strtoul(value, &value, 0);
1097 }
1098 } else if (strnicmp(data, "netbiosname", 4) == 0) {
1099 if (!value || !*value || (*value == ' ')) {
Steve French63135e02007-07-17 17:34:02 +00001100 cFYI(1, ("invalid (empty) netbiosname"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 } else {
Steve French50c2f752007-07-13 00:33:32 +00001102 memset(vol->source_rfc1001_name, 0x20, 15);
1103 for (i = 0; i < 15; i++) {
1104 /* BB are there cases in which a comma can be
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 valid in this workstation netbios name (and need
1106 special handling)? */
1107
1108 /* We do not uppercase netbiosname for user */
Steve French50c2f752007-07-13 00:33:32 +00001109 if (value[i] == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 break;
Steve French50c2f752007-07-13 00:33:32 +00001111 else
1112 vol->source_rfc1001_name[i] =
1113 value[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 }
1115 /* The string has 16th byte zero still from
1116 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001117 if ((i == 15) && (value[i] != 0))
1118 printk(KERN_WARNING "CIFS: netbiosname"
1119 " longer than 15 truncated.\n");
Steve Frencha10faeb22005-08-22 21:38:31 -07001120 }
1121 } else if (strnicmp(data, "servern", 7) == 0) {
1122 /* servernetbiosname specified override *SMBSERVER */
1123 if (!value || !*value || (*value == ' ')) {
Steve French467a8f82007-06-27 22:41:32 +00001124 cFYI(1, ("empty server netbiosname specified"));
Steve Frencha10faeb22005-08-22 21:38:31 -07001125 } else {
1126 /* last byte, type, is 0x20 for servr type */
Steve French50c2f752007-07-13 00:33:32 +00001127 memset(vol->target_rfc1001_name, 0x20, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001128
Steve French50c2f752007-07-13 00:33:32 +00001129 for (i = 0; i < 15; i++) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001130 /* BB are there cases in which a comma can be
Steve French50c2f752007-07-13 00:33:32 +00001131 valid in this workstation netbios name
1132 (and need special handling)? */
Steve Frencha10faeb22005-08-22 21:38:31 -07001133
Steve French50c2f752007-07-13 00:33:32 +00001134 /* user or mount helper must uppercase
1135 the netbiosname */
1136 if (value[i] == 0)
Steve Frencha10faeb22005-08-22 21:38:31 -07001137 break;
1138 else
Steve French50c2f752007-07-13 00:33:32 +00001139 vol->target_rfc1001_name[i] =
1140 value[i];
Steve Frencha10faeb22005-08-22 21:38:31 -07001141 }
1142 /* The string has 16th byte zero still from
1143 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001144 if ((i == 15) && (value[i] != 0))
1145 printk(KERN_WARNING "CIFS: server net"
1146 "biosname longer than 15 truncated.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 }
1148 } else if (strnicmp(data, "credentials", 4) == 0) {
1149 /* ignore */
1150 } else if (strnicmp(data, "version", 3) == 0) {
1151 /* ignore */
Steve French50c2f752007-07-13 00:33:32 +00001152 } else if (strnicmp(data, "guest", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 /* ignore */
1154 } else if (strnicmp(data, "rw", 2) == 0) {
1155 vol->rw = TRUE;
1156 } else if ((strnicmp(data, "suid", 4) == 0) ||
1157 (strnicmp(data, "nosuid", 6) == 0) ||
1158 (strnicmp(data, "exec", 4) == 0) ||
1159 (strnicmp(data, "noexec", 6) == 0) ||
1160 (strnicmp(data, "nodev", 5) == 0) ||
1161 (strnicmp(data, "noauto", 6) == 0) ||
1162 (strnicmp(data, "dev", 3) == 0)) {
1163 /* The mount tool or mount.cifs helper (if present)
Steve French50c2f752007-07-13 00:33:32 +00001164 uses these opts to set flags, and the flags are read
1165 by the kernel vfs layer before we get here (ie
1166 before read super) so there is no point trying to
1167 parse these options again and set anything and it
1168 is ok to just ignore them */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 continue;
1170 } else if (strnicmp(data, "ro", 2) == 0) {
1171 vol->rw = FALSE;
1172 } else if (strnicmp(data, "hard", 4) == 0) {
1173 vol->retry = 1;
1174 } else if (strnicmp(data, "soft", 4) == 0) {
1175 vol->retry = 0;
1176 } else if (strnicmp(data, "perm", 4) == 0) {
1177 vol->noperm = 0;
1178 } else if (strnicmp(data, "noperm", 6) == 0) {
1179 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001180 } else if (strnicmp(data, "mapchars", 8) == 0) {
1181 vol->remap = 1;
1182 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1183 vol->remap = 0;
Steve French50c2f752007-07-13 00:33:32 +00001184 } else if (strnicmp(data, "sfu", 3) == 0) {
1185 vol->sfu_emul = 1;
1186 } else if (strnicmp(data, "nosfu", 5) == 0) {
1187 vol->sfu_emul = 0;
Jeremy Allisonac670552005-06-22 17:26:35 -07001188 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1189 vol->posix_paths = 1;
1190 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1191 vol->posix_paths = 0;
Steve Frenchc18c8422007-07-18 23:21:09 +00001192 } else if (strnicmp(data, "nounix", 6) == 0) {
1193 vol->no_linux_ext = 1;
1194 } else if (strnicmp(data, "nolinux", 7) == 0) {
1195 vol->no_linux_ext = 1;
Steve French50c2f752007-07-13 00:33:32 +00001196 } else if ((strnicmp(data, "nocase", 6) == 0) ||
Steve Frencha10faeb22005-08-22 21:38:31 -07001197 (strnicmp(data, "ignorecase", 10) == 0)) {
Steve French50c2f752007-07-13 00:33:32 +00001198 vol->nocase = 1;
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001199 } else if (strnicmp(data, "brl", 3) == 0) {
1200 vol->nobrl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001201 } else if ((strnicmp(data, "nobrl", 5) == 0) ||
Steve French1c955182005-08-30 20:58:07 -07001202 (strnicmp(data, "nolock", 6) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001203 vol->nobrl = 1;
Steve Frenchd3485d32005-08-19 11:04:29 -07001204 /* turn off mandatory locking in mode
1205 if remote locking is turned off since the
1206 local vfs will do advisory */
Steve French50c2f752007-07-13 00:33:32 +00001207 if (vol->file_mode ==
1208 (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
Steve Frenchd3485d32005-08-19 11:04:29 -07001209 vol->file_mode = S_IALLUGO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 } else if (strnicmp(data, "setuids", 7) == 0) {
1211 vol->setuids = 1;
1212 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1213 vol->setuids = 0;
1214 } else if (strnicmp(data, "nohard", 6) == 0) {
1215 vol->retry = 0;
1216 } else if (strnicmp(data, "nosoft", 6) == 0) {
1217 vol->retry = 1;
1218 } else if (strnicmp(data, "nointr", 6) == 0) {
1219 vol->intr = 0;
1220 } else if (strnicmp(data, "intr", 4) == 0) {
1221 vol->intr = 1;
Steve French50c2f752007-07-13 00:33:32 +00001222 } else if (strnicmp(data, "serverino", 7) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 vol->server_ino = 1;
Steve French50c2f752007-07-13 00:33:32 +00001224 } else if (strnicmp(data, "noserverino", 9) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 vol->server_ino = 0;
Steve French50c2f752007-07-13 00:33:32 +00001226 } else if (strnicmp(data, "cifsacl", 7) == 0) {
Steve French0a4b92c2006-01-12 15:44:21 -08001227 vol->cifs_acl = 1;
1228 } else if (strnicmp(data, "nocifsacl", 9) == 0) {
1229 vol->cifs_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001230 } else if (strnicmp(data, "acl", 3) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 vol->no_psx_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001232 } else if (strnicmp(data, "noacl", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 vol->no_psx_acl = 1;
Steve French50c2f752007-07-13 00:33:32 +00001234 } else if (strnicmp(data, "sign", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +00001235 vol->secFlg |= CIFSSEC_MUST_SIGN;
1236/* } else if (strnicmp(data, "seal",4) == 0) {
1237 vol->secFlg |= CIFSSEC_MUST_SEAL; */
Steve French50c2f752007-07-13 00:33:32 +00001238 } else if (strnicmp(data, "direct", 6) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001240 } else if (strnicmp(data, "forcedirectio", 13) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001242 } else if (strnicmp(data, "in6_addr", 8) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 if (!value || !*value) {
1244 vol->in6_addr = NULL;
1245 } else if (strnlen(value, 49) == 48) {
1246 vol->in6_addr = value;
1247 } else {
Steve French50c2f752007-07-13 00:33:32 +00001248 printk(KERN_WARNING "CIFS: ip v6 address not "
1249 "48 characters long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 return 1;
1251 }
1252 } else if (strnicmp(data, "noac", 4) == 0) {
Steve French50c2f752007-07-13 00:33:32 +00001253 printk(KERN_WARNING "CIFS: Mount option noac not "
1254 "supported. Instead set "
1255 "/proc/fs/cifs/LookupCacheEnabled to 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 } else
Steve French50c2f752007-07-13 00:33:32 +00001257 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",
1258 data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 }
1260 if (vol->UNC == NULL) {
Steve French4523cc32007-04-30 20:13:06 +00001261 if (devname == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001262 printk(KERN_WARNING "CIFS: Missing UNC name for mount "
1263 "target\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 return 1;
1265 }
1266 if ((temp_len = strnlen(devname, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001267 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001268 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001270 strcpy(vol->UNC, devname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271 if (strncmp(vol->UNC, "//", 2) == 0) {
1272 vol->UNC[0] = '\\';
1273 vol->UNC[1] = '\\';
1274 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Steve French50c2f752007-07-13 00:33:32 +00001275 printk(KERN_WARNING "CIFS: UNC Path does not "
1276 "begin with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 return 1;
1278 }
1279 } else {
1280 printk(KERN_WARNING "CIFS: UNC name too long\n");
1281 return 1;
1282 }
1283 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001284 if (vol->UNCip == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 vol->UNCip = &vol->UNC[2];
1286
1287 return 0;
1288}
1289
1290static struct cifsSesInfo *
Steve French50c2f752007-07-13 00:33:32 +00001291cifs_find_tcp_session(struct in_addr *target_ip_addr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 struct in6_addr *target_ip6_addr,
1293 char *userName, struct TCP_Server_Info **psrvTcp)
1294{
1295 struct list_head *tmp;
1296 struct cifsSesInfo *ses;
1297 *psrvTcp = NULL;
1298 read_lock(&GlobalSMBSeslock);
1299
1300 list_for_each(tmp, &GlobalSMBSessionList) {
1301 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
1302 if (ses->server) {
Steve French50c2f752007-07-13 00:33:32 +00001303 if ((target_ip_addr &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 (ses->server->addr.sockAddr.sin_addr.s_addr
1305 == target_ip_addr->s_addr)) || (target_ip6_addr
1306 && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
Steve French50c2f752007-07-13 00:33:32 +00001307 target_ip6_addr, sizeof(*target_ip6_addr)))) {
1308 /* BB lock server and tcp session and increment
1309 use count here?? */
1310
1311 /* found a match on the TCP session */
1312 *psrvTcp = ses->server;
1313
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 /* BB check if reconnection needed */
1315 if (strncmp
1316 (ses->userName, userName,
1317 MAX_USERNAME_SIZE) == 0){
1318 read_unlock(&GlobalSMBSeslock);
Steve French50c2f752007-07-13 00:33:32 +00001319 /* Found exact match on both TCP and
1320 SMB sessions */
1321 return ses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 }
1323 }
1324 }
1325 /* else tcp and smb sessions need reconnection */
1326 }
1327 read_unlock(&GlobalSMBSeslock);
1328 return NULL;
1329}
1330
1331static struct cifsTconInfo *
1332find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
1333{
1334 struct list_head *tmp;
1335 struct cifsTconInfo *tcon;
1336
1337 read_lock(&GlobalSMBSeslock);
1338 list_for_each(tmp, &GlobalTreeConnectionList) {
Steve Frenche466e482006-08-15 13:07:18 +00001339 cFYI(1, ("Next tcon"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
1341 if (tcon->ses) {
1342 if (tcon->ses->server) {
1343 cFYI(1,
Steve Frenche466e482006-08-15 13:07:18 +00001344 ("old ip addr: %x == new ip %x ?",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 tcon->ses->server->addr.sockAddr.sin_addr.
1346 s_addr, new_target_ip_addr));
1347 if (tcon->ses->server->addr.sockAddr.sin_addr.
1348 s_addr == new_target_ip_addr) {
Steve Frenche466e482006-08-15 13:07:18 +00001349 /* BB lock tcon, server and tcp session and increment use count here? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 /* found a match on the TCP session */
1351 /* BB check if reconnection needed */
Steve French50c2f752007-07-13 00:33:32 +00001352 cFYI(1,
1353 ("IP match, old UNC: %s new: %s",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 tcon->treeName, uncName));
1355 if (strncmp
1356 (tcon->treeName, uncName,
1357 MAX_TREE_SIZE) == 0) {
1358 cFYI(1,
Steve Frenche466e482006-08-15 13:07:18 +00001359 ("and old usr: %s new: %s",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 tcon->treeName, uncName));
1361 if (strncmp
1362 (tcon->ses->userName,
1363 userName,
1364 MAX_USERNAME_SIZE) == 0) {
1365 read_unlock(&GlobalSMBSeslock);
Steve Frenche466e482006-08-15 13:07:18 +00001366 /* matched smb session
1367 (user name */
1368 return tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 }
1370 }
1371 }
1372 }
1373 }
1374 }
1375 read_unlock(&GlobalSMBSeslock);
1376 return NULL;
1377}
1378
1379int
1380connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
Steve French737b7582005-04-28 22:41:06 -07001381 const char *old_path, const struct nls_table *nls_codepage,
1382 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383{
1384 unsigned char *referrals = NULL;
1385 unsigned int num_referrals;
1386 int rc = 0;
1387
Steve French50c2f752007-07-13 00:33:32 +00001388 rc = get_dfs_path(xid, pSesInfo, old_path, nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001389 &num_referrals, &referrals, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390
1391 /* BB Add in code to: if valid refrl, if not ip address contact
Steve French50c2f752007-07-13 00:33:32 +00001392 the helper that resolves tcp names, mount to it, try to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 tcon to it unmount it if fail */
1394
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001395 kfree(referrals);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396
1397 return rc;
1398}
1399
1400int
Steve French50c2f752007-07-13 00:33:32 +00001401get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
1402 const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
1403 unsigned char **preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404{
1405 char *temp_unc;
1406 int rc = 0;
1407
1408 *pnum_referrals = 0;
1409
1410 if (pSesInfo->ipc_tid == 0) {
1411 temp_unc = kmalloc(2 /* for slashes */ +
Steve French50c2f752007-07-13 00:33:32 +00001412 strnlen(pSesInfo->serverName,
1413 SERVER_NAME_LEN_WITH_NULL * 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 + 1 + 4 /* slash IPC$ */ + 2,
1415 GFP_KERNEL);
1416 if (temp_unc == NULL)
1417 return -ENOMEM;
1418 temp_unc[0] = '\\';
1419 temp_unc[1] = '\\';
1420 strcpy(temp_unc + 2, pSesInfo->serverName);
1421 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1422 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1423 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00001424 ("CIFS Tcon rc = %d ipc_tid = %d", rc, pSesInfo->ipc_tid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 kfree(temp_unc);
1426 }
1427 if (rc == 0)
1428 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001429 pnum_referrals, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430
1431 return rc;
1432}
1433
1434/* See RFC1001 section 14 on representation of Netbios names */
Steve French50c2f752007-07-13 00:33:32 +00001435static void rfc1002mangle(char *target, char *source, unsigned int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436{
Steve French50c2f752007-07-13 00:33:32 +00001437 unsigned int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438
Steve French50c2f752007-07-13 00:33:32 +00001439 for (i = 0, j = 0; i < (length); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 /* mask a nibble at a time and encode */
1441 target[j] = 'A' + (0x0F & (source[i] >> 4));
1442 target[j+1] = 'A' + (0x0F & source[i]);
Steve French50c2f752007-07-13 00:33:32 +00001443 j += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 }
1445
1446}
1447
1448
1449static int
Steve French50c2f752007-07-13 00:33:32 +00001450ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
1451 char *netbios_name, char *target_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452{
1453 int rc = 0;
1454 int connected = 0;
1455 __be16 orig_port = 0;
1456
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001457 if (*csocket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001458 rc = sock_create_kern(PF_INET, SOCK_STREAM,
1459 IPPROTO_TCP, csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001461 cERROR(1, ("Error %d creating socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 *csocket = NULL;
1463 return rc;
1464 } else {
1465 /* BB other socket options to set KEEPALIVE, NODELAY? */
Steve French467a8f82007-06-27 22:41:32 +00001466 cFYI(1, ("Socket created"));
Steve French50c2f752007-07-13 00:33:32 +00001467 (*csocket)->sk->sk_allocation = GFP_NOFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 }
1469 }
1470
1471 psin_server->sin_family = AF_INET;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001472 if (psin_server->sin_port) { /* user overrode default port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 rc = (*csocket)->ops->connect(*csocket,
1474 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001475 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 if (rc >= 0)
1477 connected = 1;
Steve French50c2f752007-07-13 00:33:32 +00001478 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001480 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001481 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 later if fall back ports fail this time */
1483 orig_port = psin_server->sin_port;
1484
1485 /* do not retry on the same port we just failed on */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001486 if (psin_server->sin_port != htons(CIFS_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 psin_server->sin_port = htons(CIFS_PORT);
1488
1489 rc = (*csocket)->ops->connect(*csocket,
1490 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001491 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 if (rc >= 0)
1493 connected = 1;
1494 }
1495 }
1496 if (!connected) {
1497 psin_server->sin_port = htons(RFC1001_PORT);
1498 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
Steve French50c2f752007-07-13 00:33:32 +00001499 psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001500 sizeof(struct sockaddr_in), 0);
Steve French50c2f752007-07-13 00:33:32 +00001501 if (rc >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 connected = 1;
1503 }
1504
1505 /* give up here - unless we want to retry on different
1506 protocol families some day */
1507 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001508 if (orig_port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 psin_server->sin_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001510 cFYI(1, ("Error %d connecting to server via ipv4", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 sock_release(*csocket);
1512 *csocket = NULL;
1513 return rc;
1514 }
Steve French50c2f752007-07-13 00:33:32 +00001515 /* Eventually check for other socket options to change from
1516 the default. sock_setsockopt not used because it expects
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 user space buffer */
Steve French50c2f752007-07-13 00:33:32 +00001518 cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",
1519 (*csocket)->sk->sk_sndbuf,
Steve Frenchb387eae2005-10-10 14:21:15 -07001520 (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchb387eae2005-10-10 14:21:15 -07001522 /* make the bufsizes depend on wsize/rsize and max requests */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001523 if ((*csocket)->sk->sk_sndbuf < (200 * 1024))
Steve Frenchb387eae2005-10-10 14:21:15 -07001524 (*csocket)->sk->sk_sndbuf = 200 * 1024;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001525 if ((*csocket)->sk->sk_rcvbuf < (140 * 1024))
Steve Frenchb387eae2005-10-10 14:21:15 -07001526 (*csocket)->sk->sk_rcvbuf = 140 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527
1528 /* send RFC1001 sessinit */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001529 if (psin_server->sin_port == htons(RFC1001_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 /* some servers require RFC1001 sessinit before sending
Steve French50c2f752007-07-13 00:33:32 +00001531 negprot - BB check reconnection in case where second
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 sessinit is sent but no second negprot */
Steve French50c2f752007-07-13 00:33:32 +00001533 struct rfc1002_session_packet *ses_init_buf;
1534 struct smb_hdr *smb_buf;
1535 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
1536 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001537 if (ses_init_buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 ses_init_buf->trailer.session_req.called_len = 32;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001539 if (target_name && (target_name[0] != 0)) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001540 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1541 target_name, 16);
1542 } else {
1543 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
Steve French50c2f752007-07-13 00:33:32 +00001544 DEFAULT_CIFS_CALLED_NAME, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001545 }
1546
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 ses_init_buf->trailer.session_req.calling_len = 32;
1548 /* calling name ends in null (byte 16) from old smb
1549 convention. */
Steve French50c2f752007-07-13 00:33:32 +00001550 if (netbios_name && (netbios_name[0] != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
Steve French50c2f752007-07-13 00:33:32 +00001552 netbios_name, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 } else {
1554 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
Steve French50c2f752007-07-13 00:33:32 +00001555 "LINUX_CIFS_CLNT", 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 }
1557 ses_init_buf->trailer.session_req.scope1 = 0;
1558 ses_init_buf->trailer.session_req.scope2 = 0;
1559 smb_buf = (struct smb_hdr *)ses_init_buf;
1560 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1561 smb_buf->smb_buf_length = 0x81000044;
1562 rc = smb_send(*csocket, smb_buf, 0x44,
1563 (struct sockaddr *)psin_server);
1564 kfree(ses_init_buf);
Steve French50c2f752007-07-13 00:33:32 +00001565 msleep(1); /* RFC1001 layer in at least one server
Steve French083d3a22006-03-03 09:53:36 +00001566 requires very short break before negprot
1567 presumably because not expecting negprot
1568 to follow so fast. This is a simple
Steve French50c2f752007-07-13 00:33:32 +00001569 solution that works without
Steve French083d3a22006-03-03 09:53:36 +00001570 complicating the code and causes no
1571 significant slowing down on mount
1572 for everyone else */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 }
Steve French50c2f752007-07-13 00:33:32 +00001574 /* else the negprot may still work without this
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 even though malloc failed */
Steve French50c2f752007-07-13 00:33:32 +00001576
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 }
Steve French50c2f752007-07-13 00:33:32 +00001578
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 return rc;
1580}
1581
1582static int
1583ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1584{
1585 int rc = 0;
1586 int connected = 0;
1587 __be16 orig_port = 0;
1588
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001589 if (*csocket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001590 rc = sock_create_kern(PF_INET6, SOCK_STREAM,
1591 IPPROTO_TCP, csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001593 cERROR(1, ("Error %d creating ipv6 socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 *csocket = NULL;
1595 return rc;
1596 } else {
1597 /* BB other socket options to set KEEPALIVE, NODELAY? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001598 cFYI(1, ("ipv6 Socket created"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 (*csocket)->sk->sk_allocation = GFP_NOFS;
1600 }
1601 }
1602
1603 psin_server->sin6_family = AF_INET6;
1604
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001605 if (psin_server->sin6_port) { /* user overrode default port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 rc = (*csocket)->ops->connect(*csocket,
1607 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001608 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 if (rc >= 0)
1610 connected = 1;
Steve French50c2f752007-07-13 00:33:32 +00001611 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001613 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001614 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 later if fall back ports fail this time */
1616
1617 orig_port = psin_server->sin6_port;
1618 /* do not retry on the same port we just failed on */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001619 if (psin_server->sin6_port != htons(CIFS_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 psin_server->sin6_port = htons(CIFS_PORT);
1621
1622 rc = (*csocket)->ops->connect(*csocket,
1623 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001624 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 if (rc >= 0)
1626 connected = 1;
1627 }
1628 }
1629 if (!connected) {
1630 psin_server->sin6_port = htons(RFC1001_PORT);
1631 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001632 psin_server, sizeof(struct sockaddr_in6), 0);
Steve French50c2f752007-07-13 00:33:32 +00001633 if (rc >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 connected = 1;
1635 }
1636
1637 /* give up here - unless we want to retry on different
1638 protocol families some day */
1639 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001640 if (orig_port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 psin_server->sin6_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001642 cFYI(1, ("Error %d connecting to server via ipv6", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 sock_release(*csocket);
1644 *csocket = NULL;
1645 return rc;
1646 }
Steve French50c2f752007-07-13 00:33:32 +00001647 /* Eventually check for other socket options to change from
1648 the default. sock_setsockopt not used because it expects
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 user space buffer */
1650 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve French50c2f752007-07-13 00:33:32 +00001651
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 return rc;
1653}
1654
Steve French50c2f752007-07-13 00:33:32 +00001655void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
1656 struct super_block *sb, struct smb_vol *vol_info)
Steve French8af18972007-02-14 04:42:51 +00001657{
1658 /* if we are reconnecting then should we check to see if
1659 * any requested capabilities changed locally e.g. via
1660 * remount but we can not do much about it here
1661 * if they have (even if we could detect it by the following)
1662 * Perhaps we could add a backpointer to array of sb from tcon
1663 * or if we change to make all sb to same share the same
1664 * sb as NFS - then we only have one backpointer to sb.
1665 * What if we wanted to mount the server share twice once with
1666 * and once without posixacls or posix paths? */
1667 __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001668
Steve Frenchc18c8422007-07-18 23:21:09 +00001669 if (vol_info && vol_info->no_linux_ext) {
1670 tcon->fsUnixInfo.Capability = 0;
1671 tcon->unix_ext = 0; /* Unix Extensions disabled */
1672 cFYI(1, ("Linux protocol extensions disabled"));
1673 return;
1674 } else if (vol_info)
1675 tcon->unix_ext = 1; /* Unix Extensions supported */
1676
1677 if (tcon->unix_ext == 0) {
1678 cFYI(1, ("Unix extensions disabled so not set on reconnect"));
1679 return;
1680 }
Steve French50c2f752007-07-13 00:33:32 +00001681
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001682 if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
Steve French8af18972007-02-14 04:42:51 +00001683 __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001684
Steve French8af18972007-02-14 04:42:51 +00001685 /* check for reconnect case in which we do not
1686 want to change the mount behavior if we can avoid it */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001687 if (vol_info == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001688 /* turn off POSIX ACL and PATHNAMES if not set
Steve French8af18972007-02-14 04:42:51 +00001689 originally at mount time */
1690 if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
1691 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
1692 if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0)
1693 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French8af18972007-02-14 04:42:51 +00001694 }
Steve French50c2f752007-07-13 00:33:32 +00001695
Steve French8af18972007-02-14 04:42:51 +00001696 cap &= CIFS_UNIX_CAP_MASK;
Steve French75865f82007-06-24 18:30:48 +00001697 if (vol_info && vol_info->no_psx_acl)
Steve French8af18972007-02-14 04:42:51 +00001698 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Steve French75865f82007-06-24 18:30:48 +00001699 else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001700 cFYI(1, ("negotiated posix acl support"));
1701 if (sb)
Steve French8af18972007-02-14 04:42:51 +00001702 sb->s_flags |= MS_POSIXACL;
1703 }
1704
Steve French75865f82007-06-24 18:30:48 +00001705 if (vol_info && vol_info->posix_paths == 0)
Steve French8af18972007-02-14 04:42:51 +00001706 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French75865f82007-06-24 18:30:48 +00001707 else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001708 cFYI(1, ("negotiate posix pathnames"));
Steve French75865f82007-06-24 18:30:48 +00001709 if (sb)
Steve French50c2f752007-07-13 00:33:32 +00001710 CIFS_SB(sb)->mnt_cifs_flags |=
Steve French8af18972007-02-14 04:42:51 +00001711 CIFS_MOUNT_POSIX_PATHS;
1712 }
Steve French50c2f752007-07-13 00:33:32 +00001713
Steve French984acfe2007-04-26 16:42:50 +00001714 /* We might be setting the path sep back to a different
1715 form if we are reconnecting and the server switched its
Steve French50c2f752007-07-13 00:33:32 +00001716 posix path capability for this share */
Steve French75865f82007-06-24 18:30:48 +00001717 if (sb && (CIFS_SB(sb)->prepathlen > 0))
Steve French984acfe2007-04-26 16:42:50 +00001718 CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
Steve French75865f82007-06-24 18:30:48 +00001719
1720 if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
1721 if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
1722 CIFS_SB(sb)->rsize = 127 * 1024;
1723#ifdef CONFIG_CIFS_DEBUG2
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001724 cFYI(1, ("larger reads not supported by srv"));
Steve French75865f82007-06-24 18:30:48 +00001725#endif
1726 }
1727 }
Steve French50c2f752007-07-13 00:33:32 +00001728
1729
1730 cFYI(1, ("Negotiate caps 0x%x", (int)cap));
Steve French8af18972007-02-14 04:42:51 +00001731#ifdef CONFIG_CIFS_DEBUG2
Steve French75865f82007-06-24 18:30:48 +00001732 if (cap & CIFS_UNIX_FCNTL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001733 cFYI(1, ("FCNTL cap"));
Steve French75865f82007-06-24 18:30:48 +00001734 if (cap & CIFS_UNIX_EXTATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001735 cFYI(1, ("EXTATTR cap"));
Steve French75865f82007-06-24 18:30:48 +00001736 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001737 cFYI(1, ("POSIX path cap"));
Steve French75865f82007-06-24 18:30:48 +00001738 if (cap & CIFS_UNIX_XATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001739 cFYI(1, ("XATTR cap"));
Steve French75865f82007-06-24 18:30:48 +00001740 if (cap & CIFS_UNIX_POSIX_ACL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001741 cFYI(1, ("POSIX ACL cap"));
Steve French75865f82007-06-24 18:30:48 +00001742 if (cap & CIFS_UNIX_LARGE_READ_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001743 cFYI(1, ("very large read cap"));
Steve French75865f82007-06-24 18:30:48 +00001744 if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001745 cFYI(1, ("very large write cap"));
Steve French8af18972007-02-14 04:42:51 +00001746#endif /* CIFS_DEBUG2 */
1747 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
Steve French442aa312007-09-24 20:25:46 +00001748 if (vol_info == NULL) {
Steve French5a44b312007-09-20 15:16:24 +00001749 cFYI(1, ("resetting capabilities failed"));
Steve French442aa312007-09-24 20:25:46 +00001750 } else
Steve French5a44b312007-09-20 15:16:24 +00001751 cERROR(1, ("Negotiating Unix capabilities "
1752 "with the server failed. Consider "
1753 "mounting with the Unix Extensions\n"
1754 "disabled, if problems are found, "
1755 "by specifying the nounix mount "
Steve French2224f4e2007-09-20 15:37:29 +00001756 "option."));
Steve French5a44b312007-09-20 15:16:24 +00001757
Steve French8af18972007-02-14 04:42:51 +00001758 }
1759 }
1760}
1761
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762int
1763cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1764 char *mount_data, const char *devname)
1765{
1766 int rc = 0;
1767 int xid;
1768 int address_type = AF_INET;
1769 struct socket *csocket = NULL;
1770 struct sockaddr_in sin_server;
1771 struct sockaddr_in6 sin_server6;
1772 struct smb_vol volume_info;
1773 struct cifsSesInfo *pSesInfo = NULL;
1774 struct cifsSesInfo *existingCifsSes = NULL;
1775 struct cifsTconInfo *tcon = NULL;
1776 struct TCP_Server_Info *srvTcp = NULL;
1777
1778 xid = GetXid();
1779
1780/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
Steve French50c2f752007-07-13 00:33:32 +00001781
1782 memset(&volume_info, 0, sizeof(struct smb_vol));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001784 kfree(volume_info.UNC);
1785 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001786 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 FreeXid(xid);
1788 return -EINVAL;
1789 }
1790
Jeff Layton8426c392007-05-05 03:27:49 +00001791 if (volume_info.nullauth) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001792 cFYI(1, ("null user"));
Jeff Layton9b8f5f52007-11-09 23:25:04 +00001793 volume_info.username = "";
Jeff Layton8426c392007-05-05 03:27:49 +00001794 } else if (volume_info.username) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 /* BB fixme parse for domain name here */
Steve French467a8f82007-06-27 22:41:32 +00001796 cFYI(1, ("Username: %s", volume_info.username));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 } else {
Steve Frenchbf820672005-12-01 22:32:42 -08001798 cifserror("No username specified");
Steve French50c2f752007-07-13 00:33:32 +00001799 /* In userspace mount helper we can get user name from alternate
1800 locations such as env variables and files on disk */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001801 kfree(volume_info.UNC);
1802 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001803 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 FreeXid(xid);
1805 return -EINVAL;
1806 }
1807
1808 if (volume_info.UNCip && volume_info.UNC) {
Steve French50c2f752007-07-13 00:33:32 +00001809 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,
1810 &sin_server.sin_addr.s_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001812 if (rc <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 /* not ipv4 address, try ipv6 */
Steve French50c2f752007-07-13 00:33:32 +00001814 rc = cifs_inet_pton(AF_INET6, volume_info.UNCip,
1815 &sin_server6.sin6_addr.in6_u);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001816 if (rc > 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 address_type = AF_INET6;
1818 } else {
1819 address_type = AF_INET;
1820 }
Steve French50c2f752007-07-13 00:33:32 +00001821
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001822 if (rc <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 /* we failed translating address */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001824 kfree(volume_info.UNC);
1825 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001826 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827 FreeXid(xid);
1828 return -EINVAL;
1829 }
1830
1831 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1832 /* success */
1833 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00001834 } else if (volume_info.UNCip) {
1835 /* BB using ip addr as server name to connect to the
1836 DFS root below */
1837 cERROR(1, ("Connecting to DFS root not implemented yet"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001838 kfree(volume_info.UNC);
1839 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001840 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 FreeXid(xid);
1842 return -EINVAL;
1843 } else /* which servers DFS root would we conect to */ {
1844 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00001845 ("CIFS mount error: No UNC path (e.g. -o "
1846 "unc=//192.168.1.100/public) specified"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001847 kfree(volume_info.UNC);
1848 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001849 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 FreeXid(xid);
1851 return -EINVAL;
1852 }
1853
1854 /* this is needed for ASCII cp to Unicode converts */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001855 if (volume_info.iocharset == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 cifs_sb->local_nls = load_nls_default();
1857 /* load_nls_default can not return null */
1858 } else {
1859 cifs_sb->local_nls = load_nls(volume_info.iocharset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001860 if (cifs_sb->local_nls == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001861 cERROR(1, ("CIFS mount error: iocharset %s not found",
1862 volume_info.iocharset));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001863 kfree(volume_info.UNC);
1864 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001865 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 FreeXid(xid);
1867 return -ELIBACC;
1868 }
1869 }
1870
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001871 if (address_type == AF_INET)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1873 NULL /* no ipv6 addr */,
1874 volume_info.username, &srvTcp);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001875 else if (address_type == AF_INET6) {
1876 cFYI(1, ("looking for ipv6 address"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1878 &sin_server6.sin6_addr,
1879 volume_info.username, &srvTcp);
Steve French5858ae42007-04-25 11:59:10 +00001880 } else {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001881 kfree(volume_info.UNC);
1882 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001883 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 FreeXid(xid);
1885 return -EINVAL;
1886 }
1887
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 if (srvTcp) {
Steve French50c2f752007-07-13 00:33:32 +00001889 cFYI(1, ("Existing tcp session with server found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 } else { /* create socket */
Steve French4523cc32007-04-30 20:13:06 +00001891 if (volume_info.port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 sin_server.sin_port = htons(volume_info.port);
1893 else
1894 sin_server.sin_port = 0;
Steve French5858ae42007-04-25 11:59:10 +00001895 if (address_type == AF_INET6) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001896 cFYI(1, ("attempting ipv6 connect"));
Steve French5858ae42007-04-25 11:59:10 +00001897 /* BB should we allow ipv6 on port 139? */
1898 /* other OS never observed in Wild doing 139 with v6 */
Steve French50c2f752007-07-13 00:33:32 +00001899 rc = ipv6_connect(&sin_server6, &csocket);
1900 } else
1901 rc = ipv4_connect(&sin_server, &csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -07001902 volume_info.source_rfc1001_name,
1903 volume_info.target_rfc1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001905 cERROR(1, ("Error connecting to IPv4 socket. "
1906 "Aborting operation"));
Steve French4523cc32007-04-30 20:13:06 +00001907 if (csocket != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001909 kfree(volume_info.UNC);
1910 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001911 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 FreeXid(xid);
1913 return rc;
1914 }
1915
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00001916 srvTcp = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
1917 if (!srvTcp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 rc = -ENOMEM;
1919 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001920 kfree(volume_info.UNC);
1921 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001922 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 FreeXid(xid);
1924 return rc;
1925 } else {
Steve French50c2f752007-07-13 00:33:32 +00001926 memcpy(&srvTcp->addr.sockAddr, &sin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001927 sizeof(struct sockaddr_in));
Steve French50c2f752007-07-13 00:33:32 +00001928 atomic_set(&srvTcp->inFlight, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 /* BB Add code for ipv6 case too */
1930 srvTcp->ssocket = csocket;
1931 srvTcp->protocolType = IPV4;
1932 init_waitqueue_head(&srvTcp->response_q);
1933 init_waitqueue_head(&srvTcp->request_q);
1934 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1935 /* at this point we are the only ones with the pointer
1936 to the struct since the kernel thread not created yet
1937 so no need to spinlock this init of tcpStatus */
1938 srvTcp->tcpStatus = CifsNew;
1939 init_MUTEX(&srvTcp->tcpSem);
Igor Mammedovaaf737a2007-04-03 19:16:43 +00001940 srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd");
Steve French4523cc32007-04-30 20:13:06 +00001941 if ( IS_ERR(srvTcp->tsk) ) {
Igor Mammedovaaf737a2007-04-03 19:16:43 +00001942 rc = PTR_ERR(srvTcp->tsk);
Steve French50c2f752007-07-13 00:33:32 +00001943 cERROR(1, ("error %d create cifsd thread", rc));
Igor Mammedovaaf737a2007-04-03 19:16:43 +00001944 srvTcp->tsk = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 sock_release(csocket);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001946 kfree(volume_info.UNC);
1947 kfree(volume_info.password);
Steve French2fe87f02006-09-21 07:02:52 +00001948 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 FreeXid(xid);
1950 return rc;
Steve Frenchf1914012005-08-18 09:37:34 -07001951 }
1952 wait_for_completion(&cifsd_complete);
1953 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00001954 memcpy(srvTcp->workstation_RFC1001_name,
1955 volume_info.source_rfc1001_name, 16);
1956 memcpy(srvTcp->server_RFC1001_name,
1957 volume_info.target_rfc1001_name, 16);
Steve Frenchad009ac2005-04-28 22:41:05 -07001958 srvTcp->sequence_number = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 }
1960 }
1961
1962 if (existingCifsSes) {
1963 pSesInfo = existingCifsSes;
Steve Frenchbf820672005-12-01 22:32:42 -08001964 cFYI(1, ("Existing smb sess found"));
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001965 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966 /* volume_info.UNC freed at end of function */
1967 } else if (!rc) {
Steve Frenchbf820672005-12-01 22:32:42 -08001968 cFYI(1, ("Existing smb sess not found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969 pSesInfo = sesInfoAlloc();
1970 if (pSesInfo == NULL)
1971 rc = -ENOMEM;
1972 else {
1973 pSesInfo->server = srvTcp;
1974 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
1975 NIPQUAD(sin_server.sin_addr.s_addr));
1976 }
1977
Steve French50c2f752007-07-13 00:33:32 +00001978 if (!rc) {
1979 /* volume_info.password freed at unmount */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 if (volume_info.password)
1981 pSesInfo->password = volume_info.password;
1982 if (volume_info.username)
1983 strncpy(pSesInfo->userName,
Steve French50c2f752007-07-13 00:33:32 +00001984 volume_info.username,
1985 MAX_USERNAME_SIZE);
Steve French39798772006-05-31 22:40:51 +00001986 if (volume_info.domainname) {
1987 int len = strlen(volume_info.domainname);
Steve French50c2f752007-07-13 00:33:32 +00001988 pSesInfo->domainName =
Steve French39798772006-05-31 22:40:51 +00001989 kmalloc(len + 1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001990 if (pSesInfo->domainName)
Steve French39798772006-05-31 22:40:51 +00001991 strcpy(pSesInfo->domainName,
1992 volume_info.domainname);
1993 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 pSesInfo->linux_uid = volume_info.linux_uid;
Steve French750d1152006-06-27 06:28:30 +00001995 pSesInfo->overrideSecFlg = volume_info.secFlg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 down(&pSesInfo->sesSem);
Steve French189acaa2006-06-23 02:33:48 +00001997 /* BB FIXME need to pass vol->secFlgs BB */
Steve French50c2f752007-07-13 00:33:32 +00001998 rc = cifs_setup_session(xid, pSesInfo,
1999 cifs_sb->local_nls);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 up(&pSesInfo->sesSem);
Steve French4523cc32007-04-30 20:13:06 +00002001 if (!rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 atomic_inc(&srvTcp->socketUseCount);
2003 } else
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002004 kfree(volume_info.password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 }
Steve French50c2f752007-07-13 00:33:32 +00002006
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007 /* search for existing tcon to this server share */
2008 if (!rc) {
Steve French4523cc32007-04-30 20:13:06 +00002009 if (volume_info.rsize > CIFSMaxBufSize) {
Steve French50c2f752007-07-13 00:33:32 +00002010 cERROR(1, ("rsize %d too large, using MaxBufSize",
Steve French0ae0efa2005-10-10 10:57:19 -07002011 volume_info.rsize));
2012 cifs_sb->rsize = CIFSMaxBufSize;
Steve French75865f82007-06-24 18:30:48 +00002013 } else if ((volume_info.rsize) &&
2014 (volume_info.rsize <= CIFSMaxBufSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015 cifs_sb->rsize = volume_info.rsize;
Steve French0ae0efa2005-10-10 10:57:19 -07002016 else /* default */
2017 cifs_sb->rsize = CIFSMaxBufSize;
2018
Steve French4523cc32007-04-30 20:13:06 +00002019 if (volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
Steve French50c2f752007-07-13 00:33:32 +00002020 cERROR(1, ("wsize %d too large, using 4096 instead",
Steve French0ae0efa2005-10-10 10:57:19 -07002021 volume_info.wsize));
2022 cifs_sb->wsize = 4096;
Steve French4523cc32007-04-30 20:13:06 +00002023 } else if (volume_info.wsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024 cifs_sb->wsize = volume_info.wsize;
2025 else
Steve French50c2f752007-07-13 00:33:32 +00002026 cifs_sb->wsize =
Steve French1877c9e2006-01-27 18:36:11 -08002027 min_t(const int, PAGEVEC_SIZE * PAGE_CACHE_SIZE,
2028 127*1024);
Steve French17cbbaf2006-01-24 20:26:48 -08002029 /* old default of CIFSMaxBufSize was too small now
Steve French50c2f752007-07-13 00:33:32 +00002030 that SMB Write2 can send multiple pages in kvec.
Steve French17cbbaf2006-01-24 20:26:48 -08002031 RFC1001 does not describe what happens when frame
2032 bigger than 128K is sent so use that as max in
2033 conjunction with 52K kvec constraint on arch with 4K
2034 page size */
2035
Steve French4523cc32007-04-30 20:13:06 +00002036 if (cifs_sb->rsize < 2048) {
Steve French50c2f752007-07-13 00:33:32 +00002037 cifs_sb->rsize = 2048;
Steve French6cec2ae2006-02-22 17:31:52 -06002038 /* Windows ME may prefer this */
Steve French467a8f82007-06-27 22:41:32 +00002039 cFYI(1, ("readsize set to minimum: 2048"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 }
Steve French2fe87f02006-09-21 07:02:52 +00002041 /* calculate prepath */
2042 cifs_sb->prepath = volume_info.prepath;
Steve French4523cc32007-04-30 20:13:06 +00002043 if (cifs_sb->prepath) {
Steve French2fe87f02006-09-21 07:02:52 +00002044 cifs_sb->prepathlen = strlen(cifs_sb->prepath);
2045 cifs_sb->prepath[0] = CIFS_DIR_SEP(cifs_sb);
2046 volume_info.prepath = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002047 } else
Steve French2fe87f02006-09-21 07:02:52 +00002048 cifs_sb->prepathlen = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 cifs_sb->mnt_uid = volume_info.linux_uid;
2050 cifs_sb->mnt_gid = volume_info.linux_gid;
2051 cifs_sb->mnt_file_mode = volume_info.file_mode;
2052 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
Steve French467a8f82007-06-27 22:41:32 +00002053 cFYI(1, ("file mode: 0x%x dir mode: 0x%x",
2054 cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055
Steve French4523cc32007-04-30 20:13:06 +00002056 if (volume_info.noperm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
Steve French4523cc32007-04-30 20:13:06 +00002058 if (volume_info.setuids)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
Steve French4523cc32007-04-30 20:13:06 +00002060 if (volume_info.server_ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
Steve French4523cc32007-04-30 20:13:06 +00002062 if (volume_info.remap)
Steve French6a0b4822005-04-28 22:41:05 -07002063 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
Steve French4523cc32007-04-30 20:13:06 +00002064 if (volume_info.no_xattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
Steve French4523cc32007-04-30 20:13:06 +00002066 if (volume_info.sfu_emul)
Steve Frenchd7245c22005-07-14 18:25:12 -05002067 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
Steve French4523cc32007-04-30 20:13:06 +00002068 if (volume_info.nobrl)
Steve Frenchc46fa8a2005-08-18 20:49:57 -07002069 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Steve French4523cc32007-04-30 20:13:06 +00002070 if (volume_info.cifs_acl)
Steve French0a4b92c2006-01-12 15:44:21 -08002071 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
Steve French4523cc32007-04-30 20:13:06 +00002072 if (volume_info.override_uid)
2073 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
2074 if (volume_info.override_gid)
2075 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
2076 if (volume_info.direct_io) {
Steve French467a8f82007-06-27 22:41:32 +00002077 cFYI(1, ("mounting share using direct i/o"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
2079 }
2080
2081 tcon =
2082 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
2083 volume_info.username);
2084 if (tcon) {
Steve Frenchbf820672005-12-01 22:32:42 -08002085 cFYI(1, ("Found match on UNC path"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086 /* we can have only one retry value for a connection
2087 to a share so for resources mounted more than once
Steve French50c2f752007-07-13 00:33:32 +00002088 to the same server share the last value passed in
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089 for the retry flag is used */
2090 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07002091 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092 } else {
2093 tcon = tconInfoAlloc();
2094 if (tcon == NULL)
2095 rc = -ENOMEM;
2096 else {
Steve French50c2f752007-07-13 00:33:32 +00002097 /* check for null share name ie connecting to
Steve French8af18972007-02-14 04:42:51 +00002098 * dfs root */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099
Steve French50c2f752007-07-13 00:33:32 +00002100 /* BB check if this works for exactly length
Steve French8af18972007-02-14 04:42:51 +00002101 * three strings */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
2103 && (strchr(volume_info.UNC + 3, '/') ==
2104 NULL)) {
Steve French737b7582005-04-28 22:41:06 -07002105 rc = connect_to_dfs_path(xid, pSesInfo,
Steve French8af18972007-02-14 04:42:51 +00002106 "", cifs_sb->local_nls,
Steve French50c2f752007-07-13 00:33:32 +00002107 cifs_sb->mnt_cifs_flags &
Steve French8af18972007-02-14 04:42:51 +00002108 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002109 kfree(volume_info.UNC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 FreeXid(xid);
2111 return -ENODEV;
2112 } else {
Steve French8af18972007-02-14 04:42:51 +00002113 /* BB Do we need to wrap sesSem around
2114 * this TCon call and Unix SetFS as
2115 * we do on SessSetup and reconnect? */
Steve French50c2f752007-07-13 00:33:32 +00002116 rc = CIFSTCon(xid, pSesInfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117 volume_info.UNC,
2118 tcon, cifs_sb->local_nls);
2119 cFYI(1, ("CIFS Tcon rc = %d", rc));
2120 }
2121 if (!rc) {
2122 atomic_inc(&pSesInfo->inUse);
2123 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07002124 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125 }
2126 }
2127 }
2128 }
Steve French4523cc32007-04-30 20:13:06 +00002129 if (pSesInfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
2131 sb->s_maxbytes = (u64) 1 << 63;
2132 } else
2133 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
2134 }
2135
Steve French8af18972007-02-14 04:42:51 +00002136 /* BB FIXME fix time_gran to be larger for LANMAN sessions */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137 sb->s_time_gran = 100;
2138
2139/* on error free sesinfo and tcon struct if needed */
2140 if (rc) {
2141 /* if session setup failed, use count is zero but
2142 we still need to free cifsd thread */
Steve French4523cc32007-04-30 20:13:06 +00002143 if (atomic_read(&srvTcp->socketUseCount) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144 spin_lock(&GlobalMid_Lock);
2145 srvTcp->tcpStatus = CifsExiting;
2146 spin_unlock(&GlobalMid_Lock);
Steve French4523cc32007-04-30 20:13:06 +00002147 if (srvTcp->tsk) {
Steve French28356a12007-05-23 14:45:36 +00002148 struct task_struct *tsk;
2149 /* If we could verify that kthread_stop would
2150 always wake up processes blocked in
2151 tcp in recv_mesg then we could remove the
2152 send_sig call */
Steve French50c2f752007-07-13 00:33:32 +00002153 force_sig(SIGKILL, srvTcp->tsk);
Steve French28356a12007-05-23 14:45:36 +00002154 tsk = srvTcp->tsk;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002155 if (tsk)
Steve Frenchf7f7c312007-05-24 02:29:51 +00002156 kthread_stop(tsk);
Steve Frenchf1914012005-08-18 09:37:34 -07002157 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 }
2159 /* If find_unc succeeded then rc == 0 so we can not end */
2160 if (tcon) /* up accidently freeing someone elses tcon struct */
2161 tconInfoFree(tcon);
2162 if (existingCifsSes == NULL) {
2163 if (pSesInfo) {
Steve French50c2f752007-07-13 00:33:32 +00002164 if ((pSesInfo->server) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165 (pSesInfo->status == CifsGood)) {
2166 int temp_rc;
2167 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
2168 /* if the socketUseCount is now zero */
Steve French4523cc32007-04-30 20:13:06 +00002169 if ((temp_rc == -ESHUTDOWN) &&
Steve French50c2f752007-07-13 00:33:32 +00002170 (pSesInfo->server) &&
Jeff5d9c7202007-06-25 22:16:35 +00002171 (pSesInfo->server->tsk)) {
Steve French28356a12007-05-23 14:45:36 +00002172 struct task_struct *tsk;
Jeff5d9c7202007-06-25 22:16:35 +00002173 force_sig(SIGKILL,
2174 pSesInfo->server->tsk);
Steve French28356a12007-05-23 14:45:36 +00002175 tsk = pSesInfo->server->tsk;
Steve Frenchf7f7c312007-05-24 02:29:51 +00002176 if (tsk)
Steve French28356a12007-05-23 14:45:36 +00002177 kthread_stop(tsk);
Steve Frenchf1914012005-08-18 09:37:34 -07002178 }
Steve Frencha0136892007-10-04 20:05:09 +00002179 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180 cFYI(1, ("No session or bad tcon"));
Steve Frencha0136892007-10-04 20:05:09 +00002181 if ((pSesInfo->server) &&
2182 (pSesInfo->server->tsk)) {
2183 struct task_struct *tsk;
2184 force_sig(SIGKILL,
2185 pSesInfo->server->tsk);
2186 tsk = pSesInfo->server->tsk;
2187 if (tsk)
2188 kthread_stop(tsk);
2189 }
2190 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191 sesInfoFree(pSesInfo);
2192 /* pSesInfo = NULL; */
2193 }
2194 }
2195 } else {
2196 atomic_inc(&tcon->useCount);
2197 cifs_sb->tcon = tcon;
2198 tcon->ses = pSesInfo;
2199
Steve French82940a42006-03-02 03:24:57 +00002200 /* do not care if following two calls succeed - informational */
Steve French7f8ed422007-09-28 22:28:55 +00002201 if (!tcon->ipc) {
2202 CIFSSMBQFSDeviceInfo(xid, tcon);
2203 CIFSSMBQFSAttributeInfo(xid, tcon);
2204 }
Steve French50c2f752007-07-13 00:33:32 +00002205
Steve French8af18972007-02-14 04:42:51 +00002206 /* tell server which Unix caps we support */
2207 if (tcon->ses->capabilities & CAP_UNIX)
Steve Frenchc18c8422007-07-18 23:21:09 +00002208 /* reset of caps checks mount to see if unix extensions
2209 disabled for just this mount */
Steve French8af18972007-02-14 04:42:51 +00002210 reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
Steve Frenchc18c8422007-07-18 23:21:09 +00002211 else
2212 tcon->unix_ext = 0; /* server does not support them */
2213
2214 if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
Steve French75865f82007-06-24 18:30:48 +00002215 cifs_sb->rsize = 1024 * 127;
2216#ifdef CONFIG_CIFS_DEBUG2
Steve Frenchc18c8422007-07-18 23:21:09 +00002217 cFYI(1, ("no very large read support, rsize now 127K"));
Steve French75865f82007-06-24 18:30:48 +00002218#endif
Steve French75865f82007-06-24 18:30:48 +00002219 }
Steve French3e844692005-10-03 13:37:24 -07002220 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
2221 cifs_sb->wsize = min(cifs_sb->wsize,
2222 (tcon->ses->server->maxBuf -
2223 MAX_CIFS_HDR_SIZE));
Steve French0ae0efa2005-10-10 10:57:19 -07002224 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
Steve French50c2f752007-07-13 00:33:32 +00002225 cifs_sb->rsize = min(cifs_sb->rsize,
2226 (tcon->ses->server->maxBuf -
2227 MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 }
2229
2230 /* volume_info.password is freed above when existing session found
2231 (in which case it is not needed anymore) but when new sesion is created
2232 the password ptr is put in the new session structure (in which case the
2233 password will be freed at unmount time) */
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002234 kfree(volume_info.UNC);
Steve French2fe87f02006-09-21 07:02:52 +00002235 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 FreeXid(xid);
2237 return rc;
2238}
2239
2240static int
2241CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French7c7b25b2006-06-01 19:20:10 +00002242 char session_key[CIFS_SESS_KEY_SIZE],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 const struct nls_table *nls_codepage)
2244{
2245 struct smb_hdr *smb_buffer;
2246 struct smb_hdr *smb_buffer_response;
2247 SESSION_SETUP_ANDX *pSMB;
2248 SESSION_SETUP_ANDX *pSMBr;
2249 char *bcc_ptr;
2250 char *user;
2251 char *domain;
2252 int rc = 0;
2253 int remaining_words = 0;
2254 int bytes_returned = 0;
2255 int len;
2256 __u32 capabilities;
2257 __u16 count;
2258
Steve Frencheeac8042006-01-13 21:34:58 -08002259 cFYI(1, ("In sesssetup"));
Steve French4523cc32007-04-30 20:13:06 +00002260 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261 return -EINVAL;
2262 user = ses->userName;
2263 domain = ses->domainName;
2264 smb_buffer = cifs_buf_get();
2265 if (smb_buffer == NULL) {
2266 return -ENOMEM;
2267 }
2268 smb_buffer_response = smb_buffer;
2269 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2270
2271 /* send SMBsessionSetup here */
2272 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2273 NULL /* no tCon exists yet */ , 13 /* wct */ );
2274
Steve French1982c342005-08-17 12:38:22 -07002275 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276 pSMB->req_no_secext.AndXCommand = 0xFF;
2277 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2278 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2279
Steve French50c2f752007-07-13 00:33:32 +00002280 if (ses->server->secMode &
2281 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2283
2284 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2285 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
2286 if (ses->capabilities & CAP_UNICODE) {
2287 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2288 capabilities |= CAP_UNICODE;
2289 }
2290 if (ses->capabilities & CAP_STATUS32) {
2291 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2292 capabilities |= CAP_STATUS32;
2293 }
2294 if (ses->capabilities & CAP_DFS) {
2295 smb_buffer->Flags2 |= SMBFLG2_DFS;
2296 capabilities |= CAP_DFS;
2297 }
2298 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
2299
Steve French50c2f752007-07-13 00:33:32 +00002300 pSMB->req_no_secext.CaseInsensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002301 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302
2303 pSMB->req_no_secext.CaseSensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002304 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305 bcc_ptr = pByteArea(smb_buffer);
Steve French7c7b25b2006-06-01 19:20:10 +00002306 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2307 bcc_ptr += CIFS_SESS_KEY_SIZE;
2308 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2309 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310
2311 if (ses->capabilities & CAP_UNICODE) {
2312 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
2313 *bcc_ptr = 0;
2314 bcc_ptr++;
2315 }
Steve French4523cc32007-04-30 20:13:06 +00002316 if (user == NULL)
Steve French39798772006-05-31 22:40:51 +00002317 bytes_returned = 0; /* skip null user */
Steve French50c2f752007-07-13 00:33:32 +00002318 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319 bytes_returned =
Steve French50c2f752007-07-13 00:33:32 +00002320 cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321 nls_codepage);
2322 /* convert number of 16 bit words to bytes */
2323 bcc_ptr += 2 * bytes_returned;
2324 bcc_ptr += 2; /* trailing null */
2325 if (domain == NULL)
2326 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002327 cifs_strtoUCS((__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 "CIFS_LINUX_DOM", 32, nls_codepage);
2329 else
2330 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002331 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332 nls_codepage);
2333 bcc_ptr += 2 * bytes_returned;
2334 bcc_ptr += 2;
2335 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002336 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337 32, nls_codepage);
2338 bcc_ptr += 2 * bytes_returned;
2339 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002340 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341 32, nls_codepage);
2342 bcc_ptr += 2 * bytes_returned;
2343 bcc_ptr += 2;
2344 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002345 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346 64, nls_codepage);
2347 bcc_ptr += 2 * bytes_returned;
2348 bcc_ptr += 2;
2349 } else {
Steve French50c2f752007-07-13 00:33:32 +00002350 if (user != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351 strncpy(bcc_ptr, user, 200);
2352 bcc_ptr += strnlen(user, 200);
2353 }
2354 *bcc_ptr = 0;
2355 bcc_ptr++;
2356 if (domain == NULL) {
2357 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2358 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2359 } else {
2360 strncpy(bcc_ptr, domain, 64);
2361 bcc_ptr += strnlen(domain, 64);
2362 *bcc_ptr = 0;
2363 bcc_ptr++;
2364 }
2365 strcpy(bcc_ptr, "Linux version ");
2366 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002367 strcpy(bcc_ptr, utsname()->release);
2368 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2370 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2371 }
2372 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2373 smb_buffer->smb_buf_length += count;
2374 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2375
2376 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2377 &bytes_returned, 1);
2378 if (rc) {
2379/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2380 } else if ((smb_buffer_response->WordCount == 3)
2381 || (smb_buffer_response->WordCount == 4)) {
2382 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2383 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2384 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002385 cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */
2386 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format
2387 (little endian) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388 cFYI(1, ("UID = %d ", ses->Suid));
Steve French50c2f752007-07-13 00:33:32 +00002389 /* response can have either 3 or 4 word count - Samba sends 3 */
2390 bcc_ptr = pByteArea(smb_buffer_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391 if ((pSMBr->resp.hdr.WordCount == 3)
2392 || ((pSMBr->resp.hdr.WordCount == 4)
2393 && (blob_len < pSMBr->resp.ByteCount))) {
2394 if (pSMBr->resp.hdr.WordCount == 4)
2395 bcc_ptr += blob_len;
2396
2397 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2398 if ((long) (bcc_ptr) % 2) {
2399 remaining_words =
Steve French50c2f752007-07-13 00:33:32 +00002400 (BCC(smb_buffer_response) - 1) / 2;
2401 /* Unicode strings must be word
2402 aligned */
2403 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 } else {
2405 remaining_words =
2406 BCC(smb_buffer_response) / 2;
2407 }
2408 len =
2409 UniStrnlen((wchar_t *) bcc_ptr,
2410 remaining_words - 1);
2411/* We look for obvious messed up bcc or strings in response so we do not go off
2412 the end since (at least) WIN2K and Windows XP have a major bug in not null
2413 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002414 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002415 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002416 ses->serverOS = kzalloc(2 * (len + 1),
2417 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002418 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002419 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420 cifs_strfromUCS_le(ses->serverOS,
Steve French50c2f752007-07-13 00:33:32 +00002421 (__le16 *)bcc_ptr,
2422 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423 bcc_ptr += 2 * (len + 1);
2424 remaining_words -= len + 1;
2425 ses->serverOS[2 * len] = 0;
2426 ses->serverOS[1 + (2 * len)] = 0;
2427 if (remaining_words > 0) {
2428 len = UniStrnlen((wchar_t *)bcc_ptr,
2429 remaining_words-1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002430 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002431 ses->serverNOS = kzalloc(2 * (len + 1),
2432 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002433 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002434 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435 cifs_strfromUCS_le(ses->serverNOS,
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->serverNOS[2 * len] = 0;
2440 ses->serverNOS[1 + (2 * len)] = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002441 if (strncmp(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002442 "NT LAN Manager 4", 16) == 0) {
Steve French467a8f82007-06-27 22:41:32 +00002443 cFYI(1, ("NT4 server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444 ses->flags |= CIFS_SES_NT4;
2445 }
2446 remaining_words -= len + 1;
2447 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002448 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Steve French50c2f752007-07-13 00:33:32 +00002449 /* last string is not always null terminated
2450 (for e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002451 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002452 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 ses->serverDomain =
Steve French50c2f752007-07-13 00:33:32 +00002454 kzalloc(2*(len+1),
2455 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002456 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002457 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458 cifs_strfromUCS_le(ses->serverDomain,
Steve French50c2f752007-07-13 00:33:32 +00002459 (__le16 *)bcc_ptr,
2460 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 bcc_ptr += 2 * (len + 1);
2462 ses->serverDomain[2*len] = 0;
2463 ses->serverDomain[1+(2*len)] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002464 } else { /* else no more room so create
2465 dummy domain string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002466 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002467 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002468 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002469 kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002470 }
Steve French50c2f752007-07-13 00:33:32 +00002471 } else { /* no room so create dummy domain
2472 and NOS string */
2473
Steve French433dc242005-04-28 22:41:08 -07002474 /* if these kcallocs fail not much we
2475 can do, but better to not fail the
2476 sesssetup itself */
Steve Frenchcd49b492006-06-26 04:22:36 +00002477 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002479 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002480 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002482 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483 }
2484 } else { /* ASCII */
2485 len = strnlen(bcc_ptr, 1024);
2486 if (((long) bcc_ptr + len) - (long)
2487 pByteArea(smb_buffer_response)
2488 <= BCC(smb_buffer_response)) {
Steve Frenchcd49b492006-06-26 04:22:36 +00002489 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002490 ses->serverOS = kzalloc(len + 1,
2491 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002492 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002493 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002494 strncpy(ses->serverOS, bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495
2496 bcc_ptr += len;
Steve French50c2f752007-07-13 00:33:32 +00002497 /* null terminate the string */
2498 bcc_ptr[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499 bcc_ptr++;
2500
2501 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002502 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002503 ses->serverNOS = kzalloc(len + 1,
2504 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002505 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002506 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507 strncpy(ses->serverNOS, bcc_ptr, len);
2508 bcc_ptr += len;
2509 bcc_ptr[0] = 0;
2510 bcc_ptr++;
2511
2512 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002513 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002514 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002515 ses->serverDomain = kzalloc(len + 1,
2516 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002517 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002518 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002519 strncpy(ses->serverDomain, bcc_ptr,
2520 len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 bcc_ptr += len;
2522 bcc_ptr[0] = 0;
2523 bcc_ptr++;
2524 } else
2525 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00002526 ("Variable field of length %d "
2527 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528 len));
2529 }
2530 } else {
2531 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00002532 (" Security Blob Length extends beyond "
2533 "end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534 }
2535 } else {
2536 cERROR(1,
2537 (" Invalid Word count %d: ",
2538 smb_buffer_response->WordCount));
2539 rc = -EIO;
2540 }
Steve French433dc242005-04-28 22:41:08 -07002541sesssetup_nomem: /* do not return an error on nomem for the info strings,
2542 since that could make reconnection harder, and
2543 reconnection might be needed to free memory */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00002544 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545
2546 return rc;
2547}
2548
2549static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
Steve French50c2f752007-07-13 00:33:32 +00002551 struct cifsSesInfo *ses, int *pNTLMv2_flag,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552 const struct nls_table *nls_codepage)
2553{
2554 struct smb_hdr *smb_buffer;
2555 struct smb_hdr *smb_buffer_response;
2556 SESSION_SETUP_ANDX *pSMB;
2557 SESSION_SETUP_ANDX *pSMBr;
2558 char *bcc_ptr;
2559 char *domain;
2560 int rc = 0;
2561 int remaining_words = 0;
2562 int bytes_returned = 0;
2563 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002564 int SecurityBlobLength = sizeof(NEGOTIATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565 PNEGOTIATE_MESSAGE SecurityBlob;
2566 PCHALLENGE_MESSAGE SecurityBlob2;
2567 __u32 negotiate_flags, capabilities;
2568 __u16 count;
2569
Steve French12b3b8f2006-02-09 21:12:47 +00002570 cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002571 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572 return -EINVAL;
2573 domain = ses->domainName;
2574 *pNTLMv2_flag = FALSE;
2575 smb_buffer = cifs_buf_get();
2576 if (smb_buffer == NULL) {
2577 return -ENOMEM;
2578 }
2579 smb_buffer_response = smb_buffer;
2580 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2581 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2582
2583 /* send SMBsessionSetup here */
2584 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2585 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002586
2587 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2589 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2590
2591 pSMB->req.AndXCommand = 0xFF;
2592 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2593 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2594
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002595 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2597
2598 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2599 CAP_EXTENDED_SECURITY;
2600 if (ses->capabilities & CAP_UNICODE) {
2601 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2602 capabilities |= CAP_UNICODE;
2603 }
2604 if (ses->capabilities & CAP_STATUS32) {
2605 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2606 capabilities |= CAP_STATUS32;
2607 }
2608 if (ses->capabilities & CAP_DFS) {
2609 smb_buffer->Flags2 |= SMBFLG2_DFS;
2610 capabilities |= CAP_DFS;
2611 }
2612 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2613
2614 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2615 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2616 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2617 SecurityBlob->MessageType = NtLmNegotiate;
2618 negotiate_flags =
2619 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
Steve French12b3b8f2006-02-09 21:12:47 +00002620 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
2621 NTLMSSP_NEGOTIATE_56 |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002623 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002625/* if (ntlmv2_support)
Steve French39798772006-05-31 22:40:51 +00002626 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627 /* setup pointers to domain name and workstation name */
2628 bcc_ptr += SecurityBlobLength;
2629
2630 SecurityBlob->WorkstationName.Buffer = 0;
2631 SecurityBlob->WorkstationName.Length = 0;
2632 SecurityBlob->WorkstationName.MaximumLength = 0;
2633
Steve French12b3b8f2006-02-09 21:12:47 +00002634 /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent
2635 along with username on auth request (ie the response to challenge) */
2636 SecurityBlob->DomainName.Buffer = 0;
2637 SecurityBlob->DomainName.Length = 0;
2638 SecurityBlob->DomainName.MaximumLength = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 if (ses->capabilities & CAP_UNICODE) {
2640 if ((long) bcc_ptr % 2) {
2641 *bcc_ptr = 0;
2642 bcc_ptr++;
2643 }
2644
2645 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002646 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 32, nls_codepage);
2648 bcc_ptr += 2 * bytes_returned;
2649 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002650 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 nls_codepage);
2652 bcc_ptr += 2 * bytes_returned;
2653 bcc_ptr += 2; /* null terminate Linux version */
2654 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002655 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 64, nls_codepage);
2657 bcc_ptr += 2 * bytes_returned;
2658 *(bcc_ptr + 1) = 0;
2659 *(bcc_ptr + 2) = 0;
2660 bcc_ptr += 2; /* null terminate network opsys string */
2661 *(bcc_ptr + 1) = 0;
2662 *(bcc_ptr + 2) = 0;
2663 bcc_ptr += 2; /* null domain */
2664 } else { /* ASCII */
2665 strcpy(bcc_ptr, "Linux version ");
2666 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002667 strcpy(bcc_ptr, utsname()->release);
2668 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2670 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2671 bcc_ptr++; /* empty domain field */
2672 *bcc_ptr = 0;
2673 }
2674 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2675 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2676 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2677 smb_buffer->smb_buf_length += count;
2678 pSMB->req.ByteCount = cpu_to_le16(count);
2679
2680 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
2681 &bytes_returned, 1);
2682
2683 if (smb_buffer_response->Status.CifsError ==
2684 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2685 rc = 0;
2686
2687 if (rc) {
2688/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2689 } else if ((smb_buffer_response->WordCount == 3)
2690 || (smb_buffer_response->WordCount == 4)) {
2691 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2692 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2693
2694 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002695 cFYI(1, (" Guest login"));
2696 /* Do we want to set anything in SesInfo struct when guest login? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697
Steve French50c2f752007-07-13 00:33:32 +00002698 bcc_ptr = pByteArea(smb_buffer_response);
2699 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700
2701 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2702 if (SecurityBlob2->MessageType != NtLmChallenge) {
2703 cFYI(1,
2704 ("Unexpected NTLMSSP message type received %d",
2705 SecurityBlob2->MessageType));
2706 } else if (ses) {
Steve French50c2f752007-07-13 00:33:32 +00002707 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
Steve French12b3b8f2006-02-09 21:12:47 +00002708 cFYI(1, ("UID = %d", ses->Suid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 if ((pSMBr->resp.hdr.WordCount == 3)
2710 || ((pSMBr->resp.hdr.WordCount == 4)
2711 && (blob_len <
2712 pSMBr->resp.ByteCount))) {
2713
2714 if (pSMBr->resp.hdr.WordCount == 4) {
2715 bcc_ptr += blob_len;
Steve French12b3b8f2006-02-09 21:12:47 +00002716 cFYI(1, ("Security Blob Length %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 blob_len));
2718 }
2719
Steve French12b3b8f2006-02-09 21:12:47 +00002720 cFYI(1, ("NTLMSSP Challenge rcvd"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721
2722 memcpy(ses->server->cryptKey,
2723 SecurityBlob2->Challenge,
2724 CIFS_CRYPTO_KEY_SIZE);
Steve French50c2f752007-07-13 00:33:32 +00002725 if (SecurityBlob2->NegotiateFlags &
Steve French12b3b8f2006-02-09 21:12:47 +00002726 cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 *pNTLMv2_flag = TRUE;
2728
Steve French50c2f752007-07-13 00:33:32 +00002729 if ((SecurityBlob2->NegotiateFlags &
2730 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731 || (sign_CIFS_PDUs > 1))
Steve French50c2f752007-07-13 00:33:32 +00002732 ses->server->secMode |=
2733 SECMODE_SIGN_REQUIRED;
2734 if ((SecurityBlob2->NegotiateFlags &
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
Steve French50c2f752007-07-13 00:33:32 +00002736 ses->server->secMode |=
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 SECMODE_SIGN_ENABLED;
2738
2739 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2740 if ((long) (bcc_ptr) % 2) {
2741 remaining_words =
2742 (BCC(smb_buffer_response)
2743 - 1) / 2;
Steve French50c2f752007-07-13 00:33:32 +00002744 /* Must word align unicode strings */
2745 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746 } else {
2747 remaining_words =
2748 BCC
2749 (smb_buffer_response) / 2;
2750 }
2751 len =
2752 UniStrnlen((wchar_t *) bcc_ptr,
2753 remaining_words - 1);
2754/* We look for obvious messed up bcc or strings in response so we do not go off
2755 the end since (at least) WIN2K and Windows XP have a major bug in not null
2756 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002757 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002758 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002760 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002762 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 bcc_ptr, len,
2764 nls_codepage);
2765 bcc_ptr += 2 * (len + 1);
2766 remaining_words -= len + 1;
2767 ses->serverOS[2 * len] = 0;
2768 ses->serverOS[1 + (2 * len)] = 0;
2769 if (remaining_words > 0) {
2770 len = UniStrnlen((wchar_t *)
2771 bcc_ptr,
2772 remaining_words
2773 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002774 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002776 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 GFP_KERNEL);
2778 cifs_strfromUCS_le(ses->
2779 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002780 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 bcc_ptr,
2782 len,
2783 nls_codepage);
2784 bcc_ptr += 2 * (len + 1);
2785 ses->serverNOS[2 * len] = 0;
2786 ses->serverNOS[1 +
2787 (2 * len)] = 0;
2788 remaining_words -= len + 1;
2789 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00002790 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2791 /* last string not always null terminated
2792 (for e.g. for Windows XP & 2000) */
Steve Frenchcd49b492006-06-26 04:22:36 +00002793 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002795 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 (len +
2797 1),
2798 GFP_KERNEL);
2799 cifs_strfromUCS_le
Steve Frenche89dc922005-11-11 15:18:19 -08002800 (ses->serverDomain,
2801 (__le16 *)bcc_ptr,
2802 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803 bcc_ptr +=
2804 2 * (len + 1);
Steve Frenche89dc922005-11-11 15:18:19 -08002805 ses->serverDomain[2*len]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806 = 0;
Steve Frenche89dc922005-11-11 15:18:19 -08002807 ses->serverDomain
2808 [1 + (2 * len)]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 = 0;
2810 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002811 else {
Steve Frenchcd49b492006-06-26 04:22:36 +00002812 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002814 kzalloc(2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815 GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002816 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817 } else { /* no room so create dummy domain and NOS string */
Steve Frenchcd49b492006-06-26 04:22:36 +00002818 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002820 kzalloc(2, GFP_KERNEL);
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(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824 }
2825 } else { /* ASCII */
2826 len = strnlen(bcc_ptr, 1024);
2827 if (((long) bcc_ptr + len) - (long)
2828 pByteArea(smb_buffer_response)
2829 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002830 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002831 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002833 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834 GFP_KERNEL);
2835 strncpy(ses->serverOS,
2836 bcc_ptr, len);
2837
2838 bcc_ptr += len;
2839 bcc_ptr[0] = 0; /* null terminate string */
2840 bcc_ptr++;
2841
2842 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002843 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002845 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846 GFP_KERNEL);
2847 strncpy(ses->serverNOS, bcc_ptr, len);
2848 bcc_ptr += len;
2849 bcc_ptr[0] = 0;
2850 bcc_ptr++;
2851
2852 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002853 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002854 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002855 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +00002857 strncpy(ses->serverDomain,
2858 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859 bcc_ptr += len;
2860 bcc_ptr[0] = 0;
2861 bcc_ptr++;
2862 } else
2863 cFYI(1,
Steve French63135e02007-07-17 17:34:02 +00002864 ("field of length %d "
2865 "extends beyond end of smb",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866 len));
2867 }
2868 } else {
Steve French50c2f752007-07-13 00:33:32 +00002869 cERROR(1, ("Security Blob Length extends beyond"
2870 " end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871 }
2872 } else {
2873 cERROR(1, ("No session structure passed in."));
2874 }
2875 } else {
2876 cERROR(1,
Steve French5815449d2006-02-14 01:36:20 +00002877 (" Invalid Word count %d:",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878 smb_buffer_response->WordCount));
2879 rc = -EIO;
2880 }
2881
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00002882 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883
2884 return rc;
2885}
2886static int
2887CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002888 char *ntlm_session_key, int ntlmv2_flag,
2889 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890{
2891 struct smb_hdr *smb_buffer;
2892 struct smb_hdr *smb_buffer_response;
2893 SESSION_SETUP_ANDX *pSMB;
2894 SESSION_SETUP_ANDX *pSMBr;
2895 char *bcc_ptr;
2896 char *user;
2897 char *domain;
2898 int rc = 0;
2899 int remaining_words = 0;
2900 int bytes_returned = 0;
2901 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002902 int SecurityBlobLength = sizeof(AUTHENTICATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903 PAUTHENTICATE_MESSAGE SecurityBlob;
2904 __u32 negotiate_flags, capabilities;
2905 __u16 count;
2906
2907 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002908 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909 return -EINVAL;
2910 user = ses->userName;
2911 domain = ses->domainName;
2912 smb_buffer = cifs_buf_get();
2913 if (smb_buffer == NULL) {
2914 return -ENOMEM;
2915 }
2916 smb_buffer_response = smb_buffer;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002917 pSMB = (SESSION_SETUP_ANDX *)smb_buffer;
2918 pSMBr = (SESSION_SETUP_ANDX *)smb_buffer_response;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919
2920 /* send SMBsessionSetup here */
2921 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2922 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002923
2924 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2926 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2927 pSMB->req.AndXCommand = 0xFF;
2928 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2929 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2930
2931 pSMB->req.hdr.Uid = ses->Suid;
2932
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002933 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2935
2936 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002937 CAP_EXTENDED_SECURITY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938 if (ses->capabilities & CAP_UNICODE) {
2939 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2940 capabilities |= CAP_UNICODE;
2941 }
2942 if (ses->capabilities & CAP_STATUS32) {
2943 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2944 capabilities |= CAP_STATUS32;
2945 }
2946 if (ses->capabilities & CAP_DFS) {
2947 smb_buffer->Flags2 |= SMBFLG2_DFS;
2948 capabilities |= CAP_DFS;
2949 }
2950 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2951
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002952 bcc_ptr = (char *)&pSMB->req.SecurityBlob;
2953 SecurityBlob = (PAUTHENTICATE_MESSAGE)bcc_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2955 SecurityBlob->MessageType = NtLmAuthenticate;
2956 bcc_ptr += SecurityBlobLength;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002957 negotiate_flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
2958 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
2959 0x80000000 | NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002960 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002962 if (ntlmv2_flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
2964
2965/* setup pointers to domain name and workstation name */
2966
2967 SecurityBlob->WorkstationName.Buffer = 0;
2968 SecurityBlob->WorkstationName.Length = 0;
2969 SecurityBlob->WorkstationName.MaximumLength = 0;
2970 SecurityBlob->SessionKey.Length = 0;
2971 SecurityBlob->SessionKey.MaximumLength = 0;
2972 SecurityBlob->SessionKey.Buffer = 0;
2973
2974 SecurityBlob->LmChallengeResponse.Length = 0;
2975 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
2976 SecurityBlob->LmChallengeResponse.Buffer = 0;
2977
2978 SecurityBlob->NtChallengeResponse.Length =
Steve French7c7b25b2006-06-01 19:20:10 +00002979 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980 SecurityBlob->NtChallengeResponse.MaximumLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002981 cpu_to_le16(CIFS_SESS_KEY_SIZE);
2982 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983 SecurityBlob->NtChallengeResponse.Buffer =
2984 cpu_to_le32(SecurityBlobLength);
Steve French7c7b25b2006-06-01 19:20:10 +00002985 SecurityBlobLength += CIFS_SESS_KEY_SIZE;
2986 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987
2988 if (ses->capabilities & CAP_UNICODE) {
2989 if (domain == NULL) {
2990 SecurityBlob->DomainName.Buffer = 0;
2991 SecurityBlob->DomainName.Length = 0;
2992 SecurityBlob->DomainName.MaximumLength = 0;
2993 } else {
Steve French77159b42007-08-31 01:10:17 +00002994 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00002996 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00002998 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999 SecurityBlob->DomainName.Buffer =
3000 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003001 bcc_ptr += ln;
3002 SecurityBlobLength += ln;
3003 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004 }
3005 if (user == NULL) {
3006 SecurityBlob->UserName.Buffer = 0;
3007 SecurityBlob->UserName.Length = 0;
3008 SecurityBlob->UserName.MaximumLength = 0;
3009 } else {
Steve French77159b42007-08-31 01:10:17 +00003010 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00003012 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013 SecurityBlob->UserName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003014 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015 SecurityBlob->UserName.Buffer =
3016 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003017 bcc_ptr += ln;
3018 SecurityBlobLength += ln;
3019 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020 }
3021
Steve French63135e02007-07-17 17:34:02 +00003022 /* SecurityBlob->WorkstationName.Length =
3023 cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 SecurityBlob->WorkstationName.Length *= 2;
Steve French63135e02007-07-17 17:34:02 +00003025 SecurityBlob->WorkstationName.MaximumLength =
3026 cpu_to_le16(SecurityBlob->WorkstationName.Length);
3027 SecurityBlob->WorkstationName.Buffer =
3028 cpu_to_le32(SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029 bcc_ptr += SecurityBlob->WorkstationName.Length;
3030 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
Steve French63135e02007-07-17 17:34:02 +00003031 SecurityBlob->WorkstationName.Length =
3032 cpu_to_le16(SecurityBlob->WorkstationName.Length); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033
3034 if ((long) bcc_ptr % 2) {
3035 *bcc_ptr = 0;
3036 bcc_ptr++;
3037 }
3038 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003039 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003040 32, nls_codepage);
3041 bcc_ptr += 2 * bytes_returned;
3042 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003043 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044 nls_codepage);
3045 bcc_ptr += 2 * bytes_returned;
3046 bcc_ptr += 2; /* null term version string */
3047 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003048 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003049 64, nls_codepage);
3050 bcc_ptr += 2 * bytes_returned;
3051 *(bcc_ptr + 1) = 0;
3052 *(bcc_ptr + 2) = 0;
3053 bcc_ptr += 2; /* null terminate network opsys string */
3054 *(bcc_ptr + 1) = 0;
3055 *(bcc_ptr + 2) = 0;
3056 bcc_ptr += 2; /* null domain */
3057 } else { /* ASCII */
3058 if (domain == NULL) {
3059 SecurityBlob->DomainName.Buffer = 0;
3060 SecurityBlob->DomainName.Length = 0;
3061 SecurityBlob->DomainName.MaximumLength = 0;
3062 } else {
Steve French77159b42007-08-31 01:10:17 +00003063 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
3065 strncpy(bcc_ptr, domain, 63);
Steve French77159b42007-08-31 01:10:17 +00003066 ln = strnlen(domain, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003067 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003068 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069 SecurityBlob->DomainName.Buffer =
3070 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003071 bcc_ptr += ln;
3072 SecurityBlobLength += ln;
3073 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003074 }
3075 if (user == NULL) {
3076 SecurityBlob->UserName.Buffer = 0;
3077 SecurityBlob->UserName.Length = 0;
3078 SecurityBlob->UserName.MaximumLength = 0;
3079 } else {
Steve French77159b42007-08-31 01:10:17 +00003080 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081 strncpy(bcc_ptr, user, 63);
Steve French77159b42007-08-31 01:10:17 +00003082 ln = strnlen(user, 64);
3083 SecurityBlob->UserName.MaximumLength = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084 SecurityBlob->UserName.Buffer =
Steve French77159b42007-08-31 01:10:17 +00003085 cpu_to_le32(SecurityBlobLength);
3086 bcc_ptr += ln;
3087 SecurityBlobLength += ln;
3088 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089 }
3090 /* BB fill in our workstation name if known BB */
3091
3092 strcpy(bcc_ptr, "Linux version ");
3093 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003094 strcpy(bcc_ptr, utsname()->release);
3095 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
3097 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
3098 bcc_ptr++; /* null domain */
3099 *bcc_ptr = 0;
3100 }
3101 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
3102 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
3103 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
3104 smb_buffer->smb_buf_length += count;
3105 pSMB->req.ByteCount = cpu_to_le16(count);
3106
3107 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
3108 &bytes_returned, 1);
3109 if (rc) {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003110/* rc = map_smb_to_linux_error(smb_buffer_response) done in SendReceive now */
3111 } else if ((smb_buffer_response->WordCount == 3) ||
3112 (smb_buffer_response->WordCount == 4)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003113 __u16 action = le16_to_cpu(pSMBr->resp.Action);
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003114 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00003116 cFYI(1, (" Guest login")); /* BB Should we set anything
3117 in SesInfo struct ? */
3118/* if (SecurityBlob2->MessageType != NtLm??) {
3119 cFYI("Unexpected message type on auth response is %d"));
3120 } */
3121
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122 if (ses) {
3123 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003124 ("Check challenge UID %d vs auth response UID %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125 ses->Suid, smb_buffer_response->Uid));
Steve French50c2f752007-07-13 00:33:32 +00003126 /* UID left in wire format */
3127 ses->Suid = smb_buffer_response->Uid;
3128 bcc_ptr = pByteArea(smb_buffer_response);
3129 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130 if ((pSMBr->resp.hdr.WordCount == 3)
3131 || ((pSMBr->resp.hdr.WordCount == 4)
3132 && (blob_len <
3133 pSMBr->resp.ByteCount))) {
3134 if (pSMBr->resp.hdr.WordCount == 4) {
3135 bcc_ptr +=
3136 blob_len;
3137 cFYI(1,
3138 ("Security Blob Length %d ",
3139 blob_len));
3140 }
3141
3142 cFYI(1,
3143 ("NTLMSSP response to Authenticate "));
3144
3145 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3146 if ((long) (bcc_ptr) % 2) {
3147 remaining_words =
3148 (BCC(smb_buffer_response)
3149 - 1) / 2;
3150 bcc_ptr++; /* Unicode strings must be word aligned */
3151 } else {
3152 remaining_words = BCC(smb_buffer_response) / 2;
3153 }
Steve French77159b42007-08-31 01:10:17 +00003154 len = UniStrnlen((wchar_t *) bcc_ptr,
3155 remaining_words - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156/* We look for obvious messed up bcc or strings in response so we do not go off
3157 the end since (at least) WIN2K and Windows XP have a major bug in not null
3158 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003159 if (ses->serverOS)
Steve French08775832006-05-30 18:08:26 +00003160 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003162 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003163 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003164 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165 bcc_ptr, len,
3166 nls_codepage);
3167 bcc_ptr += 2 * (len + 1);
3168 remaining_words -= len + 1;
3169 ses->serverOS[2 * len] = 0;
3170 ses->serverOS[1 + (2 * len)] = 0;
3171 if (remaining_words > 0) {
3172 len = UniStrnlen((wchar_t *)
3173 bcc_ptr,
3174 remaining_words
3175 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00003176 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003178 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179 GFP_KERNEL);
3180 cifs_strfromUCS_le(ses->
3181 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003182 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003183 bcc_ptr,
3184 len,
3185 nls_codepage);
3186 bcc_ptr += 2 * (len + 1);
3187 ses->serverNOS[2 * len] = 0;
3188 ses->serverNOS[1+(2*len)] = 0;
3189 remaining_words -= len + 1;
3190 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00003191 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192 /* last string not always null terminated (e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003193 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003194 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003196 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197 (len +
3198 1),
3199 GFP_KERNEL);
3200 cifs_strfromUCS_le
3201 (ses->
3202 serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08003203 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003204 bcc_ptr, len,
3205 nls_codepage);
3206 bcc_ptr +=
3207 2 * (len + 1);
3208 ses->
3209 serverDomain[2
3210 * len]
3211 = 0;
3212 ses->
3213 serverDomain[1
3214 +
3215 (2
3216 *
3217 len)]
3218 = 0;
3219 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003220 else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003221 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003222 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003223 ses->serverDomain = kzalloc(2,GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00003224 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003225 } else { /* no room so create dummy domain and NOS string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003226 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003227 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003228 ses->serverDomain = kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00003229 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003230 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003231 }
3232 } else { /* ASCII */
3233 len = strnlen(bcc_ptr, 1024);
Steve French50c2f752007-07-13 00:33:32 +00003234 if (((long) bcc_ptr + len) -
3235 (long) pByteArea(smb_buffer_response)
Steve French63135e02007-07-17 17:34:02 +00003236 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003237 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00003238 kfree(ses->serverOS);
Steve French77159b42007-08-31 01:10:17 +00003239 ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240 strncpy(ses->serverOS,bcc_ptr, len);
3241
3242 bcc_ptr += len;
3243 bcc_ptr[0] = 0; /* null terminate the string */
3244 bcc_ptr++;
3245
3246 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003247 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00003248 ses->serverNOS = kzalloc(len+1,
3249 GFP_KERNEL);
Steve French63135e02007-07-17 17:34:02 +00003250 strncpy(ses->serverNOS,
3251 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003252 bcc_ptr += len;
3253 bcc_ptr[0] = 0;
3254 bcc_ptr++;
3255
3256 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003257 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003258 kfree(ses->serverDomain);
Steve French63135e02007-07-17 17:34:02 +00003259 ses->serverDomain =
3260 kzalloc(len+1,
3261 GFP_KERNEL);
3262 strncpy(ses->serverDomain,
3263 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264 bcc_ptr += len;
3265 bcc_ptr[0] = 0;
3266 bcc_ptr++;
3267 } else
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003268 cFYI(1, ("field of length %d "
Steve French63135e02007-07-17 17:34:02 +00003269 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003270 len));
3271 }
3272 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003273 cERROR(1, ("Security Blob extends beyond end "
Steve French63135e02007-07-17 17:34:02 +00003274 "of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275 }
3276 } else {
3277 cERROR(1, ("No session structure passed in."));
3278 }
3279 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003280 cERROR(1, ("Invalid Word count %d: ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003281 smb_buffer_response->WordCount));
3282 rc = -EIO;
3283 }
3284
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003285 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003286
3287 return rc;
3288}
3289
3290int
3291CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3292 const char *tree, struct cifsTconInfo *tcon,
3293 const struct nls_table *nls_codepage)
3294{
3295 struct smb_hdr *smb_buffer;
3296 struct smb_hdr *smb_buffer_response;
3297 TCONX_REQ *pSMB;
3298 TCONX_RSP *pSMBr;
3299 unsigned char *bcc_ptr;
3300 int rc = 0;
3301 int length;
3302 __u16 count;
3303
3304 if (ses == NULL)
3305 return -EIO;
3306
3307 smb_buffer = cifs_buf_get();
3308 if (smb_buffer == NULL) {
3309 return -ENOMEM;
3310 }
3311 smb_buffer_response = smb_buffer;
3312
3313 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3314 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003315
3316 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317 smb_buffer->Uid = ses->Suid;
3318 pSMB = (TCONX_REQ *) smb_buffer;
3319 pSMBr = (TCONX_RSP *) smb_buffer_response;
3320
3321 pSMB->AndXCommand = 0xFF;
3322 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003323 bcc_ptr = &pSMB->Password[0];
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003324 if ((ses->server->secMode) & SECMODE_USER) {
Steve Frencheeac8042006-01-13 21:34:58 -08003325 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00003326 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08003327 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00003328 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08003329 } else {
Steve French7c7b25b2006-06-01 19:20:10 +00003330 pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08003331 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
3332 specified as required (when that support is added to
3333 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00003334 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08003335 by Samba (not sure whether other servers allow
3336 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00003337#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French50c2f752007-07-13 00:33:32 +00003338 if ((extended_security & CIFSSEC_MAY_LANMAN) &&
Steve French7c7b25b2006-06-01 19:20:10 +00003339 (ses->server->secType == LANMAN))
3340 calc_lanman_hash(ses, bcc_ptr);
3341 else
3342#endif /* CIFS_WEAK_PW_HASH */
Steve Frencheeac8042006-01-13 21:34:58 -08003343 SMBNTencrypt(ses->password,
3344 ses->server->cryptKey,
3345 bcc_ptr);
3346
Steve French7c7b25b2006-06-01 19:20:10 +00003347 bcc_ptr += CIFS_SESS_KEY_SIZE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003348 if (ses->capabilities & CAP_UNICODE) {
Steve French7c7b25b2006-06-01 19:20:10 +00003349 /* must align unicode strings */
3350 *bcc_ptr = 0; /* null byte password */
3351 bcc_ptr++;
3352 }
Steve Frencheeac8042006-01-13 21:34:58 -08003353 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354
Steve French50c2f752007-07-13 00:33:32 +00003355 if (ses->server->secMode &
Steve Frencha878fb22006-05-30 18:04:19 +00003356 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003357 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3358
3359 if (ses->capabilities & CAP_STATUS32) {
3360 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3361 }
3362 if (ses->capabilities & CAP_DFS) {
3363 smb_buffer->Flags2 |= SMBFLG2_DFS;
3364 }
3365 if (ses->capabilities & CAP_UNICODE) {
3366 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3367 length =
Steve French50c2f752007-07-13 00:33:32 +00003368 cifs_strtoUCS((__le16 *) bcc_ptr, tree,
3369 6 /* max utf8 char length in bytes */ *
Steve Frencha878fb22006-05-30 18:04:19 +00003370 (/* server len*/ + 256 /* share len */), nls_codepage);
3371 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372 bcc_ptr += 2; /* skip trailing null */
3373 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003374 strcpy(bcc_ptr, tree);
3375 bcc_ptr += strlen(tree) + 1;
3376 }
3377 strcpy(bcc_ptr, "?????");
3378 bcc_ptr += strlen("?????");
3379 bcc_ptr += 1;
3380 count = bcc_ptr - &pSMB->Password[0];
3381 pSMB->hdr.smb_buf_length += count;
3382 pSMB->ByteCount = cpu_to_le16(count);
3383
3384 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
3385
3386 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3387 /* above now done in SendReceive */
3388 if ((rc == 0) && (tcon != NULL)) {
3389 tcon->tidStatus = CifsGood;
3390 tcon->tid = smb_buffer_response->Tid;
3391 bcc_ptr = pByteArea(smb_buffer_response);
3392 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
Steve French50c2f752007-07-13 00:33:32 +00003393 /* skip service field (NB: this field is always ASCII) */
Steve French7f8ed422007-09-28 22:28:55 +00003394 if (length == 3) {
3395 if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') &&
3396 (bcc_ptr[2] == 'C')) {
3397 cFYI(1, ("IPC connection"));
3398 tcon->ipc = 1;
3399 }
3400 } else if (length == 2) {
3401 if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) {
3402 /* the most common case */
3403 cFYI(1, ("disk share connection"));
3404 }
3405 }
Steve French50c2f752007-07-13 00:33:32 +00003406 bcc_ptr += length + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3408 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3409 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3410 if ((bcc_ptr + (2 * length)) -
3411 pByteArea(smb_buffer_response) <=
3412 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003413 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003415 kzalloc(length + 2, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003416 if (tcon->nativeFileSystem)
3417 cifs_strfromUCS_le(
3418 tcon->nativeFileSystem,
3419 (__le16 *) bcc_ptr,
3420 length, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003421 bcc_ptr += 2 * length;
3422 bcc_ptr[0] = 0; /* null terminate the string */
3423 bcc_ptr[1] = 0;
3424 bcc_ptr += 2;
3425 }
Steve French50c2f752007-07-13 00:33:32 +00003426 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427 } else {
3428 length = strnlen(bcc_ptr, 1024);
3429 if ((bcc_ptr + length) -
3430 pByteArea(smb_buffer_response) <=
3431 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003432 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003434 kzalloc(length + 1, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003435 if (tcon->nativeFileSystem)
3436 strncpy(tcon->nativeFileSystem, bcc_ptr,
3437 length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003438 }
Steve French50c2f752007-07-13 00:33:32 +00003439 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003441 if ((smb_buffer_response->WordCount == 3) ||
Steve French1a4e15a2006-10-12 21:33:51 +00003442 (smb_buffer_response->WordCount == 7))
3443 /* field is in same location */
Steve French39798772006-05-31 22:40:51 +00003444 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3445 else
3446 tcon->Flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003447 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3448 } else if ((rc == 0) && tcon == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00003449 /* all we need to save for IPC$ connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450 ses->ipc_tid = smb_buffer_response->Tid;
3451 }
3452
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003453 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454 return rc;
3455}
3456
3457int
3458cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3459{
3460 int rc = 0;
3461 int xid;
3462 struct cifsSesInfo *ses = NULL;
3463 struct task_struct *cifsd_task;
Steve French50c2f752007-07-13 00:33:32 +00003464 char *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003465
3466 xid = GetXid();
3467
3468 if (cifs_sb->tcon) {
3469 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3470 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3471 if (rc == -EBUSY) {
3472 FreeXid(xid);
3473 return 0;
3474 }
3475 tconInfoFree(cifs_sb->tcon);
3476 if ((ses) && (ses->server)) {
3477 /* save off task so we do not refer to ses later */
3478 cifsd_task = ses->server->tsk;
3479 cFYI(1, ("About to do SMBLogoff "));
3480 rc = CIFSSMBLogoff(xid, ses);
3481 if (rc == -EBUSY) {
3482 FreeXid(xid);
3483 return 0;
3484 } else if (rc == -ESHUTDOWN) {
Steve French467a8f82007-06-27 22:41:32 +00003485 cFYI(1, ("Waking up socket by sending signal"));
Steve Frenchf7f7c312007-05-24 02:29:51 +00003486 if (cifsd_task) {
Steve French50c2f752007-07-13 00:33:32 +00003487 force_sig(SIGKILL, cifsd_task);
Igor Mammedovaaf737a2007-04-03 19:16:43 +00003488 kthread_stop(cifsd_task);
Steve Frenchf1914012005-08-18 09:37:34 -07003489 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490 rc = 0;
3491 } /* else - we have an smb session
3492 left on this socket do not kill cifsd */
3493 } else
3494 cFYI(1, ("No session or bad tcon"));
3495 }
Steve French50c2f752007-07-13 00:33:32 +00003496
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497 cifs_sb->tcon = NULL;
Steve French2fe87f02006-09-21 07:02:52 +00003498 tmp = cifs_sb->prepath;
3499 cifs_sb->prepathlen = 0;
3500 cifs_sb->prepath = NULL;
3501 kfree(tmp);
Nishanth Aravamudan041e0e32005-09-10 00:27:23 -07003502 if (ses)
3503 schedule_timeout_interruptible(msecs_to_jiffies(500));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504 if (ses)
3505 sesInfoFree(ses);
3506
3507 FreeXid(xid);
Steve French50c2f752007-07-13 00:33:32 +00003508 return rc; /* BB check if we should always return zero here */
3509}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003510
3511int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
Steve French50c2f752007-07-13 00:33:32 +00003512 struct nls_table *nls_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003513{
3514 int rc = 0;
Steve French7c7b25b2006-06-01 19:20:10 +00003515 char ntlm_session_key[CIFS_SESS_KEY_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516 int ntlmv2_flag = FALSE;
Steve Frenchad009ac2005-04-28 22:41:05 -07003517 int first_time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518
3519 /* what if server changes its buffer size after dropping the session? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003520 if (pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003522 if (rc == -EAGAIN) /* retry only once on 1st time connection */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve French50c2f752007-07-13 00:33:32 +00003524 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525 rc = -EHOSTDOWN;
3526 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003527 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528 spin_lock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003529 if (pSesInfo->server->tcpStatus != CifsExiting)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530 pSesInfo->server->tcpStatus = CifsGood;
3531 else
3532 rc = -EHOSTDOWN;
3533 spin_unlock(&GlobalMid_Lock);
3534
3535 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003536 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537 }
3538 if (!rc) {
Steve French9ac00b72006-09-30 04:13:17 +00003539 pSesInfo->flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003540 pSesInfo->capabilities = pSesInfo->server->capabilities;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003541 if (linuxExtEnabled == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003543 /* pSesInfo->sequence_number = 0;*/
Steve French50c2f752007-07-13 00:33:32 +00003544 cFYI(1,
3545 ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546 pSesInfo->server->secMode,
3547 pSesInfo->server->capabilities,
Steve French175ec9e2006-09-30 01:07:38 +00003548 pSesInfo->server->timeAdj));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003549 if (experimEnabled < 2)
Steve French39798772006-05-31 22:40:51 +00003550 rc = CIFS_SessSetup(xid, pSesInfo,
3551 first_time, nls_info);
Steve French189acaa2006-06-23 02:33:48 +00003552 else if (extended_security
Steve French50c2f752007-07-13 00:33:32 +00003553 && (pSesInfo->capabilities
Steve French175ec9e2006-09-30 01:07:38 +00003554 & CAP_EXTENDED_SECURITY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555 && (pSesInfo->server->secType == NTLMSSP)) {
Steve French189acaa2006-06-23 02:33:48 +00003556 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557 } else if (extended_security
3558 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3559 && (pSesInfo->server->secType == RawNTLMSSP)) {
Steve French5815449d2006-02-14 01:36:20 +00003560 cFYI(1, ("NTLMSSP sesssetup"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003561 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3562 pSesInfo,
3563 &ntlmv2_flag,
3564 nls_info);
3565 if (!rc) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003566 if (ntlmv2_flag) {
Steve French50c2f752007-07-13 00:33:32 +00003567 char *v2_response;
Steve French467a8f82007-06-27 22:41:32 +00003568 cFYI(1, ("more secure NTLM ver2 hash"));
Steve French50c2f752007-07-13 00:33:32 +00003569 if (CalcNTLMv2_partial_mac_key(pSesInfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570 nls_info)) {
3571 rc = -ENOMEM;
3572 goto ss_err_exit;
3573 } else
3574 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003575 if (v2_response) {
Steve French50c2f752007-07-13 00:33:32 +00003576 CalcNTLMv2_response(pSesInfo,
3577 v2_response);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003578 /* if (first_time)
Steve French50c2f752007-07-13 00:33:32 +00003579 cifs_calculate_ntlmv2_mac_key(
3580 pSesInfo->server->mac_signing_key,
3581 response, ntlm_session_key,*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582 kfree(v2_response);
3583 /* BB Put dummy sig in SessSetup PDU? */
3584 } else {
3585 rc = -ENOMEM;
3586 goto ss_err_exit;
3587 }
3588
3589 } else {
3590 SMBNTencrypt(pSesInfo->password,
3591 pSesInfo->server->cryptKey,
3592 ntlm_session_key);
3593
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003594 if (first_time)
Steve Frenchad009ac2005-04-28 22:41:05 -07003595 cifs_calculate_mac_key(
Steve Frenchb609f062007-07-09 07:55:14 +00003596 &pSesInfo->server->mac_signing_key,
Steve Frenchad009ac2005-04-28 22:41:05 -07003597 ntlm_session_key,
3598 pSesInfo->password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599 }
3600 /* for better security the weaker lanman hash not sent
3601 in AuthSessSetup so we no longer calculate it */
3602
3603 rc = CIFSNTLMSSPAuthSessSetup(xid,
3604 pSesInfo,
3605 ntlm_session_key,
3606 ntlmv2_flag,
3607 nls_info);
3608 }
3609 } else { /* old style NTLM 0.12 session setup */
3610 SMBNTencrypt(pSesInfo->password,
3611 pSesInfo->server->cryptKey,
3612 ntlm_session_key);
3613
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003614 if (first_time)
Steve Frenchad009ac2005-04-28 22:41:05 -07003615 cifs_calculate_mac_key(
Steve Frenchb609f062007-07-09 07:55:14 +00003616 &pSesInfo->server->mac_signing_key,
Steve Frenchad009ac2005-04-28 22:41:05 -07003617 ntlm_session_key, pSesInfo->password);
3618
Linus Torvalds1da177e2005-04-16 15:20:36 -07003619 rc = CIFSSessSetup(xid, pSesInfo,
3620 ntlm_session_key, nls_info);
3621 }
3622 if (rc) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003623 cERROR(1, ("Send error in SessSetup = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003624 } else {
Steve French467a8f82007-06-27 22:41:32 +00003625 cFYI(1, ("CIFS Session Established successfully"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626 pSesInfo->status = CifsGood;
3627 }
3628 }
3629ss_err_exit:
3630 return rc;
3631}
3632