blob: e8fa46c7cff21f82f245e41cbd2cda8f7336d4c7 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/connect.c
3 *
Steve French366781c2008-01-25 10:12:41 +00004 * Copyright (C) International Business Machines Corp., 2002,2008
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
Linus Torvalds1da177e2005-04-16 15:20:36 -070052extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
53 unsigned char *p24);
54
55extern mempool_t *cifs_req_poolp;
56
57struct smb_vol {
58 char *username;
59 char *password;
60 char *domainname;
61 char *UNC;
62 char *UNCip;
Steve French95b1cb92008-05-15 16:44:38 +000063 char *in6_addr; /* ipv6 address as human readable form of in6_addr */
Linus Torvalds1da177e2005-04-16 15:20:36 -070064 char *iocharset; /* local code page for mapping to and from Unicode */
65 char source_rfc1001_name[16]; /* netbios name of client */
Steve Frencha10faeb22005-08-22 21:38:31 -070066 char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 uid_t linux_uid;
68 gid_t linux_gid;
69 mode_t file_mode;
70 mode_t dir_mode;
Steve French189acaa2006-06-23 02:33:48 +000071 unsigned secFlg;
Steve French4b18f2a2008-04-29 00:06:05 +000072 bool rw:1;
73 bool retry:1;
74 bool intr:1;
75 bool setuids:1;
76 bool override_uid:1;
77 bool override_gid:1;
Jeff Laytond0a9c072008-05-12 22:23:49 +000078 bool dynperm:1;
Steve French4b18f2a2008-04-29 00:06:05 +000079 bool noperm:1;
80 bool no_psx_acl:1; /* set if posix acl support should be disabled */
81 bool cifs_acl:1;
82 bool no_xattr:1; /* set if xattr (EA) support should be disabled*/
83 bool server_ino:1; /* use inode numbers from server ie UniqueId */
84 bool direct_io:1;
Steve French95b1cb92008-05-15 16:44:38 +000085 bool remap:1; /* set to remap seven reserved chars in filenames */
86 bool posix_paths:1; /* unset to not ask for posix pathnames. */
Steve French4b18f2a2008-04-29 00:06:05 +000087 bool no_linux_ext:1;
88 bool sfu_emul:1;
Steve French95b1cb92008-05-15 16:44:38 +000089 bool nullauth:1; /* attempt to authenticate with null user */
90 bool nocase:1; /* request case insensitive filenames */
91 bool nobrl:1; /* disable sending byte range locks to srv */
92 bool seal:1; /* request transport encryption on share */
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 French4b18f2a2008-04-29 00:06:05 +0000348 bool isLargeBuf = false;
349 bool isMultiRsp;
Steve Frenche4eb2952005-04-28 22:41:09 -0700350 int reconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 current->flags |= PF_MEMALLOC;
Pavel Emelyanovba25f9d2007-10-18 23:40:40 -0700353 cFYI(1, ("Demultiplex PID: %d", task_pid_nr(current)));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000354 write_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 atomic_inc(&tcpSesAllocCount);
356 length = tcpSesAllocCount.counter;
357 write_unlock(&GlobalSMBSeslock);
Steve French26f57362007-08-30 22:09:15 +0000358 if (length > 1)
359 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
360 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361
Rafael J. Wysocki83144182007-07-17 04:03:35 -0700362 set_freezable();
Igor Mammedovaaf737a2007-04-03 19:16:43 +0000363 while (!kthread_should_stop()) {
Steve Frenchede13272005-08-30 20:10:14 -0700364 if (try_to_freeze())
365 continue;
Steve Frenchb8643e12005-04-28 22:41:07 -0700366 if (bigbuf == NULL) {
367 bigbuf = cifs_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000368 if (!bigbuf) {
369 cERROR(1, ("No memory for large SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700370 msleep(3000);
371 /* retry will check if exiting */
372 continue;
373 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000374 } else if (isLargeBuf) {
375 /* we are reusing a dirty large buf, clear its start */
Steve French26f57362007-08-30 22:09:15 +0000376 memset(bigbuf, 0, sizeof(struct smb_hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700378
379 if (smallbuf == NULL) {
380 smallbuf = cifs_small_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000381 if (!smallbuf) {
382 cERROR(1, ("No memory for SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700383 msleep(1000);
384 /* retry will check if exiting */
385 continue;
386 }
387 /* beginning of smb buffer is cleared in our buf_get */
388 } else /* if existing small buf clear beginning */
Steve French26f57362007-08-30 22:09:15 +0000389 memset(smallbuf, 0, sizeof(struct smb_hdr));
Steve Frenchb8643e12005-04-28 22:41:07 -0700390
Steve French4b18f2a2008-04-29 00:06:05 +0000391 isLargeBuf = false;
392 isMultiRsp = false;
Steve Frenchb8643e12005-04-28 22:41:07 -0700393 smb_buffer = smallbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 iov.iov_base = smb_buffer;
395 iov.iov_len = 4;
396 smb_msg.msg_control = NULL;
397 smb_msg.msg_controllen = 0;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000398 pdu_length = 4; /* enough to get RFC1001 header */
399incomplete_rcv:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 length =
401 kernel_recvmsg(csocket, &smb_msg,
Steve Frenchf01d5e12007-08-30 21:13:31 +0000402 &iov, 1, pdu_length, 0 /* BB other flags? */);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403
Steve French26f57362007-08-30 22:09:15 +0000404 if (kthread_should_stop()) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 break;
406 } else if (server->tcpStatus == CifsNeedReconnect) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000407 cFYI(1, ("Reconnect after server stopped responding"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 cifs_reconnect(server);
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000409 cFYI(1, ("call to reconnect done"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 csocket = server->ssocket;
411 continue;
412 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700413 msleep(1); /* minimum sleep to prevent looping
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 allowing socket to clear and app threads to set
415 tcpStatus CifsNeedReconnect if server hung */
Steve Frenchc18c7322007-10-17 18:01:11 +0000416 if (pdu_length < 4)
417 goto incomplete_rcv;
418 else
419 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 } else if (length <= 0) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000421 if (server->tcpStatus == CifsNew) {
422 cFYI(1, ("tcp session abend after SMBnegprot"));
Steve French09d1db52005-04-28 22:41:08 -0700423 /* some servers kill the TCP session rather than
424 returning an SMB negprot error, in which
425 case reconnecting here is not going to help,
426 and so simply return error to mount */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 break;
428 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000429 if (!try_to_freeze() && (length == -EINTR)) {
Steve French467a8f82007-06-27 22:41:32 +0000430 cFYI(1, ("cifsd thread killed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 break;
432 }
Steve French467a8f82007-06-27 22:41:32 +0000433 cFYI(1, ("Reconnect after unexpected peek error %d",
Steve French57337e42005-04-28 22:41:10 -0700434 length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 cifs_reconnect(server);
436 csocket = server->ssocket;
437 wake_up(&server->response_q);
438 continue;
Petr Tesarik2a974682007-11-20 02:24:08 +0000439 } else if (length < pdu_length) {
440 cFYI(1, ("requested %d bytes but only got %d bytes",
441 pdu_length, length));
Steve Frenchf01d5e12007-08-30 21:13:31 +0000442 pdu_length -= length;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000443 msleep(1);
444 goto incomplete_rcv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 }
Steve French67010fb2005-04-28 22:41:09 -0700446
Steve French70ca7342005-09-22 16:32:06 -0700447 /* The right amount was read from socket - 4 bytes */
448 /* so we can now interpret the length field */
Steve French46810cb2005-04-28 22:41:09 -0700449
Steve French70ca7342005-09-22 16:32:06 -0700450 /* the first byte big endian of the length field,
451 is actually not part of the length but the type
452 with the most common, zero, as regular data */
453 temp = *((char *) smb_buffer);
454
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000455 /* Note that FC 1001 length is big endian on the wire,
Steve French70ca7342005-09-22 16:32:06 -0700456 but we convert it here so it is always manipulated
457 as host byte order */
Steve French46810cb2005-04-28 22:41:09 -0700458 pdu_length = ntohl(smb_buffer->smb_buf_length);
Steve French70ca7342005-09-22 16:32:06 -0700459 smb_buffer->smb_buf_length = pdu_length;
Steve French46810cb2005-04-28 22:41:09 -0700460
Steve French467a8f82007-06-27 22:41:32 +0000461 cFYI(1, ("rfc1002 length 0x%x", pdu_length+4));
Steve French70ca7342005-09-22 16:32:06 -0700462
463 if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000464 continue;
Steve French70ca7342005-09-22 16:32:06 -0700465 } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
Steve French467a8f82007-06-27 22:41:32 +0000466 cFYI(1, ("Good RFC 1002 session rsp"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700467 continue;
Steve French70ca7342005-09-22 16:32:06 -0700468 } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000469 /* we get this from Windows 98 instead of
Steve French46810cb2005-04-28 22:41:09 -0700470 an error on SMB negprot response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000471 cFYI(1, ("Negative RFC1002 Session Response Error 0x%x)",
Steve French70ca7342005-09-22 16:32:06 -0700472 pdu_length));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000473 if (server->tcpStatus == CifsNew) {
474 /* if nack on negprot (rather than
Steve French46810cb2005-04-28 22:41:09 -0700475 ret of smb negprot error) reconnecting
476 not going to help, ret error to mount */
477 break;
478 } else {
479 /* give server a second to
480 clean up before reconnect attempt */
481 msleep(1000);
482 /* always try 445 first on reconnect
483 since we get NACK on some if we ever
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000484 connected to port 139 (the NACK is
Steve French46810cb2005-04-28 22:41:09 -0700485 since we do not begin with RFC1001
486 session initialize frame) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000487 server->addr.sockAddr.sin_port =
Steve French46810cb2005-04-28 22:41:09 -0700488 htons(CIFS_PORT);
489 cifs_reconnect(server);
490 csocket = server->ssocket;
491 wake_up(&server->response_q);
492 continue;
493 }
Steve French70ca7342005-09-22 16:32:06 -0700494 } else if (temp != (char) 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000495 cERROR(1, ("Unknown RFC 1002 frame"));
Steve French70ca7342005-09-22 16:32:06 -0700496 cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
497 length);
Steve French46810cb2005-04-28 22:41:09 -0700498 cifs_reconnect(server);
499 csocket = server->ssocket;
500 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700501 }
502
503 /* else we have an SMB response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000504 if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French26f57362007-08-30 22:09:15 +0000505 (pdu_length < sizeof(struct smb_hdr) - 1 - 4)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700506 cERROR(1, ("Invalid size SMB length %d pdu_length %d",
Steve French46810cb2005-04-28 22:41:09 -0700507 length, pdu_length+4));
Steve Frenche4eb2952005-04-28 22:41:09 -0700508 cifs_reconnect(server);
509 csocket = server->ssocket;
510 wake_up(&server->response_q);
511 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000512 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700513
514 /* else length ok */
515 reconnect = 0;
516
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000517 if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
Steve French4b18f2a2008-04-29 00:06:05 +0000518 isLargeBuf = true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700519 memcpy(bigbuf, smallbuf, 4);
520 smb_buffer = bigbuf;
521 }
522 length = 0;
523 iov.iov_base = 4 + (char *)smb_buffer;
524 iov.iov_len = pdu_length;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000525 for (total_read = 0; total_read < pdu_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700526 total_read += length) {
527 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
528 pdu_length - total_read, 0);
Steve French26f57362007-08-30 22:09:15 +0000529 if (kthread_should_stop() ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700530 (length == -EINTR)) {
531 /* then will exit */
532 reconnect = 2;
533 break;
534 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700535 cifs_reconnect(server);
536 csocket = server->ssocket;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000537 /* Reconnect wakes up rspns q */
Steve Frenche4eb2952005-04-28 22:41:09 -0700538 /* Now we will reread sock */
539 reconnect = 1;
540 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000541 } else if ((length == -ERESTARTSYS) ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700542 (length == -EAGAIN)) {
543 msleep(1); /* minimum sleep to prevent looping,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000544 allowing socket to clear and app
Steve Frenche4eb2952005-04-28 22:41:09 -0700545 threads to set tcpStatus
546 CifsNeedReconnect if server hung*/
Steve Frenchc18c7322007-10-17 18:01:11 +0000547 length = 0;
Steve French46810cb2005-04-28 22:41:09 -0700548 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700549 } else if (length <= 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000550 cERROR(1, ("Received no data, expecting %d",
Steve Frenche4eb2952005-04-28 22:41:09 -0700551 pdu_length - total_read));
552 cifs_reconnect(server);
553 csocket = server->ssocket;
554 reconnect = 1;
555 break;
Steve French46810cb2005-04-28 22:41:09 -0700556 }
557 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000558 if (reconnect == 2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700559 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000560 else if (reconnect == 1)
Steve Frenche4eb2952005-04-28 22:41:09 -0700561 continue;
562
563 length += 4; /* account for rfc1002 hdr */
Steve French50c2f752007-07-13 00:33:32 +0000564
Steve Frenche4eb2952005-04-28 22:41:09 -0700565
566 dump_smb(smb_buffer, length);
Steve French184ed212006-02-24 06:15:11 +0000567 if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700568 cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
Steve Frenche4eb2952005-04-28 22:41:09 -0700569 continue;
570 }
571
572
573 task_to_wake = NULL;
574 spin_lock(&GlobalMid_Lock);
575 list_for_each(tmp, &server->pending_mid_q) {
576 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
577
Steve French50c2f752007-07-13 00:33:32 +0000578 if ((mid_entry->mid == smb_buffer->Mid) &&
Steve Frenche4eb2952005-04-28 22:41:09 -0700579 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
580 (mid_entry->command == smb_buffer->Command)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000581 if (check2ndT2(smb_buffer,server->maxBuf) > 0) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700582 /* We have a multipart transact2 resp */
Steve French4b18f2a2008-04-29 00:06:05 +0000583 isMultiRsp = true;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000584 if (mid_entry->resp_buf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700585 /* merge response - fix up 1st*/
Steve French50c2f752007-07-13 00:33:32 +0000586 if (coalesce_t2(smb_buffer,
Steve Frenche4eb2952005-04-28 22:41:09 -0700587 mid_entry->resp_buf)) {
Steve French4b18f2a2008-04-29 00:06:05 +0000588 mid_entry->multiRsp =
589 true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700590 break;
591 } else {
592 /* all parts received */
Steve French4b18f2a2008-04-29 00:06:05 +0000593 mid_entry->multiEnd =
594 true;
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;
Steve French4b18f2a2008-04-29 00:06:05 +0000606 mid_entry->largeBuf =
607 true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700608 bigbuf = NULL;
609 }
610 }
611 break;
Steve French50c2f752007-07-13 00:33:32 +0000612 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700613 mid_entry->resp_buf = smb_buffer;
Steve French4b18f2a2008-04-29 00:06:05 +0000614 mid_entry->largeBuf = isLargeBuf;
Steve Frenche4eb2952005-04-28 22:41:09 -0700615multi_t2_fnd:
616 task_to_wake = mid_entry->tsk;
617 mid_entry->midState = MID_RESPONSE_RECEIVED;
Steve French1047abc2005-10-11 19:58:06 -0700618#ifdef CONFIG_CIFS_STATS2
619 mid_entry->when_received = jiffies;
620#endif
Steve French3a5ff612006-07-14 22:37:11 +0000621 /* so we do not time out requests to server
622 which is still responding (since server could
623 be busy but not dead) */
624 server->lstrp = jiffies;
Steve Frenche4eb2952005-04-28 22:41:09 -0700625 break;
626 }
627 }
628 spin_unlock(&GlobalMid_Lock);
629 if (task_to_wake) {
Steve Frenchcd634992005-04-28 22:41:10 -0700630 /* Was previous buf put in mpx struct for multi-rsp? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000631 if (!isMultiRsp) {
Steve Frenchcd634992005-04-28 22:41:10 -0700632 /* smb buffer will be freed by user thread */
Steve French26f57362007-08-30 22:09:15 +0000633 if (isLargeBuf)
Steve Frenchcd634992005-04-28 22:41:10 -0700634 bigbuf = NULL;
Steve French26f57362007-08-30 22:09:15 +0000635 else
Steve Frenchcd634992005-04-28 22:41:10 -0700636 smallbuf = NULL;
637 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700638 wake_up_process(task_to_wake);
Steve French4b18f2a2008-04-29 00:06:05 +0000639 } else if (!is_valid_oplock_break(smb_buffer, server) &&
640 !isMultiRsp) {
Steve French50c2f752007-07-13 00:33:32 +0000641 cERROR(1, ("No task to wake, unknown frame received! "
642 "NumMids %d", midCount.counter));
643 cifs_dump_mem("Received Data is: ", (char *)smb_buffer,
Steve French70ca7342005-09-22 16:32:06 -0700644 sizeof(struct smb_hdr));
Steve French39798772006-05-31 22:40:51 +0000645#ifdef CONFIG_CIFS_DEBUG2
646 cifs_dump_detail(smb_buffer);
647 cifs_dump_mids(server);
648#endif /* CIFS_DEBUG2 */
Steve French50c2f752007-07-13 00:33:32 +0000649
Steve Frenche4eb2952005-04-28 22:41:09 -0700650 }
651 } /* end while !EXITING */
652
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 spin_lock(&GlobalMid_Lock);
654 server->tcpStatus = CifsExiting;
Steve Frenche691b9d2008-05-11 15:53:33 +0000655 spin_unlock(&GlobalMid_Lock);
Steve Frenchdbdbb872008-06-10 21:21:56 +0000656 wake_up_all(&server->response_q);
Steve Frenche691b9d2008-05-11 15:53:33 +0000657
658 /* don't exit until kthread_stop is called */
659 set_current_state(TASK_UNINTERRUPTIBLE);
660 while (!kthread_should_stop()) {
661 schedule();
662 set_current_state(TASK_UNINTERRUPTIBLE);
663 }
664 set_current_state(TASK_RUNNING);
665
Steve French31ca3bc2005-04-28 22:41:11 -0700666 /* check if we have blocked requests that need to free */
667 /* Note that cifs_max_pending is normally 50, but
668 can be set at module install time to as little as two */
Steve Frenche691b9d2008-05-11 15:53:33 +0000669 spin_lock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000670 if (atomic_read(&server->inFlight) >= cifs_max_pending)
Steve French31ca3bc2005-04-28 22:41:11 -0700671 atomic_set(&server->inFlight, cifs_max_pending - 1);
672 /* We do not want to set the max_pending too low or we
673 could end up with the counter going negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +0000675 /* Although there should not be any requests blocked on
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700677 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 to the same server - they now will see the session is in exit state
679 and get out of SendReceive. */
680 wake_up_all(&server->request_q);
681 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700682 msleep(125);
Steve French50c2f752007-07-13 00:33:32 +0000683
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000684 if (server->ssocket) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 sock_release(csocket);
686 server->ssocket = NULL;
687 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700688 /* buffer usuallly freed in free_mid - need to free it here on exit */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +0000689 cifs_buf_release(bigbuf);
690 if (smallbuf) /* no sense logging a debug message if NULL */
Steve Frenchb8643e12005-04-28 22:41:07 -0700691 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692
693 read_lock(&GlobalSMBSeslock);
694 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700695 /* loop through server session structures attached to this and
696 mark them dead */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 list_for_each(tmp, &GlobalSMBSessionList) {
698 ses =
699 list_entry(tmp, struct cifsSesInfo,
700 cifsSessionList);
701 if (ses->server == server) {
702 ses->status = CifsExiting;
703 ses->server = NULL;
704 }
705 }
706 read_unlock(&GlobalSMBSeslock);
707 } else {
Steve French31ca3bc2005-04-28 22:41:11 -0700708 /* although we can not zero the server struct pointer yet,
709 since there are active requests which may depnd on them,
710 mark the corresponding SMB sessions as exiting too */
711 list_for_each(tmp, &GlobalSMBSessionList) {
712 ses = list_entry(tmp, struct cifsSesInfo,
713 cifsSessionList);
Steve French26f57362007-08-30 22:09:15 +0000714 if (ses->server == server)
Steve French31ca3bc2005-04-28 22:41:11 -0700715 ses->status = CifsExiting;
Steve French31ca3bc2005-04-28 22:41:11 -0700716 }
717
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 spin_lock(&GlobalMid_Lock);
719 list_for_each(tmp, &server->pending_mid_q) {
720 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
721 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French50c2f752007-07-13 00:33:32 +0000722 cFYI(1, ("Clearing Mid 0x%x - waking up ",
723 mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 task_to_wake = mid_entry->tsk;
Steve French26f57362007-08-30 22:09:15 +0000725 if (task_to_wake)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 wake_up_process(task_to_wake);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 }
728 }
729 spin_unlock(&GlobalMid_Lock);
730 read_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700732 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 }
734
Steve Frenchf1914012005-08-18 09:37:34 -0700735 if (!list_empty(&server->pending_mid_q)) {
Steve French50c2f752007-07-13 00:33:32 +0000736 /* mpx threads have not exited yet give them
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700738 /* due to delays on oplock break requests, we need
739 to wait at least 45 seconds before giving up
740 on a request getting a response and going ahead
741 and killing cifsd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve French31ca3bc2005-04-28 22:41:11 -0700743 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 /* if threads still have not exited they are probably never
745 coming home not much else we can do but free the memory */
746 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747
748 write_lock(&GlobalSMBSeslock);
749 atomic_dec(&tcpSesAllocCount);
750 length = tcpSesAllocCount.counter;
Steve French31ca3bc2005-04-28 22:41:11 -0700751
752 /* last chance to mark ses pointers invalid
753 if there are any pointing to this (e.g
Steve French50c2f752007-07-13 00:33:32 +0000754 if a crazy root user tried to kill cifsd
Steve French31ca3bc2005-04-28 22:41:11 -0700755 kernel thread explicitly this might happen) */
756 list_for_each(tmp, &GlobalSMBSessionList) {
757 ses = list_entry(tmp, struct cifsSesInfo,
758 cifsSessionList);
Steve French26f57362007-08-30 22:09:15 +0000759 if (ses->server == server)
Steve French31ca3bc2005-04-28 22:41:11 -0700760 ses->server = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700761 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 write_unlock(&GlobalSMBSeslock);
Steve French31ca3bc2005-04-28 22:41:11 -0700763
Jeff Laytonc359cf32007-11-16 22:22:06 +0000764 kfree(server->hostname);
Steve French31ca3bc2005-04-28 22:41:11 -0700765 kfree(server);
Steve French26f57362007-08-30 22:09:15 +0000766 if (length > 0)
767 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
768 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +0000769
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 return 0;
771}
772
Jeff Laytonc359cf32007-11-16 22:22:06 +0000773/* extract the host portion of the UNC string */
774static char *
775extract_hostname(const char *unc)
776{
777 const char *src;
778 char *dst, *delim;
779 unsigned int len;
780
781 /* skip double chars at beginning of string */
782 /* BB: check validity of these bytes? */
783 src = unc + 2;
784
785 /* delimiter between hostname and sharename is always '\\' now */
786 delim = strchr(src, '\\');
787 if (!delim)
788 return ERR_PTR(-EINVAL);
789
790 len = delim - src;
791 dst = kmalloc((len + 1), GFP_KERNEL);
792 if (dst == NULL)
793 return ERR_PTR(-ENOMEM);
794
795 memcpy(dst, src, len);
796 dst[len] = '\0';
797
798 return dst;
799}
800
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801static int
Steve French50c2f752007-07-13 00:33:32 +0000802cifs_parse_mount_options(char *options, const char *devname,
803 struct smb_vol *vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804{
805 char *value;
806 char *data;
807 unsigned int temp_len, i, j;
808 char separator[2];
809
810 separator[0] = ',';
Steve French50c2f752007-07-13 00:33:32 +0000811 separator[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812
Linus Torvalds12e36b22006-10-13 08:09:29 -0700813 if (Local_System_Name[0] != 0)
Steve French50c2f752007-07-13 00:33:32 +0000814 memcpy(vol->source_rfc1001_name, Local_System_Name, 15);
Steve French2cd646a2006-09-28 19:43:08 +0000815 else {
Linus Torvalds12e36b22006-10-13 08:09:29 -0700816 char *nodename = utsname()->nodename;
Steve French50c2f752007-07-13 00:33:32 +0000817 int n = strnlen(nodename, 15);
818 memset(vol->source_rfc1001_name, 0x20, 15);
819 for (i = 0; i < n; i++) {
Steve French2cd646a2006-09-28 19:43:08 +0000820 /* does not have to be perfect mapping since field is
821 informational, only used for servers that do not support
822 port 445 and it can be overridden at mount time */
Linus Torvalds12e36b22006-10-13 08:09:29 -0700823 vol->source_rfc1001_name[i] = toupper(nodename[i]);
Steve French2cd646a2006-09-28 19:43:08 +0000824 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 }
826 vol->source_rfc1001_name[15] = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -0700827 /* null target name indicates to use *SMBSERVR default called name
828 if we end up sending RFC1001 session initialize */
829 vol->target_rfc1001_name[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 vol->linux_uid = current->uid; /* current->euid instead? */
831 vol->linux_gid = current->gid;
832 vol->dir_mode = S_IRWXUGO;
833 /* 2767 perms indicate mandatory locking support */
Steve French7505e052007-11-01 18:03:01 +0000834 vol->file_mode = (S_IRWXUGO | S_ISGID) & (~S_IXGRP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835
836 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
Steve French4b18f2a2008-04-29 00:06:05 +0000837 vol->rw = true;
Jeremy Allisonac670552005-06-22 17:26:35 -0700838 /* default is always to request posix paths. */
839 vol->posix_paths = 1;
840
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 if (!options)
842 return 1;
843
Steve French50c2f752007-07-13 00:33:32 +0000844 if (strncmp(options, "sep=", 4) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000845 if (options[4] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 separator[0] = options[4];
847 options += 5;
848 } else {
Steve French467a8f82007-06-27 22:41:32 +0000849 cFYI(1, ("Null separator not allowed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 }
851 }
Steve French50c2f752007-07-13 00:33:32 +0000852
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 while ((data = strsep(&options, separator)) != NULL) {
854 if (!*data)
855 continue;
856 if ((value = strchr(data, '=')) != NULL)
857 *value++ = '\0';
858
Steve French50c2f752007-07-13 00:33:32 +0000859 /* Have to parse this before we parse for "user" */
860 if (strnicmp(data, "user_xattr", 10) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 vol->no_xattr = 0;
Steve French50c2f752007-07-13 00:33:32 +0000862 } else if (strnicmp(data, "nouser_xattr", 12) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 vol->no_xattr = 1;
864 } else if (strnicmp(data, "user", 4) == 0) {
Steve French4b952a92006-10-30 21:46:13 +0000865 if (!value) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 printk(KERN_WARNING
867 "CIFS: invalid or missing username\n");
868 return 1; /* needs_arg; */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000869 } else if (!*value) {
Steve French4b952a92006-10-30 21:46:13 +0000870 /* null user, ie anonymous, authentication */
871 vol->nullauth = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 }
873 if (strnlen(value, 200) < 200) {
874 vol->username = value;
875 } else {
876 printk(KERN_WARNING "CIFS: username too long\n");
877 return 1;
878 }
879 } else if (strnicmp(data, "pass", 4) == 0) {
880 if (!value) {
881 vol->password = NULL;
882 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000883 } else if (value[0] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 /* check if string begins with double comma
885 since that would mean the password really
886 does start with a comma, and would not
887 indicate an empty string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000888 if (value[1] != separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 vol->password = NULL;
890 continue;
891 }
892 }
893 temp_len = strlen(value);
894 /* removed password length check, NTLM passwords
895 can be arbitrarily long */
896
Steve French50c2f752007-07-13 00:33:32 +0000897 /* if comma in password, the string will be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 prematurely null terminated. Commas in password are
899 specified across the cifs mount interface by a double
900 comma ie ,, and a comma used as in other cases ie ','
901 as a parameter delimiter/separator is single and due
902 to the strsep above is temporarily zeroed. */
903
904 /* NB: password legally can have multiple commas and
905 the only illegal character in a password is null */
906
Steve French50c2f752007-07-13 00:33:32 +0000907 if ((value[temp_len] == 0) &&
Steve French09d1db52005-04-28 22:41:08 -0700908 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 /* reinsert comma */
910 value[temp_len] = separator[0];
Steve French50c2f752007-07-13 00:33:32 +0000911 temp_len += 2; /* move after second comma */
912 while (value[temp_len] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 if (value[temp_len] == separator[0]) {
Steve French50c2f752007-07-13 00:33:32 +0000914 if (value[temp_len+1] ==
Steve French09d1db52005-04-28 22:41:08 -0700915 separator[0]) {
916 /* skip second comma */
917 temp_len++;
Steve French50c2f752007-07-13 00:33:32 +0000918 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 /* single comma indicating start
920 of next parm */
921 break;
922 }
923 }
924 temp_len++;
925 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000926 if (value[temp_len] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 options = NULL;
928 } else {
929 value[temp_len] = 0;
930 /* point option to start of next parm */
931 options = value + temp_len + 1;
932 }
Steve French50c2f752007-07-13 00:33:32 +0000933 /* go from value to value + temp_len condensing
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 double commas to singles. Note that this ends up
935 allocating a few bytes too many, which is ok */
Pekka Enberge915fc42005-09-06 15:18:35 -0700936 vol->password = kzalloc(temp_len, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000937 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000938 printk(KERN_WARNING "CIFS: no memory "
939 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700940 return 1;
941 }
Steve French50c2f752007-07-13 00:33:32 +0000942 for (i = 0, j = 0; i < temp_len; i++, j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 vol->password[j] = value[i];
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000944 if (value[i] == separator[0]
Steve French09d1db52005-04-28 22:41:08 -0700945 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 /* skip second comma */
947 i++;
948 }
949 }
950 vol->password[j] = 0;
951 } else {
Pekka Enberge915fc42005-09-06 15:18:35 -0700952 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000953 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000954 printk(KERN_WARNING "CIFS: no memory "
955 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700956 return 1;
957 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 strcpy(vol->password, value);
959 }
960 } else if (strnicmp(data, "ip", 2) == 0) {
961 if (!value || !*value) {
962 vol->UNCip = NULL;
963 } else if (strnlen(value, 35) < 35) {
964 vol->UNCip = value;
965 } else {
Steve French50c2f752007-07-13 00:33:32 +0000966 printk(KERN_WARNING "CIFS: ip address "
967 "too long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 return 1;
969 }
Steve French50c2f752007-07-13 00:33:32 +0000970 } else if (strnicmp(data, "sec", 3) == 0) {
971 if (!value || !*value) {
972 cERROR(1, ("no security value specified"));
973 continue;
974 } else if (strnicmp(value, "krb5i", 5) == 0) {
975 vol->secFlg |= CIFSSEC_MAY_KRB5 |
Steve French189acaa2006-06-23 02:33:48 +0000976 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800977 } else if (strnicmp(value, "krb5p", 5) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000978 /* vol->secFlg |= CIFSSEC_MUST_SEAL |
979 CIFSSEC_MAY_KRB5; */
980 cERROR(1, ("Krb5 cifs privacy not supported"));
Steve Frenchbf820672005-12-01 22:32:42 -0800981 return 1;
982 } else if (strnicmp(value, "krb5", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000983 vol->secFlg |= CIFSSEC_MAY_KRB5;
Steve Frenchbf820672005-12-01 22:32:42 -0800984 } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000985 vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
Steve French189acaa2006-06-23 02:33:48 +0000986 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800987 } else if (strnicmp(value, "ntlmv2", 6) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000988 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve Frenchbf820672005-12-01 22:32:42 -0800989 } else if (strnicmp(value, "ntlmi", 5) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000990 vol->secFlg |= CIFSSEC_MAY_NTLM |
Steve French189acaa2006-06-23 02:33:48 +0000991 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800992 } else if (strnicmp(value, "ntlm", 4) == 0) {
993 /* ntlm is default so can be turned off too */
Steve French750d1152006-06-27 06:28:30 +0000994 vol->secFlg |= CIFSSEC_MAY_NTLM;
Steve Frenchbf820672005-12-01 22:32:42 -0800995 } else if (strnicmp(value, "nontlm", 6) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000996 /* BB is there a better way to do this? */
Steve French750d1152006-06-27 06:28:30 +0000997 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve French189acaa2006-06-23 02:33:48 +0000998#ifdef CONFIG_CIFS_WEAK_PW_HASH
999 } else if (strnicmp(value, "lanman", 6) == 0) {
Steve French50c2f752007-07-13 00:33:32 +00001000 vol->secFlg |= CIFSSEC_MAY_LANMAN;
Steve French189acaa2006-06-23 02:33:48 +00001001#endif
Steve Frenchbf820672005-12-01 22:32:42 -08001002 } else if (strnicmp(value, "none", 4) == 0) {
Steve French189acaa2006-06-23 02:33:48 +00001003 vol->nullauth = 1;
Steve French50c2f752007-07-13 00:33:32 +00001004 } else {
1005 cERROR(1, ("bad security option: %s", value));
1006 return 1;
1007 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 } else if ((strnicmp(data, "unc", 3) == 0)
1009 || (strnicmp(data, "target", 6) == 0)
1010 || (strnicmp(data, "path", 4) == 0)) {
1011 if (!value || !*value) {
Steve French50c2f752007-07-13 00:33:32 +00001012 printk(KERN_WARNING "CIFS: invalid path to "
1013 "network resource\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 return 1; /* needs_arg; */
1015 }
1016 if ((temp_len = strnlen(value, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001017 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001018 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001020 strcpy(vol->UNC, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 if (strncmp(vol->UNC, "//", 2) == 0) {
1022 vol->UNC[0] = '\\';
1023 vol->UNC[1] = '\\';
Steve French50c2f752007-07-13 00:33:32 +00001024 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 printk(KERN_WARNING
Steve French50c2f752007-07-13 00:33:32 +00001026 "CIFS: UNC Path does not begin "
1027 "with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 return 1;
1029 }
1030 } else {
1031 printk(KERN_WARNING "CIFS: UNC name too long\n");
1032 return 1;
1033 }
1034 } else if ((strnicmp(data, "domain", 3) == 0)
1035 || (strnicmp(data, "workgroup", 5) == 0)) {
1036 if (!value || !*value) {
1037 printk(KERN_WARNING "CIFS: invalid domain name\n");
1038 return 1; /* needs_arg; */
1039 }
1040 /* BB are there cases in which a comma can be valid in
1041 a domain name and need special handling? */
Steve French39798772006-05-31 22:40:51 +00001042 if (strnlen(value, 256) < 256) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 vol->domainname = value;
1044 cFYI(1, ("Domain name set"));
1045 } else {
Steve French50c2f752007-07-13 00:33:32 +00001046 printk(KERN_WARNING "CIFS: domain name too "
1047 "long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 return 1;
1049 }
Steve French50c2f752007-07-13 00:33:32 +00001050 } else if (strnicmp(data, "prefixpath", 10) == 0) {
1051 if (!value || !*value) {
1052 printk(KERN_WARNING
1053 "CIFS: invalid path prefix\n");
1054 return 1; /* needs_argument */
1055 }
1056 if ((temp_len = strnlen(value, 1024)) < 1024) {
Steve French4523cc32007-04-30 20:13:06 +00001057 if (value[0] != '/')
Steve French2fe87f02006-09-21 07:02:52 +00001058 temp_len++; /* missing leading slash */
Steve French50c2f752007-07-13 00:33:32 +00001059 vol->prepath = kmalloc(temp_len+1, GFP_KERNEL);
1060 if (vol->prepath == NULL)
1061 return 1;
Steve French4523cc32007-04-30 20:13:06 +00001062 if (value[0] != '/') {
Steve French2fe87f02006-09-21 07:02:52 +00001063 vol->prepath[0] = '/';
Steve French50c2f752007-07-13 00:33:32 +00001064 strcpy(vol->prepath+1, value);
Steve French2fe87f02006-09-21 07:02:52 +00001065 } else
Steve French50c2f752007-07-13 00:33:32 +00001066 strcpy(vol->prepath, value);
1067 cFYI(1, ("prefix path %s", vol->prepath));
1068 } else {
1069 printk(KERN_WARNING "CIFS: prefix too long\n");
1070 return 1;
1071 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 } else if (strnicmp(data, "iocharset", 9) == 0) {
1073 if (!value || !*value) {
Steve French63135e02007-07-17 17:34:02 +00001074 printk(KERN_WARNING "CIFS: invalid iocharset "
1075 "specified\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 return 1; /* needs_arg; */
1077 }
1078 if (strnlen(value, 65) < 65) {
Steve French50c2f752007-07-13 00:33:32 +00001079 if (strnicmp(value, "default", 7))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 vol->iocharset = value;
Steve French50c2f752007-07-13 00:33:32 +00001081 /* if iocharset not set then load_nls_default
1082 is used by caller */
1083 cFYI(1, ("iocharset set to %s", value));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 } else {
Steve French63135e02007-07-17 17:34:02 +00001085 printk(KERN_WARNING "CIFS: iocharset name "
1086 "too long.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 return 1;
1088 }
1089 } else if (strnicmp(data, "uid", 3) == 0) {
1090 if (value && *value) {
1091 vol->linux_uid =
1092 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001093 vol->override_uid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 }
1095 } else if (strnicmp(data, "gid", 3) == 0) {
1096 if (value && *value) {
1097 vol->linux_gid =
1098 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001099 vol->override_gid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 }
1101 } else if (strnicmp(data, "file_mode", 4) == 0) {
1102 if (value && *value) {
1103 vol->file_mode =
1104 simple_strtoul(value, &value, 0);
1105 }
1106 } else if (strnicmp(data, "dir_mode", 4) == 0) {
1107 if (value && *value) {
1108 vol->dir_mode =
1109 simple_strtoul(value, &value, 0);
1110 }
1111 } else if (strnicmp(data, "dirmode", 4) == 0) {
1112 if (value && *value) {
1113 vol->dir_mode =
1114 simple_strtoul(value, &value, 0);
1115 }
1116 } else if (strnicmp(data, "port", 4) == 0) {
1117 if (value && *value) {
1118 vol->port =
1119 simple_strtoul(value, &value, 0);
1120 }
1121 } else if (strnicmp(data, "rsize", 5) == 0) {
1122 if (value && *value) {
1123 vol->rsize =
1124 simple_strtoul(value, &value, 0);
1125 }
1126 } else if (strnicmp(data, "wsize", 5) == 0) {
1127 if (value && *value) {
1128 vol->wsize =
1129 simple_strtoul(value, &value, 0);
1130 }
1131 } else if (strnicmp(data, "sockopt", 5) == 0) {
1132 if (value && *value) {
1133 vol->sockopt =
1134 simple_strtoul(value, &value, 0);
1135 }
1136 } else if (strnicmp(data, "netbiosname", 4) == 0) {
1137 if (!value || !*value || (*value == ' ')) {
Steve French63135e02007-07-17 17:34:02 +00001138 cFYI(1, ("invalid (empty) netbiosname"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 } else {
Steve French50c2f752007-07-13 00:33:32 +00001140 memset(vol->source_rfc1001_name, 0x20, 15);
1141 for (i = 0; i < 15; i++) {
1142 /* BB are there cases in which a comma can be
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 valid in this workstation netbios name (and need
1144 special handling)? */
1145
1146 /* We do not uppercase netbiosname for user */
Steve French50c2f752007-07-13 00:33:32 +00001147 if (value[i] == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 break;
Steve French50c2f752007-07-13 00:33:32 +00001149 else
1150 vol->source_rfc1001_name[i] =
1151 value[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 }
1153 /* The string has 16th byte zero still from
1154 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001155 if ((i == 15) && (value[i] != 0))
1156 printk(KERN_WARNING "CIFS: netbiosname"
1157 " longer than 15 truncated.\n");
Steve Frencha10faeb22005-08-22 21:38:31 -07001158 }
1159 } else if (strnicmp(data, "servern", 7) == 0) {
1160 /* servernetbiosname specified override *SMBSERVER */
1161 if (!value || !*value || (*value == ' ')) {
Steve French467a8f82007-06-27 22:41:32 +00001162 cFYI(1, ("empty server netbiosname specified"));
Steve Frencha10faeb22005-08-22 21:38:31 -07001163 } else {
1164 /* last byte, type, is 0x20 for servr type */
Steve French50c2f752007-07-13 00:33:32 +00001165 memset(vol->target_rfc1001_name, 0x20, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001166
Steve French50c2f752007-07-13 00:33:32 +00001167 for (i = 0; i < 15; i++) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001168 /* BB are there cases in which a comma can be
Steve French50c2f752007-07-13 00:33:32 +00001169 valid in this workstation netbios name
1170 (and need special handling)? */
Steve Frencha10faeb22005-08-22 21:38:31 -07001171
Steve French50c2f752007-07-13 00:33:32 +00001172 /* user or mount helper must uppercase
1173 the netbiosname */
1174 if (value[i] == 0)
Steve Frencha10faeb22005-08-22 21:38:31 -07001175 break;
1176 else
Steve French50c2f752007-07-13 00:33:32 +00001177 vol->target_rfc1001_name[i] =
1178 value[i];
Steve Frencha10faeb22005-08-22 21:38:31 -07001179 }
1180 /* The string has 16th byte zero still from
1181 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001182 if ((i == 15) && (value[i] != 0))
1183 printk(KERN_WARNING "CIFS: server net"
1184 "biosname longer than 15 truncated.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 }
1186 } else if (strnicmp(data, "credentials", 4) == 0) {
1187 /* ignore */
1188 } else if (strnicmp(data, "version", 3) == 0) {
1189 /* ignore */
Steve French50c2f752007-07-13 00:33:32 +00001190 } else if (strnicmp(data, "guest", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 /* ignore */
1192 } else if (strnicmp(data, "rw", 2) == 0) {
Steve French4b18f2a2008-04-29 00:06:05 +00001193 vol->rw = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 } else if ((strnicmp(data, "suid", 4) == 0) ||
1195 (strnicmp(data, "nosuid", 6) == 0) ||
1196 (strnicmp(data, "exec", 4) == 0) ||
1197 (strnicmp(data, "noexec", 6) == 0) ||
1198 (strnicmp(data, "nodev", 5) == 0) ||
1199 (strnicmp(data, "noauto", 6) == 0) ||
1200 (strnicmp(data, "dev", 3) == 0)) {
1201 /* The mount tool or mount.cifs helper (if present)
Steve French50c2f752007-07-13 00:33:32 +00001202 uses these opts to set flags, and the flags are read
1203 by the kernel vfs layer before we get here (ie
1204 before read super) so there is no point trying to
1205 parse these options again and set anything and it
1206 is ok to just ignore them */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 continue;
1208 } else if (strnicmp(data, "ro", 2) == 0) {
Steve French4b18f2a2008-04-29 00:06:05 +00001209 vol->rw = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 } else if (strnicmp(data, "hard", 4) == 0) {
1211 vol->retry = 1;
1212 } else if (strnicmp(data, "soft", 4) == 0) {
1213 vol->retry = 0;
1214 } else if (strnicmp(data, "perm", 4) == 0) {
1215 vol->noperm = 0;
1216 } else if (strnicmp(data, "noperm", 6) == 0) {
1217 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001218 } else if (strnicmp(data, "mapchars", 8) == 0) {
1219 vol->remap = 1;
1220 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1221 vol->remap = 0;
Steve French50c2f752007-07-13 00:33:32 +00001222 } else if (strnicmp(data, "sfu", 3) == 0) {
1223 vol->sfu_emul = 1;
1224 } else if (strnicmp(data, "nosfu", 5) == 0) {
1225 vol->sfu_emul = 0;
Jeremy Allisonac670552005-06-22 17:26:35 -07001226 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1227 vol->posix_paths = 1;
1228 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1229 vol->posix_paths = 0;
Steve Frenchc18c8422007-07-18 23:21:09 +00001230 } else if (strnicmp(data, "nounix", 6) == 0) {
1231 vol->no_linux_ext = 1;
1232 } else if (strnicmp(data, "nolinux", 7) == 0) {
1233 vol->no_linux_ext = 1;
Steve French50c2f752007-07-13 00:33:32 +00001234 } else if ((strnicmp(data, "nocase", 6) == 0) ||
Steve Frencha10faeb22005-08-22 21:38:31 -07001235 (strnicmp(data, "ignorecase", 10) == 0)) {
Steve French50c2f752007-07-13 00:33:32 +00001236 vol->nocase = 1;
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001237 } else if (strnicmp(data, "brl", 3) == 0) {
1238 vol->nobrl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001239 } else if ((strnicmp(data, "nobrl", 5) == 0) ||
Steve French1c955182005-08-30 20:58:07 -07001240 (strnicmp(data, "nolock", 6) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001241 vol->nobrl = 1;
Steve Frenchd3485d32005-08-19 11:04:29 -07001242 /* turn off mandatory locking in mode
1243 if remote locking is turned off since the
1244 local vfs will do advisory */
Steve French50c2f752007-07-13 00:33:32 +00001245 if (vol->file_mode ==
1246 (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
Steve Frenchd3485d32005-08-19 11:04:29 -07001247 vol->file_mode = S_IALLUGO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 } else if (strnicmp(data, "setuids", 7) == 0) {
1249 vol->setuids = 1;
1250 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1251 vol->setuids = 0;
Jeff Laytond0a9c072008-05-12 22:23:49 +00001252 } else if (strnicmp(data, "dynperm", 7) == 0) {
1253 vol->dynperm = true;
1254 } else if (strnicmp(data, "nodynperm", 9) == 0) {
1255 vol->dynperm = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 } else if (strnicmp(data, "nohard", 6) == 0) {
1257 vol->retry = 0;
1258 } else if (strnicmp(data, "nosoft", 6) == 0) {
1259 vol->retry = 1;
1260 } else if (strnicmp(data, "nointr", 6) == 0) {
1261 vol->intr = 0;
1262 } else if (strnicmp(data, "intr", 4) == 0) {
1263 vol->intr = 1;
Steve French50c2f752007-07-13 00:33:32 +00001264 } else if (strnicmp(data, "serverino", 7) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 vol->server_ino = 1;
Steve French50c2f752007-07-13 00:33:32 +00001266 } else if (strnicmp(data, "noserverino", 9) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 vol->server_ino = 0;
Steve French50c2f752007-07-13 00:33:32 +00001268 } else if (strnicmp(data, "cifsacl", 7) == 0) {
Steve French0a4b92c2006-01-12 15:44:21 -08001269 vol->cifs_acl = 1;
1270 } else if (strnicmp(data, "nocifsacl", 9) == 0) {
1271 vol->cifs_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001272 } else if (strnicmp(data, "acl", 3) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 vol->no_psx_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001274 } else if (strnicmp(data, "noacl", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 vol->no_psx_acl = 1;
Steve French50c2f752007-07-13 00:33:32 +00001276 } else if (strnicmp(data, "sign", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +00001277 vol->secFlg |= CIFSSEC_MUST_SIGN;
Steve French95b1cb92008-05-15 16:44:38 +00001278 } else if (strnicmp(data, "seal", 4) == 0) {
1279 /* we do not do the following in secFlags because seal
1280 is a per tree connection (mount) not a per socket
1281 or per-smb connection option in the protocol */
1282 /* vol->secFlg |= CIFSSEC_MUST_SEAL; */
1283 vol->seal = 1;
Steve French50c2f752007-07-13 00:33:32 +00001284 } else if (strnicmp(data, "direct", 6) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001286 } else if (strnicmp(data, "forcedirectio", 13) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001288 } else if (strnicmp(data, "in6_addr", 8) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 if (!value || !*value) {
1290 vol->in6_addr = NULL;
1291 } else if (strnlen(value, 49) == 48) {
1292 vol->in6_addr = value;
1293 } else {
Steve French50c2f752007-07-13 00:33:32 +00001294 printk(KERN_WARNING "CIFS: ip v6 address not "
1295 "48 characters long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 return 1;
1297 }
1298 } else if (strnicmp(data, "noac", 4) == 0) {
Steve French50c2f752007-07-13 00:33:32 +00001299 printk(KERN_WARNING "CIFS: Mount option noac not "
1300 "supported. Instead set "
1301 "/proc/fs/cifs/LookupCacheEnabled to 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 } else
Steve French50c2f752007-07-13 00:33:32 +00001303 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",
1304 data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 }
1306 if (vol->UNC == NULL) {
Steve French4523cc32007-04-30 20:13:06 +00001307 if (devname == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001308 printk(KERN_WARNING "CIFS: Missing UNC name for mount "
1309 "target\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 return 1;
1311 }
1312 if ((temp_len = strnlen(devname, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001313 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001314 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001316 strcpy(vol->UNC, devname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 if (strncmp(vol->UNC, "//", 2) == 0) {
1318 vol->UNC[0] = '\\';
1319 vol->UNC[1] = '\\';
1320 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Steve French50c2f752007-07-13 00:33:32 +00001321 printk(KERN_WARNING "CIFS: UNC Path does not "
1322 "begin with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 return 1;
1324 }
Igor Mammedov7c5e6282008-05-08 20:48:42 +00001325 value = strpbrk(vol->UNC+2, "/\\");
1326 if (value)
1327 *value = '\\';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 } else {
1329 printk(KERN_WARNING "CIFS: UNC name too long\n");
1330 return 1;
1331 }
1332 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001333 if (vol->UNCip == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 vol->UNCip = &vol->UNC[2];
1335
1336 return 0;
1337}
1338
1339static struct cifsSesInfo *
Steve French50c2f752007-07-13 00:33:32 +00001340cifs_find_tcp_session(struct in_addr *target_ip_addr,
Cyrill Gorcunov1b20d672008-05-09 18:17:21 +00001341 struct in6_addr *target_ip6_addr,
1342 char *userName, struct TCP_Server_Info **psrvTcp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343{
1344 struct list_head *tmp;
1345 struct cifsSesInfo *ses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346
Cyrill Gorcunov1b20d672008-05-09 18:17:21 +00001347 *psrvTcp = NULL;
1348
1349 read_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 list_for_each(tmp, &GlobalSMBSessionList) {
1351 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
Cyrill Gorcunov1b20d672008-05-09 18:17:21 +00001352 if (!ses->server)
1353 continue;
Steve French50c2f752007-07-13 00:33:32 +00001354
Cyrill Gorcunov1b20d672008-05-09 18:17:21 +00001355 if (target_ip_addr &&
1356 ses->server->addr.sockAddr.sin_addr.s_addr != target_ip_addr->s_addr)
1357 continue;
1358 else if (target_ip6_addr &&
1359 memcmp(&ses->server->addr.sockAddr6.sin6_addr,
1360 target_ip6_addr, sizeof(*target_ip6_addr)))
1361 continue;
Jeff Layton02eadef2008-05-09 21:26:11 +00001362 /* BB lock server and tcp session; increment use count here?? */
Steve French50c2f752007-07-13 00:33:32 +00001363
Cyrill Gorcunov1b20d672008-05-09 18:17:21 +00001364 /* found a match on the TCP session */
1365 *psrvTcp = ses->server;
1366
1367 /* BB check if reconnection needed */
1368 if (strncmp(ses->userName, userName, MAX_USERNAME_SIZE) == 0) {
1369 read_unlock(&GlobalSMBSeslock);
1370 /* Found exact match on both TCP and
1371 SMB sessions */
1372 return ses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 }
1374 /* else tcp and smb sessions need reconnection */
1375 }
1376 read_unlock(&GlobalSMBSeslock);
Cyrill Gorcunov1b20d672008-05-09 18:17:21 +00001377
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 return NULL;
1379}
1380
1381static struct cifsTconInfo *
1382find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
1383{
1384 struct list_head *tmp;
1385 struct cifsTconInfo *tcon;
Steve Frenchdea570e02008-05-06 22:05:51 +00001386 __be32 old_ip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387
1388 read_lock(&GlobalSMBSeslock);
Steve Frenchdea570e02008-05-06 22:05:51 +00001389
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 list_for_each(tmp, &GlobalTreeConnectionList) {
Steve Frenche466e482006-08-15 13:07:18 +00001391 cFYI(1, ("Next tcon"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
Steve Frenchdea570e02008-05-06 22:05:51 +00001393 if (!tcon->ses || !tcon->ses->server)
1394 continue;
1395
1396 old_ip = tcon->ses->server->addr.sockAddr.sin_addr.s_addr;
1397 cFYI(1, ("old ip addr: %x == new ip %x ?",
1398 old_ip, new_target_ip_addr));
1399
1400 if (old_ip != new_target_ip_addr)
1401 continue;
1402
1403 /* BB lock tcon, server, tcp session and increment use count? */
1404 /* found a match on the TCP session */
1405 /* BB check if reconnection needed */
1406 cFYI(1, ("IP match, old UNC: %s new: %s",
1407 tcon->treeName, uncName));
1408
1409 if (strncmp(tcon->treeName, uncName, MAX_TREE_SIZE))
1410 continue;
1411
1412 cFYI(1, ("and old usr: %s new: %s",
1413 tcon->treeName, uncName));
1414
1415 if (strncmp(tcon->ses->userName, userName, MAX_USERNAME_SIZE))
1416 continue;
1417
1418 /* matched smb session (user name) */
1419 read_unlock(&GlobalSMBSeslock);
1420 return tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 }
Steve Frenchdea570e02008-05-06 22:05:51 +00001422
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 read_unlock(&GlobalSMBSeslock);
1424 return NULL;
1425}
1426
1427int
Steve French50c2f752007-07-13 00:33:32 +00001428get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
1429 const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
Steve French366781c2008-01-25 10:12:41 +00001430 struct dfs_info3_param **preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431{
1432 char *temp_unc;
1433 int rc = 0;
1434
1435 *pnum_referrals = 0;
Steve French366781c2008-01-25 10:12:41 +00001436 *preferrals = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437
1438 if (pSesInfo->ipc_tid == 0) {
1439 temp_unc = kmalloc(2 /* for slashes */ +
Steve French50c2f752007-07-13 00:33:32 +00001440 strnlen(pSesInfo->serverName,
1441 SERVER_NAME_LEN_WITH_NULL * 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 + 1 + 4 /* slash IPC$ */ + 2,
1443 GFP_KERNEL);
1444 if (temp_unc == NULL)
1445 return -ENOMEM;
1446 temp_unc[0] = '\\';
1447 temp_unc[1] = '\\';
1448 strcpy(temp_unc + 2, pSesInfo->serverName);
1449 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1450 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1451 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00001452 ("CIFS Tcon rc = %d ipc_tid = %d", rc, pSesInfo->ipc_tid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 kfree(temp_unc);
1454 }
1455 if (rc == 0)
Steve Frenchc2cf07d2008-05-15 06:20:02 +00001456 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001457 pnum_referrals, nls_codepage, remap);
Steve French366781c2008-01-25 10:12:41 +00001458 /* BB map targetUNCs to dfs_info3 structures, here or
1459 in CIFSGetDFSRefer BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460
1461 return rc;
1462}
1463
1464/* See RFC1001 section 14 on representation of Netbios names */
Steve French50c2f752007-07-13 00:33:32 +00001465static void rfc1002mangle(char *target, char *source, unsigned int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466{
Steve French50c2f752007-07-13 00:33:32 +00001467 unsigned int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468
Steve French50c2f752007-07-13 00:33:32 +00001469 for (i = 0, j = 0; i < (length); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 /* mask a nibble at a time and encode */
1471 target[j] = 'A' + (0x0F & (source[i] >> 4));
1472 target[j+1] = 'A' + (0x0F & source[i]);
Steve French50c2f752007-07-13 00:33:32 +00001473 j += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 }
1475
1476}
1477
1478
1479static int
Steve French50c2f752007-07-13 00:33:32 +00001480ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
1481 char *netbios_name, char *target_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482{
1483 int rc = 0;
1484 int connected = 0;
1485 __be16 orig_port = 0;
1486
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001487 if (*csocket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001488 rc = sock_create_kern(PF_INET, SOCK_STREAM,
1489 IPPROTO_TCP, csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001491 cERROR(1, ("Error %d creating socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 *csocket = NULL;
1493 return rc;
1494 } else {
1495 /* BB other socket options to set KEEPALIVE, NODELAY? */
Steve French467a8f82007-06-27 22:41:32 +00001496 cFYI(1, ("Socket created"));
Steve French50c2f752007-07-13 00:33:32 +00001497 (*csocket)->sk->sk_allocation = GFP_NOFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 }
1499 }
1500
1501 psin_server->sin_family = AF_INET;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001502 if (psin_server->sin_port) { /* user overrode default port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 rc = (*csocket)->ops->connect(*csocket,
1504 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001505 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 if (rc >= 0)
1507 connected = 1;
Steve French50c2f752007-07-13 00:33:32 +00001508 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001510 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001511 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 later if fall back ports fail this time */
1513 orig_port = psin_server->sin_port;
1514
1515 /* do not retry on the same port we just failed on */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001516 if (psin_server->sin_port != htons(CIFS_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 psin_server->sin_port = htons(CIFS_PORT);
1518
1519 rc = (*csocket)->ops->connect(*csocket,
1520 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001521 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 if (rc >= 0)
1523 connected = 1;
1524 }
1525 }
1526 if (!connected) {
1527 psin_server->sin_port = htons(RFC1001_PORT);
1528 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
Steve French50c2f752007-07-13 00:33:32 +00001529 psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001530 sizeof(struct sockaddr_in), 0);
Steve French50c2f752007-07-13 00:33:32 +00001531 if (rc >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 connected = 1;
1533 }
1534
1535 /* give up here - unless we want to retry on different
1536 protocol families some day */
1537 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001538 if (orig_port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 psin_server->sin_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001540 cFYI(1, ("Error %d connecting to server via ipv4", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 sock_release(*csocket);
1542 *csocket = NULL;
1543 return rc;
1544 }
Steve French50c2f752007-07-13 00:33:32 +00001545 /* Eventually check for other socket options to change from
1546 the default. sock_setsockopt not used because it expects
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 user space buffer */
Steve French50c2f752007-07-13 00:33:32 +00001548 cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",
1549 (*csocket)->sk->sk_sndbuf,
Steve Frenchb387eae2005-10-10 14:21:15 -07001550 (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchb387eae2005-10-10 14:21:15 -07001552 /* make the bufsizes depend on wsize/rsize and max requests */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001553 if ((*csocket)->sk->sk_sndbuf < (200 * 1024))
Steve Frenchb387eae2005-10-10 14:21:15 -07001554 (*csocket)->sk->sk_sndbuf = 200 * 1024;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001555 if ((*csocket)->sk->sk_rcvbuf < (140 * 1024))
Steve Frenchb387eae2005-10-10 14:21:15 -07001556 (*csocket)->sk->sk_rcvbuf = 140 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557
1558 /* send RFC1001 sessinit */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001559 if (psin_server->sin_port == htons(RFC1001_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 /* some servers require RFC1001 sessinit before sending
Steve French50c2f752007-07-13 00:33:32 +00001561 negprot - BB check reconnection in case where second
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 sessinit is sent but no second negprot */
Steve French50c2f752007-07-13 00:33:32 +00001563 struct rfc1002_session_packet *ses_init_buf;
1564 struct smb_hdr *smb_buf;
1565 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
1566 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001567 if (ses_init_buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 ses_init_buf->trailer.session_req.called_len = 32;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001569 if (target_name && (target_name[0] != 0)) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001570 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1571 target_name, 16);
1572 } else {
1573 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
Steve French50c2f752007-07-13 00:33:32 +00001574 DEFAULT_CIFS_CALLED_NAME, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001575 }
1576
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 ses_init_buf->trailer.session_req.calling_len = 32;
1578 /* calling name ends in null (byte 16) from old smb
1579 convention. */
Steve French50c2f752007-07-13 00:33:32 +00001580 if (netbios_name && (netbios_name[0] != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
Steve French50c2f752007-07-13 00:33:32 +00001582 netbios_name, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 } else {
1584 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
Steve French50c2f752007-07-13 00:33:32 +00001585 "LINUX_CIFS_CLNT", 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 }
1587 ses_init_buf->trailer.session_req.scope1 = 0;
1588 ses_init_buf->trailer.session_req.scope2 = 0;
1589 smb_buf = (struct smb_hdr *)ses_init_buf;
1590 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1591 smb_buf->smb_buf_length = 0x81000044;
1592 rc = smb_send(*csocket, smb_buf, 0x44,
1593 (struct sockaddr *)psin_server);
1594 kfree(ses_init_buf);
Steve French50c2f752007-07-13 00:33:32 +00001595 msleep(1); /* RFC1001 layer in at least one server
Steve French083d3a2c2006-03-03 09:53:36 +00001596 requires very short break before negprot
1597 presumably because not expecting negprot
1598 to follow so fast. This is a simple
Steve French50c2f752007-07-13 00:33:32 +00001599 solution that works without
Steve French083d3a2c2006-03-03 09:53:36 +00001600 complicating the code and causes no
1601 significant slowing down on mount
1602 for everyone else */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 }
Steve French50c2f752007-07-13 00:33:32 +00001604 /* else the negprot may still work without this
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 even though malloc failed */
Steve French50c2f752007-07-13 00:33:32 +00001606
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 }
Steve French50c2f752007-07-13 00:33:32 +00001608
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 return rc;
1610}
1611
1612static int
1613ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1614{
1615 int rc = 0;
1616 int connected = 0;
1617 __be16 orig_port = 0;
1618
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001619 if (*csocket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001620 rc = sock_create_kern(PF_INET6, SOCK_STREAM,
1621 IPPROTO_TCP, csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001623 cERROR(1, ("Error %d creating ipv6 socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 *csocket = NULL;
1625 return rc;
1626 } else {
1627 /* BB other socket options to set KEEPALIVE, NODELAY? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001628 cFYI(1, ("ipv6 Socket created"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 (*csocket)->sk->sk_allocation = GFP_NOFS;
1630 }
1631 }
1632
1633 psin_server->sin6_family = AF_INET6;
1634
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001635 if (psin_server->sin6_port) { /* user overrode default port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 rc = (*csocket)->ops->connect(*csocket,
1637 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001638 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 if (rc >= 0)
1640 connected = 1;
Steve French50c2f752007-07-13 00:33:32 +00001641 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001643 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001644 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 later if fall back ports fail this time */
1646
1647 orig_port = psin_server->sin6_port;
1648 /* do not retry on the same port we just failed on */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001649 if (psin_server->sin6_port != htons(CIFS_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 psin_server->sin6_port = htons(CIFS_PORT);
1651
1652 rc = (*csocket)->ops->connect(*csocket,
1653 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001654 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 if (rc >= 0)
1656 connected = 1;
1657 }
1658 }
1659 if (!connected) {
1660 psin_server->sin6_port = htons(RFC1001_PORT);
1661 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001662 psin_server, sizeof(struct sockaddr_in6), 0);
Steve French50c2f752007-07-13 00:33:32 +00001663 if (rc >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 connected = 1;
1665 }
1666
1667 /* give up here - unless we want to retry on different
1668 protocol families some day */
1669 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001670 if (orig_port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 psin_server->sin6_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001672 cFYI(1, ("Error %d connecting to server via ipv6", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 sock_release(*csocket);
1674 *csocket = NULL;
1675 return rc;
1676 }
Steve French50c2f752007-07-13 00:33:32 +00001677 /* Eventually check for other socket options to change from
1678 the default. sock_setsockopt not used because it expects
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 user space buffer */
1680 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve French50c2f752007-07-13 00:33:32 +00001681
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682 return rc;
1683}
1684
Steve French50c2f752007-07-13 00:33:32 +00001685void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
1686 struct super_block *sb, struct smb_vol *vol_info)
Steve French8af18972007-02-14 04:42:51 +00001687{
1688 /* if we are reconnecting then should we check to see if
1689 * any requested capabilities changed locally e.g. via
1690 * remount but we can not do much about it here
1691 * if they have (even if we could detect it by the following)
1692 * Perhaps we could add a backpointer to array of sb from tcon
1693 * or if we change to make all sb to same share the same
1694 * sb as NFS - then we only have one backpointer to sb.
1695 * What if we wanted to mount the server share twice once with
1696 * and once without posixacls or posix paths? */
1697 __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001698
Steve Frenchc18c8422007-07-18 23:21:09 +00001699 if (vol_info && vol_info->no_linux_ext) {
1700 tcon->fsUnixInfo.Capability = 0;
1701 tcon->unix_ext = 0; /* Unix Extensions disabled */
1702 cFYI(1, ("Linux protocol extensions disabled"));
1703 return;
1704 } else if (vol_info)
1705 tcon->unix_ext = 1; /* Unix Extensions supported */
1706
1707 if (tcon->unix_ext == 0) {
1708 cFYI(1, ("Unix extensions disabled so not set on reconnect"));
1709 return;
1710 }
Steve French50c2f752007-07-13 00:33:32 +00001711
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001712 if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
Steve French8af18972007-02-14 04:42:51 +00001713 __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001714
Steve French8af18972007-02-14 04:42:51 +00001715 /* check for reconnect case in which we do not
1716 want to change the mount behavior if we can avoid it */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001717 if (vol_info == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001718 /* turn off POSIX ACL and PATHNAMES if not set
Steve French8af18972007-02-14 04:42:51 +00001719 originally at mount time */
1720 if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
1721 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00001722 if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
1723 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
1724 cERROR(1, ("POSIXPATH support change"));
Steve French8af18972007-02-14 04:42:51 +00001725 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00001726 } else if ((cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
1727 cERROR(1, ("possible reconnect error"));
1728 cERROR(1,
1729 ("server disabled POSIX path support"));
1730 }
Steve French8af18972007-02-14 04:42:51 +00001731 }
Steve French50c2f752007-07-13 00:33:32 +00001732
Steve French8af18972007-02-14 04:42:51 +00001733 cap &= CIFS_UNIX_CAP_MASK;
Steve French75865f8c2007-06-24 18:30:48 +00001734 if (vol_info && vol_info->no_psx_acl)
Steve French8af18972007-02-14 04:42:51 +00001735 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00001736 else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001737 cFYI(1, ("negotiated posix acl support"));
1738 if (sb)
Steve French8af18972007-02-14 04:42:51 +00001739 sb->s_flags |= MS_POSIXACL;
1740 }
1741
Steve French75865f8c2007-06-24 18:30:48 +00001742 if (vol_info && vol_info->posix_paths == 0)
Steve French8af18972007-02-14 04:42:51 +00001743 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00001744 else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001745 cFYI(1, ("negotiate posix pathnames"));
Steve French75865f8c2007-06-24 18:30:48 +00001746 if (sb)
Steve French50c2f752007-07-13 00:33:32 +00001747 CIFS_SB(sb)->mnt_cifs_flags |=
Steve French8af18972007-02-14 04:42:51 +00001748 CIFS_MOUNT_POSIX_PATHS;
1749 }
Steve French50c2f752007-07-13 00:33:32 +00001750
Steve French984acfe2007-04-26 16:42:50 +00001751 /* We might be setting the path sep back to a different
1752 form if we are reconnecting and the server switched its
Steve French50c2f752007-07-13 00:33:32 +00001753 posix path capability for this share */
Steve French75865f8c2007-06-24 18:30:48 +00001754 if (sb && (CIFS_SB(sb)->prepathlen > 0))
Steve French984acfe2007-04-26 16:42:50 +00001755 CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
Steve French75865f8c2007-06-24 18:30:48 +00001756
1757 if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
1758 if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
1759 CIFS_SB(sb)->rsize = 127 * 1024;
Steve French90c81e02008-02-12 20:32:36 +00001760 cFYI(DBG2,
1761 ("larger reads not supported by srv"));
Steve French75865f8c2007-06-24 18:30:48 +00001762 }
1763 }
Steve French50c2f752007-07-13 00:33:32 +00001764
1765
1766 cFYI(1, ("Negotiate caps 0x%x", (int)cap));
Steve French8af18972007-02-14 04:42:51 +00001767#ifdef CONFIG_CIFS_DEBUG2
Steve French75865f8c2007-06-24 18:30:48 +00001768 if (cap & CIFS_UNIX_FCNTL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001769 cFYI(1, ("FCNTL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001770 if (cap & CIFS_UNIX_EXTATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001771 cFYI(1, ("EXTATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001772 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001773 cFYI(1, ("POSIX path cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001774 if (cap & CIFS_UNIX_XATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001775 cFYI(1, ("XATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001776 if (cap & CIFS_UNIX_POSIX_ACL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001777 cFYI(1, ("POSIX ACL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001778 if (cap & CIFS_UNIX_LARGE_READ_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001779 cFYI(1, ("very large read cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001780 if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001781 cFYI(1, ("very large write cap"));
Steve French8af18972007-02-14 04:42:51 +00001782#endif /* CIFS_DEBUG2 */
1783 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
Steve French442aa312007-09-24 20:25:46 +00001784 if (vol_info == NULL) {
Steve French5a44b312007-09-20 15:16:24 +00001785 cFYI(1, ("resetting capabilities failed"));
Steve French442aa312007-09-24 20:25:46 +00001786 } else
Steve French5a44b312007-09-20 15:16:24 +00001787 cERROR(1, ("Negotiating Unix capabilities "
1788 "with the server failed. Consider "
1789 "mounting with the Unix Extensions\n"
1790 "disabled, if problems are found, "
1791 "by specifying the nounix mount "
Steve French2224f4e2007-09-20 15:37:29 +00001792 "option."));
Steve French5a44b312007-09-20 15:16:24 +00001793
Steve French8af18972007-02-14 04:42:51 +00001794 }
1795 }
1796}
1797
Steve French03a143c2008-02-14 06:38:30 +00001798static void
1799convert_delimiter(char *path, char delim)
1800{
1801 int i;
Steve Frenchc2d68ea2008-02-15 19:20:18 +00001802 char old_delim;
Steve French03a143c2008-02-14 06:38:30 +00001803
1804 if (path == NULL)
1805 return;
1806
Steve French582d21e2008-05-13 04:54:12 +00001807 if (delim == '/')
Steve Frenchc2d68ea2008-02-15 19:20:18 +00001808 old_delim = '\\';
1809 else
1810 old_delim = '/';
1811
Steve French03a143c2008-02-14 06:38:30 +00001812 for (i = 0; path[i] != '\0'; i++) {
Steve Frenchc2d68ea2008-02-15 19:20:18 +00001813 if (path[i] == old_delim)
Steve French03a143c2008-02-14 06:38:30 +00001814 path[i] = delim;
1815 }
1816}
1817
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818int
1819cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1820 char *mount_data, const char *devname)
1821{
1822 int rc = 0;
1823 int xid;
1824 int address_type = AF_INET;
1825 struct socket *csocket = NULL;
1826 struct sockaddr_in sin_server;
1827 struct sockaddr_in6 sin_server6;
1828 struct smb_vol volume_info;
1829 struct cifsSesInfo *pSesInfo = NULL;
1830 struct cifsSesInfo *existingCifsSes = NULL;
1831 struct cifsTconInfo *tcon = NULL;
1832 struct TCP_Server_Info *srvTcp = NULL;
1833
1834 xid = GetXid();
1835
1836/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
Steve French50c2f752007-07-13 00:33:32 +00001837
1838 memset(&volume_info, 0, sizeof(struct smb_vol));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001840 rc = -EINVAL;
1841 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 }
1843
Jeff Layton8426c392007-05-05 03:27:49 +00001844 if (volume_info.nullauth) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001845 cFYI(1, ("null user"));
Jeff Layton9b8f5f52007-11-09 23:25:04 +00001846 volume_info.username = "";
Jeff Layton8426c392007-05-05 03:27:49 +00001847 } else if (volume_info.username) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 /* BB fixme parse for domain name here */
Steve French467a8f82007-06-27 22:41:32 +00001849 cFYI(1, ("Username: %s", volume_info.username));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 } else {
Steve Frenchbf820672005-12-01 22:32:42 -08001851 cifserror("No username specified");
Steve French50c2f752007-07-13 00:33:32 +00001852 /* In userspace mount helper we can get user name from alternate
1853 locations such as env variables and files on disk */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001854 rc = -EINVAL;
1855 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 }
1857
1858 if (volume_info.UNCip && volume_info.UNC) {
Steve French50c2f752007-07-13 00:33:32 +00001859 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,
1860 &sin_server.sin_addr.s_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001862 if (rc <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 /* not ipv4 address, try ipv6 */
Steve French50c2f752007-07-13 00:33:32 +00001864 rc = cifs_inet_pton(AF_INET6, volume_info.UNCip,
1865 &sin_server6.sin6_addr.in6_u);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001866 if (rc > 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 address_type = AF_INET6;
1868 } else {
1869 address_type = AF_INET;
1870 }
Steve French50c2f752007-07-13 00:33:32 +00001871
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001872 if (rc <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 /* we failed translating address */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001874 rc = -EINVAL;
1875 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 }
1877
1878 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1879 /* success */
1880 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00001881 } else if (volume_info.UNCip) {
1882 /* BB using ip addr as server name to connect to the
1883 DFS root below */
1884 cERROR(1, ("Connecting to DFS root not implemented yet"));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001885 rc = -EINVAL;
1886 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 } else /* which servers DFS root would we conect to */ {
1888 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00001889 ("CIFS mount error: No UNC path (e.g. -o "
1890 "unc=//192.168.1.100/public) specified"));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001891 rc = -EINVAL;
1892 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 }
1894
1895 /* this is needed for ASCII cp to Unicode converts */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001896 if (volume_info.iocharset == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 cifs_sb->local_nls = load_nls_default();
1898 /* load_nls_default can not return null */
1899 } else {
1900 cifs_sb->local_nls = load_nls(volume_info.iocharset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001901 if (cifs_sb->local_nls == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001902 cERROR(1, ("CIFS mount error: iocharset %s not found",
1903 volume_info.iocharset));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001904 rc = -ELIBACC;
1905 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 }
1907 }
1908
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001909 if (address_type == AF_INET)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1911 NULL /* no ipv6 addr */,
1912 volume_info.username, &srvTcp);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001913 else if (address_type == AF_INET6) {
1914 cFYI(1, ("looking for ipv6 address"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1916 &sin_server6.sin6_addr,
1917 volume_info.username, &srvTcp);
Steve French5858ae42007-04-25 11:59:10 +00001918 } else {
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001919 rc = -EINVAL;
1920 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921 }
1922
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 if (srvTcp) {
Steve French50c2f752007-07-13 00:33:32 +00001924 cFYI(1, ("Existing tcp session with server found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 } else { /* create socket */
Steve French4523cc32007-04-30 20:13:06 +00001926 if (volume_info.port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 sin_server.sin_port = htons(volume_info.port);
1928 else
1929 sin_server.sin_port = 0;
Steve French5858ae42007-04-25 11:59:10 +00001930 if (address_type == AF_INET6) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001931 cFYI(1, ("attempting ipv6 connect"));
Steve French5858ae42007-04-25 11:59:10 +00001932 /* BB should we allow ipv6 on port 139? */
1933 /* other OS never observed in Wild doing 139 with v6 */
Steve French50c2f752007-07-13 00:33:32 +00001934 rc = ipv6_connect(&sin_server6, &csocket);
1935 } else
1936 rc = ipv4_connect(&sin_server, &csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -07001937 volume_info.source_rfc1001_name,
1938 volume_info.target_rfc1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001940 cERROR(1, ("Error connecting to IPv4 socket. "
1941 "Aborting operation"));
Steve French4523cc32007-04-30 20:13:06 +00001942 if (csocket != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 sock_release(csocket);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001944 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 }
1946
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00001947 srvTcp = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
1948 if (!srvTcp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 rc = -ENOMEM;
1950 sock_release(csocket);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001951 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 } else {
Steve French50c2f752007-07-13 00:33:32 +00001953 memcpy(&srvTcp->addr.sockAddr, &sin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001954 sizeof(struct sockaddr_in));
Steve French50c2f752007-07-13 00:33:32 +00001955 atomic_set(&srvTcp->inFlight, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 /* BB Add code for ipv6 case too */
1957 srvTcp->ssocket = csocket;
1958 srvTcp->protocolType = IPV4;
Jeff Laytonc359cf32007-11-16 22:22:06 +00001959 srvTcp->hostname = extract_hostname(volume_info.UNC);
1960 if (IS_ERR(srvTcp->hostname)) {
1961 rc = PTR_ERR(srvTcp->hostname);
1962 sock_release(csocket);
1963 goto out;
1964 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 init_waitqueue_head(&srvTcp->response_q);
1966 init_waitqueue_head(&srvTcp->request_q);
1967 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1968 /* at this point we are the only ones with the pointer
1969 to the struct since the kernel thread not created yet
1970 so no need to spinlock this init of tcpStatus */
1971 srvTcp->tcpStatus = CifsNew;
1972 init_MUTEX(&srvTcp->tcpSem);
Igor Mammedovaaf737a2007-04-03 19:16:43 +00001973 srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd");
Steve French8840dee2007-11-16 23:05:52 +00001974 if (IS_ERR(srvTcp->tsk)) {
Igor Mammedovaaf737a2007-04-03 19:16:43 +00001975 rc = PTR_ERR(srvTcp->tsk);
Steve French50c2f752007-07-13 00:33:32 +00001976 cERROR(1, ("error %d create cifsd thread", rc));
Igor Mammedovaaf737a2007-04-03 19:16:43 +00001977 srvTcp->tsk = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978 sock_release(csocket);
Jeff Laytonc359cf32007-11-16 22:22:06 +00001979 kfree(srvTcp->hostname);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001980 goto out;
Steve Frenchf1914012005-08-18 09:37:34 -07001981 }
Steve Frenchf1914012005-08-18 09:37:34 -07001982 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00001983 memcpy(srvTcp->workstation_RFC1001_name,
1984 volume_info.source_rfc1001_name, 16);
1985 memcpy(srvTcp->server_RFC1001_name,
1986 volume_info.target_rfc1001_name, 16);
Steve Frenchad009ac2005-04-28 22:41:05 -07001987 srvTcp->sequence_number = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 }
1989 }
1990
1991 if (existingCifsSes) {
1992 pSesInfo = existingCifsSes;
Jeff Layton1d9a8852007-12-31 01:37:11 +00001993 cFYI(1, ("Existing smb sess found (status=%d)",
1994 pSesInfo->status));
Steve French88e7d702008-01-03 17:37:09 +00001995 down(&pSesInfo->sesSem);
Jeff Layton1d9a8852007-12-31 01:37:11 +00001996 if (pSesInfo->status == CifsNeedReconnect) {
1997 cFYI(1, ("Session needs reconnect"));
Jeff Layton1d9a8852007-12-31 01:37:11 +00001998 rc = cifs_setup_session(xid, pSesInfo,
1999 cifs_sb->local_nls);
Jeff Layton1d9a8852007-12-31 01:37:11 +00002000 }
Steve French88e7d702008-01-03 17:37:09 +00002001 up(&pSesInfo->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 } else if (!rc) {
Steve Frenchbf820672005-12-01 22:32:42 -08002003 cFYI(1, ("Existing smb sess not found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 pSesInfo = sesInfoAlloc();
2005 if (pSesInfo == NULL)
2006 rc = -ENOMEM;
2007 else {
2008 pSesInfo->server = srvTcp;
2009 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
2010 NIPQUAD(sin_server.sin_addr.s_addr));
2011 }
2012
Steve French50c2f752007-07-13 00:33:32 +00002013 if (!rc) {
2014 /* volume_info.password freed at unmount */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002015 if (volume_info.password) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016 pSesInfo->password = volume_info.password;
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002017 /* set to NULL to prevent freeing on exit */
2018 volume_info.password = NULL;
2019 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 if (volume_info.username)
2021 strncpy(pSesInfo->userName,
Steve French50c2f752007-07-13 00:33:32 +00002022 volume_info.username,
2023 MAX_USERNAME_SIZE);
Steve French39798772006-05-31 22:40:51 +00002024 if (volume_info.domainname) {
2025 int len = strlen(volume_info.domainname);
Steve French50c2f752007-07-13 00:33:32 +00002026 pSesInfo->domainName =
Steve French39798772006-05-31 22:40:51 +00002027 kmalloc(len + 1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00002028 if (pSesInfo->domainName)
Steve French39798772006-05-31 22:40:51 +00002029 strcpy(pSesInfo->domainName,
2030 volume_info.domainname);
2031 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 pSesInfo->linux_uid = volume_info.linux_uid;
Steve French750d1152006-06-27 06:28:30 +00002033 pSesInfo->overrideSecFlg = volume_info.secFlg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 down(&pSesInfo->sesSem);
Steve French189acaa2006-06-23 02:33:48 +00002035 /* BB FIXME need to pass vol->secFlgs BB */
Steve French50c2f752007-07-13 00:33:32 +00002036 rc = cifs_setup_session(xid, pSesInfo,
2037 cifs_sb->local_nls);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 up(&pSesInfo->sesSem);
Steve French4523cc32007-04-30 20:13:06 +00002039 if (!rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 atomic_inc(&srvTcp->socketUseCount);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002041 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042 }
Steve French50c2f752007-07-13 00:33:32 +00002043
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044 /* search for existing tcon to this server share */
2045 if (!rc) {
Steve French4523cc32007-04-30 20:13:06 +00002046 if (volume_info.rsize > CIFSMaxBufSize) {
Steve French50c2f752007-07-13 00:33:32 +00002047 cERROR(1, ("rsize %d too large, using MaxBufSize",
Steve French0ae0efa2005-10-10 10:57:19 -07002048 volume_info.rsize));
2049 cifs_sb->rsize = CIFSMaxBufSize;
Steve French75865f8c2007-06-24 18:30:48 +00002050 } else if ((volume_info.rsize) &&
2051 (volume_info.rsize <= CIFSMaxBufSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052 cifs_sb->rsize = volume_info.rsize;
Steve French0ae0efa2005-10-10 10:57:19 -07002053 else /* default */
2054 cifs_sb->rsize = CIFSMaxBufSize;
2055
Steve French4523cc32007-04-30 20:13:06 +00002056 if (volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
Steve French50c2f752007-07-13 00:33:32 +00002057 cERROR(1, ("wsize %d too large, using 4096 instead",
Steve French0ae0efa2005-10-10 10:57:19 -07002058 volume_info.wsize));
2059 cifs_sb->wsize = 4096;
Steve French4523cc32007-04-30 20:13:06 +00002060 } else if (volume_info.wsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061 cifs_sb->wsize = volume_info.wsize;
2062 else
Steve French50c2f752007-07-13 00:33:32 +00002063 cifs_sb->wsize =
Steve French1877c9e2006-01-27 18:36:11 -08002064 min_t(const int, PAGEVEC_SIZE * PAGE_CACHE_SIZE,
2065 127*1024);
Steve French17cbbaf2006-01-24 20:26:48 -08002066 /* old default of CIFSMaxBufSize was too small now
Steve French50c2f752007-07-13 00:33:32 +00002067 that SMB Write2 can send multiple pages in kvec.
Steve French17cbbaf2006-01-24 20:26:48 -08002068 RFC1001 does not describe what happens when frame
2069 bigger than 128K is sent so use that as max in
2070 conjunction with 52K kvec constraint on arch with 4K
2071 page size */
2072
Steve French4523cc32007-04-30 20:13:06 +00002073 if (cifs_sb->rsize < 2048) {
Steve French50c2f752007-07-13 00:33:32 +00002074 cifs_sb->rsize = 2048;
Steve French6cec2ae2006-02-22 17:31:52 -06002075 /* Windows ME may prefer this */
Steve French467a8f82007-06-27 22:41:32 +00002076 cFYI(1, ("readsize set to minimum: 2048"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077 }
Steve French2fe87f02006-09-21 07:02:52 +00002078 /* calculate prepath */
2079 cifs_sb->prepath = volume_info.prepath;
Steve French4523cc32007-04-30 20:13:06 +00002080 if (cifs_sb->prepath) {
Steve French2fe87f02006-09-21 07:02:52 +00002081 cifs_sb->prepathlen = strlen(cifs_sb->prepath);
Steve French03a143c2008-02-14 06:38:30 +00002082 /* we can not convert the / to \ in the path
2083 separators in the prefixpath yet because we do not
2084 know (until reset_cifs_unix_caps is called later)
2085 whether POSIX PATH CAP is available. We normalize
2086 the / to \ after reset_cifs_unix_caps is called */
Steve French2fe87f02006-09-21 07:02:52 +00002087 volume_info.prepath = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002088 } else
Steve French2fe87f02006-09-21 07:02:52 +00002089 cifs_sb->prepathlen = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090 cifs_sb->mnt_uid = volume_info.linux_uid;
2091 cifs_sb->mnt_gid = volume_info.linux_gid;
2092 cifs_sb->mnt_file_mode = volume_info.file_mode;
2093 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
Steve French467a8f82007-06-27 22:41:32 +00002094 cFYI(1, ("file mode: 0x%x dir mode: 0x%x",
2095 cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096
Steve French4523cc32007-04-30 20:13:06 +00002097 if (volume_info.noperm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
Steve French4523cc32007-04-30 20:13:06 +00002099 if (volume_info.setuids)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
Steve French4523cc32007-04-30 20:13:06 +00002101 if (volume_info.server_ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
Steve French4523cc32007-04-30 20:13:06 +00002103 if (volume_info.remap)
Steve French6a0b4822005-04-28 22:41:05 -07002104 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
Steve French4523cc32007-04-30 20:13:06 +00002105 if (volume_info.no_xattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
Steve French4523cc32007-04-30 20:13:06 +00002107 if (volume_info.sfu_emul)
Steve Frenchd7245c22005-07-14 18:25:12 -05002108 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
Steve French4523cc32007-04-30 20:13:06 +00002109 if (volume_info.nobrl)
Steve Frenchc46fa8a2005-08-18 20:49:57 -07002110 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Steve French4523cc32007-04-30 20:13:06 +00002111 if (volume_info.cifs_acl)
Steve French0a4b92c2006-01-12 15:44:21 -08002112 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
Steve French4523cc32007-04-30 20:13:06 +00002113 if (volume_info.override_uid)
2114 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
2115 if (volume_info.override_gid)
2116 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
Jeff Laytond0a9c072008-05-12 22:23:49 +00002117 if (volume_info.dynperm)
2118 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
Steve French4523cc32007-04-30 20:13:06 +00002119 if (volume_info.direct_io) {
Steve French467a8f82007-06-27 22:41:32 +00002120 cFYI(1, ("mounting share using direct i/o"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
2122 }
2123
Steve French27adb442008-05-23 19:43:29 +00002124 if ((volume_info.cifs_acl) && (volume_info.dynperm))
2125 cERROR(1, ("mount option dynperm ignored if cifsacl "
2126 "mount option supported"));
2127
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128 tcon =
2129 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
2130 volume_info.username);
2131 if (tcon) {
Steve Frenchbf820672005-12-01 22:32:42 -08002132 cFYI(1, ("Found match on UNC path"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 /* we can have only one retry value for a connection
2134 to a share so for resources mounted more than once
Steve French50c2f752007-07-13 00:33:32 +00002135 to the same server share the last value passed in
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136 for the retry flag is used */
2137 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07002138 tcon->nocase = volume_info.nocase;
Steve French95b1cb92008-05-15 16:44:38 +00002139 if (tcon->seal != volume_info.seal)
2140 cERROR(1, ("transport encryption setting "
2141 "conflicts with existing tid"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142 } else {
2143 tcon = tconInfoAlloc();
2144 if (tcon == NULL)
2145 rc = -ENOMEM;
2146 else {
Steve French50c2f752007-07-13 00:33:32 +00002147 /* check for null share name ie connecting to
Steve French8af18972007-02-14 04:42:51 +00002148 * dfs root */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149
Steve French50c2f752007-07-13 00:33:32 +00002150 /* BB check if this works for exactly length
Steve French8af18972007-02-14 04:42:51 +00002151 * three strings */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
2153 && (strchr(volume_info.UNC + 3, '/') ==
2154 NULL)) {
Steve French646dd532008-05-15 01:50:56 +00002155/* rc = connect_to_dfs_path(xid, pSesInfo,
Steve French8af18972007-02-14 04:42:51 +00002156 "", cifs_sb->local_nls,
Steve French50c2f752007-07-13 00:33:32 +00002157 cifs_sb->mnt_cifs_flags &
Steve French646dd532008-05-15 01:50:56 +00002158 CIFS_MOUNT_MAP_SPECIAL_CHR);*/
2159 cFYI(1, ("DFS root not supported"));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002160 rc = -ENODEV;
2161 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162 } else {
Steve French8af18972007-02-14 04:42:51 +00002163 /* BB Do we need to wrap sesSem around
2164 * this TCon call and Unix SetFS as
2165 * we do on SessSetup and reconnect? */
Steve French50c2f752007-07-13 00:33:32 +00002166 rc = CIFSTCon(xid, pSesInfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 volume_info.UNC,
2168 tcon, cifs_sb->local_nls);
2169 cFYI(1, ("CIFS Tcon rc = %d", rc));
2170 }
2171 if (!rc) {
2172 atomic_inc(&pSesInfo->inUse);
2173 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07002174 tcon->nocase = volume_info.nocase;
Steve French95b1cb92008-05-15 16:44:38 +00002175 tcon->seal = volume_info.seal;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176 }
2177 }
2178 }
2179 }
Steve French4523cc32007-04-30 20:13:06 +00002180 if (pSesInfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
2182 sb->s_maxbytes = (u64) 1 << 63;
2183 } else
2184 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
2185 }
2186
Steve French8af18972007-02-14 04:42:51 +00002187 /* BB FIXME fix time_gran to be larger for LANMAN sessions */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188 sb->s_time_gran = 100;
2189
2190/* on error free sesinfo and tcon struct if needed */
2191 if (rc) {
2192 /* if session setup failed, use count is zero but
2193 we still need to free cifsd thread */
Steve French4523cc32007-04-30 20:13:06 +00002194 if (atomic_read(&srvTcp->socketUseCount) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 spin_lock(&GlobalMid_Lock);
2196 srvTcp->tcpStatus = CifsExiting;
2197 spin_unlock(&GlobalMid_Lock);
Steve French4523cc32007-04-30 20:13:06 +00002198 if (srvTcp->tsk) {
Steve French28356a12007-05-23 14:45:36 +00002199 /* If we could verify that kthread_stop would
2200 always wake up processes blocked in
2201 tcp in recv_mesg then we could remove the
2202 send_sig call */
Steve French50c2f752007-07-13 00:33:32 +00002203 force_sig(SIGKILL, srvTcp->tsk);
Steve Frenche691b9d2008-05-11 15:53:33 +00002204 kthread_stop(srvTcp->tsk);
Steve Frenchf1914012005-08-18 09:37:34 -07002205 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206 }
2207 /* If find_unc succeeded then rc == 0 so we can not end */
2208 if (tcon) /* up accidently freeing someone elses tcon struct */
2209 tconInfoFree(tcon);
2210 if (existingCifsSes == NULL) {
2211 if (pSesInfo) {
Steve French50c2f752007-07-13 00:33:32 +00002212 if ((pSesInfo->server) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213 (pSesInfo->status == CifsGood)) {
2214 int temp_rc;
2215 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
2216 /* if the socketUseCount is now zero */
Steve French4523cc32007-04-30 20:13:06 +00002217 if ((temp_rc == -ESHUTDOWN) &&
Steve French50c2f752007-07-13 00:33:32 +00002218 (pSesInfo->server) &&
Jeff5d9c7202007-06-25 22:16:35 +00002219 (pSesInfo->server->tsk)) {
Jeff5d9c7202007-06-25 22:16:35 +00002220 force_sig(SIGKILL,
2221 pSesInfo->server->tsk);
Steve Frenche691b9d2008-05-11 15:53:33 +00002222 kthread_stop(pSesInfo->server->tsk);
Steve Frenchf1914012005-08-18 09:37:34 -07002223 }
Steve Frencha0136892007-10-04 20:05:09 +00002224 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225 cFYI(1, ("No session or bad tcon"));
Steve Frencha0136892007-10-04 20:05:09 +00002226 if ((pSesInfo->server) &&
2227 (pSesInfo->server->tsk)) {
Steve Frencha0136892007-10-04 20:05:09 +00002228 force_sig(SIGKILL,
2229 pSesInfo->server->tsk);
Steve Frenche691b9d2008-05-11 15:53:33 +00002230 kthread_stop(pSesInfo->server->tsk);
Steve Frencha0136892007-10-04 20:05:09 +00002231 }
2232 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233 sesInfoFree(pSesInfo);
2234 /* pSesInfo = NULL; */
2235 }
2236 }
2237 } else {
2238 atomic_inc(&tcon->useCount);
2239 cifs_sb->tcon = tcon;
2240 tcon->ses = pSesInfo;
2241
Steve French82940a42006-03-02 03:24:57 +00002242 /* do not care if following two calls succeed - informational */
Steve French7f8ed422007-09-28 22:28:55 +00002243 if (!tcon->ipc) {
2244 CIFSSMBQFSDeviceInfo(xid, tcon);
2245 CIFSSMBQFSAttributeInfo(xid, tcon);
2246 }
Steve French50c2f752007-07-13 00:33:32 +00002247
Steve French8af18972007-02-14 04:42:51 +00002248 /* tell server which Unix caps we support */
2249 if (tcon->ses->capabilities & CAP_UNIX)
Steve Frenchc18c8422007-07-18 23:21:09 +00002250 /* reset of caps checks mount to see if unix extensions
2251 disabled for just this mount */
Steve French8af18972007-02-14 04:42:51 +00002252 reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
Steve Frenchc18c8422007-07-18 23:21:09 +00002253 else
2254 tcon->unix_ext = 0; /* server does not support them */
2255
Steve French03a143c2008-02-14 06:38:30 +00002256 /* convert forward to back slashes in prepath here if needed */
Igor Mammedov11b6d642008-02-15 19:06:04 +00002257 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
2258 convert_delimiter(cifs_sb->prepath,
2259 CIFS_DIR_SEP(cifs_sb));
Steve French03a143c2008-02-14 06:38:30 +00002260
Steve Frenchc18c8422007-07-18 23:21:09 +00002261 if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
Steve French75865f8c2007-06-24 18:30:48 +00002262 cifs_sb->rsize = 1024 * 127;
Steve French90c81e02008-02-12 20:32:36 +00002263 cFYI(DBG2,
2264 ("no very large read support, rsize now 127K"));
Steve French75865f8c2007-06-24 18:30:48 +00002265 }
Steve French3e844692005-10-03 13:37:24 -07002266 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
2267 cifs_sb->wsize = min(cifs_sb->wsize,
2268 (tcon->ses->server->maxBuf -
2269 MAX_CIFS_HDR_SIZE));
Steve French0ae0efa2005-10-10 10:57:19 -07002270 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
Steve French50c2f752007-07-13 00:33:32 +00002271 cifs_sb->rsize = min(cifs_sb->rsize,
2272 (tcon->ses->server->maxBuf -
2273 MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 }
2275
2276 /* volume_info.password is freed above when existing session found
2277 (in which case it is not needed anymore) but when new sesion is created
2278 the password ptr is put in the new session structure (in which case the
2279 password will be freed at unmount time) */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002280out:
2281 /* zero out password before freeing */
2282 if (volume_info.password != NULL) {
2283 memset(volume_info.password, 0, strlen(volume_info.password));
2284 kfree(volume_info.password);
2285 }
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002286 kfree(volume_info.UNC);
Steve French2fe87f02006-09-21 07:02:52 +00002287 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 FreeXid(xid);
2289 return rc;
2290}
2291
2292static int
2293CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French7c7b25b2006-06-01 19:20:10 +00002294 char session_key[CIFS_SESS_KEY_SIZE],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295 const struct nls_table *nls_codepage)
2296{
2297 struct smb_hdr *smb_buffer;
2298 struct smb_hdr *smb_buffer_response;
2299 SESSION_SETUP_ANDX *pSMB;
2300 SESSION_SETUP_ANDX *pSMBr;
2301 char *bcc_ptr;
2302 char *user;
2303 char *domain;
2304 int rc = 0;
2305 int remaining_words = 0;
2306 int bytes_returned = 0;
2307 int len;
2308 __u32 capabilities;
2309 __u16 count;
2310
Steve Frencheeac8042006-01-13 21:34:58 -08002311 cFYI(1, ("In sesssetup"));
Steve French4523cc32007-04-30 20:13:06 +00002312 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 return -EINVAL;
2314 user = ses->userName;
2315 domain = ses->domainName;
2316 smb_buffer = cifs_buf_get();
Steve French582d21e2008-05-13 04:54:12 +00002317
2318 if (smb_buffer == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319 return -ENOMEM;
Steve French582d21e2008-05-13 04:54:12 +00002320
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321 smb_buffer_response = smb_buffer;
2322 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2323
2324 /* send SMBsessionSetup here */
2325 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2326 NULL /* no tCon exists yet */ , 13 /* wct */ );
2327
Steve French1982c342005-08-17 12:38:22 -07002328 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329 pSMB->req_no_secext.AndXCommand = 0xFF;
2330 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2331 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2332
Steve French50c2f752007-07-13 00:33:32 +00002333 if (ses->server->secMode &
2334 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2336
2337 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2338 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
2339 if (ses->capabilities & CAP_UNICODE) {
2340 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2341 capabilities |= CAP_UNICODE;
2342 }
2343 if (ses->capabilities & CAP_STATUS32) {
2344 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2345 capabilities |= CAP_STATUS32;
2346 }
2347 if (ses->capabilities & CAP_DFS) {
2348 smb_buffer->Flags2 |= SMBFLG2_DFS;
2349 capabilities |= CAP_DFS;
2350 }
2351 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
2352
Steve French50c2f752007-07-13 00:33:32 +00002353 pSMB->req_no_secext.CaseInsensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002354 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355
2356 pSMB->req_no_secext.CaseSensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002357 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358 bcc_ptr = pByteArea(smb_buffer);
Steve French7c7b25b2006-06-01 19:20:10 +00002359 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2360 bcc_ptr += CIFS_SESS_KEY_SIZE;
2361 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2362 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363
2364 if (ses->capabilities & CAP_UNICODE) {
2365 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
2366 *bcc_ptr = 0;
2367 bcc_ptr++;
2368 }
Steve French4523cc32007-04-30 20:13:06 +00002369 if (user == NULL)
Steve French39798772006-05-31 22:40:51 +00002370 bytes_returned = 0; /* skip null user */
Steve French50c2f752007-07-13 00:33:32 +00002371 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 bytes_returned =
Steve French50c2f752007-07-13 00:33:32 +00002373 cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374 nls_codepage);
2375 /* convert number of 16 bit words to bytes */
2376 bcc_ptr += 2 * bytes_returned;
2377 bcc_ptr += 2; /* trailing null */
2378 if (domain == NULL)
2379 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002380 cifs_strtoUCS((__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381 "CIFS_LINUX_DOM", 32, nls_codepage);
2382 else
2383 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002384 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385 nls_codepage);
2386 bcc_ptr += 2 * bytes_returned;
2387 bcc_ptr += 2;
2388 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002389 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 32, nls_codepage);
2391 bcc_ptr += 2 * bytes_returned;
2392 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002393 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394 32, nls_codepage);
2395 bcc_ptr += 2 * bytes_returned;
2396 bcc_ptr += 2;
2397 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002398 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399 64, nls_codepage);
2400 bcc_ptr += 2 * bytes_returned;
2401 bcc_ptr += 2;
2402 } else {
Steve French50c2f752007-07-13 00:33:32 +00002403 if (user != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 strncpy(bcc_ptr, user, 200);
2405 bcc_ptr += strnlen(user, 200);
2406 }
2407 *bcc_ptr = 0;
2408 bcc_ptr++;
2409 if (domain == NULL) {
2410 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2411 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2412 } else {
2413 strncpy(bcc_ptr, domain, 64);
2414 bcc_ptr += strnlen(domain, 64);
2415 *bcc_ptr = 0;
2416 bcc_ptr++;
2417 }
2418 strcpy(bcc_ptr, "Linux version ");
2419 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002420 strcpy(bcc_ptr, utsname()->release);
2421 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2423 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2424 }
2425 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2426 smb_buffer->smb_buf_length += count;
2427 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2428
2429 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00002430 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431 if (rc) {
2432/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2433 } else if ((smb_buffer_response->WordCount == 3)
2434 || (smb_buffer_response->WordCount == 4)) {
2435 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2436 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2437 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002438 cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */
2439 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format
2440 (little endian) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441 cFYI(1, ("UID = %d ", ses->Suid));
Steve French50c2f752007-07-13 00:33:32 +00002442 /* response can have either 3 or 4 word count - Samba sends 3 */
2443 bcc_ptr = pByteArea(smb_buffer_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444 if ((pSMBr->resp.hdr.WordCount == 3)
2445 || ((pSMBr->resp.hdr.WordCount == 4)
2446 && (blob_len < pSMBr->resp.ByteCount))) {
2447 if (pSMBr->resp.hdr.WordCount == 4)
2448 bcc_ptr += blob_len;
2449
2450 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2451 if ((long) (bcc_ptr) % 2) {
2452 remaining_words =
Steve French50c2f752007-07-13 00:33:32 +00002453 (BCC(smb_buffer_response) - 1) / 2;
2454 /* Unicode strings must be word
2455 aligned */
2456 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457 } else {
2458 remaining_words =
2459 BCC(smb_buffer_response) / 2;
2460 }
2461 len =
2462 UniStrnlen((wchar_t *) bcc_ptr,
2463 remaining_words - 1);
2464/* We look for obvious messed up bcc or strings in response so we do not go off
2465 the end since (at least) WIN2K and Windows XP have a major bug in not null
2466 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002467 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002468 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002469 ses->serverOS = kzalloc(2 * (len + 1),
2470 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002471 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002472 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473 cifs_strfromUCS_le(ses->serverOS,
Steve French50c2f752007-07-13 00:33:32 +00002474 (__le16 *)bcc_ptr,
2475 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476 bcc_ptr += 2 * (len + 1);
2477 remaining_words -= len + 1;
2478 ses->serverOS[2 * len] = 0;
2479 ses->serverOS[1 + (2 * len)] = 0;
2480 if (remaining_words > 0) {
2481 len = UniStrnlen((wchar_t *)bcc_ptr,
2482 remaining_words-1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002483 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002484 ses->serverNOS = kzalloc(2 * (len + 1),
2485 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002486 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002487 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488 cifs_strfromUCS_le(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002489 (__le16 *)bcc_ptr,
2490 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 bcc_ptr += 2 * (len + 1);
2492 ses->serverNOS[2 * len] = 0;
2493 ses->serverNOS[1 + (2 * len)] = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002494 if (strncmp(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002495 "NT LAN Manager 4", 16) == 0) {
Steve French467a8f82007-06-27 22:41:32 +00002496 cFYI(1, ("NT4 server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497 ses->flags |= CIFS_SES_NT4;
2498 }
2499 remaining_words -= len + 1;
2500 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002501 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Steve French50c2f752007-07-13 00:33:32 +00002502 /* last string is not always null terminated
2503 (for e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002504 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002505 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506 ses->serverDomain =
Steve French50c2f752007-07-13 00:33:32 +00002507 kzalloc(2*(len+1),
2508 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002509 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002510 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511 cifs_strfromUCS_le(ses->serverDomain,
Steve French50c2f752007-07-13 00:33:32 +00002512 (__le16 *)bcc_ptr,
2513 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 bcc_ptr += 2 * (len + 1);
2515 ses->serverDomain[2*len] = 0;
2516 ses->serverDomain[1+(2*len)] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002517 } else { /* else no more room so create
2518 dummy domain string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002519 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002520 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002521 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002522 kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002523 }
Steve French50c2f752007-07-13 00:33:32 +00002524 } else { /* no room so create dummy domain
2525 and NOS string */
2526
Steve French433dc242005-04-28 22:41:08 -07002527 /* if these kcallocs fail not much we
2528 can do, but better to not fail the
2529 sesssetup itself */
Steve Frenchcd49b492006-06-26 04:22:36 +00002530 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002532 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002533 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002535 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536 }
2537 } else { /* ASCII */
2538 len = strnlen(bcc_ptr, 1024);
2539 if (((long) bcc_ptr + len) - (long)
2540 pByteArea(smb_buffer_response)
2541 <= BCC(smb_buffer_response)) {
Steve Frenchcd49b492006-06-26 04:22:36 +00002542 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002543 ses->serverOS = kzalloc(len + 1,
2544 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002545 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002546 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002547 strncpy(ses->serverOS, bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548
2549 bcc_ptr += len;
Steve French50c2f752007-07-13 00:33:32 +00002550 /* null terminate the string */
2551 bcc_ptr[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552 bcc_ptr++;
2553
2554 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002555 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002556 ses->serverNOS = kzalloc(len + 1,
2557 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002558 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002559 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 strncpy(ses->serverNOS, bcc_ptr, len);
2561 bcc_ptr += len;
2562 bcc_ptr[0] = 0;
2563 bcc_ptr++;
2564
2565 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002566 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002567 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002568 ses->serverDomain = kzalloc(len + 1,
2569 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002570 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002571 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002572 strncpy(ses->serverDomain, bcc_ptr,
2573 len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 bcc_ptr += len;
2575 bcc_ptr[0] = 0;
2576 bcc_ptr++;
2577 } else
2578 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00002579 ("Variable field of length %d "
2580 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581 len));
2582 }
2583 } else {
2584 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00002585 (" Security Blob Length extends beyond "
2586 "end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 }
2588 } else {
2589 cERROR(1,
2590 (" Invalid Word count %d: ",
2591 smb_buffer_response->WordCount));
2592 rc = -EIO;
2593 }
Steve French433dc242005-04-28 22:41:08 -07002594sesssetup_nomem: /* do not return an error on nomem for the info strings,
2595 since that could make reconnection harder, and
2596 reconnection might be needed to free memory */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00002597 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598
2599 return rc;
2600}
2601
2602static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
Steve French4b18f2a2008-04-29 00:06:05 +00002604 struct cifsSesInfo *ses, bool *pNTLMv2_flag,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605 const struct nls_table *nls_codepage)
2606{
2607 struct smb_hdr *smb_buffer;
2608 struct smb_hdr *smb_buffer_response;
2609 SESSION_SETUP_ANDX *pSMB;
2610 SESSION_SETUP_ANDX *pSMBr;
2611 char *bcc_ptr;
2612 char *domain;
2613 int rc = 0;
2614 int remaining_words = 0;
2615 int bytes_returned = 0;
2616 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002617 int SecurityBlobLength = sizeof(NEGOTIATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618 PNEGOTIATE_MESSAGE SecurityBlob;
2619 PCHALLENGE_MESSAGE SecurityBlob2;
2620 __u32 negotiate_flags, capabilities;
2621 __u16 count;
2622
Steve French12b3b8f2006-02-09 21:12:47 +00002623 cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002624 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625 return -EINVAL;
2626 domain = ses->domainName;
Steve French4b18f2a2008-04-29 00:06:05 +00002627 *pNTLMv2_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 smb_buffer = cifs_buf_get();
2629 if (smb_buffer == NULL) {
2630 return -ENOMEM;
2631 }
2632 smb_buffer_response = smb_buffer;
2633 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2634 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2635
2636 /* send SMBsessionSetup here */
2637 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2638 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002639
2640 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2642 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2643
2644 pSMB->req.AndXCommand = 0xFF;
2645 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2646 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2647
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002648 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2650
2651 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2652 CAP_EXTENDED_SECURITY;
2653 if (ses->capabilities & CAP_UNICODE) {
2654 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2655 capabilities |= CAP_UNICODE;
2656 }
2657 if (ses->capabilities & CAP_STATUS32) {
2658 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2659 capabilities |= CAP_STATUS32;
2660 }
2661 if (ses->capabilities & CAP_DFS) {
2662 smb_buffer->Flags2 |= SMBFLG2_DFS;
2663 capabilities |= CAP_DFS;
2664 }
2665 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2666
2667 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2668 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2669 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2670 SecurityBlob->MessageType = NtLmNegotiate;
2671 negotiate_flags =
2672 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
Steve French12b3b8f2006-02-09 21:12:47 +00002673 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
2674 NTLMSSP_NEGOTIATE_56 |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002676 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002678/* if (ntlmv2_support)
Steve French39798772006-05-31 22:40:51 +00002679 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 /* setup pointers to domain name and workstation name */
2681 bcc_ptr += SecurityBlobLength;
2682
2683 SecurityBlob->WorkstationName.Buffer = 0;
2684 SecurityBlob->WorkstationName.Length = 0;
2685 SecurityBlob->WorkstationName.MaximumLength = 0;
2686
Steve French12b3b8f2006-02-09 21:12:47 +00002687 /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent
2688 along with username on auth request (ie the response to challenge) */
2689 SecurityBlob->DomainName.Buffer = 0;
2690 SecurityBlob->DomainName.Length = 0;
2691 SecurityBlob->DomainName.MaximumLength = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692 if (ses->capabilities & CAP_UNICODE) {
2693 if ((long) bcc_ptr % 2) {
2694 *bcc_ptr = 0;
2695 bcc_ptr++;
2696 }
2697
2698 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002699 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700 32, nls_codepage);
2701 bcc_ptr += 2 * bytes_returned;
2702 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002703 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 nls_codepage);
2705 bcc_ptr += 2 * bytes_returned;
2706 bcc_ptr += 2; /* null terminate Linux version */
2707 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002708 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 64, nls_codepage);
2710 bcc_ptr += 2 * bytes_returned;
2711 *(bcc_ptr + 1) = 0;
2712 *(bcc_ptr + 2) = 0;
2713 bcc_ptr += 2; /* null terminate network opsys string */
2714 *(bcc_ptr + 1) = 0;
2715 *(bcc_ptr + 2) = 0;
2716 bcc_ptr += 2; /* null domain */
2717 } else { /* ASCII */
2718 strcpy(bcc_ptr, "Linux version ");
2719 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002720 strcpy(bcc_ptr, utsname()->release);
2721 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2723 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2724 bcc_ptr++; /* empty domain field */
2725 *bcc_ptr = 0;
2726 }
2727 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2728 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2729 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2730 smb_buffer->smb_buf_length += count;
2731 pSMB->req.ByteCount = cpu_to_le16(count);
2732
2733 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00002734 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735
2736 if (smb_buffer_response->Status.CifsError ==
2737 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2738 rc = 0;
2739
2740 if (rc) {
2741/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2742 } else if ((smb_buffer_response->WordCount == 3)
2743 || (smb_buffer_response->WordCount == 4)) {
2744 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2745 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2746
2747 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002748 cFYI(1, (" Guest login"));
2749 /* Do we want to set anything in SesInfo struct when guest login? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750
Steve French50c2f752007-07-13 00:33:32 +00002751 bcc_ptr = pByteArea(smb_buffer_response);
2752 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753
2754 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2755 if (SecurityBlob2->MessageType != NtLmChallenge) {
2756 cFYI(1,
2757 ("Unexpected NTLMSSP message type received %d",
2758 SecurityBlob2->MessageType));
2759 } else if (ses) {
Steve French50c2f752007-07-13 00:33:32 +00002760 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
Steve French12b3b8f2006-02-09 21:12:47 +00002761 cFYI(1, ("UID = %d", ses->Suid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762 if ((pSMBr->resp.hdr.WordCount == 3)
2763 || ((pSMBr->resp.hdr.WordCount == 4)
2764 && (blob_len <
2765 pSMBr->resp.ByteCount))) {
2766
2767 if (pSMBr->resp.hdr.WordCount == 4) {
2768 bcc_ptr += blob_len;
Steve French12b3b8f2006-02-09 21:12:47 +00002769 cFYI(1, ("Security Blob Length %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 blob_len));
2771 }
2772
Steve French12b3b8f2006-02-09 21:12:47 +00002773 cFYI(1, ("NTLMSSP Challenge rcvd"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774
2775 memcpy(ses->server->cryptKey,
2776 SecurityBlob2->Challenge,
2777 CIFS_CRYPTO_KEY_SIZE);
Steve French50c2f752007-07-13 00:33:32 +00002778 if (SecurityBlob2->NegotiateFlags &
Steve French12b3b8f2006-02-09 21:12:47 +00002779 cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
Steve French4b18f2a2008-04-29 00:06:05 +00002780 *pNTLMv2_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781
Steve French50c2f752007-07-13 00:33:32 +00002782 if ((SecurityBlob2->NegotiateFlags &
2783 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784 || (sign_CIFS_PDUs > 1))
Steve French50c2f752007-07-13 00:33:32 +00002785 ses->server->secMode |=
2786 SECMODE_SIGN_REQUIRED;
2787 if ((SecurityBlob2->NegotiateFlags &
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
Steve French50c2f752007-07-13 00:33:32 +00002789 ses->server->secMode |=
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790 SECMODE_SIGN_ENABLED;
2791
2792 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2793 if ((long) (bcc_ptr) % 2) {
2794 remaining_words =
2795 (BCC(smb_buffer_response)
2796 - 1) / 2;
Steve French50c2f752007-07-13 00:33:32 +00002797 /* Must word align unicode strings */
2798 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 } else {
2800 remaining_words =
2801 BCC
2802 (smb_buffer_response) / 2;
2803 }
2804 len =
2805 UniStrnlen((wchar_t *) bcc_ptr,
2806 remaining_words - 1);
2807/* We look for obvious messed up bcc or strings in response so we do not go off
2808 the end since (at least) WIN2K and Windows XP have a major bug in not null
2809 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002810 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002811 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002813 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002815 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816 bcc_ptr, len,
2817 nls_codepage);
2818 bcc_ptr += 2 * (len + 1);
2819 remaining_words -= len + 1;
2820 ses->serverOS[2 * len] = 0;
2821 ses->serverOS[1 + (2 * len)] = 0;
2822 if (remaining_words > 0) {
2823 len = UniStrnlen((wchar_t *)
2824 bcc_ptr,
2825 remaining_words
2826 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002827 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002829 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830 GFP_KERNEL);
2831 cifs_strfromUCS_le(ses->
2832 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002833 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834 bcc_ptr,
2835 len,
2836 nls_codepage);
2837 bcc_ptr += 2 * (len + 1);
2838 ses->serverNOS[2 * len] = 0;
2839 ses->serverNOS[1 +
2840 (2 * len)] = 0;
2841 remaining_words -= len + 1;
2842 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00002843 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2844 /* last string not always null terminated
2845 (for e.g. for Windows XP & 2000) */
Steve Frenchcd49b492006-06-26 04:22:36 +00002846 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002848 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849 (len +
2850 1),
2851 GFP_KERNEL);
2852 cifs_strfromUCS_le
Steve Frenche89dc922005-11-11 15:18:19 -08002853 (ses->serverDomain,
2854 (__le16 *)bcc_ptr,
2855 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856 bcc_ptr +=
2857 2 * (len + 1);
Steve Frenche89dc922005-11-11 15:18:19 -08002858 ses->serverDomain[2*len]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859 = 0;
Steve Frenche89dc922005-11-11 15:18:19 -08002860 ses->serverDomain
2861 [1 + (2 * len)]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862 = 0;
2863 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002864 else {
Steve Frenchcd49b492006-06-26 04:22:36 +00002865 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002867 kzalloc(2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868 GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002869 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870 } else { /* no room so create dummy domain and NOS string */
Steve Frenchcd49b492006-06-26 04:22:36 +00002871 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002873 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002874 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002876 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 }
2878 } else { /* ASCII */
2879 len = strnlen(bcc_ptr, 1024);
2880 if (((long) bcc_ptr + len) - (long)
2881 pByteArea(smb_buffer_response)
2882 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002883 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002884 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002886 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 GFP_KERNEL);
2888 strncpy(ses->serverOS,
2889 bcc_ptr, len);
2890
2891 bcc_ptr += len;
2892 bcc_ptr[0] = 0; /* null terminate string */
2893 bcc_ptr++;
2894
2895 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002896 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002898 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 GFP_KERNEL);
2900 strncpy(ses->serverNOS, bcc_ptr, len);
2901 bcc_ptr += len;
2902 bcc_ptr[0] = 0;
2903 bcc_ptr++;
2904
2905 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002906 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002908 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +00002910 strncpy(ses->serverDomain,
2911 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912 bcc_ptr += len;
2913 bcc_ptr[0] = 0;
2914 bcc_ptr++;
2915 } else
2916 cFYI(1,
Steve French63135e02007-07-17 17:34:02 +00002917 ("field of length %d "
2918 "extends beyond end of smb",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919 len));
2920 }
2921 } else {
Steve French50c2f752007-07-13 00:33:32 +00002922 cERROR(1, ("Security Blob Length extends beyond"
2923 " end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924 }
2925 } else {
2926 cERROR(1, ("No session structure passed in."));
2927 }
2928 } else {
2929 cERROR(1,
Steve French5815449d2006-02-14 01:36:20 +00002930 (" Invalid Word count %d:",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931 smb_buffer_response->WordCount));
2932 rc = -EIO;
2933 }
2934
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00002935 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936
2937 return rc;
2938}
2939static int
2940CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French4b18f2a2008-04-29 00:06:05 +00002941 char *ntlm_session_key, bool ntlmv2_flag,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002942 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943{
2944 struct smb_hdr *smb_buffer;
2945 struct smb_hdr *smb_buffer_response;
2946 SESSION_SETUP_ANDX *pSMB;
2947 SESSION_SETUP_ANDX *pSMBr;
2948 char *bcc_ptr;
2949 char *user;
2950 char *domain;
2951 int rc = 0;
2952 int remaining_words = 0;
2953 int bytes_returned = 0;
2954 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002955 int SecurityBlobLength = sizeof(AUTHENTICATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956 PAUTHENTICATE_MESSAGE SecurityBlob;
2957 __u32 negotiate_flags, capabilities;
2958 __u16 count;
2959
2960 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002961 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962 return -EINVAL;
2963 user = ses->userName;
2964 domain = ses->domainName;
2965 smb_buffer = cifs_buf_get();
2966 if (smb_buffer == NULL) {
2967 return -ENOMEM;
2968 }
2969 smb_buffer_response = smb_buffer;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002970 pSMB = (SESSION_SETUP_ANDX *)smb_buffer;
2971 pSMBr = (SESSION_SETUP_ANDX *)smb_buffer_response;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972
2973 /* send SMBsessionSetup here */
2974 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2975 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002976
2977 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2979 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2980 pSMB->req.AndXCommand = 0xFF;
2981 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2982 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2983
2984 pSMB->req.hdr.Uid = ses->Suid;
2985
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002986 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2988
2989 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002990 CAP_EXTENDED_SECURITY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991 if (ses->capabilities & CAP_UNICODE) {
2992 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2993 capabilities |= CAP_UNICODE;
2994 }
2995 if (ses->capabilities & CAP_STATUS32) {
2996 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2997 capabilities |= CAP_STATUS32;
2998 }
2999 if (ses->capabilities & CAP_DFS) {
3000 smb_buffer->Flags2 |= SMBFLG2_DFS;
3001 capabilities |= CAP_DFS;
3002 }
3003 pSMB->req.Capabilities = cpu_to_le32(capabilities);
3004
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003005 bcc_ptr = (char *)&pSMB->req.SecurityBlob;
3006 SecurityBlob = (PAUTHENTICATE_MESSAGE)bcc_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
3008 SecurityBlob->MessageType = NtLmAuthenticate;
3009 bcc_ptr += SecurityBlobLength;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003010 negotiate_flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
3011 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
3012 0x80000000 | NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003013 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003015 if (ntlmv2_flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
3017
3018/* setup pointers to domain name and workstation name */
3019
3020 SecurityBlob->WorkstationName.Buffer = 0;
3021 SecurityBlob->WorkstationName.Length = 0;
3022 SecurityBlob->WorkstationName.MaximumLength = 0;
3023 SecurityBlob->SessionKey.Length = 0;
3024 SecurityBlob->SessionKey.MaximumLength = 0;
3025 SecurityBlob->SessionKey.Buffer = 0;
3026
3027 SecurityBlob->LmChallengeResponse.Length = 0;
3028 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
3029 SecurityBlob->LmChallengeResponse.Buffer = 0;
3030
3031 SecurityBlob->NtChallengeResponse.Length =
Steve French7c7b25b2006-06-01 19:20:10 +00003032 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033 SecurityBlob->NtChallengeResponse.MaximumLength =
Steve French7c7b25b2006-06-01 19:20:10 +00003034 cpu_to_le16(CIFS_SESS_KEY_SIZE);
3035 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003036 SecurityBlob->NtChallengeResponse.Buffer =
3037 cpu_to_le32(SecurityBlobLength);
Steve French7c7b25b2006-06-01 19:20:10 +00003038 SecurityBlobLength += CIFS_SESS_KEY_SIZE;
3039 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003040
3041 if (ses->capabilities & CAP_UNICODE) {
3042 if (domain == NULL) {
3043 SecurityBlob->DomainName.Buffer = 0;
3044 SecurityBlob->DomainName.Length = 0;
3045 SecurityBlob->DomainName.MaximumLength = 0;
3046 } else {
Steve French77159b42007-08-31 01:10:17 +00003047 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00003049 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003050 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003051 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052 SecurityBlob->DomainName.Buffer =
3053 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003054 bcc_ptr += ln;
3055 SecurityBlobLength += ln;
3056 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057 }
3058 if (user == NULL) {
3059 SecurityBlob->UserName.Buffer = 0;
3060 SecurityBlob->UserName.Length = 0;
3061 SecurityBlob->UserName.MaximumLength = 0;
3062 } else {
Steve French77159b42007-08-31 01:10:17 +00003063 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00003065 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 SecurityBlob->UserName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003067 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068 SecurityBlob->UserName.Buffer =
3069 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003070 bcc_ptr += ln;
3071 SecurityBlobLength += ln;
3072 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073 }
3074
Steve French63135e02007-07-17 17:34:02 +00003075 /* SecurityBlob->WorkstationName.Length =
3076 cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077 SecurityBlob->WorkstationName.Length *= 2;
Steve French63135e02007-07-17 17:34:02 +00003078 SecurityBlob->WorkstationName.MaximumLength =
3079 cpu_to_le16(SecurityBlob->WorkstationName.Length);
3080 SecurityBlob->WorkstationName.Buffer =
3081 cpu_to_le32(SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003082 bcc_ptr += SecurityBlob->WorkstationName.Length;
3083 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
Steve French63135e02007-07-17 17:34:02 +00003084 SecurityBlob->WorkstationName.Length =
3085 cpu_to_le16(SecurityBlob->WorkstationName.Length); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086
3087 if ((long) bcc_ptr % 2) {
3088 *bcc_ptr = 0;
3089 bcc_ptr++;
3090 }
3091 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003092 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093 32, nls_codepage);
3094 bcc_ptr += 2 * bytes_returned;
3095 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003096 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097 nls_codepage);
3098 bcc_ptr += 2 * bytes_returned;
3099 bcc_ptr += 2; /* null term version string */
3100 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003101 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102 64, nls_codepage);
3103 bcc_ptr += 2 * bytes_returned;
3104 *(bcc_ptr + 1) = 0;
3105 *(bcc_ptr + 2) = 0;
3106 bcc_ptr += 2; /* null terminate network opsys string */
3107 *(bcc_ptr + 1) = 0;
3108 *(bcc_ptr + 2) = 0;
3109 bcc_ptr += 2; /* null domain */
3110 } else { /* ASCII */
3111 if (domain == NULL) {
3112 SecurityBlob->DomainName.Buffer = 0;
3113 SecurityBlob->DomainName.Length = 0;
3114 SecurityBlob->DomainName.MaximumLength = 0;
3115 } else {
Steve French77159b42007-08-31 01:10:17 +00003116 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
3118 strncpy(bcc_ptr, domain, 63);
Steve French77159b42007-08-31 01:10:17 +00003119 ln = strnlen(domain, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003121 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122 SecurityBlob->DomainName.Buffer =
3123 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003124 bcc_ptr += ln;
3125 SecurityBlobLength += ln;
3126 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003127 }
3128 if (user == NULL) {
3129 SecurityBlob->UserName.Buffer = 0;
3130 SecurityBlob->UserName.Length = 0;
3131 SecurityBlob->UserName.MaximumLength = 0;
3132 } else {
Steve French77159b42007-08-31 01:10:17 +00003133 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134 strncpy(bcc_ptr, user, 63);
Steve French77159b42007-08-31 01:10:17 +00003135 ln = strnlen(user, 64);
3136 SecurityBlob->UserName.MaximumLength = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137 SecurityBlob->UserName.Buffer =
Steve French77159b42007-08-31 01:10:17 +00003138 cpu_to_le32(SecurityBlobLength);
3139 bcc_ptr += ln;
3140 SecurityBlobLength += ln;
3141 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142 }
3143 /* BB fill in our workstation name if known BB */
3144
3145 strcpy(bcc_ptr, "Linux version ");
3146 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003147 strcpy(bcc_ptr, utsname()->release);
3148 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
3150 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
3151 bcc_ptr++; /* null domain */
3152 *bcc_ptr = 0;
3153 }
3154 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
3155 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
3156 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
3157 smb_buffer->smb_buf_length += count;
3158 pSMB->req.ByteCount = cpu_to_le16(count);
3159
3160 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00003161 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162 if (rc) {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003163/* rc = map_smb_to_linux_error(smb_buffer_response) done in SendReceive now */
3164 } else if ((smb_buffer_response->WordCount == 3) ||
3165 (smb_buffer_response->WordCount == 4)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166 __u16 action = le16_to_cpu(pSMBr->resp.Action);
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003167 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00003169 cFYI(1, (" Guest login")); /* BB Should we set anything
3170 in SesInfo struct ? */
3171/* if (SecurityBlob2->MessageType != NtLm??) {
3172 cFYI("Unexpected message type on auth response is %d"));
3173 } */
3174
Linus Torvalds1da177e2005-04-16 15:20:36 -07003175 if (ses) {
3176 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003177 ("Check challenge UID %d vs auth response UID %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003178 ses->Suid, smb_buffer_response->Uid));
Steve French50c2f752007-07-13 00:33:32 +00003179 /* UID left in wire format */
3180 ses->Suid = smb_buffer_response->Uid;
3181 bcc_ptr = pByteArea(smb_buffer_response);
3182 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003183 if ((pSMBr->resp.hdr.WordCount == 3)
3184 || ((pSMBr->resp.hdr.WordCount == 4)
3185 && (blob_len <
3186 pSMBr->resp.ByteCount))) {
3187 if (pSMBr->resp.hdr.WordCount == 4) {
3188 bcc_ptr +=
3189 blob_len;
3190 cFYI(1,
3191 ("Security Blob Length %d ",
3192 blob_len));
3193 }
3194
3195 cFYI(1,
3196 ("NTLMSSP response to Authenticate "));
3197
3198 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3199 if ((long) (bcc_ptr) % 2) {
3200 remaining_words =
3201 (BCC(smb_buffer_response)
3202 - 1) / 2;
3203 bcc_ptr++; /* Unicode strings must be word aligned */
3204 } else {
3205 remaining_words = BCC(smb_buffer_response) / 2;
3206 }
Steve French77159b42007-08-31 01:10:17 +00003207 len = UniStrnlen((wchar_t *) bcc_ptr,
3208 remaining_words - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209/* We look for obvious messed up bcc or strings in response so we do not go off
3210 the end since (at least) WIN2K and Windows XP have a major bug in not null
3211 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003212 if (ses->serverOS)
Steve French08775832006-05-30 18:08:26 +00003213 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003215 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003216 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003217 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218 bcc_ptr, len,
3219 nls_codepage);
3220 bcc_ptr += 2 * (len + 1);
3221 remaining_words -= len + 1;
3222 ses->serverOS[2 * len] = 0;
3223 ses->serverOS[1 + (2 * len)] = 0;
3224 if (remaining_words > 0) {
3225 len = UniStrnlen((wchar_t *)
3226 bcc_ptr,
3227 remaining_words
3228 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00003229 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003231 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232 GFP_KERNEL);
3233 cifs_strfromUCS_le(ses->
3234 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003235 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236 bcc_ptr,
3237 len,
3238 nls_codepage);
3239 bcc_ptr += 2 * (len + 1);
3240 ses->serverNOS[2 * len] = 0;
3241 ses->serverNOS[1+(2*len)] = 0;
3242 remaining_words -= len + 1;
3243 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00003244 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003245 /* last string not always null terminated (e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003246 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003247 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003249 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250 (len +
3251 1),
3252 GFP_KERNEL);
3253 cifs_strfromUCS_le
3254 (ses->
3255 serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08003256 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003257 bcc_ptr, len,
3258 nls_codepage);
3259 bcc_ptr +=
3260 2 * (len + 1);
3261 ses->
3262 serverDomain[2
3263 * len]
3264 = 0;
3265 ses->
3266 serverDomain[1
3267 +
3268 (2
3269 *
3270 len)]
3271 = 0;
3272 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003273 else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003274 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003275 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003276 ses->serverDomain = kzalloc(2,GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00003277 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003278 } else { /* no room so create dummy domain and NOS string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003279 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003280 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003281 ses->serverDomain = kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00003282 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003283 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003284 }
3285 } else { /* ASCII */
3286 len = strnlen(bcc_ptr, 1024);
Steve French50c2f752007-07-13 00:33:32 +00003287 if (((long) bcc_ptr + len) -
3288 (long) pByteArea(smb_buffer_response)
Steve French63135e02007-07-17 17:34:02 +00003289 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003290 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00003291 kfree(ses->serverOS);
Steve French77159b42007-08-31 01:10:17 +00003292 ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003293 strncpy(ses->serverOS,bcc_ptr, len);
3294
3295 bcc_ptr += len;
3296 bcc_ptr[0] = 0; /* null terminate the string */
3297 bcc_ptr++;
3298
3299 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003300 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00003301 ses->serverNOS = kzalloc(len+1,
3302 GFP_KERNEL);
Steve French63135e02007-07-17 17:34:02 +00003303 strncpy(ses->serverNOS,
3304 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305 bcc_ptr += len;
3306 bcc_ptr[0] = 0;
3307 bcc_ptr++;
3308
3309 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003310 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003311 kfree(ses->serverDomain);
Steve French63135e02007-07-17 17:34:02 +00003312 ses->serverDomain =
3313 kzalloc(len+1,
3314 GFP_KERNEL);
3315 strncpy(ses->serverDomain,
3316 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317 bcc_ptr += len;
3318 bcc_ptr[0] = 0;
3319 bcc_ptr++;
3320 } else
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003321 cFYI(1, ("field of length %d "
Steve French63135e02007-07-17 17:34:02 +00003322 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003323 len));
3324 }
3325 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003326 cERROR(1, ("Security Blob extends beyond end "
Steve French63135e02007-07-17 17:34:02 +00003327 "of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328 }
3329 } else {
3330 cERROR(1, ("No session structure passed in."));
3331 }
3332 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003333 cERROR(1, ("Invalid Word count %d: ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334 smb_buffer_response->WordCount));
3335 rc = -EIO;
3336 }
3337
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003338 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339
3340 return rc;
3341}
3342
3343int
3344CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3345 const char *tree, struct cifsTconInfo *tcon,
3346 const struct nls_table *nls_codepage)
3347{
3348 struct smb_hdr *smb_buffer;
3349 struct smb_hdr *smb_buffer_response;
3350 TCONX_REQ *pSMB;
3351 TCONX_RSP *pSMBr;
3352 unsigned char *bcc_ptr;
3353 int rc = 0;
3354 int length;
3355 __u16 count;
3356
3357 if (ses == NULL)
3358 return -EIO;
3359
3360 smb_buffer = cifs_buf_get();
3361 if (smb_buffer == NULL) {
3362 return -ENOMEM;
3363 }
3364 smb_buffer_response = smb_buffer;
3365
3366 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3367 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003368
3369 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370 smb_buffer->Uid = ses->Suid;
3371 pSMB = (TCONX_REQ *) smb_buffer;
3372 pSMBr = (TCONX_RSP *) smb_buffer_response;
3373
3374 pSMB->AndXCommand = 0xFF;
3375 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003376 bcc_ptr = &pSMB->Password[0];
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003377 if ((ses->server->secMode) & SECMODE_USER) {
Steve Frencheeac8042006-01-13 21:34:58 -08003378 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00003379 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08003380 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00003381 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08003382 } else {
Steve French7c7b25b2006-06-01 19:20:10 +00003383 pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08003384 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
3385 specified as required (when that support is added to
3386 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00003387 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08003388 by Samba (not sure whether other servers allow
3389 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00003390#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French50c2f752007-07-13 00:33:32 +00003391 if ((extended_security & CIFSSEC_MAY_LANMAN) &&
Steve French7c7b25b2006-06-01 19:20:10 +00003392 (ses->server->secType == LANMAN))
3393 calc_lanman_hash(ses, bcc_ptr);
3394 else
3395#endif /* CIFS_WEAK_PW_HASH */
Steve Frencheeac8042006-01-13 21:34:58 -08003396 SMBNTencrypt(ses->password,
3397 ses->server->cryptKey,
3398 bcc_ptr);
3399
Steve French7c7b25b2006-06-01 19:20:10 +00003400 bcc_ptr += CIFS_SESS_KEY_SIZE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003401 if (ses->capabilities & CAP_UNICODE) {
Steve French7c7b25b2006-06-01 19:20:10 +00003402 /* must align unicode strings */
3403 *bcc_ptr = 0; /* null byte password */
3404 bcc_ptr++;
3405 }
Steve Frencheeac8042006-01-13 21:34:58 -08003406 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407
Steve French50c2f752007-07-13 00:33:32 +00003408 if (ses->server->secMode &
Steve Frencha878fb22006-05-30 18:04:19 +00003409 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003410 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3411
3412 if (ses->capabilities & CAP_STATUS32) {
3413 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3414 }
3415 if (ses->capabilities & CAP_DFS) {
3416 smb_buffer->Flags2 |= SMBFLG2_DFS;
3417 }
3418 if (ses->capabilities & CAP_UNICODE) {
3419 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3420 length =
Steve French50c2f752007-07-13 00:33:32 +00003421 cifs_strtoUCS((__le16 *) bcc_ptr, tree,
3422 6 /* max utf8 char length in bytes */ *
Steve Frencha878fb22006-05-30 18:04:19 +00003423 (/* server len*/ + 256 /* share len */), nls_codepage);
3424 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425 bcc_ptr += 2; /* skip trailing null */
3426 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427 strcpy(bcc_ptr, tree);
3428 bcc_ptr += strlen(tree) + 1;
3429 }
3430 strcpy(bcc_ptr, "?????");
3431 bcc_ptr += strlen("?????");
3432 bcc_ptr += 1;
3433 count = bcc_ptr - &pSMB->Password[0];
3434 pSMB->hdr.smb_buf_length += count;
3435 pSMB->ByteCount = cpu_to_le16(count);
3436
Steve French133672e2007-11-13 22:41:37 +00003437 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
3438 CIFS_STD_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439
3440 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3441 /* above now done in SendReceive */
3442 if ((rc == 0) && (tcon != NULL)) {
3443 tcon->tidStatus = CifsGood;
3444 tcon->tid = smb_buffer_response->Tid;
3445 bcc_ptr = pByteArea(smb_buffer_response);
3446 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
Steve French50c2f752007-07-13 00:33:32 +00003447 /* skip service field (NB: this field is always ASCII) */
Steve French7f8ed422007-09-28 22:28:55 +00003448 if (length == 3) {
3449 if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') &&
3450 (bcc_ptr[2] == 'C')) {
3451 cFYI(1, ("IPC connection"));
3452 tcon->ipc = 1;
3453 }
3454 } else if (length == 2) {
3455 if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) {
3456 /* the most common case */
3457 cFYI(1, ("disk share connection"));
3458 }
3459 }
Steve French50c2f752007-07-13 00:33:32 +00003460 bcc_ptr += length + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3462 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3463 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3464 if ((bcc_ptr + (2 * length)) -
3465 pByteArea(smb_buffer_response) <=
3466 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003467 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003469 kzalloc(length + 2, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003470 if (tcon->nativeFileSystem)
3471 cifs_strfromUCS_le(
3472 tcon->nativeFileSystem,
3473 (__le16 *) bcc_ptr,
3474 length, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475 bcc_ptr += 2 * length;
3476 bcc_ptr[0] = 0; /* null terminate the string */
3477 bcc_ptr[1] = 0;
3478 bcc_ptr += 2;
3479 }
Steve French50c2f752007-07-13 00:33:32 +00003480 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003481 } else {
3482 length = strnlen(bcc_ptr, 1024);
3483 if ((bcc_ptr + length) -
3484 pByteArea(smb_buffer_response) <=
3485 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003486 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003488 kzalloc(length + 1, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003489 if (tcon->nativeFileSystem)
3490 strncpy(tcon->nativeFileSystem, bcc_ptr,
3491 length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492 }
Steve French50c2f752007-07-13 00:33:32 +00003493 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003495 if ((smb_buffer_response->WordCount == 3) ||
Steve French1a4e15a2006-10-12 21:33:51 +00003496 (smb_buffer_response->WordCount == 7))
3497 /* field is in same location */
Steve French39798772006-05-31 22:40:51 +00003498 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3499 else
3500 tcon->Flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3502 } else if ((rc == 0) && tcon == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00003503 /* all we need to save for IPC$ connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504 ses->ipc_tid = smb_buffer_response->Tid;
3505 }
3506
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003507 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003508 return rc;
3509}
3510
3511int
3512cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3513{
3514 int rc = 0;
3515 int xid;
3516 struct cifsSesInfo *ses = NULL;
3517 struct task_struct *cifsd_task;
Steve French50c2f752007-07-13 00:33:32 +00003518 char *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003519
3520 xid = GetXid();
3521
3522 if (cifs_sb->tcon) {
3523 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3524 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3525 if (rc == -EBUSY) {
3526 FreeXid(xid);
3527 return 0;
3528 }
Steve French5d941ca2008-04-15 18:40:48 +00003529 DeleteTconOplockQEntries(cifs_sb->tcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530 tconInfoFree(cifs_sb->tcon);
3531 if ((ses) && (ses->server)) {
3532 /* save off task so we do not refer to ses later */
3533 cifsd_task = ses->server->tsk;
3534 cFYI(1, ("About to do SMBLogoff "));
3535 rc = CIFSSMBLogoff(xid, ses);
3536 if (rc == -EBUSY) {
3537 FreeXid(xid);
3538 return 0;
3539 } else if (rc == -ESHUTDOWN) {
Steve French467a8f82007-06-27 22:41:32 +00003540 cFYI(1, ("Waking up socket by sending signal"));
Steve Frenchf7f7c312007-05-24 02:29:51 +00003541 if (cifsd_task) {
Steve French50c2f752007-07-13 00:33:32 +00003542 force_sig(SIGKILL, cifsd_task);
Igor Mammedovaaf737a2007-04-03 19:16:43 +00003543 kthread_stop(cifsd_task);
Steve Frenchf1914012005-08-18 09:37:34 -07003544 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003545 rc = 0;
3546 } /* else - we have an smb session
3547 left on this socket do not kill cifsd */
3548 } else
3549 cFYI(1, ("No session or bad tcon"));
3550 }
Steve French50c2f752007-07-13 00:33:32 +00003551
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552 cifs_sb->tcon = NULL;
Steve French2fe87f02006-09-21 07:02:52 +00003553 tmp = cifs_sb->prepath;
3554 cifs_sb->prepathlen = 0;
3555 cifs_sb->prepath = NULL;
3556 kfree(tmp);
Nishanth Aravamudan041e0e32005-09-10 00:27:23 -07003557 if (ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558 sesInfoFree(ses);
3559
3560 FreeXid(xid);
Steve French88e7d702008-01-03 17:37:09 +00003561 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003562}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563
3564int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
Steve French50c2f752007-07-13 00:33:32 +00003565 struct nls_table *nls_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566{
3567 int rc = 0;
Steve French7c7b25b2006-06-01 19:20:10 +00003568 char ntlm_session_key[CIFS_SESS_KEY_SIZE];
Steve French4b18f2a2008-04-29 00:06:05 +00003569 bool ntlmv2_flag = false;
Steve Frenchad009ac2005-04-28 22:41:05 -07003570 int first_time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003571
3572 /* what if server changes its buffer size after dropping the session? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003573 if (pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003575 if (rc == -EAGAIN) /* retry only once on 1st time connection */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve French50c2f752007-07-13 00:33:32 +00003577 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003578 rc = -EHOSTDOWN;
3579 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003580 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003581 spin_lock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003582 if (pSesInfo->server->tcpStatus != CifsExiting)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003583 pSesInfo->server->tcpStatus = CifsGood;
3584 else
3585 rc = -EHOSTDOWN;
3586 spin_unlock(&GlobalMid_Lock);
3587
3588 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003589 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590 }
3591 if (!rc) {
Steve French9ac00b72006-09-30 04:13:17 +00003592 pSesInfo->flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593 pSesInfo->capabilities = pSesInfo->server->capabilities;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003594 if (linuxExtEnabled == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003595 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003596 /* pSesInfo->sequence_number = 0;*/
Steve French50c2f752007-07-13 00:33:32 +00003597 cFYI(1,
3598 ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599 pSesInfo->server->secMode,
3600 pSesInfo->server->capabilities,
Steve French175ec9e2006-09-30 01:07:38 +00003601 pSesInfo->server->timeAdj));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003602 if (experimEnabled < 2)
Steve French39798772006-05-31 22:40:51 +00003603 rc = CIFS_SessSetup(xid, pSesInfo,
3604 first_time, nls_info);
Steve French189acaa2006-06-23 02:33:48 +00003605 else if (extended_security
Steve French50c2f752007-07-13 00:33:32 +00003606 && (pSesInfo->capabilities
Steve French175ec9e2006-09-30 01:07:38 +00003607 & CAP_EXTENDED_SECURITY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608 && (pSesInfo->server->secType == NTLMSSP)) {
Steve French189acaa2006-06-23 02:33:48 +00003609 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610 } else if (extended_security
3611 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3612 && (pSesInfo->server->secType == RawNTLMSSP)) {
Steve French5815449d2006-02-14 01:36:20 +00003613 cFYI(1, ("NTLMSSP sesssetup"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003614 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3615 pSesInfo,
3616 &ntlmv2_flag,
3617 nls_info);
3618 if (!rc) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003619 if (ntlmv2_flag) {
Steve French50c2f752007-07-13 00:33:32 +00003620 char *v2_response;
Steve French467a8f82007-06-27 22:41:32 +00003621 cFYI(1, ("more secure NTLM ver2 hash"));
Steve French50c2f752007-07-13 00:33:32 +00003622 if (CalcNTLMv2_partial_mac_key(pSesInfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623 nls_info)) {
3624 rc = -ENOMEM;
3625 goto ss_err_exit;
3626 } else
3627 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003628 if (v2_response) {
Steve French50c2f752007-07-13 00:33:32 +00003629 CalcNTLMv2_response(pSesInfo,
3630 v2_response);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003631 /* if (first_time)
Steve French50c2f752007-07-13 00:33:32 +00003632 cifs_calculate_ntlmv2_mac_key(
3633 pSesInfo->server->mac_signing_key,
3634 response, ntlm_session_key,*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635 kfree(v2_response);
3636 /* BB Put dummy sig in SessSetup PDU? */
3637 } else {
3638 rc = -ENOMEM;
3639 goto ss_err_exit;
3640 }
3641
3642 } else {
3643 SMBNTencrypt(pSesInfo->password,
3644 pSesInfo->server->cryptKey,
3645 ntlm_session_key);
3646
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003647 if (first_time)
Steve Frenchad009ac2005-04-28 22:41:05 -07003648 cifs_calculate_mac_key(
Steve Frenchb609f062007-07-09 07:55:14 +00003649 &pSesInfo->server->mac_signing_key,
Steve Frenchad009ac2005-04-28 22:41:05 -07003650 ntlm_session_key,
3651 pSesInfo->password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003652 }
3653 /* for better security the weaker lanman hash not sent
3654 in AuthSessSetup so we no longer calculate it */
3655
3656 rc = CIFSNTLMSSPAuthSessSetup(xid,
3657 pSesInfo,
3658 ntlm_session_key,
3659 ntlmv2_flag,
3660 nls_info);
3661 }
3662 } else { /* old style NTLM 0.12 session setup */
3663 SMBNTencrypt(pSesInfo->password,
3664 pSesInfo->server->cryptKey,
3665 ntlm_session_key);
3666
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003667 if (first_time)
Steve Frenchad009ac2005-04-28 22:41:05 -07003668 cifs_calculate_mac_key(
Steve Frenchb609f062007-07-09 07:55:14 +00003669 &pSesInfo->server->mac_signing_key,
Steve Frenchad009ac2005-04-28 22:41:05 -07003670 ntlm_session_key, pSesInfo->password);
3671
Linus Torvalds1da177e2005-04-16 15:20:36 -07003672 rc = CIFSSessSetup(xid, pSesInfo,
3673 ntlm_session_key, nls_info);
3674 }
3675 if (rc) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003676 cERROR(1, ("Send error in SessSetup = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677 } else {
Steve French467a8f82007-06-27 22:41:32 +00003678 cFYI(1, ("CIFS Session Established successfully"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003679 pSesInfo->status = CifsGood;
3680 }
3681 }
3682ss_err_exit:
3683 return rc;
3684}
3685