blob: 6444627293874f33acd3d060336b85a6e2d5cbf1 [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
Jeff Layton09e50d52008-07-23 10:11:19 -04001464#ifdef CONFIG_DEBUG_LOCK_ALLOC
1465static struct lock_class_key cifs_key[2];
1466static struct lock_class_key cifs_slock_key[2];
1467
1468static inline void
1469cifs_reclassify_socket4(struct socket *sock)
1470{
1471 struct sock *sk = sock->sk;
1472 BUG_ON(sock_owned_by_user(sk));
1473 sock_lock_init_class_and_name(sk, "slock-AF_INET-CIFS",
1474 &cifs_slock_key[0], "sk_lock-AF_INET-CIFS", &cifs_key[0]);
1475}
1476
1477static inline void
1478cifs_reclassify_socket6(struct socket *sock)
1479{
1480 struct sock *sk = sock->sk;
1481 BUG_ON(sock_owned_by_user(sk));
1482 sock_lock_init_class_and_name(sk, "slock-AF_INET6-CIFS",
1483 &cifs_slock_key[1], "sk_lock-AF_INET6-CIFS", &cifs_key[1]);
1484}
1485#else
1486static inline void
1487cifs_reclassify_socket4(struct socket *sock)
1488{
1489}
1490
1491static inline void
1492cifs_reclassify_socket6(struct socket *sock)
1493{
1494}
1495#endif
1496
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497/* See RFC1001 section 14 on representation of Netbios names */
Steve French50c2f752007-07-13 00:33:32 +00001498static void rfc1002mangle(char *target, char *source, unsigned int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499{
Steve French50c2f752007-07-13 00:33:32 +00001500 unsigned int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501
Steve French50c2f752007-07-13 00:33:32 +00001502 for (i = 0, j = 0; i < (length); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 /* mask a nibble at a time and encode */
1504 target[j] = 'A' + (0x0F & (source[i] >> 4));
1505 target[j+1] = 'A' + (0x0F & source[i]);
Steve French50c2f752007-07-13 00:33:32 +00001506 j += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 }
1508
1509}
1510
1511
1512static int
Steve French50c2f752007-07-13 00:33:32 +00001513ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
1514 char *netbios_name, char *target_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515{
1516 int rc = 0;
1517 int connected = 0;
1518 __be16 orig_port = 0;
1519
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001520 if (*csocket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001521 rc = sock_create_kern(PF_INET, SOCK_STREAM,
1522 IPPROTO_TCP, csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001524 cERROR(1, ("Error %d creating socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 *csocket = NULL;
1526 return rc;
1527 } else {
1528 /* BB other socket options to set KEEPALIVE, NODELAY? */
Steve French467a8f82007-06-27 22:41:32 +00001529 cFYI(1, ("Socket created"));
Steve French50c2f752007-07-13 00:33:32 +00001530 (*csocket)->sk->sk_allocation = GFP_NOFS;
Jeff Layton09e50d52008-07-23 10:11:19 -04001531 cifs_reclassify_socket4(*csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 }
1533 }
1534
1535 psin_server->sin_family = AF_INET;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001536 if (psin_server->sin_port) { /* user overrode default port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 rc = (*csocket)->ops->connect(*csocket,
1538 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001539 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 if (rc >= 0)
1541 connected = 1;
Steve French50c2f752007-07-13 00:33:32 +00001542 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001544 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001545 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 later if fall back ports fail this time */
1547 orig_port = psin_server->sin_port;
1548
1549 /* do not retry on the same port we just failed on */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001550 if (psin_server->sin_port != htons(CIFS_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 psin_server->sin_port = htons(CIFS_PORT);
1552
1553 rc = (*csocket)->ops->connect(*csocket,
1554 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001555 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 if (rc >= 0)
1557 connected = 1;
1558 }
1559 }
1560 if (!connected) {
1561 psin_server->sin_port = htons(RFC1001_PORT);
1562 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
Steve French50c2f752007-07-13 00:33:32 +00001563 psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001564 sizeof(struct sockaddr_in), 0);
Steve French50c2f752007-07-13 00:33:32 +00001565 if (rc >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 connected = 1;
1567 }
1568
1569 /* give up here - unless we want to retry on different
1570 protocol families some day */
1571 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001572 if (orig_port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 psin_server->sin_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001574 cFYI(1, ("Error %d connecting to server via ipv4", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 sock_release(*csocket);
1576 *csocket = NULL;
1577 return rc;
1578 }
Steve French50c2f752007-07-13 00:33:32 +00001579 /* Eventually check for other socket options to change from
1580 the default. sock_setsockopt not used because it expects
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 user space buffer */
Steve French50c2f752007-07-13 00:33:32 +00001582 cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",
1583 (*csocket)->sk->sk_sndbuf,
Steve Frenchb387eae2005-10-10 14:21:15 -07001584 (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchb387eae2005-10-10 14:21:15 -07001586 /* make the bufsizes depend on wsize/rsize and max requests */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001587 if ((*csocket)->sk->sk_sndbuf < (200 * 1024))
Steve Frenchb387eae2005-10-10 14:21:15 -07001588 (*csocket)->sk->sk_sndbuf = 200 * 1024;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001589 if ((*csocket)->sk->sk_rcvbuf < (140 * 1024))
Steve Frenchb387eae2005-10-10 14:21:15 -07001590 (*csocket)->sk->sk_rcvbuf = 140 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591
1592 /* send RFC1001 sessinit */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001593 if (psin_server->sin_port == htons(RFC1001_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 /* some servers require RFC1001 sessinit before sending
Steve French50c2f752007-07-13 00:33:32 +00001595 negprot - BB check reconnection in case where second
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 sessinit is sent but no second negprot */
Steve French50c2f752007-07-13 00:33:32 +00001597 struct rfc1002_session_packet *ses_init_buf;
1598 struct smb_hdr *smb_buf;
1599 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
1600 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001601 if (ses_init_buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 ses_init_buf->trailer.session_req.called_len = 32;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001603 if (target_name && (target_name[0] != 0)) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001604 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1605 target_name, 16);
1606 } else {
1607 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
Steve French50c2f752007-07-13 00:33:32 +00001608 DEFAULT_CIFS_CALLED_NAME, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001609 }
1610
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 ses_init_buf->trailer.session_req.calling_len = 32;
1612 /* calling name ends in null (byte 16) from old smb
1613 convention. */
Steve French50c2f752007-07-13 00:33:32 +00001614 if (netbios_name && (netbios_name[0] != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
Steve French50c2f752007-07-13 00:33:32 +00001616 netbios_name, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 } else {
1618 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
Steve French50c2f752007-07-13 00:33:32 +00001619 "LINUX_CIFS_CLNT", 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 }
1621 ses_init_buf->trailer.session_req.scope1 = 0;
1622 ses_init_buf->trailer.session_req.scope2 = 0;
1623 smb_buf = (struct smb_hdr *)ses_init_buf;
1624 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1625 smb_buf->smb_buf_length = 0x81000044;
1626 rc = smb_send(*csocket, smb_buf, 0x44,
1627 (struct sockaddr *)psin_server);
1628 kfree(ses_init_buf);
Steve French50c2f752007-07-13 00:33:32 +00001629 msleep(1); /* RFC1001 layer in at least one server
Steve French083d3a22006-03-03 09:53:36 +00001630 requires very short break before negprot
1631 presumably because not expecting negprot
1632 to follow so fast. This is a simple
Steve French50c2f752007-07-13 00:33:32 +00001633 solution that works without
Steve French083d3a22006-03-03 09:53:36 +00001634 complicating the code and causes no
1635 significant slowing down on mount
1636 for everyone else */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 }
Steve French50c2f752007-07-13 00:33:32 +00001638 /* else the negprot may still work without this
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 even though malloc failed */
Steve French50c2f752007-07-13 00:33:32 +00001640
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 }
Steve French50c2f752007-07-13 00:33:32 +00001642
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 return rc;
1644}
1645
1646static int
1647ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1648{
1649 int rc = 0;
1650 int connected = 0;
1651 __be16 orig_port = 0;
1652
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001653 if (*csocket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001654 rc = sock_create_kern(PF_INET6, SOCK_STREAM,
1655 IPPROTO_TCP, csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001657 cERROR(1, ("Error %d creating ipv6 socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 *csocket = NULL;
1659 return rc;
1660 } else {
1661 /* BB other socket options to set KEEPALIVE, NODELAY? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001662 cFYI(1, ("ipv6 Socket created"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 (*csocket)->sk->sk_allocation = GFP_NOFS;
Jeff Layton09e50d52008-07-23 10:11:19 -04001664 cifs_reclassify_socket6(*csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 }
1666 }
1667
1668 psin_server->sin6_family = AF_INET6;
1669
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001670 if (psin_server->sin6_port) { /* user overrode default port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 rc = (*csocket)->ops->connect(*csocket,
1672 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001673 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 if (rc >= 0)
1675 connected = 1;
Steve French50c2f752007-07-13 00:33:32 +00001676 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001678 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001679 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 later if fall back ports fail this time */
1681
1682 orig_port = psin_server->sin6_port;
1683 /* do not retry on the same port we just failed on */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001684 if (psin_server->sin6_port != htons(CIFS_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 psin_server->sin6_port = htons(CIFS_PORT);
1686
1687 rc = (*csocket)->ops->connect(*csocket,
1688 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001689 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 if (rc >= 0)
1691 connected = 1;
1692 }
1693 }
1694 if (!connected) {
1695 psin_server->sin6_port = htons(RFC1001_PORT);
1696 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001697 psin_server, sizeof(struct sockaddr_in6), 0);
Steve French50c2f752007-07-13 00:33:32 +00001698 if (rc >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 connected = 1;
1700 }
1701
1702 /* give up here - unless we want to retry on different
1703 protocol families some day */
1704 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001705 if (orig_port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 psin_server->sin6_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001707 cFYI(1, ("Error %d connecting to server via ipv6", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 sock_release(*csocket);
1709 *csocket = NULL;
1710 return rc;
1711 }
Steve French50c2f752007-07-13 00:33:32 +00001712 /* Eventually check for other socket options to change from
1713 the default. sock_setsockopt not used because it expects
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 user space buffer */
1715 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve French50c2f752007-07-13 00:33:32 +00001716
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 return rc;
1718}
1719
Steve French50c2f752007-07-13 00:33:32 +00001720void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
1721 struct super_block *sb, struct smb_vol *vol_info)
Steve French8af18972007-02-14 04:42:51 +00001722{
1723 /* if we are reconnecting then should we check to see if
1724 * any requested capabilities changed locally e.g. via
1725 * remount but we can not do much about it here
1726 * if they have (even if we could detect it by the following)
1727 * Perhaps we could add a backpointer to array of sb from tcon
1728 * or if we change to make all sb to same share the same
1729 * sb as NFS - then we only have one backpointer to sb.
1730 * What if we wanted to mount the server share twice once with
1731 * and once without posixacls or posix paths? */
1732 __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001733
Steve Frenchc18c8422007-07-18 23:21:09 +00001734 if (vol_info && vol_info->no_linux_ext) {
1735 tcon->fsUnixInfo.Capability = 0;
1736 tcon->unix_ext = 0; /* Unix Extensions disabled */
1737 cFYI(1, ("Linux protocol extensions disabled"));
1738 return;
1739 } else if (vol_info)
1740 tcon->unix_ext = 1; /* Unix Extensions supported */
1741
1742 if (tcon->unix_ext == 0) {
1743 cFYI(1, ("Unix extensions disabled so not set on reconnect"));
1744 return;
1745 }
Steve French50c2f752007-07-13 00:33:32 +00001746
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001747 if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
Steve French8af18972007-02-14 04:42:51 +00001748 __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001749
Steve French8af18972007-02-14 04:42:51 +00001750 /* check for reconnect case in which we do not
1751 want to change the mount behavior if we can avoid it */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001752 if (vol_info == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001753 /* turn off POSIX ACL and PATHNAMES if not set
Steve French8af18972007-02-14 04:42:51 +00001754 originally at mount time */
1755 if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
1756 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00001757 if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
1758 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
1759 cERROR(1, ("POSIXPATH support change"));
Steve French8af18972007-02-14 04:42:51 +00001760 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00001761 } else if ((cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
1762 cERROR(1, ("possible reconnect error"));
1763 cERROR(1,
1764 ("server disabled POSIX path support"));
1765 }
Steve French8af18972007-02-14 04:42:51 +00001766 }
Steve French50c2f752007-07-13 00:33:32 +00001767
Steve French8af18972007-02-14 04:42:51 +00001768 cap &= CIFS_UNIX_CAP_MASK;
Steve French75865f8c2007-06-24 18:30:48 +00001769 if (vol_info && vol_info->no_psx_acl)
Steve French8af18972007-02-14 04:42:51 +00001770 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00001771 else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001772 cFYI(1, ("negotiated posix acl support"));
1773 if (sb)
Steve French8af18972007-02-14 04:42:51 +00001774 sb->s_flags |= MS_POSIXACL;
1775 }
1776
Steve French75865f8c2007-06-24 18:30:48 +00001777 if (vol_info && vol_info->posix_paths == 0)
Steve French8af18972007-02-14 04:42:51 +00001778 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00001779 else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001780 cFYI(1, ("negotiate posix pathnames"));
Steve French75865f8c2007-06-24 18:30:48 +00001781 if (sb)
Steve French50c2f752007-07-13 00:33:32 +00001782 CIFS_SB(sb)->mnt_cifs_flags |=
Steve French8af18972007-02-14 04:42:51 +00001783 CIFS_MOUNT_POSIX_PATHS;
1784 }
Steve French50c2f752007-07-13 00:33:32 +00001785
Steve French984acfe2007-04-26 16:42:50 +00001786 /* We might be setting the path sep back to a different
1787 form if we are reconnecting and the server switched its
Steve French50c2f752007-07-13 00:33:32 +00001788 posix path capability for this share */
Steve French75865f8c2007-06-24 18:30:48 +00001789 if (sb && (CIFS_SB(sb)->prepathlen > 0))
Steve French984acfe2007-04-26 16:42:50 +00001790 CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
Steve French75865f8c2007-06-24 18:30:48 +00001791
1792 if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
1793 if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
1794 CIFS_SB(sb)->rsize = 127 * 1024;
Steve French90c81e02008-02-12 20:32:36 +00001795 cFYI(DBG2,
1796 ("larger reads not supported by srv"));
Steve French75865f8c2007-06-24 18:30:48 +00001797 }
1798 }
Steve French50c2f752007-07-13 00:33:32 +00001799
1800
1801 cFYI(1, ("Negotiate caps 0x%x", (int)cap));
Steve French8af18972007-02-14 04:42:51 +00001802#ifdef CONFIG_CIFS_DEBUG2
Steve French75865f8c2007-06-24 18:30:48 +00001803 if (cap & CIFS_UNIX_FCNTL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001804 cFYI(1, ("FCNTL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001805 if (cap & CIFS_UNIX_EXTATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001806 cFYI(1, ("EXTATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001807 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001808 cFYI(1, ("POSIX path cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001809 if (cap & CIFS_UNIX_XATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001810 cFYI(1, ("XATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001811 if (cap & CIFS_UNIX_POSIX_ACL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001812 cFYI(1, ("POSIX ACL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001813 if (cap & CIFS_UNIX_LARGE_READ_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001814 cFYI(1, ("very large read cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001815 if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001816 cFYI(1, ("very large write cap"));
Steve French8af18972007-02-14 04:42:51 +00001817#endif /* CIFS_DEBUG2 */
1818 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
Steve French442aa312007-09-24 20:25:46 +00001819 if (vol_info == NULL) {
Steve French5a44b312007-09-20 15:16:24 +00001820 cFYI(1, ("resetting capabilities failed"));
Steve French442aa312007-09-24 20:25:46 +00001821 } else
Steve French5a44b312007-09-20 15:16:24 +00001822 cERROR(1, ("Negotiating Unix capabilities "
1823 "with the server failed. Consider "
1824 "mounting with the Unix Extensions\n"
1825 "disabled, if problems are found, "
1826 "by specifying the nounix mount "
Steve French2224f4e2007-09-20 15:37:29 +00001827 "option."));
Steve French5a44b312007-09-20 15:16:24 +00001828
Steve French8af18972007-02-14 04:42:51 +00001829 }
1830 }
1831}
1832
Steve French03a143c2008-02-14 06:38:30 +00001833static void
1834convert_delimiter(char *path, char delim)
1835{
1836 int i;
Steve Frenchc2d68ea2008-02-15 19:20:18 +00001837 char old_delim;
Steve French03a143c2008-02-14 06:38:30 +00001838
1839 if (path == NULL)
1840 return;
1841
Steve French582d21e2008-05-13 04:54:12 +00001842 if (delim == '/')
Steve Frenchc2d68ea2008-02-15 19:20:18 +00001843 old_delim = '\\';
1844 else
1845 old_delim = '/';
1846
Steve French03a143c2008-02-14 06:38:30 +00001847 for (i = 0; path[i] != '\0'; i++) {
Steve Frenchc2d68ea2008-02-15 19:20:18 +00001848 if (path[i] == old_delim)
Steve French03a143c2008-02-14 06:38:30 +00001849 path[i] = delim;
1850 }
1851}
1852
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853int
1854cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1855 char *mount_data, const char *devname)
1856{
1857 int rc = 0;
1858 int xid;
1859 int address_type = AF_INET;
1860 struct socket *csocket = NULL;
1861 struct sockaddr_in sin_server;
1862 struct sockaddr_in6 sin_server6;
1863 struct smb_vol volume_info;
1864 struct cifsSesInfo *pSesInfo = NULL;
1865 struct cifsSesInfo *existingCifsSes = NULL;
1866 struct cifsTconInfo *tcon = NULL;
1867 struct TCP_Server_Info *srvTcp = NULL;
1868
1869 xid = GetXid();
1870
1871/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
Steve French50c2f752007-07-13 00:33:32 +00001872
1873 memset(&volume_info, 0, sizeof(struct smb_vol));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001875 rc = -EINVAL;
1876 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 }
1878
Jeff Layton8426c392007-05-05 03:27:49 +00001879 if (volume_info.nullauth) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001880 cFYI(1, ("null user"));
Jeff Layton9b8f5f52007-11-09 23:25:04 +00001881 volume_info.username = "";
Jeff Layton8426c392007-05-05 03:27:49 +00001882 } else if (volume_info.username) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 /* BB fixme parse for domain name here */
Steve French467a8f82007-06-27 22:41:32 +00001884 cFYI(1, ("Username: %s", volume_info.username));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 } else {
Steve Frenchbf820672005-12-01 22:32:42 -08001886 cifserror("No username specified");
Steve French50c2f752007-07-13 00:33:32 +00001887 /* In userspace mount helper we can get user name from alternate
1888 locations such as env variables and files on disk */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001889 rc = -EINVAL;
1890 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 }
1892
1893 if (volume_info.UNCip && volume_info.UNC) {
Steve French50c2f752007-07-13 00:33:32 +00001894 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,
1895 &sin_server.sin_addr.s_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001897 if (rc <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 /* not ipv4 address, try ipv6 */
Steve French50c2f752007-07-13 00:33:32 +00001899 rc = cifs_inet_pton(AF_INET6, volume_info.UNCip,
1900 &sin_server6.sin6_addr.in6_u);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001901 if (rc > 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902 address_type = AF_INET6;
1903 } else {
1904 address_type = AF_INET;
1905 }
Steve French50c2f752007-07-13 00:33:32 +00001906
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001907 if (rc <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 /* we failed translating address */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001909 rc = -EINVAL;
1910 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 }
1912
1913 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1914 /* success */
1915 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00001916 } else if (volume_info.UNCip) {
1917 /* BB using ip addr as server name to connect to the
1918 DFS root below */
1919 cERROR(1, ("Connecting to DFS root not implemented yet"));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001920 rc = -EINVAL;
1921 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 } else /* which servers DFS root would we conect to */ {
1923 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00001924 ("CIFS mount error: No UNC path (e.g. -o "
1925 "unc=//192.168.1.100/public) specified"));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001926 rc = -EINVAL;
1927 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 }
1929
1930 /* this is needed for ASCII cp to Unicode converts */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001931 if (volume_info.iocharset == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 cifs_sb->local_nls = load_nls_default();
1933 /* load_nls_default can not return null */
1934 } else {
1935 cifs_sb->local_nls = load_nls(volume_info.iocharset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001936 if (cifs_sb->local_nls == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001937 cERROR(1, ("CIFS mount error: iocharset %s not found",
1938 volume_info.iocharset));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001939 rc = -ELIBACC;
1940 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 }
1942 }
1943
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001944 if (address_type == AF_INET)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1946 NULL /* no ipv6 addr */,
1947 volume_info.username, &srvTcp);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001948 else if (address_type == AF_INET6) {
1949 cFYI(1, ("looking for ipv6 address"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1951 &sin_server6.sin6_addr,
1952 volume_info.username, &srvTcp);
Steve French5858ae42007-04-25 11:59:10 +00001953 } else {
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001954 rc = -EINVAL;
1955 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 }
1957
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 if (srvTcp) {
Steve French50c2f752007-07-13 00:33:32 +00001959 cFYI(1, ("Existing tcp session with server found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 } else { /* create socket */
Steve French4523cc32007-04-30 20:13:06 +00001961 if (volume_info.port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 sin_server.sin_port = htons(volume_info.port);
1963 else
1964 sin_server.sin_port = 0;
Steve French5858ae42007-04-25 11:59:10 +00001965 if (address_type == AF_INET6) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001966 cFYI(1, ("attempting ipv6 connect"));
Steve French5858ae42007-04-25 11:59:10 +00001967 /* BB should we allow ipv6 on port 139? */
1968 /* other OS never observed in Wild doing 139 with v6 */
Steve French50c2f752007-07-13 00:33:32 +00001969 rc = ipv6_connect(&sin_server6, &csocket);
1970 } else
1971 rc = ipv4_connect(&sin_server, &csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -07001972 volume_info.source_rfc1001_name,
1973 volume_info.target_rfc1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001975 cERROR(1, ("Error connecting to IPv4 socket. "
1976 "Aborting operation"));
Steve French4523cc32007-04-30 20:13:06 +00001977 if (csocket != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978 sock_release(csocket);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001979 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 }
1981
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00001982 srvTcp = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
1983 if (!srvTcp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984 rc = -ENOMEM;
1985 sock_release(csocket);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001986 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987 } else {
Steve French50c2f752007-07-13 00:33:32 +00001988 memcpy(&srvTcp->addr.sockAddr, &sin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001989 sizeof(struct sockaddr_in));
Steve French50c2f752007-07-13 00:33:32 +00001990 atomic_set(&srvTcp->inFlight, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 /* BB Add code for ipv6 case too */
1992 srvTcp->ssocket = csocket;
1993 srvTcp->protocolType = IPV4;
Jeff Laytonc359cf32007-11-16 22:22:06 +00001994 srvTcp->hostname = extract_hostname(volume_info.UNC);
1995 if (IS_ERR(srvTcp->hostname)) {
1996 rc = PTR_ERR(srvTcp->hostname);
1997 sock_release(csocket);
1998 goto out;
1999 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 init_waitqueue_head(&srvTcp->response_q);
2001 init_waitqueue_head(&srvTcp->request_q);
2002 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
2003 /* at this point we are the only ones with the pointer
2004 to the struct since the kernel thread not created yet
2005 so no need to spinlock this init of tcpStatus */
2006 srvTcp->tcpStatus = CifsNew;
2007 init_MUTEX(&srvTcp->tcpSem);
Igor Mammedovaaf737a2007-04-03 19:16:43 +00002008 srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd");
Steve French8840dee2007-11-16 23:05:52 +00002009 if (IS_ERR(srvTcp->tsk)) {
Igor Mammedovaaf737a2007-04-03 19:16:43 +00002010 rc = PTR_ERR(srvTcp->tsk);
Steve French50c2f752007-07-13 00:33:32 +00002011 cERROR(1, ("error %d create cifsd thread", rc));
Igor Mammedovaaf737a2007-04-03 19:16:43 +00002012 srvTcp->tsk = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013 sock_release(csocket);
Jeff Laytonc359cf32007-11-16 22:22:06 +00002014 kfree(srvTcp->hostname);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002015 goto out;
Steve Frenchf1914012005-08-18 09:37:34 -07002016 }
Steve Frenchf1914012005-08-18 09:37:34 -07002017 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002018 memcpy(srvTcp->workstation_RFC1001_name,
2019 volume_info.source_rfc1001_name, 16);
2020 memcpy(srvTcp->server_RFC1001_name,
2021 volume_info.target_rfc1001_name, 16);
Steve Frenchad009ac2005-04-28 22:41:05 -07002022 srvTcp->sequence_number = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 }
2024 }
2025
2026 if (existingCifsSes) {
2027 pSesInfo = existingCifsSes;
Jeff Layton1d9a8852007-12-31 01:37:11 +00002028 cFYI(1, ("Existing smb sess found (status=%d)",
2029 pSesInfo->status));
Steve French88e7d702008-01-03 17:37:09 +00002030 down(&pSesInfo->sesSem);
Jeff Layton1d9a8852007-12-31 01:37:11 +00002031 if (pSesInfo->status == CifsNeedReconnect) {
2032 cFYI(1, ("Session needs reconnect"));
Jeff Layton1d9a8852007-12-31 01:37:11 +00002033 rc = cifs_setup_session(xid, pSesInfo,
2034 cifs_sb->local_nls);
Jeff Layton1d9a8852007-12-31 01:37:11 +00002035 }
Steve French88e7d702008-01-03 17:37:09 +00002036 up(&pSesInfo->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 } else if (!rc) {
Steve Frenchbf820672005-12-01 22:32:42 -08002038 cFYI(1, ("Existing smb sess not found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 pSesInfo = sesInfoAlloc();
2040 if (pSesInfo == NULL)
2041 rc = -ENOMEM;
2042 else {
2043 pSesInfo->server = srvTcp;
2044 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
2045 NIPQUAD(sin_server.sin_addr.s_addr));
2046 }
2047
Steve French50c2f752007-07-13 00:33:32 +00002048 if (!rc) {
2049 /* volume_info.password freed at unmount */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002050 if (volume_info.password) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051 pSesInfo->password = volume_info.password;
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002052 /* set to NULL to prevent freeing on exit */
2053 volume_info.password = NULL;
2054 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055 if (volume_info.username)
2056 strncpy(pSesInfo->userName,
Steve French50c2f752007-07-13 00:33:32 +00002057 volume_info.username,
2058 MAX_USERNAME_SIZE);
Steve French39798772006-05-31 22:40:51 +00002059 if (volume_info.domainname) {
2060 int len = strlen(volume_info.domainname);
Steve French50c2f752007-07-13 00:33:32 +00002061 pSesInfo->domainName =
Steve French39798772006-05-31 22:40:51 +00002062 kmalloc(len + 1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00002063 if (pSesInfo->domainName)
Steve French39798772006-05-31 22:40:51 +00002064 strcpy(pSesInfo->domainName,
2065 volume_info.domainname);
2066 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067 pSesInfo->linux_uid = volume_info.linux_uid;
Steve French750d1152006-06-27 06:28:30 +00002068 pSesInfo->overrideSecFlg = volume_info.secFlg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069 down(&pSesInfo->sesSem);
Steve French189acaa2006-06-23 02:33:48 +00002070 /* BB FIXME need to pass vol->secFlgs BB */
Steve French50c2f752007-07-13 00:33:32 +00002071 rc = cifs_setup_session(xid, pSesInfo,
2072 cifs_sb->local_nls);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073 up(&pSesInfo->sesSem);
Steve French4523cc32007-04-30 20:13:06 +00002074 if (!rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075 atomic_inc(&srvTcp->socketUseCount);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002076 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077 }
Steve French50c2f752007-07-13 00:33:32 +00002078
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079 /* search for existing tcon to this server share */
2080 if (!rc) {
Steve French4523cc32007-04-30 20:13:06 +00002081 if (volume_info.rsize > CIFSMaxBufSize) {
Steve French50c2f752007-07-13 00:33:32 +00002082 cERROR(1, ("rsize %d too large, using MaxBufSize",
Steve French0ae0efa2005-10-10 10:57:19 -07002083 volume_info.rsize));
2084 cifs_sb->rsize = CIFSMaxBufSize;
Steve French75865f8c2007-06-24 18:30:48 +00002085 } else if ((volume_info.rsize) &&
2086 (volume_info.rsize <= CIFSMaxBufSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087 cifs_sb->rsize = volume_info.rsize;
Steve French0ae0efa2005-10-10 10:57:19 -07002088 else /* default */
2089 cifs_sb->rsize = CIFSMaxBufSize;
2090
Steve French4523cc32007-04-30 20:13:06 +00002091 if (volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
Steve French50c2f752007-07-13 00:33:32 +00002092 cERROR(1, ("wsize %d too large, using 4096 instead",
Steve French0ae0efa2005-10-10 10:57:19 -07002093 volume_info.wsize));
2094 cifs_sb->wsize = 4096;
Steve French4523cc32007-04-30 20:13:06 +00002095 } else if (volume_info.wsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 cifs_sb->wsize = volume_info.wsize;
2097 else
Steve French50c2f752007-07-13 00:33:32 +00002098 cifs_sb->wsize =
Steve French1877c9e2006-01-27 18:36:11 -08002099 min_t(const int, PAGEVEC_SIZE * PAGE_CACHE_SIZE,
2100 127*1024);
Steve French17cbbaf2006-01-24 20:26:48 -08002101 /* old default of CIFSMaxBufSize was too small now
Steve French50c2f752007-07-13 00:33:32 +00002102 that SMB Write2 can send multiple pages in kvec.
Steve French17cbbaf2006-01-24 20:26:48 -08002103 RFC1001 does not describe what happens when frame
2104 bigger than 128K is sent so use that as max in
2105 conjunction with 52K kvec constraint on arch with 4K
2106 page size */
2107
Steve French4523cc32007-04-30 20:13:06 +00002108 if (cifs_sb->rsize < 2048) {
Steve French50c2f752007-07-13 00:33:32 +00002109 cifs_sb->rsize = 2048;
Steve French6cec2ae2006-02-22 17:31:52 -06002110 /* Windows ME may prefer this */
Steve French467a8f82007-06-27 22:41:32 +00002111 cFYI(1, ("readsize set to minimum: 2048"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112 }
Steve French2fe87f02006-09-21 07:02:52 +00002113 /* calculate prepath */
2114 cifs_sb->prepath = volume_info.prepath;
Steve French4523cc32007-04-30 20:13:06 +00002115 if (cifs_sb->prepath) {
Steve French2fe87f02006-09-21 07:02:52 +00002116 cifs_sb->prepathlen = strlen(cifs_sb->prepath);
Steve French03a143c2008-02-14 06:38:30 +00002117 /* we can not convert the / to \ in the path
2118 separators in the prefixpath yet because we do not
2119 know (until reset_cifs_unix_caps is called later)
2120 whether POSIX PATH CAP is available. We normalize
2121 the / to \ after reset_cifs_unix_caps is called */
Steve French2fe87f02006-09-21 07:02:52 +00002122 volume_info.prepath = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002123 } else
Steve French2fe87f02006-09-21 07:02:52 +00002124 cifs_sb->prepathlen = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125 cifs_sb->mnt_uid = volume_info.linux_uid;
2126 cifs_sb->mnt_gid = volume_info.linux_gid;
2127 cifs_sb->mnt_file_mode = volume_info.file_mode;
2128 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
Steve French467a8f82007-06-27 22:41:32 +00002129 cFYI(1, ("file mode: 0x%x dir mode: 0x%x",
2130 cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131
Steve French4523cc32007-04-30 20:13:06 +00002132 if (volume_info.noperm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
Steve French4523cc32007-04-30 20:13:06 +00002134 if (volume_info.setuids)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
Steve French4523cc32007-04-30 20:13:06 +00002136 if (volume_info.server_ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
Steve French4523cc32007-04-30 20:13:06 +00002138 if (volume_info.remap)
Steve French6a0b4822005-04-28 22:41:05 -07002139 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
Steve French4523cc32007-04-30 20:13:06 +00002140 if (volume_info.no_xattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
Steve French4523cc32007-04-30 20:13:06 +00002142 if (volume_info.sfu_emul)
Steve Frenchd7245c22005-07-14 18:25:12 -05002143 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
Steve French4523cc32007-04-30 20:13:06 +00002144 if (volume_info.nobrl)
Steve Frenchc46fa8a2005-08-18 20:49:57 -07002145 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Steve French4523cc32007-04-30 20:13:06 +00002146 if (volume_info.cifs_acl)
Steve French0a4b92c2006-01-12 15:44:21 -08002147 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
Steve French4523cc32007-04-30 20:13:06 +00002148 if (volume_info.override_uid)
2149 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
2150 if (volume_info.override_gid)
2151 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
Jeff Laytond0a9c072008-05-12 22:23:49 +00002152 if (volume_info.dynperm)
2153 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
Steve French4523cc32007-04-30 20:13:06 +00002154 if (volume_info.direct_io) {
Steve French467a8f82007-06-27 22:41:32 +00002155 cFYI(1, ("mounting share using direct i/o"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
2157 }
2158
Steve French27adb442008-05-23 19:43:29 +00002159 if ((volume_info.cifs_acl) && (volume_info.dynperm))
2160 cERROR(1, ("mount option dynperm ignored if cifsacl "
2161 "mount option supported"));
2162
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163 tcon =
2164 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
2165 volume_info.username);
2166 if (tcon) {
Steve Frenchbf820672005-12-01 22:32:42 -08002167 cFYI(1, ("Found match on UNC path"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168 /* we can have only one retry value for a connection
2169 to a share so for resources mounted more than once
Steve French50c2f752007-07-13 00:33:32 +00002170 to the same server share the last value passed in
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171 for the retry flag is used */
2172 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07002173 tcon->nocase = volume_info.nocase;
Steve French95b1cb92008-05-15 16:44:38 +00002174 if (tcon->seal != volume_info.seal)
2175 cERROR(1, ("transport encryption setting "
2176 "conflicts with existing tid"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 } else {
2178 tcon = tconInfoAlloc();
2179 if (tcon == NULL)
2180 rc = -ENOMEM;
2181 else {
Steve French50c2f752007-07-13 00:33:32 +00002182 /* check for null share name ie connecting to
Steve French8af18972007-02-14 04:42:51 +00002183 * dfs root */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184
Steve French50c2f752007-07-13 00:33:32 +00002185 /* BB check if this works for exactly length
Steve French8af18972007-02-14 04:42:51 +00002186 * three strings */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
2188 && (strchr(volume_info.UNC + 3, '/') ==
2189 NULL)) {
Steve French646dd532008-05-15 01:50:56 +00002190/* rc = connect_to_dfs_path(xid, pSesInfo,
Steve French8af18972007-02-14 04:42:51 +00002191 "", cifs_sb->local_nls,
Steve French50c2f752007-07-13 00:33:32 +00002192 cifs_sb->mnt_cifs_flags &
Steve French646dd532008-05-15 01:50:56 +00002193 CIFS_MOUNT_MAP_SPECIAL_CHR);*/
2194 cFYI(1, ("DFS root not supported"));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002195 rc = -ENODEV;
2196 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197 } else {
Steve French8af18972007-02-14 04:42:51 +00002198 /* BB Do we need to wrap sesSem around
2199 * this TCon call and Unix SetFS as
2200 * we do on SessSetup and reconnect? */
Steve French50c2f752007-07-13 00:33:32 +00002201 rc = CIFSTCon(xid, pSesInfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202 volume_info.UNC,
2203 tcon, cifs_sb->local_nls);
2204 cFYI(1, ("CIFS Tcon rc = %d", rc));
2205 }
2206 if (!rc) {
2207 atomic_inc(&pSesInfo->inUse);
2208 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07002209 tcon->nocase = volume_info.nocase;
Steve French95b1cb92008-05-15 16:44:38 +00002210 tcon->seal = volume_info.seal;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211 }
2212 }
2213 }
2214 }
Steve French4523cc32007-04-30 20:13:06 +00002215 if (pSesInfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
2217 sb->s_maxbytes = (u64) 1 << 63;
2218 } else
2219 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
2220 }
2221
Steve French8af18972007-02-14 04:42:51 +00002222 /* BB FIXME fix time_gran to be larger for LANMAN sessions */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223 sb->s_time_gran = 100;
2224
2225/* on error free sesinfo and tcon struct if needed */
2226 if (rc) {
2227 /* if session setup failed, use count is zero but
2228 we still need to free cifsd thread */
Steve French4523cc32007-04-30 20:13:06 +00002229 if (atomic_read(&srvTcp->socketUseCount) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230 spin_lock(&GlobalMid_Lock);
2231 srvTcp->tcpStatus = CifsExiting;
2232 spin_unlock(&GlobalMid_Lock);
Steve French4523cc32007-04-30 20:13:06 +00002233 if (srvTcp->tsk) {
Steve French28356a12007-05-23 14:45:36 +00002234 /* If we could verify that kthread_stop would
2235 always wake up processes blocked in
2236 tcp in recv_mesg then we could remove the
2237 send_sig call */
Steve French50c2f752007-07-13 00:33:32 +00002238 force_sig(SIGKILL, srvTcp->tsk);
Steve Frenche691b9d2008-05-11 15:53:33 +00002239 kthread_stop(srvTcp->tsk);
Steve Frenchf1914012005-08-18 09:37:34 -07002240 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241 }
2242 /* If find_unc succeeded then rc == 0 so we can not end */
2243 if (tcon) /* up accidently freeing someone elses tcon struct */
2244 tconInfoFree(tcon);
2245 if (existingCifsSes == NULL) {
2246 if (pSesInfo) {
Steve French50c2f752007-07-13 00:33:32 +00002247 if ((pSesInfo->server) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 (pSesInfo->status == CifsGood)) {
2249 int temp_rc;
2250 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
2251 /* if the socketUseCount is now zero */
Steve French4523cc32007-04-30 20:13:06 +00002252 if ((temp_rc == -ESHUTDOWN) &&
Steve French50c2f752007-07-13 00:33:32 +00002253 (pSesInfo->server) &&
Jeff5d9c7202007-06-25 22:16:35 +00002254 (pSesInfo->server->tsk)) {
Jeff5d9c7202007-06-25 22:16:35 +00002255 force_sig(SIGKILL,
2256 pSesInfo->server->tsk);
Steve Frenche691b9d2008-05-11 15:53:33 +00002257 kthread_stop(pSesInfo->server->tsk);
Steve Frenchf1914012005-08-18 09:37:34 -07002258 }
Steve Frencha0136892007-10-04 20:05:09 +00002259 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 cFYI(1, ("No session or bad tcon"));
Steve Frencha0136892007-10-04 20:05:09 +00002261 if ((pSesInfo->server) &&
2262 (pSesInfo->server->tsk)) {
Steve Frencha0136892007-10-04 20:05:09 +00002263 force_sig(SIGKILL,
2264 pSesInfo->server->tsk);
Steve Frenche691b9d2008-05-11 15:53:33 +00002265 kthread_stop(pSesInfo->server->tsk);
Steve Frencha0136892007-10-04 20:05:09 +00002266 }
2267 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268 sesInfoFree(pSesInfo);
2269 /* pSesInfo = NULL; */
2270 }
2271 }
2272 } else {
2273 atomic_inc(&tcon->useCount);
2274 cifs_sb->tcon = tcon;
2275 tcon->ses = pSesInfo;
2276
Steve French82940a42006-03-02 03:24:57 +00002277 /* do not care if following two calls succeed - informational */
Steve French7f8ed422007-09-28 22:28:55 +00002278 if (!tcon->ipc) {
2279 CIFSSMBQFSDeviceInfo(xid, tcon);
2280 CIFSSMBQFSAttributeInfo(xid, tcon);
2281 }
Steve French50c2f752007-07-13 00:33:32 +00002282
Steve French8af18972007-02-14 04:42:51 +00002283 /* tell server which Unix caps we support */
2284 if (tcon->ses->capabilities & CAP_UNIX)
Steve Frenchc18c8422007-07-18 23:21:09 +00002285 /* reset of caps checks mount to see if unix extensions
2286 disabled for just this mount */
Steve French8af18972007-02-14 04:42:51 +00002287 reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
Steve Frenchc18c8422007-07-18 23:21:09 +00002288 else
2289 tcon->unix_ext = 0; /* server does not support them */
2290
Steve French03a143c2008-02-14 06:38:30 +00002291 /* convert forward to back slashes in prepath here if needed */
Igor Mammedov11b6d642008-02-15 19:06:04 +00002292 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
2293 convert_delimiter(cifs_sb->prepath,
2294 CIFS_DIR_SEP(cifs_sb));
Steve French03a143c2008-02-14 06:38:30 +00002295
Steve Frenchc18c8422007-07-18 23:21:09 +00002296 if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
Steve French75865f8c2007-06-24 18:30:48 +00002297 cifs_sb->rsize = 1024 * 127;
Steve French90c81e02008-02-12 20:32:36 +00002298 cFYI(DBG2,
2299 ("no very large read support, rsize now 127K"));
Steve French75865f8c2007-06-24 18:30:48 +00002300 }
Steve French3e844692005-10-03 13:37:24 -07002301 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
2302 cifs_sb->wsize = min(cifs_sb->wsize,
2303 (tcon->ses->server->maxBuf -
2304 MAX_CIFS_HDR_SIZE));
Steve French0ae0efa2005-10-10 10:57:19 -07002305 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
Steve French50c2f752007-07-13 00:33:32 +00002306 cifs_sb->rsize = min(cifs_sb->rsize,
2307 (tcon->ses->server->maxBuf -
2308 MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 }
2310
2311 /* volume_info.password is freed above when existing session found
2312 (in which case it is not needed anymore) but when new sesion is created
2313 the password ptr is put in the new session structure (in which case the
2314 password will be freed at unmount time) */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002315out:
2316 /* zero out password before freeing */
2317 if (volume_info.password != NULL) {
2318 memset(volume_info.password, 0, strlen(volume_info.password));
2319 kfree(volume_info.password);
2320 }
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002321 kfree(volume_info.UNC);
Steve French2fe87f02006-09-21 07:02:52 +00002322 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 FreeXid(xid);
2324 return rc;
2325}
2326
2327static int
2328CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French7c7b25b2006-06-01 19:20:10 +00002329 char session_key[CIFS_SESS_KEY_SIZE],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002330 const struct nls_table *nls_codepage)
2331{
2332 struct smb_hdr *smb_buffer;
2333 struct smb_hdr *smb_buffer_response;
2334 SESSION_SETUP_ANDX *pSMB;
2335 SESSION_SETUP_ANDX *pSMBr;
2336 char *bcc_ptr;
2337 char *user;
2338 char *domain;
2339 int rc = 0;
2340 int remaining_words = 0;
2341 int bytes_returned = 0;
2342 int len;
2343 __u32 capabilities;
2344 __u16 count;
2345
Steve Frencheeac8042006-01-13 21:34:58 -08002346 cFYI(1, ("In sesssetup"));
Steve French4523cc32007-04-30 20:13:06 +00002347 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348 return -EINVAL;
2349 user = ses->userName;
2350 domain = ses->domainName;
2351 smb_buffer = cifs_buf_get();
Steve French582d21e2008-05-13 04:54:12 +00002352
2353 if (smb_buffer == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 return -ENOMEM;
Steve French582d21e2008-05-13 04:54:12 +00002355
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356 smb_buffer_response = smb_buffer;
2357 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2358
2359 /* send SMBsessionSetup here */
2360 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2361 NULL /* no tCon exists yet */ , 13 /* wct */ );
2362
Steve French1982c342005-08-17 12:38:22 -07002363 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364 pSMB->req_no_secext.AndXCommand = 0xFF;
2365 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2366 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2367
Steve French50c2f752007-07-13 00:33:32 +00002368 if (ses->server->secMode &
2369 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2371
2372 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2373 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
2374 if (ses->capabilities & CAP_UNICODE) {
2375 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2376 capabilities |= CAP_UNICODE;
2377 }
2378 if (ses->capabilities & CAP_STATUS32) {
2379 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2380 capabilities |= CAP_STATUS32;
2381 }
2382 if (ses->capabilities & CAP_DFS) {
2383 smb_buffer->Flags2 |= SMBFLG2_DFS;
2384 capabilities |= CAP_DFS;
2385 }
2386 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
2387
Steve French50c2f752007-07-13 00:33:32 +00002388 pSMB->req_no_secext.CaseInsensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002389 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390
2391 pSMB->req_no_secext.CaseSensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002392 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393 bcc_ptr = pByteArea(smb_buffer);
Steve French7c7b25b2006-06-01 19:20:10 +00002394 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2395 bcc_ptr += CIFS_SESS_KEY_SIZE;
2396 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2397 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398
2399 if (ses->capabilities & CAP_UNICODE) {
2400 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
2401 *bcc_ptr = 0;
2402 bcc_ptr++;
2403 }
Steve French4523cc32007-04-30 20:13:06 +00002404 if (user == NULL)
Steve French39798772006-05-31 22:40:51 +00002405 bytes_returned = 0; /* skip null user */
Steve French50c2f752007-07-13 00:33:32 +00002406 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407 bytes_returned =
Steve French50c2f752007-07-13 00:33:32 +00002408 cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 nls_codepage);
2410 /* convert number of 16 bit words to bytes */
2411 bcc_ptr += 2 * bytes_returned;
2412 bcc_ptr += 2; /* trailing null */
2413 if (domain == NULL)
2414 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002415 cifs_strtoUCS((__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416 "CIFS_LINUX_DOM", 32, nls_codepage);
2417 else
2418 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002419 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420 nls_codepage);
2421 bcc_ptr += 2 * bytes_returned;
2422 bcc_ptr += 2;
2423 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002424 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425 32, nls_codepage);
2426 bcc_ptr += 2 * bytes_returned;
2427 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002428 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429 32, nls_codepage);
2430 bcc_ptr += 2 * bytes_returned;
2431 bcc_ptr += 2;
2432 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002433 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434 64, nls_codepage);
2435 bcc_ptr += 2 * bytes_returned;
2436 bcc_ptr += 2;
2437 } else {
Steve French50c2f752007-07-13 00:33:32 +00002438 if (user != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439 strncpy(bcc_ptr, user, 200);
2440 bcc_ptr += strnlen(user, 200);
2441 }
2442 *bcc_ptr = 0;
2443 bcc_ptr++;
2444 if (domain == NULL) {
2445 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2446 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2447 } else {
2448 strncpy(bcc_ptr, domain, 64);
2449 bcc_ptr += strnlen(domain, 64);
2450 *bcc_ptr = 0;
2451 bcc_ptr++;
2452 }
2453 strcpy(bcc_ptr, "Linux version ");
2454 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002455 strcpy(bcc_ptr, utsname()->release);
2456 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2458 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2459 }
2460 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2461 smb_buffer->smb_buf_length += count;
2462 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2463
2464 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00002465 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466 if (rc) {
2467/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2468 } else if ((smb_buffer_response->WordCount == 3)
2469 || (smb_buffer_response->WordCount == 4)) {
2470 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2471 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2472 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002473 cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */
2474 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format
2475 (little endian) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476 cFYI(1, ("UID = %d ", ses->Suid));
Steve French50c2f752007-07-13 00:33:32 +00002477 /* response can have either 3 or 4 word count - Samba sends 3 */
2478 bcc_ptr = pByteArea(smb_buffer_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479 if ((pSMBr->resp.hdr.WordCount == 3)
2480 || ((pSMBr->resp.hdr.WordCount == 4)
2481 && (blob_len < pSMBr->resp.ByteCount))) {
2482 if (pSMBr->resp.hdr.WordCount == 4)
2483 bcc_ptr += blob_len;
2484
2485 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2486 if ((long) (bcc_ptr) % 2) {
2487 remaining_words =
Steve French50c2f752007-07-13 00:33:32 +00002488 (BCC(smb_buffer_response) - 1) / 2;
2489 /* Unicode strings must be word
2490 aligned */
2491 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 } else {
2493 remaining_words =
2494 BCC(smb_buffer_response) / 2;
2495 }
2496 len =
2497 UniStrnlen((wchar_t *) bcc_ptr,
2498 remaining_words - 1);
2499/* We look for obvious messed up bcc or strings in response so we do not go off
2500 the end since (at least) WIN2K and Windows XP have a major bug in not null
2501 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002502 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002503 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002504 ses->serverOS = kzalloc(2 * (len + 1),
2505 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002506 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002507 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508 cifs_strfromUCS_le(ses->serverOS,
Steve French50c2f752007-07-13 00:33:32 +00002509 (__le16 *)bcc_ptr,
2510 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511 bcc_ptr += 2 * (len + 1);
2512 remaining_words -= len + 1;
2513 ses->serverOS[2 * len] = 0;
2514 ses->serverOS[1 + (2 * len)] = 0;
2515 if (remaining_words > 0) {
2516 len = UniStrnlen((wchar_t *)bcc_ptr,
2517 remaining_words-1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002518 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002519 ses->serverNOS = kzalloc(2 * (len + 1),
2520 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002521 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002522 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523 cifs_strfromUCS_le(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002524 (__le16 *)bcc_ptr,
2525 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526 bcc_ptr += 2 * (len + 1);
2527 ses->serverNOS[2 * len] = 0;
2528 ses->serverNOS[1 + (2 * len)] = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002529 if (strncmp(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002530 "NT LAN Manager 4", 16) == 0) {
Steve French467a8f82007-06-27 22:41:32 +00002531 cFYI(1, ("NT4 server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532 ses->flags |= CIFS_SES_NT4;
2533 }
2534 remaining_words -= len + 1;
2535 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002536 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Steve French50c2f752007-07-13 00:33:32 +00002537 /* last string is not always null terminated
2538 (for e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002539 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002540 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541 ses->serverDomain =
Steve French50c2f752007-07-13 00:33:32 +00002542 kzalloc(2*(len+1),
2543 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002544 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002545 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546 cifs_strfromUCS_le(ses->serverDomain,
Steve French50c2f752007-07-13 00:33:32 +00002547 (__le16 *)bcc_ptr,
2548 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549 bcc_ptr += 2 * (len + 1);
2550 ses->serverDomain[2*len] = 0;
2551 ses->serverDomain[1+(2*len)] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002552 } else { /* else no more room so create
2553 dummy domain string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002554 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002555 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002556 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002557 kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002558 }
Steve French50c2f752007-07-13 00:33:32 +00002559 } else { /* no room so create dummy domain
2560 and NOS string */
2561
Steve French433dc242005-04-28 22:41:08 -07002562 /* if these kcallocs fail not much we
2563 can do, but better to not fail the
2564 sesssetup itself */
Steve Frenchcd49b492006-06-26 04:22:36 +00002565 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002567 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002568 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002570 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571 }
2572 } else { /* ASCII */
2573 len = strnlen(bcc_ptr, 1024);
2574 if (((long) bcc_ptr + len) - (long)
2575 pByteArea(smb_buffer_response)
2576 <= BCC(smb_buffer_response)) {
Steve Frenchcd49b492006-06-26 04:22:36 +00002577 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002578 ses->serverOS = kzalloc(len + 1,
2579 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002580 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002581 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002582 strncpy(ses->serverOS, bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583
2584 bcc_ptr += len;
Steve French50c2f752007-07-13 00:33:32 +00002585 /* null terminate the string */
2586 bcc_ptr[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 bcc_ptr++;
2588
2589 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002590 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002591 ses->serverNOS = kzalloc(len + 1,
2592 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002593 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002594 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595 strncpy(ses->serverNOS, bcc_ptr, len);
2596 bcc_ptr += len;
2597 bcc_ptr[0] = 0;
2598 bcc_ptr++;
2599
2600 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002601 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002602 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002603 ses->serverDomain = kzalloc(len + 1,
2604 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002605 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002606 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002607 strncpy(ses->serverDomain, bcc_ptr,
2608 len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 bcc_ptr += len;
2610 bcc_ptr[0] = 0;
2611 bcc_ptr++;
2612 } else
2613 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00002614 ("Variable field of length %d "
2615 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 len));
2617 }
2618 } else {
2619 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00002620 (" Security Blob Length extends beyond "
2621 "end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622 }
2623 } else {
2624 cERROR(1,
2625 (" Invalid Word count %d: ",
2626 smb_buffer_response->WordCount));
2627 rc = -EIO;
2628 }
Steve French433dc242005-04-28 22:41:08 -07002629sesssetup_nomem: /* do not return an error on nomem for the info strings,
2630 since that could make reconnection harder, and
2631 reconnection might be needed to free memory */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00002632 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633
2634 return rc;
2635}
2636
2637static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
Steve French4b18f2a2008-04-29 00:06:05 +00002639 struct cifsSesInfo *ses, bool *pNTLMv2_flag,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 const struct nls_table *nls_codepage)
2641{
2642 struct smb_hdr *smb_buffer;
2643 struct smb_hdr *smb_buffer_response;
2644 SESSION_SETUP_ANDX *pSMB;
2645 SESSION_SETUP_ANDX *pSMBr;
2646 char *bcc_ptr;
2647 char *domain;
2648 int rc = 0;
2649 int remaining_words = 0;
2650 int bytes_returned = 0;
2651 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002652 int SecurityBlobLength = sizeof(NEGOTIATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 PNEGOTIATE_MESSAGE SecurityBlob;
2654 PCHALLENGE_MESSAGE SecurityBlob2;
2655 __u32 negotiate_flags, capabilities;
2656 __u16 count;
2657
Steve French12b3b8f2006-02-09 21:12:47 +00002658 cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002659 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 return -EINVAL;
2661 domain = ses->domainName;
Steve French4b18f2a2008-04-29 00:06:05 +00002662 *pNTLMv2_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 smb_buffer = cifs_buf_get();
2664 if (smb_buffer == NULL) {
2665 return -ENOMEM;
2666 }
2667 smb_buffer_response = smb_buffer;
2668 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2669 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2670
2671 /* send SMBsessionSetup here */
2672 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2673 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002674
2675 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2677 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2678
2679 pSMB->req.AndXCommand = 0xFF;
2680 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2681 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2682
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002683 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2685
2686 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2687 CAP_EXTENDED_SECURITY;
2688 if (ses->capabilities & CAP_UNICODE) {
2689 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2690 capabilities |= CAP_UNICODE;
2691 }
2692 if (ses->capabilities & CAP_STATUS32) {
2693 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2694 capabilities |= CAP_STATUS32;
2695 }
2696 if (ses->capabilities & CAP_DFS) {
2697 smb_buffer->Flags2 |= SMBFLG2_DFS;
2698 capabilities |= CAP_DFS;
2699 }
2700 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2701
2702 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2703 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2704 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2705 SecurityBlob->MessageType = NtLmNegotiate;
2706 negotiate_flags =
2707 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
Steve French12b3b8f2006-02-09 21:12:47 +00002708 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
2709 NTLMSSP_NEGOTIATE_56 |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002711 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002713/* if (ntlmv2_support)
Steve French39798772006-05-31 22:40:51 +00002714 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 /* setup pointers to domain name and workstation name */
2716 bcc_ptr += SecurityBlobLength;
2717
2718 SecurityBlob->WorkstationName.Buffer = 0;
2719 SecurityBlob->WorkstationName.Length = 0;
2720 SecurityBlob->WorkstationName.MaximumLength = 0;
2721
Steve French12b3b8f2006-02-09 21:12:47 +00002722 /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent
2723 along with username on auth request (ie the response to challenge) */
2724 SecurityBlob->DomainName.Buffer = 0;
2725 SecurityBlob->DomainName.Length = 0;
2726 SecurityBlob->DomainName.MaximumLength = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 if (ses->capabilities & CAP_UNICODE) {
2728 if ((long) bcc_ptr % 2) {
2729 *bcc_ptr = 0;
2730 bcc_ptr++;
2731 }
2732
2733 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002734 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 32, nls_codepage);
2736 bcc_ptr += 2 * bytes_returned;
2737 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002738 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 nls_codepage);
2740 bcc_ptr += 2 * bytes_returned;
2741 bcc_ptr += 2; /* null terminate Linux version */
2742 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002743 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 64, nls_codepage);
2745 bcc_ptr += 2 * bytes_returned;
2746 *(bcc_ptr + 1) = 0;
2747 *(bcc_ptr + 2) = 0;
2748 bcc_ptr += 2; /* null terminate network opsys string */
2749 *(bcc_ptr + 1) = 0;
2750 *(bcc_ptr + 2) = 0;
2751 bcc_ptr += 2; /* null domain */
2752 } else { /* ASCII */
2753 strcpy(bcc_ptr, "Linux version ");
2754 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002755 strcpy(bcc_ptr, utsname()->release);
2756 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2758 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2759 bcc_ptr++; /* empty domain field */
2760 *bcc_ptr = 0;
2761 }
2762 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2763 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2764 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2765 smb_buffer->smb_buf_length += count;
2766 pSMB->req.ByteCount = cpu_to_le16(count);
2767
2768 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00002769 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770
2771 if (smb_buffer_response->Status.CifsError ==
2772 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2773 rc = 0;
2774
2775 if (rc) {
2776/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2777 } else if ((smb_buffer_response->WordCount == 3)
2778 || (smb_buffer_response->WordCount == 4)) {
2779 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2780 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2781
2782 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002783 cFYI(1, (" Guest login"));
2784 /* Do we want to set anything in SesInfo struct when guest login? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785
Steve French50c2f752007-07-13 00:33:32 +00002786 bcc_ptr = pByteArea(smb_buffer_response);
2787 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788
2789 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2790 if (SecurityBlob2->MessageType != NtLmChallenge) {
2791 cFYI(1,
2792 ("Unexpected NTLMSSP message type received %d",
2793 SecurityBlob2->MessageType));
2794 } else if (ses) {
Steve French50c2f752007-07-13 00:33:32 +00002795 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
Steve French12b3b8f2006-02-09 21:12:47 +00002796 cFYI(1, ("UID = %d", ses->Suid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797 if ((pSMBr->resp.hdr.WordCount == 3)
2798 || ((pSMBr->resp.hdr.WordCount == 4)
2799 && (blob_len <
2800 pSMBr->resp.ByteCount))) {
2801
2802 if (pSMBr->resp.hdr.WordCount == 4) {
2803 bcc_ptr += blob_len;
Steve French12b3b8f2006-02-09 21:12:47 +00002804 cFYI(1, ("Security Blob Length %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002805 blob_len));
2806 }
2807
Steve French12b3b8f2006-02-09 21:12:47 +00002808 cFYI(1, ("NTLMSSP Challenge rcvd"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809
2810 memcpy(ses->server->cryptKey,
2811 SecurityBlob2->Challenge,
2812 CIFS_CRYPTO_KEY_SIZE);
Steve French50c2f752007-07-13 00:33:32 +00002813 if (SecurityBlob2->NegotiateFlags &
Steve French12b3b8f2006-02-09 21:12:47 +00002814 cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
Steve French4b18f2a2008-04-29 00:06:05 +00002815 *pNTLMv2_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816
Steve French50c2f752007-07-13 00:33:32 +00002817 if ((SecurityBlob2->NegotiateFlags &
2818 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819 || (sign_CIFS_PDUs > 1))
Steve French50c2f752007-07-13 00:33:32 +00002820 ses->server->secMode |=
2821 SECMODE_SIGN_REQUIRED;
2822 if ((SecurityBlob2->NegotiateFlags &
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
Steve French50c2f752007-07-13 00:33:32 +00002824 ses->server->secMode |=
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 SECMODE_SIGN_ENABLED;
2826
2827 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2828 if ((long) (bcc_ptr) % 2) {
2829 remaining_words =
2830 (BCC(smb_buffer_response)
2831 - 1) / 2;
Steve French50c2f752007-07-13 00:33:32 +00002832 /* Must word align unicode strings */
2833 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834 } else {
2835 remaining_words =
2836 BCC
2837 (smb_buffer_response) / 2;
2838 }
2839 len =
2840 UniStrnlen((wchar_t *) bcc_ptr,
2841 remaining_words - 1);
2842/* We look for obvious messed up bcc or strings in response so we do not go off
2843 the end since (at least) WIN2K and Windows XP have a major bug in not null
2844 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002845 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002846 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002848 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002850 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851 bcc_ptr, len,
2852 nls_codepage);
2853 bcc_ptr += 2 * (len + 1);
2854 remaining_words -= len + 1;
2855 ses->serverOS[2 * len] = 0;
2856 ses->serverOS[1 + (2 * len)] = 0;
2857 if (remaining_words > 0) {
2858 len = UniStrnlen((wchar_t *)
2859 bcc_ptr,
2860 remaining_words
2861 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002862 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002864 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 GFP_KERNEL);
2866 cifs_strfromUCS_le(ses->
2867 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002868 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869 bcc_ptr,
2870 len,
2871 nls_codepage);
2872 bcc_ptr += 2 * (len + 1);
2873 ses->serverNOS[2 * len] = 0;
2874 ses->serverNOS[1 +
2875 (2 * len)] = 0;
2876 remaining_words -= len + 1;
2877 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00002878 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2879 /* last string not always null terminated
2880 (for e.g. for Windows XP & 2000) */
Steve Frenchcd49b492006-06-26 04:22:36 +00002881 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002883 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884 (len +
2885 1),
2886 GFP_KERNEL);
2887 cifs_strfromUCS_le
Steve Frenche89dc922005-11-11 15:18:19 -08002888 (ses->serverDomain,
2889 (__le16 *)bcc_ptr,
2890 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 bcc_ptr +=
2892 2 * (len + 1);
Steve Frenche89dc922005-11-11 15:18:19 -08002893 ses->serverDomain[2*len]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894 = 0;
Steve Frenche89dc922005-11-11 15:18:19 -08002895 ses->serverDomain
2896 [1 + (2 * len)]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897 = 0;
2898 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002899 else {
Steve Frenchcd49b492006-06-26 04:22:36 +00002900 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002902 kzalloc(2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903 GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002904 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905 } else { /* no room so create dummy domain and NOS string */
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(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002909 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002911 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912 }
2913 } else { /* ASCII */
2914 len = strnlen(bcc_ptr, 1024);
2915 if (((long) bcc_ptr + len) - (long)
2916 pByteArea(smb_buffer_response)
2917 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002918 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002919 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002921 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922 GFP_KERNEL);
2923 strncpy(ses->serverOS,
2924 bcc_ptr, len);
2925
2926 bcc_ptr += len;
2927 bcc_ptr[0] = 0; /* null terminate string */
2928 bcc_ptr++;
2929
2930 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002931 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002933 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934 GFP_KERNEL);
2935 strncpy(ses->serverNOS, bcc_ptr, len);
2936 bcc_ptr += len;
2937 bcc_ptr[0] = 0;
2938 bcc_ptr++;
2939
2940 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002941 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002943 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +00002945 strncpy(ses->serverDomain,
2946 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947 bcc_ptr += len;
2948 bcc_ptr[0] = 0;
2949 bcc_ptr++;
2950 } else
2951 cFYI(1,
Steve French63135e02007-07-17 17:34:02 +00002952 ("field of length %d "
2953 "extends beyond end of smb",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954 len));
2955 }
2956 } else {
Steve French50c2f752007-07-13 00:33:32 +00002957 cERROR(1, ("Security Blob Length extends beyond"
2958 " end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959 }
2960 } else {
2961 cERROR(1, ("No session structure passed in."));
2962 }
2963 } else {
2964 cERROR(1,
Steve French5815449d2006-02-14 01:36:20 +00002965 (" Invalid Word count %d:",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966 smb_buffer_response->WordCount));
2967 rc = -EIO;
2968 }
2969
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00002970 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971
2972 return rc;
2973}
2974static int
2975CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French4b18f2a2008-04-29 00:06:05 +00002976 char *ntlm_session_key, bool ntlmv2_flag,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002977 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978{
2979 struct smb_hdr *smb_buffer;
2980 struct smb_hdr *smb_buffer_response;
2981 SESSION_SETUP_ANDX *pSMB;
2982 SESSION_SETUP_ANDX *pSMBr;
2983 char *bcc_ptr;
2984 char *user;
2985 char *domain;
2986 int rc = 0;
2987 int remaining_words = 0;
2988 int bytes_returned = 0;
2989 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002990 int SecurityBlobLength = sizeof(AUTHENTICATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991 PAUTHENTICATE_MESSAGE SecurityBlob;
2992 __u32 negotiate_flags, capabilities;
2993 __u16 count;
2994
2995 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002996 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997 return -EINVAL;
2998 user = ses->userName;
2999 domain = ses->domainName;
3000 smb_buffer = cifs_buf_get();
3001 if (smb_buffer == NULL) {
3002 return -ENOMEM;
3003 }
3004 smb_buffer_response = smb_buffer;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003005 pSMB = (SESSION_SETUP_ANDX *)smb_buffer;
3006 pSMBr = (SESSION_SETUP_ANDX *)smb_buffer_response;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007
3008 /* send SMBsessionSetup here */
3009 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
3010 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07003011
3012 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
3014 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
3015 pSMB->req.AndXCommand = 0xFF;
3016 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
3017 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
3018
3019 pSMB->req.hdr.Uid = ses->Suid;
3020
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003021 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3023
3024 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003025 CAP_EXTENDED_SECURITY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026 if (ses->capabilities & CAP_UNICODE) {
3027 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3028 capabilities |= CAP_UNICODE;
3029 }
3030 if (ses->capabilities & CAP_STATUS32) {
3031 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3032 capabilities |= CAP_STATUS32;
3033 }
3034 if (ses->capabilities & CAP_DFS) {
3035 smb_buffer->Flags2 |= SMBFLG2_DFS;
3036 capabilities |= CAP_DFS;
3037 }
3038 pSMB->req.Capabilities = cpu_to_le32(capabilities);
3039
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003040 bcc_ptr = (char *)&pSMB->req.SecurityBlob;
3041 SecurityBlob = (PAUTHENTICATE_MESSAGE)bcc_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
3043 SecurityBlob->MessageType = NtLmAuthenticate;
3044 bcc_ptr += SecurityBlobLength;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003045 negotiate_flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
3046 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
3047 0x80000000 | NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003048 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003049 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003050 if (ntlmv2_flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
3052
3053/* setup pointers to domain name and workstation name */
3054
3055 SecurityBlob->WorkstationName.Buffer = 0;
3056 SecurityBlob->WorkstationName.Length = 0;
3057 SecurityBlob->WorkstationName.MaximumLength = 0;
3058 SecurityBlob->SessionKey.Length = 0;
3059 SecurityBlob->SessionKey.MaximumLength = 0;
3060 SecurityBlob->SessionKey.Buffer = 0;
3061
3062 SecurityBlob->LmChallengeResponse.Length = 0;
3063 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
3064 SecurityBlob->LmChallengeResponse.Buffer = 0;
3065
3066 SecurityBlob->NtChallengeResponse.Length =
Steve French7c7b25b2006-06-01 19:20:10 +00003067 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068 SecurityBlob->NtChallengeResponse.MaximumLength =
Steve French7c7b25b2006-06-01 19:20:10 +00003069 cpu_to_le16(CIFS_SESS_KEY_SIZE);
3070 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071 SecurityBlob->NtChallengeResponse.Buffer =
3072 cpu_to_le32(SecurityBlobLength);
Steve French7c7b25b2006-06-01 19:20:10 +00003073 SecurityBlobLength += CIFS_SESS_KEY_SIZE;
3074 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075
3076 if (ses->capabilities & CAP_UNICODE) {
3077 if (domain == NULL) {
3078 SecurityBlob->DomainName.Buffer = 0;
3079 SecurityBlob->DomainName.Length = 0;
3080 SecurityBlob->DomainName.MaximumLength = 0;
3081 } else {
Steve French77159b42007-08-31 01:10:17 +00003082 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00003084 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003086 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087 SecurityBlob->DomainName.Buffer =
3088 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003089 bcc_ptr += ln;
3090 SecurityBlobLength += ln;
3091 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092 }
3093 if (user == NULL) {
3094 SecurityBlob->UserName.Buffer = 0;
3095 SecurityBlob->UserName.Length = 0;
3096 SecurityBlob->UserName.MaximumLength = 0;
3097 } else {
Steve French77159b42007-08-31 01:10:17 +00003098 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00003100 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101 SecurityBlob->UserName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003102 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103 SecurityBlob->UserName.Buffer =
3104 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003105 bcc_ptr += ln;
3106 SecurityBlobLength += ln;
3107 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003108 }
3109
Steve French63135e02007-07-17 17:34:02 +00003110 /* SecurityBlob->WorkstationName.Length =
3111 cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112 SecurityBlob->WorkstationName.Length *= 2;
Steve French63135e02007-07-17 17:34:02 +00003113 SecurityBlob->WorkstationName.MaximumLength =
3114 cpu_to_le16(SecurityBlob->WorkstationName.Length);
3115 SecurityBlob->WorkstationName.Buffer =
3116 cpu_to_le32(SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117 bcc_ptr += SecurityBlob->WorkstationName.Length;
3118 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
Steve French63135e02007-07-17 17:34:02 +00003119 SecurityBlob->WorkstationName.Length =
3120 cpu_to_le16(SecurityBlob->WorkstationName.Length); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121
3122 if ((long) bcc_ptr % 2) {
3123 *bcc_ptr = 0;
3124 bcc_ptr++;
3125 }
3126 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003127 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128 32, nls_codepage);
3129 bcc_ptr += 2 * bytes_returned;
3130 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003131 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 nls_codepage);
3133 bcc_ptr += 2 * bytes_returned;
3134 bcc_ptr += 2; /* null term version string */
3135 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003136 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137 64, nls_codepage);
3138 bcc_ptr += 2 * bytes_returned;
3139 *(bcc_ptr + 1) = 0;
3140 *(bcc_ptr + 2) = 0;
3141 bcc_ptr += 2; /* null terminate network opsys string */
3142 *(bcc_ptr + 1) = 0;
3143 *(bcc_ptr + 2) = 0;
3144 bcc_ptr += 2; /* null domain */
3145 } else { /* ASCII */
3146 if (domain == NULL) {
3147 SecurityBlob->DomainName.Buffer = 0;
3148 SecurityBlob->DomainName.Length = 0;
3149 SecurityBlob->DomainName.MaximumLength = 0;
3150 } else {
Steve French77159b42007-08-31 01:10:17 +00003151 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003152 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
3153 strncpy(bcc_ptr, domain, 63);
Steve French77159b42007-08-31 01:10:17 +00003154 ln = strnlen(domain, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003155 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003156 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003157 SecurityBlob->DomainName.Buffer =
3158 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003159 bcc_ptr += ln;
3160 SecurityBlobLength += ln;
3161 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162 }
3163 if (user == NULL) {
3164 SecurityBlob->UserName.Buffer = 0;
3165 SecurityBlob->UserName.Length = 0;
3166 SecurityBlob->UserName.MaximumLength = 0;
3167 } else {
Steve French77159b42007-08-31 01:10:17 +00003168 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169 strncpy(bcc_ptr, user, 63);
Steve French77159b42007-08-31 01:10:17 +00003170 ln = strnlen(user, 64);
3171 SecurityBlob->UserName.MaximumLength = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172 SecurityBlob->UserName.Buffer =
Steve French77159b42007-08-31 01:10:17 +00003173 cpu_to_le32(SecurityBlobLength);
3174 bcc_ptr += ln;
3175 SecurityBlobLength += ln;
3176 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177 }
3178 /* BB fill in our workstation name if known BB */
3179
3180 strcpy(bcc_ptr, "Linux version ");
3181 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003182 strcpy(bcc_ptr, utsname()->release);
3183 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003184 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
3185 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
3186 bcc_ptr++; /* null domain */
3187 *bcc_ptr = 0;
3188 }
3189 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
3190 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
3191 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
3192 smb_buffer->smb_buf_length += count;
3193 pSMB->req.ByteCount = cpu_to_le16(count);
3194
3195 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00003196 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197 if (rc) {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003198/* rc = map_smb_to_linux_error(smb_buffer_response) done in SendReceive now */
3199 } else if ((smb_buffer_response->WordCount == 3) ||
3200 (smb_buffer_response->WordCount == 4)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201 __u16 action = le16_to_cpu(pSMBr->resp.Action);
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003202 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00003204 cFYI(1, (" Guest login")); /* BB Should we set anything
3205 in SesInfo struct ? */
3206/* if (SecurityBlob2->MessageType != NtLm??) {
3207 cFYI("Unexpected message type on auth response is %d"));
3208 } */
3209
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210 if (ses) {
3211 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003212 ("Check challenge UID %d vs auth response UID %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213 ses->Suid, smb_buffer_response->Uid));
Steve French50c2f752007-07-13 00:33:32 +00003214 /* UID left in wire format */
3215 ses->Suid = smb_buffer_response->Uid;
3216 bcc_ptr = pByteArea(smb_buffer_response);
3217 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218 if ((pSMBr->resp.hdr.WordCount == 3)
3219 || ((pSMBr->resp.hdr.WordCount == 4)
3220 && (blob_len <
3221 pSMBr->resp.ByteCount))) {
3222 if (pSMBr->resp.hdr.WordCount == 4) {
3223 bcc_ptr +=
3224 blob_len;
3225 cFYI(1,
3226 ("Security Blob Length %d ",
3227 blob_len));
3228 }
3229
3230 cFYI(1,
3231 ("NTLMSSP response to Authenticate "));
3232
3233 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3234 if ((long) (bcc_ptr) % 2) {
3235 remaining_words =
3236 (BCC(smb_buffer_response)
3237 - 1) / 2;
3238 bcc_ptr++; /* Unicode strings must be word aligned */
3239 } else {
3240 remaining_words = BCC(smb_buffer_response) / 2;
3241 }
Steve French77159b42007-08-31 01:10:17 +00003242 len = UniStrnlen((wchar_t *) bcc_ptr,
3243 remaining_words - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244/* We look for obvious messed up bcc or strings in response so we do not go off
3245 the end since (at least) WIN2K and Windows XP have a major bug in not null
3246 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003247 if (ses->serverOS)
Steve French08775832006-05-30 18:08:26 +00003248 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003249 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003250 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003251 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003252 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253 bcc_ptr, len,
3254 nls_codepage);
3255 bcc_ptr += 2 * (len + 1);
3256 remaining_words -= len + 1;
3257 ses->serverOS[2 * len] = 0;
3258 ses->serverOS[1 + (2 * len)] = 0;
3259 if (remaining_words > 0) {
3260 len = UniStrnlen((wchar_t *)
3261 bcc_ptr,
3262 remaining_words
3263 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00003264 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003265 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003266 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003267 GFP_KERNEL);
3268 cifs_strfromUCS_le(ses->
3269 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003270 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271 bcc_ptr,
3272 len,
3273 nls_codepage);
3274 bcc_ptr += 2 * (len + 1);
3275 ses->serverNOS[2 * len] = 0;
3276 ses->serverNOS[1+(2*len)] = 0;
3277 remaining_words -= len + 1;
3278 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00003279 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280 /* last string not always null terminated (e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003281 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003282 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003284 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003285 (len +
3286 1),
3287 GFP_KERNEL);
3288 cifs_strfromUCS_le
3289 (ses->
3290 serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08003291 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003292 bcc_ptr, len,
3293 nls_codepage);
3294 bcc_ptr +=
3295 2 * (len + 1);
3296 ses->
3297 serverDomain[2
3298 * len]
3299 = 0;
3300 ses->
3301 serverDomain[1
3302 +
3303 (2
3304 *
3305 len)]
3306 = 0;
3307 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003308 else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003309 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003310 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003311 ses->serverDomain = kzalloc(2,GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00003312 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003313 } else { /* no room so create dummy domain and NOS string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003314 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003315 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003316 ses->serverDomain = kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00003317 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003318 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319 }
3320 } else { /* ASCII */
3321 len = strnlen(bcc_ptr, 1024);
Steve French50c2f752007-07-13 00:33:32 +00003322 if (((long) bcc_ptr + len) -
3323 (long) pByteArea(smb_buffer_response)
Steve French63135e02007-07-17 17:34:02 +00003324 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003325 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00003326 kfree(ses->serverOS);
Steve French77159b42007-08-31 01:10:17 +00003327 ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328 strncpy(ses->serverOS,bcc_ptr, len);
3329
3330 bcc_ptr += len;
3331 bcc_ptr[0] = 0; /* null terminate the string */
3332 bcc_ptr++;
3333
3334 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003335 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00003336 ses->serverNOS = kzalloc(len+1,
3337 GFP_KERNEL);
Steve French63135e02007-07-17 17:34:02 +00003338 strncpy(ses->serverNOS,
3339 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340 bcc_ptr += len;
3341 bcc_ptr[0] = 0;
3342 bcc_ptr++;
3343
3344 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003345 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003346 kfree(ses->serverDomain);
Steve French63135e02007-07-17 17:34:02 +00003347 ses->serverDomain =
3348 kzalloc(len+1,
3349 GFP_KERNEL);
3350 strncpy(ses->serverDomain,
3351 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352 bcc_ptr += len;
3353 bcc_ptr[0] = 0;
3354 bcc_ptr++;
3355 } else
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003356 cFYI(1, ("field of length %d "
Steve French63135e02007-07-17 17:34:02 +00003357 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358 len));
3359 }
3360 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003361 cERROR(1, ("Security Blob extends beyond end "
Steve French63135e02007-07-17 17:34:02 +00003362 "of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003363 }
3364 } else {
3365 cERROR(1, ("No session structure passed in."));
3366 }
3367 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003368 cERROR(1, ("Invalid Word count %d: ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369 smb_buffer_response->WordCount));
3370 rc = -EIO;
3371 }
3372
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003373 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003374
3375 return rc;
3376}
3377
3378int
3379CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3380 const char *tree, struct cifsTconInfo *tcon,
3381 const struct nls_table *nls_codepage)
3382{
3383 struct smb_hdr *smb_buffer;
3384 struct smb_hdr *smb_buffer_response;
3385 TCONX_REQ *pSMB;
3386 TCONX_RSP *pSMBr;
3387 unsigned char *bcc_ptr;
3388 int rc = 0;
3389 int length;
3390 __u16 count;
3391
3392 if (ses == NULL)
3393 return -EIO;
3394
3395 smb_buffer = cifs_buf_get();
3396 if (smb_buffer == NULL) {
3397 return -ENOMEM;
3398 }
3399 smb_buffer_response = smb_buffer;
3400
3401 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3402 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003403
3404 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405 smb_buffer->Uid = ses->Suid;
3406 pSMB = (TCONX_REQ *) smb_buffer;
3407 pSMBr = (TCONX_RSP *) smb_buffer_response;
3408
3409 pSMB->AndXCommand = 0xFF;
3410 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411 bcc_ptr = &pSMB->Password[0];
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003412 if ((ses->server->secMode) & SECMODE_USER) {
Steve Frencheeac8042006-01-13 21:34:58 -08003413 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00003414 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08003415 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00003416 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08003417 } else {
Steve French7c7b25b2006-06-01 19:20:10 +00003418 pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08003419 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
3420 specified as required (when that support is added to
3421 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00003422 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08003423 by Samba (not sure whether other servers allow
3424 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00003425#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French50c2f752007-07-13 00:33:32 +00003426 if ((extended_security & CIFSSEC_MAY_LANMAN) &&
Steve French7c7b25b2006-06-01 19:20:10 +00003427 (ses->server->secType == LANMAN))
3428 calc_lanman_hash(ses, bcc_ptr);
3429 else
3430#endif /* CIFS_WEAK_PW_HASH */
Steve Frencheeac8042006-01-13 21:34:58 -08003431 SMBNTencrypt(ses->password,
3432 ses->server->cryptKey,
3433 bcc_ptr);
3434
Steve French7c7b25b2006-06-01 19:20:10 +00003435 bcc_ptr += CIFS_SESS_KEY_SIZE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003436 if (ses->capabilities & CAP_UNICODE) {
Steve French7c7b25b2006-06-01 19:20:10 +00003437 /* must align unicode strings */
3438 *bcc_ptr = 0; /* null byte password */
3439 bcc_ptr++;
3440 }
Steve Frencheeac8042006-01-13 21:34:58 -08003441 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442
Steve French50c2f752007-07-13 00:33:32 +00003443 if (ses->server->secMode &
Steve Frencha878fb22006-05-30 18:04:19 +00003444 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003445 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3446
3447 if (ses->capabilities & CAP_STATUS32) {
3448 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3449 }
3450 if (ses->capabilities & CAP_DFS) {
3451 smb_buffer->Flags2 |= SMBFLG2_DFS;
3452 }
3453 if (ses->capabilities & CAP_UNICODE) {
3454 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3455 length =
Steve French50c2f752007-07-13 00:33:32 +00003456 cifs_strtoUCS((__le16 *) bcc_ptr, tree,
3457 6 /* max utf8 char length in bytes */ *
Steve Frencha878fb22006-05-30 18:04:19 +00003458 (/* server len*/ + 256 /* share len */), nls_codepage);
3459 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460 bcc_ptr += 2; /* skip trailing null */
3461 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462 strcpy(bcc_ptr, tree);
3463 bcc_ptr += strlen(tree) + 1;
3464 }
3465 strcpy(bcc_ptr, "?????");
3466 bcc_ptr += strlen("?????");
3467 bcc_ptr += 1;
3468 count = bcc_ptr - &pSMB->Password[0];
3469 pSMB->hdr.smb_buf_length += count;
3470 pSMB->ByteCount = cpu_to_le16(count);
3471
Steve French133672e2007-11-13 22:41:37 +00003472 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
3473 CIFS_STD_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474
3475 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3476 /* above now done in SendReceive */
3477 if ((rc == 0) && (tcon != NULL)) {
3478 tcon->tidStatus = CifsGood;
3479 tcon->tid = smb_buffer_response->Tid;
3480 bcc_ptr = pByteArea(smb_buffer_response);
3481 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
Steve French50c2f752007-07-13 00:33:32 +00003482 /* skip service field (NB: this field is always ASCII) */
Steve French7f8ed422007-09-28 22:28:55 +00003483 if (length == 3) {
3484 if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') &&
3485 (bcc_ptr[2] == 'C')) {
3486 cFYI(1, ("IPC connection"));
3487 tcon->ipc = 1;
3488 }
3489 } else if (length == 2) {
3490 if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) {
3491 /* the most common case */
3492 cFYI(1, ("disk share connection"));
3493 }
3494 }
Steve French50c2f752007-07-13 00:33:32 +00003495 bcc_ptr += length + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3497 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3498 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3499 if ((bcc_ptr + (2 * length)) -
3500 pByteArea(smb_buffer_response) <=
3501 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003502 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003504 kzalloc(length + 2, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003505 if (tcon->nativeFileSystem)
3506 cifs_strfromUCS_le(
3507 tcon->nativeFileSystem,
3508 (__le16 *) bcc_ptr,
3509 length, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003510 bcc_ptr += 2 * length;
3511 bcc_ptr[0] = 0; /* null terminate the string */
3512 bcc_ptr[1] = 0;
3513 bcc_ptr += 2;
3514 }
Steve French50c2f752007-07-13 00:33:32 +00003515 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516 } else {
3517 length = strnlen(bcc_ptr, 1024);
3518 if ((bcc_ptr + length) -
3519 pByteArea(smb_buffer_response) <=
3520 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003521 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003523 kzalloc(length + 1, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003524 if (tcon->nativeFileSystem)
3525 strncpy(tcon->nativeFileSystem, bcc_ptr,
3526 length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527 }
Steve French50c2f752007-07-13 00:33:32 +00003528 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003529 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003530 if ((smb_buffer_response->WordCount == 3) ||
Steve French1a4e15a2006-10-12 21:33:51 +00003531 (smb_buffer_response->WordCount == 7))
3532 /* field is in same location */
Steve French39798772006-05-31 22:40:51 +00003533 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3534 else
3535 tcon->Flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003536 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3537 } else if ((rc == 0) && tcon == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00003538 /* all we need to save for IPC$ connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003539 ses->ipc_tid = smb_buffer_response->Tid;
3540 }
3541
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003542 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543 return rc;
3544}
3545
3546int
3547cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3548{
3549 int rc = 0;
3550 int xid;
3551 struct cifsSesInfo *ses = NULL;
3552 struct task_struct *cifsd_task;
Steve French50c2f752007-07-13 00:33:32 +00003553 char *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554
3555 xid = GetXid();
3556
3557 if (cifs_sb->tcon) {
3558 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3559 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3560 if (rc == -EBUSY) {
3561 FreeXid(xid);
3562 return 0;
3563 }
Steve French5d941ca2008-04-15 18:40:48 +00003564 DeleteTconOplockQEntries(cifs_sb->tcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565 tconInfoFree(cifs_sb->tcon);
3566 if ((ses) && (ses->server)) {
3567 /* save off task so we do not refer to ses later */
3568 cifsd_task = ses->server->tsk;
3569 cFYI(1, ("About to do SMBLogoff "));
3570 rc = CIFSSMBLogoff(xid, ses);
3571 if (rc == -EBUSY) {
3572 FreeXid(xid);
3573 return 0;
3574 } else if (rc == -ESHUTDOWN) {
Steve French467a8f82007-06-27 22:41:32 +00003575 cFYI(1, ("Waking up socket by sending signal"));
Steve Frenchf7f7c312007-05-24 02:29:51 +00003576 if (cifsd_task) {
Steve French50c2f752007-07-13 00:33:32 +00003577 force_sig(SIGKILL, cifsd_task);
Igor Mammedovaaf737a2007-04-03 19:16:43 +00003578 kthread_stop(cifsd_task);
Steve Frenchf1914012005-08-18 09:37:34 -07003579 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580 rc = 0;
3581 } /* else - we have an smb session
3582 left on this socket do not kill cifsd */
3583 } else
3584 cFYI(1, ("No session or bad tcon"));
3585 }
Steve French50c2f752007-07-13 00:33:32 +00003586
Linus Torvalds1da177e2005-04-16 15:20:36 -07003587 cifs_sb->tcon = NULL;
Steve French2fe87f02006-09-21 07:02:52 +00003588 tmp = cifs_sb->prepath;
3589 cifs_sb->prepathlen = 0;
3590 cifs_sb->prepath = NULL;
3591 kfree(tmp);
Nishanth Aravamudan041e0e32005-09-10 00:27:23 -07003592 if (ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593 sesInfoFree(ses);
3594
3595 FreeXid(xid);
Steve French88e7d702008-01-03 17:37:09 +00003596 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003597}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598
3599int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
Steve French50c2f752007-07-13 00:33:32 +00003600 struct nls_table *nls_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003601{
3602 int rc = 0;
Steve French7c7b25b2006-06-01 19:20:10 +00003603 char ntlm_session_key[CIFS_SESS_KEY_SIZE];
Steve French4b18f2a2008-04-29 00:06:05 +00003604 bool ntlmv2_flag = false;
Steve Frenchad009ac2005-04-28 22:41:05 -07003605 int first_time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606
3607 /* what if server changes its buffer size after dropping the session? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003608 if (pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003610 if (rc == -EAGAIN) /* retry only once on 1st time connection */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003611 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve French50c2f752007-07-13 00:33:32 +00003612 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613 rc = -EHOSTDOWN;
3614 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003615 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616 spin_lock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003617 if (pSesInfo->server->tcpStatus != CifsExiting)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003618 pSesInfo->server->tcpStatus = CifsGood;
3619 else
3620 rc = -EHOSTDOWN;
3621 spin_unlock(&GlobalMid_Lock);
3622
3623 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003624 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003625 }
3626 if (!rc) {
Steve French9ac00b72006-09-30 04:13:17 +00003627 pSesInfo->flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628 pSesInfo->capabilities = pSesInfo->server->capabilities;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003629 if (linuxExtEnabled == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003631 /* pSesInfo->sequence_number = 0;*/
Steve French50c2f752007-07-13 00:33:32 +00003632 cFYI(1,
3633 ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634 pSesInfo->server->secMode,
3635 pSesInfo->server->capabilities,
Steve French175ec9e2006-09-30 01:07:38 +00003636 pSesInfo->server->timeAdj));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003637 if (experimEnabled < 2)
Steve French39798772006-05-31 22:40:51 +00003638 rc = CIFS_SessSetup(xid, pSesInfo,
3639 first_time, nls_info);
Steve French189acaa2006-06-23 02:33:48 +00003640 else if (extended_security
Steve French50c2f752007-07-13 00:33:32 +00003641 && (pSesInfo->capabilities
Steve French175ec9e2006-09-30 01:07:38 +00003642 & CAP_EXTENDED_SECURITY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003643 && (pSesInfo->server->secType == NTLMSSP)) {
Steve French189acaa2006-06-23 02:33:48 +00003644 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003645 } else if (extended_security
3646 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3647 && (pSesInfo->server->secType == RawNTLMSSP)) {
Steve French5815449d2006-02-14 01:36:20 +00003648 cFYI(1, ("NTLMSSP sesssetup"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003649 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3650 pSesInfo,
3651 &ntlmv2_flag,
3652 nls_info);
3653 if (!rc) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003654 if (ntlmv2_flag) {
Steve French50c2f752007-07-13 00:33:32 +00003655 char *v2_response;
Steve French467a8f82007-06-27 22:41:32 +00003656 cFYI(1, ("more secure NTLM ver2 hash"));
Steve French50c2f752007-07-13 00:33:32 +00003657 if (CalcNTLMv2_partial_mac_key(pSesInfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003658 nls_info)) {
3659 rc = -ENOMEM;
3660 goto ss_err_exit;
3661 } else
3662 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003663 if (v2_response) {
Steve French50c2f752007-07-13 00:33:32 +00003664 CalcNTLMv2_response(pSesInfo,
3665 v2_response);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003666 /* if (first_time)
Steve French50c2f752007-07-13 00:33:32 +00003667 cifs_calculate_ntlmv2_mac_key(
3668 pSesInfo->server->mac_signing_key,
3669 response, ntlm_session_key,*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670 kfree(v2_response);
3671 /* BB Put dummy sig in SessSetup PDU? */
3672 } else {
3673 rc = -ENOMEM;
3674 goto ss_err_exit;
3675 }
3676
3677 } else {
3678 SMBNTencrypt(pSesInfo->password,
3679 pSesInfo->server->cryptKey,
3680 ntlm_session_key);
3681
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003682 if (first_time)
Steve Frenchad009ac2005-04-28 22:41:05 -07003683 cifs_calculate_mac_key(
Steve Frenchb609f062007-07-09 07:55:14 +00003684 &pSesInfo->server->mac_signing_key,
Steve Frenchad009ac2005-04-28 22:41:05 -07003685 ntlm_session_key,
3686 pSesInfo->password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003687 }
3688 /* for better security the weaker lanman hash not sent
3689 in AuthSessSetup so we no longer calculate it */
3690
3691 rc = CIFSNTLMSSPAuthSessSetup(xid,
3692 pSesInfo,
3693 ntlm_session_key,
3694 ntlmv2_flag,
3695 nls_info);
3696 }
3697 } else { /* old style NTLM 0.12 session setup */
3698 SMBNTencrypt(pSesInfo->password,
3699 pSesInfo->server->cryptKey,
3700 ntlm_session_key);
3701
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003702 if (first_time)
Steve Frenchad009ac2005-04-28 22:41:05 -07003703 cifs_calculate_mac_key(
Steve Frenchb609f062007-07-09 07:55:14 +00003704 &pSesInfo->server->mac_signing_key,
Steve Frenchad009ac2005-04-28 22:41:05 -07003705 ntlm_session_key, pSesInfo->password);
3706
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707 rc = CIFSSessSetup(xid, pSesInfo,
3708 ntlm_session_key, nls_info);
3709 }
3710 if (rc) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003711 cERROR(1, ("Send error in SessSetup = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003712 } else {
Steve French467a8f82007-06-27 22:41:32 +00003713 cFYI(1, ("CIFS Session Established successfully"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003714 pSesInfo->status = CifsGood;
3715 }
3716 }
3717ss_err_exit:
3718 return rc;
3719}
3720