blob: d6a3c1c8a6f8c2c986aeb73482ed70cf41c1a0b7 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/connect.c
3 *
Steve French366781c2008-01-25 10:12:41 +00004 * Copyright (C) International Business Machines Corp., 2002,2008
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * This library is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published
9 * by the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
15 * the GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library; if not, write to the Free Software
Steve Frenchfb8c4b12007-07-10 01:16:18 +000019 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Linus Torvalds1da177e2005-04-16 15:20:36 -070020 */
21#include <linux/fs.h>
22#include <linux/net.h>
23#include <linux/string.h>
24#include <linux/list.h>
25#include <linux/wait.h>
26#include <linux/ipv6.h>
27#include <linux/pagemap.h>
28#include <linux/ctype.h>
29#include <linux/utsname.h>
30#include <linux/mempool.h>
Steve Frenchb8643e12005-04-28 22:41:07 -070031#include <linux/delay.h>
Steve Frenchf1914012005-08-18 09:37:34 -070032#include <linux/completion.h>
Igor Mammedovaaf737a2007-04-03 19:16:43 +000033#include <linux/kthread.h>
Steve French0ae0efa2005-10-10 10:57:19 -070034#include <linux/pagevec.h>
Nigel Cunningham7dfb7102006-12-06 20:34:23 -080035#include <linux/freezer.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <asm/uaccess.h>
37#include <asm/processor.h>
38#include "cifspdu.h"
39#include "cifsglob.h"
40#include "cifsproto.h"
41#include "cifs_unicode.h"
42#include "cifs_debug.h"
43#include "cifs_fs_sb.h"
44#include "ntlmssp.h"
45#include "nterr.h"
46#include "rfc1002pdu.h"
Steve Frencha2653eb2005-11-10 15:33:38 -080047#include "cn_cifs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
49#define CIFS_PORT 445
50#define RFC1001_PORT 139
51
Linus Torvalds1da177e2005-04-16 15:20:36 -070052extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
53 unsigned char *p24);
54
55extern mempool_t *cifs_req_poolp;
56
57struct smb_vol {
58 char *username;
59 char *password;
60 char *domainname;
61 char *UNC;
62 char *UNCip;
Steve French95b1cb92008-05-15 16:44:38 +000063 char *in6_addr; /* ipv6 address as human readable form of in6_addr */
Linus Torvalds1da177e2005-04-16 15:20:36 -070064 char *iocharset; /* local code page for mapping to and from Unicode */
65 char source_rfc1001_name[16]; /* netbios name of client */
Steve Frencha10faeb22005-08-22 21:38:31 -070066 char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 uid_t linux_uid;
68 gid_t linux_gid;
69 mode_t file_mode;
70 mode_t dir_mode;
Steve French189acaa2006-06-23 02:33:48 +000071 unsigned secFlg;
Steve French4b18f2a2008-04-29 00:06:05 +000072 bool rw:1;
73 bool retry:1;
74 bool intr:1;
75 bool setuids:1;
76 bool override_uid:1;
77 bool override_gid:1;
Jeff Laytond0a9c072008-05-12 22:23:49 +000078 bool dynperm:1;
Steve French4b18f2a2008-04-29 00:06:05 +000079 bool noperm:1;
80 bool no_psx_acl:1; /* set if posix acl support should be disabled */
81 bool cifs_acl:1;
82 bool no_xattr:1; /* set if xattr (EA) support should be disabled*/
83 bool server_ino:1; /* use inode numbers from server ie UniqueId */
84 bool direct_io:1;
Steve French95b1cb92008-05-15 16:44:38 +000085 bool remap:1; /* set to remap seven reserved chars in filenames */
86 bool posix_paths:1; /* unset to not ask for posix pathnames. */
Steve French4b18f2a2008-04-29 00:06:05 +000087 bool no_linux_ext:1;
88 bool sfu_emul:1;
Steve French95b1cb92008-05-15 16:44:38 +000089 bool nullauth:1; /* attempt to authenticate with null user */
90 bool nocase:1; /* request case insensitive filenames */
91 bool nobrl:1; /* disable sending byte range locks to srv */
92 bool seal:1; /* request transport encryption on share */
Steve French84210e92008-10-23 04:42:37 +000093 bool nodfs:1; /* Do not request DFS, even if available */
94 bool local_lease:1; /* check leases only on local system, not remote */
Steve Frenchedf1ae42008-10-29 00:47:57 +000095 bool noblocksnd:1;
96 bool noautotune:1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 unsigned int rsize;
98 unsigned int wsize;
99 unsigned int sockopt;
100 unsigned short int port;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000101 char *prepath;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102};
103
Jeff Laytonbcf4b102008-12-01 18:42:15 -0500104static int ipv4_connect(struct TCP_Server_Info *server);
Jeff Laytond5c56052008-12-01 18:42:33 -0500105static int ipv6_connect(struct TCP_Server_Info *server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106
Jeff Laytond5c56052008-12-01 18:42:33 -0500107/*
108 * cifs tcp session reconnection
109 *
110 * mark tcp session as reconnecting so temporarily locked
111 * mark all smb sessions as reconnecting for tcp session
112 * reconnect tcp session
113 * wake up waiters on reconnection? - (not needed currently)
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;
Jeff Laytonf1987b42008-11-15 11:12:47 -0500119 struct list_head *tmp, *tmp2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 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);
Jeff Layton469ee612008-10-16 18:46:39 +0000125 if (server->tcpStatus == CifsExiting) {
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 */
Jeff Layton14fbf502008-11-14 13:53:46 -0500139 read_lock(&cifs_tcp_ses_lock);
140 list_for_each(tmp, &server->smb_ses_list) {
141 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
142 ses->need_reconnect = true;
143 ses->ipc_tid = 0;
Jeff Laytonf1987b42008-11-15 11:12:47 -0500144 list_for_each(tmp2, &ses->tcon_list) {
145 tcon = list_entry(tmp2, struct cifsTconInfo, tcon_list);
146 tcon->need_reconnect = true;
147 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 }
Jeff Layton14fbf502008-11-14 13:53:46 -0500149 read_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 /* do not want to be sending data on a socket we are freeing */
Jeff Layton72ca5452008-12-01 07:09:36 -0500151 mutex_lock(&server->srv_mutex);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000152 if (server->ssocket) {
Steve French467a8f82007-06-27 22:41:32 +0000153 cFYI(1, ("State: 0x%x Flags: 0x%lx", server->ssocket->state,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 server->ssocket->flags));
Trond Myklebust91cf45f2007-11-12 18:10:39 -0800155 kernel_sock_shutdown(server->ssocket, SHUT_WR);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000156 cFYI(1, ("Post shutdown state: 0x%x Flags: 0x%lx",
Steve French467a8f82007-06-27 22:41:32 +0000157 server->ssocket->state,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 server->ssocket->flags));
159 sock_release(server->ssocket);
160 server->ssocket = NULL;
161 }
162
163 spin_lock(&GlobalMid_Lock);
164 list_for_each(tmp, &server->pending_mid_q) {
165 mid_entry = list_entry(tmp, struct
166 mid_q_entry,
167 qhead);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000168 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French09d1db52005-04-28 22:41:08 -0700169 /* Mark other intransit requests as needing
170 retry so we do not immediately mark the
171 session bad again (ie after we reconnect
172 below) as they timeout too */
Steve Frenchad8b15f2008-08-08 21:10:16 +0000173 mid_entry->midState = MID_RETRY_NEEDED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 }
175 }
176 spin_unlock(&GlobalMid_Lock);
Jeff Layton72ca5452008-12-01 07:09:36 -0500177 mutex_unlock(&server->srv_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
Jeff Layton469ee612008-10-16 18:46:39 +0000179 while ((server->tcpStatus != CifsExiting) &&
180 (server->tcpStatus != CifsGood)) {
Steve French6c3d8902006-07-31 22:46:20 +0000181 try_to_freeze();
Jeff Laytonbcf4b102008-12-01 18:42:15 -0500182 if (server->addr.sockAddr6.sin6_family == AF_INET6)
Jeff Laytond5c56052008-12-01 18:42:33 -0500183 rc = ipv6_connect(server);
Jeff Laytonbcf4b102008-12-01 18:42:15 -0500184 else
185 rc = ipv4_connect(server);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000186 if (rc) {
187 cFYI(1, ("reconnect error %d", rc));
Steve French0cb766a2005-04-28 22:41:11 -0700188 msleep(3000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 } else {
190 atomic_inc(&tcpSesReconnectCount);
191 spin_lock(&GlobalMid_Lock);
Jeff Layton469ee612008-10-16 18:46:39 +0000192 if (server->tcpStatus != CifsExiting)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 server->tcpStatus = CifsGood;
Steve Frenchad009ac2005-04-28 22:41:05 -0700194 server->sequence_number = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000195 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 /* atomic_set(&server->inFlight,0);*/
197 wake_up(&server->response_q);
198 }
199 }
200 return rc;
201}
202
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000203/*
Steve Frenche4eb2952005-04-28 22:41:09 -0700204 return codes:
205 0 not a transact2, or all data present
206 >0 transact2 with that much data missing
207 -EINVAL = invalid transact2
208
209 */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000210static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize)
Steve Frenche4eb2952005-04-28 22:41:09 -0700211{
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000212 struct smb_t2_rsp *pSMBt;
213 int total_data_size;
Steve Frenche4eb2952005-04-28 22:41:09 -0700214 int data_in_this_rsp;
215 int remaining;
216
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000217 if (pSMB->Command != SMB_COM_TRANSACTION2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700218 return 0;
219
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000220 /* check for plausible wct, bcc and t2 data and parm sizes */
221 /* check for parm and data offset going beyond end of smb */
222 if (pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
Steve French467a8f82007-06-27 22:41:32 +0000223 cFYI(1, ("invalid transact2 word count"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700224 return -EINVAL;
225 }
226
227 pSMBt = (struct smb_t2_rsp *)pSMB;
228
229 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
230 data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount);
231
232 remaining = total_data_size - data_in_this_rsp;
233
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000234 if (remaining == 0)
Steve Frenche4eb2952005-04-28 22:41:09 -0700235 return 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000236 else if (remaining < 0) {
Steve French467a8f82007-06-27 22:41:32 +0000237 cFYI(1, ("total data %d smaller than data in frame %d",
Steve Frenche4eb2952005-04-28 22:41:09 -0700238 total_data_size, data_in_this_rsp));
239 return -EINVAL;
240 } else {
Steve French467a8f82007-06-27 22:41:32 +0000241 cFYI(1, ("missing %d bytes from transact2, check next response",
Steve Frenche4eb2952005-04-28 22:41:09 -0700242 remaining));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000243 if (total_data_size > maxBufSize) {
244 cERROR(1, ("TotalDataSize %d is over maximum buffer %d",
245 total_data_size, maxBufSize));
246 return -EINVAL;
Steve Frenche4eb2952005-04-28 22:41:09 -0700247 }
248 return remaining;
249 }
250}
251
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000252static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
Steve Frenche4eb2952005-04-28 22:41:09 -0700253{
254 struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
255 struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
256 int total_data_size;
257 int total_in_buf;
258 int remaining;
259 int total_in_buf2;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000260 char *data_area_of_target;
261 char *data_area_of_buf2;
Steve Frenche4eb2952005-04-28 22:41:09 -0700262 __u16 byte_count;
263
264 total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
265
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000266 if (total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
Steve French63135e02007-07-17 17:34:02 +0000267 cFYI(1, ("total data size of primary and secondary t2 differ"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700268 }
269
270 total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
271
272 remaining = total_data_size - total_in_buf;
Steve French50c2f752007-07-13 00:33:32 +0000273
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000274 if (remaining < 0)
Steve Frenche4eb2952005-04-28 22:41:09 -0700275 return -EINVAL;
276
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000277 if (remaining == 0) /* nothing to do, ignore */
Steve Frenche4eb2952005-04-28 22:41:09 -0700278 return 0;
Steve French50c2f752007-07-13 00:33:32 +0000279
Steve Frenche4eb2952005-04-28 22:41:09 -0700280 total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000281 if (remaining < total_in_buf2) {
Steve French467a8f82007-06-27 22:41:32 +0000282 cFYI(1, ("transact2 2nd response contains too much data"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700283 }
284
285 /* find end of first SMB data area */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000286 data_area_of_target = (char *)&pSMBt->hdr.Protocol +
Steve Frenche4eb2952005-04-28 22:41:09 -0700287 le16_to_cpu(pSMBt->t2_rsp.DataOffset);
288 /* validate target area */
289
290 data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000291 le16_to_cpu(pSMB2->t2_rsp.DataOffset);
Steve Frenche4eb2952005-04-28 22:41:09 -0700292
293 data_area_of_target += total_in_buf;
294
295 /* copy second buffer into end of first buffer */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000296 memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2);
Steve Frenche4eb2952005-04-28 22:41:09 -0700297 total_in_buf += total_in_buf2;
298 pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
299 byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
300 byte_count += total_in_buf2;
301 BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
302
Steve French70ca7342005-09-22 16:32:06 -0700303 byte_count = pTargetSMB->smb_buf_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700304 byte_count += total_in_buf2;
305
306 /* BB also add check that we are not beyond maximum buffer size */
Steve French50c2f752007-07-13 00:33:32 +0000307
Steve French70ca7342005-09-22 16:32:06 -0700308 pTargetSMB->smb_buf_length = byte_count;
Steve Frenche4eb2952005-04-28 22:41:09 -0700309
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000310 if (remaining == total_in_buf2) {
Steve French467a8f82007-06-27 22:41:32 +0000311 cFYI(1, ("found the last secondary response"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700312 return 0; /* we are done */
313 } else /* more responses to go */
314 return 1;
315
316}
317
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318static int
319cifs_demultiplex_thread(struct TCP_Server_Info *server)
320{
321 int length;
322 unsigned int pdu_length, total_read;
323 struct smb_hdr *smb_buffer = NULL;
Steve Frenchb8643e12005-04-28 22:41:07 -0700324 struct smb_hdr *bigbuf = NULL;
325 struct smb_hdr *smallbuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 struct msghdr smb_msg;
327 struct kvec iov;
328 struct socket *csocket = server->ssocket;
329 struct list_head *tmp;
330 struct cifsSesInfo *ses;
331 struct task_struct *task_to_wake = NULL;
332 struct mid_q_entry *mid_entry;
Steve French70ca7342005-09-22 16:32:06 -0700333 char temp;
Steve French4b18f2a2008-04-29 00:06:05 +0000334 bool isLargeBuf = false;
335 bool isMultiRsp;
Steve Frenche4eb2952005-04-28 22:41:09 -0700336 int reconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 current->flags |= PF_MEMALLOC;
Pavel Emelyanovba25f9d2007-10-18 23:40:40 -0700339 cFYI(1, ("Demultiplex PID: %d", task_pid_nr(current)));
Jeff Layton93d0ec82008-08-02 08:00:48 -0400340
341 length = atomic_inc_return(&tcpSesAllocCount);
342 if (length > 1)
Steve French26f57362007-08-30 22:09:15 +0000343 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
344 GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345
Rafael J. Wysocki83144182007-07-17 04:03:35 -0700346 set_freezable();
Jeff Layton469ee612008-10-16 18:46:39 +0000347 while (server->tcpStatus != CifsExiting) {
Steve Frenchede13272005-08-30 20:10:14 -0700348 if (try_to_freeze())
349 continue;
Steve Frenchb8643e12005-04-28 22:41:07 -0700350 if (bigbuf == NULL) {
351 bigbuf = cifs_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000352 if (!bigbuf) {
353 cERROR(1, ("No memory for large SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700354 msleep(3000);
355 /* retry will check if exiting */
356 continue;
357 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000358 } else if (isLargeBuf) {
359 /* we are reusing a dirty large buf, clear its start */
Steve French26f57362007-08-30 22:09:15 +0000360 memset(bigbuf, 0, sizeof(struct smb_hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700362
363 if (smallbuf == NULL) {
364 smallbuf = cifs_small_buf_get();
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000365 if (!smallbuf) {
366 cERROR(1, ("No memory for SMB response"));
Steve Frenchb8643e12005-04-28 22:41:07 -0700367 msleep(1000);
368 /* retry will check if exiting */
369 continue;
370 }
371 /* beginning of smb buffer is cleared in our buf_get */
372 } else /* if existing small buf clear beginning */
Steve French26f57362007-08-30 22:09:15 +0000373 memset(smallbuf, 0, sizeof(struct smb_hdr));
Steve Frenchb8643e12005-04-28 22:41:07 -0700374
Steve French4b18f2a2008-04-29 00:06:05 +0000375 isLargeBuf = false;
376 isMultiRsp = false;
Steve Frenchb8643e12005-04-28 22:41:07 -0700377 smb_buffer = smallbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 iov.iov_base = smb_buffer;
379 iov.iov_len = 4;
380 smb_msg.msg_control = NULL;
381 smb_msg.msg_controllen = 0;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000382 pdu_length = 4; /* enough to get RFC1001 header */
383incomplete_rcv:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 length =
385 kernel_recvmsg(csocket, &smb_msg,
Steve Frenchf01d5e12007-08-30 21:13:31 +0000386 &iov, 1, pdu_length, 0 /* BB other flags? */);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387
Jeff Layton469ee612008-10-16 18:46:39 +0000388 if (server->tcpStatus == CifsExiting) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 break;
390 } else if (server->tcpStatus == CifsNeedReconnect) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000391 cFYI(1, ("Reconnect after server stopped responding"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 cifs_reconnect(server);
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000393 cFYI(1, ("call to reconnect done"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 csocket = server->ssocket;
395 continue;
396 } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
Steve Frenchb8643e12005-04-28 22:41:07 -0700397 msleep(1); /* minimum sleep to prevent looping
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 allowing socket to clear and app threads to set
399 tcpStatus CifsNeedReconnect if server hung */
Steve Frenchc527c8a2008-11-03 20:46:21 +0000400 if (pdu_length < 4) {
401 iov.iov_base = (4 - pdu_length) +
402 (char *)smb_buffer;
403 iov.iov_len = pdu_length;
404 smb_msg.msg_control = NULL;
405 smb_msg.msg_controllen = 0;
Steve Frenchc18c7322007-10-17 18:01:11 +0000406 goto incomplete_rcv;
Steve Frenchc527c8a2008-11-03 20:46:21 +0000407 } else
Steve Frenchc18c7322007-10-17 18:01:11 +0000408 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 } else if (length <= 0) {
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000410 if (server->tcpStatus == CifsNew) {
411 cFYI(1, ("tcp session abend after SMBnegprot"));
Steve French09d1db52005-04-28 22:41:08 -0700412 /* some servers kill the TCP session rather than
413 returning an SMB negprot error, in which
414 case reconnecting here is not going to help,
415 and so simply return error to mount */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 break;
417 }
Pavel Machek0fd1ffe2006-06-13 21:31:39 +0000418 if (!try_to_freeze() && (length == -EINTR)) {
Steve French467a8f82007-06-27 22:41:32 +0000419 cFYI(1, ("cifsd thread killed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 break;
421 }
Steve French467a8f82007-06-27 22:41:32 +0000422 cFYI(1, ("Reconnect after unexpected peek error %d",
Steve French57337e42005-04-28 22:41:10 -0700423 length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 cifs_reconnect(server);
425 csocket = server->ssocket;
426 wake_up(&server->response_q);
427 continue;
Petr Tesarik2a974682007-11-20 02:24:08 +0000428 } else if (length < pdu_length) {
429 cFYI(1, ("requested %d bytes but only got %d bytes",
430 pdu_length, length));
Steve Frenchf01d5e12007-08-30 21:13:31 +0000431 pdu_length -= length;
Steve Frenchf01d5e12007-08-30 21:13:31 +0000432 msleep(1);
433 goto incomplete_rcv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 }
Steve French67010fb2005-04-28 22:41:09 -0700435
Steve French70ca7342005-09-22 16:32:06 -0700436 /* The right amount was read from socket - 4 bytes */
437 /* so we can now interpret the length field */
Steve French46810cb2005-04-28 22:41:09 -0700438
Steve French70ca7342005-09-22 16:32:06 -0700439 /* the first byte big endian of the length field,
440 is actually not part of the length but the type
441 with the most common, zero, as regular data */
442 temp = *((char *) smb_buffer);
443
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000444 /* Note that FC 1001 length is big endian on the wire,
Steve French70ca7342005-09-22 16:32:06 -0700445 but we convert it here so it is always manipulated
446 as host byte order */
Harvey Harrison5ca33c62008-07-23 17:45:58 -0700447 pdu_length = be32_to_cpu((__force __be32)smb_buffer->smb_buf_length);
Steve French70ca7342005-09-22 16:32:06 -0700448 smb_buffer->smb_buf_length = pdu_length;
Steve French46810cb2005-04-28 22:41:09 -0700449
Steve French467a8f82007-06-27 22:41:32 +0000450 cFYI(1, ("rfc1002 length 0x%x", pdu_length+4));
Steve French70ca7342005-09-22 16:32:06 -0700451
452 if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000453 continue;
Steve French70ca7342005-09-22 16:32:06 -0700454 } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
Steve French467a8f82007-06-27 22:41:32 +0000455 cFYI(1, ("Good RFC 1002 session rsp"));
Steve Frenche4eb2952005-04-28 22:41:09 -0700456 continue;
Steve French70ca7342005-09-22 16:32:06 -0700457 } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000458 /* we get this from Windows 98 instead of
Steve French46810cb2005-04-28 22:41:09 -0700459 an error on SMB negprot response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000460 cFYI(1, ("Negative RFC1002 Session Response Error 0x%x)",
Steve French70ca7342005-09-22 16:32:06 -0700461 pdu_length));
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000462 if (server->tcpStatus == CifsNew) {
463 /* if nack on negprot (rather than
Steve French46810cb2005-04-28 22:41:09 -0700464 ret of smb negprot error) reconnecting
465 not going to help, ret error to mount */
466 break;
467 } else {
468 /* give server a second to
469 clean up before reconnect attempt */
470 msleep(1000);
471 /* always try 445 first on reconnect
472 since we get NACK on some if we ever
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000473 connected to port 139 (the NACK is
Steve French46810cb2005-04-28 22:41:09 -0700474 since we do not begin with RFC1001
475 session initialize frame) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000476 server->addr.sockAddr.sin_port =
Steve French46810cb2005-04-28 22:41:09 -0700477 htons(CIFS_PORT);
478 cifs_reconnect(server);
479 csocket = server->ssocket;
480 wake_up(&server->response_q);
481 continue;
482 }
Steve French70ca7342005-09-22 16:32:06 -0700483 } else if (temp != (char) 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000484 cERROR(1, ("Unknown RFC 1002 frame"));
Steve French70ca7342005-09-22 16:32:06 -0700485 cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
486 length);
Steve French46810cb2005-04-28 22:41:09 -0700487 cifs_reconnect(server);
488 csocket = server->ssocket;
489 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700490 }
491
492 /* else we have an SMB response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000493 if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
Steve French26f57362007-08-30 22:09:15 +0000494 (pdu_length < sizeof(struct smb_hdr) - 1 - 4)) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700495 cERROR(1, ("Invalid size SMB length %d pdu_length %d",
Steve French46810cb2005-04-28 22:41:09 -0700496 length, pdu_length+4));
Steve Frenche4eb2952005-04-28 22:41:09 -0700497 cifs_reconnect(server);
498 csocket = server->ssocket;
499 wake_up(&server->response_q);
500 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000501 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700502
503 /* else length ok */
504 reconnect = 0;
505
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000506 if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
Steve French4b18f2a2008-04-29 00:06:05 +0000507 isLargeBuf = true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700508 memcpy(bigbuf, smallbuf, 4);
509 smb_buffer = bigbuf;
510 }
511 length = 0;
512 iov.iov_base = 4 + (char *)smb_buffer;
513 iov.iov_len = pdu_length;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000514 for (total_read = 0; total_read < pdu_length;
Steve Frenche4eb2952005-04-28 22:41:09 -0700515 total_read += length) {
516 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
517 pdu_length - total_read, 0);
Jeff Layton469ee612008-10-16 18:46:39 +0000518 if ((server->tcpStatus == CifsExiting) ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700519 (length == -EINTR)) {
520 /* then will exit */
521 reconnect = 2;
522 break;
523 } else if (server->tcpStatus == CifsNeedReconnect) {
Steve French46810cb2005-04-28 22:41:09 -0700524 cifs_reconnect(server);
525 csocket = server->ssocket;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000526 /* Reconnect wakes up rspns q */
Steve Frenche4eb2952005-04-28 22:41:09 -0700527 /* Now we will reread sock */
528 reconnect = 1;
529 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000530 } else if ((length == -ERESTARTSYS) ||
Steve Frenche4eb2952005-04-28 22:41:09 -0700531 (length == -EAGAIN)) {
532 msleep(1); /* minimum sleep to prevent looping,
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000533 allowing socket to clear and app
Steve Frenche4eb2952005-04-28 22:41:09 -0700534 threads to set tcpStatus
535 CifsNeedReconnect if server hung*/
Steve Frenchc18c7322007-10-17 18:01:11 +0000536 length = 0;
Steve French46810cb2005-04-28 22:41:09 -0700537 continue;
Steve Frenche4eb2952005-04-28 22:41:09 -0700538 } else if (length <= 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000539 cERROR(1, ("Received no data, expecting %d",
Steve Frenche4eb2952005-04-28 22:41:09 -0700540 pdu_length - total_read));
541 cifs_reconnect(server);
542 csocket = server->ssocket;
543 reconnect = 1;
544 break;
Steve French46810cb2005-04-28 22:41:09 -0700545 }
546 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000547 if (reconnect == 2)
Steve Frenche4eb2952005-04-28 22:41:09 -0700548 break;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000549 else if (reconnect == 1)
Steve Frenche4eb2952005-04-28 22:41:09 -0700550 continue;
551
552 length += 4; /* account for rfc1002 hdr */
Steve French50c2f752007-07-13 00:33:32 +0000553
Steve Frenche4eb2952005-04-28 22:41:09 -0700554
555 dump_smb(smb_buffer, length);
Steve French184ed212006-02-24 06:15:11 +0000556 if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) {
Steve Frenchb387eae2005-10-10 14:21:15 -0700557 cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
Steve Frenche4eb2952005-04-28 22:41:09 -0700558 continue;
559 }
560
561
562 task_to_wake = NULL;
563 spin_lock(&GlobalMid_Lock);
564 list_for_each(tmp, &server->pending_mid_q) {
565 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
566
Steve French50c2f752007-07-13 00:33:32 +0000567 if ((mid_entry->mid == smb_buffer->Mid) &&
Steve Frenche4eb2952005-04-28 22:41:09 -0700568 (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
569 (mid_entry->command == smb_buffer->Command)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000570 if (check2ndT2(smb_buffer,server->maxBuf) > 0) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700571 /* We have a multipart transact2 resp */
Steve French4b18f2a2008-04-29 00:06:05 +0000572 isMultiRsp = true;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000573 if (mid_entry->resp_buf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700574 /* merge response - fix up 1st*/
Steve French50c2f752007-07-13 00:33:32 +0000575 if (coalesce_t2(smb_buffer,
Steve Frenche4eb2952005-04-28 22:41:09 -0700576 mid_entry->resp_buf)) {
Steve French4b18f2a2008-04-29 00:06:05 +0000577 mid_entry->multiRsp =
578 true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700579 break;
580 } else {
581 /* all parts received */
Steve French4b18f2a2008-04-29 00:06:05 +0000582 mid_entry->multiEnd =
583 true;
Steve French50c2f752007-07-13 00:33:32 +0000584 goto multi_t2_fnd;
Steve Frenche4eb2952005-04-28 22:41:09 -0700585 }
586 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000587 if (!isLargeBuf) {
Steve Frenche4eb2952005-04-28 22:41:09 -0700588 cERROR(1,("1st trans2 resp needs bigbuf"));
589 /* BB maybe we can fix this up, switch
Steve French50c2f752007-07-13 00:33:32 +0000590 to already allocated large buffer? */
Steve Frenche4eb2952005-04-28 22:41:09 -0700591 } else {
Steve Frenchcd634992005-04-28 22:41:10 -0700592 /* Have first buffer */
Steve Frenche4eb2952005-04-28 22:41:09 -0700593 mid_entry->resp_buf =
594 smb_buffer;
Steve French4b18f2a2008-04-29 00:06:05 +0000595 mid_entry->largeBuf =
596 true;
Steve Frenche4eb2952005-04-28 22:41:09 -0700597 bigbuf = NULL;
598 }
599 }
600 break;
Steve French50c2f752007-07-13 00:33:32 +0000601 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700602 mid_entry->resp_buf = smb_buffer;
Steve French4b18f2a2008-04-29 00:06:05 +0000603 mid_entry->largeBuf = isLargeBuf;
Steve Frenche4eb2952005-04-28 22:41:09 -0700604multi_t2_fnd:
605 task_to_wake = mid_entry->tsk;
606 mid_entry->midState = MID_RESPONSE_RECEIVED;
Steve French1047abc2005-10-11 19:58:06 -0700607#ifdef CONFIG_CIFS_STATS2
608 mid_entry->when_received = jiffies;
609#endif
Steve French3a5ff612006-07-14 22:37:11 +0000610 /* so we do not time out requests to server
611 which is still responding (since server could
612 be busy but not dead) */
613 server->lstrp = jiffies;
Steve Frenche4eb2952005-04-28 22:41:09 -0700614 break;
615 }
616 }
617 spin_unlock(&GlobalMid_Lock);
618 if (task_to_wake) {
Steve Frenchcd634992005-04-28 22:41:10 -0700619 /* Was previous buf put in mpx struct for multi-rsp? */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000620 if (!isMultiRsp) {
Steve Frenchcd634992005-04-28 22:41:10 -0700621 /* smb buffer will be freed by user thread */
Steve French26f57362007-08-30 22:09:15 +0000622 if (isLargeBuf)
Steve Frenchcd634992005-04-28 22:41:10 -0700623 bigbuf = NULL;
Steve French26f57362007-08-30 22:09:15 +0000624 else
Steve Frenchcd634992005-04-28 22:41:10 -0700625 smallbuf = NULL;
626 }
Steve Frenche4eb2952005-04-28 22:41:09 -0700627 wake_up_process(task_to_wake);
Steve French4b18f2a2008-04-29 00:06:05 +0000628 } else if (!is_valid_oplock_break(smb_buffer, server) &&
629 !isMultiRsp) {
Steve French50c2f752007-07-13 00:33:32 +0000630 cERROR(1, ("No task to wake, unknown frame received! "
631 "NumMids %d", midCount.counter));
632 cifs_dump_mem("Received Data is: ", (char *)smb_buffer,
Steve French70ca7342005-09-22 16:32:06 -0700633 sizeof(struct smb_hdr));
Steve French39798772006-05-31 22:40:51 +0000634#ifdef CONFIG_CIFS_DEBUG2
635 cifs_dump_detail(smb_buffer);
636 cifs_dump_mids(server);
637#endif /* CIFS_DEBUG2 */
Steve French50c2f752007-07-13 00:33:32 +0000638
Steve Frenche4eb2952005-04-28 22:41:09 -0700639 }
640 } /* end while !EXITING */
641
Jeff Laytone7ddee92008-11-14 13:44:38 -0500642 /* take it off the list, if it's not already */
643 write_lock(&cifs_tcp_ses_lock);
644 list_del_init(&server->tcp_ses_list);
645 write_unlock(&cifs_tcp_ses_lock);
646
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 spin_lock(&GlobalMid_Lock);
648 server->tcpStatus = CifsExiting;
Steve Frenche691b9d2008-05-11 15:53:33 +0000649 spin_unlock(&GlobalMid_Lock);
Steve Frenchdbdbb872008-06-10 21:21:56 +0000650 wake_up_all(&server->response_q);
Steve Frenche691b9d2008-05-11 15:53:33 +0000651
Steve French31ca3bc2005-04-28 22:41:11 -0700652 /* check if we have blocked requests that need to free */
653 /* Note that cifs_max_pending is normally 50, but
654 can be set at module install time to as little as two */
Steve Frenche691b9d2008-05-11 15:53:33 +0000655 spin_lock(&GlobalMid_Lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000656 if (atomic_read(&server->inFlight) >= cifs_max_pending)
Steve French31ca3bc2005-04-28 22:41:11 -0700657 atomic_set(&server->inFlight, cifs_max_pending - 1);
658 /* We do not want to set the max_pending too low or we
659 could end up with the counter going negative */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +0000661 /* Although there should not be any requests blocked on
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 this queue it can not hurt to be paranoid and try to wake up requests
Steve French09d1db52005-04-28 22:41:08 -0700663 that may haven been blocked when more than 50 at time were on the wire
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 to the same server - they now will see the session is in exit state
665 and get out of SendReceive. */
666 wake_up_all(&server->request_q);
667 /* give those requests time to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700668 msleep(125);
Steve French50c2f752007-07-13 00:33:32 +0000669
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000670 if (server->ssocket) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 sock_release(csocket);
672 server->ssocket = NULL;
673 }
Steve Frenchb8643e12005-04-28 22:41:07 -0700674 /* buffer usuallly freed in free_mid - need to free it here on exit */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +0000675 cifs_buf_release(bigbuf);
676 if (smallbuf) /* no sense logging a debug message if NULL */
Steve Frenchb8643e12005-04-28 22:41:07 -0700677 cifs_small_buf_release(smallbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678
Jeff Layton14fbf502008-11-14 13:53:46 -0500679 /*
680 * BB: we shouldn't have to do any of this. It shouldn't be
681 * possible to exit from the thread with active SMB sessions
682 */
683 read_lock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 if (list_empty(&server->pending_mid_q)) {
Steve French09d1db52005-04-28 22:41:08 -0700685 /* loop through server session structures attached to this and
686 mark them dead */
Jeff Layton14fbf502008-11-14 13:53:46 -0500687 list_for_each(tmp, &server->smb_ses_list) {
688 ses = list_entry(tmp, struct cifsSesInfo,
689 smb_ses_list);
690 ses->status = CifsExiting;
691 ses->server = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 }
Jeff Layton14fbf502008-11-14 13:53:46 -0500693 read_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 } else {
Steve French31ca3bc2005-04-28 22:41:11 -0700695 /* although we can not zero the server struct pointer yet,
696 since there are active requests which may depnd on them,
697 mark the corresponding SMB sessions as exiting too */
Jeff Layton14fbf502008-11-14 13:53:46 -0500698 list_for_each(tmp, &server->smb_ses_list) {
Steve French31ca3bc2005-04-28 22:41:11 -0700699 ses = list_entry(tmp, struct cifsSesInfo,
Jeff Layton14fbf502008-11-14 13:53:46 -0500700 smb_ses_list);
701 ses->status = CifsExiting;
Steve French31ca3bc2005-04-28 22:41:11 -0700702 }
703
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 spin_lock(&GlobalMid_Lock);
705 list_for_each(tmp, &server->pending_mid_q) {
706 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
707 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
Steve French50c2f752007-07-13 00:33:32 +0000708 cFYI(1, ("Clearing Mid 0x%x - waking up ",
709 mid_entry->mid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 task_to_wake = mid_entry->tsk;
Steve French26f57362007-08-30 22:09:15 +0000711 if (task_to_wake)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 wake_up_process(task_to_wake);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 }
714 }
715 spin_unlock(&GlobalMid_Lock);
Jeff Layton14fbf502008-11-14 13:53:46 -0500716 read_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 /* 1/8th of sec is more than enough time for them to exit */
Steve Frenchb8643e12005-04-28 22:41:07 -0700718 msleep(125);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 }
720
Steve Frenchf1914012005-08-18 09:37:34 -0700721 if (!list_empty(&server->pending_mid_q)) {
Steve French50c2f752007-07-13 00:33:32 +0000722 /* mpx threads have not exited yet give them
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 at least the smb send timeout time for long ops */
Steve French31ca3bc2005-04-28 22:41:11 -0700724 /* due to delays on oplock break requests, we need
725 to wait at least 45 seconds before giving up
726 on a request getting a response and going ahead
727 and killing cifsd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 cFYI(1, ("Wait for exit from demultiplex thread"));
Steve French31ca3bc2005-04-28 22:41:11 -0700729 msleep(46000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 /* if threads still have not exited they are probably never
731 coming home not much else we can do but free the memory */
732 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733
Steve French31ca3bc2005-04-28 22:41:11 -0700734 /* last chance to mark ses pointers invalid
735 if there are any pointing to this (e.g
Steve French50c2f752007-07-13 00:33:32 +0000736 if a crazy root user tried to kill cifsd
Steve French31ca3bc2005-04-28 22:41:11 -0700737 kernel thread explicitly this might happen) */
Jeff Layton14fbf502008-11-14 13:53:46 -0500738 /* BB: This shouldn't be necessary, see above */
739 read_lock(&cifs_tcp_ses_lock);
740 list_for_each(tmp, &server->smb_ses_list) {
741 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
742 ses->server = NULL;
Steve French31ca3bc2005-04-28 22:41:11 -0700743 }
Jeff Layton14fbf502008-11-14 13:53:46 -0500744 read_unlock(&cifs_tcp_ses_lock);
Steve French31ca3bc2005-04-28 22:41:11 -0700745
Jeff Laytonc359cf32007-11-16 22:22:06 +0000746 kfree(server->hostname);
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -0400747 task_to_wake = xchg(&server->tsk, NULL);
Steve French31ca3bc2005-04-28 22:41:11 -0700748 kfree(server);
Jeff Layton93d0ec82008-08-02 08:00:48 -0400749
750 length = atomic_dec_return(&tcpSesAllocCount);
Steve French26f57362007-08-30 22:09:15 +0000751 if (length > 0)
752 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
753 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +0000754
Jeff Laytonb1c8d2b2008-10-22 13:57:07 -0400755 /* if server->tsk was NULL then wait for a signal before exiting */
756 if (!task_to_wake) {
757 set_current_state(TASK_INTERRUPTIBLE);
758 while (!signal_pending(current)) {
759 schedule();
760 set_current_state(TASK_INTERRUPTIBLE);
761 }
762 set_current_state(TASK_RUNNING);
763 }
764
Jeff Layton0468a2c2008-12-01 07:09:35 -0500765 module_put_and_exit(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766}
767
Jeff Laytonc359cf32007-11-16 22:22:06 +0000768/* extract the host portion of the UNC string */
769static char *
770extract_hostname(const char *unc)
771{
772 const char *src;
773 char *dst, *delim;
774 unsigned int len;
775
776 /* skip double chars at beginning of string */
777 /* BB: check validity of these bytes? */
778 src = unc + 2;
779
780 /* delimiter between hostname and sharename is always '\\' now */
781 delim = strchr(src, '\\');
782 if (!delim)
783 return ERR_PTR(-EINVAL);
784
785 len = delim - src;
786 dst = kmalloc((len + 1), GFP_KERNEL);
787 if (dst == NULL)
788 return ERR_PTR(-ENOMEM);
789
790 memcpy(dst, src, len);
791 dst[len] = '\0';
792
793 return dst;
794}
795
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796static int
Steve French50c2f752007-07-13 00:33:32 +0000797cifs_parse_mount_options(char *options, const char *devname,
798 struct smb_vol *vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799{
800 char *value;
801 char *data;
802 unsigned int temp_len, i, j;
803 char separator[2];
804
805 separator[0] = ',';
Steve French50c2f752007-07-13 00:33:32 +0000806 separator[1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807
Linus Torvalds12e36b22006-10-13 08:09:29 -0700808 if (Local_System_Name[0] != 0)
Steve French50c2f752007-07-13 00:33:32 +0000809 memcpy(vol->source_rfc1001_name, Local_System_Name, 15);
Steve French2cd646a2006-09-28 19:43:08 +0000810 else {
Linus Torvalds12e36b22006-10-13 08:09:29 -0700811 char *nodename = utsname()->nodename;
Steve French50c2f752007-07-13 00:33:32 +0000812 int n = strnlen(nodename, 15);
813 memset(vol->source_rfc1001_name, 0x20, 15);
814 for (i = 0; i < n; i++) {
Steve French2cd646a2006-09-28 19:43:08 +0000815 /* does not have to be perfect mapping since field is
816 informational, only used for servers that do not support
817 port 445 and it can be overridden at mount time */
Linus Torvalds12e36b22006-10-13 08:09:29 -0700818 vol->source_rfc1001_name[i] = toupper(nodename[i]);
Steve French2cd646a2006-09-28 19:43:08 +0000819 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 }
821 vol->source_rfc1001_name[15] = 0;
Steve Frencha10faeb22005-08-22 21:38:31 -0700822 /* null target name indicates to use *SMBSERVR default called name
823 if we end up sending RFC1001 session initialize */
824 vol->target_rfc1001_name[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 vol->linux_uid = current->uid; /* current->euid instead? */
826 vol->linux_gid = current->gid;
827 vol->dir_mode = S_IRWXUGO;
828 /* 2767 perms indicate mandatory locking support */
Steve French7505e052007-11-01 18:03:01 +0000829 vol->file_mode = (S_IRWXUGO | S_ISGID) & (~S_IXGRP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830
831 /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
Steve French4b18f2a2008-04-29 00:06:05 +0000832 vol->rw = true;
Jeremy Allisonac670552005-06-22 17:26:35 -0700833 /* default is always to request posix paths. */
834 vol->posix_paths = 1;
835
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 if (!options)
837 return 1;
838
Steve French50c2f752007-07-13 00:33:32 +0000839 if (strncmp(options, "sep=", 4) == 0) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000840 if (options[4] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 separator[0] = options[4];
842 options += 5;
843 } else {
Steve French467a8f82007-06-27 22:41:32 +0000844 cFYI(1, ("Null separator not allowed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 }
846 }
Steve French50c2f752007-07-13 00:33:32 +0000847
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 while ((data = strsep(&options, separator)) != NULL) {
849 if (!*data)
850 continue;
851 if ((value = strchr(data, '=')) != NULL)
852 *value++ = '\0';
853
Steve French50c2f752007-07-13 00:33:32 +0000854 /* Have to parse this before we parse for "user" */
855 if (strnicmp(data, "user_xattr", 10) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 vol->no_xattr = 0;
Steve French50c2f752007-07-13 00:33:32 +0000857 } else if (strnicmp(data, "nouser_xattr", 12) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 vol->no_xattr = 1;
859 } else if (strnicmp(data, "user", 4) == 0) {
Steve French4b952a92006-10-30 21:46:13 +0000860 if (!value) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 printk(KERN_WARNING
862 "CIFS: invalid or missing username\n");
863 return 1; /* needs_arg; */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000864 } else if (!*value) {
Steve French4b952a92006-10-30 21:46:13 +0000865 /* null user, ie anonymous, authentication */
866 vol->nullauth = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 }
868 if (strnlen(value, 200) < 200) {
869 vol->username = value;
870 } else {
871 printk(KERN_WARNING "CIFS: username too long\n");
872 return 1;
873 }
874 } else if (strnicmp(data, "pass", 4) == 0) {
875 if (!value) {
876 vol->password = NULL;
877 continue;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000878 } else if (value[0] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 /* check if string begins with double comma
880 since that would mean the password really
881 does start with a comma, and would not
882 indicate an empty string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000883 if (value[1] != separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 vol->password = NULL;
885 continue;
886 }
887 }
888 temp_len = strlen(value);
889 /* removed password length check, NTLM passwords
890 can be arbitrarily long */
891
Steve French50c2f752007-07-13 00:33:32 +0000892 /* if comma in password, the string will be
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 prematurely null terminated. Commas in password are
894 specified across the cifs mount interface by a double
895 comma ie ,, and a comma used as in other cases ie ','
896 as a parameter delimiter/separator is single and due
897 to the strsep above is temporarily zeroed. */
898
899 /* NB: password legally can have multiple commas and
900 the only illegal character in a password is null */
901
Steve French50c2f752007-07-13 00:33:32 +0000902 if ((value[temp_len] == 0) &&
Steve French09d1db52005-04-28 22:41:08 -0700903 (value[temp_len+1] == separator[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 /* reinsert comma */
905 value[temp_len] = separator[0];
Steve French50c2f752007-07-13 00:33:32 +0000906 temp_len += 2; /* move after second comma */
907 while (value[temp_len] != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 if (value[temp_len] == separator[0]) {
Steve French50c2f752007-07-13 00:33:32 +0000909 if (value[temp_len+1] ==
Steve French09d1db52005-04-28 22:41:08 -0700910 separator[0]) {
911 /* skip second comma */
912 temp_len++;
Steve French50c2f752007-07-13 00:33:32 +0000913 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 /* single comma indicating start
915 of next parm */
916 break;
917 }
918 }
919 temp_len++;
920 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000921 if (value[temp_len] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 options = NULL;
923 } else {
924 value[temp_len] = 0;
925 /* point option to start of next parm */
926 options = value + temp_len + 1;
927 }
Steve French50c2f752007-07-13 00:33:32 +0000928 /* go from value to value + temp_len condensing
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 double commas to singles. Note that this ends up
930 allocating a few bytes too many, which is ok */
Pekka Enberge915fc42005-09-06 15:18:35 -0700931 vol->password = kzalloc(temp_len, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000932 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000933 printk(KERN_WARNING "CIFS: no memory "
934 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700935 return 1;
936 }
Steve French50c2f752007-07-13 00:33:32 +0000937 for (i = 0, j = 0; i < temp_len; i++, j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 vol->password[j] = value[i];
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000939 if (value[i] == separator[0]
Steve French09d1db52005-04-28 22:41:08 -0700940 && value[i+1] == separator[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 /* skip second comma */
942 i++;
943 }
944 }
945 vol->password[j] = 0;
946 } else {
Pekka Enberge915fc42005-09-06 15:18:35 -0700947 vol->password = kzalloc(temp_len+1, GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000948 if (vol->password == NULL) {
Steve French50c2f752007-07-13 00:33:32 +0000949 printk(KERN_WARNING "CIFS: no memory "
950 "for password\n");
Steve French433dc242005-04-28 22:41:08 -0700951 return 1;
952 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 strcpy(vol->password, value);
954 }
955 } else if (strnicmp(data, "ip", 2) == 0) {
956 if (!value || !*value) {
957 vol->UNCip = NULL;
958 } else if (strnlen(value, 35) < 35) {
959 vol->UNCip = value;
960 } else {
Steve French50c2f752007-07-13 00:33:32 +0000961 printk(KERN_WARNING "CIFS: ip address "
962 "too long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 return 1;
964 }
Steve French50c2f752007-07-13 00:33:32 +0000965 } else if (strnicmp(data, "sec", 3) == 0) {
966 if (!value || !*value) {
967 cERROR(1, ("no security value specified"));
968 continue;
969 } else if (strnicmp(value, "krb5i", 5) == 0) {
970 vol->secFlg |= CIFSSEC_MAY_KRB5 |
Steve French189acaa2006-06-23 02:33:48 +0000971 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800972 } else if (strnicmp(value, "krb5p", 5) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000973 /* vol->secFlg |= CIFSSEC_MUST_SEAL |
974 CIFSSEC_MAY_KRB5; */
975 cERROR(1, ("Krb5 cifs privacy not supported"));
Steve Frenchbf820672005-12-01 22:32:42 -0800976 return 1;
977 } else if (strnicmp(value, "krb5", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000978 vol->secFlg |= CIFSSEC_MAY_KRB5;
Steve Frenchbf820672005-12-01 22:32:42 -0800979 } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000980 vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
Steve French189acaa2006-06-23 02:33:48 +0000981 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800982 } else if (strnicmp(value, "ntlmv2", 6) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000983 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve Frenchbf820672005-12-01 22:32:42 -0800984 } else if (strnicmp(value, "ntlmi", 5) == 0) {
Steve French750d1152006-06-27 06:28:30 +0000985 vol->secFlg |= CIFSSEC_MAY_NTLM |
Steve French189acaa2006-06-23 02:33:48 +0000986 CIFSSEC_MUST_SIGN;
Steve Frenchbf820672005-12-01 22:32:42 -0800987 } else if (strnicmp(value, "ntlm", 4) == 0) {
988 /* ntlm is default so can be turned off too */
Steve French750d1152006-06-27 06:28:30 +0000989 vol->secFlg |= CIFSSEC_MAY_NTLM;
Steve Frenchbf820672005-12-01 22:32:42 -0800990 } else if (strnicmp(value, "nontlm", 6) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000991 /* BB is there a better way to do this? */
Steve French750d1152006-06-27 06:28:30 +0000992 vol->secFlg |= CIFSSEC_MAY_NTLMV2;
Steve French189acaa2006-06-23 02:33:48 +0000993#ifdef CONFIG_CIFS_WEAK_PW_HASH
994 } else if (strnicmp(value, "lanman", 6) == 0) {
Steve French50c2f752007-07-13 00:33:32 +0000995 vol->secFlg |= CIFSSEC_MAY_LANMAN;
Steve French189acaa2006-06-23 02:33:48 +0000996#endif
Steve Frenchbf820672005-12-01 22:32:42 -0800997 } else if (strnicmp(value, "none", 4) == 0) {
Steve French189acaa2006-06-23 02:33:48 +0000998 vol->nullauth = 1;
Steve French50c2f752007-07-13 00:33:32 +0000999 } else {
1000 cERROR(1, ("bad security option: %s", value));
1001 return 1;
1002 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 } else if ((strnicmp(data, "unc", 3) == 0)
1004 || (strnicmp(data, "target", 6) == 0)
1005 || (strnicmp(data, "path", 4) == 0)) {
1006 if (!value || !*value) {
Steve French50c2f752007-07-13 00:33:32 +00001007 printk(KERN_WARNING "CIFS: invalid path to "
1008 "network resource\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 return 1; /* needs_arg; */
1010 }
1011 if ((temp_len = strnlen(value, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001012 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001013 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001015 strcpy(vol->UNC, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 if (strncmp(vol->UNC, "//", 2) == 0) {
1017 vol->UNC[0] = '\\';
1018 vol->UNC[1] = '\\';
Steve French50c2f752007-07-13 00:33:32 +00001019 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 printk(KERN_WARNING
Steve French50c2f752007-07-13 00:33:32 +00001021 "CIFS: UNC Path does not begin "
1022 "with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 return 1;
1024 }
1025 } else {
1026 printk(KERN_WARNING "CIFS: UNC name too long\n");
1027 return 1;
1028 }
1029 } else if ((strnicmp(data, "domain", 3) == 0)
1030 || (strnicmp(data, "workgroup", 5) == 0)) {
1031 if (!value || !*value) {
1032 printk(KERN_WARNING "CIFS: invalid domain name\n");
1033 return 1; /* needs_arg; */
1034 }
1035 /* BB are there cases in which a comma can be valid in
1036 a domain name and need special handling? */
Steve French39798772006-05-31 22:40:51 +00001037 if (strnlen(value, 256) < 256) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 vol->domainname = value;
1039 cFYI(1, ("Domain name set"));
1040 } else {
Steve French50c2f752007-07-13 00:33:32 +00001041 printk(KERN_WARNING "CIFS: domain name too "
1042 "long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 return 1;
1044 }
Steve French50c2f752007-07-13 00:33:32 +00001045 } else if (strnicmp(data, "prefixpath", 10) == 0) {
1046 if (!value || !*value) {
1047 printk(KERN_WARNING
1048 "CIFS: invalid path prefix\n");
1049 return 1; /* needs_argument */
1050 }
1051 if ((temp_len = strnlen(value, 1024)) < 1024) {
Steve French4523cc32007-04-30 20:13:06 +00001052 if (value[0] != '/')
Steve French2fe87f02006-09-21 07:02:52 +00001053 temp_len++; /* missing leading slash */
Steve French50c2f752007-07-13 00:33:32 +00001054 vol->prepath = kmalloc(temp_len+1, GFP_KERNEL);
1055 if (vol->prepath == NULL)
1056 return 1;
Steve French4523cc32007-04-30 20:13:06 +00001057 if (value[0] != '/') {
Steve French2fe87f02006-09-21 07:02:52 +00001058 vol->prepath[0] = '/';
Steve French50c2f752007-07-13 00:33:32 +00001059 strcpy(vol->prepath+1, value);
Steve French2fe87f02006-09-21 07:02:52 +00001060 } else
Steve French50c2f752007-07-13 00:33:32 +00001061 strcpy(vol->prepath, value);
1062 cFYI(1, ("prefix path %s", vol->prepath));
1063 } else {
1064 printk(KERN_WARNING "CIFS: prefix too long\n");
1065 return 1;
1066 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 } else if (strnicmp(data, "iocharset", 9) == 0) {
1068 if (!value || !*value) {
Steve French63135e02007-07-17 17:34:02 +00001069 printk(KERN_WARNING "CIFS: invalid iocharset "
1070 "specified\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 return 1; /* needs_arg; */
1072 }
1073 if (strnlen(value, 65) < 65) {
Steve French50c2f752007-07-13 00:33:32 +00001074 if (strnicmp(value, "default", 7))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 vol->iocharset = value;
Steve French50c2f752007-07-13 00:33:32 +00001076 /* if iocharset not set then load_nls_default
1077 is used by caller */
1078 cFYI(1, ("iocharset set to %s", value));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 } else {
Steve French63135e02007-07-17 17:34:02 +00001080 printk(KERN_WARNING "CIFS: iocharset name "
1081 "too long.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 return 1;
1083 }
1084 } else if (strnicmp(data, "uid", 3) == 0) {
1085 if (value && *value) {
1086 vol->linux_uid =
1087 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001088 vol->override_uid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 }
1090 } else if (strnicmp(data, "gid", 3) == 0) {
1091 if (value && *value) {
1092 vol->linux_gid =
1093 simple_strtoul(value, &value, 0);
Steve French4523cc32007-04-30 20:13:06 +00001094 vol->override_gid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 }
1096 } else if (strnicmp(data, "file_mode", 4) == 0) {
1097 if (value && *value) {
1098 vol->file_mode =
1099 simple_strtoul(value, &value, 0);
1100 }
1101 } else if (strnicmp(data, "dir_mode", 4) == 0) {
1102 if (value && *value) {
1103 vol->dir_mode =
1104 simple_strtoul(value, &value, 0);
1105 }
1106 } else if (strnicmp(data, "dirmode", 4) == 0) {
1107 if (value && *value) {
1108 vol->dir_mode =
1109 simple_strtoul(value, &value, 0);
1110 }
1111 } else if (strnicmp(data, "port", 4) == 0) {
1112 if (value && *value) {
1113 vol->port =
1114 simple_strtoul(value, &value, 0);
1115 }
1116 } else if (strnicmp(data, "rsize", 5) == 0) {
1117 if (value && *value) {
1118 vol->rsize =
1119 simple_strtoul(value, &value, 0);
1120 }
1121 } else if (strnicmp(data, "wsize", 5) == 0) {
1122 if (value && *value) {
1123 vol->wsize =
1124 simple_strtoul(value, &value, 0);
1125 }
1126 } else if (strnicmp(data, "sockopt", 5) == 0) {
1127 if (value && *value) {
1128 vol->sockopt =
1129 simple_strtoul(value, &value, 0);
1130 }
1131 } else if (strnicmp(data, "netbiosname", 4) == 0) {
1132 if (!value || !*value || (*value == ' ')) {
Steve French63135e02007-07-17 17:34:02 +00001133 cFYI(1, ("invalid (empty) netbiosname"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 } else {
Steve French50c2f752007-07-13 00:33:32 +00001135 memset(vol->source_rfc1001_name, 0x20, 15);
1136 for (i = 0; i < 15; i++) {
1137 /* BB are there cases in which a comma can be
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 valid in this workstation netbios name (and need
1139 special handling)? */
1140
1141 /* We do not uppercase netbiosname for user */
Steve French50c2f752007-07-13 00:33:32 +00001142 if (value[i] == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 break;
Steve French50c2f752007-07-13 00:33:32 +00001144 else
1145 vol->source_rfc1001_name[i] =
1146 value[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 }
1148 /* The string has 16th byte zero still from
1149 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001150 if ((i == 15) && (value[i] != 0))
1151 printk(KERN_WARNING "CIFS: netbiosname"
1152 " longer than 15 truncated.\n");
Steve Frencha10faeb22005-08-22 21:38:31 -07001153 }
1154 } else if (strnicmp(data, "servern", 7) == 0) {
1155 /* servernetbiosname specified override *SMBSERVER */
1156 if (!value || !*value || (*value == ' ')) {
Steve French467a8f82007-06-27 22:41:32 +00001157 cFYI(1, ("empty server netbiosname specified"));
Steve Frencha10faeb22005-08-22 21:38:31 -07001158 } else {
1159 /* last byte, type, is 0x20 for servr type */
Steve French50c2f752007-07-13 00:33:32 +00001160 memset(vol->target_rfc1001_name, 0x20, 16);
Steve Frencha10faeb22005-08-22 21:38:31 -07001161
Steve French50c2f752007-07-13 00:33:32 +00001162 for (i = 0; i < 15; i++) {
Steve Frencha10faeb22005-08-22 21:38:31 -07001163 /* BB are there cases in which a comma can be
Steve French50c2f752007-07-13 00:33:32 +00001164 valid in this workstation netbios name
1165 (and need special handling)? */
Steve Frencha10faeb22005-08-22 21:38:31 -07001166
Steve French50c2f752007-07-13 00:33:32 +00001167 /* user or mount helper must uppercase
1168 the netbiosname */
1169 if (value[i] == 0)
Steve Frencha10faeb22005-08-22 21:38:31 -07001170 break;
1171 else
Steve French50c2f752007-07-13 00:33:32 +00001172 vol->target_rfc1001_name[i] =
1173 value[i];
Steve Frencha10faeb22005-08-22 21:38:31 -07001174 }
1175 /* The string has 16th byte zero still from
1176 set at top of the function */
Steve French50c2f752007-07-13 00:33:32 +00001177 if ((i == 15) && (value[i] != 0))
1178 printk(KERN_WARNING "CIFS: server net"
1179 "biosname longer than 15 truncated.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 }
1181 } else if (strnicmp(data, "credentials", 4) == 0) {
1182 /* ignore */
1183 } else if (strnicmp(data, "version", 3) == 0) {
1184 /* ignore */
Steve French50c2f752007-07-13 00:33:32 +00001185 } else if (strnicmp(data, "guest", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 /* ignore */
1187 } else if (strnicmp(data, "rw", 2) == 0) {
Steve French4b18f2a2008-04-29 00:06:05 +00001188 vol->rw = true;
Steve Frenchedf1ae42008-10-29 00:47:57 +00001189 } else if (strnicmp(data, "noblocksend", 11) == 0) {
1190 vol->noblocksnd = 1;
1191 } else if (strnicmp(data, "noautotune", 10) == 0) {
1192 vol->noautotune = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 } else if ((strnicmp(data, "suid", 4) == 0) ||
1194 (strnicmp(data, "nosuid", 6) == 0) ||
1195 (strnicmp(data, "exec", 4) == 0) ||
1196 (strnicmp(data, "noexec", 6) == 0) ||
1197 (strnicmp(data, "nodev", 5) == 0) ||
1198 (strnicmp(data, "noauto", 6) == 0) ||
1199 (strnicmp(data, "dev", 3) == 0)) {
1200 /* The mount tool or mount.cifs helper (if present)
Steve French50c2f752007-07-13 00:33:32 +00001201 uses these opts to set flags, and the flags are read
1202 by the kernel vfs layer before we get here (ie
1203 before read super) so there is no point trying to
1204 parse these options again and set anything and it
1205 is ok to just ignore them */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 continue;
1207 } else if (strnicmp(data, "ro", 2) == 0) {
Steve French4b18f2a2008-04-29 00:06:05 +00001208 vol->rw = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 } else if (strnicmp(data, "hard", 4) == 0) {
1210 vol->retry = 1;
1211 } else if (strnicmp(data, "soft", 4) == 0) {
1212 vol->retry = 0;
1213 } else if (strnicmp(data, "perm", 4) == 0) {
1214 vol->noperm = 0;
1215 } else if (strnicmp(data, "noperm", 6) == 0) {
1216 vol->noperm = 1;
Steve French6a0b4822005-04-28 22:41:05 -07001217 } else if (strnicmp(data, "mapchars", 8) == 0) {
1218 vol->remap = 1;
1219 } else if (strnicmp(data, "nomapchars", 10) == 0) {
1220 vol->remap = 0;
Steve French50c2f752007-07-13 00:33:32 +00001221 } else if (strnicmp(data, "sfu", 3) == 0) {
1222 vol->sfu_emul = 1;
1223 } else if (strnicmp(data, "nosfu", 5) == 0) {
1224 vol->sfu_emul = 0;
Steve French2c1b8612008-10-16 18:35:21 +00001225 } else if (strnicmp(data, "nodfs", 5) == 0) {
1226 vol->nodfs = 1;
Jeremy Allisonac670552005-06-22 17:26:35 -07001227 } else if (strnicmp(data, "posixpaths", 10) == 0) {
1228 vol->posix_paths = 1;
1229 } else if (strnicmp(data, "noposixpaths", 12) == 0) {
1230 vol->posix_paths = 0;
Steve Frenchc18c8422007-07-18 23:21:09 +00001231 } else if (strnicmp(data, "nounix", 6) == 0) {
1232 vol->no_linux_ext = 1;
1233 } else if (strnicmp(data, "nolinux", 7) == 0) {
1234 vol->no_linux_ext = 1;
Steve French50c2f752007-07-13 00:33:32 +00001235 } else if ((strnicmp(data, "nocase", 6) == 0) ||
Steve Frencha10faeb22005-08-22 21:38:31 -07001236 (strnicmp(data, "ignorecase", 10) == 0)) {
Steve French50c2f752007-07-13 00:33:32 +00001237 vol->nocase = 1;
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001238 } else if (strnicmp(data, "brl", 3) == 0) {
1239 vol->nobrl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001240 } else if ((strnicmp(data, "nobrl", 5) == 0) ||
Steve French1c955182005-08-30 20:58:07 -07001241 (strnicmp(data, "nolock", 6) == 0)) {
Steve Frenchc46fa8a2005-08-18 20:49:57 -07001242 vol->nobrl = 1;
Steve Frenchd3485d32005-08-19 11:04:29 -07001243 /* turn off mandatory locking in mode
1244 if remote locking is turned off since the
1245 local vfs will do advisory */
Steve French50c2f752007-07-13 00:33:32 +00001246 if (vol->file_mode ==
1247 (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
Steve Frenchd3485d32005-08-19 11:04:29 -07001248 vol->file_mode = S_IALLUGO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 } else if (strnicmp(data, "setuids", 7) == 0) {
1250 vol->setuids = 1;
1251 } else if (strnicmp(data, "nosetuids", 9) == 0) {
1252 vol->setuids = 0;
Jeff Laytond0a9c072008-05-12 22:23:49 +00001253 } else if (strnicmp(data, "dynperm", 7) == 0) {
1254 vol->dynperm = true;
1255 } else if (strnicmp(data, "nodynperm", 9) == 0) {
1256 vol->dynperm = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 } else if (strnicmp(data, "nohard", 6) == 0) {
1258 vol->retry = 0;
1259 } else if (strnicmp(data, "nosoft", 6) == 0) {
1260 vol->retry = 1;
1261 } else if (strnicmp(data, "nointr", 6) == 0) {
1262 vol->intr = 0;
1263 } else if (strnicmp(data, "intr", 4) == 0) {
1264 vol->intr = 1;
Steve French50c2f752007-07-13 00:33:32 +00001265 } else if (strnicmp(data, "serverino", 7) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 vol->server_ino = 1;
Steve French50c2f752007-07-13 00:33:32 +00001267 } else if (strnicmp(data, "noserverino", 9) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 vol->server_ino = 0;
Steve French50c2f752007-07-13 00:33:32 +00001269 } else if (strnicmp(data, "cifsacl", 7) == 0) {
Steve French0a4b92c2006-01-12 15:44:21 -08001270 vol->cifs_acl = 1;
1271 } else if (strnicmp(data, "nocifsacl", 9) == 0) {
1272 vol->cifs_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001273 } else if (strnicmp(data, "acl", 3) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 vol->no_psx_acl = 0;
Steve French50c2f752007-07-13 00:33:32 +00001275 } else if (strnicmp(data, "noacl", 5) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 vol->no_psx_acl = 1;
Steve French84210e92008-10-23 04:42:37 +00001277#ifdef CONFIG_CIFS_EXPERIMENTAL
1278 } else if (strnicmp(data, "locallease", 6) == 0) {
1279 vol->local_lease = 1;
1280#endif
Steve French50c2f752007-07-13 00:33:32 +00001281 } else if (strnicmp(data, "sign", 4) == 0) {
Steve French750d1152006-06-27 06:28:30 +00001282 vol->secFlg |= CIFSSEC_MUST_SIGN;
Steve French95b1cb92008-05-15 16:44:38 +00001283 } else if (strnicmp(data, "seal", 4) == 0) {
1284 /* we do not do the following in secFlags because seal
1285 is a per tree connection (mount) not a per socket
1286 or per-smb connection option in the protocol */
1287 /* vol->secFlg |= CIFSSEC_MUST_SEAL; */
1288 vol->seal = 1;
Steve French50c2f752007-07-13 00:33:32 +00001289 } else if (strnicmp(data, "direct", 6) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001291 } else if (strnicmp(data, "forcedirectio", 13) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 vol->direct_io = 1;
Steve French50c2f752007-07-13 00:33:32 +00001293 } else if (strnicmp(data, "in6_addr", 8) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 if (!value || !*value) {
1295 vol->in6_addr = NULL;
1296 } else if (strnlen(value, 49) == 48) {
1297 vol->in6_addr = value;
1298 } else {
Steve French50c2f752007-07-13 00:33:32 +00001299 printk(KERN_WARNING "CIFS: ip v6 address not "
1300 "48 characters long\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 return 1;
1302 }
1303 } else if (strnicmp(data, "noac", 4) == 0) {
Steve French50c2f752007-07-13 00:33:32 +00001304 printk(KERN_WARNING "CIFS: Mount option noac not "
1305 "supported. Instead set "
1306 "/proc/fs/cifs/LookupCacheEnabled to 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 } else
Steve French50c2f752007-07-13 00:33:32 +00001308 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",
1309 data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 }
1311 if (vol->UNC == NULL) {
Steve French4523cc32007-04-30 20:13:06 +00001312 if (devname == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001313 printk(KERN_WARNING "CIFS: Missing UNC name for mount "
1314 "target\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 return 1;
1316 }
1317 if ((temp_len = strnlen(devname, 300)) < 300) {
Steve French50c2f752007-07-13 00:33:32 +00001318 vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
Steve French4523cc32007-04-30 20:13:06 +00001319 if (vol->UNC == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 return 1;
Steve French50c2f752007-07-13 00:33:32 +00001321 strcpy(vol->UNC, devname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 if (strncmp(vol->UNC, "//", 2) == 0) {
1323 vol->UNC[0] = '\\';
1324 vol->UNC[1] = '\\';
1325 } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
Steve French50c2f752007-07-13 00:33:32 +00001326 printk(KERN_WARNING "CIFS: UNC Path does not "
1327 "begin with // or \\\\ \n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 return 1;
1329 }
Igor Mammedov7c5e6282008-05-08 20:48:42 +00001330 value = strpbrk(vol->UNC+2, "/\\");
1331 if (value)
1332 *value = '\\';
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 } else {
1334 printk(KERN_WARNING "CIFS: UNC name too long\n");
1335 return 1;
1336 }
1337 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001338 if (vol->UNCip == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 vol->UNCip = &vol->UNC[2];
1340
1341 return 0;
1342}
1343
Jeff Laytone7ddee92008-11-14 13:44:38 -05001344static struct TCP_Server_Info *
1345cifs_find_tcp_session(struct sockaddr *addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346{
1347 struct list_head *tmp;
Jeff Laytone7ddee92008-11-14 13:44:38 -05001348 struct TCP_Server_Info *server;
1349 struct sockaddr_in *addr4 = (struct sockaddr_in *) addr;
1350 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351
Jeff Laytone7ddee92008-11-14 13:44:38 -05001352 write_lock(&cifs_tcp_ses_lock);
1353 list_for_each(tmp, &cifs_tcp_ses_list) {
1354 server = list_entry(tmp, struct TCP_Server_Info,
1355 tcp_ses_list);
Jeff Laytone7ddee92008-11-14 13:44:38 -05001356 /*
1357 * the demux thread can exit on its own while still in CifsNew
1358 * so don't accept any sockets in that state. Since the
1359 * tcpStatus never changes back to CifsNew it's safe to check
1360 * for this without a lock.
1361 */
1362 if (server->tcpStatus == CifsNew)
Cyrill Gorcunov1b20d672008-05-09 18:17:21 +00001363 continue;
Steve French50c2f752007-07-13 00:33:32 +00001364
Jeff Laytone7ddee92008-11-14 13:44:38 -05001365 if (addr->sa_family == AF_INET &&
1366 (addr4->sin_addr.s_addr !=
1367 server->addr.sockAddr.sin_addr.s_addr))
1368 continue;
1369 else if (addr->sa_family == AF_INET6 &&
1370 memcmp(&server->addr.sockAddr6.sin6_addr,
1371 &addr6->sin6_addr, sizeof(addr6->sin6_addr)))
1372 continue;
Steve French50c2f752007-07-13 00:33:32 +00001373
Jeff Laytone7ddee92008-11-14 13:44:38 -05001374 ++server->srv_count;
1375 write_unlock(&cifs_tcp_ses_lock);
Steve Frenchd82c2df2008-11-15 00:07:26 +00001376 cFYI(1, ("Existing tcp session with server found"));
Jeff Laytone7ddee92008-11-14 13:44:38 -05001377 return server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 }
Jeff Laytone7ddee92008-11-14 13:44:38 -05001379 write_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 return NULL;
1381}
1382
Jeff Layton14fbf502008-11-14 13:53:46 -05001383static void
Jeff Laytone7ddee92008-11-14 13:44:38 -05001384cifs_put_tcp_session(struct TCP_Server_Info *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385{
Jeff Laytone7ddee92008-11-14 13:44:38 -05001386 struct task_struct *task;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387
Jeff Laytone7ddee92008-11-14 13:44:38 -05001388 write_lock(&cifs_tcp_ses_lock);
1389 if (--server->srv_count > 0) {
1390 write_unlock(&cifs_tcp_ses_lock);
1391 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 }
Steve Frenchdea570e02008-05-06 22:05:51 +00001393
Jeff Laytone7ddee92008-11-14 13:44:38 -05001394 list_del_init(&server->tcp_ses_list);
1395 write_unlock(&cifs_tcp_ses_lock);
1396
1397 spin_lock(&GlobalMid_Lock);
1398 server->tcpStatus = CifsExiting;
1399 spin_unlock(&GlobalMid_Lock);
1400
1401 task = xchg(&server->tsk, NULL);
1402 if (task)
1403 force_sig(SIGKILL, task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404}
1405
Jeff Layton63c038c2008-12-01 18:41:46 -05001406static struct TCP_Server_Info *
1407cifs_get_tcp_session(struct smb_vol *volume_info)
1408{
1409 struct TCP_Server_Info *tcp_ses = NULL;
1410 struct sockaddr addr;
1411 struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr;
1412 struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr;
1413 int rc;
1414
1415 memset(&addr, 0, sizeof(struct sockaddr));
1416
1417 if (volume_info->UNCip && volume_info->UNC) {
1418 rc = cifs_inet_pton(AF_INET, volume_info->UNCip,
1419 &sin_server->sin_addr.s_addr);
1420
1421 if (rc <= 0) {
1422 /* not ipv4 address, try ipv6 */
1423 rc = cifs_inet_pton(AF_INET6, volume_info->UNCip,
1424 &sin_server6->sin6_addr.in6_u);
1425 if (rc > 0)
1426 addr.sa_family = AF_INET6;
1427 } else {
1428 addr.sa_family = AF_INET;
1429 }
1430
1431 if (rc <= 0) {
1432 /* we failed translating address */
1433 rc = -EINVAL;
1434 goto out_err;
1435 }
1436
1437 cFYI(1, ("UNC: %s ip: %s", volume_info->UNC,
1438 volume_info->UNCip));
1439 } else if (volume_info->UNCip) {
1440 /* BB using ip addr as tcp_ses name to connect to the
1441 DFS root below */
1442 cERROR(1, ("Connecting to DFS root not implemented yet"));
1443 rc = -EINVAL;
1444 goto out_err;
1445 } else /* which tcp_sess DFS root would we conect to */ {
1446 cERROR(1,
1447 ("CIFS mount error: No UNC path (e.g. -o "
1448 "unc=//192.168.1.100/public) specified"));
1449 rc = -EINVAL;
1450 goto out_err;
1451 }
1452
1453 /* see if we already have a matching tcp_ses */
1454 tcp_ses = cifs_find_tcp_session(&addr);
1455 if (tcp_ses)
1456 return tcp_ses;
1457
1458 tcp_ses = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
1459 if (!tcp_ses) {
1460 rc = -ENOMEM;
1461 goto out_err;
1462 }
1463
1464 tcp_ses->hostname = extract_hostname(volume_info->UNC);
1465 if (IS_ERR(tcp_ses->hostname)) {
1466 rc = PTR_ERR(tcp_ses->hostname);
1467 goto out_err;
1468 }
1469
1470 tcp_ses->noblocksnd = volume_info->noblocksnd;
1471 tcp_ses->noautotune = volume_info->noautotune;
1472 atomic_set(&tcp_ses->inFlight, 0);
1473 init_waitqueue_head(&tcp_ses->response_q);
1474 init_waitqueue_head(&tcp_ses->request_q);
1475 INIT_LIST_HEAD(&tcp_ses->pending_mid_q);
1476 mutex_init(&tcp_ses->srv_mutex);
1477 memcpy(tcp_ses->workstation_RFC1001_name,
1478 volume_info->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
1479 memcpy(tcp_ses->server_RFC1001_name,
1480 volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
1481 tcp_ses->sequence_number = 0;
1482 INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
1483 INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
1484
1485 /*
1486 * at this point we are the only ones with the pointer
1487 * to the struct since the kernel thread not created yet
1488 * no need to spinlock this init of tcpStatus or srv_count
1489 */
1490 tcp_ses->tcpStatus = CifsNew;
1491 ++tcp_ses->srv_count;
1492
1493 if (addr.sa_family == AF_INET6) {
1494 cFYI(1, ("attempting ipv6 connect"));
1495 /* BB should we allow ipv6 on port 139? */
1496 /* other OS never observed in Wild doing 139 with v6 */
1497 memcpy(&tcp_ses->addr.sockAddr6, sin_server6,
1498 sizeof(struct sockaddr_in6));
1499 sin_server6->sin6_port = htons(volume_info->port);
Jeff Laytond5c56052008-12-01 18:42:33 -05001500 rc = ipv6_connect(tcp_ses);
Jeff Layton63c038c2008-12-01 18:41:46 -05001501 } else {
1502 memcpy(&tcp_ses->addr.sockAddr, sin_server,
1503 sizeof(struct sockaddr_in));
1504 sin_server->sin_port = htons(volume_info->port);
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001505 rc = ipv4_connect(tcp_ses);
Jeff Layton63c038c2008-12-01 18:41:46 -05001506 }
1507 if (rc < 0) {
1508 cERROR(1, ("Error connecting to socket. Aborting operation"));
1509 goto out_err;
1510 }
1511
1512 /*
1513 * since we're in a cifs function already, we know that
1514 * this will succeed. No need for try_module_get().
1515 */
1516 __module_get(THIS_MODULE);
1517 tcp_ses->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread,
1518 tcp_ses, "cifsd");
1519 if (IS_ERR(tcp_ses->tsk)) {
1520 rc = PTR_ERR(tcp_ses->tsk);
1521 cERROR(1, ("error %d create cifsd thread", rc));
1522 module_put(THIS_MODULE);
1523 goto out_err;
1524 }
1525
1526 /* thread spawned, put it on the list */
1527 write_lock(&cifs_tcp_ses_lock);
1528 list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list);
1529 write_unlock(&cifs_tcp_ses_lock);
1530
1531 return tcp_ses;
1532
1533out_err:
1534 if (tcp_ses) {
1535 kfree(tcp_ses->hostname);
1536 if (tcp_ses->ssocket)
1537 sock_release(tcp_ses->ssocket);
1538 kfree(tcp_ses);
1539 }
1540 return ERR_PTR(rc);
1541}
1542
Jeff Layton14fbf502008-11-14 13:53:46 -05001543static struct cifsSesInfo *
1544cifs_find_smb_ses(struct TCP_Server_Info *server, char *username)
1545{
1546 struct list_head *tmp;
1547 struct cifsSesInfo *ses;
1548
1549 write_lock(&cifs_tcp_ses_lock);
1550 list_for_each(tmp, &server->smb_ses_list) {
1551 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
1552 if (strncmp(ses->userName, username, MAX_USERNAME_SIZE))
1553 continue;
1554
1555 ++ses->ses_count;
1556 write_unlock(&cifs_tcp_ses_lock);
1557 return ses;
1558 }
1559 write_unlock(&cifs_tcp_ses_lock);
1560 return NULL;
1561}
1562
1563static void
1564cifs_put_smb_ses(struct cifsSesInfo *ses)
1565{
1566 int xid;
1567 struct TCP_Server_Info *server = ses->server;
1568
1569 write_lock(&cifs_tcp_ses_lock);
1570 if (--ses->ses_count > 0) {
1571 write_unlock(&cifs_tcp_ses_lock);
1572 return;
1573 }
1574
1575 list_del_init(&ses->smb_ses_list);
1576 write_unlock(&cifs_tcp_ses_lock);
1577
1578 if (ses->status == CifsGood) {
1579 xid = GetXid();
1580 CIFSSMBLogoff(xid, ses);
1581 _FreeXid(xid);
1582 }
1583 sesInfoFree(ses);
1584 cifs_put_tcp_session(server);
1585}
1586
Jeff Laytonf1987b42008-11-15 11:12:47 -05001587static struct cifsTconInfo *
1588cifs_find_tcon(struct cifsSesInfo *ses, const char *unc)
1589{
1590 struct list_head *tmp;
1591 struct cifsTconInfo *tcon;
1592
1593 write_lock(&cifs_tcp_ses_lock);
1594 list_for_each(tmp, &ses->tcon_list) {
1595 tcon = list_entry(tmp, struct cifsTconInfo, tcon_list);
1596 if (tcon->tidStatus == CifsExiting)
1597 continue;
1598 if (strncmp(tcon->treeName, unc, MAX_TREE_SIZE))
1599 continue;
1600
1601 ++tcon->tc_count;
1602 write_unlock(&cifs_tcp_ses_lock);
1603 return tcon;
1604 }
1605 write_unlock(&cifs_tcp_ses_lock);
1606 return NULL;
1607}
1608
1609static void
1610cifs_put_tcon(struct cifsTconInfo *tcon)
1611{
1612 int xid;
1613 struct cifsSesInfo *ses = tcon->ses;
1614
1615 write_lock(&cifs_tcp_ses_lock);
1616 if (--tcon->tc_count > 0) {
1617 write_unlock(&cifs_tcp_ses_lock);
1618 return;
1619 }
1620
1621 list_del_init(&tcon->tcon_list);
1622 write_unlock(&cifs_tcp_ses_lock);
1623
1624 xid = GetXid();
1625 CIFSSMBTDis(xid, tcon);
1626 _FreeXid(xid);
1627
1628 DeleteTconOplockQEntries(tcon);
1629 tconInfoFree(tcon);
1630 cifs_put_smb_ses(ses);
1631}
1632
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633int
Steve French50c2f752007-07-13 00:33:32 +00001634get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
1635 const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
Steve French366781c2008-01-25 10:12:41 +00001636 struct dfs_info3_param **preferrals, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637{
1638 char *temp_unc;
1639 int rc = 0;
1640
1641 *pnum_referrals = 0;
Steve French366781c2008-01-25 10:12:41 +00001642 *preferrals = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643
1644 if (pSesInfo->ipc_tid == 0) {
1645 temp_unc = kmalloc(2 /* for slashes */ +
Steve French50c2f752007-07-13 00:33:32 +00001646 strnlen(pSesInfo->serverName,
1647 SERVER_NAME_LEN_WITH_NULL * 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 + 1 + 4 /* slash IPC$ */ + 2,
1649 GFP_KERNEL);
1650 if (temp_unc == NULL)
1651 return -ENOMEM;
1652 temp_unc[0] = '\\';
1653 temp_unc[1] = '\\';
1654 strcpy(temp_unc + 2, pSesInfo->serverName);
1655 strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
1656 rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
1657 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00001658 ("CIFS Tcon rc = %d ipc_tid = %d", rc, pSesInfo->ipc_tid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659 kfree(temp_unc);
1660 }
1661 if (rc == 0)
Steve Frenchc2cf07d2008-05-15 06:20:02 +00001662 rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
Steve French737b7582005-04-28 22:41:06 -07001663 pnum_referrals, nls_codepage, remap);
Steve French366781c2008-01-25 10:12:41 +00001664 /* BB map targetUNCs to dfs_info3 structures, here or
1665 in CIFSGetDFSRefer BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666
1667 return rc;
1668}
1669
Jeff Layton09e50d52008-07-23 10:11:19 -04001670#ifdef CONFIG_DEBUG_LOCK_ALLOC
1671static struct lock_class_key cifs_key[2];
1672static struct lock_class_key cifs_slock_key[2];
1673
1674static inline void
1675cifs_reclassify_socket4(struct socket *sock)
1676{
1677 struct sock *sk = sock->sk;
1678 BUG_ON(sock_owned_by_user(sk));
1679 sock_lock_init_class_and_name(sk, "slock-AF_INET-CIFS",
1680 &cifs_slock_key[0], "sk_lock-AF_INET-CIFS", &cifs_key[0]);
1681}
1682
1683static inline void
1684cifs_reclassify_socket6(struct socket *sock)
1685{
1686 struct sock *sk = sock->sk;
1687 BUG_ON(sock_owned_by_user(sk));
1688 sock_lock_init_class_and_name(sk, "slock-AF_INET6-CIFS",
1689 &cifs_slock_key[1], "sk_lock-AF_INET6-CIFS", &cifs_key[1]);
1690}
1691#else
1692static inline void
1693cifs_reclassify_socket4(struct socket *sock)
1694{
1695}
1696
1697static inline void
1698cifs_reclassify_socket6(struct socket *sock)
1699{
1700}
1701#endif
1702
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703/* See RFC1001 section 14 on representation of Netbios names */
Steve French50c2f752007-07-13 00:33:32 +00001704static void rfc1002mangle(char *target, char *source, unsigned int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705{
Steve French50c2f752007-07-13 00:33:32 +00001706 unsigned int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707
Steve French50c2f752007-07-13 00:33:32 +00001708 for (i = 0, j = 0; i < (length); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 /* mask a nibble at a time and encode */
1710 target[j] = 'A' + (0x0F & (source[i] >> 4));
1711 target[j+1] = 'A' + (0x0F & source[i]);
Steve French50c2f752007-07-13 00:33:32 +00001712 j += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 }
1714
1715}
1716
1717
1718static int
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001719ipv4_connect(struct TCP_Server_Info *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720{
1721 int rc = 0;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001722 bool connected = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 __be16 orig_port = 0;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001724 struct socket *socket = server->ssocket;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001726 if (socket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001727 rc = sock_create_kern(PF_INET, SOCK_STREAM,
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001728 IPPROTO_TCP, &socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001730 cERROR(1, ("Error %d creating socket", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 }
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001733
1734 /* BB other socket options to set KEEPALIVE, NODELAY? */
1735 cFYI(1, ("Socket created"));
1736 server->ssocket = socket;
1737 socket->sk->sk_allocation = GFP_NOFS;
1738 cifs_reclassify_socket4(socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 }
1740
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001741 /* user overrode default port */
1742 if (server->addr.sockAddr.sin_port) {
1743 rc = socket->ops->connect(socket, (struct sockaddr *)
1744 &server->addr.sockAddr,
1745 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 if (rc >= 0)
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001747 connected = true;
Steve French50c2f752007-07-13 00:33:32 +00001748 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001750 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001751 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 later if fall back ports fail this time */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001753 orig_port = server->addr.sockAddr.sin_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754
1755 /* do not retry on the same port we just failed on */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001756 if (server->addr.sockAddr.sin_port != htons(CIFS_PORT)) {
1757 server->addr.sockAddr.sin_port = htons(CIFS_PORT);
1758 rc = socket->ops->connect(socket,
1759 (struct sockaddr *)
1760 &server->addr.sockAddr,
1761 sizeof(struct sockaddr_in), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762 if (rc >= 0)
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001763 connected = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 }
1765 }
1766 if (!connected) {
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001767 server->addr.sockAddr.sin_port = htons(RFC1001_PORT);
1768 rc = socket->ops->connect(socket, (struct sockaddr *)
1769 &server->addr.sockAddr,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001770 sizeof(struct sockaddr_in), 0);
Steve French50c2f752007-07-13 00:33:32 +00001771 if (rc >= 0)
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001772 connected = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 }
1774
1775 /* give up here - unless we want to retry on different
1776 protocol families some day */
1777 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001778 if (orig_port)
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001779 server->addr.sockAddr.sin_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001780 cFYI(1, ("Error %d connecting to server via ipv4", rc));
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001781 sock_release(socket);
1782 server->ssocket = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 return rc;
1784 }
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001785
1786
1787 /*
1788 * Eventually check for other socket options to change from
1789 * the default. sock_setsockopt not used because it expects
1790 * user space buffer
1791 */
1792 socket->sk->sk_rcvtimeo = 7 * HZ;
1793 socket->sk->sk_sndtimeo = 3 * HZ;
Steve Frenchedf1ae42008-10-29 00:47:57 +00001794
Steve Frenchb387eae2005-10-10 14:21:15 -07001795 /* make the bufsizes depend on wsize/rsize and max requests */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001796 if (server->noautotune) {
1797 if (socket->sk->sk_sndbuf < (200 * 1024))
1798 socket->sk->sk_sndbuf = 200 * 1024;
1799 if (socket->sk->sk_rcvbuf < (140 * 1024))
1800 socket->sk->sk_rcvbuf = 140 * 1024;
Steve Frenchedf1ae42008-10-29 00:47:57 +00001801 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001803 cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",
1804 socket->sk->sk_sndbuf,
1805 socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo));
1806
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 /* send RFC1001 sessinit */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001808 if (server->addr.sockAddr.sin_port == htons(RFC1001_PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 /* some servers require RFC1001 sessinit before sending
Steve French50c2f752007-07-13 00:33:32 +00001810 negprot - BB check reconnection in case where second
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 sessinit is sent but no second negprot */
Steve French50c2f752007-07-13 00:33:32 +00001812 struct rfc1002_session_packet *ses_init_buf;
1813 struct smb_hdr *smb_buf;
1814 ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
1815 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001816 if (ses_init_buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 ses_init_buf->trailer.session_req.called_len = 32;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001818 if (server->server_RFC1001_name &&
1819 server->server_RFC1001_name[0] != 0)
Jeff Layton8ecaf672008-12-01 15:23:50 -05001820 rfc1002mangle(ses_init_buf->trailer.
1821 session_req.called_name,
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001822 server->server_RFC1001_name,
Jeff Layton8ecaf672008-12-01 15:23:50 -05001823 RFC1001_NAME_LEN_WITH_NULL);
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001824 else
Jeff Layton8ecaf672008-12-01 15:23:50 -05001825 rfc1002mangle(ses_init_buf->trailer.
1826 session_req.called_name,
1827 DEFAULT_CIFS_CALLED_NAME,
1828 RFC1001_NAME_LEN_WITH_NULL);
Steve Frencha10faeb22005-08-22 21:38:31 -07001829
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 ses_init_buf->trailer.session_req.calling_len = 32;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001831
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 /* calling name ends in null (byte 16) from old smb
1833 convention. */
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001834 if (server->workstation_RFC1001_name &&
1835 server->workstation_RFC1001_name[0] != 0)
Jeff Layton8ecaf672008-12-01 15:23:50 -05001836 rfc1002mangle(ses_init_buf->trailer.
1837 session_req.calling_name,
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001838 server->workstation_RFC1001_name,
Jeff Layton8ecaf672008-12-01 15:23:50 -05001839 RFC1001_NAME_LEN_WITH_NULL);
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001840 else
Jeff Layton8ecaf672008-12-01 15:23:50 -05001841 rfc1002mangle(ses_init_buf->trailer.
1842 session_req.calling_name,
1843 "LINUX_CIFS_CLNT",
1844 RFC1001_NAME_LEN_WITH_NULL);
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001845
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 ses_init_buf->trailer.session_req.scope1 = 0;
1847 ses_init_buf->trailer.session_req.scope2 = 0;
1848 smb_buf = (struct smb_hdr *)ses_init_buf;
1849 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1850 smb_buf->smb_buf_length = 0x81000044;
Jeff Laytonbcf4b102008-12-01 18:42:15 -05001851 rc = smb_send(socket, smb_buf, 0x44,
1852 (struct sockaddr *) &server->addr.sockAddr,
1853 server->noblocksnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 kfree(ses_init_buf);
Steve French50c2f752007-07-13 00:33:32 +00001855 msleep(1); /* RFC1001 layer in at least one server
Steve French083d3a22006-03-03 09:53:36 +00001856 requires very short break before negprot
1857 presumably because not expecting negprot
1858 to follow so fast. This is a simple
Steve French50c2f752007-07-13 00:33:32 +00001859 solution that works without
Steve French083d3a22006-03-03 09:53:36 +00001860 complicating the code and causes no
1861 significant slowing down on mount
1862 for everyone else */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 }
Steve French50c2f752007-07-13 00:33:32 +00001864 /* else the negprot may still work without this
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 even though malloc failed */
Steve French50c2f752007-07-13 00:33:32 +00001866
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 }
Steve French50c2f752007-07-13 00:33:32 +00001868
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 return rc;
1870}
1871
1872static int
Jeff Laytond5c56052008-12-01 18:42:33 -05001873ipv6_connect(struct TCP_Server_Info *server)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874{
1875 int rc = 0;
Jeff Laytond5c56052008-12-01 18:42:33 -05001876 bool connected = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 __be16 orig_port = 0;
Jeff Laytond5c56052008-12-01 18:42:33 -05001878 struct socket *socket = server->ssocket;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879
Jeff Laytond5c56052008-12-01 18:42:33 -05001880 if (socket == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001881 rc = sock_create_kern(PF_INET6, SOCK_STREAM,
Jeff Laytond5c56052008-12-01 18:42:33 -05001882 IPPROTO_TCP, &socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 if (rc < 0) {
Steve French50c2f752007-07-13 00:33:32 +00001884 cERROR(1, ("Error %d creating ipv6 socket", rc));
Jeff Laytond5c56052008-12-01 18:42:33 -05001885 socket = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 }
Jeff Laytond5c56052008-12-01 18:42:33 -05001888
1889 /* BB other socket options to set KEEPALIVE, NODELAY? */
1890 cFYI(1, ("ipv6 Socket created"));
1891 server->ssocket = socket;
1892 socket->sk->sk_allocation = GFP_NOFS;
1893 cifs_reclassify_socket6(socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 }
1895
Jeff Laytond5c56052008-12-01 18:42:33 -05001896 /* user overrode default port */
1897 if (server->addr.sockAddr6.sin6_port) {
1898 rc = socket->ops->connect(socket,
1899 (struct sockaddr *) &server->addr.sockAddr6,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001900 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 if (rc >= 0)
Jeff Laytond5c56052008-12-01 18:42:33 -05001902 connected = true;
Steve French50c2f752007-07-13 00:33:32 +00001903 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001905 if (!connected) {
Steve French50c2f752007-07-13 00:33:32 +00001906 /* save original port so we can retry user specified port
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 later if fall back ports fail this time */
1908
Jeff Laytond5c56052008-12-01 18:42:33 -05001909 orig_port = server->addr.sockAddr6.sin6_port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 /* do not retry on the same port we just failed on */
Jeff Laytond5c56052008-12-01 18:42:33 -05001911 if (server->addr.sockAddr6.sin6_port != htons(CIFS_PORT)) {
1912 server->addr.sockAddr6.sin6_port = htons(CIFS_PORT);
1913 rc = socket->ops->connect(socket, (struct sockaddr *)
1914 &server->addr.sockAddr6,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00001915 sizeof(struct sockaddr_in6), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 if (rc >= 0)
Jeff Laytond5c56052008-12-01 18:42:33 -05001917 connected = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 }
1919 }
1920 if (!connected) {
Jeff Laytond5c56052008-12-01 18:42:33 -05001921 server->addr.sockAddr6.sin6_port = htons(RFC1001_PORT);
1922 rc = socket->ops->connect(socket, (struct sockaddr *)
1923 &server->addr.sockAddr6,
1924 sizeof(struct sockaddr_in6), 0);
Steve French50c2f752007-07-13 00:33:32 +00001925 if (rc >= 0)
Jeff Laytond5c56052008-12-01 18:42:33 -05001926 connected = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 }
1928
1929 /* give up here - unless we want to retry on different
1930 protocol families some day */
1931 if (!connected) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001932 if (orig_port)
Jeff Laytond5c56052008-12-01 18:42:33 -05001933 server->addr.sockAddr6.sin6_port = orig_port;
Steve French50c2f752007-07-13 00:33:32 +00001934 cFYI(1, ("Error %d connecting to server via ipv6", rc));
Jeff Laytond5c56052008-12-01 18:42:33 -05001935 sock_release(socket);
1936 server->ssocket = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 return rc;
1938 }
Steve Frenchedf1ae42008-10-29 00:47:57 +00001939
Jeff Laytond5c56052008-12-01 18:42:33 -05001940 /*
1941 * Eventually check for other socket options to change from
1942 * the default. sock_setsockopt not used because it expects
1943 * user space buffer
1944 */
1945 socket->sk->sk_rcvtimeo = 7 * HZ;
1946 socket->sk->sk_sndtimeo = 3 * HZ;
1947 server->ssocket = socket;
Steve French50c2f752007-07-13 00:33:32 +00001948
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 return rc;
1950}
1951
Steve French50c2f752007-07-13 00:33:32 +00001952void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
1953 struct super_block *sb, struct smb_vol *vol_info)
Steve French8af18972007-02-14 04:42:51 +00001954{
1955 /* if we are reconnecting then should we check to see if
1956 * any requested capabilities changed locally e.g. via
1957 * remount but we can not do much about it here
1958 * if they have (even if we could detect it by the following)
1959 * Perhaps we could add a backpointer to array of sb from tcon
1960 * or if we change to make all sb to same share the same
1961 * sb as NFS - then we only have one backpointer to sb.
1962 * What if we wanted to mount the server share twice once with
1963 * and once without posixacls or posix paths? */
1964 __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001965
Steve Frenchc18c8422007-07-18 23:21:09 +00001966 if (vol_info && vol_info->no_linux_ext) {
1967 tcon->fsUnixInfo.Capability = 0;
1968 tcon->unix_ext = 0; /* Unix Extensions disabled */
1969 cFYI(1, ("Linux protocol extensions disabled"));
1970 return;
1971 } else if (vol_info)
1972 tcon->unix_ext = 1; /* Unix Extensions supported */
1973
1974 if (tcon->unix_ext == 0) {
1975 cFYI(1, ("Unix extensions disabled so not set on reconnect"));
1976 return;
1977 }
Steve French50c2f752007-07-13 00:33:32 +00001978
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001979 if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
Steve French8af18972007-02-14 04:42:51 +00001980 __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French50c2f752007-07-13 00:33:32 +00001981
Steve French8af18972007-02-14 04:42:51 +00001982 /* check for reconnect case in which we do not
1983 want to change the mount behavior if we can avoid it */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001984 if (vol_info == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001985 /* turn off POSIX ACL and PATHNAMES if not set
Steve French8af18972007-02-14 04:42:51 +00001986 originally at mount time */
1987 if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
1988 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00001989 if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
1990 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
1991 cERROR(1, ("POSIXPATH support change"));
Steve French8af18972007-02-14 04:42:51 +00001992 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Igor Mammedov11b6d642008-02-15 19:06:04 +00001993 } else if ((cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) {
1994 cERROR(1, ("possible reconnect error"));
1995 cERROR(1,
1996 ("server disabled POSIX path support"));
1997 }
Steve French8af18972007-02-14 04:42:51 +00001998 }
Steve French50c2f752007-07-13 00:33:32 +00001999
Steve French8af18972007-02-14 04:42:51 +00002000 cap &= CIFS_UNIX_CAP_MASK;
Steve French75865f8c2007-06-24 18:30:48 +00002001 if (vol_info && vol_info->no_psx_acl)
Steve French8af18972007-02-14 04:42:51 +00002002 cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00002003 else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002004 cFYI(1, ("negotiated posix acl support"));
2005 if (sb)
Steve French8af18972007-02-14 04:42:51 +00002006 sb->s_flags |= MS_POSIXACL;
2007 }
2008
Steve French75865f8c2007-06-24 18:30:48 +00002009 if (vol_info && vol_info->posix_paths == 0)
Steve French8af18972007-02-14 04:42:51 +00002010 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
Steve French75865f8c2007-06-24 18:30:48 +00002011 else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002012 cFYI(1, ("negotiate posix pathnames"));
Steve French75865f8c2007-06-24 18:30:48 +00002013 if (sb)
Steve French50c2f752007-07-13 00:33:32 +00002014 CIFS_SB(sb)->mnt_cifs_flags |=
Steve French8af18972007-02-14 04:42:51 +00002015 CIFS_MOUNT_POSIX_PATHS;
2016 }
Steve French50c2f752007-07-13 00:33:32 +00002017
Steve French984acfe2007-04-26 16:42:50 +00002018 /* We might be setting the path sep back to a different
2019 form if we are reconnecting and the server switched its
Steve French50c2f752007-07-13 00:33:32 +00002020 posix path capability for this share */
Steve French75865f8c2007-06-24 18:30:48 +00002021 if (sb && (CIFS_SB(sb)->prepathlen > 0))
Steve French984acfe2007-04-26 16:42:50 +00002022 CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
Steve French75865f8c2007-06-24 18:30:48 +00002023
2024 if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
2025 if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
2026 CIFS_SB(sb)->rsize = 127 * 1024;
Steve French90c81e02008-02-12 20:32:36 +00002027 cFYI(DBG2,
2028 ("larger reads not supported by srv"));
Steve French75865f8c2007-06-24 18:30:48 +00002029 }
2030 }
Steve French50c2f752007-07-13 00:33:32 +00002031
2032
2033 cFYI(1, ("Negotiate caps 0x%x", (int)cap));
Steve French8af18972007-02-14 04:42:51 +00002034#ifdef CONFIG_CIFS_DEBUG2
Steve French75865f8c2007-06-24 18:30:48 +00002035 if (cap & CIFS_UNIX_FCNTL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002036 cFYI(1, ("FCNTL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002037 if (cap & CIFS_UNIX_EXTATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002038 cFYI(1, ("EXTATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002039 if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002040 cFYI(1, ("POSIX path cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002041 if (cap & CIFS_UNIX_XATTR_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002042 cFYI(1, ("XATTR cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002043 if (cap & CIFS_UNIX_POSIX_ACL_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002044 cFYI(1, ("POSIX ACL cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002045 if (cap & CIFS_UNIX_LARGE_READ_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002046 cFYI(1, ("very large read cap"));
Steve French75865f8c2007-06-24 18:30:48 +00002047 if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002048 cFYI(1, ("very large write cap"));
Steve French8af18972007-02-14 04:42:51 +00002049#endif /* CIFS_DEBUG2 */
2050 if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
Steve French442aa312007-09-24 20:25:46 +00002051 if (vol_info == NULL) {
Steve French5a44b312007-09-20 15:16:24 +00002052 cFYI(1, ("resetting capabilities failed"));
Steve French442aa312007-09-24 20:25:46 +00002053 } else
Steve French5a44b312007-09-20 15:16:24 +00002054 cERROR(1, ("Negotiating Unix capabilities "
2055 "with the server failed. Consider "
2056 "mounting with the Unix Extensions\n"
2057 "disabled, if problems are found, "
2058 "by specifying the nounix mount "
Steve French2224f4e2007-09-20 15:37:29 +00002059 "option."));
Steve French5a44b312007-09-20 15:16:24 +00002060
Steve French8af18972007-02-14 04:42:51 +00002061 }
2062 }
2063}
2064
Steve French03a143c2008-02-14 06:38:30 +00002065static void
2066convert_delimiter(char *path, char delim)
2067{
2068 int i;
Steve Frenchc2d68ea2008-02-15 19:20:18 +00002069 char old_delim;
Steve French03a143c2008-02-14 06:38:30 +00002070
2071 if (path == NULL)
2072 return;
2073
Steve French582d21e2008-05-13 04:54:12 +00002074 if (delim == '/')
Steve Frenchc2d68ea2008-02-15 19:20:18 +00002075 old_delim = '\\';
2076 else
2077 old_delim = '/';
2078
Steve French03a143c2008-02-14 06:38:30 +00002079 for (i = 0; path[i] != '\0'; i++) {
Steve Frenchc2d68ea2008-02-15 19:20:18 +00002080 if (path[i] == old_delim)
Steve French03a143c2008-02-14 06:38:30 +00002081 path[i] = delim;
2082 }
2083}
2084
Steve French3b795212008-11-13 19:45:32 +00002085static void setup_cifs_sb(struct smb_vol *pvolume_info,
2086 struct cifs_sb_info *cifs_sb)
2087{
2088 if (pvolume_info->rsize > CIFSMaxBufSize) {
2089 cERROR(1, ("rsize %d too large, using MaxBufSize",
2090 pvolume_info->rsize));
2091 cifs_sb->rsize = CIFSMaxBufSize;
2092 } else if ((pvolume_info->rsize) &&
2093 (pvolume_info->rsize <= CIFSMaxBufSize))
2094 cifs_sb->rsize = pvolume_info->rsize;
2095 else /* default */
2096 cifs_sb->rsize = CIFSMaxBufSize;
2097
2098 if (pvolume_info->wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
2099 cERROR(1, ("wsize %d too large, using 4096 instead",
2100 pvolume_info->wsize));
2101 cifs_sb->wsize = 4096;
2102 } else if (pvolume_info->wsize)
2103 cifs_sb->wsize = pvolume_info->wsize;
2104 else
2105 cifs_sb->wsize = min_t(const int,
2106 PAGEVEC_SIZE * PAGE_CACHE_SIZE,
2107 127*1024);
2108 /* old default of CIFSMaxBufSize was too small now
2109 that SMB Write2 can send multiple pages in kvec.
2110 RFC1001 does not describe what happens when frame
2111 bigger than 128K is sent so use that as max in
2112 conjunction with 52K kvec constraint on arch with 4K
2113 page size */
2114
2115 if (cifs_sb->rsize < 2048) {
2116 cifs_sb->rsize = 2048;
2117 /* Windows ME may prefer this */
2118 cFYI(1, ("readsize set to minimum: 2048"));
2119 }
2120 /* calculate prepath */
2121 cifs_sb->prepath = pvolume_info->prepath;
2122 if (cifs_sb->prepath) {
2123 cifs_sb->prepathlen = strlen(cifs_sb->prepath);
2124 /* we can not convert the / to \ in the path
2125 separators in the prefixpath yet because we do not
2126 know (until reset_cifs_unix_caps is called later)
2127 whether POSIX PATH CAP is available. We normalize
2128 the / to \ after reset_cifs_unix_caps is called */
2129 pvolume_info->prepath = NULL;
2130 } else
2131 cifs_sb->prepathlen = 0;
2132 cifs_sb->mnt_uid = pvolume_info->linux_uid;
2133 cifs_sb->mnt_gid = pvolume_info->linux_gid;
2134 cifs_sb->mnt_file_mode = pvolume_info->file_mode;
2135 cifs_sb->mnt_dir_mode = pvolume_info->dir_mode;
2136 cFYI(1, ("file mode: 0x%x dir mode: 0x%x",
2137 cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode));
2138
2139 if (pvolume_info->noperm)
2140 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
2141 if (pvolume_info->setuids)
2142 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
2143 if (pvolume_info->server_ino)
2144 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
2145 if (pvolume_info->remap)
2146 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
2147 if (pvolume_info->no_xattr)
2148 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
2149 if (pvolume_info->sfu_emul)
2150 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
2151 if (pvolume_info->nobrl)
2152 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
2153 if (pvolume_info->cifs_acl)
2154 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
2155 if (pvolume_info->override_uid)
2156 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
2157 if (pvolume_info->override_gid)
2158 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
2159 if (pvolume_info->dynperm)
2160 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
2161 if (pvolume_info->direct_io) {
2162 cFYI(1, ("mounting share using direct i/o"));
2163 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
2164 }
2165
2166 if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm))
2167 cERROR(1, ("mount option dynperm ignored if cifsacl "
2168 "mount option supported"));
2169}
2170
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171int
2172cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2173 char *mount_data, const char *devname)
2174{
2175 int rc = 0;
2176 int xid;
Jeff Layton7586b762008-12-01 18:41:49 -05002177 struct smb_vol *volume_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178 struct cifsSesInfo *pSesInfo = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179 struct cifsTconInfo *tcon = NULL;
2180 struct TCP_Server_Info *srvTcp = NULL;
2181
2182 xid = GetXid();
2183
Jeff Layton7586b762008-12-01 18:41:49 -05002184 volume_info = kzalloc(sizeof(struct smb_vol), GFP_KERNEL);
2185 if (!volume_info) {
2186 rc = -ENOMEM;
2187 goto out;
2188 }
Steve French50c2f752007-07-13 00:33:32 +00002189
Jeff Layton7586b762008-12-01 18:41:49 -05002190 if (cifs_parse_mount_options(mount_data, devname, volume_info)) {
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002191 rc = -EINVAL;
2192 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193 }
2194
Jeff Layton7586b762008-12-01 18:41:49 -05002195 if (volume_info->nullauth) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002196 cFYI(1, ("null user"));
Jeff Layton7586b762008-12-01 18:41:49 -05002197 volume_info->username = "";
2198 } else if (volume_info->username) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199 /* BB fixme parse for domain name here */
Jeff Layton7586b762008-12-01 18:41:49 -05002200 cFYI(1, ("Username: %s", volume_info->username));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 } else {
Steve Frenchbf820672005-12-01 22:32:42 -08002202 cifserror("No username specified");
Steve French50c2f752007-07-13 00:33:32 +00002203 /* In userspace mount helper we can get user name from alternate
2204 locations such as env variables and files on disk */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002205 rc = -EINVAL;
2206 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207 }
2208
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209
2210 /* this is needed for ASCII cp to Unicode converts */
Jeff Layton7586b762008-12-01 18:41:49 -05002211 if (volume_info->iocharset == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212 cifs_sb->local_nls = load_nls_default();
2213 /* load_nls_default can not return null */
2214 } else {
Jeff Layton7586b762008-12-01 18:41:49 -05002215 cifs_sb->local_nls = load_nls(volume_info->iocharset);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002216 if (cifs_sb->local_nls == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002217 cERROR(1, ("CIFS mount error: iocharset %s not found",
Jeff Layton7586b762008-12-01 18:41:49 -05002218 volume_info->iocharset));
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002219 rc = -ELIBACC;
2220 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 }
2222 }
2223
Jeff Layton63c038c2008-12-01 18:41:46 -05002224 /* get a reference to a tcp session */
Jeff Layton7586b762008-12-01 18:41:49 -05002225 srvTcp = cifs_get_tcp_session(volume_info);
Jeff Layton63c038c2008-12-01 18:41:46 -05002226 if (IS_ERR(srvTcp)) {
2227 rc = PTR_ERR(srvTcp);
2228 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 }
2230
Jeff Layton7586b762008-12-01 18:41:49 -05002231 pSesInfo = cifs_find_smb_ses(srvTcp, volume_info->username);
Jeff Layton14fbf502008-11-14 13:53:46 -05002232 if (pSesInfo) {
Jeff Layton1d9a8852007-12-31 01:37:11 +00002233 cFYI(1, ("Existing smb sess found (status=%d)",
2234 pSesInfo->status));
Jeff Layton14fbf502008-11-14 13:53:46 -05002235 /*
2236 * The existing SMB session already has a reference to srvTcp,
2237 * so we can put back the extra one we got before
2238 */
2239 cifs_put_tcp_session(srvTcp);
2240
Steve French88e7d702008-01-03 17:37:09 +00002241 down(&pSesInfo->sesSem);
Steve French3b795212008-11-13 19:45:32 +00002242 if (pSesInfo->need_reconnect) {
Jeff Layton1d9a8852007-12-31 01:37:11 +00002243 cFYI(1, ("Session needs reconnect"));
Jeff Layton1d9a8852007-12-31 01:37:11 +00002244 rc = cifs_setup_session(xid, pSesInfo,
2245 cifs_sb->local_nls);
Jeff Layton1d9a8852007-12-31 01:37:11 +00002246 }
Steve French88e7d702008-01-03 17:37:09 +00002247 up(&pSesInfo->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 } else if (!rc) {
Steve Frenchbf820672005-12-01 22:32:42 -08002249 cFYI(1, ("Existing smb sess not found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 pSesInfo = sesInfoAlloc();
Jeff Layton14fbf502008-11-14 13:53:46 -05002251 if (pSesInfo == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 rc = -ENOMEM;
Jeff Layton14fbf502008-11-14 13:53:46 -05002253 goto mount_fail_check;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 }
2255
Jeff Layton14fbf502008-11-14 13:53:46 -05002256 /* new SMB session uses our srvTcp ref */
2257 pSesInfo->server = srvTcp;
Jeff Layton63c038c2008-12-01 18:41:46 -05002258 if (srvTcp->addr.sockAddr6.sin6_family == AF_INET6)
Jeff Layton8ecaf672008-12-01 15:23:50 -05002259 sprintf(pSesInfo->serverName, NIP6_FMT,
Jeff Layton63c038c2008-12-01 18:41:46 -05002260 NIP6(srvTcp->addr.sockAddr6.sin6_addr));
Jeff Layton8ecaf672008-12-01 15:23:50 -05002261 else
2262 sprintf(pSesInfo->serverName, NIPQUAD_FMT,
Jeff Layton63c038c2008-12-01 18:41:46 -05002263 NIPQUAD(srvTcp->addr.sockAddr.sin_addr.s_addr));
Jeff Layton14fbf502008-11-14 13:53:46 -05002264
2265 write_lock(&cifs_tcp_ses_lock);
2266 list_add(&pSesInfo->smb_ses_list, &srvTcp->smb_ses_list);
2267 write_unlock(&cifs_tcp_ses_lock);
2268
Jeff Layton7586b762008-12-01 18:41:49 -05002269 /* volume_info->password freed at unmount */
2270 if (volume_info->password) {
2271 pSesInfo->password = volume_info->password;
Jeff Layton14fbf502008-11-14 13:53:46 -05002272 /* set to NULL to prevent freeing on exit */
Jeff Layton7586b762008-12-01 18:41:49 -05002273 volume_info->password = NULL;
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002274 }
Jeff Layton7586b762008-12-01 18:41:49 -05002275 if (volume_info->username)
2276 strncpy(pSesInfo->userName, volume_info->username,
Jeff Layton14fbf502008-11-14 13:53:46 -05002277 MAX_USERNAME_SIZE);
Jeff Layton7586b762008-12-01 18:41:49 -05002278 if (volume_info->domainname) {
2279 int len = strlen(volume_info->domainname);
Jeff Layton14fbf502008-11-14 13:53:46 -05002280 pSesInfo->domainName = kmalloc(len + 1, GFP_KERNEL);
2281 if (pSesInfo->domainName)
2282 strcpy(pSesInfo->domainName,
Jeff Layton7586b762008-12-01 18:41:49 -05002283 volume_info->domainname);
Jeff Layton14fbf502008-11-14 13:53:46 -05002284 }
Jeff Layton7586b762008-12-01 18:41:49 -05002285 pSesInfo->linux_uid = volume_info->linux_uid;
2286 pSesInfo->overrideSecFlg = volume_info->secFlg;
Jeff Layton14fbf502008-11-14 13:53:46 -05002287 down(&pSesInfo->sesSem);
2288
2289 /* BB FIXME need to pass vol->secFlgs BB */
2290 rc = cifs_setup_session(xid, pSesInfo,
2291 cifs_sb->local_nls);
2292 up(&pSesInfo->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293 }
Steve French50c2f752007-07-13 00:33:32 +00002294
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295 /* search for existing tcon to this server share */
2296 if (!rc) {
Jeff Layton7586b762008-12-01 18:41:49 -05002297 setup_cifs_sb(volume_info, cifs_sb);
Steve French27adb442008-05-23 19:43:29 +00002298
Jeff Layton7586b762008-12-01 18:41:49 -05002299 tcon = cifs_find_tcon(pSesInfo, volume_info->UNC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300 if (tcon) {
Steve Frenchbf820672005-12-01 22:32:42 -08002301 cFYI(1, ("Found match on UNC path"));
Jeff Laytonf1987b42008-11-15 11:12:47 -05002302 /* existing tcon already has a reference */
2303 cifs_put_smb_ses(pSesInfo);
Jeff Layton7586b762008-12-01 18:41:49 -05002304 if (tcon->seal != volume_info->seal)
Steve Frenchab3f9922008-11-17 16:03:00 +00002305 cERROR(1, ("transport encryption setting "
2306 "conflicts with existing tid"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 } else {
2308 tcon = tconInfoAlloc();
Steve French3b795212008-11-13 19:45:32 +00002309 if (tcon == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 rc = -ENOMEM;
Steve French3b795212008-11-13 19:45:32 +00002311 goto mount_fail_check;
2312 }
Steve Frenchab3f9922008-11-17 16:03:00 +00002313 tcon->ses = pSesInfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314
Steve French3b795212008-11-13 19:45:32 +00002315 /* check for null share name ie connect to dfs root */
Jeff Layton7586b762008-12-01 18:41:49 -05002316 if ((strchr(volume_info->UNC + 3, '\\') == NULL)
2317 && (strchr(volume_info->UNC + 3, '/') == NULL)) {
Steve French3b795212008-11-13 19:45:32 +00002318 /* rc = connect_to_dfs_path(...) */
2319 cFYI(1, ("DFS root not supported"));
2320 rc = -ENODEV;
2321 goto mount_fail_check;
2322 } else {
2323 /* BB Do we need to wrap sesSem around
2324 * this TCon call and Unix SetFS as
2325 * we do on SessSetup and reconnect? */
Jeff Layton7586b762008-12-01 18:41:49 -05002326 rc = CIFSTCon(xid, pSesInfo, volume_info->UNC,
Steve French3b795212008-11-13 19:45:32 +00002327 tcon, cifs_sb->local_nls);
2328 cFYI(1, ("CIFS Tcon rc = %d", rc));
Jeff Layton7586b762008-12-01 18:41:49 -05002329 if (volume_info->nodfs) {
Steve French3b795212008-11-13 19:45:32 +00002330 tcon->Flags &= ~SMB_SHARE_IS_IN_DFS;
2331 cFYI(1, ("DFS disabled (%d)",
2332 tcon->Flags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 }
2334 }
Jeff Layton14fbf502008-11-14 13:53:46 -05002335 if (rc)
Steve French3b795212008-11-13 19:45:32 +00002336 goto mount_fail_check;
Jeff Layton7586b762008-12-01 18:41:49 -05002337 tcon->seal = volume_info->seal;
Jeff Laytonf1987b42008-11-15 11:12:47 -05002338 write_lock(&cifs_tcp_ses_lock);
2339 list_add(&tcon->tcon_list, &pSesInfo->tcon_list);
2340 write_unlock(&cifs_tcp_ses_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341 }
Steve French3b795212008-11-13 19:45:32 +00002342
2343 /* we can have only one retry value for a connection
2344 to a share so for resources mounted more than once
2345 to the same server share the last value passed in
2346 for the retry flag is used */
Jeff Layton7586b762008-12-01 18:41:49 -05002347 tcon->retry = volume_info->retry;
2348 tcon->nocase = volume_info->nocase;
2349 tcon->local_lease = volume_info->local_lease;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350 }
Steve French4523cc32007-04-30 20:13:06 +00002351 if (pSesInfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
2353 sb->s_maxbytes = (u64) 1 << 63;
2354 } else
2355 sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
2356 }
2357
Steve French8af18972007-02-14 04:42:51 +00002358 /* BB FIXME fix time_gran to be larger for LANMAN sessions */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 sb->s_time_gran = 100;
2360
Steve French3b795212008-11-13 19:45:32 +00002361mount_fail_check:
Jeff Layton14fbf502008-11-14 13:53:46 -05002362 /* on error free sesinfo and tcon struct if needed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363 if (rc) {
Jeff Laytone7ddee92008-11-14 13:44:38 -05002364 /* If find_unc succeeded then rc == 0 so we can not end */
2365 /* up accidently freeing someone elses tcon struct */
2366 if (tcon)
Jeff Laytonf1987b42008-11-15 11:12:47 -05002367 cifs_put_tcon(tcon);
2368 else if (pSesInfo)
Jeff Layton14fbf502008-11-14 13:53:46 -05002369 cifs_put_smb_ses(pSesInfo);
2370 else
2371 cifs_put_tcp_session(srvTcp);
Steve Frenchd82c2df2008-11-15 00:07:26 +00002372 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373 }
Steve Frenchd82c2df2008-11-15 00:07:26 +00002374 cifs_sb->tcon = tcon;
Steve Frenchd82c2df2008-11-15 00:07:26 +00002375
2376 /* do not care if following two calls succeed - informational */
2377 if (!tcon->ipc) {
2378 CIFSSMBQFSDeviceInfo(xid, tcon);
2379 CIFSSMBQFSAttributeInfo(xid, tcon);
2380 }
2381
2382 /* tell server which Unix caps we support */
2383 if (tcon->ses->capabilities & CAP_UNIX)
2384 /* reset of caps checks mount to see if unix extensions
2385 disabled for just this mount */
Jeff Layton7586b762008-12-01 18:41:49 -05002386 reset_cifs_unix_caps(xid, tcon, sb, volume_info);
Steve Frenchd82c2df2008-11-15 00:07:26 +00002387 else
2388 tcon->unix_ext = 0; /* server does not support them */
2389
2390 /* convert forward to back slashes in prepath here if needed */
2391 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
2392 convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb));
2393
2394 if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
2395 cifs_sb->rsize = 1024 * 127;
2396 cFYI(DBG2, ("no very large read support, rsize now 127K"));
2397 }
2398 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
2399 cifs_sb->wsize = min(cifs_sb->wsize,
2400 (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
2401 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
2402 cifs_sb->rsize = min(cifs_sb->rsize,
2403 (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404
Jeff Layton7586b762008-12-01 18:41:49 -05002405 /* volume_info->password is freed above when existing session found
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406 (in which case it is not needed anymore) but when new sesion is created
2407 the password ptr is put in the new session structure (in which case the
2408 password will be freed at unmount time) */
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002409out:
2410 /* zero out password before freeing */
Jeff Layton7586b762008-12-01 18:41:49 -05002411 if (volume_info) {
2412 if (volume_info->password != NULL) {
2413 memset(volume_info->password, 0,
2414 strlen(volume_info->password));
2415 kfree(volume_info->password);
2416 }
2417 kfree(volume_info->UNC);
2418 kfree(volume_info->prepath);
2419 kfree(volume_info);
Jeff Layton70fe7dc2007-11-16 22:21:07 +00002420 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421 FreeXid(xid);
2422 return rc;
2423}
2424
2425static int
2426CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French7c7b25b2006-06-01 19:20:10 +00002427 char session_key[CIFS_SESS_KEY_SIZE],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428 const struct nls_table *nls_codepage)
2429{
2430 struct smb_hdr *smb_buffer;
2431 struct smb_hdr *smb_buffer_response;
2432 SESSION_SETUP_ANDX *pSMB;
2433 SESSION_SETUP_ANDX *pSMBr;
2434 char *bcc_ptr;
2435 char *user;
2436 char *domain;
2437 int rc = 0;
2438 int remaining_words = 0;
2439 int bytes_returned = 0;
2440 int len;
2441 __u32 capabilities;
2442 __u16 count;
2443
Steve Frencheeac8042006-01-13 21:34:58 -08002444 cFYI(1, ("In sesssetup"));
Steve French4523cc32007-04-30 20:13:06 +00002445 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446 return -EINVAL;
2447 user = ses->userName;
2448 domain = ses->domainName;
2449 smb_buffer = cifs_buf_get();
Steve French582d21e2008-05-13 04:54:12 +00002450
2451 if (smb_buffer == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452 return -ENOMEM;
Steve French582d21e2008-05-13 04:54:12 +00002453
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454 smb_buffer_response = smb_buffer;
2455 pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2456
2457 /* send SMBsessionSetup here */
2458 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2459 NULL /* no tCon exists yet */ , 13 /* wct */ );
2460
Steve French1982c342005-08-17 12:38:22 -07002461 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 pSMB->req_no_secext.AndXCommand = 0xFF;
2463 pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2464 pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2465
Steve French50c2f752007-07-13 00:33:32 +00002466 if (ses->server->secMode &
2467 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2469
2470 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2471 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
2472 if (ses->capabilities & CAP_UNICODE) {
2473 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2474 capabilities |= CAP_UNICODE;
2475 }
2476 if (ses->capabilities & CAP_STATUS32) {
2477 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2478 capabilities |= CAP_STATUS32;
2479 }
2480 if (ses->capabilities & CAP_DFS) {
2481 smb_buffer->Flags2 |= SMBFLG2_DFS;
2482 capabilities |= CAP_DFS;
2483 }
2484 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
2485
Steve French50c2f752007-07-13 00:33:32 +00002486 pSMB->req_no_secext.CaseInsensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002487 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488
2489 pSMB->req_no_secext.CaseSensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +00002490 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 bcc_ptr = pByteArea(smb_buffer);
Steve French7c7b25b2006-06-01 19:20:10 +00002492 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2493 bcc_ptr += CIFS_SESS_KEY_SIZE;
2494 memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
2495 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496
2497 if (ses->capabilities & CAP_UNICODE) {
2498 if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
2499 *bcc_ptr = 0;
2500 bcc_ptr++;
2501 }
Steve French4523cc32007-04-30 20:13:06 +00002502 if (user == NULL)
Steve French39798772006-05-31 22:40:51 +00002503 bytes_returned = 0; /* skip null user */
Steve French50c2f752007-07-13 00:33:32 +00002504 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505 bytes_returned =
Steve French50c2f752007-07-13 00:33:32 +00002506 cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507 nls_codepage);
2508 /* convert number of 16 bit words to bytes */
2509 bcc_ptr += 2 * bytes_returned;
2510 bcc_ptr += 2; /* trailing null */
2511 if (domain == NULL)
2512 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002513 cifs_strtoUCS((__le16 *) bcc_ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 "CIFS_LINUX_DOM", 32, nls_codepage);
2515 else
2516 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002517 cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518 nls_codepage);
2519 bcc_ptr += 2 * bytes_returned;
2520 bcc_ptr += 2;
2521 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002522 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523 32, nls_codepage);
2524 bcc_ptr += 2 * bytes_returned;
2525 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002526 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527 32, nls_codepage);
2528 bcc_ptr += 2 * bytes_returned;
2529 bcc_ptr += 2;
2530 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002531 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532 64, nls_codepage);
2533 bcc_ptr += 2 * bytes_returned;
2534 bcc_ptr += 2;
2535 } else {
Steve French50c2f752007-07-13 00:33:32 +00002536 if (user != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537 strncpy(bcc_ptr, user, 200);
2538 bcc_ptr += strnlen(user, 200);
2539 }
2540 *bcc_ptr = 0;
2541 bcc_ptr++;
2542 if (domain == NULL) {
2543 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
2544 bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
2545 } else {
2546 strncpy(bcc_ptr, domain, 64);
2547 bcc_ptr += strnlen(domain, 64);
2548 *bcc_ptr = 0;
2549 bcc_ptr++;
2550 }
2551 strcpy(bcc_ptr, "Linux version ");
2552 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002553 strcpy(bcc_ptr, utsname()->release);
2554 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2556 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2557 }
2558 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2559 smb_buffer->smb_buf_length += count;
2560 pSMB->req_no_secext.ByteCount = cpu_to_le16(count);
2561
2562 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00002563 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564 if (rc) {
2565/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
2566 } else if ((smb_buffer_response->WordCount == 3)
2567 || (smb_buffer_response->WordCount == 4)) {
2568 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2569 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2570 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002571 cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */
2572 ses->Suid = smb_buffer_response->Uid; /* UID left in wire format
2573 (little endian) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 cFYI(1, ("UID = %d ", ses->Suid));
Steve French50c2f752007-07-13 00:33:32 +00002575 /* response can have either 3 or 4 word count - Samba sends 3 */
2576 bcc_ptr = pByteArea(smb_buffer_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 if ((pSMBr->resp.hdr.WordCount == 3)
2578 || ((pSMBr->resp.hdr.WordCount == 4)
2579 && (blob_len < pSMBr->resp.ByteCount))) {
2580 if (pSMBr->resp.hdr.WordCount == 4)
2581 bcc_ptr += blob_len;
2582
2583 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2584 if ((long) (bcc_ptr) % 2) {
2585 remaining_words =
Steve French50c2f752007-07-13 00:33:32 +00002586 (BCC(smb_buffer_response) - 1) / 2;
2587 /* Unicode strings must be word
2588 aligned */
2589 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590 } else {
2591 remaining_words =
2592 BCC(smb_buffer_response) / 2;
2593 }
2594 len =
2595 UniStrnlen((wchar_t *) bcc_ptr,
2596 remaining_words - 1);
2597/* We look for obvious messed up bcc or strings in response so we do not go off
2598 the end since (at least) WIN2K and Windows XP have a major bug in not null
2599 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002600 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002601 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002602 ses->serverOS = kzalloc(2 * (len + 1),
2603 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002604 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002605 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 cifs_strfromUCS_le(ses->serverOS,
Steve French50c2f752007-07-13 00:33:32 +00002607 (__le16 *)bcc_ptr,
2608 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 bcc_ptr += 2 * (len + 1);
2610 remaining_words -= len + 1;
2611 ses->serverOS[2 * len] = 0;
2612 ses->serverOS[1 + (2 * len)] = 0;
2613 if (remaining_words > 0) {
2614 len = UniStrnlen((wchar_t *)bcc_ptr,
2615 remaining_words-1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002616 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002617 ses->serverNOS = kzalloc(2 * (len + 1),
2618 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002619 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002620 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621 cifs_strfromUCS_le(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002622 (__le16 *)bcc_ptr,
2623 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 bcc_ptr += 2 * (len + 1);
2625 ses->serverNOS[2 * len] = 0;
2626 ses->serverNOS[1 + (2 * len)] = 0;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002627 if (strncmp(ses->serverNOS,
Steve French50c2f752007-07-13 00:33:32 +00002628 "NT LAN Manager 4", 16) == 0) {
Steve French467a8f82007-06-27 22:41:32 +00002629 cFYI(1, ("NT4 server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 ses->flags |= CIFS_SES_NT4;
2631 }
2632 remaining_words -= len + 1;
2633 if (remaining_words > 0) {
Steve French433dc242005-04-28 22:41:08 -07002634 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Steve French50c2f752007-07-13 00:33:32 +00002635 /* last string is not always null terminated
2636 (for e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002637 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002638 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 ses->serverDomain =
Steve French50c2f752007-07-13 00:33:32 +00002640 kzalloc(2*(len+1),
2641 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002642 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002643 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 cifs_strfromUCS_le(ses->serverDomain,
Steve French50c2f752007-07-13 00:33:32 +00002645 (__le16 *)bcc_ptr,
2646 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 bcc_ptr += 2 * (len + 1);
2648 ses->serverDomain[2*len] = 0;
2649 ses->serverDomain[1+(2*len)] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002650 } else { /* else no more room so create
2651 dummy domain string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002652 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002653 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002654 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002655 kzalloc(2, GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00002656 }
Steve French50c2f752007-07-13 00:33:32 +00002657 } else { /* no room so create dummy domain
2658 and NOS string */
2659
Steve French433dc242005-04-28 22:41:08 -07002660 /* if these kcallocs fail not much we
2661 can do, but better to not fail the
2662 sesssetup itself */
Steve Frenchcd49b492006-06-26 04:22:36 +00002663 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002665 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00002666 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002668 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669 }
2670 } else { /* ASCII */
2671 len = strnlen(bcc_ptr, 1024);
2672 if (((long) bcc_ptr + len) - (long)
2673 pByteArea(smb_buffer_response)
2674 <= BCC(smb_buffer_response)) {
Steve Frenchcd49b492006-06-26 04:22:36 +00002675 kfree(ses->serverOS);
Steve French50c2f752007-07-13 00:33:32 +00002676 ses->serverOS = kzalloc(len + 1,
2677 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002678 if (ses->serverOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002679 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002680 strncpy(ses->serverOS, bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681
2682 bcc_ptr += len;
Steve French50c2f752007-07-13 00:33:32 +00002683 /* null terminate the string */
2684 bcc_ptr[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685 bcc_ptr++;
2686
2687 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00002688 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00002689 ses->serverNOS = kzalloc(len + 1,
2690 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002691 if (ses->serverNOS == NULL)
Steve French433dc242005-04-28 22:41:08 -07002692 goto sesssetup_nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693 strncpy(ses->serverNOS, bcc_ptr, len);
2694 bcc_ptr += len;
2695 bcc_ptr[0] = 0;
2696 bcc_ptr++;
2697
2698 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002699 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00002700 kfree(ses->serverDomain);
Steve French50c2f752007-07-13 00:33:32 +00002701 ses->serverDomain = kzalloc(len + 1,
2702 GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002703 if (ses->serverDomain == NULL)
Steve French433dc242005-04-28 22:41:08 -07002704 goto sesssetup_nomem;
Steve French50c2f752007-07-13 00:33:32 +00002705 strncpy(ses->serverDomain, bcc_ptr,
2706 len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 bcc_ptr += len;
2708 bcc_ptr[0] = 0;
2709 bcc_ptr++;
2710 } else
2711 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00002712 ("Variable field of length %d "
2713 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 len));
2715 }
2716 } else {
2717 cERROR(1,
Steve French50c2f752007-07-13 00:33:32 +00002718 (" Security Blob Length extends beyond "
2719 "end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 }
2721 } else {
2722 cERROR(1,
2723 (" Invalid Word count %d: ",
2724 smb_buffer_response->WordCount));
2725 rc = -EIO;
2726 }
Steve French433dc242005-04-28 22:41:08 -07002727sesssetup_nomem: /* do not return an error on nomem for the info strings,
2728 since that could make reconnection harder, and
2729 reconnection might be needed to free memory */
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00002730 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731
2732 return rc;
2733}
2734
2735static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
Steve French4b18f2a2008-04-29 00:06:05 +00002737 struct cifsSesInfo *ses, bool *pNTLMv2_flag,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 const struct nls_table *nls_codepage)
2739{
2740 struct smb_hdr *smb_buffer;
2741 struct smb_hdr *smb_buffer_response;
2742 SESSION_SETUP_ANDX *pSMB;
2743 SESSION_SETUP_ANDX *pSMBr;
2744 char *bcc_ptr;
2745 char *domain;
2746 int rc = 0;
2747 int remaining_words = 0;
2748 int bytes_returned = 0;
2749 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00002750 int SecurityBlobLength = sizeof(NEGOTIATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751 PNEGOTIATE_MESSAGE SecurityBlob;
2752 PCHALLENGE_MESSAGE SecurityBlob2;
2753 __u32 negotiate_flags, capabilities;
2754 __u16 count;
2755
Steve French12b3b8f2006-02-09 21:12:47 +00002756 cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002757 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 return -EINVAL;
2759 domain = ses->domainName;
Steve French4b18f2a2008-04-29 00:06:05 +00002760 *pNTLMv2_flag = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 smb_buffer = cifs_buf_get();
2762 if (smb_buffer == NULL) {
2763 return -ENOMEM;
2764 }
2765 smb_buffer_response = smb_buffer;
2766 pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
2767 pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
2768
2769 /* send SMBsessionSetup here */
2770 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
2771 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07002772
2773 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
2775 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
2776
2777 pSMB->req.AndXCommand = 0xFF;
2778 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
2779 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
2780
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002781 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
2783
2784 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
2785 CAP_EXTENDED_SECURITY;
2786 if (ses->capabilities & CAP_UNICODE) {
2787 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
2788 capabilities |= CAP_UNICODE;
2789 }
2790 if (ses->capabilities & CAP_STATUS32) {
2791 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
2792 capabilities |= CAP_STATUS32;
2793 }
2794 if (ses->capabilities & CAP_DFS) {
2795 smb_buffer->Flags2 |= SMBFLG2_DFS;
2796 capabilities |= CAP_DFS;
2797 }
2798 pSMB->req.Capabilities = cpu_to_le32(capabilities);
2799
2800 bcc_ptr = (char *) &pSMB->req.SecurityBlob;
2801 SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
2802 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
2803 SecurityBlob->MessageType = NtLmNegotiate;
2804 negotiate_flags =
2805 NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
Steve French12b3b8f2006-02-09 21:12:47 +00002806 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
2807 NTLMSSP_NEGOTIATE_56 |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808 /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002809 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002811/* if (ntlmv2_support)
Steve French39798772006-05-31 22:40:51 +00002812 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 /* setup pointers to domain name and workstation name */
2814 bcc_ptr += SecurityBlobLength;
2815
2816 SecurityBlob->WorkstationName.Buffer = 0;
2817 SecurityBlob->WorkstationName.Length = 0;
2818 SecurityBlob->WorkstationName.MaximumLength = 0;
2819
Steve French12b3b8f2006-02-09 21:12:47 +00002820 /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent
2821 along with username on auth request (ie the response to challenge) */
2822 SecurityBlob->DomainName.Buffer = 0;
2823 SecurityBlob->DomainName.Length = 0;
2824 SecurityBlob->DomainName.MaximumLength = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 if (ses->capabilities & CAP_UNICODE) {
2826 if ((long) bcc_ptr % 2) {
2827 *bcc_ptr = 0;
2828 bcc_ptr++;
2829 }
2830
2831 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002832 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833 32, nls_codepage);
2834 bcc_ptr += 2 * bytes_returned;
2835 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002836 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 nls_codepage);
2838 bcc_ptr += 2 * bytes_returned;
2839 bcc_ptr += 2; /* null terminate Linux version */
2840 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08002841 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842 64, nls_codepage);
2843 bcc_ptr += 2 * bytes_returned;
2844 *(bcc_ptr + 1) = 0;
2845 *(bcc_ptr + 2) = 0;
2846 bcc_ptr += 2; /* null terminate network opsys string */
2847 *(bcc_ptr + 1) = 0;
2848 *(bcc_ptr + 2) = 0;
2849 bcc_ptr += 2; /* null domain */
2850 } else { /* ASCII */
2851 strcpy(bcc_ptr, "Linux version ");
2852 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07002853 strcpy(bcc_ptr, utsname()->release);
2854 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
2856 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
2857 bcc_ptr++; /* empty domain field */
2858 *bcc_ptr = 0;
2859 }
2860 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
2861 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
2862 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
2863 smb_buffer->smb_buf_length += count;
2864 pSMB->req.ByteCount = cpu_to_le16(count);
2865
2866 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00002867 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868
2869 if (smb_buffer_response->Status.CifsError ==
2870 cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
2871 rc = 0;
2872
2873 if (rc) {
2874/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
2875 } else if ((smb_buffer_response->WordCount == 3)
2876 || (smb_buffer_response->WordCount == 4)) {
2877 __u16 action = le16_to_cpu(pSMBr->resp.Action);
2878 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
2879
2880 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00002881 cFYI(1, (" Guest login"));
2882 /* Do we want to set anything in SesInfo struct when guest login? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883
Steve French50c2f752007-07-13 00:33:32 +00002884 bcc_ptr = pByteArea(smb_buffer_response);
2885 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886
2887 SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
2888 if (SecurityBlob2->MessageType != NtLmChallenge) {
2889 cFYI(1,
2890 ("Unexpected NTLMSSP message type received %d",
2891 SecurityBlob2->MessageType));
2892 } else if (ses) {
Steve French50c2f752007-07-13 00:33:32 +00002893 ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
Steve French12b3b8f2006-02-09 21:12:47 +00002894 cFYI(1, ("UID = %d", ses->Suid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895 if ((pSMBr->resp.hdr.WordCount == 3)
2896 || ((pSMBr->resp.hdr.WordCount == 4)
2897 && (blob_len <
2898 pSMBr->resp.ByteCount))) {
2899
2900 if (pSMBr->resp.hdr.WordCount == 4) {
2901 bcc_ptr += blob_len;
Steve French12b3b8f2006-02-09 21:12:47 +00002902 cFYI(1, ("Security Blob Length %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903 blob_len));
2904 }
2905
Steve French12b3b8f2006-02-09 21:12:47 +00002906 cFYI(1, ("NTLMSSP Challenge rcvd"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907
2908 memcpy(ses->server->cryptKey,
2909 SecurityBlob2->Challenge,
2910 CIFS_CRYPTO_KEY_SIZE);
Steve French50c2f752007-07-13 00:33:32 +00002911 if (SecurityBlob2->NegotiateFlags &
Steve French12b3b8f2006-02-09 21:12:47 +00002912 cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
Steve French4b18f2a2008-04-29 00:06:05 +00002913 *pNTLMv2_flag = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914
Steve French50c2f752007-07-13 00:33:32 +00002915 if ((SecurityBlob2->NegotiateFlags &
2916 cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917 || (sign_CIFS_PDUs > 1))
Steve French50c2f752007-07-13 00:33:32 +00002918 ses->server->secMode |=
2919 SECMODE_SIGN_REQUIRED;
2920 if ((SecurityBlob2->NegotiateFlags &
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921 cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
Steve French50c2f752007-07-13 00:33:32 +00002922 ses->server->secMode |=
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923 SECMODE_SIGN_ENABLED;
2924
2925 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
2926 if ((long) (bcc_ptr) % 2) {
2927 remaining_words =
2928 (BCC(smb_buffer_response)
2929 - 1) / 2;
Steve French50c2f752007-07-13 00:33:32 +00002930 /* Must word align unicode strings */
2931 bcc_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932 } else {
2933 remaining_words =
2934 BCC
2935 (smb_buffer_response) / 2;
2936 }
2937 len =
2938 UniStrnlen((wchar_t *) bcc_ptr,
2939 remaining_words - 1);
2940/* We look for obvious messed up bcc or strings in response so we do not go off
2941 the end since (at least) WIN2K and Windows XP have a major bug in not null
2942 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002943 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00002944 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002946 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002948 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949 bcc_ptr, len,
2950 nls_codepage);
2951 bcc_ptr += 2 * (len + 1);
2952 remaining_words -= len + 1;
2953 ses->serverOS[2 * len] = 0;
2954 ses->serverOS[1 + (2 * len)] = 0;
2955 if (remaining_words > 0) {
2956 len = UniStrnlen((wchar_t *)
2957 bcc_ptr,
2958 remaining_words
2959 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00002960 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07002962 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963 GFP_KERNEL);
2964 cifs_strfromUCS_le(ses->
2965 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08002966 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967 bcc_ptr,
2968 len,
2969 nls_codepage);
2970 bcc_ptr += 2 * (len + 1);
2971 ses->serverNOS[2 * len] = 0;
2972 ses->serverNOS[1 +
2973 (2 * len)] = 0;
2974 remaining_words -= len + 1;
2975 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00002976 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
2977 /* last string not always null terminated
2978 (for e.g. for Windows XP & 2000) */
Steve Frenchcd49b492006-06-26 04:22:36 +00002979 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07002981 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982 (len +
2983 1),
2984 GFP_KERNEL);
2985 cifs_strfromUCS_le
Steve Frenche89dc922005-11-11 15:18:19 -08002986 (ses->serverDomain,
2987 (__le16 *)bcc_ptr,
2988 len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989 bcc_ptr +=
2990 2 * (len + 1);
Steve Frenche89dc922005-11-11 15:18:19 -08002991 ses->serverDomain[2*len]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992 = 0;
Steve Frenche89dc922005-11-11 15:18:19 -08002993 ses->serverDomain
2994 [1 + (2 * len)]
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995 = 0;
2996 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00002997 else {
Steve Frenchcd49b492006-06-26 04:22:36 +00002998 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003000 kzalloc(2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001 GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00003002 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003 } else { /* no room so create dummy domain and NOS string */
Steve Frenchcd49b492006-06-26 04:22:36 +00003004 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003006 kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00003007 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003009 kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 }
3011 } else { /* ASCII */
3012 len = strnlen(bcc_ptr, 1024);
3013 if (((long) bcc_ptr + len) - (long)
3014 pByteArea(smb_buffer_response)
3015 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003016 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00003017 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003019 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020 GFP_KERNEL);
3021 strncpy(ses->serverOS,
3022 bcc_ptr, len);
3023
3024 bcc_ptr += len;
3025 bcc_ptr[0] = 0; /* null terminate string */
3026 bcc_ptr++;
3027
3028 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003029 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003031 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032 GFP_KERNEL);
3033 strncpy(ses->serverNOS, bcc_ptr, len);
3034 bcc_ptr += len;
3035 bcc_ptr[0] = 0;
3036 bcc_ptr++;
3037
3038 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003039 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003040 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003041 kzalloc(len + 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 GFP_KERNEL);
Steve French50c2f752007-07-13 00:33:32 +00003043 strncpy(ses->serverDomain,
3044 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045 bcc_ptr += len;
3046 bcc_ptr[0] = 0;
3047 bcc_ptr++;
3048 } else
3049 cFYI(1,
Steve French63135e02007-07-17 17:34:02 +00003050 ("field of length %d "
3051 "extends beyond end of smb",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052 len));
3053 }
3054 } else {
Steve French50c2f752007-07-13 00:33:32 +00003055 cERROR(1, ("Security Blob Length extends beyond"
3056 " end of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057 }
3058 } else {
3059 cERROR(1, ("No session structure passed in."));
3060 }
3061 } else {
3062 cERROR(1,
Steve French5815449d2006-02-14 01:36:20 +00003063 (" Invalid Word count %d:",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 smb_buffer_response->WordCount));
3065 rc = -EIO;
3066 }
3067
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003068 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069
3070 return rc;
3071}
3072static int
3073CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
Steve French4b18f2a2008-04-29 00:06:05 +00003074 char *ntlm_session_key, bool ntlmv2_flag,
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003075 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003076{
3077 struct smb_hdr *smb_buffer;
3078 struct smb_hdr *smb_buffer_response;
3079 SESSION_SETUP_ANDX *pSMB;
3080 SESSION_SETUP_ANDX *pSMBr;
3081 char *bcc_ptr;
3082 char *user;
3083 char *domain;
3084 int rc = 0;
3085 int remaining_words = 0;
3086 int bytes_returned = 0;
3087 int len;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003088 int SecurityBlobLength = sizeof(AUTHENTICATE_MESSAGE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089 PAUTHENTICATE_MESSAGE SecurityBlob;
3090 __u32 negotiate_flags, capabilities;
3091 __u16 count;
3092
3093 cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003094 if (ses == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095 return -EINVAL;
3096 user = ses->userName;
3097 domain = ses->domainName;
3098 smb_buffer = cifs_buf_get();
3099 if (smb_buffer == NULL) {
3100 return -ENOMEM;
3101 }
3102 smb_buffer_response = smb_buffer;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003103 pSMB = (SESSION_SETUP_ANDX *)smb_buffer;
3104 pSMBr = (SESSION_SETUP_ANDX *)smb_buffer_response;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105
3106 /* send SMBsessionSetup here */
3107 header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
3108 NULL /* no tCon exists yet */ , 12 /* wct */ );
Steve French1982c342005-08-17 12:38:22 -07003109
3110 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111 pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
3112 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
3113 pSMB->req.AndXCommand = 0xFF;
3114 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
3115 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
3116
3117 pSMB->req.hdr.Uid = ses->Suid;
3118
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003119 if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3121
3122 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003123 CAP_EXTENDED_SECURITY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124 if (ses->capabilities & CAP_UNICODE) {
3125 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3126 capabilities |= CAP_UNICODE;
3127 }
3128 if (ses->capabilities & CAP_STATUS32) {
3129 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3130 capabilities |= CAP_STATUS32;
3131 }
3132 if (ses->capabilities & CAP_DFS) {
3133 smb_buffer->Flags2 |= SMBFLG2_DFS;
3134 capabilities |= CAP_DFS;
3135 }
3136 pSMB->req.Capabilities = cpu_to_le32(capabilities);
3137
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003138 bcc_ptr = (char *)&pSMB->req.SecurityBlob;
3139 SecurityBlob = (PAUTHENTICATE_MESSAGE)bcc_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140 strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
3141 SecurityBlob->MessageType = NtLmAuthenticate;
3142 bcc_ptr += SecurityBlobLength;
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003143 negotiate_flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
3144 NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
3145 0x80000000 | NTLMSSP_NEGOTIATE_128;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003146 if (sign_CIFS_PDUs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003147 negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003148 if (ntlmv2_flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149 negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
3150
3151/* setup pointers to domain name and workstation name */
3152
3153 SecurityBlob->WorkstationName.Buffer = 0;
3154 SecurityBlob->WorkstationName.Length = 0;
3155 SecurityBlob->WorkstationName.MaximumLength = 0;
3156 SecurityBlob->SessionKey.Length = 0;
3157 SecurityBlob->SessionKey.MaximumLength = 0;
3158 SecurityBlob->SessionKey.Buffer = 0;
3159
3160 SecurityBlob->LmChallengeResponse.Length = 0;
3161 SecurityBlob->LmChallengeResponse.MaximumLength = 0;
3162 SecurityBlob->LmChallengeResponse.Buffer = 0;
3163
3164 SecurityBlob->NtChallengeResponse.Length =
Steve French7c7b25b2006-06-01 19:20:10 +00003165 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166 SecurityBlob->NtChallengeResponse.MaximumLength =
Steve French7c7b25b2006-06-01 19:20:10 +00003167 cpu_to_le16(CIFS_SESS_KEY_SIZE);
3168 memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169 SecurityBlob->NtChallengeResponse.Buffer =
3170 cpu_to_le32(SecurityBlobLength);
Steve French7c7b25b2006-06-01 19:20:10 +00003171 SecurityBlobLength += CIFS_SESS_KEY_SIZE;
3172 bcc_ptr += CIFS_SESS_KEY_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173
3174 if (ses->capabilities & CAP_UNICODE) {
3175 if (domain == NULL) {
3176 SecurityBlob->DomainName.Buffer = 0;
3177 SecurityBlob->DomainName.Length = 0;
3178 SecurityBlob->DomainName.MaximumLength = 0;
3179 } else {
Steve French77159b42007-08-31 01:10:17 +00003180 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00003182 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003183 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003184 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185 SecurityBlob->DomainName.Buffer =
3186 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003187 bcc_ptr += ln;
3188 SecurityBlobLength += ln;
3189 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190 }
3191 if (user == NULL) {
3192 SecurityBlob->UserName.Buffer = 0;
3193 SecurityBlob->UserName.Length = 0;
3194 SecurityBlob->UserName.MaximumLength = 0;
3195 } else {
Steve French77159b42007-08-31 01:10:17 +00003196 __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197 nls_codepage);
Steve French77159b42007-08-31 01:10:17 +00003198 ln *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199 SecurityBlob->UserName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003200 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201 SecurityBlob->UserName.Buffer =
3202 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003203 bcc_ptr += ln;
3204 SecurityBlobLength += ln;
3205 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003206 }
3207
Steve French63135e02007-07-17 17:34:02 +00003208 /* SecurityBlob->WorkstationName.Length =
3209 cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210 SecurityBlob->WorkstationName.Length *= 2;
Steve French63135e02007-07-17 17:34:02 +00003211 SecurityBlob->WorkstationName.MaximumLength =
3212 cpu_to_le16(SecurityBlob->WorkstationName.Length);
3213 SecurityBlob->WorkstationName.Buffer =
3214 cpu_to_le32(SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215 bcc_ptr += SecurityBlob->WorkstationName.Length;
3216 SecurityBlobLength += SecurityBlob->WorkstationName.Length;
Steve French63135e02007-07-17 17:34:02 +00003217 SecurityBlob->WorkstationName.Length =
3218 cpu_to_le16(SecurityBlob->WorkstationName.Length); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219
3220 if ((long) bcc_ptr % 2) {
3221 *bcc_ptr = 0;
3222 bcc_ptr++;
3223 }
3224 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003225 cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226 32, nls_codepage);
3227 bcc_ptr += 2 * bytes_returned;
3228 bytes_returned =
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003229 cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230 nls_codepage);
3231 bcc_ptr += 2 * bytes_returned;
3232 bcc_ptr += 2; /* null term version string */
3233 bytes_returned =
Steve Frenche89dc922005-11-11 15:18:19 -08003234 cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235 64, nls_codepage);
3236 bcc_ptr += 2 * bytes_returned;
3237 *(bcc_ptr + 1) = 0;
3238 *(bcc_ptr + 2) = 0;
3239 bcc_ptr += 2; /* null terminate network opsys string */
3240 *(bcc_ptr + 1) = 0;
3241 *(bcc_ptr + 2) = 0;
3242 bcc_ptr += 2; /* null domain */
3243 } else { /* ASCII */
3244 if (domain == NULL) {
3245 SecurityBlob->DomainName.Buffer = 0;
3246 SecurityBlob->DomainName.Length = 0;
3247 SecurityBlob->DomainName.MaximumLength = 0;
3248 } else {
Steve French77159b42007-08-31 01:10:17 +00003249 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250 negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
3251 strncpy(bcc_ptr, domain, 63);
Steve French77159b42007-08-31 01:10:17 +00003252 ln = strnlen(domain, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253 SecurityBlob->DomainName.MaximumLength =
Steve French77159b42007-08-31 01:10:17 +00003254 cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255 SecurityBlob->DomainName.Buffer =
3256 cpu_to_le32(SecurityBlobLength);
Steve French77159b42007-08-31 01:10:17 +00003257 bcc_ptr += ln;
3258 SecurityBlobLength += ln;
3259 SecurityBlob->DomainName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260 }
3261 if (user == NULL) {
3262 SecurityBlob->UserName.Buffer = 0;
3263 SecurityBlob->UserName.Length = 0;
3264 SecurityBlob->UserName.MaximumLength = 0;
3265 } else {
Steve French77159b42007-08-31 01:10:17 +00003266 __u16 ln;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003267 strncpy(bcc_ptr, user, 63);
Steve French77159b42007-08-31 01:10:17 +00003268 ln = strnlen(user, 64);
3269 SecurityBlob->UserName.MaximumLength = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003270 SecurityBlob->UserName.Buffer =
Steve French77159b42007-08-31 01:10:17 +00003271 cpu_to_le32(SecurityBlobLength);
3272 bcc_ptr += ln;
3273 SecurityBlobLength += ln;
3274 SecurityBlob->UserName.Length = cpu_to_le16(ln);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275 }
3276 /* BB fill in our workstation name if known BB */
3277
3278 strcpy(bcc_ptr, "Linux version ");
3279 bcc_ptr += strlen("Linux version ");
Serge E. Hallyne9ff3992006-10-02 02:18:11 -07003280 strcpy(bcc_ptr, utsname()->release);
3281 bcc_ptr += strlen(utsname()->release) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
3283 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
3284 bcc_ptr++; /* null domain */
3285 *bcc_ptr = 0;
3286 }
3287 SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags);
3288 pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
3289 count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
3290 smb_buffer->smb_buf_length += count;
3291 pSMB->req.ByteCount = cpu_to_le16(count);
3292
3293 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
Steve French133672e2007-11-13 22:41:37 +00003294 &bytes_returned, CIFS_LONG_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 if (rc) {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003296/* rc = map_smb_to_linux_error(smb_buffer_response) done in SendReceive now */
3297 } else if ((smb_buffer_response->WordCount == 3) ||
3298 (smb_buffer_response->WordCount == 4)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299 __u16 action = le16_to_cpu(pSMBr->resp.Action);
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003300 __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301 if (action & GUEST_LOGIN)
Steve French50c2f752007-07-13 00:33:32 +00003302 cFYI(1, (" Guest login")); /* BB Should we set anything
3303 in SesInfo struct ? */
3304/* if (SecurityBlob2->MessageType != NtLm??) {
3305 cFYI("Unexpected message type on auth response is %d"));
3306 } */
3307
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308 if (ses) {
3309 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003310 ("Check challenge UID %d vs auth response UID %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003311 ses->Suid, smb_buffer_response->Uid));
Steve French50c2f752007-07-13 00:33:32 +00003312 /* UID left in wire format */
3313 ses->Suid = smb_buffer_response->Uid;
3314 bcc_ptr = pByteArea(smb_buffer_response);
3315 /* response can have either 3 or 4 word count - Samba sends 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316 if ((pSMBr->resp.hdr.WordCount == 3)
3317 || ((pSMBr->resp.hdr.WordCount == 4)
3318 && (blob_len <
3319 pSMBr->resp.ByteCount))) {
3320 if (pSMBr->resp.hdr.WordCount == 4) {
3321 bcc_ptr +=
3322 blob_len;
3323 cFYI(1,
3324 ("Security Blob Length %d ",
3325 blob_len));
3326 }
3327
3328 cFYI(1,
3329 ("NTLMSSP response to Authenticate "));
3330
3331 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3332 if ((long) (bcc_ptr) % 2) {
3333 remaining_words =
3334 (BCC(smb_buffer_response)
3335 - 1) / 2;
3336 bcc_ptr++; /* Unicode strings must be word aligned */
3337 } else {
3338 remaining_words = BCC(smb_buffer_response) / 2;
3339 }
Steve French77159b42007-08-31 01:10:17 +00003340 len = UniStrnlen((wchar_t *) bcc_ptr,
3341 remaining_words - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003342/* We look for obvious messed up bcc or strings in response so we do not go off
3343 the end since (at least) WIN2K and Windows XP have a major bug in not null
3344 terminating last Unicode string in response */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003345 if (ses->serverOS)
Steve French08775832006-05-30 18:08:26 +00003346 kfree(ses->serverOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347 ses->serverOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003348 kzalloc(2 * (len + 1), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349 cifs_strfromUCS_le(ses->serverOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003350 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351 bcc_ptr, len,
3352 nls_codepage);
3353 bcc_ptr += 2 * (len + 1);
3354 remaining_words -= len + 1;
3355 ses->serverOS[2 * len] = 0;
3356 ses->serverOS[1 + (2 * len)] = 0;
3357 if (remaining_words > 0) {
3358 len = UniStrnlen((wchar_t *)
3359 bcc_ptr,
3360 remaining_words
3361 - 1);
Steve Frenchcd49b492006-06-26 04:22:36 +00003362 kfree(ses->serverNOS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003363 ses->serverNOS =
Pekka Enberge915fc42005-09-06 15:18:35 -07003364 kzalloc(2 * (len + 1),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365 GFP_KERNEL);
3366 cifs_strfromUCS_le(ses->
3367 serverNOS,
Steve Frenche89dc922005-11-11 15:18:19 -08003368 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369 bcc_ptr,
3370 len,
3371 nls_codepage);
3372 bcc_ptr += 2 * (len + 1);
3373 ses->serverNOS[2 * len] = 0;
3374 ses->serverNOS[1+(2*len)] = 0;
3375 remaining_words -= len + 1;
3376 if (remaining_words > 0) {
Steve French50c2f752007-07-13 00:33:32 +00003377 len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378 /* last string not always null terminated (e.g. for Windows XP & 2000) */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003379 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003380 kfree(ses->serverDomain);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381 ses->serverDomain =
Pekka Enberge915fc42005-09-06 15:18:35 -07003382 kzalloc(2 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003383 (len +
3384 1),
3385 GFP_KERNEL);
3386 cifs_strfromUCS_le
3387 (ses->
3388 serverDomain,
Steve Frenche89dc922005-11-11 15:18:19 -08003389 (__le16 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003390 bcc_ptr, len,
3391 nls_codepage);
3392 bcc_ptr +=
3393 2 * (len + 1);
3394 ses->
3395 serverDomain[2
3396 * len]
3397 = 0;
3398 ses->
3399 serverDomain[1
3400 +
3401 (2
3402 *
3403 len)]
3404 = 0;
3405 } /* else no more room so create dummy domain string */
Steve Frencha424f8b2006-05-30 18:06:04 +00003406 else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003407 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003408 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003409 ses->serverDomain = kzalloc(2,GFP_KERNEL);
Steve Frencha424f8b2006-05-30 18:06:04 +00003410 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411 } else { /* no room so create dummy domain and NOS string */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003412 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003413 kfree(ses->serverDomain);
Pekka Enberge915fc42005-09-06 15:18:35 -07003414 ses->serverDomain = kzalloc(2, GFP_KERNEL);
Steve Frenchcd49b492006-06-26 04:22:36 +00003415 kfree(ses->serverNOS);
Pekka Enberge915fc42005-09-06 15:18:35 -07003416 ses->serverNOS = kzalloc(2, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003417 }
3418 } else { /* ASCII */
3419 len = strnlen(bcc_ptr, 1024);
Steve French50c2f752007-07-13 00:33:32 +00003420 if (((long) bcc_ptr + len) -
3421 (long) pByteArea(smb_buffer_response)
Steve French63135e02007-07-17 17:34:02 +00003422 <= BCC(smb_buffer_response)) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003423 if (ses->serverOS)
Steve Frencha424f8b2006-05-30 18:06:04 +00003424 kfree(ses->serverOS);
Steve French77159b42007-08-31 01:10:17 +00003425 ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426 strncpy(ses->serverOS,bcc_ptr, len);
3427
3428 bcc_ptr += len;
3429 bcc_ptr[0] = 0; /* null terminate the string */
3430 bcc_ptr++;
3431
3432 len = strnlen(bcc_ptr, 1024);
Steve Frenchcd49b492006-06-26 04:22:36 +00003433 kfree(ses->serverNOS);
Steve French50c2f752007-07-13 00:33:32 +00003434 ses->serverNOS = kzalloc(len+1,
3435 GFP_KERNEL);
Steve French63135e02007-07-17 17:34:02 +00003436 strncpy(ses->serverNOS,
3437 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003438 bcc_ptr += len;
3439 bcc_ptr[0] = 0;
3440 bcc_ptr++;
3441
3442 len = strnlen(bcc_ptr, 1024);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003443 if (ses->serverDomain)
Steve Frencha424f8b2006-05-30 18:06:04 +00003444 kfree(ses->serverDomain);
Steve French63135e02007-07-17 17:34:02 +00003445 ses->serverDomain =
3446 kzalloc(len+1,
3447 GFP_KERNEL);
3448 strncpy(ses->serverDomain,
3449 bcc_ptr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450 bcc_ptr += len;
3451 bcc_ptr[0] = 0;
3452 bcc_ptr++;
3453 } else
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003454 cFYI(1, ("field of length %d "
Steve French63135e02007-07-17 17:34:02 +00003455 "extends beyond end of smb ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456 len));
3457 }
3458 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003459 cERROR(1, ("Security Blob extends beyond end "
Steve French63135e02007-07-17 17:34:02 +00003460 "of SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461 }
3462 } else {
3463 cERROR(1, ("No session structure passed in."));
3464 }
3465 } else {
Cyrill Gorcunov6345a3a2007-10-16 17:57:55 +00003466 cERROR(1, ("Invalid Word count %d: ",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467 smb_buffer_response->WordCount));
3468 rc = -EIO;
3469 }
3470
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003471 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472
3473 return rc;
3474}
3475
3476int
3477CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3478 const char *tree, struct cifsTconInfo *tcon,
3479 const struct nls_table *nls_codepage)
3480{
3481 struct smb_hdr *smb_buffer;
3482 struct smb_hdr *smb_buffer_response;
3483 TCONX_REQ *pSMB;
3484 TCONX_RSP *pSMBr;
3485 unsigned char *bcc_ptr;
3486 int rc = 0;
3487 int length;
3488 __u16 count;
3489
3490 if (ses == NULL)
3491 return -EIO;
3492
3493 smb_buffer = cifs_buf_get();
3494 if (smb_buffer == NULL) {
3495 return -ENOMEM;
3496 }
3497 smb_buffer_response = smb_buffer;
3498
3499 header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
3500 NULL /*no tid */ , 4 /*wct */ );
Steve French1982c342005-08-17 12:38:22 -07003501
3502 smb_buffer->Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503 smb_buffer->Uid = ses->Suid;
3504 pSMB = (TCONX_REQ *) smb_buffer;
3505 pSMBr = (TCONX_RSP *) smb_buffer_response;
3506
3507 pSMB->AndXCommand = 0xFF;
3508 pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003509 bcc_ptr = &pSMB->Password[0];
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003510 if ((ses->server->secMode) & SECMODE_USER) {
Steve Frencheeac8042006-01-13 21:34:58 -08003511 pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
Steve French7c7b25b2006-06-01 19:20:10 +00003512 *bcc_ptr = 0; /* password is null byte */
Steve Frencheeac8042006-01-13 21:34:58 -08003513 bcc_ptr++; /* skip password */
Steve French7c7b25b2006-06-01 19:20:10 +00003514 /* already aligned so no need to do it below */
Steve Frencheeac8042006-01-13 21:34:58 -08003515 } else {
Steve French7c7b25b2006-06-01 19:20:10 +00003516 pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
Steve Frencheeac8042006-01-13 21:34:58 -08003517 /* BB FIXME add code to fail this if NTLMv2 or Kerberos
3518 specified as required (when that support is added to
3519 the vfs in the future) as only NTLM or the much
Steve French7c7b25b2006-06-01 19:20:10 +00003520 weaker LANMAN (which we do not send by default) is accepted
Steve Frencheeac8042006-01-13 21:34:58 -08003521 by Samba (not sure whether other servers allow
3522 NTLMv2 password here) */
Steve French7c7b25b2006-06-01 19:20:10 +00003523#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French50c2f752007-07-13 00:33:32 +00003524 if ((extended_security & CIFSSEC_MAY_LANMAN) &&
Steve French7c7b25b2006-06-01 19:20:10 +00003525 (ses->server->secType == LANMAN))
3526 calc_lanman_hash(ses, bcc_ptr);
3527 else
3528#endif /* CIFS_WEAK_PW_HASH */
Steve Frencheeac8042006-01-13 21:34:58 -08003529 SMBNTencrypt(ses->password,
3530 ses->server->cryptKey,
3531 bcc_ptr);
3532
Steve French7c7b25b2006-06-01 19:20:10 +00003533 bcc_ptr += CIFS_SESS_KEY_SIZE;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003534 if (ses->capabilities & CAP_UNICODE) {
Steve French7c7b25b2006-06-01 19:20:10 +00003535 /* must align unicode strings */
3536 *bcc_ptr = 0; /* null byte password */
3537 bcc_ptr++;
3538 }
Steve Frencheeac8042006-01-13 21:34:58 -08003539 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003540
Steve French50c2f752007-07-13 00:33:32 +00003541 if (ses->server->secMode &
Steve Frencha878fb22006-05-30 18:04:19 +00003542 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543 smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3544
3545 if (ses->capabilities & CAP_STATUS32) {
3546 smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
3547 }
3548 if (ses->capabilities & CAP_DFS) {
3549 smb_buffer->Flags2 |= SMBFLG2_DFS;
3550 }
3551 if (ses->capabilities & CAP_UNICODE) {
3552 smb_buffer->Flags2 |= SMBFLG2_UNICODE;
3553 length =
Steve French50c2f752007-07-13 00:33:32 +00003554 cifs_strtoUCS((__le16 *) bcc_ptr, tree,
3555 6 /* max utf8 char length in bytes */ *
Steve Frencha878fb22006-05-30 18:04:19 +00003556 (/* server len*/ + 256 /* share len */), nls_codepage);
3557 bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558 bcc_ptr += 2; /* skip trailing null */
3559 } else { /* ASCII */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560 strcpy(bcc_ptr, tree);
3561 bcc_ptr += strlen(tree) + 1;
3562 }
3563 strcpy(bcc_ptr, "?????");
3564 bcc_ptr += strlen("?????");
3565 bcc_ptr += 1;
3566 count = bcc_ptr - &pSMB->Password[0];
3567 pSMB->hdr.smb_buf_length += count;
3568 pSMB->ByteCount = cpu_to_le16(count);
3569
Steve French133672e2007-11-13 22:41:37 +00003570 rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length,
3571 CIFS_STD_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572
3573 /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
3574 /* above now done in SendReceive */
3575 if ((rc == 0) && (tcon != NULL)) {
3576 tcon->tidStatus = CifsGood;
Steve French3b795212008-11-13 19:45:32 +00003577 tcon->need_reconnect = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003578 tcon->tid = smb_buffer_response->Tid;
3579 bcc_ptr = pByteArea(smb_buffer_response);
3580 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
Steve French50c2f752007-07-13 00:33:32 +00003581 /* skip service field (NB: this field is always ASCII) */
Steve French7f8ed422007-09-28 22:28:55 +00003582 if (length == 3) {
3583 if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') &&
3584 (bcc_ptr[2] == 'C')) {
3585 cFYI(1, ("IPC connection"));
3586 tcon->ipc = 1;
3587 }
3588 } else if (length == 2) {
3589 if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) {
3590 /* the most common case */
3591 cFYI(1, ("disk share connection"));
3592 }
3593 }
Steve French50c2f752007-07-13 00:33:32 +00003594 bcc_ptr += length + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003595 strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
3596 if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
3597 length = UniStrnlen((wchar_t *) bcc_ptr, 512);
3598 if ((bcc_ptr + (2 * length)) -
3599 pByteArea(smb_buffer_response) <=
3600 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003601 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003603 kzalloc(length + 2, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003604 if (tcon->nativeFileSystem)
3605 cifs_strfromUCS_le(
3606 tcon->nativeFileSystem,
3607 (__le16 *) bcc_ptr,
3608 length, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609 bcc_ptr += 2 * length;
3610 bcc_ptr[0] = 0; /* null terminate the string */
3611 bcc_ptr[1] = 0;
3612 bcc_ptr += 2;
3613 }
Steve French50c2f752007-07-13 00:33:32 +00003614 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615 } else {
3616 length = strnlen(bcc_ptr, 1024);
3617 if ((bcc_ptr + length) -
3618 pByteArea(smb_buffer_response) <=
3619 BCC(smb_buffer_response)) {
Jesper Juhlf99d49a2005-11-07 01:01:34 -08003620 kfree(tcon->nativeFileSystem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621 tcon->nativeFileSystem =
Pekka Enberge915fc42005-09-06 15:18:35 -07003622 kzalloc(length + 1, GFP_KERNEL);
Steve French88f370a2007-09-15 03:01:17 +00003623 if (tcon->nativeFileSystem)
3624 strncpy(tcon->nativeFileSystem, bcc_ptr,
3625 length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626 }
Steve French50c2f752007-07-13 00:33:32 +00003627 /* else do not bother copying these information fields*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003629 if ((smb_buffer_response->WordCount == 3) ||
Steve French1a4e15a2006-10-12 21:33:51 +00003630 (smb_buffer_response->WordCount == 7))
3631 /* field is in same location */
Steve French39798772006-05-31 22:40:51 +00003632 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3633 else
3634 tcon->Flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635 cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
3636 } else if ((rc == 0) && tcon == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00003637 /* all we need to save for IPC$ connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638 ses->ipc_tid = smb_buffer_response->Tid;
3639 }
3640
Mariusz Kozlowskia8a11d32007-10-03 16:41:24 +00003641 cifs_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642 return rc;
3643}
3644
3645int
3646cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3647{
3648 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003649 char *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003650
Jeff Laytonf1987b42008-11-15 11:12:47 -05003651 if (cifs_sb->tcon)
3652 cifs_put_tcon(cifs_sb->tcon);
Steve French50c2f752007-07-13 00:33:32 +00003653
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654 cifs_sb->tcon = NULL;
Steve French2fe87f02006-09-21 07:02:52 +00003655 tmp = cifs_sb->prepath;
3656 cifs_sb->prepathlen = 0;
3657 cifs_sb->prepath = NULL;
3658 kfree(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003659
Steve French88e7d702008-01-03 17:37:09 +00003660 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003661}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003662
3663int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
Steve French50c2f752007-07-13 00:33:32 +00003664 struct nls_table *nls_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665{
3666 int rc = 0;
Steve French7c7b25b2006-06-01 19:20:10 +00003667 char ntlm_session_key[CIFS_SESS_KEY_SIZE];
Steve French4b18f2a2008-04-29 00:06:05 +00003668 bool ntlmv2_flag = false;
Steve Frenchad009ac2005-04-28 22:41:05 -07003669 int first_time = 0;
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003670 struct TCP_Server_Info *server = pSesInfo->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003671
3672 /* what if server changes its buffer size after dropping the session? */
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003673 if (server->maxBuf == 0) /* no need to send on reconnect */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003674 rc = CIFSSMBNegotiate(xid, pSesInfo);
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003675 if (rc == -EAGAIN) {
3676 /* retry only once on 1st time connection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677 rc = CIFSSMBNegotiate(xid, pSesInfo);
Steve French50c2f752007-07-13 00:33:32 +00003678 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003679 rc = -EHOSTDOWN;
3680 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00003681 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003682 spin_lock(&GlobalMid_Lock);
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003683 if (server->tcpStatus != CifsExiting)
3684 server->tcpStatus = CifsGood;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685 else
3686 rc = -EHOSTDOWN;
3687 spin_unlock(&GlobalMid_Lock);
3688
3689 }
Steve Frenchad009ac2005-04-28 22:41:05 -07003690 first_time = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003691 }
Steve French26b994f2008-08-06 05:11:33 +00003692
3693 if (rc)
3694 goto ss_err_exit;
3695
3696 pSesInfo->flags = 0;
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003697 pSesInfo->capabilities = server->capabilities;
Steve French26b994f2008-08-06 05:11:33 +00003698 if (linuxExtEnabled == 0)
3699 pSesInfo->capabilities &= (~CAP_UNIX);
Steve Frenchad009ac2005-04-28 22:41:05 -07003700 /* pSesInfo->sequence_number = 0;*/
Steve French26b994f2008-08-06 05:11:33 +00003701 cFYI(1, ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003702 server->secMode, server->capabilities, server->timeAdj));
3703
Steve French26b994f2008-08-06 05:11:33 +00003704 if (experimEnabled < 2)
3705 rc = CIFS_SessSetup(xid, pSesInfo, first_time, nls_info);
3706 else if (extended_security
3707 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003708 && (server->secType == NTLMSSP)) {
Steve French26b994f2008-08-06 05:11:33 +00003709 rc = -EOPNOTSUPP;
3710 } else if (extended_security
3711 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003712 && (server->secType == RawNTLMSSP)) {
Steve French26b994f2008-08-06 05:11:33 +00003713 cFYI(1, ("NTLMSSP sesssetup"));
3714 rc = CIFSNTLMSSPNegotiateSessSetup(xid, pSesInfo, &ntlmv2_flag,
3715 nls_info);
3716 if (!rc) {
3717 if (ntlmv2_flag) {
3718 char *v2_response;
3719 cFYI(1, ("more secure NTLM ver2 hash"));
3720 if (CalcNTLMv2_partial_mac_key(pSesInfo,
3721 nls_info)) {
3722 rc = -ENOMEM;
3723 goto ss_err_exit;
3724 } else
3725 v2_response = kmalloc(16 + 64 /* blob*/,
3726 GFP_KERNEL);
3727 if (v2_response) {
3728 CalcNTLMv2_response(pSesInfo,
3729 v2_response);
3730 /* if (first_time)
3731 cifs_calculate_ntlmv2_mac_key */
3732 kfree(v2_response);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003733 /* BB Put dummy sig in SessSetup PDU? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003734 } else {
Steve French26b994f2008-08-06 05:11:33 +00003735 rc = -ENOMEM;
3736 goto ss_err_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003737 }
Steve French26b994f2008-08-06 05:11:33 +00003738
3739 } else {
3740 SMBNTencrypt(pSesInfo->password,
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003741 server->cryptKey,
Steve French26b994f2008-08-06 05:11:33 +00003742 ntlm_session_key);
3743
3744 if (first_time)
3745 cifs_calculate_mac_key(
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003746 &server->mac_signing_key,
Steve French26b994f2008-08-06 05:11:33 +00003747 ntlm_session_key,
3748 pSesInfo->password);
3749 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750 /* for better security the weaker lanman hash not sent
3751 in AuthSessSetup so we no longer calculate it */
3752
Steve French26b994f2008-08-06 05:11:33 +00003753 rc = CIFSNTLMSSPAuthSessSetup(xid, pSesInfo,
3754 ntlm_session_key,
3755 ntlmv2_flag,
3756 nls_info);
3757 }
3758 } else { /* old style NTLM 0.12 session setup */
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003759 SMBNTencrypt(pSesInfo->password, server->cryptKey,
Steve French26b994f2008-08-06 05:11:33 +00003760 ntlm_session_key);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761
Steve French26b994f2008-08-06 05:11:33 +00003762 if (first_time)
Jeff Laytoncb7691b2008-08-18 15:41:05 -04003763 cifs_calculate_mac_key(&server->mac_signing_key,
3764 ntlm_session_key,
3765 pSesInfo->password);
Steve Frenchad009ac2005-04-28 22:41:05 -07003766
Steve French26b994f2008-08-06 05:11:33 +00003767 rc = CIFSSessSetup(xid, pSesInfo, ntlm_session_key, nls_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768 }
Steve French26b994f2008-08-06 05:11:33 +00003769 if (rc) {
3770 cERROR(1, ("Send error in SessSetup = %d", rc));
3771 } else {
3772 cFYI(1, ("CIFS Session Established successfully"));
Jeff Layton469ee612008-10-16 18:46:39 +00003773 spin_lock(&GlobalMid_Lock);
Steve French26b994f2008-08-06 05:11:33 +00003774 pSesInfo->status = CifsGood;
Steve French3b795212008-11-13 19:45:32 +00003775 pSesInfo->need_reconnect = false;
Jeff Layton469ee612008-10-16 18:46:39 +00003776 spin_unlock(&GlobalMid_Lock);
Steve French26b994f2008-08-06 05:11:33 +00003777 }
3778
Linus Torvalds1da177e2005-04-16 15:20:36 -07003779ss_err_exit:
3780 return rc;
3781}
3782