blob: 17ca8ce81bb78de0e14cc91259b2c4bb3ac0f02b [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 */
Steve French2c1b8612008-10-16 18:35:21 +000093 bool nodfs:1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070094 unsigned int rsize;
95 unsigned int wsize;
96 unsigned int sockopt;
97 unsigned short int port;
Steve Frenchfb8c4b12007-07-10 01:16:18 +000098 char *prepath;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099};
100
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000101static int ipv4_connect(struct sockaddr_in *psin_server,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 struct socket **csocket,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000103 char *netb_name,
104 char *server_netb_name);
105static int ipv6_connect(struct sockaddr_in6 *psin_server,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 struct socket **csocket);
107
108
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000109 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 * cifs tcp session reconnection
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000111 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 * mark tcp session as reconnecting so temporarily locked
113 * mark all smb sessions as reconnecting for tcp session
114 * reconnect tcp session
115 * wake up waiters on reconnection? - (not needed currently)
116 */
117
Steve French2cd646a2006-09-28 19:43:08 +0000118static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119cifs_reconnect(struct TCP_Server_Info *server)
120{
121 int rc = 0;
122 struct list_head *tmp;
123 struct cifsSesInfo *ses;
124 struct cifsTconInfo *tcon;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000125 struct mid_q_entry *mid_entry;
Steve French50c2f752007-07-13 00:33:32 +0000126
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 spin_lock(&GlobalMid_Lock);
Steve French26f57362007-08-30 22:09:15 +0000128 if (kthread_should_stop()) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000129 /* the demux thread will exit normally
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 next time through the loop */
131 spin_unlock(&GlobalMid_Lock);
132 return rc;
133 } else
134 server->tcpStatus = CifsNeedReconnect;
135 spin_unlock(&GlobalMid_Lock);
136 server->maxBuf = 0;
137
Steve Frenche4eb2952005-04-28 22:41:09 -0700138 cFYI(1, ("Reconnecting tcp session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
140 /* before reconnecting the tcp session, mark the smb session (uid)
141 and the tid bad so they are not used until reconnected */
142 read_lock(&GlobalSMBSeslock);
143 list_for_each(tmp, &GlobalSMBSessionList) {
144 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
145 if (ses->server) {
146 if (ses->server == server) {
147 ses->status = CifsNeedReconnect;
148 ses->ipc_tid = 0;
149 }
150 }
151 /* else tcp and smb sessions need reconnection */
152 }
153 list_for_each(tmp, &GlobalTreeConnectionList) {
154 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000155 if ((tcon->ses) && (tcon->ses->server == server))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 tcon->tidStatus = CifsNeedReconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 }
158 read_unlock(&GlobalSMBSeslock);
159 /* do not want to be sending data on a socket we are freeing */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000160 down(&server->tcpSem);
161 if (server->ssocket) {
Steve French467a8f82007-06-27 22:41:32 +0000162 cFYI(1, ("State: 0x%x Flags: 0x%lx", server->ssocket->state,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 server->ssocket->flags));
Trond Myklebust91cf45f2007-11-12 18:10:39 -0800164 kernel_sock_shutdown(server->ssocket, SHUT_WR);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000165 cFYI(1, ("Post shutdown state: 0x%x Flags: 0x%lx",
Steve French467a8f82007-06-27 22:41:32 +0000166 server->ssocket->state,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 server->ssocket->flags));
168 sock_release(server->ssocket);
169 server->ssocket = NULL;
170 }
171
172 spin_lock(&GlobalMid_Lock);
173 list_for_each(tmp, &server->pending_mid_q) {
174 mid_entry = list_entry(tmp, struct
175 mid_q_entry,
176 qhead);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000177 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 */
Steve Frenchad8b15f2008-08-08 21:10:16 +0000182 mid_entry->midState = MID_RETRY_NEEDED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 }
184 }
185 spin_unlock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000186 up(&server->tcpSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187
Steve French26f57362007-08-30 22:09:15 +0000188 while ((!kthread_should_stop()) && (server->tcpStatus != CifsGood)) {
Steve French6c3d8902006-07-31 22:46:20 +0000189 try_to_freeze();
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000190 if (server->protocolType == IPV6) {
191 rc = ipv6_connect(&server->addr.sockAddr6,
192 &server->ssocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000194 rc = ipv4_connect(&server->addr.sockAddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 &server->ssocket,
Steve Frencha10faeb22005-08-22 21:38:31 -0700196 server->workstation_RFC1001_name,
197 server->server_RFC1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000199 if (rc) {
200 cFYI(1, ("reconnect error %d", rc));
Steve French0cb766a2005-04-28 22:41:11 -0700201 msleep(3000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 } else {
203 atomic_inc(&tcpSesReconnectCount);
204 spin_lock(&GlobalMid_Lock);
Steve French26f57362007-08-30 22:09:15 +0000205 if (!kthread_should_stop())
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 server->tcpStatus = CifsGood;
Steve Frenchad009ac2005-04-28 22:41:05 -0700207 server->sequence_number = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000208 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 /* atomic_set(&server->inFlight,0);*/
210 wake_up(&server->response_q);
211 }
212 }
213 return rc;
214}
215
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000216/*
Steve Frenche4eb2952005-04-28 22:41:09 -0700217 return codes:
218 0 not a transact2, or all data present
219 >0 transact2 with that much data missing
220 -EINVAL = invalid transact2
221
222 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000223static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize)
Steve Frenche4eb2952005-04-28 22:41:09 -0700224{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000225 struct smb_t2_rsp *pSMBt;
226 int total_data_size;
Steve Frenche4eb2952005-04-28 22:41:09 -0700227 int data_in_this_rsp;
228 int remaining;
229
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000230 if (pSMB->Command != SMB_COM_TRANSACTION2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700231 return 0;
232
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000233 /* check for plausible wct, bcc and t2 data and parm sizes */
234 /* check for parm and data offset going beyond end of smb */
235 if (pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
Steve French467a8f82007-06-27 22:41:32 +0000236 cFYI(1, ("invalid transact2 word count"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700237 return -EINVAL;
238 }
239
240 pSMBt = (struct smb_t2_rsp *)pSMB;
241
242 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
243 data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
244
245 remaining = total_data_size - data_in_this_rsp;
246
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000247 if (remaining == 0)
Steve Frenche4eb2952005-04-28 22:41:09 -0700248 return 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000249 else if (remaining < 0) {
Steve French467a8f82007-06-27 22:41:32 +0000250 cFYI(1, ("total data %d smaller than data in frame %d",
Steve Frenche4eb2952005-04-28 22:41:09 -0700251 total_data_size, data_in_this_rsp));
252 return -EINVAL;
253 } else {
Steve French467a8f82007-06-27 22:41:32 +0000254 cFYI(1, ("missing %d bytes from transact2, check next response",
Steve Frenche4eb2952005-04-28 22:41:09 -0700255 remaining));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000256 if (total_data_size > maxBufSize) {
257 cERROR(1, ("TotalDataSize %d is over maximum buffer %d",
258 total_data_size, maxBufSize));
259 return -EINVAL;
Steve Frenche4eb2952005-04-28 22:41:09 -0700260 }
261 return remaining;
262 }
263}
264
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000265static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
Steve Frenche4eb2952005-04-28 22:41:09 -0700266{
267 struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
268 struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
269 int total_data_size;
270 int total_in_buf;
271 int remaining;
272 int total_in_buf2;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000273 char *data_area_of_target;
274 char *data_area_of_buf2;
Steve Frenche4eb2952005-04-28 22:41:09 -0700275 __u16 byte_count;
276
277 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
278
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000279 if (total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
Steve French63135e02007-07-17 17:34:02 +0000280 cFYI(1, ("total data size of primary and secondary t2 differ"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700281 }
282
283 total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
284
285 remaining = total_data_size - total_in_buf;
Steve French50c2f752007-07-13 00:33:32 +0000286
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000287 if (remaining < 0)
Steve Frenche4eb2952005-04-28 22:41:09 -0700288 return -EINVAL;
289
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000290 if (remaining == 0) /* nothing to do, ignore */
Steve Frenche4eb2952005-04-28 22:41:09 -0700291 return 0;
Steve French50c2f752007-07-13 00:33:32 +0000292
Steve Frenche4eb2952005-04-28 22:41:09 -0700293 total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000294 if (remaining < total_in_buf2) {
Steve French467a8f82007-06-27 22:41:32 +0000295 cFYI(1, ("transact2 2nd response contains too much data"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700296 }
297
298 /* find end of first SMB data area */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000299 data_area_of_target = (char *)&pSMBt->hdr.Protocol +
Steve Frenche4eb2952005-04-28 22:41:09 -0700300 le16_to_cpu(pSMBt->t2_rsp.DataOffset);
301 /* validate target area */
302
303 data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000304 le16_to_cpu(pSMB2->t2_rsp.DataOffset);
Steve Frenche4eb2952005-04-28 22:41:09 -0700305
306 data_area_of_target += total_in_buf;
307
308 /* copy second buffer into end of first buffer */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000309 memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2);
Steve Frenche4eb2952005-04-28 22:41:09 -0700310 total_in_buf += total_in_buf2;
311 pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
312 byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
313 byte_count += total_in_buf2;
314 BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
315
Steve French70ca7342005-09-22 16:32:06 -0700316 byte_count = pTargetSMB->smb_buf_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700317 byte_count += total_in_buf2;
318
319 /* BB also add check that we are not beyond maximum buffer size */
Steve French50c2f752007-07-13 00:33:32 +0000320
Steve French70ca7342005-09-22 16:32:06 -0700321 pTargetSMB->smb_buf_length = byte_count;
Steve Frenche4eb2952005-04-28 22:41:09 -0700322
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000323 if (remaining == total_in_buf2) {
Steve French467a8f82007-06-27 22:41:32 +0000324 cFYI(1, ("found the last secondary response"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700325 return 0; /* we are done */
326 } else /* more responses to go */
327 return 1;
328
329}
330
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331static int
332cifs_demultiplex_thread(struct TCP_Server_Info *server)
333{
334 int length;
335 unsigned int pdu_length, total_read;
336 struct smb_hdr *smb_buffer = NULL;
Steve Frenchb8643e12005-04-28 22:41:07 -0700337 struct smb_hdr *bigbuf = NULL;
338 struct smb_hdr *smallbuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 struct msghdr smb_msg;
340 struct kvec iov;
341 struct socket *csocket = server->ssocket;
342 struct list_head *tmp;
343 struct cifsSesInfo *ses;
344 struct task_struct *task_to_wake = NULL;
345 struct mid_q_entry *mid_entry;
Steve French70ca7342005-09-22 16:32:06 -0700346 char temp;
Steve French4b18f2a2008-04-29 00:06:05 +0000347 bool isLargeBuf = false;
348 bool isMultiRsp;
Steve Frenche4eb2952005-04-28 22:41:09 -0700349 int reconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 current->flags |= PF_MEMALLOC;
Pavel Emelyanovba25f9d2007-10-18 23:40:40 -0700352 cFYI(1, ("Demultiplex PID: %d", task_pid_nr(current)));
Jeff Layton93d0ec82008-08-02 08:00:48 -0400353
354 length = atomic_inc_return(&tcpSesAllocCount);
355 if (length > 1)
Steve French26f57362007-08-30 22:09:15 +0000356 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
357 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358
Rafael J. Wysocki83144182007-07-17 04:03:35 -0700359 set_freezable();
Igor Mammedovaaf737a2007-04-03 19:16:43 +0000360 while (!kthread_should_stop()) {
Steve Frenchede13272005-08-30 20:10:14 -0700361 if (try_to_freeze())
362 continue;
Steve Frenchb8643e12005-04-28 22:41:07 -0700363 if (bigbuf == NULL) {
364 bigbuf = cifs_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000365 if (!bigbuf) {
366 cERROR(1, ("No memory for large SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700367 msleep(3000);
368 /* retry will check if exiting */
369 continue;
370 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000371 } else if (isLargeBuf) {
372 /* we are reusing a dirty large buf, clear its start */
Steve French26f57362007-08-30 22:09:15 +0000373 memset(bigbuf, 0, sizeof(struct smb_hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700375
376 if (smallbuf == NULL) {
377 smallbuf = cifs_small_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000378 if (!smallbuf) {
379 cERROR(1, ("No memory for SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700380 msleep(1000);
381 /* retry will check if exiting */
382 continue;
383 }
384 /* beginning of smb buffer is cleared in our buf_get */
385 } else /* if existing small buf clear beginning */
Steve French26f57362007-08-30 22:09:15 +0000386 memset(smallbuf, 0, sizeof(struct smb_hdr));
Steve Frenchb8643e12005-04-28 22:41:07 -0700387
Steve French4b18f2a2008-04-29 00:06:05 +0000388 isLargeBuf = false;
389 isMultiRsp = false;
Steve Frenchb8643e12005-04-28 22:41:07 -0700390 smb_buffer = smallbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 iov.iov_base = smb_buffer;
392 iov.iov_len = 4;
393 smb_msg.msg_control = NULL;
394 smb_msg.msg_controllen = 0;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000395 pdu_length = 4; /* enough to get RFC1001 header */
396incomplete_rcv:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 length =
398 kernel_recvmsg(csocket, &smb_msg,
Steve Frenchf01d5e12007-08-30 21:13:31 +0000399 &iov, 1, pdu_length, 0 /* BB other flags? */);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400
Steve French26f57362007-08-30 22:09:15 +0000401 if (kthread_should_stop()) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 break;
403 } else if (server->tcpStatus == CifsNeedReconnect) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000404 cFYI(1, ("Reconnect after server stopped responding"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 cifs_reconnect(server);
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000406 cFYI(1, ("call to reconnect done"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 csocket = server->ssocket;
408 continue;
409 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700410 msleep(1); /* minimum sleep to prevent looping
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 allowing socket to clear and app threads to set
412 tcpStatus CifsNeedReconnect if server hung */
Steve Frenchc18c7322007-10-17 18:01:11 +0000413 if (pdu_length < 4)
414 goto incomplete_rcv;
415 else
416 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 } else if (length <= 0) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000418 if (server->tcpStatus == CifsNew) {
419 cFYI(1, ("tcp session abend after SMBnegprot"));
Steve French09d1db52005-04-28 22:41:08 -0700420 /* some servers kill the TCP session rather than
421 returning an SMB negprot error, in which
422 case reconnecting here is not going to help,
423 and so simply return error to mount */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 break;
425 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000426 if (!try_to_freeze() && (length == -EINTR)) {
Steve French467a8f82007-06-27 22:41:32 +0000427 cFYI(1, ("cifsd thread killed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 break;
429 }
Steve French467a8f82007-06-27 22:41:32 +0000430 cFYI(1, ("Reconnect after unexpected peek error %d",
Steve French57337e42005-04-28 22:41:10 -0700431 length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 cifs_reconnect(server);
433 csocket = server->ssocket;
434 wake_up(&server->response_q);
435 continue;
Petr Tesarik2a974682007-11-20 02:24:08 +0000436 } else if (length < pdu_length) {
437 cFYI(1, ("requested %d bytes but only got %d bytes",
438 pdu_length, length));
Steve Frenchf01d5e12007-08-30 21:13:31 +0000439 pdu_length -= length;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000440 msleep(1);
441 goto incomplete_rcv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 }
Steve French67010fb2005-04-28 22:41:09 -0700443
Steve French70ca7342005-09-22 16:32:06 -0700444 /* The right amount was read from socket - 4 bytes */
445 /* so we can now interpret the length field */
Steve French46810cb2005-04-28 22:41:09 -0700446
Steve French70ca7342005-09-22 16:32:06 -0700447 /* the first byte big endian of the length field,
448 is actually not part of the length but the type
449 with the most common, zero, as regular data */
450 temp = *((char *) smb_buffer);
451
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000452 /* Note that FC 1001 length is big endian on the wire,
Steve French70ca7342005-09-22 16:32:06 -0700453 but we convert it here so it is always manipulated
454 as host byte order */
Harvey Harrison5ca33c62008-07-23 17:45:58 -0700455 pdu_length = be32_to_cpu((__force __be32)smb_buffer->smb_buf_length);
Steve French70ca7342005-09-22 16:32:06 -0700456 smb_buffer->smb_buf_length = pdu_length;
Steve French46810cb2005-04-28 22:41:09 -0700457
Steve French467a8f82007-06-27 22:41:32 +0000458 cFYI(1, ("rfc1002 length 0x%x", pdu_length+4));
Steve French70ca7342005-09-22 16:32:06 -0700459
460 if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000461 continue;
Steve French70ca7342005-09-22 16:32:06 -0700462 } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
Steve French467a8f82007-06-27 22:41:32 +0000463 cFYI(1, ("Good RFC 1002 session rsp"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700464 continue;
Steve French70ca7342005-09-22 16:32:06 -0700465 } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000466 /* we get this from Windows 98 instead of
Steve French46810cb2005-04-28 22:41:09 -0700467 an error on SMB negprot response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000468 cFYI(1, ("Negative RFC1002 Session Response Error 0x%x)",
Steve French70ca7342005-09-22 16:32:06 -0700469 pdu_length));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000470 if (server->tcpStatus == CifsNew) {
471 /* if nack on negprot (rather than
Steve French46810cb2005-04-28 22:41:09 -0700472 ret of smb negprot error) reconnecting
473 not going to help, ret error to mount */
474 break;
475 } else {
476 /* give server a second to
477 clean up before reconnect attempt */
478 msleep(1000);
479 /* always try 445 first on reconnect
480 since we get NACK on some if we ever
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000481 connected to port 139 (the NACK is
Steve French46810cb2005-04-28 22:41:09 -0700482 since we do not begin with RFC1001
483 session initialize frame) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000484 server->addr.sockAddr.sin_port =
Steve French46810cb2005-04-28 22:41:09 -0700485 htons(CIFS_PORT);
486 cifs_reconnect(server);
487 csocket = server->ssocket;
488 wake_up(&server->response_q);
489 continue;
490 }
Steve French70ca7342005-09-22 16:32:06 -0700491 } else if (temp != (char) 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000492 cERROR(1, ("Unknown RFC 1002 frame"));
Steve French70ca7342005-09-22 16:32:06 -0700493 cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
494 length);
Steve French46810cb2005-04-28 22:41:09 -0700495 cifs_reconnect(server);
496 csocket = server->ssocket;
497 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700498 }
499
500 /* else we have an SMB response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000501 if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French26f57362007-08-30 22:09:15 +0000502 (pdu_length < sizeof(struct smb_hdr) - 1 - 4)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700503 cERROR(1, ("Invalid size SMB length %d pdu_length %d",
Steve French46810cb2005-04-28 22:41:09 -0700504 length, pdu_length+4));
Steve Frenche4eb2952005-04-28 22:41:09 -0700505 cifs_reconnect(server);
506 csocket = server->ssocket;
507 wake_up(&server->response_q);
508 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000509 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700510
511 /* else length ok */
512 reconnect = 0;
513
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000514 if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
Steve French4b18f2a2008-04-29 00:06:05 +0000515 isLargeBuf = true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700516 memcpy(bigbuf, smallbuf, 4);
517 smb_buffer = bigbuf;
518 }
519 length = 0;
520 iov.iov_base = 4 + (char *)smb_buffer;
521 iov.iov_len = pdu_length;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000522 for (total_read = 0; total_read < pdu_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700523 total_read += length) {
524 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
525 pdu_length - total_read, 0);
Steve French26f57362007-08-30 22:09:15 +0000526 if (kthread_should_stop() ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700527 (length == -EINTR)) {
528 /* then will exit */
529 reconnect = 2;
530 break;
531 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700532 cifs_reconnect(server);
533 csocket = server->ssocket;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000534 /* Reconnect wakes up rspns q */
Steve Frenche4eb2952005-04-28 22:41:09 -0700535 /* Now we will reread sock */
536 reconnect = 1;
537 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000538 } else if ((length == -ERESTARTSYS) ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700539 (length == -EAGAIN)) {
540 msleep(1); /* minimum sleep to prevent looping,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000541 allowing socket to clear and app
Steve Frenche4eb2952005-04-28 22:41:09 -0700542 threads to set tcpStatus
543 CifsNeedReconnect if server hung*/
Steve Frenchc18c7322007-10-17 18:01:11 +0000544 length = 0;
Steve French46810cb2005-04-28 22:41:09 -0700545 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700546 } else if (length <= 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000547 cERROR(1, ("Received no data, expecting %d",
Steve Frenche4eb2952005-04-28 22:41:09 -0700548 pdu_length - total_read));
549 cifs_reconnect(server);
550 csocket = server->ssocket;
551 reconnect = 1;
552 break;
Steve French46810cb2005-04-28 22:41:09 -0700553 }
554 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000555 if (reconnect == 2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700556 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000557 else if (reconnect == 1)
Steve Frenche4eb2952005-04-28 22:41:09 -0700558 continue;
559
560 length += 4; /* account for rfc1002 hdr */
Steve French50c2f752007-07-13 00:33:32 +0000561
Steve Frenche4eb2952005-04-28 22:41:09 -0700562
563 dump_smb(smb_buffer, length);
Steve French184ed212006-02-24 06:15:11 +0000564 if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700565 cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
Steve Frenche4eb2952005-04-28 22:41:09 -0700566 continue;
567 }
568
569
570 task_to_wake = NULL;
571 spin_lock(&GlobalMid_Lock);
572 list_for_each(tmp, &server->pending_mid_q) {
573 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
574
Steve French50c2f752007-07-13 00:33:32 +0000575 if ((mid_entry->mid == smb_buffer->Mid) &&
Steve Frenche4eb2952005-04-28 22:41:09 -0700576 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
577 (mid_entry->command == smb_buffer->Command)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000578 if (check2ndT2(smb_buffer,server->maxBuf) > 0) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700579 /* We have a multipart transact2 resp */
Steve French4b18f2a2008-04-29 00:06:05 +0000580 isMultiRsp = true;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000581 if (mid_entry->resp_buf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700582 /* merge response - fix up 1st*/
Steve French50c2f752007-07-13 00:33:32 +0000583 if (coalesce_t2(smb_buffer,
Steve Frenche4eb2952005-04-28 22:41:09 -0700584 mid_entry->resp_buf)) {
Steve French4b18f2a2008-04-29 00:06:05 +0000585 mid_entry->multiRsp =
586 true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700587 break;
588 } else {
589 /* all parts received */
Steve French4b18f2a2008-04-29 00:06:05 +0000590 mid_entry->multiEnd =
591 true;
Steve French50c2f752007-07-13 00:33:32 +0000592 goto multi_t2_fnd;
Steve Frenche4eb2952005-04-28 22:41:09 -0700593 }
594 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000595 if (!isLargeBuf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700596 cERROR(1,("1st trans2 resp needs bigbuf"));
597 /* BB maybe we can fix this up, switch
Steve French50c2f752007-07-13 00:33:32 +0000598 to already allocated large buffer? */
Steve Frenche4eb2952005-04-28 22:41:09 -0700599 } else {
Steve Frenchcd634992005-04-28 22:41:10 -0700600 /* Have first buffer */
Steve Frenche4eb2952005-04-28 22:41:09 -0700601 mid_entry->resp_buf =
602 smb_buffer;
Steve French4b18f2a2008-04-29 00:06:05 +0000603 mid_entry->largeBuf =
604 true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700605 bigbuf = NULL;
606 }
607 }
608 break;
Steve French50c2f752007-07-13 00:33:32 +0000609 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700610 mid_entry->resp_buf = smb_buffer;
Steve French4b18f2a2008-04-29 00:06:05 +0000611 mid_entry->largeBuf = isLargeBuf;
Steve Frenche4eb2952005-04-28 22:41:09 -0700612multi_t2_fnd:
613 task_to_wake = mid_entry->tsk;
614 mid_entry->midState = MID_RESPONSE_RECEIVED;
Steve French1047abc2005-10-11 19:58:06 -0700615#ifdef CONFIG_CIFS_STATS2
616 mid_entry->when_received = jiffies;
617#endif
Steve French3a5ff612006-07-14 22:37:11 +0000618 /* so we do not time out requests to server
619 which is still responding (since server could
620 be busy but not dead) */
621 server->lstrp = jiffies;
Steve Frenche4eb2952005-04-28 22:41:09 -0700622 break;
623 }
624 }
625 spin_unlock(&GlobalMid_Lock);
626 if (task_to_wake) {
Steve Frenchcd634992005-04-28 22:41:10 -0700627 /* Was previous buf put in mpx struct for multi-rsp? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000628 if (!isMultiRsp) {
Steve Frenchcd634992005-04-28 22:41:10 -0700629 /* smb buffer will be freed by user thread */
Steve French26f57362007-08-30 22:09:15 +0000630 if (isLargeBuf)
Steve Frenchcd634992005-04-28 22:41:10 -0700631 bigbuf = NULL;
Steve French26f57362007-08-30 22:09:15 +0000632 else
Steve Frenchcd634992005-04-28 22:41:10 -0700633 smallbuf = NULL;
634 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700635 wake_up_process(task_to_wake);
Steve French4b18f2a2008-04-29 00:06:05 +0000636 } else if (!is_valid_oplock_break(smb_buffer, server) &&
637 !isMultiRsp) {
Steve French50c2f752007-07-13 00:33:32 +0000638 cERROR(1, ("No task to wake, unknown frame received! "
639 "NumMids %d", midCount.counter));
640 cifs_dump_mem("Received Data is: ", (char *)smb_buffer,
Steve French70ca7342005-09-22 16:32:06 -0700641 sizeof(struct smb_hdr));
Steve French39798772006-05-31 22:40:51 +0000642#ifdef CONFIG_CIFS_DEBUG2
643 cifs_dump_detail(smb_buffer);
644 cifs_dump_mids(server);
645#endif /* CIFS_DEBUG2 */
Steve French50c2f752007-07-13 00:33:32 +0000646
Steve Frenche4eb2952005-04-28 22:41:09 -0700647 }
648 } /* end while !EXITING */
649
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 spin_lock(&GlobalMid_Lock);
651 server->tcpStatus = CifsExiting;
Steve Frenche691b9d2008-05-11 15:53:33 +0000652 spin_unlock(&GlobalMid_Lock);
Steve Frenchdbdbb872008-06-10 21:21:56 +0000653 wake_up_all(&server->response_q);
Steve Frenche691b9d2008-05-11 15:53:33 +0000654
655 /* don't exit until kthread_stop is called */
656 set_current_state(TASK_UNINTERRUPTIBLE);
657 while (!kthread_should_stop()) {
658 schedule();
659 set_current_state(TASK_UNINTERRUPTIBLE);
660 }
661 set_current_state(TASK_RUNNING);
662
Steve French31ca3bc2005-04-28 22:41:11 -0700663 /* check if we have blocked requests that need to free */
664 /* Note that cifs_max_pending is normally 50, but
665 can be set at module install time to as little as two */
Steve Frenche691b9d2008-05-11 15:53:33 +0000666 spin_lock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000667 if (atomic_read(&server->inFlight) >= cifs_max_pending)
Steve French31ca3bc2005-04-28 22:41:11 -0700668 atomic_set(&server->inFlight, cifs_max_pending - 1);
669 /* We do not want to set the max_pending too low or we
670 could end up with the counter going negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +0000672 /* Although there should not be any requests blocked on
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700674 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 to the same server - they now will see the session is in exit state
676 and get out of SendReceive. */
677 wake_up_all(&server->request_q);
678 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700679 msleep(125);
Steve French50c2f752007-07-13 00:33:32 +0000680
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000681 if (server->ssocket) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 sock_release(csocket);
683 server->ssocket = NULL;
684 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700685 /* buffer usuallly freed in free_mid - need to free it here on exit */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +0000686 cifs_buf_release(bigbuf);
687 if (smallbuf) /* no sense logging a debug message if NULL */
Steve Frenchb8643e12005-04-28 22:41:07 -0700688 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689
690 read_lock(&GlobalSMBSeslock);
691 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700692 /* loop through server session structures attached to this and
693 mark them dead */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 list_for_each(tmp, &GlobalSMBSessionList) {
695 ses =
696 list_entry(tmp, struct cifsSesInfo,
697 cifsSessionList);
698 if (ses->server == server) {
699 ses->status = CifsExiting;
700 ses->server = NULL;
701 }
702 }
703 read_unlock(&GlobalSMBSeslock);
704 } else {
Steve French31ca3bc2005-04-28 22:41:11 -0700705 /* although we can not zero the server struct pointer yet,
706 since there are active requests which may depnd on them,
707 mark the corresponding SMB sessions as exiting too */
708 list_for_each(tmp, &GlobalSMBSessionList) {
709 ses = list_entry(tmp, struct cifsSesInfo,
710 cifsSessionList);
Steve French26f57362007-08-30 22:09:15 +0000711 if (ses->server == server)
Steve French31ca3bc2005-04-28 22:41:11 -0700712 ses->status = CifsExiting;
Steve French31ca3bc2005-04-28 22:41:11 -0700713 }
714
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 spin_lock(&GlobalMid_Lock);
716 list_for_each(tmp, &server->pending_mid_q) {
717 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
718 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French50c2f752007-07-13 00:33:32 +0000719 cFYI(1, ("Clearing Mid 0x%x - waking up ",
720 mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 task_to_wake = mid_entry->tsk;
Steve French26f57362007-08-30 22:09:15 +0000722 if (task_to_wake)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 wake_up_process(task_to_wake);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 }
725 }
726 spin_unlock(&GlobalMid_Lock);
727 read_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700729 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 }
731
Steve Frenchf1914012005-08-18 09:37:34 -0700732 if (!list_empty(&server->pending_mid_q)) {
Steve French50c2f752007-07-13 00:33:32 +0000733 /* mpx threads have not exited yet give them
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700735 /* due to delays on oplock break requests, we need
736 to wait at least 45 seconds before giving up
737 on a request getting a response and going ahead
738 and killing cifsd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve French31ca3bc2005-04-28 22:41:11 -0700740 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 /* if threads still have not exited they are probably never
742 coming home not much else we can do but free the memory */
743 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744
Steve French31ca3bc2005-04-28 22:41:11 -0700745 /* last chance to mark ses pointers invalid
746 if there are any pointing to this (e.g
Steve French50c2f752007-07-13 00:33:32 +0000747 if a crazy root user tried to kill cifsd
Steve French31ca3bc2005-04-28 22:41:11 -0700748 kernel thread explicitly this might happen) */
Jeff Layton93d0ec82008-08-02 08:00:48 -0400749 write_lock(&GlobalSMBSeslock);
Steve French31ca3bc2005-04-28 22:41:11 -0700750 list_for_each(tmp, &GlobalSMBSessionList) {
751 ses = list_entry(tmp, struct cifsSesInfo,
752 cifsSessionList);
Steve French26f57362007-08-30 22:09:15 +0000753 if (ses->server == server)
Steve French31ca3bc2005-04-28 22:41:11 -0700754 ses->server = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700755 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 write_unlock(&GlobalSMBSeslock);
Steve French31ca3bc2005-04-28 22:41:11 -0700757
Jeff Laytonc359cf32007-11-16 22:22:06 +0000758 kfree(server->hostname);
Steve French31ca3bc2005-04-28 22:41:11 -0700759 kfree(server);
Jeff Layton93d0ec82008-08-02 08:00:48 -0400760
761 length = atomic_dec_return(&tcpSesAllocCount);
Steve French26f57362007-08-30 22:09:15 +0000762 if (length > 0)
763 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
764 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +0000765
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 return 0;
767}
768
Jeff Laytonc359cf32007-11-16 22:22:06 +0000769/* extract the host portion of the UNC string */
770static char *
771extract_hostname(const char *unc)
772{
773 const char *src;
774 char *dst, *delim;
775 unsigned int len;
776
777 /* skip double chars at beginning of string */
778 /* BB: check validity of these bytes? */
779 src = unc + 2;
780
781 /* delimiter between hostname and sharename is always '\\' now */
782 delim = strchr(src, '\\');
783 if (!delim)
784 return ERR_PTR(-EINVAL);
785
786 len = delim - src;
787 dst = kmalloc((len + 1), GFP_KERNEL);
788 if (dst == NULL)
789 return ERR_PTR(-ENOMEM);
790
791 memcpy(dst, src, len);
792 dst[len] = '\0';
793
794 return dst;
795}
796
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797static int
Steve French50c2f752007-07-13 00:33:32 +0000798cifs_parse_mount_options(char *options, const char *devname,
799 struct smb_vol *vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800{
801 char *value;
802 char *data;
803 unsigned int temp_len, i, j;
804 char separator[2];
805
806 separator[0] = ',';
Steve French50c2f752007-07-13 00:33:32 +0000807 separator[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808
Linus Torvalds12e36b22006-10-13 08:09:29 -0700809 if (Local_System_Name[0] != 0)
Steve French50c2f752007-07-13 00:33:32 +0000810 memcpy(vol->source_rfc1001_name, Local_System_Name, 15);
Steve French2cd646a2006-09-28 19:43:08 +0000811 else {
Linus Torvalds12e36b22006-10-13 08:09:29 -0700812 char *nodename = utsname()->nodename;
Steve French50c2f752007-07-13 00:33:32 +0000813 int n = strnlen(nodename, 15);
814 memset(vol->source_rfc1001_name, 0x20, 15);
815 for (i = 0; i < n; i++) {
Steve French2cd646a2006-09-28 19:43:08 +0000816 /* does not have to be perfect mapping since field is
817 informational, only used for servers that do not support
818 port 445 and it can be overridden at mount time */
Linus Torvalds12e36b22006-10-13 08:09:29 -0700819 vol->source_rfc1001_name[i] = toupper(nodename[i]);
Steve French2cd646a2006-09-28 19:43:08 +0000820 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 }
822 vol->source_rfc1001_name[15] = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -0700823 /* null target name indicates to use *SMBSERVR default called name
824 if we end up sending RFC1001 session initialize */
825 vol->target_rfc1001_name[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 vol->linux_uid = current->uid; /* current->euid instead? */
827 vol->linux_gid = current->gid;
828 vol->dir_mode = S_IRWXUGO;
829 /* 2767 perms indicate mandatory locking support */
Steve French7505e052007-11-01 18:03:01 +0000830 vol->file_mode = (S_IRWXUGO | S_ISGID) & (~S_IXGRP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831
832 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
Steve French4b18f2a2008-04-29 00:06:05 +0000833 vol->rw = true;
Jeremy Allisonac670552005-06-22 17:26:35 -0700834 /* default is always to request posix paths. */
835 vol->posix_paths = 1;
836
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 if (!options)
838 return 1;
839
Steve French50c2f752007-07-13 00:33:32 +0000840 if (strncmp(options, "sep=", 4) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000841 if (options[4] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 separator[0] = options[4];
843 options += 5;
844 } else {
Steve French467a8f82007-06-27 22:41:32 +0000845 cFYI(1, ("Null separator not allowed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 }
847 }
Steve French50c2f752007-07-13 00:33:32 +0000848
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 while ((data = strsep(&options, separator)) != NULL) {
850 if (!*data)
851 continue;
852 if ((value = strchr(data, '=')) != NULL)
853 *value++ = '\0';
854
Steve French50c2f752007-07-13 00:33:32 +0000855 /* Have to parse this before we parse for "user" */
856 if (strnicmp(data, "user_xattr", 10) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 vol->no_xattr = 0;
Steve French50c2f752007-07-13 00:33:32 +0000858 } else if (strnicmp(data, "nouser_xattr", 12) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 vol->no_xattr = 1;
860 } else if (strnicmp(data, "user", 4) == 0) {
Steve French4b952a92006-10-30 21:46:13 +0000861 if (!value) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 printk(KERN_WARNING
863 "CIFS: invalid or missing username\n");
864 return 1; /* needs_arg; */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000865 } else if (!*value) {
Steve French4b952a92006-10-30 21:46:13 +0000866 /* null user, ie anonymous, authentication */
867 vol->nullauth = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 }
869 if (strnlen(value, 200) < 200) {
870 vol->username = value;
871 } else {
872 printk(KERN_WARNING "CIFS: username too long\n");
873 return 1;
874 }
875 } else if (strnicmp(data, "pass", 4) == 0) {
876 if (!value) {
877 vol->password = NULL;
878 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000879 } else if (value[0] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 /* check if string begins with double comma
881 since that would mean the password really
882 does start with a comma, and would not
883 indicate an empty string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000884 if (value[1] != separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 vol->password = NULL;
886 continue;
887 }
888 }
889 temp_len = strlen(value);
890 /* removed password length check, NTLM passwords
891 can be arbitrarily long */
892
Steve French50c2f752007-07-13 00:33:32 +0000893 /* if comma in password, the string will be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 prematurely null terminated. Commas in password are
895 specified across the cifs mount interface by a double
896 comma ie ,, and a comma used as in other cases ie ','
897 as a parameter delimiter/separator is single and due
898 to the strsep above is temporarily zeroed. */
899
900 /* NB: password legally can have multiple commas and
901 the only illegal character in a password is null */
902
Steve French50c2f752007-07-13 00:33:32 +0000903 if ((value[temp_len] == 0) &&
Steve French09d1db52005-04-28 22:41:08 -0700904 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 /* reinsert comma */
906 value[temp_len] = separator[0];
Steve French50c2f752007-07-13 00:33:32 +0000907 temp_len += 2; /* move after second comma */
908 while (value[temp_len] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 if (value[temp_len] == separator[0]) {
Steve French50c2f752007-07-13 00:33:32 +0000910 if (value[temp_len+1] ==
Steve French09d1db52005-04-28 22:41:08 -0700911 separator[0]) {
912 /* skip second comma */
913 temp_len++;
Steve French50c2f752007-07-13 00:33:32 +0000914 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 /* single comma indicating start
916 of next parm */
917 break;
918 }
919 }
920 temp_len++;
921 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000922 if (value[temp_len] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 options = NULL;
924 } else {
925 value[temp_len] = 0;
926 /* point option to start of next parm */
927 options = value + temp_len + 1;
928 }
Steve French50c2f752007-07-13 00:33:32 +0000929 /* go from value to value + temp_len condensing
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 double commas to singles. Note that this ends up
931 allocating a few bytes too many, which is ok */
Pekka Enberge915fc42005-09-06 15:18:35 -0700932 vol->password = kzalloc(temp_len, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000933 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000934 printk(KERN_WARNING "CIFS: no memory "
935 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700936 return 1;
937 }
Steve French50c2f752007-07-13 00:33:32 +0000938 for (i = 0, j = 0; i < temp_len; i++, j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 vol->password[j] = value[i];
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000940 if (value[i] == separator[0]
Steve French09d1db52005-04-28 22:41:08 -0700941 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 /* skip second comma */
943 i++;
944 }
945 }
946 vol->password[j] = 0;
947 } else {
Pekka Enberge915fc42005-09-06 15:18:35 -0700948 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000949 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000950 printk(KERN_WARNING "CIFS: no memory "
951 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700952 return 1;
953 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 strcpy(vol->password, value);
955 }
956 } else if (strnicmp(data, "ip", 2) == 0) {
957 if (!value || !*value) {
958 vol->UNCip = NULL;
959 } else if (strnlen(value, 35) < 35) {
960 vol->UNCip = value;
961 } else {
Steve French50c2f752007-07-13 00:33:32 +0000962 printk(KERN_WARNING "CIFS: ip address "
963 "too long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 return 1;
965 }
Steve French50c2f752007-07-13 00:33:32 +0000966 } else if (strnicmp(data, "sec", 3) == 0) {
967 if (!value || !*value) {
968 cERROR(1, ("no security value specified"));
969 continue;
970 } else if (strnicmp(value, "krb5i", 5) == 0) {
971 vol->secFlg |= CIFSSEC_MAY_KRB5 |
Steve French189acaa2006-06-23 02:33:48 +0000972 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800973 } else if (strnicmp(value, "krb5p", 5) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000974 /* vol->secFlg |= CIFSSEC_MUST_SEAL |
975 CIFSSEC_MAY_KRB5; */
976 cERROR(1, ("Krb5 cifs privacy not supported"));
Steve Frenchbf820672005-12-01 22:32:42 -0800977 return 1;
978 } else if (strnicmp(value, "krb5", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000979 vol->secFlg |= CIFSSEC_MAY_KRB5;
Steve Frenchbf820672005-12-01 22:32:42 -0800980 } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000981 vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
Steve French189acaa2006-06-23 02:33:48 +0000982 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800983 } else if (strnicmp(value, "ntlmv2", 6) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000984 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve Frenchbf820672005-12-01 22:32:42 -0800985 } else if (strnicmp(value, "ntlmi", 5) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000986 vol->secFlg |= CIFSSEC_MAY_NTLM |
Steve French189acaa2006-06-23 02:33:48 +0000987 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800988 } else if (strnicmp(value, "ntlm", 4) == 0) {
989 /* ntlm is default so can be turned off too */
Steve French750d1152006-06-27 06:28:30 +0000990 vol->secFlg |= CIFSSEC_MAY_NTLM;
Steve Frenchbf820672005-12-01 22:32:42 -0800991 } else if (strnicmp(value, "nontlm", 6) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000992 /* BB is there a better way to do this? */
Steve French750d1152006-06-27 06:28:30 +0000993 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve French189acaa2006-06-23 02:33:48 +0000994#ifdef CONFIG_CIFS_WEAK_PW_HASH
995 } else if (strnicmp(value, "lanman", 6) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000996 vol->secFlg |= CIFSSEC_MAY_LANMAN;
Steve French189acaa2006-06-23 02:33:48 +0000997#endif
Steve Frenchbf820672005-12-01 22:32:42 -0800998 } else if (strnicmp(value, "none", 4) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000999 vol->nullauth = 1;
Steve French50c2f752007-07-13 00:33:32 +00001000 } else {
1001 cERROR(1, ("bad security option: %s", value));
1002 return 1;
1003 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 } else if ((strnicmp(data, "unc", 3) == 0)
1005 || (strnicmp(data, "target", 6) == 0)
1006 || (strnicmp(data, "path", 4) == 0)) {
1007 if (!value || !*value) {
Steve French50c2f752007-07-13 00:33:32 +00001008 printk(KERN_WARNING "CIFS: invalid path to "
1009 "network resource\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 return 1; /* needs_arg; */
1011 }
1012 if ((temp_len = strnlen(value, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001013 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001014 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001016 strcpy(vol->UNC, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 if (strncmp(vol->UNC, "//", 2) == 0) {
1018 vol->UNC[0] = '\\';
1019 vol->UNC[1] = '\\';
Steve French50c2f752007-07-13 00:33:32 +00001020 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 printk(KERN_WARNING
Steve French50c2f752007-07-13 00:33:32 +00001022 "CIFS: UNC Path does not begin "
1023 "with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 return 1;
1025 }
1026 } else {
1027 printk(KERN_WARNING "CIFS: UNC name too long\n");
1028 return 1;
1029 }
1030 } else if ((strnicmp(data, "domain", 3) == 0)
1031 || (strnicmp(data, "workgroup", 5) == 0)) {
1032 if (!value || !*value) {
1033 printk(KERN_WARNING "CIFS: invalid domain name\n");
1034 return 1; /* needs_arg; */
1035 }
1036 /* BB are there cases in which a comma can be valid in
1037 a domain name and need special handling? */
Steve French39798772006-05-31 22:40:51 +00001038 if (strnlen(value, 256) < 256) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 vol->domainname = value;
1040 cFYI(1, ("Domain name set"));
1041 } else {
Steve French50c2f752007-07-13 00:33:32 +00001042 printk(KERN_WARNING "CIFS: domain name too "
1043 "long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 return 1;
1045 }
Steve French50c2f752007-07-13 00:33:32 +00001046 } else if (strnicmp(data, "prefixpath", 10) == 0) {
1047 if (!value || !*value) {
1048 printk(KERN_WARNING
1049 "CIFS: invalid path prefix\n");
1050 return 1; /* needs_argument */
1051 }
1052 if ((temp_len = strnlen(value, 1024)) < 1024) {
Steve French4523cc32007-04-30 20:13:06 +00001053 if (value[0] != '/')
Steve French2fe87f02006-09-21 07:02:52 +00001054 temp_len++; /* missing leading slash */
Steve French50c2f752007-07-13 00:33:32 +00001055 vol->prepath = kmalloc(temp_len+1, GFP_KERNEL);
1056 if (vol->prepath == NULL)
1057 return 1;
Steve French4523cc32007-04-30 20:13:06 +00001058 if (value[0] != '/') {
Steve French2fe87f02006-09-21 07:02:52 +00001059 vol->prepath[0] = '/';
Steve French50c2f752007-07-13 00:33:32 +00001060 strcpy(vol->prepath+1, value);
Steve French2fe87f02006-09-21 07:02:52 +00001061 } else
Steve French50c2f752007-07-13 00:33:32 +00001062 strcpy(vol->prepath, value);
1063 cFYI(1, ("prefix path %s", vol->prepath));
1064 } else {
1065 printk(KERN_WARNING "CIFS: prefix too long\n");
1066 return 1;
1067 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 } else if (strnicmp(data, "iocharset", 9) == 0) {
1069 if (!value || !*value) {
Steve French63135e02007-07-17 17:34:02 +00001070 printk(KERN_WARNING "CIFS: invalid iocharset "
1071 "specified\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 return 1; /* needs_arg; */
1073 }
1074 if (strnlen(value, 65) < 65) {
Steve French50c2f752007-07-13 00:33:32 +00001075 if (strnicmp(value, "default", 7))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 vol->iocharset = value;
Steve French50c2f752007-07-13 00:33:32 +00001077 /* if iocharset not set then load_nls_default
1078 is used by caller */
1079 cFYI(1, ("iocharset set to %s", value));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 } else {
Steve French63135e02007-07-17 17:34:02 +00001081 printk(KERN_WARNING "CIFS: iocharset name "
1082 "too long.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 return 1;
1084 }
1085 } else if (strnicmp(data, "uid", 3) == 0) {
1086 if (value && *value) {
1087 vol->linux_uid =
1088 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001089 vol->override_uid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 }
1091 } else if (strnicmp(data, "gid", 3) == 0) {
1092 if (value && *value) {
1093 vol->linux_gid =
1094 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001095 vol->override_gid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 }
1097 } else if (strnicmp(data, "file_mode", 4) == 0) {
1098 if (value && *value) {
1099 vol->file_mode =
1100 simple_strtoul(value, &value, 0);
1101 }
1102 } else if (strnicmp(data, "dir_mode", 4) == 0) {
1103 if (value && *value) {
1104 vol->dir_mode =
1105 simple_strtoul(value, &value, 0);
1106 }
1107 } else if (strnicmp(data, "dirmode", 4) == 0) {
1108 if (value && *value) {
1109 vol->dir_mode =
1110 simple_strtoul(value, &value, 0);
1111 }
1112 } else if (strnicmp(data, "port", 4) == 0) {
1113 if (value && *value) {
1114 vol->port =
1115 simple_strtoul(value, &value, 0);
1116 }
1117 } else if (strnicmp(data, "rsize", 5) == 0) {
1118 if (value && *value) {
1119 vol->rsize =
1120 simple_strtoul(value, &value, 0);
1121 }
1122 } else if (strnicmp(data, "wsize", 5) == 0) {
1123 if (value && *value) {
1124 vol->wsize =
1125 simple_strtoul(value, &value, 0);
1126 }
1127 } else if (strnicmp(data, "sockopt", 5) == 0) {
1128 if (value && *value) {
1129 vol->sockopt =
1130 simple_strtoul(value, &value, 0);
1131 }
1132 } else if (strnicmp(data, "netbiosname", 4) == 0) {
1133 if (!value || !*value || (*value == ' ')) {
Steve French63135e02007-07-17 17:34:02 +00001134 cFYI(1, ("invalid (empty) netbiosname"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 } else {
Steve French50c2f752007-07-13 00:33:32 +00001136 memset(vol->source_rfc1001_name, 0x20, 15);
1137 for (i = 0; i < 15; i++) {
1138 /* BB are there cases in which a comma can be
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 valid in this workstation netbios name (and need
1140 special handling)? */
1141
1142 /* We do not uppercase netbiosname for user */
Steve French50c2f752007-07-13 00:33:32 +00001143 if (value[i] == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 break;
Steve French50c2f752007-07-13 00:33:32 +00001145 else
1146 vol->source_rfc1001_name[i] =
1147 value[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 }
1149 /* The string has 16th byte zero still from
1150 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001151 if ((i == 15) && (value[i] != 0))
1152 printk(KERN_WARNING "CIFS: netbiosname"
1153 " longer than 15 truncated.\n");
Steve Frencha10faeb22005-08-22 21:38:31 -07001154 }
1155 } else if (strnicmp(data, "servern", 7) == 0) {
1156 /* servernetbiosname specified override *SMBSERVER */
1157 if (!value || !*value || (*value == ' ')) {
Steve French467a8f82007-06-27 22:41:32 +00001158 cFYI(1, ("empty server netbiosname specified"));
Steve Frencha10faeb22005-08-22 21:38:31 -07001159 } else {
1160 /* last byte, type, is 0x20 for servr type */
Steve French50c2f752007-07-13 00:33:32 +00001161 memset(vol->target_rfc1001_name, 0x20, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001162
Steve French50c2f752007-07-13 00:33:32 +00001163 for (i = 0; i < 15; i++) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001164 /* BB are there cases in which a comma can be
Steve French50c2f752007-07-13 00:33:32 +00001165 valid in this workstation netbios name
1166 (and need special handling)? */
Steve Frencha10faeb22005-08-22 21:38:31 -07001167
Steve French50c2f752007-07-13 00:33:32 +00001168 /* user or mount helper must uppercase
1169 the netbiosname */
1170 if (value[i] == 0)
Steve Frencha10faeb22005-08-22 21:38:31 -07001171 break;
1172 else
Steve French50c2f752007-07-13 00:33:32 +00001173 vol->target_rfc1001_name[i] =
1174 value[i];
Steve Frencha10faeb22005-08-22 21:38:31 -07001175 }
1176 /* The string has 16th byte zero still from
1177 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001178 if ((i == 15) && (value[i] != 0))
1179 printk(KERN_WARNING "CIFS: server net"
1180 "biosname longer than 15 truncated.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 }
1182 } else if (strnicmp(data, "credentials", 4) == 0) {
1183 /* ignore */
1184 } else if (strnicmp(data, "version", 3) == 0) {
1185 /* ignore */
Steve French50c2f752007-07-13 00:33:32 +00001186 } else if (strnicmp(data, "guest", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 /* ignore */
1188 } else if (strnicmp(data, "rw", 2) == 0) {
Steve French4b18f2a2008-04-29 00:06:05 +00001189 vol->rw = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 } else if ((strnicmp(data, "suid", 4) == 0) ||
1191 (strnicmp(data, "nosuid", 6) == 0) ||
1192 (strnicmp(data, "exec", 4) == 0) ||
1193 (strnicmp(data, "noexec", 6) == 0) ||
1194 (strnicmp(data, "nodev", 5) == 0) ||
1195 (strnicmp(data, "noauto", 6) == 0) ||
1196 (strnicmp(data, "dev", 3) == 0)) {
1197 /* The mount tool or mount.cifs helper (if present)
Steve French50c2f752007-07-13 00:33:32 +00001198 uses these opts to set flags, and the flags are read
1199 by the kernel vfs layer before we get here (ie
1200 before read super) so there is no point trying to
1201 parse these options again and set anything and it
1202 is ok to just ignore them */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 continue;
1204 } else if (strnicmp(data, "ro", 2) == 0) {
Steve French4b18f2a2008-04-29 00:06:05 +00001205 vol->rw = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 } else if (strnicmp(data, "hard", 4) == 0) {
1207 vol->retry = 1;
1208 } else if (strnicmp(data, "soft", 4) == 0) {
1209 vol->retry = 0;
1210 } else if (strnicmp(data, "perm", 4) == 0) {
1211 vol->noperm = 0;
1212 } else if (strnicmp(data, "noperm", 6) == 0) {
1213 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001214 } else if (strnicmp(data, "mapchars", 8) == 0) {
1215 vol->remap = 1;
1216 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1217 vol->remap = 0;
Steve French50c2f752007-07-13 00:33:32 +00001218 } else if (strnicmp(data, "sfu", 3) == 0) {
1219 vol->sfu_emul = 1;
1220 } else if (strnicmp(data, "nosfu", 5) == 0) {
1221 vol->sfu_emul = 0;
Steve French2c1b8612008-10-16 18:35:21 +00001222 } else if (strnicmp(data, "nodfs", 5) == 0) {
1223 vol->nodfs = 1;
Jeremy Allisonac670552005-06-22 17:26:35 -07001224 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1225 vol->posix_paths = 1;
1226 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1227 vol->posix_paths = 0;
Steve Frenchc18c8422007-07-18 23:21:09 +00001228 } else if (strnicmp(data, "nounix", 6) == 0) {
1229 vol->no_linux_ext = 1;
1230 } else if (strnicmp(data, "nolinux", 7) == 0) {
1231 vol->no_linux_ext = 1;
Steve French50c2f752007-07-13 00:33:32 +00001232 } else if ((strnicmp(data, "nocase", 6) == 0) ||
Steve Frencha10faeb22005-08-22 21:38:31 -07001233 (strnicmp(data, "ignorecase", 10) == 0)) {
Steve French50c2f752007-07-13 00:33:32 +00001234 vol->nocase = 1;
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001235 } else if (strnicmp(data, "brl", 3) == 0) {
1236 vol->nobrl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001237 } else if ((strnicmp(data, "nobrl", 5) == 0) ||
Steve French1c955182005-08-30 20:58:07 -07001238 (strnicmp(data, "nolock", 6) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001239 vol->nobrl = 1;
Steve Frenchd3485d32005-08-19 11:04:29 -07001240 /* turn off mandatory locking in mode
1241 if remote locking is turned off since the
1242 local vfs will do advisory */
Steve French50c2f752007-07-13 00:33:32 +00001243 if (vol->file_mode ==
1244 (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
Steve Frenchd3485d32005-08-19 11:04:29 -07001245 vol->file_mode = S_IALLUGO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 } else if (strnicmp(data, "setuids", 7) == 0) {
1247 vol->setuids = 1;
1248 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1249 vol->setuids = 0;
Jeff Laytond0a9c072008-05-12 22:23:49 +00001250 } else if (strnicmp(data, "dynperm", 7) == 0) {
1251 vol->dynperm = true;
1252 } else if (strnicmp(data, "nodynperm", 9) == 0) {
1253 vol->dynperm = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 } else if (strnicmp(data, "nohard", 6) == 0) {
1255 vol->retry = 0;
1256 } else if (strnicmp(data, "nosoft", 6) == 0) {
1257 vol->retry = 1;
1258 } else if (strnicmp(data, "nointr", 6) == 0) {
1259 vol->intr = 0;
1260 } else if (strnicmp(data, "intr", 4) == 0) {
1261 vol->intr = 1;
Steve French50c2f752007-07-13 00:33:32 +00001262 } else if (strnicmp(data, "serverino", 7) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 vol->server_ino = 1;
Steve French50c2f752007-07-13 00:33:32 +00001264 } else if (strnicmp(data, "noserverino", 9) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 vol->server_ino = 0;
Steve French50c2f752007-07-13 00:33:32 +00001266 } else if (strnicmp(data, "cifsacl", 7) == 0) {
Steve French0a4b92c2006-01-12 15:44:21 -08001267 vol->cifs_acl = 1;
1268 } else if (strnicmp(data, "nocifsacl", 9) == 0) {
1269 vol->cifs_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001270 } else if (strnicmp(data, "acl", 3) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271 vol->no_psx_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001272 } else if (strnicmp(data, "noacl", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 vol->no_psx_acl = 1;
Steve French50c2f752007-07-13 00:33:32 +00001274 } else if (strnicmp(data, "sign", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +00001275 vol->secFlg |= CIFSSEC_MUST_SIGN;
Steve French95b1cb92008-05-15 16:44:38 +00001276 } else if (strnicmp(data, "seal", 4) == 0) {
1277 /* we do not do the following in secFlags because seal
1278 is a per tree connection (mount) not a per socket
1279 or per-smb connection option in the protocol */
1280 /* vol->secFlg |= CIFSSEC_MUST_SEAL; */
1281 vol->seal = 1;
Steve French50c2f752007-07-13 00:33:32 +00001282 } else if (strnicmp(data, "direct", 6) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001284 } else if (strnicmp(data, "forcedirectio", 13) == 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, "in6_addr", 8) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 if (!value || !*value) {
1288 vol->in6_addr = NULL;
1289 } else if (strnlen(value, 49) == 48) {
1290 vol->in6_addr = value;
1291 } else {
Steve French50c2f752007-07-13 00:33:32 +00001292 printk(KERN_WARNING "CIFS: ip v6 address not "
1293 "48 characters long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 return 1;
1295 }
1296 } else if (strnicmp(data, "noac", 4) == 0) {
Steve French50c2f752007-07-13 00:33:32 +00001297 printk(KERN_WARNING "CIFS: Mount option noac not "
1298 "supported. Instead set "
1299 "/proc/fs/cifs/LookupCacheEnabled to 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 } else
Steve French50c2f752007-07-13 00:33:32 +00001301 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",
1302 data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 }
1304 if (vol->UNC == NULL) {
Steve French4523cc32007-04-30 20:13:06 +00001305 if (devname == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001306 printk(KERN_WARNING "CIFS: Missing UNC name for mount "
1307 "target\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 return 1;
1309 }
1310 if ((temp_len = strnlen(devname, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001311 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001312 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001314 strcpy(vol->UNC, devname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 if (strncmp(vol->UNC, "//", 2) == 0) {
1316 vol->UNC[0] = '\\';
1317 vol->UNC[1] = '\\';
1318 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Steve French50c2f752007-07-13 00:33:32 +00001319 printk(KERN_WARNING "CIFS: UNC Path does not "
1320 "begin with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 return 1;
1322 }
Igor Mammedov7c5e6282008-05-08 20:48:42 +00001323 value = strpbrk(vol->UNC+2, "/\\");
1324 if (value)
1325 *value = '\\';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 } else {
1327 printk(KERN_WARNING "CIFS: UNC name too long\n");
1328 return 1;
1329 }
1330 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001331 if (vol->UNCip == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 vol->UNCip = &vol->UNC[2];
1333
1334 return 0;
1335}
1336
1337static struct cifsSesInfo *
Steve French50c2f752007-07-13 00:33:32 +00001338cifs_find_tcp_session(struct in_addr *target_ip_addr,
Cyrill Gorcunov1b20d672008-05-09 18:17:21 +00001339 struct in6_addr *target_ip6_addr,
1340 char *userName, struct TCP_Server_Info **psrvTcp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341{
1342 struct list_head *tmp;
1343 struct cifsSesInfo *ses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344
Cyrill Gorcunov1b20d672008-05-09 18:17:21 +00001345 *psrvTcp = NULL;
1346
1347 read_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 list_for_each(tmp, &GlobalSMBSessionList) {
1349 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
Cyrill Gorcunov1b20d672008-05-09 18:17:21 +00001350 if (!ses->server)
1351 continue;
Steve French50c2f752007-07-13 00:33:32 +00001352
Cyrill Gorcunov1b20d672008-05-09 18:17:21 +00001353 if (target_ip_addr &&
1354 ses->server->addr.sockAddr.sin_addr.s_addr != target_ip_addr->s_addr)
1355 continue;
1356 else if (target_ip6_addr &&
1357 memcmp(&ses->server->addr.sockAddr6.sin6_addr,
1358 target_ip6_addr, sizeof(*target_ip6_addr)))
1359 continue;
Jeff Layton02eadef2008-05-09 21:26:11 +00001360 /* BB lock server and tcp session; increment use count here?? */
Steve French50c2f752007-07-13 00:33:32 +00001361
Cyrill Gorcunov1b20d672008-05-09 18:17:21 +00001362 /* found a match on the TCP session */
1363 *psrvTcp = ses->server;
1364
1365 /* BB check if reconnection needed */
1366 if (strncmp(ses->userName, userName, MAX_USERNAME_SIZE) == 0) {
1367 read_unlock(&GlobalSMBSeslock);
1368 /* Found exact match on both TCP and
1369 SMB sessions */
1370 return ses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 }
1372 /* else tcp and smb sessions need reconnection */
1373 }
1374 read_unlock(&GlobalSMBSeslock);
Cyrill Gorcunov1b20d672008-05-09 18:17:21 +00001375
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 return NULL;
1377}
1378
1379static struct cifsTconInfo *
1380find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
1381{
1382 struct list_head *tmp;
1383 struct cifsTconInfo *tcon;
Steve Frenchdea570e02008-05-06 22:05:51 +00001384 __be32 old_ip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385
1386 read_lock(&GlobalSMBSeslock);
Steve Frenchdea570e02008-05-06 22:05:51 +00001387
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388 list_for_each(tmp, &GlobalTreeConnectionList) {
Steve Frenche466e482006-08-15 13:07:18 +00001389 cFYI(1, ("Next tcon"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
Steve Frenchdea570e02008-05-06 22:05:51 +00001391 if (!tcon->ses || !tcon->ses->server)
1392 continue;
1393
1394 old_ip = tcon->ses->server->addr.sockAddr.sin_addr.s_addr;
1395 cFYI(1, ("old ip addr: %x == new ip %x ?",
1396 old_ip, new_target_ip_addr));
1397
1398 if (old_ip != new_target_ip_addr)
1399 continue;
1400
1401 /* BB lock tcon, server, tcp session and increment use count? */
1402 /* found a match on the TCP session */
1403 /* BB check if reconnection needed */
1404 cFYI(1, ("IP match, old UNC: %s new: %s",
1405 tcon->treeName, uncName));
1406
1407 if (strncmp(tcon->treeName, uncName, MAX_TREE_SIZE))
1408 continue;
1409
1410 cFYI(1, ("and old usr: %s new: %s",
1411 tcon->treeName, uncName));
1412
1413 if (strncmp(tcon->ses->userName, userName, MAX_USERNAME_SIZE))
1414 continue;
1415
1416 /* matched smb session (user name) */
1417 read_unlock(&GlobalSMBSeslock);
1418 return tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 }
Steve Frenchdea570e02008-05-06 22:05:51 +00001420
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 read_unlock(&GlobalSMBSeslock);
1422 return NULL;
1423}
1424
1425int
Steve French50c2f752007-07-13 00:33:32 +00001426get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
1427 const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
Steve French366781c2008-01-25 10:12:41 +00001428 struct dfs_info3_param **preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429{
1430 char *temp_unc;
1431 int rc = 0;
1432
1433 *pnum_referrals = 0;
Steve French366781c2008-01-25 10:12:41 +00001434 *preferrals = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435
1436 if (pSesInfo->ipc_tid == 0) {
1437 temp_unc = kmalloc(2 /* for slashes */ +
Steve French50c2f752007-07-13 00:33:32 +00001438 strnlen(pSesInfo->serverName,
1439 SERVER_NAME_LEN_WITH_NULL * 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 + 1 + 4 /* slash IPC$ */ + 2,
1441 GFP_KERNEL);
1442 if (temp_unc == NULL)
1443 return -ENOMEM;
1444 temp_unc[0] = '\\';
1445 temp_unc[1] = '\\';
1446 strcpy(temp_unc + 2, pSesInfo->serverName);
1447 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1448 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1449 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00001450 ("CIFS Tcon rc = %d ipc_tid = %d", rc, pSesInfo->ipc_tid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 kfree(temp_unc);
1452 }
1453 if (rc == 0)
Steve Frenchc2cf07d2008-05-15 06:20:02 +00001454 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001455 pnum_referrals, nls_codepage, remap);
Steve French366781c2008-01-25 10:12:41 +00001456 /* BB map targetUNCs to dfs_info3 structures, here or
1457 in CIFSGetDFSRefer BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458
1459 return rc;
1460}
1461
Jeff Layton09e50d52008-07-23 10:11:19 -04001462#ifdef CONFIG_DEBUG_LOCK_ALLOC
1463static struct lock_class_key cifs_key[2];
1464static struct lock_class_key cifs_slock_key[2];
1465
1466static inline void
1467cifs_reclassify_socket4(struct socket *sock)
1468{
1469 struct sock *sk = sock->sk;
1470 BUG_ON(sock_owned_by_user(sk));
1471 sock_lock_init_class_and_name(sk, "slock-AF_INET-CIFS",
1472 &cifs_slock_key[0], "sk_lock-AF_INET-CIFS", &cifs_key[0]);
1473}
1474
1475static inline void
1476cifs_reclassify_socket6(struct socket *sock)
1477{
1478 struct sock *sk = sock->sk;
1479 BUG_ON(sock_owned_by_user(sk));
1480 sock_lock_init_class_and_name(sk, "slock-AF_INET6-CIFS",
1481 &cifs_slock_key[1], "sk_lock-AF_INET6-CIFS", &cifs_key[1]);
1482}
1483#else
1484static inline void
1485cifs_reclassify_socket4(struct socket *sock)
1486{
1487}
1488
1489static inline void
1490cifs_reclassify_socket6(struct socket *sock)
1491{
1492}
1493#endif
1494
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495/* See RFC1001 section 14 on representation of Netbios names */
Steve French50c2f752007-07-13 00:33:32 +00001496static void rfc1002mangle(char *target, char *source, unsigned int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497{
Steve French50c2f752007-07-13 00:33:32 +00001498 unsigned int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499
Steve French50c2f752007-07-13 00:33:32 +00001500 for (i = 0, j = 0; i < (length); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 /* mask a nibble at a time and encode */
1502 target[j] = 'A' + (0x0F & (source[i] >> 4));
1503 target[j+1] = 'A' + (0x0F & source[i]);
Steve French50c2f752007-07-13 00:33:32 +00001504 j += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 }
1506
1507}
1508
1509
1510static int
Steve French50c2f752007-07-13 00:33:32 +00001511ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
1512 char *netbios_name, char *target_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513{
1514 int rc = 0;
1515 int connected = 0;
1516 __be16 orig_port = 0;
1517
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001518 if (*csocket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001519 rc = sock_create_kern(PF_INET, SOCK_STREAM,
1520 IPPROTO_TCP, csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001522 cERROR(1, ("Error %d creating socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 *csocket = NULL;
1524 return rc;
1525 } else {
1526 /* BB other socket options to set KEEPALIVE, NODELAY? */
Steve French467a8f82007-06-27 22:41:32 +00001527 cFYI(1, ("Socket created"));
Steve French50c2f752007-07-13 00:33:32 +00001528 (*csocket)->sk->sk_allocation = GFP_NOFS;
Jeff Layton09e50d52008-07-23 10:11:19 -04001529 cifs_reclassify_socket4(*csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 }
1531 }
1532
1533 psin_server->sin_family = AF_INET;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001534 if (psin_server->sin_port) { /* user overrode default port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 rc = (*csocket)->ops->connect(*csocket,
1536 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001537 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 if (rc >= 0)
1539 connected = 1;
Steve French50c2f752007-07-13 00:33:32 +00001540 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001542 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001543 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 later if fall back ports fail this time */
1545 orig_port = psin_server->sin_port;
1546
1547 /* do not retry on the same port we just failed on */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001548 if (psin_server->sin_port != htons(CIFS_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 psin_server->sin_port = htons(CIFS_PORT);
1550
1551 rc = (*csocket)->ops->connect(*csocket,
1552 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001553 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 if (rc >= 0)
1555 connected = 1;
1556 }
1557 }
1558 if (!connected) {
1559 psin_server->sin_port = htons(RFC1001_PORT);
1560 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
Steve French50c2f752007-07-13 00:33:32 +00001561 psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001562 sizeof(struct sockaddr_in), 0);
Steve French50c2f752007-07-13 00:33:32 +00001563 if (rc >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 connected = 1;
1565 }
1566
1567 /* give up here - unless we want to retry on different
1568 protocol families some day */
1569 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001570 if (orig_port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 psin_server->sin_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001572 cFYI(1, ("Error %d connecting to server via ipv4", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 sock_release(*csocket);
1574 *csocket = NULL;
1575 return rc;
1576 }
Steve French50c2f752007-07-13 00:33:32 +00001577 /* Eventually check for other socket options to change from
1578 the default. sock_setsockopt not used because it expects
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 user space buffer */
Steve French50c2f752007-07-13 00:33:32 +00001580 cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",
1581 (*csocket)->sk->sk_sndbuf,
Steve Frenchb387eae2005-10-10 14:21:15 -07001582 (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchb387eae2005-10-10 14:21:15 -07001584 /* make the bufsizes depend on wsize/rsize and max requests */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001585 if ((*csocket)->sk->sk_sndbuf < (200 * 1024))
Steve Frenchb387eae2005-10-10 14:21:15 -07001586 (*csocket)->sk->sk_sndbuf = 200 * 1024;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001587 if ((*csocket)->sk->sk_rcvbuf < (140 * 1024))
Steve Frenchb387eae2005-10-10 14:21:15 -07001588 (*csocket)->sk->sk_rcvbuf = 140 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589
1590 /* send RFC1001 sessinit */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001591 if (psin_server->sin_port == htons(RFC1001_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 /* some servers require RFC1001 sessinit before sending
Steve French50c2f752007-07-13 00:33:32 +00001593 negprot - BB check reconnection in case where second
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 sessinit is sent but no second negprot */
Steve French50c2f752007-07-13 00:33:32 +00001595 struct rfc1002_session_packet *ses_init_buf;
1596 struct smb_hdr *smb_buf;
1597 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
1598 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001599 if (ses_init_buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 ses_init_buf->trailer.session_req.called_len = 32;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001601 if (target_name && (target_name[0] != 0)) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001602 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1603 target_name, 16);
1604 } else {
1605 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
Steve French50c2f752007-07-13 00:33:32 +00001606 DEFAULT_CIFS_CALLED_NAME, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001607 }
1608
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 ses_init_buf->trailer.session_req.calling_len = 32;
1610 /* calling name ends in null (byte 16) from old smb
1611 convention. */
Steve French50c2f752007-07-13 00:33:32 +00001612 if (netbios_name && (netbios_name[0] != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
Steve French50c2f752007-07-13 00:33:32 +00001614 netbios_name, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 } else {
1616 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
Steve French50c2f752007-07-13 00:33:32 +00001617 "LINUX_CIFS_CLNT", 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 }
1619 ses_init_buf->trailer.session_req.scope1 = 0;
1620 ses_init_buf->trailer.session_req.scope2 = 0;
1621 smb_buf = (struct smb_hdr *)ses_init_buf;
1622 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1623 smb_buf->smb_buf_length = 0x81000044;
1624 rc = smb_send(*csocket, smb_buf, 0x44,
1625 (struct sockaddr *)psin_server);
1626 kfree(ses_init_buf);
Steve French50c2f752007-07-13 00:33:32 +00001627 msleep(1); /* RFC1001 layer in at least one server
Steve French083d3a22006-03-03 09:53:36 +00001628 requires very short break before negprot
1629 presumably because not expecting negprot
1630 to follow so fast. This is a simple
Steve French50c2f752007-07-13 00:33:32 +00001631 solution that works without
Steve French083d3a22006-03-03 09:53:36 +00001632 complicating the code and causes no
1633 significant slowing down on mount
1634 for everyone else */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 }
Steve French50c2f752007-07-13 00:33:32 +00001636 /* else the negprot may still work without this
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 even though malloc failed */
Steve French50c2f752007-07-13 00:33:32 +00001638
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 }
Steve French50c2f752007-07-13 00:33:32 +00001640
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 return rc;
1642}
1643
1644static int
1645ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1646{
1647 int rc = 0;
1648 int connected = 0;
1649 __be16 orig_port = 0;
1650
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001651 if (*csocket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001652 rc = sock_create_kern(PF_INET6, SOCK_STREAM,
1653 IPPROTO_TCP, csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001655 cERROR(1, ("Error %d creating ipv6 socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 *csocket = NULL;
1657 return rc;
1658 } else {
1659 /* BB other socket options to set KEEPALIVE, NODELAY? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001660 cFYI(1, ("ipv6 Socket created"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661 (*csocket)->sk->sk_allocation = GFP_NOFS;
Jeff Layton09e50d52008-07-23 10:11:19 -04001662 cifs_reclassify_socket6(*csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 }
1664 }
1665
1666 psin_server->sin6_family = AF_INET6;
1667
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001668 if (psin_server->sin6_port) { /* user overrode default port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 rc = (*csocket)->ops->connect(*csocket,
1670 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001671 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 if (rc >= 0)
1673 connected = 1;
Steve French50c2f752007-07-13 00:33:32 +00001674 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001676 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001677 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 later if fall back ports fail this time */
1679
1680 orig_port = psin_server->sin6_port;
1681 /* do not retry on the same port we just failed on */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001682 if (psin_server->sin6_port != htons(CIFS_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 psin_server->sin6_port = htons(CIFS_PORT);
1684
1685 rc = (*csocket)->ops->connect(*csocket,
1686 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001687 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688 if (rc >= 0)
1689 connected = 1;
1690 }
1691 }
1692 if (!connected) {
1693 psin_server->sin6_port = htons(RFC1001_PORT);
1694 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001695 psin_server, sizeof(struct sockaddr_in6), 0);
Steve French50c2f752007-07-13 00:33:32 +00001696 if (rc >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 connected = 1;
1698 }
1699
1700 /* give up here - unless we want to retry on different
1701 protocol families some day */
1702 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001703 if (orig_port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 psin_server->sin6_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001705 cFYI(1, ("Error %d connecting to server via ipv6", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 sock_release(*csocket);
1707 *csocket = NULL;
1708 return rc;
1709 }
Steve French50c2f752007-07-13 00:33:32 +00001710 /* Eventually check for other socket options to change from
1711 the default. sock_setsockopt not used because it expects
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 user space buffer */
1713 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve French50c2f752007-07-13 00:33:32 +00001714
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 return rc;
1716}
1717
Steve French50c2f752007-07-13 00:33:32 +00001718void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
1719 struct super_block *sb, struct smb_vol *vol_info)
Steve French8af18972007-02-14 04:42:51 +00001720{
1721 /* if we are reconnecting then should we check to see if
1722 * any requested capabilities changed locally e.g. via
1723 * remount but we can not do much about it here
1724 * if they have (even if we could detect it by the following)
1725 * Perhaps we could add a backpointer to array of sb from tcon
1726 * or if we change to make all sb to same share the same
1727 * sb as NFS - then we only have one backpointer to sb.
1728 * What if we wanted to mount the server share twice once with
1729 * and once without posixacls or posix paths? */
1730 __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001731
Steve Frenchc18c8422007-07-18 23:21:09 +00001732 if (vol_info && vol_info->no_linux_ext) {
1733 tcon->fsUnixInfo.Capability = 0;
1734 tcon->unix_ext = 0; /* Unix Extensions disabled */
1735 cFYI(1, ("Linux protocol extensions disabled"));
1736 return;
1737 } else if (vol_info)
1738 tcon->unix_ext = 1; /* Unix Extensions supported */
1739
1740 if (tcon->unix_ext == 0) {
1741 cFYI(1, ("Unix extensions disabled so not set on reconnect"));
1742 return;
1743 }
Steve French50c2f752007-07-13 00:33:32 +00001744
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001745 if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
Steve French8af18972007-02-14 04:42:51 +00001746 __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001747
Steve French8af18972007-02-14 04:42:51 +00001748 /* check for reconnect case in which we do not
1749 want to change the mount behavior if we can avoid it */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001750 if (vol_info == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001751 /* turn off POSIX ACL and PATHNAMES if not set
Steve French8af18972007-02-14 04:42:51 +00001752 originally at mount time */
1753 if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
1754 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00001755 if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
1756 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
1757 cERROR(1, ("POSIXPATH support change"));
Steve French8af18972007-02-14 04:42:51 +00001758 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00001759 } else if ((cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
1760 cERROR(1, ("possible reconnect error"));
1761 cERROR(1,
1762 ("server disabled POSIX path support"));
1763 }
Steve French8af18972007-02-14 04:42:51 +00001764 }
Steve French50c2f752007-07-13 00:33:32 +00001765
Steve French8af18972007-02-14 04:42:51 +00001766 cap &= CIFS_UNIX_CAP_MASK;
Steve French75865f8c2007-06-24 18:30:48 +00001767 if (vol_info && vol_info->no_psx_acl)
Steve French8af18972007-02-14 04:42:51 +00001768 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00001769 else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001770 cFYI(1, ("negotiated posix acl support"));
1771 if (sb)
Steve French8af18972007-02-14 04:42:51 +00001772 sb->s_flags |= MS_POSIXACL;
1773 }
1774
Steve French75865f8c2007-06-24 18:30:48 +00001775 if (vol_info && vol_info->posix_paths == 0)
Steve French8af18972007-02-14 04:42:51 +00001776 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00001777 else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001778 cFYI(1, ("negotiate posix pathnames"));
Steve French75865f8c2007-06-24 18:30:48 +00001779 if (sb)
Steve French50c2f752007-07-13 00:33:32 +00001780 CIFS_SB(sb)->mnt_cifs_flags |=
Steve French8af18972007-02-14 04:42:51 +00001781 CIFS_MOUNT_POSIX_PATHS;
1782 }
Steve French50c2f752007-07-13 00:33:32 +00001783
Steve French984acfe2007-04-26 16:42:50 +00001784 /* We might be setting the path sep back to a different
1785 form if we are reconnecting and the server switched its
Steve French50c2f752007-07-13 00:33:32 +00001786 posix path capability for this share */
Steve French75865f8c2007-06-24 18:30:48 +00001787 if (sb && (CIFS_SB(sb)->prepathlen > 0))
Steve French984acfe2007-04-26 16:42:50 +00001788 CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
Steve French75865f8c2007-06-24 18:30:48 +00001789
1790 if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
1791 if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
1792 CIFS_SB(sb)->rsize = 127 * 1024;
Steve French90c81e02008-02-12 20:32:36 +00001793 cFYI(DBG2,
1794 ("larger reads not supported by srv"));
Steve French75865f8c2007-06-24 18:30:48 +00001795 }
1796 }
Steve French50c2f752007-07-13 00:33:32 +00001797
1798
1799 cFYI(1, ("Negotiate caps 0x%x", (int)cap));
Steve French8af18972007-02-14 04:42:51 +00001800#ifdef CONFIG_CIFS_DEBUG2
Steve French75865f8c2007-06-24 18:30:48 +00001801 if (cap & CIFS_UNIX_FCNTL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001802 cFYI(1, ("FCNTL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001803 if (cap & CIFS_UNIX_EXTATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001804 cFYI(1, ("EXTATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001805 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001806 cFYI(1, ("POSIX path cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001807 if (cap & CIFS_UNIX_XATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001808 cFYI(1, ("XATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001809 if (cap & CIFS_UNIX_POSIX_ACL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001810 cFYI(1, ("POSIX ACL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001811 if (cap & CIFS_UNIX_LARGE_READ_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001812 cFYI(1, ("very large read cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001813 if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001814 cFYI(1, ("very large write cap"));
Steve French8af18972007-02-14 04:42:51 +00001815#endif /* CIFS_DEBUG2 */
1816 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
Steve French442aa312007-09-24 20:25:46 +00001817 if (vol_info == NULL) {
Steve French5a44b312007-09-20 15:16:24 +00001818 cFYI(1, ("resetting capabilities failed"));
Steve French442aa312007-09-24 20:25:46 +00001819 } else
Steve French5a44b312007-09-20 15:16:24 +00001820 cERROR(1, ("Negotiating Unix capabilities "
1821 "with the server failed. Consider "
1822 "mounting with the Unix Extensions\n"
1823 "disabled, if problems are found, "
1824 "by specifying the nounix mount "
Steve French2224f4e2007-09-20 15:37:29 +00001825 "option."));
Steve French5a44b312007-09-20 15:16:24 +00001826
Steve French8af18972007-02-14 04:42:51 +00001827 }
1828 }
1829}
1830
Steve French03a143c2008-02-14 06:38:30 +00001831static void
1832convert_delimiter(char *path, char delim)
1833{
1834 int i;
Steve Frenchc2d68ea2008-02-15 19:20:18 +00001835 char old_delim;
Steve French03a143c2008-02-14 06:38:30 +00001836
1837 if (path == NULL)
1838 return;
1839
Steve French582d21e2008-05-13 04:54:12 +00001840 if (delim == '/')
Steve Frenchc2d68ea2008-02-15 19:20:18 +00001841 old_delim = '\\';
1842 else
1843 old_delim = '/';
1844
Steve French03a143c2008-02-14 06:38:30 +00001845 for (i = 0; path[i] != '\0'; i++) {
Steve Frenchc2d68ea2008-02-15 19:20:18 +00001846 if (path[i] == old_delim)
Steve French03a143c2008-02-14 06:38:30 +00001847 path[i] = delim;
1848 }
1849}
1850
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851int
1852cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1853 char *mount_data, const char *devname)
1854{
1855 int rc = 0;
1856 int xid;
1857 int address_type = AF_INET;
1858 struct socket *csocket = NULL;
1859 struct sockaddr_in sin_server;
1860 struct sockaddr_in6 sin_server6;
1861 struct smb_vol volume_info;
1862 struct cifsSesInfo *pSesInfo = NULL;
1863 struct cifsSesInfo *existingCifsSes = NULL;
1864 struct cifsTconInfo *tcon = NULL;
1865 struct TCP_Server_Info *srvTcp = NULL;
1866
1867 xid = GetXid();
1868
1869/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
Steve French50c2f752007-07-13 00:33:32 +00001870
1871 memset(&volume_info, 0, sizeof(struct smb_vol));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001873 rc = -EINVAL;
1874 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 }
1876
Jeff Layton8426c392007-05-05 03:27:49 +00001877 if (volume_info.nullauth) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001878 cFYI(1, ("null user"));
Jeff Layton9b8f5f52007-11-09 23:25:04 +00001879 volume_info.username = "";
Jeff Layton8426c392007-05-05 03:27:49 +00001880 } else if (volume_info.username) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 /* BB fixme parse for domain name here */
Steve French467a8f82007-06-27 22:41:32 +00001882 cFYI(1, ("Username: %s", volume_info.username));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 } else {
Steve Frenchbf820672005-12-01 22:32:42 -08001884 cifserror("No username specified");
Steve French50c2f752007-07-13 00:33:32 +00001885 /* In userspace mount helper we can get user name from alternate
1886 locations such as env variables and files on disk */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001887 rc = -EINVAL;
1888 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 }
1890
1891 if (volume_info.UNCip && volume_info.UNC) {
Steve French50c2f752007-07-13 00:33:32 +00001892 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,
1893 &sin_server.sin_addr.s_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001895 if (rc <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 /* not ipv4 address, try ipv6 */
Steve French50c2f752007-07-13 00:33:32 +00001897 rc = cifs_inet_pton(AF_INET6, volume_info.UNCip,
1898 &sin_server6.sin6_addr.in6_u);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001899 if (rc > 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900 address_type = AF_INET6;
1901 } else {
1902 address_type = AF_INET;
1903 }
Steve French50c2f752007-07-13 00:33:32 +00001904
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001905 if (rc <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 /* we failed translating address */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001907 rc = -EINVAL;
1908 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 }
1910
1911 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1912 /* success */
1913 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00001914 } else if (volume_info.UNCip) {
1915 /* BB using ip addr as server name to connect to the
1916 DFS root below */
1917 cERROR(1, ("Connecting to DFS root not implemented yet"));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001918 rc = -EINVAL;
1919 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 } else /* which servers DFS root would we conect to */ {
1921 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00001922 ("CIFS mount error: No UNC path (e.g. -o "
1923 "unc=//192.168.1.100/public) specified"));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001924 rc = -EINVAL;
1925 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 }
1927
1928 /* this is needed for ASCII cp to Unicode converts */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001929 if (volume_info.iocharset == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 cifs_sb->local_nls = load_nls_default();
1931 /* load_nls_default can not return null */
1932 } else {
1933 cifs_sb->local_nls = load_nls(volume_info.iocharset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001934 if (cifs_sb->local_nls == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001935 cERROR(1, ("CIFS mount error: iocharset %s not found",
1936 volume_info.iocharset));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001937 rc = -ELIBACC;
1938 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 }
1940 }
1941
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001942 if (address_type == AF_INET)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1944 NULL /* no ipv6 addr */,
1945 volume_info.username, &srvTcp);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001946 else if (address_type == AF_INET6) {
1947 cFYI(1, ("looking for ipv6 address"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1949 &sin_server6.sin6_addr,
1950 volume_info.username, &srvTcp);
Steve French5858ae42007-04-25 11:59:10 +00001951 } else {
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001952 rc = -EINVAL;
1953 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 }
1955
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 if (srvTcp) {
Steve French50c2f752007-07-13 00:33:32 +00001957 cFYI(1, ("Existing tcp session with server found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 } else { /* create socket */
Steve French4523cc32007-04-30 20:13:06 +00001959 if (volume_info.port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 sin_server.sin_port = htons(volume_info.port);
1961 else
1962 sin_server.sin_port = 0;
Steve French5858ae42007-04-25 11:59:10 +00001963 if (address_type == AF_INET6) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001964 cFYI(1, ("attempting ipv6 connect"));
Steve French5858ae42007-04-25 11:59:10 +00001965 /* BB should we allow ipv6 on port 139? */
1966 /* other OS never observed in Wild doing 139 with v6 */
Steve French50c2f752007-07-13 00:33:32 +00001967 rc = ipv6_connect(&sin_server6, &csocket);
1968 } else
1969 rc = ipv4_connect(&sin_server, &csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -07001970 volume_info.source_rfc1001_name,
1971 volume_info.target_rfc1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001973 cERROR(1, ("Error connecting to IPv4 socket. "
1974 "Aborting operation"));
Steve French4523cc32007-04-30 20:13:06 +00001975 if (csocket != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 sock_release(csocket);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001977 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978 }
1979
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00001980 srvTcp = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
1981 if (!srvTcp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 rc = -ENOMEM;
1983 sock_release(csocket);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001984 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 } else {
Steve French50c2f752007-07-13 00:33:32 +00001986 memcpy(&srvTcp->addr.sockAddr, &sin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001987 sizeof(struct sockaddr_in));
Steve French50c2f752007-07-13 00:33:32 +00001988 atomic_set(&srvTcp->inFlight, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989 /* BB Add code for ipv6 case too */
1990 srvTcp->ssocket = csocket;
1991 srvTcp->protocolType = IPV4;
Jeff Laytonc359cf32007-11-16 22:22:06 +00001992 srvTcp->hostname = extract_hostname(volume_info.UNC);
1993 if (IS_ERR(srvTcp->hostname)) {
1994 rc = PTR_ERR(srvTcp->hostname);
1995 sock_release(csocket);
1996 goto out;
1997 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 init_waitqueue_head(&srvTcp->response_q);
1999 init_waitqueue_head(&srvTcp->request_q);
2000 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
2001 /* at this point we are the only ones with the pointer
2002 to the struct since the kernel thread not created yet
2003 so no need to spinlock this init of tcpStatus */
2004 srvTcp->tcpStatus = CifsNew;
2005 init_MUTEX(&srvTcp->tcpSem);
Igor Mammedovaaf737a2007-04-03 19:16:43 +00002006 srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd");
Steve French8840dee2007-11-16 23:05:52 +00002007 if (IS_ERR(srvTcp->tsk)) {
Igor Mammedovaaf737a2007-04-03 19:16:43 +00002008 rc = PTR_ERR(srvTcp->tsk);
Steve French50c2f752007-07-13 00:33:32 +00002009 cERROR(1, ("error %d create cifsd thread", rc));
Igor Mammedovaaf737a2007-04-03 19:16:43 +00002010 srvTcp->tsk = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 sock_release(csocket);
Jeff Laytonc359cf32007-11-16 22:22:06 +00002012 kfree(srvTcp->hostname);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002013 goto out;
Steve Frenchf1914012005-08-18 09:37:34 -07002014 }
Steve Frenchf1914012005-08-18 09:37:34 -07002015 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002016 memcpy(srvTcp->workstation_RFC1001_name,
2017 volume_info.source_rfc1001_name, 16);
2018 memcpy(srvTcp->server_RFC1001_name,
2019 volume_info.target_rfc1001_name, 16);
Steve Frenchad009ac2005-04-28 22:41:05 -07002020 srvTcp->sequence_number = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021 }
2022 }
2023
2024 if (existingCifsSes) {
2025 pSesInfo = existingCifsSes;
Jeff Layton1d9a8852007-12-31 01:37:11 +00002026 cFYI(1, ("Existing smb sess found (status=%d)",
2027 pSesInfo->status));
Steve French88e7d702008-01-03 17:37:09 +00002028 down(&pSesInfo->sesSem);
Jeff Layton1d9a8852007-12-31 01:37:11 +00002029 if (pSesInfo->status == CifsNeedReconnect) {
2030 cFYI(1, ("Session needs reconnect"));
Jeff Layton1d9a8852007-12-31 01:37:11 +00002031 rc = cifs_setup_session(xid, pSesInfo,
2032 cifs_sb->local_nls);
Jeff Layton1d9a8852007-12-31 01:37:11 +00002033 }
Steve French88e7d702008-01-03 17:37:09 +00002034 up(&pSesInfo->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035 } else if (!rc) {
Steve Frenchbf820672005-12-01 22:32:42 -08002036 cFYI(1, ("Existing smb sess not found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 pSesInfo = sesInfoAlloc();
2038 if (pSesInfo == NULL)
2039 rc = -ENOMEM;
2040 else {
2041 pSesInfo->server = srvTcp;
2042 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
2043 NIPQUAD(sin_server.sin_addr.s_addr));
2044 }
2045
Steve French50c2f752007-07-13 00:33:32 +00002046 if (!rc) {
2047 /* volume_info.password freed at unmount */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002048 if (volume_info.password) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 pSesInfo->password = volume_info.password;
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002050 /* set to NULL to prevent freeing on exit */
2051 volume_info.password = NULL;
2052 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053 if (volume_info.username)
2054 strncpy(pSesInfo->userName,
Steve French50c2f752007-07-13 00:33:32 +00002055 volume_info.username,
2056 MAX_USERNAME_SIZE);
Steve French39798772006-05-31 22:40:51 +00002057 if (volume_info.domainname) {
2058 int len = strlen(volume_info.domainname);
Steve French50c2f752007-07-13 00:33:32 +00002059 pSesInfo->domainName =
Steve French39798772006-05-31 22:40:51 +00002060 kmalloc(len + 1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00002061 if (pSesInfo->domainName)
Steve French39798772006-05-31 22:40:51 +00002062 strcpy(pSesInfo->domainName,
2063 volume_info.domainname);
2064 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065 pSesInfo->linux_uid = volume_info.linux_uid;
Steve French750d1152006-06-27 06:28:30 +00002066 pSesInfo->overrideSecFlg = volume_info.secFlg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067 down(&pSesInfo->sesSem);
Steve French189acaa2006-06-23 02:33:48 +00002068 /* BB FIXME need to pass vol->secFlgs BB */
Steve French50c2f752007-07-13 00:33:32 +00002069 rc = cifs_setup_session(xid, pSesInfo,
2070 cifs_sb->local_nls);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071 up(&pSesInfo->sesSem);
Steve French4523cc32007-04-30 20:13:06 +00002072 if (!rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073 atomic_inc(&srvTcp->socketUseCount);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002074 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075 }
Steve French50c2f752007-07-13 00:33:32 +00002076
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077 /* search for existing tcon to this server share */
2078 if (!rc) {
Steve French4523cc32007-04-30 20:13:06 +00002079 if (volume_info.rsize > CIFSMaxBufSize) {
Steve French50c2f752007-07-13 00:33:32 +00002080 cERROR(1, ("rsize %d too large, using MaxBufSize",
Steve French0ae0efa2005-10-10 10:57:19 -07002081 volume_info.rsize));
2082 cifs_sb->rsize = CIFSMaxBufSize;
Steve French75865f8c2007-06-24 18:30:48 +00002083 } else if ((volume_info.rsize) &&
2084 (volume_info.rsize <= CIFSMaxBufSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 cifs_sb->rsize = volume_info.rsize;
Steve French0ae0efa2005-10-10 10:57:19 -07002086 else /* default */
2087 cifs_sb->rsize = CIFSMaxBufSize;
2088
Steve French4523cc32007-04-30 20:13:06 +00002089 if (volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
Steve French50c2f752007-07-13 00:33:32 +00002090 cERROR(1, ("wsize %d too large, using 4096 instead",
Steve French0ae0efa2005-10-10 10:57:19 -07002091 volume_info.wsize));
2092 cifs_sb->wsize = 4096;
Steve French4523cc32007-04-30 20:13:06 +00002093 } else if (volume_info.wsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 cifs_sb->wsize = volume_info.wsize;
2095 else
Steve French50c2f752007-07-13 00:33:32 +00002096 cifs_sb->wsize =
Steve French1877c9e2006-01-27 18:36:11 -08002097 min_t(const int, PAGEVEC_SIZE * PAGE_CACHE_SIZE,
2098 127*1024);
Steve French17cbbaf2006-01-24 20:26:48 -08002099 /* old default of CIFSMaxBufSize was too small now
Steve French50c2f752007-07-13 00:33:32 +00002100 that SMB Write2 can send multiple pages in kvec.
Steve French17cbbaf2006-01-24 20:26:48 -08002101 RFC1001 does not describe what happens when frame
2102 bigger than 128K is sent so use that as max in
2103 conjunction with 52K kvec constraint on arch with 4K
2104 page size */
2105
Steve French4523cc32007-04-30 20:13:06 +00002106 if (cifs_sb->rsize < 2048) {
Steve French50c2f752007-07-13 00:33:32 +00002107 cifs_sb->rsize = 2048;
Steve French6cec2ae2006-02-22 17:31:52 -06002108 /* Windows ME may prefer this */
Steve French467a8f82007-06-27 22:41:32 +00002109 cFYI(1, ("readsize set to minimum: 2048"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 }
Steve French2fe87f02006-09-21 07:02:52 +00002111 /* calculate prepath */
2112 cifs_sb->prepath = volume_info.prepath;
Steve French4523cc32007-04-30 20:13:06 +00002113 if (cifs_sb->prepath) {
Steve French2fe87f02006-09-21 07:02:52 +00002114 cifs_sb->prepathlen = strlen(cifs_sb->prepath);
Steve French03a143c2008-02-14 06:38:30 +00002115 /* we can not convert the / to \ in the path
2116 separators in the prefixpath yet because we do not
2117 know (until reset_cifs_unix_caps is called later)
2118 whether POSIX PATH CAP is available. We normalize
2119 the / to \ after reset_cifs_unix_caps is called */
Steve French2fe87f02006-09-21 07:02:52 +00002120 volume_info.prepath = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002121 } else
Steve French2fe87f02006-09-21 07:02:52 +00002122 cifs_sb->prepathlen = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123 cifs_sb->mnt_uid = volume_info.linux_uid;
2124 cifs_sb->mnt_gid = volume_info.linux_gid;
2125 cifs_sb->mnt_file_mode = volume_info.file_mode;
2126 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
Steve French467a8f82007-06-27 22:41:32 +00002127 cFYI(1, ("file mode: 0x%x dir mode: 0x%x",
2128 cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129
Steve French4523cc32007-04-30 20:13:06 +00002130 if (volume_info.noperm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
Steve French4523cc32007-04-30 20:13:06 +00002132 if (volume_info.setuids)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
Steve French4523cc32007-04-30 20:13:06 +00002134 if (volume_info.server_ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
Steve French4523cc32007-04-30 20:13:06 +00002136 if (volume_info.remap)
Steve French6a0b4822005-04-28 22:41:05 -07002137 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
Steve French4523cc32007-04-30 20:13:06 +00002138 if (volume_info.no_xattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
Steve French4523cc32007-04-30 20:13:06 +00002140 if (volume_info.sfu_emul)
Steve Frenchd7245c22005-07-14 18:25:12 -05002141 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
Steve French4523cc32007-04-30 20:13:06 +00002142 if (volume_info.nobrl)
Steve Frenchc46fa8a2005-08-18 20:49:57 -07002143 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Steve French4523cc32007-04-30 20:13:06 +00002144 if (volume_info.cifs_acl)
Steve French0a4b92c2006-01-12 15:44:21 -08002145 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
Steve French4523cc32007-04-30 20:13:06 +00002146 if (volume_info.override_uid)
2147 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
2148 if (volume_info.override_gid)
2149 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
Jeff Laytond0a9c072008-05-12 22:23:49 +00002150 if (volume_info.dynperm)
2151 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
Steve French4523cc32007-04-30 20:13:06 +00002152 if (volume_info.direct_io) {
Steve French467a8f82007-06-27 22:41:32 +00002153 cFYI(1, ("mounting share using direct i/o"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
2155 }
2156
Steve French27adb442008-05-23 19:43:29 +00002157 if ((volume_info.cifs_acl) && (volume_info.dynperm))
2158 cERROR(1, ("mount option dynperm ignored if cifsacl "
2159 "mount option supported"));
2160
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161 tcon =
2162 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
2163 volume_info.username);
2164 if (tcon) {
Steve Frenchbf820672005-12-01 22:32:42 -08002165 cFYI(1, ("Found match on UNC path"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 /* we can have only one retry value for a connection
2167 to a share so for resources mounted more than once
Steve French50c2f752007-07-13 00:33:32 +00002168 to the same server share the last value passed in
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169 for the retry flag is used */
2170 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07002171 tcon->nocase = volume_info.nocase;
Steve French95b1cb92008-05-15 16:44:38 +00002172 if (tcon->seal != volume_info.seal)
2173 cERROR(1, ("transport encryption setting "
2174 "conflicts with existing tid"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 } else {
2176 tcon = tconInfoAlloc();
2177 if (tcon == NULL)
2178 rc = -ENOMEM;
2179 else {
Steve French50c2f752007-07-13 00:33:32 +00002180 /* check for null share name ie connecting to
Steve French8af18972007-02-14 04:42:51 +00002181 * dfs root */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182
Steve French50c2f752007-07-13 00:33:32 +00002183 /* BB check if this works for exactly length
Steve French8af18972007-02-14 04:42:51 +00002184 * three strings */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
2186 && (strchr(volume_info.UNC + 3, '/') ==
2187 NULL)) {
Steve French646dd532008-05-15 01:50:56 +00002188/* rc = connect_to_dfs_path(xid, pSesInfo,
Steve French8af18972007-02-14 04:42:51 +00002189 "", cifs_sb->local_nls,
Steve French50c2f752007-07-13 00:33:32 +00002190 cifs_sb->mnt_cifs_flags &
Steve French646dd532008-05-15 01:50:56 +00002191 CIFS_MOUNT_MAP_SPECIAL_CHR);*/
2192 cFYI(1, ("DFS root not supported"));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002193 rc = -ENODEV;
2194 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 } else {
Steve French8af18972007-02-14 04:42:51 +00002196 /* BB Do we need to wrap sesSem around
2197 * this TCon call and Unix SetFS as
2198 * we do on SessSetup and reconnect? */
Steve French50c2f752007-07-13 00:33:32 +00002199 rc = CIFSTCon(xid, pSesInfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 volume_info.UNC,
2201 tcon, cifs_sb->local_nls);
2202 cFYI(1, ("CIFS Tcon rc = %d", rc));
Steve French2c1b8612008-10-16 18:35:21 +00002203 if (volume_info.nodfs) {
2204 tcon->Flags &=
2205 ~SMB_SHARE_IS_IN_DFS;
2206 cFYI(1, ("DFS disabled (%d)",
2207 tcon->Flags));
2208 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209 }
2210 if (!rc) {
2211 atomic_inc(&pSesInfo->inUse);
2212 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07002213 tcon->nocase = volume_info.nocase;
Steve French95b1cb92008-05-15 16:44:38 +00002214 tcon->seal = volume_info.seal;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 }
2216 }
2217 }
2218 }
Steve French4523cc32007-04-30 20:13:06 +00002219 if (pSesInfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
2221 sb->s_maxbytes = (u64) 1 << 63;
2222 } else
2223 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
2224 }
2225
Steve French8af18972007-02-14 04:42:51 +00002226 /* BB FIXME fix time_gran to be larger for LANMAN sessions */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227 sb->s_time_gran = 100;
2228
2229/* on error free sesinfo and tcon struct if needed */
2230 if (rc) {
2231 /* if session setup failed, use count is zero but
2232 we still need to free cifsd thread */
Steve French4523cc32007-04-30 20:13:06 +00002233 if (atomic_read(&srvTcp->socketUseCount) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234 spin_lock(&GlobalMid_Lock);
2235 srvTcp->tcpStatus = CifsExiting;
2236 spin_unlock(&GlobalMid_Lock);
Steve French4523cc32007-04-30 20:13:06 +00002237 if (srvTcp->tsk) {
Steve French28356a12007-05-23 14:45:36 +00002238 /* If we could verify that kthread_stop would
2239 always wake up processes blocked in
2240 tcp in recv_mesg then we could remove the
2241 send_sig call */
Steve French50c2f752007-07-13 00:33:32 +00002242 force_sig(SIGKILL, srvTcp->tsk);
Steve Frenche691b9d2008-05-11 15:53:33 +00002243 kthread_stop(srvTcp->tsk);
Steve Frenchf1914012005-08-18 09:37:34 -07002244 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245 }
2246 /* If find_unc succeeded then rc == 0 so we can not end */
2247 if (tcon) /* up accidently freeing someone elses tcon struct */
2248 tconInfoFree(tcon);
2249 if (existingCifsSes == NULL) {
2250 if (pSesInfo) {
Steve French50c2f752007-07-13 00:33:32 +00002251 if ((pSesInfo->server) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 (pSesInfo->status == CifsGood)) {
2253 int temp_rc;
2254 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
2255 /* if the socketUseCount is now zero */
Steve French4523cc32007-04-30 20:13:06 +00002256 if ((temp_rc == -ESHUTDOWN) &&
Steve French50c2f752007-07-13 00:33:32 +00002257 (pSesInfo->server) &&
Jeff5d9c7202007-06-25 22:16:35 +00002258 (pSesInfo->server->tsk)) {
Jeff5d9c7202007-06-25 22:16:35 +00002259 force_sig(SIGKILL,
2260 pSesInfo->server->tsk);
Steve Frenche691b9d2008-05-11 15:53:33 +00002261 kthread_stop(pSesInfo->server->tsk);
Steve Frenchf1914012005-08-18 09:37:34 -07002262 }
Steve Frencha0136892007-10-04 20:05:09 +00002263 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 cFYI(1, ("No session or bad tcon"));
Steve Frencha0136892007-10-04 20:05:09 +00002265 if ((pSesInfo->server) &&
2266 (pSesInfo->server->tsk)) {
Steve Frencha0136892007-10-04 20:05:09 +00002267 force_sig(SIGKILL,
2268 pSesInfo->server->tsk);
Steve Frenche691b9d2008-05-11 15:53:33 +00002269 kthread_stop(pSesInfo->server->tsk);
Steve Frencha0136892007-10-04 20:05:09 +00002270 }
2271 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272 sesInfoFree(pSesInfo);
2273 /* pSesInfo = NULL; */
2274 }
2275 }
2276 } else {
2277 atomic_inc(&tcon->useCount);
2278 cifs_sb->tcon = tcon;
2279 tcon->ses = pSesInfo;
2280
Steve French82940a42006-03-02 03:24:57 +00002281 /* do not care if following two calls succeed - informational */
Steve French7f8ed422007-09-28 22:28:55 +00002282 if (!tcon->ipc) {
2283 CIFSSMBQFSDeviceInfo(xid, tcon);
2284 CIFSSMBQFSAttributeInfo(xid, tcon);
2285 }
Steve French50c2f752007-07-13 00:33:32 +00002286
Steve French8af18972007-02-14 04:42:51 +00002287 /* tell server which Unix caps we support */
2288 if (tcon->ses->capabilities & CAP_UNIX)
Steve Frenchc18c8422007-07-18 23:21:09 +00002289 /* reset of caps checks mount to see if unix extensions
2290 disabled for just this mount */
Steve French8af18972007-02-14 04:42:51 +00002291 reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
Steve Frenchc18c8422007-07-18 23:21:09 +00002292 else
2293 tcon->unix_ext = 0; /* server does not support them */
2294
Steve French03a143c2008-02-14 06:38:30 +00002295 /* convert forward to back slashes in prepath here if needed */
Igor Mammedov11b6d642008-02-15 19:06:04 +00002296 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
2297 convert_delimiter(cifs_sb->prepath,
2298 CIFS_DIR_SEP(cifs_sb));
Steve French03a143c2008-02-14 06:38:30 +00002299
Steve Frenchc18c8422007-07-18 23:21:09 +00002300 if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
Steve French75865f8c2007-06-24 18:30:48 +00002301 cifs_sb->rsize = 1024 * 127;
Steve French90c81e02008-02-12 20:32:36 +00002302 cFYI(DBG2,
2303 ("no very large read support, rsize now 127K"));
Steve French75865f8c2007-06-24 18:30:48 +00002304 }
Steve French3e844692005-10-03 13:37:24 -07002305 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
2306 cifs_sb->wsize = min(cifs_sb->wsize,
2307 (tcon->ses->server->maxBuf -
2308 MAX_CIFS_HDR_SIZE));
Steve French0ae0efa2005-10-10 10:57:19 -07002309 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
Steve French50c2f752007-07-13 00:33:32 +00002310 cifs_sb->rsize = min(cifs_sb->rsize,
2311 (tcon->ses->server->maxBuf -
2312 MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 }
2314
2315 /* volume_info.password is freed above when existing session found
2316 (in which case it is not needed anymore) but when new sesion is created
2317 the password ptr is put in the new session structure (in which case the
2318 password will be freed at unmount time) */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002319out:
2320 /* zero out password before freeing */
2321 if (volume_info.password != NULL) {
2322 memset(volume_info.password, 0, strlen(volume_info.password));
2323 kfree(volume_info.password);
2324 }
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002325 kfree(volume_info.UNC);
Steve French2fe87f02006-09-21 07:02:52 +00002326 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327 FreeXid(xid);
2328 return rc;
2329}
2330
2331static int
2332CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French7c7b25b2006-06-01 19:20:10 +00002333 char session_key[CIFS_SESS_KEY_SIZE],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002334 const struct nls_table *nls_codepage)
2335{
2336 struct smb_hdr *smb_buffer;
2337 struct smb_hdr *smb_buffer_response;
2338 SESSION_SETUP_ANDX *pSMB;
2339 SESSION_SETUP_ANDX *pSMBr;
2340 char *bcc_ptr;
2341 char *user;
2342 char *domain;
2343 int rc = 0;
2344 int remaining_words = 0;
2345 int bytes_returned = 0;
2346 int len;
2347 __u32 capabilities;
2348 __u16 count;
2349
Steve Frencheeac8042006-01-13 21:34:58 -08002350 cFYI(1, ("In sesssetup"));
Steve French4523cc32007-04-30 20:13:06 +00002351 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 return -EINVAL;
2353 user = ses->userName;
2354 domain = ses->domainName;
2355 smb_buffer = cifs_buf_get();
Steve French582d21e2008-05-13 04:54:12 +00002356
2357 if (smb_buffer == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358 return -ENOMEM;
Steve French582d21e2008-05-13 04:54:12 +00002359
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 smb_buffer_response = smb_buffer;
2361 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2362
2363 /* send SMBsessionSetup here */
2364 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2365 NULL /* no tCon exists yet */ , 13 /* wct */ );
2366
Steve French1982c342005-08-17 12:38:22 -07002367 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368 pSMB->req_no_secext.AndXCommand = 0xFF;
2369 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2370 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2371
Steve French50c2f752007-07-13 00:33:32 +00002372 if (ses->server->secMode &
2373 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2375
2376 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2377 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
2378 if (ses->capabilities & CAP_UNICODE) {
2379 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2380 capabilities |= CAP_UNICODE;
2381 }
2382 if (ses->capabilities & CAP_STATUS32) {
2383 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2384 capabilities |= CAP_STATUS32;
2385 }
2386 if (ses->capabilities & CAP_DFS) {
2387 smb_buffer->Flags2 |= SMBFLG2_DFS;
2388 capabilities |= CAP_DFS;
2389 }
2390 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
2391
Steve French50c2f752007-07-13 00:33:32 +00002392 pSMB->req_no_secext.CaseInsensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002393 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394
2395 pSMB->req_no_secext.CaseSensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002396 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397 bcc_ptr = pByteArea(smb_buffer);
Steve French7c7b25b2006-06-01 19:20:10 +00002398 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2399 bcc_ptr += CIFS_SESS_KEY_SIZE;
2400 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2401 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402
2403 if (ses->capabilities & CAP_UNICODE) {
2404 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
2405 *bcc_ptr = 0;
2406 bcc_ptr++;
2407 }
Steve French4523cc32007-04-30 20:13:06 +00002408 if (user == NULL)
Steve French39798772006-05-31 22:40:51 +00002409 bytes_returned = 0; /* skip null user */
Steve French50c2f752007-07-13 00:33:32 +00002410 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 bytes_returned =
Steve French50c2f752007-07-13 00:33:32 +00002412 cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413 nls_codepage);
2414 /* convert number of 16 bit words to bytes */
2415 bcc_ptr += 2 * bytes_returned;
2416 bcc_ptr += 2; /* trailing null */
2417 if (domain == NULL)
2418 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002419 cifs_strtoUCS((__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420 "CIFS_LINUX_DOM", 32, nls_codepage);
2421 else
2422 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002423 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424 nls_codepage);
2425 bcc_ptr += 2 * bytes_returned;
2426 bcc_ptr += 2;
2427 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002428 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429 32, nls_codepage);
2430 bcc_ptr += 2 * bytes_returned;
2431 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002432 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433 32, nls_codepage);
2434 bcc_ptr += 2 * bytes_returned;
2435 bcc_ptr += 2;
2436 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002437 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438 64, nls_codepage);
2439 bcc_ptr += 2 * bytes_returned;
2440 bcc_ptr += 2;
2441 } else {
Steve French50c2f752007-07-13 00:33:32 +00002442 if (user != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 strncpy(bcc_ptr, user, 200);
2444 bcc_ptr += strnlen(user, 200);
2445 }
2446 *bcc_ptr = 0;
2447 bcc_ptr++;
2448 if (domain == NULL) {
2449 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2450 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2451 } else {
2452 strncpy(bcc_ptr, domain, 64);
2453 bcc_ptr += strnlen(domain, 64);
2454 *bcc_ptr = 0;
2455 bcc_ptr++;
2456 }
2457 strcpy(bcc_ptr, "Linux version ");
2458 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002459 strcpy(bcc_ptr, utsname()->release);
2460 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2462 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2463 }
2464 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2465 smb_buffer->smb_buf_length += count;
2466 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2467
2468 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00002469 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470 if (rc) {
2471/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2472 } else if ((smb_buffer_response->WordCount == 3)
2473 || (smb_buffer_response->WordCount == 4)) {
2474 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2475 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2476 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002477 cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */
2478 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format
2479 (little endian) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480 cFYI(1, ("UID = %d ", ses->Suid));
Steve French50c2f752007-07-13 00:33:32 +00002481 /* response can have either 3 or 4 word count - Samba sends 3 */
2482 bcc_ptr = pByteArea(smb_buffer_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483 if ((pSMBr->resp.hdr.WordCount == 3)
2484 || ((pSMBr->resp.hdr.WordCount == 4)
2485 && (blob_len < pSMBr->resp.ByteCount))) {
2486 if (pSMBr->resp.hdr.WordCount == 4)
2487 bcc_ptr += blob_len;
2488
2489 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2490 if ((long) (bcc_ptr) % 2) {
2491 remaining_words =
Steve French50c2f752007-07-13 00:33:32 +00002492 (BCC(smb_buffer_response) - 1) / 2;
2493 /* Unicode strings must be word
2494 aligned */
2495 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 } else {
2497 remaining_words =
2498 BCC(smb_buffer_response) / 2;
2499 }
2500 len =
2501 UniStrnlen((wchar_t *) bcc_ptr,
2502 remaining_words - 1);
2503/* We look for obvious messed up bcc or strings in response so we do not go off
2504 the end since (at least) WIN2K and Windows XP have a major bug in not null
2505 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002506 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002507 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002508 ses->serverOS = kzalloc(2 * (len + 1),
2509 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002510 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002511 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512 cifs_strfromUCS_le(ses->serverOS,
Steve French50c2f752007-07-13 00:33:32 +00002513 (__le16 *)bcc_ptr,
2514 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 bcc_ptr += 2 * (len + 1);
2516 remaining_words -= len + 1;
2517 ses->serverOS[2 * len] = 0;
2518 ses->serverOS[1 + (2 * len)] = 0;
2519 if (remaining_words > 0) {
2520 len = UniStrnlen((wchar_t *)bcc_ptr,
2521 remaining_words-1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002522 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002523 ses->serverNOS = kzalloc(2 * (len + 1),
2524 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002525 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002526 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527 cifs_strfromUCS_le(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002528 (__le16 *)bcc_ptr,
2529 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530 bcc_ptr += 2 * (len + 1);
2531 ses->serverNOS[2 * len] = 0;
2532 ses->serverNOS[1 + (2 * len)] = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002533 if (strncmp(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002534 "NT LAN Manager 4", 16) == 0) {
Steve French467a8f82007-06-27 22:41:32 +00002535 cFYI(1, ("NT4 server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536 ses->flags |= CIFS_SES_NT4;
2537 }
2538 remaining_words -= len + 1;
2539 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002540 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Steve French50c2f752007-07-13 00:33:32 +00002541 /* last string is not always null terminated
2542 (for e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002543 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002544 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545 ses->serverDomain =
Steve French50c2f752007-07-13 00:33:32 +00002546 kzalloc(2*(len+1),
2547 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002548 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002549 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550 cifs_strfromUCS_le(ses->serverDomain,
Steve French50c2f752007-07-13 00:33:32 +00002551 (__le16 *)bcc_ptr,
2552 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553 bcc_ptr += 2 * (len + 1);
2554 ses->serverDomain[2*len] = 0;
2555 ses->serverDomain[1+(2*len)] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002556 } else { /* else no more room so create
2557 dummy domain string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002558 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002559 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002560 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002561 kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002562 }
Steve French50c2f752007-07-13 00:33:32 +00002563 } else { /* no room so create dummy domain
2564 and NOS string */
2565
Steve French433dc242005-04-28 22:41:08 -07002566 /* if these kcallocs fail not much we
2567 can do, but better to not fail the
2568 sesssetup itself */
Steve Frenchcd49b492006-06-26 04:22:36 +00002569 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002571 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002572 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002574 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 }
2576 } else { /* ASCII */
2577 len = strnlen(bcc_ptr, 1024);
2578 if (((long) bcc_ptr + len) - (long)
2579 pByteArea(smb_buffer_response)
2580 <= BCC(smb_buffer_response)) {
Steve Frenchcd49b492006-06-26 04:22:36 +00002581 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002582 ses->serverOS = kzalloc(len + 1,
2583 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002584 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002585 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002586 strncpy(ses->serverOS, bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587
2588 bcc_ptr += len;
Steve French50c2f752007-07-13 00:33:32 +00002589 /* null terminate the string */
2590 bcc_ptr[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 bcc_ptr++;
2592
2593 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002594 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002595 ses->serverNOS = kzalloc(len + 1,
2596 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002597 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002598 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 strncpy(ses->serverNOS, bcc_ptr, len);
2600 bcc_ptr += len;
2601 bcc_ptr[0] = 0;
2602 bcc_ptr++;
2603
2604 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002605 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002606 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002607 ses->serverDomain = kzalloc(len + 1,
2608 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002609 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002610 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002611 strncpy(ses->serverDomain, bcc_ptr,
2612 len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 bcc_ptr += len;
2614 bcc_ptr[0] = 0;
2615 bcc_ptr++;
2616 } else
2617 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00002618 ("Variable field of length %d "
2619 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620 len));
2621 }
2622 } else {
2623 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00002624 (" Security Blob Length extends beyond "
2625 "end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626 }
2627 } else {
2628 cERROR(1,
2629 (" Invalid Word count %d: ",
2630 smb_buffer_response->WordCount));
2631 rc = -EIO;
2632 }
Steve French433dc242005-04-28 22:41:08 -07002633sesssetup_nomem: /* do not return an error on nomem for the info strings,
2634 since that could make reconnection harder, and
2635 reconnection might be needed to free memory */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00002636 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637
2638 return rc;
2639}
2640
2641static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
Steve French4b18f2a2008-04-29 00:06:05 +00002643 struct cifsSesInfo *ses, bool *pNTLMv2_flag,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 const struct nls_table *nls_codepage)
2645{
2646 struct smb_hdr *smb_buffer;
2647 struct smb_hdr *smb_buffer_response;
2648 SESSION_SETUP_ANDX *pSMB;
2649 SESSION_SETUP_ANDX *pSMBr;
2650 char *bcc_ptr;
2651 char *domain;
2652 int rc = 0;
2653 int remaining_words = 0;
2654 int bytes_returned = 0;
2655 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002656 int SecurityBlobLength = sizeof(NEGOTIATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 PNEGOTIATE_MESSAGE SecurityBlob;
2658 PCHALLENGE_MESSAGE SecurityBlob2;
2659 __u32 negotiate_flags, capabilities;
2660 __u16 count;
2661
Steve French12b3b8f2006-02-09 21:12:47 +00002662 cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002663 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 return -EINVAL;
2665 domain = ses->domainName;
Steve French4b18f2a2008-04-29 00:06:05 +00002666 *pNTLMv2_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 smb_buffer = cifs_buf_get();
2668 if (smb_buffer == NULL) {
2669 return -ENOMEM;
2670 }
2671 smb_buffer_response = smb_buffer;
2672 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2673 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2674
2675 /* send SMBsessionSetup here */
2676 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2677 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002678
2679 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2681 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2682
2683 pSMB->req.AndXCommand = 0xFF;
2684 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2685 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2686
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002687 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2689
2690 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2691 CAP_EXTENDED_SECURITY;
2692 if (ses->capabilities & CAP_UNICODE) {
2693 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2694 capabilities |= CAP_UNICODE;
2695 }
2696 if (ses->capabilities & CAP_STATUS32) {
2697 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2698 capabilities |= CAP_STATUS32;
2699 }
2700 if (ses->capabilities & CAP_DFS) {
2701 smb_buffer->Flags2 |= SMBFLG2_DFS;
2702 capabilities |= CAP_DFS;
2703 }
2704 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2705
2706 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2707 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2708 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2709 SecurityBlob->MessageType = NtLmNegotiate;
2710 negotiate_flags =
2711 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
Steve French12b3b8f2006-02-09 21:12:47 +00002712 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
2713 NTLMSSP_NEGOTIATE_56 |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002715 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002717/* if (ntlmv2_support)
Steve French39798772006-05-31 22:40:51 +00002718 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 /* setup pointers to domain name and workstation name */
2720 bcc_ptr += SecurityBlobLength;
2721
2722 SecurityBlob->WorkstationName.Buffer = 0;
2723 SecurityBlob->WorkstationName.Length = 0;
2724 SecurityBlob->WorkstationName.MaximumLength = 0;
2725
Steve French12b3b8f2006-02-09 21:12:47 +00002726 /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent
2727 along with username on auth request (ie the response to challenge) */
2728 SecurityBlob->DomainName.Buffer = 0;
2729 SecurityBlob->DomainName.Length = 0;
2730 SecurityBlob->DomainName.MaximumLength = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731 if (ses->capabilities & CAP_UNICODE) {
2732 if ((long) bcc_ptr % 2) {
2733 *bcc_ptr = 0;
2734 bcc_ptr++;
2735 }
2736
2737 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002738 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 32, nls_codepage);
2740 bcc_ptr += 2 * bytes_returned;
2741 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002742 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 nls_codepage);
2744 bcc_ptr += 2 * bytes_returned;
2745 bcc_ptr += 2; /* null terminate Linux version */
2746 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002747 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 64, nls_codepage);
2749 bcc_ptr += 2 * bytes_returned;
2750 *(bcc_ptr + 1) = 0;
2751 *(bcc_ptr + 2) = 0;
2752 bcc_ptr += 2; /* null terminate network opsys string */
2753 *(bcc_ptr + 1) = 0;
2754 *(bcc_ptr + 2) = 0;
2755 bcc_ptr += 2; /* null domain */
2756 } else { /* ASCII */
2757 strcpy(bcc_ptr, "Linux version ");
2758 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002759 strcpy(bcc_ptr, utsname()->release);
2760 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2762 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2763 bcc_ptr++; /* empty domain field */
2764 *bcc_ptr = 0;
2765 }
2766 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2767 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2768 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2769 smb_buffer->smb_buf_length += count;
2770 pSMB->req.ByteCount = cpu_to_le16(count);
2771
2772 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00002773 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774
2775 if (smb_buffer_response->Status.CifsError ==
2776 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2777 rc = 0;
2778
2779 if (rc) {
2780/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2781 } else if ((smb_buffer_response->WordCount == 3)
2782 || (smb_buffer_response->WordCount == 4)) {
2783 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2784 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2785
2786 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002787 cFYI(1, (" Guest login"));
2788 /* Do we want to set anything in SesInfo struct when guest login? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789
Steve French50c2f752007-07-13 00:33:32 +00002790 bcc_ptr = pByteArea(smb_buffer_response);
2791 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792
2793 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2794 if (SecurityBlob2->MessageType != NtLmChallenge) {
2795 cFYI(1,
2796 ("Unexpected NTLMSSP message type received %d",
2797 SecurityBlob2->MessageType));
2798 } else if (ses) {
Steve French50c2f752007-07-13 00:33:32 +00002799 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
Steve French12b3b8f2006-02-09 21:12:47 +00002800 cFYI(1, ("UID = %d", ses->Suid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801 if ((pSMBr->resp.hdr.WordCount == 3)
2802 || ((pSMBr->resp.hdr.WordCount == 4)
2803 && (blob_len <
2804 pSMBr->resp.ByteCount))) {
2805
2806 if (pSMBr->resp.hdr.WordCount == 4) {
2807 bcc_ptr += blob_len;
Steve French12b3b8f2006-02-09 21:12:47 +00002808 cFYI(1, ("Security Blob Length %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 blob_len));
2810 }
2811
Steve French12b3b8f2006-02-09 21:12:47 +00002812 cFYI(1, ("NTLMSSP Challenge rcvd"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813
2814 memcpy(ses->server->cryptKey,
2815 SecurityBlob2->Challenge,
2816 CIFS_CRYPTO_KEY_SIZE);
Steve French50c2f752007-07-13 00:33:32 +00002817 if (SecurityBlob2->NegotiateFlags &
Steve French12b3b8f2006-02-09 21:12:47 +00002818 cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
Steve French4b18f2a2008-04-29 00:06:05 +00002819 *pNTLMv2_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820
Steve French50c2f752007-07-13 00:33:32 +00002821 if ((SecurityBlob2->NegotiateFlags &
2822 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823 || (sign_CIFS_PDUs > 1))
Steve French50c2f752007-07-13 00:33:32 +00002824 ses->server->secMode |=
2825 SECMODE_SIGN_REQUIRED;
2826 if ((SecurityBlob2->NegotiateFlags &
Linus Torvalds1da177e2005-04-16 15:20:36 -07002827 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
Steve French50c2f752007-07-13 00:33:32 +00002828 ses->server->secMode |=
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829 SECMODE_SIGN_ENABLED;
2830
2831 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2832 if ((long) (bcc_ptr) % 2) {
2833 remaining_words =
2834 (BCC(smb_buffer_response)
2835 - 1) / 2;
Steve French50c2f752007-07-13 00:33:32 +00002836 /* Must word align unicode strings */
2837 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838 } else {
2839 remaining_words =
2840 BCC
2841 (smb_buffer_response) / 2;
2842 }
2843 len =
2844 UniStrnlen((wchar_t *) bcc_ptr,
2845 remaining_words - 1);
2846/* We look for obvious messed up bcc or strings in response so we do not go off
2847 the end since (at least) WIN2K and Windows XP have a major bug in not null
2848 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002849 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002850 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002852 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002854 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 bcc_ptr, len,
2856 nls_codepage);
2857 bcc_ptr += 2 * (len + 1);
2858 remaining_words -= len + 1;
2859 ses->serverOS[2 * len] = 0;
2860 ses->serverOS[1 + (2 * len)] = 0;
2861 if (remaining_words > 0) {
2862 len = UniStrnlen((wchar_t *)
2863 bcc_ptr,
2864 remaining_words
2865 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002866 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002868 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869 GFP_KERNEL);
2870 cifs_strfromUCS_le(ses->
2871 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002872 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873 bcc_ptr,
2874 len,
2875 nls_codepage);
2876 bcc_ptr += 2 * (len + 1);
2877 ses->serverNOS[2 * len] = 0;
2878 ses->serverNOS[1 +
2879 (2 * len)] = 0;
2880 remaining_words -= len + 1;
2881 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00002882 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2883 /* last string not always null terminated
2884 (for e.g. for Windows XP & 2000) */
Steve Frenchcd49b492006-06-26 04:22:36 +00002885 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002887 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888 (len +
2889 1),
2890 GFP_KERNEL);
2891 cifs_strfromUCS_le
Steve Frenche89dc922005-11-11 15:18:19 -08002892 (ses->serverDomain,
2893 (__le16 *)bcc_ptr,
2894 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895 bcc_ptr +=
2896 2 * (len + 1);
Steve Frenche89dc922005-11-11 15:18:19 -08002897 ses->serverDomain[2*len]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898 = 0;
Steve Frenche89dc922005-11-11 15:18:19 -08002899 ses->serverDomain
2900 [1 + (2 * len)]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901 = 0;
2902 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002903 else {
Steve Frenchcd49b492006-06-26 04:22:36 +00002904 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002906 kzalloc(2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907 GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002908 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909 } else { /* no room so create dummy domain and NOS string */
Steve Frenchcd49b492006-06-26 04:22:36 +00002910 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002912 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002913 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002915 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916 }
2917 } else { /* ASCII */
2918 len = strnlen(bcc_ptr, 1024);
2919 if (((long) bcc_ptr + len) - (long)
2920 pByteArea(smb_buffer_response)
2921 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002922 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002923 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002925 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926 GFP_KERNEL);
2927 strncpy(ses->serverOS,
2928 bcc_ptr, len);
2929
2930 bcc_ptr += len;
2931 bcc_ptr[0] = 0; /* null terminate string */
2932 bcc_ptr++;
2933
2934 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002935 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002937 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938 GFP_KERNEL);
2939 strncpy(ses->serverNOS, bcc_ptr, len);
2940 bcc_ptr += len;
2941 bcc_ptr[0] = 0;
2942 bcc_ptr++;
2943
2944 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002945 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002947 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +00002949 strncpy(ses->serverDomain,
2950 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951 bcc_ptr += len;
2952 bcc_ptr[0] = 0;
2953 bcc_ptr++;
2954 } else
2955 cFYI(1,
Steve French63135e02007-07-17 17:34:02 +00002956 ("field of length %d "
2957 "extends beyond end of smb",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958 len));
2959 }
2960 } else {
Steve French50c2f752007-07-13 00:33:32 +00002961 cERROR(1, ("Security Blob Length extends beyond"
2962 " end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963 }
2964 } else {
2965 cERROR(1, ("No session structure passed in."));
2966 }
2967 } else {
2968 cERROR(1,
Steve French5815449d2006-02-14 01:36:20 +00002969 (" Invalid Word count %d:",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 smb_buffer_response->WordCount));
2971 rc = -EIO;
2972 }
2973
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00002974 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975
2976 return rc;
2977}
2978static int
2979CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French4b18f2a2008-04-29 00:06:05 +00002980 char *ntlm_session_key, bool ntlmv2_flag,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002981 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982{
2983 struct smb_hdr *smb_buffer;
2984 struct smb_hdr *smb_buffer_response;
2985 SESSION_SETUP_ANDX *pSMB;
2986 SESSION_SETUP_ANDX *pSMBr;
2987 char *bcc_ptr;
2988 char *user;
2989 char *domain;
2990 int rc = 0;
2991 int remaining_words = 0;
2992 int bytes_returned = 0;
2993 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002994 int SecurityBlobLength = sizeof(AUTHENTICATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995 PAUTHENTICATE_MESSAGE SecurityBlob;
2996 __u32 negotiate_flags, capabilities;
2997 __u16 count;
2998
2999 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003000 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001 return -EINVAL;
3002 user = ses->userName;
3003 domain = ses->domainName;
3004 smb_buffer = cifs_buf_get();
3005 if (smb_buffer == NULL) {
3006 return -ENOMEM;
3007 }
3008 smb_buffer_response = smb_buffer;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003009 pSMB = (SESSION_SETUP_ANDX *)smb_buffer;
3010 pSMBr = (SESSION_SETUP_ANDX *)smb_buffer_response;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011
3012 /* send SMBsessionSetup here */
3013 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
3014 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07003015
3016 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
3018 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
3019 pSMB->req.AndXCommand = 0xFF;
3020 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
3021 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
3022
3023 pSMB->req.hdr.Uid = ses->Suid;
3024
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003025 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3027
3028 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003029 CAP_EXTENDED_SECURITY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030 if (ses->capabilities & CAP_UNICODE) {
3031 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3032 capabilities |= CAP_UNICODE;
3033 }
3034 if (ses->capabilities & CAP_STATUS32) {
3035 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3036 capabilities |= CAP_STATUS32;
3037 }
3038 if (ses->capabilities & CAP_DFS) {
3039 smb_buffer->Flags2 |= SMBFLG2_DFS;
3040 capabilities |= CAP_DFS;
3041 }
3042 pSMB->req.Capabilities = cpu_to_le32(capabilities);
3043
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003044 bcc_ptr = (char *)&pSMB->req.SecurityBlob;
3045 SecurityBlob = (PAUTHENTICATE_MESSAGE)bcc_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
3047 SecurityBlob->MessageType = NtLmAuthenticate;
3048 bcc_ptr += SecurityBlobLength;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003049 negotiate_flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
3050 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
3051 0x80000000 | NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003052 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003054 if (ntlmv2_flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
3056
3057/* setup pointers to domain name and workstation name */
3058
3059 SecurityBlob->WorkstationName.Buffer = 0;
3060 SecurityBlob->WorkstationName.Length = 0;
3061 SecurityBlob->WorkstationName.MaximumLength = 0;
3062 SecurityBlob->SessionKey.Length = 0;
3063 SecurityBlob->SessionKey.MaximumLength = 0;
3064 SecurityBlob->SessionKey.Buffer = 0;
3065
3066 SecurityBlob->LmChallengeResponse.Length = 0;
3067 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
3068 SecurityBlob->LmChallengeResponse.Buffer = 0;
3069
3070 SecurityBlob->NtChallengeResponse.Length =
Steve French7c7b25b2006-06-01 19:20:10 +00003071 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072 SecurityBlob->NtChallengeResponse.MaximumLength =
Steve French7c7b25b2006-06-01 19:20:10 +00003073 cpu_to_le16(CIFS_SESS_KEY_SIZE);
3074 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075 SecurityBlob->NtChallengeResponse.Buffer =
3076 cpu_to_le32(SecurityBlobLength);
Steve French7c7b25b2006-06-01 19:20:10 +00003077 SecurityBlobLength += CIFS_SESS_KEY_SIZE;
3078 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079
3080 if (ses->capabilities & CAP_UNICODE) {
3081 if (domain == NULL) {
3082 SecurityBlob->DomainName.Buffer = 0;
3083 SecurityBlob->DomainName.Length = 0;
3084 SecurityBlob->DomainName.MaximumLength = 0;
3085 } else {
Steve French77159b42007-08-31 01:10:17 +00003086 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00003088 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003090 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091 SecurityBlob->DomainName.Buffer =
3092 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003093 bcc_ptr += ln;
3094 SecurityBlobLength += ln;
3095 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096 }
3097 if (user == NULL) {
3098 SecurityBlob->UserName.Buffer = 0;
3099 SecurityBlob->UserName.Length = 0;
3100 SecurityBlob->UserName.MaximumLength = 0;
3101 } else {
Steve French77159b42007-08-31 01:10:17 +00003102 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00003104 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105 SecurityBlob->UserName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003106 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003107 SecurityBlob->UserName.Buffer =
3108 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003109 bcc_ptr += ln;
3110 SecurityBlobLength += ln;
3111 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112 }
3113
Steve French63135e02007-07-17 17:34:02 +00003114 /* SecurityBlob->WorkstationName.Length =
3115 cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116 SecurityBlob->WorkstationName.Length *= 2;
Steve French63135e02007-07-17 17:34:02 +00003117 SecurityBlob->WorkstationName.MaximumLength =
3118 cpu_to_le16(SecurityBlob->WorkstationName.Length);
3119 SecurityBlob->WorkstationName.Buffer =
3120 cpu_to_le32(SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121 bcc_ptr += SecurityBlob->WorkstationName.Length;
3122 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
Steve French63135e02007-07-17 17:34:02 +00003123 SecurityBlob->WorkstationName.Length =
3124 cpu_to_le16(SecurityBlob->WorkstationName.Length); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125
3126 if ((long) bcc_ptr % 2) {
3127 *bcc_ptr = 0;
3128 bcc_ptr++;
3129 }
3130 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003131 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 32, nls_codepage);
3133 bcc_ptr += 2 * bytes_returned;
3134 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003135 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136 nls_codepage);
3137 bcc_ptr += 2 * bytes_returned;
3138 bcc_ptr += 2; /* null term version string */
3139 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003140 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003141 64, nls_codepage);
3142 bcc_ptr += 2 * bytes_returned;
3143 *(bcc_ptr + 1) = 0;
3144 *(bcc_ptr + 2) = 0;
3145 bcc_ptr += 2; /* null terminate network opsys string */
3146 *(bcc_ptr + 1) = 0;
3147 *(bcc_ptr + 2) = 0;
3148 bcc_ptr += 2; /* null domain */
3149 } else { /* ASCII */
3150 if (domain == NULL) {
3151 SecurityBlob->DomainName.Buffer = 0;
3152 SecurityBlob->DomainName.Length = 0;
3153 SecurityBlob->DomainName.MaximumLength = 0;
3154 } else {
Steve French77159b42007-08-31 01:10:17 +00003155 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
3157 strncpy(bcc_ptr, domain, 63);
Steve French77159b42007-08-31 01:10:17 +00003158 ln = strnlen(domain, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003159 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003160 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161 SecurityBlob->DomainName.Buffer =
3162 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003163 bcc_ptr += ln;
3164 SecurityBlobLength += ln;
3165 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166 }
3167 if (user == NULL) {
3168 SecurityBlob->UserName.Buffer = 0;
3169 SecurityBlob->UserName.Length = 0;
3170 SecurityBlob->UserName.MaximumLength = 0;
3171 } else {
Steve French77159b42007-08-31 01:10:17 +00003172 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173 strncpy(bcc_ptr, user, 63);
Steve French77159b42007-08-31 01:10:17 +00003174 ln = strnlen(user, 64);
3175 SecurityBlob->UserName.MaximumLength = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176 SecurityBlob->UserName.Buffer =
Steve French77159b42007-08-31 01:10:17 +00003177 cpu_to_le32(SecurityBlobLength);
3178 bcc_ptr += ln;
3179 SecurityBlobLength += ln;
3180 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181 }
3182 /* BB fill in our workstation name if known BB */
3183
3184 strcpy(bcc_ptr, "Linux version ");
3185 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003186 strcpy(bcc_ptr, utsname()->release);
3187 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
3189 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
3190 bcc_ptr++; /* null domain */
3191 *bcc_ptr = 0;
3192 }
3193 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
3194 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
3195 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
3196 smb_buffer->smb_buf_length += count;
3197 pSMB->req.ByteCount = cpu_to_le16(count);
3198
3199 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00003200 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201 if (rc) {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003202/* rc = map_smb_to_linux_error(smb_buffer_response) done in SendReceive now */
3203 } else if ((smb_buffer_response->WordCount == 3) ||
3204 (smb_buffer_response->WordCount == 4)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205 __u16 action = le16_to_cpu(pSMBr->resp.Action);
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003206 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00003208 cFYI(1, (" Guest login")); /* BB Should we set anything
3209 in SesInfo struct ? */
3210/* if (SecurityBlob2->MessageType != NtLm??) {
3211 cFYI("Unexpected message type on auth response is %d"));
3212 } */
3213
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214 if (ses) {
3215 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003216 ("Check challenge UID %d vs auth response UID %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217 ses->Suid, smb_buffer_response->Uid));
Steve French50c2f752007-07-13 00:33:32 +00003218 /* UID left in wire format */
3219 ses->Suid = smb_buffer_response->Uid;
3220 bcc_ptr = pByteArea(smb_buffer_response);
3221 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222 if ((pSMBr->resp.hdr.WordCount == 3)
3223 || ((pSMBr->resp.hdr.WordCount == 4)
3224 && (blob_len <
3225 pSMBr->resp.ByteCount))) {
3226 if (pSMBr->resp.hdr.WordCount == 4) {
3227 bcc_ptr +=
3228 blob_len;
3229 cFYI(1,
3230 ("Security Blob Length %d ",
3231 blob_len));
3232 }
3233
3234 cFYI(1,
3235 ("NTLMSSP response to Authenticate "));
3236
3237 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3238 if ((long) (bcc_ptr) % 2) {
3239 remaining_words =
3240 (BCC(smb_buffer_response)
3241 - 1) / 2;
3242 bcc_ptr++; /* Unicode strings must be word aligned */
3243 } else {
3244 remaining_words = BCC(smb_buffer_response) / 2;
3245 }
Steve French77159b42007-08-31 01:10:17 +00003246 len = UniStrnlen((wchar_t *) bcc_ptr,
3247 remaining_words - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248/* We look for obvious messed up bcc or strings in response so we do not go off
3249 the end since (at least) WIN2K and Windows XP have a major bug in not null
3250 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003251 if (ses->serverOS)
Steve French08775832006-05-30 18:08:26 +00003252 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003254 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003256 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003257 bcc_ptr, len,
3258 nls_codepage);
3259 bcc_ptr += 2 * (len + 1);
3260 remaining_words -= len + 1;
3261 ses->serverOS[2 * len] = 0;
3262 ses->serverOS[1 + (2 * len)] = 0;
3263 if (remaining_words > 0) {
3264 len = UniStrnlen((wchar_t *)
3265 bcc_ptr,
3266 remaining_words
3267 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00003268 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003270 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271 GFP_KERNEL);
3272 cifs_strfromUCS_le(ses->
3273 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003274 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275 bcc_ptr,
3276 len,
3277 nls_codepage);
3278 bcc_ptr += 2 * (len + 1);
3279 ses->serverNOS[2 * len] = 0;
3280 ses->serverNOS[1+(2*len)] = 0;
3281 remaining_words -= len + 1;
3282 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00003283 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003284 /* last string not always null terminated (e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003285 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003286 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003287 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003288 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003289 (len +
3290 1),
3291 GFP_KERNEL);
3292 cifs_strfromUCS_le
3293 (ses->
3294 serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08003295 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296 bcc_ptr, len,
3297 nls_codepage);
3298 bcc_ptr +=
3299 2 * (len + 1);
3300 ses->
3301 serverDomain[2
3302 * len]
3303 = 0;
3304 ses->
3305 serverDomain[1
3306 +
3307 (2
3308 *
3309 len)]
3310 = 0;
3311 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003312 else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003313 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003314 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003315 ses->serverDomain = kzalloc(2,GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00003316 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317 } else { /* no room so create dummy domain and NOS string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003318 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003319 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003320 ses->serverDomain = kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00003321 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003322 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003323 }
3324 } else { /* ASCII */
3325 len = strnlen(bcc_ptr, 1024);
Steve French50c2f752007-07-13 00:33:32 +00003326 if (((long) bcc_ptr + len) -
3327 (long) pByteArea(smb_buffer_response)
Steve French63135e02007-07-17 17:34:02 +00003328 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003329 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00003330 kfree(ses->serverOS);
Steve French77159b42007-08-31 01:10:17 +00003331 ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332 strncpy(ses->serverOS,bcc_ptr, len);
3333
3334 bcc_ptr += len;
3335 bcc_ptr[0] = 0; /* null terminate the string */
3336 bcc_ptr++;
3337
3338 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003339 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00003340 ses->serverNOS = kzalloc(len+1,
3341 GFP_KERNEL);
Steve French63135e02007-07-17 17:34:02 +00003342 strncpy(ses->serverNOS,
3343 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344 bcc_ptr += len;
3345 bcc_ptr[0] = 0;
3346 bcc_ptr++;
3347
3348 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003349 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003350 kfree(ses->serverDomain);
Steve French63135e02007-07-17 17:34:02 +00003351 ses->serverDomain =
3352 kzalloc(len+1,
3353 GFP_KERNEL);
3354 strncpy(ses->serverDomain,
3355 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003356 bcc_ptr += len;
3357 bcc_ptr[0] = 0;
3358 bcc_ptr++;
3359 } else
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003360 cFYI(1, ("field of length %d "
Steve French63135e02007-07-17 17:34:02 +00003361 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003362 len));
3363 }
3364 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003365 cERROR(1, ("Security Blob extends beyond end "
Steve French63135e02007-07-17 17:34:02 +00003366 "of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003367 }
3368 } else {
3369 cERROR(1, ("No session structure passed in."));
3370 }
3371 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003372 cERROR(1, ("Invalid Word count %d: ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373 smb_buffer_response->WordCount));
3374 rc = -EIO;
3375 }
3376
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003377 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378
3379 return rc;
3380}
3381
3382int
3383CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3384 const char *tree, struct cifsTconInfo *tcon,
3385 const struct nls_table *nls_codepage)
3386{
3387 struct smb_hdr *smb_buffer;
3388 struct smb_hdr *smb_buffer_response;
3389 TCONX_REQ *pSMB;
3390 TCONX_RSP *pSMBr;
3391 unsigned char *bcc_ptr;
3392 int rc = 0;
3393 int length;
3394 __u16 count;
3395
3396 if (ses == NULL)
3397 return -EIO;
3398
3399 smb_buffer = cifs_buf_get();
3400 if (smb_buffer == NULL) {
3401 return -ENOMEM;
3402 }
3403 smb_buffer_response = smb_buffer;
3404
3405 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3406 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003407
3408 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003409 smb_buffer->Uid = ses->Suid;
3410 pSMB = (TCONX_REQ *) smb_buffer;
3411 pSMBr = (TCONX_RSP *) smb_buffer_response;
3412
3413 pSMB->AndXCommand = 0xFF;
3414 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415 bcc_ptr = &pSMB->Password[0];
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003416 if ((ses->server->secMode) & SECMODE_USER) {
Steve Frencheeac8042006-01-13 21:34:58 -08003417 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00003418 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08003419 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00003420 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08003421 } else {
Steve French7c7b25b2006-06-01 19:20:10 +00003422 pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08003423 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
3424 specified as required (when that support is added to
3425 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00003426 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08003427 by Samba (not sure whether other servers allow
3428 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00003429#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French50c2f752007-07-13 00:33:32 +00003430 if ((extended_security & CIFSSEC_MAY_LANMAN) &&
Steve French7c7b25b2006-06-01 19:20:10 +00003431 (ses->server->secType == LANMAN))
3432 calc_lanman_hash(ses, bcc_ptr);
3433 else
3434#endif /* CIFS_WEAK_PW_HASH */
Steve Frencheeac8042006-01-13 21:34:58 -08003435 SMBNTencrypt(ses->password,
3436 ses->server->cryptKey,
3437 bcc_ptr);
3438
Steve French7c7b25b2006-06-01 19:20:10 +00003439 bcc_ptr += CIFS_SESS_KEY_SIZE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003440 if (ses->capabilities & CAP_UNICODE) {
Steve French7c7b25b2006-06-01 19:20:10 +00003441 /* must align unicode strings */
3442 *bcc_ptr = 0; /* null byte password */
3443 bcc_ptr++;
3444 }
Steve Frencheeac8042006-01-13 21:34:58 -08003445 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446
Steve French50c2f752007-07-13 00:33:32 +00003447 if (ses->server->secMode &
Steve Frencha878fb22006-05-30 18:04:19 +00003448 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3450
3451 if (ses->capabilities & CAP_STATUS32) {
3452 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3453 }
3454 if (ses->capabilities & CAP_DFS) {
3455 smb_buffer->Flags2 |= SMBFLG2_DFS;
3456 }
3457 if (ses->capabilities & CAP_UNICODE) {
3458 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3459 length =
Steve French50c2f752007-07-13 00:33:32 +00003460 cifs_strtoUCS((__le16 *) bcc_ptr, tree,
3461 6 /* max utf8 char length in bytes */ *
Steve Frencha878fb22006-05-30 18:04:19 +00003462 (/* server len*/ + 256 /* share len */), nls_codepage);
3463 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464 bcc_ptr += 2; /* skip trailing null */
3465 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466 strcpy(bcc_ptr, tree);
3467 bcc_ptr += strlen(tree) + 1;
3468 }
3469 strcpy(bcc_ptr, "?????");
3470 bcc_ptr += strlen("?????");
3471 bcc_ptr += 1;
3472 count = bcc_ptr - &pSMB->Password[0];
3473 pSMB->hdr.smb_buf_length += count;
3474 pSMB->ByteCount = cpu_to_le16(count);
3475
Steve French133672e2007-11-13 22:41:37 +00003476 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
3477 CIFS_STD_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478
3479 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3480 /* above now done in SendReceive */
3481 if ((rc == 0) && (tcon != NULL)) {
3482 tcon->tidStatus = CifsGood;
3483 tcon->tid = smb_buffer_response->Tid;
3484 bcc_ptr = pByteArea(smb_buffer_response);
3485 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
Steve French50c2f752007-07-13 00:33:32 +00003486 /* skip service field (NB: this field is always ASCII) */
Steve French7f8ed422007-09-28 22:28:55 +00003487 if (length == 3) {
3488 if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') &&
3489 (bcc_ptr[2] == 'C')) {
3490 cFYI(1, ("IPC connection"));
3491 tcon->ipc = 1;
3492 }
3493 } else if (length == 2) {
3494 if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) {
3495 /* the most common case */
3496 cFYI(1, ("disk share connection"));
3497 }
3498 }
Steve French50c2f752007-07-13 00:33:32 +00003499 bcc_ptr += length + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3501 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3502 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3503 if ((bcc_ptr + (2 * length)) -
3504 pByteArea(smb_buffer_response) <=
3505 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003506 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003507 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003508 kzalloc(length + 2, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003509 if (tcon->nativeFileSystem)
3510 cifs_strfromUCS_le(
3511 tcon->nativeFileSystem,
3512 (__le16 *) bcc_ptr,
3513 length, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514 bcc_ptr += 2 * length;
3515 bcc_ptr[0] = 0; /* null terminate the string */
3516 bcc_ptr[1] = 0;
3517 bcc_ptr += 2;
3518 }
Steve French50c2f752007-07-13 00:33:32 +00003519 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520 } else {
3521 length = strnlen(bcc_ptr, 1024);
3522 if ((bcc_ptr + length) -
3523 pByteArea(smb_buffer_response) <=
3524 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003525 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003526 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003527 kzalloc(length + 1, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003528 if (tcon->nativeFileSystem)
3529 strncpy(tcon->nativeFileSystem, bcc_ptr,
3530 length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531 }
Steve French50c2f752007-07-13 00:33:32 +00003532 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003534 if ((smb_buffer_response->WordCount == 3) ||
Steve French1a4e15a2006-10-12 21:33:51 +00003535 (smb_buffer_response->WordCount == 7))
3536 /* field is in same location */
Steve French39798772006-05-31 22:40:51 +00003537 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3538 else
3539 tcon->Flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003540 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3541 } else if ((rc == 0) && tcon == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00003542 /* all we need to save for IPC$ connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543 ses->ipc_tid = smb_buffer_response->Tid;
3544 }
3545
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003546 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003547 return rc;
3548}
3549
3550int
3551cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3552{
3553 int rc = 0;
3554 int xid;
3555 struct cifsSesInfo *ses = NULL;
3556 struct task_struct *cifsd_task;
Steve French50c2f752007-07-13 00:33:32 +00003557 char *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558
3559 xid = GetXid();
3560
3561 if (cifs_sb->tcon) {
3562 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3563 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3564 if (rc == -EBUSY) {
3565 FreeXid(xid);
3566 return 0;
3567 }
Steve French5d941ca2008-04-15 18:40:48 +00003568 DeleteTconOplockQEntries(cifs_sb->tcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569 tconInfoFree(cifs_sb->tcon);
3570 if ((ses) && (ses->server)) {
3571 /* save off task so we do not refer to ses later */
3572 cifsd_task = ses->server->tsk;
3573 cFYI(1, ("About to do SMBLogoff "));
3574 rc = CIFSSMBLogoff(xid, ses);
3575 if (rc == -EBUSY) {
3576 FreeXid(xid);
3577 return 0;
3578 } else if (rc == -ESHUTDOWN) {
Steve French467a8f82007-06-27 22:41:32 +00003579 cFYI(1, ("Waking up socket by sending signal"));
Steve Frenchf7f7c312007-05-24 02:29:51 +00003580 if (cifsd_task) {
Steve French50c2f752007-07-13 00:33:32 +00003581 force_sig(SIGKILL, cifsd_task);
Igor Mammedovaaf737a2007-04-03 19:16:43 +00003582 kthread_stop(cifsd_task);
Steve Frenchf1914012005-08-18 09:37:34 -07003583 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584 rc = 0;
3585 } /* else - we have an smb session
3586 left on this socket do not kill cifsd */
3587 } else
3588 cFYI(1, ("No session or bad tcon"));
3589 }
Steve French50c2f752007-07-13 00:33:32 +00003590
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591 cifs_sb->tcon = NULL;
Steve French2fe87f02006-09-21 07:02:52 +00003592 tmp = cifs_sb->prepath;
3593 cifs_sb->prepathlen = 0;
3594 cifs_sb->prepath = NULL;
3595 kfree(tmp);
Nishanth Aravamudan041e0e32005-09-10 00:27:23 -07003596 if (ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597 sesInfoFree(ses);
3598
3599 FreeXid(xid);
Steve French88e7d702008-01-03 17:37:09 +00003600 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003601}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602
3603int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
Steve French50c2f752007-07-13 00:33:32 +00003604 struct nls_table *nls_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605{
3606 int rc = 0;
Steve French7c7b25b2006-06-01 19:20:10 +00003607 char ntlm_session_key[CIFS_SESS_KEY_SIZE];
Steve French4b18f2a2008-04-29 00:06:05 +00003608 bool ntlmv2_flag = false;
Steve Frenchad009ac2005-04-28 22:41:05 -07003609 int first_time = 0;
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003610 struct TCP_Server_Info *server = pSesInfo->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003611
3612 /* what if server changes its buffer size after dropping the session? */
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003613 if (server->maxBuf == 0) /* no need to send on reconnect */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003614 rc = CIFSSMBNegotiate(xid, pSesInfo);
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003615 if (rc == -EAGAIN) {
3616 /* retry only once on 1st time connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve French50c2f752007-07-13 00:33:32 +00003618 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003619 rc = -EHOSTDOWN;
3620 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003621 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003622 spin_lock(&GlobalMid_Lock);
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003623 if (server->tcpStatus != CifsExiting)
3624 server->tcpStatus = CifsGood;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003625 else
3626 rc = -EHOSTDOWN;
3627 spin_unlock(&GlobalMid_Lock);
3628
3629 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003630 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003631 }
Steve French26b994f2008-08-06 05:11:33 +00003632
3633 if (rc)
3634 goto ss_err_exit;
3635
3636 pSesInfo->flags = 0;
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003637 pSesInfo->capabilities = server->capabilities;
Steve French26b994f2008-08-06 05:11:33 +00003638 if (linuxExtEnabled == 0)
3639 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003640 /* pSesInfo->sequence_number = 0;*/
Steve French26b994f2008-08-06 05:11:33 +00003641 cFYI(1, ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003642 server->secMode, server->capabilities, server->timeAdj));
3643
Steve French26b994f2008-08-06 05:11:33 +00003644 if (experimEnabled < 2)
3645 rc = CIFS_SessSetup(xid, pSesInfo, first_time, nls_info);
3646 else if (extended_security
3647 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003648 && (server->secType == NTLMSSP)) {
Steve French26b994f2008-08-06 05:11:33 +00003649 rc = -EOPNOTSUPP;
3650 } else if (extended_security
3651 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003652 && (server->secType == RawNTLMSSP)) {
Steve French26b994f2008-08-06 05:11:33 +00003653 cFYI(1, ("NTLMSSP sesssetup"));
3654 rc = CIFSNTLMSSPNegotiateSessSetup(xid, pSesInfo, &ntlmv2_flag,
3655 nls_info);
3656 if (!rc) {
3657 if (ntlmv2_flag) {
3658 char *v2_response;
3659 cFYI(1, ("more secure NTLM ver2 hash"));
3660 if (CalcNTLMv2_partial_mac_key(pSesInfo,
3661 nls_info)) {
3662 rc = -ENOMEM;
3663 goto ss_err_exit;
3664 } else
3665 v2_response = kmalloc(16 + 64 /* blob*/,
3666 GFP_KERNEL);
3667 if (v2_response) {
3668 CalcNTLMv2_response(pSesInfo,
3669 v2_response);
3670 /* if (first_time)
3671 cifs_calculate_ntlmv2_mac_key */
3672 kfree(v2_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003673 /* BB Put dummy sig in SessSetup PDU? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003674 } else {
Steve French26b994f2008-08-06 05:11:33 +00003675 rc = -ENOMEM;
3676 goto ss_err_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677 }
Steve French26b994f2008-08-06 05:11:33 +00003678
3679 } else {
3680 SMBNTencrypt(pSesInfo->password,
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003681 server->cryptKey,
Steve French26b994f2008-08-06 05:11:33 +00003682 ntlm_session_key);
3683
3684 if (first_time)
3685 cifs_calculate_mac_key(
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003686 &server->mac_signing_key,
Steve French26b994f2008-08-06 05:11:33 +00003687 ntlm_session_key,
3688 pSesInfo->password);
3689 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003690 /* for better security the weaker lanman hash not sent
3691 in AuthSessSetup so we no longer calculate it */
3692
Steve French26b994f2008-08-06 05:11:33 +00003693 rc = CIFSNTLMSSPAuthSessSetup(xid, pSesInfo,
3694 ntlm_session_key,
3695 ntlmv2_flag,
3696 nls_info);
3697 }
3698 } else { /* old style NTLM 0.12 session setup */
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003699 SMBNTencrypt(pSesInfo->password, server->cryptKey,
Steve French26b994f2008-08-06 05:11:33 +00003700 ntlm_session_key);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003701
Steve French26b994f2008-08-06 05:11:33 +00003702 if (first_time)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003703 cifs_calculate_mac_key(&server->mac_signing_key,
3704 ntlm_session_key,
3705 pSesInfo->password);
Steve Frenchad009ac2005-04-28 22:41:05 -07003706
Steve French26b994f2008-08-06 05:11:33 +00003707 rc = CIFSSessSetup(xid, pSesInfo, ntlm_session_key, nls_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708 }
Steve French26b994f2008-08-06 05:11:33 +00003709 if (rc) {
3710 cERROR(1, ("Send error in SessSetup = %d", rc));
3711 } else {
3712 cFYI(1, ("CIFS Session Established successfully"));
3713 pSesInfo->status = CifsGood;
3714 }
3715
Linus Torvalds1da177e2005-04-16 15:20:36 -07003716ss_err_exit:
3717 return rc;
3718}
3719