blob: 791ca5c1a1161224d27e04ca9179bfa5982fba21 [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;
63 char *in6_addr; /* ipv6 address as human readable form of in6_addr */
64 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;
78 bool noperm:1;
79 bool no_psx_acl:1; /* set if posix acl support should be disabled */
80 bool cifs_acl:1;
81 bool no_xattr:1; /* set if xattr (EA) support should be disabled*/
82 bool server_ino:1; /* use inode numbers from server ie UniqueId */
83 bool direct_io:1;
84 bool remap:1; /* set to remap seven reserved chars in filenames */
85 bool posix_paths:1; /* unset to not ask for posix pathnames. */
86 bool no_linux_ext:1;
87 bool sfu_emul:1;
88 bool nullauth:1; /* attempt to authenticate with null user */
Steve Frenchc46fa8a2005-08-18 20:49:57 -070089 unsigned nocase; /* request case insensitive filenames */
90 unsigned nobrl; /* disable sending byte range locks to srv */
Linus Torvalds1da177e2005-04-16 15:20:36 -070091 unsigned int rsize;
92 unsigned int wsize;
93 unsigned int sockopt;
94 unsigned short int port;
Steve Frenchfb8c4b12007-07-10 01:16:18 +000095 char *prepath;
Linus Torvalds1da177e2005-04-16 15:20:36 -070096};
97
Steve Frenchfb8c4b12007-07-10 01:16:18 +000098static int ipv4_connect(struct sockaddr_in *psin_server,
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 struct socket **csocket,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000100 char *netb_name,
101 char *server_netb_name);
102static int ipv6_connect(struct sockaddr_in6 *psin_server,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 struct socket **csocket);
104
105
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000106 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 * cifs tcp session reconnection
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000108 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 * mark tcp session as reconnecting so temporarily locked
110 * mark all smb sessions as reconnecting for tcp session
111 * reconnect tcp session
112 * wake up waiters on reconnection? - (not needed currently)
113 */
114
Steve French2cd646a2006-09-28 19:43:08 +0000115static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116cifs_reconnect(struct TCP_Server_Info *server)
117{
118 int rc = 0;
119 struct list_head *tmp;
120 struct cifsSesInfo *ses;
121 struct cifsTconInfo *tcon;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000122 struct mid_q_entry *mid_entry;
Steve French50c2f752007-07-13 00:33:32 +0000123
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 spin_lock(&GlobalMid_Lock);
Steve French26f57362007-08-30 22:09:15 +0000125 if (kthread_should_stop()) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000126 /* the demux thread will exit normally
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 next time through the loop */
128 spin_unlock(&GlobalMid_Lock);
129 return rc;
130 } else
131 server->tcpStatus = CifsNeedReconnect;
132 spin_unlock(&GlobalMid_Lock);
133 server->maxBuf = 0;
134
Steve Frenche4eb2952005-04-28 22:41:09 -0700135 cFYI(1, ("Reconnecting tcp session"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136
137 /* before reconnecting the tcp session, mark the smb session (uid)
138 and the tid bad so they are not used until reconnected */
139 read_lock(&GlobalSMBSeslock);
140 list_for_each(tmp, &GlobalSMBSessionList) {
141 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
142 if (ses->server) {
143 if (ses->server == server) {
144 ses->status = CifsNeedReconnect;
145 ses->ipc_tid = 0;
146 }
147 }
148 /* else tcp and smb sessions need reconnection */
149 }
150 list_for_each(tmp, &GlobalTreeConnectionList) {
151 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
Steve French26f57362007-08-30 22:09:15 +0000152 if ((tcon) && (tcon->ses) && (tcon->ses->server == server))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 tcon->tidStatus = CifsNeedReconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 }
155 read_unlock(&GlobalSMBSeslock);
156 /* do not want to be sending data on a socket we are freeing */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000157 down(&server->tcpSem);
158 if (server->ssocket) {
Steve French467a8f82007-06-27 22:41:32 +0000159 cFYI(1, ("State: 0x%x Flags: 0x%lx", server->ssocket->state,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 server->ssocket->flags));
Trond Myklebust91cf45f2007-11-12 18:10:39 -0800161 kernel_sock_shutdown(server->ssocket, SHUT_WR);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000162 cFYI(1, ("Post shutdown state: 0x%x Flags: 0x%lx",
Steve French467a8f82007-06-27 22:41:32 +0000163 server->ssocket->state,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 server->ssocket->flags));
165 sock_release(server->ssocket);
166 server->ssocket = NULL;
167 }
168
169 spin_lock(&GlobalMid_Lock);
170 list_for_each(tmp, &server->pending_mid_q) {
171 mid_entry = list_entry(tmp, struct
172 mid_q_entry,
173 qhead);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000174 if (mid_entry) {
175 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French09d1db52005-04-28 22:41:08 -0700176 /* Mark other intransit requests as needing
177 retry so we do not immediately mark the
178 session bad again (ie after we reconnect
179 below) as they timeout too */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 mid_entry->midState = MID_RETRY_NEEDED;
181 }
182 }
183 }
184 spin_unlock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000185 up(&server->tcpSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186
Steve French26f57362007-08-30 22:09:15 +0000187 while ((!kthread_should_stop()) && (server->tcpStatus != CifsGood)) {
Steve French6c3d8902006-07-31 22:46:20 +0000188 try_to_freeze();
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000189 if (server->protocolType == IPV6) {
190 rc = ipv6_connect(&server->addr.sockAddr6,
191 &server->ssocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000193 rc = ipv4_connect(&server->addr.sockAddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 &server->ssocket,
Steve Frencha10faeb22005-08-22 21:38:31 -0700195 server->workstation_RFC1001_name,
196 server->server_RFC1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000198 if (rc) {
199 cFYI(1, ("reconnect error %d", rc));
Steve French0cb766a2005-04-28 22:41:11 -0700200 msleep(3000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 } else {
202 atomic_inc(&tcpSesReconnectCount);
203 spin_lock(&GlobalMid_Lock);
Steve French26f57362007-08-30 22:09:15 +0000204 if (!kthread_should_stop())
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 server->tcpStatus = CifsGood;
Steve Frenchad009ac2005-04-28 22:41:05 -0700206 server->sequence_number = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000207 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 /* atomic_set(&server->inFlight,0);*/
209 wake_up(&server->response_q);
210 }
211 }
212 return rc;
213}
214
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000215/*
Steve Frenche4eb2952005-04-28 22:41:09 -0700216 return codes:
217 0 not a transact2, or all data present
218 >0 transact2 with that much data missing
219 -EINVAL = invalid transact2
220
221 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000222static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize)
Steve Frenche4eb2952005-04-28 22:41:09 -0700223{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000224 struct smb_t2_rsp *pSMBt;
225 int total_data_size;
Steve Frenche4eb2952005-04-28 22:41:09 -0700226 int data_in_this_rsp;
227 int remaining;
228
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000229 if (pSMB->Command != SMB_COM_TRANSACTION2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700230 return 0;
231
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000232 /* check for plausible wct, bcc and t2 data and parm sizes */
233 /* check for parm and data offset going beyond end of smb */
234 if (pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
Steve French467a8f82007-06-27 22:41:32 +0000235 cFYI(1, ("invalid transact2 word count"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700236 return -EINVAL;
237 }
238
239 pSMBt = (struct smb_t2_rsp *)pSMB;
240
241 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
242 data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
243
244 remaining = total_data_size - data_in_this_rsp;
245
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000246 if (remaining == 0)
Steve Frenche4eb2952005-04-28 22:41:09 -0700247 return 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000248 else if (remaining < 0) {
Steve French467a8f82007-06-27 22:41:32 +0000249 cFYI(1, ("total data %d smaller than data in frame %d",
Steve Frenche4eb2952005-04-28 22:41:09 -0700250 total_data_size, data_in_this_rsp));
251 return -EINVAL;
252 } else {
Steve French467a8f82007-06-27 22:41:32 +0000253 cFYI(1, ("missing %d bytes from transact2, check next response",
Steve Frenche4eb2952005-04-28 22:41:09 -0700254 remaining));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000255 if (total_data_size > maxBufSize) {
256 cERROR(1, ("TotalDataSize %d is over maximum buffer %d",
257 total_data_size, maxBufSize));
258 return -EINVAL;
Steve Frenche4eb2952005-04-28 22:41:09 -0700259 }
260 return remaining;
261 }
262}
263
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000264static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
Steve Frenche4eb2952005-04-28 22:41:09 -0700265{
266 struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
267 struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
268 int total_data_size;
269 int total_in_buf;
270 int remaining;
271 int total_in_buf2;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000272 char *data_area_of_target;
273 char *data_area_of_buf2;
Steve Frenche4eb2952005-04-28 22:41:09 -0700274 __u16 byte_count;
275
276 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
277
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000278 if (total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
Steve French63135e02007-07-17 17:34:02 +0000279 cFYI(1, ("total data size of primary and secondary t2 differ"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700280 }
281
282 total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
283
284 remaining = total_data_size - total_in_buf;
Steve French50c2f752007-07-13 00:33:32 +0000285
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000286 if (remaining < 0)
Steve Frenche4eb2952005-04-28 22:41:09 -0700287 return -EINVAL;
288
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000289 if (remaining == 0) /* nothing to do, ignore */
Steve Frenche4eb2952005-04-28 22:41:09 -0700290 return 0;
Steve French50c2f752007-07-13 00:33:32 +0000291
Steve Frenche4eb2952005-04-28 22:41:09 -0700292 total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000293 if (remaining < total_in_buf2) {
Steve French467a8f82007-06-27 22:41:32 +0000294 cFYI(1, ("transact2 2nd response contains too much data"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700295 }
296
297 /* find end of first SMB data area */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000298 data_area_of_target = (char *)&pSMBt->hdr.Protocol +
Steve Frenche4eb2952005-04-28 22:41:09 -0700299 le16_to_cpu(pSMBt->t2_rsp.DataOffset);
300 /* validate target area */
301
302 data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000303 le16_to_cpu(pSMB2->t2_rsp.DataOffset);
Steve Frenche4eb2952005-04-28 22:41:09 -0700304
305 data_area_of_target += total_in_buf;
306
307 /* copy second buffer into end of first buffer */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000308 memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2);
Steve Frenche4eb2952005-04-28 22:41:09 -0700309 total_in_buf += total_in_buf2;
310 pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
311 byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
312 byte_count += total_in_buf2;
313 BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
314
Steve French70ca7342005-09-22 16:32:06 -0700315 byte_count = pTargetSMB->smb_buf_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700316 byte_count += total_in_buf2;
317
318 /* BB also add check that we are not beyond maximum buffer size */
Steve French50c2f752007-07-13 00:33:32 +0000319
Steve French70ca7342005-09-22 16:32:06 -0700320 pTargetSMB->smb_buf_length = byte_count;
Steve Frenche4eb2952005-04-28 22:41:09 -0700321
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000322 if (remaining == total_in_buf2) {
Steve French467a8f82007-06-27 22:41:32 +0000323 cFYI(1, ("found the last secondary response"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700324 return 0; /* we are done */
325 } else /* more responses to go */
326 return 1;
327
328}
329
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330static int
331cifs_demultiplex_thread(struct TCP_Server_Info *server)
332{
333 int length;
334 unsigned int pdu_length, total_read;
335 struct smb_hdr *smb_buffer = NULL;
Steve Frenchb8643e12005-04-28 22:41:07 -0700336 struct smb_hdr *bigbuf = NULL;
337 struct smb_hdr *smallbuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 struct msghdr smb_msg;
339 struct kvec iov;
340 struct socket *csocket = server->ssocket;
341 struct list_head *tmp;
342 struct cifsSesInfo *ses;
343 struct task_struct *task_to_wake = NULL;
344 struct mid_q_entry *mid_entry;
Steve French70ca7342005-09-22 16:32:06 -0700345 char temp;
Steve French4b18f2a2008-04-29 00:06:05 +0000346 bool isLargeBuf = false;
347 bool isMultiRsp;
Steve Frenche4eb2952005-04-28 22:41:09 -0700348 int reconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 current->flags |= PF_MEMALLOC;
351 server->tsk = current; /* save process info to wake at shutdown */
Pavel Emelyanovba25f9d2007-10-18 23:40:40 -0700352 cFYI(1, ("Demultiplex PID: %d", task_pid_nr(current)));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000353 write_lock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 atomic_inc(&tcpSesAllocCount);
355 length = tcpSesAllocCount.counter;
356 write_unlock(&GlobalSMBSeslock);
Steve French26f57362007-08-30 22:09:15 +0000357 if (length > 1)
358 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
359 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360
Rafael J. Wysocki83144182007-07-17 04:03:35 -0700361 set_freezable();
Igor Mammedovaaf737a2007-04-03 19:16:43 +0000362 while (!kthread_should_stop()) {
Steve Frenchede13272005-08-30 20:10:14 -0700363 if (try_to_freeze())
364 continue;
Steve Frenchb8643e12005-04-28 22:41:07 -0700365 if (bigbuf == NULL) {
366 bigbuf = cifs_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000367 if (!bigbuf) {
368 cERROR(1, ("No memory for large SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700369 msleep(3000);
370 /* retry will check if exiting */
371 continue;
372 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000373 } else if (isLargeBuf) {
374 /* we are reusing a dirty large buf, clear its start */
Steve French26f57362007-08-30 22:09:15 +0000375 memset(bigbuf, 0, sizeof(struct smb_hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700377
378 if (smallbuf == NULL) {
379 smallbuf = cifs_small_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000380 if (!smallbuf) {
381 cERROR(1, ("No memory for SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700382 msleep(1000);
383 /* retry will check if exiting */
384 continue;
385 }
386 /* beginning of smb buffer is cleared in our buf_get */
387 } else /* if existing small buf clear beginning */
Steve French26f57362007-08-30 22:09:15 +0000388 memset(smallbuf, 0, sizeof(struct smb_hdr));
Steve Frenchb8643e12005-04-28 22:41:07 -0700389
Steve French4b18f2a2008-04-29 00:06:05 +0000390 isLargeBuf = false;
391 isMultiRsp = false;
Steve Frenchb8643e12005-04-28 22:41:07 -0700392 smb_buffer = smallbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 iov.iov_base = smb_buffer;
394 iov.iov_len = 4;
395 smb_msg.msg_control = NULL;
396 smb_msg.msg_controllen = 0;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000397 pdu_length = 4; /* enough to get RFC1001 header */
398incomplete_rcv:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 length =
400 kernel_recvmsg(csocket, &smb_msg,
Steve Frenchf01d5e12007-08-30 21:13:31 +0000401 &iov, 1, pdu_length, 0 /* BB other flags? */);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402
Steve French26f57362007-08-30 22:09:15 +0000403 if (kthread_should_stop()) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 break;
405 } else if (server->tcpStatus == CifsNeedReconnect) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000406 cFYI(1, ("Reconnect after server stopped responding"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 cifs_reconnect(server);
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000408 cFYI(1, ("call to reconnect done"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 csocket = server->ssocket;
410 continue;
411 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700412 msleep(1); /* minimum sleep to prevent looping
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 allowing socket to clear and app threads to set
414 tcpStatus CifsNeedReconnect if server hung */
Steve Frenchc18c7322007-10-17 18:01:11 +0000415 if (pdu_length < 4)
416 goto incomplete_rcv;
417 else
418 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 } else if (length <= 0) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000420 if (server->tcpStatus == CifsNew) {
421 cFYI(1, ("tcp session abend after SMBnegprot"));
Steve French09d1db52005-04-28 22:41:08 -0700422 /* some servers kill the TCP session rather than
423 returning an SMB negprot error, in which
424 case reconnecting here is not going to help,
425 and so simply return error to mount */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 break;
427 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000428 if (!try_to_freeze() && (length == -EINTR)) {
Steve French467a8f82007-06-27 22:41:32 +0000429 cFYI(1, ("cifsd thread killed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 break;
431 }
Steve French467a8f82007-06-27 22:41:32 +0000432 cFYI(1, ("Reconnect after unexpected peek error %d",
Steve French57337e42005-04-28 22:41:10 -0700433 length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 cifs_reconnect(server);
435 csocket = server->ssocket;
436 wake_up(&server->response_q);
437 continue;
Petr Tesarik2a974682007-11-20 02:24:08 +0000438 } else if (length < pdu_length) {
439 cFYI(1, ("requested %d bytes but only got %d bytes",
440 pdu_length, length));
Steve Frenchf01d5e12007-08-30 21:13:31 +0000441 pdu_length -= length;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000442 msleep(1);
443 goto incomplete_rcv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 }
Steve French67010fb2005-04-28 22:41:09 -0700445
Steve French70ca7342005-09-22 16:32:06 -0700446 /* The right amount was read from socket - 4 bytes */
447 /* so we can now interpret the length field */
Steve French46810cb2005-04-28 22:41:09 -0700448
Steve French70ca7342005-09-22 16:32:06 -0700449 /* the first byte big endian of the length field,
450 is actually not part of the length but the type
451 with the most common, zero, as regular data */
452 temp = *((char *) smb_buffer);
453
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000454 /* Note that FC 1001 length is big endian on the wire,
Steve French70ca7342005-09-22 16:32:06 -0700455 but we convert it here so it is always manipulated
456 as host byte order */
Steve French46810cb2005-04-28 22:41:09 -0700457 pdu_length = ntohl(smb_buffer->smb_buf_length);
Steve French70ca7342005-09-22 16:32:06 -0700458 smb_buffer->smb_buf_length = pdu_length;
Steve French46810cb2005-04-28 22:41:09 -0700459
Steve French467a8f82007-06-27 22:41:32 +0000460 cFYI(1, ("rfc1002 length 0x%x", pdu_length+4));
Steve French70ca7342005-09-22 16:32:06 -0700461
462 if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000463 continue;
Steve French70ca7342005-09-22 16:32:06 -0700464 } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
Steve French467a8f82007-06-27 22:41:32 +0000465 cFYI(1, ("Good RFC 1002 session rsp"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700466 continue;
Steve French70ca7342005-09-22 16:32:06 -0700467 } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000468 /* we get this from Windows 98 instead of
Steve French46810cb2005-04-28 22:41:09 -0700469 an error on SMB negprot response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000470 cFYI(1, ("Negative RFC1002 Session Response Error 0x%x)",
Steve French70ca7342005-09-22 16:32:06 -0700471 pdu_length));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000472 if (server->tcpStatus == CifsNew) {
473 /* if nack on negprot (rather than
Steve French46810cb2005-04-28 22:41:09 -0700474 ret of smb negprot error) reconnecting
475 not going to help, ret error to mount */
476 break;
477 } else {
478 /* give server a second to
479 clean up before reconnect attempt */
480 msleep(1000);
481 /* always try 445 first on reconnect
482 since we get NACK on some if we ever
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000483 connected to port 139 (the NACK is
Steve French46810cb2005-04-28 22:41:09 -0700484 since we do not begin with RFC1001
485 session initialize frame) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000486 server->addr.sockAddr.sin_port =
Steve French46810cb2005-04-28 22:41:09 -0700487 htons(CIFS_PORT);
488 cifs_reconnect(server);
489 csocket = server->ssocket;
490 wake_up(&server->response_q);
491 continue;
492 }
Steve French70ca7342005-09-22 16:32:06 -0700493 } else if (temp != (char) 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000494 cERROR(1, ("Unknown RFC 1002 frame"));
Steve French70ca7342005-09-22 16:32:06 -0700495 cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
496 length);
Steve French46810cb2005-04-28 22:41:09 -0700497 cifs_reconnect(server);
498 csocket = server->ssocket;
499 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700500 }
501
502 /* else we have an SMB response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000503 if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French26f57362007-08-30 22:09:15 +0000504 (pdu_length < sizeof(struct smb_hdr) - 1 - 4)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700505 cERROR(1, ("Invalid size SMB length %d pdu_length %d",
Steve French46810cb2005-04-28 22:41:09 -0700506 length, pdu_length+4));
Steve Frenche4eb2952005-04-28 22:41:09 -0700507 cifs_reconnect(server);
508 csocket = server->ssocket;
509 wake_up(&server->response_q);
510 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000511 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700512
513 /* else length ok */
514 reconnect = 0;
515
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000516 if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
Steve French4b18f2a2008-04-29 00:06:05 +0000517 isLargeBuf = true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700518 memcpy(bigbuf, smallbuf, 4);
519 smb_buffer = bigbuf;
520 }
521 length = 0;
522 iov.iov_base = 4 + (char *)smb_buffer;
523 iov.iov_len = pdu_length;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000524 for (total_read = 0; total_read < pdu_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700525 total_read += length) {
526 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
527 pdu_length - total_read, 0);
Steve French26f57362007-08-30 22:09:15 +0000528 if (kthread_should_stop() ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700529 (length == -EINTR)) {
530 /* then will exit */
531 reconnect = 2;
532 break;
533 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700534 cifs_reconnect(server);
535 csocket = server->ssocket;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000536 /* Reconnect wakes up rspns q */
Steve Frenche4eb2952005-04-28 22:41:09 -0700537 /* Now we will reread sock */
538 reconnect = 1;
539 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000540 } else if ((length == -ERESTARTSYS) ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700541 (length == -EAGAIN)) {
542 msleep(1); /* minimum sleep to prevent looping,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000543 allowing socket to clear and app
Steve Frenche4eb2952005-04-28 22:41:09 -0700544 threads to set tcpStatus
545 CifsNeedReconnect if server hung*/
Steve Frenchc18c7322007-10-17 18:01:11 +0000546 length = 0;
Steve French46810cb2005-04-28 22:41:09 -0700547 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700548 } else if (length <= 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000549 cERROR(1, ("Received no data, expecting %d",
Steve Frenche4eb2952005-04-28 22:41:09 -0700550 pdu_length - total_read));
551 cifs_reconnect(server);
552 csocket = server->ssocket;
553 reconnect = 1;
554 break;
Steve French46810cb2005-04-28 22:41:09 -0700555 }
556 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000557 if (reconnect == 2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700558 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000559 else if (reconnect == 1)
Steve Frenche4eb2952005-04-28 22:41:09 -0700560 continue;
561
562 length += 4; /* account for rfc1002 hdr */
Steve French50c2f752007-07-13 00:33:32 +0000563
Steve Frenche4eb2952005-04-28 22:41:09 -0700564
565 dump_smb(smb_buffer, length);
Steve French184ed212006-02-24 06:15:11 +0000566 if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700567 cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
Steve Frenche4eb2952005-04-28 22:41:09 -0700568 continue;
569 }
570
571
572 task_to_wake = NULL;
573 spin_lock(&GlobalMid_Lock);
574 list_for_each(tmp, &server->pending_mid_q) {
575 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
576
Steve French50c2f752007-07-13 00:33:32 +0000577 if ((mid_entry->mid == smb_buffer->Mid) &&
Steve Frenche4eb2952005-04-28 22:41:09 -0700578 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
579 (mid_entry->command == smb_buffer->Command)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000580 if (check2ndT2(smb_buffer,server->maxBuf) > 0) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700581 /* We have a multipart transact2 resp */
Steve French4b18f2a2008-04-29 00:06:05 +0000582 isMultiRsp = true;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000583 if (mid_entry->resp_buf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700584 /* merge response - fix up 1st*/
Steve French50c2f752007-07-13 00:33:32 +0000585 if (coalesce_t2(smb_buffer,
Steve Frenche4eb2952005-04-28 22:41:09 -0700586 mid_entry->resp_buf)) {
Steve French4b18f2a2008-04-29 00:06:05 +0000587 mid_entry->multiRsp =
588 true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700589 break;
590 } else {
591 /* all parts received */
Steve French4b18f2a2008-04-29 00:06:05 +0000592 mid_entry->multiEnd =
593 true;
Steve French50c2f752007-07-13 00:33:32 +0000594 goto multi_t2_fnd;
Steve Frenche4eb2952005-04-28 22:41:09 -0700595 }
596 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000597 if (!isLargeBuf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700598 cERROR(1,("1st trans2 resp needs bigbuf"));
599 /* BB maybe we can fix this up, switch
Steve French50c2f752007-07-13 00:33:32 +0000600 to already allocated large buffer? */
Steve Frenche4eb2952005-04-28 22:41:09 -0700601 } else {
Steve Frenchcd634992005-04-28 22:41:10 -0700602 /* Have first buffer */
Steve Frenche4eb2952005-04-28 22:41:09 -0700603 mid_entry->resp_buf =
604 smb_buffer;
Steve French4b18f2a2008-04-29 00:06:05 +0000605 mid_entry->largeBuf =
606 true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700607 bigbuf = NULL;
608 }
609 }
610 break;
Steve French50c2f752007-07-13 00:33:32 +0000611 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700612 mid_entry->resp_buf = smb_buffer;
Steve French4b18f2a2008-04-29 00:06:05 +0000613 mid_entry->largeBuf = isLargeBuf;
Steve Frenche4eb2952005-04-28 22:41:09 -0700614multi_t2_fnd:
615 task_to_wake = mid_entry->tsk;
616 mid_entry->midState = MID_RESPONSE_RECEIVED;
Steve French1047abc2005-10-11 19:58:06 -0700617#ifdef CONFIG_CIFS_STATS2
618 mid_entry->when_received = jiffies;
619#endif
Steve French3a5ff612006-07-14 22:37:11 +0000620 /* so we do not time out requests to server
621 which is still responding (since server could
622 be busy but not dead) */
623 server->lstrp = jiffies;
Steve Frenche4eb2952005-04-28 22:41:09 -0700624 break;
625 }
626 }
627 spin_unlock(&GlobalMid_Lock);
628 if (task_to_wake) {
Steve Frenchcd634992005-04-28 22:41:10 -0700629 /* Was previous buf put in mpx struct for multi-rsp? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000630 if (!isMultiRsp) {
Steve Frenchcd634992005-04-28 22:41:10 -0700631 /* smb buffer will be freed by user thread */
Steve French26f57362007-08-30 22:09:15 +0000632 if (isLargeBuf)
Steve Frenchcd634992005-04-28 22:41:10 -0700633 bigbuf = NULL;
Steve French26f57362007-08-30 22:09:15 +0000634 else
Steve Frenchcd634992005-04-28 22:41:10 -0700635 smallbuf = NULL;
636 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700637 wake_up_process(task_to_wake);
Steve French4b18f2a2008-04-29 00:06:05 +0000638 } else if (!is_valid_oplock_break(smb_buffer, server) &&
639 !isMultiRsp) {
Steve French50c2f752007-07-13 00:33:32 +0000640 cERROR(1, ("No task to wake, unknown frame received! "
641 "NumMids %d", midCount.counter));
642 cifs_dump_mem("Received Data is: ", (char *)smb_buffer,
Steve French70ca7342005-09-22 16:32:06 -0700643 sizeof(struct smb_hdr));
Steve French39798772006-05-31 22:40:51 +0000644#ifdef CONFIG_CIFS_DEBUG2
645 cifs_dump_detail(smb_buffer);
646 cifs_dump_mids(server);
647#endif /* CIFS_DEBUG2 */
Steve French50c2f752007-07-13 00:33:32 +0000648
Steve Frenche4eb2952005-04-28 22:41:09 -0700649 }
650 } /* end while !EXITING */
651
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 spin_lock(&GlobalMid_Lock);
653 server->tcpStatus = CifsExiting;
654 server->tsk = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700655 /* check if we have blocked requests that need to free */
656 /* Note that cifs_max_pending is normally 50, but
657 can be set at module install time to as little as two */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000658 if (atomic_read(&server->inFlight) >= cifs_max_pending)
Steve French31ca3bc2005-04-28 22:41:11 -0700659 atomic_set(&server->inFlight, cifs_max_pending - 1);
660 /* We do not want to set the max_pending too low or we
661 could end up with the counter going negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +0000663 /* Although there should not be any requests blocked on
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700665 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 to the same server - they now will see the session is in exit state
667 and get out of SendReceive. */
668 wake_up_all(&server->request_q);
669 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700670 msleep(125);
Steve French50c2f752007-07-13 00:33:32 +0000671
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000672 if (server->ssocket) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 sock_release(csocket);
674 server->ssocket = NULL;
675 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700676 /* buffer usuallly freed in free_mid - need to free it here on exit */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +0000677 cifs_buf_release(bigbuf);
678 if (smallbuf) /* no sense logging a debug message if NULL */
Steve Frenchb8643e12005-04-28 22:41:07 -0700679 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680
681 read_lock(&GlobalSMBSeslock);
682 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700683 /* loop through server session structures attached to this and
684 mark them dead */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 list_for_each(tmp, &GlobalSMBSessionList) {
686 ses =
687 list_entry(tmp, struct cifsSesInfo,
688 cifsSessionList);
689 if (ses->server == server) {
690 ses->status = CifsExiting;
691 ses->server = NULL;
692 }
693 }
694 read_unlock(&GlobalSMBSeslock);
695 } else {
Steve French31ca3bc2005-04-28 22:41:11 -0700696 /* although we can not zero the server struct pointer yet,
697 since there are active requests which may depnd on them,
698 mark the corresponding SMB sessions as exiting too */
699 list_for_each(tmp, &GlobalSMBSessionList) {
700 ses = list_entry(tmp, struct cifsSesInfo,
701 cifsSessionList);
Steve French26f57362007-08-30 22:09:15 +0000702 if (ses->server == server)
Steve French31ca3bc2005-04-28 22:41:11 -0700703 ses->status = CifsExiting;
Steve French31ca3bc2005-04-28 22:41:11 -0700704 }
705
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 spin_lock(&GlobalMid_Lock);
707 list_for_each(tmp, &server->pending_mid_q) {
708 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
709 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French50c2f752007-07-13 00:33:32 +0000710 cFYI(1, ("Clearing Mid 0x%x - waking up ",
711 mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 task_to_wake = mid_entry->tsk;
Steve French26f57362007-08-30 22:09:15 +0000713 if (task_to_wake)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 wake_up_process(task_to_wake);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 }
716 }
717 spin_unlock(&GlobalMid_Lock);
718 read_unlock(&GlobalSMBSeslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700720 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 }
722
Steve Frenchf1914012005-08-18 09:37:34 -0700723 if (!list_empty(&server->pending_mid_q)) {
Steve French50c2f752007-07-13 00:33:32 +0000724 /* mpx threads have not exited yet give them
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700726 /* due to delays on oplock break requests, we need
727 to wait at least 45 seconds before giving up
728 on a request getting a response and going ahead
729 and killing cifsd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve French31ca3bc2005-04-28 22:41:11 -0700731 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 /* if threads still have not exited they are probably never
733 coming home not much else we can do but free the memory */
734 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735
736 write_lock(&GlobalSMBSeslock);
737 atomic_dec(&tcpSesAllocCount);
738 length = tcpSesAllocCount.counter;
Steve French31ca3bc2005-04-28 22:41:11 -0700739
740 /* last chance to mark ses pointers invalid
741 if there are any pointing to this (e.g
Steve French50c2f752007-07-13 00:33:32 +0000742 if a crazy root user tried to kill cifsd
Steve French31ca3bc2005-04-28 22:41:11 -0700743 kernel thread explicitly this might happen) */
744 list_for_each(tmp, &GlobalSMBSessionList) {
745 ses = list_entry(tmp, struct cifsSesInfo,
746 cifsSessionList);
Steve French26f57362007-08-30 22:09:15 +0000747 if (ses->server == server)
Steve French31ca3bc2005-04-28 22:41:11 -0700748 ses->server = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700749 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 write_unlock(&GlobalSMBSeslock);
Steve French31ca3bc2005-04-28 22:41:11 -0700751
Jeff Laytonc359cf32007-11-16 22:22:06 +0000752 kfree(server->hostname);
Steve French31ca3bc2005-04-28 22:41:11 -0700753 kfree(server);
Steve French26f57362007-08-30 22:09:15 +0000754 if (length > 0)
755 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
756 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +0000757
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 return 0;
759}
760
Jeff Laytonc359cf32007-11-16 22:22:06 +0000761/* extract the host portion of the UNC string */
762static char *
763extract_hostname(const char *unc)
764{
765 const char *src;
766 char *dst, *delim;
767 unsigned int len;
768
769 /* skip double chars at beginning of string */
770 /* BB: check validity of these bytes? */
771 src = unc + 2;
772
773 /* delimiter between hostname and sharename is always '\\' now */
774 delim = strchr(src, '\\');
775 if (!delim)
776 return ERR_PTR(-EINVAL);
777
778 len = delim - src;
779 dst = kmalloc((len + 1), GFP_KERNEL);
780 if (dst == NULL)
781 return ERR_PTR(-ENOMEM);
782
783 memcpy(dst, src, len);
784 dst[len] = '\0';
785
786 return dst;
787}
788
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789static int
Steve French50c2f752007-07-13 00:33:32 +0000790cifs_parse_mount_options(char *options, const char *devname,
791 struct smb_vol *vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792{
793 char *value;
794 char *data;
795 unsigned int temp_len, i, j;
796 char separator[2];
797
798 separator[0] = ',';
Steve French50c2f752007-07-13 00:33:32 +0000799 separator[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800
Linus Torvalds12e36b22006-10-13 08:09:29 -0700801 if (Local_System_Name[0] != 0)
Steve French50c2f752007-07-13 00:33:32 +0000802 memcpy(vol->source_rfc1001_name, Local_System_Name, 15);
Steve French2cd646a2006-09-28 19:43:08 +0000803 else {
Linus Torvalds12e36b22006-10-13 08:09:29 -0700804 char *nodename = utsname()->nodename;
Steve French50c2f752007-07-13 00:33:32 +0000805 int n = strnlen(nodename, 15);
806 memset(vol->source_rfc1001_name, 0x20, 15);
807 for (i = 0; i < n; i++) {
Steve French2cd646a2006-09-28 19:43:08 +0000808 /* does not have to be perfect mapping since field is
809 informational, only used for servers that do not support
810 port 445 and it can be overridden at mount time */
Linus Torvalds12e36b22006-10-13 08:09:29 -0700811 vol->source_rfc1001_name[i] = toupper(nodename[i]);
Steve French2cd646a2006-09-28 19:43:08 +0000812 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 }
814 vol->source_rfc1001_name[15] = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -0700815 /* null target name indicates to use *SMBSERVR default called name
816 if we end up sending RFC1001 session initialize */
817 vol->target_rfc1001_name[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 vol->linux_uid = current->uid; /* current->euid instead? */
819 vol->linux_gid = current->gid;
820 vol->dir_mode = S_IRWXUGO;
821 /* 2767 perms indicate mandatory locking support */
Steve French7505e052007-11-01 18:03:01 +0000822 vol->file_mode = (S_IRWXUGO | S_ISGID) & (~S_IXGRP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823
824 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
Steve French4b18f2a2008-04-29 00:06:05 +0000825 vol->rw = true;
Jeremy Allisonac670552005-06-22 17:26:35 -0700826 /* default is always to request posix paths. */
827 vol->posix_paths = 1;
828
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 if (!options)
830 return 1;
831
Steve French50c2f752007-07-13 00:33:32 +0000832 if (strncmp(options, "sep=", 4) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000833 if (options[4] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 separator[0] = options[4];
835 options += 5;
836 } else {
Steve French467a8f82007-06-27 22:41:32 +0000837 cFYI(1, ("Null separator not allowed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 }
839 }
Steve French50c2f752007-07-13 00:33:32 +0000840
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 while ((data = strsep(&options, separator)) != NULL) {
842 if (!*data)
843 continue;
844 if ((value = strchr(data, '=')) != NULL)
845 *value++ = '\0';
846
Steve French50c2f752007-07-13 00:33:32 +0000847 /* Have to parse this before we parse for "user" */
848 if (strnicmp(data, "user_xattr", 10) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 vol->no_xattr = 0;
Steve French50c2f752007-07-13 00:33:32 +0000850 } else if (strnicmp(data, "nouser_xattr", 12) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 vol->no_xattr = 1;
852 } else if (strnicmp(data, "user", 4) == 0) {
Steve French4b952a92006-10-30 21:46:13 +0000853 if (!value) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 printk(KERN_WARNING
855 "CIFS: invalid or missing username\n");
856 return 1; /* needs_arg; */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000857 } else if (!*value) {
Steve French4b952a92006-10-30 21:46:13 +0000858 /* null user, ie anonymous, authentication */
859 vol->nullauth = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 }
861 if (strnlen(value, 200) < 200) {
862 vol->username = value;
863 } else {
864 printk(KERN_WARNING "CIFS: username too long\n");
865 return 1;
866 }
867 } else if (strnicmp(data, "pass", 4) == 0) {
868 if (!value) {
869 vol->password = NULL;
870 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000871 } else if (value[0] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 /* check if string begins with double comma
873 since that would mean the password really
874 does start with a comma, and would not
875 indicate an empty string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000876 if (value[1] != separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 vol->password = NULL;
878 continue;
879 }
880 }
881 temp_len = strlen(value);
882 /* removed password length check, NTLM passwords
883 can be arbitrarily long */
884
Steve French50c2f752007-07-13 00:33:32 +0000885 /* if comma in password, the string will be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 prematurely null terminated. Commas in password are
887 specified across the cifs mount interface by a double
888 comma ie ,, and a comma used as in other cases ie ','
889 as a parameter delimiter/separator is single and due
890 to the strsep above is temporarily zeroed. */
891
892 /* NB: password legally can have multiple commas and
893 the only illegal character in a password is null */
894
Steve French50c2f752007-07-13 00:33:32 +0000895 if ((value[temp_len] == 0) &&
Steve French09d1db52005-04-28 22:41:08 -0700896 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 /* reinsert comma */
898 value[temp_len] = separator[0];
Steve French50c2f752007-07-13 00:33:32 +0000899 temp_len += 2; /* move after second comma */
900 while (value[temp_len] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 if (value[temp_len] == separator[0]) {
Steve French50c2f752007-07-13 00:33:32 +0000902 if (value[temp_len+1] ==
Steve French09d1db52005-04-28 22:41:08 -0700903 separator[0]) {
904 /* skip second comma */
905 temp_len++;
Steve French50c2f752007-07-13 00:33:32 +0000906 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 /* single comma indicating start
908 of next parm */
909 break;
910 }
911 }
912 temp_len++;
913 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000914 if (value[temp_len] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 options = NULL;
916 } else {
917 value[temp_len] = 0;
918 /* point option to start of next parm */
919 options = value + temp_len + 1;
920 }
Steve French50c2f752007-07-13 00:33:32 +0000921 /* go from value to value + temp_len condensing
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 double commas to singles. Note that this ends up
923 allocating a few bytes too many, which is ok */
Pekka Enberge915fc42005-09-06 15:18:35 -0700924 vol->password = kzalloc(temp_len, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000925 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000926 printk(KERN_WARNING "CIFS: no memory "
927 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700928 return 1;
929 }
Steve French50c2f752007-07-13 00:33:32 +0000930 for (i = 0, j = 0; i < temp_len; i++, j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 vol->password[j] = value[i];
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000932 if (value[i] == separator[0]
Steve French09d1db52005-04-28 22:41:08 -0700933 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 /* skip second comma */
935 i++;
936 }
937 }
938 vol->password[j] = 0;
939 } else {
Pekka Enberge915fc42005-09-06 15:18:35 -0700940 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000941 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000942 printk(KERN_WARNING "CIFS: no memory "
943 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700944 return 1;
945 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 strcpy(vol->password, value);
947 }
948 } else if (strnicmp(data, "ip", 2) == 0) {
949 if (!value || !*value) {
950 vol->UNCip = NULL;
951 } else if (strnlen(value, 35) < 35) {
952 vol->UNCip = value;
953 } else {
Steve French50c2f752007-07-13 00:33:32 +0000954 printk(KERN_WARNING "CIFS: ip address "
955 "too long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 return 1;
957 }
Steve French50c2f752007-07-13 00:33:32 +0000958 } else if (strnicmp(data, "sec", 3) == 0) {
959 if (!value || !*value) {
960 cERROR(1, ("no security value specified"));
961 continue;
962 } else if (strnicmp(value, "krb5i", 5) == 0) {
963 vol->secFlg |= CIFSSEC_MAY_KRB5 |
Steve French189acaa2006-06-23 02:33:48 +0000964 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800965 } else if (strnicmp(value, "krb5p", 5) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000966 /* vol->secFlg |= CIFSSEC_MUST_SEAL |
967 CIFSSEC_MAY_KRB5; */
968 cERROR(1, ("Krb5 cifs privacy not supported"));
Steve Frenchbf820672005-12-01 22:32:42 -0800969 return 1;
970 } else if (strnicmp(value, "krb5", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000971 vol->secFlg |= CIFSSEC_MAY_KRB5;
Steve Frenchbf820672005-12-01 22:32:42 -0800972 } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000973 vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
Steve French189acaa2006-06-23 02:33:48 +0000974 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800975 } else if (strnicmp(value, "ntlmv2", 6) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000976 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve Frenchbf820672005-12-01 22:32:42 -0800977 } else if (strnicmp(value, "ntlmi", 5) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000978 vol->secFlg |= CIFSSEC_MAY_NTLM |
Steve French189acaa2006-06-23 02:33:48 +0000979 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800980 } else if (strnicmp(value, "ntlm", 4) == 0) {
981 /* ntlm is default so can be turned off too */
Steve French750d1152006-06-27 06:28:30 +0000982 vol->secFlg |= CIFSSEC_MAY_NTLM;
Steve Frenchbf820672005-12-01 22:32:42 -0800983 } else if (strnicmp(value, "nontlm", 6) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000984 /* BB is there a better way to do this? */
Steve French750d1152006-06-27 06:28:30 +0000985 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve French189acaa2006-06-23 02:33:48 +0000986#ifdef CONFIG_CIFS_WEAK_PW_HASH
987 } else if (strnicmp(value, "lanman", 6) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000988 vol->secFlg |= CIFSSEC_MAY_LANMAN;
Steve French189acaa2006-06-23 02:33:48 +0000989#endif
Steve Frenchbf820672005-12-01 22:32:42 -0800990 } else if (strnicmp(value, "none", 4) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000991 vol->nullauth = 1;
Steve French50c2f752007-07-13 00:33:32 +0000992 } else {
993 cERROR(1, ("bad security option: %s", value));
994 return 1;
995 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 } else if ((strnicmp(data, "unc", 3) == 0)
997 || (strnicmp(data, "target", 6) == 0)
998 || (strnicmp(data, "path", 4) == 0)) {
999 if (!value || !*value) {
Steve French50c2f752007-07-13 00:33:32 +00001000 printk(KERN_WARNING "CIFS: invalid path to "
1001 "network resource\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 return 1; /* needs_arg; */
1003 }
1004 if ((temp_len = strnlen(value, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001005 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001006 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001008 strcpy(vol->UNC, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 if (strncmp(vol->UNC, "//", 2) == 0) {
1010 vol->UNC[0] = '\\';
1011 vol->UNC[1] = '\\';
Steve French50c2f752007-07-13 00:33:32 +00001012 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 printk(KERN_WARNING
Steve French50c2f752007-07-13 00:33:32 +00001014 "CIFS: UNC Path does not begin "
1015 "with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 return 1;
1017 }
1018 } else {
1019 printk(KERN_WARNING "CIFS: UNC name too long\n");
1020 return 1;
1021 }
1022 } else if ((strnicmp(data, "domain", 3) == 0)
1023 || (strnicmp(data, "workgroup", 5) == 0)) {
1024 if (!value || !*value) {
1025 printk(KERN_WARNING "CIFS: invalid domain name\n");
1026 return 1; /* needs_arg; */
1027 }
1028 /* BB are there cases in which a comma can be valid in
1029 a domain name and need special handling? */
Steve French39798772006-05-31 22:40:51 +00001030 if (strnlen(value, 256) < 256) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 vol->domainname = value;
1032 cFYI(1, ("Domain name set"));
1033 } else {
Steve French50c2f752007-07-13 00:33:32 +00001034 printk(KERN_WARNING "CIFS: domain name too "
1035 "long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 return 1;
1037 }
Steve French50c2f752007-07-13 00:33:32 +00001038 } else if (strnicmp(data, "prefixpath", 10) == 0) {
1039 if (!value || !*value) {
1040 printk(KERN_WARNING
1041 "CIFS: invalid path prefix\n");
1042 return 1; /* needs_argument */
1043 }
1044 if ((temp_len = strnlen(value, 1024)) < 1024) {
Steve French4523cc32007-04-30 20:13:06 +00001045 if (value[0] != '/')
Steve French2fe87f02006-09-21 07:02:52 +00001046 temp_len++; /* missing leading slash */
Steve French50c2f752007-07-13 00:33:32 +00001047 vol->prepath = kmalloc(temp_len+1, GFP_KERNEL);
1048 if (vol->prepath == NULL)
1049 return 1;
Steve French4523cc32007-04-30 20:13:06 +00001050 if (value[0] != '/') {
Steve French2fe87f02006-09-21 07:02:52 +00001051 vol->prepath[0] = '/';
Steve French50c2f752007-07-13 00:33:32 +00001052 strcpy(vol->prepath+1, value);
Steve French2fe87f02006-09-21 07:02:52 +00001053 } else
Steve French50c2f752007-07-13 00:33:32 +00001054 strcpy(vol->prepath, value);
1055 cFYI(1, ("prefix path %s", vol->prepath));
1056 } else {
1057 printk(KERN_WARNING "CIFS: prefix too long\n");
1058 return 1;
1059 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 } else if (strnicmp(data, "iocharset", 9) == 0) {
1061 if (!value || !*value) {
Steve French63135e02007-07-17 17:34:02 +00001062 printk(KERN_WARNING "CIFS: invalid iocharset "
1063 "specified\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 return 1; /* needs_arg; */
1065 }
1066 if (strnlen(value, 65) < 65) {
Steve French50c2f752007-07-13 00:33:32 +00001067 if (strnicmp(value, "default", 7))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 vol->iocharset = value;
Steve French50c2f752007-07-13 00:33:32 +00001069 /* if iocharset not set then load_nls_default
1070 is used by caller */
1071 cFYI(1, ("iocharset set to %s", value));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 } else {
Steve French63135e02007-07-17 17:34:02 +00001073 printk(KERN_WARNING "CIFS: iocharset name "
1074 "too long.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 return 1;
1076 }
1077 } else if (strnicmp(data, "uid", 3) == 0) {
1078 if (value && *value) {
1079 vol->linux_uid =
1080 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001081 vol->override_uid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 }
1083 } else if (strnicmp(data, "gid", 3) == 0) {
1084 if (value && *value) {
1085 vol->linux_gid =
1086 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001087 vol->override_gid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 }
1089 } else if (strnicmp(data, "file_mode", 4) == 0) {
1090 if (value && *value) {
1091 vol->file_mode =
1092 simple_strtoul(value, &value, 0);
1093 }
1094 } else if (strnicmp(data, "dir_mode", 4) == 0) {
1095 if (value && *value) {
1096 vol->dir_mode =
1097 simple_strtoul(value, &value, 0);
1098 }
1099 } else if (strnicmp(data, "dirmode", 4) == 0) {
1100 if (value && *value) {
1101 vol->dir_mode =
1102 simple_strtoul(value, &value, 0);
1103 }
1104 } else if (strnicmp(data, "port", 4) == 0) {
1105 if (value && *value) {
1106 vol->port =
1107 simple_strtoul(value, &value, 0);
1108 }
1109 } else if (strnicmp(data, "rsize", 5) == 0) {
1110 if (value && *value) {
1111 vol->rsize =
1112 simple_strtoul(value, &value, 0);
1113 }
1114 } else if (strnicmp(data, "wsize", 5) == 0) {
1115 if (value && *value) {
1116 vol->wsize =
1117 simple_strtoul(value, &value, 0);
1118 }
1119 } else if (strnicmp(data, "sockopt", 5) == 0) {
1120 if (value && *value) {
1121 vol->sockopt =
1122 simple_strtoul(value, &value, 0);
1123 }
1124 } else if (strnicmp(data, "netbiosname", 4) == 0) {
1125 if (!value || !*value || (*value == ' ')) {
Steve French63135e02007-07-17 17:34:02 +00001126 cFYI(1, ("invalid (empty) netbiosname"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 } else {
Steve French50c2f752007-07-13 00:33:32 +00001128 memset(vol->source_rfc1001_name, 0x20, 15);
1129 for (i = 0; i < 15; i++) {
1130 /* BB are there cases in which a comma can be
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 valid in this workstation netbios name (and need
1132 special handling)? */
1133
1134 /* We do not uppercase netbiosname for user */
Steve French50c2f752007-07-13 00:33:32 +00001135 if (value[i] == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 break;
Steve French50c2f752007-07-13 00:33:32 +00001137 else
1138 vol->source_rfc1001_name[i] =
1139 value[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 }
1141 /* The string has 16th byte zero still from
1142 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001143 if ((i == 15) && (value[i] != 0))
1144 printk(KERN_WARNING "CIFS: netbiosname"
1145 " longer than 15 truncated.\n");
Steve Frencha10faeb22005-08-22 21:38:31 -07001146 }
1147 } else if (strnicmp(data, "servern", 7) == 0) {
1148 /* servernetbiosname specified override *SMBSERVER */
1149 if (!value || !*value || (*value == ' ')) {
Steve French467a8f82007-06-27 22:41:32 +00001150 cFYI(1, ("empty server netbiosname specified"));
Steve Frencha10faeb22005-08-22 21:38:31 -07001151 } else {
1152 /* last byte, type, is 0x20 for servr type */
Steve French50c2f752007-07-13 00:33:32 +00001153 memset(vol->target_rfc1001_name, 0x20, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001154
Steve French50c2f752007-07-13 00:33:32 +00001155 for (i = 0; i < 15; i++) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001156 /* BB are there cases in which a comma can be
Steve French50c2f752007-07-13 00:33:32 +00001157 valid in this workstation netbios name
1158 (and need special handling)? */
Steve Frencha10faeb22005-08-22 21:38:31 -07001159
Steve French50c2f752007-07-13 00:33:32 +00001160 /* user or mount helper must uppercase
1161 the netbiosname */
1162 if (value[i] == 0)
Steve Frencha10faeb22005-08-22 21:38:31 -07001163 break;
1164 else
Steve French50c2f752007-07-13 00:33:32 +00001165 vol->target_rfc1001_name[i] =
1166 value[i];
Steve Frencha10faeb22005-08-22 21:38:31 -07001167 }
1168 /* The string has 16th byte zero still from
1169 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001170 if ((i == 15) && (value[i] != 0))
1171 printk(KERN_WARNING "CIFS: server net"
1172 "biosname longer than 15 truncated.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 }
1174 } else if (strnicmp(data, "credentials", 4) == 0) {
1175 /* ignore */
1176 } else if (strnicmp(data, "version", 3) == 0) {
1177 /* ignore */
Steve French50c2f752007-07-13 00:33:32 +00001178 } else if (strnicmp(data, "guest", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 /* ignore */
1180 } else if (strnicmp(data, "rw", 2) == 0) {
Steve French4b18f2a2008-04-29 00:06:05 +00001181 vol->rw = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 } else if ((strnicmp(data, "suid", 4) == 0) ||
1183 (strnicmp(data, "nosuid", 6) == 0) ||
1184 (strnicmp(data, "exec", 4) == 0) ||
1185 (strnicmp(data, "noexec", 6) == 0) ||
1186 (strnicmp(data, "nodev", 5) == 0) ||
1187 (strnicmp(data, "noauto", 6) == 0) ||
1188 (strnicmp(data, "dev", 3) == 0)) {
1189 /* The mount tool or mount.cifs helper (if present)
Steve French50c2f752007-07-13 00:33:32 +00001190 uses these opts to set flags, and the flags are read
1191 by the kernel vfs layer before we get here (ie
1192 before read super) so there is no point trying to
1193 parse these options again and set anything and it
1194 is ok to just ignore them */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 continue;
1196 } else if (strnicmp(data, "ro", 2) == 0) {
Steve French4b18f2a2008-04-29 00:06:05 +00001197 vol->rw = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 } else if (strnicmp(data, "hard", 4) == 0) {
1199 vol->retry = 1;
1200 } else if (strnicmp(data, "soft", 4) == 0) {
1201 vol->retry = 0;
1202 } else if (strnicmp(data, "perm", 4) == 0) {
1203 vol->noperm = 0;
1204 } else if (strnicmp(data, "noperm", 6) == 0) {
1205 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001206 } else if (strnicmp(data, "mapchars", 8) == 0) {
1207 vol->remap = 1;
1208 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1209 vol->remap = 0;
Steve French50c2f752007-07-13 00:33:32 +00001210 } else if (strnicmp(data, "sfu", 3) == 0) {
1211 vol->sfu_emul = 1;
1212 } else if (strnicmp(data, "nosfu", 5) == 0) {
1213 vol->sfu_emul = 0;
Jeremy Allisonac670552005-06-22 17:26:35 -07001214 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1215 vol->posix_paths = 1;
1216 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1217 vol->posix_paths = 0;
Steve Frenchc18c8422007-07-18 23:21:09 +00001218 } else if (strnicmp(data, "nounix", 6) == 0) {
1219 vol->no_linux_ext = 1;
1220 } else if (strnicmp(data, "nolinux", 7) == 0) {
1221 vol->no_linux_ext = 1;
Steve French50c2f752007-07-13 00:33:32 +00001222 } else if ((strnicmp(data, "nocase", 6) == 0) ||
Steve Frencha10faeb22005-08-22 21:38:31 -07001223 (strnicmp(data, "ignorecase", 10) == 0)) {
Steve French50c2f752007-07-13 00:33:32 +00001224 vol->nocase = 1;
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001225 } else if (strnicmp(data, "brl", 3) == 0) {
1226 vol->nobrl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001227 } else if ((strnicmp(data, "nobrl", 5) == 0) ||
Steve French1c955182005-08-30 20:58:07 -07001228 (strnicmp(data, "nolock", 6) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001229 vol->nobrl = 1;
Steve Frenchd3485d32005-08-19 11:04:29 -07001230 /* turn off mandatory locking in mode
1231 if remote locking is turned off since the
1232 local vfs will do advisory */
Steve French50c2f752007-07-13 00:33:32 +00001233 if (vol->file_mode ==
1234 (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
Steve Frenchd3485d32005-08-19 11:04:29 -07001235 vol->file_mode = S_IALLUGO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 } else if (strnicmp(data, "setuids", 7) == 0) {
1237 vol->setuids = 1;
1238 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1239 vol->setuids = 0;
1240 } else if (strnicmp(data, "nohard", 6) == 0) {
1241 vol->retry = 0;
1242 } else if (strnicmp(data, "nosoft", 6) == 0) {
1243 vol->retry = 1;
1244 } else if (strnicmp(data, "nointr", 6) == 0) {
1245 vol->intr = 0;
1246 } else if (strnicmp(data, "intr", 4) == 0) {
1247 vol->intr = 1;
Steve French50c2f752007-07-13 00:33:32 +00001248 } else if (strnicmp(data, "serverino", 7) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 vol->server_ino = 1;
Steve French50c2f752007-07-13 00:33:32 +00001250 } else if (strnicmp(data, "noserverino", 9) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 vol->server_ino = 0;
Steve French50c2f752007-07-13 00:33:32 +00001252 } else if (strnicmp(data, "cifsacl", 7) == 0) {
Steve French0a4b92c2006-01-12 15:44:21 -08001253 vol->cifs_acl = 1;
1254 } else if (strnicmp(data, "nocifsacl", 9) == 0) {
1255 vol->cifs_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001256 } else if (strnicmp(data, "acl", 3) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 vol->no_psx_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001258 } else if (strnicmp(data, "noacl", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 vol->no_psx_acl = 1;
Steve French50c2f752007-07-13 00:33:32 +00001260 } else if (strnicmp(data, "sign", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +00001261 vol->secFlg |= CIFSSEC_MUST_SIGN;
1262/* } else if (strnicmp(data, "seal",4) == 0) {
1263 vol->secFlg |= CIFSSEC_MUST_SEAL; */
Steve French50c2f752007-07-13 00:33:32 +00001264 } else if (strnicmp(data, "direct", 6) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001266 } else if (strnicmp(data, "forcedirectio", 13) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001268 } else if (strnicmp(data, "in6_addr", 8) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 if (!value || !*value) {
1270 vol->in6_addr = NULL;
1271 } else if (strnlen(value, 49) == 48) {
1272 vol->in6_addr = value;
1273 } else {
Steve French50c2f752007-07-13 00:33:32 +00001274 printk(KERN_WARNING "CIFS: ip v6 address not "
1275 "48 characters long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 return 1;
1277 }
1278 } else if (strnicmp(data, "noac", 4) == 0) {
Steve French50c2f752007-07-13 00:33:32 +00001279 printk(KERN_WARNING "CIFS: Mount option noac not "
1280 "supported. Instead set "
1281 "/proc/fs/cifs/LookupCacheEnabled to 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 } else
Steve French50c2f752007-07-13 00:33:32 +00001283 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",
1284 data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 }
1286 if (vol->UNC == NULL) {
Steve French4523cc32007-04-30 20:13:06 +00001287 if (devname == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001288 printk(KERN_WARNING "CIFS: Missing UNC name for mount "
1289 "target\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 return 1;
1291 }
1292 if ((temp_len = strnlen(devname, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001293 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001294 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001296 strcpy(vol->UNC, devname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 if (strncmp(vol->UNC, "//", 2) == 0) {
1298 vol->UNC[0] = '\\';
1299 vol->UNC[1] = '\\';
1300 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Steve French50c2f752007-07-13 00:33:32 +00001301 printk(KERN_WARNING "CIFS: UNC Path does not "
1302 "begin with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 return 1;
1304 }
Igor Mammedov7c5e6282008-05-08 20:48:42 +00001305 value = strpbrk(vol->UNC+2, "/\\");
1306 if (value)
1307 *value = '\\';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 } else {
1309 printk(KERN_WARNING "CIFS: UNC name too long\n");
1310 return 1;
1311 }
1312 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001313 if (vol->UNCip == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 vol->UNCip = &vol->UNC[2];
1315
1316 return 0;
1317}
1318
1319static struct cifsSesInfo *
Steve French50c2f752007-07-13 00:33:32 +00001320cifs_find_tcp_session(struct in_addr *target_ip_addr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 struct in6_addr *target_ip6_addr,
1322 char *userName, struct TCP_Server_Info **psrvTcp)
1323{
1324 struct list_head *tmp;
1325 struct cifsSesInfo *ses;
1326 *psrvTcp = NULL;
1327 read_lock(&GlobalSMBSeslock);
1328
1329 list_for_each(tmp, &GlobalSMBSessionList) {
1330 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
1331 if (ses->server) {
Steve French50c2f752007-07-13 00:33:32 +00001332 if ((target_ip_addr &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 (ses->server->addr.sockAddr.sin_addr.s_addr
1334 == target_ip_addr->s_addr)) || (target_ip6_addr
1335 && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
Steve French50c2f752007-07-13 00:33:32 +00001336 target_ip6_addr, sizeof(*target_ip6_addr)))) {
1337 /* BB lock server and tcp session and increment
1338 use count here?? */
1339
1340 /* found a match on the TCP session */
1341 *psrvTcp = ses->server;
1342
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 /* BB check if reconnection needed */
1344 if (strncmp
1345 (ses->userName, userName,
1346 MAX_USERNAME_SIZE) == 0){
1347 read_unlock(&GlobalSMBSeslock);
Steve French50c2f752007-07-13 00:33:32 +00001348 /* Found exact match on both TCP and
1349 SMB sessions */
1350 return ses;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 }
1352 }
1353 }
1354 /* else tcp and smb sessions need reconnection */
1355 }
1356 read_unlock(&GlobalSMBSeslock);
1357 return NULL;
1358}
1359
1360static struct cifsTconInfo *
1361find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
1362{
1363 struct list_head *tmp;
1364 struct cifsTconInfo *tcon;
Steve Frenchdea570e02008-05-06 22:05:51 +00001365 __be32 old_ip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366
1367 read_lock(&GlobalSMBSeslock);
Steve Frenchdea570e02008-05-06 22:05:51 +00001368
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 list_for_each(tmp, &GlobalTreeConnectionList) {
Steve Frenche466e482006-08-15 13:07:18 +00001370 cFYI(1, ("Next tcon"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
Steve Frenchdea570e02008-05-06 22:05:51 +00001372 if (!tcon->ses || !tcon->ses->server)
1373 continue;
1374
1375 old_ip = tcon->ses->server->addr.sockAddr.sin_addr.s_addr;
1376 cFYI(1, ("old ip addr: %x == new ip %x ?",
1377 old_ip, new_target_ip_addr));
1378
1379 if (old_ip != new_target_ip_addr)
1380 continue;
1381
1382 /* BB lock tcon, server, tcp session and increment use count? */
1383 /* found a match on the TCP session */
1384 /* BB check if reconnection needed */
1385 cFYI(1, ("IP match, old UNC: %s new: %s",
1386 tcon->treeName, uncName));
1387
1388 if (strncmp(tcon->treeName, uncName, MAX_TREE_SIZE))
1389 continue;
1390
1391 cFYI(1, ("and old usr: %s new: %s",
1392 tcon->treeName, uncName));
1393
1394 if (strncmp(tcon->ses->userName, userName, MAX_USERNAME_SIZE))
1395 continue;
1396
1397 /* matched smb session (user name) */
1398 read_unlock(&GlobalSMBSeslock);
1399 return tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 }
Steve Frenchdea570e02008-05-06 22:05:51 +00001401
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 read_unlock(&GlobalSMBSeslock);
1403 return NULL;
1404}
1405
1406int
1407connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
Steve French737b7582005-04-28 22:41:06 -07001408 const char *old_path, const struct nls_table *nls_codepage,
1409 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410{
Steve French366781c2008-01-25 10:12:41 +00001411 struct dfs_info3_param *referrals = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 unsigned int num_referrals;
1413 int rc = 0;
1414
Steve French50c2f752007-07-13 00:33:32 +00001415 rc = get_dfs_path(xid, pSesInfo, old_path, nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07001416 &num_referrals, &referrals, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417
1418 /* BB Add in code to: if valid refrl, if not ip address contact
Steve French50c2f752007-07-13 00:33:32 +00001419 the helper that resolves tcp names, mount to it, try to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 tcon to it unmount it if fail */
1421
Jesper Juhlf99d49a2005-11-07 01:01:34 -08001422 kfree(referrals);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423
1424 return rc;
1425}
1426
1427int
Steve French50c2f752007-07-13 00:33:32 +00001428get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
1429 const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
Steve French366781c2008-01-25 10:12:41 +00001430 struct dfs_info3_param **preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431{
1432 char *temp_unc;
1433 int rc = 0;
Steve French366781c2008-01-25 10:12:41 +00001434 unsigned char *targetUNCs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435
1436 *pnum_referrals = 0;
Steve French366781c2008-01-25 10:12:41 +00001437 *preferrals = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438
1439 if (pSesInfo->ipc_tid == 0) {
1440 temp_unc = kmalloc(2 /* for slashes */ +
Steve French50c2f752007-07-13 00:33:32 +00001441 strnlen(pSesInfo->serverName,
1442 SERVER_NAME_LEN_WITH_NULL * 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 + 1 + 4 /* slash IPC$ */ + 2,
1444 GFP_KERNEL);
1445 if (temp_unc == NULL)
1446 return -ENOMEM;
1447 temp_unc[0] = '\\';
1448 temp_unc[1] = '\\';
1449 strcpy(temp_unc + 2, pSesInfo->serverName);
1450 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1451 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1452 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00001453 ("CIFS Tcon rc = %d ipc_tid = %d", rc, pSesInfo->ipc_tid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 kfree(temp_unc);
1455 }
1456 if (rc == 0)
Steve French366781c2008-01-25 10:12:41 +00001457 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, &targetUNCs,
Steve French737b7582005-04-28 22:41:06 -07001458 pnum_referrals, nls_codepage, remap);
Steve French366781c2008-01-25 10:12:41 +00001459 /* BB map targetUNCs to dfs_info3 structures, here or
1460 in CIFSGetDFSRefer BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461
1462 return rc;
1463}
1464
1465/* See RFC1001 section 14 on representation of Netbios names */
Steve French50c2f752007-07-13 00:33:32 +00001466static void rfc1002mangle(char *target, char *source, unsigned int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467{
Steve French50c2f752007-07-13 00:33:32 +00001468 unsigned int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469
Steve French50c2f752007-07-13 00:33:32 +00001470 for (i = 0, j = 0; i < (length); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 /* mask a nibble at a time and encode */
1472 target[j] = 'A' + (0x0F & (source[i] >> 4));
1473 target[j+1] = 'A' + (0x0F & source[i]);
Steve French50c2f752007-07-13 00:33:32 +00001474 j += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 }
1476
1477}
1478
1479
1480static int
Steve French50c2f752007-07-13 00:33:32 +00001481ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
1482 char *netbios_name, char *target_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483{
1484 int rc = 0;
1485 int connected = 0;
1486 __be16 orig_port = 0;
1487
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001488 if (*csocket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001489 rc = sock_create_kern(PF_INET, SOCK_STREAM,
1490 IPPROTO_TCP, csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001492 cERROR(1, ("Error %d creating socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 *csocket = NULL;
1494 return rc;
1495 } else {
1496 /* BB other socket options to set KEEPALIVE, NODELAY? */
Steve French467a8f82007-06-27 22:41:32 +00001497 cFYI(1, ("Socket created"));
Steve French50c2f752007-07-13 00:33:32 +00001498 (*csocket)->sk->sk_allocation = GFP_NOFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 }
1500 }
1501
1502 psin_server->sin_family = AF_INET;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001503 if (psin_server->sin_port) { /* user overrode default port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 rc = (*csocket)->ops->connect(*csocket,
1505 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001506 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 if (rc >= 0)
1508 connected = 1;
Steve French50c2f752007-07-13 00:33:32 +00001509 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001511 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001512 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 later if fall back ports fail this time */
1514 orig_port = psin_server->sin_port;
1515
1516 /* do not retry on the same port we just failed on */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001517 if (psin_server->sin_port != htons(CIFS_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 psin_server->sin_port = htons(CIFS_PORT);
1519
1520 rc = (*csocket)->ops->connect(*csocket,
1521 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001522 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 if (rc >= 0)
1524 connected = 1;
1525 }
1526 }
1527 if (!connected) {
1528 psin_server->sin_port = htons(RFC1001_PORT);
1529 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
Steve French50c2f752007-07-13 00:33:32 +00001530 psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001531 sizeof(struct sockaddr_in), 0);
Steve French50c2f752007-07-13 00:33:32 +00001532 if (rc >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 connected = 1;
1534 }
1535
1536 /* give up here - unless we want to retry on different
1537 protocol families some day */
1538 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001539 if (orig_port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 psin_server->sin_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001541 cFYI(1, ("Error %d connecting to server via ipv4", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 sock_release(*csocket);
1543 *csocket = NULL;
1544 return rc;
1545 }
Steve French50c2f752007-07-13 00:33:32 +00001546 /* Eventually check for other socket options to change from
1547 the default. sock_setsockopt not used because it expects
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 user space buffer */
Steve French50c2f752007-07-13 00:33:32 +00001549 cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",
1550 (*csocket)->sk->sk_sndbuf,
Steve Frenchb387eae2005-10-10 14:21:15 -07001551 (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve Frenchb387eae2005-10-10 14:21:15 -07001553 /* make the bufsizes depend on wsize/rsize and max requests */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001554 if ((*csocket)->sk->sk_sndbuf < (200 * 1024))
Steve Frenchb387eae2005-10-10 14:21:15 -07001555 (*csocket)->sk->sk_sndbuf = 200 * 1024;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001556 if ((*csocket)->sk->sk_rcvbuf < (140 * 1024))
Steve Frenchb387eae2005-10-10 14:21:15 -07001557 (*csocket)->sk->sk_rcvbuf = 140 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558
1559 /* send RFC1001 sessinit */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001560 if (psin_server->sin_port == htons(RFC1001_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 /* some servers require RFC1001 sessinit before sending
Steve French50c2f752007-07-13 00:33:32 +00001562 negprot - BB check reconnection in case where second
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 sessinit is sent but no second negprot */
Steve French50c2f752007-07-13 00:33:32 +00001564 struct rfc1002_session_packet *ses_init_buf;
1565 struct smb_hdr *smb_buf;
1566 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
1567 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001568 if (ses_init_buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 ses_init_buf->trailer.session_req.called_len = 32;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001570 if (target_name && (target_name[0] != 0)) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001571 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
1572 target_name, 16);
1573 } else {
1574 rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
Steve French50c2f752007-07-13 00:33:32 +00001575 DEFAULT_CIFS_CALLED_NAME, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001576 }
1577
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 ses_init_buf->trailer.session_req.calling_len = 32;
1579 /* calling name ends in null (byte 16) from old smb
1580 convention. */
Steve French50c2f752007-07-13 00:33:32 +00001581 if (netbios_name && (netbios_name[0] != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
Steve French50c2f752007-07-13 00:33:32 +00001583 netbios_name, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 } else {
1585 rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
Steve French50c2f752007-07-13 00:33:32 +00001586 "LINUX_CIFS_CLNT", 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 }
1588 ses_init_buf->trailer.session_req.scope1 = 0;
1589 ses_init_buf->trailer.session_req.scope2 = 0;
1590 smb_buf = (struct smb_hdr *)ses_init_buf;
1591 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1592 smb_buf->smb_buf_length = 0x81000044;
1593 rc = smb_send(*csocket, smb_buf, 0x44,
1594 (struct sockaddr *)psin_server);
1595 kfree(ses_init_buf);
Steve French50c2f752007-07-13 00:33:32 +00001596 msleep(1); /* RFC1001 layer in at least one server
Steve French083d3a2c2006-03-03 09:53:36 +00001597 requires very short break before negprot
1598 presumably because not expecting negprot
1599 to follow so fast. This is a simple
Steve French50c2f752007-07-13 00:33:32 +00001600 solution that works without
Steve French083d3a2c2006-03-03 09:53:36 +00001601 complicating the code and causes no
1602 significant slowing down on mount
1603 for everyone else */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 }
Steve French50c2f752007-07-13 00:33:32 +00001605 /* else the negprot may still work without this
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 even though malloc failed */
Steve French50c2f752007-07-13 00:33:32 +00001607
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 }
Steve French50c2f752007-07-13 00:33:32 +00001609
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 return rc;
1611}
1612
1613static int
1614ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1615{
1616 int rc = 0;
1617 int connected = 0;
1618 __be16 orig_port = 0;
1619
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001620 if (*csocket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001621 rc = sock_create_kern(PF_INET6, SOCK_STREAM,
1622 IPPROTO_TCP, csocket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001624 cERROR(1, ("Error %d creating ipv6 socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 *csocket = NULL;
1626 return rc;
1627 } else {
1628 /* BB other socket options to set KEEPALIVE, NODELAY? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001629 cFYI(1, ("ipv6 Socket created"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 (*csocket)->sk->sk_allocation = GFP_NOFS;
1631 }
1632 }
1633
1634 psin_server->sin6_family = AF_INET6;
1635
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001636 if (psin_server->sin6_port) { /* user overrode default port */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 rc = (*csocket)->ops->connect(*csocket,
1638 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001639 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 if (rc >= 0)
1641 connected = 1;
Steve French50c2f752007-07-13 00:33:32 +00001642 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001644 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001645 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 later if fall back ports fail this time */
1647
1648 orig_port = psin_server->sin6_port;
1649 /* do not retry on the same port we just failed on */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001650 if (psin_server->sin6_port != htons(CIFS_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 psin_server->sin6_port = htons(CIFS_PORT);
1652
1653 rc = (*csocket)->ops->connect(*csocket,
1654 (struct sockaddr *) psin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001655 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 if (rc >= 0)
1657 connected = 1;
1658 }
1659 }
1660 if (!connected) {
1661 psin_server->sin6_port = htons(RFC1001_PORT);
1662 rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001663 psin_server, sizeof(struct sockaddr_in6), 0);
Steve French50c2f752007-07-13 00:33:32 +00001664 if (rc >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 connected = 1;
1666 }
1667
1668 /* give up here - unless we want to retry on different
1669 protocol families some day */
1670 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001671 if (orig_port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 psin_server->sin6_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001673 cFYI(1, ("Error %d connecting to server via ipv6", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 sock_release(*csocket);
1675 *csocket = NULL;
1676 return rc;
1677 }
Steve French50c2f752007-07-13 00:33:32 +00001678 /* Eventually check for other socket options to change from
1679 the default. sock_setsockopt not used because it expects
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 user space buffer */
1681 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
Steve French50c2f752007-07-13 00:33:32 +00001682
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 return rc;
1684}
1685
Steve French50c2f752007-07-13 00:33:32 +00001686void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
1687 struct super_block *sb, struct smb_vol *vol_info)
Steve French8af18972007-02-14 04:42:51 +00001688{
1689 /* if we are reconnecting then should we check to see if
1690 * any requested capabilities changed locally e.g. via
1691 * remount but we can not do much about it here
1692 * if they have (even if we could detect it by the following)
1693 * Perhaps we could add a backpointer to array of sb from tcon
1694 * or if we change to make all sb to same share the same
1695 * sb as NFS - then we only have one backpointer to sb.
1696 * What if we wanted to mount the server share twice once with
1697 * and once without posixacls or posix paths? */
1698 __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001699
Steve Frenchc18c8422007-07-18 23:21:09 +00001700 if (vol_info && vol_info->no_linux_ext) {
1701 tcon->fsUnixInfo.Capability = 0;
1702 tcon->unix_ext = 0; /* Unix Extensions disabled */
1703 cFYI(1, ("Linux protocol extensions disabled"));
1704 return;
1705 } else if (vol_info)
1706 tcon->unix_ext = 1; /* Unix Extensions supported */
1707
1708 if (tcon->unix_ext == 0) {
1709 cFYI(1, ("Unix extensions disabled so not set on reconnect"));
1710 return;
1711 }
Steve French50c2f752007-07-13 00:33:32 +00001712
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001713 if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
Steve French8af18972007-02-14 04:42:51 +00001714 __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001715
Steve French8af18972007-02-14 04:42:51 +00001716 /* check for reconnect case in which we do not
1717 want to change the mount behavior if we can avoid it */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001718 if (vol_info == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001719 /* turn off POSIX ACL and PATHNAMES if not set
Steve French8af18972007-02-14 04:42:51 +00001720 originally at mount time */
1721 if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
1722 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00001723 if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
1724 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
1725 cERROR(1, ("POSIXPATH support change"));
Steve French8af18972007-02-14 04:42:51 +00001726 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00001727 } else if ((cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
1728 cERROR(1, ("possible reconnect error"));
1729 cERROR(1,
1730 ("server disabled POSIX path support"));
1731 }
Steve French8af18972007-02-14 04:42:51 +00001732 }
Steve French50c2f752007-07-13 00:33:32 +00001733
Steve French8af18972007-02-14 04:42:51 +00001734 cap &= CIFS_UNIX_CAP_MASK;
Steve French75865f8c2007-06-24 18:30:48 +00001735 if (vol_info && vol_info->no_psx_acl)
Steve French8af18972007-02-14 04:42:51 +00001736 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00001737 else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001738 cFYI(1, ("negotiated posix acl support"));
1739 if (sb)
Steve French8af18972007-02-14 04:42:51 +00001740 sb->s_flags |= MS_POSIXACL;
1741 }
1742
Steve French75865f8c2007-06-24 18:30:48 +00001743 if (vol_info && vol_info->posix_paths == 0)
Steve French8af18972007-02-14 04:42:51 +00001744 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00001745 else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001746 cFYI(1, ("negotiate posix pathnames"));
Steve French75865f8c2007-06-24 18:30:48 +00001747 if (sb)
Steve French50c2f752007-07-13 00:33:32 +00001748 CIFS_SB(sb)->mnt_cifs_flags |=
Steve French8af18972007-02-14 04:42:51 +00001749 CIFS_MOUNT_POSIX_PATHS;
1750 }
Steve French50c2f752007-07-13 00:33:32 +00001751
Steve French984acfe2007-04-26 16:42:50 +00001752 /* We might be setting the path sep back to a different
1753 form if we are reconnecting and the server switched its
Steve French50c2f752007-07-13 00:33:32 +00001754 posix path capability for this share */
Steve French75865f8c2007-06-24 18:30:48 +00001755 if (sb && (CIFS_SB(sb)->prepathlen > 0))
Steve French984acfe2007-04-26 16:42:50 +00001756 CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
Steve French75865f8c2007-06-24 18:30:48 +00001757
1758 if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
1759 if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
1760 CIFS_SB(sb)->rsize = 127 * 1024;
Steve French90c81e02008-02-12 20:32:36 +00001761 cFYI(DBG2,
1762 ("larger reads not supported by srv"));
Steve French75865f8c2007-06-24 18:30:48 +00001763 }
1764 }
Steve French50c2f752007-07-13 00:33:32 +00001765
1766
1767 cFYI(1, ("Negotiate caps 0x%x", (int)cap));
Steve French8af18972007-02-14 04:42:51 +00001768#ifdef CONFIG_CIFS_DEBUG2
Steve French75865f8c2007-06-24 18:30:48 +00001769 if (cap & CIFS_UNIX_FCNTL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001770 cFYI(1, ("FCNTL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001771 if (cap & CIFS_UNIX_EXTATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001772 cFYI(1, ("EXTATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001773 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001774 cFYI(1, ("POSIX path cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001775 if (cap & CIFS_UNIX_XATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001776 cFYI(1, ("XATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001777 if (cap & CIFS_UNIX_POSIX_ACL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001778 cFYI(1, ("POSIX ACL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001779 if (cap & CIFS_UNIX_LARGE_READ_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001780 cFYI(1, ("very large read cap"));
Steve French75865f8c2007-06-24 18:30:48 +00001781 if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001782 cFYI(1, ("very large write cap"));
Steve French8af18972007-02-14 04:42:51 +00001783#endif /* CIFS_DEBUG2 */
1784 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
Steve French442aa312007-09-24 20:25:46 +00001785 if (vol_info == NULL) {
Steve French5a44b312007-09-20 15:16:24 +00001786 cFYI(1, ("resetting capabilities failed"));
Steve French442aa312007-09-24 20:25:46 +00001787 } else
Steve French5a44b312007-09-20 15:16:24 +00001788 cERROR(1, ("Negotiating Unix capabilities "
1789 "with the server failed. Consider "
1790 "mounting with the Unix Extensions\n"
1791 "disabled, if problems are found, "
1792 "by specifying the nounix mount "
Steve French2224f4e2007-09-20 15:37:29 +00001793 "option."));
Steve French5a44b312007-09-20 15:16:24 +00001794
Steve French8af18972007-02-14 04:42:51 +00001795 }
1796 }
1797}
1798
Steve French03a143c2008-02-14 06:38:30 +00001799static void
1800convert_delimiter(char *path, char delim)
1801{
1802 int i;
Steve Frenchc2d68ea2008-02-15 19:20:18 +00001803 char old_delim;
Steve French03a143c2008-02-14 06:38:30 +00001804
1805 if (path == NULL)
1806 return;
1807
Steve Frenchc2d68ea2008-02-15 19:20:18 +00001808 if (delim == '/')
1809 old_delim = '\\';
1810 else
1811 old_delim = '/';
1812
Steve French03a143c2008-02-14 06:38:30 +00001813 for (i = 0; path[i] != '\0'; i++) {
Steve Frenchc2d68ea2008-02-15 19:20:18 +00001814 if (path[i] == old_delim)
Steve French03a143c2008-02-14 06:38:30 +00001815 path[i] = delim;
1816 }
1817}
1818
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819int
1820cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1821 char *mount_data, const char *devname)
1822{
1823 int rc = 0;
1824 int xid;
1825 int address_type = AF_INET;
1826 struct socket *csocket = NULL;
1827 struct sockaddr_in sin_server;
1828 struct sockaddr_in6 sin_server6;
1829 struct smb_vol volume_info;
1830 struct cifsSesInfo *pSesInfo = NULL;
1831 struct cifsSesInfo *existingCifsSes = NULL;
1832 struct cifsTconInfo *tcon = NULL;
1833 struct TCP_Server_Info *srvTcp = NULL;
1834
1835 xid = GetXid();
1836
1837/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
Steve French50c2f752007-07-13 00:33:32 +00001838
1839 memset(&volume_info, 0, sizeof(struct smb_vol));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001841 rc = -EINVAL;
1842 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 }
1844
Jeff Layton8426c392007-05-05 03:27:49 +00001845 if (volume_info.nullauth) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001846 cFYI(1, ("null user"));
Jeff Layton9b8f5f52007-11-09 23:25:04 +00001847 volume_info.username = "";
Jeff Layton8426c392007-05-05 03:27:49 +00001848 } else if (volume_info.username) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 /* BB fixme parse for domain name here */
Steve French467a8f82007-06-27 22:41:32 +00001850 cFYI(1, ("Username: %s", volume_info.username));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 } else {
Steve Frenchbf820672005-12-01 22:32:42 -08001852 cifserror("No username specified");
Steve French50c2f752007-07-13 00:33:32 +00001853 /* In userspace mount helper we can get user name from alternate
1854 locations such as env variables and files on disk */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001855 rc = -EINVAL;
1856 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 }
1858
1859 if (volume_info.UNCip && volume_info.UNC) {
Steve French50c2f752007-07-13 00:33:32 +00001860 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,
1861 &sin_server.sin_addr.s_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001863 if (rc <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 /* not ipv4 address, try ipv6 */
Steve French50c2f752007-07-13 00:33:32 +00001865 rc = cifs_inet_pton(AF_INET6, volume_info.UNCip,
1866 &sin_server6.sin6_addr.in6_u);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001867 if (rc > 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 address_type = AF_INET6;
1869 } else {
1870 address_type = AF_INET;
1871 }
Steve French50c2f752007-07-13 00:33:32 +00001872
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001873 if (rc <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 /* we failed translating address */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001875 rc = -EINVAL;
1876 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 }
1878
1879 cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
1880 /* success */
1881 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00001882 } else if (volume_info.UNCip) {
1883 /* BB using ip addr as server name to connect to the
1884 DFS root below */
1885 cERROR(1, ("Connecting to DFS root not implemented yet"));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001886 rc = -EINVAL;
1887 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 } else /* which servers DFS root would we conect to */ {
1889 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00001890 ("CIFS mount error: No UNC path (e.g. -o "
1891 "unc=//192.168.1.100/public) specified"));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001892 rc = -EINVAL;
1893 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 }
1895
1896 /* this is needed for ASCII cp to Unicode converts */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001897 if (volume_info.iocharset == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 cifs_sb->local_nls = load_nls_default();
1899 /* load_nls_default can not return null */
1900 } else {
1901 cifs_sb->local_nls = load_nls(volume_info.iocharset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001902 if (cifs_sb->local_nls == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001903 cERROR(1, ("CIFS mount error: iocharset %s not found",
1904 volume_info.iocharset));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001905 rc = -ELIBACC;
1906 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 }
1908 }
1909
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001910 if (address_type == AF_INET)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
1912 NULL /* no ipv6 addr */,
1913 volume_info.username, &srvTcp);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001914 else if (address_type == AF_INET6) {
1915 cFYI(1, ("looking for ipv6 address"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1917 &sin_server6.sin6_addr,
1918 volume_info.username, &srvTcp);
Steve French5858ae42007-04-25 11:59:10 +00001919 } else {
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001920 rc = -EINVAL;
1921 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 }
1923
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 if (srvTcp) {
Steve French50c2f752007-07-13 00:33:32 +00001925 cFYI(1, ("Existing tcp session with server found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 } else { /* create socket */
Steve French4523cc32007-04-30 20:13:06 +00001927 if (volume_info.port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 sin_server.sin_port = htons(volume_info.port);
1929 else
1930 sin_server.sin_port = 0;
Steve French5858ae42007-04-25 11:59:10 +00001931 if (address_type == AF_INET6) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001932 cFYI(1, ("attempting ipv6 connect"));
Steve French5858ae42007-04-25 11:59:10 +00001933 /* BB should we allow ipv6 on port 139? */
1934 /* other OS never observed in Wild doing 139 with v6 */
Steve French50c2f752007-07-13 00:33:32 +00001935 rc = ipv6_connect(&sin_server6, &csocket);
1936 } else
1937 rc = ipv4_connect(&sin_server, &csocket,
Steve Frencha10faeb22005-08-22 21:38:31 -07001938 volume_info.source_rfc1001_name,
1939 volume_info.target_rfc1001_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001941 cERROR(1, ("Error connecting to IPv4 socket. "
1942 "Aborting operation"));
Steve French4523cc32007-04-30 20:13:06 +00001943 if (csocket != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 sock_release(csocket);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001945 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 }
1947
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00001948 srvTcp = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
1949 if (!srvTcp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 rc = -ENOMEM;
1951 sock_release(csocket);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001952 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 } else {
Steve French50c2f752007-07-13 00:33:32 +00001954 memcpy(&srvTcp->addr.sockAddr, &sin_server,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001955 sizeof(struct sockaddr_in));
Steve French50c2f752007-07-13 00:33:32 +00001956 atomic_set(&srvTcp->inFlight, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957 /* BB Add code for ipv6 case too */
1958 srvTcp->ssocket = csocket;
1959 srvTcp->protocolType = IPV4;
Jeff Laytonc359cf32007-11-16 22:22:06 +00001960 srvTcp->hostname = extract_hostname(volume_info.UNC);
1961 if (IS_ERR(srvTcp->hostname)) {
1962 rc = PTR_ERR(srvTcp->hostname);
1963 sock_release(csocket);
1964 goto out;
1965 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966 init_waitqueue_head(&srvTcp->response_q);
1967 init_waitqueue_head(&srvTcp->request_q);
1968 INIT_LIST_HEAD(&srvTcp->pending_mid_q);
1969 /* at this point we are the only ones with the pointer
1970 to the struct since the kernel thread not created yet
1971 so no need to spinlock this init of tcpStatus */
1972 srvTcp->tcpStatus = CifsNew;
1973 init_MUTEX(&srvTcp->tcpSem);
Igor Mammedovaaf737a2007-04-03 19:16:43 +00001974 srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd");
Steve French8840dee2007-11-16 23:05:52 +00001975 if (IS_ERR(srvTcp->tsk)) {
Igor Mammedovaaf737a2007-04-03 19:16:43 +00001976 rc = PTR_ERR(srvTcp->tsk);
Steve French50c2f752007-07-13 00:33:32 +00001977 cERROR(1, ("error %d create cifsd thread", rc));
Igor Mammedovaaf737a2007-04-03 19:16:43 +00001978 srvTcp->tsk = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 sock_release(csocket);
Jeff Laytonc359cf32007-11-16 22:22:06 +00001980 kfree(srvTcp->hostname);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00001981 goto out;
Steve Frenchf1914012005-08-18 09:37:34 -07001982 }
Steve Frenchf1914012005-08-18 09:37:34 -07001983 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00001984 memcpy(srvTcp->workstation_RFC1001_name,
1985 volume_info.source_rfc1001_name, 16);
1986 memcpy(srvTcp->server_RFC1001_name,
1987 volume_info.target_rfc1001_name, 16);
Steve Frenchad009ac2005-04-28 22:41:05 -07001988 srvTcp->sequence_number = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989 }
1990 }
1991
1992 if (existingCifsSes) {
1993 pSesInfo = existingCifsSes;
Jeff Layton1d9a8852007-12-31 01:37:11 +00001994 cFYI(1, ("Existing smb sess found (status=%d)",
1995 pSesInfo->status));
Steve French88e7d702008-01-03 17:37:09 +00001996 down(&pSesInfo->sesSem);
Jeff Layton1d9a8852007-12-31 01:37:11 +00001997 if (pSesInfo->status == CifsNeedReconnect) {
1998 cFYI(1, ("Session needs reconnect"));
Jeff Layton1d9a8852007-12-31 01:37:11 +00001999 rc = cifs_setup_session(xid, pSesInfo,
2000 cifs_sb->local_nls);
Jeff Layton1d9a8852007-12-31 01:37:11 +00002001 }
Steve French88e7d702008-01-03 17:37:09 +00002002 up(&pSesInfo->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 } else if (!rc) {
Steve Frenchbf820672005-12-01 22:32:42 -08002004 cFYI(1, ("Existing smb sess not found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 pSesInfo = sesInfoAlloc();
2006 if (pSesInfo == NULL)
2007 rc = -ENOMEM;
2008 else {
2009 pSesInfo->server = srvTcp;
2010 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
2011 NIPQUAD(sin_server.sin_addr.s_addr));
2012 }
2013
Steve French50c2f752007-07-13 00:33:32 +00002014 if (!rc) {
2015 /* volume_info.password freed at unmount */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002016 if (volume_info.password) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 pSesInfo->password = volume_info.password;
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002018 /* set to NULL to prevent freeing on exit */
2019 volume_info.password = NULL;
2020 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021 if (volume_info.username)
2022 strncpy(pSesInfo->userName,
Steve French50c2f752007-07-13 00:33:32 +00002023 volume_info.username,
2024 MAX_USERNAME_SIZE);
Steve French39798772006-05-31 22:40:51 +00002025 if (volume_info.domainname) {
2026 int len = strlen(volume_info.domainname);
Steve French50c2f752007-07-13 00:33:32 +00002027 pSesInfo->domainName =
Steve French39798772006-05-31 22:40:51 +00002028 kmalloc(len + 1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00002029 if (pSesInfo->domainName)
Steve French39798772006-05-31 22:40:51 +00002030 strcpy(pSesInfo->domainName,
2031 volume_info.domainname);
2032 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 pSesInfo->linux_uid = volume_info.linux_uid;
Steve French750d1152006-06-27 06:28:30 +00002034 pSesInfo->overrideSecFlg = volume_info.secFlg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035 down(&pSesInfo->sesSem);
Steve French189acaa2006-06-23 02:33:48 +00002036 /* BB FIXME need to pass vol->secFlgs BB */
Steve French50c2f752007-07-13 00:33:32 +00002037 rc = cifs_setup_session(xid, pSesInfo,
2038 cifs_sb->local_nls);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 up(&pSesInfo->sesSem);
Steve French4523cc32007-04-30 20:13:06 +00002040 if (!rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041 atomic_inc(&srvTcp->socketUseCount);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002042 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 }
Steve French50c2f752007-07-13 00:33:32 +00002044
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 /* search for existing tcon to this server share */
2046 if (!rc) {
Steve French4523cc32007-04-30 20:13:06 +00002047 if (volume_info.rsize > CIFSMaxBufSize) {
Steve French50c2f752007-07-13 00:33:32 +00002048 cERROR(1, ("rsize %d too large, using MaxBufSize",
Steve French0ae0efa2005-10-10 10:57:19 -07002049 volume_info.rsize));
2050 cifs_sb->rsize = CIFSMaxBufSize;
Steve French75865f8c2007-06-24 18:30:48 +00002051 } else if ((volume_info.rsize) &&
2052 (volume_info.rsize <= CIFSMaxBufSize))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053 cifs_sb->rsize = volume_info.rsize;
Steve French0ae0efa2005-10-10 10:57:19 -07002054 else /* default */
2055 cifs_sb->rsize = CIFSMaxBufSize;
2056
Steve French4523cc32007-04-30 20:13:06 +00002057 if (volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
Steve French50c2f752007-07-13 00:33:32 +00002058 cERROR(1, ("wsize %d too large, using 4096 instead",
Steve French0ae0efa2005-10-10 10:57:19 -07002059 volume_info.wsize));
2060 cifs_sb->wsize = 4096;
Steve French4523cc32007-04-30 20:13:06 +00002061 } else if (volume_info.wsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 cifs_sb->wsize = volume_info.wsize;
2063 else
Steve French50c2f752007-07-13 00:33:32 +00002064 cifs_sb->wsize =
Steve French1877c9e2006-01-27 18:36:11 -08002065 min_t(const int, PAGEVEC_SIZE * PAGE_CACHE_SIZE,
2066 127*1024);
Steve French17cbbaf2006-01-24 20:26:48 -08002067 /* old default of CIFSMaxBufSize was too small now
Steve French50c2f752007-07-13 00:33:32 +00002068 that SMB Write2 can send multiple pages in kvec.
Steve French17cbbaf2006-01-24 20:26:48 -08002069 RFC1001 does not describe what happens when frame
2070 bigger than 128K is sent so use that as max in
2071 conjunction with 52K kvec constraint on arch with 4K
2072 page size */
2073
Steve French4523cc32007-04-30 20:13:06 +00002074 if (cifs_sb->rsize < 2048) {
Steve French50c2f752007-07-13 00:33:32 +00002075 cifs_sb->rsize = 2048;
Steve French6cec2ae2006-02-22 17:31:52 -06002076 /* Windows ME may prefer this */
Steve French467a8f82007-06-27 22:41:32 +00002077 cFYI(1, ("readsize set to minimum: 2048"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078 }
Steve French2fe87f02006-09-21 07:02:52 +00002079 /* calculate prepath */
2080 cifs_sb->prepath = volume_info.prepath;
Steve French4523cc32007-04-30 20:13:06 +00002081 if (cifs_sb->prepath) {
Steve French2fe87f02006-09-21 07:02:52 +00002082 cifs_sb->prepathlen = strlen(cifs_sb->prepath);
Steve French03a143c2008-02-14 06:38:30 +00002083 /* we can not convert the / to \ in the path
2084 separators in the prefixpath yet because we do not
2085 know (until reset_cifs_unix_caps is called later)
2086 whether POSIX PATH CAP is available. We normalize
2087 the / to \ after reset_cifs_unix_caps is called */
Steve French2fe87f02006-09-21 07:02:52 +00002088 volume_info.prepath = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002089 } else
Steve French2fe87f02006-09-21 07:02:52 +00002090 cifs_sb->prepathlen = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 cifs_sb->mnt_uid = volume_info.linux_uid;
2092 cifs_sb->mnt_gid = volume_info.linux_gid;
2093 cifs_sb->mnt_file_mode = volume_info.file_mode;
2094 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
Steve French467a8f82007-06-27 22:41:32 +00002095 cFYI(1, ("file mode: 0x%x dir mode: 0x%x",
2096 cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097
Steve French4523cc32007-04-30 20:13:06 +00002098 if (volume_info.noperm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
Steve French4523cc32007-04-30 20:13:06 +00002100 if (volume_info.setuids)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
Steve French4523cc32007-04-30 20:13:06 +00002102 if (volume_info.server_ino)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
Steve French4523cc32007-04-30 20:13:06 +00002104 if (volume_info.remap)
Steve French6a0b4822005-04-28 22:41:05 -07002105 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
Steve French4523cc32007-04-30 20:13:06 +00002106 if (volume_info.no_xattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
Steve French4523cc32007-04-30 20:13:06 +00002108 if (volume_info.sfu_emul)
Steve Frenchd7245c22005-07-14 18:25:12 -05002109 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
Steve French4523cc32007-04-30 20:13:06 +00002110 if (volume_info.nobrl)
Steve Frenchc46fa8a2005-08-18 20:49:57 -07002111 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
Steve French4523cc32007-04-30 20:13:06 +00002112 if (volume_info.cifs_acl)
Steve French0a4b92c2006-01-12 15:44:21 -08002113 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
Steve French4523cc32007-04-30 20:13:06 +00002114 if (volume_info.override_uid)
2115 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
2116 if (volume_info.override_gid)
2117 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
2118 if (volume_info.direct_io) {
Steve French467a8f82007-06-27 22:41:32 +00002119 cFYI(1, ("mounting share using direct i/o"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
2121 }
2122
2123 tcon =
2124 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
2125 volume_info.username);
2126 if (tcon) {
Steve Frenchbf820672005-12-01 22:32:42 -08002127 cFYI(1, ("Found match on UNC path"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128 /* we can have only one retry value for a connection
2129 to a share so for resources mounted more than once
Steve French50c2f752007-07-13 00:33:32 +00002130 to the same server share the last value passed in
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131 for the retry flag is used */
2132 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07002133 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134 } else {
2135 tcon = tconInfoAlloc();
2136 if (tcon == NULL)
2137 rc = -ENOMEM;
2138 else {
Steve French50c2f752007-07-13 00:33:32 +00002139 /* check for null share name ie connecting to
Steve French8af18972007-02-14 04:42:51 +00002140 * dfs root */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141
Steve French50c2f752007-07-13 00:33:32 +00002142 /* BB check if this works for exactly length
Steve French8af18972007-02-14 04:42:51 +00002143 * three strings */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
2145 && (strchr(volume_info.UNC + 3, '/') ==
2146 NULL)) {
Steve French737b7582005-04-28 22:41:06 -07002147 rc = connect_to_dfs_path(xid, pSesInfo,
Steve French8af18972007-02-14 04:42:51 +00002148 "", cifs_sb->local_nls,
Steve French50c2f752007-07-13 00:33:32 +00002149 cifs_sb->mnt_cifs_flags &
Steve French8af18972007-02-14 04:42:51 +00002150 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002151 rc = -ENODEV;
2152 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 } else {
Steve French8af18972007-02-14 04:42:51 +00002154 /* BB Do we need to wrap sesSem around
2155 * this TCon call and Unix SetFS as
2156 * we do on SessSetup and reconnect? */
Steve French50c2f752007-07-13 00:33:32 +00002157 rc = CIFSTCon(xid, pSesInfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 volume_info.UNC,
2159 tcon, cifs_sb->local_nls);
2160 cFYI(1, ("CIFS Tcon rc = %d", rc));
2161 }
2162 if (!rc) {
2163 atomic_inc(&pSesInfo->inUse);
2164 tcon->retry = volume_info.retry;
Steve Frenchd3485d32005-08-19 11:04:29 -07002165 tcon->nocase = volume_info.nocase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 }
2167 }
2168 }
2169 }
Steve French4523cc32007-04-30 20:13:06 +00002170 if (pSesInfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
2172 sb->s_maxbytes = (u64) 1 << 63;
2173 } else
2174 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
2175 }
2176
Steve French8af18972007-02-14 04:42:51 +00002177 /* BB FIXME fix time_gran to be larger for LANMAN sessions */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178 sb->s_time_gran = 100;
2179
2180/* on error free sesinfo and tcon struct if needed */
2181 if (rc) {
2182 /* if session setup failed, use count is zero but
2183 we still need to free cifsd thread */
Steve French4523cc32007-04-30 20:13:06 +00002184 if (atomic_read(&srvTcp->socketUseCount) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185 spin_lock(&GlobalMid_Lock);
2186 srvTcp->tcpStatus = CifsExiting;
2187 spin_unlock(&GlobalMid_Lock);
Steve French4523cc32007-04-30 20:13:06 +00002188 if (srvTcp->tsk) {
Steve French28356a12007-05-23 14:45:36 +00002189 struct task_struct *tsk;
2190 /* If we could verify that kthread_stop would
2191 always wake up processes blocked in
2192 tcp in recv_mesg then we could remove the
2193 send_sig call */
Steve French50c2f752007-07-13 00:33:32 +00002194 force_sig(SIGKILL, srvTcp->tsk);
Steve French28356a12007-05-23 14:45:36 +00002195 tsk = srvTcp->tsk;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002196 if (tsk)
Steve Frenchf7f7c312007-05-24 02:29:51 +00002197 kthread_stop(tsk);
Steve Frenchf1914012005-08-18 09:37:34 -07002198 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199 }
2200 /* If find_unc succeeded then rc == 0 so we can not end */
2201 if (tcon) /* up accidently freeing someone elses tcon struct */
2202 tconInfoFree(tcon);
2203 if (existingCifsSes == NULL) {
2204 if (pSesInfo) {
Steve French50c2f752007-07-13 00:33:32 +00002205 if ((pSesInfo->server) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206 (pSesInfo->status == CifsGood)) {
2207 int temp_rc;
2208 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
2209 /* if the socketUseCount is now zero */
Steve French4523cc32007-04-30 20:13:06 +00002210 if ((temp_rc == -ESHUTDOWN) &&
Steve French50c2f752007-07-13 00:33:32 +00002211 (pSesInfo->server) &&
Jeff5d9c7202007-06-25 22:16:35 +00002212 (pSesInfo->server->tsk)) {
Steve French28356a12007-05-23 14:45:36 +00002213 struct task_struct *tsk;
Jeff5d9c7202007-06-25 22:16:35 +00002214 force_sig(SIGKILL,
2215 pSesInfo->server->tsk);
Steve French28356a12007-05-23 14:45:36 +00002216 tsk = pSesInfo->server->tsk;
Steve Frenchf7f7c312007-05-24 02:29:51 +00002217 if (tsk)
Steve French28356a12007-05-23 14:45:36 +00002218 kthread_stop(tsk);
Steve Frenchf1914012005-08-18 09:37:34 -07002219 }
Steve Frencha0136892007-10-04 20:05:09 +00002220 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 cFYI(1, ("No session or bad tcon"));
Steve Frencha0136892007-10-04 20:05:09 +00002222 if ((pSesInfo->server) &&
2223 (pSesInfo->server->tsk)) {
2224 struct task_struct *tsk;
2225 force_sig(SIGKILL,
2226 pSesInfo->server->tsk);
2227 tsk = pSesInfo->server->tsk;
2228 if (tsk)
2229 kthread_stop(tsk);
2230 }
2231 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 sesInfoFree(pSesInfo);
2233 /* pSesInfo = NULL; */
2234 }
2235 }
2236 } else {
2237 atomic_inc(&tcon->useCount);
2238 cifs_sb->tcon = tcon;
2239 tcon->ses = pSesInfo;
2240
Steve French82940a42006-03-02 03:24:57 +00002241 /* do not care if following two calls succeed - informational */
Steve French7f8ed422007-09-28 22:28:55 +00002242 if (!tcon->ipc) {
2243 CIFSSMBQFSDeviceInfo(xid, tcon);
2244 CIFSSMBQFSAttributeInfo(xid, tcon);
2245 }
Steve French50c2f752007-07-13 00:33:32 +00002246
Steve French8af18972007-02-14 04:42:51 +00002247 /* tell server which Unix caps we support */
2248 if (tcon->ses->capabilities & CAP_UNIX)
Steve Frenchc18c8422007-07-18 23:21:09 +00002249 /* reset of caps checks mount to see if unix extensions
2250 disabled for just this mount */
Steve French8af18972007-02-14 04:42:51 +00002251 reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
Steve Frenchc18c8422007-07-18 23:21:09 +00002252 else
2253 tcon->unix_ext = 0; /* server does not support them */
2254
Steve French03a143c2008-02-14 06:38:30 +00002255 /* convert forward to back slashes in prepath here if needed */
Igor Mammedov11b6d642008-02-15 19:06:04 +00002256 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
2257 convert_delimiter(cifs_sb->prepath,
2258 CIFS_DIR_SEP(cifs_sb));
Steve French03a143c2008-02-14 06:38:30 +00002259
Steve Frenchc18c8422007-07-18 23:21:09 +00002260 if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
Steve French75865f8c2007-06-24 18:30:48 +00002261 cifs_sb->rsize = 1024 * 127;
Steve French90c81e02008-02-12 20:32:36 +00002262 cFYI(DBG2,
2263 ("no very large read support, rsize now 127K"));
Steve French75865f8c2007-06-24 18:30:48 +00002264 }
Steve French3e844692005-10-03 13:37:24 -07002265 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
2266 cifs_sb->wsize = min(cifs_sb->wsize,
2267 (tcon->ses->server->maxBuf -
2268 MAX_CIFS_HDR_SIZE));
Steve French0ae0efa2005-10-10 10:57:19 -07002269 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
Steve French50c2f752007-07-13 00:33:32 +00002270 cifs_sb->rsize = min(cifs_sb->rsize,
2271 (tcon->ses->server->maxBuf -
2272 MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273 }
2274
2275 /* volume_info.password is freed above when existing session found
2276 (in which case it is not needed anymore) but when new sesion is created
2277 the password ptr is put in the new session structure (in which case the
2278 password will be freed at unmount time) */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002279out:
2280 /* zero out password before freeing */
2281 if (volume_info.password != NULL) {
2282 memset(volume_info.password, 0, strlen(volume_info.password));
2283 kfree(volume_info.password);
2284 }
Jesper Juhlf99d49a2005-11-07 01:01:34 -08002285 kfree(volume_info.UNC);
Steve French2fe87f02006-09-21 07:02:52 +00002286 kfree(volume_info.prepath);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287 FreeXid(xid);
2288 return rc;
2289}
2290
2291static int
2292CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French7c7b25b2006-06-01 19:20:10 +00002293 char session_key[CIFS_SESS_KEY_SIZE],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294 const struct nls_table *nls_codepage)
2295{
2296 struct smb_hdr *smb_buffer;
2297 struct smb_hdr *smb_buffer_response;
2298 SESSION_SETUP_ANDX *pSMB;
2299 SESSION_SETUP_ANDX *pSMBr;
2300 char *bcc_ptr;
2301 char *user;
2302 char *domain;
2303 int rc = 0;
2304 int remaining_words = 0;
2305 int bytes_returned = 0;
2306 int len;
2307 __u32 capabilities;
2308 __u16 count;
2309
Steve Frencheeac8042006-01-13 21:34:58 -08002310 cFYI(1, ("In sesssetup"));
Steve French4523cc32007-04-30 20:13:06 +00002311 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 return -EINVAL;
2313 user = ses->userName;
2314 domain = ses->domainName;
2315 smb_buffer = cifs_buf_get();
2316 if (smb_buffer == NULL) {
2317 return -ENOMEM;
2318 }
2319 smb_buffer_response = smb_buffer;
2320 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2321
2322 /* send SMBsessionSetup here */
2323 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2324 NULL /* no tCon exists yet */ , 13 /* wct */ );
2325
Steve French1982c342005-08-17 12:38:22 -07002326 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327 pSMB->req_no_secext.AndXCommand = 0xFF;
2328 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2329 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2330
Steve French50c2f752007-07-13 00:33:32 +00002331 if (ses->server->secMode &
2332 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2334
2335 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2336 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
2337 if (ses->capabilities & CAP_UNICODE) {
2338 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2339 capabilities |= CAP_UNICODE;
2340 }
2341 if (ses->capabilities & CAP_STATUS32) {
2342 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2343 capabilities |= CAP_STATUS32;
2344 }
2345 if (ses->capabilities & CAP_DFS) {
2346 smb_buffer->Flags2 |= SMBFLG2_DFS;
2347 capabilities |= CAP_DFS;
2348 }
2349 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
2350
Steve French50c2f752007-07-13 00:33:32 +00002351 pSMB->req_no_secext.CaseInsensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002352 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353
2354 pSMB->req_no_secext.CaseSensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002355 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356 bcc_ptr = pByteArea(smb_buffer);
Steve French7c7b25b2006-06-01 19:20:10 +00002357 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2358 bcc_ptr += CIFS_SESS_KEY_SIZE;
2359 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2360 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361
2362 if (ses->capabilities & CAP_UNICODE) {
2363 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
2364 *bcc_ptr = 0;
2365 bcc_ptr++;
2366 }
Steve French4523cc32007-04-30 20:13:06 +00002367 if (user == NULL)
Steve French39798772006-05-31 22:40:51 +00002368 bytes_returned = 0; /* skip null user */
Steve French50c2f752007-07-13 00:33:32 +00002369 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370 bytes_returned =
Steve French50c2f752007-07-13 00:33:32 +00002371 cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 nls_codepage);
2373 /* convert number of 16 bit words to bytes */
2374 bcc_ptr += 2 * bytes_returned;
2375 bcc_ptr += 2; /* trailing null */
2376 if (domain == NULL)
2377 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002378 cifs_strtoUCS((__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379 "CIFS_LINUX_DOM", 32, nls_codepage);
2380 else
2381 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002382 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383 nls_codepage);
2384 bcc_ptr += 2 * bytes_returned;
2385 bcc_ptr += 2;
2386 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002387 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388 32, nls_codepage);
2389 bcc_ptr += 2 * bytes_returned;
2390 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002391 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392 32, nls_codepage);
2393 bcc_ptr += 2 * bytes_returned;
2394 bcc_ptr += 2;
2395 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002396 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397 64, nls_codepage);
2398 bcc_ptr += 2 * bytes_returned;
2399 bcc_ptr += 2;
2400 } else {
Steve French50c2f752007-07-13 00:33:32 +00002401 if (user != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402 strncpy(bcc_ptr, user, 200);
2403 bcc_ptr += strnlen(user, 200);
2404 }
2405 *bcc_ptr = 0;
2406 bcc_ptr++;
2407 if (domain == NULL) {
2408 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2409 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2410 } else {
2411 strncpy(bcc_ptr, domain, 64);
2412 bcc_ptr += strnlen(domain, 64);
2413 *bcc_ptr = 0;
2414 bcc_ptr++;
2415 }
2416 strcpy(bcc_ptr, "Linux version ");
2417 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002418 strcpy(bcc_ptr, utsname()->release);
2419 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2421 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2422 }
2423 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2424 smb_buffer->smb_buf_length += count;
2425 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2426
2427 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00002428 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429 if (rc) {
2430/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2431 } else if ((smb_buffer_response->WordCount == 3)
2432 || (smb_buffer_response->WordCount == 4)) {
2433 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2434 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2435 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002436 cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */
2437 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format
2438 (little endian) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439 cFYI(1, ("UID = %d ", ses->Suid));
Steve French50c2f752007-07-13 00:33:32 +00002440 /* response can have either 3 or 4 word count - Samba sends 3 */
2441 bcc_ptr = pByteArea(smb_buffer_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 if ((pSMBr->resp.hdr.WordCount == 3)
2443 || ((pSMBr->resp.hdr.WordCount == 4)
2444 && (blob_len < pSMBr->resp.ByteCount))) {
2445 if (pSMBr->resp.hdr.WordCount == 4)
2446 bcc_ptr += blob_len;
2447
2448 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2449 if ((long) (bcc_ptr) % 2) {
2450 remaining_words =
Steve French50c2f752007-07-13 00:33:32 +00002451 (BCC(smb_buffer_response) - 1) / 2;
2452 /* Unicode strings must be word
2453 aligned */
2454 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455 } else {
2456 remaining_words =
2457 BCC(smb_buffer_response) / 2;
2458 }
2459 len =
2460 UniStrnlen((wchar_t *) bcc_ptr,
2461 remaining_words - 1);
2462/* We look for obvious messed up bcc or strings in response so we do not go off
2463 the end since (at least) WIN2K and Windows XP have a major bug in not null
2464 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002465 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002466 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002467 ses->serverOS = kzalloc(2 * (len + 1),
2468 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002469 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002470 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 cifs_strfromUCS_le(ses->serverOS,
Steve French50c2f752007-07-13 00:33:32 +00002472 (__le16 *)bcc_ptr,
2473 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474 bcc_ptr += 2 * (len + 1);
2475 remaining_words -= len + 1;
2476 ses->serverOS[2 * len] = 0;
2477 ses->serverOS[1 + (2 * len)] = 0;
2478 if (remaining_words > 0) {
2479 len = UniStrnlen((wchar_t *)bcc_ptr,
2480 remaining_words-1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002481 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002482 ses->serverNOS = kzalloc(2 * (len + 1),
2483 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002484 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002485 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 cifs_strfromUCS_le(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002487 (__le16 *)bcc_ptr,
2488 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489 bcc_ptr += 2 * (len + 1);
2490 ses->serverNOS[2 * len] = 0;
2491 ses->serverNOS[1 + (2 * len)] = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002492 if (strncmp(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002493 "NT LAN Manager 4", 16) == 0) {
Steve French467a8f82007-06-27 22:41:32 +00002494 cFYI(1, ("NT4 server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495 ses->flags |= CIFS_SES_NT4;
2496 }
2497 remaining_words -= len + 1;
2498 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002499 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Steve French50c2f752007-07-13 00:33:32 +00002500 /* last string is not always null terminated
2501 (for e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002502 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002503 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504 ses->serverDomain =
Steve French50c2f752007-07-13 00:33:32 +00002505 kzalloc(2*(len+1),
2506 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002507 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002508 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509 cifs_strfromUCS_le(ses->serverDomain,
Steve French50c2f752007-07-13 00:33:32 +00002510 (__le16 *)bcc_ptr,
2511 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512 bcc_ptr += 2 * (len + 1);
2513 ses->serverDomain[2*len] = 0;
2514 ses->serverDomain[1+(2*len)] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002515 } else { /* else no more room so create
2516 dummy domain string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002517 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002518 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002519 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002520 kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002521 }
Steve French50c2f752007-07-13 00:33:32 +00002522 } else { /* no room so create dummy domain
2523 and NOS string */
2524
Steve French433dc242005-04-28 22:41:08 -07002525 /* if these kcallocs fail not much we
2526 can do, but better to not fail the
2527 sesssetup itself */
Steve Frenchcd49b492006-06-26 04:22:36 +00002528 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002530 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002531 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002533 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534 }
2535 } else { /* ASCII */
2536 len = strnlen(bcc_ptr, 1024);
2537 if (((long) bcc_ptr + len) - (long)
2538 pByteArea(smb_buffer_response)
2539 <= BCC(smb_buffer_response)) {
Steve Frenchcd49b492006-06-26 04:22:36 +00002540 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002541 ses->serverOS = kzalloc(len + 1,
2542 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002543 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002544 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002545 strncpy(ses->serverOS, bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546
2547 bcc_ptr += len;
Steve French50c2f752007-07-13 00:33:32 +00002548 /* null terminate the string */
2549 bcc_ptr[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550 bcc_ptr++;
2551
2552 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002553 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002554 ses->serverNOS = kzalloc(len + 1,
2555 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002556 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002557 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558 strncpy(ses->serverNOS, bcc_ptr, len);
2559 bcc_ptr += len;
2560 bcc_ptr[0] = 0;
2561 bcc_ptr++;
2562
2563 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002564 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002565 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002566 ses->serverDomain = kzalloc(len + 1,
2567 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002568 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002569 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002570 strncpy(ses->serverDomain, bcc_ptr,
2571 len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572 bcc_ptr += len;
2573 bcc_ptr[0] = 0;
2574 bcc_ptr++;
2575 } else
2576 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00002577 ("Variable field of length %d "
2578 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579 len));
2580 }
2581 } else {
2582 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00002583 (" Security Blob Length extends beyond "
2584 "end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585 }
2586 } else {
2587 cERROR(1,
2588 (" Invalid Word count %d: ",
2589 smb_buffer_response->WordCount));
2590 rc = -EIO;
2591 }
Steve French433dc242005-04-28 22:41:08 -07002592sesssetup_nomem: /* do not return an error on nomem for the info strings,
2593 since that could make reconnection harder, and
2594 reconnection might be needed to free memory */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00002595 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596
2597 return rc;
2598}
2599
2600static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
Steve French4b18f2a2008-04-29 00:06:05 +00002602 struct cifsSesInfo *ses, bool *pNTLMv2_flag,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 const struct nls_table *nls_codepage)
2604{
2605 struct smb_hdr *smb_buffer;
2606 struct smb_hdr *smb_buffer_response;
2607 SESSION_SETUP_ANDX *pSMB;
2608 SESSION_SETUP_ANDX *pSMBr;
2609 char *bcc_ptr;
2610 char *domain;
2611 int rc = 0;
2612 int remaining_words = 0;
2613 int bytes_returned = 0;
2614 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002615 int SecurityBlobLength = sizeof(NEGOTIATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 PNEGOTIATE_MESSAGE SecurityBlob;
2617 PCHALLENGE_MESSAGE SecurityBlob2;
2618 __u32 negotiate_flags, capabilities;
2619 __u16 count;
2620
Steve French12b3b8f2006-02-09 21:12:47 +00002621 cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002622 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623 return -EINVAL;
2624 domain = ses->domainName;
Steve French4b18f2a2008-04-29 00:06:05 +00002625 *pNTLMv2_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626 smb_buffer = cifs_buf_get();
2627 if (smb_buffer == NULL) {
2628 return -ENOMEM;
2629 }
2630 smb_buffer_response = smb_buffer;
2631 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2632 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2633
2634 /* send SMBsessionSetup here */
2635 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2636 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002637
2638 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2640 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2641
2642 pSMB->req.AndXCommand = 0xFF;
2643 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2644 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2645
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002646 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2648
2649 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2650 CAP_EXTENDED_SECURITY;
2651 if (ses->capabilities & CAP_UNICODE) {
2652 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2653 capabilities |= CAP_UNICODE;
2654 }
2655 if (ses->capabilities & CAP_STATUS32) {
2656 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2657 capabilities |= CAP_STATUS32;
2658 }
2659 if (ses->capabilities & CAP_DFS) {
2660 smb_buffer->Flags2 |= SMBFLG2_DFS;
2661 capabilities |= CAP_DFS;
2662 }
2663 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2664
2665 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2666 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2667 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2668 SecurityBlob->MessageType = NtLmNegotiate;
2669 negotiate_flags =
2670 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
Steve French12b3b8f2006-02-09 21:12:47 +00002671 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
2672 NTLMSSP_NEGOTIATE_56 |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002674 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002676/* if (ntlmv2_support)
Steve French39798772006-05-31 22:40:51 +00002677 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 /* setup pointers to domain name and workstation name */
2679 bcc_ptr += SecurityBlobLength;
2680
2681 SecurityBlob->WorkstationName.Buffer = 0;
2682 SecurityBlob->WorkstationName.Length = 0;
2683 SecurityBlob->WorkstationName.MaximumLength = 0;
2684
Steve French12b3b8f2006-02-09 21:12:47 +00002685 /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent
2686 along with username on auth request (ie the response to challenge) */
2687 SecurityBlob->DomainName.Buffer = 0;
2688 SecurityBlob->DomainName.Length = 0;
2689 SecurityBlob->DomainName.MaximumLength = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 if (ses->capabilities & CAP_UNICODE) {
2691 if ((long) bcc_ptr % 2) {
2692 *bcc_ptr = 0;
2693 bcc_ptr++;
2694 }
2695
2696 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002697 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698 32, nls_codepage);
2699 bcc_ptr += 2 * bytes_returned;
2700 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002701 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702 nls_codepage);
2703 bcc_ptr += 2 * bytes_returned;
2704 bcc_ptr += 2; /* null terminate Linux version */
2705 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002706 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 64, nls_codepage);
2708 bcc_ptr += 2 * bytes_returned;
2709 *(bcc_ptr + 1) = 0;
2710 *(bcc_ptr + 2) = 0;
2711 bcc_ptr += 2; /* null terminate network opsys string */
2712 *(bcc_ptr + 1) = 0;
2713 *(bcc_ptr + 2) = 0;
2714 bcc_ptr += 2; /* null domain */
2715 } else { /* ASCII */
2716 strcpy(bcc_ptr, "Linux version ");
2717 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002718 strcpy(bcc_ptr, utsname()->release);
2719 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2721 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2722 bcc_ptr++; /* empty domain field */
2723 *bcc_ptr = 0;
2724 }
2725 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2726 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2727 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2728 smb_buffer->smb_buf_length += count;
2729 pSMB->req.ByteCount = cpu_to_le16(count);
2730
2731 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00002732 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733
2734 if (smb_buffer_response->Status.CifsError ==
2735 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2736 rc = 0;
2737
2738 if (rc) {
2739/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2740 } else if ((smb_buffer_response->WordCount == 3)
2741 || (smb_buffer_response->WordCount == 4)) {
2742 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2743 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2744
2745 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002746 cFYI(1, (" Guest login"));
2747 /* Do we want to set anything in SesInfo struct when guest login? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748
Steve French50c2f752007-07-13 00:33:32 +00002749 bcc_ptr = pByteArea(smb_buffer_response);
2750 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751
2752 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2753 if (SecurityBlob2->MessageType != NtLmChallenge) {
2754 cFYI(1,
2755 ("Unexpected NTLMSSP message type received %d",
2756 SecurityBlob2->MessageType));
2757 } else if (ses) {
Steve French50c2f752007-07-13 00:33:32 +00002758 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
Steve French12b3b8f2006-02-09 21:12:47 +00002759 cFYI(1, ("UID = %d", ses->Suid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 if ((pSMBr->resp.hdr.WordCount == 3)
2761 || ((pSMBr->resp.hdr.WordCount == 4)
2762 && (blob_len <
2763 pSMBr->resp.ByteCount))) {
2764
2765 if (pSMBr->resp.hdr.WordCount == 4) {
2766 bcc_ptr += blob_len;
Steve French12b3b8f2006-02-09 21:12:47 +00002767 cFYI(1, ("Security Blob Length %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 blob_len));
2769 }
2770
Steve French12b3b8f2006-02-09 21:12:47 +00002771 cFYI(1, ("NTLMSSP Challenge rcvd"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772
2773 memcpy(ses->server->cryptKey,
2774 SecurityBlob2->Challenge,
2775 CIFS_CRYPTO_KEY_SIZE);
Steve French50c2f752007-07-13 00:33:32 +00002776 if (SecurityBlob2->NegotiateFlags &
Steve French12b3b8f2006-02-09 21:12:47 +00002777 cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
Steve French4b18f2a2008-04-29 00:06:05 +00002778 *pNTLMv2_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779
Steve French50c2f752007-07-13 00:33:32 +00002780 if ((SecurityBlob2->NegotiateFlags &
2781 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782 || (sign_CIFS_PDUs > 1))
Steve French50c2f752007-07-13 00:33:32 +00002783 ses->server->secMode |=
2784 SECMODE_SIGN_REQUIRED;
2785 if ((SecurityBlob2->NegotiateFlags &
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
Steve French50c2f752007-07-13 00:33:32 +00002787 ses->server->secMode |=
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 SECMODE_SIGN_ENABLED;
2789
2790 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2791 if ((long) (bcc_ptr) % 2) {
2792 remaining_words =
2793 (BCC(smb_buffer_response)
2794 - 1) / 2;
Steve French50c2f752007-07-13 00:33:32 +00002795 /* Must word align unicode strings */
2796 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797 } else {
2798 remaining_words =
2799 BCC
2800 (smb_buffer_response) / 2;
2801 }
2802 len =
2803 UniStrnlen((wchar_t *) bcc_ptr,
2804 remaining_words - 1);
2805/* We look for obvious messed up bcc or strings in response so we do not go off
2806 the end since (at least) WIN2K and Windows XP have a major bug in not null
2807 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002808 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002809 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002811 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002813 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814 bcc_ptr, len,
2815 nls_codepage);
2816 bcc_ptr += 2 * (len + 1);
2817 remaining_words -= len + 1;
2818 ses->serverOS[2 * len] = 0;
2819 ses->serverOS[1 + (2 * len)] = 0;
2820 if (remaining_words > 0) {
2821 len = UniStrnlen((wchar_t *)
2822 bcc_ptr,
2823 remaining_words
2824 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002825 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002827 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 GFP_KERNEL);
2829 cifs_strfromUCS_le(ses->
2830 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002831 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 bcc_ptr,
2833 len,
2834 nls_codepage);
2835 bcc_ptr += 2 * (len + 1);
2836 ses->serverNOS[2 * len] = 0;
2837 ses->serverNOS[1 +
2838 (2 * len)] = 0;
2839 remaining_words -= len + 1;
2840 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00002841 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2842 /* last string not always null terminated
2843 (for e.g. for Windows XP & 2000) */
Steve Frenchcd49b492006-06-26 04:22:36 +00002844 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002846 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847 (len +
2848 1),
2849 GFP_KERNEL);
2850 cifs_strfromUCS_le
Steve Frenche89dc922005-11-11 15:18:19 -08002851 (ses->serverDomain,
2852 (__le16 *)bcc_ptr,
2853 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002854 bcc_ptr +=
2855 2 * (len + 1);
Steve Frenche89dc922005-11-11 15:18:19 -08002856 ses->serverDomain[2*len]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857 = 0;
Steve Frenche89dc922005-11-11 15:18:19 -08002858 ses->serverDomain
2859 [1 + (2 * len)]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 = 0;
2861 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002862 else {
Steve Frenchcd49b492006-06-26 04:22:36 +00002863 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002865 kzalloc(2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866 GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002867 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868 } else { /* no room so create dummy domain and NOS string */
Steve Frenchcd49b492006-06-26 04:22:36 +00002869 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002871 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002872 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002874 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 }
2876 } else { /* ASCII */
2877 len = strnlen(bcc_ptr, 1024);
2878 if (((long) bcc_ptr + len) - (long)
2879 pByteArea(smb_buffer_response)
2880 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002881 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002882 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002884 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885 GFP_KERNEL);
2886 strncpy(ses->serverOS,
2887 bcc_ptr, len);
2888
2889 bcc_ptr += len;
2890 bcc_ptr[0] = 0; /* null terminate string */
2891 bcc_ptr++;
2892
2893 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002894 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002896 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897 GFP_KERNEL);
2898 strncpy(ses->serverNOS, bcc_ptr, len);
2899 bcc_ptr += len;
2900 bcc_ptr[0] = 0;
2901 bcc_ptr++;
2902
2903 len = strnlen(bcc_ptr, 1024);
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(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +00002908 strncpy(ses->serverDomain,
2909 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910 bcc_ptr += len;
2911 bcc_ptr[0] = 0;
2912 bcc_ptr++;
2913 } else
2914 cFYI(1,
Steve French63135e02007-07-17 17:34:02 +00002915 ("field of length %d "
2916 "extends beyond end of smb",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917 len));
2918 }
2919 } else {
Steve French50c2f752007-07-13 00:33:32 +00002920 cERROR(1, ("Security Blob Length extends beyond"
2921 " end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922 }
2923 } else {
2924 cERROR(1, ("No session structure passed in."));
2925 }
2926 } else {
2927 cERROR(1,
Steve French5815449d2006-02-14 01:36:20 +00002928 (" Invalid Word count %d:",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929 smb_buffer_response->WordCount));
2930 rc = -EIO;
2931 }
2932
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00002933 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934
2935 return rc;
2936}
2937static int
2938CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French4b18f2a2008-04-29 00:06:05 +00002939 char *ntlm_session_key, bool ntlmv2_flag,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002940 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002941{
2942 struct smb_hdr *smb_buffer;
2943 struct smb_hdr *smb_buffer_response;
2944 SESSION_SETUP_ANDX *pSMB;
2945 SESSION_SETUP_ANDX *pSMBr;
2946 char *bcc_ptr;
2947 char *user;
2948 char *domain;
2949 int rc = 0;
2950 int remaining_words = 0;
2951 int bytes_returned = 0;
2952 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002953 int SecurityBlobLength = sizeof(AUTHENTICATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954 PAUTHENTICATE_MESSAGE SecurityBlob;
2955 __u32 negotiate_flags, capabilities;
2956 __u16 count;
2957
2958 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002959 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 return -EINVAL;
2961 user = ses->userName;
2962 domain = ses->domainName;
2963 smb_buffer = cifs_buf_get();
2964 if (smb_buffer == NULL) {
2965 return -ENOMEM;
2966 }
2967 smb_buffer_response = smb_buffer;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002968 pSMB = (SESSION_SETUP_ANDX *)smb_buffer;
2969 pSMBr = (SESSION_SETUP_ANDX *)smb_buffer_response;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970
2971 /* send SMBsessionSetup here */
2972 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2973 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002974
2975 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2977 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2978 pSMB->req.AndXCommand = 0xFF;
2979 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2980 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2981
2982 pSMB->req.hdr.Uid = ses->Suid;
2983
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002984 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2986
2987 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002988 CAP_EXTENDED_SECURITY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989 if (ses->capabilities & CAP_UNICODE) {
2990 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2991 capabilities |= CAP_UNICODE;
2992 }
2993 if (ses->capabilities & CAP_STATUS32) {
2994 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2995 capabilities |= CAP_STATUS32;
2996 }
2997 if (ses->capabilities & CAP_DFS) {
2998 smb_buffer->Flags2 |= SMBFLG2_DFS;
2999 capabilities |= CAP_DFS;
3000 }
3001 pSMB->req.Capabilities = cpu_to_le32(capabilities);
3002
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003003 bcc_ptr = (char *)&pSMB->req.SecurityBlob;
3004 SecurityBlob = (PAUTHENTICATE_MESSAGE)bcc_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
3006 SecurityBlob->MessageType = NtLmAuthenticate;
3007 bcc_ptr += SecurityBlobLength;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003008 negotiate_flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
3009 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
3010 0x80000000 | NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003011 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003013 if (ntlmv2_flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
3015
3016/* setup pointers to domain name and workstation name */
3017
3018 SecurityBlob->WorkstationName.Buffer = 0;
3019 SecurityBlob->WorkstationName.Length = 0;
3020 SecurityBlob->WorkstationName.MaximumLength = 0;
3021 SecurityBlob->SessionKey.Length = 0;
3022 SecurityBlob->SessionKey.MaximumLength = 0;
3023 SecurityBlob->SessionKey.Buffer = 0;
3024
3025 SecurityBlob->LmChallengeResponse.Length = 0;
3026 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
3027 SecurityBlob->LmChallengeResponse.Buffer = 0;
3028
3029 SecurityBlob->NtChallengeResponse.Length =
Steve French7c7b25b2006-06-01 19:20:10 +00003030 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 SecurityBlob->NtChallengeResponse.MaximumLength =
Steve French7c7b25b2006-06-01 19:20:10 +00003032 cpu_to_le16(CIFS_SESS_KEY_SIZE);
3033 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034 SecurityBlob->NtChallengeResponse.Buffer =
3035 cpu_to_le32(SecurityBlobLength);
Steve French7c7b25b2006-06-01 19:20:10 +00003036 SecurityBlobLength += CIFS_SESS_KEY_SIZE;
3037 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038
3039 if (ses->capabilities & CAP_UNICODE) {
3040 if (domain == NULL) {
3041 SecurityBlob->DomainName.Buffer = 0;
3042 SecurityBlob->DomainName.Length = 0;
3043 SecurityBlob->DomainName.MaximumLength = 0;
3044 } else {
Steve French77159b42007-08-31 01:10:17 +00003045 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00003047 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003049 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003050 SecurityBlob->DomainName.Buffer =
3051 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003052 bcc_ptr += ln;
3053 SecurityBlobLength += ln;
3054 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 }
3056 if (user == NULL) {
3057 SecurityBlob->UserName.Buffer = 0;
3058 SecurityBlob->UserName.Length = 0;
3059 SecurityBlob->UserName.MaximumLength = 0;
3060 } else {
Steve French77159b42007-08-31 01:10:17 +00003061 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00003063 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 SecurityBlob->UserName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003065 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 SecurityBlob->UserName.Buffer =
3067 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003068 bcc_ptr += ln;
3069 SecurityBlobLength += ln;
3070 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071 }
3072
Steve French63135e02007-07-17 17:34:02 +00003073 /* SecurityBlob->WorkstationName.Length =
3074 cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075 SecurityBlob->WorkstationName.Length *= 2;
Steve French63135e02007-07-17 17:34:02 +00003076 SecurityBlob->WorkstationName.MaximumLength =
3077 cpu_to_le16(SecurityBlob->WorkstationName.Length);
3078 SecurityBlob->WorkstationName.Buffer =
3079 cpu_to_le32(SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080 bcc_ptr += SecurityBlob->WorkstationName.Length;
3081 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
Steve French63135e02007-07-17 17:34:02 +00003082 SecurityBlob->WorkstationName.Length =
3083 cpu_to_le16(SecurityBlob->WorkstationName.Length); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084
3085 if ((long) bcc_ptr % 2) {
3086 *bcc_ptr = 0;
3087 bcc_ptr++;
3088 }
3089 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003090 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091 32, nls_codepage);
3092 bcc_ptr += 2 * bytes_returned;
3093 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003094 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095 nls_codepage);
3096 bcc_ptr += 2 * bytes_returned;
3097 bcc_ptr += 2; /* null term version string */
3098 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003099 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100 64, nls_codepage);
3101 bcc_ptr += 2 * bytes_returned;
3102 *(bcc_ptr + 1) = 0;
3103 *(bcc_ptr + 2) = 0;
3104 bcc_ptr += 2; /* null terminate network opsys string */
3105 *(bcc_ptr + 1) = 0;
3106 *(bcc_ptr + 2) = 0;
3107 bcc_ptr += 2; /* null domain */
3108 } else { /* ASCII */
3109 if (domain == NULL) {
3110 SecurityBlob->DomainName.Buffer = 0;
3111 SecurityBlob->DomainName.Length = 0;
3112 SecurityBlob->DomainName.MaximumLength = 0;
3113 } else {
Steve French77159b42007-08-31 01:10:17 +00003114 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
3116 strncpy(bcc_ptr, domain, 63);
Steve French77159b42007-08-31 01:10:17 +00003117 ln = strnlen(domain, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003119 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120 SecurityBlob->DomainName.Buffer =
3121 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003122 bcc_ptr += ln;
3123 SecurityBlobLength += ln;
3124 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125 }
3126 if (user == NULL) {
3127 SecurityBlob->UserName.Buffer = 0;
3128 SecurityBlob->UserName.Length = 0;
3129 SecurityBlob->UserName.MaximumLength = 0;
3130 } else {
Steve French77159b42007-08-31 01:10:17 +00003131 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 strncpy(bcc_ptr, user, 63);
Steve French77159b42007-08-31 01:10:17 +00003133 ln = strnlen(user, 64);
3134 SecurityBlob->UserName.MaximumLength = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135 SecurityBlob->UserName.Buffer =
Steve French77159b42007-08-31 01:10:17 +00003136 cpu_to_le32(SecurityBlobLength);
3137 bcc_ptr += ln;
3138 SecurityBlobLength += ln;
3139 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140 }
3141 /* BB fill in our workstation name if known BB */
3142
3143 strcpy(bcc_ptr, "Linux version ");
3144 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003145 strcpy(bcc_ptr, utsname()->release);
3146 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003147 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
3148 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
3149 bcc_ptr++; /* null domain */
3150 *bcc_ptr = 0;
3151 }
3152 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
3153 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
3154 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
3155 smb_buffer->smb_buf_length += count;
3156 pSMB->req.ByteCount = cpu_to_le16(count);
3157
3158 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00003159 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160 if (rc) {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003161/* rc = map_smb_to_linux_error(smb_buffer_response) done in SendReceive now */
3162 } else if ((smb_buffer_response->WordCount == 3) ||
3163 (smb_buffer_response->WordCount == 4)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164 __u16 action = le16_to_cpu(pSMBr->resp.Action);
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003165 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00003167 cFYI(1, (" Guest login")); /* BB Should we set anything
3168 in SesInfo struct ? */
3169/* if (SecurityBlob2->MessageType != NtLm??) {
3170 cFYI("Unexpected message type on auth response is %d"));
3171 } */
3172
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173 if (ses) {
3174 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003175 ("Check challenge UID %d vs auth response UID %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176 ses->Suid, smb_buffer_response->Uid));
Steve French50c2f752007-07-13 00:33:32 +00003177 /* UID left in wire format */
3178 ses->Suid = smb_buffer_response->Uid;
3179 bcc_ptr = pByteArea(smb_buffer_response);
3180 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181 if ((pSMBr->resp.hdr.WordCount == 3)
3182 || ((pSMBr->resp.hdr.WordCount == 4)
3183 && (blob_len <
3184 pSMBr->resp.ByteCount))) {
3185 if (pSMBr->resp.hdr.WordCount == 4) {
3186 bcc_ptr +=
3187 blob_len;
3188 cFYI(1,
3189 ("Security Blob Length %d ",
3190 blob_len));
3191 }
3192
3193 cFYI(1,
3194 ("NTLMSSP response to Authenticate "));
3195
3196 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3197 if ((long) (bcc_ptr) % 2) {
3198 remaining_words =
3199 (BCC(smb_buffer_response)
3200 - 1) / 2;
3201 bcc_ptr++; /* Unicode strings must be word aligned */
3202 } else {
3203 remaining_words = BCC(smb_buffer_response) / 2;
3204 }
Steve French77159b42007-08-31 01:10:17 +00003205 len = UniStrnlen((wchar_t *) bcc_ptr,
3206 remaining_words - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207/* We look for obvious messed up bcc or strings in response so we do not go off
3208 the end since (at least) WIN2K and Windows XP have a major bug in not null
3209 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003210 if (ses->serverOS)
Steve French08775832006-05-30 18:08:26 +00003211 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003213 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003215 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003216 bcc_ptr, len,
3217 nls_codepage);
3218 bcc_ptr += 2 * (len + 1);
3219 remaining_words -= len + 1;
3220 ses->serverOS[2 * len] = 0;
3221 ses->serverOS[1 + (2 * len)] = 0;
3222 if (remaining_words > 0) {
3223 len = UniStrnlen((wchar_t *)
3224 bcc_ptr,
3225 remaining_words
3226 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00003227 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003228 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003229 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230 GFP_KERNEL);
3231 cifs_strfromUCS_le(ses->
3232 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003233 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234 bcc_ptr,
3235 len,
3236 nls_codepage);
3237 bcc_ptr += 2 * (len + 1);
3238 ses->serverNOS[2 * len] = 0;
3239 ses->serverNOS[1+(2*len)] = 0;
3240 remaining_words -= len + 1;
3241 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00003242 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003243 /* last string not always null terminated (e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003244 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003245 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003247 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248 (len +
3249 1),
3250 GFP_KERNEL);
3251 cifs_strfromUCS_le
3252 (ses->
3253 serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08003254 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255 bcc_ptr, len,
3256 nls_codepage);
3257 bcc_ptr +=
3258 2 * (len + 1);
3259 ses->
3260 serverDomain[2
3261 * len]
3262 = 0;
3263 ses->
3264 serverDomain[1
3265 +
3266 (2
3267 *
3268 len)]
3269 = 0;
3270 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003271 else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003272 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003273 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003274 ses->serverDomain = kzalloc(2,GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00003275 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276 } else { /* no room so create dummy domain and NOS string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003277 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003278 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003279 ses->serverDomain = kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00003280 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003281 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282 }
3283 } else { /* ASCII */
3284 len = strnlen(bcc_ptr, 1024);
Steve French50c2f752007-07-13 00:33:32 +00003285 if (((long) bcc_ptr + len) -
3286 (long) pByteArea(smb_buffer_response)
Steve French63135e02007-07-17 17:34:02 +00003287 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003288 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00003289 kfree(ses->serverOS);
Steve French77159b42007-08-31 01:10:17 +00003290 ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003291 strncpy(ses->serverOS,bcc_ptr, len);
3292
3293 bcc_ptr += len;
3294 bcc_ptr[0] = 0; /* null terminate the string */
3295 bcc_ptr++;
3296
3297 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003298 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00003299 ses->serverNOS = kzalloc(len+1,
3300 GFP_KERNEL);
Steve French63135e02007-07-17 17:34:02 +00003301 strncpy(ses->serverNOS,
3302 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003303 bcc_ptr += len;
3304 bcc_ptr[0] = 0;
3305 bcc_ptr++;
3306
3307 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003308 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003309 kfree(ses->serverDomain);
Steve French63135e02007-07-17 17:34:02 +00003310 ses->serverDomain =
3311 kzalloc(len+1,
3312 GFP_KERNEL);
3313 strncpy(ses->serverDomain,
3314 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315 bcc_ptr += len;
3316 bcc_ptr[0] = 0;
3317 bcc_ptr++;
3318 } else
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003319 cFYI(1, ("field of length %d "
Steve French63135e02007-07-17 17:34:02 +00003320 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321 len));
3322 }
3323 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003324 cERROR(1, ("Security Blob extends beyond end "
Steve French63135e02007-07-17 17:34:02 +00003325 "of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326 }
3327 } else {
3328 cERROR(1, ("No session structure passed in."));
3329 }
3330 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003331 cERROR(1, ("Invalid Word count %d: ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332 smb_buffer_response->WordCount));
3333 rc = -EIO;
3334 }
3335
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003336 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003337
3338 return rc;
3339}
3340
3341int
3342CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3343 const char *tree, struct cifsTconInfo *tcon,
3344 const struct nls_table *nls_codepage)
3345{
3346 struct smb_hdr *smb_buffer;
3347 struct smb_hdr *smb_buffer_response;
3348 TCONX_REQ *pSMB;
3349 TCONX_RSP *pSMBr;
3350 unsigned char *bcc_ptr;
3351 int rc = 0;
3352 int length;
3353 __u16 count;
3354
3355 if (ses == NULL)
3356 return -EIO;
3357
3358 smb_buffer = cifs_buf_get();
3359 if (smb_buffer == NULL) {
3360 return -ENOMEM;
3361 }
3362 smb_buffer_response = smb_buffer;
3363
3364 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3365 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003366
3367 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368 smb_buffer->Uid = ses->Suid;
3369 pSMB = (TCONX_REQ *) smb_buffer;
3370 pSMBr = (TCONX_RSP *) smb_buffer_response;
3371
3372 pSMB->AndXCommand = 0xFF;
3373 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003374 bcc_ptr = &pSMB->Password[0];
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003375 if ((ses->server->secMode) & SECMODE_USER) {
Steve Frencheeac8042006-01-13 21:34:58 -08003376 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00003377 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08003378 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00003379 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08003380 } else {
Steve French7c7b25b2006-06-01 19:20:10 +00003381 pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08003382 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
3383 specified as required (when that support is added to
3384 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00003385 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08003386 by Samba (not sure whether other servers allow
3387 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00003388#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French50c2f752007-07-13 00:33:32 +00003389 if ((extended_security & CIFSSEC_MAY_LANMAN) &&
Steve French7c7b25b2006-06-01 19:20:10 +00003390 (ses->server->secType == LANMAN))
3391 calc_lanman_hash(ses, bcc_ptr);
3392 else
3393#endif /* CIFS_WEAK_PW_HASH */
Steve Frencheeac8042006-01-13 21:34:58 -08003394 SMBNTencrypt(ses->password,
3395 ses->server->cryptKey,
3396 bcc_ptr);
3397
Steve French7c7b25b2006-06-01 19:20:10 +00003398 bcc_ptr += CIFS_SESS_KEY_SIZE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003399 if (ses->capabilities & CAP_UNICODE) {
Steve French7c7b25b2006-06-01 19:20:10 +00003400 /* must align unicode strings */
3401 *bcc_ptr = 0; /* null byte password */
3402 bcc_ptr++;
3403 }
Steve Frencheeac8042006-01-13 21:34:58 -08003404 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405
Steve French50c2f752007-07-13 00:33:32 +00003406 if (ses->server->secMode &
Steve Frencha878fb22006-05-30 18:04:19 +00003407 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003408 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3409
3410 if (ses->capabilities & CAP_STATUS32) {
3411 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3412 }
3413 if (ses->capabilities & CAP_DFS) {
3414 smb_buffer->Flags2 |= SMBFLG2_DFS;
3415 }
3416 if (ses->capabilities & CAP_UNICODE) {
3417 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3418 length =
Steve French50c2f752007-07-13 00:33:32 +00003419 cifs_strtoUCS((__le16 *) bcc_ptr, tree,
3420 6 /* max utf8 char length in bytes */ *
Steve Frencha878fb22006-05-30 18:04:19 +00003421 (/* server len*/ + 256 /* share len */), nls_codepage);
3422 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423 bcc_ptr += 2; /* skip trailing null */
3424 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425 strcpy(bcc_ptr, tree);
3426 bcc_ptr += strlen(tree) + 1;
3427 }
3428 strcpy(bcc_ptr, "?????");
3429 bcc_ptr += strlen("?????");
3430 bcc_ptr += 1;
3431 count = bcc_ptr - &pSMB->Password[0];
3432 pSMB->hdr.smb_buf_length += count;
3433 pSMB->ByteCount = cpu_to_le16(count);
3434
Steve French133672e2007-11-13 22:41:37 +00003435 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
3436 CIFS_STD_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437
3438 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3439 /* above now done in SendReceive */
3440 if ((rc == 0) && (tcon != NULL)) {
3441 tcon->tidStatus = CifsGood;
3442 tcon->tid = smb_buffer_response->Tid;
3443 bcc_ptr = pByteArea(smb_buffer_response);
3444 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
Steve French50c2f752007-07-13 00:33:32 +00003445 /* skip service field (NB: this field is always ASCII) */
Steve French7f8ed422007-09-28 22:28:55 +00003446 if (length == 3) {
3447 if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') &&
3448 (bcc_ptr[2] == 'C')) {
3449 cFYI(1, ("IPC connection"));
3450 tcon->ipc = 1;
3451 }
3452 } else if (length == 2) {
3453 if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) {
3454 /* the most common case */
3455 cFYI(1, ("disk share connection"));
3456 }
3457 }
Steve French50c2f752007-07-13 00:33:32 +00003458 bcc_ptr += length + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3460 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3461 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3462 if ((bcc_ptr + (2 * length)) -
3463 pByteArea(smb_buffer_response) <=
3464 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003465 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003467 kzalloc(length + 2, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003468 if (tcon->nativeFileSystem)
3469 cifs_strfromUCS_le(
3470 tcon->nativeFileSystem,
3471 (__le16 *) bcc_ptr,
3472 length, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003473 bcc_ptr += 2 * length;
3474 bcc_ptr[0] = 0; /* null terminate the string */
3475 bcc_ptr[1] = 0;
3476 bcc_ptr += 2;
3477 }
Steve French50c2f752007-07-13 00:33:32 +00003478 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479 } else {
3480 length = strnlen(bcc_ptr, 1024);
3481 if ((bcc_ptr + length) -
3482 pByteArea(smb_buffer_response) <=
3483 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003484 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003485 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003486 kzalloc(length + 1, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003487 if (tcon->nativeFileSystem)
3488 strncpy(tcon->nativeFileSystem, bcc_ptr,
3489 length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490 }
Steve French50c2f752007-07-13 00:33:32 +00003491 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003493 if ((smb_buffer_response->WordCount == 3) ||
Steve French1a4e15a2006-10-12 21:33:51 +00003494 (smb_buffer_response->WordCount == 7))
3495 /* field is in same location */
Steve French39798772006-05-31 22:40:51 +00003496 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3497 else
3498 tcon->Flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3500 } else if ((rc == 0) && tcon == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00003501 /* all we need to save for IPC$ connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502 ses->ipc_tid = smb_buffer_response->Tid;
3503 }
3504
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003505 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506 return rc;
3507}
3508
3509int
3510cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3511{
3512 int rc = 0;
3513 int xid;
3514 struct cifsSesInfo *ses = NULL;
3515 struct task_struct *cifsd_task;
Steve French50c2f752007-07-13 00:33:32 +00003516 char *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003517
3518 xid = GetXid();
3519
3520 if (cifs_sb->tcon) {
3521 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3522 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3523 if (rc == -EBUSY) {
3524 FreeXid(xid);
3525 return 0;
3526 }
Steve French5d941ca2008-04-15 18:40:48 +00003527 DeleteTconOplockQEntries(cifs_sb->tcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528 tconInfoFree(cifs_sb->tcon);
3529 if ((ses) && (ses->server)) {
3530 /* save off task so we do not refer to ses later */
3531 cifsd_task = ses->server->tsk;
3532 cFYI(1, ("About to do SMBLogoff "));
3533 rc = CIFSSMBLogoff(xid, ses);
3534 if (rc == -EBUSY) {
3535 FreeXid(xid);
3536 return 0;
3537 } else if (rc == -ESHUTDOWN) {
Steve French467a8f82007-06-27 22:41:32 +00003538 cFYI(1, ("Waking up socket by sending signal"));
Steve Frenchf7f7c312007-05-24 02:29:51 +00003539 if (cifsd_task) {
Steve French50c2f752007-07-13 00:33:32 +00003540 force_sig(SIGKILL, cifsd_task);
Igor Mammedovaaf737a2007-04-03 19:16:43 +00003541 kthread_stop(cifsd_task);
Steve Frenchf1914012005-08-18 09:37:34 -07003542 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543 rc = 0;
3544 } /* else - we have an smb session
3545 left on this socket do not kill cifsd */
3546 } else
3547 cFYI(1, ("No session or bad tcon"));
3548 }
Steve French50c2f752007-07-13 00:33:32 +00003549
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550 cifs_sb->tcon = NULL;
Steve French2fe87f02006-09-21 07:02:52 +00003551 tmp = cifs_sb->prepath;
3552 cifs_sb->prepathlen = 0;
3553 cifs_sb->prepath = NULL;
3554 kfree(tmp);
Nishanth Aravamudan041e0e32005-09-10 00:27:23 -07003555 if (ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003556 sesInfoFree(ses);
3557
3558 FreeXid(xid);
Steve French88e7d702008-01-03 17:37:09 +00003559 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003560}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003561
3562int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
Steve French50c2f752007-07-13 00:33:32 +00003563 struct nls_table *nls_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003564{
3565 int rc = 0;
Steve French7c7b25b2006-06-01 19:20:10 +00003566 char ntlm_session_key[CIFS_SESS_KEY_SIZE];
Steve French4b18f2a2008-04-29 00:06:05 +00003567 bool ntlmv2_flag = false;
Steve Frenchad009ac2005-04-28 22:41:05 -07003568 int first_time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569
3570 /* what if server changes its buffer size after dropping the session? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003571 if (pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003573 if (rc == -EAGAIN) /* retry only once on 1st time connection */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve French50c2f752007-07-13 00:33:32 +00003575 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576 rc = -EHOSTDOWN;
3577 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003578 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579 spin_lock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003580 if (pSesInfo->server->tcpStatus != CifsExiting)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003581 pSesInfo->server->tcpStatus = CifsGood;
3582 else
3583 rc = -EHOSTDOWN;
3584 spin_unlock(&GlobalMid_Lock);
3585
3586 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003587 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588 }
3589 if (!rc) {
Steve French9ac00b72006-09-30 04:13:17 +00003590 pSesInfo->flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591 pSesInfo->capabilities = pSesInfo->server->capabilities;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003592 if (linuxExtEnabled == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003594 /* pSesInfo->sequence_number = 0;*/
Steve French50c2f752007-07-13 00:33:32 +00003595 cFYI(1,
3596 ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597 pSesInfo->server->secMode,
3598 pSesInfo->server->capabilities,
Steve French175ec9e2006-09-30 01:07:38 +00003599 pSesInfo->server->timeAdj));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003600 if (experimEnabled < 2)
Steve French39798772006-05-31 22:40:51 +00003601 rc = CIFS_SessSetup(xid, pSesInfo,
3602 first_time, nls_info);
Steve French189acaa2006-06-23 02:33:48 +00003603 else if (extended_security
Steve French50c2f752007-07-13 00:33:32 +00003604 && (pSesInfo->capabilities
Steve French175ec9e2006-09-30 01:07:38 +00003605 & CAP_EXTENDED_SECURITY)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606 && (pSesInfo->server->secType == NTLMSSP)) {
Steve French189acaa2006-06-23 02:33:48 +00003607 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608 } else if (extended_security
3609 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3610 && (pSesInfo->server->secType == RawNTLMSSP)) {
Steve French5815449d2006-02-14 01:36:20 +00003611 cFYI(1, ("NTLMSSP sesssetup"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612 rc = CIFSNTLMSSPNegotiateSessSetup(xid,
3613 pSesInfo,
3614 &ntlmv2_flag,
3615 nls_info);
3616 if (!rc) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003617 if (ntlmv2_flag) {
Steve French50c2f752007-07-13 00:33:32 +00003618 char *v2_response;
Steve French467a8f82007-06-27 22:41:32 +00003619 cFYI(1, ("more secure NTLM ver2 hash"));
Steve French50c2f752007-07-13 00:33:32 +00003620 if (CalcNTLMv2_partial_mac_key(pSesInfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621 nls_info)) {
3622 rc = -ENOMEM;
3623 goto ss_err_exit;
3624 } else
3625 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003626 if (v2_response) {
Steve French50c2f752007-07-13 00:33:32 +00003627 CalcNTLMv2_response(pSesInfo,
3628 v2_response);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003629 /* if (first_time)
Steve French50c2f752007-07-13 00:33:32 +00003630 cifs_calculate_ntlmv2_mac_key(
3631 pSesInfo->server->mac_signing_key,
3632 response, ntlm_session_key,*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633 kfree(v2_response);
3634 /* BB Put dummy sig in SessSetup PDU? */
3635 } else {
3636 rc = -ENOMEM;
3637 goto ss_err_exit;
3638 }
3639
3640 } else {
3641 SMBNTencrypt(pSesInfo->password,
3642 pSesInfo->server->cryptKey,
3643 ntlm_session_key);
3644
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003645 if (first_time)
Steve Frenchad009ac2005-04-28 22:41:05 -07003646 cifs_calculate_mac_key(
Steve Frenchb609f062007-07-09 07:55:14 +00003647 &pSesInfo->server->mac_signing_key,
Steve Frenchad009ac2005-04-28 22:41:05 -07003648 ntlm_session_key,
3649 pSesInfo->password);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003650 }
3651 /* for better security the weaker lanman hash not sent
3652 in AuthSessSetup so we no longer calculate it */
3653
3654 rc = CIFSNTLMSSPAuthSessSetup(xid,
3655 pSesInfo,
3656 ntlm_session_key,
3657 ntlmv2_flag,
3658 nls_info);
3659 }
3660 } else { /* old style NTLM 0.12 session setup */
3661 SMBNTencrypt(pSesInfo->password,
3662 pSesInfo->server->cryptKey,
3663 ntlm_session_key);
3664
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003665 if (first_time)
Steve Frenchad009ac2005-04-28 22:41:05 -07003666 cifs_calculate_mac_key(
Steve Frenchb609f062007-07-09 07:55:14 +00003667 &pSesInfo->server->mac_signing_key,
Steve Frenchad009ac2005-04-28 22:41:05 -07003668 ntlm_session_key, pSesInfo->password);
3669
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670 rc = CIFSSessSetup(xid, pSesInfo,
3671 ntlm_session_key, nls_info);
3672 }
3673 if (rc) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003674 cERROR(1, ("Send error in SessSetup = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003675 } else {
Steve French467a8f82007-06-27 22:41:32 +00003676 cFYI(1, ("CIFS Session Established successfully"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677 pSesInfo->status = CifsGood;
3678 }
3679 }
3680ss_err_exit:
3681 return rc;
3682}
3683